1 2/** 3 * Slideshow JS Bundle 4 */ 5YUI.add('fl-event-move', function(Y) { 6 7/** 8 * Adds gesturemovevertical, gesturemoveverticalend, gesturemovehorizontal 9 * and gesturemovehorizontalend events. 10 * 11 * @module fl-event-move 12 */ 13var _eventBase = { 14 15 _isEndEvent: false, 16 17 on: function(node, subscriber, ce) 18 { 19 if(this.type.indexOf('end') > -1) { 20 this._isEndEvent = true; 21 } 22 23 subscriber._direction = this.type.replace('gesturemove', '').replace('end', ''); 24 25 if(window.navigator.msPointerEnabled) { 26 subscriber._startHandle = node.on('MSPointerDown', this._onStart, this, node, subscriber, ce); 27 subscriber._moveHandle = node.on('MSPointerMove', this._onMove, this, node, subscriber, ce); 28 subscriber._endHandle = node.on('MSPointerUp', this._onEnd, this, node, subscriber, ce); 29 } 30 else { 31 subscriber._startHandle = node.on('gesturemovestart', this._onStart, null, this, node, subscriber, ce); 32 subscriber._moveHandle = node.on('gesturemove', this._onMove, null, this, node, subscriber, ce); 33 subscriber._endHandle = node.on('gesturemoveend', this._onEnd, { standAlone: true }, this, node, subscriber, ce); 34 } 35 }, 36 37 detach: function(node, subscriber, ce) 38 { 39 subscriber._startHandle.detach(); 40 subscriber._startHandle = null; 41 subscriber._moveHandle.detach(); 42 subscriber._moveHandle = null; 43 subscriber._endHandle.detach(); 44 subscriber._endHandle = null; 45 }, 46 47 _onStart: function(e, node, subscriber, ce) 48 { 49 subscriber._doMove = null; 50 subscriber._startX = e.pageX; 51 subscriber._startY = e.pageY; 52 }, 53 54 _onMove: function(e, node, subscriber, ce) 55 { 56 if(this._checkDirection(e, subscriber)) { 57 subscriber._doMove = true; 58 } 59 else { 60 subscriber._doMove = false; 61 } 62 if(subscriber._doMove && !this._isEndEvent) { 63 ce.fire(e); 64 } 65 }, 66 67 _onEnd: function(e, node, subscriber, ce) 68 { 69 if(subscriber._doMove && this._isEndEvent) { 70 e.startPageX = subscriber._startX; 71 e.startPageY = subscriber._startY; 72 ce.fire(e); 73 } 74 75 subscriber._doMove = null; 76 }, 77 78 _checkDirection: function(e, subscriber) 79 { 80 var xDelta = Math.abs(subscriber._startX - e.pageX), 81 yDelta = Math.abs(subscriber._startY - e.pageY); 82 83 if(yDelta > xDelta && subscriber._startY > e.pageY && subscriber._direction == 'vertical') { 84 return true; 85 } 86 else if(yDelta > xDelta && subscriber._startY < e.pageY && subscriber._direction == 'vertical') { 87 return true; 88 } 89 else if(yDelta < xDelta && subscriber._startX > e.pageX && subscriber._direction == 'horizontal') { 90 return true; 91 } 92 else if(yDelta < xDelta && subscriber._startX < e.pageX && subscriber._direction == 'horizontal') { 93 return true; 94 } 95 96 return false; 97 } 98}; 99 100/** 101 * @event gesturemovevertical 102 * @param type {String} "gesturemovevertical" 103 * @param fn {Function} The method the event invokes. 104 * @param ctx {Object} Context for the method the event invokes. 105 */ 106Y.Event.define('gesturemovevertical', _eventBase); 107 108/** 109 * @event gesturemoveverticalend 110 * @param type {String} "gesturemoveverticalend" 111 * @param fn {Function} The method the event invokes. 112 * @param ctx {Object} Context for the method the event invokes. 113 */ 114Y.Event.define('gesturemoveverticalend', _eventBase); 115 116/** 117 * @event gesturemovehorizontal 118 * @param type {String} "gesturemovehorizontal" 119 * @param fn {Function} The method the event invokes. 120 * @param ctx {Object} Context for the method the event invokes. 121 */ 122Y.Event.define('gesturemovehorizontal', _eventBase); 123 124/** 125 * @event gesturemovehorizontalend 126 * @param type {String} "gesturemovehorizontalend" 127 * @param fn {Function} The method the event invokes. 128 * @param ctx {Object} Context for the method the event invokes. 129 */ 130Y.Event.define('gesturemovehorizontalend', _eventBase); 131 132 133}, '2.0.0' ,{requires:['event-move']}); 134 135 136YUI.add('fl-slideshow', function(Y) { 137 138/** 139 * @module fl-slideshow 140 */ 141 142/** 143 * Caption widget used in slideshows. 144 * 145 * @namespace FL 146 * @class SlideshowCaption 147 * @constructor 148 * @param config {Object} Configuration object 149 * @extends Widget 150 */ 151Y.namespace('FL').SlideshowCaption = Y.Base.create('fl-slideshow-caption', Y.Widget, [Y.WidgetChild], { 152 153 /** 154 * Flag for whether the text has been 155 * toggled or not. 156 * 157 * @property _textToggled 158 * @type Boolean 159 * @default false 160 * @protected 161 */ 162 _textToggled: false, 163 164 /** 165 * An anchor node used for the toggle link. 166 * 167 * @property _textToggleLink 168 * @type Object 169 * @default null 170 * @protected 171 */ 172 _textToggleLink: null, 173 174 /** 175 * @method renderUI 176 * @protected 177 */ 178 renderUI: function() 179 { 180 var root = this.get('root'), 181 bb = this.get('boundingBox'); 182 183 this._textToggleLink = Y.Node.create('<a href="javascript:void(0);"></a>'); 184 this._textToggleLink.addClass('fl-slideshow-caption-toggle'); 185 this._textToggleLink.set('innerHTML', root.get('captionMoreLinkText')); 186 187 bb.appendChild(this._textToggleLink); 188 }, 189 190 /** 191 * @method bindUI 192 * @protected 193 */ 194 bindUI: function() 195 { 196 this.get('root').on('imageLoadComplete', Y.bind(this._setText, this)); 197 this._textToggleLink.on('click', Y.bind(this._toggleText, this)); 198 }, 199 200 /** 201 * Sets the caption text and displays the 202 * toggle link if necessary. 203 * 204 * @method _setText 205 * @protected 206 */ 207 208 _setText: function() 209 { 210 var root = this.get('root'), 211 text = root.imageInfo.caption, 212 textLength = root.get('captionTextLength'), 213 cb = this.get('contentBox'); 214 215 if(!root.imageInfo.caption || root.imageInfo.caption === '') { 216 cb.set('innerHTML', ''); 217 this._textToggleLink.setStyle('display', 'none'); 218 return; 219 } 220 else if(textLength > -1) { 221 if(!this._textToggled && textLength < text.length) { 222 text = this._shortenText(text); 223 this._textToggleLink.setStyle('display', 'inline-block'); 224 } 225 else if(this._textToggled && textLength < text.length) { 226 text = this._stripTags(text); 227 this._textToggleLink.setStyle('display', 'inline-block'); 228 } 229 else { 230 text = this._stripTags(text); 231 this._textToggleLink.setStyle('display', 'none'); 232 } 233 } 234 else { 235 text = this._stripTags(text); 236 } 237 238 cb.set('innerHTML', text); 239 }, 240 241 /** 242 * Shows or hides the full text when the 243 * toggle link is clicked. 244 * 245 * @method _toggleText 246 * @protected 247 */ 248 _toggleText: function() 249 { 250 var root = this.get('root'), 251 text = root.imageInfo.caption, 252 cb = this.get('contentBox'); 253 254 if(this._textToggled) { 255 text = this._shortenText(text); 256 this._textToggleLink.set('innerHTML', root.get('captionMoreLinkText')); 257 this._textToggled = false;
258 } 259 else { 260 text = this._stripTags(text); 261 this._textToggleLink.set('innerHTML', root.get('captionLessLinkText')); 262 this._textToggled = true; 263 } 264 265 cb.set('innerHTML', text); 266 }, 267 268 /** 269 * Strips out HTML tags from the caption text. 270 * 271 * @method _stripTags 272 * @param text {String} The text to strip HTML tags from. 273 * @param ignoreSettings {Boolean} If true, will strip tags even if 274 * the stripTags attribute is set to false. 275 * @protected 276 */ 277 _stripTags: function(text, ignoreSettings) 278 { 279 var root = this.get('root'), textDiv; 280 281 if(ignoreSettings || root.get('captionStripTags')) { 282 textDiv = document.createElement('div'); 283 textDiv.innerHTML = text; 284 text = textDiv.textContent || textDiv.innerText; 285 } 286 287 return text; 288 }, 289 290 /** 291 * Shortens the caption text to the length of 292 * the textLength attribute. 293 * 294 * @method _shortenText 295 * @protected 296 */ 297 _shortenText: function(text) 298 { 299 var root = this.get('root'); 300 301 text = this._stripTags(text, true).substring(0, root.get('captionTextLength')); 302 303 return Y.Lang.trim(text.substring(0, text.lastIndexOf(' '))) + ' ...'; 304 } 305 306}, { 307 308 /** 309 * Custom CSS class name for the widget. 310 * 311 * @property CSS_PREFIX
312 * @type String 313 * @protected 314 * @static 315 */ 316 CSS_PREFIX: 'fl-slideshow-caption', 317 318 /** 319 * Static property used to define the default attribute configuration of 320 * the Widget. 321 * 322 * @property ATTRS 323 * @type Object 324 * @protected 325 * @static 326 */ 327 ATTRS: { 328 329 } 330}); 331 332/** 333 * A widget for loading and transitioning between SlideshowImage 334 * instances. Each SlideshowImage instance is a child widget of 335 * SlideshowFrame. SlideshowFrame is a child widget of the main 336 * slideshow widget. 337 * 338 * @namespace FL 339 * @class SlideshowFrame 340 * @constructor 341 * @param config {Object} Configuration object 342 * @extends Widget 343 */ 344Y.namespace('FL').SlideshowFrame = Y.Base.create('fl-slideshow-frame', Y.Widget, [Y.WidgetParent, Y.WidgetChild], { 345 346 /** 347 * The imageInfo object used to load the active image. 348 * 349 * @property info 350 * @type Object 351 * @default null 352 * @protected 353 */ 354 _imageInfo: null, 355 356 /** 357 * The active FL.SlideshowImage instance in the frame. 358 * 359 * @property _activeImage 360 * @type FL.SlideshowImage 361 * @default null 362 * @protected 363 */ 364 _activeImage: null, 365 366 /** 367 * A FL.SlideshowImage instance used to load the 368 * next image and transition it into the frame. 369 * 370 * @property _nextImage 371 * @type FL.SlideshowImage 372 * @default null 373 * @protected 374 */ 375 _nextImage: null, 376 377 /** 378 * Used to store imageInfo if a load request is 379 * made while the frame is transitioning. If not null 380 * when the transition completes, a new image will 381 * be loaded using the imageInfo. 382 * 383 * @property _loadQueue 384 * @type Object 385 * @default false 386 * @protected 387 */ 388 _loadQueue: null, 389 390 /** 391 * An instance of FL.SlideshowTransition used for 392 * the current transition in progress. 393 * 394 * @property _transition 395 * @type FL.SlideshowTransition 396 * @default null 397 * @protected 398 */ 399 _transition: null, 400 401 /** 402 * A flag for whether the frame is currently transitioning or not. 403 * 404 * @property _transitioning 405 * @type Boolean 406 * @default false 407 * @protected 408 */ 409 _transitioning: false, 410 411 /** 412 * Flag for whether to resize when the current transition 413 * completes. Set to true when a resize request is made 414 * during a transition. 415 * 416 * @property _resizeAfterTransition 417 * @type Boolean 418 * @default false 419 * @protected 420 */ 421 _resizeAfterTransition: false, 422 423 /** 424 * Provides functionality for gesture based transitions 425 * between the active and next images. 426 * 427 * @property _gestures 428 * @type FL.SlideshowGestures 429 * @default null 430 * @protected 431 */ 432 _gestures: null, 433 434 /** 435 * Creates new instances of FL.SlideshowImage used in the frame. 436 * 437 * @method initializer 438 * @protected 439 */ 440 initializer: function() 441 { 442 var imageConfig = this.get('imageConfig'); 443 444 this._activeImage = new Y.FL.SlideshowImage(imageConfig); 445 this._nextImage = new Y.FL.SlideshowImage(imageConfig); 446 }, 447 448 /** 449 * Renders the FL.SlideshowImage instances used in the frame. 450 * 451 * @method renderUI 452 * @protected 453 */ 454 renderUI: function() 455 { 456 this.add(this._activeImage); 457 this.add(this._nextImage); 458 }, 459 460 /** 461 * @method bindUI 462 * @protected 463 */ 464 bindUI: function() 465 { 466 var activeBB = this._activeImage.get('boundingBox'), 467 nextBB = this._nextImage.get('boundingBox'), 468 transition = this.get('transition'); 469 470 if(('ontouchstart' in window || window.navigator.msPointerEnabled) && this.get('touchSupport')) { 471 472 this._gestures = new Y.FL.SlideshowGestures({ 473 direction: transition == 'slideVertical' ? 'vertical' : 'horizontal', 474 activeItem: activeBB, 475 nextItem: nextBB 476 }); 477 478 this._gestures.on('moveStart', this._gesturesMoveStart, this); 479 this._gestures.on('endComplete', this._gesturesEndComplete, this); 480 } 481 }, 482 483 /** 484 * Functional styles for the UI. 485 * 486 * @method syncUI 487 * @protected 488 */ 489 syncUI: function() 490 { 491 var activeBB = this._activeImage.get('boundingBox'), 492 nextBB = this._nextImage.get('boundingBox'), 493 cb = this.get('contentBox'); 494 495 activeBB.setStyle('position', 'absolute'); 496 activeBB.setStyle('top', '0px'); 497 activeBB.setStyle('left', '-9999px'); 498 499 nextBB.setStyle('position', 'absolute'); 500 nextBB.setStyle('top', '0px'); 501 nextBB.setStyle('left', '-9999px'); 502 503 cb.setStyle('position', 'relative');
504 cb.setStyle('overflow', 'hidden'); 505 }, 506 507 /** 508 * Checks whether the imageInfo should be loaded or queued. 509 * Initializes a new transition if loading is ok. 510 * 511 * @method load 512 * @param imageInfo {Object} The image info to load. 513 */ 514 load: function(imageInfo) 515 { 516 var activeInfo = this._activeImage._imageInfo; 517 518 if(this._transitioning) { 519 this._loadQueue = imageInfo; 520 return; 521 } 522 else if(activeInfo && activeInfo.largeURL == imageInfo.largeURL) { 523 return; 524 } 525 526 this._imageInfo = imageInfo; 527 this._transitionInit(imageInfo); 528 }, 529 530 /** 531 * Preloads the next image using the provided imageInfo. 532 * 533 * @method preload 534 * @param imageInfo {Object} The imageInfo to preload. 535 * @param width {Number} The width to preload. 536 * @param height {Number} The height to preload. 537 */ 538 preload: function(imageInfo, width, height) 539 { 540 this._imageInfo = imageInfo; 541 this._nextImage.preload(imageInfo, width, height); 542 }, 543 544 /** 545 * Unloads the active and next image instances. 546 * 547 * @method unload 548 */ 549 unload: function() 550 { 551 this._imageInfo = null; 552 this._loadQueue = null; 553 this._transitioning = false; 554 this._transition = null; 555 556 this._activeImage.detachAll(); 557 this._activeImage.unload(); 558 this._activeImage.get('boundingBox').setStyle('left', '-9999px'); 559 560 this._nextImage.detachAll(); 561 this._nextImage.unload(); 562 this._nextImage.get('boundingBox').setStyle('left', '-9999px'); 563 }, 564 565 /** 566 * Resizes the bounding box and active image. 567 * 568 * @method resize 569 * @param width {Number} The width value. 570 * @param height {Number} The height value. 571 */ 572 resize: function(width, height) 573 { 574 if(!width || !height) { 575 return; 576 } 577 578 var bb = this.get('boundingBox'), 579 padding = [ 580 parseInt(bb.getComputedStyle('paddingTop'), 10), 581 parseInt(bb.getComputedStyle('paddingRight'), 10), 582 parseInt(bb.getComputedStyle('paddingBottom'), 10), 583 parseInt(bb.getComputedStyle('paddingLeft'), 10) 584 ]; 585 586 width = width - padding[1] - padding[3]; 587 height = height - padding[0] - padding[2]; 588 589 this.set('width', width); 590 this.set('height', height); 591 592 if(this._transitioning) { 593 this._resizeAfterTransition = true; 594 } 595 else { 596 this._activeImage.resize(width, height); 597 this._nextImage.resize(width, height); 598 } 599 }, 600 601 /** 602 * Gets the current transition to use. 603 * 604 * @method _getTransition 605 * @protected 606 */ 607 _getTransition: function() 608 { 609 var root = this.get('root'), 610 lastIndex = root.albumInfo.images.length - 1, 611 direction = 'next', 612 transition = root.get('transition'); 613 614 if(root.lastImageIndex === null) { 615 direction = ''; 616 } 617 else if(root.imageIndex == lastIndex && root.lastImageIndex === 0) { 618 direction = 'prev'; 619 } 620 else if(root.imageIndex === 0 && root.lastImageIndex == lastIndex) { 621 direction = 'next'; 622 } 623 else if(root.lastImageIndex > root.imageIndex) { 624 direction = 'prev'; 625 } 626 else if(root.lastImageIndex < root.imageIndex) { 627 direction = 'next'; 628 } 629 630 if(direction == 'next') { 631 transition = transition.replace('slideHorizontal', 'slideLeft'); 632 transition = transition.replace('slideVertical', 'slideUp'); 633 } 634 else if(direction == 'prev') { 635 transition = transition.replace('slideHorizontal', 'slideRight'); 636 transition = transition.replace('slideVertical', 'slideDown'); 637 } 638 639 return transition; 640 }, 641 642 /** 643 * Fires the transitionInit event and loads the next image. 644 * The transition starts when the image's loadComplete 645 * event is fired. 646 * 647 * @method _transitionInit 648 * @param imageInfo {Object} The imageInfo to load before transitioning. 649 * @protected 650 */ 651 _transitionInit: function(imageInfo) 652 { 653 this._transitioning = true; 654 655 // Disable gestures if set. 656 if(this._gestures) { 657 this._gestures.disable(); 658 } 659 660 /** 661 * Fires when the next image is loading before a new transition. 662 * 663 * @event transitionInit 664 */ 665 this.fire('transitionInit'); 666 667 if(imageInfo) { 668 this._nextImage.once('loadComplete', this._transitionStart, this); 669 this._nextImage.load(imageInfo); 670 } 671 else { 672 this._transitionStart(); 673 } 674 }, 675 676 /** 677 * Fires the transitionStart event and starts the transition 678 * using a new instance of FL.SlideshowTransition. 679 * 680 * @method _transitionStart 681 * @protected 682 */ 683 _transitionStart: function() 684 { 685 var root = this.get('root'); 686 687 /** 688 * Fires when the next image has finished loading 689 * and a new transition starts. 690 * 691 * @event transitionStart 692 */ 693 this.fire('transitionStart'); 694 695 this._transition = new Y.FL.SlideshowTransition({ 696 itemIn: this._nextImage._imageInfo ? this._nextImage.get('boundingBox') : null, 697 itemOut: this._activeImage._imageInfo ? this._activeImage.get('boundingBox') : null, 698 type: this._getTransition(), 699 duration: root.get('transitionDuration'), 700 easing: root.get('transitionEasing'), 701 kenBurnsDuration: root.get('speed')/1000, 702 kenBurnsZoom: root.get('kenBurnsZoom') 703 }); 704 705 if(this._nextImage._imageInfo) { 706 this._nextImage.get('boundingBox').setStyle('left', '0px'); 707 } 708 709 this._transition.once('complete', this._transitionComplete, this); 710 this._transition.run(); 711 }, 712 713 /** 714 * Switches the next and active image variables, unloads the 715 * last image, fires the transitionComplete event and loads 716 * or resizes if appropriate. 717 * 718 * @method _transitionComplete 719 * @protected 720 */ 721 _transitionComplete: function() 722 { 723 var root = this.get('root'); 724 725 // Swap image container references. 726 this._swapImageRefs(); 727 728 /** 729 * Fired when the current transition completes. 730 * 731 * @event transitionComplete 732 */ 733 this.fire('transitionComplete'); 734 this._transition = null; 735 this._transitioning = false;
736 737 // Enable gestures if set. 738 if(this._gestures) { 739 if(root && root.albumInfo.images.length <= 1) { 740 this._gestures.disable(); 741 } 742 else { 743 this._gestures.enable(); 744 } 745 } 746 747 // Load from the queue? 748 if(this._loadQueue) { 749 this.load(this._loadQueue); 750 this._loadQueue = null; 751 } 752 // Resize the active image? 753 else if(this._resizeAfterTransition) { 754 this._resizeAfterTransition = false; 755 this._activeImage.resize(this.get('width'), this.get('height')); 756 this._nextImage.resize(this.get('width'), this.get('height')); 757 } 758 }, 759 760 /** 761 * @method _gesturesMoveStart 762 * @param e {Object} The event object. 763 * @protected 764 */ 765 _gesturesMoveStart: function(e) 766 { 767 var index = 0, 768 root = this.get('root'); 769 770 index = e.direction == 'next' ? root.imageIndex + 1 : root.imageIndex - 1; 771 index = index < 0 ? root.albumInfo.images.length - 1 : index; 772 index = index >= root.albumInfo.images.length ? 0 : index; 773 774 root.pause(); 775 root._hideLoadingImage(); 776 root._showLoadingImageWithDelay(); 777 778 Y.FL.SlideshowImageLoader.removeGroup(this._nextImage.get('loadGroup')); 779 780 this._nextImage.once('loadComplete', root._hideLoadingImage, root); 781 this._nextImage.load(root.albumInfo.images[index]); 782 }, 783 784 /** 785 * @method _gesturesEndComplete 786 * @protected 787 */ 788 _gesturesEndComplete: function() 789 { 790 var root = this.get('root'), 791 index = 0; 792 793 if(this._nextImage._imageInfo){ 794 index = this._nextImage._imageInfo.index; 795 this._swapImageRefs(); 796 this._imageInfo = root.albumInfo.images[index]; 797 root.loadImage(index); 798 } 799 }, 800 801 /** 802 * @method _swapImageRefs 803 * @protected 804 */ 805 _swapImageRefs: function() 806 { 807 var active = this._activeImage; 808 this._activeImage = this._nextImage; 809 this._nextImage = active; 810 811 if(this._nextImage._imageInfo) { 812 this._nextImage.unload(); 813 this._nextImage.get('boundingBox').setStyle('left', '-9999px'); 814 } 815 if(this._gestures) { 816 this._gestures.set('activeItem', this._activeImage.get('boundingBox')); 817 this._gestures.set('nextItem', this._nextImage.get('boundingBox')); 818 } 819 } 820 821}, { 822 823 /** 824 * Custom CSS class name for the widget. 825 826 * @property CSS_PREFIX
827 * @type String 828 * @protected 829 * @static 830 */ 831 CSS_PREFIX: 'fl-slideshow-frame', 832 833 /** 834 * Static property used to define the default attribute configuration of 835 * the Widget. 836 * 837 * @property ATTRS 838 * @type Object 839 * @protected 840 * @static 841 */ 842 ATTRS: { 843 844 /** 845 * The configuration object used to create new instances of 846 * FL.SlideshowImage. See the API docs for {@link FL.SlideshowImage} 847 * for a complete list of configuration attributes. 848 * 849 * @attribute imageConfig 850 * @type Object 851 * @default null 852 */ 853 imageConfig: { 854 value: null 855 }, 856 857 /** 858 * Whether to use touch gestures, when available, 859 * to transition between images or not. 860 * 861 * @attribute touchSupport 862 * @type Boolean 863 * @default false 864 */ 865 touchSupport: { 866 value: false 867 } 868 } 869}); 870 871/** 872 * A plugin for fullscreen slideshow functionality. 873 * 874 * @namespace FL 875 * @class SlideshowFullscreen 876 * @constructor 877 * @param config {Object} Configuration object 878 * @extends Plugin.Base 879 */ 880Y.namespace('FL').SlideshowFullscreen = Y.Base.create('fl-slideshow-fullscreen', Y.Plugin.Base, [], { 881 882 /** 883 * Flag for whether the slideshow is in 884 * fullscreen mode. 885 * 886 * @property active 887 * @type Boolean 888 * @default false 889 */ 890 active: false, 891 892 /** 893 * A div containing the close message. 894 * 895 * @property _closeMessage 896 * @type Node 897 * @default null 898 * @protected 899 */ 900 _closeMessage: null, 901 902 /** 903 * A timer for hiding the close message. 904 * 905 * @property _closeMessageTimer 906 * @type Object 907 * @default null 908 * @protected 909 */ 910 _closeMessageTimer: null, 911 912 /** 913 * The initial styles of the host's bounding box 914 * before entering fullscreen mode. 915 * 916 * @property _initialStyles 917 * @type Object 918 * @protected 919 */ 920 _initialStyles: { 921 position: 'static', 922 top: '0px', 923 left: '0px' 924 }, 925 926 /** 927 * @method initializer 928 * @protected 929 */ 930 initializer: function() 931 { 932 var host = this.get('host'), 933 bb = host.get('boundingBox'), 934 self = this; 935 936 bb.addClass('fl-fullscreen-enabled'); 937 938 if(Y.FL.SlideshowFullscreen.OS_SUPPORT) { 939 document.addEventListener('fullscreenchange', function(){ self._osChange(); }, false); 940 document.addEventListener('mozfullscreenchange', function(){ self._osChange(); }, false); 941 document.addEventListener('webkitfullscreenchange', function(){ self._osChange(); }, false); 942 } 943 else { 944 this._renderCloseMessage(); 945 } 946 }, 947 948 /** 949 * Exits fullscreen if it is currently active 950 * otherwise it enters fullscreen. 951 * 952 * @method toggle 953 */ 954 toggle: function() 955 { 956 if(this.active) { 957 this.exit(); 958 } 959 else { 960 this.enter(); 961 } 962 }, 963 964 /** 965 * Enters OS fullscreen mode if supported, otherwise 966 * the slideshow takes over the browser window. 967 * 968 * @method enter 969 */ 970 enter: function() 971 { 972 if(Y.FL.SlideshowFullscreen.OS_SUPPORT) { 973 this._osEnter(); 974 } 975 else { 976 this._browserEnter(); 977 } 978 }, 979 980 /** 981 * Exits fullscreen mode. 982 * 983 * @method exit 984 */ 985 exit: function() 986 { 987 if(Y.FL.SlideshowFullscreen.OS_SUPPORT) { 988 this._osExit(); 989 } 990 else { 991 this._browserExit(); 992 } 993 }, 994 995 /** 996 * Enters OS fullscreen mode. 997 * 998 * @method _osEnter 999 * @protected 1000 */ 1001 _osEnter: function() 1002 { 1003 var bbNode = this.get('host').get('boundingBox')._node; 1004 1005 if(bbNode.webkitRequestFullScreen) { 1006 bbNode.webkitRequestFullScreen(); 1007 } 1008 else if(bbNode.mozRequestFullScreen) { 1009 bbNode.mozRequestFullScreen(); 1010 } 1011 else if(bbNode.requestFullScreen) { 1012 bbNode.requestFullScreen(); 1013 } 1014 }, 1015 1016 /** 1017 * Exits OS fullscreen mode. 1018 * 1019 * @method _osExit 1020 * @protected 1021 */ 1022 _osExit: function() 1023 { 1024 if(document.exitFullscreen) { 1025 document.exitFullscreen(); 1026 } 1027 else if(document.mozCancelFullScreen) { 1028 document.mozCancelFullScreen(); 1029 } 1030 else if(document.webkitCancelFullScreen) { 1031 document.webkitCancelFullScreen(); 1032 } 1033 }, 1034 1035 /** 1036 * Called when the OS fullscreenchange event fires and enters 1037 * or exits standard fullscreen mode which positions and 1038 * resizes the slideshow. 1039 * 1040 * @method _osChange 1041 * @protected 1042 */ 1043 _osChange: function() 1044 { 1045 var host = this.get('host'); 1046 1047 // Transitions break on Safari while entering and 1048 // exiting fullscreen. This fixes them! 1049 if(host.frame && host.frame._transitioning) { 1050 host.frame._transitionComplete(); 1051 } 1052 1053 if(this.active) { 1054 this._exit(); 1055 } 1056 else { 1057 this._enter(); 1058 } 1059 }, 1060 1061 /** 1062 * Enter browser fullscreen mode. 1063 * 1064 * @method _browserEnter 1065 * @protected 1066 */ 1067 _browserEnter: function() 1068 { 1069 var bb = this.get('host').get('boundingBox'); 1070 1071 this._initialStyles = { 1072 position: bb.getStyle('position'), 1073 top: bb.getStyle('top'), 1074 left: bb.getStyle('left'), 1075 zIndex: bb.getStyle('zIndex') 1076 }; 1077 1078 bb.setStyles({ 1079 position: 'fixed', 1080 top: '0px', 1081 left: '0px', 1082 zIndex: 10000 1083 }); 1084 1085 Y.Node.one('body').on('fl-fullscreen|keydown', Y.bind(this._onKey, this)); 1086 1087 this._showCloseMessage(); 1088 this._enter(); 1089 }, 1090 1091 /** 1092 * Exit browser fullscreen mode. 1093 * 1094 * @method _browserExit 1095 * @protected 1096 */ 1097 _browserExit: function() 1098 { 1099 var bb = this.get('host').get('boundingBox'); 1100 1101 bb.setStyles({ 1102 position: this._initialStyles.position, 1103 top: this._initialStyles.top, 1104 left: this._initialStyles.left, 1105 zIndex: this._initialStyles.zIndex 1106 }); 1107 1108 Y.Node.one('body').detach('fl-fullscreen|keydown'); 1109 1110 this._hideCloseMessage(); 1111 this._exit(); 1112 }, 1113 1114 /** 1115 * Enters fullscreen mode. 1116 * 1117 * @method _enter 1118 * @protected 1119 */ 1120 _enter: function() 1121 { 1122 var host = this.get('host'), 1123 bb = host.get('boundingBox'); 1124 1125 bb.addClass('fl-fullscreen-active'); 1126 1127 this.active = true; 1128 1129 host.resize(); 1130 }, 1131 1132 /** 1133 * Exits fullscreen mode. 1134 * 1135 * @method _exit 1136 * @protected 1137 */ 1138 _exit: function() 1139 { 1140 var host = this.get('host'), 1141 bb = host.get('boundingBox'); 1142 1143 bb.removeClass('fl-fullscreen-active'); 1144 1145 this.active = false;
1146 1147 host.resize(); 1148 }, 1149 1150 /** 1151 * Keyboard input for the esc button. 1152 * 1153 * @method _onKey 1154 * @protected 1155 */ 1156 _onKey: function(e) 1157 { 1158 if(e.keyCode == 27) { 1159 this.exit(); 1160 return false; 1161 } 1162 }, 1163 1164 /** 1165 * Creates the close message if one is 1166 * not already available in the document. 1167 * 1168 * @method _initCloseMessage 1169 * @protected 1170 */ 1171 _renderCloseMessage: function() 1172 { 1173 this._closeMessage = Y.Node.create('<div class="fl-fullscreen-close-message"></div>'); 1174 this._closeMessage.set('innerHTML', '<span>Press the "esc" button to exit fullscreen mode.</span>'); 1175 this._closeMessage.setStyle('display', 'none'); 1176 this.get('host').get('boundingBox').insert(this._closeMessage); 1177 }, 1178 1179 /** 1180 * Shows the close message. 1181 * 1182 * @method _showCloseMessage 1183 * @protected 1184 */ 1185 _showCloseMessage: function() 1186 { 1187 if(this._closeMessageTimer) { 1188 this._closeMessageTimer.cancel(); 1189 this._closeMessageTimer = null; 1190 } 1191 1192 this._closeMessage.show(true); 1193 this._closeMessageTimer = Y.later(4000, this, this._hideCloseMessage); 1194 }, 1195 1196 /** 1197 * Hides the close message. 1198 * 1199 * @method _hideCloseMessage 1200 * @protected 1201 */ 1202 _hideCloseMessage: function() 1203 { 1204 if(this._closeMessageTimer) { 1205 this._closeMessageTimer.cancel(); 1206 this._closeMessageTimer = null; 1207 } 1208 1209 this._closeMessage.hide(true); 1210 } 1211 1212}, { 1213 1214 /** 1215 * Namespace for the plugin. 1216 * 1217 * @property NS
1218 * @type String 1219 * @protected 1220 * @static 1221 */ 1222 NS: 'fullscreen', 1223 1224 OS_SUPPORT: (function(){ 1225 1226 var doc = document.documentElement; 1227 1228 return doc.webkitRequestFullScreen || doc.mozRequestFullScreen || doc.requestFullScreen; 1229 })() 1230}); 1231 1232/** 1233 * Provides functionality for gesture based transitions 1234 * between two slideshow components. 1235 * 1236 * @namespace FL 1237 * @class SlideshowGestures 1238 * @constructor 1239 * @param config {Object} Configuration object 1240 * @extends Base 1241 */ 1242Y.namespace('FL').SlideshowGestures = Y.Base.create('fl-slideshow-gestures', Y.Base, [], { 1243 1244 /** 1245 * The x coordinate for where a gesture event starts. 1246 * 1247 * @property _startX 1248 * @type Number 1249 * @default null 1250 * @protected 1251 */ 1252 _startX: null, 1253 1254 /** 1255 * The y coordinate for where a gesture event starts. 1256 * 1257 * @property _startY 1258 * @type Number 1259 * @default null 1260 * @protected 1261 */ 1262 _startY: null, 1263 1264 /** 1265 * A flag for whether a gesture is moving or not. 1266 * 1267 * @property _moving 1268 * @type Boolean 1269 * @default false 1270 * @protected 1271 */ 1272 _touchMoving: false, 1273 1274 /** 1275 * Whether the gesture is moving or not. 1276 * 1277 * @property _moving 1278 * @type Boolean 1279 * @default false 1280 * @protected 1281 */ 1282 _moving: false, 1283 1284 /** 1285 * The direction the current gesture event 1286 * is moving in (either next or prev). 1287 * 1288 * @property _movingDirection
1289 * @type String 1290 * @default null 1291 * @protected 1292 */ 1293 _movingDirection: null, 1294 1295 /** 1296 * A flag for whether a gesture gesture is currently 1297 * transitioning or not. 1298 * 1299 * @property _transitioning 1300 * @type Boolean 1301 * @default false 1302 * @protected 1303 */ 1304 _transitioning: false, 1305 1306 /** 1307 * @method initializer 1308 * @protected 1309 */ 1310 initializer: function() 1311 { 1312 this.enable(); 1313 }, 1314 1315 /** 1316 * @method enable 1317 */ 1318 enable: function() 1319 { 1320 var id = this.get('id'), 1321 direction = this.get('direction'), 1322 active = this.get('activeItem'), 1323 next = this.get('nextItem'); 1324 1325 active.on(id + '|gesturemovestart', Y.bind(this._onStart, this)); 1326 next.on(id + '|gesturemovestart', Y.bind(this._onStart, this)); 1327 next.on(id + '|transitionend', Y.bind(this._onEndComplete, this) ); 1328 next.on(id + '|oTransitionEnd', Y.bind(this._onEndComplete, this) ); 1329 next.on(id + '|webkitTransitionEnd', Y.bind(this._onEndComplete, this) ); 1330 1331 if(direction == 'horizontal') { 1332 active.on(id + '|gesturemovehorizontal', Y.bind(this._onMoveHorizontal, this)); 1333 active.on(id + '|gesturemovehorizontalend', Y.bind(this._onEndHorizontal, this)); 1334 next.on(id + '|gesturemovehorizontal', Y.bind(this._onMoveHorizontal, this)); 1335 next.on(id + '|gesturemovehorizontalend', Y.bind(this._onEndHorizontal, this)); 1336 } 1337 else { 1338 active.on(id + '|gesturemovevertical', Y.bind(this._onMoveVertical, this)); 1339 active.on(id + '|gesturemoveverticalend', Y.bind(this._onEndVertical, this)); 1340 next.on(id + '|gesturemovevertical', Y.bind(this._onMoveVertical, this)); 1341 next.on(id + '|gesturemoveverticalend', Y.bind(this._onEndVertical, this)); 1342 } 1343 }, 1344 1345 /** 1346 * @method disable 1347 */ 1348 disable: function() 1349 { 1350 var id = this.get('id'), 1351 active = this.get('activeItem'), 1352 next = this.get('nextItem'); 1353 1354 active.detach(id + '|*'); 1355 next.detach(id + '|*'); 1356 }, 1357 1358 /** 1359 * @method _onStart 1360 * @param e {Object} The event object. 1361 * @protected 1362 */ 1363 _onStart: function(e) 1364 { 1365 var direction = this.get('direction'); 1366 1367 if(this._transitioning) { 1368 this._onEndComplete(); 1369 } 1370 1371 if(direction == 'horizontal') { 1372 this._startX = e.pageX; 1373 } 1374 else { 1375 this._startY = e.pageY; 1376 } 1377 1378 /** 1379 * @event start 1380 */ 1381 this.fire('start'); 1382 }, 1383 1384 /** 1385 * @method _onMoveHorizontal 1386 * @param e {Object} The event object. 1387 * @protected 1388 */ 1389 _onMoveHorizontal: function(e) 1390 { 1391 var x = this._startX - e.pageX, 1392 active = this.get('activeItem'), 1393 next = this.get('nextItem'), 1394 width = parseInt(active.getComputedStyle('width'), 10), 1395 translate = x < 0 ? Math.abs(x) : -x, 1396 direction = x < 0 ? 'prev' : 'next'; 1397 1398 e.preventDefault(); 1399 1400 if(!this._moving || this._movingDirection != direction) { 1401 1402 active.setStyle('left', 0); 1403 1404 next.setStyles({ 1405 'opacity': 1, 1406 'left': x < 0 ? -width : width 1407 }); 1408 1409 this._moving = true; 1410 this._movingDirection = direction; 1411 1412 /** 1413 * @event moveStart 1414 */ 1415 this.fire('moveStart', { direction: direction }); 1416 } 1417 1418 active.setStyle('-webkit-transform', 'translate('+ translate +'px, 0px) translateZ(0px)'); 1419 active.setStyle('-ms-transform', 'translate('+ translate +'px, 0px) translateZ(0px)'); 1420 next.setStyle('-webkit-transform', 'translate('+ translate +'px, 0px) translateZ(0px)'); 1421 next.setStyle('-ms-transform', 'translate('+ translate +'px, 0px) translateZ(0px)'); 1422 1423 /** 1424 * @event move 1425 */ 1426 this.fire('move'); 1427 }, 1428 1429 /** 1430 * @method _onMoveVertical 1431 * @param e {Object} The event object. 1432 * @protected 1433 */ 1434 _onMoveVertical: function(e) 1435 { 1436 var y = this._startY - e.pageY, 1437 active = this.get('activeItem'), 1438 next = this.get('nextItem'), 1439 height = parseInt(active.getComputedStyle('height'), 10), 1440 translate = y < 0 ? Math.abs(y) : -y, 1441 direction = y < 0 ? 'prev' : 'next'; 1442 1443 e.preventDefault(); 1444 1445 if(!this._moving || this._movingDirection != direction) { 1446 1447 active.setStyle('top', 0); 1448 1449 next.setStyles({ 1450 'opacity': 1, 1451 'left' : 'auto', 1452 'top': y < 0 ? -height : height 1453 }); 1454 1455 this._moving = true; 1456 this._movingDirection = direction; 1457 1458 /** 1459 * @event moveStart 1460 */ 1461 this.fire('moveStart', { direction: direction }); 1462 } 1463 1464 active.setStyle('-webkit-transform', 'translate(0px, '+ translate +'px) translateZ(0px)'); 1465 active.setStyle('-ms-transform', 'translate(0px, '+ translate +'px) translateZ(0px)'); 1466 next.setStyle('-webkit-transform', 'translate(0px, '+ translate +'px) translateZ(0px)'); 1467 next.setStyle('-ms-transform', 'translate(0px, '+ translate +'px) translateZ(0px)'); 1468 1469 /** 1470 * @event move 1471 */ 1472 this.fire('move'); 1473 }, 1474 1475 /** 1476 * @method _onEndHorizontal 1477 * @param e {Object} The event object. 1478 * @protected 1479 */ 1480 _onEndHorizontal: function(e) 1481 { 1482 if(!this._moving) { 1483 return; 1484 } 1485 1486 var x = this._startX - e.pageX, 1487 active = this.get('activeItem'), 1488 next = this.get('nextItem'), 1489 width = parseInt(next.getComputedStyle('width'), 10), 1490 translate = x < 0 ? width : -width; 1491 1492 active.transition({ 1493 'transform': 'translate('+ translate +'px, 0px)' 1494 }); 1495 1496 next.transition({ 1497 'transform': 'translate('+ translate +'px, 0px)' 1498 }); 1499 1500 this._transitioning = true; 1501 1502 /** 1503 * @event end 1504 */ 1505 this.fire('end'); 1506 }, 1507 1508 /** 1509 * @method _onEndVertical 1510 * @param e {Object} The event object. 1511 * @protected 1512 */ 1513 _onEndVertical: function(e) 1514 { 1515 if(!this._moving) { 1516 return; 1517 } 1518 1519 var y = this._startY - e.pageY, 1520 active = this.get('activeItem'), 1521 next = this.get('nextItem'), 1522 height = parseInt(next.getComputedStyle('height'), 10), 1523 translate = y < 0 ? height : -height; 1524 1525 active.transition({ 1526 'transform': 'translate(0px, '+ translate +'px)' 1527 }); 1528 1529 next.transition({ 1530 'transform': 'translate(0px, '+ translate +'px)' 1531 }); 1532 1533 this._transitioning = true; 1534 1535 /** 1536 * @event end 1537 */ 1538 this.fire('end'); 1539 }, 1540 1541 /** 1542 * @method _onEndComplete 1543 * @protected 1544 */ 1545 _onEndComplete: function() 1546 { 1547 var direction = this.get('direction'), 1548 active = this.get('activeItem'), 1549 next = this.get('nextItem'); 1550 1551 active.setStyles({ 1552 'opacity': 0, 1553 '-webkit-transform': '', 1554 '-webkit-transition': '', 1555 '-ms-transform': '', 1556 '-ms-transition': '' 1557 }); 1558 1559 next.setStyles({ 1560 '-webkit-transform': '', 1561 '-webkit-transition': '', 1562 '-ms-transform': '', 1563 '-ms-transition': '' 1564 }); 1565 1566 if(direction == 'horizontal') { 1567 active.setStyle('left', '-9999px'); 1568 next.setStyle('left', '0px'); 1569 } 1570 else { 1571 active.setStyle('top', '-9999px'); 1572 next.setStyle('top', '0px'); 1573 } 1574 1575 this.set('activeItem', next); 1576 this.set('nextItem', active); 1577 this._moving = false;
1578 this._movingDirection = null; 1579 this._transitioning = false; 1580 1581 /** 1582 * @event endComplete 1583 */ 1584 this.fire('endComplete'); 1585 } 1586 1587}, { 1588 1589 /** 1590 * Static property used to define the default attribute configuration of 1591 * the Widget. 1592 * 1593 * @property ATTRS 1594 * @type Object 1595 * @protected 1596 * @static 1597 */ 1598 ATTRS: { 1599 1600 /** 1601 * The gesture direction to use. Possible values are 1602 * horizontal and vertical. 1603 * 1604 * @attribute direction 1605 * @type String 1606 * @default horizontal 1607 */ 1608 direction: { 1609 value: 'horizontal' 1610 }, 1611 1612 /** 1613 * The Node that is currently visible. 1614 * 1615 * @attribute activeItem 1616 * @type Node 1617 * @default null 1618 */ 1619 activeItem: { 1620 value: null 1621 }, 1622 1623 /** 1624 * The Node that will be transitioned in. 1625 * 1626 * @attribute nextItem 1627 * @type Node 1628 * @default null 1629 */ 1630 nextItem: { 1631 value: null 1632 } 1633 } 1634}); 1635 1636/** 1637 * A load queue for slideshow images. 1638 * 1639 * @namespace FL 1640 * @class SlideshowImageLoader 1641 * @static 1642 */ 1643Y.namespace('FL').SlideshowImageLoader = { 1644 1645 /** 1646 * Whether an image is being loaded or not. 1647 * 1648 * @property _loading 1649 * @type Boolean 1650 * @default false 1651 * @protected 1652 */ 1653 _loading: false, 1654 1655 /** 1656 * An node for loading the next image. 1657 * 1658 * @property _currentImage 1659 * @type Node 1660 * @default null 1661 * @protected 1662 */ 1663 _currentImage: null, 1664 1665 /** 1666 * An object containing the group, src and callback 1667 * for the current image that is being loaded. 1668 * 1669 * @property _currentImageData 1670 * @type Object 1671 * @default null 1672 * @protected 1673 */ 1674 _currentImageData: null, 1675 1676 /** 1677 * An array of image data objects that contain the group, 1678 * src and callback for each image that will be loaded. 1679 * 1680 * @property _queue 1681 * @type Array 1682 * @default [] 1683 * @protected 1684 */ 1685 _queue: [], 1686 1687 /** 1688 * Adds an image to the queue. 1689 * 1690 * @method add 1691 * @param group {String} The group this image is associated with. 1692 * Used to remove images in bulk. 1693 * @param src {String} The image url to load. 1694 * @param callback {Function} A function to call when the image 1695 * has finished loading. 1696 * @param bump {Boolean} If true, the image will be added to 1697 * the first position in the queue. 1698 */ 1699 add: function(group, src, callback, bump) 1700 { 1701 var imgData = { 1702 group : group, 1703 src : src, 1704 callback : callback 1705 }; 1706 1707 if(bump) { 1708 this._queue.unshift(imgData); 1709 } 1710 else { 1711 this._queue.push(imgData); 1712 } 1713 1714 if(!this._loading) { 1715 this._load(); 1716 } 1717 }, 1718 1719 /** 1720 * Removes a group of images from the queue. 1721 * 1722 * @method removeGroup 1723 * @param group {String} The group to remove. 1724 */ 1725 removeGroup: function(group) 1726 { 1727 var i = this._queue.length - 1; 1728 1729 for( ; i > -1 ; i--) { 1730 if(this._queue[i].group == group) { 1731 this._queue.splice(i, 1); 1732 } 1733 } 1734 1735 if(this._currentImageData && this._currentImageData.group == group) { 1736 this._currentImage.detachAll(); 1737 this._currentImage = null; 1738 this._currentImageData = null; 1739 1740 if(this._queue.length > 0) { 1741 this._load(); 1742 } 1743 else { 1744 this._loading = false; 1745 } 1746 } 1747 }, 1748 1749 /** 1750 * Loads the next image in the queue. 1751 * 1752 * @method _load 1753 * @protected 1754 */ 1755 _load: function() 1756 { 1757 this._loading = true; 1758 this._currentImageData = this._queue.shift(); 1759 this._currentImage = Y.Node.create('<img />'); 1760 this._currentImage.on('error', Y.bind(this._loadComplete, this)); 1761 this._currentImage.on('load', Y.bind(this._loadComplete, this)); 1762 this._currentImage.set('src', this._currentImageData.src); 1763 }, 1764 1765 /** 1766 * Calls the current image's callback function if set 1767 * and loads the next image if the queue is not empty. 1768 * 1769 * @method _loadComplete 1770 * @protected 1771 */ 1772 _loadComplete: function() 1773 { 1774 if(this._currentImageData.callback) { 1775 this._currentImageData.callback(this._currentImage); 1776 } 1777 1778 if(this._queue.length > 0) { 1779 this._load(); 1780 } 1781 else { 1782 this._loading = false; 1783 this._currentImage = null; 1784 this._currentImageData = null; 1785 } 1786 } 1787}; 1788 1789/** 1790 * Loads an image or video using the provided imageInfo object. 1791 * 1792 * @namespace FL 1793 * @class SlideshowImage 1794 * @constructor 1795 * @param config {Object} Configuration object 1796 * @extends Widget 1797 */ 1798Y.namespace('FL').SlideshowImage = Y.Base.create('fl-slideshow-image', Y.Widget, [Y.WidgetChild], { 1799 1800 /** 1801 * The imageInfo object used to load the image and 1802 * its various sizes. 1803 * 1804 * @property info 1805 * @type Object 1806 * @default null 1807 * @protected 1808 */ 1809 _imageInfo: null, 1810 1811 /** 1812 * A reference to the current image node in the bounding box. 1813 * 1814 * @property _image 1815 * @type Node 1816 * @default null 1817 * @protected 1818 */ 1819 _image: null, 1820 1821 /** 1822 * Whether or not new imageInfo is loading. 1823 * 1824 * @property _loading 1825 * @type Boolean 1826 * @default false 1827 * @protected 1828 */ 1829 _loading: false, 1830 1831 /** 1832 * The URL that is currently being loaded. 1833 * 1834 * @property _loadingURL 1835 * @type Boolean 1836 * @default null 1837 * @protected 1838 */ 1839 _loadingURL: null, 1840 1841 /** 1842 * An anchor node used for the video play button. 1843 * 1844 * @property _videoButton 1845 * @type Node 1846 * @default null 1847 * @protected 1848 */ 1849 _videoButton: null, 1850 1851 /** 1852 * A div node used to hold the video iframe. 1853 * 1854 * @property _videoBox 1855 * @type Node 1856 * @default null 1857 * @protected 1858 */ 1859 _videoBox: null, 1860 1861 /** 1862 * An iframe node used to render the video. 1863 * 1864 * @property _video 1865 * @type Node 1866 * @default null 1867 * @protected 1868 */ 1869 _video: null, 1870 1871 /** 1872 * The default content template for the image 1873 * inherited from Y.Widget. Set to null since 1874 * only the bounding box is needed. 1875 * 1876 * @property CONTENT_TEMPLATE
1877 * @type String 1878 * @default null 1879 * @protected 1880 */ 1881 CONTENT_TEMPLATE: null, 1882 1883 /** 1884 * Initial styling for the bounding box. 1885 * 1886 * @method syncUI 1887 * @protected 1888 */ 1889 syncUI: function() 1890 { 1891 var bb = this.get('boundingBox'); 1892 1893 if(this.get('crop')) { 1894 bb.setStyle('overflow', 'hidden'); 1895 bb.addClass('fl-slideshow-image-cropped'); 1896 } 1897 }, 1898 1899 /** 1900 * Sets the imageInfo object and 1901 * loads the appropriate image size. 1902 * 1903 * @method load 1904 * @param imageInfo {Object} The imageInfo object. 1905 */ 1906 load: function(imageInfo) 1907 { 1908 this._imageInfo = imageInfo; 1909 this._loading = true; 1910 this._load(); 1911 }, 1912 1913 /** 1914 * Sets the width and height of the bounding box and 1915 * preloads an image using the provided imageInfo object. 1916 * 1917 * @method preload 1918 * @param imageInfo {Object} The imageInfo to preload. 1919 * @param width {Number} The width to preload. 1920 * @param height {Number} The height to preload. 1921 */ 1922 preload: function(imageInfo, width, height) 1923 { 1924 var isVideo = this._isVideo(), 1925 loadVideos = this.get('loadVideos'), 1926 showVideoButton = this.get('showVideoButton'); 1927 1928 this.unload(); 1929 this.set('width', width); 1930 this.set('height', height); 1931 this._imageInfo = imageInfo; 1932 1933 if(!isVideo || !loadVideos || (isVideo && loadVideos && showVideoButton)) { 1934 Y.FL.SlideshowImageLoader.add( 1935 this.get('loadGroup'), 1936 this._getImageURL(), 1937 Y.bind(this._imagePreloaded, this), 1938 this.get('loadPriority') 1939 ); 1940 } 1941 }, 1942 1943 /** 1944 * Called when preloading completes. 1945 * 1946 * @method _imagePreloaded 1947 * @param img {Object} The image that was preloaded. 1948 * @protected 1949 */ 1950 _imagePreloaded: function(img) 1951 { 1952 this._image = img; 1953 }, 1954 1955 /** 1956 * Unloads the image if there is one loaded 1957 * and sets the imageInfo object to null. 1958 * 1959 * @method unload 1960 */ 1961 unload: function() 1962 { 1963 if(this._image) { 1964 this._image.remove(); 1965 this._image.detachAll(); 1966 this._image.set('src', ''); 1967 this._image = null; 1968 } 1969 if(this._video) { 1970 this._video.remove(); 1971 this._video = null; 1972 } 1973 if(this._videoButton) { 1974 this._videoButton.remove(); 1975 this._videoButton = null; 1976 } 1977 if(this._videoBox) { 1978 this._removeVideoBox(); 1979 } 1980 1981 this._imageInfo = null; 1982 this._loading = false; 1983 this._loadingURL = null; 1984 }, 1985 1986 /** 1987 * Resizes the bounding box and loads the 1988 * appropriate image size if necessary. 1989 * 1990 * @method resize 1991 * @param width {Number} The width value. 1992 * @param height {Number} The height value. 1993 */ 1994 resize: function(width, height) 1995 { 1996 var borderWidth = parseInt(this.get('boundingBox').getComputedStyle('borderTopWidth'), 10) * 2, 1997 bb = this.get('boundingBox'); 1998 1999 this.set('width', width - borderWidth); 2000 this.set('height', height - borderWidth); 2001 bb.setStyle('width', width - borderWidth + 'px'); 2002 bb.setStyle('height', height - borderWidth + 'px'); 2003 2004 if(this._videoButton) { 2005 this._positionVideoButton(); 2006 } 2007 if(this._videoBox) { 2008 this._loadVideo(); 2009 } 2010 if(!this._loading) { 2011 if(this._imageInfo) { 2012 this._load(); 2013 } 2014 if(this._image) { 2015 this._positionImage(); 2016 } 2017 } 2018 }, 2019 2020 /** 2021 * Loads (or reloads) the image or video. 2022 * 2023 * @method _load 2024 * @protected 2025 */ 2026 _load: function() 2027 { 2028 var loadVideos = this.get('loadVideos'), 2029 showVideoButton = this.get('showVideoButton'); 2030 2031 if(this._isVideo() && loadVideos && !showVideoButton && !('ontouchstart' in window)) { 2032 this._loadVideo(); 2033 } 2034 else { 2035 this._loadImage(); 2036 } 2037 }, 2038 2039 /** 2040 * Loads the appropriate image size if 2041 * it is not already loading. 2042 * 2043 * @method _loadImage 2044 * @protected 2045 */ 2046 _loadImage: function() 2047 { 2048 var url = this._getImageURL(), 2049 loadVideos = this.get('loadVideos'); 2050 2051 // Already loading. 2052 if(url == this._loadingURL) { 2053 return; 2054 } 2055 2056 // New URL to load. 2057 this._loadingURL = url; 2058 2059 // Load the new image. 2060 Y.FL.SlideshowImageLoader.add( 2061 this.get('loadGroup'), 2062 this._loadingURL, 2063 Y.bind(this._loadImageComplete, this), 2064 this.get('loadPriority') 2065 ); 2066 2067 // Initial load? 2068 if(this._loading) { 2069 2070 if(this._isVideo() && loadVideos) { 2071 this._insertVideoButton(); 2072 } 2073 2074 /** 2075 * Only fires when a new image is being 2076 * loaded, not a different size. 2077 * 2078 * @event loadStart 2079 */ 2080 this.fire('loadStart'); 2081 } 2082 }, 2083 2084 /** 2085 * Fires when the image has finished loading. 2086 * 2087 * @method _loadImageComplete 2088 * @protected 2089 */ 2090 _loadImageComplete: function(img) 2091 { 2092 var bb = this.get('boundingBox'), 2093 showVideoButton = this.get('showVideoButton'),
2094 showAria = this.get('root').get('bgslideshow') 2095 2096 this._image = img; 2097 this._image.setStyle('visibility', 'hidden'); 2098 this._image.addClass('fl-slideshow-image-img'); 2099 2100 if( showAria ) { 2101 this._image.set( 'aria-hidden', 'true') 2102 this._image.set( 'alt', "") 2103 } 2104 else { 2105 this._image.set( 'alt', this._imageInfo.alt ) 2106 } 2107 2108 // Remove load events. 2109 this._image.detachAll(); 2110 2111 // Remove previous videos. 2112 if(this._video && !showVideoButton) { 2113 this._video.remove(); 2114 this._video = null; 2115 } 2116 2117 // Remove the old image. 2118 bb.all('img').remove(); 2119 2120 // Append the new image. 2121 bb.append(this._image); 2122 2123 // Setup, scale and position the new image. 2124 this._setupImage(); 2125 this._resizeImage(); 2126 this._positionImage(); 2127 this._image.setStyle('visibility', 'visible'); 2128 2129 // Clear the loading url. 2130 this._loadingURL = null; 2131 2132 // Finish an initial load? 2133 if(this._loading) { 2134 2135 this._loading = false; 2136 2137 /** 2138 * Only fires when a new image is being 2139 * loaded, not a different size. 2140 * 2141 * @event loadComplete 2142 */ 2143 this.fire('loadComplete'); 2144 } 2145 }, 2146 2147 /** 2148 * UI setup for the new image. 2149 * 2150 * @method _setupImage 2151 * @protected 2152 */ 2153 _setupImage: function() 2154 { 2155 var bb = this.get('boundingBox'); 2156 2157 // IE interpolation 2158 if(typeof this._image._node.style.msInterpolationMode != 'undefined') { 2159 this._image._node.style.msInterpolationMode = 'bicubic'; 2160 } 2161 2162 // Protection 2163 if(this.get('protect')) { 2164 bb.delegate('contextmenu', this._protectImage, 'img'); 2165 bb.delegate('mousedown', this._protectImage, 'img'); 2166 } 2167 }, 2168 2169 /** 2170 * Fires on contextmenu or mousedown in attempt 2171 * to keep the image from being copied. 2172 * 2173 * @method _protectImage 2174 * @return {Boolean} Returns false to prevent the default event. 2175 * @protected 2176 */ 2177 _protectImage: function(e) 2178 { 2179 e.preventDefault(); 2180 return false; 2181 }, 2182 2183 /** 2184 * Resizes the image node. 2185 * 2186 * @method _resizeImage 2187 * @protected 2188 */ 2189 _resizeImage: function() 2190 { 2191 var borderWidth = parseInt(this._image.getComputedStyle('borderTopWidth'), 10) * 2, 2192 imageWidth = this._image.get('width'), 2193 imageHeight = this._image.get('height'), 2194 targetWidth = parseInt(this.get('boundingBox').getComputedStyle('width'), 10), 2195 targetHeight = parseInt(this.get('boundingBox').getComputedStyle('height'), 10), 2196 newWidth = 0, 2197 newHeight = 0, 2198 xScale = 0, 2199 yScale = 0, 2200 cropHorizontalsOnly = this.get('cropHorizontalsOnly'), 2201 isHorizontal = imageHeight > imageWidth, 2202 noCrop = false; 2203 2204 if(this._imageInfo && this.get('checkFilenamesForNoCrop')) { 2205 noCrop = this._imageInfo.filename.indexOf('nocrop') > -1; 2206 } 2207 2208 if(this.get('crop') && !(cropHorizontalsOnly && isHorizontal) && !noCrop) { 2209 newWidth = targetWidth; 2210 newHeight = Math.round(imageHeight * targetWidth/imageWidth); 2211 2212 if(newHeight < targetHeight) { 2213 newHeight = targetHeight; 2214 newWidth = Math.round(imageWidth * targetHeight/imageHeight); 2215 } 2216 } 2217 else { 2218 xScale = imageWidth/targetWidth; 2219 yScale = imageHeight/targetHeight; 2220 2221 if (yScale > xScale){ 2222 newWidth = Math.round(imageWidth * (1/yScale)); 2223 newHeight = Math.round(imageHeight * (1/yScale)); 2224 } 2225 else { 2226 newWidth = Math.round(imageWidth * (1/xScale)); 2227 newHeight = Math.round(imageHeight * (1/xScale)); 2228 } 2229 } 2230 2231 // Don't resize past the original size? 2232 if(!this.get('crop') && !this.get('upsize') && (newWidth > imageWidth || newHeight > imageHeight)) { 2233 newWidth = imageWidth; 2234 newHeight = imageHeight; 2235 } 2236 2237 // Compensate for borders. 2238 newWidth -= borderWidth; 2239 newHeight -= borderWidth; 2240 2241 // Resize the image. 2242 this._image.setStyle('width', newWidth + 'px'); 2243 this._image.setStyle('height', newHeight + 'px'); 2244 2245 // Constrain bounding box to image size. 2246 if(!this.get('crop') && this.get('constrainWidth')) { 2247 this.set('width', newWidth + 'px'); 2248 } 2249 if(!this.get('crop') && this.get('constrainHeight')) { 2250 this.set('height', newHeight + 'px'); 2251 } 2252 }, 2253 2254 /** 2255 * Positions the image within the bounding box. 2256 * 2257 * @method _positionImage 2258 * @protected 2259 */ 2260 _positionImage: function() 2261 { 2262 var pos = this.get('position').split(' '), 2263 x = pos[0] === '' ? 'center' : pos[0], 2264 y = pos[1] === '' ? 'center' : pos[1], 2265 newX = 0, 2266 newY = 0, 2267 bbWidth = parseInt(this.get('boundingBox').getComputedStyle('width'), 10), 2268 bbHeight = parseInt(this.get('boundingBox').getComputedStyle('height'), 10), 2269 borderWidth = parseInt(this._image.getComputedStyle('borderTopWidth'), 10) * 2, 2270 imageWidth = parseInt(this._image.getComputedStyle('width'), 10) + borderWidth, 2271 imageHeight = parseInt(this._image.getComputedStyle('height'), 10) + borderWidth; 2272 2273 if(isNaN(imageWidth) && isNaN(imageHeight)) { 2274 return; 2275 } 2276 if(x == 'left') { 2277 newX = 0; 2278 } 2279 if(x == 'center') { 2280 newX = (bbWidth - imageWidth)/2; 2281 } 2282 if(x == 'right') { 2283 newX = bbWidth - imageWidth; 2284 } 2285 2286 if(y == 'top') { 2287 newY = 0; 2288 } 2289 if(y == 'center') { 2290 newY = (bbHeight - imageHeight)/2; 2291 } 2292 if(y == 'bottom') { 2293 newY = bbHeight - imageHeight; 2294 } 2295 2296 this._image.setStyles({ 2297 'left': newX, 2298 'top': newY 2299 }); 2300 }, 2301 2302 /** 2303 * Gets the appropriate image url based 2304 * on the size of the bounding box. 2305 * 2306 * @method _getImageURL 2307 * @return {String} The url to load. 2308 * @protected 2309 */ 2310 _getImageURL: function() 2311 { 2312 var imageWidth = 0, 2313 imageHeight = 0, 2314 size = 0, 2315 targetWidth = this.get('width'), 2316 targetHeight = this.get('height'), 2317 useThumbSizes = this.get('useThumbSizes'), 2318 i = this._imageInfo, 2319 sizes = [ 2320 i.tinyURL || i.thumbURL || i.largeURL, 2321 i.thumbURL || i.largeURL, 2322 i.smallURL || i.largeURL, 2323 i.mediumURL || i.largeURL || i.smallURL, 2324 i.largeURL || i.mediumURL || i.smallURL, 2325 i.xlargeURL || i.largeURL || i.mediumURL || i.smallURL, 2326 i.x2largeURL || i.largeURL || i.mediumURL || i.smallURL, 2327 i.x3largeURL || i.x2largeURL || i.largeURL || i.mediumURL || i.smallURL 2328 ]; 2329 2330 // Width 2331 if(useThumbSizes && targetWidth <= 100) { 2332 imageWidth = 0; 2333 } 2334 else if(useThumbSizes && targetWidth <= 150) { 2335 imageWidth = 1; 2336 } 2337 else if(targetWidth <= 400) { 2338 imageWidth = 2; 2339 } 2340 else if(targetWidth >= 400 && targetWidth <= 600) { 2341 imageWidth = 3; 2342 } 2343 else if(targetWidth >= 600 && targetWidth <= 800) { 2344 imageWidth = 4; 2345 } 2346 else if(targetWidth >= 800 && targetWidth <= 1024) { 2347 imageWidth = 5; 2348 } 2349 else if(targetWidth >= 1024 && targetWidth <= 1280) { 2350 imageWidth = 6; 2351 } 2352 else { 2353 imageWidth = 7; 2354 } 2355 2356 // Height 2357 if(useThumbSizes && targetHeight <= 100) { 2358 imageHeight = 0; 2359 } 2360 else if(useThumbSizes && targetHeight <= 150) { 2361 imageHeight = 1; 2362 } 2363 else if(targetHeight <= 300) { 2364 imageHeight = 2; 2365 } 2366 else if(targetHeight >= 300 && targetHeight <= 450) { 2367 imageHeight = 3; 2368 } 2369 else if(targetHeight >= 450 && targetHeight <= 600) { 2370 imageHeight = 4; 2371 } 2372 else if(targetHeight >= 600 && targetHeight <= 768) { 2373 imageHeight = 5; 2374 } 2375 else if(targetHeight >= 768 && targetHeight <= 960) { 2376 imageHeight = 6; 2377 } 2378 else { 2379 imageHeight = 7; 2380 } 2381 2382 // Get the size number. 2383 size = Math.max(imageWidth, imageHeight); 2384 2385 return sizes[size]; 2386 }, 2387 2388 /** 2389 * Checks whether this is a video or not. 2390 * 2391 * @method _isVideo 2392 * @protected 2393 */ 2394 _isVideo: function() 2395 { 2396 if(!this._imageInfo) { 2397 return false;
2398 } 2399 else if(this._imageInfo.format == 'mp4' && this._imageInfo.sourceType == 'smugmug') { 2400 return true; 2401 } 2402 else if(this._imageInfo.iframe !== '') { 2403 return true; 2404 } 2405 2406 return false; 2407 }, 2408 2409 /** 2410 * @method _loadVideo 2411 * @protected 2412 */ 2413 _loadVideo: function() 2414 { 2415 var bb = this.get('boundingBox'), 2416 showVideoButton = this.get('showVideoButton'), 2417 autoPlay = showVideoButton ? true : false; 2418 2419 // Remove previous videos 2420 if(this._video) { 2421 this._video.remove(); 2422 this._video = null; 2423 } 2424 2425 // Get the video code 2426 if(this._imageInfo.format == 'mp4' && this._imageInfo.sourceType == 'smugmug') { 2427 this._video = this._getSmugMugVideoEmbed(this._imageInfo, autoPlay); 2428 } 2429 else if(this._imageInfo.iframe !== '') { 2430 this._video = this._getIframeVideoEmbed(this._imageInfo, autoPlay); 2431 } 2432 2433 // Insert the video 2434 if(this._videoBox) { 2435 this._videoBox.one('.fl-slideshow-video-wrap').insert(this._video); 2436 } 2437 else { 2438 bb.all('img').remove(); 2439 bb.append(this._video); 2440 } 2441 2442 // Finish an initial load? 2443 if(this._loading) { 2444 this._loading = false; 2445 this.fire('loadComplete'); 2446 } 2447 }, 2448 2449 /** 2450 * @method _insertVideoButton 2451 * @protected 2452 */ 2453 _insertVideoButton: function() 2454 { 2455 var bb = this.get('boundingBox'), 2456 event = 'ontouchstart' in window ? 'touchstart' : 'click'; 2457 2458 this._videoButton = Y.Node.create('<a class="fl-slideshow-video-button" href="javascript:void(0);"></a>'); 2459 this._videoButton.on(event, Y.bind(this._showVideoBox, this)); 2460 bb.insert(this._videoButton); 2461 this._positionVideoButton(); 2462 }, 2463 2464 /** 2465 * @method _positionVideoButton 2466 * @protected 2467 */ 2468 _positionVideoButton: function() 2469 { 2470 var bbWidth = this.get('width'), 2471 bbHeight = this.get('height'), 2472 buttonWidth = parseInt(this._videoButton.getStyle('width'), 10), 2473 buttonHeight = parseInt(this._videoButton.getStyle('height'), 10); 2474 2475 this._videoButton.setStyles({ 2476 left: (bbWidth - buttonWidth)/2, 2477 top: (bbHeight - buttonHeight)/2 2478 }); 2479 }, 2480 2481 /** 2482 * @method _showVideoBox 2483 * @protected 2484 */ 2485 _showVideoBox: function() 2486 { 2487 var root = this.get('root'), 2488 wrap = Y.Node.create('<div class="fl-slideshow-video-wrap"></div>'), 2489 close = Y.Node.create('<a class="fl-slideshow-video-close" href="javascript:void(0);"></a>'), 2490 event = 'ontouchstart' in window ? 'touchstart' : 'click'; 2491 2492 this._videoBox = Y.Node.create('<div class="fl-slideshow-video"></div>'); 2493 this._videoBox.setStyle('padding', root.get('boundingBox').getStyle('padding')); 2494 this._videoBox.insert(wrap); 2495 this._videoBox.insert(close); 2496 this._videoBox.on(event, Y.bind(this._removeVideoBox, this)); 2497 close.on(event, Y.bind(this._removeVideoBox, this)); 2498 2499 if(typeof YUI.Env.mods['sm-fonticon'] !== 'undefined') { 2500 close.addClass('sm-fonticon sm-fonticon-XCrossEncircled sm-button-skin-default sm-button-nochrome'); 2501 } 2502 2503 Y.one('body').insert(this._videoBox); 2504 this._loadVideo(); 2505 2506 Y.one('body').on('fl-slideshow-image|keydown', this._onKey, this); 2507 }, 2508 2509 /** 2510 * Get the embed code for a SmugMug video. 2511 * 2512 * @method _getSmugMugVideoEmbed 2513 * @param imageInfo {Object} The image info for the embed. 2514 * @param autoPlay {Boolean} Whether to auto play videos or not. 2515 * @protected 2516 */ 2517 _getSmugMugVideoEmbed: function(imageInfo, autoPlay) 2518 { 2519 var test = document.createElement('video'), 2520 width = 0, 2521 mp4 = '', 2522 vars = '', 2523 code = ''; 2524 2525 if(Y.UA.mobile !== null && !!test.canPlayType && test.canPlayType('video/mp4')) { 2526 width = this.get('width'); 2527 mp4 = 'https://www.smugmug.com/photos/' + imageInfo.id + '_' + imageInfo.key + '-' + width + '.mp4'; 2528 code += '<video width="100%" height="100%" poster="'+ this._getImageURL() +'" controls preload="none"'; 2529 2530 if(autoPlay) { 2531 code += ' autoplay'; 2532 } 2533 2534 code += '>'; 2535 code += '<source src="'+ mp4 +'" type="video/mp4" />'; 2536 code += '</video>'; 2537 } 2538 else { 2539 vars = 'imageId=' + imageInfo.id; 2540 vars += '&imageKey=' + imageInfo.key; 2541 vars += '&albumId=' + imageInfo.albumId; 2542 vars += '&albumKey=' + imageInfo.albumKey; 2543 vars += '&apiURL=https://api.smugmug.com/&hostLevel=live&isPro=true'; 2544 2545 if(autoPlay) { 2546 vars += '&autoPlay=true'; 2547 } 2548 else { 2549 vars += '&autoPlay=false'; 2550 } 2551 2552 code += '<object type="application/x-shockwave-flash" width="100%" height="100%" data="https://cdn.smugmug.com/img/ria/SmugPlayer/2012102601.swf">'; 2553 code += '<param name="movie" value="https://cdn.smugmug.com/img/ria/SmugPlayer/2012102601.swf">'; 2554 code += '<param name="allowFullScreen" value="true">'; 2555 code += '<param name="wmode" value="transparent">'; 2556 code += '<param name="flashVars" value="' + vars + '">'; 2557 code += '<embed src="https://cdn.smugmug.com/img/ria/SmugPlayer/2012102601.swf" flashvars="'+ vars +'" width="100%" height="100%" type="application/x-shockwave-flash" allowfullscreen="true" wmode="transparent">'; 2558 code += '</object>'; 2559 } 2560 2561 return Y.Node.create(code); 2562 }, 2563 2564 /** 2565 * Get the iframe video embed code. 2566 * 2567 * @method _getIframeVideoEmbed
2568 * @param imageInfo {Object} The image info for the embed. 2569 * @param autoPlay {Boolean} Whether to auto play videos or not. 2570 * @protected 2571 */ 2572 _getIframeVideoEmbed: function(imageInfo, autoPlay) 2573 { 2574 var code = '<iframe width="100%" height="100%" allowfullscreen ', 2575 url = imageInfo.iframe; 2576 2577 if(autoPlay) { 2578 url += url.indexOf('?') > -1 ? '&autoplay=1' : '?autoplay=1'; 2579 } 2580 2581 code += 'src="'+ url +'"></iframe>'; 2582 2583 return Y.Node.create(code); 2584 }, 2585 2586 /** 2587 * @method _removeVideoBox 2588 * @protected 2589 */ 2590 _removeVideoBox: function(e) 2591 { 2592 if(typeof e !== 'undefined' && e.target) { 2593 if(e.target.get('className').indexOf('fl-slideshow-video') < 0) { 2594 return; 2595 } 2596 } 2597 2598 if(this._videoBox !== null) { 2599 this._videoBox.remove(); 2600 this._videoBox = null; 2601 this._video = null; 2602 } 2603 2604 Y.one('body').detach('fl-slideshow-image|keydown', this._onKey); 2605 }, 2606 2607 /** 2608 * Keyboard input for the esc button. 2609 * 2610 * @method _onKey 2611 * @protected 2612 */ 2613 _onKey: function(e) 2614 { 2615 if(e.keyCode == 27) { 2616 this._removeVideoBox(); 2617 return false; 2618 } 2619 } 2620 2621}, { 2622 2623 /** 2624 * Custom CSS class name for the widget. 2625 2626 * @property CSS_PREFIX
2627 * @type String 2628 * @protected 2629 * @static 2630 */ 2631 CSS_PREFIX: 'fl-slideshow-image', 2632 2633 /** 2634 * Static property used to define the default attribute configuration of 2635 * the Widget. 2636 * 2637 * @property ATTRS 2638 * @type Object 2639 * @protected 2640 * @static 2641 */ 2642 ATTRS: { 2643 2644 /** 2645 * @attribute loadGroup 2646 * @type String 2647 * @default none 2648 */ 2649 loadGroup: { 2650 value: 'none' 2651 }, 2652 2653 /** 2654 * @attribute loadPriority 2655 * @type Boolean 2656 * @default false 2657 */ 2658 loadPriority: { 2659 value: false 2660 }, 2661 2662 /** 2663 * Whether to crop the image. 2664 * 2665 * @attribute crop 2666 * @type Boolean 2667 * @default false 2668 */ 2669 crop: { 2670 value: false 2671 }, 2672 2673 /** 2674 * Checks whether the filename has nocrop in it or not. 2675 * If it does, the image will not be cropped. 2676 * 2677 * @attribute checkFilenamesForNoCrop 2678 * @type Boolean 2679 * @default true 2680 */ 2681 checkFilenamesForNoCrop: { 2682 value: true 2683 }, 2684 2685 /** 2686 * Whether to only crop horizontal images or not. 2687 * 2688 * @attribute cropHorizontalsOnly 2689 * @type Boolean 2690 * @default false 2691 */ 2692 cropHorizontalsOnly: { 2693 value: false 2694 }, 2695 2696 /** 2697 * The x and y position of the image 2698 * within the bounding box. 2699 * 2700 * @attribute position
2701 * @type String 2702 * @default center center 2703 */ 2704 position: { 2705 value: 'center center' 2706 }, 2707 2708 /** 2709 * Whether to right click protect the image. 2710 * 2711 * @attribute protect 2712 * @type Boolean 2713 * @default true 2714 */ 2715 protect: { 2716 value: true 2717 }, 2718 2719 /** 2720 * Whether to resize the image past 2721 * its original width and height. 2722 * 2723 * @attribute upsize 2724 * @type Boolean 2725 * @default true 2726 */ 2727 upsize: { 2728 value: true 2729 }, 2730 2731 /** 2732 * Whether to load thumb sizes. Defaults 2733 * to false since thumb sizes are square. 2734 * 2735 * @attribute useThumbSizes 2736 * @type Boolean 2737 * @default false 2738 */ 2739 useThumbSizes: { 2740 value: false 2741 }, 2742 2743 /** 2744 * Whether to constrain the width of the 2745 * bounding box to the width of the image. 2746 * 2747 * @attribute constrainWidth 2748 * @type Boolean 2749 * @default false 2750 */ 2751 constrainWidth: { 2752 value: false 2753 }, 2754 2755 /** 2756 * Whether to constrain the height of the 2757 * bounding box to the height of the image. 2758 * 2759 * @attribute constrainHeight 2760 * @type Boolean 2761 * @default false 2762 */ 2763 constrainHeight: { 2764 value: false 2765 }, 2766 2767 /** 2768 * Whether to load videos or not. The poster 2769 * image will be loaded if set to false. 2770 * 2771 * @attribute loadVideos 2772 * @type Boolean 2773 * @default true 2774 */ 2775 loadVideos: { 2776 value: true 2777 }, 2778 2779 /** 2780 * Whether to show the video play button or not. 2781 * When clicked, videos will be displayed in a 2782 * lightbox instead of the slideshow itself. 2783 * 2784 * @attribute showVideoButton 2785 * @type Boolean 2786 * @default true 2787 */ 2788 showVideoButton: { 2789 value: true 2790 } 2791 } 2792}); 2793 2794/** 2795 * A plugin that turns the cursor into a prev or next arrow when 2796 * it is over the left or right side of the slideshow. 2797 * 2798 * @namespace FL 2799 * @class SlideshowMouseNav 2800 * @constructor 2801 * @param config {Object} Configuration object 2802 * @extends Plugin.Base 2803 */ 2804Y.namespace('FL').SlideshowMouseNav = Y.Base.create('fl-slideshow-mouse-nav', Y.Plugin.Base, [], { 2805 2806 /** 2807 * @method initializer 2808 * @protected 2809 */ 2810 initializer: function() 2811 { 2812 var trigger = this.get('trigger'); 2813 2814 trigger.on('click', this._triggerClick, this); 2815 trigger.on('mousemove', this._showArrow, this); 2816 trigger.on('mouseleave', this._hideArrow, this); 2817 }, 2818 2819 /** 2820 * @method _triggerClick 2821 * @protected 2822 */ 2823 _triggerClick: function(e) 2824 { 2825 var host = this.get('host'), 2826 trigger = this.get('trigger'), 2827 triggerWidth = parseInt(trigger.getStyle('width'), 10), 2828 triggerRegion = trigger.get('region'), 2829 layerX = e.pageX - triggerRegion.left + 5; 2830 2831 if(layerX >= triggerWidth/2) { 2832 host.nextImage(); 2833 } 2834 else { 2835 host.prevImage(); 2836 } 2837 }, 2838 2839 /** 2840 * @method _showArrow 2841 * @protected 2842 */ 2843 _showArrow: function(e) 2844 { 2845 var host = this.get('host'), 2846 trigger = this.get('trigger'), 2847 triggerWidth = parseInt(trigger.getStyle('width'), 10), 2848 triggerRegion = trigger.get('region'), 2849 layerX = e.pageX - triggerRegion.left + 5; 2850 2851 if(host.albumInfo !== null && host.albumInfo.images.length > 1) { 2852 if(layerX >= triggerWidth/2) { 2853 trigger.removeClass('fl-slideshow-mouse-nav-prev'); 2854 trigger.addClass('fl-slideshow-mouse-nav-next'); 2855 } 2856 else { 2857 trigger.removeClass('fl-slideshow-mouse-nav-next'); 2858 trigger.addClass('fl-slideshow-mouse-nav-prev'); 2859 } 2860 } 2861 }, 2862 2863 /** 2864 * @method _hideArrow 2865 * @protected 2866 */ 2867 _hideArrow: function() 2868 { 2869 var trigger = this.get('trigger'); 2870 2871 trigger.removeClass('fl-slideshow-mouse-nav-next'); 2872 trigger.removeClass('fl-slideshow-mouse-nav-prev'); 2873 } 2874 2875}, { 2876 2877 /** 2878 * Namespace for the plugin. 2879 * 2880 * @property NS
2881 * @type String 2882 * @protected 2883 * @static 2884 */ 2885 NS: 'mouseNav', 2886 2887 /** 2888 * Static property used to define the default attribute configuration of 2889 * the Plugin. 2890 * 2891 * @property ATTRS 2892 * @type Object 2893 * @protected 2894 * @static 2895 */ 2896 ATTRS: { 2897 2898 /** 2899 * A Node that triggers the arrows. 2900 * 2901 * @attribute trigger 2902 * @type Node 2903 * @default null 2904 */ 2905 trigger: { 2906 value: null 2907 } 2908 } 2909}); 2910 2911/** 2912 * Ken Burns effect for slideshow images. 2913 * 2914 * @namespace FL 2915 * @class SlideshowKenBurns 2916 * @constructor 2917 * @param config {Object} Configuration object 2918 * @extends Base 2919 */ 2920Y.namespace('FL').SlideshowKenBurns = Y.Base.create('fl-slideshow-ken-burns', Y.Base, [], { 2921 2922 /** 2923 * Runs the Ken Burns effect. 2924 * 2925 * @method run 2926 */ 2927 run: function() 2928 { 2929 var imageNode = null, 2930 transform = null; 2931 2932 if(Y.FL.Utils.cssSupport('transform')) { 2933 2934 // Image node 2935 imageNode = this.get('image').one('img'); 2936 2937 // Transform object 2938 transform = this._getTransform(); 2939 2940 // Apply the start transform 2941 imageNode.setStyles({ 2942 '-webkit-transform-origin': transform.origin, 2943 '-moz-transform-origin': transform.origin, 2944 '-ms-transform-origin': transform.origin, 2945 'transform-origin': transform.origin, 2946 'transform': transform.start 2947 }); 2948 2949 // Transition to the end transform 2950 imageNode.transition({ 2951 easing: 'ease-out', 2952 duration : this.get('duration'), 2953 'transform' : transform.end 2954 }); 2955 } 2956 }, 2957 2958 /** 2959 * @method _getTransform 2960 * @protected 2961 */ 2962 _getTransform: function() 2963 { 2964 var zoom = this.get('zoom'), 2965 image = this.get('image'), 2966 i = 0, 2967 zoomDirection = null, 2968 transform = null; 2969 2970 // Random zoom direction 2971 i = Math.floor(Math.random() * Y.FL.SlideshowKenBurns.ZOOM_DIRECTIONS.length); 2972 zoomDirection = Y.FL.SlideshowKenBurns.ZOOM_DIRECTIONS[i]; 2973 2974 // Random transform 2975 i = Math.floor(Math.random() * Y.FL.SlideshowKenBurns.TRANSFORMS.length); 2976 transform = Y.FL.SlideshowKenBurns.TRANSFORMS[i]; 2977 2978 // Get the start and end transforms 2979 if(!image.hasClass('fl-slideshow-image-cropped') && zoomDirection == 'in') { 2980 i = Math.floor(Math.random() * 2); 2981 transform.start = i === 0 ? 'scale(1) translate(100px, 0)' : 'scale(1) translate(-100px, 0)'; 2982 transform.end = 'scale(' + zoom + ') translate(0, 0)'; 2983 transform.origin = 'center center'; 2984 } 2985 else if(zoomDirection == 'out') { 2986 transform.start = 'scale(' + zoom + ') ' + transform.translate; 2987 transform.end = 'scale(1) translate(0, 0)'; 2988 } 2989 else { 2990 transform.start = 'scale(1) translate(0, 0)'; 2991 transform.end = 'scale(' + zoom + ') ' + transform.translate; 2992 } 2993 2994 return transform; 2995 } 2996 2997}, { 2998 2999 /** 3000 * Static property used to define the default attribute configuration of 3001 * the Widget. 3002 * 3003 * @property ATTRS 3004 * @type Object 3005 * @protected 3006 * @static 3007 */ 3008 ATTRS: { 3009 3010 /** 3011 * An instance of FL.Slideshow image to apply the 3012 * Ken Burns effect on. 3013 * 3014 * @attribute image 3015 * @type FL.Slideshow 3016 * @default null 3017 */ 3018 image: { 3019 value: null 3020 }, 3021 3022 /** 3023 * The amount to zoom the image. Zooming 3024 * in our out is done randomly by this class. 3025 * 3026 * @attribute scale 3027 * @type Number 3028 * @default 1.2 3029 */ 3030 zoom: { 3031 value: 1.2 3032 }, 3033 3034 /** 3035 * The duration of the effect in seconds. 3036 * 3037 * @attribute duration 3038 * @type Number 3039 * @default 2 3040 */ 3041 duration: { 3042 value: 2 3043 } 3044 }, 3045 3046 /** 3047 * The zoom directions that can be applied to an image. 3048 * 3049 * @property ZOOM_DIRECTIONS 3050 * @type Object 3051 * @readOnly 3052 * @protected 3053 * @static 3054 */ 3055 ZOOM_DIRECTIONS: [ 3056 'in', 3057 'out' 3058 ], 3059 3060 /** 3061 * The types of transforms that can be applied to an image. 3062 * 3063 * @property TRANSFORMS 3064 * @type Object 3065 * @readOnly 3066 * @protected 3067 * @static 3068 */ 3069 TRANSFORMS: [ 3070 { 3071 origin : 'left top', 3072 translate : 'translate(-30px, -15px)' 3073 },{ 3074 origin : 'left center', 3075 translate : 'translate(-30px, 0)' 3076 },{ 3077 origin : 'left bottom', 3078 translate : 'translate(-30px, 15px)' 3079 },{ 3080 origin : 'right top', 3081 translate : 'translate(30px, -15px)' 3082 },{ 3083 origin : 'right center', 3084 translate : 'translate(30px, 0)' 3085 },{ 3086 origin : 'right bottom', 3087 translate : 'translate(30px, 15px)' 3088 } 3089 ] 3090}); 3091 3092/** 3093 * Navigation buttons widget for controlling a slideshow instance 3094 * and its child widgets. 3095 * 3096 * @namespace FL 3097 * @class SlideshowNav 3098 * @constructor 3099 * @param config {Object} Configuration object 3100 * @extends Widget 3101 */ 3102Y.namespace('FL').SlideshowNav = Y.Base.create('fl-slideshow-nav', Y.Widget, [Y.WidgetChild], { 3103 3104 /**
3105 * An object containing the anchor nodes for all buttons. 3106 * 3107 * @property _buttons 3108 * @type Object 3109 * @default null 3110 * @protected 3111 */ 3112 _buttons: null, 3113 3114 /** 3115 * An div node containing the anchor nodes for the main buttons. 3116 * 3117 * @property _buttonsContainer 3118 * @type Object 3119 * @default null 3120 * @protected 3121 */ 3122 _buttonsContainer: null, 3123 3124 /** 3125 * An div node containing the anchor nodes for the left buttons. 3126 * 3127 * @property _buttonsLeftContainer 3128 * @type Object 3129 * @default null 3130 * @protected 3131 */ 3132 _buttonsLeftContainer: null, 3133 3134 /** 3135 * An div node containing the anchor nodes for the right buttons. 3136 * 3137 * @property _buttonsRightContainer 3138 * @type Object 3139 * @default null 3140 * @protected 3141 */ 3142 _buttonsRightContainer: null, 3143 3144 /** 3145 * Property map for rendering SmugMug font icons. 3146 * 3147 * @property _fontIcons 3148 * @type Object 3149 * @protected 3150 */ 3151 _fontIcons: { 3152 buy: 'Cart', 3153 caption: 'InfoEncircled', 3154 close: 'XCrossEncircled', 3155 fullscreen: 'ScreenExpand', 3156 next: 'ArrowRight', 3157 nextPage: 'ArrowRight', 3158 pause: 'PlayerPause', 3159 play: 'PlayerPlay', 3160 prev: 'ArrowLeft', 3161 prevPage: 'ArrowLeft', 3162 social: 'Heart', 3163 thumbs: 'ViewThumbGrid' 3164 }, 3165 3166 /** 3167 * The default content template for the nav 3168 * inherited from Y.Widget. Set to null since 3169 * only the bounding box is needed. 3170 * 3171 * @property CONTENT_TEMPLATE
3172 * @type String 3173 * @default null 3174 * @protected 3175 */ 3176 CONTENT_TEMPLATE: null, 3177 3178 /** 3179 * Renders the buttons. 3180 * 3181 * @method renderUI 3182 * @protected 3183 */ 3184 renderUI: function() 3185 { 3186 this._renderContainers(); 3187 this._renderButtons(); 3188 this._renderFontIcons(); 3189 }, 3190 3191 /** 3192 * Binds events to the root slideshow for each button. 3193 * 3194 * @method bindUI 3195 * @protected 3196 */ 3197 bindUI: function() 3198 { 3199 var root = this.get('root'), 3200 id = this.get('id'); 3201 3202 if(this._buttons.prev) { 3203 this._buttons.prev.on('click', root.prevImage, root); 3204 } 3205 if(this._buttons.next) { 3206 this._buttons.next.on('click', root.nextImage, root); 3207 } 3208 if(this._buttons.play) { 3209 this._buttons.play.on('click', this._playClicked, this); 3210 root.on(id + '|played', this._showPauseButton, this); 3211 root.on(id + '|paused', this._showPlayButton, this); 3212 3213 if(root._playing) { 3214 this._showPauseButton(); 3215 } 3216 else { 3217 this._showPlayButton(); 3218 } 3219 } 3220 if(this._buttons.buy) { 3221 3222 root.on(id + '|albumLoadComplete', this._updateBuy, this); 3223 3224 if(root.albumInfo !== null) { 3225 this._updateBuy(); 3226 } 3227 } 3228 if(this._buttons.count) { 3229 root.on(id + '|imageLoadComplete', this._updateCount, this); 3230 } 3231 if(this._buttons.thumbs) { 3232 this._buttons.thumbs.on('click', root._toggleThumbs, root); 3233 } 3234 if(this._buttons.caption) { 3235 root.on(id + '|imageLoadComplete', this._updateCaption, this); 3236 this._updateCaption(); 3237 } 3238 if(this._buttons.social) { 3239 this._buttons.social.on('click', root._toggleSocial, root); 3240 } 3241 if(this._buttons.fullscreen && root.fullscreen) { 3242 this._buttons.fullscreen.on('click', root.fullscreen.toggle, root.fullscreen); 3243 } 3244 if(this._buttons.close) { 3245 this._buttons.close.on('click', root.hide, root); 3246 } 3247 }, 3248 3249 /** 3250 * @method destructor 3251 * @protected 3252 */ 3253 destructor: function() 3254 { 3255 var root = this.get('root'), 3256 id = this.get('id'); 3257 3258 root.detach(id + '|*'); 3259 }, 3260 3261 /** 3262 * Renders the button left, right and main button containers. 3263 * 3264 * @method _renderContainers 3265 * @protected 3266 */ 3267 _renderContainers: function() 3268 { 3269 var cb = this.get('contentBox'), 3270 buttonsLeft = this.get('buttonsLeft'), 3271 buttonsRight = this.get('buttonsRight'); 3272 3273 this._buttonsContainer = Y.Node.create('<div></div>'); 3274 this._buttonsContainer.addClass('fl-slideshow-nav-buttons'); 3275 cb.appendChild(this._buttonsContainer); 3276 3277 if(buttonsLeft.length > 0) { 3278 this._buttonsLeftContainer = Y.Node.create('<div></div>'); 3279 this._buttonsLeftContainer.addClass('fl-slideshow-nav-buttons-left'); 3280 cb.appendChild(this._buttonsLeftContainer); 3281 } 3282 if(buttonsRight.length > 0) { 3283 this._buttonsRightContainer = Y.Node.create('<div></div>'); 3284 this._buttonsRightContainer.addClass('fl-slideshow-nav-buttons-right'); 3285 cb.appendChild(this._buttonsRightContainer); 3286 } 3287 }, 3288 3289 /** 3290 * Renders the buttons based on the buttons array 3291 * passed in the configuration object. 3292 * 3293 * @method _renderButtons 3294 * @protected 3295 */ 3296 _renderButtons: function() 3297 { 3298 var name = '', 3299 i = 0, 3300 k = 0, 3301 b = [ 3302 { 3303 names: this.get('buttons'), 3304 container: this._buttonsContainer 3305 }, 3306 { 3307 names: this.get('buttonsLeft'), 3308 container: this._buttonsLeftContainer 3309 }, 3310 { 3311 names: this.get('buttonsRight'), 3312 container: this._buttonsRightContainer 3313 } 3314 ]; 3315 3316 this._buttons = {}; 3317 3318 for( ; i < b.length; i++) { 3319 for(k = 0; k < b[i].names.length; k++) { 3320 3321 name = b[i].names[k]; 3322 3323 if(name.indexOf('count') > -1) { 3324 this._buttons[name] = Y.Node.create('<span></span>'); 3325 this._updateCount(); 3326 } 3327 else { 3328 this._buttons[name] = Y.Node.create('<a href="javascript:void(0);"></a>'); 3329 } 3330 3331 if(name.indexOf('buy') > -1) { 3332 this._buttons[name].setStyle('display', 'none'); 3333 } 3334 3335 this._buttons[name].set('name', name); 3336 this._buttons[name].set('aria-label', name); 3337 this._buttons[name].addClass('fl-slideshow-nav-' + name); 3338 b[i].container.appendChild(this._buttons[name]); 3339 } 3340 } 3341 }, 3342 3343 /** 3344 * Renders SmugMug font icons for each button. 3345 * 3346 * @method _renderFontIcons 3347 * @protected 3348 */ 3349 _renderFontIcons: function() 3350 { 3351 var name = null; 3352 3353 if(this.get('useFontIcons') && typeof YUI.Env.mods['sm-fonticon'] !== 'undefined') { 3354 for(name in this._buttons) { 3355 if(typeof this._buttons[name] !== 'undefined' && typeof this._fontIcons[name] !== 'undefined') { 3356 this._buttons[name].addClass('sm-fonticon-' + this._fontIcons[name]); 3357 this._buttons[name].addClass('sm-fonticon sm-button-skin-default sm-button-nochrome'); 3358 } 3359 else if(name.indexOf('count') > -1) { 3360 this._buttons[name].addClass('fonticons-enabled'); 3361 } 3362 } 3363 } 3364 }, 3365 3366 /** 3367 * Updates the image count. 3368 * 3369 * @method _updateCount 3370 * @protected 3371 */ 3372 _updateCount: function() 3373 { 3374 var html = '', 3375 countText = Y.FL.SlideshowNav.COUNT_TEXT, 3376 current = 1, 3377 total = 1; 3378 3379 if(this.get('root').albumInfo) { 3380 current = this.get('root').imageInfo.index + 1; 3381 total = this.get('root').albumInfo.images.length; 3382 } 3383 3384 html = countText.replace('{current}', current).replace('{total}', total); 3385 this._buttons.count.set('innerHTML', html); 3386 }, 3387 3388 /** 3389 * Shows the caption button if the current image 3390 * has a caption, hides it if the image does not 3391 * have a caption. 3392 * 3393 * @method _updateCaption 3394 * @protected 3395 */ 3396 _updateCaption: function() 3397 { 3398 var root = this.get('root'), 3399 imageInfo = root.imageInfo; 3400 3401 if(imageInfo && imageInfo.caption === '') { 3402 root.caption.slideshowOverlay.enable(); 3403 root.caption.slideshowOverlay.hide(); 3404 this._buttons.caption.detach('click'); 3405 this._buttons.caption.addClass('fl-slideshow-nav-caption-disabled'); 3406 } 3407 else { 3408 this._buttons.caption.on('click', root._toggleCaption, root); 3409 this._buttons.caption.removeClass('fl-slideshow-nav-caption-disabled'); 3410 } 3411 }, 3412 3413 /** 3414 * Checks if buying has been enabled for the current album. 3415 * 3416 * @method _updateBuy 3417 * @protected 3418 */ 3419 _updateBuy: function() 3420 { 3421 var sm = null, 3422 root = this.get('root'), 3423 rootSource = root.get('source')[root.albumIndex], 3424 albumIndex = root.albumIndex, 3425 source = root.get('source')[albumIndex]; 3426 3427 if(rootSource && rootSource.type == 'smugmug') { 3428 if(typeof root.albumInfo.printable !== 'undefined') { 3429 this._updateBuyComplete(); 3430 } 3431 else { 3432 sm = new Y.FL.SmugMugAPI(); 3433 sm.addParam('method', 'smugmug.albums.getInfo'); 3434 sm.addParam('AlbumID', source.id); 3435 sm.addParam('AlbumKey', source.key); 3436 sm.on('complete', this._updateBuyComplete, this); 3437 sm.request(); 3438 } 3439 } 3440 }, 3441 3442 /** 3443 * Shows the buy button and updates the buy url 3444 * if buying has been enabled. 3445 * 3446 * @method _updateBuyComplete 3447 * @param e {Object} The custom event object passed to this function. 3448 * @protected 3449 */ 3450 _updateBuyComplete: function(e) 3451 { 3452 var root = this.get('root'), 3453 printable = typeof e == 'undefined' ? root.albumInfo.printable : e.Album.Printable, 3454 link = root.albumInfo.link; 3455 3456 if(printable) { 3457 root.albumInfo.printable = true; 3458 this._buttons.buy.set('href', 'https://secure.smugmug.com/cart/batchadd/?url=' + encodeURIComponent(link)); 3459 this._buttons.buy.setStyle('display', 'inline-block'); 3460 } 3461 else { 3462 root.albumInfo.printable = false;
3463 this._buttons.buy.setStyle('display', 'none'); 3464 } 3465 3466 this.fire('resize'); 3467 }, 3468 3469 /** 3470 * Pauses the slideshow if it is playing and 3471 * plays the slideshow if it is paused. 3472 * 3473 * @method _playClicked 3474 * @protected 3475 */ 3476 _playClicked: function() 3477 { 3478 var root = this.get('root'); 3479 3480 if(root._playing) { 3481 root.pause(); 3482 } 3483 else { 3484 root.play(); 3485 } 3486 }, 3487 3488 /** 3489 * Toggles the button class for the play button 3490 * so pause is hidden and play is shown. 3491 * 3492 * @method _showPlayButton 3493 * @protected 3494 */ 3495 _showPlayButton: function() 3496 { 3497 this._buttons.play.removeClass('fl-slideshow-nav-pause'); 3498 this._buttons.play.addClass('fl-slideshow-nav-play'); 3499 3500 if(this.get('useFontIcons') && typeof YUI.Env.mods['sm-fonticon'] !== 'undefined') { 3501 this._buttons.play.removeClass('sm-fonticon-PlayerPause'); 3502 this._buttons.play.addClass('sm-fonticon-PlayerPlay'); 3503 } 3504 }, 3505 3506 /** 3507 * Toggles the button class for the play button 3508 * so pause is shown and play is hidden. 3509 * 3510 * @method _showPauseButton 3511 * @protected 3512 */ 3513 _showPauseButton: function() 3514 { 3515 this._buttons.play.removeClass('fl-slideshow-nav-play'); 3516 this._buttons.play.addClass('fl-slideshow-nav-pause'); 3517 3518 if(this.get('useFontIcons') && typeof YUI.Env.mods['sm-fonticon'] !== 'undefined') { 3519 this._buttons.play.removeClass('sm-fonticon-PlayerPlay'); 3520 this._buttons.play.addClass('sm-fonticon-PlayerPause'); 3521 } 3522 } 3523 3524}, { 3525 3526 /** 3527 * Custom CSS class name for the widget. 3528 * 3529 * @property CSS_PREFIX
3530 * @type String 3531 * @protected 3532 * @static 3533 */ 3534 CSS_PREFIX: 'fl-slideshow-nav', 3535 3536 /** 3537 * Static string used for displaying the image count. Use {current} 3538 * for the current image and {total} for the total number of images. 3539 * Those placeholders will be replaced when the count node is created. 3540 * 3541 * @property COUNT_TEXT 3542 * @type String 3543 * @protected 3544 * @static 3545 */ 3546 COUNT_TEXT: '{current} of {total}', 3547 3548 /** 3549 * Static property used to define the default attribute configuration of 3550 * the Widget. 3551 * 3552 * @property ATTRS 3553 * @type Object 3554 * @protected 3555 * @static 3556 */ 3557 ATTRS: { 3558 3559 /** 3560 * An array of button names that is used to render the main buttons. 3561 * 3562 * @attribute buttons 3563 * @type Array 3564 * @default [] 3565 * @writeOnce 3566 */ 3567 buttons: { 3568 value: [], 3569 writeOnce: true 3570 }, 3571 3572 /** 3573 * An array of button names that is used to render the left buttons. 3574 * 3575 * @attribute buttonsLeft 3576 * @type Array 3577 * @default [] 3578 * @writeOnce 3579 */ 3580 buttonsLeft: { 3581 value: [], 3582 writeOnce: true 3583 }, 3584 3585 /** 3586 * An array of button names that is used to render the right buttons. 3587 * 3588 * @attribute buttonsRight 3589 * @type Array 3590 * @default [] 3591 * @writeOnce 3592 */ 3593 buttonsRight: { 3594 value: [], 3595 writeOnce: true 3596 }, 3597 3598 /** 3599 * Whether to use font icons when available. 3600 * 3601 * @attribute useFontIcons 3602 * @type Boolean 3603 * @default true 3604 * @writeOnce 3605 */ 3606 useFontIcons: { 3607 value: true, 3608 writeOnce: true 3609 } 3610 } 3611}); 3612 3613/** 3614 * A plugin for overlaying widgets in a slideshow 3615 * with specialized show and hide functionality. 3616 * 3617 * @namespace FL 3618 * @class SlideshowOverlay 3619 * @constructor 3620 * @param config {Object} Configuration object 3621 * @extends Plugin.Base 3622 */ 3623Y.namespace('FL').SlideshowOverlay = Y.Base.create('fl-slideshow-overlay', Y.Plugin.Base, [], { 3624 3625 /** 3626 * Flag for whether the mouse has entered 3627 * the host's bounding box. 3628 * 3629 * @property _focus 3630 * @type Boolean 3631 * @default false 3632 * @protected 3633 */ 3634 _focus: false, 3635 3636 /** 3637 * Flag for whether the host's bounding box is visible. 3638 * 3639 * @property _visible 3640 * @type Boolean 3641 * @default true 3642 * @protected 3643 */ 3644 _visible: true, 3645 3646 /** 3647 * Flag for whether show and hide functionality 3648 * has been disabled. 3649 * 3650 * @property _disabled 3651 * @type Boolean 3652 * @default false 3653 * @protected 3654 */ 3655 _disabled: false, 3656 3657 /** 3658 * An object containing properties for the show transition. 3659 * 3660 * @property _showProps 3661 * @type Object 3662 * @protected 3663 */ 3664 _showProps: { 3665 duration: 0.5, 3666 easing: 'ease-out', 3667 opacity: 1 3668 }, 3669 3670 /** 3671 * An object containing properties for the hide transition. 3672 * 3673 * @property _hideProps 3674 * @type Object 3675 * @protected 3676 */ 3677 _hideProps: { 3678 duration: 0.5, 3679 easing: 'ease-out', 3680 opacity: 0 3681 }, 3682 3683 /** 3684 * A timer object for delaying the hide transition. 3685 * 3686 * @property _hideTimer 3687 * @type Object 3688 * @default null 3689 * @protected 3690 */ 3691 _hideTimer: null, 3692 3693 /** 3694 * @method initializer 3695 * @protected 3696 */ 3697 initializer: function() 3698 { 3699 var bb = this.get('host').get('boundingBox'); 3700 3701 this.afterHostEvent('render', this._initFocus); 3702 this.afterHostEvent('render', this._initVisibility); 3703 3704 if(this.get('closeButton')) { 3705 this._initCloseButton(); 3706 } 3707 3708 bb.addClass('fl-slideshow-overlay'); 3709 }, 3710 3711 /** 3712 * @method destructor 3713 * @protected 3714 */ 3715 destructor: function() 3716 { 3717 this._hideTimerCancel(); 3718 }, 3719 3720 /** 3721 * Binds the mouseenter and mouseleave events for setting focus. 3722 * 3723 * @method _initFocus 3724 * @protected 3725 */ 3726 _initFocus: function() 3727 { 3728 var bb = this.get('host').get('boundingBox'); 3729 bb.on('mouseenter', Y.bind(this._setFocusOnMouseenter, this)); 3730 bb.on('mouseleave', Y.bind(this._setFocusOnMouseleave, this)); 3731 }, 3732 3733 /** 3734 * Sets the initial visibility of the host's bounding box. 3735 * 3736 * @method _initVisibility 3737 * @protected 3738 */ 3739 _initVisibility: function() 3740 { 3741 var bb = this.get('host').get('boundingBox'), 3742 hideStyle = this.get('hideStyle'); 3743 3744 if(!this.get('visible')) { 3745 3746 if(hideStyle == 'display') { 3747 bb.setStyle('display', 'none'); 3748 } 3749 else if(hideStyle == 'left') { 3750 bb.setStyle('left', '-99999px'); 3751 } 3752 3753 bb.setStyle('opacity', '0'); 3754 this._visible = false;
3755 } 3756 }, 3757 3758 /** 3759 * Creates and inserts the close button. 3760 * 3761 * @method _initCloseButton 3762 * @protected 3763 */ 3764 _initCloseButton: function() 3765 { 3766 var bb = this.get('host').get('boundingBox'), 3767 closeButton = null; 3768 3769 closeButton = Y.Node.create('<a class="fl-slideshow-overlay-close" href="javascript:void(0);"></a>'); 3770 closeButton.on('click', Y.bind(this._closeButtonClick, this)); 3771 3772 if(typeof YUI.Env.mods['sm-fonticon'] !== 'undefined') { 3773 closeButton.addClass('sm-fonticon sm-fonticon-XCrossEncircled sm-button-skin-default sm-button-nochrome'); 3774 } 3775 3776 bb.insert(closeButton); 3777 }, 3778 3779 /** 3780 * Hides the overlay when the close button is clicked. 3781 * 3782 * @method _closeButtonClick 3783 * @protected 3784 */ 3785 _closeButtonClick: function() 3786 { 3787 var bb = this.get('host').get('boundingBox'); 3788 bb.transition(this._hideProps, Y.bind(this._hideComplete, this)); 3789 }, 3790 3791 /** 3792 * Sets the focus flag to true. 3793 * 3794 * @method _setFocusOnMouseenter 3795 * @protected 3796 */ 3797 _setFocusOnMouseenter: function() 3798 { 3799 this._focus = true; 3800 }, 3801 3802 /** 3803 * Sets the focus flag to false. 3804 * 3805 * @method _setFocusOnMouseleave 3806 * @protected 3807 */ 3808 _setFocusOnMouseleave: function() 3809 { 3810 this._focus = false; 3811 }, 3812 3813 /** 3814 * Disables show and hide functionality. 3815 * 3816 * @method disable 3817 * @public 3818 */ 3819 disable: function() 3820 { 3821 this._disabled = true; 3822 }, 3823 3824 /** 3825 * Enables show and hide functionality. 3826 * 3827 * @method enable 3828 * @public 3829 */ 3830 enable: function() 3831 { 3832 this._disabled = false; 3833 }, 3834 3835 /** 3836 * Shows the host's bounding box with a fade in transition. 3837 * 3838 * @method show 3839 * @public 3840 */ 3841 show: function() 3842 { 3843 var bb = this.get('host').get('boundingBox'), 3844 hideStyle = this.get('hideStyle'); 3845 3846 if(this._disabled) { 3847 return; 3848 } 3849 3850 if(hideStyle == 'display') { 3851 bb.setStyle('display', 'block'); 3852 } 3853 else if(hideStyle == 'left') { 3854 bb.setStyle('left', 'auto'); 3855 } 3856 3857 bb.transition(this._showProps, Y.bind(this._showComplete, this)); 3858 3859 /** 3860 * @event hideStart 3861 */ 3862 this.fire('showStart'); 3863 }, 3864 3865 /** 3866 * @method _showComplete 3867 * @protected 3868 */ 3869 _showComplete: function() 3870 { 3871 this._visible = true; 3872 this.hideWithTimer(); 3873 3874 /** 3875 * @event showComplete 3876 */ 3877 this.fire('showComplete'); 3878 }, 3879 3880 /** 3881 * Hides the host's bounding box with a fade out transition. 3882 * 3883 * @method hide 3884 * @public 3885 */ 3886 hide: function() 3887 { 3888 if(this._focus || this._disabled) { 3889 return; 3890 } 3891 3892 var bb = this.get('host').get('boundingBox'); 3893 bb.transition(this._hideProps, Y.bind(this._hideComplete, this)); 3894 3895 /** 3896 * @event hideStart 3897 */ 3898 this.fire('hideStart'); 3899 }, 3900 3901 /** 3902 * Hides the host's bounding box with a fade out transition 3903 * after a timer completes. 3904 * 3905 * @method hideWithTimer 3906 * @public 3907 */ 3908 hideWithTimer: function() 3909 { 3910 this._hideTimerCancel(); 3911 this._hideTimer = Y.later(this.get('hideDelay'), this, this.hide); 3912 }, 3913 3914 /** 3915 * Cancels the hide timer. 3916 * 3917 * @method _hideTimerCancel 3918 * @protected 3919 */ 3920 _hideTimerCancel: function() 3921 { 3922 if(this._hideTimer) { 3923 this._hideTimer.cancel(); 3924 this._hideTimer = null; 3925 } 3926 }, 3927 3928 /** 3929 * @method _hideComplete 3930 * @protected 3931 */ 3932 _hideComplete: function() 3933 { 3934 var bb = this.get('host').get('boundingBox'), 3935 hideStyle = this.get('hideStyle'); 3936 3937 if(hideStyle == 'display') { 3938 bb.setStyle('display', 'none'); 3939 } 3940 else if(hideStyle == 'left') { 3941 bb.setStyle('left', '-99999px'); 3942 } 3943 3944 this._visible = false; 3945 3946 /** 3947 * @event hideComplete 3948 */ 3949 this.fire('hideComplete'); 3950 } 3951 3952}, { 3953 3954 /** 3955 * Namespace for the plugin. 3956 * 3957 * @property NS
3958 * @type String 3959 * @protected 3960 * @static 3961 */ 3962 NS: 'slideshowOverlay', 3963 3964 /** 3965 * Static property used to define the default attribute configuration of 3966 * the plugin. 3967 * 3968 * @property ATTRS 3969 * @type Object 3970 * @protected 3971 * @static 3972 */ 3973 ATTRS: { 3974 3975 /** 3976 * Whether to use the close button or not. 3977 * 3978 * @attribute closeButton 3979 * @type Boolean 3980 * @default false 3981 * @writeOnce 3982 */ 3983 closeButton: { 3984 value: false, 3985 writeOnce: true 3986 }, 3987 3988 /** 3989 * The time to wait before hiding the host's bounding box. 3990 * Measured in milliseconds. 3991 * 3992 * @attribute hideDelay 3993 * @type Number 3994 * @default 3000 3995 * @writeOnce 3996 */ 3997 hideDelay: { 3998 value: 3000, 3999 writeOnce: true 4000 }, 4001 4002 /** 4003 * The style to use for hiding the image. Possible 4004 * values are display and left. 4005 * 4006 * @attribute hideStyle 4007 * @type String 4008 * @default display 4009 * @writeOnce 4010 */ 4011 hideStyle: { 4012 value: 'display', 4013 writeOnce: true 4014 }, 4015 4016 /** 4017 * Sets the initial visibility of the host's boudning box. 4018 * 4019 * @attribute visible 4020 * @type Boolean 4021 * @default true 4022 * @writeOnce 4023 */ 4024 visible: { 4025 value: true, 4026 writeOnce: true 4027 } 4028 } 4029}); 4030 4031/** 4032 * Social buttons widget used in slideshows. 4033 * 4034 * @namespace FL 4035 * @class SlideshowSocial 4036 * @constructor 4037 * @param config {Object} Configuration object 4038 * @extends Widget 4039 */ 4040 4041Y.namespace('FL').SlideshowSocial = Y.Base.create('fl-slideshow-social', Y.Widget, [Y.WidgetChild], { 4042 4043 /** 4044 * An object containing the social button nodes. 4045 * 4046 * @property _buttons 4047 * @type Object 4048 * @default null 4049 * @protected 4050 */ 4051 _buttons: null, 4052 4053 /** 4054 * @method renderUI 4055 * @protected 4056 */ 4057 renderUI: function() 4058 { 4059 this._buttons = {}; 4060 }, 4061 4062 /** 4063 * @method bindUI 4064 * @protected 4065 */ 4066 bindUI: function() 4067 { 4068 var root = this.get('root'); 4069 4070 if(root.get('likeButtonEnabled')) { 4071 root.on('imageLoadComplete', Y.bind(this._updateLikeButton, this)); 4072 } 4073 if(root.get('tweetButtonEnabled')) { 4074 root.on('imageLoadComplete', Y.bind(this._updateTweetButton, this)); 4075 } 4076 if(root.get('pinterestButtonEnabled')) { 4077 root.on('imageLoadComplete', Y.bind(this._updatePinterestButton, this)); 4078 } 4079 }, 4080 4081 /** 4082 * @method _updateLikeButton 4083 * @protected 4084 */ 4085 _updateLikeButton: function() 4086 { 4087 var src = null, 4088 cb = this.get('contentBox'), 4089 root = this.get('root'), 4090 albumIndex = root.albumIndex, 4091 rootSource = root.get('source')[albumIndex], 4092 imageInfo = root.imageInfo; 4093 4094 if(this._buttons.like) { 4095 this._buttons.like.remove(); 4096 this._buttons.like = null; 4097 } 4098 4099 if(rootSource.type == 'smugmug') { 4100 src = 'https://www.facebook.com/plugins/like.php?'; 4101 src += 'href=' + 'https://www.smugmug.com/services/graph/gallery/'; 4102 src += rootSource.id + '_' + rootSource.key +'/' + imageInfo.id + '_' + imageInfo.key; 4103 } 4104 else { 4105 src = 'https://www.facebook.com/plugins/like.php?'; 4106 src += 'href=' + encodeURIComponent(imageInfo.largeURL); 4107 } 4108 4109 src += '&send=false'; 4110 src += '&layout=button_count'; 4111 src += '&width=90'; 4112 src += '&show_faces=false'; 4113 src += '&action=like'; 4114 src += '&colorscheme=light'; 4115 src += '&height=21'; 4116 4117 this._buttons.like = Y.Node.create('<iframe src="'+ src +'" scrolling="no" allowTransparency="true"></iframe>'); 4118 4119 this._buttons.like.setStyles({ 4120 overflow: 'hidden', 4121 width: '90px', 4122 height: '21px' 4123 }); 4124 4125 cb.appendChild(this._buttons.like); 4126 }, 4127 4128 /** 4129 * @method _updateTweetButton 4130 * @protected 4131 */ 4132 _updateTweetButton: function() 4133 { 4134 var src = null, 4135 imageInfo = this.get('root').imageInfo, 4136 cb = this.get('contentBox'); 4137 4138 if(this._buttons.tweet) { 4139 this._buttons.tweet.remove(); 4140 this._buttons.tweet = null; 4141 } 4142 4143 src = 'https://platform.twitter.com/widgets/tweet_button.html?'; 4144 src += 'url=' + encodeURIComponent(imageInfo.largeURL); 4145 src += '&count=none'; 4146 4147 this._buttons.tweet = Y.Node.create('<iframe src="'+ src +'" scrolling="no" allowTransparency="true"></iframe>'); 4148 4149 this._buttons.tweet.setStyles({ 4150 overflow: 'hidden', 4151 width: '90px', 4152 height: '21px' 4153 }); 4154 4155 cb.appendChild(this._buttons.tweet); 4156 }, 4157 4158 /** 4159 * @method _updatePinterestButton 4160 * @protected 4161 */ 4162 _updatePinterestButton: function() 4163 { 4164 var href = 'https://pinterest.com/pin/create/button/', 4165 imageInfo = this.get('root').imageInfo, 4166 cb = this.get('contentBox'); 4167 4168 if(this._buttons.pin) { 4169 this._buttons.pin.remove(); 4170 this._buttons.pin = null; 4171 } 4172 4173 href += '?url=' + encodeURIComponent(window.location.href); 4174 href += '&media='+ encodeURIComponent(imageInfo.mediumURL); 4175 href += '&description='+ encodeURIComponent(imageInfo.caption); 4176 4177 this._buttons.pin = Y.Node.create('<a></a>'); 4178 this._buttons.pin.setAttribute('data-pin-config', 'none'); 4179 this._buttons.pin.setAttribute('data-pin-do', 'buttonPin'); 4180 this._buttons.pin.setAttribute('href', href); 4181 this._buttons.pin.setAttribute('target', '_blank'); 4182 this._buttons.pin.set('innerHTML', '<img src="https://assets.pinterest.com/images/pidgets/pin_it_button.png" border="0" />'); 4183 4184 cb.appendChild(this._buttons.pin); 4185 } 4186 4187}, { 4188 4189 /** 4190 * Custom CSS class name for the widget. 4191 * 4192 * @property CSS_PREFIX
4193 * @type String 4194 * @protected 4195 * @static 4196 */ 4197 CSS_PREFIX: 'fl-slideshow-social', 4198 4199 /** 4200 * Static property used to define the default attribute configuration of 4201 * the Widget. 4202 * 4203 * @property ATTRS 4204 * @type Object 4205 * @protected 4206 * @static 4207 */ 4208 ATTRS: { 4209 4210 } 4211}); 4212 4213/** 4214 * Creates a grid of FL.SlideshowImage instances. 4215 * 4216 * @namespace FL 4217 * @class SlideshowThumbs 4218 * @constructor 4219 * @param config {Object} Configuration object 4220 * @extends Widget 4221 */ 4222Y.namespace('FL').SlideshowThumbs = Y.Base.create('fl-slideshow-thumbs', Y.Widget, [Y.WidgetParent, Y.WidgetChild], { 4223 4224 /** 4225 * A div node used to hide the overflow when 4226 * transitioning between pages. 4227 * 4228 * @property _clipBox 4229 * @type Object 4230 * @default null 4231 * @protected 4232 */ 4233 _clipBox: null, 4234 4235 /** 4236 * A div node used to hold the pages. 4237 * 4238 * @property _pagesBox 4239 * @type Object 4240 * @default null 4241 * @protected 4242 */ 4243 _pagesBox: null, 4244 4245 /** 4246 * A reference to the active page div node. Holds a grid 4247 * of FL.SlideshowImage instances. 4248 * 4249 * @property _activePageBox 4250 * @type Object 4251 * @default null 4252 * @protected 4253 */ 4254 _activePageBox: null, 4255 4256 /** 4257 * The index of the active page of thumbs. 4258 * 4259 * @property _activePageIndex 4260 * @type Number 4261 * @default 0 4262 * @protected 4263 */ 4264 _activePageIndex: 0, 4265 4266 /** 4267 * A reference to the next page div node. Holds a grid 4268 * of FL.SlideshowImage instances. 4269 * 4270 * @property _nextPageBox 4271 * @type Object 4272 * @default null 4273 * @protected 4274 */ 4275 _nextPageBox: null, 4276 4277 /** 4278 * An array of FL.SlideshowImage instances in the active page. 4279 * 4280 * @property _activeImages 4281 * @type Array 4282 * @default null 4283 * @protected 4284 */ 4285 _activeImages: null, 4286 4287 /** 4288 * An array of FL.SlideshowImage instances used to 4289 * preload the next page of images. 4290 * 4291 * @property _nextImages 4292 * @type Array 4293 * @default null 4294 * @protected 4295 */ 4296 _nextImages: null, 4297 4298 /** 4299 * An array of FL.SlideshowImage instances used to 4300 * preload the previous page of images. 4301 * 4302 * @property _prevImages 4303 * @type Array 4304 * @default null 4305 * @protected 4306 */ 4307 _prevImages: null, 4308 4309 /** 4310 * An instance of FL.SlideshowNav used for the left nav. 4311 * 4312 * @property _leftNav 4313 * @type Object 4314 * @default null 4315 * @protected 4316 */ 4317 _leftNav: null, 4318 4319 /** 4320 * An instance of FL.SlideshowNav used for the right nav. 4321 * 4322 * @property _rightNav 4323 * @type Object 4324 * @default null 4325 * @protected 4326 */ 4327 _rightNav: null, 4328 4329 /** 4330 * An instance of FL.SlideshowNav used for the top nav. 4331 * 4332 * @property _topNav 4333 * @type Object 4334 * @default null 4335 * @protected 4336 */ 4337 _topNav: null, 4338 4339 /** 4340 * An instance of FL.SlideshowNav used for the bottom nav. 4341 * 4342 * @property _bottomNav 4343 * @type Object 4344 * @default null 4345 * @protected 4346 */ 4347 _bottomNav: null, 4348 4349 /** 4350 * Height of the bounding box. 4351 * 4352 * @property _bbHeight 4353 * @type Number 4354 * @default 0 4355 * @protected 4356 */ 4357 _bbHeight: 0, 4358 4359 /** 4360 * Width of the bounding box. 4361 * 4362 * @property _bbWidth 4363 * @type Number 4364 * @default 0 4365 * @protected 4366 */ 4367 _bbWidth: 0, 4368 4369 /** 4370 * Width of the content box. 4371 * 4372 * @property _cbWidth 4373 * @type Number 4374 * @default 0 4375 * @protected 4376 */ 4377 _cbWidth: 0, 4378 4379 /** 4380 * Left margin of the clip box. 4381 * 4382 * @property _clipBoxMarginLeft 4383 * @type Number 4384 * @default 0 4385 * @protected 4386 */ 4387 _clipBoxMarginLeft: 0, 4388 4389 /** 4390 * Top position of the clip box. 4391 * 4392 * @property _clipBoxTop 4393 * @type Number 4394 * @default 0 4395 * @protected 4396 */ 4397 _clipBoxTop: 0, 4398 4399 /** 4400 * The number of columns per page. 4401 * 4402 * @property _colsPerPage 4403 * @type Number 4404 * @default 0 4405 * @protected 4406 */ 4407 _colsPerPage: 0, 4408 4409 /** 4410 * The number of rows per page. 4411 * 4412 * @property _rowsPerPage 4413 * @type Number 4414 * @default 0 4415 * @protected 4416 */ 4417 _rowsPerPage: 0, 4418 4419 /** 4420 * The number of images per page. 4421 * 4422 * @property _imagesPerPage 4423 * @type Number 4424 * @default 0 4425 * @protected 4426 */ 4427 _imagesPerPage: 0, 4428 4429 /** 4430 * The number of pages. 4431 * 4432 * @property _numPages 4433 * @type Number 4434 * @default 0 4435 * @protected 4436 */ 4437 _numPages: 0, 4438 4439 /** 4440 * Height of the pages. 4441 * 4442 * @property _pageHeight 4443 * @type Number 4444 * @default 0 4445 * @protected 4446 */ 4447 _pageHeight: 0, 4448 4449 /** 4450 * Width of the pages. 4451 * 4452 * @property _pageWidth 4453 * @type Number 4454 * @default 0 4455 * @protected 4456 */ 4457 _pageWidth: 0, 4458 4459 /** 4460 * The horizontal spacing between thumbs. 4461 * 4462 * @property _horizontalSpacing 4463 * @type Number 4464 * @default 0 4465 * @protected 4466 */ 4467 _horizontalSpacing: 0, 4468 4469 /** 4470 * The vertical spacing between thumbs. 4471 * 4472 * @property _verticalSpacing 4473 * @type Number 4474 * @default 0 4475 * @protected 4476 */ 4477 _verticalSpacing: 0, 4478 4479 /** 4480 * Width of the left nav. 4481 * 4482 * @property _leftNavWidth 4483 * @type Number 4484 * @default 0 4485 * @protected 4486 */ 4487 _leftNavWidth: 0, 4488 4489 /** 4490 * Width of the right nav. 4491 * 4492 * @property _rightNavWidth 4493 * @type Number 4494 * @default 0 4495 * @protected 4496 */ 4497 _rightNavWidth: 0, 4498 4499 /** 4500 * An instance of FL.SlideshowTransition for the current transition. 4501 * 4502 * @property _transition 4503 * @type FL.SlideshowTransition 4504 * @default null 4505 * @protected 4506 */ 4507 _transition: null, 4508 4509 /** 4510 * Whether the pages are currently transitioning or not. 4511 * 4512 * @property _verticalSpacing 4513 * @type Boolean 4514 * @default false 4515 * @protected 4516 */ 4517 _transitioning: false, 4518 4519 /** 4520 * Direction of the current transition. 4521 * 4522 * @property _transitionDirection
4523 * @type String 4524 * @default next 4525 * @protected 4526 */ 4527 _transitionDirection: 'next', 4528 4529 /** 4530 * Provides functionality for gesture based transitions 4531 * between the active and next pages. 4532 * 4533 * @property _gestures 4534 * @type FL.SlideshowGestures 4535 * @default null 4536 * @protected 4537 */ 4538 _gestures: null, 4539 4540 /** 4541 * Initialize image vars. 4542 * 4543 * @method initializer 4544 * @protected 4545 */ 4546 initializer: function() 4547 { 4548 this._activeImages = []; 4549 this._nextImages = []; 4550 this._prevImages = []; 4551 }, 4552 4553 /** 4554 * Renders the UI boxes. 4555 * 4556 * @method renderUI 4557 * @protected 4558 */ 4559 renderUI: function() 4560 { 4561 this._renderBoxes(); 4562 this._renderNavs(); 4563 }, 4564 4565 /** 4566 * Binds the UI events. 4567 * 4568 * @method bindUI 4569 * @protected 4570 */ 4571 bindUI: function() 4572 { 4573 var root = this.get('root'), 4574 id = this.get('id'), 4575 transition = this.get('transition'); 4576 4577 root.on(id + '|albumLoadComplete', this._albumLoadComplete, this); 4578 4579 if('ontouchstart' in window && this.get('touchSupport')) { 4580 4581 this._gestures = new Y.FL.SlideshowGestures({ 4582 direction: transition == 'slideVertical' ? 'vertical' : 'horizontal', 4583 activeItem: this._activePageBox, 4584 nextItem: this._nextPageBox 4585 }); 4586 4587 this._gestures.on('moveStart', this._gesturesMoveStart, this); 4588 this._gestures.on('endComplete', this._gesturesEndComplete, this); 4589 } 4590 }, 4591 4592 /** 4593 * Syncs the UI boxes. 4594 * 4595 * @method syncUI 4596 * @protected 4597 */ 4598 syncUI: function() 4599 { 4600 this._syncBoxes(); 4601 this._syncNavs(); 4602 }, 4603 4604 /** 4605 * @method destructor 4606 * @protected 4607 */ 4608 destructor: function() 4609 { 4610 var root = this.get('root'), 4611 id = this.get('id'); 4612 4613 root.detach(id + '|*'); 4614 4615 Y.FL.SlideshowImageLoader.removeGroup('thumbs'); 4616 }, 4617 4618 /** 4619 * Unload all images. 4620 * 4621 * @method unload 4622 */ 4623 unload: function() 4624 { 4625 var root = this.get('root'), 4626 id = this.get('id'), 4627 i = 0; 4628 4629 root.detach(id + '|imageLoadComplete'); 4630 4631 Y.FL.SlideshowImageLoader.removeGroup('thumbs'); 4632 4633 for( ; i < this._activeImages.length; i++) { 4634 this._activeImages[i].unload(); 4635 } 4636 }, 4637 4638 /** 4639 * Resizes the UI boxes. 4640 * 4641 * @method resize 4642 */ 4643 resize: function() 4644 { 4645 this._setSizeInfo(); 4646 this._togglePageButtons(); 4647 this._resizeBoxes(); 4648 this._resizeNavs(); 4649 4650 if(this.get('root').albumInfo) { 4651 Y.FL.SlideshowImageLoader.removeGroup('thumbs'); 4652 this._renderActivePage(); 4653 this._preloadNextPage(); 4654 this._preloadPrevPage(); 4655 } 4656 4657 // Enable or disable gestures. 4658 if(this._gestures && this._numPages < 2) { 4659 this._gestures.disable(); 4660 } 4661 else if(this._gestures) { 4662 this._gestures.enable(); 4663 } 4664 }, 4665 4666 /** 4667 * Transitions to the previous page. 4668 * 4669 * @method prevPage 4670 * @protected 4671 */ 4672 prevPage: function() 4673 { 4674 if(this._transitioning) { 4675 return; 4676 } 4677 4678 this._transitionStart('prev'); 4679 }, 4680 4681 /** 4682 * Transitions to the next page. 4683 * 4684 * @method nextPage 4685 * @protected 4686 */ 4687 nextPage: function() 4688 { 4689 if(this._transitioning) { 4690 return; 4691 } 4692 4693 this._transitionStart('next'); 4694 }, 4695 4696 /** 4697 * Called when an album is loaded into the root slideshow widget. 4698 * 4699 * @method _albumLoadComplete 4700 * @protected 4701 */ 4702 _albumLoadComplete: function() 4703 { 4704 var root = this.get('root'), 4705 id = this.get('id'); 4706 4707 root.once(id + '|imageLoadComplete', this.resize, this); 4708 root.on(id + '|imageLoadComplete', this._imageLoadComplete, this); 4709 }, 4710 4711 /** 4712 * Called when an image is loaded into the root slideshow widget. 4713 * 4714 * @method _imageLoadComplete 4715 * @protected 4716 */ 4717 _imageLoadComplete: function() 4718 { 4719 var albumInfo = this.get('root').albumInfo, 4720 lastActive = Y.one('.fl-slideshow-image-active'), 4721 lastInfo = lastActive ? lastActive._imageInfo : null, 4722 nextActive = null, 4723 nextInfo = this.get('root').imageInfo; 4724 4725 this._setActiveImage(this._activeImages); 4726 4727 nextActive = Y.one('.fl-slideshow-image-active'); 4728 4729 if(lastActive && !nextActive) { 4730 if(nextInfo.index === 0 && lastInfo.index === albumInfo.images.length - 1) { 4731 this.nextPage(); 4732 } 4733 else if(lastInfo.index === 0 && nextInfo.index === albumInfo.images.length - 1) { 4734 this.prevPage(); 4735 } 4736 else if(lastInfo.index < nextInfo.index) { 4737 this.nextPage(); 4738 } 4739 else if(lastInfo.index > nextInfo.index) { 4740 this.prevPage(); 4741 } 4742 } 4743 }, 4744 4745 /** 4746 * Renders the boxes. 4747 * 4748 * @method _renderBoxes 4749 * @protected 4750 */ 4751 _renderBoxes: function() 4752 { 4753 // Clip box 4754 this._clipBox = Y.Node.create('<div></div>'); 4755 this._clipBox.addClass('fl-slideshow-thumbs-clip'); 4756 this.get('contentBox').insert(this._clipBox); 4757 4758 // Pages box 4759 this._pagesBox = Y.Node.create('<div></div>'); 4760 this._pagesBox.addClass('fl-slideshow-thumbs-pages'); 4761 this._clipBox.insert(this._pagesBox); 4762 4763 // Active page box 4764 this._activePageBox = Y.Node.create('<div></div>'); 4765 this._activePageBox.addClass('fl-slideshow-thumbs-page'); 4766 this._pagesBox.insert(this._activePageBox); 4767 4768 // Next page box 4769 this._nextPageBox = Y.Node.create('<div></div>'); 4770 this._nextPageBox.addClass('fl-slideshow-thumbs-page'); 4771 this._pagesBox.insert(this._nextPageBox); 4772 }, 4773 4774 /** 4775 * Syncs the boxes. 4776 * 4777 * @method _syncBoxes 4778 * @protected 4779 */ 4780 _syncBoxes: function() 4781 { 4782 // Active page box 4783 this._activePageBox.setStyle('left', '0'); 4784 4785 // Next page box 4786 this._nextPageBox.setStyle('left', '-9999px'); 4787 }, 4788 4789 /** 4790 * Resizes the boxes. 4791 * 4792 * @method _resizeBoxes 4793 * @protected 4794 */ 4795 _resizeBoxes: function() 4796 { 4797 this.set('width', this._bbWidth); 4798 this.set('height', this._bbHeight); 4799 4800 this.get('contentBox').setStyle('width', this._cbWidth + 'px'); 4801 4802 this._clipBox.setStyle('width', this._pageWidth + 'px'); 4803 this._clipBox.setStyle('height', this._pageHeight + 'px'); 4804 this._clipBox.setStyle('padding', this._verticalSpacing + 'px 0 0 ' + this._horizontalSpacing + 'px '); 4805 this._clipBox.setStyle('margin', '0 0 0 ' + this._clipBoxMarginLeft + 'px'); 4806 this._clipBox.setStyle('top', this._clipBoxTop); 4807 4808 this._pagesBox.setStyle('width', this._pageWidth + 'px'); 4809 this._pagesBox.setStyle('height', this._pageHeight + 'px'); 4810 4811 this._activePageBox.setStyle('width', this._pageWidth + 'px'); 4812 this._activePageBox.setStyle('height', this._pageHeight + 'px'); 4813 4814 this._nextPageBox.setStyle('width', this._pageWidth + 'px'); 4815 this._nextPageBox.setStyle('height', this._pageHeight + 'px'); 4816 }, 4817 4818 /** 4819 * Renders the active page of images. 4820 * 4821 * @method _renderActivePage 4822 * @protected 4823 */ 4824 _renderActivePage: function() 4825 { 4826 var i = 0, 4827 root = this.get('root'), 4828 imageIndex = this._imagesPerPage * this._activePageIndex, 4829 endIndex = imageIndex + this._imagesPerPage, 4830 images = root.albumInfo.images; 4831 4832 this._clearActiveImage(); 4833 4834 // Remove current images 4835 for( ; i < this._activeImages.length; i++) { 4836 this._activeImages[i].remove(); 4837 this._activeImages[i].unload(); 4838 this._activeImages[i].get('boundingBox')._imageInfo = null; 4839 this._activeImages[i].get('boundingBox').remove(); 4840 } 4841 4842 // Draw images 4843 for(i = 0; imageIndex < endIndex; imageIndex++) { 4844 4845 if(!images[imageIndex]) { 4846 break; 4847 } 4848 4849 this._renderImage(this._activeImages, i, this._activePageBox, images[imageIndex]); 4850 i++; 4851 } 4852 4853 this._setActiveImage(this._activeImages); 4854 }, 4855 4856 /** 4857 * Renders the next page of images. 4858 * 4859 * @method _renderNextPage 4860 * @protected 4861 */ 4862 _renderNextPage: function() 4863 { 4864 var i = 0, 4865 imageArray = this._transitionDirection == 'next' ? this._nextImages : this._prevImages; 4866 4867 this._nextPageBox.get('children').remove(); 4868 4869 for( ; i < imageArray.length; i++) { 4870 if(imageArray[i]._imageInfo) { 4871 this._renderImage(imageArray, i, this._nextPageBox, imageArray[i]._imageInfo); 4872 } 4873 else { 4874 break; 4875 } 4876 } 4877 4878 this._setActiveImage(imageArray); 4879 }, 4880 4881 /** 4882 * Preloads the next page of images. 4883 * 4884 * @method _preloadNextPage 4885 * @protected 4886 */ 4887 _preloadNextPage: function() 4888 { 4889 var pageIndex = this._activePageIndex + 1 >= this._numPages ? 0 : this._activePageIndex + 1; 4890 4891 this._preloadPage(pageIndex, this._nextImages); 4892 }, 4893 4894 /** 4895 * Preloads the previous page of images. 4896 * 4897 * @method _preloadPrevPage 4898 * @protected 4899 */ 4900 _preloadPrevPage: function() 4901 { 4902 var pageIndex = this._activePageIndex - 1 < 0 ? this._numPages - 1 : this._activePageIndex - 1; 4903 4904 this._preloadPage(pageIndex, this._prevImages); 4905 }, 4906 4907 /** 4908 * Preloads a page of images. 4909 * 4910 * @method _preloadPage 4911 * @param imageIndex {Number} The image index to start preloading from. 4912 * @param imageArray {Array} The array to store the preloaded images. 4913 * @protected 4914 */ 4915 _preloadPage: function(pageIndex, imageArray) 4916 { 4917 var i = 0, 4918 root = this.get('root'), 4919 images = root.albumInfo.images, 4920 imageIndex = pageIndex * this._imagesPerPage, 4921 endIndex = imageIndex + this._imagesPerPage, 4922 imageConfig = this.get('imageConfig'), 4923 width = imageConfig.width, 4924 height = imageConfig.height; 4925 4926 if(this._numPages > 1) { 4927 4928 // Unload existing images 4929 for( ; i < imageArray.length; i++) { 4930 imageArray[i].remove(); 4931 imageArray[i].unload(); 4932 } 4933 4934 // Preload the images 4935 for(i = 0; imageIndex < endIndex; imageIndex++) { 4936 4937 if(!images[imageIndex]) { 4938 continue; 4939 } 4940 4941 this._renderImage(imageArray, i); 4942 imageArray[i].preload(images[imageIndex], width, height); 4943 i++; 4944 } 4945 } 4946 }, 4947 4948 /** 4949 * Renders an image. 4950 * 4951 * @method _renderImage 4952 * @protected 4953 */ 4954 _renderImage: function(imageArray, i, page, imageInfo) 4955 { 4956 var imageBB = null, 4957 imageConfig = this.get('imageConfig'); 4958 4959 // Create the image? 4960 if(typeof imageArray[i] == 'undefined') { 4961 imageConfig.loadGroup = 'thumbs'; 4962 imageConfig.useThumbSizes = true; 4963 imageConfig.loadVideos = false;
4964 imageArray[i] = new Y.FL.SlideshowImage(imageConfig); 4965 imageBB = imageArray[i].get('boundingBox'); 4966 imageBB.on('click', this._imageClick, this); 4967 imageBB.on('mouseover', this._imageMouseover, this); 4968 imageBB.on('mouseout', this._imageMouseout, this); 4969 } 4970 4971 // Image bounding box 4972 imageBB = imageArray[i].get('boundingBox'); 4973 imageBB.setStyle('margin', '0 ' + this._horizontalSpacing + 'px ' + this._verticalSpacing + 'px 0'); 4974 4975 // Add the image to a page? 4976 if(page) { 4977 this._childrenContainer = page; 4978 this.add(imageArray[i]); 4979 imageArray[i].resize(imageConfig.width, imageConfig.height); 4980 } 4981 4982 // Load the image? 4983 if(imageInfo) { 4984 imageArray[i].load(imageInfo); 4985 imageBB._imageInfo = imageInfo; 4986 } 4987 }, 4988 4989 /** 4990 * Overrides the WidgetParent _uiAddChild method so _renderImage 4991 * will render to the appropriate page. 4992 * 4993 * @method _uiAddChild 4994 * @protected 4995 * @param child {Widget} The child Widget instance to render. 4996 * @param parentNode {Object} The Node under which the 4997 * child Widget is to be rendered. Set to the appropriate page 4998 * in the _renderImage method by setting _childrenContainer. 4999 */ 5000 _uiAddChild: function (child, parentNode) 5001 { 5002 child.render(parentNode); 5003 parentNode.appendChild(child.get('boundingBox')); 5004 }, 5005 5006 /** 5007 * Called when an image is clicked. 5008 * 5009 * @method _imageClick 5010 * @protected 5011 */ 5012 _imageClick: function(e) 5013 { 5014 var root = this.get('root'); 5015 5016 if(this.get('pauseOnClick')) { 5017 root.pause(); 5018 } 5019 5020 root.loadImage(e.currentTarget._imageInfo.index); 5021 5022 /** 5023 * Fires when an image is clicked. 5024 * 5025 * @event imageClick 5026 */ 5027 this.fire('imageClick'); 5028 }, 5029 5030 /** 5031 * Sets the active image. 5032 * 5033 * @method _setActiveImage 5034 * @param imageArray {Array} The image array to check for the active image. 5035 * @protected 5036 */ 5037 _setActiveImage: function(imageArray) 5038 { 5039 var i = 0; 5040 5041 this._clearActiveImage(); 5042 5043 for( ; i < imageArray.length; i++) { 5044 if(imageArray[i]._imageInfo) { 5045 if(imageArray[i]._imageInfo.index == this.get('root').imageInfo.index) { 5046 imageArray[i].get('boundingBox').addClass('fl-slideshow-image-active'); 5047 break; 5048 } 5049 } 5050 } 5051 }, 5052 5053 /** 5054 * Removes the class name 'fl-slideshow-image-active' 5055 * from the active image. 5056 * 5057 * @method _clearActiveImage 5058 * @protected 5059 */ 5060 _clearActiveImage: function() 5061 { 5062 var active = Y.one('.fl-slideshow-image-active'); 5063 5064 if(active) { 5065 active.removeClass('fl-slideshow-image-active'); 5066 } 5067 }, 5068 5069 /** 5070 * Gets the transition type. 5071 * 5072 * @method _getTransition 5073 * @protected 5074 */ 5075 _getTransition: function() 5076 { 5077 var transition = this.get('transition'); 5078 5079 if(transition == 'slideHorizontal' && this._transitionDirection == 'next') { 5080 return 'slideLeft'; 5081 } 5082 else if(transition == 'slideHorizontal' && this._transitionDirection == 'prev') { 5083 return 'slideRight'; 5084 } 5085 else if(transition == 'slideVertical' && this._transitionDirection == 'next') { 5086 return 'slideUp'; 5087 } 5088 else if(transition == 'slideVertical' && this._transitionDirection == 'prev') { 5089 return 'slideDown'; 5090 } 5091 5092 return transition; 5093 }, 5094 5095 /** 5096 * Starts the transition, moving in the provided direction. 5097 * 5098 * @method _transitionStart 5099 * @param direction {String} The direction to transition. 5100 * @protected 5101 */ 5102 _transitionStart: function(direction) 5103 { 5104 if(this._numPages > 1) { 5105 5106 Y.FL.SlideshowImageLoader.removeGroup('thumbs'); 5107 5108 this._transitionDirection = direction; 5109 this._transitioning = true; 5110 this._nextPageBox.setStyle('left', '0px'); 5111 this._renderNextPage(); 5112 5113 this._transition = new Y.FL.SlideshowTransition({ 5114 itemIn: this._nextPageBox, 5115 itemOut: this._activePageBox, 5116 type: this._getTransition(), 5117 duration: this.get('transitionDuration'), 5118 easing: this.get('transitionEasing') 5119 }); 5120 5121 this._transition.once('complete', this._transitionComplete, this); 5122 this._transition.run(); 5123 5124 // Disable gestures if set. 5125 if(this._gestures) { 5126 this._gestures.disable(); 5127 } 5128 } 5129 }, 5130 5131 /** 5132 * Transition cleanup called when the current transition ends. 5133 * 5134 * @method _transitionComplete 5135 * @protected 5136 */ 5137 _transitionComplete: function() 5138 { 5139 this._swapPageRefs(); 5140 this._transitioning = false;
5141 this._transitionDirection = ''; 5142 this._transition = null; 5143 5144 // Enable gestures if set. 5145 if(this._gestures) { 5146 this._gestures.enable(); 5147 } 5148 5149 /** 5150 * Fires when a page transition completes. 5151 * 5152 * @event transitionComplete 5153 */ 5154 this.fire('transitionComplete'); 5155 }, 5156 5157 /** 5158 * @method _gesturesMoveStart 5159 * @param e {Object} The event object. 5160 * @protected 5161 */ 5162 _gesturesMoveStart: function(e) 5163 { 5164 Y.FL.SlideshowImageLoader.removeGroup('thumbs'); 5165 5166 this._transitionDirection = e.direction; 5167 this._renderNextPage(); 5168 }, 5169 5170 /** 5171 * @method _gesturesEndComplete 5172 * @protected 5173 */ 5174 _gesturesEndComplete: function() 5175 { 5176 this._swapPageRefs(); 5177 this._transitionDirection = ''; 5178 this.fire('transitionComplete'); 5179 }, 5180 5181 /** 5182 * Swaps the active page and next page references when 5183 * a transition completes and sets the active page index. 5184 * 5185 * @method _swapPageRefs 5186 * @protected 5187 */ 5188 _swapPageRefs: function() 5189 { 5190 var lastBox = this._activePageBox, 5191 lastImages = this._activeImages; 5192 5193 this._activePageBox = this._nextPageBox; 5194 this._nextPageBox = lastBox; 5195 this._nextPageBox.setStyle('left', '-9999px'); 5196 5197 if(this._transitionDirection == 'next') { 5198 this._activeImages = this._nextImages; 5199 this._nextImages = lastImages; 5200 } 5201 else { 5202 this._activeImages = this._prevImages; 5203 this._prevImages = lastImages; 5204 } 5205 5206 // Active page index 5207 if(this._transitionDirection == 'next' && this._activePageIndex + 1 < this._numPages) { 5208 this._activePageIndex++; 5209 } 5210 else if(this._transitionDirection == 'next') { 5211 this._activePageIndex = 0; 5212 } 5213 else if(this._transitionDirection == 'prev' && this._activePageIndex - 1 > -1) { 5214 this._activePageIndex--; 5215 } 5216 else if(this._transitionDirection == 'prev') { 5217 this._activePageIndex = this._numPages - 1; 5218 } 5219 5220 // Swap gesture refs 5221 if(this._gestures) { 5222 this._gestures.set('activeItem', this._activePageBox); 5223 this._gestures.set('nextItem', this._nextPageBox); 5224 } 5225 5226 this._preloadNextPage(); 5227 this._preloadPrevPage(); 5228 }, 5229 5230 /** 5231 * Renders the enabled navs. 5232 * 5233 * @method _renderNavs 5234 * @protected 5235 */ 5236 _renderNavs: function() 5237 { 5238 var topNavButtons = this.get('topNavButtons'), 5239 rightNavButtons = this.get('rightNavButtons'), 5240 bottomNavButtons = this.get('bottomNavButtons'), 5241 leftNavButtons = this.get('leftNavButtons'); 5242 5243 if(this.get('topNavEnabled') && topNavButtons.length > 0) { 5244 this._topNav = new Y.FL.SlideshowNav({ buttons: topNavButtons }); 5245 this._topNav.get('boundingBox').addClass('fl-slideshow-thumbs-top-nav'); 5246 this.add(this._topNav); 5247 this._topNav.render(this.get('contentBox')); 5248 this._clipBox.insert(this._topNav.get('boundingBox'), 'before'); 5249 this._bindNavEvents(this._topNav); 5250 } 5251 if(this.get('rightNavEnabled') && rightNavButtons.length > 0) { 5252 this._rightNav = new Y.FL.SlideshowNav({ buttons: rightNavButtons }); 5253 this._rightNav.get('boundingBox').addClass('fl-slideshow-thumbs-right-nav'); 5254 this.add(this._rightNav); 5255 this._rightNav.render(this.get('contentBox')); 5256 this._bindNavEvents(this._rightNav); 5257 } 5258 if(this.get('bottomNavEnabled') && bottomNavButtons.length > 0) { 5259 this._bottomNav = new Y.FL.SlideshowNav({ buttons: bottomNavButtons }); 5260 this._bottomNav.get('boundingBox').addClass('fl-slideshow-thumbs-bottom-nav'); 5261 this.add(this._bottomNav); 5262 this._bottomNav.render(this.get('contentBox')); 5263 this._bindNavEvents(this._bottomNav); 5264 } 5265 if(this.get('leftNavEnabled') && leftNavButtons.length > 0) { 5266 this._leftNav = new Y.FL.SlideshowNav({ buttons: leftNavButtons }); 5267 this._leftNav.get('boundingBox').addClass('fl-slideshow-thumbs-left-nav'); 5268 this.add(this._leftNav); 5269 this._leftNav.render(this.get('contentBox')); 5270 this._bindNavEvents(this._leftNav); 5271 } 5272 }, 5273 5274 /** 5275 * Syncs the navs. 5276 * 5277 * @method _syncNavs 5278 * @protected 5279 */ 5280 _syncNavs: function() 5281 { 5282 var rightNavBB, bottomNavBB, leftNavBB; 5283 5284 if(this._rightNav) { 5285 rightNavBB = this._rightNav.get('boundingBox'); 5286 rightNavBB.setStyle('position', 'absolute'); 5287 rightNavBB.setStyle('top', '0px'); 5288 rightNavBB.setStyle('right', '0px'); 5289 } 5290 if(this._bottomNav) { 5291 bottomNavBB = this._bottomNav.get('boundingBox'); 5292 bottomNavBB.setStyle('position', 'absolute'); 5293 bottomNavBB.setStyle('bottom', '0px'); 5294 bottomNavBB.setStyle('width', '100%'); 5295 } 5296 if(this._leftNav) { 5297 leftNavBB = this._leftNav.get('boundingBox'); 5298 leftNavBB.setStyle('position', 'absolute'); 5299 leftNavBB.setStyle('top', '0px'); 5300 leftNavBB.setStyle('left', '0px'); 5301 } 5302 }, 5303 5304 /** 5305 * Resizes the navs. 5306 * 5307 * @method _resizeNavs 5308 * @protected 5309 */ 5310 _resizeNavs: function() 5311 { 5312 var rightNavBB, 5313 leftNavBB, 5314 marginTop; 5315 5316 if(this._rightNav) { 5317 rightNavBB = this._rightNav.get('boundingBox'); 5318 marginTop = this._bbHeight/2 - parseInt(rightNavBB.getComputedStyle('height'), 10)/2; 5319 rightNavBB.setStyle('marginTop', marginTop + 'px'); 5320 } 5321 if(this._leftNav) { 5322 leftNavBB = this._leftNav.get('boundingBox'); 5323 marginTop = this._bbHeight/2 - parseInt(leftNavBB.getComputedStyle('height'), 10)/2; 5324 leftNavBB.setStyle('marginTop', marginTop + 'px'); 5325 } 5326 }, 5327 5328 /** 5329 * Binds events to the provided nav. 5330 * 5331 * @method _bindNavEvents 5332 * @param nav {Object} The nav to bind to. 5333 * @protected 5334 */ 5335 _bindNavEvents: function(nav) 5336 { 5337 if(nav._buttons.prevPage) { 5338 nav._buttons.prevPage.on('click', this.prevPage, this); 5339 } 5340 if(nav._buttons.nextPage) { 5341 nav._buttons.nextPage.on('click', this.nextPage, this); 5342 } 5343 5344 nav.on('resize', this.resize, this); 5345 }, 5346 5347 /** 5348 * Hides the prev page and next page buttons 5349 * if there is only one page of thumbs. 5350 * 5351 * @method _togglePageButtons 5352 * @protected 5353 */ 5354 _togglePageButtons: function() 5355 { 5356 var buttons = this.get('boundingBox').all('.fl-slideshow-nav-prevPage, .fl-slideshow-nav-nextPage'), 5357 display = buttons.getStyle('display')[0]; 5358 5359 if(this._numPages == 1 && display == 'inline-block') { 5360 buttons.setStyle('display', 'none'); 5361 this._setSizeInfo(); 5362 } 5363 else if(this._numPages > 1 && display == 'none') { 5364 buttons.setStyle('display', 'inline-block'); 5365 this._setSizeInfo(); 5366 } 5367 }, 5368 5369 /** 5370 * Sets the size info used when resizing and loading pages. 5371 * 5372 * @method _setSizeInfo 5373 * @protected 5374 */ 5375 _setSizeInfo: function() 5376 { 5377 var root = this.get('root'), 5378 bb = this.get('boundingBox'), 5379 bbPosition = bb.getStyle('position'), 5380 bbLeftMargin = parseInt(bb.getStyle('marginLeft'), 10), 5381 bbRightMargin = parseInt(bb.getStyle('marginRight'), 10), 5382 bbTopMargin = parseInt(bb.getStyle('marginTop'), 10), 5383 bbBottomMargin = parseInt(bb.getStyle('marginBottom'), 10), 5384 bbLeftPadding = parseInt(bb.getStyle('paddingLeft'), 10), 5385 bbRightPadding = parseInt(bb.getStyle('paddingRight'), 10), 5386 bbTopPadding = parseInt(bb.getStyle('paddingTop'), 10), 5387 bbBottomPadding = parseInt(bb.getStyle('paddingBottom'), 10), 5388 parent = bb.get('parentNode'), 5389 parentWidth = parseInt(parent.getComputedStyle('width'), 10), 5390 parentHeight = parseInt(parent.getComputedStyle('height'), 10), 5391 bbWidth = parentWidth - bbLeftPadding - bbRightPadding - bbLeftMargin - bbRightMargin, 5392 bbHeight = parentHeight - bbTopPadding - bbBottomPadding - bbTopMargin - bbBottomMargin, 5393 cbWidth = bbWidth, 5394 pageWidth = bbWidth, 5395 pageHeight = bbHeight, 5396 columns = this.get('columns'), 5397 rows = this.get('rows'), 5398 imageConfig = this.get('imageConfig'), 5399 horizontalSpacing = this.get('horizontalSpacing'), 5400 verticalSpacing = this.get('verticalSpacing'), 5401 spaceEvenly = this.get('spaceEvenly'), 5402 centerSinglePage = this.get('centerSinglePage'), 5403 leftNavWidth = 0, 5404 rightNavWidth = 0, 5405 topNavHeight = 0, 5406 bottomNavHeight = 0, 5407 colsPerPage = columns, 5408 rowsPerPage = rows, 5409 imagesPerPage = 0, 5410 numPages = 1, 5411 clipBoxMarginLeft = 0, 5412 clipBoxTop = 0, 5413 availHorizSpace = 0, 5414 availVerticalSpace = 0; 5415 5416 // Position absolute causes some resizing bugs. 5417 bb.setStyle('position', 'relative'); 5418 5419 // Bounding box width 5420 if(!isNaN(columns)) { 5421 bbWidth = pageWidth = columns * (imageConfig.width + horizontalSpacing) + horizontalSpacing; 5422 } 5423
5424 // Bounding box height 5425 if(!isNaN(rows)) { 5426 bbHeight = pageHeight = rows * (imageConfig.height + verticalSpacing) + verticalSpacing; 5427 } 5428 5429 // Compensate for the navs 5430 if(this._leftNav) { 5431 5432 leftNavWidth = parseInt(this._leftNav.get('boundingBox').getComputedStyle('width'), 10); 5433 5434 if(isNaN(columns)) { 5435 pageWidth -= leftNavWidth; 5436 } 5437 else { 5438 bbWidth += leftNavWidth; 5439 } 5440 } 5441 if(this._rightNav) { 5442 5443 rightNavWidth = parseInt(this._rightNav.get('boundingBox').getComputedStyle('width'), 10); 5444 5445 if(isNaN(columns)) { 5446 pageWidth -= rightNavWidth; 5447 } 5448 else { 5449 bbWidth += rightNavWidth; 5450 } 5451 } 5452 if(this._topNav) { 5453 5454 topNavHeight = parseInt(this._topNav.get('boundingBox').getComputedStyle('height'), 10); 5455 5456 if(isNaN(rows)) { 5457 pageHeight -= topNavHeight; 5458 } 5459 else { 5460 bbHeight += topNavHeight; 5461 } 5462 } 5463 if(this._bottomNav) { 5464 5465 bottomNavHeight = parseInt(this._bottomNav.get('boundingBox').getComputedStyle('height'), 10); 5466 5467 if(isNaN(rows)) { 5468 pageHeight -= bottomNavHeight; 5469 } 5470 else { 5471 bbHeight += bottomNavHeight; 5472 } 5473 } 5474 5475 // Columns per page 5476 if(isNaN(columns)) { 5477 colsPerPage = Math.floor(pageWidth/(imageConfig.width + horizontalSpacing)); 5478 colsPerPage = colsPerPage < 1 ? 1 : colsPerPage; 5479 } 5480 5481 // Rows per page 5482 if(isNaN(rows)) { 5483 rowsPerPage = Math.floor(pageHeight/(imageConfig.height + verticalSpacing)); 5484 rowsPerPage = rowsPerPage < 1 ? 1 : rowsPerPage; 5485 } 5486 5487 // Images per page 5488 imagesPerPage = colsPerPage * rowsPerPage; 5489 5490 // Number of pages 5491 if(root.albumInfo) { 5492 numPages = Math.ceil(root.albumInfo.images.length/imagesPerPage); 5493 } 5494 5495 // Horizontal spacing 5496 if(isNaN(columns) && spaceEvenly) { 5497 horizontalSpacing = Math.floor((pageWidth - (imageConfig.width * colsPerPage))/(colsPerPage + 1)); 5498 } 5499 5500 // Vertical spacing 5501 if(isNaN(rows) && spaceEvenly) { 5502 verticalSpacing = Math.floor((pageHeight - (imageConfig.height * rowsPerPage))/(rowsPerPage + 1)); 5503 } 5504 5505 // Content container width 5506 if(root.albumInfo && centerSinglePage && numPages == 1 && rowsPerPage == 1) { 5507 5508 cbWidth = root.albumInfo.images.length * imageConfig.width; 5509 cbWidth += horizontalSpacing * (root.albumInfo.images.length + 1); 5510 5511 if(this._leftNav) { 5512 cbWidth += leftNavWidth; 5513 } 5514 if(this._rightNav) { 5515 cbWidth += rightNavWidth; 5516 } 5517 } 5518 else { 5519 cbWidth = bbWidth; 5520 } 5521 5522 // Final page width and height 5523 if(root.albumInfo && centerSinglePage && numPages == 1 && rowsPerPage == 1) { 5524 pageWidth = root.albumInfo.images.length * imageConfig.width; 5525 pageWidth += horizontalSpacing * root.albumInfo.images.length; 5526 } 5527 else { 5528 pageWidth = colsPerPage * (imageConfig.width + horizontalSpacing); 5529 } 5530 5531 pageHeight = rowsPerPage * (imageConfig.height + verticalSpacing); 5532 5533 // Clip box margin left 5534 if(numPages < 2) { 5535 clipBoxMarginLeft = leftNavWidth; 5536 } 5537 else { 5538 availHorizSpace = bbWidth; 5539 5540 if(this._rightNav) { 5541 availHorizSpace -= rightNavWidth; 5542 } 5543 if(this._leftNav) { 5544 availHorizSpace -= leftNavWidth; 5545 clipBoxMarginLeft = leftNavWidth + (availHorizSpace - pageWidth - horizontalSpacing)/2; 5546 } 5547 else { 5548 clipBoxMarginLeft = (availHorizSpace - pageWidth - horizontalSpacing)/2; 5549 } 5550 } 5551 5552 // Clip box margin top 5553 if(numPages > 1 && !spaceEvenly) { 5554 5555 availVerticalSpace = bbHeight; 5556 5557 if(this._topNav) { 5558 availVerticalSpace -= topNavHeight; 5559 } 5560 if(this._bottomNav) { 5561 availVerticalSpace -= bottomNavHeight; 5562 } 5563 5564 clipBoxTop = (availVerticalSpace - (verticalSpacing + pageHeight))/2; 5565 } 5566 5567 // Set the info 5568 this._bbHeight = bbHeight; 5569 this._bbWidth = bbWidth; 5570 this._cbWidth = cbWidth; 5571 this._clipBoxMarginLeft = clipBoxMarginLeft; 5572 this._clipBoxTop = clipBoxTop; 5573 this._colsPerPage = colsPerPage; 5574 this._rowsPerPage = rowsPerPage; 5575 this._imagesPerPage = imagesPerPage; 5576 this._numPages = numPages; 5577 this._pageHeight = pageHeight; 5578 this._pageWidth = pageWidth; 5579 this._leftNavWidth = leftNavWidth; 5580 this._rightNavWidth = rightNavWidth; 5581 this._horizontalSpacing = horizontalSpacing; 5582 this._verticalSpacing = verticalSpacing; 5583 this._activePageIndex = Math.floor(root.imageIndex/this._imagesPerPage); 5584 5585 // Set back to the initial position. 5586 bb.setStyle('position', bbPosition); 5587 } 5588 5589}, { 5590 5591 /** 5592 * Custom CSS class name for the widget. 5593 * 5594 * @property CSS_PREFIX
5595 * @type String 5596 * @protected 5597 * @static 5598 */ 5599 CSS_PREFIX: 'fl-slideshow-thumbs', 5600 5601 /** 5602 * Static property used to define the default attribute configuration of 5603 * the Widget. 5604 * 5605 * @property ATTRS 5606 * @type Object 5607 * @protected 5608 * @static 5609 */ 5610 ATTRS: { 5611 5612 /** 5613 * The number of thumbnail columns. If set to auto, the number of 5614 * columns will be calculated based on the width of the parent node. 5615 * 5616 * @attribute columns 5617 * @type String or Number 5618 * @default auto 5619 */ 5620 columns: { 5621 value: 'auto' 5622 }, 5623 5624 /** 5625 * The number of thumbnail rows. If set to auto, the number of 5626 * rows will be calculated based on the height of the parent node. 5627 * 5628 * @attribute rows 5629 * @type String or Number 5630 * @default auto 5631 */ 5632 rows: { 5633 value: 'auto' 5634 }, 5635 5636 /** 5637 * The horizontal spacing between thumbs. 5638 * 5639 * @attribute horizontalSpacing 5640 * @type Number 5641 * @default 15 5642 */ 5643 horizontalSpacing: { 5644 value: 15 5645 }, 5646 5647 /** 5648 * The vertical spacing between thumbs. 5649 * 5650 * @attribute verticalSpacing 5651 * @type Number 5652 * @default 15 5653 */ 5654 verticalSpacing: { 5655 value: 15 5656 }, 5657 5658 /** 5659 * Whether to space the thumbs evenly within a page. 5660 * 5661 * @attribute spaceEvenly 5662 * @type Boolean 5663 * @default true 5664 */ 5665 spaceEvenly: { 5666 value: true 5667 }, 5668 5669 /** 5670 * Whether to center single pages of thumbs. 5671 * 5672 * @attribute centerSinglePage 5673 * @type Boolean 5674 * @default false 5675 */ 5676 centerSinglePage: { 5677 value: true 5678 }, 5679 5680 /** 5681 * Whether to pause the parent slideshow when a thumb is clicked. 5682 * 5683 * @attribute pauseOnClick 5684 * @type Boolean 5685 * @default false 5686 */ 5687 pauseOnClick: { 5688 value: false 5689 }, 5690 5691 /** 5692 * The type of transition to use between pages. 5693 * 5694 * @attribute transition
5695 * @type String 5696 * @default slideHorizontal 5697 */ 5698 transition: { 5699 value: 'slideHorizontal' 5700 }, 5701 5702 /** 5703 * The duration of the transition between pages. 5704 * 5705 * @attribute transitionDuration 5706 * @type Number 5707 * @default 0.8 5708 */ 5709 transitionDuration: { 5710 value: 0.8 5711 }, 5712 5713 /** 5714 * The type of transition easing to use between pages. 5715 * 5716 * @attribute transitionEasing 5717 * @type String 5718 * @default ease-out 5719 */ 5720 transitionEasing: { 5721 value: 'ease-out' 5722 }, 5723 5724 /** 5725 * The configuration object used to create new instances of 5726 * FL.SlideshowImage. See the API docs for {@link FL.SlideshowImage} 5727 * for a complete list of configuration attributes. 5728 * 5729 * @attribute imageConfig 5730 * @type Object 5731 * @default {} 5732 */ 5733 imageConfig: { 5734 value: { 5735 crop: true, 5736 width: 50, 5737 height: 50 5738 } 5739 }, 5740 5741 /** 5742 * Whether to use the top nav or not. 5743 * 5744 * @attribute topNavEnabled 5745 * @type Boolean 5746 * @default false 5747 */ 5748 topNavEnabled: { 5749 value: false 5750 }, 5751 5752 /** 5753 * An array of button names used to render the top nav buttons. 5754 * 5755 * @attribute topNavButtons 5756 * @type Array 5757 * @default prevPage, nextPage 5758 */ 5759 topNavButtons: { 5760 value: ['prevPage', 'nextPage'] 5761 }, 5762 5763 /** 5764 * Whether to use the right nav or not. 5765 * 5766 * @attribute rightNavEnabled 5767 * @type Boolean 5768 * @default true 5769 */ 5770 rightNavEnabled: { 5771 value: true 5772 }, 5773 5774 /** 5775 * An array of button names used to render the right nav buttons. 5776 * 5777 * @attribute rightNavButtons 5778 * @type Array 5779 * @default nextPage 5780 */ 5781 rightNavButtons: { 5782 value: ['nextPage'] 5783 }, 5784 5785 /** 5786 * Whether to use the bottom nav or not. 5787 * 5788 * @attribute bottomNavEnabled 5789 * @type Boolean 5790 * @default false 5791 */ 5792 bottomNavEnabled: { 5793 value: false 5794 }, 5795 5796 /** 5797 * An array of button names used to render the bottom nav buttons. 5798 * 5799 * @attribute bottomNavButtons 5800 * @type Array 5801 * @default prevPage, nextPage 5802 */ 5803 bottomNavButtons:{ 5804 value: ['prevPage', 'nextPage'] 5805 }, 5806 5807 /** 5808 * Whether to use the left nav or not. 5809 * 5810 * @attribute leftNavEnabled 5811 * @type Boolean 5812 * @default true 5813 */ 5814 leftNavEnabled: { 5815 value: true 5816 }, 5817 5818 /** 5819 * An array of button names used to render the left nav buttons. 5820 * 5821 * @attribute leftNavButtons 5822 * @type Array 5823 * @default prevPage 5824 */ 5825 leftNavButtons:{ 5826 value: ['prevPage'] 5827 }, 5828 5829 /** 5830 * Whether to use touch gestures, when available, 5831 * to transition between pages or not. 5832 * 5833 * @attribute touchSupport 5834 * @type Boolean 5835 * @default false 5836 */ 5837 touchSupport: { 5838 value: false 5839 } 5840 } 5841}); 5842 5843/** 5844 * Provides functionality for transitions between slideshow components. 5845 * 5846 * @namespace FL 5847 * @class SlideshowTransition 5848 * @constructor 5849 * @param config {Object} Configuration object 5850 * @extends Base 5851 */ 5852Y.namespace('FL').SlideshowTransition = Y.Base.create('fl-slideshow-transition', Y.Base, [], { 5853 5854 /** 5855 * The transition function to use when run is called. 5856 * 5857 * @property _transitionFunction
5858 * @type String 5859 * @default _transitionFade 5860 * @protected 5861 */ 5862 _transitionFunction: '_transitionFade', 5863 5864 /** 5865 * The current transition type. 5866 * 5867 * @property _type 5868 * @type String 5869 * @default fade 5870 * @protected 5871 */ 5872 _type: 'fade', 5873 5874 /** 5875 * Parses the transition type and sets the _transitionFunction 5876 * used when run is called. 5877 * 5878 * @method initializer 5879 * @protected 5880 */ 5881 initializer: function() 5882 { 5883 var type = this.get('type'), 5884 typeArray = [], 5885 types = Y.FL.SlideshowTransition.TYPES, 5886 slideshowImageTypes = Y.FL.SlideshowTransition.SLIDESHOW_IMAGE_TYPES, 5887 isSlideshowImageTransition = Y.Array.indexOf(slideshowImageTypes, type) > -1, 5888 isSlideshowImage = this._isSlideshowImage(), 5889 itemIn = this.get('itemIn'), 5890 itemOut = this.get('itemOut'); 5891 5892 // Check for random transitions. 5893 if(type.indexOf(',') > -1) { 5894 typeArray = type.split(','); 5895 typeArray.sort(function() { return 0.5 - Math.random(); }); 5896 type = typeArray[0]; 5897 } 5898 5899 // Make sure we can run this transition, otherwise set a fallback. 5900 if(!isSlideshowImage && isSlideshowImageTransition) { 5901 type = 'fade'; 5902 } 5903 else if(isSlideshowImage) { 5904 if((itemIn && itemIn.one('img') === null) || (itemOut && itemOut.one('img') === null)) { 5905 type = 'none'; 5906 } 5907 else if(isSlideshowImageTransition) { 5908 if((Y.UA.gecko && Y.UA.gecko < 5) || Y.UA.opera > 0 || (Y.UA.ie > 0 && Y.UA.ie < 9)) { 5909 type = 'fade'; 5910 } 5911 } 5912 } 5913 5914 // Set the transition function and type. 5915 if(Y.FL.SlideshowTransition.TYPES[type]) { 5916 this._transitionFunction = types[type]; 5917 this._type = type; 5918 } 5919 5920 // Setup the items. 5921 this._setupItems(); 5922 }, 5923 5924 /** 5925 * Fires the start event and calls the transition function. 5926 * 5927 * @method run 5928 */ 5929 run: function() 5930 { 5931 /** 5932 * Fires when the transition starts. 5933 * 5934 * @event start 5935 */ 5936 this.fire('start'); 5937 5938 this[this._transitionFunction].call(this); 5939 }, 5940 5941 /** 5942 * Set initial styles for the items. 5943 * 5944 * @method _setupItems 5945 * @protected 5946 */ 5947 _setupItems: function() 5948 { 5949 var itemIn = this.get('itemIn'), 5950 itemOut = this.get('itemOut'); 5951 5952 if(itemIn) { 5953 itemIn.setStyle('zIndex', 2); 5954 itemIn.setStyle('opacity', 1); 5955 5956 if(Y.FL.Utils.cssSupport('transform')) { 5957 itemIn.setStyle('transform', 'translate(0, 0)'); 5958 } 5959 else { 5960 itemIn.setStyle('top', '0'); 5961 itemIn.setStyle('left', '0'); 5962 } 5963 } 5964 if(itemOut) { 5965 itemOut.setStyle('zIndex', 1); 5966 } 5967 }, 5968 5969 /** 5970 * Checks if the transition is being run 5971 * on an instance of FL.SlideshowImage or not. 5972 * 5973 * @method _isSlideshowImage 5974 * @protected 5975 */ 5976 _isSlideshowImage: function() 5977 { 5978 var itemIn = this.get('itemIn'), 5979 itemOut = this.get('itemOut'); 5980 5981 if(itemIn && itemIn.hasClass('fl-slideshow-image')) { 5982 return true; 5983 } 5984 else if(itemOut && itemOut.hasClass('fl-slideshow-image')) { 5985 return true; 5986 } 5987 5988 return false; 5989 }, 5990 5991 /** 5992 * Starts the transtion using the provided property objects. 5993 * 5994 * @method _transitionStart 5995 * @param propsIn {Object} The properties to animate in. 5996 * @param propsOut {Object} The properties to animate out. 5997 * @protected 5998 */ 5999 _transitionStart: function(propsIn, propsOut) 6000 { 6001 var itemIn = this.get('itemIn'), 6002 itemOut = this.get('itemOut'), 6003 itemInCallback = Y.bind(this._transitionComplete, this), 6004 itemOutCallback = !itemIn ? itemInCallback : null, 6005 duration = this.get('duration'), 6006 easing = this.get('easing'); 6007 6008 if(itemIn) { 6009 propsIn.duration = propsIn.duration || duration; 6010 propsIn.easing = propsIn.easing || easing; 6011 itemIn.transition(propsIn); 6012 } 6013 if(itemOut) { 6014 propsOut.duration = propsOut.duration || duration; 6015 propsOut.easing = propsOut.easing || easing; 6016 itemOut.transition(propsOut); 6017 } 6018 6019 if(itemInCallback) { 6020 Y.later(propsIn.duration * 1000 + 100, null, itemInCallback); 6021 } 6022 else if(itemOutCallback) { 6023 Y.later(propsOut.duration * 1000 + 100, null, itemOutCallback); 6024 } 6025 }, 6026 6027 /** 6028 * Clean up method called when the transition completes. 6029 * 6030 * @method _transitionComplete 6031 * @protected 6032 */ 6033 _transitionComplete: function() 6034 { 6035 this._set('itemIn', null); 6036 this._set('itemOut', null); 6037 6038 /** 6039 * Fires when the transition completes. 6040 * 6041 * @event complete 6042 */ 6043 this.fire('complete'); 6044 }, 6045 6046 /** 6047 * No transition. 6048 * 6049 * @method _transitionNone 6050 * @protected 6051 */ 6052 _transitionNone: function() 6053 { 6054 var itemIn = this.get('itemIn'), 6055 itemOut = this.get('itemOut'); 6056 6057 if(itemIn) { 6058 itemIn.setStyle('opacity', 1); 6059 } 6060 if(itemOut) { 6061 itemOut.setStyle('opacity', 0); 6062 } 6063 6064 this._transitionComplete(); 6065 }, 6066 6067 /** 6068 * Fade transition. 6069 * 6070 * @method _transitionFade 6071 * @protected 6072 */ 6073 _transitionFade: function() 6074 { 6075 var itemIn = this.get('itemIn'); 6076 6077 if(itemIn) { 6078 itemIn.setStyle('opacity', 0); 6079 } 6080 6081 this._transitionStart({ opacity: 1 },{ opacity: 0 }); 6082 }, 6083 6084 /** 6085 * Slide left transition. 6086 * 6087 * @method _transitionSlideLeft 6088 * @protected 6089 */ 6090 _transitionSlideLeft: function() 6091 { 6092 if(Y.FL.Utils.cssSupport('transform')) { 6093 this._cssTransitionSlide({ 6094 inStart: 'translate(100%, 0)', 6095 inEnd: 'translate(0, 0)', 6096 outStart: 'translate(0, 0)', 6097 outEnd: 'translate(-100%, 0)' 6098 }); 6099 } 6100 else { 6101 this._jsTransitionSlide('left'); 6102 } 6103 }, 6104 6105 /** 6106 * Slide right transition. 6107 * 6108 * @method _transitionSlideRight 6109 * @protected 6110 */ 6111 _transitionSlideRight: function() 6112 { 6113 if(Y.FL.Utils.cssSupport('transform')) { 6114 this._cssTransitionSlide({ 6115 inStart: 'translate(-100%, 0)', 6116 inEnd: 'translate(0, 0)', 6117 outStart: 'translate(0, 0)', 6118 outEnd: 'translate(100%, 0)' 6119 }); 6120 } 6121 else { 6122 this._jsTransitionSlide('right'); 6123 } 6124 }, 6125 6126 /** 6127 * Slide up transition. 6128 * 6129 * @method _transitionSlideUp 6130 * @protected 6131 */ 6132 _transitionSlideUp: function() 6133 { 6134 if(Y.FL.Utils.cssSupport('transform')) { 6135 this._cssTransitionSlide({ 6136 inStart: 'translate(0, 100%)', 6137 inEnd: 'translate(0, 0)', 6138 outStart: 'translate(0, 0)', 6139 outEnd: 'translate(0, -100%)' 6140 }); 6141 } 6142 else { 6143 this._jsTransitionSlide('up'); 6144 } 6145 }, 6146 6147 /** 6148 * Slide down transition. 6149 * 6150 * @method _transitionSlideDown 6151 * @protected 6152 */ 6153 _transitionSlideDown: function() 6154 { 6155 if(Y.FL.Utils.cssSupport('transform')) { 6156 this._cssTransitionSlide({ 6157 inStart: 'translate(0, -100%)', 6158 inEnd: 'translate(0, 0)', 6159 outStart: 'translate(0, 0)', 6160 outEnd: 'translate(0, 100%)' 6161 }); 6162 } 6163 else { 6164 this._jsTransitionSlide('down'); 6165 } 6166 }, 6167 6168 /** 6169 * JavaScript slide transition. 6170 * 6171 * @method _jsTransitionSlide 6172 * @protected 6173 */ 6174 _jsTransitionSlide: function(direction) 6175 { 6176 var itemIn = this.get('itemIn'), 6177 itemOut = this.get('itemOut'), 6178 itemOutEnd = 0; 6179 6180 // Item Out 6181 if(itemOut && direction == 'left') { 6182 itemOutEnd = -parseInt(itemOut.getStyle('width'), 10); 6183 } 6184 if(itemOut && direction == 'right') { 6185 itemOutEnd = parseInt(itemOut.getStyle('width'), 10); 6186 } 6187 if(itemOut && direction == 'up') { 6188 itemOutEnd = -parseInt(itemOut.getStyle('height'), 10); 6189 } 6190 if(itemOut && direction == 'down') { 6191 itemOutEnd = parseInt(itemOut.getStyle('height'), 10); 6192 } 6193 6194 // Item In 6195 if(itemIn) { 6196 itemIn.setStyle('opacity', 1); 6197 } 6198 if(itemIn && direction == 'left') { 6199 itemIn.setStyle('left', itemIn.getStyle('width')); 6200 } 6201 if(itemIn && direction == 'right') { 6202 itemIn.setStyle('left', '-' + itemIn.getStyle('width')); 6203 } 6204 if(itemIn && direction == 'up') { 6205 itemIn.setStyle('top', itemIn.getStyle('height')); 6206 } 6207 if(itemIn && direction == 'down') { 6208 itemIn.setStyle('top', '-' + itemIn.getStyle('height')); 6209 } 6210 6211 // Transition Start 6212 if(direction == 'left' || direction == 'right') { 6213 this._transitionStart({ left: 0 },{ left: itemOutEnd }); 6214 } 6215 else { 6216 this._transitionStart({ top: 0 },{ top: itemOutEnd }); 6217 } 6218 }, 6219 6220 /** 6221 * CSS slide transition. 6222 *
6223 * @method _cssTransitionSlide 6224 * @protected 6225 */ 6226 _cssTransitionSlide: function(props) 6227 { 6228 var itemIn = this.get('itemIn'), 6229 itemOut = this.get('itemOut'), 6230 transformProp = Y.UA.chrome < 36 ? 'transform' : '-webkit-transform', 6231 inProps = {}, 6232 outProps = {}; 6233 6234 inProps[transformProp] = props.inEnd; 6235 outProps[transformProp] = props.outEnd; 6236 6237 if(itemIn) { 6238 itemIn.setStyle('transition', ''); 6239 itemIn.setStyle('opacity', 1); 6240 itemIn.setStyle(transformProp, props.inStart); 6241 } 6242 if(itemOut) { 6243 itemOut.setStyle('transition', ''); 6244 itemOut.setStyle(transformProp, props.outStart); 6245 } 6246 6247 this._transitionStart(inProps, outProps); 6248 }, 6249 6250 /** 6251 * Bars and blinds transition. 6252 * 6253 * @method _transitionBars 6254 * @protected 6255 */ 6256 _transitionBars: function() 6257 { 6258 // Hide the image until the slices have transitioned in. 6259 this.get('itemIn').one('.fl-slideshow-image-img').setStyle('opacity', 0); 6260 6261 var numBars = this.get('bars'), 6262 slices = this._renderSlices(1, numBars), 6263 duration = this.get('duration'), 6264 delay = 0, 6265 increment = 100, 6266 last = false, 6267 i = 0, 6268 clone = null, 6269 props = { 6270 duration: duration, 6271 opacity: 1 6272 }; 6273 6274 // barsRandom 6275 if(this._type == 'barsRandom') { 6276 slices = this._randomizeSlices(slices); 6277 } 6278 6279 // Transition the slices. 6280 for( ; i < slices.length; i++) { 6281 6282 // Make a clone of our transition properties. 6283 clone = Y.clone(props); 6284 6285 // blinds 6286 if(this._type == 'blinds') { 6287 clone.width = parseFloat(slices[i].getComputedStyle('width'), 10) + 'px'; 6288 slices[i].setStyle('width', '0px'); 6289 increment = 50; 6290 } 6291 6292 // Run the transition. 6293 last = i == slices.length - 1 ? true : false; 6294 Y.later(delay, this, this._transitionSlice, [slices[i], clone, last]); 6295 delay += increment; 6296 } 6297 6298 this._transitionSlicesFadeLast(delay); 6299 }, 6300 6301 /** 6302 * Boxes transition. 6303 * 6304 * @method _transitionBoxes 6305 * @protected 6306 */ 6307 _transitionBoxes: function() 6308 { 6309 // Hide the image until the slices have transitioned in. 6310 this.get('itemIn').one('.fl-slideshow-image-img').setStyle('opacity', 0); 6311 6312 var numCols = this.get('boxCols'), 6313 numRows = this.get('boxRows'), 6314 numSlices = numCols * numRows, 6315 multi = this._type != 'boxesRandom', 6316 slices = this._renderSlices(numRows, numCols, multi), 6317 duration = this.get('duration'), 6318 delay = 0, 6319 increment = 150, 6320 last = false, 6321 i = 0, 6322 row = 0, 6323 col = 0, 6324 startCol = -1, 6325 clone = null, 6326 props = { 6327 duration: duration, 6328 opacity: 1 6329 }; 6330 6331 // boxesRandom 6332 if(!multi) { 6333 6334 slices = this._randomizeSlices(slices); 6335 increment = 30; 6336 6337 for( ; i < slices.length; i++) { 6338 clone = Y.clone(props); 6339 last = i == slices.length - 1 ? true : false; 6340 Y.later(delay, this, this._transitionSlice, [slices[i], clone, last]); 6341 delay += increment; 6342 } 6343 } 6344 // boxes 6345 else { 6346 while(i < numSlices) { 6347 for(row = 0; row < numRows; row++) { 6348 if(row === 0) { 6349 startCol++; 6350 col = startCol; 6351 } 6352 if(col > -1 && col < numCols) { 6353 i++; 6354 clone = Y.clone(props); 6355 6356 // boxesGrow 6357 if(this._type == 'boxesGrow') { 6358 clone.height = parseFloat(slices[row][col].getComputedStyle('height'), 10) + 'px'; 6359 clone.width = parseFloat(slices[row][col].getComputedStyle('width'), 10) + 'px'; 6360 slices[row][col].setStyle('height', '0px'); 6361 slices[row][col].setStyle('width', '0px'); 6362 increment = 50; 6363 } 6364 6365 last = i == numSlices - 1 ? true : false;
6366 Y.later(delay, this, this._transitionSlice, [slices[row][col], clone, last]); 6367 } 6368 col--; 6369 } 6370 delay += increment; 6371 } 6372 } 6373 6374 this._transitionSlicesFadeLast(delay); 6375 }, 6376 6377 /** 6378 * Renders the divs for slice based transitions. 6379 * 6380 * @method _renderSlices 6381 * @protected 6382 */ 6383 _renderSlices: function(numRows, numCols, multidimensional) 6384 { 6385 var itemIn = this.get('itemIn'), 6386 itemHeight = parseFloat(itemIn.getComputedStyle('height'), 10), 6387 itemWidth = parseFloat(itemIn.getComputedStyle('width'), 10), 6388 img = itemIn.one('img'), 6389 imgSrc = img.get('src'), 6390 imgHeight = parseFloat(img.getComputedStyle('height'), 10), 6391 imgWidth = parseFloat(img.getComputedStyle('width'), 10), 6392 imgLeft = parseFloat(img.getComputedStyle('left'), 10), 6393 imgTop = parseFloat(img.getComputedStyle('top'), 10), 6394 col = 0, 6395 row = 0, 6396 sliceHeight = Math.round(itemHeight/numRows), 6397 sliceWidth = Math.round(itemWidth/numCols), 6398 slice = null, 6399 sliceImg = null, 6400 slices = []; 6401 6402 for( ; row < numRows; row++) { 6403 6404 if(typeof multidimensional !== 'undefined' && multidimensional) { 6405 slices[row] = []; 6406 } 6407 for(col = 0; col < numCols; col++) { 6408 6409 slice = Y.Node.create('<div class="fl-slideshow-transition-slice"></div>'); 6410 sliceImg = Y.Node.create('<img src="'+ imgSrc +'" />'); 6411 6412 slice.setStyles({ 6413 left: (sliceWidth * col) + 'px', 6414 top: (sliceHeight * row) + 'px', 6415 width: col == numCols - 1 ? (itemWidth - (sliceWidth * col)) + 'px' : sliceWidth + 'px', 6416 height: row == numRows - 1 ? (itemHeight - (sliceHeight * row)) + 'px' : sliceHeight + 'px', 6417 opacity: 0 6418 }); 6419 6420 sliceImg.setStyles({ 6421 height: imgHeight + 'px', 6422 width: imgWidth + 'px', 6423 top: imgTop - ((sliceHeight + (row * sliceHeight)) - sliceHeight) + 'px', 6424 left: imgLeft - ((sliceWidth + (col * sliceWidth)) - sliceWidth) + 'px' 6425 }); 6426 6427 slice.append(sliceImg); 6428 itemIn.append(slice); 6429 6430 if(typeof multidimensional !== 'undefined' && multidimensional) { 6431 slices[row].push(slice); 6432 } 6433 else { 6434 slices.push(slice); 6435 } 6436 } 6437 } 6438 6439 return slices; 6440 }, 6441 6442 /** 6443 * Fade the itemOut node. 6444 * 6445 * @method _transitionSlicesFadeLast 6446 * @protected 6447 */ 6448 _transitionSlicesFadeLast: function(delay) 6449 { 6450 var itemOut = this.get('itemOut'); 6451 6452 if(itemOut && !itemOut.hasClass('fl-slideshow-image-cropped')) { 6453 itemOut.transition({ 6454 duration: delay/1000 + this.get('duration'), 6455 opacity: 0 6456 }); 6457 } 6458 }, 6459 6460 /** 6461 * Transitions a single slice. 6462 * 6463 * @method _transitionSlice 6464 * @protected 6465 */ 6466 _transitionSlice: function(slice, props, last) 6467 { 6468 var callback = last ? Y.bind(this._transitionSlicesComplete, this) : null; 6469 6470 slice.transition(props, callback); 6471 }, 6472 6473 /** 6474 * Complete callback for slice based transitions. 6475 * 6476 * @method _transitionSlicesComplete 6477 * @protected 6478 */ 6479 _transitionSlicesComplete: function() 6480 { 6481 var itemIn = this.get('itemIn'); 6482 6483 itemIn.all('.fl-slideshow-transition-slice').remove(); 6484 itemIn.one('.fl-slideshow-image-img').setStyle('opacity', 1); 6485 this._transitionComplete(); 6486 }, 6487 6488 /** 6489 * Randomizes a slices array. 6490 * 6491 * @method _radomizeSlices 6492 * @protected 6493 */ 6494 _randomizeSlices: function(slices) 6495 { 6496 var i = slices.length, j, temp; 6497 6498 if(i === 0) { 6499 return; 6500 } 6501 while(--i) { 6502 j = Math.floor( Math.random() * ( i + 1 ) ); 6503 temp = slices[i]; 6504 slices[i] = slices[j]; 6505 slices[j] = temp; 6506 } 6507 6508 return slices; 6509 }, 6510 6511 _transitionKenBurns: function() 6512 { 6513 var kbDuration = this.get('kenBurnsDuration'), 6514 duration = this.get('duration'), 6515 itemIn = this.get('itemIn'), 6516 zoom = this.get('kenBurnsZoom'); 6517 6518 this._transitionFade(); 6519 6520 (new Y.FL.SlideshowKenBurns({ 6521 duration: kbDuration + duration + 4, 6522 image: itemIn, 6523 zoom: zoom 6524 })).run(); 6525 } 6526 6527}, { 6528 6529 /** 6530 * Static property used to define the default attribute configuration of 6531 * the Widget. 6532 * 6533 * @property ATTRS 6534 * @type Object 6535 * @protected 6536 * @static 6537 */ 6538 ATTRS: { 6539 6540 /** 6541 * The Node to transition in. 6542 * 6543 * @attribute itemIn 6544 * @type Node 6545 * @default null 6546 */ 6547 itemIn: { 6548 value: null 6549 }, 6550 6551 /** 6552 * The Node to transition out. 6553 * 6554 * @attribute itemOut 6555 * @type Node 6556 * @default null 6557 */ 6558 itemOut: { 6559 value: null 6560 }, 6561 6562 /** 6563 * The duration of the transition in seconds. 6564 * 6565 * @attribute duration 6566 * @type Number 6567 * @default 0.5 6568 */ 6569 duration: { 6570 value: 0.5 6571 }, 6572 6573 /** 6574 * The type of easing to use. 6575 * 6576 * @attribute easing
6577 * @type String 6578 * @default ease-out 6579 */ 6580 easing: { 6581 value: 'ease-out' 6582 }, 6583 6584 /** 6585 * The type of transition to use. 6586 * 6587 * @attribute type 6588 * @type String 6589 * @default fade 6590 */ 6591 type: { 6592 value: 'fade' 6593 }, 6594 6595 /** 6596 * The number of bars to use for 6597 * transitions such as blinds. 6598 * 6599 * @attribute bars 6600 * @type Number 6601 * @default 15 6602 */ 6603 bars: { 6604 value: 15 6605 }, 6606 6607 /** 6608 * The number of columns to use for 6609 * transitions such as boxes. 6610 * 6611 * @attribute boxCols 6612 * @type Number 6613 * @default 8 6614 */ 6615 boxCols: { 6616 value: 8 6617 }, 6618 6619 /** 6620 * The number of rows to use for 6621 * transitions such as boxes. 6622 * 6623 * @attribute boxRows 6624 * @type Number 6625 * @default 4 6626 */ 6627 boxRows: { 6628 value: 4 6629 }, 6630 6631 /** 6632 * The duration the ken burns effect will 6633 * last, measured in seconds. 6634 * 6635 * @attribute kenBurnsDuration 6636 * @type Number 6637 * @default 4 6638 */ 6639 kenBurnsDuration: { 6640 value: 4 6641 }, 6642 6643 /** 6644 * The amount of zoom to use for the Ken Burns effect. 6645 * 6646 * @attribute kenBurnsZoom 6647 * @type Number 6648 * @default 1.2 6649 */ 6650 kenBurnsZoom: { 6651 value: 1.2 6652 } 6653 }, 6654 6655 /** 6656 * The types of transitions and associated functions. 6657 * 6658 * @property TYPES 6659 * @type Object 6660 * @readOnly 6661 * @protected 6662 * @static 6663 */ 6664 TYPES: { 6665 fade: '_transitionFade', 6666 none: '_transitionNone', 6667 slideLeft: '_transitionSlideLeft', 6668 slideRight: '_transitionSlideRight', 6669 slideUp: '_transitionSlideUp', 6670 slideDown: '_transitionSlideDown', 6671 blinds: '_transitionBars', 6672 bars: '_transitionBars', 6673 barsRandom: '_transitionBars', 6674 boxes: '_transitionBoxes', 6675 boxesRandom: '_transitionBoxes', 6676 boxesGrow: '_transitionBoxes', 6677 kenBurns: '_transitionKenBurns' 6678 }, 6679 6680 /** 6681 * The types of transitions that can only be 6682 * run on FL.SlideshowImage widgets. 6683 * 6684 * @property SLIDESHOW_IMAGE_TYPES 6685 * @type Object 6686 * @readOnly 6687 * @protected 6688 * @static 6689 */ 6690 SLIDESHOW_IMAGE_TYPES: [ 6691 'blinds', 6692 'bars', 6693 'barsRandom', 6694 'boxes', 6695 'boxesRandom', 6696 'boxesGrow', 6697 'kenBurns' 6698 ] 6699}); 6700 6701/** 6702 * A highly configurable slideshow widget. 6703 * 6704 * @namespace FL 6705 * @class Slideshow 6706 * @constructor 6707 * @param config {Object} Configuration object 6708 * @extends FL.SlideshowBase 6709 */ 6710Y.namespace('FL').Slideshow = Y.Base.create('fl-slideshow', Y.FL.SlideshowBase, [], { 6711 6712 /** 6713 * A FL.SlideshowFrame instance used for the main image. 6714 * 6715 * @property frame 6716 * @type FL.SlideshowFrame 6717 * @default null 6718 */ 6719 frame: null, 6720 6721 /** 6722 * A FL.SlideshowNav instance used for the main nav. 6723 * 6724 * @property nav 6725 * @type FL.SlideshowNav 6726 * @default null 6727 */ 6728 nav: null, 6729 6730 /** 6731 * A FL.SlideshowNav instance used for the image nav's left button. 6732 * 6733 * @property imageNavLeft 6734 * @type FL.SlideshowNav 6735 * @default null 6736 */ 6737 imageNavLeft: null, 6738 6739 /** 6740 * A FL.SlideshowNav instance used for the image nav's right button. 6741 * 6742 * @property imageNavRight 6743 * @type FL.SlideshowNav 6744 * @default null 6745 */ 6746 imageNavRight: null, 6747 6748 /** 6749 * A FL.SlideshowThumbs instance used for the thumbnail grid. 6750 * 6751 * @property thumbs 6752 * @type FL.SlideshowThumbs 6753 * @default null 6754 */ 6755 thumbs: null, 6756 6757 /** 6758 * A FL.SlideshowThumbs instance used for the vertical thumbnail grid. 6759 * 6760 * @property verticalThumbs 6761 * @type FL.SlideshowThumbs 6762 * @default null 6763 */ 6764 verticalThumbs: null, 6765 6766 /** 6767 * A FL.SlideshowCaption instance. 6768 * 6769 * @property caption 6770 * @type FL.SlideshowCaption 6771 * @default null 6772 */ 6773 caption: null, 6774 6775 /** 6776 * A FL.SlideshowSocial instance. 6777 * 6778 * @property social 6779 * @type FL.SlideshowSocial 6780 * @default null 6781 */ 6782 social: null, 6783 6784 /** 6785 * A FL.SlideshowImage instance used to preload 6786 * the next image. 6787 * 6788 * @property _nextImagePreloader 6789 * @type FL.SlideshowImage 6790 * @default null 6791 * @protected 6792 */ 6793 _nextImagePreloader: null, 6794 6795 /** 6796 * An object that holds the initial nav settings 6797 * when the mini nav has been enabled for a responsive layout. 6798 * 6799 * @property _initialNavSettings 6800 * @type Object 6801 * @default null 6802 * @protected 6803 */ 6804 _initialNavSettings: null, 6805 6806 /** 6807 * Initializes the preloaders, nav buttons, fullscreen and captions. 6808 * 6809 * @method initializer 6810 * @protected 6811 */ 6812 initializer: function() 6813 { 6814 // Preloader config 6815 var imageConfig = { 6816 loadGroup: 'main-preload', 6817 crop: this.get('crop'), 6818 position: this.get('position'), 6819 protect: this.get('protect'), 6820 upsize: this.get('upsize') 6821 }; 6822 6823 // Preloader 6824 this._nextImagePreloader = new Y.FL.SlideshowImage(imageConfig); 6825 6826 // Nav buttons not needed for touch 6827 if(this._isMobile()) { 6828 this._removeNavButton('prevPage'); 6829 this._removeNavButton('nextPage'); 6830 this._removeNavButton('fullscreen'); 6831 } 6832 6833 // Fullscreen 6834 if(this._hasNavButton('fullscreen')) { 6835 if(Y.FL.SlideshowFullscreen.OS_SUPPORT) { 6836 this.plug(Y.FL.SlideshowFullscreen); 6837 } 6838 else { 6839 this._removeNavButton('fullscreen'); 6840 } 6841 } 6842 }, 6843 6844 /** 6845 * Calls the FL.SlideshowBase superclass renderUI method 6846 * and renders the child widgets. 6847 * 6848 * @method renderUI 6849 * @protected 6850 */ 6851 renderUI: function() 6852 { 6853 Y.FL.Slideshow.superclass.renderUI.apply(this, arguments); 6854 6855 this._renderFrame(); 6856 this._renderVerticalThumbs(); 6857 this._renderNavAndThumbs(); 6858 this._renderImageNav(); 6859 this._renderMouseNav(); 6860 this._renderCaption(); 6861 this._renderSocial(); 6862 }, 6863 6864 /** 6865 * Calls the FL.SlideshowBase superclass bindUI method, binds 6866 * _resizeChildWidgets to fire after the resize method inherited 6867 * from FL.SlideshowBase, shows the loading image, binds overlay events 6868 * and binds an event to load an image into the frame. 6869 * 6870 * @method bindUI 6871 * @protected 6872 */ 6873 bindUI: function() 6874 { 6875 var ssBB = this.get('boundingBox'), 6876 frameBB = this.frame.get('boundingBox'), 6877 navOverlay = this.get('navOverlay'), 6878 navType = this.get('navType'), 6879 nav = this._getNav(), 6880 clickAction = this.get('clickAction'); 6881 6882 // Call superclass bindUI 6883 Y.FL.Slideshow.superclass.bindUI.apply(this, arguments); 6884 6885 // Resize child widgets after the superclass resize method. 6886 Y.Do.after(this._resizeChildWidgets, this, 'resize'); 6887 6888 // Loading events 6889 this.on('albumLoadStart', this._albumLoadStart, this); 6890 this.on('albumLoadComplete', this._albumLoadComplete, this); 6891 this.on('imageLoadComplete', this._loadFrame, this); 6892 6893 // Loading image 6894 if(this.get('loadingImageAlwaysEnabled')) { 6895 this.frame.on('transitionInit', Y.bind(this._showLoadingImageWithDelay, this)); 6896 this.frame.on('transitionStart', Y.bind(this._hideLoadingImage, this)); 6897 } 6898 6899 // Overlay events 6900 if(this.get('overlayHideOnMousemove')) { 6901 if(nav && navOverlay) { 6902 this.frame.once('transitionComplete', nav.slideshowOverlay.hideWithTimer, nav.slideshowOverlay); 6903 ssBB.on('mousemove', Y.bind(this._toggleNav, this)); 6904 } 6905 if(navType == 'buttons' || navType == 'thumbs' || navType == 'custom') { 6906 ssBB.on('mouseenter', Y.bind(this._checkOverlaysOnMouseenter, this)); 6907 ssBB.on('mouseleave', Y.bind(this._hideAllOverlays, this)); 6908 } 6909 } 6910 6911 ssBB.delegate('click', Y.bind(this._overlayCloseClick, this), '.fl-slideshow-overlay-close'); 6912 6913 // Click action 6914 if(clickAction == 'gallery' || clickAction == 'url') { 6915 frameBB.delegate('click', Y.bind(this._frameClick, this), '.fl-slideshow-image-img'); 6916 } 6917 }, 6918 6919 /** 6920 * Calls the FL.SlideshowBase superclass syncUI method 6921 * and makes the bounding box unselectable. 6922 * 6923 * @method syncUI 6924 * @protected 6925 */
6926 syncUI: function() 6927 { 6928 var bb = this.get('boundingBox'); 6929 6930 Y.FL.Slideshow.superclass.syncUI.apply(this, arguments); 6931 6932 bb._node.onselectstart = function() { return false; }; 6933 bb._node.unselectable = "on"; 6934 bb._node.style.MozUserSelect = "none"; 6935 6936 if(this.get('clickAction') != 'none') { 6937 this.frame.get('boundingBox').addClass('fl-click-action-enabled'); 6938 } 6939 }, 6940 6941 /** 6942 * Checks to see if the current device is mobile. 6943 * 6944 * @since 1.9.3 6945 * @access private 6946 * @method _isMobile 6947 * @return {Boolean} 6948 */ 6949 _isMobile: function() 6950 { 6951 return /Mobile|Android|Silk\/|Kindle|BlackBerry|Opera Mini|Opera Mobi|webOS/i.test( navigator.userAgent ); 6952 }, 6953 6954 /** 6955 * Unload all slideshow images and pause 6956 * the slideshow. 6957 * 6958 * @method unload 6959 */ 6960 unload: function() 6961 { 6962 this.pause(); 6963 this.frame.unload(); 6964 6965 if(this.thumbs !== null) { 6966 this.thumbs.unload(); 6967 } 6968 }, 6969 6970 /** 6971 * @method _albumLoadStart 6972 * @protected 6973 */ 6974 _albumLoadStart: function() 6975 { 6976 this._showLoadingImage(); 6977 }, 6978 6979 /** 6980 * @method _albumLoadComplete 6981 * @protected 6982 */ 6983 _albumLoadComplete: function() 6984 { 6985 this.frame.once('transitionStart', Y.bind(this._hideLoadingImage, this)); 6986 }, 6987 6988 /** 6989 * Resizes all enabled child widgets. 6990 * 6991 * @method _resizeChildWidgets 6992 * @protected 6993 */ 6994 _resizeChildWidgets: function() 6995 { 6996 var bb = this.get('boundingBox'), 6997 cb = this.get('contentBox'), 6998 imageNavEnabled = this.get('imageNavEnabled'); 6999 7000 this._renderNavAndThumbs(); 7001 7002 if(this.get('verticalThumbsOverlay')) { 7003 this._resizeFrame(cb.get('offsetWidth'), bb.get('offsetHeight')); 7004 this._resizeVerticalThumbs(); 7005 } 7006 else { 7007 this._resizeVerticalThumbs(); 7008 this._resizeFrame(cb.get('offsetWidth'), bb.get('offsetHeight')); 7009 } 7010 7011 if(imageNavEnabled) { 7012 this._positionImageNav(); 7013 } 7014 7015 this._positionLoadingImage(); 7016 }, 7017 7018 /** 7019 * @method _renderVerticalThumbs 7020 * @protected 7021 */ 7022 _renderVerticalThumbs: function() 7023 { 7024 var threshold = this.get('responsiveThreshold'), 7025 ssBB = this.get('boundingBox'), 7026 bbWidth = ssBB.get('offsetWidth'), 7027 vtBB; 7028 7029 if(this.get('verticalThumbsEnabled') && bbWidth > threshold) { 7030 7031 this.verticalThumbs = new Y.FL.SlideshowThumbs(this._getVerticalThumbsConfig()); 7032 this.add(this.verticalThumbs); 7033 this.verticalThumbs.render(ssBB); 7034 7035 vtBB = this.verticalThumbs.get('boundingBox'); 7036 vtBB.addClass('fl-slideshow-vertical-thumbs'); 7037 vtBB.setStyle(this.get('verticalThumbsPosition'), 0); 7038 ssBB.append(vtBB); 7039 7040 if(this.get('verticalThumbsOverlay')) { 7041 this.verticalThumbs.plug(Y.FL.SlideshowOverlay, { 7042 hideDelay: this.get('overlayHideDelay'), 7043 hideStyle: 'left' 7044 }); 7045 7046 this.frame.get('boundingBox').append(vtBB); 7047 this.verticalThumbs.resize(); 7048 } 7049 else { 7050 this.verticalThumbs.resize(); 7051 this._adjustContentForVerticalThumbs(); 7052 } 7053 7054 this._bindVerticalThumbs(); 7055 } 7056 }, 7057 7058 /** 7059 * Prepares and returns the vertical thumbs config object. 7060 * 7061 * @method _getVerticalThumbsConfig 7062 * @protected 7063 * @returns Object 7064 */ 7065 _getVerticalThumbsConfig: function() 7066 { 7067 var attrs = this.getAttrs(), 7068 config = { 7069 columns: attrs.verticalThumbsColumns, 7070 rows: 'auto', 7071 centerSinglePage: false, 7072 horizontalSpacing: attrs.verticalThumbsHorizontalSpacing, 7073 verticalSpacing: attrs.verticalThumbsVerticalSpacing, 7074 spaceEvenly: attrs.verticalThumbsSpaceEvenly, 7075 rightNavEnabled: false, 7076 leftNavEnabled: false, 7077 topNavEnabled: attrs.verticalThumbsTopNavEnabled, 7078 topNavButtons: attrs.verticalThumbsTopNavButtons, 7079 bottomNavEnabled: attrs.verticalThumbsBottomNavEnabled, 7080 bottomNavButtons: attrs.verticalThumbsBottomNavButtons, 7081 pauseOnClick: attrs.verticalThumbsPauseOnClick, 7082 transition: attrs.verticalThumbsTransition, 7083 transitionDirection: attrs.verticalThumbsTransitionDirection, 7084 transitionEasing: attrs.verticalThumbsTransitionEasing, 7085 touchSupport: true, 7086 imageConfig: { 7087 crop: attrs.verticalThumbsImageCrop, 7088 width: attrs.verticalThumbsImageWidth, 7089 height: attrs.verticalThumbsImageHeight 7090 } 7091 }; 7092 7093 return config; 7094 }, 7095 7096 _bindVerticalThumbs: function() 7097 { 7098 var ssBB = this.get('boundingBox'), 7099 hideOnMouse = this.get('overlayHideOnMousemove'), 7100 vtOverlay = this.get('verticalThumbsOverlay'), 7101 vt = this.verticalThumbs; 7102 7103 if(vt && hideOnMouse && vtOverlay) { 7104 this.frame.once('transitionComplete', vt.slideshowOverlay.hideWithTimer, vt.slideshowOverlay); 7105 ssBB.on('mousemove', Y.bind(this._toggleVerticalThumbs, this)); 7106 ssBB.on('mouseenter', Y.bind(this._toggleVerticalThumbs, this)); 7107 } 7108 }, 7109 7110 /** 7111 * Resizes the vertical thumbs. 7112 * 7113 * @method _resizeVerticalThumbs 7114 * @protected 7115 */ 7116 _resizeVerticalThumbs: function() 7117 { 7118 var vtEnabled = this.get('verticalThumbsEnabled'), 7119 vtOverlay, 7120 threshold, 7121 ssBB, 7122 bbWidth, 7123 navOverlay, 7124 navType, 7125 nav, 7126 navBB; 7127 7128 if(vtEnabled) { 7129 vtOverlay = this.get('verticalThumbsOverlay'); 7130 threshold = this.get('responsiveThreshold'); 7131 ssBB = this.get('boundingBox'); 7132 bbWidth = ssBB.get('offsetWidth'); 7133 navOverlay = this.get('navOverlay'); 7134 navType = this.get('navType'); 7135 nav = this._getNav(); 7136 7137 if(this.verticalThumbs && bbWidth > threshold) { 7138 7139 this.verticalThumbs.get('boundingBox').setStyle('display', 'block'); 7140 this.verticalThumbs.resize(); 7141 7142 if(!vtOverlay) { 7143 this._adjustContentForVerticalThumbs(); 7144 } 7145 else if(nav && navOverlay) { 7146 7147 navBB = nav.get('boundingBox'); 7148 7149 if(navType == 'thumbs') { 7150 this._adjustOverlayForVerticalThumbs(navBB, true); 7151 this.thumbs.resize(); 7152 } 7153 else { 7154 this._adjustOverlayForVerticalThumbs(navBB); 7155 } 7156 } 7157 } 7158 else if(!this.verticalThumbs && bbWidth > threshold) { 7159 this._renderVerticalThumbs(); 7160 } 7161 else if(this.verticalThumbs && bbWidth <= threshold) { 7162 7163 this.verticalThumbs.get('boundingBox').setStyle('display', 'none'); 7164 7165 if(!vtOverlay) { 7166 this.get('contentBox').setStyles({ 7167 left: 'auto', 7168 position: 'relative', 7169 right: 'auto', 7170 width: 'auto' 7171 }); 7172 } 7173 } 7174 } 7175 }, 7176 7177 /** 7178 * Toggles the visibility of the vertical thumbs. 7179 * 7180 * @method _toggleVerticalThumbs 7181 * @protected 7182 */ 7183 _toggleVerticalThumbs: function() 7184 { 7185 if(this.verticalThumbs) { 7186 if(this.verticalThumbs.slideshowOverlay._visible) { 7187 this.verticalThumbs.slideshowOverlay.hideWithTimer(); 7188 } 7189 else { 7190 this.verticalThumbs.slideshowOverlay.show(); 7191 } 7192 } 7193 }, 7194 7195 /** 7196 * Adjusts the content position and width 7197 * for the vertical thumbs. 7198 * 7199 * @method _adjustContentForVerticalThumbs 7200 * @protected 7201 */ 7202 _adjustContentForVerticalThumbs: function() 7203 { 7204 var ssBB = this.get('boundingBox'), 7205 vtBB = this.verticalThumbs.get('boundingBox'), 7206 vtPos = this.get('verticalThumbsPosition'), 7207 ssCB = this.get('contentBox'), 7208 cbPos = vtPos == 'left' ? 'right' : 'left', 7209 cbWidth = ssBB.get('offsetWidth') - vtBB.get('offsetWidth'); 7210 7211 ssCB.setStyle('position', 'absolute'); 7212 ssCB.setStyle(cbPos, 0); 7213 ssCB.setStyle('width', cbWidth); 7214 }, 7215 7216 /** 7217 * Adjusts an overlay's position for the vertical 7218 * thumbs when they are overlaid as well. 7219 * 7220 * @method _adjustOverlayForVerticalThumbs 7221 * @protected 7222 */ 7223 _adjustOverlayForVerticalThumbs: function(node, useMargin) 7224 { 7225 var vtEnabled = this.get('verticalThumbsEnabled'), 7226 vtOverlay = this.get('verticalThumbsOverlay'), 7227 vtBB = null, 7228 vtPos = null, 7229 margin = typeof useMargin === 'undefined' ? '' : 'margin-', 7230 vtWidth = 0; 7231 7232 if(this.verticalThumbs && vtEnabled && vtOverlay) { 7233 vtBB = this.verticalThumbs.get('boundingBox'); 7234 vtWidth = vtBB.get('offsetWidth'); 7235 vtPos = this.get('verticalThumbsPosition'); 7236 7237 if(vtPos == 'left') { 7238 node.setStyle(margin + 'left', vtWidth + 'px'); 7239 } 7240 else { 7241 node.setStyle(margin + 'right', vtWidth + 'px'); 7242 } 7243 } 7244 }, 7245 7246 /** 7247 * Creates and renders a new instance of FL.SlideshowFrame 7248 * used for the main image. 7249 * 7250 * @method _renderFrame 7251 * @protected 7252 */ 7253 _renderFrame: function() 7254 { 7255 this.frame = new Y.FL.SlideshowFrame({ 7256 imageConfig: { 7257 loadGroup: 'main', 7258 loadPriority: true, 7259 crop: this.get('crop'),
7260 cropHorizontalsOnly: this.get('cropHorizontalsOnly'), 7261 position: this.get('position'), 7262 protect: this.get('protect'), 7263 upsize: this.get('upsize'), 7264 showVideoButton: this.get('navOverlay') 7265 }, 7266 touchSupport: this.get('touchSupport') 7267 }); 7268 7269 this.add(this.frame); 7270 this.frame.render(this.get('contentBox')); 7271 this.frame.get('boundingBox').addClass('fl-slideshow-main-image'); 7272 this._setPlayingTimerEvent(this.frame, 'transitionComplete'); 7273 this._loadingImageContainer = this.frame.get('contentBox'); 7274 }, 7275 7276 /** 7277 * Resizes the frame used for the main image. 7278 * 7279 * @method _resizeMainImage 7280 * @param width {Number} The width to resize to. 7281 * @param height {Number} The height to resize to. 7282 * @protected 7283 */ 7284 _resizeFrame: function(width, height) 7285 { 7286 var navOverlay = this.get('navOverlay'), 7287 nav = this._getNav(); 7288 7289 if(nav && !navOverlay) { 7290 height -= parseInt(nav.get('boundingBox').getComputedStyle('height'), 10); 7291 } 7292 7293 this.frame.resize(width, height); 7294 }, 7295 7296 /** 7297 * Called when the imageLoadComplete event fires. 7298 * Loads an image into the frame and preloads the next image. 7299 * 7300 * @method _loadFrame 7301 * @param e {Object} Event object containing the image info. 7302 * @protected 7303 */ 7304 _loadFrame: function(e) 7305 { 7306 var activeIndex = this.imageInfo.index, 7307 images = this.albumInfo.images, 7308 nextIndex = activeIndex + 1 >= images.length ? 0 : activeIndex + 1, 7309 width = this.frame.get('width'), 7310 height = this.frame.get('height'); 7311 7312 // Load the frame. 7313 this.frame.load(e.imageInfo); 7314 7315 // Remove main preload images from the load queue. 7316 Y.FL.SlideshowImageLoader.removeGroup('main-preload'); 7317 7318 // Preload the next image. 7319 this._nextImagePreloader.preload(images[nextIndex], width, height); 7320 }, 7321 7322 /** 7323 * Fired when the frame img tag is clicked. 7324 * 7325 * @method _frameClick 7326 * @protected 7327 */ 7328 _frameClick: function() 7329 { 7330 var clickAction = this.get('clickAction'), 7331 clickActionUrl = this.get('clickActionUrl'); 7332 7333 if(clickAction == 'url') { 7334 window.location.href = clickActionUrl; 7335 } 7336 else if(clickAction == 'gallery') { 7337 window.location.href = this.imageInfo.link; 7338 } 7339 }, 7340 7341 /** 7342 * Sets attributes to display a compact nav 7343 * for responsive layouts. 7344 * 7345 * @method _initMiniNav 7346 * @protected 7347 */ 7348 _initMiniNav: function() 7349 { 7350 var buttons = []; 7351 7352 if(this._hasNavButton('prev')) { 7353 buttons.push('prev'); 7354 } 7355 if(this._hasNavButton('thumbs') || this.get('navType') == 'thumbs') { 7356 buttons.push('thumbs'); 7357 } 7358 if(this._hasNavButton('caption')) { 7359 buttons.push('caption'); 7360 } 7361 if(this._hasNavButton('social')) { 7362 buttons.push('social'); 7363 } 7364 if(this._hasNavButton('buy')) { 7365 buttons.push('buy'); 7366 } 7367 if(this._hasNavButton('play')) { 7368 buttons.push('play'); 7369 } 7370 if(this._hasNavButton('fullscreen') && !('ontouchstart' in window)) { 7371 buttons.push('fullscreen'); 7372 } 7373 if(this._hasNavButton('next')) { 7374 buttons.push('next'); 7375 } 7376 7377 this._initialNavSettings = { 7378 buttons: this.get('navButtons'), 7379 buttonsLeft: this.get('navButtonsLeft'), 7380 buttonsRight: this.get('navButtonsRight'), 7381 type: this.get('navType') 7382 }; 7383 7384 this._set('navButtons', buttons); 7385 this._set('navButtonsLeft', []); 7386 this._set('navButtonsRight', []); 7387 this._set('navType', 'buttons'); 7388 }, 7389 7390 /** 7391 * Renders the nav and thumbs layout based on the 7392 * current window size. 7393 * 7394 * @method _renderNavAndThumbs 7395 * @protected 7396 */ 7397 _renderNavAndThumbs: function() 7398 { 7399 var navType = this.get('navType'), 7400 renderNav = false, 7401 bbWidth, 7402 threshold; 7403 7404 if(navType == 'buttons' || navType == 'thumbs') { 7405 bbWidth = this.get('boundingBox').get('offsetWidth'); 7406 threshold = this.get('responsiveThreshold'); 7407 7408 if(bbWidth <= threshold && this._initialNavSettings === null) { 7409 this._initMiniNav(); 7410 renderNav = true; 7411 } 7412 else if(bbWidth > threshold && this._initialNavSettings !== null) { 7413 this._set('navButtons', this._initialNavSettings.buttons); 7414 this._set('navButtonsLeft', this._initialNavSettings.buttonsLeft); 7415 this._set('navButtonsRight', this._initialNavSettings.buttonsRight); 7416 this._set('navType', this._initialNavSettings.type); 7417 this._initialNavSettings = null; 7418 renderNav = true; 7419 } 7420 7421 // Button nav 7422 if(renderNav || this.nav === null) { 7423 this._renderNav(); 7424 } 7425 7426 // Thumbs nav 7427 if(renderNav || this.thumbs === null) { 7428 this._renderThumbs(); 7429 } 7430 else if(this._thumbsEnabled()) { 7431 this._resizeThumbs(); 7432 } 7433 7434 // Caption 7435 if(renderNav && this.caption !== null) { 7436 this._syncCaption(); 7437 } 7438 7439 // Social 7440 if(renderNav && this.social !== null) { 7441 this._syncSocial(); 7442 } 7443 } 7444 }, 7445 7446 /** 7447 * Creates and renders a new instance of FL.SlideshowNav 7448 * used for the main nav. 7449 * 7450 * @method _renderNav 7451 * @protected 7452 */ 7453 _renderNav: function() 7454 { 7455 var frameBB = this.frame.get('boundingBox'), 7456 navBB = null, 7457 navOverlay = this.get('navOverlay'), 7458 navPosition = this.get('navPosition'); 7459 7460 // Destroy old instances 7461 this._destroyNav(); 7462 7463 // Create a new instance 7464 if(this.get('navType') == 'buttons') { 7465 7466 // Create the nav 7467 this.nav = new Y.FL.SlideshowNav({ 7468 buttons: this.get('navButtons'),
7469 buttonsLeft: this.get('navButtonsLeft'), 7470 buttonsRight: this.get('navButtonsRight') 7471 }); 7472 7473 // Add to widget parent and render 7474 this.add(this.nav); 7475 this.nav.render(this.get('contentBox')); 7476 navBB = this.nav.get('boundingBox'); 7477 7478 // Plug overlay? 7479 if(navOverlay) { 7480 this.nav.plug(Y.FL.SlideshowOverlay, { 7481 hideDelay: this.get('overlayHideDelay') 7482 }); 7483 7484 navBB.setStyle('position', 'absolute'); 7485 navBB.setStyle(navPosition, '0px'); 7486 } 7487 7488 // Insert 7489 if(navPosition == 'top') { 7490 frameBB.insert(navBB, 'before'); 7491 } 7492 else { 7493 frameBB.insert(navBB, 'after'); 7494 } 7495 7496 // CSS class name 7497 navBB.addClass('fl-slideshow-main-nav'); 7498 } 7499 }, 7500 7501 /** 7502 * Destroy the current nav instance. 7503 * 7504 * @method _destroyNav 7505 * @protected 7506 */ 7507 _destroyNav: function() 7508 { 7509 if(this.nav !== null) { 7510 if(this.nav.slideshowOverlay) { 7511 this.nav.slideshowOverlay.destroy(); 7512 } 7513 7514 this.nav.get('boundingBox').remove(); 7515 this.remove(this.nav); 7516 try { this.nav.destroy(true); } catch(e) {} 7517 this.nav = null; 7518 } 7519 }, 7520 7521 /** 7522 * Returns the nav object or null if navType is 7523 * set to none or custom. 7524 * 7525 * @method _getNav 7526 * @protected 7527 */ 7528 _getNav: function() 7529 { 7530 var navType = this.get('navType'); 7531 7532 if(navType == 'buttons') { 7533 return this.nav; 7534 } 7535 else if(navType == 'thumbs') { 7536 return this.thumbs; 7537 } 7538 else { 7539 return null; 7540 } 7541 }, 7542 7543 /** 7544 * Toggles the visibility of the nav or thumbs nav 7545 * if navOverlay is set to true. 7546 * 7547 * @method _toggleNav 7548 * @protected 7549 */ 7550 _toggleNav: function() 7551 { 7552 var nav = this._getNav(); 7553 7554 if(nav.slideshowOverlay) { 7555 if(nav.slideshowOverlay._visible) { 7556 nav.slideshowOverlay.hideWithTimer(); 7557 } 7558 else { 7559 nav.slideshowOverlay.show(); 7560 } 7561 } 7562 }, 7563 7564 /** 7565 * Creates and renders two instances of FL.SlideshowNav for the 7566 * prev and next button that will be overlaid on the main image. 7567 * 7568 * @method _renderImageNav 7569 * @protected 7570 */ 7571 _renderImageNav: function() 7572 { 7573 var ssBB; 7574 7575 if(this.get('imageNavEnabled')) { 7576 if(this._isMobile()) { 7577 this._set('imageNavEnabled', false); 7578 } 7579 else { 7580 ssBB = this.get('boundingBox'); 7581 7582 this.imageNavLeft = new Y.FL.SlideshowNav({ 7583 buttons: ['prev'], 7584 useFontIcons: false 7585 }); 7586 7587 this.imageNavRight = new Y.FL.SlideshowNav({ 7588 buttons: ['next'], 7589 useFontIcons: false 7590 }); 7591 7592 this.add(this.imageNavLeft); 7593 this.add(this.imageNavRight); 7594 7595 this.imageNavLeft.render(this.frame.get('boundingBox')); 7596 this.imageNavRight.render(this.frame.get('boundingBox')); 7597 7598 this.imageNavLeft.plug(Y.FL.SlideshowOverlay, { hideDelay: this.get('overlayHideDelay') }); 7599 this.imageNavRight.plug(Y.FL.SlideshowOverlay, { hideDelay: this.get('overlayHideDelay') }); 7600 7601 if(this.get('overlayHideOnMousemove')) { 7602 this.frame.once('transitionComplete', this.imageNavLeft.slideshowOverlay.hideWithTimer, this.imageNavLeft.slideshowOverlay); 7603 this.frame.once('transitionComplete', this.imageNavRight.slideshowOverlay.hideWithTimer, this.imageNavRight.slideshowOverlay); 7604 ssBB.on('mousemove', Y.bind(this._toggleImageNav, this)); 7605 ssBB.on('mouseenter', Y.bind(this._toggleImageNav, this)); 7606 } 7607 7608 this.imageNavLeft.get('boundingBox').addClass('fl-slideshow-image-nav-left'); 7609 this.imageNavRight.get('boundingBox').addClass('fl-slideshow-image-nav-right'); 7610 } 7611 } 7612 }, 7613 7614 /** 7615 * @method _positionImageNav 7616 * @protected 7617 */ 7618 _positionImageNav: function() 7619 { 7620 var leftBB = this.imageNavLeft.get('boundingBox'), 7621 rightBB = this.imageNavRight.get('boundingBox'), 7622 imageNavHeight = leftBB.get('offsetHeight'), 7623 frameHeight = this.frame.get('boundingBox').get('offsetHeight'), 7624 top = frameHeight/2 - imageNavHeight/2, 7625 styles = { 7626 top: top + 'px', 7627 display: 'block' 7628 }; 7629 7630 leftBB.setStyles(styles); 7631 rightBB.setStyles(styles); 7632 7633 this._adjustOverlayForVerticalThumbs(leftBB); 7634 this._adjustOverlayForVerticalThumbs(rightBB); 7635 }, 7636 7637 /** 7638 * Toggles the visibility of the image nav buttons. 7639 * 7640 * @method _toggleImageNav 7641 * @protected 7642 */ 7643 _toggleImageNav: function() 7644 { 7645 if(this.imageNavLeft.slideshowOverlay._visible) { 7646 this.imageNavLeft.slideshowOverlay.hideWithTimer(); 7647 } 7648 else { 7649 this.imageNavLeft.slideshowOverlay.show(); 7650 } 7651 7652 if(this.imageNavRight.slideshowOverlay._visible) { 7653 this.imageNavRight.slideshowOverlay.hideWithTimer(); 7654 } 7655 else { 7656 this.imageNavRight.slideshowOverlay.show(); 7657 } 7658 }, 7659 7660 /** 7661 * @method _renderMouseNav 7662 * @protected 7663 */ 7664 _renderMouseNav: function() 7665 { 7666 if(this.get('mouseNavEnabled') && !('ontouchstart' in window) && !window.navigator.msPointerEnabled) { 7667 this.plug(Y.FL.SlideshowMouseNav, { 7668 trigger: this.frame.get('boundingBox') 7669 }); 7670 } 7671 }, 7672 7673 /** 7674 * Checks whether the thumbs are enabled. 7675 * 7676 * @method _thumbsEnabled 7677 * @protected 7678 * @returns Boolean 7679 */ 7680 _thumbsEnabled: function() 7681 { 7682 var navType = this.get('navType'); 7683 7684 if(navType == 'thumbs') { 7685 return true; 7686 } 7687 if((navType == 'buttons' || navType == 'custom') && this._hasNavButton('thumbs')) { 7688 return true; 7689 } 7690 else { 7691 return false;
7692 } 7693 }, 7694 7695 /** 7696 * Creates and renders a new instance of FL.SlideshowThumbs. 7697 * 7698 * @method _renderThumbs 7699 * @protected 7700 */ 7701 _renderThumbs: function() 7702 { 7703 var frameBB, navOverlay, navPosition, navType; 7704 7705 // Destroy old instances 7706 this._destroyThumbs(); 7707 7708 // Create a new instance 7709 if(this._thumbsEnabled()) { 7710 frameBB = this.frame.get('boundingBox'); 7711 navOverlay = this.get('navOverlay'); 7712 navPosition = this.get('navPosition'); 7713 navType = this.get('navType'); 7714 7715 // Create the thumbs 7716 this.thumbs = new Y.FL.SlideshowThumbs(this._getThumbsConfig()); 7717 7718 // This breaks sometimes on SM Next. Try/catch bandaid for now. 7719 try { this.add(this.thumbs); } catch(e) {} 7720 7721 // Overlay setup 7722 if(navType == 'buttons' || navType == 'custom') { 7723 this.thumbs.plug(Y.FL.SlideshowOverlay, { 7724 hideDelay: this.get('overlayHideDelay'), 7725 hideStyle: 'left', 7726 visible: false 7727 }); 7728 } 7729 else if(navType == 'thumbs' && navOverlay) { 7730 this.thumbs.plug(Y.FL.SlideshowOverlay, { 7731 hideDelay: this.get('overlayHideDelay'), 7732 hideStyle: 'left' 7733 }); 7734 } 7735 7736 // Insert 7737 this.thumbs.render(this.get('contentBox')); 7738 7739 if(navPosition == 'top') { 7740 frameBB.insert(this.thumbs.get('boundingBox'), 'before'); 7741 } 7742 else { 7743 frameBB.insert(this.thumbs.get('boundingBox'), 'after'); 7744 } 7745 7746 // Hide overlay thumbs on click 7747 if(this.get('thumbsHideOnClick') && navType != 'thumbs') { 7748 this.thumbs.on('imageClick', Y.bind(this._hideThumbsOnImageClick, this)); 7749 } 7750 7751 this._syncThumbs(); 7752 } 7753 }, 7754 7755 /** 7756 * Destroy the current thumbs instance. 7757 * 7758 * @method _destroyThumbs 7759 * @protected 7760 */ 7761 _destroyThumbs: function() 7762 { 7763 if(this.thumbs !== null) { 7764 if(this.thumbs.slideshowOverlay) { 7765 this.thumbs.slideshowOverlay.destroy(); 7766 } 7767 7768 this.thumbs.get('boundingBox').remove(); 7769 this.remove(this.thumbs); 7770 try { this.thumbs.destroy(true); } catch(e) {} 7771 this.thumbs = null; 7772 } 7773 }, 7774 7775 /** 7776 * Syncs the thumbs UI styles. 7777 * 7778 * @method _syncThumbs 7779 * @protected 7780 */ 7781 _syncThumbs: function() 7782 { 7783 var thumbsBB = this.thumbs.get('boundingBox'), 7784 navOverlay = this.get('navOverlay'), 7785 navPosition = this.get('navPosition'), 7786 navType = this.get('navType'), 7787 paddingType = 'padding' + navPosition.charAt(0).toUpperCase() + navPosition.slice(1), 7788 navHeight = 0; 7789 7790 if(navType == 'buttons') { 7791 navHeight = parseInt(this.nav.get('boundingBox').getComputedStyle('height'), 10); 7792 thumbsBB.setStyle('position', 'absolute'); 7793 7794 if(navOverlay) { 7795 thumbsBB.setStyle(paddingType, navHeight + 'px'); 7796 thumbsBB.setStyle(navPosition, '0px'); 7797 } 7798 else { 7799 thumbsBB.setStyle(navPosition, navHeight + 'px'); 7800 } 7801 } 7802 if(navType == 'custom' || (navType == 'thumbs' && navOverlay)) { 7803 thumbsBB.setStyle('position', 'absolute'); 7804 thumbsBB.setStyle(navPosition, '0px'); 7805 } 7806 7807 this.thumbs.resize(); 7808 }, 7809 7810 /** 7811 * Prepares and returns the thumbs config object. 7812 * 7813 * @method _getThumbsConfig 7814 * @protected 7815 * @returns Object 7816 */ 7817 _getThumbsConfig: function() 7818 { 7819 var attrs = this.getAttrs(), 7820 navType = this.get('navType'), 7821 imageConfig = { 7822 crop: attrs.thumbsImageCrop, 7823 width: attrs.thumbsImageWidth, 7824 height: attrs.thumbsImageHeight 7825 }, 7826 config = { 7827 columns: 'auto', 7828 rows: 1, 7829 horizontalSpacing: attrs.thumbsHorizontalSpacing, 7830 verticalSpacing: attrs.thumbsVerticalSpacing, 7831 spaceEvenly: attrs.thumbsSpaceEvenly, 7832 centerSinglePage: attrs.thumbsCenterSinglePage, 7833 pauseOnClick: attrs.thumbsPauseOnClick, 7834 transition: attrs.thumbsTransition, 7835 transitionDirection: attrs.thumbsTransitionDirection, 7836 transitionEasing: attrs.thumbsTransitionEasing, 7837 leftNavButtons: attrs.navButtonsLeft, 7838 rightNavButtons: attrs.navButtonsRight, 7839 imageConfig: imageConfig, 7840 touchSupport: true 7841 }; 7842 7843 if(navType == 'buttons' || navType == 'custom') { 7844 if('ontouchstart' in window) { 7845 config.leftNavEnabled = false; 7846 config.rightNavEnabled = false; 7847 } 7848 else { 7849 config.centerSinglePage = false;
7850 config.leftNavButtons = ['prevPage']; 7851 config.rightNavButtons = ['nextPage']; 7852 } 7853 } 7854 7855 return config; 7856 }, 7857 7858 /** 7859 * Resizes the thumbs. 7860 * 7861 * @method _resizeThumbs 7862 * @protected 7863 */ 7864 _resizeThumbs: function() 7865 { 7866 if(this.thumbs) { 7867 this.thumbs.resize(); 7868 } 7869 }, 7870 7871 /** 7872 * Shows or hides the thumbs. 7873 * 7874 * @method _toggleThumbs 7875 * @protected 7876 */ 7877 _toggleThumbs: function() 7878 { 7879 this._toggleOverlay(this.thumbs.slideshowOverlay); 7880 }, 7881 7882 /** 7883 * Hides the thumbs when a thumb image is clicked. 7884 * 7885 * @method _hideThumbsOnImageClick 7886 * @protected 7887 */ 7888 _hideThumbsOnImageClick: function() 7889 { 7890 if(this.thumbs.slideshowOverlay) { 7891 this.thumbs.slideshowOverlay._focus = false; 7892 this.thumbs.slideshowOverlay.enable(); 7893 this.thumbs.slideshowOverlay.hide(); 7894 7895 if(this.nav && this.nav.slideshowOverlay) { 7896 this.nav.slideshowOverlay.enable(); 7897 } 7898 } 7899 }, 7900 7901 /** 7902 * Creates and renders a new instance of FL.SlideshowCaption. 7903 * 7904 * @method _renderCaption 7905 * @protected 7906 */ 7907 _renderCaption: function() 7908 { 7909 if(this._hasNavButton('caption')) { 7910 7911 this.caption = new Y.FL.SlideshowCaption({ 7912 lessLinkText: this.get('captionLessLinkText'), 7913 moreLinkText: this.get('captionMoreLinkText'), 7914 textLength: this.get('captionTextLength'), 7915 stripTags: this.get('captionStripTags') 7916 }); 7917 7918 this.add(this.caption); 7919 7920 this.caption.plug(Y.FL.SlideshowOverlay, { 7921 hideDelay: this.get('overlayHideDelay'), 7922 visible: false, 7923 closeButton: true 7924 }); 7925 7926 this._syncCaption(); 7927 } 7928 }, 7929 7930 /** 7931 * Syncs the caption UI styles. 7932 * 7933 * @method _syncCaption 7934 * @protected 7935 */ 7936 _syncCaption: function() 7937 { 7938 var captionBB = this.caption.get('boundingBox'), 7939 navOverlay = this.get('navOverlay'), 7940 navPosition = this.get('navPosition'), 7941 nav = this._getNav(), 7942 paddingType = 'padding' + navPosition.charAt(0).toUpperCase() + navPosition.slice(1), 7943 navHeight = 0; 7944 7945 captionBB.setStyle('position', 'absolute'); 7946 7947 if(nav) { 7948 navHeight = parseInt(nav.get('boundingBox').getComputedStyle('height'), 10); 7949 } 7950 7951 if(nav && navOverlay) { 7952 captionBB.setStyle(paddingType, navHeight + 'px'); 7953 captionBB.setStyle(navPosition, '0px'); 7954 } 7955 else { 7956 captionBB.setStyle(navPosition, navHeight + 'px'); 7957 } 7958 }, 7959 7960 /** 7961 * Shows or hides the caption. 7962 * 7963 * @method _toggleCaption 7964 * @protected 7965 */ 7966 _toggleCaption: function() 7967 { 7968 this._toggleOverlay(this.caption.slideshowOverlay); 7969 }, 7970 7971 /** 7972 * Creates and renders a new instance of FL.SlideshowSocial. 7973 * 7974 * @method _renderSocial 7975 * @protected 7976 */ 7977 _renderSocial: function() 7978 { 7979 if(this._hasNavButton('social')) { 7980 this.social = new Y.FL.SlideshowSocial(); 7981 this.add(this.social); 7982 7983 this.social.plug(Y.FL.SlideshowOverlay, { 7984 hideDelay: this.get('overlayHideDelay'), 7985 visible: false, 7986 closeButton: true 7987 }); 7988 7989 this._syncSocial(); 7990 } 7991 }, 7992 7993 /** 7994 * Syncs the social UI styles. 7995 * 7996 * @method _syncSocial 7997 * @protected 7998 */ 7999 _syncSocial: function() 8000 { 8001 var socialBB = this.social.get('boundingBox'), 8002 navOverlay = this.get('navOverlay'), 8003 navPosition = this.get('navPosition'), 8004 nav = this._getNav(), 8005 paddingType = 'padding' + navPosition.charAt(0).toUpperCase() + navPosition.slice(1), 8006 navHeight = 0; 8007 8008 socialBB.setStyle('position', 'absolute'); 8009 8010 if(nav) { 8011 navHeight = parseInt(nav.get('boundingBox').getComputedStyle('height'), 10); 8012 } 8013 if(nav && navOverlay) { 8014 socialBB.setStyle(paddingType, navHeight + 'px'); 8015 socialBB.setStyle(navPosition, '0px'); 8016 } 8017 else { 8018 socialBB.setStyle(navPosition, navHeight + 'px'); 8019 } 8020 }, 8021 8022 /** 8023 * Shows or hides the social buttons. 8024 * 8025 * @method _toggleSocial 8026 * @protected 8027 */ 8028 _toggleSocial: function() 8029 { 8030 this._toggleOverlay(this.social.slideshowOverlay); 8031 // Refresh iframe to fix tweet button issue visibility inside hidden elements 8032 var iFrame = jQuery('.fl-slideshow-social-content').find('iframe'); 8033 iFrame.remove(); 8034 jQuery('.fl-slideshow-social-content').prepend(iFrame); 8035 }, 8036 8037 /** 8038 * Shows or hides an overlaid widget based 8039 * on its current visibility. 8040 * 8041 * @method _toggleOverlay 8042 * @param overlay {Object} The overlay to toggle. 8043 * @protected 8044 */ 8045 _toggleOverlay: function(overlay) 8046 { 8047 var navType = this.get('navType'), 8048 nav = this._getNav(); 8049 8050 if(overlay._visible) { 8051 if(nav && nav.slideshowOverlay) { 8052 nav.slideshowOverlay.enable(); 8053 } 8054 overlay.enable(); 8055 overlay.hide(); 8056 } 8057 else { 8058 if(nav && nav.slideshowOverlay) { 8059 nav.slideshowOverlay.disable(); 8060 } 8061 overlay.show(); 8062 overlay.disable(); 8063 } 8064 8065 if(this.thumbs && navType != 'thumbs' && this.thumbs.slideshowOverlay !== overlay) { 8066 this.thumbs.slideshowOverlay.enable(); 8067 this.thumbs.slideshowOverlay.hide(); 8068 } 8069 if(this.caption && this.caption.slideshowOverlay !== overlay) { 8070 this.caption.slideshowOverlay.enable(); 8071 this.caption.slideshowOverlay.hide(); 8072 } 8073 if(this.social && this.social.slideshowOverlay !== overlay) { 8074 this.social.slideshowOverlay.enable(); 8075 this.social.slideshowOverlay.hide(); 8076 } 8077 }, 8078 8079 /** 8080 * Called when an overlay's close button is clicked. 8081 * 8082 * @method _overlayCloseClick 8083 * @protected 8084 */ 8085 _overlayCloseClick: function() 8086 { 8087 if(this.nav && this.nav.slideshowOverlay) { 8088 this.nav.slideshowOverlay.enable(); 8089 } 8090 if(this.thumbs && this.thumbs.slideshowOverlay) { 8091 this.thumbs.slideshowOverlay.enable(); 8092 } 8093 if(this.caption) { 8094 this.caption.slideshowOverlay.enable(); 8095 } 8096 if(this.social) { 8097 this.social.slideshowOverlay.enable(); 8098 } 8099 if(this.imageNavLeft) { 8100 this.imageNavLeft.slideshowOverlay.enable(); 8101 this.imageNavRight.slideshowOverlay.enable(); 8102 } 8103 }, 8104 8105 /** 8106 * Hides all overlaid widgets. 8107 * 8108 * @method _hideAllOverlays 8109 * @protected 8110 */ 8111 _hideAllOverlays: function() 8112 { 8113 if(this.nav && this.nav.slideshowOverlay && this.nav.slideshowOverlay._visible) { 8114 this.nav.slideshowOverlay.enable(); 8115 this.nav.slideshowOverlay.hideWithTimer(); 8116 } 8117 if(this.thumbs && this.thumbs.slideshowOverlay && this.thumbs.slideshowOverlay._visible) { 8118 this.thumbs.slideshowOverlay.enable(); 8119 this.thumbs.slideshowOverlay.hideWithTimer(); 8120 } 8121 if(this.caption && this.caption.slideshowOverlay._visible) { 8122 this.caption.slideshowOverlay.enable(); 8123 this.caption.slideshowOverlay.hideWithTimer(); 8124 } 8125 if(this.social && this.social.slideshowOverlay._visible) { 8126 this.social.slideshowOverlay.enable(); 8127 this.social.slideshowOverlay.hideWithTimer(); 8128 } 8129 if(this.imageNavLeft) { 8130 this.imageNavLeft.slideshowOverlay.enable(); 8131 this.imageNavLeft.slideshowOverlay.hideWithTimer(); 8132 this.imageNavRight.slideshowOverlay.enable(); 8133 this.imageNavRight.slideshowOverlay.hideWithTimer(); 8134 } 8135 }, 8136 8137 /** 8138 * Checks if overlays are still visible when the mouse enters 8139 * the bounding box. If they are, overlay functionality is disabled 8140 * until the overlays are closed by a button or the mouse leaves 8141 * the bounding box. If only the nav overlay is visible, this 8142 * function does nothing. 8143 *
8144 * @method _checkOverlaysOnMouseenter 8145 * @protected 8146 */ 8147 _checkOverlaysOnMouseenter: function() 8148 { 8149 var navType = this.get('navType'), 8150 navOverlay = this.get('navOverlay'), 8151 nav = this._getNav(), 8152 overlayVisible = false; 8153 8154 if(this.thumbs && navType != 'thumbs' && this.thumbs.slideshowOverlay._visible) { 8155 overlayVisible = true; 8156 this.thumbs.slideshowOverlay.disable(); 8157 } 8158 else if(this.caption && this.caption.slideshowOverlay._visible) { 8159 overlayVisible = true; 8160 this.caption.slideshowOverlay.disable(); 8161 } 8162 else if(this.social && this.social.slideshowOverlay._visible) { 8163 overlayVisible = true; 8164 this.social.slideshowOverlay.disable(); 8165 } 8166 8167 if(nav && overlayVisible && navOverlay) { 8168 nav.slideshowOverlay.disable(); 8169 } 8170 }, 8171 8172 /** 8173 * Checks whether a nav button is set or not. 8174 * 8175 * @method _hasNavButton 8176 * @protected 8177 * @param button {String} The button to look for. 8178 * @returns Boolean 8179 */ 8180 _hasNavButton: function(button) 8181 { 8182 var navType = this.get('navType'); 8183 8184 if(navType == 'buttons' || navType == 'thumbs' || navType == 'custom') { 8185 if(Y.Array.indexOf(this.get('navButtons'), button) > -1) { 8186 return true; 8187 } 8188 else if(Y.Array.indexOf(this.get('navButtonsLeft'), button) > -1) { 8189 return true; 8190 } 8191 else if(Y.Array.indexOf(this.get('navButtonsRight'), button) > -1) { 8192 return true; 8193 } 8194 else { 8195 return false; 8196 } 8197 } 8198 else { 8199 return false; 8200 } 8201 }, 8202 8203 /** 8204 * @method _removeNavButton 8205 * @param button {String} The name of the button to remove. 8206 * @protected 8207 */ 8208 _removeNavButton: function(button) 8209 { 8210 var buttons = this.get('navButtons'), 8211 buttonsLeft = this.get('navButtonsLeft'), 8212 buttonsRight = this.get('navButtonsRight'), 8213 vtTopNavButtons = this.get('verticalThumbsTopNavButtons'), 8214 vtBottomNavButtons = this.get('verticalThumbsBottomNavButtons'); 8215 8216 if(Y.Array.indexOf(buttons, button) > -1) { 8217 buttons.splice(Y.Array.indexOf(buttons, button), 1); 8218 } 8219 if(Y.Array.indexOf(buttonsLeft, button) > -1) { 8220 buttonsLeft.splice(Y.Array.indexOf(buttonsLeft, button), 1); 8221 } 8222 if(Y.Array.indexOf(buttonsRight, button) > -1) { 8223 buttonsRight.splice(Y.Array.indexOf(buttonsRight, button), 1); 8224 } 8225 if(Y.Array.indexOf(vtTopNavButtons, button) > -1) { 8226 vtTopNavButtons.splice(Y.Array.indexOf(vtTopNavButtons, button), 1); 8227 } 8228 if(Y.Array.indexOf(vtBottomNavButtons, button) > -1) { 8229 vtBottomNavButtons.splice(Y.Array.indexOf(vtBottomNavButtons, button), 1); 8230 } 8231 8232 this._set('navButtons', buttons); 8233 this._set('navButtonsLeft', buttonsLeft); 8234 this._set('navButtonsRight', buttonsRight); 8235 this._set('verticalThumbsTopNavButtons', vtTopNavButtons); 8236 this._set('verticalThumbsBottomNavButtons', vtBottomNavButtons); 8237 } 8238 8239}, { 8240 8241 /** 8242 * Custom CSS class name for the widget. 8243 * 8244 * @property CSS_PREFIX
8245 * @type String 8246 * @protected 8247 * @static 8248 */ 8249 CSS_PREFIX: 'fl-slideshow', 8250 8251 /** 8252 * Static property used to define the default attribute configuration of 8253 * the Widget. 8254 * 8255 * @property ATTRS 8256 * @type Object 8257 * @protected 8258 * @static 8259 */ 8260 ATTRS: { 8261 8262 /** 8263 * What should happen when the main image is clicked. 8264 * Options are none, gallery and url. If url is chosen, 8265 * clickActionUrl must be set. 8266 * 8267 * @attribute clickAction 8268 * @type String 8269 * @default none 8270 */ 8271 clickAction: { 8272 value: 'none' 8273 }, 8274 8275 /** 8276 * The redirect url to use when clickAction is set to url. 8277 * 8278 * @attribute clickActionUrl 8279 * @type String 8280 * @default none 8281 */ 8282 clickActionUrl: { 8283 value: '' 8284 }, 8285 8286 /** 8287 * Whether to crop the main image. 8288 * 8289 * @attribute crop 8290 * @type Boolean 8291 * @default false 8292 */ 8293 crop: { 8294 value: false 8295 }, 8296 8297 /** 8298 * Whether to only crop horizontal images or not. 8299 * 8300 * @attribute cropHorizontalsOnly 8301 * @type Boolean 8302 * @default false 8303 */ 8304 cropHorizontalsOnly: { 8305 value: false 8306 }, 8307 8308 /** 8309 * Whether to always use the loading image between images 8310 * or to only use it between albums. 8311 * 8312 * @attribute loadingImageAlwaysEnabled 8313 * @type Boolean 8314 * @default true 8315 */ 8316 loadingImageAlwaysEnabled: { 8317 value: true 8318 }, 8319 8320 /** 8321 * The x and y position of the main image 8322 * within the bounding box. 8323 * 8324 * @attribute position
8325 * @type String 8326 * @default center center 8327 */ 8328 position: { 8329 value: 'center center' 8330 }, 8331 8332 /** 8333 * Whether to right click protect the main image. 8334 * 8335 * @attribute protect 8336 * @type Boolean 8337 * @default true 8338 */ 8339 protect: { 8340 value: true 8341 }, 8342 8343 /** 8344 * Whether to resize the main image past 8345 * its original width and height. 8346 * 8347 * @attribute upsize 8348 * @type Boolean 8349 * @default true 8350 */ 8351 upsize: { 8352 value: true 8353 }, 8354 8355 /** 8356 * The type of transition to use. Possible values are 8357 * none, fade, slideHorizontal and slideVertical. The 8358 * value can also be a common seperated string of transitions 8359 * that will be randomly chosen for each image. 8360 * 8361 * @attribute transition 8362 * @type String 8363 * @default fade 8364 */ 8365 transition: { 8366 value: 'fade' 8367 }, 8368 8369 /** 8370 * The duration of the transition, measured in seconds. 8371 * 8372 * @attribute transitionDuration 8373 * @type Number 8374 * @default 1 8375 */ 8376 transitionDuration: { 8377 value: 1 8378 }, 8379 8380 /** 8381 * The type of transition easing to use. 8382 * 8383 * @attribute transitionEasing
8384 * @type String 8385 * @default ease-out 8386 */ 8387 transitionEasing: { 8388 value: 'ease-out' 8389 }, 8390 8391 /** 8392 * The amount of zoom to use for the Ken Burns effect. 8393 * 8394 * @attribute kenBurnsZoom 8395 * @type Number 8396 * @default 1.2 8397 */ 8398 kenBurnsZoom: { 8399 value: 1.2 8400 }, 8401 8402 /** 8403 * The type of navigation to use. Possible values are 8404 * buttons, thumbs, custon and none. 8405 * 8406 * @attribute navType 8407 * @type String 8408 * @default none 8409 */ 8410 navType: { 8411 value: 'none' 8412 }, 8413 8414 /** 8415 * The position of the main nav. Possible values are top and bottom. 8416 * 8417 * @attribute navPosition 8418 * @type String 8419 * @default bottom 8420 */ 8421 navPosition: { 8422 value: 'bottom' 8423 }, 8424 8425 /** 8426 * Whether to overlay the nav on top of the main image. 8427 * 8428 * @attribute navOverlay 8429 * @type Boolean 8430 * @default false 8431 */ 8432 navOverlay: { 8433 value: false 8434 }, 8435 8436 /** 8437 * An array of button names used to render the main nav's buttons. 8438 * 8439 * @attribute navButtons 8440 * @type Array 8441 * @default [] 8442 */ 8443 navButtons: { 8444 value: [] 8445 }, 8446 8447 /** 8448 * An array of button names used to render the main nav's left buttons. 8449 * 8450 * @attribute navButtonsLeft 8451 * @type Array 8452 * @default [] 8453 */ 8454 navButtonsLeft: { 8455 value: [] 8456 }, 8457 8458 /** 8459 * An array of button names used to render the main nav's right buttons. 8460 * 8461 * @attribute navButtonsRight 8462 * @type Array 8463 * @default [] 8464 */ 8465 navButtonsRight: { 8466 value: [] 8467 }, 8468 8469 /** 8470 * Whether to hide the overlays when the mouse moves or not. 8471 * 8472 * @attribute overlayHideOnMousemove
8473 * @type String 8474 * @default mouseover 8475 */ 8476 overlayHideOnMousemove: { 8477 value: true 8478 }, 8479 8480 /** 8481 * How long to wait before hiding the overlays. 8482 * Measured in milliseconds. 8483 * 8484 * @attribute overlayHideDelay 8485 * @type Number 8486 * @default false 8487 */ 8488 overlayHideDelay: { 8489 value: 3000 8490 }, 8491 8492 /** 8493 * Whether to use the image nav or not. If true, a prev 8494 * and next button will be overlaid on the main image. 8495 * 8496 * @attribute imageNavEnabled 8497 * @type Boolean 8498 * @default false 8499 */ 8500 imageNavEnabled: { 8501 value: false 8502 }, 8503 8504 /** 8505 * Whether to use the mouse nav or not. If true, the cursor 8506 * will turn into a prev or next button when over the slideshow. 8507 * 8508 * @attribute mouseNavEnabled 8509 * @type Boolean 8510 * @default false 8511 */ 8512 mouseNavEnabled: { 8513 value: false 8514 }, 8515 8516 /** 8517 * Whether to hide the thumbs when clicking on a thumbnail 8518 * image or not. Thumbs always hide navType is set to buttons. 8519 * 8520 * @attribute thumbsHideOnClick 8521 * @type Boolean 8522 * @default false 8523 */ 8524 thumbsHideOnClick: { 8525 value: true 8526 }, 8527 8528 /** 8529 * The horizontal spacing between thumbs. 8530 * 8531 * @attribute thumbsHorizontalSpacing 8532 * @type Number 8533 * @default 15 8534 */ 8535 thumbsHorizontalSpacing: { 8536 value: 15 8537 }, 8538 8539 /** 8540 * The vertical spacing between thumbs. 8541 * 8542 * @attribute thumbsVerticalSpacing 8543 * @type Number 8544 * @default 15 8545 */ 8546 thumbsVerticalSpacing: { 8547 value: 15 8548 }, 8549 8550 /** 8551 * Whether to space the thumbs evenly within a page. 8552 * 8553 * @attribute thumbsSpaceEvenly 8554 * @type Boolean 8555 * @default true 8556 */ 8557 thumbsSpaceEvenly: { 8558 value: true 8559 }, 8560 8561 /** 8562 * Whether to center single pages of thumbs. 8563 * 8564 * @attribute thumbsCenterSinglePage 8565 * @type Boolean 8566 * @default false 8567 */ 8568 thumbsCenterSinglePage: { 8569 value: true 8570 }, 8571 8572 /** 8573 * Whether to pause the slideshow when a thumb is clicked. 8574 * 8575 * @attribute thumbsPauseOnClick 8576 * @type Boolean 8577 * @default false 8578 */ 8579 thumbsPauseOnClick: { 8580 value: false 8581 }, 8582 8583 /** 8584 * The type of transition to use between pages of thumbs. 8585 * 8586 * @attribute thumbsTransition
8587 * @type String 8588 * @default slideHorizontal 8589 */ 8590 thumbsTransition: { 8591 value: 'slideHorizontal' 8592 }, 8593 8594 /** 8595 * The duration of the transition between pages of thumbs. 8596 * 8597 * @attribute thumbsTransitionDuration 8598 * @type Number 8599 * @default 0.8 8600 */ 8601 thumbsTransitionDuration: { 8602 value: 0.8 8603 }, 8604 8605 /** 8606 * The type of transition easing to use between pages of thumbs. 8607 * 8608 * @attribute thumbsTransitionEasing 8609 * @type String 8610 * @default ease-out 8611 */ 8612 thumbsTransitionEasing: { 8613 value: 'ease-out' 8614 }, 8615 8616 /** 8617 * Whether to crop the thumbnails. 8618 * 8619 * @attribute thumbsImageCrop 8620 * @type Boolean 8621 * @default true 8622 */ 8623 thumbsImageCrop: { 8624 value: true 8625 }, 8626 8627 /** 8628 * The width of each thumbnail. 8629 * 8630 * @attribute thumbsImageWidth 8631 * @type Number 8632 * @default 50 8633 */ 8634 thumbsImageWidth: { 8635 value: 50 8636 }, 8637 8638 /** 8639 * The height of each thumbnail. 8640 * 8641 * @attribute thumbsImageHeight 8642 * @type Number 8643 * @default 50 8644 */ 8645 thumbsImageHeight: { 8646 value: 50 8647 }, 8648 8649 /** 8650 * The text to use for the "read less" toggle link. 8651 * 8652 * @attribute captionLessLinkText
8653 * @type String 8654 * @default Read Less 8655 */ 8656 captionLessLinkText: { 8657 value: 'Read Less' 8658 }, 8659 8660 /** 8661 * The text to use for the "read more" toggle link. 8662 * 8663 * @attribute captionMoreLinkText 8664 * @type String 8665 * @default Read More 8666 */ 8667 captionMoreLinkText: { 8668 value: 'Read More' 8669 }, 8670 8671 /** 8672 * The length of the caption to show. If greater than -1, 8673 * the text will be truncated and a read more link will 8674 * be displayed. If set to -1, the entire caption will be shown. 8675 * 8676 * @attribute captionTextLength 8677 * @type Number 8678 * @default 200 8679 */ 8680 captionTextLength: { 8681 value: 200 8682 }, 8683 8684 /** 8685 * Whether to strip out HTML tags in the caption 8686 * text or not. 8687 * 8688 * @attribute captionStripTags 8689 * @type Boolean 8690 * @default false 8691 */ 8692 captionStripTags: { 8693 value: false 8694 }, 8695 8696 /** 8697 * Whether to use the vertical thumbs or not. 8698 * 8699 * @attribute verticalThumbsEnabled 8700 * @type Boolean 8701 * @default false 8702 */ 8703 verticalThumbsEnabled: { 8704 value: false 8705 }, 8706 8707 /** 8708 * Position of the vertical thumbs. Possible values 8709 * are either left or right. 8710 * 8711 * @attribute verticalThumbsPosition
8712 * @type String 8713 * @default left 8714 */ 8715 verticalThumbsPosition: { 8716 value: 'left' 8717 }, 8718 8719 /** 8720 * Whether to overlay the vertical thumbs 8721 * on the main image or not. 8722 * 8723 * @attribute verticalThumbsOverlay 8724 * @type Boolean 8725 * @default false 8726 */ 8727 verticalThumbsOverlay: { 8728 value: false 8729 }, 8730 8731 /** 8732 * The number of columns for the vertical thumbs. 8733 * 8734 * @attribute verticalThumbsColumns 8735 * @type Number 8736 * @default 1 8737 */ 8738 verticalThumbsColumns: { 8739 value: 1 8740 }, 8741 8742 /** 8743 * Whether to use the vertical thumbs top nav or not. 8744 * 8745 * @attribute verticalThumbsTopNavEnabled 8746 * @type Boolean 8747 * @default false 8748 */ 8749 verticalThumbsTopNavEnabled: { 8750 value: false 8751 }, 8752 8753 /** 8754 * An array of button names used to render 8755 * the vertical thumbs top nav buttons. 8756 * 8757 * @attribute verticalThumbsTopNavButtons 8758 * @type Array 8759 * @default prevPage, nextPage 8760 */ 8761 verticalThumbsTopNavButtons: { 8762 value: ['prevPage', 'nextPage'] 8763 }, 8764 8765 /** 8766 * Whether to use the vertical thumbs bottom nav or not. 8767 * 8768 * @attribute verticalThumbsBottomNavEnabled 8769 * @type Boolean 8770 * @default false 8771 */ 8772 verticalThumbsBottomNavEnabled: { 8773 value: true 8774 }, 8775 8776 /** 8777 * An array of button names used to render 8778 * the vertical thumbs top nav buttons. 8779 * 8780 * @attribute verticalThumbsBottomNavButtons 8781 * @type Array 8782 * @default prevPage, nextPage 8783 */ 8784 verticalThumbsBottomNavButtons: { 8785 value: ['prevPage', 'nextPage'] 8786 }, 8787 8788 /** 8789 * The horizontal spacing between vertical thumbs. 8790 * 8791 * @attribute verticalThumbsHorizontalSpacing 8792 * @type Number 8793 * @default 15 8794 */ 8795 verticalThumbsHorizontalSpacing: { 8796 value: 15 8797 }, 8798 8799 /** 8800 * The vertical spacing between vertical thumbs. 8801 * 8802 * @attribute verticalThumbsVerticalSpacing 8803 * @type Number 8804 * @default 15 8805 */ 8806 verticalThumbsVerticalSpacing: { 8807 value: 15 8808 }, 8809 8810 /** 8811 * Whether to space the vertical thumbs evenly within a page. 8812 * 8813 * @attribute verticalThumbsSpaceEvenly 8814 * @type Boolean 8815 * @default false 8816 */ 8817 verticalThumbsSpaceEvenly: { 8818 value: false 8819 }, 8820 8821 /** 8822 * Whether to pause the slideshow when a vertical thumb is clicked. 8823 * 8824 * @attribute verticalThumbsPauseOnClick 8825 * @type Boolean 8826 * @default false 8827 */ 8828 verticalThumbsPauseOnClick: { 8829 value: false 8830 }, 8831 8832 /** 8833 * Whether to crop the vertical thumbs or not. 8834 * 8835 * @attribute verticalThumbsImageCrop 8836 * @type Boolean 8837 * @default true 8838 */ 8839 verticalThumbsImageCrop: { 8840 value: true 8841 }, 8842 8843 /** 8844 * The width of each vertical thumbnail. 8845 * 8846 * @attribute verticalThumbsImageWidth 8847 * @type Number 8848 * @default 75 8849 */ 8850 verticalThumbsImageWidth: { 8851 value: 75 8852 }, 8853 8854 /** 8855 * The height of each vertical thumbnail. 8856 * 8857 * @attribute verticalThumbsImageHeight 8858 * @type Number 8859 * @default 75 8860 */ 8861 verticalThumbsImageHeight: { 8862 value: 75 8863 }, 8864 8865 /** 8866 * The type of transition to use between pages of vertical thumbs. 8867 * 8868 * @attribute verticalThumbsTransition
8869 * @type String 8870 * @default slideVertical 8871 */ 8872 verticalThumbsTransition: { 8873 value: 'slideVertical' 8874 }, 8875 8876 /** 8877 * The duration of the transition between pages of vertical thumbs. 8878 * 8879 * @attribute verticalThumbsTransitionDuration 8880 * @type Number 8881 * @default 0.8 8882 */ 8883 verticalThumbsTransitionDuration: { 8884 value: 0.8 8885 }, 8886 8887 /** 8888 * The type of transition easing to use between pages of vertical thumbs. 8889 * 8890 * @attribute verticalThumbsTransitionEasing 8891 * @type String 8892 * @default ease-out 8893 */ 8894 verticalThumbsTransitionEasing: { 8895 value: 'ease-out' 8896 }, 8897 8898 /** 8899 * Whether to use the Facebook like button or not. 8900 * 8901 * @attribute likeButtonEnabled 8902 * @type Boolean 8903 * @default true 8904 */ 8905 likeButtonEnabled: { 8906 value: true 8907 }, 8908 8909 /** 8910 * Whether to use the Pinterest button or not. 8911 * 8912 * @attribute pinterestButtonEnabled 8913 * @type Boolean 8914 * @default true 8915 */ 8916 pinterestButtonEnabled: { 8917 value: true 8918 }, 8919 8920 /** 8921 * Whether to use the Tweet button or not. 8922 * 8923 * @attribute tweetButtonEnabled 8924 * @type Boolean 8925 * @default true 8926 */ 8927 tweetButtonEnabled: { 8928 value: true 8929 }, 8930 8931 /** 8932 * Whether to use touch gestures, when available, 8933 * to transition between images or not. 8934 * 8935 * @attribute touchSupport 8936 * @type Boolean 8937 * @default true 8938 */ 8939 touchSupport: { 8940 value: true 8941 } 8942 } 8943}); 8944 8945 8946}, '2.0.0' ,{requires:['anim', 'event-mouseenter', 'plugin', 'transition', 'fl-event-move', 'fl-slideshow-css', 'fl-slideshow-base', 'fl-utils', 'sm-fonticon']}); 8947 8948 8949YUI.add('fl-slideshow-album-loader', function(Y) { 8950 8951/** 8952 * @module fl-slideshow-album-loader 8953 */ 8954 8955/** 8956 * Loads slideshow albums using a provided source object. 8957 * 8958 * @namespace FL 8959 * @class SlideshowAlbumLoader 8960 * @constructor 8961 * @param config {Object} Configuration object 8962 * @extends Base 8963 */ 8964Y.namespace('FL').SlideshowAlbumLoader = Y.Base.create('fl-slideshow-album-loader', Y.Base, [], { 8965 8966 /** 8967 * The source object used for loading. 8968 * 8969 * @property _source 8970 * @type Object 8971 * @default null 8972 * @protected 8973 */ 8974 _source: null, 8975 8976 /** 8977 * Loads slideshow album data using the provided source object. 8978 * 8979 * @method load 8980 * @param source {Object} The source object to use for loading. 8981 */ 8982 load: function(source) 8983 { 8984 this._source = source; 8985 8986 /** 8987 * Fires before a new load request is made. 8988 * 8989 * @event start 8990 */ 8991 this.fire('start'); 8992 8993 this[Y.FL.SlideshowAlbumLoader.TYPES[source.type]].call(this); 8994 }, 8995 8996 /** 8997 * Called when a source type completes loading 8998 * and fires the complete event. 8999 * 9000 * @method _loadComplete 9001 * @param o {Object} Passed to complete event subscribers. 9002 * @protected 9003 */ 9004 _loadComplete: function(o) 9005 { 9006 o = this._randomize(o); 9007 9008 /** 9009 * Fires after a new load request is made. 9010 * 9011 * @event complete 9012 */ 9013 this.fire('complete', o); 9014 }, 9015 9016 /** 9017 * Randomizes images in an album. 9018 * 9019 * @method _randomize 9020 * @param album {Object} The album to randomize. 9021 * @protected 9022 */ 9023 _randomize: function(o) 9024 { 9025 var i; 9026 9027 if(this.get('randomize')) { 9028 o.albumInfo.images.sort(function() { return 0.5 - Math.random(); }); 9029 9030 for(i = 0; i < o.albumInfo.images.length; i++) { 9031 o.albumInfo.images[i].index = i; 9032 } 9033 } 9034 9035 return o; 9036 }, 9037 9038 /** 9039 * Loads slideshow album data from SmugMug. 9040 * 9041 * @method _loadSmugMug 9042 * @protected 9043 */ 9044 _loadSmugMug: function() 9045 { 9046 var sm = new Y.FL.SmugMugAPI(); 9047 9048 sm.on('complete', this._loadSmugMugSuccess, this); 9049 sm.addParam('method', 'smugmug.images.get'); 9050 sm.addParam('AlbumID', this._source.id); 9051 sm.addParam('AlbumKey', this._source.key); 9052 sm.addParam('Extras', 'Caption,Format,FileName'); 9053 9054 // Gallery password 9055 if(this._source.password) { 9056 sm.addParam('Password', this._source.password); 9057 } 9058 9059 // Site-wide password 9060 if(this._source.sp) { 9061 sm.addParam('SitePassword', this._source.sp); 9062 } 9063 9064 sm.request(); 9065 }, 9066 9067 /** 9068 * Processes slideshow album data loaded from SmugMug. 9069 * 9070 * @method _loadSmugMugSuccess 9071 * @param e {Object} The custom event object passed to this function. 9072 * @protected 9073 */ 9074 _loadSmugMugSuccess: function(e) 9075 { 9076 var images = e.Album.Images, 9077 album = {}, 9078 proxy = typeof this._source.proxy !== 'undefined' ? this._source.proxy : '', 9079 buyBase = '', 9080 baseURL = '', 9081 ext = '', 9082 format = '', 9083 i = 0, 9084 temp = null, 9085 iframe = null; 9086 9087 album.index = this._source.index; 9088 album.id = e.Album.id; 9089 album.key = e.Album.Key; 9090 album.link = e.Album.URL; 9091 album.title = this._source.title ? this._source.title : ''; 9092 album.images = []; 9093 buyBase = album.link.replace('https://', '').split('/').shift(); 9094 buyBase = 'https://' + buyBase + '/buy/' + e.Album.id + '_' + e.Album.Key + '/'; 9095 9096 for(i = 0; i < images.length; i++) 9097 { 9098 baseURL = proxy + e.Album.URL + '/' + images[i].id + '_' + images[i].Key; 9099 format = images[i].Format.toLowerCase(); 9100 ext = format == 'mp4' ? '.jpg' : '.' + format; 9101 9102 album.images[i] = {}; 9103 album.images[i].index = i; 9104 album.images[i].sourceType = 'smugmug'; 9105 album.images[i].albumId = e.Album.id; 9106 album.images[i].albumKey = e.Album.Key; 9107 album.images[i].id = images[i].id; 9108 album.images[i].key = images[i].Key; 9109 album.images[i].filename = images[i].FileName; 9110 album.images[i].format = format;
9111 album.images[i].caption = images[i].Caption || ''; 9112 album.images[i].link = e.Album.URL + '#' + images[i].id + '_' + images[i].Key; 9113 album.images[i].tinyURL = baseURL + '-Ti' + ext; 9114 album.images[i].thumbURL = baseURL + '-Th' + ext; 9115 album.images[i].smallURL = baseURL + '-S' + ext; 9116 album.images[i].mediumURL = baseURL + '-M' + ext; 9117 album.images[i].largeURL = baseURL + '-L' + ext; 9118 album.images[i].xlargeURL = baseURL + '-XL' + ext; 9119 album.images[i].x2largeURL = baseURL + '-X2' + ext; 9120 album.images[i].x3largeURL = baseURL + '-X3' + ext; 9121 album.images[i].buyURL = buyBase + images[i].id + '_' + images[i].Key; 9122 album.images[i].iframe = ''; 9123 9124 if(album.images[i].caption.indexOf('iframe')) { 9125 temp = Y.Node.create('<div>'+ album.images[i].caption +'</div>'); 9126 iframe = temp.one('iframe'); 9127 9128 if(iframe) { 9129 album.images[i].iframe = iframe.getAttribute('src'); 9130 album.images[i].caption = album.images[i].caption.replace(/<iframe.*>.*<\/iframe>/gi, ''); 9131 } 9132 } 9133 } 9134 9135 this._loadComplete({ 'albumInfo': album }); 9136 }, 9137 9138 /** 9139 * Loads slideshow album data from an array of urls. 9140 * 9141 * NOTE: You must have a large URL. 9142 * 9143 * @method _loadUrls 9144 * @protected 9145 */ 9146 _loadUrls: function() 9147 { 9148 var album = {}, 9149 i = 0; 9150 9151 album.index = this._source.index; 9152 album.title = this._source.title ? this._source.title : ''; 9153 album.images = []; 9154 9155 for( ; i < this._source.urls.length; i++) 9156 { 9157 album.images[i] = {}; 9158 album.images[i].index = i; 9159 album.images[i].sourceType = 'urls'; 9160 album.images[i].filename = this._source.urls[i].largeURL.split('/').pop(); 9161 album.images[i].format = ''; 9162 album.images[i].caption = this._source.urls[i].caption || ''; 9163 album.images[i].alt = this._source.urls[i].alt || ''; 9164 album.images[i].link = this._source.urls[i].largeURL; 9165 album.images[i].thumbURL = this._source.urls[i].thumbURL || this._source.urls[i].largeURL; 9166 album.images[i].smallURL = this._source.urls[i].smallURL || this._source.urls[i].largeURL; 9167 album.images[i].mediumURL = this._source.urls[i].mediumURL || this._source.urls[i].largeURL; 9168 album.images[i].largeURL = this._source.urls[i].largeURL; // Must have a large URL 9169 album.images[i].xlargeURL = this._source.urls[i].xlargeURL || this._source.urls[i].largeURL; 9170 album.images[i].x2largeURL = this._source.urls[i].x2largeURL || this._source.urls[i].largeURL; 9171 album.images[i].x3largeURL = this._source.urls[i].x3largeURL || this._source.urls[i].largeURL; 9172 album.images[i].buyURL = this._source.urls[i].buyURL || ''; 9173 album.images[i].iframe = this._source.urls[i].iframe || ''; 9174 } 9175 9176 this._loadComplete({ 'albumInfo': album }); 9177 } 9178 9179}, { 9180 9181 /** 9182 * Static property used to define the default attribute configuration of 9183 * the Widget. 9184 * 9185 * @property ATTRS 9186 * @type Object 9187 * @protected 9188 * @static 9189 */ 9190 ATTRS: { 9191 9192 /** 9193 * If true, the images will be randomized after loading. 9194 * 9195 * @attribute randomize 9196 * @type Boolean 9197 * @default false 9198 */ 9199 randomize: { 9200 value: false 9201 } 9202 }, 9203 9204 /** 9205 * The types of source data that can be loaded 9206 * and associated functions. 9207 * 9208 * @property TYPES 9209 * @type Object 9210 * @readOnly 9211 * @protected 9212 * @static 9213 */ 9214 TYPES: { 9215 'smugmug': '_loadSmugMug', 9216 'flickr': '_loadFlickr', 9217 'picasa': '_loadPicasa', 9218 'urls': '_loadUrls', 9219 'html': '_loadHtml' 9220 } 9221}); 9222 9223 9224}, '2.0.0' ,{requires:['base', 'fl-smugmug-api']}); 9225 9226 9227YUI.add('fl-slideshow-base', function(Y) { 9228 9229/** 9230 * @module fl-slideshow-base 9231 */ 9232 9233/** 9234 * The base class that gets extended when creating new 9235 * slideshow widgets. Manages loading, playing, and resizing. 9236 * <p> 9237 * While SlideshowBase can be instantiated, it is only meant to 9238 * be extended and does not display any images. 9239 * 9240 * @namespace FL 9241 * @class SlideshowBase 9242 * @constructor 9243 * @param config {Object} Configuration object 9244 * @extends Widget 9245 */ 9246Y.namespace('FL').SlideshowBase = Y.Base.create('fl-slideshow-base', Y.Widget, [Y.WidgetParent], { 9247 9248 /** 9249 * FL.SlideshowAlbumLoader instance used to load albums. 9250 * 9251 * @property _loader 9252 * @type FL.SlideshowAlbumLoader 9253 * @default null 9254 * @protected 9255 */ 9256 _albumLoader: null, 9257 9258 /** 9259 * An array of albums loaded from the source attribute. 9260 * Each album is an array of objects containing image info. 9261 * 9262 * @property albums 9263 * @type Array 9264 * @default [] 9265 */ 9266 albums: [], 9267 9268 /** 9269 * Info for the active album. 9270 * 9271 * @property albumInfo 9272 * @type Object 9273 * @default null 9274 */ 9275 albumInfo: null, 9276 9277 /** 9278 * A number that represents the index of the active 9279 * album in the albums array. 9280 * 9281 * @property albumIndex 9282 * @type Number 9283 * @default null 9284 */ 9285 albumIndex: null, 9286 9287 /** 9288 * Info for the active image. 9289 * 9290 * @property imageInfo 9291 * @type Object 9292 * @default null 9293 */ 9294 imageInfo: null, 9295 9296 /** 9297 * A number that represents the index of the active 9298 * image in the albumInfo array.
9299 * 9300 * @property imageIndex 9301 * @type Number 9302 * @default null 9303 */ 9304 imageIndex: null, 9305 9306 /** 9307 * A number that represents the index of the last 9308 * image that was loaded in the albumInfo array. 9309 * 9310 * @property lastImageIndex 9311 * @type Number 9312 * @default null 9313 */ 9314 lastImageIndex: null, 9315 9316 /** 9317 * Timer for the delay before resizing if one is set. 9318 * 9319 * @property _resizeTimer 9320 * @type Object 9321 * @default null 9322 * @protected 9323 */ 9324 _resizeTimer: null, 9325 9326 /** 9327 * Flag for whether the slideshow is currently playing or not. 9328 * 9329 * @property playing 9330 * @type Boolean 9331 * @default false 9332 * @protected 9333 */ 9334 _playing: false, 9335 9336 /** 9337 * Timer for the break in between images when 9338 * the slideshow is playing. 9339 * 9340 * @property _playingTimer 9341 * @type Object 9342 * @default null 9343 * @protected 9344 */ 9345 _playingTimer: null, 9346 9347 /** 9348 * If set, the slideshow will only auto start when 9349 * this event is fired. 9350 * 9351 * @property _playingTimerEvent 9352 * @type Object 9353 * @default null 9354 * @protected 9355 */ 9356 _playingTimerEvent: null, 9357 9358 /** 9359 * An instance of FL.Spinner that is shown and hidden 9360 * using _showLoadingImage and _hideLoadingImage when 9361 * a loading activity occurs. 9362 * 9363 * @property _loadingImage 9364 * @type FL.Spinner 9365 * @default null 9366 * @protected 9367 */ 9368 _loadingImage: null, 9369 9370 /** 9371 * An div node that wraps the loading image. 9372 * 9373 * @property _loadingImageWrap 9374 * @type Node 9375 * @default null 9376 * @protected 9377 */ 9378 _loadingImageWrap: null, 9379 9380 /** 9381 * Whether the loading image is visible or not. 9382 * 9383 * @property _loadingImageVisible 9384 * @type Boolean 9385 * @default false 9386 * @protected 9387 */ 9388 _loadingImageVisible: false, 9389 9390 /** 9391 * A timer to delay the display of the loading image. 9392 * 9393 * @property _loadingImageTimer 9394 * @type Object 9395 * @default null 9396 * @protected 9397 */ 9398 _loadingImageTimer: null, 9399 9400 /** 9401 * The container to insert the loading image into. If 9402 * no container is set, the loading image will be inserted 9403 * into the widget's bounding box. 9404 * 9405 * @property _loadingImageContainer 9406 * @type Object 9407 * @default null 9408 * @protected 9409 */ 9410 _loadingImageContainer: null, 9411 9412 /** 9413 * The intial height of the slideshow. Used to resize 9414 * back to the starting height when exiting stretchy. 9415 * 9416 * @property _initialHeight 9417 * @type Number 9418 * @default null 9419 * @protected 9420 */ 9421 _initialHeight: null, 9422 9423 /** 9424 * The intial width of the slideshow. Used to resize 9425 * back to the starting width when exiting stretchy. 9426 * 9427 * @property _initialWidth 9428 * @type Number 9429 * @default null 9430 * @protected 9431 */ 9432 _initialWidth: null, 9433 9434 /** 9435 * @method initializer 9436 * @protected 9437 */ 9438 initializer: function() 9439 { 9440 // Loader 9441 this._albumLoader = new Y.FL.SlideshowAlbumLoader({ 9442 randomize: this.get('randomize') 9443 }); 9444 }, 9445 9446 /** 9447 * @method renderUI 9448 * @protected 9449 */ 9450 renderUI: function() 9451 { 9452 this._renderLoadingImage(); 9453 }, 9454 9455 /** 9456 * @method bindUI 9457 * @protected 9458 */ 9459 bindUI: function() 9460 { 9461 // Album load complete 9462 this._albumLoader.on('complete', this._loadAlbumComplete, this); 9463 9464 // Resize Events 9465 Y.one(window).on('fl-slideshow-base|resize', this._delayResize, this); 9466 Y.one(window).on('fl-slideshow-base|orientationchange', this._delayResize, this); 9467 9468 // Key Events 9469 Y.Node.one('body').on('keydown', Y.bind(this._onKey, this)); 9470 }, 9471 9472 /** 9473 * @method syncUI 9474 * @protected 9475 */ 9476 syncUI: function() 9477 { 9478 this.get('boundingBox').addClass('fl-slideshow-' + this.get('color')); 9479 9480 this.resize(); 9481 9482 if(this.get('loadOnRender')) { 9483 this.loadAlbum(this.get('defaultAlbum'), this.get('defaultImage')); 9484 } 9485 }, 9486 9487 /** 9488 * Add album data to the source object. 9489 * 9490 * @method addAlbum 9491 * @protected 9492 */ 9493 addAlbum: function(data) 9494 { 9495 var source = this.get('source'), 9496 i = source.length; 9497 9498 source[i] = data; 9499 source[i].index = i; 9500 9501 this.set('source', source); 9502 }, 9503 9504 /** 9505 * Loads an album from the source array with the provided albumIndex. 9506 * If no albumIndex is provided, the first album in the array will be loaded. 9507 * An image to load can also be specified using imageIndex. 9508 * 9509 * @method loadAlbum 9510 * @param albumIndex {Number} The album index to load from the source array. 9511 * @param imageIndex {Number} The image index to load from the album array. 9512 */ 9513 loadAlbum: function(albumIndex, imageIndex) 9514 { 9515 var source = this.get('source'), 9516 loadImageIndex = typeof imageIndex == 'undefined' ? 0 : imageIndex; 9517 9518 // Reset internal image indexes. 9519 this.imageIndex = null; 9520 this.lastImageIndex = null; 9521 9522 /** 9523 * Fires before a new album request is made. 9524 * 9525 * @event albumLoadStart 9526 */ 9527 this.fire('albumLoadStart'); 9528 9529 // Load an image after the album. 9530 this.once('albumLoadComplete', Y.bind(this.loadImage, this, loadImageIndex)); 9531 9532 // Load data passed from another slideshow instance. 9533 if(source[albumIndex] && source[albumIndex].type == 'album-data') { 9534 this.albums[albumIndex] = source[albumIndex].data; 9535 this._loadAlbumComplete({albumInfo: this.albums[albumIndex]}); 9536 } 9537 // Load the album from the albums array. 9538 else if(source[albumIndex] && this.albums[albumIndex]) { 9539 this._loadAlbumComplete({albumInfo: this.albums[albumIndex]}); 9540 } 9541 // Load the album using the album loader. 9542 else { 9543 this._albumLoader.load(source[albumIndex] || source[0]); 9544 } 9545 }, 9546 9547 /** 9548 * Processes the loaded album and fires the albumLoadComplete event. 9549 * 9550 * @method _loadAlbumComplete 9551 * @param o {Object} The custom event object passed to this method. 9552 * @protected 9553 */ 9554 _loadAlbumComplete: function(o) 9555 { 9556 this.albums[o.albumInfo.index] = o.albumInfo; 9557 this.albumInfo = o.albumInfo; 9558 this.albumIndex = o.albumInfo.index; 9559 9560 /** 9561 * Fires after a new album request is made. 9562 * 9563 * @event albumLoadComplete 9564 */ 9565 this.fire('albumLoadComplete'); 9566 9567 // Auto Play 9568 if(this.get('autoPlay')) { 9569 this._playingTimerStart(); 9570 this.fire('played'); 9571 this._playing = true; 9572 } 9573 }, 9574 9575 /** 9576 * Sets the active image index and fires the imageLoadComplete event. 9577 * 9578 * @method loadImage 9579 * @param index {Number} The image index to load. 9580 */ 9581 loadImage: function(index) 9582 { 9583 if(this._playing) { 9584 this._playingTimerStart(); 9585 } 9586 9587 index = index < 0 ? this.albumInfo.images.length - 1 : index; 9588 index = index >= this.albumInfo.images.length ? 0 : index; 9589 9590 this.lastImageIndex = this.imageIndex; 9591 this.imageIndex = index; 9592 this.imageInfo = this.albumInfo.images[index]; 9593 9594 /** 9595 * Fires after a new image index is set. 9596 * 9597 * @event imageLoadComplete 9598 */ 9599 this.fire('imageLoadComplete', { 'imageInfo': this.imageInfo }); 9600 }, 9601 9602 /** 9603 * Loads the previous image. 9604 * 9605 * @method prevImage 9606 */ 9607 prevImage: function() 9608 { 9609 if(this.get('pauseOnNextOrPrev')) { 9610 this.pause(); 9611 } 9612 9613 this.loadImage(this.imageIndex - 1); 9614 9615 /** 9616 * Fires when the previous image is loaded. 9617 * 9618 * @event prevImage 9619 */ 9620 this.fire('prevImage'); 9621 }, 9622 9623 /** 9624 * Loads the next image. 9625 * 9626 * @method nextImage 9627 */ 9628 nextImage: function() 9629 { 9630 if(this.get('pauseOnNextOrPrev')) { 9631 this.pause(); 9632 } 9633 9634 this.loadImage(this.imageIndex + 1); 9635 9636 /** 9637 * Fires when the next image is loaded. 9638 * 9639 * @event nextImage 9640 */ 9641 this.fire('nextImage'); 9642 }, 9643 9644 /** 9645 * Keyboard navigation for the next and prev images. 9646 * 9647 * @method _onKey 9648 * @protected 9649 */ 9650 _onKey: function(e) 9651 { 9652 switch(e.keyCode) { 9653 9654 case 37: 9655 this.prevImage(); 9656 break; 9657 9658 case 39: 9659 this.nextImage(); 9660 break; 9661 } 9662 }, 9663 9664 /** 9665 * Resizes the slideshow using either the 9666 * stretchy or standard functions. 9667 * 9668 * @method resize 9669 */ 9670 resize: function() 9671 { 9672 var stretchy = this.get('stretchy'), 9673 stretchyType = this.get('stretchyType'), 9674 width = parseInt(Y.one('body').get('winWidth'), 10), 9675 threshold = this.get('responsiveThreshold'); 9676 9677 // Stretchy resize to the window only if the parent width is greater 9678 // than the responsive threshold and stretchyType is set to window. 9679 if(width > threshold && stretchy && stretchyType == 'window') { 9680 this._stretchyWindowResize(); 9681 } 9682 9683 // Ratio resize if the parent width is less than the responsive 9684 // threshold or if stretchyType is set to ratio. 9685 else if((width <= threshold) || (stretchy && stretchyType == 'ratio')) { 9686 this._stretchyRatioResize(); 9687 } 9688 9689 // Do a standard resize based on the height and 9690 // width passed to the constructor function. 9691 else { 9692 this._standardResize(); 9693 } 9694 9695 /** 9696 * Fires when the slideshow is resized. 9697 * 9698 * @event resize 9699 */ 9700 this.fire('resize'); 9701 }, 9702 9703 /** 9704 * @method _standardResize 9705 * @protected 9706 */ 9707 _standardResize: function() 9708 { 9709 var stretchy = this.get('stretchy'), 9710 stretchyType = this.get('stretchyType'), 9711 bb = this.get('boundingBox'), 9712 parent = bb.get('parentNode'), 9713 parentHeight = parseInt(parent.getComputedStyle('height'), 10), 9714 parentWidth = parseInt(parent.getComputedStyle('width'), 10), 9715 height = this.get('height'), 9716 width = this.get('width'); 9717
9718 // Window resize if we are in fullscreen. 9719 if(bb.hasClass('fl-fullscreen-active')) { 9720 this._stretchyWindowResize(); 9721 return; 9722 } 9723 9724 // Resize to the width and height of the parent. 9725 else if(stretchy && stretchyType == 'contain') { 9726 bb.setStyle('height', parentHeight + 'px'); 9727 bb.setStyle('width', parentWidth + 'px'); 9728 } 9729 9730 // Ratio resize if we don't have a height defined. 9731 else if(!Y.Lang.isNumber(height)) { 9732 this._stretchyRatioResize(); 9733 return; 9734 } 9735 9736 // Resize to the defined width and height. 9737 else { 9738 9739 bb.setStyle('height', height + 'px'); 9740 9741 if(width) { 9742 bb.setStyle('width', width + 'px'); 9743 } 9744 else { 9745 bb.setStyle('width', parentWidth + 'px'); 9746 } 9747 } 9748 }, 9749 9750 /** 9751 * Resizes to the height of the window, compensating 9752 * for any padding. 9753 * 9754 * @method _stretchyWindowResize 9755 * @protected 9756 */ 9757 _stretchyWindowResize: function() 9758 { 9759 var bb = this.get('boundingBox'), 9760 verticalSpace = this.get('stretchyVerticalSpace'), 9761 paddingTop = parseInt(bb.getStyle('paddingTop'), 10), 9762 paddingBottom = parseInt(bb.getStyle('paddingBottom'), 10), 9763 height = parseInt(Y.one('body').get('winHeight'), 10), 9764 width = ''; 9765 9766 // Set the vertical space to 0 and width to the 9767 // window's width if we are in fullscreen mode. 9768 if(bb.hasClass('fl-fullscreen-active')) { 9769 verticalSpace = 0; 9770 width = parseInt(Y.one('body').get('winWidth'), 10) + 'px'; 9771 } 9772 9773 height = (height - paddingTop - paddingBottom - verticalSpace) + 'px'; 9774 9775 bb.setStyle('height', height); 9776 bb.setStyle('width', width); 9777 }, 9778 9779 /** 9780 * Resizes the height by multiplying the width and stretchyRatio value. 9781 * 9782 * @method _stretchyRatioResize 9783 * @protected 9784 */ 9785 _stretchyRatioResize: function() 9786 { 9787 var bb = this.get('boundingBox'), 9788 parent = bb.get('parentNode'), 9789 verticalSpace = 0, 9790 stretchyRatio = this.get('stretchyRatio'), 9791 paddingTop = parseInt(bb.getStyle('paddingTop'), 10), 9792 paddingBottom = parseInt(bb.getStyle('paddingBottom'), 10), 9793 computedWidth = parseInt(parent.getComputedStyle('width'), 10), 9794 winHeight = parseInt(Y.one('body').get('winHeight'), 10), 9795 winWidth = parseInt(Y.one('body').get('winWidth'), 10), 9796 height = computedWidth * stretchyRatio, 9797 width = ''; 9798 9799 // Use the window's height and width if we are in fullscreen mode. 9800 if(bb.hasClass('fl-fullscreen-active')) { 9801 height = winHeight; 9802 width = winWidth; 9803 } 9804 9805 height = (height - paddingTop - paddingBottom - verticalSpace) + 'px'; 9806 9807 bb.setStyle('height', height); 9808 bb.setStyle('width', width); 9809 }, 9810 9811 /** 9812 * Resizes the slideshow after the resize timer completes. 9813 * 9814 * @method _delayResize 9815 * @protected 9816 */ 9817 _delayResize: function() 9818 { 9819 if(this._resizeTimer) { 9820 this._resizeTimer.cancel(); 9821 } 9822 9823 this._resizeTimer = Y.later(300, this, this.resize); 9824 }, 9825 9826 /** 9827 * Starts a new playing timer and fires the played event. 9828 * 9829 * @method play 9830 */ 9831 play: function() 9832 { 9833 this._playingTimer = Y.later(this.get('speed'), this, this._playingTimerComplete); 9834 9835 /** 9836 * Fires when the playing timer starts. 9837 * 9838 * @event played 9839 */ 9840 this.fire('played'); 9841 this._playing = true; 9842 }, 9843 9844 /** 9845 * Cancels the current playing timer and fires the paused event. 9846 * 9847 * @method pause 9848 */ 9849 pause: function() 9850 { 9851 this._playingTimerCancel(); 9852 9853 /** 9854 * Fires when the playing timer is canceled. 9855 * 9856 * @event paused 9857 */ 9858 this.fire('paused'); 9859 this._playing = false; 9860 }, 9861 9862 /** 9863 * A new playing timer will start when this event is fired. 9864 *
9865 * @method _setPlayingTimerEvent 9866 * @param obj {Object} The event's host object. 9867 * @param e {String} The event to fire on the host object. 9868 * @protected 9869 */ 9870 _setPlayingTimerEvent: function(obj, e) 9871 { 9872 this._playingTimerEvent = { 9873 'obj': obj, 9874 'e': e 9875 }; 9876 }, 9877 9878 /** 9879 * Cancels the playing timer if it is running and starts a new one. 9880 * The next image is loaded when the timer completes. 9881 * 9882 * @method _playingTimerStart 9883 * @protected 9884 */ 9885 _playingTimerStart: function(e) 9886 { 9887 this._playingTimerCancel(); 9888 9889 if(!e && this._playingTimerEvent !== null) { 9890 this._playingTimerEvent.obj.once('fl-slideshow-base|' + this._playingTimerEvent.e, Y.bind(this._playingTimerStart, this)); 9891 } 9892 else { 9893 this._playingTimer = Y.later(this.get('speed'), this, this._playingTimerComplete); 9894 } 9895 }, 9896 9897 /** 9898 * Fires when the playing timer completes, starts a 9899 * new timer and loads the next image. 9900 * 9901 * @method _playingTimerComplete 9902 * @protected 9903 */ 9904 _playingTimerComplete: function() 9905 { 9906 this.loadImage(this.imageIndex + 1); 9907 9908 /** 9909 * Fires when the playing timer completes. 9910 * 9911 * @event albumLoadStart 9912 */ 9913 this.fire('playingTimerComplete'); 9914 }, 9915 9916 /** 9917 * Cancels the playing timer. 9918 * 9919 * @method _playingTimerCancel 9920 * @protected 9921 */ 9922 _playingTimerCancel: function() 9923 { 9924 if(this._playingTimer) { 9925 this._playingTimer.cancel(); 9926 } 9927 if(this._playingTimerEvent) { 9928 this._playingTimerEvent.obj.detach('fl-slideshow-base|' + this._playingTimerEvent.e); 9929 } 9930 }, 9931 9932 /** 9933 * Creates the loading image. 9934 * 9935 * @method _renderLoadingImage 9936 * @protected 9937 */ 9938 _renderLoadingImage: function() 9939 { 9940 var defaults = { 9941 lines: 11, // The number of lines to draw 9942 length: 6, // The length of each line 9943 width: 2, // The line thickness 9944 radius: 7, // The radius of the inner circle 9945 color: '', // #rbg or #rrggbb 9946 speed: 1, // Rounds per second 9947 trail: 60, // Afterglow percentage 9948 shadow: false // Whether to render a shadow 9949 }, 9950 settings = Y.merge(defaults, this.get('loadingImageSettings')); 9951 9952 if(this.get('loadingImageEnabled')) { 9953 9954 // Loading image 9955 if(settings.color === '') { 9956 settings.color = this._colorToHex(Y.one('body').getStyle('color')); 9957 } 9958 9959 this._loadingImage = new Y.FL.Spinner(settings); 9960 9961 // Loading image wrap 9962 this._loadingImageWrap = Y.Node.create('<div class="fl-loading-image"></div>'); 9963 9964 this._loadingImageWrap.setStyles({ 9965 position : 'absolute', 9966 'z-index' : '1000' 9967 }); 9968 } 9969 }, 9970 9971 /** 9972 * Inserts the loading image. 9973 * 9974 * @method _showLoadingImage 9975 * @protected 9976 */ 9977 _showLoadingImage: function() 9978 { 9979 if(this._loadingImage && !this._loadingImageVisible) { 9980 9981 this._loadingImageVisible = true; 9982 this._loadingImage.spin(); 9983 this._loadingImageWrap.insert(this._loadingImage.el); 9984 9985 if(this._loadingImageContainer !== null) { 9986 this._loadingImageContainer.insert(this._loadingImageWrap); 9987 } 9988 else { 9989 this.get('contentBox').insert(this._loadingImageWrap); 9990 } 9991 9992 this._positionLoadingImage(); 9993 } 9994 }, 9995 9996 /** 9997 * Inserts the loading image div node after 9998 * a timer completes. 9999 * 10000 * @method _showLoadingImageWithDelay 10001 * @protected 10002 */ 10003 _showLoadingImageWithDelay: function() 10004 { 10005 if(this._loadingImage) { 10006 this._loadingImageTimer = Y.later(1000, this, this._showLoadingImage); 10007 } 10008 }, 10009 10010 /** 10011 * Removes the loading image div node. 10012 * 10013 * @method _hideLoadingImage 10014 * @protected 10015 */ 10016 _hideLoadingImage: function() 10017 { 10018 if(this._loadingImageTimer) { 10019 this._loadingImageTimer.cancel(); 10020 this._loadingImageTimer = null; 10021 } 10022 if(this._loadingImage && this._loadingImageVisible) { 10023 this._loadingImageVisible = false; 10024 this._loadingImage.stop(); 10025 this._loadingImageWrap.remove(); 10026 } 10027 }, 10028 10029 /** 10030 * Centers the loading image in the content box. 10031 * 10032 * @method _positionLoadingImage 10033 * @protected 10034 */ 10035 _positionLoadingImage: function() 10036 { 10037 if(this._loadingImage && this._loadingImageVisible) { 10038 10039 var wrap = this._loadingImageWrap, 10040 wrapHeight = parseInt(wrap.getComputedStyle('height'), 10), 10041 wrapWidth = parseInt(wrap.getComputedStyle('width'), 10), 10042 parent = wrap.get('parentNode'), 10043 parentHeight = parseInt(parent.getComputedStyle('height'), 10), 10044 parentWidth = parseInt(parent.getComputedStyle('width'), 10), 10045 left = (parentWidth - wrapWidth)/2, 10046 top = (parentHeight - wrapHeight)/2; 10047 10048 wrap.setStyles({ 10049 left : left + 'px', 10050 top : top + 'px' 10051 }); 10052 10053 Y.one(this._loadingImage.el).setStyles({ 10054 left : '50%', 10055 top : '50%' 10056 }); 10057 } 10058 }, 10059 10060 /** 10061 * Convert RGB color value to a hex value. 10062 *
10063 * @method _colorToHex 10064 * @protected 10065 */ 10066 _colorToHex: function(color) 10067 { 10068 var digits, red, green, blue, rgb; 10069 10070 if(color.substr(0, 1) === '#') { 10071 return color; 10072 } 10073 10074 digits = /(.*?)rgb\((\d+), (\d+), (\d+)\)/.exec(color); 10075 10076 if ( null === digits ) { 10077 return '#000'; 10078 } 10079 10080 red = parseInt(digits[2], 10); 10081 green = parseInt(digits[3], 10); 10082 blue = parseInt(digits[4], 10); 10083 rgb = blue | (green << 8) | (red << 16); 10084 rgb = rgb.toString(16); 10085 10086 if(rgb === '0') { 10087 rgb = '000'; 10088 } 10089 10090 return digits[1] + '#' + rgb; 10091 } 10092 10093}, { 10094 10095 /** 10096 * Custom CSS class name for the widget. 10097 * 10098 * @property CSS_PREFIX 10099 * @type String 10100 * @protected 10101 * @static 10102 */ 10103 CSS_PREFIX: 'fl-slideshow-base', 10104 10105 /** 10106 * Static property used to define the default attribute configuration of 10107 * the Widget. 10108 * 10109 * @property ATTRS 10110 * @type Object 10111 * @protected 10112 * @static 10113 */ 10114 ATTRS: { 10115 10116 /** 10117 * Used to create the color class that gets added to the bounding box 10118 * when the widget is rendered. The color class is used to create new 10119 * CSS color themes. The default CSS provided includes dark and light themes. 10120 * 10121 * @attribute color
10122 * @type String 10123 * @default dark 10124 * @writeOnce 10125 */ 10126 color: { 10127 value: 'dark', 10128 writeOnce: true 10129 }, 10130 10131 /** 10132 * An array of source objects used to load albums. Each object must have 10133 * a type property and can have a title property as well. 10134 * <p> 10135 * In addition to those properties, each object has additional required 10136 * properties specific to its type. The types currently supported are 10137 * smugmug and urls with planned support for flickr and picasa. 10138 * See the user guide for information on loading different types. 10139 * 10140 * @attribute source 10141 * @type Array 10142 * @default [] 10143 * @writeOnce 10144 */ 10145 source: { 10146 value: [], 10147 setter: function(source) { 10148 10149 if(source.constructor == Object) { 10150 source = [source]; 10151 } 10152 10153 for(var i = 0; i < source.length; i++) { 10154 source[i].index = i; 10155 } 10156 10157 return source; 10158 } 10159 }, 10160 10161 /** 10162 * The default album index to load. 10163 * 10164 * @attribute defaultAlbum 10165 * @type Number 10166 * @default 0 10167 */ 10168 defaultAlbum: { 10169 value: 0 10170 }, 10171 10172 /** 10173 * The default image index to load. 10174 * 10175 * @attribute defaultImage 10176 * @type Number 10177 * @default 0 10178 */ 10179 defaultImage: { 10180 value: 0 10181 }, 10182 10183 /** 10184 * If true, the slideshow will be loaded after rendering. 10185 * 10186 * @attribute loadOnRender 10187 * @type Boolean 10188 * @default true 10189 */ 10190 loadOnRender: { 10191 value: true 10192 }, 10193 10194 /** 10195 * If true, the slideshow will start playing after loading. 10196 * 10197 * @attribute autoPlay 10198 * @type Boolean 10199 * @default true 10200 */ 10201 autoPlay: { 10202 value: true 10203 }, 10204 10205 /** 10206 * Whether to pause when the next or previous image is loaded 10207 * using nextImage or prevImage. The slideshow will not be paused 10208 * if the next or previous image is loaded using loadImage as is the 10209 * case when the slideshow is playing. 10210 * 10211 * @attribute pauseOnNextOrPrev 10212 * @type Boolean 10213 * @default true 10214 */ 10215 pauseOnNextOrPrev: { 10216 value: true 10217 }, 10218 10219 /** 10220 * If true, the images will be randomized after loading. 10221 * 10222 * @attribute randomize 10223 * @type Boolean 10224 * @default false 10225 */ 10226 randomize: { 10227 value: false 10228 }, 10229 10230 /** 10231 * The time between images when playing, measured in milliseconds. 10232 * 10233 * @attribute speed 10234 * @type Number 10235 * @default 4000 10236 */ 10237 speed: { 10238 value: 4000 10239 }, 10240 10241 /** 10242 * The minimum width of the parent node at which 10243 * responsive features are enabled. Set to 0 to 10244 * disable responsive features as they are enabled 10245 * whether stretchy is set to true or not. 10246 * 10247 * @attribute responsiveThreshold 10248 * @type Number 10249 * @default 600 10250 */ 10251 responsiveThreshold: { 10252 value: 600 10253 }, 10254 10255 /** 10256 * Whether stretchy resizing should be enabled. 10257 * 10258 * @attribute stretchy 10259 * @type Boolean 10260 * @default false 10261 */ 10262 stretchy: { 10263 value: false 10264 }, 10265 10266 /** 10267 * The type of stretchy logic to use. Possible values are 10268 * window and ratio. Both types resize the width of the 10269 * slideshow to the width of its parent node. With window, the 10270 * height of the slideshow is resized to the height of the window. 10271 * With ratio, the height of the slideshow is resized based 10272 * on the ratio set with stretchyRatio or the height of the window 10273 * if the ratio height is greater than the window height. 10274 * 10275 * @attribute stretchyType
10276 * @type String 10277 * @default ratio 10278 */ 10279 stretchyType: { 10280 value: 'ratio' 10281 }, 10282 10283 /** 10284 * The number of pixels to subtract from the height of 10285 * the slideshow when stretchy is set to true. 10286 * 10287 * @attribute stretchyVerticalSpace 10288 * @type Number 10289 * @default 0 10290 */ 10291 stretchyVerticalSpace: { 10292 value: 0 10293 }, 10294 10295 /** 10296 * Used to calculate the height of the slideshow when stretchyType 10297 * is set to ratio. 10298 * 10299 * @attribute stretchyRatio 10300 * @type Number 10301 * @default 0.7 10302 */ 10303 stretchyRatio: { 10304 value: 0.7 10305 }, 10306 10307 /** 10308 * Whether to use the loading image or not. 10309 * 10310 * @attribute loadingImageEnabled 10311 * @type Boolean 10312 * @default true 10313 */ 10314 loadingImageEnabled: { 10315 value: true 10316 }, 10317 10318 /** 10319 * Property object for setting up the spin.js loading image. 10320 * For a complete list of properties see: 10321 * http://effinroot.eiremedia.netdna-cdn.com/repo/plugins/misc/spin.js/index.html 10322 * 10323 * @attribute loadingImageSettings 10324 * @type Object 10325 */ 10326 loadingImageSettings: { 10327 value: {} 10328 } 10329 } 10330}); 10331 10332 10333}, '2.0.0' ,{requires:['node', 'base', 'widget', 'widget-parent', 'widget-child', 'fl-slideshow-album-loader', 'fl-spinner']}); 10334 10335 10336YUI.add('fl-smugmug-api', function(Y) { 10337 10338/** 10339 * @module fl-smugmug-api 10340 */ 10341 10342/** 10343 * SmugMug API wrapper. 10344 * 10345 * NOTE: Only anonymous logins are currently supported. 10346 * 10347 * @namespace FL 10348 * @class SmugMugAPI 10349 * @constructor 10350 * @param config {Object} Configuration object 10351 * @extends Base 10352 */ 10353Y.namespace('FL').SmugMugAPI = Y.Base.create('fl-smugmug-api', Y.Base, [], { 10354 10355 /** 10356 * ID for the current session. 10357 * 10358 * @property _sessionID
10359 * @type String 10360 * @default null 10361 * @protected 10362 */ 10363 _sessionID: null, 10364 10365 /** 10366 * URL with parameters for the next API request. 10367 * Reset after each request. 10368 * 10369 * @property _requestURL 10370 * @type String 10371 * @default null 10372 * @protected 10373 */ 10374 _requestURL: null, 10375 10376 /** 10377 * Lifecycle method. Initializes the request url. 10378 * 10379 * @method initializer 10380 * @protected 10381 */ 10382 initializer: function() 10383 { 10384 this._resetRequestURL(); 10385 }, 10386 10387 /** 10388 * Adds a key/value pair to the request url. 10389 * 10390 * @method addParam 10391 * @param key {String} The name of the parameter (example: key=val). 10392 * @param val {String} The value of the parameter (example: key=val). 10393 */ 10394 addParam: function(key, val) 10395 { 10396 this._requestURL = this._requestURL + '&' + key + '=' + val; 10397 }, 10398 10399 /** 10400 * Requests an anonymous login session. 10401 * 10402 * @method loginAnon 10403 */ 10404 loginAnon: function() 10405 { 10406 this.addParam('method', 'smugmug.login.anonymously'); 10407 this.once('complete', this._loginAnonComplete); 10408 this.request(); 10409 }, 10410 10411 /** 10412 * Anonymous login success handler. 10413 * 10414 * @method _loginAnonComplete 10415 * @param data {Object} A jsonp data object. 10416 * @protected 10417 */ 10418 _loginAnonComplete: function(data) 10419 { 10420 if(data.Login) { 10421 this._sessionID = data.Login.Session.id; 10422 } 10423 }, 10424 10425 /** 10426 * Sends an API request using the request url. 10427 * 10428 * @method request 10429 */ 10430 request: function() 10431 { 10432 this.addParam('Callback', '{callback}'); 10433 10434 Y.jsonp(this._requestURL, { 10435 on: { 10436 success: this._requestComplete, 10437 timeout: function(){} // TODO: Handle timeouts 10438 }, 10439 context: this, 10440 timeout: 60000, 10441 args: [] 10442 }); 10443 }, 10444 10445 /** 10446 * API request complete handler. 10447 * 10448 * @method _requestComplete 10449 * @param data {Object} A jsonp data object. 10450 * @protected 10451 */ 10452 _requestComplete: function(data) 10453 { 10454 this._resetRequestURL(); 10455 10456 /** 10457 * Fires when a request is complete. 10458 * 10459 * @event complete 10460 */ 10461 this.fire('complete', data); 10462 }, 10463 10464 /** 10465 * Clears all parameters on the request url except 10466 * the API key and session ID. 10467 * 10468 * @method _resetRequestURL 10469 * @protected 10470 */ 10471 _resetRequestURL: function() 10472 { 10473 this._requestURL = this.get('apiURL') + '?APIKey=' + this.get('apiKey'); 10474 10475 if(this._sessionID) { 10476 this.addParam('SessionID', this._sessionID); 10477 } 10478 } 10479 10480}, { 10481 10482 /** 10483 * Static property used to define the default attribute configuration of 10484 * the Widget. 10485 * 10486 * @property ATTRS 10487 * @type Object 10488 * @protected 10489 * @static 10490 */ 10491 ATTRS: { 10492 10493 /** 10494 * SmugMug API url to use for requests. 10495 * 10496 * @attribute apiUrl
10497 * @type String 10498 * @default https://api.smugmug.com/services/api/json/1.3.0/ 10499 */ 10500 apiURL: { 10501 value: 'https://api.smugmug.com/services/api/json/1.3.0/' 10502 }, 10503 10504 /** 10505 * SmugMug API key. 10506 * 10507 * @attribute apiKey 10508 * @type String 10509 * @default 7w6kuU5Ee6KSgRRExf2KLgppdkez9JD2 10510 */ 10511 apiKey: { 10512 value: '7w6kuU5Ee6KSgRRExf2KLgppdkez9JD2' 10513 } 10514 } 10515}); 10516 10517 10518}, '2.0.0' ,{requires:['base', 'jsonp']}); 10519 10520 10521YUI.add('fl-spinner', function(Y) { 10522 10523(function(window,document,undefined){var width="width",length="length",radius="radius",lines="lines",trail="trail",color="color",opacity="opacity",speed="speed",shadow="shadow",style="style",height="height",left="left",top="top",px="px",childNodes="childNodes",firstChild="firstChild",parentNode="parentNode",position="position",relative="relative",absolute="absolute",animation="animation",transform="transform",Origin="Origin",Timeout="Timeout",coord="coord",black="#000",styleSheets=style+"Sheets",prefixes="webkit0Moz0ms0O".split(0),animations={},useCssAnimations;function eachPair(args,it){var end=~~((args[length]-1)/2);for(var i=1;i<=end;i++){it(args[i*2-1],args[i*2])}}function createEl(tag){var el=document.createElement(tag||"div");eachPair(arguments,function(prop,val){el[prop]=val});return el}function ins(parent,child1,child2){if(child2&&!child2[parentNode]){ins(parent,child2)}parent.insertBefore(child1,child2||null);return parent}ins(document.getElementsByTagName("head")[0],createEl(style));var sheet=document[styleSheets][document[styleSheets][length]-1];function addAnimation(to,end){var name=[opacity,end,~~(to*100)].join("-"),dest="{"+opacity+":"+to+"}",i;if(!animations[name]){for(i=0;i<prefixes[length];i++){try{sheet.insertRule("@"+(prefixes[i]&&"-"+prefixes[i].toLowerCase()+"-"||"")+"keyframes "+name+"{0%{"+opacity+":1}"+end+"%"+dest+"to"+dest+"}",sheet.cssRules[length])}catch(err){}}animations[name]=1}return name}function vendor(el,prop){var s=el[style],pp,i;if(s[prop]!==undefined){return prop}prop=prop.charAt(0).toUpperCase()+prop.slice(1);for(i=0;i<prefixes[length];i++){pp=prefixes[i]+prop;if(s[pp]!==undefined){return pp}}}function css(el){eachPair(arguments,function(n,val){el[style][vendor(el,n)||n]=val});return el}function defaults(obj){eachPair(arguments,function(prop,val){if(obj[prop]===undefined){obj[prop]=val}});return obj}var Spinner=function Spinner(o){this.opts=defaults(o||{},lines,12,trail,100,length,7,width,5,radius,10,color,black,opacity,1/4,speed,1)},proto=Spinner.prototype={spin:function(target){var self=this,el=self.el=self[lines](self.opts);if(target){ins(target,css(el,left,~~(target.offsetWidth/2)+px,top,~~(target.offsetHeight/2)+px),target[firstChild])}if(!useCssAnimations){var o=self.opts,i=0,f=20/o[speed],ostep=(1-o[opacity])/(f*o[trail]/100),astep=f/o[lines];(function anim(){i++;for(var s=o[lines];s;s--){var alpha=Math.max(1-(i+s*astep)%f*ostep,o[opacity]);self[opacity](el,o[lines]-s,alpha,o)}self[Timeout]=self.el&&window["set"+Timeout](anim,50)})()}return self},stop:function(){var self=this,el=self.el;window["clear"+Timeout](self[Timeout]);if(el&&el[parentNode]){el[parentNode].removeChild(el)}self.el=undefined;return self}};proto[lines]=function(o){var el=css(createEl(),position,relative),animationName=addAnimation(o[opacity],o[trail]),i=0,seg;function fill(color,shadow){return css(createEl(),position,absolute,width,(o[length]+o[width])+px,height,o[width]+px,"background",color,"boxShadow",shadow,transform+Origin,left,transform,"rotate("+~~(360/o[lines]*i)+"deg) translate("+o[radius]+px+",0)","borderRadius","100em")}for(;i<o[lines];i++){seg=css(createEl(),position,absolute,top,1+~(o[width]/2)+px,transform,"translate3d(0,0,0)",animation,animationName+" "+1/o[speed]+"s linear infinite "+(1/o[lines]/o[speed]*i-1/o[speed])+"s");if(o[shadow]){ins(seg,css(fill(black,"0 0 4px "+black),top,2+px))}ins(el,ins(seg,fill(o[color],"0 0 1px rgba(0,0,0,.1)")))}return el};proto[opacity]=function(el,i,val){el[childNodes][i][style][opacity]=val};var behavior="behavior",URL_VML="url(#default#VML)",tag="group0roundrect0fill0stroke".split(0);(function(){var s=css(createEl(tag[0]),behavior,URL_VML),i;if(!vendor(s,transform)&&s.adj){for(i=0;i<tag[length];i++){sheet.addRule(tag[i],behavior+":"+URL_VML)}proto[lines]=function(){var o=this.opts,r=o[length]+o[width],s=2*r;function grp(){return css(createEl(tag[0],coord+"size",s+" "+s,coord+Origin,-r+" "+-r),width,s,height,s)}var g=grp(),margin=~(o[length]+o[radius]+o[width])+px,i;function seg(i,dx,filter){ins(g,ins(css(grp(),"rotation",360/o[lines]*i+"deg",left,~~dx),ins(css(createEl(tag[1],"arcsize",1),width,r,height,o[width],left,o[radius],top,-o[width]/2,"filter",filter),createEl(tag[2],color,o[color],op
10523acity,o[opacity]),createEl(tag[3],opacity,0))))}if(o[shadow]){for(i=1;i<=o[lines];i++){seg(i,-2,"progid:DXImage"+transform+".Microsoft.Blur(pixel"+radius+"=2,make"+shadow+"=1,"+shadow+opacity+"=.3)")}}for(i=1;i<=o[lines];i++){seg(i)}return ins(css(createEl(),"margin",margin+" 0 0 "+margin,position,relative),g)};proto[opacity]=function(el,i,val,o){o=o[shadow]&&o[lines]||0;el[firstChild][childNodes][i+o][firstChild][firstChild][opacity]=val}}else{useCssAnimations=vendor(s,animation)}})();Y.namespace('FL').Spinner=Spinner})(window,document); 10524 10525 10526}, '2.0.0' ); 10527 10528 10529YUI.add('fl-utils', function(Y) { 10530 10531/** 10532 * @module fl-utils 10533 */ 10534 10535/** 10536 * General helper functions for all FastLine modules. 10537 * 10538 * @namespace FL 10539 * @class Utils 10540 * @constructor 10541 * @static 10542 */ 10543Y.namespace('FL').Utils = { 10544 10545 /** 10546 * Checks for support of the provided CSS property. 10547 * Method adapted from: https://gist.github.com/556448 10548 * 10549 * @method cssSupport 10550 * @param p {String} The property to check. 10551 * @returns Boolean 10552 */ 10553 cssSupport: function(p) 10554 { 10555 var b = document.body || document.documentElement, 10556 s = b.style, 10557 v = ['Moz', 'Webkit', 'Khtml', 'O', 'ms', 'Icab'], 10558 i = 0; 10559 10560 // Transform not working well in these browsers 10561 if(p == 'transform' && Y.UA.gecko && Y.UA.gecko < 4) { return false; } 10562 if(p == 'transform' && Y.UA.opera > 0) { return false; } 10563 if(p == 'transform' && Y.UA.ie > 0 && Y.UA.ie < 10) { return false; } 10564 if(p == 'transform' && navigator.userAgent.match(/Trident/)) { return false; } 10565 10566 // No css support detected 10567 if(typeof s == 'undefined') { return false; } 10568 10569 // Tests for standard prop 10570 if(typeof s[p] == 'string') { return true; } 10571 10572 // Tests for vendor specific prop 10573 p = p.charAt(0).toUpperCase() + p.substr(1); 10574 10575 for( ; i < v.length; i++) { 10576 if(typeof s[v[i] + p] == 'string') { return true; } 10577 } 10578 } 10579}; 10580 10581 10582}, '2.0.0' );
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.