diff options
| -rw-r--r-- | ext/bg/js/settings/profile-controller.js | 395 | ||||
| -rw-r--r-- | ext/bg/js/settings/settings-controller.js | 4 | 
2 files changed, 242 insertions, 157 deletions
| diff --git a/ext/bg/js/settings/profile-controller.js b/ext/bg/js/settings/profile-controller.js index a32c03d1..fd7137be 100644 --- a/ext/bg/js/settings/profile-controller.js +++ b/ext/bg/js/settings/profile-controller.js @@ -1,5 +1,5 @@  /* - * Copyright (C) 2019-2020  Yomichan Authors + * 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 @@ -18,106 +18,210 @@  /* global   * ProfileConditionsUI   * api - * utilBackgroundIsolate   */  class ProfileController {      constructor(settingsController) {          this._settingsController = settingsController;          this._profileConditionsUI = new ProfileConditionsUI(settingsController); +        this._profileActiveSelect = null; +        this._profileTargetSelect = null; +        this._profileCopySourceSelect = null; +        this._profileNameInput = null; +        this._removeProfileNameElement = null; +        this._profileRemoveButton = null; +        this._profileCopyButton = null; +        this._profileMoveUpButton = null; +        this._profileMoveDownButton = null; +        this._profileRemoveModal = null; +        this._profileCopyModal = null; +        this._optionsFull = null;      }      async prepare() {          const {platform: {os}} = await api.getEnvironmentInfo();          this._profileConditionsUI.os = os; -        $('#profile-target').change(this._onTargetProfileChanged.bind(this)); -        $('#profile-name').change(this._onNameChanged.bind(this)); -        $('#profile-add').click(this._onAdd.bind(this)); -        $('#profile-remove').click(this._onRemove.bind(this)); -        $('#profile-remove-confirm').click(this._onRemoveConfirm.bind(this)); -        $('#profile-copy').click(this._onCopy.bind(this)); -        $('#profile-copy-confirm').click(this._onCopyConfirm.bind(this)); -        $('#profile-move-up').click(() => this._onMove(-1)); -        $('#profile-move-down').click(() => this._onMove(1)); -        $('.profile-form').find('input, select, textarea').not('.profile-form-manual').change(this._onInputChanged.bind(this)); +        this._profileActiveSelect = document.querySelector('#profile-active'); +        this._profileTargetSelect = document.querySelector('#profile-target'); +        this._profileCopySourceSelect = document.querySelector('#profile-copy-source'); +        this._profileNameInput = document.querySelector('#profile-name'); +        this._removeProfileNameElement = document.querySelector('#profile-remove-modal-profile-name'); +        this._profileRemoveButton = document.querySelector('#profile-remove'); +        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._profileActiveSelect.addEventListener('change', this._onProfileActiveChange.bind(this), false); +        this._profileTargetSelect.addEventListener('change', this._onProfileTargetChange.bind(this), false); +        this._profileNameInput.addEventListener('change', this._onNameChanged.bind(this), false); +        document.querySelector('#profile-add').addEventListener('click', this._onAdd.bind(this), false); +        this._profileRemoveButton.addEventListener('click', this._onRemove.bind(this), false); +        document.querySelector('#profile-remove-confirm').addEventListener('click', this._onRemoveConfirm.bind(this), false); +        this._profileCopyButton.addEventListener('click', this._onCopy.bind(this), false); +        document.querySelector('#profile-copy-confirm').addEventListener('click', this._onCopyConfirm.bind(this), false); +        this._profileMoveUpButton.addEventListener('click', this._onMove.bind(this, -1), false); +        this._profileMoveDownButton.addEventListener('click', this._onMove.bind(this, 1), false);          this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); -          this._onOptionsChanged();      }      // Private      async _onOptionsChanged() { -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        this._formWrite(optionsFull); +        this._optionsFull = await this._settingsController.getOptionsFull(); + +        this._profileConditionsUI.cleanup(); + +        const {profiles, profileCurrent} = this._optionsFull; +        const profileIndex = this._settingsController.profileIndex; + +        this._updateSelectOptions(this._profileActiveSelect); +        this._updateSelectOptions(this._profileTargetSelect); +        this._updateSelectOptions(this._profileCopySourceSelect, [profileIndex]); + +        this._profileActiveSelect.value = `${profileCurrent}`; +        this._profileTargetSelect.value = `${profileIndex}`; + +        this._profileRemoveButton.disabled = (profiles.length <= 1); +        this._profileCopyButton.disabled = (profiles.length <= 1); +        this._profileMoveUpButton.disabled = (profileIndex <= 0); +        this._profileMoveDownButton.disabled = (profileIndex >= profiles.length - 1); + +        if (profileIndex >= 0 && profileIndex < profiles.length) { +            const currentProfile = profiles[profileIndex]; +            this._profileNameInput.value = currentProfile.name; + +            const {conditionGroups} = currentProfile; +            this._profileConditionsUI.prepare(conditionGroups); +        }      } -    _tryGetIntegerValue(selector, min, max) { -        const value = parseInt($(selector).val(), 10); -        return ( -            typeof value === 'number' && -            Number.isFinite(value) && -            Math.floor(value) === value && -            value >= min && -            value < max -        ) ? value : null; +    _onProfileActiveChange(e) { +        const max = this._optionsFull.profiles.length; +        const value = this._tryGetIntegerValue(e.currentTarget.value, 0, max); +        if (value === null) { return; } +        this._settingsController.setGlobalSetting('profileCurrent', value);      } -    async _formRead(optionsFull) { -        const currentProfileIndex = this._settingsController.profileIndex; -        const profile = optionsFull.profiles[currentProfileIndex]; +    _onProfileTargetChange(e) { +        const max = this._optionsFull.profiles.length; +        const value = this._tryGetIntegerValue(e.currentTarget.value, 0, max); +        if (value === null) { return; } +        this._settingsController.profileIndex = value; +    } -        // Current profile -        const index = this._tryGetIntegerValue('#profile-active', 0, optionsFull.profiles.length); -        if (index !== null) { -            optionsFull.profileCurrent = index; -        } +    _onNameChanged(e) { +        const value = e.currentTarget.value; +        const profileIndex = this._settingsController.profileIndex; +        this._settingsController.setGlobalSetting(`profiles[${profileIndex}].name`, value); +        this._updateSelectName(profileIndex, value); +    } -        // Profile name -        profile.name = $('#profile-name').val(); +    _onAdd() { +        this._addProfile();      } -    _formWrite(optionsFull) { -        const currentProfileIndex = this._settingsController.profileIndex; -        const profile = optionsFull.profiles[currentProfileIndex]; +    _onRemove(e) { +        if (e.shiftKey) { +            return this._onRemoveConfirm(); +        } -        this._populateSelect($('#profile-active'), optionsFull.profiles, optionsFull.profileCurrent, null); -        this._populateSelect($('#profile-target'), optionsFull.profiles, currentProfileIndex, null); -        $('#profile-remove').prop('disabled', optionsFull.profiles.length <= 1); -        $('#profile-copy').prop('disabled', optionsFull.profiles.length <= 1); -        $('#profile-move-up').prop('disabled', currentProfileIndex <= 0); -        $('#profile-move-down').prop('disabled', currentProfileIndex >= optionsFull.profiles.length - 1); +        if (this._optionsFull.profiles.length <= 1) { return; } -        $('#profile-name').val(profile.name); +        const profileIndex = this._settingsController.profileIndex; +        const profile = this._optionsFull.profiles[profileIndex]; +        this._removeProfileNameElement.textContent = profile.name; +        this._setModalVisible(this._profileRemoveModal, true); +    } -        this._refreshProfileConditions(optionsFull); +    _onRemoveConfirm() { +        this._setModalVisible(this._profileRemoveModal, false); +        if (this._optionsFull.profiles.length <= 1) { return; } +        const profileIndex = this._settingsController.profileIndex; +        this._removeProfile(profileIndex);      } -    _refreshProfileConditions(optionsFull) { -        this._profileConditionsUI.cleanup(); +    _onCopy() { +        if (this._optionsFull.profiles.length <= 1) { return; } +        const {profiles, profileCurrent} = this._optionsFull;          const profileIndex = this._settingsController.profileIndex; -        if (profileIndex < 0 || profileIndex >= optionsFull.profiles.length) { return; } +        let copyFromIndex = profileCurrent; +        if (copyFromIndex === profileIndex) { +            if (profileIndex !== 0) { +                copyFromIndex = 0; +            } else if (profiles.length > 1) { +                copyFromIndex = 1; +            } +        } +        this._profileCopySourceSelect.value = `${copyFromIndex}`; -        const {conditionGroups} = optionsFull.profiles[profileIndex]; -        this._profileConditionsUI.prepare(conditionGroups); +        this._setModalVisible(this._profileCopyModal, true);      } -    _populateSelect(select, profiles, currentValue, ignoreIndices) { -        select.empty(); +    _onCopyConfirm() { +        this._setModalVisible(this._profileCopyModal, false); + +        const profileIndex = this._settingsController.profileIndex; +        const max = this._optionsFull.profiles.length; +        const index = this._tryGetIntegerValue('#profile-copy-source', 0, max); +        if (index === null || index === profileIndex) { return; } + +        this._copyProfile(profileIndex, index); +    } +    _onMove(offset) { +        const profileIndex = this._settingsController.profileIndex; +        const max = this._optionsFull.profiles.length; +        const profileIndexNew = Math.max(0, Math.min(max - 1, profileIndex + offset)); +        if (profileIndex === profileIndexNew) { return; } +        this._swapProfiles(profileIndex, profileIndexNew); +    } +    _updateSelectOptions(select, disabled) { +        const {profiles} = this._optionsFull; +        const fragment = document.createDocumentFragment();          for (let i = 0; i < profiles.length; ++i) { -            if (ignoreIndices !== null && ignoreIndices.indexOf(i) >= 0) { -                continue; -            }              const profile = profiles[i]; -            select.append($(`<option value="${i}">${profile.name}</option>`)); +            const option = document.createElement('option'); +            option.value = `${i}`; +            option.textContent = profile.name; +            option.disabled = (Array.isArray(disabled) && disabled.includes(i)); +            fragment.appendChild(option);          } +        select.textContent = ''; +        select.appendChild(fragment); +    } -        select.val(`${currentValue}`); +    _updateSelectName(index, name) { +        const selects = [ +            this._profileActiveSelect, +            this._profileTargetSelect, +            this._profileCopySourceSelect +        ]; +        const optionValue = `${index}`; +        for (const select of selects) { +            for (const option of select.querySelectorAll('option')) { +                if (option.value === optionValue) { +                    option.textContent = name; +                } +            } +        } +    } + +    _tryGetIntegerValue(value, min, max) { +        value = parseInt(value, 10); +        return ( +            typeof value === 'number' && +            Number.isFinite(value) && +            Math.floor(value) === value && +            value >= min && +            value < max +        ) ? value : null;      }      _createCopyName(name, profiles, maxUniqueAttempts) { @@ -155,128 +259,105 @@ class ProfileController {          }      } -    async _onInputChanged(e) { -        if (!e.originalEvent && !e.isTrigger) { -            return; -        } - -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        await this._formRead(optionsFull); -        await this._settingsController.save(); -    } - -    async _onTargetProfileChanged() { -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        const currentProfileIndex = this._settingsController.profileIndex; -        const index = this._tryGetIntegerValue('#profile-target', 0, optionsFull.profiles.length); -        if (index === null || currentProfileIndex === index) { -            return; -        } - -        this._settingsController.profileIndex = index; +    _getSwappedValue(currentValue, value1, value2) { +        if (currentValue === value1) { return value2; } +        if (currentValue === value2) { return value1; } +        return null;      } -    async _onAdd() { -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        const currentProfileIndex = this._settingsController.profileIndex; -        const profile = utilBackgroundIsolate(optionsFull.profiles[currentProfileIndex]); -        profile.name = this._createCopyName(profile.name, optionsFull.profiles, 100); -        optionsFull.profiles.push(profile); - -        this._settingsController.profileIndex = optionsFull.profiles.length - 1; - -        await this._settingsController.save(); +    _setModalVisible(node, visible) { +        $(node).modal(visible ? 'show' : 'hide');      } -    async _onRemove(e) { -        if (e.shiftKey) { -            return await this._onRemoveConfirm(); -        } - -        const optionsFull = await this._settingsController.getOptionsFull(); -        if (optionsFull.profiles.length <= 1) { -            return; -        } - -        const currentProfileIndex = this._settingsController.profileIndex; -        const profile = optionsFull.profiles[currentProfileIndex]; +    async _addProfile() { +        const profileIndex = this._settingsController.profileIndex; +        const profiles = this._optionsFull.profiles; +        const profile = profiles[profileIndex]; +        const newProfile = clone(profile); +        newProfile.name = this._createCopyName(profile.name, profiles, 100); + +        const index = profiles.length; +        await this._settingsController.modifyGlobalSettings([{ +            action: 'splice', +            path: 'profiles', +            start: index, +            deleteCount: 0, +            items: [newProfile] +        }]); -        $('#profile-remove-modal-profile-name').text(profile.name); -        $('#profile-remove-modal').modal('show'); +        this._settingsController.profileIndex = index;      } -    async _onRemoveConfirm() { -        $('#profile-remove-modal').modal('hide'); - -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        if (optionsFull.profiles.length <= 1) { -            return; +    async _removeProfile(index) { +        const {profiles, profileCurrent} = this._optionsFull; +        let newProfileCurrent = profileCurrent; +        const modifications = [{ +            action: 'splice', +            path: 'profiles', +            start: index, +            deleteCount: 1, +            items: [] +        }]; + +        if (profileCurrent >= index) { +            newProfileCurrent = Math.min(newProfileCurrent - 1, profiles.length - 1); +            modifications.push({ +                action: 'set', +                path: 'profileCurrent', +                value: newProfileCurrent +            });          } -        const currentProfileIndex = this._settingsController.profileIndex; -        optionsFull.profiles.splice(currentProfileIndex, 1); +        const profileIndex = this._settingsController.profileIndex; -        if (currentProfileIndex >= optionsFull.profiles.length) { -            this._settingsController.profileIndex = optionsFull.profiles.length - 1; -        } +        await this._settingsController.modifyGlobalSettings(modifications); -        if (optionsFull.profileCurrent >= optionsFull.profiles.length) { -            optionsFull.profileCurrent = optionsFull.profiles.length - 1; +        if (profileIndex === index) { +            this._settingsController.profileIndex = newProfileCurrent; +        } else { +            await this._onOptionsChanged();          } - -        await this._settingsController.save(); -    } - -    _onNameChanged() { -        const currentProfileIndex = this._settingsController.profileIndex; -        $('#profile-active, #profile-target').find(`[value="${currentProfileIndex}"]`).text(this.value);      } -    async _onMove(offset) { -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        const currentProfileIndex = this._settingsController.profileIndex; -        const index = currentProfileIndex + offset; -        if (index < 0 || index >= optionsFull.profiles.length) { -            return; +    async _swapProfiles(index1, index2) { +        const {profileCurrent} = this._optionsFull; + +        const modifications = [{ +            action: 'swap', +            path1: `profiles[${index1}]`, +            path2: `profiles[${index2}]` +        }]; + +        const newProfileCurrent = this._getSwappedValue(profileCurrent, index1, index2); +        if (newProfileCurrent !== profileCurrent) { +            modifications.push({ +                action: 'set', +                path: 'profileCurrent', +                value: newProfileCurrent +            });          } -        const profile = optionsFull.profiles[currentProfileIndex]; -        optionsFull.profiles.splice(currentProfileIndex, 1); -        optionsFull.profiles.splice(index, 0, profile); - -        if (optionsFull.profileCurrent === currentProfileIndex) { -            optionsFull.profileCurrent = index; -        } - -        this._settingsController.profileIndex = index; +        const profileIndex = this._settingsController.profileIndex; +        const newProfileIndex = this._getSwappedValue(profileIndex, index1, index2); -        await this._settingsController.save(); -    } +        await this._settingsController.modifyGlobalSettings(modifications); -    async _onCopy() { -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        if (optionsFull.profiles.length <= 1) { -            return; +        if (profileIndex !== newProfileIndex) { +            this._settingsController.profileIndex = newProfileIndex;          } - -        const currentProfileIndex = this._settingsController.profileIndex; -        this._populateSelect($('#profile-copy-source'), optionsFull.profiles, currentProfileIndex === 0 ? 1 : 0, [currentProfileIndex]); -        $('#profile-copy-modal').modal('show');      } -    async _onCopyConfirm() { -        $('#profile-copy-modal').modal('hide'); - -        const optionsFull = await this._settingsController.getOptionsFullMutable(); -        const index = this._tryGetIntegerValue('#profile-copy-source', 0, optionsFull.profiles.length); -        const currentProfileIndex = this._settingsController.profileIndex; -        if (index === null || index === currentProfileIndex) { -            return; -        } +    async _copyProfile(index, copyFromIndex) { +        const profiles = this._optionsFull.profiles; +        const copyFromProfile = profiles[copyFromIndex]; +        const options = clone(copyFromProfile.options); -        const profileOptions = utilBackgroundIsolate(optionsFull.profiles[index].options); -        optionsFull.profiles[currentProfileIndex].options = profileOptions; +        await this._settingsController.modifyGlobalSettings([{ +            action: 'set', +            path: `profiles[${index}].options`, +            value: options +        }]); -        await this._settingsController.save(); +        await this._settingsController.refresh();      }  } diff --git a/ext/bg/js/settings/settings-controller.js b/ext/bg/js/settings/settings-controller.js index b741cd6f..d2656beb 100644 --- a/ext/bg/js/settings/settings-controller.js +++ b/ext/bg/js/settings/settings-controller.js @@ -47,6 +47,10 @@ class SettingsController extends EventDispatcher {          yomichan.on('optionsUpdated', this._onOptionsUpdated.bind(this));      } +    async refresh() { +        await this._onOptionsUpdatedInternal(); +    } +      async save() {          await api.optionsSave(this._source);      } |