diff options
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/data/templates/anki-field-templates-upgrade-v29.handlebars | 13 | ||||
| -rw-r--r-- | ext/data/templates/default-anki-field-templates.handlebars | 4 | ||||
| -rw-r--r-- | ext/js/data/options-util.js | 12 | ||||
| -rw-r--r-- | ext/js/display/pronunciation-generator.js | 191 | ||||
| -rw-r--r-- | ext/js/templates/anki-template-renderer.js | 4 | ||||
| -rw-r--r-- | ext/settings.html | 4 | 
6 files changed, 226 insertions, 2 deletions
| diff --git a/ext/data/templates/anki-field-templates-upgrade-v29.handlebars b/ext/data/templates/anki-field-templates-upgrade-v29.handlebars new file mode 100644 index 00000000..e19d66c4 --- /dev/null +++ b/ext/data/templates/anki-field-templates-upgrade-v29.handlebars @@ -0,0 +1,13 @@ +{{<<<<<<<}} +{{#*inline "pitch-accent-graphs"}} +    {{~> pitch-accent-list format='graph'~}} +{{/inline}} +{{=======}} +{{#*inline "pitch-accent-graphs"}} +    {{~> pitch-accent-list format='graph'~}} +{{/inline}} + +{{#*inline "pitch-accent-graphs-jj"}} +    {{~> pitch-accent-list format='graph-jj'~}} +{{/inline}} +{{>>>>>>>}}
\ No newline at end of file diff --git a/ext/data/templates/default-anki-field-templates.handlebars b/ext/data/templates/default-anki-field-templates.handlebars index 0495af34..46d5c889 100644 --- a/ext/data/templates/default-anki-field-templates.handlebars +++ b/ext/data/templates/default-anki-field-templates.handlebars @@ -228,6 +228,10 @@      {{~> pitch-accent-list format='graph'~}}  {{/inline}} +{{#*inline "pitch-accent-graphs-jj"}} +    {{~> pitch-accent-list format='graph-jj'~}} +{{/inline}} +  {{#*inline "pitch-accent-positions"}}      {{~> pitch-accent-list format='position'~}}  {{/inline}} diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index d89b3370..af81f29e 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -534,7 +534,8 @@ export class OptionsUtil {              this._updateVersion25,              this._updateVersion26,              this._updateVersion27, -            this._updateVersion28 +            this._updateVersion28, +            this._updateVersion29          ];          /* eslint-enable @typescript-eslint/unbound-method */          if (typeof targetVersion === 'number' && targetVersion < result.length) { @@ -1209,6 +1210,15 @@ export class OptionsUtil {      }      /** +     *  - Added new handlebar for different pitch accent graph style. +     *  @type {import('options-util').UpdateFunction} +     */ +    async _updateVersion29(options) { +        await this._applyAnkiFieldTemplatesPatch(options, '/data/templates/anki-field-templates-upgrade-v29.handlebars'); +    } + + +    /**       * @param {string} url       * @returns {Promise<chrome.tabs.Tab>}       */ diff --git a/ext/js/display/pronunciation-generator.js b/ext/js/display/pronunciation-generator.js index 2c03eb94..e66df23c 100644 --- a/ext/js/display/pronunciation-generator.js +++ b/ext/js/display/pronunciation-generator.js @@ -234,3 +234,194 @@ function createGraphCircle(svgns, className, x, y, radius) {      node.setAttribute('r', radius);      return node;  } + +// The following Jidoujisho pitch graph code is based on code from +// https://github.com/lrorpilla/jidoujisho licensed under the +// GNU General Public License v3.0 + +/** + * Create a pronounciation graph in the style of Jidoujisho + * @param {string[]} mora + * @param {number} downstepPosition + * @returns {SVGSVGElement} + */ +export function createPronunciationGraphJJ(mora, downstepPosition) { +    const patt = pitchValueToPattJJ(mora.length, downstepPosition); + +    const positions = Math.max(mora.length, patt.length); +    const stepWidth = 35; +    const marginLr = 16; +    const svgWidth = Math.max(0, ((positions - 1) * stepWidth) + (marginLr * 2)); + +    const svgns = 'http://www.w3.org/2000/svg'; +    const svg = document.createElementNS(svgns, 'svg'); +    svg.setAttribute('xmlns', svgns); +    svg.setAttribute('width', `${(svgWidth * (3 / 5))}px`); +    svg.setAttribute('height', '45px'); +    svg.setAttribute('viewBox', `0 0 ${svgWidth} 75`); + + +    if (mora.length <= 0) { return svg; } + +    for (let i = 0; i < mora.length; i++) { +        const xCenter = marginLr + (i * stepWidth); +        textJJ(xCenter - 11, mora[i], svgns, svg); +    } + + +    let pathType = ''; + +    const circles = []; +    const paths = []; + +    let prevCenter = [-1, -1]; +    for (let i = 0; i < patt.length; i++) { +        const xCenter = marginLr + (i * stepWidth); +        const accent = patt[i]; +        let yCenter = 0; +        if (accent === 'H') { +            yCenter = 5; +        } else if (accent === 'L') { +            yCenter = 30; +        } +        circles.push(circleJJ(xCenter, yCenter, i >= mora.length, svgns)); + + +        if (i > 0) { +            if (prevCenter[1] === yCenter) { +                pathType = 's'; +            } else if (prevCenter[1] < yCenter) { +                pathType = 'd'; +            } else if (prevCenter[1] > yCenter) { +                pathType = 'u'; +            } +            paths.push(pathJJ(prevCenter[0], prevCenter[1], pathType, stepWidth, svgns)); +        } +        prevCenter = [xCenter, yCenter]; +    } + +    for (const path of paths) { +        svg.appendChild(path); +    } + +    for (const circle of circles) { +        svg.appendChild(circle); +    } + +    return svg; +} + +/** + * Get H&L pattern + * @param {number} numberOfMora + * @param {number} pitchValue + * @returns {string} + */ +function pitchValueToPattJJ(numberOfMora, pitchValue) { +    if (numberOfMora >= 1) { +        if (pitchValue === 0) { +        // Heiban +            return `L${'H'.repeat(numberOfMora)}`; +        } else if (pitchValue === 1) { +        // Atamadaka +            return `H${'L'.repeat(numberOfMora)}`; +        } else if (pitchValue >= 2) { +            const stepdown = pitchValue - 2; +            return `LH${'H'.repeat(stepdown)}${'L'.repeat(numberOfMora - pitchValue + 1)}`; +        } +    } +    return ''; +} + +/** + * @param {number} x + * @param {number} y + * @param {boolean} o + * @param {string} svgns + * @returns {Element} + */ +function circleJJ(x, y, o, svgns) { +    if (o) { +        const node = document.createElementNS(svgns, 'circle'); + +        node.setAttribute('r', '4'); +        node.setAttribute('cx', `${(x + 4)}`); +        node.setAttribute('cy', `${y}`); +        node.setAttribute('stroke', 'currentColor'); +        node.setAttribute('stroke-width', '2'); +        node.setAttribute('fill', 'none'); + +        return node; +    } else { +        const node = document.createElementNS(svgns, 'circle'); + +        node.setAttribute('r', '5'); +        node.setAttribute('cx', `${x}`); +        node.setAttribute('cy', `${y}`); +        node.setAttribute('style', 'opacity:1;fill:currentColor;'); + +        return node; +    } +} + +/** + * @param {number} x + * @param {string} mora + * @param {string} svgns + * @param {SVGSVGElement} svg + * @returns {void} + */ +function textJJ(x, mora, svgns, svg) { +    if (mora.length === 1) { +        const path = document.createElementNS(svgns, 'text'); +        path.setAttribute('x', `${x}`); +        path.setAttribute('y', '67.5'); +        path.setAttribute('style', 'font-size:20px;font-family:sans-serif;fill:currentColor;'); +        path.textContent = mora; +        svg.appendChild(path); +    } else { +        const path1 = document.createElementNS(svgns, 'text'); +        path1.setAttribute('x', `${x - 5}`); +        path1.setAttribute('y', '67.5'); +        path1.setAttribute('style', 'font-size:20px;font-family:sans-serif;fill:currentColor;'); +        path1.textContent = mora[0]; +        svg.appendChild(path1); + + +        const path2 = document.createElementNS(svgns, 'text'); +        path2.setAttribute('x', `${x + 12}`); +        path2.setAttribute('y', '67.5'); +        path2.setAttribute('style', 'font-size:14px;font-family:sans-serif;fill:currentColor;'); +        path2.textContent = mora[1]; +        svg.appendChild(path2); +    } +} + +/** + * @param {number} x + * @param {number} y + * @param {string} type + * @param {number} stepWidth + * @param {string} svgns + * @returns {Element} + */ +function pathJJ(x, y, type, stepWidth, svgns) { +    let delta = ''; +    switch (type) { +        case 's': +            delta = stepWidth + ',0'; +            break; +        case 'u': +            delta = stepWidth + ',-25'; +            break; +        case 'd': +            delta = stepWidth + ',25'; +            break; +    } + +    const path = document.createElementNS(svgns, 'path'); +    path.setAttribute('d', `m ${x},${y} ${delta}`); +    path.setAttribute('style', 'fill:none;stroke:currentColor;stroke-width:1.5;'); + +    return path; +} diff --git a/ext/js/templates/anki-template-renderer.js b/ext/js/templates/anki-template-renderer.js index 4bb56a4b..ae3e7a36 100644 --- a/ext/js/templates/anki-template-renderer.js +++ b/ext/js/templates/anki-template-renderer.js @@ -19,7 +19,7 @@  import {Handlebars} from '../../lib/handlebars.js';  import {createAnkiNoteData} from '../data/anki-note-data-creator.js';  import {getPronunciationsOfType, isNonNounVerbOrAdjective} from '../dictionary/dictionary-data-util.js'; -import {createPronunciationDownstepPosition, createPronunciationGraph, createPronunciationText} from '../display/pronunciation-generator.js'; +import {createPronunciationDownstepPosition, createPronunciationGraph, createPronunciationGraphJJ, createPronunciationText} from '../display/pronunciation-generator.js';  import {StructuredContentGenerator} from '../display/structured-content-generator.js';  import {CssStyleApplier} from '../dom/css-style-applier.js';  import {convertHiraganaToKatakana, convertKatakanaToHiragana, distributeFurigana, getKanaMorae, getPitchCategory, isMoraPitchHigh} from '../language/ja/japanese.js'; @@ -741,6 +741,8 @@ export class AnkiTemplateRenderer {              }              case 'graph':                  return this._getPronunciationHtml(createPronunciationGraph(morae, downstepPosition)); +            case 'graph-jj': +                return this._getPronunciationHtml(createPronunciationGraphJJ(morae, downstepPosition));              case 'position':                  return this._getPronunciationHtml(createPronunciationDownstepPosition(downstepPosition));              default: diff --git a/ext/settings.html b/ext/settings.html index 441e26df..773d7cb2 100644 --- a/ext/settings.html +++ b/ext/settings.html @@ -2979,6 +2979,10 @@                      <td>List of pitch accent graphs for the term.</td>                  </tr>                  <tr> +                    <td><code class="anki-field-marker">{pitch-accent-graphs-jj}</code></td> +                    <td>List of pitch accent graphs for the term (styled after Jidoujisho).</td> +                </tr> +                <tr>                      <td><code class="anki-field-marker">{pitch-accent-positions}</code></td>                      <td>List of accent downstep positions for the term as a number.</td>                  </tr> |