1/* 2 * jQuery SmoothDivScroll 1.3 3 * 4 * Copyright (c) 2012 Thomas Kahn 5 * Licensed under the GPL license. 6 * 7 * http://www.smoothdivscroll.com/ 8 * 9 * Depends: 10 * jquery-1.8.x.min.js 11 Please use https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js 12 ...or later 13 14 * jquery.ui.widget.js 15 * jquery.ui.effects.min.js 16 Make your own custom download at http://jqueryui.com/download. 17 First deselect all components. Then check just "Widget" and "Effects Core". 18 Download the file and put it in your javascript folder. 19 20 * jquery.mousewheel.min.js 21 Used for mousewheel functionality. 22 Download the latest version at http://brandonaaron.net/code/mousewheel/demos 23 * 24 25 * jquery.kinetic.js 26 Used for scrolling by dragging, mainly used on touch devices. 27 Download the latest version at https://github.com/davetayls/jquery.kinetic 28 * 29 */ 30(function ($) { 31 32 $.widget("thomaskahn.smoothDivScroll", { 33 // Default options 34 options: { 35 // Classes for elements added by Smooth Div Scroll 36 scrollingHotSpotLeftClass: "scrollingHotSpotLeft", // String 37 scrollingHotSpotRightClass: "scrollingHotSpotRight", // String 38 scrollableAreaClass: "scrollableArea", // String 39 scrollWrapperClass: "scrollWrapper", // String 40 41 // Misc settings 42 hiddenOnStart: false, // Boolean 43 getContentOnLoad: {}, // Object 44 countOnlyClass: "", // String 45 startAtElementId: "", // String 46 47 // Hotspot scrolling 48 hotSpotScrolling: true, // Boolean 49 hotSpotScrollingStep: 15, // Pixels 50 hotSpotScrollingInterval: 100, // Milliseconds 51 hotSpotMouseDownSpeedBooster: 3, // Integer 52 visibleHotSpotBackgrounds: "hover", // always, onStart, hover or empty (no visible hotspots) 53 hotSpotsVisibleTime: 50000, // Milliseconds 54 easingAfterHotSpotScrolling: true, // Boolean 55 easingAfterHotSpotScrollingDistance: 10, // Pixels 56 easingAfterHotSpotScrollingDuration: 3000, // Milliseconds 57 easingAfterHotSpotScrollingFunction: "easeOutQuart", // String 58 59 // Mousewheel scrolling 60 mousewheelScrolling: "", // vertical, horizontal, allDirections or empty (no mousewheel scrolling) String 61 mousewheelScrollingStep: 70, // Pixels 62 easingAfterMouseWheelScrolling: true, // Boolean 63 easingAfterMouseWheelScrollingDuration: 300, // Milliseconds 64 easingAfterMouseWheelScrollingFunction: "easeOutQuart", // String 65 66 // Manual scrolling (hotspot and/or mousewheel scrolling) 67 manualContinuousScrolling: false, // Boolean 68 69 // Autoscrolling 70 autoScrollingMode: "", // always, onStart or empty (no auto scrolling) String 71 autoScrollingDirection: "endlessLoopRight", // right, left, backAndForth, endlessLoopRight, endlessLoopLeft String 72 autoScrollingStep: 1, // Pixels 73 autoScrollingInterval: 10, // Milliseconds 74 75 // Touch scrolling 76 touchScrolling: false, 77 78 // Easing for when the scrollToElement method is used 79 scrollToAnimationDuration: 19000, // Milliseconds 80 scrollToEasingFunction: "easeOutQuart" // String 81 }, 82 _create: function () { 83 var self = this, o = this.options, el = this.element; 84 85 // Create variables for any existing or not existing 86 // scroller elements on the page. 87 el.data("scrollWrapper", el.find("." + o.scrollWrapperClass)); 88 el.data("scrollingHotSpotRight", el.find("." + o.scrollingHotSpotRightClass)); 89 el.data("scrollingHotSpotLeft", el.find("." + o.scrollingHotSpotLeftClass)); 90 el.data("scrollableArea", el.find("." + o.scrollableAreaClass)); 91 92 // Check which elements are already present on the page. 93 // Create any elements needed by the plugin if 94 // the user hasn't already created them. 95 96 // First detach any present hot spots 97 if (el.data("scrollingHotSpotRight").length > 0) { 98 99 el.data("scrollingHotSpotRight").detach(); 100 } 101 if (el.data("scrollingHotSpotLeft").length > 0) { 102 103 el.data("scrollingHotSpotLeft").detach(); 104 } 105 106 // Both the scrollable area and the wrapper are missing 107 if (el.data("scrollableArea").length === 0 && el.data("scrollWrapper").length === 0) { 108 el.wrapInner("<div class='" + o.scrollableAreaClass + "'>").wrapInner("<div class='" + o.scrollWrapperClass + "'>"); 109 110 el.data("scrollWrapper", el.find("." + o.scrollWrapperClass)); 111 el.data("scrollableArea", el.find("." + o.scrollableAreaClass)); 112 } 113 // Only the wrapper is missing 114 else if (el.data("scrollWrapper").length === 0) { 115 el.wrapInner("<div class='" + o.scrollWrapperClass + "'>"); 116 el.data("scrollWrapper", el.find("." + o.scrollWrapperClass)); 117 } 118 // Only the scrollable area is missing 119 else if (el.data("scrollableArea").length === 0) { 120 el.data("scrollWrapper").wrapInner("<div class='" + o.scrollableAreaClass + "'>"); 121 el.data("scrollableArea", el.find("." + o.scrollableAreaClass)); 122 } 123 124 // Put the right and left hot spot back into the scroller again 125 // or create them if they where not present from the beginning. 126 if (el.data("scrollingHotSpotRight").length === 0) { 127 el.prepend("<div class='" + o.scrollingHotSpotRightClass + "'></div>"); 128 el.data("scrollingHotSpotRight", el.find("." + o.scrollingHotSpotRightClass)); 129 } else { 130 el.prepend(el.data("scrollingHotSpotRight")); 131 } 132 133 if (el.data("scrollingHotSpotLeft").length === 0) { 134 el.prepend("<div class='" + o.scrollingHotSpotLeftClass + "'></div>"); 135 el.data("scrollingHotSpotLeft", el.find("." + o.scrollingHotSpotLeftClass)); 136 } else { 137 el.prepend(el.data("scrollingHotSpotLeft")); 138 } 139 140 141 // Create variables in the element data storage 142 el.data("speedBooster", 1); 143 el.data("scrollXPos", 0); 144 el.data("hotSpotWidth", el.data("scrollingHotSpotLeft").innerWidth()); 145 el.data("scrollableAreaWidth", 0); 146 el.data("startingPosition", 0); 147 el.data("rightScrollingInterval", null); 148 el.data("leftScrollingInterval", null); 149 el.data("autoScrollingInterval", null);
150 el.data("hideHotSpotBackgroundsInterval", null); 151 el.data("previousScrollLeft", 0); 152 el.data("pingPongDirection", "right"); 153 el.data("getNextElementWidth", true); 154 el.data("swapAt", null); 155 el.data("startAtElementHasNotPassed", true); 156 el.data("swappedElement", null); 157 el.data("originalElements", el.data("scrollableArea").children(o.countOnlyClass)); 158 el.data("visible", true); 159 el.data("enabled", true); 160 el.data("scrollableAreaHeight", el.data("scrollableArea").height()); 161 el.data("scrollerOffset", el.offset()); 162 163 /***************************************** 164 SET UP EVENTS FOR TOUCH SCROLLING 165 *****************************************/ 166 if (o.touchScrolling && el.data("enabled")) { 167 // Use jquery.kinetic.js for touch scrolling 168 // Vertical scrolling disabled 169 el.data("scrollWrapper").kinetic({ 170 y: false, 171 moved: function (settings) { 172 if (o.manualContinuousScrolling) { 173 if (el.data("scrollWrapper").scrollLeft() <= 0) { 174 self._checkContinuousSwapLeft(); 175 } else { 176 self._checkContinuousSwapRight(); 177 } 178 } 179 }, 180 stopped: function (settings) { 181 // Stop any ongoing animations 182 el.data("scrollWrapper").stop(true, false); 183 184 // Stop any ongoing auto scrolling 185 self.stopAutoScrolling(); 186 } 187 }); 188 } 189 190 /***************************************** 191 SET UP EVENTS FOR SCROLLING RIGHT 192 *****************************************/ 193 // Check the mouse X position and calculate 194 // the relative X position inside the right hotspot 195 el.data("scrollingHotSpotRight").bind("mousemove", function (e) { 196 if (o.hotSpotScrolling) { 197 var x = e.pageX - (this.offsetLeft + el.data("scrollerOffset").left); 198 el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep)); 199 200 // If the position is less then 1, it's set to 1 201 if (el.data("scrollXPos") === Infinity || el.data("scrollXPos") < 1) { 202 el.data("scrollXPos", 1); 203 } 204 } 205 }); 206 207 // Mouseover right hotspot - scrolling 208 el.data("scrollingHotSpotRight").bind("mouseover", function () { 209 if (o.hotSpotScrolling) { 210 // Stop any ongoing animations 211 el.data("scrollWrapper").stop(true, false); 212 213 // Stop any ongoing auto scrolling 214 self.stopAutoScrolling(); 215 216 // Start the scrolling interval 217 el.data("rightScrollingInterval", setInterval(function () { 218 if (el.data("scrollXPos") > 0 && el.data("enabled")) { 219 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (el.data("scrollXPos") * el.data("speedBooster"))); 220 221 if (o.manualContinuousScrolling) { 222 self._checkContinuousSwapRight(); 223 } 224 225 self._showHideHotSpots(); 226 } 227 }, o.hotSpotScrollingInterval)); 228 229 // Callback 230 self._trigger("mouseOverRightHotSpot"); 231 } 232 }); 233 234 // Mouseout right hotspot - stop scrolling 235 el.data("scrollingHotSpotRight").bind("mouseout", function () { 236 if (o.hotSpotScrolling) { 237 clearInterval(el.data("rightScrollingInterval")); 238 el.data("scrollXPos", 0); 239 240 // Easing out after scrolling 241 if (o.easingAfterHotSpotScrolling && el.data("enabled")) { 242 el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() + o.easingAfterHotSpotScrollingDistance }, { duration: o.easingAfterHotSpotScrollingDuration, easing: o.easingAfterHotSpotScrollingFunction }); 243 } 244 } 245 }); 246 247 248 // mousedown right hotspot (add scrolling speed booster) 249 el.data("scrollingHotSpotRight").bind("mousedown", function () { 250 el.data("speedBooster", o.hotSpotMouseDownSpeedBooster); 251 }); 252 253 // mouseup anywhere (stop boosting the scrolling speed) 254 $("body").bind("mouseup", function () { 255 el.data("speedBooster", 1); 256 }); 257 258 /***************************************** 259 SET UP EVENTS FOR SCROLLING LEFT 260 *****************************************/ 261 // Check the mouse X position and calculate 262 // the relative X position inside the left hotspot 263 el.data("scrollingHotSpotLeft").bind("mousemove", function (e) { 264 if (o.hotSpotScrolling) { 265 var x = ((this.offsetLeft + el.data("scrollerOffset").left + el.data("hotSpotWidth")) - e.pageX); 266 267 el.data("scrollXPos", Math.round((x / el.data("hotSpotWidth")) * o.hotSpotScrollingStep)); 268 269 // If the position is less then 1, it's set to 1 270 if (el.data("scrollXPos") === Infinity || el.data("scrollXPos") < 1) { 271 el.data("scrollXPos", 1); 272 } 273 } 274 }); 275 276 // Mouseover left hotspot 277 el.data("scrollingHotSpotLeft").bind("mouseover", function () { 278 if (o.hotSpotScrolling) { 279 // Stop any ongoing animations 280 el.data("scrollWrapper").stop(true, false); 281 282 // Stop any ongoing auto scrolling 283 self.stopAutoScrolling(); 284 285 el.data("leftScrollingInterval", setInterval(function () { 286 if (el.data("scrollXPos") > 0 && el.data("enabled")) { 287 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (el.data("scrollXPos") * el.data("speedBooster"))); 288 289 if (o.manualContinuousScrolling) { 290 self._checkContinuousSwapLeft(); 291 } 292 293 self._showHideHotSpots(); 294 } 295 }, o.hotSpotScrollingInterval)); 296 297 // Callback 298 self._trigger("mouseOverLeftHotSpot"); 299 } 300 }); 301 302 // mouseout left hotspot 303 el.data("scrollingHotSpotLeft").bind("mouseout", function () { 304 if (o.hotSpotScrolling) { 305 clearInterval(el.data("leftScrollingInterval")); 306 el.data("scrollXPos", 0); 307 308 // Easing out after scrolling 309 if (o.easingAfterHotSpotScrolling && el.data("enabled")) { 310 el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() - o.easingAfterHotSpotScrollingDistance }, { duration: o.easingAfterHotSpotScrollingDuration, easing: o.easingAfterHotSpotScrollingFunction }); 311 } 312 } 313 }); 314
315 // mousedown left hotspot (add scrolling speed booster) 316 el.data("scrollingHotSpotLeft").bind("mousedown", function () { 317 el.data("speedBooster", o.hotSpotMouseDownSpeedBooster); 318 }); 319 320 /***************************************** 321 SET UP EVENT FOR MOUSEWHEEL SCROLLING 322 *****************************************/ 323 el.data("scrollableArea").mousewheel(function (event, delta, deltaX, deltaY) { 324 325 if (el.data("enabled") && o.mousewheelScrolling.length > 0) { 326 var pixels; 327 328 // Can be either positive or negative 329 // Is multiplied/inverted by minus one since you want it to scroll 330 // left when moving the wheel down/right and right when moving the wheel up/left 331 if (o.mousewheelScrolling === "vertical" && deltaY !== 0) { 332 // Stop any ongoing auto scrolling if it's running 333 self.stopAutoScrolling(); 334 event.preventDefault(); 335 pixels = Math.round((o.mousewheelScrollingStep * deltaY) * -1); 336 self.move(pixels); 337 } else if (o.mousewheelScrolling === "horizontal" && deltaX !== 0) { 338 // Stop any ongoing auto scrolling if it's running 339 self.stopAutoScrolling(); 340 event.preventDefault(); 341 pixels = Math.round((o.mousewheelScrollingStep * deltaX) * -1); 342 self.move(pixels); 343 } else if (o.mousewheelScrolling === "allDirections") { 344 // Stop any ongoing auto scrolling if it's running 345 self.stopAutoScrolling(); 346 event.preventDefault(); 347 pixels = Math.round((o.mousewheelScrollingStep * delta) * -1); 348 self.move(pixels); 349 } 350 351 352 } 353 }); 354 355 // Capture and disable mousewheel events when the pointer 356 // is over any of the hotspots 357 if (o.mousewheelScrolling) { 358 el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).mousewheel(function (event) { 359 event.preventDefault(); 360 }); 361 } 362 363 /***************************************** 364 SET UP EVENT FOR RESIZING THE BROWSER WINDOW 365 *****************************************/ 366 $(window).bind("resize", function () { 367 self._showHideHotSpots(); 368 self._trigger("windowResized"); 369 }); 370 371 /***************************************** 372 FETCHING CONTENT ON INITIALIZATION 373 *****************************************/ 374 // If getContentOnLoad is present in the options, 375 // sort out the method and parameters and get the content 376 377 if (!(jQuery.isEmptyObject(o.getContentOnLoad))) { 378 self[o.getContentOnLoad.method](o.getContentOnLoad.content, o.getContentOnLoad.manipulationMethod, o.getContentOnLoad.addWhere, o.getContentOnLoad.filterTag); 379 } 380 381 // Should it be hidden on start? 382 if (o.hiddenOnStart) { 383 self.hide(); 384 } 385 386 /***************************************** 387 AUTOSCROLLING 388 *****************************************/ 389 // The $(window).load event handler is used because the width of the elements are not calculated 390 // properly until then, at least not in Google Chrome. The start of the auto scrolling and the 391 // setting of the hotspot backgrounds is started here as well for the same reason. 392 // If the auto scrolling is not started in $(window).load, it won't start because it 393 // will interpret the scrollable areas as too short. 394 395 $(function() { 396 397 //calculate the scrollable area 398 if (!(o.hiddenOnStart)) { 399 self.recalculateScrollableArea(); 400 } 401 402 // Autoscrolling is active 403 if ((o.autoScrollingMode.length > 0) && !(o.hiddenOnStart)) { 404 self.startAutoScrolling(); 405 } 406 407 // If the user wants to have visible hotspot backgrounds, 408 // here is where it's taken care of 409 if (o.autoScrollingMode !== "always") { 410 411 switch (o.visibleHotSpotBackgrounds) { 412 case "always": 413 self.showHotSpotBackgrounds(); 414 break; 415 case "onStart": 416 self.showHotSpotBackgrounds(); 417 el.data("hideHotSpotBackgroundsInterval", setTimeout(function () { 418 self.hideHotSpotBackgrounds(250); 419 }, o.hotSpotsVisibleTime)); 420 break; 421 case "hover": 422 el.mouseenter(function (event) { 423 if (o.hotSpotScrolling) { 424 event.stopPropagation();
425 self.showHotSpotBackgrounds(250); 426 } 427 }).mouseleave(function (event) { 428 if (o.hotSpotScrolling) { 429 event.stopPropagation(); 430 self.hideHotSpotBackgrounds(250); 431 } 432 }); 433 break; 434 default: 435 break; 436 } 437 } 438 439 self._showHideHotSpots(); 440 441 self._trigger("setupComplete"); 442 443 }); 444 445 }, 446 /********************************************************** 447 Override _setOption and handle altered options 448 **********************************************************/ 449 _setOption: function (key, value) { 450 var self = this, o = this.options, el = this.element; 451 452 // Update option 453 o[key] = value; 454 455 if (key === "hotSpotScrolling") { 456 // Handler if the option hotSpotScrolling is altered 457 if (value === true) { 458 self._showHideHotSpots(); 459 } else { 460 el.data("scrollingHotSpotLeft").hide(); 461 el.data("scrollingHotSpotRight").hide(); 462 } 463 } else if (key === "autoScrollingStep" || 464 // Make sure that certain values are integers, otherwise 465 // they will summon bad spirits in the plugin 466 key === "easingAfterHotSpotScrollingDistance" || 467 key === "easingAfterHotSpotScrollingDuration" || 468 key === "easingAfterMouseWheelScrollingDuration") { 469 o[key] = parseInt(value, 10); 470 } else if (key === "autoScrollingInterval") { 471 // Handler if the autoScrollingInterval is altered 472 o[key] = parseInt(value, 10); 473 self.startAutoScrolling(); 474 } 475 476 }, 477 /********************************************************** 478 Hotspot functions 479 **********************************************************/ 480 showHotSpotBackgrounds: function (fadeSpeed) { 481 482 // Alter the CSS (SmoothDivScroll.css) if you want to customize 483 // the look'n'feel of the visible hotspots 484 var self = this, el = this.element, o = this.option; 485 486 487 // Fade in the hotspot backgrounds 488 if (fadeSpeed !== undefined) { 489 // Before the fade-in starts, we need to make sure the opacity is zero 490 //el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).css("opacity", "0.0"); 491 492 el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible"); 493 el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible"); 494 495 // Fade in the hotspots 496 el.data("scrollingHotSpotLeft").add(el.data("scrollingHotSpotRight")).fadeTo(fadeSpeed, 0.35); 497 } 498 // Don't fade, just show them 499 else { 500 501 // The left hotspot 502 el.data("scrollingHotSpotLeft").addClass("scrollingHotSpotLeftVisible"); 503 el.data("scrollingHotSpotLeft").removeAttr("style"); 504 505 // The right hotspot 506 el.data("scrollingHotSpotRight").addClass("scrollingHotSpotRightVisible"); 507 el.data("scrollingHotSpotRight").removeAttr("style"); 508 } 509 510 self._showHideHotSpots(); 511 512 }, 513 hideHotSpotBackgrounds: function (fadeSpeed) { 514 var el = this.element, o = this.option; 515 516 // Fade out the hotspot backgrounds 517 if (fadeSpeed !== undefined) { 518 519 // Fade out the left hotspot 520 el.data("scrollingHotSpotLeft").fadeTo(fadeSpeed, 0.0, function () { 521 el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible"); 522 }); 523 524 // Fade out the right hotspot 525 el.data("scrollingHotSpotRight").fadeTo(fadeSpeed, 0.0, function () { 526 el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible"); 527 }); 528 529 } 530 // Don't fade, just hide them 531 else { 532 el.data("scrollingHotSpotLeft").removeClass("scrollingHotSpotLeftVisible").removeAttr("style"); 533 el.data("scrollingHotSpotRight").removeClass("scrollingHotSpotRightVisible").removeAttr("style"); 534 } 535 536 }, 537 // Function for showing and hiding hotspots depending on the 538 // offset of the scrolling 539 _showHideHotSpots: function () { 540 var self = this, el = this.element, o = this.options; 541 542 // Hot spot scrolling is not enabled so show no hot spots 543 if (!(o.hotSpotScrolling)) { 544 el.data("scrollingHotSpotLeft").hide(); 545 el.data("scrollingHotSpotRight").hide(); 546 } else { 547 548 // If the manual continuous scrolling option is set show both 549 if (o.manualContinuousScrolling && o.hotSpotScrolling && o.autoScrollingMode !== "always") { 550 el.data("scrollingHotSpotLeft").show(); 551 el.data("scrollingHotSpotRight").show(); 552 } 553 // Autoscrolling not set to always and hotspot scrolling enabled. 554 // Regular hot spot scrolling. 555 else if (o.autoScrollingMode !== "always" && o.hotSpotScrolling) { 556 // If the scrollable area is shorter than the scroll wrapper, both hotspots 557 // should be hidden 558 if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth())) { 559 el.data("scrollingHotSpotLeft").hide(); 560 el.data("scrollingHotSpotRight").hide(); 561 } 562 // When you can't scroll further left the left scroll hotspot should be hidden 563 // and the right hotspot visible. 564 else if (el.data("scrollWrapper").scrollLeft() === 0) { 565 el.data("scrollingHotSpotLeft").hide(); 566 el.data("scrollingHotSpotRight").show(); 567 // Callback 568 self._trigger("scrollerLeftLimitReached"); 569 // Clear interval 570 clearInterval(el.data("leftScrollingInterval")); 571 el.data("leftScrollingInterval", null); 572 } 573 // When you can't scroll further right 574 // the right scroll hotspot should be hidden 575 // and the left hotspot visible 576 else if (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft())) { 577 el.data("scrollingHotSpotLeft").show(); 578 el.data("scrollingHotSpotRight").hide(); 579 // Callback 580 self._trigger("scrollerRightLimitReached"); 581 // Clear interval 582 clearInterval(el.data("rightScrollingInterval")); 583 el.data("rightScrollingInterval", null); 584 } 585 // If you are somewhere in the middle of your 586 // scrolling, both hotspots should be visible 587 else { 588 el.data("scrollingHotSpotLeft").show(); 589 el.data("scrollingHotSpotRight").show(); 590 } 591 } 592 // If auto scrolling is set to always, there should be no hotspots 593 else { 594 el.data("scrollingHotSpotLeft").hide(); 595 el.data("scrollingHotSpotRight").hide(); 596 } 597 } 598 599 600 601 }, 602 // Function for calculating the scroll position of a certain element 603 _setElementScrollPosition: function (method, element) { 604 var el = this.element, o = this.options, tempScrollPosition = 0; 605 606 switch (method) { 607 case "first": 608 el.data("scrollXPos", 0); 609 return true; 610 case "start": 611 // Check to see if there is a specified start element in the options 612 // and that the element exists in the DOM 613 if (o.startAtElementId !== "") { 614 if (el.data("scrollableArea").has("#" + o.startAtElementId)) { 615 tempScrollPosition = $("#" + o.startAtElementId).position().left; 616 el.data("scrollXPos", tempScrollPosition); 617 return true; 618 } 619 } 620 return false; 621 case "last": 622 el.data("scrollXPos", (el.data("scrollableAreaWidth") - el.data("scrollWrapper").innerWidth())); 623 return true; 624 case "number": 625 // Check to see that an element number is passed 626 if (!(isNaN(element))) { 627 tempScrollPosition = el.data("scrollableArea").children(o.countOnlyClass).eq(element - 1).position().left; 628 el.data("scrollXPos", tempScrollPosition); 629 return true; 630 } 631 return false; 632 case "id": 633 // Check that an element id is passed and that the element exists in the DOM 634 if (element.length > 0) { 635 if (el.data("scrollableArea").has("#" + element)) { 636 tempScrollPosition = $("#" + element).position().left; 637 el.data("scrollXPos", tempScrollPosition); 638 return true; 639 } 640 } 641 return false; 642 default: 643 return false; 644 } 645 646 647 }, 648 /********************************************************** 649 Jumping to a certain element 650 **********************************************************/ 651 jumpToElement: function (jumpTo, element) { 652 var self = this, el = this.element; 653 654 // Check to see that the scroller is enabled 655 if (el.data("enabled")) { 656 // Get the position of the element to scroll to 657 if (self._setElementScrollPosition(jumpTo, element)) { 658 // Jump to the element 659 el.data("scrollWrapper").scrollLeft(el.data("scrollXPos")); 660 // Check the hotspots 661 self._showHideHotSpots(); 662 // Trigger the right callback 663 switch (jumpTo) { 664 case "first": 665 self._trigger("jumpedToFirstElement"); 666 break; 667 case "start": 668 self._trigger("jumpedToStartElement"); 669 break; 670 case "last": 671 self._trigger("jumpedToLastElement"); 672 break; 673 case "number": 674 self._trigger("jumpedToElementNumber", null, { "elementNumber": element }); 675 break; 676 case "id": 677 self._trigger("jumpedToElementId", null, { "elementId": element }); 678 break; 679 default: 680 break; 681 } 682 683 } 684 } 685 }, 686 /********************************************************** 687 Scrolling to a certain element 688 **********************************************************/ 689 scrollToElement: function (scrollTo, element) { 690 var self = this, el = this.element, o = this.options, autoscrollingWasRunning = false; 691 692 if (el.data("enabled")) { 693 // Get the position of the element to scroll to 694 if (self._setElementScrollPosition(scrollTo, element)) { 695 // Stop any ongoing auto scrolling 696 if (el.data("autoScrollingInterval") !== null) { 697 self.stopAutoScrolling(); 698 autoscrollingWasRunning = true; 699 } 700 701 // Stop any other running animations 702 // (clear queue but don't jump to the end) 703 el.data("scrollWrapper").stop(true, false); 704 705 // Do the scolling animation 706 el.data("scrollWrapper").animate({ 707 scrollLeft: el.data("scrollXPos") 708 }, { duration: o.scrollToAnimationDuration, easing: o.scrollToEasingFunction, complete: function () { 709 // If auto scrolling was running before, start it again 710 if (autoscrollingWasRunning) { 711 self.startAutoScrolling(); 712 } 713 714 self._showHideHotSpots(); 715 716 // Trigger the right callback 717 switch (scrollTo) { 718 case "first": 719 self._trigger("scrolledToFirstElement"); 720 break; 721 case "start": 722 self._trigger("scrolledToStartElement"); 723 break; 724 case "last": 725 self._trigger("scrolledToLastElement"); 726 break; 727 case "number": 728 self._trigger("scrolledToElementNumber", null, { "elementNumber": element }); 729 break; 730 case "id": 731 self._trigger("scrolledToElementId", null, { "elementId": element }); 732 break; 733 default: 734 break; 735 } 736 } 737 });
738 } 739 } 740 741 }, 742 move: function (pixels) { 743 var self = this, el = this.element, o = this.options; 744 // clear queue, move to end 745 el.data("scrollWrapper").stop(true, true); 746 747 // Only run this code if it's possible to scroll left or right, 748 if ((pixels < 0 && el.data("scrollWrapper").scrollLeft() > 0) || (pixels > 0 && el.data("scrollableAreaWidth") > (el.data("scrollWrapper").innerWidth() + el.data("scrollWrapper").scrollLeft()))) { 749 if (o.easingAfterMouseWheelScrolling) { 750 el.data("scrollWrapper").animate({ scrollLeft: el.data("scrollWrapper").scrollLeft() + pixels }, { duration: o.easingAfterMouseWheelScrollingDuration, easing: o.easingAfterMouseWheelFunction, complete: function () { 751 self._showHideHotSpots(); 752 if (o.manualContinuousScrolling) { 753 if (pixels > 0) { 754 self._checkContinuousSwapRight(); 755 } else { 756 self._checkContinuousSwapLeft(); 757 } 758 } 759 } 760 }); 761 } else { 762 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + pixels); 763 self._showHideHotSpots(); 764 765 if (o.manualContinuousScrolling) { 766 if (pixels > 0) { 767 self._checkContinuousSwapRight(); 768 } else { 769 self._checkContinuousSwapLeft(); 770 } 771 } 772 } 773 } 774 775 776 }, 777 /********************************************************** 778 Adding or replacing content 779 **********************************************************/ 780 /* Arguments are: 781 content - a valid URL to a Flickr feed - string 782 manipulationMethod - addFirst, addLast or replace (default) - string 783 */ 784 getFlickrContent: function (content, manipulationMethod) { 785 var self = this, el = this.element; 786 787 $.getJSON(content, function (data) { 788 // small square - size is 75x75 789 // thumbnail -> large - size is the longest side 790 var flickrImageSizes = [{ size: "small square", pixels: 75, letter: "_s" }, 791 { size: "thumbnail", pixels: 100, letter: "_t" }, 792 { size: "small", pixels: 240, letter: "_m" }, 793 { size: "medium", pixels: 500, letter: "" }, 794 { size: "medium 640", pixels: 640, letter: "_z" }, 795 { size: "large", pixels: 1024, letter: "_b"}]; 796 var loadedFlickrImages = []; 797 var imageIdStringBuffer = []; 798 var startingIndex; 799 var numberOfFlickrItems = data.items.length; 800 var loadedFlickrImagesCounter = 0; 801 802 // Determine a plausible starting value for the 803 // image height 804 if (el.data("scrollableAreaHeight") <= 75) { 805 startingIndex = 0; 806 } else if (el.data("scrollableAreaHeight") <= 100) { 807 startingIndex = 1; 808 } else if (el.data("scrollableAreaHeight") <= 240) { 809 startingIndex = 2; 810 } else if (el.data("scrollableAreaHeight") <= 500) { 811 startingIndex = 3; 812 } else if (el.data("scrollableAreaHeight") <= 640) { 813 startingIndex = 4; 814 } else { 815 startingIndex = 5; 816 } 817 818 // Put all items from the feed in an array. 819 // This is necessary 820 $.each(data.items, function (index, item) { 821 loadFlickrImage(item, startingIndex); 822 }); 823 824 function loadFlickrImage(item, sizeIndex) { 825 var path = item.media.m; 826 var imgSrc = path.replace("_m", flickrImageSizes[sizeIndex].letter); 827 var tempImg = $("<img />").attr("src", imgSrc); 828 829 tempImg.load(function () { 830 // Is it still smaller? Load next size 831 if (this.height < el.data("scrollableAreaHeight")) { 832 // Load a bigger image, if possible 833 if ((sizeIndex + 1) < flickrImageSizes.length) { 834 loadFlickrImage(item, sizeIndex + 1); 835 } else { 836 addImageToLoadedImages(this); 837 } 838 } 839 else { 840 addImageToLoadedImages(this); 841 } 842 843 // Finishing stuff to do when all images have been loaded 844 if (loadedFlickrImagesCounter === numberOfFlickrItems) { 845 switch (manipulationMethod) { 846 case "addFirst": 847 // Add the loaded content first in the scrollable area 848 el.data("scrollableArea").children(":first").before(loadedFlickrImages); 849 break; 850 case "addLast": 851 // Add the loaded content last in the scrollable area 852 el.data("scrollableArea").children(":last").after(loadedFlickrImages); 853 break; 854 default: 855 // Replace the content in the scrollable area 856 el.data("scrollableArea").html(loadedFlickrImages); 857 break; 858 } 859 860 // Recalculate the total width of the elements inside the scrollable area 861 self.recalculateScrollableArea(); 862 863 // Determine which hotspots to show 864 self._showHideHotSpots(); 865 866 // Trigger callback 867 self._trigger("addedFlickrContent", null, { "addedElementIds": imageIdStringBuffer }); 868 } 869 870 });
871 } 872 873 // Add the loaded content first or last in the scrollable area 874 function addImageToLoadedImages(imageObj) { 875 // Calculate the scaled width 876 var widthScalingFactor = el.data("scrollableAreaHeight") / imageObj.height; 877 var tempWidth = Math.round(imageObj.width * widthScalingFactor); 878 // Set an id for the image - the filename is used as an id 879 var tempIdArr = $(imageObj).attr("src").split("/"); 880 var lastElemIndex = (tempIdArr.length - 1); 881 tempIdArr = tempIdArr[lastElemIndex].split("."); 882 $(imageObj).attr("id", tempIdArr[0]); 883 // Set the height of the image to the height of the scrollable area and add the width 884 $(imageObj).css({ "height": el.data("scrollableAreaHeight"), "width": tempWidth }); 885 // Add the id of the image to the array of id's - this 886 // is used as a parameter when the callback is triggered 887 imageIdStringBuffer.push(tempIdArr[0]); 888 // Add the image to the array of loaded images 889 loadedFlickrImages.push(imageObj); 890 891 // Increment counter for loaded images 892 loadedFlickrImagesCounter++; 893 } 894 895 }); 896 }, 897 /* Arguments are: 898 content - a valid URL to an AJAX content source - string 899 manipulationMethod - addFirst, addLast or replace (default) - string 900 filterTag - a jQuery selector that matches the elements from the AJAX content 901 source that you want, for example ".myClass" or "#thisDiv" or "div" - string 902 */ 903 getAjaxContent: function (content, manipulationMethod, filterTag) { 904 var self = this, el = this.element; 905 $.ajaxSetup({ cache: false }); 906 907 $.get(content, function (data) { 908 var filteredContent; 909 910 if (filterTag !== undefined) { 911 if (filterTag.length > 0) { 912 // A bit of a hack since I can't know if the element 913 // that the user wants is a direct child of body (= use filter) 914 // or other types of elements (= use find) 915 filteredContent = $("<div>").html(data).find(filterTag); 916 } else { 917 filteredContent = content; 918 } 919 } else { 920 filteredContent = data; 921 } 922 923 switch (manipulationMethod) { 924 case "addFirst": 925 // Add the loaded content first in the scrollable area 926 el.data("scrollableArea").children(":first").before(filteredContent); 927 break; 928 case "addLast": 929 // Add the loaded content last in the scrollable area 930 el.data("scrollableArea").children(":last").after(filteredContent); 931 break; 932 default: 933 // Replace the content in the scrollable area 934 el.data("scrollableArea").html(filteredContent); 935 break; 936 } 937 938 // Recalculate the total width of the elements inside the scrollable area 939 self.recalculateScrollableArea(); 940 941 // Determine which hotspots to show 942 self._showHideHotSpots(); 943 944 // Trigger callback 945 self._trigger("addedAjaxContent"); 946 947 }); 948 }, 949 getHtmlContent: function (content, manipulationMethod, filterTag) { 950 var self = this, el = this.element; 951 952 // No AJAX involved at all - just add raw HTML-content 953 /* Arguments are: 954 content - any raw HTML that you want - string 955 manipulationMethod - addFirst, addLast or replace (default) - string 956 filterTag - a jQuery selector that matches the elements from the AJAX content 957 source that you want, for example ".myClass" or "#thisDiv" or "div" - string 958 */ 959 var filteredContent; 960 if (filterTag !== undefined) { 961 if (filterTag.length > 0) { 962 // A bit of a hack since I can't know if the element 963 // that the user wants is a direct child of body (= use filter) 964 // or other types of elements (= use find) 965 filteredContent = $("<div>").html(content).find(filterTag); 966 } else { 967 filteredContent = content; 968 } 969 } else { 970 filteredContent = content; 971 } 972 973 switch (manipulationMethod) { 974 case "addFirst": 975 // Add the loaded content first in the scrollable area 976 el.data("scrollableArea").children(":first").before(filteredContent); 977 break; 978 case "addLast": 979 // Add the loaded content last in the scrollable area 980 el.data("scrollableArea").children(":last").after(filteredContent); 981 break; 982 default: 983 // Replace the content in the scrollable area 984 el.data("scrollableArea").html(filteredContent); 985 break; 986 } 987 988 // Recalculate the total width of the elements inside the scrollable area 989 self.recalculateScrollableArea(); 990 991 // Determine which hotspots to show 992 self._showHideHotSpots(); 993 994 // Trigger callback 995 self._trigger("addedHtmlContent"); 996 997 }, 998 /********************************************************** 999 Recalculate the scrollable area 1000 **********************************************************/ 1001 recalculateScrollableArea: function () { 1002 1003 var tempScrollableAreaWidth = 0, foundStartAtElement = false, o = this.options, el = this.element; 1004 1005 // Add up the total width of all the items inside the scrollable area 1006 el.data("scrollableArea").children(o.countOnlyClass).each(function () { 1007 // Check to see if the current element in the loop is the one where the scrolling should start 1008 if ((o.startAtElementId.length > 0) && (($(this).attr("id")) === o.startAtElementId)) { 1009 el.data("startingPosition", tempScrollableAreaWidth); 1010 foundStartAtElement = true; 1011 } 1012 tempScrollableAreaWidth = tempScrollableAreaWidth + $(this).outerWidth(true); 1013 1014 }); 1015 1016 // If the element with the ID specified by startAtElementId 1017 // is not found, reset it 1018 if (!(foundStartAtElement)) { 1019 el.data("startAtElementId", ""); 1020 } 1021 1022 // Set the width of the scrollable area 1023 el.data("scrollableAreaWidth", tempScrollableAreaWidth); 1024 el.data("scrollableArea").width(el.data("scrollableAreaWidth")); 1025 1026 // Move to the starting position 1027 el.data("scrollWrapper").scrollLeft(el.data("startingPosition")); 1028 el.data("scrollXPos", el.data("startingPosition")); 1029 }, 1030 /********************************************************** 1031 Get current scrolling left offset 1032 **********************************************************/ 1033 getScrollerOffset: function () { 1034 var el = this.element; 1035 1036 // Returns the current left offset 1037 // Please remember that if the scroller is in continuous 1038 // mode, the offset is not that relevant anymore since 1039 // the plugin will swap the elements inside the scroller 1040 // around and manipulate the offset in this process. 1041 return el.data("scrollWrapper").scrollLeft(); 1042 }, 1043 /********************************************************** 1044 Stopping, starting and doing the auto scrolling 1045 **********************************************************/ 1046 stopAutoScrolling: function () { 1047 var self = this, el = this.element; 1048 1049 if (el.data("autoScrollingInterval") !== null) { 1050 clearInterval(el.data("autoScrollingInterval")); 1051 el.data("autoScrollingInterval", null); 1052 1053 // Check to see which hotspots should be active 1054 // in the position where the scroller has stopped 1055 self._showHideHotSpots(); 1056 1057 self._trigger("autoScrollingStopped"); 1058 } 1059 }, 1060 /********************************************************** 1061 Start Autoscrolling 1062 **********************************************************/ 1063 startAutoScrolling: function () { 1064 var self = this, el = this.element, o = this.options; 1065 1066 if (el.data("enabled")) { 1067 self._showHideHotSpots(); 1068 1069 // Stop any running interval 1070 clearInterval(el.data("autoScrollingInterval")); 1071 el.data("autoScrollingInterval", null); 1072 1073 // Callback 1074 self._trigger("autoScrollingStarted"); 1075 1076 // Start interval 1077 el.data("autoScrollingInterval", setInterval(function () { 1078 1079 // If the scroller is not visible or 1080 // if the scrollable area is shorter than the scroll wrapper 1081 // any running auto scroll interval should stop. 1082 if (!(el.data("visible")) || (el.data("scrollableAreaWidth") <= (el.data("scrollWrapper").innerWidth()))) { 1083 // Stop any running interval 1084 clearInterval(el.data("autoScrollingInterval")); 1085 el.data("autoScrollingInterval", null); 1086 1087 } 1088 else { 1089 1090 // Store the old scrollLeft value to see if the scrolling has reached the end 1091 el.data("previousScrollLeft", el.data("scrollWrapper").scrollLeft()); 1092 1093 switch (o.autoScrollingDirection) { 1094 case "right": 1095 1096 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep); 1097 if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) { 1098 self._trigger("autoScrollingRightLimitReached"); 1099 clearInterval(el.data("autoScrollingInterval")); 1100 el.data("autoScrollingInterval", null); 1101 self._trigger("autoScrollingIntervalStopped"); 1102 } 1103 break; 1104
1105 case "left": 1106 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep); 1107 if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) { 1108 self._trigger("autoScrollingLeftLimitReached"); 1109 clearInterval(el.data("autoScrollingInterval")); 1110 el.data("autoScrollingInterval", null); 1111 self._trigger("autoScrollingIntervalStopped"); 1112 } 1113 break; 1114 1115 case "backAndForth": 1116 if (el.data("pingPongDirection") === "right") { 1117 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + (o.autoScrollingStep)); 1118 } 1119 else { 1120 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - (o.autoScrollingStep)); 1121 } 1122 1123 // If the scrollLeft hasnt't changed it means that the scrolling has reached 1124 // the end and the direction should be switched 1125 if (el.data("previousScrollLeft") === el.data("scrollWrapper").scrollLeft()) { 1126 if (el.data("pingPongDirection") === "right") { 1127 el.data("pingPongDirection", "left"); 1128 self._trigger("autoScrollingRightLimitReached"); 1129 } 1130 else { 1131 el.data("pingPongDirection", "right"); 1132 self._trigger("autoScrollingLeftLimitReached"); 1133 } 1134 } 1135 break; 1136 1137 case "endlessLoopRight": 1138 1139 // Do the auto scrolling 1140 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + o.autoScrollingStep); 1141 1142 self._checkContinuousSwapRight(); 1143 break; 1144 case "endlessLoopLeft": 1145 1146 // Do the auto scrolling 1147 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() - o.autoScrollingStep); 1148 1149 self._checkContinuousSwapLeft(); 1150 break; 1151 default: 1152 break; 1153 1154 } 1155 } 1156 }, o.autoScrollingInterval)); 1157 } 1158 }, 1159 /********************************************************** 1160 Check Continuos Swap Right 1161 **********************************************************/ 1162 _checkContinuousSwapRight: function () { 1163 var el = this.element, o = this.options; 1164 1165 // Get the width of the first element. When it has scrolled out of view, 1166 // the element swapping should be executed. A true/false variable is used 1167 // as a flag variable so the swapAt value doesn't have to be recalculated 1168 // in each loop. 1169 if (el.data("getNextElementWidth")) { 1170 1171 if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) { 1172 // If the user has set a certain element to start at, set swapAt 1173 // to that element width. This happens once. 1174 el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true)); 1175 el.data("startAtElementHasNotPassed", false); 1176 } 1177 else { 1178 // Set swapAt to the first element in the scroller 1179 el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true)); 1180 } 1181 el.data("getNextElementWidth", false); 1182 } 1183 1184 1185 // Check to see if the swap should be done 1186 if (el.data("swapAt") <= el.data("scrollWrapper").scrollLeft()) { 1187 el.data("swappedElement", el.data("scrollableArea").children(":first").detach()); 1188 el.data("scrollableArea").append(el.data("swappedElement")); 1189 var wrapperLeft = el.data("scrollWrapper").scrollLeft(); 1190 el.data("scrollWrapper").scrollLeft(wrapperLeft - el.data("swappedElement").outerWidth(true)); 1191 el.data("getNextElementWidth", true); 1192 } 1193 }, 1194 /********************************************************** 1195 Check Continuos Swap Left 1196 **********************************************************/ 1197 _checkContinuousSwapLeft: function () { 1198 var el = this.element, o = this.options; 1199 1200 // Get the width of the first element. When it has scrolled out of view, 1201 // the element swapping should be executed. A true/false variable is used 1202 // as a flag variable so the swapAt value doesn't have to be recalculated 1203 // in each loop. 1204 1205 if (el.data("getNextElementWidth")) { 1206 if ((o.startAtElementId.length > 0) && (el.data("startAtElementHasNotPassed"))) { 1207 el.data("swapAt", $("#" + o.startAtElementId).outerWidth(true)); 1208 el.data("startAtElementHasNotPassed", false); 1209 } 1210 else { 1211 el.data("swapAt", el.data("scrollableArea").children(":first").outerWidth(true)); 1212 } 1213 1214 el.data("getNextElementWidth", false); 1215 } 1216 1217 // Check to see if the swap should be done 1218 if (el.data("scrollWrapper").scrollLeft() === 0) { 1219 el.data("swappedElement", el.data("scrollableArea").children(":last").detach()); 1220 el.data("scrollableArea").prepend(el.data("swappedElement")); 1221 el.data("scrollWrapper").scrollLeft(el.data("scrollWrapper").scrollLeft() + el.data("swappedElement").outerWidth(true)); 1222 el.data("getNextElementWidth", true); 1223 } 1224 1225 }, 1226 restoreOriginalElements: function () { 1227 var self = this, el = this.element; 1228 1229 // Restore the original content of the scrollable area 1230 el.data("scrollableArea").html(el.data("originalElements")); 1231 self.recalculateScrollableArea(); 1232 self.jumpToElement("first"); 1233 }, 1234 show: function () { 1235 var el = this.element; 1236 el.data("visible", true); 1237 el.show(); 1238 }, 1239 hide: function () { 1240 var el = this.element; 1241 el.data("visible", false); 1242 el.hide(); 1243 }, 1244 enable: function () { 1245 var el = this.element; 1246 1247 // Set enabled to true 1248 el.data("enabled", true); 1249 }, 1250 disable: function () { 1251 var self = this, el = this.element; 1252 1253 // Clear all running intervals 1254 self.stopAutoScrolling(); 1255 clearInterval(el.data("rightScrollingInterval")); 1256 clearInterval(el.data("leftScrollingInterval"));
1257 clearInterval(el.data("hideHotSpotBackgroundsInterval")); 1258 1259 // Set enabled to false 1260 el.data("enabled", false); 1261 }, 1262 destroy: function () { 1263 var self = this, el = this.element; 1264 1265 // Clear all running intervals 1266 self.stopAutoScrolling(); 1267 clearInterval(el.data("rightScrollingInterval")); 1268 clearInterval(el.data("leftScrollingInterval")); 1269 clearInterval(el.data("hideHotSpotBackgroundsInterval")); 1270 1271 // Remove all element specific events 1272 el.data("scrollingHotSpotRight").unbind("mouseover"); 1273 el.data("scrollingHotSpotRight").unbind("mouseout"); 1274 el.data("scrollingHotSpotRight").unbind("mousedown"); 1275 1276 el.data("scrollingHotSpotLeft").unbind("mouseover"); 1277 el.data("scrollingHotSpotLeft").unbind("mouseout"); 1278 el.data("scrollingHotSpotLeft").unbind("mousedown"); 1279 1280 el.unbind("mousenter"); 1281 el.unbind("mouseleave"); 1282 1283 // Remove all elements created by the plugin 1284 el.data("scrollingHotSpotRight").remove(); 1285 el.data("scrollingHotSpotLeft").remove(); 1286 el.data("scrollableArea").remove(); 1287 el.data("scrollWrapper").remove(); 1288 1289 // Restore the original content of the scrollable area 1290 el.html(el.data("originalElements")); 1291 1292 // Call the base destroy function 1293 $.Widget.prototype.destroy.apply(this, arguments); 1294 1295 } 1296 1297 1298 }); 1299})(jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.