diff options
Diffstat (limited to 'assets_src/js/lib')
| -rw-r--r-- | assets_src/js/lib/ajax.js | 60 | ||||
| -rw-r--r-- | assets_src/js/lib/dom.js | 14 | ||||
| -rw-r--r-- | assets_src/js/lib/search.js | 77 | 
3 files changed, 118 insertions, 33 deletions
diff --git a/assets_src/js/lib/ajax.js b/assets_src/js/lib/ajax.js new file mode 100644 index 0000000..048f516 --- /dev/null +++ b/assets_src/js/lib/ajax.js  | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | export class AjaxError extends Error { | ||
| 2 | constructor(status, statusText) { | ||
| 3 | let message = `${status}: ${statusText}` | ||
| 4 | super(message); | ||
| 5 | this.name = this.constructor.name; | ||
| 6 | this.message = message; | ||
| 7 | this.status = status; | ||
| 8 | this.statusText = statusText; | ||
| 9 | Error.captureStackTrace(this, this.constructor.name) | ||
| 10 | } | ||
| 11 | } | ||
| 12 | |||
| 13 | function applyOptions(xhr, options) { | ||
| 14 | options.headers = options.headers || []; | ||
| 15 | for (let header in options.headers) { | ||
| 16 | xhr.setRequestHeader(header, options.headers[header]); | ||
| 17 | } | ||
| 18 | } | ||
| 19 | |||
| 20 | function createHandler(xhr, success, fail) { | ||
| 21 | return () => { | ||
| 22 | if (xhr.readyState !== XMLHttpRequest.DONE) { | ||
| 23 | return; | ||
| 24 | } | ||
| 25 | if (xhr.status === 200) { | ||
| 26 | success(xhr.response); | ||
| 27 | } else { | ||
| 28 | fail(xhr.status, xhr.statusText); | ||
| 29 | } | ||
| 30 | }; | ||
| 31 | } | ||
| 32 | |||
| 33 | function request(method, url, body, options) { | ||
| 34 | options = options || {}; | ||
| 35 | return new Promise((resolve, reject) => { | ||
| 36 | let xhr = new XMLHttpRequest(); | ||
| 37 | xhr.onreadystatechange = createHandler( | ||
| 38 | xhr, | ||
| 39 | (res) => { | ||
| 40 | resolve(res); | ||
| 41 | }, | ||
| 42 | (status, statusText) => { | ||
| 43 | reject(new AjaxError(status, statusText)); | ||
| 44 | }); | ||
| 45 | xhr.open(method, url, true); | ||
| 46 | applyOptions(xhr, options); | ||
| 47 | xhr.onerror = function() { | ||
| 48 | reject(new AjaxError(-1, 'Network error')); | ||
| 49 | }; | ||
| 50 | xhr.send(body); | ||
| 51 | }); | ||
| 52 | } | ||
| 53 | |||
| 54 | export async function get(url, options) { | ||
| 55 | return request('GET', url, null, options); | ||
| 56 | } | ||
| 57 | |||
| 58 | export async function post(url, body, options) { | ||
| 59 | return request('POST', url, body, options); | ||
| 60 | } | ||
diff --git a/assets_src/js/lib/dom.js b/assets_src/js/lib/dom.js new file mode 100644 index 0000000..33845af --- /dev/null +++ b/assets_src/js/lib/dom.js  | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | export function ready(fn) { | ||
| 2 | document.addEventListener('DOMContentLoaded', (e) => { | ||
| 3 | fn(); | ||
| 4 | }, false); | ||
| 5 | } | ||
| 6 | |||
| 7 | export function closest(el, fn) { | ||
| 8 | while (el) { | ||
| 9 | if (fn(el)) { | ||
| 10 | return el; | ||
| 11 | } | ||
| 12 | el = el.parentNode | ||
| 13 | } | ||
| 14 | } | ||
diff --git a/assets_src/js/lib/search.js b/assets_src/js/lib/search.js index 0cb33df..85559ef 100644 --- a/assets_src/js/lib/search.js +++ b/assets_src/js/lib/search.js  | |||
| @@ -1,40 +1,51 @@ | |||
| 1 | var strokeTimeout = null; | 1 | import * as dom from './dom'; | 
| 2 | import * as ajax from './ajax'; | ||
| 2 | 3 | ||
| 3 | function instantSearch() { | 4 | export class InstantSearch { | 
| 4 | if (strokeTimeout) { | 5 | constructor(element, resultsElem) { | 
| 5 | clearTimeout(strokeTimeout); | 6 | this.resultClicked = () => {}; | 
| 6 | } | 7 | this.element = element; | 
| 7 | strokeTimeout = setTimeout(doSearch, 150); | 8 | this.resultsElem = resultsElem; | 
| 8 | } | 9 | this.strokeTimeout = null; | 
| 9 | 10 | element.addEventListener('keydown', e => { | |
| 10 | function doSearch() { | 11 | if (this.strokeTimeout) { | 
| 11 | value = document.getElementById("search").value; | 12 | clearTimeout(this.strokeTimeout); | 
| 12 | |||
| 13 | if (value === "") { | ||
| 14 | strokeTimeout = null; | ||
| 15 | document.getElementById("search-results").innerHTML = ""; | ||
| 16 | return; | ||
| 17 | } | ||
| 18 | var xhr = new XMLHttpRequest(); | ||
| 19 | xhr.onreadystatechange = function() { | ||
| 20 | if (xhr.readyState == XMLHttpRequest.DONE) { | ||
| 21 | if (xhr.status === 404 || xhr.status === 400 || typeof xhr.response === 'undefined' || xhr.response === '404 not found') { | ||
| 22 | document.getElementById("search-results").innerHTML = ''; | ||
| 23 | return | ||
| 24 | } | 13 | } | 
| 25 | if (value === "") { | 14 | this.strokeTimeout = setTimeout(() => this.doSearch(), 150); | 
| 26 | document.getElementById("search-results").innerHTML = ""; | 15 | }, false); | 
| 27 | return; | 16 | resultsElem.addEventListener('click', e => { | 
| 17 | let li = dom.closest(e.target, el => el.tagName.match(/li/i)); | ||
| 18 | if (!li) { | ||
| 19 | return true; | ||
| 28 | } | 20 | } | 
| 21 | this.resultsElem.innerHTML = ''; | ||
| 22 | this.resultClicked(li.getAttribute('data-id')); | ||
| 23 | }, true); | ||
| 24 | } | ||
| 29 | 25 | ||
| 30 | document.getElementById("search-results").innerHTML = xhr.response.replace(new RegExp('{ (.*?)(' + value + ')(.*?) }', 'gi'), "$1<b>$2</b>$3").replace(new RegExp('{ (.*?) }', 'gi'), '$1'); | 26 | async doSearch() { | 
| 27 | let value = this.element.value; | ||
| 28 | if (value.length < 2) { | ||
| 29 | this.strokeTimeout = null; | ||
| 30 | this.resultsElem.innerHTML = ""; | ||
| 31 | return; | ||
| 32 | } | ||
| 33 | let response = null; | ||
| 34 | try { | ||
| 35 | response = await ajax.get(`/search/gril_instant/${value}`); | ||
| 36 | } catch (e) { | ||
| 37 | this.resultsElem.innerHTML = ''; | ||
| 38 | return; | ||
| 31 | } | 39 | } | 
| 40 | this.resultsElem.innerHTML = response | ||
| 41 | .replace( | ||
| 42 | new RegExp('{ (.*?)(' + | ||
| 43 | value + | ||
| 44 | ')(.*?) }', 'gi'), | ||
| 45 | "$1<b>$2</b>$3") | ||
| 46 | .replace( | ||
| 47 | new RegExp('{ (.*?) }', 'gi'), | ||
| 48 | '$1'); | ||
| 49 | this.strokeTimeout = null; | ||
| 32 | } | 50 | } | 
| 33 | xhr.open('GET', '/search/gril_instant/' + value, true); | ||
| 34 | xhr.send(null); | ||
| 35 | strokeTimeout = null; | ||
| 36 | } | 51 | } | 
| 37 | |||
| 38 | function clickSearchResult(resId) { | ||
| 39 | |||
| 40 | } \ No newline at end of file | ||
