diff options
| author | Darius Jahandarie <djahandarie@gmail.com> | 2023-12-06 03:53:16 +0000 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-12-06 03:53:16 +0000 | 
| commit | bd5bc1a5db29903bc098995cd9262c4576bf76af (patch) | |
| tree | c9214189e0214480fcf6539ad1c6327aef6cbd1c /ext/js/pages/settings/dictionary-import-controller.js | |
| parent | fd6bba8a2a869eaf2b2c1fa49001f933fce3c618 (diff) | |
| parent | 23e6fb76319c9ed7c9bcdc3efba39bc5dd38f288 (diff) | |
Merge pull request #339 from toasted-nutbread/type-annotations
Type annotations
Diffstat (limited to 'ext/js/pages/settings/dictionary-import-controller.js')
| -rw-r--r-- | ext/js/pages/settings/dictionary-import-controller.js | 151 | 
1 files changed, 119 insertions, 32 deletions
diff --git a/ext/js/pages/settings/dictionary-import-controller.js b/ext/js/pages/settings/dictionary-import-controller.js index 12d29a6f..d1255e11 100644 --- a/ext/js/pages/settings/dictionary-import-controller.js +++ b/ext/js/pages/settings/dictionary-import-controller.js @@ -16,25 +16,44 @@   * along with this program.  If not, see <https://www.gnu.org/licenses/>.   */ -import {deserializeError, log} from '../../core.js'; +import {log} from '../../core.js'; +import {ExtensionError} from '../../core/extension-error.js';  import {DictionaryWorker} from '../../language/dictionary-worker.js';  import {yomitan} from '../../yomitan.js';  import {DictionaryController} from './dictionary-controller.js';  export class DictionaryImportController { +    /** +     * @param {import('./settings-controller.js').SettingsController} settingsController +     * @param {import('./modal-controller.js').ModalController} modalController +     * @param {import('./status-footer.js').StatusFooter} statusFooter +     */      constructor(settingsController, modalController, statusFooter) { +        /** @type {import('./settings-controller.js').SettingsController} */          this._settingsController = settingsController; +        /** @type {import('./modal-controller.js').ModalController} */          this._modalController = modalController; +        /** @type {import('./status-footer.js').StatusFooter} */          this._statusFooter = statusFooter; +        /** @type {boolean} */          this._modifying = false; +        /** @type {?HTMLButtonElement} */          this._purgeButton = null; +        /** @type {?HTMLButtonElement} */          this._purgeConfirmButton = null; +        /** @type {?HTMLButtonElement} */          this._importFileButton = null; +        /** @type {?HTMLInputElement} */          this._importFileInput = null; +        /** @type {?import('./modal.js').Modal} */          this._purgeConfirmModal = null; +        /** @type {?HTMLElement} */          this._errorContainer = null; +        /** @type {?HTMLElement} */          this._spinner = null; +        /** @type {?HTMLElement} */          this._purgeNotification = null; +        /** @type {[originalMessage: string, newMessage: string][]} */          this._errorToStringOverrides = [              [                  'A mutation operation was attempted on a database that did not allow mutations.', @@ -47,15 +66,16 @@ export class DictionaryImportController {          ];      } +    /** */      async prepare() { -        this._purgeButton = document.querySelector('#dictionary-delete-all-button'); -        this._purgeConfirmButton = document.querySelector('#dictionary-confirm-delete-all-button'); -        this._importFileButton = document.querySelector('#dictionary-import-file-button'); -        this._importFileInput = document.querySelector('#dictionary-import-file-input'); +        this._purgeButton = /** @type {HTMLButtonElement} */ (document.querySelector('#dictionary-delete-all-button')); +        this._purgeConfirmButton = /** @type {HTMLButtonElement} */ (document.querySelector('#dictionary-confirm-delete-all-button')); +        this._importFileButton = /** @type {HTMLButtonElement} */ (document.querySelector('#dictionary-import-file-button')); +        this._importFileInput = /** @type {HTMLInputElement} */ (document.querySelector('#dictionary-import-file-input'));          this._purgeConfirmModal = this._modalController.getModal('dictionary-confirm-delete-all'); -        this._errorContainer = document.querySelector('#dictionary-error'); -        this._spinner = document.querySelector('#dictionary-spinner'); -        this._purgeNotification = document.querySelector('#dictionary-delete-all-status'); +        this._errorContainer = /** @type {HTMLElement} */ (document.querySelector('#dictionary-error')); +        this._spinner = /** @type {HTMLElement} */ (document.querySelector('#dictionary-spinner')); +        this._purgeNotification = /** @type {HTMLElement} */ (document.querySelector('#dictionary-delete-all-status'));          this._purgeButton.addEventListener('click', this._onPurgeButtonClick.bind(this), false);          this._purgeConfirmButton.addEventListener('click', this._onPurgeConfirmButtonClick.bind(this), false); @@ -65,28 +85,41 @@ export class DictionaryImportController {      // Private +    /** */      _onImportButtonClick() { -        this._importFileInput.click(); +        /** @type {HTMLInputElement} */ (this._importFileInput).click();      } +    /** +     * @param {MouseEvent} e +     */      _onPurgeButtonClick(e) {          e.preventDefault(); -        this._purgeConfirmModal.setVisible(true); +        /** @type {import('./modal.js').Modal} */ (this._purgeConfirmModal).setVisible(true);      } +    /** +     * @param {MouseEvent} e +     */      _onPurgeConfirmButtonClick(e) {          e.preventDefault(); -        this._purgeConfirmModal.setVisible(false); +        /** @type {import('./modal.js').Modal} */ (this._purgeConfirmModal).setVisible(false);          this._purgeDatabase();      } +    /** +     * @param {Event} e +     */      _onImportFileChange(e) { -        const node = e.currentTarget; -        const files = [...node.files]; -        node.value = null; -        this._importDictionaries(files); +        const node = /** @type {HTMLInputElement} */ (e.currentTarget); +        const {files} = node; +        if (files === null) { return; } +        const files2 = [...files]; +        node.value = ''; +        this._importDictionaries(files2);      } +    /** */      async _purgeDatabase() {          if (this._modifying) { return; } @@ -106,7 +139,7 @@ export class DictionaryImportController {                  this._showErrors(errors);              }          } catch (error) { -            this._showErrors([error]); +            this._showErrors([error instanceof Error ? error : new Error(`${error}`)]);          } finally {              prevention.end();              if (purgeNotification !== null) { purgeNotification.hidden = true; } @@ -116,16 +149,19 @@ export class DictionaryImportController {          }      } +    /** +     * @param {File[]} files +     */      async _importDictionaries(files) {          if (this._modifying) { return; }          const statusFooter = this._statusFooter; -        const importInfo = document.querySelector('#dictionary-import-info'); +        const importInfo = /** @type {HTMLElement} */ (document.querySelector('#dictionary-import-info'));          const progressSelector = '.dictionary-import-progress'; -        const progressContainers = document.querySelectorAll(`#dictionaries-modal ${progressSelector}`); -        const progressBars = document.querySelectorAll(`${progressSelector} .progress-bar`); -        const infoLabels = document.querySelectorAll(`${progressSelector} .progress-info`); -        const statusLabels = document.querySelectorAll(`${progressSelector} .progress-status`); +        const progressContainers = /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll(`#dictionaries-modal ${progressSelector}`)); +        const progressBars = /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll(`${progressSelector} .progress-bar`)); +        const infoLabels = /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll(`${progressSelector} .progress-info`)); +        const statusLabels = /** @type {NodeListOf<HTMLElement>} */ (document.querySelectorAll(`${progressSelector} .progress-status`));          const prevention = this._preventPageExit(); @@ -143,6 +179,7 @@ export class DictionaryImportController {              let statusPrefix = '';              let stepIndex = -2; +            /** @type {import('dictionary-worker').ImportProgressCallback} */              const onProgress = (data) => {                  const {stepIndex: stepIndex2, index, count} = data;                  if (stepIndex !== stepIndex2) { @@ -184,7 +221,7 @@ export class DictionaryImportController {                  await this._importDictionary(files[i], importDetails, onProgress);              }          } catch (err) { -            this._showErrors([err]); +            this._showErrors([err instanceof Error ? err : new Error(`${err}`)]);          } finally {              prevention.end();              for (const progress of progressContainers) { progress.hidden = true; } @@ -199,6 +236,10 @@ export class DictionaryImportController {          }      } +    /** +     * @param {number} stepIndex +     * @returns {string} +     */      _getImportLabel(stepIndex) {          switch (stepIndex) {              case -1: @@ -212,6 +253,11 @@ export class DictionaryImportController {          }      } +    /** +     * @param {File} file +     * @param {import('dictionary-importer').ImportDetails} importDetails +     * @param {import('dictionary-worker').ImportProgressCallback} onProgress +     */      async _importDictionary(file, importDetails, onProgress) {          const archiveContent = await this._readFile(file);          const {result, errors} = await new DictionaryWorker().importDictionary(archiveContent, importDetails, onProgress); @@ -225,8 +271,14 @@ export class DictionaryImportController {          }      } +    /** +     * @param {boolean} sequenced +     * @param {string} title +     * @returns {Promise<Error[]>} +     */      async _addDictionarySettings(sequenced, title) {          const optionsFull = await this._settingsController.getOptionsFull(); +        /** @type {import('settings-modifications').Modification[]} */          const targets = [];          const profileCount = optionsFull.profiles.length;          for (let i = 0; i < profileCount; ++i) { @@ -243,8 +295,12 @@ export class DictionaryImportController {          return await this._modifyGlobalSettings(targets);      } +    /** +     * @returns {Promise<Error[]>} +     */      async _clearDictionarySettings() {          const optionsFull = await this._settingsController.getOptionsFull(); +        /** @type {import('settings-modifications').Modification[]} */          const targets = [];          const profileCount = optionsFull.profiles.length;          for (let i = 0; i < profileCount; ++i) { @@ -256,16 +312,25 @@ export class DictionaryImportController {          return await this._modifyGlobalSettings(targets);      } +    /** +     * @param {boolean} visible +     */      _setSpinnerVisible(visible) {          if (this._spinner !== null) {              this._spinner.hidden = !visible;          }      } +    /** +     * @returns {import('settings-controller').PageExitPrevention} +     */      _preventPageExit() {          return this._settingsController.preventPageExit();      } +    /** +     * @param {Error[]} errors +     */      _showErrors(errors) {          const uniqueErrors = new Map();          for (const error of errors) { @@ -292,59 +357,81 @@ export class DictionaryImportController {              fragment.appendChild(div);          } -        this._errorContainer.appendChild(fragment); -        this._errorContainer.hidden = false; +        const errorContainer = /** @type {HTMLElement} */ (this._errorContainer); +        errorContainer.appendChild(fragment); +        errorContainer.hidden = false;      } +    /** */      _hideErrors() { -        this._errorContainer.textContent = ''; -        this._errorContainer.hidden = true; +        const errorContainer = /** @type {HTMLElement} */ (this._errorContainer); +        errorContainer.textContent = ''; +        errorContainer.hidden = true;      } +    /** +     * @param {File} file +     * @returns {Promise<ArrayBuffer>} +     */      _readFile(file) {          return new Promise((resolve, reject) => {              const reader = new FileReader(); -            reader.onload = () => resolve(reader.result); +            reader.onload = () => resolve(/** @type {ArrayBuffer} */ (reader.result));              reader.onerror = () => reject(reader.error);              reader.readAsArrayBuffer(file);          });      } +    /** +     * @param {Error} error +     * @returns {string} +     */      _errorToString(error) { -        error = (typeof error.toString === 'function' ? error.toString() : `${error}`); +        const errorMessage = error.toString();          for (const [match, newErrorString] of this._errorToStringOverrides) { -            if (error.includes(match)) { +            if (errorMessage.includes(match)) {                  return newErrorString;              }          } -        return error; +        return errorMessage;      } +    /** +     * @param {boolean} value +     */      _setModifying(value) {          this._modifying = value;          this._setButtonsEnabled(!value);      } +    /** +     * @param {boolean} value +     */      _setButtonsEnabled(value) {          value = !value; -        for (const node of document.querySelectorAll('.dictionary-database-mutating-input')) { +        for (const node of /** @type {NodeListOf<HTMLInputElement>} */ (document.querySelectorAll('.dictionary-database-mutating-input'))) {              node.disabled = value;          }      } +    /** +     * @param {import('settings-modifications').Modification[]} targets +     * @returns {Promise<Error[]>} +     */      async _modifyGlobalSettings(targets) {          const results = await this._settingsController.modifyGlobalSettings(targets);          const errors = [];          for (const {error} of results) {              if (typeof error !== 'undefined') { -                errors.push(deserializeError(error)); +                errors.push(ExtensionError.deserialize(error));              }          }          return errors;      } +    /** */      _triggerStorageChanged() {          yomitan.trigger('storageChanged');      }  |