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

github.com/WingLim/hugo-tania.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWingLim <643089849@qq.com>2021-07-05 15:56:38 +0300
committerGitHub <noreply@github.com>2021-07-05 15:56:38 +0300
commit5618eca561d8d5a8230b50f7f90c41bc2453d76e (patch)
tree5dee9892fc1cb3f3b3282c6b67a894b2a13ae8c7
parent0f7d522ceac50cbfd31e189497c6c4ec007c1eeb (diff)
refactor: rewrite script (#24)v1.6.0
* docs: add thanks * refactor: rewrite footnotes * refactor: rewrite search * chore: rename to el
-rw-r--r--README.md4
-rw-r--r--assets/ts/features.ts72
-rw-r--r--assets/ts/footnotes.ts56
-rw-r--r--assets/ts/search.ts285
-rw-r--r--layouts/_default/archives.html2
5 files changed, 216 insertions, 203 deletions
diff --git a/README.md b/README.md
index 75b81b1..2f39bd4 100644
--- a/README.md
+++ b/README.md
@@ -149,8 +149,8 @@ Some content...
```
## Thanks to
-- [你好黑暗,我的老朋友 —— 为网站添加用户友好的深色模式支持](https://blog.skk.moe/post/hello-darkmode-my-old-friend/)
-- [Footnotes, citations, and sidenotes](https://prose.yihui.org/about/#footnotes-citations-and-sidenotes)
+- [hugo-theme-stack](https://github.com/CaiJimmy/hugo-theme-stack) for dark mode switch
+- [hugo-prose](https://github.com/yihui/hugo-prose) for float footnotes
## License
diff --git a/assets/ts/features.ts b/assets/ts/features.ts
index 417c169..cfe676d 100644
--- a/assets/ts/features.ts
+++ b/assets/ts/features.ts
@@ -1,74 +1,16 @@
import ThemeColorScheme from "ts/colorScheme";
+import { renderFootnotes } from "ts/footnotes"
-(function (d) {
- let enableFootnotes = false
- if (d.currentScript) {
- enableFootnotes = d.currentScript.dataset['enableFootnotes'] == 'true'
- }
- let renderFootnotes = function () {
- const removeEl = (el: Element) => {
- if (!el) return;
- el.remove ? el.remove() : el.parentNode.removeChild(el);
- };
-
- const insertAfter = (target: HTMLElement, sib: Element) => {
- target.after ? target.after(sib) : (
- target.parentNode.insertBefore(sib, target.nextSibling)
- );
- };
-
- const insideOut = (el: Element) => {
- var p = el.parentNode as HTMLElement,
- x = el.innerHTML,
- c = document.createElement('div'); // a tmp container
- insertAfter(p, c);
- c.appendChild(el);
- el.innerHTML = '';
- el.appendChild(p);
- p.innerHTML = x; // let the original parent have the content of its child
- insertAfter(c, c.firstElementChild);
- removeEl(c);
- };
+let enableFootnotes = false
+if (document.currentScript) {
+ enableFootnotes = document.currentScript.dataset.enableFootnotes == 'true'
+}
- document.querySelectorAll('.footnotes > ol > li[id^="fn"], #refs > div[id^="ref-"]').forEach(function (fn) {
- let a = document.querySelectorAll('a[href="#' + fn.id + '"]');
- if (a.length === 0) return;
- a.forEach(function (el) { el.removeAttribute('href') });
- let newA = a[0] as HTMLElement;
- let side = document.createElement('div');
- side.className = 'side side-right';
- if (/^fn/.test(fn.id)) {
- side.innerHTML = fn.innerHTML;
- var number = newA.innerHTML; // footnote number
- side.firstElementChild.innerHTML = '<span class="bg-number">' + number +
- '</span> ' + side.firstElementChild.innerHTML;
- removeEl(side.querySelector('a[href^="#fnref"]')); // remove backreference
- let newAParent = newA.parentNode as HTMLElement
- newAParent.tagName === 'SUP' && insideOut(newA);
- } else {
- side.innerHTML = fn.outerHTML;
- newA = newA.parentNode as HTMLElement;
- }
- insertAfter(newA, side);
- newA.classList.add('note-ref');
- removeEl(fn);
- })
- document.querySelectorAll('.footnotes, #refs').forEach(function (fn) {
- var items = fn.children;
- if (fn.id === 'refs') return items.length === 0 && removeEl(fn);
- // there must be a <hr> and an <ol> left
- if (items.length !== 2 || items[0].tagName !== 'HR' || items[1].tagName !== 'OL') return;
- items[1].childElementCount === 0 && removeEl(fn);
- });
- };
+const init = () => {
+ new ThemeColorScheme(document.getElementById('dark-mode-button'))
if (enableFootnotes) {
renderFootnotes()
}
-})(document);
-
-
-const init = () => {
- new ThemeColorScheme(document.getElementById('dark-mode-button'))
}
window.addEventListener('load', () => {
diff --git a/assets/ts/footnotes.ts b/assets/ts/footnotes.ts
new file mode 100644
index 0000000..889c2be
--- /dev/null
+++ b/assets/ts/footnotes.ts
@@ -0,0 +1,56 @@
+const removeEl = (el: Element) => {
+ if (!el) return;
+ el.remove ? el.remove() : el.parentNode.removeChild(el);
+};
+
+const insertAfter = (target: HTMLElement, sib: Element) => {
+ target.after ? target.after(sib) : (
+ target.parentNode.insertBefore(sib, target.nextSibling)
+ );
+};
+
+const insideOut = (el: Element) => {
+ var p = el.parentNode as HTMLElement,
+ x = el.innerHTML,
+ c = document.createElement('div'); // a tmp container
+ insertAfter(p, c);
+ c.appendChild(el);
+ el.innerHTML = '';
+ el.appendChild(p);
+ p.innerHTML = x; // let the original parent have the content of its child
+ insertAfter(c, c.firstElementChild);
+ removeEl(c);
+};
+
+export let renderFootnotes = function () {
+ document.querySelectorAll('.footnotes > ol > li[id^="fn"], #refs > div[id^="ref-"]').forEach(function (fn) {
+ let a = document.querySelectorAll('a[href="#' + fn.id + '"]');
+ if (a.length === 0) return;
+ a.forEach(function (el) { el.removeAttribute('href') });
+ let newA = a[0] as HTMLElement;
+ let side = document.createElement('div');
+ side.className = 'side side-right';
+ if (/^fn/.test(fn.id)) {
+ side.innerHTML = fn.innerHTML;
+ var number = newA.innerHTML; // footnote number
+ side.firstElementChild.innerHTML = '<span class="bg-number">' + number +
+ '</span> ' + side.firstElementChild.innerHTML;
+ removeEl(side.querySelector('a[href^="#fnref"]')); // remove backreference
+ let newAParent = newA.parentNode as HTMLElement
+ newAParent.tagName === 'SUP' && insideOut(newA);
+ } else {
+ side.innerHTML = fn.outerHTML;
+ newA = newA.parentNode as HTMLElement;
+ }
+ insertAfter(newA, side);
+ newA.classList.add('note-ref');
+ removeEl(fn);
+ })
+ document.querySelectorAll('.footnotes, #refs').forEach(function (fn) {
+ var items = fn.children;
+ if (fn.id === 'refs') return items.length === 0 && removeEl(fn);
+ // there must be a <hr> and an <ol> left
+ if (items.length !== 2 || items[0].tagName !== 'HR' || items[1].tagName !== 'OL') return;
+ items[1].childElementCount === 0 && removeEl(fn);
+ });
+};
diff --git a/assets/ts/search.ts b/assets/ts/search.ts
index ef982d1..ef6c39d 100644
--- a/assets/ts/search.ts
+++ b/assets/ts/search.ts
@@ -1,153 +1,168 @@
import Fuse from '../js/fuse'
-declare global {
- interface Window {
- fuse: any;
- filterSelect: any;
- }
+interface searchItem {
+ item: {
+ categorise: Array<string>,
+ contents: string,
+ date: string,
+ permalink: string,
+ tags: Array<string>,
+ title: string
+ },
+ refIndex: number
}
-let show = function (elem: HTMLElement) {
- elem.style.display = 'block';
+const show = function (el: HTMLElement) {
+ el.style.display = 'block';
};
-let hide = function (elem: HTMLElement) {
- elem.style.display = 'none';
+const hide = function (el: HTMLElement) {
+ el.style.display = 'none';
};
-let initFuse = function () {
- const fuseOptions = {
- shouldSort: true,
- threshold: 0.3,
- location: 0,
- distance: 100,
- maxPatternLength: 32,
- minMatchCharLength: 1,
- useExtendedSearch: true,
- keys: [
- { name: "title", weight: 0.8 },
- { name: "contents", weight: 0.5 },
- { name: "tags", weight: 0.3 },
- { name: "categories", weight: 0.3 }
- ]
- };
+class Search {
+ private searchInput = document.getElementById('search-query') as HTMLInputElement;
+ private searchResults = document.getElementById('search-results');
+ private articlesList = document.getElementById('articles-list');
+ private filterItems = document.getElementsByClassName('filter-item') as HTMLCollectionOf<HTMLElement>;
+ private searchFilter = new Map();
+ private fuse: any
- fetch('/index.json')
- .then(function (response) {
- if (response.status !== 200) {
- console.error('[' + response.status + ']Error:', response.statusText);
- return;
- }
- response.json().then(function (pages) {
- let fuse = new Fuse(pages, fuseOptions);
- window.fuse = fuse;
- })
-
- })
- .catch(function (err) {
- console.error('[Fetch]Error:', err);
- });
-}
-initFuse();
+ constructor() {
+ this.initFuse()
+ this.bindInput()
+ this.bindFilters()
+ }
-const searchInput = document.getElementById('search-query') as HTMLInputElement;
-const searchResults = document.getElementById('search-results');
-const articlesList = document.getElementById('articles-list');
-if (searchInput != undefined) {
- searchInput.addEventListener("input", function () {
- let value = searchInput.value;
- executeSearch(buildSearchValue(value));
- })
-}
+ private initFuse() {
+ const fuseOptions = {
+ shouldSort: true,
+ threshold: 0.3,
+ location: 0,
+ distance: 100,
+ maxPatternLength: 32,
+ minMatchCharLength: 1,
+ useExtendedSearch: true,
+ keys: [
+ { name: "title", weight: 0.8 },
+ { name: "contents", weight: 0.5 },
+ { name: "tags", weight: 0.3 },
+ { name: "categories", weight: 0.3 }
+ ]
+ };
+ fetch('/index.json')
+ .then((response) => {
+ if (response.status !== 200) {
+ console.error('[' + response.status + ']Error:', response.statusText);
+ return;
+ }
+ return response.json()
+ })
+ .then((pages) => {
+ let fuse = new Fuse(pages, fuseOptions)
+ this.fuse = fuse
+ })
+ .catch(function (err) {
+ console.error('[Fetch]Error:', err);
+ });
+ }
-let searchFilter = new Map();
-let buildSearchValue = function(value: string) {
- let filter = [];
- if (searchFilter.size == 0 && value.length == 0) {
- return "";
- }
- searchFilter.forEach((v: string, k: string) => {
- let object = {};
- if (v == "categories") {
- object = {
- categories: k
- }
- }
- filter.push(object);
- })
- if (value != undefined && value.length != 0) {
- let orObject = {
- $or: [
- {title: value},
- // fuse extended search, 'value is include-match
- // more details: https://fusejs.io/examples.html#extended-search
- {contents: "'"+value}
- ]
- }
- filter.push(orObject);
- }
- return {
- $and: filter
- }
-}
+ private bindInput() {
+ this.searchInput.addEventListener("input", () => {
+ let value = this.searchInput.value;
+ this.executeSearch(this.buildSearchValue(value));
+ })
+ }
-let filterSelect = function(element: HTMLElement) {
- let value = element.dataset.value;
- let type = element.dataset.type;
- if (element.classList.contains('active')) {
- searchFilter.delete(value);
- element.classList.remove('active');
- } else {
- searchFilter.set(value, type);
- element.classList.add('active');
- }
- executeSearch(buildSearchValue(""));
-}
-window.filterSelect = filterSelect;
+ private bindFilters() {
+ Array.from(this.filterItems).forEach((el) => {
+ el.addEventListener('click', () => {
+ this.filterSelect(el)
+ })
+ })
+ }
-let executeSearch = function(value: string|object) {
- if ((typeof value === "string" && value.length != 0) || typeof value === "object") {
- hide(articlesList);
- show(searchResults);
- } else {
- hide(searchResults);
- show(articlesList);
- }
+ private executeSearch(value: string | object) {
+ if ((typeof value === "string" && value.length != 0) || typeof value === "object") {
+ hide(this.articlesList);
+ show(this.searchResults);
+ } else {
+ hide(this.searchResults);
+ show(this.articlesList);
+ }
- let result = window.fuse.search(value);
- if (result.length > 0) {
- populateResults(result);
- } else {
- searchResults.innerHTML = '<p>Sorry, nothing matched that search.</p>';
- }
+ let result = this.fuse.search(value);
+ if (result.length > 0) {
+ this.populateResults(result);
+ } else {
+ this.searchResults.innerHTML = '<p>Sorry, nothing matched that search.</p>';
+ }
+ }
- interface searchItem {
- item: {
- categorise: Array<string>,
- contents: string,
- date: string,
- permalink: string,
- tags: Array<string>,
- title: string
- },
- refIndex: number
- }
+ private populateResults(results: Array<searchItem>) {
+ this.searchResults.innerHTML = "";
+
+ results.forEach((value) => {
+ let item = value.item
+ let html = `
+ <div class="post">
+ <a href="${item.permalink}">
+ <div class="post-row">
+ <time>${item.date}</time>
+ <h3>${item.title}</h3>
+ </div>
+ </a>
+ </div>`
+ this.searchResults.innerHTML += html;
+ });
+ }
- function populateResults(results: Array<searchItem>) {
- searchResults.innerHTML = "";
+ private buildSearchValue = function (value: string) {
+ let filter = [];
+ if (this.searchFilter.size == 0 && value.length == 0) {
+ return "";
+ }
+ this.searchFilter.forEach((v: string, k: string) => {
+ let object = {};
+ if (v == "categories") {
+ object = {
+ categories: k
+ }
+ }
+ filter.push(object);
+ })
+ if (value != undefined && value.length != 0) {
+ let orObject = {
+ $or: [
+ { title: value },
+ // fuse extended search, 'value is include-match
+ // more details: https://fusejs.io/examples.html#extended-search
+ { contents: "'" + value }
+ ]
+ }
+ filter.push(orObject);
+ }
+ return {
+ $and: filter
+ }
+ }
- results.forEach(function (value) {
- let item = value.item
- let html = `
- <div class="post">
- <a href="${item.permalink}">
- <div class="post-row">
- <time>${item.date}</time>
- <h3>${item.title}</h3>
- </div>
- </a>
- </div>`
- searchResults.innerHTML += html;
- });
- }
+ private filterSelect(el: HTMLElement) {
+ let value = el.dataset.value;
+ let type = el.dataset.type;
+ if (el.classList.contains('active')) {
+ this.searchFilter.delete(value);
+ el.classList.remove('active');
+ } else {
+ this.searchFilter.set(value, type);
+ el.classList.add('active');
+ }
+ this.executeSearch(this.buildSearchValue(""));
+ }
}
+
+window.addEventListener('load', () => {
+ setTimeout(function () {
+ new Search()
+ }, 0)
+})
diff --git a/layouts/_default/archives.html b/layouts/_default/archives.html
index 60d2749..d9e0cda 100644
--- a/layouts/_default/archives.html
+++ b/layouts/_default/archives.html
@@ -14,7 +14,7 @@
<div class="filter-container">
{{ $maxCategoryToShow := $.Site.Params.maxCategoryToShow | default 5 }}
{{ range .Site.Taxonomies.categories.TaxonomyArray | first $maxCategoryToShow }}
- <div class="filter-item" data-value="{{ .Page.Title }}" data-type="categories" onclick="filterSelect(this)">
+ <div class="filter-item" data-value="{{ .Page.Title }}" data-type="categories">
{{ .Page.Title }}<sup>{{ .Count }}</sup>
</div>
{{ end }}