From 5929f0c7f6af6503d356cc1609228003749ef867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?LA7ECA=2C=20=C3=98yvind?= Date: Sat, 16 Mar 2024 17:41:39 +0100 Subject: [PATCH] Update the webapp --- webapp/arcticsetup-min.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/webapp/arcticsetup-min.js b/webapp/arcticsetup-min.js index d863fa2..07bb2b1 100644 --- a/webapp/arcticsetup-min.js +++ b/webapp/arcticsetup-min.js @@ -1,12 +1,12 @@ var pol=pol||{};pol.security=pol.security||{};pol.security.bin2base64=function(arr){const abc="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";const bin=n=>n.toString(2).padStart(8,0);const l=arr.length;let result="";for(let i=0;i<=(l-1)/3;i++){let c1=i*3+1>=l;let c2=i*3+2>=l;let chunk=bin(arr[3*i])+bin(c1?0:arr[3*i+1])+bin(c2?0:arr[3*i+2]);let r=chunk.match(/.{1,6}/g).map((x,j)=>j==3&&c2?"=":j==2&&c1?"=":abc[+("0b"+x)]);result+=r.join("")}return result};pol.security.hmac_getKey=async function(secret){const enc=new TextEncoder("utf-8");const algorithm={name:"HMAC",hash:"SHA-256"};const _key=await crypto.subtle.importKey("raw",enc.encode(secret),algorithm,false,["sign","verify"]);return _key};pol.security.hmac_Sha256_B64=async function(key,message){const enc=new TextEncoder("utf-8");const algorithm={name:"HMAC",hash:"SHA-256"};const hashBuffer=await crypto.subtle.sign(algorithm.name,key,enc.encode(message));const hashArray=Array.from(new Uint8Array(hashBuffer));const hashHex=pol.security.bin2base64(hashArray);return hashHex};pol.security.Sha256_B64=async function(message){const enc=new TextEncoder("utf-8");const hashBuffer=await crypto.subtle.digest("SHA-256",enc.encode(message));const hashArray=Array.from(new Uint8Array(hashBuffer));const hashHex=await pol.security.bin2base64(hashArray);return hashHex};pol.security.getRandom=function(n){const rnd=new Uint8Array(n);crypto.getRandomValues(rnd);return pol.security.bin2base64(rnd)}; var pol=pol||{};pol.core=pol.core||{};pol.ui=pol.ui||{};pol.widget={};pol.widget._stored={};pol.widget._active={};pol.widget._factory={};pol.widget.setFactory=function(id,arg){pol.widget._factory[id]=arg};pol.widget.restore=function(){pol.widget._stored=CONFIG.get("core.widget._stored");if(pol.widget._stored==null)pol.widget._stored={};for(const x in pol.widget._stored){if(pol.widget._stored[x]==null)continue;const w=pol.widget.get(x);pol.widget._active[x]=w;const pos=CONFIG.get("core.widget."+x);if(w!=null)w.activatePopup(x,pos,true);const fact=pol.widget._factory[x];if(!fact||!fact.create){CONFIG.remove("core.widget."+x);delete pol.widget._stored[x];CONFIG.store("core.widget._stored",pol.widget._stored,true);continue}if(fact.onRestore&&fact.onRestore!=null)fact.onRestore()}};pol.widget.get=function(id){let x=pol.widget._active[id];const fact=pol.widget._factory[id];if(!fact||!fact.create){console.warn("No factory found for: "+id);return null}if(!x)x=pol.widget._active[id]=fact.create();return x};pol.widget.start=function(id,pos,pinned,saved,f){const x=pol.widget.get(id);if(x==null)return;x.activatePopup(id,pos,pinned,saved);if(f&&f!=null)setTimeout(()=>f(x),300)};pol.core.Widget=class{constructor(){this.pos=null;this.saved=true;this.classname=null;this.active=false;this._allowPopup=true;this.rs_running=false;this.rs_to=null;this.rs_func=null;this.rs_first=true;this.rs_ro=new ResizeObserver(entries=>{for(let entry of entries){if(this.rs_running&&this.rs_to!=null)clearTimeout(this.rs_to);this.rs_running=true;this.rs_to=setTimeout(()=>{if(this.rs_first==true){this.rs_first=false;return}if(this.rs_func)this.rs_func();this.rs_running=false;this.rs_to=null},400)}})}resizeObserve(func){this.rs_ro.observe($("#map").get(0));this.rs_func=func}isActive(){return this.active}allowPopup(allow){this._allowPopup=allow}activate(w){console.assert(w&&w!=null,"w="+w);this.delement=w;m.mount(this.delement,this.widget);this.delement.addEventListener("unload",this.onclose);this.active=true;if(this.onActivate)this.onActivate()}onclose(){this.rs_ro.disconnect()}activatePopup(id,pixPos,pinned,saved){console.assert(id!=null&&pixPos!=null&&pixPos[0]>=0&&pixPos[1]>=0,"id="+id+", pixPos="+pixPos);if(!this._allowPopup)return null;if(pixPos==null)pixPos=[20,20];const t=this;this.pos=pixPos;t.saved=saved;t.active=true;t.errmsg="";if(t.onActivate)t.onActivate();this.popup=browser.gui.showPopup({vnode:this.widget,pixPos:pixPos,draggable:true,dragStop:dragStop,pin:saveCb,pinned:pinned,id:id,cclass:"widget",onclose:()=>{unSave();t.active=false;t.onclose()}});if(this.popup&&this.popup!=null&&this.popup.adjustedPos)t.pos=this.popup.adjustedPos;t.close=()=>{this.popup.close()};return this.popup;function saveCb(p){if(!t.saved)return;if(p)save();else unSave()}function dragStop(event,ui){t.pos=[ui.position.left,ui.position.top];if(t.saved)save()}function save(){CONFIG.store("core.widget."+id,t.pos,true);if(!pol.widget._stored[id]||pol.widget._stored[id]==null){pol.widget._stored[id]=true;CONFIG.store("core.widget._stored",pol.widget._stored,true)}}function unSave(){CONFIG.remove("core.widget."+id,t.pos);if(pol.widget._stored[id]&&pol.widget._stored[id]!=null){delete pol.widget._stored[id];CONFIG.store("core.widget._stored",pol.widget._stored,true)}}}setScrollTable(topdiv,searchresult){let ht=$("#map").height()-($(topdiv).height()-$(searchresult).height())-this.pos[1]-8;setTimeout(()=>{if($(searchresult).height(){let ht=$("#map").height()-($(topdiv).height()-elem.height())-this.pos[1]-20;if(elem.height()>ht){const hht=elem.height();elem.css({"display":"block","overflow-y":"auto","overflow-x":"hidden","height":""+Math.round(ht)});if(scrollBottom)elem.scrollTop(hht)}},100)}error(txt,x){var msg=txt;if(x!=null)if(x.status!=null&&x.status==401)msg="Access denied: "+x.responseText;else if(x.message!=null)msg=x.message;this.errmsg=msg;console.warn(msg);m.redraw()}clearerr(){this.errmsg="";m.redraw()}}; -var pol=pol||{};pol.core=pol.core||{};pol.core.ajax=(type,service,data,success,error)=>{return $.ajax(service,{type:type,data:data,success:success,error:error,contentType:false,processData:type!="POST",crossDomain:true,xhrFields:{withCredentials:false}})};pol.core.Server=class{constructor(id){const t=this;t.id="NOCALL";t.url="";t.setId(id);t.key=null;datastore.getItem("arctic.key."+t.id).then(x=>{t.key=x})}ajax(type,service,data,success,error){const nonce=pol.security.getRandom(8);data=data==null?"":data;if(this.key==null){console.warn("KEY NOT SET");error({message:"Key not set"});return}this.getHmac(nonce,data).then(hash=>{this._ajax(type,service,data,success,error,{"Arctic-Nonce":nonce,"Arctic-Hmac":hash})}).catch(e=>{console.log("ERROR",e)})}_ajax(type,service,data,success,error,headers){return $.ajax(this.url+service,{type:type,data:data,success:success,error:error,contentType:false,processData:type!="POST",crossDomain:true,xhrFields:{withCredentials:true},headers:headers})}async getHmac(nonce,message){let msgHash="";if(this.key==null)return null;if(message!=null&&message!="")msgHash=await pol.security.Sha256_B64(message);return await pol.security.hmac_Sha256_B64(this.key,nonce+msgHash)}async setKey(secret){await pol.security.hmac_getKey(secret).then(x=>{this.key=x;console.log("setKey: "+x);datastore.setItem("arctic.key."+this.id,x)});return true}removeKey(){datastore.removeItem("arctic.key."+this.id);this.key=null}setUrl(u){console.log("setUrl: "+u);this.url=u}setId(id){this.id=id;if(/http(s)?:\/\//.test(id))this.setUrl(id);else if(/[A-Za-z0-9\-]+$/.test(id))this.setUrl("https://Arctic-"+id.toUpperCase()+".local/");else this.setUrl("https://"+id+"/")}GET(service,data,success,error){return this.ajax("GET",service,data,success,error)}POST(service,data,success,error){return this.ajax("POST",service,data,success,error)}PUT(service,data,success,error){return this.ajax("PUT",service,data,success,error)}DELETE(service,success,error){return this.ajax("DELETE",service,null,success,error)}}; +var pol=pol||{};pol.core=pol.core||{};pol.core.ajax=(type,service,data,success,error)=>{return $.ajax(service,{type:type,data:data,success:success,error:error,contentType:false,processData:type!="POST",crossDomain:true,xhrFields:{withCredentials:false}})};pol.core.Server=class{constructor(id){const t=this;t.id="NOCALL";t.url="";t.setId(id);t.key=null;datastore.getItem("arctic.key."+t.id).then(x=>{t.key=x})}ajax(type,service,data,success,error){const nonce=pol.security.getRandom(8);data=data==null?"":data;if(this.key==null){console.warn("KEY NOT SET");error({message:"Key not set"});return}this.getHmac(nonce,data).then(hash=>{this._ajax(type,service,data,success,error,{"Arctic-Nonce":nonce,"Arctic-Hmac":hash})}).catch(e=>{console.log("ERROR",e)})}_ajax(type,service,data,success,error,headers){return $.ajax(this.url+service,{type:type,data:data,success:success,error:error,contentType:false,processData:type!="POST",crossDomain:true,xhrFields:{withCredentials:true},headers:headers})}async getHmac(nonce,message){let msgHash="";if(this.key==null)return null;if(message!=null&&message!="")msgHash=await pol.security.Sha256_B64(message);return await pol.security.hmac_Sha256_B64(this.key,nonce+msgHash)}async setKey(secret){await pol.security.hmac_getKey(secret).then(x=>{this.key=x;datastore.setItem("arctic.key."+this.id,x)});return true}removeKey(){datastore.removeItem("arctic.key."+this.id);this.key=null}setUrl(u){console.log("setUrl: "+u);this.url=u}setId(id){this.id=id;if(/http(s)?:\/\//.test(id))this.setUrl(id);else if(/[A-Za-z0-9\-]+$/.test(id))this.setUrl("https://Arctic-"+id.toUpperCase()+".local/");else this.setUrl("https://"+id+"/")}GET(service,data,success,error){return this.ajax("GET",service,data,success,error)}POST(service,data,success,error){return this.ajax("POST",service,data,success,error)}PUT(service,data,success,error){return this.ajax("PUT",service,data,success,error)}DELETE(service,success,error){return this.ajax("DELETE",service,null,success,error)}}; const br=m("br");const hr=m("hr");const nbsp=m.trust(" ");const textInput={view:function(vn){var t=this;var type=!vn.attrs.passwd||vn.attrs.passwd==false?"text":"password";return m("input#"+vn.attrs.id,{type:type,list:vn.attrs.list,config:vn.attrs.config,size:vn.attrs.size,maxLength:vn.attrs.maxLength,contentEditable:vn.attrs.contentEditable?vn.attrs.contentEditable:true,oninput:function(ev){vn.attrs.value(ev.target.value);if(!vn.attrs.regex)return;if(vn.attrs.regex.test(ev.target.value)){vn.state.cssclass="valid";vn.dom.title="Input OK";$(vn.dom).attr("ok",true)}else{vn.state.cssclass="invalid";vn.dom.title="Invalid input!";$(vn.dom).attr("ok",false)}},onchange:function(ev){vn.attrs.value(ev.target.value);t.cssclass="";if(vn.attrs.onchange!=null)vn.attrs.onchange()},value:vn.attrs.value(),className:t.cssclass?t.cssclass:""})}};const checkBox={view:function(vn){return m("span.nobr",{title:vn.attrs.title},m("input#"+vn.attrs.id,{onclick:vn.attrs.onclick,type:"checkbox",name:vn.attrs.name,value:vn.attrs.id,checked:vn.attrs.checked?"checked":null,onchange:vn.attrs.onchange}),nbsp,vn.children)}};const select={view:function(vn){return m("select#"+vn.attrs.id,{onchange:vn.attrs.onchange},vn.attrs.list.map(x=>m("option",{value:x.val,style:x.style},x.label)))}};const iconPick={oncreate:function(vn){const inp=vn.state;inp.id=vn.attrs.id},doSelect:function(vn,x){vn.state.selected=x;$("div#iconlist").css("visibility","hidden");$("div#iconlist").css("max-height","1px");$("#iconpick").get(0).value=x},showIcons:function(){$("div#iconlist").css("visibility","visible");$("div#iconlist").css("max-height","")},view:function(vn){const icons=vn.attrs.icons;const dfl=vn.attrs.default?vn.attrs.default:0;const xx=vn.attrs.value&&vn.attrs.value!=null?vn.attrs.value:icons[dfl];const yy=vn.state.selected?vn.state.selected:xx;setTimeout(()=>{if(yy&&$("#iconpick").get(0))$("#iconpick").get(0).value=yy},600);return m("span",[m("span#iconpick",{onclick:()=>this.showIcons(),onchange:()=>{vn.state.selected=$("#iconpick>img").val()}},m("img",{src:yy})),m("div#iconlist",{style:"max-height: 1px"},icons.map(x=>{return m("img",{src:x,onclick:()=>this.doSelect(vn,x)})}))])}};const Datepick={oncreate:function(vn){const input=document.createElement("input");input.readOnly=true;input.id=vn.attrs.id;input.value=vn.attrs.value;vn.dom.appendChild(input);new Pikaday({field:input,format:"YYYY-MM-DD"})},onchange:function(vn){vn.attrs.value=input.value},view:function(vn){return m("span.datepick")}};const dateTimeInput={view:function(vn){return m("span",m(Datepick,{value:vn.attrs.dvalue,id:vn.attrs.id+"_date"}),m(textInput,{id:vn.attrs.id+"_time",size:"5",maxLength:"5",value:vn.attrs.tvalue,regex:/^(([0-1][0-9])|(2[0-3]))\:[0-5][0-9]$/}))}};const removeEdit={view:vn=>{return m("span.removeEdit",[m("img",{src:"images/edit-delete.png",onclick:vn.attrs.remove}),m("img",{src:"images/edit.png",onclick:vn.attrs.edit})])}};function dragdrop(element,onchange){element.addEventListener("dragover",activate);element.addEventListener("dragleave",deactivate);element.addEventListener("dragend",deactivate);element.addEventListener("drop",deactivate);element.addEventListener("drop",update);window.addEventListener("blur",deactivate);function activate(e){e.preventDefault();$(element).addClass("dragover")}function deactivate(){$(element).removeClass("dragover")}function update(e){e.preventDefault();if(typeof onchange=="function"){onchange(e.dataTransfer||e.target)}}}function formatDTG(date){const mths=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];const ltime=new Date(date);const mth=mths[ltime.getMonth()];const day=ltime.getDate();const hour=ltime.getHours();const min=ltime.getMinutes();return day+" "+mth+" "+hour+":"+(min<=9?"0":"")+min} -pol.core.keySetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.keySetup";t.myTrackers=[];t.myServers=[];t.selected=-1;t.trackerid=m.stream("");t.key=m.stream("");t.auth=false;t.dirty=false;this.widget={view:function(){let i=0;return m("div",[m("h1","Access and Key setup"),m("div.itemList",t.myTrackers.map(x=>{const cls=x.access?"allowed":x.denied?"denied":x.active?"active":"unknown";return[m("span.box",[m("img",{src:"img/delete.png",onclick:apply(y=>t.removeTracker(y),i)}),m("span."+cls,{onclick:apply(_select,i++)},x.id),nbsp])," "]})),m("form.key",[br,m("div.field",m("span.leftlab","Tracker id: "),m(textInput,{value:t.trackerid,size:15,maxLength:32,onchange:dirty,regex:/^[a-zA-Z0-9\-\.]+$/i})),m("div.field",{className:"key"},m("span.leftlab","Server key: "),m(textInput,{value:t.key,size:32,maxLength:128,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","Key set: "),m("span",t.hasKey()?"Yes":"No")),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Clear"),m("button",{type:"button",onclick:add},"Add"),m("span.errmsg",t.errmsg))])])}};datastore.getItem("arctic.mytrackers").then(x=>{t.myTrackers=x;if(t.myTrackers==null)t.myTrackers=[];else t.selected=0;for(const i in t.myTrackers)t.myServers[i]=new pol.core.Server(t.myTrackers[i].id);m.redraw()});datastore.getItem("arctic.selected").then(x=>{if(x<0)return;t.selected=x;m.redraw()});setTimeout(scanTrackers,2000);setInterval(scanTrackers,20000);setInterval(scanMdns,25000);function _select(i){t.select(i);datastore.setItem("arctic.selected",i)}function scanTrackers(){for(const i in t.myTrackers)t.pingTracker(i);m.redraw()}function scanMdns(){for(const i in t.myTrackers)if(t.myTrackers[i]&&t.myTrackers[i].server&&typeof t.myTrackers[i].server.GET=="function"&&t.myTrackers[i].access==true){t.getMdns(i);break}}function add(){t.addTracker(t.trackerid());t.dirty=false}function update(){if(t.trackerid()!=""){t.getSelected().id=t.trackerid();t.getSelectedSrv().setId(t.trackerid());t.dirty=false}if(t.key()=="")return;t.getSelectedSrv().setKey(t.key()).then(()=>{t.key("");t.dirty=false;t.getInfo()});m.redraw()}function dirty(){t.dirty=true}function reset(){t.key("");t.getSelected().removeKey()}function apply(f,id){return function(){f(id)}};}getSelected(){return this.myTrackers[this.selected]}getSelectedSrv(){return this.myServers[this.selected]}select(i){if(i==null||i<0)return;const tr=this.myTrackers[i];if(!tr.server||tr.server==null)tr.server=new pol.core.Server(tr.id);if(i==this.selected&&this.myTrackers[i].access){setTimeout(show("core.statusInfo"),500);return}this.selected=i;this.trackerid(this.getSelected().id);this.key("");datastore.setItem("arctic.selected",i)}selectNext(){if(this.myTrackers.length<=1)return;let i=this.selected;let orig=i;do{i=(i+1)%this.myTrackers.length;this.select(i)}while(!this.isAvailable()&&i!=orig)}selectPrev(){if(this.myTrackers.length<=1)return;let i=this.selected;let orig=i;do{i=i-1;if(i<0)i=this.myTrackers.length-1;this.select(i)}while(!this.isAvailable()&&i!=orig)}addTracker(id){id=id.toUpperCase();if(this.exists(id)){return false}const i=this.myTrackers.push({id:id,access:false,denied:false})-1;const j=this.myServers.push(new pol.core.Server(id));if(i!=j)console.error("Tracker-list doesn't correspond to server-list");this.dirty=false;datastore.setItem("arctic.mytrackers",this.myTrackers);m.redraw();console.log("Added tracker: "+id+" trying to ping it.",i);this.pingTracker(i);return true}removeTracker(i){console.log("removeTracker: "+i);this.myTrackers.splice(i,1);this.myServers.splice(i,1);datastore.setItem("arctic.mytrackers",this.myTrackers);if(this.selected>=i)this.selected--;datastore.setItem("arctic.selected",this.selected)}pingTracker(i){const t=this;t.myTrackers[i].access=false;this.dirty=false;if(t.myServers[i].key!=null)t.getInfo(i)}exists(tr){for(const x of this.myTrackers)if(x.id==tr)return true;return false}hasKey(){return this.getSelected()&&this.getSelected().server&&this.getSelected().server.key!=null}isAuth(){return this.auth}isAvailable(){return this.auth&&this.getSelected().access}setAuth(i,a,d){if(i==this.selected)this.auth=a;if(i<0)i=this.selected;if(i>=0){this.myTrackers[i].access=a;this.myTrackers[i].denied=d}m.redraw()}showError(i,x){if(i==this.selected)this.error(x)}getInfo(i){let srv=null;let t=this;this.clearerr();srv=t.getSelectedSrv();console.log("SRV: ",srv);let auth_ok=false;setTimeout(()=>{if(auth_ok==false){t.setAuth(i,false,false);t.showError(i,"Timeout (no response)")}},10000);srv.GET("api/info",null,st=>{t.setAuth(i,true,false);auth_ok=true;m.redraw()},(x,y,z)=>{const denied=x.status!=null&&x.status==401;t.setAuth(i,false,denied);m.redraw();if(denied)t.showError(i,"Access denied");else t.showError(i,"Cannot GET data (se browser log)",x)})}getMdns(i){let srv=null;let t=this;if(!i||i==-1)srv=server;else srv=t.myTrackers[i].server;srv.GET("api/trackers",null,ttr=>{const tr=JSON.parse(ttr);if(tr==null||tr.length==0)return;for(const tt of tr){const id=tt.host.split(/[Aa]rctic-/);if(id[1]){if(t.addTracker(id[1]))console.log("MDNS TRACKER: ",tt.name,tt.host,tt.port)}}},x=>{})}};pol.widget.setFactory("core.keySetup",{create:()=>new pol.core.keySetup}); +pol.core.keySetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.keySetup";t.myTrackers=[];t.myServers=[];t.selected=-1;t.trackerid=m.stream("");t.key=m.stream("");t.auth=false;t.dirty=false;t.editmode=false;this.widget={view:function(){let i=0;return m("div",[m("h1","Access and Key setup"),m("div.itemList",t.myTrackers.map(x=>{const cls=x.access?"allowed":x.denied?"denied":x.active?"active":"unknown";return[m("span.box",[m("img",{src:"img/delete.png",onclick:apply(y=>t.removeTracker(y),i)}),m("span."+cls,{onclick:apply(_select,i++)},x.id),nbsp])," "]})),m("form.key",[br,m("div.field",m("span.leftlab","Tracker id: "),m(textInput,{value:t.trackerid,size:15,maxLength:32,onchange:dirtyid,regex:/^[a-zA-Z0-9\-\.]+$/i})),m("div.field",{className:"key"},m("span.leftlab","Server key: "),m(textInput,{value:t.key,size:32,maxLength:128,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","Key set: "),m("span",t.hasKey()?"Yes":"No")),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",disabled:t.editmode,onclick:add},"Add"),m("button",{type:"button",disabled:!t.editmode,onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Clear"),m("span.errmsg",t.errmsg))])])}};datastore.getItem("arctic.mytrackers").then(x=>{t.myTrackers=x;if(t.myTrackers==null)t.myTrackers=[];else t.selected=0;for(const i in t.myTrackers){t.setAuth(i,false,false);t.myServers[i]=new pol.core.Server(t.myTrackers[i].id)}m.redraw();console.log("myTrackers/myServers",t.myTrackers,t.myServers)});datastore.getItem("arctic.selected").then(x=>{if(x<0)return;t.selected=x;m.redraw()});setTimeout(scanTrackers,2000);setInterval(scanTrackers,25000);setInterval(scanMdns,25000);$("#trackerid").change(()=>{alert("bert")});function _select(i){t.select(i);datastore.setItem("arctic.selected",i)}function scanTrackers(){for(const i in t.myTrackers)t.pingTracker(i);m.redraw()}function scanMdns(){for(const i in t.myTrackers)if(t.myTrackers[i]&&t.myServers[i]&&t.myTrackers[i].access==true){t.getMdns(i);break}}function add(){t.addTracker(t.trackerid());t.dirty=false}function update(){if(t.trackerid()!=""){t.getSelected().id=t.trackerid();t.getSelectedSrv().setId(t.trackerid());t.dirty=false}if(t.key()=="")return;t.setKey(t.key());m.redraw()}function dirty(){t.dirty=true}function dirtyid(){t.editmode=false}function reset(){t.trackerid("");t.key("");t.editmode=false}function apply(f,id){return function(){f(id)}};}getSelected(){return this.myTrackers[this.selected]}getSelectedSrv(){return this.myServers[this.selected]}select(i){if(i==null||i<0)return;const tr=this.myTrackers[i];if(!tr.server||tr.server==null)tr.server=new pol.core.Server(tr.id);this.selected=i;this.editmode=true;this.trackerid(this.getSelected().id);this.key("");datastore.setItem("arctic.selected",i)}selectNext(){if(this.myTrackers.length<=1)return;let i=this.selected;let orig=i;do{i=(i+1)%this.myTrackers.length}while(this.isAvailable(i)==false&&i!=orig);this.select(i)}selectPrev(){if(this.myTrackers.length<=1)return;let i=this.selected;let orig=i;do{i=i-1;if(i<0)i=this.myTrackers.length-1}while(this.isAvailable(i)==false&&i!=orig);this.select(i)}addTracker(id){id=id.toUpperCase();if(this.exists(id)){return false}const i=this.myTrackers.push({id:id,access:false,denied:false})-1;const j=this.myServers.push(new pol.core.Server(id))-1;if(i!=j)console.error("Tracker-list doesn't correspond to server-list",i,j);this.selected=i;if(this.key()!="")this.setKey(this.key());this.dirty=false;datastore.setItem("arctic.mytrackers",this.myTrackers);m.redraw();console.log("Added tracker: "+id+" trying to ping it.",i);this.pingTracker(i);console.log("myTrackers/myServers",this.myTrackers,this.myServers);return true}removeTracker(i){this.myTrackers.splice(i,1);this.myServers.splice(i,1);datastore.setItem("arctic.mytrackers",this.myTrackers);if(this.selected>=i)this.selected--;datastore.setItem("arctic.selected",this.selected)}setKey(k){this.getSelectedSrv().setKey(k).then(()=>{this.key("");this.dirty=false;setTimeout(()=>this.getInfo(this.selected),500);m.redraw()})}hasKey(){return this.trackerid()!=""&&this.getSelected()&&this.getSelectedSrv()&&this.getSelectedSrv().key!=null}pingTracker(i){const t=this;this.dirty=false;if(t.myServers[i].key!=null)t.getInfo(i)}exists(tr){for(const x of this.myTrackers)if(x.id==tr)return true;return false}isAuth(){return this.auth}isAvailable(){return this.auth&&this.getSelected().access}isAvailable(i){return this.myTrackers.access}setAuth(i,a,d){if(i==this.selected)this.auth=a;if(i<0)i=this.selected;if(i>=0){this.myTrackers[i].access=a;this.myTrackers[i].denied=d}m.redraw()}showError(i,x){if(i==this.selected)this.error(x)}getInfo(i){let srv=null;let t=this;this.clearerr();srv=t.myServers[i];let auth_ok=false;let tout=setTimeout(()=>{if(auth_ok==false&&t.isAvailable()){t.setAuth(i,false,false);t.showError(i,"Timeout (no response): "+t.myTrackers[i].id)}},10000);srv.GET("api/info",null,st=>{t.setAuth(i,true,false);auth_ok=true;clearTimeout(tout);m.redraw()},(x,y,z)=>{clearTimeout(tout);if(t.isAvailable()==false||i>=this.myTrackers.size())return;const denied=x.status!=null&&x.status==401;t.setAuth(i,false,denied);clearTimeout(tout);m.redraw();if(denied)t.showError(i,"Access denied: "+t.myTrackers[i].id);else t.showError(i,"Cannot GET data: "+t.myTrackers[i].id)})}getMdns(i){let srv=null;let t=this;if(!i||i==-1)srv=t.getSelectedSrv();else srv=t.myServers[i];srv.GET("api/trackers",null,ttr=>{const tr=JSON.parse(ttr);if(tr==null||tr.length==0)return;for(const tt of tr){const id=tt.host.split(/[Aa]rctic-/);if(id[1]){if(t.addTracker(id[1]))console.log("MDNS TRACKER: ",tt.name,tt.host,tt.port)}}},x=>{})}};pol.widget.setFactory("core.keySetup",{create:()=>new pol.core.keySetup}); pol.core.statusInfo=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.statusInfo";t.data={heap:0,flash:0,ap:"-",ipaddr:"-",macaddr:"-",mdns:"-",vbatt:"-"};t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","Status Info"),m("form.status",[m("div.field",m("span.leftlab","Free heap: "),toKbytes(t.data.heap)),m("div.field",m("span.leftlab","Flash size: "),toKbytes(t.data.flash)),m("div.field",m("span.leftlab","Filesystem size: "),toKbytes(t.data.sizefs)),m("div.field",m("span.leftlab","Filesystem free space: "),toKbytes(t.data.freefs)),m("div.field",m("span.leftlab","Connected AP: "),t.data.ap),m("div.field",m("span.leftlab","IP address: "),t.data.ipaddr),m("div.field",m("span.leftlab","mDNS hostname: "),t.data.mdns),m("div.field",m("span.leftlab","Soft AP: "),t.data.softap?"Enabled":"Disabled"),m("div.field",m("span.leftlab","MAC address: "),t.data.macaddr),m("div.field",m("span.leftlab","Battery voltage: "),t.data.vbatt+" V ("+t.data.vpercent+" %)"),m("div.field",m("span.leftlab","Battery status: "),t.data.battstatus),m("span.errmsg",t.errmsg)])])}};setInterval(()=>t.getInfo(),30000);function toKbytes(x){return Math.round(x/100)/10+" kB"}}getInfo(){this.keys.getSelectedSrv().GET("api/info",null,st=>{this.data=st;pol.widget.get("core.keySetup").setAuth(-1,true,false);this.clearerr()},x=>{pol.widget.get("core.keySetup").setAuth(-1,false,x.status!=null&&x.status==401);this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.statusInfo",{create:()=>new pol.core.statusInfo}); pol.core.wifiSetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.wifiSetup";t.data={apssid:"",appass:m.stream(""),fwurl:m.stream(""),apikey:m.stream(""),ap_0_ssid:m.stream(""),ap_0_pw:m.stream(""),ap_1_ssid:m.stream(""),ap_1_pw:m.stream(""),ap_2_ssid:m.stream(""),ap_2_pw:m.stream(""),ap_3_ssid:m.stream(""),ap_3_pw:m.stream(""),ap_4_ssid:m.stream(""),ap_4_pw:m.stream(""),ap_5_ssid:m.stream(""),ap_5_pw:m.stream("")};t.dirty=false;t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","WIFI / Internet configuration"),m("form.aprs",[m("div.field",m("span.leftlab","Soft AP SSID: "),t.data.apssid),m("div.field",m("span.leftlab","Soft AP password: "),m(textInput,{passwd:true,value:t.data.appass,size:15,maxLength:64,onchange:dirty,regex:/^.*$/i})),br,m("div.field",m("span.leftlab","AP 1 (ssid,passwd): "),m(textInput,{value:t.data.ap_0_ssid,size:15,maxLength:32,onchange:dirty,regex:/^.*$/i}),m(textInput,{passwd:true,value:t.data.ap_0_pw,size:15,maxLength:64,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","AP 2 (ssid,passwd): "),m(textInput,{value:t.data.ap_1_ssid,size:15,maxLength:32,onchange:dirty,regex:/^.*$/i}),m(textInput,{passwd:true,value:t.data.ap_1_pw,size:15,maxLength:64,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","AP 3 (ssid,passwd): "),m(textInput,{value:t.data.ap_2_ssid,size:15,maxLength:32,onchange:dirty,regex:/^.*$/i}),m(textInput,{passwd:true,value:t.data.ap_2_pw,size:15,maxLength:64,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","AP 4 (ssid,passwd): "),m(textInput,{value:t.data.ap_3_ssid,size:15,maxLength:32,onchange:dirty,regex:/^.*$/i}),m(textInput,{passwd:true,value:t.data.ap_3_pw,size:15,maxLength:64,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","AP 5 (ssid,passwd): "),m(textInput,{value:t.data.ap_4_ssid,size:15,maxLength:32,onchange:dirty,regex:/^.*$/i}),m(textInput,{passwd:true,value:t.data.ap_4_pw,size:15,maxLength:64,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","AP 6 (ssid,passwd): "),m(textInput,{value:t.data.ap_5_ssid,size:15,maxLength:32,onchange:dirty,regex:/^.*$/i}),m(textInput,{passwd:true,value:t.data.ap_5_pw,size:15,maxLength:64,onchange:dirty,regex:/^.*$/i})),br,m("div.field",m("span.leftlab","FW update URL: "),m(textInput,{value:t.data.fwurl,size:32,maxLength:64,onchange:dirty,regex:/^[a-zA-Z0-9\-\.\/\:]+$/i})),m("div.field",{className:"key"},m("span.leftlab","API Key: "),m(textInput,{value:t.data.apikey,size:32,maxLength:128,onchange:dirty,regex:/^.*$/i})),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Reset"),m("span.errmsg",t.errmsg))])])}};function dirty(){t.dirty=true}function toggle(x){return()=>{t.data[x]=t.data[x]?false:true}}function reset(){t.getInfo()}function toNumber(obj,x){obj[x]=Number(obj[x]())}function update(){var obj=Object.assign({},t.data);t.keys.getSelectedSrv().PUT("api/wifi",JSON.stringify(obj),()=>{t.dirty=false;t.data.apikey("");t.clearerr()},x=>{t.error("Update error (see browser log)",x)})}}getInfo(){this.keys.getSelectedSrv().GET("api/wifi",null,st=>{this.data=st;this.data.appass=m.stream(st.appass);this.data.htuser=m.stream(st.htuser);this.data.htpass=m.stream(st.htpass);this.data.fwurl=m.stream(st.fwurl);this.data.apikey=m.stream("");for(var i=0;i<6;i++){this.data["ap_"+i+"_ssid"]=m.stream(st["ap_"+i+"_ssid"]);this.data["ap_"+i+"_pw"]=m.stream(st["ap_"+i+"_pw"])}this.dirty=false;this.clearerr()},x=>{this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.wifiSetup",{create:()=>new pol.core.wifiSetup}); -pol.core.aprsSetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.aprsSetup";t.data={mycall:m.stream(""),symbol:m.stream(""),path:m.stream(""),comment:m.stream(""),txfreq:m.stream(""),rxfreq:m.stream(""),maxpause:m.stream(""),minpause:m.stream(""),mindist:m.stream(""),repeat:m.stream(""),turnlimit:m.stream(""),timestamp:false,compress:false,altitude:false,extraturn:false};t.dirty=false;t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","APRS configuration"),m("form.aprs",[m("div.field",m("span.leftlab","My callsign: "),m(textInput,{id:"callsign",value:t.data.mycall,size:10,maxLength:15,onchange:dirty,regex:/^[a-zA-Z0-9\-]+$/i})),m("div.field",m("span.leftlab","Symbol (tab/sym): "),m(textInput,{id:"symbol",value:t.data.symbol,size:2,maxLength:2,onchange:dirty,regex:/^\.\.$/i})),m("div.field",m("span.leftlab","Report comment: "),m(textInput,{id:"comment",value:t.data.comment,size:25,maxLength:40,onchange:dirty,regex:/^\.*$/i})),m("div.field",m("span.leftlab","Digipeater path: "),m(textInput,{id:"path",value:t.data.path,size:25,maxLength:40,onchange:dirty,regex:/^([a-zA-Z0-9\-]+)(,([a-zA-Z0-9\-]+))* $/i})),m("div.field",m("span.leftlab","TX frequency: "),m(textInput,{id:"txfreq",value:t.data.txfreq,size:7,maxLength:7,onchange:dirty,regex:/^[0-9]{7}$/i})),m("div.field",m("span.leftlab","RX frequency: "),m(textInput,{id:"rxfreq",value:t.data.rxfreq,size:7,maxLength:7,onchange:dirty,regex:/^[0-9]{7}$/i})),br,m("div.field",m("span.leftlab",{class:"subsect"},"Tracking attributes: "),[m(checkBox,{id:"timestamp_on",checked:t.data.timestamp,onclick:toggle("timestamp")},"Timestamp "),nbsp,m(checkBox,{id:"compress_on",checked:t.data.compress,onclick:toggle("compress")},"Compress "),nbsp,m(checkBox,{id:"altitude_on",checked:t.data.altitude,onclick:toggle("altitude")},"Altitude ")]),m("div.field",m("span.leftlab","Turn limit: "),m(textInput,{id:"turnlimit",value:t.data.turnlimit,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(degrees)"),m("div.field",m("span.leftlab","Max pause: "),m(textInput,{id:"maxpause",value:t.data.maxpause,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(seconds)"),m("div.field",m("span.leftlab","Min pause: "),m(textInput,{id:"minpause",value:t.data.minpause,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(seconds)"),m("div.field",m("span.leftlab","Min distance: "),m(textInput,{id:"mindist",value:t.data.mindist,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(meters)"),br,m("div.field",m("span.leftlab",{class:"subsect"},"Extra posreports: "),m(checkBox,{id:"extraturn",checked:t.data.extraturn,onclick:toggle("extraturn")},"Add when turning")),m("div.field",m("span.leftlab","Redundant reports: "),m(textInput,{id:"repeat",value:t.data.repeat,size:1,maxLength:2,onchange:dirty,regex:/^[0-4]{1}$/i})),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Reset"),m("span.errmsg",t.errmsg))])])}};function dirty(){t.dirty=true}function toggle(x){return()=>{t.dirty=true;t.data[x]=t.data[x]?false:true;m.redraw()}}function reset(){t.getInfo()}function toNumber(obj,x){obj[x]=Number(obj[x]())}function update(){var obj=Object.assign({},t.data);toNumber(obj,"maxpause");toNumber(obj,"minpause");toNumber(obj,"mindist");toNumber(obj,"repeat");toNumber(obj,"turnlimit");this.keys.getSelectedSrv().PUT("api/aprs",JSON.stringify(obj),()=>{t.dirty=false;t.clearerr()},x=>{t.error("Update error (see browser log)",x)})}}getInfo(){this.keys.getSelectedSrv().GET("api/aprs",null,st=>{this.data=st;this.data.mycall=m.stream(st.mycall);this.data.symbol=m.stream(""+st.symbol);this.data.comment=m.stream(st.comment);this.data.path=m.stream(st.path);this.data.txfreq=m.stream(st.rxfreq);this.data.rxfreq=m.stream(st.rxfreq);this.data.turnlimit=m.stream(st.turnlimit);this.data.maxpause=m.stream(st.maxpause);this.data.minpause=m.stream(st.minpause);this.data.mindist=m.stream(st.mindist);this.data.repeat=m.stream(st.repeat);this.dirty=false;this.clearerr()},x=>{this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.aprsSetup",{create:()=>new pol.core.aprsSetup}); -pol.core.digiSetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.digiSetup";t.data={digiOn:false,wide1:false,sar:false,igateOn:false,server:m.stream(""),port:m.stream(""),user:m.stream(""),passcode:m.stream("")};t.dirty=false;t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","Digi/Igate configuration"),m("form.digi",[m("div.field",m("span.leftlab",{class:"subsect"},"Digipeater: "),m(checkBox,{id:"digi_on",checked:t.data.digiOn,onclick:toggle("digiOn")},"Activate")),m("div.field",m("span.leftlab","Digipeat modes: "),[m(checkBox,{id:"wide1_on",checked:t.data.wide1,onclick:toggle("wide1")},"Wide-1 (fill-in) "),nbsp,m(checkBox,{id:"sar_on",checked:t.data.sar,onclick:toggle("sar")},"Preemption on SAR")]),br,m("div.field",m("span.leftlab",{class:"subsect"},"Internet gate: "),m(checkBox,{id:"igate_on",checked:t.data.igateOn,onclick:toggle("igateOn")},"Activate")),m("div.field",m("span.leftlab","APRS/IS server: "),m(textInput,{id:"aprs_server",value:t.data.server,size:25,maxLength:40,onchange:dirty,regex:/^[a-zA-Z0-9\-]+$/i})),m("div.field",m("span.leftlab","Port number: "),m(textInput,{id:"server_port",value:t.data.port,size:5,maxLength:5,onchange:dirty,regex:/^[0-9\-]+$/i})),m("div.field",m("span.leftlab","Username: "),m(textInput,{id:"username",value:t.data.user,size:10,maxLength:30,onchange:dirty,regex:/^[a-zA-Z0-9\-]+$/i})),m("div.field",m("span.leftlab","Passcode: "),m(textInput,{id:"passcode",value:t.data.passcode,size:5,maxLength:5,onchange:dirty,regex:/^[0-9\-]+$/i})),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Reset"),m("span.errmsg",t.errmsg))])])}};function dirty(){t.dirty=true}function toggle(x){return()=>{t.dirty=true;t.data[x]=t.data[x]?false:true;m.redraw()}}function reset(){t.getInfo()}function toNumber(obj,x){obj[x]=Number(obj[x]())}function update(){var obj=Object.assign({},t.data);toNumber(obj,"port");toNumber(obj,"passcode");t.keys.getSelectedSrv().PUT("api/digi",JSON.stringify(obj),()=>{t.dirty=false;t.clearerr()},x=>{t.error("Update error (see browser log)",x)})}}getInfo(){this.keys.getSelectedSrv().GET("api/digi",null,st=>{this.data=st;this.data.server=m.stream(st.server);this.data.port=m.stream(""+st.port);this.data.user=m.stream(st.user);this.data.passcode=m.stream(st.passcode);this.dirty=false;this.clearerr()},x=>{console.log(x);this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.digiSetup",{create:()=>new pol.core.digiSetup}); -pol.core.trklogSetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.trklogSetup";t.data={trklog_on:false,trkpost_on:false,url:m.stream(""),key:m.stream(""),interv:m.stream(""),ttl:m.stream("")};t.dirty=false;t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","Track logging configuration"),m("form.digi",[m("div.field",m("span.leftlab",{class:"subsect"},"Track logging: "),m(checkBox,{checked:t.data.trklog_on,onclick:toggle("trklog_on")},"Activate")),m("div.field",m("span.leftlab","Save interval: "),m(textInput,{value:t.data.interv,size:3,maxLength:4,onchange:dirty,regex:/^[0-9\-]+$/i}),nbsp,"(seconds)"),m("div.field",m("span.leftlab","Time to live: "),m(textInput,{value:t.data.ttl,size:3,maxLength:4,onchange:dirty,regex:/^[0-9\-]+$/i}),nbsp,"(days)"),br,m("div.field",m("span.leftlab",{class:"subsect"},"Auto upload: "),m(checkBox,{checked:t.data.trkpost_on,onclick:toggle("trkpost_on")},"Activate")),m("div.field",m("span.leftlab","Server URL: "),m(textInput,{value:t.data.url,size:32,maxLength:64,onchange:dirty,regex:/^[a-zA-Z0-9\-\.]+$/i})),m("div.field",m("span.leftlab","Server key: "),m(textInput,{value:t.data.key,size:32,maxLength:128,onchange:dirty,regex:/^.*$/i})),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Reset"),m("span.errmsg",t.errmsg))])])}};function dirty(){t.dirty=true}function toggle(x){return()=>{t.dirty=true;t.data[x]=t.data[x]?false:true;m.redraw()}}function reset(){t.getInfo()}function toNumber(obj,x){obj[x]=Number(obj[x]())}function update(){var obj=Object.assign({},t.data);toNumber(obj,"interv");toNumber(obj,"ttl");t.keys.getSelectedSrv().PUT("api/trklog",JSON.stringify(obj),()=>{t.dirty=false;t.clearerr()},x=>{t.error("Update error (see browser log)",x)})}}getInfo(){this.keys.getSelectedSrv().GET("api/trklog",null,st=>{this.data=st;this.data.url=m.stream(st.url);this.data.key=m.stream(""+st.key);this.data.interv=m.stream(st.interv);this.data.ttl=m.stream(st.ttl);this.dirty=false;this.clearerr()},x=>{this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.trklogSetup",{create:()=>new pol.core.trklogSetup}); -localforage.config({driver:localforage.INDEXEDDB,version:1,storeName:"Arctic",description:"Web app datastore for arctic tracker"});var datastore=localforage.createInstance({name:"ArcticTracker"});let selectedWidget=null;function show(id){return()=>{var x=pol.widget.get(id);x.activate($("#widget")[0]);selectedWidget=x;console.log("Selected Widget: ",x)}}setTimeout(show("core.keySetup"),300);function nextTracker(){pol.widget.get("core.keySetup").selectNext();if(selectedWidget.onActivate)selectedWidget.onActivate()}function prevTracker(){pol.widget.get("core.keySetup").selectPrev();if(selectedWidget.onActivate)selectedWidget.onActivate()}function isOpen(){let keys=pol.widget.get("core.keySetup");if(keys.getSelected()==null||keys.getSelectedSrv()==null)return false;return keys.getSelectedSrv().key!=null&&keys.isAuth()}function getSelectedId(){let keys=pol.widget.get("core.keySetup");if(keys.getSelected()==null)return"NONE";return keys.getSelected().id}function isSel(x){console.log("GAKK: ",x,selectedWidget);if(selectedWidget!=null&&selectedWidget.classname==x)return".sel";else return""}menu={view:function(){return m("div.menu",[m("img",{onclick:show("core.keySetup"),src:isOpen()?"img/unlocked.png":"img/locked.png"}),m("span"+isSel("core.statusInfo"),{onclick:show("core.statusInfo")},"Status"),m("span"+isSel("core.wifiSetup"),{onclick:show("core.wifiSetup")},"Wifi"),m("span"+isSel("core.aprsSetup"),{onclick:show("core.aprsSetup")},"Aprs"),m("span"+isSel("core.digiSetup"),{onclick:show("core.digiSetup")},"Digi/Igate"),m("span"+isSel("core.trklogSetup"),{onclick:show("core.trklogSetup")},"Trklog"),nbsp,getSelectedId(),nbsp,m("img",{src:"img/back.png",id:"fwd",onclick:prevTracker}),m("img",{src:"img/forward.png",id:"fwd",onclick:nextTracker})])}};m.mount($("div#heading")[0],menu);m.redraw(); +pol.core.aprsSetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.aprsSetup";t.data={mycall:m.stream(""),symbol:m.stream(""),path:m.stream(""),comment:m.stream(""),txfreq:m.stream(""),rxfreq:m.stream(""),maxpause:m.stream(""),minpause:m.stream(""),mindist:m.stream(""),repeat:m.stream(""),turnlimit:m.stream(""),timestamp:false,compress:false,altitude:false,extraturn:false};t.dirty=false;t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","APRS configuration"),m("form.aprs",[m("div.field",m("span.leftlab","My callsign: "),m(textInput,{id:"callsign",value:t.data.mycall,size:10,maxLength:15,onchange:dirty,regex:/^[a-zA-Z0-9\-]+$/i})),m("div.field",m("span.leftlab","Symbol (tab/sym): "),m(textInput,{id:"symbol",value:t.data.symbol,size:2,maxLength:2,onchange:dirty,regex:/^..$/i})),m("div.field",m("span.leftlab","Report comment: "),m(textInput,{id:"comment",value:t.data.comment,size:25,maxLength:40,onchange:dirty,regex:/^.*$/i})),m("div.field",m("span.leftlab","Digipeater path: "),m(textInput,{id:"path",value:t.data.path,size:25,maxLength:40,onchange:dirty,regex:/^([a-zA-Z0-9\-]+)(,([a-zA-Z0-9\-]+))*$/i})),m("div.field",m("span.leftlab","TX frequency: "),m(textInput,{id:"txfreq",value:t.data.txfreq,size:7,maxLength:7,onchange:dirty,regex:/^[0-9]{7}$/i})),m("div.field",m("span.leftlab","RX frequency: "),m(textInput,{id:"rxfreq",value:t.data.rxfreq,size:7,maxLength:7,onchange:dirty,regex:/^[0-9]{7}$/i})),br,m("div.field",m("span.leftlab",{class:"subsect"},"Tracking attributes: "),[m(checkBox,{id:"timestamp_on",checked:t.data.timestamp,onclick:toggle("timestamp")},"Timestamp "),nbsp,m(checkBox,{id:"compress_on",checked:t.data.compress,onclick:toggle("compress")},"Compress "),nbsp,m(checkBox,{id:"altitude_on",checked:t.data.altitude,onclick:toggle("altitude")},"Altitude ")]),m("div.field",m("span.leftlab","Turn limit: "),m(textInput,{id:"turnlimit",value:t.data.turnlimit,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(degrees)"),m("div.field",m("span.leftlab","Max pause: "),m(textInput,{id:"maxpause",value:t.data.maxpause,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(seconds)"),m("div.field",m("span.leftlab","Min pause: "),m(textInput,{id:"minpause",value:t.data.minpause,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(seconds)"),m("div.field",m("span.leftlab","Min distance: "),m(textInput,{id:"mindist",value:t.data.mindist,size:4,maxLength:4,onchange:dirty,regex:/^[0-9]{1,3}$/i}),nbsp,"(meters)"),br,m("div.field",m("span.leftlab",{class:"subsect"},"Extra posreports: "),m(checkBox,{id:"extraturn",checked:t.data.extraturn,onclick:toggle("extraturn")},"Add when turning")),m("div.field",m("span.leftlab","Redundant reports: "),m(textInput,{id:"repeat",value:t.data.repeat,size:1,maxLength:2,onchange:dirty,regex:/^[0-4]{1}$/i})),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Reset"),m("span.errmsg",t.errmsg))])])}};function dirty(){t.dirty=true}function toggle(x){return()=>{t.dirty=true;t.data[x]=t.data[x]?false:true;m.redraw()}}function reset(){t.getInfo()}function toNumber(obj,x){obj[x]=Number(obj[x]())}function update(){var obj=Object.assign({},t.data);toNumber(obj,"maxpause");toNumber(obj,"minpause");toNumber(obj,"mindist");toNumber(obj,"repeat");toNumber(obj,"turnlimit");t.keys.getSelectedSrv().PUT("api/aprs",JSON.stringify(obj),()=>{t.dirty=false;t.clearerr()},x=>{t.error("Update error (see browser log)",x)})}}getInfo(){this.keys.getSelectedSrv().GET("api/aprs",null,st=>{this.data=st;this.data.mycall=m.stream(st.mycall);this.data.symbol=m.stream(""+st.symbol);this.data.comment=m.stream(st.comment);this.data.path=m.stream(st.path);this.data.txfreq=m.stream(st.rxfreq);this.data.rxfreq=m.stream(st.rxfreq);this.data.turnlimit=m.stream(st.turnlimit);this.data.maxpause=m.stream(st.maxpause);this.data.minpause=m.stream(st.minpause);this.data.mindist=m.stream(st.mindist);this.data.repeat=m.stream(st.repeat);this.dirty=false;this.clearerr()},x=>{this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.aprsSetup",{create:()=>new pol.core.aprsSetup}); +pol.core.digiSetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.digiSetup";t.data={digiOn:false,wide1:false,sar:false,igateOn:false,server:m.stream(""),port:m.stream(""),user:m.stream(""),passcode:m.stream("")};t.dirty=false;t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","Digi/Igate configuration"),m("form.digi",[m("div.field",m("span.leftlab",{class:"subsect"},"Digipeater: "),m(checkBox,{id:"digi_on",checked:t.data.digiOn,onclick:toggle("digiOn")},"Activate")),m("div.field",m("span.leftlab","Digipeat modes: "),[m(checkBox,{id:"wide1_on",checked:t.data.wide1,onclick:toggle("wide1")},"Wide-1 (fill-in) "),nbsp,m(checkBox,{id:"sar_on",checked:t.data.sar,onclick:toggle("sar")},"Preemption on SAR")]),br,m("div.field",m("span.leftlab",{class:"subsect"},"Internet gate: "),m(checkBox,{id:"igate_on",checked:t.data.igateOn,onclick:toggle("igateOn")},"Activate")),m("div.field",m("span.leftlab","APRS/IS server: "),m(textInput,{id:"aprs_server",value:t.data.server,size:25,maxLength:40,onchange:dirty,regex:/^[a-zA-Z0-9\-\.]+$/i})),m("div.field",m("span.leftlab","Port number: "),m(textInput,{id:"server_port",value:t.data.port,size:5,maxLength:5,onchange:dirty,regex:/^[0-9\-]+$/i})),m("div.field",m("span.leftlab","Username: "),m(textInput,{id:"username",value:t.data.user,size:10,maxLength:30,onchange:dirty,regex:/^[a-zA-Z0-9\-]+$/i})),m("div.field",m("span.leftlab","Passcode: "),m(textInput,{id:"passcode",value:t.data.passcode,size:5,maxLength:5,onchange:dirty,regex:/^[0-9\-]+$/i})),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Reset"),m("span.errmsg",t.errmsg))])])}};function dirty(){t.dirty=true}function toggle(x){return()=>{t.dirty=true;t.data[x]=t.data[x]?false:true;m.redraw()}}function reset(){t.getInfo()}function toNumber(obj,x){obj[x]=Number(obj[x]())}function update(){var obj=Object.assign({},t.data);toNumber(obj,"port");toNumber(obj,"passcode");t.keys.getSelectedSrv().PUT("api/digi",JSON.stringify(obj),()=>{t.dirty=false;t.clearerr()},x=>{t.error("Update error (see browser log)",x)})}}getInfo(){this.keys.getSelectedSrv().GET("api/digi",null,st=>{this.data=st;this.data.server=m.stream(st.server);this.data.port=m.stream(""+st.port);this.data.user=m.stream(st.user);this.data.passcode=m.stream(st.passcode);this.dirty=false;this.clearerr()},x=>{console.log(x);this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.digiSetup",{create:()=>new pol.core.digiSetup}); +pol.core.trklogSetup=class extends pol.core.Widget{constructor(){super();const t=this;t.classname="core.trklogSetup";t.data={trklog_on:false,trkpost_on:false,url:m.stream(""),key:m.stream(""),interv:m.stream(""),ttl:m.stream("")};t.dirty=false;t.keys=pol.widget.get("core.keySetup");this.widget={view:function(){return m("div",[m("h1","Track logging configuration"),m("form.digi",[m("div.field",m("span.leftlab",{class:"subsect"},"Track logging: "),m(checkBox,{checked:t.data.trklog_on,onclick:toggle("trklog_on")},"Activate")),m("div.field",m("span.leftlab","Save interval: "),m(textInput,{value:t.data.interv,size:3,maxLength:4,onchange:dirty,regex:/^[0-9\-]+$/i}),nbsp,"(seconds)"),m("div.field",m("span.leftlab","Time to live: "),m(textInput,{value:t.data.ttl,size:3,maxLength:4,onchange:dirty,regex:/^[0-9\-]+$/i}),nbsp,"(days)"),br,m("div.field",m("span.leftlab",{class:"subsect"},"Auto upload: "),m(checkBox,{checked:t.data.trkpost_on,onclick:toggle("trkpost_on")},"Activate")),m("div.field",m("span.leftlab","Server URL: "),m(textInput,{value:t.data.url,size:32,maxLength:64,onchange:dirty,regex:/^[a-zA-Z0-9\-\.\:\/]+$/i})),m("div.field",m("span.leftlab","Server key: "),m(textInput,{value:t.data.key,size:32,maxLength:128,onchange:dirty,regex:/^.*$/i})),m("div.butt",m("img.upd",{src:t.dirty?"img/warn.png":"img/ok.png"}),m("button",{type:"button",onclick:update},"Update"),m("button",{type:"button",onclick:reset},"Reset"),m("span.errmsg",t.errmsg))])])}};function dirty(){t.dirty=true}function toggle(x){return()=>{t.dirty=true;t.data[x]=t.data[x]?false:true;m.redraw()}}function reset(){t.getInfo()}function toNumber(obj,x){obj[x]=Number(obj[x]())}function update(){var obj=Object.assign({},t.data);toNumber(obj,"interv");toNumber(obj,"ttl");t.keys.getSelectedSrv().PUT("api/trklog",JSON.stringify(obj),()=>{t.dirty=false;t.clearerr()},x=>{t.error("Update error (see browser log)",x)})}}getInfo(){this.keys.getSelectedSrv().GET("api/trklog",null,st=>{this.data=st;this.data.url=m.stream(st.url);this.data.key=m.stream(""+st.key);this.data.interv=m.stream(st.interv);this.data.ttl=m.stream(st.ttl);this.dirty=false;this.clearerr()},x=>{this.error("Cannot GET data (se browser log)",x)})}onActivate(){this.getInfo()}};pol.widget.setFactory("core.trklogSetup",{create:()=>new pol.core.trklogSetup}); +localforage.config({driver:localforage.INDEXEDDB,version:1,storeName:"Arctic",description:"Web app datastore for arctic tracker"});var datastore=localforage.createInstance({name:"ArcticTracker"});let selectedWidget=null;function show(id){return()=>{var x=pol.widget.get(id);x.activate($("#widget")[0]);selectedWidget=x}}setTimeout(show("core.keySetup"),400);function nextTracker(){pol.widget.get("core.keySetup").selectNext();if(selectedWidget.onActivate)selectedWidget.onActivate()}function prevTracker(){pol.widget.get("core.keySetup").selectPrev();if(selectedWidget.onActivate)selectedWidget.onActivate()}function isOpen(){let keys=pol.widget.get("core.keySetup");if(keys.getSelected()==null||keys.getSelectedSrv()==null)return false;return keys.getSelectedSrv().key!=null&&keys.isAuth()}function getSelectedId(){let keys=pol.widget.get("core.keySetup");if(keys.getSelected()==null)return"NONE";return keys.getSelected().id}function isSel(x){if(selectedWidget!=null&&selectedWidget.classname==x)return".sel";else return""}menu={view:function(){return m("div.menu",[m("img",{onclick:show("core.keySetup"),src:isOpen()?"img/unlocked.png":"img/locked.png"}),m("span"+isSel("core.statusInfo"),{onclick:show("core.statusInfo")},"Status"),m("span"+isSel("core.wifiSetup"),{onclick:show("core.wifiSetup")},"Wifi"),m("span"+isSel("core.aprsSetup"),{onclick:show("core.aprsSetup")},"Aprs"),m("span"+isSel("core.digiSetup"),{onclick:show("core.digiSetup")},"Digi/Igate"),m("span"+isSel("core.trklogSetup"),{onclick:show("core.trklogSetup")},"Trklog"),nbsp,getSelectedId(),nbsp,m("img",{src:"img/back.png",id:"fwd",onclick:prevTracker}),m("img",{src:"img/forward.png",id:"fwd",onclick:nextTracker})])}};m.mount($("div#heading")[0],menu);m.redraw();