diff options
Diffstat (limited to 'ext/bg/js/settings/profile-conditions-ui.js')
-rw-r--r-- | ext/bg/js/settings/profile-conditions-ui.js | 712 |
1 files changed, 0 insertions, 712 deletions
diff --git a/ext/bg/js/settings/profile-conditions-ui.js b/ext/bg/js/settings/profile-conditions-ui.js deleted file mode 100644 index 5fda1dc0..00000000 --- a/ext/bg/js/settings/profile-conditions-ui.js +++ /dev/null @@ -1,712 +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 - * KeyboardMouseInputField - */ - -class ProfileConditionsUI extends EventDispatcher { - constructor(settingsController) { - super(); - this._settingsController = settingsController; - this._os = null; - this._conditionGroupsContainer = null; - this._addConditionGroupButton = null; - this._children = []; - this._eventListeners = new EventListenerCollection(); - this._defaultType = 'popupLevel'; - this._profileIndex = 0; - this._descriptors = new Map([ - [ - 'popupLevel', - { - displayName: 'Popup Level', - defaultOperator: 'equal', - operators: new Map([ - ['equal', {displayName: '=', type: 'integer', defaultValue: '0', validate: this._validateInteger.bind(this), normalize: this._normalizeInteger.bind(this)}], - ['notEqual', {displayName: '\u2260', type: 'integer', defaultValue: '0', validate: this._validateInteger.bind(this), normalize: this._normalizeInteger.bind(this)}], - ['lessThan', {displayName: '<', type: 'integer', defaultValue: '0', validate: this._validateInteger.bind(this), normalize: this._normalizeInteger.bind(this)}], - ['greaterThan', {displayName: '>', type: 'integer', defaultValue: '0', validate: this._validateInteger.bind(this), normalize: this._normalizeInteger.bind(this)}], - ['lessThanOrEqual', {displayName: '\u2264', type: 'integer', defaultValue: '0', validate: this._validateInteger.bind(this), normalize: this._normalizeInteger.bind(this)}], - ['greaterThanOrEqual', {displayName: '\u2265', type: 'integer', defaultValue: '0', validate: this._validateInteger.bind(this), normalize: this._normalizeInteger.bind(this)}] - ]) - } - ], - [ - 'url', - { - displayName: 'URL', - defaultOperator: 'matchDomain', - operators: new Map([ - ['matchDomain', {displayName: 'Matches Domain', type: 'string', defaultValue: 'example.com', resetDefaultOnChange: true, validate: this._validateDomains.bind(this), normalize: this._normalizeDomains.bind(this)}], - ['matchRegExp', {displayName: 'Matches RegExp', type: 'string', defaultValue: 'example\\.com', resetDefaultOnChange: true, validate: this._validateRegExp.bind(this)}] - ]) - } - ], - [ - 'modifierKeys', - { - displayName: 'Modifier Keys', - defaultOperator: 'are', - operators: new Map([ - ['are', {displayName: 'Are', type: 'modifierKeys', defaultValue: ''}], - ['areNot', {displayName: 'Are Not', type: 'modifierKeys', defaultValue: ''}], - ['include', {displayName: 'Include', type: 'modifierKeys', defaultValue: ''}], - ['notInclude', {displayName: 'Don\'t Include', type: 'modifierKeys', defaultValue: ''}] - ]) - } - ] - ]); - } - - get settingsController() { - return this._settingsController; - } - - get profileIndex() { - return this._profileIndex; - } - - get os() { - return this._os; - } - - set os(value) { - this._os = value; - } - - async prepare(profileIndex) { - const options = await this._settingsController.getOptionsFull(); - const {profiles} = options; - if (profileIndex < 0 || profileIndex >= profiles.length) { return; } - const {conditionGroups} = profiles[profileIndex]; - - this._profileIndex = profileIndex; - this._conditionGroupsContainer = document.querySelector('#profile-condition-groups'); - this._addConditionGroupButton = document.querySelector('#profile-add-condition-group'); - - for (let i = 0, ii = conditionGroups.length; i < ii; ++i) { - this._addConditionGroup(conditionGroups[i], i); - } - - this._eventListeners.addEventListener(this._addConditionGroupButton, 'click', this._onAddConditionGroupButtonClick.bind(this), false); - } - - cleanup() { - this._eventListeners.removeAllEventListeners(); - - for (const child of this._children) { - child.cleanup(); - } - this._children = []; - - this._conditionGroupsContainer = null; - this._addConditionGroupButton = null; - } - - instantiateTemplate(names) { - return this._settingsController.instantiateTemplate(names); - } - - getDescriptorTypes() { - const results = []; - for (const [name, {displayName}] of this._descriptors.entries()) { - results.push({name, displayName}); - } - return results; - } - - getDescriptorOperators(type) { - const info = this._descriptors.get(type); - const results = []; - if (typeof info !== 'undefined') { - for (const [name, {displayName}] of info.operators.entries()) { - results.push({name, displayName}); - } - } - return results; - } - - getDefaultType() { - return this._defaultType; - } - - getDefaultOperator(type) { - const info = this._descriptors.get(type); - return (typeof info !== 'undefined' ? info.defaultOperator : ''); - } - - getOperatorDetails(type, operator) { - const info = this._getOperatorDetails(type, operator); - - const { - displayName=operator, - type: type2='string', - defaultValue='', - resetDefaultOnChange=false, - validate=null, - normalize=null - } = (typeof info === 'undefined' ? {} : info); - - return { - displayName, - type: type2, - defaultValue, - resetDefaultOnChange, - validate, - normalize - }; - } - - getDefaultCondition() { - const type = this.getDefaultType(); - const operator = this.getDefaultOperator(type); - const {defaultValue: value} = this.getOperatorDetails(type, operator); - return {type, operator, value}; - } - - removeConditionGroup(child) { - const index = child.index; - if (index < 0 || index >= this._children.length) { return false; } - - const child2 = this._children[index]; - if (child !== child2) { return false; } - - this._children.splice(index, 1); - child.cleanup(); - - for (let i = index, ii = this._children.length; i < ii; ++i) { - this._children[i].index = i; - } - - this.settingsController.modifyGlobalSettings([{ - action: 'splice', - path: this.getPath('conditionGroups'), - start: index, - deleteCount: 1, - items: [] - }]); - - this._triggerConditionGroupCountChanged(this._children.length); - - return true; - } - - splitValue(value) { - return value.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0); - } - - getPath(property) { - property = (typeof property === 'string' ? `.${property}` : ''); - return `profiles[${this.profileIndex}]${property}`; - } - - createKeyboardMouseInputField(inputNode, mouseButton) { - return new KeyboardMouseInputField(inputNode, mouseButton, this._os); - } - - // Private - - _onAddConditionGroupButtonClick() { - const conditionGroup = { - conditions: [this.getDefaultCondition()] - }; - const index = this._children.length; - - this._addConditionGroup(conditionGroup, index); - - this.settingsController.modifyGlobalSettings([{ - action: 'splice', - path: this.getPath('conditionGroups'), - start: index, - deleteCount: 0, - items: [conditionGroup] - }]); - - this._triggerConditionGroupCountChanged(this._children.length); - } - - _addConditionGroup(conditionGroup, index) { - const child = new ProfileConditionGroupUI(this, index); - child.prepare(conditionGroup); - this._children.push(child); - this._conditionGroupsContainer.appendChild(child.node); - return child; - } - - _getOperatorDetails(type, operator) { - const info = this._descriptors.get(type); - return (typeof info !== 'undefined' ? info.operators.get(operator) : void 0); - } - - _validateInteger(value) { - const number = Number.parseFloat(value); - return Number.isFinite(number) && Math.floor(number) === number; - } - - _validateDomains(value) { - return this.splitValue(value).length > 0; - } - - _validateRegExp(value) { - try { - new RegExp(value, 'i'); - return true; - } catch (e) { - return false; - } - } - - _normalizeInteger(value) { - const number = Number.parseFloat(value); - return `${number}`; - } - - _normalizeDomains(value) { - return this.splitValue(value).join(', '); - } - - _triggerConditionGroupCountChanged(count) { - this.trigger('conditionGroupCountChanged', {count, profileIndex: this._profileIndex}); - } -} - -class ProfileConditionGroupUI { - constructor(parent, index) { - this._parent = parent; - this._index = index; - this._node = null; - this._conditionContainer = null; - this._addConditionButton = null; - this._children = []; - this._eventListeners = new EventListenerCollection(); - } - - get settingsController() { - return this._parent.settingsController; - } - - get parent() { - return this._parent; - } - - get index() { - return this._index; - } - - set index(value) { - this._index = value; - } - - get node() { - return this._node; - } - - get childCount() { - return this._children.length; - } - - prepare(conditionGroup) { - this._node = this._parent.instantiateTemplate('profile-condition-group'); - this._conditionContainer = this._node.querySelector('.profile-condition-list'); - this._addConditionButton = this._node.querySelector('.profile-condition-add-button'); - - const conditions = conditionGroup.conditions; - for (let i = 0, ii = conditions.length; i < ii; ++i) { - this._addCondition(conditions[i], i); - } - - this._eventListeners.addEventListener(this._addConditionButton, 'click', this._onAddConditionButtonClick.bind(this), false); - } - - cleanup() { - this._eventListeners.removeAllEventListeners(); - - for (const child of this._children) { - child.cleanup(); - } - this._children = []; - - if (this._node === null) { return; } - - const node = this._node; - this._node = null; - this._conditionContainer = null; - this._addConditionButton = null; - - if (node.parentNode !== null) { - node.parentNode.removeChild(node); - } - } - - removeCondition(child) { - const index = child.index; - if (index < 0 || index >= this._children.length) { return false; } - - const child2 = this._children[index]; - if (child !== child2) { return false; } - - this._children.splice(index, 1); - child.cleanup(); - - for (let i = index, ii = this._children.length; i < ii; ++i) { - this._children[i].index = i; - } - - this.settingsController.modifyGlobalSettings([{ - action: 'splice', - path: this.getPath('conditions'), - start: index, - deleteCount: 1, - items: [] - }]); - - if (this._children.length === 0) { - this.removeSelf(); - } - - return true; - } - - getPath(property) { - property = (typeof property === 'string' ? `.${property}` : ''); - return this._parent.getPath(`conditionGroups[${this._index}]${property}`); - } - - removeSelf() { - this._parent.removeConditionGroup(this); - } - - // Private - - _onAddConditionButtonClick() { - const condition = this._parent.getDefaultCondition(); - const index = this._children.length; - - this._addCondition(condition, index); - - this.settingsController.modifyGlobalSettings([{ - action: 'splice', - path: this.getPath('conditions'), - start: index, - deleteCount: 0, - items: [condition] - }]); - } - - _addCondition(condition, index) { - const child = new ProfileConditionUI(this, index); - child.prepare(condition); - this._children.push(child); - this._conditionContainer.appendChild(child.node); - return child; - } -} - -class ProfileConditionUI { - constructor(parent, index) { - this._parent = parent; - this._index = index; - this._node = null; - this._typeInput = null; - this._operatorInput = null; - this._valueInputContainer = null; - this._removeButton = null; - this._mouseButton = null; - this._mouseButtonContainer = null; - this._menuButton = null; - this._value = ''; - this._kbmInputField = null; - this._eventListeners = new EventListenerCollection(); - this._inputEventListeners = new EventListenerCollection(); - } - - get settingsController() { - return this._parent.parent.settingsController; - } - - get parent() { - return this._parent; - } - - get index() { - return this._index; - } - - set index(value) { - this._index = value; - } - - get node() { - return this._node; - } - - prepare(condition) { - const {type, operator, value} = condition; - - this._node = this._parent.parent.instantiateTemplate('profile-condition'); - this._typeInput = this._node.querySelector('.profile-condition-type'); - this._typeOptionContainer = this._typeInput.querySelector('optgroup'); - this._operatorInput = this._node.querySelector('.profile-condition-operator'); - this._operatorOptionContainer = this._operatorInput.querySelector('optgroup'); - this._valueInput = this._node.querySelector('.profile-condition-input'); - this._removeButton = this._node.querySelector('.profile-condition-remove'); - this._mouseButton = this._node.querySelector('.mouse-button'); - this._mouseButtonContainer = this._node.querySelector('.mouse-button-container'); - this._menuButton = this._node.querySelector('.profile-condition-menu-button'); - - const operatorDetails = this._getOperatorDetails(type, operator); - this._updateTypes(type); - this._updateOperators(type, operator); - this._updateValueInput(value, operatorDetails); - - this._eventListeners.addEventListener(this._typeInput, 'change', this._onTypeChange.bind(this), false); - this._eventListeners.addEventListener(this._operatorInput, 'change', this._onOperatorChange.bind(this), false); - if (this._removeButton !== null) { this._eventListeners.addEventListener(this._removeButton, 'click', this._onRemoveButtonClick.bind(this), false); } - if (this._menuButton !== null) { - 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(); - this._value = ''; - - if (this._node === null) { return; } - - const node = this._node; - this._node = null; - this._typeInput = null; - this._operatorInput = null; - this._valueInputContainer = null; - this._removeButton = null; - - if (node.parentNode !== null) { - node.parentNode.removeChild(node); - } - } - - getPath(property) { - property = (typeof property === 'string' ? `.${property}` : ''); - return this._parent.getPath(`conditions[${this._index}]${property}`); - } - - // Private - - _onTypeChange(e) { - const type = e.currentTarget.value; - this._setType(type); - } - - _onOperatorChange(e) { - const type = this._typeInput.value; - const operator = e.currentTarget.value; - this._setOperator(type, operator); - } - - _onValueInputChange({validate, normalize}, e) { - const node = e.currentTarget; - const value = node.value; - const okay = this._validateValue(value, validate); - this._value = value; - if (okay) { - const normalizedValue = this._normalizeValue(value, normalize); - node.value = normalizedValue; - this.settingsController.setGlobalSetting(this.getPath('value'), normalizedValue); - } - } - - _onModifierInputChange({validate, normalize}, {modifiers}) { - modifiers = this._joinModifiers(modifiers); - const okay = this._validateValue(modifiers, validate); - this._value = modifiers; - if (okay) { - const normalizedValue = this._normalizeValue(modifiers, normalize); - this.settingsController.setGlobalSetting(this.getPath('value'), normalizedValue); - } - } - - _onRemoveButtonClick() { - this._removeSelf(); - } - - _onMenuOpen(e) { - const bodyNode = e.detail.menu.bodyNode; - const deleteGroup = bodyNode.querySelector('.popup-menu-item[data-menu-action="deleteGroup"]'); - if (deleteGroup !== null) { - deleteGroup.hidden = (this._parent.childCount <= 1); - } - } - - _onMenuClose(e) { - switch (e.detail.action) { - case 'delete': - this._removeSelf(); - break; - case 'deleteGroup': - this._parent.removeSelf(); - break; - case 'resetValue': - this._resetValue(); - break; - } - } - - _getDescriptorTypes() { - return this._parent.parent.getDescriptorTypes(); - } - - _getDescriptorOperators(type) { - return this._parent.parent.getDescriptorOperators(type); - } - - _getOperatorDetails(type, operator) { - return this._parent.parent.getOperatorDetails(type, operator); - } - - _updateTypes(type) { - const types = this._getDescriptorTypes(); - this._updateSelect(this._typeInput, this._typeOptionContainer, types, type); - } - - _updateOperators(type, operator) { - const operators = this._getDescriptorOperators(type); - this._updateSelect(this._operatorInput, this._operatorOptionContainer, operators, operator); - } - - _updateSelect(select, optionContainer, values, value) { - optionContainer.textContent = ''; - for (const {name, displayName} of values) { - const option = document.createElement('option'); - option.value = name; - option.textContent = displayName; - optionContainer.appendChild(option); - } - select.value = value; - } - - _updateValueInput(value, {type, validate, normalize}) { - this._inputEventListeners.removeAllEventListeners(); - if (this._kbmInputField !== null) { - this._kbmInputField.cleanup(); - this._kbmInputField = null; - } - - let inputType = 'text'; - let inputValue = value; - let inputStep = null; - let showMouseButton = false; - const events = []; - const inputData = {validate, normalize}; - const node = this._valueInput; - - switch (type) { - case 'integer': - inputType = 'number'; - inputStep = '1'; - events.push(['addEventListener', node, 'change', this._onValueInputChange.bind(this, inputData), false]); - break; - case 'modifierKeys': - case 'modifierInputs': - inputValue = null; - showMouseButton = (type === 'modifierInputs'); - this._kbmInputField = this._parent.parent.createKeyboardMouseInputField(node, this._mouseButton); - this._kbmInputField.prepare(null, this._splitModifiers(value), showMouseButton, false); - events.push(['on', this._kbmInputField, 'change', this._onModifierInputChange.bind(this, inputData), false]); - break; - default: // 'string' - events.push(['addEventListener', node, 'change', this._onValueInputChange.bind(this, inputData), false]); - break; - } - - this._value = value; - delete node.dataset.invalid; - node.type = inputType; - if (inputValue !== null) { - node.value = inputValue; - } - if (typeof inputStep === 'string') { - node.step = inputStep; - } else { - node.removeAttribute('step'); - } - this._mouseButtonContainer.hidden = !showMouseButton; - for (const args of events) { - this._inputEventListeners.addGeneric(...args); - } - - this._validateValue(value, validate); - } - - _validateValue(value, validate) { - const okay = (validate === null || validate(value)); - this._valueInput.dataset.invalid = `${!okay}`; - return okay; - } - - _normalizeValue(value, normalize) { - return (normalize !== null ? normalize(value) : value); - } - - _removeSelf() { - this._parent.removeCondition(this); - } - - _splitModifiers(modifiersString) { - return modifiersString.split(/[,;\s]+/).map((v) => v.trim().toLowerCase()).filter((v) => v.length > 0); - } - - _joinModifiers(modifiersArray) { - return modifiersArray.join(', '); - } - - async _setType(type, operator) { - const operators = this._getDescriptorOperators(type); - if (typeof operator === 'undefined') { - operator = operators.length > 0 ? operators[0].name : ''; - } - const operatorDetails = this._getOperatorDetails(type, operator); - const {defaultValue} = operatorDetails; - this._updateSelect(this._operatorInput, this._operatorOptionContainer, operators, operator); - this._updateValueInput(defaultValue, operatorDetails); - await this.settingsController.modifyGlobalSettings([ - {action: 'set', path: this.getPath('type'), value: type}, - {action: 'set', path: this.getPath('operator'), value: operator}, - {action: 'set', path: this.getPath('value'), value: defaultValue} - ]); - } - - async _setOperator(type, operator) { - const operatorDetails = this._getOperatorDetails(type, operator); - const settingsModifications = [{action: 'set', path: this.getPath('operator'), value: operator}]; - if (operatorDetails.resetDefaultOnChange) { - const {defaultValue} = operatorDetails; - const okay = this._updateValueInput(defaultValue, operatorDetails); - if (okay) { - settingsModifications.push({action: 'set', path: this.getPath('value'), value: defaultValue}); - } - } - await this.settingsController.modifyGlobalSettings(settingsModifications); - } - - async _resetValue() { - const type = this._typeInput.value; - const operator = this._operatorInput.value; - await this._setType(type, operator); - } -} |