3
Copyright 2012 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
119
else { Y.log('unable to convert ' + nodes + ' to fragment', 'warn', 'dom'); }
124
* Inserts content in a node at the given location
126
* @param {HTMLElement} node The node to insert into
127
* @param {HTMLElement | Array | HTMLCollection} content The content to be inserted
128
* @param {HTMLElement} where Where to insert the content
129
* If no "where" is given, content is appended to the node
130
* Possible values for "where"
132
* <dt>HTMLElement</dt>
133
* <dd>The element to insert before</dd>
135
* <dd>Replaces the existing HTML</dd>
137
* <dd>Inserts before the existing HTML</dd>
139
* <dd>Inserts content before the node</dd>
141
* <dd>Inserts content after the node</dd>
144
addHTML: function(node, content, where) {
145
var nodeParent = node.parentNode,
152
if (content != undefined) { // not null or undefined (maybe 0)
153
if (content.nodeType) { // DOM node, just add it
155
} else if (typeof content == 'string' || typeof content == 'number') {
156
ret = newNode = Y_DOM.create(content);
157
} else if (content[0] && content[0].nodeType) { // array or collection
158
newNode = Y.config.doc.createDocumentFragment();
159
while ((item = content[i++])) {
160
newNode.appendChild(item); // append to fragment for insertion
166
if (where.nodeType) { // insert regardless of relationship to node
167
where.parentNode.insertBefore(newNode, where);
171
while (node.firstChild) {
172
node.removeChild(node.firstChild);
174
if (newNode) { // allow empty content to clear node
175
node.appendChild(newNode);
179
nodeParent.insertBefore(newNode, node);
182
if (node.nextSibling) { // IE errors if refNode is null
183
nodeParent.insertBefore(newNode, node.nextSibling);
185
nodeParent.appendChild(newNode);
189
node.appendChild(newNode);
192
} else if (newNode) {
193
node.appendChild(newNode);
200
addFeature('innerhtml', 'table', {
202
var node = Y.config.doc.createElement('table');
204
node.innerHTML = '<tbody></tbody>';
208
return (node.firstChild && node.firstChild.nodeName === 'TBODY');
212
addFeature('innerhtml-div', 'tr', {
214
return createFromDIV('<tr></tr>', 'tr');
218
addFeature('innerhtml-div', 'script', {
220
return createFromDIV('<script></script>', 'script');
224
if (!testFeature('innerhtml', 'table')) {
225
// TODO: thead/tfoot with nested tbody
226
// IE adds TBODY when creating TABLE elements (which may share this impl)
227
creators.tbody = function(html, doc) {
228
var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc),
229
tb = frag.children.tags('tbody')[0];
231
if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
232
tb.parentNode.removeChild(tb); // strip extraneous tbody
238
if (!testFeature('innerhtml-div', 'script')) {
239
creators.script = function(html, doc) {
240
var frag = doc.createElement('div');
242
frag.innerHTML = '-' + html;
243
frag.removeChild(frag.firstChild);
247
creators.link = creators.style = creators.script;
250
if (!testFeature('innerhtml-div', 'tr')) {
252
option: function(html, doc) {
253
return Y_DOM.create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc);
256
tr: function(html, doc) {
257
return Y_DOM.create('<tbody>' + html + '</tbody>', doc);
260
td: function(html, doc) {
261
return Y_DOM.create('<tr>' + html + '</tr>', doc);
264
col: function(html, doc) {
265
return Y_DOM.create('<colgroup>' + html + '</colgroup>', doc);
274
thead: creators.tbody,
275
tfoot: creators.tbody,
276
caption: creators.tbody,
277
colgroup: creators.tbody,
278
optgroup: creators.option
282
Y_DOM.creators = creators;
285
}, '3.5.1' ,{requires:['dom-core']});