3
Copyright 2011 Yahoo! Inc. All rights reserved.
4
Licensed under the BSD License.
5
http://yuilibrary.com/license/
7
YUI.add('dom-create', function(Y) {
9
var re_tag = /<([a-z]+)/i,
13
addFeature = Y.Features.add,
14
testFeature = Y.Features.test,
18
createFromDIV = function(html, tag) {
19
var div = Y.config.doc.createElement('div'),
23
if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) {
30
re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/,
32
TABLE_OPEN = '<table>',
33
TABLE_CLOSE = '</table>';
38
_create: function(html, doc, tag) {
41
var frag = Y_DOM._fragClones[tag];
43
frag = frag.cloneNode(false);
45
frag = Y_DOM._fragClones[tag] = doc.createElement(tag);
47
frag.innerHTML = html;
52
* Creates a new dom node using the provided markup string.
54
* @param {String} html The markup used to create the element
55
* @param {HTMLDocument} doc An optional document context
56
* @return {HTMLElement|DocumentFragment} returns a single HTMLElement
57
* when creating one node, and a documentFragment when creating
60
create: function(html, doc) {
61
if (typeof html === 'string') {
62
html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
66
doc = doc || Y.config.doc;
67
var m = re_tag.exec(html),
68
create = Y_DOM._create,
74
if (html != undefined) { // not undefined or null
76
creator = custom[m[1].toLowerCase()];
77
if (typeof creator === 'function') {
84
nodes = create(html, doc, tag).childNodes;
86
if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
87
ret = nodes[0].parentNode.removeChild(nodes[0]);
88
} else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected)
89
if (nodes.length === 2) {
90
ret = nodes[0].nextSibling;
92
nodes[0].parentNode.removeChild(nodes[0]);
93
ret = Y_DOM._nl2frag(nodes, doc);
95
} else { // return multiple nodes as a fragment
96
ret = Y_DOM._nl2frag(nodes, doc);
103
_nl2frag: function(nodes, doc) {
107
if (nodes && (nodes.push || nodes.item) && nodes[0]) {
108
doc = doc || nodes[0].ownerDocument;
109
ret = doc.createDocumentFragment();
111
if (nodes.item) { // convert live list to static array
112
nodes = Y.Array(nodes, 0, true);
115
for (i = 0, len = nodes.length; i < len; i++) {
116
ret.appendChild(nodes[i]);
118
} // else inline with log for minification
123
* Inserts content in a node at the given location
125
* @param {HTMLElement} node The node to insert into
126
* @param {HTMLElement | Array | HTMLCollection} content The content to be inserted
127
* @param {HTMLElement} where Where to insert the content
128
* If no "where" is given, content is appended to the node
129
* Possible values for "where"
131
* <dt>HTMLElement</dt>
132
* <dd>The element to insert before</dd>
134
* <dd>Replaces the existing HTML</dd>
136
* <dd>Inserts before the existing HTML</dd>
138
* <dd>Inserts content before the node</dd>
140
* <dd>Inserts content after the node</dd>
143
addHTML: function(node, content, where) {
144
var nodeParent = node.parentNode,
151
if (content != undefined) { // not null or undefined (maybe 0)
152
if (content.nodeType) { // DOM node, just add it
154
} else if (typeof content == 'string' || typeof content == 'number') {
155
ret = newNode = Y_DOM.create(content);
156
} else if (content[0] && content[0].nodeType) { // array or collection
157
newNode = Y.config.doc.createDocumentFragment();
158
while ((item = content[i++])) {
159
newNode.appendChild(item); // append to fragment for insertion
165
if (where.nodeType) { // insert regardless of relationship to node
166
where.parentNode.insertBefore(newNode, where);
170
while (node.firstChild) {
171
node.removeChild(node.firstChild);
173
if (newNode) { // allow empty content to clear node
174
node.appendChild(newNode);
178
nodeParent.insertBefore(newNode, node);
181
if (node.nextSibling) { // IE errors if refNode is null
182
nodeParent.insertBefore(newNode, node.nextSibling);
184
nodeParent.appendChild(newNode);
188
node.appendChild(newNode);
191
} else if (newNode) {
192
node.appendChild(newNode);
199
addFeature('innerhtml', 'table', {
201
var node = Y.config.doc.createElement('table');
203
node.innerHTML = '<tbody></tbody>';
207
return (node.firstChild && node.firstChild.nodeName === 'TBODY');
211
addFeature('innerhtml-div', 'tr', {
213
return createFromDIV('<tr></tr>', 'tr');
217
addFeature('innerhtml-div', 'script', {
219
return createFromDIV('<script></script>', 'script');
223
if (!testFeature('innerhtml', 'table')) {
224
// TODO: thead/tfoot with nested tbody
225
// IE adds TBODY when creating TABLE elements (which may share this impl)
226
creators.tbody = function(html, doc) {
227
var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc),
228
tb = frag.children.tags('tbody')[0];
230
if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
231
tb.parentNode.removeChild(tb); // strip extraneous tbody
237
if (!testFeature('innerhtml-div', 'script')) {
238
creators.script = function(html, doc) {
239
var frag = doc.createElement('div');
241
frag.innerHTML = '-' + html;
242
frag.removeChild(frag.firstChild);
246
creators.link = creators.style = creators.script;
249
if (!testFeature('innerhtml-div', 'tr')) {
251
option: function(html, doc) {
252
return Y_DOM.create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc);
255
tr: function(html, doc) {
256
return Y_DOM.create('<tbody>' + html + '</tbody>', doc);
259
td: function(html, doc) {
260
return Y_DOM.create('<tr>' + html + '</tr>', doc);
263
col: function(html, doc) {
264
return Y_DOM.create('<colgroup>' + html + '</colgroup>', doc);
273
thead: creators.tbody,
274
tfoot: creators.tbody,
275
caption: creators.tbody,
276
colgroup: creators.tbody,
277
optgroup: creators.option
281
Y_DOM.creators = creators;
284
}, '3.4.1' ,{requires:['dom-core']});