PageRenderTime 29ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/hippo/src/main/webapp/yui/carousel/carousel-debug.js

http://hdbc.googlecode.com/
JavaScript | 2042 lines | 845 code | 265 blank | 932 comment | 174 complexity | ddde469bd8397d0d57eb7de969d6d04e MD5 | raw file
  1. /*
  2. Copyright (c) 2009, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.net/yui/license.txt
  5. version: 2.7.0
  6. */
  7. /**
  8. * The Carousel module provides a widget for browsing among a set of like
  9. * objects represented pictorially.
  10. *
  11. * @module carousel
  12. * @requires yahoo, dom, event, element
  13. * @optional animation
  14. * @namespace YAHOO.widget
  15. * @title Carousel Widget
  16. * @beta
  17. */
  18. (function () {
  19. var WidgetName; // forward declaration
  20. /**
  21. * The Carousel widget.
  22. *
  23. * @class Carousel
  24. * @extends YAHOO.util.Element
  25. * @constructor
  26. * @param el {HTMLElement | String} The HTML element that represents the
  27. * the container that houses the Carousel.
  28. * @param cfg {Object} (optional) The configuration values
  29. */
  30. YAHOO.widget.Carousel = function (el, cfg) {
  31. YAHOO.log("Component creation", WidgetName);
  32. YAHOO.widget.Carousel.superclass.constructor.call(this, el, cfg);
  33. };
  34. /*
  35. * Private variables of the Carousel component
  36. */
  37. /* Some abbreviations to avoid lengthy typing and lookups. */
  38. var Carousel = YAHOO.widget.Carousel,
  39. Dom = YAHOO.util.Dom,
  40. Event = YAHOO.util.Event,
  41. JS = YAHOO.lang;
  42. /**
  43. * The widget name.
  44. * @private
  45. * @static
  46. */
  47. WidgetName = "Carousel";
  48. /**
  49. * The internal table of Carousel instances.
  50. * @private
  51. * @static
  52. */
  53. var instances = {},
  54. /*
  55. * Custom events of the Carousel component
  56. */
  57. /**
  58. * @event afterScroll
  59. * @description Fires when the Carousel has scrolled to the previous or
  60. * next page. Passes back the index of the first and last visible items in
  61. * the Carousel. See
  62. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  63. * for more information on listening for this event.
  64. * @type YAHOO.util.CustomEvent
  65. */
  66. afterScrollEvent = "afterScroll",
  67. /**
  68. * @event allItemsRemovedEvent
  69. * @description Fires when all items have been removed from the Carousel.
  70. * See
  71. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  72. * for more information on listening for this event.
  73. * @type YAHOO.util.CustomEvent
  74. */
  75. allItemsRemovedEvent = "allItemsRemoved",
  76. /**
  77. * @event beforeHide
  78. * @description Fires before the Carousel is hidden. See
  79. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  80. * for more information on listening for this event.
  81. * @type YAHOO.util.CustomEvent
  82. */
  83. beforeHideEvent = "beforeHide",
  84. /**
  85. * @event beforePageChange
  86. * @description Fires when the Carousel is about to scroll to the previous
  87. * or next page. Passes back the page number of the current page. Note
  88. * that the first page number is zero. See
  89. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  90. * for more information on listening for this event.
  91. * @type YAHOO.util.CustomEvent
  92. */
  93. beforePageChangeEvent = "beforePageChange",
  94. /**
  95. * @event beforeScroll
  96. * @description Fires when the Carousel is about to scroll to the previous
  97. * or next page. Passes back the index of the first and last visible items
  98. * in the Carousel and the direction (backward/forward) of the scroll. See
  99. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  100. * for more information on listening for this event.
  101. * @type YAHOO.util.CustomEvent
  102. */
  103. beforeScrollEvent = "beforeScroll",
  104. /**
  105. * @event beforeShow
  106. * @description Fires when the Carousel is about to be shown. See
  107. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  108. * for more information on listening for this event.
  109. * @type YAHOO.util.CustomEvent
  110. */
  111. beforeShowEvent = "beforeShow",
  112. /**
  113. * @event blur
  114. * @description Fires when the Carousel loses focus. See
  115. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  116. * for more information on listening for this event.
  117. * @type YAHOO.util.CustomEvent
  118. */
  119. blurEvent = "blur",
  120. /**
  121. * @event focus
  122. * @description Fires when the Carousel gains focus. See
  123. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  124. * for more information on listening for this event.
  125. * @type YAHOO.util.CustomEvent
  126. */
  127. focusEvent = "focus",
  128. /**
  129. * @event hide
  130. * @description Fires when the Carousel is hidden. See
  131. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  132. * for more information on listening for this event.
  133. * @type YAHOO.util.CustomEvent
  134. */
  135. hideEvent = "hide",
  136. /**
  137. * @event itemAdded
  138. * @description Fires when an item has been added to the Carousel. Passes
  139. * back the content of the item that would be added, the index at which the
  140. * item would be added, and the event itself. See
  141. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  142. * for more information on listening for this event.
  143. * @type YAHOO.util.CustomEvent
  144. */
  145. itemAddedEvent = "itemAdded",
  146. /**
  147. * @event itemRemoved
  148. * @description Fires when an item has been removed from the Carousel.
  149. * Passes back the content of the item that would be removed, the index
  150. * from which the item would be removed, and the event itself. See
  151. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  152. * for more information on listening for this event.
  153. * @type YAHOO.util.CustomEvent
  154. */
  155. itemRemovedEvent = "itemRemoved",
  156. /**
  157. * @event itemSelected
  158. * @description Fires when an item has been selected in the Carousel.
  159. * Passes back the index of the selected item in the Carousel. Note, that
  160. * the index begins from zero. See
  161. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  162. * for more information on listening for this event.
  163. * @type YAHOO.util.CustomEvent
  164. */
  165. itemSelectedEvent = "itemSelected",
  166. /**
  167. * @event loadItems
  168. * @description Fires when the Carousel needs more items to be loaded for
  169. * displaying them. Passes back the first and last visible items in the
  170. * Carousel, and the number of items needed to be loaded. See
  171. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  172. * for more information on listening for this event.
  173. * @type YAHOO.util.CustomEvent
  174. */
  175. loadItemsEvent = "loadItems",
  176. /**
  177. * @event navigationStateChange
  178. * @description Fires when the state of either one of the navigation
  179. * buttons are changed from enabled to disabled or vice versa. Passes back
  180. * the state (true/false) of the previous and next buttons. The value true
  181. * signifies the button is enabled, false signifies disabled. See
  182. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  183. * for more information on listening for this event.
  184. * @type YAHOO.util.CustomEvent
  185. */
  186. navigationStateChangeEvent = "navigationStateChange",
  187. /**
  188. * @event pageChange
  189. * @description Fires after the Carousel has scrolled to the previous or
  190. * next page. Passes back the page number of the current page. Note
  191. * that the first page number is zero. See
  192. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  193. * for more information on listening for this event.
  194. * @type YAHOO.util.CustomEvent
  195. */
  196. pageChangeEvent = "pageChange",
  197. /*
  198. * Internal event.
  199. * @event render
  200. * @description Fires when the Carousel is rendered. See
  201. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  202. * for more information on listening for this event.
  203. * @type YAHOO.util.CustomEvent
  204. */
  205. renderEvent = "render",
  206. /**
  207. * @event show
  208. * @description Fires when the Carousel is shown. See
  209. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  210. * for more information on listening for this event.
  211. * @type YAHOO.util.CustomEvent
  212. */
  213. showEvent = "show",
  214. /**
  215. * @event startAutoPlay
  216. * @description Fires when the auto play has started in the Carousel. See
  217. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  218. * for more information on listening for this event.
  219. * @type YAHOO.util.CustomEvent
  220. */
  221. startAutoPlayEvent = "startAutoPlay",
  222. /**
  223. * @event stopAutoPlay
  224. * @description Fires when the auto play has been stopped in the Carousel.
  225. * See
  226. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  227. * for more information on listening for this event.
  228. * @type YAHOO.util.CustomEvent
  229. */
  230. stopAutoPlayEvent = "stopAutoPlay",
  231. /*
  232. * Internal event.
  233. * @event uiUpdateEvent
  234. * @description Fires when the UI has been updated.
  235. * See
  236. * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
  237. * for more information on listening for this event.
  238. * @type YAHOO.util.CustomEvent
  239. */
  240. uiUpdateEvent = "uiUpdate";
  241. /*
  242. * Private helper functions used by the Carousel component
  243. */
  244. /**
  245. * Create an element, set its class name and optionally install the element
  246. * to its parent.
  247. * @method createElement
  248. * @param el {String} The element to be created
  249. * @param attrs {Object} Configuration of parent, class and id attributes.
  250. * If the content is specified, it is inserted after creation of the
  251. * element. The content can also be an HTML element in which case it would
  252. * be appended as a child node of the created element.
  253. * @private
  254. */
  255. function createElement(el, attrs) {
  256. var newEl = document.createElement(el);
  257. attrs = attrs || {};
  258. if (attrs.className) {
  259. Dom.addClass(newEl, attrs.className);
  260. }
  261. if (attrs.parent) {
  262. attrs.parent.appendChild(newEl);
  263. }
  264. if (attrs.id) {
  265. newEl.setAttribute("id", attrs.id);
  266. }
  267. if (attrs.content) {
  268. if (attrs.content.nodeName) {
  269. newEl.appendChild(attrs.content);
  270. } else {
  271. newEl.innerHTML = attrs.content;
  272. }
  273. }
  274. return newEl;
  275. }
  276. /**
  277. * Get the computed style of an element.
  278. *
  279. * @method getStyle
  280. * @param el {HTMLElement} The element for which the style needs to be
  281. * returned.
  282. * @param style {String} The style attribute
  283. * @param type {String} "int", "float", etc. (defaults to int)
  284. * @private
  285. */
  286. function getStyle(el, style, type) {
  287. var value;
  288. if (!el) {
  289. return 0;
  290. }
  291. function getStyleIntVal(el, style) {
  292. var val;
  293. /*
  294. * XXX: Safari calculates incorrect marginRight for an element
  295. * which has its parent element style set to overflow: hidden
  296. * https://bugs.webkit.org/show_bug.cgi?id=13343
  297. * Let us assume marginLeft == marginRight
  298. */
  299. if (style == "marginRight" && YAHOO.env.ua.webkit) {
  300. val = parseInt(Dom.getStyle(el, "marginLeft"), 10);
  301. } else {
  302. val = parseInt(Dom.getStyle(el, style), 10);
  303. }
  304. return JS.isNumber(val) ? val : 0;
  305. }
  306. function getStyleFloatVal(el, style) {
  307. var val;
  308. /*
  309. * XXX: Safari calculates incorrect marginRight for an element
  310. * which has its parent element style set to overflow: hidden
  311. * https://bugs.webkit.org/show_bug.cgi?id=13343
  312. * Let us assume marginLeft == marginRight
  313. */
  314. if (style == "marginRight" && YAHOO.env.ua.webkit) {
  315. val = parseFloat(Dom.getStyle(el, "marginLeft"));
  316. } else {
  317. val = parseFloat(Dom.getStyle(el, style));
  318. }
  319. return JS.isNumber(val) ? val : 0;
  320. }
  321. if (typeof type == "undefined") {
  322. type = "int";
  323. }
  324. switch (style) {
  325. case "height":
  326. value = el.offsetHeight;
  327. if (value > 0) {
  328. value += getStyleIntVal(el, "marginTop") +
  329. getStyleIntVal(el, "marginBottom");
  330. } else {
  331. value = getStyleFloatVal(el, "height") +
  332. getStyleIntVal(el, "marginTop") +
  333. getStyleIntVal(el, "marginBottom") +
  334. getStyleIntVal(el, "borderTopWidth") +
  335. getStyleIntVal(el, "borderBottomWidth") +
  336. getStyleIntVal(el, "paddingTop") +
  337. getStyleIntVal(el, "paddingBottom");
  338. }
  339. break;
  340. case "width":
  341. value = el.offsetWidth;
  342. if (value > 0) {
  343. value += getStyleIntVal(el, "marginLeft") +
  344. getStyleIntVal(el, "marginRight");
  345. } else {
  346. value = getStyleFloatVal(el, "width") +
  347. getStyleIntVal(el, "marginLeft") +
  348. getStyleIntVal(el, "marginRight") +
  349. getStyleIntVal(el, "borderLeftWidth") +
  350. getStyleIntVal(el, "borderRightWidth") +
  351. getStyleIntVal(el, "paddingLeft") +
  352. getStyleIntVal(el, "paddingRight");
  353. }
  354. break;
  355. default:
  356. if (type == "int") {
  357. value = getStyleIntVal(el, style);
  358. } else if (type == "float") {
  359. value = getStyleFloatVal(el, style);
  360. } else {
  361. value = Dom.getStyle(el, style);
  362. }
  363. break;
  364. }
  365. return value;
  366. }
  367. /**
  368. * Compute and return the height or width of a single Carousel item
  369. * depending upon the orientation.
  370. *
  371. * @method getCarouselItemSize
  372. * @param which {String} "height" or "width" to be returned. If this is
  373. * passed explicitly, the calculated size is not cached.
  374. * @private
  375. */
  376. function getCarouselItemSize(which) {
  377. var carousel = this,
  378. child,
  379. size = 0,
  380. vertical = false;
  381. if (carousel._itemsTable.numItems === 0) {
  382. return 0;
  383. }
  384. if (typeof which == "undefined") {
  385. if (carousel._itemsTable.size > 0) {
  386. return carousel._itemsTable.size;
  387. }
  388. }
  389. if (JS.isUndefined(carousel._itemsTable.items[0])) {
  390. return 0;
  391. }
  392. child = Dom.get(carousel._itemsTable.items[0].id);
  393. if (typeof which == "undefined") {
  394. vertical = carousel.get("isVertical");
  395. } else {
  396. vertical = which == "height";
  397. }
  398. if (vertical) {
  399. size = getStyle(child, "height");
  400. } else {
  401. size = getStyle(child, "width");
  402. }
  403. if (typeof which == "undefined") {
  404. carousel._itemsTable.size = size; // save the size for later
  405. }
  406. return size;
  407. }
  408. /**
  409. * Return the index of the first item in the view port for displaying item
  410. * in "pos".
  411. *
  412. * @method getFirstVisibleForPosition
  413. * @param pos {Number} The position of the item to be displayed
  414. * @private
  415. */
  416. function getFirstVisibleForPosition(pos) {
  417. var num = this.get("numVisible");
  418. return Math.floor(pos / num) * num;
  419. }
  420. /**
  421. * Return the scrolling offset size given the number of elements to
  422. * scroll.
  423. *
  424. * @method getScrollOffset
  425. * @param delta {Number} The delta number of elements to scroll by.
  426. * @private
  427. */
  428. function getScrollOffset(delta) {
  429. var itemSize = 0,
  430. size = 0;
  431. itemSize = getCarouselItemSize.call(this);
  432. size = itemSize * delta;
  433. // XXX: really, when the orientation is vertical, the scrolling
  434. // is not exactly the number of elements into element size.
  435. if (this.get("isVertical")) {
  436. size -= delta;
  437. }
  438. return size;
  439. }
  440. /**
  441. * Scroll the Carousel by a page backward.
  442. *
  443. * @method scrollPageBackward
  444. * @param {Event} ev The event object
  445. * @param {Object} obj The context object
  446. * @private
  447. */
  448. function scrollPageBackward(ev, obj) {
  449. obj.scrollPageBackward();
  450. Event.preventDefault(ev);
  451. }
  452. /**
  453. * Scroll the Carousel by a page forward.
  454. *
  455. * @method scrollPageForward
  456. * @param {Event} ev The event object
  457. * @param {Object} obj The context object
  458. * @private
  459. */
  460. function scrollPageForward(ev, obj) {
  461. obj.scrollPageForward();
  462. Event.preventDefault(ev);
  463. }
  464. /**
  465. * Set the selected item.
  466. *
  467. * @method setItemSelection
  468. * @param {Number} newpos The index of the new position
  469. * @param {Number} oldpos The index of the previous position
  470. * @private
  471. */
  472. function setItemSelection(newpos, oldpos) {
  473. var carousel = this,
  474. cssClass = carousel.CLASSES,
  475. el,
  476. firstItem = carousel._firstItem,
  477. isCircular = carousel.get("isCircular"),
  478. numItems = carousel.get("numItems"),
  479. numVisible = carousel.get("numVisible"),
  480. position = oldpos,
  481. sentinel = firstItem + numVisible - 1;
  482. if (position >= 0 && position < numItems) {
  483. if (!JS.isUndefined(carousel._itemsTable.items[position])) {
  484. el = Dom.get(carousel._itemsTable.items[position].id);
  485. if (el) {
  486. Dom.removeClass(el, cssClass.SELECTED_ITEM);
  487. }
  488. }
  489. }
  490. if (JS.isNumber(newpos)) {
  491. newpos = parseInt(newpos, 10);
  492. newpos = JS.isNumber(newpos) ? newpos : 0;
  493. } else {
  494. newpos = firstItem;
  495. }
  496. if (JS.isUndefined(carousel._itemsTable.items[newpos])) {
  497. newpos = getFirstVisibleForPosition.call(carousel, newpos);
  498. carousel.scrollTo(newpos); // still loading the item
  499. }
  500. if (!JS.isUndefined(carousel._itemsTable.items[newpos])) {
  501. el = Dom.get(carousel._itemsTable.items[newpos].id);
  502. if (el) {
  503. Dom.addClass(el, cssClass.SELECTED_ITEM);
  504. }
  505. }
  506. if (newpos < firstItem || newpos > sentinel) { // out of focus
  507. newpos = getFirstVisibleForPosition.call(carousel, newpos);
  508. carousel.scrollTo(newpos);
  509. }
  510. }
  511. /**
  512. * Fire custom events for enabling/disabling navigation elements.
  513. *
  514. * @method syncNavigation
  515. * @private
  516. */
  517. function syncNavigation() {
  518. var attach = false,
  519. carousel = this,
  520. cssClass = carousel.CLASSES,
  521. i,
  522. navigation,
  523. sentinel;
  524. // Don't do anything if the Carousel is not rendered
  525. if (!carousel._hasRendered) {
  526. return;
  527. }
  528. navigation = carousel.get("navigation");
  529. sentinel = carousel._firstItem + carousel.get("numVisible");
  530. if (navigation.prev) {
  531. if (carousel.get("numItems") === 0 || carousel._firstItem === 0) {
  532. if (carousel.get("numItems") === 0 ||
  533. !carousel.get("isCircular")) {
  534. Event.removeListener(navigation.prev, "click",
  535. scrollPageBackward);
  536. Dom.addClass(navigation.prev, cssClass.FIRST_NAV_DISABLED);
  537. for (i = 0; i < carousel._navBtns.prev.length; i++) {
  538. carousel._navBtns.prev[i].setAttribute("disabled",
  539. "true");
  540. }
  541. carousel._prevEnabled = false;
  542. } else {
  543. attach = !carousel._prevEnabled;
  544. }
  545. } else {
  546. attach = !carousel._prevEnabled;
  547. }
  548. if (attach) {
  549. Event.on(navigation.prev, "click", scrollPageBackward,
  550. carousel);
  551. Dom.removeClass(navigation.prev, cssClass.FIRST_NAV_DISABLED);
  552. for (i = 0; i < carousel._navBtns.prev.length; i++) {
  553. carousel._navBtns.prev[i].removeAttribute("disabled");
  554. }
  555. carousel._prevEnabled = true;
  556. }
  557. }
  558. attach = false;
  559. if (navigation.next) {
  560. if (sentinel >= carousel.get("numItems")) {
  561. if (!carousel.get("isCircular")) {
  562. Event.removeListener(navigation.next, "click",
  563. scrollPageForward);
  564. Dom.addClass(navigation.next, cssClass.DISABLED);
  565. for (i = 0; i < carousel._navBtns.next.length; i++) {
  566. carousel._navBtns.next[i].setAttribute("disabled",
  567. "true");
  568. }
  569. carousel._nextEnabled = false;
  570. } else {
  571. attach = !carousel._nextEnabled;
  572. }
  573. } else {
  574. attach = !carousel._nextEnabled;
  575. }
  576. if (attach) {
  577. Event.on(navigation.next, "click", scrollPageForward,
  578. carousel);
  579. Dom.removeClass(navigation.next, cssClass.DISABLED);
  580. for (i = 0; i < carousel._navBtns.next.length; i++) {
  581. carousel._navBtns.next[i].removeAttribute("disabled");
  582. }
  583. carousel._nextEnabled = true;
  584. }
  585. }
  586. carousel.fireEvent(navigationStateChangeEvent,
  587. { next: carousel._nextEnabled, prev: carousel._prevEnabled });
  588. }
  589. /**
  590. * Synchronize and redraw the Pager UI if necessary.
  591. *
  592. * @method syncPagerUi
  593. * @private
  594. */
  595. function syncPagerUi(page) {
  596. var carousel = this, numPages, numVisible;
  597. // Don't do anything if the Carousel is not rendered
  598. if (!carousel._hasRendered) {
  599. return;
  600. }
  601. numVisible = carousel.get("numVisible");
  602. if (!JS.isNumber(page)) {
  603. page = Math.ceil(carousel.get("selectedItem") / numVisible);
  604. }
  605. numPages = Math.ceil(carousel.get("numItems") / numVisible);
  606. carousel._pages.num = numPages;
  607. carousel._pages.cur = page;
  608. if (numPages > carousel.CONFIG.MAX_PAGER_BUTTONS) {
  609. carousel._updatePagerMenu();
  610. } else {
  611. carousel._updatePagerButtons();
  612. }
  613. }
  614. /**
  615. * Handle UI update.
  616. * Call the appropriate methods on events fired when an item is added, or
  617. * removed for synchronizing the DOM.
  618. *
  619. * @method syncUi
  620. * @param {Object} o The item that needs to be added or removed
  621. * @private
  622. */
  623. function syncUi(o) {
  624. var carousel = this;
  625. if (!JS.isObject(o)) {
  626. return;
  627. }
  628. switch (o.ev) {
  629. case itemAddedEvent:
  630. carousel._syncUiForItemAdd(o);
  631. break;
  632. case itemRemovedEvent:
  633. carousel._syncUiForItemRemove(o);
  634. break;
  635. case loadItemsEvent:
  636. carousel._syncUiForLazyLoading(o);
  637. break;
  638. }
  639. carousel.fireEvent(uiUpdateEvent);
  640. }
  641. /**
  642. * Update the state variables after scrolling the Carousel view port.
  643. *
  644. * @method updateStateAfterScroll
  645. * @param {Integer} item The index to which the Carousel has scrolled to.
  646. * @param {Integer} sentinel The last element in the view port.
  647. * @private
  648. */
  649. function updateStateAfterScroll(item, sentinel) {
  650. var carousel = this,
  651. page = carousel.get("currentPage"),
  652. newPage,
  653. numPerPage = carousel.get("numVisible");
  654. newPage = parseInt(carousel._firstItem / numPerPage, 10);
  655. if (newPage != page) {
  656. carousel.setAttributeConfig("currentPage", { value: newPage });
  657. carousel.fireEvent(pageChangeEvent, newPage);
  658. }
  659. if (carousel.get("selectOnScroll")) {
  660. if (carousel.get("selectedItem") != carousel._selectedItem) {
  661. carousel.set("selectedItem", carousel._selectedItem);
  662. }
  663. }
  664. clearTimeout(carousel._autoPlayTimer);
  665. delete carousel._autoPlayTimer;
  666. if (carousel.isAutoPlayOn()) {
  667. carousel.startAutoPlay();
  668. }
  669. carousel.fireEvent(afterScrollEvent,
  670. { first: carousel._firstItem,
  671. last: sentinel },
  672. carousel);
  673. }
  674. /*
  675. * Static members and methods of the Carousel component
  676. */
  677. /**
  678. * Return the appropriate Carousel object based on the id associated with
  679. * the Carousel element or false if none match.
  680. * @method getById
  681. * @public
  682. * @static
  683. */
  684. Carousel.getById = function (id) {
  685. return instances[id] ? instances[id].object : false;
  686. };
  687. YAHOO.extend(Carousel, YAHOO.util.Element, {
  688. /*
  689. * Internal variables used within the Carousel component
  690. */
  691. /**
  692. * The Animation object.
  693. *
  694. * @property _animObj
  695. * @private
  696. */
  697. _animObj: null,
  698. /**
  699. * The Carousel element.
  700. *
  701. * @property _carouselEl
  702. * @private
  703. */
  704. _carouselEl: null,
  705. /**
  706. * The Carousel clipping container element.
  707. *
  708. * @property _clipEl
  709. * @private
  710. */
  711. _clipEl: null,
  712. /**
  713. * The current first index of the Carousel.
  714. *
  715. * @property _firstItem
  716. * @private
  717. */
  718. _firstItem: 0,
  719. /**
  720. * Does the Carousel element have focus?
  721. *
  722. * @property _hasFocus
  723. * @private
  724. */
  725. _hasFocus: false,
  726. /**
  727. * Is the Carousel rendered already?
  728. *
  729. * @property _hasRendered
  730. * @private
  731. */
  732. _hasRendered: false,
  733. /**
  734. * Is the animation still in progress?
  735. *
  736. * @property _isAnimationInProgress
  737. * @private
  738. */
  739. _isAnimationInProgress: false,
  740. /**
  741. * Is the auto-scrolling of Carousel in progress?
  742. *
  743. * @property _isAutoPlayInProgress
  744. * @private
  745. */
  746. _isAutoPlayInProgress: false,
  747. /**
  748. * The table of items in the Carousel.
  749. * The numItems is the number of items in the Carousel, items being the
  750. * array of items in the Carousel. The size is the size of a single
  751. * item in the Carousel. It is cached here for efficiency (to avoid
  752. * computing the size multiple times).
  753. *
  754. * @property _itemsTable
  755. * @private
  756. */
  757. _itemsTable: null,
  758. /**
  759. * The Carousel navigation buttons.
  760. *
  761. * @property _navBtns
  762. * @private
  763. */
  764. _navBtns: null,
  765. /**
  766. * The Carousel navigation.
  767. *
  768. * @property _navEl
  769. * @private
  770. */
  771. _navEl: null,
  772. /**
  773. * Status of the next navigation item.
  774. *
  775. * @property _nextEnabled
  776. * @private
  777. */
  778. _nextEnabled: true,
  779. /**
  780. * The Carousel pages structure.
  781. * This is an object of the total number of pages and the current page.
  782. *
  783. * @property _pages
  784. * @private
  785. */
  786. _pages: null,
  787. /**
  788. * Status of the previous navigation item.
  789. *
  790. * @property _prevEnabled
  791. * @private
  792. */
  793. _prevEnabled: true,
  794. /**
  795. * Whether the Carousel size needs to be recomputed or not?
  796. *
  797. * @property _recomputeSize
  798. * @private
  799. */
  800. _recomputeSize: true,
  801. /*
  802. * CSS classes used by the Carousel component
  803. */
  804. CLASSES: {
  805. /**
  806. * The class name of the Carousel navigation buttons.
  807. *
  808. * @property BUTTON
  809. * @default "yui-carousel-button"
  810. */
  811. BUTTON: "yui-carousel-button",
  812. /**
  813. * The class name of the Carousel element.
  814. *
  815. * @property CAROUSEL
  816. * @default "yui-carousel"
  817. */
  818. CAROUSEL: "yui-carousel",
  819. /**
  820. * The class name of the container of the items in the Carousel.
  821. *
  822. * @property CAROUSEL_EL
  823. * @default "yui-carousel-element"
  824. */
  825. CAROUSEL_EL: "yui-carousel-element",
  826. /**
  827. * The class name of the Carousel's container element.
  828. *
  829. * @property CONTAINER
  830. * @default "yui-carousel-container"
  831. */
  832. CONTAINER: "yui-carousel-container",
  833. /**
  834. * The class name of the Carousel's container element.
  835. *
  836. * @property CONTENT
  837. * @default "yui-carousel-content"
  838. */
  839. CONTENT: "yui-carousel-content",
  840. /**
  841. * The class name of a disabled navigation button.
  842. *
  843. * @property DISABLED
  844. * @default "yui-carousel-button-disabled"
  845. */
  846. DISABLED: "yui-carousel-button-disabled",
  847. /**
  848. * The class name of the first Carousel navigation button.
  849. *
  850. * @property FIRST_NAV
  851. * @default " yui-carousel-first-button"
  852. */
  853. FIRST_NAV: " yui-carousel-first-button",
  854. /**
  855. * The class name of a first disabled navigation button.
  856. *
  857. * @property FIRST_NAV_DISABLED
  858. * @default "yui-carousel-first-button-disabled"
  859. */
  860. FIRST_NAV_DISABLED: "yui-carousel-first-button-disabled",
  861. /**
  862. * The class name of a first page element.
  863. *
  864. * @property FIRST_PAGE
  865. * @default "yui-carousel-nav-first-page"
  866. */
  867. FIRST_PAGE: "yui-carousel-nav-first-page",
  868. /**
  869. * The class name of the Carousel navigation button that has focus.
  870. *
  871. * @property FOCUSSED_BUTTON
  872. * @default "yui-carousel-button-focus"
  873. */
  874. FOCUSSED_BUTTON: "yui-carousel-button-focus",
  875. /**
  876. * The class name of a horizontally oriented Carousel.
  877. *
  878. * @property HORIZONTAL
  879. * @default "yui-carousel-horizontal"
  880. */
  881. HORIZONTAL: "yui-carousel-horizontal",
  882. /**
  883. * The element to be used as the progress indicator when the item
  884. * is still being loaded.
  885. *
  886. * @property ITEM_LOADING
  887. * @default The progress indicator (spinner) image CSS class
  888. */
  889. ITEM_LOADING: "yui-carousel-item-loading",
  890. /**
  891. * The class name that will be set if the Carousel adjusts itself
  892. * for a minimum width.
  893. *
  894. * @property MIN_WIDTH
  895. * @default "yui-carousel-min-width"
  896. */
  897. MIN_WIDTH: "yui-carousel-min-width",
  898. /**
  899. * The navigation element container class name.
  900. *
  901. * @property NAVIGATION
  902. * @default "yui-carousel-nav"
  903. */
  904. NAVIGATION: "yui-carousel-nav",
  905. /**
  906. * The class name of the next Carousel navigation button.
  907. *
  908. * @property NEXT_NAV
  909. * @default " yui-carousel-next-button"
  910. */
  911. NEXT_NAV: " yui-carousel-next-button",
  912. /**
  913. * The class name of the next navigation link. This variable is
  914. * not only used for styling, but also for identifying the link
  915. * within the Carousel container.
  916. *
  917. * @property NEXT_PAGE
  918. * @default "yui-carousel-next"
  919. */
  920. NEXT_PAGE: "yui-carousel-next",
  921. /**
  922. * The class name for the navigation container for prev/next.
  923. *
  924. * @property NAV_CONTAINER
  925. * @default "yui-carousel-buttons"
  926. */
  927. NAV_CONTAINER: "yui-carousel-buttons",
  928. /**
  929. * The class name of the focussed page navigation. This class is
  930. * specifically used for the ugly focus handling in Opera.
  931. *
  932. * @property PAGE_FOCUS
  933. * @default "yui-carousel-nav-page-focus"
  934. */
  935. PAGE_FOCUS: "yui-carousel-nav-page-focus",
  936. /**
  937. * The class name of the previous navigation link. This variable
  938. * is not only used for styling, but also for identifying the link
  939. * within the Carousel container.
  940. *
  941. * @property PREV_PAGE
  942. * @default "yui-carousel-prev"
  943. */
  944. PREV_PAGE: "yui-carousel-prev",
  945. /**
  946. * The class name of the selected item.
  947. *
  948. * @property SELECTED_ITEM
  949. * @default "yui-carousel-item-selected"
  950. */
  951. SELECTED_ITEM: "yui-carousel-item-selected",
  952. /**
  953. * The class name of the selected paging navigation.
  954. *
  955. * @property SELECTED_NAV
  956. * @default "yui-carousel-nav-page-selected"
  957. */
  958. SELECTED_NAV: "yui-carousel-nav-page-selected",
  959. /**
  960. * The class name of a vertically oriented Carousel.
  961. *
  962. * @property VERTICAL
  963. * @default "yui-carousel-vertical"
  964. */
  965. VERTICAL: "yui-carousel-vertical",
  966. /**
  967. * The class name of the (vertical) Carousel's container element.
  968. *
  969. * @property VERTICAL_CONTAINER
  970. * @default "yui-carousel-vertical-container"
  971. */
  972. VERTICAL_CONTAINER: "yui-carousel-vertical-container",
  973. /**
  974. * The class name of a visible Carousel.
  975. *
  976. * @property VISIBLE
  977. * @default "yui-carousel-visible"
  978. */
  979. VISIBLE: "yui-carousel-visible"
  980. },
  981. /*
  982. * Configuration attributes for configuring the Carousel component
  983. */
  984. CONFIG: {
  985. /**
  986. * The offset of the first visible item in the Carousel.
  987. *
  988. * @property FIRST_VISIBLE
  989. * @default 0
  990. */
  991. FIRST_VISIBLE: 0,
  992. /**
  993. * The minimum width of the horizontal Carousel container to support
  994. * the navigation buttons.
  995. *
  996. * @property HORZ_MIN_WIDTH
  997. * @default 180
  998. */
  999. HORZ_MIN_WIDTH: 180,
  1000. /**
  1001. * The maximum number of pager buttons allowed beyond which the UI
  1002. * of the pager would be a drop-down of pages instead of buttons.
  1003. *
  1004. * @property MAX_PAGER_BUTTONS
  1005. * @default 5
  1006. */
  1007. MAX_PAGER_BUTTONS: 5,
  1008. /**
  1009. * The minimum width of the vertical Carousel container to support
  1010. * the navigation buttons.
  1011. *
  1012. * @property VERT_MIN_WIDTH
  1013. * @default 99
  1014. */
  1015. VERT_MIN_WIDTH: 99,
  1016. /**
  1017. * The number of visible items in the Carousel.
  1018. *
  1019. * @property NUM_VISIBLE
  1020. * @default 3
  1021. */
  1022. NUM_VISIBLE: 3
  1023. },
  1024. /*
  1025. * Internationalizable strings in the Carousel component
  1026. */
  1027. STRINGS: {
  1028. /**
  1029. * The content to be used as the progress indicator when the item
  1030. * is still being loaded.
  1031. *
  1032. * @property ITEM_LOADING_CONTENT
  1033. * @default "Loading"
  1034. */
  1035. ITEM_LOADING_CONTENT: "Loading",
  1036. /**
  1037. * The next navigation button name/text.
  1038. *
  1039. * @property NEXT_BUTTON_TEXT
  1040. * @default "Next Page"
  1041. */
  1042. NEXT_BUTTON_TEXT: "Next Page",
  1043. /**
  1044. * The prefix text for the pager in case the UI is a drop-down.
  1045. *
  1046. * @property PAGER_PREFIX_TEXT
  1047. * @default "Go to page "
  1048. */
  1049. PAGER_PREFIX_TEXT: "Go to page ",
  1050. /**
  1051. * The previous navigation button name/text.
  1052. *
  1053. * @property PREVIOUS_BUTTON_TEXT
  1054. * @default "Previous Page"
  1055. */
  1056. PREVIOUS_BUTTON_TEXT: "Previous Page"
  1057. },
  1058. /*
  1059. * Public methods of the Carousel component
  1060. */
  1061. /**
  1062. * Insert or append an item to the Carousel.
  1063. *
  1064. * @method addItem
  1065. * @public
  1066. * @param item {String | Object | HTMLElement} The item to be appended
  1067. * to the Carousel. If the parameter is a string, it is assumed to be
  1068. * the content of the newly created item. If the parameter is an
  1069. * object, it is assumed to supply the content and an optional class
  1070. * and an optional id of the newly created item.
  1071. * @param index {Number} optional The position to where in the list
  1072. * (starts from zero).
  1073. * @return {Boolean} Return true on success, false otherwise
  1074. */
  1075. addItem: function (item, index) {
  1076. var carousel = this,
  1077. className,
  1078. content,
  1079. elId,
  1080. numItems = carousel.get("numItems");
  1081. if (!item) {
  1082. return false;
  1083. }
  1084. if (JS.isString(item) || item.nodeName) {
  1085. content = item.nodeName ? item.innerHTML : item;
  1086. } else if (JS.isObject(item)) {
  1087. content = item.content;
  1088. } else {
  1089. YAHOO.log("Invalid argument to addItem", "error", WidgetName);
  1090. return false;
  1091. }
  1092. className = item.className || "";
  1093. elId = item.id ? item.id : Dom.generateId();
  1094. if (JS.isUndefined(index)) {
  1095. carousel._itemsTable.items.push({
  1096. item : content,
  1097. className : className,
  1098. id : elId
  1099. });
  1100. } else {
  1101. if (index < 0 || index >= numItems) {
  1102. YAHOO.log("Index out of bounds", "error", WidgetName);
  1103. return false;
  1104. }
  1105. carousel._itemsTable.items.splice(index, 0, {
  1106. item : content,
  1107. className : className,
  1108. id : elId
  1109. });
  1110. }
  1111. carousel._itemsTable.numItems++;
  1112. if (numItems < carousel._itemsTable.items.length) {
  1113. carousel.set("numItems", carousel._itemsTable.items.length);
  1114. }
  1115. carousel.fireEvent(itemAddedEvent, { pos: index, ev: itemAddedEvent });
  1116. return true;
  1117. },
  1118. /**
  1119. * Insert or append multiple items to the Carousel.
  1120. *
  1121. * @method addItems
  1122. * @public
  1123. * @param items {Array} An array of items to be added with each item
  1124. * representing an item, index pair [{item, index}, ...]
  1125. * @return {Boolean} Return true on success, false otherwise
  1126. */
  1127. addItems: function (items) {
  1128. var i, n, rv = true;
  1129. if (!JS.isArray(items)) {
  1130. return false;
  1131. }
  1132. for (i = 0, n = items.length; i < n; i++) {
  1133. if (this.addItem(items[i][0], items[i][1]) === false) {
  1134. rv = false;
  1135. }
  1136. }
  1137. return rv;
  1138. },
  1139. /**
  1140. * Remove focus from the Carousel.
  1141. *
  1142. * @method blur
  1143. * @public
  1144. */
  1145. blur: function () {
  1146. this._carouselEl.blur();
  1147. this.fireEvent(blurEvent);
  1148. },
  1149. /**
  1150. * Clears the items from Carousel.
  1151. *
  1152. * @method clearItems
  1153. * public
  1154. */
  1155. clearItems: function () {
  1156. var carousel = this, n = carousel.get("numItems");
  1157. while (n > 0) {
  1158. if (!carousel.removeItem(0)) {
  1159. YAHOO.log("Item could not be removed - missing?",
  1160. "warn", WidgetName);
  1161. }
  1162. /*
  1163. For dynamic loading, the numItems may be much larger than
  1164. the actual number of items in the table. So, set the
  1165. numItems to zero, and break out of the loop if the table
  1166. is already empty.
  1167. */
  1168. if (carousel._itemsTable.numItems === 0) {
  1169. carousel.set("numItems", 0);
  1170. break;
  1171. }
  1172. n--;
  1173. }
  1174. carousel.fireEvent(allItemsRemovedEvent);
  1175. },
  1176. /**
  1177. * Set focus on the Carousel.
  1178. *
  1179. * @method focus
  1180. * @public
  1181. */
  1182. focus: function () {
  1183. var carousel = this,
  1184. first,
  1185. focusEl,
  1186. isSelectionInvisible,
  1187. itemsTable,
  1188. last,
  1189. numVisible,
  1190. selectOnScroll,
  1191. selected,
  1192. selItem;
  1193. // Don't do anything if the Carousel is not rendered
  1194. if (!carousel._hasRendered) {
  1195. return;
  1196. }
  1197. if (carousel.isAnimating()) {
  1198. // this messes up real bad!
  1199. return;
  1200. }
  1201. selItem = carousel.get("selectedItem");
  1202. numVisible = carousel.get("numVisible");
  1203. selectOnScroll = carousel.get("selectOnScroll");
  1204. selected = (selItem >= 0) ?
  1205. carousel.getItem(selItem) : null;
  1206. first = carousel.get("firstVisible");
  1207. last = first + numVisible - 1;
  1208. isSelectionInvisible = (selItem < first || selItem > last);
  1209. focusEl = (selected && selected.id) ?
  1210. Dom.get(selected.id) : null;
  1211. itemsTable = carousel._itemsTable;
  1212. if (!selectOnScroll && isSelectionInvisible) {
  1213. focusEl = (itemsTable && itemsTable.items &&
  1214. itemsTable.items[first]) ?
  1215. Dom.get(itemsTable.items[first].id) : null;
  1216. }
  1217. if (focusEl) {
  1218. try {
  1219. focusEl.focus();
  1220. } catch (ex) {
  1221. // ignore focus errors
  1222. }
  1223. }
  1224. carousel.fireEvent(focusEvent);
  1225. },
  1226. /**
  1227. * Hide the Carousel.
  1228. *
  1229. * @method hide
  1230. * @public
  1231. */
  1232. hide: function () {
  1233. var carousel = this;
  1234. if (carousel.fireEvent(beforeHideEvent) !== false) {
  1235. carousel.removeClass(carousel.CLASSES.VISIBLE);
  1236. carousel.fireEvent(hideEvent);
  1237. }
  1238. },
  1239. /**
  1240. * Initialize the Carousel.
  1241. *
  1242. * @method init
  1243. * @public
  1244. * @param el {HTMLElement | String} The html element that represents
  1245. * the Carousel container.
  1246. * @param attrs {Object} The set of configuration attributes for
  1247. * creating the Carousel.
  1248. */
  1249. init: function (el, attrs) {
  1250. var carousel = this,
  1251. elId = el, // save for a rainy day
  1252. parse = false;
  1253. if (!el) {
  1254. YAHOO.log(el + " is neither an HTML element, nor a string",
  1255. "error", WidgetName);
  1256. return;
  1257. }
  1258. carousel._hasRendered = false;
  1259. carousel._navBtns = { prev: [], next: [] };
  1260. carousel._pages = { el: null, num: 0, cur: 0 };
  1261. carousel._itemsTable = { loading: {}, numItems: 0,
  1262. items: [], size: 0 };
  1263. YAHOO.log("Component initialization", WidgetName);
  1264. if (JS.isString(el)) {
  1265. el = Dom.get(el);
  1266. } else if (!el.nodeName) {
  1267. YAHOO.log(el + " is neither an HTML element, nor a string",
  1268. "error", WidgetName);
  1269. return;
  1270. }
  1271. Carousel.superclass.init.call(carousel, el, attrs);
  1272. if (el) {
  1273. if (!el.id) { // in case the HTML element is passed
  1274. el.setAttribute("id", Dom.generateId());
  1275. }
  1276. parse = carousel._parseCarousel(el);
  1277. if (!parse) {
  1278. carousel._createCarousel(elId);
  1279. }
  1280. } else {
  1281. el = carousel._createCarousel(elId);
  1282. }
  1283. elId = el.id;
  1284. carousel.initEvents();
  1285. if (parse) {
  1286. carousel._parseCarouselItems();
  1287. }
  1288. if (!attrs || typeof attrs.isVertical == "undefined") {
  1289. carousel.set("isVertical", false);
  1290. }
  1291. carousel._parseCarouselNavigation(el);
  1292. carousel._navEl = carousel._setupCarouselNavigation();
  1293. instances[elId] = { object: carousel };
  1294. carousel._loadItems();
  1295. },
  1296. /**
  1297. * Initialize the configuration attributes used to create the Carousel.
  1298. *
  1299. * @method initAttributes
  1300. * @public
  1301. * @param attrs {Object} The set of configuration attributes for
  1302. * creating the Carousel.
  1303. */
  1304. initAttributes: function (attrs) {
  1305. var carousel = this;
  1306. attrs = attrs || {};
  1307. Carousel.superclass.initAttributes.call(carousel, attrs);
  1308. /**
  1309. * @attribute carouselEl
  1310. * @description The type of the Carousel element.
  1311. * @default OL
  1312. * @type Boolean
  1313. */
  1314. carousel.setAttributeConfig("carouselEl", {
  1315. validator : JS.isString,
  1316. value : attrs.carouselEl || "OL"
  1317. });
  1318. /**
  1319. * @attribute carouselItemEl
  1320. * @description The type of the list of items within the Carousel.
  1321. * @default LI
  1322. * @type Boolean
  1323. */
  1324. carousel.setAttributeConfig("carouselItemEl", {
  1325. validator : JS.isString,
  1326. value : attrs.carouselItemEl || "LI"
  1327. });
  1328. /**
  1329. * @attribute currentPage
  1330. * @description The current page number (read-only.)
  1331. * @type Number
  1332. */
  1333. carousel.setAttributeConfig("currentPage", {
  1334. readOnly : true,
  1335. value : 0
  1336. });
  1337. /**
  1338. * @attribute firstVisible
  1339. * @description The index to start the Carousel from (indexes begin
  1340. * from zero)
  1341. * @default 0
  1342. * @type Number
  1343. */
  1344. carousel.setAttributeConfig("firstVisible", {
  1345. method : carousel._setFirstVisible,
  1346. validator : carousel._validateFirstVisible,
  1347. value :
  1348. attrs.firstVisible || carousel.CONFIG.FIRST_VISIBLE
  1349. });
  1350. /**
  1351. * @attribute selectOnScroll
  1352. * @description Set this to true to automatically set focus to
  1353. * follow scrolling in the Carousel.
  1354. * @default true
  1355. * @type Boolean
  1356. */
  1357. carousel.setAttributeConfig("selectOnScroll", {
  1358. validator : JS.isBoolean,
  1359. value : attrs.selectOnScroll || true
  1360. });
  1361. /**
  1362. * @attribute numVisible
  1363. * @description The number of visible items in the Carousel's
  1364. * viewport.
  1365. * @default 3
  1366. * @type Number
  1367. */
  1368. carousel.setAttributeConfig("numVisible", {
  1369. method : carousel._setNumVisible,
  1370. validator : carousel._validateNumVisible,
  1371. value : attrs.numVisible || carousel.CONFIG.NUM_VISIBLE
  1372. });
  1373. /**
  1374. * @attribute numItems
  1375. * @description The number of items in the Carousel.
  1376. * @type Number
  1377. */
  1378. carousel.setAttributeConfig("numItems", {
  1379. method : carousel._setNumItems,
  1380. validator : carousel._validateNumItems,
  1381. value : carousel._itemsTable.numItems
  1382. });
  1383. /**
  1384. * @attribute scrollIncrement
  1385. * @description The number of items to scroll by for arrow keys.
  1386. * @default 1
  1387. * @type Number
  1388. */
  1389. carousel.setAttributeConfig("scrollIncrement", {
  1390. validator : carousel._validateScrollIncrement,
  1391. value : attrs.scrollIncrement || 1
  1392. });
  1393. /**
  1394. * @attribute selectedItem
  1395. * @description The index of the selected item.
  1396. * @type Number
  1397. */
  1398. carousel.setAttributeConfig("selectedItem", {
  1399. method : carousel._setSelectedItem,
  1400. validator : JS.isNumber,
  1401. value : -1
  1402. });
  1403. /**
  1404. * @attribute revealAmount
  1405. * @description The percentage of the item to be revealed on each
  1406. * side of the Carousel (before and after the first and last item
  1407. * in the Carousel's viewport.)
  1408. * @default 0
  1409. * @type Number
  1410. */
  1411. carousel.setAttributeConfig("revealAmount", {
  1412. method : carousel._setRevealAmount,
  1413. validator : carousel._validateRevealAmount,
  1414. value : attrs.revealAmount || 0
  1415. });
  1416. /**
  1417. * @attribute isCircular
  1418. * @description Set this to true to wrap scrolling of the contents
  1419. * in the Carousel.
  1420. * @default false
  1421. * @type Boolean
  1422. */
  1423. carousel.setAttributeConfig("isCircular", {
  1424. validator : JS.isBoolean,
  1425. value : attrs.isCircular || false
  1426. });
  1427. /**
  1428. * @attribute isVertical
  1429. * @description True if the orientation of the Carousel is vertical
  1430. * @default false
  1431. * @type Boolean
  1432. */
  1433. carousel.setAttributeConfig("isVertical", {
  1434. method : carousel._setOrientation,
  1435. validator : JS.isBoolean,
  1436. value : attrs.isVertical || false
  1437. });
  1438. /**
  1439. * @attribute navigation
  1440. * @description The set of navigation controls for Carousel
  1441. * @default <br>
  1442. * { prev: null, // the previous navigation element<br>
  1443. * next: null } // the next navigation element
  1444. * @type Object
  1445. */
  1446. carousel.setAttributeConfig("navigation", {
  1447. method : carousel._setNavigation,
  1448. validator : carousel._validateNavigation,
  1449. value :
  1450. attrs.navigation || {prev: null,next: null,page: null}
  1451. });
  1452. /**
  1453. * @attribute animation
  1454. * @description The optional animation attributes for the Carousel.
  1455. * @default <br>
  1456. * { speed: 0, // the animation speed (in seconds)<br>
  1457. * effect: null } // the animation effect (like
  1458. * YAHOO.util.Easing.easeOut)
  1459. * @type Object
  1460. */
  1461. carousel.setAttributeConfig("animation", {
  1462. validator : carousel._validateAnimation,
  1463. value : attrs.animation || { speed: 0, effect: null }
  1464. });
  1465. /**
  1466. * @attribute autoPlay
  1467. * @description Set this to time in milli-seconds to have the
  1468. * Carousel automatically scroll the contents.
  1469. * @type Number
  1470. * @deprecated Use autoPlayInterval instead.
  1471. */
  1472. carousel.setAttributeConfig("autoPlay", {
  1473. validator : JS.isNumber,
  1474. value : attrs.autoPlay || 0
  1475. });
  1476. /**
  1477. * @attribute autoPlayInterval
  1478. * @description The delay in milli-seconds for scrolling the
  1479. * Carousel during auto-play.
  1480. * Note: The startAutoPlay() method needs to be invoked to trigger
  1481. * automatic scrolling of Carousel.
  1482. * @type Number
  1483. */
  1484. carousel.setAttributeConfig("autoPlayInterval", {
  1485. validator : JS.isNumber,
  1486. value : attrs.autoPlayInterval || 0
  1487. });
  1488. },
  1489. /**
  1490. * Initialize and bind the event handlers.
  1491. *
  1492. * @method initEvents
  1493. * @public
  1494. */
  1495. initEvents: function () {
  1496. var carousel = this,
  1497. cssClass = carousel.CLASSES,
  1498. focussedLi;
  1499. carousel.on("keydown", carousel._keyboardEventHandler);
  1500. carousel.on(afterScrollEvent, syncNavigation);
  1501. carousel.on(itemAddedEvent, syncUi);
  1502. carousel.on(itemRemovedEvent, syncUi);
  1503. carousel.on(itemSelectedEvent, function () {
  1504. if (carousel._hasFocus) {
  1505. carousel.focus();
  1506. }
  1507. });
  1508. carousel.on(loadItemsEvent, syncUi);
  1509. carousel.on(allItemsRemovedEvent, function (ev) {
  1510. carousel.scrollTo(0);
  1511. syncNavigation.call(carousel);
  1512. syncPagerUi.call(carousel);
  1513. });
  1514. carousel.on(pageChangeEvent, syncPagerUi, carousel);
  1515. carousel.on(renderEvent, function (ev) {
  1516. carousel.set("selectedItem", carousel.get("firstVisible"));
  1517. syncNavigation.call(carousel, ev);
  1518. syncPagerUi.call(carousel, ev);
  1519. carousel._setClipContainerSize();
  1520. });
  1521. carousel.on("selectedItemChange", function (ev) {
  1522. setItemSelection.call(carousel, ev.newValue, ev.prevValue);
  1523. if (ev.newValue >= 0) {
  1524. carousel._updateTabIndex(
  1525. carousel.getElementForItem(ev.newValue));
  1526. }
  1527. carousel.fireEvent(itemSelectedEvent, ev.newValue);
  1528. });
  1529. carousel.on(uiUpdateEvent, function (ev) {
  1530. syncNavigation.call(carousel, ev);
  1531. syncPagerUi.call(carousel, ev);
  1532. });
  1533. carousel.on("firstVisibleChange", function (ev) {
  1534. if (!carousel.get("selectOnScroll")) {
  1535. if (ev.newValue >= 0) {
  1536. carousel._updateTabIndex(
  1537. carousel.getElementForItem(ev.newValue));
  1538. }
  1539. }
  1540. });
  1541. // Handle item selection on mouse click
  1542. carousel.on("click", function (ev) {
  1543. if (carousel.isAutoPlayOn()) {
  1544. carousel.stopAutoPlay();
  1545. }
  1546. carousel._itemClickHandler(ev);
  1547. carousel._pagerClickHandler(ev);
  1548. });
  1549. // Restore the focus on the navigation buttons
  1550. Event.onFocus(carousel.get("element"), function (ev, obj) {
  1551. var target = Event.getTarget(ev);
  1552. if (target && target.nodeName.toUpperCase() == "A" &&
  1553. Dom.getAncestorByClassName(target, cssClass.NAVIGATION)) {
  1554. if (focussedLi) {
  1555. Dom.removeClass(focussedLi, cssClass.PAGE_FOCUS);
  1556. }
  1557. focussedLi = target.parentNode;
  1558. Dom.addClass(focussedLi, cssClass.PAGE_FOCUS);
  1559. } else {
  1560. if (focussedLi) {
  1561. Dom.removeClass(focussedLi, cssClass.PAGE_FOCUS);
  1562. }
  1563. }
  1564. obj._hasFocus = true;
  1565. obj._updateNavButtons(Event.getTarget(ev), true);
  1566. }, carousel);
  1567. Event.onBlur(carousel.get("element"), function (ev, obj) {
  1568. obj._hasFocus = false;
  1569. obj._updateNavButtons(Event.getTarget(ev), false);
  1570. }, carousel);
  1571. },
  1572. /**
  1573. * Return true if the Carousel is still animating, or false otherwise.
  1574. *
  1575. * @method isAnimating
  1576. * @return {Boolean} Return true if animation is still in progress, or
  1577. * false otherwise.
  1578. * @public
  1579. */
  1580. isAnimating: function () {
  1581. return this._isAnimationInProgress;
  1582. },
  1583. /**
  1584. * Return true if the auto-scrolling of Carousel is "on", or false
  1585. * otherwise.
  1586. *
  1587. * @method isAutoPlayOn
  1588. * @return {Boolean} Return true if autoPlay is "on", or false
  1589. * otherwise.
  1590. * @public
  1591. */
  1592. isAutoPlayOn: function () {
  1593. return this._isAutoPlayInProgress;
  1594. },
  1595. /**
  1596. * Return the carouselItemEl at index or null if the index is not
  1597. * found.
  1598. *
  1599. * @method getElementForItem
  1600. * @param index {Number} The index of the item to be returned
  1601. * @return {Element} Return the item at index or null if not found
  1602. * @public
  1603. */
  1604. getElementForItem: function (index) {
  1605. var carousel = this;
  1606. if (index < 0 || index >= carousel.get("numItems")) {
  1607. YAHOO.log("Index out of bounds", "error", WidgetName);
  1608. return null;
  1609. }
  1610. // TODO: may be cache the item
  1611. if (carousel._itemsTable.numItems > index) {
  1612. if (!JS.isUndefined(carousel._itemsTable.items[index])) {
  1613. return Dom.get(carousel._itemsTable.items[index].id);
  1614. }
  1615. }
  1616. return null;
  1617. },
  1618. /**
  1619. * Return the carouselItemEl for all items in the Carousel.
  1620. *
  1621. * @method getElementForItems
  1622. * @return {Array} Return all the items
  1623. * @public
  1624. */
  1625. getElementForItems: function () {
  1626. var carousel = this, els = [], i;
  1627. for (i = 0; i < carousel._itemsTable.numItems; i++) {
  1628. els.push(carousel.getElementForItem(i));
  1629. }
  1630. return els;
  1631. },
  1632. /**
  1633. * Return the item at index or null if the index is not found.
  1634. *
  1635. * @method getItem
  1636. * @param index {Number} The index of the item to be returned
  1637. * @return {Object} Return the item at index or null if not found
  1638. * @public
  1639. */
  1640. getItem: function (index) {
  1641. var carousel = this;
  1642. if (index < 0 || index >= carousel.get("numItems")) {
  1643. YAHOO.log("Index out of bounds", "error", WidgetName);
  1644. return null;
  1645. }
  1646. if (carousel._itemsTable.numItems > index) {
  1647. if (!JS.isUndefined(carousel._itemsTable.items[index])) {
  1648. return carousel._itemsTable.items[index];
  1649. }
  1650. }
  1651. return null;
  1652. },
  1653. /**
  1654. * Return all items as an array.
  1655. *
  1656. * @method getItems
  1657. * @return {Array} Return all items in the Carousel
  1658. * @public
  1659. */
  1660. getItems: function (index) {
  1661. return this._itemsTable.items;
  1662. },
  1663. /**
  1664. * Return the position of the Carousel item that has the id "id", or -1
  1665. * if the id is not found.
  1666. *
  1667. * @method getItemPositionById
  1668. * @param index {Number} The index of the item to be returned
  1669. * @public
  1670. */
  1671. getItemPositionById: function (id) {
  1672. var carousel = this, i = 0, n = carousel._itemsTable.numItems;
  1673. while (i < n) {
  1674. if (!JS.isUndefined(carousel._itemsTable.items[i])) {
  1675. if (carousel._itemsTable.items[i].id == id) {
  1676. return i;
  1677. }
  1678. }
  1679. i++;
  1680. }
  1681. return -1;
  1682. },
  1683. /**
  1684. * Return all visible items as an array.
  1685. *
  1686. * @method getVisibleItems
  1687. * @return {Array} The array of visible items
  1688. * @public
  1689. */
  1690. getVisibleItems: function () {
  1691. var carousel = this,
  1692. i = carousel.get("firstVisible"),
  1693. n = i + carousel.get("numVisible"),
  1694. r = [];
  1695. while (i < n) {
  1696. r.push(carousel.getElementForItem(i));
  1697. i++;
  1698. }
  1699. return r;
  1700. },
  1701. /**
  1702. * Remove an item at index from the Carousel.
  1703. *
  1704. * @method removeItem
  1705. * @public
  1706. * @param index {Number} The position to where in the list (starts from
  1707. * zero).
  1708. * @return {Boolean} Return true on success, false otherwise
  1709. */
  1710. removeItem: function (index) {
  1711. var carousel = this,
  1712. item,
  1713. num = carousel.get("numItems");
  1714. if (index < 0 || index >= num) {
  1715. YAHOO.log("Index out of bounds", "error", WidgetName);
  1716. return false;
  1717. }
  1718. item = carousel._itemsTable.items.splice(index, 1);
  1719. if (item && item.length == 1) {
  1720. carousel._itemsTable.numItems--;
  1721. carousel.set("numItems", num - 1);
  1722. carousel.fireEvent(itemRemovedEvent,
  1723. { item: item[0], pos: index, ev: itemRemovedEvent });
  1724. return true;
  1725. }
  1726. return false;
  1727. },
  1728. /**
  1729. * Render the Carousel.
  1730. *
  1731. * @method render
  1732. * @public
  1733. * @param appendTo {HTMLElement | String} The element to which the
  1734. * Carousel should be appended prior to rendering.
  1735. * @return {Boolean} Status of the operation
  1736. */
  1737. render: function (appendTo) {
  1738. var carousel = this,
  1739. cssClass = carousel.CLASSES;
  1740. carousel.addClass(cssClass.CAROUSEL);
  1741. if (!carousel._clipEl) {
  1742. carousel._clipEl = carousel._createCarouselClip();
  1743. carousel._clipEl.appendChild(carousel._carouselEl);
  1744. }
  1745. if (appendTo) {
  1746. carousel.appendChild(carousel._clipEl);
  1747. carousel.appendTo(appendTo);
  1748. } else {
  1749. if (!Dom.inDocument(carousel.get("element"))) {
  1750. YAHOO.log("Nothing to render. The container should be " +
  1751. "within the document if appendTo is not " +
  1752. "specified", "error", WidgetName);
  1753. return false;
  1754. }
  1755. carousel.appendChild(carousel._clipEl);
  1756. }
  1757. if (carousel.get("isVertical")) {
  1758. carousel.addClass(cssClass.VERTICAL);
  1759. } else {
  1760. carousel.addClass(cssClass.HORIZONTAL);
  1761. }
  1762. if (carousel.get("numItems") < 1) {
  1763. YAHOO.log("No items in the Carousel to render", "warn",
  1764. WidgetName);
  1765. return false;
  1766. }
  1767. carousel._refreshUi();
  1768. return true;
  1769. },
  1770. /**
  1771. * Scroll the Carousel by an item backward.
  1772. *
  1773. * @method scrollBackward
  1774. * @public
  1775. */
  1776. scrollBackward: function () {
  1777. var carousel = this;