This commit is contained in:
gorhill 2014-11-07 10:07:26 -05:00
parent 20d790e30d
commit 2ebe5dc13a
4 changed files with 286 additions and 80 deletions

View file

@ -323,7 +323,7 @@ var updateWidgets = function() {
/******************************************************************************/ /******************************************************************************/
var onListCheckboxChanged = function() { var onListCheckboxChanged = function() {
var href = uDom(this).parent().find('a').first().attr('href'); var href = uDom(this).parent().descendants('a').first().attr('href');
if ( typeof href !== 'string' ) { if ( typeof href !== 'string' ) {
return; return;
} }
@ -349,13 +349,13 @@ var onListLinkClicked = function(ev) {
var onPurgeClicked = function() { var onPurgeClicked = function() {
var button = uDom(this); var button = uDom(this);
var li = button.parent(); var li = button.parent();
var href = li.find('a').first().attr('href'); var href = li.descendants('a').first().attr('href');
if ( !href ) { if ( !href ) {
return; return;
} }
messaging.tell({ what: 'purgeCache', path: href }); messaging.tell({ what: 'purgeCache', path: href });
button.remove(); button.remove();
if ( li.find('input').first().prop('checked') ) { if ( li.descendants('input').first().prop('checked') ) {
cacheWasPurged = true; cacheWasPurged = true;
updateWidgets(); updateWidgets();
} }
@ -377,16 +377,16 @@ var reloadAll = function(update) {
// Reload blacklists // Reload blacklists
var switches = []; var switches = [];
var lis = uDom('#lists .listDetails'); var lis = uDom('#lists .listDetails');
var i = lis.length(); var i = lis.length;
var path; var path;
while ( i-- ) { while ( i-- ) {
path = lis path = lis
.subset(i) .subset(i, 1)
.find('a') .descendants('a')
.attr('href'); .attr('href');
switches.push({ switches.push({
location: path, location: path,
off: lis.subset(i).find('input').prop('checked') === false off: lis.subset(i, 1).descendants('input').prop('checked') === false
}); });
} }
messaging.tell({ messaging.tell({

View file

@ -28,7 +28,7 @@ uDom.onLoad(function() {
uDom('.whatisthis').on('click', function() { uDom('.whatisthis').on('click', function() {
uDom(this) uDom(this)
.parent() .parent()
.find('.whatisthis-expandable') .descendants('.whatisthis-expandable')
.toggleClass('whatisthis-expanded'); .toggleClass('whatisthis-expanded');
}); });
}); });

View file

@ -22,19 +22,19 @@
// Helper to deal with the i18n'ing of HTML files. // Helper to deal with the i18n'ing of HTML files.
uDom.onLoad(function() { uDom.onLoad(function() {
uDom('[data-i18n]').forEach(function() { uDom('[data-i18n]').forEach(function(elem) {
this.innerHTML = chrome.i18n.getMessage(this.getAttribute('data-i18n')); elem.html(chrome.i18n.getMessage(elem.attr('data-i18n')));
}); });
uDom('[title]').forEach(function() { uDom('[title]').forEach(function(elem) {
var title = chrome.i18n.getMessage(this.getAttribute('title')); var title = chrome.i18n.getMessage(elem.attr('title'));
if ( title ) { if ( title ) {
this.setAttribute('title', title); elem.attr('title', title);
} }
}); });
uDom('[data-i18n-tip]').forEach(function() { uDom('[data-i18n-tip]').forEach(function(elem) {
this.setAttribute( elem.attr(
'data-tip', 'data-tip',
chrome.i18n.getMessage(this.getAttribute('data-i18n-tip')).replace(/<br>/g, '') chrome.i18n.getMessage(elem.attr('data-i18n-tip')).replace(/<br>/g, '')
); );
}); });
}); });

View file

@ -38,6 +38,18 @@ var DOMList = function() {
/******************************************************************************/ /******************************************************************************/
Object.defineProperty(
DOMList.prototype,
'length',
{
get: function() {
return this.nodes.length;
}
}
);
/******************************************************************************/
var DOMListFactory = function(selector, context) { var DOMListFactory = function(selector, context) {
var r = new DOMList(); var r = new DOMList();
if ( typeof selector === 'string' ) { if ( typeof selector === 'string' ) {
@ -100,8 +112,8 @@ var addListToList = function(list, other) {
var addSelectorToList = function(list, selector, context) { var addSelectorToList = function(list, selector, context) {
var p = context || document; var p = context || document;
var r = p.querySelectorAll(selector); var r = p.querySelectorAll(selector);
var i = r.length; var n = r.length;
while ( i-- ) { for ( var i = 0; i < n; i++ ) {
list.nodes.push(r[i]); list.nodes.push(r[i]);
} }
return list; return list;
@ -114,6 +126,8 @@ var pTagOfChildTag = {
'option': 'select' 'option': 'select'
}; };
// TODO: documentFragment
var addHTMLToList = function(list, html) { var addHTMLToList = function(list, html) {
var matches = html.match(/^<([a-z]+)/); var matches = html.match(/^<([a-z]+)/);
if ( !matches || matches.length !== 2 ) { if ( !matches || matches.length !== 2 ) {
@ -134,15 +148,99 @@ var addHTMLToList = function(list, html) {
/******************************************************************************/ /******************************************************************************/
var isChildOf = function(child, parent) {
return child !== null && parent !== null && child.parentNode === parent;
};
/******************************************************************************/
var isDescendantOf = function(descendant, ancestor) {
while ( descendant.parentNode !== null ) {
if ( descendant.parentNode === ancestor ) {
return true;
}
descendant = descendant.parentNode;
}
return false;
};
/******************************************************************************/
var nodeInNodeList = function(node, nodeList) {
var i = nodeList.length;
while ( i-- ) {
if ( nodeList[i] === node ) {
return true;
}
}
return false;
};
/******************************************************************************/
var doesMatchSelector = function(node, selector) {
if ( !node ) {
return false;
}
if ( node.nodeType !== 1 ) {
return false;
}
if ( selector === undefined ) {
return true;
}
var parentNode = node.parentNode;
if ( !parentNode || !parentNode.setAttribute ) {
return false;
}
var doesMatch = false;
parentNode.setAttribute('uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO', '');
var grandpaNode = parentNode.parentNode || document;
var nl = grandpaNode.querySelectorAll('[uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO] > ' + selector);
var i = nl.length;
while ( doesMatch === false && i-- ) {
doesMatch = nl[i] === node;
}
parentNode.removeAttribute('uDom-32kXc6xEZA7o73AMB8vLbLct1RZOkeoO');
return doesMatch;
};
/******************************************************************************/
DOMList.prototype.length = function() { DOMList.prototype.length = function() {
return this.nodes.length; return this.nodes.length;
}; };
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.nodeAt = function(i) {
return this.nodes[i];
};
DOMList.prototype.at = function(i) {
return addNodeToList(new DOMList(), this.nodes[i]);
};
/******************************************************************************/
DOMList.prototype.toArray = function() {
return this.nodes.slice();
};
/******************************************************************************/
DOMList.prototype.forEach = function(fn) {
var n = this.nodes.length;
for ( var i = 0; i < n; i++ ) {
fn(this.at(i), i);
}
return this;
};
/******************************************************************************/
DOMList.prototype.subset = function(i, l) { DOMList.prototype.subset = function(i, l) {
var r = new DOMList(); var r = new DOMList();
var n = l !== undefined ? l : 1; var n = l !== undefined ? l : this.nodes.length;
var j = Math.min(i + n, this.nodes.length); var j = Math.min(i + n, this.nodes.length);
if ( i < j ) { if ( i < j ) {
r.nodes = this.nodes.slice(i, j); r.nodes = this.nodes.slice(i, j);
@ -153,13 +251,30 @@ DOMList.prototype.subset = function(i, l) {
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.first = function() { DOMList.prototype.first = function() {
return this.subset(0); return this.subset(0, 1);
}; };
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.node = function(i) { DOMList.prototype.next = function(selector) {
return this.nodes[i]; 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;
if ( node.nodeType !== 1 ) {
continue;
}
if ( doesMatchSelector(node, selector) === false ) {
continue;
}
addNodeToList(r, node);
break;
}
}
return r;
}; };
/******************************************************************************/ /******************************************************************************/
@ -174,7 +289,54 @@ DOMList.prototype.parent = function() {
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.find = function(selector) { DOMList.prototype.filter = function(filter) {
var r = new DOMList();
var filterFunc;
if ( typeof filter === 'string' ) {
filterFunc = function() {
return doesMatchSelector(this, filter);
};
} 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();
var n = this.nodes.length;
var node;
for ( var i = 0; i < n; i++ ) {
node = this.nodes[i].parentNode;
while ( node ) {
if ( doesMatchSelector(node, selector) ) {
addNodeToList(r, node);
}
node = node.parentNode;
}
}
return r;
};
/******************************************************************************/
DOMList.prototype.descendants = function(selector) {
var r = new DOMList(); var r = new DOMList();
var n = this.nodes.length; var n = this.nodes.length;
var nl; var nl;
@ -187,28 +349,36 @@ DOMList.prototype.find = function(selector) {
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.forEach = function(callback) { DOMList.prototype.contents = function() {
var r = new DOMList();
var cnodes, cn, ci;
var n = this.nodes.length; var n = this.nodes.length;
for ( var i = 0; i < n; i++ ) { for ( var i = 0; i < n; i++ ) {
callback.bind(this.nodes[i]).call(); cnodes = this.nodes[i].childNodes;
cn = cnodes.length;
for ( ci = 0; ci < cn; ci++ ) {
addNodeToList(r, cnodes.item(ci));
}
} }
return this; return r;
}; };
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.remove = function() { DOMList.prototype.remove = function() {
var n = this.nodes.length; var cn, p;
var c, p; var i = this.nodes.length;
for ( var i = 0; i < n; i++ ) { while ( i-- ) {
c = this.nodes[i]; cn = this.nodes[i];
if ( p = c.parentNode ) { if ( p = cn.parentNode ) {
p.removeChild(c); p.removeChild(cn);
} }
} }
return this; return this;
}; };
DOMList.prototype.detach = DOMList.prototype.remove;
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.empty = function() { DOMList.prototype.empty = function() {
@ -254,12 +424,10 @@ DOMList.prototype.prepend = function(selector, context) {
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.appendTo = function(selector, context) { DOMList.prototype.appendTo = function(selector, context) {
var p = DOMListFactory(selector, context); var p = selector instanceof DOMListFactory ? selector : DOMListFactory(selector, context);
if ( p.length ) { var n = p.length;
var n = this.nodes.length; for ( var i = 0; i < n; i++ ) {
for ( var i = 0; i < n; i++ ) { p.nodes[0].appendChild(this.nodes[i]);
p.nodes[0].appendChild(this.nodes[i]);
}
} }
return this; return this;
}; };
@ -284,6 +452,28 @@ DOMList.prototype.insertAfter = function(selector, context) {
/******************************************************************************/ /******************************************************************************/
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;
};
/******************************************************************************/
DOMList.prototype.clone = function(notDeep) { DOMList.prototype.clone = function(notDeep) {
var r = new DOMList(); var r = new DOMList();
var n = this.nodes.length; var n = this.nodes.length;
@ -324,7 +514,7 @@ DOMList.prototype.attr = function(attr, value) {
DOMList.prototype.prop = function(prop, value) { DOMList.prototype.prop = function(prop, value) {
var i = this.nodes.length; var i = this.nodes.length;
if ( value === undefined ) { if ( value === undefined ) {
return i ? this.nodes[0][prop] : undefined; return i !== 0 ? this.nodes[0][prop] : undefined;
} }
while ( i-- ) { while ( i-- ) {
this.nodes[i][prop] = value; this.nodes[i][prop] = value;
@ -379,13 +569,33 @@ DOMList.prototype.text = function(text) {
/******************************************************************************/ /******************************************************************************/
DOMList.prototype.hasClassName = function(className) { var toggleClass = function(node, className, targetState) {
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;
}
tokenList.toggle(className, newState)
};
/******************************************************************************/
DOMList.prototype.hasClass = function(className) {
if ( !this.nodes.length ) { if ( !this.nodes.length ) {
return false; return false;
} }
var re = new RegExp('(^| )' + className + '( |$)'); var tokenList = this.nodes[0].classList;
return re.test(this.nodes[0].className); return tokenList instanceof DOMTokenList &&
tokenList.contains(className);
}; };
DOMList.prototype.hasClassName = DOMList.prototype.hasClass;
DOMList.prototype.addClass = function(className) { DOMList.prototype.addClass = function(className) {
return this.toggleClass(className, true); return this.toggleClass(className, true);
@ -402,49 +612,46 @@ DOMList.prototype.removeClass = function(className) {
return this; return this;
}; };
/******************************************************************************/
DOMList.prototype.toggleClass = function(className, targetState) { DOMList.prototype.toggleClass = function(className, targetState) {
var re = new RegExp('(^| )' + className + '( |$)'); if ( className.indexOf(' ') !== -1 ) {
var n = this.nodes.length; return this.toggleClasses(className, true);
var node, currentState, newState, newClassName; }
for ( var i = 0; i < n; i++ ) { var i = this.nodes.length;
node = this.nodes[i]; while ( i-- ) {
currentState = re.test(node.className); toggleClass(this.nodes[i], className, targetState);
newState = targetState;
if ( newState === undefined ) {
newState = !currentState;
}
if ( newState === currentState ) {
continue;
}
newClassName = node.className;
if ( newState ) {
newClassName += ' ' + className;
} else {
newClassName = newClassName.replace(re, ' ');
}
node.className = newClassName.trim();
} }
return this; return this;
}; };
/******************************************************************************/ /******************************************************************************/
var makeEventHandler = function(context, selector, callback) { DOMList.prototype.toggleClasses = function(classNames, targetState) {
var tokens = classNames.split(/\s+/);
var i = this.nodes.length;
var node, j;
while ( i-- ) {
node = this.nodes[i];
j = tokens.length;
while ( j-- ) {
toggleClass(node, tokens[j], targetState);
}
}
return this;
};
/******************************************************************************/
var makeEventHandler = function(selector, callback) {
return function(event) { return function(event) {
var candidates = context.querySelectorAll(selector); var dispatcher = event.currentTarget;
if ( !candidates.length ) { if ( !dispatcher || typeof dispatcher.querySelectorAll !== 'function' ) {
return; return;
} }
var node = event.target; var receiver = event.target;
var i; if ( nodeInNodeList(receiver, dispatcher.querySelectorAll(selector)) ) {
while ( node && node !== context ) { callback.call(receiver, event);
i = candidates.length;
while ( i-- ) {
if ( candidates[i] === node ) {
return callback.call(node, event);
}
}
node = node.parentNode;
} }
}; };
}; };
@ -453,14 +660,13 @@ DOMList.prototype.on = function(etype, selector, callback) {
if ( typeof selector === 'function' ) { if ( typeof selector === 'function' ) {
callback = selector; callback = selector;
selector = undefined; selector = undefined;
} else {
callback = makeEventHandler(selector, callback);
} }
var i = this.nodes.length; var i = this.nodes.length;
while ( i-- ) { while ( i-- ) {
if ( selector !== undefined ) { this.nodes[i].addEventListener(etype, callback, selector !== undefined);
this.nodes[i].addEventListener(etype, makeEventHandler(this.nodes[i], selector, callback), true);
} else {
this.nodes[i].addEventListener(etype, callback);
}
} }
return this; return this;
}; };