1// Scrollbar Width function 2function getScrollBarWidth() { 3 var inner = document.createElement('p'); 4 inner.style.width = "100%"; 5 inner.style.height = "200px"; 6 7 var outer = document.createElement('div'); 8 outer.style.position = "absolute"; 9 outer.style.top = "0px"; 10 outer.style.left = "0px"; 11 outer.style.visibility = "hidden"; 12 outer.style.width = "200px"; 13 outer.style.height = "150px"; 14 outer.style.overflow = "hidden"; 15 outer.appendChild(inner); 16 17 document.body.appendChild(outer); 18 var w1 = inner.offsetWidth; 19 outer.style.overflow = 'scroll'; 20 var w2 = inner.offsetWidth; 21 if (w1 == w2) w2 = outer.clientWidth; 22 23 document.body.removeChild(outer); 24 25 return (w1 - w2); 26}; 27 28var topics = {}; 29var hOP = topics.hasOwnProperty; 30 31var huePubSub = { 32 subscribe: function(topic, listener, app) { 33 if (!hOP.call(topics, topic)) { 34 topics[topic] = []; 35 } 36 37 var index = 38 topics[topic].push({ 39 listener: listener, 40 app: app, 41 status: 'running' 42 }) - 1; 43 44 return { 45 remove: function() { 46 delete topics[topic][index]; 47 } 48 }; 49 }, 50 removeAll: function(topic) { 51 topics[topic] = []; 52 }, 53 subscribeOnce: function(topic, listener, app) { 54 var ephemeral = this.subscribe( 55 topic, 56 function() { 57 listener.apply(listener, arguments); 58 ephemeral.remove(); 59 }, 60 app 61 ); 62 }, 63 publish: function(topic, info) { 64 if (!hOP.call(topics, topic)) { 65 return; 66 } 67 68 topics[topic].forEach(item => { 69 if (item.status === 'running') { 70 item.listener(info); 71 } 72 }); 73 }, 74 getTopics: function() { 75 return topics; 76 }, 77 pauseAppSubscribers: function(app) { 78 if (app) { 79 Object.keys(topics).forEach(topicName => { 80 topics[topicName].forEach(topic => { 81 if ( 82 typeof topic.app !== 'undefined' && 83 topic.app !== null && 84 (topic.app === app || topic.app.split('-')[0] === app) 85 ) { 86 topic.status = 'paused'; 87 } 88 }); 89 }); 90 } 91 }, 92 resumeAppSubscribers: function(app) { 93 if (app) { 94 Object.keys(topics).forEach(topicName => { 95 topics[topicName].forEach(topic => { 96 if ( 97 typeof topic.app !== 'undefined' && 98 topic.app !== null && 99 (topic.app === app || topic.app.split('-')[0] === app) 100 ) { 101 topic.status = 'running'; 102 } 103 }); 104 }); 105 } 106 }, 107 clearAppSubscribers: function(app) { 108 if (app) { 109 Object.keys(topics).forEach(topicName => { 110 topics[topicName] = topics[topicName].filter(obj => { 111 return obj.app !== app; 112 }); 113 }); 114 } 115 } 116}; 117 118(function ($, window, document, undefined) { 119 120 var pluginName = "jHueScrollUp", 121 defaults = { 122 threshold: 100, // it displays it after 100 px of scroll 123 scrollLeft: false 124 }; 125 126 function Plugin(element, options) { 127 this.element = element; 128 this.options = $.extend({}, defaults, options); 129 this._defaults = defaults; 130 this._name = pluginName; 131 if ($(element).attr('jHueScrollified') !== 'true') { 132 this.setupScrollUp(); 133 } 134 if (this.options.scrollLeft) { 135 $(element).jHueScrollLeft(this.options.threshold); 136 } 137 } 138 139 Plugin.prototype.setOptions = function (options) { 140 this.options = $.extend({}, defaults, options); 141 }; 142 143 Plugin.prototype.setupScrollUp = function () { 144 var _this = this, 145 link = null; 146 147 if ($("#jHueScrollUpAnchor").length > 0) { // just one scroll up per page 148 link = $("#jHueScrollUpAnchor");
149 $(document).off("click", "#jHueScrollUpAnchor"); 150 } else { 151 link = $("<a/>").attr("id", "jHueScrollUpAnchor") 152 .hide() 153 .addClass("hueAnchor hueAnchorScroller") 154 .attr("href", "javascript:void(0)") 155 .html("<i class='fa fa-fw fa-chevron-up'></i>") 156 .appendTo('#body-inner'); 157 } 158 159 if ($(window).scrollTop() > _this.options.threshold) { 160 link.show(); 161 } 162 $(_this.element).attr("jHueScrollified", "true"); 163 164 if ($(_this.element).is("body")) { 165 setScrollBehavior($(window), $("body, html")); 166 } else { 167 setScrollBehavior($(_this.element), $(_this.element)); 168 } 169 170 huePubSub.subscribe('reposition.scroll.anchor.up', function(){ 171 $('#jHueScrollUpAnchor').css('right', '20px'); 172 if (!$(_this.element).is('body') && $(_this.element).is(':visible')) { 173 var adjustRight = $(window).width() - ($(_this.element).width() + $(_this.element).offset().left); 174 if (adjustRight > 0) { 175 $('#jHueScrollUpAnchor').css('right', adjustRight + 'px'); 176 } 177 } 178 }); 179 180 181 function setScrollBehavior(scrolled, scrollable) { 182 scrolled.scroll(function () { 183 if (scrolled.scrollTop() > _this.options.threshold) { 184 if (link.is(":hidden")) { 185 huePubSub.publish('reposition.scroll.anchor.up'); 186 link.fadeIn(200, function(){ 187 huePubSub.publish('reposition.scroll.anchor.up'); 188 }); 189 } 190 if ($(_this.element).data("lastScrollTop") == null || $(_this.element).data("lastScrollTop") < scrolled.scrollTop()) { 191 $("#jHueScrollUpAnchor").data("caller", scrollable); 192 } 193 $(_this.element).data("lastScrollTop", scrolled.scrollTop()); 194 } else { 195 checkForAllScrolls(); 196 } 197 }); 198 window.setTimeout(function() { 199 huePubSub.publish('reposition.scroll.anchor.up'); 200 }, 0); 201 } 202 203 function checkForAllScrolls() { 204 var _allOk = true; 205 $(document).find("[jHueScrollified='true']").each(function (cnt, item) { 206 if ($(item).is("body")) { 207 if ($(window).scrollTop() > _this.options.threshold) { 208 _allOk = false; 209 $("#jHueScrollUpAnchor").data("caller", $("body, html")); 210 } 211 } else if ($(item).scrollTop() > _this.options.threshold) { 212 _allOk = false; 213 $("#jHueScrollUpAnchor").data("caller", $(item)); 214 } 215 }); 216 if (_allOk) { 217 link.fadeOut(200); 218 $("#jHueScrollUpAnchor").data("caller", null); 219 } 220 } 221 222 $(document).on("click", "#jHueScrollUpAnchor", function (event) { 223 if ($("#jHueScrollUpAnchor").data("caller") != null) { 224 $("html, body").animate({ scrollTop: 0 }, 200); 225 if ($(document).find("[jHueScrollified='true']").not($("#jHueScrollUpAnchor").data("caller")).is("body") && $(window).scrollTop() > _this.options.threshold) { 226 $("#jHueScrollUpAnchor").data("caller", $("body, html")); 227 } else { 228 checkForAllScrolls(); 229 } 230 } 231 return false; 232 }); 233 }; 234 235 $.fn[pluginName] = function (options) { 236 return this.each(function () { 237 $.data(this, 'plugin_' + pluginName, new Plugin(this, options)); 238 }); 239 }; 240 241 $[pluginName] = function (options) { 242 new Plugin($("body"), options); 243 }; 244 245})(jQuery, window, document); 246 247$('body').jHueScrollUp(); 248 249function setMenuHeight() { 250 $('#sidebar .highlightable').height($('#sidebar').innerHeight() - $('#header-wrapper').height() - 40); 251 $('#sidebar .highlightable').perfectScrollbar('update'); 252} 253 254function fallbackMessage(action) { 255 var actionMsg = ''; 256 var actionKey = (action === 'cut' ? 'X' : 'C'); 257 258 if (/iPhone|iPad/i.test(navigator.userAgent)) { 259 actionMsg = 'No support :('; 260 } 261 else if (/Mac/i.test(navigator.userAgent)) { 262 actionMsg = 'Press â-' + actionKey + ' to ' + action; 263 } 264 else { 265 actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action; 266 } 267 268 return actionMsg; 269} 270 271// for the window resize 272$(window).resize(function() { 273 setMenuHeight(); 274}); 275 276// debouncing function from John Hann 277// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/ 278(function($, sr) { 279 280 var debounce = function(func, threshold, execAsap) { 281 var timeout; 282 283 return function debounced() { 284 var obj = this, args = arguments; 285 286 function delayed() { 287 if (!execAsap) 288 func.apply(obj, args); 289 timeout = null; 290 }; 291 292 if (timeout) 293 clearTimeout(timeout); 294 else if (execAsap) 295 func.apply(obj, args); 296 297 timeout = setTimeout(delayed, threshold || 100); 298 }; 299 } 300 // smartresize 301 jQuery.fn[sr] = function(fn) { return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); }; 302 303})(jQuery, 'smartresize'); 304 305 306jQuery(document).ready(function() { 307 jQuery('#sidebar .category-icon').on('click', function() { 308 $( this ).toggleClass("fa-angle-down fa-angle-right") ; 309 $( this ).parent().parent().children('ul').toggle() ; 310 return false;
311 }); 312 313 var sidebarStatus = searchStatus = 'open'; 314 $('#sidebar .highlightable').perfectScrollbar(); 315 setMenuHeight(); 316 317 jQuery('#overlay').on('click', function() { 318 jQuery(document.body).toggleClass('sidebar-hidden'); 319 sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open'); 320 321 return false; 322 }); 323 324 jQuery('[data-sidebar-toggle]').on('click', function() { 325 jQuery(document.body).toggleClass('sidebar-hidden'); 326 sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open'); 327 328 return false; 329 }); 330 jQuery('[data-clear-history-toggle]').on('click', function() { 331 sessionStorage.clear(); 332 location.reload(); 333 return false; 334 }); 335 jQuery('[data-search-toggle]').on('click', function() { 336 if (sidebarStatus == 'closed') { 337 jQuery('[data-sidebar-toggle]').trigger('click'); 338 jQuery(document.body).removeClass('searchbox-hidden'); 339 searchStatus = 'open'; 340 341 return false; 342 } 343 344 jQuery(document.body).toggleClass('searchbox-hidden'); 345 searchStatus = (jQuery(document.body).hasClass('searchbox-hidden') ? 'closed' : 'open'); 346 347 return false; 348 }); 349 350 var ajax; 351 jQuery('[data-search-input]').on('input', function() { 352 var input = jQuery(this), 353 value = input.val(), 354 items = jQuery('[data-nav-id]'); 355 items.removeClass('search-match'); 356 if (!value.length) { 357 $('ul.topics').removeClass('searched'); 358 items.css('display', 'block'); 359 sessionStorage.removeItem('search-value'); 360 $(".highlightable").unhighlight({ element: 'mark' }) 361 return; 362 } 363 364 sessionStorage.setItem('search-value', value); 365 $(".highlightable").unhighlight({ element: 'mark' }).highlight(value, { element: 'mark' }); 366 367 if (ajax && ajax.abort) ajax.abort(); 368 369 jQuery('[data-search-clear]').on('click', function() { 370 jQuery('[data-search-input]').val('').trigger('input'); 371 sessionStorage.removeItem('search-input'); 372 $(".highlightable").unhighlight({ element: 'mark' }) 373 }); 374 }); 375 376 $.expr[":"].contains = $.expr.createPseudo(function(arg) { 377 return function( elem ) { 378 return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0; 379 }; 380 }); 381 382 if (sessionStorage.getItem('search-value')) { 383 var searchValue = sessionStorage.getItem('search-value') 384 $(document.body).removeClass('searchbox-hidden'); 385 $('[data-search-input]').val(searchValue); 386 $('[data-search-input]').trigger('input'); 387 var searchedElem = $('#body-inner').find(':contains(' + searchValue + ')').get(0); 388 if (searchedElem) { 389 searchedElem.scrollIntoView(true); 390 var scrolledY = window.scrollY; 391 if(scrolledY){ 392 window.scroll(0, scrolledY - 125); 393 } 394 } 395 } 396 397 // clipboard 398 var clipInit = false; 399 $('code').each(function() { 400 var code = $(this), 401 text = code.text(); 402 403 if (text.length > 5) { 404 if (!clipInit) { 405 var text, clip = new Clipboard('.copy-to-clipboard', { 406 text: function(trigger) { 407 text = $(trigger).prev('code').text(); 408 return text.replace(/^\$\s/gm, ''); 409 } 410 }); 411 412 var inPre; 413 clip.on('success', function(e) { 414 e.clearSelection(); 415 inPre = $(e.trigger).parent().prop('tagName') == 'PRE'; 416 $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's')); 417 }); 418 419 clip.on('error', function(e) { 420 inPre = $(e.trigger).parent().prop('tagName') == 'PRE'; 421 $(e.trigger).attr('aria-label', fallbackMessage(e.action)).addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's')); 422 $(document).one('copy', function(){ 423 $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's')); 424 }); 425 }); 426 427 clipInit = true; 428 } 429
430 code.after('<span class="copy-to-clipboard" title="Copy to clipboard" />'); 431 code.next('.copy-to-clipboard').on('mouseleave', function() { 432 $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w'); 433 }); 434 } 435 }); 436 437 // allow keyboard control for prev/next links 438 jQuery(function() { 439 jQuery('.nav-prev').click(function(){ 440 location.href = jQuery(this).attr('href'); 441 }); 442 jQuery('.nav-next').click(function() { 443 location.href = jQuery(this).attr('href'); 444 }); 445 }); 446 447 jQuery('input, textarea').keydown(function (e) { 448 // left and right arrow keys 449 if (e.which == '37' || e.which == '39') { 450 e.stopPropagation(); 451 } 452 }); 453 454 jQuery(document).keydown(function(e) { 455 // prev links - left arrow key 456 if(e.which == '37') { 457 jQuery('.nav.nav-prev').click(); 458 } 459 460 // next links - right arrow key 461 if(e.which == '39') { 462 jQuery('.nav.nav-next').click(); 463 } 464 }); 465 466 $('#top-bar a:not(:has(img)):not(.btn)').addClass('highlight'); 467 $('#body-inner a:not(:has(img)):not(.btn):not(a[rel="footnote"])').addClass('highlight'); 468 469 var touchsupport = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0) 470 if (!touchsupport){ // browser doesn't support touch 471 $('#toc-menu').hover(function() { 472 $('.progress').stop(true, false, true).fadeToggle(100); 473 }); 474 475 $('.progress').hover(function() { 476 $('.progress').stop(true, false, true).fadeToggle(100); 477 }); 478 } 479 if (touchsupport){ // browser does support touch 480 $('#toc-menu').click(function() { 481 $('.progress').stop(true, false, true).fadeToggle(100); 482 }); 483 $('.progress').click(function() { 484 $('.progress').stop(true, false, true).fadeToggle(100); 485 }); 486 } 487 488 /** 489 * Fix anchor scrolling that hides behind top nav bar 490 * Courtesy of https://stackoverflow.com/a/13067009/28106 491 * 492 * We could use pure css for this if only heading anchors were 493 * involved, but this works for any anchor, including footnotes 494 **/ 495 (function (document, history, location) { 496 var HISTORY_SUPPORT = !!(history && history.pushState); 497 498 var anchorScrolls = { 499 ANCHOR_REGEX: /^#[^ ]+$/, 500 OFFSET_HEIGHT_PX: 50, 501 502 /** 503 * Establish events, and fix initial scroll position if a hash is provided. 504 */ 505 init: function () { 506 this.scrollToCurrent(); 507 $(window).on('hashchange', $.proxy(this, 'scrollToCurrent')); 508 $('body').on('click', 'a', $.proxy(this, 'delegateAnchors')); 509 }, 510 511 /** 512 * Return the offset amount to deduct from the normal scroll position. 513 * Modify as appropriate to allow for dynamic calculations 514 */ 515 getFixedOffset: function () { 516 return this.OFFSET_HEIGHT_PX; 517 }, 518 519 /** 520 * If the provided href is an anchor which resolves to an element on the 521 * page, scroll to it. 522 * @param {String} href 523 * @return {Boolean} - Was the href an anchor. 524 */ 525 scrollIfAnchor: function (href, pushToHistory) { 526 var match, anchorOffset; 527 528 if (!this.ANCHOR_REGEX.test(href)) { 529 return false; 530 } 531 532 match = document.getElementById(href.slice(1)); 533 534 if (match) { 535 anchorOffset = $(match).offset().top - this.getFixedOffset(); 536 $('html, body').animate({ scrollTop: anchorOffset }); 537 538 // Add the state to history as-per normal anchor links 539 if (HISTORY_SUPPORT && pushToHistory) { 540 history.pushState({}, document.title, location.pathname + href); 541 } 542 } 543 544 return !!match; 545 }, 546 547 /** 548 * Attempt to scroll to the current location's hash. 549 */ 550 scrollToCurrent: function (e) { 551 if (this.scrollIfAnchor(window.location.hash) && e) { 552 e.preventDefault(); 553 } 554 }, 555 556 /** 557 * If the click event's target was an anchor, fix the scroll position. 558 */ 559 delegateAnchors: function (e) { 560 var elem = e.target; 561 562 if (this.scrollIfAnchor(elem.getAttribute('href'), true)) { 563 e.preventDefault(); 564 } 565 } 566 }; 567 568 $(document).ready($.proxy(anchorScrolls, 'init')); 569 })(window.document, window.history, window.location); 570 571}); 572 573jQuery(window).on('load', function() { 574 575 function adjustForScrollbar() {
576 if ((parseInt(jQuery('#body-inner').height()) + 83) >= jQuery('#body').height()) { 577 jQuery('.nav.nav-next').css({ 'margin-right': getScrollBarWidth() }); 578 } else { 579 jQuery('.nav.nav-next').css({ 'margin-right': 0 }); 580 } 581 } 582 583 // adjust sidebar for scrollbar 584 adjustForScrollbar(); 585 586 jQuery(window).smartresize(function() { 587 adjustForScrollbar(); 588 }); 589 590 // store this page in session 591 sessionStorage.setItem(jQuery('body').data('url'), 1); 592 593 // loop through the sessionStorage and see if something should be marked as visited 594 for (var url in sessionStorage) { 595 if (sessionStorage.getItem(url) == 1) jQuery('[data-nav-id="' + url + '"]').addClass('visited'); 596 } 597 598 599 $(".highlightable").highlight(sessionStorage.getItem('search-value'), { element: 'mark' }); 600}); 601 602$(function() { 603 $('a[rel="lightbox"]').featherlight({ 604 root: 'section#body' 605 }); 606}); 607 608jQuery.extend({ 609 highlight: function(node, re, nodeName, className) { 610 if (node.nodeType === 3) { 611 var match = node.data.match(re); 612 if (match) { 613 var highlight = document.createElement(nodeName || 'span'); 614 highlight.className = className || 'highlight'; 615 var wordNode = node.splitText(match.index); 616 wordNode.splitText(match[0].length); 617 var wordClone = wordNode.cloneNode(true); 618 highlight.appendChild(wordClone); 619 wordNode.parentNode.replaceChild(highlight, wordNode); 620 return 1; //skip added node in parent 621 } 622 } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children 623 !/(script|style)/i.test(node.tagName) && // ignore script and style nodes 624 !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted 625 for (var i = 0; i < node.childNodes.length; i++) { 626 i += jQuery.highlight(node.childNodes[i], re, nodeName, className); 627 } 628 } 629 return 0; 630 } 631}); 632 633jQuery.fn.unhighlight = function(options) { 634 var settings = { 635 className: 'highlight', 636 element: 'span' 637 }; 638 jQuery.extend(settings, options); 639 640 return this.find(settings.element + "." + settings.className).each(function() { 641 var parent = this.parentNode; 642 parent.replaceChild(this.firstChild, this); 643 parent.normalize(); 644 }).end(); 645}; 646 647jQuery.fn.highlight = function(words, options) { 648 var settings = { 649 className: 'highlight', 650 element: 'span', 651 caseSensitive: false, 652 wordsOnly: false 653 }; 654 jQuery.extend(settings, options); 655 656 if (!words) { return; } 657 658 if (words.constructor === String) { 659 words = [words]; 660 } 661 words = jQuery.grep(words, function(word, i) { 662 return word != ''; 663 }); 664 words = jQuery.map(words, function(word, i) { 665 return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&"); 666 }); 667 if (words.length == 0) { return this; } 668 ; 669 670 var flag = settings.caseSensitive ? "" : "i"; 671 var pattern = "(" + words.join("|") + ")"; 672 if (settings.wordsOnly) { 673 pattern = "\\b" + pattern + "\\b"; 674 } 675 var re = new RegExp(pattern, flag); 676 677 return this.each(function() { 678 jQuery.highlight(this, re, settings.element, settings.className); 679 }); 680}; 681 682$(window).on('DOMContentLoaded load resize scroll', function () { 683 function isElementInViewport (el) { 684 685 var rect = el.getBoundingClientRect(), 686 vWidth = window.innerWidth || doc.documentElement.clientWidth, 687 vHeight = window.innerHeight || doc.documentElement.clientHeight, 688 efp = function (x, y) { return document.elementFromPoint(x, y) }; 689 690 // Return false if it's not in the viewport 691 if (rect.right < 0 || rect.bottom < 0 692 || rect.left > vWidth || rect.top > vHeight) 693 return false; 694
695 // Return true if any of its four corners are visible 696 return ( 697 el.contains(efp(rect.left, rect.top)) 698 || el.contains(efp(rect.right, rect.top)) 699 || el.contains(efp(rect.right, rect.bottom)) 700 || el.contains(efp(rect.left, rect.bottom)) 701 ); 702 } 703 var visible = 0; 704 $('#body-inner h1, #body-inner h2, #body-inner h3, #body-inner h4, #body-inner h5, #body-inner h6').each(function (i,e) { 705 if(isElementInViewport(e)) { 706 visible = $(e).attr('id'); 707 if (visible) { 708 return false; 709 } 710 } 711 }); 712 713 if(visible){ 714 $('.toc ul li a').removeClass('active'); 715 $('.toc ul li a[href="#'+visible+'"]').addClass('active'); 716 } 717});
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.