PageRenderTime 97ms CodeModel.GetById 20ms app.highlight 67ms RepoModel.GetById 1ms app.codeStats 1ms

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

http://hdbc.googlecode.com/
JavaScript | 2042 lines | 845 code | 265 blank | 932 comment | 174 complexity | ddde469bd8397d0d57eb7de969d6d04e MD5 | raw file

Large files files are truncated, but you can click here to view the full file

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

Large files files are truncated, but you can click here to view the full file