1 /* 2 * Copyright © 2009 Apple Inc. All rights reserved. 3 */ 4 5 // --------------------------------------------------- 6 // A crossfading slideshow view 7 // --------------------------------------------------- 8 9 // data source method names 10 const TKSlideshowViewNumberOfElements = 'slideshowViewNumberOfElements'; 11 const TKSlideshowViewElementAtIndex = 'slideshowViewElementAtIndex'; 12 13 const TKSlideshowViewDidShowElementAtIndex = 'slideshowViewDidFocusElementAtIndex'; 14 const TKSlideshowViewDidHideElementAtIndex = 'slideshowViewDidHideElementAtIndex'; // TODO: XXX 15 16 // css protocol 17 const TKSlideshowViewCSSContainerClass = 'slideshow-view'; 18 const TKSlideshowViewCSSElementClass = 'slideshow-view-element'; 19 20 TKSlideshowView.synthetizes = ['dataSource', 21 'delegate', 22 'activeElementIndex', // the index of the currently displayed element 23 'duration', // time between automatic advance, in ms 24 'fadeDuration', // the time each crossfade will take, in ms 25 'numberOfElements']; 26 27 function TKSlideshowView (element) { 28 this.callSuper(); 29 this._activeElementIndex = null; 30 this._duration = 3000; 31 this._fadeDuration = 1000; 32 this._playing = false; 33 34 if (element) { 35 this.container = element; 36 } else { 37 // create the element we'll use as a container 38 this.container = document.createElement("div"); 39 } 40 this.container.addClassName(TKSlideshowViewCSSContainerClass); 41 42 this.currentElement = null; 43 } 44 45 TKSlideshowView.prototype.init = function () { 46 47 if (!this.dataSource || 48 !TKUtils.objectHasMethod(this.dataSource, TKSlideshowViewNumberOfElements) || 49 !TKUtils.objectHasMethod(this.dataSource, TKSlideshowViewElementAtIndex)) { 50 return; 51 } 52 53 this.showElement(); 54 }; 55 56 TKSlideshowView.prototype.setActiveElementIndex = function (newActiveElementIndex) { 57 58 if (newActiveElementIndex >= 0 && 59 newActiveElementIndex < this.numberOfElements && 60 newActiveElementIndex != this._activeElementIndex) { 61 62 // return early if this is the first time we've been set/initialised 63 if (this._activeElementIndex === null) { 64 this._activeElementIndex = newActiveElementIndex; 65 return; 66 } 67 68 // call delegate to inform hide of current active element 69 if (TKUtils.objectHasMethod(this.delegate, TKSlideshowViewDidHideElementAtIndex)) { 70 this.delegate[TKSlideshowViewDidHideElementAtIndex](this, this._activeElementIndex); 71 } 72 73 this._activeElementIndex = newActiveElementIndex; 74 75 this.showElement(); 76 } 77 }; 78 79 TKSlideshowView.prototype.getNumberOfElements = function () { 80 this._numberOfElements = this.dataSource[TKSlideshowViewNumberOfElements](this); 81 return this._numberOfElements; 82 }; 83 84 TKSlideshowView.prototype.advance = function () { 85 if (this._playing) { 86 if (this.activeElementIndex < this.numberOfElements - 1) { 87 this.activeElementIndex++; 88 } else { 89 this.activeElementIndex = 0; 90 } 91 var _this = this; 92 setTimeout(function() { 93 _this.advance(); 94 }, this._duration); 95 } 96 }; 97 98 TKSlideshowView.prototype.play = function () { 99 if (!this._playing) { 100 this._playing = true; 101 var _this = this; 102 setTimeout(function() { 103 _this.advance(); 104 }, this._duration); 105 } 106 }; 107 108 TKSlideshowView.prototype.pause = function () { 109 this._playing = false; 110 }; 111 112 TKSlideshowView.prototype.reset = function () { 113 this._playing = false; 114 this.currentElement = null; 115 }; 116 117 TKSlideshowView.prototype.showElement = function () { 118 119 var oldElement = this.currentElement; 120 121 var el = this.dataSource[TKSlideshowViewElementAtIndex](this, this._activeElementIndex); 122 el.addClassName(TKSlideshowViewCSSElementClass); 123 el.style.webkitTransitionProperty = "opacity"; 124 el.style.webkitTransitionDuration = this._fadeDuration + "ms"; 125 el.style.opacity = 0; 126 127 if (oldElement) { 128 this.container.insertBefore(el, oldElement); 129 } else { 130 this.container.appendChild(el); 131 } 132 133 // call delegate to inform show of new active element 134 if (TKUtils.objectHasMethod(this.delegate, TKSlideshowViewDidShowElementAtIndex)) { 135 this.delegate[TKSlideshowViewDidShowElementAtIndex](this, this._activeElementIndex); 136 } 137 138 this.currentElement = el; 139 140 var _this = this; 141 setTimeout(function() { 142 el.style.opacity = 1; 143 if (oldElement) { 144 // make sure the old element becomes inactive to clicks (it is on top) 145 // FIXME: maybe the user wants it to be active - this should be done via a css class 146 oldElement.style.pointerEvents = "none"; 147 oldElement.style.opacity = 0; 148 setTimeout(function() { 149 // An external controller might have removed the child by now. Check. 150 if (_this.container && _this.container.hasChild(oldElement)) { 151 _this.container.removeChild(oldElement); 152 } 153 }, (_this.fadeDuration + 10)); 154 } 155 }, 0); 156 }; 157 158 159 TKClass(TKSlideshowView); 160 161 /* ====================== Datasource helper ====================== */ 162 163 function TKSlideshowViewDataSourceHelper(data) { 164 this.data = data; 165 }; 166 167 TKSlideshowViewDataSourceHelper.prototype.slideshowViewNumberOfElements = function(view) { 168 if (this.data) { 169 return this.data.length; 170 } else { 171 return 0; 172 } 173 }; 174 175 TKSlideshowViewDataSourceHelper.prototype.slideshowViewElementAtIndex = function(view, index) { 176 if (!this.data || index >= this.data.length) { 177 return null; 178 } 179 var source = this.data[index]; 180 var element = TKUtils.buildElement(source); 181 return element; 182 }; 183 184 /* ====================== Declarative helper ====================== */ 185 186 TKSlideshowView.buildSlideshowView = function(element, data) { 187 if (TKUtils.objectIsUndefined(data) || !data || data.type != "TKSlideshowView") { 188 return null; 189 } 190 191 var slideshowView = new TKSlideshowView(element); 192 193 if (!TKUtils.objectIsUndefined(data.elements)) { 194 slideshowView.dataSource = new TKSlideshowViewDataSourceHelper(data.elements); 195 } 196 197 TKSlideshowView.synthetizes.forEach(function(prop) { 198 if (prop != "dataSource" && prop != "delegate") { 199 if (!TKUtils.objectIsUndefined(data[prop])) { 200 slideshowView[prop] = data[prop]; 201 } 202 } 203 }); 204 205 return slideshowView; 206 }; 207 208