1/** 2 * jQuery Content Slider plugin 3 * 4 * @author ThimPress 5 */ 6; 7(function ($) { 8 $.thimContentSlider = function (el, options) { 9 this.$el = $(el).addClass('thim-content-slider'); 10 this.$items = []; 11 this.options = $.extend({}, $.fn.thimContentSlider.defaults, options); 12 var root = this, 13 $win = $(window), 14 $doc = $(document), 15 $body = $(document.body), 16 containerWidth = 0, 17 updateTimer = null, 18 playTimer = null, 19 midElement = 0, 20 activeElement = 0, 21 viewPortWidth = 0, 22 scrolling = false, 23 currentItem = 0, 24 maxItems = 0, 25 ratio = this.options.activeItemRatio || 2.5, 26 activeItemPadding = this.options.activeItemPadding, 27 itemWidth = 0, 28 midItemWidth = 0, 29 itemsVisible = this.options.itemsVisible || 7, 30 midPosition = 0, 31 navDuration = 250, 32 touch = {}, 33 isTouch = "ontouchstart" in window || window.navigator.msMaxTouchPoints, 34 events = { 35 start: isTouch ? 'touchstart' : 'mousedown', 36 move : isTouch ? 'touchmove' : 'mousemove', 37 end : isTouch ? 'touchend' : 'mouseup' 38 }, 39 _speed = '', 40 _showContent = true; 41 42 function createItem(args) { 43 var $item = $(' \ 44 <li> \ 45 <div class="slide-content" style="margin: ' + _opt('itemPadding') + 'px;"> \ 46 <img src="' + args.image + '" /> \ 47 </div> \ 48 </li> \ 49 '); 50 return $item; 51 } 52 53 function parseItems() { 54 var itemType = typeof root.options.items, 55 $items = null; 56 if (itemType == 'string') { 57 $items = $(root.options.items); 58 } else if (itemType == 'object') { 59 $items = $(root.options.items).children(); 60 } 61 if ($items) { 62 root.options.items = []; 63 $items.each(function () { 64 var $item = $(this), 65 $img = $item.find('img' + root.options.imageSelector + ':first'), 66 $url = $img.parent(); 67 root.options.items.push({ 68 image : $img.attr('src'), 69 url : $url.is('a') ? $url.attr('href') : '', 70 content: $item.find(root.options.contentSelector) 71 }); 72 }); 73 } 74 } 75 76 function createHTML() { 77 var $html = $(' \ 78 <div class="slides-content"></div>\ 79 <div class="slides-wrapper"> \ 80 <ul class="scrollable"></ul> \ 81 <a href="prev" class="control-nav prev"></a> \ 82 <a href="next" class="control-nav next"></a> \ 83 </div> \ 84 '), 85 items = root.options.items; 86 root.$el.html($html); 87 root.$slidesWrapper = root.$el.find('.slides-wrapper'); 88 root.$scrollable = root.$el.find('.scrollable').css({ 89 marginTop : -_opt('itemPadding'), 90 marginBottom: -_opt('itemPadding') 91 }); 92 root.$slideContent = root.$el.find('.slides-content'); 93 for (var i = 0, n = items.length; i < n; i++) { 94 var $item = createItem({image: items[i].image}), 95 $content = $('<div class="slide-content" />').append(items[i].content); 96 root.$scrollable.append($item); 97 root.$slideContent.append($content); 98 } 99 root.$items = root.$scrollable.children(); 100 101 itemsVisible = _opt('itemsVisible') <= _opt('items').length ? _opt('itemsVisible') : _opt('items').length; 102 midElement = Math.floor(itemsVisible / 2); 103 activeElement = midElement; 104 maxItems = root.$items.length; 105 currentItem = activeElement; 106 107 root.$el 108 .on('click', '.control-nav', _controlNav) 109 .on('click', '.scrollable > li', _controlNav); 110 111 if (root.options.mouseWheel) { 112 root.$el 113 .on('mousewheel', function (e, t, n, r) { 114 e.preventDefault(); 115 if (t != -1) _prevItem(); 116 else _nextItem(); 117 }); 118 } 119 120 if (root.options.autoPlay) { 121 _autoPlay(); 122 } 123 124 if (root.options.pauseOnHover) { 125 root.$el.hover(function () { 126 _pause(); 127 }, function () { 128 _restart(); 129 }); 130 } 131 132 root.$scrollable 133 .bind(events.start, _touchStart) 134 .bind(events.move, _touchMove) 135 .bind(events.end, _touchEnd) 136 137 _initNav(); 138 root.$slideContent.children().eq(activeElement).css({opacity: 1}).addClass('current').siblings().removeClass('current'); 139 } 140 141 function _touchStart() { 142 // TODO: 143 } 144 145 function _touchMove() { 146 // TODO: 147 } 148 149 function _touchEnd() { 150 // TODO: 151 } 152 153 function _showNav() { 154 var $nav = root.$nav, 155 navHeight = $nav.height(), 156 left = _opt('controlNav') == 'behind' ? (containerWidth - midItemWidth) / 2 - navHeight + 20 : 20; 157 $nav.show(); 158 $nav.first().css({ 159 left : left, 160 opacity: 0 161 }).stop().animate({ 162 opacity: 1, 163 left : left - 20 164 }, navDuration); 165 $nav.last().css({ 166 right : left, 167 opacity: 0 168 }).stop().animate({ 169 opacity: 1, 170 right : left - 20 171 }, navDuration); 172 } 173 174 function _hideNav() {
175 var $nav = root.$nav; 176 $nav.first().stop().animate({ 177 opacity: 0, 178 left : '+=20' 179 }, navDuration); 180 $nav.last().stop().animate({ 181 opacity: 0, 182 right : '+=20' 183 }, navDuration); 184 } 185 186 function _initNav() { 187 var $nav = root.$el.find('.control-nav') 188 root.$el.hover(function () { 189 root.$el.addClass('hover'); 190 //_showNav(); 191 }, function () { 192 root.$el.removeClass('hover'); 193 //_hideNav(); 194 }); 195 root.$nav = $nav; 196 } 197 198 function updateNav() { 199 var navHeight = root.$nav.height(), 200 css = { 201 top : (midItemWidth - _opt('itemPadding') * 2) / 2, 202 marginTop: -navHeight / 2 203 }; 204 if (_opt('controlNav') == 'behind') { 205 206 } 207 root.$nav.css(css); 208 } 209 210 function _getItemOffset(item) { 211 if (item.hasClass('mid-item')) { 212 return 0; 213 } 214 var itemIndex = root.$items.index(item), 215 midIndex = root.$items.index(root.$items.filter('.mid-item')), 216 offset = itemIndex - midIndex; 217 return offset; 218 } 219 220 function _controlNav(e) { 221 e.preventDefault(); 222 var nav = $(this).attr('href'); 223 switch (nav) { 224 case 'prev': 225 _prevItem(); 226 break; 227 case 'next': 228 _nextItem(); 229 break; 230 default: 231 var $item = $(e.target); 232 if (!$item.is('li')) { 233 $item = $item.closest('li'); 234 } 235 _move(_getItemOffset($item)); 236 237 } 238 } 239 240 function _animateDone(dir, callback) { 241 if (dir == 'prev') { 242 root.$items.last().remove(); 243 } else { 244 root.$items.first().remove(); 245 } 246 _getItems(); 247 root.$items.eq(midElement).addClass('mid-item').siblings().removeClass('mid-item'); 248 if (_showContent) { 249 root.$slideContent.children().eq(currentItem).stop().show().animate({opacity: 1}).siblings().hide(); 250 } 251 scrolling = false; 252 _restart(); 253 if (root.$el.hasClass('hover')) { 254 //_showNav(); 255 } 256 $.isFunction(callback) && callback.apply(root); 257 } 258 259 function _move(offset) { 260 if (offset == 0) { 261 _speed = ''; 262 _showContent = true; 263 return; 264 } else if (Math.abs(offset) == 1) { 265 _showContent = true; 266 } else { 267 _showContent = false; 268 } 269 //_hideNav(); 270 _speed = 250; 271 var dir = offset < 0 ? _prevItem : _nextItem; 272 dir.call(this, function () { 273 _move(offset < 0 ? offset + 1 : offset - 1); 274 }) 275 } 276 277 function _prevItem(callback) { 278 if (scrolling) return; 279 _pause(); 280 //_hideNav(); 281 scrolling = true; 282 root.$slideContent.children().eq(currentItem).stop().animate({opacity: 0}); 283 currentItem--; 284 if (currentItem < 0) { 285 currentItem = maxItems - 1; 286 } 287 var itemPadding = _opt('itemPadding'), 288 top = parseInt( ( midItemWidth - itemWidth ) / 2 ), 289 start = 0, 290 end = root.$items.length, 291 count = 0, 292 _done = function () { 293 count++; 294 if (count == end) { 295 _animateDone('prev', callback); 296 } 297 }; 298 var $clone = root.$items.last().clone(); 299 $clone.insertBefore(root.$items.first()).css({ 300 left: parseInt(root.$items.first().css('left')) - itemWidth 301 }); 302 _getItems(); 303 root.$el.find('.mid-item').removeClass('mid-item'); 304 root.$items.eq(activeElement + 1).addClass('mid-item'); 305 for (var i = start; i <= end; i++) { 306 var animation = { 307 left : midPosition - ( activeElement - i ) * itemWidth, 308 width: itemWidth, 309 top : top 310 } 311 if (i < activeElement) { 312 animation.left -= activeItemPadding; 313 } else if (i == activeElement) { 314 animation.left = midPosition; 315 animation.top = 0; 316 animation.width = midItemWidth 317 } else if (i == activeElement + 1) { 318 animation.left = midPosition + midItemWidth + activeItemPadding; 319 animation.top = top; 320 animation.width = itemWidth 321 } else { 322 animation.left += (midItemWidth - itemWidth) + activeItemPadding; 323 } 324 root.$items.eq(i).stop().show().animate(animation, _speed, _done); 325 } 326 } 327 328 function _nextItem(callback) { 329 if (scrolling) return; 330 _pause(); 331 //_hideNav(); 332 scrolling = true; 333 root.$slideContent.children().eq(currentItem).stop().animate({opacity: 0}); 334 currentItem++; 335 if (currentItem >= maxItems) { 336 currentItem = 0; 337 } 338 var itemPadding = _opt('itemPadding'), 339 top = parseInt( ( midItemWidth - itemWidth ) / 2 ), 340 start = 0, 341 end = root.$items.length, 342 count = 0, 343 _done = function () { 344 count++; 345 if (count == end) { 346 _animateDone('next', callback); 347 } 348 }; 349 var $clone = root.$items.first().clone();
350 $clone.insertAfter(root.$items.last()).css({ 351 left: parseInt(root.$items.last().css('left')) + itemWidth 352 }); 353 _getItems(); 354 root.$el.find('.mid-item').removeClass('mid-item'); 355 root.$items.eq(activeElement + 1).addClass('mid-item'); 356 for (var i = start; i <= end; i++) { 357 var animation = { 358 left : midPosition - ( activeElement - i ) * itemWidth, 359 width: itemWidth, 360 top : top 361 } 362 if (i < activeElement) { 363 animation.left -= itemWidth + activeItemPadding; 364 } else if (i == activeElement) { 365 animation.left -= itemWidth + activeItemPadding; 366 animation.top = top; 367 animation.width = itemWidth; 368 } else if (i == activeElement + 1) { 369 animation.left = midPosition; 370 animation.top = 0; 371 animation.width = midItemWidth; 372 } else { 373 animation.left = midPosition + midItemWidth + ( i - activeElement - 2 ) * itemWidth + activeItemPadding 374 } 375 root.$items.eq(i).stop().show().animate(animation, _speed, _done); 376 } 377 } 378 379 function _getItems() { 380 root.$items = root.$scrollable.children(); 381 } 382 383 function _opt(key) { 384 return root.options[key]; 385 } 386 387 function _autoPlay() { 388 playTimer && clearTimeout(playTimer); 389 playTimer = setTimeout(function () { 390 _autoPlay(); 391 _nextItem(); 392 }, _opt('pauseTime')) 393 } 394 395 function _pause() { 396 playTimer && clearTimeout(playTimer); 397 } 398 399 function _restart() { 400 if (_opt('autoPlay')) { 401 _autoPlay(); 402 } 403 } 404 405 function calculate(args) { 406 root.$scrollable.css("width", ""); 407 args = $.extend({ 408 itemPadding : _opt('itemPadding'), 409 itemMaxWidth: _opt('itemMaxWidth'), 410 itemsVisible: itemsVisible, 411 itemMinWidth: _opt('itemMinWidth') 412 }, args || {}); 413 containerWidth = root.$el.width(); 414 midItemWidth = parseInt( args.itemMaxWidth + 2 * args.itemPadding ); 415 itemWidth = parseInt( midItemWidth / ratio ); 416 viewPortWidth = itemWidth * ( args.itemsVisible - 1 ) + midItemWidth + 2 * activeItemPadding; 417 418 if (viewPortWidth > containerWidth) { 419 var mod = viewPortWidth - containerWidth, 420 dx = mod / ( args.itemsVisible + ratio - 1 ); 421 if (midItemWidth - dx * ratio < args.itemMinWidth) { 422 if (args.itemsVisible - 2 >= 1) { 423 args.itemsVisible -= 2; 424 calculate({ 425 itemsVisible: args.itemsVisible, 426 }); 427 return; 428 } 429 } else { 430 midItemWidth -= dx * ratio; 431 itemWidth -= dx; 432 } 433 viewPortWidth = containerWidth;//??? 434 } else { 435 root.$scrollable.width(viewPortWidth); 436 } 437 midPosition = parseInt( ( viewPortWidth - midItemWidth ) / 2 ); 438 } 439 440 function _update() { 441 calculate(); 442 updateNav(); 443 var itemPadding = _opt('itemPadding'); 444 root.$scrollable.height(midItemWidth); 445 var left = 0, 446 top = parseInt( ( midItemWidth - itemWidth ) / 2 ), 447 start = 0, 448 end = root.$items.length - 1; 449 root.$items.hide(); 450 for (var i = start; i <= end; i++) { 451 root.$items.eq(i).show(); 452 if (i == activeElement) { 453 root.$items.eq(i) 454 .css({ 455 left : parseInt( midPosition ), 456 width: parseInt( midItemWidth ), 457 }) 458 .addClass('mid-item') 459 .find('.slide-content').css({ 460 margin: itemPadding 461 }); 462 } else { 463 left = midPosition - ( activeElement - i ) * itemWidth; 464 if (i > activeElement) { 465 left += ( midItemWidth - itemWidth ) + activeItemPadding; 466 } else { 467 left -= activeItemPadding; 468 } 469 root.$items.eq(i).css({ 470 width: parseInt( itemWidth ), 471 left : parseInt( left ), 472 top : parseInt( top ) 473 }).removeClass('mid-item'); 474 } 475 } 476 } 477 478 function update(force) { 479 if (force) { 480 _update(); 481 } else { 482 updateTimer && clearTimeout(updateTimer); 483 updateTimer = setTimeout(function () { 484 _update(); 485 }, 350) 486 } 487 } 488 489 function init() { 490 parseItems(); 491 createHTML(); 492 $win.on('resize.thim-content-slider', function () { 493 update(); 494 }).trigger('resize.thim-content-slider'); 495 _update(); 496 } 497 498 // global function 499 this.pause = _pause; 500 this.restart = _restart; 501 this.prev = _prevItem; 502 this.next = _nextItem; 503 this.update = _update; 504 this.move = _move; 505 506 init(); 507 } 508 509 $.fn.thimContentSlider = function (opt) { 510 var method = false, 511 args = []; 512 if (arguments.length > 0) { 513 if (typeof arguments[0] == 'string') { 514 method = arguments[0]; 515 for (var i = 1; i < arguments.length; i++) { 516 args[i - 1] = arguments[i]; 517 } 518 } 519 } 520 return $.each(this, function () { 521 var $el = $(this), 522 contentSlider = $el.data('thim-content-slider'); 523 if (!contentSlider) { 524 contentSlider = new $.thimContentSlider(this, opt); 525 $el.data('thim-content-slider', contentSlider); 526 } 527 if (method) { 528 if ($.isFunction(contentSlider[method])) { 529 return contentSlider[method].apply(contentSlider, args); 530 } 531 throw 'Method thimContentSlider.' + method + '() does not exists'; 532 } else { 533 return $el; 534 } 535 }); 536 } 537 538 $.fn.thimContentSlider.defaults = { 539 items : [ 540 { 541 image: '', // thumb of user or product 542 url : '', // full image of user or product to display in the light-box 543 html : '' // the content to display beside item 544 } 545 ], 546 itemMaxWidth : 200, 547 itemMinWidth : 150, 548 itemsVisible : 7, 549 itemPadding : 10, 550 activeItemRatio : 2, 551 activeItemPadding: 0, 552 mouseWheel : true, 553 autoPlay : true, 554 pauseTime : 3000, 555 pauseOnHover : true, 556 imageSelector : '', 557 contentSelector : '.content', 558 controlNav : 'behind' 559 } 560})(jQuery);
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.