/* Method: jsonAppObj Description: Functionality for jsonAppObj. @param {any} options - Description for options @returns {any} - Result of the operation */ var jsonAppObj = function (options) { var self = this; console.log(); this.json = { setup: {}, blocks: {}, parts: {}, functions: {}, do: {}, on: {}, shortcuts: {}, texts: {}, data: {}, var: {} }; this.app = this.json; var alertObj = {}; var alertValues = {}; this.params = {}; this.javascriptReservedWord = ['abstract', 'arguments', 'await', 'boolean', 'break', 'byte', 'case', 'catch', 'char', 'class', 'const', 'continue', 'debugger', 'default', 'delete', 'do', 'double', 'else', 'enum', 'eval', 'export', 'extends', 'false', 'final', 'finally', 'float', 'for', 'function', 'goto', 'if', 'implements', 'import', 'in', 'instanceof', 'int', 'interface', 'let', 'long', 'native', 'new', 'null', 'package', 'private', 'protected', 'public', 'return', 'short', 'static', 'super', 'switch', 'synchronized', 'this', 'throw', 'throws', 'transient', 'true', 'try', 'typeof', 'var', 'void', 'volatile', 'while', 'with', 'yield', 'Array', 'Date', 'eval', 'function', 'hasOwnProperty', 'Infinity', 'isFinite', 'isNaN', 'isPrototypeOf', 'length', 'Math', 'NaN', 'name', 'Number', 'Object', 'prototype', 'String', 'toString', 'undefined', 'valueOf', 'getClass', 'java', 'JavaArray', 'javaClass', 'JavaObject', 'JavaPackage', 'alert', 'all', 'anchor', 'anchors', 'area', 'assign', 'blur', 'button', 'checkbox', 'clearInterval', 'clearTimeout', 'clientInformation', 'close', 'closed', 'confirm', 'constructor', 'crypto', 'decodeURI', 'decodeURIComponent', 'defaultStatus', 'document', 'element', 'elements', 'embed', 'embeds', 'encodeURI', 'encodeURIComponent', 'escape', 'event', 'fileUpload', 'focus', 'form', 'forms', 'frame', 'innerHeight', 'innerWidth', 'layer', 'layers', 'link', 'location', 'mimeTypes', 'navigate', 'navigator', 'frames', 'frameRate', 'hidden', 'history', 'image', 'images', 'offscreenBuffering', 'open', 'opener', 'option', 'outerHeight', 'outerWidth', 'packages', 'pageXOffset', 'pageYOffset', 'parent', 'parseFloat', 'parseInt', 'password', 'pkcs11', 'plugin', 'prompt', 'propertyIsEnum', 'radio', 'reset', 'screenX', 'screenY', 'scroll', 'secure', 'select', 'self', 'setInterval', 'setTimeout', 'status', 'submit', 'taint', 'text', 'textarea', 'top', 'unescape', 'untaint', 'window', 'onblur', 'onclick', 'onerror', 'onfocus', 'onkeydown', 'onkeypress', 'onkeyup', 'onmouseover', 'onload', 'onmouseup', 'onmousedown', 'onsubmit']; var nodes = { extend: ['setup', 'blocks', 'parts', 'css', 'actions', 'texts', 'data', 'functions'], params: ['style', 'on', 'matchMedia', 'action', 'code', 'roles', 'plugins', 'css'], exclude: ['setup', 'container', 'selector', 'info', 'note', 'comment', 'lang', 'tag', 'plugins', 'template'] }; const FORMAT_REGEX = { email: /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/, url: /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/, ip: /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/, date: /^(?:(?:31(\/|-|\.)(?:0?[13578]|1[02]))\1|(?:(?:29|30)(\/|-|\.)(?:0?[13-9]|1[0-2])\2))(?:(?:1[6-9]|[2-9]\d)?\d{2})$|^(?:29(\/|-|\.)0?2\3(?:(?:(?:1[6-9]|[2-9]\d)?(?:0[48]|[2468][048]|[13579][26])|(?:(?:16|[2468][048]|[3579][26])00))))$|^(?:0?[1-9]|1\d|2[0-8])(\/|-|\.)(?:(?:0?[1-9])|(?:1[0-2]))\4(?:(?:1[6-9]|[2-9]\d)?\d{2})$/, color: /^#(?:[0-9a-fA-F]{3}){1,2}$|#(?:[0-9a-fA-F]{3,4}){1,2}$/, }; /* Method: jsonToSchema Description: Functionality for jsonToSchema. @param {any} json - Description for json @param {any} options = {} - Description for options = {} @returns {any} - Result of the operation */ this.jsonToSchema = function (json, options = {}) { if (typeof json === 'function') { throw new TypeError('Can not convert a function'); } if (json === undefined) { return {}; } if (typeof json === 'string') { if (FORMAT_REGEX.url.test(json)) return { type: 'string', format: 'url' }; else if (FORMAT_REGEX.email.test(json)) return { type: 'string', format: 'email' }; else if (FORMAT_REGEX.ip.test(json)) return { type: 'string', format: 'ip' }; else if (FORMAT_REGEX.date.test(json)) return { type: 'string', format: 'date' }; else if (FORMAT_REGEX.color.test(json)) return { type: 'string', format: 'color' }; else return { type: 'string' }; } else if (typeof json === 'boolean') return { type: 'boolean' }; else if (typeof json === 'number') { if (Number.isInteger(json)) { return { type: 'integer' }; } else { return { type: 'number' }; } } else if (Array.isArray(json)) { let schema = { type: 'array' }; if (!json.length) { schema.items = {}; return schema; } let schemas = json.map(self.jsonToSchema); if (schemas.every(s => self.isEqual(s, schemas[0]))) { schema.items = schemas[0]; } else { schema.items = { oneOf: unique(schemas) }; } return schema; } if (json === null) { return { type: 'null' }; } let schema = { type: 'object' }; if (!Object.keys(json).length) { return schema; } schema.properties = Object.keys(json).reduce((properties, key) => { properties[key] = self.jsonToSchema(json[key]); return properties; }, {}); return schema; }; /* Method: isEqual Description: Functionality for isEqual. @param {any} a - Description for a @param {any} b - Description for b @returns {any} - Result of the operation */ this.isEqual = function (a, b) { return (JSON.stringify(a) == JSON.stringify(b)); }; this.dataStorage = { _storage: new WeakMap(), set: function (element, key, obj) { if (!this._storage.has(element)) { this._storage.set(element, new Map()); } this._storage.get(element).set(key, obj); }, get: function (element, key) { return this._storage.get(element).get(key); }, has: function (element, key) { return this._storage.has(element) && this._storage.get(element).has(key); }, remove: function (element, key) { var ret = this._storage.get(element).delete(key); if (!this._storage.get(element).size === 0) { this._storage.delete(element); } return ret; } }; /* Method: extend Description: Functionality for extend. @param {any} out - Description for out @returns {any} - Result of the operation */ this.extend = function (out) { if (typeof arguments[0] == 'boolean' && arguments[0] == true) return deepExtend(out); else { out = out || {}; for (var i = 1; i < arguments.length; i++) { if (!arguments[i]) continue; for (var key in arguments[i]) { if (arguments[i].hasOwnProperty(key)) out[key] = arguments[i][key]; } } return out; } }; /* Method: deepExtend Description: Functionality for deepExtend. @param {any} out - Description for out @returns {any} - Result of the operation */ var deepExtend = function (out) { out = out || {}; for (var i = 1; i < arguments.length; i++) { var obj = arguments[i]; if (!obj) continue; for (var key in obj) { if (obj.hasOwnProperty(key)) { if (typeof obj[key] === "object" && obj[key] !== null) { if (obj[key] instanceof Array) out[key] = obj[key].slice(0); else out[key] = deepExtend(out[key], obj[key]); } else out[key] = obj[key]; } } } return out; }; /* Method: var Description: Functionality for var. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.var = function (params, args) { if (Array.isArray(params)) { for (var index in params) self.var(params[index], args); } else { var name; var value; var varValue; if (params.path && !params.name) name = self.path(params.path, args, '.'); if (typeof params == 'string') { name = self.replaceProperties(params, args); varValue = self.docElement('self.json.var.' + name); } else { var paramsReplaced = self.replaceProperties(params, args); name = paramsReplaced.name; value = paramsReplaced.value; var operator = paramsReplaced.operator; var type = paramsReplaced.type; if (name) { var pathString = 'self.json.var.' + name; var pathLast = pathString.substr(pathString.lastIndexOf(".") + 1); var pathBase = pathString.substr(0, pathString.lastIndexOf(".")); var varObj = self.docElement(pathBase); if (value !== undefined) { value = self.actionResult(value, args); switch (type) { case 'string': value = String(value); break; case 'number': value = Number(value); break; case 'boolean': value = Boolean(value); break; case 'array': value = JSON.parse(value); break; case 'object': value = JSON.parse(value); break; } if (varObj && pathLast) { switch (operator) { case '+=': varObj[pathLast] += value; break; case '-=': varObj[pathLast] -= value; break; case '/=': varObj[pathLast] /= value; break; case '*=': varObj[pathLast] *= value; break; default: varObj[pathLast] = value; break; } varValue = varObj[pathLast]; } else { self.docElement(pathString, value); } } else if (paramsReplaced.push) { if (varObj && pathLast && varObj[pathLast]) { varObj[pathLast] = varObj[pathLast].push(paramsReplaced.push); varValue = varObj[pathLast]; } } else if (paramsReplaced.extend) { if (varObj && pathLast && varObj[pathLast]) { varObj[pathLast] = self.extend({}, varObj[pathLast], paramsReplaced.extend); varValue = varObj[pathLast]; } } else { varValue = varObj[pathLast]; } } else { self.log('var name undefined'); self.log(params); varValue = undefined; } if (params.do && params.do.length > 0) { self.log('this.var params.do'); self.log(params.do); self.do(params.do, undefined, args); } } return varValue; } }; /* Method: find Description: Functionality for find. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.find = function (params, args) { if (params.in) { var list = self.replaceProperties(params.in, args); return list.filter(function (item) { if (params.value) { if (typeof params.value == 'string') { if (JSON.stringify(item).indexOf(params.value) >= 0) return item; } else { for (var key in params.value) { if (params.value[key] == item[key]) return item; } } } }); } }; /* Method: array Description: Functionality for array. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.array = function (params, args) { if (args) params = self.replacePropertyWithPrefix(params, 'result', args); for (var par in params) { var paramReplaced = self.replaceProperties(params[par], args); params[par] = paramReplaced; } var value = self.element({ path: params.name }) || []; if (params.push) { if (Array.isArray(params.push)) value.push(...params.push); else value.push(params.push); } if (params.unshift) value.unshift(...params.unshift); if (params.pop) return value.pop(params.pop); if (params.shift) return value.shift(params.shift); self.element({ path: params.name, value: value }); }; /* Method: replace Description: Functionality for replace. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.replace = function (params, args) { params = self.replacePropertyWithPrefix(params, 'result', args); var value = self.element({ path: params.path }) || []; var to = params.to || ''; var type = typeof value; if (type !== "string") value = JSON.stringify(value); if (params.from) value = self.replaceAll(value, params.from, to); switch (type) { case "number": value = Number(value); break; case "boolean": value = Boolean(value); break; case "object": value = JSON.parse(value); break; } return self.element({ path: params.path, value: value }); }; /* Method: unshift Description: Functionality for unshift. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.unshift = function (params, args) { for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || []; obj.unshift(value); self.element({ path: path, value: obj }); } } }; /* Method: set Description: Functionality for set. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.set = function (params, args) { if (Array.isArray(params)) { for (var obj of params) self.set(obj, args); } else { for (var param in params) { var value = params[param]; if (value) value = self.replaceProperties(value, args, false); if (value && args) value = self.replacePropertyWithPrefix(value, 'result', args); self.element({ path: param, value: value }); } } }; /* Method: get Description: Functionality for get. @param {any} element - Description for element @returns {any} - Result of the operation */ this.get = function (element) { if (element.startsWith('\'')) return String(element.match(/\'([^\']*)\'/)[1]); // stringa racchiusa tra apici (serve?) else if (element.startsWith('Boolean')) return Boolean(element.match(/Boolean\(([^\)]*)\)/)[0]); // Boolean(x) else if (element.startsWith('Number')) return Number(element.match(/Number\(([^\)]*)\)/)[0]); // Number(x) else if (element.startsWith('String')) return String(element.match(/String\(([^\)]*)\)/)[0]); // String(x) else return (self.docElement(element)); // ora le tipizzazioni sono già in docElement grazie a eval }; /* Method: getJSON Description: Functionality for getJSON. @param {any} url - Description for url @param {any} callback - Description for callback @returns {any} - Result of the operation */ this.getJSON = function (url, callback) { var xhr = new XMLHttpRequest(); xhr.open('GET', url, true); xhr.responseType = 'json'; xhr.onload = function () { var status = xhr.status; if (status === 200) { callback(null, xhr.response); } else { callback(status, xhr.response); } }; xhr.send(); }; /*--------------------- var ---------------------*/ var database, auth, storage; this.listeners = {}; this.resizeActions = {}; /* var iconsFile; this.device = false; // touch device this.touch = 'mousedown'; if (this.device) {this.touch = 'touchstart';} var animations = {}; var tweenLoading; var tasksIntervals = {}; var timedTasks = {'yearly':{},'monthly':{},'daily':{},'hourly':{}, '10mins':{}, '5mins':{}, '30mins':{}, '1min':{}, '30sec': {}, '10sec': {}, '1sec': {}}; */ /* this.dateSelection; // = {day:0, month:0, year:0}; this.timeSelection = {hour:0, min:0, sec:0, ampm:'AM', allday:true}; this.timeSelectionCallback = null; */ /*-------------------- FIREBASE --------------------*/ //var firebaseInitialized = false; /* Method: firebaseVerifyUser Description: Functionality for firebaseVerifyUser. @param {any} data - Description for data @returns {any} - Result of the operation */ this.firebaseVerifyUser = function (data) { self.log('firebaseVerifyUser'); //self.log(data); //self.log(data.code); if (self.params.oobCode) { var oobCode = self.params.oobCode; auth.applyActionCode(oobCode).then(function (resp) { // self.log('resp'); // self.log(resp); self.alert({ //toast: true, icon: "success", title: "titVerifyEmail", html: "msgVerifyEmail", confirmButtonText: "btnOk", //showCancelButton: false, confirm: function () { //self.reload(); // self.do(data); window.location.href = "/app/index.html"; } }); }).catch(function (error) { self.log('error'); self.alert({ icon: "error", title: "titWarning", html: error.code + " - " + error.message, confirmButtonText: "btnOk", //showCancelButton: false, confirm: function () { // self.reload(); // self.do(data); window.location.href = "/app/index.html"; } }); }); // verifica su auth } //data.code / data.params.code //self.do(data); self.do(data); }; /* /* Method: firebaseInit Description: Functionality for firebaseInit. @param {any} data - Description for data @returns {any} - Result of the operation */ this.firebaseInit = function (data) { self.log("firebaseInit"); if (json.setup && json.setup.firebase) { //var.databaseURL = json.setup.firebase.databaseURL; firebase.initializeApp(json.setup.firebase); database = firebase.database(); auth = firebase.auth(); // if (self.json.plugins['firebase-storage'].active) OR find in self.json.plugins name: 'firebase-storage' //storage = firebase.storage(); auth.onAuthStateChanged(user => { self.json.var.user = user; if (!user) { // No user logged in self.log('onAuthStateChanged:GUEST\n'); // non bisognerebbe chiedere sempre di fare login } else { // User logged in self.log('onAuthStateChanged:USER\n'); self.log('name: '+self.user('displayName') + '\nemail: '+user.email + '\nuid: '+ user.uid); } //self.log('firebaseInitialized'); //self.log(firebaseInitialized); if (!firebaseInitialized) { firebaseInitialized = true; self.do(data); } }); } else { self.do(data); } } */ /* Method: sendMail Description: Functionality for sendMail. @param {any} data - Description for data @returns {any} - Result of the operation */ this.sendMail = function (data) { self.log('sendMail'); var emailParams = { Host: "smtp.mailgun.com", Username: "vito@nuvolaria.com", Password: "bee02191be84c784a665fa98c61e03ce-915161b7-d32cb9d0", From: data.from, To: data.to, Subject: data.subject, Body: data.html }; Email.send(emailParams).then( message => self.alert({ icon: 'success', title: 'titEmailSuccess', confirmButtonText: 'btnClose' }) ); /* "from": "gianfrancoguglielmi@gmail.com", "to": "vito.minchilli@gmail.com", "subject": "Prova oggetto", "html": "Prova testo", "text": "Prova testo" */ /* var SERVER_NODEJS_BASEURL='https: var params = { rom: data.from, to: data.to, subject: data.subject, html: data.html, text: data.text }; $.ajax({ type: "POST", 'beforeSend': function(xhr) { xhr.setRequestHeader('Accept', 'application/json'); xhr.setRequestHeader('Content-Type', 'application/json'); }, data: JSON.stringify(params), url: SERVER_NODEJS_BASEURL + '/sendMail', success: function(data) { self.log('sendMail SUCCESS'); self.log(data); self.do(data); }, error: function(error) { self.log('sendMail ERROR'); self.log(error); self.do(data); } }); */ }; var x = [{ if: 3 }, function () { }, 3, []]; /* Method: firebaseAddListener Description: Functionality for firebaseAddListener. @param {any} params - Description for params @returns {any} - Result of the operation */ this.firebaseAddListener = function (params) { if (database) { if (params.action) { if (!self.listeners[params.path]) self.listeners[params.path] = []; self.listeners[params.path].push(params.action); } var dbRef = database.ref(params.path); dbRef.off(); if (params.orderByChild) dbRef = dbRef.orderByChild(params.orderByChild); if (params.orderByKey) dbRef = dbRef.orderByKey(params.orderByKey); if (params.orderByValue) dbRef = dbRef.orderByValue(params.orderByValue); if (params.equalTo) dbRef = dbRef.equalTo(params.equalTo); if (params.startAt) dbRef = dbRef.startAt(params.startAt); if (params.startAfter) dbRef = dbRef.startAfter(params.startAfter); if (params.endAt) dbRef = dbRef.endAt(params.endAt); if (params.endBefore) dbRef = dbRef.endBefore(params.endBefore); if (params.limitToFirst) dbRef = dbRef.limitToFirst(params.limitToFirst); if (params.limitToLast) dbRef = dbRef.limitToLast(params.limitToLast); if (params.where) dbRef = dbRef.where(params.where[0], params.where[1], params.where[2]); var feedback = dbRef.on('value', firebaseEvent); } else { self.log('database undefined'); } }; /* Method: firebaseEvent Description: Functionality for firebaseEvent. @param {any} snapshot - Description for snapshot @returns {any} - Result of the operation */ var firebaseEvent = function (snapshot) { console.log(snapshot.val()); var ref = snapshot.ref; if (snapshot.val() !== undefined) { var dbVal = snapshot.val(); var path = snapshot.ref.toString(); var pathArr = path.split(/\.\w+\ var dbPath = pathArr[1]; self.log('firebaseEvent: ' + dbPath); if (dbVal) self.localDbUpdate(dbVal, dbPath); else { var dbObj = self.element({ path: 'self.json.var.db.' + self.replaceAll(dbPath, '/', '.') }); if (dbObj) dbObj = null; } } }; /* Method: localDbUpdate Description: Functionality for localDbUpdate. @param {any} newObj - Description for newObj @param {any} dbPath - Description for dbPath @returns {any} - Result of the operation */ this.localDbUpdate = function (newObj, dbPath) { newObj = Object.fromEntries(Object.entries(newObj).reverse()); self.element({ path: 'self.json.var.db.' + self.replaceAll(dbPath, '/', '.'), value: newObj }); if (self.listeners[dbPath] !== undefined && self.listeners[dbPath] !== null && self.listeners[dbPath].length > 0) { newObj.path = dbPath; if (self.listeners[dbPath]) { self.methods.firebaseEvent.action(newObj); self.do(self.listeners[dbPath], undefined, newObj); } } }; /* Method: firebaseRemoveListener Description: Functionality for firebaseRemoveListener. @param {any} params - Description for params @returns {any} - Result of the operation */ this.firebaseRemoveListener = function (params) { self.log('firebaseRemoveListener'); if (self.listeners[params.path]) { delete self.listeners[params.path]; var dbRef = database.ref(params.path); dbRef.off(); } }; /* Method: firebaseRemove Description: Functionality for firebaseRemove. @param {any} path - Description for path @param {any} callback - Description for callback @returns {any} - Result of the operation */ this.firebaseRemove = function (path, callback) { self.log('firebaseRemove'); self.log(path); if (database) { var result, dbRef; if (path) { dbRef = database.ref().child(path); } else { dbRef = database.ref(); } return dbRef.remove(function (error) { if (error == null) { self.log('set SUCCESS'); result = { success: true }; } else { self.log('set ERROR'); result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; /* Method: firebaseSet Description: Functionality for firebaseSet. @param {any} path - Description for path @param {any} value - Description for value @param {any} callback - Description for callback @returns {any} - Result of the operation */ this.firebaseSet = function (path, value, callback) { if (database) { var result, dbRef; if (path) { dbRef = database.ref().child(path); } else { dbRef = database.ref(); } return dbRef.set(value, function (error) { if (error == null) { self.log('set SUCCESS'); result = { success: true }; } else { self.log('set ERROR'); result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; /* Method: firebaseUpdate Description: Functionality for firebaseUpdate. @param {any} path - Description for path @param {any} value - Description for value @param {any} callback - Description for callback @returns {any} - Result of the operation */ this.firebaseUpdate = function (path, value, callback) { self.log('firebaseUpdate'); self.log('path'); self.log(path); self.log('value'); self.log(value); if (database) { var result, dbRef; if (path) { dbRef = database.ref().child(path); } else { dbRef = database.ref(); } return dbRef.update(value, function (error) { if (error == null) { self.log('update SUCCESS'); result = { success: true }; } else { self.log('update ERROR'); result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; /* Method: firebasePush Description: Functionality for firebasePush. @param {any} path - Description for path @param {any} value - Description for value @param {any} callback - Description for callback @returns {any} - Result of the operation */ this.firebasePush = function (path, value, callback) { self.log('firebasePush'); self.log(path); if (database) { var result, dbRef; if (path) { dbRef = database.ref().child(path); } else { dbRef = database.ref(); } return dbRef.push(value, function (error) { if (error == null) { self.log('push SUCCESS'); result = { success: true }; } else { self.log('push ERROR'); result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; /* Method: firebaseGetPart Description: Functionality for firebaseGetPart. @param {any} params - Description for params @returns {any} - Result of the operation */ this.firebaseGetPart = function (params) { self.log('firebaseGetPart'); let remotePath = self.replaceAll(params.localPath, '.', '/'); self.log('localPath:' + params.localPath); if (self.partContainers[params.localPath]) { self.partContainers[params.localPath].push(params); } else { self.partContainers[params.localPath] = []; self.partContainers[params.localPath].push(params); dbRef = database.ref().child(remotePath); return dbRef.once('value').then(function (object) { if (object) { self.log('firebaseGetPart SUCCESS'); self.log(object); if (object.val() !== undefined) { window.dbVal = object.val(); var dbVal = object.val(); self.log('dbVal'); self.log(dbVal); if (dbVal !== null) { let fullPath = object.ref.toString(); let pathArr = fullPath.split(/\.\w+\ let dbPath = pathArr[1]; let localPath = self.replaceAll(dbPath, '/', '.'); self.log('dbPath: ' + dbPath); self.log('localPath: ' + localPath); self.element({ path: localPath, value: dbVal }); for (partObj of self.partContainers[localPath]) { let part = self.replacePropertyWithPrefix(dbVal, 'setup', partObj.setup); part = self.replacePropertyWithPrefix(part, 'arg', partObj.arg); self.extendJsonFromElement(part); self.html(part, partObj.container); } } } } else { self.log('firebaseGetPart ERROR'); result = { success: false, error: 8 }; } }); } }; /* Method: firebaseIncrease Description: Functionality for firebaseIncrease. @param {any} params - Description for params @returns {any} - Result of the operation */ this.firebaseIncrease = function (params) { console.log('firebaseIncrease'); self.firebaseGet(params.path, function (result) { console.log(result); if (result.success) { if (result.data === null || result.data === undefined || typeof result.data == 'number') { var counter = Number(result.data) + 1; console.log('counter:' + counter); self.firebaseSet(params.path, counter, function (result) { if (result.success) { self.log('firebaseIncrease SUCCESS'); if (params.on && params.on.success) self.do(params.on.success, undefined, result); } else { if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); } else { if (params.on && params.on.error) self.do(params.on.error, undefined, result); } } else { if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); }; /* Method: firebaseGet Description: Functionality for firebaseGet. @param {any} path - Description for path @param {any} callback - Description for callback @returns {any} - Result of the operation */ this.firebaseGet = function (path, callback) { self.log('firebaseGet:' + path); var result = { success: false, error: 7 }; if (path) { dbRef = database.ref().child(path); } else { dbRef = database.ref(); } return dbRef.once('value').then(function (object) { if (object) { self.log('get SUCCESS'); result = { success: true, error: null, data: object.val() }; if (object.val() !== undefined) { var dbVal = object.val(); var path = object.ref.toString(); if (!dbVal) dbVal = {}; var pathArr = path.split(/\.\w+\ var dbPath = pathArr[1]; self.log('dbPath: ' + dbPath); self.localDbUpdate(dbVal, dbPath); } } else { self.log('get ERROR'); result = { success: false, error: 8 }; } callback(result); }); }; /* Method: stringToKey Description: Functionality for stringToKey. @param {any} str - Description for str @returns {any} - Result of the operation */ this.stringToKey = function (str) { return str.replace(/\./g, '%2E'); }; /* Method: keyToString Description: Functionality for keyToString. @param {any} key - Description for key @returns {any} - Result of the operation */ this.keyToString = function (key) { return key.replace(/%2E/g, '.'); }; this.firebaseKey = /* Method: getKey Description: Functionality for getKey. @param {any} path - Description for path @returns {any} - Result of the operation */ this.getKey = function (path) { var dbRef = database.ref(path); return dbRef.child(path).push().getKey(); }; /* Method: exist Description: Functionality for exist. @param {any} selector - Description for selector @returns {any} - Result of the operation */ this.exist = function (selector) { console.log('selector'); console.log(selector); console.log(Boolean(self.query(selector))); return Boolean(self.query(selector)); }; /* Method: count Description: Functionality for count. @param {any} selector - Description for selector @returns {any} - Result of the operation */ this.count = function (selector) { return self.queryAll(selector).length; }; /* Method: log Description: Functionality for log. @param {any} id - Description for id @param {any} value - Description for value @returns {any} - Result of the operation */ var log = function (id, value) { self.log(id); self.log(value); }; /* Method: classSelector Description: Functionality for classSelector. @param {any} selClass - Description for selClass @returns {any} - Result of the operation */ this.classSelector = function (selClass) { if (selClass.indexOf('.') == 0) { selClass = String(selClass).substr(1); } let classes = selClass.split(' '); selClass = classes[0]; var regex = new RegExp('[\-][\[]'); if (selClass && selClass.match(regex)) selClass = classes[1]; if (selClass && selClass.match(regex)) selClass = classes[2]; return selClass; }; /* Method: selector Description: Functionality for selector. @param {any} params - Description for params @param {any} containerParams - Description for containerParams @param {any} selectAll - Description for selectAll @returns {any} - Result of the operation */ this.selector = function (params, containerParams, selectAll) { var selector; if (params) { if (typeof params == 'string') { return params; } else if (Array.isArray(params)) { return params; } else { var selContainer; if (params.selector || params.container) selContainer = params.selector || params.container; else if (containerParams) selContainer = containerParams.selector || containerParams.container; var attr = (params.attr) ? params.attr : {}; var selId = (attr.id) ? attr.id : params.id; var selClass = (attr.class) ? attr.class : params.class; var selValue = (attr.value) ? attr.value : params.value; var selDataValue = (attr['data-value']) ? attr['data-value'] : params['data-value']; selValue = selDataValue || selValue; if (selId) selId = self.replaceProperties(selId); if (selValue) selValue = self.replaceProperties(selValue); if (selClass) selClass = self.replaceProperties(selClass); if (selClass) selClass = self.classSelector(selClass); if (selId) { selector = '#' + selId; } else if (selValue && selClass) { selector = '.' + selClass + '[data-value="' + selValue + '"]'; } else if (selValue && params.tag) { selector = params.tag + '[data-value="' + selValue + '"]'; } else if (selClass && selectAll) { selector = '.' + selClass; } else if (params.tag) { selector = params.tag; if (selContainer) { selector = selContainer + ' > ' + params.tag; if (!selectAll) { selector += ':eq(' + self.count(selector) + ')'; } } else { if (!selectAll) { selector += ':eq(' + self.count(selector) + ')'; } } } else { selector = selContainer; }; } return selector; } }; /* Method: stringify Description: Functionality for stringify. @param {any} obj - Description for obj @returns {any} - Result of the operation */ this.stringify = function (obj) { if (typeof obj == 'object') try { return JSON.stringify(obj); } catch (error) { return obj; } else return obj; }; /* Method: parse Description: Functionality for parse. @param {any} str - Description for str @returns {any} - Result of the operation */ this.parse = function (str) { if (typeof str == 'string') try { return JSON.parse(str); } catch (error) { return str; } else return str; }; self.setupId = 0; /* Method: replacePropertyWithPrefix Description: Functionality for replacePropertyWithPrefix. @param {any} params - Description for params @param {any} prefix - Description for prefix @param {any} args - Description for args @returns {any} - Result of the operation */ this.replacePropertyWithPrefix = function (params, prefix, args) { var paramsString; if (typeof params == 'object') paramsString = self.stringify(params); else paramsString = String(params); if (paramsString && paramsString.indexOf('{' + prefix) >= 0) { paramsString = paramsString.replace(new RegExp('"{' + prefix + '[:\\s]?([\\w\\d\\s\\.\\|]*)}"', 'g'), function (match, path) { if (path) { let value = self.replaceUndefined({ match: match, path: path, root: args, removeUndefined: true }); if (value === undefined) { return '""'; } else if (typeof value == 'object') return JSON.stringify(value); else if (typeof value == 'string') return '"' + value + '"'; else return value; } else { if (typeof args == 'object') return JSON.stringify(args); else if (typeof args == 'string') return '"' + args + '"'; else return args; } }); paramsString = paramsString.replace(new RegExp('{' + prefix + '[:\\s]?([\\w\\d\\s\\.]*)}', 'g'), function (match, path) { if (path) { let value = self.replaceUndefined({ match: match, path: path, root: args, removeUndefined: true }); if (value === undefined) return ''; else if (typeof value == 'object') return JSON.stringify(value); else return value; } else { if (typeof args == 'object') return JSON.stringify(args); else return args; } }); if (self.isJsonString(paramsString)) { var paramsObj = self.parse(paramsString); return paramsObj; } else { return paramsString; } } else { return params; } }; /* Method: replaceResult Description: Functionality for replaceResult. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.replaceResult = function (params, args) { var paramOn, paramSuccess, paramError; if (typeof params == 'object') { var paramsObj = self.cloneObject(params); if (paramsObj && paramsObj.on) { paramOn = self.cloneObject(paramsObj.on); delete paramsObj.on; } if (paramsObj && paramsObj.success) { paramSuccess = self.cloneObject(paramsObj.success); delete paramsObj.success; } params = self.stringify(params); } if (typeof args !== 'string') { params = self.replaceAll(params, '"{result}"', JSON.stringify(args)); } else { params = self.replaceAll(params, '{result}', args); } if (self.isJson(params)) { var paramsObj = self.parse(params); if (paramOn) paramsObj.on = paramOn; if (paramSuccess) paramsObj.success = paramSuccess; if (paramError) paramsObj.error = paramError; return paramsObj; } else { return params; } }; /* Method: langText Description: Functionality for langText. @param {any} textId - Description for textId @returns {any} - Result of the operation */ this.langText = function (textId) { if (textId) { var textValue = textId; if (typeof textId == 'string') { if (self.json.texts[textId]) { textValue = self.json.texts[textId]; if (typeof textValue == 'object') textValue = textValue[self.json.setup.language] || textValue['en'] || textValue[Object.keys[0]]; } else textValue = textId; } else if (typeof textId == 'object') { textValue = textId[self.json.setup.language] || textId['en'] || textId[Object.keys[0]]; } return textValue; } else { return textId; } }; /* Method: lang Description: Functionality for lang. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.lang = function (params, args) { if (args) { var value = self.replaceProperties(params, args); self.json.setup.language = value; self.log('lang'); self.log(value); document.querySelectorAll('[data-text]').forEach(function (element, index) { var dataParams = self.dataStorage.get(element, 'params'); var selector = self.dataStorage.get(element, 'selector'); self.html(dataParams, { selector: selector }); }); } else { return self.json.setup.language; } }; /* Method: isClipboardWritingAllowed Description: Functionality for isClipboardWritingAllowed. @param {any} - No parameters @returns {any} - Result of the operation */ var isClipboardWritingAllowed = function () { return new Promise(function (resolve, reject) { try { navigator.permissions.query({ name: "clipboard-write" }).then(function (status) { self.log(status); resolve((status.state == "granted")); }); } catch (error) { reject(error); } }); }; /* Method: codeSearch Description: Functionality for codeSearch. @param {any} params - Description for params @returns {any} - Result of the operation */ this.codeSearch = function (params) { let selector = params.selector || params.container; if (selector && params.word) { var element = self.query(selector); var editor = ace.edit(element); var range = editor.find(params.word, { wrap: true, caseSensitive: true, wholeWord: true, regExp: false, preventScroll: false }); editor.session.selection.clearSelection(); editor.setOption("highlightActiveLine", true); } }; /* Method: ace Description: Functionality for ace. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @returns {any} - Result of the operation */ this.ace = function (params, selectorParams) { var selector = params.selector || params.container; var container = selector || self.selector(selectorParams); var value = params.value; if (params.blocks && self.json.blocks) if (self.json.blocks[params.blocks]) value = self.json.blocks[params.blocks]; else self.log('"code" method can\'t find in "blocks" the element ' + params.blocks); if (params.module) { let moduleName = self.replaceProperties(params.module); if (moduleName && self.modules[moduleName] !== undefined) { value = self.modules[moduleName]; } else self.log('"code" method can\'t find the file ' + params.file); } if (params.var) if (self.json.var) value = self.var(params.var); else self.log('"code" method can\'t find the variable ' + params.blocks); var element = self.query(container); if (element) { var editor = ace.edit(element); if (!params.do || (params.do == 'set')) { if (params.theme) editor.setTheme(params.theme); var editorMode = params.mode || "ace/mode/json"; editor.getSession().setMode(editorMode); if (params.options) editor.setOptions(params.options); var editorStyle = self.extend({ }, params.style); self.css({ style: editorStyle }, { selector: container }); var codeString; if (typeof value == 'string') if (editorMode == "ace/mode/json") codeString = JSON.stringify(JSON.parse(value), null, '\t'); else codeString = value; else { if (editorMode == "ace/mode/json") codeString = JSON.stringify(value, null, '\t'); else { var functionObj = self.docElement(value.function); var functionParams = value.params; codeString = functionObj(functionParams); } } if (codeString) { var codeRows = codeString.split(/\r\n|\r|\n/).length; element.style.height = Number(21 * codeRows) + 'px'; editor.setValue(codeString, -1); self.uiUpdate(); } if (params.on) { var containerId = self.attribute(element, 'id'); self.codeChangeFunctions[containerId] = params.on; if (params.on.change) { editor.on('change', function (event, obj) { if (self.isJson(obj.getValue())) { var code = JSON.parse(obj.getValue()); var action = self.codeChangeFunctions[obj.container.id].change; var methods = self.replaceResult(action, code); self.do(methods); } else { } }); } } } else if (params.do == 'get') { return JSON.parse(editor.getValue()); } else if (params.do == 'update') { self.uiUpdate(); } else if (params.do == 'search') { if (params.word) { var range = editor.find(params.word, { wrap: true, caseSensitive: true, wholeWord: true, regExp: false, preventScroll: false }); editor.session.selection.clearSelection(); editor.setOption("highlightActiveLine", true); } } else if (params.do == 'find') { editor.execCommand('find'); } else if (params.do == 'copy') { editor.selectAll(); let copyText = editor.getCopyText(); isClipboardWritingAllowed().then(function (allowed) { if (allowed) { navigator.clipboard.writeText(copyText).then(function () { editor.getSession().selection.clearSelection(); }); } }).catch(function (err) { self.log("Cannot copy to clipboard", err); }); } else { self.log('"code" function requires value param'); } } else { self.log('"code" method can\'t select the container'); self.log('container'); self.log(container); self.log('element'); self.log(element); } }; this.codeChangeFunctions = {}; this.editorChangeFunctions = {}; this.quillElements = {}; /* Method: text Description: Functionality for text. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.text = function (params, selectorParams, args) { var textKey; var textCase; var textArgs; var textLang; var langId; var selector, element; if (typeof params == 'object') { if (selectorParams && selectorParams.isConnected) { element = selectorParams; selector = self.elementToSelector(element); } else { selector = self.selector(self.extend({}, params, selectorParams)); element = self.query(selector); } textCase = params.case; textArgs = params.args; if (typeof params == 'object') { textKey = params.key || params.string || params; } else { textKey = params; } } else if (typeof params == 'string') { textKey = params; if (selectorParams) { if (selectorParams.isConnected) { element = selectorParams; selector = self.dataStorage.get(element, 'selector'); } else { selector = self.selector(selectorParams); element = self.query(selector); } } else { } } if (typeof textKey == 'string') { textKey = self.replaceProperties(textKey, textArgs); } if (params && params.lang) { textLang = self.langText(params.lang); textLang = self.replaceProperties(textLang, textArgs); if (textCase) textLang = self.textCase(textLang, textCase); if (element) { element.textContent = textLang; self.attribute(element, 'data-text', true); self.dataStorage.set(element, 'params', params); } } else { if (textKey) { if (textKey.lang) textLang = self.langText(textKey.lang); else textLang = textKey; textLang = self.replaceProperties(textLang, textArgs); if (textCase) textLang = self.textCase(textLang, textCase); if (element) { if (self.json.texts[textKey]) { self.attribute(element, 'data-text', true); self.dataStorage.set(element, 'params', params); } if (params.style) self.css({ style: params.style }, { selector: selector }); element.textContent = textLang; } else { return textLang; } } else { return params; } } }; /* Method: caseUp Description: Functionality for caseUp. @param {any} string - Description for string @returns {any} - Result of the operation */ var caseUp = function (string) { return string.toUpperCase(); }; /* Method: caseDown Description: Functionality for caseDown. @param {any} string - Description for string @returns {any} - Result of the operation */ var caseDown = function (string) { return string.toLowerCase(); }; /* Method: capitalize Description: Functionality for capitalize. @param {any} string - Description for string @returns {any} - Result of the operation */ var capitalize = function (string) { return self.capitalize(string); }; /* Method: textCase Description: Functionality for textCase. @param {any} textParam - Description for textParam @param {any} caseParam - Description for caseParam @returns {any} - Result of the operation */ this.textCase = function (textParam, caseParam) { if (textParam) { var text = textParam; switch (caseParam) { case 'up': text = text.toUpperCase(); break; case 'down': text = text.toLowerCase(); break; case 'capitalize': text = self.capitalize(text); break; } return text; } else { self.log('textParam undefined in textCase'); } }; /* Method: replaceUndefined Description: Functionality for replaceUndefined. @param {any} params - Description for params @returns {any} - Result of the operation */ this.replaceUndefined = function (params) { let value, defaultValue; if (typeof params.path !== undefined) { if (params.path.indexOf('|') > 0) [params.path, defaultValue] = params.path.split('|'); value = self.element({ path: params.path, root: params.root }); } if (value == undefined || value == null) { if (typeof defaultValue !== undefined) value = defaultValue; else { if (params.removeUndefined) { value = ''; } else { value = params.match; self.log(value + ' not found', 'yellow'); } } } else { } return value; }; /* Method: replaceProperties Description: Functionality for replaceProperties. @param {any} params - Description for params @param {any} args - Description for args @param {any} removeUndefined - Description for removeUndefined @returns {any} - Result of the operation */ this.replaceProperties = function (params, args, removeUndefined) { var paramsString; var paramOn, paramDo, paramSuccess, paramError, paramEvents, paramConfirm; if (typeof params == 'string') { paramsString = params; } else { var paramsObj = self.cloneObject(params); if (paramsObj) { if (paramsObj.on) { paramOn = paramsObj.on; delete paramsObj.on; } if (paramsObj.success) { paramSuccess = paramsObj.success; delete paramsObj.success; } if (paramsObj.error) { paramError = paramsObj.error; delete paramsObj.error; } if (paramsObj.events) { paramEvents = paramsObj.events; delete paramsObj.events; } if (paramsObj.confirm) { paramConfirm = paramsObj.confirm; delete paramsObj.confirm; } if (paramsObj.do) { paramDo = paramsObj.do; delete paramsObj.do; } } paramsString = JSON.stringify(paramsObj); } if (paramsString && paramsString.indexOf('{') >= 0) { paramsString = paramsString.replace(/\"\{([\w\s\.]+)\}\"/g, function (match, p1, offset, string) { var value; if (p1) { //self.log('p1:' + p1); //value = self.element({path: p1}); // || match; value = self.replaceUndefined({ match: '{' + match + '}', path: p1, removeUndefined: removeUndefined }); if (value) { if (value.isConnected) return self.elementToSelector(value); // DOM element to CSS selector if (typeof value !== 'string') return self.stringify(value); // object or array to string (TO DO: check numbers) else { //console.warn('we are here'); return '"' + value + '"'; } } else return '""'; } else { return '""'; } }); paramsString = paramsString.replace(/\{(\w+\:)?([\w\s\->|\/=\.:#&;,\[\]\']+)\}/g, function (match, p1, p2, offset, string) { /* Firebase references may contain any unicode characters except: . (period) $ (dollar sign) [ (left square bracket) ] (right square bracket) # (hash or pound sign) / (forward slash) */ /* self.log("paramstring"); self.log(match, p1, p2); */ // self.log(match, p1, p2); var value; if (p1) { if (p1.endsWith(':')) { p1 = p1.slice(0, -1); // remove the final ":" // check if is a /* Method: name Description: Functionality for name. @param {any} in this.json.functions - Description for in this.json.functions @returns {any} - Result of the operation */ function name (in this.json.functions) if (self.functions[p1]) { //value = self.functions[p1](JSON.parse(p2)); let funcArgs = p2.split('|'); /* console.warn('p2'); console.warn(p2); console.warn('funcArgs'); console.warn(funcArgs); */ // if Number(funcArgs[i]) == funcArgs[i] -> funcArgs[i] = Number(funcArgs[i]); value = self.function({ name: p1, arguments: [funcArgs] }); } else { switch (p1) { /* case 'hasClass': var element = document.querySelector(p2); if (p3) value = self.hasClass(el,p3); else value = false; el:selector.class (esiste l'elemento selector.class o l'elemento selector ha la classe class) break; */ // 'isVisible', 'isHidden', 'isDisplay', 'inViewport', 'outViewport', 'notClass', 'hasClass' // hasClass da aggiungere come funzione css // html markups // 'b:string' 'i:string' 'u:string' 'a:STRING|URL' /* case 'i': case 'b': case 'u': case 'strong': case 'em': case 'mark': case 'del': case 'ins': case 'sub': case 'sup': value = '<'+p1+'>'+p2+''; break; case 'a': // example: "{a:text|href:....|target:_blank}" let props = p2.split('|'); // or indexOf(':') prima occorrenza let string = props.shift(); var propsString = ''; for (var prop of props) { //let propArr = prop.split(':'), propName = propArr[0], propValue = propArr[1]; propsString += ' ' + prop; } if (propsString == '') propsString = ' href="'+string+'"'; value = ''+string+''; // https://stackoverflow.com/questions/1547899/which-characters-make-a-url-invalid // https://www.w3schools.com/tags/tag_a.asp break; */ // DOM properties case 'visible': var element = document.querySelector(p2); // self.query(p2); value = (element && self.isVisible(element)); //value = ($(p2).is(':visible')); break; case 'number': value = Number(p2); break; case 'string': value = String(p2); break; case 'js': // deprecated (too much special characters like {}) try { value = eval(p2); } catch (error) { value = ''; self.log('javascript error on ' + p2); self.log(error); } break; /* case 'item': if (fieldsObj) { //self.log('fieldsObj['+p2+']:'+fieldsObj[p2]); value = fieldsObj[p2] || ''; //|| p2+'=NULL'; } else { //self.log('p2:'+p2); //self.log('fieldsObj == undefined'); value = '{'+p1+':'+p2+'}'; } break; */ /* case 'item': case 'items': value = self.docElement('self.json.items.'+p2); break; */ /* case 'frame': var element = self.query(p2); element.contentWindow break; */ /* case 'field': if (fieldsObj) { //self.log('fieldsObj['+p2+']:'+fieldsObj[p2]); value = fieldsObj[p2] || ''; // || p2+'=NULL'; } else { //self.log('p2:'+p2); //self.log('fieldsObj == undefined'); value = ''; } break; */ /* case 'setup': value = self.docElement('self.json.setup.'+p2) || match; break; */ /* case 'setup': if (args) { self.partSetup = args; value = self.docElement('self.partSetup.'+p2); delete self)Setup; } else { value = ''; } break; */ case 'wp': case 'wordpress': // TO DO: should get/set data with jsonic.get/setWordpressData // setWordpressData can be done automatically in the init value = self.docElement('self.json.setup.wordpress.' + p2) ?? match; //alert(value); //if (value.indexOf('"') >= 0) // value = self.replaceAll(value, '"', '\\"'); // the first should replace only " and not \" but it doesn't works break; case 'plugins': value = self.json.resources.pluginsFunctions[p2]; if (value && !Array.isArray(value)) value = [value]; else value = []; break; case 'database': case 'db': value = self.docElement('self.json.var.db.' + self.replaceProperties(p2, args)); break; case 'media': if (self.json.setup && self.json.data.media) value = self.docElement('self.json.data.media.' + p2) || match; else value = match; break; case 'color': if (self.json.data && self.json.data.colors) value = self.docElement('self.json.data.colors.' + p2) || match; else value = match; break; case 'class': if (self.json.data && self.json.data.class) value = self.docElement('self.json.data.class.' + p2) || match; else value = match; break; case 'text': value = self.langText(p2); break; case 'param': value = self.params[p2] || ''; break; case 'height': var element = document.querySelector(p2); if (element) value = element.offsetHeight + 'px'; else value = '0px'; break; case 'offsetWidth': var element = document.querySelector(p2); if (element) value = element.offsetWidth; else value = '0'; break; case 'width': var element = document.querySelector(p2); if (element) value = element.offsetWidth + 'px'; else value = '0px'; break; case 'local': value = self.methods.local.get(p2); break; case 'ace': var element = document.querySelector(p2); if (element) { var editor = ace.edit(element); value = JSON.parse(editor.getValue()); } break; case 'shuffle': value = self.element({ path: p2 }); value = self.methods.shuffle(value); break; case 'select': case 'input': case 'value': var element = document.querySelector(p2); value = (element) ? String(element.value || '') : ''; break; case 'user': if (p2 == 'in') { value = self.userIn(); } else if (p2 == 'out') value = self.userOut(); else value = self.user(p2) || match; break; case 'length': var varObj = self.element({ path: p2 }); if (varObj) if (typeof varObj == 'object') value = Object.keys(varObj).length; else value = varObj.length; else self.log('' + p2 + ' is undefined'); break; case 'Date': case 'time': if (p2 == 'timeZone') value = new Intl.DateTimeFormat().resolvedOptions().timeZone; else if (p2 == 'weekday') value = self.weekday(); else if (p2 == 'stamp') value = self.getTimestamp(); else if (p2 == 'timestamp') value = self.getTimestamp(); else if (p2 == 'getTimestamp') value = self.getTimestamp(); else if (p2 == 'getDay') value = new Date().getDay(); else if (p2 == 'getDate') value = new Date().getDate(); else if (p2 == 'getMonth') value = new Date().getMonth(); else if (p2 == 'getFullYear') value = new Date().getFullYear(); else if (p2 == 'getTime') value = new Date().getTime(); else if (p2 == 'getSeconds') value = new Date().getSeconds(); else if (p2 == 'getMinutes') value = new Date().getMinutes(); else if (p2 == 'getHours') value = new Date().getHours(); else value = p2 + '=NULL'; break; case 'now': break; case 'month': var month = (p2 == 'today' || p2 == undefined) ? new Date().getMonth() : Number(p2); value = self.month(month); break; case 'weekday': var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2); value = self.calendar({ index: Number(day), unit: 'weekday', format: 'long' }); break; case 'weekdayNarrow': var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2); value = self.calendar({ index: Number(day), unit: 'weekday', format: 'narrow' }); break; case 'weekdayShort': var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2); value = self.calendar({ index: Number(day), unit: 'weekday', format: 'short' }); break; case 'moment': var timeFormat = (p2) ? p2 : ''; value = moment().format(timeFormat); break; case 'dayjs': var timeFormat = (p2) ? p2 : ''; value = dayjs().format(timeFormat); break; case 'Math': value = self.Math(p2); break; case 'action': case 'do': self.log('do'); self.log('p2'); self.log(p2); value = self.do(p2); break; case 'method': var method = self.element({ path: p2, root: self.methods }); if (method) { value = method(args); } else { value = match; } break; case 'function': var func = self.element({ path: p2, root: self.functions }); if (func) { value = func(args); } else { value = match; } break; case 'on': if (args) { self.onResult = args; value = self.docElement('self.onResult.' + p2); delete self.onResult; } else { value = match; } break; case 'ajax': if (args) { self.ajaxResult = args; value = self.docElement('self.ajaxResult.' + p2); delete self.ajaxResult; } else { value = match; } break; case 'if': p2 = self.replaceProperties(p2); var ifArr = p2.split('|'); if (self.js(ifArr[0])) value = true; if (ifArr.length > 1 && value) value = ifArr[1]; if (ifArr.length > 2 && !value) value = ifArr[2]; break; case 'random': value = String(Math.floor(Number(p2) * Math.random())); break; case 'getKey': case 'firebaseKey': value = self.firebaseKey(p2); break; case 'window': value = self.docElement(p2) || match; break; default: break; } } } } else if (p2) { let keyPrefix = p2.split(' ')[0]; if (self.functions[keyPrefix]) { value = self.function({ name: keyPrefix }); value = self.element({ path: p2, root: value }); console.log(keyPrefix); console.log(value); } else value = self.replaceUndefined({ match: match, path: p2, removeUndefined: removeUndefined }); } if (value && value.isConnected) value = self.elementToSelector(value); if (!value) { if (removeUndefined) value = ''; else { if (typeof value == undefined) self.log(match + ' is undefined', 'yellow'); } } if (typeof value !== 'string') value = self.stringify(value); return value; }); if (paramsString.startsWith('{js:') && paramsString.endsWith('}')) paramsString = self.js(paramsString.substr(4, paramsString.length - 1 - 4)); if (self.isJsonString(paramsString)) { var paramsObj = self.parse(paramsString); if (paramOn) paramsObj.on = paramOn; if (paramDo) paramsObj.do = paramDo; if (paramConfirm) paramsObj.confirm = paramConfirm; if (paramSuccess) paramsObj.success = paramSuccess; if (paramError) paramsObj.success = paramError; if (paramEvents) paramsObj.events = paramEvents; return paramsObj; } else { return paramsString; } } else { if (paramOn) params.on = paramOn; if (paramDo) params.do = paramDo; if (paramConfirm) params.confirm = paramConfirm; if (paramSuccess) params.success = paramSuccess; if (paramError) params.error = paramError; if (paramEvents) params.events = paramEvents; return params; } }; /* Method: isJsonString Description: Functionality for isJsonString. @param {any} str - Description for str @returns {any} - Result of the operation */ this.isJsonString = function (str) { try { JSON.parse(str); } catch (e) { return false; } return true; }; /* Method: isJson Description: Functionality for isJson. @param {any} item - Description for item @returns {any} - Result of the operation */ this.isJson = function (item) { item = typeof item !== "string" ? JSON.stringify(item) : item; try { item = JSON.parse(item); } catch (e) { return false; } if (typeof item === "object" && item !== null) { return true; } return false; }; /* Method: replaceStringInObject Description: Functionality for replaceStringInObject. @param {any} obj - Description for obj @param {any} stringToReplace - Description for stringToReplace @param {any} value - Description for value @returns {any} - Result of the operation */ this.replaceStringInObject = function (obj, stringToReplace, value) { var paramsString, valueString; if (typeof obj == 'string') paramsString = obj; else paramsString = JSON.stringify(obj); if (typeof value == 'string') valueString = value; else valueString = JSON.stringify(value); paramsString = self.replaceAll(paramsString, stringToReplace, valueString); if (self.isJson(paramsString)) return self.parse(paramsString); else return paramsString; }; /* Method: replaceItems Description: Functionality for replaceItems. @param {any} params - Description for params @param {any} item - Description for item @param {any} name - Description for name @returns {any} - Result of the operation */ this.replaceItems = function (params, item, name) { var paramsString; var specialPattern; var itemName = name || 'item'; if (typeof params == 'string') paramsString = params; else paramsString = JSON.stringify(params); if (typeof item == 'object' || Array.isArray(item)) { paramsString = self.replaceAll(paramsString, '"{' + itemName + '}"', JSON.stringify(item)); for (let key in item) { if (typeof item[key] == 'object') paramsString = self.replaceAll(paramsString, '"{' + itemName + ':' + key + '}"', JSON.stringify(item[key])); else paramsString = self.replaceAll(paramsString, '{' + itemName + ':' + key + '}', item[key]); } } else { paramsString = self.replaceAll(paramsString, '{' + itemName + '}', String(item)); } paramsString = paramsString.replace(/(\"\s*)\{item\:(\w+)\}(\s*\")/g, function (match, p1, p2, p3, offset, string) { var value; if (item) value = item[p2] || ''; else value = ''; if (typeof value == 'object') value = self.stringify(value); else if (Array.isArray(value)) value = value; else value = p1 + value + p3; // p1 and p3 are the " matched by (\"\s*) and (\s*\") return value; }); /* specialPattern = new RegExp('\{'+itemName+'\:([^\}]*)\}', 'g'); paramsString = paramsString.replace(specialPattern, function(match, p2, offset, string) { //paramsString = paramsString.replace(/\{item\:([^\}]*)\}/g, function(match, p2, offset, string) { var value; if (item) value = item[p2] || ''; else value = ''; if (typeof value == 'object') value = self.stringify(value); return value; }); */ if (self.isJson(paramsString)) return self.parse(paramsString); else return paramsString; //if (typeof params == 'object') return self.parse(paramsString); else return paramsString; }; /* /* Method: replaceItems Description: Functionality for replaceItems. @param {any} objWithNames - Description for objWithNames @param {any} name - Description for name @returns {any} - Result of the operation */ this.replaceItems = function (objWithNames, name) { //self.log('replaceItems'); var paramString = self.stringify(objWithNames); //self.log(paramString); if (!name) name = ''; paramString = self.replaceAll(paramString, '{item}', name); //self.log(paramString); //paramString = self.replaceTags({text:paramString}); //self.log(paramString); //paramString = self.replaceProperties(paramString); //self.log(paramString); if (typeof objWithNames == 'object') return self.parse(paramString); else return paramString; } */ /* Method: color Description: Functionality for color. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.color = function (params, args) { var paramsReplaced = self.replaceProperties(params, args); //if (self.json.styles.colors) // return self.json.styles.colors[paramsReplaced]; if (self.json.data && self.json.data.colors) return self.json.data.colors[paramsReplaced]; }; // ---------------------------- // ELEMENT METHODS // ---------------------------- /* Method: empty Description: Functionality for empty. @param {any} params - Description for params @returns {any} - Result of the operation */ this.empty = function (params) { /* self.log('empty'); self.log(params); */ var el = self.query(params); if (el) { while (el.firstChild) el.removeChild(el.firstChild); } else { self.log('"empty" is unable to select element'); self.log(params); } }; /* Method: isArray Description: Functionality for isArray. @param {any} value - Description for value @returns {any} - Result of the operation */ this.isArray = function (value) { return Array.isArray(self.js(value)); }; /* Method: isVisible Description: Functionality for isVisible. @param {any} el - Description for el @returns {any} - Result of the operation */ this.isVisible = function (el) { return (el.style.display !== 'none' && !self.hasClass(el, 'd-none')); }; /* Method: isHidden Description: Functionality for isHidden. @param {any} el - Description for el @returns {any} - Result of the operation */ this.isHidden = function (el) { return (el.offsetParent === null); }; /* Method: isDisplay Description: Functionality for isDisplay. @param {any} el - Description for el @param {any} displayValue - Description for displayValue @returns {any} - Result of the operation */ this.isDisplay = function (el, displayValue) { //var style = window.getComputedStyle(el); /* self.log('isDisplay'); self.log('el.style'); self.log(el.style); self.log('displayValue'); self.log(displayValue); */ return (el.style.display === displayValue); }; /* Method: inViewport Description: Functionality for inViewport. @param {any} el - Description for el @returns {any} - Result of the operation */ this.inViewport = function (el) { const rect = el.getBoundingClientRect(); return ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) && rect.right <= (window.innerWidth || document.documentElement.clientWidth) ); }; /* Method: outViewport Description: Functionality for outViewport. @param {any} el - Description for el @returns {any} - Result of the operation */ this.outViewport = function (el) { return !self.outViewport(el); }; /* Method: notClass Description: Functionality for notClass. @param {any} el - Description for el @param {any} className - Description for className @returns {any} - Result of the operation */ this.notClass = function (el, className) { return !self.hasClass(el, className); }; /* Method: hasClass Description: Functionality for hasClass. @param {any} el - Description for el @param {any} className - Description for className @returns {any} - Result of the operation */ this.hasClass = function (el, className) { if (el.classList) return el.classList.contains(className); else return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)')); }; /* Method: addClass Description: Functionality for addClass. @param {any} el - Description for el @param {any} className - Description for className @returns {any} - Result of the operation */ this.addClass = function (el, className) { if (el.classList) el.classList.add(className); else if (!self.hasClass(el, className)) el.className += " " + className; }; /* Method: removeClass Description: Functionality for removeClass. @param {any} el - Description for el @param {any} className - Description for className @returns {any} - Result of the operation */ this.removeClass = function (el, className) { if (el.classList) el.classList.remove(className); else if (self.hasClass(el, className)) { var reg = new RegExp('(\\s|^)' + className + '(\\s|$)'); el.className = el.className.replace(reg, ' '); } }; /* Method: toggleClass Description: Functionality for toggleClass. @param {any} el - Description for el @param {any} className - Description for className @returns {any} - Result of the operation */ this.toggleClass = function (el, className) { if (self.hasClass(el, className)) self.removeClass(el, className); else self.addClass(el, className); }; this.choose = /* Method: select Description: Functionality for select. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.select = function (params, selectorParams, args) { // "choose OR options / "select" is deprecated because select is an html tag if (Array.isArray(params)) { for (var obj of params) self.choose(obj, args); } else { var selId, selClass, selValue; selValue = params['data-value']; if (params.id) selId = self.replaceProperties(params.id, args); if (params.class) selClass = self.replaceProperties(params.class, args); if (selValue) selValue = self.replaceProperties(selValue, args); if (params.selection) { var selectionClass = params.selection; var selector = self.selector({ class: selClass }); var elements = document.querySelectorAll('.' + selClass); elements.forEach(function (element, index) { self.removeClass(element, selectionClass); }); if (selId || selValue) { var selector = self.selector({ id: selId, class: selClass, 'data-value': selValue }); var elements = document.querySelectorAll(selector); elements.forEach(function (element, index) { self.addClass(element, selectionClass); }); } } else { self.hide({ "selector": { "class": selClass } }); self.show({ "selector": { "id": selId, "class": selClass, "data-value": selValue } }); } self.uiUpdate(); } }; /* Method: toggle Description: Functionality for toggle. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.toggle = function (params, selectorParams, args) { self.log('toggle'); self.log(params); if (Array.isArray(params)) { for (var index in params) self.toggle(params[index], selectorParams, args); } else { var selector; if (typeof params == 'string') selector = params; else selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); var element = self.query(selector); if (self.isVisible(element)) self.out(params, selectorParams, args); else self.in(params, selectorParams, args); } }; /* Method: in Description: Functionality for in. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.in = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.in(params[index], selectorParams, args); } else { var selector; if (typeof params == 'string') selector = params; else selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); var transition = params.transition || 'fadeIn'; var duration = params.duration || '500ms'; var start = [{ "show": { "selector": selector, } }]; var end = [ { "do": self.resizeEvent } ]; if (params.on && params.on.start) start.push(params.on.start); if (params.on && params.on.end) end.push(params.on.end); var animation = { "animate": { "selector": selector, "transition": transition, "duration": duration, "on": { "start": start, "end": end } } }; self.do(animation, undefined, args); } }; /* Method: out Description: Functionality for out. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.out = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.out(params[index], selectorParams); } else { var selector; if (typeof params == 'string') selector = params; else selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); var transition = params.transition || 'fadeOut'; var duration = params.duration || '500ms'; var start = []; var end = [ { "hide": { "selector": selector, } }, { "do": self.resizeEvent } ]; if (params.on && params.on.start) start.push(params.on.start); if (params.on && params.on.end) end.push(params.on.end); var animation = { "animate": { "selector": selector, "transition": transition, "duration": duration, "on": { "start": start, "end": end } } }; self.do(animation, undefined, args); } }; /* Method: show Description: Functionality for show. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.show = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.show(params[index], selectorParams); } else { var selector; if (typeof params == 'string') selector = params; else selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); var elements = self.queryAll(selector); elements.forEach(function (element, index) { self.removeClass(element, 'hidden'); self.removeClass(element, 'opacity-0'); self.removeClass(element, 'invisible'); self.removeClass(element, 'd-none'); element.style.visibility = 'visible'; }); } }; /* Method: hide Description: Functionality for hide. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.hide = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.hide(params[index], selectorParams); } else { var selector; if (typeof params == 'string') selector = params; else selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); var elements = self.queryAll(selector); elements.forEach(function (element, index) { self.addClass(element, 'hidden'); }); } }; /* Method: matchMedia Description: Functionality for matchMedia. @param {any} mediaAction - Description for mediaAction @param {any} mediaEvent - Description for mediaEvent @returns {any} - Result of the operation */ this.matchMedia = function (mediaAction, mediaEvent) { const mediaQuery = window.matchMedia(mediaEvent); mediaQuery.addListener(function (e) { if (e.matches) { self.do(mediaAction); } }); }; /* Method: addFirebaseTag Description: Functionality for addFirebaseTag. @param {any} params - Description for params @returns {any} - Result of the operation */ this.addFirebaseTag = function (params) { var dataObj = params.database; if (dataObj) { dataObj = self.replaceProperties(dataObj); var path, success; if (typeof dataObj == 'string') { path = dataObj; } else { path = dataObj.path; success = dataObj.success; } if (path) { var selector = self.selector(params, undefined, false); var elements = self.queryAll(selector); if (elements) elements.forEach(function (element, index) { var listenerObj = { path: path }; var elementsDataPath = document.querySelectorAll('[data-firebase="' + path + '"]'); if (elementsDataPath.length == 0) { listenerObj.action = [ ]; if (dataObj.success) listenerObj.action.push(dataObj.success); } if (element) { element.setAttribute('data-firebase', path); self.dataStorage.set(element, 'data-template', params); } else { self.log('!element selector:' + selector + ' / firebase path:' + path); self.log('params'); self.log(params); } if (dataObj.orderByChild !== undefined) listenerObj.orderByChild = dataObj.orderByChild; if (dataObj.equalTo !== undefined) listenerObj.equalTo = dataObj.equalTo; self.firebaseAddListener(listenerObj); }); } else { self.log('data object requires path parameter'); self.log(params); } } }; /* Method: dbObject Description: Functionality for dbObject. @param {any} path - Description for path @returns {any} - Result of the operation */ this.dbObject = function (path) { var pathString = 'self.json.var.db.' + self.replaceAll(path, '/', '.'); return self.docElement(pathString); }; /* Method: only Description: Functionality for only. @param {any} permissions - Description for permissions @param {any} user - Description for user @returns {any} - Result of the operation */ this.only = function (permissions, user) { if (user) { return (user == self.user('uid')); } else { var permission = (permissions) ? String(permissions).split(',') : false; return (!permission || (permissions.indexOf(self.userRole()) >= 0)); } }; /* Method: extendJsonFromElement Description: Functionality for extendJsonFromElement. @param {any} p - Description for p @returns {any} - Result of the operation */ this.extendJsonFromElement = function (p) { var params = self.cloneObject(p); if (params.resources) self.extendJson(self.json, { "resources": params.resources }); if (params.plugins) self.extendJson(self.json, { "plugins": params.plugins }); if (params.parts) self.extendJson(self.json, { "parts": params.parts }); if (params.blocks) self.extendJson(self.json, { "blocks": params.parts }); if (params.shortcuts) self.extendJson(self.json, { "shortcuts": params.shortcuts }); if (params.css) self.extendJson(self.json, { "css": params.css }); if (params.setup) self.extendJson(self.json, { "setup": params.setup }); if (params.data) self.extendJson(self.json, { "data": params.data }); if (params.var) self.extendJson(self.json, { "var": params.var }); if (params.texts) self.extendJson(self.json, { "texts": params.texts }); }; /* Method: query Description: Functionality for query. @param {any} selector - Description for selector @param {any} element - Description for element @returns {any} - Result of the operation */ this.query = function (selector, element) { if (selector) { if (typeof selector == 'object') selector = self.selector(selector, undefined, true); var routes = selector.split(/[ >]+/); if (!element) element = document; for (var index in routes) { if (element && element[0]) element = element[0]; if (element && element.isConnected) { var route = routes[index]; var routeParts = route.match(/(.*):eq\((\d*)\)/); if (routeParts) { var routeElement = String(routeParts[1]); var routeIndex = Number(routeParts[2]); if (routeElement.startsWith('.')) routeElement = '.' + self.classSelector(routeElement); element = element.querySelectorAll(routeElement)[routeIndex]; } else { if (route.startsWith('.')) route = '.' + self.classSelector(route); element = element.querySelectorAll(route)[0]; } } else { element = undefined; } } if (!element) self.log('can\'t find the element "' + selector + '" ("query" function)'); return element; } else { } }; /* Method: queryAll Description: Functionality for queryAll. @param {any} selector - Description for selector @param {any} element - Description for element @returns {any} - Result of the operation */ this.queryAll = function (selector, element) { if (selector) { if (Array.isArray(selector)) { let elements = self.queryAll(selector[0]); selector.shift(); for (let str of selector) { elements = Array.prototype.slice.call(elements).concat(Array.prototype.slice.call(self.queryAll(str))); } return elements; } else { var routes = selector.split(/[ >]+/); if (!element) element = document; for (var index in routes) { if (element && element[0]) element = element[0]; if (element && element.isConnected) { var route = routes[index]; var routeParts = route.match(/([^:]*):eq\((\d*)\)/); if (routeParts) { var routeElement = String(routeParts[1]); var routeIndex = Number(routeParts[2]); if (routeElement.startsWith('.')) routeElement = '.' + self.classSelector(routeElement); element = element.querySelectorAll(routeElement)[routeIndex]; if (index == (routes.length - 1) && element) { element = [element]; } } else { if (route.startsWith('.')) routeElement = '.' + self.classSelector(route); element = element.querySelectorAll(route); } } else { element = []; } } if (!element) self.log('No element selected by ' + selector); return element; } } else { console.log('%cDOM queryAll requires selector argument', 'color: orange'); } }; /* Method: jitcss Description: Functionality for jitcss. @param {any} classes - Description for classes @returns {any} - Result of the operation */ this.jitcss = function (classes) { if (classes.indexOf('-[') > -1) { let classesArr = classes.split(' '); self.log('jitcss'); for (cl of classesArr) { self.log(cl); let par = [...cl.matchAll(new RegExp('([^-]+)[\-][\[](.+)\]', 'g'))]; self.log('jitcss'); self.log(par); } } }; /* Method: compileClasses Description: Functionality for compileClasses. @param {any} string - Description for string @returns {any} - Result of the operation */ this.compileClasses = function (string) { var classesString = string; if (self.json.shortcuts && self.json.shortcuts.class) { for (shortcut in self.json.shortcuts.class) { if (string.indexOf(shortcut) > -1) { classesString = self.replaceAll(string, shortcut, self.json.shortcuts.class[shortcut]); } } } if (string.indexOf('(') >= 0) { classesString = ''; let classesArr = string.split(' '); for (cl of classesArr) { if (cl.indexOf('(') >= 0 && cl.endsWith(')')) { let classArr = cl.split('('); classArr[1] = classArr[1].slice(0, -1); if (Boolean(self.js(classArr[1]))) { if (classesString !== '') classesString += ' '; classesString += classArr[0]; } } else { if (classesString !== '') classesString += ' '; classesString += cl; } } if (string == classesString) { self.log('wrong dynamic class syntax'); self.log(string); } } return classesString; }; /* Method: createElement Description: Functionality for createElement. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @returns {any} - Result of the operation */ this.createElement = function (params, selectorParams) { let selector = params.selector || params.container; var container = selector || self.selector(selectorParams); var containerElement = self.query(container); var newSelector = self.selector(params, selectorParams); var newElements = []; if (containerElement) { if (!params) params = {}; var element = document.createElement(params.tag); containerElement.appendChild(element); if (params.attr) { if (params.attr.class) { params.attr.class = self.compileClasses(params.attr.class); } } self.dataStorage.set(element, 'code', params); self.dataStorage.set(element, 'key', params.key); newElements.push(element); if (params.attr) self.setAttributes(newElements, params.attr); if (params.style) self.css(params, newSelector); } return newElements; }; this.do = this.action = /* Method: execute Description: Functionality for execute. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.execute = function (params, selectorParams, args) { if (params !== undefined && params !== null) { if (typeof params == 'string') params = self.replaceProperties(params, args); let pluginsRequired = self.pluginsRequired(params); if (pluginsRequired.length > 0) self.pluginsLoader(pluginsRequired, self.do, [params, selectorParams, args]); else { if (Array.isArray(params)) for (var obj of params) self.do(obj, selectorParams, args); else if (typeof params == 'object') { if (params.if == undefined || self.if(params.if)) { if (self.only(params.roles, params.user)) { if (params.tag) { var selector = self.selector(params, selectorParams); self.extendJsonFromElement(params); var newElements = self.createElement(params, selectorParams); if (params.matchMedia) { for (var mediaEvent in params.matchMedia) { self.matchMedia(params.matchMedia[mediaEvent], mediaEvent); } } if (params.html) { self.html(params.html, selector, args); } else { for (var par in params) if ((nodes.exclude.indexOf(par) < 0) && (nodes.params.indexOf(par) < 0)) self.nested({ key: par, obj: params[par], selector: { selector: selector }, args: args }); } self.on(params.on, { selector: selector }); } else { var selector = self.selector(params, selectorParams); for (var par in params) if ((nodes.exclude.indexOf(par) < 0) && (nodes.params.indexOf(par) < 0)) self.nested({ key: par, obj: params[par], selector: selector, args: args }); if (params.on) self.on(params.on, { selector: selector }); } } } } else if (typeof params == 'function') return params(selectorParams); else self.log('can\'t execute: ' + params); } } }; /* Method: callback Description: Functionality for callback. @param {any} params - Description for params @returns {any} - Result of the operation */ this.callback = function (params) { if (params) { var path = params.to; if (params.var) path = 'var ' + params.var; let selector; let element = params.element; if (element && element.isConnected) params.value = self.elementToSelector(element); if (path) { var context = self.context(path); self.element({ path: path, value: params.value, root: context }); } if (params.do) self.do(params.do, selector); } }; /* Method: nested Description: Functionality for nested. @param {any} params - Description for params @returns {any} - Result of the operation */ this.nested = function (params) { let pluginsRequired = self.pluginsRequired(params.key); if (pluginsRequired.length > 0) { self.pluginsLoader(pluginsRequired, self.nested, [params]); } else { if (params.key.startsWith('set ')) { self.setData({ key: params.key.substr(4), value: params.obj }); } else if (params.key.startsWith('var ') || params.key.startsWith('data ') || params.key.startsWith('set ')) { console.log('%cdeprecated key: "' + params.key + '". Use "set key": "value"}', 'color:orange'); self.setData({ key: params.key, value: params.obj }); } else { var method = self.element({ path: params.key, root: self.methods }); if (method) { self.log('METHOD: ' + params.key, 'grey'); var methodArgs = params.obj; method(methodArgs, params.selector, params.args); } else { let nested; let part; var jsonicPart = false; if (self.json.parts) { part = self.element({ path: self.replaceAll(params.key, ':', '.'), root: self.json.parts }); } if (part) { self.log('PART: ' + params.key, 'grey'); var partObj = params.obj; partObj = self.replaceProperties(partObj); partObj.selector = partObj.selector || params.selector; if (partObj.setup) partObj = partObj.setup; nested = self.replacePropertyWithPrefix(part, 'setup', partObj); nested = self.replacePropertyWithPrefix(nested, 'arguments', partObj); self.extendJsonFromElement(nested); self.do(nested, params.selector, partObj); } else { if (self.json && self.json.functions && params.key && self.json.functions[params.key]) { self.log('FUNCTION: ' + params.key, 'grey'); let args = self.replaceProperties(params.obj, undefined, true); if (!args || !Array.isArray(args)) args = [args]; if (self.json.functions[params.key].requires) { let pluginsRequired = []; for (let plugin of self.json.functions[params.key].requires) { if (!self.pluginsLoaded[plugin]) pluginsRequired.push({ "name": plugin, version: "" }); } if (pluginsRequired.length > 0) self.pluginsLoader(pluginsRequired, self.function, [{ name: params.key, arguments: args }]); else { self.log('Plugins already loaded: ' + params.key, 'grey'); self.function({ name: params.key, arguments: args }); } } else { self.log('Function without plugin required: ' + params.key, 'grey'); self.function({ name: params.key, arguments: args }); } } else { var windowFunction = self.element({ path: params.key, root: window }); if (typeof windowFunction === 'function') { self.log('WINDOW function: ' + params.key, 'grey'); windowFunction(self.replaceProperties(params.obj, undefined, true)); } else if (windowFunction !== undefined) { self.log('window.' + params.key + ' is not a function', 'red'); } else { if (params.selector) { self.log('TAG: ' + params.key, 'grey'); let pluginsRequired = self.pluginsRequiredByTag(params.obj, params.key); if (pluginsRequired.length > 0) { let htmlTagParams = [params.obj, params.selector, params.key]; self.pluginsLoader(pluginsRequired, self.htmlTag, htmlTagParams); } else { self.htmlTag(params.obj, params.selector, params.key); } } else { self.log(params.key + ' not found', 'red'); } } } } } } } }; /* Method: setData Description: Functionality for setData. @param {any} params - Description for params @returns {any} - Result of the operation */ this.setData = function (params) { let setObj = {}; setObj[params.key] = params.value; self.set(setObj); }; this.partContainers = {}; /* Method: pluginsRequiredByTag Description: Functionality for pluginsRequiredByTag. @param {any} params - Description for params @param {any} tagKey - Description for tagKey @returns {any} - Result of the operation */ this.pluginsRequiredByTag = function (params, tagKey) { if (self.json.resources) { const pluginsTags = self.json.resources.pluginsTags; const pluginsAttr = self.json.resources.pluginsAttr; var pluginsRequired = []; if (pluginsTags[tagKey] && !self.pluginsLoaded[pluginsTags[tagKey].name]) pluginsRequired.push(pluginsTags[tagKey]); if (typeof params == 'string') { } else if (typeof params == 'object') { var objArray; if (Array.isArray(params)) objArray = params; else objArray = [params]; for (var obj of objArray) { if (obj.attr) { var attr = 'data-icon'; if (obj.attr[attr]) { if (pluginsAttr[attr] && !self.pluginsLoaded[pluginsAttr[attr].name]) pluginsRequired.push(pluginsAttr[attr]); } } } } return pluginsRequired; } else { return false; } }; /* Method: calendar Description: Functionality for calendar. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.calendar = function (params, args) { const localeName = (self.json.setup.language !== 'en') ? self.json.setup.language : 'en-US'; let calendarArr, todayIndex; if (params.unit) { switch (params.unit) { case 'month': const monthFormat = params.format || 'long'; var format = new Intl.DateTimeFormat(localeName, { month: monthFormat }).format; calendarArr = [...Array(12).keys()].map((m) => format(new Date(Date.UTC(2021, m)))); todayIndex = new Date().getMonth(); break; case 'weekday': const weekdayFormat = params.format || 'long'; var format = new Intl.DateTimeFormat(localeName, { weekday: weekdayFormat }).format; calendarArr = [...Array(7).keys()].map((day) => format(new Date(Date.UTC(2021, 5, day)))); todayIndex = self.weekday(); break; default: self.log('"calendar" function can\'t recognize "unit" parameter'); self.log(params.unit); break; } if (calendarArr) { if (params.index !== undefined) { params.index = self.js(params.index); let index = Number(self.replaceProperties(params.index, args)); return calendarArr[index]; } else { return calendarArr[todayIndex]; } } else { self.log('"calendar" function can\'t recognize "unit" or "format" parameters'); } } else { self.log('"calendar" function requires "unit" parameter'); } }; /* Method: month Description: Functionality for month. @param {any} params - Description for params @param {any} monthFormat = 'long' - Description for monthFormat = 'long' @returns {any} - Result of the operation */ this.month = function (params, monthFormat = 'long') { const localeName = (self.json.setup.language !== 'en') ? self.json.setup.language : 'en-GB'; const format = new Intl.DateTimeFormat(localeName, { month: monthFormat }).format; const weekdayArr = [...Array(12).keys()].map((m) => format(new Date(Date.UTC(2021, m)))); if (params !== undefined) { var index = Number(self.replaceProperties(params)); return weekdayArr[index]; } else return weekdayArr; }; /* Method: weekday Description: Functionality for weekday. @param {any} params - Description for params @param {any} weekdayFormat - Description for weekdayFormat @returns {any} - Result of the operation */ this.weekday = function (params, weekdayFormat) { const localeName = (self.json.setup.language !== 'en') ? self.json.setup.language : 'en-GB'; const format = new Intl.DateTimeFormat(localeName, { weekday: weekdayFormat }).format; const weekdayArr = [...Array(7).keys()].map((day) => format(new Date(Date.UTC(2021, 5, day)))); var result; if (params !== undefined) { var index = Number(self.replaceProperties(params)); result = weekdayArr[index]; } else result = weekdayArr; return result; }; /* Method: method Description: Functionality for method. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.method = function (params, args) { var value; if (typeof params == 'string') { return self.docElement(params); } else { if ((params.if == undefined) || self.if(params.if, undefined, args)) { if (self.notEmptyObject(params)) { var actionKey = Object.keys(params)[0]; var actionFunction = self.docElement(actionKey); var actionValue = params[actionKey]; if (!Array.isArray(actionValue)) actionValue = [actionValue]; if (actionFunction) { if (typeof actionFunction == 'function') return actionFunction(...actionValue); else return actionFunction; } else { self.log('unknown function'); self.log(params); return params; } } else { return undefined; } } } }; /* Method: Number Description: Functionality for Number. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.Number = function (params, args) { self.log('Number'); return self.method({ "Number": params }, args); }; /* Method: String Description: Functionality for String. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.String = function (params, args) { self.log('String'); return self.method({ "String": params }, args); }; /* Method: Math Description: Functionality for Math. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.Math = function (params, args) { return self.method(params, args, 'Math'); }; /* Method: dayjs Description: Functionality for dayjs. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.dayjs = function (params, args) { return self.method(params, args, 'dayjs'); }; /* Method: moment Description: Functionality for moment. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.moment = function (params, args) { return self.method(params, args, 'moment'); }; /* Method: dynamicCss Description: Functionality for dynamicCss. @param {any} selector - Description for selector @param {any} property - Description for property @param {any} value - Description for value @returns {any} - Result of the operation */ this.dynamicCss = function (selector, property, value) { if (value.indexOf('{') >= 0) { var resizeData = self.dataStorage.get(element, "resize"); if (!resizeData) resizeData = {}; resizeData[property] = value; var resizeData = self.dataStorage.set(element, "resize", resizeData); if (!self.resizeActions[selector]) self.resizeActions[selector] = {}; self.resizeActions[selector][property] = value; var result = self.replaceProperties(value) || ''; } else { var style = {}; style[property] = value; self.css({ style: style }); } }; /* Method: li Description: Functionality for li. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @returns {any} - Result of the operation */ this.li = function (params, selectorParams) { if (Array.isArray(params)) { for (var index in params) self.li(params[index], selectorParams); } else { if (params.items) { var itemsArray = (typeof params.items == 'string') ? self.json.items[params.items] : params.items; delete params.items; for (var index in itemsArray) { if (self.only(itemsArray[index].roles)) self.li(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') { params = { html: params }; }; params.tag = 'li'; self.do(params, selectorParams); } } }; /* Method: remove Description: Functionality for remove. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.remove = function (params, selectorParams, args) { var selector = self.selector(params.selector || self.selector(selectorParams)); if (selector) { var elements = self.queryAll(selector); if (elements) { elements.forEach(function (element, index) { element.remove(); }); } } }; /* Method: dispatchEvent Description: Functionality for dispatchEvent. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.dispatchEvent = function (params, selectorParams, args) { var selector = self.selector(params.selector || self.selector(selectorParams)); if (selector) { var elements = self.queryAll(selector); if (elements) { elements.forEach(function (element, index) { element.dispatchEvent(new Event(params.name)); }); } } }; /* Method: html Description: Functionality for html. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.html = function (params, selectorParams, args) { if (params) { if (Array.isArray(params)) { for (var obj of params) self.html(obj, selectorParams, args); } else { var container = self.selector(params.selector || params.container) || self.selector(selectorParams); if (container) { var element = self.query(container); if (element) { if (typeof params == 'string') { var paramsCompiled = self.replaceProperties(params, args); if (paramsCompiled) { if (typeof paramsCompiled == 'object') { self.do(paramsCompiled, { selector: container }, args); } else if (typeof paramsCompiled == 'string') { element.innerHTML += paramsCompiled; } } } else { if (params.empty || params.do == 'empty') { element.innerHTML = ''; delete params.empty; } if (params.tag) { self.do(params, container, args); } else if (params.html) { var htmlCompiled = self.replaceProperties(params.html, args); self.html(htmlCompiled, { selector: container }); } else if (params.lang) { var textLang = params.lang[self.json.setup.language] || params.lang['en'] || params.lang[Object.keys[0]]; if (Array.isArray(textLang)) { var paragraphs = []; for (var paragraph of textLang) paragraphs.push({ p: paragraph }); self.html(paragraphs, selectorParams, args); } else element.innerHTML = self.replaceProperties(textLang, args); if (element) { self.attribute(element, 'data-text', true); self.dataStorage.set(element, 'params', params); } } else if (params.text) { element.textContent = self.replaceProperties(params.text, args); } else if (params.append) { element.innerHTML += self.replaceProperties(params.append, args); } else if (params.prepend) { element.innerHTML = self.replaceProperties(params.prepend, args) + element.innerHTML; } else if (params.blocks) { self.blocks(params.blocks, { selector: container }, args); } else { let nestedParams = self.cloneObject(params); if (nestedParams.style) delete nestedParams.style; if (nestedParams.attr) delete nestedParams.attr; console.warn('UNKNOWN TAG'); console.warn(params); self.do(nestedParams, { selector: container }, args); if (element.isConnected) { if (params.attr) self.setAttributes(element, params.attr, args); if (params.style) self.css(params, selectorParams, args); } } } } else { } } else { self.log('"html" object requires selector property', 'red'); self.log(params); } } } else { self.log('"html" object without params'); } }; /* Method: setAttributes Description: Functionality for setAttributes. @param {any} elements - Description for elements @param {any} attrs - Description for attrs @param {any} args - Description for args @returns {any} - Result of the operation */ this.setAttributes = function (elements, attrs, args) { for (var attribute in attrs) if (attrs[attribute]) self.attribute(elements, attribute, self.replaceResult(attrs[attribute], args)); else self.attribute(elements, attribute, ""); }; /* Method: attribute Description: Functionality for attribute. @param {any} elements - Description for elements @param {any} attrId - Description for attrId @param {any} attrValue - Description for attrValue @returns {any} - Result of the operation */ this.attribute = function (elements, attrId, attrValue) { if (typeof attrValue !== undefined) { if (!Array.isArray(elements)) elements = [elements]; elements.forEach(function (element, index) { if (typeof attrValue == 'boolean' && attrValue) { element.setAttribute(attrId, ""); } else { element.setAttribute(attrId, self.replaceProperties(attrValue)); } }); } else { if (!Array.isArray(elements)) return elements.getAttribute(attrId); else return elements[0].getAttribute(attrId); } }; /* Method: attr Description: Functionality for attr. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.attr = function (params, selectorParams, args) { self.css(self.replaceProperties(params), selectorParams, args); }; /* Method: styleElement Description: Functionality for styleElement. @param {any} params - Description for params @param {any} element - Description for element @param {any} args - Description for args @returns {any} - Result of the operation */ this.styleElement = function (params, element, args) { for (var styleName in params) { if (styleName.startsWith('--')) element.style.setProperty(styleName, self.replaceProperties(params[styleName], args)); else element.style[styleName] = self.replaceProperties(params[styleName], args); } }; /* Method: css Description: Functionality for css. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.css = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var obj of params) self.css(obj, selectorParams, args); } else { var selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); var elements = self.queryAll(selector); if (elements) { elements.forEach(function (element, index) { if (element) { if (typeof params.style == 'object') { self.styleElement(params.style, element, args); } if (params.addClass) self.addClass(element, params.addClass); if (params.removeClass) self.removeClass(element, params.removeClass); if (params.toggleClass) self.toggleClass(element, params.toggleClass); } else { self.log('the function "css" can\'t find the selector ' + selector); self.log(params); self.log(selectorParams); } }); } else { self.log('"css" function is unable to select: ' + selector); self.log('params'); self.log(params); self.log('selectorParams'); self.log(selectorParams); } } }; /* Method: numberToHour Description: Functionality for numberToHour. @param {any} data - Description for data @returns {any} - Result of the operation */ this.numberToHour = function (data) { var fraction = data.value / data.max; var dayMin = Math.round(24 * 60 * fraction); var hour = parseInt(dayMin / 60); var min = dayMin - hour * 60; var hourString = String(hour < 10 ? '0' : '') + String(hour); var minString = String(min < 10 ? '0' : '') + String(min); return hourString + ':' + minString; }; /* Method: hourToNumber Description: Functionality for hourToNumber. @param {any} data - Description for data @returns {any} - Result of the operation */ this.hourToNumber = function (data) { var timeArr = data.value.split(':'); var dayMin = (60 * Number(timeArr[0])) + Number(timeArr[1]); var fraction = dayMin / (24 * 60); return Math.round(fraction * data.max); }; /* Method: pannellum Description: Functionality for pannellum. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.pannellum = function (params, selectorParams, args) { self.log('pannellum'); var container = params.selector || params.container; var selector = self.selector(container) || self.selector(selectorParams); var element = self.query(selector); pannellum.viewer(element, params); }; /* Method: qrcode Description: Functionality for qrcode. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.qrcode = function (params, selectorParams, args) { self.log('qrcode'); var container = params.selector || params.container; var selector = self.selector(container) || self.selector(selectorParams); var element = self.query(selector); self.log(selector); self.log('element'); self.log(element); var QRCodeOptions = { text: self.replaceProperties(params.text, args) || 'jsonic.io', width: params.size || 128, height: params.size || 128, useSVG: true, colorDark: params.colorDark || '#000000', colorLight: params.colorLight || '#ffffff', correctLevel: QRCode.CorrectLevel.H }; self.log('QRCodeOptions'); self.log(QRCodeOptions); element.textContent = ''; var qrcode = new QRCode(element, QRCodeOptions); self.log('qrcode'); self.log(qrcode); return qrcode; }; /* Method: weekdaysShort Description: Functionality for weekdaysShort. @param {any} length - Description for length @param {any} caseFunction - Description for caseFunction @returns {any} - Result of the operation */ this.weekdaysShort = function (length, caseFunction) { if (!caseFunction) caseFunction = caseUp; var language = 'en'; var fixoLang = fixo.getFixoLanguage(); var userLang = fixo.getUserLanguage(); if (fixo.device) language = fixoLang; else language = userLang; var weekDays = self.cloneObject(moment.localeData(language).weekdays()); weekDays[7] = weekDays[0]; weekDays.shift(); for (var i = 0; i < 7; i++) { if (length) weekDays[i] = weekDays[i].substr(0, length); if (caseFunction) weekDays[i] = caseFunction(weekDays[i]); } return weekDays; }; /* Method: weekDaysToString Description: Functionality for weekDaysToString. @param {any} days - Description for days @returns {any} - Result of the operation */ this.weekDaysToString = function (days) { var text = ''; for (var i in days) { if (days[i]) { if (text !== '') text += '/'; text += self.weekdaysShort(3, capitalize)[i]; } } return text; }; var sortField; /* Method: dynamicSort Description: Functionality for dynamicSort. @param {any} data - Description for data @returns {any} - Result of the operation */ var dynamicSort = function (data) { var sortOrder = 1; if (data.reverse) { sortOrder = -1; } sortField = data.field; return function (a, b) { var result = (a[sortField] < b[sortField]) ? -1 : (a[sortField] > b[sortField]) ? 1 : 0; return result * sortOrder; }; }; /* Method: sort Description: Functionality for sort. @param {any} data - Description for data @returns {any} - Result of the operation */ this.sort = function (data) { if (data.object !== undefined) { if (Array.isArray(data.object)) { return data.object.sort(dynamicSort({ field: data.field, reverse: data.reverse })); } else { var arr = self.objectToArray({ object: data.object, add: data.add, }); return arr.sort(dynamicSort({ field: data.field, reverse: data.reverse })); } } else { self.log('sort of undefined'); return []; } }; /* Method: objectToArray Description: Functionality for objectToArray. @param {any} data - Description for data @returns {any} - Result of the operation */ this.objectToArray = function (data) { var arr = []; var obj = data.object; if (obj !== undefined) { for (var key in obj) { obj[key].id = key; if (data.add) obj[key] = Object.assign(obj[key], data.add); arr.push(obj[key]); } } return arr; }; /* Method: equal Description: Functionality for equal. @param {any} obj1 - Description for obj1 @param {any} obj2 - Description for obj2 @returns {any} - Result of the operation */ this.equal = function (obj1, obj2) { if (obj1 && obj2) { return (JSON.stringify(obj1).replace('"', '') == JSON.stringify(obj2).replace('"', '')); } else { return (obj1 == obj2); } }; /* Method: escapeRegExp Description: Functionality for escapeRegExp. @param {any} str - Description for str @returns {any} - Result of the operation */ var escapeRegExp = function (str) { return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); }; /* Method: replaceAll Description: Functionality for replaceAll. @param {any} str - Description for str @param {any} find - Description for find @param {any} replace - Description for replace @returns {any} - Result of the operation */ this.replaceAll = function (str, find, replace) { if (str !== undefined) { let result; if (typeof str == 'string') result = str; else result = JSON.stringify(str); if (str) { if (find) { result = String(str).replace(new RegExp(escapeRegExp(find), 'g'), replace); if (typeof str == 'object' && result) return JSON.parse(result); else return result; } else { return str; } } } else { return str; } }; /* Method: capitalize Description: Functionality for capitalize. @param {any} str - Description for str @returns {any} - Result of the operation */ this.capitalize = function (str) { return str.replace(/\b\w/g, l => l.toUpperCase()); }; /* Method: getPageName Description: Functionality for getPageName. @param {any} url - Description for url @returns {any} - Result of the operation */ this.getPageName = function (url) { var index = url.lastIndexOf("/") + 1; var filenameWithExtension = url.substr(index); var filename = filenameWithExtension.split(".")[0]; return filename; }; /* Method: goToMainUrl Description: Functionality for goToMainUrl. @param {any} - No parameters @returns {any} - Result of the operation */ this.goToMainUrl = function () { window.location = self.mainUrl; }; /* Method: getParameterByName Description: Functionality for getParameterByName. @param {any} name - Description for name @param {any} url - Description for url @returns {any} - Result of the operation */ this.getParameterByName = function (name, url) { if (!url) url = window.location.href; name = name.replace(/[\[\]]/g, "\\$&"); var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), results = regex.exec(url); if (!results) return null; if (!results[2]) return ''; return decodeURIComponent(results[2].replace(/\+/g, " ")); }; /* Method: paramsToObject Description: Functionality for paramsToObject. @param {any} params - Description for params @returns {any} - Result of the operation */ var paramsToObject = function (params) { params = params.split('#')[0]; return JSON.parse('{"' + params.replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}'); }; /* Method: objectToParams Description: Functionality for objectToParams. @param {any} object - Description for object @returns {any} - Result of the operation */ var objectToParams = function (object) { var str = ''; for (var key in object) str += '&' + key + '=' + object[key]; if (str) str = str.substr(1); return encodeURI(str); }; /* Method: getParams Description: Functionality for getParams. @param {any} - No parameters @returns {any} - Result of the operation */ this.getParams = function () { var params = {}; var url = window.location.href.split('#')[0]; if (url.indexOf('?') > -1) { var urlParams = decodeURI(url.split('?')[1]); self.log(urlParams); if (urlParams) { var k = self.getParameterByName('k', url); //self.log(k); if (k) { params = self.atob(k); } else { params = paramsToObject(urlParams); } } } return params; }; /* Method: atob Description: Functionality for atob. @param {any} k - Description for k @returns {any} - Result of the operation */ this.atob = function (k) { self.log('atob'); var params = paramsToObject(atob(k)); // base64 -> query -> object // decompress params if (params.h) // hotel params.h = String(parseInt(String(params.h), 36)); // base36 if (params.c) // customer params.c = String(parseInt(String(params.c), 36)); // base36 if (params.n) { // phone params.n = String(parseInt(String(params.n), 36)); // base36 params.n = '+' + params.n; } //if (params.s) params.s = var.services.id[params.s]; self.log(params); return params; }; /* Method: btoa Description: Functionality for btoa. @param {any} params - Description for params @returns {any} - Result of the operation */ this.btoa = function (params) { self.log('btoa'); //if (params.s) params.s = var.services.id.indexOf(params.s); if (params.h) // hotel params.h = Number(params.h).toString(36); // base36 if (params.c) // customer params.c = Number(params.c).toString(36); // base36 if (params.n) { // phone if (params.n.startsWith('+')) params.n = params.n.substr(1); params.n = params.n.replace(/ /g, ''); params.n = params.n.replace(/-/g, ''); params.n = Number(params.n).toString(36); // base36 } self.log(params); return btoa(objectToParams(params)); // query -> base64 }; /* /* Method: encodeNum Description: Functionality for encodeNum. @param {any} num - Description for num @returns {any} - Result of the operation */ var encodeNum = function(num) { // 0..1296 es:customer var hex = c.toString(36); return c.toString(36); } /* Method: decodeNum Description: Functionality for decodeNum. @param {any} str - Description for str @returns {any} - Result of the operation */ var decodeNum = function(str) { return str.parseInt(36); // .length == 1 ? "0" + hex : hex } */ /* Method: colorToRgba Description: Functionality for colorToRgba. @param {any} hex - Description for hex @param {any} opacity - Description for opacity @returns {any} - Result of the operation */ this.colorToRgba = function (hex, opacity) { if (hex == 'white') { hex = '#fff'; } if (hex == 'black') { hex = '#000'; } var c; if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) { c = hex.substring(1).split(''); if (c.length == 3) { c = [c[0], c[0], c[1], c[1], c[2], c[2]]; } c = '0x' + c.join(''); return 'rgba(' + [(c >> 16) & 255, (c >> 8) & 255, c & 255].join(',') + ',' + opacity + ')'; } else { self.log('Bad Hex:' + hex); } }; /* Method: hueToRGB Description: Functionality for hueToRGB. @param {any} m1 - Description for m1 @param {any} m2 - Description for m2 @param {any} h - Description for h @returns {any} - Result of the operation */ var hueToRGB = function (m1, m2, h) { h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h); if (h * 6 < 1) return m1 + (m2 - m1) * h * 6; if (h * 2 < 1) return m2; if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6; return m1; }; /* Method: HSLToRGB Description: Functionality for HSLToRGB. @param {any} hsl - Description for hsl @returns {any} - Result of the operation */ var HSLToRGB = function (hsl) { var m1, m2, r, g, b; var h = hsl[0], s = hsl[1], l = hsl[2]; m2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s; m1 = l * 2 - m2; return [hueToRGB(m1, m2, h + 0.33333), hueToRGB(m1, m2, h), hueToRGB(m1, m2, h - 0.33333)]; }; /* Method: packRGB Description: Functionality for packRGB. @param {any} rgb - Description for rgb @returns {any} - Result of the operation */ var packRGB = function (rgb) { var r = Math.round(rgb[0] * 255); var g = Math.round(rgb[1] * 255); var b = Math.round(rgb[2] * 255); // '#' + return (r < 16 ? '0' : '') + r.toString(16) + (g < 16 ? '0' : '') + g.toString(16) + (b < 16 ? '0' : '') + b.toString(16); }; /* Method: degToRGB Description: Functionality for degToRGB. @param {any} deg - Description for deg @returns {any} - Result of the operation */ this.degToRGB = function (deg) { return packRGB(HSLToRGB([deg / 360, 1, 0.5])); }; /* Method: stripHtml Description: Functionality for stripHtml. @param {any} html - Description for html @returns {any} - Result of the operation */ this.stripHtml = function (html) { var tmp = document.createElement("DIV"); tmp.innerHTML = html; return tmp.textContent || tmp.innerText || ""; }; //-------------------------- // TASK MANAGER //-------------------------- /* Method: log Description: Functionality for log. @param {any} value - Description for value @param {any} color - Description for color @returns {any} - Result of the operation */ this.log = function (value, color) { if (self.json.setup && self.json.setup.log) { // log enabled if (typeof value === 'string') console.log('%c' + value, 'color:' + color); else console.log(value); } }; /* Method: varlog Description: Functionality for varlog. @param {any} str - Description for str @returns {any} - Result of the operation */ var varlog = function (str) { self.log(str); self.log(window[str]); // 'var' -> var }; /* Method: logJson Description: Functionality for logJson. @param {any} jsonPar - Description for jsonPar @returns {any} - Result of the operation */ this.logJson = function (jsonPar) { self.log(JSON.stringify(jsonPar)); }; /* Method: getTimestamp Description: Functionality for getTimestamp. @param {any} - No parameters @returns {any} - Result of the operation */ this.getTimestamp = function () { // we need also an API to get the time // like .getTime()? return Math.floor(Date.now()); }; /* Method: cloneObject Description: Functionality for cloneObject. @param {any} obj - Description for obj @returns {any} - Result of the operation */ this.cloneObject = function (obj) { var newObj = JSON.stringify(obj); return self.parse(newObj); }; /*------------------------ TEXT ------------------------*/ /* /* Method: caseUp Description: Functionality for caseUp. @param {any} string - Description for string @returns {any} - Result of the operation */ var caseUp = function (string) { if (!string) string = ''; return string.toUpperCase(); } /* Method: caseDown Description: Functionality for caseDown. @param {any} string - Description for string @returns {any} - Result of the operation */ var caseDown = function (string) { if (!string) string = ''; return string.toLowerCase(); } /* Method: capitalize Description: Functionality for capitalize. @param {any} string - Description for string @returns {any} - Result of the operation */ var capitalize = function(string) { if (!string) string = ''; return self.capitalize(string); } /* Method: text Description: Functionality for text. @param {any} key - Description for key @param {any} caseFunction - Description for caseFunction @returns {any} - Result of the operation */ var text = function (key, caseFunction) { var t = self.json.text[key] || ''; if (caseFunction) return caseFunction(t); else return t; } */ /* Method: setElement Description: Functionality for setElement. @param {any} elementString - Description for elementString @param {any} elementValue - Description for elementValue @returns {any} - Result of the operation */ this.setElement = function (elementString, elementValue) { var context = window; var namespaces = elementString.split("."); var func = namespaces.pop(); if (namespaces[0] == 'frame') { namespaces.shift(); var frameName = namespaces.shift(); if (frameName && document.getElementById(frameName) !== null) context = document.getElementById(frameName).contentWindow; } else if (namespaces[0] == 'admin') { // fixo namespaces.shift(); context = fixoAdmin; } for (var i = 0; i < namespaces.length; i++) { if (context[namespaces[i]]) { // var context = context[namespaces[i]]; } else { if (elementValue) // scrittura context[namespaces[i]] = {}; // crea contesto inesistente } } context[func] = elementValue; }; /* Method: context Description: Functionality for context. @param {any} path - Description for path @returns {any} - Result of the operation */ this.context = function (path) { const re = /^(setup|var|data|texts|parts)[\.\s]/; // reserved namespaces if (re.test(path)) { /* self.log('MATCHED setup|var|data|parts'); console.log(params); */ return self.json; } else { return window; } }; /* Method: element Description: Functionality for element. @param {any} params - Description for params @returns {any} - Result of the operation */ this.element = function (params) { // {root, path, value} // in respect to docElement, it includes replaceProperties for path and value // but only if value is a string. TO DO: check it let context; let path = self.replaceProperties(params.path, params.args); let value = (params.value && typeof params.value == 'string') ? self.replaceProperties(params.value, params.args) : params.value; // NOTE: log error if the params.root is equal to the first element of the path? (window.window works) if (!params.root) { context = self.context(path); } else { context = params.root; } return self.docElement(path, value, context, params.delete); //self.log(value); /* if (value && typeof value == 'string') { if (value.startsWith('js:')) value = self.js(value.substr(3)); else if (value.startsWith('+=')) value = self.element({path: path}) + self.js(value.substr(2)); else if (value.startsWith('-=')) value = self.element({path: path}) - self.js(value.substr(2)); else if (value.startsWith('/=')) value = self.element({path: path}) / self.js(value.substr(2)); else if (value.startsWith('*=')) value = self.element({path: path}) / self.js(value.substr(2)) } */ // self.log(value); /* if (value.startsWith('number:')) value = Number(self.js(value.substr(6))); alert('dopo number:'+value); if (value.startsWith('boolean:')) value = Boolean(self.js(value.substr(7))); if (value.startsWith('string:')) value = String(self.js(value.substr(6))); if (value.startsWith('+:')) value = self.element({path: path}) + self.js(value.substr(2)); if (value.startsWith('-:')) value = self.element({path: path}) - self.js(value.substr(2)); if (value.startsWith('/:')) value = self.element({path: path}) / self.js(value.substr(2)); if (value.startsWith('*:')) value = self.element({path: path}) / self.js(value.substr(2)); */ /* // verificare... if (value.startsWith('push:')) {var obj = self.docElement(path, undefined, root); return obj.push(value.substr(3));} if (value.startsWith('unshift:')) {var obj = self.docElement(path, undefined, root); return obj.unshift(value.substr(3));} if (value.startsWith('pop:')) {var obj = self.docElement(path, undefined, root); return obj.pop(value.substr(3));} if (value.startsWith('shift:')) {var obj = self.docElement(path, undefined, root); return obj.shift(value.substr(3));} */ }; /* Method: docElement Description: Functionality for docElement. @param {any} elementString - Description for elementString @param {any} elementValue - Description for elementValue @param {any} context - Description for context @param {any} elementDelete - Description for elementDelete @returns {any} - Result of the operation */ this.docElement = function (elementString, elementValue, context, elementDelete) { if (!context) context = window; // TO DO: remove var namespaces = elementString.split(/[.\s]+/); // path nodes separed by dot or spaces /* console.log('<-------'); console.log('context'); console.log(context); console.log('path'); console.log(elementString); console.log('value'); console.log(elementValue); console.log('------>'); */ var lastElement = namespaces.pop(); /* if (namespaces[0] == 'self') { namespaces.shift(); context = self; } else if (namespaces[0] == 'frame') { namespaces.shift(); var frameName = namespaces.shift(); if (frameName && document.getElementById(frameName) !== null) context = document.getElementById(frameName).contentWindow; } */ /* console.log('namespaces'); console.log(namespaces); */ for (var i = 0; i < namespaces.length; i++) { if (context[namespaces[i]]) { // var context = context[namespaces[i]]; } else { if (elementValue !== undefined && elementValue !== null) { // wants to assign a value context[namespaces[i]] = {}; // it create the context context[namespaces[i]] if it doesn't exist context = context[namespaces[i]]; /* self.log('crea context inesistente'); self.log('namespaces[i]: '+namespaces[i]); */ /* self.log('elementValue'); self.log(elementValue); self.log('context[namespaces[i]]'); self.log(context[namespaces[i]]); */ } else { /* self.log(elementString + ' undefined'); self.log('lastElement:' + lastElement); self.log(elementValue); */ } //break; // perché? rendeva impossibile creare un listener su un nodo secondario (solo su app e non su app/dev) } } if (elementValue !== undefined) { // write //self.log(lastElement+'='+elementValue); if (typeof elementValue == 'string') elementValue = self.js(elementValue); // 1.0.3 context[lastElement] = elementValue; // elementValue can be a js function /* self.log('context'); self.log(context); self.log('context[lastElement]'); self.log(context[lastElement]); self.log('====='); */ } if (elementDelete) delete context[lastElement]; /* self.log('context'); self.log(context); */ /* console.log('namespaces'); console.log(namespaces); self.log('lastElement'); self.log(lastElement); self.log('context[lastElement]'); self.log(context[lastElement]); */ if (context[lastElement] && context[lastElement].isConnected) return self.elementToSelector(context[lastElement]); else return context[lastElement]; }; /* /* Method: openCloseDropdown Description: Functionality for openCloseDropdown. @param {any} key - Description for key @returns {any} - Result of the operation */ this.openCloseDropdown = function(key) { self.log('openCloseDropdown'); self.log("key"); self.log(key); //$('.dropdown-menu').css('display','none'); var selector = self.selector({ "id": "dropdown" +key, "class": 'points', "value": key, }); self.log("selector"); self.log(selector); if ($(selector + ' > .dropdown-menu').css('display') == 'none') { $(selector + ' > .dropdown-menu').css('display', 'block'); } else { $(selector + ' > .dropdown-menu').css('display', 'none'); } } */ /* Method: timeToMs Description: Functionality for timeToMs. @param {any} string - Description for string @returns {any} - Result of the operation */ this.timeToMs = function (string) { // bug var timeArray = string.match(/(\d+)(\w+)/); // es: 1s / 100ms if (timeArray) { var value = Number(timeArray[0]); var unit = timeArray[1]; var unitInMs = { ms: 1, s: 1000, m: 1000 * 60, h: 1000 * 60 * 60, d: 1000 * 60 * 60 * 24, milliseconds: 1, seconds: 1000, minutes: 1000 * 60, hours: 1000 * 60 * 60, days: 1000 * 60 * 60 * 24 }; if (value) if (unitInMs[unit]) return value * unitInMs[unit]; else self.log('wrong unit in the time string [value][unit]: ' + string); else self.log('wrong value in the time string [value][unit]: ' + string); } else return Number(string); }; this.intervals = {}; /* Method: timer Description: Functionality for timer. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.timer = function (params, args) { // can go in "browser.json / functions (JS Browser BOM) let name = self.replaceProperties(params.name); if (!name) name = self.getTimestamp() + Math.random(1000); if (params.play !== undefined && params.play == 0) { if (self.intervals[name]) { self.clearInterval({ name: name }, args); } if (self.timeouts[name]) { self.clearTimeout({ name: name }, args); } } else if (params.every !== undefined) { let every = self.replaceProperties(params.every); if (every) { self.setInterval({ name: name, duration: every, do: params.do }, args); } } else if (params.after !== undefined) { let after = self.replaceProperties(params.after); if (after) { self.setTimeout({ name: name, duration: after, do: params.do }, args); } else { self.do(params.do, null, args); } } }; /* Method: setInterval Description: Functionality for setInterval. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.setInterval = function (params, args) { if (params.name && params.duration) { if (self.intervals[params.name]) clearInterval(self.intervals[params.name]); self.do(params.do); self.intervals[params.name] = setInterval(function () { self.do(params.do); return params.name; }, Number(params.duration)); } else self.log('"setInterval" function requires "name" and "duration" parameters'); }; /* Method: clearInterval Description: Functionality for clearInterval. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.clearInterval = function (params, args) { if (self.intervals[params.name]) { clearInterval(self.intervals[params.name]); delete self.intervals[params.name]; } }; this.timeouts = {}; /* Method: setTimeout Description: Functionality for setTimeout. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.setTimeout = function (params, args) { if (params.name && params.duration) { if (self.timeouts[params.name]) clearInterval(self.timeouts[params.name]); self.timeouts[params.name] = setTimeout(function () { self.do(params.do); return params.name; }, Number(params.duration)); } else self.log('"setTimeout" function requires "name" and "duration" parameters'); }; /* Method: clearTimeout Description: Functionality for clearTimeout. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.clearTimeout = function (params, args) { if (self.timeouts[params.name]) { clearTimeout(self.timeouts[params.name]); delete self.timeouts[params.name]; } }; /* Method: on Description: Functionality for on. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @returns {any} - Result of the operation */ this.on = function (params, selectorParams) { var container = (selectorParams) ? self.selector(selectorParams) : params.selector; var element; if (container) { element = self.query(container); if (element) self.dataStorage.set(element, "onData", { on: params, selector: container }); else { self.log('can\'t find the element "' + container + '" ("on" function)'); self.log('params'); self.log(params); self.log('selectorParams'); self.log(selectorParams); } } for (var eventId in params) { if (eventId == 'init') { self.do(params.init, selectorParams); } else if (eventId == 'hashchange') { self.onHashChange.push(params.hashchange); window.addEventListener('hashchange', function () { self.json.setup.page.hash = window.location.hash.substr(1); self.do(self.onHashChange); self.uiUpdate(); }); } else if (eventId == 'scroll') { self.onScroll.push(params.scroll); window.addEventListener('scroll', function () { self.do(self.onScroll); }); } else if (eventId == 'resize') { self.onResize.push(params.resize); window.addEventListener('resize', function () { self.do(self.onResize); }); } else if (eventId == 'in') { if (container) { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(function (entry) { if (entry.intersectionRatio == 1) { var el = entry.target; if (el.getAttribute('in') !== 'true') { el.setAttribute('in', 'true'); self.onEvent(entry.target, { type: 'in' }); } } }); }, { rootMargin: '0px', threshold: [0, 1] }); observer.observe(self.query(container)); } } else if (eventId == 'inViewport') { if (container) { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(function (entry) { if (entry.intersectionRatio > 0) { self.onEvent(entry.target, { type: 'inViewport' }); } }); }, { rootMargin: '0px', threshold: [0, 1] }); observer.observe(self.query(container)); } } else if (eventId == 'outViewport') { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(function (entry) { if (entry.intersectionRatio == 0) { self.onEvent(entry.target, { type: 'outViewport' }); } }); }, { rootMargin: '0px', threshold: [0, 1] }); const element = self.query(container); observer.observe(element); } else if (eventId !== 'selector') { if (element) { element.addEventListener(eventId, function (event) { element.setAttribute('listener', 'true'); self.onEvent(this, event); }); if (eventId == 'mousedown' || eventId == 'mouseup' || eventId == 'click') element.style.cursor = 'pointer'; } } } }; /* Method: money Description: Functionality for money. @param {any} value - Description for value @returns {any} - Result of the operation */ this.money = function (value) { var rounded = Math.round(Number(value) * 100) / 100; var string = String(rounded); if (rounded == Math.floor(rounded)) string += ',00'; string = String(string).replace('.', ','); return string; }; /* Method: offcanvas Description: Functionality for offcanvas. @param {any} params - Description for params @returns {any} - Result of the operation */ this.offcanvas = function (params) { self.log('offcanvas'); self.log('params'); self.log(params); var container = params.selector || params.container; var selector = self.selector(container); var element = self.query(selector); self.log('offcanvas'); self.log(params); self.log('selector'); self.log(selector); self.log('element'); self.log(element); if (element) { if (params.do == 'hide') { self.css({ removeClass: 'show' }, params); } else { new bootstrap.Offcanvas(element).show(); } } else { self.log('"offcanvas" method can\'t find the selected element'); } }; /* Method: elementToSelector Description: Functionality for elementToSelector. @param {any} element - Description for element @returns {any} - Result of the operation */ this.elementToSelector = function (element) { if (element.id) { return '#' + element.id; } if (element.dataset?.value) { const sameDataValue = document.querySelectorAll(`[data-value="${element.dataset.value}"]`); if (sameDataValue.length === 1) { return `[data-value="${element.dataset.value}"]`; } } if (element.classList && element.classList.length > 0) { for (const className of element.classList) { if (className) { const sameClass = document.querySelectorAll('.' + className); if (sameClass.length === 1) { return '.' + className; } } } } const tagName = element.tagName.toLowerCase(); const sameTag = document.querySelectorAll(tagName); if (sameTag.length === 1) { return tagName; } let path = []; while (element.parentNode) { let selector = element.tagName.toLowerCase(); const index = Array.from(element.parentNode.children).indexOf(element) + 1; selector += `:nth-child(${index})`; path.unshift(selector); element = element.parentNode; } return path.join(' > '); }; /* Method: onEvent Description: Functionality for onEvent. @param {any} element - Description for element @param {any} event - Description for event @returns {any} - Result of the operation */ this.onEvent = function (element, event) { var item = self.dataStorage.get(element, 'onData'); var code = self.dataStorage.get(element, 'code') || ''; var value = element.getAttribute('data-value'); var selector = self.elementToSelector(element); var eventType = (event.type && item.on) ? item.on[event.type] : undefined; var action, specialKey; if (item.on) { if (event.button == '2' && event.type == 'mousedown') { if (item.on['contextmenu']) action = item.on['contextmenu']; } else if (event.type && item.on[event.type]) { var eventAction = item.on[event.type]; if (eventAction) { if (eventAction.shiftKey && event.shiftKey) { specialKey = 'shiftKey'; action = eventAction.shiftKey; } else if (eventAction.altKey && event.altKey) { specialKey = 'altKey'; action = eventAction.altKey; } else if (eventAction.cmdKey && event.cmdKey) { specialKey = 'cmdKey'; action = eventAction.cmdKey; } else if (!eventAction.shiftKey && !eventAction.altKey && !eventAction.cmdKey) { action = item.on[event.type]; } } } } if (action) { if (event.target) { var actionString; var targetId = event.target.id; var targetClass = event.target.className; var targetValue = event.target.dataset.value; var targetSelector = event.target.dataset.selector; targetSelector = self.replaceAll(targetSelector, '"', '\''); action = self.stringify(action); if (typeof targetId !== 'string') targetId = ''; if (typeof targetClass !== 'string') targetClass = ''; actionString = self.replaceAll(action, '{on:target.id}', targetId); actionString = self.replaceAll(actionString, '{on:altKey}', event.altKey); actionString = self.replaceAll(actionString, '{on:target.className}', targetClass); actionString = self.replaceAll(actionString, '{on:target.data-value}', targetValue); actionString = self.replaceAll(actionString, '{on:target.dataset.value}', targetValue); actionString = self.replaceAll(actionString, '{on:target.dataset.selector}', targetSelector); actionString = self.replaceAll(actionString, '{on:which}', event.which); actionString = self.replaceAll(actionString, '{on:clientY}', event.clientY); actionString = self.replaceAll(actionString, '{on:clientX}', event.clientX); actionString = self.replaceAll(actionString, '{on:value}', targetValue); actionString = self.replaceAll(actionString, '{on:dragging}', (event.which > 0)); if (this.isJson(actionString)) action = self.parse(actionString); else action = actionString; } var args = item.args; let specialKeyLog = (specialKey) ? ' + ' + specialKey : ''; self.do(action, { selector: selector }, args); } }; this.pluginsFunctionAvailable = []; self.pluginsLoader = function (packs, callback, params) { var filesToLoad = []; for (pack of packs) { if (self.pluginsLoaded[pack.name] == undefined) { self.log('require plugin ' + pack.name, 'grey'); var plugin = self.findPlugin(pack.name); let version; var pluginsFiles; if (plugin) { pluginsFiles = plugin.files || plugin; version = plugin.version; } else { pluginsFiles = self.json.resources.pluginsFiles[pack.name]; version = pack.version; } self.pluginsLoaded[pack.name] = version; if (!Array.isArray(pluginsFiles)) pluginsFiles = [pluginsFiles]; for (item of pluginsFiles) { var url = self.replaceAll(item.url, '{version}', version); if (!self.findUrl(filesToLoad, url)) filesToLoad.push({ name: item.name, url: url, type: item.type }); } } } if (filesToLoad.length > 0) { let promises = []; filesToLoad.forEach(function (item) { promises.push(loadPlugin({ name: item.name, url: item.url, type: item.type, rel: item.rel, as: item.as, content: item.content })); }); Promise.all(promises).then(function (files) { callback(...params); }).catch(function (script) { self.log('failed to load error'); self.log(item); self.log(script); }); } }; /* Method: pluginsRequired Description: Functionality for pluginsRequired. @param {any} params - Description for params @returns {any} - Result of the operation */ this.pluginsRequired = function (params) { if (self.json.resources) { const pluginsFunctions = self.json.resources.pluginsFunctions; var pluginsRequired = []; if (typeof params == 'string') { if (pluginsFunctions[params]) { if (!self.pluginsLoaded[pluginsFunctions[params].name]) pluginsRequired.push(pluginsFunctions[params]); } } else if (typeof params == 'object') { var objArray; if (Array.isArray(params)) objArray = params; else objArray = [params]; for (var obj of objArray) { for (var key in obj) { var mainFunction = (key.indexOf('.') >= 0) ? key.substr(0, key.indexOf('.')) : key; if (pluginsFunctions[mainFunction]) { if (!self.pluginsLoaded[pluginsFunctions[mainFunction].name]) pluginsRequired.push(pluginsFunctions[mainFunction]); } } } } return pluginsRequired; } else { return []; } }; /* Method: functionName Description: Functionality for functionName. @param {any} obj - Description for obj @returns {any} - Result of the operation */ this.functionName = function (obj) { if (obj == 'object') { const name = Object.keys(obj)[0]; const pluginFunctions = ['database', 'ace', 'moment', 'dayjs']; if (pluginFunctions.indexOf(name) >= 0) return name; } }; /* Method: for Description: Functionality for for. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.for = function (params, selectorParams, args) { let container = self.selector(params.selector || params.container) || self.selector(selectorParams); let itemsName = params.id || params.name; if (params.of) { var itemsArray = self.replaceProperties(params.of, args); if (itemsArray) { if (params.html) { if (!params.do) params.do = []; else if (!Array.isArray(params.do)) params.do = [params.do]; params.do.push({ html: params.html }); } if (typeof itemsArray == 'object') { let indexNum = 0; for (var index in itemsArray) { var item = itemsArray[index]; if (typeof item == 'object') { item.key = index; item.index = index; } if (typeof item.output == 'object') { for (let key in item.output) { var output = item.output[key]; if (typeof output == 'string') { output = self.js(output, args); } else if (typeof output == 'object') { output = self.replaceProperties(output, args); } item = self.replaceItems(item, output, key); } } if (params.do.length > 0) { let objWithIndex = self.cloneObject(params.do); if (params.var) { self.element({ path: params.var, value: item, root: self.json.var }); objWithIndex = self.replacePropertyWithPrefix(objWithIndex, 'index:' + params.var, index); } if (itemsName) { objWithIndex = self.replacePropertyWithPrefix(objWithIndex, 'index:' + itemsName, index); objWithIndex = self.replacePropertyWithPrefix(objWithIndex, itemsName, item); } if (params.delay) { params.delay = self.replaceProperties(params.delay); let forId = params.var || itemsName; self.timer({ name: 't' + forId + index, after: indexNum * params.delay, do: objWithIndex }); } else { self.do(objWithIndex, { selector: container }); } } indexNum += 1; } } } } else if (params.from !== undefined && params.to !== undefined) { var step = self.js(self.replaceProperties(params.step)) || 1; var from = self.js(self.replaceProperties(params.from)) || 0; var to = self.js(self.replaceProperties(params.to)); if (to !== undefined) { for (var index = Number(from); index <= Number(to); index += Number(step)) { if (params.var) self.element({ path: params.var, value: index, root: self.json.var }); var item = self.replaceItems(params, String(index), itemsName); if (item.output && typeof item.output == 'object') { for (let key in item.output) { var output = item.output[key]; if (typeof output == 'string') { output = self.js(output, args); } else if (typeof output == 'object') { output = self.replaceProperties(output, args); } item = self.replaceItems(item, output, key); } } if (item.do) { params.do = self.replacePropertyWithPrefix(item.do, 'index:' + itemsName, index); self.do(item.do, selectorParams, args); } if (item.html) { params.html = self.replacePropertyWithPrefix(item.html, 'index:' + itemsName, index); self.html(item.html, selectorParams); } } } } else { self.log('"for" element requires "value" or "from" and "to" parameters'); self.log(params); } }; /* Method: htmlTag Description: Functionality for htmlTag. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} tagParam - Description for tagParam @param {any} mainParam - Description for mainParam @returns {any} - Result of the operation */ this.htmlTag = function (params, selectorParams, tagParam, mainParam) { if (Array.isArray(params)) { for (var index in params) self.htmlTag(params[index], selectorParams, tagParam, mainParam); } else { let htmlTagSplitter = tagParam.indexOf(' '); if (htmlTagSplitter > 0) { let tagClass = tagParam.substr(htmlTagSplitter + 1); tagParam = tagParam.slice(0, htmlTagSplitter); if (tagClass) { if (typeof params !== 'object') params = { 'text': String(params) }; if (!params.attr) params.attr = {}; let tagArr = tagClass.split(' '); var attrClass = ''; for (let tagProp of tagArr) { let tagAttr = new RegExp("([_a-zA-Z]+[_a-zA-Z0-9-]*)=(.+)"); if (tagAttr.test(tagProp)) { let tagPropArr = tagProp.split('='); params.attr[tagPropArr[0]] = tagPropArr[1]; } else { attrClass += ' ' + tagProp; } } if (params.attr.class) params.attr.class = params.attr.class + attrClass; else { params.attr.class = attrClass; } } } let htmlTagObj = self.createTagParams(params, tagParam, mainParam); self.do(htmlTagObj, selectorParams); if (params.database) self.addFirebaseTag(self.extend({}, params, selectorParams)); } }; /* Method: createTagParams Description: Functionality for createTagParams. @param {any} params - Description for params @param {any} tagParam - Description for tagParam @param {any} mainParam - Description for mainParam @returns {any} - Result of the operation */ this.createTagParams = function (params, tagParam, mainParam) { if (!mainParam) { switch (tagParam) { case 'header': case 'main': case 'footer': case 'div': case 'p': mainParam = 'html'; break; case 'img': mainParam = 'src'; break; default: mainParam = 'text'; break; } } var paramsObj = {}; if (typeof params == 'string') paramsObj[mainParam] = params; else paramsObj = params; paramsObj.tag = tagParam; return paramsObj; }; this.onResize = []; this.onHashChange = []; this.onScroll = []; /* Method: notEmptyObject Description: Functionality for notEmptyObject. @param {any} obj - Description for obj @returns {any} - Result of the operation */ this.notEmptyObject = function (obj) { return (obj && Object.keys(obj).length > 0); }; /* Method: run Description: Functionality for run. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.run = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.run(params[index], selectorParams, args); } else { var codeToRun; if (typeof params == 'object') codeToRun = self.cloneObject(params); else if (typeof params == 'string') codeToRun = self.replaceProperties(params); else if (typeof params == 'function') return params(args); else return params; if (typeof codeToRun == 'object') { var selector = codeToRun.selector || codeToRun.container; if (!selector) selector = selectorParams; if (typeof selector == 'string') selector = { selector: selector }; var actions = {}; for (key in codeToRun) { if (nodes.extend.indexOf(key) >= 0) { var obj = {}; obj[key] = codeToRun[key]; self.extendJson(self.json, obj); } else if (['setup', 'container', 'selector', 'resources', 'on', 'do'].indexOf(key) < 0) actions[key] = codeToRun[key]; } if (codeToRun.on) { self.on(codeToRun.on, selector); } if (codeToRun.do) { self.do(codeToRun.do, selector, args); } if (self.notEmptyObject(actions)) { return self.do(actions, selector, args); } } } }; /* Method: inputValue Description: Functionality for inputValue. @param {any} params - Description for params @returns {any} - Result of the operation */ this.inputValue = function (params) { var selector = self.selector(params.selector || params.container); var element = document.querySelector(selector); return element.value; }; this.part = /* Method: block Description: Functionality for block. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.block = function (params, selectorParams, args) { let nested; let part; let partArguments; if (typeof params.do == 'string' && self.json.parts) { self.log('PART: ' + params.do, 'brown'); params.do = self.replaceProperties(params.do); if (typeof params.do == 'object') part = params.do; else part = self.element({ path: self.replaceAll(params.do, ':', '.'), root: self.json.parts }); } else if (typeof params.do == 'object') part = params.do; if (part) { if (params.arguments) partArguments = self.replaceProperties(params.arguments); if (typeof params.arguments == 'object') { partArguments = (params.arguments.setup) ? params.arguments.setup : params.arguments; partArguments.selector = partArguments.selector || params.selector; } nested = self.replacePropertyWithPrefix(part, 'setup', partArguments); nested = self.replacePropertyWithPrefix(nested, 'arguments', partArguments); self.extendJsonFromElement(nested); self.do(nested, params.selector, partArguments); } }; /* Method: blocks Description: Functionality for blocks. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.blocks = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.blocks(params[index], selectorParams, args); } else { if (typeof params == 'string') { var blockName = self.replaceProperties(params, args); var libraryObj = self.element({ path: 'self.json.blocks.' + blockName }); if (libraryObj) self.run(libraryObj, selectorParams, args); else self.log('library component not found: ' + params); } else { self.run(params, selectorParams, args); } } }; /* Method: uiUpdate Description: Functionality for uiUpdate. @param {any} option - Description for option @returns {any} - Result of the operation */ this.uiUpdate = function (option) { window.dispatchEvent(new Event('resize')); }; /* Method: resizeEvent Description: Functionality for resizeEvent. @param {any} event - Description for event @returns {any} - Result of the operation */ this.resizeEvent = function (event) { for (var selector in self.resizeActions) { var element = self.query(selector); for (var property in self.resizeActions[selector]) { if (property == 'action') { self.do(self.resizeActions[element].action, { selector: selector }); } else { var value = self.resizeActions[selector][property]; var result = self.replaceProperties(value) || ''; element.style[property] = result; } } } }; /* Method: pageFullScreen Description: Functionality for pageFullScreen. @param {any} onOff - Description for onOff @returns {any} - Result of the operation */ this.pageFullScreen = function (onOff) { self.log('pageFullScreen'); if (onOff) self.addClass(document.querySelector('body'), 'fullscreen'); else self.removeClass(document.querySelector('body'), 'fullscreen'); }; /* Method: link Description: Functionality for link. @param {any} link - Description for link @param {any} args - Description for args @returns {any} - Result of the operation */ this.link = function (link, args) { link = self.replaceProperties(link, args); window.location.href = link; }; /* Method: reload Description: Functionality for reload. @param {any} - No parameters @returns {any} - Result of the operation */ this.reload = function () { location.reload(); }; /* Method: gotoHomePage Description: Functionality for gotoHomePage. @param {any} - No parameters @returns {any} - Result of the operation */ this.gotoHomePage = function () { self.gotoPage(self.homePage()); }; /* Method: homePage Description: Functionality for homePage. @param {any} - No parameters @returns {any} - Result of the operation */ this.homePage = function () { if (self.json.pages) { if (Object.keys(self.json.pages).length > 0) { if (self.json.pages.home) return 'home'; else return Object.keys(self.json.pages)[0]; } else { self.log('No pages in "pages" node'); } } else { self.log('Can\'t find the "pages" node'); } }; /* Method: updateCodeEditors Description: Functionality for updateCodeEditors. @param {any} - No parameters @returns {any} - Result of the operation */ this.updateCodeEditors = function () { var elements = document.querySelectorAll('.ace_editor'); if (elements) { elements.forEach(function (element, index) { var editor = ace.edit(element); editor.renderer.updateFull(true); }); } }; /* Method: gotoPage Description: Functionality for gotoPage. @param {any} pageId - Description for pageId @param {any} fromHash - Description for fromHash @returns {any} - Result of the operation */ this.gotoPage = function (pageId, fromHash) { self.log('page'); self.log('pageId'); self.log(pageId); self.log('fromHash'); self.log(fromHash); if (pageId) { if (self.json.pages) { if (self.json.pages[pageId]) { var page = self.json.pages[pageId]; if (pageId !== self.json.setup.page.id || fromHash !== self.json.setup.page.hash) { if (fromHash) { self.json.setup.page.hash = fromHash; } else { delete self.json.setup.page.hash; } var fullScreen = self.json.pages[pageId].fullscreen || false; var pageRoles = (page.roles) ? String(page.roles).split(',') : undefined; if (self.params.d || !page.roles || pageRoles.indexOf(self.userRole()) >= 0) { if (pageId !== self.json.setup.page.id) { self.json.setup.page.id = pageId; self.json.setup.page.title = page.title; self.json.setup.page.roles = page.roles; self.hide({ "class": "page" }); self.in({ "class": "page", "data-value": pageId, "transition": "fadeIn" }); self.uiUpdate(); } if (page.update) { self.do(page.update); } if (page.init) self.do(page.init); self.log(page); if (page.on) self.on(page.on, { selector: '.page[data-value=' + pageId + ']' }); } else { if (self.userRole() == 'guest') { } else { self.alert('Non hai i privilegi per accedere a questa pagina'); } } } else { } } else { self.log('Can\'t find the page "' + pageId + '"'); } } else { self.log('Can\'t find the main node "pages"'); } } else { return self.json.setup.page; } }; var alertInterval; /* Method: getTime Description: Functionality for getTime. @param {any} ms - Description for ms @returns {any} - Result of the operation */ this.getTime = function (ms) { var sec = parseInt(ms / 1000); var min = parseInt(sec / 60); sec = sec - min * 60; if (min < 10) min = '0' + min; if (sec < 10) sec = '0' + sec; return min + ':' + sec; }; /* Method: sortablejs Description: Functionality for sortablejs. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.sortablejs = function (params, selectorParams, args) { let container = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); let query = self.query(container); self.log('container'); self.log(container); self.log('query'); self.log(query); var sortable = Sortable.create(query); }; /* Method: alert Description: Functionality for alert. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.alert = function (params, args) { var paramsReplaced = self.cloneObject(params); if (paramsReplaced) { if (paramsReplaced.do && paramsReplaced.do !== 'fire') { return Swal[paramsReplaced.do](params); } else { if (typeof paramsReplaced == 'string') paramsReplaced = self.text({ string: paramsReplaced, args: args }); if (typeof paramsReplaced == 'number') paramsReplaced = String(paramsReplaced); if (paramsReplaced.title !== undefined) paramsReplaced.title = self.text({ string: paramsReplaced.title, args: args }); if (paramsReplaced.html && typeof paramsReplaced.html == 'string') paramsReplaced.html = self.replaceProperties(paramsReplaced.html, args); if (paramsReplaced.text !== undefined) paramsReplaced.text = self.text({ string: paramsReplaced.text, args: args }); if (paramsReplaced.inputValue) paramsReplaced.inputValue = self.text({ string: paramsReplaced.inputValue, args: args }); if (paramsReplaced.cancelButtonText) paramsReplaced.cancelButtonText = self.text({ string: paramsReplaced.cancelButtonText, args: args }); if (paramsReplaced.confirmButtonText) paramsReplaced.confirmButtonText = self.text({ string: paramsReplaced.confirmButtonText, args: args }); if (paramsReplaced.denyButtonText) paramsReplaced.denyButtonText = self.text({ string: paramsReplaced.denyButtonText, args: args }); if (paramsReplaced.inputPlaceholder) paramsReplaced.inputPlaceholder = self.text({ string: paramsReplaced.inputPlaceholder, args: args }); if (paramsReplaced.validationMessage) paramsReplaced.validationMessage = self.text({ string: paramsReplaced.validationMessage, args: args }); if (paramsReplaced.footer) { paramsReplaced.footer = self.text({ string: paramsReplaced.footer, args: args }); } if (paramsReplaced.upload) { paramsReplaced.html = '
' + self.text('dragAndDropFiles') + '
' + self.text('chooseFiles') + '
'; } alertObj.confirm = paramsReplaced.confirm; alertObj.cancel = paramsReplaced.cancel; alertObj.deny = paramsReplaced.deny; alertObj.on = paramsReplaced.on; alertObj.id = paramsReplaced.id; delete paramsReplaced.on; var alertHtml = paramsReplaced.html || paramsReplaced.blocks; if (alertHtml) paramsReplaced.html = " "; var swalParams = self.replaceProperties(paramsReplaced, args); if (paramsReplaced.animate) { var animationIn = paramsReplaced.animate.in || paramsReplaced.animate; var animationOut = paramsReplaced.animate.out || paramsReplaced.animate; if (paramsReplaced.animate.in) animationIn = paramsReplaced.animate.in.transition || paramsReplaced.animate.in; if (paramsReplaced.animate.out) animationOut = paramsReplaced.animate.out.transition || paramsReplaced.animate.out; swalParams.showClass = { popup: 'animate__animated animate__faster animate__animated animate__' + animationIn }; swalParams.hideClass = { popup: 'animate__animated animate__faster animate__animated animate__' + animationOut }; } var customIcon; if (swalParams.icon) { if (typeof swalParams.icon !== 'string') { customIcon = self.cloneObject(swalParams.icon); delete swalParams.icon; } } delete swalParams.blocks; delete swalParams.onUpload; delete swalParams.upload; if (swalParams.confirm) delete swalParams.confirm; if (swalParams.cancel) delete swalParams.cancel; if (swalParams.timerProgressBar) { swalParams.onBeforeOpen = function () { alertInterval = setInterval(() => { const content = Swal.getContent(); if (content) { const b = content.querySelector('b'); if (b) { b.textContent = self.getTime(Swal.getTimerLeft()); } } }, 100); }; swalParams.onClose = function () { clearInterval(alertInterval); }; } Swal.fire(swalParams).then((result) => { var alertResult = result.value; if (alertObj.on) { if (alertObj.on.value && result.value) { if (alertObj.id) alertValues[alertObj.id] = result.value; alertValues.value = result.value; setTimeout(function () { alertObj.on.value = self.replacePropertyWithPrefix(alertObj.on.value, 'alert', alertValues); self.do(alertObj.on.value, undefined, result.value); }, 500); } if (alertObj.on.isConfirmed && result.isConfirmed) { if (alertObj.id) alertValues[alertObj.id] = result.isConfirmed; alertObj.on.isConfirmed = self.replacePropertyWithPrefix(alertObj.on.isConfirmed, 'alert', alertValues); alertObj.on.isConfirmed = self.replacePropertyWithPrefix(alertObj.on.isConfirmed, 'alert', result); self.do(alertObj.on.isConfirmed, undefined, result.value); } if (alertObj.on.isDenied && result.isDenied) { alertObj.on.isDenied = self.replacePropertyWithPrefix(alertObj.on.isDenied, 'alert', result); self.do(alertObj.on.isDenied, undefined, result.value); } if (alertObj.on.isDismissed && result.isDismissed) { alertObj.on.isDismissed = self.replacePropertyWithPrefix(alertObj.on.isDismissed, 'alert', result); self.do(alertObj.on.isDismissed, undefined, result.dismiss); } console.log('alertValues'); console.log(alertValues); } else { } }); if (alertHtml) self.do(alertHtml, { selector: '#swal2-html-container' }); if (customIcon) { self.do(customIcon, { selector: '.swal2-icon' }); self.css({ selector: '.swal2-icon', style: { 'border': '0px solid transparent' } }); self.show({ selector: '.swal2-icon' }); } if (swalParams.on && swalParams.on.init) self.do(swalParams.on.init); } } }; /* Method: findKey Description: Functionality for findKey. @param {any} obj - Description for obj @param {any} key - Description for key @returns {any} - Result of the operation */ this.findKey = function (obj, key) { return obj.filter(function (item) { return Boolean(item[key]); }); }; /* Method: formatBytes Description: Functionality for formatBytes. @param {any} bytes - Description for bytes @param {any} decimals - Description for decimals @returns {any} - Result of the operation */ var formatBytes = function (bytes, decimals) { if (bytes == 0) return '0 Byte'; var k = 1000; var dm = decimals + 1 || 3; var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']; var i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i]; }; /* Method: userRole Description: Functionality for userRole. @param {any} - No parameters @returns {any} - Result of the operation */ this.userRole = function () { switch (Boolean(self.user('uid'))) { case true: return 'user'; break; case false: return 'guest'; break; } }; /* Method: userIn Description: Functionality for userIn. @param {any} - No parameters @returns {any} - Result of the operation */ this.userIn = function () { return Boolean(self.user('uid')); }; /* Method: userOut Description: Functionality for userOut. @param {any} - No parameters @returns {any} - Result of the operation */ this.userOut = function () { return (!self.user('uid')); }; /* Method: user Description: Functionality for user. @param {any} param - Description for param @returns {any} - Result of the operation */ this.user = function (param) { if (auth && auth.currentUser) if (param == 'firstName') return self.firstName(auth.currentUser['displayName']); else if (auth.currentUser[param]) return auth.currentUser[param]; else if (!param) return auth.currentUser; else return undefined; else return undefined; }; /* Method: firstName Description: Functionality for firstName. @param {any} nameParam - Description for nameParam @returns {any} - Result of the operation */ this.firstName = function (nameParam) { var firstNameStr = (nameParam) ? nameParam.split(' ')[0] : ''; return firstNameStr; }; /* Method: userUid Description: Functionality for userUid. @param {any} - No parameters @returns {any} - Result of the operation */ this.userUid = function () { if (auth) return auth.currentUser.uid; else return undefined; }; /* Method: userVerified Description: Functionality for userVerified. @param {any} - No parameters @returns {any} - Result of the operation */ this.userVerified = function () { if (auth) return auth.currentUser.emailVerified; else return undefined; }; /* Method: thunkableMessage Description: Functionality for thunkableMessage. @param {any} message - Description for message @param {any} callback - Description for callback @returns {any} - Result of the operation */ this.thunkableMessage = function (message, callback) { if (callback) callback(message); }; this.onMessage = { alert: "test" }; /* Method: processMessage Description: Functionality for processMessage. @param {any} message - Description for message @returns {any} - Result of the operation */ this.processMessage = function (message) { self.alert('processMessage'); self.do(self.onMessage, message); }; /* Method: thunkable Description: Functionality for thunkable. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.thunkable = function (params, args) { if (params.postMessage) { var message = self.replaceProperties(params.postMessage, args); if (message) { try { ThunkableWebviewerExtension.postMessage(message); } catch (error) { } } else self.log('in function "thunkable" "postMessage" parameter is wrong'); } if (params.receiveMessage) { self.onMessage = params.receiveMessage; try { ThunkableWebviewerExtension.receiveMessage(self.processMessage); } catch (error) { } } }; /* Method: extendFunctions Description: Functionality for extendFunctions. @param {any} functions - Description for functions @returns {any} - Result of the operation */ this.extendFunctions = function (functions) { for (var name in functions) { if (functions[name].js) { try { self.functions[name] = new Function(functions[name].js); } catch (error) { console.log('ERROR creating function %c' + name, 'color:orange;'); self.log(functions[name].js); self.log(error.message); } } else { self.log(name + ' function requires js property'); } } }; /* Method: function Description: Functionality for function. @param {any} obj - Description for obj @param {any} args - Description for args @returns {any} - Result of the operation */ this.function = function (obj, args) { if (obj.name && obj.js) { self.functions[obj.name] = new Function(obj.js); } else if (obj.name && !obj.js) { if (self.functions[obj.name]) { if (!obj.arguments || !Array.isArray(obj.arguments)) obj.arguments = [obj.arguments]; try { return self.functions[obj.name](...obj.arguments); } catch (error) { console.log('ERROR in function %c' + obj.name, 'color:orange;'); console.log('obj'); console.log(obj); console.log('function'); console.log(self.json.functions[obj.name]); console.log(error.message); } } else { console.log('ERROR function undefined %c' + obj.name, 'color:orange;'); } } else if (obj.js) { if (obj.arguments && Array.isArray(obj.arguments)) { return new Function(obj.js).call(null, obj.arguments); } else { return new Function(obj.js).call(null, obj.arguments); } } }; this.eval = /* Method: js Description: Functionality for js. @param {any} code - Description for code @param {any} args - Description for args @returns {any} - Result of the operation */ this.js = function (code, args) { code = self.replaceProperties(code, args); try { return eval(code); } catch (error) { return code; } }; /* Method: if Description: Functionality for if. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.if = function (params, selectorParams, args) { if (typeof params == 'object') { var conditionString = 'if'; var condition; if (params.is !== undefined) { if (typeof params.is == 'string') { let isReplaced = self.replaceProperties(params.is, args, true); self.log(isReplaced, 'grey'); try { condition = Boolean(eval(isReplaced)); self.log(isReplaced + ' is ' + condition, 'grey'); } catch (error) { self.log(isReplaced, 'red'); self.log('"if" condition wrong', 'red'); self.log(error, 'red'); } conditionString += ' is ' + params.is; } else if (Array.isArray(params.is)) { let i = 0; params.is[i]; switch (params.is[i + 1]) { case '=': condition = Boolean(eval(params.is[i] + '===' + params.is[i + 2])); break; } } } else if (params.not !== undefined) { condition = (!Boolean(eval(self.replaceProperties(params.not, args, true)))); if (typeof params.not == 'string') conditionString += ' not ' + params.not; } else if (params.regexp) { const regex = new RegExp(params.regexp); condition = Boolean(regex.test(params.string)); } else if (params.isArray) { condition = self.isArray(params.isArray); conditionString += 'isArray ' + params.isArray; } else if (params.exist) { let elementExist = self.element({ path: params.exist }); condition = (elementExist); self.log('"if" exist ' + params.exist, 'grey'); } else if (params.value && params.in) { condition = self.valueInJson(self.replaceProperties(params.in, args, true), self.replaceProperties(params.value)); self.log('"if" value ' + self.replaceProperties(params.value) + ' in array is ' + condition, 'grey'); } else if (params.key && params.in) { condition = self.keyInJson(self.replaceProperties(params.in, args, true), self.replaceProperties(params.key)); self.log('"if" key ' + self.replaceProperties(params.key) + ' in object is ' + condition, 'grey'); } else { let selector = self.selector(params.selector || params.container, undefined) || self.selector(selectorParams, undefined); if (selector) { if (params.exist) { condition = Boolean(self.exist(selector)); conditionString += ' ' + selector + ' exist ' + params.exist; } if (params.hasClass) { var element = self.query(selector); condition = Boolean(self.hasClass(element, params.hasClass)); conditionString += ' ' + selector + ' hasClass ' + params.hasClass; } if (params.isVisible) { var element = self.query(selector); condition = Boolean(self.isVisible(element, params.isVisible)); conditionString += ' ' + selector + ' isVisible'; } if (params.isHidden) { var element = self.query(selector); condition = Boolean(self.isHidden(element, params.isHidden)); conditionString += ' ' + selector + ' isHidden'; } if (params.inViewport) { var element = self.query(selector); condition = Boolean(self.inViewport(element, params.inViewport)); conditionString += ' ' + selector + ' inViewport'; } if (params.outViewport) { var element = self.query(selector); condition = Boolean(self.outViewport(element, params.outViewport)); conditionString += ' ' + selector + ' outViewport'; } if (params.isDisplay) { var element = self.query(selector); condition = Boolean(self.isDisplay(element, params.isDisplay)); conditionString += ' ' + selector + ' isDisplay ' + params.isDisplay; } } else { self.log('the "if" function requires "is" or "not" parameter'); } } if (condition) if (params.then) { if (typeof params.then == 'object') { return self.do(params.then); } if (typeof params.then == 'string') { return self.replaceProperties(params.then); } else { return params.then; } } else self.log('the "if" function requires "then" parameter'); else if (params.else) { if (typeof params.else == 'object') { return self.do(params.else); } if (typeof params.else == 'string') { return self.replaceProperties(params.else); } else { return params.else; } } } else { return Boolean(self.js(params, args)); } }; /* Method: switch Description: Functionality for switch. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.switch = function (params, args) { var value; var answer; if (params.expression) value = String(self.js(params.expression, args)); else self.log('"switch" function requires "expression" parameter'); if (params.cases) { if (value !== undefined && params.cases[value]) { if (typeof params.cases[value] == 'object') answer = self.do(params.cases[value], undefined, args); else answer = params.cases[value]; } else if (params.cases['default']) { self.log('default'); self.log(params.cases['default']); if (typeof params.cases['default'] == 'object') answer = self.do(params.cases['default'], undefined, args); else answer = params.cases['default']; } } else { self.log('"switch" function requires "cases" parameter'); self.log('answer'); self.log(answer); } return answer; }; /* Method: delay Description: Functionality for delay. @param {any} params - Description for params @param {any} selector - Description for selector @param {any} args - Description for args @returns {any} - Result of the operation */ this.delay = function (params, selector, args) { self.log('delay'); self.log('selector'); self.log(selector); var duration = params.duration || 1000; duration = Number(self.replaceProperties(duration, args)); self.log(duration); if (params.do) { setTimeout(function () { self.do(params.do, selector, args); }, duration); } }; /* Method: firebasePasswordReset Description: Functionality for firebasePasswordReset. @param {any} paramEmail - Description for paramEmail @param {any} paramSuccess - Description for paramSuccess @param {any} paramError - Description for paramError @returns {any} - Result of the operation */ this.firebasePasswordReset = function (paramEmail, paramSuccess, paramError) { firebase.auth().useDeviceLanguage(); auth.sendPasswordResetEmail(paramEmail).then(function () { if (paramSuccess) self.do(paramSuccess); }).catch(function (error) { if (paramError) self.do(paramError, undefined, error.message); }); }; /* Method: firebaseUpdateProfile Description: Functionality for firebaseUpdateProfile. @param {any} params - Description for params @param {any} paramSuccess - Description for paramSuccess @param {any} paramError - Description for paramError @returns {any} - Result of the operation */ this.firebaseUpdateProfile = function (params, paramSuccess, paramError) { self.log('firebaseUpdateProfile'); self.log(params); auth.currentUser.updateProfile(params).then(function () { self.log('User Profile Updated Successfully'); if (paramSuccess) self.do(paramSuccess); }).catch(function (error) { if (paramError) self.do(paramError, undefined, error.message); }); }; /* Method: firebaseRegister Description: Functionality for firebaseRegister. @param {any} params - Description for params @param {any} success - Description for success @param {any} error - Description for error @returns {any} - Result of the operation */ this.firebaseRegister = function (params, success, error) { if (params.email && params.password) { auth.createUserWithEmailAndPassword(params.email, params.password).then(cred => { self.log(cred.user); var user = firebase.auth().currentUser; if (params.success) self.do(params.success); }).catch(error => { if (params.error) self.do(params.error, undefined, error.message); }); } }; /* Method: firebaseLogin Description: Functionality for firebaseLogin. @param {any} params - Description for params @returns {any} - Result of the operation */ this.firebaseLogin = function (params) { self.log('firebaseLogin'); self.log(params); if (auth) { auth.signInWithEmailAndPassword(String(params.email), String(params.password)).then(cred => { var user = firebase.auth().currentUser; if (user.emailVerified) { if (params.success) self.do(self.replaceResult(params, undefined, cred)); } else { self.sendEmailVerification(params); } }).catch(error => { self.log('error.code'); self.log(error.code); if (params.error) self.do(self.replaceResult(params, undefined, error.message)); }); } else { } }; /* Method: firebaseLogout Description: Functionality for firebaseLogout. @param {any} params - Description for params @returns {any} - Result of the operation */ this.firebaseLogout = function (params) { self.log('firebaseLogout'); firebase.auth().signOut().then(function () { self.log('firebaseLogout SUCCESS'); self.log(params.success); if (params.success) { localStorage.clear(); self.do(params.success); } }).catch(function (error) { self.log('firebaseLogout ERROR'); self.log(error); if (params.error) self.do(params.error); }); }; /* Method: sendEmailVerification Description: Functionality for sendEmailVerification. @param {any} params - Description for params @returns {any} - Result of the operation */ this.sendEmailVerification = function (params) { self.log('sendEmailVerification'); var user = firebase.auth().currentUser; firebase.auth().languageCode = 'it'; var successAction = params.success || self.reload; user.sendEmailVerification().then(function () { firebase.auth().signOut(); self.alert({ icon: "success", title: "verifyingemail", html: "msgverifyingemail", showConfirmButton: false, confirm: successAction }); }); }; /* Method: path Description: Functionality for path. @param {any} pathParams - Description for pathParams @param {any} args - Description for args @param {any} separatorParam - Description for separatorParam @returns {any} - Result of the operation */ this.path = function (pathParams, args, separatorParam) { var pathString = ''; var separator = separatorParam || '/'; if (typeof pathParams == 'string') { pathString = self.replaceProperties(pathParams, args); } else { for (var index in pathParams) { pathObj = pathParams[index]; if (pathString !== '') pathString += separator; if (pathObj.string) pathString += String(pathObj.string); else if (pathObj.number) pathString += Number(pathObj.number); else if (pathObj.function) pathString += self.doFunctionByName(pathObj.function, window, ''); } } return pathString; }; /* Method: executeFunctionByName Description: Functionality for executeFunctionByName. @param {any} functionName - Description for functionName @param {any} context - Description for context @returns {any} - Result of the operation */ this.executeFunctionByName = function (functionName, context ) { if (functionName) { var args = [].slice.call(arguments).splice(2); var namespaces = functionName.split("."); var func = namespaces.pop(); for (var i = 0; i < namespaces.length; i++) { context = context[namespaces[i]]; } if (context[func] !== undefined) { return context[func].apply(context, args); } else { } } else { self.log('executeFunctionByName'); self.log('functionName undefined'); } }; this.functions = {}; this.methods = { run: function (params, container, args) { self.run(params, container, args); }, delay: function (params, container, args) { self.delay(params, container, args); }, ajax: function (params, container, args) { self.ajax(params, container, args); }, do: function (params, container, args) { self.do(params, container, args); }, module: function (params, container, args) { self.module(params, args); }, js: function (params, container, args) { self.js(params, args); }, function: function (params, container, args) { self.function(params, args); }, dispatchEvent: function (params, container, args) { self.dispatchEvent(params, args); }, lang: function (params, container, args) { self.lang(params, args); }, find: function (params, container, args) { self.find(params, args); }, page: function (params, container, args) { self.page(params, args); }, for: function (params, container, args) { self.for(params, container, args); }, if: function (params, container, args) { self.if(params, container, args); }, switch: function (params, container, args) { self.switch(params, args); }, set: function (params, container, args) { self.set(params, args); }, data: { set: function (params, args) { for (var param in params) { var value = params[param]; if (value) value = self.replaceProperties(value, args); if (value && args) value = self.replacePropertyWithPrefix(value, 'result', args); self.element({ path: param, value: value }); } }, get: function (params) { return self.element(params); }, delete: function (params, args) { var path = self.replaceProperties(params, args); alert(path); self.objToDelete = self.element({ path: path }); delete self.objToDelete; }, add: function (params, args) { for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || ''; obj += String(value); self.element({ path: path, value: obj }); } } }, sum: function (params, args) { console.log('%cdeprecated key "sum". Use set{x: "{x}+1"}', 'color:orange'); console.log(params); console.log(args); for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || 0; obj += Number(value); self.element({ path: path, value: obj }); } } }, sub: function (params, args) { console.log('%cdeprecated key "sub". Use set{x: "{x}+1"}', 'color:orange'); console.log(params); console.log(args); for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || 0; obj -= Number(value); self.element({ path: path, value: obj }); } } }, push: function (params, args) { for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || []; obj.push(value); self.element({ path: path, value: obj }); } } } }, text: function (params, container, args) { self.text(params, container, args); }, html: function (params, container, args) { self.html(params, container, args); }, attr: function (params, container, args) { self.attr(params, container, args); }, empty: function (params, container, args) { self.empty(params, args); }, delete: function (params, args) { var path = self.replaceProperties(params, args); var obj = self.element({ path: path }); self.log(JSON.stringify(obj)); self.element({ path: path, delete: true }); self.log(obj); }, add: function (params, container, args) { for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || ''; obj += String(value); self.element({ path: path, value: obj }); } } }, sum: function (params, container, args) { for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || 0; obj += Number(value); self.element({ path: path, value: obj }); } } }, sub: function (params, container, args) { for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || 0; obj -= Number(value); self.element({ path: path, value: obj }); } } }, push: function (params, container, args) { for (var param in params) { var path = self.replaceProperties(param, args); var value = self.replaceProperties(params[param], args); if (value) { var obj = self.element({ path: path }) || []; obj.push(value); self.element({ path: path, value: obj }); self.log('push obj'); self.log(obj); } } }, calendar: function (params, container, args) { self.calendar(params, args); }, array: function (params, container, args) { self.array(params, args); }, replace: function (params, container, args) { self.replace(params, args); }, shuffle: function (array) { let currentIndex = array.length, randomIndex; while (currentIndex != 0) { randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; [array[currentIndex], array[randomIndex]] = [ array[randomIndex], array[currentIndex] ]; } return array; }, alert: function (params, container, args) { self.alert(params, args); }, offcanvas: function (params, container, args) { self.offcanvas(params, args); }, out: function (params, container, args) { self.out(params, container, args); }, qrcode: function (params, container, args) { self.qrcode(params, container, args); }, hide: function (params, container, args) { self.hide(params, container, args); }, show: function (params, container, args) { self.show(params, container, args); }, toggle: function (params, container, args) { self.toggle(params, container, args); }, sortablejs: function (params, container, args) { self.sortablejs(params, args); }, lottie: function (params, container, args) { self.lottie(params, container, args); }, chart: function (params, container, args) { var selector = self.selector(container); var element = self.query(selector); element.innerHTML = ''; const ctx = element.querySelector('canvas'); const myChart = new Chart(ctx, self.replaceProperties(params)); }, animate: function (params, container, args) { self.animate(params, container, args); }, uiUpdate: function (params, container, args) { self.uiUpdate(params, args); }, swiper: { data: {}, init: function (params, selector, args) { setTimeout(function () { console.log('swiper inited'); console.log(selector || params.selector); console.log(params.options); var swiperConfig = params.options; self.methods.swiper.data[params.name] = new Swiper(self.selector(selector || params.selector), swiperConfig); console.log(self.methods.swiper.data[params.name]); }, 1000); } }, link: function (params, container, args) { self.link(params, args); }, scroll: function (params, container, args) { self.scroll(params, args); }, reload: function (params, container, args) { self.reload(params, args); }, timer: function (params, container, args) { self.timer(params, args); }, setInterval: function (params, container, args) { self.setInterval(params, args); }, clearInterval: function (params, container, args) { self.clearInterval(params, args); }, setTimeout: function (params, container, args) { self.setTimeout(params, args); }, clearTimeout: function (params, container, args) { self.clearTimeout(params, args); }, local: { set: function (params) { for (var param in params) { var value = params[param]; if (value) value = self.replaceProperties(value); if (typeof value == 'object') value = JSON.stringify(value); localStorage.setItem(param, value); } }, get: function (key) { var localValue = localStorage.getItem(key); if (localValue && self.isJsonString(localValue)) localValue = JSON.parse(localValue); return localValue; }, remove: function (key) { localStorage.removeItem(key); }, clear: function () { localStorage.clear(); } }, storage: { _storage: new WeakMap(), set: function (element, key, obj) { if (!self.methods.storage._storage.has(element)) { self.methods.storage._storage.set(element, new Map()); } self.methods.storage._storage.get(element).set(key, obj); }, get: function (element, key) { return self.methods.storage._storage.get(element).get(key); }, has: function (element, key) { return self.methods.storage._storage.has(element) && self.methods.storage._storage.get(element).has(key); }, remove: function (element, key) { var ret = self.methods.storage._storage.get(element).delete(key); if (!self.methods.storage._storage.get(element).size === 0) { self.methods.storage._storage.delete(element); } return ret; } }, choose: function (params, container, args) { self.choose(params, container, args); }, remove: function (params, container, args) { self.remove(params, container, args); }, part: function (params, container, args) { self.part(params, container, args); }, blocks: function (params, container, args) { self.part(params, container, args); }, block: function (params, container, args) { self.part(params, container, args); }, ace: function (params, container, args) { self.ace(params, container, args); }, code: function (params, container, args) { self.code(params, container, args); }, database: function (params, container, args) { self.database(params, args); }, firebase: function (params, container, args) { self.firebase(params, args); }, firebaseEvent: { action: function (newObj) { var path = newObj.path; delete newObj.path; document.querySelectorAll('[data-firebase="' + path + '"]').forEach(function (element, index) { var pathString = 'self.json.var.db.' + self.replaceAll(element.getAttribute('data-firebase'), '/', '.'); var dbObj = self.docElement(pathString); var firebaseValue = newObj[element.getAttribute('data-value')]; var template = self.dataStorage.get(element, 'data-template'); if (element.tagName == 'UL') { var liTemplate = template.li || template.template; element.innerHTML = ''; var items = newObj; for (itemKey in items) { var item = items[itemKey]; item.key = itemKey; var dbParams = self.replaceItems(liTemplate, item, 'item') || ''; var container = element.getAttribute('data-selector'); self.li(dbParams, { selector: container }); } } else if (element.tagName == 'SPAN' || element.tagName == 'P') { element.textContent = firebaseValue; } else if (element.tagName == 'SVG') { } else { if (template.blocks || template.html) { var blocksTemplate = template.html || template.blocks; element.innerHTML = ''; var items = newObj; self.log('newObj'); self.log(newObj); for (itemKey in items) { var item = items[itemKey]; item.key = itemKey; var dbParams = self.replaceProperties(blocksTemplate, undefined, item) || ''; self.html(dbParams, { selector: container }); } } if (template.init) self.do(template.init); } }); } }, auth: { init: function (params, container, args) { self.log("auth init"); auth = firebase.auth(); auth.onAuthStateChanged(user => { self.json.var.user = user; if (!user) { self.log('authStateChanged: GUEST\n'); } else { self.log('authStateChanged: USER\n'); self.log('name: ' + self.user('displayName') + '\nemail: ' + user.email + '\nuid:' + user.uid); } self.do(params.onAuthStateChanged); }); }, sendEmailVerification: function (params, container, args) { self.sendEmailVerification(params); }, login: function (params, container, args) { self.log('params.auth'); self.log(params.auth); self.log(args); var fba = self.replaceProperties(params.auth, args); self.log('fba'); self.log(fba); var fbAuth = self.cloneObject(fba); self.log('fbAuth'); self.log(fbAuth); if (params.success) fbAuth.success = params.success; if (params.error) fbAuth.error = params.error; self.firebaseLogin(fbAuth, params.success, params.error); }, register: function (params, container, args) { var fbAuth = self.replaceProperties(params.auth, args); fbAuth.success = params.success; fbAuth.error = params.error; self.firebaseRegister(fbAuth, params.success, params.error); }, updateProfile: function (params, container, args) { params.profile = self.replaceProperties(params.profile, args); self.firebaseUpdateProfile(params.profile, params.success, params.error); }, passwordReset: function (params, container, args) { params.email = self.replaceProperties(params.email, args); self.firebasePasswordReset(params.email, params.success, params.error); }, logout: function (params, container, args) { self.firebaseLogout(params); } }, thunkable: function (params, container, args) { self.thunkable(params, args); }, modelViewer: { events: {}, on: function (params) { let container = self.selector(params.selector || params.container); let element = self.query(container); self.log('modelViewer on'); self.log('container'); self.log(container); self.log('element'); self.log(element); if (element) { self.methods.modelViewer.events[container] = {}; var event = 'load'; if (params[event]) { self.methods.modelViewer.events[container][event] = params[event]; self.log('modelViewer element'); self.log(element); element.addEventListener(event, (e) => { self.log('modelViewer event'); self.log(e); let container = e.path[0].getAttribute('data-selector'); self.log(container); self.do(self.methods.modelViewer.events[container][e.type]); }); } } }, set: function (params) { let element = self.query(self.selector(params.selector || params.container)); if (element) { if (params.color) { let color = params.color.split(',').map(numberString => parseFloat(numberString)); self.log('Changing color to: ', color); const [material] = element.model.materials; material.pbrMetallicRoughness.setBaseColorFactor(color); } if (params.exposure) element.exposure = params.exposure; if (params.shadow) element.shadowIntensity = params.shadow; if (params.orientation) element.orientation = params.orientation; } } } }; /* Method: googleSignInPopup Description: Functionality for googleSignInPopup. @param {any} - No parameters @returns {any} - Result of the operation */ this.googleSignInPopup = function () { self.log('googleSignInPopup'); var provider = new firebase.auth.GoogleAuthProvider(); firebase.auth().useDeviceLanguage(); firebase.auth() .signInWithPopup(provider) .then((result) => { var credential = result.credential; var token = credential.accessToken; var user = result.user; window.location.reload(); }).catch((error) => { var errorCode = error.code; var errorMessage = error.message; var email = error.email; var credential = error.credential; }); }; /* Method: console Description: Functionality for console. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.console = function (params, args) { if (typeof params.log == 'string' && params.color) { var color = params.color || 'white'; console.log('%c' + self.replaceProperties(params.log), 'color:' + color); } else { console.log(self.replaceProperties(params.log || params)); } }; /* Method: module Description: Functionality for module. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.module = function (params, args) { if (typeof params == 'string') { var nameReplaced = self.replaceProperties(params, args); return self.element({ root: self.modules, path: nameReplaced }); } else { if (params.name) { if (params.value) { var name = self.replaceProperties(params.name, args); var value = self.replaceProperties(value, args); self.log('module'); self.log(name); self.log('value'); self.log(value); self.log(value.app.html.div.div[0].text.lang.en); self.modules[name] = value; } else if (params.url) { self.addModule(params); } } } }; /* Method: db Description: Functionality for db. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.db = function (params, args) { self.log('db'); if (typeof params == 'string') { var paramsReplaced = self.replaceProperties(params, args); self.log('paramsReplaced'); self.log(paramsReplaced); self.log(self.var('db.' + paramsReplaced, args)); return self.var('db.' + paramsReplaced, args); } }; /* Method: firebase Description: Functionality for firebase. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.firebase = function (params, args) { if (params.initializeApp) { var firebaseConfig = self.replaceProperties(params.initializeApp); firebase.initializeApp(firebaseConfig); } else { self.database(params, args); } }; /* Method: database Description: Functionality for database. @param {any} params - Description for params @param {any} args - Description for args @returns {any} - Result of the operation */ this.database = function (params, args) { if (params.do == 'init') { database = firebase.database(); self.log('database'); self.log(database); } else { if (database) { if (typeof params == 'string') { return self.db(params, args); } else { if (params) { if (params.path) { params.path = self.path(params.path, args); } if (params.value) { params.value = self.replaceProperties(params.value, args); self.log("params.value post replace"); self.log(params.value); } if (params.do == 'init') { } else if (params.do == 'increase') { self.firebaseIncrease(params); } else if (params.do == 'get') { self.firebaseGet(params.path, function (result) { if (result.success) { if (result.data) { self.log('firebase get SUCCESS'); self.log(params.success); if (params.on && params.on.success) self.do(params.on.success, undefined, result); } else { self.log('firebase get no result.data ERROR'); if (params.on && params.on.error) self.do(params.on.error); } } else { self.log('firebase get ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); } else if (params.do == 'new' && params.value) { var newKey = self.getKey(params.path); self.firebaseSet(params.path + '/' + newKey, params.value, function (result) { if (result.success) { self.log('firebase set SUCCESS'); if (params.on && params.on.success) self.do(params.on.success, undefined, result); } else { self.log('firebase set ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); } else if (params.do == 'remove' && params.path) { self.firebaseRemove(params.path, function (result) { if (result.success) { self.log('firebase set SUCCESS'); if (params.on && params.on.success) self.do(params.on.success, undefined, result); } else { self.log('firebase set ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); } else if (params.do == 'addListener') { self.firebaseAddListener(params); } else if (params.do == 'removeListener') { self.firebaseRemoveListener(params); } else if (params.do == 'update') { if (params.value) { self.firebaseUpdate(params.path, params.value, function (result) { if (result.success) { self.log('firebase update SUCCESS'); if (params.on && params.on.success) self.do(params.on.success, undefined, result); } else { self.log('firebase update ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); } else { self.log('data update requires value param'); } } else if (params.do == 'push') { if (params.value) { self.firebasePush(params.path, params.value, function (result) { if (result.success) { self.log('firebase push SUCCESS'); if (params.on && params.on.success) self.do(params.on.success, undefined, result); } else { self.log('firebase push ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); } else { self.log('data push requires value param'); } } else { if (params.value) { self.firebaseSet(params.path, params.value, function (result) { if (result.success) { self.log('firebase set SUCCESS'); if (params.on && params.on.success) self.do(params.on.success, undefined, result); } else { self.log('firebase set ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); } }); } } } } } else { self.log('"database" function needs to be initialised'); } } }; /* Method: ajax Description: Functionality for ajax. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @param {any} args - Description for args @returns {any} - Result of the operation */ this.ajax = function (params, selectorParams, args) { if (params.url) { var url = self.replaceProperties(params.url, args); var data; if (params.data) data = JSON.stringify(self.replaceProperties(params.data, args)); var type = params.type || 'POST'; var request = new XMLHttpRequest(); request.open(type, url, true); request.onload = function () { self.log('onload'); self.log(this); if (this.status >= 200 && this.status < 400) { var result = {}; var response = this.response; response = response.replace(/(\\\")/g, '"'); try { response = decodeURI(response); } catch (error) { /* console.log('response'); console.log(response); */ console.log('decodeURI error'); console.log(error); } result.response = self.parse(response); result.status = this.status; result.header = this.getAllResponseHeaders().split('\r\n').reduce((resultHeader, current) => { let [name, value] = current.split(': '); resultHeader[name] = value; return resultHeader; }, {}); //} catch (e) { //} self.log('result'); self.log(result); if (params.success) self.do(params.success, undefined, result); //self.do(params.success, result); //self.do(self.replaceProperty(params.success, 'result', result), result); } else { // We reached our target server, but it returned an error if (params.error) self.do(params.error, undefined, 'Server error'); //self.do(params.error, 'Server error'); } }; request.onerror = function (error) { // There was a connection error of some sort self.log('error'); self.log(error); self.log('this'); self.log(this); if (params.error) self.do(params.error, undefined, 'Server unavailable'); //self.do(params.error, 'Server unavailable'); }; //request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8'); if (data) request.send(data); else request.send(); } else { self.log('ajax method requires url parameter'); } /* $.ajax({ url: paramsReplaced.url, type: params.type || 'post', //dataType: 'json', // questo dovrebbe evitare JSON.parse //dataType: 'text', // verificare se necessario data: paramsReplaced.data || {}, success: function (result) { self.log('ajax'); self.log('result'); self.log(result); self.do(params.success, result); //self.do(data); // in .params dovrebbe andare il resto }, error: function (error) { var errorText = error.responseText || error; self.do(params.error, errorText); //self.do(data); // in .params dovrebbe andare il resto } }); */ }; /* View in fullscreen */ /* Method: openFullscreen Description: Functionality for openFullscreen. @param {any} id - Description for id @returns {any} - Result of the operation */ this.openFullscreen = function (id) { var element = document.getElementById(id); if (screenfull.isEnabled) { screenfull.request(element); } }; /* /* Method: addListener Description: Functionality for addListener. @param {any} params - Description for params @returns {any} - Result of the operation */ this.addListener = function(params) { var selector = self.selector(params); if (selector) $(selector).on(params.event, self.do(params.action)); //event.stopPropagation(); } */ /* Close fullscreen */ /* Method: closeFullscreen Description: Functionality for closeFullscreen. @param {any} - No parameters @returns {any} - Result of the operation */ this.closeFullscreen = function () { //document.exitFullscreen(); screenfull.off('change'); // callback }; /* /* Method: list Description: Functionality for list. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @returns {any} - Result of the operation */ this.list = function (params, selectorParams) { var container = (selectorParams) ? self.selector(selectorParams) : params.container; var selector = self.selector(self.extend({}, params, selectorParams)); if (selector) { if (params.list) params.items = params.list; // retro-compatibilità if (params.listAction) $(selector).data('listAction', params.listAction); if (params.listClass) $(selector).data('listClass', params.listClass); // ul if (params.items) { $(selector).empty(); var index = 0; //params.items = self.replaceTags({text:params.items, args:selectorParams}); //params.items = self.replaceResult(params.items, selectorParams); params.items = self.replaceProperties(params.items, selectorParams); for (var itemKey in params.items) { // da rimuovere id="item'+itemKey+'" href="" //self.log('PARAMETRI'); //self.log(itemKey); //self.log(params.items); $(selector).append('
  • '); var item = params.items[itemKey]; //var itemSelector = selector + ' li:eq(' + index + ')'; var itemSelector = selector + ' li:eq(' + itemKey + ')'; // Item action var itemAction; if (item.action) itemAction = item.action; else if (params.action) itemAction = params.action; else if ($(selector).data('listAction')) itemAction = $(selector).data('listAction'); item.action = itemAction; if (item.action) { $(itemSelector).addClass('list-group-item-action'); $(itemSelector).css('cursor', 'pointer'); } if (item.color) $(itemSelector).css('color', item.color); if (item.background) $(itemSelector).css('background', item.background); //$(itemSelector).append('
    '); var itemFields = params.items[itemKey].fields || params.items[itemKey]; // retro-compatibilità //self.log('itemFields'); //self.log(itemFields); for (var itemField in itemFields) { var field = itemFields[itemField]; //self.log(field); if (itemField == 'icons') { self.icons(field, {container: itemSelector}); } else if ((itemField != 'params') && (itemField != 'action')) { // retro-compatibilità $(itemSelector).append(''+self.text(itemFields[itemField])+''); } } // action if (item.action) { $(itemSelector).data('onData', item); $(itemSelector).on(self.touch, function (event) { event.stopPropagation(); self.onEvent(this, event); }); } // events if (item.on) self.on(item.on, {container: selector}); index++; } } else if (params.append) { // aggiunge una riga alla fine (calcolare path) } else if (params.prepend) { // aggiunge una riga all'inizio (calcolare path) // sballa tutti i dati presenti in var.functions // sarebbe meglio mem in data value tutto il json // azione } // List classes //if (params.id) $(selector).attr('id', params.id); var listClass = $(selector).data('listClass'); if (listClass) { var ulClass = listClass.ul || ''; var liClass = listClass.li || ''; $(selector).addClass(ulClass); $(selector + ' > li').addClass(liClass); var index = 0; for (var field in listClass.fields) { var fieldClass = listClass.fields[field] || ''; $(selector + ' > li > span[data-field='+field+']').addClass(fieldClass); index++; } } } } */ /* Method: scroll Description: Functionality for scroll. @param {any} params - Description for params @returns {any} - Result of the operation */ this.scroll = function (params) { // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView // {id, class, value} var selector = self.selector(params.selector || params.container); var block = document.querySelector(selector); //var offset = elem.dataset.offset ? parseInt(elem.dataset.offset) : 0; if (block) { var bodyOffset = document.body.getBoundingClientRect().top; window.scrollTo({ top: block.getBoundingClientRect().top - bodyOffset, // + offset, behavior: 'smooth' }); } else { self.log('scroll to unknown element: ' + selector); } }; /* /* Method: scroll Description: Functionality for scroll. @param {any} params - Description for params @returns {any} - Result of the operation */ this.scroll = function (params) { // var selector = self.selector(params); //var obj = $(selector).get(0); var selector = "g."+params.class+".myLabelStyle."+params.value; //var parent = $(selector).parent().get(0); //document.querySelector(selector).scrollIntoView(); //self.resizeEvent(); // bug workaround //$(selector).parent().scrollTop($(selector).position().top); $(selector).parent().animate({ //scrollTop: $(selector).position().top //scrollTop: $(selector).position().top, transform: 'translate(0,-'+$(selector).position().top+'), scale(1)' }); } */ //------------------------ /* /* Method: do Description: Functionality for do. @param {any} data - Description for data @param {any} args - Description for args @returns {any} - Result of the operation */ this.do = function (data, args) { if (data) { if (typeof data == 'string' && self.json.actions[data]) { self.do(self.json.actions[data], args); } else { if (!data.index) data.index = 0; if (!data.tasks) { if (Array.isArray(data)) { if (data.index < data.length) { self.do(data[data.index]); data.index = data.index +1; self.do(data); } else { delete data.index; } } else { self.do(data); } //} else if (data.tasks.length > 0) { } else { if (data.index < data.tasks.length) { var currentTask = data.tasks[data.index]; //var currentTask = data.tasks.shift(); if (currentTask.params == undefined) {currentTask.params = {}} if (data.params == undefined) {data.params = {}} if (currentTask.if == undefined) {currentTask.if = true} var taskParams = currentTask.params; // parametri specifici del task taskParams.params = data.params; taskParams.index = data.index+1; //for (var param in data.params) {taskParams[param] = data.params[param]; } // merge taskParams.tasks = data.tasks; var taskIf = (typeof currentTask.if == "function") ? currentTask.if() : currentTask.if; if (taskIf) { if (currentTask.delay !== undefined) { setTimeout(function () { self.do(currentTask.task, taskParams); }, currentTask.delay); } else if (currentTask.interval !== undefined) { self.createTaskInterval(currentTask); } else { self.do(currentTask.task,taskParams); } } else { self.do(taskParams); } } } } } } */ /* /* Method: playTaskInterval Description: Functionality for playTaskInterval. @param {any} taskFunction - Description for taskFunction @returns {any} - Result of the operation */ this.playTaskInterval = function (taskFunction) { self.log('playTaskInterval'); var taskName = taskFunction.name; if (tasksIntervals[taskName]) { clearInterval(tasksIntervals[taskName].id); tasksIntervals[taskName].id = setInterval(function () { tasksIntervals[taskName].task(tasksIntervals[taskName].params); }, tasksIntervals[taskName].interval); } else { self.log('taskName: '+taskName); } } /* Method: stopTaskInterval Description: Functionality for stopTaskInterval. @param {any} taskFunction - Description for taskFunction @returns {any} - Result of the operation */ this.stopTaskInterval = function (taskFunction) { self.log('stopTaskInterval'); var taskName = taskFunction.name; if (tasksIntervals[taskFunction.name]) { clearInterval(tasksIntervals[taskFunction.name].id); } else { self.log('taskName: '+taskName); } } /* Method: createTaskInterval Description: Functionality for createTaskInterval. @param {any} myTask - Description for myTask @returns {any} - Result of the operation */ this.createTaskInterval = function (myTask) { tasksIntervals[myTask.task.name] = {}; tasksIntervals[myTask.task.name].task = myTask.task; tasksIntervals[myTask.task.name].params = myTask.params; tasksIntervals[myTask.task.name].interval = myTask.interval; self.playTaskInterval(myTask.task.name); } /* Method: addTimedTask Description: Functionality for addTimedTask. @param {any} data - Description for data @returns {any} - Result of the operation */ this.addTimedTask = function (data) { self.log('addTimedTask'); if (data.frequence && data.task) { if (!data.active) {data.active = true;} if (!timedTasks[data.frequence]) {timedTasks[data.frequence] = {}} timedTasks[data.frequence][data.task] = {active:data.active, params:{}}; if (data.params) { timedTasks[data.frequence][id].params = data.params; } } } /* Method: removeTimedTask Description: Functionality for removeTimedTask. @param {any} data - Description for data @returns {any} - Result of the operation */ this.removeTimedTask = function (data) { self.log('removeTimedTask'); if (data.frequence && data.task) { delete timedTasks[data.frequence][data.task]; } } /* Method: doTimedTask Description: Functionality for doTimedTask. @param {any} data - Description for data @returns {any} - Result of the operation */ this.doTimedTask = function (data) { self.log('doTimedTask'); self.log(data); for (var task in timedTasks[data.frequence]) { var taskObj = timedTasks[data.frequence][task]; if (taskObj.active) { self.do(task, taskObj.params); } } } */ //------------------------ // CSS METHODS //------------------------ /* // SELETTORI var previewPanel = '.appPanel[data-value="pnlPreview"]'; var toolsPanel = '.appPanel[data-value="pnlTools"]'; var stagePanel = '.framePanel[data-value="pnlStage"]'; var devicePanel = '.framePanel[data-value="pnlDevice"]'; /* Method: closePanel Description: Functionality for closePanel. @param {any} value - Description for value @returns {any} - Result of the operation */ this.closePanel = function(value) { self.log(value); switch (value) { case 'closePanelTools': $(toolsPanel).fadeOut(); $(previewPanel).fadeIn(); case 'closePanelFrame': $(devicePanel).fadeOut(); $(stagePanel).fadeIn(); } } */ //------------------------ // CSS METHODS //------------------------ /* /* Method: cssProp Description: Functionality for cssProp. @param {any} propPar - Description for propPar @returns {any} - Result of the operation */ this.cssProp = function (propPar) { var cssObj = {transform: ''}; if ((propPar.x) && (propPar.y)) {cssObj.transform += ' translate('+propPar.x+'px,'+propPar.y+'px)'; } if (propPar.rotateY) {cssObj.transform += ' rotateY('+propPar.rotateY+'deg)'; } if (propPar.rotateX) {cssObj.transform += ' rotateX('+propPar.rotateX+'deg)'; } if (propPar.scale) {cssObj.transform += ' scale('+propPar.scale+','+propPar.scale+')'; } if (propPar.deg) {cssObj.transform += ' rotate('+propPar.deg+'deg)'; } if (propPar.opacity) {cssObj.opacity = propPar.opacity;} return cssObj; } */ /* /* Method: getCSS Description: Functionality for getCSS. @param {any} data - Description for data @returns {any} - Result of the operation */ this.getCSS = function (data) { var $inspector = $("
    ").css('display', 'none').addClass(data.class); $("body").append($inspector); // add to DOM, in order to read the CSS property try { var props = []; for (i=0; i { /* self.log('animate'); self.log('params'); self.log(params); self.log('selectorParams'); self.log(selectorParams); */ /* selectorParams.container = (params.container) ? params.container : selectorParams.container; selectorParams.id = (params.id) ? params.id : selectorParams.id ; selectorParams.class = (params.class) ? params.class : selectorParams.class; selectorParams.value = (params.value) ? params.value : selectorParams.value; */ const prefix = 'animate__'; //var selector = self.selector(self.extend({}, params, selectorParams), undefined, true); // selectAll let selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true); //var selector = self.selector(params.selector || params.container, selectorParams, true); // selectAll /* self.log('animate'); self.log('selector'); self.log(selector); */ var transition = params.transition || params; transition = self.replaceProperties(transition, args); const duration = params.duration || '0.5s'; const animationName = `${prefix}${transition}`; if (!selector) { self.log('animate function without selector'); self.log(params); self.log(selectorParams); } else { var elements = self.queryAll(selector); /* console.log('elements'); console.log(elements); */ //var elements = document.querySelectorAll(selector); if (elements) elements.forEach(function (element, index) { if (element) { //element.classList.add(`${prefix}animated`, animationName); //console.log(element.classList); element.classList.add('animate__animated', animationName); element.style.setProperty('--animate-duration', duration); } else { console.log('element'); console.log(element); } }); if (params.on && params.on.start) self.do(params.on.start, { selector: selector }); //self.do(params.on.start, undefined, {selector: selector}); if (params.style) self.css(params, selectorParams); // TO DO: deprecated / to be removed //if (params.infinite) // node.style.setProperty('--animate-infinite', 'infinite'); // When the animation ends, we clean the classes and resolve the Promise /* Method: handleAnimationEnd Description: Functionality for handleAnimationEnd. @param {any} event - Description for event @returns {any} - Result of the operation */ function handleAnimationEnd(event) { if (params.on && params.on.end) { self.do(params.on.end, { selector: selector }); //self.do(params.on.end, undefined, {selector: selector}); /* self.log('handleAnimationEnd'); self.log('params.on.end'); self.log(params.on.end); */ } event.stopPropagation(); if (elements) elements.forEach(function (element, index) { if (element) element.classList.remove('animate__animated', animationName); }); resolve('Animation ended'); } if (elements) elements.forEach(function (element, index) { if (element) element.addEventListener('animationend', handleAnimationEnd, { once: true }); }); } }); }; /* /* Method: animation Description: Functionality for animation. @param {any} data - Description for data @returns {any} - Result of the operation */ this.animation = function (data) { // deprecated if (data.animation != undefined) { if (data.animation == 'show') { $(data.object).css({'display':'block', opacity:1}); } else if (data.animation == 'hide') { $(data.object).css({'display':'none'}); } else { //if (data.autoDisplay == undefined) {data.autoDisplay = true}; //var animationObject = self.cloneObject(animations[data.animation]); var animationObject = jQuery.extend({}, animations[data.animation]); //if (data.autoDisplay) // if (data.animation == 'fadeIn') $(data.object).css({'display':'block'}); if (data.reverse) {animationObject.name += 'Reverse'} if (data.duration !== undefined) {animationObject.duration = data.duration} animationObject.complete = function () { if (data.autoDisplay) { if ((data.animation == 'fadeOut') || (data.animation == 'hide')) { $('data.object').css({'display':'none'}); } } if (data.onComplete !== undefined) { self.do(data.onComplete); } } self.log('animationObject.name'); self.log(animationObject.name); self.log('animationObject'); self.log(animationObject); // playKeyframe va aggiornato con // animate({from, to, ease, type, stiffness, dumping, mass, velocity, duration}) // https://popmotion.io/#quick-start-animation-animate-keyframes-options //var obj = popmotion.styler($(data.object)); //popmotion.animate(animationObject).start(obj.set); // $(data.object).css $(data.object).playKeyframe(animationObject); } } else { $(data.object).resetKeyframe(); $(data.object).css({'opacity':1,'display':'block'}); self.log('ANIMATION UNDEFINED'); self.log(data); } } /* Method: move Description: Functionality for move. @param {any} data - Description for data @returns {any} - Result of the operation */ this.move = function (data) { // deprecated var targetPos = {x:0,y:0}; if (data.target != 'center') { targetPos = {x:384,y:384}; } else if (data.target !== undefined) {targetPos = self.getTransform(data.target);} else {self.log(data);} if (data.move == 'toTarget') { TweenMax.to(data.object, self.TweenMaxDuration(data.duration), { x: targetPos.x, y: targetPos.y}); } else if (data.move == 'fromTarget') { TweenMax.from(this, self.TweenMaxDuration(data.duration), { x: targetPos.x, y: targetPos.y}); } if (data.animation !== undefined) { self.animation({object:data.object, animation:data.animation}); } } /* Method: TweenMaxDuration Description: Functionality for TweenMaxDuration. @param {any} duration - Description for duration @returns {any} - Result of the operation */ this.TweenMaxDuration = function (duration) { if (duration != undefined) {return Number(duration)/1000} else {return 0.667;} } */ // CSS CLASSES /* Method: addClassRule Description: Functionality for addClassRule. @param {any} ruleName - Description for ruleName @param {any} ruleParams - Description for ruleParams @returns {any} - Result of the operation */ this.addClassRule = function (ruleName, ruleParams) { //self.log('addClassRule'); var ruleProperties = '{'; for (var property in ruleParams) { if (typeof ruleParams[property] == 'object') { self.addClassRule(ruleName + ' ' + property, ruleParams[property]); } else { ruleProperties += property + ':' + ruleParams[property] + ';'; } } ruleProperties += '}'; self.styleObj.sheet.insertRule(ruleName + ' ' + ruleProperties); }; /* Method: addApplyRule Description: Functionality for addApplyRule. @param {any} ruleName - Description for ruleName @param {any} ruleParams - Description for ruleParams @returns {any} - Result of the operation */ this.addApplyRule = function (ruleName, ruleParams) { // Use @apply to inline any existing utility classes into your own custom CSS // https://tailwindcss.com/docs/functions-and-directives#apply self.styleObj.sheet.insertRule(ruleName + ' {@apply ' + ruleParams + '}'); }; /* Method: findPlugin Description: Functionality for findPlugin. @param {any} name - Description for name @returns {any} - Result of the operation */ this.findPlugin = function (name) { if (self.json.plugins) { for (var plugin of self.json.plugins) { if (plugin.name == name) return plugin; } } else { return false; } }; /* Method: defineCss Description: Functionality for defineCss. @param {any} cssObj - Description for cssObj @returns {any} - Result of the operation */ this.defineCss = function (cssObj) { self.log('defineCss'); self.styleObj = document.createElement("style"); document.head.appendChild(self.styleObj); self.styleObj.appendChild(document.createTextNode("")); /* self.styleObj.sheet.insertRule('@tailwind base;'); self.styleObj.sheet.insertRule('@tailwind components;'); self.styleObj.sheet.insertRule('@tailwind utilities;'); */ // shortcuts (must be improved / can't be extended) /* if (self.json.shortcuts && self.json.shortcuts.class) shortcuts = self.json.shortcuts.class; */ if (cssObj) { if (Array.isArray(cssObj)) { for (var cssElement of cssObj) { //console.log(cssElement); for (var elementName in cssElement) { //console.log(elementName); let valueWithData = self.replaceProperties(cssElement[elementName]); self.addClassRule(elementName, valueWithData); } } } else { for (var elementName in cssObj) { let valueWithData = self.replaceProperties(cssObj[elementName]); self.addClassRule(elementName, valueWithData); } } } if (self.pluginsLoaded.tailwindcss) { var plugin = self.findPlugin('tailwindcss'); //var config = (plugin) ? plugin.config : {preflight: false}; var config = (self.json.setup.config.tailwindcss) ? self.json.setup.config.tailwindcss : { preflight: false }; //if (self.json.style.theme) setup.theme = self.json.style.theme; //loadPlugin(undefined, 'tailwind-config', undefined, undefined, JSON.stringify(config)) // version 2.2.0 if (tailwind) tailwind.config = config; else console.log('tailwind object is undefined'); } /* // OBSOLETE if (self.pluginsLoaded.twind && window.twind) { var plugin = self.findPlugin('twind'); var config = (plugin) ? plugin.config : {preflight: false, mode:'silent'}; //if (self.json.setup.target) setup.target = self.query(self.json.setup.target); //if (self.json.style.theme) setup.theme = self.json.style.theme; window.twind.setup(config); } */ /* if (self.pluginsLoaded.windicss && window.windicssRuntimeOptions) { var config = self.json.style.windi || { // enabled preflight preflight: false, // scan the entire dom tree to infer the classnames on page loaded extractInitial: false, // generate mock classes for browser to do the auto-completeion mockClasses: false, // the windi config you are used to put in `windi.setup.js` setup: {}, theme: {extend: {}} }; if (self.json.style.theme) setup.theme.extend = self.json.style.theme; window.windicssRuntimeOptions = config; } */ /* if (self.pluginsLoaded.unocss) { var config = self.json.style.unocss || { // -> self.json.plugins[].setup rules: [ // custom rules... ], presets: [ // custom presets... ], // ... }; if (self.json.style.theme) setup.theme = self.json.style.theme; if (self.json.shortcuts) setup.shortcuts = self.json.shortcuts; window.__unocss = config; //alert(JSON.stringify(config)); } */ //self.do(data); }; /* /* Method: createLoader Description: Functionality for createLoader. @param {any} data - Description for data @returns {any} - Result of the operation */ this.createLoader = function (data) { // !--
    Loading...
    --> if (self.json.loader) $('.preloader img').attr('src', self.json.loader); self.do(data); } */ /* /* Method: preloadIcons Description: Functionality for preloadIcons. @param {any} data - Description for data @returns {any} - Result of the operation */ this.preloadIcons = function (data) { self.log('preloadIcons'); // to do: check for duplicated ids if (self.json.icons) { if (!data.icons && self.json.icons) data.icons = self.cloneObject(self.json.icons); if (data.icons) { var iconSet = Object.keys(data.icons)[0]; var icons = data.icons[iconSet]; delete data.icons[iconSet]; if (icons.preload) { var ajax = new XMLHttpRequest(); ajax.open("GET", icons.src, true); ajax.onload = function(e) { if (this.status >= 200 && this.status < 400) { self.log('Icon set loaded ' + iconSet); var result = this.response; // responseText //self.log(result); var div = document.createElement("div"); //var iconsHtml = new XMLSerializer().serializeToString(result); var iconsHtml = result; iconsHtml = self.replaceAll(iconsHtml, 'id="', 'id="' + iconSet + '_'); div.innerHTML = iconsHtml; div.setAttribute("style", "display: none"); //div.setAttribute("aria-hidden", "true"); //document.getElementbyId('preloadIcons').appendChild(element); document.body.insertBefore(div, null); if (Object.keys(data.icons).length > 0) self.preloadIcons(data); else self.do(data); } } ajax.send(); } else { if (Object.keys(data.icons).length > 0) self.preloadIcons(data); else self.do(data); } } else self.do(data); } else { self.do(data); } } */ /* /* Method: initApp Description: Functionality for initApp. @param {any} data - Description for data @returns {any} - Result of the operation */ this.initApp = function (data) { self.log('initApp'); self.defineCss(); window.addEventListener('resize', self.resizeEvent); if (self.json) { // can be self.json.init //if (self.json.on.init) if (self.json.on) self.on(self.json.on); //else // self.log('no on init functions'); } //self.do(data); } */ /* /* Method: createUI Description: Functionality for createUI. @param {any} data - Description for data @returns {any} - Result of the operation */ this.createUI = function (data) { jsonic.do({ tasks:[ {task: self.firebaseInit}, { task: self.firebaseVerifyUser, params: { code: self.params.oobCode } }, {task: self.getDevices, if: jsonic.userIn}, {task: self.defineCss}, {task: self.defineAnimations}, // animazioni css predefinite {task: self.createHeader}, {task: self.createMenu, params: { container: '#menu', id: data.params.mode || 'guest' }}, {task: jsonic.createPages} ] }); } */ /* /* Method: openPageFromUrl Description: Functionality for openPageFromUrl. @param {any} data - Description for data @returns {any} - Result of the operation */ this.openPageFromUrl = function(data){ jsonic.log('openPageFromUrl'); jsonic.log('self.params'); jsonic.log(self.params); var pageId = ''; //if (localStorage.getItem('scanning')) { // self.hashopenTask({id:localStorage.getItem('scanningFile')}); //} else { //self.disableFileIcons(); //var noDevices = (jsonic.userIn() && (!var.db.devices || Object.keys(var.db.devices).length == 0)); //if (noDevices && !self.params.d && !self.params.m) { // jsonic.gotoPage('devices'); //} else { if (window.location.hash && window.location.hash !== '') { //pageId = window.location.hash.substr(1); self.hash(); } else { if (self.params.p) // retro-compatibilità pageId = self.params.p; else pageId = self.homePage(); self.gotoPage(pageId); } //} self.do(data); } */ /* // Load a script from given `url` /* Method: loadPlugin Description: Functionality for loadPlugin. @param {any} url - Description for url @returns {any} - Result of the operation */ var loadPlugin = function(url) { return new Promise(function(resolve, reject) { const script = document.createElement('script'); script.src = url; script.addEventListener('load', function() { // The script is loaded completely resolve(true); }); document.head.appendChild(script); }); }; // Perform all promises in the order /* Method: waterfall Description: Functionality for waterfall. @param {any} promises - Description for promises @returns {any} - Result of the operation */ var waterfall = function(promises) { return promises.reduce( function(p, c) { // Waiting for `p` completed return p.then(function() { // and then `c` return c().then(function(result) { return true; }); }); }, // The initial value passed to the reduce method Promise.resolve([]) ); }; // Load an array of scripts in order /* Method: loadScriptsInOrder Description: Functionality for loadScriptsInOrder. @param {any} arrayOfJs - Description for arrayOfJs @returns {any} - Result of the operation */ var loadScriptsInOrder = function(arrayOfJs) { self.log('loadScriptsInOrder'); self.log(arrayOfJs); const promises = arrayOfJs.map(function(url) { self.log(url); return loadScript(url); }); return waterfall(promises); }; */ /* Method: hash Description: Functionality for hash. @param {any} path - Description for path @param {any} args - Description for args @returns {any} - Result of the operation */ this.hash = function (path, args) { self.log('hash'); var path = self.replaceProperties(path, args); self.log(path); window.location.hash = path; }; /* Method: page Description: Functionality for page. @param {any} path - Description for path @param {any} args - Description for args @returns {any} - Result of the operation */ this.page = function (path, args) { self.log('page'); var path = self.replaceProperties(path, args); self.log(path); if (path.startsWith('#')) window.location.hash = path; else window.location.href = path; //window.location.hash = path; }; /* Method: hashChangeEvent Description: Functionality for hashChangeEvent. @param {any} - No parameters @returns {any} - Result of the operation */ this.hashChangeEvent = function () { self.log('hashChangeEvent'); self.log(window.location.hash); /* if (window.location.hash && window.location.hash !== '') { var hashParams = window.location.hash.substr(1).split('/'); self.gotoPage(hashParams[0], hashParams[1]); } else { //pageId = self.homePage(); if (self.json.setup && self.json.setup.wordpress && self.json.setup.wordpress.slug) self.gotoPage(self.json.setup.wordpress.slug); else self.gotoPage(self.homePage()); } if (json && json.app && json.app.on && json.app.on.page) { // page event self.do(json.app.on.page); } if (json && json.actions && json.actions.init) { // obsolete self.do(json.actions.init); } */ }; /* /* Method: addPageListeners Description: Functionality for addPageListeners. @param {any} data - Description for data @returns {any} - Result of the operation */ this.addPageListeners = function (data) { self.log('addPageListeners'); // Resize event window.addEventListener('resize', self.resizeEvent); // Location hash (url) event window.addEventListener('hashchange', self.hashChangeEvent); //$(window).on('hashchange', self.hashChangeEvent); self.hashChangeEvent(); self.do(data); } */ /* // testing /* Method: findValues Description: Functionality for findValues. @param {any} obj - Description for obj @param {any} key - Description for key @param {any} found - Description for found @returns {any} - Result of the operation */ let findValues = function(obj, key, found) { for (let localKey in obj) { if (obj.hasOwnProperty(localKey)) { let val = obj[localKey]; //self.log(localKey) if (localKey === key) { found.add(val) } else { if (typeof val === 'object') { findValues(val, key, found) } } } } } /* Method: uniqueValue Description: Functionality for uniqueValue. @param {any} obj - Description for obj @param {any} key - Description for key @param {any} value - Description for value @returns {any} - Result of the operation */ function uniqueValue(obj, key, value) { let found = new Set() findValues(object, key, found) return found.size === 1 && found.has(value); } */ /* Method: lookup Description: Functionality for lookup. @param {any} obj - Description for obj @param {any} k - Description for k @returns {any} - Result of the operation */ this.lookup = function (obj, k) { for (var key in obj) { var value = obj[key]; if (k == key) { return [k, value]; } if (typeof (value) === "object" && !Array.isArray(value)) { var y = lookup(value, k); if (y && y[0] == k) return y; } if (Array.isArray(value)) { // for..in doesn't work the way you want on arrays in some browsers // for (var i = 0; i < value.length; ++i) { var x = lookup(value[i], k); if (x && x[0] == k) return x; } } } return null; }; /* Method: findValues Description: Functionality for findValues. @param {any} obj - Description for obj @param {any} key - Description for key @returns {any} - Result of the operation */ this.findValues = function (obj, key) { //return Boolean(JSON.stringify(obj).indexOf('"' + string + '":') >= 0) let matrix = [...JSON.stringify(obj).matchAll(new RegExp('\"?' + key + '\"?\:\s*\"([^,\"]+)', 'gi'))]; var results = []; for (var element of matrix) results.push(element[1]); return results; //return Boolean(JSON.stringify(obj).match(new RegExp('\"?' + key + '\"?\:\s+\"' + value + '\"'))) // JSON5 compatible }; // testing /* Method: findKey Description: Functionality for findKey. @param {any} obj - Description for obj @param {any} key - Description for key @returns {any} - Result of the operation */ function findKey(obj, key) { for ([k, v] of Object.entries(obj)) { if (k == key) return v; if (typeof v === 'object' && v !== null) { let found = findKey(v, key); if (found) return found; } } } // lookup in json /* Method: keyInJson Description: Functionality for keyInJson. @param {any} obj - Description for obj @param {any} string - Description for string @returns {any} - Result of the operation */ this.keyInJson = function (obj, string) { //return Boolean(JSON.stringify(obj).indexOf('"' + string + '":') >= 0) return Boolean(JSON.stringify(obj).match(new RegExp('\"?' + string + '\"?\:'))); // JSON5 compatible }; // lookup in json /* Method: valueInJson Description: Functionality for valueInJson. @param {any} obj - Description for obj @param {any} string - Description for string @returns {any} - Result of the operation */ this.valueInJson = function (obj, string) { //return Boolean(JSON.stringify(obj).indexOf('"' + string + '":') >= 0) return Boolean(JSON.stringify(obj).match(new RegExp('\"?' + string + '\"?'))); // JSON5 compatible }; /* /* Method: keyInFiles Description: Functionality for keyInFiles. @param {any} string - Description for string @returns {any} - Result of the operation */ this.keyInFiles = function (string) { var found = self.keyInJson(self.options, string); // in main app options: jsonic = jsonicApp(options) for (fileName in self.modules) { if (fileName !== 'resources' && self.keyInJson(self.modules[fileName], string)) found = true; } return found; } */ /* /* Method: openPageFromUrl Description: Functionality for openPageFromUrl. @param {any} data - Description for data @returns {any} - Result of the operation */ this.openPageFromUrl = function (data) { self.log('openPageFromUrl'); self.hashChangeEvent(); self.do(data); }; */ /* /* Method: addEventListeners Description: Functionality for addEventListeners. @param {any} data - Description for data @returns {any} - Result of the operation */ this.addEventListeners = function (data) { self.log('addEventListeners'); // Resize event window.addEventListener('resize', self.resizeEvent); // Location hash (url) event window.addEventListener('hashchange', self.hashChangeEvent); $(window).on('hashchange', self.hashChangeEvent); self.hashChangeEvent(); // add here on.hashchange // Fullscreen event if (screenfull && screenfull.isEnabled) { screenfull.on('change', () => { self.log('Am I fullscreen?', screenfull.isFullscreen ? 'Yes' : 'No'); if (screenfull.isFullscreen) { var.fullscreen = true; if (var.onFullScreenOpen) self.do(var.onFullScreenOpen); } else { var.fullscreen = false; if (var.onFullScreenClose) self.do(var.onFullScreenClose); } }); } if (json && json.app && json.app.on) { if (json.app.on.thunkable && json.app.on.thunkable.receiveMessage) window.receiveMessage(function (message) { //document.querySelector('#message').value = message; jsonic.functions(json.app.on.thunkable.receiveMessage, message, undefined); }); var container = json.app.container || 'body'; self.on(json.app.on, {container: container}); self.do(data); } else { self.do(data); } } */ /* /* Method: loadIconset Description: Functionality for loadIconset. @param {any} data - Description for data @returns {any} - Result of the operation */ this.loadIconset = function (data) { self.log('loadIconset'); if (self.json.iconset) { if (!self.pluginsLoaded['iconify']) { let plugin = self.json.resources.pluginsFunctions['iconify']; self.pluginsLoader([plugin], self.loadIconset, [data]); } else { var iconset; if (!self.json.iconset[0]) iconset = [self.json.iconset]; else iconset = self.json.iconset; for (var index in iconset) { if (Iconify.addCollection(iconset[index])) self.log('added iconset '+ iconset[index].prefix); else self.log('can\t add iconset '+ iconset[index].prefix); //alert(x); } self.do(data); } } else { self.do(data); } } */ // Si potrebbe creare una nuova istanza di jsonicApp /* Method: start Description: Functionality for start. @param {any} - No parameters @returns {any} - Result of the operation */ this.start = function () { self.log('start'); //if (params.onFullScreenOpen) var.onFullScreenOpen = params.onFullScreenOpen; //if (params.onFullScreenClose) var.onFullScreenClose = params.onFullScreenClose; // PWA /* if ('serviceWorker' in navigator) { // Register a service worker hosted at the root of the // site using the default scope. navigator.serviceWorker.register('/app/assets/pwa/sw.js').then(function(registration) { self.log('Service worker registration succeeded:', registration); }, function(error) { self.log('Service worker registration failed:', error); }); } else { self.log('Service workers are not supported.'); } */ let deferredPrompt; window.addEventListener('beforeinstallprompt', (e) => { // Prevent Chrome 67 and earlier from automatically showing the prompt e.preventDefault(); // Stash the event so it can be triggered later. deferredPrompt = e; }); window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => { self.json.setup.darkMode = e.matches ? "dark" : false; }); // DEFINE ICONSET (iconify) if (self.json.iconset) { if (!self.pluginsLoaded['iconify']) { let plugin = self.json.resources.pluginsFunctions['iconify']; self.pluginsLoader([plugin], self.start); return false; } else { var iconset; if (!self.json.iconset[0]) iconset = [self.json.iconset]; else iconset = self.json.iconset; for (var index in iconset) { if (Iconify.addCollection(iconset[index])) self.log('added iconset ' + iconset[index].prefix); else self.log('can\t add iconset ' + iconset[index].prefix); //alert(x); } } } // DEFINE CSS //self.defineCss(); // TO DO: only additional css (do it on load module success) // ADD RESIZE LISTENER (for dynamic styles) TO DO: check it window.addEventListener('resize', self.resizeEvent); // PAGE if (!self.json.setup.page) self.json.setup.page = {}; self.json.setup.page.hash = window.location.hash.substr(1); // DO / ON /* if (self.json) { if (self.json.do) self.do(self.json.do, undefined, self.json.container); if (self.json.on) self.on(self.json.on, self.json.container); } */ var selector = self.json.selector || self.json.container; /* if (self.json.do) self.do(self.json.do, undefined, selector); */ // should go action/run if (self.json.on) self.on(self.json.on, selector); }; /* Method: extendJson Description: Functionality for extendJson. @param {any} jsonBase - Description for jsonBase @param {any} jsonExtension - Description for jsonExtension @returns {any} - Result of the operation */ this.extendJson = function (jsonBase, jsonExtension) { // TO DO: should be renamed in extendApp (or executeModule) because extend self.json and add CSS style if (jsonExtension.css) self.defineCss(jsonExtension.css); if (jsonExtension.functions) self.extendFunctions(jsonExtension.functions); for (var key in jsonExtension) { // AGGIUNGERE ALL'ARRAY DELLE AZIONI ON.INIT... if (key == 'on') { for (var subKey in jsonExtension[key]) { if (typeof jsonExtension[key][subKey] !== 'string') { //jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]); if (!jsonBase[key][subKey]) jsonBase[key][subKey] = []; jsonBase[key][subKey].push(jsonExtension[key][subKey]); } else { jsonBase[key][subKey] = jsonExtension[key][subKey]; } } } else if (key == 'parts' || key == 'shortcuts') { // combine subelements for (var subKey in jsonExtension[key]) { if (typeof jsonExtension[key][subKey] !== 'string') jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]); else jsonBase[key][subKey] = jsonExtension[key][subKey]; } /* } else if (key == 'css') { for (var subKey in jsonExtension[key]) { if (typeof jsonExtension[key][subKey] !== 'string') jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]); else jsonBase[key][subKey] = jsonExtension[key][subKey]; } */ /* } else if (key == 'app') { // to do: obsolete for (var subKey in jsonExtension[key]) { if (typeof jsonExtension[key][subKey] !== 'string') jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]); else jsonBase[key][subKey] = jsonExtension[key][subKey]; } */ } else if (key == 'iconset' || key == 'plugins') { // combine arrays if (!jsonBase[key]) jsonBase[key] = []; jsonBase[key] = jsonBase[key].concat(jsonExtension[key]); } else { if (key == 'css') { } else { jsonBase[key] = self.extend({}, jsonBase[key], jsonExtension[key]); } } } return jsonBase; }; /* Method: loadModuleFromDb Description: Functionality for loadModuleFromDb. @param {any} data - Description for data @returns {any} - Result of the operation */ this.loadModuleFromDb = function (data) { self.log('loadModuleFromDb'); self.firebaseGet('jsonic', function (result) { if (result.success) { self.log('firebase get SUCCESS'); for (codeKey in result.data) if (result.data[codeKey].code) self.extendJson(json, result.data[codeKey].code); //self.log('json'); //self.log(json); //if (params.success) self.do(params.success,result.data); } else { self.log('firebase get ERROR'); //if (params.error) self.do(params.error, result.error); // alert errore di connessione. alert riprova } self.do(data); //self.do(data); }); }; this.modules = {}; this.modulesLoading = {}; /* Method: fileType Description: Functionality for fileType. @param {any} fileName - Description for fileName @returns {any} - Result of the operation */ this.fileType = function (fileName) { return /(?:\.([^.]+))?$/.exec(fileName)[1]; }; /* Method: jsoncToJson Description: Functionality for jsoncToJson. @param {any} jsoncText - Description for jsoncText @returns {any} - Result of the operation */ this.jsoncToJson = function (jsoncText) { return jsoncText.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1').replace(/\r/, "\n").replace(/\n[\n]+/, "\n"); // https://stackoverflow.com/questions/244777/can-comments-be-used-in-json/24545329 }; //var json = jsoncToJson('https://fantacards.com/app/data.jsonc'); //console.log(json); /* Method: loadModule Description: Functionality for loadModule. @param {any} mod - Description for mod @returns {any} - Result of the operation */ this.loadModule = function (mod) { /* self.log('loadModule'); self.log(mod); */ // params: {files, onComplete} // self.cloneObject(params.json) to avoid to remove from initial params //if (typeof setup.modules == 'string') setup.modules = [setup.modules]; if (!self.modulesLoading[mod.name] && !self.modules[mod.name]) { self.modulesLoading[mod.name] = true; return new Promise(function (resolve, reject) { //mod = self.replaceProperties(mod); //self.log(mod); const getAPIData = new XMLHttpRequest(); getAPIData.open("GET", mod.url); getAPIData.onload = function () { self.modulesLoading[mod.name] = false; //console.log(getAPIData); let responseText = getAPIData.responseText; if (self.fileType(getAPIData.responseURL) == 'jsonc') responseText = self.jsoncToJson(responseText); // try const result = JSON.parse(responseText); // error self.log('Wrong JSON in module '+ mod.name); if (self.isJson(result)) { self.modules[mod.name] = result; self.extendJson(self.json, result); self.log('Loaded module ' + mod.name, 'grey'); } else { self.log('Wrong JSON in module ' + mod.name, 'red'); } resolve(); }; getAPIData.onerror = function () { self.modulesLoading[mod.name] = false; }; getAPIData.send(); }); } else { self.log('Module ' + mod.name + ' already loaded', 'orange'); } }; /* /* Method: loadPlugin Description: Functionality for loadPlugin. @param {any} url - Description for url @returns {any} - Result of the operation */ var loadPlugin = function (url) { //self.log('loading ' + url); return new Promise(function(resolve, reject) { var type = 'script'; if (url.endsWith('.css')) type = 'link'; let obj = document.createElement(type); // obj.src = url; obj.async = false; obj.onload = function() { resolve(url); }; obj.onerror = function() { self.log('error loading: '+url); reject(url); }; if (type === 'script') { if (url) obj.src = url; //if (code) obj.text = code; obj.location = document.body; document.body.appendChild(obj); } else { obj.href = url; obj.rel = 'stylesheet'; obj.type = 'text/css'; obj.location = document.head; document.head.appendChild(obj); } //self.log('obj'); //self.log(obj); }); } */ /* Method: loadPlugin Description: Functionality for loadPlugin. @param {any} params - Description for params @returns {any} - Result of the operation */ var loadPlugin = function (params) { //self.log('loading ' + url); return new Promise(function (resolve, reject) { var tag = 'script', type = 'text/javascript'; if (params.type == 'script') { tag = 'script'; type = 'text/javascript'; } else if (params.type == 'module') { tag = 'script'; type = 'module'; } else if (params.type == 'tailwind-config') { tag = 'script'; type = 'tailwind-config'; } else if (params.type == 'link') { tag = 'link'; type = 'text/css'; } else if (params.type == 'font') { tag = 'link'; type = undefined; } //if (!tag) // tag = (url.endsWith('.js')) ? 'script' : 'link'; let obj = document.createElement(tag); if (params.content) obj.appendChild(document.createTextNode(params.content)); obj.async = false; obj.onload = function () { self.pluginsLoaded[params.name] = { version: "1.0.0" }; self.log('Loaded plugin ' + params.name, 'grey'); resolve(params.url); }; obj.onerror = function () { self.log('Error loading plugin ' + params.url, 'red'); reject(params.url); }; if (tag === 'script') { if (params.url) obj.src = params.url; //if (code) obj.text = code; obj.location = document.body; obj.type = type || 'text/javascript'; /* if (type == 'tailwind-config') { self.log('obj'); self.log(obj); } */ document.body.appendChild(obj); } else if (tag === 'link') { obj.rel = params.rel || 'stylesheet'; obj.location = document.head; if (params.url) obj.href = params.url; if (type) obj.type = type; if (params.as) obj.as = params.as; document.head.appendChild(obj); } }); }; /* /* Method: loadPlugin Description: Functionality for loadPlugin. @param {any} url - Description for url @param {any} tag - Description for tag @param {any} rel - Description for rel @param {any} as - Description for as @returns {any} - Result of the operation */ var loadPlugin = function (url, tag, rel, as) { //self.log('loading ' + url); //alert(url); return new Promise(function(resolve, reject) { if (tag == 'js') tag = 'script'; if (tag == 'css') tag = 'link'; if (!tag) tag = (url.endsWith('.js')) ? 'script' : 'link'; let obj = document.createElement(tag); obj.async = false; obj.onload = function() { self.log('loaded plugin: '+url); resolve(url); }; obj.onerror = function() { self.log('error loading: '+url); reject(url); }; if (tag === 'script') { if (url) obj.src = url; //if (code) obj.text = code; obj.location = document.body; document.body.appendChild(obj); } else { obj.href = url; obj.rel = rel || 'stylesheet'; if (obj.rel == 'stylesheet') obj.type = 'text/css'; if (as) obj.as = as; obj.location = document.head; document.head.appendChild(obj); } }); } */ this.uiLoaded = {}; this.pluginsLoaded = {}; //The Firebase Realtime Database lets you store and query user data, and makes it available between users in realtime /* Method: findUrl Description: Functionality for findUrl. @param {any} array - Description for array @param {any} url - Description for url @returns {any} - Result of the operation */ this.findUrl = function (array, url) { for (var item of array) { if (item.url == url) return true; } }; /* /* Method: export Description: Functionality for export. @param {any} params - Description for params @returns {any} - Result of the operation */ this.export = function (params) { // {name, data} if (params && params.name && params.data) { let element = document.createElement('a'); element.style.display = 'none'; element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(params.data))); element.setAttribute('download', params.name); document.body.appendChild(element); element.click(); document.body.removeChild(element); } else { self.log('"export" requires name and data attributes'); } } */ /* /* Method: exportData Description: Functionality for exportData. @param {any} path - Description for path @returns {any} - Result of the operation */ this.exportData = function (path) { // data const fileName = self.replaceAll(path, ' ', '.') + '.json'; const jsonData = self.element({path: path, root: params.root}); self.export({name: fileName, data: jsonData}); } */ /* Method: loadPlugins Description: Functionality for loadPlugins. @param {any} - No parameters @returns {any} - Result of the operation */ this.loadPlugins = function () { //self.log('loadPlugins'); //var setup = json.setup; // TEMPORAL API // https://cdn.jsdelivr.net/npm/@cogitatio/tc39-temporal@0.0.12-alpha.2/index.js // https://cdn.jsdelivr.net/npm/cogitatio-tc39-temporal@1.0.2/index.js /* */ var filesToLoad = []; // plugins if (self.json.plugins) { for (var index in self.json.plugins) { var plugin = self.json.plugins[index]; //self.log('loading ' + plugin.name + '...'); var version = plugin.version || ''; if (!plugin.ondemand) { // V. >= 1.0.2 if (plugin.url) { // directly loaded // plugin.name and version are needed? if (!self.findUrl(filesToLoad, plugin.url)) { // not included yet filesToLoad.push({ name: plugin.name, url: plugin.url, type: plugin.type }); } } else { // from resources (TO DO: remove) var pluginsFiles = plugin.files || self.json.resources.pluginsFiles[plugin.name]; // moved in loadPlugin = ... onload /* self.pluginsLoaded[plugin.name] = { version: version }; */ if (!Array.isArray(pluginsFiles)) pluginsFiles = [pluginsFiles]; for (item of pluginsFiles) { var url = self.replaceAll(item.url, '{version}', version); if (plugin.params) url += '?' + plugin.params; let pluginName = plugin.name || item.name; if (!url || !self.findUrl(filesToLoad, url)) // not included yet filesToLoad.push({ name: pluginName, url: url, type: item.type, content: item.content }); } } } } } // ui /* for (var index in config.ui) { var configUI = config.ui[index]; //self.log('loading ' + configUI.name + '...'); var version = configUI.version || ''; var uiFiles = self.json.resources.uiFiles[configUI.name]; if (!Array.isArray(uiFiles)) uiFiles = [uiFiles]; for (item of uiFiles) { var url = self.replaceAll(item.url, '{version}', version); if (!self.findUrl(filesToLoad, url)) // not included yet filesToLoad.push({url: url, type: item.type, content: item.content}); } } */ // Auto load Google Fonts // TO DO: comment for (fontName of self.findValues(self.json, 'font-family')) { if (self.json.resources.googleFonts.indexOf(fontName) >= 0) { //alert(fontName); fontName = self.replaceAll(fontName, ' ', '+'); //filesToLoad.push({type: 'font', url:'https://fonts.googleapis.com/css2?family='+fontName+'&display=swap', rel:'preload', as:'font'}); filesToLoad.push({ type: 'link', url: 'https://fonts.googleapis.com/css2?family=' + fontName }); // +'&display=swap' // https://css-tricks.com/almanac/properties/f/font-display/ } } // Auto load plugins (firebase only) /* if (config.plugins && config.plugins.autoload) { self.log('plugins autoload'); //for (var index in self.json.resources.pluginsFunctions) { var pluginFunctions = self.json.resources.pluginsFirebase; // pluginFunctions for (var index in self.json.resources.pluginsFirebase) { //self.log(index + ':' + self.keyInFiles(index)); if (self.keyInFiles(index)) { if (pluginFunctions[index]) { var plugins = []; if (Array.isArray(pluginFunctions[index])) plugins = pluginFunctions[index]; else plugins = [pluginFunctions[index]]; for (plugin of plugins) { self.log('loading ' + plugin.name + '...'); self.pluginsLoaded[plugin.name] = version; var version = plugin.version || ''; var pluginsFiles = self.json.resources.pluginsFiles[plugin.name]; if (!Array.isArray(pluginsFiles)) pluginsFiles = [pluginsFiles]; for (item of pluginsFiles) { var url = self.replaceAll(item.url, '{version}', version); if (!self.findUrl(filesToLoad, url)) // not included yet filesToLoad.push({url: url, type: item.type, content: item.content}); } } } } } } */ // load multiple scripts in sequence // https://bit.ly/3nT5Ky1 // one after another // https://medium.com/@asimmittal/sequential-script-loading-in-javascript-a0b77ca9467c // load multi js and css // https://sphacks.io/load-multiple-js-scripts-dynamically-without-jquery/ // save all Promises as array let promises = []; //promises.push(loadPlugin("https: filesToLoad.forEach(function (item) { if (item.url) promises.push(loadPlugin({ name: item.name, url: item.url, type: item.type, rel: item.rel, as: item.as, content: item.content })); else loadPlugin({ name: item.name, url: item.url, type: item.type, rel: item.rel, as: item.as, content: item.content }); }); Promise.all(promises).then(function () { self.start(); }).catch(function (script) { self.log('Failed to load'); self.log(script); }); }; /* Method: modulesList Description: Functionality for modulesList. @param {any} modulesObj - Description for modulesObj @returns {any} - Result of the operation */ this.modulesList = function (modulesObj) { var modulesList = []; if (modulesObj) { for (key in modulesObj) { var mod = self.replaceProperties(modulesObj[key]); modulesList = modulesList.concat(mod); } } return self.replaceProperties(modulesObj); }; /* Method: loadModules Description: Functionality for loadModules. @param {any} - No parameters @returns {any} - Result of the operation */ this.loadModules = function () { if (self.json.setup.modules) { var modules = self.replaceProperties(self.json.setup.modules); var promises = []; modules.forEach(function (item) { if (!self.modulesLoading[item.name] && !self.modules[item.name]) { promises.push(self.loadModule(item)); } }); Promise.all(promises).then(function () { self.loadPlugins(); }).catch(function (file) { self.log('Failed to load'); self.log(file); }); } else { self.loadPlugins(); } }; this.moduleExecuted = {}; /* Method: addModule Description: Functionality for addModule. @param {any} params - Description for params @returns {any} - Result of the operation */ this.addModule = function (params) { if (!self.modules[params.name]) { var promises = []; promises.push(self.loadModule(params)); Promise.all(promises).then(function () { if (!self.moduleExecuted[params.name]) { var module = self.modules[params.name]; if (module.html) { self.moduleExecuted[params.name] = true; self.html(module.html); } } if (params.success) self.do(params.success); }).catch(function (file) { self.log('Failed to load'); self.log(file); if (params.error) self.do(params.error); }); } else { if (params.success) self.do(params.success); } }; /* Method: loadModuleGlobal Description: Functionality for loadModuleGlobal. @param {any} - No parameters @returns {any} - Result of the operation */ this.loadModuleGlobal = function () { self.log('loadModuleGlobal'); var promises = []; var modules = []; for (let key in self.json.setup.modules) { var mod = self.replaceProperties(self.json.setup.modules[key]); modules = modules.concat(self.cloneObject(mod)); } for (let mod of modules) promises.push(self.loadModule(mod)); Promise.all(promises).then(function () { self.loadModules(); }).catch(function (file) { self.log('Failed to load'); self.log(file); }); }; /* Method: code Description: Functionality for code. @param {any} params - Description for params @param {any} selectorParams - Description for selectorParams @returns {any} - Result of the operation */ this.code = function (params, selectorParams) { let container = self.selector(params.selector || params.container) || self.selector(selectorParams); self.log("this.code"); self.log("container"); self.log(container); var editorContainer = container.slice(1); var editor = ace.edit(editorContainer); var value = params.value; if (!params.do || (params.do == 'set')) { if (params.theme) editor.setTheme(params.theme); var editorMode = params.mode || "ace/mode/json"; editor.getSession().setMode(editorMode); var editorStyle = self.extend({ background: "rgba(255,255,255,0)" }, params.style); var codeOptions = self.extend({ fontSize: "11pt", selectionStyle: "line", highlightActiveLine: false, wrap: true, showLineNumbers: false, showGutter: false, fixedWidthGutter: false, readOnly: true, }, params.options); editor.setOptions(codeOptions); var codeString; if (typeof value == 'string') if (editorMode == "ace/mode/json") codeString = JSON.stringify(JSON.parse(value), null, '\t'); else codeString = value; else { if (editorMode == "ace/mode/json") codeString = JSON.stringify(value, null, '\t'); else { var functionObj = self.docElement(value.function); var functionParams = value.params; codeString = functionObj(functionParams); } } var codeRows = codeString.split(/\r\n|\r|\n/).length; editor.setValue(codeString, -1); } else if (params.do == 'get') { return editor.getValue(); } else { self.log('"code" function requires value param'); } }; /* Method: init Description: Functionality for init. @param {any} appString - Description for appString @param {any} modulesString - Description for modulesString @returns {any} - Result of the operation */ this.init = function (appString, modulesString) { console.log('init'); if (typeof appString == 'string') { let modules = [{ "name": "app", "url": appString }]; let modulesNames = (modulesString) ? modulesString.split(",") : []; for (let modName of modulesNames) { modules.push({ "name": modName, "url": "jsonic/modules/" + modName + ".json" }); } self.json.setup = { "modules": modules }; } else { if (appString) self.extendJson(self.json, appString); if (appString.css) self.defineCss(appString.css); } self.loadModuleGlobal(); }; /* Method: toJsonNode Description: Functionality for toJsonNode. @param {any} xml - Description for xml @returns {any} - Result of the operation */ function toJsonNode(xml) { let obj = {}; if (xml.nodeType == 1) { if (xml.attributes.length > 0) { obj["attr"] = {}; for (let j = 0; j < xml.attributes.length; j++) { let attribute = xml.attributes.item(j); obj["attr"][attribute.nodeName] = attribute.nodeValue; } } } if (xml.hasChildNodes()) { for (let i = 0; i < xml.childNodes.length; i++) { let item = xml.childNodes.item(i); let nodeName = item.nodeName; if (item.nodeType == 3 && nodeName == "#text") { if (/^\s+$/.test(item.nodeValue)) { } else obj.text = item.nodeValue; } else { if (typeof obj[nodeName] == "undefined") { obj[nodeName] = toJsonNode(item); } else { if (!Array.isArray(obj[nodeName])) obj[nodeName] = [obj[nodeName]]; obj[nodeName].push(toJsonNode(item)); } } } } return obj; } /* Method: htmlToJson Description: Functionality for htmlToJson. @param {any} text - Description for text @returns {any} - Result of the operation */ this.htmlToJson = function (text) { let xmlDoc = new DOMParser().parseFromString(text, "text/xml"); return JSON.stringify(toJsonNode(xmlDoc), null, "\t"); }; /* Method: elementToJson Description: Functionality for elementToJson. @param {any} selector - Description for selector @returns {any} - Result of the operation */ this.elementToJson = function (selector) { let el = document.querySelector(selector); return self.htmlToJson(el.getHTML()); }; /* Method: clearSelection Description: Functionality for clearSelection. @param {any} - No parameters @returns {any} - Result of the operation */ function clearSelection() { if (window.getSelection) { window.getSelection().removeAllRanges(); } else if (document.selection) { document.selection.empty(); } } /* Method: importHtml Description: Functionality for importHtml. @param {any} htmlText - Description for htmlText @returns {any} - Result of the operation */ this.importHtml = function (htmlText) { if (!htmlText) htmlText = prompt("html/xml"); if (htmlText) { let jsonDoc = self.htmlToJson(htmlText); let textarea = document.createElement("textarea"); textarea.value = jsonDoc; textarea.style = "position: absolute; z-index: 999999; background: white; width:100vw; height:100vh"; document.body.appendChild(textarea); textarea.addEventListener('click', function () { textarea.remove(); navigator.clipboard.writeText(textarea.value).then(() => console.log('copied!')); }); } }; if (typeof options == 'object') { } else if (options) self.init(arguments[0], arguments[1]); } var jsonApp = new jsonAppObj(); var js = jsonApp; var jsonic = jsonApp;