]> git.wh0rd.org - tt-rss.git/blob - lib/dojo/dom-construct.js.uncompressed.js
upgrade dojo to 1.8.3 (refs #570)
[tt-rss.git] / lib / dojo / dom-construct.js.uncompressed.js
1 define("dojo/dom-construct", ["exports", "./_base/kernel", "./sniff", "./_base/window", "./dom", "./dom-attr", "./on"],
2 function(exports, dojo, has, win, dom, attr, on){
3 // module:
4 // dojo/dom-construct
5 // summary:
6 // This module defines the core dojo DOM construction API.
7
8 // TODOC: summary not showing up in output, see https://github.com/csnover/js-doc-parse/issues/42
9
10 // support stuff for toDom()
11 var tagWrap = {
12 option: ["select"],
13 tbody: ["table"],
14 thead: ["table"],
15 tfoot: ["table"],
16 tr: ["table", "tbody"],
17 td: ["table", "tbody", "tr"],
18 th: ["table", "thead", "tr"],
19 legend: ["fieldset"],
20 caption: ["table"],
21 colgroup: ["table"],
22 col: ["table", "colgroup"],
23 li: ["ul"]
24 },
25 reTag = /<\s*([\w\:]+)/,
26 masterNode = {}, masterNum = 0,
27 masterName = "__" + dojo._scopeName + "ToDomId";
28
29 // generate start/end tag strings to use
30 // for the injection for each special tag wrap case.
31 for(var param in tagWrap){
32 if(tagWrap.hasOwnProperty(param)){
33 var tw = tagWrap[param];
34 tw.pre = param == "option" ? '<select multiple="multiple">' : "<" + tw.join("><") + ">";
35 tw.post = "</" + tw.reverse().join("></") + ">";
36 // the last line is destructive: it reverses the array,
37 // but we don't care at this point
38 }
39 }
40
41 function _insertBefore(/*DomNode*/ node, /*DomNode*/ ref){
42 var parent = ref.parentNode;
43 if(parent){
44 parent.insertBefore(node, ref);
45 }
46 }
47
48 function _insertAfter(/*DomNode*/ node, /*DomNode*/ ref){
49 // summary:
50 // Try to insert node after ref
51 var parent = ref.parentNode;
52 if(parent){
53 if(parent.lastChild == ref){
54 parent.appendChild(node);
55 }else{
56 parent.insertBefore(node, ref.nextSibling);
57 }
58 }
59 }
60
61 exports.toDom = function toDom(frag, doc){
62 // summary:
63 // instantiates an HTML fragment returning the corresponding DOM.
64 // frag: String
65 // the HTML fragment
66 // doc: DocumentNode?
67 // optional document to use when creating DOM nodes, defaults to
68 // dojo.doc if not specified.
69 // returns:
70 // Document fragment, unless it's a single node in which case it returns the node itself
71 // example:
72 // Create a table row:
73 // | var tr = dojo.toDom("<tr><td>First!</td></tr>");
74
75 doc = doc || win.doc;
76 var masterId = doc[masterName];
77 if(!masterId){
78 doc[masterName] = masterId = ++masterNum + "";
79 masterNode[masterId] = doc.createElement("div");
80 }
81
82 // make sure the frag is a string.
83 frag += "";
84
85 // find the starting tag, and get node wrapper
86 var match = frag.match(reTag),
87 tag = match ? match[1].toLowerCase() : "",
88 master = masterNode[masterId],
89 wrap, i, fc, df;
90 if(match && tagWrap[tag]){
91 wrap = tagWrap[tag];
92 master.innerHTML = wrap.pre + frag + wrap.post;
93 for(i = wrap.length; i; --i){
94 master = master.firstChild;
95 }
96 }else{
97 master.innerHTML = frag;
98 }
99
100 // one node shortcut => return the node itself
101 if(master.childNodes.length == 1){
102 return master.removeChild(master.firstChild); // DOMNode
103 }
104
105 // return multiple nodes as a document fragment
106 df = doc.createDocumentFragment();
107 while((fc = master.firstChild)){ // intentional assignment
108 df.appendChild(fc);
109 }
110 return df; // DocumentFragment
111 };
112
113 exports.place = function place(/*DOMNode|String*/ node, /*DOMNode|String*/ refNode, /*String|Number?*/ position){
114 // summary:
115 // Attempt to insert node into the DOM, choosing from various positioning options.
116 // Returns the first argument resolved to a DOM node.
117 // node: DOMNode|String
118 // id or node reference, or HTML fragment starting with "<" to place relative to refNode
119 // refNode: DOMNode|String
120 // id or node reference to use as basis for placement
121 // position: String|Number?
122 // string noting the position of node relative to refNode or a
123 // number indicating the location in the childNodes collection of refNode.
124 // Accepted string values are:
125 //
126 // - before
127 // - after
128 // - replace
129 // - only
130 // - first
131 // - last
132 //
133 // "first" and "last" indicate positions as children of refNode, "replace" replaces refNode,
134 // "only" replaces all children. position defaults to "last" if not specified
135 // returns: DOMNode
136 // Returned values is the first argument resolved to a DOM node.
137 //
138 // .place() is also a method of `dojo/NodeList`, allowing `dojo.query` node lookups.
139 // example:
140 // Place a node by string id as the last child of another node by string id:
141 // | dojo.place("someNode", "anotherNode");
142 // example:
143 // Place a node by string id before another node by string id
144 // | dojo.place("someNode", "anotherNode", "before");
145 // example:
146 // Create a Node, and place it in the body element (last child):
147 // | dojo.place("<div></div>", dojo.body());
148 // example:
149 // Put a new LI as the first child of a list by id:
150 // | dojo.place("<li></li>", "someUl", "first");
151
152 refNode = dom.byId(refNode);
153 if(typeof node == "string"){ // inline'd type check
154 node = /^\s*</.test(node) ? exports.toDom(node, refNode.ownerDocument) : dom.byId(node);
155 }
156 if(typeof position == "number"){ // inline'd type check
157 var cn = refNode.childNodes;
158 if(!cn.length || cn.length <= position){
159 refNode.appendChild(node);
160 }else{
161 _insertBefore(node, cn[position < 0 ? 0 : position]);
162 }
163 }else{
164 switch(position){
165 case "before":
166 _insertBefore(node, refNode);
167 break;
168 case "after":
169 _insertAfter(node, refNode);
170 break;
171 case "replace":
172 refNode.parentNode.replaceChild(node, refNode);
173 break;
174 case "only":
175 exports.empty(refNode);
176 refNode.appendChild(node);
177 break;
178 case "first":
179 if(refNode.firstChild){
180 _insertBefore(node, refNode.firstChild);
181 break;
182 }
183 // else fallthrough...
184 default: // aka: last
185 refNode.appendChild(node);
186 }
187 }
188 return node; // DomNode
189 };
190
191 exports.create = function create(/*DOMNode|String*/ tag, /*Object*/ attrs, /*DOMNode|String?*/ refNode, /*String?*/ pos){
192 // summary:
193 // Create an element, allowing for optional attribute decoration
194 // and placement.
195 // description:
196 // A DOM Element creation function. A shorthand method for creating a node or
197 // a fragment, and allowing for a convenient optional attribute setting step,
198 // as well as an optional DOM placement reference.
199 //
200 // Attributes are set by passing the optional object through `dojo.setAttr`.
201 // See `dojo.setAttr` for noted caveats and nuances, and API if applicable.
202 //
203 // Placement is done via `dojo.place`, assuming the new node to be the action
204 // node, passing along the optional reference node and position.
205 // tag: DOMNode|String
206 // A string of the element to create (eg: "div", "a", "p", "li", "script", "br"),
207 // or an existing DOM node to process.
208 // attrs: Object
209 // An object-hash of attributes to set on the newly created node.
210 // Can be null, if you don't want to set any attributes/styles.
211 // See: `dojo.setAttr` for a description of available attributes.
212 // refNode: DOMNode|String?
213 // Optional reference node. Used by `dojo.place` to place the newly created
214 // node somewhere in the dom relative to refNode. Can be a DomNode reference
215 // or String ID of a node.
216 // pos: String?
217 // Optional positional reference. Defaults to "last" by way of `dojo.place`,
218 // though can be set to "first","after","before","last", "replace" or "only"
219 // to further control the placement of the new node relative to the refNode.
220 // 'refNode' is required if a 'pos' is specified.
221 // example:
222 // Create a DIV:
223 // | var n = dojo.create("div");
224 //
225 // example:
226 // Create a DIV with content:
227 // | var n = dojo.create("div", { innerHTML:"<p>hi</p>" });
228 //
229 // example:
230 // Place a new DIV in the BODY, with no attributes set
231 // | var n = dojo.create("div", null, dojo.body());
232 //
233 // example:
234 // Create an UL, and populate it with LI's. Place the list as the first-child of a
235 // node with id="someId":
236 // | var ul = dojo.create("ul", null, "someId", "first");
237 // | var items = ["one", "two", "three", "four"];
238 // | dojo.forEach(items, function(data){
239 // | dojo.create("li", { innerHTML: data }, ul);
240 // | });
241 //
242 // example:
243 // Create an anchor, with an href. Place in BODY:
244 // | dojo.create("a", { href:"foo.html", title:"Goto FOO!" }, dojo.body());
245 //
246 // example:
247 // Create a `dojo/NodeList()` from a new element (for syntactic sugar):
248 // | dojo.query(dojo.create('div'))
249 // | .addClass("newDiv")
250 // | .onclick(function(e){ console.log('clicked', e.target) })
251 // | .place("#someNode"); // redundant, but cleaner.
252
253 var doc = win.doc;
254 if(refNode){
255 refNode = dom.byId(refNode);
256 doc = refNode.ownerDocument;
257 }
258 if(typeof tag == "string"){ // inline'd type check
259 tag = doc.createElement(tag);
260 }
261 if(attrs){ attr.set(tag, attrs); }
262 if(refNode){ exports.place(tag, refNode, pos); }
263 return tag; // DomNode
264 };
265
266 var _empty = has("ie") ?
267 function(/*DomNode*/ node){
268 try{
269 node.innerHTML = ""; // really fast when it works
270 }catch(e){ // IE can generate Unknown Error
271 for(var c; c = node.lastChild;){ // intentional assignment
272 _destroy(c, node); // destroy is better than removeChild so TABLE elements are removed in proper order
273 }
274 }
275 } :
276 function(/*DomNode*/ node){
277 node.innerHTML = "";
278 };
279
280 exports.empty = function empty(/*DOMNode|String*/ node){
281 // summary:
282 // safely removes all children of the node.
283 // node: DOMNode|String
284 // a reference to a DOM node or an id.
285 // example:
286 // Destroy node's children byId:
287 // | dojo.empty("someId");
288 //
289 // example:
290 // Destroy all nodes' children in a list by reference:
291 // | dojo.query(".someNode").forEach(dojo.empty);
292
293 _empty(dom.byId(node));
294 };
295
296
297 function _destroy(/*DomNode*/ node, /*DomNode*/ parent){
298 if(node.firstChild){
299 _empty(node);
300 }
301 if(parent){
302 parent.removeChild(node);
303 }
304 }
305 exports.destroy = function destroy(/*DOMNode|String*/ node){
306 // summary:
307 // Removes a node from its parent, clobbering it and all of its
308 // children.
309 //
310 // description:
311 // Removes a node from its parent, clobbering it and all of its
312 // children. Function only works with DomNodes, and returns nothing.
313 //
314 // node: DOMNode|String
315 // A String ID or DomNode reference of the element to be destroyed
316 //
317 // example:
318 // Destroy a node byId:
319 // | dojo.destroy("someId");
320 //
321 // example:
322 // Destroy all nodes in a list by reference:
323 // | dojo.query(".someNode").forEach(dojo.destroy);
324
325 node = dom.byId(node);
326 if(!node){ return; }
327 _destroy(node, node.parentNode);
328 };
329 });