Browse Source

feat(feature/table-of-contents): add native smooth-scroll

fixes #43
Josh Habdas 6 months ago
parent
commit
94b13a1af7
No account linked to committer's email address

+ 1
- 0
assets/css/theme.css View File

@@ -1,4 +1,5 @@
1 1
 :root {
2
+  scroll-behavior: smooth;
2 3
   --screen-size-small: 30em; /* breakpoint reference only */
3 4
 }
4 5
 @keyframes intro {

+ 0
- 2
docs/content/feature/jit-requests.id.md View File

@@ -24,6 +24,4 @@ jit-requests (document)
24 24
 
25 25
 Menggunakan [Fetch Injection](../fetch-injection) permintaan JIT dikeluarkan untuk mulai mengunduh sorotan stylesheet dengan cepat secara pararel dengan sumber daya lain, dan tata letak dasar berhati-hati untuk memastikan CSS hanya diminta pada halaman yang membutuhkan itu.
26 26
 
27
-Contoh lain dari permintaan JIT dapat dilihat di [Table Of Contents](../table-of-contents) dimana `scroll-behavior` polyfill dimuat secara tidak sinkron dan hanya sekali saja pengguna menunjukkan keinginan untuk menggunakan fitur ini, jika tidak disembunyikan di bawah penyingkapan.
28
-
29 27
 Buatlah permintaan JIT anda sendiri menggunakan [Custom Layout](../custom-layouts) dan [Fetch Injection](../fetch-injection).

+ 0
- 2
docs/content/feature/jit-requests.md View File

@@ -24,6 +24,4 @@ jit-requests (document)
24 24
 
25 25
 Using [Fetch Injection](../fetch-injection) a JIT request is issued to begin downloading the highlighter stylesheet on-the-fly in parallel with other resources and the base layout takes care to ensure the CSS is only requested on pages that need it.
26 26
 
27
-Another example of a JIT request can be seen in the [Table Of Contents](../table-of-contents) whereby a `scroll-behavior` polyfill is loaded asynchronyously and only once the user shows intent to use the feature, otherwise hidden under a disclosure.
28
-
29 27
 Create your own JIT requests using [Custom Layout](../custom-layouts) and [Fetch Injection](../fetch-injection).

+ 0
- 19
layouts/partials/toc-maybe.html View File

@@ -3,23 +3,4 @@
3 3
     <summary>Table of Contents</summary>
4 4
     {{ .TableOfContents }}
5 5
   </details>
6
-  <script>
7
-    (function (window, document, undefined) {
8
-      const el = document.querySelector('details summary');
9
-      el.onclick = () => {
10
-        window.fetchInject([{{ "/js/smoothscroll.js" | relURL }}]);
11
-        el.onclick = null;
12
-        document.querySelectorAll('#TableOfContents a').forEach(link => {
13
-          link.addEventListener('click', evt => {
14
-            evt.preventDefault();
15
-            const selector = link.href.slice(link.href.indexOf('#'));
16
-            document.querySelector(
17
-              selector
18
-            ).scrollIntoView({ behavior: 'smooth' });
19
-            window.history.pushState({}, "", selector);
20
-          });
21
-        });
22
-      };
23
-    })(window, document);
24
-  </script>
25 6
 {{ end }}

+ 0
- 6
package-lock.json View File

@@ -1796,12 +1796,6 @@
1796 1796
       "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
1797 1797
       "dev": true
1798 1798
     },
