summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/YUI/DomQuery.js
Side-by-side diff
Diffstat (limited to 'frontend/delta/js/Clipperz/YUI/DomQuery.js') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/delta/js/Clipperz/YUI/DomQuery.js709
1 files changed, 709 insertions, 0 deletions
diff --git a/frontend/delta/js/Clipperz/YUI/DomQuery.js b/frontend/delta/js/Clipperz/YUI/DomQuery.js
new file mode 100644
index 0000000..c1af0ca
--- a/dev/null
+++ b/frontend/delta/js/Clipperz/YUI/DomQuery.js
@@ -0,0 +1,709 @@
+/*
+
+Copyright 2008-2013 Clipperz Srl
+
+This file is part of Clipperz, the online password manager.
+For further information about its features and functionalities please
+refer to http://www.clipperz.com.
+
+* Clipperz is free software: you can redistribute it and/or modify it
+ under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+* Clipperz 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 Affero General Public License for more details.
+
+* You should have received a copy of the GNU Affero General Public
+ License along with Clipperz. If not, see http://www.gnu.org/licenses/.
+
+*/
+
+if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
+if (typeof(Clipperz.YUI) == 'undefined') { Clipperz.YUI = {}; }
+
+
+/*
+ * yui-ext 0.40
+ * Copyright(c) 2006, Jack Slocum.
+ */
+
+/**
+ * @class Clipperz.YUI.DomQuery
+ * Provides high performance selector/xpath processing by compiling queries into reusable functions.
+ * New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
+ * @singleton
+ */
+Clipperz.YUI.DomQuery = function(){
+ var cache = {}, simpleCache = {}, valueCache = {};
+ var nonSpace = /\S/;
+ var trimRe = /^\s*(.*?)\s*$/;
+ var tplRe = /\{(\d+)\}/g;
+ var modeRe = /^(\s?[\/>]\s?|\s|$)/;
+ var clsRes = {};
+
+ function child(p, index){
+ var i = 0;
+ var n = p.firstChild;
+ while(n){
+ if(n.nodeType == 1){
+ i++;
+ if(i == index){
+ return n;
+ }
+ }
+ n = n.nextSibling;
+ }
+ return null;
+ };
+
+ function next(d){
+ var n = d.nextSibling;
+ while(n && n.nodeType != 1){
+ n = n.nextSibling;
+ }
+ return n;
+ };
+
+ function prev(d){
+ var n = d.previousSibling;
+ while(n && n.nodeType != 1){
+ n = n.previousSibling;
+ }
+ return n;
+ };
+
+ function clean(d){
+ var n = d.firstChild, ni = -1;
+ while(n){
+ var nx = n.nextSibling;
+ if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
+ d.removeChild(n);
+ }else{
+ n.nodeIndex = ++ni;
+ }
+ n = nx;
+ }
+ return this;
+ };
+
+ function byClassName(c, a, v){
+ if(!v){
+ return c;
+ }
+ var re = clsRes[v];
+ if(!re){
+ re = new RegExp('(?:^|\\s)(?:' + v + ')(?:\\s|$)');
+ clsRes[v] = re;
+ }
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ if(re.test(ci.className)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ };
+
+ function convert(c){
+ if(c.slice){
+ return c;
+ }
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ r[r.length] = c[i];
+ }
+ return r;
+ };
+
+ function attrValue(n, attr){
+ if(!n.tagName && typeof n.length != 'undefined'){
+ n = n[0];
+ }
+ if(!n){
+ return null;
+ }
+ if(attr == 'for'){
+ return n.htmlFor;
+ }
+ if(attr == 'class' || attr == 'className'){
+ return n.className;
+ }
+ return n.getAttribute(attr) || n[attr];
+
+ };
+
+ function getNodes(ns, mode, tagName){
+ var result = [], cs;
+ if(!ns){
+ return result;
+ }
+ mode = mode ? mode.replace(trimRe, '$1') : '';
+ tagName = tagName || '*';
+ if(ns.tagName || ns == document){
+ ns = [ns];
+ }
+ if(mode != '/' && mode != '>'){
+ for(var i = 0, ni; ni = ns[i]; i++){
+ cs = ni.getElementsByTagName(tagName);
+ result = concat(result, cs);
+ }
+ }else{
+ for(var i = 0, ni; ni = ns[i]; i++){
+ var cn = ni.getElementsByTagName(tagName);
+ for(var j = 0, cj; cj = cn[j]; j++){
+ if(cj.parentNode == ni){
+ result[result.length] = cj;
+ }
+ }
+ }
+
+ }
+ return result;
+ };
+
+ function concat(a, b){
+ if(b.slice){
+ return a.concat(b);
+ }
+ for(var i = 0, l = b.length; i < l; i++){
+ a[a.length] = b[i];
+ }
+ return a;
+ }
+
+ function byTag(cs, tagName){
+ if(cs.tagName || cs == document){
+ cs = [cs];
+ }
+ if(!tagName){
+ return cs;
+ }
+ var r = []; tagName = tagName.toLowerCase();
+ for(var i = 0, ci; ci = cs[i]; i++){
+ if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ };
+
+ function byId(cs, attr, id){
+ if(cs.tagName || cs == document){
+ cs = [cs];
+ }
+ if(!id){
+ return cs;
+ }
+ var r = [];
+ for(var i = 0, l = cs.length; i < l; i++){
+ var ci = cs[i];
+ if(ci && ci.id == id){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ };
+
+ function byAttribute(cs, attr, value, op, custom){
+ var r = [], st = custom=='{';
+ var f = Clipperz.YUI.DomQuery.operators[op];
+ for(var i = 0, l = cs.length; i < l; i++){
+ var a;
+ if(st){
+ a = Clipperz.YUI.DomQuery.getStyle(cs[i], attr);
+ }
+ else if(attr == 'class' || attr == 'className'){
+ a = cs[i].className;
+ }else if(attr == 'for'){
+ a = cs[i].htmlFor;
+ }else{
+ a = cs[i].getAttribute(attr);
+ }
+ if((f && f(a, value)) || (!f && a)){
+ r[r.length] = cs[i];
+ }
+ }
+ return r;
+ };
+
+ function byPseudo(cs, name, value){
+ return Clipperz.YUI.DomQuery.pseudos[name](cs, value);
+ };
+
+ // This is for IE MSXML which does not support expandos.
+ // IE runs the same speed using setAttribute, however FF slows way down
+ // and Safari completely fails so they need to continue to use expandos.
+ // Branched at load time for faster execution.
+ var isIE = window.ActiveXObject;
+ var addAttr = isIE ?
+ function(n, a, v){
+ n.setAttribute(a, v);
+ } :
+ function(n, a, v){
+ n[a] = v;
+ };
+ var getAttr = isIE ?
+ function(n, a){
+ return n.getAttribute(a);
+ } :
+ function(n, a){
+ return n[a];
+ };
+ var clearAttr = isIE ?
+ function(n, a){
+ n.removeAttribute(a);
+ } :
+ function(n, a, v){
+ delete n[a];
+ };
+
+ function nodup(cs){
+ if(!cs.length){
+ return cs;
+ }
+ addAttr(cs[0], '_nodup', true);
+ var r = [cs[0]];
+ for(var i = 1, len = cs.length; i < len; i++){
+ var c = cs[i];
+ if(!getAttr(c, '_nodup')){
+ addAttr(c, '_nodup', true);
+ r[r.length] = c;
+ }
+ }
+ for(var i = 0, len = cs.length; i < len; i++){
+ clearAttr(cs[i], '_nodup');
+ }
+ return r;
+ }
+
+ function quickDiff(c1, c2){
+ if(!c1.length){
+ return c2;
+ }
+ for(var i = 0, len = c1.length; i < len; i++){
+ addAttr(c1[i], '_qdiff', true);
+ }
+ var r = [];
+ for(var i = 0, len = c2.length; i < len; i++){
+ if(!getAttr(c2[i], '_qdiff')){
+ r[r.length] = c2[i];
+ }
+ }
+ for(var i = 0, len = c1.length; i < len; i++){
+ clearAttr(c1[i], '_qdiff');
+ }
+ return r;
+ }
+
+ function quickId(ns, mode, root, id){
+ if(ns == root){
+ var d = root.ownerDocument || root;
+ return d.getElementById(id);
+ }
+ ns = getNodes(ns, mode, '*');
+ return byId(ns, null, id);
+ }
+
+ return {
+ getStyle : function(el, name){
+ return YAHOO.util.Dom.getStyle(el, name);
+ },
+ /**
+ * Compiles a selector/xpath query into a reusable function. The returned function
+ * takes one parameter "root" (optional), which is the context node from where the query should start.
+ * @param {String} selector The selector/xpath query
+ * @param {String} type (optional) Either 'select' (the default) or 'simple' for a simple selector match
+ * @return {Function}
+ */
+ compile : function(path, type){
+ // strip leading slashes
+ while(path.substr(0, 1)=='/'){
+ path = path.substr(1);
+ }
+ type = type || 'select';
+
+ var fn = ['var f = function(root){\n var mode; var n = root || document;\n'];
+ var q = path, mode, lq;
+ var tk = Clipperz.YUI.DomQuery.matchers;
+ var tklen = tk.length;
+ var mm;
+ while(q && lq != q){
+ lq = q;
+ var tm = q.match(/^(#)?([\w-\*]+)/);
+ if(type == 'select'){
+ if(tm){
+ if(tm[1] == '#'){
+ fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
+ }else{
+ fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
+ }
+ q = q.replace(tm[0], '');
+ }else{
+ fn[fn.length] = 'n = getNodes(n, mode, "*");';
+ }
+ }else{
+ if(tm){
+ if(tm[1] == '#'){
+ fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
+ }else{
+ fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
+ }
+ q = q.replace(tm[0], '');
+ }
+ }
+ while(!(mm = q.match(modeRe))){
+ var matched = false;
+ for(var j = 0; j < tklen; j++){
+ var t = tk[j];
+ var m = q.match(t.re);
+ if(m){
+ fn[fn.length] = t.select.replace(tplRe, function(x, i){
+ return m[i];
+ });
+ q = q.replace(m[0], '');
+ matched = true;
+ break;
+ }
+ }
+ // prevent infinite loop on bad selector
+ if(!matched){
+ throw 'Error parsing selector, parsing failed at "' + q + '"';
+ }
+ }
+ if(mm[1]){
+ fn[fn.length] = 'mode="'+mm[1]+'";';
+ q = q.replace(mm[1], '');
+ }
+ }
+ fn[fn.length] = 'return nodup(n);\n}';
+ eval(fn.join(''));
+ return f;
+ },
+
+ /**
+ * Selects a group of elements.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @return {Array}
+ */
+ select : function(path, root, type){
+ if(!root || root == document){
+ root = document;
+ }
+ if(typeof root == 'string'){
+ root = document.getElementById(root);
+ }
+ var paths = path.split(',');
+ var results = [];
+ for(var i = 0, len = paths.length; i < len; i++){
+ var p = paths[i].replace(trimRe, '$1');
+ if(!cache[p]){
+ cache[p] = Clipperz.YUI.DomQuery.compile(p);
+ if(!cache[p]){
+ throw p + ' is not a valid selector';
+ }
+ }
+ var result = cache[p](root);
+ if(result && result != document){
+ results = results.concat(result);
+ }
+ }
+ return results;
+ },
+
+ /**
+ * Selects a single element.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @return {Element}
+ */
+ selectNode : function(path, root){
+ return Clipperz.YUI.DomQuery.select(path, root)[0];
+ },
+
+ /**
+ * Selects the value of a node, optionally replacing null with the defaultValue.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @param {String} defaultValue
+ */
+ selectValue : function(path, root, defaultValue){
+ path = path.replace(trimRe, '$1');
+ if(!valueCache[path]){
+ valueCache[path] = Clipperz.YUI.DomQuery.compile(path, 'simple');
+ }
+ var n = valueCache[path](root);
+ n = n[0] ? n[0] : n;
+ var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
+ return (v === null ? defaultValue : v);
+ },
+
+ /**
+ * Selects the value of a node, parsing integers and floats.
+ * @param {String} selector The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @param {Number} defaultValue
+ * @return {Number}
+ */
+ selectNumber : function(path, root, defaultValue){
+ var v = Clipperz.YUI.DomQuery.selectValue(path, root, defaultValue || 0);
+ return parseFloat(v);
+ },
+
+ /**
+ * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
+ * @param {String/HTMLElement/Array} el An element id, element or array of elements
+ * @param {String} selector The simple selector to test
+ * @return {Boolean}
+ */
+ is : function(el, ss){
+ if(typeof el == 'string'){
+ el = document.getElementById(el);
+ }
+ var isArray = (el instanceof Array);
+ var result = Clipperz.YUI.DomQuery.filter(isArray ? el : [el], ss);
+ return isArray ? (result.length == el.length) : (result.length > 0);
+ },
+
+ /**
+ * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
+ * @param {Array} el An array of elements to filter
+ * @param {String} selector The simple selector to test
+ * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
+ * the selector instead of the ones that match
+ * @return {Array}
+ */
+ filter : function(els, ss, nonMatches){
+ ss = ss.replace(trimRe, '$1');
+ if(!simpleCache[ss]){
+ simpleCache[ss] = Clipperz.YUI.DomQuery.compile(ss, 'simple');
+ }
+ var result = simpleCache[ss](els);
+ return nonMatches ? quickDiff(result, els) : result;
+ },
+
+ /**
+ * Collection of matching regular expressions and code snippets.
+ */
+ matchers : [{
+ re: /^\.([\w-]+)/,
+ select: 'n = byClassName(n, null, "{1}");'
+ }, {
+ re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
+ select: 'n = byPseudo(n, "{1}", "{2}");'
+ },{
+ re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
+ select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
+ }, {
+ re: /^#([\w-]+)/,
+ select: 'n = byId(n, null, "{1}");'
+ },{
+ re: /^@([\w-]+)/,
+ select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
+ }
+ ],
+
+ /**
+ * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *= and %=.
+ * New operators can be added as long as the match the format <i>c</i>= where <i>c<i> is any character other than space, &gt; &lt;.
+ */
+ operators : {
+ '=' : function(a, v){
+ return a == v;
+ },
+ '!=' : function(a, v){
+ return a != v;
+ },
+ '^=' : function(a, v){
+ return a && a.substr(0, v.length) == v;
+ },
+ '$=' : function(a, v){
+ return a && a.substr(a.length-v.length) == v;
+ },
+ '*=' : function(a, v){
+ return a && a.indexOf(v) !== -1;
+ },
+ '%=' : function(a, v){
+ return (a % v) == 0;
+ }
+ },
+
+ /**
+ * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
+ * and the argument (if any) supplied in the selector.
+ */
+ pseudos : {
+ 'first-child' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!prev(ci)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'last-child' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!next(ci)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'nth-child' : function(c, a){
+ var r = [];
+ if(a != 'odd' && a != 'even'){
+ for(var i = 0, ci; ci = c[i]; i++){
+ var m = child(ci.parentNode, a);
+ if(m == ci){
+ r[r.length] = m;
+ }
+ }
+ return r;
+ }
+ var p;
+ // first let's clean up the parent nodes
+ for(var i = 0, l = c.length; i < l; i++){
+ var cp = c[i].parentNode;
+ if(cp != p){
+ clean(cp);
+ p = cp;
+ }
+ }
+ // then lets see if we match
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i], m = false;
+ if(a == 'odd'){
+ m = ((ci.nodeIndex+1) % 2 == 1);
+ }else if(a == 'even'){
+ m = ((ci.nodeIndex+1) % 2 == 0);
+ }
+ if(m){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'only-child' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!prev(ci) && !next(ci)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'empty' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(!ci.firstChild){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'contains' : function(c, v){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ var ci = c[i];
+ if(ci.innerHTML.indexOf(v) !== -1){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'checked' : function(c){
+ var r = [];
+ for(var i = 0, l = c.length; i < l; i++){
+ if(c[i].checked == 'checked'){
+ r[r.length] = c[i];
+ }
+ }
+ return r;
+ },
+
+ 'not' : function(c, ss){
+ return Clipperz.YUI.DomQuery.filter(c, ss, true);
+ },
+
+ 'odd' : function(c){
+ return this['nth-child'](c, 'odd');
+ },
+
+ 'even' : function(c){
+ return this['nth-child'](c, 'even');
+ },
+
+ 'nth' : function(c, a){
+ return c[a-1];
+ },
+
+ 'first' : function(c){
+ return c[0];
+ },
+
+ 'last' : function(c){
+ return c[c.length-1];
+ },
+
+ 'has' : function(c, ss){
+ var s = Clipperz.YUI.DomQuery.select;
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ if(s(ss, ci).length > 0){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'next' : function(c, ss){
+ var is = Clipperz.YUI.DomQuery.is;
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ var n = next(ci);
+ if(n && is(n, ss)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ },
+
+ 'prev' : function(c, ss){
+ var is = Clipperz.YUI.DomQuery.is;
+ var r = [];
+ for(var i = 0, ci; ci = c[i]; i++){
+ var n = prev(ci);
+ if(n && is(n, ss)){
+ r[r.length] = ci;
+ }
+ }
+ return r;
+ }
+ }
+ };
+}();
+
+/**
+ * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Clipperz.YUI.DomQuery#select}
+ * @param {String} path The selector/xpath query
+ * @param {Node} root (optional) The start of the query (defaults to document).
+ * @return {Array}
+ * @member Ext
+ * @method query
+ */
+Clipperz.YUI.query = Clipperz.YUI.DomQuery.select;