diff options
Diffstat (limited to 'ext/js/settings/profile-controller.js')
-rw-r--r-- | ext/js/settings/profile-controller.js | 697 |
1 files changed, 0 insertions, 697 deletions
diff --git a/ext/js/settings/profile-controller.js b/ext/js/settings/profile-controller.js deleted file mode 100644 index 3883e80a..00000000 --- a/ext/js/settings/profile-controller.js +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Copyright (C) 2020-2021 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/>. - */ - -/* global - * ProfileConditionsUI - */ - -class ProfileController { - constructor(settingsController, modalController) { - this._settingsController = settingsController; - this._modalController = modalController; - this._profileConditionsUI = new ProfileConditionsUI(settingsController); - this._profileConditionsIndex = null; - this._profileActiveSelect = null; - this._profileTargetSelect = null; - this._profileCopySourceSelect = null; - this._profileNameInput = null; - this._removeProfileNameElement = null; - this._profileAddButton = null; - this._profileRemoveButton = null; - this._profileRemoveConfirmButton = null; - this._profileCopyButton = null; - this._profileCopyConfirmButton = null; - this._profileMoveUpButton = null; - this._profileMoveDownButton = null; - this._profileEntryListContainer = null; - this._profileConditionsProfileName = null; - this._profileRemoveModal = null; - this._profileCopyModal = null; - this._profileConditionsModal = null; - this._profileEntriesSupported = false; - this._profileEntryList = []; - this._profiles = []; - this._profileCurrent = 0; - } - - get profileCount() { - return this._profiles.length; - } - - get profileCurrentIndex() { - return this._profileCurrent; - } - - async prepare() { - const {platform: {os}} = await yomichan.api.getEnvironmentInfo(); - this._profileConditionsUI.os = os; - - this._profileActiveSelect = document.querySelector('#profile-active-select'); - this._profileTargetSelect = document.querySelector('#profile-target-select'); - this._profileCopySourceSelect = document.querySelector('#profile-copy-source-select'); - this._profileNameInput = document.querySelector('#profile-name-input'); - this._removeProfileNameElement = document.querySelector('#profile-remove-name'); - this._profileAddButton = document.querySelector('#profile-add-button'); - this._profileRemoveButton = document.querySelector('#profile-remove-button'); - this._profileRemoveConfirmButton = document.querySelector('#profile-remove-confirm-button'); - this._profileCopyButton = document.querySelector('#profile-copy-button'); - this._profileCopyConfirmButton = document.querySelector('#profile-copy-confirm-button'); - this._profileMoveUpButton = document.querySelector('#profile-move-up-button'); - this._profileMoveDownButton = document.querySelector('#profile-move-down-button'); - this._profileEntryListContainer = document.querySelector('#profile-entry-list'); - this._profileConditionsProfileName = document.querySelector('#profile-conditions-profile-name'); - this._profileRemoveModal = this._modalController.getModal('profile-remove'); - this._profileCopyModal = this._modalController.getModal('profile-copy'); - this._profileConditionsModal = this._modalController.getModal('profile-conditions'); - - this._profileEntriesSupported = (this._profileEntryListContainer !== null); - - if (this._profileActiveSelect !== null) { this._profileActiveSelect.addEventListener('change', this._onProfileActiveChange.bind(this), false); } - if (this._profileTargetSelect !== null) { this._profileTargetSelect.addEventListener('change', this._onProfileTargetChange.bind(this), false); } - if (this._profileNameInput !== null) { this._profileNameInput.addEventListener('change', this._onNameChanged.bind(this), false); } - if (this._profileAddButton !== null) { this._profileAddButton.addEventListener('click', this._onAdd.bind(this), false); } - if (this._profileRemoveButton !== null) { this._profileRemoveButton.addEventListener('click', this._onDelete.bind(this), false); } - if (this._profileRemoveConfirmButton !== null) { this._profileRemoveConfirmButton.addEventListener('click', this._onDeleteConfirm.bind(this), false); } - if (this._profileCopyButton !== null) { this._profileCopyButton.addEventListener('click', this._onCopy.bind(this), false); } - if (this._profileCopyConfirmButton !== null) { this._profileCopyConfirmButton.addEventListener('click', this._onCopyConfirm.bind(this), false); } - if (this._profileMoveUpButton !== null) { this._profileMoveUpButton.addEventListener('click', this._onMove.bind(this, -1), false); } - if (this._profileMoveDownButton !== null) { this._profileMoveDownButton.addEventListener('click', this._onMove.bind(this, 1), false); } - - this._profileConditionsUI.on('conditionGroupCountChanged', this._onConditionGroupCountChanged.bind(this)); - this._settingsController.on('optionsChanged', this._onOptionsChanged.bind(this)); - this._onOptionsChanged(); - } - - async moveProfile(profileIndex, offset) { - if (this._getProfile(profileIndex) === null) { return; } - - const profileIndexNew = Math.max(0, Math.min(this._profiles.length - 1, profileIndex + offset)); - if (profileIndex === profileIndexNew) { return; } - - await this.swapProfiles(profileIndex, profileIndexNew); - } - - async setProfileName(profileIndex, value) { - const profile = this._getProfile(profileIndex); - if (profile === null) { return; } - - profile.name = value; - this._updateSelectName(profileIndex, value); - - const profileEntry = this._getProfileEntry(profileIndex); - if (profileEntry !== null) { profileEntry.setName(value); } - - await this._settingsController.setGlobalSetting(`profiles[${profileIndex}].name`, value); - } - - async setDefaultProfile(profileIndex) { - const profile = this._getProfile(profileIndex); - if (profile === null) { return; } - - this._profileActiveSelect.value = `${profileIndex}`; - this._profileCurrent = profileIndex; - - const profileEntry = this._getProfileEntry(profileIndex); - if (profileEntry !== null) { profileEntry.setIsDefault(true); } - - await this._settingsController.setGlobalSetting('profileCurrent', profileIndex); - } - - async copyProfile(sourceProfileIndex, destinationProfileIndex) { - const sourceProfile = this._getProfile(sourceProfileIndex); - if (sourceProfile === null || !this._getProfile(destinationProfileIndex)) { return; } - - const options = clone(sourceProfile.options); - this._profiles[destinationProfileIndex].options = options; - - this._updateProfileSelectOptions(); - - const destinationProfileEntry = this._getProfileEntry(destinationProfileIndex); - if (destinationProfileEntry !== null) { - destinationProfileEntry.updateState(); - } - - await this._settingsController.modifyGlobalSettings([{ - action: 'set', - path: `profiles[${destinationProfileIndex}].options`, - value: options - }]); - - await this._settingsController.refresh(); - } - - async duplicateProfile(profileIndex) { - const profile = this._getProfile(profileIndex); - if (this.profile === null) { return; } - - // Create new profile - const newProfile = clone(profile); - newProfile.name = this._createCopyName(profile.name, this._profiles, 100); - - // Update state - const index = this._profiles.length; - this._profiles.push(newProfile); - if (this._profileEntriesSupported) { - this._addProfileEntry(index); - } - this._updateProfileSelectOptions(); - - // Modify settings - await this._settingsController.modifyGlobalSettings([{ - action: 'splice', - path: 'profiles', - start: index, - deleteCount: 0, - items: [newProfile] - }]); - - // Update profile index - this._settingsController.profileIndex = index; - } - - async deleteProfile(profileIndex) { - const profile = this._getProfile(profileIndex); - if (profile === null || this.profileCount <= 1) { return; } - - // Get indices - let profileCurrentNew = this._profileCurrent; - const settingsProfileIndex = this._settingsController.profileIndex; - - // Construct settings modifications - const modifications = [{ - action: 'splice', - path: 'profiles', - start: profileIndex, - deleteCount: 1, - items: [] - }]; - if (profileCurrentNew >= profileIndex) { - profileCurrentNew = Math.min(profileCurrentNew - 1, this._profiles.length - 1); - modifications.push({ - action: 'set', - path: 'profileCurrent', - value: profileCurrentNew - }); - } - - // Update state - this._profileCurrent = profileCurrentNew; - - this._profiles.splice(profileIndex, 1); - - if (profileIndex < this._profileEntryList.length) { - const profileEntry = this._profileEntryList[profileIndex]; - profileEntry.cleanup(); - this._profileEntryList.splice(profileIndex, 1); - - for (let i = profileIndex, ii = this._profileEntryList.length; i < ii; ++i) { - this._profileEntryList[i].index = i; - } - } - - const profileEntry2 = this._getProfileEntry(profileCurrentNew); - if (profileEntry2 !== null) { - profileEntry2.setIsDefault(true); - } - - this._updateProfileSelectOptions(); - - // Modify settings - await this._settingsController.modifyGlobalSettings(modifications); - - // Update profile index - if (settingsProfileIndex === profileIndex) { - this._settingsController.profileIndex = profileCurrentNew; - } - } - - async swapProfiles(index1, index2) { - const profile1 = this._getProfile(index1); - const profile2 = this._getProfile(index2); - if (profile1 === null || profile2 === null || index1 === index2) { return; } - - // Get swapped indices - const profileCurrent = this._profileCurrent; - const profileCurrentNew = this._getSwappedValue(profileCurrent, index1, index2); - - const settingsProfileIndex = this._settingsController.profileIndex; - const settingsProfileIndexNew = this._getSwappedValue(settingsProfileIndex, index1, index2); - - // Construct settings modifications - const modifications = [{ - action: 'swap', - path1: `profiles[${index1}]`, - path2: `profiles[${index2}]` - }]; - if (profileCurrentNew !== profileCurrent) { - modifications.push({ - action: 'set', - path: 'profileCurrent', - value: profileCurrentNew - }); - } - - // Update state - this._profileCurrent = profileCurrentNew; - - this._profiles[index1] = profile2; - this._profiles[index2] = profile1; - - const entry1 = this._getProfileEntry(index1); - const entry2 = this._getProfileEntry(index2); - if (entry1 !== null && entry2 !== null) { - entry1.index = index2; - entry2.index = index1; - this._swapDomNodes(entry1.node, entry2.node); - this._profileEntryList[index1] = entry2; - this._profileEntryList[index2] = entry1; - } - - this._updateProfileSelectOptions(); - - // Modify settings - await this._settingsController.modifyGlobalSettings(modifications); - - // Update profile index - if (settingsProfileIndex !== settingsProfileIndexNew) { - this._settingsController.profileIndex = settingsProfileIndexNew; - } - } - - openDeleteProfileModal(profileIndex) { - const profile = this._getProfile(profileIndex); - if (profile === null || this.profileCount <= 1) { return; } - - this._removeProfileNameElement.textContent = profile.name; - this._profileRemoveModal.node.dataset.profileIndex = `${profileIndex}`; - this._profileRemoveModal.setVisible(true); - } - - openCopyProfileModal(profileIndex) { - const profile = this._getProfile(profileIndex); - if (profile === null || this.profileCount <= 1) { return; } - - let copyFromIndex = this._profileCurrent; - if (copyFromIndex === profileIndex) { - if (profileIndex !== 0) { - copyFromIndex = 0; - } else if (this.profileCount > 1) { - copyFromIndex = 1; - } - } - - const profileIndexString = `${profileIndex}`; - for (const option of this._profileCopySourceSelect.querySelectorAll('option')) { - const {value} = option; - option.disabled = (value === profileIndexString); - } - this._profileCopySourceSelect.value = `${copyFromIndex}`; - - this._profileCopyModal.node.dataset.profileIndex = `${profileIndex}`; - this._profileCopyModal.setVisible(true); - } - - openProfileConditionsModal(profileIndex) { - const profile = this._getProfile(profileIndex); - if (profile === null) { return; } - - if (this._profileConditionsModal === null) { return; } - this._profileConditionsModal.setVisible(true); - - this._profileConditionsUI.cleanup(); - this._profileConditionsIndex = profileIndex; - this._profileConditionsUI.prepare(profileIndex); - if (this._profileConditionsProfileName !== null) { - this._profileConditionsProfileName.textContent = profile.name; - } - } - - // Private - - async _onOptionsChanged() { - // Update state - const {profiles, profileCurrent} = await this._settingsController.getOptionsFull(); - this._profiles = profiles; - this._profileCurrent = profileCurrent; - - const settingsProfileIndex = this._settingsController.profileIndex; - const settingsProfile = this._getProfile(settingsProfileIndex); - - // Udpate UI - this._updateProfileSelectOptions(); - - this._profileActiveSelect.value = `${profileCurrent}`; - this._profileTargetSelect.value = `${settingsProfileIndex}`; - - if (this._profileRemoveButton !== null) { this._profileRemoveButton.disabled = (profiles.length <= 1); } - if (this._profileCopyButton !== null) { this._profileCopyButton.disabled = (profiles.length <= 1); } - if (this._profileMoveUpButton !== null) { this._profileMoveUpButton.disabled = (settingsProfileIndex <= 0); } - if (this._profileMoveDownButton !== null) { this._profileMoveDownButton.disabled = (settingsProfileIndex >= profiles.length - 1); } - - if (this._profileNameInput !== null && settingsProfile !== null) { this._profileNameInput.value = settingsProfile.name; } - - // Update profile conditions - this._profileConditionsUI.cleanup(); - const conditionsProfile = this._getProfile(this._profileConditionsIndex !== null ? this._profileConditionsIndex : settingsProfileIndex); - if (conditionsProfile !== null) { - this._profileConditionsUI.prepare(settingsProfileIndex); - } - - // Udpate profile entries - for (const entry of this._profileEntryList) { - entry.cleanup(); - } - this._profileEntryList = []; - if (this._profileEntriesSupported) { - for (let i = 0, ii = profiles.length; i < ii; ++i) { - this._addProfileEntry(i); - } - } - } - - _onProfileActiveChange(e) { - const value = this._tryGetValidProfileIndex(e.currentTarget.value); - if (value === null) { return; } - this.setDefaultProfile(value); - } - - _onProfileTargetChange(e) { - const value = this._tryGetValidProfileIndex(e.currentTarget.value); - if (value === null) { return; } - this._settingsController.profileIndex = value; - } - - _onNameChanged(e) { - this.setProfileName(this._settingsController.profileIndex, e.currentTarget.value); - } - - _onAdd() { - this.duplicateProfile(this._settingsController.profileIndex); - } - - _onDelete(e) { - const profileIndex = this._settingsController.profileIndex; - if (e.shiftKey) { - this.deleteProfile(profileIndex); - } else { - this.openDeleteProfileModal(profileIndex); - } - } - - _onDeleteConfirm() { - const modal = this._profileRemoveModal; - modal.setVisible(false); - const {node} = modal; - let profileIndex = node.dataset.profileIndex; - delete node.dataset.profileIndex; - - profileIndex = this._tryGetValidProfileIndex(profileIndex); - if (profileIndex === null) { return; } - - this.deleteProfile(profileIndex); - } - - _onCopy() { - this.openCopyProfileModal(this._settingsController.profileIndex); - } - - _onCopyConfirm() { - const modal = this._profileCopyModal; - modal.setVisible(false); - const {node} = modal; - let destinationProfileIndex = node.dataset.profileIndex; - delete node.dataset.profileIndex; - - destinationProfileIndex = this._tryGetValidProfileIndex(destinationProfileIndex); - if (destinationProfileIndex === null) { return; } - - const sourceProfileIndex = this._tryGetValidProfileIndex(this._profileCopySourceSelect.value); - if (sourceProfileIndex === null) { return; } - - this.copyProfile(sourceProfileIndex, destinationProfileIndex); - } - - _onMove(offset) { - this.moveProfile(this._settingsController.profileIndex, offset); - } - - _onConditionGroupCountChanged({count, profileIndex}) { - if (profileIndex >= 0 && profileIndex < this._profileEntryList.length) { - const profileEntry = this._profileEntryList[profileIndex]; - profileEntry.setConditionGroupsCount(count); - } - } - - _addProfileEntry(profileIndex) { - const profile = this._profiles[profileIndex]; - const node = this._settingsController.instantiateTemplate('profile-entry'); - const entry = new ProfileEntry(this, node); - this._profileEntryList.push(entry); - entry.prepare(profile, profileIndex); - this._profileEntryListContainer.appendChild(node); - } - - _updateProfileSelectOptions() { - for (const select of this._getAllProfileSelects()) { - const fragment = document.createDocumentFragment(); - for (let i = 0; i < this._profiles.length; ++i) { - const profile = this._profiles[i]; - const option = document.createElement('option'); - option.value = `${i}`; - option.textContent = profile.name; - fragment.appendChild(option); - } - select.textContent = ''; - select.appendChild(fragment); - } - } - - _updateSelectName(index, name) { - const optionValue = `${index}`; - for (const select of this._getAllProfileSelects()) { - for (const option of select.querySelectorAll('option')) { - if (option.value === optionValue) { - option.textContent = name; - } - } - } - } - - _getAllProfileSelects() { - return [ - this._profileActiveSelect, - this._profileTargetSelect, - this._profileCopySourceSelect - ]; - } - - _tryGetValidProfileIndex(stringValue) { - if (typeof stringValue !== 'string') { return null; } - const intValue = parseInt(stringValue, 10); - return ( - Number.isFinite(intValue) && - intValue >= 0 && - intValue < this.profileCount ? - intValue : null - ); - } - - _createCopyName(name, profiles, maxUniqueAttempts) { - let space, index, prefix, suffix; - const match = /^([\w\W]*\(Copy)((\s+)(\d+))?(\)\s*)$/.exec(name); - if (match === null) { - prefix = `${name} (Copy`; - space = ''; - index = ''; - suffix = ')'; - } else { - prefix = match[1]; - suffix = match[5]; - if (typeof match[2] === 'string') { - space = match[3]; - index = parseInt(match[4], 10) + 1; - } else { - space = ' '; - index = 2; - } - } - - let i = 0; - while (true) { - const newName = `${prefix}${space}${index}${suffix}`; - if (i++ >= maxUniqueAttempts || profiles.findIndex((profile) => profile.name === newName) < 0) { - return newName; - } - if (typeof index !== 'number') { - index = 2; - space = ' '; - } else { - ++index; - } - } - } - - _getSwappedValue(currentValue, value1, value2) { - if (currentValue === value1) { return value2; } - if (currentValue === value2) { return value1; } - return currentValue; - } - - _getProfile(profileIndex) { - return (profileIndex >= 0 && profileIndex < this._profiles.length ? this._profiles[profileIndex] : null); - } - - _getProfileEntry(profileIndex) { - return (profileIndex >= 0 && profileIndex < this._profileEntryList.length ? this._profileEntryList[profileIndex] : null); - } - - _swapDomNodes(node1, node2) { - const parent1 = node1.parentNode; - const parent2 = node2.parentNode; - const next1 = node1.nextSibling; - const next2 = node2.nextSibling; - if (node2 !== next1) { parent1.insertBefore(node2, next1); } - if (node1 !== next2) { parent2.insertBefore(node1, next2); } - } -} - -class ProfileEntry { - constructor(profileController, node) { - this._profileController = profileController; - this._node = node; - this._profile = null; - this._index = 0; - this._isDefaultRadio = null; - this._nameInput = null; - this._countLink = null; - this._countText = null; - this._menuButton = null; - this._eventListeners = new EventListenerCollection(); - } - - get index() { - return this._index; - } - - set index(value) { - this._index = value; - } - - get node() { - return this._node; - } - - prepare(profile, index) { - this._profile = profile; - this._index = index; - - const node = this._node; - this._isDefaultRadio = node.querySelector('.profile-entry-is-default-radio'); - this._nameInput = node.querySelector('.profile-entry-name-input'); - this._countLink = node.querySelector('.profile-entry-condition-count-link'); - this._countText = node.querySelector('.profile-entry-condition-count'); - this._menuButton = node.querySelector('.profile-entry-menu-button'); - - this.updateState(); - - this._eventListeners.addEventListener(this._isDefaultRadio, 'change', this._onIsDefaultRadioChange.bind(this), false); - this._eventListeners.addEventListener(this._nameInput, 'input', this._onNameInputInput.bind(this), false); - this._eventListeners.addEventListener(this._countLink, 'click', this._onConditionsCountLinkClick.bind(this), false); - this._eventListeners.addEventListener(this._menuButton, 'menuOpen', this._onMenuOpen.bind(this), false); - this._eventListeners.addEventListener(this._menuButton, 'menuClose', this._onMenuClose.bind(this), false); - } - - cleanup() { - this._eventListeners.removeAllEventListeners(); - if (this._node.parentNode !== null) { - this._node.parentNode.removeChild(this._node); - } - } - - setName(value) { - if (this._nameInput.value === value) { return; } - this._nameInput.value = value; - } - - setIsDefault(value) { - this._isDefaultRadio.checked = value; - } - - updateState() { - this._nameInput.value = this._profile.name; - this._countText.textContent = `${this._profile.conditionGroups.length}`; - this._isDefaultRadio.checked = (this._index === this._profileController.profileCurrentIndex); - } - - setConditionGroupsCount(count) { - this._countText.textContent = `${count}`; - } - - // Private - - _onIsDefaultRadioChange(e) { - if (!e.currentTarget.checked) { return; } - this._profileController.setDefaultProfile(this._index); - } - - _onNameInputInput(e) { - const name = e.currentTarget.value; - this._profileController.setProfileName(this._index, name); - } - - _onConditionsCountLinkClick() { - this._profileController.openProfileConditionsModal(this._index); - } - - _onMenuOpen(e) { - const bodyNode = e.detail.menu.bodyNode; - const count = this._profileController.profileCount; - this._setMenuActionEnabled(bodyNode, 'moveUp', this._index > 0); - this._setMenuActionEnabled(bodyNode, 'moveDown', this._index < count - 1); - this._setMenuActionEnabled(bodyNode, 'copyFrom', count > 1); - this._setMenuActionEnabled(bodyNode, 'delete', count > 1); - } - - _onMenuClose(e) { - switch (e.detail.action) { - case 'moveUp': - this._profileController.moveProfile(this._index, -1); - break; - case 'moveDown': - this._profileController.moveProfile(this._index, 1); - break; - case 'copyFrom': - this._profileController.openCopyProfileModal(this._index); - break; - case 'editConditions': - this._profileController.openProfileConditionsModal(this._index); - break; - case 'duplicate': - this._profileController.duplicateProfile(this._index); - break; - case 'delete': - this._profileController.openDeleteProfileModal(this._index); - break; - } - } - - _setMenuActionEnabled(menu, action, enabled) { - const element = menu.querySelector(`[data-menu-action="${action}"]`); - if (element === null) { return; } - element.disabled = !enabled; - } -} |