1799
-    "smoothscroll-polyfill": {
1800
-      "version": "0.4.3",
1801
-      "resolved": "https://registry.npmjs.org/smoothscroll-polyfill/-/smoothscroll-polyfill-0.4.3.tgz",
1802
-      "integrity": "sha512-aUg0sY8XlWw9reC3VGlVdmC9W4K565alN4t8Cm50kULz53NB4GvsZbrinWPLqYqLolY60NBdqHDyh89MqDUc/Q==",
1803
-      "dev": true
1804
-    },
1805 1799
     "source-map": {
1806 1800
       "version": "0.6.1",
1807 1801
       "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",

+ 0
- 2
package.json View File

@@ -25,7 +25,6 @@
25 25
   "scripts": {
26 26
     "update:lazysizes": "npm up lazysizes && cp -i node_modules/lazysizes/lazysizes.min.js static/js",
27 27
     "update:lodash:custom": "./node_modules/.bin/lodash include=debounce -p -o static/js/lodash.custom.min.js",
28
-    "update:smoothscroll": "npm up smoothscroll && cp -i node_modules/smoothscroll-polyfill/dist/smoothscroll.js static/js",
29 28
     "update:fuse": "npm up fuse.js && cp -i node_modules/fuse.js/dist/fuse.min.js static/js",
30 29
     "update:vue": "npm up vue && cp -i node_modules/vue/dist/vue.min.js static/js",
31 30
     "update:mark": "npm up mark.js && cp -i node_modules/mark.js/dist/mark.min.js static/js",
@@ -41,7 +40,6 @@
41 40
     "lazysizes": "^4.1.4",
42 41
     "lodash-cli": "^4.17.5",
43 42
     "mark.js": "^8.11.1",
44
-    "smoothscroll-polyfill": "^0.4.3",
45 43
     "standard-version": "^4.4.0",
46 44
     "toxic-swamp": "git+ssh://git@git.habd.as/comfusion/toxic-swamp.git#v0.1.0-alpha.0",
47 45
     "vue": "^2.5.16"

+ 0
- 291
static/js/smoothscroll.js View File

@@ -1,291 +0,0 @@
1
-/*
2
- * smoothscroll polyfill - v0.3.4
3
- * https://iamdustan.github.io/smoothscroll
4
- * 2016 (c) Dustan Kasten, Jeremias Menichelli - MIT License
5
- */
6
-
7
-(function(w, d, undefined) {
8
-  'use strict';
9
-
10
-  /*
11
-   * aliases
12
-   * w: window global object
13
-   * d: document
14
-   * undefined: undefined
15
-   */
16
-
17
-  // polyfill
18
-  function polyfill() {
19
-    // return when scrollBehavior interface is supported
20
-    if ('scrollBehavior' in d.documentElement.style) {
21
-      return;
22
-    }
23
-
24
-    /*
25
-     * globals
26
-     */
27
-    var Element = w.HTMLElement || w.Element;
28
-    var SCROLL_TIME = 468;
29
-
30
-    /*
31
-     * object gathering original scroll methods
32
-     */
33
-    var original = {
34
-      scroll: w.scroll || w.scrollTo,
35
-      scrollBy: w.scrollBy,
36
-      scrollIntoView: Element.prototype.scrollIntoView
37
-    };
38
-
39
-    /*
40
-     * define timing method
41
-     */
42
-    var now = w.performance && w.performance.now
43
-      ? w.performance.now.bind(w.performance) : Date.now;
44
-
45
-    /**
46
-     * changes scroll position inside an element
47
-     * @method scrollElement
48
-     * @param {Number} x
49
-     * @param {Number} y
50
-     */
51
-    function scrollElement(x, y) {
52
-      this.scrollLeft = x;
53
-      this.scrollTop = y;
54
-    }
55
-
56
-    /**
57
-     * returns result of applying ease math function to a number
58
-     * @method ease
59
-     * @param {Number} k
60
-     * @returns {Number}
61
-     */
62
-    function ease(k) {
63
-      return 0.5 * (1 - Math.cos(Math.PI * k));
64
-    }
65
-
66
-    /**
67
-     * indicates if a smooth behavior should be applied
68
-     * @method shouldBailOut
69
-     * @param {Number|Object} x
70
-     * @returns {Boolean}
71
-     */
72
-    function shouldBailOut(x) {
73
-      if (typeof x !== 'object'
74
-            || x === null
75
-            || x.behavior === undefined
76
-            || x.behavior === 'auto'
77
-            || x.behavior === 'instant') {
78
-        // first arg not an object/null
79
-        // or behavior is auto, instant or undefined
80
-        return true;
81
-      }
82
-
83
-      if (typeof x === 'object'
84
-            && x.behavior === 'smooth') {
85
-        // first argument is an object and behavior is smooth
86
-        return false;
87
-      }
88
-
89
-      // throw error when behavior is not supported
90
-      throw new TypeError('behavior not valid');
91
-    }
92
-
93
-    /**
94
-     * finds scrollable parent of an element
95
-     * @method findScrollableParent
96
-     * @param {Node} el
97
-     * @returns {Node} el
98
-     */
99
-    function findScrollableParent(el) {
100
-      var isBody;
101
-      var hasScrollableSpace;
102
-      var hasVisibleOverflow;
103
-
104
-      do {
105
-        el = el.parentNode;
106
-
107
-        // set condition variables
108
-        isBody = el === d.body;
109
-        hasScrollableSpace =
110
-          el.clientHeight < el.scrollHeight ||
111
-          el.clientWidth < el.scrollWidth;
112
-        hasVisibleOverflow =
113
-          w.getComputedStyle(el, null).overflow === 'visible';
114
-      } while (!isBody && !(hasScrollableSpace && !hasVisibleOverflow));
115
-
116
-      isBody = hasScrollableSpace = hasVisibleOverflow = null;
117
-
118
-      return el;
119
-    }
120
-
121
-    /**
122
-     * self invoked function that, given a context, steps through scrolling
123
-     * @method step
124
-     * @param {Object} context
125
-     */
126
-    function step(context) {
127
-      // call method again on next available frame
128
-      context.frame = w.requestAnimationFrame(step.bind(w, context));
129
-
130
-      var time = now();
131
-      var value;
132
-      var currentX;
133
-      var currentY;
134
-      var elapsed = (time - context.startTime) / SCROLL_TIME;
135
-
136
-      // avoid elapsed times higher than one
137
-      elapsed = elapsed > 1 ? 1 : elapsed;
138
-
139
-      // apply easing to elapsed time
140
-      value = ease(elapsed);
141
-
142
-      currentX = context.startX + (context.x - context.startX) * value;
143
-      currentY = context.startY + (context.y - context.startY) * value;
144
-
145
-      context.method.call(context.scrollable, currentX, currentY);
146
-
147
-      // return when end points have been reached
148
-      if (currentX === context.x && currentY === context.y) {
149
-        w.cancelAnimationFrame(context.frame);
150
-        return;
151
-      }
152
-    }
153
-
154
-    /**
155
-     * scrolls window with a smooth behavior
156
-     * @method smoothScroll
157
-     * @param {Object|Node} el
158
-     * @param {Number} x
159
-     * @param {Number} y
160
-     */
161
-    function smoothScroll(el, x, y) {
162
-      var scrollable;
163
-      var startX;
164
-      var startY;
165
-      var method;
166
-      var startTime = now();
167
-      var frame;
168
-
169
-      // define scroll context
170
-      if (el === d.body) {
171
-        scrollable = w;
172
-        startX = w.scrollX || w.pageXOffset;
173
-        startY = w.scrollY || w.pageYOffset;
174
-        method = original.scroll;
175
-      } else {
176
-        scrollable = el;
177
-        startX = el.scrollLeft;
178
-        startY = el.scrollTop;
179
-        method = scrollElement;
180
-      }
181
-
182
-      // cancel frame when a scroll event's happening
183
-      if (frame) {
184
-        w.cancelAnimationFrame(frame);
185
-      }
186
-
187
-      // scroll looping over a frame
188
-      step({
189
-        scrollable: scrollable,
190
-        method: method,
191
-        startTime: startTime,
192
-        startX: startX,
193
-        startY: startY,
194
-        x: x,
195
-        y: y,
196
-        frame: frame
197
-      });
198
-    }
199
-
200
-    /*
201
-     * ORIGINAL METHODS OVERRIDES
202
-     */
203
-
204
-    // w.scroll and w.scrollTo
205
-    w.scroll = w.scrollTo = function() {
206
-      // avoid smooth behavior if not required
207
-      if (shouldBailOut(arguments[0])) {
208
-        original.scroll.call(
209
-          w,
210
-          arguments[0].left || arguments[0],
211
-          arguments[0].top || arguments[1]
212
-        );
213
-        return;
214
-      }
215
-
216
-      // LET THE SMOOTHNESS BEGIN!
217
-      smoothScroll.call(
218
-        w,
219
-        d.body,
220
-        ~~arguments[0].left,
221
-        ~~arguments[0].top
222
-      );
223
-    };
224
-
225
-    // w.scrollBy
226
-    w.scrollBy = function() {
227
-      // avoid smooth behavior if not required
228
-      if (shouldBailOut(arguments[0])) {
229
-        original.scrollBy.call(
230
-          w,
231
-          arguments[0].left || arguments[0],
232
-          arguments[0].top || arguments[1]
233
-        );
234
-        return;
235
-      }
236
-
237
-      // LET THE SMOOTHNESS BEGIN!
238
-      smoothScroll.call(
239
-        w,
240
-        d.body,
241
-        ~~arguments[0].left + (w.scrollX || w.pageXOffset),
242
-        ~~arguments[0].top + (w.scrollY || w.pageYOffset)
243
-      );
244
-    };
245
-
246
-    // Element.prototype.scrollIntoView
247
-    Element.prototype.scrollIntoView = function() {
248
-      // avoid smooth behavior if not required
249
-      if (shouldBailOut(arguments[0])) {
250
-        original.scrollIntoView.call(this, arguments[0] || true);
251
-        return;
252
-      }
253
-
254
-      // LET THE SMOOTHNESS BEGIN!
255
-      var scrollableParent = findScrollableParent(this);
256
-      var parentRects = scrollableParent.getBoundingClientRect();
257
-      var clientRects = this.getBoundingClientRect();
258
-
259
-      if (scrollableParent !== d.body) {
260
-        // reveal element inside parent
261
-        smoothScroll.call(
262
-          this,
263
-          scrollableParent,
264
-          scrollableParent.scrollLeft + clientRects.left - parentRects.left,
265
-          scrollableParent.scrollTop + clientRects.top - parentRects.top
266
-        );
267
-        // reveal parent in viewport
268
-        w.scrollBy({
269
-          left: parentRects.left,
270
-          top: parentRects.top,
271
-          behavior: 'smooth'
272
-        });
273
-      } else {
274
-        // reveal element in viewport
275
-        w.scrollBy({
276
-          left: clientRects.left,
277
-          top: clientRects.top,
278
-          behavior: 'smooth'
279
-        });
280
-      }
281
-    };
282
-  }
283
-
284
-  if (typeof exports === 'object') {
285
-    // commonjs
286
-    module.exports = { polyfill: polyfill };
287
-  } else {
288
-    // global
289
-    polyfill();
290
-  }
291
-})(window, document);

Loading…
Cancel
Save