diff --git a/data/favicon-16x16.png b/data/favicon-16x16.png deleted file mode 100644 index 806956c..0000000 Binary files a/data/favicon-16x16.png and /dev/null differ diff --git a/data/favicon-96x96.png b/data/favicon-96x96.png deleted file mode 100644 index f4bffd8..0000000 Binary files a/data/favicon-96x96.png and /dev/null differ diff --git a/data/index.html b/data/index.html index 5541332..51fd3b6 100644 --- a/data/index.html +++ b/data/index.html @@ -3,38 +3,9 @@ Esp8266 laserspiro controller - - - + - - - +
@@ -122,21 +93,21 @@
- some tests: -
- /motor/1/128 - /motor/2/3 - /laser/1/128 - /laser/1/13 - /laser/1/1 -
+ + + + + + + +
last uri:
last respone:
-
+

diff --git a/data/scripts.js b/data/scripts.js new file mode 100644 index 0000000..4c85a3c --- /dev/null +++ b/data/scripts.js @@ -0,0 +1,185 @@ +/** + * Poor Man's JQuery + * Lightweight DOM manipulation utility + */ +var $ = function(selector){ + + var that = this; + var element = selector.nodeType === 1 ? selector : {}; + + // utility functions + this.util = { + // build a fragment from a given html string + buildFragment: function(html){ + // set the html to a temporary element + var nodeHolder = document.createElement('div'); + nodeHolder.innerHTML = html; + // create a document fragment and append all input nodes + var fragment = document.createDocumentFragment(); + while(nodeHolder.firstChild){ + fragment.appendChild(nodeHolder.firstChild); + } + return fragment; + } + }; + // check if the input selector is already an element or a css selector + if(selector.nodeType === 1){ // is element + if(selector.is$ ? selector.is$() : false){ // check if the element is already extended + return selector; + } + element = selector; // set the element to be extended + } else { // the element is in fact a css selector + element = document.querySelector(selector); // search for the element + } + + // overload the innerHTML attribute + element.html = function(val){ + this.innerHTML = val; + return this; + }; + + // overload the value attribute + element.val = function(val){ + this.value = val; + return this; + }; + + // append the given string as child fragment + element.append = function(html){ + var fragment = that.util.buildFragment(html); + this.appendChild(fragment); + return this; + }; + + // prepend the given string as child fragment + element.prepend = function(html){ + var fragment = that.util.buildFragment(html); + this.insertBefore(fragment,this.firstChild); + return this; + }; + + // search for an element inside of an element + element.find = function(what){ + var found = $(what); + if(found){ + return $(found); + } + return; + } + + // get parent of the current element + element.parent = function(){ + if(this.parentElement){ + return $(this.parentElement); + } + } + + // indicates that this element is a $ function + element.is$ = function(){ + return true; + } + + element.on = function(event, func, useCapture) { + this.addEventListener(event, func, useCapture); + return this; + } + + return element; +};var Sui = { + ready: (callback) => { + document.addEventListener("DOMContentLoaded", function() { + callback(); + }, false); + }, + select: (selector) => { + return document.querySelectorAll(selector); + }, + link: function(node){ + return (actuator) => { + let update = function(endpoint, method, props) { + Sui.http.ajax({ + method: method, + endpoint: node.api[endpoint] + props.join('/'), + cache: false + }, actuator.onResponse || null); + }; + Sui.select(actuator.selector).forEach( (domEl) =>{ + let handle = function(event) { + data = [this.value]; + actuator.data ? data.push(actuator.data.call(this)) : undefined; + update.call(this, actuator.api, 'GET', data); + } + $(domEl).on(actuator.event, handle) + }); + }; + }, + util: { + + /** + * serialize a flat json object + */ + serialize: (obj) => { + var str = []; + for(var p in obj){ + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + } + }, + http: { + + /** + * ajax request + * { + * method: <'GET', 'POST', whatever >, + * endpoint: , + * async: , (default true) + * data: , + * cache: (default false) + * } + */ + ajax: (config, callback) => { + var cache = config.cache || false; + var data = config.data || {}; + if(!cache) { + data['_'] = new Date().getTime(); + } + var serializedData = Sui.util.serialize(data); + var endPointUrl = (config.method === 'GET' || config.method === 'DELETE') && data ? config.endpoint+'?'+serializedData : config.endpoint; + var postData = config.method === 'POST' || config.method === 'PUT' ? serializedData : null; + + var request = new XMLHttpRequest(); + request.open(config.method, endPointUrl, config.async || true); + request.onreadystatechange = function () { + // TODO handle response properly + callback ? callback(request.responseText, request.status) : undefined; + }; + request.send(postData); + } + } + };Sui.ready(() => { + let debugResponse = (data) => { + $('#response').html(data); + }; + [{ + api: 'MOTOR', + method: 'GET', + selector: '.motor.slider', + event: 'change', + data: function(){ + return this.getAttribute('data-motor-nr'); + }, + onResponse: debugResponse + }, { + api: 'LASER', + method: 'GET', + selector: '.laser.slider', + event: 'change', + onResponse: debugResponse + }].forEach(Sui.link({ + api: { + MOTOR: '/motor/', // {motorNr}/{value} + LASER: '/laser/' // {value} + } + })); +}); \ No newline at end of file diff --git a/data/styles.css b/data/styles.css index 441c022..e4f896e 100644 --- a/data/styles.css +++ b/data/styles.css @@ -1,3 +1,11 @@ +label { + width: 10%; + display: inline-block; +} +.slider { + width: 80%; + display: inline-block; +} body { font-size: 14px; font-family: "Bookman Old Style", "Serifa BT", "URW Bookman L", "itc bookman", times, serif; diff --git a/frontend/pages/favicon-16x16.png b/frontend/pages/favicon-16x16.png deleted file mode 100644 index 806956c..0000000 Binary files a/frontend/pages/favicon-16x16.png and /dev/null differ diff --git a/frontend/pages/favicon-96x96.png b/frontend/pages/favicon-96x96.png deleted file mode 100644 index f4bffd8..0000000 Binary files a/frontend/pages/favicon-96x96.png and /dev/null differ diff --git a/frontend/pages/index.html b/frontend/pages/index.html index 5541332..51fd3b6 100644 --- a/frontend/pages/index.html +++ b/frontend/pages/index.html @@ -3,38 +3,9 @@ Esp8266 laserspiro controller - - - + - - - +
@@ -122,21 +93,21 @@
- some tests: - + + + + + + + +
last uri:
last respone:
-
+

diff --git a/frontend/scripts/pmjq.js b/frontend/scripts/pmjq.js new file mode 100644 index 0000000..896d9a6 --- /dev/null +++ b/frontend/scripts/pmjq.js @@ -0,0 +1,88 @@ +/** + * Poor Man's JQuery + * Lightweight DOM manipulation utility + */ +var $ = function(selector){ + + var that = this; + var element = selector.nodeType === 1 ? selector : {}; + + // utility functions + this.util = { + // build a fragment from a given html string + buildFragment: function(html){ + // set the html to a temporary element + var nodeHolder = document.createElement('div'); + nodeHolder.innerHTML = html; + // create a document fragment and append all input nodes + var fragment = document.createDocumentFragment(); + while(nodeHolder.firstChild){ + fragment.appendChild(nodeHolder.firstChild); + } + return fragment; + } + }; + // check if the input selector is already an element or a css selector + if(selector.nodeType === 1){ // is element + if(selector.is$ ? selector.is$() : false){ // check if the element is already extended + return selector; + } + element = selector; // set the element to be extended + } else { // the element is in fact a css selector + element = document.querySelector(selector); // search for the element + } + + // overload the innerHTML attribute + element.html = function(val){ + this.innerHTML = val; + return this; + }; + + // overload the value attribute + element.val = function(val){ + this.value = val; + return this; + }; + + // append the given string as child fragment + element.append = function(html){ + var fragment = that.util.buildFragment(html); + this.appendChild(fragment); + return this; + }; + + // prepend the given string as child fragment + element.prepend = function(html){ + var fragment = that.util.buildFragment(html); + this.insertBefore(fragment,this.firstChild); + return this; + }; + + // search for an element inside of an element + element.find = function(what){ + var found = $(what); + if(found){ + return $(found); + } + return; + } + + // get parent of the current element + element.parent = function(){ + if(this.parentElement){ + return $(this.parentElement); + } + } + + // indicates that this element is a $ function + element.is$ = function(){ + return true; + } + + element.on = function(event, func, useCapture) { + this.addEventListener(event, func, useCapture); + return this; + } + + return element; +}; \ No newline at end of file diff --git a/frontend/scripts/sui.js b/frontend/scripts/sui.js new file mode 100644 index 0000000..61a69bc --- /dev/null +++ b/frontend/scripts/sui.js @@ -0,0 +1,73 @@ +var Sui = { + ready: (callback) => { + document.addEventListener("DOMContentLoaded", function() { + callback(); + }, false); + }, + select: (selector) => { + return document.querySelectorAll(selector); + }, + link: function(node){ + return (actuator) => { + let update = function(endpoint, method, props) { + Sui.http.ajax({ + method: method, + endpoint: node.api[endpoint] + props.join('/'), + cache: false + }, actuator.onResponse || null); + }; + Sui.select(actuator.selector).forEach( (domEl) =>{ + let handle = function(event) { + data = [this.value]; + actuator.data ? data.push(actuator.data.call(this)) : undefined; + update.call(this, actuator.api, 'GET', data); + } + $(domEl).on(actuator.event, handle) + }); + }; + }, + util: { + + /** + * serialize a flat json object + */ + serialize: (obj) => { + var str = []; + for(var p in obj){ + str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p])); + } + return str.join("&"); + } + }, + http: { + + /** + * ajax request + * { + * method: <'GET', 'POST', whatever >, + * endpoint: , + * async: , (default true) + * data: , + * cache: (default false) + * } + */ + ajax: (config, callback) => { + var cache = config.cache || false; + var data = config.data || {}; + if(!cache) { + data['_'] = new Date().getTime(); + } + var serializedData = Sui.util.serialize(data); + var endPointUrl = (config.method === 'GET' || config.method === 'DELETE') && data ? config.endpoint+'?'+serializedData : config.endpoint; + var postData = config.method === 'POST' || config.method === 'PUT' ? serializedData : null; + + var request = new XMLHttpRequest(); + request.open(config.method, endPointUrl, config.async || true); + request.onreadystatechange = function () { + // TODO handle response properly + callback ? callback(request.responseText, request.status) : undefined; + }; + request.send(postData); + } + } + }; \ No newline at end of file diff --git a/frontend/scripts/zMain.js b/frontend/scripts/zMain.js new file mode 100644 index 0000000..ba0f272 --- /dev/null +++ b/frontend/scripts/zMain.js @@ -0,0 +1,26 @@ +Sui.ready(() => { + let debugResponse = (data) => { + $('#response').html(data); + }; + [{ + api: 'MOTOR', + method: 'GET', + selector: '.motor.slider', + event: 'change', + data: function(){ + return this.getAttribute('data-motor-nr'); + }, + onResponse: debugResponse + }, { + api: 'LASER', + method: 'GET', + selector: '.laser.slider', + event: 'change', + onResponse: debugResponse + }].forEach(Sui.link({ + api: { + MOTOR: '/motor/', // {motorNr}/{value} + LASER: '/laser/' // {value} + } + })); +}); \ No newline at end of file diff --git a/frontend/styles/main.less b/frontend/styles/main.less index 1fcd08c..8f7d17e 100644 --- a/frontend/styles/main.less +++ b/frontend/styles/main.less @@ -1,3 +1,15 @@ + +label { + width: 10%; + display: inline-block; +} +.slider { + width: 80%; + display: inline-block; +} + + + body { font-size: 14px; font-family: "Bookman Old Style","Serifa BT","URW Bookman L","itc bookman",times,serif; diff --git a/package.json b/package.json index fba1e33..caab06a 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,12 @@ "clear": "rm -rf data/*", "cp:config": "cp config/* data/", "build:css": "lessc frontend/styles/main.less data/styles.css", + "build:js": "cat frontend/scripts/* > data/scripts.js", "build:html": "cp -r frontend/pages/* data/", - "build": "npm run build:css && npm run build:html", + "build": "npm run build:css && npm run build:html && npm run build:js", "watch:html": "nodemon -q -w frontend/pages/ --ext \".\" --exec \"npm run build:html\"", "watch:css": "nodemon -q -w frontend/styles --ext \".\" --exec \"npm run build:css\"", + "watch:js": "nodemon -q -w frontend/scripts --ext \".\" --exec \"npm run build:js\"", "watch:config": "nodemon -q -w config --ext \".\" --exec \"npm run cp:config\"", "watch:livereload": "cd data && live-server", "dev": "npm run clear && npm run build && npm-run-all --parallel watch:*"