Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

aui-node-base.js 35KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630
  1. AUI.add('aui-node-base', function(A) {
  2. /**
  3. * aui-node-base A set of utility methods to the Node.
  4. *
  5. * @module aui-node
  6. * @submodule aui-node-base
  7. */
  8. var Lang = A.Lang,
  9. isArray = Lang.isArray,
  10. isFunction = Lang.isFunction,
  11. isObject = Lang.isObject,
  12. isString = Lang.isString,
  13. isUndefined = Lang.isUndefined,
  14. isValue = Lang.isValue,
  15. AArray = A.Array,
  16. Node = A.Node,
  17. NodeList = A.NodeList,
  18. getClassName = A.getClassName,
  19. getRegExp = A.DOM._getRegExp,
  20. prefix = Lang.String.prefix,
  21. CONFIG = A.config,
  22. DOC = CONFIG.doc,
  23. WIN = CONFIG.win,
  24. NODE_PROTO = Node.prototype,
  25. NODELIST_PROTO = NodeList.prototype,
  26. STR_EMPTY = '',
  27. ARRAY_EMPTY_STRINGS = [STR_EMPTY, STR_EMPTY],
  28. HELPER = 'helper',
  29. OFFSET = 'offset',
  30. CSS_HELPER_FORCE_OFFSET = getClassName(HELPER, 'force', OFFSET),
  31. CSS_HELPER_HIDDEN = getClassName(HELPER, 'hidden'),
  32. CSS_HELPER_UNSELECTABLE = getClassName(HELPER, 'unselectable'),
  33. CHILD_NODES = 'childNodes',
  34. CREATE_DOCUMENT_FRAGMENT = 'createDocumentFragment',
  35. INNER = 'inner',
  36. INNER_HTML = 'innerHTML',
  37. NEXT_SIBLING = 'nextSibling',
  38. NONE = 'none',
  39. OUTER = 'outer',
  40. PARENT_NODE = 'parentNode',
  41. REGION = 'region',
  42. SCRIPT = 'script',
  43. SUPPORT_CLONED_EVENTS = false,
  44. VALUE = 'value',
  45. MAP_BORDER = {
  46. b: 'borderBottomWidth',
  47. l: 'borderLeftWidth',
  48. r: 'borderRightWidth',
  49. t: 'borderTopWidth'
  50. },
  51. MAP_MARGIN = {
  52. b: 'marginBottom',
  53. l: 'marginLeft',
  54. r: 'marginRight',
  55. t: 'marginTop'
  56. },
  57. MAP_PADDING = {
  58. b: 'paddingBottom',
  59. l: 'paddingLeft',
  60. r: 'paddingRight',
  61. t: 'paddingTop'
  62. },
  63. prefixSelector = function(ns, id) {
  64. return '#' + prefix(ns, id);
  65. },
  66. formatSelectorNS = function(ns, selector) {
  67. return selector.replace(getRegExp('(#|\\[id=(\\\"|\\\'))(?!' + ns + ')', 'g'), '$1' + ns);
  68. };
  69. /*
  70. Parts of this file are used from jQuery (http://jquery.com)
  71. Dual-licensed under MIT/GPL
  72. */
  73. var div = DOC.createElement('div');
  74. div.style.display = 'none';
  75. div.innerHTML = ' <table></table>&nbsp;';
  76. if (div.attachEvent && div.fireEvent) {
  77. div.attachEvent(
  78. 'onclick',
  79. function(){
  80. SUPPORT_CLONED_EVENTS = true;
  81. div.detachEvent('onclick', arguments.callee);
  82. }
  83. );
  84. div.cloneNode(true).fireEvent('onclick');
  85. }
  86. var SUPPORT_OPTIONAL_TBODY = !div.getElementsByTagName('tbody').length;
  87. var REGEX_LEADING_WHITE_SPACE = /^\s+/,
  88. REGEX_IE8_ACTION = /=([^=\x27\x22>\s]+\/)>/g,
  89. REGEX_TAGNAME = /<([\w:]+)/;
  90. div = null;
  91. Node.cssId = prefixSelector;
  92. Node.formatSelectorNS = formatSelectorNS;
  93. /**
  94. * Augment the <a href="Node.html">YUI3 Node</a> with more util methods.
  95. *
  96. * Check the list of <a href="Node.html#methods">Methods</a> available for
  97. * AUI Node.
  98. *
  99. * @class A.Node
  100. * @constructor
  101. * @uses Node
  102. */
  103. A.mix(NODE_PROTO, {
  104. allNS: function(ns, selector) {
  105. var instance = this;
  106. return instance.all(formatSelectorNS(ns, selector));
  107. },
  108. /**
  109. * <p>Returns the current ancestors of the node element. If a selector is
  110. * specified, the ancestors are filtered to match the selector.</p>
  111. *
  112. * Example:
  113. *
  114. * <pre><code>
  115. * A.one('#nodeId').ancestors('div');
  116. * </code></pre>
  117. *
  118. * @method ancestors
  119. * @param {String} selector A selector to filter the ancestor elements against.
  120. * @return {NodeList}
  121. */
  122. ancestors: function(selector) {
  123. var instance = this;
  124. var ancestors = [];
  125. var currentEl = instance.getDOM();
  126. while (currentEl && currentEl.nodeType !== 9) {
  127. if (currentEl.nodeType === 1) {
  128. ancestors.push(currentEl);
  129. }
  130. currentEl = currentEl.parentNode;
  131. }
  132. var nodeList = new A.all(ancestors);
  133. if (selector) {
  134. nodeList = nodeList.filter(selector);
  135. }
  136. return nodeList;
  137. },
  138. /**
  139. * <p>Returns the current ancestors of the node element filtered by a className.
  140. * This is an optimized method for finding ancestors by a specific CSS class name.</p>
  141. *
  142. * Example:
  143. *
  144. * <pre><code>
  145. * A.one('#nodeId').ancestorsByClassName('aui-helper-hidden');
  146. * </code></pre>
  147. *
  148. * @method ancestors
  149. * @param {String} selector A selector to filter the ancestor elements against.
  150. * @return {NodeList}
  151. */
  152. ancestorsByClassName: function(className) {
  153. var instance = this;
  154. var ancestors = [];
  155. var cssRE = new RegExp('\\b' + className + '\\b');
  156. var currentEl = instance.getDOM();
  157. while (currentEl && currentEl.nodeType !== 9) {
  158. if (currentEl.nodeType === 1 && cssRE.test(currentEl.className)) {
  159. ancestors.push(currentEl);
  160. }
  161. currentEl = currentEl.parentNode;
  162. }
  163. return A.all(ancestors);
  164. },
  165. /**
  166. * <p>Insert the node instance to the end of the <code>selector</code>
  167. * element.</p>
  168. *
  169. * Example:
  170. *
  171. * <pre><code>var node = A.one('#nodeId');
  172. * // using another Node instance
  173. * var body = A.one('body');
  174. * node.appendTo(body);
  175. * // using a CSS selector
  176. * node.appendTo('#container');
  177. * </code></pre>
  178. *
  179. * @method appendTo
  180. * @chainable
  181. * @param {Node | String} selector A selector, element, HTML string, Node
  182. * @return {String}
  183. */
  184. appendTo: function(selector) {
  185. var instance = this;
  186. A.one(selector).append(instance);
  187. return instance;
  188. },
  189. /**
  190. * <p>Get or Set the value of an attribute for the first element in the
  191. * set of matched elements. If only the <code>name</code> is passed it
  192. * works as a getter.</p>
  193. *
  194. * Example:
  195. *
  196. * <pre><code>var node = A.one('#nodeId');
  197. * node.attr('title', 'Setting a new title attribute');
  198. * // Alert the value of the title attribute: 'Setting a new title attribute'
  199. * alert( node.attr('title') );
  200. * </code></pre>
  201. *
  202. * @method attr
  203. * @param {String} name The name of the attribute
  204. * @param {String} value The value of the attribute to be set. Optional.
  205. * @return {String}
  206. */
  207. attr: function(name, value) {
  208. var instance = this;
  209. if (!isUndefined(value)) {
  210. var el = instance.getDOM();
  211. if (name in el) {
  212. instance.set(name, value);
  213. }
  214. else {
  215. instance.setAttribute(name, value);
  216. }
  217. return instance;
  218. }
  219. else {
  220. if (isObject(name)) {
  221. for (var i in name) {
  222. instance.attr(i, name[i]);
  223. }
  224. return instance;
  225. }
  226. var currentValue = instance.get(name);
  227. if (!Lang.isValue(currentValue)) {
  228. currentValue = instance.getAttribute(name);
  229. }
  230. return currentValue;
  231. }
  232. },
  233. /**
  234. * Normalizes the behavior of cloning a node, which by default should not clone
  235. * the events that are attached to it.
  236. *
  237. * Example:
  238. *
  239. * <pre><code>var node = A.one('#nodeId');
  240. * node.clone().appendTo('body');
  241. * </code></pre>
  242. *
  243. * @method clone
  244. * @return {Node}
  245. */
  246. clone: (function() {
  247. var clone;
  248. if (SUPPORT_CLONED_EVENTS) {
  249. clone = function() {
  250. var el = this.getDOM();
  251. var clone;
  252. if (el.nodeType != 3) {
  253. var outerHTML = this.outerHTML();
  254. outerHTML = outerHTML.replace(REGEX_IE8_ACTION, '="$1">').replace(REGEX_LEADING_WHITE_SPACE, STR_EMPTY);
  255. clone = Node.create(outerHTML);
  256. }
  257. else {
  258. clone = A.one(el.cloneNode());
  259. }
  260. return clone;
  261. };
  262. }
  263. else {
  264. clone = function() {
  265. return this.cloneNode(true);
  266. };
  267. }
  268. return clone;
  269. })(),
  270. /**
  271. * <p>Centralize the current Node instance with the passed
  272. * <code>val</code> Array, Node, String, or Region, if not specified, the body will be
  273. * used.</p>
  274. *
  275. * Example:
  276. *
  277. * <pre><code>var node = A.one('#nodeId');
  278. * // Center the <code>node</code> with the <code>#container</code>.
  279. * node.center('#container');
  280. * </code></pre>
  281. *
  282. * @method center
  283. * @chainable
  284. * @param {Array | Node | Region | String} val Array, Node, String, or Region to center with
  285. */
  286. center: function(val) {
  287. var instance = this,
  288. nodeRegion = instance.get(REGION),
  289. x,
  290. y;
  291. if (isArray(val)) {
  292. x = val[0];
  293. y = val[1];
  294. }
  295. else {
  296. var region;
  297. if (isObject(val) && !A.instanceOf(val, A.Node)) {
  298. region = val;
  299. }
  300. else {
  301. region = (A.one(val) || A.getBody()).get(REGION);
  302. }
  303. x = region.left + (region.width / 2);
  304. y = region.top + (region.height / 2);
  305. }
  306. instance.setXY([x - (nodeRegion.width / 2), y - (nodeRegion.height / 2)]);
  307. },
  308. /**
  309. * <p>This method removes not only child (and other descendant) elements,
  310. * but also any text within the set of matched elements. This is because,
  311. * according to the DOM specification, any string of text within an element
  312. * is considered a child node of that element.</p>
  313. *
  314. * Example:
  315. *
  316. * <pre><code>var node = A.one('#nodeId');
  317. * node.empty();
  318. * </code></pre>
  319. *
  320. * @method empty
  321. * @chainable
  322. */
  323. empty: function() {
  324. var instance = this;
  325. instance.all('>*').remove().purge();
  326. var el = Node.getDOMNode(instance);
  327. while (el.firstChild) {
  328. el.removeChild(el.firstChild);
  329. }
  330. return instance;
  331. },
  332. /**
  333. * Retrieves the DOM node bound to a Node instance. See
  334. * <a href="Node.html#method_getDOMNode">getDOMNode</a>.
  335. *
  336. * @method getDOM
  337. * @return {HTMLNode} The DOM node bound to the Node instance.
  338. */
  339. getDOM: function() {
  340. var instance = this;
  341. return Node.getDOMNode(instance);
  342. },
  343. /**
  344. * Return the combined width of the border for the specified sides.
  345. *
  346. * @method getBorderWidth
  347. * @param {string} sides Can be t, r, b, l or any combination of
  348. * those to represent the top, right, bottom, or left sides.
  349. * @return {number}
  350. */
  351. getBorderWidth: function(sides) {
  352. var instance = this;
  353. return instance._getBoxStyleAsNumber(sides, MAP_BORDER);
  354. },
  355. /**
  356. * Gets the current center position of the node in page coordinates.
  357. * @method getCenterXY
  358. * @for Node
  359. * @return {Array} The XY position of the node
  360. */
  361. getCenterXY: function() {
  362. var instance = this;
  363. var region = instance.get(REGION);
  364. return [(region.left + region.width/2), (region.top + region.height/2)];
  365. },
  366. /**
  367. * Return the combined size of the margin for the specified sides.
  368. *
  369. * @method getMargin
  370. * @param {string} sides Can be t, r, b, l or any combination of
  371. * those to represent the top, right, bottom, or left sides.
  372. * @return {number}
  373. */
  374. getMargin: function(sides) {
  375. var instance = this;
  376. return instance._getBoxStyleAsNumber(sides, MAP_MARGIN);
  377. },
  378. /**
  379. * Return the combined width of the border for the specified sides.
  380. *
  381. * @method getPadding
  382. * @param {string} sides Can be t, r, b, l or any combination of
  383. * those to represent the top, right, bottom, or left sides.
  384. * @return {number}
  385. */
  386. getPadding: function(sides) {
  387. var instance = this;
  388. return instance._getBoxStyleAsNumber(sides, MAP_PADDING);
  389. },
  390. /**
  391. * Set the id of the Node instance if the object does not have one. The
  392. * generated id is based on a guid created by the
  393. * <a href="YUI.html#method_stamp">stamp</a> method.
  394. *
  395. * @method guid
  396. * @param {string} prefix optional guid prefix
  397. * @return {String} The current id of the node
  398. */
  399. guid: function(prefix) {
  400. var instance = this;
  401. var currentId = instance.get('id');
  402. if (!currentId) {
  403. currentId = A.stamp(instance);
  404. instance.set('id', currentId);
  405. }
  406. return currentId;
  407. },
  408. /**
  409. * Create a hover interaction.
  410. *
  411. * @method hover
  412. * @param {string} overFn
  413. * @param {string} outFn
  414. * @return {Node} The current Node instance
  415. */
  416. hover: function(overFn, outFn) {
  417. var instance = this;
  418. var hoverOptions;
  419. var defaultHoverOptions = instance._defaultHoverOptions;
  420. if (isObject(overFn, true)) {
  421. hoverOptions = overFn;
  422. hoverOptions = A.mix(hoverOptions, defaultHoverOptions);
  423. overFn = hoverOptions.over;
  424. outFn = hoverOptions.out;
  425. }
  426. else {
  427. hoverOptions = A.mix(
  428. {
  429. over: overFn,
  430. out: outFn
  431. },
  432. defaultHoverOptions
  433. );
  434. }
  435. instance._hoverOptions = hoverOptions;
  436. hoverOptions.overTask = A.debounce(instance._hoverOverTaskFn, null, instance);
  437. hoverOptions.outTask = A.debounce(instance._hoverOutTaskFn, null, instance);
  438. return new A.EventHandle(
  439. [
  440. instance.on(hoverOptions.overEventType, instance._hoverOverHandler, instance),
  441. instance.on(hoverOptions.outEventType, instance._hoverOutHandler, instance)
  442. ]
  443. );
  444. },
  445. /**
  446. * <p>Get or Set the HTML contents of the node. If the <code>value</code>
  447. * is passed it's set the content of the element, otherwise it works as a
  448. * getter for the current content.</p>
  449. *
  450. * Example:
  451. *
  452. * <pre><code>var node = A.one('#nodeId');
  453. * node.html('Setting new HTML');
  454. * // Alert the value of the current content
  455. * alert( node.html() );
  456. * </code></pre>
  457. *
  458. * @method html
  459. * @param {string} value A string of html to set as the content of the node instance.
  460. */
  461. html: function() {
  462. var args = arguments, length = args.length;
  463. if (length) {
  464. this.set(INNER_HTML, args[0]);
  465. }
  466. else {
  467. return this.get(INNER_HTML);
  468. }
  469. return this;
  470. },
  471. oneNS: function(ns, selector) {
  472. var instance = this;
  473. return instance.one(formatSelectorNS(ns, selector));
  474. },
  475. /**
  476. * Gets the outerHTML of a node, which islike innerHTML, except that it
  477. * actually contains the HTML of the node itself.
  478. *
  479. * @return {string} The outerHTML of the given element.
  480. */
  481. outerHTML: function() {
  482. var instance = this;
  483. var domEl = instance.getDOM();
  484. // IE, Opera and WebKit all have outerHTML.
  485. if ('outerHTML' in domEl) {
  486. return domEl.outerHTML;
  487. }
  488. var temp = Node.create('<div></div>').append(
  489. this.clone()
  490. );
  491. try {
  492. return temp.html();
  493. }
  494. catch(e) {}
  495. finally {
  496. temp = null;
  497. }
  498. },
  499. /**
  500. * <p>Inserts a <code>newNode</code> after the node instance (i.e., as the next
  501. * sibling). If the reference node has no parent, then does nothing.</p>
  502. *
  503. * Example:
  504. *
  505. * <pre><code>var titleNode = A.one('#titleNode');
  506. * var descriptionNode = A.one('#descriptionNode');
  507. * // the description is usually shown after the title
  508. * titleNode.placeAfter(descriptionNode);
  509. * </code></pre>
  510. *
  511. * @method placeAfter
  512. * @chainable
  513. * @param {Node} newNode Node to insert.
  514. */
  515. placeAfter: function(newNode) {
  516. var instance = this;
  517. return instance._place(newNode, instance.get(NEXT_SIBLING));
  518. },
  519. /**
  520. * <p>Inserts a <code>newNode</code> before the node instance (i.e., as the previous
  521. * sibling). If the reference node has no parent, then does nothing.</p>
  522. *
  523. * Example:
  524. *
  525. * <pre><code>var descriptionNode = A.one('#descriptionNode');
  526. * var titleNode = A.one('#titleNode');
  527. * // the title is usually shown before the description
  528. * descriptionNode.placeBefore(titleNode);
  529. * </code></pre>
  530. *
  531. * @method placeBefore
  532. * @chainable
  533. * @param {Node} newNode Node to insert.
  534. */
  535. placeBefore: function(newNode) {
  536. var instance = this;
  537. return instance._place(newNode, instance);
  538. },
  539. /**
  540. * <p>Inserts the node instance to the begining of the <code>selector</code>
  541. * node (i.e., insert before the <code>firstChild</code> of the
  542. * <code>selector</code>).</p>
  543. *
  544. * Example:
  545. *
  546. * <pre><code>var node = A.one('#nodeId');
  547. * node.prependTo('body');
  548. * </code></pre>
  549. *
  550. * @method prependTo
  551. * @chainable
  552. * @param {Node | String} selector A selector, element, HTML string, Node
  553. */
  554. prependTo: function(selector) {
  555. var instance = this;
  556. A.one(selector).prepend(instance);
  557. return instance;
  558. },
  559. /**
  560. * Add one or more CSS classes to an element and remove the class(es)
  561. * from the siblings of the element.
  562. *
  563. * @method radioClass
  564. * @chainable
  565. * @param {String} cssClass
  566. */
  567. radioClass: function(cssClass) {
  568. var instance = this;
  569. var siblings = instance.siblings();
  570. if (isString(cssClass)) {
  571. siblings.removeClass(cssClass);
  572. instance.addClass(cssClass);
  573. }
  574. else if (isArray(cssClass)) {
  575. var siblingNodes = siblings.getDOM();
  576. var regex = getRegExp('(?:^|\\s+)(?:' + cssClass.join('|') + ')(?=\\s+|$)', 'g');
  577. var node;
  578. for (var i = siblingNodes.length - 1; i >= 0; i--) {
  579. node = siblingNodes[i];
  580. node.className = node.className.replace(regex, '');
  581. }
  582. instance.addClass(cssClass.join(' '));
  583. }
  584. return instance;
  585. },
  586. /**
  587. * Generate an unique identifier and reset the id attribute of the node
  588. * instance using the new value. Invokes the
  589. * <a href="Node.html#method_guid">guid</a>.
  590. *
  591. * @method resetId
  592. * @chainable
  593. * @param {String} prefix Optional prefix for the guid.
  594. */
  595. resetId: function(prefix) {
  596. var instance = this;
  597. instance.attr('id', A.guid(prefix));
  598. return instance;
  599. },
  600. /**
  601. * Selects a substring of text inside of the input element.
  602. *
  603. * @method selectText
  604. * @param {Number} start The index to start the selection range from
  605. * @param {Number} end The index to end the selection range at
  606. */
  607. selectText: function(start, end) {
  608. var instance = this;
  609. var textField = instance.getDOM();
  610. var length = instance.val().length;
  611. end = isValue(end) ? end : length;
  612. start = isValue(start) ? start : 0;
  613. // Some form elements could throw a (NS_ERROR_FAILURE)
  614. // [nsIDOMNSHTMLInputElement.setSelectionRange] error when invoke the
  615. // setSelectionRange on firefox. Wrapping in a try/catch to prevent the error be thrown
  616. try {
  617. if (textField.setSelectionRange) {
  618. textField.setSelectionRange(start, end);
  619. }
  620. else if (textField.createTextRange) {
  621. var range = textField.createTextRange();
  622. range.moveStart('character', start);
  623. range.moveEnd('character', end - length);
  624. range.select();
  625. }
  626. else {
  627. textField.select();
  628. }
  629. if (textField != DOC.activeElement) {
  630. textField.focus();
  631. }
  632. }
  633. catch(e) {}
  634. return instance;
  635. },
  636. /**
  637. * Enables text selection for this element (normalized across browsers).
  638. *
  639. * @method selectable
  640. * @chainable
  641. */
  642. selectable: function() {
  643. var instance = this;
  644. instance.getDOM().unselectable = 'off';
  645. instance.detach('selectstart');
  646. instance.setStyles(
  647. {
  648. 'MozUserSelect': STR_EMPTY,
  649. 'KhtmlUserSelect': STR_EMPTY
  650. }
  651. );
  652. instance.removeClass(CSS_HELPER_UNSELECTABLE);
  653. return instance;
  654. },
  655. /**
  656. * <p>Stops the specified event(s) from bubbling and optionally prevents the
  657. * default action.</p>
  658. *
  659. * Example:
  660. *
  661. * <pre><code>var anchor = A.one('a#anchorId');
  662. * anchor.swallowEvent('click');
  663. * </code></pre>
  664. *
  665. * @method swallowEvent
  666. * @chainable
  667. * @param {String/Array} eventName an event or array of events to stop from bubbling
  668. * @param {Boolean} preventDefault (optional) true to prevent the default action too
  669. */
  670. swallowEvent: function(eventName, preventDefault) {
  671. var instance = this;
  672. var fn = function(event) {
  673. event.stopPropagation();
  674. if (preventDefault) {
  675. event.preventDefault();
  676. event.halt();
  677. }
  678. return false;
  679. };
  680. if(isArray(eventName)) {
  681. AArray.each(
  682. eventName,
  683. function(name) {
  684. instance.on(name, fn);
  685. }
  686. );
  687. return this;
  688. }
  689. else {
  690. instance.on(eventName, fn);
  691. }
  692. return instance;
  693. },
  694. /**
  695. * <p>Get or Set the combined text contents of the node instance,
  696. * including it's descendants. If the <code>text</code>
  697. * is passed it's set the content of the element, otherwise it works as a
  698. * getter for the current content.</p>
  699. *
  700. * Example:
  701. *
  702. * <pre><code>var node = A.one('#nodeId');
  703. * node.text('Setting new text content');
  704. * // Alert the value of the current content
  705. * alert( node.text() );
  706. * </code></pre>
  707. *
  708. * @method text
  709. * @param {String} text A string of text to set as the content of the node instance.
  710. */
  711. text: function(text) {
  712. var instance = this;
  713. var el = instance.getDOM();
  714. if (!isUndefined(text)) {
  715. text = A.DOM._getDoc(el).createTextNode(text);
  716. return instance.empty().append(text);
  717. }
  718. return instance._getText(el.childNodes);
  719. },
  720. /**
  721. * <p>Displays or hide the node instance.</p>
  722. *
  723. * <p><string>NOTE:</string> This method assume that your node were hidden
  724. * because of the 'aui-helper-hidden' css class were being used. This won't
  725. * manipulate the inline <code>style.display</code> property.</p>
  726. *
  727. * @method toggle
  728. * @chainable
  729. * @param {Boolean} on Whether to force the toggle. Optional.
  730. * @param {Function} callback A function to run after the visibility change. Optional.
  731. */
  732. toggle: function(on, callback) {
  733. var instance = this;
  734. instance._toggleView.apply(instance, arguments);
  735. return instance;
  736. },
  737. /**
  738. * Disables text selection for this element (normalized across browsers).
  739. *
  740. * @method unselectable
  741. * @chainable
  742. */
  743. unselectable: function() {
  744. var instance = this;
  745. instance.getDOM().unselectable = 'on';
  746. instance.swallowEvent('selectstart', true);
  747. instance.setStyles(
  748. {
  749. 'MozUserSelect': NONE,
  750. 'KhtmlUserSelect': NONE
  751. }
  752. );
  753. instance.addClass(CSS_HELPER_UNSELECTABLE);
  754. return instance;
  755. },
  756. /**
  757. * <p>Get or Set the value attribute of the node instance. If the
  758. * <code>value</code> is passed it's set the value of the element,
  759. * otherwise it works as a getter for the current value.</p>
  760. *
  761. * Example:
  762. *
  763. * <pre><code>var input = A.one('#inputId');
  764. * input.val('Setting new input value');
  765. * // Alert the value of the input
  766. * alert( input.val() );
  767. * </code></pre>
  768. *
  769. * @method val
  770. * @param {string} value Value to be set. Optional.
  771. */
  772. val: function(value) {
  773. var instance = this;
  774. if (isUndefined(value)) {
  775. return instance.get(VALUE);
  776. }
  777. else {
  778. return instance.set(VALUE, value);
  779. }
  780. },
  781. /**
  782. * Return the combined size of the box style for the specified sides.
  783. *
  784. * @method _getBoxStyleAsNumber
  785. * @param {string} sides Can be t, r, b, l or any combination of
  786. * those to represent the top, right, bottom, or left sides.
  787. * @param {string} map An object mapping mapping the "sides" param to the a CSS value to retrieve
  788. * @return {number}
  789. */
  790. _getBoxStyleAsNumber: function(sides, map) {
  791. var instance = this;
  792. var sidesArray = sides.match(/\w/g);
  793. var value = 0;
  794. var side;
  795. var sideKey;
  796. for (var i = sidesArray.length - 1; i >= 0; i--) {
  797. sideKey = sidesArray[i];
  798. side = 0;
  799. if (sideKey) {
  800. side = parseFloat(instance.getComputedStyle(map[sideKey]));
  801. side = Math.abs(side);
  802. value += side || 0;
  803. }
  804. }
  805. return value;
  806. },
  807. /**
  808. * Extract text content from the passed nodes.
  809. *
  810. * @method _getText
  811. * @private
  812. * @param {Native NodeList} childNodes
  813. */
  814. _getText: function(childNodes) {
  815. var instance = this;
  816. var length = childNodes.length;
  817. var childNode;
  818. var str = [];
  819. for (var i = 0; i < length; i++) {
  820. childNode = childNodes[i];
  821. if (childNode && childNode.nodeType != 8) {
  822. if (childNode.nodeType != 1) {
  823. str.push(childNode.nodeValue);
  824. }
  825. if (childNode.childNodes) {
  826. str.push(instance._getText(childNode.childNodes));
  827. }
  828. }
  829. }
  830. return str.join(STR_EMPTY);
  831. },
  832. /**
  833. * The event handler for the "out" function that is fired for events attached via the hover method.
  834. *
  835. * @method _hoverOutHandler
  836. * @private
  837. * @param {EventFacade} event
  838. */
  839. _hoverOutHandler: function(event) {
  840. var instance = this;
  841. var hoverOptions = instance._hoverOptions;
  842. hoverOptions.outTask.delay(hoverOptions.outDelay, event);
  843. },
  844. /**
  845. * The event handler for the "over" function that is fired for events attached via the hover method.
  846. *
  847. * @method _hoverOverHandler
  848. * @private
  849. * @param {EventFacade} event
  850. */
  851. _hoverOverHandler: function(event) {
  852. var instance = this;
  853. var hoverOptions = instance._hoverOptions;
  854. hoverOptions.overTask.delay(hoverOptions.overDelay, event);
  855. },
  856. /**
  857. * Cancels the over task, and fires the users custom "out" function for the hover method
  858. *
  859. * @method _hoverOverHandler
  860. * @private
  861. * @param {EventFacade} event
  862. */
  863. _hoverOutTaskFn: function(event) {
  864. var instance = this;
  865. var hoverOptions = instance._hoverOptions;
  866. hoverOptions.overTask.cancel();
  867. hoverOptions.out.apply(hoverOptions.context || event.currentTarget, arguments);
  868. },
  869. /**
  870. * Cancels the out task, and fires the users custom "over" function for the hover method
  871. *
  872. * @method _hoverOverHandler
  873. * @private
  874. * @param {EventFacade} event
  875. */
  876. _hoverOverTaskFn: function(event) {
  877. var instance = this;
  878. var hoverOptions = instance._hoverOptions;
  879. hoverOptions.outTask.cancel();
  880. hoverOptions.over.apply(hoverOptions.context || event.currentTarget, arguments);
  881. },
  882. /**
  883. * Place a node or html string at a specific location
  884. *
  885. * @method _place
  886. * @private
  887. * @param {Node|String} newNode
  888. * @param {Node} refNode
  889. */
  890. _place: function(newNode, refNode) {
  891. var instance = this;
  892. var parent = instance.get(PARENT_NODE);
  893. if (parent) {
  894. if (isString(newNode)) {
  895. newNode = Node.create(newNode);
  896. }
  897. parent.insertBefore(newNode, refNode);
  898. }
  899. return instance;
  900. },
  901. _defaultHoverOptions: {
  902. overEventType: 'mouseenter',
  903. outEventType: 'mouseleave',
  904. overDelay: 0,
  905. outDelay: 0,
  906. over: Lang.emptyFn,
  907. out: Lang.emptyFn
  908. }
  909. }, true);
  910. NODE_PROTO.__show = NODE_PROTO._show;
  911. NODE_PROTO.__hide = NODE_PROTO._hide;
  912. NODE_PROTO.__isHidden = NODE_PROTO._isHidden;
  913. NODE_PROTO._isHidden = function() {
  914. var instance = this;
  915. return NODE_PROTO.__isHidden.call(instance) || instance.hasClass(instance._hideClass || CSS_HELPER_HIDDEN);
  916. };
  917. /**
  918. * <p>Hide the node adding a css class on it. If <code>cssClass</code> is not
  919. * passed as argument, the className 'aui-helper-hidden' will be used by
  920. * default.</p>
  921. *
  922. * <p><string>NOTE:</string> This method assume that your node were visible
  923. * because the absence of 'aui-helper-hidden' css class. This won't
  924. * manipulate the inline <code>style.display</code> property.</p>
  925. *
  926. * @method hide
  927. * @chainable
  928. * @param {string} cssClass Class name to hide the element. Optional.
  929. */
  930. NODE_PROTO._hide = function() {
  931. var instance = this;
  932. instance.addClass(instance._hideClass || CSS_HELPER_HIDDEN);
  933. return instance;
  934. };
  935. /**
  936. * <p>Show the node removing a css class used to hide it. Use the same
  937. * className added using the <a href="A.Node.html#method_hide">hide</a>
  938. * method. If <code>cssClass</code> is not passed as argument, the
  939. * className 'aui-helper-hidden' will be used by default.</p>
  940. *
  941. * <p><string>NOTE:</string> This method assume that your node were hidden
  942. * because of the 'aui-helper-hidden' css class were being used. This won't
  943. * manipulate the inline <code>style.display</code> property.</p>
  944. *
  945. * @method show
  946. * @chainable
  947. * @param {string} cssClass Class name to hide the element. Optional.
  948. */
  949. NODE_PROTO._show = function() {
  950. var instance = this;
  951. instance.removeClass(instance._hideClass || CSS_HELPER_HIDDEN);
  952. return instance;
  953. };
  954. /**
  955. * Returns the width of the content, not including
  956. * the padding, border or margin. If a width is passed,
  957. * the node's overall width is set to that size.
  958. *
  959. * Example:
  960. *
  961. * <pre><code>var node = A.one('#nodeId');
  962. * node.width(); //returns content width
  963. * node.width(100); // sets box width
  964. * </code></pre>
  965. *
  966. * @method width
  967. * @return {number}
  968. */
  969. /**
  970. * Returns the height of the content, not including
  971. * the padding, border or margin. If a height is passed,
  972. * the node's overall height is set to that size.
  973. *
  974. * Example:
  975. *
  976. * <pre><code>var node = A.one('#nodeId');
  977. * node.height(); //returns content height
  978. * node.height(100); // sets box height
  979. * </code></pre>
  980. *
  981. * @method height
  982. * @return {number}
  983. */
  984. /**
  985. * Returns the size of the box from inside of the border,
  986. * which is the offsetWidth plus the padding on the left and right.
  987. *
  988. * Example:
  989. *
  990. * <pre><code>var node = A.one('#nodeId');
  991. * node.innerWidth();
  992. * </code></pre>
  993. *
  994. * @method innerWidth
  995. * @return {number}
  996. */
  997. /**
  998. * Returns the size of the box from inside of the border,
  999. * which is offsetHeight plus the padding on the top and bottom.
  1000. *
  1001. * Example:
  1002. *
  1003. * <pre><code>var node = A.one('#nodeId');
  1004. * node.innerHeight();
  1005. * </code></pre>
  1006. *
  1007. * @method innerHeight
  1008. * @return {number}
  1009. */
  1010. /**
  1011. * Returns the outer width of the box including the border,
  1012. * if true is passed as the first argument, the margin is included.
  1013. *
  1014. * Example:
  1015. *
  1016. * <pre><code>var node = A.one('#nodeId');
  1017. * node.outerWidth();
  1018. * node.outerWidth(true); // includes margin
  1019. * </code></pre>
  1020. *
  1021. * @method outerWidth
  1022. * @return {number}
  1023. */
  1024. /**
  1025. * Returns the outer height of the box including the border,
  1026. * if true is passed as the first argument, the margin is included.
  1027. *
  1028. * Example:
  1029. *
  1030. * <pre><code>var node = A.one('#nodeId');
  1031. * node.outerHeight();
  1032. * node.outerHeight(true); // includes margin
  1033. * </code></pre>
  1034. *
  1035. * @method outerHeight
  1036. * @return {number}
  1037. */
  1038. A.each(
  1039. ['Height', 'Width'],
  1040. function(item, index, collection) {
  1041. var sides = index ? 'lr' : 'tb';
  1042. var dimensionType = item.toLowerCase();
  1043. NODE_PROTO[dimensionType] = function(size) {
  1044. var instance = this;
  1045. var returnValue = instance;
  1046. if (isUndefined(size)) {
  1047. var node = instance._node;
  1048. var dimension;
  1049. if (node) {
  1050. if ((!node.tagName && node.nodeType === 9) || node.alert) {
  1051. dimension = instance.get(REGION)[dimensionType];
  1052. }
  1053. else {
  1054. dimension = instance.get(OFFSET + item);
  1055. var previous = {};
  1056. var styleObj = node.style;
  1057. if (!dimension) {
  1058. instance.addClass(CSS_HELPER_FORCE_OFFSET);
  1059. dimension = instance.get(OFFSET + item);
  1060. instance.removeClass(CSS_HELPER_FORCE_OFFSET);
  1061. }
  1062. if (dimension) {
  1063. dimension -= (instance.getPadding(sides) + instance.getBorderWidth(sides));
  1064. }
  1065. }
  1066. }
  1067. returnValue = dimension;
  1068. }
  1069. else {
  1070. instance.setStyle(dimensionType, size);
  1071. }
  1072. return returnValue;
  1073. };
  1074. NODE_PROTO[INNER + item] = function() {
  1075. var instance = this;
  1076. return instance[dimensionType]() + instance.getPadding(sides);
  1077. };
  1078. NODE_PROTO[OUTER + item] = function(margin) {
  1079. var instance = this;
  1080. var innerSize = instance[INNER + item]();
  1081. var borderSize = instance.getBorderWidth(sides);
  1082. var size = innerSize + borderSize;
  1083. if (margin) {
  1084. size += instance.getMargin(sides);
  1085. }
  1086. return size;
  1087. };
  1088. }
  1089. );
  1090. if (!SUPPORT_OPTIONAL_TBODY) {
  1091. A.DOM._ADD_HTML = A.DOM.addHTML;
  1092. A.DOM.addHTML = function(node, content, where) {
  1093. var nodeName = (node.nodeName && node.nodeName.toLowerCase()) || STR_EMPTY;
  1094. var tagName = STR_EMPTY;
  1095. if (!isUndefined(content)) {
  1096. if (isString(content)) {
  1097. tagName = (REGEX_TAGNAME.exec(content) || ARRAY_EMPTY_STRINGS)[1];
  1098. }
  1099. else if (content.nodeType && content.nodeType == 11 && content.childNodes.length) { // a doc frag
  1100. tagName = content.childNodes[0].nodeName;
  1101. }
  1102. else if (content.nodeName) { // a node
  1103. tagName = content.nodeName;
  1104. }
  1105. tagName = tagName && tagName.toLowerCase();
  1106. }
  1107. if (nodeName == 'table' && tagName == 'tr') {
  1108. node = node.getElementsByTagName('tbody')[0] || node.appendChild(node.ownerDocument.createElement('tbody'));
  1109. var whereNodeName = ((where && where.nodeName) || STR_EMPTY).toLowerCase();
  1110. // Assuming if the "where" is a tbody node,
  1111. // we're trying to prepend to a table. Attempt to
  1112. // grab the first child of the tbody.
  1113. if (whereNodeName == 'tbody' && where.childNodes.length > 0) {
  1114. where = where.firstChild;
  1115. }
  1116. }
  1117. return A.DOM._ADD_HTML(node, content, where);
  1118. };
  1119. }
  1120. /**
  1121. * Augment the <a href="NodeList.html">YUI3 NodeList</a> with more util methods.
  1122. *
  1123. * Check the list of <a href="NodeList.html#methods">Methods</a> available for
  1124. * AUI NodeList.
  1125. *
  1126. * @class A.NodeList
  1127. * @constructor
  1128. * @uses A.Node
  1129. */
  1130. NodeList.importMethod(
  1131. NODE_PROTO,
  1132. [
  1133. 'after',
  1134. 'appendTo',
  1135. 'attr',
  1136. 'before',
  1137. 'empty',
  1138. 'hover',
  1139. 'html',
  1140. 'innerHeight',
  1141. 'innerWidth',
  1142. 'outerHeight',
  1143. 'outerHTML',
  1144. 'outerWidth',
  1145. 'prepend',
  1146. 'prependTo',
  1147. 'purge',
  1148. 'selectText',
  1149. 'selectable',
  1150. 'text',
  1151. 'toggle',
  1152. 'unselectable',
  1153. 'val'
  1154. ]
  1155. );
  1156. A.mix(
  1157. NODELIST_PROTO,
  1158. {
  1159. /**
  1160. * See <a href="Node.html#method_all">Node all</a>.
  1161. *
  1162. * @method all
  1163. */
  1164. all: function(selector) {
  1165. var instance = this;
  1166. var newNodeList = [];
  1167. var nodes = instance._nodes;
  1168. var length = nodes.length;
  1169. var subList;
  1170. for (var i = 0; i < length; i++) {
  1171. subList = A.Selector.query(selector, nodes[i]);
  1172. if (subList && subList.length) {
  1173. newNodeList.push.apply(newNodeList, subList);
  1174. }
  1175. }
  1176. newNodeList = AArray.unique(newNodeList);
  1177. return A.all(newNodeList);
  1178. },
  1179. allNS: function(ns, selector) {
  1180. var instance = this;
  1181. return instance.all(formatSelectorNS(ns, selector));
  1182. },
  1183. /**
  1184. * Returns the first element in the node list collection.
  1185. *
  1186. * @method first
  1187. * @return {Node}
  1188. */
  1189. first: function() {
  1190. var instance = this;
  1191. return instance.item(0);
  1192. },
  1193. /**
  1194. * See <a href="Node.html#method_getDOM">Node getDOM</a>.
  1195. *
  1196. * @method getDOM
  1197. */
  1198. getDOM: function() {
  1199. var instance = this;
  1200. return NodeList.getDOMNodes(this);
  1201. },
  1202. /**
  1203. * Returns the last element in the node list collection.
  1204. *
  1205. * @method last
  1206. * @return {Node}
  1207. */
  1208. last: function() {
  1209. var instance = this;
  1210. return instance.item(instance._nodes.length - 1);
  1211. },
  1212. /**
  1213. * See <a href="Node.html#method_one">Node one</a>.
  1214. *
  1215. * @method one
  1216. */
  1217. one: function(selector) {
  1218. var instance = this;
  1219. var newNode = null;
  1220. var nodes = instance._nodes;
  1221. var length = nodes.length;
  1222. for (var i = 0; i < length; i++) {
  1223. newNode = A.Selector.query(selector, nodes[i], true);
  1224. if (newNode) {
  1225. newNode = A.one(newNode);
  1226. break;
  1227. }
  1228. }
  1229. return newNode;
  1230. },
  1231. oneNS: function(ns, selector) {
  1232. var instance = this;
  1233. return instance.one(formatSelectorNS(ns, selector));
  1234. }
  1235. }
  1236. );
  1237. NODELIST_PROTO.__filter = NODELIST_PROTO.filter;
  1238. NODELIST_PROTO.filter = function(value, context) {
  1239. var instance = this;
  1240. var newNodeList;
  1241. if (isFunction(value)) {
  1242. var nodes = [];
  1243. instance.each(
  1244. function(item, index, collection) {
  1245. if (value.call(context || item, item, index, collection)) {
  1246. nodes.push(item._node);
  1247. }
  1248. }
  1249. );
  1250. newNodeList = A.all(nodes);
  1251. }
  1252. else {
  1253. newNodeList = NODELIST_PROTO.__filter.call(instance, value);
  1254. }
  1255. return newNodeList;
  1256. };
  1257. A.mix(
  1258. NodeList,
  1259. {
  1260. create: function(html) {
  1261. var docFrag = A.getDoc().invoke(CREATE_DOCUMENT_FRAGMENT);
  1262. return docFrag.append(html).get(CHILD_NODES);
  1263. }
  1264. }
  1265. );
  1266. A.mix(
  1267. A,
  1268. {
  1269. /**
  1270. * Get the body node. Shortcut to <code>A.one('body')</code>.
  1271. *
  1272. * @method getBody
  1273. */
  1274. getBody: function() {
  1275. var instance = this;
  1276. if (!instance._bodyNode) {
  1277. instance._bodyNode = A.one(DOC.body);
  1278. }
  1279. return instance._bodyNode;
  1280. },
  1281. /**
  1282. * Get the document node. Shortcut to <code>A.one(document)</code>.
  1283. *
  1284. * @method getDoc
  1285. */
  1286. getDoc: function() {
  1287. var instance = this;
  1288. if (!instance._documentNode) {
  1289. instance._documentNode = A.one(DOC);
  1290. }
  1291. return instance._documentNode;
  1292. },
  1293. /**
  1294. * Get the window node. Shortcut to <code>A.one(window)</code>.
  1295. *
  1296. * @method getWin
  1297. */
  1298. getWin: function() {
  1299. var instance = this;
  1300. if (!instance._windowNode) {
  1301. instance._windowNode = A.one(WIN);
  1302. }
  1303. return instance._windowNode;
  1304. }
  1305. }
  1306. );
  1307. A.queryNS = function(ns, selector, methodName) {
  1308. return A[methodName || 'one'](formatSelectorNS(ns, selector));
  1309. };
  1310. A.oneNS = A.queryNS;
  1311. A.allNS = function(ns, selector) {
  1312. return A.queryNS(ns, selector, 'all');
  1313. }
  1314. A.byIdNS = function(ns, id) {
  1315. return A.one(prefixSelector(ns, id));
  1316. };
  1317. // Patch for http://yuilibrary.com/projects/yui3/ticket/2531537
  1318. var addMethod = NodeList.addMethod;
  1319. AArray.each(
  1320. ['hide', 'show'],
  1321. function(item, index, collection) {
  1322. addMethod(
  1323. item,
  1324. function() {
  1325. return this[item].apply(this, arguments);
  1326. }
  1327. );
  1328. }
  1329. );
  1330. }, '@VERSION@' ,{requires:['array-extras','aui-base-lang','aui-classnamemanager','node']});