diff options
| author | toasted-nutbread <toasted-nutbread@users.noreply.github.com> | 2020-09-19 17:14:51 -0400 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-09-19 17:14:51 -0400 | 
| commit | 2ff4f830722940d2bfc35328fa913f93d04a330b (patch) | |
| tree | 19eb865b31eaaa9c69f6bd913985ae5460e7340d | |
| parent | 613c7ebf69413723486ab49a7b2f928422de3541 (diff) | |
Modal refactor (#842)
* Add Modal class
* Use Modal class
| -rw-r--r-- | ext/bg/js/settings/anki-templates-controller.js | 8 | ||||
| -rw-r--r-- | ext/bg/js/settings/backup-controller.js | 29 | ||||
| -rw-r--r-- | ext/bg/js/settings/dictionary-controller.js | 19 | ||||
| -rw-r--r-- | ext/bg/js/settings/dictionary-import-controller.js | 12 | ||||
| -rw-r--r-- | ext/bg/js/settings/modal.js | 65 | ||||
| -rw-r--r-- | ext/bg/js/settings/profile-controller.js | 17 | ||||
| -rw-r--r-- | ext/bg/settings.html | 1 | ||||
| -rw-r--r-- | ext/mixed/js/core.js | 5 | 
8 files changed, 115 insertions, 41 deletions
| diff --git a/ext/bg/js/settings/anki-templates-controller.js b/ext/bg/js/settings/anki-templates-controller.js index c980bfa2..f2e5be43 100644 --- a/ext/bg/js/settings/anki-templates-controller.js +++ b/ext/bg/js/settings/anki-templates-controller.js @@ -17,6 +17,7 @@  /* global   * AnkiNoteBuilder + * Modal   * TemplateRendererProxy   * api   */ @@ -28,12 +29,15 @@ class AnkiTemplatesController {          this._cachedDefinitionValue = null;          this._cachedDefinitionText = null;          this._defaultFieldTemplates = null; +        this._fieldTemplateResetModal = null;          this._templateRenderer = new TemplateRendererProxy();      }      async prepare() {          this._defaultFieldTemplates = await api.getDefaultAnkiFieldTemplates(); +        this._fieldTemplateResetModal = new Modal(document.querySelector('#field-template-reset-modal')); +          const markers = new Set([              ...this._ankiController.getFieldMarkers('terms'),              ...this._ankiController.getFieldMarkers('kanji') @@ -69,13 +73,13 @@ class AnkiTemplatesController {      _onReset(e) {          e.preventDefault(); -        $('#field-template-reset-modal').modal('show'); +        this._fieldTemplateResetModal.setVisible(true);      }      _onResetConfirm(e) {          e.preventDefault(); -        $('#field-template-reset-modal').modal('hide'); +        this._fieldTemplateResetModal.setVisible(false);          const value = this._defaultFieldTemplates; diff --git a/ext/bg/js/settings/backup-controller.js b/ext/bg/js/settings/backup-controller.js index 08ee7070..0676d451 100644 --- a/ext/bg/js/settings/backup-controller.js +++ b/ext/bg/js/settings/backup-controller.js @@ -16,6 +16,7 @@   */  /* global + * Modal   * OptionsUtil   * api   */ @@ -26,12 +27,19 @@ class BackupController {          this._settingsExportToken = null;          this._settingsExportRevoke = null;          this._currentVersion = 0; +        this._settingsResetModal = null; +        this._settingsImportErrorModal = null; +        this._settingsImportWarningModal = null;          this._optionsUtil = new OptionsUtil();      }      async prepare() {          await this._optionsUtil.prepare(); +        this._settingsResetModal = new Modal(document.querySelector('#settings-reset-modal')); +        this._settingsImportErrorModal = new Modal(document.querySelector('#settings-import-error-modal')); +        this._settingsImportWarningModal = new Modal(document.querySelector('#settings-import-warning-modal')); +          document.querySelector('#settings-export').addEventListener('click', this._onSettingsExportClick.bind(this), false);          document.querySelector('#settings-import').addEventListener('click', this._onSettingsImportClick.bind(this), false);          document.querySelector('#settings-import-file').addEventListener('change', this._onSettingsImportFileChange.bind(this), false); @@ -153,14 +161,14 @@ class BackupController {      _showSettingsImportError(error) {          yomichan.logError(error);          document.querySelector('#settings-import-error-modal-message').textContent = `${error}`; -        $('#settings-import-error-modal').modal('show'); +        this._settingsImportErrorModal.setVisible(true);      }      async _showSettingsImportWarnings(warnings) { -        const modalNode = $('#settings-import-warning-modal'); +        const modal = this._settingsImportWarningModal;          const buttons = document.querySelectorAll('.settings-import-warning-modal-import-button');          const messageContainer = document.querySelector('#settings-import-warning-modal-message'); -        if (modalNode.length === 0 || buttons.length === 0 || messageContainer === null) { +        if (buttons.length === 0 || messageContainer === null) {              return {result: false};          } @@ -175,7 +183,7 @@ class BackupController {          messageContainer.appendChild(fragment);          // Show modal -        modalNode.modal('show'); +        modal.setVisible(true);          // Wait for modal to close          return new Promise((resolve) => { @@ -185,9 +193,10 @@ class BackupController {                      result: true,                      sanitize: e.currentTarget.dataset.importSanitize === 'true'                  }); -                modalNode.modal('hide'); +                modal.setVisible(false);              }; -            const onModalHide = () => { +            const onModalVisibilityChanged = ({visible}) => { +                if (visible) { return; }                  complete({result: false});              }; @@ -196,7 +205,7 @@ class BackupController {                  if (completed) { return; }                  completed = true; -                modalNode.off('hide.bs.modal', onModalHide); +                modal.off('visibilityChanged', onModalVisibilityChanged);                  for (const button of buttons) {                      button.removeEventListener('click', onButtonClick, false);                  } @@ -205,7 +214,7 @@ class BackupController {              };              // Hook events -            modalNode.on('hide.bs.modal', onModalHide); +            modal.on('visibilityChanged', onModalVisibilityChanged);              for (const button of buttons) {                  button.addEventListener('click', onButtonClick, false);              } @@ -368,11 +377,11 @@ class BackupController {      // Resetting      _onSettingsResetClick() { -        $('#settings-reset-modal').modal('show'); +        this._settingsResetModal.setVisible(true);      }      async _onSettingsResetConfirmClick() { -        $('#settings-reset-modal').modal('hide'); +        this._settingsResetModal.setVisible(false);          // Get default options          const optionsFull = this._optionsUtil.getDefault(); diff --git a/ext/bg/js/settings/dictionary-controller.js b/ext/bg/js/settings/dictionary-controller.js index 75022d1f..afc198e2 100644 --- a/ext/bg/js/settings/dictionary-controller.js +++ b/ext/bg/js/settings/dictionary-controller.js @@ -16,6 +16,7 @@   */  /* global + * Modal   * ObjectPropertyAccessor   * api   */ @@ -164,7 +165,7 @@ class DictionaryController {          this._checkIntegrityButton = document.querySelector('#dict-check-integrity');          this._dictionaryEntryContainer = document.querySelector('#dict-groups');          this._integrityExtraInfoContainer = document.querySelector('#dict-groups-extra'); -        this._deleteDictionaryModal = document.querySelector('#dict-delete-modal'); +        this._deleteDictionaryModal = new Modal(document.querySelector('#dict-delete-modal'));          yomichan.on('databaseUpdated', this._onDatabaseUpdated.bind(this)); @@ -177,9 +178,9 @@ class DictionaryController {      deleteDictionary(dictionaryTitle) {          if (this._isDeleting) { return; }          const modal = this._deleteDictionaryModal; -        modal.dataset.dictionaryTitle = dictionaryTitle; -        modal.querySelector('#dict-remove-modal-dict-name').textContent = dictionaryTitle; -        this._setModalVisible(modal, true); +        modal.node.dataset.dictionaryTitle = dictionaryTitle; +        modal.node.querySelector('#dict-remove-modal-dict-name').textContent = dictionaryTitle; +        modal.setVisible(true);      }      // Private @@ -209,11 +210,11 @@ class DictionaryController {          e.preventDefault();          const modal = this._deleteDictionaryModal; -        this._setModalVisible(modal, false); +        modal.setVisible(false); -        const title = modal.dataset.dictionaryTitle; +        const title = modal.node.dataset.dictionaryTitle;          if (typeof title !== 'string') { return; } -        delete modal.dataset.dictionaryTitle; +        delete modal.node.dataset.dictionaryTitle;          this._deleteDictionary(title);      } @@ -223,10 +224,6 @@ class DictionaryController {          this._checkIntegrity();      } -    _setModalVisible(node, visible) { -        $(node).modal(visible ? 'show' : 'hide'); -    } -      _updateMainDictionarySelectOptions(dictionaries) {          const fragment = document.createDocumentFragment(); diff --git a/ext/bg/js/settings/dictionary-import-controller.js b/ext/bg/js/settings/dictionary-import-controller.js index dd4889dc..a78378e8 100644 --- a/ext/bg/js/settings/dictionary-import-controller.js +++ b/ext/bg/js/settings/dictionary-import-controller.js @@ -18,6 +18,7 @@  /* global   * DictionaryDatabase   * DictionaryImporter + * Modal   * ObjectPropertyAccessor   * api   */ @@ -53,7 +54,7 @@ class DictionaryImportController {          this._purgeConfirmButton = document.querySelector('#dict-purge-confirm');          this._importFileButton = document.querySelector('#dict-file-button');          this._importFileInput = document.querySelector('#dict-file'); -        this._purgeConfirmModal = document.querySelector('#dict-purge-modal'); +        this._purgeConfirmModal = new Modal(document.querySelector('#dict-purge-modal'));          this._errorContainer = document.querySelector('#dict-error');          this._spinner = document.querySelector('#dict-spinner');          this._progressContainer = document.querySelector('#dict-import-progress'); @@ -75,12 +76,12 @@ class DictionaryImportController {      _onPurgeButtonClick(e) {          e.preventDefault(); -        this._setPurgeModalVisible(true); +        this._purgeConfirmModal.setVisible(true);      }      _onPurgeConfirmButtonClick(e) {          e.preventDefault(); -        this._setPurgeModalVisible(false); +        this._purgeConfirmModal.setVisible(false);          this._purgeDatabase();      } @@ -220,11 +221,6 @@ class DictionaryImportController {          return await this._modifyGlobalSettings(targets);      } -    _setPurgeModalVisible(visible) { -        const node = $(this._purgeConfirmModal); -        node.modal(visible ? 'show' : 'hide'); -    } -      _setSpinnerVisible(visible) {          this._spinner.hidden = !visible;      } diff --git a/ext/bg/js/settings/modal.js b/ext/bg/js/settings/modal.js new file mode 100644 index 00000000..42a511ca --- /dev/null +++ b/ext/bg/js/settings/modal.js @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2020  Yomichan Authors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <https://www.gnu.org/licenses/>. + */ + +class Modal extends EventDispatcher { +    constructor(node) { +        super(); +        this._node = node; +        this._eventListeners = new EventListenerCollection(); +    } + +    get node() { +        return this._node; +    } + +    setVisible(value) { +        this._getWrappedNode().modal(value ? 'show' : 'hide'); +    } + +    on(eventName, callback) { +        if (eventName === 'visibilityChanged') { +            if (this._eventListeners.size === 0) { +                const wrappedNode = this._getWrappedNode(); +                this._eventListeners.on(wrappedNode, 'hidden.bs.modal', this._onModalHide.bind(this)); +                this._eventListeners.on(wrappedNode, 'shown.bs.modal', this._onModalShow.bind(this)); +            } +        } +        return super.on(eventName, callback); +    } + +    off(eventName, callback) { +        const result = super.off(eventName, callback); +        if (eventName === 'visibilityChanged' && !this.hasListeners(eventName)) { +            this._eventListeners.removeAllEventListeners(); +        } +        return result; +    } + +    // Private + +    _onModalHide() { +        this.trigger('visibilityChanged', {visible: false}); +    } + +    _onModalShow() { +        this.trigger('visibilityChanged', {visible: true}); +    } + +    _getWrappedNode() { +        return $(this._node); +    } +} diff --git a/ext/bg/js/settings/profile-controller.js b/ext/bg/js/settings/profile-controller.js index fd7137be..7c6dfae5 100644 --- a/ext/bg/js/settings/profile-controller.js +++ b/ext/bg/js/settings/profile-controller.js @@ -16,6 +16,7 @@   */  /* global + * Modal   * ProfileConditionsUI   * api   */ @@ -51,8 +52,8 @@ class ProfileController {          this._profileCopyButton = document.querySelector('#profile-copy');          this._profileMoveUpButton = document.querySelector('#profile-move-up');          this._profileMoveDownButton = document.querySelector('#profile-move-down'); -        this._profileRemoveModal = document.querySelector('#profile-remove-modal'); -        this._profileCopyModal = document.querySelector('#profile-copy-modal'); +        this._profileRemoveModal = new Modal(document.querySelector('#profile-remove-modal')); +        this._profileCopyModal = new Modal(document.querySelector('#profile-copy-modal'));          this._profileActiveSelect.addEventListener('change', this._onProfileActiveChange.bind(this), false);          this._profileTargetSelect.addEventListener('change', this._onProfileTargetChange.bind(this), false); @@ -135,11 +136,11 @@ class ProfileController {          const profileIndex = this._settingsController.profileIndex;          const profile = this._optionsFull.profiles[profileIndex];          this._removeProfileNameElement.textContent = profile.name; -        this._setModalVisible(this._profileRemoveModal, true); +        this._profileRemoveModal.setVisible(true);      }      _onRemoveConfirm() { -        this._setModalVisible(this._profileRemoveModal, false); +        this._profileRemoveModal.setVisible(false);          if (this._optionsFull.profiles.length <= 1) { return; }          const profileIndex = this._settingsController.profileIndex;          this._removeProfile(profileIndex); @@ -160,11 +161,11 @@ class ProfileController {          }          this._profileCopySourceSelect.value = `${copyFromIndex}`; -        this._setModalVisible(this._profileCopyModal, true); +        this._profileCopyModal.setVisible(true);      }      _onCopyConfirm() { -        this._setModalVisible(this._profileCopyModal, false); +        this._profileCopyModal.setVisible(false);          const profileIndex = this._settingsController.profileIndex;          const max = this._optionsFull.profiles.length; @@ -265,10 +266,6 @@ class ProfileController {          return null;      } -    _setModalVisible(node, visible) { -        $(node).modal(visible ? 'show' : 'hide'); -    } -      async _addProfile() {          const profileIndex = this._settingsController.profileIndex;          const profiles = this._optionsFull.profiles; diff --git a/ext/bg/settings.html b/ext/bg/settings.html index 7141776c..9c8621f7 100644 --- a/ext/bg/settings.html +++ b/ext/bg/settings.html @@ -1216,6 +1216,7 @@          <script src="/bg/js/template-renderer-proxy.js"></script>          <script src="/bg/js/settings/keyboard-mouse-input-field.js"></script> +        <script src="/bg/js/settings/modal.js"></script>          <script src="/bg/js/settings/profile-conditions-ui.js"></script>          <script src="/bg/js/settings/anki-controller.js"></script> diff --git a/ext/mixed/js/core.js b/ext/mixed/js/core.js index 351d9371..7eb21659 100644 --- a/ext/mixed/js/core.js +++ b/ext/mixed/js/core.js @@ -325,6 +325,11 @@ class EventDispatcher {          }          return false;      } + +    hasListeners(eventName) { +        const callbacks = this._eventMap.get(eventName); +        return (typeof callbacks !== 'undefined' && callbacks.length > 0); +    }  }  class EventListenerCollection { |