e7cc82280e0c2d310fe13df417489f8aea7f279d.svn-base 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. /*
  2. * Ext JS Library 2.0 Copyright(c) 2006-2007, Ext JS, LLC. licensing@extjs.com
  3. *
  4. * http://extjs.com/license
  5. */
  6. /*
  7. * Copyright (c) 2007, Yahoo! Inc. All rights reserved. Code licensed under the
  8. * BSD License: http://developer.yahoo.net/yui/license.txt version: 2.2.0
  9. */
  10. /*
  11. * Copyright (c) 2006, Yahoo! Inc. All rights reserved. Code licensed under the
  12. * BSD License: http://developer.yahoo.net/yui/license.txt
  13. */
  14. /**
  15. * The dom module provides helper methods for manipulating Dom elements.
  16. *
  17. * @module dom
  18. *
  19. */
  20. (function() {
  21. var Y = YAHOO.util, // internal shorthand
  22. getStyle, // for load time browser branching
  23. setStyle, // ditto
  24. id_counter = 0, // for use with generateId
  25. propertyCache = {}; // for faster hyphen converts
  26. // brower detection
  27. var ua = navigator.userAgent.toLowerCase(), isOpera = (ua.indexOf('opera') > -1), isSafari = (ua
  28. .indexOf('safari') > -1), isGecko = (!isOpera && !isSafari && ua
  29. .indexOf('gecko') > -1), isIE = (!isOpera && ua.indexOf('msie') > -1);
  30. // regex cache
  31. var patterns = {
  32. HYPHEN : /(-[a-z])/i
  33. };
  34. var toCamel = function(property) {
  35. if (!patterns.HYPHEN.test(property)) {
  36. return property; // no hyphens
  37. }
  38. if (propertyCache[property]) { // already converted
  39. return propertyCache[property];
  40. }
  41. while (patterns.HYPHEN.exec(property)) {
  42. property = property.replace(RegExp.$1, RegExp.$1.substr(1)
  43. .toUpperCase());
  44. }
  45. propertyCache[property] = property;
  46. return property;
  47. // return property.replace(/-([a-z])/gi, function(m0, m1) {return
  48. // m1.toUpperCase()}) // cant use function as 2nd arg yet due to safari
  49. // bug
  50. };
  51. // branching at load instead of runtime
  52. if (document.defaultView && document.defaultView.getComputedStyle) { // W3C
  53. // DOM
  54. // method
  55. getStyle = function(el, property) {
  56. var value = null;
  57. var computed = document.defaultView.getComputedStyle(el, '');
  58. if (computed) { // test computed before touching for safari
  59. value = computed[toCamel(property)];
  60. }
  61. return el.style[property] || value;
  62. };
  63. } else if (document.documentElement.currentStyle && isIE) { // IE method
  64. getStyle = function(el, property) {
  65. switch (toCamel(property)) {
  66. case 'opacity' :// IE opacity uses filter
  67. var val = 100;
  68. try { // will error if no DXImageTransform
  69. val = el.filters['DXImageTransform.Microsoft.Alpha'].opacity;
  70. } catch (e) {
  71. try { // make sure its in the document
  72. val = el.filters('alpha').opacity;
  73. } catch (e) {
  74. }
  75. }
  76. return val / 100;
  77. break;
  78. default :
  79. // test currentStyle before touching
  80. var value = el.currentStyle
  81. ? el.currentStyle[property]
  82. : null;
  83. return (el.style[property] || value);
  84. }
  85. };
  86. } else { // default to inline only
  87. getStyle = function(el, property) {
  88. return el.style[property];
  89. };
  90. }
  91. if (isIE) {
  92. setStyle = function(el, property, val) {
  93. switch (property) {
  94. case 'opacity' :
  95. if (typeof el.style.filter == 'string') { // in case not
  96. // appended
  97. el.style.filter = 'alpha(opacity=' + val * 100 + ')';
  98. if (!el.currentStyle || !el.currentStyle.hasLayout) {
  99. el.style.zoom = 1; // when no layout or cant tell
  100. }
  101. }
  102. break;
  103. default :
  104. el.style[property] = val;
  105. }
  106. };
  107. } else {
  108. setStyle = function(el, property, val) {
  109. el.style[property] = val;
  110. };
  111. }
  112. /**
  113. * Provides helper methods for DOM elements.
  114. *
  115. * @namespace YAHOO.util
  116. * @class Dom
  117. */
  118. YAHOO.util.Dom = {
  119. /**
  120. * Returns an HTMLElement reference.
  121. *
  122. * @method get
  123. * @param {String |
  124. * HTMLElement |Array} el Accepts a string to use as an ID
  125. * for getting a DOM reference, an actual DOM reference, or
  126. * an Array of IDs and/or HTMLElements.
  127. * @return {HTMLElement | Array} A DOM reference to an HTML element or
  128. * an array of HTMLElements.
  129. */
  130. get : function(el) {
  131. if (!el) {
  132. return null;
  133. } // nothing to work with
  134. if (typeof el != 'string' && !(el instanceof Array)) { // assuming
  135. // HTMLElement
  136. // or
  137. // HTMLCollection,
  138. // so pass
  139. // back as
  140. // is
  141. return el;
  142. }
  143. if (typeof el == 'string') { // ID
  144. return document.getElementById(el);
  145. } else { // array of ID's and/or elements
  146. var collection = [];
  147. for (var i = 0, len = el.length; i < len; ++i) {
  148. collection[collection.length] = Y.Dom.get(el[i]);
  149. }
  150. return collection;
  151. }
  152. return null; // safety, should never happen
  153. },
  154. /**
  155. * Normalizes currentStyle and ComputedStyle.
  156. *
  157. * @method getStyle
  158. * @param {String |
  159. * HTMLElement |Array} el Accepts a string to use as an ID,
  160. * an actual DOM reference, or an Array of IDs and/or
  161. * HTMLElements.
  162. * @param {String}
  163. * property The style property whose value is returned.
  164. * @return {String | Array} The current value of the style property for
  165. * the element(s).
  166. */
  167. getStyle : function(el, property) {
  168. property = toCamel(property);
  169. var f = function(element) {
  170. return getStyle(element, property);
  171. };
  172. return Y.Dom.batch(el, f, Y.Dom, true);
  173. },
  174. /**
  175. * Wrapper for setting style properties of HTMLElements. Normalizes
  176. * "opacity" across modern browsers.
  177. *
  178. * @method setStyle
  179. * @param {String |
  180. * HTMLElement | Array} el Accepts a string to use as an ID,
  181. * an actual DOM reference, or an Array of IDs and/or
  182. * HTMLElements.
  183. * @param {String}
  184. * property The style property to be set.
  185. * @param {String}
  186. * val The value to apply to the given property.
  187. */
  188. setStyle : function(el, property, val) {
  189. property = toCamel(property);
  190. var f = function(element) {
  191. setStyle(element, property, val);
  192. };
  193. Y.Dom.batch(el, f, Y.Dom, true);
  194. },
  195. /**
  196. * Gets the current position of an element based on page coordinates.
  197. * Element must be part of the DOM tree to have page coordinates
  198. * (display:none or elements not appended return false).
  199. *
  200. * @method getXY
  201. * @param {String |
  202. * HTMLElement | Array} el Accepts a string to use as an ID,
  203. * an actual DOM reference, or an Array of IDs and/or
  204. * HTMLElements
  205. * @return {Array} The XY position of the element(s)
  206. */
  207. getXY : function(el) {
  208. var f = function(el) {
  209. // has to be part of document to have pageXY
  210. if (el.parentNode === null || el.offsetParent === null
  211. || this.getStyle(el, 'display') == 'none') {
  212. return false;
  213. }
  214. var parentNode = null;
  215. var pos = [];
  216. var box;
  217. if (el.getBoundingClientRect) { // IE
  218. box = el.getBoundingClientRect();
  219. var doc = document;
  220. if (!this.inDocument(el) && parent.document != document) {// might
  221. // be
  222. // in a
  223. // frame,
  224. // need
  225. // to
  226. // get
  227. // its
  228. // scroll
  229. doc = parent.document;
  230. if (!this.isAncestor(doc.documentElement, el)) {
  231. return false;
  232. }
  233. }
  234. var scrollTop = Math.max(doc.documentElement.scrollTop,
  235. doc.body.scrollTop);
  236. var scrollLeft = Math.max(doc.documentElement.scrollLeft,
  237. doc.body.scrollLeft);
  238. return [box.left + scrollLeft, box.top + scrollTop];
  239. } else { // safari, opera, & gecko
  240. pos = [el.offsetLeft, el.offsetTop];
  241. parentNode = el.offsetParent;
  242. if (parentNode != el) {
  243. while (parentNode) {
  244. pos[0] += parentNode.offsetLeft;
  245. pos[1] += parentNode.offsetTop;
  246. parentNode = parentNode.offsetParent;
  247. }
  248. }
  249. if (isSafari && this.getStyle(el, 'position') == 'absolute') { // safari
  250. // doubles
  251. // in
  252. // some
  253. // cases
  254. pos[0] -= document.body.offsetLeft;
  255. pos[1] -= document.body.offsetTop;
  256. }
  257. }
  258. if (el.parentNode) {
  259. parentNode = el.parentNode;
  260. } else {
  261. parentNode = null;
  262. }
  263. while (parentNode && parentNode.tagName.toUpperCase() != 'BODY'
  264. && parentNode.tagName.toUpperCase() != 'HTML') { // account
  265. // for
  266. // any
  267. // scrolled
  268. // ancestors
  269. if (Y.Dom.getStyle(parentNode, 'display') != 'inline') { // work
  270. // around
  271. // opera
  272. // inline
  273. // scrollLeft/Top
  274. // bug
  275. pos[0] -= parentNode.scrollLeft;
  276. pos[1] -= parentNode.scrollTop;
  277. }
  278. if (parentNode.parentNode) {
  279. parentNode = parentNode.parentNode;
  280. } else {
  281. parentNode = null;
  282. }
  283. }
  284. return pos;
  285. };
  286. return Y.Dom.batch(el, f, Y.Dom, true);
  287. },
  288. /**
  289. * Gets the current X position of an element based on page coordinates.
  290. * The element must be part of the DOM tree to have page coordinates
  291. * (display:none or elements not appended return false).
  292. *
  293. * @method getX
  294. * @param {String |
  295. * HTMLElement | Array} el Accepts a string to use as an ID,
  296. * an actual DOM reference, or an Array of IDs and/or
  297. * HTMLElements
  298. * @return {String | Array} The X position of the element(s)
  299. */
  300. getX : function(el) {
  301. var f = function(el) {
  302. return Y.Dom.getXY(el)[0];
  303. };
  304. return Y.Dom.batch(el, f, Y.Dom, true);
  305. },
  306. /**
  307. * Gets the current Y position of an element based on page coordinates.
  308. * Element must be part of the DOM tree to have page coordinates
  309. * (display:none or elements not appended return false).
  310. *
  311. * @method getY
  312. * @param {String |
  313. * HTMLElement | Array} el Accepts a string to use as an ID,
  314. * an actual DOM reference, or an Array of IDs and/or
  315. * HTMLElements
  316. * @return {String | Array} The Y position of the element(s)
  317. */
  318. getY : function(el) {
  319. var f = function(el) {
  320. return Y.Dom.getXY(el)[1];
  321. };
  322. return Y.Dom.batch(el, f, Y.Dom, true);
  323. },
  324. /**
  325. * Set the position of an html element in page coordinates, regardless
  326. * of how the element is positioned. The element(s) must be part of the
  327. * DOM tree to have page coordinates (display:none or elements not
  328. * appended return false).
  329. *
  330. * @method setXY
  331. * @param {String |
  332. * HTMLElement | Array} el Accepts a string to use as an ID,
  333. * an actual DOM reference, or an Array of IDs and/or
  334. * HTMLElements
  335. * @param {Array}
  336. * pos Contains X & Y values for new position (coordinates
  337. * are page-based)
  338. * @param {Boolean}
  339. * noRetry By default we try and set the position a second
  340. * time if the first fails
  341. */
  342. setXY : function(el, pos, noRetry) {
  343. var f = function(el) {
  344. var style_pos = this.getStyle(el, 'position');
  345. if (style_pos == 'static') { // default to relative
  346. this.setStyle(el, 'position', 'relative');
  347. style_pos = 'relative';
  348. }
  349. var pageXY = this.getXY(el);
  350. if (pageXY === false) { // has to be part of doc to have pageXY
  351. return false;
  352. }
  353. var delta = [ // assuming pixels; if not we will have to retry
  354. parseInt(this.getStyle(el, 'left'), 10),
  355. parseInt(this.getStyle(el, 'top'), 10)];
  356. if (isNaN(delta[0])) {// in case of 'auto'
  357. delta[0] = (style_pos == 'relative') ? 0 : el.offsetLeft;
  358. }
  359. if (isNaN(delta[1])) { // in case of 'auto'
  360. delta[1] = (style_pos == 'relative') ? 0 : el.offsetTop;
  361. }
  362. if (pos[0] !== null) {
  363. el.style.left = pos[0] - pageXY[0] + delta[0] + 'px';
  364. }
  365. if (pos[1] !== null) {
  366. el.style.top = pos[1] - pageXY[1] + delta[1] + 'px';
  367. }
  368. if (!noRetry) {
  369. var newXY = this.getXY(el);
  370. // if retry is true, try one more time if we miss
  371. if ((pos[0] !== null && newXY[0] != pos[0])
  372. || (pos[1] !== null && newXY[1] != pos[1])) {
  373. this.setXY(el, pos, true);
  374. }
  375. }
  376. };
  377. Y.Dom.batch(el, f, Y.Dom, true);
  378. },
  379. /**
  380. * Set the X position of an html element in page coordinates, regardless
  381. * of how the element is positioned. The element must be part of the DOM
  382. * tree to have page coordinates (display:none or elements not appended
  383. * return false).
  384. *
  385. * @method setX
  386. * @param {String |
  387. * HTMLElement | Array} el Accepts a string to use as an ID,
  388. * an actual DOM reference, or an Array of IDs and/or
  389. * HTMLElements.
  390. * @param {Int}
  391. * x The value to use as the X coordinate for the element(s).
  392. */
  393. setX : function(el, x) {
  394. Y.Dom.setXY(el, [x, null]);
  395. },
  396. /**
  397. * Set the Y position of an html element in page coordinates, regardless
  398. * of how the element is positioned. The element must be part of the DOM
  399. * tree to have page coordinates (display:none or elements not appended
  400. * return false).
  401. *
  402. * @method setY
  403. * @param {String |
  404. * HTMLElement | Array} el Accepts a string to use as an ID,
  405. * an actual DOM reference, or an Array of IDs and/or
  406. * HTMLElements.
  407. * @param {Int}
  408. * x To use as the Y coordinate for the element(s).
  409. */
  410. setY : function(el, y) {
  411. Y.Dom.setXY(el, [null, y]);
  412. },
  413. /**
  414. * Returns the region position of the given element. The element must be
  415. * part of the DOM tree to have a region (display:none or elements not
  416. * appended return false).
  417. *
  418. * @method getRegion
  419. * @param {String |
  420. * HTMLElement | Array} el Accepts a string to use as an ID,
  421. * an actual DOM reference, or an Array of IDs and/or
  422. * HTMLElements.
  423. * @return {Region | Array} A Region or array of Region instances
  424. * containing "top, left, bottom, right" member data.
  425. */
  426. getRegion : function(el) {
  427. var f = function(el) {
  428. var region = new Y.Region.getRegion(el);
  429. return region;
  430. };
  431. return Y.Dom.batch(el, f, Y.Dom, true);
  432. },
  433. /**
  434. * Returns the width of the client (viewport).
  435. *
  436. * @method getClientWidth
  437. * @deprecated Now using getViewportWidth. This interface left intact
  438. * for back compat.
  439. * @return {Int} The width of the viewable area of the page.
  440. */
  441. getClientWidth : function() {
  442. return Y.Dom.getViewportWidth();
  443. },
  444. /**
  445. * Returns the height of the client (viewport).
  446. *
  447. * @method getClientHeight
  448. * @deprecated Now using getViewportHeight. This interface left intact
  449. * for back compat.
  450. * @return {Int} The height of the viewable area of the page.
  451. */
  452. getClientHeight : function() {
  453. return Y.Dom.getViewportHeight();
  454. },
  455. /**
  456. * Returns a array of HTMLElements with the given class. For optimized
  457. * performance, include a tag and/or root node when possible.
  458. *
  459. * @method getElementsByClassName
  460. * @param {String}
  461. * className The class name to match against
  462. * @param {String}
  463. * tag (optional) The tag name of the elements being
  464. * collected
  465. * @param {String |
  466. * HTMLElement} root (optional) The HTMLElement or an ID to
  467. * use as the starting point
  468. * @return {Array} An array of elements that have the given class name
  469. */
  470. getElementsByClassName : function(className, tag, root) {
  471. var method = function(el) {
  472. return Y.Dom.hasClass(el, className);
  473. };
  474. return Y.Dom.getElementsBy(method, tag, root);
  475. },
  476. /**
  477. * Determines whether an HTMLElement has the given className.
  478. *
  479. * @method hasClass
  480. * @param {String |
  481. * HTMLElement | Array} el The element or collection to test
  482. * @param {String}
  483. * className the class name to search for
  484. * @return {Boolean | Array} A boolean value or array of boolean values
  485. */
  486. hasClass : function(el, className) {
  487. var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)');
  488. var f = function(el) {
  489. return re.test(el['className']);
  490. };
  491. return Y.Dom.batch(el, f, Y.Dom, true);
  492. },
  493. /**
  494. * Adds a class name to a given element or collection of elements.
  495. *
  496. * @method addClass
  497. * @param {String |
  498. * HTMLElement | Array} el The element or collection to add
  499. * the class to
  500. * @param {String}
  501. * className the class name to add to the class attribute
  502. */
  503. addClass : function(el, className) {
  504. var f = function(el) {
  505. if (this.hasClass(el, className)) {
  506. return;
  507. } // already present
  508. el['className'] = [el['className'], className].join(' ');
  509. };
  510. Y.Dom.batch(el, f, Y.Dom, true);
  511. },
  512. /**
  513. * Removes a class name from a given element or collection of elements.
  514. *
  515. * @method removeClass
  516. * @param {String |
  517. * HTMLElement | Array} el The element or collection to
  518. * remove the class from
  519. * @param {String}
  520. * className the class name to remove from the class
  521. * attribute
  522. */
  523. removeClass : function(el, className) {
  524. var re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', 'g');
  525. var f = function(el) {
  526. if (!this.hasClass(el, className)) {
  527. return;
  528. } // not present
  529. var c = el['className'];
  530. el['className'] = c.replace(re, ' ');
  531. if (this.hasClass(el, className)) { // in case of multiple
  532. // adjacent
  533. this.removeClass(el, className);
  534. }
  535. };
  536. Y.Dom.batch(el, f, Y.Dom, true);
  537. },
  538. /**
  539. * Replace a class with another class for a given element or collection
  540. * of elements. If no oldClassName is present, the newClassName is
  541. * simply added.
  542. *
  543. * @method replaceClass
  544. * @param {String |
  545. * HTMLElement | Array} el The element or collection to
  546. * remove the class from
  547. * @param {String}
  548. * oldClassName the class name to be replaced
  549. * @param {String}
  550. * newClassName the class name that will be replacing the old
  551. * class name
  552. */
  553. replaceClass : function(el, oldClassName, newClassName) {
  554. if (oldClassName === newClassName) { // avoid infinite loop
  555. return false;
  556. }
  557. var re = new RegExp('(?:^|\\s+)' + oldClassName + '(?:\\s+|$)', 'g');
  558. var f = function(el) {
  559. if (!this.hasClass(el, oldClassName)) {
  560. this.addClass(el, newClassName); // just add it if
  561. // nothing to replace
  562. return; // note return
  563. }
  564. el['className'] = el['className'].replace(re, ' '
  565. + newClassName + ' ');
  566. if (this.hasClass(el, oldClassName)) { // in case of multiple
  567. // adjacent
  568. this.replaceClass(el, oldClassName, newClassName);
  569. }
  570. };
  571. Y.Dom.batch(el, f, Y.Dom, true);
  572. },
  573. /**
  574. * Generates a unique ID
  575. *
  576. * @method generateId
  577. * @param {String |
  578. * HTMLElement | Array} el (optional) An optional element
  579. * array of elements to add an ID to (no ID is added if one
  580. * is already present).
  581. * @param {String}
  582. * prefix (optional) an optional prefix to use (defaults to
  583. * "yui-gen").
  584. * @return {String | Array} The generated ID, or array of generated IDs
  585. * (or original ID if already present on an element)
  586. */
  587. generateId : function(el, prefix) {
  588. prefix = prefix || 'yui-gen';
  589. el = el || {};
  590. var f = function(el) {
  591. if (el) {
  592. el = Y.Dom.get(el);
  593. } else {
  594. el = {}; // just generating ID in this case
  595. }
  596. if (!el.id) {
  597. el.id = prefix + id_counter++;
  598. } // dont override existing
  599. return el.id;
  600. };
  601. return Y.Dom.batch(el, f, Y.Dom, true);
  602. },
  603. /**
  604. * Determines whether an HTMLElement is an ancestor of another HTML
  605. * element in the DOM hierarchy.
  606. *
  607. * @method isAncestor
  608. * @param {String |
  609. * HTMLElement} haystack The possible ancestor
  610. * @param {String |
  611. * HTMLElement} needle The possible descendent
  612. * @return {Boolean} Whether or not the haystack is an ancestor of
  613. * needle
  614. */
  615. isAncestor : function(haystack, needle) {
  616. haystack = Y.Dom.get(haystack);
  617. if (!haystack || !needle) {
  618. return false;
  619. }
  620. var f = function(needle) {
  621. if (haystack.contains && !isSafari) { // safari "contains" is
  622. // broken
  623. return haystack.contains(needle);
  624. } else if (haystack.compareDocumentPosition) {
  625. return !!(haystack.compareDocumentPosition(needle) & 16);
  626. } else { // loop up and test each parent
  627. var parent = needle.parentNode;
  628. while (parent) {
  629. if (parent == haystack) {
  630. return true;
  631. } else if (!parent.tagName
  632. || parent.tagName.toUpperCase() == 'HTML') {
  633. return false;
  634. }
  635. parent = parent.parentNode;
  636. }
  637. return false;
  638. }
  639. };
  640. return Y.Dom.batch(needle, f, Y.Dom, true);
  641. },
  642. /**
  643. * Determines whether an HTMLElement is present in the current document.
  644. *
  645. * @method inDocument
  646. * @param {String |
  647. * HTMLElement} el The element to search for
  648. * @return {Boolean} Whether or not the element is present in the
  649. * current document
  650. */
  651. inDocument : function(el) {
  652. var f = function(el) {
  653. return this.isAncestor(document.documentElement, el);
  654. };
  655. return Y.Dom.batch(el, f, Y.Dom, true);
  656. },
  657. /**
  658. * Returns a array of HTMLElements that pass the test applied by
  659. * supplied boolean method. For optimized performance, include a tag
  660. * and/or root node when possible.
  661. *
  662. * @method getElementsBy
  663. * @param {Function}
  664. * method - A boolean method for testing elements which
  665. * receives the element as its only argument.
  666. *
  667. * @param {String}
  668. * tag (optional) The tag name of the elements being
  669. * collected
  670. * @param {String |
  671. * HTMLElement} root (optional) The HTMLElement or an ID to
  672. * use as the starting point
  673. * @return {Array} Array of HTMLElements
  674. */
  675. getElementsBy : function(method, tag, root) {
  676. tag = tag || '*';
  677. var nodes = [];
  678. if (root) {
  679. root = Y.Dom.get(root);
  680. if (!root) { // if no root node, then no children
  681. return nodes;
  682. }
  683. } else {
  684. root = document;
  685. }
  686. var elements = root.getElementsByTagName(tag);
  687. if (!elements.length && (tag == '*' && root.all)) {
  688. elements = root.all; // IE < 6
  689. }
  690. for (var i = 0, len = elements.length; i < len; ++i) {
  691. if (method(elements[i])) {
  692. nodes[nodes.length] = elements[i];
  693. }
  694. }
  695. return nodes;
  696. },
  697. /**
  698. * Returns an array of elements that have had the supplied method
  699. * applied. The method is called with the element(s) as the first arg,
  700. * and the optional param as the second ( method(el, o) ).
  701. *
  702. * @method batch
  703. * @param {String |
  704. * HTMLElement | Array} el (optional) An element or array of
  705. * elements to apply the method to
  706. * @param {Function}
  707. * method The method to apply to the element(s)
  708. * @param {Any}
  709. * o (optional) An optional arg that is passed to the
  710. * supplied method
  711. * @param {Boolean}
  712. * override (optional) Whether or not to override the scope
  713. * of "method" with "o"
  714. * @return {HTMLElement | Array} The element(s) with the method applied
  715. */
  716. batch : function(el, method, o, override) {
  717. var id = el;
  718. el = Y.Dom.get(el);
  719. var scope = (override) ? o : window;
  720. if (!el || el.tagName || !el.length) { // is null or not a
  721. // collection (tagName for
  722. // SELECT and others that
  723. // can be both an element
  724. // and a collection)
  725. if (!el) {
  726. return false;
  727. }
  728. return method.call(scope, el, o);
  729. }
  730. var collection = [];
  731. for (var i = 0, len = el.length; i < len; ++i) {
  732. if (!el[i]) {
  733. id = el[i];
  734. }
  735. collection[collection.length] = method.call(scope, el[i], o);
  736. }
  737. return collection;
  738. },
  739. /**
  740. * Returns the height of the document.
  741. *
  742. * @method getDocumentHeight
  743. * @return {Int} The height of the actual document (which includes the
  744. * body and its margin).
  745. */
  746. getDocumentHeight : function() {
  747. var scrollHeight = (document.compatMode != 'CSS1Compat')
  748. ? document.body.scrollHeight
  749. : document.documentElement.scrollHeight;
  750. var h = Math.max(scrollHeight, Y.Dom.getViewportHeight());
  751. return h;
  752. },
  753. /**
  754. * Returns the width of the document.
  755. *
  756. * @method getDocumentWidth
  757. * @return {Int} The width of the actual document (which includes the
  758. * body and its margin).
  759. */
  760. getDocumentWidth : function() {
  761. var scrollWidth = (document.compatMode != 'CSS1Compat')
  762. ? document.body.scrollWidth
  763. : document.documentElement.scrollWidth;
  764. var w = Math.max(scrollWidth, Y.Dom.getViewportWidth());
  765. return w;
  766. },
  767. /**
  768. * Returns the current height of the viewport.
  769. *
  770. * @method getViewportHeight
  771. * @return {Int} The height of the viewable area of the page (excludes
  772. * scrollbars).
  773. */
  774. getViewportHeight : function() {
  775. var height = self.innerHeight; // Safari, Opera
  776. var mode = document.compatMode;
  777. if ((mode || isIE) && !isOpera) { // IE, Gecko
  778. height = (mode == 'CSS1Compat')
  779. ? document.documentElement.clientHeight
  780. : // Standards
  781. document.body.clientHeight; // Quirks
  782. }
  783. return height;
  784. },
  785. /**
  786. * Returns the current width of the viewport.
  787. *
  788. * @method getViewportWidth
  789. * @return {Int} The width of the viewable area of the page (excludes
  790. * scrollbars).
  791. */
  792. getViewportWidth : function() {
  793. var width = self.innerWidth; // Safari
  794. var mode = document.compatMode;
  795. if (mode || isIE) { // IE, Gecko, Opera
  796. width = (mode == 'CSS1Compat')
  797. ? document.documentElement.clientWidth
  798. : // Standards
  799. document.body.clientWidth; // Quirks
  800. }
  801. return width;
  802. }
  803. };
  804. })();
  805. /**
  806. * A region is a representation of an object on a grid. It is defined by the
  807. * top, right, bottom, left extents, so is rectangular by default. If other
  808. * shapes are required, this class could be extended to support it.
  809. *
  810. * @namespace YAHOO.util
  811. * @class Region
  812. * @param {Int}
  813. * t the top extent
  814. * @param {Int}
  815. * r the right extent
  816. * @param {Int}
  817. * b the bottom extent
  818. * @param {Int}
  819. * l the left extent
  820. * @constructor
  821. */
  822. YAHOO.util.Region = function(t, r, b, l) {
  823. /**
  824. * The region's top extent
  825. *
  826. * @property top
  827. * @type Int
  828. */
  829. this.top = t;
  830. /**
  831. * The region's top extent as index, for symmetry with set/getXY
  832. *
  833. * @property 1
  834. * @type Int
  835. */
  836. this[1] = t;
  837. /**
  838. * The region's right extent
  839. *
  840. * @property right
  841. * @type int
  842. */
  843. this.right = r;
  844. /**
  845. * The region's bottom extent
  846. *
  847. * @property bottom
  848. * @type Int
  849. */
  850. this.bottom = b;
  851. /**
  852. * The region's left extent
  853. *
  854. * @property left
  855. * @type Int
  856. */
  857. this.left = l;
  858. /**
  859. * The region's left extent as index, for symmetry with set/getXY
  860. *
  861. * @property 0
  862. * @type Int
  863. */
  864. this[0] = l;
  865. };
  866. /**
  867. * Returns true if this region contains the region passed in
  868. *
  869. * @method contains
  870. * @param {Region}
  871. * region The region to evaluate
  872. * @return {Boolean} True if the region is contained with this region, else
  873. * false
  874. */
  875. YAHOO.util.Region.prototype.contains = function(region) {
  876. return (region.left >= this.left && region.right <= this.right
  877. && region.top >= this.top && region.bottom <= this.bottom);
  878. };
  879. /**
  880. * Returns the area of the region
  881. *
  882. * @method getArea
  883. * @return {Int} the region's area
  884. */
  885. YAHOO.util.Region.prototype.getArea = function() {
  886. return ((this.bottom - this.top) * (this.right - this.left));
  887. };
  888. /**
  889. * Returns the region where the passed in region overlaps with this one
  890. *
  891. * @method intersect
  892. * @param {Region}
  893. * region The region that intersects
  894. * @return {Region} The overlap region, or null if there is no overlap
  895. */
  896. YAHOO.util.Region.prototype.intersect = function(region) {
  897. var t = Math.max(this.top, region.top);
  898. var r = Math.min(this.right, region.right);
  899. var b = Math.min(this.bottom, region.bottom);
  900. var l = Math.max(this.left, region.left);
  901. if (b >= t && r >= l) {
  902. return new YAHOO.util.Region(t, r, b, l);
  903. } else {
  904. return null;
  905. }
  906. };
  907. /**
  908. * Returns the region representing the smallest region that can contain both the
  909. * passed in region and this region.
  910. *
  911. * @method union
  912. * @param {Region}
  913. * region The region that to create the union with
  914. * @return {Region} The union region
  915. */
  916. YAHOO.util.Region.prototype.union = function(region) {
  917. var t = Math.min(this.top, region.top);
  918. var r = Math.max(this.right, region.right);
  919. var b = Math.max(this.bottom, region.bottom);
  920. var l = Math.min(this.left, region.left);
  921. return new YAHOO.util.Region(t, r, b, l);
  922. };
  923. /**
  924. * toString
  925. *
  926. * @method toString
  927. * @return string the region properties
  928. */
  929. YAHOO.util.Region.prototype.toString = function() {
  930. return ("Region {" + "top: " + this.top + ", right: " + this.right
  931. + ", bottom: " + this.bottom + ", left: " + this.left + "}");
  932. };
  933. /**
  934. * Returns a region that is occupied by the DOM element
  935. *
  936. * @method getRegion
  937. * @param {HTMLElement}
  938. * el The element
  939. * @return {Region} The region that the element occupies
  940. * @static
  941. */
  942. YAHOO.util.Region.getRegion = function(el) {
  943. var p = YAHOO.util.Dom.getXY(el);
  944. var t = p[1];
  945. var r = p[0] + el.offsetWidth;
  946. var b = p[1] + el.offsetHeight;
  947. var l = p[0];
  948. return new YAHOO.util.Region(t, r, b, l);
  949. };
  950. // ///////////////////////////////////////////////////////////////////////////
  951. /**
  952. * A point is a region that is special in that it represents a single point on
  953. * the grid.
  954. *
  955. * @namespace YAHOO.util
  956. * @class Point
  957. * @param {Int}
  958. * x The X position of the point
  959. * @param {Int}
  960. * y The Y position of the point
  961. * @constructor
  962. * @extends YAHOO.util.Region
  963. */
  964. YAHOO.util.Point = function(x, y) {
  965. if (x instanceof Array) { // accept output from Dom.getXY
  966. y = x[1];
  967. x = x[0];
  968. }
  969. /**
  970. * The X position of the point, which is also the right, left and index zero
  971. * (for Dom.getXY symmetry)
  972. *
  973. * @property x
  974. * @type Int
  975. */
  976. this.x = this.right = this.left = this[0] = x;
  977. /**
  978. * The Y position of the point, which is also the top, bottom and index one
  979. * (for Dom.getXY symmetry)
  980. *
  981. * @property y
  982. * @type Int
  983. */
  984. this.y = this.top = this.bottom = this[1] = y;
  985. };
  986. YAHOO.util.Point.prototype = new YAHOO.util.Region();
  987. YAHOO.register("dom", YAHOO.util.Dom, {
  988. version : "2.2.0",
  989. build : "127"
  990. });