| LEFT | RIGHT | 
|---|
| (no file at all) |  | 
| 1 /* globals module, require */ | 1 /* | 
|  | 2  * This file is part of Adblock Plus <https://adblockplus.org/>, | 
|  | 3  * Copyright (C) 2006-present eyeo GmbH | 
|  | 4  * | 
|  | 5  * Adblock Plus is free software: you can redistribute it and/or modify | 
|  | 6  * it under the terms of the GNU General Public License version 3 as | 
|  | 7  * published by the Free Software Foundation. | 
|  | 8  * | 
|  | 9  * Adblock Plus is distributed in the hope that it will be useful, | 
|  | 10  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 12  * GNU General Public License for more details. | 
|  | 13  * | 
|  | 14  * You should have received a copy of the GNU General Public License | 
|  | 15  * along with Adblock Plus.  If not, see <http://www.gnu.org/licenses/>. | 
|  | 16  */ | 
| 2 | 17 | 
| 3 "use strict"; | 18 "use strict"; | 
| 4 | 19 | 
| 5 // Custom Elements ponyfill (a polyfill triggered on demand) | 20 // Custom Elements ponyfill (a polyfill triggered on demand) | 
| 6 const customElementsPonyfill = require("document-register-element/pony"); | 21 const customElementsPonyfill = require("document-register-element/pony"); | 
| 7 if (typeof customElements !== "object") | 22 if (typeof customElements !== "object") | 
| 8   customElementsPonyfill(window); | 23   customElementsPonyfill(window); | 
| 9 | 24 | 
| 10 // external dependencies | 25 // external dependencies | 
| 11 const {default: HyperHTMLElement} = require("hyperhtml-element/cjs"); | 26 const {default: HyperHTMLElement} = require("hyperhtml-element/cjs"); | 
| 12 | 27 | 
|  | 28 // common DOM utilities exposed as IOElement.utils | 
|  | 29 const DOMUtils = { | 
|  | 30 | 
|  | 31   // boolean related operations/helpers | 
|  | 32   boolean: { | 
|  | 33     // utils.boolean.attribute(node, name, setAsTrue):void | 
|  | 34     // set a generic node attribute name as "true" | 
|  | 35     // if value is a boolean one or it removes the attribute | 
|  | 36     attribute(node, name, setAsTrue) | 
|  | 37     { | 
|  | 38       // don't use `this.value(value)` with `this` as context | 
|  | 39       // to make destructuring of helpers always work. | 
|  | 40       // @example | 
|  | 41       // const {attribute: setBoolAttr} = IOElement.utils.boolean; | 
|  | 42       // setBoolAttr(node, 'test', true); | 
|  | 43       if (DOMUtils.boolean.value(setAsTrue)) | 
|  | 44       { | 
|  | 45         node.setAttribute(name, "true"); | 
|  | 46       } | 
|  | 47       else | 
|  | 48       { | 
|  | 49         node.removeAttribute(name); | 
|  | 50       } | 
|  | 51     }, | 
|  | 52 | 
|  | 53     // utils.boolean.value(any):boolean | 
|  | 54     // it returns either true or false | 
|  | 55     // via truthy or falsy values, but also via strings | 
|  | 56     // representing "true", "false" as well as "0" or "1" | 
|  | 57     value(value) | 
|  | 58     { | 
|  | 59       if (typeof value === "string" && value.length) | 
|  | 60       { | 
|  | 61         try | 
|  | 62         { | 
|  | 63           value = JSON.parse(value); | 
|  | 64         } | 
|  | 65         catch (error) | 
|  | 66         { | 
|  | 67           // Ignore invalid JSON to continue using value as string | 
|  | 68         } | 
|  | 69       } | 
|  | 70       return !!value; | 
|  | 71     } | 
|  | 72   } | 
|  | 73 }; | 
|  | 74 | 
| 13 // provides a unique-id suffix per each component | 75 // provides a unique-id suffix per each component | 
| 14 let counter = 0; | 76 let counter = 0; | 
| 15 | 77 | 
| 16 // common Custom Element class to extend | 78 // common Custom Element class to extend | 
| 17 class IOElement extends HyperHTMLElement | 79 class IOElement extends HyperHTMLElement | 
| 18 { | 80 { | 
|  | 81   // exposes DOM helpers as read only utils | 
|  | 82   static get utils() | 
|  | 83   { | 
|  | 84     return DOMUtils; | 
|  | 85   } | 
|  | 86 | 
| 19   // get a unique ID or, if null, set one and returns it | 87   // get a unique ID or, if null, set one and returns it | 
| 20   static getID(element) | 88   static getID(element) | 
| 21   { | 89   { | 
| 22     return element.getAttribute("id") || IOElement.setID(element); | 90     return element.getAttribute("id") || IOElement.setID(element); | 
| 23   } | 91   } | 
| 24 | 92 | 
| 25   // set a unique ID to a generic element and returns the ID | 93   // set a unique ID to a generic element and returns the ID | 
| 26   static setID(element) | 94   static setID(element) | 
| 27   { | 95   { | 
| 28     const id = `${element.nodeName.toLowerCase()}-${counter++}`; | 96     const id = `${element.nodeName.toLowerCase()}-${counter++}`; | 
| 29     element.setAttribute("id", id); | 97     element.setAttribute("id", id); | 
| 30     return id; | 98     return id; | 
| 31   } | 99   } | 
| 32 | 100 | 
| 33   // lazily retrieve or define a custom element ID | 101   // lazily retrieve or define a custom element ID | 
| 34   get id() | 102   get id() | 
| 35   { | 103   { | 
| 36     return IOElement.getID(this); | 104     return IOElement.getID(this); | 
| 37   } | 105   } | 
| 38 | 106 | 
| 39   // whenever an element is created, render its content once | 107   // whenever an element is created, render its content once | 
| 40   created() { this.render(); } | 108   created() { this.render(); } | 
| 41 | 109 | 
| 42   // by default, render is a no-op | 110   // by default, render is a no-op | 
| 43   render() {} | 111   render() {} | 
|  | 112 | 
|  | 113   // usually a template would contain a main element such | 
|  | 114   // input, button, div, section, etc. | 
|  | 115   // having a simple way to retrieve such element can be | 
|  | 116   // both semantic and handy, as opposite of using | 
|  | 117   // this.children[0] each time | 
|  | 118   get child() | 
|  | 119   { | 
|  | 120     let element = this.firstElementChild; | 
|  | 121     // if accessed too early, will render automatically | 
|  | 122     if (!element) | 
|  | 123     { | 
|  | 124       this.render(); | 
|  | 125       element = this.firstElementChild; | 
|  | 126     } | 
|  | 127     return element; | 
|  | 128   } | 
| 44 } | 129 } | 
| 45 | 130 | 
| 46 // whenever an interpolation with ${{i18n: 'string-id'}} is found | 131 // whenever an interpolation with ${{i18n: 'string-id'}} is found | 
| 47 // transform such value into the expected content | 132 // transform such value into the expected content | 
| 48 // example: | 133 // example: | 
| 49 //  render() { | 134 //  render() { | 
| 50 //    return this.html`<div>${{i18n:'about-abp'}}</div>`; | 135 //    return this.html`<div>${{i18n:'about-abp'}}</div>`; | 
| 51 //  } | 136 //  } | 
| 52 const {setElementText} = ext.i18n; | 137 const {setElementText} = ext.i18n; | 
| 53 IOElement.intent("i18n", id => | 138 IOElement.intent("i18n", id => | 
| 54 { | 139 { | 
| 55   const fragment = document.createDocumentFragment(); | 140   const fragment = document.createDocumentFragment(); | 
| 56   setElementText(fragment, id); | 141   setElementText(fragment, id); | 
| 57   return fragment; | 142   return fragment; | 
| 58 }); | 143 }); | 
| 59 | 144 | 
| 60 module.exports = IOElement; | 145 module.exports = IOElement; | 
| LEFT | RIGHT | 
|---|