[ Index ]

PHP Cross Reference of Unnamed Project

title

Body

[close]

/lib/yuilib/3.17.2/dom-base/ -> dom-base.js (source)

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


Generated: Thu Aug 11 10:00:09 2016 Cross-referenced by PHPXref 0.7.1