/*----------------------------- JSONIC V. 1.0.13 jsonic.io -------------------------------*/ // CHANGELOG // 1.0.13 jsonApp removed; [replaceProperties: include event properties] // 1.0.12 jsonApp; if is array option // 1.0.11 block blocks -> parts // 1.0.10 for: {name} work also with {value:name with path} (function replaceValue) // 1.0.8 for: {name} replaced with {value:name} // 1.0.5 set: if array of, the assignments follow the order // 1.0.4 deprecated: to assign without set (too ambiguous now that the key can be function, window.function, etc) // 1.0.3 "x": "2*3" if the value is a string, -> self.js(value) // 1.0.2 plugins ondemand // 1.0.1 jsonc support // 1.0.0 FUNCTIONS // 0.9.9 RESOURCES: Inside modules (resources will be deprecated) // 0.9.3 DEBUG: Rimosso break in docElement // 0.9.4 NOTE: In this.nested, commented and decommented nested.animate = partObj.animate; nested.if partObj.if, ... // 0.9.5 CLASS: "div btn": "content" =
content
// 0.9.6 DEBUG: in this.createElement newSelector (newSelector should be a dedicated function separated from selector) // 0.9.7 REMOVE: method to remove an element from the DOM / Restored html {attr} to set the attributes of an element // https://minify-js.com Input: 624.1 kB; Output: 95.46 kB; Compression: 84.7%, saving: 528.64 kB; // README // PRIORITY // in attr -> addStyle / removeStyle // instead of shortcuts the user can use {data shortcuts} // {arguments:value|default} -> ({arguments:value}) ? {arguments:value} : default // use (typeof id == "undefined") to understand if id is defined and is = 0 // css should call defineCss in any part of code // attr (addClass, removeClass, changeStyle direct methods?) can be changed (in element?) to avoid confusion with the use inside html // add remove element from array // debug of "set" key // can be useful to define pointers (shortcode/path of the objects) // https://dev.to/ternentdotdev/json-compression-in-the-browser-with-gzip-and-the-compression-streams-api-4135 // a method to append an image to the DOM in base64 format methods? no // check this.html notes // anime can be a part/block/key function? called with "ui:anime" asking for the relative plugin? // if the name of the block/part includes ":" it is more explicit // blocks or parts or keys or nodes? // parts -> blocks considering jsblocks.com? // Dynamic modules loading? What if we ask for a node that is in the main modules? // remove console from methods and add log in browser functions // add log of the error if the app or json module is not in json format // init, run, start -> do // if selector is an array, repeat the action (do) // think about html/do. Is it possible to avoid html object? Any unknown object is an html tag // in parts, {setup:on.success} or {setup:config.color} doesn't work // setup -> arguments // part ui:icon: {selector:, config:} can be a js function () {var part = {}; self.run(config); } // {arguments[0] arguments[1]. {1.setup} } // improve shortcuts (in extendJsonFromElement and in attr) // this.text -> this.content // html attribute of html method -> content (should be an html but can be multilingual) // property validation like the sintax (\w[\w+d+]) of the "name" in the "for" method ) // default "html" al posto di "text": ogni contenuto testuale viene inserito con innerHTML anziché innerTEXT // html [] tipo array e "" stringa (innerHTML) ok, html {} deprecato // "p": "text" -> p.innerTHTML('text') // "p": [] -> se item è oggetto -> htmlTag, se stringa dovrebbe fare append della stringa html sempre nello p. Ora invece crea più p.innerText // ADD: append. empty true fixed on html /* 1 page -> url (method and property) 2 dynamic class with ternary condition 3 swal button style 4 components copy bugs 5 installation guide 6 self.page -> not the variable but the real window path and window hash (can be jsonic.url) 7 page -> url 8 "roles" -> "only" 9 add localStorage actions -> ANY WINDOW method 10 add dataStorage 10 in parts {string} instead of {value} ? 11 on load image solution (should already work on: load -> animate -> fadein) */ // BUGS // BUG from Tailwind 3.3.2 // Sembra richiesto tailwind nel plugin Jsonic e non caricato dinamicamente come su eliokit.com // Different rendering width or without spaces after commans "alert": " {js:(1 == 2) ? \"test\" : \"false condition\"} " // HOW IT WORKS // loadModules -> loadPlugins -> Run // KNOWN BUGS // in museomira.it cerca "socialIcons", rimuovendo data-value l'icona finisce dentro contatti perché il newSelector è a:eq(5) // è necesario creare una funzione selector destinata ai nuovi elementi // PARTS // 1. Responsive header menu // 2. Alert // 3. Slide // 4. Form // 5. Table // GOAL // Reduce custom js code in Jsonic and move the functions in modules // Requires an extension of js method to make it more flexible // js {function: String, params: Array} // TO DO // inline use: data-jsonic -> jsonic.run(data-jsonic, selector); (es. in body) // init = run (or play) // in parts {setup} should get subreferences link {setup:on.success} // i plugins possono includere direttamente l'url // la gestione dei plugin dovrebbe essere centralizzata (riferimento a jsonic e non all'oggetto) // si potrebbe definire la distinsione tra oggetti specifici e oggetti globali (jsonic) // verificare se oggetto function con {name: , params: []} è assegnabile a variabili // addClass, removeClass etc with array // change the behaviour of p: [] become a a list of content, not a list of p // to do it, search and change "div": [ "p": [ "span": [ "li": [ "button": [ // hypothesis (no, more complete with actions): class="ui:button{text:#333;bg:#fff}" -> bg-[white] text-[#333] hover:bg-[#fff] hover:text-[white] // OPTIMIZATION: pluginsRequiredByTag only for self.json.resources.pluginsFunctions keys or better only for parts that requires plugins. alert -> ui:alert // getJSON: load json (id: exampleApp, url: ...), success-> {getJSON:exampleApp} // Ajax: load ajax (id: exampleApp, url: ...), success-> {ajax:exampleApp} // DOM: queryAll(selector) -> value is string, el.before(value) and all the other methods of an element of the dom // properties {dom:title} // https://www.w3schools.com/jsref/dom_obj_all.asp // DOCUMENT // https://www.w3schools.com/jsref/dom_obj_document.asp // {document: {title: 'test'}} // properties {document:title} // ON: https://www.w3schools.com/jsref/dom_obj_event.asp // "selector" can be "query" / no selector recalls querySelector // or APPEND/PREPEND // https://registry.npmjs.com/-/v1/search?text=tailwindcss&size=1 //https://api.npms.io/v2/package/tailwindcss // https://api-docs.npms.io /* TO DO 1. ajax call with an id to identify the data in case of simultaneous requests 1. database path should be separated by spaces (or slashes) replaceProperties default: check if if p1 is a function, if p2 -> value = p1(p2), if p3 -> value = p1(p2(p3)) if p1 is a value, and not p2, value = p1 self.methods[p1] or... p1 is a function {alert:string} {window.f} {window f1:window f2:window x} = window.f1(window.f2(window.x)) {querySelector:'.class':append} = window.f(jsonic.json.var.x) ESEMPI {new Date:'December 17, 1995 03:24:00'} {new Date().getDay} {console.log:'test'} {window.innerHeight} invece di {window:innerHeight} (specifica) o {js:window.innerHeight} il vantaggio di questo schema è che si evita un livello di parentesi annidate quando sono coinvolte variabili jsonic: {querySelector:var obj x:append} che puo diventare {querySelector:var {item} x:append} LIMITE questo metodo preclude l'accesso ad eventuali oggetti javascript var o data SOLUZIONE in realtà, var e data devono essere elementi definiti nel json altrimenti non sono trovati dall'interprete che può vagliare l'esistenza di una funzione js {path to a data} is a reference to a value in the data node of the Jsonic app if the action context (do) {path to an action} is a reference to a method or a sub app in the "parts" node of the Jsonic app if the html rendering context (html) {window.f:var x} = window.f(jsonic.json.var.x) {window.f:num} if is number {window.f:array} if isArray (more than one parameter) {window.f:'string'} {jsonic.f:var x} do: [ "functionName": [] // parameters ] check if functionName is a function html tags can't have a space or points... Align with ELIO Language: 1. "if": {"is": ["a", "=", "b","and"...] (retrocompatibile: se is è un array...) 2. "set": ["a", "+=", "1","*", "3"...] (retrocompatibile: se set è un array...) 3. "div classes": ... CODE REDUCING 1. string in "html" object that starts with a tag and continue with classes "html": [ "span appsDeviceListName ms-2 me-2 text-[16px] text-left w-[80%] leading-tight|content" ] NOTES // datapicker and other input fiels now are native https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date COMPONENTS MONACO TAILWINDCSS AUTOCOMPLETE (check Tailwindcss VS Code extensions) https://github.com/remcohaszing/monaco-tailwindcss FIREBASE STRUCTURE DATA If you create your own keys, they must be UTF-8 encoded, can be a maximum of 768 bytes, and cannot contain ., $, #, [, ], /, or ASCII control characters 0-31 or 127. You cannot use ASCII control characters in the values themselves, either. 24.4KB gzipped (85.24KB minified) 25.2KB minified + gzipped in 100ms 65ms 3G 3 Mbps (375 KBs) 10ms 4G 20 Mbps (2,5 MBs) <1ms 5G/Fiber 200 Mbps (25 MBs) TEST tailwindcss 104 KB 105 ms INTEGRATIONS: https://b2bsaasleads.com NEW PLUGINS: http://jakim.me/Toasty.js/ https://tingle.robinparisi.com GUIDE: COMPONENTS: reusable components / architectural philosophy ENGINE, (no hidden code) all the parts of the app is exposed to the developer / can set the layout and the behaviour JSON E' il modello di struttura ad albero usato da JSONIC per descrivere i dati, lo stile, e le azioni dell'applicazione SHORTCUTS: combinations of utility names (classes) to reuse in "class" property (from WindiCSS) // preloaded js/css plugins { "attr": { "class": "py-2 text-center" }, "subTitle": { "lang": { "it": "L'albero JSON dell'app può contenere i seguenti rami principali:", "en": "The JSON app tree may contain the following main branches:", "es": "El árbol de la aplicación JSON puede contener los siguientes ramas principales:" } } }, PROPERTIES With {property}, a string delimited by braces you can refer to any sub-branch the app tree and special properties. ----------------------- HOME PARAGRAPHS ----------------------- AUTO-LOADED PLUGINS NESTED CSS HTML has a clear nested and visual hierarchy but CSS doesn't. JSONIC let you nest your CSS definitions in a way that follows the same visual hierarchy of your HTML. It's similar to the SAAS extension but without the need to compile the code. In modo simile al linguaggio SAAS, è necessario compilare il codice // BP Questo dimostra che c'è bisogno di semplificazione più di quanto non si possa pensare IDE Special char (or shortener or autocomplete) with { } etcetera) PRIORITY: tags: button: "title" or button: { text: title color: color on: ... } buttonOutline: { text: title color: color on: ... } ------------------------ qualunque metodo: [ {"path": args}, {"path": args} {"path": args} ] ------------------------ DEBUG class must be a string otherwise log error style in attr must work (now error) CONFIG (now setup) extend the main branch {b:config} ACTIONS (now parts) extend the main branch {b:actions} DO execute one or an array of functions "do": "actionID" (string) execute the actions.actionID function CONTAINER (now selector) change the context to the element {b:container} Can be an object like {id, class, data-value} or a string with a CSS selector like "body > div:nt-child(2)" or a jquery-like selector like "body > div:eq(2)" ------------------------ bootstrap menu -> tailwind ------------------------ IDEAS - share the modules in the object "jsonic" with the other jsonic objects in the page - jsonic.registerJsMethod(name, function) register new js method to be inserted in jsonic.methods and called with "method": {params} - choose can contain the methods "next":"1" / "previous":"1" or step "+1"/"-1" - calendar can return the object {lang: {...}} - self.js can be embedded in self.compile (if typeof params == 'string') - Page doesn't exist / if admin / want to create it? - if no jsonic file for the page, create it on save - AUTH (debug) + GITHUB - preload font flag - IDE: Wordpress API new page - window methods in (docs) - for -> addTag (?) - setup: form to set setup properties - Method ARRAY "array": { "push": "{var:num}" (pop, shift, unshift, length) DONE: remove JSONIC references: jsonic.firebaseEventAction / jsonic.resizeEvent - HOME: docs / examples / integrations - wordpress: access to media API - iconify - iconify remove SVG old - colors -> setup (mmm) (like logo) - styles -> css -> senza categorie, solo elements '#div' -> https://transform.tools/css-to-js DONE } BUGS: - version è necessario in pluginsFunctions - shortcut as a node: attr / class values doesn't overwrite the shortcut WORDPRESS: (_embed to your URL will add the wp:featuremedia) https://jsonic.io/wp-json/wp/v2/media?&context=embed&per_page=100 https://jsonic.io/wp-json/wp/v2/media?&context=embed&after=2017-11-07T00:00:00 https://jsonic.io/wp-json/wp/v2/media?include=1681,491 // https://github.com/schlosser/pig.js NOTE: - autoupdate only if the previous update is complete (we need a param in config complete:true/false) - Play (create your app!) - add a tag in menu buttons ? - inViewport -> 'enter'/'exit' ? - inViewport solo la prima volta? - ('on': 'in'/out NO) confirm 'init'? - IDE: backup timeline - duplicato di this.selector dedicata a ottenere il selector di un nuovo elemento (su append e poco altro) - col: [1,2,3] -> row with col1 col2 col3 ? or tailwind grid solution (ragionare su soluzione di tag. esempio: flex: []) - in examples, test in posizione assoluta sul codice (utile su mobile) KEY BENEFITS - Integration (Jsonic code includes the logic, the layout and the style of the app on in one JSON object) - Accelerator */ // JQUERY to Vanilla: https://youmightnotneedjquery.com | http://vanilla-js.com // Jquery plus: https://atypiccraft.com/insights/reasons-why-we-still-use-jquery // https://cyrilletuzi.github.io/javascript-guides/jquery-to-javascript.html // Tools to integrate: https://bestofjs.org/tags // MINIFY: https://closure-compiler.appspot.com/home // https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=cat // INTEGRATIONS // https://www.dropzone.dev/js/ // uploadcare // zaiper // a graph js tool // anime.js // transition.style // analogo ad animate.style /* There were issues affecting this run of Lighthouse: There may be stored data affecting loading performance in this location: IndexedDB. Audit this page in an incognito window to prevent those resources from affecting your scores. // UI https://windicss.org/play.html https://basscss.com https://twind.dev https://emotion.sh/docs/introduction https://cssinjs.org/?v=v10.8.2 https://picturepan2.github.io/spectre/ https://get.foundation https://ant.design/ https://purecss.io https://onsen.io/ https://shuffle.dev/ */ //{"type": "js", "url":"https://cdn.jsdelivr.net/npm/tailwindcss@{version}/lib/index.min.js"}, //$.fn.jsonic = function(options) {return new jsonicObject(options);}; //jsonicApp = function(options) {return new jsonicObject(options);}; var jsonAppObj = function(options) { var self = this; console.log(); //this.options = options; /* var json = { // the jsonic app tree setup: {}, blocks: {}, // to be removed parts: {}, // plugins: {}, // TO DO: remove the error if included // css: {}, do: {}, on: {}, shortcuts: {}, texts: {}, data: {}, var: {} }; */ //var var = json.var; //this.setup = json.setup; // for external access this.json = { setup: {}, blocks: {}, // to be removed parts: {}, // plugins: {}, // TO DO: remove the error if included // css: {}, functions: {}, do: {}, on: {}, shortcuts: {}, texts: {}, data: {}, var: {} }; this.app = this.json; //var json = self.json; // TO DO: remove var alertObj = {}; var alertValues = {}; this.params = {}; // maybe can be removed 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']; // Source: https://www.w3schools.com/js/js_reserved.asp var nodes = { //parts: ['text', 'div', 'ul', 'p', 'a', 'button', 'input', 'span', 'img', 'video', 'audio', 'source', 'figure', 'figcaption', 'textarea', 'iframe', 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'svg', 'path', 'g', 'd', 'polygon', 'circle', 'small', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'form', 'form-group', 'label', 'select', 'option', 'optgroup', 'nav', 'tab', 'header', 'main', 'footer', 'ide', 'model-viewer', 'i', 'icon', 'pre', 'code','animateMotion','animateTransform','circle','clipPath','defs','desc','discard','ellipse','feBlend','feColorMatrix','feComponentTransfer','feComposite','feConvolveMatrix','feDiffuseLighting','feDisplacementMap','feDistantLight','feDropShadow','feFlood','feFuncA','feFuncB','feFuncG','feFuncR','feGaussianBlur','feImage','feMerge','feMergeNode','feMorphology','feOffset','fePointLight','feSpecularLighting','feSpotLight','feTile','feTurbulence','filter','foreignObject','g','hatch','hatchpath','image','line','linearGradient','marker','mask','metadata','mpath','path','pattern','polygon','polyline','radialGradient','rect','script','set','stop','switch','symbol','text','textPath','title','tspan','use','view'], //functions: ['do', 'function', 'for', 'run', 'module', 'page', 'html', 'text', 'empty', 'alert', 'blocks', 'attr', 'color', 'set', 'array', 'replace', 'var', 'js', 'javascript', 'if', 'switch', 'choose', 'delay', 'ajax', 'hide', 'show', 'toggle', 'in', 'out', 'link', 'scroll', 'lang', 'find', 'data', 'reload', 'calendar', 'moment', 'dayjs', 'log', 'setInterval', 'clearInterval', 'offcanvas', 'firebase', 'database', 'qrcode', 'editor', 'ace', 'code', 'thunkable', 'animate', 'sortablejs', 'uiUpdate'], // 'String', 'Number', 'Math', //functionsWithContainer: ['for', 'editor', 'ace', 'code', 'qrcode', 'lottie', 'animate', 'html', 'hide', 'show', 'toggle', 'in', 'out', 'if', 'ajax', 'attr', 'run', 'delay'], // not execute extend: ['setup', 'blocks', 'parts', 'css', 'actions', 'texts', 'data', 'functions'], // also plugins? (TO DO: remove actions) params: ['style', 'on', 'matchMedia', 'action', 'code', 'roles', 'plugins', 'css'], // 'if', 'attr', 'text'. 'html' exclude: ['setup', 'container', 'selector', 'info', 'note', 'comment', 'lang', 'tag', 'plugins', 'template'] }; /* * Converts a JSON object to a JSON Schema * @param {any} json * @param {object} options * @returns {object} a json schema */ // [{"name": "vito", "gallery": {"name":2, "date":"10-10-2012"}, "num":3, "bool":true, "color": "#ff0000"}] 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]?)$/, // J. Meijer / Stackoverflow / 15491894 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})$/, // Joey / Stackoverflow / 1636350 color: /^#(?:[0-9a-fA-F]{3}){1,2}$|#(?:[0-9a-fA-F]{3,4}){1,2}$/, }; this.jsonToSchema = function (json, options = {}) { // https://github.com/mohsen1/json-to-json-schema if (typeof json === 'function') { throw new TypeError('Can not convert a function'); } if (json === undefined) { return {}; } // primitives 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 all schemas are the same use that schema for items if (schemas.every(s => self.isEqual(s, schemas[0]))) { schema.items = schemas[0]; // if there are multiple schemas use oneOf } 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; }; this.isEqual = function (a, b) { return (JSON.stringify(a) == JSON.stringify(b)); }; //var canvasElement = document.getElementById("canvas"); // * this is not important for PDFMake, it's here just to render the result * // It's a Mozilla lib called PDFjs that handles pdf rendering directly on the browser /* this.pdfjs = function (params, selectorParams) { var url = params.url; var options = params.options || { scale: 1.4 }; let container = self.selector(params.selector || params.container) || self.selector(selectorParams); var canvasContainer = self.query(container); function renderPage(page) { var viewport = page.getViewport(options.scale); var wrapper = document.createElement("div"); wrapper.className = "canvas-wrapper"; var canvas = document.createElement('canvas'); var ctx = canvas.getContext('2d'); var renderContext = { canvasContext: ctx, viewport: viewport }; canvas.height = viewport.height; canvas.width = viewport.width; wrapper.appendChild(canvas) canvasContainer.appendChild(wrapper); page.render(renderContext); } function renderPages(pdfDoc) { for(var num = 1; num <= pdfDoc.numPages; num++) pdfDoc.getPage(num).then(renderPage); } PDFJS.disableWorker = true; PDFJS.getDocument(url).then(renderPages); } */ //renderPDF('https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf', document.querySelector('#canvas')); /* this.localStorage = function (params) { // -> use self.method if (params.getItem) return localStorage.getItem(params.get); else if (params.setItem) return localStorage.setItem(params.setItem.name, params.setItem.value); } */ // UTILITY /** A storage solution aimed at replacing jQuerys data function. * Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap]. * This makes sure the data is garbage collected when the node is removed. */ 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; } }; // JQUERY cross-over 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; } }; 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; }; /* this.actionResult = function(value, args) { // value -> params // Methods with a result if (value && typeof value == 'object') { // jsonic methods if (value.js) { return self.js(value.js, args); } else if (value.array) { return self.array(value.array, args); } else if (value.calendar) { return self.calendar(value.calendar, args); } else if (value.data) { return self.data(value.data, args); } else if (value.var) { return self.var(value.var, args); } else if (value.module) { return self.module(value.module, args); } else if (value.color) { return self.color(value.color, args); } else if (value.css) { return self.css(value.css, undefined, args); } else if (value.if) { return self.if(value.if, undefined, args); } else if (value.switch) { return self.switch(value.switch, args); } else if (value.database) { return self.database(value.database, args); // js methods } else if (value.Math) { return self.Math(value.Math, args); } else if (value.Number) { return self.Number(value.Number, args); } else if (value.String) { return self.String(value.String, args); // plugin methods } else if (value.ace) { return self.ace(value.ace, args); // else if (value.code) { // return self.code(value.code, args); } else if (value.moment) { return self.moment(value.moment, args); } else if (value.dayjs) { return self.dayjs(value.dayjs, args); } else if (value.function) { // TO DO: remove (replaced by do) return self.function(value.function, value.params); } else { return value; } } else { return value } //} else if (typeof value == 'string') { // return self.javascript(value, args); } */ this.var = function (params, args) { if (Array.isArray(params)) { for (var index in params) self.var(params[index], args); } else { //self.log('var'); var name; var value; var varValue; if (params.path && !params.name) name = self.path(params.path, args, '.'); if (typeof params == 'string') { // gives a variable value name = self.replaceProperties(params, args); /* self.log('name'); self.log(name); */ /* self.log('typeof params == string'); self.log('params'); self.log(params); self.log('name'); self.log(params); */ varValue = self.docElement('self.json.var.' + name); /* self.log('varValue'); self.log(varValue); */ } else { /* self.log('var'); self.log('params'); self.log(params); self.log('args'); self.log(args); */ //self.log('params'); //self.log(params); var paramsReplaced = self.replaceProperties(params, args); //self.log('paramsReplaced'); //self.log(paramsReplaced); name = paramsReplaced.name; value = paramsReplaced.value; var operator = paramsReplaced.operator; var type = paramsReplaced.type; /* self.log('extend'); self.log(extend); */ 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); /* self.log('name'); self.log(name); self.log('pathBase'); self.log(pathBase); self.log('pathLast'); self.log(pathLast); self.log('varObj'); self.log(varObj); */ if (value !== undefined) { //if (value == 'string') // value = self.docElement('self.json.var.'+value); // todo //else value = self.actionResult(value, args); // typization 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; } //self.log('value'); //self.log(value); /* // reset if (value == undefined && typeof value == 'string') value = ''; if (value == undefined && typeof value == 'number') value = 0; if (value == undefined && typeof value == 'object') value = {}; */ /* self.log('operator'); self.log(operator); self.log('pathLast'); self.log(pathLast); self.log('varObj[pathLast]'); self.log(varObj[pathLast]); */ 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; } /* operators: [ '=', '>', '<', '!', '~', '?', ':', '==', '<=', '>=', '!=', '&&', '||', '++', '--', '+', '-', '*', '/', '&', '|', '^', '%', '<<', '>>', '>>>', '+=', '-=', '*=', '/=', '&=', '|=', '^=', '%=', '<<=', '>>=', '>>>=' ], */ //self.log('varObj[pathLast]'); varValue = varObj[pathLast]; } else { /* self.log('pathString'); self.log(pathString); */ //varValue = self.docElement(pathString, value); //varValue = value; self.docElement(pathString, value); /* self.log('name'); self.log(name); self.log('var '+name); self.log(self.var(name)); */ } /* self.log('pathLast'); self.log(pathLast); self.log('varObj[pathLast]'); self.log(varObj[pathLast]); */ /* //alert(value); //value = self.replaceProperties(value, args); if (value == 'string') { //self.json.var[name] = self.docElement('self.json.var.'+value); varObj[pathLast] = self.docElement('self.json.var.'+value); } else { //self.json.var[name] = self.actionResult(value, args); varObj[pathLast] = self.actionResult(value, args); } */ //self.log('varObj[pathLast]'); //if (self.isJson(self.json.var[name])) // self.json.var[name] = self.parse(self.json.var[name]); } 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 { // no "value" property: return the value of the var "name" varValue = varObj[pathLast]; /* varValue = self.replaceProperties(varObj[pathLast], args); alert(JSON.stringify(varValue)); */ } //varValue = self.json.var[name] || {}; // to check } 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); //alert(JSON.stringify(params.do)); //self.do(params.do, args); self.do(params.do, undefined, args); } } return varValue; } }; 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 { // if (typeof params.value == 'string') { for (var key in params.value) { if (params.value[key] == item[key]) return item; } } } }); } }; /* this.data = function (params, args) { if (typeof params == 'string') return self.db(params, args); else self.firebase(params, args); } */ this.array = function (params, args) { /* self.log("---- this.array ----"); self.log('params'); self.log(params); */ if (args) params = self.replacePropertyWithPrefix(params, 'result', args); for (var par in params) { var paramReplaced = self.replaceProperties(params[par], args); //value[par](params[par]) // ipotesi di eseguire in automatico qualunque funzione js su stringhe /* self.log("par"); self.log(par); self.log("params[par]"); self.log(params[par]); self.log("paramReplaced"); self.log(paramReplaced); */ params[par] = paramReplaced; } //self.log("params"); //self.log(params); var value = self.element({ path: params.name }) || []; /* self.log("value"); self.log(...value); */ 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 }); }; this.replace = function (params, args) { // self.log("---- this.replace ----"); params = self.replacePropertyWithPrefix(params, 'result', args); /* self.log("params"); self.log(params); */ var value = self.element({ path: params.path }) || []; var to = params.to || ''; var type = typeof value; /* self.log("type"); self.log(type); */ if (type !== "string") value = JSON.stringify(value); /* self.log("value 1"); self.log(value); */ if (params.from) value = self.replaceAll(value, params.from, to); /* self.log("value2 "); self.log(value); */ switch (type) { case "number": value = Number(value); break; case "boolean": value = Boolean(value); break; case "object": value = JSON.parse(value); break; } /* self.log("value 3"); self.log(value); */ //return value; return self.element({ path: params.path, value: value }); }; 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 }); } } }; this.set = function (params, args) { if (Array.isArray(params)) { // 1.0.5 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); // TO DO: check if (value && args) value = self.replacePropertyWithPrefix(value, 'result', args); // backward compatibility TO DO: remove self.element({ path: param, value: value }); } } //return true }; this.get = function (element) { //self.log('self.get'); 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 }; 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; 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); }; /* 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); } } */ 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://app.fixo.io:4002'; 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 multipleFiles = []; /* this.fileDownload = function (url) { self.log('fileDownload'); self.log(url); var fileArr = url.split('?'); self.log(fileArr); //var file = fileArr[0]; var urlArr = fileArr[0].split('/'); self.log(urlArr); var name = urlArr[urlArr.length-1]; self.log(name); var token = self.getParameterByName('token', url); self.log(token); window.location.href = '/app/php/proxy.php?name='+ name + '&url='+ url; } */ /* this.fileUrl = function (params) { // da nome file a l'url Firebase Storage inclusiva del token self.log('fileUrl'); self.log(params); // self.log('storage'); // self.log(storage); if (storage) { var storageRef = storage.ref(); var pathReference = storageRef.child(params.user+'/'+params.name); pathReference.getDownloadURL().then(function(url) { if (params.callback) params.callback(url); }).catch(function(error) { if (error && error.code && params.error) { self.log(self.firebaseStorageError(error.code)); params.error(error.code); } // A full list of error codes is available at // https://firebase.google.com/docs/storage/web/handle-errors }); } else { self.log('storage undefined'); } } */ /* this.firebaseStorageError = function (errorCode) { switch (errorCode) { case 'storage/object-not-found': // File doesn\'t exist return 'File doesn\'t exist'; case 'storage/unauthorized': // User doesn\'t have permission to access the object return 'User doesn\'t have permission to access the object'; case 'storage/canceled': // User canceled the upload return 'User canceled the upload'; case 'storage/unknown': // Unknown error occurred, inspect the server response return 'Unknown error occurred, inspect the server response'; default: return 'No error' } } */ var x = [{ if: 3 }, function () { }, 3, []]; this.firebaseAddListener = function (params) { /* self.log('firebaseAddListener'); self.log(params); */ // {path, orderByChild, equalTo} //self.log(params.path); if (database) { // Aggiunge listener in ascolto su params.path che esegue params.action if (params.action) { if (!self.listeners[params.path]) self.listeners[params.path] = []; /* alert('params.action:'+params.action); alert('type params.action:' + typeof params.action); alert(params.path+':'+JSON.stringify({ action: params.action })); */ //if (Array.isArray(params.action)) // self.listeners[params.path].concat(params.action); //else self.listeners[params.path].push(params.action); } /* if (params.success !== undefined) { alert('params.success:'+params.success); alert('type params.success:' + typeof params.success); alert(params.path+':'+JSON.stringify({ success: params.success })); self.listeners[params.path].push(params.success); } */ //self.log('params.path: '+ params.path); //self.listeners[params.path] = params.action; //alert(self.listeners[params.path]); /* limitToFirst() Sets the maximum number of items to return from the beginning of the ordered list of results. limitToLast() Sets the maximum number of items to return from the end of the ordered list of results. startAt() Return items greater than or equal to the specified key or value, depending on the order-by method chosen. startAfter() Return items greater than the specified key or value depending on the order-by method chosen. endAt() Return items less than or equal to the specified key or value, depending on the order-by method chosen. endBefore() endBefore() Return items less than the specified key or value depending on the order-by method chosen. equalTo() Return items equal to the specified key or value, depending on the order-by method chosen. orderByChild() Order results by the value of a specified child key or nested child path. orderByKey() Order results by child keys. orderByValue() Order results by child values. orderByPriority() Order results by priority https://firebase.google.com/docs/reference/js/v8/firebase.database.Query */ //Firestore.collection(collectionName).orderBy(field).where(field, ">=", keyword.toUpperCase()).where(field, "<=", keyword.toUpperCase() + "\uf8ff").get() // https://medium.com/feedflood/filter-by-search-keyword-in-cloud-firestore-query-638377bf0123 // https://firebase.google.com/docs/database/rest/retrieve-data?hl=it#range-queries // startAt , endAt , limitToFirst , limitToLast o equalTo //databaseReference.orderByChild('_searchLastName').startAt(queryText).endAt(queryText+"\uf8ff") // where ("string, "in"/"not-in", array) // https://firebase.google.com/docs/firestore/query-data/queries?hl=it#in_and_array-contains-any 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]); // maybe params.where in enough var feedback = dbRef.on('value', firebaseEvent); //console.log(feedback); /* console.log('dbRef'); console.log(dbRef); */ /* if (params.orderByChild && params.equalTo) dbRef.orderByChild(params.orderByChild).equalTo(params.equalTo).on('value', firebaseEvent); else dbRef.on('value', firebaseEvent); */ } else { self.log('database undefined'); // Restart the db } }; 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(); //if (!dbVal) dbVal = {}; var pathArr = path.split(/\.\w+\//); var dbPath = pathArr[1]; self.log('firebaseEvent: ' + dbPath); //if (var.databaseURL) dbPath = path.substr(var.databaseURL.length+1); //else dbPath = path; /* self.log('path: '+ path); //self.log('var.databaseURL: '+ var.databaseURL); self.log('dbPath: '+ dbPath); */ if (dbVal) self.localDbUpdate(dbVal, dbPath); else { var dbObj = self.element({ path: 'self.json.var.db.' + self.replaceAll(dbPath, '/', '.') }); if (dbObj) dbObj = null; //delete dbObj; } //self.do(self.listeners[dbPath], dbVal); } }; this.localDbUpdate = function (newObj, dbPath) { /* self.log('localDbUpdate'); self.log(newObj); self.log(dbPath); */ //var path = newObj.path; //delete newObj.path; /* self.do( { var: { name: "db."+self.replaceAll(dbPath, '/', '.'), value: newObj, //success: function () { // self.do(self.listeners[dbPath], newObj); //} } } ); */ //alert('db.'+self.replaceAll(dbPath, '/', '.')); /* var dbUpdateAction = { var: { name: 'db.'+self.replaceAll(dbPath, '/', '.'), value: newObj //do: (self.listeners[dbPath] && self.listeners[dbPath].length > 0) ? self.listeners[dbPath] : undefined } }; if (self.listeners[dbPath] !== undefined && self.listeners[dbPath] !== null && self.listeners[dbPath].length > 0) dbUpdateAction.var.do = self.listeners[dbPath]; newObj.path = dbPath; self.do(dbUpdateAction, newObj); */ // TO DO: decide l'utente dove salvare i dati newObj = Object.fromEntries(Object.entries(newObj).reverse()); //newObj = Object.keys(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], newObj); self.do(self.listeners[dbPath], undefined, newObj); } } }; this.firebaseRemoveListener = function (params) { // Rimuove listener in ascolto su data.path self.log('firebaseRemoveListener'); if (self.listeners[params.path]) { delete self.listeners[params.path]; var dbRef = database.ref(params.path); dbRef.off(); } }; // Rimuove un elemento del database 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) { //Dati impostati con successo if (error == null) { self.log('set SUCCESS'); result = { success: true }; } else { self.log('set ERROR'); //Errore inserimento dati result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; // Write or replace data to a defined path this.firebaseSet = function (path, value, callback) { /* set Write or replace data to a defined path, like messages/users/ update Update some of the keys for a defined path without replacing all of the data push Add to a list of data in the database. Every time you push a new node onto a list, your database generates a unique key, like messages/users// transaction Use transactions when working with complex data that could be corrupted by concurrent updates */ if (database) { var result, dbRef; if (path) { dbRef = database.ref().child(path); } else { dbRef = database.ref(); } return dbRef.set(value, function (error) { //Dati impostati con successo if (error == null) { self.log('set SUCCESS'); result = { success: true }; } else { self.log('set ERROR'); //Errore inserimento dati result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; // Update some of the keys for a defined path without replacing all of the data 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) { //Dati impostati con successo if (error == null) { self.log('update SUCCESS'); result = { success: true }; } else { self.log('update ERROR'); //Errore inserimento dati result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; // Add to a list of data in the database. Every time you push a new node onto a list, your database generates a unique key, like messages/users// 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) { //Dati impostati con successo if (error == null) { self.log('push SUCCESS'); result = { success: true }; } else { self.log('push ERROR'); //Errore inserimento dati result = { success: false, error: error }; } if (callback) callback(result); }); } else { self.log('database not initialized'); } }; // https://firebase.google.com/docs/database/security/rules-conditions // tutte le get / o listeners / potrebbero essere basate su orderByChild("owner") /* rooms": { // this rule applies to any child of /rooms/, the key for each room id // is stored inside $room_id variable for reference "$room_id": { "topic": { // the room's topic can be changed if the room id has "public" in it ".write": "$room_id.contains('public')" } } } */ /* this.firebaseQuery = function(params) { self.log('firebaseQuery'); self.log(params); // path = 'users/'+self.user('email') // value = 'guest' var dbRef = database.ref(params.path); if (!params.result) params.result = {}; if (params.value && !Array.isArray(params.value)) { var buffer = params.value; params.value = []; params.value[0] = buffer; } //self.log('params.value'); //self.log(params.value); if (params.value && params.value.length > 0) { var value = params.value.shift(); //self.log('value'); //self.log(value); //self.log('params.key'); //self.log(params.key); dbRef.orderByChild(params.key).equalTo(value).once('value', (object) => { self.log('object'); self.log(object); if(object) { params.result = self.extend(params.result, object.val()); if (params.value.length > 0) self.firebaseQuery(params); else params.callback({ success: true, error: null, data: params.result }); } else { //self.log('firebaseQuery ERROR'); //result = {success:false, error:8}; params.callback({ success:true, error:null, data: params.result }); } }); } else { params.callback({success:false, error:null}); } } */ this.firebaseGetPart = function (params) { self.log('firebaseGetPart'); let remotePath = self.replaceAll(params.localPath, '.', '/'); self.log('localPath:' + params.localPath); //self.log('remotePath:'+remotePath); 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) { //Dati recuperati con successo if (object) { self.log('firebaseGetPart SUCCESS'); self.log(object); // local db update 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+\//); // split on the domain extension let dbPath = pathArr[1]; // path after the domain extension let localPath = self.replaceAll(dbPath, '/', '.'); //var dbPath = path.substr(var.databaseURL.length+1); self.log('dbPath: ' + dbPath); self.log('localPath: ' + localPath); //self.log('self.partContainers[localPath]'); //self.log(self.partContainers[localPath]); self.element({ path: localPath, value: dbVal }); for (partObj of self.partContainers[localPath]) { /* self.log('partObj'); self.log(partObj); */ let part = self.replacePropertyWithPrefix(dbVal, 'setup', partObj.setup); part = self.replacePropertyWithPrefix(part, 'arg', partObj.arg); self.extendJsonFromElement(part); // or selectorParams /* self.log('part'); self.log(part); */ self.html(part, partObj.container); //self.run(part, partObj.container); //self.run(dbVal, container); } } } } else { self.log('firebaseGetPart ERROR'); result = { success: false, error: 8 }; } //self.log(result); //callback(result); }); } }; /* { "database": { "do": "get", "path": "apps/dev/{setup:key}", "on": { "success": [ { */ 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); } }); }; this.firebaseGet = function (path, callback) { self.log('firebaseGet:' + path); var result = { success: false, error: 7 }; if (path) { // try, if path is wrong "Uncaught TypeError: Cannot read properties of undefined (reading 'ref')" dbRef = database.ref().child(path); } else { dbRef = database.ref(); } /* if (false) { //path == 'files') { //alert(self.user('email')); return dbRef.orderByChild('users/'+self.user('email')).equalTo('guest').on('value', (object) => { //return dbRef.orderByChild('prefs/authorId').equalTo(self.user('uuid')).on('value', (object) => { //return dbRef.orderByChild('users').equalTo(self.user('email')).on('value', (object) => { //self.log(object); //var user = object.val(); //Dati recuperati con successo if(object) { result = {success:true, error:null, data: object.val()}; } else { self.log('get ERROR'); //Errore recupero dati result = {success:false, error:8}; } //self.log(result); callback(result); }); } else { */ // ATTENZIONE: va intercettato e loggato l'errore di accesso negato dalle regole return dbRef.once('value').then(function (object) { //Dati recuperati con successo if (object) { self.log('get SUCCESS'); result = { success: true, error: null, data: object.val() }; // local db update if (object.val() !== undefined) { var dbVal = object.val(); var path = object.ref.toString(); if (!dbVal) dbVal = {}; var pathArr = path.split(/\.\w+\//); // split on the domain extension var dbPath = pathArr[1]; // path after the domain extension //var dbPath = path.substr(var.databaseURL.length+1); self.log('dbPath: ' + dbPath); self.localDbUpdate(dbVal, dbPath); } } else { self.log('get ERROR'); //Errore recupero dati result = { success: false, error: 8 }; } //self.log(result); callback(result); }); //} }; this.stringToKey = function (str) { return str.replace(/\./g, '%2E'); }; this.keyToString = function (key) { return key.replace(/%2E/g, '.'); }; this.firebaseKey = this.getKey = function (path) { var dbRef = database.ref(path); return dbRef.child(path).push().getKey(); }; // -------------- // SELECTOR // -------------- this.exist = function (selector) { console.log('selector'); console.log(selector); console.log(Boolean(self.query(selector))); return Boolean(self.query(selector)); }; this.count = function (selector) { //self.log('count:'+selector+ '='+ self.queryAll(selector).length); return self.queryAll(selector).length; /* if (selector) { var routes = selector.split(/[ >]+/); if (!element) element = document; for (var index in routes) { var route = routes[index]; //onsole.log('route'); //self.log(route); var routeParts = route.match(/(.*):eq\((\d*)\)/); //self.log('routeParts'); //self.log(routeParts); if (routeParts) { var routeElement = String(routeParts[1]); var routeIndex = Number(routeParts[2]); element = element.querySelectorAll(routeElement)[routeIndex]; } else { element = element.querySelectorAll(route)[0]; } } */ /* var elements = self.query(selector); if (elements) return elements.querySelectorAll().length; else return 0 */ /* if (self.exist(selector)) return document.querySelectorAll(selector).length; else return 0 */ }; var log = function (id, value) { self.log(id); self.log(value); }; this.classSelector = function (selClass) { if (selClass.indexOf('.') == 0) { selClass = String(selClass).substr(1); } // backward compatibility let classes = selClass.split(' '); selClass = classes[0]; /* self.log('selClass'); self.log(selClass); */ // avoid dynamic classes as selector var regex = new RegExp('[\-][\[]'); if (selClass && selClass.match(regex)) selClass = classes[1]; if (selClass && selClass.match(regex)) selClass = classes[2]; return selClass; }; this.selector = function (params, containerParams, selectAll) { // {container, class, value, id} var selector; if (params) { if (typeof params == 'string') { /* self.log('this.selector'); self.log(params); */ 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 selContainer = container; //data.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 (selId) selId = self.compile(selId); if (selValue) selValue = self.compile(selValue); if (selClass) selClass = self.compile(selClass); */ // use the first class as selector if (selClass) selClass = self.classSelector(selClass); //if (!selectAll) selClass = undefined; 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; //if (!selectAll) // selector += ':eq(' + self.count(selector) + ')'; // qui c'è / c'era un baco: // quando proviamo a eseguire un'azione su un elemento esistente // usando solo la classe come selector, $(selector).length = 1 // quindi prova a selezionare il secondo elemento eq(1), non il primo eq(0) } else if (params.tag) { //if (selContainer) selector = selContainer; selector = params.tag; if (selContainer) { selector = selContainer + ' > ' + params.tag; if (!selectAll) { //if (count !== $(selector).length) self.log('>> '+ selector + ' count:'+ self.count(selector) + ' !== ' + $(selector).length ); selector += ':eq(' + self.count(selector) + ')'; //selector += '[' + self.count(selector) + ']'; //selector += ':eq(' + $(selector).length + ')'; } } else { if (!selectAll) { selector += ':eq(' + self.count(selector) + ')'; //selector += '[' + self.count(selector) + ']'; } } } else { selector = selContainer; }; } return selector; } }; // -------------- // TEXTS // -------------- this.stringify = function (obj) { if (typeof obj == 'object') try { return JSON.stringify(obj); } catch (error) { return obj; } else return obj; }; this.parse = function (str) { if (typeof str == 'string') try { return JSON.parse(str); // json } catch (error) { return str; // non json } else return str; }; /* this.removeEventProperties = function (params) { 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; } return paramsObj; }; */ self.setupId = 0; this.replacePropertyWithPrefix = function (params, prefix, args) { var paramsString; if (typeof params == 'object') paramsString = self.stringify(params); else paramsString = String(params); /* let argsWithProperties = (args) ? JSON.stringify(args) : ''; paramsString = self.replaceAll(paramsString, '"{'+prefix+'}"', argsWithProperties); // obsolete */ //if (typeof args == undefined) // self.log('replacePropertyWithPrefix args is undefined', 'yellow'); 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 }); //let value = self.element({path:path, root: args}); /* if (typeof value == undefined) { self.log(match + ' not found', 'orange'); value = ''; } else */ 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; } }); /* if (paramsString && paramsString.indexOf('Contacts')>= 0) { self.log(paramsString, 'green'); } */ 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 }); //let value = self.element({path:path, root: args}); /* if (typeof value == undefined) { self.log(match + ' not found', 'orange'); value = ''; } else */ if (value === undefined) return ''; else if (typeof value == 'object') // when object inside a string? 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; } }; /* this.replaceProperty = function (params, name, args) { // TO DO: change name in replaceArguments //console.log('replaceProperty:'+name); //var actions = {}; if (typeof params == 'object') { params = self.stringify(params); } if (typeof args !== 'string') { let argsWithProperties = (args) ? JSON.stringify(args) : ''; params = self.replaceAll(params, '"{'+name+'}"', argsWithProperties); // obsolete // TO DO: get self.element({path:key, root: args}); for (let key in args) { if (typeof args[key] !== undefined) { if (typeof args[key] == 'object') params = self.replaceAll(params, '"{'+name+' '+key+'}"', JSON.stringify(args[key])); else params = self.replaceAll(params, '{'+name+' '+key+'}', args[key]); } else { params = self.replaceAll(params, '{'+name+' '+key+'}', ''); self.log('{'+name+' '+key+'}' + ' not found', 'yellow'); } } for (let key in args) { if (args[key]) { if (typeof args[key] == 'object') params = self.replaceAll(params, '"{'+name+':'+key+'}"', JSON.stringify(args[key])); else params = self.replaceAll(params, '{'+name+':'+key+'}', args[key]); } else { params = self.replaceAll(params, '{'+name+':'+key+'}', ''); } } } else { //console.log('args STRINGA'); params = self.replaceAll(params, '{'+name+'}', args); } if (self.isJson(params)) {// (typeof params == 'object') var paramsObj = self.parse(params); return paramsObj; } else { //alert(paramsString); return params; } } */ 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); } /* self.log('replaceResult'); self.log('params'); self.log(params); */ if (self.isJson(params)) { // (typeof params == 'object') var paramsObj = self.parse(params); if (paramOn) paramsObj.on = paramOn; if (paramSuccess) paramsObj.success = paramSuccess; if (paramError) paramsObj.error = paramError; return paramsObj; } else { //alert(paramsString); return params; } }; /* this.replaceTags = function (params, selectorParams) { self.log('replaceTags'); var undef = false; if (params.text && (typeof params.text == 'string' || typeof params.text == 'object')) { //alert(params.text); params.text = self.stringify(params.text); // i tag speciali sono contenuti tra i caratteri { e } if (params.text.indexOf('{') >= 0) { // alert(params.text.indexOf('{')); // <{visible:element}> params.text = params.text.replace(/\<\{visible\:([^\}]*)\}\>/g, function(match, p1, offset, string) { var value = ($(p1).is(':visible')); return value; }); // <{var:var.object}> params.text = params.text.replace(/\<\{this\:([^\}]*)\}\>/g, function(match, p1, offset, string) { var value = self.json[p1]; if (!value) undef = true; return self.stringify(value); }); // <{data:value}> params.text = params.text.replace(/\<\{data\:([^\}]*)\}\>/g, function(match, p1, offset, string) { var value = self.json.var[p1]; if (!value) undef = true; return self.stringify(value); }); params.text = params.text.replace(/\<\{var\:([^\}]*)\}\>/g, function(match, p1, offset, string) { var value = self.get(p1); if (!value) undef = true; return self.stringify(value); }); params.text = params.text.replace(/\<\{param\:([^\}]*)\}\>/g, function(match, p1, offset, string) { var value = self.params[p2]; if (!value) undef = true; return value; }); // <{value:[id]}> params.text = params.text.replace(/\<\{value\:([^\}]*)\}\>/g, function(match, p1, offset, string) { var value = $('#'+p1).val(); // https://www.geeksforgeeks.org/html-value-attribute/ if (!value) undef = true; return value; }); // <{user:[fieldName]}> params.text = params.text.replace(/\<\{user\:([^\}]*)\}\>/g, function(match, p1, offset, string) { var value = self.user(p1); if (!value) undef = true; return self.stringify(value); }); // <{time:timestamp}> params.text = params.text.replace(/\<\{time\:timestamp\}\>/g, self.getTimestamp()); // <{result}> if (params.args) { params.args = self.stringify(params.args); params.text = params.text.replace(/\<\{result\}\>/g, params.args); } // <{function:app.mac}> params.text = params.text.replace(/\?/g, function(match, p1, offset, string) { var functionName = self.docElement(p1); return functionName(selectorParams); }); // <{random}> params.text = params.text.replace(/\<\{random\:([^\-]+)\-([^\}]+)\}\>/g, function(match, p1, p2, offset, string) { return Number(p1)+Math.round((p2-p1)*Math.random()); }); // <{firebaseKey:path}> params.text = params.text.replace(/\<\{firebaseKey\:([^\}]*)\}\>/g, function(match, p1, offset, string) { return self.firebaseKey(p1); }); } if (undef) return undefined else return self.parse(params.text); } else { //self.log('params.text undefined or number or boolean'); return params.text; } } */ this.langText = function (textId) { // find text in language and follow the capitalization of textId // we could need text in langId language 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]]; //textValue = textObj[langId] || textObj[self.json.setup.language] || textObj['en']; } return textValue; } else { return textId; } /* if (self.json.texts[textId]) textObj = self.json.texts[textId]; else if (self.json.texts[textId.toLowerCase()]) textObj = self.json.texts[textId.toLowerCase()]; //else if (self.json.texts[textId.toUpperCase()]) // textObj = self.json.texts[textId.toUpperCase()]; if (textObj) { var textValue = textObj[self.json.setup.language] || textObj['en'] || textId; if (textId.charAt(0) == textId.charAt(0).toUpperCase()) // first char uppercase if (textId.charAt(1) == textId.charAt(1).toUpperCase()) return textValue.toUpperCase(); else return textValue.replace(/\b\w/, l => l.toUpperCase()); // capitalize // textValue = textValue.charAt(0).toUpperCase() + name.slice(1) // style: text-transform: capitalize; else return textValue.toLowerCase(); } else { return textId; } */ /* } else { self.log('textId undefined in langText'); } */ }; this.lang = function (params, args) { if (args) { var value = self.replaceProperties(params, args); self.json.setup.language = value; //alert(value); self.log('lang'); self.log(value); document.querySelectorAll('[data-text]').forEach(function (element, index) { //$('*[data-text]').each(function( index ) { var dataParams = self.dataStorage.get(element, 'params'); var selector = self.dataStorage.get(element, 'selector'); /* self.log('index'); self.log(index); self.log('dataParams'); self.log(dataParams); */ //alert(JSON.stringify(dataParams)); self.html(dataParams, { selector: selector }); //self.text($(this).data('params'), {container: this}); }); /* var elements = document.querySelectorAll('[data-text]'); self.log('elements'); self.log(elements); //var elements = document.querySelectorAll(selector); if (elements) elements.forEach(function (element, index) { self.log(index); //var dataParams = self.dataStorage.get(element, 'params'); var dataSelector = self.attribute(element, 'data-selector'); //self.text(dataParams, {container: dataSelector}); self.text($(dataSelector).data('params'), {container: dataSelector}); }); */ } else { return self.json.setup.language; } }; // Determine whether is possible to write an image/text to the clipboard. var isClipboardWritingAllowed = function () { return new Promise(function (resolve, reject) { try { navigator.permissions.query({ name: "clipboard-write" }).then(function (status) { // PermissionStatus object // { // onchange: null, // state: "granted" (it could be as well `denied` or `prompt`) // } self.log(status); resolve((status.state == "granted")); }); } catch (error) { // This could be caused because of a Browser incompatibility or security error // Remember that this feature works only through HTTPS reject(error); } }); }; this.codeSearch = function (params) { let selector = params.selector || params.container; // {container, word} 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 // do not change selection }); editor.session.selection.clearSelection(); editor.setOption("highlightActiveLine", true); /* range.start.column = 0; range.end.column = Number.MAX_VALUE; //editor.session.replace(range, "x" + editor.session.getLine(range.start.row) + "x"); editor.selection.setRange(range); */ } }; this.ace = function (params, selectorParams) { // https://codepen.io/zymawy/pen/XwbxoJ //self.log('code'); //self.log(params); var selector = params.selector || params.container; var container = selector || self.selector(selectorParams); //paramsReplaced = self.cloneObject(params); //paramsReplaced.value = self.actionResult(paramsReplaced.value); var value = params.value; // item from library 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); // json file if (params.module) { let moduleName = self.replaceProperties(params.module); if (moduleName && self.modules[moduleName] !== undefined) { value = self.modules[moduleName]; /* self.log('value'); self.log(value); self.log(value); */ } 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); //var containerId = $(container).attr('id'); //self.log('containerId'); //self.log(containerId); //var containerId = $(container).attr('id'); if (element) { //var containerId = self.attribute(element, 'id'); // or assign a random unique id var editor = ace.edit(element); /* var keywordMapper = this.createKeywordMapper({ "tag" : 'div|ul|p|a|button|input|span|img|video|audio|source|figure|figcaption|textarea|iframe|table|thead|tbody|tfoot|tr|th|td|svg|small|h1|h2|h3|h4|h5|h6|form|form-group|label|select|option|optgroup|nav|lottie-player|qrcode|tab|model-viewer' }, "identifier"); */ /* var staticWordCompleter = { getCompletions: function(editor, session, pos, prefix, callback) { var wordList = ['div', 'ul', 'p', 'a', 'button', 'input', 'span', 'img', 'video', 'audio', 'source', 'figure', 'figcaption', 'textarea', 'iframe', 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'svg', 'small', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'form', 'form-group', 'label', 'select', 'option', 'optgroup', 'nav', 'lottie-player', 'qrcode', 'tab', 'model-viewer']; callback(null, wordList.map(function(word) { return { caption: word, value: word, meta: "static" }; })); } } //langTools.setCompleters([staticWordCompleter]) // or editor.completers = [staticWordCompleter] */ /* if (editor) AceColorPicker.load(ace, editor); */ //var value = paramsReplaced.value; // else value = params; if (!params.do || (params.do == 'set')) { //var langTools = ace.require('ace/ext/language_tools'); if (params.theme) editor.setTheme(params.theme); // "ace/theme/monokai" var editorMode = params.mode || "ace/mode/json"; editor.getSession().setMode(editorMode); if (params.options) editor.setOptions(params.options); //AceColorPicker.load(ace, editor, {hideDelay: 1000}); //import AceColorPicker from 'ace-colorpicker'; /* editor.getSession().setMode(editorMode, () => { AceColorPicker.load(ace); // , {hideDelay: 1000} }); */ var editorStyle = self.extend({ //background: "rgba(255,255,255,0)" }, params.style); //$(container).css(editorStyle); //editor.container.style self.css({ style: editorStyle }, { selector: container }); //var aceOptions = params.options; /* var aceOptions = self.extend({ fontSize: "12pt", selectionStyle: "line", //showGutter: false, highlightGutterLine: false, fixedWidthGutter: false, //vScrollBarAlwaysVisible: true, tabSize: 3, //readOnly: true, //enableBasicAutocompletion: false, //enableSnippets: false, //enableLiveAutocompletion: false, }, params.options); */ // https://github.com/ajaxorg/ace/wiki/Configuring-Ace var codeString; if (typeof value == 'string') if (editorMode == "ace/mode/json") codeString = JSON.stringify(JSON.parse(value), null, '\t'); // json formatting 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); } } // should be {lines:dividcode} if (codeString) { var codeRows = codeString.split(/\r\n|\r|\n/).length; /* $(container).css({ height: Number(21 * (codeRows)) + 'px' }); */ /* self.log('element'); self.log(element); self.log('container'); self.log(container); self.log('codeRows'); self.log(codeRows); */ element.style.height = Number(21 * codeRows) + 'px'; //element.querySelector('.ace_scroller').querySelector('.ace_content').height = Number(21 * codeRows) + 'px'; /* self.css({ style: { height: Number(21 * codeRows) + 'px' } }, { container: container }); */ editor.setValue(codeString, -1); // -1 unselect the code //editor.renderer.updateFull(true); //AceColorPicker.load(ace, ace.edit(containerId)); self.uiUpdate(); // resize event trigger // workaround known ACE bug (.ace_content element doesn't follow the height until window resize) } if (params.on) { var containerId = self.attribute(element, 'id'); // or assign a random unique id self.codeChangeFunctions[containerId] = params.on; //self.editorChangeFunctions[editor.id] = params.on; if (params.on.change) { editor.on('change', function (event, obj) { /* self.log('event'); self.log(event); self.log('obj'); self.log(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); var methods = self.replaceResult(action, code); //var methods = self.replaceProperties(action, code); // check on jsonic.io/play (methods is string instead of object) /* self.log('code'); self.log(code); self.log('method'); self.log(method); self.log('-------------'); */ //self.do(methods); self.do(methods); //self.do(code, self.editorChangeFunctions[obj.id]); //var container = self.editorChangeFunctions[obj.id].change.container; } else { // syntax error } //self.do(self.editorChangeFunctions[obj.id].change, JSON.parse(obj.getValue())); //self.log(obj); //self.blocks(JSON.parse(obj.getValue()), {container: }); }); } // save key // https://michilehr.de/overwrite-cmds-and-ctrls-in-javascript } } else if (params.do == 'get') { return JSON.parse(editor.getValue()); } else if (params.do == 'update') { self.uiUpdate(); // resize event trigger // workaround known ACE bug (.ace_content element doesn't follow the height until window resize) } else if (params.do == 'search') { if (params.word) { var range = editor.find(params.word, { wrap: true, caseSensitive: true, wholeWord: true, regExp: false, preventScroll: false // do not change selection }); editor.session.selection.clearSelection(); editor.setOption("highlightActiveLine", true); /* range.start.column = 0; range.end.column = Number.MAX_VALUE; //editor.session.replace(range, "x" + editor.session.getLine(range.start.row) + "x"); editor.selection.setRange(range); */ } } else if (params.do == 'find') { // toggle editor.execCommand('find'); //editor.searchBox.show(); } else if (params.do == 'copy') { // Select the whole content of the editor editor.selectAll(); // Store text that will be copied to clipboard let copyText = editor.getCopyText(); // Verify if clipboard writing is allowed isClipboardWritingAllowed().then(function (allowed) { // Write to clipboard if allowed if (allowed) { navigator.clipboard.writeText(copyText).then(function () { editor.getSession().selection.clearSelection(); //self.log("Code copied!"); }); } }).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); } }; // TO DO: should be in the app var and reset on a new execution this.codeChangeFunctions = {}; this.editorChangeFunctions = {}; this.quillElements = {}; this.text = function (params, selectorParams, args) { /* { "text": / "string": / textId -> textId "{text:textId}" "case": [up, down, capitalize] } */ /* if (Array.isArray(params)) { for (var obj of params) self.text(obj, selectorParams, args); } else { */ var textKey; var textCase; var textArgs; var textLang; var langId; var selector, element; //var textAction; if (typeof params == 'object') { if (selectorParams && selectorParams.isConnected) { // Check if an element is attached to DOM element = selectorParams; //selector = self.dataStorage.get(element, 'selector'); //selector = element.getAttribute('data-selector'); selector = self.elementToSelector(element); // 1.0.12 } else { selector = self.selector(self.extend({}, params, selectorParams)); element = self.query(selector); } // todo: REMOVE (check the menu) //textAction = self.actionResult(params, textArgs); //textAction = params; //textKey = params.string; // || params.text || params.title; // params.key to be removed? textCase = params.case; // use text-transform uppercase lowercase capitalize textArgs = params.args; // deve diventare args (secondo parametro) al posto di caseFunction //langId = params.langId; if (typeof params == 'object') { textKey = params.key || params.string || params; // || params.text || params.title; // params.key to be removed? //textCase = params.case; // use text-transform uppercase lowercase capitalize //textArgs = params.args; // deve diventare args (secondo parametro) al posto di caseFunction //langId = params.langId; } else { textKey = params; } /* self.log('textKey'); self.log(textKey); */ } else if (typeof params == 'string') { textKey = params; /* self.log('textKey'); self.log(textKey); */ //textCase = caseFunction; if (selectorParams) { if (selectorParams.isConnected) { // Check if an element is attached to DOM element = selectorParams; selector = self.dataStorage.get(element, 'selector'); } else { selector = self.selector(selectorParams); element = self.query(selector); } } else { // here when windowTitle += ' ' + self.text(page.title); // window title } } if (typeof textKey == 'string') { /* // TO DO: remove if (textKey.startsWith('js:')) textKey = self.js(textKey.substr(3)); else if (textKey.startsWith('db:')) textKey = self.element({path: 'var.db.'+textKey.substr(3)}); else if (textKey.startsWith('var:')) textKey = self.element({path: 'var.'+textKey.substr(4)}); else if (textKey.startsWith('data:')) textKey = self.element({path: 'data.'+textKey.substr(5)}); else // ----- */ /* console.log('textKey'); console.log(textKey); */ textKey = self.replaceProperties(textKey, textArgs); /* console.log('textKey'); console.log(textKey); */ } //self.log('selector'); //self.log(selector); //self.log(selector.isConnected); /* self.log('HOTSPOT'); self.log(params); self.log(self.json.setup.language); */ if (params && params.lang) { // multi-language text //self.log('params.lang definito'); textLang = self.langText(params.lang); // , langId //textLang = params.lang[self.json.setup.language] || params.lang['en'] || params.lang[Object.keys[0]]; textLang = self.replaceProperties(textLang, textArgs); /* self.log('textLang'); self.log(textLang); self.log('element'); self.log(element); */ if (textCase) textLang = self.textCase(textLang, textCase); //self.log('textLang'); //self.log(textLang); if (element) { element.textContent = textLang; self.attribute(element, 'data-text', true); // textKey instead of lang? self.dataStorage.set(element, 'params', params); //$(selector).data('params', params); } } else { //self.log('params.lang non definito'); //if (!textKey) textKey = params; if (textKey) { //textKey = self.compile(textKey, textArgs); // TO DO: verify /* self.log('textKey'); self.log(textKey); */ //if (!textKey) alert(JSON.stringify(params)); //if (typeof textKey == 'object') { // textLang = JSON.stringify(textKey, null, '\t'); //} else { //textLang = params.lang[self.json.setup.language] || params.lang['en'] || params.lang[Object.keys[0]]; if (textKey.lang) // multi-language text textLang = self.langText(textKey.lang); // , langId else textLang = textKey; /* self.log('textLang1'); self.log(textLang); */ textLang = self.replaceProperties(textLang, textArgs); // move after textLang = self.langText(textKey.lang); if (textCase) textLang = self.textCase(textLang, textCase); //} /* self.log('textLang2'); self.log(textLang); */ //if (selector) { // set if (element) { // set if (self.json.texts[textKey]) { // save data-text for lang change //$(selector).data('params', params); //$(selector).attr('data-text', textKey); self.attribute(element, 'data-text', true); self.dataStorage.set(element, 'params', params); } // obsolete /* if (params.background) $(selector).css({'background': params.background}); if (params.color) $(selector).css({'color': params.color}); if (params.size) $(selector).css({'font-size': params.size}); */ if (params.style) self.css({ style: params.style }, { selector: selector }); //$(selector).css(params.style); element.textContent = textLang; // put text in element //$(selector).text(textLang); } else { // get return textLang; } } else { /* self.log('"string" parameter required in text object'); self.log(params); */ return params; } } }; var caseUp = function (string) { return string.toUpperCase(); }; var caseDown = function (string) { return string.toLowerCase(); }; var capitalize = function (string) { return self.capitalize(string); }; 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'); } }; /* this.textFit = function (selector,params) { if (params.alignHoriz == undefined) { params.alignHoriz = true; } if (params.alignVert == undefined) { params.alignVert = true; } if (params.minFontSize) { params.minFontSize = parseInt(params.minFontSize, 10); // remove px } if (params.maxFontSize) { params.maxFontSize = parseInt(params.maxFontSize, 10); // remove px } // textFit va in errore se l'oggetto diventa invisibile // mentre sta elaborando la dimensione del testo if (!$(selector).children('span').hasClass('textFitted')) { $(selector).each(function(i, obj) { if ($(obj).is(":visible") && ($(obj).css("display") !== 'none') && ($(obj).css('width')) && ($(obj).css('height'))) { textFit($(obj), params); } }); } } */ /* this.data = function (path, value) { if (!value) return self.json.var; } this.setvar = function (data) { var = self.data(); self.data(data); } */ // -------------- // PAGES // -------------- /* this.lastInteraction = function () { // uso: self.lastInteraction().asMinutes() var lastInteraction = 0; if (var.touchTime) lastInteraction = moment(var.touchTime); var thisMoment = moment(); var duration = moment.duration(thisMoment.diff(lastInteraction)); return duration } */ // -------------- // icons e // -------------- /* this.icons = this.icon = function (params, selectorParams, args) { // { [container, class, value, id] // [html, text, append, prepend] } if (Array.isArray(params)) { for (var index in params) {self.icons(params[index], selectorParams);} } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.icons(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { //if (selectorParams) params = self.extend(params, selectorParams); var paramsReplaced = self.replaceProperties(params, args); self.log('icons'); self.log('paramsReplaced'); self.log(paramsReplaced); if (paramsReplaced) { if (paramsReplaced.disabled == true) self.disableIcon(paramsReplaced, selectorParams); else if (paramsReplaced.disabled == false) self.enableIcon(paramsReplaced, selectorParams); else if (paramsReplaced.change) self.changeItem(paramsReplaced, selectorParams); else self.addItem(paramsReplaced, selectorParams); } if (paramsReplaced.firebase) self.addFirebaseTag(paramsReplaced); var selector = self.selector(self.extend(paramsReplaced, selectorParams)); if (paramsReplaced.span) // text near icon self.addTag(paramsReplaced, {container: selector}); } } } */ /* this.buttons = this.tab = function (params, selectorParams) { // { [container, class, value, id] // [html, text, append, prepend] } if (Array.isArray(params)) { for (var index in params) self.tab(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.tab(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { // se necessario, replaceProperties dovrebbe escludere il contenuto di events/action // in quanto verrà ripetuto sulle azioni in tempo reale solo dove necessario //params = self.replaceProperties(params); if (!params.class) params.class = ''; var classes = params.class.split(' '); if (params.change) { if (classes.includes('icon')) self.changeItem(params, selectorParams); else // if (classes.includes('tabs')) self.changeTab(params, selectorParams); } else { if (classes.includes('icon')) self.addItem(params, selectorParams); else // if (classes.includes('tabs')) self.addTab(params, selectorParams); } if (params.firebase) self.addFirebaseTag(params); } } } */ /* this.replacePropertyNew = function (params, name, args) { console.log('replacePropertyNew'); // like replaceProperties but only for {name:...} property var paramsString; if (typeof paramsString !== 'string') {paramsString = JSON.stringify(self.cloneObject(params));} // remove string quotes for object property if (args && paramsString && paramsString.indexOf('{')>= 0) { //if (args && paramsString && /{\w/.test(paramsString)) { paramsString = paramsString.replace(/\"\{(\w+\:)?([\w\s\.\:]+)\}\"/g, function(match, p1, p2, offset, string) { var value; if (p1 && p1.endsWith(':')) {p1 = p1.slice(0, -1);} console.log('match:'+match); console.log('p1:'+p1); console.log('p2:'+p2); if (p1 == name || (!p1 && p2 == name)) { let nameFound = p1 || p2; let pathFound = (p1) ? p2 : undefined; console.log(nameFound+':'+pathFound); if (typeof args !== 'string') { //return self.replaceAll(self.stringify(args), '\"', '\''); return self.stringify(args); } else { return '"' + args + '"'; } } else return match; }); //console.log('paramsString without quotes'); //console.log(paramsString); paramsString = paramsString.replace(/\{(\w+\:)?([\w\s\.\:]+)\}/g, function(match, p1, p2, offset, string) { var value; if (p1 && p1.endsWith(':')) {p1 = p1.slice(0, -1);} if (p1 == name || (!p1 && p2 == name)) { let nameFound = p1 || p2; let pathFound = (p1) ? p2 : undefined; console.log(nameFound+':'+pathFound); self.partSetup = args; if (pathFound) { value = self.docElement('self.partSetup.'+pathFound); } else { value = args; } console.log('value:'+value); delete self.partSetup; } else { value = match } if (typeof value !== 'string') value = self.stringify(value); return value; }); if (self.isJsonString(paramsString)) {// (typeof params == 'object') console.log('isJsonString'); var paramsObj = self.parse(paramsString); return paramsObj; } else { console.log('NOT isJsonString'); console.log(paramsString); // TO DO: log of wrong json string return paramsString; } } else { return params } } */ this.replaceUndefined = function (params) { let value, defaultValue; //if (params.path == 'badge') alert(); 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) { // empty string is false if (typeof defaultValue !== undefined) value = defaultValue; else { if (params.removeUndefined) { //p1 == 'args' || p1 == 'selector') { value = ''; // remove undefined values } else { value = params.match; self.log(value + ' not found', 'yellow'); } } } else { //console.log('match:'+params.match); //if (params.removeUndefined) value = ''; } return value; }; //value = self.replaceUndefined({match: '{'+match+'}', id:p1, removeUndefined: removeUndefined}); this.replaceProperties = function (params, args, removeUndefined) { // TO DO: remove fieldsObj. can't find replaceProperties with 3 args // the third parameter can be removeUndefined // test with a firebase app like elio var paramsString; var paramOn, paramDo, paramSuccess, paramError, paramEvents, paramConfirm; if (typeof params == 'string') { paramsString = params; } else { //paramsString = JSON.stringify(params); 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; } // TO DO: remove if (paramsObj.confirm) { paramConfirm = paramsObj.confirm; delete paramsObj.confirm; } // TO DO: check it if (paramsObj.do) { paramDo = paramsObj.do; delete paramsObj.do; } } paramsString = JSON.stringify(paramsObj); } /* self.log("paramsString"); self.log(paramsString); */ 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 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 //value = value.replaceAll(/([^\\\"])\"/g, '$1\\"'); break; case 'plugins': value = self.json.resources.pluginsFunctions[p2]; if (value && !Array.isArray(value)) value = [value]; else value = []; /* self.log('plugins'); self.log('value'); self.log(value); */ /* value = plugins; for (plugin of plugins) { value = self.json.resources.pluginsFunctions[p2].name || 'unknown plugin required'; } */ break; case 'database': case 'db': value = self.docElement('self.json.var.db.' + self.replaceProperties(p2, args)); break; // shorteners (useful?) case 'media': // or m or src if (self.json.setup && self.json.data.media) value = self.docElement('self.json.data.media.' + p2) || match; else value = match; break; case 'color': // or col if (self.json.data && self.json.data.colors) value = self.docElement('self.json.data.colors.' + p2) || match; else value = match; break; case 'class': // or cla 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] || ''; // || p2+'=NULL'; break; case 'height': /* self.log('{height:p2}'); self.log('p2'); self.log(p2); */ var element = document.querySelector(p2); // self.query(p2); if (element) // && self.isVisible(element) //value = getComputedStyle(element, null).height; value = element.offsetHeight + 'px'; //if ($(p2).is(':visible')) //value = $(p2).height() + 'px' else value = '0px'; break; case 'offsetWidth': var element = document.querySelector(p2); // self.query(p2); if (element) // && self.isVisible(element) //value = getComputedStyle(element, null).height; value = element.offsetWidth; //if ($(p2).is(':visible')) //value = $(p2).height() + 'px' else value = '0'; break; case 'width': var element = document.querySelector(p2); // self.query(p2); if (element) // && self.isVisible(element) //value = getComputedStyle(element, null).height; value = element.offsetWidth + 'px'; //if ($(p2).is(':visible')) //value = $(p2).height() + 'px' else value = '0px'; break; case 'local': value = self.methods.local.get(p2); //self.log('{localStorage:cart}'); //self.log(value); break; case 'ace': var element = document.querySelector(p2); if (element) { var editor = ace.edit(element); value = JSON.parse(editor.getValue()); } //self.log('{localStorage:cart}'); //self.log(value); break; /* case 'innerText': var element = document.querySelector(p2); value = (element) ? element.innerText : undefined; self.log('p1:'+p1); self.log('p2:'+p2); self.log('value:'+value); //.trisBox[data-value="0"] break; case 'innerHtml': var element = document.querySelector(p2); value = (element) ? element.innerHTML : undefined; break; */ case 'shuffle': value = self.element({ path: p2 }); value = self.methods.shuffle(value); break; case 'select': case 'input': case 'value': // deprecated var element = document.querySelector(p2); // self.query(p2); value = (element) ? String(element.value || '') : ''; //value = $('#'+p2).val() || ''; //|| p2+'=NULL'; // input field value // https://www.geeksforgeeks.org/html-value-attribute/ break; case 'user': if (p2 == 'in') { value = self.userIn(); } else if (p2 == 'out') value = self.userOut(); else value = self.user(p2) || match; //|| p2+'=NULL'; break; // can go in objects case 'length': var varObj = self.element({ path: p2 }); // to get also js objects length //var varObj = self.docElement('self.json.'+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(); // timestamp else if (p2 == 'getSeconds') value = new Date().getSeconds(); else if (p2 == 'getMinutes') value = new Date().getMinutes(); else if (p2 == 'getHours') value = new Date().getHours(); // second, minute, hour, weekday, day, month, year 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': // format: long, short, narrow var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2); value = self.calendar({ index: Number(day), unit: 'weekday', format: 'long' }); break; case 'weekdayNarrow': // format: long, short, narrow var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2); value = self.calendar({ index: Number(day), unit: 'weekday', format: 'narrow' }); break; case 'weekdayShort': // format: long, short, narrow 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': // TO DO: check 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); // || match; // TO DO: log error value = self.do(p2); // || match; // TO DO: log error //var functionName = self.docElement(p2); //value = (functionName) ? functionName(functionName) : p2+'=NULL' break; /* WITH ARGS */ case 'method': var method = self.element({ path: p2, root: self.methods }); if (method) { value = method(args); // how to pass args? needs p3 } else { value = match; } break; case 'function': // TO DO: remove var func = self.element({ path: p2, root: self.functions }); if (func) { value = func(args); // how to pass args? needs p3 } else { value = match; } break; case 'on': /* self.log('args'); self.log(args); */ if (args) { self.onResult = args; value = self.docElement('self.onResult.' + p2); //alert(JSON.stringify(value)); delete self.onResult; } else { //alert(JSON.stringify(value)); value = match; } //value = ($(p2).is(':visible')); break; case 'ajax': if (args) { self.ajaxResult = args; // -> self.json.var.ajaxData[self.json.var.ajaxId] = args.response //alert(JSON.stringify(args)); value = self.docElement('self.ajaxResult.' + p2); delete self.ajaxResult; } else { //alert(JSON.stringify(value)); value = match; } //value = ($(p2).is(':visible')); break; /* case 'function': // TO DO: remove //self.log('function'); //self.log('p2'); //self.log(p2); // app.mac value = self.function(p2) || match; // TO DO: log error //var functionName = self.docElement(p2); //value = (functionName) ? functionName(functionName) : p2+'=NULL' break; */ case 'if': // TO DO: remove (can't manage spacial characters !<>'' etc) 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': /* var random = p2.replace(/([^\-]+)\-([^\}]+)/g, function(match, n1, n2, offset, string) { return Number(n1)+Math.round((n2-n1)*Math.random()); }); */ value = String(Math.floor(Number(p2) * Math.random())); //self.log('random value: '+value); //value = random; //p2+' format is wrong' // CHANGE TO {math.random:max} break; case 'getKey': case 'firebaseKey': value = self.firebaseKey(p2); // https://firebase.google.com/docs/reference/android/com/google/firebase/database/DataSnapshot // CHANGE TO {data.exists:path/to/record} //"alert.close" functions(alert, do:close) break; case 'window': /* try { value = eval('window.'.p2); } catch (error) { self.log('javascript error on '+ p2); value = match; } */ //value = self.js('window.'.p2) || match; value = self.docElement(p2) || match; break; /* case 'args': // often replaceProperties is called without args value = match; break; */ default: // ci finiamo dentro con {setup:value} /* var element = document.querySelector(p2); value = (element) ? element[p1] : ''; self.log('p1 ' + p1); self.log('p2 ' + p2); self.log('value ' + value); if (!element) self.log('can\'t match ' + match, 'color:red'); */ break; /* default: var node = self.docElement('self.json.'+p1); self.log('node'); self.log(node); if (node) value = node[p2] // example: p1 = styles.colors p2 = colorName else value = '<{'+p1+':'+p2+'}>'; break; */ } } // not self.functions[p1] } } else if (p2) { // can be a FUNCTION: from modules let keyPrefix = p2.split(' ')[0]; // /\s\./ if (self.functions[keyPrefix]) { value = self.function({ name: keyPrefix }); value = self.element({ path: p2, root: value }); // example: {pathFromHash 0} console.log(keyPrefix); console.log(value); } else value = self.replaceUndefined({ match: match, path: p2, removeUndefined: removeUndefined }); //value = self.element({path: p2}); } // value is a DOM element if (value && value.isConnected) value = self.elementToSelector(value); // DOM element to CSS selector if (!value) { // TO DO: should be (typeof value == undefined) // t's a critical change. It changes the result of "is": "'{data id}' !== ''" if (removeUndefined) value = ''; else { if (typeof value == undefined) self.log(match + ' is undefined', 'yellow'); } } if (typeof value !== 'string') value = self.stringify(value); // object or array to string (TO DO: check numbers) return value; }); // js property TO DO: check it if (paramsString.startsWith('{js:') && paramsString.endsWith('}')) paramsString = self.js(paramsString.substr(4, paramsString.length - 1 - 4)); //if (self.isJson(paramsString)) {// (typeof params == 'object') if (self.isJsonString(paramsString)) { // (typeof params == 'object') var paramsObj = self.parse(paramsString); // restore event nodes 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; // obsolete return paramsObj; } else { // TO DO: log of wrong json string //alert(paramsString); /* if (Array.isArray(self.parse(paramsString))) return self.parse(paramsString) else */ return paramsString; } } else { // restore event nodes 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; // obsolete return params; } }; /* if (!value) undef = true; if (undef) return undefined else return params; */ this.isJsonString = function (str) { try { JSON.parse(str); } catch (e) { return false; } return true; }; 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; }; 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; }; /* this.replaceResult = function (params, args) { paramsString = paramsString.replace(/(\"\s*)\{[result]\:(\w+)\}(\s*\")/g, function(match, p1, p2, p3, offset, string) { }); } */ this.replaceItems = function (params, item, name) { // check this: http://mir.aculo.us/2011/03/09/little-helpers-a-tweet-sized-javascript-templating-engine/ // params:
  • <{item:name}>
  • , item: Vito or item: {name: Vito} //var paramString = self.replaceProperties(params, undefined, item); var paramsString; var specialPattern; var itemName = name || 'item'; /* if (name) { self.log('replaceItems'); self.log('params'); self.log(params); self.log('item'); self.log(item); self.log('name'); self.log(name); } */ if (typeof params == 'string') paramsString = params; else paramsString = JSON.stringify(params); /* paramsString = paramsString.replace(/\{item\}/g, function(match, p1, offset, string) { var value; if (item) { value = item; } else { value = ''; } if (typeof value == 'object') value = self.stringify(value); return value; }); */ if (typeof item == 'object' || Array.isArray(item)) { // || Array.isArray(item) not needed 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)); } //if (itemName == 'hour') alert(paramsString); /* if (itemName !== 'item') { // TO DO: remove var propertyPattern = new RegExp('\{'+itemName+'\:([^\}]+)\}', 'g'); paramsString = paramsString.replace(propertyPattern, function(match, p1, p2, p3, offset, string) { var value = self.docElement(p1, undefined, item); if (value) return value else return match; }); } */ //specialPattern = new RegExp(/\"\{(\w+)\}\"/, "g"); // item: inside double quotes (to manage objects inside double string) //specialPattern = new RegExp(`(\")\{${itemName}\:(\w+)\}(\")`, 'g'); //paramsString = paramsString.replace(specialPattern, function(match, p1, p2, p3, offset, string) { //specialPattern = new RegExp('(\"\s*)\{'+itemName+'\:(\w+)\}(\s*\")', 'g'); 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; }; /* 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; } */ 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 // ---------------------------- 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); } }; this.isArray = function (value) { return Array.isArray(self.js(value)); }; this.isVisible = function (el) { return (el.style.display !== 'none' && !self.hasClass(el, 'd-none')); }; this.isHidden = function (el) { return (el.offsetParent === null); }; 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); }; 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) ); }; this.outViewport = function (el) { return !self.outViewport(el); }; this.notClass = function (el, className) { return !self.hasClass(el, className); }; this.hasClass = function (el, className) { if (el.classList) return el.classList.contains(className); else return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)')); }; this.addClass = function (el, className) { if (el.classList) el.classList.add(className); else if (!self.hasClass(el, className)) el.className += " " + className; }; 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, ' '); } }; this.toggleClass = function (el, className) { if (self.hasClass(el, className)) self.removeClass(el, className); else self.addClass(el, className); }; this.choose = this.select = function (params, selectorParams, args) { // "choose OR options / "select" is deprecated because select is an html tag // {selection: selection class, id: selected id} // or: choosed, choosable, selection // or: selector, selectable, selection // or: opted, options, selection /* self.log('select'); self.log('params'); self.log(params); self.log('args'); self.log(args); */ if (Array.isArray(params)) { for (var obj of params) self.choose(obj, args); } else { //if (selectorParams) params = self.extend({}, selectorParams, params); var selId, selClass, selValue; selValue = params['data-value']; // || params.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); //var selector = self.selector(params.selector, undefined, true) || self.selector(selectorParams, undefined, true); if (params.selection) { var selectionClass = params.selection; /* self.log('selClass'); self.log(selClass); self.log('selValue'); self.log(selValue); self.log('selectionClass'); self.log(selectionClass); */ var selector = self.selector({ class: selClass }); var elements = document.querySelectorAll('.' + selClass); // convert to any string selector (move the point to the code) elements.forEach(function (element, index) { self.removeClass(element, selectionClass); }); //$(selector).removeClass(selectionClass); if (selId || selValue) { var selector = self.selector({ id: selId, class: selClass, 'data-value': selValue }); //self.log('selector'); //self.log(selector); //var elements = self.query(selector); //self.log('elements'); //self.log(elements); //if (elements) //self.addClass(elements, selectedIconClass); var elements = document.querySelectorAll(selector); elements.forEach(function (element, index) { self.addClass(element, selectionClass); }); } } else { /* self.log('select'); self.log('selClass'); self.log(selClass); self.log('selValue'); self.log(selValue); self.log('selectionClass'); self.log(selectionClass); */ self.hide({ "selector": { "class": selClass } }); self.show({ "selector": { "id": selId, "class": selClass, "data-value": selValue } }); //self.log('selectselection" class parameter is required in "select" object'); } //self.updateCodeEditors(); // workaround known ACE bug self.uiUpdate(); // resize event trigger } }; /* this.select = function (params, selectorParams) { // { [container, class, value, id] self.log('self.select'); if (Array.isArray(params)) { for (var index in params) self.choose(params[index], selectorParams); } else { if (selectorParams) params = self.extend({}, selectorParams, params); params = self.replaceProperties(params); //params = self.replaceTags({text:params}); self.selectItem(params); } } */ 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); /* self.log('selector'); self.log(selector); self.log('element'); self.log(element); self.log('self.isVisible(element)'); self.log(self.isVisible(element)); */ //if ($(selector).is(":visible")) if (self.isVisible(element)) //self.fadeOut(params, selectorParams); self.out(params, selectorParams, args); else //self.fadeIn(params, selectorParams); self.in(params, selectorParams, args); //$(selector).toggle(500); // jquery bugs // , self.resizeEvent } }; 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'; //self.log('selector'); //self.log(selector); 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, args); self.do(animation, undefined, args); //self.resizeEvent(); } }; 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, args); self.do(animation, undefined, args); } }; 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'); // bootstrap //element.style.display = 'block'; element.style.visibility = 'visible'; /* container = element.getAttribute('data-selector'); //container = self.dataStorage.get(element, 'selector'); var action = [ { "if": { "container": container, "hasClass": "opacity-0", "then": { "attr": { "container": container, "removeClass": "opacity-0" } } } }, { "if": { "container": container, "hasClass": "invisible", "then": { "attr": { "container": container, "removeClass": "invisible" // bootstrap & tailwind } } } }, { "if": { "container": container, "hasClass": "d-none", "then": { "attr": { "container": container, "removeClass": "d-none" // bootstrap } } } }, { "if": { "container": container, "hasClass": "hidden", "then": { "attr": { "container": container, "removeClass": "hidden" // taliwind } } } }, { "if": { // should be if style.display == none "container": container, "isDisplay": "none", "then": { "attr": { "container": container, "style": { "display": "" } } } } } ]; //element.style.display = ' '; //alert(JSON.stringify(element.style)); if (element.style.visibility && element.style.visibility !== 'visible') element.style.visibility = 'visible'; //self.do(action, args); //self.do(action, undefined, args); self.do(action, undefined, args); */ }); } }; 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'); /* container = element.getAttribute('data-selector'); var action = [ { "attr": { "container": container, "addClass": "d-none" // bootstrap (to be removed) } }, { "attr": { "container": container, "addClass": "hidden" // tailwind } } ]; //self.do(action, args); self.do(action, undefined, args); */ }); } }; /* this.fadeIn = function (params, selectorParams, args) { //self.log('fadeIn'); //self.log(params); if (Array.isArray(params)) { for (var index in params) self.fadeIn(params[index], selectorParams); } else { //params.container = params.container || self.selector(selectorParams); //var selector = self.selector(params); var selector = self.selector(self.extend({}, params, selectorParams), {}, true); var duration = params.duration || 500; var done = (params.done) ? function () { self.resizeEvent(); self.do(params.done); } : null; $(selector).stop().fadeIn(duration, done); } } this.fadeOut = function (params, selectorParams, args) { //self.log('fadeOut'); //self.log(params); // add onComplete and duration if (Array.isArray(params)) { for (var index in params) self.fadeOut(params[index], selectorParams); } else { //params.container = params.container || self.selector(selectorParams); //var selector = self.selector(params); var selector = self.selector(self.extend({}, params, selectorParams), {}, true); var duration = params.duration || 500; var done = (params.done) ? function () { self.do(params.done); } : null; $(selector).stop().fadeOut({ duration: duration, done: function () { self.resizeEvent(); self.do(params.done); } }); } } */ /* this.show = function (params, selectorParams, args) { //self.log('show'); //self.log(JSON.stringify(params)); if (Array.isArray(params)) { for (var index in params) self.show(params[index], selectorParams); } else { //params.container = params.container || self.selector(selectorParams); //var selector = self.selector(params); var selector = self.selector(self.extend({}, params, selectorParams), {}, true); //self.log('selector'); //self.log(selector); $(selector).show(); self.resizeEvent(); } } this.hide = function (params, selectorParams, args) { //self.log('hide'); //self.log(JSON.stringify(params)); if (Array.isArray(params)) { for (var index in params) self.hide(params[index], selectorParams); } else { //params.container = params.container || self.selector(selectorParams); //var selector = self.selector(params); var selector = self.selector(self.extend({}, params, selectorParams), {}, true); //self.log('selector'); //self.log(selector); $(selector).hide(); self.resizeEvent(); } } */ this.matchMedia = function (mediaAction, mediaEvent) { const mediaQuery = window.matchMedia(mediaEvent); mediaQuery.addListener(function (e) { /* self.log('matchMedia'); self.log('e'); self.log(e); */ if (e.matches) { self.do(mediaAction); //self.do(mediaAction); } }); //self.do(mediaAction); }; /* this.firebaseEventAction = 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'), '/', '.'); // data('firebase') var dbObj = self.docElement(pathString); var firebaseValue = newObj[element.getAttribute('data-value')]; // TODO: not works for nested nodes var container = element.getAttribute('data-selector'); //var template = element.getAttribute('data-template'); var template = self.dataStorage.get(element, 'data-template'); if (element.tagName == 'UL') { // se $(this) è un ul var liTemplate = template.li; //$(container).empty(); element.innerHTML = ''; var items = newObj; for (itemKey in items) { var item = items[itemKey]; item.key = itemKey; //if (dbPath == 'lessons') //prompt(JSON.stringify(liTemplate)); var dbParams = self.replaceItems(liTemplate, item, 'item') || ''; // var dbParams = self.replaceProperties(liTemplate, undefined, item) || ''; self.li(dbParams, {container: container}); } //} else if ( $(element).is('span') || $(element).is('p')) { } else if (element.tagName == 'SPAN' || element.tagName == 'P') { //$(element).text(firebaseValue); element.textContent = firebaseValue; } else { // se $(this) non è un ul if (template.blocks || template.html) { var blocksTemplate = template.html || template.blocks; //$(container).empty(); 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, {container: container}); } } if (template.init) self.do(template.init); } }); }; */ /* self.jsonic = function () { } */ this.addFirebaseTag = function (params) { // self.log('addFirebaseTag'); var dataObj = params.database; if (dataObj) { dataObj = self.replaceProperties(dataObj); /* self.log('dataObj'); self.log(dataObj); */ //var path = self.replaceTags({text:params.firebase}); 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 element = self.query(selector); var elements = self.queryAll(selector); //var elements = document.querySelectorAll(selector); if (elements) elements.forEach(function (element, index) { var listenerObj = { path: path //success: dataObj.success }; var elementsDataPath = document.querySelectorAll('[data-firebase="' + path + '"]'); //if ($('[data-firebase="'+path+'"]').length == 0) { if (elementsDataPath.length == 0) { listenerObj.action = [ /* { "firebaseEvent.action": {} // should use self.get function to parse "self" // todo: remove "jsonic". The function firebaseEventAction can be stored in self.do (or?) } */ ]; if (dataObj.success) listenerObj.action.push(dataObj.success); } //$(selector).attr('data-firebase', path); //$(selector).data('data-template', params); 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 (params.on && params.on.data) $(selector).data('ondata', params.on.data); // maestry 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); } } }; this.dbObject = function (path) { var pathString = 'self.json.var.db.' + self.replaceAll(path, '/', '.'); return self.docElement(pathString); }; this.only = function (permissions, user) { // "visitor" or "only" if (user) { return (user == self.user('uid')); } else { var permission = (permissions) ? String(permissions).split(',') : false; return (!permission || (permissions.indexOf(self.userRole()) >= 0)); } }; this.extendJsonFromElement = function (p) { /* self.log('extendJsonFromElement'); self.log(p); */ var params = self.cloneObject(p); // properties 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 }); // obsolete 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 }); // maybe used in self.text // can't be extended "setup" (is relative to the full app) and "on" (is relative to the element) }; this.query = function (selector, element) { //self.log('query: '+selector); 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]; /* route.replace(/([^\s])\[/g, function(match, p1) { // -> .class [data-value=...] return p1 + ' [' }); */ //self.log('route'); //self.log(route); var routeParts = route.match(/(.*):eq\((\d*)\)/); //self.log('routeParts'); //self.log(routeParts); if (routeParts) { var routeElement = String(routeParts[1]); var routeIndex = Number(routeParts[2]); if (routeElement.startsWith('.')) routeElement = '.' + self.classSelector(routeElement); //if (self.exist(routeElement)) element = element.querySelectorAll(routeElement)[routeIndex]; /* self.log('routeElement'); self.log(routeElement); self.log('routeIndex'); self.log(routeIndex); */ } else { //if (self.exist(route)) if (route.startsWith('.')) route = '.' + self.classSelector(route); element = element.querySelectorAll(route)[0]; } } else { element = undefined; } } //element.innerHTML = 'test'; //element.style.display = 'none'; //self.log(element); //if (element && !Array.isArray(element)) element = [element]; if (!element) self.log('can\'t find the element "' + selector + '" ("query" function)'); return element; } else { //self.log('function "query" without selector parameters'); // BUG: many calls from addtag } }; /* this.queryAllTest = function (selector, element) { //self.log('query: '+selector); if (selector) { //route = self.replaceAll(route, '[', ' ['); selector.replace(/([^\s])\[/g, function(match, p1) { // -> .class [data-value=...] return p1 + '[' }); var routes = selector.split(/[ >]+/); if (!element) element = document; self.log('routes'); self.log(routes); for (var index in routes) { self.log('index'); self.log(index); if (element.isConnected) { var route = routes[index]; var routeParts = route.match(/([^:]*):eq\((\d*)\)/); self.log('routeParts'); self.log(routeParts); if (routeParts) { var routeElement = String(routeParts[1]); var routeIndex = Number(routeParts[2]); //if (self.exist(routeElement)) element = element.querySelectorAll(routeElement)[routeIndex]; self.log('routeElement'); self.log(routeElement); self.log('routeIndex'); self.log(routeIndex); } else { //if (self.exist(route)) self.log('route'); self.log(route); element = element.querySelectorAll(route); } } else { self.log('Not in the DOM '+ selector); self.log('route'); self.log(route); element = []; } } //element.innerHTML = 'test'; //element.style.display = 'none'; //if (element && !Array.isArray(element)) element = [element]; //self.log(element); return element; } else { self.log('DOM "query" without selector parameters'); } } */ /* this.convertRoute = function (route) { var routeElement, routeValue; route = route.replace(/([^\s])\[/g, function(match, p1) { // -> .class [data-value=...] return p1 + ' [' }); if (route.indexOf(' ')) { var parts = route.split(' '); routeElement = parts[0]; routeValue = parts[1]; } else { routeElement = route } self.log(routeElement); self.log(routeValue); if (routeElement.startsWith('.')) routeQuery = '[class='+routeElement+']'; else if (routeElement.startsWith('#')) routeQuery = '[id='+routeElement+']'; else routeQuery = routeElement + routeValue; if (routeValue) routeQuery += ' ' + routeValue; return routeQuery; } */ /* // https://www.examplefiles.net/cs/1222124 var querySelectorAllWithEq = function(selector, document) { var remainingSelector = selector; var baseElement = document; var firstEqIndex = remainingSelector.indexOf(':eq('); while (firstEqIndex !== -1) { var leftSelector = remainingSelector.substring(0, firstEqIndex); var rightBracketIndex = remainingSelector.indexOf(')', firstEqIndex); var eqNum = remainingSelector.substring(firstEqIndex + 4, rightBracketIndex); eqNum = parseInt(eqNum, 10); var selectedElements = baseElement.querySelectorAll(leftSelector); if (eqNum >= selectedElements.length) { return []; } baseElement = selectedElements[eqNum]; remainingSelector = remainingSelector.substring(rightBracketIndex + 1).trim(); // Note - for now we just ignore direct descendants: // 'a:eq(0) > i' gets transformed into 'a:eq(0) i'; we could maybe use :scope // to fix this later but support is iffy if (remainingSelector.charAt(0) === '>') { remainingSelector = remainingSelector.substring(1).trim(); } firstEqIndex = remainingSelector.indexOf(':eq('); } if (remainingSelector !== '') { return Array.from(baseElement.querySelectorAll(remainingSelector)); } return [baseElement]; }; */ this.queryAll = function (selector, element) { //self.log('queryAll: '+selector); 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))); //elements = elements.concat(self.queryAll(str)); } /* console.log('queryAll'); console.log(elements); */ return elements; } else { /* if (selector.indexOf(',')>= 0) { return element.querySelectorAll(selector) } // TO DO: check why all the rest */ var routes = selector.split(/[ >]+/); if (!element) element = document; /* self.log('routes'); self.log(routes); */ /* self.log('element[0]'); self.log(element[0]); */ for (var index in routes) { if (element && element[0]) element = element[0]; /* self.log('element'); self.log(element); */ if (element && element.isConnected) { var route = routes[index]; var routeParts = route.match(/([^:]*):eq\((\d*)\)/); /* self.log('route'); self.log(route); self.log('routeParts'); self.log(routeParts); */ if (routeParts) { var routeElement = String(routeParts[1]); var routeIndex = Number(routeParts[2]); /* self.log('routeElement'); self.log(routeElement); self.log('routeIndex'); self.log(routeIndex); */ if (routeElement.startsWith('.')) routeElement = '.' + self.classSelector(routeElement); //if (self.exist(routeElement)) element = element.querySelectorAll(routeElement)[routeIndex]; if (index == (routes.length - 1) && element) { /* console.log('index:'+index); console.log('routes.length:'+routes.length); */ element = [element]; } } else { //if (self.exist(route)) if (route.startsWith('.')) routeElement = '.' + self.classSelector(route); /* self.log('route'); self.log(route); */ element = element.querySelectorAll(route); } } else { //self.log('!element.isConnected'); element = []; } } //if (element && !Array.isArray(element)) element = [element]; //if (element && !element.length) element = [element]; if (!element) self.log('No element selected by ' + selector); //else // if (!Array.isArray(element)) // element = [element]; return element; } } else { console.log('%cDOM queryAll requires selector argument', 'color: orange'); //self.log('DOM "query" without selector parameters'); } }; /* this.queryAll = function (selector, element) { //self.log('query: '+selector); if (selector) { var routes = selector.split(/[ >]+/); if (!element) element = document; for (var index in routes) { var route = routes[index]; //onsole.log('route'); //self.log(route); var routeParts = route.match(/(.*):eq\((\d*)\)/); //self.log('routeParts'); //self.log(routeParts); if (routeParts) { var routeElement = String(routeParts[1]); var routeIndex = Number(routeParts[2]); //if (self.exist(routeElement)) element = [element.querySelectorAll(routeElement)[routeIndex]]; } else { //if (self.exist(route)) element = element.querySelectorAll(route); } } //element.innerHTML = 'test'; //element.style.display = 'none'; //if (element && !Array.isArray(element)) element = [element]; //self.log(element); return element; } else { self.log('DOM "query" without selector parameters'); } } */ /* var querySelectorAllWithEq = function(selector, document) { var remainingSelector = selector; var baseElement = document; var firstEqIndex = remainingSelector.indexOf(':eq('); while (firstEqIndex !== -1) { var leftSelector = remainingSelector.substring(0, firstEqIndex); var rightBracketIndex = remainingSelector.indexOf(')', firstEqIndex); var eqNum = remainingSelector.substring(firstEqIndex + 4, rightBracketIndex); eqNum = parseInt(eqNum, 10); var selectedElements = baseElement.querySelectorAll(leftSelector); if (eqNum >= selectedElements.length) { return []; } baseElement = selectedElements[eqNum]; remainingSelector = remainingSelector.substring(rightBracketIndex + 1).trim(); // Note - for now we just ignore direct descendants: // 'a:eq(0) > i' gets transformed into 'a:eq(0) i'; we could maybe use :scope // to fix this later but support is iffy if (remainingSelector.charAt(0) === '>') { remainingSelector = remainingSelector.substring(1).trim(); } firstEqIndex = remainingSelector.indexOf(':eq('); } if (remainingSelector !== '') { return Array.from(baseElement.querySelectorAll(remainingSelector)); } return [baseElement]; }; */ this.jitcss = function (classes) { // https://tailwindcss.com/docs/just-in-time-mode if (classes.indexOf('-[') > -1) { let classesArr = classes.split(' '); // change to one or more spaces // (sm\:|md\:|lg\:|xl\:|2xl\:)? self.log('jitcss'); for (cl of classesArr) { self.log(cl); let par = [...cl.matchAll(new RegExp('([^-]+)[\-][\[](.+)\]', 'g'))]; self.log('jitcss'); self.log(par); } } /* sm:w-1 .w-1 { width: 1em; } @media (min-width: 640px) { .sm\:w-1 { width: 1em } } */ }; this.compileClasses = function (string) { var classesString = string; // classes shortcuts 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]); } } } // dynamic classes if (string.indexOf('(') >= 0) { //self.log('compileClasses'); classesString = ''; let classesArr = string.split(' '); for (cl of classesArr) { /* self.log('cl'); self.log(cl); */ if (cl.indexOf('(') >= 0 && cl.endsWith(')')) { let classArr = cl.split('('); classArr[1] = classArr[1].slice(0, -1); // remove ) //let par = [...cl.match(new RegExp('([^\(]+)\(([^\)]+)\)$'))]; // doesn't work /* self.log('classArr'); self.log(classArr); self.log('classArr[1]'); self.log(classArr[1]); self.log('self.js(classArr[1])'); self.log(self.js(classArr[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; }; 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); // from 0.9.6: must stay before document.createElement /* console.log('append'); console.log('selector:'+selector); console.log('container:'+container); console.log('newSelector:'+newSelector); */ var newElements = []; //if (containerElement) //containerElements.forEach(function (containerElement, index) { if (containerElement) { if (!params) params = {}; var element = document.createElement(params.tag); containerElement.appendChild(element); if (params.attr) { // shortcuts (windy property not in twind) and dynamic classes with js condition if (params.attr.class) { // replace shortcuts and dynamic classes: class(condition) params.attr.class = self.compileClasses(params.attr.class); } } //if (container) element.setAttribute('data-selector', self.selector(params, selectorParams)); //if (container) element.setAttribute('data-selector', newSelector); // from 0.9.6. removed 1.0.12 // for IDE self.dataStorage.set(element, 'code', params); self.dataStorage.set(element, 'key', params.key); /* if (params.attr && params.attr.class) self.jitcss(params.attr.class); */ newElements.push(element); if (params.attr) self.setAttributes(newElements, params.attr); if (params.style) self.css(params, newSelector); // TO DO: deprecated / to be removed; /* // attributes TO DO: move up / call self.attr if (params.attr) for (var attrId in params.attr) self.attribute(newElements, attrId, self.replaceProperties(params.attr[attrId])); //self.log(self.replaceProperties(params.attr[attrId])); //$(selector).attr(attrId, params.attr[attrId]); */ } //}); return newElements; /* for (let element of elements) { element.appendChild(string); } */ }; /* this.newSelector = function (params, selectorParams) { var container = self.selector(self.extend({}, params, selectorParams), undefined, true); if (container) { var selectorObj = { container: container, //class: params.class, //value: params.value, //'data-value': params['data-value'] }; // , selectorParams); self.log('container'); self.log(container); var index = document.querySelectorAll(container).length; if (index > 1) selectorObj.index = index-1; self.log('newSelector'); self.log(selectorObj); return selectorObj; } else { self.log('container undefine in newSelector'); self.log('params'); self.log(params); self.log('selectorParams'); self.log(selectorParams); } } */ /* this.editor = function (params, selectorParams, args) { self.log('editor'); self.log('params'); self.log(params); var selector = self.selector(selectorParams, undefined, true); // self.selector(params, undefined, true) || if (selector) { var element = self.query(selector); if (element) { if (!self.quillElements[selector]) { self.quillElements[selector] = new Quill(element, { modules: params.modules || { // or default modules toolbar: [ [{ header: [1, 2, false] }], ['bold', 'italic', 'underline'], ['image', 'code-block'] ] }, // scrollingContainer: '#scrolling-container', placeholder: params.placeholder || 'Write here', theme: params.theme || 'bubble' }); } if (self.quillElements[selector]) { if (params.setContents) { var contents = self.replaceProperties(params.setContents, args); self.quillElements[selector].setContents(contents); } if (params.getContents) { self.quillElements[params.getContents].getContents(); } if (params.on) { for (var eventId in params.on) { self.editorChangeFunctions[selector] = params.on; if (params.on[eventId]) { self.quillElements[selector].on(eventId, function(delta, oldDelta, source) { var action = self.editorChangeFunctions[selector][eventId]; var actionWithResult = self.replaceResult(action, delta); //self.do(actionWithResult); self.do(actionWithResult); }); } } } } } else { self.log('can\'t find the element "'+ selector + '" ("editor" function)'); self.log(params); } } else { self.log('the "editor" function has a wrong selector'); self.log(params); } } */ this.do = this.action = this.execute = function (params, selectorParams, args) { /* self.log('params'); self.log(params); self.log('selectorParams'); self.log(selectorParams); self.log('args'); self.log(args); */ if (params !== undefined && params !== null) { // empty string is ok /* // problematic for nested {args} / {selector} if (selectorParams && typeof selectorParams == 'string') { params = self.replaceProperty(params, 'selector', selectorParams); } if (args) { params = self.replaceProperty(params, 'args', args); } */ if (typeof params == 'string') params = self.replaceProperties(params, args); let pluginsRequired = self.pluginsRequired(params); /* self.log('pluginsRequired'); self.log(pluginsRequired); */ if (pluginsRequired.length > 0) //let params = [params, args, selectorParams]; self.pluginsLoader(pluginsRequired, self.do, [params, selectorParams, args]); else { if (Array.isArray(params)) for (var obj of params) self.do(obj, selectorParams, args); // -> execute dopo aver portato qui pluginsLoaded else if (typeof params == 'object') { /* if (params.after) { let paramsAfter = params.after; let paramsWithoutAfter = self.cloneObject(params); delete paramsWithoutAfter.after; self.timer({ after: paramsAfter, do: paramsWithoutAfter }); } else { */ if (params.if == undefined || self.if(params.if)) { // || Boolean(self.js(params.if))) { // , args /* console.log('IF---------------'); console.log(params.if); console.log(params); */ if (self.only(params.roles, params.user)) { //if (!params) params = {}; //var newContainer; //self.newSelector(params, selectorParams); // {container: selector} // Add an element in the DOM if (params.tag) { var selector = self.selector(params, selectorParams); /* self.log('selector'); self.log(selector); */ self.extendJsonFromElement(params); // or selectorParams //newContainer = {selector: selector}; //if (1) //self.user('uid') == 'L0y20rjPp6a6ejqVuDXuTWCU2rH3') //'ocXuFBV4aWcy7KZMAmi6mICFi872') // create new html element var newElements = self.createElement(params, selectorParams); /* if (params.key == 'text') //let element = self.query(self.selector(params.selector)); newElements.innerText = self.text(nested); */ 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 { // nested html tags as property for (var par in params) // && (par !== 'attr') 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 }); } } // end of self.only } //} } else if (typeof params == 'function') return params(selectorParams); else self.log('can\'t execute: ' + params); } } }; this.callback = function (params) { /* console.log('callback'); console.log(params); */ // {do, find, replace} if (params) { var path = params.to; if (params.var) path = 'var ' + params.var; // TO DO: remove let selector; let element = params.element; // elementToSelector ? 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); } }; this.nested = function (params) { /* console.log('nested'); console.log(params); */ // check plugins required let pluginsRequired = self.pluginsRequired(params.key); if (pluginsRequired.length > 0) { self.pluginsLoader(pluginsRequired, self.nested, [params]); } else { // TO DO: regular expression like in this.element (should include setup and also :) 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 ')) { // TO DO: remove this option. Is too ambiguous for debug -> use set // deprecated from 1.0.4 console.log('%cdeprecated key: "' + params.key + '". Use "set key": "value"}', 'color:orange'); // Data setting prefix // should be removed and replaced with the method "set" to improve the compatibility // with the other possible keys (js functions, jsonic methods, html tags ex. ) // https://www.w3schools.com/tags/tag_data.asp self.setData({ key: params.key, value: params.obj }); } else { // CHECK IF KEY IS METHOD //console.log('check if is a method'); var method = self.element({ path: params.key, root: self.methods }); if (method) { // search in jsonic.methods self.log('METHOD: ' + params.key, 'grey'); var methodArgs = params.obj; /* if (params.key == 'swiper init') { self.log('method: ' + params.key); self.log('methodArgs'); self.log(methodArgs); self.log('params.selector'); self.log(params.selector); self.log('-----------'); } */ //methodArgs = self.replaceProperty(methodArgs, 'selector', params.selector); method(methodArgs, params.selector, params.args); /* } else if (params.key == 'set') { // TO DO: REMOVE // JS METHOD (old) var actionObj = {}; actionObj[params.key] = params.obj; self.do(actionObj, params.selector); */ /* } else if (nodes.functions.indexOf(params.key) >= 0) { // TO DO: REMOVE // JS METHOD (old) var actionObj = {}; actionObj[params.key] = params.obj; //self.do(actionObj, undefined, params.selector); self.do(actionObj, params.selector); */ } else { // CHECK IF KEY IS A PARTS //console.log('check if is a part'); // shortcut: content let nested; let part; var jsonicPart = false; if (self.json.parts) { // && par.match(/[.>]+/)) part = self.element({ path: self.replaceAll(params.key, ':', '.'), root: self.json.parts }); /* if (par.indexOf(':')>0 && !part) { jsonicPart = true; self.firebaseGetPart({localPath:localPath, container: params.selector, arg:params.obj}); } */ } if (part) { self.log('PART: ' + params.key, 'grey'); /* console.log('params'); console.log(params); */ var partObj = params.obj; //nested = self.replaceProperty(part, 'value', params.obj); // obsolete? //nested = self.replaceProperty(part, 'arg', partObj); // obsolete //if (typeof partObj == 'string' && partObj.indexOf('{') >= 0) { // obsolete? // TO DO: this should be already inside self.do partObj = self.replaceProperties(partObj); // for backward compatibility can be partObj, null, true) // true is removeUndefined //} /* console.log('partObj'); console.log(partObj); */ //var partSelector = params.selector || partObj.selector; // TO DO: Check this // seems a workaround for fantacards/ui:qrcode // parts can receive the parameters {selector:..., setup:...} partObj.selector = partObj.selector || params.selector; // TO DO: deprecated fantacards:setPlayer if (partObj.setup) partObj = partObj.setup; // overwrites partObj.selector but execute receive params.selector // TO DO: replaceProperty should be improved to get also sub values like {arguments:on.success} //nested = self.replaceProperty(part, 'setup', partObj); // {setup} -> {arguments} //nested = self.replaceProperty(nested, 'arguments', partObj); //nested = self.replacePropertyWithPrefix(part, 'setup:', partObj); // {setup} -> {arguments} //nested = self.replacePropertyWithPrefix(nested, 'arguments:', partObj);// to tix nested = self.replacePropertyWithPrefix(part, 'setup', partObj); // {setup} -> {arguments} nested = self.replacePropertyWithPrefix(nested, 'arguments', partObj); // to tix self.extendJsonFromElement(nested); // or selectorParams //self.do(nested, partSelector, partObj); self.do(nested, params.selector, partObj); /* self.log('nested'); self.log(nested); self.log('part key'); self.log(params.key); self.log('part obj'); self.log(part); */ } else { // if (!jsonicPart) { // should be if (par !== 'on', 'attr', 'style', 'items/data') // params.key is not var/data, a method, a part //var jsFunction = self.element({path: params.key, root: self.functions}); if (self.json && self.json.functions && params.key && self.json.functions[params.key]) { //if (self.json.functions[params.key]) { self.log('FUNCTION: ' + params.key, 'grey'); /* self.log('pluginsRequired'); self.log(pluginsRequired); */ let args = self.replaceProperties(params.obj, undefined, true); // undefined properties -> '' /* console.log('%cargs', 'color:red'); console.log(args); */ 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.functions[params.key], args); 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 }); //self.functions[params.key](...args); } } else { /* let args = self.replaceProperties(params.obj); if (!args || !Array.isArray(args)) args = [args]; */ self.log('Function without plugin required: ' + params.key, 'grey'); self.function({ name: params.key, arguments: args }); // TO DO: check why here it can't have [] //self.functions[params.key](...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)); // undefined properties -> '' //windowFunction(self.replaceProperties(params.obj)); } else if (windowFunction !== undefined) { self.log('window.' + params.key + ' is not a function', 'red'); //self.log(params.key + ' not found', 'red'); // use set for window assignment /* self.element({path: params.key, value:params.obj, root: window}); */ } else { // NESTED HTML // Need to be improved. with nestedAction and nestedTag // here we can search only nestedAction // and from html we can search only for nestedTag's //nested = params.obj; // removed in 1.0.1 // if is a nested html params.selector is required // impossible to understand if we are inside an html method // because the html tags can be nested and with any name if (params.selector) { // added in 1.0.1 self.log('TAG: ' + params.key, 'grey'); // should be also in this.html function if params is an array 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); // tagParam = params.key //if (nested.database) self.addFirebaseTag(self.extend({}, nested, params.selector)); } } else { self.log(params.key + ' not found', 'red'); } } } } } } } }; this.setData = function (params) { //self.log('setData'); let setObj = {}; setObj[params.key] = params.value; self.set(setObj); /* if (params.path.indexOf('{') >= 0) params.path = self.replaceProperties(params.path); if (typeof params.value == 'string' && params.value.indexOf('{') >= 0) params.value = self.replaceProperties(params.value); self.element({path: params.path, value: params.value}); */ /* self.log(params.path); self.log(self.element({path: params.path})); */ }; this.partContainers = {}; this.pluginsRequiredByTag = function (params, tagKey) { // self.log('pluginsRequiredByTag'); /* self.log('params'); self.log(params); self.log('par'); self.log(par); */ if (self.json.resources) { // analize function object or array of objects 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') { // for example: "tagName": "string" where tagName requires a plugin } else if (typeof params == 'object') { var objArray; if (Array.isArray(params)) objArray = params; else objArray = [params]; for (var obj of objArray) { if (obj.attr) { // attr var attr = 'data-icon'; if (obj.attr[attr]) { if (pluginsAttr[attr] && !self.pluginsLoaded[pluginsAttr[attr].name]) pluginsRequired.push(pluginsAttr[attr]); } } } } return pluginsRequired; } else { // should load resources return false; } }; /* 'locale': { unit: month, weekday format: long, short, narrow index: 1, lang: page:language */ 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'); } }; 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; }; this.weekday = function (params, weekdayFormat) { //weekdayFormat = weekdayFormat || 'long'; 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; //if (weekdayFormat == 'short') result = result.substring(0,3); return result; }; /* this.array = function (params, args) { // TO DO: to be removed self.log('array'); self.log(params); if (Array.isArray(params)) return params; else if (typeof params == 'string') return self.docElement(params); else if (typeof params == 'object') { if (params && Object.keys(params).length > 0) { // actionObj !== {} var actionKey = Object.keys(params)[0]; // -> for var actionFunction = self.docElement('Array.prototype.' + actionKey); // method in window var actionValue = params[actionKey]; //actionValue = self.compile(actionValue, args); // array -> undefined if (!Array.isArray(actionValue)) actionValue = [actionValue]; if (actionFunction) { if (typeof actionFunction == 'function') return actionFunction.call(actionValue); else return actionFunction; } else { self.log('unknown window function'); return params; // return the same object } } else { self.log('empty function'); //self.log(actionObj); return undefined } } } */ 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]; // -> for var actionFunction = self.docElement(actionKey); // method in window var actionValue = params[actionKey]; //actionValue = self.compile(actionValue, args); 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; // return the same object } } else { //self.log('empty function'); //self.log(params); return undefined; } } } /* var methodArgs = self.compile(actionValue, args); if (value !== undefined) { if (!Array.isArray(methodArgs)) methodArgs = [methodArgs]; self.log('params'); self.log(params); for (let method of methodArgs) { for (let key in method) { if (key !== 'args') { self.log('key'); self.log(key); if (value[key]) if (method[key] && method[key] !== '') { // va aggiunto? -> && value[key](method[key]) method[key] !== undefined && methodArgs = method[key]; self.log('methodArgs'); self.log(methodArgs); if (!Array.isArray(methodArgs)) methodArgs = [methodArgs]; for (let index in methodArgs) { let methodArg = self.compile(methodArgs[index], args); //if (typeof methodArg == 'string' && methodArg !== '' && methodArg == Number(methodArg)) // can be in compile methodArgs[index] = methodArg; // Number(methodArg) } //try { //} catch (error) { // self.log('Dayjs function error'); if (typeof value[key] == 'function') value = value[key](...methodArgs); // ES6 way } else if (typeof value[key] == 'function') value = value[key](); else value = value[key]; } else { self.log('Method ' + key + ' in ' + methodName + ' not exist'); } } } } else { self.log('method '+ methodName +' undefined'); } */ }; this.Number = function (params, args) { self.log('Number'); return self.method({ "Number": params }, args); }; this.String = function (params, args) { self.log('String'); return self.method({ "String": params }, args); // jsonic.compile({String:{args:'1',padStart:[2, '0']}}) /* "text": { "String": { "args": "{hour}", "padStart": [ "0", 2 ] } } */ }; this.Math = function (params, args) { return self.method(params, args, 'Math'); /* if (!Array.isArray(params)) params = [params]; for (let method of params) { for (let key in method) { self.log(key); if (method[key] && method[key] !== '' && value[key](method[key])) { //methodArgs = self.compile(method[key]); methodArgs = method[key]; if (!Array.isArray(methodArgs)) methodArgs = [methodArgs]; for (let index in methodArgs) { let methodArg = self.compile(methodArgs[index]); if (typeof methodArg == 'string' && methodArg !== '' && methodArg == Number(methodArg)) // can be in compile methodArgs[index] = Number(methodArg); } value = value[key](...methodArgs); // ES6 way } else value = value[key](); } } return value; */ }; this.dayjs = function (params, args) { return self.method(params, args, 'dayjs'); /* self.log('dayjs'); var value = dayjs(); if (params.time) value = dayjs(params.time); //value = self.compile(value); if (!Array.isArray(params)) params = [params]; for (let method of params) { for (let key in method) { if (key == 'time') { } else if (value[key]) { if (method[key] && method[key] !== '' && value[key](method[key])) { //methodArgs = self.compile(method[key]); methodArgs = method[key]; if (!Array.isArray(methodArgs)) methodArgs = [methodArgs]; for (let index in methodArgs) { let methodArg = self.compile(methodArgs[index]); if (typeof methodArg == 'string' && methodArg !== '' && methodArg == Number(methodArg)) // can be in compile methodArgs[index] = Number(methodArg); } value = value[key](...methodArgs); // ES6 way } else value = value[key](); } else { try { } catch (error) { self.log('Dayjs function error'); self.log(error); self.log('key'); self.log(key); self.log('method[key]'); self.log(method[key]); } } } self.log('value'); self.log(value); } return value; */ }; this.moment = function (params, args) { return self.method(params, args, 'moment'); /* self.log('moment'); var value = moment(); if (params.time) value = moment(params.time); if (!Array.isArray(params)) params = [params]; for (let method of params) { for (let key in method) { if (key !== 'time') { if (key == 'add') { value = value.add(Number(method[key].value), method[key].unit); } else if (key == 'subtract') { value = value.add(Number(method[key].value), method[key].unit); } else if (method[key] && method[key] !== '' && value[key](method[key])) { value = value[key](method[key]); } else { self.log('Moment function error: '); self.log('key'); self.log(key); self.log('method[key]'); self.log(method[key]); } } } self.log('value'); self.log(value); } return value; */ }; /* const methodsList = ['day, format', 'year', 'years', 'quarter', 'dayOfYear', 'month', 'months', 'date', 'minute', 'minutes', 'hour', 'hours', 'second', 'seconds', 'millisecond', 'milliseconds', 'weekday', 'weekdays', 'isoWeekday', 'weekYear', 'isoWeekYear', 'weeksInYear', 'week', 'isoWeek', 'set', 'max', 'min', 'local', 'parseZone', 'unix', 'utc', 'utcOffset', 'zone', 'isValid', 'invalid', 'valueOf', 'startOf', 'endOf', 'fromNow', 'toNow', 'from', 'to', 'calendar', 'diff', 'daysInMonth', 'toDate', 'toArray', 'toJSON', 'toString', 'toISOString', 'toObject', 'inspect', 'isBefore', 'isSame', 'isAfter', 'isSameOrBefore', 'isSameOrAfter', 'isBetween', 'isDST', 'isLeapYear', 'isDate', 'locale', 'localeData', 'lang', 'monthsShort', 'weekdaysShort', 'weekdaysMin', 'defineLocale', 'updateLocale', 'monthsParse', 'weekdaysParse', 'longDateFormat', 'isPM', 'meridiem', 'relativeTime', 'pastFuture', 'ordinal', 'preparse', 'postformat', 'invalidDate', 'firstDayOfWeek', 'firstDayOfYear', 'duration', 'clone', 'humanize', 'asMilliseconds']; for (var method in methodsList) { if (params[method]) value = value[method](params[method]); } */ /* for (let param in params) { if (param !== 'time') { if (typeof value == 'object') { //if (param == 'day') value = value.day(Number(params[param])); if (param == 'add') { self.log('params.add.value'); self.log(params.add.value); self.log('params.add.unit'); self.log(params.add.unit); self.log('value'); self.log(value); value.add(Number(5), params.add.unit); self.log('value.format(H)'); self.log(value.format('H')); } else if (param == 'subtract') value.add(Number(params.subtract.value), params.subtract.unit); else if (value[param] && value[param](params[param])) value = value[param](params[param]); else self.log('Moment function error: '+ params[param]); } self.log('value'); self.log(value); } } */ /* this.addNestedTag = function (params, selectorParams) { var selector = self.selector(self.extend({}, params, selectorParams)); // remove tag params var nestedParams = self.cloneObject(params); var tagParams = ['tag', 'container', 'id', 'class', 'value', 'data-value', 'style', 'attr', 'title', 'text', 'animation', 'action', 'on', 'src', 'media', 'color', 'background', 'width', 'height', 'margin', 'padding', 'firebase']; for (var par in nestedParams) { if (tagParams.indexOf(par) >= 0) delete nestedParams[par] } // serach for nested params var mainTags = ['div', 'ul', 'p', 'span', 'a', 'button', 'input', 'textarea', 'iframe', 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'figure', 'figcaption', 'svg', 'small', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'icons']; for (var par in nestedParams) { self.log(par + ' NESTED IN ' + selector); if (mainTags.indexOf(par) >= 0) { self.htmlTag(nestedParams[par], {container: selector}, mainTags[mainTags.indexOf(par)]); } } } */ this.dynamicCss = function (selector, property, value) { if (value.indexOf('{') >= 0) { var resizeData = self.dataStorage.get(element, "resize"); //var resizeData = $(selector).data('resize'); if (!resizeData) resizeData = {}; resizeData[property] = value; var resizeData = self.dataStorage.set(element, "resize", resizeData); //$(selector).data('resize', resizeData); if (!self.resizeActions[selector]) self.resizeActions[selector] = {}; self.resizeActions[selector][property] = value; var result = self.replaceProperties(value) || ''; //$(selector).css(property, result); // al cambio di pagina su this.page applichiamo self.resizeEvent() /* self.log('----------------------'); self.log('dynamicCss'); self.log('selector'); self.log(selector); self.log('property'); self.log(property); self.log('value'); self.log(value); self.log('result'); self.log(result); self.log('----------------------'); */ } else { var style = {}; style[property] = value; self.css({ style: style }); //$(selector).css(property, value); } }; /* this.calc = function (selector, property, value) { if (value.indexOf('{')>= 0) { //var calcFunction = String(element.match(/calc\(([^\)]*)\)/)[0]); var result = self.replaceProperties(value) || ''; return result; } else { return value; } } */ /* this.hTag = function (params, selectorParams, index) { // this.img already exist if (Array.isArray(params)) { for (var index in params) self.hTag(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.hTag(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') {params = {text: params}}; params.tag = 'h'+index; var paramsReplaced = self.replaceProperties(params); self.addTag(paramsReplaced, selectorParams); } } } */ /* this.img = function (params, selectorParams, args) { //self.log('img'); var tagParam = 'img'; var mainParam = 'src'; if (Array.isArray(params)) { for (var index in params) self.img(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.img(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') {params = {src: params}}; params.tag = 'img'; //if (params.media) params.src = '{media:' + params.media + '}'; // can go under replaceProperties var paramsReplaced = self.replaceProperties(params, args); //var container = params.container || self.selector(selectorParams); self.addTag(paramsReplaced, selectorParams); } } } */ /* this.small = function (params, selectorParams) { // bootstrap var mainParam = 'text'; if (Array.isArray(params)) { for (var index in params) self.small(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.small(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') {params = {text: params}}; params.tag = 'small'; self.addTag(params, selectorParams); if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } } */ /* this.button = function (params, selectorParams) { // bootstrap var mainParam = 'text'; if (Array.isArray(params)) { for (var index in params) self.button(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.button(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') {params = {text: params}}; params.tag = 'button'; self.addTag(params, selectorParams); if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } } */ /* this.input = function (params, selectorParams) { var tagParam = 'input'; var mainParam = 'text'; if (Array.isArray(params)) { for (var index in params) self.input(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.input(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { self.addTag(self.createTagParams(params, tagParam, mainParam), selectorParams); if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } } this.span = function (params, selectorParams) { var mainParam = 'text'; if (Array.isArray(params)) { for (var index in params) self.span(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.span(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { params.tag = 'span'; // qui ci andrebbe replaceProperties if (typeof params == 'string') {params = {text: params}}; self.addTag(params, selectorParams); if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } } */ /* this.a = function (params, selectorParams) { var mainParam = 'text'; var tagParam = 'a'; if (Array.isArray(params)) { for (var index in params) self.a(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.a(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') {params = {text: params}}; params.tag = 'a'; self.addTag(params, selectorParams); if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } } */ /* this.p = function (params, selectorParams) { var mainParam = 'html'; if (Array.isArray(params)) { for (var index in params) self.p(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.p(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') {params = {html: params}}; params.tag = 'p'; self.addTag(params, selectorParams); if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } } */ /* this.lottie = function (params, selectorParams, args) { self.htmlTag(params, selectorParams, 'lottie-player', 'src'); } */ //this.lottie = function (params, selectorParams, args) { // self.htmlTag(params, selectorParams, 'lottie-player', 'src'); /* self.log('lottie'); var mainParam = 'src'; var tagParam = 'lottie-player'; if (Array.isArray(params)) { for (var index in params) self.lottie(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.lottie(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { var container = params.container || self.selector(selectorParams); // qui ci andrebbe replaceProperties //this.alert(self.selector(self.extend({}, params, selectorParams))); self.addTag(self.createTagParams(params, tagParam, mainParam), {container: container}); //if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } */ //} /* this.iframe = function (params, selectorParams) { var mainParam = 'src'; if (Array.isArray(params)) { for (var index in params) self.iframe(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.iframe(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (typeof params == 'string') {params = {src: params}}; params.tag = 'iframe'; var paramsReplaced = self.replaceProperties(params); self.addTag(paramsReplaced, selectorParams); } } } */ /* this.textarea = function (params, selectorParams) { if (Array.isArray(params)) { for (var index in params) self.textarea(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.textarea(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { if (!params.tag) params.tag = 'textarea'; //params.container = params.container || self.selector(selectorParams); self.addTag(params, selectorParams); } } } */ /* this.div = function (params, selectorParams) { if (params.firebase) { self.log('=========='); self.log('div'); self.log(params); self.log('=========='); } var tagParam = 'div'; var mainParam = 'text'; if (Array.isArray(params)) { for (var index in params) self.div(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.div(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { self.addTag(self.createTagParams(params, tagParam, mainParam), selectorParams); if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams)); } } } this.ul = function (params, selectorParams) { if (Array.isArray(params)) { for (var index in params) self.ul(params[index], selectorParams); } else { if (params.items) { var itemsArray = params.items; delete params.items; for (var index in itemsArray) { self.ul(self.replaceItems(params, itemsArray[index]), selectorParams); } } else { params.tag = 'ul'; var paramsReplaced = self.replaceProperties(params); self.addTag(paramsReplaced, selectorParams); if (params.firebase) self.addFirebaseTag(params); } } } */ 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; //var itemsArray = 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'; //params.container = params.container || self.selector(selectorParams); self.do(params, selectorParams); } } }; 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(); }); } } }; 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)); }); } } }; /* this.element with "selector" and "method": (remove/dispatchEvent) */ this.html = function (params, selectorParams, args) { /* self.log('html'); self.log('params'); self.log(params); self.log('selectorParams'); self.log(selectorParams); */ // TO DO: update // html properties can be only: // selector, attr, html, on, for, if // can't be: // animate (should go inside on: init?) // tags (div etc) because it should go inside html // do // functions, window functions... // text should be alternative to html tag. if inside html, it should give an error // TO DO: verificare se args viene portato agli elementi annidati (non andava con svg) if (params) { if (Array.isArray(params)) { // TO DO: shoud check if params require plugins for (var obj of params) self.html(obj, selectorParams, args); } else { //if (params.container == '#weatherReport') alert() //var container = (selectorParams) ? self.selector(selectorParams) : params.container; // unused //var selector = self.selector(self.extend({}, params, selectorParams), undefined, true); //), undefined, true); /* self.log('selector'); self.log(selector); */ var container = self.selector(params.selector || params.container) || self.selector(selectorParams); //var container = self.selector(selectorParams, undefined, true) || self.selector(params, selectorParams, true); /* self.log('container'); self.log(container); */ /* var element = self.query(container); self.log('element'); self.log(element); */ if (container) { var element = self.query(container); // empty or not? probably yes (like jquery) but we need append/prepend method // append only all the items in the array // TO DO: queryAll -> elements if (element) { if (typeof params == 'string') { //var paramsCompiled = self.compile(params, args); var paramsCompiled = self.replaceProperties(params, args); //$(container).append(paramsCompiled); // should be .html not append //element.appendChild(paramsCompiled); if (paramsCompiled) { if (typeof paramsCompiled == 'object') { // should be a nested tag or actions on,for,if,empty self.do(paramsCompiled, { selector: container }, args); } else if (typeof paramsCompiled == 'string') { element.innerHTML += paramsCompiled; // TO DO: now is like append. Is it correct? } } } else { if (params.empty || params.do == 'empty') { element.innerHTML = ''; delete params.empty; } if (params.tag) { self.do(params, container, args); //self.nested({key: params.tag, obj: params[par], selector: {selector: container}, args: args}); } else if (params.html) { // replace \" to " //var htmlCompiled = self.compile(params.html, args); // is undefined // TO DO: replace all the following "compile" with replaceProperties? /* self.log('params.html'); self.log(params.html); */ var htmlCompiled = self.replaceProperties(params.html, args); /* self.log('htmlCompiled'); self.log(htmlCompiled); */ self.html(htmlCompiled, { selector: container }); } else if (params.lang) { //alert(self.json.setup.language); 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); // textKey instead of lang? self.dataStorage.set(element, 'params', params); } } else if (params.text) { // string //params.text = self.replaceTags({text:params.text}); //params.text = self.text(params.text); // verifica presenza di tags e traduzioni //$(selector).text(self.compile(params.text, args)); element.textContent = self.replaceProperties(params.text, args); //} else if (params.empty || params.do == 'empty') { // element.innerHTML = ''; } else if (params.append) { // string //params.append = self.replaceTags({text:params.append}); //$(selector).append(self.compile(params.append, args)); //element.appendChild(self.compile(params.append, args)); element.innerHTML += self.replaceProperties(params.append, args); } else if (params.prepend) { // string //params.prepend = self.replaceTags({text:params.prepend}); //$(selector).prepend(self.compile(params.prepend, args)); //element.insertBefore(self.compile(params.prepend, args)); element.innerHTML = self.replaceProperties(params.prepend, args) + element.innerHTML; } else if (params.blocks) { // obsolete 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); // on, for, if... (can be changed to include also html) self.do(nestedParams, { selector: container }, args); if (element.isConnected) { // case "html":{selector:... attr: } // the wrong use "html":{selector, attr, html:...} // now doesn't work (because is inside the last else) /* if (params.on) { alert(container); self.on(params.on, { selector: container }, args); } */ if (params.attr) self.setAttributes(element, params.attr, args); if (params.style) self.css(params, selectorParams, args); // to be removed // TO DO: params.style is deprecated (now in attr or css) } //self.blocks(params, selectorParams, args); } } } else { // !element } } else { self.log('"html" object requires selector property', 'red'); self.log(params); //self.log(selectorParams); } //} //} } } else { self.log('"html" object without params'); } }; /* this.add = function (params) { // obsoleto, sostituito da html var selector = self.selector(params); if (params.inverse) $(selector).append(params.html); else $(selector).prepend(params.html); } */ /* this.attr = function (params, selectorParams, args) { var selector = self.selector(params); var element = self.query(selector); for (var attribute in params.attr) elements.forEach(function (element, index) { element.setAttribute(attrId, attrValue); }); } */ /* this.empty = function (params) { // { [container, class, value, id] } var selector = self.selector(params); $(selector).empty(); } */ /* this.addClass = function (params) { var selector = self.selector(params); $(selector).addClass(params); } this.removeClass = function (params) { self.log('removeClass'); var selector = self.selector(params); $(selector).removeClass(params); } */ /* this.toggleClass = function (params) { var selector = self.selector(params); $(selector).toggleClass(params); } */ //"#wifi > ul > li > span[data-field=share]:contains('Private')" 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, ""); //self.attribute(elements, attribute, attrs[attribute]); //self.attribute(elements, attribute, self.replaceWithPrefix(attrs[attribute], 'result', args)); // TO DO: check // before remove and check all the {result} occurrence (result excludes do/then/success etc.) // replaceResult replace {result} from Alert (should be obsolete) // check in the actual apps if {result} is used }; /* this.setAttributes = function (elements, attrs, args) { if (!Array.isArray(elements)) elements = [elements]; elements.forEach(function (element, index) { for (var attribute in attrs) { if (typeof attrs[attribute] == 'boolean' && attrs[attribute]) { // it consider also firebase (empty values are removed) element.setAttribute(attribute, ""); } else { //if (attrs[attribute] == undefined) attrs[attribute] = ''; element.setAttribute(attribute, self.replaceProperties(attrs[attribute])); } } }); self.attribute(elements, attribute, self.replaceResult(attrs[attribute], args)); }; */ // TO DO: distinguish setAttribute from getAttribute // because we need to set attribute empty 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) { // it consider also firebase (empty values are removed) element.setAttribute(attrId, ""); } else { element.setAttribute(attrId, self.replaceProperties(attrValue)); } }); } else { if (!Array.isArray(elements)) return elements.getAttribute(attrId); // todo: intercept the error "Cannot read properties of undefined (reading 'getAttribute" else return elements[0].getAttribute(attrId); } }; this.attr = function (params, selectorParams, args) { // deprecated. to be replaced with "css" {selector, style, addClass, removeClass, toggleClass} // css is used as an action to apply addClass removeClass toggleClass // and to apply style: {...} //params = self.replaceProperties(params); self.css(self.replaceProperties(params), selectorParams, args); }; 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); } }; this.css = function (params, selectorParams, args) { // {selector, style, addClass, removeClass, toggleClass} /* console.log('selectorParams'); console.log(selectorParams); console.log('css'); console.log(params); */ if (Array.isArray(params)) { for (var obj of params) self.css(obj, selectorParams, args); /* } else if (params.selector && Array.isArray(params.selector)) { for (let selector of params.selector) { let obj = self.cloneObject(params); obj.selector = selector; 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); //var selector = params.selector || selectorParams; //var elements = document.querySelectorAll(selector); //console.log(elements); 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); } } }; /* this.class = function (params) { // obsolete -> css self.log('self.class'); self.log(params); // { [container, class, value, id] // [style, addClass, removeClass] } var selector = self.selector(params); if (params.style) $(selector).css(params.style); if (params.add) $(selector).addClass(params.add); if (params.remove) $(selector).removeClass(params.remove); if (params.toggle) $(selector).toggleClass(params.toggle); } */ /* this.createPage = function (data) { // SPOSTATA SOTTO fixo.pages.js //self.log('createPage'); //self.log(data); if (!$('#'+data.id).length) { $(data.container).append('
    '); if (data.background) { $('#'+data.id).css({ 'background-color': data.background }); } } } */ /* this.iconPng = function(icon) { return 'https://'+self.domain+'/app/files/icons/100white/'+icon+'.png'; } */ /* this.imgTag = function (data) { // DIPENDENZA CON iconPng var imgId = data.id || ''; var imgClass = data.class || ''; var imgValue = data.value || ''; var imgStyle = data.style || ''; // || 'width: 84px; margin:6px 10px;'; // ATTENZIONE: stile predefinito da rimuovere var onClick = (data.action) ? 'onclick="javascript:self.do(\''+data.action+'\',\''+imgValue+'\')" ' : ''; return ''; } */ /* this.setImg = function (data) { // Sembra inutilizzata // DIPENDENZA CON iconPng // data = {icon, style} var selector = self.selector(data); var imgValue = data.value || ''; $(selector).attr('src', self.iconPng(data.icon)); if (data.style) $(selector).css(style); if (data.action) { $(selector).attr('onclick', 'javascript:self.do(\''+data.action+'\',\''+imgValue+'\')'); } } */ // -------------- // SVG // -------------- /* this.svgSet = function (params) { //self.log('svgSet'); //self.log(params); if (self.json && self.json.icons) { //if (self.json.setup && self.json.setup.icons) { if (params.icon) { var iconObj = {}; iconObj.icon = (params.icon.indexOf(':')) ? params.icon.split(/:/)[1] : string; iconObj.set = (params.icon.indexOf(':')) ? params.icon.split(/:/)[0] : undefined; var svgIcons = self.json.icons || {}; // {src, prefix, suffix} //var svgIcons = self.json.setup.icons || {}; // {src, prefix, suffix} if (iconObj.set) if (svgIcons[iconObj.set]) svgIcons = svgIcons[iconObj.set]; else self.log('Can\'t find the icons set "'+iconObj.set+'" in "icons"'); iconObj.src = svgIcons.src || ''; // serve? var svgPrefix = svgIcons.prefix || ''; var svgSuffix = svgIcons.suffix || ''; //if (iconObj.src !== '' && iconObj.icon) iconObj.src = '#' + svgPrefix + iconObj.icon + svgSuffix; if (iconObj.icon) { if (!svgIcons.preload) // siamo vicini iconObj.src = svgIcons.src + '#' + svgPrefix + iconObj.icon + svgSuffix; else iconObj.src = '#' + iconObj.set + '_' + svgPrefix + iconObj.icon + svgSuffix; } iconObj.viewbox = svgIcons.viewbox; // || '0 0 25 25'; return iconObj; // {src, set, name, viewbox} } else { self.log('icon "name" parameter undefined'); } } else { self.log('Can\'t find "icons" in "setup"'); } } this.svgChange = function (data) { self.log('svgChange'); self.log(data); var selector = self.selector(data); //), undefined, true); var containerElement = self.query(selector); var elementSvg = containerElement.querySelectorAll('svg')[0]; var elementSvgUse = elementSvg.querySelectorAll('use')[0]; var elementSvgText = elementSvg.querySelectorAll('text')[0]; var elementSvgCircle = elementSvg.querySelectorAll('circle')[0]; var iconObj = self.svgSet(data); // {src, set, name, viewbox} if (iconObj.src) elementSvgUse.setAttribute('xlink:href', iconObj.src); //$(data.container + ' > svg > use').attr('xlink:href', iconObj.src); if (data.text !== undefined) { elementSvgText.textContent = data.text; // $(data.container + ' > svg > text').text(data.text); var textY = 6.5; // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor if (data.textSize !== undefined) {textY = data.textSize/2;} if (data.textPosition == 'bottom') { // textPosition should be removed elementSvgUse.setAttribute('transform', 'translate(0, -20) scale(0.80)'); //$(data.container + ' > svg > use').attr("transform", "translate(0, -20) scale(0.80)"); textY += 26; } elementSvgText.setAttribute('y', textY); //$(data.container + ' > svg > text').attr('y',textY); elementSvgText.style['font-size'] = data.textSize+'px'; //$(data.container + ' > svg > text').css('font-size',data.textSize+'px'); } else { elementSvgText.textContent = ''; //$(data.container + ' > svg > text').text(''); } if (data.background !== undefined){ elementSvgCircle.setAttribute('fill', data.background); elementSvgCircle.setAttribute('fill-opacity', 1); elementSvgCircle.style['stroke'] = data.background; } if (data.border !== undefined) { elementSvgCircle.setAttribute('stroke-opacity', 1); elementSvgCircle.style['stroke'] = data.border; } if (data.color !== undefined && data.color !== 'colored') { elementSvgUse.style['fill'] = data.color; } if (data.textColor !== undefined){ elementSvgText.style['fill'] = data.textColor; } else if (data.color) { elementSvgText.style['fill'] = data.color; } } this.svgImage = function (data) { //$(data.container).hide(); //$(data.container).css({opacity:0}); var selector = self.selector(data); //), undefined, true); var containerElement = self.query(selector); //var containerElement = self.query(data.container); //if (data.value !== undefined) $(data.container).data('value', data.value); var iconObj = self.svgSet(data); // {src, set, name, viewbox} var viewBox = iconObj.viewbox || '-50 -50 100 100'; var htmlString = ''; if (containerElement) { containerElement.innerHTML = htmlString; //$(data.container).append(''); var elementSvg = containerElement.querySelectorAll('svg')[0]; var elementSvgUse = elementSvg.querySelectorAll('use')[0]; var elementSvgText = elementSvg.querySelectorAll('text')[0]; var elementSvgCircle = elementSvg.querySelectorAll('circle')[0]; elementSvgUse.setAttribute('xlink:href', iconObj.src); //$(data.container + ' > svg > use').attr('xlink:href', iconObj.src); if (data.text !== undefined) { elementSvgText.textContent = data.text; // $(data.container + ' > svg > text').text(data.text); var textY = 6.5; // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor if (data.textSize !== undefined) {textY = data.textSize/2;} if (data.textPosition == 'bottom') { // textPosition should be removed elementSvgUse.setAttribute('transform', 'translate(0, -20) scale(0.80)'); //$(data.container + ' > svg > use').attr("transform", "translate(0, -20) scale(0.80)"); textY += 26; } elementSvgText.setAttribute('y', textY); //$(data.container + ' > svg > text').attr('y',textY); elementSvgText.style['font-size'] = data.textSize+'px'; //$(data.container + ' > svg > text').css('font-size',data.textSize+'px'); } if (data.background !== undefined) { elementSvgCircle.setAttribute('fill', data.background); elementSvgCircle.setAttribute('fill-opacity', 1); elementSvgCircle.style['stroke'] = data.background; } if (data.border !== undefined){ elementSvgCircle.setAttribute('stroke-opacity', 1); elementSvgCircle.style['stroke'] = data.border; //$(data.container + ' > svg > circle').attr('stroke-opacity', 1); // FORSE DEVE DIVENTARE attr ANZICHE' css //$(data.container + ' > svg > circle').css({'stroke': data.border}); } //if ((data.color === undefined) && (data.color !== 'colored')) {data.color = '#fff';} if (data.color !== undefined && data.color !== 'colored') { elementSvgUse.style['fill'] = data.color; //$(data.container + ' > svg > use').css({'fill': data.color}); //$(data.container + ' > svg > text').css({'fill': data.color}); } if (data.textColor !== undefined){ elementSvgText.style['fill'] = data.textColor; //$(data.container + ' > svg > text').css({'fill': data.textColor}); } else { elementSvgText.style['fill'] = data.color; //$(data.container + ' > svg > text').css({'fill': data.color}); } self.css({style: data.style}, {container: data.container + ' > svg'}); } } this.svg = function (params, selectorParams, args) { var paramsReplaced = self.replaceProperties(params, args); //var container = self.selector(self.extend({}, params, selectorParams)); var container = self.selector(paramsReplaced, undefined, true) || self.selector(selectorParams, undefined, true); var element = self.query(container); var color = paramsReplaced.color || getComputedStyle(element).color; //if (element.getElementsByTagName('SVG').length == 0) { //if (element.querySelectorAll('svg').length == 0) { self.svgImage({ container: container, // special param icon: paramsReplaced.icon, text: paramsReplaced.text, textSize: paramsReplaced.textSize, // verify (obsolete when span will be nested) textPosition: paramsReplaced.textPosition, // verify (obsolete when span will be nested) textColor: paramsReplaced.textColor, // verify (obsolete when span will be nested) background: paramsReplaced.background, border: paramsReplaced.border, color: paramsReplaced.color || color, // $(container).css("color"), style: paramsReplaced.style, // da fare css in svgImage class: paramsReplaced.class //hoverBackground: data.hoverBackground, // verify //hoverBorder: data.hoverBorder, // verify //hoverColor: data.hoverColor, // verify }); } */ // -------------- // ITEM // -------------- /* this.checkItem = function (data) { var selectedIconClass = data.selection || 'selectedIcon'; // self.json.setup.classes.selectedIcon; //self.log('checkItem'); //self.log(data); var checked = 0; // var selector = ''; var selector = self.selector(data); if (data.style === undefined) {data.style = selectedIconClass;} if (data.checked !== undefined) { checked = self.replaceProperties(data.checked); //checked = self.replaceTags({text:data.checked}); checked = data.checked; if (data.checked) { $(selector).addClass(data.style); } else { $(selector).removeClass(data.style); } } else { checked = $(selector).hasClass( data.style ); } return checked; } */ /* this.toggleItem = function (data) { // modificato 20180709 da changeCheckItem in toggleItem self.log('toggleItem'); //self.log(data); var checked; checked = self.checkItem({ id: data.id, class: data.class, value: data.value //style: data.style }); checked = !checked; // inverte il valore self.checkItem({ id: data.id, class: data.class, value: data.value, checked: checked //style: data.style, }); return checked; } */ /* this.selectItem = function (data) { var selectedIconClass = self.json.setup.classes.selectedIcon; var selector = self.selector({container: data.container, class: data.class}); if (data.style === undefined) {data.style = selectedIconClass;} $(selector).removeClass(data.style); self.log('selector'); self.log(selector); if (data.value || data.id) { selector = self.selector(data); $(selector).addClass(data.style); } } this.unselectItems = function (data) { var selectedIconClass = self.json.setup.classes.selectedIcon; //if (data.style) if (data.style === undefined) {data.style = selectedIconClass;} if (data.class.indexOf('.') < 0) {data.class = '.' + data.class} $(data.class).removeClass(data.style); } */ /* this.removeImage = function (data) { var selector = self.selector(data); $(selector).css({'background-image':'url()'}); } this.loadImage = function (data) { var selector = self.selector(data); //if (!data.style) data.style = {}; //if (data.background) data.style['background-color'] = data.background; if (data.image || data.image === '') { self.getImage({ // ex fixo.loadImage object: selector, url: data.image //style: data.style, //animation: data.animation, }); } else { self.removeImage(data); } } */ /* this.changeItem = function (data, selectorParams, args) { self.log('changeItem'); self.log(data); var container = (selectorParams) ? self.selector(selectorParams) : data.container; var selector = self.selector(self.extend({}, data, selectorParams)); var iconClass = ''; //self.json.setup.classes.icon || ''; var badgeClass = 'iconBadge'; //self.json.setup.classes.badge || ''; if (data.svg || data.text || data.background || data.border || data.color) { $(selector + ' > svg').css({opacity:1}); self.svgChange({ container: selector, name: data.svg, text: data.text, background: data.background, border: data.border, color: data.color, }); } else { $(selector + ' > svg').css({opacity:0}); } // IMMAGINE if (data.image && data.image !== '') { var imgData = data; imgData.style = { width: '82px', height: '82px', 'margin-bottom': '27px' }; if (data.background) imgData.style['background-color'] = data.background; self.loadImage(imgData); $(selector + ' > svg').css({opacity:0}); } else { self.removeImage(data); $(selector + ' > svg').css({opacity:1}); } if (data.badgeIcon || data.badgeText) { if (!$('.'+badgeClass).length) $(selector).append('
    '); self.svgImage({ container: selector + ' > .'+badgeClass, icon: data.badgeIcon, text: data.badgeText, background: data.badgeBackground, border: data.badgeBorder, color: data.badgeColor, }); } else { $(selector + ' > .'+badgeClass).remove(); } if (data.titleColor) $(selector + ' > span').css({'color':data.titleColor}); else if (data.color) $(selector + ' > span').css({'color':data.color}); if (data.titleSize) $(selector + ' > span').css({'font-size':data.titleSize}); if (data.title) { $(selector+' > span').text(data.title); if ($(selector+' > span').hasClass('textFitted')) { self.textFit($(selector+' > span'), { alignHoriz: false, multiLine: false, alignVert: false, minFontSize: 10, maxFontSize: data.titleSize || 12, }); } } if (data.checked !== undefined) { self.checkItem({ container: data.container, class: data.class, value: data.value, id: data.id, checked: data.checked //style: data.style, }); } // action (obsolete) if (data.action) { var onData = $(selector).data('onData'); onData.action = data.action; $(selector).data('onData', onData); // nuova versione } // events if (data.on) self.on(data.on, {container: selector}); } */ /* this.enableIcon = function (params, selectorParams) { var container = (selectorParams) ? self.selector(selectorParams) : params.container; var selector = self.selector(self.extend({}, params, selectorParams)); $(selector).css({'opacity':'1'}); $(selector).off().on(self.touch, function(event){ event.stopPropagation(); self.onEvent(this, event); }); } this.disableIcon = function (params, selectorParams) { var badgeClass = self.json.setup.classes.badge || ''; var container = (selectorParams) ? self.selector(selectorParams) : params.container; var selector = self.selector(self.extend({}, params, selectorParams)); $(selector + ' > .'+badgeClass).remove(); $(selector).css({'opacity':'0.5'}); $(selector).off(); } */ /* this.getFileExtension = function (path) { var dotPosition=path.lastIndexOf("."); var stringLength=path.length; var extensionFile=path.substring(dotPosition+1,stringLength); return extensionFile; } */ // -------------------- // SLIDER // -------------------- /* var slides = {}; var sliderLib = 'fixoSlider'; var sliderWrapperClass = 'fixoSlider'; //var sliderSlideClass = 'fixoSlidez'; var sliderSelectedClass = 'slideSelected'; */ /* var sliderLib = 'flickity'; var sliderWrapperClass = 'fixoSlider'; var sliderSlideClass = 'fixoSlide'; var sliderSelectedClass = 'is-selected'; */ /* var sliderLib = 'sliderpro'; var sliderWrapperClass = 'sp-slides'; var sliderSlideClass = 'sp-slide'; var sliderSelectedClass = 'sp-selected'; */ /* var sliderLib = 'swiper'; var sliderWrapperClass = 'swiper-wrapper'; var sliderSlideClass = 'swiper-slide'; var sliderSelectedClass = 'swiper-slide-active'; */ /* this.sliderResume = function (data) { var selector = self.selector(data); if (slides[selector]) slides[selector].object.resume(); } this.sliderFreeze = function (data) { var selector = self.selector(data); if (slides[selector]) slides[selector].object.freeze(); } this.sliderNext = function(data) { var selector = self.selector(data); if (sliderLib == 'fixoSlider') slides[selector].object.next(); //if (sliderLib == 'flickity') slides[selector].object.flickity('next'); } this.sliderPrev = function(data) { var selector = self.selector(data); if (sliderLib == 'fixoSlider') slides[selector].object.prev(); //if (sliderLib == 'flickity') slides[selector].object.flickity('previous'); } this.autoSliderEvent = function() { var selector = self.selector(data); if (self.sliderSelected) slides[self.sliderSelected].object.autoSliderEvent(); } this.addSlideIcon = function(data) { // creata per rendere più leggibile createSlide var selector = self.selector(data); var isImage = self.getFileExtension(data.icon); if (isImage == 'gif' || isImage == 'jpg' || isImage == 'jpeg' || isImage == 'png') fixo.loadImage({ object: selector + ' > .slideIcon', url: data.icon, style: {height: '150px', width: '150px', marginTop: '25px', marginLeft: '-75px', backgroundSize: 'cover' } }); else //if (data.icon) self.svgImage({ container: selector + ' > .slideIcon', icon: data.icon, color: '#fff', }); if (data.iconName) $(selector + ' > .slideIconName').html(data.iconName); // da cancellare? if (data.iconAction) { var value = data.iconValue || ''; $(selector + ' > .slideIcon').attr('onclick', 'javascript:self.do(\''+data.iconAction+'\', \''+value+'\')'); } } this.changeSlideIcon = function(data) { var selector = self.selector(data); // verificare se si può usare changeItem if (data.icon) self.svgChange({ container: selector + ' > .slideIcon', name: data.icon, color: '#fff', }); if (data.iconName) $(selector + ' > .slideIconName').html(data.iconName); } this.updateSlide = function(data) { self.log('updateSlide'); if (!data.class) data.class = 'fixoSlide'; var selector = self.selector(data); // ICONA self.changeSlideIcon(data); // BACKGROUND if (data.background) $(selector).css({'background-color':data.background}); // TITOLO E TESTO var alertTitleObj = $(selector).children('.slideTitle'); var alertTextObj = $(selector).children('.slideText'); var titleAndText = (alertTitleObj.text() !== '' && alertTextObj.text() !== ''); if (titleAndText) { alertTitleObj.css({'margin-top':'-225px'}); } else { alertTitleObj.css({'margin-top':'-60px'}); } if (data.title !== undefined) { alertTitleObj.html(data.title); self.textFit(titleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 40, maxFontSize: 56}); } if (data.text !== undefined) { alertTextObj.html(data.text); self.textFit(textObj, {alignHoriz: true, multiLine: false, alignVert: !titleAndText, minFontSize: 17, maxFontSize: 40}); } // BOTTONE if (data.button !== undefined) { if (data.button) { if (data.buttonLabel) { $(selector + ' > .slideButton').html(data.buttonLabel); } if (data.buttonAction) { $(selector + ' > .slideButton').data('action', data.buttonAction); $(selector + ' > .slideButton').data('value', data.value); $(selector + ' > .slideButton').attr('onclick', 'javascript:self.do(\'' + data.buttonAction + '\',\''+data.value+'\')'); } $(selector + ' > .slideButton').show(); } else { $(selector + ' > .slideButton').hide(); } // aggiungere changeItem dell'icona } } this.slideTextFit = function() { //self.log('slideTextFit'); //if (!data.class) data.class = 'fixoSlide'; //var selector = self.selector(data); var slideSelector = self.sliderSelected + ' > .' + sliderSelectedClass; titleObj = $(slideSelector).children('.slideTitle'); textObj = $(slideSelector).children('.slideText'); var titleAndText = (titleObj.text() !== '' && textObj.text() !== ''); if (titleAndText) { titleObj.css({'margin-top':'-225px'}); //textObj.css({'top':(384+125-30)+'px'}); } else { titleObj.css({'margin-top':'-60px'}); } self.textFit(titleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 40, maxFontSize: 56}); self.textFit(textObj, {alignHoriz: true, multiLine: false, alignVert: !titleAndText, minFontSize: 17, maxFontSize: 40}); } this.sliderTo = function(data) { // apre la slide data.index self.log('sliderTo'); var selector = self.selector(data); if (data.index !== undefined) // comprende il caso = 0 if (slides[selector] && slides[selector].object) slides[selector].object.to(data.index); //if (sliderLib == 'swiper') // slides[selector].object.slideToLoop(data.index); // slideToLoop //if (sliderLib == 'flickity') // slides[selector].object.flickity('select', data.index); //if (sliderLib == 'extraslider') // $(selector+' > .extra-slider').trigger('extra:slider:goto', data.index); if (data.value !== undefined) { // comprende il caso = 0 self.log(self.selector(data)); if (!data.class) data.class = 'fixoSlide'; var slideToSelect = self.selector(data); var index = $(slideToSelect).index(); if (index > -1) slides[selector].object.to(index); //var slideToSelect = '.' + sliderSlideClass + '[data-value="' + data.prefix + data.value + '"]'; } //if (sliderLib == 'flickity') // slides[selector].object.flickity('selectCell', slideToSelect); } this.sliderExist = function(data) { // si può cancellare? var selector = self.selector(data); //alert(($(selector + ' > .extra-slider').length > 0)); return ($(selector + ' > .extra-slider').length > 0) // return (slides[selector]) } this.createSlide = function(data) { self.log('createSlide'); //if (!data.prefix) data.prefix = ""; if (!data.class) data.class = "fixoSlide"; //var containerSelector = self.selector(data); var slideContent = '
    '; if (data.inverse) { $(data.container).prepend(slideContent); } else { $(data.container).append(slideContent); } var selector = self.selector(data); var infoButtons = data.infoButtons || {}; // STORE DATA $(selector).data('container', data.container); if (data.value) $(selector).data('value', data.value); //if (data.id) $(selector).data('id', data.id); //if (data.prefix) $(selector).data('prefix', data.prefix); var textHtml = (data.text) ? data.text.replace(/\r?\n/g, '
    ') : ''; // PRICE //if(data.price && data.price !== '') textHtml += '
    € '+data.price; // BACKGROUND if (data.background) $(selector).css({'background-color':data.background}); // IMAGE if (data.image && data.image !== '') { if (data.title !== '' || textHtml !== '' ) { //$(selector).css({'background-image':'linear-gradient(to right,rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('+data.image+')'}); //} else { //$(selector).css({'background-image':'url('+data.image+')'}); $(selector).append('
    ') } if (sliderLib == 'fixoSlider') { $(selector).css({'background-image':'url('+data.image+')'}); // DA GESTIRE INTERNAMENTE A fixo.slider.js // DOVRA' CARICARE SOLO SLIDE ATTUALE, PREC. E SUCC //fixo.loadImage({ // object: selector, // url: data.image, // animation: 'fadeIn', //}); } //if (sliderLib == 'swiper') { // $(selector).addClass('swiper-lazy'); // $(selector).attr('data-background', data.image); //} //if (sliderLib == 'flickity') { // $(selector).attr('data-flickity-bg-lazyload', data.image); //} } else { $(selector).css({'background-image':'none'}); // SERVICE ICON //$(selector).append('
    '); //self.addSlideIcon(data); // if (data.icon) // self.svgImage({ // container: selector + ' > .slideIcon', // icon: data.icon, // color: '#fff', // }); // if (data.iconName) // $(selector + ' > .slideIconName').html(data.iconName); // if (data.icon) // self.svgImage({ // container: selector + ' > .slideIcon', // icon: data.icon, // color: '#fff', // }); // if (data.iconName) // $(selector + ' > .slideIconName').html(data.iconName); } // ICONA $(selector).append('
    '); self.addSlideIcon(data); // TITLE & TEXT $(selector).append('
    '); var alertTitleObj = $(selector + ' > .slideTitle'); var alertTextObj = $(selector + ' > .slideText'); var alertInfoObj = $(selector + ' > .slideInfo'); // BOTTONI INFO var btnInfo = ''; for (var i in infoButtons) { if (infoButtons[i].icon !== '') btnInfo += self.imgTag({ icon: infoButtons[i].icon, action: infoButtons[i].action, class: infoButtons[i].class, value: infoButtons[i].value, //style: 'width: 84px; margin:6px 10px;' }); //alertInfoObj.html(btnInfo); } alertInfoObj.html(btnInfo); // TESTO if (data.title && data.title !== '') { alertTitleObj.html(data.title); } else { alertTitleObj.html(data.iconName); } alertTextObj.html(textHtml); //alertInfoObj.html() // if (data.link && data.link !== '') { // serviva a costruire il div con il qrcode, sostituito dal link per aprire lo swal alert // var link = data.link; // self.log('DATALINK: '+link); // if (link.indexOf('musement.com') || link.indexOf('booking.com')) { // link = link.replace(/^https?:\/\//,''); //rimuovo https dal link // self.log('link: '+link); // link = 'https://c83.travelpayouts.com/click?shmarker=219111&promo_id=2015&source_type=customlink&type=click&custom_url=' + link; // } // self.log('DATALINK1: '+link); // $(selector).append('
    '); // self.qrCode({ // container: selector, // class: 'slideQrCode', // text: link, // size: 100 // }); // // attributo sul Codice QR per la visualizzazione dell'alert // $('.slideQrCode > img').attr('onclick','javascript:self.do(\'app.hot.alertQRCode\')'); // } else { $(selector).append(''); if (data.button) { if (data.buttonLabel) { $(selector + ' > .slideButton').html(data.buttonLabel); } if (data.buttonAction) { $(selector + ' > .slideButton').data('action', data.buttonAction); $(selector + ' > .slideButton').data('value', data.value); $(selector + ' > .slideButton').attr('onclick', 'javascript:self.do(\'' + data.buttonAction + '\',\''+data.value+'\')'); } $(selector + ' > .slideButton').show(); // $(selector + ' > .slideButton').off().on(self.touch, function(){ // var action = $(this).data('action'); // var key = $(this).data('value'); // self.do(action, value); // }); } else { $(selector + ' > .slideButton').hide(); } //} chiude l'IF del data.link var titleAndText = (alertTitleObj.text() !== '' && alertTextObj.text() !== ''); // POSIZIONE TITOLO var titleTop = -70 -170 * (titleAndText); alertTitleObj.css({'margin-top': titleTop + 'px'}); self.textFit(alertTitleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 30, maxFontSize: 56}); // ALTEZZA TESTO var textHeight = 340 - 100 * (infoButtons.length > 0); alertTextObj.css({'height': textHeight + 'px'}); //self.textFit(alertTitleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 30, maxFontSize: 56}); //self.textFit(alertTextObj, {alignHoriz: true, multiLine: false, alignVert: !titleAndText, minFontSize: 15, maxFontSize: 45}); //self.log('END createSLIDE'); } this.createSlider = function (data) { self.log('createSlider'); //if (!data.prefix) data.prefix = ""; var selector = self.selector(data); var startIndex = data.index || 0; //self.log('pre DATAINDEX: '+data.index); // RIMUOVE ISTANZA PRECEDENTE if (slides[selector] && slides[selector].object) { // Memorizza posizione var slideSelector = selector + ' > .' + sliderSelectedClass; //self.log('slideSelector di self.createSlider: '+slideSelector); startIndex = data.index || $(slideSelector).index(); // Rimuove slider precedente //self.log('startIndex: di '+data.index+' .index() '+$(slideSelector).index()); $(selector).empty(); delete slides[selector].object; } slides[selector] = {}; // FRECCE // if (data.buttons) { // if (sliderLib == 'swiper') { // $(selector).append('
    '); // $(selector).append('
    '); // } // } for (var key in data.slides) { var slide = data.slides[key]; slide.inverse = data.inverse; //slide.container = selector; //+' > .' + sliderWrapperClass; slide = self.extend({ container: selector, class: 'fixoSlide', //sliderSlideClass, value: data.value, //data.prefix + data.value }, slide); self.createSlide(slide); } // CREAZIONE OGGETTO SLIDER if (sliderLib == 'fixoSlider') { var params = { container: selector, //+' > .' + sliderWrapperClass, play: data.play, interval: data.interval, // ms onChange: data.onChange, onChangeStart: self.slideTextFit, index: startIndex // prima slide // direction: 1, // from right to left // opts.swipeDuration: 0.6, // sec // opts.swipeTreshold: 0.2, // Swipe from +/-20% }; slides[selector].object = $.fn.slide(params); } //self.log('END createSlider'); } */ /* this.getSelectedSlide = function (data) { self.log('getSelectedSlide'); //self.log(data); var selector = self.selector(data); if (sliderLib == 'fixoSlider') { var slideSelector = selector + ' > .' + sliderSelectedClass; self.log($(slideSelector).data('value')); return $(slideSelector).data('value'); } } var sliderSelect = function (currentItem, currentIndex) { //si può cancellare? var id = $(currentItem).parent().parent().parent().attr('id'); self.log('slideId:'+id); self.log('currentItem:'+currentItem); self.log('currentIndex:'+currentIndex); slides[id].currentItem = currentItem; slides[id].currentIndex = currentIndex; } var sliderPause = function (currentItem, currentIndex) { // si può cancellare? $(currentItem).parent().parent().trigger('extra:slider:pause'); var id = $(currentItem).parent().parent().parent().attr('id'); self.log('slideId:'+id); self.log('currentItem:'+currentItem); self.log('currentIndex:'+currentIndex); slides[id].currentItem = currentItem; slides[id].currentIndex = currentIndex; } var sliderPlay = function (currentItem, currentIndex) { // si può cancellare? $(currentItem).parent().parent().trigger('extra:slider:pause'); $(currentItem).parent().parent().trigger('extra:slider:resume'); var id = $(currentItem).parent().parent().parent().attr('id'); self.log('slideId:'+id); self.log('currentItem:'+currentItem); self.log('currentIndex:'+currentIndex); slides[id].currentItem = currentItem; slides[id].currentIndex = currentIndex; } var sliderResume = function (currentItem, currentIndex) { //si può cancellare? var id = $(currentItem).parent().parent().parent().attr('id'); if (slides[id].active) { sliderPlay(currentItem, currentIndex); } else { sliderPause(currentItem, currentIndex); } } var sliderClick = function (currentItem, currentIndex) { // si può cancellare ? var id = $(currentItem).parent().parent().parent().attr('id'); if (slides[id].active) { slides[id].active = false; } else { slides[id].active = true; } } */ /* this.addItem = function (data, selectorParams) { // obsolete var container = (selectorParams) ? self.selector(selectorParams) : data.container; var selector = self.selector(self.extend({}, data, selectorParams)); // app default // aggiungere anche dimensione di default var iconClass = self.json.setup.classes.icon || ''; var badgeClass = self.json.setup.classes.badge || ''; var style = (data.style) ? data.style : {}; // retro-compatibility if (data.size) { if (data.size == 'small') style.width = '50px'; else if (data.size == 'medium') style.width = '80px'; else if (data.size == 'big') style.width = '120px'; else if (data.size) style.width = data.size; } style = self.extend({}, style, { // retrocompatibilità / obsoleto color: data.color, background: data.background, border: data.border, display: data.display, margin: data.margin, padding: data.padding, width: data.width, height: data.height }); // Create if (data.id === undefined) {data.id = '';} if (data.value === undefined) {data.value = data.id}; if (data.class === undefined) {data.class = iconClass} else if (data.class !== iconClass) {data.class += ' ' + iconClass}; var itemDiv = '
    '; if (data.prepend) { $(data.container).prepend(itemDiv); } else { $(data.container).append(itemDiv); } self.css({style: { width: style.width, display: style.display, padding: style.padding, margin: style.margin }}, {container: selector}); // SVG if (data.svg || data.text) { self.svgImage({ container: selector, icon: data.svg, text: data.text, textSize: data.textSize, // verify (obsolete when span will be nested) textPosition: data.textPosition, // verify (obsolete when span will be nested) textColor: data.textColor, // verify (obsolete when span will be nested) background: style.background, border: style.border, color: style.color //hoverBackground: data.hoverBackground, // verify //hoverBorder: data.hoverBorder, // verify //hoverColor: data.hoverColor, // verify }); } else { } // image if (data.image) { var imgData = data; imgData.style = { width:'82px', height:'82px', 'margin-bottom':'27px' }; if (style.background) imgData.style['background-color'] = style.background; self.loadImage(imgData); } // badge if (data.badgeIcon || data.badgeText) { $(selector).append('
    '); self.svgImage({ container: selector + ' > .'+badgeClass, icon: data.badgeIcon, text: data.badgeText, background: data.badgeBackground, border: data.badgeBorder, color: data.badgeColor, }); } if (data.title) { //data.title = self.text(data.title); data.titleColor = data.titleColor || style.color; if (data.titleColor == undefined) {data.titleColor = ''} if (data.titleSize == undefined) {data.titleSize = ''} //if (data.titleSizeMin == undefined) {data.titleSize = '7px'} $(selector).append(''); $(selector + ' > span').css({ color: data.titleColor, 'font-size': data.titleSize }); //if (typeof data.title == 'object') alert(data.title.text); self.text(data.title, {container: selector + ' > span'}); //var title = self.text(data.title); //$(selector + ' > span').text(title); //self.text(data.title); // itemSelectedBorderWhite GESTITO IN INDEX.CSS // questo stile dovrebbe essere fisso e con posizione assoluta if (data.image) $(selector + ' > span').css({ 'margin-top':'89px', position: 'absolute' }); if (data.textFit !== false) { self.textFit($(selector+' > span'), { alignHoriz: false, multiLine: false, alignVert: false, minFontSize: 10, maxFontSize: data.titleSize, }); } } // action (obsolete) if (data.action || data.functions) { var.functions[selector] = data.functions || data.action; // obsoleto $(selector).data('onData', data); // nuova versione $(selector).off().on(self.touch, function(event){ event.stopPropagation(); self.onEvent(this, event); }); } // matchMedia if (data.matchMedia) { for (var mediaEvent in data.matchMedia) { self.matchMedia(data.matchMedia[mediaEvent], mediaEvent); } } // events if (data.on) self.on(data.on, {container: selector}); if (data.checked !== undefined) { self.checkItem({ container: data.container, class: data.class, value: data.value, id: data.id, checked: data.checked //style: data.style, }); } } */ // -------------- // TABS // -------------- /* this.addTab = function (data, selectorParams) { //self.log('addTab'); //self.log(data); var containerParams = self.cloneObject(selectorParams); data.container = containerParams.container; var selector = self.selector(data); var tabClass = ''; //self.json.setup.classes.button || ''; var badgeClass = 'iconBadge'; //self.json.setup.classes.badge || ''; var style = (data.style) ? data.style : {}; // span height //style["line-height"] = (style.height) ? style.height : '42px'; style = self.extend({}, style, { color: data.color, background: data.background, border: data.border, display: data.display, margin: data.margin, padding: data.padding, width: data.width, height: data.height }); if (data.id === undefined) {data.id = '';} if (data.value === undefined) {data.value = data.id}; if (data.class === undefined) {data.class = tabClass} else if (data.class !== tabClass) {data.class += ' ' + tabClass}; var tabDiv = '
    '; $(data.container).append(tabDiv); self.css({style: style}, {container: selector}); //if (data.key) {$(selector).data('key', data.key);} //var iconColor = style.color || $(selector).css("color"); // ICON if (data.icon) { self.addItem({ class: 'icon', value: data.value, svg: data.icon, image: data.image, style: { color: style.color || $(selector).css("color"), width: style.height } }, {container: selector}); } // TEXT if (data.text !== undefined) { //alert(JSON.stringify(data.text)); $(selector).append(''); self.text(data.text, {container: selector + ' > span'}); } else { //alert(JSON.stringify(data.text)); } if (data.icon) $(selector + ' > span').css({'padding-left': '0px'}); // SPAN if(style.color) $(selector + ' > span').css({'color':style.color}); // BADGE if (data.badgeIcon || data.badgeText) { if (!$('.'+badgeClass).length) $(selector).append('
    '); self.svgImage({ container: selector + ' > .'+badgeClass, icon: data.badgeIcon, text: data.badgeText, background: data.badgeBackground, border: data.badgeBorder, color: data.badgeColor, }); } else { $(selector + ' > .'+badgeClass).remove(); } // data if (data.action || data.functions){ var.functions[selector] = data.functions || data.action; // obsoleto $(selector).data('onData', data); // nuova versione $(selector).off().on(self.touch, function(event){ event.stopPropagation(); self.onEvent(this, event); //$(this).data('value') //var selector = $(this).data('selector'); //var action = var.functions[selector]; //self.do($(this).data('onData').action, $(this).data('value')); }); } // matchMedia if (data.matchMedia) { for (var mediaEvent in data.matchMedia) { self.matchMedia(data.matchMedia[mediaEvent], mediaEvent); } } // events if (data.on) self.on(data.on, {container: selector}); if (data.selected) self.selectTab(data); } */ /* this.changeTab = function (data, selectorParams) { var container = (selectorParams) ? self.selector(selectorParams) : data.container; var selector = self.selector(self.extend({}, data, selectorParams)); if (data.icon && data.value) { self.changeItem({ container: selector, class: 'icon', value: data.value, svg: data.icon, color: data.color, background: data.background }); } if(data.background) $(selector).css({'background':data.background}); if(data.color) $(selector + ' > span').css({'color':data.color}); if (data.text) { //$(selector + ' > span').text(self.text(data.text)); self.text(data.text, {container: selector + ' > span'}); } if (data.action){ $(selector).off().on(self.touch, function(){ data.action(data.value) }); } // events if (data.on) self.on(data.on, {container: selector}); if (data.selected) self.selectTab(data); } */ /* this.unselectTabs = function (data) { var selectionClass = data.selection || 'selectedButton'; //var selectionClass = self.json.setup.classes.selectedButton; if (data.style) selectionClass = data.style; $(data.class).removeClass(selectionClass); } this.toggleTab = function (data) { data.toggle = true; return self.selectTab(data); } this.selectTab = function (data) { var selectionClass = data.selection || 'selectedButton'; //var selectionClass = self.json.setup.classes.selectedButton; if (data.style) selectionClass = data.style; var selector = self.selector(data); if (data.deselectClass) if (data.class) $('.'+data.class).removeClass(selectionClass); if (data.checked !== undefined) { if (data.checked == false) $(selector).removeClass(selectionClass); else $(selector).addClass(selectionClass); } else if (data.toggle !== undefined) { // da toggleTab if ($(selector).hasClass(selectionClass)) { $(selector).removeClass(selectionClass); return false; } else { //if (data.class) $('.'+data.class).removeClass(selectionClass); $(selector).addClass(selectionClass); return true; } } else { //if (data.class) $('.'+data.class).removeClass(selectionClass); $(selector).addClass(selectionClass); } } */ // --------------------------- // FUNZIONI DATEPICKER // --------------------------- /* // basato su: http://www.daterangepicker.com/#options this.createDatePicker = function (data) { self.log('createDatePicker'); var calendarVisible = false; if (!data.field) data.field = data.container + ' > .daterange'; if (!$(data.field).length) { calendarVisible = true; // Crea e nasconde campo testo e mostra calendario $(data.container).html(''); } var weekD = self.weekdaysShort(1, capitalize); weekD = weekD.unshift(weekD[6]); var monthsOfYear = ["January","February","March","April","May","June","July","August","September","October","November","December"]; if (data.language) { monthsOfYear = moment.localeData(data.language).months(); for (var index in monthsOfYear) { monthsOfYear[index] = monthsOfYear[index].substr(0,1).toUpperCase() + monthsOfYear[index].substr(1); } } //var datarange = $('#daterange'); $(data.field).daterangepicker({ singleDatePicker: data.single, parentEl: data.container, startDate: data.start, endDate: data.end, autoApply: true, autoUpdateInput: false, locale: { format: 'DD/MM/YYYY', daysOfWeek: weekD, monthNames: monthsOfYear, firstDay: 1 // monday } }); $(data.field).on('cancel.daterangepicker', function(ev, picker) { data.onCancel(); }); $(data.field).on('apply.daterangepicker', function(ev, picker) { data.onChange({ start: picker.startDate.format('YYYYMMDD'), end: picker.endDate.format('YYYYMMDD') }); if (picker.startDate && picker.endDate && picker.startDate !== picker.endDate) { $(data.field).val(picker.startDate.format('DD/MM/YYYY') + '-' + picker.endDate.format('DD/MM/YYYY')); } else { $(data.field).val(picker.startDate.format('DD/MM/YYYY')); } }); self.unselectDatePicker({container: data.container}); } var disableDates = []; this.updateDatePicker = function(data) { var datePicker = $(data.container + ' > .daterange').data('daterangepicker'); if (data.disableDates) {disableDates = data.disableDates;} // alert(datePicker+'-'+data.container); datePicker.isInvalidDate = function(date) { return (disableDates.indexOf(date.format('YYYYMMDD')) >= 0) } datePicker.updateView(); if (data.start && data.end) { self.setDatePicker({ container: data.container, start: data.start, end: data.end, }); } else { self.unselectDatePicker({container: data.container}); } } this.unselectDatePicker = function(data) { $(data.container).find('.start-date').removeClass('start-date active'); $(data.container).find('.end-date').removeClass('end-date active'); $(data.container).find('.in-range').removeClass('in-range'); } this.setDatePicker = function (data) { var datePicker = $(data.container + ' > .daterange').data('daterangepicker'); datePicker.setStartDate(data.start); datePicker.setEndDate(data.end); datePicker.updateView(); } this.getDatePicker = function (data) { var start = $(data.container + ' > .daterange').data('daterangepicker').startDate(data.start); var end = $(data.container + ' > .daterange').data('daterangepicker').endDate(data.end); //alert('ok: '+data.container); return {start: start, end: end} } // --------------------------- // FUNZIONI TIMEPICKER // --------------------------- this.createTimePicker = function (data) { $(data.container).html('
    '); $(data.container + ' > .datetimepicker').datetimepicker({ icons: { up: "fixoNavUp", down: "fixoNavDown", previous: "fixoNavBackward", next: "fixoNavForward" }, inline: true, sideBySide: true, //locale: 'it' locale: { format: 'DD/MM/YYYY', daysOfWeek: weekD, monthNames: monthsOfYear, firstDay: 1 // monday } }); //self.log('now: '+Date.now()+' moment: '+moment()); self.setTimePicker({ container: data.container, time: data.time }); $(data.container + ' > .datetimepicker').off().on('dp.change', function(event) { var datePicked = moment(event.date).unix(); //alert(datePicked); data.onChange(datePicked); }); } this.setTimePicker = function (data) { //self.log('>>> setTimePicker --> data container: '+data.container+' data time: '+data.time+' moment: '+moment.unix(data.time).calendar()); $(data.container + ' > .datetimepicker').data('DateTimePicker').date(moment.unix(data.time));//.format('LLL')); } this.getTimePicker = function (data) { //alert('ok: '+data.container); $(data.container + ' > .datetimepicker').data('DateTimePicker').date(); } */ // --------------------------- // TIME SLIDER // --------------------------- /* this.createTimeSlider = function(data){ var container = data.container; var id = data.id; // c'è un'anomalia nella libreria bootstrap-slider // crea il contenitore dello slider con lo stesso id del campo input // va verificata la possibilità di configurazione della funzione .slider $('#'+data.container).append(''); $('#'+id).slider(); $('#'+id).off().on("slide slideStop", function(event) { self.log(event); self.changeItem({ id:'stepbackwardSlider'+id, text: self.numberToHour({value: event.value[0], max: 48}) }); self.changeItem({ id:'stepforwardSlider'+id, text: self.numberToHour({value: event.value[1], max: 48}) }); if (data.onChange) { data.onChange({ start: self.numberToHour({value: event.value[0], max: 48}), end: self.numberToHour({value: event.value[1], max: 48}) }) } }); // ICONS Slider self.addItem({ container:'#'+id+' > .min-slider-handle', class: 'sliderIconLeft', id: 'stepbackwardSlider'+id, background: '#fff', color: 'black', border: 1, text: '00:00' }); self.addItem({ container:'#'+id+' > .max-slider-handle', class: 'sliderIconRight', id: 'stepforwardSlider'+id, background: '#fff', color: 'black', border: 1, text: '24:00' }); //$('#'+sliderId+' .slider-selection').css({'background': '#fff'}); } this.setTimeSlider = function(data){ //Change value on slider left/right icon self.changeItem({ id:'stepbackwardSlider'+data.id, text: data.start }); self.changeItem({ id:'stepforwardSlider'+data.id, text: data.end }); //Convert value in 0-48 format var start = self.hourToNumber({value: data.start, max: 48}); var end = self.hourToNumber({value: data.end, max: 48}); // Set value on slider $('input[id="'+data.id+'"]').slider('setValue',[start,end]); } this.getTimeSlider = function(data){ var slideStart = $('input[id="'+data.id+'"]').slider('getValue')[0] || 0; var slideEnd = $('input[id="'+data.id+'"]').slider('getValue')[1] || 48; var start = self.numberToHour({value: slideStart, max: 48}); var end = self.numberToHour({value: slideEnd, max: 48}); if (start == '24:00') {start = '00:00'} var timetable = { start: start || '00:00', end: end || '24:00' } return timetable; } */ 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; }; 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); }; 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); }; 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); // var obj = self.compile(data); 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; //qrcode.clear(); // clear the code. //qrcode.makeCode(text); // make another code }; /* this.qrcode = function (data) { self.log('qrcode'); var selector = self.selector(data); var options = { // render method: 'canvas', 'image' or 'div' render: 'image', // version range somewhere in 1 .. 40 minVersion: 1, maxVersion: 40, // error correction level: 'L', 'M', 'Q' or 'H' ecLevel: 'L', // offset in pixel if drawn onto existing canvas left: 0, top: 0, // size in pixel size: data.size || 200, // code color or image element fill: data.color || '#000', // background color or image element, null for transparent background background: data.background || null, // content text: self.replaceProperties(data.text) || 'no text', // corner radius relative to module width: 0.0 .. 0.5 radius: 0, // quiet zone in modules quiet: 0, // modes // 0: normal // 1: label strip // 2: label box // 3: image strip // 4: image box mode: 0, mSize: 0.1, mPosX: 0.5, mPosY: 0.5, label: data.label || 'no label', fontname: data.fontname || 'sans', fontcolor: data.fontcolor || '#000', image: null } $(selector).empty().qrcode(options); } */ 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; }; 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; }; // ----------- // DRAG // ----------- /* var draggingData; this.sortable = function (data) { var rootEl = $(data.container)[ 0 ]; var dragEl; draggingData = data; var selector = self.selector(data); $(selector).attr('draggable', 'true'); $(data.exclude).attr('draggable', 'false'); // Function responsible for sorting function onDragOver(event) { event.preventDefault(); event.dataTransfer.dropEffect = 'move'; var dragTarget = event.target; // target.nextSibling || if ($(dragTarget).hasClass(draggingData.class)) $( dragEl ).insertAfter( $(dragTarget) ); if ($(dragTarget).parent().hasClass(draggingData.class)) $( dragEl ).insertAfter( $(dragTarget).parent() ); } // End of sorting function onDragEnd(event){ event.preventDefault(); $(dragEl).css({'opacity':'100%'}); rootEl.removeEventListener('dragover', onDragOver, false); rootEl.removeEventListener('dragend', onDragEnd, false); // Notification about the end of sorting draggingData.target = dragEl; draggingData.onDragEnd(draggingData); } // Sorting starts rootEl.addEventListener('dragstart', function (event){ dragEl = event.target; // Remembering an element that will be moved $(dragEl).css({'opacity':'50%'}); // Limiting the movement type event.dataTransfer.effectAllowed = 'move'; event.dataTransfer.setData('Text', dragEl.textContent); // Subscribing to the events at dnd rootEl.addEventListener('dragover', onDragOver, false); rootEl.addEventListener('dragend', onDragEnd, false); setTimeout(function () { // If this action is performed without setTimeout, then // the moved object will be of this class. $(dragEl).css({'opacity':'100%'}); }, 0) }, false); } */ /* this.setWeekDays = function(data){ if (!data.days) data.days = {}; for (var i=1; i<7; i++){ self.selectTab({ container: data.container, class: 'fixoTabsWeekDays', value: String(i), checked: data.days[String(i)] || false }); } } this.createWeekDays = function(data){ //var selector = self.selector(data); var weekDays = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"]; self.log('data.language '+data.language); if (data.language) weekDays=moment.localeData(data.language).weekdaysShort(); for (var i=0; i<7; i++){ var weekDay = weekDays[i]; self.addTab({ container: data.container, class: data.class, value: String(i), id: data.container + i, background: 'black', color: 'white', border: '1px solid rgba(0, 0, 0, 1)', text: weekDay, action: function(value){ //alert($(this).attr(id)); // il toggleTab deselezionava sempre gli altri giorni // risolto usando il selectTab col parametro checked // va sistemato toggleTab if (!data.days) data.days = {}; var checked = !Boolean(data.days[value]); self.selectTab({ container: data.container, class: 'fixoTabsWeekDays', value: value, checked: checked }); data.days[value] = checked; } }); } } */ //-------------------------- // DA FIXO.JS //-------------------------- /*--------------------- UTILS ---------------------*/ var sortField; 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; }; }; this.sort = function (data) { // fixo.sort({object:{}, add: {}, field:'time', reverse:true}) 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 []; } }; this.objectToArray = function (data) { // data: {object:{}, add: {}} var arr = []; var obj = data.object; if (obj !== undefined) { for (var key in obj) { obj[key].id = key; // aggiunge la chiave dell'oggetto come proprietà if (data.add) obj[key] = Object.assign(obj[key], data.add); arr.push(obj[key]); } } return arr; }; /* this.itemsFound = function(items, field, value) { return $.grep(items, function(e){ return e.name == value; }); } */ /* this.itemFound = function(items, field, value) { var itemFound = false; for (var i=0; i 0); } else { return ($(data.class).length > 0); } } */ this.equal = function (obj1, obj2) { if (obj1 && obj2) { return (JSON.stringify(obj1).replace('"', '') == JSON.stringify(obj2).replace('"', '')); } else { return (obj1 == obj2); } }; /* this.arraysEquals = function(arr1,arr2) { return ($(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0); } */ var escapeRegExp = function (str) { return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1"); }; 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) { // && replace //if (typeof str !== 'string') self.log(str); result = String(str).replace(new RegExp(escapeRegExp(find), 'g'), replace); //if (typeof str == 'string') return result; else return JSON.parse(result); if (typeof str == 'object' && result) return JSON.parse(result); else return result; } else { /* self.log('str:'+str); self.log('find:'+find); self.log('replace:'+replace); */ return str; } } } else { return str; } }; this.capitalize = function (str) { return str.replace(/\b\w/g, l => l.toUpperCase()); }; /*--------------------- URL UTILS ---------------------*/ this.getPageName = function (url) { var index = url.lastIndexOf("/") + 1; var filenameWithExtension = url.substr(index); var filename = filenameWithExtension.split(".")[0]; // <-- added this line return filename; // <-- added this line }; this.goToMainUrl = function () { window.location = self.mainUrl; }; 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, " ")); }; var paramsToObject = function (params) { params = params.split('#')[0]; return JSON.parse('{"' + params.replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}'); }; var objectToParams = function (object) { var str = ''; for (var key in object) str += '&' + key + '=' + object[key]; if (str) str = str.substr(1); return encodeURI(str); }; 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; }; 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; }; 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 }; /* var encodeNum = function(num) { // 0..1296 es:customer var hex = c.toString(36); return c.toString(36); } var decodeNum = function(str) { return str.parseInt(36); // .length == 1 ? "0" + hex : hex } */ 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); } }; 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; }; 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)]; }; 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); }; this.degToRGB = function (deg) { return packRGB(HSLToRGB([deg / 360, 1, 0.5])); }; this.stripHtml = function (html) { var tmp = document.createElement("DIV"); tmp.innerHTML = html; return tmp.textContent || tmp.innerText || ""; }; //-------------------------- // TASK MANAGER //-------------------------- 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); } }; var varlog = function (str) { self.log(str); self.log(window[str]); // 'var' -> var }; this.logJson = function (jsonPar) { self.log(JSON.stringify(jsonPar)); }; this.getTimestamp = function () { // we need also an API to get the time // like .getTime()? return Math.floor(Date.now()); }; this.cloneObject = function (obj) { var newObj = JSON.stringify(obj); return self.parse(newObj); }; /*------------------------ TEXT ------------------------*/ /* var caseUp = function (string) { if (!string) string = ''; return string.toUpperCase(); } var caseDown = function (string) { if (!string) string = ''; return string.toLowerCase(); } var capitalize = function(string) { if (!string) string = ''; return self.capitalize(string); } var text = function (key, caseFunction) { var t = self.json.text[key] || ''; if (caseFunction) return caseFunction(t); else return t; } */ 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; }; 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; } }; 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));} */ }; 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]; }; /* 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'); } } */ 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 = {}; this.timer = function (params, args) { // can go in "browser.json / functions (JS Browser BOM) // https://www.w3schools.com/js/js_window.asp 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); } } }; this.setInterval = function (params, args) { // could include the param "fromNow": true to execute the function /* self.log('setInterval'); self.log(params); */ if (params.name && params.duration) { if (self.intervals[params.name]) clearInterval(self.intervals[params.name]); //self.do(params.do); self.do(params.do); self.intervals[params.name] = setInterval(function () { //self.do(params.do); self.do(params.do); return params.name; }, Number(params.duration)); // self.timeToMs } else self.log('"setInterval" function requires "name" and "duration" parameters'); }; this.clearInterval = function (params, args) { /* self.log('params'); self.log(params); self.log('self.intervals[params.name]'); self.log(self.intervals[params.name]); */ if (self.intervals[params.name]) { clearInterval(self.intervals[params.name]); delete self.intervals[params.name]; } // else // self.log('"clearInterval" name not found: ' + params.name); }; this.timeouts = {}; this.setTimeout = function (params, args) { // could include the param "fromNow": true to execute the function /* self.log('setTimeout'); self.log(params); */ if (params.name && params.duration) { if (self.timeouts[params.name]) clearInterval(self.timeouts[params.name]); //self.do(params.do); //self.do(params.do); self.timeouts[params.name] = setTimeout(function () { //self.do(params.do); self.do(params.do); return params.name; }, Number(params.duration)); // self.timeToMs } else self.log('"setTimeout" function requires "name" and "duration" parameters'); }; this.clearTimeout = function (params, args) { /* self.log('params'); self.log(params); self.log('self.timeouts[params.name]'); self.log(self.timeouts[params.name]); */ if (self.timeouts[params.name]) { clearTimeout(self.timeouts[params.name]); delete self.timeouts[params.name]; } //else // self.log('"clearInterval" name not found: ' + params.name); }; this.on = function (params, selectorParams) { //let selector = params.selector || params.container; var container = (selectorParams) ? self.selector(selectorParams) : params.selector; // 1.0.9 instead of params.container /* self.log('on'); self.log(params); self.log('container'); self.log(container); */ //var selector = self.selector(self.extend({}, params, selectorParams)); //$(container).data('onData', {events: params, container: container}); var element; if (container) { element = self.query(container); // shoud be foreach elements... 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); } } /* else { self.log('"on" function with selector undefined'); self.log('params'); self.log(params); self.log('selectorParams'); self.log(selectorParams); } */ for (var eventId in params) { //var eventAction = params[eventId]; //$(selector).data('onData').action = eventAction; /* if (eventId == 'thunkable') { self.thunkable(params[eventId]); } else */ if (eventId == 'init') { //self.log(params.init); //self.do(params.init, undefined, selectorParams); 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); // potrebbe essere esplicitato sulla app //var action = self.cloneObject(params.app.on.hashchange); //self.replaceAll("{result}", window.location.hash); //self.do(self.onHashChange); self.do(self.onHashChange); self.uiUpdate(); }); } else if (eventId == 'scroll') { self.onScroll.push(params.scroll); window.addEventListener('scroll', function () { //self.do(self.onScroll); self.do(self.onScroll); }); } else if (eventId == 'resize') { self.onResize.push(params.resize); window.addEventListener('resize', function () { //self.do(self.onResize); self.do(self.onResize); }); } else if (eventId == 'in') { // like inViewport but only one time if (container) { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(function (entry) { /* self.log('entry'); self.log(entry); self.log('entry.target'); self.log(entry.target); */ /* self.log(entry); self.log(entry.intersectionRatio); self.log(entry.isIntersecting); self.log(entry.isVisible); */ // isIntersecting, isVisible //var element = self.query(entry.target); //self.log(entry.intersectionRatio); if (entry.intersectionRatio == 1) { // .isIntersecting? var el = entry.target; if (el.getAttribute('in') !== 'true') { el.setAttribute('in', 'true'); // change with dataStorage self.onEvent(entry.target, { type: 'in' }); } } }); }, { rootMargin: '0px', threshold: [0, 1] // if 0.5 is the half-height of the elmement }); //const element = self.query(container); observer.observe(self.query(container)); } } else if (eventId == 'inViewport') { if (container) { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(function (entry) { /* self.log('entry'); self.log(entry); self.log('entry.target'); self.log(entry.target); */ /* self.log(entry.intersectionRatio); self.log(entry.isIntersecting); self.log(entry.isVisible); */ // isIntersecting, isVisible //var element = self.query(entry.target); //self.log(entry.intersectionRatio); if (entry.intersectionRatio > 0) { self.onEvent(entry.target, { type: 'inViewport' }); } }); }, { rootMargin: '0px', threshold: [0, 1] // if 0.5 is the half-height of the elmement }); //const element = self.query(container); observer.observe(self.query(container)); } } else if (eventId == 'outViewport') { const observer = new IntersectionObserver((entries, observer) => { entries.forEach(function (entry) { /* self.log(entry); self.log(entry.isIntersecting); self.log(entry.isVisible); */ // isIntersecting, isVisible //var element = self.query(entry.target); //self.log(entry.intersectionRatio); if (entry.intersectionRatio == 0) { self.onEvent(entry.target, { type: 'outViewport' }); /* var el = entry.target; if (el.getAttribute('in') == 'true') { el.setAttribute('in', 'false'); self.onEvent(entry.target, {type: 'out'}); } */ } }); }, { rootMargin: '0px', threshold: [0, 1] // if 0.5 is the half-height of the elmement }); const element = self.query(container); observer.observe(element); } else if (eventId !== 'selector') { /* if (container == '.nav-link[data-value="docs"]') { alert(JSON.stringify(params)); //element = element[0]; $(element).hide(); } */ //element.removeEventListener(eventId); // $(container).off(eventId); if (element) { // TO DO: verify //if (element.getAttribute('listener') !== 'true') { // only one mouse event //self.log('addEventListener: ' + eventId); element.addEventListener(eventId, function (event) { //$(container).off(eventId).on(eventId, function (event) { /* self.log('event'); self.log(event); */ element.setAttribute('listener', 'true'); //event.preventDefault(); //event.stopPropagation(); self.onEvent(this, event); }); //} if (eventId == 'mousedown' || eventId == 'mouseup' || eventId == 'click') element.style.cursor = 'pointer'; } /* $(container).off(eventId).on(eventId, function (event) { //$(container).off(eventId).on(eventId, function (event) { self.log('event'); self.log(event); event.preventDefault(); event.stopPropagation(); self.onEvent(this, event); }); */ //$(container).css({cursor: 'pointer'}); } } }; /* this.addAction = function (params, selectorParams) { var container = (selectorParams) ? self.selector(selectorParams) : params.container; var selector = self.selector(self.extend({}, params, selectorParams)); $(selector).data('onData', params); //$(selector).data('onData', {action: params.action, params: params.args}); $(selector).off().on(this.touch, function (event) { event.stopPropagation(); self.onEvent(this, event); }); $(selector).css({cursor: 'pointer'}); } */ /* this.ace = function (params) { params.container = 'blockCode'; var editor = ace.edit("blockCode"); var langTools = ace.require('ace/ext/language_tools'); editor.setTheme("ace/theme/monokai"); // ambiance editor.getSession().setMode("ace/mode/json"); //editor.renderer.setOption('showLineNumbers', false); editor.container.style.background="rgba(255,255,255,0)"; var staticWordCompleter = { getCompletions: function(editor, session, pos, prefix, callback) { var wordList = ["app", "setup", "pages"]; callback(null, wordList.map(function(word) { return { caption: word, value: word, meta: "static" }; })); } } editor.completers = [staticWordCompleter]; // https://github.com/ajaxorg/ace/wiki/Configuring-Ace editor.setOptions({ fontSize: "11pt", selectionStyle: "text", highlightActiveLine: true, wrap: true, showLineNumbers: false, showGutter: false, fixedWidthGutter: false, readOnly: true, //enableBasicAutocompletion: true, //enableSnippets: true, //enableLiveAutocompletion: true, }); editor.setValue(var.code, -1); } */ /* this.edit = function (item) { //var.code = JSON.stringify(item, null, '\t'); self.do( { "alert": { "background": "rgba(255,255,255,0.9)", "width": "93%", "showCancelButton": true, "cancelButtonText": 'Cancel', "confirmButtonText": 'Save', "html": '
    ' } }); //self.code(JSON.stringify(item, null, '\t'),); self.code(item, {container: '#blockCode'}); //setTimeout(function () { //alert(var.blockCode); // https://codepen.io/jjsjjja/pen/VoGYRB //}, 100); } */ this.money = function (value) { /* if (value && value.indexOf(',') == -1 && value.indexOf('.') == -1) { value = value + '.00'; } */ 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; }; this.offcanvas = function (params) { self.log('offcanvas'); self.log('params'); self.log(params); // https://getbootstrap.com/docs/5.0/components/offcanvas/ // to add: toggle, getInstance, getOrCreateInstance 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); // do: show (default) / hide (see boostrap Offcanvas docs) if (element) { if (params.do == 'hide') { self.css({ removeClass: 'show' }, params); //new bootstrap.Offcanvas(element).hide(); // doesn't work } else { new bootstrap.Offcanvas(element).show(); } } else { self.log('"offcanvas" method can\'t find the selected element'); } }; /** * Converts a DOM element to its CSS selector string representation * @param {HTMLElement} element - The DOM element to convert * @returns {string} The CSS selector string that uniquely identifies the element */ this.elementToSelector = function (element) { // 1. Use ID if available if (element.id) { return '#' + element.id; } // 2. Use data-value if unique if (element.dataset?.value) { const sameDataValue = document.querySelectorAll(`[data-value="${element.dataset.value}"]`); if (sameDataValue.length === 1) { return `[data-value="${element.dataset.value}"]`; } } // 3. Use class if unique 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; } } } } // 4. Use tag if unique const tagName = element.tagName.toLowerCase(); const sameTag = document.querySelectorAll(tagName); if (sameTag.length === 1) { return tagName; } // 5. Fallback to tag + nth-child path 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(' > '); }; this.onEvent = function (element, event) { //self.log('element'); //self.log(element); /* self.log('event'); self.log(event); */ /* if (event) { event.preventDefault(); // verify event.stopPropagation(); } */ /* var item = {}; if (self.dataStorage.has(element, 'onData')) item = self.dataStorage.get(element, 'onData'); */ var item = self.dataStorage.get(element, 'onData'); var code = self.dataStorage.get(element, 'code') || ''; //var item = $(element).data('onData'); //var code = $(element).data('code'); //var value = String($(element).data('value')); //var selector = $(element).data('selector'); //var value = String(self.dataStorage.get(element, 'value')); var value = element.getAttribute('data-value'); //var selector = element.getAttribute('data-selector'); var selector = self.elementToSelector(element); // 1.0.12 /* self.log('value'); self.log(value); self.log('args'); self.log(args); */ var eventType = (event.type && item.on) ? item.on[event.type] : undefined; /* self.log('onEvent'); self.log('item'); self.log(item); self.log('selector'); self.log(selector); self.log('event.type'); self.log(event.type); */ /* if (event) { args = { value: value, event: eventType } } */ /* self.log('event.type'); self.log(event.type); self.log('event'); self.log(event); */ var action, specialKey; if (item.on) { if (event.button == '2' && event.type == 'mousedown') { // right click / long touch if (item.on['contextmenu']) action = item.on['contextmenu']; } else if (event.type && item.on[event.type]) { var eventAction = item.on[event.type]; //const specialKeys = ['shiftKey', 'altKey', 'cmdKey']; 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) { //console.dir(action); //action = self.replaceProperty(action, '{on:target}', targetId); if (event.target) { //self.log(event); var actionString; var targetId = event.target.id; var targetClass = event.target.className; var targetValue = event.target.dataset.value; var targetSelector = event.target.dataset.selector; // deprecated /* self.log('event'); self.log(event); */ //if (targetValue) alert(targetValue); targetSelector = self.replaceAll(targetSelector, '"', '\''); // TO DO: if JSON5? action = self.stringify(action); if (typeof targetId !== 'string') targetId = ''; if (typeof targetClass !== 'string') targetClass = ''; /* actionString = self.replaceAll(action, '{event.target.id}', targetId); actionString = self.replaceAll(actionString, '{event.altKey}', event.altKey); actionString = self.replaceAll(actionString, '{event.target.className}', targetClass); actionString = self.replaceAll(actionString, '{event.target.data-value}', targetValue); // obsolete actionString = self.replaceAll(actionString, '{event.target.dataset.value}', targetValue); actionString = self.replaceAll(actionString, '{event.target.dataset.selector}', targetSelector); */ 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); // obsolete actionString = self.replaceAll(actionString, '{on:target.dataset.value}', targetValue); actionString = self.replaceAll(actionString, '{on:target.dataset.selector}', targetSelector); // deprecated actionString = self.replaceAll(actionString, '{on:which}', event.which); actionString = self.replaceAll(actionString, '{on:clientY}', event.clientY); actionString = self.replaceAll(actionString, '{on:clientX}', event.clientX); // custom actionString = self.replaceAll(actionString, '{on:value}', targetValue); actionString = self.replaceAll(actionString, '{on:dragging}', (event.which > 0)); //actionString = self.replaceProperty(actionString, 'on', event); if (this.isJson(actionString)) action = self.parse(actionString); else action = actionString; } // TODO: let decide to the user the parameter to pass var args = item.args; // || item.params || item.value || value; //args.event = event; //if (args) // action = self.replaceResult(action, args); let specialKeyLog = (specialKey) ? ' + ' + specialKey : ''; //self.log('event ' + event.type + specialKeyLog); //self.log('action'); //self.log(action); /* self.log('args'); self.log(args); self.log('{container: selector}'); self.log({container: selector}); */ //self.do(action, args, {selector: selector}); // TO DO: only if mouse over or self.do(action, { selector: selector }, args); } // (action) }; this.pluginsFunctionAvailable = []; // should use pluginsLoaded self.pluginsLoader = function (packs, callback, params) { /* self.log('pluginsLoader'); self.log('packs'); self.log(packs); self.log('callback'); self.log(callback); self.log('params'); self.log(params); */ //self.pluginsFunctionAvailable.push(name); // posizione giusta var filesToLoad = []; for (pack of packs) { /* self.log('pack'); self.log(pack); */ 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]; // TO DO: obsolete, remove version = pack.version; } /* if (params) { if (!Array.isArray(params[0])) params[0] = [params[0]]; if (!self.pluginsCallbacks[pack.name]) self.pluginsCallbacks[pack.name] = []; self.pluginsCallbacks[pack.name].concat(params[0]); } */ self.pluginsLoaded[pack.name] = version; // should contain the queue of actions to do after the plugin loads // TO DO: move in Promise.all(promises).then(function() { // it needs to feed a queue of actions to do after the plugin loads if (!Array.isArray(pluginsFiles)) // multi-file plugin pluginsFiles = [pluginsFiles]; /* self.log('pluginsFiles'); self.log(pluginsFiles); */ for (item of pluginsFiles) { var url = self.replaceAll(item.url, '{version}', version); if (!self.findUrl(filesToLoad, url)) // not included yet filesToLoad.push({ name: item.name, url: url, type: item.type }); } } } //self.log(filesToLoad); 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 })); //promises.push(loadPlugin(url)); }); Promise.all(promises).then(function (files) { // all filesToLoad are loaded (all the Promise in loadPlugin are solved) /* self.log('all plugin files are loaded'); self.log(files); self.log(params); */ callback(...params); // change with ... //callback(params[0], params[1], params[2]); // change with ... }).catch(function (script) { self.log('failed to load error'); self.log(item); self.log(script); }); } }; this.pluginsRequired = function (params) { /* self.log('pluginsRequired'); self.log(params); */ // analize function object or array of objects if (self.json.resources) { const pluginsFunctions = self.json.resources.pluginsFunctions; var pluginsRequired = []; if (typeof params == 'string') { /* self.log('params'); self.log(params); */ 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]; /* self.log('objArray'); self.log(objArray); */ for (var obj of objArray) { /* self.log('obj'); self.log(obj); */ for (var key in obj) { var mainFunction = (key.indexOf('.') >= 0) ? key.substr(0, key.indexOf('.')) : key; //self.log('mainFunction'); //self.log(mainFunction); if (pluginsFunctions[mainFunction]) { if (!self.pluginsLoaded[pluginsFunctions[mainFunction].name]) pluginsRequired.push(pluginsFunctions[mainFunction]); } /* else if (key == 'var') { const functionName = self.functionName(obj.var.value); if (functionName) { if (!self.pluginsLoaded[pluginsFunctions[functionName].name]) pluginsRequired.push(pluginsFunctions[functionName]); } } */ } } } return pluginsRequired; } else { return []; } }; 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; } }; /* this.runParts = function (actionObj, container, argumentsPar, handleOtherActions) { console.log('runParts'); console.log(actionObj); if (Array.isArray(actionObj)) { for (var action in actionObj) self.runParts(action); } else { var otherMethods = false; var otherActions = {}; for (var partKey in actionObj) { if (partKey.startsWith('var ') || partKey.startsWith('data ') || partKey.startsWith('set ')) self.setData({path: partKey, value: actionObj[partKey]}); else { var methodOrPart = false; var method = self.element({path: partKey, root: self.methods}); if (method) { // search in jsonic.methods methodOrPart = true; if (typeof method == 'function') { //self.docElement(actionObj[partKey]); self.log('method: ' + partKey); method(actionObj[partKey], container, argumentsPar); } } else if (self.json.parts) { // search in self.json.parts var part = self.element({path: 'parts.'+self.replaceAll(partKey,':','.')}); if (part) { part = self.replaceProperty(part, 'arg', actionObj[partKey]); if (actionObj[partKey].setup) part = self.replaceProperty(part, 'setup', actionObj[partKey].setup); console.log('part'); console.log(part); self.run(part, container); methodOrPart = true; // if (!actionFound) { will go in the else (!part) } } if (!methodOrPart) otherActions[partKey] = actionObj[partKey]; else otherMethods = true; } } //if (handleOtherActions) handleOtherActions(otherActions, container, argumentsPar); return otherMethods; } } */ /* this.jsonicMethods = function (actions, container, argumentsPar) { // 'icons' should be removed from the json files var withContainer; var functionFound = false; for (var actionKey in actions) { //if (nodes.functions.indexOf(actionKey) >= 0) { switch (actionKey) { case 'for': case 'editor': case 'ace': case 'code': case 'qrcode': case 'lottie': case 'animate': case 'html': case 'hide': case 'show': case 'toggle': case 'in': case 'out': case 'if': case 'ajax': case 'attr': case 'run': case 'delay': case 'css': withContainer = true; break; default: withContainer = false; } var functionObj = actions[actionKey]; if (functionObj) { functionFound = true; if ((functionObj.if == undefined) || self.if(functionObj.if, container, argumentsPar)) { return self.doFunction({ name: nodes.functions[actionKey], function: functionObj, args: argumentsPar, selector: container, withContainer: withContainer }); } else { if (functionObj.if !== undefined) { self.log(self.js(functionObj.if, argumentsPar)); } } } else if (nodes.params.indexOf(actionKey) < 0) return self.method(actions[actionKey], argumentsPar); } } */ /* this.do = function (actionPar, argumentsPar, selectorParams) { // ex this.action if (actionPar !== undefined && actionPar !== null) { // !== undefined // check plugins required let pluginsRequired = self.pluginsRequired(actionPar); if (pluginsRequired.length > 0) { let params = [actionPar, argumentsPar, selectorParams]; self.pluginsLoader(pluginsRequired, self.do, params); } else { if (Array.isArray(actionPar)) { if (actionPar.length > 0) { var actionArray = []; for (var index in actionPar) if (typeof actionPar[index] == 'object') actionArray[index] = self.cloneObject(actionPar[index]); else actionArray[index] = actionPar[index]; //actionArray = actionArray.concat(actionPar); //actionArray = self.cloneObject(actionPar); var actionFunction = actionArray.shift(); self.do(actionFunction, argumentsPar, selectorParams); if (actionArray.length > 0) self.do(actionArray, argumentsPar, selectorParams); } } else { if (typeof actionPar == 'function') { return actionPar(argumentsPar); } else if (typeof actionPar == 'string') { var actionPart = self.element({path: 'parts.' + actionPar}); // it includes replaceProperties self.log('actionPar stringa'); self.log(actionPar); if (actionPart) return self.do(actionPart, argumentsPar); //else if (json.actions[actionPar]) // obsolete // return self.do(json.actions[actionPar], argumentsPar); else return actionPar; //return self.js(actionPar); // TO DO: finisce qui anche una stringa di un tag p ("p": "string") } else if (typeof actionPar == "object") { var actionObj = actionPar; var container = actionObj.selector || actionObj.container || selectorParams; // events if (actionObj.on) {self.on(actionObj.on, container);} if (self.notEmptyObject(actionObj)) { var actionFound = self.runParts(actionObj, container, argumentsPar, self.jsonicMethods); if (!actionFound) { var functionFound = false; for (var index in nodes.functions) { //if (nodes.params.indexOf(actionKey) < 0) //var action = Object.keys(actionObj)[0]; var withContainer = (nodes.functionsWithContainer.indexOf(nodes.functions[index]) >=0 ); var functionObj = actionObj[nodes.functions[index]]; if (functionObj) { functionFound = true; if ((functionObj.if == undefined) || self.if(functionObj.if, container, argumentsPar)) { //if ((functionObj.if == undefined) || Boolean(self.js(functionObj.if, argumentsPar))) { return self.doFunction({ name: nodes.functions[index], function: functionObj, args: argumentsPar, selector: selectorParams, withContainer: withContainer }); } else { if (functionObj.if !== undefined) { self.log(self.js(functionObj.if, argumentsPar)); } } } } if (!functionFound) { self.log('actionPar'); self.log(actionPar); self.log('!functionFound'); self.log(actionObj); return self.method(actionObj, argumentsPar); } } } } else { //self.log('Function not found'); //self.log(actionPar); //self.log(argumentsPar); return actionPar; // functions from this.do //actionPar(argumentsPar); } } } } else { // TO DO: check //self.log('function with actionPar undefined'); } } */ /* this.jsonicMethod2 = function (actionObj, selectorParams, argumentsPar) { var functionFound = false; for (var action in actionObj) { var functionObj = actionObj[action]; if (functionObj) { var withContainer = (nodes.functionsWithContainer.indexOf(action) >=0 ); functionFound = true; if ((functionObj.if == undefined) || Boolean(self.js(functionObj.if, argumentsPar))) { return self.doFunction({ name: action, function: functionObj, args: argumentsPar, selector: selectorParams, withContainer: withContainer }); } } if (!functionFound) { self.log('!functionFound'); self.log('actionObj'); self.log(actionObj); return self.method(actionObj, argumentsPar); } } } */ this.for = function (params, selectorParams, args) { /* self.log('for'); self.log(params); */ let container = self.selector(params.selector || params.container) || self.selector(selectorParams); // TO DO: doesn't go as an automous function (needs to be inside a div) /* self.log('for'); self.log('container'); self.log(container); */ //if (params.html) { // new version let itemsName = params.id || params.name; //self.log('itemsArray'); //self.log(itemsArray); /* if (params.reverse) { var itemsReversed = {}; for (var key in Object(itemsArray).keys().reverse()) { itemsReversed[key] = itemsArray[key]; } itemsArray = itemsReversed; } */ if (params.of) { //var itemsArray = self.cloneObject(params.of); // value is the previous array id //if (typeof itemsArray == 'string') //itemsArray = self.compile(itemsArray, args); // compile includes functions and create bugs //self.log('params.of'); //self.log(params.of); var itemsArray = self.replaceProperties(params.of, args); /* self.log('itemsArray'); self.log(itemsArray); */ /* if (typeof itemsArray == 'string') { itemsArray = self.js(itemsArray); // TO DO: check } */ if (itemsArray) { /* if (typeof itemsArray == 'string') { if (itemsArray.startsWith('js:')) itemsArray = self.js(itemsArray.substr(3)); //else itemsArray = self.replaceProperties(itemsArray, args); } */ /* else { itemsArray = self.actionResult(itemsArray, args); itemsArray = self.replaceProperties(itemsArray, args); } */ /* self.log('itemsArray replaced'); self.log(itemsArray); */ /* self.log('for'); */ /* self.log(itemsName); */ /* self.log(itemsArray); */ if (params.html) { // 1.0.6 html in for is deprecated if (!params.do) params.do = []; else if (!Array.isArray(params.do)) params.do = [params.do]; params.do.push({ html: params.html }); } //delete params; // needed to avoid infinite loop if (typeof itemsArray == 'object') { let indexNum = 0; for (var index in itemsArray) { var item = itemsArray[index]; if (typeof item == 'object') { item.key = index; // obsolete item.index = index; // obsolete } if (typeof item.output == 'object') { // TO DO: obsolete /* self.log('item.for.output'); self.log(item.for.output); */ 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.compile(output, args); output = self.replaceProperties(output, args); } item = self.replaceItems(item, output, key); // replace //item = self.replaceProperty(item, key, output); } } if (params.do.length > 0) { //alert(JSON.stringify(params.do)); //self.do(self.replaceProperty(params.do, itemsName, item), undefined, {selector: container}); //let objWithIndex = self.replaceStringInObject(params.do, '{' + params.index + '}', index); let objWithIndex = params.do; if (params.var) { // TO DO: obsolete (remove when used) self.element({ path: params.var, value: item, root: self.json.var }); objWithIndex = self.replacePropertyWithPrefix(objWithIndex, 'index:' + params.var, index); //objWithIndex = self.replaceStringInObject(objWithIndex, '{index:'+params.var+'}', index); } if (itemsName) { //objWithIndex = self.replaceStringInObject(objWithIndex, '{index:'+itemsName+'}', index); objWithIndex = self.replacePropertyWithPrefix(objWithIndex, 'index:' + itemsName, index); objWithIndex = self.replacePropertyWithPrefix(objWithIndex, itemsName, item); //objWithIndex = self.replaceProperty(objWithIndex, 'value:'+itemsName, item); //objWithIndex = self.replaceProperty(objWithIndex, itemsName, item); // obsolete } 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 }); } } /* if (params.html) { // should be inside a do // commented from 1.0.6 let indexName = params.index || 'index'; let objWithIndex = self.replaceStringInObject(params.html, '{'+indexName+':'+itemsName+'}', index); objWithIndex = self.replaceProperty(objWithIndex, itemsName, item); self.do(objWithIndex, {selector: container}); } */ indexNum += 1; } } } } else if (params.from !== undefined && params.to !== undefined) { /* var step = Number(params.step) || 1; var from = Number(params.from) || 0; var to = Number(params.to); */ 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)); /* var step = Number(self.replaceProperties(params.step)) || 1; var from = Number(self.replaceProperties(params.from)) || 0; var to = Number(self.replaceProperties(params.to)); */ /* self.log('from'); self.log(from); self.log('to'); self.log(to); self.log('step'); self.log(step); */ 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 }); // TO DO: find "if (params.html) { // 1.0.6" and modify also the following code var item = self.replaceItems(params, String(index), itemsName); // obsolete: replaced with {index:itemsName} //var item = self.replaceProperty(params, itemsName, String(index)); /* self.log('itemsName'); self.log(itemsName); self.log('index'); self.log(index); self.log('item'); self.log(item); */ if (item.output && typeof item.output == 'object') { //} !== undefined) { /* self.log('item.for.output'); self.log(item.for.output); */ 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.compile(output, args); output = self.replaceProperties(output, args); } item = self.replaceItems(item, output, key); //item = self.replaceProperty(item, key, output); } } // item = self.replaceItems(item, itemValue, itemsName); old version //delete item.for; // needed to avoid infinite loop if (item.do) { params.do = self.replacePropertyWithPrefix(item.do, 'index:' + itemsName, index); //params.do = self.replaceStringInObject(item.do, '{index:'+itemsName+'}', index); self.do(item.do, selectorParams, args); // return? //self.do(item.do, args, selectorParams); // return? } if (item.html) { //params.html = self.replaceStringInObject(item.html, '{index:'+itemsName+'}', index); 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'); // link to see the documentation self.log(params); } //} // } }; this.htmlTag = function (params, selectorParams, tagParam, mainParam) { /* self.log('htmlTag'); self.log(tagParam); */ if (Array.isArray(params)) { for (var index in params) self.htmlTag(params[index], selectorParams, tagParam, mainParam); } else { //---------------------------------- // attributes of the tag in the key // example: "div id=btn btn" // (classes are without identifier) //---------------------------------- 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 = {}; // attributes in key: attribute=value let tagArr = tagClass.split(' '); var attrClass = ''; for (let tagProp of tagArr) { let tagAttr = new RegExp("([_a-zA-Z]+[_a-zA-Z0-9-]*)=(.+)"); // [_a-zA-Z0-9-/] if (tagAttr.test(tagProp)) { //console.log('attribute found '+tagProp); let tagPropArr = tagProp.split('='); params.attr[tagPropArr[0]] = tagPropArr[1]; } else { attrClass += ' ' + tagProp; } } // classes if (params.attr.class) params.attr.class = params.attr.class + attrClass; else { params.attr.class = attrClass; } //alert(tagParam + '/'+ tagClass+ '#'); } } let htmlTagObj = self.createTagParams(params, tagParam, mainParam); self.do(htmlTagObj, selectorParams); if (params.database) self.addFirebaseTag(self.extend({}, params, selectorParams)); } }; 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'; // TO DO: -> html (to test with actual apps) break; } } var paramsObj = {}; if (typeof params == 'string') paramsObj[mainParam] = params; else paramsObj = params; paramsObj.tag = tagParam; return paramsObj; }; this.onResize = []; this.onHashChange = []; this.onScroll = []; //let swup; this.notEmptyObject = function (obj) { return (obj // null and undefined check && Object.keys(obj).length > 0); // && Object.getPrototypeOf(obj) === Object.prototype // https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object }; this.run = function (params, selectorParams, args) { /* self.log('run'); self.log(params); */ 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; /* self.log('codeToRun'); self.log(codeToRun); */ 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]; } /* self.log('codeToRun.on'); self.log(codeToRun.on); self.log('selector'); self.log(selector); */ // actions //if (codeToRun.container) {self.empty(codeToRun.container);} // reset // .in SIGNIFICA CONTENITORE (select) if (codeToRun.on) { self.on(codeToRun.on, selector); } if (codeToRun.do) { self.do(codeToRun.do, selector, args); } if (self.notEmptyObject(actions)) { /* self.log('notEmptyObject actions'); self.log(actions); self.log('selector'); self.log(selector); */ return self.do(actions, selector, args); //return self.do(actions, args, codeToRun.in); } } } //self.extendJsonFromElement(codeToRun); // style, actions, texts, data, var. no setup, on, do, blocks, container }; /* this.execute = function (params, selectorParams, args) { // obsolete // should create a new jsonicApp instance and assign it to jsonic[id] // jsonicApp should load the plugins required and not are already loaded // jsonicApp should import the json not already imported // jsonicApp should load the icons not already loaded // jsonicApp should init the database if not already initialized // otherwise should copy the db object from window.jsonic? // to have app relative var and data these should be called as var:clock.... / var:calendar.... // or each app should have an ID (without id the ID is "app") // to have exclusive setup, var, data/items, pages and to reset var on the second execution // for example: window.jsonic['container'] = new jsonicObject(options); self.log('execute'); if (params) { if (params.do == 'init') { self.log('init'); window.removeEventListener('hashchange'); window.removeEventListener('resize'); window.removeEventListener('beforeinstallprompt'); // 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; }); self.json.setup.page.hash = window.location.hash.substr(1); // we consider json.setup.modules instead of self.modules // to be sure to follow the right order of execution var modules = []; // we need it to keep the order of the modules given in the setup for (key in json.setup.modules) { var mod = self.replaceProperties(json.setup.modules[key]); modules = modules.concat(self.cloneObject(mod)); } //modules.push({name: 'ide', url: 'https://jsonic.io/app/modules/ide.json'}); // TO DO if admin // or can execute global before all the rest // modules can contain {libs and apps} // ide module can be loaded only if required for (var mod of modules) { //self.log(mod.name); var params = self.modules[mod.name]; //self.log(params); if (params.html) { var container = selectorParams || 'body'; //if (params.app.html) { //var documentTitle = self.json.setup.title; //if (documentTitle) // document.title = documentTitle; //if (document.querySelector('meta[name="description"]')) // document.querySelector('meta[name="description"]').setAttribute("content", documentDescription); self.html(params.html, {container: container}); // window events //} } if (params.on) { // -> this.on // hashchange if (params.on.hashchange) { self.onHashChange.push(params.on.hashchange); window.addEventListener('hashchange', function() { self.json.setup.page.hash = window.location.hash.substr(1); // potrebbe essere esplicitato sulla app //var action = self.cloneObject(params.app.on.hashchange); //self.replaceAll("{result}", window.location.hash); self.do(self.onHashChange); self.uiUpdate(); }); } // resize window.addEventListener('resize', self.resizeEvent); if (params.on.resize) { self.onResize.push(params.on.resize); window.addEventListener('resize', function () { self.do(self.onResize); }); } // receiveMessage if (params.on.thunkable && params.on.thunkable.receiveMessage) window.receiveMessage(function (message) { //document.querySelector('#message').value = message; jsonic.functions(params.on.thunkable.receiveMessage, message, undefined); }); self.on(params.on, {container: container}); // init included } //else //self.log('The node "app" requires "container" and "html" properties'); } } else { //if (params.setup) args = self.extend(args, params.setup); // or params.args? if (params.blocks) self.extendJson(json, {blocks: params.blocks}); //if (params.library) self.extendJson(json, {library: params.library}); // obsolete if (params.media) self.extendJson(json, {media: params.media}); // obsolete if (params.functions) self.extendJson(json, {functions: params.functions}); // obsolete if (params.actions) self.extendJson(json, {actions: params.actions}); if (params.css) self.extendJson(json, {css: params.css}); //if (params.styles) self.extendJson(json, {styles: params.styles}); //if (params.iconset) self.extendJson(json, {iconset: params.iconset}); if (params.data) self.extendJson(json, {data: params.data}); if (params.items) self.extendJson(json, {items: params.items}); if (params.var) self.extendJson(json, {var: params.var}); if (params.html) { var container = selectorParams || 'body'; // is an object if (typeof container == 'string') container = {container: container}; //if (self.inputValue({id: 'module'}) == 'base') { // icons will be obsolete //} else { //var setup = extendParams.setup || params.setup; //if (container || html.container) { //if (params.app.html) { var code = self.cloneObject(params.html); //self.log('code'); //self.log(code); //self.log(JSON.stringify(code)); self.html(code, container); //} //} else { // self.log('execute method requires container parameter'); //} if (params.on && params.on.init) { self.do(params.on.init, undefined, container); } // args can be params.setup //} } else if (params.module) { var moduleId = self.replaceProperties(params.module); return self.do(self.modules[moduleId]); } } } } */ /* this.createApp = function (data) { self.log('createApp'); //self.log(self.modules); 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; }); self.json.setup.page.hash = window.location.hash.substr(1); for (var file in self.modules) { var params = self.modules[file]; //if (params.on) self.extendJson(json, {media: params.media}); // if (params.icons) self.extendJson(json, {icons: params.icons}); //if (params.functions) self.extendJson(json, {functions: params.functions}); //if (params.styles) self.extendJson(json, {styles: params.styles}); //if (params.items) self.extendJson(json, {items: params.items}); //if (params.var) self.extendJson(json, {var: params.var}); //if (params.library) self.extendJson(json, {library: params.library}); if (params.app && params.app.container) { //var documentTitle = self.json.setup.title; //if (documentTitle) // document.title = documentTitle; //if (document.querySelector('meta[name="description"]')) // document.querySelector('meta[name="description"]').setAttribute("content", documentDescription); //alert(document.querySelector(params.app.container).isConnected); self.html(params.app.html, {container: params.app.container}); // window events if (params.app.on) { // -> this.on // hashchange if (params.app.on.hashchange) { self.onHashChange.push(params.app.on.hashchange); window.addEventListener('hashchange', function() { self.json.setup.page.hash = window.location.hash.substr(1); // potrebbe essere esplicitato sulla app //var action = self.cloneObject(params.app.on.hashchange); //self.replaceAll("{result}", window.location.hash); self.do(self.onHashChange); self.uiUpdate(); }); } // resize window.addEventListener('resize', self.resizeEvent); if (params.app.on.resize) { self.onResize.push(params.app.on.resize); window.addEventListener('resize', function () { self.do(self.onResize); }); } // receiveMessage if (params.app.on.thunkable && params.app.on.thunkable.receiveMessage) window.receiveMessage(function (message) { //document.querySelector('#message').value = message; jsonic.functions(params.app.on.thunkable.receiveMessage, message, undefined); }); // init self.log('params.app.on'); self.log(params.app.on); self.log('params.app.container'); self.log(params.app.container); self.on(params.app.on, {container: params.app.container}); } } //else //self.log('The node "app" requires the "container" property'); } if (self.pluginsLoaded['swup'] && self.json.setup.swup) { let swup = new Swup(self.json.setup.swup); } self.do(data); } */ /* this.menuToggle = function () { self.log('menuToggle'); //$('.offcanvas-collapse').toggleClass('open'); $('#header').toggleClass('headerMenuOpen'); var.menuOpen = (!var.menuOpen); self.log(var.menuOpen); } this.menuOpen = function () { self.log('menuOpen'); $('#menu').addClass('menuOpen'); var.menuOpen = true; self.log(var.menuOpen); } this.menuClose = function () { self.log('menuClose'); $('#menu').removeClass('menuOpen'); var.menuOpen = false; self.log(var.menuOpen); } */ /* this.createMenu = function (data) { self.log('createMenu'); // self.userRole var menuId = (typeof data.id == 'function') ? data.id() : data.id; var container = data.container || '#header > ul'; $(container).empty(); for (var index in self.json.menu[menuId]) { var selector = container + ' > li:eq(' + index + ')'; // > span'; var item = self.json.menu[menuId][index]; // action //if (item.page && !item.action) item.action = {page: item.page}; if (!var.functions[container]) var.functions[container] = {}; var.functions[container][index] = item; $(container).append('
  • '); item.color = item.color || 'inherit'; item.background = item.background || 'transparent'; item.border = item.border || 'transparent'; self.tab(item, {container: selector}); } self.do(data); } */ /* this.changeMenu = function (menuId) { } */ /* this.form = function (params, selectorParams) { // replaceProperties può essere passato all'inizio di ogni costruttore //params.container = params.container || self.selector(selectorParams); //var selector = self.selector(params); var container = params.container || self.selector(selectorParams); //var elementContainer = self.query(container); //var selector = self.selector(self.extend({}, params, selectorParams)); //var element = self.query(selector); //params.tag = 'form'; //if (params.id === undefined) {params.id = '';} //if (params.value === undefined) {params.value = ''}; //if (params.class === undefined) {params.class = ''}; //$(container).append('<'+params.tag+' id="'+params.id+'" class="'+params.class+'" data-value="'+params.value+'" data-selector="'+selector+'">'); for (var itemKey in params.items) { var item = params.items[itemKey]; self.html({ "form": { "attr": { "id": params.id, "class": params.class, "data-value": params.data-value || params.value }, "div": [ { "attr": { "class": "form-group", "data-value": itemKey }, "html": [ { "label": { "attr": { "for": itemKey, "text": item.title } } }, { "input": { "attr": { "id": itemKey, "class": "form-control", "data-value": "formInput" + itemKey, "value": item.inputValue, "type": item.type, "text": item.title, "aria-describedby": "note"+itemKey, "placeholder": "", "disabled": disabled } } }, { "small": { "attr": { "class": "form-text text-muted", "data-value": "formNote"+itemKey, "text": item.note } } }, ] } ] } }, { container: container }); } } */ /* this.addList = function (params, selectorParams) { var container = (selectorParams) ? self.selector(selectorParams) : params.container; var selector = self.selector(self.extend({}, params, selectorParams)); if (params.id === undefined) {params.id = '';} if (params.value === undefined) {params.value = ''}; if (params.class === undefined) {params.class = ''}; $(container).append('
      '); self.list(params, {container: container}); } */ /* this.addBlock = function (params, selectorParams) { if (params.icons) self.icons(params.icons, selectorParams); if (params.tab) self.tab(params.tab, selectorParams); if (params.html) self.html(params.html, selectorParams); if (params.div) self.div(params.div, selectorParams); if (params.ul) self.ul(params.ul, selectorParams); if (params.li) self.li(params.li, selectorParams); if (params.span) self.span(params.span, selectorParams); if (params.img) self.img(params.img, selectorParams); if (params.form) self.form(params.form, selectorParams); if (params.list) self.addList(params.list, selectorParams); //if (params.img) alert(JSON.stringify(params.img.src)); } */ /* 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 blocksObj = self.get('self.json.library.'+params); if (blocksObj) self.blocks(blocksObj.blocks, selectorParams); } else { if (params.library) { self.library(params.library, selectorParams, args); // {container: container} } else { self.addTag(params, selectorParams, args); // {container: container} } } } } */ this.inputValue = function (params) { var selector = self.selector(params.selector || params.container); var element = document.querySelector(selector); // self.query(p2); return element.value; }; /* this.layout = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.layout(params[index], selectorParams, args); } else { if (typeof params == 'string') { var libraryObj = self.get('self.json.layouts.'+params); // todo: get? //var libraryHtml = libraryObj.html || libraryObj.blocks; if (libraryObj) self.layout(libraryObj, selectorParams, args); // TODO warning potential infinite loop (if string) else self.log('"theme" not found: ' + params); } else { var libraryHtml = params.html; // can a library component be an object? if (params.setup) args = self.extend(args, params.setup); // or params.args? if (params.functions) self.extendJson(json, {functions: params.functions}); if (params.css) self.extendJson(json, {css: params.css}); //if (params.styles) self.extendJson(json, {styles: params.styles}); if (params.items) self.extendJson(json, {items: params.items}); if (params.var) self.extendJson(json, {var: params.var}); self.html(libraryHtml, selectorParams, args); // {container: container} //self.(params, selectorParams, args); } } } */ this.part = this.block = function (params, selectorParams, args) { let nested; let part; let partArguments; if (typeof params.do == 'string' && self.json.parts) { // && par.match(/[.>]+/)) 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 }); // TO DO: . -> space? /* if (par.indexOf(':')>0 && !part) { self.firebaseGetPart({localPath:localPath, container: params.selector, arg:params.obj}); } */ } else if (typeof params.do == 'object') part = params.do; if (part) { //if (!params.arguments) params.arguments = {}; // TO DO: Check this. seems a workaround for fantacards/ui:qrcode if (params.arguments) partArguments = self.replaceProperties(params.arguments); if (typeof params.arguments == 'object') { partArguments = (params.arguments.setup) ? params.arguments.setup : params.arguments; // compatibility partArguments.selector = partArguments.selector || params.selector; } nested = self.replacePropertyWithPrefix(part, 'setup', partArguments); // {setup} -> {arguments} nested = self.replacePropertyWithPrefix(nested, 'arguments', partArguments); // to tix self.extendJsonFromElement(nested); self.do(nested, params.selector, partArguments); } }; this.blocks = function (params, selectorParams, args) { if (Array.isArray(params)) { for (var index in params) self.blocks(params[index], selectorParams, args); } else { //self.log('blocks'); //self.log(params); if (typeof params == 'string') { var blockName = self.replaceProperties(params, args); // self.compile(params, args); //self.log('blockName'); //self.log(blockName); var libraryObj = self.element({ path: 'self.json.blocks.' + blockName }); // todo: get? //self.log('libraryObj'); //self.log(libraryObj); //var libraryHtml = libraryObj.html || libraryObj.blocks; if (libraryObj) //self.html(libraryObj, selectorParams, args); self.run(libraryObj, selectorParams, args); //self.blocks(libraryObj, selectorParams, args); // TODO warning potential infinite loop (if string) else self.log('library component not found: ' + params); } else { self.run(params, selectorParams, args); //self.run(params, selectorParams, args); //var libraryHtml = params.html || params.app.html; /* // can a library component be an object? if (params.setup) args = self.extend(args, params.setup); // or params.args? if (params.parts) self.extendJson(json, {parts: params.parts}); if (params.actions) self.extendJson(json, {actions: params.actions}); if (params.css) self.extendJson(json, {css: params.css}); if (params.data) self.extendJson(json, {data: params.data}); if (params.var) self.extendJson(json, {var: params.var}); if (params.texts) self.extendJson(json, {texts: params.texts}); self.html(params.html, selectorParams, args); // {container: container} //self.do(params, selectorParams, args); */ } } }; this.uiUpdate = function (option) { window.dispatchEvent(new Event('resize')); // workaround known ACE bug //self.updateCodeEditors(); // workaround known ACE bug }; this.resizeEvent = function (event) { //self.log('resizeEvent'); 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 }); //self.do(self.resizeActions[element].action, {selector: selector}); } else { var value = self.resizeActions[selector][property]; var result = self.replaceProperties(value) || ''; //$(selector).css(property, result); element.style[property] = result; } } } }; /* var pages = {}; var pagesSlider; this.createPages = function (data) { self.log('createPages'); //backLink = (self.json.setup && self.json.setup.home && self.json.setup.home[var.mode]) ? self.json.setup.home[var.mode] : ''; // class="container-fluid px-0" style="margin-top:'+self.json.setup.main.top+'" var pageContainer = '#pages'; // 'main > div' for (var pageKey in self.json.pages) { params = self.json.pages[pageKey]; var pageRoles = (params.roles) ? String(params.roles).split(',') : undefined; // se il ruolo dell'utente permette la vista della pagina e se non è stata già creata if (!params.roles || (pageRoles.indexOf(self.userRole()) >= 0 && document.querySelectorAll('#'+pageKey).length == 0)) { // $('#'+pageKey).length == '#'+pageKey doesn't exist //if (params.preload) { params.tag = 'div'; //params.id = pageKey; params.class = 'page'; params.value = pageKey; // the previous definition should be in layout.page self.addTag(params, {container: pageContainer}); //} } else { self.log('' + self.userRole() + ' users can\'t access to the page '+pageKey); } } self.do(data); } */ this.pageFullScreen = function (onOff) { self.log('pageFullScreen'); if (onOff) self.addClass(document.querySelector('body'), 'fullscreen'); else self.removeClass(document.querySelector('body'), 'fullscreen'); }; //var backLink = 'stage'; /* this.pageBack = function () { self.gotoPage(backLink); //window.location.href = '?p='+backLink; //$('body').removeClass('nav-open'); // chiude menu } */ this.link = function (link, args) { /* function link() { [native code] } */ //alert(link); link = self.replaceProperties(link, args); window.location.href = link; }; this.reload = function () { location.reload(); }; this.gotoHomePage = function () { self.gotoPage(self.homePage()); }; this.homePage = function () { //alert('homePage'); if (self.json.pages) { if (Object.keys(self.json.pages).length > 0) { //var homeKey = Object.keys(self.json.pages).find(key => self.json.pages[key] === 'home'); 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'); } }; /* this.activePage = function () { // to check if obsolete return var.page; } */ /* this.slideIndex = function (id) { return $('#'+id).index()+1; } */ /* this.slideTo = function (params) { if (pagesSlider) pagesSlider.goTo(self.slideIndex(params.id)); $('#pages > .seq-canvas > .seq-in').addClass(params.transition); } */ this.updateCodeEditors = function () { // workaround known ACE bug: // setValue doesn't work if editor is hidden // http://jsfiddle.net/e4r7byLn/ var elements = document.querySelectorAll('.ace_editor'); if (elements) { elements.forEach(function (element, index) { var editor = ace.edit(element); editor.renderer.updateFull(true); //AceColorPicker.load(ace, editor); //AceColorPicker.load(ace, editor); // works after some ms }); } }; this.gotoPage = function (pageId, fromHash) { self.log('page'); // changePage self.log('pageId'); self.log(pageId); self.log('fromHash'); self.log(fromHash); //self.log("var.page"); //self.log(var.page); 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) { //var.pagePath = fromHash; // obsolete self.json.setup.page.hash = fromHash; } else { //delete var.pagePath; delete self.json.setup.page.hash; } //var.page = pageId; // activePage //var newHash = pageId; //if (!fromHash) window.location.hash = newHash; var fullScreen = self.json.pages[pageId].fullscreen || false; //self.pageFullScreen(fullScreen); 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.out({ "class": "page", "data-value": self.json.setup.page.id, "transition": "fadeOutLeft" }); */ self.json.setup.page.id = pageId; self.json.setup.page.title = page.title; self.json.setup.page.roles = page.roles; /* // TO DO: don't change document title and description // window title var documentTitle = self.json.setup.title; if (page.title) documentTitle += ' ' + self.text(page.title); var documentDescription = self.json.setup.description || ''; if (documentTitle) document.title = documentTitle; if (document.querySelector('meta[name="description"]')) document.querySelector('meta[name="description"]').setAttribute("content", documentDescription); */ //$('title').text(windowTitle); // change page self.hide({ "class": "page" }); self.in({ "class": "page", "data-value": pageId, "transition": "fadeIn" }); /* $('.page').hide(); $('.page[data-value='+pageId+']').fadeIn(); */ //self.resizeEvent(); self.uiUpdate(); // resize event trigger /* // page back icon if (page.back) { backLink = page.back; $('#headerLeftIcons').show((page.back)); } else { $('#headerLeftIcons').hide(); } */ } if (page.update) { // obsolete self.do(page.update); //, {container: '.page[data-value='+pageId+']'}); //self.do(page.update); //, {container: '.page[data-value='+pageId+']'}); } if (page.init) self.do(page.init); self.log(page); if (page.on) self.on(page.on, { selector: '.page[data-value=' + pageId + ']' }); //$('body').removeClass('nav-open'); // chiude menu //$('.offcanvas-collapse').removeClass('open'); } else { if (self.userRole() == 'guest') { /* self.do({ "login": { "success": { "reload": true } } }); */ } else { self.alert('Non hai i privilegi per accedere a questa pagina'); } } } else { // pagina non trovata } } 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; 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; }; 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); }; this.alert = function (params, args) { /* self.log('alert'); self.log('params'); self.log(params); self.log('args'); self.log(args); */ var paramsReplaced = self.cloneObject(params); //paramsReplaced = self.replaceProperties(paramsReplaced, args); //self.log('paramsReplaced'); //self.log(paramsReplaced); if (paramsReplaced) { if (paramsReplaced.do && paramsReplaced.do !== 'fire') { return Swal[paramsReplaced.do](params); // more info on https://sweetalert2.github.io/#methods } else { if (typeof paramsReplaced == 'string') paramsReplaced = self.text({ string: paramsReplaced, args: args }); // verify //self.log('paramsReplaced string replaced'); //self.log(paramsReplaced); if (typeof paramsReplaced == 'number') paramsReplaced = String(paramsReplaced); // avoid bug if (paramsReplaced.title !== undefined) paramsReplaced.title = self.text({ string: paramsReplaced.title, args: args }); //self.log('paramsReplaced2'); //self.log(paramsReplaced); 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 }); //self.log('paramsReplaced string replaced 2'); if (paramsReplaced.inputValue) paramsReplaced.inputValue = self.text({ string: paramsReplaced.inputValue, args: args }); //if (paramsReplaced.html) paramsReplaced.html = self.text({string: paramsReplaced.html, args: args}); // verify 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.showConfirmButton) paramsReplaced.showConfirmButton = self.text({string: paramsReplaced.showConfirmButton, 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.inputOptions) paramsReplaced.inputOptions = self.text({string: paramsReplaced.inputOptions, args: args}); if (paramsReplaced.footer) { paramsReplaced.footer = self.text({ string: paramsReplaced.footer, args: args }); } //if (paramsReplaced.upload) alert('paramsReplaced.upload: '+paramsReplaced.upload); if (paramsReplaced.upload) { paramsReplaced.html = '
      ' + self.text('dragAndDropFiles') + '
      ' + self.text('chooseFiles') + '
      '; // //if (paramsReplaced.onUpload) var.onUpload = paramsReplaced.onUpload; //var.uploadingTarget = paramsReplaced.uploadingTarget; } //self.log('paramsReplaced3'); //self.log(paramsReplaced); alertObj.confirm = paramsReplaced.confirm; // deprecated alertObj.cancel = paramsReplaced.cancel; // deprecated alertObj.deny = paramsReplaced.deny; // deprecated 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); // animate 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) { //swalParams.icon = self.replaceProperties(swalParams.icon, args); if (typeof swalParams.icon !== 'string') { customIcon = self.cloneObject(swalParams.icon); delete swalParams.icon; } /* var swalIcons = []; //"warning", "error", "success", "info", "question"]; if (swalIcons.indexOf(params.icon)<0) { customIcon = params.icon; //if (!params.customClass) params.customClass = {}; //params.customClass.icon = "customIcon"; } */ } //if (swalParams.showConfirmButton) delete swalParams.showConfirmButton; // swalParams.update = function() { // self.log('swalParams.update'); // self.log(var.updateSwal); // } // onRender is obsolete /* swalParams.onRender = function () { startUploadListeners({ container: '.drop-zone', onUpload: params.onUpload, path: params.path //uploadingTarget: var.uploadingTarget //onError: }); } */ 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 () { //Swal.showLoading(); // rimuove i bottoni 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); }; } //self.log('swalParams'); //self.log(swalParams); Swal.fire(swalParams).then((result) => { //self.log('alert result'); //self.log(result); // TO DO: if (!result) result = {} to avoid errors var alertResult = result.value; if (alertObj.on) { if (alertObj.on.value && result.value) { //if (alertObj.id) alertObj.values[alertObj.id] = 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); //alertObj.on.value = self.replaceProperty(alertObj.on.value, 'alert', result); self.do(alertObj.on.value, undefined, result.value); // TO DO: remove result.value once removed all {result} //self.do(alertObj.on.value, result.value); // TO DO: remove result.value once removed all {result} }, 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); // TO DO: remove result.value once removed all {result} //self.do(alertObj.on.isConfirmed, result.value); // TO DO: remove result.value once removed all {result} } if (alertObj.on.isDenied && result.isDenied) { alertObj.on.isDenied = self.replacePropertyWithPrefix(alertObj.on.isDenied, 'alert', result); self.do(alertObj.on.isDenied, undefined, result.value); // TO DO: remove result.value once removed all {result} //self.do(alertObj.on.isDenied, result.value); // TO DO: remove result.value once removed all {result} } if (alertObj.on.isDismissed && result.isDismissed) { alertObj.on.isDismissed = self.replacePropertyWithPrefix(alertObj.on.isDismissed, 'alert', result); self.do(alertObj.on.isDismissed, undefined, result.dismiss); // TO DO: remove result.value once removed all {result} //self.do(alertObj.on.isDismissed, result.dismiss); // TO DO: remove result.value once removed all {result} } console.log('alertValues'); console.log(alertValues); } else { /* if (result.isConfirmed) { self.do(alertObj.confirm, result.value); } else if (result.isDenied) { self.do(alertObj.deny, result.value); } else if (result.dismiss === Swal.DismissReason.cancel) { self.do(alertObj.cancel, result.value); } else if (result.dismiss === Swal.DismissReason.timer) { self.log('Alert closed by the timer'); } */ } /* Reason Description Related configuration Swal.DismissReason.backdrop The user clicked the backdrop. allowOutsideClick Swal.DismissReason.cancel The user clicked the cancel button. showCancelButton Swal.DismissReason.close The user clicked the close button. showCloseButton Swal.DismissReason.esc The user clicked the Esc key. allowEscapeKey Swal.DismissReason.timer The timer ran out, and the alert closed automatically. timer */ }); if (alertHtml) self.do(alertHtml, { selector: '#swal2-html-container' }); //self.log('customIcon'); //self.log(customIcon); if (customIcon) { /* self.icons({ "class": "icon", "svg": customIcon }, {container: '.swal2-icon'}); */ self.do(customIcon, { selector: '.swal2-icon' }); //self.addTag(customIcon, {container: '.swal2-icon'}); // check self.css({ selector: '.swal2-icon', style: { 'border': '0px solid transparent' } }); self.show({ selector: '.swal2-icon' }); /* $('.swal2-icon').css({ 'border': '0px solid transparent' }); $('.swal2-icon').show(); */ } if (swalParams.on && swalParams.on.init) // to be repeated in each function self.do(swalParams.on.init); //self.do(swalParams.on.init); } } }; /* var startUploadListeners = function (params) { // da FIXO self.log('startUploadListeners'); var.upload = params; var obj = $(params.container); self.log(params); obj.on('dragenter', function (e) { e.stopPropagation(); e.preventDefault(); $(this).css('border', '2px solid #0B85A1'); }); obj.on('dragover', function (e) { e.stopPropagation(); e.preventDefault(); }); $(document).on('dragenter', function (e) { e.stopPropagation(); e.preventDefault(); }); $(document).on('dragover', function (e) { e.stopPropagation(); e.preventDefault(); obj.css('border', '2px dotted #0B85A1'); }); $(document).on('drop', function (e) { e.stopPropagation(); e.preventDefault(); }); // automatically submit the form on file select obj.on('drop', function (e) { $(this).css('border', '2px dotted #0B85A1'); e.preventDefault(); var files = e.originalEvent.dataTransfer.files; //We need to send dropped files to firebase handleFileUpload(files); }); $(params.container+'-file').on('change', function (e) { var files = $(params.container+'-file')[0].files; self.log(params.container+'-file'); self.log(files) handleFileUpload(files); }); } */ /* this.uploadFileNameAndType = function(params){ self.log('uploadFileNameAndType'); self.log(params); var fileArr = params.fileName.split('.'); var.upload.fileName = params; var.upload.fileType = fileArr[1].toLowerCase(); if (!$('.swal2-act').length) $('.swal2-modal').append('
      '); if (var.upload.fileType == 'ply') { $('.swal2-act').css({'display':'none'}); } else { $('.swal2-act').css({'display':'block'}); $('.swal2-act').append(''); } } */ /* var handleFileUpload = function(files) { self.log('handleFileUpload'); self.log(files); self.log('var.upload'); self.log(var.upload); //var auth0Id = fixo.getAuth0Id(); // Swal.close(); // chiusura popup for (var i = 0; i < files.length; i++) { var fd = new FormData(); fd.append('file', files[i]); if (!files[i].name.endsWith('png')) var.upload.fileTimestamp = self.getTimestamp(); self.fireBaseUpload({ 'file': files[i], //base64toBlob(files), 'timestamp': var.upload.fileTimestamp, 'path': var.user.uid+'/' || '' //auth0Id+'/files/images' //path_to_where_you_to_store_the_file }, function (data) { self.log('data'); self.log(data); if (!data.error) { //if (data.progress && data.progress == 0) $('.swal2-actions').append(''); if (data.progress >= 0 && data.progress <= 100) { //progress update to view here // self.log('Uploading file'); // self.log(var.uploadingTarget); $('#msgFooter').html(''+data.progress+'%') } if (data.progress == 100) { //$(var.uploadingTarget).removeClass('pulseFade'); // Swal.close(); if (data.fileExt !== 'png'){ self.log('diverso da png'); $('.drop-zone-file').attr('accept','.png'); var.upload.data = data; } if (var.upload.onUpload) self.do(var.upload.onUpload, data); } } else { //$(var.uploadingTarget).removeClass('pulseFade'); self.log(data.error + ' Firebase image upload error'); } }); } }; */ /* var uploadDone = function (data) { self.log('uploadDone'); // download URL here "data.downloadURL" var auth0Id = fixo.getAuth0Id(); var storageRef = firebase.storage().ref(); var imageRef = storageRef.child(auth0Id+'/files/images/'+data.fileName); // Get the download URL imageRef.getDownloadURL().then(function(url) { self.do(var.onUpload, url); // Insert url into an tag to "download" }).catch(function(error) { self.log(error.code); // A full list of error codes is available at // https://firebase.google.com/docs/storage/web/handle-errors switch (error.code) { case 'storage/object_not_found': // File doesn't exist break; case 'storage/unauthorized': // User doesn't have permission to access the object break; case 'storage/canceled': // User canceled the upload break; case 'storage/unknown': // Unknown error occurred, inspect the server response break; } }); } */ this.findKey = function (obj, key) { return obj.filter(function (item) { return Boolean(item[key]); }); }; /* this.fireBaseUpload = function(parameters, callBackData) { self.log('fireBaseUpload'); self.log('parameters'); self.log(parameters); // Get a reference to the storage service, which is used to create references in your storage bucket var storageRef = firebase.storage().ref(); var file = parameters.file; var path = parameters.path; var timestamp = parameters.timestamp; //var path = var.user.uid; // non riesco a passare la path come parametro da olo.app.json così come l'errore funzione onUpload self.log('file'); self.log(file); self.log('timestamp'); self.log(timestamp); self.log('path'); self.log(path); //Riga originale pre-modifica nome file // var fullPath = path + '/' + file.name; // expected parameters to start storage upload var metaData = {'contentType': file.type}; var fileSize = formatBytes(file.size); // get clean file size var fileType = file.type; var fileName = file.name; var fileExt = fileName.split('.')[1]; self.log(metaData); self.log(fileSize); self.log(fileType); self.log(fileName); self.log(fileExt); var modFileName = timestamp+'.'+fileExt; //var fullFilePath = storageRef.child(path+timestamp+'-'+fileName); var fullFilePath = storageRef.child(path+modFileName); self.log('fullFilePath'); self.log(fullFilePath); var nm = fileName.split('.'); var name = nm[0]; self.log('nm'); self.log(nm); self.log('name'); self.log(name); // Modifica file name generato // var name = generateRandomString(16); //(location function below) // var n = name+'.'+file.type.replace('image/',''); // var fullPath = path + '/' + n; //Riga originale pre-modifica nome file // var n = file.name; // generate random string to identify each upload instance //name = generateRandomString(12); //(location function below) // var uploadFile = storageRef.child(parameters.path).put(file, metaData); var uploadFile = fullFilePath.put(file, metaData); // first instance identifier //callBackData({id: name, fileSize: fileSize, fileType: fileType, fileName: n}); 20200724 callBackData({id: timestamp.toString(), fileSize: fileSize, fileType: fileType, fileName: modFileName, fileExt: fileExt}); // fileName: fileName //id: name uploadFile.on('state_changed', function (snapshot) { var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; progress = Math.floor(progress); self.log('progress'); self.log(progress); callBackData({ progress: progress, element: timestamp.toString(), //element: name, fileSize: fileSize, fileType: fileType, fileName: modFileName, fileExt: fileExt}); //fileName: fileName }, function (error) { callBackData({error: error}); }, function () { var downloadURL = uploadFile.snapshot.downloadURL; callBackData({ downloadURL: downloadURL, element: timestamp.toString(), //element: name, fileSize: fileSize, fileType: fileType, fileName: modFileName, fileExt: fileExt}); //fileName: fileName }); } */ 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]; }; this.userRole = function () { switch (Boolean(self.user('uid'))) { case true: return 'user'; // user logged in break; case false: return 'guest'; break; } }; this.userIn = function () { //var user = firebase.auth().currentUser; //if (user.emailVerified) { return Boolean(self.user('uid')); }; this.userOut = function () { return (!self.user('uid')); }; this.user = function (param) { /* self.log('user'); self.log(auth); */ 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; }; this.firstName = function (nameParam) { var firstNameStr = (nameParam) ? nameParam.split(' ')[0] : ''; return firstNameStr; }; this.userUid = function () { if (auth) return auth.currentUser.uid; else return undefined; }; this.userVerified = function () { if (auth) return auth.currentUser.emailVerified; else return undefined; }; /* this.value = function (valueParams) { if (valueParams.string) return valueParams.string else if (valueParams.function) //return self.doFunctionByName(valueParams.function, window, ''); } */ this.thunkableMessage = function (message, callback) { if (callback) callback(message); }; this.onMessage = { alert: "test" }; this.processMessage = function (message) { self.alert('processMessage'); self.do(self.onMessage, message); //self.do(self.onMessage, undefined, message); }; 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) { } } }; /* var ThunkableWebviewerExtension = (function () { const postMessageToWebview = (message) => { if (window.ReactNativeWebView) { window.ReactNativeWebView.postMessage(message); } else { window.parent.postMessage(message, '*'); } }; const getReceiveMessageCallback = (fxn, hasReturnValue) => (event) => { if (typeof fxn === 'function') { if (event.data) { let dataObject; try { dataObject = JSON.parse(event.data); } catch (e) { // message is not valid json } if (dataObject && dataObject.type === 'ThunkablePostMessage' && hasReturnValue) { fxn(dataObject.message, (returnValue) => { const returnMessageObject = { type: 'ThunkablePostMessageReturnValue', uuid: dataObject.uuid, returnValue }; postMessageToWebview(JSON.stringify(returnMessageObject)); }); } else if (!hasReturnValue && (!dataObject || dataObject.type !== 'ThunkablePostMessage')) { fxn(event.data); } } } }; return { postMessage: postMessageToWebview, receiveMessage: function (fxn) { const callbackFunction = getReceiveMessageCallback(fxn, false); document.addEventListener('message', callbackFunction, false); window.addEventListener('message', callbackFunction, false); }, receiveMessageWithReturnValue: function (fxn) { const callbackFunction = getReceiveMessageCallback(fxn, true); document.addEventListener('message', callbackFunction, false); window.addEventListener('message', callbackFunction, false); }, }; })(); */ this.extendFunctions = function (functions) { // change it. don't call self.function for (var name in functions) { if (functions[name].js) { try { // create or override function 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); // error.column is wrong /* let col = error.column -17; console.log( functions[name].js.substring(0,col) + '%c' + functions[name].js.substring(col, col+1) + '%c' + functions[name].js.substring(col+1), 'color:orange; font-weight:bold', 'color:#ddd') console.log('%c' + error.message, 'color:orange;'); */ // since the script is in one row, error.columns is the exact position of the error } } else { self.log(name + ' function requires js property'); } } }; this.function = function (obj, args) { /* console.log('function'); console.log(params); console.log('args'); console.log(args); */ // TO DO: add "name" parameter to make the js function permanently available in self.methods[name] // https://stackoverflow.com/questions/49125059/how-to-pass-parameters-to-an-eval-based-function-injavascript //app[func].apply( this, args ); // or app[func]( ...args ); // ES6 (2015) // https://stackoverflow.com/questions/1316371/converting-an-array-to-a-function-arguments-list //args = self.replaceProperties(args); // needed? //try { if (obj.name && obj.js) { // create or replace function self.functions[obj.name] = new Function(obj.js); } else if (obj.name && !obj.js) { if (self.functions[obj.name]) { // execute function if (!obj.arguments || !Array.isArray(obj.arguments)) obj.arguments = [obj.arguments]; try { return self.functions[obj.name](...obj.arguments); //return self.functions[obj.name].apply(null, 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;'); } //return self.functions[obj.name](...obj.arguments); // also args? } else if (obj.js) { // execute js code as a function if (obj.arguments && Array.isArray(obj.arguments)) { return new Function(obj.js).call(null, obj.arguments); //return new Function( obj.js ).apply(this, obj.arguments ); } else { return new Function(obj.js).call(null, obj.arguments); } } /* } catch (error) { self.log('function ERROR'); self.log(error); self.log(obj); return false } */ }; this.eval = this.js = function (code, args) { /* self.log('js'); self.log(code); self.log(args); */ /* if (Array.isArray(code)) { let codeCombined = ''; for (var codePart of code) codeCombined += self.replaceProperties(codePart, args); try { return eval(code); } catch (error) { self.log('JS error'); self.log(error); return code; } */ /* if (typeof code == 'object') { } else { */ code = self.replaceProperties(code, args); /* self.log('args'); self.log(args); */ try { //return new Function( code ).call(null, args); return eval(code); } catch (error) { /* self.log('javascript catch on "'+ codeString + '"'); self.log('error'); self.log(error); self.log('codeString'); self.log(codeString); self.log('args'); self.log(args); return false */ return code; } //} }; /* this.compile = function (obj, args) { // functions e addTag potrebbero essere eseguiti da una stessa funzione // in reatà addTag è la funzione che andrebbe lanciata quando la chiave // dell'azione è tra i tag html if (obj !== undefined) { var result; if (typeof obj == 'object') result = self.actionResult(obj, args); result = self.replaceProperties(obj, args); if (result == 'undefined') return undefined; else if (typeof result == 'object') // Array is also an object type return self.do(result, args); else if (typeof result == 'function') return result(args); else { return result; } } else { return undefined; } } */ this.if = function (params, selectorParams, args) { // add array 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)); // remove undefined values 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)))); // remove undefined values 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) { //let arr = self.replaceProperties(params.in, args, true); //condition = (arr.indexOf(self.replaceProperties(params.value)) >= 0); 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); //var selector = self.selector(params.selector || params.container, selectorParams); if (selector) { if (params.exist) { //var element = self.query(params.exist); //condition = Boolean(self.query(selector)); condition = Boolean(self.exist(selector)); conditionString += ' ' + selector + ' exist ' + params.exist; } if (params.hasClass) { // to be reviewed (self.hasClass need 1 parameter) 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); /* self.log('element'); self.log(element); */ condition = Boolean(self.isDisplay(element, params.isDisplay)); conditionString += ' ' + selector + ' isDisplay ' + params.isDisplay; } } else { self.log('the "if" function requires "is" or "not" parameter'); } } /* conditionString += ': ' + condition; self.log(condition, 'grey'); */ if (condition) if (params.then) { // self.console dovrebbe diventare così if (typeof params.then == 'object') { return self.do(params.then); //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); //return self.do(params.else); } if (typeof params.else == 'string') { return self.replaceProperties(params.else); } else { return params.else; } } } else { //self.log(Boolean(params) && params !== 'false'); return Boolean(self.js(params, args)); // 0.9.7 //return Boolean(eval(self.replaceProperties(params, args))) // need try } }; this.switch = function (params, args) { //self.log('switch'); //self.log(params); var value; var answer; if (params.expression) value = String(self.js(params.expression, args)); else self.log('"switch" function requires "expression" parameter'); //self.log(value); if (params.cases) { //self.log('params.cases[value]'); //self.log(params.cases[value]); if (value !== undefined && params.cases[value]) { if (typeof params.cases[value] == 'object') answer = self.do(params.cases[value], undefined, args); //answer = self.do(params.cases[value], 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); //answer = self.do(params.cases['default'], args); else answer = params.cases['default']; } } else { self.log('"switch" function requires "cases" parameter'); self.log('answer'); self.log(answer); } return answer; }; /* this.varAction = this.set = function (params, args) { // {name, value, operator} var value; var operator = params.operator; //self.log('operator'); //self.log(operator); if (operator && args) operator = self.replaceProperties(operator, args); //self.log('operator'); //self.log(operator); if (params.value !== undefined) { // set value = self.js(params.value, args); if (params.var) { self.docElement('self.json.var.'+params.var, value); } else if (params.name) { var actualValue = self.docElement('self.json.var.'+params.name); if (actualValue == undefined && typeof value == 'string') actualValue = ''; if (actualValue == undefined && typeof value == 'number') actualValue = 0; if (actualValue == undefined && typeof value == 'object') actualValue = {}; if (operator) { if (operator == '+=') actualValue += value; if (operator == '-=') actualValue -= value; if (operator == '/=') actualValue /= value; if (operator == '*=') actualValue *= value; value = actualValue; } self.docElement('self.json.var.'+params.name, value); //self.log('self.json.var[params.name]'); //self.log(self.json.var[params.name]); } else { self.log('set command requires "var" parameter'); } } else { // get if (params.var) { return self.docElement('self.json.var.'+params.var); } else if (params.name) { return self.docElement('self.json.var.'+params.name); } else { self.log('set command requires "value" parameter'); } } //self.log('value'); //self.log(value); self.log('var ' + params.name + ' = ' + value); } */ 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); //self.do(params.do, args, container) }, duration); } }; this.firebasePasswordReset = function (paramEmail, paramSuccess, paramError) { //firebase.auth().languageCode = 'it'; firebase.auth().useDeviceLanguage(); auth.sendPasswordResetEmail(paramEmail).then(function () { // Email sent. if (paramSuccess) self.do(paramSuccess); //if (paramSuccess) self.do(paramSuccess); }).catch(function (error) { // An error happened. if (paramError) self.do(paramError, undefined, error.message); //if (paramError) self.do(paramError, error.message); }); }; this.firebaseUpdateProfile = function (params, paramSuccess, paramError) { self.log('firebaseUpdateProfile'); self.log(params); auth.currentUser.updateProfile(params).then(function () { // Update successful. self.log('User Profile Updated Successfully'); if (paramSuccess) self.do(paramSuccess); //if (paramSuccess) self.do(paramSuccess); }).catch(function (error) { // An error happened. if (paramError) self.do(paramError, undefined, error.message); //if (paramError) self.do(paramError, error.message); }); }; this.firebaseRegister = function (params, success, error) { if (params.email && params.password) { // log the user in auth.createUserWithEmailAndPassword(params.email, params.password).then(cred => { self.log(cred.user); //var.auth.cred = cred; var user = firebase.auth().currentUser; /* if (user.emailVerified) { } else { self.sendEmailVerification(params); } */ //if (params.success) self.do(params.success); if (params.success) self.do(params.success); }).catch(error => { // Handle Errors here. //if (params.error) self.do(params.error, error.message); if (params.error) self.do(params.error, undefined, error.message); }); } }; this.firebaseLogin = function (params) { self.log('firebaseLogin'); self.log(params); if (auth) { auth.signInWithEmailAndPassword(String(params.email), String(params.password)).then(cred => { //var.auth.cred = cred; var user = firebase.auth().currentUser; //firebase.auth().languageCode = 'it'; if (user.emailVerified) { if (params.success) self.do(self.replaceResult(params, undefined, cred)); //if (params.success) self.do(self.replaceResult(params, 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)); //if (params.error) self.do(self.replaceResult(params, error.message)); }); } else { // firebase auth non inizializzato } }; this.firebaseLogout = function (params) { self.log('firebaseLogout'); firebase.auth().signOut().then(function () { self.log('firebaseLogout SUCCESS'); self.log(params.success); if (params.success) { //app.stopMeeting(); localStorage.clear(); //self.do(params.success); self.do(params.success); } }).catch(function (error) { self.log('firebaseLogout ERROR'); self.log(error); //if (params.error) self.do(params.error); if (params.error) self.do(params.error); }); }; // this.firebaseUserVerify = function (params) { // self.log('firebaseUserVerify'); // self.log(params); // self.log(params.oobCode); // if (params.oobCode) self.params.codeMail = params.oobCode // self.log(self.params.codeMail); // //self.do(data); // // inviare mail di verifica // } 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({ //toast: true, icon: "success", title: "verifyingemail", // all\'indirizzo "+params.email+" html: "msgverifyingemail", //confirmButtonText: "Ok", //showCancelButton: false, showConfirmButton: false, confirm: successAction }); }); }; /* //self.log('function'); params = self.replaceProperties(params, args); // -> compile if (typeof params == 'object') { // jsonic function //return self.do(params, args); return self.do(params, args); } else if (typeof params == 'function') { // javascript function return params(args); } else if (typeof params == 'string') { if (json.actions[params]) { var functionCompiled = self.replaceResult(json.actions[params], args); // replace {result} //functionCompiled = self.replaceProperties(functionCompiled, args); // jsonic predefined function //return self.do(functionCompiled); return self.do(functionCompiled); //return self.actionResult(json.actions[params], args); } else { // javascript function name var functionName = self.docElement(params); if (functionName) if (typeof functionName == 'function') { // javascript function return functionName(args) } else { // javascript object return functionName; } else self.log('function undefined: '+ params); } } */ this.path = function (pathParams, args, separatorParam) { var pathString = ''; var separator = separatorParam || '/'; /* self.log('this.path'); self.log(pathParams); self.log(args); */ 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; }; this.executeFunctionByName = function (functionName, context /*, arguments */) { //self.log('executeFunctionByName'); //self.log(functionName); 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 { //self.log('Error: executeFunctionByName'); //if (functionName !== undefined) {self.log('functionName:'+functionName);} } } else { self.log('executeFunctionByName'); self.log('functionName undefined'); } }; this.functions = {}; this.methods = { // main 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); }, // TO DO: check 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); }, // DA VERIFICARE //dayjs: function (params, args) {self.dayjs(params, args)}, //moment: function (params, args) {self.moment(params, args)}, //data: function (params, args) {self.data(params, args)}, //var: function (params, args) {self.var(params, args)}, //javascript: function (params, args) {self.javascript(params, args)}, //color: function (params, args) {self.color(params, args)}, //select: function (params, args) {self.select(params, args)}, // LOGIC & DATA 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); }, // TO DO: check is needs to be renamed to avoid confusion with self.json.data 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); // backward compatibility TO DO: remove 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 }); } } } }, // DOM text: function (params, container, args) { self.text(params, container, args); }, // TO DO: -> html 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 }); // NOTE: obj = self.element non prende l'oggetto effettivo. quindi element deve contenere tutte le funzioni //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); /* self.log('value'); self.log(value); */ 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); } } }, // should go in utils.json calendar: function (params, container, args) { self.calendar(params, args); }, // to check 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 there remain elements to shuffle. while (currentIndex != 0) { // Pick a remaining element. randomIndex = Math.floor(Math.random() * currentIndex); currentIndex--; // And swap it with the current element. [array[currentIndex], array[randomIndex]] = [ array[randomIndex], array[currentIndex] ]; } return array; }, // should go in ui.json (or ux) module alert: function (params, container, args) { self.alert(params, args); }, // change in swal2 offcanvas: function (params, container, args) { self.offcanvas(params, args); }, // bootstrap / obsolete //in: function (params, container, args) {self.in(params, container, args)}, // bootstrap TO DO: replace in code with ui:in out: function (params, container, args) { self.out(params, container, args); }, // bootstrap TO DO: replace in code with ui:out qrcode: function (params, container, args) { self.qrcode(params, container, args); }, // obsolete TO DO: replace in code with ui:qrcode hide: function (params, container, args) { self.hide(params, container, args); }, // TO DO: replace in code with ui:hide show: function (params, container, args) { self.show(params, container, args); }, // TO DO: replace in code with ui:show toggle: function (params, container, args) { self.toggle(params, container, args); }, // TO DO: replace in code with ui:toggle sortablejs: function (params, container, args) { self.sortablejs(params, args); }, // TO DO: replace in code with ui:sortable lottie: function (params, container, args) { self.lottie(params, container, args); }, // TO DO: replace in code with ui:lottie 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); }, //editor: function (params, container, args) {self.editor(params, container, args)}, // quill // window.dispatchEvent(new Event('resize')); // workaround known ACE bug uiUpdate: function (params, container, args) { self.uiUpdate(params, args); }, swiper: { data: {}, init: function (params, selector, args) { //swiperConfig.on = {}; setTimeout(function () { // waits the plugin... TO DO: add this function to a promise 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); } }, // should go in browser.json module //export: function (params, container, args) {self.export(params, container, args)}, -> browser //console: function (params, container, args) {self.console(params, args)}, // obsolete, changed in log 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); }, // obsolete 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); }, // should go in firebase.json module database: function (params, container, args) { self.database(params, args); }, // obsolete (check) firebase: function (params, container, args) { self.firebase(params, args); }, firebaseEvent: { action: function (newObj) { /* self.logdbRef('firebaseEvent.action'); self.log('newObj'); self.log(newObj); */ /* var path = newObj.path; delete newObj.path; var pathString = 'self.json.var.db.' + self.replaceAll(path, '/', '.'); self.log('pathString:'+pathString); var dbObj = self.docElement(pathString); dbObj = newObj; // update local db */ var path = newObj.path; delete newObj.path; //alert(path); document.querySelectorAll('[data-firebase="' + path + '"]').forEach(function (element, index) { //$('[data-firebase="'+path+'"]').each(function (index) { // var element = this; var pathString = 'self.json.var.db.' + self.replaceAll(element.getAttribute('data-firebase'), '/', '.'); // data('firebase') var dbObj = self.docElement(pathString); var firebaseValue = newObj[element.getAttribute('data-value')]; // TODO: not works for nested nodes //var template = element.getAttribute('data-template'); var template = self.dataStorage.get(element, 'data-template'); //if ($(element).is('ul')) { if (element.tagName == 'UL') { // se $(this) è un ul //var dbObj = self.docElement(pathString); // se il percorso ha più nodi e il dato non è presente nel db locale, // va creato un oggetto vuoto per ogni nodo //var context = element.getAttribute('data-firebase'); //self.var.db[context] = newObj; // update local db var liTemplate = template.li || template.template; // template.li retro-compatibility /* self.log('liTemplate'); self.log(liTemplate); self.log('newObj'); self.log(newObj); */ //$(container).empty(); element.innerHTML = ''; var items = newObj; for (itemKey in items) { var item = items[itemKey]; item.key = itemKey; /* if (params.li.class == "deviceItem d-flex flex-wrap align-items-center list-group-item list-group-item-action d-flex align-items-center justify-content-between") { alert(JSON.stringify(params.li)); } */ //if (dbPath == 'lessons') //prompt(JSON.stringify(liTemplate)); // TO DO: replace with replaceProperty var dbParams = self.replaceItems(liTemplate, item, 'item') || ''; // var dbParams = self.replaceProperties(liTemplate, undefined, item) || ''; // -> TO DO container = self.elementToSelector(element); var container = element.getAttribute('data-selector'); self.li(dbParams, { selector: container }); } //} else if ( $(element).is('span') || $(element).is('p')) { } else if (element.tagName == 'SPAN' || element.tagName == 'P') { //$(element).text(firebaseValue); element.textContent = firebaseValue; } else if (element.tagName == 'SVG') { // TODO without JQUERY //$(element).children('text').text(firebaseValue); } else { // se $(this) non è un ul //var dbObj = self.docElement(pathString); // se il percorso ha più nodi e il dato non è presente nel db locale, // va creato un oggetto vuoto per ogni nodo //var context = element.getAttribute('data-firebase'); //self.var.db[context] = newObj; // update local db if (template.blocks || template.html) { var blocksTemplate = template.html || template.blocks; //$(container).empty(); 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.log('container'); self.log(container); self.log('dbParams'); self.log(dbParams); */ self.html(dbParams, { selector: container }); } } if (template.init) self.do(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) { // No user logged in self.log('authStateChanged: GUEST\n'); // non bisognerebbe chiedere sempre di fare login } else { // User logged in self.log('authStateChanged: USER\n'); self.log('name: ' + self.user('displayName') + '\nemail: ' + user.email + '\nuid:' + user.uid); //self.log('email verificata'); //self.log(self.userVerified()); } /* self.log('params'); self.log(params); */ //self.do(params.onAuthStateChanged); self.do(params.onAuthStateChanged); //if (!firebaseInitialized) { // firebaseInitialized = true; //self.do(data); //} }); }, sendEmailVerification: function (params, container, args) { self.sendEmailVerification(params); }, login: function (params, container, args) { self.log('params.auth'); self.log(params.auth); // QUESTO E' {var:auth} MA SEMBRA NON RIMPIAZZARLO self.log(args); // QUI MI RIPORTA LA PWD, ma perché ultimo 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.replaceTags({text: params.auth, args: args}); //var fbAuth = self.replaceResult(params.auth, args); var fbAuth = self.replaceProperties(params.auth, args); fbAuth.success = params.success; fbAuth.error = params.error; //alert(JSON.stringify(fbAuth)) self.firebaseRegister(fbAuth, params.success, params.error); }, updateProfile: function (params, container, args) { //params.profile = self.replaceTags({text: params.profile, args: args}); //params.profile = self.replaceResult(params.profile, args); params.profile = self.replaceProperties(params.profile, args); self.firebaseUpdateProfile(params.profile, params.success, params.error); }, passwordReset: function (params, container, args) { //params.email = self.replaceTags({text: params.email, args: args}); //params.email = self.replaceResult(params.email, args); params.email = self.replaceProperties(params.email, args); self.firebasePasswordReset(params.email, params.success, params.error); }, logout: function (params, container, args) { self.firebaseLogout(params); } }, // should go in mobile.json module thunkable: function (params, container, args) { self.thunkable(params, args); }, // should go in 3d.json module 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] = {}; // use self.element //let events = ['load', 'preload']; //for (var event in events) { var event = 'load'; if (params[event]) { //self.element({root: 'self.methods.modelViewer.events', path: container+'.'+event, value: 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]); 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; } } } }; this.googleSignInPopup = function () { self.log('googleSignInPopup'); var provider = new firebase.auth.GoogleAuthProvider(); firebase.auth().useDeviceLanguage(); // lingua del dispositivo firebase.auth() .signInWithPopup(provider) .then((result) => { // @type {firebase.auth.OAuthCredential} var credential = result.credential; // This gives you a Google Access Token. You can use it to access the Google API. var token = credential.accessToken; // The signed-in user info. var user = result.user; window.location.reload(); // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; var errorMessage = error.message; // The email of the user's account used. var email = error.email; // The firebase.auth.AuthCredential type that was used. var credential = error.credential; }); }; /* this.googleSignInPopup = function () { // [START auth_google_signin_popup] self.log('googleSignInPopup'); var provider = new firebase.auth.GoogleAuthProvider(); //provider.addScope('https://www.googleapis.com/auth/contacts.readonly'); //check security //provider.addScope('https://www.googleapis.com/auth/calendar'); //var languageApp = jsonic.var.language || 'en'; //firebase.auth().languageCode = 'it';//languageApp; //self.log(provider); //return; firebase.auth() .signInWithPopup(provider) .then((result) => { // @type {firebase.auth.OAuthCredential} var credential = result.credential; // This gives you a Google Access Token. You can use it to access the Google API. var token = credential.accessToken; // The signed-in user info. var user = result.user; //######### result ########// self.log("credential"); self.log(credential); self.log("token"); self.log(token); self.log("user"); self.log(user); window.location.reload(); // ... }).catch((error) => { // Handle Errors here. var errorCode = error.code; self.log('errorCode'); self.log(errorCode); var errorMessage = error.message; self.log('errorMessage'); self.log(errorMessage); // The email of the user's account used. var email = error.email; self.log('email'); self.log(email); // The firebase.auth.AuthCredential type that was used. var credential = error.credential; self.log('credential'); self.log(credential); // ... }); // [END auth_google_signin_popup] } */ /* this.auth = function (params, args) { self.log('auth'); self.log(params); if (params.do == 'init') { auth = firebase.auth(); auth.onAuthStateChanged(user => { self.json.var.user = user; if (!user) { // No user logged in self.log('authStateChanged: GUEST\n'); // non bisognerebbe chiedere sempre di fare login } else { // User logged in self.log('authStateChanged: USER\n'); self.log('name: '+self.user('displayName') + '\nemail: '+user.email + '\nuid:'+ user.uid); //self.log('email verificata'); //self.log(self.userVerified()); } //self.log('params.onAuthStateChanged'); //self.log(params.onAuthStateChanged); self.do(params.onAuthStateChanged); //if (!firebaseInitialized) { // firebaseInitialized = true; //self.do(data); //} }); } else if (params.do == 'sendEmailVerification') { self.sendEmailVerification(params); } else if (params.do == 'login') { self.log('params.auth'); self.log(params.auth); 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); } else if (params.do == 'register') { //var fbAuth = self.replaceTags({text: params.auth, args: args}); //var fbAuth = self.replaceResult(params.auth, args); var fbAuth = self.replaceProperties(params.auth, args); fbAuth.success = params.success; fbAuth.error = params.error; //alert(JSON.stringify(fbAuth)) self.firebaseRegister(fbAuth, params.success, params.error); } else if (params.do == 'updateProfile') { //params.profile = self.replaceTags({text: params.profile, args: args}); //params.profile = self.replaceResult(params.profile, args); params.profile = self.replaceProperties(params.profile, args); self.firebaseUpdateProfile(params.profile, params.success, params.error); } else if (params.do == 'passwordReset') { //params.email = self.replaceTags({text: params.email, args: args}); //params.email = self.replaceResult(params.email, args); params.email = self.replaceProperties(params.email, args); self.firebasePasswordReset(params.email, params.success, params.error); } else if (params.do == 'logout') { self.firebaseLogout(params); } // else //self.database(params, args); } */ /* this.db = function (params, args) { if (typeof params == 'string') return self.db(params, args); else self.firebase(params, args); } */ this.console = function (params, args) { //value = self.replaceProperties(params); //console.log('JSONIC: '+value, 'color:pink'); 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)); } }; 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.actionResult(params.value, 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); // TO DO: return? } } } }; 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)); //var varValue = self.docElement('self.json.var.db.'+name); return self.var('db.' + paramsReplaced, args); // to do: change with self.element({path: 'db.'+paramsReplaced}}) /* // questa versione non funzionava. vuol dire che this.var ha un errore nel caso di oggetto return self.var({ name: 'db.'+paramsReplaced }, args); */ } /* else { return self.actionResult(params, args); } */ }; this.firebase = function (params, args) { if (params.initializeApp) { var firebaseConfig = self.replaceProperties(params.initializeApp); firebase.initializeApp(firebaseConfig); } else { self.database(params, args); } }; this.database = function (params, args) { //console.log('database'); 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); // local db } else { if (params) { if (params.path) { params.path = self.path(params.path, args); } /* console.log('params.path'); console.log(params.path); */ /* if (params.value) params.value = params.value; */ //self.value({string: params.value}); if (params.value) { /* self.log("params.value pre replace"); self.log(params.value); */ //params.value = self.replaceTags({text: params.value, args: args}); //params.value = self.replaceResult(params.value, args); //params.value = self.replaceProperties(params.value, args); //params.value = self.actionResult(params.value, args); params.value = self.replaceProperties(params.value, args); self.log("params.value post replace"); self.log(params.value); } /* self.log('params to FIREBASE'); self.log(params); */ // params.value = "${var.newDevice}" //var newDevice = `${params.value}`; //var newDevice = `${var.newDevice}`; 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); //if (params.on && params.on.success) self.do(params.on.success, result); } else { self.log('firebase get no result.data ERROR'); //if (params.on && params.on.error) self.do(params.on.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, result); if (params.on && params.on.error) self.do(params.on.error, undefined, result); // alert errore di connessione. alert riprova } }); } 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); //if (params.on && params.on.success) self.do(params.on.success, result); } else { self.log('firebase set ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); //if (params.on && params.on.error) self.do(params.on.error, result); // alert errore di connessione. alert riprova } }); } 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, result); 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); //if (params.on && params.on.success) self.do(params.on.success, result); // alert errore di connessione. alert riprova } }); } else if (params.do == 'addListener') { self.firebaseAddListener(params); } else if (params.do == 'removeListener') { self.firebaseRemoveListener(params); } else if (params.do == 'update') { if (params.value) { // 'set' is the default action with 'value' param 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); //if (params.on && params.on.success) self.do(params.on.success, result); } else { self.log('firebase update ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); //if (params.on && params.on.error) self.do(params.on.error, result); // alert errore di connessione. alert riprova } }); } else { self.log('data update requires value param'); } } else if (params.do == 'push') { if (params.value) { // 'set' is the default action with 'value' param 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); //if (params.on && params.on.success) self.do(params.on.success,result); } else { self.log('firebase push ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); //if (params.on && params.on.error) self.do(params.on.error, result); // alert errore di connessione. alert riprova } }); } else { self.log('data push requires value param'); } } else { if (params.value) { // 'set' is the default action with 'value' param 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); //if (params.on && params.on.success) self.do(params.on.success,result); } else { self.log('firebase set ERROR'); if (params.on && params.on.error) self.do(params.on.error, undefined, result); //if (params.on && params.on.error) self.do(params.on.error, result); // alert errore di connessione. alert riprova } }); } } } } } else { self.log('"database" function needs to be initialised'); } } }; this.ajax = function (params, selectorParams, args) { /* self.log('ajax'); // TO DO: selectorParams self.log('ajax'); self.log('params'); self.log(params); self.log('args'); self.log(args); */ if (params.url) { //var url = self.compile(params.url, args); var url = self.replaceProperties(params.url, args); var data; if (params.data) data = JSON.stringify(self.replaceProperties(params.data, args)); //data = JSON.stringify(self.compile(params.data, args)); /* self.log('data'); self.log(data); */ var type = params.type || 'POST'; var request = new XMLHttpRequest(); request.open(type, url, true); //request.setRequestHeader("Accept", "application/json"); //request.setRequestHeader('Content-Type', 'application/json'); /* request.onreadystatechange = function () { if (r.readyState != 4 || r.status != 200) return; alert("Success: " + r.responseText); } */ request.onload = function () { self.log('onload'); self.log(this); if (this.status >= 200 && this.status < 400) { // Success! var result = {}; //try { 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 */ this.openFullscreen = function (id) { var element = document.getElementById(id); if (screenfull.isEnabled) { screenfull.request(element); } }; /* this.addListener = function(params) { var selector = self.selector(params); if (selector) $(selector).on(params.event, self.do(params.action)); //event.stopPropagation(); } */ /* Close fullscreen */ this.closeFullscreen = function () { //document.exitFullscreen(); screenfull.off('change'); // callback }; /* 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++; } } } } */ 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); } }; /* 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)' }); } */ //------------------------ /* 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); } } } } } } */ /* 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); } } 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); } } 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); } 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; } } } this.removeTimedTask = function (data) { self.log('removeTimedTask'); if (data.frequence && data.task) { delete timedTasks[data.frequence][data.task]; } } 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"]'; this.closePanel = function(value) { self.log(value); switch (value) { case 'closePanelTools': $(toolsPanel).fadeOut(); $(previewPanel).fadeIn(); case 'closePanelFrame': $(devicePanel).fadeOut(); $(stagePanel).fadeIn(); } } */ //------------------------ // CSS METHODS //------------------------ /* 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; } */ /* 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 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 }); }); } }); }; /* 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); } } 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}); } } this.TweenMaxDuration = function (duration) { if (duration != undefined) {return Number(duration)/1000} else {return 0.667;} } */ // CSS CLASSES 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); }; 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 + '}'); }; this.findPlugin = function (name) { if (self.json.plugins) { for (var plugin of self.json.plugins) { if (plugin.name == name) return plugin; } } else { return false; } }; 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); }; /* this.createLoader = function (data) { // !--
      Loading...
      --> if (self.json.loader) $('.preloader img').attr('src', self.json.loader); self.do(data); } */ /* 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); } } */ /* 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); } */ /* 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} ] }); } */ /* 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` 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 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 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); }; */ this.hash = function (path, args) { self.log('hash'); var path = self.replaceProperties(path, args); self.log(path); window.location.hash = path; }; 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; }; 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); } */ }; /* 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 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) } } } } } function uniqueValue(obj, key, value) { let found = new Set() findValues(object, key, found) return found.size === 1 && found.has(value); } */ 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; }; 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 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 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 this.valueInJson = function (obj, string) { //return Boolean(JSON.stringify(obj).indexOf('"' + string + '":') >= 0) return Boolean(JSON.stringify(obj).match(new RegExp('\"?' + string + '\"?'))); // JSON5 compatible }; /* 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; } */ /* this.openPageFromUrl = function (data) { self.log('openPageFromUrl'); self.hashChangeEvent(); self.do(data); }; */ /* 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); } } */ /* 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 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); }; 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; }; 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 = {}; this.fileType = function (fileName) { return /(?:\.([^.]+))?$/.exec(fileName)[1]; }; 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); 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'); } }; /* 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); }); } */ 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); } }); }; /* 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 this.findUrl = function (array, url) { for (var item of array) { if (item.url == url) return true; } }; /* 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'); } } */ /* 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}); } */ 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://fonts.googleapis.com", 'link', 'preconnect')); //promises.push(loadPlugin("https://fonts.gstatic.com", 'link', 'preconnect')); 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 }); //promises.push(loadPlugin(url)); }); //self.log(filesToLoad); Promise.all(promises).then(function () { self.start(); }).catch(function (script) { self.log('Failed to load'); self.log(script); }); }; this.modulesList = function (modulesObj) { /* self.log('modulesList'); self.log('modulesObj'); self.log(modulesObj); */ var modulesList = []; if (modulesObj) { for (key in modulesObj) { var mod = self.replaceProperties(modulesObj[key]); modulesList = modulesList.concat(mod); } } return self.replaceProperties(modulesObj); }; this.loadModules = function () { //self.log('loadModules'); if (self.json.setup.modules) { var modules = self.replaceProperties(self.json.setup.modules); // replace {page:id} /* self.log('modules'); self.log(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 = {}; this.addModule = function (params) { if (!self.modules[params.name]) { var promises = []; //var ideModule = {name: 'ide', url: 'https://jsonic.io/app/modules/ide.json'}; promises.push(self.loadModule(params)); Promise.all(promises).then(function () { if (!self.moduleExecuted[params.name]) { //self.log('all modules loaded'); var module = self.modules[params.name]; if (module.html) { self.moduleExecuted[params.name] = true; self.html(module.html); // TO DO: add also on, funcions ... } } if (params.success) self.do(params.success); //self.do(params.success); }).catch(function (file) { self.log('Failed to load'); self.log(file); if (params.error) self.do(params.error); //self.do(params.error); }); } else { if (params.success) self.do(params.success); //self.do(params.success); } }; this.loadModuleGlobal = function () { self.log('loadModuleGlobal'); var promises = []; var modules = []; // we need it to keep the order of the modules given in the config for (let key in self.json.setup.modules) { var mod = self.replaceProperties(self.json.setup.modules[key]); modules = modules.concat(self.cloneObject(mod)); } /* self.log('modules'); self.log(modules); */ for (let mod of modules) promises.push(self.loadModule(mod)); //var pageModule = {name: 'global', url: '/app/modules/global.json'}; //var ideModule = {name: 'ide', url: '/app/modules/ide.json'}; //promises.push(self.loadModule(ideModule)); // if admin Promise.all(promises).then(function () { //self.log('page module loaded'); //if (self.json.modules) { //self.json.setup.modules = self.cloneObject(self.json.modules); // required modules //self.json.setup.modules.app.push(pageModule); // page module //self.json.setup.modules.app.push(ideModule); // ide module if admin self.loadModules(); //} }).catch(function (file) { self.log('Failed to load'); self.log(file); }); }; /* this.extendJsonFromModules = function () { self.log('extendJsonFromModules'); for (var mod in self.modules) { //self.extendJsonFromElement(self.modules[mod.name]); self.extendJson(json, self.modules[mod]); } } */ /* DA SISTEMARE - TEMPORANEO */ this.code = function (params, selectorParams) { /* self.log("params"); self.log(params); self.log("selectorParams"); self.log(selectorParams); */ let container = self.selector(params.selector || params.container) || self.selector(selectorParams); //var container = self.selector(params) || self.selector(selectorParams); self.log("this.code"); self.log("container"); self.log(container); var editorContainer = container.slice(1); //if (editorContainer.startsWith('#')) {editorContainer.slice(1);} // remove # var editor = ace.edit(editorContainer); var value = params.value; // else value = params; if (!params.do || (params.do == 'set')) { //var langTools = ace.require('ace/ext/language_tools'); if (params.theme) editor.setTheme(params.theme); // "ace/theme/monokai" var editorMode = params.mode || "ace/mode/json"; editor.getSession().setMode(editorMode); var editorStyle = self.extend({ background: "rgba(255,255,255,0)" }, params.style); //$(container).css(editorStyle); //editor.container.style /* self.css({ style: editorStyle }, { container: container }); */ // Eventualmente var codeOptions = self.extend({ fontSize: "11pt", selectionStyle: "line", highlightActiveLine: false, wrap: true, showLineNumbers: false, showGutter: false, fixedWidthGutter: false, readOnly: true, //enableBasicAutocompletion: false, //enableSnippets: false, //enableLiveAutocompletion: false, }, params.options); // https://github.com/ajaxorg/ace/wiki/Configuring-Ace editor.setOptions(codeOptions); var codeString; if (typeof value == 'string') if (editorMode == "ace/mode/json") codeString = JSON.stringify(JSON.parse(value), null, '\t'); // json formatting 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; // $(container).css({ // height: Number(21 * codeRows) + 'px' // }); /* self.css({ style: { height: Number(21*codeRows)+"px" } }, { container: container }); */ // Eventualmente editor.setValue(codeString, -1); } else if (params.do == 'get') { return editor.getValue(); } else { self.log('"code" function requires value param'); } }; this.init = function (appString, modulesString) { console.log('init'); // app(String: app url) (Object = json app) // modules(String): modules "ui,daisyui,svg" /* json = { // the jsonic app tree blocks: {}, parts: {}, css: {}, do: {}, on: {}, texts: {}, data: {}, var: {} }; */ //self.app = self.getParams(); // from url 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); /* // TO DO: remove the requirement of resources.json if (!self.json.setup || !self.json.setup.modules) { self.json.setup = { "modules": [ { "name": "resources", "url": "https://jsonic.io/app/modules/lib/resources.json" } ] } } */ if (appString.css) self.defineCss(appString.css); // can be removed? } self.loadModuleGlobal(); }; 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; } this.htmlToJson = function (text) { let xmlDoc = new DOMParser().parseFromString(text, "text/xml"); return JSON.stringify(toJsonNode(xmlDoc), null, "\t"); }; this.elementToJson = function (selector) { let el = document.querySelector(selector); return self.htmlToJson(el.getHTML()); }; function clearSelection() { if (window.getSelection) { window.getSelection().removeAllRanges(); } else if (document.selection) { document.selection.empty(); } } this.importHtml = function (htmlText) { // use modal and monaco js 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.innerHTML = ''; document.body.appendChild(textarea); //document.execCommand("copy"); textarea.addEventListener('click', function () { textarea.remove(); navigator.clipboard.writeText(textarea.value).then(() => console.log('copied!')); }); //console.log(JSON.parse(jsonDoc)); } }; // https://github.com/ktskts/html2json/blob/master/src/html2json.js /* var Util = { div : null, attrs: "id,name,style,class,value,src,href,width,height,title,type".split(","), getJson: function(childNodes, attrs, length) { var result = []; for ( var i = 0, len = childNodes.length; i < len; i++) { var item = childNodes[i]; if (item.nodeType == 3) { // textual content in an element or attribute result.push({ text : item.nodeValue }) } else if (item.nodeType == 1) { // element var obj = { //tag : item.nodeName.toLowerCase(), attr : {} }; var flag = false; //for ie6 if (attrs) { for (var j = 0; j < length; j++){ if (attrs[j] == 'style'){ var sStyle = item.getAttribute('style').cssText; if(sStyle){ obj.attr["style"] = sStyle; flag = true; } } else { var attrNode = item.attributes[attrs[j]]; if(attrNode && attrNode.nodeType === 2){ var value = attrNode.value; if(value && value != 'null'){ obj.attr[attrs[j]] = value; flag = true; } } } } } else { if (item.attributes.length) { for ( var n = 0, l = item.attributes.length; n < l; n++) { var value = item.attributes[n].value; if(value){ flag = true; obj.attr[item.attributes[n].name] = value; } } } } let nodeOut = {}; let nodeTag = item.nodeName.toLowerCase(); let nodeChild = Util.getJson(item.childNodes, attrs, length); nodeOut[nodeTag] = {}; self.log( 'item.childNodes'); self.log( item.childNodes); self.log( 'nodeChild'); self.log( nodeChild); //self.log( item.textContent); nodeOut[nodeTag].html = nodeChild; if (flag) nodeOut[nodeTag].attr = obj.attr; result.push(nodeOut); } else { // do nothing } } if (result.length == 1) return result[0] else if (result.length > 1) return result; } } this.html2json = function(text) { if (!Util.div) Util.div = document.createElement('div'); Util.div.innerHTML = text; return {html: Util.getJson(Util.div.childNodes)}; }; */ /* var jsonicOptions = self.extend({ }, options); */ if (typeof options == 'object') { } else if (options) self.init(arguments[0], arguments[1]); } // of jsonicObject //var jsonicApp = jsonApp; var jsonApp = new jsonAppObj(); var js = jsonApp; var jsonic = jsonApp; //window.jsonic = new jsonicObject(); /* var receiveMessage = function (process) { if (ThunkableWebviewerExtension) ThunkableWebviewerExtension.receiveMessage(process); } var postMessage = function (message) { if (ThunkableWebviewerExtension) ThunkableWebviewerExtension.postMessage(message); } */ /* "on": { "init": [ { "thunkable": { "postMessage": "Hi Rick!" } }, { "thunkable": { "receiveMessage": { "alert": "message: {result}" } } } ] } */