1YUI.add('dom-base', function (Y, NAME) { 2 3/** 4* @for DOM 5* @module dom 6*/ 7var documentElement = Y.config.doc.documentElement, 8 Y_DOM = Y.DOM, 9 TAG_NAME = 'tagName', 10 OWNER_DOCUMENT = 'ownerDocument', 11 EMPTY_STRING = '', 12 addFeature = Y.Features.add, 13 testFeature = Y.Features.test; 14 15Y.mix(Y_DOM, { 16 /** 17 * Returns the text content of the HTMLElement. 18 * @method getText 19 * @param {HTMLElement} element The html element. 20 * @return {String} The text content of the element (includes text of any descending elements). 21 */ 22 getText: (documentElement.textContent !== undefined) ? 23 function(element) { 24 var ret = ''; 25 if (element) { 26 ret = element.textContent; 27 } 28 return ret || ''; 29 } : function(element) { 30 var ret = ''; 31 if (element) { 32 ret = element.innerText || element.nodeValue; // might be a textNode 33 } 34 return ret || ''; 35 }, 36 37 /** 38 * Sets the text content of the HTMLElement. 39 * @method setText 40 * @param {HTMLElement} element The html element. 41 * @param {String} content The content to add. 42 */ 43 setText: (documentElement.textContent !== undefined) ? 44 function(element, content) { 45 if (element) { 46 element.textContent = content; 47 } 48 } : function(element, content) { 49 if ('innerText' in element) { 50 element.innerText = content; 51 } else if ('nodeValue' in element) { 52 element.nodeValue = content; 53 } 54 }, 55 56 CUSTOM_ATTRIBUTES: (!documentElement.hasAttribute) ? { // IE < 8 57 'for': 'htmlFor', 58 'class': 'className' 59 } : { // w3c 60 'htmlFor': 'for', 61 'className': 'class' 62 }, 63 64 /** 65 * Provides a normalized attribute interface. 66 * @method setAttribute 67 * @param {HTMLElement} el The target element for the attribute. 68 * @param {String} attr The attribute to set. 69 * @param {String} val The value of the attribute. 70 */ 71 setAttribute: function(el, attr, val, ieAttr) { 72 if (el && attr && el.setAttribute) { 73 attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; 74 el.setAttribute(attr, val, ieAttr); 75 } 76 }, 77 78 79 /** 80 * Provides a normalized attribute interface. 81 * @method getAttribute 82 * @param {HTMLElement} el The target element for the attribute. 83 * @param {String} attr The attribute to get. 84 * @return {String} The current value of the attribute. 85 */ 86 getAttribute: function(el, attr, ieAttr) { 87 ieAttr = (ieAttr !== undefined) ? ieAttr : 2; 88 var ret = ''; 89 if (el && attr && el.getAttribute) { 90 attr = Y_DOM.CUSTOM_ATTRIBUTES[attr] || attr; 91 ret = el.getAttribute(attr, ieAttr); 92 93 if (ret === null) { 94 ret = ''; // per DOM spec 95 } 96 } 97 return ret; 98 }, 99 100 VALUE_SETTERS: {}, 101 102 VALUE_GETTERS: {}, 103 104 getValue: function(node) { 105 var ret = '', // TODO: return null? 106 getter; 107 108 if (node && node[TAG_NAME]) { 109 getter = Y_DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()]; 110 111 if (getter) { 112 ret = getter(node); 113 } else { 114 ret = node.value; 115 } 116 } 117 118 // workaround for IE8 JSON stringify bug 119 // which converts empty string values to null 120 if (ret === EMPTY_STRING) { 121 ret = EMPTY_STRING; // for real 122 } 123 124 return (typeof ret === 'string') ? ret : ''; 125 }, 126 127 setValue: function(node, val) { 128 var setter; 129 130 if (node && node[TAG_NAME]) { 131 setter = Y_DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()]; 132 133 if (setter) { 134 setter(node, val); 135 } else { 136 node.value = val; 137 } 138 } 139 }, 140 141 creators: {} 142}); 143 144addFeature('value-set', 'select', { 145 test: function() { 146 var node = Y.config.doc.createElement('select'); 147 node.innerHTML = '<option>1</option><option>2</option>'; 148 node.value = '2'; 149 return (node.value && node.value === '2'); 150 } 151}); 152
153if (!testFeature('value-set', 'select')) { 154 Y_DOM.VALUE_SETTERS.select = function(node, val) { 155 for (var i = 0, options = node.getElementsByTagName('option'), option; 156 option = options[i++];) { 157 if (Y_DOM.getValue(option) === val) { 158 option.selected = true; 159 //Y_DOM.setAttribute(option, 'selected', 'selected'); 160 break; 161 } 162 } 163 }; 164} 165 166Y.mix(Y_DOM.VALUE_GETTERS, { 167 button: function(node) { 168 return (node.attributes && node.attributes.value) ? node.attributes.value.value : ''; 169 } 170}); 171 172Y.mix(Y_DOM.VALUE_SETTERS, { 173 // IE: node.value changes the button text, which should be handled via innerHTML 174 button: function(node, val) { 175 var attr = node.attributes.value; 176 if (!attr) { 177 attr = node[OWNER_DOCUMENT].createAttribute('value'); 178 node.setAttributeNode(attr); 179 } 180 181 attr.value = val; 182 } 183}); 184 185 186Y.mix(Y_DOM.VALUE_GETTERS, { 187 option: function(node) { 188 var attrs = node.attributes; 189 return (attrs.value && attrs.value.specified) ? node.value : node.text; 190 }, 191 192 select: function(node) { 193 var val = node.value, 194 options = node.options; 195 196 if (options && options.length) { 197 // TODO: implement multipe select 198 if (node.multiple) { 199 } else if (node.selectedIndex > -1) { 200 val = Y_DOM.getValue(options[node.selectedIndex]); 201 } 202 } 203 204 return val; 205 } 206}); 207var addClass, hasClass, removeClass; 208 209Y.mix(Y.DOM, { 210 /** 211 * Determines whether a DOM element has the given className. 212 * @method hasClass 213 * @for DOM 214 * @param {HTMLElement} element The DOM element. 215 * @param {String} className the class name to search for 216 * @return {Boolean} Whether or not the element has the given class. 217 */ 218 hasClass: function(node, className) { 219 var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)'); 220 return re.test(node.className); 221 }, 222 223 /** 224 * Adds a class name to a given DOM element. 225 * @method addClass 226 * @for DOM 227 * @param {HTMLElement} element The DOM element. 228 * @param {String} className the class name to add to the class attribute 229 */ 230 addClass: function(node, className) { 231 if (!Y.DOM.hasClass(node, className)) { // skip if already present 232 node.className = Y.Lang.trim([node.className, className].join(' ')); 233 } 234 }, 235 236 /** 237 * Removes a class name from a given element. 238 * @method removeClass 239 * @for DOM 240 * @param {HTMLElement} element The DOM element. 241 * @param {String} className the class name to remove from the class attribute 242 */ 243 removeClass: function(node, className) { 244 if (className && hasClass(node, className)) { 245 node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' + 246 className + '(?:\\s+|$)'), ' ')); 247 248 if ( hasClass(node, className) ) { // in case of multiple adjacent 249 removeClass(node, className); 250 } 251 } 252 }, 253 254 /** 255 * Replace a class with another class for a given element. 256 * If no oldClassName is present, the newClassName is simply added. 257 * @method replaceClass 258 * @for DOM 259 * @param {HTMLElement} element The DOM element 260 * @param {String} oldClassName the class name to be replaced 261 * @param {String} newClassName the class name that will be replacing the old class name 262 */ 263 replaceClass: function(node, oldC, newC) { 264 removeClass(node, oldC); // remove first in case oldC === newC 265 addClass(node, newC); 266 }, 267 268 /** 269 * If the className exists on the node it is removed, if it doesn't exist it is added. 270 * @method toggleClass 271 * @for DOM 272 * @param {HTMLElement} element The DOM element 273 * @param {String} className the class name to be toggled 274 * @param {Boolean} addClass optional boolean to indicate whether class 275 * should be added or removed regardless of current state 276 */ 277 toggleClass: function(node, className, force) { 278 var add = (force !== undefined) ? force : 279 !(hasClass(node, className)); 280 281 if (add) { 282 addClass(node, className); 283 } else { 284 removeClass(node, className); 285 } 286 } 287}); 288 289hasClass = Y.DOM.hasClass; 290removeClass = Y.DOM.removeClass; 291addClass = Y.DOM.addClass; 292 293var re_tag = /<([a-z]+)/i, 294 295 Y_DOM = Y.DOM, 296 297 addFeature = Y.Features.add, 298 testFeature = Y.Features.test, 299 300 creators = {}, 301 302 createFromDIV = function(html, tag) { 303 var div = Y.config.doc.createElement('div'), 304 ret = true; 305 306 div.innerHTML = html; 307 if (!div.firstChild || div.firstChild.tagName !== tag.toUpperCase()) { 308 ret = false;
309 } 310 311 return ret; 312 }, 313 314 re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/, 315 316 TABLE_OPEN = '<table>', 317 TABLE_CLOSE = '</table>'; 318 319Y.mix(Y.DOM, { 320 _fragClones: {}, 321 322 _create: function(html, doc, tag) { 323 tag = tag || 'div'; 324 325 var frag = Y_DOM._fragClones[tag]; 326 if (frag) { 327 frag = frag.cloneNode(false); 328 } else { 329 frag = Y_DOM._fragClones[tag] = doc.createElement(tag); 330 } 331 frag.innerHTML = html; 332 return frag; 333 }, 334 335 _children: function(node, tag) { 336 var i = 0, 337 children = node.children, 338 childNodes, 339 hasComments, 340 child; 341 342 if (children && children.tags) { // use tags filter when possible 343 if (tag) { 344 children = node.children.tags(tag); 345 } else { // IE leaks comments into children 346 hasComments = children.tags('!').length; 347 } 348 } 349 350 if (!children || (!children.tags && tag) || hasComments) { 351 childNodes = children || node.childNodes; 352 children = []; 353 while ((child = childNodes[i++])) { 354 if (child.nodeType === 1) { 355 if (!tag || tag === child.tagName) { 356 children.push(child); 357 } 358 } 359 } 360 } 361 362 return children || []; 363 }, 364 365 /** 366 * Creates a new dom node using the provided markup string. 367 * @method create 368 * @param {String} html The markup used to create the element 369 * @param {HTMLDocument} doc An optional document context 370 * @return {HTMLElement|DocumentFragment} returns a single HTMLElement 371 * when creating one node, and a documentFragment when creating 372 * multiple nodes. 373 */ 374 create: function(html, doc) { 375 if (typeof html === 'string') { 376 html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML 377 378 } 379 380 doc = doc || Y.config.doc; 381 var m = re_tag.exec(html), 382 create = Y_DOM._create, 383 custom = creators, 384 ret = null, 385 creator, 386 tag, nodes; 387 388 if (html != undefined) { // not undefined or null 389 if (m && m[1]) { 390 creator = custom[m[1].toLowerCase()]; 391 if (typeof creator === 'function') { 392 create = creator; 393 } else { 394 tag = creator; 395 } 396 } 397 398 nodes = create(html, doc, tag).childNodes; 399 400 if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment" 401 ret = nodes[0].parentNode.removeChild(nodes[0]); 402 } else if (nodes[0] && nodes[0].className === 'yui3-big-dummy') { // using dummy node to preserve some attributes (e.g. OPTION not selected) 403 if (nodes.length === 2) { 404 ret = nodes[0].nextSibling; 405 } else { 406 nodes[0].parentNode.removeChild(nodes[0]); 407 ret = Y_DOM._nl2frag(nodes, doc); 408 } 409 } else { // return multiple nodes as a fragment 410 ret = Y_DOM._nl2frag(nodes, doc); 411 } 412 413 } 414 415 return ret; 416 }, 417 418 _nl2frag: function(nodes, doc) { 419 var ret = null, 420 i, len; 421 422 if (nodes && (nodes.push || nodes.item) && nodes[0]) { 423 doc = doc || nodes[0].ownerDocument; 424 ret = doc.createDocumentFragment(); 425 426 if (nodes.item) { // convert live list to static array 427 nodes = Y.Array(nodes, 0, true); 428 } 429 430 for (i = 0, len = nodes.length; i < len; i++) { 431 ret.appendChild(nodes[i]); 432 } 433 } // else inline with log for minification 434 return ret; 435 }, 436 437 /** 438 * Inserts content in a node at the given location 439 * @method addHTML 440 * @param {HTMLElement} node The node to insert into 441 * @param {HTMLElement | Array | HTMLCollection} content The content to be inserted 442 * @param {HTMLElement} where Where to insert the content 443 * If no "where" is given, content is appended to the node 444 * Possible values for "where" 445 * <dl> 446 * <dt>HTMLElement</dt> 447 * <dd>The element to insert before</dd> 448 * <dt>"replace"</dt> 449 * <dd>Replaces the existing HTML</dd> 450 * <dt>"before"</dt> 451 * <dd>Inserts before the existing HTML</dd> 452 * <dt>"before"</dt> 453 * <dd>Inserts content before the node</dd> 454 * <dt>"after"</dt> 455 * <dd>Inserts content after the node</dd> 456 * </dl> 457 */ 458 addHTML: function(node, content, where) { 459 var nodeParent = node.parentNode, 460 i = 0, 461 item, 462 ret = content, 463 newNode; 464 465 466 if (content != undefined) { // not null or undefined (maybe 0) 467 if (content.nodeType) { // DOM node, just add it 468 newNode = content; 469 } else if (typeof content == 'string' || typeof content == 'number') { 470 ret = newNode = Y_DOM.create(content); 471 } else if (content[0] && content[0].nodeType) { // array or collection 472 newNode = Y.config.doc.createDocumentFragment(); 473 while ((item = content[i++])) { 474 newNode.appendChild(item); // append to fragment for insertion 475 } 476 } 477 } 478 479 if (where) { 480 if (newNode && where.parentNode) { // insert regardless of relationship to node 481 where.parentNode.insertBefore(newNode, where); 482 } else { 483 switch (where) { 484 case 'replace': 485 while (node.firstChild) { 486 node.removeChild(node.firstChild); 487 } 488 if (newNode) { // allow empty content to clear node 489 node.appendChild(newNode); 490 } 491 break; 492 case 'before': 493 if (newNode) { 494 nodeParent.insertBefore(newNode, node); 495 } 496 break; 497 case 'after': 498 if (newNode) { 499 if (node.nextSibling) { // IE errors if refNo
499de is null 500 nodeParent.insertBefore(newNode, node.nextSibling); 501 } else { 502 nodeParent.appendChild(newNode); 503 } 504 } 505 break; 506 default: 507 if (newNode) { 508 node.appendChild(newNode); 509 } 510 } 511 } 512 } else if (newNode) { 513 node.appendChild(newNode); 514 } 515 516 return ret; 517 }, 518 519 wrap: function(node, html) { 520 var parent = (html && html.nodeType) ? html : Y.DOM.create(html), 521 nodes = parent.getElementsByTagName('*'); 522 523 if (nodes.length) { 524 parent = nodes[nodes.length - 1]; 525 } 526 527 if (node.parentNode) { 528 node.parentNode.replaceChild(parent, node); 529 } 530 parent.appendChild(node); 531 }, 532 533 unwrap: function(node) { 534 var parent = node.parentNode, 535 lastChild = parent.lastChild, 536 next = node, 537 grandparent; 538 539 if (parent) { 540 grandparent = parent.parentNode; 541 if (grandparent) { 542 node = parent.firstChild; 543 while (node !== lastChild) { 544 next = node.nextSibling; 545 grandparent.insertBefore(node, parent); 546 node = next; 547 } 548 grandparent.replaceChild(lastChild, parent); 549 } else { 550 parent.removeChild(node); 551 } 552 } 553 } 554}); 555 556addFeature('innerhtml', 'table', { 557 test: function() { 558 var node = Y.config.doc.createElement('table'); 559 try { 560 node.innerHTML = '<tbody></tbody>'; 561 } catch(e) { 562 return false; 563 } 564 return (node.firstChild && node.firstChild.nodeName === 'TBODY'); 565 } 566}); 567 568addFeature('innerhtml-div', 'tr', { 569 test: function() { 570 return createFromDIV('<tr></tr>', 'tr'); 571 } 572}); 573 574addFeature('innerhtml-div', 'script', { 575 test: function() { 576 return createFromDIV('<script></script>', 'script'); 577 } 578}); 579 580if (!testFeature('innerhtml', 'table')) { 581 // TODO: thead/tfoot with nested tbody 582 // IE adds TBODY when creating TABLE elements (which may share this impl) 583 creators.tbody = function(html, doc) { 584 var frag = Y_DOM.create(TABLE_OPEN + html + TABLE_CLOSE, doc), 585 tb = Y.DOM._children(frag, 'tbody')[0]; 586 587 if (frag.children.length > 1 && tb && !re_tbody.test(html)) { 588 tb.parentNode.removeChild(tb); // strip extraneous tbody 589 } 590 return frag; 591 }; 592} 593 594if (!testFeature('innerhtml-div', 'script')) { 595 creators.script = function(html, doc) { 596 var frag = doc.createElement('div'); 597 598 frag.innerHTML = '-' + html; 599 frag.removeChild(frag.firstChild); 600 return frag; 601 }; 602 603 creators.link = creators.style = creators.script; 604} 605 606if (!testFeature('innerhtml-div', 'tr')) { 607 Y.mix(creators, { 608 option: function(html, doc) { 609 return Y_DOM.create('<select><option class="yui3-big-dummy" selected></option>' + html + '</select>', doc); 610 }, 611 612 tr: function(html, doc) { 613 return Y_DOM.create('<tbody>' + html + '</tbody>', doc); 614 }, 615 616 td: function(html, doc) { 617 return Y_DOM.create('<tr>' + html + '</tr>', doc); 618 }, 619 620 col: function(html, doc) { 621 return Y_DOM.create('<colgroup>' + html + '</colgroup>', doc); 622 }, 623 624 tbody: 'table' 625 }); 626 627 Y.mix(creators, { 628 legend: 'fieldset', 629 th: creators.td, 630 thead: creators.tbody, 631 tfoot: creators.tbody, 632 caption: creators.tbody, 633 colgroup: creators.tbody, 634 optgroup: creators.option 635 }); 636} 637 638Y_DOM.creators = creators; 639Y.mix(Y.DOM, { 640 /** 641 * Sets the width of the element to the given size, regardless 642 * of box model, border, padding, etc. 643 * @method setWidth 644 * @param {HTMLElement} element The DOM element. 645 * @param {String|Number} size The pixel height to size to 646 */ 647 648 setWidth: function(node, size) { 649 Y.DOM._setSize(node, 'width', size); 650 }, 651 652 /** 653 * Sets the height of the element to the given size, regardless 654 * of box model, border, padding, etc. 655 * @method setHeight 656 * @param {HTMLElement} element The DOM element. 657 * @param {String|Number} size The pixel height to size to 658 */ 659 660 setHeight: function(node, size) { 661 Y.DOM._setSize(node, 'height', size); 662 }, 663 664 _setSize: function(node, prop, val) { 665 val = (val > 0) ? val : 0; 666 var size = 0; 667 668 node.style[prop] = val + 'px'; 669 size = (prop === 'height') ? node.offsetHeight : node.offsetWidth; 670 671 if (size > val) { 672 val = val - (size - val); 673 674 if (val < 0) { 675 val = 0; 676 } 677 678 node.style[prop] = val + 'px'; 679 } 680 } 681}); 682 683 684}, 'patched-v3.11.0', {"requires": ["dom-core"]});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.