From 0506cfbee5443635ebd6ac79054b85f171775039 Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 21:21:30 +0100 Subject: [PATCH 01/22] initial handlebars patch --- .../anki-field-templates-upgrade-v21.handlebars | 0 ext/js/data/options-util.js | 8 +++++++- test/test-options-util.js | 15 +++++++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 ext/data/templates/anki-field-templates-upgrade-v21.handlebars diff --git a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars new file mode 100644 index 0000000000..e69de29bb2 diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index 2674701f3f..7b0504169f 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -470,7 +470,8 @@ class OptionsUtil { {async: false, update: this._updateVersion17.bind(this)}, {async: false, update: this._updateVersion18.bind(this)}, {async: false, update: this._updateVersion19.bind(this)}, - {async: false, update: this._updateVersion20.bind(this)} + {async: false, update: this._updateVersion20.bind(this)}, + {async: true, update: this._updateVersion21.bind(this)} ]; if (typeof targetVersion === 'number' && targetVersion < result.length) { result.splice(targetVersion); @@ -997,4 +998,9 @@ class OptionsUtil { } return options; } + + async _updateVersion21(options) { + await this._applyAnkiFieldTemplatesPatch(options, '/data/templates/anki-field-templates-upgrade-v21.handlebars'); + return options; + } } diff --git a/test/test-options-util.js b/test/test-options-util.js index 2be6b2f737..068367a2e4 100644 --- a/test/test-options-util.js +++ b/test/test-options-util.js @@ -622,7 +622,7 @@ function createOptionsUpdatedTestData1() { } ], profileCurrent: 0, - version: 20, + version: 21, global: { database: { prefixWildcardsSupported: false @@ -689,7 +689,8 @@ async function testFieldTemplatesUpdate(extDir) { {version: 8, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v8.handlebars')}, {version: 10, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v10.handlebars')}, {version: 12, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v12.handlebars')}, - {version: 13, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v13.handlebars')} + {version: 13, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v13.handlebars')}, + {version: 21, changes: loadDataFile('data/templates/anki-field-templates-upgrade-v21.handlebars')} ]; const getUpdateAdditions = (startVersion, targetVersion) => { let value = ''; @@ -1214,6 +1215,16 @@ async function testFieldTemplatesUpdate(extDir) { {{! End Pitch Accents }} <<>> +{{~> (lookup . "marker") ~}}`.trimStart() + }, + // block helper update + { + oldVersion: 20, + newVersion: 21, + old: ` +{{~> (lookup . "marker") ~}}`.trimStart(), + + expected: ` {{~> (lookup . "marker") ~}}`.trimStart() } ]; From 9a78edaee74a8355d49ec930c82e118518d5d625 Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 21:23:47 +0100 Subject: [PATCH 02/22] fix: dumpObject --- docs/templates.md | 4 ++-- ext/js/templates/sandbox/anki-template-renderer.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index 778b8e2dba..c050889f35 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -14,7 +14,7 @@ This function can be helpful for debugging values when creating templates.
Syntax: - {{#dumpObject}}<object>{{/dumpObject}} + {{dumpObject object}} * _`object`_
The object to convert. @@ -23,7 +23,7 @@ This function can be helpful for debugging values when creating templates. Example: ```handlebars -
{{#dumpObject}}{{.}}{{/dumpObject}}
+
{{dumpObject .}}
``` Output: diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index 789f094246..9e0bc8edfd 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -134,8 +134,8 @@ class AnkiTemplateRenderer { // Template helpers - _dumpObject(context, options) { - const dump = JSON.stringify(options.fn(context), null, 4); + _dumpObject(context, object) { + const dump = JSON.stringify(object, null, 4); return this._escape(dump); } From ae91e2442d7b3746c633871ff956a8addd7046b5 Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 21:41:45 +0100 Subject: [PATCH 03/22] fix: furigana and furiganaPlain --- docs/templates.md | 16 ++-- ...nki-field-templates-upgrade-v21.handlebars | 30 +++++++ .../default-anki-field-templates.handlebars | 10 +-- .../sandbox/anki-template-renderer.js | 21 +++-- test/test-options-util.js | 80 ++++++++++++++++++- 5 files changed, 136 insertions(+), 21 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index c050889f35..bf5bd8972f 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -49,8 +49,8 @@ Converts a definition or expression/reading pair to its furigana representation.
Syntax: - {{#furigana}}<definition>{{/furigana}}
- {{#furigana expression reading}}{{/furigana}}
+ {{furigana definition}}
+ {{furigana expression reading}}
* _`definition`_
The definition to convert. @@ -63,8 +63,8 @@ Converts a definition or expression/reading pair to its furigana representation. Example: ```handlebars - {{#furigana}}{{.}}{{/furigana}} - {{#furigana "読む" "よむ"}}{{/furigana}} + {{furigana .}} + {{furigana "読む" "よむ"}} ``` Output: @@ -84,8 +84,8 @@ Converts a definition or expression/reading pair to its simplified furigana repr
Syntax: - {{#furiganaPlain}}<definition>{{/furigana}} - {{#furiganaPlain expression reading}}{{/furiganaPlain}}
+ {{furiganaPlain definition}} + {{furiganaPlain expression reading}}
* _`definition`_
The definition to convert. @@ -98,8 +98,8 @@ Converts a definition or expression/reading pair to its simplified furigana repr Example: ```handlebars - {{~#furiganaPlain~}}{{.}}{{~/furiganaPlain~}} - {{#furiganaPlain "読む" "よむ"}}{{/furiganaPlain}} + {{~furiganaPlain .~}} + {{furiganaPlain "読む" "よむ"}} ``` Output: diff --git a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars index e69de29bb2..92034995db 100644 --- a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars +++ b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars @@ -0,0 +1,30 @@ + +{{<<<<<<<}} +{{~#furigana}}{{{.}}}{{/furigana~}} +{{=======}} +{{~furigana .~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{#furigana}}{{{definition}}}{{/furigana}} +{{=======}} +{{furigana definition}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}} +{{=======}} +{{~furiganaPlain .~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}} +{{=======}} +{{furiganaPlain definition}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#furigana expression reading~}}{{~/furigana~}} +{{=======}} +{{~furigana expression reading~}} +{{>>>>>>>}} diff --git a/ext/data/templates/default-anki-field-templates.handlebars b/ext/data/templates/default-anki-field-templates.handlebars index 31d5d13fb9..751236f430 100644 --- a/ext/data/templates/default-anki-field-templates.handlebars +++ b/ext/data/templates/default-anki-field-templates.handlebars @@ -78,22 +78,22 @@ {{#*inline "furigana"}} {{~#if merge~}} {{~#each definition.expressions~}} - {{~#furigana}}{{{.}}}{{/furigana~}} + {{~furigana .~}} {{~#unless @last}}、{{/unless~}} {{~/each~}} {{~else~}} - {{#furigana}}{{{definition}}}{{/furigana}} + {{furigana definition}} {{~/if~}} {{/inline}} {{#*inline "furigana-plain"}} {{~#if merge~}} {{~#each definition.expressions~}} - {{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}} + {{~furiganaPlain .~}} {{~#unless @last}}、{{/unless~}} {{~/each~}} {{~else~}} - {{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}} + {{furiganaPlain definition}} {{~/if~}} {{/inline}} @@ -255,7 +255,7 @@
  • {{~#if (op "!==" ../definition.type "kanji")~}} {{~#if (op "||" (op ">" ../uniqueExpressions.length 1) (op ">" ../uniqueReadings.length 1))~}}( - {{~#furigana expression reading~}}{{~/furigana~}} + {{~furigana expression reading~}} ) {{/if~}} {{~/if~}} {{~dictionary}}: {{frequency~}} diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index 9e0bc8edfd..e15bf89569 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -132,6 +132,10 @@ class AnkiTemplateRenderer { return Handlebars.Utils.escapeExpression(text); } + _safeString(text) { + return new Handlebars.SafeString(text); + } + // Template helpers _dumpObject(context, object) { @@ -145,14 +149,16 @@ class AnkiTemplateRenderer { let result = ''; for (const {text, reading: reading2} of segs) { - if (reading2.length > 0) { - result += `${text}${reading2}`; + const safeText = this._escape(text); + const safeReading = this._escape(reading2); + if (safeReading.length > 0) { + result += `${safeText}${safeReading}`; } else { - result += text; + result += safeText; } } - return result; + return this._safeString(result); } _furiganaPlain(context, ...args) { @@ -173,12 +179,13 @@ class AnkiTemplateRenderer { } _getFuriganaExpressionAndReading(context, ...args) { - const options = args[args.length - 1]; if (args.length >= 3) { return {expression: args[0], reading: args[1]}; - } else { - const {expression, reading} = options.fn(context); + } else if (args.length === 2) { + const {expression, reading} = args[0]; return {expression, reading}; + } else { + return void 0; } } diff --git a/test/test-options-util.js b/test/test-options-util.js index 068367a2e4..e9504b0d73 100644 --- a/test/test-options-util.js +++ b/test/test-options-util.js @@ -1217,14 +1217,92 @@ async function testFieldTemplatesUpdate(extDir) { <<>> {{~> (lookup . "marker") ~}}`.trimStart() }, - // block helper update + // block helper update: furigana and furiganaPlain { oldVersion: 20, newVersion: 21, old: ` +{{#*inline "furigana"}} + {{~#if merge~}} + {{~#each definition.expressions~}} + {{~#furigana}}{{{.}}}{{/furigana~}} + {{~#unless @last}}、{{/unless~}} + {{~/each~}} + {{~else~}} + {{#furigana}}{{{definition}}}{{/furigana}} + {{~/if~}} +{{/inline}} + +{{#*inline "furigana-plain"}} + {{~#if merge~}} + {{~#each definition.expressions~}} + {{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}} + {{~#unless @last}}、{{/unless~}} + {{~/each~}} + {{~else~}} + {{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}} + {{~/if~}} +{{/inline}} + +{{#*inline "frequencies"}} + {{~#if (op ">" definition.frequencies.length 0)~}} +
      + {{~#each definition.frequencies~}} +
    • + {{~#if (op "!==" ../definition.type "kanji")~}} + {{~#if (op "||" (op ">" ../uniqueExpressions.length 1) (op ">" ../uniqueReadings.length 1))~}}( + {{~#furigana expression reading~}}{{~/furigana~}} + ) {{/if~}} + {{~/if~}} + {{~dictionary}}: {{frequency~}} +
    • + {{~/each~}} +
    + {{~/if~}} +{{/inline}} + {{~> (lookup . "marker") ~}}`.trimStart(), expected: ` +{{#*inline "furigana"}} + {{~#if merge~}} + {{~#each definition.expressions~}} + {{~furigana .~}} + {{~#unless @last}}、{{/unless~}} + {{~/each~}} + {{~else~}} + {{furigana definition}} + {{~/if~}} +{{/inline}} + +{{#*inline "furigana-plain"}} + {{~#if merge~}} + {{~#each definition.expressions~}} + {{~furiganaPlain .~}} + {{~#unless @last}}、{{/unless~}} + {{~/each~}} + {{~else~}} + {{furiganaPlain definition}} + {{~/if~}} +{{/inline}} + +{{#*inline "frequencies"}} + {{~#if (op ">" definition.frequencies.length 0)~}} +
      + {{~#each definition.frequencies~}} +
    • + {{~#if (op "!==" ../definition.type "kanji")~}} + {{~#if (op "||" (op ">" ../uniqueExpressions.length 1) (op ">" ../uniqueReadings.length 1))~}}( + {{~furigana expression reading~}} + ) {{/if~}} + {{~/if~}} + {{~dictionary}}: {{frequency~}} +
    • + {{~/each~}} +
    + {{~/if~}} +{{/inline}} + {{~> (lookup . "marker") ~}}`.trimStart() } ]; From 376a1b096874e601296321fa6307836e2736a05c Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 21:52:31 +0100 Subject: [PATCH 04/22] fix: formatGlossary --- docs/templates.md | 4 +- ...nki-field-templates-upgrade-v21.handlebars | 18 +++++ .../default-anki-field-templates.handlebars | 6 +- .../sandbox/anki-template-renderer.js | 5 +- test/test-options-util.js | 74 +++++++++++++++++++ 5 files changed, 99 insertions(+), 8 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index bf5bd8972f..ce1e8d7efc 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -657,7 +657,7 @@ structured-content generation.
    Syntax: - {{#formatGlossary dictionary}}{{{definitionEntry}}}{{/pitchCategories}}
    + {{formatGlossary dictionary definitionEntry}}
    * _`dictionary`_
    The dictionary that the glossary entry belongs to. @@ -668,7 +668,7 @@ structured-content generation. Example: ```handlebars - {{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{/each}} + {{#each glossary}}{{formatGlossary ../dictionary .}}{{/each}} ``` Output: diff --git a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars index 92034995db..99db50b604 100644 --- a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars +++ b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars @@ -1,4 +1,22 @@ +{{<<<<<<<}} +{{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{/each}} +{{=======}} +{{#each glossary}}{{formatGlossary ../dictionary .}}{{/each}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{#unless @last}} | {{/unless}}{{/each}} +{{=======}} +{{#each glossary}}{{formatGlossary ../dictionary .}}{{#unless @last}} | {{/unless}}{{/each}} +{{>>>>>>>}} + +{{<<<<<<<}} +
      {{#each glossary}}
    • {{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}
    • {{/each}}
    +{{=======}} +
      {{#each glossary}}
    • {{formatGlossary ../dictionary .}}
    • {{/each}}
    +{{>>>>>>>}} + {{<<<<<<<}} {{~#furigana}}{{{.}}}{{/furigana~}} {{=======}} diff --git a/ext/data/templates/default-anki-field-templates.handlebars b/ext/data/templates/default-anki-field-templates.handlebars index 751236f430..58bc68e259 100644 --- a/ext/data/templates/default-anki-field-templates.handlebars +++ b/ext/data/templates/default-anki-field-templates.handlebars @@ -21,11 +21,11 @@ {{~#if only~}}({{#each only}}{{.}}{{#unless @last}}, {{/unless}}{{/each}} only) {{/if~}} {{~/unless~}} {{~#if (op "<=" glossary.length 1)~}} - {{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{/each}} + {{#each glossary}}{{formatGlossary ../dictionary .}}{{/each}} {{~else if @root.compactGlossaries~}} - {{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{#unless @last}} | {{/unless}}{{/each}} + {{#each glossary}}{{formatGlossary ../dictionary .}}{{#unless @last}} | {{/unless}}{{/each}} {{~else~}} -
      {{#each glossary}}
    • {{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}
    • {{/each}}
    +
      {{#each glossary}}
    • {{formatGlossary ../dictionary .}}
    • {{/each}}
    {{~/if~}} {{~#set "previousDictionary" dictionary~}}{{~/set~}} {{/inline}} diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index e15bf89569..62bf71b8e7 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -497,7 +497,7 @@ class AnkiTemplateRenderer { this._normalizeHtml(container, styleApplier, datasetKeyIgnorePattern); const result = container.innerHTML; container.textContent = ''; - return result; + return this._safeString(result); } _normalizeHtml(root, styleApplier, datasetKeyIgnorePattern) { @@ -550,9 +550,8 @@ class AnkiTemplateRenderer { return instance; } - _formatGlossary(context, dictionary, options) { + _formatGlossary(context, dictionary, content, options) { const data = options.data.root; - const content = options.fn(context); if (typeof content === 'string') { return this._stringToMultiLineHtml(this._escape(content)); } if (!(typeof content === 'object' && content !== null)) { return ''; } switch (content.type) { diff --git a/test/test-options-util.js b/test/test-options-util.js index e9504b0d73..c27806505e 100644 --- a/test/test-options-util.js +++ b/test/test-options-util.js @@ -1303,6 +1303,80 @@ async function testFieldTemplatesUpdate(extDir) { {{~/if~}} {{/inline}} +{{~> (lookup . "marker") ~}}`.trimStart() + }, + // block helper update: formatGlossary + { + oldVersion: 20, + newVersion: 21, + old: ` +{{#*inline "glossary-single"}} + {{~#unless brief~}} + {{~#scope~}} + {{~#set "any" false}}{{/set~}} + {{~#each definitionTags~}} + {{~#if (op "||" (op "!" @root.compactTags) (op "!" redundant))~}} + {{~#if (get "any")}}, {{else}}({{/if~}} + {{name}} + {{~#set "any" true}}{{/set~}} + {{~/if~}} + {{~/each~}} + {{~#unless noDictionaryTag~}} + {{~#if (op "||" (op "!" @root.compactTags) (op "!==" dictionary (get "previousDictionary")))~}} + {{~#if (get "any")}}, {{else}}({{/if~}} + {{dictionary}} + {{~#set "any" true}}{{/set~}} + {{~/if~}} + {{~/unless~}} + {{~#if (get "any")}}) {{/if~}} + {{~/scope~}} + {{~#if only~}}({{#each only}}{{.}}{{#unless @last}}, {{/unless}}{{/each}} only) {{/if~}} + {{~/unless~}} + {{~#if (op "<=" glossary.length 1)~}} + {{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{/each}} + {{~else if @root.compactGlossaries~}} + {{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{#unless @last}} | {{/unless}}{{/each}} + {{~else~}} +
      {{#each glossary}}
    • {{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}
    • {{/each}}
    + {{~/if~}} + {{~#set "previousDictionary" dictionary~}}{{~/set~}} +{{/inline}} + +{{~> (lookup . "marker") ~}}`.trimStart(), + + expected: ` +{{#*inline "glossary-single"}} + {{~#unless brief~}} + {{~#scope~}} + {{~#set "any" false}}{{/set~}} + {{~#each definitionTags~}} + {{~#if (op "||" (op "!" @root.compactTags) (op "!" redundant))~}} + {{~#if (get "any")}}, {{else}}({{/if~}} + {{name}} + {{~#set "any" true}}{{/set~}} + {{~/if~}} + {{~/each~}} + {{~#unless noDictionaryTag~}} + {{~#if (op "||" (op "!" @root.compactTags) (op "!==" dictionary (get "previousDictionary")))~}} + {{~#if (get "any")}}, {{else}}({{/if~}} + {{dictionary}} + {{~#set "any" true}}{{/set~}} + {{~/if~}} + {{~/unless~}} + {{~#if (get "any")}}) {{/if~}} + {{~/scope~}} + {{~#if only~}}({{#each only}}{{.}}{{#unless @last}}, {{/unless}}{{/each}} only) {{/if~}} + {{~/unless~}} + {{~#if (op "<=" glossary.length 1)~}} + {{#each glossary}}{{formatGlossary ../dictionary .}}{{/each}} + {{~else if @root.compactGlossaries~}} + {{#each glossary}}{{formatGlossary ../dictionary .}}{{#unless @last}} | {{/unless}}{{/each}} + {{~else~}} +
      {{#each glossary}}
    • {{formatGlossary ../dictionary .}}
    • {{/each}}
    + {{~/if~}} + {{~#set "previousDictionary" dictionary~}}{{~/set~}} +{{/inline}} + {{~> (lookup . "marker") ~}}`.trimStart() } ]; From 68ff30006edcd0dca44326780d34a6ca39f65157 Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 21:54:53 +0100 Subject: [PATCH 05/22] fix: regexReplace and regexMatch joining the args together without cutting out the options arg can add an '[object Object]' into the result. --- docs/templates.md | 4 ++-- ext/js/templates/sandbox/anki-template-renderer.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index ce1e8d7efc..e0ea086137 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -147,7 +147,7 @@ Uses a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScr Syntax: {{#regexReplace regex replacement [flags]}}text-to-modify{{/regexReplace}}
    - {{#regexReplace regex replacement [flags] [text-to-modify]...}}{{/regexReplace}}
    + {{regexReplace regex replacement [flags] [text-to-modify]...}}
    * _`regex`_
    The raw string used to create the regular expression. This value is passed to the [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp) constructor. @@ -181,7 +181,7 @@ Uses a [regular expression](https://developer.mozilla.org/en-US/docs/Web/JavaScr Syntax: {{#regexMatch regex [flags]}}text-to-modify{{/regexMatch}}
    - {{#regexMatch regex [flags] [text-to-modify]...}}{{/regexMatch}}
    + {{regexMatch regex [flags] [text-to-modify]...}}
    * _`regex`_
    The raw string used to create the regular expression. This value is passed to the [`RegExp`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/RegExp) constructor. diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index 62bf71b8e7..5d8ebd3894 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -226,7 +226,7 @@ class AnkiTemplateRenderer { const options = args[argCount]; let value = typeof options.fn === 'function' ? options.fn(context) : ''; if (argCount > 3) { - value = `${args.slice(3).join('')}${value}`; + value = `${args.slice(3, -1).join('')}${value}`; } if (argCount > 1) { try { @@ -250,7 +250,7 @@ class AnkiTemplateRenderer { const options = args[argCount]; let value = typeof options.fn === 'function' ? options.fn(context) : ''; if (argCount > 2) { - value = `${args.slice(2).join('')}${value}`; + value = `${args.slice(2, -1).join('')}${value}`; } if (argCount > 0) { try { From 9f8269606fdf51765f6d13de4caac709691b0fea Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 22:11:29 +0100 Subject: [PATCH 06/22] update: set and get --- docs/templates.md | 20 ++-- ...nki-field-templates-upgrade-v21.handlebars | 61 ++++++++++ .../default-anki-field-templates.handlebars | 24 ++-- test/test-options-util.js | 110 +++++++++++++++++- 4 files changed, 189 insertions(+), 26 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index e0ea086137..e19309a775 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -351,7 +351,7 @@ Gets a value from the custom state stack.
    Syntax: - {{#get name}}{{/get}} + {{get name}} * _`name`_
    The name of the variable to get. @@ -360,7 +360,7 @@ Gets a value from the custom state stack. Example: ```handlebars - {{#get "some-text"}}{{/get}} + {{get "some-text"}} ``` Output: @@ -378,7 +378,7 @@ Assigns a value to the custom state stack. Syntax: {{#set name}}value{{/get}}
    - {{#set name value}}{{/get}}
    + {{set name value}}
    * _`name`_
    The name of the variable to assign. @@ -390,7 +390,7 @@ Assigns a value to the custom state stack. ```handlebars {{#set "some-text"}}This is the value of some-text!{{/set~}} - {{~#set "some-number" 32}}{{/set}} + {{~set "some-number" 32}} ``` Output: @@ -419,14 +419,14 @@ and variable lookups will start from the most recent scope and work backwards un Example: ```handlebars - {{~#set "key" 32}}{{/set~}} - {{~#get "key"}}{{/get~}}, + {{~set "key" 32~}} + {{~get "key"~}}, {{~#scope~}} - {{~#get "key"}}{{/get~}}, - {{~#set "key" 64}}{{/set~}} - {{~#get "key"}}{{/get~}}, + {{~#get "key"~}}, + {{~#set "key" 64~}} + {{~#get "key"~}}, {{~/scope~}} - {{~#get "key"}}{{/get~}} + {{~get "key"~}} ``` Output: diff --git a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars index 99db50b604..2fa0f0aa39 100644 --- a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars +++ b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars @@ -1,3 +1,14 @@ +{{<<<<<<<}} +{{~#set "any" false}}{{/set~}} +{{=======}} +{{~set "any" false~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "any" true}}{{/set~}} +{{=======}} +{{~set "any" true~}} +{{>>>>>>>}} {{<<<<<<<}} {{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{/each}} @@ -17,6 +28,12 @@
      {{#each glossary}}
    • {{formatGlossary ../dictionary .}}
    • {{/each}}
    {{>>>>>>>}} +{{<<<<<<<}} +{{~#set "previousDictionary" dictionary~}}{{~/set~}} +{{=======}} +{{~set "previousDictionary" dictionary~}} +{{>>>>>>>}} + {{<<<<<<<}} {{~#furigana}}{{{.}}}{{/furigana~}} {{=======}} @@ -46,3 +63,47 @@ {{=======}} {{~furigana expression reading~}} {{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "exclusive" (spread exclusiveExpressions exclusiveReadings)}}{{/set~}} +{{=======}} +{{~set "exclusive" (spread exclusiveExpressions exclusiveReadings)~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "separator" ""~}}{{/set~}} +{{=======}} +{{~set "separator" ""~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#get "separator"}}{{/get~}}{{{.}}} +{{=======}} +{{~get "separator"~}}{{{.}}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "found" false}}{{/set~}} +{{=======}} +{{~set "found" false~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "found" true}}{{/set~}} +{{=======}} +{{~set "found" true~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "first" true}}{{/set~}} +{{=======}} +{{~set "first" true~}} +{{>>>>>>>}} + +{{<<<<<<<}} + {{~#set (concat "used_" .) true~}}{{~/set~}} + {{~#set "first" false~}}{{~/set~}} +{{=======}} + {{~set (concat "used_" .) true~}} + {{~set "first" false~}} +{{>>>>>>>}} diff --git a/ext/data/templates/default-anki-field-templates.handlebars b/ext/data/templates/default-anki-field-templates.handlebars index 58bc68e259..69c7e7a19e 100644 --- a/ext/data/templates/default-anki-field-templates.handlebars +++ b/ext/data/templates/default-anki-field-templates.handlebars @@ -1,19 +1,19 @@ {{#*inline "glossary-single"}} {{~#unless brief~}} {{~#scope~}} - {{~#set "any" false}}{{/set~}} + {{~set "any" false~}} {{~#each definitionTags~}} {{~#if (op "||" (op "!" @root.compactTags) (op "!" redundant))~}} {{~#if (get "any")}}, {{else}}({{/if~}} {{name}} - {{~#set "any" true}}{{/set~}} + {{~set "any" true~}} {{~/if~}} {{~/each~}} {{~#unless noDictionaryTag~}} {{~#if (op "||" (op "!" @root.compactTags) (op "!==" dictionary (get "previousDictionary")))~}} {{~#if (get "any")}}, {{else}}({{/if~}} {{dictionary}} - {{~#set "any" true}}{{/set~}} + {{~set "any" true~}} {{~/if~}} {{~/unless~}} {{~#if (get "any")}}) {{/if~}} @@ -27,7 +27,7 @@ {{~else~}}
      {{#each glossary}}
    • {{formatGlossary ../dictionary .}}
    • {{/each}}
    {{~/if~}} - {{~#set "previousDictionary" dictionary~}}{{~/set~}} + {{~set "previousDictionary" dictionary~}} {{/inline}} {{#*inline "audio"}} @@ -189,11 +189,11 @@ {{#*inline "pitch-accent-item-disambiguation"}} {{~#scope~}} - {{~#set "exclusive" (spread exclusiveExpressions exclusiveReadings)}}{{/set~}} + {{~set "exclusive" (spread exclusiveExpressions exclusiveReadings)~}} {{~#if (op ">" (property (get "exclusive") "length") 0)~}} - {{~#set "separator" ""~}}{{/set~}} + {{~set "separator" ""~}} ({{#each (get "exclusive")~}} - {{~#get "separator"}}{{/get~}}{{{.}}} + {{~get "separator"~}}{{{.}}} {{~/each}} only) {{~/if~}} {{~/scope~}} @@ -267,10 +267,10 @@ {{#*inline "stroke-count"}} {{~#scope~}} - {{~#set "found" false}}{{/set~}} + {{~set "found" false~}} {{~#each definition.stats.misc~}} {{~#if (op "===" name "strokes")~}} - {{~#set "found" true}}{{/set~}} + {{~set "found" true~}} Stroke count: {{value}} {{~/if~}} {{~/each~}} @@ -295,14 +295,14 @@ {{#*inline "part-of-speech"}} {{~#scope~}} {{~#if (op "!==" definition.type "kanji")~}} - {{~#set "first" true}}{{/set~}} + {{~set "first" true~}} {{~#each definition.expressions~}} {{~#each wordClasses~}} {{~#unless (get (concat "used_" .))~}} {{~> part-of-speech-pretty . ~}} {{~#unless (get "first")}}, {{/unless~}} - {{~#set (concat "used_" .) true~}}{{~/set~}} - {{~#set "first" false~}}{{~/set~}} + {{~set (concat "used_" .) true~}} + {{~set "first" false~}} {{~/unless~}} {{~/each~}} {{~/each~}} diff --git a/test/test-options-util.js b/test/test-options-util.js index c27806505e..78204de9cb 100644 --- a/test/test-options-util.js +++ b/test/test-options-util.js @@ -1348,19 +1348,19 @@ async function testFieldTemplatesUpdate(extDir) { {{#*inline "glossary-single"}} {{~#unless brief~}} {{~#scope~}} - {{~#set "any" false}}{{/set~}} + {{~set "any" false~}} {{~#each definitionTags~}} {{~#if (op "||" (op "!" @root.compactTags) (op "!" redundant))~}} {{~#if (get "any")}}, {{else}}({{/if~}} {{name}} - {{~#set "any" true}}{{/set~}} + {{~set "any" true~}} {{~/if~}} {{~/each~}} {{~#unless noDictionaryTag~}} {{~#if (op "||" (op "!" @root.compactTags) (op "!==" dictionary (get "previousDictionary")))~}} {{~#if (get "any")}}, {{else}}({{/if~}} {{dictionary}} - {{~#set "any" true}}{{/set~}} + {{~set "any" true~}} {{~/if~}} {{~/unless~}} {{~#if (get "any")}}) {{/if~}} @@ -1374,7 +1374,109 @@ async function testFieldTemplatesUpdate(extDir) { {{~else~}}
      {{#each glossary}}
    • {{formatGlossary ../dictionary .}}
    • {{/each}}
    {{~/if~}} - {{~#set "previousDictionary" dictionary~}}{{~/set~}} + {{~set "previousDictionary" dictionary~}} +{{/inline}} + +{{~> (lookup . "marker") ~}}`.trimStart() + }, + // block helper update: set and get + { + oldVersion: 20, + newVersion: 21, + old: ` +{{#*inline "pitch-accent-item-disambiguation"}} + {{~#scope~}} + {{~#set "exclusive" (spread exclusiveExpressions exclusiveReadings)}}{{/set~}} + {{~#if (op ">" (property (get "exclusive") "length") 0)~}} + {{~#set "separator" ""~}}{{/set~}} + ({{#each (get "exclusive")~}} + {{~#get "separator"}}{{/get~}}{{{.}}} + {{~/each}} only) + {{~/if~}} + {{~/scope~}} +{{/inline}} + +{{#*inline "stroke-count"}} + {{~#scope~}} + {{~#set "found" false}}{{/set~}} + {{~#each definition.stats.misc~}} + {{~#if (op "===" name "strokes")~}} + {{~#set "found" true}}{{/set~}} + Stroke count: {{value}} + {{~/if~}} + {{~/each~}} + {{~#if (op "!" (get "found"))~}} + Stroke count: Unknown + {{~/if~}} + {{~/scope~}} +{{/inline}} + +{{#*inline "part-of-speech"}} + {{~#scope~}} + {{~#if (op "!==" definition.type "kanji")~}} + {{~#set "first" true}}{{/set~}} + {{~#each definition.expressions~}} + {{~#each wordClasses~}} + {{~#unless (get (concat "used_" .))~}} + {{~> part-of-speech-pretty . ~}} + {{~#unless (get "first")}}, {{/unless~}} + {{~#set (concat "used_" .) true~}}{{~/set~}} + {{~#set "first" false~}}{{~/set~}} + {{~/unless~}} + {{~/each~}} + {{~/each~}} + {{~#if (get "first")~}}Unknown{{~/if~}} + {{~/if~}} + {{~/scope~}} +{{/inline}} + +{{~> (lookup . "marker") ~}}`.trimStart(), + + expected: ` +{{#*inline "pitch-accent-item-disambiguation"}} + {{~#scope~}} + {{~set "exclusive" (spread exclusiveExpressions exclusiveReadings)~}} + {{~#if (op ">" (property (get "exclusive") "length") 0)~}} + {{~set "separator" ""~}} + ({{#each (get "exclusive")~}} + {{~get "separator"~}}{{{.}}} + {{~/each}} only) + {{~/if~}} + {{~/scope~}} +{{/inline}} + +{{#*inline "stroke-count"}} + {{~#scope~}} + {{~set "found" false~}} + {{~#each definition.stats.misc~}} + {{~#if (op "===" name "strokes")~}} + {{~set "found" true~}} + Stroke count: {{value}} + {{~/if~}} + {{~/each~}} + {{~#if (op "!" (get "found"))~}} + Stroke count: Unknown + {{~/if~}} + {{~/scope~}} +{{/inline}} + +{{#*inline "part-of-speech"}} + {{~#scope~}} + {{~#if (op "!==" definition.type "kanji")~}} + {{~set "first" true~}} + {{~#each definition.expressions~}} + {{~#each wordClasses~}} + {{~#unless (get (concat "used_" .))~}} + {{~> part-of-speech-pretty . ~}} + {{~#unless (get "first")}}, {{/unless~}} + {{~set (concat "used_" .) true~}} + {{~set "first" false~}} + {{~/unless~}} + {{~/each~}} + {{~/each~}} + {{~#if (get "first")~}}Unknown{{~/if~}} + {{~/if~}} + {{~/scope~}} {{/inline}} {{~> (lookup . "marker") ~}}`.trimStart() From 9b798601b48a40b65e38b433924a99d155872ba7 Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 22:25:30 +0100 Subject: [PATCH 07/22] update: hasMedia and getMedia --- docs/templates.md | 18 ++-- ...nki-field-templates-upgrade-v21.handlebars | 36 ++++++++ .../default-anki-field-templates.handlebars | 12 +-- test/test-options-util.js | 82 +++++++++++++++++++ 4 files changed, 133 insertions(+), 15 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index e19309a775..0aa26b84f1 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -686,8 +686,8 @@ These functions are used together in order to request media and other types of o
    Syntax: - {{#hasMedia type args...}}{{/hasMedia}}
    - {{#getMedia type args... [escape=true|false]}}{{/getMedia}}
    + {{hasMedia type args...}}
    + {{getMedia type args... [escape=true|false]}}
    * _`type`_
    The type of media to check for. @@ -710,19 +710,19 @@ These functions are used together in order to request media and other types of o Examples: ```handlebars - {{#if (hasMedia "audio")}}The audio file name is: {{#getMedia "audio"}}{{/getMedia}}{{/if}} + {{#if (hasMedia "audio")}}The audio file name is: {{getMedia "audio"}}{{/if}} - {{#if (hasMedia "screenshot")}}The screenshot file name is: {{#getMedia "screenshot"}}{{/getMedia}}{{/if}} + {{#if (hasMedia "screenshot")}}The screenshot file name is: {{getMedia "screenshot"}}{{/if}} - {{#if (hasMedia "clipboardImage")}}The clipboard image file name is: {{#getMedia "clipboardImage"}}{{/getMedia}}{{/if}} + {{#if (hasMedia "clipboardImage")}}The clipboard image file name is: {{getMedia "clipboardImage"}}{{/if}} - {{#if (hasMedia "clipboardText")}}The clipboard text is: {{#getMedia "clipboardText"}}{{/getMedia}}{{/if}} + {{#if (hasMedia "clipboardText")}}The clipboard text is: {{getMedia "clipboardText"}}{{/if}} - {{#if (hasMedia "selectionText")}}The selection text is: {{#getMedia "selectionText"}}{{/getMedia}}{{/if}} + {{#if (hasMedia "selectionText")}}The selection text is: {{getMedia "selectionText"}}{{/if}} - {{#if (hasMedia "textFurigana" "日本語")}}This is an example of text with generated furigana: {{#getMedia "textFurigana" "日本語" escape=false}}{{/getMedia}}{{/if}} + {{#if (hasMedia "textFurigana" "日本語")}}This is an example of text with generated furigana: {{getMedia "textFurigana" "日本語" escape=false}}{{/if}} - {{#if (hasMedia "dictionaryMedia" "image.png" dictionary="Example Dictionary")}}The remapped file name for image.png is: {{#getMedia "dictionaryMedia" "image.png" dictionary="Example Dictionary"}}{{/getMedia}}{{/if}} + {{#if (hasMedia "dictionaryMedia" "image.png" dictionary="Example Dictionary")}}The remapped file name for image.png is: {{getMedia "dictionaryMedia" "image.png" dictionary="Example Dictionary"}}{{/if}} ``` Output: diff --git a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars index 2fa0f0aa39..0bfd95a544 100644 --- a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars +++ b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars @@ -34,6 +34,12 @@ {{~set "previousDictionary" dictionary~}} {{>>>>>>>}} +{{<<<<<<<}} +[sound:{{#getMedia "audio"}}{{/getMedia}}] +{{=======}} +[sound:{{getMedia "audio"}}] +{{>>>>>>>}} + {{<<<<<<<}} {{~#furigana}}{{{.}}}{{/furigana~}} {{=======}} @@ -58,6 +64,24 @@ {{furiganaPlain definition}} {{>>>>>>>}} +{{<<<<<<<}} + +{{=======}} + +{{>>>>>>>}} + +{{<<<<<<<}} + +{{=======}} + +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#if (hasMedia "clipboardText")}}{{#getMedia "clipboardText"}}{{/getMedia}}{{/if~}} +{{=======}} +{{~#if (hasMedia "clipboardText")}}{{getMedia "clipboardText"}}{{/if~}} +{{>>>>>>>}} + {{<<<<<<<}} {{~#furigana expression reading~}}{{~/furigana~}} {{=======}} @@ -107,3 +131,15 @@ {{~set (concat "used_" .) true~}} {{~set "first" false~}} {{>>>>>>>}} + +{{<<<<<<<}} +{{~#if (hasMedia "selectionText")}}{{#getMedia "selectionText"}}{{/getMedia}}{{/if~}} +{{=======}} +{{~#if (hasMedia "selectionText")}}{{getMedia "selectionText"}}{{/if~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{#getMedia "textFurigana" definition.cloze.sentence escape=false}}{{/getMedia}} +{{=======}} +{{getMedia "textFurigana" definition.cloze.sentence escape=false}} +{{>>>>>>>}} diff --git a/ext/data/templates/default-anki-field-templates.handlebars b/ext/data/templates/default-anki-field-templates.handlebars index 69c7e7a19e..08950f78aa 100644 --- a/ext/data/templates/default-anki-field-templates.handlebars +++ b/ext/data/templates/default-anki-field-templates.handlebars @@ -32,7 +32,7 @@ {{#*inline "audio"}} {{~#if (hasMedia "audio")~}} - [sound:{{#getMedia "audio"}}{{/getMedia}}] + [sound:{{getMedia "audio"}}] {{~/if~}} {{/inline}} @@ -174,7 +174,7 @@ {{#*inline "screenshot"}} {{~#if (hasMedia "screenshot")~}} - + {{~/if~}} {{/inline}} @@ -231,12 +231,12 @@ {{#*inline "clipboard-image"}} {{~#if (hasMedia "clipboardImage")~}} - + {{~/if~}} {{/inline}} {{#*inline "clipboard-text"}} - {{~#if (hasMedia "clipboardText")}}{{#getMedia "clipboardText"}}{{/getMedia}}{{/if~}} + {{~#if (hasMedia "clipboardText")}}{{getMedia "clipboardText"}}{{/if~}} {{/inline}} {{#*inline "conjugation"}} @@ -316,13 +316,13 @@ {{/inline}} {{#*inline "selection-text"}} - {{~#if (hasMedia "selectionText")}}{{#getMedia "selectionText"}}{{/getMedia}}{{/if~}} + {{~#if (hasMedia "selectionText")}}{{getMedia "selectionText"}}{{/if~}} {{/inline}} {{#*inline "sentence-furigana"}} {{~#if definition.cloze~}} {{~#if (hasMedia "textFurigana" definition.cloze.sentence)~}} - {{#getMedia "textFurigana" definition.cloze.sentence escape=false}}{{/getMedia}} + {{getMedia "textFurigana" definition.cloze.sentence escape=false}} {{~else~}} {{definition.cloze.sentence}} {{~/if~}} diff --git a/test/test-options-util.js b/test/test-options-util.js index 78204de9cb..23cfc1217c 100644 --- a/test/test-options-util.js +++ b/test/test-options-util.js @@ -1479,6 +1479,88 @@ async function testFieldTemplatesUpdate(extDir) { {{~/scope~}} {{/inline}} +{{~> (lookup . "marker") ~}}`.trimStart() + }, + // block helper update: hasMedia and getMedia + { + oldVersion: 20, + newVersion: 21, + old: ` +{{#*inline "audio"}} + {{~#if (hasMedia "audio")~}} + [sound:{{#getMedia "audio"}}{{/getMedia}}] + {{~/if~}} +{{/inline}} + +{{#*inline "screenshot"}} + {{~#if (hasMedia "screenshot")~}} + + {{~/if~}} +{{/inline}} + +{{#*inline "clipboard-image"}} + {{~#if (hasMedia "clipboardImage")~}} + + {{~/if~}} +{{/inline}} + +{{#*inline "clipboard-text"}} + {{~#if (hasMedia "clipboardText")}}{{#getMedia "clipboardText"}}{{/getMedia}}{{/if~}} +{{/inline}} + +{{#*inline "selection-text"}} + {{~#if (hasMedia "selectionText")}}{{#getMedia "selectionText"}}{{/getMedia}}{{/if~}} +{{/inline}} + +{{#*inline "sentence-furigana"}} + {{~#if definition.cloze~}} + {{~#if (hasMedia "textFurigana" definition.cloze.sentence)~}} + {{#getMedia "textFurigana" definition.cloze.sentence escape=false}}{{/getMedia}} + {{~else~}} + {{definition.cloze.sentence}} + {{~/if~}} + {{~/if~}} +{{/inline}} + +{{~> (lookup . "marker") ~}}`.trimStart(), + + expected: ` +{{#*inline "audio"}} + {{~#if (hasMedia "audio")~}} + [sound:{{getMedia "audio"}}] + {{~/if~}} +{{/inline}} + +{{#*inline "screenshot"}} + {{~#if (hasMedia "screenshot")~}} + + {{~/if~}} +{{/inline}} + +{{#*inline "clipboard-image"}} + {{~#if (hasMedia "clipboardImage")~}} + + {{~/if~}} +{{/inline}} + +{{#*inline "clipboard-text"}} + {{~#if (hasMedia "clipboardText")}}{{getMedia "clipboardText"}}{{/if~}} +{{/inline}} + +{{#*inline "selection-text"}} + {{~#if (hasMedia "selectionText")}}{{getMedia "selectionText"}}{{/if~}} +{{/inline}} + +{{#*inline "sentence-furigana"}} + {{~#if definition.cloze~}} + {{~#if (hasMedia "textFurigana" definition.cloze.sentence)~}} + {{getMedia "textFurigana" definition.cloze.sentence escape=false}} + {{~else~}} + {{definition.cloze.sentence}} + {{~/if~}} + {{~/if~}} +{{/inline}} + {{~> (lookup . "marker") ~}}`.trimStart() } ]; From 4527cc03fe88cd747d0eb62a65d9d54247653483 Mon Sep 17 00:00:00 2001 From: praschke Date: Tue, 17 Oct 2023 22:35:34 +0100 Subject: [PATCH 08/22] update: pronunciation --- docs/templates.md | 4 ++-- ...anki-field-templates-upgrade-v21.handlebars | 6 ++++++ .../default-anki-field-templates.handlebars | 2 +- test/test-options-util.js | 18 ++++++++++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index 0aa26b84f1..f021dea60d 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -754,7 +754,7 @@ same as the system used for generating popup and search page dictionary entries.
    Syntax: - {{#pronunciation format=string reading=string downstepPosition=integer [nasalPositions=array] [devoicePositions=array]}}{{/pronunciation}}
    + {{pronunciation format=string reading=string downstepPosition=integer [nasalPositions=array] [devoicePositions=array]}}
    * _`format`_
    The format of the HTML to generate. This can be any of the following values: @@ -774,7 +774,7 @@ same as the system used for generating popup and search page dictionary entries. Example: ```handlebars - {{~#pronunciation format='text' reading='よむ' downstepPosition=1~}}{{~/pronunciation~}} + {{~pronunciation format='text' reading='よむ' downstepPosition=1~}} ```
    diff --git a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars index 0bfd95a544..4d88b812d6 100644 --- a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars +++ b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars @@ -82,6 +82,12 @@ {{~#if (hasMedia "clipboardText")}}{{getMedia "clipboardText"}}{{/if~}} {{>>>>>>>}} +{{<<<<<<<}} +{{~#pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}}{{~/pronunciation~}} +{{=======}} +{{~pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}} +{{>>>>>>>}} + {{<<<<<<<}} {{~#furigana expression reading~}}{{~/furigana~}} {{=======}} diff --git a/ext/data/templates/default-anki-field-templates.handlebars b/ext/data/templates/default-anki-field-templates.handlebars index 08950f78aa..d94f6d709f 100644 --- a/ext/data/templates/default-anki-field-templates.handlebars +++ b/ext/data/templates/default-anki-field-templates.handlebars @@ -184,7 +184,7 @@ {{! Pitch Accents }} {{#*inline "pitch-accent-item"}} - {{~#pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}}{{~/pronunciation~}} + {{~pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}} {{/inline}} {{#*inline "pitch-accent-item-disambiguation"}} diff --git a/test/test-options-util.js b/test/test-options-util.js index 23cfc1217c..d94028c05d 100644 --- a/test/test-options-util.js +++ b/test/test-options-util.js @@ -1561,6 +1561,24 @@ async function testFieldTemplatesUpdate(extDir) { {{~/if~}} {{/inline}} +{{~> (lookup . "marker") ~}}`.trimStart() + }, + // block helper update: pronunciation + { + oldVersion: 20, + newVersion: 21, + old: ` +{{#*inline "pitch-accent-item"}} + {{~#pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}}{{~/pronunciation~}} +{{/inline}} + +{{~> (lookup . "marker") ~}}`.trimStart(), + + expected: ` +{{#*inline "pitch-accent-item"}} + {{~pronunciation format=format reading=reading downstepPosition=position nasalPositions=nasalPositions devoicePositions=devoicePositions~}} +{{/inline}} + {{~> (lookup . "marker") ~}}`.trimStart() } ]; From a454cc3ca1c34e51de13fe21f375f1f47d96a1e9 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:02:41 +0100 Subject: [PATCH 09/22] remove kanjiLinks and sanitizeCssClass --- docs/templates.md | 57 ------------------- .../sandbox/anki-template-renderer.js | 20 ------- 2 files changed, 77 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index f021dea60d..86c60db947 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -842,60 +842,3 @@ Converts hiragana text to katakana. ヨミチャン ヨミチャン ヨミチャン ```
    - - -## Legacy Helpers - -Yomichan has historically used Handlebars templates to generate the HTML used on the search page and results popup. -To simplify the and improve Yomichan's capabilities, the HTML elements are now generated directly using a different process. - -As such, there are several leftover Handlebars helpers that do not have much utility for Anki templates, but are kept for compatibility purposes. - - -### `kanjiLinks` - -Replaces kanji characters in the text with linkified versions. - -
    - Syntax: - - {{#kanjiLinks}}text{{/kanjiLinks}} -
    -
    - Example: - - ```handlebars - {{#kanjiLinks}}読む{{/kanjiLinks}} - ``` - - Output: - ```html - む - ``` - - Preview: -
    -
    - - -### `sanitizeCssClass` - -Sanitizes text so it can be used as a CSS class name. - -
    - Syntax: - - {{#sanitizeCssClass}}text{{/sanitizeCssClass}} -
    -
    - Example: - - ```handlebars - {{#sanitizeCssClass}}some text with many types of characters !@#$%^ 読む{{/sanitizeCssClass}} - ``` - - Output: - ```html - some_text_with_many_types_of_characters________読む - ``` -
    diff --git a/ext/js/templates/sandbox/anki-template-renderer.js b/ext/js/templates/sandbox/anki-template-renderer.js index 5d8ebd3894..766c7798a4 100644 --- a/ext/js/templates/sandbox/anki-template-renderer.js +++ b/ext/js/templates/sandbox/anki-template-renderer.js @@ -68,9 +68,7 @@ class AnkiTemplateRenderer { ['dumpObject', this._dumpObject.bind(this)], ['furigana', this._furigana.bind(this)], ['furiganaPlain', this._furiganaPlain.bind(this)], - ['kanjiLinks', this._kanjiLinks.bind(this)], ['multiLine', this._multiLine.bind(this)], - ['sanitizeCssClass', this._sanitizeCssClass.bind(this)], ['regexReplace', this._regexReplace.bind(this)], ['regexMatch', this._regexMatch.bind(this)], ['mergeTags', this._mergeTags.bind(this)], @@ -189,20 +187,6 @@ class AnkiTemplateRenderer { } } - _kanjiLinks(context, options) { - const jp = this._japaneseUtil; - let result = ''; - for (const c of options.fn(context)) { - if (jp.isCodePointKanji(c.codePointAt(0))) { - result += `${c}`; - } else { - result += c; - } - } - - return result; - } - _stringToMultiLineHtml(string) { return string.split('\n').join('
    '); } @@ -211,10 +195,6 @@ class AnkiTemplateRenderer { return this._stringToMultiLineHtml(options.fn(context)); } - _sanitizeCssClass(context, options) { - return options.fn(context).replace(/[^_a-z0-9\u00a0-\uffff]/ig, '_'); - } - _regexReplace(context, ...args) { // Usage: // {{#regexReplace regex string [flags] [content]...}}content{{/regexReplace}} From 60a3740af9c4dbf08181ae74b71d753b5ea133dd Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:10:09 +0100 Subject: [PATCH 10/22] docs: mergeTags --- docs/templates.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index 86c60db947..6605012ad8 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -212,7 +212,7 @@ Creates a set of all unique tags for the definition and returns a text represent
    Syntax: - {{#mergeTags definition isGroupMode isMergeMode}}{{/mergeTags}} + {{mergeTags definition isGroupMode isMergeMode}} * _`definition`_
    The root definition object. @@ -225,7 +225,7 @@ Creates a set of all unique tags for the definition and returns a text represent Example: ```handlebars - {{~#mergeTags definition group merge}}{{/mergeTags~}} + {{~mergeTags definition group merge~}} ``` Output: From 383366bc064040e6b6323cce459019e0a147a636 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:13:43 +0100 Subject: [PATCH 11/22] docs: multiLine --- docs/templates.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index 6605012ad8..b7e75437f5 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -122,11 +122,11 @@ Replaces newline characters with a forced HTML line break `
    `. Example: ```handlebars - {{#kanjiLinks~}} + {{#multiLine~}} some multiline text - {{~/kanjiLinks}} + {{~/multiLine}} ``` Output: From f5145607ce2933fa9ae8cfb99e651a3dc3860fef Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:14:15 +0100 Subject: [PATCH 12/22] docs: spread --- docs/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates.md b/docs/templates.md index b7e75437f5..d27382fe29 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -279,7 +279,7 @@ This allows it to be used similar to an [`Array.concat`](https://developer.mozil
    Syntax: - {{#spread iterable1 iterable2 ... iterableN}}{{/spread}} + {{spread iterable1 iterable2 ... iterableN}} * _`iterableN`_
    A variable amount of iterable objects to combine into a single array. From daf3c0f44434ad79f7bbcdc518368396d43b8cf1 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:15:43 +0100 Subject: [PATCH 13/22] docs: op --- docs/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates.md b/docs/templates.md index d27382fe29..c1ef23b70e 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -331,7 +331,7 @@ If an unknown operator is specified, the `undefined` value is returned. ```handlebars {{#if (op "===" value1 value2)}}Values are equal{{/op~}}
    {{~#op "-" value1}}{{/op~}}
    - {{~#op "?:" value1 "a" "b"}}{{/op}} + {{~op "?:" value1 "a" "b"}} ``` Output: From 23a1ca60d65c0f896b954633792f2f4fc544a3d7 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:25:03 +0100 Subject: [PATCH 14/22] docs: property --- docs/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates.md b/docs/templates.md index c1ef23b70e..05a5247ab9 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -443,7 +443,7 @@ Repeatedly gets a property of an object.
    Syntax: - {{#property object property1 property2 ... propertyN}}{{/property}} + {{property object property1 property2 ... propertyN}} * _`object`_
    The initial object to use. From 881a7cd77d4894db490de274bf32119228137a21 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:26:35 +0100 Subject: [PATCH 15/22] docs: isMoraPitchHigh and getKanaMorae --- docs/templates.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index 05a5247ab9..b99702b352 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -494,7 +494,7 @@ Returns whether or not a mora will have a high pitch, given the index of the mor
    Syntax: - {{#isMoraPitchHigh index position}}{{/isMoraPitchHigh}} + {{isMoraPitchHigh index position}}
    Example: @@ -517,7 +517,7 @@ Returns an array of the mora for a kana string.
    Syntax: - {{#getKanaMorae kana-string}}{{/getKanaMorae}} + {{getKanaMorae kana-string}}
    Example: From feec5af726a3094405586be6d755be562dbe497f Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:27:14 +0100 Subject: [PATCH 16/22] docs: typeof this shouldn't be used as a block helper, the result may be non-portable --- docs/templates.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index b99702b352..f5eeb95e8b 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -543,7 +543,7 @@ Returns the type of a value.
    Syntax: - {{#typeof value}}{{/typeof}}
    + {{typeof value}}
    {{#typeof}}value{{/typeof}}
    * _`value`_
    @@ -553,8 +553,8 @@ Returns the type of a value. Example: ```handlebars - {{#typeof "よみちゃん"}}{{/typeof}} - {{#typeof 1}}{{/typeof}} + {{typeof "よみちゃん"}} + {{typeof 1}} {{#typeof}}よみちゃん{{/typeof}} ``` From 5dc0deb51239b2ed0ab04f3e232e3ceb6e93ea03 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:29:17 +0100 Subject: [PATCH 17/22] docs: join and concat --- docs/templates.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index f5eeb95e8b..3ae8c58e48 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -574,7 +574,7 @@ Joins the arguments to a single string with a separator, flattening any argument
    Syntax: - {{#join separator value1 value2 valueN...}}{{/join}}
    + {{join separator value1 value2 valueN...}}
    * _`separator`_
    The separator string to use between values. @@ -585,8 +585,8 @@ Joins the arguments to a single string with a separator, flattening any argument Example: ```handlebars - {{#set "index" 32}}{{/set~}} - {{~#join "_" "yomichan" (get "index") "value"}}{{/join}} + {{set "index" 32~}} + {{~join "_" "yomichan" (get "index") "value"}} ``` Output: @@ -603,7 +603,7 @@ Joins the arguments to a single string, without flattening arguments that are ar
    Syntax: - {{#concat value1 value1 valueN...}}{{/concat}}
    + {{concat value1 value1 valueN...}}
    * _`valueN`_
    A value to join into the resulting string @@ -612,8 +612,8 @@ Joins the arguments to a single string, without flattening arguments that are ar Example: ```handlebars - {{#set "index" 32}}{{/set~}} - {{~#concat "yomichan_" (get "index") "_value"}}{{/concat}} + {{set "index" 32~}} + {{~concat "yomichan_" (get "index") "_value"}} ``` Output: From f6ffe2ffd7d610310521c79cdf9e4e776aa96de1 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:39:46 +0100 Subject: [PATCH 18/22] docs: pitchCategories --- docs/templates.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/templates.md b/docs/templates.md index 3ae8c58e48..94d4cc9317 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -630,7 +630,7 @@ Returns an array representing the different pitch categories for a specific term
    Syntax: - {{#pitchCategories @root}}{{/pitchCategories}}
    + {{pitchCategories @root}}
    * _`@root`_
    The argument passed should always be the root data object. From 18757dc0a0b8b2491864112fe07f8aed0aa74df0 Mon Sep 17 00:00:00 2001 From: praschke Date: Mon, 16 Oct 2023 23:47:47 +0100 Subject: [PATCH 19/22] docs: hiragana and katakana --- docs/templates.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/templates.md b/docs/templates.md index 94d4cc9317..dcdf9d1b67 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -786,7 +786,7 @@ Converts katakana text to hiragana.
    Syntax: - {{#hiragana value [keepProlongedSoundMarks=true|false]}}{{/hiragana}}
    + {{hiragana value [keepProlongedSoundMarks=true|false]}}
    {{#hiragana [keepProlongedSoundMarks=true|false]}}value{{/hiragana}}
    * _`value`_
    @@ -799,7 +799,7 @@ Converts katakana text to hiragana. Example: ```handlebars - {{#hiragana "よみちゃん ヨミちゃん ヨミチャン"}}{{/hiragana}} + {{hiragana "よみちゃん ヨミちゃん ヨミチャン"}} {{#hiragana}}よみちゃん ヨミちゃん ヨミチャン{{/hiragana}} {{#hiragana}}ローマ字{{/hiragana}} {{#hiragana keepProlongedSoundMarks=true}}ローマ字{{/hiragana}} @@ -822,7 +822,7 @@ Converts hiragana text to katakana.
    Syntax: - {{#katakana text}}{{/katakana}}
    + {{katakana text}}
    {{#katakana}}text{{/katakana}}
    * _`text`_
    @@ -832,7 +832,7 @@ Converts hiragana text to katakana. Example: ```handlebars - {{#katakana "よみちゃん ヨミちゃん ヨミチャン"}}{{/katakana}} + {{katakana "よみちゃん ヨミちゃん ヨミチャン"}} {{#katakana}}よみちゃん ヨミちゃん ヨミチャン{{/katakana}} ``` From 3b886960050e9c41071e032b0cf92d0d5ab547f5 Mon Sep 17 00:00:00 2001 From: praschke Date: Sun, 22 Oct 2023 14:33:33 +0100 Subject: [PATCH 20/22] catch a few more cases in the template patch --- ...nki-field-templates-upgrade-v21.handlebars | 98 ++++++++++--------- 1 file changed, 54 insertions(+), 44 deletions(-) diff --git a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars index 4d88b812d6..33c4dc6c02 100644 --- a/ext/data/templates/anki-field-templates-upgrade-v21.handlebars +++ b/ext/data/templates/anki-field-templates-upgrade-v21.handlebars @@ -1,85 +1,91 @@ {{<<<<<<<}} -{{~#set "any" false}}{{/set~}} +{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}} {{=======}} -{{~set "any" false~}} +{{formatGlossary ../dictionary .}} {{>>>>>>>}} {{<<<<<<<}} -{{~#set "any" true}}{{/set~}} +{{~#furigana}}{{{.}}}{{/furigana~}} {{=======}} -{{~set "any" true~}} +{{~furigana .~}} {{>>>>>>>}} {{<<<<<<<}} -{{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{/each}} +{{#furigana}}{{{definition}}}{{/furigana}} {{=======}} -{{#each glossary}}{{formatGlossary ../dictionary .}}{{/each}} +{{furigana definition}} {{>>>>>>>}} {{<<<<<<<}} -{{#each glossary}}{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}{{#unless @last}} | {{/unless}}{{/each}} +{{~#furigana expression reading~}}{{~/furigana~}} {{=======}} -{{#each glossary}}{{formatGlossary ../dictionary .}}{{#unless @last}} | {{/unless}}{{/each}} +{{~furigana expression reading~}} {{>>>>>>>}} {{<<<<<<<}} -
      {{#each glossary}}
    • {{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}
    • {{/each}}
    +{{~#furigana expression reading}}{{/furigana~}} {{=======}} -
      {{#each glossary}}
    • {{formatGlossary ../dictionary .}}
    • {{/each}}
    +{{~furigana expression reading~}} {{>>>>>>>}} {{<<<<<<<}} -{{~#set "previousDictionary" dictionary~}}{{~/set~}} +{{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}} {{=======}} -{{~set "previousDictionary" dictionary~}} +{{~furiganaPlain .~}} {{>>>>>>>}} {{<<<<<<<}} -[sound:{{#getMedia "audio"}}{{/getMedia}}] +{{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}} {{=======}} -[sound:{{getMedia "audio"}}] +{{furiganaPlain definition}} {{>>>>>>>}} {{<<<<<<<}} -{{~#furigana}}{{{.}}}{{/furigana~}} +{{~#furiganaPlain expression reading~}}{{~/furiganaPlain~}} {{=======}} -{{~furigana .~}} +{{~furiganaPlain expression reading~}} {{>>>>>>>}} {{<<<<<<<}} -{{#furigana}}{{{definition}}}{{/furigana}} +{{~#furiganaPlain expression reading}}{{/furiganaPlain~}} {{=======}} -{{furigana definition}} +{{~furiganaPlain expression reading~}} {{>>>>>>>}} {{<<<<<<<}} -{{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}} +{{#getMedia "audio"}}{{/getMedia}} {{=======}} -{{~furiganaPlain .~}} +{{getMedia "audio"}} {{>>>>>>>}} {{<<<<<<<}} -{{#furiganaPlain}}{{{definition}}}{{/furiganaPlain}} +{{#getMedia "screenshot"}}{{/getMedia}} {{=======}} -{{furiganaPlain definition}} +{{getMedia "screenshot"}} {{>>>>>>>}} {{<<<<<<<}} - +{{#getMedia "clipboardImage"}}{{/getMedia}} {{=======}} - +{{getMedia "clipboardImage"}} {{>>>>>>>}} {{<<<<<<<}} - +{{#getMedia "clipboardText"}}{{/getMedia}} {{=======}} - +{{getMedia "clipboardText"}} {{>>>>>>>}} {{<<<<<<<}} -{{~#if (hasMedia "clipboardText")}}{{#getMedia "clipboardText"}}{{/getMedia}}{{/if~}} +{{#getMedia "selectionText"}}{{/getMedia}} {{=======}} -{{~#if (hasMedia "clipboardText")}}{{getMedia "clipboardText"}}{{/if~}} +{{getMedia "selectionText"}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{#getMedia "textFurigana" definition.cloze.sentence escape=false}}{{/getMedia}} +{{=======}} +{{getMedia "textFurigana" definition.cloze.sentence escape=false}} {{>>>>>>>}} {{<<<<<<<}} @@ -89,9 +95,21 @@ {{>>>>>>>}} {{<<<<<<<}} -{{~#furigana expression reading~}}{{~/furigana~}} +{{~#set "any" false}}{{/set~}} {{=======}} -{{~furigana expression reading~}} +{{~set "any" false~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "any" true}}{{/set~}} +{{=======}} +{{~set "any" true~}} +{{>>>>>>>}} + +{{<<<<<<<}} +{{~#set "previousDictionary" dictionary~}}{{~/set~}} +{{=======}} +{{~set "previousDictionary" dictionary~}} {{>>>>>>>}} {{<<<<<<<}} @@ -107,9 +125,9 @@ {{>>>>>>>}} {{<<<<<<<}} -{{~#get "separator"}}{{/get~}}{{{.}}} +{{~#get "separator"}}{{/get~}} {{=======}} -{{~get "separator"~}}{{{.}}} +{{~get "separator"~}} {{>>>>>>>}} {{<<<<<<<}} @@ -131,21 +149,13 @@ {{>>>>>>>}} {{<<<<<<<}} - {{~#set (concat "used_" .) true~}}{{~/set~}} - {{~#set "first" false~}}{{~/set~}} +{{~#set "first" false~}}{{~/set~}} {{=======}} - {{~set (concat "used_" .) true~}} - {{~set "first" false~}} +{{~set "first" false~}} {{>>>>>>>}} {{<<<<<<<}} -{{~#if (hasMedia "selectionText")}}{{#getMedia "selectionText"}}{{/getMedia}}{{/if~}} +{{~#set (concat "used_" .) true~}}{{~/set~}} {{=======}} -{{~#if (hasMedia "selectionText")}}{{getMedia "selectionText"}}{{/if~}} -{{>>>>>>>}} - -{{<<<<<<<}} -{{#getMedia "textFurigana" definition.cloze.sentence escape=false}}{{/getMedia}} -{{=======}} -{{getMedia "textFurigana" definition.cloze.sentence escape=false}} +{{~set (concat "used_" .) true~}} {{>>>>>>>}} From f88bded2f05b440a8aa7beb980d8c5d76b150011 Mon Sep 17 00:00:00 2001 From: praschke Date: Sun, 22 Oct 2023 15:21:38 +0100 Subject: [PATCH 21/22] docs: note changes to custom templates in the readme --- README.md | 23 ++++++++++++++++++++++- docs/templates.md | 12 ++++++------ 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 0da2c61795..2c838645ac 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,8 @@ updates automatically. ## Migrating from Yomichan +### Exporting Data + If you are an existing user of Yomichan, you can export your dictionary collection and settings such that they can be imported into Yomitan to reflect your setup exactly as it was. You can export your settings from Yomichan's Settings page. Go to the `Backup` section and click on `Export Settings`. @@ -81,7 +83,26 @@ You can export your settings from Yomichan's Settings page. Go to the `Backup` s Yomichan doesn't have first-class support to export the dictionary collection. Please follow the instructions provided in the following link to export your data: https://github.com/themoeway/yomichan-data-exporter#steps-to-export-the-data -You can them import the exported files into Yomitan from the `Backup` section of the `Settings` page. Please see [the section on importing dictionaries](#importing-dictionaries) further below for more explicit steps. +You can then import the exported files into Yomitan from the `Backup` section of the `Settings` page. Please see [the section on importing dictionaries](#importing-dictionaries) further below for more explicit steps. + +### Custom Templates + +If you do not use custom templates for Anki note creation, this section can be skipped. + +Due to security concerns, an alternate implementation of Handlebars is being used which behaves slightly differently. +This revealed a bug in four of Yomitan's template helpers, which have now been fixed in the default templates. If your +custom templates use the following helpers, please ensure their use matches the corrected forms. + +Helper | Example | Corrected +-------|---------|---------- +`formatGlossary` | `{{#formatGlossary ../dictionary}}{{{.}}}{{/formatGlossary}}` | `{{formatGlossary ../dictionary .}}` +`furigana` | `{{#furigana}}{{{definition}}}{{/furigana}}` | `{{furigana definition}}` +`furiganaPlain` | `{{~#furiganaPlain}}{{{.}}}{{/furiganaPlain~}}` | `{{~furiganaPlain .~}}` +`dumpObject` | `{{#dumpObject}}{{{.}}}{{/dumpObject}}` | `{{dumpObject .}}` + +Authors of custom templates may be interested to know that other helpers previously used and documented in the block +form (e.g. `{{#set "key" "value"}}{{/set}}`), while not broken by this change, may also be replaced with the less verbose +form (e.g. `{{set "key" "value"}}`). The default templates and helper documentation have been changed to reflect this. ## Dictionaries diff --git a/docs/templates.md b/docs/templates.md index dcdf9d1b67..030ca3d247 100644 --- a/docs/templates.md +++ b/docs/templates.md @@ -235,9 +235,9 @@ Creates a set of all unique tags for the definition and returns a text represent
    -### `eachUpTo` +### `#eachUpTo` -Similar to the built-in `each` function, but iterates up to a maximum count. +Similar to the built-in `#each` function, but iterates up to a maximum count. If the iterable is falsy or empty, the `else` condition will be used.
    @@ -314,7 +314,7 @@ If an unknown operator is specified, the `undefined` value is returned.
    Syntax: - {{#op operator operand1 [operand2] [operand3]}}{{/op}} + {{op operator operand1 [operand2] [operand3]}} * _`operator`_
    One of the unary, binary, or ternary operators. @@ -329,7 +329,7 @@ If an unknown operator is specified, the `undefined` value is returned. Example: ```handlebars - {{#if (op "===" value1 value2)}}Values are equal{{/op~}}
    + {{#if (op "===" value1 value2)}}Values are equal{{/if~}}
    {{~#op "-" value1}}{{/op~}}
    {{~op "?:" value1 "a" "b"}} ``` @@ -399,7 +399,7 @@ Assigns a value to the custom state stack.
    -### `scope` +### `#scope` Pushes a new variable scope to the custom state stack. Variable assignments are applied to the most recent scope, @@ -538,7 +538,7 @@ Returns an array of the mora for a kana string. ### `typeof` -Returns the type of a value. +Returns the type of a value. Use of `#typeof` in the block form may be nonportable.
    Syntax: From 757707539690b6aec45e9de8cd37fdfc907d8843 Mon Sep 17 00:00:00 2001 From: praschke Date: Sun, 22 Oct 2023 17:23:04 +0100 Subject: [PATCH 22/22] warn about custom templates in the welcome page --- ext/css/settings.css | 7 +++++++ ext/js/background/backend.js | 20 ++++++-------------- ext/js/data/options-util.js | 27 +++++++++++++++++++++++++++ ext/js/pages/welcome-main.js | 7 +++++++ ext/welcome.html | 27 ++++++++++++++++++++++----- 5 files changed, 69 insertions(+), 19 deletions(-) diff --git a/ext/css/settings.css b/ext/css/settings.css index eaebc3af02..a2618d88c8 100644 --- a/ext/css/settings.css +++ b/ext/css/settings.css @@ -2167,6 +2167,13 @@ button.hotkey-list-item-enabled-button[data-scope-count='0'] { display: none; } +.warn-custom-templates-notification { + border: 1px solid var(--danger-color); +} +:root:not([data-warn-custom-templates=true]) .warn-custom-templates-notification { + display: none; +} + .test-anki-note-viewer-container { margin-top: 0.85em; display: flex; diff --git a/ext/js/background/backend.js b/ext/js/background/backend.js index 565f4abf3c..755010a30b 100644 --- a/ext/js/background/backend.js +++ b/ext/js/background/backend.js @@ -2099,20 +2099,12 @@ class Backend { } async _openWelcomeGuidePageOnce() { - if (isObject(chrome.storage) && isObject(chrome.storage.session)) { - // Chrome - chrome.storage.session.get(['openedWelcomePage']).then((result) => { - if (!result.openedWelcomePage) { - this._openWelcomeGuidePage(); - chrome.storage.session.set({'openedWelcomePage': true}); - } - }); - } else { - // Firefox (storage.session is not supported yet) - // NOTE: This means that the welcome page will repeatedly open in Firefox - // until they support storage.session. - this._openWelcomeGuidePage(); - } + chrome.storage.session.get(['openedWelcomePage']).then((result) => { + if (!result.openedWelcomePage) { + this._openWelcomeGuidePage(); + chrome.storage.session.set({'openedWelcomePage': true}); + } + }); } async _openWelcomeGuidePage() { diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index 7b0504169f..1f2ffb05fe 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -1001,6 +1001,33 @@ class OptionsUtil { async _updateVersion21(options) { await this._applyAnkiFieldTemplatesPatch(options, '/data/templates/anki-field-templates-upgrade-v21.handlebars'); + + let customTemplates = false; + for (const {options: profileOptions} of options.profiles) { + if (profileOptions.anki.fieldTemplates !== null) { + customTemplates = true; + } + } + + if (customTemplates && isObject(chrome.storage)) { + chrome.storage.session.set({'needsCustomTemplatesWarning': true}); + await this._createTab(chrome.runtime.getURL('/welcome.html')); + chrome.storage.session.set({'openedWelcomePage': true}); + } + return options; } + + _createTab(url) { + return new Promise((resolve, reject) => { + chrome.tabs.create({url}, (tab) => { + const e = chrome.runtime.lastError; + if (e) { + reject(new Error(e.message)); + } else { + resolve(tab); + } + }); + }); + } } diff --git a/ext/js/pages/welcome-main.js b/ext/js/pages/welcome-main.js index 521ce2c2de..8039dae5eb 100644 --- a/ext/js/pages/welcome-main.js +++ b/ext/js/pages/welcome-main.js @@ -58,6 +58,13 @@ async function setupGenericSettingsController(genericSettingController) { setupEnvironmentInfo(); + chrome.storage.session.get({'needsCustomTemplatesWarning': false}).then((result) => { + if (result.needsCustomTemplatesWarning) { + document.documentElement.dataset.warnCustomTemplates = 'true'; + chrome.storage.session.remove(['needsCustomTemplatesWarning']); + } + }); + const preparePromises = []; const modalController = new ModalController(); diff --git a/ext/welcome.html b/ext/welcome.html index 14e9836737..561678666d 100644 --- a/ext/welcome.html +++ b/ext/welcome.html @@ -25,6 +25,19 @@

    Welcome to Yomitan!

    + +
    +
    +
    +

    + There are custom Anki templates in your settings. Note that some syntax has changed from previous versions of Yomitan. + Please ensure that your custom templates are using the updated syntax. +

    +
    +
    +
    + +

    Here are some basics to get started

    @@ -49,10 +62,9 @@

    Here are some basics to get started

    Yomitan requires one or more dictionaries to be installed in order to look up terms, kanji, and other information. - Several downloadable dictionaries can be found on the Yomitan homepage, - allowing you to choose the dictionaries most relevant for you. + Several downloadable dictionaries can be found on the Yomitan homepage. Dictionaries can be configured using the button below, - or later from the the Settings page. + or later from the Settings page.
    @@ -67,12 +79,17 @@

    Here are some basics to get started

    - You can also import an exported collection of dictionaries to migrate from a different device or browser from the Backup section of the Settings page. + You can also import an exported collection of dictionaries from the Backup section of the Settings page.

    - If you are migrating from Yomichan, you may be particularly interested in migrating your data from Yomichan into Yomitan. + If you are migrating from Yomichan, you may be interested in importing your data into Yomitan. Please follow instructions from Yomitan's README for that. + +

    + + If you are using or planning to use custom templates for Anki note creation, note that some syntax has changed from Yomichan and Yomibaba. + Please ensure that your custom templates are using the updated syntax.