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