diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2022-05-14 18:12:57 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-05-14 18:12:57 -0400 | 
| commit | 5dcc2315d242bcec29cc478618d448c941f73ab1 (patch) | |
| tree | 9d36e666cc71bb1c1a89c725eaa9fdaa5c938626 /ext | |
| parent | 6a74746113c724e750620d10b58ad6bac94060c9 (diff) | |
Structured content auto language (#2131)
* Pass JapaneseUtil instance to StructuredContentGenerator
* Move body of createStructuredContent to an internal function
* Create _createStructuredContentGenericElement
* Wrap structured content in a <span>
* Change _createStructuredContent to _appendStructuredContent
* Add public appendStructuredContent function
* Add missing return
* Remove unused _createDocumentFragment
* Automatically assign lang=ja for content with Japanese characters
without an explicit language
* Add test
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/js/display/display-generator.js | 9 | ||||
| -rw-r--r-- | ext/js/display/sandbox/structured-content-generator.js | 141 | ||||
| -rw-r--r-- | ext/js/templates/sandbox/anki-template-renderer.js | 2 | 
3 files changed, 86 insertions, 66 deletions
| diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js index 1f485a4f..3fabdbb0 100644 --- a/ext/js/display/display-generator.js +++ b/ext/js/display/display-generator.js @@ -28,7 +28,7 @@ class DisplayGenerator {          this._contentManager = contentManager;          this._hotkeyHelpController = hotkeyHelpController;          this._templates = null; -        this._structuredContentGenerator = new StructuredContentGenerator(this._contentManager, document); +        this._structuredContentGenerator = new StructuredContentGenerator(this._contentManager, japaneseUtil, document);          this._pronunciationGenerator = new PronunciationGenerator(japaneseUtil);      } @@ -347,11 +347,8 @@ class DisplayGenerator {      _createTermDefinitionEntryStructuredContent(content, dictionary) {          const node = this._templates.instantiate('gloss-item'); -        const child = this._structuredContentGenerator.createStructuredContent(content, dictionary); -        if (child !== null) { -            const contentContainer = node.querySelector('.gloss-content'); -            contentContainer.appendChild(child); -        } +        const contentContainer = node.querySelector('.gloss-content'); +        this._structuredContentGenerator.appendStructuredContent(contentContainer, content, dictionary);          return node;      } diff --git a/ext/js/display/sandbox/structured-content-generator.js b/ext/js/display/sandbox/structured-content-generator.js index 6102cfdd..5b11965a 100644 --- a/ext/js/display/sandbox/structured-content-generator.js +++ b/ext/js/display/sandbox/structured-content-generator.js @@ -16,56 +16,21 @@   */  class StructuredContentGenerator { -    constructor(contentManager, document) { +    constructor(contentManager, japaneseUtil, document) {          this._contentManager = contentManager; +        this._japaneseUtil = japaneseUtil;          this._document = document;      } +    appendStructuredContent(node, content, dictionary) { +        node.classList.add('structured-content'); +        this._appendStructuredContent(node, content, dictionary, null); +    } +      createStructuredContent(content, dictionary) { -        if (typeof content === 'string') { -            return this._createTextNode(content); -        } -        if (!(typeof content === 'object' && content !== null)) { -            return null; -        } -        if (Array.isArray(content)) { -            const fragment = this._createDocumentFragment(); -            for (const item of content) { -                const child = this.createStructuredContent(item, dictionary); -                if (child !== null) { fragment.appendChild(child); } -            } -            return fragment; -        } -        const {tag} = content; -        switch (tag) { -            case 'br': -                return this._createStructuredContentElement(tag, content, dictionary, 'simple', false, false); -            case 'ruby': -            case 'rt': -            case 'rp': -                return this._createStructuredContentElement(tag, content, dictionary, 'simple', true, false); -            case 'table': -                return this._createStructuredContentTableElement(tag, content, dictionary); -            case 'thead': -            case 'tbody': -            case 'tfoot': -            case 'tr': -                return this._createStructuredContentElement(tag, content, dictionary, 'table', true, false); -            case 'th': -            case 'td': -                return this._createStructuredContentElement(tag, content, dictionary, 'table-cell', true, true); -            case 'div': -            case 'span': -            case 'ol': -            case 'ul': -            case 'li': -                return this._createStructuredContentElement(tag, content, dictionary, 'simple', true, true); -            case 'img': -                return this.createDefinitionImage(content, dictionary); -            case 'a': -                return this._createLinkElement(content, dictionary); -        } -        return null; +        const node = this._createElement('span', 'structured-content'); +        this._appendStructuredContent(node, content, dictionary, null); +        return node;      }      createDefinitionImage(data, dictionary) { @@ -160,6 +125,31 @@ class StructuredContentGenerator {      // Private +    _appendStructuredContent(container, content, dictionary, language) { +        if (typeof content === 'string') { +            if (content.length > 0) { +                container.appendChild(this._createTextNode(content)); +                if (language === null && this._japaneseUtil.isStringPartiallyJapanese(content)) { +                    container.lang = 'ja'; +                } +            } +            return; +        } +        if (!(typeof content === 'object' && content !== null)) { +            return; +        } +        if (Array.isArray(content)) { +            for (const item of content) { +                this._appendStructuredContent(container, item, dictionary, language); +            } +            return; +        } +        const node = this._createStructuredContentGenericElement(content, dictionary, language); +        if (node !== null) { +            container.appendChild(node); +        } +    } +      _createElement(tagName, className) {          const node = this._document.createElement(tagName);          node.className = className; @@ -170,10 +160,6 @@ class StructuredContentGenerator {          return this._document.createTextNode(data);      } -    _createDocumentFragment() { -        return this._document.createDocumentFragment(); -    } -      _setElementDataset(element, data) {          for (let [key, value] of Object.entries(data)) {              if (key.length > 0) { @@ -198,18 +184,54 @@ class StructuredContentGenerator {          }      } -    _createStructuredContentTableElement(tag, content, dictionary) { +    _createStructuredContentGenericElement(content, dictionary, language) { +        const {tag} = content; +        switch (tag) { +            case 'br': +                return this._createStructuredContentElement(tag, content, dictionary, language, 'simple', false, false); +            case 'ruby': +            case 'rt': +            case 'rp': +                return this._createStructuredContentElement(tag, content, dictionary, language, 'simple', true, false); +            case 'table': +                return this._createStructuredContentTableElement(tag, content, dictionary, language); +            case 'thead': +            case 'tbody': +            case 'tfoot': +            case 'tr': +                return this._createStructuredContentElement(tag, content, dictionary, language, 'table', true, false); +            case 'th': +            case 'td': +                return this._createStructuredContentElement(tag, content, dictionary, language, 'table-cell', true, true); +            case 'div': +            case 'span': +            case 'ol': +            case 'ul': +            case 'li': +                return this._createStructuredContentElement(tag, content, dictionary, language, 'simple', true, true); +            case 'img': +                return this.createDefinitionImage(content, dictionary); +            case 'a': +                return this._createLinkElement(content, dictionary, language); +        } +        return null; +    } + +    _createStructuredContentTableElement(tag, content, dictionary, language) {          const container = this._createElement('div', 'gloss-sc-table-container'); -        const table = this._createStructuredContentElement(tag, content, dictionary, 'table', true, false); +        const table = this._createStructuredContentElement(tag, content, dictionary, language, 'table', true, false);          container.appendChild(table);          return container;      } -    _createStructuredContentElement(tag, content, dictionary, type, hasChildren, hasStyle) { +    _createStructuredContentElement(tag, content, dictionary, language, type, hasChildren, hasStyle) {          const node = this._createElement(tag, `gloss-sc-${tag}`);          const {data, lang} = content;          if (typeof data === 'object' && data !== null) { this._setElementDataset(node, data); } -        if (typeof lang === 'string') { node.lang = lang; } +        if (typeof lang === 'string') { +            node.lang = lang; +            language = lang; +        }          switch (type) {              case 'table-cell':                  { @@ -226,8 +248,7 @@ class StructuredContentGenerator {              }          }          if (hasChildren) { -            const child = this.createStructuredContent(content.content, dictionary); -            if (child !== null) { node.appendChild(child); } +            this._appendStructuredContent(node, content.content, dictionary, language);          }          return node;      } @@ -262,7 +283,7 @@ class StructuredContentGenerator {          if (typeof listStyleType === 'string') { style.listStyleType = listStyleType; }      } -    _createLinkElement(content, dictionary) { +    _createLinkElement(content, dictionary, language) {          let {href} = content;          const internal = href.startsWith('?');          if (internal) { @@ -276,10 +297,12 @@ class StructuredContentGenerator {          node.appendChild(text);          const {lang} = content; -        if (typeof lang === 'string') { node.lang = lang; } +        if (typeof lang === 'string') { +            node.lang = lang; +            language = lang; +        } -        const child = this.createStructuredContent(content.content, dictionary); -        if (child !== null) { text.appendChild(child); } +        this._appendStructuredContent(text, content.content, dictionary, language);          if (!internal) {              const icon = this._createElement('span', 'gloss-link-external-icon icon'); diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index c75f92d3..45dda06c 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -536,7 +536,7 @@ class AnkiTemplateRenderer {      _createStructuredContentGenerator(data) {          const contentManager = new AnkiTemplateRendererContentManager(this._mediaProvider, data); -        const instance = new StructuredContentGenerator(contentManager, document); +        const instance = new StructuredContentGenerator(contentManager, this._japaneseUtil, document);          this._cleanupCallbacks.push(() => contentManager.unloadAll());          return instance;      } |