From 11b3c17a54d486cf64e1ce9eade48231f9b8ef46 Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 23:13:19 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- js/web/utils.js | 943 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 943 insertions(+) create mode 100644 js/web/utils.js diff --git a/js/web/utils.js b/js/web/utils.js new file mode 100644 index 0000000..20d4d39 --- /dev/null +++ b/js/web/utils.js @@ -0,0 +1,943 @@ +var XHR = XMLHttpRequest +if (!XHR) throw new Error('missing XMLHttpRequest') +else console.log('HTTP Browser Module Ver. 1.1.3 initialized.'); + +Utils = { + addCSS : function (styles) { + var styleSheet = document.createElement("style") + styleSheet.type = "text/css" + styleSheet.innerText = styles + document.head.appendChild(styleSheet) + }, + + // Analyze JS using esprima + analyze : function (code) { + var more=''; + try { + var ast = esprima.parse(code, { tolerant: true, loc:true }); + if (ast.errors && ast.errors.length>0) more = ast.errors[0]; + } catch (e) { + if (e.lineNumber) more = e+', in line '+e.lineNumber; + } + return more; + }, + + beep : function (duration,volume,frequency,type) { + if (!Utils.audioCtx) Utils.audioCtx=new(window.AudioContext || window.webkitAudioContext)(); + + var oscillator = Utils.audioCtx.createOscillator(); + var gainNode = Utils.audioCtx.createGain(); + duration=duration||10; + volume=volume||100; + frequency=frequency||1000; + type=type||'sine'; + oscillator.connect(gainNode); + gainNode.connect(Utils.audioCtx.destination); + + gainNode.gain.value = volume; + oscillator.frequency.value = frequency; + oscillator.type = type; + + + oscillator.start(); + + setTimeout( + function() { + oscillator.stop(); + }, + duration + ); + + oscillator.onended = function () { + Utils.audioCtx.close(); + Utils.audioCtx=null; + }; + }, + + BrowserVersion :(function(){ + var ua= navigator.userAgent, tem, + M= ua.match(/(opera|chrome|safari|firefox|msie|trident(?=\/))\/?\s*(\d+)/i) || []; + if(/trident/i.test(M[1])){ + tem= /\brv[ :]+(\d+)/g.exec(ua) || []; + return 'IE '+(tem[1] || ''); + } + if(M[1]=== 'Chrome'){ + tem= ua.match(/\b(OPR|Edge)\/(\d+)/); + if(tem!= null) return tem.slice(1).join(' ').replace('OPR', 'Opera'); + } + M= M[2]? [M[1], M[2]]: [navigator.appName, navigator.appVersion, '-?']; + if((tem= ua.match(/version\/(\d+)/i))!= null) M.splice(1, 1, tem[1]); + return {name:M[0],version:M[1]}; + })(), + + /** Change CSS + * + */ + changeCSS: function changeCSS(theClass,element,value) { + var cssRules; + + for (var S = 0; S < document.styleSheets.length; S++) { + try { + document.styleSheets[S].insertRule(theClass+' { '+element+': '+value+'; }', + document.styleSheets[S][cssRules].length); + } catch(err) { + try{ + document.styleSheets[S].addRule(theClass,element+': '+value+';'); + } catch(err){ + try{ + if (document.styleSheets[S]['rules']) { + cssRules = 'rules'; + } else if (document.styleSheets[S]['cssRules']) { + cssRules = 'cssRules'; + } else { + //no rules found... browser unknown + } + + for (var R = 0; R < document.styleSheets[S][cssRules].length; R++) { + if (document.styleSheets[S][cssRules][R].selectorText == theClass) { + if(document.styleSheets[S][cssRules][R].style[element]){ + document.styleSheets[S][cssRules][R].style[element] = value; + break; + } + } + } + } catch (err){} + } + } + } + }, + + copy : function (o) { + // recursively copy objects + var _o,p; + if (Utils.isArray(o)) { + if (typeof o[0] != 'object') return o.slice(); + else return o.map(function (e) { + if (typeof e == 'object') return Utils.copy(e); + else return e; + }); + + } else if (Utils.isObject(o)) { + if (o instanceof Date) return o; + _o={}; + for(p in o) _o[p]=(typeof o[p]=='object'?Utils.copy(o[p]):o[p]); + return _o; + } + else if (Utils.isString(o)) + return o.slice(); + else return o; + + }, + + empty : function (v) { + if (v == undefined) return true; + if (Utils.isString(v)) return v==''; + if (Utils.isArray(v)) return v.length==0; + if (Utils.isObject(v)) return Object.keys(v).length==0; + return false + }, + + equal : function (o1,o2) { + if (Utils.isArray(o1) && Utils.isArray(o2)) { + if (o1.length!=o2.length) return false; + for(var i=0;i 0 ) + while (i < l) + h = (h << 5) - h + s.charCodeAt(i++) | 0; + return h; + }, + + info: function (o) { + switch (typeof o) { + case 'function': + return o.toString().match(/^(function[ ]*[a-zA-Z0-9_]*\([^\)]+\))/)[1]; + } + }, + + inspect : inspect, + isArray: function isArray(o) { + if (o==_ || o ==null) return false; + else return typeof o == "array" || (typeof o == "object" && o.constructor === Array); + }, + isArrayArray: function isArrayArray(o) { + if (o==_ || o ==null) return false; + else return Utils.isArray(o) && + Utils.isArray(o[0]); + }, + isArrayArrayArray: function isArrayArrayArray(o) { + if (o==_ || o ==null) return false; + else return Utils.isArray(o) && + Utils.isArray(o[0]) && + Utils.isArray(o[0][0]); + }, + isBuffer: function isBuffer(o) { + if (o==_ || o ==null) return false; + else return o instanceof Buffer; + }, + isEmpty: function isEmpty(o) { + for(var prop in o) { + if (o[prop]!=undefined) return false; + } + return true; + }, + isError : function (o) { + return o instanceof Error + }, + isFunction: function isFunction(o) { + return typeof o == "function"; + }, + isMatrix: function isMatrix(o,noarray) { + if (o==_ || o ==null) return false; + else return (!noarray && Utils.isArray(o) && + Utils.isArray(o[0])) || + (Math.MatrixTA && Math.MatrixTA.isMatrix(o)) || + (Math.Matrix && Math.Matrix.isMatrix(o)) + ; + }, + isObj: function isObj(o) { + return typeof o == "object"; + }, + isObject: function isObject(o) { + return typeof o == "object"; + }, + isRegex: function isRegex(o) { + return o instanceof RegExp; + }, + isString: function isString(o) { + return typeof o == "string" || (typeof o == "object" && o.constructor === String); + }, + isNumber: function isNumber(o) { + return typeof o == "number" || (typeof o == "object" && o.constructor === Number); + }, + isBoolean: function isBoolean (o) { + return typeof o == "boolean" + }, + isString: function isString(o) { + return typeof o == "string" + }, + isStruct: function isStruct(o) { + return !Utils.isArray(o) && Utils.isObject(o) + }, + isTypedArray: function isTypedArray(o) { + return Utils.isObject(o) && o.buffer instanceof ArrayBuffer + }, + isVector: function isVector(o,noarray) { + if (o==_ || o ==null) return false; + else return (!noarray && Utils.isArray(o)) || + (Math.VectorTA && Math.VectorTA.isVector(o)) || + (Math.Vector && Math.Vector.isVector(o)) + ; + }, + + // toplevel entry for loading JS/JSON/JSOB/CSV files + load : function (url,mimetype,cb) { + var text; + function filedia(e,process) { + popup.confirm({ + content : url+':
\n'+e+'
\n', + },function (reply) { + if (!reply.proceed) return; + Common.loadFile(function (data) { + if (!data) return; + cb(process(data)); + },false) + }); + } + if (typeof mimetype == 'function') cb=mimetype,mimetype=null; + if (!mimetype && url.match(/\.json$/)) mimetype='JSON'; + if (!mimetype && url.match(/\.js/)) mimetype='JS'; + if (!mimetype && url.match(/\.csv/)) mimetype='CSV'; + switch (mimetype && mimetype.replace(/application\//,'')) { + case 'JSON': + if (cb) return Utils.loadFile(url,function (text,err) { + if (!err) cb(Utils.ofJSON(text)); + else filedia(err,Utils.ofJSON); + }); + else return Utils.ofJSON(Utils.loadFile(url)); + case 'JSOB': + if (cb) return Utils.loadFile(url,function (text,err) { + if (!err) cb(Utils.ofString(text)); + else filedia(err,Utils.ofString); + }); + else return Utils.ofString(Utils.loadFile(url)); + case 'CSV': + if (cb) return Utils.loadFile(url,function (text,err) { + if (!err) cb(Utils.ofCSV(text)); + else filedia(err,Utils.ofCSV); + }); + else { + text =Utils.loadFile(url,null,true); + if (typeof text != 'string') return text; + else return Utils.ofCSV(text); + } + case 'JS': + default: + return Utils.loadScript(url); + break; + }; + + }, + + loadFile: function (url,cb) { + var result,error,_cb=cb; + if (!_cb) _cb=function (_result,_error) { result=_result; error=_error; }; + try { + // print(url+params) + var request = new XMLHttpRequest(); + request.open("GET",url, cb); + request.onreadystatechange = function () { + if(request.readyState === 4) + { + if(request.status === 200 || request.status == 0) + { + var allText = request.responseText; + _cb(allText); + } else _cb(null,'GET from '+url+' failed (status)'); + } + } + request.onerror = function (err) { + _cb(null,'GET from '+url+' failed (error)') + } + request.send(null); + } catch (e) { + _cb(null,e) + } + return error||result; + }, + + loadScript: function (filename) { + var fileref = document.createElement('script'); + fileref.setAttribute("type", "text/javascript"); + fileref.setAttribute("src", filename); + if (typeof fileref != "undefined") + document.getElementsByTagName("head")[0].appendChild(fileref) + }, + + name: function (o) { + switch (typeof o) { + case 'function': + return o.toString().match(/^function[ ]*([a-zA-Z0-9_]*)\([^\)]+\)/)[1]; + } + }, + + ofCSV : function (source,convert) { + try { + Papa.parse(source,{ + skipEmptyLines: true, + dynamicTyping: true, + complete: function(results) { + data=results.data; + if (convert) { // first line must be header + header=data.shift(); + data=data.map(function (row) { + var r={}; + header.forEach(function (col,i) { r[col]=row[i] }); + return r; + }) + } + } + }); + if (data && data[0].length==1) data=data.map(function (row) { return row[0] }); + return data; + } catch (e) { + return e; + } + }, + + ofJSON : function (source) { + return JSONfn.parse(source,{}); + }, + + /** Convert agent text sources to agent code in JSOB format + * + */ + ofString : function (source) { + var code; + try { + // execute script in private context + eval('code = '+source); + } catch (e) { console.log(e,source) }; + return code; + }, + + parseUrl : function (url) { + if (!url) return {}; + var queryString = url.substring( url.indexOf('?') + 1 ); + if (queryString == url) return {}; + var params = {}, queries, temp, i, l; + + // Split into key/value pairs + queries = queryString.split("&"); + + // Convert the array of strings into an object + for ( i = 0, l = queries.length; i < l; i++ ) { + temp = queries[i].split('='); + if (temp[1]==undefined) temp[1]='true'; + params[temp[0]] = temp[1].replace('%20',' '); + } + + return params; + }, + + + save : function (path,data,mimetype) { + if (!mimetype && path.match(/\.json$/)) mimetype='JSON'; + if (!mimetype && path.match(/\.csv/)) mimetype='CSV'; + switch (mimetype && mimetype.replace(/application\//,'')) { + case 'JSON': + if (typeof data == 'object') data=JSONfn.stringify(data); + break; + } + return Common.saveFile(data,path); + }, + + strip: function strip(line) { + return line.replace(/\"/g,'') + .replace(/\'/g,'') + }, + + + /** Cookie Management + * + */ + sessionCache : {}, + + setCookie:function setCookie(name,value,days) { + var expires = ""; + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days*24*60*60*1000)); + expires = "; expires=" + date.toUTCString(); + } + document.cookie = name + "=" + (value || "") + expires + "; path=/"; + Utils.sessionCache[name]=value; // fallback if cookies are denied + }, + + setCookieObject:function (name,obj,days) { + var expires = ""; + var value = JSONfn.stringify(obj); + if (days) { + var date = new Date(); + date.setTime(date.getTime() + (days*24*60*60*1000)); + expires = "; expires=" + date.toUTCString(); + } + document.cookie = name + "=" + (value || "") + expires + "; path=/"; + }, + + stringToArrayBuffer : function (str) { + var buf = new ArrayBuffer(str.length); + var bufView = new Uint8Array(buf); + + for (var i=0, strLen=str.length; i ' + result) + return result + } + + try { + var xhr = new XHR(), + err, + url = options.url || options.uri || ((options.proto?options.proto:'http')+'://'+options.host+':'+(options.port?options.port:80)+'/'+options.path), + is_cors = is_crossDomain(url), + supports_cors = ('withCredentials' in xhr) + + if(is_cors && !supports_cors) { + err = new Error('Browser does not support cross-origin request: ' + options.uri) + err.cors = 'unsupported' + return callback(err, xhr) + } + options.headers = options.headers || {}; + options.timeout = options.timeout || DEFAULT_TIMEOUT; + options.headers = options.headers || {}; + options.body = options.body || null; + + if(is_cors) xhr.withCredentials = !! options.withCredentials; + xhr.timeout = options.timeout; + + xhr.onopen = function () { + for (var key in options.headers) + xhr.setRequestHeader(key, options.headers[key]) + } + + xhr.onload = function () { + if(xhr.status === 0) { + err = new Error('EREQUEST') + callback(err, xhr) + } + else callback(null,xhr,xhr.responseText) + } + + xhr.ontimeout = function () { + // XMLHttpRequest timed out. Do something here. + err = new Error('ETIMEOUT') + err.duration = options.timeout + callback(err,xhr, null) + }; + + xhr.onrror = function () { + // XMLHttpRequest failed. Do something here. + err = new Error('ESERVER') + callback(err,xhr, null) + }; + + xhr.onreadystatechange = function () { + if (xhr.readyState === XHR.DONE) { + if(xhr.status === 0) { + err = new Error('ENETWORK') + callback(err, xhr) + } + } + }; + + switch (options.method) { + case 'GET': + case 'get': + xhr.open('GET', url, true /* async */); + xhr.send() + break; + case 'PUT': + case 'POST': + case 'put': + case 'post': + xhr.open('POST', url, true /* async */); + xhr.send(options.body) + break; + } + } catch (e) { _log(options,e);console.log(['xhr error: ',options.host,options.path,e].join(' ')); } + }, + + GET: function (url,params,cb,sync) { + var result; + // if (sync && !cb) cb=function (_result) { result=_result }; + if (url.indexOf('http')!=0) url = 'http://'+url; + try { + if (params) { + var o=params,sep=''; + params='/?'; + for(var p in o) { + params = params + sep + p + '='+o[p]; + sep='&'; + } + } else params=''; + // print(url+params) + var request = new XMLHttpRequest(); + request.open("GET",url+params, !sync); + request.onreadystatechange = function () { + if(request.readyState === 4) + { + if(request.status === 200 || request.status == 0) + { + var allText = request.responseText; + if (allText!='') result=JSONfn.parse(allText); + else result = new Error('GET data error (empty data)'); + if (cb) cb(result); + } else { + result=new Error('GET from '+url+params+' failed (status '+request.status+')'); + if (cb) cb(result) + } + } + } + request.onerror = function (error) { + result='Error: GET from '+url+params+' failed: '+error; + if (cb) cb(result); + } + request.send(null); + } catch (error) { + result=new Error('GET from '+url+params+' failed: '+error.toString()); + if (cb) cb(result); + } + return result; + }, + + POST: function (url,data,cb,sync){ + var result; + // if (sync && !cb) cb=function (_result) { result=_result }; + if (url.indexOf('http')!=0) url = 'http://'+url; + try { + var request = new XMLHttpRequest(); + request.open("POST", url, !sync); + request.onreadystatechange = function () { + if(request.readyState === 4) + { + if(request.status === 200 || request.status == 0) + { + var allText = request.responseText; + try { + if (allText!='') result=JSONfn.parse(allText) + else result=new Error('POST data error (empty data)'); + } catch (e) { + result = new Error(e.toString()); + } + if (cb) cb(result); + } else { + result = new Error('POST to '+url+' failed (status)'); + if (cb) cb(result); + } + } + } + request.onerror = function (error) { + result = new Error('POST to '+url+' failed: '+error); + if (cb) cb(result) + } + request.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); + request.send(JSONfn.stringify(data)); + } catch (error) { + result=new Error('POST to '+url+' failed: '+error.toString()); + if (cb) cb(result) + } + return result; + }, + + + version: '1.5.1' +} + +Utils._init = function () { + Object.addProperty = function (obj,name,fun) { + if (obj.prototype[name]) return; + obj.prototype[name]=fun; + Object.defineProperty(obj.prototype, name, {enumerable: false}); + }; + + Object.updateProperty = function (obj,name,fun) { + obj.prototype[name]=fun; + Object.defineProperty(obj.prototype, name, {enumerable: false}); + }; + + // Array static methods extensions + if (!Array.create) Array.create = function(length,init) { + var arr = [], i = length; + while (i--) { + arr[i] = init; + } + return arr; + } + + if (!Array.matrix) Array.matrix = function (rows,cols,init) { + if (init==undefined) init=0; + var mat=[]; + for(var i=0;i>4) & 0xf).toString(16))+ + ((n&0xf).toString(16)); + case 4: return (((n>>12) & 0xf).toString(16)+ + ((n>>8) & 0xf).toString(16)+ + ((n>>4) & 0xf).toString(16)+ + (n&0xf).toString(16)); + case 6: return (((n>>20) & 0xf).toString(16)+ + ((n>>16) & 0xf).toString(16)+ + ((n>>12) & 0xf).toString(16)+ + ((n>>8) & 0xf).toString(16)+ + ((n>>4) & 0xf).toString(16)+ + (n&0xf).toString(16)); + case 8: return (((n>>28) & 0xf).toString(16)+ + ((n>>24) & 0xf).toString(16)+ + ((n>>20) & 0xf).toString(16)+ + ((n>>16) & 0xf).toString(16)+ + ((n>>12) & 0xf).toString(16)+ + ((n>>8) & 0xf).toString(16)+ + ((n>>4) & 0xf).toString(16)+ + (n&0xf).toString(16)); + default: return 'format_hex??'; + } + }; + if (!String.set) String.set = function (str,index,char) { + return str.substr(0, index) + char + str.substr(index+1) + } + // String prototype extensions + Object.addProperty(String,'contains', function (el) { + return this.includes(el) + }) + + Object.addProperty(String, 'hashCode', function (seed) { + var str=this,seed=seed||0; + var h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed; + for (var i = 0, ch; i < str.length; i++) { + ch = str.charCodeAt(i); + h1 = Math.imul(h1 ^ ch, 2654435761); + h2 = Math.imul(h2 ^ ch, 1597334677); + } + h1 = Math.imul(h1 ^ (h1>>>16), 2246822507) ^ Math.imul(h2 ^ (h2>>>13), 3266489909); + h2 = Math.imul(h2 ^ (h2>>>16), 2246822507) ^ Math.imul(h1 ^ (h1>>>13), 3266489909); + return (4294967296 * (2097151 & h2) + (h1>>>0)).toString(16).toUpperCase(); + }); + + if (typeof assert == 'undefined') assert = function(condmsg) { + if (condmsg != true) { + Io.out('** Assertion failed: '+condmsg+' **'); + Io.stacktrace(); + throw Error(condmsg); + } + }; +} + +Utils._init(); + + + +