github.com/mweagle/Sparta@v1.15.0/docs_source/themes/hugo-theme-learn/static/js/learn.js (about)

     1  // Scrollbar Width function
     2  function 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  
    28  function setMenuHeight() {
    29      $('#sidebar .highlightable').height($('#sidebar').innerHeight() - $('#header-wrapper').height() - 40);
    30      $('#sidebar .highlightable').perfectScrollbar('update');
    31  }
    32  
    33  function fallbackMessage(action) {
    34      var actionMsg = '';
    35      var actionKey = (action === 'cut' ? 'X' : 'C');
    36  
    37      if (/iPhone|iPad/i.test(navigator.userAgent)) {
    38          actionMsg = 'No support :(';
    39      }
    40      else if (/Mac/i.test(navigator.userAgent)) {
    41          actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;
    42      }
    43      else {
    44          actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;
    45      }
    46  
    47      return actionMsg;
    48  }
    49  
    50  // for the window resize
    51  $(window).resize(function() {
    52      setMenuHeight();
    53  });
    54  
    55  // debouncing function from John Hann
    56  // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
    57  (function($, sr) {
    58  
    59      var debounce = function(func, threshold, execAsap) {
    60          var timeout;
    61  
    62          return function debounced() {
    63              var obj = this, args = arguments;
    64  
    65              function delayed() {
    66                  if (!execAsap)
    67                      func.apply(obj, args);
    68                  timeout = null;
    69              };
    70  
    71              if (timeout)
    72                  clearTimeout(timeout);
    73              else if (execAsap)
    74                  func.apply(obj, args);
    75  
    76              timeout = setTimeout(delayed, threshold || 100);
    77          };
    78      }
    79      // smartresize
    80      jQuery.fn[sr] = function(fn) { return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
    81  
    82  })(jQuery, 'smartresize');
    83  
    84  
    85  jQuery(document).ready(function() {
    86      jQuery('#sidebar .category-icon').on('click', function() {
    87          $( this ).toggleClass("fa-angle-down fa-angle-right") ;
    88          $( this ).parent().parent().children('ul').toggle() ;
    89          return false;
    90      });
    91  
    92      var sidebarStatus = searchStatus = 'open';
    93      $('#sidebar .highlightable').perfectScrollbar();
    94      setMenuHeight();
    95  
    96      jQuery('#overlay').on('click', function() {
    97          jQuery(document.body).toggleClass('sidebar-hidden');
    98          sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');
    99  
   100          return false;
   101      });
   102  
   103      jQuery('[data-sidebar-toggle]').on('click', function() {
   104          jQuery(document.body).toggleClass('sidebar-hidden');
   105          sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');
   106  
   107          return false;
   108      });
   109      jQuery('[data-clear-history-toggle]').on('click', function() {
   110          sessionStorage.clear();
   111          location.reload();
   112          return false;
   113      });
   114      jQuery('[data-search-toggle]').on('click', function() {
   115          if (sidebarStatus == 'closed') {
   116              jQuery('[data-sidebar-toggle]').trigger('click');
   117              jQuery(document.body).removeClass('searchbox-hidden');
   118              searchStatus = 'open';
   119  
   120              return false;
   121          }
   122  
   123          jQuery(document.body).toggleClass('searchbox-hidden');
   124          searchStatus = (jQuery(document.body).hasClass('searchbox-hidden') ? 'closed' : 'open');
   125  
   126          return false;
   127      });
   128  
   129      var ajax;
   130      jQuery('[data-search-input]').on('input', function() {
   131          var input = jQuery(this),
   132              value = input.val(),
   133              items = jQuery('[data-nav-id]');
   134          items.removeClass('search-match');
   135          if (!value.length) {
   136              $('ul.topics').removeClass('searched');
   137              items.css('display', 'block');
   138              sessionStorage.removeItem('search-value');
   139              $(".highlightable").unhighlight({ element: 'mark' })
   140              return;
   141          }
   142  
   143          sessionStorage.setItem('search-value', value);
   144          $(".highlightable").unhighlight({ element: 'mark' }).highlight(value, { element: 'mark' });
   145  
   146          if (ajax && ajax.abort) ajax.abort();
   147  
   148          jQuery('[data-search-clear]').on('click', function() {
   149              jQuery('[data-search-input]').val('').trigger('input');
   150              sessionStorage.removeItem('search-input');
   151              $(".highlightable").unhighlight({ element: 'mark' })
   152          });
   153      });
   154  
   155      $.expr[":"].contains = $.expr.createPseudo(function(arg) {
   156          return function( elem ) {
   157              return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
   158          };
   159      });
   160  
   161      if (sessionStorage.getItem('search-value')) {
   162          var searchValue = sessionStorage.getItem('search-value')
   163          $(document.body).removeClass('searchbox-hidden');
   164          $('[data-search-input]').val(searchValue);
   165          $('[data-search-input]').trigger('input');
   166          var searchedElem = $('#body-inner').find(':contains(' + searchValue + ')').get(0);
   167          if (searchedElem) {
   168              searchedElem.scrollIntoView(true);
   169              var scrolledY = window.scrollY;
   170              if(scrolledY){
   171                  window.scroll(0, scrolledY - 125);
   172              }
   173          }
   174      }
   175  
   176      // clipboard
   177      var clipInit = false;
   178      $('code').each(function() {
   179          var code = $(this),
   180              text = code.text();
   181  
   182          if (text.length > 5) {
   183              if (!clipInit) {
   184                  var text, clip = new ClipboardJS('.copy-to-clipboard', {
   185                      text: function(trigger) {
   186                          text = $(trigger).prev('code').text();
   187                          return text.replace(/^\$\s/gm, '');
   188                      }
   189                  });
   190  
   191                  var inPre;
   192                  clip.on('success', function(e) {
   193                      e.clearSelection();
   194                      inPre = $(e.trigger).parent().prop('tagName') == 'PRE';
   195                      $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
   196                  });
   197  
   198                  clip.on('error', function(e) {
   199                      inPre = $(e.trigger).parent().prop('tagName') == 'PRE';
   200                      $(e.trigger).attr('aria-label', fallbackMessage(e.action)).addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
   201                      $(document).one('copy', function(){
   202                          $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
   203                      });
   204                  });
   205  
   206                  clipInit = true;
   207              }
   208  
   209              code.after('<span class="copy-to-clipboard" title="Copy to clipboard" />');
   210              code.next('.copy-to-clipboard').on('mouseleave', function() {
   211                  $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w');
   212              });
   213          }
   214      });
   215  
   216      // allow keyboard control for prev/next links
   217      jQuery(function() {
   218          jQuery('.nav-prev').click(function(){
   219              location.href = jQuery(this).attr('href');
   220          });
   221          jQuery('.nav-next').click(function() {
   222              location.href = jQuery(this).attr('href');
   223          });
   224      });
   225  
   226      jQuery('input, textarea').keydown(function (e) {
   227           //  left and right arrow keys
   228           if (e.which == '37' || e.which == '39') {
   229               e.stopPropagation();
   230           }
   231       });
   232      
   233      jQuery(document).keydown(function(e) {
   234        // prev links - left arrow key
   235        if(e.which == '37') {
   236          jQuery('.nav.nav-prev').click();
   237        }
   238  
   239        // next links - right arrow key
   240        if(e.which == '39') {
   241          jQuery('.nav.nav-next').click();
   242        }
   243      });
   244  
   245      $('#top-bar a:not(:has(img)):not(.btn)').addClass('highlight');
   246      $('#body-inner a:not(:has(img)):not(.btn):not(a[rel="footnote"])').addClass('highlight');
   247  
   248      var touchsupport = ('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)
   249      if (!touchsupport){ // browser doesn't support touch
   250          $('#toc-menu').hover(function() {
   251              $('.progress').stop(true, false, true).fadeToggle(100);
   252          });
   253  
   254          $('.progress').hover(function() {
   255              $('.progress').stop(true, false, true).fadeToggle(100);
   256          });
   257      }
   258      if (touchsupport){ // browser does support touch
   259          $('#toc-menu').click(function() {
   260              $('.progress').stop(true, false, true).fadeToggle(100);
   261          });
   262          $('.progress').click(function() {
   263              $('.progress').stop(true, false, true).fadeToggle(100);
   264          });
   265      }
   266  
   267      /** 
   268      * Fix anchor scrolling that hides behind top nav bar
   269      * Courtesy of https://stackoverflow.com/a/13067009/28106
   270      *
   271      * We could use pure css for this if only heading anchors were
   272      * involved, but this works for any anchor, including footnotes
   273      **/
   274      (function (document, history, location) {
   275          var HISTORY_SUPPORT = !!(history && history.pushState);
   276  
   277          var anchorScrolls = {
   278              ANCHOR_REGEX: /^#[^ ]+$/,
   279              OFFSET_HEIGHT_PX: 50,
   280  
   281              /**
   282               * Establish events, and fix initial scroll position if a hash is provided.
   283               */
   284              init: function () {
   285                  this.scrollToCurrent();
   286                  $(window).on('hashchange', $.proxy(this, 'scrollToCurrent'));
   287                  $('body').on('click', 'a', $.proxy(this, 'delegateAnchors'));
   288              },
   289  
   290              /**
   291               * Return the offset amount to deduct from the normal scroll position.
   292               * Modify as appropriate to allow for dynamic calculations
   293               */
   294              getFixedOffset: function () {
   295                  return this.OFFSET_HEIGHT_PX;
   296              },
   297  
   298              /**
   299               * If the provided href is an anchor which resolves to an element on the
   300               * page, scroll to it.
   301               * @param  {String} href
   302               * @return {Boolean} - Was the href an anchor.
   303               */
   304              scrollIfAnchor: function (href, pushToHistory) {
   305                  var match, anchorOffset;
   306  
   307                  if (!this.ANCHOR_REGEX.test(href)) {
   308                      return false;
   309                  }
   310  
   311                  match = document.getElementById(href.slice(1));
   312  
   313                  if (match) {
   314                      anchorOffset = $(match).offset().top - this.getFixedOffset();
   315                      $('html, body').animate({ scrollTop: anchorOffset });
   316  
   317                      // Add the state to history as-per normal anchor links
   318                      if (HISTORY_SUPPORT && pushToHistory) {
   319                          history.pushState({}, document.title, location.pathname + href);
   320                      }
   321                  }
   322  
   323                  return !!match;
   324              },
   325  
   326              /**
   327               * Attempt to scroll to the current location's hash.
   328               */
   329              scrollToCurrent: function (e) {
   330                  if (this.scrollIfAnchor(window.location.hash) && e) {
   331                      e.preventDefault();
   332                  }
   333              },
   334  
   335              /**
   336               * If the click event's target was an anchor, fix the scroll position.
   337               */
   338              delegateAnchors: function (e) {
   339                  var elem = e.target;
   340  
   341                  if (this.scrollIfAnchor(elem.getAttribute('href'), true)) {
   342                      e.preventDefault();
   343                  }
   344              }
   345          };
   346  
   347          $(document).ready($.proxy(anchorScrolls, 'init'));
   348      })(window.document, window.history, window.location);
   349      
   350  });
   351  
   352  jQuery(window).on('load', function() {
   353  
   354      function adjustForScrollbar() {
   355          if ((parseInt(jQuery('#body-inner').height()) + 83) >= jQuery('#body').height()) {
   356              jQuery('.nav.nav-next').css({ 'margin-right': getScrollBarWidth() });
   357          } else {
   358              jQuery('.nav.nav-next').css({ 'margin-right': 0 });
   359          }
   360      }
   361  
   362      // adjust sidebar for scrollbar
   363      adjustForScrollbar();
   364  
   365      jQuery(window).smartresize(function() {
   366          adjustForScrollbar();
   367      });
   368  
   369      // store this page in session
   370      sessionStorage.setItem(jQuery('body').data('url'), 1);
   371  
   372      // loop through the sessionStorage and see if something should be marked as visited
   373      for (var url in sessionStorage) {
   374          if (sessionStorage.getItem(url) == 1) jQuery('[data-nav-id="' + url + '"]').addClass('visited');
   375      }
   376  
   377  
   378      $(".highlightable").highlight(sessionStorage.getItem('search-value'), { element: 'mark' });
   379  });
   380  
   381  $(function() {
   382      $('a[rel="lightbox"]').featherlight({
   383          root: 'section#body'
   384      });
   385  });
   386  
   387  jQuery.extend({
   388      highlight: function(node, re, nodeName, className) {
   389          if (node.nodeType === 3) {
   390              var match = node.data.match(re);
   391              if (match) {
   392                  var highlight = document.createElement(nodeName || 'span');
   393                  highlight.className = className || 'highlight';
   394                  var wordNode = node.splitText(match.index);
   395                  wordNode.splitText(match[0].length);
   396                  var wordClone = wordNode.cloneNode(true);
   397                  highlight.appendChild(wordClone);
   398                  wordNode.parentNode.replaceChild(highlight, wordNode);
   399                  return 1; //skip added node in parent
   400              }
   401          } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
   402              !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
   403              !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
   404              for (var i = 0; i < node.childNodes.length; i++) {
   405                  i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
   406              }
   407          }
   408          return 0;
   409      }
   410  });
   411  
   412  jQuery.fn.unhighlight = function(options) {
   413      var settings = {
   414          className: 'highlight',
   415          element: 'span'
   416      };
   417      jQuery.extend(settings, options);
   418  
   419      return this.find(settings.element + "." + settings.className).each(function() {
   420          var parent = this.parentNode;
   421          parent.replaceChild(this.firstChild, this);
   422          parent.normalize();
   423      }).end();
   424  };
   425  
   426  jQuery.fn.highlight = function(words, options) {
   427      var settings = {
   428          className: 'highlight',
   429          element: 'span',
   430          caseSensitive: false,
   431          wordsOnly: false
   432      };
   433      jQuery.extend(settings, options);
   434  
   435      if (!words) { return; }
   436  
   437      if (words.constructor === String) {
   438          words = [words];
   439      }
   440      words = jQuery.grep(words, function(word, i) {
   441          return word != '';
   442      });
   443      words = jQuery.map(words, function(word, i) {
   444          return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
   445      });
   446      if (words.length == 0) { return this; }
   447      ;
   448  
   449      var flag = settings.caseSensitive ? "" : "i";
   450      var pattern = "(" + words.join("|") + ")";
   451      if (settings.wordsOnly) {
   452          pattern = "\\b" + pattern + "\\b";
   453      }
   454      var re = new RegExp(pattern, flag);
   455  
   456      return this.each(function() {
   457          jQuery.highlight(this, re, settings.element, settings.className);
   458      });
   459  };