source: Dev/branches/rest-dojo-ui/client/dojo/dom-construct.js @ 273

Last change on this file since 273 was 256, checked in by hendrikvanantwerpen, 13 years ago

Reworked project structure based on REST interaction and Dojo library. As
soon as this is stable, the old jQueryUI branch can be removed (it's
kept for reference).

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