diff --git "a/Icon\r" "b/Icon\r"
new file mode 100644
index 0000000..e69de29
diff --git a/app.css b/app.css
index 330b9d6..994e2c6 100644
--- a/app.css
+++ b/app.css
@@ -1,3 +1,7 @@
+.columnVisibility:last-child {
+ display: none;
+}
+
/* FONT */
/* latin */
diff --git a/app.html b/app.html
index c227324..803a221 100644
--- a/app.html
+++ b/app.html
@@ -16,7 +16,7 @@
-
+
--> */
+ 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}"
+ }
+ }
+ }
+ ]
+}
+ */
diff --git a/jsonic/js/jsonic.1.0.13.js b/jsonic/js/jsonic.1.0.13.js
new file mode 100644
index 0000000..d321526
--- /dev/null
+++ b/jsonic/js/jsonic.1.0.13.js
@@ -0,0 +1,16029 @@
+/*-----------------------------
+ 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(/\\{function:([^\}]*)\}\>?/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+''+p1+'>';
+ 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+'">'+params.tag+'>');
+ 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 = ' ';
+ //
+ //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) {
+ // !---->
+
+ 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}"
+ }
+ }
+ }
+ ]
+}
+ */
diff --git a/jsonic/js/jsonic-1.0.14.js b/jsonic/js/jsonic.1.0.14.js
similarity index 100%
rename from jsonic/js/jsonic-1.0.14.js
rename to jsonic/js/jsonic.1.0.14.js
diff --git "a/jsonic/modules/Icon\r" "b/jsonic/modules/Icon\r"
new file mode 100644
index 0000000..e69de29
diff --git "a/jsonic/plugins/Icon\r" "b/jsonic/plugins/Icon\r"
new file mode 100644
index 0000000..e69de29
diff --git a/uploads/.DS_Store b/uploads/.DS_Store
deleted file mode 100644
index 662daaf..0000000
Binary files a/uploads/.DS_Store and /dev/null differ
diff --git "a/uploads/Icon\r" "b/uploads/Icon\r"
new file mode 100644
index 0000000..e69de29
diff --git "a/uploads/plans/Icon\r" "b/uploads/plans/Icon\r"
new file mode 100644
index 0000000..e69de29