Source file: /~heha/ewa/Motor/cdesk.zip/js/app-guihelp.js

/*************************
 ** GUI-Hilfsfunktionen **
 *************************/
"use strict"

function clearRows(tbody) {
  while (tbody.firstChild) tbody.firstChild.remove();
}
// dv = DataView, stets Little Endian (USB)
function getInt16(dv,ofs,fak) {
  const v=dv.getInt16(ofs,true);
  switch (v) {
    case  32767: return Number.POSITIVE_INFINITY;
    case -32768: return Number.NaN;
    case -32767: return Number.NEGATIVE_INFINITY;
  }
  if (!fak) return v;
  return v*fak;
}
function getInt8(dv,ofs,fak) {
  const v=dv.getInt8(ofs);
  switch (v) {
    case  127: return Number.POSITIVE_INFINITY;
    case -128: return Number.NaN;
    case -127: return Number.NEGATIVE_INFINITY;
  }
  if (!fak) return v;
  return v*fak;
}
function numberToPrec(v,n=12) {
  return v.toPrecision(n).replace(/\.?0+$/,"");
}
// <input> zu einem Int16-Eingabefeld machen; <value> ist bereits mit <step> skaliert
function make_Int16_input(inp,value,step,userRange) {
  inp.type="number";
  inp.step=numberToPrec(step,3);	// nicht mit Kommastellen überfluten
  let min=-32766*step;
  if (userRange && min<userRange.a) min=userRange.a;
  inp.min=numberToPrec(min,3);
  let max=+32766*step;
  if (userRange && max>userRange.e) max=userRange.e;
  inp.max=numberToPrec(max,3);
  if (value!==undefined) inp.value=emptyNaN(value);
  inp.placeholder="NaN";
}

// Hilfsklasse für 4-Status-Checkboxen (die als "Button" realisiert werden)
class Fourstate{
  constructor(div,k) {	// k = Anzahl Zustände, die der Anwender durchklicken kann; 0,2,3,4 erlaubt
    const inp=div.insertBefore(document.createElement("input"),div.firstChild);
    this.inp=inp;
    this.chars="01 ↕";	// so vorbelegt und ggf. individuell veränderbar
    this.k=k;
    inp.type="button";
    if (k) inp.addEventListener("click",e => {
      let i=this.state+1;	// this.state ruft Getter
      if (i>=k) i=0;
      this.state = i;		// this.state ruft Setter
    }); else inp.disabled=true;	// nur Anzeige, kein EventListener
  }
  get state() {return this.chars.indexOf(this.inp.value);}
  set state(i) {
    this.inp.value=this.chars.charAt(i);
    this.inp.title=["Aus","Ein","unverändert","Wechsel"][i];
  }
}

class FourstateGroup{
  constructor(div,n,k,bit0,bit1) {
    clearRows(div);
    div.style="white-space:nowrap;"
    this.a=new Array(n);
    if (bit0===undefined) {bit0=0; bit1=~0;}
    for(let i=0; i<n; i++) {
      const f=new Fourstate(div,k);
      f.state = (bit1&1)<<1 | bit0&1;
      bit0>>=1;	// nächstes Bit
      bit1>>=1;
      this.a[i]=f;
    }
  }
  setState(bit0,bit1,focus) {
    this.a.forEach(f => {
      if (f!=focus) f.state = (bit1&1)<<1 | bit0&1;
      bit0>>=1; bit1>>=1;
    });
  }
  getState(mask=1) {	// erlaubte Masken: 1 (Bit 0) und 2 (Bit 1)
    let r=0, m=1;
    this.a.forEach(f => {
      if (f.state&mask) r|=m;
      m<<=1;
    });
    return r;
  }
  get state() {return this.getState();}
}

class CheckboxList{
  constructor(div,ena,titles) {
    clearRows(div);
    this.a=[];
    titles.forEach(t => {
      const inp=div.appendChild(document.createElement("input"));
      inp.type="checkbox";
      inp.id=div.id+this.a.length;
      if (!(ena&1)) inp.disabled=true;
      inp.indeterminate=true;		// Zustand zunächst unbekannt
      ena>>=1;
      const lbl=div.appendChild(document.createElement("label"));
      lbl.setAttribute("for",inp.id);	// lbl.for= geht nicht
      lbl.innerHTML=t;
      div.appendChild(document.createElement("br"));
      this.a.push(inp);
    });
  }
  setState(bit0,bit1,focus) {
    this.a.forEach(inp => {
      if (inp!=focus) {
        inp.checked = bit0&1;
	inp.indeterminate = bit1&1;
	bit0>>=1; bit1>>=1;
      }
    });
  }
  getState(mask=1) {
    let r=0, m=1;
    this.a.forEach(inp => {
      if (mask==1 && inp.checked
       || mask==2 && inp.indeterminate) r|=m;
      m<<=1;
    });
    return r;
  }
  get state() {return this.getState();}
}

