2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
8 * The Carousel module provides a widget for browsing among a set of like
9 * objects represented pictorially.
12 * @requires yahoo, dom, event, element
14 * @namespace YAHOO.widget
15 * @title Carousel Widget
20 var WidgetName; // forward declaration
23 * The Carousel widget.
26 * @extends YAHOO.util.Element
28 * @param el {HTMLElement | String} The HTML element that represents the
29 * the container that houses the Carousel.
30 * @param cfg {Object} (optional) The configuration values
32 YAHOO.widget.Carousel = function (el, cfg) {
33 YAHOO.log("Component creation", WidgetName);
35 YAHOO.widget.Carousel.superclass.constructor.call(this, el, cfg);
39 * Private variables of the Carousel component
42 /* Some abbreviations to avoid lengthy typing and lookups. */
43 var Carousel = YAHOO.widget.Carousel,
45 Event = YAHOO.util.Event,
53 WidgetName = "Carousel";
56 * The internal table of Carousel instances.
63 * Custom events of the Carousel component
68 * @description Fires when the Carousel has scrolled to the previous or
69 * next page. Passes back the index of the first and last visible items in
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
75 afterScrollEvent = "afterScroll",
78 * @event allItemsRemovedEvent
79 * @description Fires when all items have been removed from the Carousel.
81 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
82 * for more information on listening for this event.
83 * @type YAHOO.util.CustomEvent
85 allItemsRemovedEvent = "allItemsRemoved",
89 * @description Fires before the Carousel is hidden. See
90 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
91 * for more information on listening for this event.
92 * @type YAHOO.util.CustomEvent
94 beforeHideEvent = "beforeHide",
97 * @event beforePageChange
98 * @description Fires when the Carousel is about to scroll to the previous
99 * or next page. Passes back the page number of the current page. Note
100 * that the first page number is zero. See
101 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
102 * for more information on listening for this event.
103 * @type YAHOO.util.CustomEvent
105 beforePageChangeEvent = "beforePageChange",
108 * @event beforeScroll
109 * @description Fires when the Carousel is about to scroll to the previous
110 * or next page. Passes back the index of the first and last visible items
111 * in the Carousel and the direction (backward/forward) of the scroll. See
112 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
113 * for more information on listening for this event.
114 * @type YAHOO.util.CustomEvent
116 beforeScrollEvent = "beforeScroll",
120 * @description Fires when the Carousel is about to be shown. See
121 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
122 * for more information on listening for this event.
123 * @type YAHOO.util.CustomEvent
125 beforeShowEvent = "beforeShow",
129 * @description Fires when the Carousel loses focus. See
130 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
131 * for more information on listening for this event.
132 * @type YAHOO.util.CustomEvent
138 * @description Fires when the Carousel gains focus. See
139 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
140 * for more information on listening for this event.
141 * @type YAHOO.util.CustomEvent
143 focusEvent = "focus",
147 * @description Fires when the Carousel is hidden. See
148 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
149 * for more information on listening for this event.
150 * @type YAHOO.util.CustomEvent
156 * @description Fires when an item has been added to the Carousel. Passes
157 * back the content of the item that would be added, the index at which the
158 * item would be added, and the event itself. See
159 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
160 * for more information on listening for this event.
161 * @type YAHOO.util.CustomEvent
163 itemAddedEvent = "itemAdded",
167 * @description Fires when an item has been removed from the Carousel.
168 * Passes back the content of the item that would be removed, the index
169 * from which the item would be removed, and the event itself. See
170 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
171 * for more information on listening for this event.
172 * @type YAHOO.util.CustomEvent
174 itemRemovedEvent = "itemRemoved",
177 * @event itemReplaced
178 * @description Fires when an item has been replaced in the Carousel.
179 * Passes back the content of the item that was replaced, the content
180 * of the new item, the index where the replacement occurred, and the event
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
186 itemReplacedEvent = "itemReplaced",
189 * @event itemSelected
190 * @description Fires when an item has been selected in the Carousel.
191 * Passes back the index of the selected item in the Carousel. Note, that
192 * the index begins from zero. See
193 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
194 * for more information on listening for this event.
195 * @type YAHOO.util.CustomEvent
197 itemSelectedEvent = "itemSelected",
201 * @description Fires when the Carousel needs more items to be loaded for
202 * displaying them. Passes back the first and last visible items in the
203 * Carousel, and the number of items needed to be loaded. See
204 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
205 * for more information on listening for this event.
206 * @type YAHOO.util.CustomEvent
208 loadItemsEvent = "loadItems",
211 * @event navigationStateChange
212 * @description Fires when the state of either one of the navigation
213 * buttons are changed from enabled to disabled or vice versa. Passes back
214 * the state (true/false) of the previous and next buttons. The value true
215 * signifies the button is enabled, false signifies disabled. See
216 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
217 * for more information on listening for this event.
218 * @type YAHOO.util.CustomEvent
220 navigationStateChangeEvent = "navigationStateChange",
224 * @description Fires after the Carousel has scrolled to the previous or
225 * next page. Passes back the page number of the current page. Note
226 * that the first page number is zero. See
227 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
228 * for more information on listening for this event.
229 * @type YAHOO.util.CustomEvent
231 pageChangeEvent = "pageChange",
236 * @description Fires when the Carousel is rendered. See
237 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
238 * for more information on listening for this event.
239 * @type YAHOO.util.CustomEvent
241 renderEvent = "render",
245 * @description Fires when the Carousel is shown. See
246 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
247 * for more information on listening for this event.
248 * @type YAHOO.util.CustomEvent
253 * @event startAutoPlay
254 * @description Fires when the auto play has started in the Carousel. See
255 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
256 * for more information on listening for this event.
257 * @type YAHOO.util.CustomEvent
259 startAutoPlayEvent = "startAutoPlay",
262 * @event stopAutoPlay
263 * @description Fires when the auto play has been stopped in the Carousel.
265 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
266 * for more information on listening for this event.
267 * @type YAHOO.util.CustomEvent
269 stopAutoPlayEvent = "stopAutoPlay",
273 * @event uiUpdateEvent
274 * @description Fires when the UI has been updated.
276 * <a href="YAHOO.util.Element.html#addListener">Element.addListener</a>
277 * for more information on listening for this event.
278 * @type YAHOO.util.CustomEvent
280 uiUpdateEvent = "uiUpdate";
283 * Private helper functions used by the Carousel component
287 * Set multiple styles on one element.
289 * @param el {HTMLElement} The element to set styles on
290 * @param style {Object} top:"10px", left:"0px", etc.
293 function setStyles(el, styles) {
296 for (which in styles) {
297 if (styles.hasOwnProperty(which)) {
298 Dom.setStyle(el, which, styles[which]);
304 * Create an element, set its class name and optionally install the element
306 * @method createElement
307 * @param el {String} The element to be created
308 * @param attrs {Object} Configuration of parent, class and id attributes.
309 * If the content is specified, it is inserted after creation of the
310 * element. The content can also be an HTML element in which case it would
311 * be appended as a child node of the created element.
314 function createElement(el, attrs) {
315 var newEl = document.createElement(el);
318 if (attrs.className) {
319 Dom.addClass(newEl, attrs.className);
323 setStyles(newEl, attrs.styles);
327 attrs.parent.appendChild(newEl);
331 newEl.setAttribute("id", attrs.id);
335 if (attrs.content.nodeName) {
336 newEl.appendChild(attrs.content);
338 newEl.innerHTML = attrs.content;
346 * Get the computed style of an element.
349 * @param el {HTMLElement} The element for which the style needs to be
351 * @param style {String} The style attribute
352 * @param type {String} "int", "float", etc. (defaults to int)
355 function getStyle(el, style, type) {
362 function getStyleIntVal(el, style) {
366 * XXX: Safari calculates incorrect marginRight for an element
367 * which has its parent element style set to overflow: hidden
368 * https://bugs.webkit.org/show_bug.cgi?id=13343
369 * Let us assume marginLeft == marginRight
371 if (style == "marginRight" && YAHOO.env.ua.webkit) {
372 val = parseInt(Dom.getStyle(el, "marginLeft"), 10);
374 val = parseInt(Dom.getStyle(el, style), 10);
377 return JS.isNumber(val) ? val : 0;
380 function getStyleFloatVal(el, style) {
384 * XXX: Safari calculates incorrect marginRight for an element
385 * which has its parent element style set to overflow: hidden
386 * https://bugs.webkit.org/show_bug.cgi?id=13343
387 * Let us assume marginLeft == marginRight
389 if (style == "marginRight" && YAHOO.env.ua.webkit) {
390 val = parseFloat(Dom.getStyle(el, "marginLeft"));
392 val = parseFloat(Dom.getStyle(el, style));
395 return JS.isNumber(val) ? val : 0;
398 if (typeof type == "undefined") {
404 value = el.offsetHeight;
406 value += getStyleIntVal(el, "marginTop") +
407 getStyleIntVal(el, "marginBottom");
409 value = getStyleFloatVal(el, "height") +
410 getStyleIntVal(el, "marginTop") +
411 getStyleIntVal(el, "marginBottom") +
412 getStyleIntVal(el, "borderTopWidth") +
413 getStyleIntVal(el, "borderBottomWidth") +
414 getStyleIntVal(el, "paddingTop") +
415 getStyleIntVal(el, "paddingBottom");
419 value = el.offsetWidth;
421 value += getStyleIntVal(el, "marginLeft") +
422 getStyleIntVal(el, "marginRight");
424 value = getStyleFloatVal(el, "width") +
425 getStyleIntVal(el, "marginLeft") +
426 getStyleIntVal(el, "marginRight") +
427 getStyleIntVal(el, "borderLeftWidth") +
428 getStyleIntVal(el, "borderRightWidth") +
429 getStyleIntVal(el, "paddingLeft") +
430 getStyleIntVal(el, "paddingRight");
435 value = getStyleIntVal(el, style);
436 } else if (type == "float") {
437 value = getStyleFloatVal(el, style);
439 value = Dom.getStyle(el, style);
448 * Compute and return the height or width of a single Carousel item
449 * depending upon the orientation.
451 * @method getCarouselItemSize
452 * @param which {String} "height" or "width" to be returned. If this is
453 * passed explicitly, the calculated size is not cached.
456 function getCarouselItemSize(which) {
461 first = carousel.get("firstVisible"),
464 if (carousel._itemsTable.numItems === 0) {
468 item = carousel._itemsTable.items[first] ||
469 carousel._itemsTable.loading[first];
471 if (JS.isUndefined(item)) {
475 child = Dom.get(item.id);
477 if (typeof which == "undefined") {
478 vertical = carousel.get("isVertical");
480 vertical = which == "height";
483 if (this._itemAttrCache[which]) {
484 return this._itemAttrCache[which];
488 size = getStyle(child, "height");
490 size = getStyle(child, "width");
493 this._itemAttrCache[which] = size;
499 * Return the size of a part of the item (reveal).
501 * @method getRevealSize
504 function getRevealSize() {
505 var carousel = this, isVertical, sz;
507 isVertical = carousel.get("isVertical");
508 sz = getCarouselItemSize.call(carousel,
509 isVertical ? "height" : "width");
510 return (sz * carousel.get("revealAmount") / 100);
514 * Compute and return the position of a Carousel item based on its
517 * @method getCarouselItemPosition
518 * @param position {Number} The position of the Carousel item.
521 function getCarouselItemPosition(pos) {
523 itemsPerRow = carousel._cols,
524 itemsPerCol = carousel._rows,
537 itemsTable = carousel._itemsTable,
538 items = itemsTable.items,
539 loading = itemsTable.loading;
541 isVertical = carousel.get("isVertical");
542 sz = getCarouselItemSize.call(carousel,
543 isVertical ? "height" : "width");
544 rsz = getRevealSize.call(carousel);
546 // adjust for items not yet loaded
547 while (index < pos) {
548 if (!items[index] && !loading[index]) {
556 page = this.getPageForItem(pos);
558 itemsRow = Math.floor(pos/itemsPerRow);
561 styles.top = (top + rsz) + "px";
563 sz = getCarouselItemSize.call(carousel, "width");
565 itemsCol = pos % itemsPerRow;
568 styles.left = left + "px";
570 itemsCol = pos % itemsPerRow;
571 sentinel = (page - 1) * itemsPerRow;
572 delta = itemsCol + sentinel;
574 styles.left = (left + rsz) + "px";
576 sz = getCarouselItemSize.call(carousel, "height");
578 itemsRow = Math.floor(pos/itemsPerRow);
579 sentinel = (page - 1) * itemsPerCol;
580 delta = itemsRow - sentinel;
583 styles.top = top + "px";
588 styles.top = ((pos * sz) + rsz) + "px";
591 styles.left = ((pos * sz) + rsz) + "px";
599 * Return the index of the first item in the view port for displaying item
602 * @method getFirstVisibleForPosition
603 * @param pos {Number} The position of the item to be displayed
606 function getFirstVisibleForPosition(pos) {
607 var num = this.get("numVisible");
608 return Math.floor(pos / num) * num;
612 * Return the scrolling offset size given the number of elements to
615 * @method getScrollOffset
616 * @param delta {Number} The delta number of elements to scroll by.
619 function getScrollOffset(delta) {
623 itemSize = getCarouselItemSize.call(this);
624 size = itemSize * delta;
630 * Scroll the Carousel by a page backward.
632 * @method scrollPageBackward
633 * @param {Event} ev The event object
634 * @param {Object} obj The context object
637 function scrollPageBackward(ev, obj) {
638 obj.scrollPageBackward();
639 Event.preventDefault(ev);
643 * Scroll the Carousel by a page forward.
645 * @method scrollPageForward
646 * @param {Event} ev The event object
647 * @param {Object} obj The context object
650 function scrollPageForward(ev, obj) {
651 obj.scrollPageForward();
652 Event.preventDefault(ev);
656 * Set the selected item.
658 * @method setItemSelection
659 * @param {Number} newpos The index of the new position
660 * @param {Number} oldpos The index of the previous position
663 function setItemSelection(newpos, oldpos) {
665 cssClass = carousel.CLASSES,
667 firstItem = carousel._firstItem,
668 isCircular = carousel.get("isCircular"),
669 numItems = carousel.get("numItems"),
670 numVisible = carousel.get("numVisible"),
672 sentinel = firstItem + numVisible - 1;
674 if (position >= 0 && position < numItems) {
675 if (!JS.isUndefined(carousel._itemsTable.items[position])) {
676 el = Dom.get(carousel._itemsTable.items[position].id);
678 Dom.removeClass(el, cssClass.SELECTED_ITEM);
683 if (JS.isNumber(newpos)) {
684 newpos = parseInt(newpos, 10);
685 newpos = JS.isNumber(newpos) ? newpos : 0;
690 if (JS.isUndefined(carousel._itemsTable.items[newpos])) {
691 newpos = getFirstVisibleForPosition.call(carousel, newpos);
692 carousel.scrollTo(newpos); // still loading the item
695 if (!JS.isUndefined(carousel._itemsTable.items[newpos])) {
696 el = Dom.get(carousel._itemsTable.items[newpos].id);
698 Dom.addClass(el, cssClass.SELECTED_ITEM);
702 if (newpos < firstItem || newpos > sentinel) { // out of focus
703 newpos = getFirstVisibleForPosition.call(carousel, newpos);
704 carousel.scrollTo(newpos);
709 * Fire custom events for enabling/disabling navigation elements.
711 * @method syncNavigation
714 function syncNavigation() {
717 cssClass = carousel.CLASSES,
722 // Don't do anything if the Carousel is not rendered
723 if (!carousel._hasRendered) {
727 navigation = carousel.get("navigation");
728 sentinel = carousel._firstItem + carousel.get("numVisible");
730 if (navigation.prev) {
731 if (carousel.get("numItems") === 0 || carousel._firstItem === 0) {
732 if (carousel.get("numItems") === 0 ||
733 !carousel.get("isCircular")) {
734 Event.removeListener(navigation.prev, "click",
736 Dom.addClass(navigation.prev, cssClass.FIRST_NAV_DISABLED);
737 for (i = 0; i < carousel._navBtns.prev.length; i++) {
738 carousel._navBtns.prev[i].setAttribute("disabled",
741 carousel._prevEnabled = false;
743 attach = !carousel._prevEnabled;
746 attach = !carousel._prevEnabled;
750 Event.on(navigation.prev, "click", scrollPageBackward,
752 Dom.removeClass(navigation.prev, cssClass.FIRST_NAV_DISABLED);
753 for (i = 0; i < carousel._navBtns.prev.length; i++) {
754 carousel._navBtns.prev[i].removeAttribute("disabled");
756 carousel._prevEnabled = true;
761 if (navigation.next) {
762 if (sentinel >= carousel.get("numItems")) {
763 if (!carousel.get("isCircular")) {
764 Event.removeListener(navigation.next, "click",
766 Dom.addClass(navigation.next, cssClass.DISABLED);
767 for (i = 0; i < carousel._navBtns.next.length; i++) {
768 carousel._navBtns.next[i].setAttribute("disabled",
771 carousel._nextEnabled = false;
773 attach = !carousel._nextEnabled;
776 attach = !carousel._nextEnabled;
780 Event.on(navigation.next, "click", scrollPageForward,
782 Dom.removeClass(navigation.next, cssClass.DISABLED);
783 for (i = 0; i < carousel._navBtns.next.length; i++) {
784 carousel._navBtns.next[i].removeAttribute("disabled");
786 carousel._nextEnabled = true;
790 carousel.fireEvent(navigationStateChangeEvent,
791 { next: carousel._nextEnabled, prev: carousel._prevEnabled });
795 * Synchronize and redraw the Pager UI if necessary.
797 * @method syncPagerUi
800 function syncPagerUi(page) {
801 var carousel = this, numPages, numVisible;
803 // Don't do anything if the Carousel is not rendered
804 if (!carousel._hasRendered) {
808 numVisible = carousel.get("numVisible");
810 if (!JS.isNumber(page)) {
811 page = Math.floor(carousel.get("selectedItem") / numVisible);
814 numPages = Math.ceil(carousel.get("numItems") / numVisible);
816 carousel._pages.num = numPages;
817 carousel._pages.cur = page;
819 if (numPages > carousel.CONFIG.MAX_PAGER_BUTTONS) {
820 carousel._updatePagerMenu();
822 carousel._updatePagerButtons();
827 * Get full dimensions of an element.
829 * @method getDimensions
830 * @param {Object} el The element to get the dimensions of
831 * @param {String} which Get the height or width of an element
834 function getDimensions(el, which) {
837 return getStyle(el, "marginTop") +
838 getStyle(el, "marginBottom") +
839 getStyle(el, "paddingTop") +
840 getStyle(el, "paddingBottom") +
841 getStyle(el, "borderTopWidth") +
842 getStyle(el, "borderBottomWidth");
844 return getStyle(el, "marginLeft") +
845 getStyle(el, "marginRight") +
846 getStyle(el, "paddingLeft") +
847 getStyle(el, "paddingRight") +
848 getStyle(el, "borderLeftWidth") +
849 getStyle(el, "borderRightWidth");
854 return getStyle(el, which);
859 * Call the appropriate methods on events fired when an item is added, or
860 * removed for synchronizing the DOM.
863 * @param {Object} o The item that needs to be added or removed
869 if (!JS.isObject(o)) {
875 carousel._syncUiForItemAdd(o);
877 case itemRemovedEvent:
878 carousel._syncUiForItemRemove(o);
880 case itemReplacedEvent:
881 carousel._syncUiForItemReplace(o);
884 carousel._syncUiForLazyLoading(o);
888 carousel.fireEvent(uiUpdateEvent);
892 * Update the state variables after scrolling the Carousel view port.
894 * @method updateStateAfterScroll
895 * @param {Integer} item The index to which the Carousel has scrolled to.
896 * @param {Integer} sentinel The last element in the view port.
899 function updateStateAfterScroll(item, sentinel) {
901 page = carousel.get("currentPage"),
903 numPerPage = carousel.get("numVisible");
905 newPage = parseInt(carousel._firstItem / numPerPage, 10);
906 if (newPage != page) {
907 carousel.setAttributeConfig("currentPage", { value: newPage });
908 carousel.fireEvent(pageChangeEvent, newPage);
911 if (carousel.get("selectOnScroll")) {
912 if (carousel.get("selectedItem") != carousel._selectedItem) {
913 carousel.set("selectedItem", carousel._selectedItem);
917 clearTimeout(carousel._autoPlayTimer);
918 delete carousel._autoPlayTimer;
919 if (carousel.isAutoPlayOn()) {
920 carousel.startAutoPlay();
923 carousel.fireEvent(afterScrollEvent,
924 { first: carousel._firstItem,
930 * Static members and methods of the Carousel component
934 * Return the appropriate Carousel object based on the id associated with
935 * the Carousel element or false if none match.
940 Carousel.getById = function (id) {
941 return instances[id] ? instances[id].object : false;
944 YAHOO.extend(Carousel, YAHOO.util.Element, {
947 * Internal variables used within the Carousel component
951 * Number of rows for a multirow carousel.
959 * Number of cols for a multirow carousel.
967 * The Animation object.
975 * The Carousel element.
977 * @property _carouselEl
983 * The Carousel clipping container element.
991 * The current first index of the Carousel.
993 * @property _firstItem
999 * Does the Carousel element have focus?
1001 * @property _hasFocus
1007 * Is the Carousel rendered already?
1009 * @property _hasRendered
1012 _hasRendered: false,
1015 * Is the animation still in progress?
1017 * @property _isAnimationInProgress
1020 _isAnimationInProgress: false,
1023 * Is the auto-scrolling of Carousel in progress?
1025 * @property _isAutoPlayInProgress
1028 _isAutoPlayInProgress: false,
1031 * The table of items in the Carousel.
1032 * The numItems is the number of items in the Carousel, items being the
1033 * array of items in the Carousel. The size is the size of a single
1034 * item in the Carousel. It is cached here for efficiency (to avoid
1035 * computing the size multiple times).
1037 * @property _itemsTable
1043 * The Carousel navigation buttons.
1045 * @property _navBtns
1051 * The Carousel navigation.
1059 * Status of the next navigation item.
1061 * @property _nextEnabled
1067 * The Carousel pages structure.
1068 * This is an object of the total number of pages and the current page.
1076 * The Carousel pagination structure.
1078 * @property _pagination
1084 * Status of the previous navigation item.
1086 * @property _prevEnabled
1092 * Whether the Carousel size needs to be recomputed or not?
1094 * @property _recomputeSize
1097 _recomputeSize: true,
1100 * Cache the Carousel item attributes.
1102 * @property _itemAttrCache
1108 * CSS classes used by the Carousel component
1114 * The class name of the Carousel navigation buttons.
1117 * @default "yui-carousel-button"
1119 BUTTON: "yui-carousel-button",
1122 * The class name of the Carousel element.
1124 * @property CAROUSEL
1125 * @default "yui-carousel"
1127 CAROUSEL: "yui-carousel",
1130 * The class name of the container of the items in the Carousel.
1132 * @property CAROUSEL_EL
1133 * @default "yui-carousel-element"
1135 CAROUSEL_EL: "yui-carousel-element",
1138 * The class name of the Carousel's container element.
1140 * @property CONTAINER
1141 * @default "yui-carousel-container"
1143 CONTAINER: "yui-carousel-container",
1146 * The class name of the Carousel's container element.
1149 * @default "yui-carousel-content"
1151 CONTENT: "yui-carousel-content",
1154 * The class name of a disabled navigation button.
1156 * @property DISABLED
1157 * @default "yui-carousel-button-disabled"
1159 DISABLED: "yui-carousel-button-disabled",
1162 * The class name of the first Carousel navigation button.
1164 * @property FIRST_NAV
1165 * @default " yui-carousel-first-button"
1167 FIRST_NAV: " yui-carousel-first-button",
1170 * The class name of a first disabled navigation button.
1172 * @property FIRST_NAV_DISABLED
1173 * @default "yui-carousel-first-button-disabled"
1175 FIRST_NAV_DISABLED: "yui-carousel-first-button-disabled",
1178 * The class name of a first page element.
1180 * @property FIRST_PAGE
1181 * @default "yui-carousel-nav-first-page"
1183 FIRST_PAGE: "yui-carousel-nav-first-page",
1186 * The class name of the Carousel navigation button that has focus.
1188 * @property FOCUSSED_BUTTON
1189 * @default "yui-carousel-button-focus"
1191 FOCUSSED_BUTTON: "yui-carousel-button-focus",
1194 * The class name of a horizontally oriented Carousel.
1196 * @property HORIZONTAL
1197 * @default "yui-carousel-horizontal"
1199 HORIZONTAL: "yui-carousel-horizontal",
1202 * The element to be used as the progress indicator when the item
1203 * is still being loaded.
1205 * @property ITEM_LOADING
1206 * @default The progress indicator (spinner) image CSS class
1208 ITEM_LOADING: "yui-carousel-item-loading",
1211 * The class name that will be set if the Carousel adjusts itself
1212 * for a minimum width.
1214 * @property MIN_WIDTH
1215 * @default "yui-carousel-min-width"
1217 MIN_WIDTH: "yui-carousel-min-width",
1220 * The navigation element container class name.
1222 * @property NAVIGATION
1223 * @default "yui-carousel-nav"
1225 NAVIGATION: "yui-carousel-nav",
1228 * The class name of the next Carousel navigation button.
1230 * @property NEXT_NAV
1231 * @default " yui-carousel-next-button"
1233 NEXT_NAV: " yui-carousel-next-button",
1236 * The class name of the next navigation link. This variable is
1237 * not only used for styling, but also for identifying the link
1238 * within the Carousel container.
1240 * @property NEXT_PAGE
1241 * @default "yui-carousel-next"
1243 NEXT_PAGE: "yui-carousel-next",
1246 * The class name for the navigation container for prev/next.
1248 * @property NAV_CONTAINER
1249 * @default "yui-carousel-buttons"
1251 NAV_CONTAINER: "yui-carousel-buttons",
1254 * The class name for an item in the pager UL or dropdown menu.
1256 * @property PAGER_ITEM
1257 * @default "yui-carousel-pager-item"
1259 PAGER_ITEM: "yui-carousel-pager-item",
1262 * The class name for the pagination container
1264 * @property PAGINATION
1265 * @default "yui-carousel-pagination"
1267 PAGINATION: "yui-carousel-pagination",
1270 * The class name of the focussed page navigation. This class is
1271 * specifically used for the ugly focus handling in Opera.
1273 * @property PAGE_FOCUS
1274 * @default "yui-carousel-nav-page-focus"
1276 PAGE_FOCUS: "yui-carousel-nav-page-focus",
1279 * The class name of the previous navigation link. This variable
1280 * is not only used for styling, but also for identifying the link
1281 * within the Carousel container.
1283 * @property PREV_PAGE
1284 * @default "yui-carousel-prev"
1286 PREV_PAGE: "yui-carousel-prev",
1289 * The class name of the selected item.
1291 * @property SELECTED_ITEM
1292 * @default "yui-carousel-item-selected"
1294 SELECTED_ITEM: "yui-carousel-item-selected",
1297 * The class name of the selected paging navigation.
1299 * @property SELECTED_NAV
1300 * @default "yui-carousel-nav-page-selected"
1302 SELECTED_NAV: "yui-carousel-nav-page-selected",
1305 * The class name of a vertically oriented Carousel.
1307 * @property VERTICAL
1308 * @default "yui-carousel-vertical"
1310 VERTICAL: "yui-carousel-vertical",
1313 * The class name of a multirow Carousel.
1315 * @property MULTI_ROW
1316 * @default "yui-carousel-multi-row"
1318 MULTI_ROW: "yui-carousel-multi-row",
1321 * The class name of a row in a multirow Carousel.
1324 * @default "yui-carousel-new-row"
1326 ROW: "yui-carousel-row",
1329 * The class name of a vertical Carousel's container element.
1331 * @property VERTICAL_CONTAINER
1332 * @default "yui-carousel-vertical-container"
1334 VERTICAL_CONTAINER: "yui-carousel-vertical-container",
1337 * The class name of a visible Carousel.
1340 * @default "yui-carousel-visible"
1342 VISIBLE: "yui-carousel-visible"
1347 * Configuration attributes for configuring the Carousel component
1353 * The offset of the first visible item in the Carousel.
1355 * @property FIRST_VISIBLE
1361 * The minimum width of the horizontal Carousel container to support
1362 * the navigation buttons.
1364 * @property HORZ_MIN_WIDTH
1367 HORZ_MIN_WIDTH: 180,
1370 * The maximum number of pager buttons allowed beyond which the UI
1371 * of the pager would be a drop-down of pages instead of buttons.
1373 * @property MAX_PAGER_BUTTONS
1376 MAX_PAGER_BUTTONS: 5,
1379 * The minimum width of the vertical Carousel container to support
1380 * the navigation buttons.
1382 * @property VERT_MIN_WIDTH
1385 VERT_MIN_WIDTH: 115,
1388 * The number of visible items in the Carousel.
1390 * @property NUM_VISIBLE
1398 * Internationalizable strings in the Carousel component
1404 * The content to be used as the progress indicator when the item
1405 * is still being loaded.
1407 * @property ITEM_LOADING_CONTENT
1408 * @default "Loading"
1410 ITEM_LOADING_CONTENT: "Loading",
1413 * The next navigation button name/text.
1415 * @property NEXT_BUTTON_TEXT
1416 * @default "Next Page"
1418 NEXT_BUTTON_TEXT: "Next Page",
1421 * The prefix text for the pager in case the UI is a drop-down.
1423 * @property PAGER_PREFIX_TEXT
1424 * @default "Go to page "
1426 PAGER_PREFIX_TEXT: "Go to page ",
1429 * The previous navigation button name/text.
1431 * @property PREVIOUS_BUTTON_TEXT
1432 * @default "Previous Page"
1434 PREVIOUS_BUTTON_TEXT: "Previous Page"
1439 * Public methods of the Carousel component
1443 * Insert or append an item to the Carousel.
1444 * E.g. if Object: ({content:"Your Content", id:"", className:""}, index)
1448 * @param item {String | Object | HTMLElement} The item to be appended
1449 * to the Carousel. If the parameter is a string, it is assumed to be
1450 * the content of the newly created item. If the parameter is an
1451 * object, it is assumed to supply the content and an optional class
1452 * and an optional id of the newly created item.
1453 * @param index {Number} optional The position to where in the list
1454 * (starts from zero).
1455 * @return {Boolean} Return true on success, false otherwise
1457 addItem: function (item, index) {
1458 var carousel = this,
1463 newIndex, // Add newIndex as workaround for undefined pos
1464 numItems = carousel.get("numItems");
1470 if (JS.isString(item) || item.nodeName) {
1471 content = item.nodeName ? item.innerHTML : item;
1472 } else if (JS.isObject(item)) {
1473 content = item.content;
1475 YAHOO.log("Invalid argument to addItem", "error", WidgetName);
1479 className = item.className || "";
1480 elId = item.id ? item.id : Dom.generateId();
1482 if (JS.isUndefined(index)) {
1483 carousel._itemsTable.items.push({
1485 className : className,
1488 // Add newIndex as workaround for undefined pos
1489 newIndex = carousel._itemsTable.items.length-1;
1491 if (index < 0 || index > numItems) {
1492 YAHOO.log("Index out of bounds", "error", WidgetName);
1496 // make sure we splice into the correct position
1497 if(!carousel._itemsTable.items[index]){
1498 carousel._itemsTable.items[index] = undefined;
1502 carousel._itemsTable.items.splice(index, replaceItems, {
1504 className : className,
1508 carousel._itemsTable.numItems++;
1510 if (numItems < carousel._itemsTable.items.length) {
1511 carousel.set("numItems", carousel._itemsTable.items.length);
1514 // Add newPos as workaround for undefined pos
1515 carousel.fireEvent(itemAddedEvent, { pos: index, ev: itemAddedEvent, newPos:newIndex });
1521 * Insert or append multiple items to the Carousel.
1525 * @param items {Array} An array containing an array of new items each linked to the
1526 * index where the insertion should take place.
1527 * E.g. [[{content:'<img/>'}, index1], [{content:'<img/>'}, index2]]
1528 * NOTE: An item at index must already exist.
1529 * @return {Boolean} Return true on success, false otherwise
1531 addItems: function (items) {
1532 var i, n, rv = true;
1534 if (!JS.isArray(items)) {
1538 for (i = 0, n = items.length; i < n; i++) {
1539 if (this.addItem(items[i][0], items[i][1]) === false) {
1548 * Remove focus from the Carousel.
1554 this._carouselEl.blur();
1555 this.fireEvent(blurEvent);
1559 * Clears the items from Carousel.
1561 * @method clearItems
1564 clearItems: function () {
1565 var carousel = this, n = carousel.get("numItems");
1568 if (!carousel.removeItem(0)) {
1569 YAHOO.log("Item could not be removed - missing?",
1570 "warn", WidgetName);
1573 For dynamic loading, the numItems may be much larger than
1574 the actual number of items in the table. So, set the
1575 numItems to zero, and break out of the loop if the table
1578 if (carousel._itemsTable.numItems === 0) {
1579 carousel.set("numItems", 0);
1585 carousel.fireEvent(allItemsRemovedEvent);
1589 * Set focus on the Carousel.
1594 focus: function () {
1595 var carousel = this,
1598 isSelectionInvisible,
1606 // Don't do anything if the Carousel is not rendered
1607 if (!carousel._hasRendered) {
1611 if (carousel.isAnimating()) {
1612 // this messes up real bad!
1616 selItem = carousel.get("selectedItem");
1617 numVisible = carousel.get("numVisible");
1618 selectOnScroll = carousel.get("selectOnScroll");
1619 selected = (selItem >= 0) ?
1620 carousel.getItem(selItem) : null;
1621 first = carousel.get("firstVisible");
1622 last = first + numVisible - 1;
1623 isSelectionInvisible = (selItem < first || selItem > last);
1624 focusEl = (selected && selected.id) ?
1625 Dom.get(selected.id) : null;
1626 itemsTable = carousel._itemsTable;
1628 if (!selectOnScroll && isSelectionInvisible) {
1629 focusEl = (itemsTable && itemsTable.items &&
1630 itemsTable.items[first]) ?
1631 Dom.get(itemsTable.items[first].id) : null;
1638 // ignore focus errors
1642 carousel.fireEvent(focusEvent);
1646 * Hide the Carousel.
1652 var carousel = this;
1654 if (carousel.fireEvent(beforeHideEvent) !== false) {
1655 carousel.removeClass(carousel.CLASSES.VISIBLE);
1656 carousel.fireEvent(hideEvent);
1661 * Initialize the Carousel.
1665 * @param el {HTMLElement | String} The html element that represents
1666 * the Carousel container.
1667 * @param attrs {Object} The set of configuration attributes for
1668 * creating the Carousel.
1670 init: function (el, attrs) {
1671 var carousel = this,
1672 elId = el, // save for a rainy day
1677 YAHOO.log(el + " is neither an HTML element, nor a string",
1678 "error", WidgetName);
1682 carousel._hasRendered = false;
1683 carousel._navBtns = { prev: [], next: [] };
1684 carousel._pages = { el: null, num: 0, cur: 0 };
1685 carousel._pagination = {};
1686 carousel._itemAttrCache = {};
1688 carousel._itemsTable = { loading: {}, numItems: 0,
1689 items: [], size: 0 };
1691 YAHOO.log("Component initialization", WidgetName);
1693 if (JS.isString(el)) {
1695 } else if (!el.nodeName) {
1696 YAHOO.log(el + " is neither an HTML element, nor a string",
1697 "error", WidgetName);
1701 Carousel.superclass.init.call(carousel, el, attrs);
1703 // check if we're starting somewhere in the middle
1704 selected = carousel.get("selectedItem");
1706 carousel.set("firstVisible",getFirstVisibleForPosition.call(carousel,selected));
1710 if (!el.id) { // in case the HTML element is passed
1711 el.setAttribute("id", Dom.generateId());
1713 parse = carousel._parseCarousel(el);
1715 carousel._createCarousel(elId);
1718 el = carousel._createCarousel(elId);
1722 carousel.initEvents();
1725 carousel._parseCarouselItems();
1728 // add the selected class
1730 setItemSelection.call(carousel,selected,0);
1733 if (!attrs || typeof attrs.isVertical == "undefined") {
1734 carousel.set("isVertical", false);
1737 carousel._parseCarouselNavigation(el);
1738 carousel._navEl = carousel._setupCarouselNavigation();
1740 instances[elId] = { object: carousel };
1741 carousel._loadItems(Math.min(carousel.get("firstVisible")+carousel.get("numVisible"),carousel.get("numItems"))-1);
1745 * Initialize the configuration attributes used to create the Carousel.
1747 * @method initAttributes
1749 * @param attrs {Object} The set of configuration attributes for
1750 * creating the Carousel.
1752 initAttributes: function (attrs) {
1753 var carousel = this;
1755 attrs = attrs || {};
1756 Carousel.superclass.initAttributes.call(carousel, attrs);
1759 * @attribute carouselEl
1760 * @description The type of the Carousel element.
1764 carousel.setAttributeConfig("carouselEl", {
1765 validator : JS.isString,
1766 value : attrs.carouselEl || "OL"
1770 * @attribute carouselItemEl
1771 * @description The type of the list of items within the Carousel.
1775 carousel.setAttributeConfig("carouselItemEl", {
1776 validator : JS.isString,
1777 value : attrs.carouselItemEl || "LI"
1781 * @attribute currentPage
1782 * @description The current page number (read-only.)
1785 carousel.setAttributeConfig("currentPage", {
1791 * @attribute firstVisible
1792 * @description The index to start the Carousel from (indexes begin
1797 carousel.setAttributeConfig("firstVisible", {
1798 method : carousel._setFirstVisible,
1799 validator : carousel._validateFirstVisible,
1801 attrs.firstVisible || carousel.CONFIG.FIRST_VISIBLE
1805 * @attribute selectOnScroll
1806 * @description Set this to true to automatically set focus to
1807 * follow scrolling in the Carousel.
1811 carousel.setAttributeConfig("selectOnScroll", {
1812 validator : JS.isBoolean,
1813 value : attrs.selectOnScroll || true
1817 * @attribute numVisible
1818 * @description The number of visible items in the Carousel's
1823 carousel.setAttributeConfig("numVisible", {
1824 setter : carousel._numVisibleSetter,
1825 method : carousel._setNumVisible,
1826 validator : carousel._validateNumVisible,
1827 value : attrs.numVisible || carousel.CONFIG.NUM_VISIBLE
1831 * @attribute numItems
1832 * @description The number of items in the Carousel.
1835 carousel.setAttributeConfig("numItems", {
1836 method : carousel._setNumItems,
1837 validator : carousel._validateNumItems,
1838 value : carousel._itemsTable.numItems
1842 * @attribute scrollIncrement
1843 * @description The number of items to scroll by for arrow keys.
1847 carousel.setAttributeConfig("scrollIncrement", {
1848 validator : carousel._validateScrollIncrement,
1849 value : attrs.scrollIncrement || 1
1853 * @attribute selectedItem
1854 * @description The index of the selected item.
1857 carousel.setAttributeConfig("selectedItem", {
1858 setter : carousel._selectedItemSetter,
1859 method : carousel._setSelectedItem,
1860 validator : JS.isNumber,
1865 * @attribute revealAmount
1866 * @description The percentage of the item to be revealed on each
1867 * side of the Carousel (before and after the first and last item
1868 * in the Carousel's viewport.)
1872 carousel.setAttributeConfig("revealAmount", {
1873 method : carousel._setRevealAmount,
1874 validator : carousel._validateRevealAmount,
1875 value : attrs.revealAmount || 0
1879 * @attribute isCircular
1880 * @description Set this to true to wrap scrolling of the contents
1885 carousel.setAttributeConfig("isCircular", {
1886 validator : JS.isBoolean,
1887 value : attrs.isCircular || false
1891 * @attribute isVertical
1892 * @description True if the orientation of the Carousel is vertical
1896 carousel.setAttributeConfig("isVertical", {
1897 method : carousel._setOrientation,
1898 validator : JS.isBoolean,
1899 value : attrs.isVertical || false
1903 * @attribute navigation
1904 * @description The set of navigation controls for Carousel
1906 * { prev: null, // the previous navigation element<br>
1907 * next: null } // the next navigation element
1910 carousel.setAttributeConfig("navigation", {
1911 method : carousel._setNavigation,
1912 validator : carousel._validateNavigation,
1914 attrs.navigation || {prev: null,next: null,page: null}
1918 * @attribute animation
1919 * @description The optional animation attributes for the Carousel.
1921 * { speed: 0, // the animation speed (in seconds)<br>
1922 * effect: null } // the animation effect (like
1923 * YAHOO.util.Easing.easeOut)
1926 carousel.setAttributeConfig("animation", {
1927 validator : carousel._validateAnimation,
1928 value : attrs.animation || { speed: 0, effect: null }
1932 * @attribute autoPlay
1933 * @description Set this to time in milli-seconds to have the
1934 * Carousel automatically scroll the contents.
1936 * @deprecated Use autoPlayInterval instead.
1938 carousel.setAttributeConfig("autoPlay", {
1939 validator : JS.isNumber,
1940 value : attrs.autoPlay || 0
1944 * @attribute autoPlayInterval
1945 * @description The delay in milli-seconds for scrolling the
1946 * Carousel during auto-play.
1947 * Note: The startAutoPlay() method needs to be invoked to trigger
1948 * automatic scrolling of Carousel.
1951 carousel.setAttributeConfig("autoPlayInterval", {
1952 validator : JS.isNumber,
1953 value : attrs.autoPlayInterval || 0
1957 * @attribute numPages
1958 * @description The number of pages in the carousel.
1961 carousel.setAttributeConfig("numPages", {
1963 getter : carousel._getNumPages
1967 * @attribute lastVisible
1968 * @description The last item visible in the carousel.
1971 carousel.setAttributeConfig("lastVisible", {
1973 getter : carousel._getLastVisible
1978 * Initialize and bind the event handlers.
1980 * @method initEvents
1983 initEvents: function () {
1984 var carousel = this,
1985 cssClass = carousel.CLASSES,
1988 carousel.on("keydown", carousel._keyboardEventHandler);
1990 carousel.on(afterScrollEvent, syncNavigation);
1992 carousel.on(itemAddedEvent, syncUi);
1994 carousel.on(itemRemovedEvent, syncUi);
1996 carousel.on(itemReplacedEvent, syncUi);
1998 carousel.on(itemSelectedEvent, function () {
1999 if (carousel._hasFocus) {
2004 carousel.on(loadItemsEvent, syncUi);
2006 carousel.on(allItemsRemovedEvent, function (ev) {
2007 carousel.scrollTo(0);
2008 syncNavigation.call(carousel);
2009 syncPagerUi.call(carousel);
2012 carousel.on(pageChangeEvent, syncPagerUi, carousel);
2014 carousel.on(renderEvent, function (ev) {
2015 if (carousel.get("selectedItem") === null ||
2016 carousel.get("selectedItem") <= 0) { //in either case
2017 carousel.set("selectedItem", carousel.get("firstVisible"));
2019 syncNavigation.call(carousel, ev);
2020 syncPagerUi.call(carousel, ev);
2021 carousel._setClipContainerSize();
2025 carousel.on("selectedItemChange", function (ev) {
2026 setItemSelection.call(carousel, ev.newValue, ev.prevValue);
2027 if (ev.newValue >= 0) {
2028 carousel._updateTabIndex(
2029 carousel.getElementForItem(ev.newValue));
2031 carousel.fireEvent(itemSelectedEvent, ev.newValue);
2034 carousel.on(uiUpdateEvent, function (ev) {
2035 syncNavigation.call(carousel, ev);
2036 syncPagerUi.call(carousel, ev);
2039 carousel.on("firstVisibleChange", function (ev) {
2040 if (!carousel.get("selectOnScroll")) {
2041 if (ev.newValue >= 0) {
2042 carousel._updateTabIndex(
2043 carousel.getElementForItem(ev.newValue));
2048 // Handle item selection on mouse click
2049 carousel.on("click", function (ev) {
2050 if (carousel.isAutoPlayOn()) {
2051 carousel.stopAutoPlay();
2053 carousel._itemClickHandler(ev);
2054 carousel._pagerClickHandler(ev);
2057 // Restore the focus on the navigation buttons
2059 Event.onFocus(carousel.get("element"), function (ev, obj) {
2060 var target = Event.getTarget(ev);
2062 if (target && target.nodeName.toUpperCase() == "A" &&
2063 Dom.getAncestorByClassName(target, cssClass.NAVIGATION)) {
2065 Dom.removeClass(focussedLi, cssClass.PAGE_FOCUS);
2067 focussedLi = target.parentNode;
2068 Dom.addClass(focussedLi, cssClass.PAGE_FOCUS);
2071 Dom.removeClass(focussedLi, cssClass.PAGE_FOCUS);
2075 obj._hasFocus = true;
2076 obj._updateNavButtons(Event.getTarget(ev), true);
2079 Event.onBlur(carousel.get("element"), function (ev, obj) {
2080 obj._hasFocus = false;
2081 obj._updateNavButtons(Event.getTarget(ev), false);
2086 * Return true if the Carousel is still animating, or false otherwise.
2088 * @method isAnimating
2089 * @return {Boolean} Return true if animation is still in progress, or
2093 isAnimating: function () {
2094 return this._isAnimationInProgress;
2098 * Return true if the auto-scrolling of Carousel is "on", or false
2101 * @method isAutoPlayOn
2102 * @return {Boolean} Return true if autoPlay is "on", or false
2106 isAutoPlayOn: function () {
2107 return this._isAutoPlayInProgress;
2111 * Return the carouselItemEl at index or null if the index is not
2114 * @method getElementForItem
2115 * @param index {Number} The index of the item to be returned
2116 * @return {Element} Return the item at index or null if not found
2119 getElementForItem: function (index) {
2120 var carousel = this;
2122 if (index < 0 || index >= carousel.get("numItems")) {
2123 YAHOO.log("Index out of bounds", "error", WidgetName);
2127 if (carousel._itemsTable.items[index]) {
2128 return Dom.get(carousel._itemsTable.items[index].id);
2135 * Return the carouselItemEl for all items in the Carousel.
2137 * @method getElementForItems
2138 * @return {Array} Return all the items
2141 getElementForItems: function () {
2142 var carousel = this, els = [], i;
2144 for (i = 0; i < carousel._itemsTable.numItems; i++) {
2145 els.push(carousel.getElementForItem(i));
2152 * Return the item at index or null if the index is not found.
2155 * @param index {Number} The index of the item to be returned
2156 * @return {Object} Return the item at index or null if not found
2159 getItem: function (index) {
2160 var carousel = this;
2162 if (index < 0 || index >= carousel.get("numItems")) {
2163 YAHOO.log("Index out of bounds", "error", WidgetName);
2167 if (carousel._itemsTable.numItems > index) {
2168 if (!JS.isUndefined(carousel._itemsTable.items[index])) {
2169 return carousel._itemsTable.items[index];
2177 * Return all items as an array.
2180 * @return {Array} Return all items in the Carousel
2183 getItems: function () {
2184 return this._itemsTable.items;
2188 * Return all loading items as an array.
2190 * @method getLoadingItems
2191 * @return {Array} Return all items that are loading in the Carousel.
2194 getLoadingItems: function () {
2195 return this._itemsTable.loading;
2199 * For a multirow carousel, return the number of rows specified by user.
2202 * @return {Number} Number of rows
2205 getRows: function () {
2210 * For a multirow carousel, return the number of cols specified by user.
2213 * @return {Array} Return all items in the Carousel
2216 getCols: function () {
2221 * Return the position of the Carousel item that has the id "id", or -1
2222 * if the id is not found.
2224 * @method getItemPositionById
2225 * @param index {Number} The index of the item to be returned
2228 getItemPositionById: function (id) {
2229 var carousel = this,
2230 n = carousel.get("numItems"),
2232 items = carousel._itemsTable.items,
2236 item = items[i] || {};
2247 * Return all visible items as an array.
2249 * @method getVisibleItems
2250 * @return {Array} The array of visible items
2253 getVisibleItems: function () {
2254 var carousel = this,
2255 i = carousel.get("firstVisible"),
2256 n = i + carousel.get("numVisible"),
2260 r.push(carousel.getElementForItem(i));
2268 * Remove an item at index from the Carousel.
2270 * @method removeItem
2272 * @param index {Number} The position to where in the list (starts from
2274 * @return {Boolean} Return true on success, false otherwise
2276 removeItem: function (index) {
2277 var carousel = this,
2279 num = carousel.get("numItems");
2281 if (index < 0 || index >= num) {
2282 YAHOO.log("Index out of bounds", "error", WidgetName);
2286 item = carousel._itemsTable.items.splice(index, 1);
2287 if (item && item.length == 1) {
2288 carousel._itemsTable.numItems--;
2289 carousel.set("numItems", num - 1);
2291 carousel.fireEvent(itemRemovedEvent,
2292 { item: item[0], pos: index, ev: itemRemovedEvent });
2300 * Replace an item at index witin Carousel.
2302 * @method replaceItem
2304 * @param item {String | Object | HTMLElement} The item to be appended
2305 * to the Carousel. If the parameter is a string, it is assumed to be
2306 * the content of the newly created item. If the parameter is an
2307 * object, it is assumed to supply the content and an optional class
2308 * and an optional id of the newly created item.
2309 * @param index {Number} The position to where in the list (starts from
2311 * @return {Boolean} Return true on success, false otherwise
2313 replaceItem: function (item, index) {
2314 var carousel = this,
2318 numItems = carousel.get("numItems"),
2326 if (JS.isString(item) || item.nodeName) {
2327 content = item.nodeName ? item.innerHTML : item;
2328 } else if (JS.isObject(item)) {
2329 content = item.content;
2331 YAHOO.log("Invalid argument to replaceItem", "error", WidgetName);
2335 if (JS.isUndefined(index)) {
2336 YAHOO.log("Index must be defined for replaceItem", "error", WidgetName);
2339 if (index < 0 || index >= numItems) {
2340 YAHOO.log("Index out of bounds in replaceItem", "error", WidgetName);
2344 oel = carousel._itemsTable.items[index];
2346 oel = carousel._itemsTable.loading[index];
2347 carousel._itemsTable.items[index] = undefined;
2350 carousel._itemsTable.items.splice(index, 1, {
2352 className : item.className || "",
2353 id : Dom.generateId()
2356 el = carousel._itemsTable.items[index];
2358 carousel.fireEvent(itemReplacedEvent,
2359 { newItem: el, oldItem: oel, pos: index, ev: itemReplacedEvent });
2365 * Replace multiple items at specified indexes.
2366 * NOTE: item at index must already exist.
2368 * @method replaceItems
2370 * @param items {Array} An array containing an array of replacement items each linked to the
2371 * index where the substitution should take place.
2372 * E.g. [[{content:'<img/>'}, index1], [{content:'<img/>'}, index2]]
2373 * @return {Boolean} Return true on success, false otherwise
2375 replaceItems: function (items) {
2376 var i, n, rv = true;
2378 if (!JS.isArray(items)) {
2382 for (i = 0, n = items.length; i < n; i++) {
2383 if (this.replaceItem(items[i][0], items[i][1]) === false) {
2392 * Render the Carousel.
2396 * @param appendTo {HTMLElement | String} The element to which the
2397 * Carousel should be appended prior to rendering.
2398 * @return {Boolean} Status of the operation
2400 render: function (appendTo) {
2401 var carousel = this,
2402 cssClass = carousel.CLASSES,
2403 rows = carousel._rows;
2405 carousel.addClass(cssClass.CAROUSEL);
2407 if (!carousel._clipEl) {
2408 carousel._clipEl = carousel._createCarouselClip();
2409 carousel._clipEl.appendChild(carousel._carouselEl);
2413 carousel.appendChild(carousel._clipEl);
2414 carousel.appendTo(appendTo);
2416 if (!Dom.inDocument(carousel.get("element"))) {
2417 YAHOO.log("Nothing to render. The container should be " +
2418 "within the document if appendTo is not " +
2419 "specified", "error", WidgetName);
2422 carousel.appendChild(carousel._clipEl);
2426 Dom.addClass(carousel._clipEl, cssClass.MULTI_ROW);
2429 if (carousel.get("isVertical")) {
2430 carousel.addClass(cssClass.VERTICAL);
2432 carousel.addClass(cssClass.HORIZONTAL);
2435 if (carousel.get("numItems") < 1) {
2436 YAHOO.log("No items in the Carousel to render", "warn",
2441 carousel._refreshUi();
2447 * Scroll the Carousel by an item backward.
2449 * @method scrollBackward
2452 scrollBackward: function () {
2453 var carousel = this;
2454 carousel.scrollTo(carousel._firstItem -
2455 carousel.get("scrollIncrement"));
2459 * Scroll the Carousel by an item forward.
2461 * @method scrollForward
2464 scrollForward: function () {
2465 var carousel = this;
2466 carousel.scrollTo(carousel._firstItem +
2467 carousel.get("scrollIncrement"));
2471 * Scroll the Carousel by a page backward.
2473 * @method scrollPageBackward
2476 scrollPageBackward: function () {
2477 var carousel = this,
2478 isVertical = carousel.get("isVertical"),
2479 cols = carousel._cols,
2480 item = carousel._firstItem - carousel.get("numVisible");
2482 if (item < 0) { // only account for multi-row when scrolling backwards from item 0
2484 item = carousel._firstItem - cols;
2488 if (carousel.get("selectOnScroll")) {
2489 carousel._selectedItem = carousel._getSelectedItem(item);
2492 carousel.scrollTo(item);
2496 * Scroll the Carousel by a page forward.
2498 * @method scrollPageForward
2501 scrollPageForward: function () {
2502 var carousel = this,
2503 item = carousel._firstItem + carousel.get("numVisible");
2505 if (item > carousel.get("numItems")) {
2509 if (carousel.get("selectOnScroll")) {
2510 carousel._selectedItem = carousel._getSelectedItem(item);
2513 carousel.scrollTo(item);
2517 * Scroll the Carousel to make the item the first visible item.
2521 * @param item Number The index of the element to position at.
2522 * @param dontSelect Boolean True if select should be avoided
2524 scrollTo: function (item, dontSelect) {
2525 var carousel = this, animate, animCfg, isCircular, isVertical,
2526 rows, delta, direction, firstItem, lastItem, itemsPerRow,
2527 itemsPerCol, numItems, numPerPage, offset, page, rv, sentinel,
2528 index, stopAutoScroll,
2529 itemsTable = carousel._itemsTable,
2530 items = itemsTable.items,
2531 loading = itemsTable.loading;
2533 if (JS.isUndefined(item) || item == carousel._firstItem ||
2534 carousel.isAnimating()) {
2535 return; // nothing to do!
2538 animCfg = carousel.get("animation");
2539 isCircular = carousel.get("isCircular");
2540 isVertical = carousel.get("isVertical");
2541 itemsPerRow = carousel._cols;
2542 itemsPerCol = carousel._rows;
2543 firstItem = carousel._firstItem;
2544 numItems = carousel.get("numItems");
2545 numPerPage = carousel.get("numVisible");
2546 page = carousel.get("currentPage");
2548 stopAutoScroll = function () {
2549 if (carousel.isAutoPlayOn()) {
2550 carousel.stopAutoPlay();
2556 item = numItems + item;
2558 stopAutoScroll.call(carousel);
2561 } else if (numItems > 0 && item > numItems - 1) {
2563 if (carousel.get("isCircular")) {
2564 item = numItems - item;
2566 stopAutoScroll.call(carousel);
2575 direction = (carousel._firstItem > item) ? "backward" : "forward";
2577 sentinel = firstItem + numPerPage;
2578 sentinel = (sentinel > numItems - 1) ? numItems - 1 : sentinel;
2579 rv = carousel.fireEvent(beforeScrollEvent,
2580 { dir: direction, first: firstItem, last: sentinel });
2581 if (rv === false) { // scrolling is prevented
2585 carousel.fireEvent(beforePageChangeEvent, { page: page });
2587 // call loaditems to check if we have all the items to display
2588 lastItem = item + numPerPage - 1;
2589 carousel._loadItems(lastItem > numItems-1 ? numItems-1 : lastItem);
2591 // Calculate the delta relative to the first item, the delta is
2596 // offset calculations for multirow Carousel
2598 delta = parseInt(delta / itemsPerRow, 10);
2600 delta = parseInt(delta / itemsPerCol, 10);
2604 // adjust for items not yet loaded
2606 while (delta < 0 && index < item+numPerPage-1 && index < numItems) {
2607 if (!items[index] && !loading[index]) {
2610 index += itemsPerCol ? itemsPerCol : 1;
2613 carousel._firstItem = item;
2614 carousel.set("firstVisible", item);
2616 YAHOO.log("Scrolling to " + item + " delta = " + delta, WidgetName);
2618 sentinel = item + numPerPage;
2619 sentinel = (sentinel > numItems - 1) ? numItems - 1 : sentinel;
2621 offset = getScrollOffset.call(carousel, delta);
2622 YAHOO.log("Scroll offset = " + offset, WidgetName);
2624 animate = animCfg.speed > 0;
2627 carousel._animateAndSetCarouselOffset(offset, item, sentinel,
2630 carousel._setCarouselOffset(offset);
2631 updateStateAfterScroll.call(carousel, item, sentinel);
2636 * Get the page an item is on within carousel.
2638 * @method getPageForItem
2640 * @param index {Number} Index of item
2641 * @return {Number} Page item is on
2643 getPageForItem : function(item) {
2645 (item+1) / parseInt(this.get("numVisible"),10)
2650 * Get the first visible item's index on any given page.
2652 * @method getFirstVisibleOnpage
2654 * @param page {Number} Page
2655 * @return {Number} First item's index
2657 getFirstVisibleOnPage : function(page) {
2658 return (page - 1) * this.get("numVisible");
2662 * Select the previous item in the Carousel.
2664 * @method selectPreviousItem
2667 selectPreviousItem: function () {
2668 var carousel = this,
2670 selected = carousel.get("selectedItem");
2672 if (selected == this._firstItem) {
2673 newpos = selected - carousel.get("numVisible");
2674 carousel._selectedItem = carousel._getSelectedItem(selected-1);
2675 carousel.scrollTo(newpos);
2677 newpos = carousel.get("selectedItem") -
2678 carousel.get("scrollIncrement");
2679 carousel.set("selectedItem",carousel._getSelectedItem(newpos));
2684 * Select the next item in the Carousel.
2686 * @method selectNextItem
2689 selectNextItem: function () {
2690 var carousel = this, newpos = 0;
2692 newpos = carousel.get("selectedItem") +
2693 carousel.get("scrollIncrement");
2694 carousel.set("selectedItem", carousel._getSelectedItem(newpos));
2698 * Display the Carousel.
2704 var carousel = this,
2705 cssClass = carousel.CLASSES;
2707 if (carousel.fireEvent(beforeShowEvent) !== false) {
2708 carousel.addClass(cssClass.VISIBLE);
2709 carousel.fireEvent(showEvent);
2714 * Start auto-playing the Carousel.
2716 * @method startAutoPlay
2719 startAutoPlay: function () {
2720 var carousel = this, timer;
2722 if (JS.isUndefined(carousel._autoPlayTimer)) {
2723 timer = carousel.get("autoPlayInterval");
2727 carousel._isAutoPlayInProgress = true;
2728 carousel.fireEvent(startAutoPlayEvent);
2729 carousel._autoPlayTimer = setTimeout(function () {
2730 carousel._autoScroll();
2736 * Stop auto-playing the Carousel.
2738 * @method stopAutoPlay
2741 stopAutoPlay: function () {
2742 var carousel = this;
2744 if (!JS.isUndefined(carousel._autoPlayTimer)) {
2745 clearTimeout(carousel._autoPlayTimer);
2746 delete carousel._autoPlayTimer;
2747 carousel._isAutoPlayInProgress = false;
2748 carousel.fireEvent(stopAutoPlayEvent);
2753 * Update interface's pagination data within a registered template.
2755 * @method updatePagination
2758 updatePagination: function () {
2759 var carousel = this,
2760 pagination = carousel._pagination;
2761 if(!pagination.el){ return false; }
2763 var numItems = carousel.get('numItems'),
2764 numVisible = carousel.get('numVisible'),
2765 firstVisible = carousel.get('firstVisible')+1,
2766 currentPage = carousel.get('currentPage')+1,
2767 numPages = carousel.get('numPages'),
2769 'numVisible' : numVisible,
2770 'numPages' : numPages,
2771 'numItems' : numItems,
2772 'selectedItem' : carousel.get('selectedItem')+1,
2773 'currentPage' : currentPage,
2774 'firstVisible' : firstVisible,
2775 'lastVisible' : carousel.get("lastVisible")+1
2777 cb = pagination.callback || {},
2778 scope = cb.scope && cb.obj ? cb.obj : carousel;
2780 pagination.el.innerHTML = JS.isFunction(cb.fn) ? cb.fn.apply(scope, [pagination.template, replacements]) : YAHOO.lang.substitute(pagination.template, replacements);
2784 * Register carousels pagination template, append to interface, and populate.
2786 * @method registerPagination
2787 * @param template {String} Pagination template as passed to lang.substitute
2790 registerPagination: function (tpl, pos, cb) {
2791 var carousel = this;
2793 carousel._pagination.template = tpl;
2794 carousel._pagination.callback = cb || {};
2796 if(!carousel._pagination.el){
2797 carousel._pagination.el = createElement('DIV', {className:carousel.CLASSES.PAGINATION});
2799 if(pos == "before"){
2800 carousel._navEl.insertBefore(carousel._pagination.el, carousel._navEl.firstChild);
2802 carousel._navEl.appendChild(carousel._pagination.el);
2805 carousel.on('itemSelected', carousel.updatePagination);
2806 carousel.on('pageChange', carousel.updatePagination);
2809 carousel.updatePagination();
2813 * Return the string representation of the Carousel.
2819 toString: function () {
2820 return WidgetName + (this.get ? " (#" + this.get("id") + ")" : "");
2824 * Protected methods of the Carousel component
2828 * Set the Carousel offset to the passed offset after animating.
2830 * @method _animateAndSetCarouselOffset
2831 * @param {Integer} offset The offset to which the Carousel has to be
2833 * @param {Integer} item The index to which the Carousel will scroll.
2834 * @param {Integer} sentinel The last element in the view port.
2837 _animateAndSetCarouselOffset: function (offset, item, sentinel) {
2838 var carousel = this,
2839 animCfg = carousel.get("animation"),
2842 if (carousel.get("isVertical")) {
2843 animObj = new YAHOO.util.Motion(carousel._carouselEl,
2844 { top: { to: offset } },
2845 animCfg.speed, animCfg.effect);
2847 animObj = new YAHOO.util.Motion(carousel._carouselEl,
2848 { left: { to: offset } },
2849 animCfg.speed, animCfg.effect);
2852 carousel._isAnimationInProgress = true;
2853 animObj.onComplete.subscribe(carousel._animationCompleteHandler,
2854 { scope: carousel, item: item,
2860 * Handle the animation complete event.
2862 * @method _animationCompleteHandler
2863 * @param {Event} ev The event.
2864 * @param {Array} p The event parameters.
2865 * @param {Object} o The object that has the state of the Carousel
2868 _animationCompleteHandler: function (ev, p, o) {
2869 o.scope._isAnimationInProgress = false;
2870 updateStateAfterScroll.call(o.scope, o.item, o.last);
2874 * Automatically scroll the contents of the Carousel.
2875 * @method _autoScroll
2878 _autoScroll: function() {
2879 var carousel = this,
2880 currIndex = carousel._firstItem,
2883 if (currIndex >= carousel.get("numItems") - 1) {
2884 if (carousel.get("isCircular")) {
2887 carousel.stopAutoPlay();
2890 index = currIndex + carousel.get("numVisible");
2893 carousel._selectedItem = carousel._getSelectedItem(index);
2894 carousel.scrollTo.call(carousel, index);
2898 * Create the Carousel.
2900 * @method createCarousel
2901 * @param elId {String} The id of the element to be created
2904 _createCarousel: function (elId) {
2905 var carousel = this,
2906 cssClass = carousel.CLASSES,
2910 el = createElement("DIV", {
2911 className : cssClass.CAROUSEL,
2916 if (!carousel._carouselEl) {
2917 carousel._carouselEl=createElement(carousel.get("carouselEl"),
2918 { className: cssClass.CAROUSEL_EL });
2925 * Create the Carousel clip container.
2927 * @method createCarouselClip
2930 _createCarouselClip: function () {
2931 return createElement("DIV", { className: this.CLASSES.CONTENT });
2935 * Create the Carousel item.
2937 * @method createCarouselItem
2938 * @param obj {Object} The attributes of the element to be created
2941 _createCarouselItem: function (obj) {
2942 var attr, carousel = this,
2943 styles = getCarouselItemPosition.call(carousel, obj.pos);
2945 return createElement(carousel.get("carouselItemEl"), {
2946 className : obj.className,
2947 styles : obj.styles,
2948 content : obj.content,
2954 * Return a valid item for a possibly out of bounds index considering
2955 * the isCircular property.
2957 * @method _getValidIndex
2958 * @param index {Number} The index of the item to be returned
2959 * @return {Object} Return a valid item index
2962 _getValidIndex: function (index) {
2963 var carousel = this,
2964 isCircular = carousel.get("isCircular"),
2965 numItems = carousel.get("numItems"),
2966 numVisible = carousel.get("numVisible"),
2967 sentinel = numItems - 1;
2970 index = isCircular ?
2971 Math.ceil(numItems/numVisible)*numVisible + index : 0;
2972 } else if (index > sentinel) {
2973 index = isCircular ? 0 : sentinel;
2980 * Get the value for the selected item.
2982 * @method _getSelectedItem
2983 * @param val {Number} The new value for "selected" item
2984 * @return {Number} The new value that would be set
2987 _getSelectedItem: function (val) {
2988 var carousel = this,
2989 isCircular = carousel.get("isCircular"),
2990 numItems = carousel.get("numItems"),
2991 sentinel = numItems - 1;
2995 val = numItems + val;
2997 val = carousel.get("selectedItem");
2999 } else if (val > sentinel) {
3001 val = val - numItems;
3003 val = carousel.get("selectedItem");
3010 * The "click" handler for the item.
3012 * @method _itemClickHandler
3013 * @param {Event} ev The event object
3016 _itemClickHandler: function (ev) {
3017 var carousel = this,
3018 carouselItem = carousel.get("carouselItemEl"),
3019 container = carousel.get("element"),
3022 target = Event.getTarget(ev),
3023 tag = target.tagName.toUpperCase();
3025 if(tag === "INPUT" ||
3027 tag === "TEXTAREA") {
3031 while (target && target != container &&
3032 target.id != carousel._carouselEl) {
3033 el = target.nodeName;
3034 if (el.toUpperCase() == carouselItem) {
3037 target = target.parentNode;
3040 if ((item = carousel.getItemPositionById(target.id)) >= 0) {
3041 YAHOO.log("Setting selection to " + item, WidgetName);
3042 carousel.set("selectedItem", carousel._getSelectedItem(item));
3048 * The keyboard event handler for Carousel.
3050 * @method _keyboardEventHandler
3051 * @param ev {Event} The event that is being handled.
3054 _keyboardEventHandler: function (ev) {
3055 var carousel = this,
3056 key = Event.getCharCode(ev),
3057 target = Event.getTarget(ev),
3060 // do not mess while animation is in progress or naving via select
3061 if (carousel.isAnimating() || target.tagName.toUpperCase() === "SELECT") {
3066 case 0x25: // left arrow
3067 case 0x26: // up arrow
3068 carousel.selectPreviousItem();
3071 case 0x27: // right arrow
3072 case 0x28: // down arrow
3073 carousel.selectNextItem();
3076 case 0x21: // page-up
3077 carousel.scrollPageBackward();
3080 case 0x22: // page-down
3081 carousel.scrollPageForward();
3087 if (carousel.isAutoPlayOn()) {
3088 carousel.stopAutoPlay();
3090 Event.preventDefault(ev);
3095 * The load the required set of items that are needed for display.
3097 * @method _loadItems
3100 _loadItems: function(last) {
3101 var carousel = this,
3102 numItems = carousel.get("numItems"),
3103 numVisible = carousel.get("numVisible"),
3104 reveal = carousel.get("revealAmount"),
3105 first = carousel._itemsTable.items.length,
3106 lastVisible = carousel.get("lastVisible");
3108 // adjust if going backwards
3109 if(first > last && last+1 >= numVisible){
3110 // need to get first a bit differently for the last page
3111 first = last % numVisible || last == lastVisible ? last - last % numVisible : last - numVisible + 1;
3114 if(reveal && last < numItems - 1){ last++; }
3116 if (last >= first && (!carousel.getItem(first) || !carousel.getItem(last))) {
3117 carousel.fireEvent(loadItemsEvent, {
3118 ev: loadItemsEvent, first: first, last: last,
3119 num: last - first + 1
3126 * The "onchange" handler for select box pagination.
3128 * @method _pagerChangeHandler
3129 * @param {Event} ev The event object
3132 _pagerChangeHandler: function (ev) {
3133 var carousel = this,
3134 target = Event.getTarget(ev),
3135 page = target.value,
3139 item = carousel.getFirstVisibleOnPage(page);
3140 carousel._selectedItem = item;
3141 carousel.scrollTo(item);
3146 * The "click" handler for anchor pagination.
3148 * @method _pagerClickHandler
3149 * @param {Event} ev The event object
3152 _pagerClickHandler: function (ev) {
3153 var carousel = this,
3154 css = carousel.CLASSES,
3155 target = Event.getTarget(ev),
3156 elNode = target.nodeName.toUpperCase(),
3162 if (Dom.hasClass(target, css.PAGER_ITEM) || Dom.hasClass(target.parentNode, css.PAGER_ITEM)) {
3163 if (elNode == "EM") {
3164 target = target.parentNode;// item is an em and not an anchor (when text is visible)
3167 stringIndex = val.lastIndexOf("#");
3168 page = parseInt(val.substring(stringIndex+1), 10);
3170 item = carousel.getFirstVisibleOnPage(page);
3171 carousel._selectedItem = item;
3172 carousel.scrollTo(item);
3175 Event.preventDefault(ev);
3180 * Find the Carousel within a container. The Carousel is identified by
3181 * the first element that matches the carousel element tag or the
3182 * element that has the Carousel class.
3184 * @method parseCarousel
3185 * @param parent {HTMLElement} The parent element to look under
3186 * @return {Boolean} True if Carousel is found, false otherwise
3189 _parseCarousel: function (parent) {
3190 var carousel = this, child, cssClass, domEl, found, node;
3192 cssClass = carousel.CLASSES;
3193 domEl = carousel.get("carouselEl");
3196 for (child = parent.firstChild; child; child = child.nextSibling) {
3197 if (child.nodeType == 1) {
3198 node = child.nodeName;
3199 if (node.toUpperCase() == domEl) {
3200 carousel._carouselEl = child;
3201 Dom.addClass(carousel._carouselEl,
3202 carousel.CLASSES.CAROUSEL_EL);
3203 YAHOO.log("Found Carousel - " + node +
3204 (child.id ? " (#" + child.id + ")" : ""),
3215 * Find the items within the Carousel and add them to the items table.
3216 * A Carousel item is identified by elements that matches the carousel
3219 * @method parseCarouselItems
3222 _parseCarouselItems: function () {
3223 var carousel = this,
3224 cssClass = carousel.CLASSES,
3231 index = carousel.get("firstVisible"),
3232 parent = carousel._carouselEl;
3234 rows = carousel._rows;
3235 domItemEl = carousel.get("carouselItemEl");
3237 for (child = parent.firstChild; child; child = child.nextSibling) {
3238 if (child.nodeType == 1) {
3239 node = child.nodeName;
3240 if (node.toUpperCase() == domItemEl) {
3244 elId = Dom.generateId();
3245 child.setAttribute("id", elId);
3247 carousel.addItem(child,index);
3255 * Find the Carousel navigation within a container. The navigation
3256 * elements need to match the carousel navigation class names.
3258 * @method parseCarouselNavigation
3259 * @param parent {HTMLElement} The parent element to look under
3260 * @return {Boolean} True if at least one is found, false otherwise
3263 _parseCarouselNavigation: function (parent) {
3264 var carousel = this,
3266 cssClass = carousel.CLASSES,
3273 nav = Dom.getElementsByClassName(cssClass.PREV_PAGE, "*", parent);
3274 if (nav.length > 0) {
3276 if (nav.hasOwnProperty(i)) {
3278 YAHOO.log("Found Carousel previous page navigation - " +
3279 el + (el.id ? " (#" + el.id + ")" : ""),
3281 if (el.nodeName == "INPUT" ||
3282 el.nodeName == "BUTTON" ||
3283 el.nodeName == "A") {// Anchor support in Nav (for SEO)
3284 carousel._navBtns.prev.push(el);
3286 j = el.getElementsByTagName("INPUT");
3287 if (JS.isArray(j) && j.length > 0) {
3288 carousel._navBtns.prev.push(j[0]);
3290 j = el.getElementsByTagName("BUTTON");
3291 if (JS.isArray(j) && j.length > 0) {
3292 carousel._navBtns.prev.push(j[0]);
3298 cfg = { prev: nav };
3301 nav = Dom.getElementsByClassName(cssClass.NEXT_PAGE, "*", parent);
3302 if (nav.length > 0) {
3304 if (nav.hasOwnProperty(i)) {
3306 YAHOO.log("Found Carousel next page navigation - " +
3307 el + (el.id ? " (#" + el.id + ")" : ""),
3309 if (el.nodeName == "INPUT" ||
3310 el.nodeName == "BUTTON" ||
3311 el.nodeName == "A") {// Anchor support in Nav (for SEO)
3312 carousel._navBtns.next.push(el);
3314 j = el.getElementsByTagName("INPUT");
3315 if (JS.isArray(j) && j.length > 0) {
3316 carousel._navBtns.next.push(j[0]);
3318 j = el.getElementsByTagName("BUTTON");
3319 if (JS.isArray(j) && j.length > 0) {
3320 carousel._navBtns.next.push(j[0]);
3329 cfg = { next: nav };
3334 carousel.set("navigation", cfg);
3342 * Refresh the widget UI if it is not already rendered, on first item
3345 * @method _refreshUi
3348 _refreshUi: function () {
3349 var carousel = this, i, isVertical = carousel.get("isVertical"), firstVisible = carousel.get("firstVisible"), item, n, rsz, sz;
3351 if (carousel._itemsTable.numItems < 1) {
3355 sz = getCarouselItemSize.call(carousel,
3356 isVertical ? "height" : "width");
3357 // This fixes the widget to auto-adjust height/width for absolute
3358 // positioned children.
3359 item = carousel._itemsTable.items[firstVisible].id;
3361 sz = isVertical ? getStyle(item, "width") :
3362 getStyle(item, "height");
3364 Dom.setStyle(carousel._carouselEl,
3365 isVertical ? "width" : "height", sz + "px");
3367 // Set the rendered state appropriately.
3368 carousel._hasRendered = true;
3369 carousel.fireEvent(renderEvent);
3373 * Set the Carousel offset to the passed offset.
3375 * @method _setCarouselOffset
3378 _setCarouselOffset: function (offset) {
3379 var carousel = this, which;
3381 which = carousel.get("isVertical") ? "top" : "left";
3382 Dom.setStyle(carousel._carouselEl, which, offset + "px");
3386 * Setup/Create the Carousel navigation element (if needed).
3388 * @method _setupCarouselNavigation
3391 _setupCarouselNavigation: function () {
3392 var carousel = this,
3393 btn, cfg, cssClass, nav, navContainer, nextButton, prevButton;
3395 cssClass = carousel.CLASSES;
3397 // TODO: can the _navBtns be tested against instead?
3398 navContainer = Dom.getElementsByClassName(cssClass.NAVIGATION,
3399 "DIV", carousel.get("element"));
3401 if (navContainer.length === 0) {
3402 navContainer = createElement("DIV",
3403 { className: cssClass.NAVIGATION });
3404 carousel.insertBefore(navContainer,
3405 Dom.getFirstChild(carousel.get("element")));
3407 navContainer = navContainer[0];
3410 carousel._pages.el = createElement("UL");
3411 navContainer.appendChild(carousel._pages.el);
3413 nav = carousel.get("navigation");
3414 if (JS.isString(nav.prev) || JS.isArray(nav.prev)) {
3415 if (JS.isString(nav.prev)) {
3416 nav.prev = [nav.prev];
3418 for (btn in nav.prev) {
3419 if (nav.prev.hasOwnProperty(btn)) {
3420 carousel._navBtns.prev.push(Dom.get(nav.prev[btn]));
3424 // TODO: separate method for creating a navigation button
3425 prevButton = createElement("SPAN",
3426 { className: cssClass.BUTTON + cssClass.FIRST_NAV });
3428 Dom.setStyle(prevButton, "visibility", "visible");
3429 btn = Dom.generateId();
3430 prevButton.innerHTML = "<button type=\"button\" " +
3431 "id=\"" + btn + "\" name=\"" +
3432 carousel.STRINGS.PREVIOUS_BUTTON_TEXT + "\">" +
3433 carousel.STRINGS.PREVIOUS_BUTTON_TEXT + "</button>";
3434 navContainer.appendChild(prevButton);
3436 carousel._navBtns.prev = [btn];
3437 cfg = { prev: [prevButton] };
3440 if (JS.isString(nav.next) || JS.isArray(nav.next)) {
3441 if (JS.isString(nav.next)) {
3442 nav.next = [nav.next];
3444 for (btn in nav.next) {
3445 if (nav.next.hasOwnProperty(btn)) {
3446 carousel._navBtns.next.push(Dom.get(nav.next[btn]));
3450 // TODO: separate method for creating a navigation button
3451 nextButton = createElement("SPAN",
3452 { className: cssClass.BUTTON + cssClass.NEXT_NAV });
3454 Dom.setStyle(nextButton, "visibility", "visible");
3455 btn = Dom.generateId();
3456 nextButton.innerHTML = "<button type=\"button\" " +
3457 "id=\"" + btn + "\" name=\"" +
3458 carousel.STRINGS.NEXT_BUTTON_TEXT + "\">" +
3459 carousel.STRINGS.NEXT_BUTTON_TEXT + "</button>";
3460 navContainer.appendChild(nextButton);
3462 carousel._navBtns.next = [btn];
3464 cfg.next = [nextButton];
3466 cfg = { next: [nextButton] };
3471 carousel.set("navigation", cfg);
3474 return navContainer;
3478 * Set the clip container size (based on the new numVisible value).
3480 * @method _setClipContainerSize
3481 * @param clip {HTMLElement} The clip container element.
3482 * @param num {Number} optional The number of items per page.
3485 _setClipContainerSize: function (clip, num) {
3486 var carousel = this,
3487 isVertical = carousel.get("isVertical"),
3488 rows = carousel._rows,
3489 cols = carousel._cols,
3490 reveal = carousel.get("revealAmount"),
3491 itemHeight = getCarouselItemSize.call(carousel, "height"),
3492 itemWidth = getCarouselItemSize.call(carousel, "width"),
3496 clip = clip || carousel._clipEl;
3499 containerHeight = itemHeight * rows;
3500 containerWidth = itemWidth * cols;
3502 num = num || carousel.get("numVisible");
3504 containerHeight = itemHeight * num;
3506 containerWidth = itemWidth * num;
3510 // TODO: try to re-use the _hasRendered indicator
3512 carousel._recomputeSize = (containerHeight === 0); // bleh!
3513 if (carousel._recomputeSize) {
3514 carousel._hasRendered = false;
3515 return; // no use going further, bail out!
3518 reveal = getRevealSize.call(carousel);
3520 containerHeight += (reveal * 2);
3522 containerWidth += (reveal * 2);
3526 containerHeight += getDimensions(carousel._carouselEl,"height");
3527 Dom.setStyle(clip, "height", containerHeight + "px");
3528 // For multi-row Carousel
3530 containerWidth += getDimensions(carousel._carouselEl,
3532 Dom.setStyle(clip, "width", containerWidth + (0) + "px");
3535 containerWidth += getDimensions(carousel._carouselEl, "width");
3536 Dom.setStyle(clip, "width", containerWidth + "px");
3537 // For multi-row Carousel
3539 containerHeight += getDimensions(carousel._carouselEl,
3541 Dom.setStyle(clip, "height", containerHeight + "px");
3545 carousel._setContainerSize(clip); // adjust the container size too
3549 * Set the container size.
3551 * @method _setContainerSize
3552 * @param clip {HTMLElement} The clip container element.
3553 * @param attr {String} Either set the height or width.
3556 _setContainerSize: function (clip, attr) {
3557 var carousel = this,
3558 config = carousel.CONFIG,
3559 cssClass = carousel.CLASSES,
3565 isVertical = carousel.get("isVertical");
3566 rows = carousel._rows;
3567 cols = carousel._cols;
3568 clip = clip || carousel._clipEl;
3569 attr = attr || (isVertical ? "height" : "width");
3570 size = parseFloat(Dom.getStyle(clip, attr), 10);
3572 size = JS.isNumber(size) ? size : 0;
3575 size += getDimensions(carousel._carouselEl, "height") +
3576 getStyle(carousel._navEl, "height");
3578 size += getDimensions(carousel._carouselEl, "width");
3582 if (size < config.HORZ_MIN_WIDTH) {
3583 size = config.HORZ_MIN_WIDTH;
3584 carousel.addClass(cssClass.MIN_WIDTH);
3587 carousel.setStyle(attr, size + "px");
3589 // Additionally the width of the container should be set for
3590 // the vertical Carousel
3592 size = getCarouselItemSize.call(carousel, "width");
3596 Dom.setStyle(carousel._carouselEl, "width", size + "px");// Bug fix for vertical carousel (goes in conjunction with .yui-carousel-element {... 3200px removed from styles), and allows for multirows in IEs).
3597 if (size < config.VERT_MIN_WIDTH) {
3598 size = config.VERT_MIN_WIDTH;
3599 carousel.addClass(cssClass.MIN_WIDTH);// set a min width on vertical carousel, don't see why this shouldn't always be set...
3601 carousel.setStyle("width", size + "px");
3604 size = getCarouselItemSize.call(carousel, "height");
3606 Dom.setStyle(carousel._carouselEl, "height", size + "px");
3612 * Set the value for the Carousel's first visible item.
3614 * @method _setFirstVisible
3615 * @param val {Number} The new value for firstVisible
3616 * @return {Number} The new value that would be set
3619 _setFirstVisible: function (val) {
3620 var carousel = this;
3622 if (val >= 0 && val < carousel.get("numItems")) {
3623 carousel.scrollTo(val);
3625 val = carousel.get("firstVisible");
3631 * Set the value for the Carousel's navigation.
3633 * @method _setNavigation
3634 * @param cfg {Object} The navigation configuration
3635 * @return {Object} The new value that would be set
3638 _setNavigation: function (cfg) {
3639 var carousel = this;
3642 Event.on(cfg.prev, "click", scrollPageBackward, carousel);
3645 Event.on(cfg.next, "click", scrollPageForward, carousel);
3650 * Clip the container size every time numVisible is set.
3652 * @method _setNumVisible
3653 * @param val {Number} The new value for numVisible
3654 * @return {Number} The new value that would be set
3657 _setNumVisible: function (val) { // TODO: _setNumVisible should just be reserved for setting numVisible.
3658 var carousel = this;
3660 carousel._setClipContainerSize(carousel._clipEl, val);
3664 * Set the value for the number of visible items in the Carousel.
3666 * @method _numVisibleSetter
3667 * @param val {Number} The new value for numVisible
3668 * @return {Number} The new value that would be set
3671 _numVisibleSetter: function (val) {
3672 var carousel = this,
3675 if(JS.isArray(val)) {
3676 carousel._cols = val[0];
3677 carousel._rows = val[1];
3678 numVisible = val[0] * val[1];
3684 * Set the value for selectedItem.
3686 * @method _selectedItemSetter
3687 * @param val {Number} The new value for selectedItem
3688 * @return {Number} The new value that would be set
3691 _selectedItemSetter: function (val) {
3692 var carousel = this;
3693 return (val < carousel.get("numItems")) ? val : 0;
3697 * Set the number of items in the Carousel.
3698 * Warning: Setting this to a lower number than the current removes
3699 * items from the end.
3701 * @method _setNumItems
3702 * @param val {Number} The new value for numItems
3703 * @return {Number} The new value that would be set
3706 _setNumItems: function (val) {
3707 var carousel = this,
3708 num = carousel._itemsTable.numItems;
3710 if (JS.isArray(carousel._itemsTable.items)) {
3711 if (carousel._itemsTable.items.length != num) { // out of sync
3712 num = carousel._itemsTable.items.length;
3713 carousel._itemsTable.numItems = num;
3719 carousel.removeItem(num - 1);
3728 * Set the orientation of the Carousel.
3730 * @method _setOrientation
3731 * @param val {Boolean} The new value for isVertical
3732 * @return {Boolean} The new value that would be set
3735 _setOrientation: function (val) {
3736 var carousel = this,
3737 cssClass = carousel.CLASSES;
3740 carousel.replaceClass(cssClass.HORIZONTAL, cssClass.VERTICAL);
3742 carousel.replaceClass(cssClass.VERTICAL, cssClass.HORIZONTAL);
3744 this._itemAttrCache = {}; // force recomputed next time
3750 * Set the value for the reveal amount percentage in the Carousel.
3752 * @method _setRevealAmount
3753 * @param val {Number} The new value for revealAmount
3754 * @return {Number} The new value that would be set
3757 _setRevealAmount: function (val) {
3758 var carousel = this;
3760 if (val >= 0 && val <= 100) {
3761 val = parseInt(val, 10);
3762 val = JS.isNumber(val) ? val : 0;
3763 carousel._setClipContainerSize();
3765 val = carousel.get("revealAmount");
3771 * Set the value for the selected item.
3773 * @method _setSelectedItem
3774 * @param val {Number} The new value for "selected" item
3777 _setSelectedItem: function (val) {
3778 this._selectedItem = val;
3782 * Get the total number of pages.
3784 * @method _getNumPages
3787 _getNumPages: function () {
3789 parseInt(this.get("numItems"),10) / parseInt(this.get("numVisible"),10)
3794 * Get the index of the last visible item
3796 * @method _getLastVisible
3799 _getLastVisible: function () {
3800 var carousel = this;
3801 return carousel.get("currentPage") + 1 == carousel.get("numPages") ?
3802 carousel.get("numItems") - 1:
3803 carousel.get("firstVisible") + carousel.get("numVisible") - 1;
3807 * Synchronize and redraw the UI after an item is added.
3809 * @method _syncUiForItemAdd
3812 _syncUiForItemAdd: function (obj) {
3815 carouselEl = carousel._carouselEl,
3818 itemsTable = carousel._itemsTable,
3824 pos = JS.isUndefined(obj.pos) ?
3825 obj.newPos || itemsTable.numItems - 1 : obj.pos;
3828 item = itemsTable.items[pos] || {};
3829 el = carousel._createCarouselItem({
3830 className : item.className,
3831 styles : item.styles,
3832 content : item.item,
3836 if (JS.isUndefined(obj.pos)) {
3837 if (!JS.isUndefined(itemsTable.loading[pos])) {
3838 oel = itemsTable.loading[pos];
3839 // if oel is null, it is a problem ...
3843 carouselEl.replaceChild(el, oel);
3844 // ... and remove the item from the data structure
3845 delete itemsTable.loading[pos];
3847 carouselEl.appendChild(el);
3850 if (!JS.isUndefined(itemsTable.items[obj.pos + 1])) {
3851 sibling = Dom.get(itemsTable.items[obj.pos + 1].id);
3854 carouselEl.insertBefore(el, sibling);
3856 YAHOO.log("Unable to find sibling","error",WidgetName);
3860 if (JS.isUndefined(obj.pos)) {
3861 if (!Dom.isAncestor(carousel._carouselEl, oel)) {
3862 carouselEl.appendChild(oel);
3865 if (!Dom.isAncestor(carouselEl, oel)) {
3866 if (!JS.isUndefined(itemsTable.items[obj.pos + 1])) {
3867 carouselEl.insertBefore(oel,
3868 Dom.get(itemsTable.items[obj.pos + 1].id));
3874 if (!carousel._hasRendered) {
3875 carousel._refreshUi();
3878 if (carousel.get("selectedItem") < 0) {
3879 carousel.set("selectedItem", carousel.get("firstVisible"));
3882 carousel._syncUiItems();
3886 * Synchronize and redraw the UI after an item is replaced.
3888 * @method _syncUiForItemReplace
3891 _syncUiForItemReplace: function (o) {
3892 var carousel = this,
3893 carouselEl = carousel._carouselEl,
3894 itemsTable = carousel._itemsTable,
3900 el = carousel._createCarouselItem({
3901 className : item.className,
3902 styles : item.styles,
3903 content : item.item,
3909 Event.purgeElement(oel, true);
3910 carouselEl.replaceChild(el, Dom.get(oel.id));
3911 if (!JS.isUndefined(itemsTable.loading[pos])) {
3912 itemsTable.numItems++;
3913 delete itemsTable.loading[pos];
3916 // TODO: should we add the item if oel is undefined?
3918 if (!carousel._hasRendered) {
3919 carousel._refreshUi();
3922 carousel._syncUiItems();
3926 * Synchronize and redraw the UI after an item is removed.
3928 * @method _syncUiForItemAdd
3931 _syncUiForItemRemove: function (obj) {
3932 var carousel = this,
3933 carouselEl = carousel._carouselEl,
3936 num = carousel.get("numItems");
3940 if (item && (el = Dom.get(item.id))) {
3941 if (el && Dom.isAncestor(carouselEl, el)) {
3942 Event.purgeElement(el, true);
3943 carouselEl.removeChild(el);
3946 if (carousel.get("selectedItem") == pos) {
3947 pos = pos >= num ? num - 1 : pos;
3950 YAHOO.log("Unable to find item", "warn", WidgetName);
3953 carousel._syncUiItems();
3957 * Synchronize and redraw the UI for lazy loading.
3959 * @method _syncUiForLazyLoading
3962 _syncUiForLazyLoading: function (obj) {
3963 var carousel = this,
3964 carouselEl = carousel._carouselEl,
3965 itemsTable = carousel._itemsTable,
3966 len = itemsTable.items.length,
3967 sibling = itemsTable.items[obj.last + 1],
3971 // attempt to find the next closest sibling
3972 if(!sibling && obj.last < len){
3975 sibling = itemsTable.items[j];
3977 } while (j<len && !sibling);
3980 for (var i = obj.first; i <= obj.last; i++) {
3981 if(JS.isUndefined(itemsTable.loading[i]) && JS.isUndefined(itemsTable.items[i])){
3982 el = carousel._createCarouselItem({
3983 className : carousel.CLASSES.ITEM_LOADING,
3984 content : carousel.STRINGS.ITEM_LOADING_CONTENT,
3985 id : Dom.generateId(),
3990 sibling = Dom.get(sibling.id);
3992 carouselEl.insertBefore(el, sibling);
3994 YAHOO.log("Unable to find sibling", "error",
3998 carouselEl.appendChild(el);
4001 itemsTable.loading[i] = el;
4005 carousel._syncUiItems();
4009 * Redraw the UI for item positioning.
4011 * @method _syncUiItems
4014 _syncUiItems: function () {
4017 numItems = carousel.get("numItems"),
4019 itemsTable = carousel._itemsTable,
4020 items = itemsTable.items,
4021 loading = itemsTable.loading,
4025 for (i = 0; i < numItems; i++) {
4026 item = items[i] || loading[i];
4028 if (item && item.id) {
4029 styles = getCarouselItemPosition.call(carousel, i);
4030 item.styles = item.styles || {};
4031 for (attr in styles) {
4032 if (styles.hasOwnProperty(attr)) {
4033 item.styles[attr] = styles[attr];
4036 setStyles(Dom.get(item.id), styles);
4042 * Set the correct class for the navigation buttons.
4044 * @method _updateNavButtons
4045 * @param el {Object} The target button
4046 * @param setFocus {Boolean} True to set focus ring, false otherwise.
4049 _updateNavButtons: function (el, setFocus) {
4051 cssClass = this.CLASSES,
4053 parent = el.parentNode;
4058 grandParent = parent.parentNode;
4060 if (el.nodeName.toUpperCase() == "BUTTON" &&
4061 Dom.hasClass(parent, cssClass.BUTTON)) {
4064 children = Dom.getChildren(grandParent);
4066 Dom.removeClass(children, cssClass.FOCUSSED_BUTTON);
4069 Dom.addClass(parent, cssClass.FOCUSSED_BUTTON);
4071 Dom.removeClass(parent, cssClass.FOCUSSED_BUTTON);
4077 * Update the UI for the pager buttons based on the current page and
4078 * the number of pages.
4080 * @method _updatePagerButtons
4083 _updatePagerButtons: function () {
4084 var carousel = this,
4085 css = carousel.CLASSES,
4086 cur = carousel._pages.cur, // current page
4091 n = carousel.get("numVisible"),
4092 num = carousel._pages.num, // total pages
4093 pager = carousel._pages.el; // the pager container element
4095 if (num === 0 || !pager) {
4096 return; // don't do anything if number of pages is 0
4099 // Hide the pager before redrawing it
4100 Dom.setStyle(pager, "visibility", "hidden");
4102 // Remove all nodes from the pager
4103 while (pager.firstChild) {
4104 pager.removeChild(pager.firstChild);
4107 for (i = 0; i < num; i++) {
4109 el = document.createElement("LI");
4112 Dom.addClass(el, css.FIRST_PAGE);
4115 Dom.addClass(el, css.SELECTED_NAV);
4118 html = "<a class=" + css.PAGER_ITEM + " href=\"#" + (i+1) + "\" tabindex=\"0\"><em>" +
4119 carousel.STRINGS.PAGER_PREFIX_TEXT + " " + (i+1) +
4121 el.innerHTML = html;
4123 pager.appendChild(el);
4126 // Show the pager now
4127 Dom.setStyle(pager, "visibility", "visible");
4131 * Update the UI for the pager menu based on the current page and
4132 * the number of pages. If the number of pages is greater than
4133 * MAX_PAGER_BUTTONS, then the selection of pages is provided by a drop
4134 * down menu instead of a set of buttons.
4136 * @method _updatePagerMenu
4139 _updatePagerMenu: function () {
4140 var carousel = this,
4141 css = carousel.CLASSES,
4142 cur = carousel._pages.cur, // current page
4146 n = carousel.get("numVisible"),
4147 num = carousel._pages.num, // total pages
4148 pager = carousel._pages.el, // the pager container element
4152 return;// don't do anything if number of pages is 0
4155 sel = document.createElement("SELECT");
4159 YAHOO.log("Unable to create the pager menu", "error",
4164 // Hide the pager before redrawing it
4165 Dom.setStyle(pager, "visibility", "hidden");
4167 // Remove all nodes from the pager
4168 while (pager.firstChild) {
4169 pager.removeChild(pager.firstChild);
4172 for (i = 0; i < num; i++) {
4174 el = document.createElement("OPTION");
4176 el.innerHTML = carousel.STRINGS.PAGER_PREFIX_TEXT+" "+(i+1);
4179 el.setAttribute("selected", "selected");
4182 sel.appendChild(el);
4185 el = document.createElement("FORM");
4187 YAHOO.log("Unable to create the pager menu", "error",
4190 el.appendChild(sel);
4191 pager.appendChild(el);
4194 // Show the pager now
4195 Event.addListener(sel, "change", carousel._pagerChangeHandler, this, true);
4196 Dom.setStyle(pager, "visibility", "visible");
4200 * Set the correct tab index for the Carousel items.
4202 * @method _updateTabIndex
4203 * @param el {Object} The element to be focussed
4206 _updateTabIndex: function (el) {
4207 var carousel = this;
4210 if (carousel._focusableItemEl) {
4211 carousel._focusableItemEl.tabIndex = -1;
4213 carousel._focusableItemEl = el;
4219 * Validate animation parameters.
4221 * @method _validateAnimation
4222 * @param cfg {Object} The animation configuration
4223 * @return {Boolean} The status of the validation
4226 _validateAnimation: function (cfg) {
4229 if (JS.isObject(cfg)) {
4231 rv = rv && JS.isNumber(cfg.speed);
4234 rv = rv && JS.isFunction(cfg.effect);
4235 } else if (!JS.isUndefined(YAHOO.util.Easing)) {
4236 cfg.effect = YAHOO.util.Easing.easeOut;
4246 * Validate the firstVisible value.
4248 * @method _validateFirstVisible
4249 * @param val {Number} The first visible value
4250 * @return {Boolean} The status of the validation
4253 _validateFirstVisible: function (val) {
4254 var carousel = this, numItems = carousel.get("numItems");
4256 if (JS.isNumber(val)) {
4257 if (numItems === 0 && val == numItems) {
4260 return (val >= 0 && val < numItems);
4268 * Validate and navigation parameters.
4270 * @method _validateNavigation
4271 * @param cfg {Object} The navigation configuration
4272 * @return {Boolean} The status of the validation
4275 _validateNavigation : function (cfg) {
4278 if (!JS.isObject(cfg)) {
4283 if (!JS.isArray(cfg.prev)) {
4286 for (i in cfg.prev) {
4287 if (cfg.prev.hasOwnProperty(i)) {
4288 if (!JS.isString(cfg.prev[i].nodeName)) {
4296 if (!JS.isArray(cfg.next)) {
4299 for (i in cfg.next) {
4300 if (cfg.next.hasOwnProperty(i)) {
4301 if (!JS.isString(cfg.next[i].nodeName)) {
4312 * Validate the numItems value.
4314 * @method _validateNumItems
4315 * @param val {Number} The numItems value
4316 * @return {Boolean} The status of the validation
4319 _validateNumItems: function (val) {
4320 return JS.isNumber(val) && (val >= 0);
4324 * Validate the numVisible value.
4326 * @method _validateNumVisible
4327 * @param val {Number} The numVisible value
4328 * @return {Boolean} The status of the validation
4331 _validateNumVisible: function (val) {
4334 if (JS.isNumber(val)) {
4335 rv = val > 0 && val <= this.get("numItems");
4336 } else if (JS.isArray(val)) {
4337 if (JS.isNumber(val[0]) && JS.isNumber(val[1])) {
4338 rv = val[0] * val[1] > 0 && val.length == 2;
4346 * Validate the revealAmount value.
4348 * @method _validateRevealAmount
4349 * @param val {Number} The revealAmount value
4350 * @return {Boolean} The status of the validation
4353 _validateRevealAmount: function (val) {
4356 if (JS.isNumber(val)) {
4357 rv = val >= 0 && val < 100;
4364 * Validate the scrollIncrement value.
4366 * @method _validateScrollIncrement
4367 * @param val {Number} The scrollIncrement value
4368 * @return {Boolean} The status of the validation
4371 _validateScrollIncrement: function (val) {
4374 if (JS.isNumber(val)) {
4375 rv = (val > 0 && val < this.get("numItems"));
4385 ;; Local variables: **
4387 ;; indent-tabs-mode: nil **
4390 YAHOO.register("carousel", YAHOO.widget.Carousel, {version: "2.8.0r4", build: "2449"});