// //@ts-check
'use strict'
// $Id$
/**
*
* @category Tools
*
* @classdesc
* Helper functions
*
*/
export class Func {
constructor() {
}
/**
*
* Sanitize ID
*
* Remove :, =, ' '
*
* @param {string} id
* @returns {string}
*/
static sanitize(id) {
id = id.replace(/:/g, "")
id = id.replace(/=/g, "")
id = id.replace(/\s/g, "")
return id
}
/**
* Create a new ID
* @returns {string} New ID
*/
static createId () {
return "id" + Math.random().toString(16).slice(2)
}
/**
* Get number of bytes as formatted text in suitable units ['Bytes', 'kB', 'MB', 'GB']
*
* @param {number} size
* @returns {string}
*/
static getSizeAsString (size) {
const u = ['Bytes', 'kB', 'MB', 'GB']
let idx = 0
while (size > 1024) {
size /= 1024
idx++
if (idx >= (u.length - 1)) break;
}
return size.toFixed(idx) + " " + u[idx]
}
/**
* Clone/Deep copy this object
* @param {Object} obj
* @returns {Object}
*/
static clone (obj) {
let copy;
// Handle the 3 simple types, and null or undefined. Note that typeof null = 'object'
if (null == obj || "object" != typeof obj) return obj;
// Handle Date
if (obj instanceof Date) {
copy = new Date();
copy.setTime(obj.getTime());
return copy;
}
// Handle Array
if (obj instanceof Array) {
copy = [];
for (let i = 0, len = obj.length; i < len; i++) {
copy[i] = this.clone(obj[i]);
}
return copy;
}
// Handle Object
if (obj instanceof Object) {
copy = {};
for (const attr in obj) {
if (obj.hasOwnProperty(attr)) copy[attr] = this.clone(obj[attr]);
}
return copy;
}
throw new Error("Unable to copy obj! Unsupported type.");
}
/**
* Count objects/keys in a dictionary.
* @param {Object} obj
* @returns {number} Number of 'own' properties
*/
static count (obj) {
return Object.keys(obj).length // get only own properties, not properties from the prototype chain!
// var c = 0
// for (var i in obj) c++
// return c
}
/**
*
* @param {*} str
* @param {*} olds
* @param {*} news
* @returns {string}
*/
static replaceStr ( str, olds, news ) {
let val = String(str)
let m = val.split( olds )
let e = ''
let lb = ''
for( let j in m ) {
e += lb + m[j]
lb = news
}
return e
}
/**
* Compares content of two objects (yet not recursively for objects!)
*
* @param {Object} obj1
* @param {Object} obj2
* @param {boolean} [recursively] not implemented yet
* @returns {boolean}
*/
static compare (obj1, obj2, recursively = false) {
if(obj1 == null && obj2 != null ) return false
if(obj2 == null && obj1 != null ) return false
if(obj2 == null && obj1 == null ) return true
// check simple types
if (typeof obj1 !== 'object' || typeof obj2 !== 'object') {
if (obj1 === obj2) return true
console.log('>>> compare: ' + obj1 + ' !== ' + obj2 + ' <<<')
return false
}
// check arrays
if (Array.isArray(obj1) && Array.isArray(obj2)) {
return JSON.stringify(obj1) === JSON.stringify(obj2); // should be faster than recursive check?
}
// check dates
if (obj1 instanceof Date && obj2 instanceof Date) {
return obj1.getTime() === obj2.getTime();
}
// check properties
// console.log("obj1: " + JSON.stringify(obj1))
// console.log("obj2: " + JSON.stringify(obj2))
const props1 = Object.getOwnPropertyNames(obj1);
const props2 = Object.getOwnPropertyNames(obj2);
if (props1.length !== props2.length) {
return false;
}
// Compare the values of each property
for (const prop of props1) {
const val1 = obj1[prop]
const val2 = obj2[prop]
if (!this.compare(val1, val2)) {
return false;
}
}
return true;
}
/**
* Get tokens specified by start-end string in str
* Examples start = '[[' , end = ']]'
* @param {string} str
* @param {string} start
* @param {string} end
* @returns {Array<string>} Array with extracted tokens, empty array if no tokens could be extractred
*/
static getTokenList (str, start, end) {
let tokenlist = []
let token = ''
for (let i = 0; i < str.length - 1; i++) {
const g = str[i] + str[i + 1]
if (g == start) {
token = ''
i++
} else if (g == end) {
// console.log("token: " + token)
tokenlist.push(token)
token = ''
} else {
token += str[i]
}
}
return tokenlist
}
/**
*
* Create a md5 key from a given string
*
* @param {string} inputString
* @returns {string} MD5 key
*/
static md5 (inputString) {
let hc = "0123456789abcdef";
function rh(n) { var j, s = ""; for (j = 0; j <= 3; j++) s += hc.charAt((n >> (j * 8 + 4)) & 0x0F) + hc.charAt((n >> (j * 8)) & 0x0F); return s; }
function ad(x, y) { var l = (x & 0xFFFF) + (y & 0xFFFF); var m = (x >> 16) + (y >> 16) + (l >> 16); return (m << 16) | (l & 0xFFFF); }
function rl(n, c) { return (n << c) | (n >>> (32 - c)); }
function cm(q, a, b, x, s, t) { return ad(rl(ad(ad(a, q), ad(x, t)), s), b); }
function ff(a, b, c, d, x, s, t) { return cm((b & c) | ((~b) & d), a, b, x, s, t); }
function gg(a, b, c, d, x, s, t) { return cm((b & d) | (c & (~d)), a, b, x, s, t); }
function hh(a, b, c, d, x, s, t) { return cm(b ^ c ^ d, a, b, x, s, t); }
function ii(a, b, c, d, x, s, t) { return cm(c ^ (b | (~d)), a, b, x, s, t); }
function sb(x) {
var i; var nblk = ((x.length + 8) >> 6) + 1; var blks = new Array(nblk * 16); for (i = 0; i < nblk * 16; i++) blks[i] = 0;
for (i = 0; i < x.length; i++) blks[i >> 2] |= x.charCodeAt(i) << ((i % 4) * 8);
blks[i >> 2] |= 0x80 << ((i % 4) * 8); blks[nblk * 16 - 2] = x.length * 8; return blks;
}
var i, x = sb(inputString), a = 1732584193, b = -271733879, c = -1732584194, d = 271733878, olda, oldb, oldc, oldd;
for (i = 0; i < x.length; i += 16) {
olda = a; oldb = b; oldc = c; oldd = d;
a = ff(a, b, c, d, x[i + 0], 7, -680876936); d = ff(d, a, b, c, x[i + 1], 12, -389564586); c = ff(c, d, a, b, x[i + 2], 17, 606105819);
b = ff(b, c, d, a, x[i + 3], 22, -1044525330); a = ff(a, b, c, d, x[i + 4], 7, -176418897); d = ff(d, a, b, c, x[i + 5], 12, 1200080426);
c = ff(c, d, a, b, x[i + 6], 17, -1473231341); b = ff(b, c, d, a, x[i + 7], 22, -45705983); a = ff(a, b, c, d, x[i + 8], 7, 1770035416);
d = ff(d, a, b, c, x[i + 9], 12, -1958414417); c = ff(c, d, a, b, x[i + 10], 17, -42063); b = ff(b, c, d, a, x[i + 11], 22, -1990404162);
a = ff(a, b, c, d, x[i + 12], 7, 1804603682); d = ff(d, a, b, c, x[i + 13], 12, -40341101); c = ff(c, d, a, b, x[i + 14], 17, -1502002290);
b = ff(b, c, d, a, x[i + 15], 22, 1236535329); a = gg(a, b, c, d, x[i + 1], 5, -165796510); d = gg(d, a, b, c, x[i + 6], 9, -1069501632);
c = gg(c, d, a, b, x[i + 11], 14, 643717713); b = gg(b, c, d, a, x[i + 0], 20, -373897302); a = gg(a, b, c, d, x[i + 5], 5, -701558691);
d = gg(d, a, b, c, x[i + 10], 9, 38016083); c = gg(c, d, a, b, x[i + 15], 14, -660478335); b = gg(b, c, d, a, x[i + 4], 20, -405537848);
a = gg(a, b, c, d, x[i + 9], 5, 568446438); d = gg(d, a, b, c, x[i + 14], 9, -1019803690); c = gg(c, d, a, b, x[i + 3], 14, -187363961);
b = gg(b, c, d, a, x[i + 8], 20, 1163531501); a = gg(a, b, c, d, x[i + 13], 5, -1444681467); d = gg(d, a, b, c, x[i + 2], 9, -51403784);
c = gg(c, d, a, b, x[i + 7], 14, 1735328473); b = gg(b, c, d, a, x[i + 12], 20, -1926607734); a = hh(a, b, c, d, x[i + 5], 4, -378558);
d = hh(d, a, b, c, x[i + 8], 11, -2022574463); c = hh(c, d, a, b, x[i + 11], 16, 1839030562); b = hh(b, c, d, a, x[i + 14], 23, -35309556);
a = hh(a, b, c, d, x[i + 1], 4, -1530992060); d = hh(d, a, b, c, x[i + 4], 11, 1272893353); c = hh(c, d, a, b, x[i + 7], 16, -155497632);
b = hh(b, c, d, a, x[i + 10], 23, -1094730640); a = hh(a, b, c, d, x[i + 13], 4, 681279174); d = hh(d, a, b, c, x[i + 0], 11, -358537222);
c = hh(c, d, a, b, x[i + 3], 16, -722521979); b = hh(b, c, d, a, x[i + 6], 23, 76029189); a = hh(a, b, c, d, x[i + 9], 4, -640364487);
d = hh(d, a, b, c, x[i + 12], 11, -421815835); c = hh(c, d, a, b, x[i + 15], 16, 530742520); b = hh(b, c, d, a, x[i + 2], 23, -995338651);
a = ii(a, b, c, d, x[i + 0], 6, -198630844); d = ii(d, a, b, c, x[i + 7], 10, 1126891415); c = ii(c, d, a, b, x[i + 14], 15, -1416354905);
b = ii(b, c, d, a, x[i + 5], 21, -57434055); a = ii(a, b, c, d, x[i + 12], 6, 1700485571); d = ii(d, a, b, c, x[i + 3], 10, -1894986606);
c = ii(c, d, a, b, x[i + 10], 15, -1051523); b = ii(b, c, d, a, x[i + 1], 21, -2054922799); a = ii(a, b, c, d, x[i + 8], 6, 1873313359);
d = ii(d, a, b, c, x[i + 15], 10, -30611744); c = ii(c, d, a, b, x[i + 6], 15, -1560198380); b = ii(b, c, d, a, x[i + 13], 21, 1309151649);
a = ii(a, b, c, d, x[i + 4], 6, -145523070); d = ii(d, a, b, c, x[i + 11], 10, -1120210379); c = ii(c, d, a, b, x[i + 2], 15, 718787259);
b = ii(b, c, d, a, x[i + 9], 21, -343485551); a = ad(a, olda); b = ad(b, oldb); c = ad(c, oldc); d = ad(d, oldd);
}
return rh(a) + rh(b) + rh(c) + rh(d);
}
/**
* Elide text
*
* @param {string} str - Text
* @param {number} max_length - Maximum length of text
* @returns {string|null} Center elided text or null if str = null
*/
static elideText (str, max_length) {
if( str == undefined ) {
return null
}
if( typeof str != 'string' ) {
return str
}
if (str.length <= max_length) {
return str
}
const ellipsis = ' ... '
if (max_length < ellipsis.length) {
return str
}
const truncatedLength = Math.trunc(0.5 * (max_length - ellipsis.length))
let s = str.substring(0, truncatedLength + (max_length + 1) % 2)
s += ellipsis
s += str.substring(str.length - truncatedLength)
return s
}
/**
* Encode text from text to JSON acceptable text.
* So this text can be transferred and stored in a DB.
*
* \n -> <br>
* ' -> ```
*
* @param {string} str - Text to be encoded from JSON
* @returns {string}
*/
static txtToDb (str) {
if( str == undefined ) return ''
if( typeof str != 'string' ) str = String(str)
str = str.replace(/\n\r?/g, '<br>')
// str = str.replace( /\\n/g , '<br>' )
str = str.replace(/'/g, '```')
return str
}
/**
*
* Encode text from text to HTML acceptable text
*
* \n -> <br>
* ``` -> '
*
* @param {string} str
* @returns {string}
*/
static txtToHtml (str) {
if( str == undefined ) return ''
// str = str.replace( /\\n/g, '<br>')
str = str.replace(/\n\r?/g, '<br>')
str = str.replace(/```/g, "'")
return str
}
/**
*
* @param {string} str - Text to be decoded from DB format to JSON.
* @returns {string}
*/
static dbToTxt (str) {
if( str == undefined ) return ''
str = str.replace(/<br>/g, '\n')
str = str.replace(/```/g, "'")
return str
}
/**
* Convert a string which is stored in a db to a string
* that can be rendered in html.
*
* ``` -> '
*
* @param {*} str
* @returns {string}
*/
static dbToHtml (str) {
if( str == undefined ) return ''
// str = str.replace(/```/g, "'")
str = str.replace(/```/g, "'" )
return str
}
/**
*
* Sanitize string 'a' so it can be used in a html tooltip (title).
*
* @param {string} a
* @returns {string}
*/
static sanitizeTooltip( a ) {
return a.replace(/&/g, '&')
.replace(/'/g, ''')
.replace(/"/g, '"')
.replace(/</g, '<')
.replace(/>/g, '>');
}
/**
* Validates whether a text is a syntactically correct email address.
* Note: The only way to reliably verify that a supplied email is a working valid email is to send a mail with a verification link
*
* @param {string} str - String holding the Email address
* @returns {boolean} True, if validation is successful, else false
*/
static validateEmail (str) {
// version 1
const regex = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/g
// version 2 (RFC 5322 compliant)
//const regex = /^(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/g
return regex.test(str)
}
/**
* Check if pattern is a valid regex expression.
*
* @param {string} pattern
* @returns {boolean}
*/
static validateRegex (pattern) {
let regex = pattern
let options = ''
if (!pattern.startsWith('/')) {
return false
}
regex = pattern.slice(1)
const lastPos = regex.lastIndexOf('/')
if (lastPos >= 0) {
options = regex.slice(lastPos + 1)
regex = regex.slice(0, lastPos)
}
console.log("regex = " + regex)
console.log("options = " + options)
try {
new RegExp(regex, options);
return true;
}
catch (e) {
console.log(e)
return false;
}
}
/**
*
* @param {string} wildcard
* @returns {RegExp}
*/
static wildcardToRegex(wildcard) {
// escape special characters
const escapedWildcard = wildcard.replace(/[.+^${}()|[\]\\]/g, '\\$&');
// replace "*" with ".*" and "?" with "."
const regexString = escapedWildcard
.replace(/\*/g, '.*')
.replace(/\?/g, '.');
return new RegExp('^' + regexString + '$');
}
/**
* Check if pattern is a string representation (JSON) of an array.
*
* @param {string} pattern
* @returns {boolean}
*/
static validateArray (pattern) {
try {
const tmpVal = JSON.parse(pattern)
if (Array.isArray(tmpVal)) {
return true
}
} catch (e) {
console.log(e)
}
return false
}
/**
* Remove 'invalid'/invisible characters from string which can occur when copy-pasting from html pages
* Todo: better Black- or Whitelist? Ranges?
*
* @param {string} str
* @returns {string} Sanitized string
*/
static sanitizeText (str) {
str = str.replaceAll('\u200A', '') // HSP
str = str.replaceAll('\u200B', '') // ZwSP
str = str.replaceAll('\u200C', '') // ZwNJ
str = str.replaceAll('\u200D', '') // ZwJ
str = str.replaceAll('\u00A0', ' ') // Non-Breaking Space
str = str.replaceAll('\u00AD', '') // Soft Hyphen
// ...
return str
}
/**
* Convert hmtl to plain text.
*
* @param {string} html
* @param {boolean} all if true, get full text content (faster), else if slow get inner text (considering styles like display: none, slightly slower)
* @returns {string} Plain text, empty string if html is invalid
*/
static htmlToText (html, all) {
const tmpDiv = document.createElement('div')
tmpDiv.innerHTML = html
let txt = all ? tmpDiv.textContent : tmpDiv.innerText
if (!txt) txt = ''
tmpDiv.remove()
return txt
}
/**
*
* Compile filter string from id, type, name pattern and properties
*
* @param {*} projectlist can be empty
* @param {*} cataloguelist can be empty
* @param {*} constraints = {
* 'pattern_object_id' : ' ... ' // AND
* 'pattern_object_name' : ' ... ' // AND
* 'pattern_object_type' : ' ... ' // AND
* }
* @param {*} property_typeids Search in these property types
* @param {*} ptr_property Search in each property type for this pattern
*
* @returns Filterstring according to web service
*
*/
static compileFilterString ( projectlist, cataloguelist , constraints , property_typeids, ptr_property) {
let f = ''
let cfg = new Object(constraints)
let pattern_property = ptr_property
if (cfg.pattern_object_id) {
cfg.pattern_object_id = cfg.pattern_object_id.replace(/'/g, "\\'")
cfg.pattern_object_id = cfg.pattern_object_id.replace(/\*/g, "%")
cfg.pattern_object_id = cfg.pattern_object_id.replace(/"/g, "\\'")
}
if (cfg.pattern_object_name) {
cfg.pattern_object_name = cfg.pattern_object_name.replace(/'/g, "\\'")
cfg.pattern_object_name = cfg.pattern_object_name.replace(/\*/g, "%")
cfg.pattern_object_name = cfg.pattern_object_name.replace(/"/g, "\\'")
}
if (pattern_property) {
pattern_property = pattern_property.replace(/'/g, "\\'")
pattern_property = pattern_property.replace(/\*/g, "%")
pattern_property = pattern_property.replace(/"/g, "\\'")
}
let con = ''
let c1 = ' ( '
let c2 = ''
if (projectlist?.length > 0) {
if (projectlist.length = 1) {
f += c1 + "$project ~eq~ '" + projectlist[0] + "' "
} else {
f += c1 + "$project ~in~ " + JSON.stringify(projectlist)
}
c1 = ' $AND '
c2 = ' ) '
con = ' $AND '
} else if (cataloguelist?.length > 0) {
if (cataloguelist.length = 1) {
f += c1 + "$catalogue ~eq~ '" + cataloguelist[0] + "' "
} else {
f += c1 + "$catalogue ~in~ " + JSON.stringify(cataloguelist)
}
c1 = ' $AND '
c2 = ' ) '
con = ' $AND '
}
if (cfg.pattern_object_id?.length > 0) {
let op = '~eq~'
if (cfg.pattern_object_id.indexOf('%') >= 0) {
op = '~like~'
}
f += c1 + " $object_id " + op + " \'" + cfg.pattern_object_id + "\' " // $OR $object_name " + op + "\'" + pattern_object_id + " ) "
c1 = ' $AND '
c2 = ' ) '
con = ' $AND '
}
if (cfg.pattern_object_name?.length > 0) {
let op = '~eq~'
if (cfg.pattern_object_name.indexOf('%') >= 0) {
op = '~like~'
}
f += c1 + " $object_name " + op + " \'" + cfg.pattern_object_name + "\' "
c2 = ' ) '
con = ' $AND '
}
if ( cfg.pattern_object_type ) {
if (Array.isArray(cfg.pattern_object_type)) {
if( cfg.pattern_object_type.length > 0 ) {
let ll = "'" + cfg.pattern_object_type[0] + "'"
for( let i=1; i<cfg.pattern_object_type.length; i++ ) {
ll += ",'" + cfg.pattern_object_type[i] + "'"
}
f += c1 + " $object_type ~in~ [" + ll + "] "
}
} else {
if (cfg.pattern_object_type) {
cfg.pattern_object_type = cfg.pattern_object_type.replace(/'/g, "\\'")
cfg.pattern_object_type = cfg.pattern_object_type.replace(/\*/g, "%")
cfg.pattern_object_type = cfg.pattern_object_type.replace(/"/g, "\\'")
}
let op = '~eq~'
if (cfg.pattern_object_type.indexOf('%') >= 0) {
op = '~like~'
}
f += c1 + " $object_type " + op + " \'" + cfg.pattern_object_type + "\' "
}
c2 = ' ) '
con = ' $AND '
}
f += c2
if (property_typeids?.length > 0) {
f += con + ' ( '
con = ''
let patternlist = pattern_property.split(' ')
for (let i = 0; i < property_typeids.length; i++) {
let ptype = property_typeids[i]
ptype = '$' + ptype.trim()
// console.log("Ptype = [" + ptype + "]" )
let f_and = ''
let f_or = ''
let con_and = ''
let con_or = ''
f += con + ' ( '
for (let j = 0; j < patternlist.length; j++) {
let pat = patternlist[j]
pat = pat.trim()
// console.log("pat = [" + pat + "]")
if (pat.length < 1) continue
let op = ' ~eq~ '
if (pat.indexOf('%') >= 0) {
op = ' ~like~ '
}
if (pat[0] == '+') {
pat = pat.substring(1)
f_and += con_and + ptype + op + "'" + pat + "'"
con_and = ' $AND '
} else {
f_or += con_or + ptype + op + "'" + pat + "'"
con_or = ' $OR '
}
}
if (f_or.length > 0) {
f += " ( " + f_or + " ) "
if (f_and.length > 0) {
f += ' $AND '
}
}
f += f_and
f += " ) "
con = ' $OR '
}
f += ' ) '
}
console.log("=== > FILTER return [" + f + "]")
return f
}
/**
*
* @param {*} b64
* @returns {string}
*/
static atou (b64) {
return decodeURIComponent(escape(atob(b64)))
}
/**
*
* @param {*} data
* @returns {string}
*/
static utoa (data) {
return btoa(unescape(encodeURIComponent(data)));
}
/**
*
* @param {*} v
* @returns {boolean}
*/
static isValue (v) {
if (v == undefined) return false
if (v == './.') return false
if (v == '.*.') return false
if (v == '...') return false
return true
}
/**
*
* @param {*} val1
* @param {*} val2
* @param {Object} propertytype
* @param {Object} options
* {
* precision: 0.0001,
* case_sensitive: true
* }
* @returns {boolean}
*/
static isEqual (val1, val2, propertytype, options = null) {
if (!propertytype) return false
if (propertytype.datatype == 'xs:double' || propertytype.datatype == 'xs:double') {
const precision = options?.precision || 0.0001
let v1 = parseFloat(val1)
let v2 = parseFloat(val2)
if (Math.abs(v1 - v2) < precision) return true
return false
} else if (propertytype.datatype == 'xs:boolean') {
let f = [false, 'false', 0, '0'] // all numbers != 0 -> true
return (f.includes(val1) === f.includes(val2))
}
if (options?.case_sensitive == false && typeof val1 == 'string' && typeof val2 == 'string') {
return (val1.toLower() == val2.toLower())
}
return (val1 == val2)
}
/**
* Check if a property value matches the given values.
*
* @param {any} value Value of property. If null or undefined, false will be returned.
* @param {string} xsdatatype Explicit data type of value ('xs:...')
* @param {*} matchvalue Values : '*', ["A","B", "C"], [1,2,3], /^abc/g, == 'Text', > 1.234
* @param {Object} propertymap Evaluated values for property references [[name##type]]
* {
* 'Text##xs:string' : "ABC",
* 'Number##xs:double' : 1.234
* }
* @returns {boolean} true if match was successful, else false
*/
static matchValue(value, propertytype, matchvalue, propertymap = null) {
// console.log("")
// console.log("VALUE: " + v )
// console.log("MATCH: " + matchvalue )
// console.log("TYPE: " + propertytype )
if (value == undefined) {
return (matchvalue === '!*')
}
if (matchvalue === '*') {
return true
}
let check = false
let isNumber = false;
const ptype_number = ['xs:double', 'xs:float', 'xs:int', 'xs:long']
const ptype_string = ['xs:string', 'xs:ID', 'xs:IDREF', 'xs:anyURI']
if (ptype_number.indexOf(propertytype) > -1) {
isNumber = true
value = parseFloat(value).toFixed(5)
if (Array.isArray(matchvalue)) {
for (const i in matchvalue) matchvalue[i] = parseFloat(matchvalue[i]).toFixed(5)
}
}
if (Array.isArray(matchvalue)) { // check containment in list ["ABC", "DEF"] or [1.23456, 5.00000. -9.10000]
check = (matchvalue.indexOf(value) >= 0)
} else if (matchvalue.startsWith("/")) { // check RegExp
let pattern = matchvalue
let options = ''
if (pattern.startsWith('/')) {
pattern = pattern.slice(1)
const pos = pattern.lastIndexOf('/')
if (pos > -1) {
options = pattern.slice(pos + 1)
pattern = pattern.slice(0, pos)
}
}
let r = null
try {
r = new RegExp(pattern, options)
} catch (e) {
console.log(e)
}
if (r) {
check = (value.match(r) != null)
} else {
check = false
}
// console.log("=> regex, return " + check )
// console.log("")
} else {
// console.log("is number? " + isNumber)
if (isNumber) {
if (isNaN(matchvalue) == true) { // isNaN erwartet eigentlich den Datentyp number als Parameter, funktioniert aber auch für nicht-leere Strings wie '[[.]] > 5'
let t = ''
if (matchvalue.indexOf('[[.]]') >= 0) {
t = "( " + matchvalue + " )"
t = t.replaceAll('[[.]]', value)
// "[[.]] > 1 && [[.]] < 5"
// => "(value > 1 && value < 5)"
} else {
t = "(" + value + " " + matchvalue + ")"
// "5"
// => "(value 5)"
}
// console.log("eval : " + t)
if (propertymap) {
for (let p in propertymap) {
t.replaceAll('[[' + p + ']]', propertymap[p])
}
}
try {
///////////////
check = window.eval(t)
///////////////
} catch (e) {
console.log(e)
}
} else {
check = (Math.abs(matchvalue - value) < 0.0001)
// console.log("check: " + matchvalue + " - " + value + " = " + (matchvalue-value) )
}
} else {
let t = ''
if (matchvalue.indexOf('[[.]]') >= 0) {
t = "( " + matchvalue + " )"
if (ptype_string.indexOf(propertytype) >= 0) {
t = t.replaceAll('[[.]]', "'" + value + "'")
} else {
t = t.replaceAll('[[.]]', value)
}
} else {
if (ptype_string.indexOf(propertytype) >= 0) {
value = "'" + value + "'" // 'Textwert' == 'Vergleichszeichenkette'
}
t = "(" + value + " " + matchvalue + ")"
}
if (propertymap) {
for (let p in propertymap) {
t.replaceAll('[[' + p + ']]', propertymap[p])
}
}
// console.log("eval : " + t)
try {
// eval() should not be used with bundlers
// => Using direct eval with a bundler is not recommended and may cause problems [direct-eval]
///////////////
check = window.eval(t)
///////////////
} catch (e) {
console.log(e)
}
}
}
// console.log("return " + check )
// console.log("")
return check
}
/**
* Convert component (R,G or B) to hex value.
* 0 => 0
* 255 => FF
*
* @param {number} c
* @returns {string}
*/
static componentToHex (c) {
const hex = c.toString(16);
return hex.length == 1 ? "0" + hex : hex;
}
/**
*
* Convert (RGB) color to hex value
*
* (0,0,0) => #000000
* (255,255,255) => #FFFFFF
*
* @param {*} r
* @param {*} g
* @param {*} b
* @returns {string}
*/
static rgbToHex (r, g, b) {
return "#" + cn_func.componentToHex(r) + cn_func.componentToHex(g) + cn_func.componentToHex(b);
}
/**
*
* @param {*} a
* @param {*} b
* @returns {boolean}
*/
static xor( a , b ) {
return ( a || b ) && !( a && b )
}
/**
*
* Increase Index given as A0, A1, ... , B0, B1, ...
*
* @param {*} str_number
* @returns {string}
*/
static increaseIndex ( str_number ) {
console.log('---')
str_number = String(str_number)
if( str_number == '' ) {
console.log('retunnnn')
return "A0"
}
// Separate the letter and number parts
let letter = str_number[0];
let number = parseInt( str_number.slice(1), 10 )
// Increment the number
number++;
// If the number reaches 10, reset to 0 and increment the letter
if (number === 10) {
number = 0;
letter = String.fromCharCode(letter.charCodeAt(0) + 1);
}
// Return the next value in the format "A0", "A1", ..., "B0", etc.
console.log( "return : " + `${letter}${number}` )
return `${letter}${number}`
}
/**
*
* @returns {string}
*/
static createTimestamp () {
const now = new Date();
const year = now.getFullYear();
const month = String(now.getMonth() + 1).padStart(2, '0'); // Months are 0-based
const day = String(now.getDate()).padStart(2, '0');
const hours = String(now.getHours()).padStart(2, '0');
const minutes = String(now.getMinutes()).padStart(2, '0');
const seconds = String(now.getSeconds()).padStart(2, '0');
return `${year}${month}${day}_${hours}${minutes}${seconds}`;
}
/**
* replaces each character of !"#$%&'()*+,./:;<=>?@[\]^`{|}~ with _<ASCIcode>_. So jQuery can work with it.
* see jquery docs: https://api.jquery.com/category/selectors/
* Escaping with \\ as recommended there didn't work.
* @param {String} id any String used as id with jquery
* @returns {String} id but each character of !"#$%&'()*+,./:;<=>?@[\]^`{|}~ replaced by _<ASCIcode>_
*
*/
static replaceSpecialCharsWithASCII(id){
if (!id) return id
const specialChars = /[!"#$%&'()*+,./:;<=>?@[\]^` {|}~]/g
return id.replace(specialChars, match => {
return `_${match.charCodeAt(0)}_`;
})
}
}
Source