aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrtz12 <koenig@fagott.pw>2016-01-25 19:01:15 (UTC)
committerrtz12 <koenig@fagott.pw>2016-01-25 19:01:15 (UTC)
commitd4b2422fd753df71be58d1a499194849b6e6d438 (patch)
treeac1b4eec67f6b83a955a82878b81ba2a1148fb0c
parenteaaa1ac2e509bf9df04aec24daa7286ab31089a9 (diff)
JavaScript Kram auf Hippe ES6 Kacke umgebaut
-rw-r--r--.babelrc6
-rw-r--r--assets_src/js/lib/ajax.js60
-rw-r--r--assets_src/js/lib/dom.js14
-rw-r--r--assets_src/js/lib/search.js77
-rw-r--r--assets_src/js/list.js42
-rw-r--r--package.json.tpl3
-rw-r--r--views/includes/instant_search_results.html4
-rw-r--r--views/pages/list.html5
8 files changed, 157 insertions, 54 deletions
diff --git a/.babelrc b/.babelrc
index 7b37dd5..fc3d89c 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,3 +1,7 @@
1{ 1{
2 "presets": ["es2015"] 2 "presets": ["es2015"],
3 "plugins": [
4 "syntax-async-functions",
5 "transform-regenerator"
6 ]
3} 7}
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 @@
1export 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
13function 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
20function 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
33function 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
54export async function get(url, options) {
55 return request('GET', url, null, options);
56}
57
58export 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 @@
1export function ready(fn) {
2 document.addEventListener('DOMContentLoaded', (e) => {
3 fn();
4 }, false);
5}
6
7export 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 @@
1var strokeTimeout = null; 1import * as dom from './dom';
2import * as ajax from './ajax';
2 3
3function instantSearch() { 4export 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 => {
10function 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
38function clickSearchResult(resId) {
39
40} \ No newline at end of file
diff --git a/assets_src/js/list.js b/assets_src/js/list.js
index 25ff80d..413f517 100644
--- a/assets_src/js/list.js
+++ b/assets_src/js/list.js
@@ -1,17 +1,29 @@
1function clickSearchResult(resId) { 1import 'babel-polyfill';
2 var xhr = new XMLHttpRequest(); 2import * as search from './lib/search';
3 xhr.onreadystatechange = function() { 3import * as dom from './lib/dom';
4 if (xhr.readyState == XMLHttpRequest.DONE) { 4import * as ajax from './lib/ajax';
5 if (xhr.status !== 200) {
6 alert(xhr.status + ": " + xhr.response);
7 return;
8 }
9 5
10 data = xhr.responseText; 6async function resultClicked(grilId) {
11 document.getElementById("gril-list").innerHTML += data; 7 let response = null;
12 } 8 try {
9 response = await ajax.post(
10 window.location,
11 'id=' + grilId,
12 { headers: {
13 'Content-type': 'application/x-www-form-urlencoded'
14 } });
15 } catch (e) {
16 alert(e.message);
17 return;
13 } 18 }
14 xhr.open('POST', window.location, true); 19 document.getElementById('gril-list').innerHTML += response;
15 xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); 20}
16 xhr.send('id=' + resId); 21
17} \ No newline at end of file 22function main() {
23 let is = new search.InstantSearch(
24 document.getElementById('gril-add-search'),
25 document.getElementById('search-results'));
26 is.resultClicked = resultClicked;
27}
28
29dom.ready(main);
diff --git a/package.json.tpl b/package.json.tpl
index c2d075b..8d0bb1a 100644
--- a/package.json.tpl
+++ b/package.json.tpl
@@ -3,7 +3,10 @@
3 "version": "%($VERSION%)", 3 "version": "%($VERSION%)",
4 "devDependencies": { 4 "devDependencies": {
5 "less": "2.5.3", 5 "less": "2.5.3",
6 "babel-polyfill": "6.3.14",
6 "babel-preset-es2015": "6.3.13", 7 "babel-preset-es2015": "6.3.13",
8 "babel-plugin-syntax-async-functions": "6.3.13",
9 "babel-plugin-transform-regenerator": "6.4.4",
7 "browserify": "13.0.0", 10 "browserify": "13.0.0",
8 "babelify": "7.2.0" 11 "babelify": "7.2.0"
9 } 12 }
diff --git a/views/includes/instant_search_results.html b/views/includes/instant_search_results.html
index 0dd445c..acdbb30 100644
--- a/views/includes/instant_search_results.html
+++ b/views/includes/instant_search_results.html
@@ -1,8 +1,8 @@
1{{ define "instant_search_results" }} 1{{ define "instant_search_results" }}
2{{ range .results }} 2{{ range .results }}
3<li class="collection-item search-result avatar hoverable valign-wrapper" onClick="clickSearchResult({{ .ID }})" > 3<li class="collection-item search-result avatar hoverable valign-wrapper" data-id="{{ .ID }}">
4 <img src="/{{ .ImagePath }}" alt="" class="circle"> 4 <img src="/{{ .ImagePath }}" alt="" class="circle">
5 <span class="title valign">{ {{ .Name }} }</span> 5 <span class="title valign">{ {{ .Name }} }</span>
6</li> 6</li>
7{{ end }} 7{{ end }}
8{{ end }} \ No newline at end of file 8{{ end }}
diff --git a/views/pages/list.html b/views/pages/list.html
index c85e147..c608b77 100644
--- a/views/pages/list.html
+++ b/views/pages/list.html
@@ -7,7 +7,6 @@
7 <title>grilist</title> 7 <title>grilist</title>
8 <link rel="stylesheet" href="/assets/css/list.css" /> 8 <link rel="stylesheet" href="/assets/css/list.css" />
9 <link rel="stylesheet" href="/assets/css/search.css" /> 9 <link rel="stylesheet" href="/assets/css/search.css" />
10 <script src="/assets/js/search.js"></script>
11 <script src="/assets/js/list.js"></script> 10 <script src="/assets/js/list.js"></script>
12 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"> 11 <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
13 </head> 12 </head>
@@ -35,8 +34,8 @@
35 <span style="font-size: 130%">Gril hinzufügen</span><br /> 34 <span style="font-size: 130%">Gril hinzufügen</span><br />
36 <form> 35 <form>
37 <div class="input-field"> 36 <div class="input-field">
38 <input id="search" type="search" onKeyDown="instantSearch()" required> 37 <input id="gril-add-search" class="gril-search" type="search" required>
39 <label for="search"><i class="material-icons">search</i></label> 38 <label for="gril-add-search"><i class="material-icons">search</i></label>
40 <i class="material-icons">close</i> 39 <i class="material-icons">close</i>
41 </div> 40 </div>
42 </form> 41 </form>