Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/AmazingRise/hugo-theme-diary.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoramazingrise <8315221+AmazingRise@users.noreply.github.com>2020-06-04 18:14:02 +0300
committeramazingrise <8315221+AmazingRise@users.noreply.github.com>2020-06-04 18:14:02 +0300
commit7980b976cfc62ab3ed1c852c47ea00b112f01b63 (patch)
treea1a283fb091d335f751887a6746cbf95b329d9ee
parentdbe3f9a9ebf7900f7c745eb6262b95c5c307fcc6 (diff)
parentecc7086da523397834a054cf5235cf7084b64f1e (diff)
Merge branch 'testing' with ToC collapse feature.
-rw-r--r--layouts/partials/head.html14
-rw-r--r--layouts/partials/toc.html31
-rw-r--r--static/js/journal.js10
-rw-r--r--static/js/table.js9
-rw-r--r--static/js/toc-collapse.js205
-rw-r--r--static/js/toc.js69
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