// Das <input>-Element macht Komma-Punkt-Konvertierung
function fromTime(s) {	// "hh:mm:ss.xxx" nach Sekunden
  const a=s.split(':');
  return (+a[0]*60+ +a[1])*60+(+a[2]||0);
}
// Das <input>-Element macht Punkt-Komma-Konvertierung
function toTime(t) {	// Sekunden nach "hh:mm:ss.xxx"
  const date=new Date(t*1000);
  function digi(v,l=2) {return v.toString().padStart(l,'0');}
  return digi(date.getUTCHours())
    +':'+digi(date.getUTCMinutes())
    +':'+digi(date.getSeconds())
    +'.'+digi(date.getMilliseconds(),3);
}
function toTimeShort(t) {	// Sekunden nach [hh:]mm:ss[,x[x[x]]]
  return toTime(t).replace(/^00:/,"").replace(/.?0+$/,"").replace(".",",");
}

function emptyNaN(v) {
  return isFinite(v)?numberToPrec(v,5):"";
}

class Color{
  constructor(r,g,b,a=1,t) {this.init(r,g,b,a,t); Object.seal(this);}
  init(r,g,b,a=1,t) {
    if (typeof r == "string") return this.fromString(r);
    if (r instanceof Color) return this.init(r.r,r.g,r.b,r.a);
    switch (t) {
      case true:
      case "hsv":
      case "HSV": {
	while (r<0) r+=360;
	while (r>=360) r-=360;
	let e=r/60>>>0;	// ganzzahliger Sextant
	let f=r/60-e;	// 0..1
	let p=b*(1-g);
	let q=b*(1-g*f);
	let t=b*(1-g*(1-f))
	switch (e) {
	  case 1: return this.init(b,t,p,a);
	  case 2: return this.init(q,b,p,a);
	  case 3: return this.init(p,b,t,a);
	  case 4: return this.init(t,p,b,a);
	  case 5: return this.init(b,p,q,a);
	}
	return this.init(b,t,p,a);
      }break;
      case "hsl": return this.init(r,g,b,a,"hsv");
    }
    this.r=r; this.g=g; this.b=b; this.a=a; return this;
  }
  static base255(b) {return b*255.5>>>0;}
  static hexByte(b) {return Color.base255(b).toString(16).padStart(1,'0');}
  static hexChr2(s) {return s.parseInt(16)/255;}
  static hexChr1(s) {return s.parseInt(16)/15;}
  toString(t) {
    if (!t && this.a!==1) t="rgba";
    switch (t) {
      case "rgba": return t+"("+Color.base255(this.r)+","+Color.base255(this.g)+","+Color.base255(this.b)+","+this.a+")";
    }
    return "#"+Color.hexByte(this.r)+Color.hexByte(this.g)+Color.hexByte(this.b);
  }
  fromString(s) {
    s=s.trim();
    if (s.startsWith("#") && s.length==7) return this.init(Color.hexChr2(s.substr(1,2)),Color.hexChr2(s.substr(3,2)),Color.hexChr2(s.substr(5,2)));
    if (s.startsWith("#") && s.length==4) return this.init(Color.hexChr1(s.substr(1,1)),Color.hexChr1(s.substr(2,1)),Color.hexChr1(s.substr(3,1)));
    if (s.startsWith("rgba(") && s.endsWith(")")) {
      let a=s.substr(5,s.length-6).split(",");
      if (a.length==4) return this.init(a[0]/255,a[1]/255,a[2]/255,a[3]);
    }
    if (s.startsWith("rgb(") && s.endsWith(")")) {
      let a=s.substr(4,s.length-5).split(",");
      if (a.length==3) return this.init(a[0]/255,a[1]/255,a[2]/255);
    }
    return this.init();
  }
  get hsv() {
    const min = Math.min(this.r,this.g,this.b);
    const max = Math.max(this.r,this.g,this.b);
    const d = max-min;
    let h = d && (max==this.r ? (this.g-this.b)/d : max==this.g ? 2+(this.b-this.r)/d : 4+(this.r-this.g)/d);
    if (h<0) h+=6;
    return {
      h: h*60,
      s: d && d/max,
      v: max};
  }
}
Detected encoding: UTF-80