From 5b58a9aeef66194bc51fe25f66aebf95f673089a Mon Sep 17 00:00:00 2001 From: toasted-nutbread Date: Sat, 9 Jan 2021 16:02:03 -0500 Subject: Update term tags display and fix a layout issue (#1208) * Fix layout issue with term expression display * Update display of term tags * Update tag notification to include disambiguation information --- ext/mixed/js/dictionary-data-util.js | 37 ++++++++++++++++++++++++- ext/mixed/js/display-generator.js | 52 ++++++++++++++++++++++++++++++++++++ ext/mixed/js/display-notification.js | 9 +++++-- ext/mixed/js/display.js | 7 +++-- 4 files changed, 98 insertions(+), 7 deletions(-) (limited to 'ext/mixed/js') diff --git a/ext/mixed/js/dictionary-data-util.js b/ext/mixed/js/dictionary-data-util.js index 1e82ef63..70a51e89 100644 --- a/ext/mixed/js/dictionary-data-util.js +++ b/ext/mixed/js/dictionary-data-util.js @@ -16,6 +16,37 @@ */ class DictionaryDataUtil { + static groupTermTags(definition) { + const {expressions} = definition; + const expressionsLength = expressions.length; + const uniqueCheck = (expressionsLength > 1); + const resultsMap = new Map(); + const results = []; + for (let i = 0; i < expressionsLength; ++i) { + const {termTags, expression, reading} = expressions[i]; + for (const tag of termTags) { + if (uniqueCheck) { + const {name, category, notes, dictionary} = tag; + const key = this._createMapKey([name, category, notes, dictionary]); + const index = resultsMap.get(key); + if (typeof index !== 'undefined') { + const existingItem = results[index]; + existingItem.expressions.push({index: i, expression, reading}); + continue; + } + resultsMap.set(key, results.length); + } + + const item = { + tag, + expressions: [{index: i, expression, reading}] + }; + results.push(item); + } + } + return results; + } + static groupTermFrequencies(frequencies) { const map1 = new Map(); for (const {dictionary, expression, reading, hasReading, frequency} of frequencies) { @@ -26,7 +57,7 @@ class DictionaryDataUtil { } const readingKey = hasReading ? reading : null; - const key = JSON.stringify([expression, readingKey], null, 0); + const key = this._createMapKey([expression, readingKey]); let frequencyData = map2.get(key); if (typeof frequencyData === 'undefined') { frequencyData = {expression, reading: readingKey, frequencies: new Set()}; @@ -179,4 +210,8 @@ class DictionaryDataUtil { } return result; } + + static _createMapKey(array) { + return JSON.stringify(array); + } } diff --git a/ext/mixed/js/display-generator.js b/ext/mixed/js/display-generator.js index a47a65ee..b48ddadc 100644 --- a/ext/mixed/js/display-generator.js +++ b/ext/mixed/js/display-generator.js @@ -49,6 +49,7 @@ class DisplayGenerator { const pitchesContainer = node.querySelector('.term-pitch-accent-group-list'); const frequencyGroupListContainer = node.querySelector('.frequency-group-list'); const definitionsContainer = node.querySelector('.term-definition-list'); + const termTagsContainer = node.querySelector('.term-tags'); const {expressions, type, reasons, frequencies} = details; const definitions = (type === 'term' ? [details] : details.definitions); @@ -56,6 +57,7 @@ class DisplayGenerator { const pitches = DictionaryDataUtil.getPitchAccentInfos(details); const pitchCount = pitches.reduce((i, v) => i + v.pitches.length, 0); const groupedFrequencies = DictionaryDataUtil.groupTermFrequencies(frequencies); + const termTags = DictionaryDataUtil.groupTermTags(details); const uniqueExpressions = new Set(); const uniqueReadings = new Set(); @@ -80,6 +82,7 @@ class DisplayGenerator { 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); + this._appendMultiple(termTagsContainer, this._createTermTag.bind(this), termTags, expressions.length); return node; } @@ -119,6 +122,45 @@ class DisplayGenerator { return this._templates.instantiate('footer-notification'); } + createTagFooterNotificationDetails(tagNode) { + const node = this._templates.instantiateFragment('footer-notification-tag-details'); + + const details = tagNode.dataset.details; + node.querySelector('.tag-details').textContent = details; + + let disambiguation = null; + try { + let a = tagNode.dataset.disambiguation; + if (typeof a !== 'undefined') { + a = JSON.parse(a); + if (Array.isArray(a)) { disambiguation = a; } + } + } catch (e) { + // NOP + } + + if (disambiguation !== null) { + const disambiguationContainer = node.querySelector('.tag-details-disambiguation-list'); + const copyAttributes = ['totalExpressionCount', 'matchedExpressionCount', 'unmatchedExpressionCount']; + for (const attribute of copyAttributes) { + const value = tagNode.dataset[attribute]; + if (typeof value === 'undefined') { continue; } + disambiguationContainer.dataset[attribute] = value; + } + for (const {expression, reading} of disambiguation) { + const segments = this._japaneseUtil.distributeFurigana(expression, reading); + const disambiguationItem = document.createElement('span'); + disambiguationItem.className = 'tag-details-disambiguation'; + this._appendFurigana(disambiguationItem, segments, (container, text) => { + container.appendChild(document.createTextNode(text)); + }); + disambiguationContainer.appendChild(disambiguationItem); + } + } + + return node; + } + createProfileListItem() { return this._templates.instantiate('profile-list-item'); } @@ -321,6 +363,16 @@ class DisplayGenerator { return node; } + _createTermTag(details, totalExpressionCount) { + const {tag, expressions} = details; + const node = this._createTag(tag); + node.dataset.disambiguation = `${JSON.stringify(expressions)}`; + node.dataset.totalExpressionCount = `${totalExpressionCount}`; + node.dataset.matchedExpressionCount = `${expressions.length}`; + node.dataset.unmatchedExpressionCount = `${Math.max(0, totalExpressionCount - expressions.length)}`; + return node; + } + _createSearchTag(text) { return this._createTag({ notes: '', diff --git a/ext/mixed/js/display-notification.js b/ext/mixed/js/display-notification.js index 0e79f1c6..8b6325d0 100644 --- a/ext/mixed/js/display-notification.js +++ b/ext/mixed/js/display-notification.js @@ -58,8 +58,13 @@ class DisplayNotification { } } - setContent(text) { - this._body.textContent = text; + setContent(value) { + if (typeof value === 'string') { + this._body.textContent = value; + } else { + this._body.textContent = ''; + this._body.appendChild(value); + } } isClosing() { diff --git a/ext/mixed/js/display.js b/ext/mixed/js/display.js index c36a0c1c..e4433925 100644 --- a/ext/mixed/js/display.js +++ b/ext/mixed/js/display.js @@ -837,18 +837,17 @@ class Display extends EventDispatcher { } _onTagClick(e) { - const node = e.currentTarget; - const {dataset: {details}} = node; - this._showTagNotification(details); + this._showTagNotification(e.currentTarget); } - _showTagNotification(content) { + _showTagNotification(tagNode) { if (this._tagNotification === null) { const node = this._displayGenerator.createEmptyFooterNotification(); node.classList.add('click-scannable'); this._tagNotification = new DisplayNotification(this._tagNotificationContainer, node); } + const content = this._displayGenerator.createTagFooterNotificationDetails(tagNode); this._tagNotification.setContent(content); this._tagNotification.open(); } -- cgit v1.2.3