diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2021-05-19 18:24:50 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-05-19 18:24:50 -0400 | 
| commit | eddd0288643f08d2a2c85f73575bc7ee1c157539 (patch) | |
| tree | bbcc7dd1279f4954324eccc34d6bf718ff1899aa /ext/js | |
| parent | ae89a8f2ad6274f77afbc0c8c202c0fbc0dc8757 (diff) | |
Add support for definitions with structured content (#1689)
* Add structured content to schema
* Add support for generating custom content
* Update importer
* Update test data
* Add verticalAlign property
Diffstat (limited to 'ext/js')
| -rw-r--r-- | ext/js/display/display-generator.js | 51 | ||||
| -rw-r--r-- | ext/js/language/dictionary-importer.js | 50 | 
2 files changed, 94 insertions, 7 deletions
| diff --git a/ext/js/display/display-generator.js b/ext/js/display/display-generator.js index 299d730b..2131d805 100644 --- a/ext/js/display/display-generator.js +++ b/ext/js/display/display-generator.js @@ -295,6 +295,8 @@ class DisplayGenerator {              switch (entry.type) {                  case 'image':                      return this._createTermDefinitionEntryImage(entry, dictionary); +                case 'structured-content': +                    return this._createTermDefinitionEntryStructuredContent(entry.content, dictionary);              }          } @@ -327,8 +329,18 @@ class DisplayGenerator {          return node;      } +    _createTermDefinitionEntryStructuredContent(content, dictionary) { +        const node = this._templates.instantiate('gloss-item'); +        const child = this._createStructuredContent(content, dictionary); +        if (child !== null) { +            const contentContainer = node.querySelector('.gloss-content'); +            contentContainer.appendChild(child); +        } +        return node; +    } +      _createDefinitionImage(data, dictionary) { -        const {path, width, height, preferredWidth, preferredHeight, title, pixelated, collapsed, collapsible} = data; +        const {path, width, height, preferredWidth, preferredHeight, title, pixelated, collapsed, collapsible, verticalAlign} = data;          const usedWidth = (              typeof preferredWidth === 'number' ? @@ -349,6 +361,9 @@ class DisplayGenerator {          node.dataset.hasAspectRatio = 'true';          node.dataset.collapsed = typeof collapsed === 'boolean' ? `${collapsed}` : 'false';          node.dataset.collapsible = typeof collapsible === 'boolean' ? `${collapsible}` : 'true'; +        if (typeof verticalAlign === 'string') { +            node.dataset.verticalAlign = verticalAlign; +        }          const imageContainer = node.querySelector('.gloss-image-container');          imageContainer.style.width = `${usedWidth}em`; @@ -386,6 +401,40 @@ class DisplayGenerator {          }      } +    _createStructuredContent(content, dictionary) { +        if (typeof content === 'string') { +            return document.createTextNode(content); +        } +        if (!(typeof content === 'object' && content !== null)) { +            return null; +        } +        if (Array.isArray(content)) { +            const fragment = document.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 'ruby': +            case 'rt': +            case 'rp': +            { +                const node = document.createElement(tag); +                const child = this._createStructuredContent(content.content, dictionary); +                if (child !== null) { +                    node.appendChild(child); +                } +                return node; +            } +            case 'img': +                return this._createDefinitionImage(content, dictionary); +        } +        return null; +    } +      _createTermDisambiguation(disambiguation) {          const node = this._templates.instantiate('definition-disambiguation');          node.dataset.term = disambiguation; diff --git a/ext/js/language/dictionary-importer.js b/ext/js/language/dictionary-importer.js index 051375a0..4d885a74 100644 --- a/ext/js/language/dictionary-importer.js +++ b/ext/js/language/dictionary-importer.js @@ -300,20 +300,58 @@ class DictionaryImporter {                  return data.text;              case 'image':                  return await this._formatDictionaryTermGlossaryImage(data, context, entry); +            case 'structured-content': +                return await this._formatStructuredContent(data, context, entry);              default:                  throw new Error(`Unhandled data type: ${data.type}`);          }      }      async _formatDictionaryTermGlossaryImage(data, context, entry) { +        return await this._createImageData(data, context, entry, {type: 'image'}); +    } + +    async _formatStructuredContent(data, context, entry) { +        const content = await this._prepareStructuredContent(data.content, context, entry); +        return { +            type: 'structured-content', +            content +        }; +    } + +    async _prepareStructuredContent(content, context, entry) { +        if (typeof content === 'string' || !(typeof content === 'object' && content !== null)) { +            return content; +        } +        if (Array.isArray(content)) { +            for (let i = 0, ii = content.length; i < ii; ++i) { +                content[i] = await this._prepareStructuredContent(content[i], context, entry); +            } +            return content; +        } +        const {tag} = content; +        switch (tag) { +            case 'img': +                return await this._prepareStructuredContentImage(content, context, entry); +        } +        const childContent = content.content; +        if (typeof childContent !== 'undefined') { +            content.content = await this._prepareStructuredContent(childContent, context, entry); +        } +        return content; +    } + +    async _prepareStructuredContentImage(content, context, entry) { +        const {verticalAlign} = content; +        const result = await this._createImageData(content, context, entry, {tag: 'img'}); +        if (typeof verticalAlign === 'string') { result.verticalAlign = verticalAlign; } +        return result; +    } + +    async _createImageData(data, context, entry, attributes) {          const {path, width: preferredWidth, height: preferredHeight, title, description, pixelated, collapsed, collapsible} = data;          const {width, height} = await this._getImageMedia(path, context, entry); -        const newData = { -            type: 'image', -            path, -            width, -            height -        }; +        const newData = Object.assign({}, attributes, {path, width, height});          if (typeof preferredWidth === 'number') { newData.preferredWidth = preferredWidth; }          if (typeof preferredHeight === 'number') { newData.preferredHeight = preferredHeight; }          if (typeof title === 'string') { newData.title = title; } |