diff options
author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2021-01-09 10:41:17 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-01-09 10:41:17 -0500 |
commit | 06d23f59d83ef89ebda89db547195ecf2a1c6ebf (patch) | |
tree | 0b0088003dbc0b27fd1aad4fa86b67d0c47f2217 | |
parent | b20622b2c84ce3ca1781c7bf8e10fed0af1e5001 (diff) |
Improve frequency display (#1209)
* Disable old frequencies
* Update layout
* Implement new frequency display
* Update count info
-rw-r--r-- | ext/mixed/css/display.css | 153 | ||||
-rw-r--r-- | ext/mixed/display-templates.html | 58 | ||||
-rw-r--r-- | ext/mixed/js/dictionary-data-util.js | 55 | ||||
-rw-r--r-- | ext/mixed/js/display-generator.js | 72 |
4 files changed, 235 insertions, 103 deletions
diff --git a/ext/mixed/css/display.css b/ext/mixed/css/display.css index 0e4b2012..fd320904 100644 --- a/ext/mixed/css/display.css +++ b/ext/mixed/css/display.css @@ -249,6 +249,12 @@ h3 { margin: 0.25em 0 0.375em; padding: 0; } +h5 { + font-size: calc(12em / 14); + margin: 0; + padding: 0; + font-weight: normal; +} a { color: var(--link-color); text-decoration: underline; @@ -693,27 +699,6 @@ button.action-button[data-icon=source-term]::before { .tag-inner { display: block; } -.tag-frequency-separator::before { - content: ':'; -} -.tag-frequency-disambiguation-separator::before { - content: ':'; -} -.tag-frequency-disambiguation::before { - content: '('; -} -.tag-frequency-disambiguation::after { - content: ') '; -} -.frequencies .tag[data-reading-is-same=true] .tag-frequency-disambiguation-separator, -.frequencies .tag[data-reading-is-same=true] .tag-frequency-disambiguation-reading, -.entry[data-unique-expression-count='1'] .tag-frequency-disambiguation-separator, -.entry[data-unique-expression-count='1'] .tag-frequency-disambiguation-expression, -.entry[data-unique-reading-count='1'] .tag-frequency-disambiguation-separator, -.entry[data-unique-reading-count='1'] .tag-frequency-disambiguation-reading, -.entry[data-unique-expression-count='1'][data-unique-reading-count='1'] .tag-frequency-disambiguation { - display: none; -} /* Entries */ @@ -949,16 +934,6 @@ button.action-button[data-icon=source-term]::before { bottom: -0.5em; white-space: nowrap; } -.entry[data-expression-multi=true] .term-expression-list .term-expression-details>.frequencies { - display: block; - position: absolute; - left: 0; - bottom: -1.9em; - white-space: nowrap; -} -.entry[data-expression-multi=true] .term-expression-list .term-expression-details>.frequencies .tag-frequency-disambiguation { - display: none; -} /* Definitions */ @@ -1008,24 +983,106 @@ button.action-button[data-icon=source-term]::before { opacity: 0; white-space: pre-wrap; } -.term-special-tags>.frequencies { - display: inline; +.entry-body { + margin-top: -0.5em; +} +.entry-body-section { + margin-top: 0.5em; +} +.entry[data-definition-count='0'] .entry-body-section[data-section-type=definitions], +.entry[data-frequency-count='0'] .entry-body-section[data-section-type=frequencies], +.entry[data-pitch-accent-count='0'] .entry-body-section[data-section-type=pitch-accents] { + display: none; } -.term-entry-body[data-section-count='0'] .term-entry-body-section-header, -.term-entry-body[data-section-count='1'] .term-entry-body-section-header { +.entry[data-pitch-accent-count='0'][data-frequency-count='0'] .entry-body-section[data-section-type=definitions]>h5 { display: none; } -/* Pitch accent styles */ -.entry[data-pitch-accent-count='0'] .term-pitch-accent-container { +/* Frequencies */ +.frequency-group-list { + margin: 0; + padding: 0 0 0 var(--list-padding1); + list-style-type: decimal; +} +.frequency-group-list[data-count='0'], +.frequency-group-list[data-count='1'] { + padding-left: 0; + list-style-type: none; +} +.frequency-list { + margin: 0; + padding: 0 0 0 var(--list-padding2); + list-style-type: circle; +} +.frequency-list[data-count='0'], +.frequency-list[data-count='1'] { + padding-left: 0; + list-style-type: none; +} +.frequency-group-item::marker, +.frequency-item::marker { + color: var(--text-color-light); +} +.frequency-disambiguation { + color: var(--text-color-light); +} +.frequency-separator::before { + content: ''; +} +.frequency-disambiguation-separator::before { + content: ':'; +} +.frequency-disambiguation::before { + content: '('; +} +.frequency-disambiguation::after { + content: ' only) '; +} +.entry[data-unique-expression-count='1'] .frequency-item[data-has-reading=false] .frequency-disambiguation, +.entry[data-unique-reading-count='1'][data-unique-expression-count='1'] .frequency-disambiguation, +.frequency-item[data-reading-is-same=true] .frequency-disambiguation-separator, +.frequency-item[data-reading-is-same=true] .frequency-disambiguation-reading, +.frequency-item[data-has-reading=false] .frequency-disambiguation-separator, +.frequency-item[data-has-reading=false] .frequency-disambiguation-reading, +.entry[data-unique-expression-count='1'] .frequency-disambiguation-separator, +.entry[data-unique-expression-count='1'] .frequency-disambiguation-expression, +.entry[data-unique-reading-count='1'] .frequency-disambiguation-separator, +.entry[data-unique-reading-count='1'] .frequency-disambiguation-reading { display: none; } -.term-pitch-accent-container { - border-bottom: var(--thin-border-size) solid var(--light-border-color); - padding-bottom: 0.25em; - margin-bottom: 0.25em; +:root[data-glossary-layout-mode=compact] .frequency-group-list, +:root[data-glossary-layout-mode=compact] .frequency-list, +.frequency-list[data-count='1'] { + display: inline; + list-style: none; + padding-left: 0; +} +:root[data-glossary-layout-mode=compact] .frequency-group-item { + display: inline-block; + margin-right: 1em; +} +:root[data-glossary-layout-mode=compact] .entry-body-section[data-section-type=frequencies] { + margin-right: -1em; +} +:root[data-glossary-layout-mode=compact] .frequency-item, +.frequency-list[data-count='1'] .frequency-item { + display: inline-block; +} +:root[data-glossary-layout-mode=compact] .frequency-item:not(:first-child)::before, +.frequency-list[data-count='1'] .frequency-item:not(:first-child)::before { + white-space: pre-wrap; + content: var(--compact-list-separator); + display: inline; + color: var(--text-color-light); } +:root[data-glossary-layout-mode=compact] .frequency-tag-list, +.frequency-group-item[data-count='1'] .frequency-tag-list { + display: inline; +} + + +/* Pitch accent styles */ .term-pitch-accent-group-list { margin: 0; padding: 0 0 0 var(--list-padding1); @@ -1582,17 +1639,15 @@ button.footer-notification-close-button:active { display: inline; color: var(--text-color-light); } -:root[data-glossary-layout-mode=compact] .entry:not([data-expression-multi=true]) .term-special-tags { + +:root[data-glossary-layout-mode=compact] .entry-body-section>h5 { display: none; } -:root[data-glossary-layout-mode=compact] .term-expression-details>.frequencies { - display: inline; +:root[data-glossary-layout-mode=compact] .entry-body { + margin-top: 0; } - -:root[data-glossary-layout-mode=compact] .term-pitch-accent-container { - border-bottom: none; - padding-bottom: 0; - margin-bottom: 0; +:root[data-glossary-layout-mode=compact] .entry-body-section { + margin-top: 0; } :root[data-show-pitch-accent-downstep-notation=true] .term-pitch-accent-disambiguation-list[data-expression-count='0'], :root[data-show-pitch-accent-downstep-notation=true] .term-pitch-accent-disambiguation[data-type=reading] { diff --git a/ext/mixed/display-templates.html b/ext/mixed/display-templates.html index 95432ad2..ac42e138 100644 --- a/ext/mixed/display-templates.html +++ b/ext/mixed/display-templates.html @@ -17,11 +17,20 @@ </div> <div class="term-reasons"></div> </div> - <div class="term-special-tags"><div class="frequencies tag-list"></div></div> </div> - <div class="term-entry-body"> - <div class="term-entry-body-section term-pitch-accent-container"><ol class="term-entry-body-section-content term-pitch-accent-group-list"></ol></div> - <div class="term-entry-body-section term-definition-container"><ol class="term-entry-body-section-content term-definition-list"></ol></div> + <div class="entry-body"> + <div class="entry-body-section" data-section-type="frequencies"> + <h5>Frequencies</h5> + <ol class="entry-body-section-content frequency-group-list"></ol> + </div> + <div class="entry-body-section" data-section-type="pitch-accents"> + <h5>Pitch Accents</h5> + <ol class="entry-body-section-content term-pitch-accent-group-list"></ol> + </div> + <div class="entry-body-section" data-section-type="definitions"> + <h5>Definitions</h5> + <ol class="entry-body-section-content term-definition-list"></ol> + </div> </div> <div class="debug-info"><a class="debug-log-link">Log debug info to console</a></div> </div></template> @@ -34,7 +43,6 @@ <div class="term-expression-details"> <button class="action-button action-play-audio" data-icon="play-audio" title="Play audio"></button> <div class="tags tag-list"></div> - <div class="frequencies tag-list"></div> </div> </div></template> <template id="term-definition-item-template"><li class="term-definition-item"><div class="term-definition-tag-list tag-list"></div><div class="term-definition-disambiguation-list"></div><ul class="term-glossary-list"></ul></li></template> @@ -43,6 +51,21 @@ <template id="term-glossary-item-image-template"><li class="term-glossary-item click-scannable" data-has-image="true"><span class="term-glossary-separator"> </span><span class="term-glossary"><a class="term-glossary-image-link" target="_blank" rel="noreferrer noopener"><span class="term-glossary-image-container"><span class="term-glossary-image-aspect-ratio-sizer"></span><img class="term-glossary-image" alt="" /><span class="term-glossary-image-container-overlay"></span></span><span class="term-glossary-image-link-text">Image</span></a> <span class="term-glossary-image-description"></span></span></li></template> <template id="term-reason-template"><span class="term-reason"></span><span class="term-reason-separator"> </span></template> +<!-- Frequency templates --> +<template id="frequency-group-item-template"><li class="frequency-group-item"><div class="frequency-tag-list tag-list"></div><ul class="frequency-list"></ul></li></template> +<template id="term-frequency-item-template" data-remove-whitespace-text="true"><li class="frequency-item" data-frequency-type="term"> + <span class="frequency-disambiguation"> + <span class="frequency-disambiguation-expression"></span> + <span class="frequency-disambiguation-separator"></span> + <span class="frequency-disambiguation-reading"></span> + </span> + <span class="frequency-separator"></span> + <span class="frequency-value"></span> +</li></template> +<template id="kanji-frequency-item-template" data-remove-whitespace-text="true"><li class="frequency-item" data-frequency-type="kanji"> + <span class="frequency-value"></span> +</li></template> + <!-- Pitch accent templates --> <template id="term-pitch-accent-static-template"><svg xmlns="http://www.w3.org/2000/svg" style="display: none;"> <defs> @@ -73,9 +96,13 @@ </div> </div> </div> - <div class="frequencies"></div> </div> <div class="tags tag-list"></div> + <div class="entry-body"> + <div class="entry-body-section" data-section-type="frequencies"> + <ol class="entry-body-section-content frequency-group-list"></ol> + </div> + </div> <table class="kanji-glyph-data"><tbody> <tr> <th>Glossary</th> @@ -104,25 +131,6 @@ <!-- Tag templates --> <template id="tag-template"><span class="tag"><span class="tag-inner"></span></span></template> -<template id="term-tag-frequency-template" data-remove-whitespace-text="true"><span class="tag" data-category="frequency"> - <span class="tag-inner"> - <span class="tag-frequency-disambiguation"> - <span class="tag-frequency-disambiguation-expression"></span> - <span class="tag-frequency-disambiguation-separator"></span> - <span class="tag-frequency-disambiguation-reading"></span> - </span> - <span class="tag-frequency-dictionary-name"></span> - <span class="tag-frequency-separator"></span> - <span class="tag-frequency-value"></span> - </span> -</span></template> -<template id="kanji-tag-frequency-template" data-remove-whitespace-text="true"><span class="tag" data-category="frequency"> - <span class="tag-inner"> - <span class="tag-frequency-dictionary-name"></span> - <span class="tag-frequency-separator"></span> - <span class="tag-frequency-value"></span> - </span> -</span></template> <!-- Extra --> <template id="footer-notification-template"><div class="footer-notification"> diff --git a/ext/mixed/js/dictionary-data-util.js b/ext/mixed/js/dictionary-data-util.js index 8d8772fe..1e82ef63 100644 --- a/ext/mixed/js/dictionary-data-util.js +++ b/ext/mixed/js/dictionary-data-util.js @@ -16,6 +16,48 @@ */ class DictionaryDataUtil { + static groupTermFrequencies(frequencies) { + const map1 = new Map(); + for (const {dictionary, expression, reading, hasReading, frequency} of frequencies) { + let map2 = map1.get(dictionary); + if (typeof map2 === 'undefined') { + map2 = new Map(); + map1.set(dictionary, map2); + } + + const readingKey = hasReading ? reading : null; + const key = JSON.stringify([expression, readingKey], null, 0); + let frequencyData = map2.get(key); + if (typeof frequencyData === 'undefined') { + frequencyData = {expression, reading: readingKey, frequencies: new Set()}; + map2.set(key, frequencyData); + } + + frequencyData.frequencies.add(frequency); + } + return this._createFrequencyGroupsFromMap(map1); + } + + static groupKanjiFrequencies(frequencies) { + const map1 = new Map(); + for (const {dictionary, character, frequency} of frequencies) { + let map2 = map1.get(dictionary); + if (typeof map2 === 'undefined') { + map2 = new Map(); + map1.set(dictionary, map2); + } + + let frequencyData = map2.get(character); + if (typeof frequencyData === 'undefined') { + frequencyData = {character, frequencies: new Set()}; + map2.set(character, frequencyData); + } + + frequencyData.frequencies.add(frequency); + } + return this._createFrequencyGroupsFromMap(map1); + } + static getPitchAccentInfos(definition) { if (definition.type === 'kanji') { return []; } @@ -73,6 +115,19 @@ class DictionaryDataUtil { // Private + static _createFrequencyGroupsFromMap(map) { + const results = []; + for (const [dictionary, map2] of map.entries()) { + const frequencyDataArray = []; + for (const frequencyData of map2.values()) { + frequencyData.frequencies = [...frequencyData.frequencies]; + frequencyDataArray.push(frequencyData); + } + results.push({dictionary, frequencyData: frequencyDataArray}); + } + return results; + } + static _findExistingPitchAccentInfo(reading, position, tags, pitchAccentInfoList) { for (const pitchInfo of pitchAccentInfoList) { if ( diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js index 6a8c03e3..a47a65ee 100644 --- a/ext/mixed/js/display-generator.js +++ b/ext/mixed/js/display-generator.js @@ -47,15 +47,15 @@ class DisplayGenerator { const expressionsContainer = node.querySelector('.term-expression-list'); const reasonsContainer = node.querySelector('.term-reasons'); const pitchesContainer = node.querySelector('.term-pitch-accent-group-list'); - const frequenciesContainer = node.querySelector('.frequencies'); + const frequencyGroupListContainer = node.querySelector('.frequency-group-list'); const definitionsContainer = node.querySelector('.term-definition-list'); - const bodyContainer = node.querySelector('.term-entry-body'); const {expressions, type, reasons, frequencies} = details; const definitions = (type === 'term' ? [details] : details.definitions); const merged = (type === 'termMerged' || type === 'termMergedByGlossary'); const pitches = DictionaryDataUtil.getPitchAccentInfos(details); const pitchCount = pitches.reduce((i, v) => i + v.pitches.length, 0); + const groupedFrequencies = DictionaryDataUtil.groupTermFrequencies(frequencies); const uniqueExpressions = new Set(); const uniqueReadings = new Set(); @@ -72,15 +72,12 @@ class DisplayGenerator { node.dataset.pitchAccentCount = `${pitchCount}`; node.dataset.uniqueExpressionCount = `${uniqueExpressions.size}`; node.dataset.uniqueReadingCount = `${uniqueReadings.size}`; - - bodyContainer.dataset.sectionCount = `${ - (definitions.length > 0 ? 1 : 0) + - (pitches.length > 0 ? 1 : 0) - }`; + node.dataset.frequencyCount = `${frequencies.length}`; + node.dataset.groupedFrequencyCount = `${groupedFrequencies.length}`; this._appendMultiple(expressionsContainer, this._createTermExpression.bind(this), expressions); this._appendMultiple(reasonsContainer, this._createTermReason.bind(this), reasons); - this._appendMultiple(frequenciesContainer, this._createTermFrequencyTag.bind(this), frequencies); + this._appendMultiple(frequencyGroupListContainer, this._createFrequencyGroup.bind(this), groupedFrequencies, false); this._appendMultiple(pitchesContainer, this._createPitches.bind(this), pitches); this._appendMultiple(definitionsContainer, this._createTermDefinitionItem.bind(this), definitions); @@ -91,7 +88,7 @@ class DisplayGenerator { const node = this._templates.instantiate('kanji-entry'); const glyphContainer = node.querySelector('.kanji-glyph'); - const frequenciesContainer = node.querySelector('.frequencies'); + const frequencyGroupListContainer = node.querySelector('.frequency-group-list'); const tagContainer = node.querySelector('.tags'); const glossaryContainer = node.querySelector('.kanji-glossary-list'); const chineseReadingsContainer = node.querySelector('.kanji-readings-chinese'); @@ -102,8 +99,9 @@ class DisplayGenerator { const dictionaryIndicesContainer = node.querySelector('.kanji-dictionary-indices'); glyphContainer.textContent = details.character; + const groupedFrequencies = DictionaryDataUtil.groupKanjiFrequencies(details.frequencies); - this._appendMultiple(frequenciesContainer, this._createKanjiFrequencyTag.bind(this), details.frequencies); + this._appendMultiple(frequencyGroupListContainer, this._createFrequencyGroup.bind(this), groupedFrequencies, true); this._appendMultiple(tagContainer, this._createTag.bind(this), details.tags); this._appendMultiple(glossaryContainer, this._createKanjiGlossaryItem.bind(this), details.glossary); this._appendMultiple(chineseReadingsContainer, this._createKanjiReading.bind(this), details.onyomi); @@ -128,7 +126,7 @@ class DisplayGenerator { // Private _createTermExpression(details) { - const {termFrequency, furiganaSegments, expression, reading, termTags, frequencies} = details; + const {termFrequency, furiganaSegments, expression, reading, termTags} = details; const searchQueries = []; if (expression) { searchQueries.push(expression); } @@ -138,7 +136,6 @@ class DisplayGenerator { const expressionContainer = node.querySelector('.term-expression-text'); const tagContainer = node.querySelector('.tags'); - const frequencyContainer = node.querySelector('.frequencies'); node.dataset.readingIsSame = `${!reading || reading === expression}`; node.dataset.frequency = termFrequency; @@ -146,7 +143,6 @@ class DisplayGenerator { this._appendFurigana(expressionContainer, furiganaSegments, this._appendKanjiLinks.bind(this)); this._appendMultiple(tagContainer, this._createTag.bind(this), termTags); this._appendMultiple(tagContainer, this._createSearchTag.bind(this), searchQueries); - this._appendMultiple(frequencyContainer, this._createTermFrequencyTag.bind(this), frequencies); return node; } @@ -467,36 +463,54 @@ class DisplayGenerator { path.setAttribute('d', `M${pathPoints.join(' L')}`); } - _createTermFrequencyTag(details) { - const {expression, reading, dictionary, frequency} = details; - const node = this._templates.instantiate('term-tag-frequency'); + _createFrequencyGroup(details, kanji) { + const {dictionary, frequencyData} = details; + const node = this._templates.instantiate('frequency-group-item'); + + const tagList = node.querySelector('.frequency-tag-list'); + const tag = this._createTag({notes: '', name: dictionary, category: 'frequency'}); + tagList.appendChild(tag); + + const frequencyListContainer = node.querySelector('.frequency-list'); + const createItem = (kanji ? this._createKanjiFrequency.bind(this) : this._createTermFrequency.bind(this)); + this._appendMultiple(frequencyListContainer, createItem, frequencyData, dictionary); + + node.dataset.count = `${frequencyData.length}`; + + return node; + } + + _createTermFrequency(details, dictionary) { + const {expression, reading, frequencies} = details; + const node = this._templates.instantiate('term-frequency-item'); - node.querySelector('.tag-frequency-disambiguation-expression').textContent = expression; - node.querySelector('.tag-frequency-disambiguation-reading').textContent = reading; - node.querySelector('.tag-frequency-dictionary-name').textContent = dictionary; - node.querySelector('.tag-frequency-value').textContent = frequency; + const frequency = frequencies.join(', '); + + node.querySelector('.frequency-disambiguation-expression').textContent = expression; + node.querySelector('.frequency-disambiguation-reading').textContent = (reading !== null ? reading : ''); + node.querySelector('.frequency-value').textContent = frequency; node.dataset.expression = expression; node.dataset.reading = reading; + node.dataset.hasReading = `${reading !== null}`; node.dataset.readingIsSame = `${reading === expression}`; node.dataset.dictionary = dictionary; - node.dataset.frequency = frequency; - node.dataset.details = `${dictionary}: ${frequency}`; + node.dataset.frequency = `${frequency}`; return node; } - _createKanjiFrequencyTag(details) { - const {character, dictionary, frequency} = details; - const node = this._templates.instantiate('kanji-tag-frequency'); + _createKanjiFrequency(details, dictionary) { + const {character, frequencies} = details; + const node = this._templates.instantiate('kanji-frequency-item'); + + const frequency = frequencies.join(', '); - node.querySelector('.tag-frequency-dictionary-name').textContent = dictionary; - node.querySelector('.tag-frequency-value').textContent = frequency; + node.querySelector('.frequency-value').textContent = frequency; node.dataset.character = character; node.dataset.dictionary = dictionary; - node.dataset.frequency = frequency; - node.dataset.details = `${dictionary}: ${frequency}`; + node.dataset.frequency = `${frequency}`; return node; } |