Simple webserver to accept commands and output state
This commit is contained in:
+246
@@ -0,0 +1,246 @@
|
||||
html {
|
||||
font-family: sans-serif; /* 1 */
|
||||
-ms-text-size-adjust: 100%; /* 2 */
|
||||
-webkit-text-size-adjust: 100%; /* 2 */
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* HTML5 display definitions
|
||||
========================================================================== */
|
||||
|
||||
article,
|
||||
aside,
|
||||
details,
|
||||
figcaption,
|
||||
figure,
|
||||
footer,
|
||||
header,
|
||||
hgroup,
|
||||
main,
|
||||
menu,
|
||||
nav,
|
||||
section,
|
||||
summary {
|
||||
display: block;
|
||||
}
|
||||
|
||||
audio,
|
||||
canvas,
|
||||
progress,
|
||||
video {
|
||||
display: inline-block; /* 1 */
|
||||
vertical-align: baseline; /* 2 */
|
||||
}
|
||||
|
||||
audio:not([controls]) {
|
||||
display: none;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
[hidden],
|
||||
template {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Links
|
||||
========================================================================== */
|
||||
|
||||
a {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
a:active,
|
||||
a:hover {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
/* Text-level semantics
|
||||
========================================================================== */
|
||||
|
||||
abbr[title] {
|
||||
border-bottom: 1px dotted;
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
dfn {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 2em;
|
||||
margin: 0.67em 0;
|
||||
}
|
||||
|
||||
mark {
|
||||
background: #ff0;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
small {
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
sub,
|
||||
sup {
|
||||
font-size: 75%;
|
||||
line-height: 0;
|
||||
position: relative;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
sup {
|
||||
top: -0.5em;
|
||||
}
|
||||
|
||||
sub {
|
||||
bottom: -0.25em;
|
||||
}
|
||||
|
||||
/* Embedded content
|
||||
========================================================================== */
|
||||
|
||||
img {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
svg:not(:root) {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Grouping content
|
||||
========================================================================== */
|
||||
|
||||
figure {
|
||||
margin: 1em 40px;
|
||||
}
|
||||
|
||||
hr {
|
||||
-moz-box-sizing: content-box;
|
||||
box-sizing: content-box;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
pre {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
code,
|
||||
kbd,
|
||||
pre,
|
||||
samp {
|
||||
font-family: monospace, monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
button,
|
||||
input,
|
||||
optgroup,
|
||||
select,
|
||||
textarea {
|
||||
color: inherit; /* 1 */
|
||||
font: inherit; /* 2 */
|
||||
margin: 0; /* 3 */
|
||||
}
|
||||
|
||||
button {
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
button,
|
||||
select {
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
button,
|
||||
html input[type="button"], /* 1 */
|
||||
input[type="reset"],
|
||||
input[type="submit"] {
|
||||
-webkit-appearance: button; /* 2 */
|
||||
cursor: pointer; /* 3 */
|
||||
}
|
||||
|
||||
button[disabled],
|
||||
html input[disabled] {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
button::-moz-focus-inner,
|
||||
input::-moz-focus-inner {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
input {
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
input[type="checkbox"],
|
||||
input[type="radio"] {
|
||||
box-sizing: border-box; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
input[type="number"]::-webkit-inner-spin-button,
|
||||
input[type="number"]::-webkit-outer-spin-button {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
input[type="search"] {
|
||||
-webkit-appearance: textfield; /* 1 */
|
||||
-moz-box-sizing: content-box;
|
||||
-webkit-box-sizing: content-box; /* 2 */
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
input[type="search"]::-webkit-search-cancel-button,
|
||||
input[type="search"]::-webkit-search-decoration {
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
border: 1px solid #c0c0c0;
|
||||
margin: 0 2px;
|
||||
padding: 0.35em 0.625em 0.75em;
|
||||
}
|
||||
|
||||
/**
|
||||
* 1. Correct `color` not being inherited in IE 8/9/10/11.
|
||||
* 2. Remove padding so people aren't caught out if they zero out fieldsets.
|
||||
*/
|
||||
|
||||
legend {
|
||||
border: 0; /* 1 */
|
||||
padding: 0; /* 2 */
|
||||
}
|
||||
|
||||
textarea {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
/**
|
||||
* Don't inherit the `font-weight` (applied by a rule above).
|
||||
* NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
|
||||
*/
|
||||
|
||||
optgroup {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
/* Tables
|
||||
========================================================================== */
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}img{border:0}svg:not(:root){overflow:visible}figure{margin:1em 40px}hr{-moz-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace,monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}
|
||||
File diff suppressed because it is too large
Load Diff
+1
File diff suppressed because one or more lines are too long
@@ -0,0 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Control</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link
|
||||
rel="shortcut icon"
|
||||
href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC"
|
||||
/>
|
||||
<link rel="stylesheet" href="/css/normalize.css" />
|
||||
<link rel="stylesheet" href="/css/style.css" />
|
||||
|
||||
<script src="/js/zepto.min.js"></script>
|
||||
<script src="/js/slider.js"></script>
|
||||
<script src="/js/graph.js"></script>
|
||||
<script src="/js/controls.js"></script>
|
||||
<script src="/js/tabbedcontent.js"></script>
|
||||
</head>
|
||||
|
||||
<body onload="javascript:start();">
|
||||
<div>
|
||||
<h4>
|
||||
<div id="mainHeader">Control</div>
|
||||
<span id="conStatus" class="label">Offline</span>
|
||||
</h4>
|
||||
</div>
|
||||
<hr />
|
||||
<div class="container">
|
||||
<div id="row" class="row u-full-width"></div>
|
||||
<ul id="tabsnav" class="navigation navigation-tabs u-full-width"></ul>
|
||||
<div id="tabscontent" class="tabscontent u-full-width"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1 @@
|
||||
<!DOCTYPE html><html> <head><meta charset=utf-8><title>Control</title><meta name=viewport content="width=device-width, initial-scale=1"><link rel="shortcut icon" href=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAABGdBTUEAALGPC/xhBQAAACBjSFJNAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3CculE8AAAAPFBMVEUAAACA1VWR21qQ2liR3FqR3FqS3VuR3VqR3VuR3VqO21mS21uS3FqS3FqS21uJ2GKQ21qR3FuR3FoAAAB/3Gu7AAAAEnRSTlMABoA3kPBwz8i5Kzioxg4NVcU3uEJHAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAAN1wAADdcBQiibeAAAAAd0SU1FB+EFEhcEM+HpYwQAAABYSURBVBjThY/JDsAgCESt4lpX/v9jLQZJ6qF9t3khAyj1xXUKbQ4BVowDwqOYgExkkW4iY6lPaF06RqM8YItOuRbMaz6xjbsusDAW/drplBg47jP696cXE8bPA1eUDeK2AAAAJXRFWHRkYXRlOmNyZWF0ZQAyMDE3LTA1LTE4VDIzOjA0OjUxKzAyOjAwxE59ewAAACV0RVh0ZGF0ZTptb2RpZnkAMjAxNy0wNS0xOFQyMzowNDo1MSswMjowMLUTxccAAAAZdEVYdFNvZnR3YXJlAHd3dy5pbmtzY2FwZS5vcmeb7jwaAAAAAElFTkSuQmCC><link rel=stylesheet href=/css/normalize.css><link rel=stylesheet href=/css/style.css><script src=/js/zepto.min.js></script><script src=/js/slider.js></script><script src=/js/graph.js></script><script src=/js/controls.js></script><script src=/js/tabbedcontent.js></script></head> <body onload=javascript:start();> <div> <h4> <div id=mainHeader>Control</div> <span id=conStatus class=label>Offline</span> </h4> </div> <hr> <div class=container> <div id=row class="row u-full-width"></div> <ul id=tabsnav class="navigation navigation-tabs u-full-width"></ul> <div id=tabscontent class="tabscontent u-full-width"></div> </div> </body> </html>
|
||||
+1138
File diff suppressed because it is too large
Load Diff
+136
@@ -0,0 +1,136 @@
|
||||
const UI_INITIAL_GUI=200;const UI_RELOAD=201;const UPDATE_OFFSET=100;const UI_EXTEND_GUI=210;const UI_TITEL=0;const UI_PAD=1;const UPDATE_PAD=101;const UI_CPAD=2;const UPDATE_CPAD=102;const UI_BUTTON=3;const UPDATE_BUTTON=103;const UI_LABEL=4;const UPDATE_LABEL=104;const UI_SWITCHER=5;const UPDATE_SWITCHER=105;const UI_SLIDER=6;const UPDATE_SLIDER=106;const UI_NUMBER=7;const UPDATE_NUMBER=107;const UI_TEXT_INPUT=8;const UPDATE_TEXT_INPUT=108;const UI_GRAPH=9;const ADD_GRAPH_POINT=10;const CLEAR_GRAPH=109;const UI_TAB=11;const UPDATE_TAB=111;const UI_SELECT=12;const UPDATE_SELECT=112;const UI_OPTION=13;const UPDATE_OPTION=113;const UI_MIN=14;const UPDATE_MIN=114;const UI_MAX=15;const UPDATE_MAX=115;const UI_STEP=16;const UPDATE_STEP=116;const UI_GAUGE=17;const UPDATE_GAUGE=117;const UI_ACCEL=18;const UPDATE_ACCEL=118;const UI_SEPARATOR=19;const UPDATE_SEPARATOR=119;const UI_TIME=20;const UPDATE_TIME=120;const UI_FILEDISPLAY=21;const UPDATE_FILEDISPLAY=121;const UI_FRAGMENT=98;const UP=0;const DOWN=1;const LEFT=2;const RIGHT=3;const CENTER=4;const C_TURQUOISE=0;const C_EMERALD=1;const C_PETERRIVER=2;const C_WETASPHALT=3;const C_SUNFLOWER=4;const C_CARROT=5;const C_ALIZARIN=6;const C_DARK=7;const C_NONE=255;var controlAssemblyArray=new Object();var FragmentAssemblyTimer=new Array();var graphData=new Array();var hasAccel=false;var sliderContinuous=false;function colorClass(colorId){colorId=Number(colorId);switch(colorId){case C_TURQUOISE:return"turquoise";case C_EMERALD:return"emerald";case C_PETERRIVER:return"peterriver";case C_WETASPHALT:return"wetasphalt";case C_SUNFLOWER:return"sunflower";case C_CARROT:return"carrot";case C_ALIZARIN:return"alizarin";case C_DARK:case C_NONE:return"dark";default:return"";}}
|
||||
var websock;var websockConnected=false;var WebSocketTimer=null;function requestOrientationPermission(){}
|
||||
function saveGraphData(){localStorage.setItem("espuigraphs",JSON.stringify(graphData));}
|
||||
function restoreGraphData(id){var savedData=localStorage.getItem("espuigraphs",graphData);if(savedData!=null){savedData=JSON.parse(savedData);let idData=savedData[id];return Array.isArray(idData)?idData:[];}
|
||||
return[];}
|
||||
function restart(){$(document).add("*").off();$("#row").html("");conStatusError();start();}
|
||||
function conStatusError(){FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Array();controlAssemblyArray=new Array();if(true===websockConnected){websockConnected=false;websock.close();$("#conStatus").removeClass("color-green");$("#conStatus").addClass("color-red");$("#conStatus").html("Error / No Connection ↻");$("#conStatus").off();$("#conStatus").on({click:restart,});}}
|
||||
function handleVisibilityChange(){if(!websockConnected&&!document.hidden){restart();}}
|
||||
function start(){let location=window.location.hostname;let port=window.location.port;document.addEventListener("visibilitychange",handleVisibilityChange,false);if(port!=""||port!=80||port!=443){websock=new WebSocket("ws://"+location+":"+port+"/ws");}else{websock=new WebSocket("ws://"+location+"/ws");}
|
||||
if(null===WebSocketTimer){WebSocketTimer=setInterval(function(){if(websock.readyState===3){restart();}},5000);}
|
||||
websock.onopen=function(evt){console.log("websock open");$("#conStatus").addClass("color-green");$("#conStatus").text("Connected");websockConnected=true;FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Array();controlAssemblyArray=new Array();};websock.onclose=function(evt){console.log("websock close");conStatusError();FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Array();controlAssemblyArray=new Array();};websock.onerror=function(evt){console.log("websock Error");restart();FragmentAssemblyTimer.forEach(element=>{clearInterval(element);});FragmentAssemblyTimer=new Array();controlAssemblyArray=new Array();};var handleEvent=function(evt){try{var data=JSON.parse(evt.data);}
|
||||
catch(Event){console.error(Event);websock.send("uiok:"+0);return;}
|
||||
var e=document.body;var center="";switch(data.type){case UI_INITIAL_GUI:$("#row").html("");$("#tabsnav").html("");$("#tabscontent").html("");if(data.sliderContinuous){sliderContinuous=data.sliderContinuous;}
|
||||
data.controls.forEach(element=>{var fauxEvent={data:JSON.stringify(element),};handleEvent(fauxEvent);});if(data.totalcontrols>(data.controls.length-1)){websock.send("uiok:"+(data.controls.length-1));}
|
||||
break;case UI_EXTEND_GUI:data.controls.forEach(element=>{var fauxEvent={data:JSON.stringify(element),};handleEvent(fauxEvent);});if(data.totalcontrols>data.startindex+(data.controls.length-1)){websock.send("uiok:"+(data.startindex+(data.controls.length-1)));}
|
||||
break;case UI_RELOAD:window.location.reload();break;case UI_TITEL:document.title=data.label;$("#mainHeader").html(data.label);break;case UI_LABEL:case UI_NUMBER:case UI_TEXT_INPUT:case UI_SELECT:case UI_GAUGE:case UI_SEPARATOR:if(data.visible)addToHTML(data);break;case UI_BUTTON:if(data.visible){addToHTML(data);$("#btn"+data.id).on({touchstart:function(e){e.preventDefault();buttonclick(data.id,true);},touchend:function(e){e.preventDefault();buttonclick(data.id,false);},});}
|
||||
break;case UI_SWITCHER:if(data.visible){addToHTML(data);switcher(data.id,data.value);}
|
||||
break;case UI_CPAD:case UI_PAD:if(data.visible){addToHTML(data);$("#pf"+data.id).on({touchstart:function(e){e.preventDefault();padclick(UP,data.id,true);},touchend:function(e){e.preventDefault();padclick(UP,data.id,false);},});$("#pl"+data.id).on({touchstart:function(e){e.preventDefault();padclick(LEFT,data.id,true);},touchend:function(e){e.preventDefault();padclick(LEFT,data.id,false);},});$("#pr"+data.id).on({touchstart:function(e){e.preventDefault();padclick(RIGHT,data.id,true);},touchend:function(e){e.preventDefault();padclick(RIGHT,data.id,false);},});$("#pb"+data.id).on({touchstart:function(e){e.preventDefault();padclick(DOWN,data.id,true);},touchend:function(e){e.preventDefault();padclick(DOWN,data.id,false);},});$("#pc"+data.id).on({touchstart:function(e){e.preventDefault();padclick(CENTER,data.id,true);},touchend:function(e){e.preventDefault();padclick(CENTER,data.id,false);},});}
|
||||
break;case UI_SLIDER:if(data.visible){addToHTML(data);rangeSlider(!sliderContinuous);}
|
||||
break;case UI_TAB:if(data.visible){$("#tabsnav").append("<li><a onmouseup='tabclick("+data.id+")' href='#tab"+data.id+"'>"+data.value+"</a></li>");$("#tabscontent").append("<div id='tab"+data.id+"'></div>");tabs=$(".tabscontent").tabbedContent({loop:true}).data("api");$("a").filter(function(){return $(this).attr("href")==="#click-to-switch";}).on("click",function(e){var tab=prompt("Tab to switch to (number or id)?");if(!tabs.switchTab(tab)){alert("That tab does not exist :\\");}
|
||||
e.preventDefault();});}
|
||||
break;case UI_OPTION:if(data.parentControl){var parent=$("#select"+data.parentControl);parent.append("<option id='option"+
|
||||
data.id+
|
||||
"' value='"+
|
||||
data.value+
|
||||
"' "+
|
||||
data.selected+
|
||||
">"+
|
||||
data.label+
|
||||
"</option>");}
|
||||
break;case UI_MIN:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("min",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("min",data.value);}}
|
||||
break;case UI_MAX:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("max",data.value);}else if($('#text'+data.parentControl).length){$('#text'+data.parentControl).attr("maxlength",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("max",data.value);}}
|
||||
break;case UI_STEP:if(data.parentControl){if($('#sl'+data.parentControl).length){$('#sl'+data.parentControl).attr("step",data.value);}else if($('#num'+data.parentControl).length){$('#num'+data.parentControl).attr("step",data.value);}}
|
||||
break;case UI_GRAPH:if(data.visible){addToHTML(data);graphData[data.id]=restoreGraphData(data.id);renderGraphSvg(graphData[data.id],"graph"+data.id);}
|
||||
break;case ADD_GRAPH_POINT:var ts=new Date().getTime();graphData[data.id].push({x:ts,y:data.value});saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case CLEAR_GRAPH:graphData[data.id]=[];saveGraphData();renderGraphSvg(graphData[data.id],"graph"+data.id);break;case UI_ACCEL:if(hasAccel)break;hasAccel=true;if(data.visible){addToHTML(data);requestOrientationPermission();}
|
||||
break;case UI_FILEDISPLAY:if(data.visible)
|
||||
{addToHTML(data);FileDisplayUploadFile(data);}
|
||||
break;case UPDATE_LABEL:$("#l"+data.id).html(data.value);if(data.hasOwnProperty('elementStyle')){$("#l"+data.id).attr("style",data.elementStyle);}
|
||||
break;case UPDATE_SWITCHER:switcher(data.id,data.value=="0"?0:1);if(data.hasOwnProperty('elementStyle')){$("#sl"+data.id).attr("style",data.elementStyle);}
|
||||
break;case UPDATE_SLIDER:$("#sl"+data.id).attr("value",data.value)
|
||||
slider_move($("#sl"+data.id).parent().parent(),data.value,"100",false);if(data.hasOwnProperty('elementStyle')){$("#sl"+data.id).attr("style",data.elementStyle);}
|
||||
break;case UPDATE_NUMBER:$("#num"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#num"+data.id).attr("style",data.elementStyle);}
|
||||
break;case UPDATE_TEXT_INPUT:$("#text"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#text"+data.id).attr("style",data.elementStyle);}
|
||||
if(data.hasOwnProperty('inputType')){$("#text"+data.id).attr("type",data.inputType);}
|
||||
break;case UPDATE_SELECT:$("#select"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#select"+data.id).attr("style",data.elementStyle);}
|
||||
break;case UPDATE_BUTTON:$("#btn"+data.id).val(data.value);$("#btn"+data.id).text(data.value);if(data.hasOwnProperty('elementStyle')){$("#btn"+data.id).attr("style",data.elementStyle);}
|
||||
break;case UPDATE_PAD:case UPDATE_CPAD:break;case UPDATE_GAUGE:$("#gauge"+data.id).val(data.value);if(data.hasOwnProperty('elementStyle')){$("#gauge"+data.id).attr("style",data.elementStyle);}
|
||||
break;case UPDATE_ACCEL:break;case UPDATE_TIME:var rv=new Date().toISOString();websock.send("time:"+rv+":"+data.id);break;case UPDATE_FILEDISPLAY:FileDisplayUploadFile(data);break;case UI_FRAGMENT:let FragmentLen=data.length;let FragementOffset=data.offset;let NextFragmentOffset=FragementOffset+FragmentLen;let Total=data.total;let Arrived=(FragmentLen+FragementOffset);let FragmentFinal=Total===Arrived;if(!data.hasOwnProperty('control'))
|
||||
{console.error("UI_FRAGMENT:Missing control record, skipping control");break;}
|
||||
let control=data.control;StopFragmentAssemblyTimer(data.control.id);if(0===FragementOffset)
|
||||
{controlAssemblyArray[control.id]=data;controlAssemblyArray[control.id].offset=NextFragmentOffset;StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':NextFragmentOffset});websock.send("uifragmentok:"+0+": "+TotalRequest+":");break;}
|
||||
if("undefined"===typeof controlAssemblyArray[control.id])
|
||||
{console.error("Missing first fragment for control: "+control.id);StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':0});websock.send("uifragmentok:"+0+": "+TotalRequest+":");break;}
|
||||
if(FragementOffset!==controlAssemblyArray[control.id].offset)
|
||||
{console.error("Wrong next fragment. Expected: "+controlAssemblyArray[control.id].offset+" Got: "+FragementOffset);StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':controlAssemblyArray[control.id].length+controlAssemblyArray[control.id].offset});websock.send("uifragmentok:"+0+": "+TotalRequest+":");break;}
|
||||
controlAssemblyArray[control.id].control.value+=control.value;controlAssemblyArray[control.id].offset=NextFragmentOffset;if(true===FragmentFinal)
|
||||
{var fauxEvent={data:JSON.stringify(controlAssemblyArray[control.id].control),};handleEvent(fauxEvent);controlAssemblyArray[control.id]=null;}
|
||||
else
|
||||
{StartFragmentAssemblyTimer(control.id);let TotalRequest=JSON.stringify({'id':control.id,'offset':NextFragmentOffset});websock.send("uifragmentok:"+0+": "+TotalRequest+":");}
|
||||
break;default:console.error("Unknown type or event");break;}
|
||||
if(data.type>=UI_TITEL&&data.type<UPDATE_OFFSET){processEnabled(data);}
|
||||
if(data.type>=UPDATE_OFFSET&&data.type<UI_INITIAL_GUI){var element=$("#id"+data.id);if(data.hasOwnProperty('panelStyle')){$("#id"+data.id).attr("style",data.panelStyle);}
|
||||
if(data.hasOwnProperty('visible')){if(data['visible'])
|
||||
$("#id"+data.id).show();else
|
||||
$("#id"+data.id).hide();}
|
||||
if(data.type==UPDATE_SLIDER){element.removeClass("slider-turquoise slider-emerald slider-peterriver slider-wetasphalt slider-sunflower slider-carrot slider-alizarin");element.addClass("slider-"+colorClass(data.color));}else{element.removeClass("turquoise emerald peterriver wetasphalt sunflower carrot alizarin");element.addClass(colorClass(data.color));}
|
||||
processEnabled(data);}
|
||||
$(".range-slider__range").each(function(){$(this)[0].value=$(this).attr("value");$(this).next().html($(this).attr("value"));});};websock.onmessage=handleEvent;}
|
||||
async function FileDisplayUploadFile(data)
|
||||
{let text=await downloadFile(data.value);let ItemToUpdateId="fd"+data.id;$("#"+ItemToUpdateId).val(text);$("#"+ItemToUpdateId).css("textAlign","left");$("#"+ItemToUpdateId).css("white-space","nowrap");$("#"+ItemToUpdateId).css("overflow","scroll");$("#"+ItemToUpdateId).css("overflow-y","scroll");$("#"+ItemToUpdateId).css("overflow-x","scroll");$("#"+ItemToUpdateId).scrollTop($("#"+ItemToUpdateId).val().length);}
|
||||
async function downloadFile(filename)
|
||||
{let response=await fetch(filename);if(response.status!=200){throw new Error("File Read Server Error: '"+response.status+"'");}
|
||||
let text_data=await response.text();return text_data;}
|
||||
function StartFragmentAssemblyTimer(Id)
|
||||
{StopFragmentAssemblyTimer(Id);FragmentAssemblyTimer[Id]=setInterval(function(_Id)
|
||||
{if("undefined"!==typeof controlAssemblyArray[_Id])
|
||||
{if(null!==controlAssemblyArray[_Id])
|
||||
{let TotalRequest=JSON.stringify({'id':controlAssemblyArray[_Id].control.id,'offset':controlAssemblyArray[_Id].offset});websock.send("uifragmentok:"+0+": "+TotalRequest+":");}}},1000,Id);}
|
||||
function StopFragmentAssemblyTimer(Id)
|
||||
{if("undefined"!==typeof FragmentAssemblyTimer[Id])
|
||||
{if(FragmentAssemblyTimer[Id])
|
||||
{clearInterval(FragmentAssemblyTimer[Id]);}}}
|
||||
function sliderchange(number){var val=$("#sl"+number).val();websock.send("slvalue:"+val+":"+number);$(".range-slider__range").each(function(){$(this).attr("value",$(this)[0].value);});}
|
||||
function numberchange(number){var val=$("#num"+number).val();websock.send("nvalue:"+val+":"+number);}
|
||||
function textchange(number){var val=$("#text"+number).val();websock.send("tvalue:"+val+":"+number);}
|
||||
function tabclick(number){var val=$("#tab"+number).val();websock.send("tabvalue:"+val+":"+number);}
|
||||
function selectchange(number){var val=$("#select"+number).val();websock.send("svalue:"+val+":"+number);}
|
||||
function buttonclick(number,isdown){if(isdown)websock.send("bdown:"+number);else websock.send("bup:"+number);}
|
||||
function padclick(type,number,isdown){if($("#id"+number+" nav").hasClass("disabled")){return;}
|
||||
switch(type){case CENTER:if(isdown)websock.send("pcdown:"+number);else websock.send("pcup:"+number);break;case UP:if(isdown)websock.send("pfdown:"+number);else websock.send("pfup:"+number);break;case DOWN:if(isdown)websock.send("pbdown:"+number);else websock.send("pbup:"+number);break;case LEFT:if(isdown)websock.send("pldown:"+number);else websock.send("plup:"+number);break;case RIGHT:if(isdown)websock.send("prdown:"+number);else websock.send("prup:"+number);break;}}
|
||||
function switcher(number,state){if(state==null){if(!$("#sl"+number).hasClass("checked")){websock.send("sactive:"+number);$("#sl"+number).addClass("checked");}else{websock.send("sinactive:"+number);$("#sl"+number).removeClass("checked");}}else if(state==1){$("#sl"+number).addClass("checked");$("#sl"+number).prop("checked",true);}else if(state==0){$("#sl"+number).removeClass("checked");$("#sl"+number).prop("checked",false);}}
|
||||
var rangeSlider=function(isDiscrete){var range=$(".range-slider__range");var slidercb=function(){sliderchange($(this).attr("id").replace(/^\D+/g,""));};range.on({input:function(){$(this).next().html(this.value)}});range.each(function(){$(this).next().html(this.value);if($(this).attr("callbackSet")!="true"){if(!isDiscrete){$(this).on({input:slidercb});}else{$(this).on({change:slidercb});}
|
||||
$(this).attr("callbackSet","true");}});};var addToHTML=function(data){panelStyle=data.hasOwnProperty('panelStyle')?" style='"+data.panelStyle+"' ":"";panelwide=data.hasOwnProperty('wide')?"wide":"";if(!data.hasOwnProperty('parentControl')||$("#tab"+data.parentControl).length>0){var parent=data.hasOwnProperty('parentControl')?$("#tab"+data.parentControl):$("#row");var html="";switch(data.type){case UI_LABEL:case UI_BUTTON:case UI_SWITCHER:case UI_CPAD:case UI_PAD:case UI_SLIDER:case UI_NUMBER:case UI_TEXT_INPUT:case UI_SELECT:case UI_GRAPH:case UI_GAUGE:case UI_ACCEL:case UI_FILEDISPLAY:html="<div id='id"+data.id+"' "+panelStyle+" class='two columns "+panelwide+" card tcenter "+
|
||||
colorClass(data.color)+"'><h5>"+data.label+"</h5><hr/>"+
|
||||
elementHTML(data)+
|
||||
"</div>";break;case UI_SEPARATOR:html="<div id='id"+data.id+"' "+panelStyle+" class='sectionbreak columns'>"+
|
||||
"<h5>"+data.label+"</h5><hr/></div>";break;case UI_TIME:break;}
|
||||
parent.append(html);}else{var parent=$("#id"+data.parentControl);parent.append(elementHTML(data));}}
|
||||
var elementHTML=function(data){var id=data.id
|
||||
var elementStyle=data.hasOwnProperty('elementStyle')?" style='"+data.elementStyle+"' ":"";var inputType=data.hasOwnProperty('inputType')?" type='"+data.inputType+"' ":"";switch(data.type){case UI_LABEL:return"<span id='l"+id+"' "+elementStyle+
|
||||
" class='label label-wrap'>"+data.value+"</span>";case UI_FILEDISPLAY:return"<textarea id='fd"+id+"' rows='4' "+elementStyle+
|
||||
" class='label label-wrap'>"+"</textarea>";case UI_BUTTON:return"<button id='btn"+id+"' "+elementStyle+
|
||||
" onmousedown='buttonclick("+id+", true)'"+
|
||||
" onmouseup='buttonclick("+id+", false)'>"+
|
||||
data.value+"</button>";case UI_SWITCHER:return"<label id='sl"+id+"' "+elementStyle+
|
||||
" class='switch "+(data.value=="1"?"checked":"")+
|
||||
(data.hasOwnProperty('vertical')?" vert-switcher ":"")+
|
||||
"'>"+
|
||||
"<div class='in'>"+
|
||||
"<input type='checkbox' id='s"+id+"' onClick='switcher("+id+",null)' "+
|
||||
(data.value=="1"?"checked":"")+"/></div></label>";case UI_CPAD:case UI_PAD:return"<nav class='control'><ul>"+
|
||||
"<li><a onmousedown='padclick(UP, "+id+", true)' "+
|
||||
"onmouseup='padclick(UP, "+id+", false)' id='pf"+id+"'>▲</a></li>"+
|
||||
"<li><a onmousedown='padclick(RIGHT, "+id+", true)' "+
|
||||
"onmouseup='padclick(RIGHT, "+id+", false)' id='pr"+id+"'>▲</a></li>"+
|
||||
"<li><a onmousedown='padclick(LEFT, "+id+", true)' "+
|
||||
"onmouseup='padclick(LEFT, "+id+", false)' id='pl"+id+"'>▲</a></li>"+
|
||||
"<li><a onmousedown='padclick(DOWN, "+id+", true)' "+
|
||||
"onmouseup='padclick(DOWN, "+id+", false)' id='pb"+id+"'>▲</a></li>"+
|
||||
"</ul>"+
|
||||
(data.type==UI_CPAD?"<a class='confirm' onmousedown='padclick(CENTER,"+id+", true)' "+
|
||||
"onmouseup='padclick(CENTER, "+id+", false)' id='pc"+id+"'>OK</a>":"")+
|
||||
"</nav>";case UI_SLIDER:return"<div class='range-slider "+
|
||||
(data.hasOwnProperty('vertical')?" vert-slider ":"")+
|
||||
"'>"+
|
||||
"<input id='sl"+id+"' type='range' min='0' max='100' value='"+data.value+"' "+
|
||||
elementStyle+" class='range-slider__range'><span class='range-slider__value'>"+
|
||||
data.value+"</span></div>";case UI_NUMBER:return"<input style='color:black; "+data.elementStyle+"' id='num"+id+
|
||||
"' type='number' value='"+data.value+"' onchange='numberchange("+id+")' />";case UI_TEXT_INPUT:return"<input "+inputType+"style='color:black; "+data.elementStyle+"' id='text"+id+
|
||||
"' value='"+data.value+"' onchange='textchange("+id+")' />";case UI_SELECT:return"<select style='color:black; "+data.elementStyle+"' id='select"+id+
|
||||
"' onchange='selectchange("+id+")' />";case UI_GRAPH:return"<figure id='graph"+id+"'><figcaption>"+data.label+"</figcaption></figure>";case UI_GAUGE:return"WILL BE A GAUGE <input style='color:black;' id='gauge"+id+
|
||||
"' type='number' value='"+data.value+"' onchange='numberchange("+id+")' />";case UI_ACCEL:return"ACCEL // Not implemented fully!<div class='accelerometer' id='accel"+id+
|
||||
"' ><div class='ball"+id+"'></div><pre class='accelerometeroutput"+id+"'></pre>";default:return"";}}
|
||||
var processEnabled=function(data){switch(data.type){case UI_SWITCHER:case UPDATE_SWITCHER:if(data.enabled){$("#sl"+data.id).removeClass('disabled');$("#s"+data.id).prop("disabled",false);}else{$("#sl"+data.id).addClass('disabled');$("#s"+data.id).prop("disabled",true);}
|
||||
break;case UI_SLIDER:case UPDATE_SLIDER:$("#sl"+data.id).prop("disabled",!data.enabled);break;case UI_NUMBER:case UPDATE_NUMBER:$("#num"+data.id).prop("disabled",!data.enabled);break;case UI_TEXT_INPUT:case UPDATE_TEXT_INPUT:$("#text"+data.id).prop("disabled",!data.enabled);break;case UI_SELECT:case UPDATE_SELECT:$("#select"+data.id).prop("disabled",!data.enabled);break;case UI_BUTTON:case UPDATE_BUTTON:$("#btn"+data.id).prop("disabled",!data.enabled);break;case UI_PAD:case UI_CPAD:case UPDATE_PAD:case UPDATE_CPAD:case UI_FILEDISPLAY:case UPDATE_FILEDISPLAY:if(data.enabled){$("#id"+data.id+" nav").removeClass('disabled');}else{$("#id"+data.id+" nav").addClass('disabled');}
|
||||
break;}}
|
||||
@@ -0,0 +1,297 @@
|
||||
function lineGraph(parent, xAccessor, yAccessor) {
|
||||
// Constant size definitions TODO: this could well be improved and calculated...
|
||||
const width = 620;
|
||||
const height = 420;
|
||||
const gutter = 40;
|
||||
const pixelsPerTick = 30;
|
||||
|
||||
/**
|
||||
* Creates an object that contatins transform functions that:
|
||||
* transforms numeric data into coordinate space, linearly
|
||||
* transforms coordinates into numeric data, linearly
|
||||
*/
|
||||
function numericTransformer(dataMin, dataMax, pxMin, pxMax) {
|
||||
var dataDiff = dataMax - dataMin,
|
||||
pxDiff = pxMax - pxMin,
|
||||
dataRatio = pxDiff / dataDiff,
|
||||
coordRatio = dataDiff / pxDiff;
|
||||
|
||||
return {
|
||||
// transforms a data point to a coordinate point
|
||||
toCoord: function(data) {
|
||||
return (data - dataMin) * dataRatio + pxMin;
|
||||
},
|
||||
// transforms a coord point to a data point
|
||||
toData: function(coord) {
|
||||
return (coord - pxMin) * coordRatio + dataMin;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an axis.
|
||||
* orientation = 'x' or 'y'
|
||||
* transform = a function for transforming px into data for labeling/creating tick marks
|
||||
*/
|
||||
function axisRenderer(orientation, transform) {
|
||||
var axisGroup = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
||||
var axisPath = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"path"
|
||||
);
|
||||
|
||||
axisGroup.setAttribute("class", orientation + "-axis");
|
||||
|
||||
var xMin = gutter;
|
||||
var xMax = width - gutter;
|
||||
var yMin = height - gutter;
|
||||
var yMax = gutter;
|
||||
|
||||
if (orientation === "x") {
|
||||
axisPath.setAttribute(
|
||||
"d",
|
||||
"M " + xMin + " " + yMin + " L " + xMax + " " + yMin
|
||||
);
|
||||
|
||||
// generate labels
|
||||
for (var i = xMin; i <= xMax; i++) {
|
||||
if ((i - xMin) % (pixelsPerTick*3) === 0 && i !== xMin) {
|
||||
var text = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"text"
|
||||
);
|
||||
// primitive formatting
|
||||
text.innerHTML = new Date(Math.floor(transform(i))).toLocaleTimeString();
|
||||
text.setAttribute("x", i);
|
||||
text.setAttribute("y", yMin);
|
||||
// offset the text by 1 em
|
||||
text.setAttribute("dy", "1em");
|
||||
axisGroup.appendChild(text);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
axisPath.setAttribute(
|
||||
"d",
|
||||
"M " + xMin + " " + yMin + " L " + xMin + " " + yMax
|
||||
);
|
||||
|
||||
// generate labels
|
||||
for (var i = yMax; i <= yMin; i++) {
|
||||
if ((i - yMin) % pixelsPerTick === 0 && i !== yMin) {
|
||||
var tickGroup = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"g"
|
||||
);
|
||||
var gridLine = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"path"
|
||||
);
|
||||
text = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
||||
// primitive formatting
|
||||
text.innerHTML = Math.floor(transform(i));
|
||||
text.setAttribute("x", xMin);
|
||||
text.setAttribute("y", i);
|
||||
// offset the text labels to align with grid line and keeping it to the left of the y-axis
|
||||
text.setAttribute("dx", "-.5em");
|
||||
text.setAttribute("dy", ".3em");
|
||||
|
||||
gridLine.setAttribute(
|
||||
"d",
|
||||
"M " + xMin + " " + i + " L " + xMax + " " + i
|
||||
);
|
||||
|
||||
tickGroup.appendChild(gridLine);
|
||||
tickGroup.appendChild(text);
|
||||
axisGroup.appendChild(tickGroup);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
axisGroup.appendChild(axisPath);
|
||||
parent.appendChild(axisGroup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a line
|
||||
*/
|
||||
function lineRenderer(xAccessor, yAccessor, xTransform, yTransform) {
|
||||
var line = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
||||
|
||||
xAccessor.reset();
|
||||
yAccessor.reset();
|
||||
if (!xAccessor.hasNext() || !yAccessor.hasNext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
var pathString =
|
||||
"M " + xTransform(xAccessor.next()) + " " + yTransform(yAccessor.next());
|
||||
while (xAccessor.hasNext() && yAccessor.hasNext()) {
|
||||
pathString +=
|
||||
" L " +
|
||||
xTransform(xAccessor.next()) +
|
||||
" " +
|
||||
yTransform(yAccessor.next());
|
||||
}
|
||||
|
||||
line.setAttribute("class", "series");
|
||||
line.setAttribute("d", pathString);
|
||||
|
||||
parent.appendChild(line);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders data point circles + text labels
|
||||
*/
|
||||
function pointRenderer(xAccessor, yAccessor, xTransform, yTransform) {
|
||||
var pointGroup = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"g"
|
||||
);
|
||||
|
||||
pointGroup.setAttribute("class", "data-points");
|
||||
|
||||
xAccessor.reset();
|
||||
yAccessor.reset();
|
||||
if (!xAccessor.hasNext() || !yAccessor.hasNext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
while (xAccessor.hasNext() && yAccessor.hasNext()) {
|
||||
var xDataValue = xAccessor.next();
|
||||
var x = xTransform(xDataValue);
|
||||
var yDataValue = yAccessor.next();
|
||||
var y = yTransform(yDataValue);
|
||||
|
||||
var circle = document.createElementNS(
|
||||
"http://www.w3.org/2000/svg",
|
||||
"circle"
|
||||
);
|
||||
circle.setAttribute("cx", x);
|
||||
circle.setAttribute("cy", y);
|
||||
circle.setAttribute("r", "4");
|
||||
|
||||
var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
||||
// primitive formatting
|
||||
text.innerHTML = Math.floor(xDataValue) + " / " + Math.floor(yDataValue);
|
||||
text.setAttribute("x", x);
|
||||
text.setAttribute("y", y);
|
||||
|
||||
text.setAttribute("dx", "1em");
|
||||
text.setAttribute("dy", "-.7em");
|
||||
|
||||
pointGroup.appendChild(circle);
|
||||
pointGroup.appendChild(text);
|
||||
}
|
||||
|
||||
parent.appendChild(pointGroup);
|
||||
}
|
||||
|
||||
// perform the rendering
|
||||
xTransform = numericTransformer(
|
||||
xAccessor.min(),
|
||||
xAccessor.max(),
|
||||
0 + gutter,
|
||||
width - gutter
|
||||
);
|
||||
// NOTE: for y... have to reverse coordinate space
|
||||
yTransform = numericTransformer(
|
||||
yAccessor.min(),
|
||||
yAccessor.max(),
|
||||
height - gutter,
|
||||
0 + gutter
|
||||
);
|
||||
|
||||
axisRenderer("x", xTransform.toData);
|
||||
axisRenderer("y", yTransform.toData);
|
||||
|
||||
lineRenderer(xAccessor, yAccessor, xTransform.toCoord, yTransform.toCoord);
|
||||
pointRenderer(xAccessor, yAccessor, xTransform.toCoord, yTransform.toCoord);
|
||||
}
|
||||
|
||||
// Final render function
|
||||
function renderGraphSvg(dataArray, renderId) {
|
||||
var figure = document.getElementById(renderId);
|
||||
while (figure.hasChildNodes()) {
|
||||
figure.removeChild(figure.lastChild);
|
||||
}
|
||||
//console.log(dataArray);
|
||||
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
|
||||
svg.setAttribute("viewBox", "0 0 640 440");
|
||||
svg.setAttribute("preserveAspectRatio", "xMidYMid meet");
|
||||
|
||||
lineGraph(
|
||||
svg,
|
||||
// time accessor
|
||||
(function(data, min, max) {
|
||||
var i = 0;
|
||||
return {
|
||||
hasNext: function() {
|
||||
return i < data.length;
|
||||
},
|
||||
next: function() {
|
||||
return data[i++].x;
|
||||
},
|
||||
reset: function() {
|
||||
i = 0;
|
||||
},
|
||||
min: function() {
|
||||
return min;
|
||||
},
|
||||
max: function() {
|
||||
return max;
|
||||
}
|
||||
};
|
||||
})(
|
||||
dataArray,
|
||||
Math.min.apply(
|
||||
Math,
|
||||
dataArray.map(function(o) {
|
||||
return o.x;
|
||||
})
|
||||
),
|
||||
Math.max.apply(
|
||||
Math,
|
||||
dataArray.map(function(o) {
|
||||
return o.x;
|
||||
})
|
||||
)
|
||||
),
|
||||
// value accessor
|
||||
(function(data, min, max) {
|
||||
var i = 0;
|
||||
return {
|
||||
hasNext: function() {
|
||||
return i < data.length;
|
||||
},
|
||||
next: function() {
|
||||
return data[i++].y;
|
||||
},
|
||||
reset: function() {
|
||||
i = 0;
|
||||
},
|
||||
min: function() {
|
||||
return min;
|
||||
},
|
||||
max: function() {
|
||||
return max;
|
||||
}
|
||||
};
|
||||
})(
|
||||
dataArray,
|
||||
Math.min.apply(
|
||||
Math,
|
||||
dataArray.map(function(o) {
|
||||
return o.y;
|
||||
})
|
||||
),
|
||||
Math.max.apply(
|
||||
Math,
|
||||
dataArray.map(function(o) {
|
||||
return o.y;
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
figure.appendChild(svg);
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
function lineGraph(parent,xAccessor,yAccessor){const width=620;const height=420;const gutter=40;const pixelsPerTick=30;function numericTransformer(dataMin,dataMax,pxMin,pxMax){var dataDiff=dataMax-dataMin,pxDiff=pxMax-pxMin,dataRatio=pxDiff/dataDiff,coordRatio=dataDiff/pxDiff;return{toCoord:function(data){return(data-dataMin)*dataRatio+pxMin;},toData:function(coord){return(coord-pxMin)*coordRatio+dataMin;}};}
|
||||
function axisRenderer(orientation,transform){var axisGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var axisPath=document.createElementNS("http://www.w3.org/2000/svg","path");axisGroup.setAttribute("class",orientation+"-axis");var xMin=gutter;var xMax=width-gutter;var yMin=height-gutter;var yMax=gutter;if(orientation==="x"){axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMax+" "+yMin);for(var i=xMin;i<=xMax;i++){if((i-xMin)%(pixelsPerTick*3)===0&&i!==xMin){var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=new Date(Math.floor(transform(i))).toLocaleTimeString();text.setAttribute("x",i);text.setAttribute("y",yMin);text.setAttribute("dy","1em");axisGroup.appendChild(text);}}}else{axisPath.setAttribute("d","M "+xMin+" "+yMin+" L "+xMin+" "+yMax);for(var i=yMax;i<=yMin;i++){if((i-yMin)%pixelsPerTick===0&&i!==yMin){var tickGroup=document.createElementNS("http://www.w3.org/2000/svg","g");var gridLine=document.createElementNS("http://www.w3.org/2000/svg","path");text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(transform(i));text.setAttribute("x",xMin);text.setAttribute("y",i);text.setAttribute("dx","-.5em");text.setAttribute("dy",".3em");gridLine.setAttribute("d","M "+xMin+" "+i+" L "+xMax+" "+i);tickGroup.appendChild(gridLine);tickGroup.appendChild(text);axisGroup.appendChild(tickGroup);}}}
|
||||
axisGroup.appendChild(axisPath);parent.appendChild(axisGroup);}
|
||||
function lineRenderer(xAccessor,yAccessor,xTransform,yTransform){var line=document.createElementNS("http://www.w3.org/2000/svg","path");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
|
||||
var pathString="M "+xTransform(xAccessor.next())+" "+yTransform(yAccessor.next());while(xAccessor.hasNext()&&yAccessor.hasNext()){pathString+=" L "+
|
||||
xTransform(xAccessor.next())+
|
||||
" "+
|
||||
yTransform(yAccessor.next());}
|
||||
line.setAttribute("class","series");line.setAttribute("d",pathString);parent.appendChild(line);}
|
||||
function pointRenderer(xAccessor,yAccessor,xTransform,yTransform){var pointGroup=document.createElementNS("http://www.w3.org/2000/svg","g");pointGroup.setAttribute("class","data-points");xAccessor.reset();yAccessor.reset();if(!xAccessor.hasNext()||!yAccessor.hasNext()){return;}
|
||||
while(xAccessor.hasNext()&&yAccessor.hasNext()){var xDataValue=xAccessor.next();var x=xTransform(xDataValue);var yDataValue=yAccessor.next();var y=yTransform(yDataValue);var circle=document.createElementNS("http://www.w3.org/2000/svg","circle");circle.setAttribute("cx",x);circle.setAttribute("cy",y);circle.setAttribute("r","4");var text=document.createElementNS("http://www.w3.org/2000/svg","text");text.innerHTML=Math.floor(xDataValue)+" / "+Math.floor(yDataValue);text.setAttribute("x",x);text.setAttribute("y",y);text.setAttribute("dx","1em");text.setAttribute("dy","-.7em");pointGroup.appendChild(circle);pointGroup.appendChild(text);}
|
||||
parent.appendChild(pointGroup);}
|
||||
xTransform=numericTransformer(xAccessor.min(),xAccessor.max(),0+gutter,width-gutter);yTransform=numericTransformer(yAccessor.min(),yAccessor.max(),height-gutter,0+gutter);axisRenderer("x",xTransform.toData);axisRenderer("y",yTransform.toData);lineRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);pointRenderer(xAccessor,yAccessor,xTransform.toCoord,yTransform.toCoord);}
|
||||
function renderGraphSvg(dataArray,renderId){var figure=document.getElementById(renderId);while(figure.hasChildNodes()){figure.removeChild(figure.lastChild);}
|
||||
var svg=document.createElementNS("http://www.w3.org/2000/svg","svg");svg.setAttribute("viewBox","0 0 640 440");svg.setAttribute("preserveAspectRatio","xMidYMid meet");lineGraph(svg,(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].x;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.x;})),Math.max.apply(Math,dataArray.map(function(o){return o.x;}))),(function(data,min,max){var i=0;return{hasNext:function(){return i<data.length;},next:function(){return data[i++].y;},reset:function(){i=0;},min:function(){return min;},max:function(){return max;}};})(dataArray,Math.min.apply(Math,dataArray.map(function(o){return o.y;})),Math.max.apply(Math,dataArray.map(function(o){return o.y;}))));figure.appendChild(svg);}
|
||||
@@ -0,0 +1,123 @@
|
||||
/* -----------------------------------------------------
|
||||
Material Design Sliders
|
||||
CodePen URL: https://codepen.io/rkchauhan/pen/xVGGpR
|
||||
By: Ravikumar Chauhan
|
||||
-------------------------------------------------------- */
|
||||
function rkmd_rangeSlider(selector) {
|
||||
var self, slider_width, slider_offset, curnt, sliderDiscrete, range, slider;
|
||||
self = $(selector);
|
||||
slider_width = self.width();
|
||||
slider_offset = self.offset().left;
|
||||
sliderDiscrete = self;
|
||||
|
||||
sliderDiscrete.each(function (i, v) {
|
||||
curnt = $(this);
|
||||
curnt.append(sliderDiscrete_tmplt());
|
||||
range = curnt.find('input[type="range"]');
|
||||
slider = curnt.find(".slider");
|
||||
slider_fill = slider.find(".slider-fill");
|
||||
slider_handle = slider.find(".slider-handle");
|
||||
slider_label = slider.find(".slider-label");
|
||||
|
||||
var range_val = parseInt(range.val());
|
||||
slider_fill.css("width", range_val + "%");
|
||||
slider_handle.css("left", range_val + "%");
|
||||
slider_label.find("span").text(range_val);
|
||||
});
|
||||
|
||||
self.on("mousedown touchstart", ".slider-handle", function (e) {
|
||||
if (e.button === 2) {
|
||||
return false;
|
||||
}
|
||||
var parents = $(this).parents(".rkmd-slider");
|
||||
var slider_width = parents.width();
|
||||
var slider_offset = parents.offset().left;
|
||||
var check_range = parents.find('input[type="range"]').is(":disabled");
|
||||
if (check_range === true) {
|
||||
return false;
|
||||
}
|
||||
$(this).addClass("is-active");
|
||||
var moveFu = function (e) {
|
||||
var pageX = e.pageX || e.changedTouches[0].pageX;
|
||||
var slider_new_width = pageX - slider_offset;
|
||||
if (slider_new_width <= slider_width && !(slider_new_width < "0")) {
|
||||
slider_move(parents, slider_new_width, slider_width, true);
|
||||
}
|
||||
};
|
||||
var upFu = function (e) {
|
||||
$(this).off(handlers);
|
||||
parents.find(".is-active").removeClass("is-active");
|
||||
};
|
||||
|
||||
var handlers = {
|
||||
mousemove: moveFu,
|
||||
touchmove: moveFu,
|
||||
mouseup: upFu,
|
||||
touchend: upFu,
|
||||
};
|
||||
$(document).on(handlers);
|
||||
});
|
||||
|
||||
self.on("mousedown touchstart", ".slider", function (e) {
|
||||
if (e.button === 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var parents = $(this).parents(".rkmd-slider");
|
||||
var slider_width = parents.width();
|
||||
var slider_offset = parents.offset().left;
|
||||
var check_range = parents.find('input[type="range"]').is(":disabled");
|
||||
|
||||
if (check_range === true) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var slider_new_width = e.pageX - slider_offset;
|
||||
if (slider_new_width <= slider_width && !(slider_new_width < "0")) {
|
||||
slider_move(parents, slider_new_width, slider_width, true);
|
||||
}
|
||||
var upFu = function (e) {
|
||||
$(this).off(handlers);
|
||||
};
|
||||
|
||||
var handlers = {
|
||||
mouseup: upFu,
|
||||
touchend: upFu,
|
||||
};
|
||||
$(document).on(handlers);
|
||||
});
|
||||
}
|
||||
|
||||
function sliderDiscrete_tmplt() {
|
||||
var tmplt =
|
||||
'<div class="slider">' +
|
||||
'<div class="slider-fill"></div>' +
|
||||
'<div class="slider-handle"><div class="slider-label"><span>0</span></div></div>' +
|
||||
"</div>";
|
||||
|
||||
return tmplt;
|
||||
}
|
||||
|
||||
function slider_move(parents, newW, sliderW, send) {
|
||||
var slider_new_val = parseInt(Math.round((newW / sliderW) * 100));
|
||||
|
||||
var slider_fill = parents.find(".slider-fill");
|
||||
var slider_handle = parents.find(".slider-handle");
|
||||
var range = parents.find('input[type="range"]');
|
||||
range.next().html(newW); // update value
|
||||
|
||||
slider_fill.css("width", slider_new_val + "%");
|
||||
slider_handle.css({
|
||||
left: slider_new_val + "%",
|
||||
transition: "none",
|
||||
"-webkit-transition": "none",
|
||||
"-moz-transition": "none",
|
||||
});
|
||||
|
||||
range.val(slider_new_val);
|
||||
if (parents.find(".slider-handle span").text() != slider_new_val) {
|
||||
parents.find(".slider-handle span").text(slider_new_val);
|
||||
var number = parents.attr("id").substring(2);
|
||||
if (send) websock.send("slvalue:" + slider_new_val + ":" + number);
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
function rkmd_rangeSlider(selector){var self,slider_width,slider_offset,curnt,sliderDiscrete,range,slider;self=$(selector);slider_width=self.width();slider_offset=self.offset().left;sliderDiscrete=self;sliderDiscrete.each(function(i,v){curnt=$(this);curnt.append(sliderDiscrete_tmplt());range=curnt.find('input[type="range"]');slider=curnt.find(".slider");slider_fill=slider.find(".slider-fill");slider_handle=slider.find(".slider-handle");slider_label=slider.find(".slider-label");var range_val=parseInt(range.val());slider_fill.css("width",range_val+"%");slider_handle.css("left",range_val+"%");slider_label.find("span").text(range_val);});self.on("mousedown touchstart",".slider-handle",function(e){if(e.button===2){return false;}
|
||||
var parents=$(this).parents(".rkmd-slider");var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(":disabled");if(check_range===true){return false;}
|
||||
$(this).addClass("is-active");var moveFu=function(e){var pageX=e.pageX||e.changedTouches[0].pageX;var slider_new_width=pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<"0")){slider_move(parents,slider_new_width,slider_width,true);}};var upFu=function(e){$(this).off(handlers);parents.find(".is-active").removeClass("is-active");};var handlers={mousemove:moveFu,touchmove:moveFu,mouseup:upFu,touchend:upFu,};$(document).on(handlers);});self.on("mousedown touchstart",".slider",function(e){if(e.button===2){return false;}
|
||||
var parents=$(this).parents(".rkmd-slider");var slider_width=parents.width();var slider_offset=parents.offset().left;var check_range=parents.find('input[type="range"]').is(":disabled");if(check_range===true){return false;}
|
||||
var slider_new_width=e.pageX-slider_offset;if(slider_new_width<=slider_width&&!(slider_new_width<"0")){slider_move(parents,slider_new_width,slider_width,true);}
|
||||
var upFu=function(e){$(this).off(handlers);};var handlers={mouseup:upFu,touchend:upFu,};$(document).on(handlers);});}
|
||||
function sliderDiscrete_tmplt(){var tmplt='<div class="slider">'+
|
||||
'<div class="slider-fill"></div>'+
|
||||
'<div class="slider-handle"><div class="slider-label"><span>0</span></div></div>'+
|
||||
"</div>";return tmplt;}
|
||||
function slider_move(parents,newW,sliderW,send){var slider_new_val=parseInt(Math.round((newW/sliderW)*100));var slider_fill=parents.find(".slider-fill");var slider_handle=parents.find(".slider-handle");var range=parents.find('input[type="range"]');range.next().html(newW);slider_fill.css("width",slider_new_val+"%");slider_handle.css({left:slider_new_val+"%",transition:"none","-webkit-transition":"none","-moz-transition":"none",});range.val(slider_new_val);if(parents.find(".slider-handle span").text()!=slider_new_val){parents.find(".slider-handle span").text(slider_new_val);var number=parents.attr("id").substring(2);if(send)websock.send("slvalue:"+slider_new_val+":"+number);}}
|
||||
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
* Tabs plugin for jQuery created by Òscar Casajuana < elboletaire at underave dot net >
|
||||
*
|
||||
* @copyright Copyright 2013-2016 Òscar Casajuana
|
||||
* @license MIT
|
||||
* @author Òscar Casajuana Alonso <elboletaire at underave dot net>
|
||||
*/
|
||||
;(function($, document, window, undefined) {
|
||||
"use strict";
|
||||
|
||||
var Tabbedcontent = function(tabcontent, options) {
|
||||
var defaults = {
|
||||
links : tabcontent.prev().find('a').length ? tabcontent.prev().find('a') : '.tabs a', // the tabs itself. By default it selects the links contained in the previous wrapper or the links inside ".tabs a" if there's no previous item
|
||||
errorSelector : '.error-message', // false to disable
|
||||
speed : false, // speed of the show effect. Set to null or false to disable
|
||||
onSwitch : false, // onSwitch callback
|
||||
onInit : false, // onInit callback
|
||||
currentClass : 'active', // current selected tab class (is set to the <a> element)
|
||||
tabErrorClass : 'has-errors', // a class to be added to the tab where errorSelector is detected
|
||||
history : true, // set to false to disable HTML5 history
|
||||
historyOnInit : true, // allows to deactivate the history for the intial autmatically tab switch on load
|
||||
loop : false // if set to true will loop between tabs when using the next() and prev() api methods
|
||||
},
|
||||
firstTime = false,
|
||||
children = tabcontent.children(),
|
||||
history = window.history,
|
||||
loc = document.location,
|
||||
current = null
|
||||
;
|
||||
|
||||
options = $.extend(defaults, options);
|
||||
|
||||
if (!(options.links instanceof $)) {
|
||||
options.links = $(options.links);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the specified tab id exists.
|
||||
*
|
||||
* @param string tab Tab #id
|
||||
* @return bool
|
||||
*/
|
||||
function tabExists(tab) {
|
||||
return Boolean(children.filter(tab).length);
|
||||
}
|
||||
/**
|
||||
* Checks if the current tab is the
|
||||
* first one in the tabs set.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function isFirst() {
|
||||
return current === 0;
|
||||
}
|
||||
/**
|
||||
* Checks if the passed number is an integer.
|
||||
*
|
||||
* @param mixed num The value to be checked.
|
||||
* @return bool
|
||||
*/
|
||||
function isInt(num) {
|
||||
return num % 1 === 0;
|
||||
}
|
||||
/**
|
||||
* Checks if the current tab is the
|
||||
* last one in the tabs set.
|
||||
*
|
||||
* @return {Boolean} [description]
|
||||
*/
|
||||
function isLast() {
|
||||
return current === children.length - 1;
|
||||
}
|
||||
/**
|
||||
* Filters a tab based on current links href.
|
||||
*
|
||||
* Method for compatibility with Zepto.js
|
||||
*
|
||||
* @param string tab Tab #href
|
||||
* @return bool
|
||||
*/
|
||||
function filterTab(tab) {
|
||||
return $(this).attr('href').match(new RegExp(tab + '$'));
|
||||
}
|
||||
/**
|
||||
* Returns an object containing two jQuery instances:
|
||||
* one for the tab content and the other for its link.
|
||||
*
|
||||
* @param mixed tab A tab id, #id or index.
|
||||
* @return object With thi
|
||||
*/
|
||||
function getTab(tab) {
|
||||
if (tab instanceof $) {
|
||||
return {
|
||||
tab : tab,
|
||||
link : options.links.eq(tab.index())
|
||||
};
|
||||
}
|
||||
if (isInt(tab)) {
|
||||
return {
|
||||
tab : children.eq(tab),
|
||||
link : options.links.eq(tab)
|
||||
};
|
||||
}
|
||||
if (children.filter(tab).length) {
|
||||
return {
|
||||
tab : children.filter(tab),
|
||||
link : options.links.filter(function() {
|
||||
return filterTab.apply(this, [tab]);
|
||||
})
|
||||
};
|
||||
}
|
||||
// assume it's an id without #
|
||||
return {
|
||||
tab : children.filter('#' + tab),
|
||||
link : options.links.filter(function() {
|
||||
return filterTab.apply(this, ['#' + tab]);
|
||||
})
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Returns the index of the current tab.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function getCurrent() {
|
||||
return options.links.parent().filter('.' + options.currentClass).index();
|
||||
}
|
||||
/**
|
||||
* Go to the next tab in the tabs set.
|
||||
*
|
||||
* @param bool loop If defined will overwrite options.loop
|
||||
* @return mixed
|
||||
*/
|
||||
function next(loop) {
|
||||
++current;
|
||||
|
||||
if (loop === undefined) loop = options.loop;
|
||||
|
||||
if (current < children.length) {
|
||||
return switchTab(current, true);
|
||||
} else if (loop && current >= children.length) {
|
||||
return switchTab(0, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Go to the previous tab in the tabs set.
|
||||
*
|
||||
* @param bool loop If defined will overwrite options.loop
|
||||
* @return mixed
|
||||
*/
|
||||
function prev(loop) {
|
||||
--current;
|
||||
|
||||
if (loop === undefined) loop = options.loop;
|
||||
|
||||
if (current >= 0) {
|
||||
return switchTab(current, true);
|
||||
} else if (loop && current < 0) {
|
||||
return switchTab(children.length - 1, true);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* onSwitch callback for switchTab.
|
||||
*
|
||||
* @param string tab The tab #id
|
||||
* @return void
|
||||
*/
|
||||
function onSwitch(tab) {
|
||||
if (options.history && options.historyOnInit && firstTime && history !== undefined && ('pushState' in history)) {
|
||||
firstTime = false;
|
||||
window.setTimeout(function() {
|
||||
history.replaceState(null, '', tab);
|
||||
}, 100);
|
||||
}
|
||||
current = getCurrent();
|
||||
if (options.onSwitch && typeof options.onSwitch === 'function') {
|
||||
options.onSwitch(tab, api());
|
||||
}
|
||||
tabcontent.trigger('tabcontent.switch', [tab, api()]);
|
||||
}
|
||||
/**
|
||||
* Switch to specified tab.
|
||||
*
|
||||
* @param mixed tab The tab to switch to.
|
||||
* @param bool api Set to true to force history writing.
|
||||
* @return bool Returns false if tab does not exist; true otherwise.
|
||||
*/
|
||||
function switchTab(tab, api) {
|
||||
if (!tab.toString().match(/^#/)) {
|
||||
tab = '#' + getTab(tab).tab.attr('id');
|
||||
}
|
||||
|
||||
if (!tabExists(tab)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Toggle active class
|
||||
options.links.attr('aria-selected','false').parent().removeClass(options.currentClass);
|
||||
options.links.filter(function() {
|
||||
return filterTab.apply(this, [tab]);
|
||||
}).attr('aria-selected','true').parent().addClass(options.currentClass);
|
||||
// Hide tabs
|
||||
children.hide();
|
||||
|
||||
// We need to force the change of the hash if we're using the API
|
||||
if (options.history && api) {
|
||||
if (history !== undefined && ('pushState' in history)) {
|
||||
history.pushState(null, '', tab);
|
||||
} else {
|
||||
// force hash change to add it to the history
|
||||
window.location.hash = tab;
|
||||
}
|
||||
}
|
||||
|
||||
// Show tabs
|
||||
children.attr('aria-hidden','true').filter(tab).show(options.speed, function() {
|
||||
if (options.speed) {
|
||||
onSwitch(tab);
|
||||
}
|
||||
}).attr('aria-hidden','false');
|
||||
if (!options.speed) {
|
||||
onSwitch(tab);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* Api method to switch tabs.
|
||||
*
|
||||
* @param mixed tab Tab to switch to.
|
||||
* @return bool Returns false if tab does not exist; true otherwise.
|
||||
*/
|
||||
function apiSwitch(tab) {
|
||||
return switchTab(tab, true);
|
||||
}
|
||||
/**
|
||||
* Method used to switch tabs using the
|
||||
* browser query hash.
|
||||
*
|
||||
* @param object e Event.
|
||||
* @return void
|
||||
*/
|
||||
function hashSwitch(e) {
|
||||
switchTab(loc.hash);
|
||||
}
|
||||
/**
|
||||
* Initialization method.
|
||||
*
|
||||
* The tab checking preference is:
|
||||
* - document.location.hash
|
||||
* - options.errorSelector
|
||||
* - first tab in the set of tabs
|
||||
*
|
||||
* The onInit method is called at the
|
||||
* end of this method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function init() {
|
||||
// Switch to tab using location.hash
|
||||
if (tabExists(loc.hash)) {
|
||||
// Switch to current hash tab
|
||||
switchTab(loc.hash);
|
||||
}
|
||||
// If there's a tab link with the options.currentClass set,
|
||||
// switch to that tab.
|
||||
else if (options.links.parent().filter('.' + options.currentClass).length) {
|
||||
switchTab(options.links.parent().filter('.' + options.currentClass).index());
|
||||
}
|
||||
// Switch to tab containing class options.errorSelector
|
||||
else if (options.errorSelector && children.find(options.errorSelector).length) {
|
||||
// Search for errors and show first tab containing one
|
||||
children.each(function() {
|
||||
if ($(this).find(options.errorSelector).length) {
|
||||
switchTab("#" + $(this).attr("id"));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
// Open first tab
|
||||
else {
|
||||
switchTab("#" + children.filter(":first-child").attr("id"));
|
||||
}
|
||||
// Add a class to every tab containing errors
|
||||
if (options.errorSelector) {
|
||||
children.find(options.errorSelector).each(function() {
|
||||
var tab = getTab($(this).parent());
|
||||
tab.link.parent().addClass(options.tabErrorClass);
|
||||
});
|
||||
}
|
||||
|
||||
// Binding
|
||||
if ('onhashchange' in window) {
|
||||
$(window).bind('hashchange', hashSwitch);
|
||||
} else { // old browsers
|
||||
var current_href = loc.href;
|
||||
window.setInterval(function() {
|
||||
if (current_href !== loc.href) {
|
||||
hashSwitch.call(window.event);
|
||||
current_href = loc.href;
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
// Bind click event on links, to ensure we don't rewrite the URI in
|
||||
// case history is disabled
|
||||
$(options.links).on('click', function(e) {
|
||||
switchTab($(this).attr('href').replace(/^[^#]+/, ''), options.history);
|
||||
e.preventDefault();
|
||||
});
|
||||
|
||||
// onInit callback
|
||||
if (options.onInit && typeof options.onInit === 'function') {
|
||||
options.onInit(api());
|
||||
}
|
||||
tabcontent.trigger('tabcontent.init', [api()]);
|
||||
}
|
||||
/**
|
||||
* Returns the methods exposed in the api.
|
||||
*
|
||||
* @return object Containing each api method.
|
||||
*/
|
||||
function api() {
|
||||
return {
|
||||
'switch' : apiSwitch,
|
||||
'switchTab' : apiSwitch, // for old browsers
|
||||
'getCurrent' : getCurrent,
|
||||
'getTab' : getTab,
|
||||
'next' : next,
|
||||
'prev' : prev,
|
||||
'isFirst' : isFirst,
|
||||
'isLast' : isLast
|
||||
};
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
return api();
|
||||
};
|
||||
|
||||
$.fn.tabbedContent = function(options) {
|
||||
return this.each(function() {
|
||||
var tabs = new Tabbedcontent($(this), options);
|
||||
$(this).data('api', tabs);
|
||||
});
|
||||
};
|
||||
|
||||
})(window.jQuery || window.Zepto || window.$, document, window);
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
;(function($,document,window,undefined){"use strict";var Tabbedcontent=function(tabcontent,options){var defaults={links:tabcontent.prev().find('a').length?tabcontent.prev().find('a'):'.tabs a',errorSelector:'.error-message',speed:false,onSwitch:false,onInit:false,currentClass:'active',tabErrorClass:'has-errors',history:true,historyOnInit:true,loop:false},firstTime=false,children=tabcontent.children(),history=window.history,loc=document.location,current=null;options=$.extend(defaults,options);if(!(options.links instanceof $)){options.links=$(options.links);}
|
||||
function tabExists(tab){return Boolean(children.filter(tab).length);}
|
||||
function isFirst(){return current===0;}
|
||||
function isInt(num){return num%1===0;}
|
||||
function isLast(){return current===children.length-1;}
|
||||
function filterTab(tab){return $(this).attr('href').match(new RegExp(tab+'$'));}
|
||||
function getTab(tab){if(tab instanceof $){return{tab:tab,link:options.links.eq(tab.index())};}
|
||||
if(isInt(tab)){return{tab:children.eq(tab),link:options.links.eq(tab)};}
|
||||
if(children.filter(tab).length){return{tab:children.filter(tab),link:options.links.filter(function(){return filterTab.apply(this,[tab]);})};}
|
||||
return{tab:children.filter('#'+tab),link:options.links.filter(function(){return filterTab.apply(this,['#'+tab]);})};}
|
||||
function getCurrent(){return options.links.parent().filter('.'+options.currentClass).index();}
|
||||
function next(loop){++current;if(loop===undefined)loop=options.loop;if(current<children.length){return switchTab(current,true);}else if(loop&¤t>=children.length){return switchTab(0,true);}
|
||||
return false;}
|
||||
function prev(loop){--current;if(loop===undefined)loop=options.loop;if(current>=0){return switchTab(current,true);}else if(loop&¤t<0){return switchTab(children.length-1,true);}
|
||||
return false;}
|
||||
function onSwitch(tab){if(options.history&&options.historyOnInit&&firstTime&&history!==undefined&&('pushState'in history)){firstTime=false;window.setTimeout(function(){history.replaceState(null,'',tab);},100);}
|
||||
current=getCurrent();if(options.onSwitch&&typeof options.onSwitch==='function'){options.onSwitch(tab,api());}
|
||||
tabcontent.trigger('tabcontent.switch',[tab,api()]);}
|
||||
function switchTab(tab,api){if(!tab.toString().match(/^#/)){tab='#'+getTab(tab).tab.attr('id');}
|
||||
if(!tabExists(tab)){return false;}
|
||||
options.links.attr('aria-selected','false').parent().removeClass(options.currentClass);options.links.filter(function(){return filterTab.apply(this,[tab]);}).attr('aria-selected','true').parent().addClass(options.currentClass);children.hide();if(options.history&&api){if(history!==undefined&&('pushState'in history)){history.pushState(null,'',tab);}else{window.location.hash=tab;}}
|
||||
children.attr('aria-hidden','true').filter(tab).show(options.speed,function(){if(options.speed){onSwitch(tab);}}).attr('aria-hidden','false');if(!options.speed){onSwitch(tab);}
|
||||
return true;}
|
||||
function apiSwitch(tab){return switchTab(tab,true);}
|
||||
function hashSwitch(e){switchTab(loc.hash);}
|
||||
function init(){if(tabExists(loc.hash)){switchTab(loc.hash);}
|
||||
else if(options.links.parent().filter('.'+options.currentClass).length){switchTab(options.links.parent().filter('.'+options.currentClass).index());}
|
||||
else if(options.errorSelector&&children.find(options.errorSelector).length){children.each(function(){if($(this).find(options.errorSelector).length){switchTab("#"+$(this).attr("id"));return false;}});}
|
||||
else{switchTab("#"+children.filter(":first-child").attr("id"));}
|
||||
if(options.errorSelector){children.find(options.errorSelector).each(function(){var tab=getTab($(this).parent());tab.link.parent().addClass(options.tabErrorClass);});}
|
||||
if('onhashchange'in window){$(window).bind('hashchange',hashSwitch);}else{var current_href=loc.href;window.setInterval(function(){if(current_href!==loc.href){hashSwitch.call(window.event);current_href=loc.href;}},100);}
|
||||
$(options.links).on('click',function(e){switchTab($(this).attr('href').replace(/^[^#]+/,''),options.history);e.preventDefault();});if(options.onInit&&typeof options.onInit==='function'){options.onInit(api());}
|
||||
tabcontent.trigger('tabcontent.init',[api()]);}
|
||||
function api(){return{'switch':apiSwitch,'switchTab':apiSwitch,'getCurrent':getCurrent,'getTab':getTab,'next':next,'prev':prev,'isFirst':isFirst,'isLast':isLast};}
|
||||
init();return api();};$.fn.tabbedContent=function(options){return this.each(function(){var tabs=new Tabbedcontent($(this),options);$(this).data('api',tabs);});};})(window.jQuery||window.Zepto||window.$,document,window);
|
||||
+2
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user