summaryrefslogtreecommitdiff
path: root/frontend/delta/js/Clipperz/YUI/DomQuery.js
Unidiff
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 @@
1/*
2
3Copyright 2008-2013 Clipperz Srl
4
5This file is part of Clipperz, the online password manager.
6For further information about its features and functionalities please
7refer to http://www.clipperz.com.
8
9* Clipperz is free software: you can redistribute it and/or modify it
10 under the terms of the GNU Affero General Public License as published
11 by the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14* Clipperz is distributed in the hope that it will be useful, but
15 WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17 See the GNU Affero General Public License for more details.
18
19* You should have received a copy of the GNU Affero General Public
20 License along with Clipperz. If not, see http://www.gnu.org/licenses/.
21
22*/
23
24if (typeof(Clipperz) == 'undefined') { Clipperz = {}; }
25if (typeof(Clipperz.YUI) == 'undefined') { Clipperz.YUI = {}; }
26
27
28/*
29 * yui-ext 0.40
30 * Copyright(c) 2006, Jack Slocum.
31 */
32
33/**
34 * @class Clipperz.YUI.DomQuery
35 * Provides high performance selector/xpath processing by compiling queries into reusable functions.
36 * New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
37 * @singleton
38 */
39Clipperz.YUI.DomQuery = function(){
40 var cache = {}, simpleCache = {}, valueCache = {};
41 var nonSpace = /\S/;
42 var trimRe = /^\s*(.*?)\s*$/;
43 var tplRe = /\{(\d+)\}/g;
44 var modeRe = /^(\s?[\/>]\s?|\s|$)/;
45 var clsRes = {};
46
47 function child(p, index){
48 var i = 0;
49 var n = p.firstChild;
50 while(n){
51 if(n.nodeType == 1){
52 i++;
53 if(i == index){
54 return n;
55 }
56 }
57 n = n.nextSibling;
58 }
59 return null;
60 };
61
62 function next(d){
63 var n = d.nextSibling;
64 while(n && n.nodeType != 1){
65 n = n.nextSibling;
66 }
67 return n;
68 };
69
70 function prev(d){
71 var n = d.previousSibling;
72 while(n && n.nodeType != 1){
73 n = n.previousSibling;
74 }
75 return n;
76 };
77
78 function clean(d){
79 var n = d.firstChild, ni = -1;
80 while(n){
81 var nx = n.nextSibling;
82 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
83 d.removeChild(n);
84 }else{
85 n.nodeIndex = ++ni;
86 }
87 n = nx;
88 }
89 return this;
90 };
91
92 function byClassName(c, a, v){
93 if(!v){
94 return c;
95 }
96 var re = clsRes[v];
97 if(!re){
98 re = new RegExp('(?:^|\\s)(?:' + v + ')(?:\\s|$)');
99 clsRes[v] = re;
100 }
101 var r = [];
102 for(var i = 0, ci; ci = c[i]; i++){
103 if(re.test(ci.className)){
104 r[r.length] = ci;
105 }
106 }
107 return r;
108 };
109
110 function convert(c){
111 if(c.slice){
112 return c;
113 }
114 var r = [];
115 for(var i = 0, l = c.length; i < l; i++){
116 r[r.length] = c[i];
117 }
118 return r;
119 };
120
121 function attrValue(n, attr){
122 if(!n.tagName && typeof n.length != 'undefined'){
123 n = n[0];
124 }
125 if(!n){
126 return null;
127 }
128 if(attr == 'for'){
129 return n.htmlFor;
130 }
131 if(attr == 'class' || attr == 'className'){
132 return n.className;
133 }
134 return n.getAttribute(attr) || n[attr];
135
136 };
137
138 function getNodes(ns, mode, tagName){
139 var result = [], cs;
140 if(!ns){
141 return result;
142 }
143 mode = mode ? mode.replace(trimRe, '$1') : '';
144 tagName = tagName || '*';
145 if(ns.tagName || ns == document){
146 ns = [ns];
147 }
148 if(mode != '/' && mode != '>'){
149 for(var i = 0, ni; ni = ns[i]; i++){
150 cs = ni.getElementsByTagName(tagName);
151 result = concat(result, cs);
152 }
153 }else{
154 for(var i = 0, ni; ni = ns[i]; i++){
155 var cn = ni.getElementsByTagName(tagName);
156 for(var j = 0, cj; cj = cn[j]; j++){
157 if(cj.parentNode == ni){
158 result[result.length] = cj;
159 }
160 }
161 }
162
163 }
164 return result;
165 };
166
167 function concat(a, b){
168 if(b.slice){
169 return a.concat(b);
170 }
171 for(var i = 0, l = b.length; i < l; i++){
172 a[a.length] = b[i];
173 }
174 return a;
175 }
176
177 function byTag(cs, tagName){
178 if(cs.tagName || cs == document){
179 cs = [cs];
180 }
181 if(!tagName){
182 return cs;
183 }
184 var r = []; tagName = tagName.toLowerCase();
185 for(var i = 0, ci; ci = cs[i]; i++){
186 if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
187 r[r.length] = ci;
188 }
189 }
190 return r;
191 };
192
193 function byId(cs, attr, id){
194 if(cs.tagName || cs == document){
195 cs = [cs];
196 }
197 if(!id){
198 return cs;
199 }
200 var r = [];
201 for(var i = 0, l = cs.length; i < l; i++){
202 var ci = cs[i];
203 if(ci && ci.id == id){
204 r[r.length] = ci;
205 }
206 }
207 return r;
208 };
209
210 function byAttribute(cs, attr, value, op, custom){
211 var r = [], st = custom=='{';
212 var f = Clipperz.YUI.DomQuery.operators[op];
213 for(var i = 0, l = cs.length; i < l; i++){
214 var a;
215 if(st){
216 a = Clipperz.YUI.DomQuery.getStyle(cs[i], attr);
217 }
218 else if(attr == 'class' || attr == 'className'){
219 a = cs[i].className;
220 }else if(attr == 'for'){
221 a = cs[i].htmlFor;
222 }else{
223 a = cs[i].getAttribute(attr);
224 }
225 if((f && f(a, value)) || (!f && a)){
226 r[r.length] = cs[i];
227 }
228 }
229 return r;
230 };
231
232 function byPseudo(cs, name, value){
233 return Clipperz.YUI.DomQuery.pseudos[name](cs, value);
234 };
235
236 // This is for IE MSXML which does not support expandos.
237 // IE runs the same speed using setAttribute, however FF slows way down
238 // and Safari completely fails so they need to continue to use expandos.
239 // Branched at load time for faster execution.
240 var isIE = window.ActiveXObject;
241 var addAttr = isIE ?
242 function(n, a, v){
243 n.setAttribute(a, v);
244 } :
245 function(n, a, v){
246 n[a] = v;
247 };
248 var getAttr = isIE ?
249 function(n, a){
250 return n.getAttribute(a);
251 } :
252 function(n, a){
253 return n[a];
254 };
255 var clearAttr = isIE ?
256 function(n, a){
257 n.removeAttribute(a);
258 } :
259 function(n, a, v){
260 delete n[a];
261 };
262
263 function nodup(cs){
264 if(!cs.length){
265 return cs;
266 }
267 addAttr(cs[0], '_nodup', true);
268 var r = [cs[0]];
269 for(var i = 1, len = cs.length; i < len; i++){
270 var c = cs[i];
271 if(!getAttr(c, '_nodup')){
272 addAttr(c, '_nodup', true);
273 r[r.length] = c;
274 }
275 }
276 for(var i = 0, len = cs.length; i < len; i++){
277 clearAttr(cs[i], '_nodup');
278 }
279 return r;
280 }
281
282 function quickDiff(c1, c2){
283 if(!c1.length){
284 return c2;
285 }
286 for(var i = 0, len = c1.length; i < len; i++){
287 addAttr(c1[i], '_qdiff', true);
288 }
289 var r = [];
290 for(var i = 0, len = c2.length; i < len; i++){
291 if(!getAttr(c2[i], '_qdiff')){
292 r[r.length] = c2[i];
293 }
294 }
295 for(var i = 0, len = c1.length; i < len; i++){
296 clearAttr(c1[i], '_qdiff');
297 }
298 return r;
299 }
300
301 function quickId(ns, mode, root, id){
302 if(ns == root){
303 var d = root.ownerDocument || root;
304 return d.getElementById(id);
305 }
306 ns = getNodes(ns, mode, '*');
307 return byId(ns, null, id);
308 }
309
310 return {
311 getStyle : function(el, name){
312 return YAHOO.util.Dom.getStyle(el, name);
313 },
314 /**
315 * Compiles a selector/xpath query into a reusable function. The returned function
316 * takes one parameter "root" (optional), which is the context node from where the query should start.
317 * @param {String} selector The selector/xpath query
318 * @param {String} type (optional) Either 'select' (the default) or 'simple' for a simple selector match
319 * @return {Function}
320 */
321 compile : function(path, type){
322 // strip leading slashes
323 while(path.substr(0, 1)=='/'){
324 path = path.substr(1);
325 }
326 type = type || 'select';
327
328 var fn = ['var f = function(root){\n var mode; var n = root || document;\n'];
329 var q = path, mode, lq;
330 var tk = Clipperz.YUI.DomQuery.matchers;
331 var tklen = tk.length;
332 var mm;
333 while(q && lq != q){
334 lq = q;
335 var tm = q.match(/^(#)?([\w-\*]+)/);
336 if(type == 'select'){
337 if(tm){
338 if(tm[1] == '#'){
339 fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
340 }else{
341 fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
342 }
343 q = q.replace(tm[0], '');
344 }else{
345 fn[fn.length] = 'n = getNodes(n, mode, "*");';
346 }
347 }else{
348 if(tm){
349 if(tm[1] == '#'){
350 fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
351 }else{
352 fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
353 }
354 q = q.replace(tm[0], '');
355 }
356 }
357 while(!(mm = q.match(modeRe))){
358 var matched = false;
359 for(var j = 0; j < tklen; j++){
360 var t = tk[j];
361 var m = q.match(t.re);
362 if(m){
363 fn[fn.length] = t.select.replace(tplRe, function(x, i){
364 return m[i];
365 });
366 q = q.replace(m[0], '');
367 matched = true;
368 break;
369 }
370 }
371 // prevent infinite loop on bad selector
372 if(!matched){
373 throw 'Error parsing selector, parsing failed at "' + q + '"';
374 }
375 }
376 if(mm[1]){
377 fn[fn.length] = 'mode="'+mm[1]+'";';
378 q = q.replace(mm[1], '');
379 }
380 }
381 fn[fn.length] = 'return nodup(n);\n}';
382 eval(fn.join(''));
383 return f;
384 },
385
386 /**
387 * Selects a group of elements.
388 * @param {String} selector The selector/xpath query
389 * @param {Node} root (optional) The start of the query (defaults to document).
390 * @return {Array}
391 */
392 select : function(path, root, type){
393 if(!root || root == document){
394 root = document;
395 }
396 if(typeof root == 'string'){
397 root = document.getElementById(root);
398 }
399 var paths = path.split(',');
400 var results = [];
401 for(var i = 0, len = paths.length; i < len; i++){
402 var p = paths[i].replace(trimRe, '$1');
403 if(!cache[p]){
404 cache[p] = Clipperz.YUI.DomQuery.compile(p);
405 if(!cache[p]){
406 throw p + ' is not a valid selector';
407 }
408 }
409 var result = cache[p](root);
410 if(result && result != document){
411 results = results.concat(result);
412 }
413 }
414 return results;
415 },
416
417 /**
418 * Selects a single element.
419 * @param {String} selector The selector/xpath query
420 * @param {Node} root (optional) The start of the query (defaults to document).
421 * @return {Element}
422 */
423 selectNode : function(path, root){
424 return Clipperz.YUI.DomQuery.select(path, root)[0];
425 },
426
427 /**
428 * Selects the value of a node, optionally replacing null with the defaultValue.
429 * @param {String} selector The selector/xpath query
430 * @param {Node} root (optional) The start of the query (defaults to document).
431 * @param {String} defaultValue
432 */
433 selectValue : function(path, root, defaultValue){
434 path = path.replace(trimRe, '$1');
435 if(!valueCache[path]){
436 valueCache[path] = Clipperz.YUI.DomQuery.compile(path, 'simple');
437 }
438 var n = valueCache[path](root);
439 n = n[0] ? n[0] : n;
440 var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
441 return (v === null ? defaultValue : v);
442 },
443
444 /**
445 * Selects the value of a node, parsing integers and floats.
446 * @param {String} selector The selector/xpath query
447 * @param {Node} root (optional) The start of the query (defaults to document).
448 * @param {Number} defaultValue
449 * @return {Number}
450 */
451 selectNumber : function(path, root, defaultValue){
452 var v = Clipperz.YUI.DomQuery.selectValue(path, root, defaultValue || 0);
453 return parseFloat(v);
454 },
455
456 /**
457 * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
458 * @param {String/HTMLElement/Array} el An element id, element or array of elements
459 * @param {String} selector The simple selector to test
460 * @return {Boolean}
461 */
462 is : function(el, ss){
463 if(typeof el == 'string'){
464 el = document.getElementById(el);
465 }
466 var isArray = (el instanceof Array);
467 var result = Clipperz.YUI.DomQuery.filter(isArray ? el : [el], ss);
468 return isArray ? (result.length == el.length) : (result.length > 0);
469 },
470
471 /**
472 * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
473 * @param {Array} el An array of elements to filter
474 * @param {String} selector The simple selector to test
475 * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
476 * the selector instead of the ones that match
477 * @return {Array}
478 */
479 filter : function(els, ss, nonMatches){
480 ss = ss.replace(trimRe, '$1');
481 if(!simpleCache[ss]){
482 simpleCache[ss] = Clipperz.YUI.DomQuery.compile(ss, 'simple');
483 }
484 var result = simpleCache[ss](els);
485 return nonMatches ? quickDiff(result, els) : result;
486 },
487
488 /**
489 * Collection of matching regular expressions and code snippets.
490 */
491 matchers : [{
492 re: /^\.([\w-]+)/,
493 select: 'n = byClassName(n, null, "{1}");'
494 }, {
495 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
496 select: 'n = byPseudo(n, "{1}", "{2}");'
497 },{
498 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
499 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
500 }, {
501 re: /^#([\w-]+)/,
502 select: 'n = byId(n, null, "{1}");'
503 },{
504 re: /^@([\w-]+)/,
505 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
506 }
507 ],
508
509 /**
510 * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *= and %=.
511 * 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;.
512 */
513 operators : {
514 '=' : function(a, v){
515 return a == v;
516 },
517 '!=' : function(a, v){
518 return a != v;
519 },
520 '^=' : function(a, v){
521 return a && a.substr(0, v.length) == v;
522 },
523 '$=' : function(a, v){
524 return a && a.substr(a.length-v.length) == v;
525 },
526 '*=' : function(a, v){
527 return a && a.indexOf(v) !== -1;
528 },
529 '%=' : function(a, v){
530 return (a % v) == 0;
531 }
532 },
533
534 /**
535 * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
536 * and the argument (if any) supplied in the selector.
537 */
538 pseudos : {
539 'first-child' : function(c){
540 var r = [];
541 for(var i = 0, l = c.length; i < l; i++){
542 var ci = c[i];
543 if(!prev(ci)){
544 r[r.length] = ci;
545 }
546 }
547 return r;
548 },
549
550 'last-child' : function(c){
551 var r = [];
552 for(var i = 0, l = c.length; i < l; i++){
553 var ci = c[i];
554 if(!next(ci)){
555 r[r.length] = ci;
556 }
557 }
558 return r;
559 },
560
561 'nth-child' : function(c, a){
562 var r = [];
563 if(a != 'odd' && a != 'even'){
564 for(var i = 0, ci; ci = c[i]; i++){
565 var m = child(ci.parentNode, a);
566 if(m == ci){
567 r[r.length] = m;
568 }
569 }
570 return r;
571 }
572 var p;
573 // first let's clean up the parent nodes
574 for(var i = 0, l = c.length; i < l; i++){
575 var cp = c[i].parentNode;
576 if(cp != p){
577 clean(cp);
578 p = cp;
579 }
580 }
581 // then lets see if we match
582 for(var i = 0, l = c.length; i < l; i++){
583 var ci = c[i], m = false;
584 if(a == 'odd'){
585 m = ((ci.nodeIndex+1) % 2 == 1);
586 }else if(a == 'even'){
587 m = ((ci.nodeIndex+1) % 2 == 0);
588 }
589 if(m){
590 r[r.length] = ci;
591 }
592 }
593 return r;
594 },
595
596 'only-child' : function(c){
597 var r = [];
598 for(var i = 0, l = c.length; i < l; i++){
599 var ci = c[i];
600 if(!prev(ci) && !next(ci)){
601 r[r.length] = ci;
602 }
603 }
604 return r;
605 },
606
607 'empty' : function(c){
608 var r = [];
609 for(var i = 0, l = c.length; i < l; i++){
610 var ci = c[i];
611 if(!ci.firstChild){
612 r[r.length] = ci;
613 }
614 }
615 return r;
616 },
617
618 'contains' : function(c, v){
619 var r = [];
620 for(var i = 0, l = c.length; i < l; i++){
621 var ci = c[i];
622 if(ci.innerHTML.indexOf(v) !== -1){
623 r[r.length] = ci;
624 }
625 }
626 return r;
627 },
628
629 'checked' : function(c){
630 var r = [];
631 for(var i = 0, l = c.length; i < l; i++){
632 if(c[i].checked == 'checked'){
633 r[r.length] = c[i];
634 }
635 }
636 return r;
637 },
638
639 'not' : function(c, ss){
640 return Clipperz.YUI.DomQuery.filter(c, ss, true);
641 },
642
643 'odd' : function(c){
644 return this['nth-child'](c, 'odd');
645 },
646
647 'even' : function(c){
648 return this['nth-child'](c, 'even');
649 },
650
651 'nth' : function(c, a){
652 return c[a-1];
653 },
654
655 'first' : function(c){
656 return c[0];
657 },
658
659 'last' : function(c){
660 return c[c.length-1];
661 },
662
663 'has' : function(c, ss){
664 var s = Clipperz.YUI.DomQuery.select;
665 var r = [];
666 for(var i = 0, ci; ci = c[i]; i++){
667 if(s(ss, ci).length > 0){
668 r[r.length] = ci;
669 }
670 }
671 return r;
672 },
673
674 'next' : function(c, ss){
675 var is = Clipperz.YUI.DomQuery.is;
676 var r = [];
677 for(var i = 0, ci; ci = c[i]; i++){
678 var n = next(ci);
679 if(n && is(n, ss)){
680 r[r.length] = ci;
681 }
682 }
683 return r;
684 },
685
686 'prev' : function(c, ss){
687 var is = Clipperz.YUI.DomQuery.is;
688 var r = [];
689 for(var i = 0, ci; ci = c[i]; i++){
690 var n = prev(ci);
691 if(n && is(n, ss)){
692 r[r.length] = ci;
693 }
694 }
695 return r;
696 }
697 }
698 };
699}();
700
701/**
702 * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Clipperz.YUI.DomQuery#select}
703 * @param {String} path The selector/xpath query
704 * @param {Node} root (optional) The start of the query (defaults to document).
705 * @return {Array}
706 * @member Ext
707 * @method query
708 */
709Clipperz.YUI.query = Clipperz.YUI.DomQuery.select;