diff options
Diffstat (limited to 'ext/bg')
-rw-r--r-- | ext/bg/js/settings/generic-setting-controller.js | 96 |
1 files changed, 73 insertions, 23 deletions
diff --git a/ext/bg/js/settings/generic-setting-controller.js b/ext/bg/js/settings/generic-setting-controller.js index aa20dbbc..cb49845a 100644 --- a/ext/bg/js/settings/generic-setting-controller.js +++ b/ext/bg/js/settings/generic-setting-controller.js @@ -33,6 +33,7 @@ class GenericSettingController { this._transforms = new Map([ ['setDocumentAttribute', this._setDocumentAttribute.bind(this)], ['setRelativeAttribute', this._setRelativeAttribute.bind(this)], + ['setVisibility', this._setVisibility.bind(this)], ['splitTags', this._splitTags.bind(this)], ['joinTags', this._joinTags.bind(this)], ['toNumber', this._toNumber.bind(this)], @@ -52,11 +53,12 @@ class GenericSettingController { } _createElementMetadata(element) { + const {dataset: {setting: path, scope, transform, transformPre, transformPost}} = element; return { - path: element.dataset.setting, - scope: element.dataset.scope, - transformPre: element.dataset.transformPre, - transformPost: element.dataset.transformPost + path, + scope, + transformPre: typeof transformPre === 'string' ? transformPre : transform, + transformPost: typeof transformPost === 'string' ? transformPost : transform }; } @@ -118,6 +120,62 @@ class GenericSettingController { return value; } + _getAncestor(node, ancestorDistance) { + if (typeof ancestorDistance === 'string') { + const ii = Number.parseInt(ancestorDistance, 10); + if (Number.isFinite(ii)) { + if (ii < 0) { + node = document.documentElement; + } else { + for (let i = 0; i < ii && node !== null; ++i) { + node = node.parentNode; + } + } + } + } + return node; + } + + _getElementRelativeToAncestor(node, ancestorDistance, relativeSelector) { + const relativeElement = this._getAncestor(node, ancestorDistance); + if (relativeElement === null) { return null; } + + return ( + typeof relativeSelector === 'string' ? + relativeElement.querySelector(relativeSelector) : + relativeElement + ); + } + + _getConditionalResult(value, conditionString) { + let op = '!!'; + let rhsOperand = null; + try { + if (typeof conditionString === 'string') { + const {op: op2, value: value2} = JSON.parse(conditionString); + op = (typeof op2 === 'string' ? op2 : '==='); + rhsOperand = value2; + } + } catch (e) { + // NOP + } + return this._evaluateSimpleOperation(op, value, rhsOperand); + } + + _evaluateSimpleOperation(operation, lhs, rhs) { + switch (operation) { + case '!': return !lhs; + case '!!': return !!lhs; + case '===': return lhs === rhs; + case '!==': return lhs !== rhs; + case '>=': return lhs >= rhs; + case '<=': return lhs <= rhs; + case '>': return lhs > rhs; + case '<': return lhs < rhs; + default: return false; + } + } + // Transforms _setDocumentAttribute(value, metadata, element) { @@ -127,14 +185,18 @@ class GenericSettingController { _setRelativeAttribute(value, metadata, element) { const {ancestorDistance, relativeSelector, relativeAttribute} = element.dataset; - let relativeElement = this._getAncestor(element, ancestorDistance); + const relativeElement = this._getElementRelativeToAncestor(element, ancestorDistance, relativeSelector); if (relativeElement !== null) { - if (typeof relativeSelector === 'string') { - relativeElement = relativeElement.querySelector(relativeSelector); - } - if (relativeElement !== null) { - relativeElement.setAttribute(relativeAttribute, `${value}`); - } + relativeElement.setAttribute(relativeAttribute, `${value}`); + } + return value; + } + + _setVisibility(value, metadata, element) { + const {ancestorDistance, relativeSelector, visbilityCondition} = element.dataset; + const relativeElement = this._getElementRelativeToAncestor(element, ancestorDistance, relativeSelector); + if (relativeElement !== null) { + relativeElement.hidden = !this._getConditionalResult(value, visbilityCondition); } return value; } @@ -147,18 +209,6 @@ class GenericSettingController { return value.join(' '); } - _getAncestor(node, ancestorDistance) { - if (typeof ancestorDistance === 'string') { - const ii = Number.parseInt(ancestorDistance, 10); - if (Number.isFinite(ii)) { - for (let i = 0; i < ii && node !== null; ++i) { - node = node.parentNode; - } - } - } - return node; - } - _toNumber(value, metadata, element) { return DOMDataBinder.convertToNumber(value, element.dataset); } |