No Description
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

learn.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. // Scrollbar Width function
  2. function getScrollBarWidth() {
  3. var inner = document.createElement('p');
  4. inner.style.width = "100%";
  5. inner.style.height = "200px";
  6. var outer = document.createElement('div');
  7. outer.style.position = "absolute";
  8. outer.style.top = "0px";
  9. outer.style.left = "0px";
  10. outer.style.visibility = "hidden";
  11. outer.style.width = "200px";
  12. outer.style.height = "150px";
  13. outer.style.overflow = "hidden";
  14. outer.appendChild(inner);
  15. document.body.appendChild(outer);
  16. var w1 = inner.offsetWidth;
  17. outer.style.overflow = 'scroll';
  18. var w2 = inner.offsetWidth;
  19. if (w1 == w2) w2 = outer.clientWidth;
  20. document.body.removeChild(outer);
  21. return (w1 - w2);
  22. };
  23. function setMenuHeight() {
  24. $('#sidebar .highlightable').height($('#sidebar').innerHeight() - $('#header-wrapper').height() - 40);
  25. }
  26. function fallbackMessage(action) {
  27. var actionMsg = '';
  28. var actionKey = (action === 'cut' ? 'X' : 'C');
  29. if (/iPhone|iPad/i.test(navigator.userAgent)) {
  30. actionMsg = 'No support :(';
  31. }
  32. else if (/Mac/i.test(navigator.userAgent)) {
  33. actionMsg = 'Press ⌘-' + actionKey + ' to ' + action;
  34. }
  35. else {
  36. actionMsg = 'Press Ctrl-' + actionKey + ' to ' + action;
  37. }
  38. return actionMsg;
  39. }
  40. // for the window resize
  41. $(window).resize(function() {
  42. setMenuHeight();
  43. });
  44. // debouncing function from John Hann
  45. // http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
  46. (function($, sr) {
  47. var debounce = function(func, threshold, execAsap) {
  48. var timeout;
  49. return function debounced() {
  50. var obj = this, args = arguments;
  51. function delayed() {
  52. if (!execAsap)
  53. func.apply(obj, args);
  54. timeout = null;
  55. };
  56. if (timeout)
  57. clearTimeout(timeout);
  58. else if (execAsap)
  59. func.apply(obj, args);
  60. timeout = setTimeout(delayed, threshold || 100);
  61. };
  62. }
  63. // smartresize
  64. jQuery.fn[sr] = function(fn) { return fn ? this.bind('resize', debounce(fn)) : this.trigger(sr); };
  65. })(jQuery, 'smartresize');
  66. jQuery(document).ready(function() {
  67. var sidebarStatus = searchStatus = 'open';
  68. // set the menu height
  69. setMenuHeight();
  70. jQuery('#overlay').on('click', function() {
  71. jQuery(document.body).toggleClass('sidebar-hidden');
  72. sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');
  73. return false;
  74. });
  75. jQuery('.scrollbar-inner').scrollbar();
  76. jQuery('[data-sidebar-toggle]').on('click', function() {
  77. jQuery(document.body).toggleClass('sidebar-hidden');
  78. sidebarStatus = (jQuery(document.body).hasClass('sidebar-hidden') ? 'closed' : 'open');
  79. return false;
  80. });
  81. jQuery('[data-clear-history-toggle]').on('click', function() {
  82. sessionStorage.clear();
  83. location.reload();
  84. return false;
  85. });
  86. jQuery('[data-search-toggle]').on('click', function() {
  87. if (sidebarStatus == 'closed') {
  88. jQuery('[data-sidebar-toggle]').trigger('click');
  89. jQuery(document.body).removeClass('searchbox-hidden');
  90. searchStatus = 'open';
  91. return false;
  92. }
  93. jQuery(document.body).toggleClass('searchbox-hidden');
  94. searchStatus = (jQuery(document.body).hasClass('searchbox-hidden') ? 'closed' : 'open');
  95. return false;
  96. });
  97. var ajax;
  98. jQuery('[data-search-input]').on('input', function() {
  99. var input = jQuery(this),
  100. value = input.val(),
  101. items = jQuery('[data-nav-id]');
  102. items.removeClass('search-match');
  103. if (!value.length) {
  104. $('ul.topics').removeClass('searched');
  105. items.css('display', 'block');
  106. sessionStorage.removeItem('search-value');
  107. $(".highlightable").unhighlight({ element: 'mark' })
  108. return;
  109. }
  110. sessionStorage.setItem('search-value', value);
  111. $(".highlightable").unhighlight({ element: 'mark' }).highlight(value, { element: 'mark' });
  112. if (ajax && ajax.abort) ajax.abort();
  113. ajax = jQuery.ajax({
  114. url: input.data('search-input') + ':' + value
  115. }).done(function(data) {
  116. if (data && data.results && data.results.length) {
  117. items.css('display', 'none');
  118. $('ul.topics').addClass('searched');
  119. data.results.forEach(function(navitem) {
  120. jQuery('[data-nav-id="' + navitem + '"]').css('display', 'block').addClass('search-match');
  121. jQuery('[data-nav-id="' + navitem + '"]').parents('li').css('display', 'block');
  122. });
  123. }
  124. ;
  125. });
  126. jQuery('[data-search-clear]').on('click', function() {
  127. jQuery('[data-search-input]').val('').trigger('input');
  128. sessionStorage.removeItem('search-input');
  129. $(".highlightable").unhighlight({ element: 'mark' })
  130. });
  131. });
  132. if (sessionStorage.getItem('search-value')) {
  133. jQuery(document.body).removeClass('searchbox-hidden');
  134. jQuery('[data-search-input]').val(sessionStorage.getItem('search-value'));
  135. jQuery('[data-search-input]').trigger('input');
  136. }
  137. // clipboard
  138. var clipInit = false;
  139. $('code').each(function() {
  140. var code = $(this),
  141. text = code.text();
  142. if (text.length > 5) {
  143. if (!clipInit) {
  144. var text, clip = new Clipboard('.copy-to-clipboard', {
  145. text: function(trigger) {
  146. text = $(trigger).prev('code').text();
  147. return text.replace(/^\$\s/gm, '');
  148. }
  149. });
  150. var inPre;
  151. clip.on('success', function(e) {
  152. e.clearSelection();
  153. inPre = $(e.trigger).parent().prop('tagName') == 'PRE';
  154. $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
  155. });
  156. clip.on('error', function(e) {
  157. inPre = $(e.trigger).parent().prop('tagName') == 'PRE';
  158. $(e.trigger).attr('aria-label', fallbackMessage(e.action)).addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
  159. $(document).one('copy', function(){
  160. $(e.trigger).attr('aria-label', 'Copied to clipboard!').addClass('tooltipped tooltipped-' + (inPre ? 'w' : 's'));
  161. });
  162. });
  163. clipInit = true;
  164. }
  165. code.after('<span class="copy-to-clipboard" title="Copy to clipboard" />');
  166. code.next('.copy-to-clipboard').on('mouseleave', function() {
  167. $(this).attr('aria-label', null).removeClass('tooltipped tooltipped-s tooltipped-w');
  168. });
  169. }
  170. });
  171. // allow keyboard control for prev/next links
  172. jQuery(function() {
  173. jQuery('.nav-prev').click(function(){
  174. location.href = jQuery(this).attr('href');
  175. });
  176. jQuery('.nav-next').click(function() {
  177. location.href = jQuery(this).attr('href');
  178. });
  179. });
  180. jQuery(document).keydown(function(e) {
  181. // prev links - left arrow key
  182. if(e.which == '37') {
  183. jQuery('.nav.nav-prev').click();
  184. }
  185. // next links - right arrow key
  186. if(e.which == '39') {
  187. jQuery('.nav.nav-next').click();
  188. }
  189. });
  190. });
  191. jQuery(window).on('load', function() {
  192. function adjustForScrollbar() {
  193. if ((parseInt(jQuery('#body-inner').height()) + 83) >= jQuery('#body').height()) {
  194. jQuery('.nav.nav-next').css({ 'margin-right': getScrollBarWidth() });
  195. } else {
  196. jQuery('.nav.nav-next').css({ 'margin-right': 0 });
  197. }
  198. }
  199. // adjust sidebar for scrollbar
  200. adjustForScrollbar();
  201. jQuery(window).smartresize(function() {
  202. adjustForScrollbar();
  203. });
  204. // store this page in session
  205. sessionStorage.setItem(jQuery('body').data('url'), 1);
  206. // loop through the sessionStorage and see if something should be marked as visited
  207. for (var url in sessionStorage) {
  208. if (sessionStorage.getItem(url) == 1) jQuery('[data-nav-id="' + url + '"]').addClass('visited');
  209. }
  210. $(".highlightable").highlight(sessionStorage.getItem('search-value'), { element: 'mark' });
  211. });
  212. $(function() {
  213. $('a[rel="lightbox"]').featherlight({
  214. root: 'section#body'
  215. });
  216. });
  217. jQuery.extend({
  218. highlight: function(node, re, nodeName, className) {
  219. if (node.nodeType === 3) {
  220. var match = node.data.match(re);
  221. if (match) {
  222. var highlight = document.createElement(nodeName || 'span');
  223. highlight.className = className || 'highlight';
  224. var wordNode = node.splitText(match.index);
  225. wordNode.splitText(match[0].length);
  226. var wordClone = wordNode.cloneNode(true);
  227. highlight.appendChild(wordClone);
  228. wordNode.parentNode.replaceChild(highlight, wordNode);
  229. return 1; //skip added node in parent
  230. }
  231. } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
  232. !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
  233. !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
  234. for (var i = 0; i < node.childNodes.length; i++) {
  235. i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
  236. }
  237. }
  238. return 0;
  239. }
  240. });
  241. jQuery.fn.unhighlight = function(options) {
  242. var settings = {
  243. className: 'highlight',
  244. element: 'span'
  245. };
  246. jQuery.extend(settings, options);
  247. return this.find(settings.element + "." + settings.className).each(function() {
  248. var parent = this.parentNode;
  249. parent.replaceChild(this.firstChild, this);
  250. parent.normalize();
  251. }).end();
  252. };
  253. jQuery.fn.highlight = function(words, options) {
  254. var settings = {
  255. className: 'highlight',
  256. element: 'span',
  257. caseSensitive: false,
  258. wordsOnly: false
  259. };
  260. jQuery.extend(settings, options);
  261. if (!words) { return; }
  262. if (words.constructor === String) {
  263. words = [words];
  264. }
  265. words = jQuery.grep(words, function(word, i) {
  266. return word != '';
  267. });
  268. words = jQuery.map(words, function(word, i) {
  269. return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
  270. });
  271. if (words.length == 0) { return this; }
  272. ;
  273. var flag = settings.caseSensitive ? "" : "i";
  274. var pattern = "(" + words.join("|") + ")";
  275. if (settings.wordsOnly) {
  276. pattern = "\\b" + pattern + "\\b";
  277. }
  278. var re = new RegExp(pattern, flag);
  279. return this.each(function() {
  280. jQuery.highlight(this, re, settings.element, settings.className);
  281. });
  282. };