From 4197228e0072b3faf59abe4a83686b7b83076726 Mon Sep 17 00:00:00 2001 From: Kuuuube <61125188+Kuuuube@users.noreply.github.com> Date: Mon, 20 Jan 2025 19:12:41 -0500 Subject: [PATCH 1/2] Add minimumTouchTime setting to scanning inputs settings (#1764) --- ext/data/schemas/options-schema.json | 13 ++++++++++--- ext/js/data/options-util.js | 14 ++++++++++++++ ext/js/display/display.js | 1 + ext/js/language/text-scanner.js | 14 ++++++++++++++ ext/js/pages/settings/scan-inputs-controller.js | 5 +++++ ext/templates-settings.html | 4 ++++ test/options-util.test.js | 5 ++++- types/ext/settings.d.ts | 1 + types/ext/text-scanner.d.ts | 2 ++ 9 files changed, 55 insertions(+), 4 deletions(-) diff --git a/ext/data/schemas/options-schema.json b/ext/data/schemas/options-schema.json index 0cc3bc2e4d..86e35aced1 100644 --- a/ext/data/schemas/options-schema.json +++ b/ext/data/schemas/options-schema.json @@ -499,7 +499,8 @@ "scanOnPenPress": true, "scanOnPenRelease": false, "preventTouchScrolling": false, - "preventPenScrolling": false + "preventPenScrolling": false, + "minimumTouchTime": 0 } }, { @@ -524,7 +525,8 @@ "scanOnPenPress": true, "scanOnPenRelease": false, "preventTouchScrolling": true, - "preventPenScrolling": true + "preventPenScrolling": true, + "minimumTouchTime": 0 } } ], @@ -583,7 +585,8 @@ "scanOnPenPress", "scanOnPenRelease", "preventTouchScrolling", - "preventPenScrolling" + "preventPenScrolling", + "minimumTouchTime" ], "properties": { "showAdvanced": { @@ -641,6 +644,10 @@ "preventPenScrolling": { "type": "boolean", "default": true + }, + "minimumTouchTime": { + "type": "number", + "default": 0 } } } diff --git a/ext/js/data/options-util.js b/ext/js/data/options-util.js index cc2dd9677d..ee67fa275b 100644 --- a/ext/js/data/options-util.js +++ b/ext/js/data/options-util.js @@ -568,6 +568,7 @@ export class OptionsUtil { this._updateVersion54, this._updateVersion55, this._updateVersion56, + this._updateVersion57, ]; /* eslint-enable @typescript-eslint/unbound-method */ if (typeof targetVersion === 'number' && targetVersion < result.length) { @@ -642,6 +643,7 @@ export class OptionsUtil { scanOnPenPress: true, scanOnPenRelease: false, preventTouchScrolling: true, + minimumTouchTime: 0, }); for (const {options: profileOptions} of options.profiles) { profileOptions.general.usePopupWindow = false; @@ -1553,6 +1555,18 @@ export class OptionsUtil { } } + /** + * - Added scanning.inputs[].options.minimumTouchTime. + * @type {import('options-util').UpdateFunction} + */ + async _updateVersion57(options) { + for (const profile of options.profiles) { + for (const input of profile.options.scanning.inputs) { + input.options.minimumTouchTime = 0; + } + } + } + /** * @param {string} url * @returns {Promise} diff --git a/ext/js/display/display.js b/ext/js/display/display.js index 10a9c97fa1..8e038fde95 100644 --- a/ext/js/display/display.js +++ b/ext/js/display/display.js @@ -2069,6 +2069,7 @@ export class Display extends EventDispatcher { scanOnPenRelease: false, preventTouchScrolling: false, preventPenScrolling: false, + minimumTouchTime: 0, }, }], deepContentScan: scanningOptions.deepDomScan, diff --git a/ext/js/language/text-scanner.js b/ext/js/language/text-scanner.js index c99d7c0633..a7b4eb22b4 100644 --- a/ext/js/language/text-scanner.js +++ b/ext/js/language/text-scanner.js @@ -144,6 +144,8 @@ export class TextScanner extends EventDispatcher { /** @type {boolean} */ this._touchTapValid = false; + /** @type {number} */ + this._touchPressTime = 0; /** @type {?number} */ this._primaryTouchIdentifier = null; /** @type {boolean} */ @@ -723,6 +725,7 @@ export class TextScanner extends EventDispatcher { this._preventNextMouseDown = false; this._preventNextClick = false; this._touchTapValid = true; + this._touchPressTime = Date.now(); const languageNotNull = this._language !== null ? this._language : ''; const selection = window.getSelection(); @@ -760,6 +763,7 @@ export class TextScanner extends EventDispatcher { * @param {boolean} allowSearch */ _onPrimaryTouchEnd(e, x, y, allowSearch) { + const touchReleaseTime = Date.now(); this._primaryTouchIdentifier = null; this._preventScroll = false; this._preventNextClick = false; @@ -770,6 +774,7 @@ export class TextScanner extends EventDispatcher { const inputInfo = this._getMatchingInputGroupFromEvent('touch', 'touchEnd', e); if (inputInfo === null || inputInfo.input === null) { return; } + if (touchReleaseTime - this._touchPressTime < inputInfo.input.minimumTouchTime) { return; } if (inputInfo.input.scanOnTouchRelease || (inputInfo.input.scanOnTouchTap && this._touchTapValid)) { void this._searchAtFromTouchEnd(x, y, inputInfo); } @@ -1493,6 +1498,7 @@ export class TextScanner extends EventDispatcher { scanOnPenRelease: this._getInputBoolean(options.scanOnPenRelease), preventTouchScrolling: this._getInputBoolean(options.preventTouchScrolling), preventPenScrolling: this._getInputBoolean(options.preventPenScrolling), + minimumTouchTime: this._getInputNumber(options.minimumTouchTime), }; } @@ -1528,6 +1534,14 @@ export class TextScanner extends EventDispatcher { return typeof value === 'boolean' && value; } + /** + * @param {unknown} value + * @returns {number} + */ + _getInputNumber(value) { + return typeof value === 'number' ? value : -1; + } + /** * @param {PointerEvent} e * @returns {string} diff --git a/ext/js/pages/settings/scan-inputs-controller.js b/ext/js/pages/settings/scan-inputs-controller.js index 32910f6b61..90e7ab4b1c 100644 --- a/ext/js/pages/settings/scan-inputs-controller.js +++ b/ext/js/pages/settings/scan-inputs-controller.js @@ -219,6 +219,7 @@ export class ScanInputsController { scanOnPenRelease: false, preventTouchScrolling: true, preventPenScrolling: true, + minimumTouchTime: 0, }, }; } @@ -392,6 +393,10 @@ class ScanInputField { const {property} = typeCheckbox.dataset; typeCheckbox.dataset.setting = `scanning.inputs[${index}].${property}`; } + for (const typeInput of /** @type {NodeListOf} */ (this._node.querySelectorAll('.scan-input-settings-input'))) { + const {property} = typeInput.dataset; + typeInput.dataset.setting = `scanning.inputs[${index}].${property}`; + } } /** */ diff --git a/ext/templates-settings.html b/ext/templates-settings.html index 82e47d8d39..3a47c7a01c 100644 --- a/ext/templates-settings.html +++ b/ext/templates-settings.html @@ -238,6 +238,10 @@ Prevent touch scrolling +
Pen options:
diff --git a/test/options-util.test.js b/test/options-util.test.js index d7da01d5f3..ee3fd8aee3 100644 --- a/test/options-util.test.js +++ b/test/options-util.test.js @@ -387,6 +387,7 @@ function createProfileOptionsUpdatedTestData1() { scanOnPenRelease: false, preventTouchScrolling: true, preventPenScrolling: true, + minimumTouchTime: 0, }, }, { @@ -412,6 +413,7 @@ function createProfileOptionsUpdatedTestData1() { scanOnPenRelease: false, preventTouchScrolling: true, preventPenScrolling: true, + minimumTouchTime: 0, }, }, { @@ -437,6 +439,7 @@ function createProfileOptionsUpdatedTestData1() { scanOnPenRelease: false, preventTouchScrolling: true, preventPenScrolling: true, + minimumTouchTime: 0, }, }, ], @@ -669,7 +672,7 @@ function createOptionsUpdatedTestData1() { }, ], profileCurrent: 0, - version: 56, + version: 57, global: { database: { prefixWildcardsSupported: false, diff --git a/types/ext/settings.d.ts b/types/ext/settings.d.ts index d6cb5ccbca..754c7050c0 100644 --- a/types/ext/settings.d.ts +++ b/types/ext/settings.d.ts @@ -228,6 +228,7 @@ export type ScanningInputOptions = { scanOnPenRelease: boolean; preventTouchScrolling: boolean; preventPenScrolling: boolean; + minimumTouchTime: number; }; export type ScanningPreventMiddleMouseOptions = { diff --git a/types/ext/text-scanner.d.ts b/types/ext/text-scanner.d.ts index 90f04369ab..3de84aa089 100644 --- a/types/ext/text-scanner.d.ts +++ b/types/ext/text-scanner.d.ts @@ -68,6 +68,7 @@ export type InputOptions = { scanOnPenRelease: boolean; preventTouchScrolling: boolean; preventPenScrolling: boolean; + minimumTouchTime: number; }; export type SentenceParsingOptions = { @@ -93,6 +94,7 @@ export type InputConfig = { scanOnPenRelease: boolean; preventTouchScrolling: boolean; preventPenScrolling: boolean; + minimumTouchTime: number; }; export type InputInfo = { From 70de0f31b25429627dc3ed61e9b18c29922996ca Mon Sep 17 00:00:00 2001 From: Stephen Kraus <8003332+stephenmk@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:14:51 -0600 Subject: [PATCH 2/2] Allow dictionaries to specify minimum compatible Yomitan version (#1750) * Add `minimumYomitanVersion` parameter to dictionary index schema * Can't use `chrome.runtime` in `DictionaryImporter` class * Add `yomitanVersion` parameter to test data * More test data adjustments * Use single quotes to please the tests --------- Co-authored-by: stephenmk --- ext/data/schemas/dictionary-index-schema.json | 4 ++++ ext/js/dictionary/dictionary-importer.js | 14 ++++++++++++-- .../pages/settings/dictionary-import-controller.js | 1 + test/database.test.js | 8 ++++---- test/fixtures/translator-test.js | 2 +- types/ext/dictionary-data.d.ts | 1 + types/ext/dictionary-importer.d.ts | 3 +++ 7 files changed, 26 insertions(+), 7 deletions(-) diff --git a/ext/data/schemas/dictionary-index-schema.json b/ext/data/schemas/dictionary-index-schema.json index ec8b73b20d..f68e321e11 100644 --- a/ext/data/schemas/dictionary-index-schema.json +++ b/ext/data/schemas/dictionary-index-schema.json @@ -23,6 +23,10 @@ "type": "string", "description": "Revision of the dictionary. This value is displayed, and used to check for dictionary updates." }, + "minimumYomitanVersion": { + "type": "string", + "description": "Minimum version of Yomitan that is compatible with this dictionary." + }, "sequenced": { "type": "boolean", "default": false, diff --git a/ext/js/dictionary/dictionary-importer.js b/ext/js/dictionary/dictionary-importer.js index e8a72ba821..f0586f3302 100644 --- a/ext/js/dictionary/dictionary-importer.js +++ b/ext/js/dictionary/dictionary-importer.js @@ -24,6 +24,7 @@ import { ZipReader as ZipReader0, configure, } from '../../lib/zip.js'; +import {compareRevisions} from './dictionary-data-util.js'; import {ExtensionError} from '../core/extension-error.js'; import {parseJson} from '../core/json.js'; import {toError} from '../core/to-error.js'; @@ -180,8 +181,9 @@ export class DictionaryImporter { } } + const yomitanVersion = details.yomitanVersion; /** @type {import('dictionary-importer').SummaryDetails} */ - const summaryDetails = {prefixWildcardsSupported, counts, styles}; + const summaryDetails = {prefixWildcardsSupported, counts, styles, yomitanVersion}; const summary = this._createSummary(dictionaryTitle, version, index, summaryDetails); await dictionaryDatabase.bulkAdd('dictionaries', [summary], 0, 1); @@ -328,7 +330,15 @@ export class DictionaryImporter { styles, }; - const {author, url, description, attribution, frequencyMode, isUpdatable, sourceLanguage, targetLanguage} = index; + const {minimumYomitanVersion, author, url, description, attribution, frequencyMode, isUpdatable, sourceLanguage, targetLanguage} = index; + if (typeof minimumYomitanVersion === 'string') { + if (details.yomitanVersion === '0.0.0.0') { + // Running a development version of Yomitan + } else if (compareRevisions(details.yomitanVersion, minimumYomitanVersion)) { + throw new Error(`Dictionary is incompatible with this version of Yomitan (${details.yomitanVersion}; minimum required: ${minimumYomitanVersion})`); + } + summary.minimumYomitanVersion = minimumYomitanVersion; + } if (typeof author === 'string') { summary.author = author; } if (typeof url === 'string') { summary.url = url; } if (typeof description === 'string') { summary.description = description; } diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index d8e803f019..48fedbbc4f 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -555,6 +555,7 @@ export class DictionaryImportController { const optionsFull = await this._settingsController.getOptionsFull(); const importDetails = { prefixWildcardsSupported: optionsFull.global.database.prefixWildcardsSupported, + yomitanVersion: chrome.runtime.getManifest().version, }; for (let i = 0; i < importProgressTracker.dictionaryCount; ++i) { diff --git a/test/database.test.js b/test/database.test.js index 50fc213449..1edbf53abf 100644 --- a/test/database.test.js +++ b/test/database.test.js @@ -122,7 +122,7 @@ describe('Database', () => { // Setup database const dictionaryDatabase = new DictionaryDatabase(); /** @type {import('dictionary-importer').ImportDetails} */ - const defaultImportDetails = {prefixWildcardsSupported: false}; + const defaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: '0.0.0.0'}; // Database not open await expect.soft(dictionaryDatabase.deleteDictionary(title, 1000, () => {})).rejects.toThrow('Database not open'); @@ -167,7 +167,7 @@ describe('Database', () => { const testDictionarySource = await createTestDictionaryArchiveData(name); /** @type {import('dictionary-importer').ImportDetails} */ - const detaultImportDetails = {prefixWildcardsSupported: false}; + const detaultImportDetails = {prefixWildcardsSupported: false, yomitanVersion: '0.0.0.0'}; await expect.soft(createDictionaryImporter(expect).importDictionary(dictionaryDatabase, testDictionarySource, detaultImportDetails)).rejects.toThrow('Dictionary has invalid data'); await dictionaryDatabase.close(); }); @@ -199,7 +199,7 @@ describe('Database', () => { const {result: importDictionaryResult, errors: importDictionaryErrors} = await dictionaryImporter.importDictionary( dictionaryDatabase, testDictionarySource, - {prefixWildcardsSupported: true}, + {prefixWildcardsSupported: true, yomitanVersion: '0.0.0.0'}, ); if (importDictionaryResult) { @@ -324,7 +324,7 @@ describe('Database', () => { // Import data const dictionaryImporter = createDictionaryImporter(expect); - await dictionaryImporter.importDictionary(dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true}); + await dictionaryImporter.importDictionary(dictionaryDatabase, testDictionarySource, {prefixWildcardsSupported: true, yomitanVersion: '0.0.0.0'}); // Clear switch (clearMethod) { diff --git a/test/fixtures/translator-test.js b/test/fixtures/translator-test.js index 857e8a98ae..4b82598770 100644 --- a/test/fixtures/translator-test.js +++ b/test/fixtures/translator-test.js @@ -49,7 +49,7 @@ export async function createTranslatorContext(dictionaryDirectory, dictionaryNam const {errors, result} = await dictionaryImporter.importDictionary( dictionaryDatabase, testDictionaryData, - {prefixWildcardsSupported: true}, + {prefixWildcardsSupported: true, yomitanVersion: '0.0.0.0'}, ); expect(errors.length).toEqual(0); diff --git a/types/ext/dictionary-data.d.ts b/types/ext/dictionary-data.d.ts index 92e52b8d61..1b1d7c3306 100644 --- a/types/ext/dictionary-data.d.ts +++ b/types/ext/dictionary-data.d.ts @@ -24,6 +24,7 @@ export type Index = { version?: IndexVersion; title: string; revision: string; + minimumYomitanVersion?: string; sequenced?: boolean; isUpdatable?: true; indexUrl?: string; diff --git a/types/ext/dictionary-importer.d.ts b/types/ext/dictionary-importer.d.ts index 97472e6cfa..27b177cf9c 100644 --- a/types/ext/dictionary-importer.d.ts +++ b/types/ext/dictionary-importer.d.ts @@ -40,12 +40,14 @@ export type ImportResult = { export type ImportDetails = { prefixWildcardsSupported: boolean; + yomitanVersion: string; }; export type Summary = { title: string; revision: string; sequenced: boolean; + minimumYomitanVersion?: string; version: number; importDate: number; prefixWildcardsSupported: boolean; @@ -67,6 +69,7 @@ export type SummaryDetails = { prefixWildcardsSupported: boolean; counts: SummaryCounts; styles: string; + yomitanVersion: string; }; export type SummaryCounts = {