/ajax/libs/yui/3.0.0b1/dom/dom.js

https://gitlab.com/Mirros/cdnjs · JavaScript · 1491 lines · 966 code · 197 blank · 328 comment · 238 complexity · d84e8553260bfe5dbab05a27e856b51b MD5 · raw file

  1. YUI.add('dom-base', function(Y) {
  2. (function(Y) {
  3. /**
  4. * The DOM utility provides a cross-browser abtraction layer
  5. * normalizing DOM tasks, and adds extra helper functionality
  6. * for other common tasks.
  7. * @module dom
  8. * @submodule dom-base
  9. *
  10. */
  11. /**
  12. * Provides DOM helper methods.
  13. * @class DOM
  14. *
  15. */
  16. var NODE_TYPE = 'nodeType',
  17. OWNER_DOCUMENT = 'ownerDocument',
  18. DOCUMENT_ELEMENT = 'documentElement',
  19. DEFAULT_VIEW = 'defaultView',
  20. PARENT_WINDOW = 'parentWindow',
  21. TAG_NAME = 'tagName',
  22. PARENT_NODE = 'parentNode',
  23. FIRST_CHILD = 'firstChild',
  24. LAST_CHILD = 'lastChild',
  25. PREVIOUS_SIBLING = 'previousSibling',
  26. NEXT_SIBLING = 'nextSibling',
  27. CONTAINS = 'contains',
  28. COMPARE_DOCUMENT_POSITION = 'compareDocumentPosition',
  29. re_tag = /<([a-z]+)/i;
  30. Y.DOM = {
  31. /**
  32. * Returns the HTMLElement with the given ID (Wrapper for document.getElementById).
  33. * @method byId
  34. * @param {String} id the id attribute
  35. * @param {Object} doc optional The document to search. Defaults to current document
  36. * @return {HTMLElement | null} The HTMLElement with the id, or null if none found.
  37. */
  38. byId: function(id, doc) {
  39. doc = doc || Y.config.doc;
  40. // TODO: IE Name
  41. return doc.getElementById(id);
  42. },
  43. /**
  44. * Returns the text content of the HTMLElement.
  45. * @method getText
  46. * @param {HTMLElement} element The html element.
  47. * @return {String} The text content of the element (includes text of any descending elements).
  48. */
  49. getText: (document.documentElement.textContent !== undefined) ?
  50. function(element) {
  51. var ret = '';
  52. if (element) {
  53. ret = element.textContent;
  54. }
  55. return ret || '';
  56. } : function(element) {
  57. var ret = '';
  58. if (element) {
  59. ret = element.innerText;
  60. }
  61. return ret || '';
  62. },
  63. /**
  64. * Sets the text content of the HTMLElement.
  65. * @method setText
  66. * @param {HTMLElement} element The html element.
  67. * @param {String} content The content to add.
  68. */
  69. setText: (document.documentElement.textContent !== undefined) ?
  70. function(element, content) {
  71. if (element) {
  72. element.textContent = content;
  73. }
  74. } : function(element, content) {
  75. if (element) {
  76. element.innerText = content;
  77. }
  78. },
  79. // TODO: pull out sugar (rely on _childBy, byAxis, etc)?
  80. /*
  81. * Finds the firstChild of the given HTMLElement.
  82. * @method firstChild
  83. * @deprecated Use _childBy
  84. * @param {HTMLElement} element The html element.
  85. * @param {Function} fn optional An optional boolean test to apply.
  86. * The optional function is passed the current HTMLElement being tested as its only argument.
  87. * If no function is given, the first found is returned.
  88. * @return {HTMLElement | null} The first matching child html element.
  89. */
  90. firstChild: function(element, fn) {
  91. return Y.DOM._childBy(element, null, fn);
  92. },
  93. // @deprecated Use _childBy
  94. firstChildByTag: function(element, tag, fn) {
  95. return Y.DOM._childBy(element, tag, fn);
  96. },
  97. /*
  98. * Finds the lastChild of the given HTMLElement.
  99. * @method lastChild
  100. * @deprecated Use _childBy
  101. * @param {HTMLElement} element The html element.
  102. * @param {String} tag The tag to search for.
  103. * @param {Function} fn optional An optional boolean test to apply.
  104. * The optional function is passed the current HTMLElement being tested as its only argument.
  105. * If no function is given, the first found is returned.
  106. * @return {HTMLElement | null} The first matching child html element.
  107. */
  108. lastChild: function(element, fn) {
  109. return Y.DOM._childBy(element, null, fn, true);
  110. },
  111. // @deprecated Use _childBy
  112. lastChildByTag: function(element, tag, fn) {
  113. return Y.DOM._childBy(element, tag, fn, true);
  114. },
  115. /*
  116. * Finds all HTMLElement childNodes matching the given tag.
  117. * @method childrenByTag
  118. * @deprecated Use Selector
  119. * @param {HTMLElement} element The html element.
  120. * @param {String} tag The tag to search for.
  121. * @param {Function} fn optional An optional boolean test to apply.
  122. * The optional function is passed the current HTMLElement being tested as its only argument.
  123. * If no function is given, all children with the given tag are collected.
  124. * @return {Array} The collection of child elements.
  125. * TODO: Webkit children.tags() returns grandchildren
  126. */
  127. _childrenByTag: function() {
  128. if (document[DOCUMENT_ELEMENT].children) {
  129. return function(element, tag, fn, toArray) { // TODO: keep toArray option?
  130. tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
  131. var elements = [],
  132. wrapFn = fn;
  133. if (element) {
  134. if (tag && !Y.UA.webkit) { // children.tags() broken in safari
  135. elements = element.children.tags(tag);
  136. } else {
  137. elements = element.children;
  138. if (tag) {
  139. wrapFn = function(el) {
  140. return el[TAG_NAME].toUpperCase() === tag && (!fn || fn(el));
  141. };
  142. }
  143. }
  144. elements = Y.DOM.filterElementsBy(elements, wrapFn);
  145. }
  146. return elements;
  147. };
  148. } else {
  149. return function(element, tag, fn) {
  150. tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
  151. var elements = [],
  152. wrapFn = fn;
  153. if (element) {
  154. elements = element.childNodes;
  155. if (tag) { // wrap fn and add tag test TODO: allow tag in filterElementsBy?
  156. wrapFn = function(el) {
  157. return el[TAG_NAME].toUpperCase() === tag && (!fn || fn(el));
  158. };
  159. }
  160. elements = Y.DOM.filterElementsBy(elements, wrapFn);
  161. }
  162. return elements;
  163. };
  164. }
  165. }(),
  166. /*
  167. * Finds all HTMLElement childNodes.
  168. * @method children
  169. * @deprecated Use Selector
  170. * @param {HTMLElement} element The html element.
  171. * @param {Function} fn optional An optional boolean test to apply.
  172. * The optional function is passed the current HTMLElement being tested as its only argument.
  173. * If no function is given, all children are collected.
  174. * @return {Array} The collection of child elements.
  175. */
  176. children: function(element, fn) {
  177. return Y.DOM._childrenByTag(element, null, fn);
  178. },
  179. /*
  180. * Finds the previous sibling of the element.
  181. * @method previous
  182. * @deprecated Use elementByAxis
  183. * @param {HTMLElement} element The html element.
  184. * @param {Function} fn optional An optional boolean test to apply.
  185. * The optional function is passed the current DOM node being tested as its only argument.
  186. * If no function is given, the first sibling is returned.
  187. * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
  188. * @return {HTMLElement | null} The matching DOM node or null if none found.
  189. */
  190. previous: function(element, fn, all) {
  191. return Y.DOM.elementByAxis(element, PREVIOUS_SIBLING, fn, all);
  192. },
  193. /*
  194. * Finds the next sibling of the element.
  195. * @method next
  196. * @deprecated Use elementByAxis
  197. * @param {HTMLElement} element The html element.
  198. * @param {Function} fn optional An optional boolean test to apply.
  199. * The optional function is passed the current DOM node being tested as its only argument.
  200. * If no function is given, the first sibling is returned.
  201. * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
  202. * @return {HTMLElement | null} The matching DOM node or null if none found.
  203. */
  204. next: function(element, fn, all) {
  205. return Y.DOM.elementByAxis(element, NEXT_SIBLING, fn, all);
  206. },
  207. /*
  208. * Finds the ancestor of the element.
  209. * @method ancestor
  210. * @deprecated Use elementByAxis
  211. * @param {HTMLElement} element The html element.
  212. * @param {Function} fn optional An optional boolean test to apply.
  213. * The optional function is passed the current DOM node being tested as its only argument.
  214. * If no function is given, the parentNode is returned.
  215. * @param {Boolean} all optional Whether all node types should be scanned, or just element nodes.
  216. * @return {HTMLElement | null} The matching DOM node or null if none found.
  217. */
  218. // TODO: optional stopAt node?
  219. ancestor: function(element, fn, all) {
  220. return Y.DOM.elementByAxis(element, PARENT_NODE, fn, all);
  221. },
  222. /**
  223. * Searches the element by the given axis for the first matching element.
  224. * @method elementByAxis
  225. * @param {HTMLElement} element The html element.
  226. * @param {String} axis The axis to search (parentNode, nextSibling, previousSibling).
  227. * @param {Function} fn optional An optional boolean test to apply.
  228. * @param {Boolean} all optional Whether all node types should be returned, or just element nodes.
  229. * The optional function is passed the current HTMLElement being tested as its only argument.
  230. * If no function is given, the first element is returned.
  231. * @return {HTMLElement | null} The matching element or null if none found.
  232. */
  233. elementByAxis: function(element, axis, fn, all) {
  234. while (element && (element = element[axis])) { // NOTE: assignment
  235. if ( (all || element[TAG_NAME]) && (!fn || fn(element)) ) {
  236. return element;
  237. }
  238. }
  239. return null;
  240. },
  241. /*
  242. * Finds all elements with the given tag.
  243. * @method byTag
  244. * @deprecated Use Selector
  245. * @param {String} tag The tag being search for.
  246. * @param {HTMLElement} root optional An optional root element to start from.
  247. * @param {Function} fn optional An optional boolean test to apply.
  248. * The optional function is passed the current HTMLElement being tested as its only argument.
  249. * If no function is given, all elements with the given tag are returned.
  250. * @return {Array} The collection of matching elements.
  251. */
  252. byTag: function(tag, root, fn) {
  253. root = root || Y.config.doc;
  254. var elements = root.getElementsByTagName(tag),
  255. retNodes = [],
  256. i, len;
  257. for (i = 0, len = elements.length; i < len; ++i) {
  258. if ( !fn || fn(elements[i]) ) {
  259. retNodes[retNodes.length] = elements[i];
  260. }
  261. }
  262. return retNodes;
  263. },
  264. /*
  265. * Finds the first element with the given tag.
  266. * @method firstByTag
  267. * @deprecated Use Selector
  268. * @param {String} tag The tag being search for.
  269. * @param {HTMLElement} root optional An optional root element to start from.
  270. * @param {Function} fn optional An optional boolean test to apply.
  271. * The optional function is passed the current HTMLElement being tested as its only argument.
  272. * If no function is given, the first match is returned.
  273. * @return {HTMLElement} The matching element.
  274. */
  275. firstByTag: function(tag, root, fn) {
  276. root = root || Y.config.doc;
  277. var elements = root.getElementsByTagName(tag),
  278. ret = null,
  279. i, len;
  280. for (i = 0, len = elements.length; i < len; ++i) {
  281. if ( !fn || fn(elements[i]) ) {
  282. ret = elements[i];
  283. break;
  284. }
  285. }
  286. return ret;
  287. },
  288. /*
  289. * Filters a collection of HTMLElements by the given attributes.
  290. * @method filterElementsBy
  291. * @param {Array} elements The collection of HTMLElements to filter.
  292. * @param {Function} fn A boolean test to apply.
  293. * The function is passed the current HTMLElement being tested as its only argument.
  294. * If no function is given, all HTMLElements are kept.
  295. * @return {Array} The filtered collection of HTMLElements.
  296. */
  297. filterElementsBy: function(elements, fn, firstOnly) {
  298. var ret = (firstOnly) ? null : [],
  299. i, len;
  300. for (i = 0, len = elements.length; i < len; ++i) {
  301. if (elements[i][TAG_NAME] && (!fn || fn(elements[i]))) {
  302. if (firstOnly) {
  303. ret = elements[i];
  304. break;
  305. } else {
  306. ret[ret.length] = elements[i];
  307. }
  308. }
  309. }
  310. return ret;
  311. },
  312. /**
  313. * Determines whether or not one HTMLElement is or contains another HTMLElement.
  314. * @method contains
  315. * @param {HTMLElement} element The containing html element.
  316. * @param {HTMLElement} needle The html element that may be contained.
  317. * @return {Boolean} Whether or not the element is or contains the needle.
  318. */
  319. contains: function(element, needle) {
  320. var ret = false;
  321. if ( !needle || !element || !needle[NODE_TYPE] || !element[NODE_TYPE]) {
  322. ret = false;
  323. } else if (element[CONTAINS]) {
  324. if (Y.UA.opera || needle[NODE_TYPE] === 1) { // IE & SAF contains fail if needle not an ELEMENT_NODE
  325. ret = element[CONTAINS](needle);
  326. } else {
  327. ret = Y.DOM._bruteContains(element, needle);
  328. }
  329. } else if (element[COMPARE_DOCUMENT_POSITION]) { // gecko
  330. if (element === needle || !!(element[COMPARE_DOCUMENT_POSITION](needle) & 16)) {
  331. ret = true;
  332. }
  333. }
  334. return ret;
  335. },
  336. /**
  337. * Determines whether or not the HTMLElement is part of the document.
  338. * @method inDoc
  339. * @param {HTMLElement} element The containing html element.
  340. * @param {HTMLElement} doc optional The document to check.
  341. * @return {Boolean} Whether or not the element is attached to the document.
  342. */
  343. inDoc: function(element, doc) {
  344. doc = doc || element[OWNER_DOCUMENT];
  345. var id = element.id;
  346. if (!id) { // TODO: remove when done?
  347. id = element.id = Y.guid();
  348. }
  349. return !! (doc.getElementById(id));
  350. },
  351. /**
  352. * Inserts the new node as the previous sibling of the reference node
  353. * @method insertBefore
  354. * @param {String | HTMLElement} newNode The node to be inserted
  355. * @param {String | HTMLElement} referenceNode The node to insert the new node before
  356. * @return {HTMLElement} The node that was inserted (or null if insert fails)
  357. */
  358. insertBefore: function(newNode, referenceNode) {
  359. var ret = null,
  360. parent;
  361. if (newNode && referenceNode && (parent = referenceNode.parentNode)) { // NOTE: assignment
  362. if (typeof newNode === 'string') {
  363. newNode = Y.DOM.create(newNode);
  364. }
  365. ret = parent.insertBefore(newNode, referenceNode);
  366. } else {
  367. }
  368. return ret;
  369. },
  370. /**
  371. * Inserts the new node as the next sibling of the reference node
  372. * @method insertAfter
  373. * @param {String | HTMLElement} newNode The node to be inserted
  374. * @param {String | HTMLElement} referenceNode The node to insert the new node after
  375. * @return {HTMLElement} The node that was inserted (or null if insert fails)
  376. */
  377. insertAfter: function(newNode, referenceNode) {
  378. if (!newNode || !referenceNode || !referenceNode[PARENT_NODE]) {
  379. return null;
  380. }
  381. if (typeof newNode === 'string') {
  382. newNode = Y.DOM.create(newNode);
  383. }
  384. if (referenceNode[NEXT_SIBLING]) {
  385. return referenceNode[PARENT_NODE].insertBefore(newNode, referenceNode[NEXT_SIBLING]);
  386. } else {
  387. return referenceNode[PARENT_NODE].appendChild(newNode);
  388. }
  389. },
  390. /**
  391. * Creates a new dom node using the provided markup string.
  392. * @method create
  393. * @param {String} html The markup used to create the element
  394. * @param {HTMLDocument} doc An optional document context
  395. */
  396. create: function(html, doc) {
  397. html = Y.Lang.trim(html); // match IE which trims whitespace from innerHTML
  398. if (!doc && Y.DOM._cloneCache[html]) {
  399. return Y.DOM._cloneCache[html].cloneNode(true); // NOTE: return
  400. }
  401. doc = doc || Y.config.doc;
  402. var m = re_tag.exec(html),
  403. create = Y.DOM._create,
  404. custom = Y.DOM.creators,
  405. ret = null,
  406. tag, nodes;
  407. if (m && custom[m[1]]) {
  408. if (typeof custom[m[1]] === 'function') {
  409. create = custom[m[1]];
  410. } else {
  411. tag = custom[m[1]];
  412. }
  413. }
  414. nodes = create(html, doc, tag).childNodes;
  415. if (nodes.length === 1) { // return single node, breaking parentNode ref from "fragment"
  416. ret = nodes[0].parentNode.removeChild(nodes[0]);
  417. } else { // return multiple nodes as a fragment
  418. ret = doc.createDocumentFragment();
  419. while (nodes.length) {
  420. ret.appendChild(nodes[0]);
  421. }
  422. }
  423. Y.DOM._cloneCache[html] = ret.cloneNode(true);
  424. return ret;
  425. },
  426. CUSTOM_ATTRIBUTES: (!document.documentElement.hasAttribute) ? { // IE < 8
  427. 'for': 'htmlFor',
  428. 'class': 'className'
  429. } : { // w3c
  430. 'htmlFor': 'for',
  431. 'className': 'class'
  432. },
  433. /**
  434. * Provides a normalized attribute interface.
  435. * @method setAttibute
  436. * @param {String | HTMLElement} el The target element for the attribute.
  437. * @param {String} attr The attribute to set.
  438. * @param {String} val The value of the attribute.
  439. */
  440. setAttribute: function(el, attr, val) {
  441. if (el && el.setAttribute) {
  442. attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
  443. el.setAttribute(attr, val);
  444. }
  445. },
  446. /**
  447. * Provides a normalized attribute interface.
  448. * @method getAttibute
  449. * @param {String | HTMLElement} el The target element for the attribute.
  450. * @param {String} attr The attribute to get.
  451. * @return {String} The current value of the attribute.
  452. */
  453. getAttribute: function(el, attr) {
  454. var ret = '';
  455. if (el && el.getAttribute) {
  456. attr = Y.DOM.CUSTOM_ATTRIBUTES[attr] || attr;
  457. ret = el.getAttribute(attr, 2);
  458. if (ret === null) {
  459. ret = ''; // per DOM spec
  460. }
  461. }
  462. return ret;
  463. },
  464. // @deprecated
  465. srcIndex: (document.documentElement.sourceIndex) ?
  466. function(node) {
  467. return (node && node.sourceIndex) ? node.sourceIndex : null;
  468. } :
  469. function(node) {
  470. return (node && node[OWNER_DOCUMENT]) ?
  471. [].indexOf.call(node[OWNER_DOCUMENT].
  472. getElementsByTagName('*'), node) : null;
  473. },
  474. isWindow: function(obj) {
  475. return obj.alert && obj.document;
  476. },
  477. _fragClones: {
  478. div: document.createElement('div')
  479. },
  480. _create: function(html, doc, tag) {
  481. tag = tag || 'div';
  482. var frag = Y.DOM._fragClones[tag];
  483. if (frag) {
  484. frag = frag.cloneNode(false);
  485. } else {
  486. frag = Y.DOM._fragClones[tag] = doc.createElement(tag);
  487. }
  488. frag.innerHTML = html;
  489. return frag;
  490. },
  491. _removeChildNodes: function(node) {
  492. while (node.firstChild) {
  493. node.removeChild(node.firstChild);
  494. }
  495. },
  496. _cloneCache: {},
  497. /**
  498. * Inserts content in a node at the given location
  499. * @method addHTML
  500. * @param {HTMLElement} node The node to insert into
  501. * @param {String} content The content to be inserted
  502. * @param {String} where Where to insert the content; default is after lastChild
  503. */
  504. addHTML: function(node, content, where) {
  505. if (typeof content === 'string') {
  506. content = Y.Lang.trim(content); // match IE which trims whitespace from innerHTML
  507. }
  508. var newNode = Y.DOM._cloneCache[content];
  509. if (newNode) {
  510. newNode = newNode.cloneNode(true);
  511. } else {
  512. if (content.nodeType) { // domNode
  513. newNode = content;
  514. } else { // create from string and cache
  515. newNode = Y.DOM.create(content);
  516. }
  517. }
  518. if (where) {
  519. if (where.nodeType) { // insert regardless of relationship to node
  520. // TODO: check if node.contains(where)?
  521. where.parentNode.insertBefore(newNode, where);
  522. } else {
  523. switch (where) {
  524. case 'replace':
  525. while (node.firstChild) {
  526. node.removeChild(node.firstChild);
  527. }
  528. node.appendChild(newNode);
  529. break;
  530. case 'before':
  531. node.parentNode.insertBefore(newNode, node);
  532. break;
  533. case 'after':
  534. if (node.nextSibling) { // IE errors if refNode is null
  535. node.parentNode.insertBefore(newNode, node.nextSibling);
  536. } else {
  537. node.parentNode.appendChild(newNode);
  538. }
  539. break;
  540. default:
  541. node.appendChild(newNode);
  542. }
  543. }
  544. } else {
  545. node.appendChild(newNode);
  546. }
  547. return newNode;
  548. },
  549. VALUE_SETTERS: {},
  550. VALUE_GETTERS: {},
  551. getValue: function(node) {
  552. var ret = '', // TODO: return null?
  553. getter;
  554. if (node && node[TAG_NAME]) {
  555. getter = Y.DOM.VALUE_GETTERS[node[TAG_NAME].toLowerCase()];
  556. if (getter) {
  557. ret = getter(node);
  558. } else {
  559. ret = node.value;
  560. }
  561. }
  562. return (typeof ret === 'string') ? ret : '';
  563. },
  564. setValue: function(node, val) {
  565. var setter;
  566. if (node && node[TAG_NAME]) {
  567. setter = Y.DOM.VALUE_SETTERS[node[TAG_NAME].toLowerCase()];
  568. if (setter) {
  569. setter(node, val);
  570. } else {
  571. node.value = val;
  572. }
  573. }
  574. },
  575. _stripScripts: function(node) {
  576. var scripts = node.getElementsByTagName('script'),
  577. i, script;
  578. for (i = 0, script; script = scripts[i++];) {
  579. script.parentNode.removeChild(script);
  580. }
  581. },
  582. _execScripts: function(scripts, startIndex) {
  583. var newScript,
  584. i, script;
  585. startIndex = startIndex || 0;
  586. for (i = startIndex, script; script = scripts[i++];) {
  587. newScript = script.ownerDocument.createElement('script');
  588. script.parentNode.replaceChild(newScript, script);
  589. if (script.text) {
  590. newScript.text = script.text;
  591. } else if (script.src) {
  592. newScript.src = script.src;
  593. // "pause" while loading to ensure exec order
  594. // FF reports typeof onload as "undefined", so try IE first
  595. if (typeof newScript.onreadystatechange !== 'undefined') {
  596. newScript.onreadystatechange = function() {
  597. if (/loaded|complete/.test(script.readyState)) {
  598. event.srcElement.onreadystatechange = null;
  599. // timer to help ensure exec order
  600. setTimeout(function() {
  601. Y.DOM._execScripts(scripts, i++);
  602. }, 0);
  603. }
  604. };
  605. } else {
  606. newScript.onload = function(e) {
  607. e.target.onload = null;
  608. Y.DOM._execScripts(scripts, i++);
  609. };
  610. }
  611. return; // NOTE: early return to chain async loading
  612. }
  613. }
  614. },
  615. /**
  616. * Brute force version of contains.
  617. * Used for browsers without contains support for non-HTMLElement Nodes (textNodes, etc).
  618. * @method _bruteContains
  619. * @private
  620. * @param {HTMLElement} element The containing html element.
  621. * @param {HTMLElement} needle The html element that may be contained.
  622. * @return {Boolean} Whether or not the element is or contains the needle.
  623. */
  624. _bruteContains: function(element, needle) {
  625. while (needle) {
  626. if (element === needle) {
  627. return true;
  628. }
  629. needle = needle.parentNode;
  630. }
  631. return false;
  632. },
  633. // TODO: move to Lang?
  634. /**
  635. * Memoizes dynamic regular expressions to boost runtime performance.
  636. * @method _getRegExp
  637. * @private
  638. * @param {String} str The string to convert to a regular expression.
  639. * @param {String} flags optional An optinal string of flags.
  640. * @return {RegExp} An instance of RegExp
  641. */
  642. _getRegExp: function(str, flags) {
  643. flags = flags || '';
  644. Y.DOM._regexCache = Y.DOM._regexCache || {};
  645. if (!Y.DOM._regexCache[str + flags]) {
  646. Y.DOM._regexCache[str + flags] = new RegExp(str, flags);
  647. }
  648. return Y.DOM._regexCache[str + flags];
  649. },
  650. // TODO: make getDoc/Win true privates?
  651. /**
  652. * returns the appropriate document.
  653. * @method _getDoc
  654. * @private
  655. * @param {HTMLElement} element optional Target element.
  656. * @return {Object} The document for the given element or the default document.
  657. */
  658. _getDoc: function(element) {
  659. element = element || {};
  660. return (element[NODE_TYPE] === 9) ? element : // element === document
  661. element[OWNER_DOCUMENT] || // element === DOM node
  662. element.document || // element === window
  663. Y.config.doc; // default
  664. },
  665. /**
  666. * returns the appropriate window.
  667. * @method _getWin
  668. * @private
  669. * @param {HTMLElement} element optional Target element.
  670. * @return {Object} The window for the given element or the default window.
  671. */
  672. _getWin: function(element) {
  673. var doc = Y.DOM._getDoc(element);
  674. return doc[DEFAULT_VIEW] || doc[PARENT_WINDOW] || Y.config.win;
  675. },
  676. // @deprecated, use Selector
  677. _childBy: function(element, tag, fn, rev) {
  678. var ret = null,
  679. root, axis;
  680. if (element) {
  681. if (rev) {
  682. root = element[LAST_CHILD];
  683. axis = PREVIOUS_SIBLING;
  684. } else {
  685. root = element[FIRST_CHILD];
  686. axis = NEXT_SIBLING;
  687. }
  688. if (Y.DOM._testElement(root, tag, fn)) { // is the matching element
  689. ret = root;
  690. } else { // need to scan nextSibling axis of firstChild to find matching element
  691. ret = Y.DOM.elementByAxis(root, axis, fn);
  692. }
  693. }
  694. return ret;
  695. },
  696. _batch: function(nodes, fn, arg1, arg2, arg3, etc) {
  697. fn = (typeof name === 'string') ? Y.DOM[fn] : fn;
  698. var result,
  699. ret = [];
  700. if (fn && nodes) {
  701. Y.each(nodes, function(node) {
  702. if ((result = fn.call(Y.DOM, node, arg1, arg2, arg3, etc)) !== undefined) {
  703. ret[ret.length] = result;
  704. }
  705. });
  706. }
  707. return ret.length ? ret : nodes;
  708. },
  709. _testElement: function(element, tag, fn) {
  710. tag = (tag && tag !== '*') ? tag.toUpperCase() : null;
  711. return (element && element[TAG_NAME] &&
  712. (!tag || element[TAG_NAME].toUpperCase() === tag) &&
  713. (!fn || fn(element)));
  714. },
  715. creators: {},
  716. _IESimpleCreate: function(html, doc) {
  717. doc = doc || Y.config.doc;
  718. return doc.createElement(html);
  719. }
  720. };
  721. (function(Y) {
  722. var creators = Y.DOM.creators,
  723. create = Y.DOM.create,
  724. re_tbody = /(?:\/(?:thead|tfoot|tbody|caption|col|colgroup)>)+\s*<tbody/,
  725. TABLE_OPEN = '<table>',
  726. TABLE_CLOSE = '</table>';
  727. if (Y.UA.gecko || Y.UA.ie) { // require custom creation code for certain element types
  728. Y.mix(creators, {
  729. option: function(html, doc) {
  730. return create('<select>' + html + '</select>', doc);
  731. },
  732. tr: function(html, doc) {
  733. return create('<tbody>' + html + '</tbody>', doc);
  734. },
  735. td: function(html, doc) {
  736. return create('<tr>' + html + '</tr>', doc);
  737. },
  738. tbody: function(html, doc) {
  739. return create(TABLE_OPEN + html + TABLE_CLOSE, doc);
  740. },
  741. legend: 'fieldset'
  742. });
  743. creators.col = creators.tbody; // IE wraps in colgroup
  744. }
  745. if (Y.UA.ie) {
  746. Y.mix(creators, {
  747. // TODO: thead/tfoot with nested tbody
  748. // IE adds TBODY when creating TABLE elements (which may share this impl)
  749. tbody: function(html, doc) {
  750. var frag = create(TABLE_OPEN + html + TABLE_CLOSE, doc),
  751. tb = frag.children.tags('tbody')[0];
  752. if (frag.children.length > 1 && tb && !re_tbody.test(html)) {
  753. tb[PARENT_NODE].removeChild(tb); // strip extraneous tbody
  754. }
  755. return frag;
  756. },
  757. script: function(html, doc) {
  758. var frag = doc.createElement('div');
  759. frag.innerHTML = '-' + html;
  760. frag.removeChild(frag[FIRST_CHILD]);
  761. return frag;
  762. }
  763. }, true);
  764. Y.mix(Y.DOM.VALUE_GETTERS, {
  765. button: function(node) {
  766. return (node.attributes && node.attributes.value) ? node.attributes.value.value : '';
  767. }
  768. });
  769. Y.mix(Y.DOM.VALUE_SETTERS, {
  770. // IE: node.value changes the button text, which should be handled via innerHTML
  771. button: function(node, val) {
  772. var attr = node.attributes.value;
  773. if (!attr) {
  774. attr = node[OWNER_DOCUMENT].createAttribute('value');
  775. node.setAttributeNode(attr);
  776. }
  777. attr.value = val;
  778. }
  779. });
  780. }
  781. if (Y.UA.gecko || Y.UA.ie) {
  782. Y.mix(creators, {
  783. th: creators.td,
  784. thead: creators.tbody,
  785. tfoot: creators.tbody,
  786. caption: creators.tbody,
  787. colgroup: creators.tbody,
  788. col: creators.tbody,
  789. optgroup: creators.option
  790. });
  791. }
  792. Y.mix(Y.DOM.VALUE_GETTERS, {
  793. option: function(node) {
  794. var attrs = node.attributes;
  795. return (attrs.value && attrs.value.specified) ? node.value : node.text;
  796. },
  797. select: function(node) {
  798. var val = node.value,
  799. options = node.options;
  800. if (options && val === '') {
  801. if (node.multiple) {
  802. } else {
  803. val = Y.DOM.getValue(options[node.selectedIndex], 'value');
  804. }
  805. }
  806. return val;
  807. }
  808. });
  809. })(Y);
  810. })(Y);
  811. Y.mix(Y.DOM, {
  812. /**
  813. * Determines whether a DOM element has the given className.
  814. * @method hasClass
  815. * @param {HTMLElement} element The DOM element.
  816. * @param {String} className the class name to search for
  817. * @return {Boolean} Whether or not the element has the given class.
  818. */
  819. hasClass: function(node, className) {
  820. var re = Y.DOM._getRegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
  821. return re.test(node.className);
  822. },
  823. /**
  824. * Adds a class name to a given DOM element.
  825. * @method addClass
  826. * @param {HTMLElement} element The DOM element.
  827. * @param {String} className the class name to add to the class attribute
  828. */
  829. addClass: function(node, className) {
  830. if (!Y.DOM.hasClass(node, className)) { // skip if already present
  831. node.className = Y.Lang.trim([node.className, className].join(' '));
  832. }
  833. },
  834. /**
  835. * Removes a class name from a given element.
  836. * @method removeClass
  837. * @param {HTMLElement} element The DOM element.
  838. * @param {String} className the class name to remove from the class attribute
  839. */
  840. removeClass: function(node, className) {
  841. if (className && Y.DOM.hasClass(node, className)) {
  842. node.className = Y.Lang.trim(node.className.replace(Y.DOM._getRegExp('(?:^|\\s+)' +
  843. className + '(?:\\s+|$)'), ' '));
  844. if ( Y.DOM.hasClass(node, className) ) { // in case of multiple adjacent
  845. Y.DOM.removeClass(node, className);
  846. }
  847. }
  848. },
  849. /**
  850. * Replace a class with another class for a given element.
  851. * If no oldClassName is present, the newClassName is simply added.
  852. * @method replaceClass
  853. * @param {HTMLElement} element The DOM element.
  854. * @param {String} oldClassName the class name to be replaced
  855. * @param {String} newClassName the class name that will be replacing the old class name
  856. */
  857. replaceClass: function(node, oldC, newC) {
  858. Y.DOM.addClass(node, newC);
  859. Y.DOM.removeClass(node, oldC);
  860. },
  861. /**
  862. * If the className exists on the node it is removed, if it doesn't exist it is added.
  863. * @method toggleClass
  864. * @param {HTMLElement} element The DOM element.
  865. * @param {String} className the class name to be toggled
  866. */
  867. toggleClass: function(node, className) {
  868. if (Y.DOM.hasClass(node, className)) {
  869. Y.DOM.removeClass(node, className);
  870. } else {
  871. Y.DOM.addClass(node, className);
  872. }
  873. }
  874. });
  875. }, '@VERSION@' ,{requires:['event'], skinnable:false});
  876. YUI.add('dom-style', function(Y) {
  877. (function(Y) {
  878. /**
  879. * Add style management functionality to DOM.
  880. * @module dom
  881. * @submodule dom-style
  882. * @for DOM
  883. */
  884. var DOCUMENT_ELEMENT = 'documentElement',
  885. DEFAULT_VIEW = 'defaultView',
  886. OWNER_DOCUMENT = 'ownerDocument',
  887. STYLE = 'style',
  888. FLOAT = 'float',
  889. CSS_FLOAT = 'cssFloat',
  890. STYLE_FLOAT = 'styleFloat',
  891. TRANSPARENT = 'transparent',
  892. GET_COMPUTED_STYLE = 'getComputedStyle',
  893. DOCUMENT = Y.config.doc,
  894. UNDEFINED = undefined,
  895. re_color = /color$/i;
  896. Y.mix(Y.DOM, {
  897. CUSTOM_STYLES: {
  898. },
  899. /**
  900. * Sets a style property for a given element.
  901. * @method setStyle
  902. * @param {HTMLElement} An HTMLElement to apply the style to.
  903. * @param {String} att The style property to set.
  904. * @param {String|Number} val The value.
  905. */
  906. setStyle: function(node, att, val, style) {
  907. style = style || node.style;
  908. var CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES;
  909. if (style) {
  910. if (val === null) {
  911. val = ''; // normalize for unsetting
  912. }
  913. if (att in CUSTOM_STYLES) {
  914. if (CUSTOM_STYLES[att].set) {
  915. CUSTOM_STYLES[att].set(node, val, style);
  916. return; // NOTE: return
  917. } else if (typeof CUSTOM_STYLES[att] === 'string') {
  918. att = CUSTOM_STYLES[att];
  919. }
  920. }
  921. style[att] = val;
  922. }
  923. },
  924. /**
  925. * Returns the current style value for the given property.
  926. * @method getStyle
  927. * @param {HTMLElement} An HTMLElement to get the style from.
  928. * @param {String} att The style property to get.
  929. */
  930. getStyle: function(node, att) {
  931. var style = node[STYLE],
  932. CUSTOM_STYLES = Y.DOM.CUSTOM_STYLES,
  933. val = '';
  934. if (style) {
  935. if (att in CUSTOM_STYLES) {
  936. if (CUSTOM_STYLES[att].get) {
  937. return CUSTOM_STYLES[att].get(node, att, style); // NOTE: return
  938. } else if (typeof CUSTOM_STYLES[att] === 'string') {
  939. att = CUSTOM_STYLES[att];
  940. }
  941. }
  942. val = style[att];
  943. if (val === '') { // TODO: is empty string sufficient?
  944. val = Y.DOM[GET_COMPUTED_STYLE](node, att);
  945. }
  946. }
  947. return val;
  948. },
  949. /**
  950. * Sets multiple style properties.
  951. * @method setStyles
  952. * @param {HTMLElement} node An HTMLElement to apply the styles to.
  953. * @param {Object} hash An object literal of property:value pairs.
  954. */
  955. setStyles: function(node, hash) {
  956. var style = node.style;
  957. Y.each(hash, function(v, n) {
  958. Y.DOM.setStyle(node, n, v, style);
  959. }, Y.DOM);
  960. },
  961. /**
  962. * Returns the computed style for the given node.
  963. * @method getComputedStyle
  964. * @param {HTMLElement} An HTMLElement to get the style from.
  965. * @param {String} att The style property to get.
  966. * @return {String} The computed value of the style property.
  967. */
  968. getComputedStyle: function(node, att) {
  969. var val = '',
  970. doc = node[OWNER_DOCUMENT];
  971. if (node[STYLE]) {
  972. val = doc[DEFAULT_VIEW][GET_COMPUTED_STYLE](node, null)[att];
  973. }
  974. return val;
  975. }
  976. });
  977. // normalize reserved word float alternatives ("cssFloat" or "styleFloat")
  978. if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][CSS_FLOAT] !== UNDEFINED) {
  979. Y.DOM.CUSTOM_STYLES[FLOAT] = CSS_FLOAT;
  980. } else if (DOCUMENT[DOCUMENT_ELEMENT][STYLE][STYLE_FLOAT] !== UNDEFINED) {
  981. Y.DOM.CUSTOM_STYLES[FLOAT] = STYLE_FLOAT;
  982. }
  983. // fix opera computedStyle default color unit (convert to rgb)
  984. if (Y.UA.opera) {
  985. Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
  986. var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
  987. val = view[GET_COMPUTED_STYLE](node, '')[att];
  988. if (re_color.test(att)) {
  989. val = Y.Color.toRGB(val);
  990. }
  991. return val;
  992. };
  993. }
  994. // safari converts transparent to rgba(), others use "transparent"
  995. if (Y.UA.webkit) {
  996. Y.DOM[GET_COMPUTED_STYLE] = function(node, att) {
  997. var view = node[OWNER_DOCUMENT][DEFAULT_VIEW],
  998. val = view[GET_COMPUTED_STYLE](node, '')[att];
  999. if (val === 'rgba(0, 0, 0, 0)') {
  1000. val = TRANSPARENT;
  1001. }
  1002. return val;
  1003. };
  1004. }
  1005. })(Y);
  1006. (function(Y) {
  1007. var TO_STRING = 'toString',
  1008. PARSE_INT = parseInt,
  1009. RE = RegExp;
  1010. Y.Color = {
  1011. KEYWORDS: {
  1012. black: '000',
  1013. silver: 'c0c0c0',
  1014. gray: '808080',
  1015. white: 'fff',
  1016. maroon: '800000',
  1017. red: 'f00',
  1018. purple: '800080',
  1019. fuchsia: 'f0f',
  1020. green: '008000',
  1021. lime: '0f0',
  1022. olive: '808000',
  1023. yellow: 'ff0',
  1024. navy: '000080',
  1025. blue: '00f',
  1026. teal: '008080',
  1027. aqua: '0ff'
  1028. },
  1029. re_RGB: /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i,
  1030. re_hex: /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i,
  1031. re_hex3: /([0-9A-F])/gi,
  1032. toRGB: function(val) {
  1033. if (!Y.Color.re_RGB.test(val)) {
  1034. val = Y.Color.toHex(val);
  1035. }
  1036. if(Y.Color.re_hex.exec(val)) {
  1037. val = 'rgb(' + [
  1038. PARSE_INT(RE.$1, 16),
  1039. PARSE_INT(RE.$2, 16),
  1040. PARSE_INT(RE.$3, 16)
  1041. ].join(', ') + ')';
  1042. }
  1043. return val;
  1044. },
  1045. toHex: function(val) {
  1046. val = Y.Color.KEYWORDS[val] || val;
  1047. if (Y.Color.re_RGB.exec(val)) {
  1048. var r = (RE.$1.length === 1) ? '0' + RE.$1 : Number(RE.$1),
  1049. g = (RE.$2.length === 1) ? '0' + RE.$2 : Number(RE.$2),
  1050. b = (RE.$3.length === 1) ? '0' + RE.$3 : Number(RE.$3);
  1051. val = [
  1052. r[TO_STRING](16),
  1053. g[TO_STRING](16),
  1054. b[TO_STRING](16)
  1055. ].join('');
  1056. }
  1057. if (val.length < 6) {
  1058. val = val.replace(Y.Color.re_hex3, '$1$1');
  1059. }
  1060. if (val !== 'transparent' && val.indexOf('#') < 0) {
  1061. val = '#' + val;
  1062. }
  1063. return val.toLowerCase();
  1064. }
  1065. };
  1066. })(Y);
  1067. (function(Y) {
  1068. var CLIENT_TOP = 'clientTop',
  1069. CLIENT_LEFT = 'clientLeft',
  1070. HAS_LAYOUT = 'hasLayout',
  1071. PX = 'px',
  1072. FILTER = 'filter',
  1073. FILTERS = 'filters',
  1074. OPACITY = 'opacity',
  1075. AUTO = 'auto',
  1076. BORDER_TOP_WIDTH = 'borderTopWidth',
  1077. BORDER_RIGHT_WIDTH = 'borderRightWidth',
  1078. BORDER_BOTTOM_WIDTH = 'borderBottomWidth',
  1079. BORDER_LEFT_WIDTH = 'borderLeftWidth',
  1080. WIDTH = 'width',
  1081. HEIGHT = 'height',
  1082. TRANSPARENT = 'transparent',
  1083. VISIBLE = 'visible',
  1084. GET_COMPUTED_STYLE = 'getComputedStyle',
  1085. UNDEFINED = undefined,
  1086. documentElement = document.documentElement,
  1087. // TODO: unit-less lineHeight (e.g. 1.22)
  1088. re_size = /^width|height$/,
  1089. re_unit = /^(\d[.\d]*)+(em|ex|px|gd|rem|vw|vh|vm|ch|mm|cm|in|pt|pc|deg|rad|ms|s|hz|khz|%){1}?/i,
  1090. _getStyleObj = function(node) {
  1091. return node.currentStyle || node.style;
  1092. },
  1093. ComputedStyle = {
  1094. CUSTOM_STYLES: {},
  1095. get: function(el, property) {
  1096. var value = '',
  1097. current;
  1098. if (el) {
  1099. current = _getStyleObj(el)[property];
  1100. if (property === OPACITY) {
  1101. value = Y.DOM.CUSTOM_STYLES[OPACITY].get(el);
  1102. } else if (!current || (current.indexOf && current.indexOf(PX) > -1)) { // no need to convert
  1103. value = current;
  1104. } else if (Y.DOM.IE.COMPUTED[property]) { // use compute function
  1105. value = Y.DOM.IE.COMPUTED[property](el, property);
  1106. } else if (re_unit.test(current)) { // convert to pixel
  1107. value = ComputedStyle.getPixel(el, property) + PX;
  1108. } else {
  1109. value = current;
  1110. }
  1111. }
  1112. return value;
  1113. },
  1114. getOffset: function(el, prop) {
  1115. var current = _getStyleObj(el)[prop], // value of "width", "top", etc.
  1116. capped = prop.charAt(0).toUpperCase() + prop.substr(1), // "Width", "Top", etc.
  1117. offset = 'offset' + capped, // "offsetWidth", "offsetTop", etc.
  1118. pixel = 'pixel' + capped, // "pixelWidth", "pixelTop", etc.
  1119. actual,
  1120. value = '';
  1121. if (current === AUTO) {
  1122. actual = el[offset]; // offsetHeight/Top etc.
  1123. if (actual === UNDEFINED) { // likely "right" or "bottom"
  1124. value = 0;
  1125. }
  1126. value = actual;
  1127. if (re_size.test(prop)) { // account for box model diff
  1128. el.style[prop] = actual;
  1129. if (el[offset] > actual) {
  1130. // the difference is padding + border (works in Standards & Quirks modes)
  1131. value = actual - (el[offset] - actual);
  1132. }
  1133. el.style[prop] = AUTO; // revert to auto
  1134. }
  1135. } else { // convert units to px
  1136. if (current.indexOf('%') > -1) { // IE pixelWidth incorrect for percent; manually compute
  1137. current = el.clientWidth - // offsetWidth - borderWidth
  1138. ComputedStyle.getPixel(el, 'paddingRight') -
  1139. ComputedStyle.getPixel(el, 'paddingLeft');
  1140. }
  1141. if (!el.style[pixel] && !el.style[prop]) { // need to map style.width to currentStyle (no currentStyle.pixelWidth)
  1142. el.style[prop] = current; // no style.pixelWidth if no style.width
  1143. }
  1144. value = el.style[pixel];
  1145. }
  1146. return value + PX;
  1147. },
  1148. getBorderWidth: function(el, property) {
  1149. // clientHeight/Width = paddingBox (e.g. offsetWidth - borderWidth)
  1150. // clientTop/Left = borderWidth
  1151. var value = null;
  1152. if (!el.currentStyle || !el.currentStyle[HAS_LAYOUT]) { // TODO: unset layout?
  1153. el.style.zoom = 1; // need layout to measure client
  1154. }
  1155. switch(property) {
  1156. case BORDER_TOP_WIDTH:
  1157. value = el[CLIENT_TOP];
  1158. break;
  1159. case BORDER_BOTTOM_WIDTH:
  1160. value = el.offsetHeight - el.clientHeight - el[CLIENT_TOP];
  1161. break;
  1162. case BORDER_LEFT_WIDTH:
  1163. value = el[CLIENT_LEFT];
  1164. break;
  1165. case BORDER_RIGHT_WIDTH:
  1166. value = el.offsetWidth - el.clientWidth - el[CLIENT_LEFT];
  1167. break;
  1168. }
  1169. return value + PX;
  1170. },
  1171. getPixel: function(node, att) {
  1172. // use pixelRight to convert to px
  1173. var val = null,
  1174. style = _getStyleObj(node),
  1175. styleRight = style.right,
  1176. current = style[att];
  1177. node.style.right = current;
  1178. val = node.style.pixelRight;
  1179. node.style.right = styleRight; // revert
  1180. return val;
  1181. },
  1182. getMargin: function(node, att) {
  1183. var val,
  1184. style = _getStyleObj(node);
  1185. if (style[att] == AUTO) {
  1186. val = 0;
  1187. } else {
  1188. val = ComputedStyle.getPixel(node, att);
  1189. }
  1190. return val + PX;
  1191. },
  1192. getVisibility: function(node, att) {
  1193. var current;
  1194. while ( (current = node.currentStyle) && current[att] == 'inherit') { // NOTE: assignment in test
  1195. node = node.parentNode;
  1196. }
  1197. return (current) ? current[att] : VISIBLE;
  1198. },
  1199. getColor: function(node, att) {
  1200. var current = _getStyleObj(node)[att];
  1201. if (!current || current === TRANSPARENT) {
  1202. Y.DOM.elementByAxis(node, 'parentNode', null, function(parent) {
  1203. current = _getStyleObj(parent)[att];
  1204. if (current && current !== TRANSPARENT) {
  1205. node = parent;
  1206. return true;
  1207. }
  1208. });
  1209. }
  1210. return Y.Color.toRGB(current);
  1211. },
  1212. getBorderColor: function(node, att) {
  1213. var current = _getStyleObj(node),
  1214. val = current[att] || current.color;
  1215. return Y.Color.toRGB(Y.Color.toHex(val));
  1216. }
  1217. },
  1218. //fontSize: getPixelFont,
  1219. IEComputed = {};
  1220. // use alpha filter for IE opacity
  1221. if (documentElement.style[OPACITY] === UNDEFINED &&
  1222. documentElement[FILTERS]) {
  1223. Y.DOM.CUSTOM_STYLES[OPACITY] = {
  1224. get: function(node) {
  1225. var val = 100;
  1226. try { // will error if no DXImageTransform
  1227. val = node[FILTERS]['DXImageTransform.Microsoft.Alpha'][OPACITY];
  1228. } catch(e) {
  1229. try { // make sure its in the document
  1230. val = node[FILTERS]('alpha')[OPACITY];
  1231. } catch(err) {
  1232. }
  1233. }
  1234. return val / 100;
  1235. },
  1236. set: function(node, val, style) {
  1237. var current,
  1238. styleObj;
  1239. if (val === '') { // normalize inline style behavior
  1240. styleObj = _getStyleObj(node);
  1241. current = (OPACITY in styleObj) ? styleObj[OPACITY] : 1; // revert to original opacity
  1242. val = current;
  1243. }
  1244. if (typeof style[FILTER] == 'string') { // in case not appended
  1245. style[FILTER] = 'alpha(' + OPACITY + '=' + val * 100 + ')';
  1246. if (!node.currentStyle || !node.currentStyle[HAS_LAYOUT]) {
  1247. style.zoom = 1; // needs layout
  1248. }
  1249. }
  1250. }
  1251. };
  1252. }
  1253. try {
  1254. document.createElement('div').style.height = '-1px';
  1255. } catch(e) { // IE throws error on invalid style set; trap common cases
  1256. Y.DOM.CUSTOM_STYLES.height = {
  1257. set: function(node, val, style) {
  1258. if (parseInt(val, 10) >= 0) {
  1259. style.height = val;
  1260. } else {
  1261. }
  1262. }
  1263. };
  1264. Y.DOM.CUSTOM_STYLES.width = {
  1265. set: function(node, val, style) {
  1266. if (parseInt(val, 10) >= 0) {
  1267. style.width = val;
  1268. } else {
  1269. }
  1270. }
  1271. };
  1272. }
  1273. // TODO: top, right, bottom, left
  1274. IEComputed[WIDTH] = IEComputed[HEIGHT] = ComputedStyle.getOffset;
  1275. IEComputed.color = IEComputed.backgroundColor = ComputedStyle.getColor;
  1276. IEComputed[BORDER_TOP_WIDTH] = IEComputed[BORDER_RIGHT_WIDTH] =
  1277. IEComputed[BORDER_BOTTOM_WIDTH] = IEComputed[BORDER_LEFT_WIDTH] =
  1278. ComputedStyle.getBorderWidth;
  1279. IEComputed.marginTop = IEComputed.marginRight = IEComputed.marginBottom =
  1280. IEComputed.marginLeft = ComputedStyle.getMargin;
  1281. IEComputed.visibility = ComputedStyle.getVisibility;
  1282. IEComputed.borderColor = IEComputed.borderTopColor =
  1283. IEComputed.borderRightColor = IEComputed.borderBottomColor =
  1284. IEComputed.borderLeftColor = ComputedStyle.getBorderColor;
  1285. if (!Y.config.win[GET_COMPUTED_STYLE]) {
  1286. Y.DOM[GET_COMPUTED_STYLE] = ComputedStyle.get;
  1287. }
  1288. Y.namespace('DOM.IE');
  1289. Y.DOM.IE.COMPUTED = IEComputed;
  1290. Y.DOM.IE.ComputedStyle = ComputedStyle;
  1291. })(Y);
  1292. }, '@VERSION@' ,{skinnable:false, requires:['dom-base']});
  1293. YUI.add('dom-screen', function(Y) {
  1294. (fun