1/*! 2 * ScrollMagic v2.0.3 (2015-04-07) 3 * The javascript library for magical scroll interactions. 4 * (c) 2015 Jan Paepke (@janpaepke) 5 * Project Website: http://janpaepke.github.io/ScrollMagic 6 * 7 * @version 2.0.3 8 * @license Dual licensed under MIT license and GPL. 9 * @author Jan Paepke - [email protected] 10 * 11 * @file Debug Extension for ScrollMagic. 12 */ 13/** 14 * This plugin was formerly known as the ScrollMagic debug extension. 15 * 16 * It enables you to add visual indicators to your page, to be able to see exactly when a scene is triggered. 17 * 18 * To have access to this extension, please include `plugins/debug.addIndicators.js`. 19 * @mixin debug.addIndicators 20 */ 21(function (root, factory) { 22 if (typeof define === 'function' && define.amd) { 23 // AMD. Register as an anonymous module. 24 define(['ScrollMagic'], factory); 25 } else if (typeof exports === 'object') { 26 // CommonJS 27 factory(require('scrollmagic')); 28 } else { 29 // no browser global export needed, just execute 30 factory(root.ScrollMagic || (root.jQuery && root.jQuery.ScrollMagic)); 31 } 32}(this, function (ScrollMagic) { 33 "use strict"; 34 var NAMESPACE = "debug.addIndicators"; 35 36 var err = Function.prototype.bind.call((console && (console.error || console.log)) || 37 function () {}, console); 38 if (!ScrollMagic) { 39 err("(" + NAMESPACE + ") -> ERROR: The ScrollMagic main module could not be found. Please make sure it's loaded before this plugin or use an asynchronous loader like requirejs."); 40 } 41 42 // plugin settings 43 var 44 FONT_SIZE = "0.85em", 45 ZINDEX = "9999", 46 EDGE_OFFSET = 15; // minimum edge distance, added to indentation 47 48 // overall vars 49 var 50 _util = ScrollMagic._util, 51 _autoindex = 0; 52 53 54 55 ScrollMagic.Scene.extend(function () { 56 var 57 Scene = this, 58 _indicator; 59 60 var log = function () { 61 if (Scene._log) { // not available, when main source minified 62 Array.prototype.splice.call(arguments, 1, 0, "(" + NAMESPACE + ")", "->"); 63 Scene._log.apply(this, arguments); 64 } 65 }; 66 67 /** 68 * Add visual indicators for a ScrollMagic.Scene. 69 * @memberof! debug.addIndicators# 70 * 71 * @example 72 * // add basic indicators 73 * scene.addIndicators() 74 * 75 * // passing options 76 * scene.addIndicators({name: "pin scene", colorEnd: "#FFFFFF"}); 77 * 78 * @param {object} [options] - An object containing one or more options for the indicators. 79 * @param {(string|object)} [options.parent=undefined] - A selector, DOM Object or a jQuery object that the indicators should be added to. 80 If undefined, the controller's container will be used. 81 * @param {number} [options.name=""] - This string will be displayed at the start and end indicators of the scene for identification purposes. If no name is supplied an automatic index will be used. 82 * @param {number} [options.indent=0] - Additional position offset for the indicators (useful, when having multiple scenes starting at the same position). 83 * @param {string} [options.colorStart=green] - CSS color definition for the start indicator. 84 * @param {string} [options.colorEnd=red] - CSS color definition for the end indicator. 85 * @param {string} [options.colorTrigger=blue] - CSS color definition for the trigger indicator. 86 */ 87 Scene.addIndicators = function (options) { 88 if (!_indicator) { 89 var 90 DEFAULT_OPTIONS = { 91 name: "", 92 indent: 0, 93 parent: undefined, 94 colorStart: "green", 95 colorEnd: "red", 96 colorTrigger: "blue", 97 }; 98 99 options = _util.extend({}, DEFAULT_OPTIONS, options); 100 101 _autoindex++; 102 _indicator = new Indicator(Scene, options); 103 104 Scene.on("add.plugin_addIndicators", _indicator.add); 105 Scene.on("remove.plugin_addIndicators", _indicator.remove); 106 Scene.on("destroy.plugin_addIndicators", Scene.removeIndicators); 107 108 // it the scene already has a controller we can start right away. 109 if (Scene.controller()) { 110 _indicator.add(); 111 } 112 } 113 return Scene; 114 }; 115 116 /** 117 * Removes visual indicators from a ScrollMagic.Scene. 118 * @memberof! debug.addIndicators# 119 * 120 * @example 121 * // remove previously added indicators 122 * scene.removeIndicators() 123 * 124 */ 125 Scene.removeIndicators = function () { 126 if (_indicator) { 127 _indicator.remove(); 128 this.off("*.plugin_addIndicators"); 129 _indicator = undefined; 130 } 131 return Scene; 132 }; 133 134 }); 135 136 137/* 138 * ---------------------------------------------------------------- 139 * Extension for controller to store and update related indicators 140 * ---------------------------------------------------------------- 141 */ 142 // add option to globally auto-add indicators to scenes 143 /** 144 * Every ScrollMagic.Controller instance now accepts an additional option. 145 * See {@link ScrollMagic.Controller} for a complete list of the standard options. 146 * @memberof! debug.addIndicators# 147 * @method new ScrollMagic.Controller(options) 148 * @example 149 * // make a controller and add indicators to all scenes attached 150 * var controller = new ScrollMagic.Controller({addIndicators: true}); 151 * // this scene will automatically have indicators added to it 152 * new ScrollMagic.Scene() 153 * .addTo(controller); 154 * 155 * @param {object} [options] - Options for the Controller. 156 * @param {boolean} [options.addIndicators=false] - If set to `true` every scene that is added to the controller will automatically get indicators added to it. 157 */ 158 ScrollMagic.Controller.addOption("addIndicators", false); 159 // extend Controller 160 ScrollMagic.Controller.extend(function () { 161 var 162 Controller = this, 163 _info = Controller.info(), 164 _container = _info.container, 165 _isDocument = _info.isDocument, 166 _vertical = _info.vertical, 167 _indicators = { // container for all indicators and methods 168 groups: [] 169 }; 170 171 var log = function () { 172 if (Controller._log) { // not available, when main source minified 173 Array.prototype.splice.call(arguments, 1, 0, "(" + NAMESPACE + ")", "->"); 174 Controller._log.apply(this, arguments); 175 } 176 }; 177 if (Controller._indicators) {
178 log(2, "WARNING: Scene already has a property '_indicators', which will be overwritten by plugin."); 179 } 180 181 // add indicators container 182 this._indicators = _indicators; 183/* 184 needed updates: 185 +++++++++++++++ 186 start/end position on scene shift (handled in Indicator class) 187 trigger parameters on triggerHook value change (handled in Indicator class) 188 bounds position on container scroll or resize (to keep alignment to bottom/right) 189 trigger position on container resize, window resize (if container isn't document) and window scroll (if container isn't document) 190 */ 191 192 // event handler for when associated bounds markers need to be repositioned 193 var handleBoundsPositionChange = function () { 194 _indicators.updateBoundsPositions(); 195 }; 196 197 // event handler for when associated trigger groups need to be repositioned 198 var handleTriggerPositionChange = function () { 199 _indicators.updateTriggerGroupPositions(); 200 }; 201 202 _container.addEventListener("resize", handleTriggerPositionChange); 203 if (!_isDocument) { 204 window.addEventListener("resize", handleTriggerPositionChange); 205 window.addEventListener("scroll", handleTriggerPositionChange); 206 } 207 // update all related bounds containers 208 _container.addEventListener("resize", handleBoundsPositionChange); 209 _container.addEventListener("scroll", handleBoundsPositionChange); 210 211 212 // updates the position of the bounds container to aligned to the right for vertical containers and to the bottom for horizontal 213 this._indicators.updateBoundsPositions = function (specificIndicator) { 214 var // constant for all bounds 215 groups = specificIndicator ? [_util.extend({}, specificIndicator.triggerGroup, { 216 members: [specificIndicator] 217 })] : // create a group with only one element 218 _indicators.groups, 219 // use all 220 g = groups.length, 221 css = {}, 222 paramPos = _vertical ? "left" : "top", 223 paramDimension = _vertical ? "width" : "height", 224 edge = _vertical ? _util.get.scrollLeft(_container) + _util.get.width(_container) - EDGE_OFFSET : _util.get.scrollTop(_container) + _util.get.height(_container) - EDGE_OFFSET, 225 b, triggerSize, group; 226 while (g--) { // group loop 227 group = groups[g]; 228 b = group.members.length; 229 triggerSize = _util.get[paramDimension](group.element.firstChild); 230 while (b--) { // indicators loop 231 css[paramPos] = edge - triggerSize; 232 _util.css(group.members[b].bounds, css); 233 } 234 } 235 }; 236 237 // updates the positions of all trigger groups attached to a controller or a specific one, if provided 238 this._indicators.updateTriggerGroupPositions = function (specificGroup) { 239 var // constant vars 240 groups = specificGroup ? [specificGroup] : _indicators.groups, 241 i = groups.length, 242 container = _isDocument ? document.body : _container, 243 containerOffset = _isDocument ? { 244 top: 0, 245 left: 0 246 } : _util.get.offset(container, true), 247 edge = _vertical ? _util.get.width(_container) - EDGE_OFFSET : _util.get.height(_container) - EDGE_OFFSET, 248 paramDimension = _vertical ? "width" : "height", 249 paramTransform = _vertical ? "Y" : "X"; 250 var // changing vars 251 group, elem, pos, elemSize, transform; 252 while (i--) { 253 group = groups[i]; 254 elem = group.element; 255 pos = group.triggerHook * Controller.info("size"); 256 elemSize = _util.get[paramDimension](elem.firstChild.firstChild); 257 transform = pos > elemSize ? "translate" + paramTransform + "(-100%)" : ""; 258 259 _util.css(elem, { 260 top: containerOffset.top + (_vertical ? pos : edge - group.members[0].options.indent), 261 left: containerOffset.left + (_vertical ? edge - group.members[0].options.indent : pos) 262 }); 263 _util.css(elem.firstChild.firstChild, { 264 "-ms-transform": transform, 265 "-webkit-transform": transform, 266 "transform": transform 267 }); 268 } 269 }; 270 271 // updates the label for the group to contain the name, if it only has one member 272 this._indicators.updateTriggerGroupLabel = function (group) { 273 var 274 text = "trigger" + (group.members.length > 1 ? "" : " " + group.members[0].options.name), 275 elem = group.element.firstChild.firstChild, 276 doUpdate = elem.textContent !== text; 277 if (doUpdate) { 278 elem.textContent = text; 279 if (_vertical) { // bounds position is dependent on text length, so update 280 _indicators.updateBoundsPositions(); 281 } 282 } 283 }; 284 285 // add indicators if global option is set 286 this.addScene = function (newScene) { 287 288 if (this._options.addIndicators && newScene instanceof ScrollMagic.Scene && newScene.controller() === Controller) { 289 newScene.addIndicators(); 290 } 291 // call original destroy method 292 this.$super.addScene.apply(this, arguments); 293 }; 294 295 // remove all previously set listeners on destroy 296 this.destroy = function () { 297 _container.removeEventListener("resize", handleTriggerPositionChange); 298 if (!_isDocument) { 299 window.removeEventListener("resize", handleTriggerPositionChange); 300 window.removeEventListener("scroll", handleTriggerPositionChange); 301 } 302 _container.removeEventListener("resize", handleBoundsPositionChange); 303 _container.removeEventListener("scroll", handleBoundsPositionChange); 304 // call original destroy method 305 this.$super.destroy.apply(this, arguments); 306 }; 307 return Controller; 308 309 }); 310 311/* 312 * ----------------------------------------------------------------
313 * Internal class for the construction of Indicators 314 * ---------------------------------------------------------------- 315 */ 316 var Indicator = function (Scene, options) { 317 var 318 Indicator = this, 319 _elemBounds = TPL.bounds(), 320 _elemStart = TPL.start(options.colorStart), 321 _elemEnd = TPL.end(options.colorEnd), 322 _boundsContainer = options.parent && _util.get.elements(options.parent)[0], 323 _vertical, _ctrl; 324 325 var log = function () { 326 if (Scene._log) { // not available, when main source minified 327 Array.prototype.splice.call(arguments, 1, 0, "(" + NAMESPACE + ")", "->"); 328 Scene._log.apply(this, arguments); 329 } 330 }; 331 332 options.name = options.name || _autoindex; 333 334 // prepare bounds elements 335 _elemStart.firstChild.textContent += " " + options.name; 336 _elemEnd.textContent += " " + options.name; 337 _elemBounds.appendChild(_elemStart); 338 _elemBounds.appendChild(_elemEnd); 339 340 // set public variables 341 Indicator.options = options; 342 Indicator.bounds = _elemBounds; 343 // will be set later 344 Indicator.triggerGroup = undefined; 345 346 // add indicators to DOM 347 this.add = function () { 348 _ctrl = Scene.controller(); 349 _vertical = _ctrl.info("vertical"); 350 351 var isDocument = _ctrl.info("isDocument"); 352 353 if (!_boundsContainer) { 354 // no parent supplied or doesnt exist 355 _boundsContainer = isDocument ? document.body : _ctrl.info("container"); // check if window/document (then use body) 356 } 357 if (!isDocument && _util.css(_boundsContainer, "position") === 'static') {
358 // position mode needed for correct positioning of indicators 359 _util.css(_boundsContainer, { 360 position: "relative" 361 }); 362 } 363 364 // add listeners for updates 365 Scene.on("change.plugin_addIndicators", handleTriggerParamsChange); 366 Scene.on("shift.plugin_addIndicators", handleBoundsParamsChange); 367 368 // updates trigger & bounds (will add elements if needed) 369 updateTriggerGroup(); 370 updateBounds(); 371 372 setTimeout(function () { // do after all execution is finished otherwise sometimes size calculations are off 373 _ctrl._indicators.updateBoundsPositions(Indicator); 374 }, 0); 375 376 log(3, "added indicators"); 377 }; 378 379 // remove indicators from DOM 380 this.remove = function () { 381 if (Indicator.triggerGroup) { // if not set there's nothing to remove 382 Scene.off("change.plugin_addIndicators", handleTriggerParamsChange); 383 Scene.off("shift.plugin_addIndicators", handleBoundsParamsChange); 384 385 if (Indicator.triggerGroup.members.length > 1) { 386 // just remove from memberlist of old group 387 var group = Indicator.triggerGroup; 388 group.members.splice(group.members.indexOf(Indicator), 1); 389 _ctrl._indicators.updateTriggerGroupLabel(group); 390 _ctrl._indicators.updateTriggerGroupPositions(group); 391 Indicator.triggerGroup = undefined; 392 } else { 393 // remove complete group 394 removeTriggerGroup(); 395 } 396 removeBounds(); 397 398 log(3, "removed indicators"); 399 } 400 }; 401 402/* 403 * ---------------------------------------------------------------- 404 * internal Event Handlers 405 * ---------------------------------------------------------------- 406 */ 407 408 // event handler for when bounds params change 409 var handleBoundsParamsChange = function () { 410 updateBounds(); 411 }; 412 413 // event handler for when trigger params change 414 var handleTriggerParamsChange = function (e) { 415 if (e.what === "triggerHook") { 416 updateTriggerGroup(); 417 } 418 }; 419 420/* 421 * ---------------------------------------------------------------- 422 * Bounds (start / stop) management 423 * ---------------------------------------------------------------- 424 */ 425 426 // adds an new bounds elements to the array and to the DOM 427 var addBounds = function () { 428 var v = _ctrl.info("vertical"); 429 // apply stuff we didn't know before... 430 _util.css(_elemStart.firstChild, { 431 "border-bottom-width": v ? 1 : 0, 432 "border-right-width": v ? 0 : 1, 433 "bottom": v ? -1 : options.indent, 434 "right": v ? options.indent : -1, 435 "padding": v ? "0 8px" : "2px 4px", 436 }); 437 _util.css(_elemEnd, { 438 "border-top-width": v ? 1 : 0, 439 "border-left-width": v ? 0 : 1, 440 "top": v ? "100%" : "", 441 "right": v ? options.indent : "", 442 "bottom": v ? "" : options.indent, 443 "left": v ? "" : "100%", 444 "padding": v ? "0 8px" : "2px 4px" 445 }); 446 // append 447 _boundsContainer.appendChild(_elemBounds); 448 }; 449 450 // remove bounds from list and DOM 451 var removeBounds = function () { 452 _elemBounds.parentNode.removeChild(_elemBounds); 453 }; 454 455 // update the start and end positions of the scene 456 var updateBounds = function () { 457 if (_elemBounds.parentNode !== _boundsContainer) { 458 addBounds(); // Add Bounds elements (start/end) 459 } 460 var css = {}; 461 css[_vertical ? "top" : "left"] = Scene.triggerPosition(); 462 css[_vertical ? "height" : "width"] = Scene.duration(); 463 _util.css(_elemBounds, css); 464 _util.css(_elemEnd, { 465 display: Scene.duration() > 0 ? "" : "none" 466 }); 467 }; 468 469/* 470 * ---------------------------------------------------------------- 471 * trigger and trigger group management 472 * ---------------------------------------------------------------- 473 */ 474 475 // adds an new trigger group to the array and to the DOM 476 var addTriggerGroup = function () { 477 var triggerElem = TPL.trigger(options.colorTrigger); // new trigger element 478 var css = {}; 479 css[_vertical ? "right" : "bottom"] = 0; 480 css[_vertical ? "border-top-width" : "border-left-width"] = 1; 481 _util.css(triggerElem.firstChild, css); 482 _util.css(triggerElem.firstChild.firstChild, { 483 padding: _vertical ? "0 8px 3px 8px" : "3px 4px" 484 }); 485 document.body.appendChild(triggerElem); // directly add to body 486 var newGroup = { 487 triggerHook: Scene.triggerHook(), 488 element: triggerElem, 489 members: [Indicator] 490 }; 491 _ctrl._indicators.groups.push(newGroup); 492 Indicator.triggerGroup = newGroup; 493 // update right away 494 _ctrl._indicators.updateTriggerGroupLabel(newGroup); 495 _ctrl._indicators.updateTriggerGroupPositions(newGroup); 496 }; 497 498 var removeTriggerGroup = function () { 499 _ctrl._indicators.groups.splice(_ctrl._indicators.groups.indexOf(Indicator.triggerGroup), 1); 500 Indicator.triggerGroup.element.parentNode.removeChild(Indicator.triggerGroup.element); 501 Indicator.triggerGroup = undefined; 502 }; 503 504 // updates the trigger group -> either join existing or add new one 505/* 506 * Logic: 507 * 1 if a trigger group exist, check if it's in sync with Scene settings â if so, nothing else needs to happen 508 * 2 try to find an existing one that matches Scene parameters 509 * 2.1 If a match is found check if already assigned to an existing group 510 * If so: 511 * A: it was the last member of existing group -> kill whole group 512 * B: the existing group has other members -> just remove from member list 513 * 2.2 Assign to matching group 514 * 3 if no new match could be found, check if assigned to existing group 515 * A: yes, and it's the only member -> just update parameters and positions and keep using this group 516 * B: yes but there are other members -> remove from member list and create a new one 517 * C: no, so create a new one 518 */ 519 var updateTriggerGroup = function () { 520 var 521 triggerHook = Scene.triggerHook(), 522 closeEnough = 0.0001; 523 524 // Have a group, check if it still matches 525 if (Indicator.triggerGroup) { 526 if (Math.abs(Indicator.triggerGroup.triggerHook - triggerHook) < closeEnough) { 527 // _util.log(0, "trigger", options.name, "->", "no need to change, still in sync"); 528 return; // all good 529 } 530 } 531 // Don't have a group, check if a matching one exists 532 // _util.log(0, "trigger", options.name, "->", "out of sync!"); 533 var 534 groups = _ctrl._indicators.groups, 535 group, i = groups.length; 536 while (i--) { 537 group = groups[i]; 538 if (Math.abs(group.triggerHook - triggerHook) < closeEnough) { 539 // found a match! 540 // _util.log(0, "trigger", options.name, "->", "found match"); 541 if (Indicator.triggerGroup) { // do I have an old group that is out of sync? 542 if (Indicator.triggerGroup.members.length === 1) { // is it the only remaining group? 543 // _util.log(0, "trigger", options.name, "->", "kill"); 544 // was the last member, remove the whole group 545 removeTriggerGroup(); 546 } else { 547 Indicator.triggerGroup.members.splice(Indicator.triggerGroup.members.indexOf(Indicator), 1); // just remove from memberlist of old group 548 _ctrl._indicators.updateTriggerGroupLabel(Indicator.triggerGroup); 549 _ctrl._indicators.updateTriggerGroupPositions(Indicator.triggerGroup); 550 // _util.log(0, "trigger", options.name, "->", "removing from previous member list"); 551 } 552 } 553 // join new group 554 group.members.push(Indicator); 555 Indicator.triggerGroup = group; 556 _ctrl._indicators.updateTriggerGroupLabel(group); 557 return; 558 } 559 } 560 561 // at this point I am obviously out of sync and don't match any other group 562 if (Indicator.triggerGroup) { 563 if (Indicator.triggerGroup.members.length === 1) { 564 // _util.log(0, "trigger", options.name, "->", "updating existing"); 565 // out of sync but i'm the only member => just change and update 566 Indicator.triggerGroup.triggerHook = triggerHook; 567 _ctrl._indicators.updateTriggerGroupPositions(Indicator.triggerGroup); 568 return; 569 } else { 570 // _util.log(0, "trigger", options.name, "->", "removing from previous member list"); 571 Indicator.triggerGroup.members.splice(Indicator.triggerGroup.members.indexOf(Indicator), 1); // just remove from memberlist of old group 572 _ctrl._indicators.updateTriggerGroupLabel(Indicator.triggerGroup); 573 _ctrl._indicators.updateTriggerGroupPositions(Indicator.triggerGroup); 574 Indicator.triggerGroup = undefined; // need a brand new group... 575 } 576 } 577 // _util.log(0, "trigger", options.name, "->", "add a new one"); 578 // did not find any match, make new trigger group 579 addTriggerGroup(); 580 }; 581 }; 582 583/* 584 * ---------------------------------------------------------------- 585 * Templates for the indicators 586 * ---------------------------------------------------------------- 587 */ 588 var TPL = { 589 start: function (color) { 590 // inner element (for bottom offset -1, while keeping top position 0) 591 var inner = document.createElement("div"); 592 inner.textContent = "start"; 593 _util.css(inner, { 594 position: "absolute", 595 overflow: "visible", 596 "border-width": 0, 597 "border-style": "solid", 598 color: color, 599 "border-color": color 600 }); 601 var e = document.createElement('div'); 602 // wrapper 603 _util.css(e, { 604 position: "absolute", 605 overflow: "visible", 606 width: 0, 607 height: 0 608 }); 609 e.appendChild(inner); 610 return e; 611 }, 612 end: function (color) { 613 var e = document.createElement('div'); 614 e.textContent = "end"; 615 _util.css(e, { 616 position: "absolute", 617 overflow: "visible", 618 "border-width": 0, 619 "border-style": "solid", 620 color: color, 621 "border-color": color 622 }); 623 return e; 624 }, 625 bounds: function () { 626 var e = document.createElement('div'); 627 _util.css(e, { 628 position: "absolute", 629 overflow: "visible", 630 "white-space": "nowrap", 631 "pointer-events": "none", 632 "font-size": FONT_SIZE 633 }); 634 e.style.zIndex = ZINDEX; 635 return e; 636 }, 637 trigger: function (color) { 638 // inner to be above or below line but keep position 639 var inner = document.createElement('div'); 640 inner.textContent = "trigger"; 641 _util.css(inner, { 642 position: "relative", 643 }); 644 // inner wrapper for right: 0 and main element has no size 645 var w = document.createElement('div'); 646 _util.css(w, { 647 position: "absolute", 648 overflow: "visible", 649 "border-width": 0, 650 "border-style": "solid", 651 color: color, 652 "border-color": color 653 }); 654 w.appendChild(inner); 655 // wrapper 656 var e = document.createElement('div'); 657 _util.css(e, { 658 position: "fixed", 659 overflow: "visible", 660 "white-space": "nowrap", 661 "pointer-events": "none", 662 "font-size": FONT_SIZE 663 }); 664 e.style.zIndex = ZINDEX; 665 e.appendChild(w); 666 return e; 667 }, 668 }; 669 670}));
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.