]>
git.wh0rd.org - tt-rss.git/blob - lib/dojo/NodeList-manipulate.js.uncompressed.js
1 define("dojo/NodeList-manipulate", ["./query", "./_base/lang", "./_base/array", "./dom-construct", "./NodeList-dom"], function(dquery
, lang
, array
, construct
){
3 // dojo/NodeList-manipulate
8 // Adds chainable methods to dojo.query() / NodeList instances for manipulating HTML
9 // and DOM nodes and their properties.
13 var NodeList
= dquery
.NodeList
;
15 //TODO: add a way to parse for widgets in the injected markup?
17 function getText(/*DOMNode*/node
){
19 // recursion method for text() to use. Gets text value for a node.
21 // Juse uses nodedValue so things like <br/> tags do not end up in
22 // the text as any sort of line return.
23 var text
= "", ch
= node
.childNodes
;
24 for(var i
= 0, n
; n
= ch
[i
]; i
++){
37 function getWrapInsertion(/*DOMNode*/node
){
39 // finds the innermost element to use for wrap insertion.
41 //Make it easy, assume single nesting, no siblings.
42 while(node
.childNodes
[0] && node
.childNodes
[0].nodeType
== 1){
43 node
= node
.childNodes
[0];
45 return node
; //DOMNode
48 function makeWrapNode(/*DOMNode||String*/html
, /*DOMNode*/refNode
){
50 // convert HTML into nodes if it is not already a node.
51 if(typeof html
== "string"){
52 html
= construct
.toDom(html
, (refNode
&& refNode
.ownerDocument
));
53 if(html
.nodeType
== 11){
54 //DocumentFragment cannot handle cloneNode, so choose first child.
55 html
= html
.childNodes
[0];
57 }else if(html
.nodeType
== 1 && html
.parentNode
){
58 //This element is already in the DOM clone it, but not its children.
59 html
= html
.cloneNode(false);
61 return html
; /*DOMNode*/
64 lang
.extend(NodeList
, {
65 _placeMultiple: function(/*String||Node||NodeList*/query
, /*String*/position
){
67 // private method for inserting queried nodes into all nodes in this NodeList
68 // at different positions. Differs from NodeList.place because it will clone
69 // the nodes in this NodeList if the query matches more than one element.
70 var nl2
= typeof query
== "string" || query
.nodeType
? dquery(query
) : query
;
72 for(var i
= 0; i
< nl2
.length
; i
++){
73 //Go backwards in DOM to make dom insertions easier via insertBefore
75 var length
= this.length
;
76 for(var j
= length
- 1, item
; item
= this[j
]; j
--){
78 //Need to clone the item. This also means
79 //it needs to be added to the current NodeList
80 //so it can also be the target of other chaining operations.
81 item
= this._cloneNode(item
);
85 construct
.place(item
, refNode
, position
);
87 refNode
.parentNode
.insertBefore(item
, refNode
);
94 //Add the toAdd items to the current NodeList. Build up list of args
97 toAdd
.unshift(this.length
- 1);
98 Array
.prototype.splice
.apply(this, toAdd
);
101 return this; // dojo/NodeList
104 innerHTML: function(/*String|DOMNode|NodeList?*/ value
){
106 // allows setting the innerHTML of each node in the NodeList,
107 // if there is a value passed in, otherwise, reads the innerHTML value of the first node.
109 // This method is simpler than the dojo/NodeList.html() method provided by
110 // `dojo/NodeList-html`. This method just does proper innerHTML insertion of HTML fragments,
111 // and it allows for the innerHTML to be read for the first node in the node list.
112 // Since dojo/NodeList-html already took the "html" name, this method is called
113 // "innerHTML". However, if dojo/NodeList-html has not been loaded yet, this
114 // module will define an "html" method that can be used instead. Be careful if you
115 // are working in an environment where it is possible that dojo/NodeList-html could
116 // have been loaded, since its definition of "html" will take precedence.
117 // The nodes represented by the value argument will be cloned if more than one
118 // node is in this NodeList. The nodes in this NodeList are returned in the "set"
119 // usage of this method, not the HTML that was inserted.
121 // if no value is passed, the result is String, the innerHTML of the first node.
122 // If a value is passed, the return is this dojo/NodeList
124 // assume a DOM created by this markup:
125 // | <div id="foo"></div>
126 // | <div id="bar"></div>
127 // This code inserts `<p>Hello World</p>` into both divs:
128 // | dojo.query("div").innerHTML("<p>Hello World</p>");
130 // assume a DOM created by this markup:
131 // | <div id="foo"><p>Hello Mars</p></div>
132 // | <div id="bar"><p>Hello World</p></div>
133 // This code returns `<p>Hello Mars</p>`:
134 // | var message = dojo.query("div").innerHTML();
135 if(arguments
.length
){
136 return this.addContent(value
, "only"); // dojo/NodeList
138 return this[0].innerHTML
; //String
143 html: function(value){
145 // see the information for "innerHTML". "html" is an alias for "innerHTML", but is
146 // only defined if dojo/NodeList-html has not been loaded.
148 // An alias for the "innerHTML" method, but only defined if there is not an existing
149 // "html" method on dojo/NodeList. Be careful if you are working in an environment
150 // where it is possible that dojo/NodeList-html could have been loaded, since its
151 // definition of "html" will take precedence. If you are not sure if dojo/NodeList-html
152 // could be loaded, use the "innerHTML" method.
153 // value: String|DOMNode|NodeList?
154 // The HTML fragment to use as innerHTML. If value is not passed, then the innerHTML
155 // of the first element in this NodeList is returned.
157 // if no value is passed, the result is String, the innerHTML of the first node.
158 // If a value is passed, the return is this dojo/NodeList
159 return; // dojo/NodeList|String
163 text: function(/*String*/value
){
165 // allows setting the text value of each node in the NodeList,
166 // if there is a value passed in, otherwise, returns the text value for all the
167 // nodes in the NodeList in one string.
169 // assume a DOM created by this markup:
170 // | <div id="foo"></div>
171 // | <div id="bar"></div>
172 // This code inserts "Hello World" into both divs:
173 // | dojo.query("div").text("Hello World");
175 // assume a DOM created by this markup:
176 // | <div id="foo"><p>Hello Mars <span>today</span></p></div>
177 // | <div id="bar"><p>Hello World</p></div>
178 // This code returns "Hello Mars today":
179 // | var message = dojo.query("div").text();
181 // if no value is passed, the result is String, the text value of the first node.
182 // If a value is passed, the return is this dojo/NodeList
183 if(arguments
.length
){
184 for(var i
= 0, node
; node
= this[i
]; i
++){
185 if(node
.nodeType
== 1){
186 construct
.empty(node
);
187 node
.appendChild(node
.ownerDocument
.createTextNode(value
));
190 return this; // dojo/NodeList
193 for(i
= 0; node
= this[i
]; i
++){
194 result
+= getText(node
);
196 return result
; //String
200 val: function(/*String||Array*/value
){
202 // If a value is passed, allows seting the value property of form elements in this
203 // NodeList, or properly selecting/checking the right value for radio/checkbox/select
204 // elements. If no value is passed, the value of the first node in this NodeList
207 // if no value is passed, the result is String or an Array, for the value of the
209 // If a value is passed, the return is this dojo/NodeList
211 // assume a DOM created by this markup:
212 // | <input type="text" value="foo">
213 // | <select multiple>
214 // | <option value="red" selected>Red</option>
215 // | <option value="blue">Blue</option>
216 // | <option value="yellow" selected>Yellow</option>
218 // This code gets and sets the values for the form fields above:
219 // | dojo.query('[type="text"]').val(); //gets value foo
220 // | dojo.query('[type="text"]').val("bar"); //sets the input's value to "bar"
221 // | dojo.query("select").val() //gets array value ["red", "yellow"]
222 // | dojo.query("select").val(["blue", "yellow"]) //Sets the blue and yellow options to selected.
224 //Special work for input elements.
225 if(arguments
.length
){
226 var isArray
= lang
.isArray(value
);
227 for(var index
= 0, node
; node
= this[index
]; index
++){
228 var name
= node
.nodeName
.toUpperCase();
229 var type
= node
.type
;
230 var newValue
= isArray
? value
[index
] : value
;
232 if(name
== "SELECT"){
233 var opts
= node
.options
;
234 for(var i
= 0; i
< opts
.length
; i
++){
237 opt
.selected
= (array
.indexOf(value
, opt
.value
) != -1);
239 opt
.selected
= (opt
.value
== newValue
);
242 }else if(type
== "checkbox" || type
== "radio"){
243 node
.checked
= (node
.value
== newValue
);
245 node
.value
= newValue
;
248 return this; // dojo/NodeList
250 //node already declared above.
252 if(!node
|| node
.nodeType
!= 1){
255 value
= node
.value
|| "";
256 if(node
.nodeName
.toUpperCase() == "SELECT" && node
.multiple
){
257 //A multivalued selectbox. Do the pain.
259 //opts declared above in if block.
261 //i declared above in if block;
262 for(i
= 0; i
< opts
.length
; i
++){
263 //opt declared above in if block
266 value
.push(opt
.value
);
273 return value
; //String||Array
277 append: function(/*String||DOMNode||NodeList*/content
){
279 // appends the content to every node in the NodeList.
281 // The content will be cloned if the length of NodeList
282 // is greater than 1. Only the DOM nodes are cloned, not
283 // any attached event handlers.
285 // dojo/NodeList, the nodes currently in this NodeList will be returned,
286 // not the appended content.
288 // assume a DOM created by this markup:
289 // | <div id="foo"><p>Hello Mars</p></div>
290 // | <div id="bar"><p>Hello World</p></div>
291 // Running this code:
292 // | dojo.query("div").append("<span>append</span>");
293 // Results in this DOM structure:
294 // | <div id="foo"><p>Hello Mars</p><span>append</span></div>
295 // | <div id="bar"><p>Hello World</p><span>append</span></div>
296 return this.addContent(content
, "last"); // dojo/NodeList
299 appendTo: function(/*String*/query
){
301 // appends nodes in this NodeList to the nodes matched by
302 // the query passed to appendTo.
304 // The nodes in this NodeList will be cloned if the query
305 // matches more than one element. Only the DOM nodes are cloned, not
306 // any attached event handlers.
308 // dojo/NodeList, the nodes currently in this NodeList will be returned,
309 // not the matched nodes from the query.
311 // assume a DOM created by this markup:
312 // | <span>append</span>
313 // | <p>Hello Mars</p>
314 // | <p>Hello World</p>
315 // Running this code:
316 // | dojo.query("span").appendTo("p");
317 // Results in this DOM structure:
318 // | <p>Hello Mars<span>append</span></p>
319 // | <p>Hello World<span>append</span></p>
320 return this._placeMultiple(query
, "last"); // dojo/NodeList
323 prepend: function(/*String||DOMNode||NodeList*/content
){
325 // prepends the content to every node in the NodeList.
327 // The content will be cloned if the length of NodeList
328 // is greater than 1. Only the DOM nodes are cloned, not
329 // any attached event handlers.
331 // dojo/NodeList, the nodes currently in this NodeList will be returned,
332 // not the appended content.
333 // assume a DOM created by this markup:
334 // | <div id="foo"><p>Hello Mars</p></div>
335 // | <div id="bar"><p>Hello World</p></div>
336 // Running this code:
337 // | dojo.query("div").prepend("<span>prepend</span>");
338 // Results in this DOM structure:
339 // | <div id="foo"><span>prepend</span><p>Hello Mars</p></div>
340 // | <div id="bar"><span>prepend</span><p>Hello World</p></div>
341 return this.addContent(content
, "first"); // dojo/NodeList
344 prependTo: function(/*String*/query
){
346 // prepends nodes in this NodeList to the nodes matched by
347 // the query passed to prependTo.
349 // The nodes in this NodeList will be cloned if the query
350 // matches more than one element. Only the DOM nodes are cloned, not
351 // any attached event handlers.
353 // dojo/NodeList, the nodes currently in this NodeList will be returned,
354 // not the matched nodes from the query.
356 // assume a DOM created by this markup:
357 // | <span>prepend</span>
358 // | <p>Hello Mars</p>
359 // | <p>Hello World</p>
360 // Running this code:
361 // | dojo.query("span").prependTo("p");
362 // Results in this DOM structure:
363 // | <p><span>prepend</span>Hello Mars</p>
364 // | <p><span>prepend</span>Hello World</p>
365 return this._placeMultiple(query
, "first"); // dojo/NodeList
368 after: function(/*String||Element||NodeList*/content
){
370 // Places the content after every node in the NodeList.
372 // The content will be cloned if the length of NodeList
373 // is greater than 1. Only the DOM nodes are cloned, not
374 // any attached event handlers.
376 // dojo/NodeList, the nodes currently in this NodeList will be returned,
377 // not the appended content.
379 // assume a DOM created by this markup:
380 // | <div id="foo"><p>Hello Mars</p></div>
381 // | <div id="bar"><p>Hello World</p></div>
382 // Running this code:
383 // | dojo.query("div").after("<span>after</span>");
384 // Results in this DOM structure:
385 // | <div id="foo"><p>Hello Mars</p></div><span>after</span>
386 // | <div id="bar"><p>Hello World</p></div><span>after</span>
387 return this.addContent(content
, "after"); // dojo/NodeList
390 insertAfter: function(/*String*/query
){
392 // The nodes in this NodeList will be placed after the nodes
393 // matched by the query passed to insertAfter.
395 // The nodes in this NodeList will be cloned if the query
396 // matches more than one element. Only the DOM nodes are cloned, not
397 // any attached event handlers.
399 // dojo/NodeList, the nodes currently in this NodeList will be returned,
400 // not the matched nodes from the query.
402 // assume a DOM created by this markup:
403 // | <span>after</span>
404 // | <p>Hello Mars</p>
405 // | <p>Hello World</p>
406 // Running this code:
407 // | dojo.query("span").insertAfter("p");
408 // Results in this DOM structure:
409 // | <p>Hello Mars</p><span>after</span>
410 // | <p>Hello World</p><span>after</span>
411 return this._placeMultiple(query
, "after"); // dojo/NodeList
414 before: function(/*String||DOMNode||NodeList*/content
){
416 // Places the content before every node in the NodeList.
418 // The content will be cloned if the length of NodeList
419 // is greater than 1. Only the DOM nodes are cloned, not
420 // any attached event handlers.
422 // dojo/NodeList, the nodes currently in this NodeList will be returned,
423 // not the appended content.
425 // assume a DOM created by this markup:
426 // | <div id="foo"><p>Hello Mars</p></div>
427 // | <div id="bar"><p>Hello World</p></div>
428 // Running this code:
429 // | dojo.query("div").before("<span>before</span>");
430 // Results in this DOM structure:
431 // | <span>before</span><div id="foo"><p>Hello Mars</p></div>
432 // | <span>before</span><div id="bar"><p>Hello World</p></div>
433 return this.addContent(content
, "before"); // dojo/NodeList
436 insertBefore: function(/*String*/query
){
438 // The nodes in this NodeList will be placed after the nodes
439 // matched by the query passed to insertAfter.
441 // The nodes in this NodeList will be cloned if the query
442 // matches more than one element. Only the DOM nodes are cloned, not
443 // any attached event handlers.
445 // dojo/NodeList, the nodes currently in this NodeList will be returned,
446 // not the matched nodes from the query.
448 // assume a DOM created by this markup:
449 // | <span>before</span>
450 // | <p>Hello Mars</p>
451 // | <p>Hello World</p>
452 // Running this code:
453 // | dojo.query("span").insertBefore("p");
454 // Results in this DOM structure:
455 // | <span>before</span><p>Hello Mars</p>
456 // | <span>before</span><p>Hello World</p>
457 return this._placeMultiple(query
, "before"); // dojo/NodeList
461 remove: function(simpleFilter){
463 // alias for dojo/NodeList's orphan method. Removes elements
464 // in this list that match the simple filter from their parents
465 // and returns them as a new NodeList.
466 // simpleFilter: String
467 // single-expression CSS rule. For example, ".thinger" or
468 // "#someId[attrName='value']" but not "div > span". In short,
469 // anything which does not invoke a descent to evaluate but
470 // can instead be used to test a single node is acceptable.
472 return; // dojo/NodeList
475 remove
: NodeList
.prototype.orphan
,
477 wrap: function(/*String||DOMNode*/html
){
479 // Wrap each node in the NodeList with html passed to wrap.
481 // html will be cloned if the NodeList has more than one
482 // element. Only DOM nodes are cloned, not any attached
485 // the nodes in the current NodeList will be returned,
486 // not the nodes from html argument.
488 // assume a DOM created by this markup:
491 // Running this code:
492 // | dojo.query("b").wrap("<div><span></span></div>");
493 // Results in this DOM structure:
494 // | <div><span><b>one</b></span></div>
495 // | <div><span><b>two</b></span></div>
497 html
= makeWrapNode(html
, this[0]);
499 //Now cycle through the elements and do the insertion.
500 for(var i
= 0, node
; node
= this[i
]; i
++){
501 //Always clone because if html is used to hold one of
502 //the "this" nodes, then on the clone of html it will contain
503 //that "this" node, and that would be bad.
504 var clone
= this._cloneNode(html
);
506 node
.parentNode
.replaceChild(clone
, node
);
508 //Find deepest element and insert old node in it.
509 var insertion
= getWrapInsertion(clone
);
510 insertion
.appendChild(node
);
513 return this; // dojo/NodeList
516 wrapAll: function(/*String||DOMNode*/html
){
518 // Insert html where the first node in this NodeList lives, then place all
519 // nodes in this NodeList as the child of the html.
521 // the nodes in the current NodeList will be returned,
522 // not the nodes from html argument.
524 // assume a DOM created by this markup:
525 // | <div class="container">
526 // | <div class="red">Red One</div>
527 // | <div class="blue">Blue One</div>
528 // | <div class="red">Red Two</div>
529 // | <div class="blue">Blue Two</div>
531 // Running this code:
532 // | dojo.query(".red").wrapAll('<div class="allRed"></div>');
533 // Results in this DOM structure:
534 // | <div class="container">
535 // | <div class="allRed">
536 // | <div class="red">Red One</div>
537 // | <div class="red">Red Two</div>
539 // | <div class="blue">Blue One</div>
540 // | <div class="blue">Blue Two</div>
543 html
= makeWrapNode(html
, this[0]);
545 //Place the wrap HTML in place of the first node.
546 this[0].parentNode
.replaceChild(html
, this[0]);
548 //Now cycle through the elements and move them inside
550 var insertion
= getWrapInsertion(html
);
551 for(var i
= 0, node
; node
= this[i
]; i
++){
552 insertion
.appendChild(node
);
555 return this; // dojo/NodeList
558 wrapInner: function(/*String||DOMNode*/html
){
560 // For each node in the NodeList, wrap all its children with the passed in html.
562 // html will be cloned if the NodeList has more than one
563 // element. Only DOM nodes are cloned, not any attached
566 // the nodes in the current NodeList will be returned,
567 // not the nodes from html argument.
569 // assume a DOM created by this markup:
570 // | <div class="container">
571 // | <div class="red">Red One</div>
572 // | <div class="blue">Blue One</div>
573 // | <div class="red">Red Two</div>
574 // | <div class="blue">Blue Two</div>
576 // Running this code:
577 // | dojo.query(".red").wrapInner('<span class="special"></span>');
578 // Results in this DOM structure:
579 // | <div class="container">
580 // | <div class="red"><span class="special">Red One</span></div>
581 // | <div class="blue">Blue One</div>
582 // | <div class="red"><span class="special">Red Two</span></div>
583 // | <div class="blue">Blue Two</div>
586 html
= makeWrapNode(html
, this[0]);
587 for(var i
= 0; i
< this.length
; i
++){
588 //Always clone because if html is used to hold one of
589 //the "this" nodes, then on the clone of html it will contain
590 //that "this" node, and that would be bad.
591 var clone
= this._cloneNode(html
);
593 //Need to convert the childNodes to an array since wrapAll modifies the
594 //DOM and can change the live childNodes NodeList.
595 this._wrap(lang
._toArray(this[i
].childNodes
), null, this._NodeListCtor
).wrapAll(clone
);
598 return this; // dojo/NodeList
601 replaceWith: function(/*String||DOMNode||NodeList*/content
){
603 // Replaces each node in ths NodeList with the content passed to replaceWith.
605 // The content will be cloned if the length of NodeList
606 // is greater than 1. Only the DOM nodes are cloned, not
607 // any attached event handlers.
609 // The nodes currently in this NodeList will be returned, not the replacing content.
610 // Note that the returned nodes have been removed from the DOM.
612 // assume a DOM created by this markup:
613 // | <div class="container">
614 // | <div class="red">Red One</div>
615 // | <div class="blue">Blue One</div>
616 // | <div class="red">Red Two</div>
617 // | <div class="blue">Blue Two</div>
619 // Running this code:
620 // | dojo.query(".red").replaceWith('<div class="green">Green</div>');
621 // Results in this DOM structure:
622 // | <div class="container">
623 // | <div class="green">Green</div>
624 // | <div class="blue">Blue One</div>
625 // | <div class="green">Green</div>
626 // | <div class="blue">Blue Two</div>
628 content
= this._normalize(content
, this[0]);
629 for(var i
= 0, node
; node
= this[i
]; i
++){
630 this._place(content
, node
, "before", i
> 0);
631 node
.parentNode
.removeChild(node
);
633 return this; // dojo/NodeList
636 replaceAll: function(/*String*/query
){
638 // replaces nodes matched by the query passed to replaceAll with the nodes
641 // The nodes in this NodeList will be cloned if the query
642 // matches more than one element. Only the DOM nodes are cloned, not
643 // any attached event handlers.
645 // The nodes currently in this NodeList will be returned, not the matched nodes
646 // from the query. The nodes currently in this NodeLIst could have
647 // been cloned, so the returned NodeList will include the cloned nodes.
649 // assume a DOM created by this markup:
650 // | <div class="container">
651 // | <div class="spacer">___</div>
652 // | <div class="red">Red One</div>
653 // | <div class="spacer">___</div>
654 // | <div class="blue">Blue One</div>
655 // | <div class="spacer">___</div>
656 // | <div class="red">Red Two</div>
657 // | <div class="spacer">___</div>
658 // | <div class="blue">Blue Two</div>
660 // Running this code:
661 // | dojo.query(".red").replaceAll(".blue");
662 // Results in this DOM structure:
663 // | <div class="container">
664 // | <div class="spacer">___</div>
665 // | <div class="spacer">___</div>
666 // | <div class="red">Red One</div>
667 // | <div class="red">Red Two</div>
668 // | <div class="spacer">___</div>
669 // | <div class="spacer">___</div>
670 // | <div class="red">Red One</div>
671 // | <div class="red">Red Two</div>
673 var nl
= dquery(query
);
674 var content
= this._normalize(this, this[0]);
675 for(var i
= 0, node
; node
= nl
[i
]; i
++){
676 this._place(content
, node
, "before", i
> 0);
677 node
.parentNode
.removeChild(node
);
679 return this; // dojo/NodeList
684 // Clones all the nodes in this NodeList and returns them as a new NodeList.
686 // Only the DOM nodes are cloned, not any attached event handlers.
688 // a cloned set of the original nodes.
690 // assume a DOM created by this markup:
691 // | <div class="container">
692 // | <div class="red">Red One</div>
693 // | <div class="blue">Blue One</div>
694 // | <div class="red">Red Two</div>
695 // | <div class="blue">Blue Two</div>
697 // Running this code:
698 // | dojo.query(".red").clone().appendTo(".container");
699 // Results in this DOM structure:
700 // | <div class="container">
701 // | <div class="red">Red One</div>
702 // | <div class="blue">Blue One</div>
703 // | <div class="red">Red Two</div>
704 // | <div class="blue">Blue Two</div>
705 // | <div class="red">Red One</div>
706 // | <div class="red">Red Two</div>
709 //TODO: need option to clone events?
711 for(var i
= 0; i
< this.length
; i
++){
712 ary
.push(this._cloneNode(this[i
]));
714 return this._wrap(ary
, this, this._NodeListCtor
); // dojo/NodeList
718 //set up html method if one does not exist
719 if(!NodeList
.prototype.html
){
720 NodeList
.prototype.html
= NodeList
.prototype.innerHTML
;