]>
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
7 var NodeList
= dquery
.NodeList
;
10 dojo["NodeList-manipulate"] = {
11 // summary: Adds a chainable methods to dojo.query() / Nodelist instances for manipulating HTML
12 // and DOM nodes and their properties.
16 NodeList = dojo.NodeList;
19 //TODO: add a way to parse for widgets in the injected markup?
21 function getText(/*DOMNode*/node
){
23 // recursion method for text() to use. Gets text value for a node.
25 // Juse uses nodedValue so things like <br/> tags do not end up in
26 // the text as any sort of line return.
27 var text
= "", ch
= node
.childNodes
;
28 for(var i
= 0, n
; n
= ch
[i
]; i
++){
41 function getWrapInsertion(/*DOMNode*/node
){
43 // finds the innermost element to use for wrap insertion.
45 //Make it easy, assume single nesting, no siblings.
46 while(node
.childNodes
[0] && node
.childNodes
[0].nodeType
== 1){
47 node
= node
.childNodes
[0];
49 return node
; //DOMNode
52 function makeWrapNode(/*DOMNode||String*/html
, /*DOMNode*/refNode
){
54 // convert HTML into nodes if it is not already a node.
55 if(typeof html
== "string"){
56 html
= construct
.toDom(html
, (refNode
&& refNode
.ownerDocument
));
57 if(html
.nodeType
== 11){
58 //DocumentFragment cannot handle cloneNode, so choose first child.
59 html
= html
.childNodes
[0];
61 }else if(html
.nodeType
== 1 && html
.parentNode
){
62 //This element is already in the DOM clone it, but not its children.
63 html
= html
.cloneNode(false);
65 return html
; /*DOMNode*/
68 lang
.extend(NodeList
, {
69 _placeMultiple: function(/*String||Node||NodeList*/query
, /*String*/position
){
71 // private method for inserting queried nodes into all nodes in this NodeList
72 // at different positions. Differs from NodeList.place because it will clone
73 // the nodes in this NodeList if the query matches more than one element.
74 var nl2
= typeof query
== "string" || query
.nodeType
? dquery(query
) : query
;
76 for(var i
= 0; i
< nl2
.length
; i
++){
77 //Go backwards in DOM to make dom insertions easier via insertBefore
79 var length
= this.length
;
80 for(var j
= length
- 1, item
; item
= this[j
]; j
--){
82 //Need to clone the item. This also means
83 //it needs to be added to the current NodeList
84 //so it can also be the target of other chaining operations.
85 item
= this._cloneNode(item
);
89 construct
.place(item
, refNode
, position
);
91 refNode
.parentNode
.insertBefore(item
, refNode
);
98 //Add the toAdd items to the current NodeList. Build up list of args
101 toAdd
.unshift(this.length
- 1);
102 Array
.prototype.splice
.apply(this, toAdd
);
105 return this; //dojo.NodeList
108 innerHTML: function(/*String?||DOMNode?|NodeList?*/value
){
110 // allows setting the innerHTML of each node in the NodeList,
111 // if there is a value passed in, otherwise, reads the innerHTML value of the first node.
113 // This method is simpler than the dojo.NodeList.html() method provided by
114 // `dojo.NodeList-html`. This method just does proper innerHTML insertion of HTML fragments,
115 // and it allows for the innerHTML to be read for the first node in the node list.
116 // Since dojo.NodeList-html already took the "html" name, this method is called
117 // "innerHTML". However, if dojo.NodeList-html has not been loaded yet, this
118 // module will define an "html" method that can be used instead. Be careful if you
119 // are working in an environment where it is possible that dojo.NodeList-html could
120 // have been loaded, since its definition of "html" will take precedence.
121 // The nodes represented by the value argument will be cloned if more than one
122 // node is in this NodeList. The nodes in this NodeList are returned in the "set"
123 // usage of this method, not the HTML that was inserted.
125 // if no value is passed, the result is String, the innerHTML of the first node.
126 // If a value is passed, the return is this dojo.NodeList
128 // assume a DOM created by this markup:
129 // | <div id="foo"></div>
130 // | <div id="bar"></div>
131 // This code inserts <p>Hello World</p> into both divs:
132 // | dojo.query("div").innerHTML("<p>Hello World</p>");
134 // assume a DOM created by this markup:
135 // | <div id="foo"><p>Hello Mars</p></div>
136 // | <div id="bar"><p>Hello World</p></div>
137 // This code returns "<p>Hello Mars</p>":
138 // | var message = dojo.query("div").innerHTML();
139 if(arguments
.length
){
140 return this.addContent(value
, "only"); //dojo.NodeList
142 return this[0].innerHTML
; //String
147 html: function(value){
149 // see the information for "innerHTML". "html" is an alias for "innerHTML", but is
150 // only defined if dojo.NodeList-html has not been loaded.
152 // An alias for the "innerHTML" method, but only defined if there is not an existing
153 // "html" method on dojo.NodeList. Be careful if you are working in an environment
154 // where it is possible that dojo.NodeList-html could have been loaded, since its
155 // definition of "html" will take precedence. If you are not sure if dojo.NodeList-html
156 // could be loaded, use the "innerHTML" method.
157 // value: String?||DOMNode?||NodeList?
158 // optional. The HTML fragment to use as innerHTML. If value is not passed, then the innerHTML
159 // of the first element in this NodeList is returned.
161 // if no value is passed, the result is String, the innerHTML of the first node.
162 // If a value is passed, the return is this dojo.NodeList
163 return; // dojo.NodeList
168 text: function(/*String*/value
){
170 // allows setting the text value of each node in the NodeList,
171 // if there is a value passed in, otherwise, returns the text value for all the
172 // nodes in the NodeList in one string.
174 // assume a DOM created by this markup:
175 // | <div id="foo"></div>
176 // | <div id="bar"></div>
177 // This code inserts "Hello World" into both divs:
178 // | dojo.query("div").text("Hello World");
180 // assume a DOM created by this markup:
181 // | <div id="foo"><p>Hello Mars <span>today</span></p></div>
182 // | <div id="bar"><p>Hello World</p></div>
183 // This code returns "Hello Mars today":
184 // | var message = dojo.query("div").text();
186 // if no value is passed, the result is String, the text value of the first node.
187 // If a value is passed, the return is this dojo.NodeList
188 if(arguments
.length
){
189 for(var i
= 0, node
; node
= this[i
]; i
++){
190 if(node
.nodeType
== 1){
191 construct
.empty(node
);
192 node
.appendChild(node
.ownerDocument
.createTextNode(value
));
195 return this; //dojo.NodeList
198 for(i
= 0; node
= this[i
]; i
++){
199 result
+= getText(node
);
201 return result
; //String
205 val: function(/*String||Array*/value
){
207 // If a value is passed, allows seting the value property of form elements in this
208 // NodeList, or properly selecting/checking the right value for radio/checkbox/select
209 // elements. If no value is passed, the value of the first node in this NodeList
212 // if no value is passed, the result is String or an Array, for the value of the
214 // If a value is passed, the return is this dojo.NodeList
216 // assume a DOM created by this markup:
217 // | <input type="text" value="foo">
218 // | <select multiple>
219 // | <option value="red" selected>Red</option>
220 // | <option value="blue">Blue</option>
221 // | <option value="yellow" selected>Yellow</option>
223 // This code gets and sets the values for the form fields above:
224 // | dojo.query('[type="text"]').val(); //gets value foo
225 // | dojo.query('[type="text"]').val("bar"); //sets the input's value to "bar"
226 // | dojo.query("select").val() //gets array value ["red", "yellow"]
227 // | dojo.query("select").val(["blue", "yellow"]) //Sets the blue and yellow options to selected.
229 //Special work for input elements.
230 if(arguments
.length
){
231 var isArray
= lang
.isArray(value
);
232 for(var index
= 0, node
; node
= this[index
]; index
++){
233 var name
= node
.nodeName
.toUpperCase();
234 var type
= node
.type
;
235 var newValue
= isArray
? value
[index
] : value
;
237 if(name
== "SELECT"){
238 var opts
= node
.options
;
239 for(var i
= 0; i
< opts
.length
; i
++){
242 opt
.selected
= (array
.indexOf(value
, opt
.value
) != -1);
244 opt
.selected
= (opt
.value
== newValue
);
247 }else if(type
== "checkbox" || type
== "radio"){
248 node
.checked
= (node
.value
== newValue
);
250 node
.value
= newValue
;
253 return this; //dojo.NodeList
255 //node already declared above.
257 if(!node
|| node
.nodeType
!= 1){
260 value
= node
.value
|| "";
261 if(node
.nodeName
.toUpperCase() == "SELECT" && node
.multiple
){
262 //A multivalued selectbox. Do the pain.
264 //opts declared above in if block.
266 //i declared above in if block;
267 for(i
= 0; i
< opts
.length
; i
++){
268 //opt declared above in if block
271 value
.push(opt
.value
);
278 return value
; //String||Array
282 append: function(/*String||DOMNode||NodeList*/content
){
284 // appends the content to every node in the NodeList.
286 // The content will be cloned if the length of NodeList
287 // is greater than 1. Only the DOM nodes are cloned, not
288 // any attached event handlers.
290 // dojo.NodeList, the nodes currently in this NodeList will be returned,
291 // not the appended content.
293 // assume a DOM created by this markup:
294 // | <div id="foo"><p>Hello Mars</p></div>
295 // | <div id="bar"><p>Hello World</p></div>
296 // Running this code:
297 // | dojo.query("div").append("<span>append</span>");
298 // Results in this DOM structure:
299 // | <div id="foo"><p>Hello Mars</p><span>append</span></div>
300 // | <div id="bar"><p>Hello World</p><span>append</span></div>
301 return this.addContent(content
, "last"); //dojo.NodeList
304 appendTo: function(/*String*/query
){
306 // appends nodes in this NodeList to the nodes matched by
307 // the query passed to appendTo.
309 // The nodes in this NodeList will be cloned if the query
310 // matches more than one element. Only the DOM nodes are cloned, not
311 // any attached event handlers.
313 // dojo.NodeList, the nodes currently in this NodeList will be returned,
314 // not the matched nodes from the query.
316 // assume a DOM created by this markup:
317 // | <span>append</span>
318 // | <p>Hello Mars</p>
319 // | <p>Hello World</p>
320 // Running this code:
321 // | dojo.query("span").appendTo("p");
322 // Results in this DOM structure:
323 // | <p>Hello Mars<span>append</span></p>
324 // | <p>Hello World<span>append</span></p>
325 return this._placeMultiple(query
, "last"); //dojo.NodeList
328 prepend: function(/*String||DOMNode||NodeList*/content
){
330 // prepends the content to every node in the NodeList.
332 // The content will be cloned if the length of NodeList
333 // is greater than 1. Only the DOM nodes are cloned, not
334 // any attached event handlers.
336 // dojo.NodeList, the nodes currently in this NodeList will be returned,
337 // not the appended content.
338 // assume a DOM created by this markup:
339 // | <div id="foo"><p>Hello Mars</p></div>
340 // | <div id="bar"><p>Hello World</p></div>
341 // Running this code:
342 // | dojo.query("div").prepend("<span>prepend</span>");
343 // Results in this DOM structure:
344 // | <div id="foo"><span>prepend</span><p>Hello Mars</p></div>
345 // | <div id="bar"><span>prepend</span><p>Hello World</p></div>
346 return this.addContent(content
, "first"); //dojo.NodeList
349 prependTo: function(/*String*/query
){
351 // prepends nodes in this NodeList to the nodes matched by
352 // the query passed to prependTo.
354 // The nodes in this NodeList will be cloned if the query
355 // matches more than one element. Only the DOM nodes are cloned, not
356 // any attached event handlers.
358 // dojo.NodeList, the nodes currently in this NodeList will be returned,
359 // not the matched nodes from the query.
361 // assume a DOM created by this markup:
362 // | <span>prepend</span>
363 // | <p>Hello Mars</p>
364 // | <p>Hello World</p>
365 // Running this code:
366 // | dojo.query("span").prependTo("p");
367 // Results in this DOM structure:
368 // | <p><span>prepend</span>Hello Mars</p>
369 // | <p><span>prepend</span>Hello World</p>
370 return this._placeMultiple(query
, "first"); //dojo.NodeList
373 after: function(/*String||Element||NodeList*/content
){
375 // Places the content after every node in the NodeList.
377 // The content will be cloned if the length of NodeList
378 // is greater than 1. Only the DOM nodes are cloned, not
379 // any attached event handlers.
381 // dojo.NodeList, the nodes currently in this NodeList will be returned,
382 // not the appended content.
384 // assume a DOM created by this markup:
385 // | <div id="foo"><p>Hello Mars</p></div>
386 // | <div id="bar"><p>Hello World</p></div>
387 // Running this code:
388 // | dojo.query("div").after("<span>after</span>");
389 // Results in this DOM structure:
390 // | <div id="foo"><p>Hello Mars</p></div><span>after</span>
391 // | <div id="bar"><p>Hello World</p></div><span>after</span>
392 return this.addContent(content
, "after"); //dojo.NodeList
395 insertAfter: function(/*String*/query
){
397 // The nodes in this NodeList will be placed after the nodes
398 // matched by the query passed to insertAfter.
400 // The nodes in this NodeList will be cloned if the query
401 // matches more than one element. Only the DOM nodes are cloned, not
402 // any attached event handlers.
404 // dojo.NodeList, the nodes currently in this NodeList will be returned,
405 // not the matched nodes from the query.
407 // assume a DOM created by this markup:
408 // | <span>after</span>
409 // | <p>Hello Mars</p>
410 // | <p>Hello World</p>
411 // Running this code:
412 // | dojo.query("span").insertAfter("p");
413 // Results in this DOM structure:
414 // | <p>Hello Mars</p><span>after</span>
415 // | <p>Hello World</p><span>after</span>
416 return this._placeMultiple(query
, "after"); //dojo.NodeList
419 before: function(/*String||DOMNode||NodeList*/content
){
421 // Places the content before every node in the NodeList.
423 // The content will be cloned if the length of NodeList
424 // is greater than 1. Only the DOM nodes are cloned, not
425 // any attached event handlers.
427 // dojo.NodeList, the nodes currently in this NodeList will be returned,
428 // not the appended content.
430 // assume a DOM created by this markup:
431 // | <div id="foo"><p>Hello Mars</p></div>
432 // | <div id="bar"><p>Hello World</p></div>
433 // Running this code:
434 // | dojo.query("div").before("<span>before</span>");
435 // Results in this DOM structure:
436 // | <span>before</span><div id="foo"><p>Hello Mars</p></div>
437 // | <span>before</span><div id="bar"><p>Hello World</p></div>
438 return this.addContent(content
, "before"); //dojo.NodeList
441 insertBefore: function(/*String*/query
){
443 // The nodes in this NodeList will be placed after the nodes
444 // matched by the query passed to insertAfter.
446 // The nodes in this NodeList will be cloned if the query
447 // matches more than one element. Only the DOM nodes are cloned, not
448 // any attached event handlers.
450 // dojo.NodeList, the nodes currently in this NodeList will be returned,
451 // not the matched nodes from the query.
453 // assume a DOM created by this markup:
454 // | <span>before</span>
455 // | <p>Hello Mars</p>
456 // | <p>Hello World</p>
457 // Running this code:
458 // | dojo.query("span").insertBefore("p");
459 // Results in this DOM structure:
460 // | <span>before</span><p>Hello Mars</p>
461 // | <span>before</span><p>Hello World</p>
462 return this._placeMultiple(query
, "before"); //dojo.NodeList
466 remove: function(simpleFilter){
468 // alias for dojo.NodeList's orphan method. Removes elements
469 // in this list that match the simple filter from their parents
470 // and returns them as a new NodeList.
471 // simpleFilter: String
472 // single-expression CSS rule. For example, ".thinger" or
473 // "#someId[attrName='value']" but not "div > span". In short,
474 // anything which does not invoke a descent to evaluate but
475 // can instead be used to test a single node is acceptable.
478 return; // dojo.NodeList
481 remove
: NodeList
.prototype.orphan
,
483 wrap: function(/*String||DOMNode*/html
){
485 // Wrap each node in the NodeList with html passed to wrap.
487 // html will be cloned if the NodeList has more than one
488 // element. Only DOM nodes are cloned, not any attached
491 // dojo.NodeList, the nodes in the current NodeList will be returned,
492 // not the nodes from html argument.
494 // assume a DOM created by this markup:
497 // Running this code:
498 // | dojo.query("b").wrap("<div><span></span></div>");
499 // Results in this DOM structure:
500 // | <div><span><b>one</b></span></div>
501 // | <div><span><b>two</b></span></div>
503 html
= makeWrapNode(html
, this[0]);
505 //Now cycle through the elements and do the insertion.
506 for(var i
= 0, node
; node
= this[i
]; i
++){
507 //Always clone because if html is used to hold one of
508 //the "this" nodes, then on the clone of html it will contain
509 //that "this" node, and that would be bad.
510 var clone
= this._cloneNode(html
);
512 node
.parentNode
.replaceChild(clone
, node
);
514 //Find deepest element and insert old node in it.
515 var insertion
= getWrapInsertion(clone
);
516 insertion
.appendChild(node
);
519 return this; //dojo.NodeList
522 wrapAll: function(/*String||DOMNode*/html
){
524 // Insert html where the first node in this NodeList lives, then place all
525 // nodes in this NodeList as the child of the html.
527 // dojo.NodeList, the nodes in the current NodeList will be returned,
528 // not the nodes from html argument.
530 // assume a DOM created by this markup:
531 // | <div class="container">
532 // | <div class="red">Red One</div>
533 // | <div class="blue">Blue One</div>
534 // | <div class="red">Red Two</div>
535 // | <div class="blue">Blue Two</div>
537 // Running this code:
538 // | dojo.query(".red").wrapAll('<div class="allRed"></div>');
539 // Results in this DOM structure:
540 // | <div class="container">
541 // | <div class="allRed">
542 // | <div class="red">Red One</div>
543 // | <div class="red">Red Two</div>
545 // | <div class="blue">Blue One</div>
546 // | <div class="blue">Blue Two</div>
549 html
= makeWrapNode(html
, this[0]);
551 //Place the wrap HTML in place of the first node.
552 this[0].parentNode
.replaceChild(html
, this[0]);
554 //Now cycle through the elements and move them inside
556 var insertion
= getWrapInsertion(html
);
557 for(var i
= 0, node
; node
= this[i
]; i
++){
558 insertion
.appendChild(node
);
561 return this; //dojo.NodeList
564 wrapInner: function(/*String||DOMNode*/html
){
566 // For each node in the NodeList, wrap all its children with the passed in html.
568 // html will be cloned if the NodeList has more than one
569 // element. Only DOM nodes are cloned, not any attached
572 // dojo.NodeList, the nodes in the current NodeList will be returned,
573 // not the nodes from html argument.
575 // assume a DOM created by this markup:
576 // | <div class="container">
577 // | <div class="red">Red One</div>
578 // | <div class="blue">Blue One</div>
579 // | <div class="red">Red Two</div>
580 // | <div class="blue">Blue Two</div>
582 // Running this code:
583 // | dojo.query(".red").wrapInner('<span class="special"></span>');
584 // Results in this DOM structure:
585 // | <div class="container">
586 // | <div class="red"><span class="special">Red One</span></div>
587 // | <div class="blue">Blue One</div>
588 // | <div class="red"><span class="special">Red Two</span></div>
589 // | <div class="blue">Blue Two</div>
592 html
= makeWrapNode(html
, this[0]);
593 for(var i
= 0; i
< this.length
; i
++){
594 //Always clone because if html is used to hold one of
595 //the "this" nodes, then on the clone of html it will contain
596 //that "this" node, and that would be bad.
597 var clone
= this._cloneNode(html
);
599 //Need to convert the childNodes to an array since wrapAll modifies the
600 //DOM and can change the live childNodes NodeList.
601 this._wrap(lang
._toArray(this[i
].childNodes
), null, this._NodeListCtor
).wrapAll(clone
);
604 return this; //dojo.NodeList
607 replaceWith: function(/*String||DOMNode||NodeList*/content
){
609 // Replaces each node in ths NodeList with the content passed to replaceWith.
611 // The content will be cloned if the length of NodeList
612 // is greater than 1. Only the DOM nodes are cloned, not
613 // any attached event handlers.
615 // The nodes currently in this NodeList will be returned, not the replacing content.
616 // Note that the returned nodes have been removed from the DOM.
618 // assume a DOM created by this markup:
619 // | <div class="container">
620 // | <div class="red">Red One</div>
621 // | <div class="blue">Blue One</div>
622 // | <div class="red">Red Two</div>
623 // | <div class="blue">Blue Two</div>
625 // Running this code:
626 // | dojo.query(".red").replaceWith('<div class="green">Green</div>');
627 // Results in this DOM structure:
628 // | <div class="container">
629 // | <div class="green">Green</div>
630 // | <div class="blue">Blue One</div>
631 // | <div class="green">Green</div>
632 // | <div class="blue">Blue Two</div>
634 content
= this._normalize(content
, this[0]);
635 for(var i
= 0, node
; node
= this[i
]; i
++){
636 this._place(content
, node
, "before", i
> 0);
637 node
.parentNode
.removeChild(node
);
639 return this; //dojo.NodeList
642 replaceAll: function(/*String*/query
){
644 // replaces nodes matched by the query passed to replaceAll with the nodes
647 // The nodes in this NodeList will be cloned if the query
648 // matches more than one element. Only the DOM nodes are cloned, not
649 // any attached event handlers.
651 // The nodes currently in this NodeList will be returned, not the matched nodes
652 // from the query. The nodes currently in this NodeLIst could have
653 // been cloned, so the returned NodeList will include the cloned nodes.
655 // assume a DOM created by this markup:
656 // | <div class="container">
657 // | <div class="spacer">___</div>
658 // | <div class="red">Red One</div>
659 // | <div class="spacer">___</div>
660 // | <div class="blue">Blue One</div>
661 // | <div class="spacer">___</div>
662 // | <div class="red">Red Two</div>
663 // | <div class="spacer">___</div>
664 // | <div class="blue">Blue Two</div>
666 // Running this code:
667 // | dojo.query(".red").replaceAll(".blue");
668 // Results in this DOM structure:
669 // | <div class="container">
670 // | <div class="spacer">___</div>
671 // | <div class="spacer">___</div>
672 // | <div class="red">Red One</div>
673 // | <div class="red">Red Two</div>
674 // | <div class="spacer">___</div>
675 // | <div class="spacer">___</div>
676 // | <div class="red">Red One</div>
677 // | <div class="red">Red Two</div>
679 var nl
= dquery(query
);
680 var content
= this._normalize(this, this[0]);
681 for(var i
= 0, node
; node
= nl
[i
]; i
++){
682 this._place(content
, node
, "before", i
> 0);
683 node
.parentNode
.removeChild(node
);
685 return this; //dojo.NodeList
690 // Clones all the nodes in this NodeList and returns them as a new NodeList.
692 // Only the DOM nodes are cloned, not any attached event handlers.
694 // dojo.NodeList, a cloned set of the original nodes.
696 // assume a DOM created by this markup:
697 // | <div class="container">
698 // | <div class="red">Red One</div>
699 // | <div class="blue">Blue One</div>
700 // | <div class="red">Red Two</div>
701 // | <div class="blue">Blue Two</div>
703 // Running this code:
704 // | dojo.query(".red").clone().appendTo(".container");
705 // Results in this DOM structure:
706 // | <div class="container">
707 // | <div class="red">Red One</div>
708 // | <div class="blue">Blue One</div>
709 // | <div class="red">Red Two</div>
710 // | <div class="blue">Blue Two</div>
711 // | <div class="red">Red One</div>
712 // | <div class="red">Red Two</div>
715 //TODO: need option to clone events?
717 for(var i
= 0; i
< this.length
; i
++){
718 ary
.push(this._cloneNode(this[i
]));
720 return this._wrap(ary
, this, this._NodeListCtor
); //dojo.NodeList
724 //set up html method if one does not exist
725 if(!NodeList
.prototype.html
){
726 NodeList
.prototype.html
= NodeList
.prototype.innerHTML
;