diff options
author | amazingrise <8315221+AmazingRise@users.noreply.github.com> | 2020-06-04 18:14:02 +0300 |
---|---|---|
committer | amazingrise <8315221+AmazingRise@users.noreply.github.com> | 2020-06-04 18:14:02 +0300 |
commit | 7980b976cfc62ab3ed1c852c47ea00b112f01b63 (patch) | |
tree | a1a283fb091d335f751887a6746cbf95b329d9ee | |
parent | dbe3f9a9ebf7900f7c745eb6262b95c5c307fcc6 (diff) | |
parent | ecc7086da523397834a054cf5235cf7084b64f1e (diff) |
Merge branch 'testing' with ToC collapse feature.
-rw-r--r-- | layouts/partials/head.html | 14 | ||||
-rw-r--r-- | layouts/partials/toc.html | 31 | ||||
-rw-r--r-- | static/js/journal.js | 10 | ||||
-rw-r--r-- | static/js/table.js | 9 | ||||
-rw-r--r-- | static/js/toc-collapse.js | 205 | ||||
-rw-r--r-- | static/js/toc.js | 69 |
6 files changed, 292 insertions, 46 deletions
diff --git a/layouts/partials/head.html b/layouts/partials/head.html index 773bff3..588d07e 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -40,20 +40,16 @@ loadCSS("https://fonts.googleapis.com/css?family=Lora|Montserrat|Fira+Mono|Noto+Serif+SC|Material+Icons"); </script> -<script src="{{.Site.BaseURL}}/js/table.js"></script> - {{ if .Params.enableMathJax }} {{ partial "mathjax.html" . }} {{ end }} {{ if and (not (.Params.disableToC) ) (.IsPage) }} -<script src="{{.Site.BaseURL}}/js/toc.js"></script> -{{ else }} -<style> - .toc{ - display: none !important; - } -</style> + {{ if .Params.disableAutoCollapse }} + <script src="{{.Site.BaseURL}}/js/toc.js"></script> + {{ else }} + <script src="{{.Site.BaseURL}}/js/toc-collapse.js"></script> + {{ end }} {{ end }} {{ if and (.Site.Params.enableGitalk) (.IsPage) }} diff --git a/layouts/partials/toc.html b/layouts/partials/toc.html index a21fa69..667b12c 100644 --- a/layouts/partials/toc.html +++ b/layouts/partials/toc.html @@ -7,25 +7,36 @@ {{ $re := (cond (eq $h1_n 0) "<h[2-4]" "<h[1-4]") }} {{ $renum := (cond (eq $h1_n 0) "[2-4]" "[1-4]") }} <center>- {{ i18n "toc_title" }} -</center> + {{ $scratch := newScratch }} + {{ $scratch.Set "prev_heading" 1 }} + <ul> {{ range $headers }} {{ $header := . }} {{ range first 1 (findRE $re $header 1) }} {{ range findRE $renum . 1 }} {{ $next_heading := (cond (eq $h1_n 0) (sub (int .) 1 ) (int . ) ) }} - {{ range seq $next_heading }} - <ul> + {{ $prev_heading := $scratch.Get "prev_heading"}} + {{ if lt $next_heading $prev_heading }} + {{ range seq (sub $prev_heading $next_heading) }} + </ul> + {{ end }} {{ end }} - {{ $anchorId := (replaceRE ".* id=\"(.*?)\".*" "$1" $header ) }} - <li> - <a href="#{{ $anchorId }}" v-on:click="closeDrawer" id="{{ $anchorId }}-nav"> - {{ $header | plainify | htmlUnescape }} - </a> - </li> - {{ range seq $next_heading }} - </ul> + {{ if gt $next_heading $prev_heading }} + {{ range seq (sub $next_heading $prev_heading) }} + <ul class="collapse" data-toggle="collapse"> + {{ end }} {{ end }} + {{ $anchorId := (replaceRE ".* id=\"(.*?)\".*" "$1" $header ) }} + <li> + <a href="#{{ $anchorId }}" onclick="collapseOthers(`#{{ $anchorId | safeJS}}-nav`)" id="{{ $anchorId }}-nav"> + {{ $header | plainify | htmlUnescape }} + </a> + </li> + + {{ $scratch.Set "prev_heading" $next_heading }} {{ end }} {{ end }} {{ end }} + </ul> </div> {{ end }} diff --git a/static/js/journal.js b/static/js/journal.js index 849fc57..fe6d4fe 100644 --- a/static/js/journal.js +++ b/static/js/journal.js @@ -16,3 +16,13 @@ Vue.component('parent',{ </div> ` }); + +$().ready(function(){ + var elems = $("table"); + elems.each(function(idx){ + $(this).addClass('table-striped'); + $(this).addClass('table'); + $(this).addClass('table-responsive'); + $(this).addClass('table-hover'); + }); +});
\ No newline at end of file diff --git a/static/js/table.js b/static/js/table.js deleted file mode 100644 index 6d8605d..0000000 --- a/static/js/table.js +++ /dev/null @@ -1,9 +0,0 @@ -$().ready(function(){ - var elems = $("table"); - elems.each(function(idx){ - $(this).addClass('table-striped'); - $(this).addClass('table'); - $(this).addClass('table-responsive'); - $(this).addClass('table-hover'); - }); -});
\ No newline at end of file diff --git a/static/js/toc-collapse.js b/static/js/toc-collapse.js new file mode 100644 index 0000000..a2780f9 --- /dev/null +++ b/static/js/toc-collapse.js @@ -0,0 +1,205 @@ +var spy = function () { + var elems = $(":header"); + if (elems.length == 0) { + return; + } + var currentTop = $(window).scrollTop(); + var currentBottom = $(window).scrollTop() + $(window).height(); + var pageBottom = $('#EOF').offset().top; + + var meetUnread = false + var currentIndex = -1 + elems.each(function (idx) { + var elemTop = $(this).offset().top; + var id = $(this).attr('id'); + var navElem = $('#' + id + '-nav'); + if (currentTop + $(this).height() >= elemTop || currentBottom >= pageBottom) { + navElem.addClass('toc-active'); + } else { + if (meetUnread == false) { + meetUnread = true + currentIndex = idx - 1 + } + navElem.removeClass('toc-active'); + } + }) + if (currentIndex == -1) { + currentIndex = elems.length - 1; + } + //console.log(elems[currentIndex].id); + //Collapse them + collapseOthers("#" + elems[currentIndex].id + "-nav"); +} +var collapseOthers = function (currentId) { + //console.log(currentId); + $(currentId).parents(".collapse").each(function (idx) { + $(this).collapse("show"); + }); + $(currentId).parent().next().filter(".collapse").collapse("show"); + $(".collapse").not($(currentId).parents()).not($(currentId).parent().next()).each(function (idx) { + $(this).collapse("hide"); + }); + +} +$().ready(function () { + spy(); + $(window).bind('scroll', debounce(spy, 250, { 'maxWait': 1000 })); +}); + + +//From https://github.com/lodash/lodash/blob/master/debounce.js +// and https://github.com/lodash/lodash/blob/master/isObject.js + +function debounce(func, wait, options) { + let lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime + + let lastInvokeTime = 0 + let leading = false + let maxing = false + let trailing = true + + // Bypass `requestAnimationFrame` by explicitly setting `wait=0`. + const useRAF = (!wait && wait !== 0 && typeof root.requestAnimationFrame === 'function') + + if (typeof func !== 'function') { + throw new TypeError('Expected a function') + } + function isObject(value) { + const type = typeof value + return value != null && (type === 'object' || type === 'function') + } + + wait = +wait || 0 + if (isObject(options)) { + leading = !!options.leading + maxing = 'maxWait' in options + maxWait = maxing ? Math.max(+options.maxWait || 0, wait) : maxWait + trailing = 'trailing' in options ? !!options.trailing : trailing + } + + function invokeFunc(time) { + const args = lastArgs + const thisArg = lastThis + + lastArgs = lastThis = undefined + lastInvokeTime = time + result = func.apply(thisArg, args) + return result + } + + function startTimer(pendingFunc, wait) { + if (useRAF) { + root.cancelAnimationFrame(timerId) + return root.requestAnimationFrame(pendingFunc) + } + return setTimeout(pendingFunc, wait) + } + + function cancelTimer(id) { + if (useRAF) { + return root.cancelAnimationFrame(id) + } + clearTimeout(id) + } + + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time + // Start the timer for the trailing edge. + timerId = startTimer(timerExpired, wait) + // Invoke the leading edge. + return leading ? invokeFunc(time) : result + } + + function remainingWait(time) { + const timeSinceLastCall = time - lastCallTime + const timeSinceLastInvoke = time - lastInvokeTime + const timeWaiting = wait - timeSinceLastCall + + return maxing + ? Math.min(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting + } + + function shouldInvoke(time) { + const timeSinceLastCall = time - lastCallTime + const timeSinceLastInvoke = time - lastInvokeTime + + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)) + } + + function timerExpired() { + const time = Date.now() + if (shouldInvoke(time)) { + return trailingEdge(time) + } + // Restart the timer. + timerId = startTimer(timerExpired, remainingWait(time)) + } + + function trailingEdge(time) { + timerId = undefined + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time) + } + lastArgs = lastThis = undefined + return result + } + + function cancel() { + if (timerId !== undefined) { + cancelTimer(timerId) + } + lastInvokeTime = 0 + lastArgs = lastCallTime = lastThis = timerId = undefined + } + + function flush() { + return timerId === undefined ? result : trailingEdge(Date.now()) + } + + function pending() { + return timerId !== undefined + } + + function debounced(...args) { + const time = Date.now() + const isInvoking = shouldInvoke(time) + + lastArgs = args + lastThis = this + lastCallTime = time + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime) + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = startTimer(timerExpired, wait) + return invokeFunc(lastCallTime) + } + } + if (timerId === undefined) { + timerId = startTimer(timerExpired, wait) + } + return result + } + debounced.cancel = cancel + debounced.flush = flush + debounced.pending = pending + return debounced + } +
\ No newline at end of file diff --git a/static/js/toc.js b/static/js/toc.js index 075a09e..61fdc93 100644 --- a/static/js/toc.js +++ b/static/js/toc.js @@ -1,22 +1,55 @@ -$().ready(function(){ - var elems = $(":header"); - if (elems.length == 0) { - return; - } - $(window).bind('scroll', function() { - var currentTop = $(window).scrollTop(); - var currentBottom = $(window).scrollTop() + $(window).height(); - var pageBottom = $('#EOF').offset().top; - - elems.each(function(idx){ +var spy = function () { + var elems = $(":header"); + if (elems.length == 0) { + return; + } + var currentTop = $(window).scrollTop(); + var currentBottom = $(window).scrollTop() + $(window).height(); + var pageBottom = $('#EOF').offset().top; + + var meetUnread = false + var currentIndex = -1 + elems.each(function (idx) { var elemTop = $(this).offset().top; var id = $(this).attr('id'); - var navElem = $('#' + id+ '-nav'); - if(currentTop >= elemTop || currentBottom >= pageBottom){ - navElem.addClass('toc-active'); + var navElem = $('#' + id + '-nav'); + if (currentTop + $(this).height() >= elemTop || currentBottom >= pageBottom) { + navElem.addClass('toc-active'); } else { - navElem.removeClass('toc-active'); + if (meetUnread == false) { + meetUnread = true + currentIndex = idx - 1 + } + navElem.removeClass('toc-active'); } - }) - }); -});
\ No newline at end of file + }) +} +$().ready(function () { + $(".collapse").each(function (idx) { + $(this).collapse("show"); + }); + spy(); + $(window).bind('scroll', throttle(spy)); +}); + +function throttle(func, timeout = 250) { + let last; + let timer; + + return function () { + const context = this; + const args = arguments; + const now = +new Date(); + + if (last && now < last + timeout) { + clearTimeout(timer) + timer = setTimeout(function () { + last = now + func.apply(context, args) + }, timeout) + } else { + last = now + func.apply(context, args) + } + } + }
\ No newline at end of file |