1$(function () { 2 3 4 5 // http://www.netcu.de/jquery-touchwipe-iphone-ipad-library 6 $.fn.touchwipe = function (settings) { 7 8 var config = { 9 min_move_x: 20, 10 min_move_y: 20, 11 wipeLeft: function () {}, 12 wipeRight: function () {}, 13 wipeUp: function () {}, 14 wipeDown: function () {}, 15 preventDefaultEvents: true 16 }; 17 18 if (settings) $.extend(config, settings); 19 20 this.each(function () { 21 var startX; 22 var startY; 23 var isMoving = false; 24 25 function cancelTouch() { 26 this.removeEventListener('touchmove', onTouchMove); 27 startX = null; 28 isMoving = false; 29 } 30 31 function onTouchMove(e) { 32 if (config.preventDefaultEvents) { 33 e.preventDefault(); 34 } 35 if (isMoving) { 36 var x = e.touches[0].pageX; 37 var y = e.touches[0].pageY; 38 var dx = startX - x; 39 var dy = startY - y; 40 if (Math.abs(dx) >= config.min_move_x) { 41 cancelTouch(); 42 if (dx > 0) { 43 config.wipeLeft(); 44 } else { 45 config.wipeRight(); 46 } 47 } else if (Math.abs(dy) >= config.min_move_y) { 48 cancelTouch(); 49 if (dy > 0) { 50 config.wipeDown(); 51 } else { 52 config.wipeUp(); 53 } 54 } 55 } 56 } 57 58 function onTouchStart(e) { 59 if (e.touches.length == 1) { 60 startX = e.touches[0].pageX; 61 startY = e.touches[0].pageY; 62 isMoving = true; 63 this.addEventListener('touchmove', onTouchMove, false); 64 } 65 } 66 if ('ontouchstart' in document.documentElement) { 67 this.addEventListener('touchstart', onTouchStart, false); 68 } 69 }); 70 71 return this; 72 }; 73 74 $.elastislide = function (options, element) { 75 this.$el = $(element); 76 this._init(options); 77 }; 78 79 $.elastislide.defaults = { 80 speed: 450, // animation speed 81 easing: '', // animation easing effect 82 imageW: 280, // the images width 83 margin: 3, // image margin right 84 border: 2, // image border 85 minItems: 1, // the minimum number of items to show. 86 // when we resize the window, this will make sure minItems are always shown 87 // (unless of course minItems is higher than the total number of elements) 88 current: 0, // index of the current item 89 // when we resize the window, the carousel will make sure this item is visible 90 onClick: function () { 91 return false; 92 } // click item callback 93 }; 94 95 $.elastislide.prototype = { 96 _init: function (options) { 97 98 this.options = $.extend(true, {}, $.elastislide.defaults, options); 99 100 // <ul> 101 this.$slider = this.$el.find('ul'); 102 103 // <li> 104 this.$items = this.$slider.children('li'); 105 106 // total number of elements / images 107 this.itemsCount = this.$items.length; 108 109 // cache the <ul>'s parent, since we will eventually need to recalculate its width on window resize 110 this.$esCarousel = this.$slider.parent(); 111 112 // validate options 113 this._validateOptions(); 114 115 // set sizes and initialize some vars... 116 this._configure(); 117 118 // add navigation buttons 119 this._addControls(); 120 121 // initialize the events 122 this._initEvents(); 123 124 // show the <ul> 125 this.$slider.show(); 126 127 // slide to current's position 128 this._slideToCurrent(false); 129 130 }, 131 _validateOptions: function () { 132 133 if (this.options.speed < 0) 134 this.options.speed = 450; 135 if (this.options.margin < 0) 136 this.options.margin = 4; 137 if (this.options.border < 0) 138 this.options.border = 1; 139 if (this.options.minItems < 1 || this.options.minItems > this.itemsCount) 140 this.options.minItems = 1; 141 if (this.options.current > this.itemsCount - 1) 142 this.options.current = 0; 143 144 }, 145 _configure: function () { 146 147 // current item's index 148 this.current = this.options.current; 149 150 // the ul's parent's (div.es-carousel) width is the "visible" width 151 this.visibleWidth = this.$esCarousel.width(); 152 153 154 // test to see if we need to initially resize the items 155 if (this.visibleWidth < this.options.minItems * (this.options.imageW + 2 * this.options.border) + (this.options.minItems - 1) * this.options.margin) { 156 this._setDim((this.visibleWidth - (this.options.minItems - 1) * this.options.margin) / this.options.minItems); 157 this._setCurrentValues();
158 // how many items fit with the current width 159 this.fitCount = this.options.minItems; 160 } else { 161 this._setDim(); 162 this._setCurrentValues(); 163 } 164 165 // set the <ul> width 166 this.$slider.css({ 167 width: this.sliderW 168 }); 169 170 }, 171 _setDim: function (elW) { 172 173 // <li> style 174 this.$items.css({ 175 marginRight: this.options.margin, 176 width: (elW) ? elW : this.options.imageW + 2 * this.options.border 177 }).children('a').css({ // <a> style 178 borderWidth: this.options.border 179 }); 180 181 }, 182 _setCurrentValues: function () { 183 184 // the total space occupied by one item 185 this.itemW = this.$items.outerWidth(true); 186 187 // total width of the slider / <ul> 188 // this will eventually change on window resize 189 this.sliderW = this.itemW * this.itemsCount; 190 191 // the ul parent's (div.es-carousel) width is the "visible" width 192 this.visibleWidth = this.$esCarousel.width(); 193 194 // how many items fit with the current width 195 this.fitCount = Math.floor(this.visibleWidth / this.itemW); 196 197 }, 198 _addControls: function () { 199 200 /*this.$navNext = $('<span class="es-nav-next">Next</span>'); 201 this.$navPrev = $('<span class="es-nav-prev">Previous</span>'); 202 $('<div class="es-nav"/>') 203 .append(this.$navPrev) 204 .append(this.$navNext) 205 .appendTo(this.$el);*/ 206 this.$navNext = $('<div class="es-nav-next"><img src="images/icons/right-arrow-thumb.png" alt="Previous"/></div>'); 207 this.$navPrev = $('<div class="es-nav-prev"><img src="images/icons/left-arrow-thumb.png" alt="Next"/></div>'); 208 $('<div class="es-nav"/>') 209 .append(this.$navPrev) 210 .append(this.$navNext) 211 .appendTo(this.$el); 212 213 //this._toggleControls(); 214 215 }, 216 _toggleControls: function (dir, status) { 217 218 // show / hide navigation buttons 219 if (dir && status) { 220 if (status === 1) 221 (dir === 'right') ? this.$navNext.show() : this.$navPrev.show(); 222 else 223 (dir === 'right') ? this.$navNext.hide() : this.$navPrev.hide(); 224 } else if (this.current === this.itemsCount - 1 || this.fitCount >= this.itemsCount) 225 this.$navNext.hide(); 226 227 }, 228 _initEvents: function () { 229 230 var instance = this; 231 232 // window resize 233 $(window).on('resize.elastislide', function (event) { 234 235 instance._reload(); 236 237 // slide to the current element 238 clearTimeout(instance.resetTimeout); 239 instance.resetTimeout = setTimeout(function () { 240 instance._slideToCurrent(); 241 }, 200); 242 243 }); 244 245 // navigation buttons events 246 this.$navNext.on('click.elastislide', function (event) { 247 instance._slide('right'); 248 }); 249 250 this.$navPrev.on('click.elastislide', function (event) { 251 instance._slide('left'); 252 }); 253 254 // item click event 255 this.$slider.on('click.elastislide', 'li', function (event) { 256 instance.options.onClick($(this)); 257 return false; 258 }); 259 260 // touch events 261 instance.$slider.touchwipe({ 262 wipeLeft: function () { 263 instance._slide('right'); 264 }, 265 wipeRight: function () { 266 instance._slide('left'); 267 } 268 }); 269 270 }, 271 reload: function (callback) { 272 this._reload(); 273 if (callback) callback.call(); 274 275 }, 276 _reload: function () { 277 278 var instance = this; 279 280 // set values again 281 instance._setCurrentValues();
282 283 // need to resize items 284 if (instance.visibleWidth < instance.options.minItems * (instance.options.imageW + 2 * instance.options.border) + (instance.options.minItems - 1) * instance.options.margin) { 285 instance._setDim((instance.visibleWidth - (instance.options.minItems - 1) * instance.options.margin) / instance.options.minItems); 286 instance._setCurrentValues(); 287 instance.fitCount = instance.options.minItems; 288 } else { 289 instance._setDim(); 290 instance._setCurrentValues(); 291 } 292 293 instance.$slider.css({ 294 width: instance.sliderW + 10 // TODO: +10px seems to solve a firefox "bug" :S 295 }); 296 297 }, 298 _slide: function (dir, val, anim, callback) { 299 300 // if animating return 301 //if( this.$slider.is(':animated') ) 302 //return false; 303 304 // current margin left 305 var ml = parseFloat(this.$slider.css('margin-left')); 306 307 // val is just passed when we want an exact value for the margin left (used in the _slideToCurrent function) 308 if (val === undefined) { 309 310 // how much to slide? 311 var amount = this.fitCount * this.itemW, 312 val; 313 314 if (amount < 0) return false; 315 316 // make sure not to leave a space between the last item / first item and the end / beggining of the slider available width 317 if (dir === 'right' && this.sliderW - (Math.abs(ml) + amount) < this.visibleWidth) { 318 amount = this.sliderW - (Math.abs(ml) + this.visibleWidth) - this.options.margin; // decrease the margin left 319 // show / hide navigation buttons 320 this._toggleControls('right', -1); 321 this._toggleControls('left', 1); 322 } else if (dir === 'left' && Math.abs(ml) - amount < 0) { 323 amount = Math.abs(ml); 324 // show / hide navigation buttons 325 this._toggleControls('left', -1); 326 this._toggleControls('right', 1); 327 } else { 328 var fml; // future margin left 329 (dir === 'right') ? 330 fml = Math.abs(ml) + this.options.margin + Math.abs(amount): fml = Math.abs(ml) - this.options.margin - Math.abs(amount); 331 332 // show / hide navigation buttons 333 if (fml > 0) 334 this._toggleControls('left', 1); 335 else 336 this._toggleControls('left', -1); 337 338 if (fml < this.sliderW - this.visibleWidth) 339 this._toggleControls('right', 1); 340 else 341 this._toggleControls('right', -1); 342 343 } 344 345 (dir === 'right') ? val = '-=' + amount: val = '+=' + amount 346 347 } else { 348 var fml = Math.abs(val); // future margin left 349 350 if (Math.max(this.sliderW, this.visibleWidth) - fml < this.visibleWidth) { 351 val = -(Math.max(this.sliderW, this.visibleWidth) - this.visibleWidth); 352 if (val !== 0) 353 val += this.options.margin; // decrease the margin left if not on the first position 354 355 // show / hide navigation buttons 356 this._toggleControls('right', -1); 357 fml = Math.abs(val); 358 } 359 360 // show / hide navigation buttons 361 if (fml > 0) 362 this._toggleControls('left', 1); 363 else 364 this._toggleControls('left', -1); 365 366 if (Math.max(this.sliderW, this.visibleWidth) - this.visibleWidth > fml + this.options.margin) 367 this._toggleControls('right', 1); 368 else 369 this._toggleControls('right', -1); 370 371 } 372 373 $.fn.applyStyle = (anim === undefined) ? $.fn.animate : $.fn.css; 374 375 var sliderCSS = { 376 marginLeft: val 377 }; 378 379 var instance = this; 380 381 this.$slider.stop().applyStyle(sliderCSS, $.extend(true, [], { 382 duration: this.options.speed, 383 easing: this.options.easing, 384 complete: function () { 385 if (callback) callback.call(); 386 } 387 })); 388 389 }, 390 _slideToCurrent: function (anim) { 391 392 // how much to slide? 393 var amount = this.current * this.itemW; 394 this._slide('', -amount, anim); 395 396 }, 397 add: function ($newelems, callback) { 398 399 // adds new items to the carousel 400 this.$items = this.$items.add($newelems); 401 this.itemsCount = this.$items.length; 402 this._setDim(); 403 this._setCurrentValues();
404 this.$slider.css({ 405 width: this.sliderW 406 }); 407 this._slideToCurrent(); 408 409 if (callback) callback.call($newelems); 410 411 }, 412 setCurrent: function (idx, callback) { 413 414 this.current = idx; 415 416 var ml = Math.abs(parseFloat(this.$slider.css('margin-left'))), 417 posR = ml + this.visibleWidth, 418 fml = Math.abs(this.current * this.itemW); 419 420 if (fml + this.itemW > posR || fml < ml) { 421 this._slideToCurrent(); 422 } 423 424 if (callback) callback.call(); 425 426 }, 427 destroy: function (callback) { 428 429 this._destroy(callback); 430 431 }, 432 _destroy: function (callback) { 433 this.$el.off('.elastislide').removeData('elastislide'); 434 $(window).off('.elastislide'); 435 if (callback) callback.call(); 436 } 437 }; 438 439 var logError = function (message) { 440 if (this.console) { 441 console.error(message); 442 } 443 }; 444 445 $.fn.elastislide = function (options) { 446 if (typeof options === 'string') { 447 var args = Array.prototype.slice.call(arguments, 1); 448 449 this.each(function () { 450 var instance = $.data(this, 'elastislide'); 451 if (!instance) { 452 logError("cannot call methods on elastislide prior to initialization; " + 453 "attempted to call method '" + options + "'"); 454 return; 455 } 456 if (!$.isFunction(instance[options]) || options.charAt(0) === "_") { 457 logError("no such method '" + options + "' for elastislide instance"); 458 return; 459 } 460 instance[options].apply(instance, args); 461 }); 462 } else { 463 this.each(function () { 464 var instance = $.data(this, 'elastislide'); 465 if (!instance) { 466 $.data(this, 'elastislide', new $.elastislide(options, this)); 467 } 468 }); 469 } 470 return this; 471 }; 472});
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.