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.
 
 
 
 
 

313 lines
10 KiB

  1. ---
  2. ---
  3. (function (jtd, undefined) {
  4. // Event handling
  5. jtd.addEvent = function(el, type, handler) {
  6. if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler);
  7. }
  8. jtd.removeEvent = function(el, type, handler) {
  9. if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler);
  10. }
  11. jtd.onReady = function(ready) {
  12. // in case the document is already rendered
  13. if (document.readyState!='loading') ready();
  14. // modern browsers
  15. else if (document.addEventListener) document.addEventListener('DOMContentLoaded', ready);
  16. // IE <= 8
  17. else document.attachEvent('onreadystatechange', function(){
  18. if (document.readyState=='complete') ready();
  19. });
  20. }
  21. // Show/hide mobile menu
  22. function initNav() {
  23. const mainNav = document.querySelector('.js-main-nav');
  24. const pageHeader = document.querySelector('.js-page-header');
  25. const navTrigger = document.querySelector('.js-main-nav-trigger');
  26. jtd.addEvent(navTrigger, 'click', function(e){
  27. e.preventDefault();
  28. var text = navTrigger.innerText;
  29. var textToggle = navTrigger.getAttribute('data-text-toggle');
  30. mainNav.classList.toggle('nav-open');
  31. pageHeader.classList.toggle('nav-open');
  32. navTrigger.classList.toggle('nav-open');
  33. navTrigger.innerText = textToggle;
  34. navTrigger.setAttribute('data-text-toggle', text);
  35. textToggle = text;
  36. })
  37. }
  38. // Site search
  39. function initSearch() {
  40. var request = new XMLHttpRequest();
  41. request.open('GET', '{{ "assets/js/search-data.json" | absolute_url }}', true);
  42. request.onload = function(){
  43. if (request.status >= 200 && request.status < 400) {
  44. // Success!
  45. var data = JSON.parse(request.responseText);
  46. {% if site.search_tokenizer_separator != nil %}
  47. lunr.tokenizer.separator = {{ site.search_tokenizer_separator }}
  48. {% else %}
  49. lunr.tokenizer.separator = /[\s\-/]+/
  50. {% endif %}
  51. var index = lunr(function () {
  52. this.ref('id');
  53. this.field('title', { boost: 200 });
  54. this.field('content', { boost: 2 });
  55. this.field('url');
  56. this.metadataWhitelist = ['position']
  57. for (var i in data) {
  58. this.add({
  59. id: i,
  60. title: data[i].title,
  61. content: data[i].content,
  62. url: data[i].url
  63. });
  64. }
  65. });
  66. searchResults(index, data);
  67. } else {
  68. // We reached our target server, but it returned an error
  69. console.log('Error loading ajax request. Request status:' + request.status);
  70. }
  71. };
  72. request.onerror = function(){
  73. // There was a connection error of some sort
  74. console.log('There was a connection error');
  75. };
  76. request.send();
  77. function searchResults(index, data) {
  78. var index = index;
  79. var docs = data;
  80. var searchInput = document.querySelector('.js-search-input');
  81. var searchResults = document.querySelector('.js-search-results');
  82. function hideResults() {
  83. searchResults.innerHTML = '';
  84. searchResults.classList.remove('active');
  85. }
  86. jtd.addEvent(searchInput, 'keydown', function(e){
  87. switch (e.keyCode) {
  88. case 38: // arrow up
  89. e.preventDefault();
  90. var active = document.querySelector('.search-result.active');
  91. if (active) {
  92. active.classList.remove('active');
  93. if (active.parentElement.previousSibling) {
  94. var previous = active.parentElement.previousSibling.querySelector('.search-result');
  95. previous.classList.add('active');
  96. }
  97. }
  98. return;
  99. case 40: // arrow down
  100. e.preventDefault();
  101. var active = document.querySelector('.search-result.active');
  102. if (active) {
  103. if (active.parentElement.nextSibling) {
  104. var next = active.parentElement.nextSibling.querySelector('.search-result');
  105. active.classList.remove('active');
  106. next.classList.add('active');
  107. }
  108. } else {
  109. var next = document.querySelector('.search-result');
  110. if (next) {
  111. next.classList.add('active');
  112. }
  113. }
  114. return;
  115. case 13: // enter
  116. e.preventDefault();
  117. var active = document.querySelector('.search-result.active');
  118. if (active) {
  119. active.click();
  120. } else {
  121. var first = document.querySelector('.search-result');
  122. if (first) {
  123. first.click();
  124. }
  125. }
  126. return;
  127. }
  128. });
  129. jtd.addEvent(searchInput, 'keyup', function(e){
  130. switch (e.keyCode) {
  131. case 27: // When esc key is pressed, hide the results and clear the field
  132. hideResults();
  133. searchInput.value = '';
  134. return;
  135. case 38: // arrow up
  136. case 40: // arrow down
  137. case 13: // enter
  138. e.preventDefault();
  139. return;
  140. }
  141. hideResults();
  142. var input = this.value;
  143. if (input === '') {
  144. return;
  145. }
  146. var results = index.query(function (query) {
  147. var tokens = lunr.tokenizer(input)
  148. query.term(tokens, {
  149. boost: 10
  150. });
  151. query.term(tokens, {
  152. wildcard: lunr.Query.wildcard.TRAILING
  153. });
  154. });
  155. if (results.length > 0) {
  156. searchResults.classList.add('active');
  157. var resultsList = document.createElement('ul');
  158. resultsList.classList.add('search-results-list');
  159. searchResults.appendChild(resultsList);
  160. for (var i in results) {
  161. var result = results[i];
  162. var doc = docs[result.ref];
  163. var resultsListItem = document.createElement('li');
  164. resultsListItem.classList.add('search-results-list-item');
  165. resultsList.appendChild(resultsListItem);
  166. var resultLink = document.createElement('a');
  167. resultLink.classList.add('search-result');
  168. resultLink.setAttribute('href', doc.url);
  169. resultsListItem.appendChild(resultLink);
  170. var resultTitle = document.createElement('div');
  171. resultTitle.classList.add('search-result-title');
  172. resultTitle.innerText = doc.title;
  173. resultLink.appendChild(resultTitle);
  174. var resultRelUrl = document.createElement('span');
  175. resultRelUrl.classList.add('search-result-rel-url');
  176. resultRelUrl.innerText = doc.relUrl;
  177. resultTitle.appendChild(resultRelUrl);
  178. var metadata = result.matchData.metadata;
  179. var contentFound = false;
  180. for (var j in metadata) {
  181. if (metadata[j].title) {
  182. var position = metadata[j].title.position[0];
  183. var start = position[0];
  184. var end = position[0] + position[1];
  185. resultTitle.innerHTML = doc.title.substring(0, start) + '<span class="search-result-highlight">' + doc.title.substring(start, end) + '</span>' + doc.title.substring(end, doc.title.length)+'<span class="search-result-rel-url">'+doc.relUrl+'</span>';
  186. } else if (metadata[j].content && !contentFound) {
  187. contentFound = true;
  188. var position = metadata[j].content.position[0];
  189. var start = position[0];
  190. var end = position[0] + position[1];
  191. var previewStart = start;
  192. var previewEnd = end;
  193. var ellipsesBefore = true;
  194. var ellipsesAfter = true;
  195. for (var k = 0; k < 3; k++) {
  196. var nextSpace = doc.content.lastIndexOf(' ', previewStart - 2);
  197. var nextDot = doc.content.lastIndexOf('.', previewStart - 2);
  198. if ((nextDot > 0) && (nextDot > nextSpace)) {
  199. previewStart = nextDot + 1;
  200. ellipsesBefore = false;
  201. break;
  202. }
  203. if (nextSpace < 0) {
  204. previewStart = 0;
  205. ellipsesBefore = false;
  206. break;
  207. }
  208. previewStart = nextSpace + 1;
  209. }
  210. for (var k = 0; k < 10; k++) {
  211. var nextSpace = doc.content.indexOf(' ', previewEnd + 1);
  212. var nextDot = doc.content.indexOf('.', previewEnd + 1);
  213. if ((nextDot > 0) && (nextDot < nextSpace)) {
  214. previewEnd = nextDot;
  215. ellipsesAfter = false;
  216. break;
  217. }
  218. if (nextSpace < 0) {
  219. previewEnd = doc.content.length;
  220. ellipsesAfter = false;
  221. break;
  222. }
  223. previewEnd = nextSpace;
  224. }
  225. var preview = doc.content.substring(previewStart, start);
  226. if (ellipsesBefore) {
  227. preview = '... ' + preview;
  228. }
  229. preview += '<span class="search-result-highlight">' + doc.content.substring(start, end) + '</span>';
  230. preview += doc.content.substring(end, previewEnd);
  231. if (ellipsesAfter) {
  232. preview += ' ...';
  233. }
  234. var resultPreview = document.createElement('div');
  235. resultPreview.classList.add('search-result-preview');
  236. resultPreview.innerHTML = preview;
  237. resultLink.appendChild(resultPreview);
  238. }
  239. }
  240. }
  241. }
  242. });
  243. jtd.addEvent(searchInput, 'blur', function(){
  244. setTimeout(function(){ hideResults() }, 300);
  245. });
  246. }
  247. }
  248. function pageFocus() {
  249. var mainContent = document.querySelector('.js-main-content');
  250. mainContent.focus();
  251. }
  252. // Set theme according to user preferences
  253. function setTheme() {
  254. const cssFile = document.querySelector('[rel="stylesheet"]')
  255. const originalCssRef = cssFile.getAttribute('href')
  256. const darkModeCssRef = originalCssRef.replace('just-the-docs.css', 'dark-mode-preview.css')
  257. if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
  258. cssFile.setAttribute('href', darkModeCssRef)
  259. }
  260. }
  261. // Document ready
  262. jtd.onReady(function(){
  263. initNav();
  264. setTheme();
  265. pageFocus();
  266. if (typeof lunr !== 'undefined') {
  267. initSearch();
  268. }
  269. });
  270. })(window.jtd = window.jtd || {});
  271. {% include js/custom.js %}