[256] | 1 | define(["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 | }); |
---|