1/*! 2 * The Grid Slider v1.0.0 3 * Copyright © 2015 All Rights Reserved. 4 * @author Themeone [http://theme-one.com/the-grid/] 5 */ 6 7/*jslint bitwise: true */ 8 9;(function ($, w, undefined) { 10 'use strict'; 11 12 var pluginName = 'TG_Slider', 13 className = 'TG_Slider', 14 namespace = pluginName, 15 // Local WindowAnimationTiming interface 16 cAF = w.cancelAnimationFrame || w.cancelRequestAnimationFrame, 17 rAF = w.requestAnimationFrame, 18 // Support indicators 19 transform, gpuAcceleration, 20 // Other global values 21 $doc = $(document), 22 dragInitEvents = 'touchstart.' + namespace + ' mousedown.' + namespace, 23 dragMouseEvents = 'mousemove.' + namespace + ' mouseup.' + namespace, 24 dragTouchEvents = 'touchmove.' + namespace + ' touchend.' + namespace, 25 wheelEvent = (document.implementation.hasFeature('Event.wheel', '3.0') ? 'wheel.' : 'mousewheel.') + namespace, 26 clickEvent = 'click.' + namespace, 27 mouseDownEvent = 'mousedown.' + namespace, 28 interactiveElements = ['INPUT', 'SELECT', 'BUTTON', 'TEXTAREA'], 29 tmpArray = [], 30 time, 31 // Math shorthands 32 abs = Math.abs, 33 sqrt = Math.sqrt, 34 pow = Math.pow, 35 round = Math.round, 36 max = Math.max, 37 min = Math.min; 38 39 // Keep track of last fired global wheel event 40 var lastGlobalWheel = 0; 41 $doc.on(wheelEvent, function (event) { 42 var TG_Slider = event.originalEvent[namespace]; 43 var time = +new Date(); 44 // Update last global wheel time, but only when event didn't originate 45 // in TG_Slider frame, or the origin was less than scrollHijack time ago 46 if (!TG_Slider || TG_Slider.options.scrollHijack < time - lastGlobalWheel) lastGlobalWheel = time; 47 }); 48 49 /** 50 * TG_Slider. 51 * 52 * @class 53 * 54 * @param {Element} frame DOM element of TG_Slider container. 55 * @param {Object} options Object with options. 56 * @param {Object} callbackMap Callbacks map. 57 */ 58 function TG_Slider(frame, options, callbackMap) { 59 // Extend options 60 var o = $.extend({}, TG_Slider.defaults, options), 61 // Private variables 62 self = this, 63 parallax = isNumber(frame), 64 // Frame 65 $frame = $(frame), 66 $slidee = o.slidee ? $(o.slidee).eq(0) : $frame.children().eq(0), 67 frameSize = 0, 68 slideeSize = 0, 69 pos = { 70 start: 0, 71 center: 0, 72 end: 0, 73 cur: 0, 74 dest: 0 75 }, 76 // Scrollbar 77 $sb = $(o.scrollBar).eq(0), 78 $handle = $sb.children().eq(0), 79 sbSize = 0, 80 handleSize = 0, 81 hPos = { 82 start: 0, 83 end: 0, 84 cur: 0 85 }, 86 // Pagesbar 87 $pb = $(o.pagesBar), 88 $pages = 0, 89 pages = [], 90 // Items 91 $items = 0, 92 items = [], 93 rel = { 94 firstItem: 0, 95 lastItem: 0, 96 centerItem: 0, 97 activeItem: null, 98 activePage: 0 99 }, 100 // Styles 101 frameStyles = new StyleRestorer($frame[0]), 102 slideeStyles = new StyleRestorer($slidee[0]), 103 sbStyles = new StyleRestorer($sb[0]), 104 handleStyles = new StyleRestorer($handle[0]), 105 // Navigation type booleans 106 basicNav = o.itemNav === 'basic', 107 forceCenteredNav = o.itemNav === 'forceCentered', 108 centeredNav = o.itemNav === 'centered' || forceCenteredNav, 109 itemNav = !parallax && (basicNav || centeredNav || forceCenteredNav), 110 // Miscellaneous 111 $scrollSource = o.scrollSource ? $(o.scrollSource) : $frame, 112 $dragSource = o.dragSource ? $(o.dragSource) : $frame, 113 $forwardButton = $(o.forward), 114 $backwardButton = $(o.backward), 115 $prevButton = $(o.prev), 116 $nextButton = $(o.next), 117 $prevPageButton = $(o.prevPage), 118 $nextPageButton = $(o.nextPage), 119 callbacks = {}, 120 last = {}, 121 animation = {}, 122 move = {}, 123 dragging = { 124 released: 1 125 }, 126 scrolling = { 127 last: 0, 128 delta: 0, 129 resetTime: 200 130 }, 131 renderID = 0, 132 historyID = 0, 133 cycleID = 0, 134 continuousID = 0, 135 i, l; 136 137 // Normalizing frame 138 if (!parallax) { 139 frame = $frame[0]; 140 } 141 142 // Expose properties 143 self.initialized = 0; 144 self.frame = frame; 145 self.slidee = $slidee[0];
146 self.pos = pos; 147 self.rel = rel; 148 self.items = items; 149 self.pages = pages; 150 self.isPaused = 0; 151 self.options = o; 152 self.dragging = dragging; 153 154 /** 155 * Loading function. 156 * 157 * Populate arrays, set sizes, bind events, ... 158 * 159 * @param {Boolean} [isInit] Whether load is called from within self.init(). 160 * @return {Void} 161 */ 162 function load(isInit) { 163 164 // Local variables 165 var lastItemsCount = 0, 166 lastPagesCount = pages.length, 167 data = $slidee.data('TG_Layout'), 168 itemGutter = (data) ? data.options[data.options.layoutMode].gutter.offsetWidth : 0; 169 170 // for backend 171 if (!data) { return false; } 172 173 // Reset global variables 174 frameSize = $frame.width(); 175 sbSize = $sb.width(); 176 slideeSize = $slidee.outerWidth(); 177 pages.length = 0; 178 // Set position limits & relatives 179 pos.start = 0; 180 pos.end = max(slideeSize - frameSize, 0); 181 182 // Sizes & offsets for item based navigations 183 if (itemNav) { 184 185 // Save the number of current items 186 lastItemsCount = items.length; 187 188 // Reset itemNav related variables 189 $items = $slidee.children(o.itemSelector); 190 items.length = 0; 191 192 // Needed variables 193 var paddingStart = getPx($slidee, o.horizontal ? 'paddingLeft' : 'paddingTop'), 194 paddingEnd = getPx($slidee, o.horizontal ? 'paddingRight' : 'paddingBottom'), 195 borderBox = $($items).css('boxSizing') === 'border-box', 196 filteredItems = data.filteredItems, 197 ignoredMargin = 0, 198 lastItemIndex = 0, 199 lastItem, 200 max_width = 0, 201 pos_items = [], 202 new_pos_item = []; 203 204 for (var i = 0; i < filteredItems.length; i++) { 205 var width = parseFloat(getComputedStyle(filteredItems[i].element).width)+itemGutter, 206 pos_x = filteredItems[i].position.x; 207 max_width = (pos_x+width > max_width) ? pos_x+width : max_width; 208 pos_items.push(pos_x); 209 } 210 pos_items.push(max_width); 211 pos_items.sort(function(a,b){return a - b;}); 212 for (var i = 1; i < pos_items.length; i++) { 213 new_pos_item.push(pos_items[i]-pos_items[i-1]); 214 } 215 216 // Reset slideeSize 217 slideeSize = 0; 218 219 // Iterate through filtered items 220 $(filteredItems).each(function (i, element) { 221 222 // set item with and margin (gutter) 223 var itemMarginStart = itemGutter/2, 224 itemMarginEnd = itemGutter/2; 225 var item = {}; 226 item.el = element; 227 item.size = new_pos_item[i]; 228 item.half = item.size / 2; 229 item.start = slideeSize - itemMarginStart; 230 item.center = item.start - round(frameSize / 2 - item.size / 2); 231 item.end = item.start - frameSize + item.size; 232 233 // Account for slidee padding 234 if (!i) { 235 slideeSize += paddingStart; 236 } 237 // Increment slidee size for size of the active element 238 slideeSize += item.size; 239 240 // Try to account for vertical margin collapsing in vertical mode 241 if (!o.horizontal) { 242 // Subtract smaller margin, but only when top margin is not 0, and this is not the first element 243 if (itemMarginEnd && itemMarginStart && i > 0) { 244 slideeSize -= min(itemMarginStart, itemMarginEnd); 245 } 246 } 247 248 // Things to be done on last item 249 if (i === lastItemIndex) { 250 item.end += paddingEnd; 251 slideeSize += paddingEnd; 252 ignoredMargin = itemMarginEnd; 253 } 254 255 // Add item object to items array 256 if (item.size) { 257 items.push(item); 258 lastItem = item; 259 } 260 261 }); 262 263 // Resize SLIDEE to fit all items 264 $slidee[0].style[o.horizontal ? 'width' : 'height'] = (borderBox ? slideeSize: slideeSize - paddingStart - paddingEnd) + 'px'; 265 266 // Adjust internal SLIDEE size for last margin 267 slideeSize -= ignoredMargin; 268 269 // Set limits 270 if (items.length) { 271 pos.start = items[0][forceCenteredNav ? 'center' : 'start']; 272 pos.end = forceCenteredNav ? lastItem.center : frameSize < slideeSize ? lastItem.end : pos.start; 273 } else { 274 pos.start = pos.end = 0; 275 } 276 } 277 278 // Calculate SLIDEE center position 279 pos.center = round(pos.end / 2 + pos.start / 2); 280 281 // Update relative positions 282 updateRelatives(); 283 284 // Pages 285 if (!parallax && frameSize > 0) { 286 var tempPagePos = pos.start; 287 var pagesHtml = ''; 288 289 // Populate pages array 290 if (itemNav) { 291 $.each(items, function (i, item) { 292 if (forceCenteredNav) { 293 pages.push(item.center); 294 } else if (item.start + item.size > tempPagePos && tempPagePos <= pos.end) { 295 tempPagePos = item.start; 296 pages.push(item.size < frameSize && data.options.layoutMode === 'justified' ? item.start+(item.size-frameSize)/2 : item.start); 297 tempPagePos += frameSize; 298 if (tempPagePos > pos.end && tempPagePos < pos.end + frameSize) { 299 pages.push(pos.end); 300 } 301 } 302 });
303 } else { 304 while (tempPagePos - frameSize < pos.end) { 305 pages.push(tempPagePos); 306 tempPagePos += frameSize; 307 } 308 } 309 310 // Pages bar 311 if ($pb[0] && lastPagesCount !== pages.length) { 312 for (var i = 0; i < pages.length; i++) { 313 pagesHtml += o.pageBuilder.call(self, i); 314 } 315 if (pages.length === 1) { 316 pagesHtml = null; 317 } 318 $pages = $pb.html(pagesHtml).children(); 319 $pages.eq(rel.activePage).addClass(o.activeClass); 320 321 } 322 } 323 324 // Extend relative variables object with some useful info 325 rel.slideeSize = slideeSize; 326 rel.frameSize = frameSize; 327 rel.sbSize = sbSize; 328 rel.handleSize = handleSize; 329 330 // Activate requested position 331 if (itemNav) { 332 if (isInit && o.startAt != null) { 333 //activate(o.startAt); 334 self[centeredNav ? 'toCenter' : 'toStart'](o.startAt); 335 } 336 // Fix possible overflowing 337 var activeItem = items[rel.activeItem]; 338 slideTo(centeredNav && activeItem ? activeItem.center : within(pos.dest, pos.start, pos.end)); 339 } else { 340 if (isInit) { 341 if (o.startAt != null) slideTo(o.startAt, 1); 342 } else { 343 // Fix possible overflowing 344 slideTo(within(pos.dest, pos.start, pos.end)); 345 } 346 } 347 348 // Trigger load event 349 trigger('load'); 350 } 351 self.reload = function () { load(); }; 352 353 /** 354 * Animate to a position. 355 * 356 * @param {Int} newPos New position. 357 * @param {Bool} immediate Reposition immediately without an animation. 358 * @param {Bool} dontAlign Do not align items, use the raw position passed in first argument. 359 * 360 * @return {Void} 361 */ 362 function slideTo(newPos, immediate, dontAlign) { 363 // Align items 364 if (itemNav && dragging.released && !dontAlign) { 365 var tempRel = getRelatives(newPos); 366 var isNotBordering = newPos > pos.start && newPos < pos.end; 367 368 if (centeredNav) { 369 if (isNotBordering) { 370 newPos = items[tempRel.centerItem].center; 371 } 372 if (forceCenteredNav && o.activateMiddle) { 373 activate(tempRel.centerItem); 374 } 375 } else if (isNotBordering) { 376 newPos = items[tempRel.firstItem].start; 377 } 378 } 379 380 // Handle overflowing position limits 381 if (dragging.init && dragging.slidee && o.elasticBounds) { 382 if (newPos > pos.end) { 383 newPos = pos.end + (newPos - pos.end) / 6; 384 } else if (newPos < pos.start) { 385 newPos = pos.start + (newPos - pos.start) / 6; 386 } 387 } else { 388 newPos = within(newPos, pos.start, pos.end); 389 } 390 391 // Update the animation object 392 animation.start = +new Date(); 393 animation.time = 0; 394 animation.from = pos.cur; 395 animation.to = newPos; 396 animation.delta = newPos - pos.cur; 397 animation.tweesing = dragging.tweese || dragging.init && !dragging.slidee; 398 animation.immediate = !animation.tweesing && (immediate || dragging.init && dragging.slidee || !o.speed); 399 400 // Reset dragging tweesing request 401 dragging.tweese = 0; 402 403 // Start animation rendering 404 if (newPos !== pos.dest) { 405 pos.dest = newPos; 406 trigger('change'); 407 if (!renderID) { 408 render(); 409 } 410 } 411 412 // Reset next cycle timeout 413 resetCycle(); 414 415 // Synchronize states 416 updateRelatives(); 417 updateButtonsState(); 418 syncPagesbar(); 419 } 420 421 /** 422 * Render animation frame. 423 * 424 * @return {Void} 425 */ 426 function render() { 427 428 if (!self.initialized) { 429 return; 430 } 431 432 // If first render call, wait for next animationFrame 433 if (!renderID) { 434 renderID = rAF(render); 435 if (dragging.released) { 436 trigger('moveStart'); 437 } 438 return; 439 } 440 441 // If immediate repositioning is requested, don't animate. 442 if (animation.immediate) { 443 pos.cur = animation.to; 444 } 445 // Use tweesing for animations without known end point 446 else if (animation.tweesing) { 447 animation.tweeseDelta = animation.to - pos.cur; 448 // Fuck Zeno's paradox 449 if (abs(animation.tweeseDelta) < 0.1) { 450 pos.cur = animation.to; 451 } else { 452 pos.cur += animation.tweeseDelta * (dragging.released ? o.swingSpeed : o.syncSpeed); 453 } 454 } 455 // Use tweening for basic animations with known end point 456 else { 457 animation.time = min(+new Date() - animation.start, o.speed); 458 pos.cur = animation.from + animation.delta * $.easing[o.easing](animation.time/o.speed, animation.time, 0, 1, o.speed); 459 } 460 461 // If there is nothing more to render break the rendering loop, otherwise request new animation frame. 462 if (animation.to === pos.cur) { 463 pos.cur = animation.to; 464 dragging.tweese = renderID = 0; 465 } else { 466 renderID = rAF(render); 467 } 468 469 trigger('move'); 470 471 // Update SLIDEE position 472 if (!parallax) { 473 if (transform) { 474 $slidee[0].style[transform] = gpuAcceleration + (o.horizontal ? 'translateX' : 'translateY') + '(' + (-pos.cur) + 'px)'; 475 } else { 476 $slidee[0].style[o.horizontal ? 'left' : 'top'] = -round(pos.cur) + 'px'; 477 } 478 } 479 480 // When animation reached the end, and dragging is not active, trigger moveEnd 481 if (!renderID && dragging.released) { 482 trigger('moveEnd'); 483 } 484 485 } 486 487 /** 488 * Synchronizes pagesbar with SLIDEE. 489 * 490 * @return {Void} 491 */ 492 function syncPagesbar() { 493 if ($pages[0] && last.page !== rel.activePage) { 494 last.page = rel.activePage; 495 $pages.removeClass(o.activeClass).eq(rel.activePage).addClass(o.activeClass); 496 trigger('activePage', last.page); 497 } 498 } 499 500 /** 501 * Returns the position object. 502 * 503 * @param {Mixed} item 504 * 505 * @return {Object} 506 */ 507 self.getPos = function (item) { 508 if (itemNav) { 509 var index = getIndex(item); 510 return index !== -1 ? items[index] : false; 511 } else { 512 var $item = $slidee.find(item).eq(0); 513 514 if ($item[0]) { 515 var offset = o.horizontal ? $item.offset().left - $slidee.offset().left : $item.offset().top - $slidee.offset().top; 516 var size = $item[o.horizontal ? 'outerWidth' : 'outerHeight'](); 517 518 return { 519 start: offset, 520 center: offset - frameSize / 2 + size / 2, 521 end: offset - frameSize + size, 522 size: size 523 }; 524 } else { 525 return false; 526 } 527 } 528 }; 529 530 /** 531 * Continuous move in a specified direction. 532 * 533 * @param {Bool} forward True for forward movement, otherwise it'll go backwards. 534 * @param {Int} speed Movement speed in pixels per frame. Overrides options.moveBy value. 535 * 536 * @return {Void} 537 */ 538 self.moveBy = function (speed) {
539 move.speed = speed; 540 // If already initiated, or there is nowhere to move, abort 541 if (dragging.init || !move.speed || pos.cur === (move.speed > 0 ? pos.end : pos.start)) { 542 return; 543 } 544 // Initiate move object 545 move.lastTime = +new Date(); 546 move.startPos = pos.cur; 547 // Set dragging as initiated 548 continuousInit('button'); 549 dragging.init = 1; 550 // Start movement 551 trigger('moveStart'); 552 cAF(continuousID); 553 moveLoop(); 554 }; 555 556 /** 557 * Continuous movement loop. 558 * 559 * @return {Void} 560 */ 561 function moveLoop() { 562 // If there is nowhere to move anymore, stop 563 if (!move.speed || pos.cur === (move.speed > 0 ? pos.end : pos.start)) { 564 self.stop(); 565 } 566 // Request new move loop if it hasn't been stopped 567 continuousID = dragging.init ? rAF(moveLoop) : 0; 568 // Update move object 569 move.now = +new Date(); 570 move.pos = pos.cur + (move.now - move.lastTime) / 1000 * move.speed; 571 // Slide 572 slideTo(dragging.init ? move.pos : round(move.pos)); 573 // Normally, this is triggered in render(), but if there 574 // is nothing to render, we have to do it manually here. 575 if (!dragging.init && pos.cur === pos.dest) { 576 trigger('moveEnd'); 577 } 578 // Update times for future iteration 579 move.lastTime = move.now; 580 } 581 582 /** 583 * Stops continuous movement. 584 * 585 * @return {Void} 586 */ 587 self.stop = function () { 588 if (dragging.source === 'button') { 589 dragging.init = 0; 590 dragging.released = 1; 591 } 592 }; 593 594 /** 595 * Activate previous item. 596 * 597 * @return {Void} 598 */ 599 self.prev = function () { 600 self.activate(rel.activeItem == null ? 0 : rel.activeItem - 1); 601 }; 602 603 /** 604 * Activate next item. 605 * 606 * @return {Void} 607 */ 608 self.next = function () { 609 self.activate(rel.activeItem == null ? 0 : rel.activeItem + 1); 610 }; 611 612 /** 613 * Activate previous page. 614 * 615 * @return {Void} 616 */ 617 self.prevPage = function () { 618 self.activatePage(rel.activePage - 1); 619 }; 620 621 /** 622 * Activate next page. 623 * 624 * @return {Void} 625 */ 626 self.nextPage = function () {
627 self.activatePage(rel.activePage + 1); 628 }; 629 630 /** 631 * Slide SLIDEE by amount of pixels. 632 * 633 * @param {Int} delta Pixels/Items. Positive means forward, negative means backward. 634 * @param {Bool} immediate Reposition immediately without an animation. 635 * 636 * @return {Void} 637 */ 638 self.slideBy = function (delta, immediate) { 639 if (!delta) { 640 return; 641 } 642 if (itemNav) { 643 self[centeredNav ? 'toCenter' : 'toStart']( 644 within((centeredNav ? rel.centerItem : rel.firstItem) + o.scrollBy * delta, 0, items.length) 645 ); 646 } else { 647 slideTo(pos.dest + delta, immediate); 648 } 649 }; 650 651 /** 652 * Animate SLIDEE to a specific position. 653 * 654 * @param {Int} pos New position. 655 * @param {Bool} immediate Reposition immediately without an animation. 656 * 657 * @return {Void} 658 */ 659 self.slideTo = function (pos, immediate) { 660 slideTo(pos, immediate); 661 }; 662 663 /** 664 * Core method for handling `toLocation` methods. 665 * 666 * @param {String} location 667 * @param {Mixed} item 668 * @param {Bool} immediate 669 * 670 * @return {Void} 671 */ 672 function to(location, item, immediate) { 673 // Optional arguments logic 674 if (type(item) === 'boolean') { 675 immediate = item; 676 item = undefined; 677 } 678 679 if (item === undefined) { 680 slideTo(pos[location], immediate); 681 } else { 682 // You can't align items to sides of the frame 683 // when centered navigation type is enabled 684 if (centeredNav && location !== 'center') { 685 return; 686 } 687 688 var itemPos = self.getPos(item); 689 if (itemPos) { 690 slideTo(itemPos[location], immediate, !centeredNav); 691 } 692 } 693 } 694 695 /** 696 * Animate element or the whole SLIDEE to the start of the frame. 697 * 698 * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE. 699 * @param {Bool} immediate Reposition immediately without an animation. 700 * 701 * @return {Void} 702 */ 703 self.toStart = function (item, immediate) { 704 to('start', item, immediate); 705 }; 706 707 /** 708 * Animate element or the whole SLIDEE to the end of the frame. 709 * 710 * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE. 711 * @param {Bool} immediate Reposition immediately without an animation. 712 * 713 * @return {Void} 714 */ 715 self.toEnd = function (item, immediate) { 716 to('end', item, immediate); 717 }; 718 719 /** 720 * Animate element or the whole SLIDEE to the center of the frame. 721 * 722 * @param {Mixed} item Item DOM element, or index starting at 0. Omitting will animate SLIDEE. 723 * @param {Bool} immediate Reposition immediately without an animation. 724 * 725 * @return {Void} 726 */ 727 self.toCenter = function (item, immediate) { 728 to('center', item, immediate); 729 }; 730 731 /** 732 * Get the index of an item in SLIDEE. 733 * 734 * @param {Mixed} item Item DOM element. 735 * 736 * @return {Int} Item index, or -1 if not found. 737 */ 738 739 function getIndex(item) { 740 return item != null ? 741 isNumber(item) ? 742 item >= 0 && item < items.length ? item : -1 : 743 $items.index(item) : 744 -1; 745 } 746 // Expose getIndex without lowering the compressibility of it, 747 // as it is used quite often throughout TG_Slider. 748 self.getIndex = getIndex; 749 750 /** 751 * Get index of an item in SLIDEE based on a variety of input types. 752 * 753 * @param {Mixed} item DOM element, positive or negative integer. 754 * 755 * @return {Int} Item index, or -1 if not found. 756 */ 757 function getRelativeIndex(item) { 758 return getIndex(isNumber(item) && item < 0 ? item + items.length : item); 759 } 760 761 /** 762 * Activates an item. 763 * 764 * @param {Mixed} item Item DOM element, or index starting at 0. 765 * 766 * @return {Mixed} Activated item index or false on fail. 767 */ 768 /*function activate(item, force) { 769 var index = getIndex(item); 770 771 if (!itemNav || index < 0) { 772 return false; 773 } 774 775 // Update classes, last active index, and trigger active event only when there 776 // has been a change. Otherwise just return the current active index. 777 if (last.active !== index || force) { 778 // Update classes 779 $items.eq(rel.activeItem).removeClass(o.activeClass); 780 $items.eq(index).addClass(o.activeClass); 781 last.active = rel.activeItem = index; 782 783 updateButtonsState(); 784 trigger('active', index); 785 } 786 787 return index; 788 }*/ 789 790 /** 791 * Activates an item and helps with further navigation when o.smart is enabled. 792 * 793 * @param {Mixed} item Item DOM element, or index starting at 0. 794 * @param {Bool} immediate Whether to reposition immediately in smart navigation. 795 * 796 * @return {Void} 797 */ 798 /*self.activate = function (item, immediate) { 799 var index = activate(item); 800 801 // Smart navigation 802 if (o.smart && index !== false) { 803 // When centeredNav is enabled, center the element. 804 // Otherwise, determine where to position the element based on its current position. 805 // If the element is currently on the far end side of the frame, assume that user is 806 // moving forward and animate it to the start of the visible frame, and vice versa. 807 if (centeredNav) { 808 self.toCenter(index, immediate); 809 } else if (index >= rel.lastItem) { 810 self.toStart(index, immediate); 811 } else if (index <= rel.firstItem) { 812 self.toEnd(index, immediate); 813 } else { 814 resetCycle(); 815 } 816 } 817 };*/ 818 819 /** 820 * Activates a page. 821 * 822 * @param {Int} index Page index, starting from 0. 823 * @param {Bool} immediate Whether to reposition immediately without animation. 824 * 825 * @return {Void} 826 */ 827 self.activatePage = function (index, immediate) { 828 if (isNumber(index)) { 829 slideTo(pages[within(index, 0, pages.length - 1)], immediate); 830 } 831 }; 832 833 /** 834 * Return relative positions of items based on their visibility within FRAME. 835 * 836 * @param {Int} slideePos Position of SLIDEE. 837 * 838 * @return {Void} 839 */ 840 function getRelatives(slideePos) {
841 slideePos = within(isNumber(slideePos) ? slideePos : pos.dest, pos.start, pos.end); 842 843 var relatives = {}; 844 var centerOffset = forceCenteredNav ? 0 : frameSize / 2; 845 846 // Determine active page 847 if (!parallax) { 848 for (var p = 0, pl = pages.length; p < pl; p++) { 849 if (slideePos >= pos.end || p === pages.length - 1) { 850 relatives.activePage = pages.length - 1; 851 break; 852 } 853 854 if (slideePos <= pages[p] + centerOffset) { 855 relatives.activePage = p; 856 break; 857 } 858 } 859 } 860 861 // Relative item indexes 862 if (itemNav) { 863 var first = false; 864 var last = false; 865 var center = false; 866 867 // From start 868 for (var i = 0, il = items.length; i < il; i++) { 869 // First item 870 if (first === false && slideePos <= items[i].start + items[i].half) { 871 first = i; 872 } 873 874 // Center item 875 if (center === false && slideePos <= items[i].center + items[i].half) { 876 center = i; 877 } 878 879 880 // Last item 881 if (i === il - 1 || slideePos <= items[i].end + items[i].half) { 882 last = i; 883 break; 884 } 885 } 886 887 // Safe assignment, just to be sure the false won't be returned 888 relatives.firstItem = isNumber(first) ? first : 0; 889 relatives.centerItem = isNumber(center) ? center : relatives.firstItem; 890 relatives.lastItem = isNumber(last) ? last : relatives.centerItem; 891 } 892 893 return relatives; 894 } 895 896 /** 897 * Update object with relative positions. 898 * 899 * @param {Int} newPos 900 * 901 * @return {Void} 902 */ 903 function updateRelatives(newPos) { 904 $.extend(rel, getRelatives(newPos)); 905 } 906 907 /** 908 * Disable navigation buttons when needed. 909 * 910 * Adds disabledClass, and when the button is <button> or <input>, activates :disabled state. 911 * 912 * @return {Void} 913 */ 914 function updateButtonsState() { 915 var isStart = pos.dest <= pos.start; 916 var isEnd = pos.dest >= pos.end; 917 var slideePosState = (isStart ? 1 : 0) | (isEnd ? 2 : 0); 918 919 // Update paging buttons only if there has been a change in SLIDEE position 920 if (last.slideePosState !== slideePosState) { 921 last.slideePosState = slideePosState; 922 923 if ($prevPageButton.is('button,input')) { 924 $prevPageButton.prop('disabled', isStart); 925 } 926 927 if ($nextPageButton.is('button,input')) { 928 $nextPageButton.prop('disabled', isEnd); 929 } 930 931 $prevPageButton.add($backwardButton)[isStart ? 'addClass' : 'removeClass'](o.disabledClass); 932 $nextPageButton.add($forwardButton)[isEnd ? 'addClass' : 'removeClass'](o.disabledClass); 933 } 934 935 // Forward & Backward buttons need a separate state caching because we cannot "property disable" 936 // them while they are being used, as disabled buttons stop emitting mouse events. 937 if (last.fwdbwdState !== slideePosState && dragging.released) { 938 last.fwdbwdState = slideePosState; 939 940 if ($backwardButton.is('button,input')) { 941 $backwardButton.prop('disabled', isStart); 942 } 943 944 if ($forwardButton.is('button,input')) { 945 $forwardButton.prop('disabled', isEnd); 946 } 947 } 948 949 // Item navigation 950 if (itemNav && rel.activeItem != null) { 951 var isFirst = rel.activeItem === 0; 952 var isLast = rel.activeItem >= items.length - 1; 953 var itemsButtonState = (isFirst ? 1 : 0) | (isLast ? 2 : 0); 954 955 if (last.itemsButtonState !== itemsButtonState) { 956 last.itemsButtonState = itemsButtonState; 957 958 if ($prevButton.is('button,input')) { 959 $prevButton.prop('disabled', isFirst); 960 } 961 962 if ($nextButton.is('button,input')) { 963 $nextButton.prop('disabled', isLast); 964 } 965 966 $prevButton[isFirst ? 'addClass' : 'removeClass'](o.disabledClass); 967 $nextButton[isLast ? 'addClass' : 'removeClass'](o.disabledClass); 968 } 969 } 970 } 971 972 /** 973 * Resume cycling. 974 * 975 * @param {Int} priority Resume pause with priority lower or equal than this. Used internally for pauseOnHover. 976 * 977 * @return {Void} 978 */ 979 self.resume = function (priority) { 980 if (!o.cycleBy || !o.cycleInterval || o.cycleBy === 'items' && (!items[0] || rel.activeItem == null) || priority < self.isPaused) { 981 return; 982 } 983 984 self.isPaused = 0; 985 986 if (cycleID) { 987 cycleID = clearTimeout(cycleID); 988 } else { 989 trigger('resume'); 990 } 991 992 cycleID = setTimeout(function () { 993 trigger('cycle'); 994 switch (o.cycleBy) { 995 case 'items': 996 self.activate(rel.activeItem >= items.length - 1 ? 0 : rel.activeItem + 1); 997 break; 998 999 case 'pages': 1000 self.activatePage(rel.activePage >
1000= pages.length - 1 ? 0 : rel.activePage + 1); 1001 break; 1002 } 1003 }, o.cycleInterval); 1004 }; 1005 1006 /** 1007 * Pause cycling. 1008 * 1009 * @param {Int} priority Pause priority. 100 is default. Used internally for pauseOnHover. 1010 * 1011 * @return {Void} 1012 */ 1013 self.pause = function (priority) { 1014 if (priority < self.isPaused) { 1015 return; 1016 } 1017 1018 self.isPaused = priority || 100; 1019 1020 if (cycleID) { 1021 cycleID = clearTimeout(cycleID); 1022 trigger('pause'); 1023 } 1024 }; 1025 1026 /** 1027 * Toggle cycling. 1028 * 1029 * @return {Void} 1030 */ 1031 self.toggle = function () { 1032 self[cycleID ? 'pause' : 'resume'](); 1033 }; 1034 1035 /** 1036 * Updates a signle or multiple option values. 1037 * 1038 * @param {Mixed} name Name of the option that should be updated, or object that will extend the options. 1039 * @param {Mixed} value New option value. 1040 * 1041 * @return {Void} 1042 */ 1043 /*self.set = function (name, value) { 1044 if ($.isPlainObject(name)) { 1045 $.extend(o, name); 1046 } else if (o.hasOwnProperty(name)) { 1047 o[name] = value; 1048 } 1049 };*/ 1050 1051 /** 1052 * Registers callbacks. 1053 * 1054 * @param {Mixed} name Event name, or callbacks map. 1055 * @param {Mixed} fn Callback, or an array of callback functions. 1056 * 1057 * @return {Void} 1058 */ 1059 self.on = function (name, fn) { 1060 // Callbacks map 1061 if (type(name) === 'object') { 1062 for (var key in name) { 1063 if (name.hasOwnProperty(key)) { 1064 self.on(key, name[key]); 1065 } 1066 } 1067 // Callback 1068 } else if (type(fn) === 'function') { 1069 var names = name.split(' '); 1070 for (var n = 0, nl = names.length; n < nl; n++) { 1071 callbacks[names[n]] = callbacks[names[n]] || []; 1072 if (callbackIndex(names[n], fn) === -1) { 1073 callbacks[names[n]].push(fn); 1074 } 1075 } 1076 // Callbacks array 1077 } else if (type(fn) === 'array') { 1078 for (var f = 0, fl = fn.length; f < fl; f++) { 1079 self.on(name, fn[f]); 1080 } 1081 } 1082 }; 1083 1084 /** 1085 * Registers callbacks to be executed only once. 1086 * 1087 * @param {Mixed} name Event name, or callbacks map. 1088 * @param {Mixed} fn Callback, or an array of callback functions. 1089 * 1090 * @return {Void} 1091 */ 1092 /*self.one = function (name, fn) { 1093 function proxy() { 1094 fn.apply(self, arguments); 1095 self.off(name, proxy); 1096 } 1097 self.on(name, proxy); 1098 };*/ 1099 1100 /** 1101 * Remove one or all callbacks. 1102 * 1103 * @param {String} name Event name. 1104 * @param {Mixed} fn Callback, or an array of callback functions. Omit to remove all callbacks. 1105 * 1106 * @return {Void} 1107 */ 1108 /*self.off = function (name, fn) { 1109 if (fn instanceof Array) { 1110 for (var f = 0, fl = fn.length; f < fl; f++) { 1111 self.off(name, fn[f]); 1112 } 1113 } else { 1114 var names = name.split(' '); 1115 for (var n = 0, nl = names.length; n < nl; n++) { 1116 callbacks[names[n]] = callbacks[names[n]] || []; 1117 if (fn == null) { 1118 callbacks[names[n]].length = 0; 1119 } else { 1120 var index = callbackIndex(names[n], fn); 1121 if (index !== -1) { 1122 callbacks[names[n]].splice(index, 1); 1123 } 1124 } 1125 } 1126 } 1127 };*/ 1128 1129 /** 1130 * Returns callback array index. 1131 * 1132 * @param {String} name Event name. 1133 * @param {Function} fn Function 1134 * 1135 * @return {Int} Callback array index, or -1 if isn't registered. 1136 */ 1137 function callbackIndex(name, fn) { 1138 for (var i = 0, l = callbacks[name].length; i < l; i++) { 1139 if (callbacks[name][i] === fn) { 1140 return i; 1141 } 1142 } 1143 return -1; 1144 } 1145 1146 /** 1147 * Reset next cycle timeout. 1148 * 1149 * @return {Void} 1150 */ 1151 function resetCycle() { 1152 if (dragging.released && !self.isPaused) { 1153 self.resume(); 1154 } 1155 } 1156 1157 /** 1158 * Calculate SLIDEE representation of handle position. 1159 * 1160 * @param {Int} handlePos 1161 * 1162 * @return {Int} 1163 */ 1164 function handleToSlidee(handlePos) { 1165 return round(within(handlePos, hPos.start, hPos.end) / hPos.end * (pos.end - pos.start)) + pos.start; 1166 } 1167 1168 /** 1169 * Keeps track of a dragging delta history. 1170 * 1171 * @return {Void} 1172 */ 1173 function draggingHistoryTick() { 1174 // Looking at this, I know what you're thinking :) But as we need only 4 history states, doing it this way 1175 // as opposed to a proper loop is ~25 bytes smaller (when minified with GCC), a lot faster, and doesn't 1176 // generate garbage. The loop version would create 2 new variables on every tick. Unexaptable! 1177 dragging.history[0] = dragging.history[1]; 1178 dragging.history[1] = dragging.history[2]; 1179 dragging.history[2] = dragging.history[3]; 1180 dragging.history[3] = dragging.delta; 1181 } 1182 1183 /** 1184 * Initialize continuous movement. 1185 * 1186 * @return {Void} 1187 */ 1188 function continuousInit(source) { 1189 dragging.released = 0; 1190 dragging.source = source; 1191 dragging.slidee = source === 'slidee'; 1192 } 1193 1194 /** 1195 * Dragging initiator. 1196 * 1197 * @param {Event} event 1198 * 1199 * @return {Void} 1200 */ 1201 function dragInit(event) { 1202 var isTouch = event.type === 'touchstart'; 1203 var source = event.data.source; 1204 var isSlidee = source === 'slidee'; 1205 1206 // Ignore when already in progress, or interactive element in non-touch navivagion 1207 if (dragging.init || !isTouch && isInteractive(event.target)) { 1208 return; 1209 } 1210 1211 // Handle dragging conditions 1212 if (source === 'handle' && (!o.dragHandle || hPos.start === hPos.end)) { 1213 return; 1214 } 1215 1216 // SLIDEE dragging conditions 1217 if (isSlidee && !(isTouch ? o.touchDragging : o.mouseDragging && event.which < 2)) { 1218 return; 1219 } 1220 1221 if (!isTouch) { 1222 // prevents native image dragging in Firefox 1223 stopDefault(event); 1224 } 1225 1226 // Reset dragging object 1227 continuousInit(source); 1228 1229 // Properties used in dragHandler 1230 dragging.init = 0; 1231 dragging.$source = $(event.target); 1232 dragging.touch = isTouch; 1233 dragging.pointer = isTouch ? event.originalEvent.touches[0] : event; 1234 dragging.initX = dragging.pointer.pageX; 1235 dragging.initY = dragging.pointer.pageY;
1236 dragging.initPos = isSlidee ? pos.cur : hPos.cur; 1237 dragging.start = +new Date(); 1238 dragging.time = 0; 1239 dragging.path = 0; 1240 dragging.delta = 0; 1241 dragging.locked = 0; 1242 dragging.history = [0, 0, 0, 0]; 1243 dragging.pathToLock = isSlidee ? isTouch ? 30 : 10 : 0; 1244 1245 // Bind dragging events 1246 $doc.on(isTouch ? dragTouchEvents : dragMouseEvents, dragHandler); 1247 1248 // Pause ongoing cycle 1249 self.pause(1); 1250 1251 // Add dragging class 1252 (isSlidee ? $slidee : $handle).addClass(o.draggedClass); 1253 1254 // Trigger moveStart event 1255 trigger('moveStart'); 1256 1257 // Keep track of a dragging path history. This is later used in the 1258 // dragging release swing calculation when dragging SLIDEE. 1259 if (isSlidee) { 1260 historyID = setInterval(draggingHistoryTick, 10); 1261 } 1262 } 1263 1264 /** 1265 * Handler for dragging scrollbar handle or SLIDEE. 1266 * 1267 * @param {Event} event 1268 * 1269 * @return {Void} 1270 */ 1271 function dragHandler(event) { 1272 dragging.released = event.type === 'mouseup' || event.type === 'touchend'; 1273 dragging.pointer = dragging.touch ? event.originalEvent[dragging.released ? 'changedTouches' : 'touches'][0] : event; 1274 dragging.pathX = dragging.pointer.pageX - dragging.initX; 1275 dragging.pathY = dragging.pointer.pageY - dragging.initY; 1276 dragging.path = sqrt(pow(dragging.pathX, 2) + pow(dragging.pathY, 2)); 1277 dragging.delta = o.horizontal ? dragging.pathX : dragging.pathY; 1278 1279 if (!dragging.released && dragging.path < 1) return; 1280 1281 if (!dragging.init) { 1282 if (o.horizontal ? abs(dragging.pathX) > abs(dragging.pathY) : abs(dragging.pathX) < abs(dragging.pathY)) { 1283 dragging.init = 1; 1284 } else { 1285 return dragEnd(); 1286 } 1287 } 1288 1289 stopDefault(event); 1290 1291 // Disable click on a source element, as it is unwelcome when dragging 1292 if (!dragging.locked && dragging.path > dragging.pathToLock && dragging.slidee) { 1293 dragging.locked = 1; 1294 dragging.$source.on(clickEvent, disableOneEvent); 1295 } 1296 1297 // Cancel dragging on release 1298 if (dragging.released) { 1299 dragEnd(); 1300 1301 // Adjust path with a swing on mouse release 1302 if (o.releaseSwing && dragging.slidee) { 1303 dragging.swing = (dragging.delta - dragging.history[0]) / 40 * 300; 1304 dragging.delta += dragging.swing; 1305 dragging.tweese = abs(dragging.swing) > 10; 1306 } 1307 } 1308 1309 slideTo(dragging.slidee ? round(dragging.initPos - dragging.delta) : handleToSlidee(dragging.initPos + dragging.delta)); 1310 } 1311 1312 /** 1313 * Stops dragging and cleans up after it. 1314 * 1315 * @return {Void} 1316 */ 1317 function dragEnd() { 1318 clearInterval(historyID); 1319 dragging.released = true; 1320 $doc.off(dragging.touch ? dragTouchEvents : dragMouseEvents, dragHandler); 1321 (dragging.slidee ? $slidee : $handle).removeClass(o.draggedClass); 1322 1323 // Make sure that disableOneEvent is not active in next tick. 1324 setTimeout(function () { 1325 dragging.$source.off(clickEvent, disableOneEvent); 1326 }); 1327 1328 // Normally, this is triggered in render(), but if there 1329 // is nothing to render, we have to do it manually here. 1330 if (pos.cur === pos.dest && dragging.init) { 1331 trigger('moveEnd'); 1332 } 1333 1334 // Resume ongoing cycle 1335 self.resume(1); 1336 1337 dragging.init = 0; 1338 } 1339 1340 /** 1341 * Check whether element is interactive. 1342 * 1343 * @return {Boolean} 1344 */ 1345 function isInteractive(element) { 1346 return ~$.inArray(element.nodeName, interactiveElements) || $(element).is(o.interactive); 1347 } 1348 1349 /** 1350 * Continuous movement cleanup on mouseup. 1351 * 1352 * @return {Void} 1353 */ 1354 function movementReleaseHandler() { 1355 self.stop(); 1356 $doc.off('mouseup', movementReleaseHandler); 1357 } 1358 1359 /** 1360 * Buttons navigation handler. 1361 * 1362 * @param {Event} event 1363 * 1364 * @return {Void} 1365 */ 1366 function buttonsHandler(event) { 1367 /*jshint validthis:true */ 1368 stopDefault(event); 1369 switch (this) { 1370 case $forwardButton[0]: 1371 case $backwardButton[0]: 1372 self.moveBy($forwardButton.is(this) ? o.moveBy : -o.moveBy); 1373 $doc.on('mouseup', movementReleaseHandler); 1374 break; 1375 1376 case $prevButton[0]: 1377 self.prev(); 1378 break; 1379 1380 case $nextButton[0]: 1381 self.next(); 1382 break; 1383 1384 case $prevPageButton[0]: 1385 self.prevPage(); 1386 break; 1387 1388 case $nextPageButton[0]: 1389 self.nextPage(); 1390 break; 1391 } 1392 } 1393 1394 /** 1395 * Mouse wheel delta normalization. 1396 * 1397 * @param {Event} event 1398 * 1399 * @return {Int} 1400 */ 1401 /*function normalizeWheelDelta(event) { 1402 // wheelDelta needed only for IE8- 1403 scrolling.curDelta = ((o.horizontal ? event.deltaY || event.deltaX : event.deltaY) || -event.wheelDelta); 1404 scrolling.curDelta /= event.deltaMode === 1 ? 3 : 100; 1405 if (!itemNav) { 1406 return scrolling.curDelta; 1407 } 1408 time = +new Date(); 1409 if (scrolling.last < time - scrolling.resetTime) { 1410 scrolling.delta = 0; 1411 } 1412 scrolling.last = time; 1413 scrolling.delta += scrolling.curDelta; 1414 if (abs(scrolling.delta) < 1) { 1415 scrolling.finalDelta = 0; 1416 } else { 1417 scrolling.finalDelta = round(scrolling.delta / 1); 1418 scrolling.delta %= 1;
1419 } 1420 return scrolling.finalDelta; 1421 }*/ 1422 1423 /** 1424 * Mouse scrolling handler. 1425 * 1426 * @param {Event} event 1427 * 1428 * @return {Void} 1429 */ 1430 /*function scrollHandler(event) { 1431 // Mark event as originating in a TG_Slider instance 1432 event.originalEvent[namespace] = self; 1433 // Don't hijack global scrolling 1434 var time = +new Date(); 1435 if (lastGlobalWheel + o.scrollHijack > time && $scrollSource[0] !== document && $scrollSource[0] !== window) { 1436 lastGlobalWheel = time; 1437 return; 1438 } 1439 // Ignore if there is no scrolling to be done 1440 if (!o.scrollBy || pos.start === pos.end) { 1441 return; 1442 } 1443 var delta = normalizeWheelDelta(event.originalEvent); 1444 // Trap scrolling only when necessary and/or requested 1445 if (o.scrollTrap || delta > 0 && pos.dest < pos.end || delta < 0 && pos.dest > pos.start) { 1446 stopDefault(event, 1); 1447 } 1448 self.slideBy(o.scrollBy * delta); 1449 }*/ 1450 1451 /** 1452 * Scrollbar click handler. 1453 * 1454 * @param {Event} event 1455 * 1456 * @return {Void} 1457 */ 1458 /*function scrollbarHandler(event) { 1459 // Only clicks on scroll bar. Ignore the handle. 1460 if (o.clickBar && event.target === $sb[0]) { 1461 stopDefault(event); 1462 // Calculate new handle position and sync SLIDEE to it 1463 slideTo(handleToSlidee((o.horizontal ? event.pageX - $sb.offset().left : event.pageY - $sb.offset().top) - handleSize / 2)); 1464 } 1465 }*/ 1466 1467 /** 1468 * Keyboard input handler. 1469 * 1470 * @param {Event} event 1471 * 1472 * @return {Void} 1473 */ 1474 function keyboardHandler(event) { 1475 if (!o.keyboardNavBy) { 1476 return; 1477 } 1478 1479 switch (event.which) { 1480 // Left or Up 1481 case o.horizontal ? 37 : 38: 1482 stopDefault(event); 1483 self[o.keyboardNavBy === 'pages' ? 'prevPage' : 'prev'](); 1484 break; 1485 1486 // Right or Down 1487 case o.horizontal ? 39 : 40: 1488 stopDefault(event); 1489 self[o.keyboardNavBy === 'pages' ? 'nextPage' : 'next'](); 1490 break; 1491 } 1492 } 1493 1494 /** 1495 * Click on item activation handler. 1496 * 1497 * @param {Event} event 1498 * 1499 * @return {Void} 1500 */ 1501 /*function activateHandler(event) { 1502 1503 // Ignore clicks on interactive elements. 1504 if (isInteractive(this)) { 1505 event.originalEvent[namespace + 'ignore'] = true; 1506 return; 1507 } 1508 1509 // Ignore events that: 1510 // - are not originating from direct SLIDEE children 1511 // - originated from interactive elements 1512 if (this.parentNode !== $slidee[0] || event.originalEvent[namespace + 'ignore']) return; 1513 1514 self.activate(this); 1515 }*/ 1516 1517 /** 1518 * Click on page button handler. 1519 * 1520 * @param {Event} event 1521 * 1522 * @return {Void} 1523 */ 1524 function activatePageHandler() { 1525 /*jshint validthis:true */ 1526 // Accept only events from direct pages bar children. 1527 if (this.parentNode === $pb[0]) { 1528 self.activatePage($pages.index(this)); 1529 } 1530 } 1531 1532 /** 1533 * Pause on hover handler. 1534 * 1535 * @param {Event} event 1536 * 1537 * @return {Void} 1538 */ 1539 function pauseOnHoverHandler(event) { 1540 if (o.pauseOnHover) { 1541 self[event.type === 'mouseenter' ? 'pause' : 'resume'](2); 1542 } 1543 } 1544 1545 /** 1546 * Trigger callbacks for event. 1547 * 1548 * @param {String} name Event name. 1549 * @param {Mixed} argX Arguments passed to callbacks. 1550 * 1551 * @return {Void} 1552 */ 1553 function trigger(name, arg1) { 1554 if (callbacks[name]) { 1555 l = callbacks[name].length; 1556 // Callbacks will be stored and executed from a temporary array to not 1557 // break the execution queue when one of the callbacks unbinds itself. 1558 tmpArray.length = 0; 1559 for (i = 0; i < l; i++) { 1560 tmpArray.push(callbacks[name][i]); 1561 } 1562 // Execute the callbacks 1563 for (i = 0; i < l; i++) { 1564 tmpArray[i].call(self, name, arg1); 1565 } 1566 } 1567 } 1568 1569 /** 1570 * Destroys instance and everything it created. 1571 * 1572 * @return {Void} 1573 */ 1574 /*self.destroy = function () { 1575 // Unbind all events 1576 $scrollSource 1577 .add($handle) 1578 .add($sb) 1579 .add($pb) 1580 .add($forwardButton) 1581 .add($backwardButton) 1582 .add($prevButton) 1583 .add($nextButton) 1584 .add($prevPageButton) 1585 .add($nextPageButton) 1586 .off('.' + namespace); 1587 1588 // Unbinding specifically as to not nuke out other instances 1589 $doc.off('keydown', keyboardHandler); 1590 1591 // Remove classes 1592 $prevButton 1593 .add($nextButton) 1594 .add($prevPageButton) 1595 .add($nextPageButton) 1596 .removeClass(o.disabledClass); 1597 1598 if ($items && rel.activeItem != null) { 1599 $items.eq(rel.activeItem).removeClass(o.activeClass); 1600 } 1601 1602 // Remove page items 1603 $pb.empty(); 1604 1605 if (!parallax) { 1606 // Unbind events from frame 1607 $frame.off('.' + namespace); 1608 // Restore original styles
1609 frameStyles.restore(); 1610 slideeStyles.restore(); 1611 sbStyles.restore(); 1612 handleStyles.restore(); 1613 // Remove the instance from element data storage 1614 $.removeData(frame, namespace); 1615 } 1616 1617 // Clean up collections 1618 items.length = pages.length = 0; 1619 last = {}; 1620 1621 // Reset initialized status and return the instance 1622 self.initialized = 0; 1623 return self; 1624 };*/ 1625 1626 /** 1627 * Initialize. 1628 * 1629 * @return {Object} 1630 */ 1631 self.init = function () { 1632 if (self.initialized) { 1633 return; 1634 } 1635 1636 // Register callbacks map 1637 self.on(callbackMap); 1638 1639 // Save styles 1640 var holderProps = ['overflow', 'position']; 1641 var movableProps = ['position', 'webkitTransform', 'msTransform', 'transform', 'left', 'top', 'width', 'height']; 1642 frameStyles.save.apply(frameStyles, holderProps); 1643 sbStyles.save.apply(sbStyles, holderProps); 1644 slideeStyles.save.apply(slideeStyles, movableProps); 1645 handleStyles.save.apply(handleStyles, movableProps); 1646 1647 // Set required styles 1648 var $movables = $handle; 1649 if (!parallax) { 1650 $movables = $movables.add($slidee); 1651 $frame.css('overflow', 'hidden'); 1652 if (!transform && $frame.css('position') === 'static') { 1653 $frame.css('position', 'relative'); 1654 } 1655 } 1656 if (transform) { 1657 if (gpuAcceleration) { 1658 $movables.css(transform, gpuAcceleration); 1659 } 1660 } else { 1661 if ($sb.css('position') === 'static') { 1662 $sb.css('position', 'relative'); 1663 } 1664 $movables.css({ position: 'absolute' }); 1665 } 1666 1667 // Navigation buttons 1668 if (o.forward) { 1669 $forwardButton.on(mouseDownEvent, buttonsHandler); 1670 } 1671 if (o.backward) { 1672 $backwardButton.on(mouseDownEvent, buttonsHandler); 1673 } 1674 if (o.prev) { 1675 $prevButton.on(clickEvent, buttonsHandler); 1676 } 1677 if (o.next) { 1678 $nextButton.on(clickEvent, buttonsHandler); 1679 } 1680 if (o.prevPage) { 1681 $prevPageButton.on(clickEvent, buttonsHandler); 1682 } 1683 if (o.nextPage) { 1684 $nextPageButton.on(clickEvent, buttonsHandler); 1685 } 1686 1687 // Scrolling navigation 1688 //$scrollSource.on(wheelEvent, scrollHandler); 1689 1690 // Clicking on scrollbar navigation 1691 /*if ($sb[0]) { 1692 $sb.on(clickEvent, scrollbarHandler); 1693 }*/ 1694 1695 // Click on items navigation 1696 /*if (itemNav && o.activateOn) { 1697 $frame.on(o.activateOn + '.' + namespace, '*', activateHandler); 1698 }*/ 1699 1700 // Pages navigation 1701 if ($pb[0] && o.activatePageOn) { 1702 $pb.on(o.activatePageOn + '.' + namespace, '*', activatePageHandler); 1703 } 1704 1705 // Dragging navigation 1706 $dragSource.on(dragInitEvents, { source: 'slidee' }, dragInit); 1707 1708 // Scrollbar dragging navigation 1709 if ($handle) { 1710 $handle.on(dragInitEvents, { source: 'handle' }, dragInit); 1711 } 1712 1713 // Keyboard navigation 1714 $doc.on('keydown', keyboardHandler); 1715 1716 if (!parallax) { 1717 // Pause on hover 1718 $frame.on('mouseenter.' + namespace + ' mouseleave.' + namespace, pauseOnHoverHandler); 1719 // Reset native FRAME element scroll 1720 $frame.on('scroll.' + namespace, resetScroll); 1721 } 1722 1723 // Mark instance as initialized 1724 self.initialized = 1; 1725 1726 // Load 1727 load(true); 1728 1729 // Initiate automatic cycling 1730 if (o.cycleBy && !parallax) { 1731 self[o.startPaused ? 'pause' : 'resume'](); 1732 } 1733 1734 // Return instance 1735 return self; 1736 }; 1737 } 1738 1739 /** 1740 * Return type of the value. 1741 * 1742 * @param {Mixed} value 1743 * 1744 * @return {String} 1745 */ 1746 function type(value) { 1747 if (value == null) { 1748 return String(value); 1749 } 1750 1751 if (typeof value === 'object' || typeof value === 'function') { 1752 return Object.prototype.toString.call(value).match(/\s([a-z]+)/i)[1].toLowerCase() || 'object'; 1753 } 1754 1755 return typeof value; 1756 } 1757 1758 /** 1759 * Event preventDefault & stopPropagation helper. 1760 * 1761 * @param {Event} event Event object. 1762 * @param {Bool} noBubbles Cancel event bubbling. 1763 * 1764 * @return {Void} 1765 */ 1766 function stopDefault(event, noBubbles) { 1767 event.preventDefault(); 1768 if (noBubbles) { 1769 event.stopPropagation(); 1770 } 1771 } 1772 1773 /** 1774 * Disables an event it was triggered on and unbinds itself. 1775 * 1776 * @param {Event} event 1777 * 1778 * @return {Void} 1779 */ 1780 function disableOneEvent(event) { 1781 /*jshint validthis:true */ 1782 stopDefault(event, 1); 1783 $(this).off(event.type, disableOneEvent); 1784 } 1785 1786 /** 1787 * Resets native element scroll values to 0. 1788 * 1789 * @return {Void} 1790 */ 1791 function resetScroll() { 1792 /*jshint validthis:true */ 1793 this.scrollLeft = 0; 1794 this.scrollTop = 0; 1795 } 1796 1797 /** 1798 * Check if variable is a number. 1799 * 1800 * @param {Mixed} value 1801 * 1802 * @return {Boolean} 1803 */ 1804 function isNumber(value) { 1805 return !isNaN(parseFloat(value)) && isFinite(value); 1806 } 1807 1808 /** 1809 * Parse style to pixels. 1810 * 1811 * @param {Object} $item jQuery object with element. 1812 * @param {Property} property CSS property to get the pixels from. 1813 * 1814 * @return {Int} 1815 */ 1816 function getPx($item, property) {
1817 return 0 | round(String($item.css(property)).replace(/[^\-0-9.]/g, '')); 1818 } 1819 1820 /** 1821 * Make sure that number is within the limits. 1822 * 1823 * @param {Number} number 1824 * @param {Number} min 1825 * @param {Number} max 1826 * 1827 * @return {Number} 1828 */ 1829 function within(number, min, max) { 1830 return number < min ? min : number > max ? max : number; 1831 } 1832 1833 /** 1834 * Saves element styles for later restoration. 1835 * 1836 * Example: 1837 * var styles = new StyleRestorer(frame); 1838 * styles.save('position'); 1839 * element.style.position = 'absolute'; 1840 * styles.restore(); // restores to state before the assignment above 1841 * 1842 * @param {Element} element 1843 */ 1844 function StyleRestorer(element) { 1845 var self = {}; 1846 self.style = {}; 1847 self.save = function () { 1848 if (!element || !element.nodeType) return; 1849 for (var i = 0; i < arguments.length; i++) { 1850 self.style[arguments[i]] = element.style[arguments[i]]; 1851 } 1852 return self; 1853 }; 1854 self.restore = function () { 1855 if (!element || !element.nodeType) return; 1856 for (var prop in self.style) { 1857 if (self.style.hasOwnProperty(prop)) element.style[prop] = self.style[prop]; 1858 } 1859 return self; 1860 }; 1861 return self; 1862 } 1863 1864 // Local WindowAnimationTiming interface polyfill 1865 (function (w) { 1866 rAF = w.requestAnimationFrame 1867 || w.webkitRequestAnimationFrame 1868 || fallback; 1869 1870 /** 1871 * Fallback implementation. 1872 */ 1873 var prev = new Date().getTime(); 1874 function fallback(fn) { 1875 var curr = new Date().getTime(); 1876 var ms = Math.max(0, 16 - (curr - prev)); 1877 var req = setTimeout(fn, ms); 1878 prev = curr; 1879 return req; 1880 } 1881 1882 /** 1883 * Cancel. 1884 */ 1885 var cancel = w.cancelAnimationFrame 1886 || w.webkitCancelAnimationFrame 1887 || w.clearTimeout; 1888 1889 cAF = function(id){ 1890 cancel.call(w, id); 1891 }; 1892 }(window)); 1893 1894 // Feature detects 1895 (function () { 1896 var prefixes = ['', 'Webkit', 'Moz', 'ms', 'O']; 1897 var el = document.createElement('div'); 1898 1899 function testProp(prop) { 1900 for (var p = 0, pl = prefixes.length; p < pl; p++) { 1901 var prefixedProp = prefixes[p] ? prefixes[p] + prop.charAt(0).toUpperCase() + prop.slice(1) : prop; 1902 if (el.style[prefixedProp] != null) { 1903 return prefixedProp; 1904 } 1905 } 1906 } 1907 1908 // Global support indicators 1909 transform = testProp('transform'); 1910 gpuAcceleration = testProp('perspective') ? 'translateZ(0) ' : ''; 1911 }()); 1912 1913 // Expose class globally 1914 w[className] = TG_Slider; 1915 1916 // jQuery proxy 1917 $.fn[pluginName] = function (options, callbackMap) { 1918 var method, methodArgs; 1919 1920 // Attributes logic 1921 if (!$.isPlainObject(options)) { 1922 if (type(options) === 'string' || options === false) { 1923 method = options === false ? 'destroy' : options; 1924 methodArgs = Array.prototype.slice.call(arguments, 1); 1925 } 1926 options = {}; 1927 } 1928 1929 // Apply to all elements 1930 return this.each(function (i, element) { 1931 // Call with prevention against multiple instantiations 1932 var plugin = $.data(element, namespace); 1933 1934 if (!plugin && !method) { 1935 // Create a new object if it doesn't exist yet 1936 plugin = $.data(element, namespace, new TG_Slider(element, options, callbackMap).init()); 1937 } else if (plugin && method) { 1938 // Call method 1939 if (plugin[method]) { 1940 plugin[method].apply(plugin, methodArgs); 1941 } 1942 } 1943 }); 1944 }; 1945 1946 // Default options 1947 /*TG_Slider.defaults = { 1948 slidee: null, // Selector, DOM element, or jQuery object with DOM element representing SLIDEE. 1949 horizontal: false, // Switch to horizontal mode. 1950 1951 // Item based navigation 1952 itemNav: null, // Item navigation type. Can be: 'basic', 'centered', 'forceCentered'. 1953 itemSelector: null, // Select only items that match this selector. 1954 smart: false, // Repositions the activated item to help with further navigation. 1955 activateOn: null, // Activate an item on this event. Can be: 'click', 'mouseenter', ... 1956 activateMiddle: false, // Always activate the item in the middle of the FRAME. forceCentered only. 1957 1958 // Scrolling 1959 scrollSource: null, // Element for catching the mouse wheel scrolling. Default is FRAME. 1960 scrollBy: 0, // Pixels or items to move per one mouse scroll. 0 to disable scrolling. 1961 scrollHijack: 300, // Milliseconds since last wheel event after which it is acceptable to hijack global scroll. 1962 scrollTrap: false, // Don't bubble scrolling when hitting scrolling limits. 1963 1964 // Dragging 1965 dragSource: null, // Selector or DOM element for catching dragging events. Default is FRAME. 1966 mouseDragging: false, // Enable navigation by dragging the SLIDEE with mouse cursor. 1967 touchDragging: false, // Enable navigation by dragging the SLIDEE with touch events. 1968 releaseSwing: false, // Ease out on dragging swing release. 1969 swingSpeed: 0.2, // Swing synchronization speed, where: 1 = instant, 0 = infinite. 1970 elasticBounds: false, // Stretch SLIDEE position limits when dragging past FRAME boundaries. 1971 interactive: null, // Selector for special interactive elements. 1972 1973 // Scrollbar 1974 scrollBar: null, // Selector or DOM element for scrollbar container. 1975 dragHandle: false, // Whether the scrollbar handle should be draggable. 1976 dynamicHandle: false, // Scrollbar handle represents the ratio between hidden and visible content. 1977 minHandleSize: 50, // Minimal height or width (depends on TG_Slider direction) of a handle in pixels. 1978 clickBar: false, // Enable navigation by clicking on scrollbar. 1979 syncSpeed: 0.5, // Handle =>
1979 SLIDEE synchronization speed, where: 1 = instant, 0 = infinite. 1980 1981 // Pagesbar 1982 pagesBar: null, // Selector or DOM element for pages bar container. 1983 activatePageOn: null, // Event used to activate page. Can be: click, mouseenter, ... 1984 pageBuilder: // Page item generator. 1985 function (index) { 1986 return '<li>' + (index + 1) + '</li>'; 1987 }, 1988 1989 // Navigation buttons 1990 forward: null, // Selector or DOM element for "forward movement" button. 1991 backward: null, // Selector or DOM element for "backward movement" button. 1992 prev: null, // Selector or DOM element for "previous item" button. 1993 next: null, // Selector or DOM element for "next item" button. 1994 prevPage: null, // Selector or DOM element for "previous page" button. 1995 nextPage: null, // Selector or DOM element for "next page" button. 1996 1997 // Automated cycling 1998 cycleBy: null, // Enable automatic cycling by 'items' or 'pages'. 1999 cycleInterval: 5000, // Delay between cycles in milliseconds. 2000 pauseOnHover: false, // Pause cycling when mouse hovers over the FRAME. 2001 startPaused: false, // Whether to start in paused sate. 2002 2003 // Mixed options 2004 moveBy: 300, // Speed in pixels per second used by forward and backward buttons. 2005 speed: 0, // Animations speed in milliseconds. 0 to disable animations. 2006 easing: 'swing', // Easing for duration based (tweening) animations. 2007 startAt: null, // Starting offset in pixels or items. 2008 keyboardNavBy: null, // Enable keyboard navigation by 'items' or 'pages'. 2009 2010 // Classes 2011 draggedClass: 'dragged', // Class for dragged elements (like SLIDEE or scrollbar handle). 2012 activeClass: 'active', // Class for active items and pages. 2013 disabledClass: 'disabled' // Class for disabled navigation elements. 2014 };*/ 2015}(jQuery, window));
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.