2014-07-02 18:02:29 +02:00
|
|
|
/*******************************************************************************
|
|
|
|
|
2016-10-18 18:33:50 +02:00
|
|
|
uBlock Origin - a browser extension to block requests.
|
2019-01-14 20:57:31 +01:00
|
|
|
Copyright (C) 2014-present Raymond Hill
|
2014-07-02 18:02:29 +02:00
|
|
|
|
|
|
|
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 {http://www.gnu.org/licenses/}.
|
|
|
|
|
|
|
|
Home: https://github.com/gorhill/uBlock
|
|
|
|
*/
|
|
|
|
|
2015-03-14 19:12:05 +01:00
|
|
|
/* global DOMTokenList */
|
2014-10-19 13:11:27 +02:00
|
|
|
/* exported uDom */
|
|
|
|
|
2016-11-05 19:48:42 +01:00
|
|
|
'use strict';
|
|
|
|
|
2014-07-02 18:02:29 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// It's just a silly, minimalist DOM framework: this allows me to not rely
|
|
|
|
// on jQuery. jQuery contains way too much stuff than I need, and as per
|
|
|
|
// Opera rules, I am not allowed to use a cut-down version of jQuery. So
|
|
|
|
// the code here does *only* what I need, and nothing more, and with a lot
|
|
|
|
// of assumption on passed parameters, etc. I grow it on a per-need-basis only.
|
|
|
|
|
2020-04-18 15:48:53 +02:00
|
|
|
const uDom = (( ) => {
|
2014-07-02 18:02:29 +02:00
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-14 20:57:31 +01:00
|
|
|
const DOMList = function() {
|
2014-07-02 18:02:29 +02:00
|
|
|
this.nodes = [];
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-10 19:25:17 +01:00
|
|
|
Object.defineProperty(
|
|
|
|
DOMList.prototype,
|
|
|
|
'length',
|
|
|
|
{
|
|
|
|
get: function() {
|
|
|
|
return this.nodes.length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-14 20:57:31 +01:00
|
|
|
const DOMListFactory = function(selector, context) {
|
2014-07-02 18:02:29 +02:00
|
|
|
var r = new DOMList();
|
|
|
|
if ( typeof selector === 'string' ) {
|
|
|
|
selector = selector.trim();
|
|
|
|
if ( selector !== '' ) {
|
|
|
|
return addSelectorToList(r, selector, context);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( selector instanceof Node ) {
|
|
|
|
return addNodeToList(r, selector);
|
|
|
|
}
|
|
|
|
if ( selector instanceof NodeList ) {
|
|
|
|
return addNodeListToList(r, selector);
|
|
|
|
}
|
|
|
|
if ( selector instanceof DOMList ) {
|
|
|
|
return addListToList(r, selector);
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMListFactory.onLoad = function(callback) {
|
|
|
|
window.addEventListener('load', callback);
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-06-10 14:25:47 +02:00
|
|
|
DOMListFactory.nodeFromId = function(id) {
|
|
|
|
return document.getElementById(id);
|
|
|
|
};
|
|
|
|
|
2015-06-10 14:58:10 +02:00
|
|
|
DOMListFactory.nodeFromSelector = function(selector) {
|
|
|
|
return document.querySelector(selector);
|
|
|
|
};
|
|
|
|
|
2015-06-10 14:25:47 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2020-04-18 15:48:53 +02:00
|
|
|
{
|
2020-10-03 13:13:40 +02:00
|
|
|
// https://github.com/uBlockOrigin/uBlock-issues/issues/1044
|
|
|
|
// Offer the possibility to bypass uBO's default styling
|
|
|
|
vAPI.messaging.send('uDom', { what: 'uiStyles' }).then(response => {
|
|
|
|
if ( typeof response !== 'object' || response === null ) { return; }
|
|
|
|
if ( response.uiTheme !== 'unset' ) {
|
|
|
|
if ( response.uiTheme === 'light' ) {
|
|
|
|
root.classList.remove('dark');
|
|
|
|
} else if ( response.uiTheme === 'dark' ) {
|
|
|
|
root.classList.add('dark');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if ( response.uiStyles !== 'unset' ) {
|
2020-10-17 18:05:03 +02:00
|
|
|
document.body.style.cssText = response.uiStyles;
|
2020-10-03 13:13:40 +02:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-04-18 15:48:53 +02:00
|
|
|
const root = DOMListFactory.root = document.querySelector(':root');
|
2020-05-19 16:29:09 +02:00
|
|
|
if ( vAPI.webextFlavor.soup.has('mobile') ) {
|
2020-04-18 15:48:53 +02:00
|
|
|
root.classList.add('mobile');
|
2020-05-19 16:29:09 +02:00
|
|
|
} else {
|
2020-04-18 15:48:53 +02:00
|
|
|
root.classList.add('desktop');
|
|
|
|
}
|
2020-04-22 17:17:58 +02:00
|
|
|
if ( window.matchMedia('(min-resolution: 150dpi)').matches ) {
|
|
|
|
root.classList.add('hidpi');
|
|
|
|
}
|
2020-11-13 18:15:29 +01:00
|
|
|
// TODO: re-enable once there is a fully functional dark theme
|
|
|
|
//if ( window.matchMedia('(prefers-color-scheme: dark)').matches ) {
|
|
|
|
// root.classList.add('dark');
|
|
|
|
//}
|
2020-04-18 15:48:53 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-14 20:57:31 +01:00
|
|
|
const addNodeToList = function(list, node) {
|
2014-07-02 18:02:29 +02:00
|
|
|
if ( node ) {
|
|
|
|
list.nodes.push(node);
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-14 20:57:31 +01:00
|
|
|
const addNodeListToList = function(list, nodelist) {
|
2014-07-02 18:02:29 +02:00
|
|
|
if ( nodelist ) {
|
|
|
|
var n = nodelist.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
list.nodes.push(nodelist[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-14 20:57:31 +01:00
|
|
|
const addListToList = function(list, other) {
|
2014-07-02 18:02:29 +02:00
|
|
|
list.nodes = list.nodes.concat(other.nodes);
|
|
|
|
return list;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-14 20:57:31 +01:00
|
|
|
const addSelectorToList = function(list, selector, context) {
|
2014-07-02 18:02:29 +02:00
|
|
|
var p = context || document;
|
|
|
|
var r = p.querySelectorAll(selector);
|
2014-11-07 16:07:26 +01:00
|
|
|
var n = r.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
2014-07-02 18:02:29 +02:00
|
|
|
list.nodes.push(r[i]);
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.nodeAt = function(i) {
|
2015-12-13 06:17:38 +01:00
|
|
|
return this.nodes[i] || null;
|
2014-11-07 16:07:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
DOMList.prototype.at = function(i) {
|
|
|
|
return addNodeToList(new DOMList(), this.nodes[i]);
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.toArray = function() {
|
|
|
|
return this.nodes.slice();
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-01-10 17:23:28 +01:00
|
|
|
DOMList.prototype.pop = function() {
|
|
|
|
return addNodeToList(new DOMList(), this.nodes.pop());
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.forEach = function(fn) {
|
|
|
|
var n = this.nodes.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
fn(this.at(i), i);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-07-02 18:02:29 +02:00
|
|
|
DOMList.prototype.subset = function(i, l) {
|
|
|
|
var r = new DOMList();
|
2014-11-07 16:07:26 +01:00
|
|
|
var n = l !== undefined ? l : this.nodes.length;
|
2014-07-02 18:02:29 +02:00
|
|
|
var j = Math.min(i + n, this.nodes.length);
|
|
|
|
if ( i < j ) {
|
2014-07-07 03:52:16 +02:00
|
|
|
r.nodes = this.nodes.slice(i, j);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.first = function() {
|
2014-11-07 16:07:26 +01:00
|
|
|
return this.subset(0, 1);
|
2014-07-02 18:02:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.next = function(selector) {
|
|
|
|
var r = new DOMList();
|
|
|
|
var n = this.nodes.length;
|
|
|
|
var node;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
node = this.nodes[i];
|
|
|
|
while ( node.nextSibling !== null ) {
|
|
|
|
node = node.nextSibling;
|
2018-04-09 14:28:36 +02:00
|
|
|
if ( node.nodeType !== 1 ) { continue; }
|
|
|
|
if ( node.matches(selector) === false ) { continue; }
|
2014-11-07 16:07:26 +01:00
|
|
|
addNodeToList(r, node);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
2014-07-02 18:02:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.parent = function() {
|
|
|
|
var r = new DOMList();
|
|
|
|
if ( this.nodes.length ) {
|
2014-07-07 03:52:16 +02:00
|
|
|
addNodeToList(r, this.nodes[0].parentNode);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.filter = function(filter) {
|
|
|
|
var r = new DOMList();
|
|
|
|
var filterFunc;
|
|
|
|
if ( typeof filter === 'string' ) {
|
|
|
|
filterFunc = function() {
|
2018-04-09 14:28:36 +02:00
|
|
|
return this.matches(filter);
|
2014-11-07 16:07:26 +01:00
|
|
|
};
|
|
|
|
} else if ( typeof filter === 'function' ) {
|
|
|
|
filterFunc = filter;
|
|
|
|
} else {
|
|
|
|
filterFunc = function(){
|
|
|
|
return true;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
var n = this.nodes.length;
|
|
|
|
var node;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
node = this.nodes[i];
|
|
|
|
if ( filterFunc.apply(node) ) {
|
|
|
|
addNodeToList(r, node);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// TODO: Avoid possible duplicates
|
|
|
|
|
|
|
|
DOMList.prototype.ancestors = function(selector) {
|
|
|
|
var r = new DOMList();
|
2018-04-09 14:28:36 +02:00
|
|
|
for ( var i = 0, n = this.nodes.length; i < n; i++ ) {
|
|
|
|
var node = this.nodes[i].parentNode;
|
2014-11-07 16:07:26 +01:00
|
|
|
while ( node ) {
|
2018-04-09 14:28:36 +02:00
|
|
|
if (
|
|
|
|
node instanceof Element &&
|
|
|
|
node.matches(selector)
|
|
|
|
) {
|
2014-11-07 16:07:26 +01:00
|
|
|
addNodeToList(r, node);
|
|
|
|
}
|
|
|
|
node = node.parentNode;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.descendants = function(selector) {
|
2014-07-02 18:02:29 +02:00
|
|
|
var r = new DOMList();
|
|
|
|
var n = this.nodes.length;
|
|
|
|
var nl;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
nl = this.nodes[i].querySelectorAll(selector);
|
2014-07-07 03:52:16 +02:00
|
|
|
addNodeListToList(r, nl);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.contents = function() {
|
|
|
|
var r = new DOMList();
|
|
|
|
var cnodes, cn, ci;
|
2014-07-02 18:02:29 +02:00
|
|
|
var n = this.nodes.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
2014-11-07 16:07:26 +01:00
|
|
|
cnodes = this.nodes[i].childNodes;
|
|
|
|
cn = cnodes.length;
|
|
|
|
for ( ci = 0; ci < cn; ci++ ) {
|
|
|
|
addNodeToList(r, cnodes.item(ci));
|
|
|
|
}
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
2014-11-07 16:07:26 +01:00
|
|
|
return r;
|
2014-07-02 18:02:29 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.remove = function() {
|
2014-11-07 16:07:26 +01:00
|
|
|
var cn, p;
|
|
|
|
var i = this.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
cn = this.nodes[i];
|
2015-08-18 17:44:24 +02:00
|
|
|
if ( (p = cn.parentNode) ) {
|
2014-11-07 16:07:26 +01:00
|
|
|
p.removeChild(cn);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.detach = DOMList.prototype.remove;
|
|
|
|
|
2014-07-02 18:02:29 +02:00
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.empty = function() {
|
|
|
|
var node;
|
|
|
|
var i = this.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
node = this.nodes[i];
|
|
|
|
while ( node.firstChild ) {
|
|
|
|
node.removeChild(node.firstChild);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.append = function(selector, context) {
|
|
|
|
var p = this.nodes[0];
|
|
|
|
if ( p ) {
|
|
|
|
var c = DOMListFactory(selector, context);
|
|
|
|
var n = c.nodes.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
p.appendChild(c.nodes[i]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.prepend = function(selector, context) {
|
|
|
|
var p = this.nodes[0];
|
|
|
|
if ( p ) {
|
|
|
|
var c = DOMListFactory(selector, context);
|
|
|
|
var i = c.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
p.insertBefore(c.nodes[i], p.firstChild);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.appendTo = function(selector, context) {
|
2014-11-07 16:07:26 +01:00
|
|
|
var p = selector instanceof DOMListFactory ? selector : DOMListFactory(selector, context);
|
|
|
|
var n = p.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
p.nodes[0].appendChild(this.nodes[i]);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.insertAfter = function(selector, context) {
|
|
|
|
if ( this.nodes.length === 0 ) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var p = this.nodes[0].parentNode;
|
|
|
|
if ( !p ) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var c = DOMListFactory(selector, context);
|
|
|
|
var n = c.nodes.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
p.appendChild(c.nodes[i]);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.insertBefore = function(selector, context) {
|
|
|
|
if ( this.nodes.length === 0 ) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var referenceNodes = DOMListFactory(selector, context);
|
|
|
|
if ( referenceNodes.nodes.length === 0 ) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var referenceNode = referenceNodes.nodes[0];
|
|
|
|
var parentNode = referenceNode.parentNode;
|
|
|
|
if ( !parentNode ) {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
var n = this.nodes.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
parentNode.insertBefore(this.nodes[i], referenceNode);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-07-02 18:02:29 +02:00
|
|
|
DOMList.prototype.clone = function(notDeep) {
|
|
|
|
var r = new DOMList();
|
|
|
|
var n = this.nodes.length;
|
|
|
|
for ( var i = 0; i < n; i++ ) {
|
|
|
|
addNodeToList(r, this.nodes[i].cloneNode(!notDeep));
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2015-03-14 19:12:05 +01:00
|
|
|
DOMList.prototype.nthOfType = function() {
|
|
|
|
if ( this.nodes.length === 0 ) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
var node = this.nodes[0];
|
|
|
|
var tagName = node.tagName;
|
|
|
|
var i = 1;
|
|
|
|
while ( node.previousElementSibling !== null ) {
|
|
|
|
node = node.previousElementSibling;
|
|
|
|
if ( typeof node.tagName !== 'string' ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ( node.tagName !== tagName ) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
return i;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-07-02 18:02:29 +02:00
|
|
|
DOMList.prototype.attr = function(attr, value) {
|
|
|
|
var i = this.nodes.length;
|
|
|
|
if ( value === undefined && typeof attr !== 'object' ) {
|
|
|
|
return i ? this.nodes[0].getAttribute(attr) : undefined;
|
|
|
|
}
|
|
|
|
if ( typeof attr === 'object' ) {
|
|
|
|
var attrNames = Object.keys(attr);
|
|
|
|
var node, j, attrName;
|
|
|
|
while ( i-- ) {
|
|
|
|
node = this.nodes[i];
|
|
|
|
j = attrNames.length;
|
|
|
|
while ( j-- ) {
|
|
|
|
attrName = attrNames[j];
|
|
|
|
node.setAttribute(attrName, attr[attrName]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i].setAttribute(attr, value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2016-11-05 19:48:42 +01:00
|
|
|
DOMList.prototype.removeAttr = function(attr) {
|
|
|
|
var i = this.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i].removeAttribute(attr);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-07-02 18:02:29 +02:00
|
|
|
DOMList.prototype.prop = function(prop, value) {
|
|
|
|
var i = this.nodes.length;
|
|
|
|
if ( value === undefined ) {
|
2014-11-07 16:07:26 +01:00
|
|
|
return i !== 0 ? this.nodes[0][prop] : undefined;
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i][prop] = value;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.css = function(prop, value) {
|
|
|
|
var i = this.nodes.length;
|
|
|
|
if ( value === undefined ) {
|
|
|
|
return i ? this.nodes[0].style[prop] : undefined;
|
|
|
|
}
|
2015-07-20 22:33:07 +02:00
|
|
|
if ( value !== '' ) {
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i].style.setProperty(prop, value);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
2014-07-02 18:02:29 +02:00
|
|
|
while ( i-- ) {
|
2015-07-20 22:33:07 +02:00
|
|
|
this.nodes[i].style.removeProperty(prop);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.val = function(value) {
|
|
|
|
return this.prop('value', value);
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.text = function(text) {
|
|
|
|
var i = this.nodes.length;
|
|
|
|
if ( text === undefined ) {
|
|
|
|
return i ? this.nodes[0].textContent : '';
|
|
|
|
}
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i].textContent = text;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-14 20:57:31 +01:00
|
|
|
const toggleClass = function(node, className, targetState) {
|
2014-11-07 16:07:26 +01:00
|
|
|
var tokenList = node.classList;
|
|
|
|
if ( tokenList instanceof DOMTokenList === false ) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
var currentState = tokenList.contains(className);
|
|
|
|
var newState = targetState;
|
|
|
|
if ( newState === undefined ) {
|
|
|
|
newState = !currentState;
|
|
|
|
}
|
|
|
|
if ( newState === currentState ) {
|
|
|
|
return;
|
|
|
|
}
|
2014-11-07 16:47:09 +01:00
|
|
|
tokenList.toggle(className, newState);
|
2014-11-07 16:07:26 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.hasClass = function(className) {
|
2014-07-02 18:02:29 +02:00
|
|
|
if ( !this.nodes.length ) {
|
|
|
|
return false;
|
|
|
|
}
|
2014-11-07 16:07:26 +01:00
|
|
|
var tokenList = this.nodes[0].classList;
|
|
|
|
return tokenList instanceof DOMTokenList &&
|
|
|
|
tokenList.contains(className);
|
2014-07-02 18:02:29 +02:00
|
|
|
};
|
2014-11-07 16:07:26 +01:00
|
|
|
DOMList.prototype.hasClassName = DOMList.prototype.hasClass;
|
2014-07-02 18:02:29 +02:00
|
|
|
|
|
|
|
DOMList.prototype.addClass = function(className) {
|
2014-07-07 19:02:03 +02:00
|
|
|
return this.toggleClass(className, true);
|
2014-07-02 18:02:29 +02:00
|
|
|
};
|
|
|
|
|
2014-07-07 19:02:03 +02:00
|
|
|
DOMList.prototype.removeClass = function(className) {
|
|
|
|
if ( className !== undefined ) {
|
|
|
|
return this.toggleClass(className, false);
|
|
|
|
}
|
2014-07-02 18:02:29 +02:00
|
|
|
var i = this.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i].className = '';
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
2014-11-07 16:07:26 +01:00
|
|
|
/******************************************************************************/
|
|
|
|
|
2014-07-02 18:02:29 +02:00
|
|
|
DOMList.prototype.toggleClass = function(className, targetState) {
|
2014-11-07 16:07:26 +01:00
|
|
|
if ( className.indexOf(' ') !== -1 ) {
|
2014-11-07 16:47:09 +01:00
|
|
|
return this.toggleClasses(className, targetState);
|
2014-11-07 16:07:26 +01:00
|
|
|
}
|
|
|
|
var i = this.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
toggleClass(this.nodes[i], className, targetState);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.toggleClasses = function(classNames, targetState) {
|
|
|
|
var tokens = classNames.split(/\s+/);
|
|
|
|
var i = this.nodes.length;
|
|
|
|
var node, j;
|
|
|
|
while ( i-- ) {
|
2014-07-02 18:02:29 +02:00
|
|
|
node = this.nodes[i];
|
2014-11-07 16:07:26 +01:00
|
|
|
j = tokens.length;
|
|
|
|
while ( j-- ) {
|
|
|
|
toggleClass(node, tokens[j], targetState);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-12 22:36:20 +01:00
|
|
|
const listenerEntries = [];
|
2015-01-04 16:03:51 +01:00
|
|
|
|
2019-01-12 22:36:20 +01:00
|
|
|
const ListenerEntry = function(target, type, capture, callback) {
|
2015-01-04 16:03:51 +01:00
|
|
|
this.target = target;
|
|
|
|
this.type = type;
|
|
|
|
this.capture = capture;
|
|
|
|
this.callback = callback;
|
|
|
|
target.addEventListener(type, callback, capture);
|
|
|
|
};
|
|
|
|
|
|
|
|
ListenerEntry.prototype.dispose = function() {
|
|
|
|
this.target.removeEventListener(this.type, this.callback, this.capture);
|
|
|
|
this.target = null;
|
|
|
|
this.callback = null;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
2019-01-12 22:36:20 +01:00
|
|
|
const makeEventHandler = function(selector, callback) {
|
2014-07-02 18:02:29 +02:00
|
|
|
return function(event) {
|
2019-01-12 22:36:20 +01:00
|
|
|
const dispatcher = event.currentTarget;
|
|
|
|
if (
|
|
|
|
dispatcher instanceof HTMLElement === false ||
|
|
|
|
typeof dispatcher.querySelectorAll !== 'function'
|
|
|
|
) {
|
2014-07-02 18:02:29 +02:00
|
|
|
return;
|
|
|
|
}
|
2019-01-12 22:36:20 +01:00
|
|
|
const receiver = event.target;
|
2019-01-14 20:57:31 +01:00
|
|
|
const ancestor = receiver.closest(selector);
|
|
|
|
if (
|
2019-01-15 14:18:45 +01:00
|
|
|
ancestor === receiver &&
|
2019-01-14 20:57:31 +01:00
|
|
|
ancestor !== dispatcher &&
|
|
|
|
dispatcher.contains(ancestor)
|
|
|
|
) {
|
2014-11-07 16:07:26 +01:00
|
|
|
callback.call(receiver, event);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
DOMList.prototype.on = function(etype, selector, callback) {
|
|
|
|
if ( typeof selector === 'function' ) {
|
|
|
|
callback = selector;
|
|
|
|
selector = undefined;
|
2014-11-07 16:07:26 +01:00
|
|
|
} else {
|
|
|
|
callback = makeEventHandler(selector, callback);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
2014-11-07 16:07:26 +01:00
|
|
|
|
2019-01-12 22:36:20 +01:00
|
|
|
for ( const node of this.nodes ) {
|
|
|
|
listenerEntries.push(
|
|
|
|
new ListenerEntry(node, etype, selector !== undefined, callback)
|
|
|
|
);
|
2014-07-02 18:02:29 +02:00
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
// TODO: Won't work for delegated handlers. Need to figure
|
|
|
|
// what needs to be done.
|
|
|
|
|
|
|
|
DOMList.prototype.off = function(evtype, callback) {
|
|
|
|
var i = this.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i].removeEventListener(evtype, callback);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
DOMList.prototype.trigger = function(etype) {
|
|
|
|
var ev = new CustomEvent(etype);
|
|
|
|
var i = this.nodes.length;
|
|
|
|
while ( i-- ) {
|
|
|
|
this.nodes[i].dispatchEvent(ev);
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
|
|
|
|
/******************************************************************************/
|
|
|
|
|
|
|
|
return DOMListFactory;
|
|
|
|
|
|
|
|
})();
|