Initial AD port
This commit is contained in:
20
themes/after-dark/assets/js/baseof.js
Normal file
20
themes/after-dark/assets/js/baseof.js
Normal file
@@ -0,0 +1,20 @@
|
||||
/*!
|
||||
* Copyright (C) 2019 Josh Habdas <jhabdas@protonmail.com>
|
||||
*
|
||||
* This file is part of After Dark.
|
||||
*
|
||||
* After Dark is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* After Dark is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
fetchInject(["{{ "/js/lazysizes.min.js" | relURL }}"]);
|
||||
145
themes/after-dark/assets/js/search.js
Normal file
145
themes/after-dark/assets/js/search.js
Normal file
@@ -0,0 +1,145 @@
|
||||
/*!
|
||||
* Copyright (C) 2019 Josh Habdas <jhabdas@protonmail.com>
|
||||
*
|
||||
* This file is part of After Dark.
|
||||
*
|
||||
* After Dark is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published
|
||||
* by the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* After Dark is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
fetchInject([
|
||||
"{{ "/js/vue.min.js" | relURL }}",
|
||||
"{{ "/js/lodash.custom.min.js" | relURL }}",
|
||||
"{{ "/js/fuse.min.js" | relURL }}",
|
||||
"{{ "/js/mark.min.js" | relURL }}"
|
||||
]).then(() => {
|
||||
(function (window, document, undefined) {
|
||||
'use strict';
|
||||
|
||||
const getQueryByParam = param => decodeURIComponent(
|
||||
(location.search.split(param + '=')[1] || '').split('&')[0]
|
||||
).replace(/\+/g, ' ');
|
||||
|
||||
const queryParam = 's';
|
||||
const hotkeys = {{ (.Params.form.hotkeys | default (slice "/" "s")) | jsonify }};
|
||||
const selectors = {
|
||||
appContainer: '#search-app',
|
||||
resultContainer: '#search-results',
|
||||
searchInput: '#query'
|
||||
};
|
||||
|
||||
const fuseOpts = {
|
||||
shouldSort: true,
|
||||
tokenize: true,
|
||||
matchAllTokens: true,
|
||||
includeScore: true,
|
||||
includeMatches: true,
|
||||
keys: [
|
||||
{ name: "title", weight: 0.8 },
|
||||
{ name: "contents", weight: 0.5 },
|
||||
{ name: "tags", weight: 0.3 },
|
||||
{ name: "categories", weight: 0.3 }
|
||||
]
|
||||
};
|
||||
|
||||
const getSearchInput = () => document.querySelector(selectors.searchInput);
|
||||
const focusSearchInput = () => getSearchInput().focus();
|
||||
const searchQuery = getSearchInput().value = getQueryByParam(queryParam);
|
||||
|
||||
const fuse = new Fuse([], fuseOpts);
|
||||
window.fetch('/index.json').then(response => {
|
||||
response.text().then(searchData => {
|
||||
fuse.setCollection(JSON.parse(searchData));
|
||||
searchQuery && search(searchQuery);
|
||||
});
|
||||
});
|
||||
|
||||
const getUrl = (query) => {
|
||||
const encodedQuery = encodeURIComponent(query);
|
||||
const url = "{{ .RelPermalink }}";
|
||||
return (encodedQuery)
|
||||
? `${url}?${queryParam}=${encodedQuery}`
|
||||
: url;
|
||||
};
|
||||
|
||||
let mark = new Mark(
|
||||
document.querySelector(
|
||||
selectors.resultContainer
|
||||
)
|
||||
);
|
||||
|
||||
const app = new Vue({
|
||||
delimiters: ['{', '}'],
|
||||
el: selectors.appContainer,
|
||||
data: {
|
||||
fuse: null,
|
||||
results: [],
|
||||
query: getQueryByParam(queryParam),
|
||||
resultsForSearch: getQueryByParam(queryParam)
|
||||
},
|
||||
mounted () {
|
||||
this.fuse = fuse;
|
||||
window.onpopstate = (evt) => {
|
||||
this.query = evt.state.query;
|
||||
};
|
||||
const searchInput = getSearchInput();
|
||||
document.onkeydown = function (evt) {
|
||||
if (evt.target === searchInput) return;
|
||||
if (hotkeys.includes(evt.key)) {
|
||||
evt.preventDefault();
|
||||
focusSearchInput();
|
||||
getSearchInput().select();
|
||||
};
|
||||
}
|
||||
focusSearchInput();
|
||||
},
|
||||
watch: {
|
||||
query () {
|
||||
this.executeSearch();
|
||||
window.history.replaceState(
|
||||
{query: this.query},
|
||||
null,
|
||||
getUrl(this.query)
|
||||
);
|
||||
}
|
||||
},
|
||||
beforeUpdate: function () {
|
||||
mark.unmark();
|
||||
},
|
||||
updated: function () {
|
||||
this.$nextTick(function () {
|
||||
mark = new Mark(
|
||||
document.querySelector(
|
||||
selectors.resultContainer
|
||||
)
|
||||
)
|
||||
mark.mark(this.query.trim());
|
||||
})
|
||||
},
|
||||
methods: {
|
||||
executeSearch: _.debounce(function () {
|
||||
const trimmedQuery = this.query.trim();
|
||||
this.resultsForSearch = trimmedQuery;
|
||||
this.results = (trimmedQuery)
|
||||
? this.fuse.search(trimmedQuery)
|
||||
: [];
|
||||
}, 250)
|
||||
}
|
||||
});
|
||||
|
||||
const search = query => {
|
||||
app.results = fuse.search(query);
|
||||
};
|
||||
|
||||
})(window, document);
|
||||
});
|
||||
2
themes/after-dark/assets/js/vendor/fetch-inject.min.js
vendored
Normal file
2
themes/after-dark/assets/js/vendor/fetch-inject.min.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/*! Fetch Inject v2.0.4 | Copyright (C) Josh Habdas <jhabdas@protonmail.com> (https://habd.as) | @license Zlib */
|
||||
var fetchInject=function(){"use strict";const e=function(e,t,r,n,o,c,i){c=t.createElement(r),i=t.getElementsByTagName(r)[0],c.appendChild(t.createTextNode(n.text)),c.onload=o(n),i?i.parentNode.insertBefore(c,i):t.head.appendChild(c)};return function(t,r){if(!arguments.length)return Promise.reject(new ReferenceError("Failed to execute 'fetchInject': 1 argument required but only 0 present."));if(arguments[0]&&arguments[0].constructor!==Array)return Promise.reject(new TypeError("Failed to execute 'fetchInject': argument 1 must be of type 'Array'."));if(arguments[1]&&arguments[1].constructor!==Promise)return Promise.reject(new TypeError("Failed to execute 'fetchInject': argument 2 must be of type 'Promise'."));const n=[],o=r?[].concat(r):[],c=[];return t.forEach(e=>o.push(window.fetch(e).then(e=>[e.clone().text(),e.blob()]).then(e=>Promise.all(e).then(e=>{n.push({text:e[0],blob:e[1]})})))),Promise.all(o).then(()=>(n.forEach(t=>{c.push({then:r=>{t.blob.type.includes("text/css")?e(window,document,"style",t,r):e(window,document,"script",t,r)}})}),Promise.all(c)))}}();
|
||||
Reference in New Issue
Block a user