1/** 2 * Copyright (c) 2006-2007, Bill W. Scott 3 * All rights reserved. 4 * 5 * This work is licensed under the Creative Commons Attribution 2.5 License. To view a copy 6 * of this license, visit http://creativecommons.org/licenses/by/2.5/ or send a letter to 7 * Creative Commons, 543 Howard Street, 5th Floor, San Francisco, California, 94105, USA. 8 * 9 * This work was created by Bill Scott (billwscott.com, looksgoodworkswell.com). 10 * 11 * The only attribution I require is to keep this notice of copyright & license 12 * in this original source file. 13 * 14 * Version 0.6.1 - 07.08.2007 15 * 16 */ 17YAHOO.namespace("extension"); 18 19/** 20* @class 21* The carousel class manages a content list (a set of LI elements within an UL list) that can be displayed horizontally or vertically. The content can be scrolled back and forth with or without animation. The content can reference static HTML content or the list items can be created dynamically on-the-fly (with or without Ajax). The navigation and event handling can be externalized from the class. 22* @param {object|string} carouselElementID The element ID (id name or id object) of the DIV that will become a carousel 23* @param {object} carouselCfg The configuration object literal containing the configuration that should be set for this module. See configuration documentation for more details. 24* @constructor 25*/ 26YAHOO.extension.Carousel = function(carouselElementID, carouselCfg) { 27 this.init(carouselElementID, carouselCfg); 28 }; 29 30YAHOO.extension.Carousel.prototype = { 31 32 33 /** 34 * Constant denoting that the carousel size is unbounded (no limits set on scrolling) 35 * @type number 36 */ 37 UNBOUNDED_SIZE: 1000000, 38 39 /** 40 * Initializes the carousel object and all of its local members. 41 * @param {object|string} carouselElementID The element ID (id name or id object) 42 * of the DIV that will become a carousel 43 * @param {object} carouselCfg The configuration object literal containing the 44 * configuration that should be set for this module. See configuration documentation for more details. 45 */ 46 init: function(carouselElementID, carouselCfg) { 47 48 var oThis = this; 49 50 /** 51 * For deprecation. 52 * getItem is the replacement for getCarouselItem 53 */ 54 this.getCarouselItem = this.getItem; 55 56 // CSS style classes 57 var carouselListClass = "carousel-list"; 58 var carouselClipRegionClass = "carousel-clip-region"; 59 var carouselNextClass = "carousel-next"; 60 var carouselPrevClass = "carousel-prev"; 61 62 this._carouselElemID = carouselElementID; 63 this.carouselElem = YAHOO.util.Dom.get(carouselElementID); 64 65 this._prevEnabled = true; 66 this._nextEnabled = true; 67 68 // Create the config object 69 this.cfg = new YAHOO.util.Config(this); 70 71 /** 72 * scrollBeforeAmount property. 73 * Normally, set to 0, this is how much you are allowed to 74 * scroll below the first item. Setting it to 2 allows you 75 * to scroll to the -1 position. 76 * However, the load handlers will not be asked to load anything 77 * below 1. 78 * 79 * A good example is the spotlight example which treats the middle item 80 * as the "selected" item. It sets scrollBeforeAmount to 2 and 81 * scrollAfterAmount to 2. 82 * 83 * The actual items loaded would be from 1 to 15 (size=15), 84 * but scrolling range would be -1 to 17. 85 */ 86 this.cfg.addProperty("scrollBeforeAmount", { 87 value:0, 88 handler: function(type, args, carouselElem) { 89 }, 90 validator: oThis.cfg.checkNumber 91 } ); 92 93 /** 94 * scrollAfterAmount property. 95 * Normally, set to 0, this is how much you are allowed to 96 * scroll past the size. Setting it to 2 allows you 97 * to scroll to the size+scrollAfterAmount position. 98 * However, the load handlers will not be asked to load anything 99 * beyond size. 100 * 101 * A good example is the spotlight example which treats the middle item 102 * as the "selected" item. It sets scrollBeforeAmount to 2 and 103 * scrollAfterAmount to 2. 104 * 105 * The actual items loaded would be from 1 to 15 (size=15), 106 * but scrolling range would be -1 to 17. 107 */ 108 this.cfg.addProperty("scrollAfterAmount", { 109 value:0, 110 handler: function(type, args, carouselElem) { 111 }, 112 validator: oThis.cfg.checkNumber 113 } ); 114 115 /** 116 * loadOnStart property. 117 * If true, will call loadInitHandler on startup. 118 * If false, will not. Useful for delaying the initialization 119 * of the carousel for a later time after creation. 120 */ 121 this.cfg.addProperty("loadOnStart", { 122 value:true, 123 handler: function(type, args, carouselElem) { 124 // no action, only affects startup 125 }, 126 validator: oThis.cfg.checkBoolean 127 } ); 128 129 /** 130 * orientation property. 131 * Either "horizontal" or "vertical". Changes carousel from a 132 * left/right style carousel to a up/down style carousel. 133 */ 134 this.cfg.addProperty("orientation", { 135 value:"horizontal", 136 handler: function(type, args, carouselElem) { 137 oThis.reload(); 138 }, 139 validator: function(orientation) { 140 if(typeof orientation == "string") { 141 return ("horizontal,vertical".indexOf(orientation.toLowerCase()) != -1); 142 } else { 143 return false;
144 } 145 } 146 } ); 147 148 /** 149 * size property. 150 * The upper bound for scrolling in the 'next' set of content. 151 * Set to a large value by default (this means unlimited scrolling.) 152 */ 153 this.cfg.addProperty("size", { 154 value:this.UNBOUNDED_SIZE, 155 handler: function(type, args, carouselElem) { 156 oThis.reload(); 157 }, 158 validator: oThis.cfg.checkNumber 159 } ); 160 161 /** 162 * numVisible property. 163 * The number of items that will be visible. 164 */ 165 this.cfg.addProperty("numVisible", { 166 value:3, 167 handler: function(type, args, carouselElem) { 168 oThis.reload(); 169 }, 170 validator: oThis.cfg.checkNumber 171 } ); 172 173 /** 174 * firstVisible property. 175 * Sets which item should be the first visible item in the carousel. Use to set which item will 176 * display as the first element when the carousel is first displayed. After the carousel is created, 177 * you can manipulate which item is the first visible by using the moveTo() or scrollTo() convenience 178 * methods. Can be < 1 or greater than size if the scrollBeforeAmount or scrollAmountAfter has been set 179 * to non-zero values. 180 */ 181 this.cfg.addProperty("firstVisible", { 182 value:1, 183 handler: function(type, args, carouselElem) { 184 oThis.moveTo(args[0]); 185 }, 186 validator: oThis.cfg.checkNumber 187 } ); 188 189 /** 190 * scrollInc property. 191 * The number of items to scroll by. Think of this as the page increment. 192 */ 193 this.cfg.addProperty("scrollInc", { 194 value:3, 195 handler: function(type, args, carouselElem) { 196 }, 197 validator: oThis.cfg.checkNumber 198 } ); 199
200 /** 201 * animationSpeed property. 202 * The time (in seconds) it takes to complete the scroll animation. 203 * If set to 0, animated transitions are turned off and the new page of content is 204 * moved immdediately into place. 205 */ 206 this.cfg.addProperty("animationSpeed", { 207 value:0.25, 208 handler: function(type, args, carouselElem) { 209 oThis.animationSpeed = args[0]; 210 }, 211 validator: oThis.cfg.checkNumber 212 } ); 213 214 /** 215 * animationMethod property. 216 * The <a href="http://developer.yahoo.com/yui/docs/animation/YAHOO.util.Easing.html">YAHOO.util.Easing</a> 217 * method. 218 */ 219 this.cfg.addProperty("animationMethod", { 220 value: YAHOO.util.Easing.easeOut, 221 handler: function(type, args, carouselElem) { 222 } 223 } ); 224 225 /** 226 * animationCompleteHandler property. 227 * JavaScript function that is called when the Carousel finishes animation 228 * after a next or previous nagivation. 229 * Only invoked if animationSpeed > 0. 230 * Two parameters are passed: type (set to 'onAnimationComplete') and 231 * args array (args[0] = direction [either: 'next' or 'previous']). 232 */ 233 this.cfg.addProperty("animationCompleteHandler", { 234 value:null, 235 handler: function(type, args, carouselElem) { 236 if(oThis._animationCompleteEvt) { 237 oThis._animationCompleteEvt.unsubscribe(oThis._currAnimationCompleteHandler, oThis); 238 } 239 oThis._currAnimationCompleteHandler = args[0]; 240 if(oThis._currAnimationCompleteHandler) { 241 if(!oThis._animationCompleteEvt) { 242 oThis._animationCompleteEvt = new YAHOO.util.CustomEvent("onAnimationComplete", oThis); 243 } 244 oThis._animationCompleteEvt.subscribe(oThis._currAnimationCompleteHandler, oThis); 245 } 246 } 247 } ); 248 249 /** 250 * autoPlay property. 251 * Specifies how many milliseconds to periodically auto scroll the content. 252 * If set to 0 (default) then autoPlay is turned off. 253 * If the user interacts by clicking left or right navigation, autoPlay is turned off. 254 * You can restart autoPlay by calling the <em>startAutoPlay()</em>. 255 * If you externally control navigation (with your own event handlers) 256 * then you may want to turn off the autoPlay by calling<em>stopAutoPlay()</em> 257 */ 258 this.cfg.addProperty("autoPlay", { 259 value:0, 260 handler: function(type, args, carouselElem) { 261 var autoPlay = args[0]; 262 if(autoPlay > 0) 263 oThis.startAutoPlay(); 264 else 265 oThis.stopAutoPlay(); 266 } 267 } ); 268 269 /** 270 * wrap property. 271 * Specifies whether to wrap when at the end of scrolled content. When the end is reached, 272 * the carousel will scroll backwards to the item 1 (the animationSpeed parameter is used to 273 * determine how quickly it should animate back to the start.) 274 * Ignored if the <em>size</em> attribute is not explicitly set 275 * (i.e., value equals YAHOO.extension.Carousel.UNBOUNDED_SIZE) 276 */ 277 this.cfg.addProperty("wrap", { 278 value:false, 279 handler: function(type, args, carouselElem) { 280 }, 281 validator: oThis.cfg.checkBoolean 282 } ); 283 284 /** 285 * navMargin property. 286 * The margin space for the navigation controls. This is only useful for horizontal carousels 287 * in which you have embedded navigation controls. 288 * The <em>navMargin</em> allocates space between the left and right margins 289 * (each navMargin wide) giving space for the navigation controls. 290 */ 291 this.cfg.addProperty("navMargin", { 292 value:0, 293 handler: function(type, args, carouselElem) { 294 oThis.calculateSize(); 295 }, 296 validator: oThis.cfg.checkNumber 297 } ); 298
299 /** 300 * revealAmount property. 301 * The amount to reveal of what comes before and what comes after the firstVisible and 302 * the lastVisible items. Setting this will provide a slight preview that something 303 * exists before and after, providing an additional hint for the user. 304 * The <em>revealAmount</em> will reveal the specified number of pixels for any item 305 * before the firstVisible and an item after the lastVisible. Additionall, the 306 * loadNextHandler and loadPrevHandler methods will be passed a start or end that guarantees 307 * the revealed item will be loaded (if set to non-zero). 308 */ 309 this.cfg.addProperty("revealAmount", { 310 value:0, 311 handler: function(type, args, carouselElem) { 312 oThis.reload(); 313 }, 314 validator: oThis.cfg.checkNumber 315 } ); 316 317 // For backward compatibility. Deprecated. 318 this.cfg.addProperty("prevElementID", { 319 value: null, 320 handler: function(type, args, carouselElem) { 321 if(oThis._carouselPrev) { 322 YAHOO.util.Event.removeListener(oThis._carouselPrev, "click", oThis._scrollPrev); 323 } 324 oThis._prevElementID = args[0]; 325 if(oThis._prevElementID == null) { 326 oThis._carouselPrev = YAHOO.util.Dom.getElementsByClassName(carouselPrevClass, 327 "div", oThis.carouselElem)[0]; 328 } else { 329 oThis._carouselPrev = YAHOO.util.Dom.get(oThis._prevElementID); 330 } 331 YAHOO.util.Event.addListener(oThis._carouselPrev, "click", oThis._scrollPrev, oThis); 332 } 333 }); 334 335 /** 336 * prevElement property. 337 * An element or elements that will provide the previous navigation control. 338 * prevElement may be a single element or an array of elements. The values may be strings denoting 339 * the ID of the element or the object itself. 340 * If supplied, then events are wired to this control to fire scroll events to move the carousel to 341 * the previous content. 342 * You may want to provide your own interaction for controlling the carousel. If 343 * so leave this unset and provide your own event handling mechanism. 344 */ 345 this.cfg.addProperty("prevElement", { 346 value:null, 347 handler: function(type, args, carouselElem) { 348 if(oThis._carouselPrev) { 349 YAHOO.util.Event.removeListener(oThis._carouselPrev, "click", oThis._scrollPrev); 350 } 351 oThis._prevElementID = args[0]; 352 if(oThis._prevElementID == null) { 353 oThis._carouselPrev = YAHOO.util.Dom.getElementsByClassName(carouselPrevClass, 354 "div", oThis.carouselElem)[0]; 355 } else { 356 oThis._carouselPrev = YAHOO.util.Dom.get(oThis._prevElementID); 357 } 358 YAHOO.util.Event.addListener(oThis._carouselPrev, "click", oThis._scrollPrev, oThis); 359 } 360 } ); 361 362 // For backward compatibility. Deprecated. 363 this.cfg.addProperty("nextElementID", { 364 value: null, 365 handler: function(type, args, carouselElem) { 366 if(oThis._carouselNext) { 367 YAHOO.util.Event.removeListener(oThis._carouselNext, "click", oThis._scrollNext); 368 } 369 oThis._nextElementID = args[0]; 370 if(oThis._nextElementID == null) { 371 oThis._carouselNext = YAHOO.util.Dom.getElementsByClassName(carouselNextClass, 372 "div", oThis.carouselElem); 373 } else { 374 oThis._carouselNext = YAHOO.util.Dom.get(oThis._nextElementID); 375 } 376 if(oThis._carouselNext) { 377 YAHOO.util.Event.addListener(oThis._carouselNext, "click", oThis._scrollNext, oThis); 378 } 379 } 380 }); 381 382 /** 383 * nextElement property. 384 * An element or elements that will provide the next navigation control. 385 * nextElement may be a single element or an array of elements. The values may be strings denoting 386 * the ID of the element or the object itself. 387 * If supplied, then events are wired to this control to fire scroll events to move the carousel to 388 * the next content. 389 * You may want to provide your own interaction for controlling the carousel. If 390 * so leave this unset and provide your own event handling mechanism. 391 */ 392 this.cfg.addProperty("nextElement", { 393 value:null, 394 handler: function(type, args, carouselElem) { 395 if(oThis._carouselNext) { 396 YAHOO.util.Event.removeListener(oThis._carouselNext, "click", oThis._scrollNext); 397 } 398 oThis._nextElementID = args[0]; 399 if(oThis._nextElementID == null) { 400 oThis._carouselNext = YAHOO.util.Dom.getElementsByClassName(carouselNextClass, 401 "div", oThis.carouselElem); 402 } else { 403 oThis._carouselNext = YAHOO.util.Dom.get(oThis._nextElementID); 404 } 405 if(oThis._carouselNext) { 406 YAHOO.util.Event.addListener(oThis._carouselNext, "click", oThis._scrollNext, oThis); 407 } 408 } 409 } ); 410
411 /** 412 * loadInitHandler property. 413 * JavaScript function that is called when the Carousel needs to load 414 * the initial set of visible items. Two parameters are passed: 415 * type (set to 'onLoadInit') and an argument array (args[0] = start index, args[1] = last index). 416 */ 417 this.cfg.addProperty("loadInitHandler", { 418 value:null, 419 handler: function(type, args, carouselElem) { 420 if(oThis._loadInitHandlerEvt) { 421 oThis._loadInitHandlerEvt.unsubscribe(oThis._currLoadInitHandler, oThis); 422 } 423 oThis._currLoadInitHandler = args[0]; 424 if(oThis._currLoadInitHandler) { 425 if(!oThis._loadInitHandlerEvt) { 426 oThis._loadInitHandlerEvt = new YAHOO.util.CustomEvent("onLoadInit", oThis); 427 } 428 oThis._loadInitHandlerEvt.subscribe(oThis._currLoadInitHandler, oThis); 429 } 430 } 431 } ); 432 433 /** 434 * loadNextHandler property. 435 * JavaScript function that is called when the Carousel needs to load 436 * the next set of items (in response to the user navigating to the next set.) 437 * Two parameters are passed: type (set to 'onLoadNext') and 438 * args array (args[0] = start index, args[1] = last index). 439 */ 440 this.cfg.addProperty("loadNextHandler", { 441 value:null, 442 handler: function(type, args, carouselElem) { 443 if(oThis._loadNextHandlerEvt) { 444 oThis._loadNextHandlerEvt.unsubscribe(oThis._currLoadNextHandler, oThis); 445 } 446 oThis._currLoadNextHandler = args[0]; 447 if(oThis._currLoadNextHandler) { 448 if(!oThis._loadNextHandlerEvt) { 449 oThis._loadNextHandlerEvt = new YAHOO.util.CustomEvent("onLoadNext", oThis); 450 } 451 oThis._loadNextHandlerEvt.subscribe(oThis._currLoadNextHandler, oThis); 452 } 453 } 454 } ); 455 456 /** 457 * loadPrevHandler property. 458 * JavaScript function that is called when the Carousel needs to load 459 * the previous set of items (in response to the user navigating to the previous set.) 460 * Two parameters are passed: type (set to 'onLoadPrev') and args array 461 * (args[0] = start index, args[1] = last index). 462 */ 463 this.cfg.addProperty("loadPrevHandler", { 464 value:null, 465 handler: function(type, args, carouselElem) { 466 if(oThis._loadPrevHandlerEvt) { 467 oThis._loadPrevHandlerEvt.unsubscribe(oThis._currLoadPrevHandler, oThis); 468 } 469 oThis._currLoadPrevHandler = args[0]; 470 if(oThis._currLoadPrevHandler) { 471 if(!oThis._loadPrevHandlerEvt) { 472 oThis._loadPrevHandlerEvt = new YAHOO.util.CustomEvent("onLoadPrev", oThis); 473 } 474 oThis._loadPrevHandlerEvt.subscribe(oThis._currLoadPrevHandler, oThis); 475 } 476 } 477 } ); 478 479 /** 480 * prevButtonStateHandler property. 481 * JavaScript function that is called when the enabled state of the 482 * 'previous' control is changing. The responsibility of 483 * this method is to enable or disable the 'previous' control. 484 * Two parameters are passed to this method: <em>type</em> 485 * (which is set to "onPrevButtonStateChange") and <em>args</em>, 486 * an array that contains two values. 487 * The parameter args[0] is a flag denoting whether the 'previous' control 488 * is being enabled or disabled. The parameter args[1] is the element object 489 * derived from the <em>prevElement</em> parameter. 490 * If you do not supply a prevElement then you will need to track 491 * the elements that you would want to enable/disable while handling the state change. 492 */ 493 this.cfg.addProperty("prevButtonStateHandler", { 494 value:null, 495 handler: function(type, args, carouselElem) { 496 if(oThis._currPrevButtonStateHandler) { 497 oThis._prevButtonStateHandlerEvt.unsubscribe(oThis._currPrevButtonStateHandler, oThis); 498 } 499 500 oThis._currPrevButtonStateHandler = args[0]; 501 502 if(oThis._currPrevButtonStateHandler) { 503 if(!oThis._prevButtonStateHandlerEvt) { 504 oThis._prevButtonStateHandlerEvt = new YAHOO.util.CustomEvent("onPrevButtonStateChange", oThis); 505 } 506 oThis._prevButtonStateHandlerEvt.subscribe(oThis._currPrevButtonStateHandler, oThis); 507 } 508 } 509 } ); 510 511 /** 512 * nextButtonStateHandler property. 513 * JavaScript function that is called when the enabled state of the 514 * 'next' control is changing. The responsibility of 515 * this method is to enable or disable the 'next' control. 516 * Two parameters are passed to this method: <em>type</em> 517 * (which is set to "onNextButtonStateChange") and <em>args</em>, 518 * an array that contains two values. 519 * The parameter args[0] is a flag denoting whether the 'next' control
520 * is being enabled or disabled. The parameter args[1] is the element object 521 * derived from the <em>nextElement</em> parameter. 522 * If you do not supply a nextElement then you will need to track 523 * the elements that you would want to enable/disable while handling the state change. 524 */ 525 this.cfg.addProperty("nextButtonStateHandler", { 526 value:null, 527 handler: function(type, args, carouselElem) { 528 if(oThis._currNextButtonStateHandler) { 529 oThis._nextButtonStateHandlerEvt.unsubscribe(oThis._currNextButtonStateHandler, oThis); 530 } 531 oThis._currNextButtonStateHandler = args[0]; 532 533 if(oThis._currNextButtonStateHandler) { 534 if(!oThis._nextButtonStateHandlerEvt) { 535 oThis._nextButtonStateHandlerEvt = new YAHOO.util.CustomEvent("onNextButtonStateChange", oThis); 536 } 537 oThis._nextButtonStateHandlerEvt.subscribe(oThis._currNextButtonStateHandler, oThis); 538 } 539 } 540 } ); 541 542 543 if(carouselCfg) { 544 this.cfg.applyConfig(carouselCfg); 545 } 546 547 this._origFirstVisible = this.cfg.getProperty("firstVisible"); 548 549 // keep a copy of curr handler so it can be removed when a new handler is set 550 this._currLoadInitHandler = this.cfg.getProperty("loadInitHandler"); 551 this._currLoadNextHandler = this.cfg.getProperty("loadNextHandler"); 552 this._currLoadPrevHandler = this.cfg.getProperty("loadPrevHandler"); 553 this._currPrevButtonStateHandler = this.cfg.getProperty("prevButtonStateHandler"); 554 this._currNextButtonStateHandler = this.cfg.getProperty("nextButtonStateHandler"); 555 this._currAnimationCompleteHandler = this.cfg.getProperty("animationCompleteHandler"); 556 557 this._nextElementID = this.cfg.getProperty("nextElementID"); 558 if(!this._nextElementID) 559 this._nextElementID = this.cfg.getProperty("nextElement"); 560 561 this._prevElementID = this.cfg.getProperty("prevElementID"); 562 if(!this._prevElementID) 563 this._prevElementID = this.cfg.getProperty("prevElement"); 564 565 this._autoPlayTimer = null; 566 this._priorLastVisible = this._priorFirstVisible = this.cfg.getProperty("firstVisible"); 567 this._lastPrebuiltIdx = 0; 568// this._currSize = 0; 569 570 // prefetch elements 571 this.carouselList = YAHOO.util.Dom.getElementsByClassName(carouselListClass, 572 "ul", this.carouselElem)[0]; 573 574 if(this._nextElementID == null) { 575 this._carouselNext = YAHOO.util.Dom.getElementsByClassName(carouselNextClass, 576 "div", this.carouselElem)[0]; 577 } else { 578 this._carouselNext = YAHOO.util.Dom.get(this._nextElementID); 579 } 580 581 if(this._prevElementID == null) { 582 this._carouselPrev = YAHOO.util.Dom.getElementsByClassName(carouselPrevClass, 583 "div", this.carouselElem)[0]; 584 } else { 585 this._carouselPrev = YAHOO.util.Dom.get(this._prevElementID); 586 } 587 588 this._clipReg = YAHOO.util.Dom.getElementsByClassName(carouselClipRegionClass, 589 "div", this.carouselElem)[0]; 590 591 // add a style class dynamically so that the correct styles get applied for a vertical carousel 592 if(this.isVertical()) { 593 YAHOO.util.Dom.addClass(this.carouselList, "carousel-vertical"); 594 } 595 596 // initialize the animation objects for next/previous 597 this._scrollNextAnim = new YAHOO.util.Motion(this.carouselList, this.scrollNextParams, 598 this.cfg.getProperty("animationSpeed"), this.cfg.getProperty("animationMethod")); 599 this._scrollPrevAnim = new YAHOO.util.Motion(this.carouselList, this.scrollPrevParams, 600 this.cfg.getProperty("animationSpeed"), this.cfg.getProperty("animationMethod")); 601 602 // If they supplied a nextElementID then wire an event listener for the click 603 if(this._carouselNext) { 604 YAHOO.util.Event.addListener(this._carouselNext, "click", this._scrollNext, this); 605 } 606 607 // If they supplied a prevElementID then wire an event listener for the click 608 if(this._carouselPrev) { 609 YAHOO.util.Event.addListener(this._carouselPrev, "click", this._scrollPrev, this); 610 } 611 612 // Wire up the various event handlers that they might have supplied 613 var loadInitHandler = this.cfg.getProperty("loadInitHandler"); 614 if(loadInitHandler) { 615 this._loadInitHandlerEvt = new YAHOO.util.CustomEvent("onLoadInit", this); 616 this._loadInitHandlerEvt.subscribe(loadInitHandler, this); 617 } 618 var loadNextHandler = this.cfg.getProperty("loadNextHandler"); 619 if(loadNextHandler) { 620 this._loadNextHandlerEvt = new YAHOO.util.CustomEvent("onLoadNext", this); 621 this._loadNextHandlerEvt.subscribe(loadNextHandler, this); 622 } 623 var loadPrevHandler = this.cfg.getProperty("loadPrevHandler"); 624 if(loadPrevHandler) { 625 this._loadPrevHandlerEvt = new YAHOO.util.CustomEvent("onLoadPrev", this); 626 this._loadPrevHandlerEvt.subscribe(loadPrevHandler, this); 627 } 628 var animationCompleteHandler = this.cfg.getProperty("animationCompleteHandler"); 629 if(animationCompleteHandler) { 630 this._animationCompleteEvt = new YAHOO.util.CustomEvent("onAnimationComplete", this); 631 this._animationCompleteEvt.subscribe(animationCompleteHandler, this); 632 } 633 var prevButtonStateHandler = this.cfg.getProperty("prevButtonStateHandler"); 634 if(prevButtonStateHandler) { 635 this._prevButtonStateHandlerEvt = new YAHOO.util.CustomEvent("onPrevButtonStateChange", 636 this); 637 this._prevButtonStateHandlerEvt.subscribe(prevButtonStateHandler, this); 638 } 639 var nextButtonStateHandler = this.cfg.getProperty("nextButtonStateHandler"); 640 if(nextButtonStateHandler) { 641 this._nextButtonStateHandlerEvt = new YAHOO.util.CustomEvent("onNextButtonStateChange", this); 642 this._nextButtonStateHandlerEvt.subscribe(nextButtonStateHandler, this); 643 } 644 645 // Since loading may take some time, wire up a listener to fire when at least the first 646 // element actually gets loaded 647 var visibleExtent = this._calculateVisibleExtent(); 648 YAHOO.util.Event.onAvailable(this._carouselElemID + "-item-"+ 649 visibleExtent.start, this._calculateSize, this); 650 651 // Call the initial loading sequence 652 if(this.cfg.getProperty("loadOnStart")) 653 this._loadInitial(); 654 655 }, 656 657 // /////////////////// Public API ////////////////////////////////////////// 658 659 /** 660 * Clears all items from the list and resets to the carousel to its original initial state. 661 */ 662 clear: function() { 663 // remove all items from the carousel for dynamic content 664 var loadInitHandler = this.cfg.getProperty("loadInitHandler"); 665 if(loadInitHandler) { 666 this._removeChildrenFromNode(this.carouselList); 667 this._lastPrebuiltIdx = 0; 668 } 669 // turn off autoplay 670 this.stopAutoPlay(); // should we only turn this off for dynamic during reload? 671 672 this._priorLastVisible = this._priorFirstVisible = this._origFirstVisible; 673 674 // is this redundant since moveTo will set this? 675 this.cfg.setProperty("firstVisible", this._origFirstVisible, true); 676 this.moveTo(this._origFirstVisible); 677 }, 678 679 /** 680 * Clears all items from the list and calls the loadInitHandler to load new items into the list. 681 * The carousel size is reset to the original size set during creation. 682 * @param {number} numVisible Optional parameter: numVisible. 683 * If set, the carousel will resize on the reload to show numVisible items. 684 */ 685 reload: function(numVisible) {
686 // this should be deprecated, not needed since can be set via property change 687 if(this._isValidObj(numVisible)) { 688 this.cfg.setProperty("numVisible", numVisible); 689 } 690 this.clear(); 691 692 // clear resets back to start 693 var visibleExtent = this._calculateVisibleExtent(); 694 YAHOO.util.Event.onAvailable(this._carouselElemID+"-item-"+visibleExtent.start, 695 this._calculateSize, this); 696 this._loadInitial(); 697 698 }, 699 700 load: function() { 701 var visibleExtent = this._calculateVisibleExtent(); 702 703 YAHOO.util.Event.onAvailable(this._carouselElemID + "-item-"+visibleExtent.start, 704 this._calculateSize, this); 705 this._loadInitial(); 706 }, 707 708 /** 709 * With patch from Dan Hobbs for handling unordered loading. 710 * @param {number} idx which item in the list to potentially create. 711 * If item already exists it will not create a new item. 712 * @param {string} innerHTML The innerHTML string to use to create the contents of an LI element. 713 * @param {string} itemClass A class optionally supplied to add to the LI item created 714 */ 715 addItem: function(idx, innerHTMLOrElem, itemClass) { 716 717 if(idx > this.cfg.getProperty("size")) { 718 return null; 719 } 720 721 var liElem = this.getItem(idx); 722 723 // Need to create the li 724 if(!this._isValidObj(liElem)) { 725 liElem = this._createItem(idx, innerHTMLOrElem); 726 this.carouselList.appendChild(liElem); 727 728 } else if(this._isValidObj(liElem.placeholder)) { 729 var newLiElem = this._createItem(idx, innerHTMLOrElem); 730 this.carouselList.replaceChild(newLiElem, liElem); 731 liElem = newLiElem; 732 } 733 734 // if they supplied an item class add it to the element 735 if(this._isValidObj(itemClass)){ 736 YAHOO.util.Dom.addClass(liElem, itemClass); 737 } 738 739 /** 740 * Not real comfortable with this line of code. It exists for vertical 741 * carousels for IE6. For some reason LI elements are not displaying 742 * unless you after the fact set the display to block. (Even though 743 * the CSS sets vertical LIs to display:block) 744 */ 745 if(this.isVertical()) 746 setTimeout( function() { liElem.style.display="block"; }, 1 ); 747 748 return liElem; 749 750 }, 751 752 /** 753 * Inserts a new LI item before the index specified. Uses the innerHTML to create the contents of the new LI item 754 * @param {number} refIdx which item in the list to insert this item before. 755 * @param {string} innerHTML The innerHTML string to use to create the contents of an LI element. 756 */ 757 insertBefore: function(refIdx, innerHTML) { 758 // don't allow insertion beyond the size 759 if(refIdx >= this.cfg.getProperty("size")) { 760 return null; 761 } 762 763 if(refIdx < 1) { 764 refIdx = 1; 765 } 766 767 var insertionIdx = refIdx - 1; 768 769 if(insertionIdx > this._lastPrebuiltIdx) { 770 this._prebuildItems(this._lastPrebuiltIdx, refIdx); // is this right? 771 } 772 773 var liElem = this._insertBeforeItem(refIdx, innerHTML); 774 775 this._enableDisableControls(); 776 777 return liElem; 778 }, 779 780 /** 781 * Inserts a new LI item after the index specified. Uses the innerHTML to create the contents of the new LI item 782 * @param {number} refIdx which item in the list to insert this item after. 783 * @param {string} innerHTML The innerHTML string to use to create the contents of an LI element. 784 */ 785 insertAfter: function(refIdx, innerHTML) { 786 787 if(refIdx > this.cfg.getProperty("size")) { 788 refIdx = this.cfg.getProperty("size"); 789 } 790 791 var insertionIdx = refIdx + 1; 792 793 // if we are inserting this item past where we have prebuilt items, then 794 // prebuild up to this point. 795 if(insertionIdx > this._lastPrebuiltIdx) { 796 this._prebuildItems(this._lastPrebuiltIdx, insertionIdx+1); 797 } 798 799 var liElem = this._insertAfterItem(refIdx, innerHTML); 800 801 if(insertionIdx > this.cfg.getProperty("size")) { 802 this.cfg.setProperty("size", insertionIdx, true); 803 } 804 805 this._enableDisableControls(); 806 807 return liElem; 808 }, 809 810 /** 811 * Simulates a next button event. Causes the carousel to scroll the next set of content into view. 812 */ 813 scrollNext: function() { 814 this._scrollNext(null, this); 815 816 // we know the timer has expired. 817 //if(this._autoPlayTimer) clearTimeout(this._autoPlayTimer); 818 this._autoPlayTimer = null; 819 if(this.cfg.getProperty("autoPlay") !== 0) { 820 this._autoPlayTimer = this.startAutoPlay(); 821 } 822 }, 823 824 /** 825 * Simulates a prev button event. Causes the carousel to scroll the previous set of content into view. 826 */ 827 scrollPrev: function() { 828 this._scrollPrev(null, this); 829 }, 830 831 /** 832 * Scrolls the content to place itemNum as the start item in the view 833 * (if size is specified, the last element will not scroll past the end.). 834 * Uses current animation speed & method. 835 * @param {number} newStart The item to scroll to. 836 */ 837 scrollTo: function(newStart) { 838 this._position(newStart, true); 839 }, 840 841 /** 842 * Moves the content to place itemNum as the start item in the view 843 * (if size is specified, the last element will not scroll past the end.) 844 * Ignores animation speed & method; moves directly to the item. 845 * Note that you can also set the <em>firstVisible</em> property upon initialization 846 * to get the carousel to start at a position different than 1. 847 * @param {number} newStart The item to move directly to. 848 */ 849 moveTo: function(newStart) { 850 this._position(newStart, false); 851 }, 852 853 /**
854 * Starts up autoplay. If autoPlay has been stopped (by calling stopAutoPlay or by user interaction), 855 * you can start it back up by using this method. 856 * @param {number} interval optional parameter that sets the interval 857 * for auto play the next time that autoplay fires. 858 */ 859 startAutoPlay: function(interval) { 860 // if interval is passed as arg, then set autoPlay to this interval. 861 if(this._isValidObj(interval)) { 862 this.cfg.setProperty("autoPlay", interval, true); 863 } 864 865 // if we already are playing, then do nothing. 866 if(this._autoPlayTimer !== null) { 867 return this._autoPlayTimer; 868 } 869 870 var oThis = this; 871 var autoScroll = function() { oThis.scrollNext(); }; 872 this._autoPlayTimer = setTimeout( autoScroll, this.cfg.getProperty("autoPlay") ); 873 874 return this._autoPlayTimer; 875 }, 876 877 /** 878 * Stops autoplay. Useful for when you want to control what events will stop the autoplay feature. 879 * Call <em>startAutoPlay()</em> to restart autoplay. 880 */ 881 stopAutoPlay: function() { 882 if (this._autoPlayTimer !== null) { 883 clearTimeout(this._autoPlayTimer); 884 this._autoPlayTimer = null; 885 } 886 }, 887 888 /** 889 * Returns whether the carousel's orientation is set to vertical. 890 */ 891 isVertical: function() { 892 return (this.cfg.getProperty("orientation") != "horizontal"); 893 }, 894 895 896 /** 897 * Check to see if an element (by index) has been loaded or not. If the item is simply pre-built, but not 898 * loaded this will return false. If the item has not been pre-built it will also return false. 899 * @param {number} idx Index of the element to check load status for. 900 */ 901 isItemLoaded: function(idx) { 902 var liElem = this.getItem(idx); 903 904 // if item exists and is not a placeholder, then it is already loaded. 905 if(this._isValidObj(liElem) && !this._isValidObj(liElem.placeholder)) { 906 return true; 907 } 908 909 return false; 910 }, 911 912 /** 913 * Lookup the element object for a carousel list item by index. 914 * @param {number} idx Index of the element to lookup. 915 */ 916 getItem: function(idx) { 917 var elemName = this._carouselElemID + "-item-" + idx; 918 var liElem = YAHOO.util.Dom.get(elemName); 919 return liElem; 920 }, 921 922 show: function() { 923 YAHOO.util.Dom.setStyle(this.carouselElem, "display", "block"); 924 this.calculateSize(); 925 }, 926 927 hide: function() { 928 YAHOO.util.Dom.setStyle(this.carouselElem, "display", "none"); 929 }, 930 931 calculateSize: function() { 932 var ulKids = this.carouselList.childNodes; 933 var li = null; 934 for(var i=0; i<ulKids.length; i++) { 935 936 li = ulKids[i]; 937 if(li.tagName == "LI" || li.tagName == "li") { 938 break; 939 } 940 } 941 942 var navMargin = this.cfg.getProperty("navMargin"); 943 var numVisible = this.cfg.getProperty("numVisible"); 944 var firstVisible = this.cfg.getProperty("firstVisible"); 945 var pl = this._getStyleVal(li, "paddingLeft"); 946 var pr = this._getStyleVal(li, "paddingRight"); 947 var ml = this._getStyleVal(li, "marginLeft"); 948 var mr = this._getStyleVal(li, "marginRight"); 949 var pt = this._getStyleVal(li, "paddingTop"); 950 var pb = this._getStyleVal(li, "paddingBottom"); 951 var mt = this._getStyleVal(li, "marginTop"); 952 var mb = this._getStyleVal(li, "marginBottom"); 953 954 YAHOO.util.Dom.removeClass(this.carouselList, "carousel-vertical"); 955 YAHOO.util.Dom.removeClass(this.carouselList, "carousel-horizontal"); 956 if(this.isVertical()) { 957 var liPaddingMarginWidth = pl + pr + ml + mr; 958 YAHOO.util.Dom.addClass(this.carouselList, "carousel-vertical"); 959 var liPaddingMarginHeight = pt + pb + mt + mb; 960 961 var upt = this._getStyleVal(this.carouselList, "paddingTop"); 962 var upb = this._getStyleVal(this.carouselList, "paddingBottom"); 963 var umt = this._getStyleVal(this.carouselList, "marginTop") 964 var umb = this._getStyleVal(this.carouselList, "marginBottom") 965 var ulPaddingHeight = upt + upb + umt + umb; 966 967 // try to reveal the amount taking into consideration the margin & padding. 968 // This guarantees that this.revealAmount of pixels will be shown on both sides 969 var revealAmt = (this._isExtraRevealed()) ? 970 (this.cfg.getProperty("revealAmount")+(liPaddingMarginHeight)/2) : 0; 971 972 // get the height from the height computed style not the offset height 973 // The reason is that on IE the offsetHeight when some part of the margin is 974 // explicitly set to 'auto' can cause accessing that value to crash AND 975 // on FF, in certain cases the actual value used for the LI's height is fractional 976 // For example, while li.offsetHeight might return 93, YAHOO.util.Dom.getStyle(li, "height") 977 // would return "93.2px". This fractional value will affect the scrolling, so it must be
978 // factored in for FF. 979 // The caveat is that for IE, you will need to set the LI's height explicitly 980 // REPLACED: this.scrollAmountPerInc = (li.offsetHeight + liPaddingMarginHeight); 981 // WITH: 982 var liHeight = this._getStyleVal(li, "height", true); 983 this.scrollAmountPerInc = (liHeight + liPaddingMarginHeight); 984 985 var liWidth = this._getStyleVal(li, "width"); 986 this.carouselElem.style.width = (liWidth + liPaddingMarginWidth) + "px"; 987 this._clipReg.style.height = 988 (this.scrollAmountPerInc * numVisible + revealAmt*2 + 989 ulPaddingHeight) + "px"; 990//alert(this._clipReg.style.height); 991 this.carouselElem.style.height = 992 (this.scrollAmountPerInc * numVisible + revealAmt*2 + navMargin*2 + 993 ulPaddingHeight) + "px"; 994 995 // possible that the umt+upt is needed... need to test this. 996 var revealTop = (this._isExtraRevealed()) ? 997 (revealAmt - (Math.abs(mt-mb)+Math.abs(pt-pb))/2 998 ) : 999 0; 1000 YAHOO.util.Dom.setStyle(this.carouselList, "position", "relative"); 1001 YAHOO.util.Dom.setStyle(this.carouselList, "top", "" + revealTop + "px"); 1002 1003 // if we set the initial start >
1003 1 then this will adjust the scrolled location 1004 var currY = YAHOO.util.Dom.getY(this.carouselList); 1005 YAHOO.util.Dom.setY(this.carouselList, currY - this.scrollAmountPerInc*(firstVisible-1)); 1006 1007 // --- HORIZONTAL 1008 } else { 1009 YAHOO.util.Dom.addClass(this.carouselList, "carousel-horizontal"); 1010 1011 var upl = this._getStyleVal(this.carouselList, "paddingLeft"); 1012 var upr = this._getStyleVal(this.carouselList, "paddingRight"); 1013 var uml = this._getStyleVal(this.carouselList, "marginLeft") 1014 var umr = this._getStyleVal(this.carouselList, "marginRight") 1015 var ulPaddingWidth = upl + upr + uml + umr; 1016 1017 var liMarginWidth = ml + mr; 1018 var liPaddingMarginWidth = liMarginWidth + pr + pl; 1019 1020 // try to reveal the amount taking into consideration the margin & padding. 1021 // This guarantees that this.revealAmount of pixels will be shown on both sides 1022 var revealAmt = (this._isExtraRevealed()) ? 1023 (this.cfg.getProperty("revealAmount")+(liPaddingMarginWidth)/2) : 0; 1024 1025 var liWidth = li.offsetWidth; 1026 this.scrollAmountPerInc = liWidth + liMarginWidth; 1027 1028 this._clipReg.style.width = 1029 (this.scrollAmountPerInc*numVisible + revealAmt*2) + "px"; 1030 this.carouselElem.style.width = 1031 (this.scrollAmountPerInc*numVisible + navMargin*2 + revealAmt*2 + 1032 ulPaddingWidth) + "px"; 1033 1034 var revealLeft = (this._isExtraRevealed()) ? 1035 (revealAmt - (Math.abs(mr-ml)+Math.abs(pr-pl))/2 - (uml+upl) 1036 ) : 1037 0; 1038 YAHOO.util.Dom.setStyle(this.carouselList, "position", "relative"); 1039 YAHOO.util.Dom.setStyle(this.carouselList, "left", "" + revealLeft + "px"); 1040 1041 // if we set the initial start >
1041 1 then this will adjust the scrolled location 1042 var currX = YAHOO.util.Dom.getX(this.carouselList); 1043 YAHOO.util.Dom.setX(this.carouselList, currX - this.scrollAmountPerInc*(firstVisible-1)); 1044 } 1045 }, 1046 1047 // Hides the cfg object 1048 setProperty: function(property, value, silent) { 1049 this.cfg.setProperty(property, value, silent); 1050 }, 1051 1052 getProperty: function(property) { 1053 return this.cfg.getProperty(property); 1054 }, 1055 1056 getFirstItemRevealed: function() { 1057 return this._firstItemRevealed; 1058 }, 1059 getLastItemRevealed: function() { 1060 return this._lastItemRevealed; 1061 }, 1062 1063 // Just for convenience and to be symmetrical with getFirstVisible 1064 getFirstVisible: function() { 1065 return this.cfg.getProperty("firstVisible"); 1066 }, 1067 1068 getLastVisible: function() { 1069 var firstVisible = this.cfg.getProperty("firstVisible"); 1070 var numVisible = this.cfg.getProperty("numVisible"); 1071 1072 return firstVisible + numVisible - 1; 1073 }, 1074 1075 // /////////////////// PRIVATE API ////////////////////////////////////////// 1076 _getStyleVal : function(li, style, returnFloat) { 1077 var styleValStr = YAHOO.util.Dom.getStyle(li, style); 1078 1079 var styleVal = returnFloat ? parseFloat(styleValStr) : parseInt(styleValStr, 10); 1080 if(style=="height" && isNaN(styleVal)) { 1081 styleVal = li.offsetHeight; 1082 } else if(isNaN(styleVal)) { 1083 styleVal = 0; 1084 } 1085 return styleVal; 1086 }, 1087 1088 _calculateSize: function(me) { 1089 me.calculateSize(); 1090 me.show(); 1091 //YAHOO.util.Dom.setStyle(me.carouselElem, "visibility", "visible"); 1092 }, 1093 1094 // From Mike Chambers: http://weblogs.macromedia.com/mesh/archives/2006/01/removing_html_e.html 1095 _removeChildrenFromNode: function(node) 1096 { 1097 if(!this._isValidObj(node)) 1098 { 1099 return; 1100 } 1101 1102 var len = node.childNodes.length; 1103 1104 while (node.hasChildNodes()) 1105 { 1106 node.removeChild(node.firstChild); 1107 } 1108 }, 1109 1110 _prebuildLiElem: function(idx) { 1111 if(idx < 1) return; 1112 1113 1114 var liElem = document.createElement("li"); 1115 liElem.id = this._carouselElemID + "-item-" + idx; 1116 // this is default flag to know that we're not really loaded yet. 1117 liElem.placeholder = true; 1118 this.carouselList.appendChild(liElem); 1119 1120 this._lastPrebuiltIdx = (idx > this._lastPrebuiltIdx) ? idx : this._lastPrebuiltIdx; 1121 }, 1122 1123 _createItem: function(idx, innerHTMLOrElem) { 1124 if(idx < 1) return; 1125 1126 1127 var liElem = document.createElement("li"); 1128 liElem.id = this._carouselElemID + "-item-" + idx; 1129 1130 // if String then assume innerHTML, else an elem object 1131 if(typeof(innerHTMLOrElem) === "string") { 1132 liElem.innerHTML = innerHTMLOrElem; 1133 } else { 1134 liElem.appendChild(innerHTMLOrElem); 1135 } 1136 1137 return liElem; 1138 }, 1139 1140 // idx is the location to insert after 1141 _insertAfterItem: function(refIdx, innerHTMLOrElem) { 1142 return this._insertBeforeItem(refIdx+1, innerHTMLOrElem); 1143 }, 1144 1145 1146 _insertBeforeItem: function(refIdx, innerHTMLOrElem) { 1147 1148 var refItem = this.getItem(refIdx); 1149 var size = this.cfg.getProperty("size"); 1150 if(size != this.UNBOUNDED_SIZE) { 1151 this.cfg.setProperty("size", size + 1, true); 1152 } 1153 1154 for(var i=this._lastPrebuiltIdx; i>=refIdx; i--) { 1155 var anItem = this.getItem(i); 1156 if(this._isValidObj(anItem)) { 1157 anItem.id = this._carouselElemID + "-item-" + (i+1); 1158 } 1159 } 1160 1161 var liElem = this._createItem(refIdx, innerHTMLOrElem); 1162 1163 var insertedItem = this.carouselList.insertBefore(liElem, refItem); 1164 this._lastPrebuiltIdx += 1; 1165 1166 return liElem; 1167 }, 1168 1169 // TEST THIS... think it has to do with prebuild 1170 insertAfterEnd: function(innerHTMLOrElem) { 1171 return this.insertAfter(this.cfg.getProperty("size"), innerHTMLOrElem); 1172 }, 1173 1174 _position: function(newStart, showAnimation) { 1175 // do we bypass the isAnimated check? 1176 var currStart = this._priorFirstVisible; 1177 if(newStart > currStart) { 1178 var inc = newStart - currStart; 1179 this._scrollNextInc(inc, showAnimation); 1180 } else { 1181 var dec = currStart - newStart; 1182 this._scrollPrevInc(dec, showAnimation); 1183 } 1184 }, 1185 1186 _scrollPrev: function(e, carousel) { 1187 if(e !== null) { // event fired this so disable autoplay 1188 carousel.stopAutoPlay(); 1189 } 1190 if(carousel._scrollPrevAnim.isAnimated()) { 1191 return false; 1192 } 1193 carousel._scrollPrevInc(carousel.cfg.getProperty("scrollInc"), 1194 (carousel.cfg.getProperty("animationSpeed") !== 0)); 1195 }, 1196 1197 // event handler
1198 _scrollNext: function(e, carousel) { 1199 if(e !== null) { // event fired this so disable autoplay 1200 carousel.stopAutoPlay(); 1201 } 1202 if(carousel._scrollNextAnim.isAnimated()) { 1203 return false; // might be better to set ourself waiting for animation completion and 1204 // then just do this function. that will allow faster scroll responses. 1205 } 1206 1207 carousel._scrollNextInc(carousel.cfg.getProperty("scrollInc"), 1208 (carousel.cfg.getProperty("animationSpeed") !== 0)); 1209 }, 1210 1211 1212 _handleAnimationComplete: function(type, args, argList) { 1213 var carousel = argList[0]; 1214 var direction = argList[1]; 1215 1216 carousel._animationCompleteEvt.fire(direction); 1217 1218 1219 }, 1220 1221 // If EVERY item is already loaded in the range then return true 1222 // Also prebuild whatever is not already created. 1223 _areAllItemsLoaded: function(first, last) { 1224 var itemsLoaded = true; 1225 for(var i=first; i<=last; i++) { 1226 var liElem = this.getItem(i); 1227 1228 // If the li elem does not exist, then prebuild it in the correct order 1229 // but still flag as not loaded (just prebuilt the li item. 1230 if(!this._isValidObj(liElem)) { 1231 this._prebuildLiElem(i); 1232 itemsLoaded = false; 1233 // but if the item exists and is a placeholder, then 1234 // note that this item is not loaded (only a placeholder) 1235 } else if(this._isValidObj(liElem.placeholder)) { 1236 itemsLoaded = false; 1237 } 1238 } 1239 return itemsLoaded; 1240 }, 1241 1242 _prebuildItems: function(first, last) { 1243 for(var i=first; i<=last; i++) { 1244 var liElem = this.getItem(i); 1245 1246 // If the li elem does not exist, then prebuild it in the correct order 1247 // but still flag as not loaded (just prebuilt the li item. 1248 if(!this._isValidObj(liElem)) { 1249 this._prebuildLiElem(i); 1250 } 1251 } 1252 }, 1253 1254 _isExtraRevealed: function() { 1255 return (this.cfg.getProperty("revealAmount") > 0); 1256 }, 1257 1258 // probably no longer need carousel passed in, this should be correct now. 1259 _scrollNextInc: function(inc, showAnimation) { 1260 var numVisible = this.cfg.getProperty("numVisible"); 1261 var currStart = this._priorFirstVisible; 1262 var currEnd = this._priorLastVisible; 1263 var size = this.cfg.getProperty("size"); 1264 1265 var scrollExtent = this._calculateAllowableScrollExtent(); 1266 1267 if(this.cfg.getProperty("wrap") && currEnd == scrollExtent.end) { 1268 this.scrollTo(scrollExtent.start); // might need to check animation is on or not 1269 return; 1270 } 1271 1272 // increment start by inc 1273 var newStart = currStart + inc; 1274 var newEnd = newStart + numVisible - 1; 1275 1276 // If we are past the end, adjust or wrap 1277 if(newEnd > scrollExtent.end) { 1278 newEnd = scrollExtent.end; 1279 newStart = newEnd - numVisible + 1; 1280 } 1281 1282 inc = newStart - currStart; 1283 1284 // at this point the following variables are set 1285 // inc... amount to increment by 1286 // newStart... the firstVisible item after the scroll 1287 // newEnd... the last item visible after the scroll 1288 1289 this.cfg.setProperty("firstVisible", newStart, true); 1290 1291 1292 if(inc > 0) { 1293 if(this._isValidObj(this.cfg.getProperty("loadNextHandler"))) { 1294 var visibleExtent = this._calculateVisibleExtent(newStart, newEnd); 1295 var cacheStart = (currEnd+1) < visibleExtent.start ? (currEnd+1) : visibleExtent.start; 1296 var alreadyCached = this._areAllItemsLoaded(cacheStart, visibleExtent.end); 1297 this._loadNextHandlerEvt.fire(visibleExtent.start, visibleExtent.end, alreadyCached); 1298 } 1299 1300 if(showAnimation) { 1301 var nextParams = { points: { by: [-this.scrollAmountPerInc*inc, 0] } }; 1302 if(this.isVertical()) { 1303 nextParams = { points: { by: [0, -this.scrollAmountPerInc*inc] } }; 1304 } 1305 1306 this._scrollNextAnim = new YAHOO.util.Motion(this.carouselList, 1307 nextParams, 1308 this.cfg.getProperty("animationSpeed"), 1309 this.cfg.getProperty("animationMethod")); 1310 1311// is this getting added multiple times? 1312 if(this.cfg.getProperty("animationCompleteHandler")) { 1313 this._scrollNextAnim.onComplete.subscribe(this._handleAnimationComplete, [this, "next"]); 1314 } 1315 this._scrollNextAnim.animate(); 1316 } else { 1317 if(this.isVertical()) { 1318 var currY = YAHOO.util.Dom.getY(this.carouselList); 1319 1320 YAHOO.util.Dom.setY(this.carouselList, 1321 currY - this.scrollAmountPerInc*inc); 1322 } else { 1323 var currX = YAHOO.util.Dom.getX(this.carouselList); 1324 YAHOO.util.Dom.setX(this.carouselList, 1325 currX - this.scrollAmountPerInc*inc); 1326 } 1327 } 1328 1329 } 1330 this._priorFirstVisible = newStart; 1331 this._priorLastVisible = newEnd; 1332 1333 this._enableDisableControls(); 1334 return false;
1335 }, 1336 1337 // firstVisible is already set 1338 _scrollPrevInc: function(dec, showAnimation) { 1339 var numVisible = this.cfg.getProperty("numVisible"); 1340 var currStart = this._priorFirstVisible; 1341 var currEnd = this._priorLastVisible; 1342 var size = this.cfg.getProperty("size"); 1343 1344 // decrement start by dec 1345 var newStart = currStart - dec; 1346 1347 var scrollExtent = this._calculateAllowableScrollExtent(); 1348 1349 // How to decide whether to stop at 1 or not 1350 newStart = (newStart < scrollExtent.start) ? scrollExtent.start : newStart; 1351 1352 // if we are going to extend past the end, then we need to correct the start 1353 var newEnd = newStart + numVisible - 1; 1354 if(newEnd > scrollExtent.end) { 1355 newEnd = scrollExtent.end; 1356 newStart = newEnd - numVisible + 1; 1357 } 1358 1359 dec = currStart - newStart; 1360 1361 // at this point the following variables are set 1362 // dec... amount to decrement by 1363 // newStart... the firstVisible item after the scroll 1364 // newEnd... the last item visible after the scroll 1365 this.cfg.setProperty("firstVisible", newStart, true); 1366 1367 // if we are decrementing 1368 if(dec > 0) { 1369 if(this._isValidObj(this.cfg.getProperty("loadPrevHandler"))) { 1370 var visibleExtent = this._calculateVisibleExtent(newStart, newEnd); 1371 var cacheEnd = (currStart-1) > visibleExtent.end ? (currStart-1) : visibleExtent.end; 1372 var alreadyCached = this._areAllItemsLoaded(visibleExtent.start, cacheEnd); 1373 1374 this._loadPrevHandlerEvt.fire(visibleExtent.start, visibleExtent.end, alreadyCached); 1375 } 1376 1377 if(showAnimation) { 1378 var prevParams = { points: { by: [this.scrollAmountPerInc*dec, 0] } }; 1379 if(this.isVertical()) { 1380 prevParams = { points: { by: [0, this.scrollAmountPerInc*dec] } }; 1381 } 1382 1383 this._scrollPrevAnim = new YAHOO.util.Motion(this.carouselList, 1384 prevParams, 1385 this.cfg.getProperty("animationSpeed"), this.cfg.getProperty("animationMethod")); 1386 if(this.cfg.getProperty("animationCompleteHandler")) { 1387 this._scrollPrevAnim.onComplete.subscribe(this._handleAnimationComplete, [this, "prev"]); 1388 } 1389 this._scrollPrevAnim.animate(); 1390 } else { 1391 if(this.isVertical()) { 1392 var currY = YAHOO.util.Dom.getY(this.carouselList); 1393 YAHOO.util.Dom.setY(this.carouselList, currY + 1394 this.scrollAmountPerInc*dec); 1395 } else { 1396 var currX = YAHOO.util.Dom.getX(this.carouselList); 1397 YAHOO.util.Dom.setX(this.carouselList, currX + 1398 this.scrollAmountPerInc*dec); 1399 } 1400 } 1401 } 1402 this._priorFirstVisible = newStart; 1403 this._priorLastVisible = newEnd; 1404 1405 this._enableDisableControls(); 1406 1407 return false; 1408 }, 1409 1410 // Check for all cases and enable/disable controls as needed by current state 1411 _enableDisableControls: function() { 1412 1413 var firstVisible = this.cfg.getProperty("firstVisible"); 1414 var lastVisible = this.getLastVisible(); 1415 var scrollExtent = this._calculateAllowableScrollExtent(); 1416 1417 // previous arrow is turned on. Check to see if we need to turn it off 1418 if(this._prevEnabled) { 1419 if(firstVisible === scrollExtent.start) { 1420 this._disablePrev(); 1421 } 1422 } 1423 1424 // previous arrow is turned off. Check to see if we need to turn it on 1425 if(this._prevEnabled === false) { 1426 if(firstVisible > scrollExtent.start) { 1427 this._enablePrev(); 1428 } 1429 } 1430 1431 // next arrow is turned on. Check to see if we need to turn it off 1432 if(this._nextEnabled) { 1433 if(lastVisible === scrollExtent.end) { 1434 this._disableNext(); 1435 } 1436 } 1437 1438 // next arrow is turned off. Check to see if we need to turn it on 1439 if(this._nextEnabled === false) { 1440 if(lastVisible < scrollExtent.end) { 1441 this._enableNext(); 1442 } 1443 } 1444 }, 1445 1446 /** 1447 * _loadInitial looks at firstItemVisible for the start (not necessarily 1) 1448 */ 1449 _loadInitial: function() { 1450 var firstVisible = this.cfg.getProperty("firstVisible"); 1451 this._priorLastVisible = this.getLastVisible(); 1452 // Load from 1 to the last visible 1453 // The _calculateSize method will adjust the scroll position 1454 // for starts > 1 1455 if(this._loadInitHandlerEvt) { 1456 var visibleExtent = this._calculateVisibleExtent(firstVisible, this._priorLastVisible); 1457 // still treat the first real item as starting at 1 1458 var alreadyCached = this._areAllItemsLoaded(1, visibleExtent.end
1458); 1459 1460 this._loadInitHandlerEvt.fire(visibleExtent.start, visibleExtent.end, alreadyCached); 1461 } 1462 1463 if(this.cfg.getProperty("autoPlay") !== 0) { 1464 this._autoPlayTimer = this.startAutoPlay(); 1465 } 1466 1467 this._enableDisableControls(); 1468 }, 1469 1470 _calculateAllowableScrollExtent: function() { 1471 var scrollBeforeAmount = this.cfg.getProperty("scrollBeforeAmount"); 1472 var scrollAfterAmount = this.cfg.getProperty("scrollAfterAmount"); 1473 var size = this.cfg.getProperty("size"); 1474 1475 var extent = {start: 1-scrollBeforeAmount, end: size+scrollAfterAmount}; 1476 return extent; 1477 1478 }, 1479 1480 _calculateVisibleExtent: function(start, end) { 1481 if(!start) { 1482 start = this.cfg.getProperty("firstVisible"); 1483 end = this.getLastVisible(); 1484 } 1485 1486 var size = this.cfg.getProperty("size"); 1487 1488 // we ignore the firstItem property... this method is used 1489 // for prebuilding the cache and signaling the developer 1490 // what to render on a given scroll. 1491 start = start<1?1:start; 1492 end = end>size?size:end; 1493 1494 var extent = {start: start, end: end}; 1495 1496 // set up the indices for revealed items. If there is no item revealed, then set 1497 // the index to -1 1498 this._firstItemRevealed = -1; 1499 this._lastItemRevealed = -1; 1500 if(this._isExtraRevealed()) { 1501 if(start > 1) { 1502 this._firstItemRevealed = start - 1; 1503 extent.start = this._firstItemRevealed; 1504 } 1505 if(end < size) { 1506 this._lastItemRevealed = end + 1; 1507 extent.end = this._lastItemRevealed; 1508 } 1509 } 1510 1511 return extent; 1512 }, 1513 1514 _disablePrev: function() { 1515 this._prevEnabled = false; 1516 if(this._prevButtonStateHandlerEvt) { 1517 this._prevButtonStateHandlerEvt.fire(false, this._carouselPrev); 1518 } 1519 if(this._isValidObj(this._carouselPrev)) { 1520 YAHOO.util.Event.removeListener(this._carouselPrev, "click", this._scrollPrev); 1521 } 1522 }, 1523 1524 _enablePrev: function() { 1525 this._prevEnabled = true; 1526 if(this._prevButtonStateHandlerEvt) { 1527 this._prevButtonStateHandlerEvt.fire(true, this._carouselPrev); 1528 } 1529 if(this._isValidObj(this._carouselPrev)) { 1530 YAHOO.util.Event.addListener(this._carouselPrev, "click", this._scrollPrev, this); 1531 } 1532 }, 1533 1534 _disableNext: function() { 1535 if(this.cfg.getProperty("wrap")) { 1536 return; 1537 } 1538 this._nextEnabled = false; 1539 if(this._isValidObj(this._nextButtonStateHandlerEvt)) { 1540 this._nextButtonStateHandlerEvt.fire(false, this._carouselNext); 1541 } 1542 if(this._isValidObj(this._carouselNext)) { 1543 YAHOO.util.Event.removeListener(this._carouselNext, "click", this._scrollNext); 1544 } 1545 }, 1546 1547 _enableNext: function() { 1548 this._nextEnabled = true; 1549 if(this._isValidObj(this._nextButtonStateHandlerEvt)) { 1550 this._nextButtonStateHandlerEvt.fire(true, this._carouselNext); 1551 } 1552 if(this._isValidObj(this._carouselNext)) { 1553 YAHOO.util.Event.addListener(this._carouselNext, "click", this._scrollNext, this); 1554 } 1555 }, 1556 1557 _isValidObj: function(obj) { 1558 1559 if (null == obj) { 1560 return false; 1561 } 1562 if ("undefined" == typeof(obj) ) { 1563 return false; 1564 } 1565 return true; 1566 } 1567};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.