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