Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 

16030 строки
659 KiB

  1. /*-----------------------------
  2. JSONIC V. 1.0.13
  3. jsonic.io
  4. -------------------------------*/
  5. // CHANGELOG
  6. // 1.0.13 jsonApp removed; [replaceProperties: include event properties]
  7. // 1.0.12 jsonApp; if is array option
  8. // 1.0.11 block blocks -> parts
  9. // 1.0.10 for: {name} work also with {value:name with path} (function replaceValue)
  10. // 1.0.8 for: {name} replaced with {value:name}
  11. // 1.0.5 set: if array of, the assignments follow the order
  12. // 1.0.4 deprecated: to assign without set (too ambiguous now that the key can be function, window.function, etc)
  13. // 1.0.3 "x": "2*3" if the value is a string, -> self.js(value)
  14. // 1.0.2 plugins ondemand
  15. // 1.0.1 jsonc support
  16. // 1.0.0 FUNCTIONS
  17. // 0.9.9 RESOURCES: Inside modules (resources will be deprecated)
  18. // 0.9.3 DEBUG: Rimosso break in docElement
  19. // 0.9.4 NOTE: In this.nested, commented and decommented nested.animate = partObj.animate; nested.if partObj.if, ...
  20. // 0.9.5 CLASS: "div btn": "content" = <div class="btn">content</div>
  21. // 0.9.6 DEBUG: in this.createElement newSelector (newSelector should be a dedicated function separated from selector)
  22. // 0.9.7 REMOVE: method to remove an element from the DOM / Restored html {attr} to set the attributes of an element
  23. // https://minify-js.com Input: 624.1 kB; Output: 95.46 kB; Compression: 84.7%, saving: 528.64 kB;
  24. // README
  25. // PRIORITY
  26. // in attr -> addStyle / removeStyle
  27. // instead of shortcuts the user can use {data shortcuts}
  28. // {arguments:value|default} -> ({arguments:value}) ? {arguments:value} : default
  29. // use (typeof id == "undefined") to understand if id is defined and is = 0
  30. // css should call defineCss in any part of code
  31. // attr (addClass, removeClass, changeStyle direct methods?) can be changed (in element?) to avoid confusion with the use inside html
  32. // add remove element from array
  33. // debug of "set" key
  34. // can be useful to define pointers (shortcode/path of the objects)
  35. // https://dev.to/ternentdotdev/json-compression-in-the-browser-with-gzip-and-the-compression-streams-api-4135
  36. // a method to append an image to the DOM in base64 format <image xlink:href="data:image/png;base64,...
  37. // after (ms) can be a standard parameter (like selector) very useful
  38. // BUG: if {arguments:id} is undefined gives "undefined"
  39. // try to replace Snap.load with fetch
  40. // selctor, if string, should return querySelectorAll
  41. // find element.getAttribute('data-selector') and replace with self.elementToSelector(value). Then change queryAll
  42. // // it let to select more than one element cardColorDark
  43. // in self.pluginsLoadedQueue add the actions to do when the plugin is loaded
  44. // notUndefined può essere migliorato per "if" e per considerare vera la stringa se presente (ma va considerato '0' e 0)
  45. // for name=i, if i is an object, can use {i:node1} but not {i:node1.node2}ì. Workaround is to assign i to a var
  46. // so a possible solution is to use "var" parameter
  47. // functions (js like) -> methods? no
  48. // check this.html notes
  49. // anime can be a part/block/key function? called with "ui:anime" asking for the relative plugin?
  50. // if the name of the block/part includes ":" it is more explicit
  51. // blocks or parts or keys or nodes?
  52. // parts -> blocks considering jsblocks.com?
  53. // Dynamic modules loading? What if we ask for a node that is in the main modules?
  54. // remove console from methods and add log in browser functions
  55. // add log of the error if the app or json module is not in json format
  56. // init, run, start -> do
  57. // if selector is an array, repeat the action (do)
  58. // think about html/do. Is it possible to avoid html object? Any unknown object is an html tag
  59. // in parts, {setup:on.success} or {setup:config.color} doesn't work
  60. // setup -> arguments
  61. // part ui:icon: {selector:, config:} can be a js function () {var part = {}; self.run(config); }
  62. // {arguments[0] arguments[1]. {1.setup} }
  63. // improve shortcuts (in extendJsonFromElement and in attr)
  64. // this.text -> this.content
  65. // html attribute of html method -> content (should be an html but can be multilingual)
  66. // property validation like the sintax (\w[\w+d+]) of the "name" in the "for" method )
  67. // default "html" al posto di "text": ogni contenuto testuale viene inserito con innerHTML anziché innerTEXT
  68. // html [] tipo array e "" stringa (innerHTML) ok, html {} deprecato
  69. // "p": "text" -> p.innerTHTML('text')
  70. // "p": [] -> se item è oggetto -> htmlTag, se stringa dovrebbe fare append della stringa html sempre nello p. Ora invece crea più p.innerText
  71. // ADD: append. empty true fixed on html
  72. /*
  73. 1 page -> url (method and property)
  74. 2 dynamic class with ternary condition
  75. 3 swal button style
  76. 4 components copy bugs
  77. 5 installation guide
  78. 6 self.page -> not the variable but the real window path and window hash (can be jsonic.url)
  79. 7 page -> url
  80. 8 "roles" -> "only"
  81. 9 add localStorage actions -> ANY WINDOW method
  82. 10 add dataStorage
  83. 10 in parts {string} instead of {value} ?
  84. 11 on load image solution (should already work on: load -> animate -> fadein)
  85. */
  86. // BUGS
  87. // BUG from Tailwind 3.3.2
  88. // Sembra richiesto tailwind nel plugin Jsonic e non caricato dinamicamente come su eliokit.com
  89. // Different rendering width or without spaces after commans "alert": " {js:(1 == 2) ? \"test\" : \"false condition\"} "
  90. // HOW IT WORKS
  91. // loadModules -> loadPlugins -> Run
  92. // KNOWN BUGS
  93. // in museomira.it cerca "socialIcons", rimuovendo data-value l'icona finisce dentro contatti perché il newSelector è a:eq(5)
  94. // è necesario creare una funzione selector destinata ai nuovi elementi
  95. // PARTS
  96. // 1. Responsive header menu
  97. // 2. Alert
  98. // 3. Slide
  99. // 4. Form
  100. // 5. Table
  101. // GOAL
  102. // Reduce custom js code in Jsonic and move the functions in modules
  103. // Requires an extension of js method to make it more flexible
  104. // js {function: String, params: Array}
  105. // TO DO
  106. // inline use: data-jsonic -> jsonic.run(data-jsonic, selector); (es. in body)
  107. // init = run (or play)
  108. // in parts {setup} should get subreferences link {setup:on.success}
  109. // i plugins possono includere direttamente l'url
  110. // la gestione dei plugin dovrebbe essere centralizzata (riferimento a jsonic e non all'oggetto)
  111. // si potrebbe definire la distinsione tra oggetti specifici e oggetti globali (jsonic)
  112. // verificare se oggetto function con {name: , params: []} è assegnabile a variabili
  113. // addClass, removeClass etc with array
  114. // change the behaviour of p: [] become a a list of content, not a list of p
  115. // to do it, search and change "div": [ "p": [ "span": [ "li": [ "button": [
  116. // hypothesis (no, more complete with actions): class="ui:button{text:#333;bg:#fff}" -> bg-[white] text-[#333] hover:bg-[#fff] hover:text-[white]
  117. // OPTIMIZATION: pluginsRequiredByTag only for self.json.resources.pluginsFunctions keys or better only for parts that requires plugins. alert -> ui:alert
  118. // getJSON: load json (id: exampleApp, url: ...), success-> {getJSON:exampleApp}
  119. // Ajax: load ajax (id: exampleApp, url: ...), success-> {ajax:exampleApp}
  120. // DOM: queryAll(selector) -> value is string, el.before(value) and all the other methods of an element of the dom
  121. // properties {dom:title}
  122. // https://www.w3schools.com/jsref/dom_obj_all.asp
  123. // DOCUMENT
  124. // https://www.w3schools.com/jsref/dom_obj_document.asp
  125. // {document: {title: 'test'}}
  126. // properties {document:title}
  127. // ON: https://www.w3schools.com/jsref/dom_obj_event.asp
  128. // "selector" can be "query" / no selector recalls querySelector
  129. // or APPEND/PREPEND
  130. // https://registry.npmjs.com/-/v1/search?text=tailwindcss&size=1
  131. //https://api.npms.io/v2/package/tailwindcss
  132. // https://api-docs.npms.io
  133. /*
  134. TO DO
  135. 1. ajax call with an id to identify the data in case of simultaneous requests
  136. 1. database path should be separated by spaces (or slashes)
  137. replaceProperties default:
  138. check if
  139. if p1 is a function, if p2 -> value = p1(p2), if p3 -> value = p1(p2(p3))
  140. if p1 is a value, and not p2, value = p1
  141. self.methods[p1] or...
  142. p1 is a function
  143. {alert:string}
  144. {window.f}
  145. {window f1:window f2:window x} = window.f1(window.f2(window.x))
  146. {querySelector:'.class':append} = window.f(jsonic.json.var.x)
  147. ESEMPI
  148. {new Date:'December 17, 1995 03:24:00'}
  149. {new Date().getDay}
  150. {console.log:'test'}
  151. {window.innerHeight} invece di {window:innerHeight} (specifica) o {js:window.innerHeight}
  152. il vantaggio di questo schema è che si evita un livello di parentesi annidate
  153. quando sono coinvolte variabili jsonic:
  154. {querySelector:var obj x:append}
  155. che puo diventare
  156. {querySelector:var {item} x:append}
  157. LIMITE
  158. questo metodo preclude l'accesso ad eventuali oggetti javascript var o data
  159. SOLUZIONE
  160. in realtà, var e data devono essere elementi definiti nel json
  161. altrimenti non sono trovati dall'interprete che può vagliare l'esistenza
  162. di una funzione js
  163. {path to a data} is a reference to a value in the data node of the Jsonic app
  164. if the action context (do)
  165. {path to an action} is a reference to a method or a sub app in the "parts" node of the Jsonic app
  166. if the html rendering context (html)
  167. {window.f:var x} = window.f(jsonic.json.var.x)
  168. {window.f:num} if is number
  169. {window.f:array} if isArray (more than one parameter)
  170. {window.f:'string'}
  171. {jsonic.f:var x}
  172. do: [
  173. "functionName": [] // parameters
  174. ]
  175. check if functionName is a function
  176. html tags can't have a space or points...
  177. Align with ELIO Language:
  178. 1. "if": {"is": ["a", "=", "b","and"...] (retrocompatibile: se is è un array...)
  179. 2. "set": ["a", "+=", "1","*", "3"...] (retrocompatibile: se set è un array...)
  180. 3. "div classes": ...
  181. CODE REDUCING
  182. 1. string in "html" object that starts with a tag and continue with classes
  183. "html": [
  184. "span appsDeviceListName ms-2 me-2 text-[16px] text-left w-[80%] leading-tight|content"
  185. ]
  186. NOTES
  187. // datapicker and other input fiels now are native https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date
  188. COMPONENTS
  189. MONACO TAILWINDCSS AUTOCOMPLETE (check Tailwindcss VS Code extensions)
  190. https://github.com/remcohaszing/monaco-tailwindcss
  191. FIREBASE STRUCTURE DATA
  192. 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.
  193. 24.4KB gzipped (85.24KB minified)
  194. 25.2KB minified + gzipped in 100ms
  195. 65ms 3G 3 Mbps (375 KBs)
  196. 10ms 4G 20 Mbps (2,5 MBs)
  197. <1ms 5G/Fiber 200 Mbps (25 MBs)
  198. TEST
  199. tailwindcss
  200. 104 KB 105 ms
  201. INTEGRATIONS:
  202. https://b2bsaasleads.com
  203. NEW PLUGINS:
  204. http://jakim.me/Toasty.js/
  205. https://tingle.robinparisi.com
  206. GUIDE:
  207. COMPONENTS: reusable components / architectural philosophy
  208. ENGINE, (no hidden code) all the parts of the app is exposed to the developer / can set the layout and the behaviour
  209. JSON E' il modello di struttura ad albero usato da JSONIC per descrivere i dati, lo stile, e le azioni dell'applicazione
  210. SHORTCUTS: combinations of utility names (classes) to reuse in "class" property (from WindiCSS)
  211. // preloaded js/css plugins
  212. {
  213. "attr": {
  214. "class": "py-2 text-center"
  215. },
  216. "subTitle": {
  217. "lang": {
  218. "it": "L'albero JSON dell'app può contenere i seguenti rami principali:",
  219. "en": "The JSON app tree may contain the following main branches:",
  220. "es": "El árbol de la aplicación JSON puede contener los siguientes ramas principales:"
  221. }
  222. }
  223. },
  224. PROPERTIES
  225. With {property}, a string delimited by braces you can refer to any sub-branch the app tree and special properties.
  226. -----------------------
  227. HOME PARAGRAPHS
  228. -----------------------
  229. AUTO-LOADED PLUGINS
  230. NESTED CSS
  231. 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
  232. // BP
  233. Questo dimostra che c'è bisogno di semplificazione più di quanto non si possa pensare
  234. IDE
  235. Special char (or shortener or autocomplete) with &lbrace; &rbrace; etcetera)
  236. PRIORITY:
  237. tags:
  238. button: "title"
  239. or
  240. button: {
  241. text: title
  242. color: color
  243. on: ...
  244. }
  245. buttonOutline: {
  246. text: title
  247. color: color
  248. on: ...
  249. }
  250. ------------------------
  251. qualunque metodo:
  252. [
  253. {"path": args},
  254. {"path": args}
  255. {"path": args}
  256. ]
  257. ------------------------
  258. DEBUG
  259. class must be a string otherwise log error
  260. style in attr must work (now error)
  261. CONFIG (now setup)
  262. extend the main branch {b:config}
  263. ACTIONS (now parts)
  264. extend the main branch {b:actions}
  265. DO
  266. execute one or an array of functions
  267. "do": "actionID" (string) execute the actions.actionID function
  268. CONTAINER (now selector)
  269. change the context to the element {b:container}
  270. Can be an object like {id, class, data-value}
  271. or a string with a CSS selector like "body > div:nt-child(2)"
  272. or a jquery-like selector like "body > div:eq(2)"
  273. ------------------------
  274. bootstrap menu -> tailwind
  275. ------------------------
  276. IDEAS
  277. - share the modules in the object "jsonic" with the other jsonic objects in the page
  278. - jsonic.registerJsMethod(name, function) register new js method to be inserted in jsonic.methods and called with "method": {params}
  279. - choose can contain the methods "next":"1" / "previous":"1" or step "+1"/"-1"
  280. - calendar can return the object {lang: {...}}
  281. - self.js can be embedded in self.compile (if typeof params == 'string')
  282. - Page doesn't exist / if admin / want to create it?
  283. - if no jsonic file for the page, create it on save
  284. - AUTH (debug) + GITHUB
  285. - preload font flag
  286. - IDE: Wordpress API new page
  287. - window methods in (docs)
  288. - for -> addTag (?)
  289. - setup: form to set setup properties
  290. - Method ARRAY
  291. "array": {
  292. "push": "{var:num}" (pop, shift, unshift, length)
  293. DONE:
  294. remove JSONIC references: jsonic.firebaseEventAction / jsonic.resizeEvent
  295. - HOME: docs / examples / integrations
  296. - wordpress: access to media API
  297. - iconify
  298. - iconify remove SVG old
  299. - colors -> setup (mmm) (like logo)
  300. - styles -> css -> senza categorie, solo elements '#div' -> https://transform.tools/css-to-js DONE
  301. }
  302. BUGS:
  303. - version è necessario in pluginsFunctions
  304. - shortcut as a node: attr / class values doesn't overwrite the shortcut
  305. WORDPRESS:
  306. (_embed to your URL will add the wp:featuremedia)
  307. https://jsonic.io/wp-json/wp/v2/media?&context=embed&per_page=100
  308. https://jsonic.io/wp-json/wp/v2/media?&context=embed&after=2017-11-07T00:00:00
  309. https://jsonic.io/wp-json/wp/v2/media?include=1681,491
  310. // https://github.com/schlosser/pig.js
  311. NOTE:
  312. - autoupdate only if the previous update is complete (we need a param in config complete:true/false)
  313. - Play (create your app!)
  314. - add a tag in menu buttons ?
  315. - inViewport -> 'enter'/'exit' ?
  316. - inViewport solo la prima volta?
  317. - ('on': 'in'/out NO) confirm 'init'?
  318. - IDE: backup timeline
  319. - duplicato di this.selector dedicata a ottenere il selector di un nuovo elemento (su append e poco altro)
  320. - col: [1,2,3] -> row with col1 col2 col3 ? or tailwind grid solution (ragionare su soluzione di tag. esempio: flex: [])
  321. - in examples, test in posizione assoluta sul codice (utile su mobile)
  322. KEY BENEFITS
  323. - Integration (Jsonic code includes the logic, the layout and the style of the app on in one JSON object)
  324. - Accelerator
  325. */
  326. // JQUERY to Vanilla: https://youmightnotneedjquery.com | http://vanilla-js.com
  327. // Jquery plus: https://atypiccraft.com/insights/reasons-why-we-still-use-jquery
  328. // https://cyrilletuzi.github.io/javascript-guides/jquery-to-javascript.html
  329. // Tools to integrate: https://bestofjs.org/tags
  330. // MINIFY: https://closure-compiler.appspot.com/home
  331. // https://api.giphy.com/v1/gifs/random?api_key=dc6zaTOxFJmzC&tag=cat
  332. // INTEGRATIONS
  333. // https://www.dropzone.dev/js/
  334. // uploadcare
  335. // zaiper
  336. // a graph js tool
  337. // anime.js
  338. // transition.style // analogo ad animate.style
  339. /* There were issues affecting this run of Lighthouse:
  340. 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.
  341. // UI
  342. https://windicss.org/play.html
  343. https://basscss.com
  344. https://twind.dev
  345. https://emotion.sh/docs/introduction
  346. https://cssinjs.org/?v=v10.8.2
  347. https://picturepan2.github.io/spectre/
  348. https://get.foundation
  349. https://ant.design/
  350. https://purecss.io
  351. https://onsen.io/
  352. https://shuffle.dev/
  353. */
  354. //{"type": "js", "url":"https://cdn.jsdelivr.net/npm/tailwindcss@{version}/lib/index.min.js"},
  355. //$.fn.jsonic = function(options) {return new jsonicObject(options);};
  356. //jsonicApp = function(options) {return new jsonicObject(options);};
  357. var jsonAppObj = function(options) {
  358. var self = this;
  359. console.log();
  360. //this.options = options;
  361. /* var json = { // the jsonic app tree
  362. setup: {},
  363. blocks: {}, // to be removed
  364. parts: {},
  365. // plugins: {}, // TO DO: remove the error if included
  366. // css: {},
  367. do: {},
  368. on: {},
  369. shortcuts: {},
  370. texts: {},
  371. data: {},
  372. var: {}
  373. }; */
  374. //var var = json.var;
  375. //this.setup = json.setup;
  376. // for external access
  377. this.json = {
  378. setup: {},
  379. blocks: {}, // to be removed
  380. parts: {},
  381. // plugins: {}, // TO DO: remove the error if included
  382. // css: {},
  383. functions: {},
  384. do: {},
  385. on: {},
  386. shortcuts: {},
  387. texts: {},
  388. data: {},
  389. var: {}
  390. };
  391. this.app = this.json;
  392. //var json = self.json; // TO DO: remove
  393. var alertObj = {};
  394. var alertValues = {};
  395. this.params = {}; // maybe can be removed
  396. 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'];
  397. // Source: https://www.w3schools.com/js/js_reserved.asp
  398. var nodes = {
  399. //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'],
  400. //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',
  401. //functionsWithContainer: ['for', 'editor', 'ace', 'code', 'qrcode', 'lottie', 'animate', 'html', 'hide', 'show', 'toggle', 'in', 'out', 'if', 'ajax', 'attr', 'run', 'delay'],
  402. // not execute
  403. extend: ['setup', 'blocks', 'parts', 'css', 'actions', 'texts', 'data', 'functions'], // also plugins? (TO DO: remove actions)
  404. params: ['style', 'on', 'matchMedia', 'action', 'code', 'roles', 'plugins', 'css'], // 'if', 'attr', 'text'. 'html'
  405. exclude: ['setup', 'container', 'selector', 'info', 'note', 'comment', 'lang', 'tag', 'plugins', 'template']
  406. };
  407. /*
  408. * Converts a JSON object to a JSON Schema
  409. * @param {any} json
  410. * @param {object} options
  411. * @returns {object} a json schema
  412. */
  413. // [{"name": "vito", "gallery": {"name":2, "date":"10-10-2012"}, "num":3, "bool":true, "color": "#ff0000"}]
  414. const FORMAT_REGEX = {
  415. email: /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/,
  416. url: /^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/,
  417. 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]?)$/,
  418. // J. Meijer / Stackoverflow / 15491894
  419. 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})$/,
  420. // Joey / Stackoverflow / 1636350
  421. color: /^#(?:[0-9a-fA-F]{3}){1,2}$|#(?:[0-9a-fA-F]{3,4}){1,2}$/,
  422. };
  423. this.jsonToSchema = function (json, options = {}) {
  424. // https://github.com/mohsen1/json-to-json-schema
  425. if (typeof json === 'function') {
  426. throw new TypeError('Can not convert a function');
  427. }
  428. if (json === undefined) {
  429. return {};
  430. }
  431. // primitives
  432. if (typeof json === 'string') {
  433. if (FORMAT_REGEX.url.test(json)) return { type: 'string', format: 'url' };
  434. else if (FORMAT_REGEX.email.test(json)) return { type: 'string', format: 'email' };
  435. else if (FORMAT_REGEX.ip.test(json)) return { type: 'string', format: 'ip' };
  436. else if (FORMAT_REGEX.date.test(json)) return { type: 'string', format: 'date' };
  437. else if (FORMAT_REGEX.color.test(json)) return { type: 'string', format: 'color' };
  438. else return { type: 'string' };
  439. }
  440. else if (typeof json === 'boolean') return { type: 'boolean' };
  441. else if (typeof json === 'number') {
  442. if (Number.isInteger(json)) {
  443. return { type: 'integer' };
  444. } else {
  445. return { type: 'number' };
  446. }
  447. }
  448. else if (Array.isArray(json)) {
  449. let schema = { type: 'array' };
  450. if (!json.length) {
  451. schema.items = {};
  452. return schema;
  453. }
  454. let schemas = json.map(self.jsonToSchema);
  455. // if all schemas are the same use that schema for items
  456. if (schemas.every(s => self.isEqual(s, schemas[0]))) {
  457. schema.items = schemas[0];
  458. // if there are multiple schemas use oneOf
  459. } else {
  460. schema.items = { oneOf: unique(schemas) };
  461. }
  462. return schema;
  463. }
  464. if (json === null) {
  465. return { type: 'null' };
  466. }
  467. let schema = { type: 'object' };
  468. if (!Object.keys(json).length) {
  469. return schema;
  470. }
  471. schema.properties = Object.keys(json).reduce((properties, key) => {
  472. properties[key] = self.jsonToSchema(json[key]);
  473. return properties;
  474. }, {});
  475. return schema;
  476. };
  477. this.isEqual = function (a, b) {
  478. return (JSON.stringify(a) == JSON.stringify(b));
  479. };
  480. //var canvasElement = document.getElementById("canvas");
  481. // * this is not important for PDFMake, it's here just to render the result *
  482. // It's a Mozilla lib called PDFjs that handles pdf rendering directly on the browser
  483. /* this.pdfjs = function (params, selectorParams) {
  484. var url = params.url;
  485. var options = params.options || { scale: 1.4 };
  486. let container = self.selector(params.selector || params.container) || self.selector(selectorParams);
  487. var canvasContainer = self.query(container);
  488. function renderPage(page) {
  489. var viewport = page.getViewport(options.scale);
  490. var wrapper = document.createElement("div");
  491. wrapper.className = "canvas-wrapper";
  492. var canvas = document.createElement('canvas');
  493. var ctx = canvas.getContext('2d');
  494. var renderContext = {
  495. canvasContext: ctx,
  496. viewport: viewport
  497. };
  498. canvas.height = viewport.height;
  499. canvas.width = viewport.width;
  500. wrapper.appendChild(canvas)
  501. canvasContainer.appendChild(wrapper);
  502. page.render(renderContext);
  503. }
  504. function renderPages(pdfDoc) {
  505. for(var num = 1; num <= pdfDoc.numPages; num++)
  506. pdfDoc.getPage(num).then(renderPage);
  507. }
  508. PDFJS.disableWorker = true;
  509. PDFJS.getDocument(url).then(renderPages);
  510. } */
  511. //renderPDF('https://raw.githubusercontent.com/mozilla/pdf.js/ba2edeae/examples/learning/helloworld.pdf', document.querySelector('#canvas'));
  512. /* this.localStorage = function (params) {
  513. // -> use self.method
  514. if (params.getItem) return localStorage.getItem(params.get);
  515. else if (params.setItem) return localStorage.setItem(params.setItem.name, params.setItem.value);
  516. } */
  517. // UTILITY
  518. /** A storage solution aimed at replacing jQuerys data function.
  519. * Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap].
  520. * This makes sure the data is garbage collected when the node is removed.
  521. */
  522. this.dataStorage = {
  523. _storage: new WeakMap(),
  524. set: function (element, key, obj) {
  525. if (!this._storage.has(element)) {
  526. this._storage.set(element, new Map());
  527. }
  528. this._storage.get(element).set(key, obj);
  529. },
  530. get: function (element, key) {
  531. return this._storage.get(element).get(key);
  532. },
  533. has: function (element, key) {
  534. return this._storage.has(element) && this._storage.get(element).has(key);
  535. },
  536. remove: function (element, key) {
  537. var ret = this._storage.get(element).delete(key);
  538. if (!this._storage.get(element).size === 0) {
  539. this._storage.delete(element);
  540. }
  541. return ret;
  542. }
  543. };
  544. // JQUERY cross-over
  545. this.extend = function (out) {
  546. if (typeof arguments[0] == 'boolean' && arguments[0] == true)
  547. return deepExtend(out);
  548. else {
  549. out = out || {};
  550. for (var i = 1; i < arguments.length; i++) {
  551. if (!arguments[i])
  552. continue;
  553. for (var key in arguments[i]) {
  554. if (arguments[i].hasOwnProperty(key))
  555. out[key] = arguments[i][key];
  556. }
  557. }
  558. return out;
  559. }
  560. };
  561. var deepExtend = function (out) {
  562. out = out || {};
  563. for (var i = 1; i < arguments.length; i++) {
  564. var obj = arguments[i];
  565. if (!obj) continue;
  566. for (var key in obj) {
  567. if (obj.hasOwnProperty(key)) {
  568. if (typeof obj[key] === "object" && obj[key] !== null) {
  569. if (obj[key] instanceof Array) out[key] = obj[key].slice(0);
  570. else out[key] = deepExtend(out[key], obj[key]);
  571. } else out[key] = obj[key];
  572. }
  573. }
  574. }
  575. return out;
  576. };
  577. /* this.actionResult = function(value, args) { // value -> params
  578. // Methods with a result
  579. if (value && typeof value == 'object') {
  580. // jsonic methods
  581. if (value.js) {
  582. return self.js(value.js, args);
  583. } else if (value.array) {
  584. return self.array(value.array, args);
  585. } else if (value.calendar) {
  586. return self.calendar(value.calendar, args);
  587. } else if (value.data) {
  588. return self.data(value.data, args);
  589. } else if (value.var) {
  590. return self.var(value.var, args);
  591. } else if (value.module) {
  592. return self.module(value.module, args);
  593. } else if (value.color) {
  594. return self.color(value.color, args);
  595. } else if (value.css) {
  596. return self.css(value.css, undefined, args);
  597. } else if (value.if) {
  598. return self.if(value.if, undefined, args);
  599. } else if (value.switch) {
  600. return self.switch(value.switch, args);
  601. } else if (value.database) {
  602. return self.database(value.database, args);
  603. // js methods
  604. } else if (value.Math) {
  605. return self.Math(value.Math, args);
  606. } else if (value.Number) {
  607. return self.Number(value.Number, args);
  608. } else if (value.String) {
  609. return self.String(value.String, args);
  610. // plugin methods
  611. } else if (value.ace) {
  612. return self.ace(value.ace, args);
  613. // else if (value.code) {
  614. // return self.code(value.code, args);
  615. } else if (value.moment) {
  616. return self.moment(value.moment, args);
  617. } else if (value.dayjs) {
  618. return self.dayjs(value.dayjs, args);
  619. } else if (value.function) { // TO DO: remove (replaced by do)
  620. return self.function(value.function, value.params);
  621. } else {
  622. return value;
  623. }
  624. } else {
  625. return value
  626. }
  627. //} else if (typeof value == 'string') {
  628. // return self.javascript(value, args);
  629. } */
  630. this.var = function (params, args) {
  631. if (Array.isArray(params)) {
  632. for (var index in params)
  633. self.var(params[index], args);
  634. } else {
  635. //self.log('var');
  636. var name;
  637. var value;
  638. var varValue;
  639. if (params.path && !params.name)
  640. name = self.path(params.path, args, '.');
  641. if (typeof params == 'string') {
  642. // gives a variable value
  643. name = self.replaceProperties(params, args);
  644. /* self.log('name');
  645. self.log(name); */
  646. /* self.log('typeof params == string');
  647. self.log('params');
  648. self.log(params);
  649. self.log('name');
  650. self.log(params); */
  651. varValue = self.docElement('self.json.var.' + name);
  652. /* self.log('varValue');
  653. self.log(varValue); */
  654. } else {
  655. /* self.log('var');
  656. self.log('params');
  657. self.log(params);
  658. self.log('args');
  659. self.log(args); */
  660. //self.log('params');
  661. //self.log(params);
  662. var paramsReplaced = self.replaceProperties(params, args);
  663. //self.log('paramsReplaced');
  664. //self.log(paramsReplaced);
  665. name = paramsReplaced.name;
  666. value = paramsReplaced.value;
  667. var operator = paramsReplaced.operator;
  668. var type = paramsReplaced.type;
  669. /* self.log('extend');
  670. self.log(extend); */
  671. if (name) {
  672. var pathString = 'self.json.var.' + name;
  673. var pathLast = pathString.substr(pathString.lastIndexOf(".") + 1);
  674. var pathBase = pathString.substr(0, pathString.lastIndexOf("."));
  675. var varObj = self.docElement(pathBase);
  676. /* self.log('name');
  677. self.log(name);
  678. self.log('pathBase');
  679. self.log(pathBase);
  680. self.log('pathLast');
  681. self.log(pathLast);
  682. self.log('varObj');
  683. self.log(varObj); */
  684. if (value !== undefined) {
  685. //if (value == 'string')
  686. // value = self.docElement('self.json.var.'+value); // todo
  687. //else
  688. value = self.actionResult(value, args);
  689. // typization
  690. switch (type) {
  691. case 'string': value = String(value); break;
  692. case 'number': value = Number(value); break;
  693. case 'boolean': value = Boolean(value); break;
  694. case 'array': value = JSON.parse(value); break;
  695. case 'object': value = JSON.parse(value); break;
  696. }
  697. //self.log('value');
  698. //self.log(value);
  699. /*
  700. // reset
  701. if (value == undefined && typeof value == 'string') value = '';
  702. if (value == undefined && typeof value == 'number') value = 0;
  703. if (value == undefined && typeof value == 'object') value = {}; */
  704. /* self.log('operator');
  705. self.log(operator);
  706. self.log('pathLast');
  707. self.log(pathLast);
  708. self.log('varObj[pathLast]');
  709. self.log(varObj[pathLast]); */
  710. if (varObj && pathLast) {
  711. switch (operator) {
  712. case '+=': varObj[pathLast] += value; break;
  713. case '-=': varObj[pathLast] -= value; break;
  714. case '/=': varObj[pathLast] /= value; break;
  715. case '*=': varObj[pathLast] *= value; break;
  716. default: varObj[pathLast] = value; break;
  717. }
  718. /* operators: [
  719. '=', '>', '<', '!', '~', '?', ':', '==', '<=', '>=', '!=',
  720. '&&', '||', '++', '--', '+', '-', '*', '/', '&', '|', '^', '%',
  721. '<<', '>>', '>>>', '+=', '-=', '*=', '/=', '&=', '|=', '^=',
  722. '%=', '<<=', '>>=', '>>>='
  723. ], */
  724. //self.log('varObj[pathLast]');
  725. varValue = varObj[pathLast];
  726. } else {
  727. /* self.log('pathString');
  728. self.log(pathString); */
  729. //varValue = self.docElement(pathString, value);
  730. //varValue = value;
  731. self.docElement(pathString, value);
  732. /* self.log('name');
  733. self.log(name);
  734. self.log('var '+name);
  735. self.log(self.var(name)); */
  736. }
  737. /* self.log('pathLast');
  738. self.log(pathLast);
  739. self.log('varObj[pathLast]');
  740. self.log(varObj[pathLast]); */
  741. /* //alert(value);
  742. //value = self.replaceProperties(value, args);
  743. if (value == 'string') {
  744. //self.json.var[name] = self.docElement('self.json.var.'+value);
  745. varObj[pathLast] = self.docElement('self.json.var.'+value);
  746. } else {
  747. //self.json.var[name] = self.actionResult(value, args);
  748. varObj[pathLast] = self.actionResult(value, args);
  749. } */
  750. //self.log('varObj[pathLast]');
  751. //if (self.isJson(self.json.var[name]))
  752. // self.json.var[name] = self.parse(self.json.var[name]);
  753. } else if (paramsReplaced.push) {
  754. if (varObj && pathLast && varObj[pathLast]) {
  755. varObj[pathLast] = varObj[pathLast].push(paramsReplaced.push);
  756. varValue = varObj[pathLast];
  757. }
  758. } else if (paramsReplaced.extend) {
  759. if (varObj && pathLast && varObj[pathLast]) {
  760. varObj[pathLast] = self.extend({}, varObj[pathLast], paramsReplaced.extend);
  761. varValue = varObj[pathLast];
  762. }
  763. } else {
  764. // no "value" property: return the value of the var "name"
  765. varValue = varObj[pathLast];
  766. /* varValue = self.replaceProperties(varObj[pathLast], args);
  767. alert(JSON.stringify(varValue)); */
  768. }
  769. //varValue = self.json.var[name] || {}; // to check
  770. } else {
  771. self.log('var name undefined');
  772. self.log(params);
  773. varValue = undefined;
  774. }
  775. if (params.do && params.do.length > 0) {
  776. self.log('this.var params.do');
  777. self.log(params.do);
  778. //alert(JSON.stringify(params.do));
  779. //self.do(params.do, args);
  780. self.do(params.do, undefined, args);
  781. }
  782. }
  783. return varValue;
  784. }
  785. };
  786. this.find = function (params, args) {
  787. if (params.in) {
  788. var list = self.replaceProperties(params.in, args);
  789. return list.filter(function (item) {
  790. if (params.value) {
  791. if (typeof params.value == 'string') {
  792. if (JSON.stringify(item).indexOf(params.value) >= 0)
  793. return item;
  794. } else { // if (typeof params.value == 'string') {
  795. for (var key in params.value) {
  796. if (params.value[key] == item[key])
  797. return item;
  798. }
  799. }
  800. }
  801. });
  802. }
  803. };
  804. /* this.data = function (params, args) {
  805. if (typeof params == 'string')
  806. return self.db(params, args);
  807. else
  808. self.firebase(params, args);
  809. } */
  810. this.array = function (params, args) {
  811. /* self.log("---- this.array ----");
  812. self.log('params');
  813. self.log(params); */
  814. if (args)
  815. params = self.replacePropertyWithPrefix(params, 'result', args);
  816. for (var par in params) {
  817. var paramReplaced = self.replaceProperties(params[par], args);
  818. //value[par](params[par]) // ipotesi di eseguire in automatico qualunque funzione js su stringhe
  819. /* self.log("par");
  820. self.log(par);
  821. self.log("params[par]");
  822. self.log(params[par]);
  823. self.log("paramReplaced");
  824. self.log(paramReplaced); */
  825. params[par] = paramReplaced;
  826. }
  827. //self.log("params");
  828. //self.log(params);
  829. var value = self.element({ path: params.name }) || [];
  830. /* self.log("value");
  831. self.log(...value); */
  832. if (params.push) {
  833. if (Array.isArray(params.push))
  834. value.push(...params.push);
  835. else
  836. value.push(params.push);
  837. }
  838. if (params.unshift) value.unshift(...params.unshift);
  839. if (params.pop) return value.pop(params.pop);
  840. if (params.shift) return value.shift(params.shift);
  841. self.element({ path: params.name, value: value });
  842. };
  843. this.replace = function (params, args) {
  844. // self.log("---- this.replace ----");
  845. params = self.replacePropertyWithPrefix(params, 'result', args);
  846. /* self.log("params");
  847. self.log(params); */
  848. var value = self.element({ path: params.path }) || [];
  849. var to = params.to || '';
  850. var type = typeof value;
  851. /* self.log("type");
  852. self.log(type); */
  853. if (type !== "string") value = JSON.stringify(value);
  854. /* self.log("value 1");
  855. self.log(value); */
  856. if (params.from) value = self.replaceAll(value, params.from, to);
  857. /* self.log("value2 ");
  858. self.log(value); */
  859. switch (type) {
  860. case "number":
  861. value = Number(value);
  862. break;
  863. case "boolean":
  864. value = Boolean(value);
  865. break;
  866. case "object":
  867. value = JSON.parse(value);
  868. break;
  869. }
  870. /* self.log("value 3");
  871. self.log(value); */
  872. //return value;
  873. return self.element({ path: params.path, value: value });
  874. };
  875. this.unshift = function (params, args) {
  876. for (var param in params) {
  877. var path = self.replaceProperties(param, args);
  878. var value = self.replaceProperties(params[param], args);
  879. if (value) {
  880. var obj = self.element({ path: path }) || [];
  881. obj.unshift(value);
  882. self.element({ path: path, value: obj });
  883. }
  884. }
  885. };
  886. this.set = function (params, args) {
  887. if (Array.isArray(params)) { // 1.0.5
  888. for (var obj of params)
  889. self.set(obj, args);
  890. } else {
  891. for (var param in params) {
  892. var value = params[param];
  893. if (value) value = self.replaceProperties(value, args, false); // TO DO: check
  894. if (value && args) value = self.replacePropertyWithPrefix(value, 'result', args); // backward compatibility TO DO: remove
  895. self.element({ path: param, value: value });
  896. }
  897. }
  898. //return true
  899. };
  900. this.get = function (element) {
  901. //self.log('self.get');
  902. if (element.startsWith('\''))
  903. return String(element.match(/\'([^\']*)\'/)[1]); // stringa racchiusa tra apici (serve?)
  904. else if (element.startsWith('Boolean'))
  905. return Boolean(element.match(/Boolean\(([^\)]*)\)/)[0]); // Boolean(x)
  906. else if (element.startsWith('Number'))
  907. return Number(element.match(/Number\(([^\)]*)\)/)[0]); // Number(x)
  908. else if (element.startsWith('String'))
  909. return String(element.match(/String\(([^\)]*)\)/)[0]); // String(x)
  910. else
  911. return (self.docElement(element)); // ora le tipizzazioni sono già in docElement grazie a eval
  912. };
  913. this.getJSON = function (url, callback) {
  914. var xhr = new XMLHttpRequest();
  915. xhr.open('GET', url, true);
  916. xhr.responseType = 'json';
  917. xhr.onload = function () {
  918. var status = xhr.status;
  919. if (status === 200) {
  920. callback(null, xhr.response);
  921. } else {
  922. callback(status, xhr.response);
  923. }
  924. };
  925. xhr.send();
  926. };
  927. /*---------------------
  928. var
  929. ---------------------*/
  930. var database, auth, storage;
  931. this.listeners = {};
  932. this.resizeActions = {};
  933. /* var iconsFile;
  934. this.device = false; // touch device
  935. this.touch = 'mousedown'; if (this.device) {this.touch = 'touchstart';}
  936. var animations = {};
  937. var tweenLoading;
  938. var tasksIntervals = {};
  939. var timedTasks = {'yearly':{},'monthly':{},'daily':{},'hourly':{}, '10mins':{}, '5mins':{}, '30mins':{}, '1min':{}, '30sec': {}, '10sec': {}, '1sec': {}}; */
  940. /* this.dateSelection; // = {day:0, month:0, year:0};
  941. this.timeSelection = {hour:0, min:0, sec:0, ampm:'AM', allday:true};
  942. this.timeSelectionCallback = null; */
  943. /*--------------------
  944. FIREBASE
  945. --------------------*/
  946. //var firebaseInitialized = false;
  947. this.firebaseVerifyUser = function (data) {
  948. self.log('firebaseVerifyUser');
  949. //self.log(data);
  950. //self.log(data.code);
  951. if (self.params.oobCode) {
  952. var oobCode = self.params.oobCode;
  953. auth.applyActionCode(oobCode).then(function (resp) {
  954. // self.log('resp');
  955. // self.log(resp);
  956. self.alert({
  957. //toast: true,
  958. icon: "success",
  959. title: "titVerifyEmail",
  960. html: "msgVerifyEmail",
  961. confirmButtonText: "btnOk",
  962. //showCancelButton: false,
  963. confirm: function () {
  964. //self.reload();
  965. // self.do(data);
  966. window.location.href = "/app/index.html";
  967. }
  968. });
  969. }).catch(function (error) {
  970. self.log('error');
  971. self.alert({
  972. icon: "error",
  973. title: "titWarning",
  974. html: error.code + " - " + error.message,
  975. confirmButtonText: "btnOk",
  976. //showCancelButton: false,
  977. confirm: function () {
  978. // self.reload();
  979. // self.do(data);
  980. window.location.href = "/app/index.html";
  981. }
  982. });
  983. });
  984. // verifica su auth
  985. }
  986. //data.code / data.params.code
  987. //self.do(data);
  988. self.do(data);
  989. };
  990. /* this.firebaseInit = function (data) {
  991. self.log("firebaseInit");
  992. if (json.setup && json.setup.firebase) {
  993. //var.databaseURL = json.setup.firebase.databaseURL;
  994. firebase.initializeApp(json.setup.firebase);
  995. database = firebase.database();
  996. auth = firebase.auth();
  997. // if (self.json.plugins['firebase-storage'].active) OR find in self.json.plugins name: 'firebase-storage'
  998. //storage = firebase.storage();
  999. auth.onAuthStateChanged(user => {
  1000. self.json.var.user = user;
  1001. if (!user) {
  1002. // No user logged in
  1003. self.log('onAuthStateChanged:GUEST\n');
  1004. // non bisognerebbe chiedere sempre di fare login
  1005. } else {
  1006. // User logged in
  1007. self.log('onAuthStateChanged:USER\n');
  1008. self.log('name: '+self.user('displayName') + '\nemail: '+user.email + '\nuid: '+ user.uid);
  1009. }
  1010. //self.log('firebaseInitialized');
  1011. //self.log(firebaseInitialized);
  1012. if (!firebaseInitialized) {
  1013. firebaseInitialized = true;
  1014. self.do(data);
  1015. }
  1016. });
  1017. } else {
  1018. self.do(data);
  1019. }
  1020. } */
  1021. this.sendMail = function (data) {
  1022. self.log('sendMail');
  1023. var emailParams = {
  1024. Host: "smtp.mailgun.com",
  1025. Username: "vito@nuvolaria.com",
  1026. Password: "bee02191be84c784a665fa98c61e03ce-915161b7-d32cb9d0",
  1027. From: data.from,
  1028. To: data.to,
  1029. Subject: data.subject,
  1030. Body: data.html
  1031. };
  1032. Email.send(emailParams).then(
  1033. message => self.alert({
  1034. icon: 'success',
  1035. title: 'titEmailSuccess',
  1036. confirmButtonText: 'btnClose'
  1037. })
  1038. );
  1039. /*
  1040. "from": "gianfrancoguglielmi@gmail.com",
  1041. "to": "vito.minchilli@gmail.com",
  1042. "subject": "Prova oggetto",
  1043. "html": "Prova testo",
  1044. "text": "Prova testo"
  1045. */
  1046. /*
  1047. var SERVER_NODEJS_BASEURL='https://app.fixo.io:4002';
  1048. var params = {
  1049. rom: data.from,
  1050. to: data.to,
  1051. subject: data.subject,
  1052. html: data.html,
  1053. text: data.text
  1054. };
  1055. $.ajax({
  1056. type: "POST",
  1057. 'beforeSend': function(xhr) {
  1058. xhr.setRequestHeader('Accept', 'application/json');
  1059. xhr.setRequestHeader('Content-Type', 'application/json');
  1060. },
  1061. data: JSON.stringify(params),
  1062. url: SERVER_NODEJS_BASEURL + '/sendMail',
  1063. success: function(data) {
  1064. self.log('sendMail SUCCESS');
  1065. self.log(data);
  1066. self.do(data);
  1067. },
  1068. error: function(error) {
  1069. self.log('sendMail ERROR');
  1070. self.log(error);
  1071. self.do(data);
  1072. }
  1073. });
  1074. */
  1075. };
  1076. //var multipleFiles = [];
  1077. /* this.fileDownload = function (url) {
  1078. self.log('fileDownload');
  1079. self.log(url);
  1080. var fileArr = url.split('?');
  1081. self.log(fileArr);
  1082. //var file = fileArr[0];
  1083. var urlArr = fileArr[0].split('/');
  1084. self.log(urlArr);
  1085. var name = urlArr[urlArr.length-1];
  1086. self.log(name);
  1087. var token = self.getParameterByName('token', url);
  1088. self.log(token);
  1089. window.location.href = '/app/php/proxy.php?name='+ name + '&url='+ url;
  1090. } */
  1091. /* this.fileUrl = function (params) {
  1092. // da nome file a l'url Firebase Storage inclusiva del token
  1093. self.log('fileUrl');
  1094. self.log(params);
  1095. // self.log('storage');
  1096. // self.log(storage);
  1097. if (storage) {
  1098. var storageRef = storage.ref();
  1099. var pathReference = storageRef.child(params.user+'/'+params.name);
  1100. pathReference.getDownloadURL().then(function(url) {
  1101. if (params.callback) params.callback(url);
  1102. }).catch(function(error) {
  1103. if (error && error.code && params.error) {
  1104. self.log(self.firebaseStorageError(error.code));
  1105. params.error(error.code);
  1106. }
  1107. // A full list of error codes is available at
  1108. // https://firebase.google.com/docs/storage/web/handle-errors
  1109. });
  1110. } else {
  1111. self.log('storage undefined');
  1112. }
  1113. } */
  1114. /* this.firebaseStorageError = function (errorCode) {
  1115. switch (errorCode) {
  1116. case 'storage/object-not-found':
  1117. // File doesn\'t exist
  1118. return 'File doesn\'t exist';
  1119. case 'storage/unauthorized':
  1120. // User doesn\'t have permission to access the object
  1121. return 'User doesn\'t have permission to access the object';
  1122. case 'storage/canceled':
  1123. // User canceled the upload
  1124. return 'User canceled the upload';
  1125. case 'storage/unknown':
  1126. // Unknown error occurred, inspect the server response
  1127. return 'Unknown error occurred, inspect the server response';
  1128. default:
  1129. return 'No error'
  1130. }
  1131. } */
  1132. var x = [{ if: 3 }, function () { }, 3, []];
  1133. this.firebaseAddListener = function (params) {
  1134. /* self.log('firebaseAddListener');
  1135. self.log(params); */
  1136. // {path, orderByChild, equalTo}
  1137. //self.log(params.path);
  1138. if (database) {
  1139. // Aggiunge listener in ascolto su params.path che esegue params.action
  1140. if (params.action) {
  1141. if (!self.listeners[params.path]) self.listeners[params.path] = [];
  1142. /* alert('params.action:'+params.action);
  1143. alert('type params.action:' + typeof params.action);
  1144. alert(params.path+':'+JSON.stringify({
  1145. action: params.action
  1146. })); */
  1147. //if (Array.isArray(params.action))
  1148. // self.listeners[params.path].concat(params.action);
  1149. //else
  1150. self.listeners[params.path].push(params.action);
  1151. }
  1152. /* if (params.success !== undefined) {
  1153. alert('params.success:'+params.success);
  1154. alert('type params.success:' + typeof params.success);
  1155. alert(params.path+':'+JSON.stringify({
  1156. success: params.success
  1157. }));
  1158. self.listeners[params.path].push(params.success);
  1159. } */
  1160. //self.log('params.path: '+ params.path);
  1161. //self.listeners[params.path] = params.action;
  1162. //alert(self.listeners[params.path]);
  1163. /*
  1164. limitToFirst() Sets the maximum number of items to return from the beginning of the ordered list of results.
  1165. limitToLast() Sets the maximum number of items to return from the end of the ordered list of results.
  1166. startAt() Return items greater than or equal to the specified key or value, depending on the order-by method chosen.
  1167. startAfter() Return items greater than the specified key or value depending on the order-by method chosen.
  1168. endAt() Return items less than or equal to the specified key or value, depending on the order-by method chosen.
  1169. endBefore() endBefore() Return items less than the specified key or value depending on the order-by method chosen.
  1170. equalTo() Return items equal to the specified key or value, depending on the order-by method chosen.
  1171. orderByChild() Order results by the value of a specified child key or nested child path.
  1172. orderByKey() Order results by child keys.
  1173. orderByValue() Order results by child values.
  1174. orderByPriority() Order results by priority
  1175. https://firebase.google.com/docs/reference/js/v8/firebase.database.Query
  1176. */
  1177. //Firestore.collection(collectionName).orderBy(field).where(field, ">=", keyword.toUpperCase()).where(field, "<=", keyword.toUpperCase() + "\uf8ff").get()
  1178. // https://medium.com/feedflood/filter-by-search-keyword-in-cloud-firestore-query-638377bf0123
  1179. // https://firebase.google.com/docs/database/rest/retrieve-data?hl=it#range-queries
  1180. // startAt , endAt , limitToFirst , limitToLast o equalTo
  1181. //databaseReference.orderByChild('_searchLastName').startAt(queryText).endAt(queryText+"\uf8ff")
  1182. // where ("string, "in"/"not-in", array)
  1183. // https://firebase.google.com/docs/firestore/query-data/queries?hl=it#in_and_array-contains-any
  1184. var dbRef = database.ref(params.path);
  1185. dbRef.off();
  1186. if (params.orderByChild) dbRef = dbRef.orderByChild(params.orderByChild);
  1187. if (params.orderByKey) dbRef = dbRef.orderByKey(params.orderByKey);
  1188. if (params.orderByValue) dbRef = dbRef.orderByValue(params.orderByValue);
  1189. if (params.equalTo) dbRef = dbRef.equalTo(params.equalTo);
  1190. if (params.startAt) dbRef = dbRef.startAt(params.startAt);
  1191. if (params.startAfter) dbRef = dbRef.startAfter(params.startAfter);
  1192. if (params.endAt) dbRef = dbRef.endAt(params.endAt);
  1193. if (params.endBefore) dbRef = dbRef.endBefore(params.endBefore);
  1194. if (params.limitToFirst) dbRef = dbRef.limitToFirst(params.limitToFirst);
  1195. if (params.limitToLast) dbRef = dbRef.limitToLast(params.limitToLast);
  1196. if (params.where) dbRef = dbRef.where(params.where[0], params.where[1], params.where[2]); // maybe params.where in enough
  1197. var feedback = dbRef.on('value', firebaseEvent);
  1198. //console.log(feedback);
  1199. /* console.log('dbRef');
  1200. console.log(dbRef);
  1201. */
  1202. /* if (params.orderByChild && params.equalTo)
  1203. dbRef.orderByChild(params.orderByChild).equalTo(params.equalTo).on('value', firebaseEvent);
  1204. else
  1205. dbRef.on('value', firebaseEvent); */
  1206. } else {
  1207. self.log('database undefined');
  1208. // Restart the db
  1209. }
  1210. };
  1211. var firebaseEvent = function (snapshot) {
  1212. console.log(snapshot.val());
  1213. var ref = snapshot.ref;
  1214. if (snapshot.val() !== undefined) {
  1215. var dbVal = snapshot.val();
  1216. var path = snapshot.ref.toString();
  1217. //if (!dbVal) dbVal = {};
  1218. var pathArr = path.split(/\.\w+\//);
  1219. var dbPath = pathArr[1];
  1220. self.log('firebaseEvent: ' + dbPath);
  1221. //if (var.databaseURL) dbPath = path.substr(var.databaseURL.length+1);
  1222. //else dbPath = path;
  1223. /* self.log('path: '+ path);
  1224. //self.log('var.databaseURL: '+ var.databaseURL);
  1225. self.log('dbPath: '+ dbPath); */
  1226. if (dbVal)
  1227. self.localDbUpdate(dbVal, dbPath);
  1228. else {
  1229. var dbObj = self.element({ path: 'self.json.var.db.' + self.replaceAll(dbPath, '/', '.') });
  1230. if (dbObj)
  1231. dbObj = null;
  1232. //delete dbObj;
  1233. }
  1234. //self.do(self.listeners[dbPath], dbVal);
  1235. }
  1236. };
  1237. this.localDbUpdate = function (newObj, dbPath) {
  1238. /* self.log('localDbUpdate');
  1239. self.log(newObj);
  1240. self.log(dbPath); */
  1241. //var path = newObj.path;
  1242. //delete newObj.path;
  1243. /* self.do(
  1244. {
  1245. var: {
  1246. name: "db."+self.replaceAll(dbPath, '/', '.'),
  1247. value: newObj,
  1248. //success: function () {
  1249. // self.do(self.listeners[dbPath], newObj);
  1250. //}
  1251. }
  1252. }
  1253. ); */
  1254. //alert('db.'+self.replaceAll(dbPath, '/', '.'));
  1255. /* var dbUpdateAction = {
  1256. var: {
  1257. name: 'db.'+self.replaceAll(dbPath, '/', '.'),
  1258. value: newObj
  1259. //do: (self.listeners[dbPath] && self.listeners[dbPath].length > 0) ? self.listeners[dbPath] : undefined
  1260. }
  1261. };
  1262. if (self.listeners[dbPath] !== undefined && self.listeners[dbPath] !== null && self.listeners[dbPath].length > 0)
  1263. dbUpdateAction.var.do = self.listeners[dbPath];
  1264. newObj.path = dbPath;
  1265. self.do(dbUpdateAction, newObj); */
  1266. // TO DO: decide l'utente dove salvare i dati
  1267. newObj = Object.fromEntries(Object.entries(newObj).reverse());
  1268. //newObj = Object.keys(newObj).reverse();
  1269. self.element({ path: 'self.json.var.db.' + self.replaceAll(dbPath, '/', '.'), value: newObj });
  1270. if (self.listeners[dbPath] !== undefined && self.listeners[dbPath] !== null && self.listeners[dbPath].length > 0) {
  1271. newObj.path = dbPath;
  1272. if (self.listeners[dbPath]) {
  1273. self.methods.firebaseEvent.action(newObj);
  1274. //self.do(self.listeners[dbPath], newObj);
  1275. self.do(self.listeners[dbPath], undefined, newObj);
  1276. }
  1277. }
  1278. };
  1279. this.firebaseRemoveListener = function (params) {
  1280. // Rimuove listener in ascolto su data.path
  1281. self.log('firebaseRemoveListener');
  1282. if (self.listeners[params.path]) {
  1283. delete self.listeners[params.path];
  1284. var dbRef = database.ref(params.path);
  1285. dbRef.off();
  1286. }
  1287. };
  1288. // Rimuove un elemento del database
  1289. this.firebaseRemove = function (path, callback) {
  1290. self.log('firebaseRemove');
  1291. self.log(path);
  1292. if (database) {
  1293. var result, dbRef;
  1294. if (path) {
  1295. dbRef = database.ref().child(path);
  1296. } else {
  1297. dbRef = database.ref();
  1298. }
  1299. return dbRef.remove(function (error) {
  1300. //Dati impostati con successo
  1301. if (error == null) {
  1302. self.log('set SUCCESS');
  1303. result = { success: true };
  1304. } else {
  1305. self.log('set ERROR');
  1306. //Errore inserimento dati
  1307. result = { success: false, error: error };
  1308. }
  1309. if (callback) callback(result);
  1310. });
  1311. } else {
  1312. self.log('database not initialized');
  1313. }
  1314. };
  1315. // Write or replace data to a defined path
  1316. this.firebaseSet = function (path, value, callback) {
  1317. /*
  1318. set Write or replace data to a defined path, like messages/users/<username>
  1319. update Update some of the keys for a defined path without replacing all of the data
  1320. 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/<unique-user-id>/<username>
  1321. transaction Use transactions when working with complex data that could be corrupted by concurrent updates
  1322. */
  1323. if (database) {
  1324. var result, dbRef;
  1325. if (path) {
  1326. dbRef = database.ref().child(path);
  1327. } else {
  1328. dbRef = database.ref();
  1329. }
  1330. return dbRef.set(value, function (error) {
  1331. //Dati impostati con successo
  1332. if (error == null) {
  1333. self.log('set SUCCESS');
  1334. result = { success: true };
  1335. } else {
  1336. self.log('set ERROR');
  1337. //Errore inserimento dati
  1338. result = { success: false, error: error };
  1339. }
  1340. if (callback) callback(result);
  1341. });
  1342. } else {
  1343. self.log('database not initialized');
  1344. }
  1345. };
  1346. // Update some of the keys for a defined path without replacing all of the data
  1347. this.firebaseUpdate = function (path, value, callback) {
  1348. self.log('firebaseUpdate');
  1349. self.log('path');
  1350. self.log(path);
  1351. self.log('value');
  1352. self.log(value);
  1353. if (database) {
  1354. var result, dbRef;
  1355. if (path) {
  1356. dbRef = database.ref().child(path);
  1357. } else {
  1358. dbRef = database.ref();
  1359. }
  1360. return dbRef.update(value, function (error) {
  1361. //Dati impostati con successo
  1362. if (error == null) {
  1363. self.log('update SUCCESS');
  1364. result = { success: true };
  1365. } else {
  1366. self.log('update ERROR');
  1367. //Errore inserimento dati
  1368. result = { success: false, error: error };
  1369. }
  1370. if (callback) callback(result);
  1371. });
  1372. } else {
  1373. self.log('database not initialized');
  1374. }
  1375. };
  1376. // 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/<unique-user-id>/<username>
  1377. this.firebasePush = function (path, value, callback) {
  1378. self.log('firebasePush');
  1379. self.log(path);
  1380. if (database) {
  1381. var result, dbRef;
  1382. if (path) {
  1383. dbRef = database.ref().child(path);
  1384. } else {
  1385. dbRef = database.ref();
  1386. }
  1387. return dbRef.push(value, function (error) {
  1388. //Dati impostati con successo
  1389. if (error == null) {
  1390. self.log('push SUCCESS');
  1391. result = { success: true };
  1392. } else {
  1393. self.log('push ERROR');
  1394. //Errore inserimento dati
  1395. result = { success: false, error: error };
  1396. }
  1397. if (callback) callback(result);
  1398. });
  1399. } else {
  1400. self.log('database not initialized');
  1401. }
  1402. };
  1403. // https://firebase.google.com/docs/database/security/rules-conditions
  1404. // tutte le get / o listeners / potrebbero essere basate su orderByChild("owner")
  1405. /*
  1406. rooms": {
  1407. // this rule applies to any child of /rooms/, the key for each room id
  1408. // is stored inside $room_id variable for reference
  1409. "$room_id": {
  1410. "topic": {
  1411. // the room's topic can be changed if the room id has "public" in it
  1412. ".write": "$room_id.contains('public')"
  1413. }
  1414. }
  1415. }
  1416. */
  1417. /* this.firebaseQuery = function(params) {
  1418. self.log('firebaseQuery');
  1419. self.log(params);
  1420. // path = 'users/'+self.user('email')
  1421. // value = 'guest'
  1422. var dbRef = database.ref(params.path);
  1423. if (!params.result) params.result = {};
  1424. if (params.value && !Array.isArray(params.value)) {
  1425. var buffer = params.value;
  1426. params.value = [];
  1427. params.value[0] = buffer;
  1428. }
  1429. //self.log('params.value');
  1430. //self.log(params.value);
  1431. if (params.value && params.value.length > 0) {
  1432. var value = params.value.shift();
  1433. //self.log('value');
  1434. //self.log(value);
  1435. //self.log('params.key');
  1436. //self.log(params.key);
  1437. dbRef.orderByChild(params.key).equalTo(value).once('value', (object) => {
  1438. self.log('object');
  1439. self.log(object);
  1440. if(object) {
  1441. params.result = self.extend(params.result, object.val());
  1442. if (params.value.length > 0)
  1443. self.firebaseQuery(params);
  1444. else
  1445. params.callback({
  1446. success: true,
  1447. error: null,
  1448. data: params.result
  1449. });
  1450. } else {
  1451. //self.log('firebaseQuery ERROR');
  1452. //result = {success:false, error:8};
  1453. params.callback({
  1454. success:true,
  1455. error:null,
  1456. data: params.result
  1457. });
  1458. }
  1459. });
  1460. } else {
  1461. params.callback({success:false, error:null});
  1462. }
  1463. } */
  1464. this.firebaseGetPart = function (params) {
  1465. self.log('firebaseGetPart');
  1466. let remotePath = self.replaceAll(params.localPath, '.', '/');
  1467. self.log('localPath:' + params.localPath);
  1468. //self.log('remotePath:'+remotePath);
  1469. if (self.partContainers[params.localPath]) {
  1470. self.partContainers[params.localPath].push(params);
  1471. } else {
  1472. self.partContainers[params.localPath] = [];
  1473. self.partContainers[params.localPath].push(params);
  1474. dbRef = database.ref().child(remotePath);
  1475. return dbRef.once('value').then(function (object) {
  1476. //Dati recuperati con successo
  1477. if (object) {
  1478. self.log('firebaseGetPart SUCCESS');
  1479. self.log(object);
  1480. // local db update
  1481. if (object.val() !== undefined) {
  1482. window.dbVal = object.val();
  1483. var dbVal = object.val();
  1484. self.log('dbVal');
  1485. self.log(dbVal);
  1486. if (dbVal !== null) {
  1487. let fullPath = object.ref.toString();
  1488. let pathArr = fullPath.split(/\.\w+\//); // split on the domain extension
  1489. let dbPath = pathArr[1]; // path after the domain extension
  1490. let localPath = self.replaceAll(dbPath, '/', '.');
  1491. //var dbPath = path.substr(var.databaseURL.length+1);
  1492. self.log('dbPath: ' + dbPath);
  1493. self.log('localPath: ' + localPath);
  1494. //self.log('self.partContainers[localPath]');
  1495. //self.log(self.partContainers[localPath]);
  1496. self.element({ path: localPath, value: dbVal });
  1497. for (partObj of self.partContainers[localPath]) {
  1498. /* self.log('partObj');
  1499. self.log(partObj); */
  1500. let part = self.replacePropertyWithPrefix(dbVal, 'setup', partObj.setup);
  1501. part = self.replacePropertyWithPrefix(part, 'arg', partObj.arg);
  1502. self.extendJsonFromElement(part); // or selectorParams
  1503. /* self.log('part');
  1504. self.log(part); */
  1505. self.html(part, partObj.container);
  1506. //self.run(part, partObj.container);
  1507. //self.run(dbVal, container);
  1508. }
  1509. }
  1510. }
  1511. } else {
  1512. self.log('firebaseGetPart ERROR');
  1513. result = { success: false, error: 8 };
  1514. }
  1515. //self.log(result);
  1516. //callback(result);
  1517. });
  1518. }
  1519. };
  1520. /* {
  1521. "database": {
  1522. "do": "get",
  1523. "path": "apps/dev/{setup:key}",
  1524. "on": {
  1525. "success": [
  1526. { */
  1527. this.firebaseIncrease = function (params) {
  1528. console.log('firebaseIncrease');
  1529. self.firebaseGet(params.path, function (result) {
  1530. console.log(result);
  1531. if (result.success) {
  1532. if (result.data === null || result.data === undefined || typeof result.data == 'number') {
  1533. var counter = Number(result.data) + 1;
  1534. console.log('counter:' + counter);
  1535. self.firebaseSet(params.path, counter, function (result) {
  1536. if (result.success) {
  1537. self.log('firebaseIncrease SUCCESS');
  1538. if (params.on && params.on.success) self.do(params.on.success, undefined, result);
  1539. } else {
  1540. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  1541. }
  1542. });
  1543. } else {
  1544. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  1545. }
  1546. } else {
  1547. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  1548. }
  1549. });
  1550. };
  1551. this.firebaseGet = function (path, callback) {
  1552. self.log('firebaseGet:' + path);
  1553. var result = { success: false, error: 7 };
  1554. if (path) {
  1555. // try, if path is wrong "Uncaught TypeError: Cannot read properties of undefined (reading 'ref')"
  1556. dbRef = database.ref().child(path);
  1557. } else {
  1558. dbRef = database.ref();
  1559. }
  1560. /* if (false) { //path == 'files') {
  1561. //alert(self.user('email'));
  1562. return dbRef.orderByChild('users/'+self.user('email')).equalTo('guest').on('value', (object) => {
  1563. //return dbRef.orderByChild('prefs/authorId').equalTo(self.user('uuid')).on('value', (object) => {
  1564. //return dbRef.orderByChild('users').equalTo(self.user('email')).on('value', (object) => {
  1565. //self.log(object);
  1566. //var user = object.val();
  1567. //Dati recuperati con successo
  1568. if(object) {
  1569. result = {success:true, error:null, data: object.val()};
  1570. } else {
  1571. self.log('get ERROR');
  1572. //Errore recupero dati
  1573. result = {success:false, error:8};
  1574. }
  1575. //self.log(result);
  1576. callback(result);
  1577. });
  1578. } else { */
  1579. // ATTENZIONE: va intercettato e loggato l'errore di accesso negato dalle regole
  1580. return dbRef.once('value').then(function (object) {
  1581. //Dati recuperati con successo
  1582. if (object) {
  1583. self.log('get SUCCESS');
  1584. result = { success: true, error: null, data: object.val() };
  1585. // local db update
  1586. if (object.val() !== undefined) {
  1587. var dbVal = object.val();
  1588. var path = object.ref.toString();
  1589. if (!dbVal) dbVal = {};
  1590. var pathArr = path.split(/\.\w+\//); // split on the domain extension
  1591. var dbPath = pathArr[1]; // path after the domain extension
  1592. //var dbPath = path.substr(var.databaseURL.length+1);
  1593. self.log('dbPath: ' + dbPath);
  1594. self.localDbUpdate(dbVal, dbPath);
  1595. }
  1596. } else {
  1597. self.log('get ERROR');
  1598. //Errore recupero dati
  1599. result = { success: false, error: 8 };
  1600. }
  1601. //self.log(result);
  1602. callback(result);
  1603. });
  1604. //}
  1605. };
  1606. this.stringToKey = function (str) {
  1607. return str.replace(/\./g, '%2E');
  1608. };
  1609. this.keyToString = function (key) {
  1610. return key.replace(/%2E/g, '.');
  1611. };
  1612. this.firebaseKey = this.getKey = function (path) {
  1613. var dbRef = database.ref(path);
  1614. return dbRef.child(path).push().getKey();
  1615. };
  1616. // --------------
  1617. // SELECTOR
  1618. // --------------
  1619. this.exist = function (selector) {
  1620. console.log('selector');
  1621. console.log(selector);
  1622. console.log(Boolean(self.query(selector)));
  1623. return Boolean(self.query(selector));
  1624. };
  1625. this.count = function (selector) {
  1626. //self.log('count:'+selector+ '='+ self.queryAll(selector).length);
  1627. return self.queryAll(selector).length;
  1628. /* if (selector) {
  1629. var routes = selector.split(/[ >]+/);
  1630. if (!element) element = document;
  1631. for (var index in routes) {
  1632. var route = routes[index];
  1633. //onsole.log('route');
  1634. //self.log(route);
  1635. var routeParts = route.match(/(.*):eq\((\d*)\)/);
  1636. //self.log('routeParts');
  1637. //self.log(routeParts);
  1638. if (routeParts) {
  1639. var routeElement = String(routeParts[1]);
  1640. var routeIndex = Number(routeParts[2]);
  1641. element = element.querySelectorAll(routeElement)[routeIndex];
  1642. } else {
  1643. element = element.querySelectorAll(route)[0];
  1644. }
  1645. } */
  1646. /* var elements = self.query(selector);
  1647. if (elements)
  1648. return elements.querySelectorAll().length;
  1649. else
  1650. return 0 */
  1651. /* if (self.exist(selector))
  1652. return document.querySelectorAll(selector).length;
  1653. else
  1654. return 0 */
  1655. };
  1656. var log = function (id, value) {
  1657. self.log(id);
  1658. self.log(value);
  1659. };
  1660. this.classSelector = function (selClass) {
  1661. if (selClass.indexOf('.') == 0) { selClass = String(selClass).substr(1); } // backward compatibility
  1662. let classes = selClass.split(' ');
  1663. selClass = classes[0];
  1664. /* self.log('selClass');
  1665. self.log(selClass); */
  1666. // avoid dynamic classes as selector
  1667. var regex = new RegExp('[\-][\[]');
  1668. if (selClass && selClass.match(regex)) selClass = classes[1];
  1669. if (selClass && selClass.match(regex)) selClass = classes[2];
  1670. return selClass;
  1671. };
  1672. this.selector = function (params, containerParams, selectAll) {
  1673. // {container, class, value, id}
  1674. var selector;
  1675. if (params) {
  1676. if (typeof params == 'string') {
  1677. /* self.log('this.selector');
  1678. self.log(params); */
  1679. return params;
  1680. } else if (Array.isArray(params)) {
  1681. return params;
  1682. } else {
  1683. var selContainer;
  1684. if (params.selector || params.container)
  1685. selContainer = params.selector || params.container;
  1686. else if (containerParams)
  1687. selContainer = containerParams.selector || containerParams.container;
  1688. //var selContainer = container; //data.container;
  1689. var attr = (params.attr) ? params.attr : {};
  1690. var selId = (attr.id) ? attr.id : params.id;
  1691. var selClass = (attr.class) ? attr.class : params.class;
  1692. var selValue = (attr.value) ? attr.value : params.value;
  1693. var selDataValue = (attr['data-value']) ? attr['data-value'] : params['data-value'];
  1694. selValue = selDataValue || selValue;
  1695. if (selId) selId = self.replaceProperties(selId);
  1696. if (selValue) selValue = self.replaceProperties(selValue);
  1697. if (selClass) selClass = self.replaceProperties(selClass);
  1698. /* if (selId) selId = self.compile(selId);
  1699. if (selValue) selValue = self.compile(selValue);
  1700. if (selClass) selClass = self.compile(selClass); */
  1701. // use the first class as selector
  1702. if (selClass)
  1703. selClass = self.classSelector(selClass);
  1704. //if (!selectAll) selClass = undefined;
  1705. if (selId) {
  1706. selector = '#' + selId;
  1707. } else if (selValue && selClass) {
  1708. selector = '.' + selClass + '[data-value="' + selValue + '"]';
  1709. } else if (selValue && params.tag) {
  1710. selector = params.tag + '[data-value="' + selValue + '"]';
  1711. } else if (selClass && selectAll) {
  1712. selector = '.' + selClass;
  1713. //if (!selectAll)
  1714. // selector += ':eq(' + self.count(selector) + ')';
  1715. // qui c'è / c'era un baco:
  1716. // quando proviamo a eseguire un'azione su un elemento esistente
  1717. // usando solo la classe come selector, $(selector).length = 1
  1718. // quindi prova a selezionare il secondo elemento eq(1), non il primo eq(0)
  1719. } else if (params.tag) {
  1720. //if (selContainer) selector = selContainer;
  1721. selector = params.tag;
  1722. if (selContainer) {
  1723. selector = selContainer + ' > ' + params.tag;
  1724. if (!selectAll) {
  1725. //if (count !== $(selector).length) self.log('>> '+ selector + ' count:'+ self.count(selector) + ' !== ' + $(selector).length );
  1726. selector += ':eq(' + self.count(selector) + ')';
  1727. //selector += '[' + self.count(selector) + ']';
  1728. //selector += ':eq(' + $(selector).length + ')';
  1729. }
  1730. } else {
  1731. if (!selectAll) {
  1732. selector += ':eq(' + self.count(selector) + ')';
  1733. //selector += '[' + self.count(selector) + ']';
  1734. }
  1735. }
  1736. } else {
  1737. selector = selContainer;
  1738. };
  1739. }
  1740. return selector;
  1741. }
  1742. };
  1743. // --------------
  1744. // TEXTS
  1745. // --------------
  1746. this.stringify = function (obj) {
  1747. if (typeof obj == 'object')
  1748. try {
  1749. return JSON.stringify(obj);
  1750. } catch (error) {
  1751. return obj;
  1752. }
  1753. else
  1754. return obj;
  1755. };
  1756. this.parse = function (str) {
  1757. if (typeof str == 'string')
  1758. try {
  1759. return JSON.parse(str); // json
  1760. } catch (error) {
  1761. return str; // non json
  1762. }
  1763. else
  1764. return str;
  1765. };
  1766. /* this.removeEventProperties = function (params) {
  1767. var paramsObj = self.cloneObject(params);
  1768. if (paramsObj && paramsObj.on) {
  1769. paramOn = self.cloneObject(paramsObj.on);
  1770. delete paramsObj.on;
  1771. }
  1772. if (paramsObj && paramsObj.success) {
  1773. paramSuccess = self.cloneObject(paramsObj.success);
  1774. delete paramsObj.success;
  1775. }
  1776. return paramsObj;
  1777. }; */
  1778. self.setupId = 0;
  1779. this.replacePropertyWithPrefix = function (params, prefix, args) {
  1780. var paramsString;
  1781. if (typeof params == 'object')
  1782. paramsString = self.stringify(params);
  1783. else
  1784. paramsString = String(params);
  1785. /* let argsWithProperties = (args) ? JSON.stringify(args) : '';
  1786. paramsString = self.replaceAll(paramsString, '"{'+prefix+'}"', argsWithProperties); // obsolete */
  1787. //if (typeof args == undefined)
  1788. // self.log('replacePropertyWithPrefix args is undefined', 'yellow');
  1789. if (paramsString && paramsString.indexOf('{' + prefix) >= 0) {
  1790. paramsString = paramsString.replace(new RegExp('"{' + prefix + '[:\\s]?([\\w\\d\\s\\.\\|]*)}"', 'g'), function (match, path) {
  1791. if (path) {
  1792. let value = self.replaceUndefined({ match: match, path: path, root: args, removeUndefined: true });
  1793. //let value = self.element({path:path, root: args});
  1794. /* if (typeof value == undefined) {
  1795. self.log(match + ' not found', 'orange');
  1796. value = '';
  1797. } else */
  1798. if (value === undefined) {
  1799. return '""';
  1800. } else if (typeof value == 'object')
  1801. return JSON.stringify(value);
  1802. else if (typeof value == 'string')
  1803. return '"' + value + '"';
  1804. else
  1805. return value;
  1806. } else {
  1807. if (typeof args == 'object')
  1808. return JSON.stringify(args);
  1809. else if (typeof args == 'string')
  1810. return '"' + args + '"';
  1811. else
  1812. return args;
  1813. }
  1814. });
  1815. /* if (paramsString && paramsString.indexOf('Contacts')>= 0) {
  1816. self.log(paramsString, 'green');
  1817. } */
  1818. paramsString = paramsString.replace(new RegExp('{' + prefix + '[:\\s]?([\\w\\d\\s\\.]*)}', 'g'), function (match, path) {
  1819. if (path) {
  1820. let value = self.replaceUndefined({ match: match, path: path, root: args, removeUndefined: true });
  1821. //let value = self.element({path:path, root: args});
  1822. /* if (typeof value == undefined) {
  1823. self.log(match + ' not found', 'orange');
  1824. value = '';
  1825. } else */
  1826. if (value === undefined)
  1827. return '';
  1828. else if (typeof value == 'object') // when object inside a string?
  1829. return JSON.stringify(value);
  1830. else
  1831. return value;
  1832. } else {
  1833. if (typeof args == 'object')
  1834. return JSON.stringify(args);
  1835. else
  1836. return args;
  1837. }
  1838. });
  1839. if (self.isJsonString(paramsString)) {
  1840. var paramsObj = self.parse(paramsString);
  1841. return paramsObj;
  1842. } else {
  1843. return paramsString;
  1844. }
  1845. } else {
  1846. return params;
  1847. }
  1848. };
  1849. /* this.replaceProperty = function (params, name, args) { // TO DO: change name in replaceArguments
  1850. //console.log('replaceProperty:'+name);
  1851. //var actions = {};
  1852. if (typeof params == 'object') {
  1853. params = self.stringify(params);
  1854. }
  1855. if (typeof args !== 'string') {
  1856. let argsWithProperties = (args) ? JSON.stringify(args) : '';
  1857. params = self.replaceAll(params, '"{'+name+'}"', argsWithProperties); // obsolete
  1858. // TO DO: get self.element({path:key, root: args});
  1859. for (let key in args) {
  1860. if (typeof args[key] !== undefined) {
  1861. if (typeof args[key] == 'object')
  1862. params = self.replaceAll(params, '"{'+name+' '+key+'}"', JSON.stringify(args[key]));
  1863. else
  1864. params = self.replaceAll(params, '{'+name+' '+key+'}', args[key]);
  1865. } else {
  1866. params = self.replaceAll(params, '{'+name+' '+key+'}', '');
  1867. self.log('{'+name+' '+key+'}' + ' not found', 'yellow');
  1868. }
  1869. }
  1870. for (let key in args) {
  1871. if (args[key]) {
  1872. if (typeof args[key] == 'object')
  1873. params = self.replaceAll(params, '"{'+name+':'+key+'}"', JSON.stringify(args[key]));
  1874. else
  1875. params = self.replaceAll(params, '{'+name+':'+key+'}', args[key]);
  1876. } else {
  1877. params = self.replaceAll(params, '{'+name+':'+key+'}', '');
  1878. }
  1879. }
  1880. } else {
  1881. //console.log('args STRINGA');
  1882. params = self.replaceAll(params, '{'+name+'}', args);
  1883. }
  1884. if (self.isJson(params)) {// (typeof params == 'object')
  1885. var paramsObj = self.parse(params);
  1886. return paramsObj;
  1887. } else {
  1888. //alert(paramsString);
  1889. return params;
  1890. }
  1891. }
  1892. */
  1893. this.replaceResult = function (params, args) {
  1894. var paramOn, paramSuccess, paramError;
  1895. if (typeof params == 'object') {
  1896. var paramsObj = self.cloneObject(params);
  1897. if (paramsObj && paramsObj.on) {
  1898. paramOn = self.cloneObject(paramsObj.on);
  1899. delete paramsObj.on;
  1900. }
  1901. if (paramsObj && paramsObj.success) {
  1902. paramSuccess = self.cloneObject(paramsObj.success);
  1903. delete paramsObj.success;
  1904. }
  1905. params = self.stringify(params);
  1906. }
  1907. if (typeof args !== 'string') {
  1908. params = self.replaceAll(params, '"{result}"', JSON.stringify(args));
  1909. } else {
  1910. params = self.replaceAll(params, '{result}', args);
  1911. }
  1912. /* self.log('replaceResult');
  1913. self.log('params');
  1914. self.log(params); */
  1915. if (self.isJson(params)) { // (typeof params == 'object')
  1916. var paramsObj = self.parse(params);
  1917. if (paramOn) paramsObj.on = paramOn;
  1918. if (paramSuccess) paramsObj.success = paramSuccess;
  1919. if (paramError) paramsObj.error = paramError;
  1920. return paramsObj;
  1921. } else {
  1922. //alert(paramsString);
  1923. return params;
  1924. }
  1925. };
  1926. /*
  1927. this.replaceTags = function (params, selectorParams) {
  1928. self.log('replaceTags');
  1929. var undef = false;
  1930. if (params.text && (typeof params.text == 'string' || typeof params.text == 'object')) {
  1931. //alert(params.text);
  1932. params.text = self.stringify(params.text);
  1933. // i tag speciali sono contenuti tra i caratteri { e }
  1934. if (params.text.indexOf('{') >= 0) {
  1935. // alert(params.text.indexOf('{'));
  1936. // <{visible:element}>
  1937. params.text = params.text.replace(/\<\{visible\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1938. var value = ($(p1).is(':visible'));
  1939. return value;
  1940. });
  1941. // <{var:var.object}>
  1942. params.text = params.text.replace(/\<\{this\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1943. var value = self.json[p1];
  1944. if (!value) undef = true;
  1945. return self.stringify(value);
  1946. });
  1947. // <{data:value}>
  1948. params.text = params.text.replace(/\<\{data\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1949. var value = self.json.var[p1];
  1950. if (!value) undef = true;
  1951. return self.stringify(value);
  1952. });
  1953. params.text = params.text.replace(/\<\{var\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1954. var value = self.get(p1);
  1955. if (!value) undef = true;
  1956. return self.stringify(value);
  1957. });
  1958. params.text = params.text.replace(/\<\{param\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1959. var value = self.params[p2];
  1960. if (!value) undef = true;
  1961. return value;
  1962. });
  1963. // <{value:[id]}>
  1964. params.text = params.text.replace(/\<\{value\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1965. var value = $('#'+p1).val();
  1966. // https://www.geeksforgeeks.org/html-value-attribute/
  1967. if (!value) undef = true;
  1968. return value;
  1969. });
  1970. // <{user:[fieldName]}>
  1971. params.text = params.text.replace(/\<\{user\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1972. var value = self.user(p1);
  1973. if (!value) undef = true;
  1974. return self.stringify(value);
  1975. });
  1976. // <{time:timestamp}>
  1977. params.text = params.text.replace(/\<\{time\:timestamp\}\>/g, self.getTimestamp());
  1978. // <{result}>
  1979. if (params.args) {
  1980. params.args = self.stringify(params.args);
  1981. params.text = params.text.replace(/\<\{result\}\>/g, params.args);
  1982. }
  1983. // <{function:app.mac}>
  1984. params.text = params.text.replace(/\<?\{function:([^\}]*)\}\>?/g, function(match, p1, offset, string) {
  1985. var functionName = self.docElement(p1);
  1986. return functionName(selectorParams);
  1987. });
  1988. // <{random}>
  1989. params.text = params.text.replace(/\<\{random\:([^\-]+)\-([^\}]+)\}\>/g, function(match, p1, p2, offset, string) {
  1990. return Number(p1)+Math.round((p2-p1)*Math.random());
  1991. });
  1992. // <{firebaseKey:path}>
  1993. params.text = params.text.replace(/\<\{firebaseKey\:([^\}]*)\}\>/g, function(match, p1, offset, string) {
  1994. return self.firebaseKey(p1);
  1995. });
  1996. }
  1997. if (undef) return undefined
  1998. else return self.parse(params.text);
  1999. } else {
  2000. //self.log('params.text undefined or number or boolean');
  2001. return params.text;
  2002. }
  2003. } */
  2004. this.langText = function (textId) {
  2005. // find text in language and follow the capitalization of textId
  2006. // we could need text in langId language
  2007. if (textId) {
  2008. var textValue = textId;
  2009. if (typeof textId == 'string') {
  2010. if (self.json.texts[textId]) {
  2011. textValue = self.json.texts[textId];
  2012. if (typeof textValue == 'object')
  2013. textValue = textValue[self.json.setup.language] || textValue['en'] || textValue[Object.keys[0]];
  2014. }
  2015. else
  2016. textValue = textId;
  2017. } else if (typeof textId == 'object') {
  2018. textValue = textId[self.json.setup.language] || textId['en'] || textId[Object.keys[0]];
  2019. //textValue = textObj[langId] || textObj[self.json.setup.language] || textObj['en'];
  2020. }
  2021. return textValue;
  2022. } else {
  2023. return textId;
  2024. }
  2025. /* if (self.json.texts[textId])
  2026. textObj = self.json.texts[textId];
  2027. else if (self.json.texts[textId.toLowerCase()])
  2028. textObj = self.json.texts[textId.toLowerCase()];
  2029. //else if (self.json.texts[textId.toUpperCase()])
  2030. // textObj = self.json.texts[textId.toUpperCase()];
  2031. if (textObj) {
  2032. var textValue = textObj[self.json.setup.language] || textObj['en'] || textId;
  2033. if (textId.charAt(0) == textId.charAt(0).toUpperCase()) // first char uppercase
  2034. if (textId.charAt(1) == textId.charAt(1).toUpperCase())
  2035. return textValue.toUpperCase();
  2036. else
  2037. return textValue.replace(/\b\w/, l => l.toUpperCase()); // capitalize
  2038. // textValue = textValue.charAt(0).toUpperCase() + name.slice(1)
  2039. // style: text-transform: capitalize;
  2040. else
  2041. return textValue.toLowerCase();
  2042. } else {
  2043. return textId;
  2044. } */
  2045. /* } else {
  2046. self.log('textId undefined in langText');
  2047. } */
  2048. };
  2049. this.lang = function (params, args) {
  2050. if (args) {
  2051. var value = self.replaceProperties(params, args);
  2052. self.json.setup.language = value;
  2053. //alert(value);
  2054. self.log('lang');
  2055. self.log(value);
  2056. document.querySelectorAll('[data-text]').forEach(function (element, index) {
  2057. //$('*[data-text]').each(function( index ) {
  2058. var dataParams = self.dataStorage.get(element, 'params');
  2059. var selector = self.dataStorage.get(element, 'selector');
  2060. /* self.log('index');
  2061. self.log(index);
  2062. self.log('dataParams');
  2063. self.log(dataParams);
  2064. */
  2065. //alert(JSON.stringify(dataParams));
  2066. self.html(dataParams, { selector: selector });
  2067. //self.text($(this).data('params'), {container: this});
  2068. });
  2069. /*
  2070. var elements = document.querySelectorAll('[data-text]');
  2071. self.log('elements');
  2072. self.log(elements);
  2073. //var elements = document.querySelectorAll(selector);
  2074. if (elements)
  2075. elements.forEach(function (element, index) {
  2076. self.log(index);
  2077. //var dataParams = self.dataStorage.get(element, 'params');
  2078. var dataSelector = self.attribute(element, 'data-selector');
  2079. //self.text(dataParams, {container: dataSelector});
  2080. self.text($(dataSelector).data('params'), {container: dataSelector});
  2081. });
  2082. */
  2083. } else {
  2084. return self.json.setup.language;
  2085. }
  2086. };
  2087. // Determine whether is possible to write an image/text to the clipboard.
  2088. var isClipboardWritingAllowed = function () {
  2089. return new Promise(function (resolve, reject) {
  2090. try {
  2091. navigator.permissions.query({ name: "clipboard-write" }).then(function (status) {
  2092. // PermissionStatus object
  2093. // {
  2094. // onchange: null,
  2095. // state: "granted" (it could be as well `denied` or `prompt`)
  2096. // }
  2097. self.log(status);
  2098. resolve((status.state == "granted"));
  2099. });
  2100. } catch (error) {
  2101. // This could be caused because of a Browser incompatibility or security error
  2102. // Remember that this feature works only through HTTPS
  2103. reject(error);
  2104. }
  2105. });
  2106. };
  2107. this.codeSearch = function (params) {
  2108. let selector = params.selector || params.container;
  2109. // {container, word}
  2110. if (selector && params.word) {
  2111. var element = self.query(selector);
  2112. var editor = ace.edit(element);
  2113. var range = editor.find(params.word, {
  2114. wrap: true,
  2115. caseSensitive: true,
  2116. wholeWord: true,
  2117. regExp: false,
  2118. preventScroll: false // do not change selection
  2119. });
  2120. editor.session.selection.clearSelection();
  2121. editor.setOption("highlightActiveLine", true);
  2122. /* range.start.column = 0;
  2123. range.end.column = Number.MAX_VALUE;
  2124. //editor.session.replace(range, "x" + editor.session.getLine(range.start.row) + "x");
  2125. editor.selection.setRange(range); */
  2126. }
  2127. };
  2128. this.ace = function (params, selectorParams) {
  2129. // https://codepen.io/zymawy/pen/XwbxoJ
  2130. //self.log('code');
  2131. //self.log(params);
  2132. var selector = params.selector || params.container;
  2133. var container = selector || self.selector(selectorParams);
  2134. //paramsReplaced = self.cloneObject(params);
  2135. //paramsReplaced.value = self.actionResult(paramsReplaced.value);
  2136. var value = params.value;
  2137. // item from library
  2138. if (params.blocks && self.json.blocks)
  2139. if (self.json.blocks[params.blocks])
  2140. value = self.json.blocks[params.blocks];
  2141. else
  2142. self.log('"code" method can\'t find in "blocks" the element ' + params.blocks);
  2143. // json file
  2144. if (params.module) {
  2145. let moduleName = self.replaceProperties(params.module);
  2146. if (moduleName && self.modules[moduleName] !== undefined) {
  2147. value = self.modules[moduleName];
  2148. /* self.log('value');
  2149. self.log(value);
  2150. self.log(value); */
  2151. }
  2152. else
  2153. self.log('"code" method can\'t find the file ' + params.file);
  2154. }
  2155. if (params.var)
  2156. if (self.json.var)
  2157. value = self.var(params.var);
  2158. else
  2159. self.log('"code" method can\'t find the variable ' + params.blocks);
  2160. var element = self.query(container);
  2161. //var containerId = $(container).attr('id');
  2162. //self.log('containerId');
  2163. //self.log(containerId);
  2164. //var containerId = $(container).attr('id');
  2165. if (element) {
  2166. //var containerId = self.attribute(element, 'id'); // or assign a random unique id
  2167. var editor = ace.edit(element);
  2168. /* var keywordMapper = this.createKeywordMapper({
  2169. "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'
  2170. }, "identifier"); */
  2171. /* var staticWordCompleter = {
  2172. getCompletions: function(editor, session, pos, prefix, callback) {
  2173. 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'];
  2174. callback(null, wordList.map(function(word) {
  2175. return {
  2176. caption: word,
  2177. value: word,
  2178. meta: "static"
  2179. };
  2180. }));
  2181. }
  2182. }
  2183. //langTools.setCompleters([staticWordCompleter])
  2184. // or
  2185. editor.completers = [staticWordCompleter] */
  2186. /* if (editor)
  2187. AceColorPicker.load(ace, editor); */
  2188. //var value = paramsReplaced.value; // else value = params;
  2189. if (!params.do || (params.do == 'set')) {
  2190. //var langTools = ace.require('ace/ext/language_tools');
  2191. if (params.theme)
  2192. editor.setTheme(params.theme); // "ace/theme/monokai"
  2193. var editorMode = params.mode || "ace/mode/json";
  2194. editor.getSession().setMode(editorMode);
  2195. if (params.options)
  2196. editor.setOptions(params.options);
  2197. //AceColorPicker.load(ace, editor, {hideDelay: 1000});
  2198. //import AceColorPicker from 'ace-colorpicker';
  2199. /* editor.getSession().setMode(editorMode, () => {
  2200. AceColorPicker.load(ace); // , {hideDelay: 1000}
  2201. }); */
  2202. var editorStyle = self.extend({
  2203. //background: "rgba(255,255,255,0)"
  2204. }, params.style);
  2205. //$(container).css(editorStyle); //editor.container.style
  2206. self.css({
  2207. style: editorStyle
  2208. }, {
  2209. selector: container
  2210. });
  2211. //var aceOptions = params.options;
  2212. /* var aceOptions = self.extend({
  2213. fontSize: "12pt",
  2214. selectionStyle: "line",
  2215. //showGutter: false,
  2216. highlightGutterLine: false,
  2217. fixedWidthGutter: false,
  2218. //vScrollBarAlwaysVisible: true,
  2219. tabSize: 3,
  2220. //readOnly: true,
  2221. //enableBasicAutocompletion: false,
  2222. //enableSnippets: false,
  2223. //enableLiveAutocompletion: false,
  2224. }, params.options); */
  2225. // https://github.com/ajaxorg/ace/wiki/Configuring-Ace
  2226. var codeString;
  2227. if (typeof value == 'string')
  2228. if (editorMode == "ace/mode/json")
  2229. codeString = JSON.stringify(JSON.parse(value), null, '\t'); // json formatting
  2230. else
  2231. codeString = value;
  2232. else {
  2233. if (editorMode == "ace/mode/json")
  2234. codeString = JSON.stringify(value, null, '\t');
  2235. else {
  2236. var functionObj = self.docElement(value.function); //?
  2237. var functionParams = value.params;
  2238. codeString = functionObj(functionParams);
  2239. }
  2240. }
  2241. // should be {lines:dividcode}
  2242. if (codeString) {
  2243. var codeRows = codeString.split(/\r\n|\r|\n/).length;
  2244. /* $(container).css({
  2245. height: Number(21 * (codeRows)) + 'px'
  2246. }); */
  2247. /* self.log('element');
  2248. self.log(element);
  2249. self.log('container');
  2250. self.log(container);
  2251. self.log('codeRows');
  2252. self.log(codeRows); */
  2253. element.style.height = Number(21 * codeRows) + 'px';
  2254. //element.querySelector('.ace_scroller').querySelector('.ace_content').height = Number(21 * codeRows) + 'px';
  2255. /* self.css({
  2256. style: {
  2257. height: Number(21 * codeRows) + 'px'
  2258. }
  2259. }, {
  2260. container: container
  2261. }); */
  2262. editor.setValue(codeString, -1); // -1 unselect the code
  2263. //editor.renderer.updateFull(true);
  2264. //AceColorPicker.load(ace, ace.edit(containerId));
  2265. self.uiUpdate(); // resize event trigger
  2266. // workaround known ACE bug (.ace_content element doesn't follow the height until window resize)
  2267. }
  2268. if (params.on) {
  2269. var containerId = self.attribute(element, 'id'); // or assign a random unique id
  2270. self.codeChangeFunctions[containerId] = params.on;
  2271. //self.editorChangeFunctions[editor.id] = params.on;
  2272. if (params.on.change) {
  2273. editor.on('change', function (event, obj) {
  2274. /* self.log('event');
  2275. self.log(event);
  2276. self.log('obj');
  2277. self.log(obj); */
  2278. if (self.isJson(obj.getValue())) {
  2279. var code = JSON.parse(obj.getValue());
  2280. var action = self.codeChangeFunctions[obj.container.id].change;
  2281. //var methods = self.replaceResult(action, code);
  2282. var methods = self.replaceResult(action, code);
  2283. //var methods = self.replaceProperties(action, code);
  2284. // check on jsonic.io/play (methods is string instead of object)
  2285. /* self.log('code');
  2286. self.log(code);
  2287. self.log('method');
  2288. self.log(method);
  2289. self.log('-------------'); */
  2290. //self.do(methods);
  2291. self.do(methods);
  2292. //self.do(code, self.editorChangeFunctions[obj.id]);
  2293. //var container = self.editorChangeFunctions[obj.id].change.container;
  2294. } else {
  2295. // syntax error
  2296. }
  2297. //self.do(self.editorChangeFunctions[obj.id].change, JSON.parse(obj.getValue()));
  2298. //self.log(obj);
  2299. //self.blocks(JSON.parse(obj.getValue()), {container: });
  2300. });
  2301. }
  2302. // save key
  2303. // https://michilehr.de/overwrite-cmds-and-ctrls-in-javascript
  2304. }
  2305. } else if (params.do == 'get') {
  2306. return JSON.parse(editor.getValue());
  2307. } else if (params.do == 'update') {
  2308. self.uiUpdate(); // resize event trigger
  2309. // workaround known ACE bug (.ace_content element doesn't follow the height until window resize)
  2310. } else if (params.do == 'search') {
  2311. if (params.word) {
  2312. var range = editor.find(params.word, {
  2313. wrap: true,
  2314. caseSensitive: true,
  2315. wholeWord: true,
  2316. regExp: false,
  2317. preventScroll: false // do not change selection
  2318. });
  2319. editor.session.selection.clearSelection();
  2320. editor.setOption("highlightActiveLine", true);
  2321. /* range.start.column = 0;
  2322. range.end.column = Number.MAX_VALUE;
  2323. //editor.session.replace(range, "x" + editor.session.getLine(range.start.row) + "x");
  2324. editor.selection.setRange(range); */
  2325. }
  2326. } else if (params.do == 'find') {
  2327. // toggle
  2328. editor.execCommand('find');
  2329. //editor.searchBox.show();
  2330. } else if (params.do == 'copy') {
  2331. // Select the whole content of the editor
  2332. editor.selectAll();
  2333. // Store text that will be copied to clipboard
  2334. let copyText = editor.getCopyText();
  2335. // Verify if clipboard writing is allowed
  2336. isClipboardWritingAllowed().then(function (allowed) {
  2337. // Write to clipboard if allowed
  2338. if (allowed) {
  2339. navigator.clipboard.writeText(copyText).then(function () {
  2340. editor.getSession().selection.clearSelection();
  2341. //self.log("Code copied!");
  2342. });
  2343. }
  2344. }).catch(function (err) {
  2345. self.log("Cannot copy to clipboard", err);
  2346. });
  2347. } else {
  2348. self.log('"code" function requires value param');
  2349. }
  2350. } else {
  2351. self.log('"code" method can\'t select the container');
  2352. self.log('container');
  2353. self.log(container);
  2354. self.log('element');
  2355. self.log(element);
  2356. }
  2357. };
  2358. // TO DO: should be in the app var and reset on a new execution
  2359. this.codeChangeFunctions = {};
  2360. this.editorChangeFunctions = {};
  2361. this.quillElements = {};
  2362. this.text = function (params, selectorParams, args) {
  2363. /*
  2364. {
  2365. "text": / "string": / textId -> textId "{text:textId}"
  2366. "case": [up, down, capitalize]
  2367. }
  2368. */
  2369. /* if (Array.isArray(params)) {
  2370. for (var obj of params)
  2371. self.text(obj, selectorParams, args);
  2372. } else { */
  2373. var textKey;
  2374. var textCase;
  2375. var textArgs;
  2376. var textLang;
  2377. var langId;
  2378. var selector, element;
  2379. //var textAction;
  2380. if (typeof params == 'object') {
  2381. if (selectorParams && selectorParams.isConnected) { // Check if an element is attached to DOM
  2382. element = selectorParams;
  2383. //selector = self.dataStorage.get(element, 'selector');
  2384. //selector = element.getAttribute('data-selector');
  2385. selector = self.elementToSelector(element); // 1.0.12
  2386. } else {
  2387. selector = self.selector(self.extend({}, params, selectorParams));
  2388. element = self.query(selector);
  2389. }
  2390. // todo: REMOVE (check the menu)
  2391. //textAction = self.actionResult(params, textArgs);
  2392. //textAction = params;
  2393. //textKey = params.string; // || params.text || params.title; // params.key to be removed?
  2394. textCase = params.case; // use text-transform uppercase lowercase capitalize
  2395. textArgs = params.args; // deve diventare args (secondo parametro) al posto di caseFunction
  2396. //langId = params.langId;
  2397. if (typeof params == 'object') {
  2398. textKey = params.key || params.string || params; // || params.text || params.title; // params.key to be removed?
  2399. //textCase = params.case; // use text-transform uppercase lowercase capitalize
  2400. //textArgs = params.args; // deve diventare args (secondo parametro) al posto di caseFunction
  2401. //langId = params.langId;
  2402. } else {
  2403. textKey = params;
  2404. }
  2405. /* self.log('textKey');
  2406. self.log(textKey); */
  2407. } else if (typeof params == 'string') {
  2408. textKey = params;
  2409. /* self.log('textKey');
  2410. self.log(textKey); */
  2411. //textCase = caseFunction;
  2412. if (selectorParams) {
  2413. if (selectorParams.isConnected) { // Check if an element is attached to DOM
  2414. element = selectorParams;
  2415. selector = self.dataStorage.get(element, 'selector');
  2416. } else {
  2417. selector = self.selector(selectorParams);
  2418. element = self.query(selector);
  2419. }
  2420. } else {
  2421. // here when windowTitle += ' ' + self.text(page.title); // window title
  2422. }
  2423. }
  2424. if (typeof textKey == 'string') {
  2425. /* // TO DO: remove
  2426. if (textKey.startsWith('js:')) textKey = self.js(textKey.substr(3));
  2427. else if (textKey.startsWith('db:')) textKey = self.element({path: 'var.db.'+textKey.substr(3)});
  2428. else if (textKey.startsWith('var:')) textKey = self.element({path: 'var.'+textKey.substr(4)});
  2429. else if (textKey.startsWith('data:')) textKey = self.element({path: 'data.'+textKey.substr(5)});
  2430. else
  2431. // ----- */
  2432. /* console.log('textKey');
  2433. console.log(textKey); */
  2434. textKey = self.replaceProperties(textKey, textArgs);
  2435. /* console.log('textKey');
  2436. console.log(textKey); */
  2437. }
  2438. //self.log('selector');
  2439. //self.log(selector);
  2440. //self.log(selector.isConnected);
  2441. /* self.log('HOTSPOT');
  2442. self.log(params);
  2443. self.log(self.json.setup.language); */
  2444. if (params && params.lang) { // multi-language text
  2445. //self.log('params.lang definito');
  2446. textLang = self.langText(params.lang); // , langId
  2447. //textLang = params.lang[self.json.setup.language] || params.lang['en'] || params.lang[Object.keys[0]];
  2448. textLang = self.replaceProperties(textLang, textArgs);
  2449. /* self.log('textLang');
  2450. self.log(textLang);
  2451. self.log('element');
  2452. self.log(element); */
  2453. if (textCase) textLang = self.textCase(textLang, textCase);
  2454. //self.log('textLang');
  2455. //self.log(textLang);
  2456. if (element) {
  2457. element.textContent = textLang;
  2458. self.attribute(element, 'data-text', true); // textKey instead of lang?
  2459. self.dataStorage.set(element, 'params', params);
  2460. //$(selector).data('params', params);
  2461. }
  2462. } else {
  2463. //self.log('params.lang non definito');
  2464. //if (!textKey) textKey = params;
  2465. if (textKey) {
  2466. //textKey = self.compile(textKey, textArgs); // TO DO: verify
  2467. /* self.log('textKey');
  2468. self.log(textKey); */
  2469. //if (!textKey) alert(JSON.stringify(params));
  2470. //if (typeof textKey == 'object') {
  2471. // textLang = JSON.stringify(textKey, null, '\t');
  2472. //} else {
  2473. //textLang = params.lang[self.json.setup.language] || params.lang['en'] || params.lang[Object.keys[0]];
  2474. if (textKey.lang) // multi-language text
  2475. textLang = self.langText(textKey.lang); // , langId
  2476. else
  2477. textLang = textKey;
  2478. /* self.log('textLang1');
  2479. self.log(textLang); */
  2480. textLang = self.replaceProperties(textLang, textArgs); // move after textLang = self.langText(textKey.lang);
  2481. if (textCase) textLang = self.textCase(textLang, textCase);
  2482. //}
  2483. /* self.log('textLang2');
  2484. self.log(textLang); */
  2485. //if (selector) { // set
  2486. if (element) { // set
  2487. if (self.json.texts[textKey]) {
  2488. // save data-text for lang change
  2489. //$(selector).data('params', params);
  2490. //$(selector).attr('data-text', textKey);
  2491. self.attribute(element, 'data-text', true);
  2492. self.dataStorage.set(element, 'params', params);
  2493. }
  2494. // obsolete
  2495. /* if (params.background) $(selector).css({'background': params.background});
  2496. if (params.color) $(selector).css({'color': params.color});
  2497. if (params.size) $(selector).css({'font-size': params.size}); */
  2498. if (params.style)
  2499. self.css({
  2500. style: params.style
  2501. }, {
  2502. selector: selector
  2503. });
  2504. //$(selector).css(params.style);
  2505. element.textContent = textLang; // put text in element
  2506. //$(selector).text(textLang);
  2507. } else { // get
  2508. return textLang;
  2509. }
  2510. } else {
  2511. /* self.log('"string" parameter required in text object');
  2512. self.log(params); */
  2513. return params;
  2514. }
  2515. }
  2516. };
  2517. var caseUp = function (string) {
  2518. return string.toUpperCase();
  2519. };
  2520. var caseDown = function (string) {
  2521. return string.toLowerCase();
  2522. };
  2523. var capitalize = function (string) {
  2524. return self.capitalize(string);
  2525. };
  2526. this.textCase = function (textParam, caseParam) {
  2527. if (textParam) {
  2528. var text = textParam;
  2529. switch (caseParam) {
  2530. case 'up':
  2531. text = text.toUpperCase();
  2532. break;
  2533. case 'down':
  2534. text = text.toLowerCase();
  2535. break;
  2536. case 'capitalize':
  2537. text = self.capitalize(text);
  2538. break;
  2539. }
  2540. return text;
  2541. } else {
  2542. self.log('textParam undefined in textCase');
  2543. }
  2544. };
  2545. /* this.textFit = function (selector,params) {
  2546. if (params.alignHoriz == undefined) {
  2547. params.alignHoriz = true;
  2548. }
  2549. if (params.alignVert == undefined) {
  2550. params.alignVert = true;
  2551. }
  2552. if (params.minFontSize) {
  2553. params.minFontSize = parseInt(params.minFontSize, 10); // remove px
  2554. }
  2555. if (params.maxFontSize) {
  2556. params.maxFontSize = parseInt(params.maxFontSize, 10); // remove px
  2557. }
  2558. // textFit va in errore se l'oggetto diventa invisibile
  2559. // mentre sta elaborando la dimensione del testo
  2560. if (!$(selector).children('span').hasClass('textFitted')) {
  2561. $(selector).each(function(i, obj) {
  2562. if ($(obj).is(":visible")
  2563. && ($(obj).css("display") !== 'none')
  2564. && ($(obj).css('width'))
  2565. && ($(obj).css('height'))) {
  2566. textFit($(obj), params);
  2567. }
  2568. });
  2569. }
  2570. } */
  2571. /* this.data = function (path, value) {
  2572. if (!value) return self.json.var;
  2573. }
  2574. this.setvar = function (data) {
  2575. var = self.data();
  2576. self.data(data);
  2577. } */
  2578. // --------------
  2579. // PAGES
  2580. // --------------
  2581. /* this.lastInteraction = function () {
  2582. // uso: self.lastInteraction().asMinutes()
  2583. var lastInteraction = 0;
  2584. if (var.touchTime) lastInteraction = moment(var.touchTime);
  2585. var thisMoment = moment();
  2586. var duration = moment.duration(thisMoment.diff(lastInteraction));
  2587. return duration
  2588. } */
  2589. // --------------
  2590. // icons e
  2591. // --------------
  2592. /* this.icons = this.icon = function (params, selectorParams, args) {
  2593. // { [container, class, value, id]
  2594. // [html, text, append, prepend] }
  2595. if (Array.isArray(params)) {
  2596. for (var index in params)
  2597. {self.icons(params[index], selectorParams);}
  2598. } else {
  2599. if (params.items) {
  2600. var itemsArray = params.items;
  2601. delete params.items;
  2602. for (var index in itemsArray) {
  2603. self.icons(self.replaceItems(params, itemsArray[index]), selectorParams);
  2604. }
  2605. } else {
  2606. //if (selectorParams) params = self.extend(params, selectorParams);
  2607. var paramsReplaced = self.replaceProperties(params, args);
  2608. self.log('icons');
  2609. self.log('paramsReplaced');
  2610. self.log(paramsReplaced);
  2611. if (paramsReplaced) {
  2612. if (paramsReplaced.disabled == true)
  2613. self.disableIcon(paramsReplaced, selectorParams);
  2614. else if (paramsReplaced.disabled == false)
  2615. self.enableIcon(paramsReplaced, selectorParams);
  2616. else if (paramsReplaced.change)
  2617. self.changeItem(paramsReplaced, selectorParams);
  2618. else
  2619. self.addItem(paramsReplaced, selectorParams);
  2620. }
  2621. if (paramsReplaced.firebase) self.addFirebaseTag(paramsReplaced);
  2622. var selector = self.selector(self.extend(paramsReplaced, selectorParams));
  2623. if (paramsReplaced.span) // text near icon
  2624. self.addTag(paramsReplaced, {container: selector});
  2625. }
  2626. }
  2627. } */
  2628. /* this.buttons = this.tab = function (params, selectorParams) {
  2629. // { [container, class, value, id]
  2630. // [html, text, append, prepend] }
  2631. if (Array.isArray(params)) {
  2632. for (var index in params)
  2633. self.tab(params[index], selectorParams);
  2634. } else {
  2635. if (params.items) {
  2636. var itemsArray = params.items;
  2637. delete params.items;
  2638. for (var index in itemsArray) {
  2639. self.tab(self.replaceItems(params, itemsArray[index]), selectorParams);
  2640. }
  2641. } else {
  2642. // se necessario, replaceProperties dovrebbe escludere il contenuto di events/action
  2643. // in quanto verrà ripetuto sulle azioni in tempo reale solo dove necessario
  2644. //params = self.replaceProperties(params);
  2645. if (!params.class) params.class = '';
  2646. var classes = params.class.split(' ');
  2647. if (params.change) {
  2648. if (classes.includes('icon'))
  2649. self.changeItem(params, selectorParams);
  2650. else // if (classes.includes('tabs'))
  2651. self.changeTab(params, selectorParams);
  2652. } else {
  2653. if (classes.includes('icon'))
  2654. self.addItem(params, selectorParams);
  2655. else // if (classes.includes('tabs'))
  2656. self.addTab(params, selectorParams);
  2657. }
  2658. if (params.firebase) self.addFirebaseTag(params);
  2659. }
  2660. }
  2661. }
  2662. */
  2663. /*
  2664. this.replacePropertyNew = function (params, name, args) {
  2665. console.log('replacePropertyNew');
  2666. // like replaceProperties but only for {name:...} property
  2667. var paramsString;
  2668. if (typeof paramsString !== 'string') {paramsString = JSON.stringify(self.cloneObject(params));}
  2669. // remove string quotes for object property
  2670. if (args && paramsString && paramsString.indexOf('{')>= 0) {
  2671. //if (args && paramsString && /{\w/.test(paramsString)) {
  2672. paramsString = paramsString.replace(/\"\{(\w+\:)?([\w\s\.\:]+)\}\"/g, function(match, p1, p2, offset, string) {
  2673. var value;
  2674. if (p1 && p1.endsWith(':')) {p1 = p1.slice(0, -1);}
  2675. console.log('match:'+match);
  2676. console.log('p1:'+p1);
  2677. console.log('p2:'+p2);
  2678. if (p1 == name || (!p1 && p2 == name)) {
  2679. let nameFound = p1 || p2;
  2680. let pathFound = (p1) ? p2 : undefined;
  2681. console.log(nameFound+':'+pathFound);
  2682. if (typeof args !== 'string') {
  2683. //return self.replaceAll(self.stringify(args), '\"', '\'');
  2684. return self.stringify(args);
  2685. } else {
  2686. return '"' + args + '"';
  2687. }
  2688. } else
  2689. return match;
  2690. });
  2691. //console.log('paramsString without quotes');
  2692. //console.log(paramsString);
  2693. paramsString = paramsString.replace(/\{(\w+\:)?([\w\s\.\:]+)\}/g, function(match, p1, p2, offset, string) {
  2694. var value;
  2695. if (p1 && p1.endsWith(':')) {p1 = p1.slice(0, -1);}
  2696. if (p1 == name || (!p1 && p2 == name)) {
  2697. let nameFound = p1 || p2;
  2698. let pathFound = (p1) ? p2 : undefined;
  2699. console.log(nameFound+':'+pathFound);
  2700. self.partSetup = args;
  2701. if (pathFound) {
  2702. value = self.docElement('self.partSetup.'+pathFound);
  2703. } else {
  2704. value = args;
  2705. }
  2706. console.log('value:'+value);
  2707. delete self.partSetup;
  2708. } else {
  2709. value = match
  2710. }
  2711. if (typeof value !== 'string') value = self.stringify(value);
  2712. return value;
  2713. });
  2714. if (self.isJsonString(paramsString)) {// (typeof params == 'object')
  2715. console.log('isJsonString');
  2716. var paramsObj = self.parse(paramsString);
  2717. return paramsObj;
  2718. } else {
  2719. console.log('NOT isJsonString');
  2720. console.log(paramsString);
  2721. // TO DO: log of wrong json string
  2722. return paramsString;
  2723. }
  2724. } else {
  2725. return params
  2726. }
  2727. }
  2728. */
  2729. this.replaceUndefined = function (params) {
  2730. let value, defaultValue;
  2731. //if (params.path == 'badge') alert();
  2732. if (typeof params.path !== undefined) {
  2733. if (params.path.indexOf('|') > 0)
  2734. [params.path, defaultValue] = params.path.split('|');
  2735. value = self.element({ path: params.path, root: params.root });
  2736. }
  2737. if (value == undefined || value == null) { // empty string is false
  2738. if (typeof defaultValue !== undefined)
  2739. value = defaultValue;
  2740. else {
  2741. if (params.removeUndefined) { //p1 == 'args' || p1 == 'selector') {
  2742. value = ''; // remove undefined values
  2743. } else {
  2744. value = params.match;
  2745. self.log(value + ' not found', 'yellow');
  2746. }
  2747. }
  2748. } else {
  2749. //console.log('match:'+params.match);
  2750. //if (params.removeUndefined) value = '';
  2751. }
  2752. return value;
  2753. };
  2754. //value = self.replaceUndefined({match: '{'+match+'}', id:p1, removeUndefined: removeUndefined});
  2755. this.replaceProperties = function (params, args, removeUndefined) {
  2756. // TO DO: remove fieldsObj. can't find replaceProperties with 3 args
  2757. // the third parameter can be removeUndefined
  2758. // test with a firebase app like elio
  2759. var paramsString;
  2760. var paramOn, paramDo, paramSuccess, paramError, paramEvents, paramConfirm;
  2761. if (typeof params == 'string') {
  2762. paramsString = params;
  2763. } else {
  2764. //paramsString = JSON.stringify(params);
  2765. var paramsObj = self.cloneObject(params);
  2766. if (paramsObj) {
  2767. if (paramsObj.on) { paramOn = paramsObj.on; delete paramsObj.on; }
  2768. if (paramsObj.success) { paramSuccess = paramsObj.success; delete paramsObj.success; }
  2769. if (paramsObj.error) { paramError = paramsObj.error; delete paramsObj.error; }
  2770. if (paramsObj.events) { paramEvents = paramsObj.events; delete paramsObj.events; } // TO DO: remove
  2771. if (paramsObj.confirm) { paramConfirm = paramsObj.confirm; delete paramsObj.confirm; } // TO DO: check it
  2772. if (paramsObj.do) { paramDo = paramsObj.do; delete paramsObj.do; }
  2773. }
  2774. paramsString = JSON.stringify(paramsObj);
  2775. }
  2776. /* self.log("paramsString");
  2777. self.log(paramsString); */
  2778. if (paramsString && paramsString.indexOf('{') >= 0) {
  2779. paramsString = paramsString.replace(/\"\{([\w\s\.]+)\}\"/g, function (match, p1, offset, string) {
  2780. var value;
  2781. if (p1) {
  2782. //self.log('p1:' + p1);
  2783. //value = self.element({path: p1}); // || match;
  2784. value = self.replaceUndefined({ match: '{' + match + '}', path: p1, removeUndefined: removeUndefined });
  2785. if (value) {
  2786. if (value.isConnected) return self.elementToSelector(value); // DOM element to CSS selector
  2787. if (typeof value !== 'string')
  2788. return self.stringify(value); // object or array to string (TO DO: check numbers)
  2789. else {
  2790. //console.warn('we are here');
  2791. return '"' + value + '"';
  2792. }
  2793. }
  2794. else
  2795. return '""';
  2796. } else {
  2797. return '""';
  2798. }
  2799. });
  2800. paramsString = paramsString.replace(/\{(\w+\:)?([\w\s\->|\/=\.:#&;,\[\]\']+)\}/g, function (match, p1, p2, offset, string) {
  2801. /*
  2802. Firebase references may contain any unicode characters except:
  2803. . (period)
  2804. $ (dollar sign)
  2805. [ (left square bracket)
  2806. ] (right square bracket)
  2807. # (hash or pound sign)
  2808. / (forward slash)
  2809. */
  2810. /* self.log("paramstring");
  2811. self.log(match, p1, p2); */
  2812. // self.log(match, p1, p2);
  2813. var value;
  2814. if (p1) {
  2815. if (p1.endsWith(':')) {
  2816. p1 = p1.slice(0, -1); // remove the final ":"
  2817. // check if is a function name (in this.json.functions)
  2818. if (self.functions[p1]) {
  2819. //value = self.functions[p1](JSON.parse(p2));
  2820. let funcArgs = p2.split('|');
  2821. /* console.warn('p2');
  2822. console.warn(p2);
  2823. console.warn('funcArgs');
  2824. console.warn(funcArgs); */
  2825. // if Number(funcArgs[i]) == funcArgs[i] -> funcArgs[i] = Number(funcArgs[i]);
  2826. value = self.function({ name: p1, arguments: [funcArgs] });
  2827. } else {
  2828. switch (p1) {
  2829. /* case 'hasClass':
  2830. var element = document.querySelector(p2);
  2831. if (p3)
  2832. value = self.hasClass(el,p3);
  2833. else
  2834. value = false; el:selector.class (esiste l'elemento selector.class o l'elemento selector ha la classe class)
  2835. break; */
  2836. // 'isVisible', 'isHidden', 'isDisplay', 'inViewport', 'outViewport', 'notClass', 'hasClass'
  2837. // hasClass da aggiungere come funzione css
  2838. // html markups
  2839. // 'b:string' 'i:string' 'u:string' 'a:STRING|URL'
  2840. /* case 'i': case 'b': case 'u': case 'strong': case 'em': case 'mark': case 'del': case 'ins': case 'sub': case 'sup':
  2841. value = '<'+p1+'>'+p2+'</'+p1+'>';
  2842. break;
  2843. case 'a':
  2844. // example: "{a:text|href:....|target:_blank}"
  2845. let props = p2.split('|'); // or indexOf(':') prima occorrenza
  2846. let string = props.shift();
  2847. var propsString = '';
  2848. for (var prop of props) {
  2849. //let propArr = prop.split(':'), propName = propArr[0], propValue = propArr[1];
  2850. propsString += ' ' + prop;
  2851. }
  2852. if (propsString == '') propsString = ' href="'+string+'"';
  2853. value = '<a'+propsString+'>'+string+'</a>';
  2854. // https://stackoverflow.com/questions/1547899/which-characters-make-a-url-invalid
  2855. // https://www.w3schools.com/tags/tag_a.asp
  2856. break;
  2857. */
  2858. // DOM properties
  2859. case 'visible':
  2860. var element = document.querySelector(p2); // self.query(p2);
  2861. value = (element && self.isVisible(element));
  2862. //value = ($(p2).is(':visible'));
  2863. break;
  2864. case 'number':
  2865. value = Number(p2);
  2866. break;
  2867. case 'string':
  2868. value = String(p2);
  2869. break;
  2870. case 'js': // deprecated (too much special characters like {})
  2871. try {
  2872. value = eval(p2);
  2873. } catch (error) {
  2874. value = '';
  2875. self.log('javascript error on ' + p2);
  2876. self.log(error);
  2877. }
  2878. break;
  2879. /* case 'item':
  2880. if (fieldsObj) {
  2881. //self.log('fieldsObj['+p2+']:'+fieldsObj[p2]);
  2882. value = fieldsObj[p2] || ''; //|| p2+'=NULL';
  2883. } else {
  2884. //self.log('p2:'+p2);
  2885. //self.log('fieldsObj == undefined');
  2886. value = '{'+p1+':'+p2+'}';
  2887. }
  2888. break; */
  2889. /* case 'item':
  2890. case 'items':
  2891. value = self.docElement('self.json.items.'+p2);
  2892. break; */
  2893. /* case 'frame':
  2894. var element = self.query(p2);
  2895. element.contentWindow
  2896. break; */
  2897. /* case 'field':
  2898. if (fieldsObj) {
  2899. //self.log('fieldsObj['+p2+']:'+fieldsObj[p2]);
  2900. value = fieldsObj[p2] || ''; // || p2+'=NULL';
  2901. } else {
  2902. //self.log('p2:'+p2);
  2903. //self.log('fieldsObj == undefined');
  2904. value = '';
  2905. }
  2906. break; */
  2907. /* case 'setup':
  2908. value = self.docElement('self.json.setup.'+p2) || match;
  2909. break; */
  2910. /*
  2911. case 'setup':
  2912. if (args) {
  2913. self.partSetup = args;
  2914. value = self.docElement('self.partSetup.'+p2);
  2915. delete self)Setup;
  2916. } else {
  2917. value = '';
  2918. }
  2919. break; */
  2920. case 'wp':
  2921. case 'wordpress':
  2922. // TO DO: should get/set data with jsonic.get/setWordpressData
  2923. // setWordpressData can be done automatically in the init
  2924. value = self.docElement('self.json.setup.wordpress.' + p2) ?? match;
  2925. //alert(value);
  2926. //if (value.indexOf('"') >= 0)
  2927. // value = self.replaceAll(value, '"', '\\"');
  2928. // the first should replace only " and not \" but it doesn't works
  2929. //value = value.replaceAll(/([^\\\"])\"/g, '$1\\"');
  2930. break;
  2931. case 'plugins':
  2932. value = self.json.resources.pluginsFunctions[p2];
  2933. if (value && !Array.isArray(value)) value = [value];
  2934. else value = [];
  2935. /* self.log('plugins');
  2936. self.log('value');
  2937. self.log(value); */
  2938. /* value = plugins;
  2939. for (plugin of plugins) {
  2940. value = self.json.resources.pluginsFunctions[p2].name || 'unknown plugin required';
  2941. } */
  2942. break;
  2943. case 'database':
  2944. case 'db':
  2945. value = self.docElement('self.json.var.db.' + self.replaceProperties(p2, args));
  2946. break;
  2947. // shorteners (useful?)
  2948. case 'media': // or m or src
  2949. if (self.json.setup && self.json.data.media)
  2950. value = self.docElement('self.json.data.media.' + p2) || match;
  2951. else
  2952. value = match;
  2953. break;
  2954. case 'color': // or col
  2955. if (self.json.data && self.json.data.colors)
  2956. value = self.docElement('self.json.data.colors.' + p2) || match;
  2957. else
  2958. value = match;
  2959. break;
  2960. case 'class': // or cla
  2961. if (self.json.data && self.json.data.class)
  2962. value = self.docElement('self.json.data.class.' + p2) || match;
  2963. else
  2964. value = match;
  2965. break;
  2966. case 'text':
  2967. value = self.langText(p2);
  2968. break;
  2969. case 'param':
  2970. value = self.params[p2] || ''; // || p2+'=NULL';
  2971. break;
  2972. case 'height':
  2973. /* self.log('{height:p2}');
  2974. self.log('p2');
  2975. self.log(p2); */
  2976. var element = document.querySelector(p2); // self.query(p2);
  2977. if (element) // && self.isVisible(element)
  2978. //value = getComputedStyle(element, null).height;
  2979. value = element.offsetHeight + 'px';
  2980. //if ($(p2).is(':visible'))
  2981. //value = $(p2).height() + 'px'
  2982. else
  2983. value = '0px';
  2984. break;
  2985. case 'offsetWidth':
  2986. var element = document.querySelector(p2); // self.query(p2);
  2987. if (element) // && self.isVisible(element)
  2988. //value = getComputedStyle(element, null).height;
  2989. value = element.offsetWidth;
  2990. //if ($(p2).is(':visible'))
  2991. //value = $(p2).height() + 'px'
  2992. else
  2993. value = '0';
  2994. break;
  2995. case 'width':
  2996. var element = document.querySelector(p2); // self.query(p2);
  2997. if (element) // && self.isVisible(element)
  2998. //value = getComputedStyle(element, null).height;
  2999. value = element.offsetWidth + 'px';
  3000. //if ($(p2).is(':visible'))
  3001. //value = $(p2).height() + 'px'
  3002. else
  3003. value = '0px';
  3004. break;
  3005. case 'local':
  3006. value = self.methods.local.get(p2);
  3007. //self.log('{localStorage:cart}');
  3008. //self.log(value);
  3009. break;
  3010. case 'ace':
  3011. var element = document.querySelector(p2);
  3012. if (element) {
  3013. var editor = ace.edit(element);
  3014. value = JSON.parse(editor.getValue());
  3015. }
  3016. //self.log('{localStorage:cart}');
  3017. //self.log(value);
  3018. break;
  3019. /* case 'innerText':
  3020. var element = document.querySelector(p2);
  3021. value = (element) ? element.innerText : undefined;
  3022. self.log('p1:'+p1);
  3023. self.log('p2:'+p2);
  3024. self.log('value:'+value);
  3025. //.trisBox[data-value="0"]
  3026. break;
  3027. case 'innerHtml':
  3028. var element = document.querySelector(p2);
  3029. value = (element) ? element.innerHTML : undefined;
  3030. break; */
  3031. case 'shuffle':
  3032. value = self.element({ path: p2 });
  3033. value = self.methods.shuffle(value);
  3034. break;
  3035. case 'select':
  3036. case 'input':
  3037. case 'value': // deprecated
  3038. var element = document.querySelector(p2); // self.query(p2);
  3039. value = (element) ? String(element.value || '') : '';
  3040. //value = $('#'+p2).val() || ''; //|| p2+'=NULL';
  3041. // input field value
  3042. // https://www.geeksforgeeks.org/html-value-attribute/
  3043. break;
  3044. case 'user':
  3045. if (p2 == 'in') {
  3046. value = self.userIn();
  3047. } else if (p2 == 'out')
  3048. value = self.userOut();
  3049. else
  3050. value = self.user(p2) || match; //|| p2+'=NULL';
  3051. break;
  3052. // can go in objects
  3053. case 'length':
  3054. var varObj = self.element({ path: p2 }); // to get also js objects length
  3055. //var varObj = self.docElement('self.json.'+p2);
  3056. if (varObj)
  3057. if (typeof varObj == 'object')
  3058. value = Object.keys(varObj).length;
  3059. else
  3060. value = varObj.length;
  3061. else
  3062. self.log('' + p2 + ' is undefined');
  3063. break;
  3064. case 'Date':
  3065. case 'time':
  3066. if (p2 == 'timeZone') value = new Intl.DateTimeFormat().resolvedOptions().timeZone;
  3067. else if (p2 == 'weekday') value = self.weekday();
  3068. else if (p2 == 'stamp') value = self.getTimestamp();
  3069. else if (p2 == 'timestamp') value = self.getTimestamp();
  3070. else if (p2 == 'getTimestamp') value = self.getTimestamp();
  3071. else if (p2 == 'getDay') value = new Date().getDay();
  3072. else if (p2 == 'getDate') value = new Date().getDate();
  3073. else if (p2 == 'getMonth') value = new Date().getMonth();
  3074. else if (p2 == 'getFullYear') value = new Date().getFullYear();
  3075. else if (p2 == 'getTime') value = new Date().getTime(); // timestamp
  3076. else if (p2 == 'getSeconds') value = new Date().getSeconds();
  3077. else if (p2 == 'getMinutes') value = new Date().getMinutes();
  3078. else if (p2 == 'getHours') value = new Date().getHours();
  3079. // second, minute, hour, weekday, day, month, year
  3080. else value = p2 + '=NULL';
  3081. break;
  3082. case 'now':
  3083. // ...
  3084. break;
  3085. case 'month':
  3086. var month = (p2 == 'today' || p2 == undefined) ? new Date().getMonth() : Number(p2);
  3087. value = self.month(month);
  3088. break;
  3089. case 'weekday': // format: long, short, narrow
  3090. var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2);
  3091. value = self.calendar({ index: Number(day), unit: 'weekday', format: 'long' });
  3092. break;
  3093. case 'weekdayNarrow': // format: long, short, narrow
  3094. var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2);
  3095. value = self.calendar({ index: Number(day), unit: 'weekday', format: 'narrow' });
  3096. break;
  3097. case 'weekdayShort': // format: long, short, narrow
  3098. var day = (p2 == 'today' || p2 == undefined) ? new Date().getDay() : Number(p2);
  3099. value = self.calendar({ index: Number(day), unit: 'weekday', format: 'short' });
  3100. break;
  3101. case 'moment':
  3102. var timeFormat = (p2) ? p2 : '';
  3103. value = moment().format(timeFormat);
  3104. break;
  3105. case 'dayjs': // TO DO: check
  3106. var timeFormat = (p2) ? p2 : '';
  3107. value = dayjs().format(timeFormat);
  3108. break;
  3109. case 'Math':
  3110. value = self.Math(p2);
  3111. break;
  3112. case 'action':
  3113. case 'do':
  3114. self.log('do');
  3115. self.log('p2');
  3116. self.log(p2);
  3117. //value = self.do(p2); // || match; // TO DO: log error
  3118. value = self.do(p2); // || match; // TO DO: log error
  3119. //var functionName = self.docElement(p2);
  3120. //value = (functionName) ? functionName(functionName) : p2+'=NULL'
  3121. break;
  3122. /* WITH ARGS */
  3123. case 'method':
  3124. var method = self.element({ path: p2, root: self.methods });
  3125. if (method) {
  3126. value = method(args); // how to pass args? needs p3
  3127. } else {
  3128. value = match;
  3129. }
  3130. break;
  3131. case 'function': // TO DO: remove
  3132. var func = self.element({ path: p2, root: self.functions });
  3133. if (func) {
  3134. value = func(args); // how to pass args? needs p3
  3135. } else {
  3136. value = match;
  3137. }
  3138. break;
  3139. case 'on':
  3140. /* self.log('args');
  3141. self.log(args); */
  3142. if (args) {
  3143. self.onResult = args;
  3144. value = self.docElement('self.onResult.' + p2);
  3145. //alert(JSON.stringify(value));
  3146. delete self.onResult;
  3147. } else {
  3148. //alert(JSON.stringify(value));
  3149. value = match;
  3150. }
  3151. //value = ($(p2).is(':visible'));
  3152. break;
  3153. case 'ajax':
  3154. if (args) {
  3155. self.ajaxResult = args; // -> self.json.var.ajaxData[self.json.var.ajaxId] = args.response
  3156. //alert(JSON.stringify(args));
  3157. value = self.docElement('self.ajaxResult.' + p2);
  3158. delete self.ajaxResult;
  3159. } else {
  3160. //alert(JSON.stringify(value));
  3161. value = match;
  3162. }
  3163. //value = ($(p2).is(':visible'));
  3164. break;
  3165. /* case 'function': // TO DO: remove
  3166. //self.log('function');
  3167. //self.log('p2');
  3168. //self.log(p2); // app.mac
  3169. value = self.function(p2) || match; // TO DO: log error
  3170. //var functionName = self.docElement(p2);
  3171. //value = (functionName) ? functionName(functionName) : p2+'=NULL'
  3172. break; */
  3173. case 'if': // TO DO: remove (can't manage spacial characters !<>'' etc)
  3174. p2 = self.replaceProperties(p2);
  3175. var ifArr = p2.split('|');
  3176. if (self.js(ifArr[0])) value = true;
  3177. if (ifArr.length > 1 && value) value = ifArr[1];
  3178. if (ifArr.length > 2 && !value) value = ifArr[2];
  3179. break;
  3180. case 'random':
  3181. /* var random = p2.replace(/([^\-]+)\-([^\}]+)/g, function(match, n1, n2, offset, string) {
  3182. return Number(n1)+Math.round((n2-n1)*Math.random());
  3183. }); */
  3184. value = String(Math.floor(Number(p2) * Math.random()));
  3185. //self.log('random value: '+value);
  3186. //value = random; //p2+' format is wrong'
  3187. // CHANGE TO {math.random:max}
  3188. break;
  3189. case 'getKey':
  3190. case 'firebaseKey':
  3191. value = self.firebaseKey(p2);
  3192. // https://firebase.google.com/docs/reference/android/com/google/firebase/database/DataSnapshot
  3193. // CHANGE TO {data.exists:path/to/record}
  3194. //"alert.close" functions(alert, do:close)
  3195. break;
  3196. case 'window':
  3197. /* try {
  3198. value = eval('window.'.p2);
  3199. } catch (error) {
  3200. self.log('javascript error on '+ p2);
  3201. value = match;
  3202. } */
  3203. //value = self.js('window.'.p2) || match;
  3204. value = self.docElement(p2) || match;
  3205. break;
  3206. /* case 'args':
  3207. // often replaceProperties is called without args
  3208. value = match;
  3209. break; */
  3210. default:
  3211. // ci finiamo dentro con {setup:value}
  3212. /* var element = document.querySelector(p2);
  3213. value = (element) ? element[p1] : '';
  3214. self.log('p1 ' + p1);
  3215. self.log('p2 ' + p2);
  3216. self.log('value ' + value);
  3217. if (!element)
  3218. self.log('can\'t match ' + match, 'color:red'); */
  3219. break;
  3220. /* default:
  3221. var node = self.docElement('self.json.'+p1);
  3222. self.log('node');
  3223. self.log(node);
  3224. if (node) value = node[p2] // example: p1 = styles.colors p2 = colorName
  3225. else value = '<{'+p1+':'+p2+'}>';
  3226. break;
  3227. */
  3228. }
  3229. } // not self.functions[p1]
  3230. }
  3231. } else if (p2) {
  3232. // can be a FUNCTION: from modules
  3233. let keyPrefix = p2.split(' ')[0]; // /\s\./
  3234. if (self.functions[keyPrefix]) {
  3235. value = self.function({ name: keyPrefix });
  3236. value = self.element({ path: p2, root: value }); // example: {pathFromHash 0}
  3237. console.log(keyPrefix);
  3238. console.log(value);
  3239. }
  3240. else
  3241. value = self.replaceUndefined({ match: match, path: p2, removeUndefined: removeUndefined });
  3242. //value = self.element({path: p2});
  3243. }
  3244. // value is a DOM element
  3245. if (value && value.isConnected) value = self.elementToSelector(value); // DOM element to CSS selector
  3246. if (!value) {
  3247. // TO DO: should be (typeof value == undefined)
  3248. // t's a critical change. It changes the result of "is": "'{data id}' !== ''"
  3249. if (removeUndefined)
  3250. value = '';
  3251. else {
  3252. if (typeof value == undefined)
  3253. self.log(match + ' is undefined', 'yellow');
  3254. }
  3255. }
  3256. if (typeof value !== 'string') value = self.stringify(value); // object or array to string (TO DO: check numbers)
  3257. return value;
  3258. });
  3259. // js property TO DO: check it
  3260. if (paramsString.startsWith('{js:') && paramsString.endsWith('}'))
  3261. paramsString = self.js(paramsString.substr(4, paramsString.length - 1 - 4));
  3262. //if (self.isJson(paramsString)) {// (typeof params == 'object')
  3263. if (self.isJsonString(paramsString)) { // (typeof params == 'object')
  3264. var paramsObj = self.parse(paramsString);
  3265. // restore event nodes
  3266. if (paramOn) paramsObj.on = paramOn;
  3267. if (paramDo) paramsObj.do = paramDo;
  3268. if (paramConfirm) paramsObj.confirm = paramConfirm;
  3269. if (paramSuccess) paramsObj.success = paramSuccess;
  3270. if (paramError) paramsObj.success = paramError;
  3271. if (paramEvents) paramsObj.events = paramEvents; // obsolete
  3272. return paramsObj;
  3273. } else {
  3274. // TO DO: log of wrong json string
  3275. //alert(paramsString);
  3276. /* if (Array.isArray(self.parse(paramsString)))
  3277. return self.parse(paramsString)
  3278. else */
  3279. return paramsString;
  3280. }
  3281. } else {
  3282. // restore event nodes
  3283. if (paramOn) params.on = paramOn;
  3284. if (paramDo) params.do = paramDo;
  3285. if (paramConfirm) params.confirm = paramConfirm;
  3286. if (paramSuccess) params.success = paramSuccess;
  3287. if (paramError) params.error = paramError;
  3288. if (paramEvents) params.events = paramEvents; // obsolete
  3289. return params;
  3290. }
  3291. };
  3292. /* if (!value) undef = true;
  3293. if (undef) return undefined
  3294. else return params;
  3295. */
  3296. this.isJsonString = function (str) {
  3297. try {
  3298. JSON.parse(str);
  3299. } catch (e) {
  3300. return false;
  3301. }
  3302. return true;
  3303. };
  3304. this.isJson = function (item) {
  3305. item = typeof item !== "string" ? JSON.stringify(item) : item;
  3306. try {
  3307. item = JSON.parse(item);
  3308. } catch (e) {
  3309. return false;
  3310. }
  3311. if (typeof item === "object" && item !== null) {
  3312. return true;
  3313. }
  3314. return false;
  3315. };
  3316. this.replaceStringInObject = function (obj, stringToReplace, value) {
  3317. var paramsString, valueString;
  3318. if (typeof obj == 'string') paramsString = obj; else paramsString = JSON.stringify(obj);
  3319. if (typeof value == 'string') valueString = value; else valueString = JSON.stringify(value);
  3320. paramsString = self.replaceAll(paramsString, stringToReplace, valueString);
  3321. if (self.isJson(paramsString))
  3322. return self.parse(paramsString);
  3323. else
  3324. return paramsString;
  3325. };
  3326. /* this.replaceResult = function (params, args) {
  3327. paramsString = paramsString.replace(/(\"\s*)\{[result]\:(\w+)\}(\s*\")/g, function(match, p1, p2, p3, offset, string) {
  3328. });
  3329. }
  3330. */
  3331. this.replaceItems = function (params, item, name) {
  3332. // check this: http://mir.aculo.us/2011/03/09/little-helpers-a-tweet-sized-javascript-templating-engine/
  3333. // params: <li><{item:name}></li>, item: Vito or item: {name: Vito}
  3334. //var paramString = self.replaceProperties(params, undefined, item);
  3335. var paramsString;
  3336. var specialPattern;
  3337. var itemName = name || 'item';
  3338. /* if (name) {
  3339. self.log('replaceItems');
  3340. self.log('params');
  3341. self.log(params);
  3342. self.log('item');
  3343. self.log(item);
  3344. self.log('name');
  3345. self.log(name);
  3346. } */
  3347. if (typeof params == 'string') paramsString = params; else paramsString = JSON.stringify(params);
  3348. /* paramsString = paramsString.replace(/\{item\}/g, function(match, p1, offset, string) {
  3349. var value;
  3350. if (item) {
  3351. value = item;
  3352. } else {
  3353. value = '';
  3354. }
  3355. if (typeof value == 'object') value = self.stringify(value);
  3356. return value;
  3357. }); */
  3358. if (typeof item == 'object' || Array.isArray(item)) { // || Array.isArray(item) not needed
  3359. paramsString = self.replaceAll(paramsString, '"{' + itemName + '}"', JSON.stringify(item));
  3360. for (let key in item) {
  3361. if (typeof item[key] == 'object')
  3362. paramsString = self.replaceAll(paramsString, '"{' + itemName + ':' + key + '}"', JSON.stringify(item[key]));
  3363. else
  3364. paramsString = self.replaceAll(paramsString, '{' + itemName + ':' + key + '}', item[key]);
  3365. }
  3366. } else {
  3367. paramsString = self.replaceAll(paramsString, '{' + itemName + '}', String(item));
  3368. }
  3369. //if (itemName == 'hour') alert(paramsString);
  3370. /* if (itemName !== 'item') { // TO DO: remove
  3371. var propertyPattern = new RegExp('\{'+itemName+'\:([^\}]+)\}', 'g');
  3372. paramsString = paramsString.replace(propertyPattern, function(match, p1, p2, p3, offset, string) {
  3373. var value = self.docElement(p1, undefined, item);
  3374. if (value)
  3375. return value
  3376. else
  3377. return match;
  3378. });
  3379. } */
  3380. //specialPattern = new RegExp(/\"\{(\w+)\}\"/, "g");
  3381. // item: inside double quotes (to manage objects inside double string)
  3382. //specialPattern = new RegExp(`(\")\{${itemName}\:(\w+)\}(\")`, 'g');
  3383. //paramsString = paramsString.replace(specialPattern, function(match, p1, p2, p3, offset, string) {
  3384. //specialPattern = new RegExp('(\"\s*)\{'+itemName+'\:(\w+)\}(\s*\")', 'g');
  3385. paramsString = paramsString.replace(/(\"\s*)\{item\:(\w+)\}(\s*\")/g, function (match, p1, p2, p3, offset, string) {
  3386. var value;
  3387. if (item)
  3388. value = item[p2] || '';
  3389. else
  3390. value = '';
  3391. if (typeof value == 'object')
  3392. value = self.stringify(value);
  3393. else if (Array.isArray(value))
  3394. value = value;
  3395. else
  3396. value = p1 + value + p3; // p1 and p3 are the " matched by (\"\s*) and (\s*\")
  3397. return value;
  3398. });
  3399. /*
  3400. specialPattern = new RegExp('\{'+itemName+'\:([^\}]*)\}', 'g');
  3401. paramsString = paramsString.replace(specialPattern, function(match, p2, offset, string) {
  3402. //paramsString = paramsString.replace(/\{item\:([^\}]*)\}/g, function(match, p2, offset, string) {
  3403. var value;
  3404. if (item)
  3405. value = item[p2] || '';
  3406. else
  3407. value = '';
  3408. if (typeof value == 'object')
  3409. value = self.stringify(value);
  3410. return value;
  3411. }); */
  3412. if (self.isJson(paramsString))
  3413. return self.parse(paramsString);
  3414. else
  3415. return paramsString;
  3416. //if (typeof params == 'object') return self.parse(paramsString); else return paramsString;
  3417. };
  3418. /* this.replaceItems = function (objWithNames, name) {
  3419. //self.log('replaceItems');
  3420. var paramString = self.stringify(objWithNames);
  3421. //self.log(paramString);
  3422. if (!name) name = '';
  3423. paramString = self.replaceAll(paramString, '{item}', name);
  3424. //self.log(paramString);
  3425. //paramString = self.replaceTags({text:paramString});
  3426. //self.log(paramString);
  3427. //paramString = self.replaceProperties(paramString);
  3428. //self.log(paramString);
  3429. if (typeof objWithNames == 'object') return self.parse(paramString); else return paramString;
  3430. } */
  3431. this.color = function (params, args) {
  3432. var paramsReplaced = self.replaceProperties(params, args);
  3433. //if (self.json.styles.colors)
  3434. // return self.json.styles.colors[paramsReplaced];
  3435. if (self.json.data && self.json.data.colors)
  3436. return self.json.data.colors[paramsReplaced];
  3437. };
  3438. // ----------------------------
  3439. // ELEMENT METHODS
  3440. // ----------------------------
  3441. this.empty = function (params) {
  3442. /* self.log('empty');
  3443. self.log(params); */
  3444. var el = self.query(params);
  3445. if (el) {
  3446. while (el.firstChild)
  3447. el.removeChild(el.firstChild);
  3448. } else {
  3449. self.log('"empty" is unable to select element');
  3450. self.log(params);
  3451. }
  3452. };
  3453. this.isArray = function (value) {
  3454. return Array.isArray(self.js(value));
  3455. };
  3456. this.isVisible = function (el) {
  3457. return (el.style.display !== 'none' && !self.hasClass(el, 'd-none'));
  3458. };
  3459. this.isHidden = function (el) {
  3460. return (el.offsetParent === null);
  3461. };
  3462. this.isDisplay = function (el, displayValue) {
  3463. //var style = window.getComputedStyle(el);
  3464. /* self.log('isDisplay');
  3465. self.log('el.style');
  3466. self.log(el.style);
  3467. self.log('displayValue');
  3468. self.log(displayValue); */
  3469. return (el.style.display === displayValue);
  3470. };
  3471. this.inViewport = function (el) {
  3472. const rect = el.getBoundingClientRect();
  3473. return (
  3474. rect.top >= 0 &&
  3475. rect.left >= 0 &&
  3476. rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
  3477. rect.right <= (window.innerWidth || document.documentElement.clientWidth)
  3478. );
  3479. };
  3480. this.outViewport = function (el) {
  3481. return !self.outViewport(el);
  3482. };
  3483. this.notClass = function (el, className) {
  3484. return !self.hasClass(el, className);
  3485. };
  3486. this.hasClass = function (el, className) {
  3487. if (el.classList)
  3488. return el.classList.contains(className);
  3489. else
  3490. return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)'));
  3491. };
  3492. this.addClass = function (el, className) {
  3493. if (el.classList)
  3494. el.classList.add(className);
  3495. else if (!self.hasClass(el, className)) el.className += " " + className;
  3496. };
  3497. this.removeClass = function (el, className) {
  3498. if (el.classList)
  3499. el.classList.remove(className);
  3500. else if (self.hasClass(el, className)) {
  3501. var reg = new RegExp('(\\s|^)' + className + '(\\s|$)');
  3502. el.className = el.className.replace(reg, ' ');
  3503. }
  3504. };
  3505. this.toggleClass = function (el, className) {
  3506. if (self.hasClass(el, className))
  3507. self.removeClass(el, className);
  3508. else
  3509. self.addClass(el, className);
  3510. };
  3511. this.choose = this.select = function (params, selectorParams, args) {
  3512. // "choose OR options / "select" is deprecated because select is an html tag
  3513. // {selection: selection class, id: selected id}
  3514. // or: choosed, choosable, selection
  3515. // or: selector, selectable, selection
  3516. // or: opted, options, selection
  3517. /* self.log('select');
  3518. self.log('params');
  3519. self.log(params);
  3520. self.log('args');
  3521. self.log(args); */
  3522. if (Array.isArray(params)) {
  3523. for (var obj of params)
  3524. self.choose(obj, args);
  3525. } else {
  3526. //if (selectorParams) params = self.extend({}, selectorParams, params);
  3527. var selId, selClass, selValue;
  3528. selValue = params['data-value']; // || params.value
  3529. if (params.id) selId = self.replaceProperties(params.id, args);
  3530. if (params.class) selClass = self.replaceProperties(params.class, args);
  3531. if (selValue) selValue = self.replaceProperties(selValue, args);
  3532. //var selector = self.selector(params.selector, undefined, true) || self.selector(selectorParams, undefined, true);
  3533. if (params.selection) {
  3534. var selectionClass = params.selection;
  3535. /* self.log('selClass');
  3536. self.log(selClass);
  3537. self.log('selValue');
  3538. self.log(selValue);
  3539. self.log('selectionClass');
  3540. self.log(selectionClass); */
  3541. var selector = self.selector({ class: selClass });
  3542. var elements = document.querySelectorAll('.' + selClass); // convert to any string selector (move the point to the code)
  3543. elements.forEach(function (element, index) {
  3544. self.removeClass(element, selectionClass);
  3545. });
  3546. //$(selector).removeClass(selectionClass);
  3547. if (selId || selValue) {
  3548. var selector = self.selector({ id: selId, class: selClass, 'data-value': selValue });
  3549. //self.log('selector');
  3550. //self.log(selector);
  3551. //var elements = self.query(selector);
  3552. //self.log('elements');
  3553. //self.log(elements);
  3554. //if (elements)
  3555. //self.addClass(elements, selectedIconClass);
  3556. var elements = document.querySelectorAll(selector);
  3557. elements.forEach(function (element, index) {
  3558. self.addClass(element, selectionClass);
  3559. });
  3560. }
  3561. } else {
  3562. /* self.log('select');
  3563. self.log('selClass');
  3564. self.log(selClass);
  3565. self.log('selValue');
  3566. self.log(selValue);
  3567. self.log('selectionClass');
  3568. self.log(selectionClass); */
  3569. self.hide({
  3570. "selector": {
  3571. "class": selClass
  3572. }
  3573. });
  3574. self.show({
  3575. "selector": {
  3576. "id": selId,
  3577. "class": selClass,
  3578. "data-value": selValue
  3579. }
  3580. });
  3581. //self.log('selectselection" class parameter is required in "select" object');
  3582. }
  3583. //self.updateCodeEditors(); // workaround known ACE bug
  3584. self.uiUpdate(); // resize event trigger
  3585. }
  3586. };
  3587. /* this.select = function (params, selectorParams) {
  3588. // { [container, class, value, id]
  3589. self.log('self.select');
  3590. if (Array.isArray(params)) {
  3591. for (var index in params)
  3592. self.choose(params[index], selectorParams);
  3593. } else {
  3594. if (selectorParams) params = self.extend({}, selectorParams, params);
  3595. params = self.replaceProperties(params);
  3596. //params = self.replaceTags({text:params});
  3597. self.selectItem(params);
  3598. }
  3599. }
  3600. */
  3601. this.toggle = function (params, selectorParams, args) {
  3602. self.log('toggle');
  3603. self.log(params);
  3604. if (Array.isArray(params)) {
  3605. for (var index in params)
  3606. self.toggle(params[index], selectorParams, args);
  3607. } else {
  3608. var selector;
  3609. if (typeof params == 'string')
  3610. selector = params;
  3611. else
  3612. selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  3613. var element = self.query(selector);
  3614. /* self.log('selector');
  3615. self.log(selector);
  3616. self.log('element');
  3617. self.log(element);
  3618. self.log('self.isVisible(element)');
  3619. self.log(self.isVisible(element)); */
  3620. //if ($(selector).is(":visible"))
  3621. if (self.isVisible(element))
  3622. //self.fadeOut(params, selectorParams);
  3623. self.out(params, selectorParams, args);
  3624. else
  3625. //self.fadeIn(params, selectorParams);
  3626. self.in(params, selectorParams, args);
  3627. //$(selector).toggle(500); // jquery bugs // , self.resizeEvent
  3628. }
  3629. };
  3630. this.in = function (params, selectorParams, args) {
  3631. if (Array.isArray(params)) {
  3632. for (var index in params)
  3633. self.in(params[index], selectorParams, args);
  3634. } else {
  3635. var selector;
  3636. if (typeof params == 'string')
  3637. selector = params;
  3638. else
  3639. selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  3640. var transition = params.transition || 'fadeIn';
  3641. var duration = params.duration || '500ms';
  3642. //self.log('selector');
  3643. //self.log(selector);
  3644. var start = [{
  3645. "show": {
  3646. "selector": selector,
  3647. }
  3648. }];
  3649. var end = [
  3650. {
  3651. "do": self.resizeEvent
  3652. }
  3653. ];
  3654. if (params.on && params.on.start)
  3655. start.push(params.on.start);
  3656. if (params.on && params.on.end)
  3657. end.push(params.on.end);
  3658. var animation = {
  3659. "animate": {
  3660. "selector": selector,
  3661. "transition": transition,
  3662. "duration": duration,
  3663. "on": {
  3664. "start": start,
  3665. "end": end
  3666. }
  3667. }
  3668. };
  3669. //self.do(animation, args);
  3670. self.do(animation, undefined, args);
  3671. //self.resizeEvent();
  3672. }
  3673. };
  3674. this.out = function (params, selectorParams, args) {
  3675. if (Array.isArray(params)) {
  3676. for (var index in params)
  3677. self.out(params[index], selectorParams);
  3678. } else {
  3679. var selector;
  3680. if (typeof params == 'string')
  3681. selector = params;
  3682. else
  3683. selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  3684. var transition = params.transition || 'fadeOut';
  3685. var duration = params.duration || '500ms';
  3686. var start = [];
  3687. var end = [
  3688. {
  3689. "hide": {
  3690. "selector": selector,
  3691. }
  3692. },
  3693. {
  3694. "do": self.resizeEvent
  3695. }
  3696. ];
  3697. if (params.on && params.on.start)
  3698. start.push(params.on.start);
  3699. if (params.on && params.on.end)
  3700. end.push(params.on.end);
  3701. var animation = {
  3702. "animate": {
  3703. "selector": selector,
  3704. "transition": transition,
  3705. "duration": duration,
  3706. "on": {
  3707. "start": start,
  3708. "end": end
  3709. }
  3710. }
  3711. };
  3712. //self.do(animation, args);
  3713. self.do(animation, undefined, args);
  3714. }
  3715. };
  3716. this.show = function (params, selectorParams, args) {
  3717. if (Array.isArray(params)) {
  3718. for (var index in params)
  3719. self.show(params[index], selectorParams);
  3720. } else {
  3721. var selector;
  3722. if (typeof params == 'string')
  3723. selector = params;
  3724. else
  3725. selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  3726. var elements = self.queryAll(selector);
  3727. elements.forEach(function (element, index) {
  3728. self.removeClass(element, 'hidden');
  3729. self.removeClass(element, 'opacity-0');
  3730. self.removeClass(element, 'invisible');
  3731. self.removeClass(element, 'd-none'); // bootstrap
  3732. //element.style.display = 'block';
  3733. element.style.visibility = 'visible';
  3734. /*
  3735. container = element.getAttribute('data-selector');
  3736. //container = self.dataStorage.get(element, 'selector');
  3737. var action = [
  3738. {
  3739. "if": {
  3740. "container": container,
  3741. "hasClass": "opacity-0",
  3742. "then": {
  3743. "attr": {
  3744. "container": container,
  3745. "removeClass": "opacity-0"
  3746. }
  3747. }
  3748. }
  3749. },
  3750. {
  3751. "if": {
  3752. "container": container,
  3753. "hasClass": "invisible",
  3754. "then": {
  3755. "attr": {
  3756. "container": container,
  3757. "removeClass": "invisible" // bootstrap & tailwind
  3758. }
  3759. }
  3760. }
  3761. },
  3762. {
  3763. "if": {
  3764. "container": container,
  3765. "hasClass": "d-none",
  3766. "then": {
  3767. "attr": {
  3768. "container": container,
  3769. "removeClass": "d-none" // bootstrap
  3770. }
  3771. }
  3772. }
  3773. },
  3774. {
  3775. "if": {
  3776. "container": container,
  3777. "hasClass": "hidden",
  3778. "then": {
  3779. "attr": {
  3780. "container": container,
  3781. "removeClass": "hidden" // taliwind
  3782. }
  3783. }
  3784. }
  3785. },
  3786. {
  3787. "if": { // should be if style.display == none
  3788. "container": container,
  3789. "isDisplay": "none",
  3790. "then": {
  3791. "attr": {
  3792. "container": container,
  3793. "style": {
  3794. "display": ""
  3795. }
  3796. }
  3797. }
  3798. }
  3799. }
  3800. ];
  3801. //element.style.display = ' ';
  3802. //alert(JSON.stringify(element.style));
  3803. if (element.style.visibility && element.style.visibility !== 'visible')
  3804. element.style.visibility = 'visible';
  3805. //self.do(action, args);
  3806. //self.do(action, undefined, args);
  3807. self.do(action, undefined, args); */
  3808. });
  3809. }
  3810. };
  3811. this.hide = function (params, selectorParams, args) {
  3812. if (Array.isArray(params)) {
  3813. for (var index in params)
  3814. self.hide(params[index], selectorParams);
  3815. } else {
  3816. var selector;
  3817. if (typeof params == 'string')
  3818. selector = params;
  3819. else
  3820. selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  3821. var elements = self.queryAll(selector);
  3822. elements.forEach(function (element, index) {
  3823. self.addClass(element, 'hidden');
  3824. /* container = element.getAttribute('data-selector');
  3825. var action = [
  3826. {
  3827. "attr": {
  3828. "container": container,
  3829. "addClass": "d-none" // bootstrap (to be removed)
  3830. }
  3831. },
  3832. {
  3833. "attr": {
  3834. "container": container,
  3835. "addClass": "hidden" // tailwind
  3836. }
  3837. }
  3838. ];
  3839. //self.do(action, args);
  3840. self.do(action, undefined, args); */
  3841. });
  3842. }
  3843. };
  3844. /* this.fadeIn = function (params, selectorParams, args) {
  3845. //self.log('fadeIn');
  3846. //self.log(params);
  3847. if (Array.isArray(params)) {
  3848. for (var index in params)
  3849. self.fadeIn(params[index], selectorParams);
  3850. } else {
  3851. //params.container = params.container || self.selector(selectorParams);
  3852. //var selector = self.selector(params);
  3853. var selector = self.selector(self.extend({}, params, selectorParams), {}, true);
  3854. var duration = params.duration || 500;
  3855. var done = (params.done) ? function () {
  3856. self.resizeEvent();
  3857. self.do(params.done);
  3858. } : null;
  3859. $(selector).stop().fadeIn(duration, done);
  3860. }
  3861. }
  3862. this.fadeOut = function (params, selectorParams, args) {
  3863. //self.log('fadeOut');
  3864. //self.log(params);
  3865. // add onComplete and duration
  3866. if (Array.isArray(params)) {
  3867. for (var index in params)
  3868. self.fadeOut(params[index], selectorParams);
  3869. } else {
  3870. //params.container = params.container || self.selector(selectorParams);
  3871. //var selector = self.selector(params);
  3872. var selector = self.selector(self.extend({}, params, selectorParams), {}, true);
  3873. var duration = params.duration || 500;
  3874. var done = (params.done) ? function () {
  3875. self.do(params.done);
  3876. } : null;
  3877. $(selector).stop().fadeOut({
  3878. duration: duration,
  3879. done: function () {
  3880. self.resizeEvent();
  3881. self.do(params.done);
  3882. }
  3883. });
  3884. }
  3885. } */
  3886. /* this.show = function (params, selectorParams, args) {
  3887. //self.log('show');
  3888. //self.log(JSON.stringify(params));
  3889. if (Array.isArray(params)) {
  3890. for (var index in params)
  3891. self.show(params[index], selectorParams);
  3892. } else {
  3893. //params.container = params.container || self.selector(selectorParams);
  3894. //var selector = self.selector(params);
  3895. var selector = self.selector(self.extend({}, params, selectorParams), {}, true);
  3896. //self.log('selector');
  3897. //self.log(selector);
  3898. $(selector).show();
  3899. self.resizeEvent();
  3900. }
  3901. }
  3902. this.hide = function (params, selectorParams, args) {
  3903. //self.log('hide');
  3904. //self.log(JSON.stringify(params));
  3905. if (Array.isArray(params)) {
  3906. for (var index in params)
  3907. self.hide(params[index], selectorParams);
  3908. } else {
  3909. //params.container = params.container || self.selector(selectorParams);
  3910. //var selector = self.selector(params);
  3911. var selector = self.selector(self.extend({}, params, selectorParams), {}, true);
  3912. //self.log('selector');
  3913. //self.log(selector);
  3914. $(selector).hide();
  3915. self.resizeEvent();
  3916. }
  3917. } */
  3918. this.matchMedia = function (mediaAction, mediaEvent) {
  3919. const mediaQuery = window.matchMedia(mediaEvent);
  3920. mediaQuery.addListener(function (e) {
  3921. /* self.log('matchMedia');
  3922. self.log('e');
  3923. self.log(e); */
  3924. if (e.matches) {
  3925. self.do(mediaAction);
  3926. //self.do(mediaAction);
  3927. }
  3928. });
  3929. //self.do(mediaAction);
  3930. };
  3931. /* this.firebaseEventAction = function (newObj) {
  3932. var path = newObj.path;
  3933. delete newObj.path;
  3934. document.querySelectorAll('[data-firebase="'+path+'"]').forEach(function (element, index) {
  3935. var pathString = 'self.json.var.db.' + self.replaceAll(element.getAttribute('data-firebase'), '/', '.'); // data('firebase')
  3936. var dbObj = self.docElement(pathString);
  3937. var firebaseValue = newObj[element.getAttribute('data-value')]; // TODO: not works for nested nodes
  3938. var container = element.getAttribute('data-selector');
  3939. //var template = element.getAttribute('data-template');
  3940. var template = self.dataStorage.get(element, 'data-template');
  3941. if (element.tagName == 'UL') { // se $(this) è un ul
  3942. var liTemplate = template.li;
  3943. //$(container).empty();
  3944. element.innerHTML = '';
  3945. var items = newObj;
  3946. for (itemKey in items) {
  3947. var item = items[itemKey];
  3948. item.key = itemKey;
  3949. //if (dbPath == 'lessons')
  3950. //prompt(JSON.stringify(liTemplate));
  3951. var dbParams = self.replaceItems(liTemplate, item, 'item') || '';
  3952. // var dbParams = self.replaceProperties(liTemplate, undefined, item) || '';
  3953. self.li(dbParams, {container: container});
  3954. }
  3955. //} else if ( $(element).is('span') || $(element).is('p')) {
  3956. } else if (element.tagName == 'SPAN' || element.tagName == 'P') {
  3957. //$(element).text(firebaseValue);
  3958. element.textContent = firebaseValue;
  3959. } else { // se $(this) non è un ul
  3960. if (template.blocks || template.html) {
  3961. var blocksTemplate = template.html || template.blocks;
  3962. //$(container).empty();
  3963. element.innerHTML = '';
  3964. var items = newObj;
  3965. self.log('newObj');
  3966. self.log(newObj);
  3967. for (itemKey in items) {
  3968. var item = items[itemKey];
  3969. item.key = itemKey;
  3970. var dbParams = self.replaceProperties(blocksTemplate, undefined, item) || '';
  3971. self.html(dbParams, {container: container});
  3972. }
  3973. }
  3974. if (template.init) self.do(template.init);
  3975. }
  3976. });
  3977. }; */
  3978. /* self.jsonic = function () {
  3979. } */
  3980. this.addFirebaseTag = function (params) {
  3981. // self.log('addFirebaseTag');
  3982. var dataObj = params.database;
  3983. if (dataObj) {
  3984. dataObj = self.replaceProperties(dataObj);
  3985. /* self.log('dataObj');
  3986. self.log(dataObj); */
  3987. //var path = self.replaceTags({text:params.firebase});
  3988. var path, success;
  3989. if (typeof dataObj == 'string') {
  3990. path = dataObj;
  3991. } else {
  3992. path = dataObj.path;
  3993. success = dataObj.success;
  3994. }
  3995. if (path) {
  3996. var selector = self.selector(params, undefined, false);
  3997. //var element = self.query(selector);
  3998. var elements = self.queryAll(selector);
  3999. //var elements = document.querySelectorAll(selector);
  4000. if (elements)
  4001. elements.forEach(function (element, index) {
  4002. var listenerObj = {
  4003. path: path
  4004. //success: dataObj.success
  4005. };
  4006. var elementsDataPath = document.querySelectorAll('[data-firebase="' + path + '"]');
  4007. //if ($('[data-firebase="'+path+'"]').length == 0) {
  4008. if (elementsDataPath.length == 0) {
  4009. listenerObj.action = [
  4010. /* {
  4011. "firebaseEvent.action": {} // should use self.get function to parse "self"
  4012. // todo: remove "jsonic". The function firebaseEventAction can be stored in self.do (or?)
  4013. } */
  4014. ];
  4015. if (dataObj.success)
  4016. listenerObj.action.push(dataObj.success);
  4017. }
  4018. //$(selector).attr('data-firebase', path);
  4019. //$(selector).data('data-template', params);
  4020. if (element) {
  4021. element.setAttribute('data-firebase', path);
  4022. self.dataStorage.set(element, 'data-template', params);
  4023. } else {
  4024. self.log('!element selector:' + selector + ' / firebase path:' + path);
  4025. self.log('params');
  4026. self.log(params);
  4027. }
  4028. //if (params.on && params.on.data) $(selector).data('ondata', params.on.data); // maestry
  4029. if (dataObj.orderByChild !== undefined) listenerObj.orderByChild = dataObj.orderByChild;
  4030. if (dataObj.equalTo !== undefined) listenerObj.equalTo = dataObj.equalTo;
  4031. self.firebaseAddListener(listenerObj);
  4032. });
  4033. } else {
  4034. self.log('data object requires path parameter');
  4035. self.log(params);
  4036. }
  4037. }
  4038. };
  4039. this.dbObject = function (path) {
  4040. var pathString = 'self.json.var.db.' + self.replaceAll(path, '/', '.');
  4041. return self.docElement(pathString);
  4042. };
  4043. this.only = function (permissions, user) {
  4044. // "visitor" or "only"
  4045. if (user) {
  4046. return (user == self.user('uid'));
  4047. } else {
  4048. var permission = (permissions) ? String(permissions).split(',') : false;
  4049. return (!permission || (permissions.indexOf(self.userRole()) >= 0));
  4050. }
  4051. };
  4052. this.extendJsonFromElement = function (p) {
  4053. /* self.log('extendJsonFromElement');
  4054. self.log(p); */
  4055. var params = self.cloneObject(p);
  4056. // properties
  4057. if (params.resources) self.extendJson(self.json, { "resources": params.resources });
  4058. if (params.plugins) self.extendJson(self.json, { "plugins": params.plugins });
  4059. if (params.parts) self.extendJson(self.json, { "parts": params.parts });
  4060. if (params.blocks) self.extendJson(self.json, { "blocks": params.parts }); // obsolete
  4061. if (params.shortcuts) self.extendJson(self.json, { "shortcuts": params.shortcuts });
  4062. if (params.css) self.extendJson(self.json, { "css": params.css });
  4063. if (params.setup) self.extendJson(self.json, { "setup": params.setup });
  4064. if (params.data) self.extendJson(self.json, { "data": params.data });
  4065. if (params.var) self.extendJson(self.json, { "var": params.var });
  4066. if (params.texts) self.extendJson(self.json, { "texts": params.texts }); // maybe used in self.text
  4067. // can't be extended "setup" (is relative to the full app) and "on" (is relative to the element)
  4068. };
  4069. this.query = function (selector, element) {
  4070. //self.log('query: '+selector);
  4071. if (selector) {
  4072. if (typeof selector == 'object')
  4073. selector = self.selector(selector, undefined, true);
  4074. var routes = selector.split(/[ >]+/);
  4075. if (!element) element = document;
  4076. for (var index in routes) {
  4077. if (element && element[0]) element = element[0];
  4078. if (element && element.isConnected) {
  4079. var route = routes[index];
  4080. /* route.replace(/([^\s])\[/g, function(match, p1) { // -> .class [data-value=...]
  4081. return p1 + ' ['
  4082. }); */
  4083. //self.log('route');
  4084. //self.log(route);
  4085. var routeParts = route.match(/(.*):eq\((\d*)\)/);
  4086. //self.log('routeParts');
  4087. //self.log(routeParts);
  4088. if (routeParts) {
  4089. var routeElement = String(routeParts[1]);
  4090. var routeIndex = Number(routeParts[2]);
  4091. if (routeElement.startsWith('.'))
  4092. routeElement = '.' + self.classSelector(routeElement);
  4093. //if (self.exist(routeElement))
  4094. element = element.querySelectorAll(routeElement)[routeIndex];
  4095. /* self.log('routeElement');
  4096. self.log(routeElement);
  4097. self.log('routeIndex');
  4098. self.log(routeIndex); */
  4099. } else {
  4100. //if (self.exist(route))
  4101. if (route.startsWith('.'))
  4102. route = '.' + self.classSelector(route);
  4103. element = element.querySelectorAll(route)[0];
  4104. }
  4105. } else {
  4106. element = undefined;
  4107. }
  4108. }
  4109. //element.innerHTML = 'test';
  4110. //element.style.display = 'none';
  4111. //self.log(element);
  4112. //if (element && !Array.isArray(element)) element = [element];
  4113. if (!element)
  4114. self.log('can\'t find the element "' + selector + '" ("query" function)');
  4115. return element;
  4116. } else {
  4117. //self.log('function "query" without selector parameters');
  4118. // BUG: many calls from addtag
  4119. }
  4120. };
  4121. /* this.queryAllTest = function (selector, element) {
  4122. //self.log('query: '+selector);
  4123. if (selector) {
  4124. //route = self.replaceAll(route, '[', ' [');
  4125. selector.replace(/([^\s])\[/g, function(match, p1) { // -> .class [data-value=...]
  4126. return p1 + '['
  4127. });
  4128. var routes = selector.split(/[ >]+/);
  4129. if (!element) element = document;
  4130. self.log('routes');
  4131. self.log(routes);
  4132. for (var index in routes) {
  4133. self.log('index');
  4134. self.log(index);
  4135. if (element.isConnected) {
  4136. var route = routes[index];
  4137. var routeParts = route.match(/([^:]*):eq\((\d*)\)/);
  4138. self.log('routeParts');
  4139. self.log(routeParts);
  4140. if (routeParts) {
  4141. var routeElement = String(routeParts[1]);
  4142. var routeIndex = Number(routeParts[2]);
  4143. //if (self.exist(routeElement))
  4144. element = element.querySelectorAll(routeElement)[routeIndex];
  4145. self.log('routeElement');
  4146. self.log(routeElement);
  4147. self.log('routeIndex');
  4148. self.log(routeIndex);
  4149. } else {
  4150. //if (self.exist(route))
  4151. self.log('route');
  4152. self.log(route);
  4153. element = element.querySelectorAll(route);
  4154. }
  4155. } else {
  4156. self.log('Not in the DOM '+ selector);
  4157. self.log('route');
  4158. self.log(route);
  4159. element = [];
  4160. }
  4161. }
  4162. //element.innerHTML = 'test';
  4163. //element.style.display = 'none';
  4164. //if (element && !Array.isArray(element)) element = [element];
  4165. //self.log(element);
  4166. return element;
  4167. } else {
  4168. self.log('DOM "query" without selector parameters');
  4169. }
  4170. } */
  4171. /* this.convertRoute = function (route) {
  4172. var routeElement, routeValue;
  4173. route = route.replace(/([^\s])\[/g, function(match, p1) { // -> .class [data-value=...]
  4174. return p1 + ' ['
  4175. });
  4176. if (route.indexOf(' ')) {
  4177. var parts = route.split(' ');
  4178. routeElement = parts[0];
  4179. routeValue = parts[1];
  4180. } else {
  4181. routeElement = route
  4182. }
  4183. self.log(routeElement);
  4184. self.log(routeValue);
  4185. if (routeElement.startsWith('.'))
  4186. routeQuery = '[class='+routeElement+']';
  4187. else if (routeElement.startsWith('#'))
  4188. routeQuery = '[id='+routeElement+']';
  4189. else
  4190. routeQuery = routeElement + routeValue;
  4191. if (routeValue)
  4192. routeQuery += ' ' + routeValue;
  4193. return routeQuery;
  4194. } */
  4195. /*
  4196. // https://www.examplefiles.net/cs/1222124
  4197. var querySelectorAllWithEq = function(selector, document) {
  4198. var remainingSelector = selector;
  4199. var baseElement = document;
  4200. var firstEqIndex = remainingSelector.indexOf(':eq(');
  4201. while (firstEqIndex !== -1) {
  4202. var leftSelector = remainingSelector.substring(0, firstEqIndex);
  4203. var rightBracketIndex = remainingSelector.indexOf(')', firstEqIndex);
  4204. var eqNum = remainingSelector.substring(firstEqIndex + 4, rightBracketIndex);
  4205. eqNum = parseInt(eqNum, 10);
  4206. var selectedElements = baseElement.querySelectorAll(leftSelector);
  4207. if (eqNum >= selectedElements.length) {
  4208. return [];
  4209. }
  4210. baseElement = selectedElements[eqNum];
  4211. remainingSelector = remainingSelector.substring(rightBracketIndex + 1).trim();
  4212. // Note - for now we just ignore direct descendants:
  4213. // 'a:eq(0) > i' gets transformed into 'a:eq(0) i'; we could maybe use :scope
  4214. // to fix this later but support is iffy
  4215. if (remainingSelector.charAt(0) === '>') {
  4216. remainingSelector = remainingSelector.substring(1).trim();
  4217. }
  4218. firstEqIndex = remainingSelector.indexOf(':eq(');
  4219. }
  4220. if (remainingSelector !== '') {
  4221. return Array.from(baseElement.querySelectorAll(remainingSelector));
  4222. }
  4223. return [baseElement];
  4224. }; */
  4225. this.queryAll = function (selector, element) {
  4226. //self.log('queryAll: '+selector);
  4227. if (selector) {
  4228. if (Array.isArray(selector)) {
  4229. let elements = self.queryAll(selector[0]);
  4230. selector.shift();
  4231. for (let str of selector) {
  4232. elements = Array.prototype.slice.call(elements).concat(Array.prototype.slice.call(self.queryAll(str)));
  4233. //elements = elements.concat(self.queryAll(str));
  4234. }
  4235. /* console.log('queryAll');
  4236. console.log(elements); */
  4237. return elements;
  4238. } else {
  4239. /*
  4240. if (selector.indexOf(',')>= 0) {
  4241. return element.querySelectorAll(selector)
  4242. }
  4243. // TO DO: check why all the rest
  4244. */
  4245. var routes = selector.split(/[ >]+/);
  4246. if (!element) element = document;
  4247. /* self.log('routes');
  4248. self.log(routes); */
  4249. /* self.log('element[0]');
  4250. self.log(element[0]); */
  4251. for (var index in routes) {
  4252. if (element && element[0]) element = element[0];
  4253. /* self.log('element');
  4254. self.log(element); */
  4255. if (element && element.isConnected) {
  4256. var route = routes[index];
  4257. var routeParts = route.match(/([^:]*):eq\((\d*)\)/);
  4258. /* self.log('route');
  4259. self.log(route);
  4260. self.log('routeParts');
  4261. self.log(routeParts); */
  4262. if (routeParts) {
  4263. var routeElement = String(routeParts[1]);
  4264. var routeIndex = Number(routeParts[2]);
  4265. /* self.log('routeElement');
  4266. self.log(routeElement);
  4267. self.log('routeIndex');
  4268. self.log(routeIndex); */
  4269. if (routeElement.startsWith('.'))
  4270. routeElement = '.' + self.classSelector(routeElement);
  4271. //if (self.exist(routeElement))
  4272. element = element.querySelectorAll(routeElement)[routeIndex];
  4273. if (index == (routes.length - 1) && element) {
  4274. /* console.log('index:'+index);
  4275. console.log('routes.length:'+routes.length); */
  4276. element = [element];
  4277. }
  4278. } else {
  4279. //if (self.exist(route))
  4280. if (route.startsWith('.'))
  4281. routeElement = '.' + self.classSelector(route);
  4282. /* self.log('route');
  4283. self.log(route); */
  4284. element = element.querySelectorAll(route);
  4285. }
  4286. } else {
  4287. //self.log('!element.isConnected');
  4288. element = [];
  4289. }
  4290. }
  4291. //if (element && !Array.isArray(element)) element = [element];
  4292. //if (element && !element.length) element = [element];
  4293. if (!element)
  4294. self.log('No element selected by ' + selector);
  4295. //else
  4296. // if (!Array.isArray(element))
  4297. // element = [element];
  4298. return element;
  4299. }
  4300. } else {
  4301. console.log('%cDOM queryAll requires selector argument', 'color: orange');
  4302. //self.log('DOM "query" without selector parameters');
  4303. }
  4304. };
  4305. /* this.queryAll = function (selector, element) {
  4306. //self.log('query: '+selector);
  4307. if (selector) {
  4308. var routes = selector.split(/[ >]+/);
  4309. if (!element) element = document;
  4310. for (var index in routes) {
  4311. var route = routes[index];
  4312. //onsole.log('route');
  4313. //self.log(route);
  4314. var routeParts = route.match(/(.*):eq\((\d*)\)/);
  4315. //self.log('routeParts');
  4316. //self.log(routeParts);
  4317. if (routeParts) {
  4318. var routeElement = String(routeParts[1]);
  4319. var routeIndex = Number(routeParts[2]);
  4320. //if (self.exist(routeElement))
  4321. element = [element.querySelectorAll(routeElement)[routeIndex]];
  4322. } else {
  4323. //if (self.exist(route))
  4324. element = element.querySelectorAll(route);
  4325. }
  4326. }
  4327. //element.innerHTML = 'test';
  4328. //element.style.display = 'none';
  4329. //if (element && !Array.isArray(element)) element = [element];
  4330. //self.log(element);
  4331. return element;
  4332. } else {
  4333. self.log('DOM "query" without selector parameters');
  4334. }
  4335. } */
  4336. /* var querySelectorAllWithEq = function(selector, document) {
  4337. var remainingSelector = selector;
  4338. var baseElement = document;
  4339. var firstEqIndex = remainingSelector.indexOf(':eq(');
  4340. while (firstEqIndex !== -1) {
  4341. var leftSelector = remainingSelector.substring(0, firstEqIndex);
  4342. var rightBracketIndex = remainingSelector.indexOf(')', firstEqIndex);
  4343. var eqNum = remainingSelector.substring(firstEqIndex + 4, rightBracketIndex);
  4344. eqNum = parseInt(eqNum, 10);
  4345. var selectedElements = baseElement.querySelectorAll(leftSelector);
  4346. if (eqNum >= selectedElements.length) {
  4347. return [];
  4348. }
  4349. baseElement = selectedElements[eqNum];
  4350. remainingSelector = remainingSelector.substring(rightBracketIndex + 1).trim();
  4351. // Note - for now we just ignore direct descendants:
  4352. // 'a:eq(0) > i' gets transformed into 'a:eq(0) i'; we could maybe use :scope
  4353. // to fix this later but support is iffy
  4354. if (remainingSelector.charAt(0) === '>') {
  4355. remainingSelector = remainingSelector.substring(1).trim();
  4356. }
  4357. firstEqIndex = remainingSelector.indexOf(':eq(');
  4358. }
  4359. if (remainingSelector !== '') {
  4360. return Array.from(baseElement.querySelectorAll(remainingSelector));
  4361. }
  4362. return [baseElement];
  4363. }; */
  4364. this.jitcss = function (classes) {
  4365. // https://tailwindcss.com/docs/just-in-time-mode
  4366. if (classes.indexOf('-[') > -1) {
  4367. let classesArr = classes.split(' '); // change to one or more spaces
  4368. // (sm\:|md\:|lg\:|xl\:|2xl\:)?
  4369. self.log('jitcss');
  4370. for (cl of classesArr) {
  4371. self.log(cl);
  4372. let par = [...cl.matchAll(new RegExp('([^-]+)[\-][\[](.+)\]', 'g'))];
  4373. self.log('jitcss');
  4374. self.log(par);
  4375. }
  4376. }
  4377. /* sm:w-1
  4378. .w-1 {
  4379. width: 1em;
  4380. }
  4381. @media (min-width: 640px) {
  4382. .sm\:w-1 { width: 1em }
  4383. }
  4384. */
  4385. };
  4386. this.compileClasses = function (string) {
  4387. var classesString = string;
  4388. // classes shortcuts
  4389. if (self.json.shortcuts && self.json.shortcuts.class) {
  4390. for (shortcut in self.json.shortcuts.class) {
  4391. if (string.indexOf(shortcut) > -1) {
  4392. classesString = self.replaceAll(string, shortcut, self.json.shortcuts.class[shortcut]);
  4393. }
  4394. }
  4395. }
  4396. // dynamic classes
  4397. if (string.indexOf('(') >= 0) {
  4398. //self.log('compileClasses');
  4399. classesString = '';
  4400. let classesArr = string.split(' ');
  4401. for (cl of classesArr) {
  4402. /* self.log('cl');
  4403. self.log(cl); */
  4404. if (cl.indexOf('(') >= 0 && cl.endsWith(')')) {
  4405. let classArr = cl.split('(');
  4406. classArr[1] = classArr[1].slice(0, -1); // remove )
  4407. //let par = [...cl.match(new RegExp('([^\(]+)\(([^\)]+)\)$'))]; // doesn't work
  4408. /* self.log('classArr');
  4409. self.log(classArr);
  4410. self.log('classArr[1]');
  4411. self.log(classArr[1]);
  4412. self.log('self.js(classArr[1])');
  4413. self.log(self.js(classArr[1])); */
  4414. if (Boolean(self.js(classArr[1]))) {
  4415. if (classesString !== '') classesString += ' ';
  4416. classesString += classArr[0];
  4417. }
  4418. } else {
  4419. if (classesString !== '') classesString += ' ';
  4420. classesString += cl;
  4421. }
  4422. }
  4423. if (string == classesString) {
  4424. self.log('wrong dynamic class syntax');
  4425. self.log(string);
  4426. }
  4427. }
  4428. return classesString;
  4429. };
  4430. this.createElement = function (params, selectorParams) {
  4431. let selector = params.selector || params.container;
  4432. var container = selector || self.selector(selectorParams);
  4433. var containerElement = self.query(container);
  4434. var newSelector = self.selector(params, selectorParams); // from 0.9.6: must stay before document.createElement
  4435. /* console.log('append');
  4436. console.log('selector:'+selector);
  4437. console.log('container:'+container);
  4438. console.log('newSelector:'+newSelector); */
  4439. var newElements = [];
  4440. //if (containerElement)
  4441. //containerElements.forEach(function (containerElement, index) {
  4442. if (containerElement) {
  4443. if (!params) params = {};
  4444. var element = document.createElement(params.tag);
  4445. containerElement.appendChild(element);
  4446. if (params.attr) {
  4447. // shortcuts (windy property not in twind) and dynamic classes with js condition
  4448. if (params.attr.class) {
  4449. // replace shortcuts and dynamic classes: class(condition)
  4450. params.attr.class = self.compileClasses(params.attr.class);
  4451. }
  4452. }
  4453. //if (container) element.setAttribute('data-selector', self.selector(params, selectorParams));
  4454. //if (container) element.setAttribute('data-selector', newSelector); // from 0.9.6. removed 1.0.12
  4455. // for IDE
  4456. self.dataStorage.set(element, 'code', params);
  4457. self.dataStorage.set(element, 'key', params.key);
  4458. /* if (params.attr && params.attr.class)
  4459. self.jitcss(params.attr.class); */
  4460. newElements.push(element);
  4461. if (params.attr) self.setAttributes(newElements, params.attr);
  4462. if (params.style) self.css(params, newSelector); // TO DO: deprecated / to be removed;
  4463. /* // attributes TO DO: move up / call self.attr
  4464. if (params.attr)
  4465. for (var attrId in params.attr)
  4466. self.attribute(newElements, attrId, self.replaceProperties(params.attr[attrId]));
  4467. //self.log(self.replaceProperties(params.attr[attrId]));
  4468. //$(selector).attr(attrId, params.attr[attrId]); */
  4469. }
  4470. //});
  4471. return newElements;
  4472. /* for (let element of elements) {
  4473. element.appendChild(string);
  4474. } */
  4475. };
  4476. /* this.newSelector = function (params, selectorParams) {
  4477. var container = self.selector(self.extend({}, params, selectorParams), undefined, true);
  4478. if (container) {
  4479. var selectorObj = {
  4480. container: container,
  4481. //class: params.class,
  4482. //value: params.value,
  4483. //'data-value': params['data-value']
  4484. }; // , selectorParams);
  4485. self.log('container');
  4486. self.log(container);
  4487. var index = document.querySelectorAll(container).length;
  4488. if (index > 1) selectorObj.index = index-1;
  4489. self.log('newSelector');
  4490. self.log(selectorObj);
  4491. return selectorObj;
  4492. } else {
  4493. self.log('container undefine in newSelector');
  4494. self.log('params');
  4495. self.log(params);
  4496. self.log('selectorParams');
  4497. self.log(selectorParams);
  4498. }
  4499. }
  4500. */
  4501. /*
  4502. this.editor = function (params, selectorParams, args) {
  4503. self.log('editor');
  4504. self.log('params');
  4505. self.log(params);
  4506. var selector = self.selector(selectorParams, undefined, true); // self.selector(params, undefined, true) ||
  4507. if (selector) {
  4508. var element = self.query(selector);
  4509. if (element) {
  4510. if (!self.quillElements[selector]) {
  4511. self.quillElements[selector] = new Quill(element, {
  4512. modules: params.modules || { // or default modules
  4513. toolbar: [
  4514. [{ header: [1, 2, false] }],
  4515. ['bold', 'italic', 'underline'],
  4516. ['image', 'code-block']
  4517. ]
  4518. },
  4519. // scrollingContainer: '#scrolling-container',
  4520. placeholder: params.placeholder || 'Write here',
  4521. theme: params.theme || 'bubble'
  4522. });
  4523. }
  4524. if (self.quillElements[selector]) {
  4525. if (params.setContents) {
  4526. var contents = self.replaceProperties(params.setContents, args);
  4527. self.quillElements[selector].setContents(contents);
  4528. }
  4529. if (params.getContents) {
  4530. self.quillElements[params.getContents].getContents();
  4531. }
  4532. if (params.on) {
  4533. for (var eventId in params.on) {
  4534. self.editorChangeFunctions[selector] = params.on;
  4535. if (params.on[eventId]) {
  4536. self.quillElements[selector].on(eventId, function(delta, oldDelta, source) {
  4537. var action = self.editorChangeFunctions[selector][eventId];
  4538. var actionWithResult = self.replaceResult(action, delta);
  4539. //self.do(actionWithResult);
  4540. self.do(actionWithResult);
  4541. });
  4542. }
  4543. }
  4544. }
  4545. }
  4546. } else {
  4547. self.log('can\'t find the element "'+ selector + '" ("editor" function)');
  4548. self.log(params);
  4549. }
  4550. } else {
  4551. self.log('the "editor" function has a wrong selector');
  4552. self.log(params);
  4553. }
  4554. }
  4555. */
  4556. this.do = this.action = this.execute = function (params, selectorParams, args) {
  4557. /* self.log('params');
  4558. self.log(params);
  4559. self.log('selectorParams');
  4560. self.log(selectorParams);
  4561. self.log('args');
  4562. self.log(args); */
  4563. if (params !== undefined && params !== null) { // empty string is ok
  4564. /*
  4565. // problematic for nested {args} / {selector}
  4566. if (selectorParams && typeof selectorParams == 'string') {
  4567. params = self.replaceProperty(params, 'selector', selectorParams);
  4568. }
  4569. if (args) {
  4570. params = self.replaceProperty(params, 'args', args);
  4571. }
  4572. */
  4573. if (typeof params == 'string')
  4574. params = self.replaceProperties(params, args);
  4575. let pluginsRequired = self.pluginsRequired(params);
  4576. /* self.log('pluginsRequired');
  4577. self.log(pluginsRequired); */
  4578. if (pluginsRequired.length > 0)
  4579. //let params = [params, args, selectorParams];
  4580. self.pluginsLoader(pluginsRequired, self.do, [params, selectorParams, args]);
  4581. else {
  4582. if (Array.isArray(params))
  4583. for (var obj of params)
  4584. self.do(obj, selectorParams, args); // -> execute dopo aver portato qui pluginsLoaded
  4585. else if (typeof params == 'object') {
  4586. /* if (params.after) {
  4587. let paramsAfter = params.after;
  4588. let paramsWithoutAfter = self.cloneObject(params);
  4589. delete paramsWithoutAfter.after;
  4590. self.timer({
  4591. after: paramsAfter,
  4592. do: paramsWithoutAfter
  4593. });
  4594. } else {
  4595. */
  4596. if (params.if == undefined || self.if(params.if)) { // || Boolean(self.js(params.if))) { // , args
  4597. /* console.log('IF---------------');
  4598. console.log(params.if);
  4599. console.log(params); */
  4600. if (self.only(params.roles, params.user)) {
  4601. //if (!params) params = {};
  4602. //var newContainer; //self.newSelector(params, selectorParams); // {container: selector}
  4603. // Add an element in the DOM
  4604. if (params.tag) {
  4605. var selector = self.selector(params, selectorParams);
  4606. /* self.log('selector');
  4607. self.log(selector); */
  4608. self.extendJsonFromElement(params); // or selectorParams
  4609. //newContainer = {selector: selector};
  4610. //if (1) //self.user('uid') == 'L0y20rjPp6a6ejqVuDXuTWCU2rH3') //'ocXuFBV4aWcy7KZMAmi6mICFi872')
  4611. // create new html element
  4612. var newElements = self.createElement(params, selectorParams);
  4613. /* if (params.key == 'text')
  4614. //let element = self.query(self.selector(params.selector));
  4615. newElements.innerText = self.text(nested); */
  4616. if (params.matchMedia) {
  4617. for (var mediaEvent in params.matchMedia) {
  4618. self.matchMedia(params.matchMedia[mediaEvent], mediaEvent);
  4619. }
  4620. }
  4621. if (params.html) {
  4622. self.html(params.html, selector, args);
  4623. } else {
  4624. // nested html tags as property
  4625. for (var par in params) // && (par !== 'attr')
  4626. if ((nodes.exclude.indexOf(par) < 0) && (nodes.params.indexOf(par) < 0))
  4627. self.nested({ key: par, obj: params[par], selector: { selector: selector }, args: args });
  4628. }
  4629. self.on(params.on, { selector: selector });
  4630. } else {
  4631. var selector = self.selector(params, selectorParams);
  4632. for (var par in params)
  4633. if ((nodes.exclude.indexOf(par) < 0) && (nodes.params.indexOf(par) < 0))
  4634. self.nested({ key: par, obj: params[par], selector: selector, args: args });
  4635. if (params.on)
  4636. self.on(params.on, { selector: selector });
  4637. }
  4638. } // end of self.only
  4639. }
  4640. //}
  4641. } else if (typeof params == 'function')
  4642. return params(selectorParams);
  4643. else
  4644. self.log('can\'t execute: ' + params);
  4645. }
  4646. }
  4647. };
  4648. this.callback = function (params) {
  4649. /* console.log('callback');
  4650. console.log(params); */
  4651. // {do, find, replace}
  4652. if (params) {
  4653. var path = params.to;
  4654. if (params.var) path = 'var ' + params.var; // TO DO: remove
  4655. let selector;
  4656. let element = params.element; // elementToSelector ?
  4657. if (element && element.isConnected) params.value = self.elementToSelector(element);
  4658. if (path) {
  4659. var context = self.context(path);
  4660. self.element({ path: path, value: params.value, root: context });
  4661. }
  4662. if (params.do)
  4663. self.do(params.do, selector);
  4664. }
  4665. };
  4666. this.nested = function (params) {
  4667. /* console.log('nested');
  4668. console.log(params); */
  4669. // check plugins required
  4670. let pluginsRequired = self.pluginsRequired(params.key);
  4671. if (pluginsRequired.length > 0) {
  4672. self.pluginsLoader(pluginsRequired, self.nested, [params]);
  4673. } else {
  4674. // TO DO: regular expression like in this.element (should include setup and also :)
  4675. if (params.key.startsWith('set ')) {
  4676. self.setData({ key: params.key.substr(4), value: params.obj });
  4677. } else if (params.key.startsWith('var ') || params.key.startsWith('data ') || params.key.startsWith('set ')) {
  4678. // TO DO: remove this option. Is too ambiguous for debug -> use set
  4679. // deprecated from 1.0.4
  4680. console.log('%cdeprecated key: "' + params.key + '". Use "set key": "value"}', 'color:orange');
  4681. // Data setting prefix
  4682. // should be removed and replaced with the method "set" to improve the compatibility
  4683. // with the other possible keys (js functions, jsonic methods, html tags ex. <data class=""></data>)
  4684. // https://www.w3schools.com/tags/tag_data.asp
  4685. self.setData({ key: params.key, value: params.obj });
  4686. } else {
  4687. // CHECK IF KEY IS METHOD
  4688. //console.log('check if is a method');
  4689. var method = self.element({ path: params.key, root: self.methods });
  4690. if (method) { // search in jsonic.methods
  4691. self.log('METHOD: ' + params.key, 'grey');
  4692. var methodArgs = params.obj;
  4693. /* if (params.key == 'swiper init') {
  4694. self.log('method: ' + params.key);
  4695. self.log('methodArgs');
  4696. self.log(methodArgs);
  4697. self.log('params.selector');
  4698. self.log(params.selector);
  4699. self.log('-----------');
  4700. } */
  4701. //methodArgs = self.replaceProperty(methodArgs, 'selector', params.selector);
  4702. method(methodArgs, params.selector, params.args);
  4703. /* } else if (params.key == 'set') { // TO DO: REMOVE
  4704. // JS METHOD (old)
  4705. var actionObj = {};
  4706. actionObj[params.key] = params.obj;
  4707. self.do(actionObj, params.selector); */
  4708. /* } else if (nodes.functions.indexOf(params.key) >= 0) { // TO DO: REMOVE
  4709. // JS METHOD (old)
  4710. var actionObj = {};
  4711. actionObj[params.key] = params.obj;
  4712. //self.do(actionObj, undefined, params.selector);
  4713. self.do(actionObj, params.selector); */
  4714. } else {
  4715. // CHECK IF KEY IS A PARTS
  4716. //console.log('check if is a part');
  4717. // shortcut: content
  4718. let nested;
  4719. let part;
  4720. var jsonicPart = false;
  4721. if (self.json.parts) { // && par.match(/[.>]+/))
  4722. part = self.element({ path: self.replaceAll(params.key, ':', '.'), root: self.json.parts });
  4723. /* if (par.indexOf(':')>0 && !part) {
  4724. jsonicPart = true;
  4725. self.firebaseGetPart({localPath:localPath, container: params.selector, arg:params.obj});
  4726. } */
  4727. }
  4728. if (part) {
  4729. self.log('PART: ' + params.key, 'grey');
  4730. /* console.log('params');
  4731. console.log(params); */
  4732. var partObj = params.obj;
  4733. //nested = self.replaceProperty(part, 'value', params.obj); // obsolete?
  4734. //nested = self.replaceProperty(part, 'arg', partObj); // obsolete
  4735. //if (typeof partObj == 'string' && partObj.indexOf('{') >= 0) { // obsolete?
  4736. // TO DO: this should be already inside self.do
  4737. partObj = self.replaceProperties(partObj);
  4738. // for backward compatibility can be partObj, null, true) // true is removeUndefined
  4739. //}
  4740. /* console.log('partObj');
  4741. console.log(partObj);
  4742. */
  4743. //var partSelector = params.selector || partObj.selector;
  4744. // TO DO: Check this
  4745. // seems a workaround for fantacards/ui:qrcode
  4746. // parts can receive the parameters {selector:..., setup:...}
  4747. partObj.selector = partObj.selector || params.selector;
  4748. // TO DO: deprecated fantacards:setPlayer
  4749. if (partObj.setup) partObj = partObj.setup;
  4750. // overwrites partObj.selector but execute receive params.selector
  4751. // TO DO: replaceProperty should be improved to get also sub values like {arguments:on.success}
  4752. //nested = self.replaceProperty(part, 'setup', partObj); // {setup} -> {arguments}
  4753. //nested = self.replaceProperty(nested, 'arguments', partObj);
  4754. //nested = self.replacePropertyWithPrefix(part, 'setup:', partObj); // {setup} -> {arguments}
  4755. //nested = self.replacePropertyWithPrefix(nested, 'arguments:', partObj);// to tix
  4756. nested = self.replacePropertyWithPrefix(part, 'setup', partObj); // {setup} -> {arguments}
  4757. nested = self.replacePropertyWithPrefix(nested, 'arguments', partObj); // to tix
  4758. self.extendJsonFromElement(nested); // or selectorParams
  4759. //self.do(nested, partSelector, partObj);
  4760. self.do(nested, params.selector, partObj);
  4761. /*
  4762. self.log('nested');
  4763. self.log(nested);
  4764. self.log('part key');
  4765. self.log(params.key);
  4766. self.log('part obj');
  4767. self.log(part);
  4768. */
  4769. } else { // if (!jsonicPart) { // should be if (par !== 'on', 'attr', 'style', 'items/data')
  4770. // params.key is not var/data, a method, a part
  4771. //var jsFunction = self.element({path: params.key, root: self.functions});
  4772. if (self.json && self.json.functions && params.key && self.json.functions[params.key]) {
  4773. //if (self.json.functions[params.key]) {
  4774. self.log('FUNCTION: ' + params.key, 'grey');
  4775. /* self.log('pluginsRequired');
  4776. self.log(pluginsRequired); */
  4777. let args = self.replaceProperties(params.obj, undefined, true); // undefined properties -> ''
  4778. /* console.log('%cargs', 'color:red');
  4779. console.log(args); */
  4780. if (!args || !Array.isArray(args)) args = [args];
  4781. if (self.json.functions[params.key].requires) {
  4782. let pluginsRequired = [];
  4783. for (let plugin of self.json.functions[params.key].requires) {
  4784. if (!self.pluginsLoaded[plugin])
  4785. pluginsRequired.push({ "name": plugin, version: "" });
  4786. }
  4787. if (pluginsRequired.length > 0)
  4788. //self.pluginsLoader(pluginsRequired, self.functions[params.key], args);
  4789. self.pluginsLoader(pluginsRequired, self.function, [{ name: params.key, arguments: args }]);
  4790. else {
  4791. self.log('Plugins already loaded: ' + params.key, 'grey');
  4792. self.function({ name: params.key, arguments: args });
  4793. //self.functions[params.key](...args);
  4794. }
  4795. } else {
  4796. /* let args = self.replaceProperties(params.obj);
  4797. if (!args || !Array.isArray(args)) args = [args]; */
  4798. self.log('Function without plugin required: ' + params.key, 'grey');
  4799. self.function({ name: params.key, arguments: args }); // TO DO: check why here it can't have []
  4800. //self.functions[params.key](...args);
  4801. }
  4802. } else {
  4803. var windowFunction = self.element({ path: params.key, root: window });
  4804. if (typeof windowFunction === 'function') {
  4805. self.log('WINDOW function: ' + params.key, 'grey');
  4806. windowFunction(self.replaceProperties(params.obj, undefined, true)); // undefined properties -> ''
  4807. //windowFunction(self.replaceProperties(params.obj));
  4808. } else if (windowFunction !== undefined) {
  4809. self.log('window.' + params.key + ' is not a function', 'red');
  4810. //self.log(params.key + ' not found', 'red');
  4811. // use set for window assignment
  4812. /*
  4813. self.element({path: params.key, value:params.obj, root: window}); */
  4814. } else {
  4815. // NESTED HTML
  4816. // Need to be improved. with nestedAction and nestedTag
  4817. // here we can search only nestedAction
  4818. // and from html we can search only for nestedTag's
  4819. //nested = params.obj; // removed in 1.0.1
  4820. // if is a nested html params.selector is required
  4821. // impossible to understand if we are inside an html method
  4822. // because the html tags can be nested and with any name
  4823. if (params.selector) { // added in 1.0.1
  4824. self.log('TAG: ' + params.key, 'grey');
  4825. // should be also in this.html function if params is an array
  4826. let pluginsRequired = self.pluginsRequiredByTag(params.obj, params.key);
  4827. if (pluginsRequired.length > 0) {
  4828. let htmlTagParams = [params.obj, params.selector, params.key];
  4829. self.pluginsLoader(pluginsRequired, self.htmlTag, htmlTagParams);
  4830. } else {
  4831. self.htmlTag(params.obj, params.selector, params.key); // tagParam = params.key
  4832. //if (nested.database) self.addFirebaseTag(self.extend({}, nested, params.selector));
  4833. }
  4834. } else {
  4835. self.log(params.key + ' not found', 'red');
  4836. }
  4837. }
  4838. }
  4839. }
  4840. }
  4841. }
  4842. }
  4843. };
  4844. this.setData = function (params) {
  4845. //self.log('setData');
  4846. let setObj = {};
  4847. setObj[params.key] = params.value;
  4848. self.set(setObj);
  4849. /* if (params.path.indexOf('{') >= 0)
  4850. params.path = self.replaceProperties(params.path);
  4851. if (typeof params.value == 'string' && params.value.indexOf('{') >= 0)
  4852. params.value = self.replaceProperties(params.value);
  4853. self.element({path: params.path, value: params.value}); */
  4854. /* self.log(params.path);
  4855. self.log(self.element({path: params.path})); */
  4856. };
  4857. this.partContainers = {};
  4858. this.pluginsRequiredByTag = function (params, tagKey) {
  4859. // self.log('pluginsRequiredByTag');
  4860. /* self.log('params');
  4861. self.log(params);
  4862. self.log('par');
  4863. self.log(par); */
  4864. if (self.json.resources) {
  4865. // analize function object or array of objects
  4866. const pluginsTags = self.json.resources.pluginsTags;
  4867. const pluginsAttr = self.json.resources.pluginsAttr;
  4868. var pluginsRequired = [];
  4869. if (pluginsTags[tagKey] && !self.pluginsLoaded[pluginsTags[tagKey].name])
  4870. pluginsRequired.push(pluginsTags[tagKey]);
  4871. if (typeof params == 'string') {
  4872. // for example: "tagName": "string" where tagName requires a plugin
  4873. } else if (typeof params == 'object') {
  4874. var objArray;
  4875. if (Array.isArray(params)) objArray = params; else objArray = [params];
  4876. for (var obj of objArray) {
  4877. if (obj.attr) { // attr
  4878. var attr = 'data-icon';
  4879. if (obj.attr[attr]) {
  4880. if (pluginsAttr[attr] && !self.pluginsLoaded[pluginsAttr[attr].name])
  4881. pluginsRequired.push(pluginsAttr[attr]);
  4882. }
  4883. }
  4884. }
  4885. }
  4886. return pluginsRequired;
  4887. } else {
  4888. // should load resources
  4889. return false;
  4890. }
  4891. };
  4892. /*
  4893. 'locale': {
  4894. unit: month, weekday
  4895. format: long, short, narrow
  4896. index: 1,
  4897. lang: page:language
  4898. */
  4899. this.calendar = function (params, args) {
  4900. const localeName = (self.json.setup.language !== 'en') ? self.json.setup.language : 'en-US';
  4901. let calendarArr, todayIndex;
  4902. if (params.unit) {
  4903. switch (params.unit) {
  4904. case 'month':
  4905. const monthFormat = params.format || 'long';
  4906. var format = new Intl.DateTimeFormat(localeName, { month: monthFormat }).format;
  4907. calendarArr = [...Array(12).keys()].map((m) => format(new Date(Date.UTC(2021, m))));
  4908. todayIndex = new Date().getMonth();
  4909. break;
  4910. case 'weekday':
  4911. const weekdayFormat = params.format || 'long';
  4912. var format = new Intl.DateTimeFormat(localeName, { weekday: weekdayFormat }).format;
  4913. calendarArr = [...Array(7).keys()].map((day) => format(new Date(Date.UTC(2021, 5, day))));
  4914. todayIndex = self.weekday();
  4915. break;
  4916. default:
  4917. self.log('"calendar" function can\'t recognize "unit" parameter');
  4918. self.log(params.unit);
  4919. break;
  4920. }
  4921. if (calendarArr) {
  4922. if (params.index !== undefined) {
  4923. params.index = self.js(params.index);
  4924. let index = Number(self.replaceProperties(params.index, args));
  4925. return calendarArr[index];
  4926. } else {
  4927. return calendarArr[todayIndex];
  4928. }
  4929. } else {
  4930. self.log('"calendar" function can\'t recognize "unit" or "format" parameters');
  4931. }
  4932. } else {
  4933. self.log('"calendar" function requires "unit" parameter');
  4934. }
  4935. };
  4936. this.month = function (params, monthFormat = 'long') {
  4937. const localeName = (self.json.setup.language !== 'en') ? self.json.setup.language : 'en-GB';
  4938. const format = new Intl.DateTimeFormat(localeName, { month: monthFormat }).format;
  4939. const weekdayArr = [...Array(12).keys()].map((m) => format(new Date(Date.UTC(2021, m))));
  4940. if (params !== undefined) {
  4941. var index = Number(self.replaceProperties(params));
  4942. return weekdayArr[index];
  4943. }
  4944. else
  4945. return weekdayArr;
  4946. };
  4947. this.weekday = function (params, weekdayFormat) {
  4948. //weekdayFormat = weekdayFormat || 'long';
  4949. const localeName = (self.json.setup.language !== 'en') ? self.json.setup.language : 'en-GB';
  4950. const format = new Intl.DateTimeFormat(localeName, { weekday: weekdayFormat }).format;
  4951. const weekdayArr = [...Array(7).keys()].map((day) => format(new Date(Date.UTC(2021, 5, day))));
  4952. var result;
  4953. if (params !== undefined) {
  4954. var index = Number(self.replaceProperties(params));
  4955. result = weekdayArr[index];
  4956. }
  4957. else
  4958. result = weekdayArr;
  4959. //if (weekdayFormat == 'short') result = result.substring(0,3);
  4960. return result;
  4961. };
  4962. /* this.array = function (params, args) { // TO DO: to be removed
  4963. self.log('array');
  4964. self.log(params);
  4965. if (Array.isArray(params))
  4966. return params;
  4967. else if (typeof params == 'string')
  4968. return self.docElement(params);
  4969. else if (typeof params == 'object') {
  4970. if (params && Object.keys(params).length > 0) { // actionObj !== {}
  4971. var actionKey = Object.keys(params)[0]; // -> for
  4972. var actionFunction = self.docElement('Array.prototype.' + actionKey); // method in window
  4973. var actionValue = params[actionKey];
  4974. //actionValue = self.compile(actionValue, args); // array -> undefined
  4975. if (!Array.isArray(actionValue))
  4976. actionValue = [actionValue];
  4977. if (actionFunction) {
  4978. if (typeof actionFunction == 'function')
  4979. return actionFunction.call(actionValue);
  4980. else
  4981. return actionFunction;
  4982. } else {
  4983. self.log('unknown window function');
  4984. return params; // return the same object
  4985. }
  4986. } else {
  4987. self.log('empty function');
  4988. //self.log(actionObj);
  4989. return undefined
  4990. }
  4991. }
  4992. } */
  4993. this.method = function (params, args) {
  4994. var value;
  4995. if (typeof params == 'string') {
  4996. return self.docElement(params);
  4997. } else {
  4998. if ((params.if == undefined) || self.if(params.if, undefined, args)) {
  4999. if (self.notEmptyObject(params)) {
  5000. var actionKey = Object.keys(params)[0]; // -> for
  5001. var actionFunction = self.docElement(actionKey); // method in window
  5002. var actionValue = params[actionKey];
  5003. //actionValue = self.compile(actionValue, args);
  5004. if (!Array.isArray(actionValue))
  5005. actionValue = [actionValue];
  5006. if (actionFunction) {
  5007. if (typeof actionFunction == 'function')
  5008. return actionFunction(...actionValue);
  5009. else
  5010. return actionFunction;
  5011. } else {
  5012. self.log('unknown function');
  5013. self.log(params);
  5014. return params; // return the same object
  5015. }
  5016. } else {
  5017. //self.log('empty function');
  5018. //self.log(params);
  5019. return undefined;
  5020. }
  5021. }
  5022. }
  5023. /*
  5024. var methodArgs = self.compile(actionValue, args);
  5025. if (value !== undefined) {
  5026. if (!Array.isArray(methodArgs))
  5027. methodArgs = [methodArgs];
  5028. self.log('params');
  5029. self.log(params);
  5030. for (let method of methodArgs) {
  5031. for (let key in method) {
  5032. if (key !== 'args') {
  5033. self.log('key');
  5034. self.log(key);
  5035. if (value[key])
  5036. if (method[key] && method[key] !== '') { // va aggiunto? -> && value[key](method[key]) method[key] !== undefined &&
  5037. methodArgs = method[key];
  5038. self.log('methodArgs');
  5039. self.log(methodArgs);
  5040. if (!Array.isArray(methodArgs))
  5041. methodArgs = [methodArgs];
  5042. for (let index in methodArgs) {
  5043. let methodArg = self.compile(methodArgs[index], args);
  5044. //if (typeof methodArg == 'string' && methodArg !== '' && methodArg == Number(methodArg)) // can be in compile
  5045. methodArgs[index] = methodArg; // Number(methodArg)
  5046. }
  5047. //try {
  5048. //} catch (error) {
  5049. // self.log('Dayjs function error');
  5050. if (typeof value[key] == 'function')
  5051. value = value[key](...methodArgs); // ES6 way
  5052. } else
  5053. if (typeof value[key] == 'function')
  5054. value = value[key]();
  5055. else
  5056. value = value[key];
  5057. } else {
  5058. self.log('Method ' + key + ' in ' + methodName + ' not exist');
  5059. }
  5060. }
  5061. }
  5062. } else {
  5063. self.log('method '+ methodName +' undefined');
  5064. }
  5065. */
  5066. };
  5067. this.Number = function (params, args) {
  5068. self.log('Number');
  5069. return self.method({ "Number": params }, args);
  5070. };
  5071. this.String = function (params, args) {
  5072. self.log('String');
  5073. return self.method({ "String": params }, args);
  5074. // jsonic.compile({String:{args:'1',padStart:[2, '0']}})
  5075. /*
  5076. "text": {
  5077. "String": {
  5078. "args": "{hour}",
  5079. "padStart": [
  5080. "0",
  5081. 2
  5082. ]
  5083. }
  5084. }
  5085. */
  5086. };
  5087. this.Math = function (params, args) {
  5088. return self.method(params, args, 'Math');
  5089. /* if (!Array.isArray(params))
  5090. params = [params];
  5091. for (let method of params) {
  5092. for (let key in method) {
  5093. self.log(key);
  5094. if (method[key] && method[key] !== '' && value[key](method[key])) {
  5095. //methodArgs = self.compile(method[key]);
  5096. methodArgs = method[key];
  5097. if (!Array.isArray(methodArgs))
  5098. methodArgs = [methodArgs];
  5099. for (let index in methodArgs) {
  5100. let methodArg = self.compile(methodArgs[index]);
  5101. if (typeof methodArg == 'string' && methodArg !== '' && methodArg == Number(methodArg)) // can be in compile
  5102. methodArgs[index] = Number(methodArg);
  5103. }
  5104. value = value[key](...methodArgs); // ES6 way
  5105. } else
  5106. value = value[key]();
  5107. }
  5108. }
  5109. return value; */
  5110. };
  5111. this.dayjs = function (params, args) {
  5112. return self.method(params, args, 'dayjs');
  5113. /* self.log('dayjs');
  5114. var value = dayjs();
  5115. if (params.time)
  5116. value = dayjs(params.time);
  5117. //value = self.compile(value);
  5118. if (!Array.isArray(params))
  5119. params = [params];
  5120. for (let method of params) {
  5121. for (let key in method) {
  5122. if (key == 'time') {
  5123. } else if (value[key]) {
  5124. if (method[key] && method[key] !== '' && value[key](method[key])) {
  5125. //methodArgs = self.compile(method[key]);
  5126. methodArgs = method[key];
  5127. if (!Array.isArray(methodArgs))
  5128. methodArgs = [methodArgs];
  5129. for (let index in methodArgs) {
  5130. let methodArg = self.compile(methodArgs[index]);
  5131. if (typeof methodArg == 'string' && methodArg !== '' && methodArg == Number(methodArg)) // can be in compile
  5132. methodArgs[index] = Number(methodArg);
  5133. }
  5134. value = value[key](...methodArgs); // ES6 way
  5135. } else
  5136. value = value[key]();
  5137. } else {
  5138. try {
  5139. } catch (error) {
  5140. self.log('Dayjs function error');
  5141. self.log(error);
  5142. self.log('key');
  5143. self.log(key);
  5144. self.log('method[key]');
  5145. self.log(method[key]);
  5146. }
  5147. }
  5148. }
  5149. self.log('value');
  5150. self.log(value);
  5151. }
  5152. return value; */
  5153. };
  5154. this.moment = function (params, args) {
  5155. return self.method(params, args, 'moment');
  5156. /* self.log('moment');
  5157. var value = moment();
  5158. if (params.time)
  5159. value = moment(params.time);
  5160. if (!Array.isArray(params))
  5161. params = [params];
  5162. for (let method of params) {
  5163. for (let key in method) {
  5164. if (key !== 'time') {
  5165. if (key == 'add') {
  5166. value = value.add(Number(method[key].value), method[key].unit);
  5167. } else if (key == 'subtract') {
  5168. value = value.add(Number(method[key].value), method[key].unit);
  5169. } else if (method[key] && method[key] !== '' && value[key](method[key])) {
  5170. value = value[key](method[key]);
  5171. } else {
  5172. self.log('Moment function error: ');
  5173. self.log('key');
  5174. self.log(key);
  5175. self.log('method[key]');
  5176. self.log(method[key]);
  5177. }
  5178. }
  5179. }
  5180. self.log('value');
  5181. self.log(value);
  5182. }
  5183. return value;
  5184. */
  5185. };
  5186. /* 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'];
  5187. for (var method in methodsList) {
  5188. if (params[method]) value = value[method](params[method]);
  5189. } */
  5190. /* for (let param in params) {
  5191. if (param !== 'time') {
  5192. if (typeof value == 'object') {
  5193. //if (param == 'day') value = value.day(Number(params[param]));
  5194. if (param == 'add') {
  5195. self.log('params.add.value');
  5196. self.log(params.add.value);
  5197. self.log('params.add.unit');
  5198. self.log(params.add.unit);
  5199. self.log('value');
  5200. self.log(value);
  5201. value.add(Number(5), params.add.unit);
  5202. self.log('value.format(H)');
  5203. self.log(value.format('H'));
  5204. }
  5205. else if (param == 'subtract') value.add(Number(params.subtract.value), params.subtract.unit);
  5206. else if (value[param] && value[param](params[param]))
  5207. value = value[param](params[param]);
  5208. else
  5209. self.log('Moment function error: '+ params[param]);
  5210. }
  5211. self.log('value');
  5212. self.log(value);
  5213. }
  5214. }
  5215. */
  5216. /* this.addNestedTag = function (params, selectorParams) {
  5217. var selector = self.selector(self.extend({}, params, selectorParams));
  5218. // remove tag params
  5219. var nestedParams = self.cloneObject(params);
  5220. 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'];
  5221. for (var par in nestedParams) {
  5222. if (tagParams.indexOf(par) >= 0)
  5223. delete nestedParams[par]
  5224. }
  5225. // serach for nested params
  5226. 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'];
  5227. for (var par in nestedParams) {
  5228. self.log(par + ' NESTED IN ' + selector);
  5229. if (mainTags.indexOf(par) >= 0) {
  5230. self.htmlTag(nestedParams[par], {container: selector}, mainTags[mainTags.indexOf(par)]);
  5231. }
  5232. }
  5233. } */
  5234. this.dynamicCss = function (selector, property, value) {
  5235. if (value.indexOf('{') >= 0) {
  5236. var resizeData = self.dataStorage.get(element, "resize");
  5237. //var resizeData = $(selector).data('resize');
  5238. if (!resizeData) resizeData = {};
  5239. resizeData[property] = value;
  5240. var resizeData = self.dataStorage.set(element, "resize", resizeData);
  5241. //$(selector).data('resize', resizeData);
  5242. if (!self.resizeActions[selector]) self.resizeActions[selector] = {};
  5243. self.resizeActions[selector][property] = value;
  5244. var result = self.replaceProperties(value) || '';
  5245. //$(selector).css(property, result); // al cambio di pagina su this.page applichiamo self.resizeEvent()
  5246. /* self.log('----------------------');
  5247. self.log('dynamicCss');
  5248. self.log('selector');
  5249. self.log(selector);
  5250. self.log('property');
  5251. self.log(property);
  5252. self.log('value');
  5253. self.log(value);
  5254. self.log('result');
  5255. self.log(result);
  5256. self.log('----------------------');
  5257. */
  5258. } else {
  5259. var style = {};
  5260. style[property] = value;
  5261. self.css({
  5262. style: style
  5263. });
  5264. //$(selector).css(property, value);
  5265. }
  5266. };
  5267. /* this.calc = function (selector, property, value) {
  5268. if (value.indexOf('{')>= 0) {
  5269. //var calcFunction = String(element.match(/calc\(([^\)]*)\)/)[0]);
  5270. var result = self.replaceProperties(value) || '';
  5271. return result;
  5272. } else {
  5273. return value;
  5274. }
  5275. } */
  5276. /* this.hTag = function (params, selectorParams, index) { // this.img already exist
  5277. if (Array.isArray(params)) {
  5278. for (var index in params)
  5279. self.hTag(params[index], selectorParams);
  5280. } else {
  5281. if (params.items) {
  5282. var itemsArray = params.items;
  5283. delete params.items;
  5284. for (var index in itemsArray) {
  5285. self.hTag(self.replaceItems(params, itemsArray[index]), selectorParams);
  5286. }
  5287. } else {
  5288. if (typeof params == 'string') {params = {text: params}};
  5289. params.tag = 'h'+index;
  5290. var paramsReplaced = self.replaceProperties(params);
  5291. self.addTag(paramsReplaced, selectorParams);
  5292. }
  5293. }
  5294. } */
  5295. /* this.img = function (params, selectorParams, args) {
  5296. //self.log('img');
  5297. var tagParam = 'img';
  5298. var mainParam = 'src';
  5299. if (Array.isArray(params)) {
  5300. for (var index in params)
  5301. self.img(params[index], selectorParams);
  5302. } else {
  5303. if (params.items) {
  5304. var itemsArray = params.items;
  5305. delete params.items;
  5306. for (var index in itemsArray) {
  5307. self.img(self.replaceItems(params, itemsArray[index]), selectorParams);
  5308. }
  5309. } else {
  5310. if (typeof params == 'string') {params = {src: params}};
  5311. params.tag = 'img';
  5312. //if (params.media) params.src = '{media:' + params.media + '}'; // can go under replaceProperties
  5313. var paramsReplaced = self.replaceProperties(params, args);
  5314. //var container = params.container || self.selector(selectorParams);
  5315. self.addTag(paramsReplaced, selectorParams);
  5316. }
  5317. }
  5318. } */
  5319. /* this.small = function (params, selectorParams) { // bootstrap
  5320. var mainParam = 'text';
  5321. if (Array.isArray(params)) {
  5322. for (var index in params)
  5323. self.small(params[index], selectorParams);
  5324. } else {
  5325. if (params.items) {
  5326. var itemsArray = params.items;
  5327. delete params.items;
  5328. for (var index in itemsArray) {
  5329. self.small(self.replaceItems(params, itemsArray[index]), selectorParams);
  5330. }
  5331. } else {
  5332. if (typeof params == 'string') {params = {text: params}};
  5333. params.tag = 'small';
  5334. self.addTag(params, selectorParams);
  5335. if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5336. }
  5337. }
  5338. } */
  5339. /* this.button = function (params, selectorParams) { // bootstrap
  5340. var mainParam = 'text';
  5341. if (Array.isArray(params)) {
  5342. for (var index in params)
  5343. self.button(params[index], selectorParams);
  5344. } else {
  5345. if (params.items) {
  5346. var itemsArray = params.items;
  5347. delete params.items;
  5348. for (var index in itemsArray) {
  5349. self.button(self.replaceItems(params, itemsArray[index]), selectorParams);
  5350. }
  5351. } else {
  5352. if (typeof params == 'string') {params = {text: params}};
  5353. params.tag = 'button';
  5354. self.addTag(params, selectorParams);
  5355. if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5356. }
  5357. }
  5358. } */
  5359. /*
  5360. this.input = function (params, selectorParams) {
  5361. var tagParam = 'input';
  5362. var mainParam = 'text';
  5363. if (Array.isArray(params)) {
  5364. for (var index in params)
  5365. self.input(params[index], selectorParams);
  5366. } else {
  5367. if (params.items) {
  5368. var itemsArray = params.items;
  5369. delete params.items;
  5370. for (var index in itemsArray) {
  5371. self.input(self.replaceItems(params, itemsArray[index]), selectorParams);
  5372. }
  5373. } else {
  5374. self.addTag(self.createTagParams(params, tagParam, mainParam), selectorParams);
  5375. if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5376. }
  5377. }
  5378. }
  5379. this.span = function (params, selectorParams) {
  5380. var mainParam = 'text';
  5381. if (Array.isArray(params)) {
  5382. for (var index in params)
  5383. self.span(params[index], selectorParams);
  5384. } else {
  5385. if (params.items) {
  5386. var itemsArray = params.items;
  5387. delete params.items;
  5388. for (var index in itemsArray) {
  5389. self.span(self.replaceItems(params, itemsArray[index]), selectorParams);
  5390. }
  5391. } else {
  5392. params.tag = 'span';
  5393. // qui ci andrebbe replaceProperties
  5394. if (typeof params == 'string') {params = {text: params}};
  5395. self.addTag(params, selectorParams);
  5396. if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5397. }
  5398. }
  5399. }
  5400. */
  5401. /* this.a = function (params, selectorParams) {
  5402. var mainParam = 'text';
  5403. var tagParam = 'a';
  5404. if (Array.isArray(params)) {
  5405. for (var index in params)
  5406. self.a(params[index], selectorParams);
  5407. } else {
  5408. if (params.items) {
  5409. var itemsArray = params.items;
  5410. delete params.items;
  5411. for (var index in itemsArray) {
  5412. self.a(self.replaceItems(params, itemsArray[index]), selectorParams);
  5413. }
  5414. } else {
  5415. if (typeof params == 'string') {params = {text: params}};
  5416. params.tag = 'a';
  5417. self.addTag(params, selectorParams);
  5418. if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5419. }
  5420. }
  5421. } */
  5422. /* this.p = function (params, selectorParams) {
  5423. var mainParam = 'html';
  5424. if (Array.isArray(params)) {
  5425. for (var index in params)
  5426. self.p(params[index], selectorParams);
  5427. } else {
  5428. if (params.items) {
  5429. var itemsArray = params.items;
  5430. delete params.items;
  5431. for (var index in itemsArray) {
  5432. self.p(self.replaceItems(params, itemsArray[index]), selectorParams);
  5433. }
  5434. } else {
  5435. if (typeof params == 'string') {params = {html: params}};
  5436. params.tag = 'p';
  5437. self.addTag(params, selectorParams);
  5438. if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5439. }
  5440. }
  5441. } */
  5442. /* this.lottie = function (params, selectorParams, args) {
  5443. self.htmlTag(params, selectorParams, 'lottie-player', 'src');
  5444. } */
  5445. //this.lottie = function (params, selectorParams, args) {
  5446. // self.htmlTag(params, selectorParams, 'lottie-player', 'src');
  5447. /* self.log('lottie');
  5448. var mainParam = 'src';
  5449. var tagParam = 'lottie-player';
  5450. if (Array.isArray(params)) {
  5451. for (var index in params)
  5452. self.lottie(params[index], selectorParams);
  5453. } else {
  5454. if (params.items) {
  5455. var itemsArray = params.items;
  5456. delete params.items;
  5457. for (var index in itemsArray) {
  5458. self.lottie(self.replaceItems(params, itemsArray[index]), selectorParams);
  5459. }
  5460. } else {
  5461. var container = params.container || self.selector(selectorParams);
  5462. // qui ci andrebbe replaceProperties
  5463. //this.alert(self.selector(self.extend({}, params, selectorParams)));
  5464. self.addTag(self.createTagParams(params, tagParam, mainParam), {container: container});
  5465. //if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5466. }
  5467. } */
  5468. //}
  5469. /* this.iframe = function (params, selectorParams) {
  5470. var mainParam = 'src';
  5471. if (Array.isArray(params)) {
  5472. for (var index in params)
  5473. self.iframe(params[index], selectorParams);
  5474. } else {
  5475. if (params.items) {
  5476. var itemsArray = params.items;
  5477. delete params.items;
  5478. for (var index in itemsArray) {
  5479. self.iframe(self.replaceItems(params, itemsArray[index]), selectorParams);
  5480. }
  5481. } else {
  5482. if (typeof params == 'string') {params = {src: params}};
  5483. params.tag = 'iframe';
  5484. var paramsReplaced = self.replaceProperties(params);
  5485. self.addTag(paramsReplaced, selectorParams);
  5486. }
  5487. }
  5488. } */
  5489. /* this.textarea = function (params, selectorParams) {
  5490. if (Array.isArray(params)) {
  5491. for (var index in params)
  5492. self.textarea(params[index], selectorParams);
  5493. } else {
  5494. if (params.items) {
  5495. var itemsArray = params.items;
  5496. delete params.items;
  5497. for (var index in itemsArray) {
  5498. self.textarea(self.replaceItems(params, itemsArray[index]), selectorParams);
  5499. }
  5500. } else {
  5501. if (!params.tag) params.tag = 'textarea';
  5502. //params.container = params.container || self.selector(selectorParams);
  5503. self.addTag(params, selectorParams);
  5504. }
  5505. }
  5506. } */
  5507. /*
  5508. this.div = function (params, selectorParams) {
  5509. if (params.firebase) {
  5510. self.log('==========');
  5511. self.log('div');
  5512. self.log(params);
  5513. self.log('==========');
  5514. }
  5515. var tagParam = 'div';
  5516. var mainParam = 'text';
  5517. if (Array.isArray(params)) {
  5518. for (var index in params)
  5519. self.div(params[index], selectorParams);
  5520. } else {
  5521. if (params.items) {
  5522. var itemsArray = params.items;
  5523. delete params.items;
  5524. for (var index in itemsArray) {
  5525. self.div(self.replaceItems(params, itemsArray[index]), selectorParams);
  5526. }
  5527. } else {
  5528. self.addTag(self.createTagParams(params, tagParam, mainParam), selectorParams);
  5529. if (params.firebase) self.addFirebaseTag(self.extend({}, params, selectorParams));
  5530. }
  5531. }
  5532. }
  5533. this.ul = function (params, selectorParams) {
  5534. if (Array.isArray(params)) {
  5535. for (var index in params)
  5536. self.ul(params[index], selectorParams);
  5537. } else {
  5538. if (params.items) {
  5539. var itemsArray = params.items;
  5540. delete params.items;
  5541. for (var index in itemsArray) {
  5542. self.ul(self.replaceItems(params, itemsArray[index]), selectorParams);
  5543. }
  5544. } else {
  5545. params.tag = 'ul';
  5546. var paramsReplaced = self.replaceProperties(params);
  5547. self.addTag(paramsReplaced, selectorParams);
  5548. if (params.firebase) self.addFirebaseTag(params);
  5549. }
  5550. }
  5551. }
  5552. */
  5553. this.li = function (params, selectorParams) {
  5554. if (Array.isArray(params)) {
  5555. for (var index in params)
  5556. self.li(params[index], selectorParams);
  5557. } else {
  5558. if (params.items) {
  5559. var itemsArray = (typeof params.items == 'string') ? self.json.items[params.items] : params.items;
  5560. //var itemsArray = params.items;
  5561. delete params.items;
  5562. for (var index in itemsArray) {
  5563. if (self.only(itemsArray[index].roles))
  5564. self.li(self.replaceItems(params, itemsArray[index]), selectorParams);
  5565. }
  5566. } else {
  5567. if (typeof params == 'string') { params = { html: params }; };
  5568. params.tag = 'li';
  5569. //params.container = params.container || self.selector(selectorParams);
  5570. self.do(params, selectorParams);
  5571. }
  5572. }
  5573. };
  5574. this.remove = function (params, selectorParams, args) {
  5575. var selector = self.selector(params.selector || self.selector(selectorParams));
  5576. if (selector) {
  5577. var elements = self.queryAll(selector);
  5578. if (elements) {
  5579. elements.forEach(function (element, index) {
  5580. element.remove();
  5581. });
  5582. }
  5583. }
  5584. };
  5585. this.dispatchEvent = function (params, selectorParams, args) {
  5586. var selector = self.selector(params.selector || self.selector(selectorParams));
  5587. if (selector) {
  5588. var elements = self.queryAll(selector);
  5589. if (elements) {
  5590. elements.forEach(function (element, index) {
  5591. element.dispatchEvent(new Event(params.name));
  5592. });
  5593. }
  5594. }
  5595. };
  5596. /* this.element with "selector" and "method": (remove/dispatchEvent) */
  5597. this.html = function (params, selectorParams, args) {
  5598. /* self.log('html');
  5599. self.log('params');
  5600. self.log(params);
  5601. self.log('selectorParams');
  5602. self.log(selectorParams); */
  5603. // TO DO: update
  5604. // html properties can be only:
  5605. // selector, attr, html, on, for, if
  5606. // can't be:
  5607. // animate (should go inside on: init?)
  5608. // tags (div etc) because it should go inside html
  5609. // do
  5610. // functions, window functions...
  5611. // text should be alternative to html tag. if inside html, it should give an error
  5612. // TO DO: verificare se args viene portato agli elementi annidati (non andava con svg)
  5613. if (params) {
  5614. if (Array.isArray(params)) {
  5615. // TO DO: shoud check if params require plugins
  5616. for (var obj of params)
  5617. self.html(obj, selectorParams, args);
  5618. } else {
  5619. //if (params.container == '#weatherReport') alert()
  5620. //var container = (selectorParams) ? self.selector(selectorParams) : params.container; // unused
  5621. //var selector = self.selector(self.extend({}, params, selectorParams), undefined, true); //), undefined, true);
  5622. /*
  5623. self.log('selector');
  5624. self.log(selector); */
  5625. var container = self.selector(params.selector || params.container) || self.selector(selectorParams);
  5626. //var container = self.selector(selectorParams, undefined, true) || self.selector(params, selectorParams, true);
  5627. /* self.log('container');
  5628. self.log(container); */
  5629. /* var element = self.query(container);
  5630. self.log('element');
  5631. self.log(element);
  5632. */
  5633. if (container) {
  5634. var element = self.query(container);
  5635. // empty or not? probably yes (like jquery) but we need append/prepend method
  5636. // append only all the items in the array
  5637. // TO DO: queryAll -> elements
  5638. if (element) {
  5639. if (typeof params == 'string') {
  5640. //var paramsCompiled = self.compile(params, args);
  5641. var paramsCompiled = self.replaceProperties(params, args);
  5642. //$(container).append(paramsCompiled); // should be .html not append
  5643. //element.appendChild(paramsCompiled);
  5644. if (paramsCompiled) {
  5645. if (typeof paramsCompiled == 'object') {
  5646. // should be a nested tag or actions on,for,if,empty
  5647. self.do(paramsCompiled, { selector: container }, args);
  5648. } else if (typeof paramsCompiled == 'string') {
  5649. element.innerHTML += paramsCompiled; // TO DO: now is like append. Is it correct?
  5650. }
  5651. }
  5652. } else {
  5653. if (params.empty || params.do == 'empty') {
  5654. element.innerHTML = '';
  5655. delete params.empty;
  5656. }
  5657. if (params.tag) {
  5658. self.do(params, container, args);
  5659. //self.nested({key: params.tag, obj: params[par], selector: {selector: container}, args: args});
  5660. }
  5661. else if (params.html) {
  5662. // replace \" to "
  5663. //var htmlCompiled = self.compile(params.html, args); // is undefined
  5664. // TO DO: replace all the following "compile" with replaceProperties?
  5665. /* self.log('params.html');
  5666. self.log(params.html); */
  5667. var htmlCompiled = self.replaceProperties(params.html, args);
  5668. /* self.log('htmlCompiled');
  5669. self.log(htmlCompiled); */
  5670. self.html(htmlCompiled, { selector: container });
  5671. } else if (params.lang) {
  5672. //alert(self.json.setup.language);
  5673. var textLang = params.lang[self.json.setup.language] || params.lang['en'] || params.lang[Object.keys[0]];
  5674. if (Array.isArray(textLang)) {
  5675. var paragraphs = [];
  5676. for (var paragraph of textLang)
  5677. paragraphs.push({ p: paragraph });
  5678. self.html(paragraphs, selectorParams, args);
  5679. }
  5680. else
  5681. element.innerHTML = self.replaceProperties(textLang, args);
  5682. if (element) {
  5683. self.attribute(element, 'data-text', true); // textKey instead of lang?
  5684. self.dataStorage.set(element, 'params', params);
  5685. }
  5686. } else if (params.text) { // string
  5687. //params.text = self.replaceTags({text:params.text});
  5688. //params.text = self.text(params.text); // verifica presenza di tags e traduzioni
  5689. //$(selector).text(self.compile(params.text, args));
  5690. element.textContent = self.replaceProperties(params.text, args);
  5691. //} else if (params.empty || params.do == 'empty') {
  5692. // element.innerHTML = '';
  5693. } else if (params.append) { // string
  5694. //params.append = self.replaceTags({text:params.append});
  5695. //$(selector).append(self.compile(params.append, args));
  5696. //element.appendChild(self.compile(params.append, args));
  5697. element.innerHTML += self.replaceProperties(params.append, args);
  5698. } else if (params.prepend) { // string
  5699. //params.prepend = self.replaceTags({text:params.prepend});
  5700. //$(selector).prepend(self.compile(params.prepend, args));
  5701. //element.insertBefore(self.compile(params.prepend, args));
  5702. element.innerHTML = self.replaceProperties(params.prepend, args) + element.innerHTML;
  5703. } else if (params.blocks) { // obsolete
  5704. self.blocks(params.blocks, { selector: container }, args);
  5705. } else {
  5706. let nestedParams = self.cloneObject(params);
  5707. if (nestedParams.style) delete nestedParams.style;
  5708. if (nestedParams.attr) delete nestedParams.attr;
  5709. console.warn('UNKNOWN TAG');
  5710. console.warn(params);
  5711. // on, for, if... (can be changed to include also html)
  5712. self.do(nestedParams, { selector: container }, args);
  5713. if (element.isConnected) {
  5714. // case "html":{selector:... attr: }
  5715. // the wrong use "html":{selector, attr, html:...}
  5716. // now doesn't work (because is inside the last else)
  5717. /* if (params.on) {
  5718. alert(container);
  5719. self.on(params.on, { selector: container }, args);
  5720. } */
  5721. if (params.attr) self.setAttributes(element, params.attr, args);
  5722. if (params.style) self.css(params, selectorParams, args); // to be removed
  5723. // TO DO: params.style is deprecated (now in attr or css)
  5724. }
  5725. //self.blocks(params, selectorParams, args);
  5726. }
  5727. }
  5728. } else { // !element
  5729. }
  5730. } else {
  5731. self.log('"html" object requires selector property', 'red');
  5732. self.log(params);
  5733. //self.log(selectorParams);
  5734. }
  5735. //}
  5736. //}
  5737. }
  5738. } else {
  5739. self.log('"html" object without params');
  5740. }
  5741. };
  5742. /* this.add = function (params) { // obsoleto, sostituito da html
  5743. var selector = self.selector(params);
  5744. if (params.inverse)
  5745. $(selector).append(params.html);
  5746. else
  5747. $(selector).prepend(params.html);
  5748. } */
  5749. /* this.attr = function (params, selectorParams, args) {
  5750. var selector = self.selector(params);
  5751. var element = self.query(selector);
  5752. for (var attribute in params.attr)
  5753. elements.forEach(function (element, index) {
  5754. element.setAttribute(attrId, attrValue);
  5755. });
  5756. }
  5757. */
  5758. /* this.empty = function (params) {
  5759. // { [container, class, value, id] }
  5760. var selector = self.selector(params);
  5761. $(selector).empty();
  5762. } */
  5763. /* this.addClass = function (params) {
  5764. var selector = self.selector(params);
  5765. $(selector).addClass(params);
  5766. }
  5767. this.removeClass = function (params) {
  5768. self.log('removeClass');
  5769. var selector = self.selector(params);
  5770. $(selector).removeClass(params);
  5771. } */
  5772. /* this.toggleClass = function (params) {
  5773. var selector = self.selector(params);
  5774. $(selector).toggleClass(params);
  5775. } */
  5776. //"#wifi > ul > li > span[data-field=share]:contains('Private')"
  5777. this.setAttributes = function (elements, attrs, args) {
  5778. for (var attribute in attrs)
  5779. if (attrs[attribute])
  5780. self.attribute(elements, attribute, self.replaceResult(attrs[attribute], args));
  5781. else
  5782. self.attribute(elements, attribute, "");
  5783. //self.attribute(elements, attribute, attrs[attribute]);
  5784. //self.attribute(elements, attribute, self.replaceWithPrefix(attrs[attribute], 'result', args)); // TO DO: check
  5785. // before remove and check all the {result} occurrence (result excludes do/then/success etc.)
  5786. // replaceResult replace {result} from Alert (should be obsolete)
  5787. // check in the actual apps if {result} is used
  5788. };
  5789. /* this.setAttributes = function (elements, attrs, args) {
  5790. if (!Array.isArray(elements)) elements = [elements];
  5791. elements.forEach(function (element, index) {
  5792. for (var attribute in attrs) {
  5793. if (typeof attrs[attribute] == 'boolean' && attrs[attribute]) { // it consider also firebase (empty values are removed)
  5794. element.setAttribute(attribute, "");
  5795. } else {
  5796. //if (attrs[attribute] == undefined) attrs[attribute] = '';
  5797. element.setAttribute(attribute, self.replaceProperties(attrs[attribute]));
  5798. }
  5799. }
  5800. });
  5801. self.attribute(elements, attribute, self.replaceResult(attrs[attribute], args));
  5802. }; */
  5803. // TO DO: distinguish setAttribute from getAttribute
  5804. // because we need to set attribute empty
  5805. this.attribute = function (elements, attrId, attrValue) {
  5806. if (typeof attrValue !== undefined) {
  5807. if (!Array.isArray(elements)) elements = [elements];
  5808. elements.forEach(function (element, index) {
  5809. if (typeof attrValue == 'boolean' && attrValue) { // it consider also firebase (empty values are removed)
  5810. element.setAttribute(attrId, "");
  5811. } else {
  5812. element.setAttribute(attrId, self.replaceProperties(attrValue));
  5813. }
  5814. });
  5815. } else {
  5816. if (!Array.isArray(elements))
  5817. return elements.getAttribute(attrId); // todo: intercept the error "Cannot read properties of undefined (reading 'getAttribute"
  5818. else
  5819. return elements[0].getAttribute(attrId);
  5820. }
  5821. };
  5822. this.attr = function (params, selectorParams, args) {
  5823. // deprecated. to be replaced with "css" {selector, style, addClass, removeClass, toggleClass}
  5824. // css is used as an action to apply addClass removeClass toggleClass
  5825. // and to apply style: {...}
  5826. //params = self.replaceProperties(params);
  5827. self.css(self.replaceProperties(params), selectorParams, args);
  5828. };
  5829. this.styleElement = function (params, element, args) {
  5830. for (var styleName in params) {
  5831. if (styleName.startsWith('--'))
  5832. element.style.setProperty(styleName, self.replaceProperties(params[styleName], args));
  5833. else
  5834. element.style[styleName] = self.replaceProperties(params[styleName], args);
  5835. }
  5836. };
  5837. this.css = function (params, selectorParams, args) {
  5838. // {selector, style, addClass, removeClass, toggleClass}
  5839. /* console.log('selectorParams');
  5840. console.log(selectorParams);
  5841. console.log('css');
  5842. console.log(params); */
  5843. if (Array.isArray(params)) {
  5844. for (var obj of params)
  5845. self.css(obj, selectorParams, args);
  5846. /* } else if (params.selector && Array.isArray(params.selector)) {
  5847. for (let selector of params.selector) {
  5848. let obj = self.cloneObject(params);
  5849. obj.selector = selector;
  5850. self.css(obj, selectorParams, args); */
  5851. } else {
  5852. var selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  5853. var elements = self.queryAll(selector);
  5854. //var selector = params.selector || selectorParams;
  5855. //var elements = document.querySelectorAll(selector);
  5856. //console.log(elements);
  5857. if (elements) {
  5858. elements.forEach(function (element, index) {
  5859. if (element) {
  5860. if (typeof params.style == 'object') {
  5861. self.styleElement(params.style, element, args);
  5862. }
  5863. if (params.addClass)
  5864. self.addClass(element, params.addClass);
  5865. if (params.removeClass)
  5866. self.removeClass(element, params.removeClass);
  5867. if (params.toggleClass)
  5868. self.toggleClass(element, params.toggleClass);
  5869. } else {
  5870. self.log('the function "css" can\'t find the selector ' + selector);
  5871. self.log(params);
  5872. self.log(selectorParams);
  5873. }
  5874. });
  5875. } else {
  5876. self.log('"css" function is unable to select: ' + selector);
  5877. self.log('params');
  5878. self.log(params);
  5879. self.log('selectorParams');
  5880. self.log(selectorParams);
  5881. }
  5882. }
  5883. };
  5884. /* this.class = function (params) { // obsolete -> css
  5885. self.log('self.class');
  5886. self.log(params);
  5887. // { [container, class, value, id]
  5888. // [style, addClass, removeClass] }
  5889. var selector = self.selector(params);
  5890. if (params.style)
  5891. $(selector).css(params.style);
  5892. if (params.add)
  5893. $(selector).addClass(params.add);
  5894. if (params.remove)
  5895. $(selector).removeClass(params.remove);
  5896. if (params.toggle)
  5897. $(selector).toggleClass(params.toggle);
  5898. } */
  5899. /* this.createPage = function (data) {
  5900. // SPOSTATA SOTTO fixo.pages.js
  5901. //self.log('createPage');
  5902. //self.log(data);
  5903. if (!$('#'+data.id).length) {
  5904. $(data.container).append('<div id="'+data.id+'" class="fixoPage"></div>');
  5905. if (data.background) {
  5906. $('#'+data.id).css({
  5907. 'background-color': data.background
  5908. });
  5909. }
  5910. }
  5911. } */
  5912. /* this.iconPng = function(icon) {
  5913. return 'https://'+self.domain+'/app/files/icons/100white/'+icon+'.png';
  5914. } */
  5915. /* this.imgTag = function (data) {
  5916. // DIPENDENZA CON iconPng
  5917. var imgId = data.id || '';
  5918. var imgClass = data.class || '';
  5919. var imgValue = data.value || '';
  5920. var imgStyle = data.style || ''; // || 'width: 84px; margin:6px 10px;'; // ATTENZIONE: stile predefinito da rimuovere
  5921. var onClick = (data.action) ? 'onclick="javascript:self.do(\''+data.action+'\',\''+imgValue+'\')" ' : '';
  5922. return '<img src="'+self.iconPng(data.icon)+'" id="'+imgId+'" class="'+imgClass+'" data-value="'+imgValue+'" style="'+data.style+'" '+onClick+'/>';
  5923. } */
  5924. /* this.setImg = function (data) {
  5925. // Sembra inutilizzata
  5926. // DIPENDENZA CON iconPng
  5927. // data = {icon, style}
  5928. var selector = self.selector(data);
  5929. var imgValue = data.value || '';
  5930. $(selector).attr('src', self.iconPng(data.icon));
  5931. if (data.style) $(selector).css(style);
  5932. if (data.action) {
  5933. $(selector).attr('onclick', 'javascript:self.do(\''+data.action+'\',\''+imgValue+'\')');
  5934. }
  5935. } */
  5936. // --------------
  5937. // SVG
  5938. // --------------
  5939. /* this.svgSet = function (params) {
  5940. //self.log('svgSet');
  5941. //self.log(params);
  5942. if (self.json && self.json.icons) {
  5943. //if (self.json.setup && self.json.setup.icons) {
  5944. if (params.icon) {
  5945. var iconObj = {};
  5946. iconObj.icon = (params.icon.indexOf(':')) ? params.icon.split(/:/)[1] : string;
  5947. iconObj.set = (params.icon.indexOf(':')) ? params.icon.split(/:/)[0] : undefined;
  5948. var svgIcons = self.json.icons || {}; // {src, prefix, suffix}
  5949. //var svgIcons = self.json.setup.icons || {}; // {src, prefix, suffix}
  5950. if (iconObj.set)
  5951. if (svgIcons[iconObj.set])
  5952. svgIcons = svgIcons[iconObj.set];
  5953. else
  5954. self.log('Can\'t find the icons set "'+iconObj.set+'" in "icons"');
  5955. iconObj.src = svgIcons.src || ''; // serve?
  5956. var svgPrefix = svgIcons.prefix || '';
  5957. var svgSuffix = svgIcons.suffix || '';
  5958. //if (iconObj.src !== '' && iconObj.icon) iconObj.src = '#' + svgPrefix + iconObj.icon + svgSuffix;
  5959. if (iconObj.icon) {
  5960. if (!svgIcons.preload)
  5961. // siamo vicini
  5962. iconObj.src = svgIcons.src + '#' + svgPrefix + iconObj.icon + svgSuffix;
  5963. else
  5964. iconObj.src = '#' + iconObj.set + '_' + svgPrefix + iconObj.icon + svgSuffix;
  5965. }
  5966. iconObj.viewbox = svgIcons.viewbox; // || '0 0 25 25';
  5967. return iconObj; // {src, set, name, viewbox}
  5968. } else {
  5969. self.log('icon "name" parameter undefined');
  5970. }
  5971. } else {
  5972. self.log('Can\'t find "icons" in "setup"');
  5973. }
  5974. }
  5975. this.svgChange = function (data) {
  5976. self.log('svgChange');
  5977. self.log(data);
  5978. var selector = self.selector(data); //), undefined, true);
  5979. var containerElement = self.query(selector);
  5980. var elementSvg = containerElement.querySelectorAll('svg')[0];
  5981. var elementSvgUse = elementSvg.querySelectorAll('use')[0];
  5982. var elementSvgText = elementSvg.querySelectorAll('text')[0];
  5983. var elementSvgCircle = elementSvg.querySelectorAll('circle')[0];
  5984. var iconObj = self.svgSet(data); // {src, set, name, viewbox}
  5985. if (iconObj.src)
  5986. elementSvgUse.setAttribute('xlink:href', iconObj.src);
  5987. //$(data.container + ' > svg > use').attr('xlink:href', iconObj.src);
  5988. if (data.text !== undefined) {
  5989. elementSvgText.textContent = data.text;
  5990. // $(data.container + ' > svg > text').text(data.text);
  5991. var textY = 6.5; // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor
  5992. if (data.textSize !== undefined) {textY = data.textSize/2;}
  5993. if (data.textPosition == 'bottom') { // textPosition should be removed
  5994. elementSvgUse.setAttribute('transform', 'translate(0, -20) scale(0.80)');
  5995. //$(data.container + ' > svg > use').attr("transform", "translate(0, -20) scale(0.80)");
  5996. textY += 26;
  5997. }
  5998. elementSvgText.setAttribute('y', textY);
  5999. //$(data.container + ' > svg > text').attr('y',textY);
  6000. elementSvgText.style['font-size'] = data.textSize+'px';
  6001. //$(data.container + ' > svg > text').css('font-size',data.textSize+'px');
  6002. } else {
  6003. elementSvgText.textContent = '';
  6004. //$(data.container + ' > svg > text').text('');
  6005. }
  6006. if (data.background !== undefined){
  6007. elementSvgCircle.setAttribute('fill', data.background);
  6008. elementSvgCircle.setAttribute('fill-opacity', 1);
  6009. elementSvgCircle.style['stroke'] = data.background;
  6010. }
  6011. if (data.border !== undefined) {
  6012. elementSvgCircle.setAttribute('stroke-opacity', 1);
  6013. elementSvgCircle.style['stroke'] = data.border;
  6014. }
  6015. if (data.color !== undefined && data.color !== 'colored') {
  6016. elementSvgUse.style['fill'] = data.color;
  6017. }
  6018. if (data.textColor !== undefined){
  6019. elementSvgText.style['fill'] = data.textColor;
  6020. } else if (data.color) {
  6021. elementSvgText.style['fill'] = data.color;
  6022. }
  6023. }
  6024. this.svgImage = function (data) {
  6025. //$(data.container).hide();
  6026. //$(data.container).css({opacity:0});
  6027. var selector = self.selector(data); //), undefined, true);
  6028. var containerElement = self.query(selector);
  6029. //var containerElement = self.query(data.container);
  6030. //if (data.value !== undefined) $(data.container).data('value', data.value);
  6031. var iconObj = self.svgSet(data); // {src, set, name, viewbox}
  6032. var viewBox = iconObj.viewbox || '-50 -50 100 100';
  6033. var htmlString = '<svg viewBox="'+viewBox+'"><circle cx="0" cy="0" r="46" fill-opacity="0"></circle><use xlink:href=""></use><text x="0" y="0" text-anchor="middle" fill=""></text></svg>';
  6034. if (containerElement) {
  6035. containerElement.innerHTML = htmlString;
  6036. //$(data.container).append('<svg viewBox="'+viewBox+'"><circle cx="0" cy="0" r="46" fill-opacity="0"></circle><use xlink:href=""></use><text x="0" y="0" text-anchor="middle" fill=""></text></svg>');
  6037. var elementSvg = containerElement.querySelectorAll('svg')[0];
  6038. var elementSvgUse = elementSvg.querySelectorAll('use')[0];
  6039. var elementSvgText = elementSvg.querySelectorAll('text')[0];
  6040. var elementSvgCircle = elementSvg.querySelectorAll('circle')[0];
  6041. elementSvgUse.setAttribute('xlink:href', iconObj.src);
  6042. //$(data.container + ' > svg > use').attr('xlink:href', iconObj.src);
  6043. if (data.text !== undefined) {
  6044. elementSvgText.textContent = data.text;
  6045. // $(data.container + ' > svg > text').text(data.text);
  6046. var textY = 6.5; // https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/text-anchor
  6047. if (data.textSize !== undefined) {textY = data.textSize/2;}
  6048. if (data.textPosition == 'bottom') { // textPosition should be removed
  6049. elementSvgUse.setAttribute('transform', 'translate(0, -20) scale(0.80)');
  6050. //$(data.container + ' > svg > use').attr("transform", "translate(0, -20) scale(0.80)");
  6051. textY += 26;
  6052. }
  6053. elementSvgText.setAttribute('y', textY);
  6054. //$(data.container + ' > svg > text').attr('y',textY);
  6055. elementSvgText.style['font-size'] = data.textSize+'px';
  6056. //$(data.container + ' > svg > text').css('font-size',data.textSize+'px');
  6057. }
  6058. if (data.background !== undefined) {
  6059. elementSvgCircle.setAttribute('fill', data.background);
  6060. elementSvgCircle.setAttribute('fill-opacity', 1);
  6061. elementSvgCircle.style['stroke'] = data.background;
  6062. }
  6063. if (data.border !== undefined){
  6064. elementSvgCircle.setAttribute('stroke-opacity', 1);
  6065. elementSvgCircle.style['stroke'] = data.border;
  6066. //$(data.container + ' > svg > circle').attr('stroke-opacity', 1);
  6067. // FORSE DEVE DIVENTARE attr ANZICHE' css
  6068. //$(data.container + ' > svg > circle').css({'stroke': data.border});
  6069. }
  6070. //if ((data.color === undefined) && (data.color !== 'colored')) {data.color = '#fff';}
  6071. if (data.color !== undefined && data.color !== 'colored') {
  6072. elementSvgUse.style['fill'] = data.color;
  6073. //$(data.container + ' > svg > use').css({'fill': data.color});
  6074. //$(data.container + ' > svg > text').css({'fill': data.color});
  6075. }
  6076. if (data.textColor !== undefined){
  6077. elementSvgText.style['fill'] = data.textColor;
  6078. //$(data.container + ' > svg > text').css({'fill': data.textColor});
  6079. } else {
  6080. elementSvgText.style['fill'] = data.color;
  6081. //$(data.container + ' > svg > text').css({'fill': data.color});
  6082. }
  6083. self.css({style: data.style}, {container: data.container + ' > svg'});
  6084. }
  6085. }
  6086. this.svg = function (params, selectorParams, args) {
  6087. var paramsReplaced = self.replaceProperties(params, args);
  6088. //var container = self.selector(self.extend({}, params, selectorParams));
  6089. var container = self.selector(paramsReplaced, undefined, true) || self.selector(selectorParams, undefined, true);
  6090. var element = self.query(container);
  6091. var color = paramsReplaced.color || getComputedStyle(element).color;
  6092. //if (element.getElementsByTagName('SVG').length == 0) {
  6093. //if (element.querySelectorAll('svg').length == 0) {
  6094. self.svgImage({
  6095. container: container,
  6096. // special param
  6097. icon: paramsReplaced.icon,
  6098. text: paramsReplaced.text,
  6099. textSize: paramsReplaced.textSize, // verify (obsolete when span will be nested)
  6100. textPosition: paramsReplaced.textPosition, // verify (obsolete when span will be nested)
  6101. textColor: paramsReplaced.textColor, // verify (obsolete when span will be nested)
  6102. background: paramsReplaced.background,
  6103. border: paramsReplaced.border,
  6104. color: paramsReplaced.color || color, // $(container).css("color"),
  6105. style: paramsReplaced.style, // da fare css in svgImage
  6106. class: paramsReplaced.class
  6107. //hoverBackground: data.hoverBackground, // verify
  6108. //hoverBorder: data.hoverBorder, // verify
  6109. //hoverColor: data.hoverColor, // verify
  6110. });
  6111. } */
  6112. // --------------
  6113. // ITEM
  6114. // --------------
  6115. /*
  6116. this.checkItem = function (data) {
  6117. var selectedIconClass = data.selection || 'selectedIcon'; // self.json.setup.classes.selectedIcon;
  6118. //self.log('checkItem');
  6119. //self.log(data);
  6120. var checked = 0;
  6121. // var selector = '';
  6122. var selector = self.selector(data);
  6123. if (data.style === undefined) {data.style = selectedIconClass;}
  6124. if (data.checked !== undefined) {
  6125. checked = self.replaceProperties(data.checked);
  6126. //checked = self.replaceTags({text:data.checked});
  6127. checked = data.checked;
  6128. if (data.checked) {
  6129. $(selector).addClass(data.style);
  6130. } else {
  6131. $(selector).removeClass(data.style);
  6132. }
  6133. } else {
  6134. checked = $(selector).hasClass( data.style );
  6135. }
  6136. return checked;
  6137. } */
  6138. /*
  6139. this.toggleItem = function (data) { // modificato 20180709 da changeCheckItem in toggleItem
  6140. self.log('toggleItem');
  6141. //self.log(data);
  6142. var checked;
  6143. checked = self.checkItem({
  6144. id: data.id,
  6145. class: data.class,
  6146. value: data.value
  6147. //style: data.style
  6148. });
  6149. checked = !checked; // inverte il valore
  6150. self.checkItem({
  6151. id: data.id,
  6152. class: data.class,
  6153. value: data.value,
  6154. checked: checked
  6155. //style: data.style,
  6156. });
  6157. return checked;
  6158. }
  6159. */
  6160. /* this.selectItem = function (data) {
  6161. var selectedIconClass = self.json.setup.classes.selectedIcon;
  6162. var selector = self.selector({container: data.container, class: data.class});
  6163. if (data.style === undefined) {data.style = selectedIconClass;}
  6164. $(selector).removeClass(data.style);
  6165. self.log('selector');
  6166. self.log(selector);
  6167. if (data.value || data.id) {
  6168. selector = self.selector(data);
  6169. $(selector).addClass(data.style);
  6170. }
  6171. }
  6172. this.unselectItems = function (data) {
  6173. var selectedIconClass = self.json.setup.classes.selectedIcon;
  6174. //if (data.style)
  6175. if (data.style === undefined) {data.style = selectedIconClass;}
  6176. if (data.class.indexOf('.') < 0) {data.class = '.' + data.class}
  6177. $(data.class).removeClass(data.style);
  6178. }
  6179. */
  6180. /* this.removeImage = function (data) {
  6181. var selector = self.selector(data);
  6182. $(selector).css({'background-image':'url()'});
  6183. }
  6184. this.loadImage = function (data) {
  6185. var selector = self.selector(data);
  6186. //if (!data.style) data.style = {};
  6187. //if (data.background) data.style['background-color'] = data.background;
  6188. if (data.image || data.image === '') {
  6189. self.getImage({ // ex fixo.loadImage
  6190. object: selector,
  6191. url: data.image
  6192. //style: data.style,
  6193. //animation: data.animation,
  6194. });
  6195. } else {
  6196. self.removeImage(data);
  6197. }
  6198. } */
  6199. /* this.changeItem = function (data, selectorParams, args) {
  6200. self.log('changeItem');
  6201. self.log(data);
  6202. var container = (selectorParams) ? self.selector(selectorParams) : data.container;
  6203. var selector = self.selector(self.extend({}, data, selectorParams));
  6204. var iconClass = ''; //self.json.setup.classes.icon || '';
  6205. var badgeClass = 'iconBadge'; //self.json.setup.classes.badge || '';
  6206. if (data.svg || data.text || data.background || data.border || data.color) {
  6207. $(selector + ' > svg').css({opacity:1});
  6208. self.svgChange({
  6209. container: selector,
  6210. name: data.svg,
  6211. text: data.text,
  6212. background: data.background,
  6213. border: data.border,
  6214. color: data.color,
  6215. });
  6216. } else {
  6217. $(selector + ' > svg').css({opacity:0});
  6218. }
  6219. // IMMAGINE
  6220. if (data.image && data.image !== '') {
  6221. var imgData = data;
  6222. imgData.style = {
  6223. width: '82px',
  6224. height: '82px',
  6225. 'margin-bottom': '27px'
  6226. };
  6227. if (data.background) imgData.style['background-color'] = data.background;
  6228. self.loadImage(imgData);
  6229. $(selector + ' > svg').css({opacity:0});
  6230. } else {
  6231. self.removeImage(data);
  6232. $(selector + ' > svg').css({opacity:1});
  6233. }
  6234. if (data.badgeIcon || data.badgeText) {
  6235. if (!$('.'+badgeClass).length)
  6236. $(selector).append('<div class="'+badgeClass+'"></div>');
  6237. self.svgImage({
  6238. container: selector + ' > .'+badgeClass,
  6239. icon: data.badgeIcon,
  6240. text: data.badgeText,
  6241. background: data.badgeBackground,
  6242. border: data.badgeBorder,
  6243. color: data.badgeColor,
  6244. });
  6245. } else {
  6246. $(selector + ' > .'+badgeClass).remove();
  6247. }
  6248. if (data.titleColor)
  6249. $(selector + ' > span').css({'color':data.titleColor});
  6250. else if (data.color)
  6251. $(selector + ' > span').css({'color':data.color});
  6252. if (data.titleSize) $(selector + ' > span').css({'font-size':data.titleSize});
  6253. if (data.title) {
  6254. $(selector+' > span').text(data.title);
  6255. if ($(selector+' > span').hasClass('textFitted')) {
  6256. self.textFit($(selector+' > span'), {
  6257. alignHoriz: false,
  6258. multiLine: false,
  6259. alignVert: false,
  6260. minFontSize: 10,
  6261. maxFontSize: data.titleSize || 12,
  6262. });
  6263. }
  6264. }
  6265. if (data.checked !== undefined) {
  6266. self.checkItem({
  6267. container: data.container,
  6268. class: data.class,
  6269. value: data.value,
  6270. id: data.id,
  6271. checked: data.checked
  6272. //style: data.style,
  6273. });
  6274. }
  6275. // action (obsolete)
  6276. if (data.action) {
  6277. var onData = $(selector).data('onData');
  6278. onData.action = data.action;
  6279. $(selector).data('onData', onData); // nuova versione
  6280. }
  6281. // events
  6282. if (data.on) self.on(data.on, {container: selector});
  6283. } */
  6284. /* this.enableIcon = function (params, selectorParams) {
  6285. var container = (selectorParams) ? self.selector(selectorParams) : params.container;
  6286. var selector = self.selector(self.extend({}, params, selectorParams));
  6287. $(selector).css({'opacity':'1'});
  6288. $(selector).off().on(self.touch, function(event){
  6289. event.stopPropagation();
  6290. self.onEvent(this, event);
  6291. });
  6292. }
  6293. this.disableIcon = function (params, selectorParams) {
  6294. var badgeClass = self.json.setup.classes.badge || '';
  6295. var container = (selectorParams) ? self.selector(selectorParams) : params.container;
  6296. var selector = self.selector(self.extend({}, params, selectorParams));
  6297. $(selector + ' > .'+badgeClass).remove();
  6298. $(selector).css({'opacity':'0.5'});
  6299. $(selector).off();
  6300. }
  6301. */
  6302. /* this.getFileExtension = function (path) {
  6303. var dotPosition=path.lastIndexOf(".");
  6304. var stringLength=path.length;
  6305. var extensionFile=path.substring(dotPosition+1,stringLength);
  6306. return extensionFile;
  6307. } */
  6308. // --------------------
  6309. // SLIDER
  6310. // --------------------
  6311. /* var slides = {};
  6312. var sliderLib = 'fixoSlider';
  6313. var sliderWrapperClass = 'fixoSlider';
  6314. //var sliderSlideClass = 'fixoSlidez';
  6315. var sliderSelectedClass = 'slideSelected'; */
  6316. /*
  6317. var sliderLib = 'flickity';
  6318. var sliderWrapperClass = 'fixoSlider';
  6319. var sliderSlideClass = 'fixoSlide';
  6320. var sliderSelectedClass = 'is-selected';
  6321. */
  6322. /*
  6323. var sliderLib = 'sliderpro';
  6324. var sliderWrapperClass = 'sp-slides';
  6325. var sliderSlideClass = 'sp-slide';
  6326. var sliderSelectedClass = 'sp-selected';
  6327. */
  6328. /*
  6329. var sliderLib = 'swiper';
  6330. var sliderWrapperClass = 'swiper-wrapper';
  6331. var sliderSlideClass = 'swiper-slide';
  6332. var sliderSelectedClass = 'swiper-slide-active';
  6333. */
  6334. /*
  6335. this.sliderResume = function (data) {
  6336. var selector = self.selector(data);
  6337. if (slides[selector]) slides[selector].object.resume();
  6338. }
  6339. this.sliderFreeze = function (data) {
  6340. var selector = self.selector(data);
  6341. if (slides[selector]) slides[selector].object.freeze();
  6342. }
  6343. this.sliderNext = function(data) {
  6344. var selector = self.selector(data);
  6345. if (sliderLib == 'fixoSlider') slides[selector].object.next();
  6346. //if (sliderLib == 'flickity') slides[selector].object.flickity('next');
  6347. }
  6348. this.sliderPrev = function(data) {
  6349. var selector = self.selector(data);
  6350. if (sliderLib == 'fixoSlider') slides[selector].object.prev();
  6351. //if (sliderLib == 'flickity') slides[selector].object.flickity('previous');
  6352. }
  6353. this.autoSliderEvent = function() {
  6354. var selector = self.selector(data);
  6355. if (self.sliderSelected)
  6356. slides[self.sliderSelected].object.autoSliderEvent();
  6357. }
  6358. this.addSlideIcon = function(data) {
  6359. // creata per rendere più leggibile createSlide
  6360. var selector = self.selector(data);
  6361. var isImage = self.getFileExtension(data.icon);
  6362. if (isImage == 'gif' || isImage == 'jpg' || isImage == 'jpeg' || isImage == 'png')
  6363. fixo.loadImage({
  6364. object: selector + ' > .slideIcon',
  6365. url: data.icon,
  6366. style: {height: '150px',
  6367. width: '150px',
  6368. marginTop: '25px',
  6369. marginLeft: '-75px',
  6370. backgroundSize: 'cover'
  6371. }
  6372. });
  6373. else
  6374. //if (data.icon)
  6375. self.svgImage({
  6376. container: selector + ' > .slideIcon',
  6377. icon: data.icon,
  6378. color: '#fff',
  6379. });
  6380. if (data.iconName)
  6381. $(selector + ' > .slideIconName').html(data.iconName); // da cancellare?
  6382. if (data.iconAction) {
  6383. var value = data.iconValue || '';
  6384. $(selector + ' > .slideIcon').attr('onclick', 'javascript:self.do(\''+data.iconAction+'\', \''+value+'\')');
  6385. }
  6386. }
  6387. this.changeSlideIcon = function(data) {
  6388. var selector = self.selector(data);
  6389. // verificare se si può usare changeItem
  6390. if (data.icon)
  6391. self.svgChange({
  6392. container: selector + ' > .slideIcon',
  6393. name: data.icon,
  6394. color: '#fff',
  6395. });
  6396. if (data.iconName)
  6397. $(selector + ' > .slideIconName').html(data.iconName);
  6398. }
  6399. this.updateSlide = function(data) {
  6400. self.log('updateSlide');
  6401. if (!data.class) data.class = 'fixoSlide';
  6402. var selector = self.selector(data);
  6403. // ICONA
  6404. self.changeSlideIcon(data);
  6405. // BACKGROUND
  6406. if (data.background) $(selector).css({'background-color':data.background});
  6407. // TITOLO E TESTO
  6408. var alertTitleObj = $(selector).children('.slideTitle');
  6409. var alertTextObj = $(selector).children('.slideText');
  6410. var titleAndText = (alertTitleObj.text() !== '' && alertTextObj.text() !== '');
  6411. if (titleAndText) {
  6412. alertTitleObj.css({'margin-top':'-225px'});
  6413. } else {
  6414. alertTitleObj.css({'margin-top':'-60px'});
  6415. }
  6416. if (data.title !== undefined) {
  6417. alertTitleObj.html(data.title);
  6418. self.textFit(titleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 40, maxFontSize: 56});
  6419. }
  6420. if (data.text !== undefined) {
  6421. alertTextObj.html(data.text);
  6422. self.textFit(textObj, {alignHoriz: true, multiLine: false, alignVert: !titleAndText, minFontSize: 17, maxFontSize: 40});
  6423. }
  6424. // BOTTONE
  6425. if (data.button !== undefined) {
  6426. if (data.button) {
  6427. if (data.buttonLabel) {
  6428. $(selector + ' > .slideButton').html(data.buttonLabel);
  6429. }
  6430. if (data.buttonAction) {
  6431. $(selector + ' > .slideButton').data('action', data.buttonAction);
  6432. $(selector + ' > .slideButton').data('value', data.value);
  6433. $(selector + ' > .slideButton').attr('onclick', 'javascript:self.do(\'' + data.buttonAction + '\',\''+data.value+'\')');
  6434. }
  6435. $(selector + ' > .slideButton').show();
  6436. } else {
  6437. $(selector + ' > .slideButton').hide();
  6438. }
  6439. // aggiungere changeItem dell'icona
  6440. }
  6441. }
  6442. this.slideTextFit = function() {
  6443. //self.log('slideTextFit');
  6444. //if (!data.class) data.class = 'fixoSlide';
  6445. //var selector = self.selector(data);
  6446. var slideSelector = self.sliderSelected + ' > .' + sliderSelectedClass;
  6447. titleObj = $(slideSelector).children('.slideTitle');
  6448. textObj = $(slideSelector).children('.slideText');
  6449. var titleAndText = (titleObj.text() !== '' && textObj.text() !== '');
  6450. if (titleAndText) {
  6451. titleObj.css({'margin-top':'-225px'});
  6452. //textObj.css({'top':(384+125-30)+'px'});
  6453. } else {
  6454. titleObj.css({'margin-top':'-60px'});
  6455. }
  6456. self.textFit(titleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 40, maxFontSize: 56});
  6457. self.textFit(textObj, {alignHoriz: true, multiLine: false, alignVert: !titleAndText, minFontSize: 17, maxFontSize: 40});
  6458. }
  6459. this.sliderTo = function(data) {
  6460. // apre la slide data.index
  6461. self.log('sliderTo');
  6462. var selector = self.selector(data);
  6463. if (data.index !== undefined) // comprende il caso = 0
  6464. if (slides[selector] && slides[selector].object)
  6465. slides[selector].object.to(data.index);
  6466. //if (sliderLib == 'swiper')
  6467. // slides[selector].object.slideToLoop(data.index); // slideToLoop
  6468. //if (sliderLib == 'flickity')
  6469. // slides[selector].object.flickity('select', data.index);
  6470. //if (sliderLib == 'extraslider')
  6471. // $(selector+' > .extra-slider').trigger('extra:slider:goto', data.index);
  6472. if (data.value !== undefined) { // comprende il caso = 0
  6473. self.log(self.selector(data));
  6474. if (!data.class) data.class = 'fixoSlide';
  6475. var slideToSelect = self.selector(data);
  6476. var index = $(slideToSelect).index();
  6477. if (index > -1) slides[selector].object.to(index);
  6478. //var slideToSelect = '.' + sliderSlideClass + '[data-value="' + data.prefix + data.value + '"]';
  6479. }
  6480. //if (sliderLib == 'flickity')
  6481. // slides[selector].object.flickity('selectCell', slideToSelect);
  6482. }
  6483. this.sliderExist = function(data) { // si può cancellare?
  6484. var selector = self.selector(data);
  6485. //alert(($(selector + ' > .extra-slider').length > 0));
  6486. return ($(selector + ' > .extra-slider').length > 0)
  6487. // return (slides[selector])
  6488. }
  6489. this.createSlide = function(data) {
  6490. self.log('createSlide');
  6491. //if (!data.prefix) data.prefix = "";
  6492. if (!data.class) data.class = "fixoSlide";
  6493. //var containerSelector = self.selector(data);
  6494. var slideContent = '<div class="' + data.class + '" data-value="'+ data.value + '"></div>';
  6495. if (data.inverse) {
  6496. $(data.container).prepend(slideContent);
  6497. } else {
  6498. $(data.container).append(slideContent);
  6499. }
  6500. var selector = self.selector(data);
  6501. var infoButtons = data.infoButtons || {};
  6502. // STORE DATA
  6503. $(selector).data('container', data.container);
  6504. if (data.value) $(selector).data('value', data.value);
  6505. //if (data.id) $(selector).data('id', data.id);
  6506. //if (data.prefix) $(selector).data('prefix', data.prefix);
  6507. var textHtml = (data.text) ? data.text.replace(/\r?\n/g, '<br/>') : '';
  6508. // PRICE
  6509. //if(data.price && data.price !== '') textHtml += '<br/>€ '+data.price;
  6510. // BACKGROUND
  6511. if (data.background) $(selector).css({'background-color':data.background});
  6512. // IMAGE
  6513. if (data.image && data.image !== '') {
  6514. if (data.title !== '' || textHtml !== '' )
  6515. {
  6516. //$(selector).css({'background-image':'linear-gradient(to right,rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('+data.image+')'});
  6517. //} else {
  6518. //$(selector).css({'background-image':'url('+data.image+')'});
  6519. $(selector).append('<div class="fixoImgOverlay"></div>')
  6520. }
  6521. if (sliderLib == 'fixoSlider') {
  6522. $(selector).css({'background-image':'url('+data.image+')'});
  6523. // DA GESTIRE INTERNAMENTE A fixo.slider.js
  6524. // DOVRA' CARICARE SOLO SLIDE ATTUALE, PREC. E SUCC
  6525. //fixo.loadImage({
  6526. // object: selector,
  6527. // url: data.image,
  6528. // animation: 'fadeIn',
  6529. //});
  6530. }
  6531. //if (sliderLib == 'swiper') {
  6532. // $(selector).addClass('swiper-lazy');
  6533. // $(selector).attr('data-background', data.image);
  6534. //}
  6535. //if (sliderLib == 'flickity') {
  6536. // $(selector).attr('data-flickity-bg-lazyload', data.image);
  6537. //}
  6538. } else {
  6539. $(selector).css({'background-image':'none'});
  6540. // SERVICE ICON
  6541. //$(selector).append('<div class="slideIcon"></div><div class="slideIconName" style="display:none"></div></div>');
  6542. //self.addSlideIcon(data);
  6543. // if (data.icon)
  6544. // self.svgImage({
  6545. // container: selector + ' > .slideIcon',
  6546. // icon: data.icon,
  6547. // color: '#fff',
  6548. // });
  6549. // if (data.iconName)
  6550. // $(selector + ' > .slideIconName').html(data.iconName);
  6551. // if (data.icon)
  6552. // self.svgImage({
  6553. // container: selector + ' > .slideIcon',
  6554. // icon: data.icon,
  6555. // color: '#fff',
  6556. // });
  6557. // if (data.iconName)
  6558. // $(selector + ' > .slideIconName').html(data.iconName);
  6559. }
  6560. // ICONA
  6561. $(selector).append('<div class="slideIcon"></div><div class="slideIconName" style="display:none"></div></div>');
  6562. self.addSlideIcon(data);
  6563. // TITLE & TEXT
  6564. $(selector).append('<div class="slideTitle"></div><div class="slideText"></div><div class="slideInfo"></div>');
  6565. var alertTitleObj = $(selector + ' > .slideTitle');
  6566. var alertTextObj = $(selector + ' > .slideText');
  6567. var alertInfoObj = $(selector + ' > .slideInfo');
  6568. // BOTTONI INFO
  6569. var btnInfo = '';
  6570. for (var i in infoButtons) {
  6571. if (infoButtons[i].icon !== '')
  6572. btnInfo += self.imgTag({
  6573. icon: infoButtons[i].icon,
  6574. action: infoButtons[i].action,
  6575. class: infoButtons[i].class,
  6576. value: infoButtons[i].value,
  6577. //style: 'width: 84px; margin:6px 10px;'
  6578. });
  6579. //alertInfoObj.html(btnInfo);
  6580. }
  6581. alertInfoObj.html(btnInfo);
  6582. // TESTO
  6583. if (data.title && data.title !== '') {
  6584. alertTitleObj.html(data.title);
  6585. } else {
  6586. alertTitleObj.html(data.iconName);
  6587. }
  6588. alertTextObj.html(textHtml);
  6589. //alertInfoObj.html()
  6590. // if (data.link && data.link !== '') { // serviva a costruire il div con il qrcode, sostituito dal link per aprire lo swal alert
  6591. // var link = data.link;
  6592. // self.log('DATALINK: '+link);
  6593. // if (link.indexOf('musement.com') || link.indexOf('booking.com')) {
  6594. // link = link.replace(/^https?:\/\//,''); //rimuovo https dal link
  6595. // self.log('link: '+link);
  6596. // link = 'https://c83.travelpayouts.com/click?shmarker=219111&promo_id=2015&source_type=customlink&type=click&custom_url=' + link;
  6597. // }
  6598. // self.log('DATALINK1: '+link);
  6599. // $(selector).append('<div class="slideQrCode"></div>');
  6600. // self.qrCode({
  6601. // container: selector,
  6602. // class: 'slideQrCode',
  6603. // text: link,
  6604. // size: 100
  6605. // });
  6606. // // attributo sul Codice QR per la visualizzazione dell'alert
  6607. // $('.slideQrCode > img').attr('onclick','javascript:self.do(\'app.hot.alertQRCode\')');
  6608. // } else {
  6609. $(selector).append('<div class="slideButton" style="display:none"></div>');
  6610. if (data.button) {
  6611. if (data.buttonLabel) {
  6612. $(selector + ' > .slideButton').html(data.buttonLabel);
  6613. }
  6614. if (data.buttonAction) {
  6615. $(selector + ' > .slideButton').data('action', data.buttonAction);
  6616. $(selector + ' > .slideButton').data('value', data.value);
  6617. $(selector + ' > .slideButton').attr('onclick', 'javascript:self.do(\'' + data.buttonAction + '\',\''+data.value+'\')');
  6618. }
  6619. $(selector + ' > .slideButton').show();
  6620. // $(selector + ' > .slideButton').off().on(self.touch, function(){
  6621. // var action = $(this).data('action');
  6622. // var key = $(this).data('value');
  6623. // self.do(action, value);
  6624. // });
  6625. } else {
  6626. $(selector + ' > .slideButton').hide();
  6627. }
  6628. //} chiude l'IF del data.link
  6629. var titleAndText = (alertTitleObj.text() !== '' && alertTextObj.text() !== '');
  6630. // POSIZIONE TITOLO
  6631. var titleTop = -70 -170 * (titleAndText);
  6632. alertTitleObj.css({'margin-top': titleTop + 'px'});
  6633. self.textFit(alertTitleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 30, maxFontSize: 56});
  6634. // ALTEZZA TESTO
  6635. var textHeight = 340 - 100 * (infoButtons.length > 0);
  6636. alertTextObj.css({'height': textHeight + 'px'});
  6637. //self.textFit(alertTitleObj, {alignHoriz: true, multiLine: false, alignVert: true, minFontSize: 30, maxFontSize: 56});
  6638. //self.textFit(alertTextObj, {alignHoriz: true, multiLine: false, alignVert: !titleAndText, minFontSize: 15, maxFontSize: 45});
  6639. //self.log('END createSLIDE');
  6640. }
  6641. this.createSlider = function (data) {
  6642. self.log('createSlider');
  6643. //if (!data.prefix) data.prefix = "";
  6644. var selector = self.selector(data);
  6645. var startIndex = data.index || 0;
  6646. //self.log('pre DATAINDEX: '+data.index);
  6647. // RIMUOVE ISTANZA PRECEDENTE
  6648. if (slides[selector] && slides[selector].object) {
  6649. // Memorizza posizione
  6650. var slideSelector = selector + ' > .' + sliderSelectedClass;
  6651. //self.log('slideSelector di self.createSlider: '+slideSelector);
  6652. startIndex = data.index || $(slideSelector).index();
  6653. // Rimuove slider precedente
  6654. //self.log('startIndex: di '+data.index+' .index() '+$(slideSelector).index());
  6655. $(selector).empty();
  6656. delete slides[selector].object;
  6657. }
  6658. slides[selector] = {};
  6659. // FRECCE
  6660. // if (data.buttons) {
  6661. // if (sliderLib == 'swiper') {
  6662. // $(selector).append('<div class="swiper-button-next swiper-button-white"></div>');
  6663. // $(selector).append('<div class="swiper-button-prev swiper-button-white"></div>');
  6664. // }
  6665. // }
  6666. for (var key in data.slides) {
  6667. var slide = data.slides[key];
  6668. slide.inverse = data.inverse;
  6669. //slide.container = selector; //+' > .' + sliderWrapperClass;
  6670. slide = self.extend({
  6671. container: selector,
  6672. class: 'fixoSlide', //sliderSlideClass,
  6673. value: data.value, //data.prefix + data.value
  6674. }, slide);
  6675. self.createSlide(slide);
  6676. }
  6677. // CREAZIONE OGGETTO SLIDER
  6678. if (sliderLib == 'fixoSlider') {
  6679. var params = {
  6680. container: selector, //+' > .' + sliderWrapperClass,
  6681. play: data.play,
  6682. interval: data.interval, // ms
  6683. onChange: data.onChange,
  6684. onChangeStart: self.slideTextFit,
  6685. index: startIndex // prima slide
  6686. // direction: 1, // from right to left
  6687. // opts.swipeDuration: 0.6, // sec
  6688. // opts.swipeTreshold: 0.2, // Swipe from +/-20%
  6689. };
  6690. slides[selector].object = $.fn.slide(params);
  6691. }
  6692. //self.log('END createSlider');
  6693. }
  6694. */
  6695. /*
  6696. this.getSelectedSlide = function (data) {
  6697. self.log('getSelectedSlide');
  6698. //self.log(data);
  6699. var selector = self.selector(data);
  6700. if (sliderLib == 'fixoSlider') {
  6701. var slideSelector = selector + ' > .' + sliderSelectedClass;
  6702. self.log($(slideSelector).data('value'));
  6703. return $(slideSelector).data('value');
  6704. }
  6705. }
  6706. var sliderSelect = function (currentItem, currentIndex) { //si può cancellare?
  6707. var id = $(currentItem).parent().parent().parent().attr('id');
  6708. self.log('slideId:'+id);
  6709. self.log('currentItem:'+currentItem);
  6710. self.log('currentIndex:'+currentIndex);
  6711. slides[id].currentItem = currentItem;
  6712. slides[id].currentIndex = currentIndex;
  6713. }
  6714. var sliderPause = function (currentItem, currentIndex) { // si può cancellare?
  6715. $(currentItem).parent().parent().trigger('extra:slider:pause');
  6716. var id = $(currentItem).parent().parent().parent().attr('id');
  6717. self.log('slideId:'+id);
  6718. self.log('currentItem:'+currentItem);
  6719. self.log('currentIndex:'+currentIndex);
  6720. slides[id].currentItem = currentItem;
  6721. slides[id].currentIndex = currentIndex;
  6722. }
  6723. var sliderPlay = function (currentItem, currentIndex) { // si può cancellare?
  6724. $(currentItem).parent().parent().trigger('extra:slider:pause');
  6725. $(currentItem).parent().parent().trigger('extra:slider:resume');
  6726. var id = $(currentItem).parent().parent().parent().attr('id');
  6727. self.log('slideId:'+id);
  6728. self.log('currentItem:'+currentItem);
  6729. self.log('currentIndex:'+currentIndex);
  6730. slides[id].currentItem = currentItem;
  6731. slides[id].currentIndex = currentIndex;
  6732. }
  6733. var sliderResume = function (currentItem, currentIndex) { //si può cancellare?
  6734. var id = $(currentItem).parent().parent().parent().attr('id');
  6735. if (slides[id].active) {
  6736. sliderPlay(currentItem, currentIndex);
  6737. } else {
  6738. sliderPause(currentItem, currentIndex);
  6739. }
  6740. }
  6741. var sliderClick = function (currentItem, currentIndex) { // si può cancellare ?
  6742. var id = $(currentItem).parent().parent().parent().attr('id');
  6743. if (slides[id].active) {
  6744. slides[id].active = false;
  6745. } else {
  6746. slides[id].active = true;
  6747. }
  6748. } */
  6749. /* this.addItem = function (data, selectorParams) { // obsolete
  6750. var container = (selectorParams) ? self.selector(selectorParams) : data.container;
  6751. var selector = self.selector(self.extend({}, data, selectorParams));
  6752. // app default
  6753. // aggiungere anche dimensione di default
  6754. var iconClass = self.json.setup.classes.icon || '';
  6755. var badgeClass = self.json.setup.classes.badge || '';
  6756. var style = (data.style) ? data.style : {};
  6757. // retro-compatibility
  6758. if (data.size) {
  6759. if (data.size == 'small')
  6760. style.width = '50px';
  6761. else if (data.size == 'medium')
  6762. style.width = '80px';
  6763. else if (data.size == 'big')
  6764. style.width = '120px';
  6765. else if (data.size)
  6766. style.width = data.size;
  6767. }
  6768. style = self.extend({}, style, { // retrocompatibilità / obsoleto
  6769. color: data.color,
  6770. background: data.background,
  6771. border: data.border,
  6772. display: data.display,
  6773. margin: data.margin,
  6774. padding: data.padding,
  6775. width: data.width,
  6776. height: data.height
  6777. });
  6778. // Create
  6779. if (data.id === undefined) {data.id = '';}
  6780. if (data.value === undefined) {data.value = data.id};
  6781. if (data.class === undefined) {data.class = iconClass} else if (data.class !== iconClass) {data.class += ' ' + iconClass};
  6782. var itemDiv = '<div id="'+data.id+'" class="'+data.class+'" data-value="'+data.value+'" data-selector="'+selector+'"></div>';
  6783. if (data.prepend) {
  6784. $(data.container).prepend(itemDiv);
  6785. } else {
  6786. $(data.container).append(itemDiv);
  6787. }
  6788. self.css({style: {
  6789. width: style.width,
  6790. display: style.display,
  6791. padding: style.padding,
  6792. margin: style.margin
  6793. }}, {container: selector});
  6794. // SVG
  6795. if (data.svg || data.text) {
  6796. self.svgImage({
  6797. container: selector,
  6798. icon: data.svg,
  6799. text: data.text,
  6800. textSize: data.textSize, // verify (obsolete when span will be nested)
  6801. textPosition: data.textPosition, // verify (obsolete when span will be nested)
  6802. textColor: data.textColor, // verify (obsolete when span will be nested)
  6803. background: style.background,
  6804. border: style.border,
  6805. color: style.color
  6806. //hoverBackground: data.hoverBackground, // verify
  6807. //hoverBorder: data.hoverBorder, // verify
  6808. //hoverColor: data.hoverColor, // verify
  6809. });
  6810. } else {
  6811. }
  6812. // image
  6813. if (data.image) {
  6814. var imgData = data;
  6815. imgData.style = {
  6816. width:'82px',
  6817. height:'82px',
  6818. 'margin-bottom':'27px'
  6819. };
  6820. if (style.background) imgData.style['background-color'] = style.background;
  6821. self.loadImage(imgData);
  6822. }
  6823. // badge
  6824. if (data.badgeIcon || data.badgeText) {
  6825. $(selector).append('<div class="'+badgeClass+'"></div>');
  6826. self.svgImage({
  6827. container: selector + ' > .'+badgeClass,
  6828. icon: data.badgeIcon,
  6829. text: data.badgeText,
  6830. background: data.badgeBackground,
  6831. border: data.badgeBorder,
  6832. color: data.badgeColor,
  6833. });
  6834. }
  6835. if (data.title) {
  6836. //data.title = self.text(data.title);
  6837. data.titleColor = data.titleColor || style.color;
  6838. if (data.titleColor == undefined) {data.titleColor = ''}
  6839. if (data.titleSize == undefined) {data.titleSize = ''}
  6840. //if (data.titleSizeMin == undefined) {data.titleSize = '7px'}
  6841. $(selector).append('<span></span>');
  6842. $(selector + ' > span').css({
  6843. color: data.titleColor,
  6844. 'font-size': data.titleSize
  6845. });
  6846. //if (typeof data.title == 'object') alert(data.title.text);
  6847. self.text(data.title, {container: selector + ' > span'});
  6848. //var title = self.text(data.title);
  6849. //$(selector + ' > span').text(title);
  6850. //self.text(data.title);
  6851. // itemSelectedBorderWhite GESTITO IN INDEX.CSS
  6852. // questo stile dovrebbe essere fisso e con posizione assoluta
  6853. if (data.image)
  6854. $(selector + ' > span').css({
  6855. 'margin-top':'89px',
  6856. position: 'absolute'
  6857. });
  6858. if (data.textFit !== false) {
  6859. self.textFit($(selector+' > span'), {
  6860. alignHoriz: false,
  6861. multiLine: false,
  6862. alignVert: false,
  6863. minFontSize: 10,
  6864. maxFontSize: data.titleSize,
  6865. });
  6866. }
  6867. }
  6868. // action (obsolete)
  6869. if (data.action || data.functions) {
  6870. var.functions[selector] = data.functions || data.action; // obsoleto
  6871. $(selector).data('onData', data); // nuova versione
  6872. $(selector).off().on(self.touch, function(event){
  6873. event.stopPropagation();
  6874. self.onEvent(this, event);
  6875. });
  6876. }
  6877. // matchMedia
  6878. if (data.matchMedia) {
  6879. for (var mediaEvent in data.matchMedia) {
  6880. self.matchMedia(data.matchMedia[mediaEvent], mediaEvent);
  6881. }
  6882. }
  6883. // events
  6884. if (data.on) self.on(data.on, {container: selector});
  6885. if (data.checked !== undefined) {
  6886. self.checkItem({
  6887. container: data.container,
  6888. class: data.class,
  6889. value: data.value,
  6890. id: data.id,
  6891. checked: data.checked
  6892. //style: data.style,
  6893. });
  6894. }
  6895. } */
  6896. // --------------
  6897. // TABS
  6898. // --------------
  6899. /* this.addTab = function (data, selectorParams) {
  6900. //self.log('addTab');
  6901. //self.log(data);
  6902. var containerParams = self.cloneObject(selectorParams);
  6903. data.container = containerParams.container;
  6904. var selector = self.selector(data);
  6905. var tabClass = ''; //self.json.setup.classes.button || '';
  6906. var badgeClass = 'iconBadge'; //self.json.setup.classes.badge || '';
  6907. var style = (data.style) ? data.style : {};
  6908. // span height
  6909. //style["line-height"] = (style.height) ? style.height : '42px';
  6910. style = self.extend({}, style, {
  6911. color: data.color,
  6912. background: data.background,
  6913. border: data.border,
  6914. display: data.display,
  6915. margin: data.margin,
  6916. padding: data.padding,
  6917. width: data.width,
  6918. height: data.height
  6919. });
  6920. if (data.id === undefined) {data.id = '';}
  6921. if (data.value === undefined) {data.value = data.id};
  6922. if (data.class === undefined) {data.class = tabClass} else if (data.class !== tabClass) {data.class += ' ' + tabClass};
  6923. var tabDiv = '<div id="'+data.id+'" class="'+data.class+'" data-value="'+data.value+'" data-selector="'+selector+'"></div>';
  6924. $(data.container).append(tabDiv);
  6925. self.css({style: style}, {container: selector});
  6926. //if (data.key) {$(selector).data('key', data.key);}
  6927. //var iconColor = style.color || $(selector).css("color");
  6928. // ICON
  6929. if (data.icon) {
  6930. self.addItem({
  6931. class: 'icon',
  6932. value: data.value,
  6933. svg: data.icon,
  6934. image: data.image,
  6935. style: {
  6936. color: style.color || $(selector).css("color"),
  6937. width: style.height
  6938. }
  6939. }, {container: selector});
  6940. }
  6941. // TEXT
  6942. if (data.text !== undefined) {
  6943. //alert(JSON.stringify(data.text));
  6944. $(selector).append('<span></span>');
  6945. self.text(data.text, {container: selector + ' > span'});
  6946. } else {
  6947. //alert(JSON.stringify(data.text));
  6948. }
  6949. if (data.icon) $(selector + ' > span').css({'padding-left': '0px'});
  6950. // SPAN
  6951. if(style.color) $(selector + ' > span').css({'color':style.color});
  6952. // BADGE
  6953. if (data.badgeIcon || data.badgeText) {
  6954. if (!$('.'+badgeClass).length)
  6955. $(selector).append('<div class="'+badgeClass+'"></div>');
  6956. self.svgImage({
  6957. container: selector + ' > .'+badgeClass,
  6958. icon: data.badgeIcon,
  6959. text: data.badgeText,
  6960. background: data.badgeBackground,
  6961. border: data.badgeBorder,
  6962. color: data.badgeColor,
  6963. });
  6964. } else {
  6965. $(selector + ' > .'+badgeClass).remove();
  6966. }
  6967. // data
  6968. if (data.action || data.functions){
  6969. var.functions[selector] = data.functions || data.action; // obsoleto
  6970. $(selector).data('onData', data); // nuova versione
  6971. $(selector).off().on(self.touch, function(event){
  6972. event.stopPropagation();
  6973. self.onEvent(this, event);
  6974. //$(this).data('value')
  6975. //var selector = $(this).data('selector');
  6976. //var action = var.functions[selector];
  6977. //self.do($(this).data('onData').action, $(this).data('value'));
  6978. });
  6979. }
  6980. // matchMedia
  6981. if (data.matchMedia) {
  6982. for (var mediaEvent in data.matchMedia) {
  6983. self.matchMedia(data.matchMedia[mediaEvent], mediaEvent);
  6984. }
  6985. }
  6986. // events
  6987. if (data.on) self.on(data.on, {container: selector});
  6988. if (data.selected) self.selectTab(data);
  6989. } */
  6990. /* this.changeTab = function (data, selectorParams) {
  6991. var container = (selectorParams) ? self.selector(selectorParams) : data.container;
  6992. var selector = self.selector(self.extend({}, data, selectorParams));
  6993. if (data.icon && data.value) {
  6994. self.changeItem({
  6995. container: selector,
  6996. class: 'icon',
  6997. value: data.value,
  6998. svg: data.icon,
  6999. color: data.color,
  7000. background: data.background
  7001. });
  7002. }
  7003. if(data.background) $(selector).css({'background':data.background});
  7004. if(data.color) $(selector + ' > span').css({'color':data.color});
  7005. if (data.text) {
  7006. //$(selector + ' > span').text(self.text(data.text));
  7007. self.text(data.text, {container: selector + ' > span'});
  7008. }
  7009. if (data.action){
  7010. $(selector).off().on(self.touch, function(){
  7011. data.action(data.value)
  7012. });
  7013. }
  7014. // events
  7015. if (data.on) self.on(data.on, {container: selector});
  7016. if (data.selected) self.selectTab(data);
  7017. } */
  7018. /* this.unselectTabs = function (data) {
  7019. var selectionClass = data.selection || 'selectedButton';
  7020. //var selectionClass = self.json.setup.classes.selectedButton;
  7021. if (data.style) selectionClass = data.style;
  7022. $(data.class).removeClass(selectionClass);
  7023. }
  7024. this.toggleTab = function (data) {
  7025. data.toggle = true;
  7026. return self.selectTab(data);
  7027. }
  7028. this.selectTab = function (data) {
  7029. var selectionClass = data.selection || 'selectedButton';
  7030. //var selectionClass = self.json.setup.classes.selectedButton;
  7031. if (data.style) selectionClass = data.style;
  7032. var selector = self.selector(data);
  7033. if (data.deselectClass)
  7034. if (data.class) $('.'+data.class).removeClass(selectionClass);
  7035. if (data.checked !== undefined) {
  7036. if (data.checked == false) $(selector).removeClass(selectionClass);
  7037. else $(selector).addClass(selectionClass);
  7038. } else if (data.toggle !== undefined) {
  7039. // da toggleTab
  7040. if ($(selector).hasClass(selectionClass)) {
  7041. $(selector).removeClass(selectionClass);
  7042. return false;
  7043. } else {
  7044. //if (data.class) $('.'+data.class).removeClass(selectionClass);
  7045. $(selector).addClass(selectionClass);
  7046. return true;
  7047. }
  7048. } else {
  7049. //if (data.class) $('.'+data.class).removeClass(selectionClass);
  7050. $(selector).addClass(selectionClass);
  7051. }
  7052. } */
  7053. // ---------------------------
  7054. // FUNZIONI DATEPICKER
  7055. // ---------------------------
  7056. /*
  7057. // basato su: http://www.daterangepicker.com/#options
  7058. this.createDatePicker = function (data) {
  7059. self.log('createDatePicker');
  7060. var calendarVisible = false;
  7061. if (!data.field) data.field = data.container + ' > .daterange';
  7062. if (!$(data.field).length) {
  7063. calendarVisible = true; // Crea e nasconde campo testo e mostra calendario
  7064. $(data.container).html('<input type="text" class="form-control daterange" style="display:none"/>');
  7065. }
  7066. var weekD = self.weekdaysShort(1, capitalize);
  7067. weekD = weekD.unshift(weekD[6]);
  7068. var monthsOfYear = ["January","February","March","April","May","June","July","August","September","October","November","December"];
  7069. if (data.language) {
  7070. monthsOfYear = moment.localeData(data.language).months();
  7071. for (var index in monthsOfYear) {
  7072. monthsOfYear[index] =
  7073. monthsOfYear[index].substr(0,1).toUpperCase()
  7074. + monthsOfYear[index].substr(1);
  7075. }
  7076. }
  7077. //var datarange = $('#daterange');
  7078. $(data.field).daterangepicker({
  7079. singleDatePicker: data.single,
  7080. parentEl: data.container,
  7081. startDate: data.start,
  7082. endDate: data.end,
  7083. autoApply: true,
  7084. autoUpdateInput: false,
  7085. locale: {
  7086. format: 'DD/MM/YYYY',
  7087. daysOfWeek: weekD,
  7088. monthNames: monthsOfYear,
  7089. firstDay: 1 // monday
  7090. }
  7091. });
  7092. $(data.field).on('cancel.daterangepicker', function(ev, picker) {
  7093. data.onCancel();
  7094. });
  7095. $(data.field).on('apply.daterangepicker', function(ev, picker) {
  7096. data.onChange({
  7097. start: picker.startDate.format('YYYYMMDD'),
  7098. end: picker.endDate.format('YYYYMMDD')
  7099. });
  7100. if (picker.startDate && picker.endDate && picker.startDate !== picker.endDate) {
  7101. $(data.field).val(picker.startDate.format('DD/MM/YYYY') + '-' + picker.endDate.format('DD/MM/YYYY'));
  7102. } else {
  7103. $(data.field).val(picker.startDate.format('DD/MM/YYYY'));
  7104. }
  7105. });
  7106. self.unselectDatePicker({container: data.container});
  7107. }
  7108. var disableDates = [];
  7109. this.updateDatePicker = function(data) {
  7110. var datePicker = $(data.container + ' > .daterange').data('daterangepicker');
  7111. if (data.disableDates) {disableDates = data.disableDates;}
  7112. // alert(datePicker+'-'+data.container);
  7113. datePicker.isInvalidDate = function(date) {
  7114. return (disableDates.indexOf(date.format('YYYYMMDD')) >= 0)
  7115. }
  7116. datePicker.updateView();
  7117. if (data.start && data.end) {
  7118. self.setDatePicker({
  7119. container: data.container,
  7120. start: data.start,
  7121. end: data.end,
  7122. });
  7123. } else {
  7124. self.unselectDatePicker({container: data.container});
  7125. }
  7126. }
  7127. this.unselectDatePicker = function(data) {
  7128. $(data.container).find('.start-date').removeClass('start-date active');
  7129. $(data.container).find('.end-date').removeClass('end-date active');
  7130. $(data.container).find('.in-range').removeClass('in-range');
  7131. }
  7132. this.setDatePicker = function (data) {
  7133. var datePicker = $(data.container + ' > .daterange').data('daterangepicker');
  7134. datePicker.setStartDate(data.start);
  7135. datePicker.setEndDate(data.end);
  7136. datePicker.updateView();
  7137. }
  7138. this.getDatePicker = function (data) {
  7139. var start = $(data.container + ' > .daterange').data('daterangepicker').startDate(data.start);
  7140. var end = $(data.container + ' > .daterange').data('daterangepicker').endDate(data.end);
  7141. //alert('ok: '+data.container);
  7142. return {start: start, end: end}
  7143. }
  7144. // ---------------------------
  7145. // FUNZIONI TIMEPICKER
  7146. // ---------------------------
  7147. this.createTimePicker = function (data) {
  7148. $(data.container).html('<div class="datetimepicker" data-value="'+data.value+'"></div>');
  7149. $(data.container + ' > .datetimepicker').datetimepicker({
  7150. icons: {
  7151. up: "fixoNavUp",
  7152. down: "fixoNavDown",
  7153. previous: "fixoNavBackward",
  7154. next: "fixoNavForward"
  7155. },
  7156. inline: true,
  7157. sideBySide: true,
  7158. //locale: 'it'
  7159. locale: {
  7160. format: 'DD/MM/YYYY',
  7161. daysOfWeek: weekD,
  7162. monthNames: monthsOfYear,
  7163. firstDay: 1 // monday
  7164. }
  7165. });
  7166. //self.log('now: '+Date.now()+' moment: '+moment());
  7167. self.setTimePicker({
  7168. container: data.container,
  7169. time: data.time
  7170. });
  7171. $(data.container + ' > .datetimepicker').off().on('dp.change', function(event) {
  7172. var datePicked = moment(event.date).unix();
  7173. //alert(datePicked);
  7174. data.onChange(datePicked);
  7175. });
  7176. }
  7177. this.setTimePicker = function (data) {
  7178. //self.log('>>> setTimePicker --> data container: '+data.container+' data time: '+data.time+' moment: '+moment.unix(data.time).calendar());
  7179. $(data.container + ' > .datetimepicker').data('DateTimePicker').date(moment.unix(data.time));//.format('LLL'));
  7180. }
  7181. this.getTimePicker = function (data) {
  7182. //alert('ok: '+data.container);
  7183. $(data.container + ' > .datetimepicker').data('DateTimePicker').date();
  7184. }
  7185. */
  7186. // ---------------------------
  7187. // TIME SLIDER
  7188. // ---------------------------
  7189. /*
  7190. this.createTimeSlider = function(data){
  7191. var container = data.container;
  7192. var id = data.id;
  7193. // c'è un'anomalia nella libreria bootstrap-slider
  7194. // crea il contenitore dello slider con lo stesso id del campo input
  7195. // va verificata la possibilità di configurazione della funzione .slider
  7196. $('#'+data.container).append('<input id="'+id+'" data-slider-id="'+id+'" type="text" class="span2" value="" data-slider-min="0" data-slider-max="48" data-slider-step="1" data-slider-value="[0,48]" data-slider-tooltip="hide"/>');
  7197. $('#'+id).slider();
  7198. $('#'+id).off().on("slide slideStop", function(event) {
  7199. self.log(event);
  7200. self.changeItem({
  7201. id:'stepbackwardSlider'+id,
  7202. text: self.numberToHour({value: event.value[0], max: 48})
  7203. });
  7204. self.changeItem({
  7205. id:'stepforwardSlider'+id,
  7206. text: self.numberToHour({value: event.value[1], max: 48})
  7207. });
  7208. if (data.onChange) {
  7209. data.onChange({
  7210. start: self.numberToHour({value: event.value[0], max: 48}),
  7211. end: self.numberToHour({value: event.value[1], max: 48})
  7212. })
  7213. }
  7214. });
  7215. // ICONS Slider
  7216. self.addItem({
  7217. container:'#'+id+' > .min-slider-handle',
  7218. class: 'sliderIconLeft',
  7219. id: 'stepbackwardSlider'+id,
  7220. background: '#fff',
  7221. color: 'black',
  7222. border: 1,
  7223. text: '00:00'
  7224. });
  7225. self.addItem({
  7226. container:'#'+id+' > .max-slider-handle',
  7227. class: 'sliderIconRight',
  7228. id: 'stepforwardSlider'+id,
  7229. background: '#fff',
  7230. color: 'black',
  7231. border: 1,
  7232. text: '24:00'
  7233. });
  7234. //$('#'+sliderId+' .slider-selection').css({'background': '#fff'});
  7235. }
  7236. this.setTimeSlider = function(data){
  7237. //Change value on slider left/right icon
  7238. self.changeItem({
  7239. id:'stepbackwardSlider'+data.id,
  7240. text: data.start
  7241. });
  7242. self.changeItem({
  7243. id:'stepforwardSlider'+data.id,
  7244. text: data.end
  7245. });
  7246. //Convert value in 0-48 format
  7247. var start = self.hourToNumber({value: data.start, max: 48});
  7248. var end = self.hourToNumber({value: data.end, max: 48});
  7249. // Set value on slider
  7250. $('input[id="'+data.id+'"]').slider('setValue',[start,end]);
  7251. }
  7252. this.getTimeSlider = function(data){
  7253. var slideStart = $('input[id="'+data.id+'"]').slider('getValue')[0] || 0;
  7254. var slideEnd = $('input[id="'+data.id+'"]').slider('getValue')[1] || 48;
  7255. var start = self.numberToHour({value: slideStart, max: 48});
  7256. var end = self.numberToHour({value: slideEnd, max: 48});
  7257. if (start == '24:00') {start = '00:00'}
  7258. var timetable = {
  7259. start: start || '00:00',
  7260. end: end || '24:00'
  7261. }
  7262. return timetable;
  7263. }
  7264. */
  7265. this.numberToHour = function (data) {
  7266. var fraction = data.value / data.max;
  7267. var dayMin = Math.round(24 * 60 * fraction);
  7268. var hour = parseInt(dayMin / 60);
  7269. var min = dayMin - hour * 60;
  7270. var hourString = String(hour < 10 ? '0' : '') + String(hour);
  7271. var minString = String(min < 10 ? '0' : '') + String(min);
  7272. return hourString + ':' + minString;
  7273. };
  7274. this.hourToNumber = function (data) {
  7275. var timeArr = data.value.split(':');
  7276. var dayMin = (60 * Number(timeArr[0])) + Number(timeArr[1]);
  7277. var fraction = dayMin / (24 * 60);
  7278. return Math.round(fraction * data.max);
  7279. };
  7280. this.pannellum = function (params, selectorParams, args) {
  7281. self.log('pannellum');
  7282. var container = params.selector || params.container;
  7283. var selector = self.selector(container) || self.selector(selectorParams);
  7284. var element = self.query(selector);
  7285. pannellum.viewer(element, params);
  7286. };
  7287. this.qrcode = function (params, selectorParams, args) {
  7288. self.log('qrcode');
  7289. var container = params.selector || params.container;
  7290. var selector = self.selector(container) || self.selector(selectorParams);
  7291. var element = self.query(selector);
  7292. // var obj = self.compile(data);
  7293. self.log(selector);
  7294. self.log('element');
  7295. self.log(element);
  7296. var QRCodeOptions = {
  7297. text: self.replaceProperties(params.text, args) || 'jsonic.io',
  7298. width: params.size || 128,
  7299. height: params.size || 128,
  7300. useSVG: true,
  7301. colorDark: params.colorDark || '#000000',
  7302. colorLight: params.colorLight || '#ffffff',
  7303. correctLevel: QRCode.CorrectLevel.H
  7304. };
  7305. self.log('QRCodeOptions');
  7306. self.log(QRCodeOptions);
  7307. element.textContent = '';
  7308. var qrcode = new QRCode(element, QRCodeOptions);
  7309. self.log('qrcode');
  7310. self.log(qrcode);
  7311. return qrcode;
  7312. //qrcode.clear(); // clear the code.
  7313. //qrcode.makeCode(text); // make another code
  7314. };
  7315. /* this.qrcode = function (data) {
  7316. self.log('qrcode');
  7317. var selector = self.selector(data);
  7318. var options = {
  7319. // render method: 'canvas', 'image' or 'div'
  7320. render: 'image',
  7321. // version range somewhere in 1 .. 40
  7322. minVersion: 1,
  7323. maxVersion: 40,
  7324. // error correction level: 'L', 'M', 'Q' or 'H'
  7325. ecLevel: 'L',
  7326. // offset in pixel if drawn onto existing canvas
  7327. left: 0,
  7328. top: 0,
  7329. // size in pixel
  7330. size: data.size || 200,
  7331. // code color or image element
  7332. fill: data.color || '#000',
  7333. // background color or image element, null for transparent background
  7334. background: data.background || null,
  7335. // content
  7336. text: self.replaceProperties(data.text) || 'no text',
  7337. // corner radius relative to module width: 0.0 .. 0.5
  7338. radius: 0,
  7339. // quiet zone in modules
  7340. quiet: 0,
  7341. // modes
  7342. // 0: normal
  7343. // 1: label strip
  7344. // 2: label box
  7345. // 3: image strip
  7346. // 4: image box
  7347. mode: 0,
  7348. mSize: 0.1,
  7349. mPosX: 0.5,
  7350. mPosY: 0.5,
  7351. label: data.label || 'no label',
  7352. fontname: data.fontname || 'sans',
  7353. fontcolor: data.fontcolor || '#000',
  7354. image: null
  7355. }
  7356. $(selector).empty().qrcode(options);
  7357. } */
  7358. this.weekdaysShort = function (length, caseFunction) {
  7359. if (!caseFunction) caseFunction = caseUp;
  7360. var language = 'en';
  7361. var fixoLang = fixo.getFixoLanguage();
  7362. var userLang = fixo.getUserLanguage();
  7363. if (fixo.device) language = fixoLang; else language = userLang;
  7364. var weekDays = self.cloneObject(moment.localeData(language).weekdays());
  7365. weekDays[7] = weekDays[0];
  7366. weekDays.shift();
  7367. for (var i = 0; i < 7; i++) {
  7368. if (length) weekDays[i] = weekDays[i].substr(0, length);
  7369. if (caseFunction) weekDays[i] = caseFunction(weekDays[i]);
  7370. }
  7371. return weekDays;
  7372. };
  7373. this.weekDaysToString = function (days) {
  7374. var text = '';
  7375. for (var i in days) {
  7376. if (days[i]) {
  7377. if (text !== '') text += '/';
  7378. text += self.weekdaysShort(3, capitalize)[i];
  7379. }
  7380. }
  7381. return text;
  7382. };
  7383. // -----------
  7384. // DRAG
  7385. // -----------
  7386. /*
  7387. var draggingData;
  7388. this.sortable = function (data) {
  7389. var rootEl = $(data.container)[ 0 ];
  7390. var dragEl;
  7391. draggingData = data;
  7392. var selector = self.selector(data);
  7393. $(selector).attr('draggable', 'true');
  7394. $(data.exclude).attr('draggable', 'false');
  7395. // Function responsible for sorting
  7396. function onDragOver(event) {
  7397. event.preventDefault();
  7398. event.dataTransfer.dropEffect = 'move';
  7399. var dragTarget = event.target; // target.nextSibling ||
  7400. if ($(dragTarget).hasClass(draggingData.class))
  7401. $( dragEl ).insertAfter( $(dragTarget) );
  7402. if ($(dragTarget).parent().hasClass(draggingData.class))
  7403. $( dragEl ).insertAfter( $(dragTarget).parent() );
  7404. }
  7405. // End of sorting
  7406. function onDragEnd(event){
  7407. event.preventDefault();
  7408. $(dragEl).css({'opacity':'100%'});
  7409. rootEl.removeEventListener('dragover', onDragOver, false);
  7410. rootEl.removeEventListener('dragend', onDragEnd, false);
  7411. // Notification about the end of sorting
  7412. draggingData.target = dragEl;
  7413. draggingData.onDragEnd(draggingData);
  7414. }
  7415. // Sorting starts
  7416. rootEl.addEventListener('dragstart', function (event){
  7417. dragEl = event.target; // Remembering an element that will be moved
  7418. $(dragEl).css({'opacity':'50%'});
  7419. // Limiting the movement type
  7420. event.dataTransfer.effectAllowed = 'move';
  7421. event.dataTransfer.setData('Text', dragEl.textContent);
  7422. // Subscribing to the events at dnd
  7423. rootEl.addEventListener('dragover', onDragOver, false);
  7424. rootEl.addEventListener('dragend', onDragEnd, false);
  7425. setTimeout(function () {
  7426. // If this action is performed without setTimeout, then
  7427. // the moved object will be of this class.
  7428. $(dragEl).css({'opacity':'100%'});
  7429. }, 0)
  7430. }, false);
  7431. }
  7432. */
  7433. /*
  7434. this.setWeekDays = function(data){
  7435. if (!data.days) data.days = {};
  7436. for (var i=1; i<7; i++){
  7437. self.selectTab({
  7438. container: data.container,
  7439. class: 'fixoTabsWeekDays',
  7440. value: String(i),
  7441. checked: data.days[String(i)] || false
  7442. });
  7443. }
  7444. }
  7445. this.createWeekDays = function(data){
  7446. //var selector = self.selector(data);
  7447. var weekDays = ["Sun","Mon","Tue","Wed","Thu","Fri","Sat"];
  7448. self.log('data.language '+data.language);
  7449. if (data.language) weekDays=moment.localeData(data.language).weekdaysShort();
  7450. for (var i=0; i<7; i++){
  7451. var weekDay = weekDays[i];
  7452. self.addTab({
  7453. container: data.container,
  7454. class: data.class,
  7455. value: String(i),
  7456. id: data.container + i,
  7457. background: 'black',
  7458. color: 'white',
  7459. border: '1px solid rgba(0, 0, 0, 1)',
  7460. text: weekDay,
  7461. action: function(value){
  7462. //alert($(this).attr(id));
  7463. // il toggleTab deselezionava sempre gli altri giorni
  7464. // risolto usando il selectTab col parametro checked
  7465. // va sistemato toggleTab
  7466. if (!data.days) data.days = {};
  7467. var checked = !Boolean(data.days[value]);
  7468. self.selectTab({
  7469. container: data.container,
  7470. class: 'fixoTabsWeekDays',
  7471. value: value,
  7472. checked: checked
  7473. });
  7474. data.days[value] = checked;
  7475. }
  7476. });
  7477. }
  7478. }
  7479. */
  7480. //--------------------------
  7481. // DA FIXO.JS
  7482. //--------------------------
  7483. /*---------------------
  7484. UTILS
  7485. ---------------------*/
  7486. var sortField;
  7487. var dynamicSort = function (data) {
  7488. var sortOrder = 1;
  7489. if (data.reverse) { sortOrder = -1; }
  7490. sortField = data.field;
  7491. return function (a, b) {
  7492. var result = (a[sortField] < b[sortField]) ? -1 : (a[sortField] > b[sortField]) ? 1 : 0;
  7493. return result * sortOrder;
  7494. };
  7495. };
  7496. this.sort = function (data) {
  7497. // fixo.sort({object:{}, add: {}, field:'time', reverse:true})
  7498. if (data.object !== undefined) {
  7499. if (Array.isArray(data.object)) {
  7500. return data.object.sort(dynamicSort({
  7501. field: data.field,
  7502. reverse: data.reverse
  7503. }));
  7504. } else {
  7505. var arr = self.objectToArray({
  7506. object: data.object,
  7507. add: data.add,
  7508. });
  7509. return arr.sort(dynamicSort({
  7510. field: data.field,
  7511. reverse: data.reverse
  7512. }));
  7513. }
  7514. } else {
  7515. self.log('sort of undefined');
  7516. return [];
  7517. }
  7518. };
  7519. this.objectToArray = function (data) {
  7520. // data: {object:{}, add: {}}
  7521. var arr = [];
  7522. var obj = data.object;
  7523. if (obj !== undefined) {
  7524. for (var key in obj) {
  7525. obj[key].id = key; // aggiunge la chiave dell'oggetto come proprietà
  7526. if (data.add) obj[key] = Object.assign(obj[key], data.add);
  7527. arr.push(obj[key]);
  7528. }
  7529. }
  7530. return arr;
  7531. };
  7532. /*
  7533. this.itemsFound = function(items, field, value) {
  7534. return $.grep(items, function(e){ return e.name == value; });
  7535. }
  7536. */
  7537. /* this.itemFound = function(items, field, value) {
  7538. var itemFound = false;
  7539. for (var i=0; i<items.length; i++) {
  7540. if (items[i][field] == value) {
  7541. itemFound = true;
  7542. }
  7543. }
  7544. return itemFound;
  7545. } */
  7546. /* this.itemExist = function(data) {
  7547. if (data.value) {
  7548. return ($(data.class + '[data-value='+data.value+']').length > 0);
  7549. } else {
  7550. return ($(data.class).length > 0);
  7551. }
  7552. } */
  7553. this.equal = function (obj1, obj2) {
  7554. if (obj1 && obj2) {
  7555. return (JSON.stringify(obj1).replace('"', '') == JSON.stringify(obj2).replace('"', ''));
  7556. } else {
  7557. return (obj1 == obj2);
  7558. }
  7559. };
  7560. /* this.arraysEquals = function(arr1,arr2) {
  7561. return ($(arr1).not(arr2).length === 0 && $(arr2).not(arr1).length === 0);
  7562. } */
  7563. var escapeRegExp = function (str) {
  7564. return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, "\\$1");
  7565. };
  7566. this.replaceAll = function (str, find, replace) {
  7567. if (str !== undefined) {
  7568. let result;
  7569. if (typeof str == 'string') result = str; else result = JSON.stringify(str);
  7570. if (str) {
  7571. if (find) { // && replace
  7572. //if (typeof str !== 'string') self.log(str);
  7573. result = String(str).replace(new RegExp(escapeRegExp(find), 'g'), replace);
  7574. //if (typeof str == 'string') return result; else return JSON.parse(result);
  7575. if (typeof str == 'object' && result) return JSON.parse(result);
  7576. else
  7577. return result;
  7578. } else {
  7579. /* self.log('str:'+str);
  7580. self.log('find:'+find);
  7581. self.log('replace:'+replace); */
  7582. return str;
  7583. }
  7584. }
  7585. } else {
  7586. return str;
  7587. }
  7588. };
  7589. this.capitalize = function (str) {
  7590. return str.replace(/\b\w/g, l => l.toUpperCase());
  7591. };
  7592. /*---------------------
  7593. URL UTILS
  7594. ---------------------*/
  7595. this.getPageName = function (url) {
  7596. var index = url.lastIndexOf("/") + 1;
  7597. var filenameWithExtension = url.substr(index);
  7598. var filename = filenameWithExtension.split(".")[0]; // <-- added this line
  7599. return filename; // <-- added this line
  7600. };
  7601. this.goToMainUrl = function () {
  7602. window.location = self.mainUrl;
  7603. };
  7604. this.getParameterByName = function (name, url) {
  7605. if (!url) url = window.location.href;
  7606. name = name.replace(/[\[\]]/g, "\\$&");
  7607. var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"), results = regex.exec(url);
  7608. if (!results) return null;
  7609. if (!results[2]) return '';
  7610. return decodeURIComponent(results[2].replace(/\+/g, " "));
  7611. };
  7612. var paramsToObject = function (params) {
  7613. params = params.split('#')[0];
  7614. return JSON.parse('{"' + params.replace(/"/g, '\\"').replace(/&/g, '","').replace(/=/g, '":"') + '"}');
  7615. };
  7616. var objectToParams = function (object) {
  7617. var str = '';
  7618. for (var key in object) str += '&' + key + '=' + object[key];
  7619. if (str) str = str.substr(1);
  7620. return encodeURI(str);
  7621. };
  7622. this.getParams = function () {
  7623. var params = {};
  7624. var url = window.location.href.split('#')[0];
  7625. if (url.indexOf('?') > -1) {
  7626. var urlParams = decodeURI(url.split('?')[1]);
  7627. self.log(urlParams);
  7628. if (urlParams) {
  7629. var k = self.getParameterByName('k', url);
  7630. //self.log(k);
  7631. if (k) {
  7632. params = self.atob(k);
  7633. } else {
  7634. params = paramsToObject(urlParams);
  7635. }
  7636. }
  7637. }
  7638. return params;
  7639. };
  7640. this.atob = function (k) {
  7641. self.log('atob');
  7642. var params = paramsToObject(atob(k)); // base64 -> query -> object
  7643. // decompress params
  7644. if (params.h) // hotel
  7645. params.h = String(parseInt(String(params.h), 36)); // base36
  7646. if (params.c) // customer
  7647. params.c = String(parseInt(String(params.c), 36)); // base36
  7648. if (params.n) { // phone
  7649. params.n = String(parseInt(String(params.n), 36)); // base36
  7650. params.n = '+' + params.n;
  7651. }
  7652. //if (params.s) params.s = var.services.id[params.s];
  7653. self.log(params);
  7654. return params;
  7655. };
  7656. this.btoa = function (params) {
  7657. self.log('btoa');
  7658. //if (params.s) params.s = var.services.id.indexOf(params.s);
  7659. if (params.h) // hotel
  7660. params.h = Number(params.h).toString(36); // base36
  7661. if (params.c) // customer
  7662. params.c = Number(params.c).toString(36); // base36
  7663. if (params.n) { // phone
  7664. if (params.n.startsWith('+')) params.n = params.n.substr(1);
  7665. params.n = params.n.replace(/ /g, '');
  7666. params.n = params.n.replace(/-/g, '');
  7667. params.n = Number(params.n).toString(36); // base36
  7668. }
  7669. self.log(params);
  7670. return btoa(objectToParams(params)); // query -> base64
  7671. };
  7672. /*
  7673. var encodeNum = function(num) { // 0..1296 es:customer
  7674. var hex = c.toString(36);
  7675. return c.toString(36);
  7676. }
  7677. var decodeNum = function(str) {
  7678. return str.parseInt(36); // .length == 1 ? "0" + hex : hex
  7679. }
  7680. */
  7681. this.colorToRgba = function (hex, opacity) {
  7682. if (hex == 'white') { hex = '#fff'; }
  7683. if (hex == 'black') { hex = '#000'; }
  7684. var c;
  7685. if (/^#([A-Fa-f0-9]{3}){1,2}$/.test(hex)) {
  7686. c = hex.substring(1).split('');
  7687. if (c.length == 3) {
  7688. c = [c[0], c[0], c[1], c[1], c[2], c[2]];
  7689. }
  7690. c = '0x' + c.join('');
  7691. return 'rgba(' + [(c >> 16) & 255, (c >> 8) & 255, c & 255].join(',') + ',' + opacity + ')';
  7692. } else {
  7693. self.log('Bad Hex:' + hex);
  7694. }
  7695. };
  7696. var hueToRGB = function (m1, m2, h) {
  7697. h = (h < 0) ? h + 1 : ((h > 1) ? h - 1 : h);
  7698. if (h * 6 < 1) return m1 + (m2 - m1) * h * 6;
  7699. if (h * 2 < 1) return m2;
  7700. if (h * 3 < 2) return m1 + (m2 - m1) * (0.66666 - h) * 6;
  7701. return m1;
  7702. };
  7703. var HSLToRGB = function (hsl) {
  7704. var m1, m2, r, g, b;
  7705. var h = hsl[0], s = hsl[1], l = hsl[2];
  7706. m2 = (l <= 0.5) ? l * (s + 1) : l + s - l * s;
  7707. m1 = l * 2 - m2;
  7708. return [hueToRGB(m1, m2, h + 0.33333),
  7709. hueToRGB(m1, m2, h),
  7710. hueToRGB(m1, m2, h - 0.33333)];
  7711. };
  7712. var packRGB = function (rgb) {
  7713. var r = Math.round(rgb[0] * 255);
  7714. var g = Math.round(rgb[1] * 255);
  7715. var b = Math.round(rgb[2] * 255);
  7716. // '#' +
  7717. return (r < 16 ? '0' : '') + r.toString(16) +
  7718. (g < 16 ? '0' : '') + g.toString(16) +
  7719. (b < 16 ? '0' : '') + b.toString(16);
  7720. };
  7721. this.degToRGB = function (deg) {
  7722. return packRGB(HSLToRGB([deg / 360, 1, 0.5]));
  7723. };
  7724. this.stripHtml = function (html) {
  7725. var tmp = document.createElement("DIV");
  7726. tmp.innerHTML = html;
  7727. return tmp.textContent || tmp.innerText || "";
  7728. };
  7729. //--------------------------
  7730. // TASK MANAGER
  7731. //--------------------------
  7732. this.log = function (value, color) {
  7733. if (self.json.setup && self.json.setup.log) { // log enabled
  7734. if (typeof value === 'string')
  7735. console.log('%c' + value, 'color:' + color);
  7736. else
  7737. console.log(value);
  7738. }
  7739. };
  7740. var varlog = function (str) {
  7741. self.log(str);
  7742. self.log(window[str]); // 'var' -> var
  7743. };
  7744. this.logJson = function (jsonPar) { self.log(JSON.stringify(jsonPar)); };
  7745. this.getTimestamp = function () {
  7746. // we need also an API to get the time
  7747. // like .getTime()?
  7748. return Math.floor(Date.now());
  7749. };
  7750. this.cloneObject = function (obj) {
  7751. var newObj = JSON.stringify(obj);
  7752. return self.parse(newObj);
  7753. };
  7754. /*------------------------
  7755. TEXT
  7756. ------------------------*/
  7757. /* var caseUp = function (string) {
  7758. if (!string) string = '';
  7759. return string.toUpperCase();
  7760. }
  7761. var caseDown = function (string) {
  7762. if (!string) string = '';
  7763. return string.toLowerCase();
  7764. }
  7765. var capitalize = function(string) {
  7766. if (!string) string = '';
  7767. return self.capitalize(string);
  7768. }
  7769. var text = function (key, caseFunction) {
  7770. var t = self.json.text[key] || '';
  7771. if (caseFunction) return caseFunction(t); else return t;
  7772. } */
  7773. this.setElement = function (elementString, elementValue) {
  7774. var context = window;
  7775. var namespaces = elementString.split(".");
  7776. var func = namespaces.pop();
  7777. if (namespaces[0] == 'frame') {
  7778. namespaces.shift();
  7779. var frameName = namespaces.shift();
  7780. if (frameName && document.getElementById(frameName) !== null)
  7781. context = document.getElementById(frameName).contentWindow;
  7782. } else if (namespaces[0] == 'admin') { // fixo
  7783. namespaces.shift();
  7784. context = fixoAdmin;
  7785. }
  7786. for (var i = 0; i < namespaces.length; i++) {
  7787. if (context[namespaces[i]]) { // var
  7788. context = context[namespaces[i]];
  7789. } else {
  7790. if (elementValue) // scrittura
  7791. context[namespaces[i]] = {}; // crea contesto inesistente
  7792. }
  7793. }
  7794. context[func] = elementValue;
  7795. };
  7796. this.context = function (path) {
  7797. const re = /^(setup|var|data|texts|parts)[\.\s]/; // reserved namespaces
  7798. if (re.test(path)) {
  7799. /* self.log('MATCHED setup|var|data|parts');
  7800. console.log(params); */
  7801. return self.json;
  7802. } else {
  7803. return window;
  7804. }
  7805. };
  7806. this.element = function (params) {
  7807. // {root, path, value}
  7808. // in respect to docElement, it includes replaceProperties for path and value
  7809. // but only if value is a string. TO DO: check it
  7810. let context;
  7811. let path = self.replaceProperties(params.path, params.args);
  7812. let value = (params.value && typeof params.value == 'string') ? self.replaceProperties(params.value, params.args) : params.value;
  7813. // NOTE: log error if the params.root is equal to the first element of the path? (window.window works)
  7814. if (!params.root) {
  7815. context = self.context(path);
  7816. } else {
  7817. context = params.root;
  7818. }
  7819. return self.docElement(path, value, context, params.delete);
  7820. //self.log(value);
  7821. /* if (value && typeof value == 'string') {
  7822. if (value.startsWith('js:')) value = self.js(value.substr(3));
  7823. else if (value.startsWith('+=')) value = self.element({path: path}) + self.js(value.substr(2));
  7824. else if (value.startsWith('-=')) value = self.element({path: path}) - self.js(value.substr(2));
  7825. else if (value.startsWith('/=')) value = self.element({path: path}) / self.js(value.substr(2));
  7826. else if (value.startsWith('*=')) value = self.element({path: path}) / self.js(value.substr(2))
  7827. } */
  7828. // self.log(value);
  7829. /* if (value.startsWith('number:')) value = Number(self.js(value.substr(6)));
  7830. alert('dopo number:'+value);
  7831. if (value.startsWith('boolean:')) value = Boolean(self.js(value.substr(7)));
  7832. if (value.startsWith('string:')) value = String(self.js(value.substr(6)));
  7833. if (value.startsWith('+:')) value = self.element({path: path}) + self.js(value.substr(2));
  7834. if (value.startsWith('-:')) value = self.element({path: path}) - self.js(value.substr(2));
  7835. if (value.startsWith('/:')) value = self.element({path: path}) / self.js(value.substr(2));
  7836. if (value.startsWith('*:')) value = self.element({path: path}) / self.js(value.substr(2)); */
  7837. /* // verificare...
  7838. if (value.startsWith('push:')) {var obj = self.docElement(path, undefined, root); return obj.push(value.substr(3));}
  7839. if (value.startsWith('unshift:')) {var obj = self.docElement(path, undefined, root); return obj.unshift(value.substr(3));}
  7840. if (value.startsWith('pop:')) {var obj = self.docElement(path, undefined, root); return obj.pop(value.substr(3));}
  7841. if (value.startsWith('shift:')) {var obj = self.docElement(path, undefined, root); return obj.shift(value.substr(3));} */
  7842. };
  7843. this.docElement = function (elementString, elementValue, context, elementDelete) {
  7844. if (!context) context = window; // TO DO: remove
  7845. var namespaces = elementString.split(/[.\s]+/); // path nodes separed by dot or spaces
  7846. /* console.log('<-------');
  7847. console.log('context');
  7848. console.log(context);
  7849. console.log('path');
  7850. console.log(elementString);
  7851. console.log('value');
  7852. console.log(elementValue);
  7853. console.log('------>');
  7854. */
  7855. var lastElement = namespaces.pop();
  7856. /* if (namespaces[0] == 'self') {
  7857. namespaces.shift();
  7858. context = self;
  7859. } else if (namespaces[0] == 'frame') {
  7860. namespaces.shift();
  7861. var frameName = namespaces.shift();
  7862. if (frameName && document.getElementById(frameName) !== null)
  7863. context = document.getElementById(frameName).contentWindow;
  7864. } */
  7865. /* console.log('namespaces');
  7866. console.log(namespaces); */
  7867. for (var i = 0; i < namespaces.length; i++) {
  7868. if (context[namespaces[i]]) { // var
  7869. context = context[namespaces[i]];
  7870. } else {
  7871. if (elementValue !== undefined && elementValue !== null) { // wants to assign a value
  7872. context[namespaces[i]] = {}; // it create the context context[namespaces[i]] if it doesn't exist
  7873. context = context[namespaces[i]];
  7874. /* self.log('crea context inesistente');
  7875. self.log('namespaces[i]: '+namespaces[i]); */
  7876. /* self.log('elementValue');
  7877. self.log(elementValue);
  7878. self.log('context[namespaces[i]]');
  7879. self.log(context[namespaces[i]]); */
  7880. } else {
  7881. /* self.log(elementString + ' undefined');
  7882. self.log('lastElement:' + lastElement);
  7883. self.log(elementValue); */
  7884. }
  7885. //break; // perché? rendeva impossibile creare un listener su un nodo secondario (solo su app e non su app/dev)
  7886. }
  7887. }
  7888. if (elementValue !== undefined) { // write
  7889. //self.log(lastElement+'='+elementValue);
  7890. if (typeof elementValue == 'string') elementValue = self.js(elementValue); // 1.0.3
  7891. context[lastElement] = elementValue;
  7892. // elementValue can be a js function
  7893. /* self.log('context');
  7894. self.log(context);
  7895. self.log('context[lastElement]');
  7896. self.log(context[lastElement]);
  7897. self.log('====='); */
  7898. }
  7899. if (elementDelete) delete context[lastElement];
  7900. /* self.log('context');
  7901. self.log(context); */
  7902. /* console.log('namespaces');
  7903. console.log(namespaces);
  7904. self.log('lastElement');
  7905. self.log(lastElement);
  7906. self.log('context[lastElement]');
  7907. self.log(context[lastElement]); */
  7908. if (context[lastElement] && context[lastElement].isConnected)
  7909. return self.elementToSelector(context[lastElement]);
  7910. else
  7911. return context[lastElement];
  7912. };
  7913. /* this.openCloseDropdown = function(key) {
  7914. self.log('openCloseDropdown');
  7915. self.log("key");
  7916. self.log(key);
  7917. //$('.dropdown-menu').css('display','none');
  7918. var selector = self.selector({
  7919. "id": "dropdown" +key,
  7920. "class": 'points',
  7921. "value": key,
  7922. });
  7923. self.log("selector");
  7924. self.log(selector);
  7925. if ($(selector + ' > .dropdown-menu').css('display') == 'none') {
  7926. $(selector + ' > .dropdown-menu').css('display', 'block');
  7927. } else {
  7928. $(selector + ' > .dropdown-menu').css('display', 'none');
  7929. }
  7930. } */
  7931. this.timeToMs = function (string) {
  7932. // bug
  7933. var timeArray = string.match(/(\d+)(\w+)/); // es: 1s / 100ms
  7934. if (timeArray) {
  7935. var value = Number(timeArray[0]);
  7936. var unit = timeArray[1];
  7937. var unitInMs = {
  7938. ms: 1,
  7939. s: 1000,
  7940. m: 1000 * 60,
  7941. h: 1000 * 60 * 60,
  7942. d: 1000 * 60 * 60 * 24,
  7943. milliseconds: 1,
  7944. seconds: 1000,
  7945. minutes: 1000 * 60,
  7946. hours: 1000 * 60 * 60,
  7947. days: 1000 * 60 * 60 * 24
  7948. };
  7949. if (value)
  7950. if (unitInMs[unit])
  7951. return value * unitInMs[unit];
  7952. else
  7953. self.log('wrong unit in the time string [value][unit]: ' + string);
  7954. else
  7955. self.log('wrong value in the time string [value][unit]: ' + string);
  7956. }
  7957. else
  7958. return Number(string);
  7959. };
  7960. this.intervals = {};
  7961. this.timer = function (params, args) {
  7962. // can go in "browser.json / functions (JS Browser BOM)
  7963. // https://www.w3schools.com/js/js_window.asp
  7964. let name = self.replaceProperties(params.name);
  7965. if (!name)
  7966. name = self.getTimestamp() + Math.random(1000);
  7967. if (params.play !== undefined && params.play == 0) {
  7968. if (self.intervals[name]) {
  7969. self.clearInterval({
  7970. name: name
  7971. }, args);
  7972. }
  7973. if (self.timeouts[name]) {
  7974. self.clearTimeout({
  7975. name: name
  7976. }, args);
  7977. }
  7978. }
  7979. else if (params.every !== undefined) {
  7980. let every = self.replaceProperties(params.every);
  7981. if (every) {
  7982. self.setInterval({
  7983. name: name,
  7984. duration: every,
  7985. do: params.do
  7986. }, args);
  7987. }
  7988. }
  7989. else if (params.after !== undefined) {
  7990. let after = self.replaceProperties(params.after);
  7991. if (after) {
  7992. self.setTimeout({
  7993. name: name,
  7994. duration: after,
  7995. do: params.do
  7996. }, args);
  7997. } else {
  7998. self.do(params.do, null, args);
  7999. }
  8000. }
  8001. };
  8002. this.setInterval = function (params, args) {
  8003. // could include the param "fromNow": true to execute the function
  8004. /* self.log('setInterval');
  8005. self.log(params); */
  8006. if (params.name && params.duration) {
  8007. if (self.intervals[params.name])
  8008. clearInterval(self.intervals[params.name]);
  8009. //self.do(params.do);
  8010. self.do(params.do);
  8011. self.intervals[params.name] = setInterval(function () {
  8012. //self.do(params.do);
  8013. self.do(params.do);
  8014. return params.name;
  8015. }, Number(params.duration)); // self.timeToMs
  8016. }
  8017. else
  8018. self.log('"setInterval" function requires "name" and "duration" parameters');
  8019. };
  8020. this.clearInterval = function (params, args) {
  8021. /* self.log('params');
  8022. self.log(params);
  8023. self.log('self.intervals[params.name]');
  8024. self.log(self.intervals[params.name]); */
  8025. if (self.intervals[params.name]) {
  8026. clearInterval(self.intervals[params.name]);
  8027. delete self.intervals[params.name];
  8028. }
  8029. // else
  8030. // self.log('"clearInterval" name not found: ' + params.name);
  8031. };
  8032. this.timeouts = {};
  8033. this.setTimeout = function (params, args) {
  8034. // could include the param "fromNow": true to execute the function
  8035. /* self.log('setTimeout');
  8036. self.log(params); */
  8037. if (params.name && params.duration) {
  8038. if (self.timeouts[params.name])
  8039. clearInterval(self.timeouts[params.name]);
  8040. //self.do(params.do);
  8041. //self.do(params.do);
  8042. self.timeouts[params.name] = setTimeout(function () {
  8043. //self.do(params.do);
  8044. self.do(params.do);
  8045. return params.name;
  8046. }, Number(params.duration)); // self.timeToMs
  8047. }
  8048. else
  8049. self.log('"setTimeout" function requires "name" and "duration" parameters');
  8050. };
  8051. this.clearTimeout = function (params, args) {
  8052. /* self.log('params');
  8053. self.log(params);
  8054. self.log('self.timeouts[params.name]');
  8055. self.log(self.timeouts[params.name]); */
  8056. if (self.timeouts[params.name]) {
  8057. clearTimeout(self.timeouts[params.name]);
  8058. delete self.timeouts[params.name];
  8059. }
  8060. //else
  8061. // self.log('"clearInterval" name not found: ' + params.name);
  8062. };
  8063. this.on = function (params, selectorParams) {
  8064. //let selector = params.selector || params.container;
  8065. var container = (selectorParams) ? self.selector(selectorParams) : params.selector; // 1.0.9 instead of params.container
  8066. /* self.log('on');
  8067. self.log(params);
  8068. self.log('container');
  8069. self.log(container); */
  8070. //var selector = self.selector(self.extend({}, params, selectorParams));
  8071. //$(container).data('onData', {events: params, container: container});
  8072. var element;
  8073. if (container) {
  8074. element = self.query(container); // shoud be foreach elements...
  8075. if (element)
  8076. self.dataStorage.set(element, "onData", { on: params, selector: container });
  8077. else {
  8078. self.log('can\'t find the element "' + container + '" ("on" function)');
  8079. self.log('params');
  8080. self.log(params);
  8081. self.log('selectorParams');
  8082. self.log(selectorParams);
  8083. }
  8084. } /* else {
  8085. self.log('"on" function with selector undefined');
  8086. self.log('params');
  8087. self.log(params);
  8088. self.log('selectorParams');
  8089. self.log(selectorParams);
  8090. } */
  8091. for (var eventId in params) {
  8092. //var eventAction = params[eventId];
  8093. //$(selector).data('onData').action = eventAction;
  8094. /* if (eventId == 'thunkable') {
  8095. self.thunkable(params[eventId]);
  8096. } else */
  8097. if (eventId == 'init') {
  8098. //self.log(params.init);
  8099. //self.do(params.init, undefined, selectorParams);
  8100. self.do(params.init, selectorParams);
  8101. } else if (eventId == 'hashchange') {
  8102. self.onHashChange.push(params.hashchange);
  8103. window.addEventListener('hashchange', function () {
  8104. self.json.setup.page.hash = window.location.hash.substr(1); // potrebbe essere esplicitato sulla app
  8105. //var action = self.cloneObject(params.app.on.hashchange);
  8106. //self.replaceAll("{result}", window.location.hash);
  8107. //self.do(self.onHashChange);
  8108. self.do(self.onHashChange);
  8109. self.uiUpdate();
  8110. });
  8111. } else if (eventId == 'scroll') {
  8112. self.onScroll.push(params.scroll);
  8113. window.addEventListener('scroll', function () {
  8114. //self.do(self.onScroll);
  8115. self.do(self.onScroll);
  8116. });
  8117. } else if (eventId == 'resize') {
  8118. self.onResize.push(params.resize);
  8119. window.addEventListener('resize', function () {
  8120. //self.do(self.onResize);
  8121. self.do(self.onResize);
  8122. });
  8123. } else if (eventId == 'in') { // like inViewport but only one time
  8124. if (container) {
  8125. const observer = new IntersectionObserver((entries, observer) => {
  8126. entries.forEach(function (entry) {
  8127. /* self.log('entry');
  8128. self.log(entry);
  8129. self.log('entry.target');
  8130. self.log(entry.target); */
  8131. /* self.log(entry);
  8132. self.log(entry.intersectionRatio);
  8133. self.log(entry.isIntersecting);
  8134. self.log(entry.isVisible); */
  8135. // isIntersecting, isVisible
  8136. //var element = self.query(entry.target);
  8137. //self.log(entry.intersectionRatio);
  8138. if (entry.intersectionRatio == 1) { // .isIntersecting?
  8139. var el = entry.target;
  8140. if (el.getAttribute('in') !== 'true') {
  8141. el.setAttribute('in', 'true'); // change with dataStorage
  8142. self.onEvent(entry.target, { type: 'in' });
  8143. }
  8144. }
  8145. });
  8146. }, {
  8147. rootMargin: '0px',
  8148. threshold: [0, 1] // if 0.5 is the half-height of the elmement
  8149. });
  8150. //const element = self.query(container);
  8151. observer.observe(self.query(container));
  8152. }
  8153. } else if (eventId == 'inViewport') {
  8154. if (container) {
  8155. const observer = new IntersectionObserver((entries, observer) => {
  8156. entries.forEach(function (entry) {
  8157. /* self.log('entry');
  8158. self.log(entry);
  8159. self.log('entry.target');
  8160. self.log(entry.target); */
  8161. /*
  8162. self.log(entry.intersectionRatio);
  8163. self.log(entry.isIntersecting);
  8164. self.log(entry.isVisible); */
  8165. // isIntersecting, isVisible
  8166. //var element = self.query(entry.target);
  8167. //self.log(entry.intersectionRatio);
  8168. if (entry.intersectionRatio > 0) {
  8169. self.onEvent(entry.target, { type: 'inViewport' });
  8170. }
  8171. });
  8172. }, {
  8173. rootMargin: '0px',
  8174. threshold: [0, 1] // if 0.5 is the half-height of the elmement
  8175. });
  8176. //const element = self.query(container);
  8177. observer.observe(self.query(container));
  8178. }
  8179. } else if (eventId == 'outViewport') {
  8180. const observer = new IntersectionObserver((entries, observer) => {
  8181. entries.forEach(function (entry) {
  8182. /* self.log(entry);
  8183. self.log(entry.isIntersecting);
  8184. self.log(entry.isVisible); */
  8185. // isIntersecting, isVisible
  8186. //var element = self.query(entry.target);
  8187. //self.log(entry.intersectionRatio);
  8188. if (entry.intersectionRatio == 0) {
  8189. self.onEvent(entry.target, { type: 'outViewport' });
  8190. /* var el = entry.target;
  8191. if (el.getAttribute('in') == 'true') {
  8192. el.setAttribute('in', 'false');
  8193. self.onEvent(entry.target, {type: 'out'});
  8194. } */
  8195. }
  8196. });
  8197. }, {
  8198. rootMargin: '0px',
  8199. threshold: [0, 1] // if 0.5 is the half-height of the elmement
  8200. });
  8201. const element = self.query(container);
  8202. observer.observe(element);
  8203. } else if (eventId !== 'selector') {
  8204. /* if (container == '.nav-link[data-value="docs"]') {
  8205. alert(JSON.stringify(params));
  8206. //element = element[0];
  8207. $(element).hide();
  8208. } */
  8209. //element.removeEventListener(eventId);
  8210. // $(container).off(eventId);
  8211. if (element) {
  8212. // TO DO: verify
  8213. //if (element.getAttribute('listener') !== 'true') { // only one mouse event
  8214. //self.log('addEventListener: ' + eventId);
  8215. element.addEventListener(eventId, function (event) {
  8216. //$(container).off(eventId).on(eventId, function (event) {
  8217. /* self.log('event');
  8218. self.log(event); */
  8219. element.setAttribute('listener', 'true');
  8220. //event.preventDefault();
  8221. //event.stopPropagation();
  8222. self.onEvent(this, event);
  8223. });
  8224. //}
  8225. if (eventId == 'mousedown' || eventId == 'mouseup' || eventId == 'click')
  8226. element.style.cursor = 'pointer';
  8227. }
  8228. /* $(container).off(eventId).on(eventId, function (event) {
  8229. //$(container).off(eventId).on(eventId, function (event) {
  8230. self.log('event');
  8231. self.log(event);
  8232. event.preventDefault();
  8233. event.stopPropagation();
  8234. self.onEvent(this, event);
  8235. }); */
  8236. //$(container).css({cursor: 'pointer'});
  8237. }
  8238. }
  8239. };
  8240. /* this.addAction = function (params, selectorParams) {
  8241. var container = (selectorParams) ? self.selector(selectorParams) : params.container;
  8242. var selector = self.selector(self.extend({}, params, selectorParams));
  8243. $(selector).data('onData', params);
  8244. //$(selector).data('onData', {action: params.action, params: params.args});
  8245. $(selector).off().on(this.touch, function (event) {
  8246. event.stopPropagation();
  8247. self.onEvent(this, event);
  8248. });
  8249. $(selector).css({cursor: 'pointer'});
  8250. } */
  8251. /* this.ace = function (params) {
  8252. params.container = 'blockCode';
  8253. var editor = ace.edit("blockCode");
  8254. var langTools = ace.require('ace/ext/language_tools');
  8255. editor.setTheme("ace/theme/monokai"); // ambiance
  8256. editor.getSession().setMode("ace/mode/json");
  8257. //editor.renderer.setOption('showLineNumbers', false);
  8258. editor.container.style.background="rgba(255,255,255,0)";
  8259. var staticWordCompleter = {
  8260. getCompletions: function(editor, session, pos, prefix, callback) {
  8261. var wordList = ["app", "setup", "pages"];
  8262. callback(null, wordList.map(function(word) {
  8263. return {
  8264. caption: word,
  8265. value: word,
  8266. meta: "static"
  8267. };
  8268. }));
  8269. }
  8270. }
  8271. editor.completers = [staticWordCompleter];
  8272. // https://github.com/ajaxorg/ace/wiki/Configuring-Ace
  8273. editor.setOptions({
  8274. fontSize: "11pt",
  8275. selectionStyle: "text",
  8276. highlightActiveLine: true,
  8277. wrap: true,
  8278. showLineNumbers: false,
  8279. showGutter: false,
  8280. fixedWidthGutter: false,
  8281. readOnly: true,
  8282. //enableBasicAutocompletion: true,
  8283. //enableSnippets: true,
  8284. //enableLiveAutocompletion: true,
  8285. });
  8286. editor.setValue(var.code, -1);
  8287. } */
  8288. /* this.edit = function (item) {
  8289. //var.code = JSON.stringify(item, null, '\t');
  8290. self.do( {
  8291. "alert": {
  8292. "background": "rgba(255,255,255,0.9)",
  8293. "width": "93%",
  8294. "showCancelButton": true,
  8295. "cancelButtonText": 'Cancel',
  8296. "confirmButtonText": 'Save',
  8297. "html": '<div id="blockCode" align="left" style="background: transparent; margin: 0; width: 93%; height:86vh"></div>'
  8298. }
  8299. });
  8300. //self.code(JSON.stringify(item, null, '\t'),);
  8301. self.code(item, {container: '#blockCode'});
  8302. //setTimeout(function () {
  8303. //alert(var.blockCode);
  8304. // https://codepen.io/jjsjjja/pen/VoGYRB
  8305. //}, 100);
  8306. } */
  8307. this.money = function (value) {
  8308. /* if (value && value.indexOf(',') == -1 && value.indexOf('.') == -1) {
  8309. value = value + '.00';
  8310. } */
  8311. var rounded = Math.round(Number(value) * 100) / 100;
  8312. var string = String(rounded);
  8313. if (rounded == Math.floor(rounded))
  8314. string += ',00';
  8315. string = String(string).replace('.', ',');
  8316. return string;
  8317. };
  8318. this.offcanvas = function (params) {
  8319. self.log('offcanvas');
  8320. self.log('params');
  8321. self.log(params);
  8322. // https://getbootstrap.com/docs/5.0/components/offcanvas/
  8323. // to add: toggle, getInstance, getOrCreateInstance
  8324. var container = params.selector || params.container;
  8325. var selector = self.selector(container);
  8326. var element = self.query(selector);
  8327. self.log('offcanvas');
  8328. self.log(params);
  8329. self.log('selector');
  8330. self.log(selector);
  8331. self.log('element');
  8332. self.log(element);
  8333. // do: show (default) / hide (see boostrap Offcanvas docs)
  8334. if (element) {
  8335. if (params.do == 'hide') {
  8336. self.css({
  8337. removeClass: 'show'
  8338. }, params);
  8339. //new bootstrap.Offcanvas(element).hide(); // doesn't work
  8340. } else {
  8341. new bootstrap.Offcanvas(element).show();
  8342. }
  8343. } else {
  8344. self.log('"offcanvas" method can\'t find the selected element');
  8345. }
  8346. };
  8347. /**
  8348. * Converts a DOM element to its CSS selector string representation
  8349. * @param {HTMLElement} element - The DOM element to convert
  8350. * @returns {string} The CSS selector string that uniquely identifies the element
  8351. */
  8352. this.elementToSelector = function (element) {
  8353. // 1. Use ID if available
  8354. if (element.id) {
  8355. return '#' + element.id;
  8356. }
  8357. // 2. Use data-value if unique
  8358. if (element.dataset?.value) {
  8359. const sameDataValue = document.querySelectorAll(`[data-value="${element.dataset.value}"]`);
  8360. if (sameDataValue.length === 1) {
  8361. return `[data-value="${element.dataset.value}"]`;
  8362. }
  8363. }
  8364. // 3. Use class if unique
  8365. if (element.classList && element.classList.length > 0) {
  8366. for (const className of element.classList) {
  8367. if (className) {
  8368. const sameClass = document.querySelectorAll('.' + className);
  8369. if (sameClass.length === 1) {
  8370. return '.' + className;
  8371. }
  8372. }
  8373. }
  8374. }
  8375. // 4. Use tag if unique
  8376. const tagName = element.tagName.toLowerCase();
  8377. const sameTag = document.querySelectorAll(tagName);
  8378. if (sameTag.length === 1) {
  8379. return tagName;
  8380. }
  8381. // 5. Fallback to tag + nth-child path
  8382. let path = [];
  8383. while (element.parentNode) {
  8384. let selector = element.tagName.toLowerCase();
  8385. const index = Array.from(element.parentNode.children).indexOf(element) + 1;
  8386. selector += `:nth-child(${index})`;
  8387. path.unshift(selector);
  8388. element = element.parentNode;
  8389. }
  8390. return path.join(' > ');
  8391. };
  8392. this.onEvent = function (element, event) {
  8393. //self.log('element');
  8394. //self.log(element);
  8395. /* self.log('event');
  8396. self.log(event); */
  8397. /* if (event) {
  8398. event.preventDefault(); // verify
  8399. event.stopPropagation();
  8400. } */
  8401. /* var item = {};
  8402. if (self.dataStorage.has(element, 'onData'))
  8403. item = self.dataStorage.get(element, 'onData'); */
  8404. var item = self.dataStorage.get(element, 'onData');
  8405. var code = self.dataStorage.get(element, 'code') || '';
  8406. //var item = $(element).data('onData');
  8407. //var code = $(element).data('code');
  8408. //var value = String($(element).data('value'));
  8409. //var selector = $(element).data('selector');
  8410. //var value = String(self.dataStorage.get(element, 'value'));
  8411. var value = element.getAttribute('data-value');
  8412. //var selector = element.getAttribute('data-selector');
  8413. var selector = self.elementToSelector(element); // 1.0.12
  8414. /* self.log('value');
  8415. self.log(value);
  8416. self.log('args');
  8417. self.log(args); */
  8418. var eventType = (event.type && item.on) ? item.on[event.type] : undefined;
  8419. /* self.log('onEvent');
  8420. self.log('item');
  8421. self.log(item);
  8422. self.log('selector');
  8423. self.log(selector);
  8424. self.log('event.type');
  8425. self.log(event.type); */
  8426. /*
  8427. if (event) {
  8428. args = {
  8429. value: value,
  8430. event: eventType
  8431. }
  8432. }
  8433. */
  8434. /* self.log('event.type');
  8435. self.log(event.type);
  8436. self.log('event');
  8437. self.log(event); */
  8438. var action, specialKey;
  8439. if (item.on) {
  8440. if (event.button == '2' && event.type == 'mousedown') { // right click / long touch
  8441. if (item.on['contextmenu'])
  8442. action = item.on['contextmenu'];
  8443. } else if (event.type && item.on[event.type]) {
  8444. var eventAction = item.on[event.type];
  8445. //const specialKeys = ['shiftKey', 'altKey', 'cmdKey'];
  8446. if (eventAction) {
  8447. if (eventAction.shiftKey && event.shiftKey) {
  8448. specialKey = 'shiftKey';
  8449. action = eventAction.shiftKey;
  8450. } else if (eventAction.altKey && event.altKey) {
  8451. specialKey = 'altKey';
  8452. action = eventAction.altKey;
  8453. } else if (eventAction.cmdKey && event.cmdKey) {
  8454. specialKey = 'cmdKey';
  8455. action = eventAction.cmdKey;
  8456. } else if (!eventAction.shiftKey && !eventAction.altKey && !eventAction.cmdKey) {
  8457. action = item.on[event.type];
  8458. }
  8459. }
  8460. }
  8461. }
  8462. if (action) {
  8463. //console.dir(action);
  8464. //action = self.replaceProperty(action, '{on:target}', targetId);
  8465. if (event.target) {
  8466. //self.log(event);
  8467. var actionString;
  8468. var targetId = event.target.id;
  8469. var targetClass = event.target.className;
  8470. var targetValue = event.target.dataset.value;
  8471. var targetSelector = event.target.dataset.selector; // deprecated
  8472. /* self.log('event');
  8473. self.log(event); */
  8474. //if (targetValue) alert(targetValue);
  8475. targetSelector = self.replaceAll(targetSelector, '"', '\''); // TO DO: if JSON5?
  8476. action = self.stringify(action);
  8477. if (typeof targetId !== 'string') targetId = '';
  8478. if (typeof targetClass !== 'string') targetClass = '';
  8479. /* actionString = self.replaceAll(action, '{event.target.id}', targetId);
  8480. actionString = self.replaceAll(actionString, '{event.altKey}', event.altKey);
  8481. actionString = self.replaceAll(actionString, '{event.target.className}', targetClass);
  8482. actionString = self.replaceAll(actionString, '{event.target.data-value}', targetValue); // obsolete
  8483. actionString = self.replaceAll(actionString, '{event.target.dataset.value}', targetValue);
  8484. actionString = self.replaceAll(actionString, '{event.target.dataset.selector}', targetSelector); */
  8485. actionString = self.replaceAll(action, '{on:target.id}', targetId);
  8486. actionString = self.replaceAll(actionString, '{on:altKey}', event.altKey);
  8487. actionString = self.replaceAll(actionString, '{on:target.className}', targetClass);
  8488. actionString = self.replaceAll(actionString, '{on:target.data-value}', targetValue); // obsolete
  8489. actionString = self.replaceAll(actionString, '{on:target.dataset.value}', targetValue);
  8490. actionString = self.replaceAll(actionString, '{on:target.dataset.selector}', targetSelector); // deprecated
  8491. actionString = self.replaceAll(actionString, '{on:which}', event.which);
  8492. actionString = self.replaceAll(actionString, '{on:clientY}', event.clientY);
  8493. actionString = self.replaceAll(actionString, '{on:clientX}', event.clientX);
  8494. // custom
  8495. actionString = self.replaceAll(actionString, '{on:value}', targetValue);
  8496. actionString = self.replaceAll(actionString, '{on:dragging}', (event.which > 0));
  8497. //actionString = self.replaceProperty(actionString, 'on', event);
  8498. if (this.isJson(actionString))
  8499. action = self.parse(actionString);
  8500. else
  8501. action = actionString;
  8502. }
  8503. // TODO: let decide to the user the parameter to pass
  8504. var args = item.args; // || item.params || item.value || value;
  8505. //args.event = event;
  8506. //if (args)
  8507. // action = self.replaceResult(action, args);
  8508. let specialKeyLog = (specialKey) ? ' + ' + specialKey : '';
  8509. //self.log('event ' + event.type + specialKeyLog);
  8510. //self.log('action');
  8511. //self.log(action);
  8512. /* self.log('args');
  8513. self.log(args);
  8514. self.log('{container: selector}');
  8515. self.log({container: selector}); */
  8516. //self.do(action, args, {selector: selector}); // TO DO: only if mouse over or
  8517. self.do(action, { selector: selector }, args);
  8518. } // (action)
  8519. };
  8520. this.pluginsFunctionAvailable = []; // should use pluginsLoaded
  8521. self.pluginsLoader = function (packs, callback, params) {
  8522. /* self.log('pluginsLoader');
  8523. self.log('packs');
  8524. self.log(packs);
  8525. self.log('callback');
  8526. self.log(callback);
  8527. self.log('params');
  8528. self.log(params); */
  8529. //self.pluginsFunctionAvailable.push(name); // posizione giusta
  8530. var filesToLoad = [];
  8531. for (pack of packs) {
  8532. /* self.log('pack');
  8533. self.log(pack); */
  8534. if (self.pluginsLoaded[pack.name] == undefined) {
  8535. self.log('require plugin ' + pack.name, 'grey');
  8536. var plugin = self.findPlugin(pack.name);
  8537. let version;
  8538. var pluginsFiles;
  8539. if (plugin) {
  8540. pluginsFiles = plugin.files || plugin;
  8541. version = plugin.version;
  8542. } else {
  8543. pluginsFiles = self.json.resources.pluginsFiles[pack.name]; // TO DO: obsolete, remove
  8544. version = pack.version;
  8545. }
  8546. /* if (params) {
  8547. if (!Array.isArray(params[0])) params[0] = [params[0]];
  8548. if (!self.pluginsCallbacks[pack.name]) self.pluginsCallbacks[pack.name] = [];
  8549. self.pluginsCallbacks[pack.name].concat(params[0]);
  8550. } */
  8551. self.pluginsLoaded[pack.name] = version; // should contain the queue of actions to do after the plugin loads
  8552. // TO DO: move in Promise.all(promises).then(function() {
  8553. // it needs to feed a queue of actions to do after the plugin loads
  8554. if (!Array.isArray(pluginsFiles)) // multi-file plugin
  8555. pluginsFiles = [pluginsFiles];
  8556. /* self.log('pluginsFiles');
  8557. self.log(pluginsFiles); */
  8558. for (item of pluginsFiles) {
  8559. var url = self.replaceAll(item.url, '{version}', version);
  8560. if (!self.findUrl(filesToLoad, url)) // not included yet
  8561. filesToLoad.push({ name: item.name, url: url, type: item.type });
  8562. }
  8563. }
  8564. }
  8565. //self.log(filesToLoad);
  8566. if (filesToLoad.length > 0) {
  8567. let promises = [];
  8568. filesToLoad.forEach(function (item) {
  8569. promises.push(loadPlugin({ name: item.name, url: item.url, type: item.type, rel: item.rel, as: item.as, content: item.content }));
  8570. //promises.push(loadPlugin(url));
  8571. });
  8572. Promise.all(promises).then(function (files) {
  8573. // all filesToLoad are loaded (all the Promise in loadPlugin are solved)
  8574. /* self.log('all plugin files are loaded');
  8575. self.log(files);
  8576. self.log(params); */
  8577. callback(...params); // change with ...
  8578. //callback(params[0], params[1], params[2]); // change with ...
  8579. }).catch(function (script) {
  8580. self.log('failed to load error');
  8581. self.log(item);
  8582. self.log(script);
  8583. });
  8584. }
  8585. };
  8586. this.pluginsRequired = function (params) {
  8587. /* self.log('pluginsRequired');
  8588. self.log(params); */
  8589. // analize function object or array of objects
  8590. if (self.json.resources) {
  8591. const pluginsFunctions = self.json.resources.pluginsFunctions;
  8592. var pluginsRequired = [];
  8593. if (typeof params == 'string') {
  8594. /* self.log('params');
  8595. self.log(params); */
  8596. if (pluginsFunctions[params]) {
  8597. if (!self.pluginsLoaded[pluginsFunctions[params].name])
  8598. pluginsRequired.push(pluginsFunctions[params]);
  8599. }
  8600. } else if (typeof params == 'object') {
  8601. var objArray;
  8602. if (Array.isArray(params)) objArray = params; else objArray = [params];
  8603. /* self.log('objArray');
  8604. self.log(objArray); */
  8605. for (var obj of objArray) {
  8606. /* self.log('obj');
  8607. self.log(obj); */
  8608. for (var key in obj) {
  8609. var mainFunction = (key.indexOf('.') >= 0) ? key.substr(0, key.indexOf('.')) : key;
  8610. //self.log('mainFunction');
  8611. //self.log(mainFunction);
  8612. if (pluginsFunctions[mainFunction]) {
  8613. if (!self.pluginsLoaded[pluginsFunctions[mainFunction].name])
  8614. pluginsRequired.push(pluginsFunctions[mainFunction]);
  8615. } /* else if (key == 'var') {
  8616. const functionName = self.functionName(obj.var.value);
  8617. if (functionName) {
  8618. if (!self.pluginsLoaded[pluginsFunctions[functionName].name])
  8619. pluginsRequired.push(pluginsFunctions[functionName]);
  8620. }
  8621. } */
  8622. }
  8623. }
  8624. }
  8625. return pluginsRequired;
  8626. } else {
  8627. return [];
  8628. }
  8629. };
  8630. this.functionName = function (obj) {
  8631. if (obj == 'object') {
  8632. const name = Object.keys(obj)[0];
  8633. const pluginFunctions = ['database', 'ace', 'moment', 'dayjs'];
  8634. if (pluginFunctions.indexOf(name) >= 0)
  8635. return name;
  8636. }
  8637. };
  8638. /*
  8639. this.runParts = function (actionObj, container, argumentsPar, handleOtherActions) {
  8640. console.log('runParts');
  8641. console.log(actionObj);
  8642. if (Array.isArray(actionObj)) {
  8643. for (var action in actionObj)
  8644. self.runParts(action);
  8645. } else {
  8646. var otherMethods = false;
  8647. var otherActions = {};
  8648. for (var partKey in actionObj) {
  8649. if (partKey.startsWith('var ') || partKey.startsWith('data ') || partKey.startsWith('set '))
  8650. self.setData({path: partKey, value: actionObj[partKey]});
  8651. else {
  8652. var methodOrPart = false;
  8653. var method = self.element({path: partKey, root: self.methods});
  8654. if (method) { // search in jsonic.methods
  8655. methodOrPart = true;
  8656. if (typeof method == 'function') {
  8657. //self.docElement(actionObj[partKey]);
  8658. self.log('method: ' + partKey);
  8659. method(actionObj[partKey], container, argumentsPar);
  8660. }
  8661. } else if (self.json.parts) { // search in self.json.parts
  8662. var part = self.element({path: 'parts.'+self.replaceAll(partKey,':','.')});
  8663. if (part) {
  8664. part = self.replaceProperty(part, 'arg', actionObj[partKey]);
  8665. if (actionObj[partKey].setup)
  8666. part = self.replaceProperty(part, 'setup', actionObj[partKey].setup);
  8667. console.log('part');
  8668. console.log(part);
  8669. self.run(part, container);
  8670. methodOrPart = true; // if (!actionFound) { will go in the else (!part)
  8671. }
  8672. }
  8673. if (!methodOrPart) otherActions[partKey] = actionObj[partKey];
  8674. else otherMethods = true;
  8675. }
  8676. }
  8677. //if (handleOtherActions) handleOtherActions(otherActions, container, argumentsPar);
  8678. return otherMethods;
  8679. }
  8680. }
  8681. */
  8682. /* this.jsonicMethods = function (actions, container, argumentsPar) {
  8683. // 'icons' should be removed from the json files
  8684. var withContainer;
  8685. var functionFound = false;
  8686. for (var actionKey in actions) {
  8687. //if (nodes.functions.indexOf(actionKey) >= 0) {
  8688. switch (actionKey) {
  8689. case 'for':
  8690. case 'editor':
  8691. case 'ace':
  8692. case 'code':
  8693. case 'qrcode':
  8694. case 'lottie':
  8695. case 'animate':
  8696. case 'html':
  8697. case 'hide':
  8698. case 'show':
  8699. case 'toggle':
  8700. case 'in':
  8701. case 'out':
  8702. case 'if':
  8703. case 'ajax':
  8704. case 'attr':
  8705. case 'run':
  8706. case 'delay':
  8707. case 'css': withContainer = true; break;
  8708. default: withContainer = false;
  8709. }
  8710. var functionObj = actions[actionKey];
  8711. if (functionObj) {
  8712. functionFound = true;
  8713. if ((functionObj.if == undefined) || self.if(functionObj.if, container, argumentsPar)) {
  8714. return self.doFunction({
  8715. name: nodes.functions[actionKey],
  8716. function: functionObj,
  8717. args: argumentsPar,
  8718. selector: container,
  8719. withContainer: withContainer
  8720. });
  8721. } else {
  8722. if (functionObj.if !== undefined) {
  8723. self.log(self.js(functionObj.if, argumentsPar));
  8724. }
  8725. }
  8726. } else if (nodes.params.indexOf(actionKey) < 0)
  8727. return self.method(actions[actionKey], argumentsPar);
  8728. }
  8729. } */
  8730. /* this.do = function (actionPar, argumentsPar, selectorParams) { // ex this.action
  8731. if (actionPar !== undefined && actionPar !== null) { // !== undefined
  8732. // check plugins required
  8733. let pluginsRequired = self.pluginsRequired(actionPar);
  8734. if (pluginsRequired.length > 0) {
  8735. let params = [actionPar, argumentsPar, selectorParams];
  8736. self.pluginsLoader(pluginsRequired, self.do, params);
  8737. } else {
  8738. if (Array.isArray(actionPar)) {
  8739. if (actionPar.length > 0) {
  8740. var actionArray = [];
  8741. for (var index in actionPar)
  8742. if (typeof actionPar[index] == 'object')
  8743. actionArray[index] = self.cloneObject(actionPar[index]);
  8744. else
  8745. actionArray[index] = actionPar[index];
  8746. //actionArray = actionArray.concat(actionPar);
  8747. //actionArray = self.cloneObject(actionPar);
  8748. var actionFunction = actionArray.shift();
  8749. self.do(actionFunction, argumentsPar, selectorParams);
  8750. if (actionArray.length > 0)
  8751. self.do(actionArray, argumentsPar, selectorParams);
  8752. }
  8753. } else {
  8754. if (typeof actionPar == 'function') {
  8755. return actionPar(argumentsPar);
  8756. } else if (typeof actionPar == 'string') {
  8757. var actionPart = self.element({path: 'parts.' + actionPar}); // it includes replaceProperties
  8758. self.log('actionPar stringa');
  8759. self.log(actionPar);
  8760. if (actionPart)
  8761. return self.do(actionPart, argumentsPar);
  8762. //else if (json.actions[actionPar]) // obsolete
  8763. // return self.do(json.actions[actionPar], argumentsPar);
  8764. else
  8765. return actionPar; //return self.js(actionPar); // TO DO: finisce qui anche una stringa di un tag p ("p": "string")
  8766. } else if (typeof actionPar == "object") {
  8767. var actionObj = actionPar;
  8768. var container = actionObj.selector || actionObj.container || selectorParams;
  8769. // events
  8770. if (actionObj.on) {self.on(actionObj.on, container);}
  8771. if (self.notEmptyObject(actionObj)) {
  8772. var actionFound = self.runParts(actionObj, container, argumentsPar, self.jsonicMethods);
  8773. if (!actionFound) {
  8774. var functionFound = false;
  8775. for (var index in nodes.functions) {
  8776. //if (nodes.params.indexOf(actionKey) < 0)
  8777. //var action = Object.keys(actionObj)[0];
  8778. var withContainer = (nodes.functionsWithContainer.indexOf(nodes.functions[index]) >=0 );
  8779. var functionObj = actionObj[nodes.functions[index]];
  8780. if (functionObj) {
  8781. functionFound = true;
  8782. if ((functionObj.if == undefined) || self.if(functionObj.if, container, argumentsPar)) {
  8783. //if ((functionObj.if == undefined) || Boolean(self.js(functionObj.if, argumentsPar))) {
  8784. return self.doFunction({
  8785. name: nodes.functions[index],
  8786. function: functionObj,
  8787. args: argumentsPar,
  8788. selector: selectorParams,
  8789. withContainer: withContainer
  8790. });
  8791. } else {
  8792. if (functionObj.if !== undefined) {
  8793. self.log(self.js(functionObj.if, argumentsPar));
  8794. }
  8795. }
  8796. }
  8797. }
  8798. if (!functionFound) {
  8799. self.log('actionPar');
  8800. self.log(actionPar);
  8801. self.log('!functionFound');
  8802. self.log(actionObj);
  8803. return self.method(actionObj, argumentsPar);
  8804. }
  8805. }
  8806. }
  8807. } else {
  8808. //self.log('Function not found');
  8809. //self.log(actionPar);
  8810. //self.log(argumentsPar);
  8811. return actionPar;
  8812. // functions from this.do
  8813. //actionPar(argumentsPar);
  8814. }
  8815. }
  8816. }
  8817. } else {
  8818. // TO DO: check
  8819. //self.log('function with actionPar undefined');
  8820. }
  8821. }
  8822. */
  8823. /* this.jsonicMethod2 = function (actionObj, selectorParams, argumentsPar) {
  8824. var functionFound = false;
  8825. for (var action in actionObj) {
  8826. var functionObj = actionObj[action];
  8827. if (functionObj) {
  8828. var withContainer = (nodes.functionsWithContainer.indexOf(action) >=0 );
  8829. functionFound = true;
  8830. if ((functionObj.if == undefined) || Boolean(self.js(functionObj.if, argumentsPar))) {
  8831. return self.doFunction({
  8832. name: action,
  8833. function: functionObj,
  8834. args: argumentsPar,
  8835. selector: selectorParams,
  8836. withContainer: withContainer
  8837. });
  8838. }
  8839. }
  8840. if (!functionFound) {
  8841. self.log('!functionFound');
  8842. self.log('actionObj');
  8843. self.log(actionObj);
  8844. return self.method(actionObj, argumentsPar);
  8845. }
  8846. }
  8847. } */
  8848. this.for = function (params, selectorParams, args) {
  8849. /* self.log('for');
  8850. self.log(params); */
  8851. let container = self.selector(params.selector || params.container) || self.selector(selectorParams);
  8852. // TO DO: doesn't go as an automous function (needs to be inside a div)
  8853. /* self.log('for');
  8854. self.log('container');
  8855. self.log(container); */
  8856. //if (params.html) { // new version
  8857. let itemsName = params.id || params.name;
  8858. //self.log('itemsArray');
  8859. //self.log(itemsArray);
  8860. /* if (params.reverse) {
  8861. var itemsReversed = {};
  8862. for (var key in Object(itemsArray).keys().reverse()) {
  8863. itemsReversed[key] = itemsArray[key];
  8864. }
  8865. itemsArray = itemsReversed;
  8866. } */
  8867. if (params.of) {
  8868. //var itemsArray = self.cloneObject(params.of); // value is the previous array id
  8869. //if (typeof itemsArray == 'string')
  8870. //itemsArray = self.compile(itemsArray, args); // compile includes functions and create bugs
  8871. //self.log('params.of');
  8872. //self.log(params.of);
  8873. var itemsArray = self.replaceProperties(params.of, args);
  8874. /* self.log('itemsArray');
  8875. self.log(itemsArray); */
  8876. /* if (typeof itemsArray == 'string') {
  8877. itemsArray = self.js(itemsArray); // TO DO: check
  8878. } */
  8879. if (itemsArray) {
  8880. /* if (typeof itemsArray == 'string') {
  8881. if (itemsArray.startsWith('js:')) itemsArray = self.js(itemsArray.substr(3));
  8882. //else itemsArray = self.replaceProperties(itemsArray, args);
  8883. } */
  8884. /* else {
  8885. itemsArray = self.actionResult(itemsArray, args);
  8886. itemsArray = self.replaceProperties(itemsArray, args);
  8887. } */
  8888. /* self.log('itemsArray replaced');
  8889. self.log(itemsArray); */
  8890. /* self.log('for'); */
  8891. /* self.log(itemsName); */
  8892. /* self.log(itemsArray); */
  8893. if (params.html) { // 1.0.6 html in for is deprecated
  8894. if (!params.do) params.do = [];
  8895. else if (!Array.isArray(params.do)) params.do = [params.do];
  8896. params.do.push({ html: params.html });
  8897. }
  8898. //delete params; // needed to avoid infinite loop
  8899. if (typeof itemsArray == 'object') {
  8900. let indexNum = 0;
  8901. for (var index in itemsArray) {
  8902. var item = itemsArray[index];
  8903. if (typeof item == 'object') {
  8904. item.key = index; // obsolete
  8905. item.index = index; // obsolete
  8906. }
  8907. if (typeof item.output == 'object') { // TO DO: obsolete
  8908. /* self.log('item.for.output');
  8909. self.log(item.for.output); */
  8910. for (let key in item.output) {
  8911. var output = item.output[key];
  8912. if (typeof output == 'string') {
  8913. output = self.js(output, args);
  8914. } else if (typeof output == 'object') {
  8915. //output = self.compile(output, args);
  8916. output = self.replaceProperties(output, args);
  8917. }
  8918. item = self.replaceItems(item, output, key); // replace
  8919. //item = self.replaceProperty(item, key, output);
  8920. }
  8921. }
  8922. if (params.do.length > 0) {
  8923. //alert(JSON.stringify(params.do));
  8924. //self.do(self.replaceProperty(params.do, itemsName, item), undefined, {selector: container});
  8925. //let objWithIndex = self.replaceStringInObject(params.do, '{' + params.index + '}', index);
  8926. let objWithIndex = params.do;
  8927. if (params.var) { // TO DO: obsolete (remove when used)
  8928. self.element({ path: params.var, value: item, root: self.json.var });
  8929. objWithIndex = self.replacePropertyWithPrefix(objWithIndex, 'index:' + params.var, index);
  8930. //objWithIndex = self.replaceStringInObject(objWithIndex, '{index:'+params.var+'}', index);
  8931. }
  8932. if (itemsName) {
  8933. //objWithIndex = self.replaceStringInObject(objWithIndex, '{index:'+itemsName+'}', index);
  8934. objWithIndex = self.replacePropertyWithPrefix(objWithIndex, 'index:' + itemsName, index);
  8935. objWithIndex = self.replacePropertyWithPrefix(objWithIndex, itemsName, item);
  8936. //objWithIndex = self.replaceProperty(objWithIndex, 'value:'+itemsName, item);
  8937. //objWithIndex = self.replaceProperty(objWithIndex, itemsName, item); // obsolete
  8938. }
  8939. if (params.delay) {
  8940. params.delay = self.replaceProperties(params.delay);
  8941. let forId = params.var || itemsName;
  8942. self.timer({
  8943. name: 't' + forId + index,
  8944. after: indexNum * params.delay,
  8945. do: objWithIndex
  8946. });
  8947. } else {
  8948. self.do(objWithIndex, { selector: container });
  8949. }
  8950. }
  8951. /* if (params.html) { // should be inside a do // commented from 1.0.6
  8952. let indexName = params.index || 'index';
  8953. let objWithIndex = self.replaceStringInObject(params.html, '{'+indexName+':'+itemsName+'}', index);
  8954. objWithIndex = self.replaceProperty(objWithIndex, itemsName, item);
  8955. self.do(objWithIndex, {selector: container});
  8956. } */
  8957. indexNum += 1;
  8958. }
  8959. }
  8960. }
  8961. } else if (params.from !== undefined && params.to !== undefined) {
  8962. /* var step = Number(params.step) || 1;
  8963. var from = Number(params.from) || 0;
  8964. var to = Number(params.to); */
  8965. var step = self.js(self.replaceProperties(params.step)) || 1;
  8966. var from = self.js(self.replaceProperties(params.from)) || 0;
  8967. var to = self.js(self.replaceProperties(params.to));
  8968. /* var step = Number(self.replaceProperties(params.step)) || 1;
  8969. var from = Number(self.replaceProperties(params.from)) || 0;
  8970. var to = Number(self.replaceProperties(params.to)); */
  8971. /* self.log('from');
  8972. self.log(from);
  8973. self.log('to');
  8974. self.log(to);
  8975. self.log('step');
  8976. self.log(step); */
  8977. if (to !== undefined) {
  8978. for (var index = Number(from); index <= Number(to); index += Number(step)) {
  8979. if (params.var)
  8980. self.element({ path: params.var, value: index, root: self.json.var });
  8981. // TO DO: find "if (params.html) { // 1.0.6" and modify also the following code
  8982. var item = self.replaceItems(params, String(index), itemsName); // obsolete: replaced with {index:itemsName}
  8983. //var item = self.replaceProperty(params, itemsName, String(index));
  8984. /* self.log('itemsName');
  8985. self.log(itemsName);
  8986. self.log('index');
  8987. self.log(index);
  8988. self.log('item');
  8989. self.log(item); */
  8990. if (item.output && typeof item.output == 'object') { //} !== undefined) {
  8991. /* self.log('item.for.output');
  8992. self.log(item.for.output); */
  8993. for (let key in item.output) {
  8994. var output = item.output[key];
  8995. if (typeof output == 'string') {
  8996. output = self.js(output, args);
  8997. } else if (typeof output == 'object') {
  8998. //output = self.compile(output, args);
  8999. output = self.replaceProperties(output, args);
  9000. }
  9001. item = self.replaceItems(item, output, key);
  9002. //item = self.replaceProperty(item, key, output);
  9003. }
  9004. }
  9005. // item = self.replaceItems(item, itemValue, itemsName); old version
  9006. //delete item.for; // needed to avoid infinite loop
  9007. if (item.do) {
  9008. params.do = self.replacePropertyWithPrefix(item.do, 'index:' + itemsName, index);
  9009. //params.do = self.replaceStringInObject(item.do, '{index:'+itemsName+'}', index);
  9010. self.do(item.do, selectorParams, args); // return?
  9011. //self.do(item.do, args, selectorParams); // return?
  9012. }
  9013. if (item.html) {
  9014. //params.html = self.replaceStringInObject(item.html, '{index:'+itemsName+'}', index);
  9015. params.html = self.replacePropertyWithPrefix(item.html, 'index:' + itemsName, index);
  9016. self.html(item.html, selectorParams);
  9017. }
  9018. }
  9019. }
  9020. } else {
  9021. self.log('"for" element requires "value" or "from" and "to" parameters'); // link to see the documentation
  9022. self.log(params);
  9023. }
  9024. //}
  9025. // }
  9026. };
  9027. this.htmlTag = function (params, selectorParams, tagParam, mainParam) {
  9028. /* self.log('htmlTag');
  9029. self.log(tagParam); */
  9030. if (Array.isArray(params)) {
  9031. for (var index in params)
  9032. self.htmlTag(params[index], selectorParams, tagParam, mainParam);
  9033. } else {
  9034. //----------------------------------
  9035. // attributes of the tag in the key
  9036. // example: "div id=btn btn"
  9037. // (classes are without identifier)
  9038. //----------------------------------
  9039. let htmlTagSplitter = tagParam.indexOf(' ');
  9040. if (htmlTagSplitter > 0) {
  9041. let tagClass = tagParam.substr(htmlTagSplitter + 1);
  9042. tagParam = tagParam.slice(0, htmlTagSplitter);
  9043. if (tagClass) {
  9044. if (typeof params !== 'object') params = { 'text': String(params) };
  9045. if (!params.attr) params.attr = {};
  9046. // attributes in key: attribute=value
  9047. let tagArr = tagClass.split(' ');
  9048. var attrClass = '';
  9049. for (let tagProp of tagArr) {
  9050. let tagAttr = new RegExp("([_a-zA-Z]+[_a-zA-Z0-9-]*)=(.+)"); // [_a-zA-Z0-9-/]
  9051. if (tagAttr.test(tagProp)) {
  9052. //console.log('attribute found '+tagProp);
  9053. let tagPropArr = tagProp.split('=');
  9054. params.attr[tagPropArr[0]] = tagPropArr[1];
  9055. } else {
  9056. attrClass += ' ' + tagProp;
  9057. }
  9058. }
  9059. // classes
  9060. if (params.attr.class)
  9061. params.attr.class = params.attr.class + attrClass;
  9062. else {
  9063. params.attr.class = attrClass;
  9064. }
  9065. //alert(tagParam + '/'+ tagClass+ '#');
  9066. }
  9067. }
  9068. let htmlTagObj = self.createTagParams(params, tagParam, mainParam);
  9069. self.do(htmlTagObj, selectorParams);
  9070. if (params.database) self.addFirebaseTag(self.extend({}, params, selectorParams));
  9071. }
  9072. };
  9073. this.createTagParams = function (params, tagParam, mainParam) {
  9074. if (!mainParam) {
  9075. switch (tagParam) {
  9076. case 'header':
  9077. case 'main':
  9078. case 'footer':
  9079. case 'div':
  9080. case 'p':
  9081. mainParam = 'html';
  9082. break;
  9083. case 'img':
  9084. mainParam = 'src';
  9085. break;
  9086. default:
  9087. mainParam = 'text'; // TO DO: -> html (to test with actual apps)
  9088. break;
  9089. }
  9090. }
  9091. var paramsObj = {};
  9092. if (typeof params == 'string') paramsObj[mainParam] = params; else paramsObj = params;
  9093. paramsObj.tag = tagParam;
  9094. return paramsObj;
  9095. };
  9096. this.onResize = [];
  9097. this.onHashChange = [];
  9098. this.onScroll = [];
  9099. //let swup;
  9100. this.notEmptyObject = function (obj) {
  9101. return (obj // null and undefined check
  9102. && Object.keys(obj).length > 0);
  9103. // && Object.getPrototypeOf(obj) === Object.prototype
  9104. // https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object
  9105. };
  9106. this.run = function (params, selectorParams, args) {
  9107. /* self.log('run');
  9108. self.log(params); */
  9109. if (Array.isArray(params)) {
  9110. for (var index in params)
  9111. self.run(params[index], selectorParams, args);
  9112. } else {
  9113. var codeToRun;
  9114. if (typeof params == 'object')
  9115. codeToRun = self.cloneObject(params);
  9116. else if (typeof params == 'string')
  9117. codeToRun = self.replaceProperties(params);
  9118. else if (typeof params == 'function')
  9119. return params(args);
  9120. else
  9121. return params;
  9122. /* self.log('codeToRun');
  9123. self.log(codeToRun); */
  9124. if (typeof codeToRun == 'object') {
  9125. var selector = codeToRun.selector || codeToRun.container;
  9126. if (!selector) selector = selectorParams;
  9127. if (typeof selector == 'string') selector = { selector: selector };
  9128. var actions = {};
  9129. for (key in codeToRun) {
  9130. if (nodes.extend.indexOf(key) >= 0) {
  9131. var obj = {};
  9132. obj[key] = codeToRun[key];
  9133. self.extendJson(self.json, obj);
  9134. } else if (['setup', 'container', 'selector', 'resources', 'on', 'do'].indexOf(key) < 0)
  9135. actions[key] = codeToRun[key];
  9136. }
  9137. /* self.log('codeToRun.on');
  9138. self.log(codeToRun.on);
  9139. self.log('selector');
  9140. self.log(selector); */
  9141. // actions
  9142. //if (codeToRun.container) {self.empty(codeToRun.container);} // reset
  9143. // .in SIGNIFICA CONTENITORE (select)
  9144. if (codeToRun.on) { self.on(codeToRun.on, selector); }
  9145. if (codeToRun.do) { self.do(codeToRun.do, selector, args); }
  9146. if (self.notEmptyObject(actions)) {
  9147. /* self.log('notEmptyObject actions');
  9148. self.log(actions);
  9149. self.log('selector');
  9150. self.log(selector); */
  9151. return self.do(actions, selector, args);
  9152. //return self.do(actions, args, codeToRun.in);
  9153. }
  9154. }
  9155. }
  9156. //self.extendJsonFromElement(codeToRun); // style, actions, texts, data, var. no setup, on, do, blocks, container
  9157. };
  9158. /*
  9159. this.execute = function (params, selectorParams, args) { // obsolete
  9160. // should create a new jsonicApp instance and assign it to jsonic[id]
  9161. // jsonicApp should load the plugins required and not are already loaded
  9162. // jsonicApp should import the json not already imported
  9163. // jsonicApp should load the icons not already loaded
  9164. // jsonicApp should init the database if not already initialized
  9165. // otherwise should copy the db object from window.jsonic?
  9166. // to have app relative var and data these should be called as var:clock.... / var:calendar....
  9167. // or each app should have an ID (without id the ID is "app")
  9168. // to have exclusive setup, var, data/items, pages and to reset var on the second execution
  9169. // for example: window.jsonic['container'] = new jsonicObject(options);
  9170. self.log('execute');
  9171. if (params) {
  9172. if (params.do == 'init') {
  9173. self.log('init');
  9174. window.removeEventListener('hashchange');
  9175. window.removeEventListener('resize');
  9176. window.removeEventListener('beforeinstallprompt');
  9177. // PWA
  9178. if ('serviceWorker' in navigator) {
  9179. // Register a service worker hosted at the root of the
  9180. // site using the default scope.
  9181. navigator.serviceWorker.register('/app/assets/pwa/sw.js').then(function(registration) {
  9182. self.log('Service worker registration succeeded:', registration);
  9183. }, function(error) {
  9184. self.log('Service worker registration failed:', error);
  9185. });
  9186. } else {
  9187. self.log('Service workers are not supported.');
  9188. }
  9189. let deferredPrompt;
  9190. window.addEventListener('beforeinstallprompt', (e) => {
  9191. // Prevent Chrome 67 and earlier from automatically showing the prompt
  9192. e.preventDefault();
  9193. // Stash the event so it can be triggered later.
  9194. deferredPrompt = e;
  9195. });
  9196. self.json.setup.page.hash = window.location.hash.substr(1);
  9197. // we consider json.setup.modules instead of self.modules
  9198. // to be sure to follow the right order of execution
  9199. var modules = []; // we need it to keep the order of the modules given in the setup
  9200. for (key in json.setup.modules) {
  9201. var mod = self.replaceProperties(json.setup.modules[key]);
  9202. modules = modules.concat(self.cloneObject(mod));
  9203. }
  9204. //modules.push({name: 'ide', url: 'https://jsonic.io/app/modules/ide.json'}); // TO DO if admin
  9205. // or can execute global before all the rest
  9206. // modules can contain {libs and apps}
  9207. // ide module can be loaded only if required
  9208. for (var mod of modules) {
  9209. //self.log(mod.name);
  9210. var params = self.modules[mod.name];
  9211. //self.log(params);
  9212. if (params.html) {
  9213. var container = selectorParams || 'body';
  9214. //if (params.app.html) {
  9215. //var documentTitle = self.json.setup.title;
  9216. //if (documentTitle)
  9217. // document.title = documentTitle;
  9218. //if (document.querySelector('meta[name="description"]'))
  9219. // document.querySelector('meta[name="description"]').setAttribute("content", documentDescription);
  9220. self.html(params.html, {container: container});
  9221. // window events
  9222. //}
  9223. }
  9224. if (params.on) { // -> this.on
  9225. // hashchange
  9226. if (params.on.hashchange) {
  9227. self.onHashChange.push(params.on.hashchange);
  9228. window.addEventListener('hashchange', function() {
  9229. self.json.setup.page.hash = window.location.hash.substr(1); // potrebbe essere esplicitato sulla app
  9230. //var action = self.cloneObject(params.app.on.hashchange);
  9231. //self.replaceAll("{result}", window.location.hash);
  9232. self.do(self.onHashChange);
  9233. self.uiUpdate();
  9234. });
  9235. }
  9236. // resize
  9237. window.addEventListener('resize', self.resizeEvent);
  9238. if (params.on.resize) {
  9239. self.onResize.push(params.on.resize);
  9240. window.addEventListener('resize', function () {
  9241. self.do(self.onResize);
  9242. });
  9243. }
  9244. // receiveMessage
  9245. if (params.on.thunkable && params.on.thunkable.receiveMessage)
  9246. window.receiveMessage(function (message) {
  9247. //document.querySelector('#message').value = message;
  9248. jsonic.functions(params.on.thunkable.receiveMessage, message, undefined);
  9249. });
  9250. self.on(params.on, {container: container}); // init included
  9251. }
  9252. //else
  9253. //self.log('The node "app" requires "container" and "html" properties');
  9254. }
  9255. } else {
  9256. //if (params.setup) args = self.extend(args, params.setup); // or params.args?
  9257. if (params.blocks) self.extendJson(json, {blocks: params.blocks});
  9258. //if (params.library) self.extendJson(json, {library: params.library}); // obsolete
  9259. if (params.media) self.extendJson(json, {media: params.media}); // obsolete
  9260. if (params.functions) self.extendJson(json, {functions: params.functions}); // obsolete
  9261. if (params.actions) self.extendJson(json, {actions: params.actions});
  9262. if (params.css) self.extendJson(json, {css: params.css});
  9263. //if (params.styles) self.extendJson(json, {styles: params.styles});
  9264. //if (params.iconset) self.extendJson(json, {iconset: params.iconset});
  9265. if (params.data) self.extendJson(json, {data: params.data});
  9266. if (params.items) self.extendJson(json, {items: params.items});
  9267. if (params.var) self.extendJson(json, {var: params.var});
  9268. if (params.html) {
  9269. var container = selectorParams || 'body'; // is an object
  9270. if (typeof container == 'string')
  9271. container = {container: container};
  9272. //if (self.inputValue({id: 'module'}) == 'base') {
  9273. // icons will be obsolete
  9274. //} else {
  9275. //var setup = extendParams.setup || params.setup;
  9276. //if (container || html.container) {
  9277. //if (params.app.html) {
  9278. var code = self.cloneObject(params.html);
  9279. //self.log('code');
  9280. //self.log(code);
  9281. //self.log(JSON.stringify(code));
  9282. self.html(code, container);
  9283. //}
  9284. //} else {
  9285. // self.log('execute method requires container parameter');
  9286. //}
  9287. if (params.on && params.on.init) {
  9288. self.do(params.on.init, undefined, container);
  9289. }
  9290. // args can be params.setup
  9291. //}
  9292. } else if (params.module) {
  9293. var moduleId = self.replaceProperties(params.module);
  9294. return self.do(self.modules[moduleId]);
  9295. }
  9296. }
  9297. }
  9298. } */
  9299. /* this.createApp = function (data) {
  9300. self.log('createApp');
  9301. //self.log(self.modules);
  9302. let deferredPrompt;
  9303. window.addEventListener('beforeinstallprompt', (e) => {
  9304. // Prevent Chrome 67 and earlier from automatically showing the prompt
  9305. e.preventDefault();
  9306. // Stash the event so it can be triggered later.
  9307. deferredPrompt = e;
  9308. });
  9309. self.json.setup.page.hash = window.location.hash.substr(1);
  9310. for (var file in self.modules) {
  9311. var params = self.modules[file];
  9312. //if (params.on) self.extendJson(json, {media: params.media});
  9313. // if (params.icons) self.extendJson(json, {icons: params.icons});
  9314. //if (params.functions) self.extendJson(json, {functions: params.functions});
  9315. //if (params.styles) self.extendJson(json, {styles: params.styles});
  9316. //if (params.items) self.extendJson(json, {items: params.items});
  9317. //if (params.var) self.extendJson(json, {var: params.var});
  9318. //if (params.library) self.extendJson(json, {library: params.library});
  9319. if (params.app && params.app.container) {
  9320. //var documentTitle = self.json.setup.title;
  9321. //if (documentTitle)
  9322. // document.title = documentTitle;
  9323. //if (document.querySelector('meta[name="description"]'))
  9324. // document.querySelector('meta[name="description"]').setAttribute("content", documentDescription);
  9325. //alert(document.querySelector(params.app.container).isConnected);
  9326. self.html(params.app.html, {container: params.app.container});
  9327. // window events
  9328. if (params.app.on) { // -> this.on
  9329. // hashchange
  9330. if (params.app.on.hashchange) {
  9331. self.onHashChange.push(params.app.on.hashchange);
  9332. window.addEventListener('hashchange', function() {
  9333. self.json.setup.page.hash = window.location.hash.substr(1); // potrebbe essere esplicitato sulla app
  9334. //var action = self.cloneObject(params.app.on.hashchange);
  9335. //self.replaceAll("{result}", window.location.hash);
  9336. self.do(self.onHashChange);
  9337. self.uiUpdate();
  9338. });
  9339. }
  9340. // resize
  9341. window.addEventListener('resize', self.resizeEvent);
  9342. if (params.app.on.resize) {
  9343. self.onResize.push(params.app.on.resize);
  9344. window.addEventListener('resize', function () {
  9345. self.do(self.onResize);
  9346. });
  9347. }
  9348. // receiveMessage
  9349. if (params.app.on.thunkable && params.app.on.thunkable.receiveMessage)
  9350. window.receiveMessage(function (message) {
  9351. //document.querySelector('#message').value = message;
  9352. jsonic.functions(params.app.on.thunkable.receiveMessage, message, undefined);
  9353. });
  9354. // init
  9355. self.log('params.app.on');
  9356. self.log(params.app.on);
  9357. self.log('params.app.container');
  9358. self.log(params.app.container);
  9359. self.on(params.app.on, {container: params.app.container});
  9360. }
  9361. }
  9362. //else
  9363. //self.log('The node "app" requires the "container" property');
  9364. }
  9365. if (self.pluginsLoaded['swup'] && self.json.setup.swup) {
  9366. let swup = new Swup(self.json.setup.swup);
  9367. }
  9368. self.do(data);
  9369. } */
  9370. /* this.menuToggle = function () {
  9371. self.log('menuToggle');
  9372. //$('.offcanvas-collapse').toggleClass('open');
  9373. $('#header').toggleClass('headerMenuOpen');
  9374. var.menuOpen = (!var.menuOpen);
  9375. self.log(var.menuOpen);
  9376. }
  9377. this.menuOpen = function () {
  9378. self.log('menuOpen');
  9379. $('#menu').addClass('menuOpen');
  9380. var.menuOpen = true;
  9381. self.log(var.menuOpen);
  9382. }
  9383. this.menuClose = function () {
  9384. self.log('menuClose');
  9385. $('#menu').removeClass('menuOpen');
  9386. var.menuOpen = false;
  9387. self.log(var.menuOpen);
  9388. } */
  9389. /* this.createMenu = function (data) {
  9390. self.log('createMenu');
  9391. // self.userRole
  9392. var menuId = (typeof data.id == 'function') ? data.id() : data.id;
  9393. var container = data.container || '#header > ul';
  9394. $(container).empty();
  9395. for (var index in self.json.menu[menuId]) {
  9396. var selector = container + ' > li:eq(' + index + ')'; // > span';
  9397. var item = self.json.menu[menuId][index];
  9398. // action
  9399. //if (item.page && !item.action) item.action = {page: item.page};
  9400. if (!var.functions[container])
  9401. var.functions[container] = {};
  9402. var.functions[container][index] = item;
  9403. $(container).append('<li id="item'+index+'"></li>');
  9404. item.color = item.color || 'inherit';
  9405. item.background = item.background || 'transparent';
  9406. item.border = item.border || 'transparent';
  9407. self.tab(item, {container: selector});
  9408. }
  9409. self.do(data);
  9410. } */
  9411. /* this.changeMenu = function (menuId) {
  9412. }
  9413. */
  9414. /* this.form = function (params, selectorParams) {
  9415. // replaceProperties può essere passato all'inizio di ogni costruttore
  9416. //params.container = params.container || self.selector(selectorParams);
  9417. //var selector = self.selector(params);
  9418. var container = params.container || self.selector(selectorParams);
  9419. //var elementContainer = self.query(container);
  9420. //var selector = self.selector(self.extend({}, params, selectorParams));
  9421. //var element = self.query(selector);
  9422. //params.tag = 'form';
  9423. //if (params.id === undefined) {params.id = '';}
  9424. //if (params.value === undefined) {params.value = ''};
  9425. //if (params.class === undefined) {params.class = ''};
  9426. //$(container).append('<'+params.tag+' id="'+params.id+'" class="'+params.class+'" data-value="'+params.value+'" data-selector="'+selector+'"></'+params.tag+'>');
  9427. for (var itemKey in params.items) {
  9428. var item = params.items[itemKey];
  9429. self.html({
  9430. "form": {
  9431. "attr": {
  9432. "id": params.id,
  9433. "class": params.class,
  9434. "data-value": params.data-value || params.value
  9435. },
  9436. "div": [
  9437. {
  9438. "attr": {
  9439. "class": "form-group",
  9440. "data-value": itemKey
  9441. },
  9442. "html": [
  9443. {
  9444. "label": {
  9445. "attr": {
  9446. "for": itemKey,
  9447. "text": item.title
  9448. }
  9449. }
  9450. },
  9451. {
  9452. "input": {
  9453. "attr": {
  9454. "id": itemKey,
  9455. "class": "form-control",
  9456. "data-value": "formInput" + itemKey,
  9457. "value": item.inputValue,
  9458. "type": item.type,
  9459. "text": item.title,
  9460. "aria-describedby": "note"+itemKey,
  9461. "placeholder": "",
  9462. "disabled": disabled
  9463. }
  9464. }
  9465. },
  9466. {
  9467. "small": {
  9468. "attr": {
  9469. "class": "form-text text-muted",
  9470. "data-value": "formNote"+itemKey,
  9471. "text": item.note
  9472. }
  9473. }
  9474. },
  9475. ]
  9476. }
  9477. ]
  9478. }
  9479. }, {
  9480. container: container
  9481. });
  9482. }
  9483. } */
  9484. /* this.addList = function (params, selectorParams) {
  9485. var container = (selectorParams) ? self.selector(selectorParams) : params.container;
  9486. var selector = self.selector(self.extend({}, params, selectorParams));
  9487. if (params.id === undefined) {params.id = '';}
  9488. if (params.value === undefined) {params.value = ''};
  9489. if (params.class === undefined) {params.class = ''};
  9490. $(container).append('<ul id="'+params.id+'" class="'+params.class+' list-group" data-value="'+params.value+'"></ul>');
  9491. self.list(params, {container: container});
  9492. } */
  9493. /*
  9494. this.addBlock = function (params, selectorParams) {
  9495. if (params.icons) self.icons(params.icons, selectorParams);
  9496. if (params.tab) self.tab(params.tab, selectorParams);
  9497. if (params.html) self.html(params.html, selectorParams);
  9498. if (params.div) self.div(params.div, selectorParams);
  9499. if (params.ul) self.ul(params.ul, selectorParams);
  9500. if (params.li) self.li(params.li, selectorParams);
  9501. if (params.span) self.span(params.span, selectorParams);
  9502. if (params.img) self.img(params.img, selectorParams);
  9503. if (params.form) self.form(params.form, selectorParams);
  9504. if (params.list) self.addList(params.list, selectorParams);
  9505. //if (params.img) alert(JSON.stringify(params.img.src));
  9506. }
  9507. */
  9508. /* this.blocks = function (params, selectorParams, args) {
  9509. if (Array.isArray(params)) {
  9510. for (var index in params)
  9511. self.blocks(params[index], selectorParams, args);
  9512. } else {
  9513. if (typeof params == 'string') {
  9514. var blocksObj = self.get('self.json.library.'+params);
  9515. if (blocksObj)
  9516. self.blocks(blocksObj.blocks, selectorParams);
  9517. } else {
  9518. if (params.library) {
  9519. self.library(params.library, selectorParams, args); // {container: container}
  9520. } else {
  9521. self.addTag(params, selectorParams, args); // {container: container}
  9522. }
  9523. }
  9524. }
  9525. }
  9526. */
  9527. this.inputValue = function (params) {
  9528. var selector = self.selector(params.selector || params.container);
  9529. var element = document.querySelector(selector); // self.query(p2);
  9530. return element.value;
  9531. };
  9532. /* this.layout = function (params, selectorParams, args) {
  9533. if (Array.isArray(params)) {
  9534. for (var index in params)
  9535. self.layout(params[index], selectorParams, args);
  9536. } else {
  9537. if (typeof params == 'string') {
  9538. var libraryObj = self.get('self.json.layouts.'+params); // todo: get?
  9539. //var libraryHtml = libraryObj.html || libraryObj.blocks;
  9540. if (libraryObj)
  9541. self.layout(libraryObj, selectorParams, args); // TODO warning potential infinite loop (if string)
  9542. else
  9543. self.log('"theme" not found: ' + params);
  9544. } else {
  9545. var libraryHtml = params.html;
  9546. // can a library component be an object?
  9547. if (params.setup) args = self.extend(args, params.setup); // or params.args?
  9548. if (params.functions) self.extendJson(json, {functions: params.functions});
  9549. if (params.css) self.extendJson(json, {css: params.css});
  9550. //if (params.styles) self.extendJson(json, {styles: params.styles});
  9551. if (params.items) self.extendJson(json, {items: params.items});
  9552. if (params.var) self.extendJson(json, {var: params.var});
  9553. self.html(libraryHtml, selectorParams, args); // {container: container}
  9554. //self.(params, selectorParams, args);
  9555. }
  9556. }
  9557. } */
  9558. this.part = this.block = function (params, selectorParams, args) {
  9559. let nested;
  9560. let part;
  9561. let partArguments;
  9562. if (typeof params.do == 'string' && self.json.parts) { // && par.match(/[.>]+/))
  9563. self.log('PART: ' + params.do, 'brown');
  9564. params.do = self.replaceProperties(params.do);
  9565. if (typeof params.do == 'object')
  9566. part = params.do;
  9567. else
  9568. part = self.element({ path: self.replaceAll(params.do, ':', '.'), root: self.json.parts }); // TO DO: . -> space?
  9569. /* if (par.indexOf(':')>0 && !part) {
  9570. self.firebaseGetPart({localPath:localPath, container: params.selector, arg:params.obj});
  9571. } */
  9572. } else if (typeof params.do == 'object')
  9573. part = params.do;
  9574. if (part) {
  9575. //if (!params.arguments) params.arguments = {};
  9576. // TO DO: Check this. seems a workaround for fantacards/ui:qrcode
  9577. if (params.arguments)
  9578. partArguments = self.replaceProperties(params.arguments);
  9579. if (typeof params.arguments == 'object') {
  9580. partArguments = (params.arguments.setup) ? params.arguments.setup : params.arguments; // compatibility
  9581. partArguments.selector = partArguments.selector || params.selector;
  9582. }
  9583. nested = self.replacePropertyWithPrefix(part, 'setup', partArguments); // {setup} -> {arguments}
  9584. nested = self.replacePropertyWithPrefix(nested, 'arguments', partArguments); // to tix
  9585. self.extendJsonFromElement(nested);
  9586. self.do(nested, params.selector, partArguments);
  9587. }
  9588. };
  9589. this.blocks = function (params, selectorParams, args) {
  9590. if (Array.isArray(params)) {
  9591. for (var index in params)
  9592. self.blocks(params[index], selectorParams, args);
  9593. } else {
  9594. //self.log('blocks');
  9595. //self.log(params);
  9596. if (typeof params == 'string') {
  9597. var blockName = self.replaceProperties(params, args); // self.compile(params, args);
  9598. //self.log('blockName');
  9599. //self.log(blockName);
  9600. var libraryObj = self.element({ path: 'self.json.blocks.' + blockName }); // todo: get?
  9601. //self.log('libraryObj');
  9602. //self.log(libraryObj);
  9603. //var libraryHtml = libraryObj.html || libraryObj.blocks;
  9604. if (libraryObj)
  9605. //self.html(libraryObj, selectorParams, args);
  9606. self.run(libraryObj, selectorParams, args);
  9607. //self.blocks(libraryObj, selectorParams, args); // TODO warning potential infinite loop (if string)
  9608. else
  9609. self.log('library component not found: ' + params);
  9610. } else {
  9611. self.run(params, selectorParams, args);
  9612. //self.run(params, selectorParams, args);
  9613. //var libraryHtml = params.html || params.app.html;
  9614. /* // can a library component be an object?
  9615. if (params.setup) args = self.extend(args, params.setup); // or params.args?
  9616. if (params.parts) self.extendJson(json, {parts: params.parts});
  9617. if (params.actions) self.extendJson(json, {actions: params.actions});
  9618. if (params.css) self.extendJson(json, {css: params.css});
  9619. if (params.data) self.extendJson(json, {data: params.data});
  9620. if (params.var) self.extendJson(json, {var: params.var});
  9621. if (params.texts) self.extendJson(json, {texts: params.texts});
  9622. self.html(params.html, selectorParams, args); // {container: container}
  9623. //self.do(params, selectorParams, args); */
  9624. }
  9625. }
  9626. };
  9627. this.uiUpdate = function (option) {
  9628. window.dispatchEvent(new Event('resize')); // workaround known ACE bug
  9629. //self.updateCodeEditors(); // workaround known ACE bug
  9630. };
  9631. this.resizeEvent = function (event) {
  9632. //self.log('resizeEvent');
  9633. for (var selector in self.resizeActions) {
  9634. var element = self.query(selector);
  9635. for (var property in self.resizeActions[selector]) {
  9636. if (property == 'action') {
  9637. self.do(self.resizeActions[element].action, { selector: selector });
  9638. //self.do(self.resizeActions[element].action, {selector: selector});
  9639. } else {
  9640. var value = self.resizeActions[selector][property];
  9641. var result = self.replaceProperties(value) || '';
  9642. //$(selector).css(property, result);
  9643. element.style[property] = result;
  9644. }
  9645. }
  9646. }
  9647. };
  9648. /* var pages = {};
  9649. var pagesSlider;
  9650. this.createPages = function (data) {
  9651. self.log('createPages');
  9652. //backLink = (self.json.setup && self.json.setup.home && self.json.setup.home[var.mode]) ? self.json.setup.home[var.mode] : '';
  9653. // class="container-fluid px-0" style="margin-top:'+self.json.setup.main.top+'"
  9654. var pageContainer = '#pages'; // 'main > div'
  9655. for (var pageKey in self.json.pages) {
  9656. params = self.json.pages[pageKey];
  9657. var pageRoles = (params.roles) ? String(params.roles).split(',') : undefined;
  9658. // se il ruolo dell'utente permette la vista della pagina e se non è stata già creata
  9659. if (!params.roles || (pageRoles.indexOf(self.userRole()) >= 0 && document.querySelectorAll('#'+pageKey).length == 0)) { // $('#'+pageKey).length == '#'+pageKey doesn't exist
  9660. //if (params.preload) {
  9661. params.tag = 'div';
  9662. //params.id = pageKey;
  9663. params.class = 'page';
  9664. params.value = pageKey;
  9665. // the previous definition should be in layout.page
  9666. self.addTag(params, {container: pageContainer});
  9667. //}
  9668. } else {
  9669. self.log('' + self.userRole() + ' users can\'t access to the page '+pageKey);
  9670. }
  9671. }
  9672. self.do(data);
  9673. } */
  9674. this.pageFullScreen = function (onOff) {
  9675. self.log('pageFullScreen');
  9676. if (onOff)
  9677. self.addClass(document.querySelector('body'), 'fullscreen');
  9678. else
  9679. self.removeClass(document.querySelector('body'), 'fullscreen');
  9680. };
  9681. //var backLink = 'stage';
  9682. /* this.pageBack = function () {
  9683. self.gotoPage(backLink);
  9684. //window.location.href = '?p='+backLink;
  9685. //$('body').removeClass('nav-open'); // chiude menu
  9686. } */
  9687. this.link = function (link, args) {
  9688. /* function link() {
  9689. [native code]
  9690. } */
  9691. //alert(link);
  9692. link = self.replaceProperties(link, args);
  9693. window.location.href = link;
  9694. };
  9695. this.reload = function () {
  9696. location.reload();
  9697. };
  9698. this.gotoHomePage = function () {
  9699. self.gotoPage(self.homePage());
  9700. };
  9701. this.homePage = function () {
  9702. //alert('homePage');
  9703. if (self.json.pages) {
  9704. if (Object.keys(self.json.pages).length > 0) {
  9705. //var homeKey = Object.keys(self.json.pages).find(key => self.json.pages[key] === 'home');
  9706. if (self.json.pages.home)
  9707. return 'home';
  9708. else
  9709. return Object.keys(self.json.pages)[0];
  9710. } else {
  9711. self.log('No pages in "pages" node');
  9712. }
  9713. } else {
  9714. self.log('Can\'t find the "pages" node');
  9715. }
  9716. };
  9717. /* this.activePage = function () { // to check if obsolete
  9718. return var.page;
  9719. } */
  9720. /* this.slideIndex = function (id) {
  9721. return $('#'+id).index()+1;
  9722. } */
  9723. /* this.slideTo = function (params) {
  9724. if (pagesSlider) pagesSlider.goTo(self.slideIndex(params.id));
  9725. $('#pages > .seq-canvas > .seq-in').addClass(params.transition);
  9726. } */
  9727. this.updateCodeEditors = function () {
  9728. // workaround known ACE bug:
  9729. // setValue doesn't work if editor is hidden
  9730. // http://jsfiddle.net/e4r7byLn/
  9731. var elements = document.querySelectorAll('.ace_editor');
  9732. if (elements) {
  9733. elements.forEach(function (element, index) {
  9734. var editor = ace.edit(element);
  9735. editor.renderer.updateFull(true);
  9736. //AceColorPicker.load(ace, editor);
  9737. //AceColorPicker.load(ace, editor); // works after some ms
  9738. });
  9739. }
  9740. };
  9741. this.gotoPage = function (pageId, fromHash) {
  9742. self.log('page'); // changePage
  9743. self.log('pageId');
  9744. self.log(pageId);
  9745. self.log('fromHash');
  9746. self.log(fromHash);
  9747. //self.log("var.page");
  9748. //self.log(var.page);
  9749. if (pageId) {
  9750. if (self.json.pages) {
  9751. if (self.json.pages[pageId]) {
  9752. var page = self.json.pages[pageId];
  9753. if (pageId !== self.json.setup.page.id || fromHash !== self.json.setup.page.hash) {
  9754. if (fromHash) {
  9755. //var.pagePath = fromHash; // obsolete
  9756. self.json.setup.page.hash = fromHash;
  9757. } else {
  9758. //delete var.pagePath;
  9759. delete self.json.setup.page.hash;
  9760. }
  9761. //var.page = pageId; // activePage
  9762. //var newHash = pageId;
  9763. //if (!fromHash) window.location.hash = newHash;
  9764. var fullScreen = self.json.pages[pageId].fullscreen || false;
  9765. //self.pageFullScreen(fullScreen);
  9766. var pageRoles = (page.roles) ? String(page.roles).split(',') : undefined;
  9767. if (self.params.d || !page.roles || pageRoles.indexOf(self.userRole()) >= 0) {
  9768. if (pageId !== self.json.setup.page.id) {
  9769. /* self.out({
  9770. "class": "page",
  9771. "data-value": self.json.setup.page.id,
  9772. "transition": "fadeOutLeft"
  9773. }); */
  9774. self.json.setup.page.id = pageId;
  9775. self.json.setup.page.title = page.title;
  9776. self.json.setup.page.roles = page.roles;
  9777. /* // TO DO: don't change document title and description
  9778. // window title
  9779. var documentTitle = self.json.setup.title;
  9780. if (page.title)
  9781. documentTitle += ' ' + self.text(page.title);
  9782. var documentDescription = self.json.setup.description || '';
  9783. if (documentTitle)
  9784. document.title = documentTitle;
  9785. if (document.querySelector('meta[name="description"]'))
  9786. document.querySelector('meta[name="description"]').setAttribute("content", documentDescription); */
  9787. //$('title').text(windowTitle);
  9788. // change page
  9789. self.hide({
  9790. "class": "page"
  9791. });
  9792. self.in({
  9793. "class": "page",
  9794. "data-value": pageId,
  9795. "transition": "fadeIn"
  9796. });
  9797. /* $('.page').hide();
  9798. $('.page[data-value='+pageId+']').fadeIn(); */
  9799. //self.resizeEvent();
  9800. self.uiUpdate(); // resize event trigger
  9801. /* // page back icon
  9802. if (page.back) {
  9803. backLink = page.back;
  9804. $('#headerLeftIcons').show((page.back));
  9805. } else {
  9806. $('#headerLeftIcons').hide();
  9807. } */
  9808. }
  9809. if (page.update) { // obsolete
  9810. self.do(page.update); //, {container: '.page[data-value='+pageId+']'});
  9811. //self.do(page.update); //, {container: '.page[data-value='+pageId+']'});
  9812. }
  9813. if (page.init) self.do(page.init);
  9814. self.log(page);
  9815. if (page.on)
  9816. self.on(page.on, { selector: '.page[data-value=' + pageId + ']' });
  9817. //$('body').removeClass('nav-open'); // chiude menu
  9818. //$('.offcanvas-collapse').removeClass('open');
  9819. } else {
  9820. if (self.userRole() == 'guest') {
  9821. /* self.do({
  9822. "login": {
  9823. "success": {
  9824. "reload": true
  9825. }
  9826. }
  9827. }); */
  9828. } else {
  9829. self.alert('Non hai i privilegi per accedere a questa pagina');
  9830. }
  9831. }
  9832. } else {
  9833. // pagina non trovata
  9834. }
  9835. } else {
  9836. self.log('Can\'t find the page "' + pageId + '"');
  9837. }
  9838. } else {
  9839. self.log('Can\'t find the main node "pages"');
  9840. }
  9841. } else {
  9842. return self.json.setup.page;
  9843. }
  9844. };
  9845. var alertInterval;
  9846. this.getTime = function (ms) {
  9847. var sec = parseInt(ms / 1000);
  9848. var min = parseInt(sec / 60);
  9849. sec = sec - min * 60;
  9850. if (min < 10) min = '0' + min;
  9851. if (sec < 10) sec = '0' + sec;
  9852. return min + ':' + sec;
  9853. };
  9854. this.sortablejs = function (params, selectorParams, args) {
  9855. let container = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  9856. let query = self.query(container);
  9857. self.log('container');
  9858. self.log(container);
  9859. self.log('query');
  9860. self.log(query);
  9861. var sortable = Sortable.create(query);
  9862. };
  9863. this.alert = function (params, args) {
  9864. /* self.log('alert');
  9865. self.log('params');
  9866. self.log(params);
  9867. self.log('args');
  9868. self.log(args); */
  9869. var paramsReplaced = self.cloneObject(params);
  9870. //paramsReplaced = self.replaceProperties(paramsReplaced, args);
  9871. //self.log('paramsReplaced');
  9872. //self.log(paramsReplaced);
  9873. if (paramsReplaced) {
  9874. if (paramsReplaced.do && paramsReplaced.do !== 'fire') {
  9875. return Swal[paramsReplaced.do](params);
  9876. // more info on https://sweetalert2.github.io/#methods
  9877. } else {
  9878. if (typeof paramsReplaced == 'string') paramsReplaced = self.text({ string: paramsReplaced, args: args }); // verify
  9879. //self.log('paramsReplaced string replaced');
  9880. //self.log(paramsReplaced);
  9881. if (typeof paramsReplaced == 'number') paramsReplaced = String(paramsReplaced); // avoid bug
  9882. if (paramsReplaced.title !== undefined) paramsReplaced.title = self.text({ string: paramsReplaced.title, args: args });
  9883. //self.log('paramsReplaced2');
  9884. //self.log(paramsReplaced);
  9885. if (paramsReplaced.html && typeof paramsReplaced.html == 'string') paramsReplaced.html = self.replaceProperties(paramsReplaced.html, args);
  9886. if (paramsReplaced.text !== undefined) paramsReplaced.text = self.text({ string: paramsReplaced.text, args: args });
  9887. //self.log('paramsReplaced string replaced 2');
  9888. if (paramsReplaced.inputValue) paramsReplaced.inputValue = self.text({ string: paramsReplaced.inputValue, args: args });
  9889. //if (paramsReplaced.html) paramsReplaced.html = self.text({string: paramsReplaced.html, args: args}); // verify
  9890. if (paramsReplaced.cancelButtonText) paramsReplaced.cancelButtonText = self.text({ string: paramsReplaced.cancelButtonText, args: args });
  9891. if (paramsReplaced.confirmButtonText) paramsReplaced.confirmButtonText = self.text({ string: paramsReplaced.confirmButtonText, args: args });
  9892. if (paramsReplaced.denyButtonText) paramsReplaced.denyButtonText = self.text({ string: paramsReplaced.denyButtonText, args: args });
  9893. //if (paramsReplaced.showConfirmButton) paramsReplaced.showConfirmButton = self.text({string: paramsReplaced.showConfirmButton, args: args});
  9894. if (paramsReplaced.inputPlaceholder) paramsReplaced.inputPlaceholder = self.text({ string: paramsReplaced.inputPlaceholder, args: args });
  9895. if (paramsReplaced.validationMessage) paramsReplaced.validationMessage = self.text({ string: paramsReplaced.validationMessage, args: args });
  9896. //if (paramsReplaced.inputOptions) paramsReplaced.inputOptions = self.text({string: paramsReplaced.inputOptions, args: args});
  9897. if (paramsReplaced.footer) {
  9898. paramsReplaced.footer = self.text({ string: paramsReplaced.footer, args: args });
  9899. }
  9900. //if (paramsReplaced.upload) alert('paramsReplaced.upload: '+paramsReplaced.upload);
  9901. if (paramsReplaced.upload) {
  9902. paramsReplaced.html = '<form class="box" method="post" action="" enctype="multipart/form-data"><div class="drop-zone"><div class="drop-zone-caption">' + self.text('dragAndDropFiles') + '</div><span class="btn btn-primary btn-file" style="position: relative"><span>' + self.text('chooseFiles') + '</span><input type="file" accept=".ply, .obj, .stl" class="drop-zone-file" name="files[]"></span></div></form> ';
  9903. // <img src="" alt="" style="background:#333" width="100" height="100" id="hidden-img" />
  9904. //if (paramsReplaced.onUpload) var.onUpload = paramsReplaced.onUpload;
  9905. //var.uploadingTarget = paramsReplaced.uploadingTarget;
  9906. }
  9907. //self.log('paramsReplaced3');
  9908. //self.log(paramsReplaced);
  9909. alertObj.confirm = paramsReplaced.confirm; // deprecated
  9910. alertObj.cancel = paramsReplaced.cancel; // deprecated
  9911. alertObj.deny = paramsReplaced.deny; // deprecated
  9912. alertObj.on = paramsReplaced.on;
  9913. alertObj.id = paramsReplaced.id;
  9914. delete paramsReplaced.on;
  9915. var alertHtml = paramsReplaced.html || paramsReplaced.blocks;
  9916. if (alertHtml)
  9917. paramsReplaced.html = " ";
  9918. var swalParams = self.replaceProperties(paramsReplaced, args);
  9919. // animate
  9920. if (paramsReplaced.animate) {
  9921. var animationIn = paramsReplaced.animate.in || paramsReplaced.animate;
  9922. var animationOut = paramsReplaced.animate.out || paramsReplaced.animate;
  9923. if (paramsReplaced.animate.in)
  9924. animationIn = paramsReplaced.animate.in.transition || paramsReplaced.animate.in;
  9925. if (paramsReplaced.animate.out)
  9926. animationOut = paramsReplaced.animate.out.transition || paramsReplaced.animate.out;
  9927. swalParams.showClass = {
  9928. popup: 'animate__animated animate__faster animate__animated animate__' + animationIn
  9929. };
  9930. swalParams.hideClass = {
  9931. popup: 'animate__animated animate__faster animate__animated animate__' + animationOut
  9932. };
  9933. }
  9934. var customIcon;
  9935. if (swalParams.icon) {
  9936. //swalParams.icon = self.replaceProperties(swalParams.icon, args);
  9937. if (typeof swalParams.icon !== 'string') {
  9938. customIcon = self.cloneObject(swalParams.icon);
  9939. delete swalParams.icon;
  9940. }
  9941. /* var swalIcons = []; //"warning", "error", "success", "info", "question"];
  9942. if (swalIcons.indexOf(params.icon)<0) {
  9943. customIcon = params.icon;
  9944. //if (!params.customClass) params.customClass = {};
  9945. //params.customClass.icon = "customIcon";
  9946. } */
  9947. }
  9948. //if (swalParams.showConfirmButton) delete swalParams.showConfirmButton;
  9949. // swalParams.update = function() {
  9950. // self.log('swalParams.update');
  9951. // self.log(var.updateSwal);
  9952. // }
  9953. // onRender is obsolete
  9954. /* swalParams.onRender = function () {
  9955. startUploadListeners({
  9956. container: '.drop-zone',
  9957. onUpload: params.onUpload,
  9958. path: params.path
  9959. //uploadingTarget: var.uploadingTarget
  9960. //onError:
  9961. });
  9962. }
  9963. */
  9964. delete swalParams.blocks;
  9965. delete swalParams.onUpload;
  9966. delete swalParams.upload;
  9967. if (swalParams.confirm) delete swalParams.confirm;
  9968. if (swalParams.cancel) delete swalParams.cancel;
  9969. if (swalParams.timerProgressBar) {
  9970. swalParams.onBeforeOpen = function () {
  9971. //Swal.showLoading(); // rimuove i bottoni
  9972. alertInterval = setInterval(() => {
  9973. const content = Swal.getContent();
  9974. if (content) {
  9975. const b = content.querySelector('b');
  9976. if (b) {
  9977. b.textContent = self.getTime(Swal.getTimerLeft());
  9978. }
  9979. }
  9980. }, 100);
  9981. };
  9982. swalParams.onClose = function () {
  9983. clearInterval(alertInterval);
  9984. };
  9985. }
  9986. //self.log('swalParams');
  9987. //self.log(swalParams);
  9988. Swal.fire(swalParams).then((result) => {
  9989. //self.log('alert result');
  9990. //self.log(result);
  9991. // TO DO: if (!result) result = {} to avoid errors
  9992. var alertResult = result.value;
  9993. if (alertObj.on) {
  9994. if (alertObj.on.value && result.value) {
  9995. //if (alertObj.id) alertObj.values[alertObj.id] = result.value;
  9996. if (alertObj.id) alertValues[alertObj.id] = result.value;
  9997. alertValues.value = result.value;
  9998. setTimeout(function () {
  9999. alertObj.on.value = self.replacePropertyWithPrefix(alertObj.on.value, 'alert', alertValues);
  10000. //alertObj.on.value = self.replaceProperty(alertObj.on.value, 'alert', result);
  10001. self.do(alertObj.on.value, undefined, result.value); // TO DO: remove result.value once removed all {result}
  10002. //self.do(alertObj.on.value, result.value); // TO DO: remove result.value once removed all {result}
  10003. }, 500);
  10004. }
  10005. if (alertObj.on.isConfirmed && result.isConfirmed) {
  10006. if (alertObj.id) alertValues[alertObj.id] = result.isConfirmed;
  10007. alertObj.on.isConfirmed = self.replacePropertyWithPrefix(alertObj.on.isConfirmed, 'alert', alertValues);
  10008. alertObj.on.isConfirmed = self.replacePropertyWithPrefix(alertObj.on.isConfirmed, 'alert', result);
  10009. self.do(alertObj.on.isConfirmed, undefined, result.value); // TO DO: remove result.value once removed all {result}
  10010. //self.do(alertObj.on.isConfirmed, result.value); // TO DO: remove result.value once removed all {result}
  10011. }
  10012. if (alertObj.on.isDenied && result.isDenied) {
  10013. alertObj.on.isDenied = self.replacePropertyWithPrefix(alertObj.on.isDenied, 'alert', result);
  10014. self.do(alertObj.on.isDenied, undefined, result.value); // TO DO: remove result.value once removed all {result}
  10015. //self.do(alertObj.on.isDenied, result.value); // TO DO: remove result.value once removed all {result}
  10016. }
  10017. if (alertObj.on.isDismissed && result.isDismissed) {
  10018. alertObj.on.isDismissed = self.replacePropertyWithPrefix(alertObj.on.isDismissed, 'alert', result);
  10019. self.do(alertObj.on.isDismissed, undefined, result.dismiss); // TO DO: remove result.value once removed all {result}
  10020. //self.do(alertObj.on.isDismissed, result.dismiss); // TO DO: remove result.value once removed all {result}
  10021. }
  10022. console.log('alertValues');
  10023. console.log(alertValues);
  10024. } else {
  10025. /* if (result.isConfirmed) {
  10026. self.do(alertObj.confirm, result.value);
  10027. } else if (result.isDenied) {
  10028. self.do(alertObj.deny, result.value);
  10029. } else if (result.dismiss === Swal.DismissReason.cancel) {
  10030. self.do(alertObj.cancel, result.value);
  10031. } else if (result.dismiss === Swal.DismissReason.timer) {
  10032. self.log('Alert closed by the timer');
  10033. } */
  10034. }
  10035. /*
  10036. Reason Description Related configuration
  10037. Swal.DismissReason.backdrop The user clicked the backdrop. allowOutsideClick
  10038. Swal.DismissReason.cancel The user clicked the cancel button. showCancelButton
  10039. Swal.DismissReason.close The user clicked the close button. showCloseButton
  10040. Swal.DismissReason.esc The user clicked the Esc key. allowEscapeKey
  10041. Swal.DismissReason.timer The timer ran out, and the alert closed automatically. timer
  10042. */
  10043. });
  10044. if (alertHtml)
  10045. self.do(alertHtml, { selector: '#swal2-html-container' });
  10046. //self.log('customIcon');
  10047. //self.log(customIcon);
  10048. if (customIcon) {
  10049. /* self.icons({
  10050. "class": "icon",
  10051. "svg": customIcon
  10052. }, {container: '.swal2-icon'}); */
  10053. self.do(customIcon, { selector: '.swal2-icon' });
  10054. //self.addTag(customIcon, {container: '.swal2-icon'}); // check
  10055. self.css({
  10056. selector: '.swal2-icon',
  10057. style: {
  10058. 'border': '0px solid transparent'
  10059. }
  10060. });
  10061. self.show({
  10062. selector: '.swal2-icon'
  10063. });
  10064. /* $('.swal2-icon').css({
  10065. 'border': '0px solid transparent'
  10066. });
  10067. $('.swal2-icon').show(); */
  10068. }
  10069. if (swalParams.on && swalParams.on.init) // to be repeated in each function
  10070. self.do(swalParams.on.init);
  10071. //self.do(swalParams.on.init);
  10072. }
  10073. }
  10074. };
  10075. /* var startUploadListeners = function (params) { // da FIXO
  10076. self.log('startUploadListeners');
  10077. var.upload = params;
  10078. var obj = $(params.container);
  10079. self.log(params);
  10080. obj.on('dragenter', function (e) {
  10081. e.stopPropagation();
  10082. e.preventDefault();
  10083. $(this).css('border', '2px solid #0B85A1');
  10084. });
  10085. obj.on('dragover', function (e) {
  10086. e.stopPropagation();
  10087. e.preventDefault();
  10088. });
  10089. $(document).on('dragenter', function (e) {
  10090. e.stopPropagation();
  10091. e.preventDefault();
  10092. });
  10093. $(document).on('dragover', function (e) {
  10094. e.stopPropagation();
  10095. e.preventDefault();
  10096. obj.css('border', '2px dotted #0B85A1');
  10097. });
  10098. $(document).on('drop', function (e) {
  10099. e.stopPropagation();
  10100. e.preventDefault();
  10101. });
  10102. // automatically submit the form on file select
  10103. obj.on('drop', function (e) {
  10104. $(this).css('border', '2px dotted #0B85A1');
  10105. e.preventDefault();
  10106. var files = e.originalEvent.dataTransfer.files;
  10107. //We need to send dropped files to firebase
  10108. handleFileUpload(files);
  10109. });
  10110. $(params.container+'-file').on('change', function (e) {
  10111. var files = $(params.container+'-file')[0].files;
  10112. self.log(params.container+'-file');
  10113. self.log(files)
  10114. handleFileUpload(files);
  10115. });
  10116. } */
  10117. /* this.uploadFileNameAndType = function(params){
  10118. self.log('uploadFileNameAndType');
  10119. self.log(params);
  10120. var fileArr = params.fileName.split('.');
  10121. var.upload.fileName = params;
  10122. var.upload.fileType = fileArr[1].toLowerCase();
  10123. if (!$('.swal2-act').length) $('.swal2-modal').append('<div class="swal2-act"></div>');
  10124. if (var.upload.fileType == 'ply') {
  10125. $('.swal2-act').css({'display':'none'});
  10126. } else {
  10127. $('.swal2-act').css({'display':'block'});
  10128. $('.swal2-act').append('<button onclick=\"app.onUploadConfirm()\" type=\"button\" class=\"swal2-confirm swal2-styled\" aria-label=\"\" style=\"display: inline-block; border-left-color: rgb(48, 133, 214); border-right-color: rgb(48, 133, 214);\">'+self.text('btnImport')+'</button>');
  10129. }
  10130. } */
  10131. /* var handleFileUpload = function(files) {
  10132. self.log('handleFileUpload');
  10133. self.log(files);
  10134. self.log('var.upload');
  10135. self.log(var.upload);
  10136. //var auth0Id = fixo.getAuth0Id();
  10137. // Swal.close(); // chiusura popup
  10138. for (var i = 0; i < files.length; i++) {
  10139. var fd = new FormData();
  10140. fd.append('file', files[i]);
  10141. if (!files[i].name.endsWith('png')) var.upload.fileTimestamp = self.getTimestamp();
  10142. self.fireBaseUpload({
  10143. 'file': files[i], //base64toBlob(files),
  10144. 'timestamp': var.upload.fileTimestamp,
  10145. 'path': var.user.uid+'/' || '' //auth0Id+'/files/images' //path_to_where_you_to_store_the_file
  10146. }, function (data) {
  10147. self.log('data');
  10148. self.log(data);
  10149. if (!data.error) {
  10150. //if (data.progress && data.progress == 0) $('.swal2-actions').append('<span class="prog" style="font-size:48px;font-weight:bolder"></span>');
  10151. if (data.progress >= 0 && data.progress <= 100) {
  10152. //progress update to view here
  10153. // self.log('Uploading file');
  10154. // self.log(var.uploadingTarget);
  10155. $('#msgFooter').html('<span>'+data.progress+'%</span>')
  10156. }
  10157. if (data.progress == 100) {
  10158. //$(var.uploadingTarget).removeClass('pulseFade');
  10159. // Swal.close();
  10160. if (data.fileExt !== 'png'){
  10161. self.log('diverso da png');
  10162. $('.drop-zone-file').attr('accept','.png');
  10163. var.upload.data = data;
  10164. }
  10165. if (var.upload.onUpload) self.do(var.upload.onUpload, data);
  10166. }
  10167. } else {
  10168. //$(var.uploadingTarget).removeClass('pulseFade');
  10169. self.log(data.error + ' Firebase image upload error');
  10170. }
  10171. });
  10172. }
  10173. }; */
  10174. /* var uploadDone = function (data) {
  10175. self.log('uploadDone');
  10176. // download URL here "data.downloadURL"
  10177. var auth0Id = fixo.getAuth0Id();
  10178. var storageRef = firebase.storage().ref();
  10179. var imageRef = storageRef.child(auth0Id+'/files/images/'+data.fileName);
  10180. // Get the download URL
  10181. imageRef.getDownloadURL().then(function(url) {
  10182. self.do(var.onUpload, url);
  10183. // Insert url into an <img> tag to "download"
  10184. }).catch(function(error) {
  10185. self.log(error.code);
  10186. // A full list of error codes is available at
  10187. // https://firebase.google.com/docs/storage/web/handle-errors
  10188. switch (error.code) {
  10189. case 'storage/object_not_found':
  10190. // File doesn't exist
  10191. break;
  10192. case 'storage/unauthorized':
  10193. // User doesn't have permission to access the object
  10194. break;
  10195. case 'storage/canceled':
  10196. // User canceled the upload
  10197. break;
  10198. case 'storage/unknown':
  10199. // Unknown error occurred, inspect the server response
  10200. break;
  10201. }
  10202. });
  10203. } */
  10204. this.findKey = function (obj, key) {
  10205. return obj.filter(function (item) {
  10206. return Boolean(item[key]);
  10207. });
  10208. };
  10209. /* this.fireBaseUpload = function(parameters, callBackData) {
  10210. self.log('fireBaseUpload');
  10211. self.log('parameters');
  10212. self.log(parameters);
  10213. // Get a reference to the storage service, which is used to create references in your storage bucket
  10214. var storageRef = firebase.storage().ref();
  10215. var file = parameters.file;
  10216. var path = parameters.path;
  10217. var timestamp = parameters.timestamp;
  10218. //var path = var.user.uid; // non riesco a passare la path come parametro da olo.app.json così come l'errore funzione onUpload
  10219. self.log('file');
  10220. self.log(file);
  10221. self.log('timestamp');
  10222. self.log(timestamp);
  10223. self.log('path');
  10224. self.log(path);
  10225. //Riga originale pre-modifica nome file
  10226. // var fullPath = path + '/' + file.name;
  10227. // expected parameters to start storage upload
  10228. var metaData = {'contentType': file.type};
  10229. var fileSize = formatBytes(file.size); // get clean file size
  10230. var fileType = file.type;
  10231. var fileName = file.name;
  10232. var fileExt = fileName.split('.')[1];
  10233. self.log(metaData);
  10234. self.log(fileSize);
  10235. self.log(fileType);
  10236. self.log(fileName);
  10237. self.log(fileExt);
  10238. var modFileName = timestamp+'.'+fileExt;
  10239. //var fullFilePath = storageRef.child(path+timestamp+'-'+fileName);
  10240. var fullFilePath = storageRef.child(path+modFileName);
  10241. self.log('fullFilePath');
  10242. self.log(fullFilePath);
  10243. var nm = fileName.split('.');
  10244. var name = nm[0];
  10245. self.log('nm');
  10246. self.log(nm);
  10247. self.log('name');
  10248. self.log(name);
  10249. // Modifica file name generato
  10250. // var name = generateRandomString(16); //(location function below)
  10251. // var n = name+'.'+file.type.replace('image/','');
  10252. // var fullPath = path + '/' + n;
  10253. //Riga originale pre-modifica nome file
  10254. // var n = file.name;
  10255. // generate random string to identify each upload instance
  10256. //name = generateRandomString(12); //(location function below)
  10257. // var uploadFile = storageRef.child(parameters.path).put(file, metaData);
  10258. var uploadFile = fullFilePath.put(file, metaData);
  10259. // first instance identifier
  10260. //callBackData({id: name, fileSize: fileSize, fileType: fileType, fileName: n}); 20200724
  10261. callBackData({id: timestamp.toString(), fileSize: fileSize, fileType: fileType, fileName: modFileName, fileExt: fileExt}); // fileName: fileName //id: name
  10262. uploadFile.on('state_changed', function (snapshot) {
  10263. var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
  10264. progress = Math.floor(progress);
  10265. self.log('progress');
  10266. self.log(progress);
  10267. callBackData({
  10268. progress: progress,
  10269. element: timestamp.toString(),
  10270. //element: name,
  10271. fileSize: fileSize,
  10272. fileType: fileType,
  10273. fileName: modFileName,
  10274. fileExt: fileExt});
  10275. //fileName: fileName
  10276. }, function (error) {
  10277. callBackData({error: error});
  10278. }, function () {
  10279. var downloadURL = uploadFile.snapshot.downloadURL;
  10280. callBackData({
  10281. downloadURL: downloadURL,
  10282. element: timestamp.toString(),
  10283. //element: name,
  10284. fileSize: fileSize,
  10285. fileType: fileType,
  10286. fileName: modFileName,
  10287. fileExt: fileExt});
  10288. //fileName: fileName
  10289. });
  10290. } */
  10291. var formatBytes = function (bytes, decimals) {
  10292. if (bytes == 0) return '0 Byte';
  10293. var k = 1000;
  10294. var dm = decimals + 1 || 3;
  10295. var sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
  10296. var i = Math.floor(Math.log(bytes) / Math.log(k));
  10297. return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + ' ' + sizes[i];
  10298. };
  10299. this.userRole = function () {
  10300. switch (Boolean(self.user('uid'))) {
  10301. case true:
  10302. return 'user'; // user logged in
  10303. break;
  10304. case false:
  10305. return 'guest';
  10306. break;
  10307. }
  10308. };
  10309. this.userIn = function () {
  10310. //var user = firebase.auth().currentUser;
  10311. //if (user.emailVerified) {
  10312. return Boolean(self.user('uid'));
  10313. };
  10314. this.userOut = function () {
  10315. return (!self.user('uid'));
  10316. };
  10317. this.user = function (param) {
  10318. /* self.log('user');
  10319. self.log(auth); */
  10320. if (auth && auth.currentUser)
  10321. if (param == 'firstName')
  10322. return self.firstName(auth.currentUser['displayName']);
  10323. else if (auth.currentUser[param])
  10324. return auth.currentUser[param];
  10325. else if (!param)
  10326. return auth.currentUser;
  10327. else
  10328. return undefined;
  10329. else
  10330. return undefined;
  10331. };
  10332. this.firstName = function (nameParam) {
  10333. var firstNameStr = (nameParam) ? nameParam.split(' ')[0] : '';
  10334. return firstNameStr;
  10335. };
  10336. this.userUid = function () {
  10337. if (auth) return auth.currentUser.uid;
  10338. else return undefined;
  10339. };
  10340. this.userVerified = function () {
  10341. if (auth) return auth.currentUser.emailVerified;
  10342. else return undefined;
  10343. };
  10344. /* this.value = function (valueParams) {
  10345. if (valueParams.string)
  10346. return valueParams.string
  10347. else if (valueParams.function)
  10348. //return self.doFunctionByName(valueParams.function, window, '');
  10349. }
  10350. */
  10351. this.thunkableMessage = function (message, callback) {
  10352. if (callback) callback(message);
  10353. };
  10354. this.onMessage = {
  10355. alert: "test"
  10356. };
  10357. this.processMessage = function (message) {
  10358. self.alert('processMessage');
  10359. self.do(self.onMessage, message);
  10360. //self.do(self.onMessage, undefined, message);
  10361. };
  10362. this.thunkable = function (params, args) {
  10363. if (params.postMessage) {
  10364. var message = self.replaceProperties(params.postMessage, args);
  10365. if (message) {
  10366. try {
  10367. ThunkableWebviewerExtension.postMessage(message);
  10368. } catch (error) {
  10369. }
  10370. }
  10371. else
  10372. self.log('in function "thunkable" "postMessage" parameter is wrong');
  10373. }
  10374. if (params.receiveMessage) {
  10375. self.onMessage = params.receiveMessage;
  10376. try {
  10377. ThunkableWebviewerExtension.receiveMessage(self.processMessage);
  10378. } catch (error) {
  10379. }
  10380. }
  10381. };
  10382. /* var ThunkableWebviewerExtension = (function () {
  10383. const postMessageToWebview = (message) => {
  10384. if (window.ReactNativeWebView) {
  10385. window.ReactNativeWebView.postMessage(message);
  10386. } else {
  10387. window.parent.postMessage(message, '*');
  10388. }
  10389. };
  10390. const getReceiveMessageCallback = (fxn, hasReturnValue) => (event) => {
  10391. if (typeof fxn === 'function') {
  10392. if (event.data) {
  10393. let dataObject;
  10394. try {
  10395. dataObject = JSON.parse(event.data);
  10396. } catch (e) {
  10397. // message is not valid json
  10398. }
  10399. if (dataObject && dataObject.type === 'ThunkablePostMessage' && hasReturnValue) {
  10400. fxn(dataObject.message, (returnValue) => {
  10401. const returnMessageObject = { type: 'ThunkablePostMessageReturnValue', uuid: dataObject.uuid, returnValue };
  10402. postMessageToWebview(JSON.stringify(returnMessageObject));
  10403. });
  10404. } else if (!hasReturnValue && (!dataObject || dataObject.type !== 'ThunkablePostMessage')) {
  10405. fxn(event.data);
  10406. }
  10407. }
  10408. }
  10409. };
  10410. return {
  10411. postMessage: postMessageToWebview,
  10412. receiveMessage: function (fxn) {
  10413. const callbackFunction = getReceiveMessageCallback(fxn, false);
  10414. document.addEventListener('message', callbackFunction, false);
  10415. window.addEventListener('message', callbackFunction, false);
  10416. },
  10417. receiveMessageWithReturnValue: function (fxn) {
  10418. const callbackFunction = getReceiveMessageCallback(fxn, true);
  10419. document.addEventListener('message', callbackFunction, false);
  10420. window.addEventListener('message', callbackFunction, false);
  10421. },
  10422. };
  10423. })(); */
  10424. this.extendFunctions = function (functions) {
  10425. // change it. don't call self.function
  10426. for (var name in functions) {
  10427. if (functions[name].js) {
  10428. try {
  10429. // create or override function
  10430. self.functions[name] = new Function(functions[name].js);
  10431. } catch (error) {
  10432. console.log('ERROR creating function %c' + name, 'color:orange;');
  10433. self.log(functions[name].js);
  10434. self.log(error.message);
  10435. // error.column is wrong
  10436. /* let col = error.column -17;
  10437. console.log(
  10438. functions[name].js.substring(0,col)
  10439. + '%c' + functions[name].js.substring(col, col+1)
  10440. + '%c' + functions[name].js.substring(col+1), 'color:orange; font-weight:bold', 'color:#ddd')
  10441. console.log('%c' + error.message, 'color:orange;'); */
  10442. // since the script is in one row, error.columns is the exact position of the error
  10443. }
  10444. } else {
  10445. self.log(name + ' function requires js property');
  10446. }
  10447. }
  10448. };
  10449. this.function = function (obj, args) {
  10450. /* console.log('function');
  10451. console.log(params);
  10452. console.log('args');
  10453. console.log(args); */
  10454. // TO DO: add "name" parameter to make the js function permanently available in self.methods[name]
  10455. // https://stackoverflow.com/questions/49125059/how-to-pass-parameters-to-an-eval-based-function-injavascript
  10456. //app[func].apply( this, args ); // or app[func]( ...args ); // ES6 (2015)
  10457. // https://stackoverflow.com/questions/1316371/converting-an-array-to-a-function-arguments-list
  10458. //args = self.replaceProperties(args); // needed?
  10459. //try {
  10460. if (obj.name && obj.js) {
  10461. // create or replace function
  10462. self.functions[obj.name] = new Function(obj.js);
  10463. } else if (obj.name && !obj.js) {
  10464. if (self.functions[obj.name]) {
  10465. // execute function
  10466. if (!obj.arguments || !Array.isArray(obj.arguments)) obj.arguments = [obj.arguments];
  10467. try {
  10468. return self.functions[obj.name](...obj.arguments);
  10469. //return self.functions[obj.name].apply(null, obj.arguments);
  10470. } catch (error) {
  10471. console.log('ERROR in function %c' + obj.name, 'color:orange;');
  10472. console.log('obj');
  10473. console.log(obj);
  10474. console.log('function');
  10475. console.log(self.json.functions[obj.name]);
  10476. console.log(error.message);
  10477. }
  10478. } else {
  10479. console.log('ERROR function undefined %c' + obj.name, 'color:orange;');
  10480. }
  10481. //return self.functions[obj.name](...obj.arguments); // also args?
  10482. } else if (obj.js) {
  10483. // execute js code as a function
  10484. if (obj.arguments && Array.isArray(obj.arguments)) {
  10485. return new Function(obj.js).call(null, obj.arguments);
  10486. //return new Function( obj.js ).apply(this, obj.arguments );
  10487. } else {
  10488. return new Function(obj.js).call(null, obj.arguments);
  10489. }
  10490. }
  10491. /* } catch (error) {
  10492. self.log('function ERROR');
  10493. self.log(error);
  10494. self.log(obj);
  10495. return false
  10496. } */
  10497. };
  10498. this.eval = this.js = function (code, args) {
  10499. /* self.log('js');
  10500. self.log(code);
  10501. self.log(args); */
  10502. /* if (Array.isArray(code)) {
  10503. let codeCombined = '';
  10504. for (var codePart of code) codeCombined += self.replaceProperties(codePart, args);
  10505. try {
  10506. return eval(code);
  10507. } catch (error) {
  10508. self.log('JS error');
  10509. self.log(error);
  10510. return code;
  10511. } */
  10512. /* if (typeof code == 'object') {
  10513. } else { */
  10514. code = self.replaceProperties(code, args);
  10515. /* self.log('args');
  10516. self.log(args); */
  10517. try {
  10518. //return new Function( code ).call(null, args);
  10519. return eval(code);
  10520. } catch (error) {
  10521. /* self.log('javascript catch on "'+ codeString + '"');
  10522. self.log('error');
  10523. self.log(error);
  10524. self.log('codeString');
  10525. self.log(codeString);
  10526. self.log('args');
  10527. self.log(args);
  10528. return false */
  10529. return code;
  10530. }
  10531. //}
  10532. };
  10533. /* this.compile = function (obj, args) {
  10534. // functions e addTag potrebbero essere eseguiti da una stessa funzione
  10535. // in reatà addTag è la funzione che andrebbe lanciata quando la chiave
  10536. // dell'azione è tra i tag html
  10537. if (obj !== undefined) {
  10538. var result;
  10539. if (typeof obj == 'object')
  10540. result = self.actionResult(obj, args);
  10541. result = self.replaceProperties(obj, args);
  10542. if (result == 'undefined')
  10543. return undefined;
  10544. else if (typeof result == 'object') // Array is also an object type
  10545. return self.do(result, args);
  10546. else if (typeof result == 'function')
  10547. return result(args);
  10548. else {
  10549. return result;
  10550. }
  10551. } else {
  10552. return undefined;
  10553. }
  10554. } */
  10555. this.if = function (params, selectorParams, args) {
  10556. // add array
  10557. if (typeof params == 'object') {
  10558. var conditionString = 'if';
  10559. var condition;
  10560. if (params.is !== undefined) {
  10561. if (typeof params.is == 'string') {
  10562. let isReplaced = self.replaceProperties(params.is, args, true);
  10563. self.log(isReplaced, 'grey');
  10564. try {
  10565. condition = Boolean(eval(isReplaced)); // remove undefined values
  10566. self.log(isReplaced + ' is ' + condition, 'grey');
  10567. } catch (error) {
  10568. self.log(isReplaced, 'red');
  10569. self.log('"if" condition wrong', 'red');
  10570. self.log(error, 'red');
  10571. }
  10572. conditionString += ' is ' + params.is;
  10573. } else if (Array.isArray(params.is)) {
  10574. let i = 0;
  10575. params.is[i];
  10576. switch (params.is[i + 1]) {
  10577. case '=': condition = Boolean(eval(params.is[i] + '===' + params.is[i + 2])); break;
  10578. }
  10579. }
  10580. } else if (params.not !== undefined) {
  10581. condition = (!Boolean(eval(self.replaceProperties(params.not, args, true)))); // remove undefined values
  10582. if (typeof params.not == 'string') conditionString += ' not ' + params.not;
  10583. } else if (params.regexp) {
  10584. const regex = new RegExp(params.regexp);
  10585. condition = Boolean(regex.test(params.string));
  10586. } else if (params.isArray) {
  10587. condition = self.isArray(params.isArray);
  10588. conditionString += 'isArray ' + params.isArray;
  10589. } else if (params.exist) {
  10590. let elementExist = self.element({ path: params.exist });
  10591. condition = (elementExist);
  10592. self.log('"if" exist ' + params.exist, 'grey');
  10593. } else if (params.value && params.in) {
  10594. //let arr = self.replaceProperties(params.in, args, true);
  10595. //condition = (arr.indexOf(self.replaceProperties(params.value)) >= 0);
  10596. condition = self.valueInJson(self.replaceProperties(params.in, args, true), self.replaceProperties(params.value));
  10597. self.log('"if" value ' + self.replaceProperties(params.value) + ' in array is ' + condition, 'grey');
  10598. } else if (params.key && params.in) {
  10599. condition = self.keyInJson(self.replaceProperties(params.in, args, true), self.replaceProperties(params.key));
  10600. self.log('"if" key ' + self.replaceProperties(params.key) + ' in object is ' + condition, 'grey');
  10601. } else {
  10602. let selector = self.selector(params.selector || params.container, undefined) || self.selector(selectorParams, undefined);
  10603. //var selector = self.selector(params.selector || params.container, selectorParams);
  10604. if (selector) {
  10605. if (params.exist) {
  10606. //var element = self.query(params.exist);
  10607. //condition = Boolean(self.query(selector));
  10608. condition = Boolean(self.exist(selector));
  10609. conditionString += ' ' + selector + ' exist ' + params.exist;
  10610. }
  10611. if (params.hasClass) { // to be reviewed (self.hasClass need 1 parameter)
  10612. var element = self.query(selector);
  10613. condition = Boolean(self.hasClass(element, params.hasClass));
  10614. conditionString += ' ' + selector + ' hasClass ' + params.hasClass;
  10615. }
  10616. if (params.isVisible) {
  10617. var element = self.query(selector);
  10618. condition = Boolean(self.isVisible(element, params.isVisible));
  10619. conditionString += ' ' + selector + ' isVisible';
  10620. }
  10621. if (params.isHidden) {
  10622. var element = self.query(selector);
  10623. condition = Boolean(self.isHidden(element, params.isHidden));
  10624. conditionString += ' ' + selector + ' isHidden';
  10625. }
  10626. if (params.inViewport) {
  10627. var element = self.query(selector);
  10628. condition = Boolean(self.inViewport(element, params.inViewport));
  10629. conditionString += ' ' + selector + ' inViewport';
  10630. }
  10631. if (params.outViewport) {
  10632. var element = self.query(selector);
  10633. condition = Boolean(self.outViewport(element, params.outViewport));
  10634. conditionString += ' ' + selector + ' outViewport';
  10635. }
  10636. if (params.isDisplay) {
  10637. var element = self.query(selector);
  10638. /* self.log('element');
  10639. self.log(element); */
  10640. condition = Boolean(self.isDisplay(element, params.isDisplay));
  10641. conditionString += ' ' + selector + ' isDisplay ' + params.isDisplay;
  10642. }
  10643. } else {
  10644. self.log('the "if" function requires "is" or "not" parameter');
  10645. }
  10646. }
  10647. /* conditionString += ': ' + condition;
  10648. self.log(condition, 'grey'); */
  10649. if (condition)
  10650. if (params.then) {
  10651. // self.console dovrebbe diventare così
  10652. if (typeof params.then == 'object') {
  10653. return self.do(params.then);
  10654. //return self.do(params.then);
  10655. } if (typeof params.then == 'string') {
  10656. return self.replaceProperties(params.then);
  10657. } else {
  10658. return params.then;
  10659. }
  10660. }
  10661. else
  10662. self.log('the "if" function requires "then" parameter');
  10663. else if (params.else) {
  10664. if (typeof params.else == 'object') {
  10665. return self.do(params.else);
  10666. //return self.do(params.else);
  10667. } if (typeof params.else == 'string') {
  10668. return self.replaceProperties(params.else);
  10669. } else {
  10670. return params.else;
  10671. }
  10672. }
  10673. } else {
  10674. //self.log(Boolean(params) && params !== 'false');
  10675. return Boolean(self.js(params, args)); // 0.9.7
  10676. //return Boolean(eval(self.replaceProperties(params, args))) // need try
  10677. }
  10678. };
  10679. this.switch = function (params, args) {
  10680. //self.log('switch');
  10681. //self.log(params);
  10682. var value;
  10683. var answer;
  10684. if (params.expression)
  10685. value = String(self.js(params.expression, args));
  10686. else
  10687. self.log('"switch" function requires "expression" parameter');
  10688. //self.log(value);
  10689. if (params.cases) {
  10690. //self.log('params.cases[value]');
  10691. //self.log(params.cases[value]);
  10692. if (value !== undefined && params.cases[value]) {
  10693. if (typeof params.cases[value] == 'object')
  10694. answer = self.do(params.cases[value], undefined, args);
  10695. //answer = self.do(params.cases[value], args);
  10696. else
  10697. answer = params.cases[value];
  10698. } else if (params.cases['default']) {
  10699. self.log('default');
  10700. self.log(params.cases['default']);
  10701. if (typeof params.cases['default'] == 'object')
  10702. answer = self.do(params.cases['default'], undefined, args);
  10703. //answer = self.do(params.cases['default'], args);
  10704. else
  10705. answer = params.cases['default'];
  10706. }
  10707. } else {
  10708. self.log('"switch" function requires "cases" parameter');
  10709. self.log('answer');
  10710. self.log(answer);
  10711. }
  10712. return answer;
  10713. };
  10714. /*
  10715. this.varAction = this.set = function (params, args) {
  10716. // {name, value, operator}
  10717. var value;
  10718. var operator = params.operator;
  10719. //self.log('operator');
  10720. //self.log(operator);
  10721. if (operator && args) operator = self.replaceProperties(operator, args);
  10722. //self.log('operator');
  10723. //self.log(operator);
  10724. if (params.value !== undefined) { // set
  10725. value = self.js(params.value, args);
  10726. if (params.var) {
  10727. self.docElement('self.json.var.'+params.var, value);
  10728. } else if (params.name) {
  10729. var actualValue = self.docElement('self.json.var.'+params.name);
  10730. if (actualValue == undefined && typeof value == 'string') actualValue = '';
  10731. if (actualValue == undefined && typeof value == 'number') actualValue = 0;
  10732. if (actualValue == undefined && typeof value == 'object') actualValue = {};
  10733. if (operator) {
  10734. if (operator == '+=') actualValue += value;
  10735. if (operator == '-=') actualValue -= value;
  10736. if (operator == '/=') actualValue /= value;
  10737. if (operator == '*=') actualValue *= value;
  10738. value = actualValue;
  10739. }
  10740. self.docElement('self.json.var.'+params.name, value);
  10741. //self.log('self.json.var[params.name]');
  10742. //self.log(self.json.var[params.name]);
  10743. } else {
  10744. self.log('set command requires "var" parameter');
  10745. }
  10746. } else { // get
  10747. if (params.var) {
  10748. return self.docElement('self.json.var.'+params.var);
  10749. } else if (params.name) {
  10750. return self.docElement('self.json.var.'+params.name);
  10751. } else {
  10752. self.log('set command requires "value" parameter');
  10753. }
  10754. }
  10755. //self.log('value');
  10756. //self.log(value);
  10757. self.log('var ' + params.name + ' = ' + value);
  10758. } */
  10759. this.delay = function (params, selector, args) {
  10760. self.log('delay');
  10761. self.log('selector');
  10762. self.log(selector);
  10763. var duration = params.duration || 1000;
  10764. duration = Number(self.replaceProperties(duration, args));
  10765. self.log(duration);
  10766. if (params.do) {
  10767. setTimeout(function () {
  10768. self.do(params.do, selector, args);
  10769. //self.do(params.do, args, container)
  10770. }, duration);
  10771. }
  10772. };
  10773. this.firebasePasswordReset = function (paramEmail, paramSuccess, paramError) {
  10774. //firebase.auth().languageCode = 'it';
  10775. firebase.auth().useDeviceLanguage();
  10776. auth.sendPasswordResetEmail(paramEmail).then(function () {
  10777. // Email sent.
  10778. if (paramSuccess) self.do(paramSuccess);
  10779. //if (paramSuccess) self.do(paramSuccess);
  10780. }).catch(function (error) {
  10781. // An error happened.
  10782. if (paramError) self.do(paramError, undefined, error.message);
  10783. //if (paramError) self.do(paramError, error.message);
  10784. });
  10785. };
  10786. this.firebaseUpdateProfile = function (params, paramSuccess, paramError) {
  10787. self.log('firebaseUpdateProfile');
  10788. self.log(params);
  10789. auth.currentUser.updateProfile(params).then(function () {
  10790. // Update successful.
  10791. self.log('User Profile Updated Successfully');
  10792. if (paramSuccess) self.do(paramSuccess);
  10793. //if (paramSuccess) self.do(paramSuccess);
  10794. }).catch(function (error) {
  10795. // An error happened.
  10796. if (paramError) self.do(paramError, undefined, error.message);
  10797. //if (paramError) self.do(paramError, error.message);
  10798. });
  10799. };
  10800. this.firebaseRegister = function (params, success, error) {
  10801. if (params.email && params.password) {
  10802. // log the user in
  10803. auth.createUserWithEmailAndPassword(params.email, params.password).then(cred => {
  10804. self.log(cred.user);
  10805. //var.auth.cred = cred;
  10806. var user = firebase.auth().currentUser;
  10807. /* if (user.emailVerified) {
  10808. } else {
  10809. self.sendEmailVerification(params);
  10810. } */
  10811. //if (params.success) self.do(params.success);
  10812. if (params.success) self.do(params.success);
  10813. }).catch(error => {
  10814. // Handle Errors here.
  10815. //if (params.error) self.do(params.error, error.message);
  10816. if (params.error) self.do(params.error, undefined, error.message);
  10817. });
  10818. }
  10819. };
  10820. this.firebaseLogin = function (params) {
  10821. self.log('firebaseLogin');
  10822. self.log(params);
  10823. if (auth) {
  10824. auth.signInWithEmailAndPassword(String(params.email), String(params.password)).then(cred => {
  10825. //var.auth.cred = cred;
  10826. var user = firebase.auth().currentUser;
  10827. //firebase.auth().languageCode = 'it';
  10828. if (user.emailVerified) {
  10829. if (params.success) self.do(self.replaceResult(params, undefined, cred));
  10830. //if (params.success) self.do(self.replaceResult(params, cred));
  10831. } else {
  10832. self.sendEmailVerification(params);
  10833. }
  10834. }).catch(error => {
  10835. self.log('error.code');
  10836. self.log(error.code);
  10837. if (params.error) self.do(self.replaceResult(params, undefined, error.message));
  10838. //if (params.error) self.do(self.replaceResult(params, error.message));
  10839. });
  10840. } else {
  10841. // firebase auth non inizializzato
  10842. }
  10843. };
  10844. this.firebaseLogout = function (params) {
  10845. self.log('firebaseLogout');
  10846. firebase.auth().signOut().then(function () {
  10847. self.log('firebaseLogout SUCCESS');
  10848. self.log(params.success);
  10849. if (params.success) {
  10850. //app.stopMeeting();
  10851. localStorage.clear();
  10852. //self.do(params.success);
  10853. self.do(params.success);
  10854. }
  10855. }).catch(function (error) {
  10856. self.log('firebaseLogout ERROR');
  10857. self.log(error);
  10858. //if (params.error) self.do(params.error);
  10859. if (params.error) self.do(params.error);
  10860. });
  10861. };
  10862. // this.firebaseUserVerify = function (params) {
  10863. // self.log('firebaseUserVerify');
  10864. // self.log(params);
  10865. // self.log(params.oobCode);
  10866. // if (params.oobCode) self.params.codeMail = params.oobCode
  10867. // self.log(self.params.codeMail);
  10868. // //self.do(data);
  10869. // // inviare mail di verifica
  10870. // }
  10871. this.sendEmailVerification = function (params) {
  10872. self.log('sendEmailVerification');
  10873. var user = firebase.auth().currentUser;
  10874. firebase.auth().languageCode = 'it';
  10875. var successAction = params.success || self.reload;
  10876. user.sendEmailVerification().then(function () {
  10877. firebase.auth().signOut();
  10878. self.alert({
  10879. //toast: true,
  10880. icon: "success",
  10881. title: "verifyingemail", // all\'indirizzo "+params.email+"
  10882. html: "msgverifyingemail",
  10883. //confirmButtonText: "Ok",
  10884. //showCancelButton: false,
  10885. showConfirmButton: false,
  10886. confirm: successAction
  10887. });
  10888. });
  10889. };
  10890. /* //self.log('function');
  10891. params = self.replaceProperties(params, args); // -> compile
  10892. if (typeof params == 'object') {
  10893. // jsonic function
  10894. //return self.do(params, args);
  10895. return self.do(params, args);
  10896. } else if (typeof params == 'function') {
  10897. // javascript function
  10898. return params(args);
  10899. } else if (typeof params == 'string') {
  10900. if (json.actions[params]) {
  10901. var functionCompiled = self.replaceResult(json.actions[params], args); // replace {result}
  10902. //functionCompiled = self.replaceProperties(functionCompiled, args);
  10903. // jsonic predefined function
  10904. //return self.do(functionCompiled);
  10905. return self.do(functionCompiled);
  10906. //return self.actionResult(json.actions[params], args);
  10907. } else {
  10908. // javascript function name
  10909. var functionName = self.docElement(params);
  10910. if (functionName)
  10911. if (typeof functionName == 'function') {
  10912. // javascript function
  10913. return functionName(args)
  10914. } else {
  10915. // javascript object
  10916. return functionName;
  10917. }
  10918. else
  10919. self.log('function undefined: '+ params);
  10920. }
  10921. } */
  10922. this.path = function (pathParams, args, separatorParam) {
  10923. var pathString = '';
  10924. var separator = separatorParam || '/';
  10925. /* self.log('this.path');
  10926. self.log(pathParams);
  10927. self.log(args); */
  10928. if (typeof pathParams == 'string') {
  10929. pathString = self.replaceProperties(pathParams, args);
  10930. } else {
  10931. for (var index in pathParams) {
  10932. pathObj = pathParams[index];
  10933. if (pathString !== '') pathString += separator;
  10934. if (pathObj.string)
  10935. pathString += String(pathObj.string);
  10936. else if (pathObj.number)
  10937. pathString += Number(pathObj.number);
  10938. else if (pathObj.function)
  10939. pathString += self.doFunctionByName(pathObj.function, window, '');
  10940. }
  10941. }
  10942. return pathString;
  10943. };
  10944. this.executeFunctionByName = function (functionName, context /*, arguments */) {
  10945. //self.log('executeFunctionByName');
  10946. //self.log(functionName);
  10947. if (functionName) {
  10948. var args = [].slice.call(arguments).splice(2);
  10949. var namespaces = functionName.split(".");
  10950. var func = namespaces.pop();
  10951. for (var i = 0; i < namespaces.length; i++) {
  10952. context = context[namespaces[i]];
  10953. }
  10954. if (context[func] !== undefined) {
  10955. return context[func].apply(context, args);
  10956. } else {
  10957. //self.log('Error: executeFunctionByName');
  10958. //if (functionName !== undefined) {self.log('functionName:'+functionName);}
  10959. }
  10960. } else {
  10961. self.log('executeFunctionByName');
  10962. self.log('functionName undefined');
  10963. }
  10964. };
  10965. this.functions = {};
  10966. this.methods = {
  10967. // main methods
  10968. run: function (params, container, args) { self.run(params, container, args); },
  10969. delay: function (params, container, args) { self.delay(params, container, args); },
  10970. ajax: function (params, container, args) { self.ajax(params, container, args); },
  10971. do: function (params, container, args) { self.do(params, container, args); },
  10972. module: function (params, container, args) { self.module(params, args); },
  10973. js: function (params, container, args) { self.js(params, args); },
  10974. function: function (params, container, args) { self.function(params, args); },
  10975. dispatchEvent: function (params, container, args) { self.dispatchEvent(params, args); },
  10976. // TO DO: check
  10977. lang: function (params, container, args) { self.lang(params, args); },
  10978. find: function (params, container, args) { self.find(params, args); },
  10979. page: function (params, container, args) { self.page(params, args); },
  10980. // DA VERIFICARE
  10981. //dayjs: function (params, args) {self.dayjs(params, args)},
  10982. //moment: function (params, args) {self.moment(params, args)},
  10983. //data: function (params, args) {self.data(params, args)},
  10984. //var: function (params, args) {self.var(params, args)},
  10985. //javascript: function (params, args) {self.javascript(params, args)},
  10986. //color: function (params, args) {self.color(params, args)},
  10987. //select: function (params, args) {self.select(params, args)},
  10988. // LOGIC & DATA
  10989. for: function (params, container, args) { self.for(params, container, args); },
  10990. if: function (params, container, args) { self.if(params, container, args); },
  10991. switch: function (params, container, args) { self.switch(params, args); },
  10992. set: function (params, container, args) { self.set(params, args); },
  10993. // TO DO: check is needs to be renamed to avoid confusion with self.json.data
  10994. data: {
  10995. set: function (params, args) {
  10996. for (var param in params) {
  10997. var value = params[param];
  10998. if (value) value = self.replaceProperties(value, args);
  10999. if (value && args) value = self.replacePropertyWithPrefix(value, 'result', args); // backward compatibility TO DO: remove
  11000. self.element({ path: param, value: value });
  11001. }
  11002. },
  11003. get: function (params) {
  11004. return self.element(params);
  11005. },
  11006. delete: function (params, args) {
  11007. var path = self.replaceProperties(params, args);
  11008. alert(path);
  11009. self.objToDelete = self.element({ path: path });
  11010. delete self.objToDelete;
  11011. },
  11012. add: function (params, args) {
  11013. for (var param in params) {
  11014. var path = self.replaceProperties(param, args);
  11015. var value = self.replaceProperties(params[param], args);
  11016. if (value) {
  11017. var obj = self.element({ path: path }) || '';
  11018. obj += String(value);
  11019. self.element({ path: path, value: obj });
  11020. }
  11021. }
  11022. },
  11023. sum: function (params, args) {
  11024. console.log('%cdeprecated key "sum". Use set{x: "{x}+1"}', 'color:orange');
  11025. console.log(params);
  11026. console.log(args);
  11027. for (var param in params) {
  11028. var path = self.replaceProperties(param, args);
  11029. var value = self.replaceProperties(params[param], args);
  11030. if (value) {
  11031. var obj = self.element({ path: path }) || 0;
  11032. obj += Number(value);
  11033. self.element({ path: path, value: obj });
  11034. }
  11035. }
  11036. },
  11037. sub: function (params, args) {
  11038. console.log('%cdeprecated key "sub". Use set{x: "{x}+1"}', 'color:orange');
  11039. console.log(params);
  11040. console.log(args);
  11041. for (var param in params) {
  11042. var path = self.replaceProperties(param, args);
  11043. var value = self.replaceProperties(params[param], args);
  11044. if (value) {
  11045. var obj = self.element({ path: path }) || 0;
  11046. obj -= Number(value);
  11047. self.element({ path: path, value: obj });
  11048. }
  11049. }
  11050. },
  11051. push: function (params, args) {
  11052. for (var param in params) {
  11053. var path = self.replaceProperties(param, args);
  11054. var value = self.replaceProperties(params[param], args);
  11055. if (value) {
  11056. var obj = self.element({ path: path }) || [];
  11057. obj.push(value);
  11058. self.element({ path: path, value: obj });
  11059. }
  11060. }
  11061. }
  11062. },
  11063. // DOM
  11064. text: function (params, container, args) { self.text(params, container, args); }, // TO DO: -> html
  11065. html: function (params, container, args) { self.html(params, container, args); },
  11066. attr: function (params, container, args) { self.attr(params, container, args); },
  11067. empty: function (params, container, args) { self.empty(params, args); },
  11068. delete: function (params, args) {
  11069. var path = self.replaceProperties(params, args);
  11070. var obj = self.element({ path: path });
  11071. self.log(JSON.stringify(obj));
  11072. self.element({ path: path, delete: true });
  11073. // NOTE: obj = self.element non prende l'oggetto effettivo. quindi element deve contenere tutte le funzioni
  11074. //self.element({path: path, delete: true});
  11075. self.log(obj);
  11076. },
  11077. add: function (params, container, args) {
  11078. for (var param in params) {
  11079. var path = self.replaceProperties(param, args);
  11080. var value = self.replaceProperties(params[param], args);
  11081. /* self.log('value');
  11082. self.log(value); */
  11083. if (value) {
  11084. var obj = self.element({ path: path }) || '';
  11085. obj += String(value);
  11086. self.element({ path: path, value: obj });
  11087. }
  11088. }
  11089. },
  11090. sum: function (params, container, args) {
  11091. for (var param in params) {
  11092. var path = self.replaceProperties(param, args);
  11093. var value = self.replaceProperties(params[param], args);
  11094. if (value) {
  11095. var obj = self.element({ path: path }) || 0;
  11096. obj += Number(value);
  11097. self.element({ path: path, value: obj });
  11098. }
  11099. }
  11100. },
  11101. sub: function (params, container, args) {
  11102. for (var param in params) {
  11103. var path = self.replaceProperties(param, args);
  11104. var value = self.replaceProperties(params[param], args);
  11105. if (value) {
  11106. var obj = self.element({ path: path }) || 0;
  11107. obj -= Number(value);
  11108. self.element({ path: path, value: obj });
  11109. }
  11110. }
  11111. },
  11112. push: function (params, container, args) {
  11113. for (var param in params) {
  11114. var path = self.replaceProperties(param, args);
  11115. var value = self.replaceProperties(params[param], args);
  11116. if (value) {
  11117. var obj = self.element({ path: path }) || [];
  11118. obj.push(value);
  11119. self.element({ path: path, value: obj });
  11120. self.log('push obj');
  11121. self.log(obj);
  11122. }
  11123. }
  11124. },
  11125. // should go in utils.json
  11126. calendar: function (params, container, args) { self.calendar(params, args); }, // to check
  11127. array: function (params, container, args) { self.array(params, args); },
  11128. replace: function (params, container, args) { self.replace(params, args); },
  11129. shuffle: function (array) {
  11130. let currentIndex = array.length, randomIndex;
  11131. // While there remain elements to shuffle.
  11132. while (currentIndex != 0) {
  11133. // Pick a remaining element.
  11134. randomIndex = Math.floor(Math.random() * currentIndex);
  11135. currentIndex--;
  11136. // And swap it with the current element.
  11137. [array[currentIndex], array[randomIndex]] = [
  11138. array[randomIndex], array[currentIndex]
  11139. ];
  11140. }
  11141. return array;
  11142. },
  11143. // should go in ui.json (or ux) module
  11144. alert: function (params, container, args) { self.alert(params, args); }, // change in swal2
  11145. offcanvas: function (params, container, args) { self.offcanvas(params, args); }, // bootstrap / obsolete
  11146. //in: function (params, container, args) {self.in(params, container, args)}, // bootstrap TO DO: replace in code with ui:in
  11147. out: function (params, container, args) { self.out(params, container, args); }, // bootstrap TO DO: replace in code with ui:out
  11148. qrcode: function (params, container, args) { self.qrcode(params, container, args); }, // obsolete TO DO: replace in code with ui:qrcode
  11149. hide: function (params, container, args) { self.hide(params, container, args); }, // TO DO: replace in code with ui:hide
  11150. show: function (params, container, args) { self.show(params, container, args); }, // TO DO: replace in code with ui:show
  11151. toggle: function (params, container, args) { self.toggle(params, container, args); }, // TO DO: replace in code with ui:toggle
  11152. sortablejs: function (params, container, args) { self.sortablejs(params, args); }, // TO DO: replace in code with ui:sortable
  11153. lottie: function (params, container, args) { self.lottie(params, container, args); }, // TO DO: replace in code with ui:lottie
  11154. chart: function (params, container, args) {
  11155. var selector = self.selector(container);
  11156. var element = self.query(selector);
  11157. element.innerHTML = '<canvas width="100%" height="100%"></canvas>';
  11158. const ctx = element.querySelector('canvas');
  11159. const myChart = new Chart(ctx, self.replaceProperties(params));
  11160. },
  11161. animate: function (params, container, args) { self.animate(params, container, args); },
  11162. //editor: function (params, container, args) {self.editor(params, container, args)}, // quill
  11163. // window.dispatchEvent(new Event('resize')); // workaround known ACE bug
  11164. uiUpdate: function (params, container, args) { self.uiUpdate(params, args); },
  11165. swiper: {
  11166. data: {},
  11167. init: function (params, selector, args) {
  11168. //swiperConfig.on = {};
  11169. setTimeout(function () {
  11170. // waits the plugin... TO DO: add this function to a promise
  11171. console.log('swiper inited');
  11172. console.log(selector || params.selector);
  11173. console.log(params.options);
  11174. var swiperConfig = params.options;
  11175. self.methods.swiper.data[params.name] = new Swiper(self.selector(selector || params.selector), swiperConfig);
  11176. console.log(self.methods.swiper.data[params.name]);
  11177. }, 1000);
  11178. }
  11179. },
  11180. // should go in browser.json module
  11181. //export: function (params, container, args) {self.export(params, container, args)}, -> browser
  11182. //console: function (params, container, args) {self.console(params, args)}, // obsolete, changed in log
  11183. link: function (params, container, args) { self.link(params, args); },
  11184. scroll: function (params, container, args) { self.scroll(params, args); },
  11185. reload: function (params, container, args) { self.reload(params, args); },
  11186. timer: function (params, container, args) { self.timer(params, args); },
  11187. setInterval: function (params, container, args) { self.setInterval(params, args); },
  11188. clearInterval: function (params, container, args) { self.clearInterval(params, args); },
  11189. setTimeout: function (params, container, args) { self.setTimeout(params, args); },
  11190. clearTimeout: function (params, container, args) { self.clearTimeout(params, args); },
  11191. local: {
  11192. set: function (params) {
  11193. for (var param in params) {
  11194. var value = params[param];
  11195. if (value) value = self.replaceProperties(value);
  11196. if (typeof value == 'object') value = JSON.stringify(value);
  11197. localStorage.setItem(param, value);
  11198. }
  11199. },
  11200. get: function (key) {
  11201. var localValue = localStorage.getItem(key);
  11202. if (localValue && self.isJsonString(localValue))
  11203. localValue = JSON.parse(localValue);
  11204. return localValue;
  11205. },
  11206. remove: function (key) {
  11207. localStorage.removeItem(key);
  11208. },
  11209. clear: function () {
  11210. localStorage.clear();
  11211. }
  11212. },
  11213. storage: {
  11214. _storage: new WeakMap(),
  11215. set: function (element, key, obj) {
  11216. if (!self.methods.storage._storage.has(element)) {
  11217. self.methods.storage._storage.set(element, new Map());
  11218. }
  11219. self.methods.storage._storage.get(element).set(key, obj);
  11220. },
  11221. get: function (element, key) {
  11222. return self.methods.storage._storage.get(element).get(key);
  11223. },
  11224. has: function (element, key) {
  11225. return self.methods.storage._storage.has(element) && self.methods.storage._storage.get(element).has(key);
  11226. },
  11227. remove: function (element, key) {
  11228. var ret = self.methods.storage._storage.get(element).delete(key);
  11229. if (!self.methods.storage._storage.get(element).size === 0) {
  11230. self.methods.storage._storage.delete(element);
  11231. }
  11232. return ret;
  11233. }
  11234. },
  11235. choose: function (params, container, args) { self.choose(params, container, args); },
  11236. remove: function (params, container, args) { self.remove(params, container, args); },
  11237. part: function (params, container, args) { self.part(params, container, args); },
  11238. blocks: function (params, container, args) { self.part(params, container, args); }, // obsolete
  11239. block: function (params, container, args) { self.part(params, container, args); },
  11240. ace: function (params, container, args) { self.ace(params, container, args); },
  11241. code: function (params, container, args) { self.code(params, container, args); },
  11242. // should go in firebase.json module
  11243. database: function (params, container, args) { self.database(params, args); }, // obsolete (check)
  11244. firebase: function (params, container, args) { self.firebase(params, args); },
  11245. firebaseEvent: {
  11246. action: function (newObj) {
  11247. /* self.logdbRef('firebaseEvent.action');
  11248. self.log('newObj');
  11249. self.log(newObj); */
  11250. /* var path = newObj.path;
  11251. delete newObj.path;
  11252. var pathString = 'self.json.var.db.' + self.replaceAll(path, '/', '.');
  11253. self.log('pathString:'+pathString);
  11254. var dbObj = self.docElement(pathString);
  11255. dbObj = newObj; // update local db */
  11256. var path = newObj.path;
  11257. delete newObj.path;
  11258. //alert(path);
  11259. document.querySelectorAll('[data-firebase="' + path + '"]').forEach(function (element, index) {
  11260. //$('[data-firebase="'+path+'"]').each(function (index) {
  11261. // var element = this;
  11262. var pathString = 'self.json.var.db.' + self.replaceAll(element.getAttribute('data-firebase'), '/', '.'); // data('firebase')
  11263. var dbObj = self.docElement(pathString);
  11264. var firebaseValue = newObj[element.getAttribute('data-value')]; // TODO: not works for nested nodes
  11265. //var template = element.getAttribute('data-template');
  11266. var template = self.dataStorage.get(element, 'data-template');
  11267. //if ($(element).is('ul')) {
  11268. if (element.tagName == 'UL') { // se $(this) è un ul
  11269. //var dbObj = self.docElement(pathString);
  11270. // se il percorso ha più nodi e il dato non è presente nel db locale,
  11271. // va creato un oggetto vuoto per ogni nodo
  11272. //var context = element.getAttribute('data-firebase');
  11273. //self.var.db[context] = newObj; // update local db
  11274. var liTemplate = template.li || template.template; // template.li retro-compatibility
  11275. /* self.log('liTemplate');
  11276. self.log(liTemplate);
  11277. self.log('newObj');
  11278. self.log(newObj); */
  11279. //$(container).empty();
  11280. element.innerHTML = '';
  11281. var items = newObj;
  11282. for (itemKey in items) {
  11283. var item = items[itemKey];
  11284. item.key = itemKey;
  11285. /* 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") {
  11286. alert(JSON.stringify(params.li));
  11287. } */
  11288. //if (dbPath == 'lessons')
  11289. //prompt(JSON.stringify(liTemplate));
  11290. // TO DO: replace with replaceProperty
  11291. var dbParams = self.replaceItems(liTemplate, item, 'item') || '';
  11292. // var dbParams = self.replaceProperties(liTemplate, undefined, item) || '';
  11293. // -> TO DO container = self.elementToSelector(element);
  11294. var container = element.getAttribute('data-selector');
  11295. self.li(dbParams, { selector: container });
  11296. }
  11297. //} else if ( $(element).is('span') || $(element).is('p')) {
  11298. } else if (element.tagName == 'SPAN' || element.tagName == 'P') {
  11299. //$(element).text(firebaseValue);
  11300. element.textContent = firebaseValue;
  11301. } else if (element.tagName == 'SVG') {
  11302. // TODO without JQUERY
  11303. //$(element).children('text').text(firebaseValue);
  11304. } else { // se $(this) non è un ul
  11305. //var dbObj = self.docElement(pathString);
  11306. // se il percorso ha più nodi e il dato non è presente nel db locale,
  11307. // va creato un oggetto vuoto per ogni nodo
  11308. //var context = element.getAttribute('data-firebase');
  11309. //self.var.db[context] = newObj; // update local db
  11310. if (template.blocks || template.html) {
  11311. var blocksTemplate = template.html || template.blocks;
  11312. //$(container).empty();
  11313. element.innerHTML = '';
  11314. var items = newObj;
  11315. self.log('newObj');
  11316. self.log(newObj);
  11317. for (itemKey in items) {
  11318. var item = items[itemKey];
  11319. item.key = itemKey;
  11320. var dbParams = self.replaceProperties(blocksTemplate, undefined, item) || '';
  11321. /* self.log('container');
  11322. self.log(container);
  11323. self.log('dbParams');
  11324. self.log(dbParams); */
  11325. self.html(dbParams, { selector: container });
  11326. }
  11327. }
  11328. if (template.init) self.do(template.init); //self.do(template.init);
  11329. }
  11330. });
  11331. }
  11332. },
  11333. auth: {
  11334. init: function (params, container, args) {
  11335. self.log("auth init");
  11336. auth = firebase.auth();
  11337. auth.onAuthStateChanged(user => {
  11338. self.json.var.user = user;
  11339. if (!user) {
  11340. // No user logged in
  11341. self.log('authStateChanged: GUEST\n');
  11342. // non bisognerebbe chiedere sempre di fare login
  11343. } else {
  11344. // User logged in
  11345. self.log('authStateChanged: USER\n');
  11346. self.log('name: ' + self.user('displayName') + '\nemail: ' + user.email + '\nuid:' + user.uid);
  11347. //self.log('email verificata');
  11348. //self.log(self.userVerified());
  11349. }
  11350. /* self.log('params');
  11351. self.log(params); */
  11352. //self.do(params.onAuthStateChanged);
  11353. self.do(params.onAuthStateChanged);
  11354. //if (!firebaseInitialized) {
  11355. // firebaseInitialized = true;
  11356. //self.do(data);
  11357. //}
  11358. });
  11359. },
  11360. sendEmailVerification: function (params, container, args) {
  11361. self.sendEmailVerification(params);
  11362. },
  11363. login: function (params, container, args) {
  11364. self.log('params.auth');
  11365. self.log(params.auth); // QUESTO E' {var:auth} MA SEMBRA NON RIMPIAZZARLO
  11366. self.log(args); // QUI MI RIPORTA LA PWD, ma perché ultimo args
  11367. var fba = self.replaceProperties(params.auth, args);
  11368. self.log('fba');
  11369. self.log(fba);
  11370. var fbAuth = self.cloneObject(fba);
  11371. self.log('fbAuth');
  11372. self.log(fbAuth);
  11373. if (params.success) fbAuth.success = params.success;
  11374. if (params.error) fbAuth.error = params.error;
  11375. self.firebaseLogin(fbAuth, params.success, params.error);
  11376. },
  11377. register: function (params, container, args) {
  11378. //var fbAuth = self.replaceTags({text: params.auth, args: args});
  11379. //var fbAuth = self.replaceResult(params.auth, args);
  11380. var fbAuth = self.replaceProperties(params.auth, args);
  11381. fbAuth.success = params.success;
  11382. fbAuth.error = params.error;
  11383. //alert(JSON.stringify(fbAuth))
  11384. self.firebaseRegister(fbAuth, params.success, params.error);
  11385. },
  11386. updateProfile: function (params, container, args) {
  11387. //params.profile = self.replaceTags({text: params.profile, args: args});
  11388. //params.profile = self.replaceResult(params.profile, args);
  11389. params.profile = self.replaceProperties(params.profile, args);
  11390. self.firebaseUpdateProfile(params.profile, params.success, params.error);
  11391. },
  11392. passwordReset: function (params, container, args) {
  11393. //params.email = self.replaceTags({text: params.email, args: args});
  11394. //params.email = self.replaceResult(params.email, args);
  11395. params.email = self.replaceProperties(params.email, args);
  11396. self.firebasePasswordReset(params.email, params.success, params.error);
  11397. },
  11398. logout: function (params, container, args) {
  11399. self.firebaseLogout(params);
  11400. }
  11401. },
  11402. // should go in mobile.json module
  11403. thunkable: function (params, container, args) { self.thunkable(params, args); },
  11404. // should go in 3d.json module
  11405. modelViewer: {
  11406. events: {},
  11407. on: function (params) {
  11408. let container = self.selector(params.selector || params.container);
  11409. let element = self.query(container);
  11410. self.log('modelViewer on');
  11411. self.log('container');
  11412. self.log(container);
  11413. self.log('element');
  11414. self.log(element);
  11415. if (element) {
  11416. self.methods.modelViewer.events[container] = {}; // use self.element
  11417. //let events = ['load', 'preload'];
  11418. //for (var event in events) {
  11419. var event = 'load';
  11420. if (params[event]) {
  11421. //self.element({root: 'self.methods.modelViewer.events', path: container+'.'+event, value: params[event]})
  11422. self.methods.modelViewer.events[container][event] = params[event];
  11423. self.log('modelViewer element');
  11424. self.log(element);
  11425. element.addEventListener(event, (e) => {
  11426. self.log('modelViewer event');
  11427. self.log(e);
  11428. let container = e.path[0].getAttribute('data-selector');
  11429. self.log(container);
  11430. //self.do(self.methods.modelViewer.events[container][e.type]);
  11431. self.do(self.methods.modelViewer.events[container][e.type]);
  11432. });
  11433. }
  11434. }
  11435. },
  11436. set: function (params) {
  11437. let element = self.query(self.selector(params.selector || params.container));
  11438. if (element) {
  11439. if (params.color) {
  11440. let color = params.color.split(',').map(numberString => parseFloat(numberString));
  11441. self.log('Changing color to: ', color);
  11442. const [material] = element.model.materials;
  11443. material.pbrMetallicRoughness.setBaseColorFactor(color);
  11444. }
  11445. if (params.exposure) element.exposure = params.exposure;
  11446. if (params.shadow) element.shadowIntensity = params.shadow;
  11447. if (params.orientation) element.orientation = params.orientation;
  11448. }
  11449. }
  11450. }
  11451. };
  11452. this.googleSignInPopup = function () {
  11453. self.log('googleSignInPopup');
  11454. var provider = new firebase.auth.GoogleAuthProvider();
  11455. firebase.auth().useDeviceLanguage(); // lingua del dispositivo
  11456. firebase.auth()
  11457. .signInWithPopup(provider)
  11458. .then((result) => {
  11459. // @type {firebase.auth.OAuthCredential}
  11460. var credential = result.credential;
  11461. // This gives you a Google Access Token. You can use it to access the Google API.
  11462. var token = credential.accessToken;
  11463. // The signed-in user info.
  11464. var user = result.user;
  11465. window.location.reload();
  11466. // ...
  11467. }).catch((error) => {
  11468. // Handle Errors here.
  11469. var errorCode = error.code;
  11470. var errorMessage = error.message;
  11471. // The email of the user's account used.
  11472. var email = error.email;
  11473. // The firebase.auth.AuthCredential type that was used.
  11474. var credential = error.credential;
  11475. });
  11476. };
  11477. /* this.googleSignInPopup = function () {
  11478. // [START auth_google_signin_popup]
  11479. self.log('googleSignInPopup');
  11480. var provider = new firebase.auth.GoogleAuthProvider();
  11481. //provider.addScope('https://www.googleapis.com/auth/contacts.readonly'); //check security
  11482. //provider.addScope('https://www.googleapis.com/auth/calendar');
  11483. //var languageApp = jsonic.var.language || 'en';
  11484. //firebase.auth().languageCode = 'it';//languageApp;
  11485. //self.log(provider);
  11486. //return;
  11487. firebase.auth()
  11488. .signInWithPopup(provider)
  11489. .then((result) => {
  11490. // @type {firebase.auth.OAuthCredential}
  11491. var credential = result.credential;
  11492. // This gives you a Google Access Token. You can use it to access the Google API.
  11493. var token = credential.accessToken;
  11494. // The signed-in user info.
  11495. var user = result.user;
  11496. //######### result ########//
  11497. self.log("credential");
  11498. self.log(credential);
  11499. self.log("token");
  11500. self.log(token);
  11501. self.log("user");
  11502. self.log(user);
  11503. window.location.reload();
  11504. // ...
  11505. }).catch((error) => {
  11506. // Handle Errors here.
  11507. var errorCode = error.code;
  11508. self.log('errorCode');
  11509. self.log(errorCode);
  11510. var errorMessage = error.message;
  11511. self.log('errorMessage');
  11512. self.log(errorMessage);
  11513. // The email of the user's account used.
  11514. var email = error.email;
  11515. self.log('email');
  11516. self.log(email);
  11517. // The firebase.auth.AuthCredential type that was used.
  11518. var credential = error.credential;
  11519. self.log('credential');
  11520. self.log(credential);
  11521. // ...
  11522. });
  11523. // [END auth_google_signin_popup]
  11524. } */
  11525. /* this.auth = function (params, args) {
  11526. self.log('auth');
  11527. self.log(params);
  11528. if (params.do == 'init') {
  11529. auth = firebase.auth();
  11530. auth.onAuthStateChanged(user => {
  11531. self.json.var.user = user;
  11532. if (!user) {
  11533. // No user logged in
  11534. self.log('authStateChanged: GUEST\n');
  11535. // non bisognerebbe chiedere sempre di fare login
  11536. } else {
  11537. // User logged in
  11538. self.log('authStateChanged: USER\n');
  11539. self.log('name: '+self.user('displayName') + '\nemail: '+user.email + '\nuid:'+ user.uid);
  11540. //self.log('email verificata');
  11541. //self.log(self.userVerified());
  11542. }
  11543. //self.log('params.onAuthStateChanged');
  11544. //self.log(params.onAuthStateChanged);
  11545. self.do(params.onAuthStateChanged);
  11546. //if (!firebaseInitialized) {
  11547. // firebaseInitialized = true;
  11548. //self.do(data);
  11549. //}
  11550. });
  11551. } else if (params.do == 'sendEmailVerification') {
  11552. self.sendEmailVerification(params);
  11553. } else if (params.do == 'login') {
  11554. self.log('params.auth');
  11555. self.log(params.auth);
  11556. var fba = self.replaceProperties(params.auth, args);
  11557. self.log('fba');
  11558. self.log(fba);
  11559. var fbAuth = self.cloneObject(fba);
  11560. self.log('fbAuth');
  11561. self.log(fbAuth);
  11562. if (params.success) fbAuth.success = params.success;
  11563. if (params.error) fbAuth.error = params.error;
  11564. self.firebaseLogin(fbAuth, params.success, params.error);
  11565. } else if (params.do == 'register') {
  11566. //var fbAuth = self.replaceTags({text: params.auth, args: args});
  11567. //var fbAuth = self.replaceResult(params.auth, args);
  11568. var fbAuth = self.replaceProperties(params.auth, args);
  11569. fbAuth.success = params.success;
  11570. fbAuth.error = params.error;
  11571. //alert(JSON.stringify(fbAuth))
  11572. self.firebaseRegister(fbAuth, params.success, params.error);
  11573. } else if (params.do == 'updateProfile') {
  11574. //params.profile = self.replaceTags({text: params.profile, args: args});
  11575. //params.profile = self.replaceResult(params.profile, args);
  11576. params.profile = self.replaceProperties(params.profile, args);
  11577. self.firebaseUpdateProfile(params.profile, params.success, params.error);
  11578. } else if (params.do == 'passwordReset') {
  11579. //params.email = self.replaceTags({text: params.email, args: args});
  11580. //params.email = self.replaceResult(params.email, args);
  11581. params.email = self.replaceProperties(params.email, args);
  11582. self.firebasePasswordReset(params.email, params.success, params.error);
  11583. } else if (params.do == 'logout') {
  11584. self.firebaseLogout(params);
  11585. }
  11586. // else
  11587. //self.database(params, args);
  11588. }
  11589. */
  11590. /* this.db = function (params, args) {
  11591. if (typeof params == 'string')
  11592. return self.db(params, args);
  11593. else
  11594. self.firebase(params, args);
  11595. } */
  11596. this.console = function (params, args) {
  11597. //value = self.replaceProperties(params);
  11598. //console.log('JSONIC: '+value, 'color:pink');
  11599. if (typeof params.log == 'string' && params.color) {
  11600. var color = params.color || 'white';
  11601. console.log('%c' + self.replaceProperties(params.log), 'color:' + color);
  11602. } else {
  11603. console.log(self.replaceProperties(params.log || params));
  11604. }
  11605. };
  11606. this.module = function (params, args) {
  11607. if (typeof params == 'string') {
  11608. var nameReplaced = self.replaceProperties(params, args);
  11609. return self.element({ root: self.modules, path: nameReplaced });
  11610. } else {
  11611. if (params.name) {
  11612. if (params.value) {
  11613. var name = self.replaceProperties(params.name, args);
  11614. //var value = self.actionResult(params.value, args);
  11615. var value = self.replaceProperties(value, args);
  11616. self.log('module');
  11617. self.log(name);
  11618. self.log('value');
  11619. self.log(value);
  11620. self.log(value.app.html.div.div[0].text.lang.en);
  11621. self.modules[name] = value;
  11622. } else if (params.url) {
  11623. self.addModule(params); // TO DO: return?
  11624. }
  11625. }
  11626. }
  11627. };
  11628. this.db = function (params, args) {
  11629. self.log('db');
  11630. if (typeof params == 'string') {
  11631. var paramsReplaced = self.replaceProperties(params, args);
  11632. self.log('paramsReplaced');
  11633. self.log(paramsReplaced);
  11634. self.log(self.var('db.' + paramsReplaced, args));
  11635. //var varValue = self.docElement('self.json.var.db.'+name);
  11636. return self.var('db.' + paramsReplaced, args); // to do: change with self.element({path: 'db.'+paramsReplaced}})
  11637. /*
  11638. // questa versione non funzionava. vuol dire che this.var ha un errore nel caso di oggetto
  11639. return self.var({
  11640. name: 'db.'+paramsReplaced
  11641. }, args);
  11642. */
  11643. } /* else {
  11644. return self.actionResult(params, args);
  11645. } */
  11646. };
  11647. this.firebase = function (params, args) {
  11648. if (params.initializeApp) {
  11649. var firebaseConfig = self.replaceProperties(params.initializeApp);
  11650. firebase.initializeApp(firebaseConfig);
  11651. } else {
  11652. self.database(params, args);
  11653. }
  11654. };
  11655. this.database = function (params, args) {
  11656. //console.log('database');
  11657. if (params.do == 'init') {
  11658. database = firebase.database();
  11659. self.log('database');
  11660. self.log(database);
  11661. } else {
  11662. if (database) {
  11663. if (typeof params == 'string') {
  11664. return self.db(params, args); // local db
  11665. } else {
  11666. if (params) {
  11667. if (params.path) {
  11668. params.path = self.path(params.path, args);
  11669. }
  11670. /* console.log('params.path');
  11671. console.log(params.path); */
  11672. /* if (params.value)
  11673. params.value = params.value; */ //self.value({string: params.value});
  11674. if (params.value) {
  11675. /* self.log("params.value pre replace");
  11676. self.log(params.value); */
  11677. //params.value = self.replaceTags({text: params.value, args: args});
  11678. //params.value = self.replaceResult(params.value, args);
  11679. //params.value = self.replaceProperties(params.value, args);
  11680. //params.value = self.actionResult(params.value, args);
  11681. params.value = self.replaceProperties(params.value, args);
  11682. self.log("params.value post replace");
  11683. self.log(params.value);
  11684. }
  11685. /* self.log('params to FIREBASE');
  11686. self.log(params); */
  11687. // params.value = "${var.newDevice}"
  11688. //var newDevice = `${params.value}`;
  11689. //var newDevice = `${var.newDevice}`;
  11690. if (params.do == 'init') {
  11691. } else if (params.do == 'increase') {
  11692. self.firebaseIncrease(params);
  11693. } else if (params.do == 'get') {
  11694. self.firebaseGet(params.path, function (result) {
  11695. if (result.success) {
  11696. if (result.data) {
  11697. self.log('firebase get SUCCESS');
  11698. self.log(params.success);
  11699. if (params.on && params.on.success) self.do(params.on.success, undefined, result);
  11700. //if (params.on && params.on.success) self.do(params.on.success, result);
  11701. } else {
  11702. self.log('firebase get no result.data ERROR');
  11703. //if (params.on && params.on.error) self.do(params.on.error);
  11704. if (params.on && params.on.error) self.do(params.on.error);
  11705. }
  11706. } else {
  11707. self.log('firebase get ERROR');
  11708. //if (params.on && params.on.error) self.do(params.on.error, result);
  11709. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  11710. // alert errore di connessione. alert riprova
  11711. }
  11712. });
  11713. } else if (params.do == 'new' && params.value) {
  11714. var newKey = self.getKey(params.path);
  11715. self.firebaseSet(params.path + '/' + newKey, params.value, function (result) {
  11716. if (result.success) {
  11717. self.log('firebase set SUCCESS');
  11718. if (params.on && params.on.success) self.do(params.on.success, undefined, result);
  11719. //if (params.on && params.on.success) self.do(params.on.success, result);
  11720. } else {
  11721. self.log('firebase set ERROR');
  11722. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  11723. //if (params.on && params.on.error) self.do(params.on.error, result);
  11724. // alert errore di connessione. alert riprova
  11725. }
  11726. });
  11727. } else if (params.do == 'remove' && params.path) {
  11728. self.firebaseRemove(params.path, function (result) {
  11729. if (result.success) {
  11730. self.log('firebase set SUCCESS');
  11731. //if (params.on && params.on.success) self.do(params.on.success, result);
  11732. if (params.on && params.on.success) self.do(params.on.success, undefined, result);
  11733. } else {
  11734. self.log('firebase set ERROR');
  11735. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  11736. //if (params.on && params.on.success) self.do(params.on.success, result);
  11737. // alert errore di connessione. alert riprova
  11738. }
  11739. });
  11740. } else if (params.do == 'addListener') {
  11741. self.firebaseAddListener(params);
  11742. } else if (params.do == 'removeListener') {
  11743. self.firebaseRemoveListener(params);
  11744. } else if (params.do == 'update') {
  11745. if (params.value) { // 'set' is the default action with 'value' param
  11746. self.firebaseUpdate(params.path, params.value, function (result) {
  11747. if (result.success) {
  11748. self.log('firebase update SUCCESS');
  11749. if (params.on && params.on.success) self.do(params.on.success, undefined, result);
  11750. //if (params.on && params.on.success) self.do(params.on.success, result);
  11751. } else {
  11752. self.log('firebase update ERROR');
  11753. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  11754. //if (params.on && params.on.error) self.do(params.on.error, result);
  11755. // alert errore di connessione. alert riprova
  11756. }
  11757. });
  11758. } else {
  11759. self.log('data update requires value param');
  11760. }
  11761. } else if (params.do == 'push') {
  11762. if (params.value) { // 'set' is the default action with 'value' param
  11763. self.firebasePush(params.path, params.value, function (result) {
  11764. if (result.success) {
  11765. self.log('firebase push SUCCESS');
  11766. if (params.on && params.on.success) self.do(params.on.success, undefined, result);
  11767. //if (params.on && params.on.success) self.do(params.on.success,result);
  11768. } else {
  11769. self.log('firebase push ERROR');
  11770. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  11771. //if (params.on && params.on.error) self.do(params.on.error, result);
  11772. // alert errore di connessione. alert riprova
  11773. }
  11774. });
  11775. } else {
  11776. self.log('data push requires value param');
  11777. }
  11778. } else {
  11779. if (params.value) { // 'set' is the default action with 'value' param
  11780. self.firebaseSet(params.path, params.value, function (result) {
  11781. if (result.success) {
  11782. self.log('firebase set SUCCESS');
  11783. if (params.on && params.on.success) self.do(params.on.success, undefined, result);
  11784. //if (params.on && params.on.success) self.do(params.on.success,result);
  11785. } else {
  11786. self.log('firebase set ERROR');
  11787. if (params.on && params.on.error) self.do(params.on.error, undefined, result);
  11788. //if (params.on && params.on.error) self.do(params.on.error, result);
  11789. // alert errore di connessione. alert riprova
  11790. }
  11791. });
  11792. }
  11793. }
  11794. }
  11795. }
  11796. } else {
  11797. self.log('"database" function needs to be initialised');
  11798. }
  11799. }
  11800. };
  11801. this.ajax = function (params, selectorParams, args) {
  11802. /* self.log('ajax');
  11803. // TO DO: selectorParams
  11804. self.log('ajax');
  11805. self.log('params');
  11806. self.log(params);
  11807. self.log('args');
  11808. self.log(args); */
  11809. if (params.url) {
  11810. //var url = self.compile(params.url, args);
  11811. var url = self.replaceProperties(params.url, args);
  11812. var data;
  11813. if (params.data)
  11814. data = JSON.stringify(self.replaceProperties(params.data, args));
  11815. //data = JSON.stringify(self.compile(params.data, args));
  11816. /* self.log('data');
  11817. self.log(data); */
  11818. var type = params.type || 'POST';
  11819. var request = new XMLHttpRequest();
  11820. request.open(type, url, true);
  11821. //request.setRequestHeader("Accept", "application/json");
  11822. //request.setRequestHeader('Content-Type', 'application/json');
  11823. /* request.onreadystatechange = function () {
  11824. if (r.readyState != 4 || r.status != 200) return;
  11825. alert("Success: " + r.responseText);
  11826. } */
  11827. request.onload = function () {
  11828. self.log('onload');
  11829. self.log(this);
  11830. if (this.status >= 200 && this.status < 400) {
  11831. // Success!
  11832. var result = {};
  11833. //try {
  11834. var response = this.response;
  11835. response = response.replace(/(\\\")/g, '&quot;');
  11836. try {
  11837. response = decodeURI(response);
  11838. } catch (error) {
  11839. /* console.log('response');
  11840. console.log(response); */
  11841. console.log('decodeURI error');
  11842. console.log(error);
  11843. }
  11844. result.response = self.parse(response);
  11845. result.status = this.status;
  11846. result.header = this.getAllResponseHeaders().split('\r\n').reduce((resultHeader, current) => {
  11847. let [name, value] = current.split(': ');
  11848. resultHeader[name] = value;
  11849. return resultHeader;
  11850. }, {});
  11851. //} catch (e) {
  11852. //}
  11853. self.log('result');
  11854. self.log(result);
  11855. if (params.success)
  11856. self.do(params.success, undefined, result);
  11857. //self.do(params.success, result);
  11858. //self.do(self.replaceProperty(params.success, 'result', result), result);
  11859. } else {
  11860. // We reached our target server, but it returned an error
  11861. if (params.error)
  11862. self.do(params.error, undefined, 'Server error');
  11863. //self.do(params.error, 'Server error');
  11864. }
  11865. };
  11866. request.onerror = function (error) {
  11867. // There was a connection error of some sort
  11868. self.log('error');
  11869. self.log(error);
  11870. self.log('this');
  11871. self.log(this);
  11872. if (params.error)
  11873. self.do(params.error, undefined, 'Server unavailable');
  11874. //self.do(params.error, 'Server unavailable');
  11875. };
  11876. //request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
  11877. if (data)
  11878. request.send(data);
  11879. else
  11880. request.send();
  11881. } else {
  11882. self.log('ajax method requires url parameter');
  11883. }
  11884. /* $.ajax({
  11885. url: paramsReplaced.url,
  11886. type: params.type || 'post',
  11887. //dataType: 'json', // questo dovrebbe evitare JSON.parse
  11888. //dataType: 'text', // verificare se necessario
  11889. data: paramsReplaced.data || {},
  11890. success: function (result) {
  11891. self.log('ajax');
  11892. self.log('result');
  11893. self.log(result);
  11894. self.do(params.success, result);
  11895. //self.do(data); // in .params dovrebbe andare il resto
  11896. },
  11897. error: function (error) {
  11898. var errorText = error.responseText || error;
  11899. self.do(params.error, errorText);
  11900. //self.do(data); // in .params dovrebbe andare il resto
  11901. }
  11902. }); */
  11903. };
  11904. /* View in fullscreen */
  11905. this.openFullscreen = function (id) {
  11906. var element = document.getElementById(id);
  11907. if (screenfull.isEnabled) {
  11908. screenfull.request(element);
  11909. }
  11910. };
  11911. /* this.addListener = function(params) {
  11912. var selector = self.selector(params);
  11913. if (selector)
  11914. $(selector).on(params.event, self.do(params.action));
  11915. //event.stopPropagation();
  11916. } */
  11917. /* Close fullscreen */
  11918. this.closeFullscreen = function () {
  11919. //document.exitFullscreen();
  11920. screenfull.off('change'); // callback
  11921. };
  11922. /* this.list = function (params, selectorParams) {
  11923. var container = (selectorParams) ? self.selector(selectorParams) : params.container;
  11924. var selector = self.selector(self.extend({}, params, selectorParams));
  11925. if (selector) {
  11926. if (params.list) params.items = params.list; // retro-compatibilità
  11927. if (params.listAction) $(selector).data('listAction', params.listAction);
  11928. if (params.listClass) $(selector).data('listClass', params.listClass); // ul
  11929. if (params.items) {
  11930. $(selector).empty();
  11931. var index = 0;
  11932. //params.items = self.replaceTags({text:params.items, args:selectorParams});
  11933. //params.items = self.replaceResult(params.items, selectorParams);
  11934. params.items = self.replaceProperties(params.items, selectorParams);
  11935. for (var itemKey in params.items) {
  11936. // da rimuovere id="item'+itemKey+'" href=""
  11937. //self.log('PARAMETRI');
  11938. //self.log(itemKey);
  11939. //self.log(params.items);
  11940. $(selector).append('<li data-index="'+itemKey+'" class="list-group-item"></li>');
  11941. var item = params.items[itemKey];
  11942. //var itemSelector = selector + ' li:eq(' + index + ')';
  11943. var itemSelector = selector + ' li:eq(' + itemKey + ')';
  11944. // Item action
  11945. var itemAction;
  11946. if (item.action)
  11947. itemAction = item.action;
  11948. else if (params.action)
  11949. itemAction = params.action;
  11950. else if ($(selector).data('listAction'))
  11951. itemAction = $(selector).data('listAction');
  11952. item.action = itemAction;
  11953. if (item.action) {
  11954. $(itemSelector).addClass('list-group-item-action');
  11955. $(itemSelector).css('cursor', 'pointer');
  11956. }
  11957. if (item.color) $(itemSelector).css('color', item.color);
  11958. if (item.background) $(itemSelector).css('background', item.background);
  11959. //$(itemSelector).append('<div></div>');
  11960. var itemFields = params.items[itemKey].fields || params.items[itemKey]; // retro-compatibilità
  11961. //self.log('itemFields');
  11962. //self.log(itemFields);
  11963. for (var itemField in itemFields) {
  11964. var field = itemFields[itemField];
  11965. //self.log(field);
  11966. if (itemField == 'icons') {
  11967. self.icons(field, {container: itemSelector});
  11968. } else if ((itemField != 'params') && (itemField != 'action')) { // retro-compatibilità
  11969. $(itemSelector).append('<span data-field="'+itemField+'">'+self.text(itemFields[itemField])+'</span>');
  11970. }
  11971. }
  11972. // action
  11973. if (item.action) {
  11974. $(itemSelector).data('onData', item);
  11975. $(itemSelector).on(self.touch, function (event) {
  11976. event.stopPropagation();
  11977. self.onEvent(this, event);
  11978. });
  11979. }
  11980. // events
  11981. if (item.on) self.on(item.on, {container: selector});
  11982. index++;
  11983. }
  11984. } else if (params.append) {
  11985. // aggiunge una riga alla fine (calcolare path)
  11986. } else if (params.prepend) {
  11987. // aggiunge una riga all'inizio (calcolare path)
  11988. // sballa tutti i dati presenti in var.functions
  11989. // sarebbe meglio mem in data value tutto il json
  11990. // azione
  11991. }
  11992. // List classes
  11993. //if (params.id) $(selector).attr('id', params.id);
  11994. var listClass = $(selector).data('listClass');
  11995. if (listClass) {
  11996. var ulClass = listClass.ul || '';
  11997. var liClass = listClass.li || '';
  11998. $(selector).addClass(ulClass);
  11999. $(selector + ' > li').addClass(liClass);
  12000. var index = 0;
  12001. for (var field in listClass.fields) {
  12002. var fieldClass = listClass.fields[field] || '';
  12003. $(selector + ' > li > span[data-field='+field+']').addClass(fieldClass);
  12004. index++;
  12005. }
  12006. }
  12007. }
  12008. } */
  12009. this.scroll = function (params) {
  12010. // https://developer.mozilla.org/en-US/docs/Web/API/Element/scrollIntoView
  12011. // {id, class, value}
  12012. var selector = self.selector(params.selector || params.container);
  12013. var block = document.querySelector(selector);
  12014. //var offset = elem.dataset.offset ? parseInt(elem.dataset.offset) : 0;
  12015. if (block) {
  12016. var bodyOffset = document.body.getBoundingClientRect().top;
  12017. window.scrollTo({
  12018. top: block.getBoundingClientRect().top - bodyOffset, // + offset,
  12019. behavior: 'smooth'
  12020. });
  12021. } else {
  12022. self.log('scroll to unknown element: ' + selector);
  12023. }
  12024. };
  12025. /* this.scroll = function (params) {
  12026. // var selector = self.selector(params);
  12027. //var obj = $(selector).get(0);
  12028. var selector = "g."+params.class+".myLabelStyle."+params.value;
  12029. //var parent = $(selector).parent().get(0);
  12030. //document.querySelector(selector).scrollIntoView();
  12031. //self.resizeEvent(); // bug workaround
  12032. //$(selector).parent().scrollTop($(selector).position().top);
  12033. $(selector).parent().animate({
  12034. //scrollTop: $(selector).position().top
  12035. //scrollTop: $(selector).position().top,
  12036. transform: 'translate(0,-'+$(selector).position().top+'), scale(1)'
  12037. });
  12038. }
  12039. */
  12040. //------------------------
  12041. /* this.do = function (data, args) {
  12042. if (data) {
  12043. if (typeof data == 'string' && self.json.actions[data]) {
  12044. self.do(self.json.actions[data], args);
  12045. } else {
  12046. if (!data.index) data.index = 0;
  12047. if (!data.tasks) {
  12048. if (Array.isArray(data)) {
  12049. if (data.index < data.length) {
  12050. self.do(data[data.index]);
  12051. data.index = data.index +1;
  12052. self.do(data);
  12053. } else {
  12054. delete data.index;
  12055. }
  12056. } else {
  12057. self.do(data);
  12058. }
  12059. //} else if (data.tasks.length > 0) {
  12060. } else {
  12061. if (data.index < data.tasks.length) {
  12062. var currentTask = data.tasks[data.index];
  12063. //var currentTask = data.tasks.shift();
  12064. if (currentTask.params == undefined) {currentTask.params = {}}
  12065. if (data.params == undefined) {data.params = {}}
  12066. if (currentTask.if == undefined) {currentTask.if = true}
  12067. var taskParams = currentTask.params; // parametri specifici del task
  12068. taskParams.params = data.params;
  12069. taskParams.index = data.index+1;
  12070. //for (var param in data.params) {taskParams[param] = data.params[param]; } // merge
  12071. taskParams.tasks = data.tasks;
  12072. var taskIf = (typeof currentTask.if == "function") ? currentTask.if() : currentTask.if;
  12073. if (taskIf) {
  12074. if (currentTask.delay !== undefined) {
  12075. setTimeout(function () {
  12076. self.do(currentTask.task, taskParams);
  12077. }, currentTask.delay);
  12078. } else if (currentTask.interval !== undefined) {
  12079. self.createTaskInterval(currentTask);
  12080. } else {
  12081. self.do(currentTask.task,taskParams);
  12082. }
  12083. } else {
  12084. self.do(taskParams);
  12085. }
  12086. }
  12087. }
  12088. }
  12089. }
  12090. } */
  12091. /* this.playTaskInterval = function (taskFunction) {
  12092. self.log('playTaskInterval');
  12093. var taskName = taskFunction.name;
  12094. if (tasksIntervals[taskName]) {
  12095. clearInterval(tasksIntervals[taskName].id);
  12096. tasksIntervals[taskName].id = setInterval(function () {
  12097. tasksIntervals[taskName].task(tasksIntervals[taskName].params);
  12098. }, tasksIntervals[taskName].interval);
  12099. } else {
  12100. self.log('taskName: '+taskName);
  12101. }
  12102. }
  12103. this.stopTaskInterval = function (taskFunction) {
  12104. self.log('stopTaskInterval');
  12105. var taskName = taskFunction.name;
  12106. if (tasksIntervals[taskFunction.name]) {
  12107. clearInterval(tasksIntervals[taskFunction.name].id);
  12108. } else {
  12109. self.log('taskName: '+taskName);
  12110. }
  12111. }
  12112. this.createTaskInterval = function (myTask) {
  12113. tasksIntervals[myTask.task.name] = {};
  12114. tasksIntervals[myTask.task.name].task = myTask.task;
  12115. tasksIntervals[myTask.task.name].params = myTask.params;
  12116. tasksIntervals[myTask.task.name].interval = myTask.interval;
  12117. self.playTaskInterval(myTask.task.name);
  12118. }
  12119. this.addTimedTask = function (data) {
  12120. self.log('addTimedTask');
  12121. if (data.frequence && data.task) {
  12122. if (!data.active) {data.active = true;}
  12123. if (!timedTasks[data.frequence]) {timedTasks[data.frequence] = {}}
  12124. timedTasks[data.frequence][data.task] = {active:data.active, params:{}};
  12125. if (data.params) {
  12126. timedTasks[data.frequence][id].params = data.params;
  12127. }
  12128. }
  12129. }
  12130. this.removeTimedTask = function (data) {
  12131. self.log('removeTimedTask');
  12132. if (data.frequence && data.task) {
  12133. delete timedTasks[data.frequence][data.task];
  12134. }
  12135. }
  12136. this.doTimedTask = function (data) {
  12137. self.log('doTimedTask');
  12138. self.log(data);
  12139. for (var task in timedTasks[data.frequence]) {
  12140. var taskObj = timedTasks[data.frequence][task];
  12141. if (taskObj.active) {
  12142. self.do(task, taskObj.params);
  12143. }
  12144. }
  12145. } */
  12146. //------------------------
  12147. // CSS METHODS
  12148. //------------------------
  12149. /* // SELETTORI
  12150. var previewPanel = '.appPanel[data-value="pnlPreview"]';
  12151. var toolsPanel = '.appPanel[data-value="pnlTools"]';
  12152. var stagePanel = '.framePanel[data-value="pnlStage"]';
  12153. var devicePanel = '.framePanel[data-value="pnlDevice"]';
  12154. this.closePanel = function(value) {
  12155. self.log(value);
  12156. switch (value) {
  12157. case 'closePanelTools':
  12158. $(toolsPanel).fadeOut();
  12159. $(previewPanel).fadeIn();
  12160. case 'closePanelFrame':
  12161. $(devicePanel).fadeOut();
  12162. $(stagePanel).fadeIn();
  12163. }
  12164. }
  12165. */
  12166. //------------------------
  12167. // CSS METHODS
  12168. //------------------------
  12169. /* this.cssProp = function (propPar) {
  12170. var cssObj = {transform: ''};
  12171. if ((propPar.x) && (propPar.y)) {cssObj.transform += ' translate('+propPar.x+'px,'+propPar.y+'px)'; }
  12172. if (propPar.rotateY) {cssObj.transform += ' rotateY('+propPar.rotateY+'deg)'; }
  12173. if (propPar.rotateX) {cssObj.transform += ' rotateX('+propPar.rotateX+'deg)'; }
  12174. if (propPar.scale) {cssObj.transform += ' scale('+propPar.scale+','+propPar.scale+')'; }
  12175. if (propPar.deg) {cssObj.transform += ' rotate('+propPar.deg+'deg)'; }
  12176. if (propPar.opacity) {cssObj.opacity = propPar.opacity;}
  12177. return cssObj;
  12178. } */
  12179. /* this.getCSS = function (data) {
  12180. var $inspector = $("<div>").css('display', 'none').addClass(data.class);
  12181. $("body").append($inspector); // add to DOM, in order to read the CSS property
  12182. try {
  12183. var props = [];
  12184. for (i=0; i<data.properties.length; i++) {props.push($inspector.css(data.properties[i]))}
  12185. return props;
  12186. } finally {
  12187. $inspector.remove(); // and remove from DOM
  12188. }
  12189. }
  12190. this.getTransform = function (object) {
  12191. var transformArray = $(object).css('transform').match(/(-?[0-9\.]+)/g);
  12192. var objTransform = {x:0,y:0};
  12193. objTransform.x = transformArray[4];
  12194. objTransform.y = transformArray[5];
  12195. return objTransform;
  12196. } */
  12197. var getClickPosition = function (e) {
  12198. var parentPosition = getPosition(e.currentTarget);
  12199. var xPosition = e.clientX - parentPosition.x;
  12200. var yPosition = e.clientY - parentPosition.y;
  12201. };
  12202. function getPosition(element) {
  12203. var xPosition = 0;
  12204. var yPosition = 0;
  12205. while (element) {
  12206. xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
  12207. yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
  12208. element = element.offsetParent;
  12209. }
  12210. return { x: xPosition, y: yPosition };
  12211. }
  12212. /* var cssTransform = function (namePar, fromPar, toPar) {
  12213. var sdDefineFrom = {transform: ''};
  12214. var sdDefineTo = {transform: ''};
  12215. if ((fromPar.x) && (fromPar.y)) {sdDefineFrom.transform += ' translate('+fromPar.x+'px,'+fromPar.y+'px)'; }
  12216. if ((toPar.x) && (toPar.y)) {sdDefineTo.transform += ' translate('+toPar.x+'px,'+toPar.y+'px)'; }
  12217. if (fromPar.scale) {sdDefineFrom.transform += ' scale('+fromPar.scale+','+fromPar.scale+')'; }
  12218. if (toPar.scale) {sdDefineTo.transform += ' scale('+toPar.scale+','+toPar.scale+')'; }
  12219. if (fromPar.deg !== undefined) {sdDefineFrom.transform += ' rotate('+fromPar.deg+'deg)'; }
  12220. if (toPar.deg !== undefined) {sdDefineTo.transform += ' rotate('+toPar.deg+'deg)';}
  12221. if (fromPar.opacity) {sdDefineFrom.transform += ' opacity'; sdDefineFrom.opacity = String(fromPar.opacity); }
  12222. if (toPar.opacity) {sdDefineTo.transform += ' opacity'; sdDefineTo.opacity = String(toPar.opacity); }
  12223. $.keyframe.define({name: namePar, from: sdDefineFrom, to: sdDefineTo});
  12224. }
  12225. this.defineTransform = function (data) {
  12226. cssTransform(data.name, data.from, data.to);
  12227. cssTransform(data.name+'Reverse', data.to, data.from);
  12228. animations[data.name] = {name: data.name, duration:data.duration, timingFunction: data.ease, fillMode:'both'};
  12229. } */
  12230. /* this.defineAnimations = function (data) {
  12231. self.log('defineAnimations');
  12232. for (var name in self.json.styles.animations) {
  12233. self.json.styles.animations[name].name = name;
  12234. self.defineTransform(self.json.styles.animations[name]);
  12235. }
  12236. self.do(data);
  12237. }
  12238. */
  12239. /* this.styleToAnimation = function (obj, style) {
  12240. // inutilizzata
  12241. $(obj).addClass('resetAnimation'); // Disable transitions
  12242. $(obj).css(style);
  12243. $(obj).eq(0).offsetHeight; // Trigger a reflow, flushing the CSS changes
  12244. $(obj).removeClass('resetAnimation'); // Re-enable transitions
  12245. // https://stackoverflow.com/questions/11131875/what-is-the-cleanest-way-to-disable-css-transition-effects-temporarily
  12246. } */
  12247. //------------------------
  12248. // DIPENDENZE TWEENMAX
  12249. //------------------------
  12250. /* this.getImage = function (data) {
  12251. // corrisponde al metodo fixo.loadImage
  12252. // ma senza la dipendenza con fixo.iconUrl
  12253. // che aggiunge il dominio ai nomi di file senza url
  12254. // se si vuole utilizzare al posto di fixo.loadImage
  12255. // data.url = fixo.iconUrl(data.url); va fatta in fixo.js
  12256. // fixo.loadImage è usato sicuramente in hom.js / spo.js
  12257. // e in fixo.items.js
  12258. if (data.style)
  12259. $(data.object).css(data.style);
  12260. //if (data.animation == undefined) {TweenMax.to(data.object,0,{opacity:0,display:'block'});}
  12261. if (data.animation !== undefined)
  12262. $(data.object).css({opacity:0, display:'none'});
  12263. if (TweenMax) TweenMax.set(data.object,{backgroundImage:'url('+data.url+')'});
  12264. $(data.object).waitForImages({
  12265. each: function(loaded, count, success) {if(!success) {log('error loadImage id:'+this.id);}},
  12266. eachError: function() {
  12267. // http://stackoverflow.com/questions/6137934/how-should-i-handle-a-missing-image-in-my-plugin
  12268. self.log('error:'+urlPar);
  12269. },
  12270. finished: function () {
  12271. if (data.animation !== undefined) {
  12272. self.animation({object:data.object, animation:data.animation});
  12273. } else {
  12274. if (TweenMax) TweenMax.to(data.object,1,{autoAlpha:1,display:'block',float:'left'});
  12275. else $(data.object).css({display: 'block', opacity: '1'});
  12276. }
  12277. if (data.move != undefined) {
  12278. self.move({object:data.object, move:data.move, target:data.target});
  12279. }
  12280. if (data.action) {self.setAction({object:data.object, action:data.action});} // obsolete
  12281. if (data.on) {self.on(data.on, {container: data.object});}
  12282. if (data.onComplete) {self.do(data.onComplete)};
  12283. },
  12284. waitForAll: true
  12285. });
  12286. //$(objPar).waitForImages.progress(function(loaded, count, success) {alert(loaded + ' of ' + count + ' images has ' + (success ? 'loaded' : 'failed to load') + '.');});
  12287. } */
  12288. /* this.setAction = function (data) {
  12289. $(data.object).off().on(self.touch, function () {
  12290. var.touchTime = self.getTimestamp();
  12291. self.do(data.action, data.value);
  12292. });
  12293. } */
  12294. this.animate = function (params, selectorParams, args) {
  12295. // We create a Promise and return it
  12296. new Promise((resolve, reject) => {
  12297. /* self.log('animate');
  12298. self.log('params');
  12299. self.log(params);
  12300. self.log('selectorParams');
  12301. self.log(selectorParams); */
  12302. /* selectorParams.container = (params.container) ? params.container : selectorParams.container;
  12303. selectorParams.id = (params.id) ? params.id : selectorParams.id ;
  12304. selectorParams.class = (params.class) ? params.class : selectorParams.class;
  12305. selectorParams.value = (params.value) ? params.value : selectorParams.value; */
  12306. const prefix = 'animate__';
  12307. //var selector = self.selector(self.extend({}, params, selectorParams), undefined, true); // selectAll
  12308. let selector = self.selector(params.selector || params.container, undefined, true) || self.selector(selectorParams, undefined, true);
  12309. //var selector = self.selector(params.selector || params.container, selectorParams, true); // selectAll
  12310. /* self.log('animate');
  12311. self.log('selector');
  12312. self.log(selector); */
  12313. var transition = params.transition || params;
  12314. transition = self.replaceProperties(transition, args);
  12315. const duration = params.duration || '0.5s';
  12316. const animationName = `${prefix}${transition}`;
  12317. if (!selector) {
  12318. self.log('animate function without selector');
  12319. self.log(params);
  12320. self.log(selectorParams);
  12321. } else {
  12322. var elements = self.queryAll(selector);
  12323. /* console.log('elements');
  12324. console.log(elements); */
  12325. //var elements = document.querySelectorAll(selector);
  12326. if (elements)
  12327. elements.forEach(function (element, index) {
  12328. if (element) {
  12329. //element.classList.add(`${prefix}animated`, animationName);
  12330. //console.log(element.classList);
  12331. element.classList.add('animate__animated', animationName);
  12332. element.style.setProperty('--animate-duration', duration);
  12333. } else {
  12334. console.log('element');
  12335. console.log(element);
  12336. }
  12337. });
  12338. if (params.on && params.on.start)
  12339. self.do(params.on.start, { selector: selector });
  12340. //self.do(params.on.start, undefined, {selector: selector});
  12341. if (params.style) self.css(params, selectorParams); // TO DO: deprecated / to be removed
  12342. //if (params.infinite)
  12343. // node.style.setProperty('--animate-infinite', 'infinite');
  12344. // When the animation ends, we clean the classes and resolve the Promise
  12345. function handleAnimationEnd(event) {
  12346. if (params.on && params.on.end) {
  12347. self.do(params.on.end, { selector: selector });
  12348. //self.do(params.on.end, undefined, {selector: selector});
  12349. /* self.log('handleAnimationEnd');
  12350. self.log('params.on.end');
  12351. self.log(params.on.end); */
  12352. }
  12353. event.stopPropagation();
  12354. if (elements)
  12355. elements.forEach(function (element, index) {
  12356. if (element)
  12357. element.classList.remove('animate__animated', animationName);
  12358. });
  12359. resolve('Animation ended');
  12360. }
  12361. if (elements)
  12362. elements.forEach(function (element, index) {
  12363. if (element)
  12364. element.addEventListener('animationend', handleAnimationEnd, { once: true });
  12365. });
  12366. }
  12367. });
  12368. };
  12369. /*
  12370. this.animation = function (data) { // deprecated
  12371. if (data.animation != undefined) {
  12372. if (data.animation == 'show') {
  12373. $(data.object).css({'display':'block', opacity:1});
  12374. } else if (data.animation == 'hide') {
  12375. $(data.object).css({'display':'none'});
  12376. } else {
  12377. //if (data.autoDisplay == undefined) {data.autoDisplay = true};
  12378. //var animationObject = self.cloneObject(animations[data.animation]);
  12379. var animationObject = jQuery.extend({}, animations[data.animation]);
  12380. //if (data.autoDisplay)
  12381. // if (data.animation == 'fadeIn') $(data.object).css({'display':'block'});
  12382. if (data.reverse) {animationObject.name += 'Reverse'}
  12383. if (data.duration !== undefined) {animationObject.duration = data.duration}
  12384. animationObject.complete = function () {
  12385. if (data.autoDisplay) {
  12386. if ((data.animation == 'fadeOut') || (data.animation == 'hide')) {
  12387. $('data.object').css({'display':'none'});
  12388. }
  12389. }
  12390. if (data.onComplete !== undefined) {
  12391. self.do(data.onComplete);
  12392. }
  12393. }
  12394. self.log('animationObject.name');
  12395. self.log(animationObject.name);
  12396. self.log('animationObject');
  12397. self.log(animationObject);
  12398. // playKeyframe va aggiornato con
  12399. // animate({from, to, ease, type, stiffness, dumping, mass, velocity, duration})
  12400. // https://popmotion.io/#quick-start-animation-animate-keyframes-options
  12401. //var obj = popmotion.styler($(data.object));
  12402. //popmotion.animate(animationObject).start(obj.set); // $(data.object).css
  12403. $(data.object).playKeyframe(animationObject);
  12404. }
  12405. } else {
  12406. $(data.object).resetKeyframe();
  12407. $(data.object).css({'opacity':1,'display':'block'});
  12408. self.log('ANIMATION UNDEFINED');
  12409. self.log(data);
  12410. }
  12411. }
  12412. this.move = function (data) { // deprecated
  12413. var targetPos = {x:0,y:0};
  12414. if (data.target != 'center') { targetPos = {x:384,y:384}; }
  12415. else if (data.target !== undefined) {targetPos = self.getTransform(data.target);}
  12416. else {self.log(data);}
  12417. if (data.move == 'toTarget') {
  12418. TweenMax.to(data.object, self.TweenMaxDuration(data.duration), { x: targetPos.x, y: targetPos.y});
  12419. } else if (data.move == 'fromTarget') {
  12420. TweenMax.from(this, self.TweenMaxDuration(data.duration), { x: targetPos.x, y: targetPos.y});
  12421. }
  12422. if (data.animation !== undefined) {
  12423. self.animation({object:data.object, animation:data.animation});
  12424. }
  12425. }
  12426. this.TweenMaxDuration = function (duration) {
  12427. if (duration != undefined) {return Number(duration)/1000} else {return 0.667;}
  12428. }
  12429. */
  12430. // CSS CLASSES
  12431. this.addClassRule = function (ruleName, ruleParams) {
  12432. //self.log('addClassRule');
  12433. var ruleProperties = '{';
  12434. for (var property in ruleParams) {
  12435. if (typeof ruleParams[property] == 'object') {
  12436. self.addClassRule(ruleName + ' ' + property, ruleParams[property]);
  12437. } else {
  12438. ruleProperties += property + ':' + ruleParams[property] + ';';
  12439. }
  12440. }
  12441. ruleProperties += '}';
  12442. self.styleObj.sheet.insertRule(ruleName + ' ' + ruleProperties);
  12443. };
  12444. this.addApplyRule = function (ruleName, ruleParams) {
  12445. // Use @apply to inline any existing utility classes into your own custom CSS
  12446. // https://tailwindcss.com/docs/functions-and-directives#apply
  12447. self.styleObj.sheet.insertRule(ruleName + ' {@apply ' + ruleParams + '}');
  12448. };
  12449. this.findPlugin = function (name) {
  12450. if (self.json.plugins) {
  12451. for (var plugin of self.json.plugins) {
  12452. if (plugin.name == name) return plugin;
  12453. }
  12454. } else {
  12455. return false;
  12456. }
  12457. };
  12458. this.defineCss = function (cssObj) {
  12459. self.log('defineCss');
  12460. self.styleObj = document.createElement("style");
  12461. document.head.appendChild(self.styleObj);
  12462. self.styleObj.appendChild(document.createTextNode(""));
  12463. /* self.styleObj.sheet.insertRule('@tailwind base;');
  12464. self.styleObj.sheet.insertRule('@tailwind components;');
  12465. self.styleObj.sheet.insertRule('@tailwind utilities;'); */
  12466. // shortcuts (must be improved / can't be extended)
  12467. /* if (self.json.shortcuts && self.json.shortcuts.class)
  12468. shortcuts = self.json.shortcuts.class; */
  12469. if (cssObj) {
  12470. if (Array.isArray(cssObj)) {
  12471. for (var cssElement of cssObj) {
  12472. //console.log(cssElement);
  12473. for (var elementName in cssElement) {
  12474. //console.log(elementName);
  12475. let valueWithData = self.replaceProperties(cssElement[elementName]);
  12476. self.addClassRule(elementName, valueWithData);
  12477. }
  12478. }
  12479. } else {
  12480. for (var elementName in cssObj) {
  12481. let valueWithData = self.replaceProperties(cssObj[elementName]);
  12482. self.addClassRule(elementName, valueWithData);
  12483. }
  12484. }
  12485. }
  12486. if (self.pluginsLoaded.tailwindcss) {
  12487. var plugin = self.findPlugin('tailwindcss');
  12488. //var config = (plugin) ? plugin.config : {preflight: false};
  12489. var config = (self.json.setup.config.tailwindcss) ? self.json.setup.config.tailwindcss : { preflight: false };
  12490. //if (self.json.style.theme) setup.theme = self.json.style.theme;
  12491. //loadPlugin(undefined, 'tailwind-config', undefined, undefined, JSON.stringify(config)) // version 2.2.0
  12492. if (tailwind)
  12493. tailwind.config = config;
  12494. else
  12495. console.log('tailwind object is undefined');
  12496. }
  12497. /* // OBSOLETE
  12498. if (self.pluginsLoaded.twind && window.twind) {
  12499. var plugin = self.findPlugin('twind');
  12500. var config = (plugin) ? plugin.config : {preflight: false, mode:'silent'};
  12501. //if (self.json.setup.target) setup.target = self.query(self.json.setup.target);
  12502. //if (self.json.style.theme) setup.theme = self.json.style.theme;
  12503. window.twind.setup(config);
  12504. } */
  12505. /* if (self.pluginsLoaded.windicss && window.windicssRuntimeOptions) {
  12506. var config = self.json.style.windi || {
  12507. // enabled preflight
  12508. preflight: false,
  12509. // scan the entire dom tree to infer the classnames on page loaded
  12510. extractInitial: false,
  12511. // generate mock classes for browser to do the auto-completeion
  12512. mockClasses: false,
  12513. // the windi config you are used to put in `windi.setup.js`
  12514. setup: {},
  12515. theme: {extend: {}}
  12516. };
  12517. if (self.json.style.theme) setup.theme.extend = self.json.style.theme;
  12518. window.windicssRuntimeOptions = config;
  12519. } */
  12520. /* if (self.pluginsLoaded.unocss) {
  12521. var config = self.json.style.unocss || { // -> self.json.plugins[].setup
  12522. rules: [
  12523. // custom rules...
  12524. ],
  12525. presets: [
  12526. // custom presets...
  12527. ],
  12528. // ...
  12529. };
  12530. if (self.json.style.theme) setup.theme = self.json.style.theme;
  12531. if (self.json.shortcuts) setup.shortcuts = self.json.shortcuts;
  12532. window.__unocss = config;
  12533. //alert(JSON.stringify(config));
  12534. } */
  12535. //self.do(data);
  12536. };
  12537. /* this.createLoader = function (data) {
  12538. // !--<div class="preloader-wrapper"><div class="preloader"><img alt="Loading..."/></div></div>-->
  12539. if (self.json.loader) $('.preloader img').attr('src', self.json.loader);
  12540. self.do(data);
  12541. } */
  12542. /* this.preloadIcons = function (data) {
  12543. self.log('preloadIcons');
  12544. // to do: check for duplicated ids
  12545. if (self.json.icons) {
  12546. if (!data.icons && self.json.icons) data.icons = self.cloneObject(self.json.icons);
  12547. if (data.icons) {
  12548. var iconSet = Object.keys(data.icons)[0];
  12549. var icons = data.icons[iconSet];
  12550. delete data.icons[iconSet];
  12551. if (icons.preload) {
  12552. var ajax = new XMLHttpRequest();
  12553. ajax.open("GET", icons.src, true);
  12554. ajax.onload = function(e) {
  12555. if (this.status >= 200 && this.status < 400) {
  12556. self.log('Icon set loaded ' + iconSet);
  12557. var result = this.response; // responseText
  12558. //self.log(result);
  12559. var div = document.createElement("div");
  12560. //var iconsHtml = new XMLSerializer().serializeToString(result);
  12561. var iconsHtml = result;
  12562. iconsHtml = self.replaceAll(iconsHtml, 'id="', 'id="' + iconSet + '_');
  12563. div.innerHTML = iconsHtml;
  12564. div.setAttribute("style", "display: none");
  12565. //div.setAttribute("aria-hidden", "true");
  12566. //document.getElementbyId('preloadIcons').appendChild(element);
  12567. document.body.insertBefore(div, null);
  12568. if (Object.keys(data.icons).length > 0)
  12569. self.preloadIcons(data);
  12570. else
  12571. self.do(data);
  12572. }
  12573. }
  12574. ajax.send();
  12575. } else {
  12576. if (Object.keys(data.icons).length > 0)
  12577. self.preloadIcons(data);
  12578. else
  12579. self.do(data);
  12580. }
  12581. } else
  12582. self.do(data);
  12583. } else {
  12584. self.do(data);
  12585. }
  12586. } */
  12587. /* this.initApp = function (data) {
  12588. self.log('initApp');
  12589. self.defineCss();
  12590. window.addEventListener('resize', self.resizeEvent);
  12591. if (self.json) { // can be self.json.init
  12592. //if (self.json.on.init)
  12593. if (self.json.on)
  12594. self.on(self.json.on);
  12595. //else
  12596. // self.log('no on init functions');
  12597. }
  12598. //self.do(data);
  12599. }
  12600. */
  12601. /* this.createUI = function (data) {
  12602. jsonic.do({
  12603. tasks:[
  12604. {task: self.firebaseInit},
  12605. {
  12606. task: self.firebaseVerifyUser,
  12607. params: {
  12608. code: self.params.oobCode
  12609. }
  12610. },
  12611. {task: self.getDevices, if: jsonic.userIn},
  12612. {task: self.defineCss},
  12613. {task: self.defineAnimations}, // animazioni css predefinite
  12614. {task: self.createHeader},
  12615. {task: self.createMenu, params: {
  12616. container: '#menu',
  12617. id: data.params.mode || 'guest'
  12618. }},
  12619. {task: jsonic.createPages}
  12620. ]
  12621. });
  12622. } */
  12623. /* this.openPageFromUrl = function(data){
  12624. jsonic.log('openPageFromUrl');
  12625. jsonic.log('self.params');
  12626. jsonic.log(self.params);
  12627. var pageId = '';
  12628. //if (localStorage.getItem('scanning')) {
  12629. // self.hashopenTask({id:localStorage.getItem('scanningFile')});
  12630. //} else {
  12631. //self.disableFileIcons();
  12632. //var noDevices = (jsonic.userIn() && (!var.db.devices || Object.keys(var.db.devices).length == 0));
  12633. //if (noDevices && !self.params.d && !self.params.m) {
  12634. // jsonic.gotoPage('devices');
  12635. //} else {
  12636. if (window.location.hash && window.location.hash !== '') {
  12637. //pageId = window.location.hash.substr(1);
  12638. self.hash();
  12639. } else {
  12640. if (self.params.p) // retro-compatibilità
  12641. pageId = self.params.p;
  12642. else
  12643. pageId = self.homePage();
  12644. self.gotoPage(pageId);
  12645. }
  12646. //}
  12647. self.do(data);
  12648. }
  12649. */
  12650. /*
  12651. // Load a script from given `url`
  12652. var loadPlugin = function(url) {
  12653. return new Promise(function(resolve, reject) {
  12654. const script = document.createElement('script');
  12655. script.src = url;
  12656. script.addEventListener('load', function() {
  12657. // The script is loaded completely
  12658. resolve(true);
  12659. });
  12660. document.head.appendChild(script);
  12661. });
  12662. };
  12663. // Perform all promises in the order
  12664. var waterfall = function(promises) {
  12665. return promises.reduce(
  12666. function(p, c) {
  12667. // Waiting for `p` completed
  12668. return p.then(function() {
  12669. // and then `c`
  12670. return c().then(function(result) {
  12671. return true;
  12672. });
  12673. });
  12674. },
  12675. // The initial value passed to the reduce method
  12676. Promise.resolve([])
  12677. );
  12678. };
  12679. // Load an array of scripts in order
  12680. var loadScriptsInOrder = function(arrayOfJs) {
  12681. self.log('loadScriptsInOrder');
  12682. self.log(arrayOfJs);
  12683. const promises = arrayOfJs.map(function(url) {
  12684. self.log(url);
  12685. return loadScript(url);
  12686. });
  12687. return waterfall(promises);
  12688. };
  12689. */
  12690. this.hash = function (path, args) {
  12691. self.log('hash');
  12692. var path = self.replaceProperties(path, args);
  12693. self.log(path);
  12694. window.location.hash = path;
  12695. };
  12696. this.page = function (path, args) {
  12697. self.log('page');
  12698. var path = self.replaceProperties(path, args);
  12699. self.log(path);
  12700. if (path.startsWith('#'))
  12701. window.location.hash = path;
  12702. else
  12703. window.location.href = path;
  12704. //window.location.hash = path;
  12705. };
  12706. this.hashChangeEvent = function () {
  12707. self.log('hashChangeEvent');
  12708. self.log(window.location.hash);
  12709. /* if (window.location.hash && window.location.hash !== '') {
  12710. var hashParams = window.location.hash.substr(1).split('/');
  12711. self.gotoPage(hashParams[0], hashParams[1]);
  12712. } else {
  12713. //pageId = self.homePage();
  12714. if (self.json.setup && self.json.setup.wordpress && self.json.setup.wordpress.slug)
  12715. self.gotoPage(self.json.setup.wordpress.slug);
  12716. else
  12717. self.gotoPage(self.homePage());
  12718. }
  12719. if (json && json.app && json.app.on && json.app.on.page) { // page event
  12720. self.do(json.app.on.page);
  12721. }
  12722. if (json && json.actions && json.actions.init) { // obsolete
  12723. self.do(json.actions.init);
  12724. } */
  12725. };
  12726. /* this.addPageListeners = function (data) {
  12727. self.log('addPageListeners');
  12728. // Resize event
  12729. window.addEventListener('resize', self.resizeEvent);
  12730. // Location hash (url) event
  12731. window.addEventListener('hashchange', self.hashChangeEvent);
  12732. //$(window).on('hashchange', self.hashChangeEvent);
  12733. self.hashChangeEvent();
  12734. self.do(data);
  12735. } */
  12736. /* // testing
  12737. let findValues = function(obj, key, found) {
  12738. for (let localKey in obj) {
  12739. if (obj.hasOwnProperty(localKey)) {
  12740. let val = obj[localKey];
  12741. //self.log(localKey)
  12742. if (localKey === key) {
  12743. found.add(val)
  12744. } else {
  12745. if (typeof val === 'object') {
  12746. findValues(val, key, found)
  12747. }
  12748. }
  12749. }
  12750. }
  12751. }
  12752. function uniqueValue(obj, key, value) {
  12753. let found = new Set()
  12754. findValues(object, key, found)
  12755. return found.size === 1 && found.has(value);
  12756. } */
  12757. this.lookup = function (obj, k) {
  12758. for (var key in obj) {
  12759. var value = obj[key];
  12760. if (k == key) {
  12761. return [k, value];
  12762. }
  12763. if (typeof (value) === "object" && !Array.isArray(value)) {
  12764. var y = lookup(value, k);
  12765. if (y && y[0] == k) return y;
  12766. }
  12767. if (Array.isArray(value)) {
  12768. // for..in doesn't work the way you want on arrays in some browsers
  12769. //
  12770. for (var i = 0; i < value.length; ++i) {
  12771. var x = lookup(value[i], k);
  12772. if (x && x[0] == k) return x;
  12773. }
  12774. }
  12775. }
  12776. return null;
  12777. };
  12778. this.findValues = function (obj, key) {
  12779. //return Boolean(JSON.stringify(obj).indexOf('"' + string + '":') >= 0)
  12780. let matrix = [...JSON.stringify(obj).matchAll(new RegExp('\"?' + key + '\"?\:\s*\"([^,\"]+)', 'gi'))];
  12781. var results = [];
  12782. for (var element of matrix)
  12783. results.push(element[1]);
  12784. return results;
  12785. //return Boolean(JSON.stringify(obj).match(new RegExp('\"?' + key + '\"?\:\s+\"' + value + '\"'))) // JSON5 compatible
  12786. };
  12787. // testing
  12788. function findKey(obj, key) {
  12789. for ([k, v] of Object.entries(obj)) {
  12790. if (k == key) return v;
  12791. if (typeof v === 'object' && v !== null) {
  12792. let found = findKey(v, key);
  12793. if (found) return found;
  12794. }
  12795. }
  12796. }
  12797. // lookup in json
  12798. this.keyInJson = function (obj, string) {
  12799. //return Boolean(JSON.stringify(obj).indexOf('"' + string + '":') >= 0)
  12800. return Boolean(JSON.stringify(obj).match(new RegExp('\"?' + string + '\"?\:'))); // JSON5 compatible
  12801. };
  12802. // lookup in json
  12803. this.valueInJson = function (obj, string) {
  12804. //return Boolean(JSON.stringify(obj).indexOf('"' + string + '":') >= 0)
  12805. return Boolean(JSON.stringify(obj).match(new RegExp('\"?' + string + '\"?'))); // JSON5 compatible
  12806. };
  12807. /* this.keyInFiles = function (string) {
  12808. var found = self.keyInJson(self.options, string); // in main app options: jsonic = jsonicApp(options)
  12809. for (fileName in self.modules) {
  12810. if (fileName !== 'resources' && self.keyInJson(self.modules[fileName], string))
  12811. found = true;
  12812. }
  12813. return found;
  12814. } */
  12815. /* this.openPageFromUrl = function (data) {
  12816. self.log('openPageFromUrl');
  12817. self.hashChangeEvent();
  12818. self.do(data);
  12819. }; */
  12820. /* this.addEventListeners = function (data) {
  12821. self.log('addEventListeners');
  12822. // Resize event
  12823. window.addEventListener('resize', self.resizeEvent);
  12824. // Location hash (url) event
  12825. window.addEventListener('hashchange', self.hashChangeEvent);
  12826. $(window).on('hashchange', self.hashChangeEvent);
  12827. self.hashChangeEvent(); // add here on.hashchange
  12828. // Fullscreen event
  12829. if (screenfull && screenfull.isEnabled) {
  12830. screenfull.on('change', () => {
  12831. self.log('Am I fullscreen?', screenfull.isFullscreen ? 'Yes' : 'No');
  12832. if (screenfull.isFullscreen) {
  12833. var.fullscreen = true;
  12834. if (var.onFullScreenOpen) self.do(var.onFullScreenOpen);
  12835. } else {
  12836. var.fullscreen = false;
  12837. if (var.onFullScreenClose) self.do(var.onFullScreenClose);
  12838. }
  12839. });
  12840. }
  12841. if (json && json.app && json.app.on) {
  12842. if (json.app.on.thunkable && json.app.on.thunkable.receiveMessage)
  12843. window.receiveMessage(function (message) {
  12844. //document.querySelector('#message').value = message;
  12845. jsonic.functions(json.app.on.thunkable.receiveMessage, message, undefined);
  12846. });
  12847. var container = json.app.container || 'body';
  12848. self.on(json.app.on, {container: container});
  12849. self.do(data);
  12850. } else {
  12851. self.do(data);
  12852. }
  12853. } */
  12854. /* this.loadIconset = function (data) {
  12855. self.log('loadIconset');
  12856. if (self.json.iconset) {
  12857. if (!self.pluginsLoaded['iconify']) {
  12858. let plugin = self.json.resources.pluginsFunctions['iconify'];
  12859. self.pluginsLoader([plugin], self.loadIconset, [data]);
  12860. } else {
  12861. var iconset;
  12862. if (!self.json.iconset[0])
  12863. iconset = [self.json.iconset];
  12864. else
  12865. iconset = self.json.iconset;
  12866. for (var index in iconset) {
  12867. if (Iconify.addCollection(iconset[index]))
  12868. self.log('added iconset '+ iconset[index].prefix);
  12869. else
  12870. self.log('can\t add iconset '+ iconset[index].prefix);
  12871. //alert(x);
  12872. }
  12873. self.do(data);
  12874. }
  12875. } else {
  12876. self.do(data);
  12877. }
  12878. } */
  12879. // Si potrebbe creare una nuova istanza di jsonicApp
  12880. this.start = function () {
  12881. self.log('start');
  12882. //if (params.onFullScreenOpen) var.onFullScreenOpen = params.onFullScreenOpen;
  12883. //if (params.onFullScreenClose) var.onFullScreenClose = params.onFullScreenClose;
  12884. // PWA
  12885. /* if ('serviceWorker' in navigator) {
  12886. // Register a service worker hosted at the root of the
  12887. // site using the default scope.
  12888. navigator.serviceWorker.register('/app/assets/pwa/sw.js').then(function(registration) {
  12889. self.log('Service worker registration succeeded:', registration);
  12890. }, function(error) {
  12891. self.log('Service worker registration failed:', error);
  12892. });
  12893. } else {
  12894. self.log('Service workers are not supported.');
  12895. } */
  12896. let deferredPrompt;
  12897. window.addEventListener('beforeinstallprompt', (e) => {
  12898. // Prevent Chrome 67 and earlier from automatically showing the prompt
  12899. e.preventDefault();
  12900. // Stash the event so it can be triggered later.
  12901. deferredPrompt = e;
  12902. });
  12903. window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', e => {
  12904. self.json.setup.darkMode = e.matches ? "dark" : false;
  12905. });
  12906. // DEFINE ICONSET (iconify)
  12907. if (self.json.iconset) {
  12908. if (!self.pluginsLoaded['iconify']) {
  12909. let plugin = self.json.resources.pluginsFunctions['iconify'];
  12910. self.pluginsLoader([plugin], self.start);
  12911. return false;
  12912. } else {
  12913. var iconset;
  12914. if (!self.json.iconset[0])
  12915. iconset = [self.json.iconset];
  12916. else
  12917. iconset = self.json.iconset;
  12918. for (var index in iconset) {
  12919. if (Iconify.addCollection(iconset[index]))
  12920. self.log('added iconset ' + iconset[index].prefix);
  12921. else
  12922. self.log('can\t add iconset ' + iconset[index].prefix);
  12923. //alert(x);
  12924. }
  12925. }
  12926. }
  12927. // DEFINE CSS
  12928. //self.defineCss(); // TO DO: only additional css (do it on load module success)
  12929. // ADD RESIZE LISTENER (for dynamic styles) TO DO: check it
  12930. window.addEventListener('resize', self.resizeEvent);
  12931. // PAGE
  12932. if (!self.json.setup.page) self.json.setup.page = {};
  12933. self.json.setup.page.hash = window.location.hash.substr(1);
  12934. // DO / ON
  12935. /* if (self.json) {
  12936. if (self.json.do)
  12937. self.do(self.json.do, undefined, self.json.container);
  12938. if (self.json.on)
  12939. self.on(self.json.on, self.json.container);
  12940. } */
  12941. var selector = self.json.selector || self.json.container;
  12942. /* if (self.json.do)
  12943. self.do(self.json.do, undefined, selector); */
  12944. // should go action/run
  12945. if (self.json.on)
  12946. self.on(self.json.on, selector);
  12947. };
  12948. this.extendJson = function (jsonBase, jsonExtension) {
  12949. // TO DO: should be renamed in extendApp (or executeModule) because extend self.json and add CSS style
  12950. if (jsonExtension.css) self.defineCss(jsonExtension.css);
  12951. if (jsonExtension.functions) self.extendFunctions(jsonExtension.functions);
  12952. for (var key in jsonExtension) {
  12953. // AGGIUNGERE ALL'ARRAY DELLE AZIONI ON.INIT...
  12954. if (key == 'on') {
  12955. for (var subKey in jsonExtension[key]) {
  12956. if (typeof jsonExtension[key][subKey] !== 'string') {
  12957. //jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]);
  12958. if (!jsonBase[key][subKey]) jsonBase[key][subKey] = [];
  12959. jsonBase[key][subKey].push(jsonExtension[key][subKey]);
  12960. } else {
  12961. jsonBase[key][subKey] = jsonExtension[key][subKey];
  12962. }
  12963. }
  12964. } else if (key == 'parts' || key == 'shortcuts') { // combine subelements
  12965. for (var subKey in jsonExtension[key]) {
  12966. if (typeof jsonExtension[key][subKey] !== 'string')
  12967. jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]);
  12968. else
  12969. jsonBase[key][subKey] = jsonExtension[key][subKey];
  12970. }
  12971. /* } else if (key == 'css') {
  12972. for (var subKey in jsonExtension[key]) {
  12973. if (typeof jsonExtension[key][subKey] !== 'string')
  12974. jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]);
  12975. else
  12976. jsonBase[key][subKey] = jsonExtension[key][subKey];
  12977. } */
  12978. /* } else if (key == 'app') { // to do: obsolete
  12979. for (var subKey in jsonExtension[key]) {
  12980. if (typeof jsonExtension[key][subKey] !== 'string')
  12981. jsonBase[key][subKey] = self.extend({}, jsonBase[key][subKey], jsonExtension[key][subKey]);
  12982. else
  12983. jsonBase[key][subKey] = jsonExtension[key][subKey];
  12984. } */
  12985. } else if (key == 'iconset' || key == 'plugins') { // combine arrays
  12986. if (!jsonBase[key]) jsonBase[key] = [];
  12987. jsonBase[key] = jsonBase[key].concat(jsonExtension[key]);
  12988. } else {
  12989. if (key == 'css') {
  12990. } else {
  12991. jsonBase[key] = self.extend({}, jsonBase[key], jsonExtension[key]);
  12992. }
  12993. }
  12994. }
  12995. return jsonBase;
  12996. };
  12997. this.loadModuleFromDb = function (data) {
  12998. self.log('loadModuleFromDb');
  12999. self.firebaseGet('jsonic', function (result) {
  13000. if (result.success) {
  13001. self.log('firebase get SUCCESS');
  13002. for (codeKey in result.data)
  13003. if (result.data[codeKey].code)
  13004. self.extendJson(json, result.data[codeKey].code);
  13005. //self.log('json');
  13006. //self.log(json);
  13007. //if (params.success) self.do(params.success,result.data);
  13008. } else {
  13009. self.log('firebase get ERROR');
  13010. //if (params.error) self.do(params.error, result.error);
  13011. // alert errore di connessione. alert riprova
  13012. }
  13013. self.do(data);
  13014. //self.do(data);
  13015. });
  13016. };
  13017. this.modules = {};
  13018. this.modulesLoading = {};
  13019. this.fileType = function (fileName) {
  13020. return /(?:\.([^.]+))?$/.exec(fileName)[1];
  13021. };
  13022. this.jsoncToJson = function (jsoncText) {
  13023. return jsoncText.replace(/\/\*[\s\S]*?\*\/|([^\\:]|^)\/\/.*$/gm, '$1').replace(/\r/, "\n").replace(/\n[\n]+/, "\n");
  13024. // https://stackoverflow.com/questions/244777/can-comments-be-used-in-json/24545329
  13025. };
  13026. //var json = jsoncToJson('https://fantacards.com/app/data.jsonc');
  13027. //console.log(json);
  13028. this.loadModule = function (mod) {
  13029. /* self.log('loadModule');
  13030. self.log(mod); */
  13031. // params: {files, onComplete}
  13032. // self.cloneObject(params.json) to avoid to remove from initial params
  13033. //if (typeof setup.modules == 'string') setup.modules = [setup.modules];
  13034. if (!self.modulesLoading[mod.name] && !self.modules[mod.name]) {
  13035. self.modulesLoading[mod.name] = true;
  13036. return new Promise(function (resolve, reject) {
  13037. //mod = self.replaceProperties(mod);
  13038. //self.log(mod);
  13039. const getAPIData = new XMLHttpRequest();
  13040. getAPIData.open("GET", mod.url);
  13041. getAPIData.onload = function () {
  13042. self.modulesLoading[mod.name] = false;
  13043. //console.log(getAPIData);
  13044. let responseText = getAPIData.responseText;
  13045. if (self.fileType(getAPIData.responseURL) == 'jsonc')
  13046. responseText = self.jsoncToJson(responseText);
  13047. // try
  13048. const result = JSON.parse(responseText);
  13049. // error self.log('Wrong JSON in module '+ mod.name);
  13050. if (self.isJson(result)) {
  13051. self.modules[mod.name] = result;
  13052. self.extendJson(self.json, result);
  13053. self.log('Loaded module ' + mod.name, 'grey');
  13054. } else {
  13055. self.log('Wrong JSON in module ' + mod.name, 'red');
  13056. }
  13057. resolve();
  13058. };
  13059. getAPIData.onerror = function () {
  13060. self.modulesLoading[mod.name] = false;
  13061. };
  13062. getAPIData.send();
  13063. });
  13064. } else {
  13065. self.log('Module ' + mod.name + ' already loaded', 'orange');
  13066. }
  13067. };
  13068. /* var loadPlugin = function (url) {
  13069. //self.log('loading ' + url);
  13070. return new Promise(function(resolve, reject) {
  13071. var type = 'script';
  13072. if (url.endsWith('.css')) type = 'link';
  13073. let obj = document.createElement(type);
  13074. // obj.src = url;
  13075. obj.async = false;
  13076. obj.onload = function() {
  13077. resolve(url);
  13078. };
  13079. obj.onerror = function() {
  13080. self.log('error loading: '+url);
  13081. reject(url);
  13082. };
  13083. if (type === 'script') {
  13084. if (url) obj.src = url;
  13085. //if (code) obj.text = code;
  13086. obj.location = document.body;
  13087. document.body.appendChild(obj);
  13088. } else {
  13089. obj.href = url;
  13090. obj.rel = 'stylesheet';
  13091. obj.type = 'text/css';
  13092. obj.location = document.head;
  13093. document.head.appendChild(obj);
  13094. }
  13095. //self.log('obj');
  13096. //self.log(obj);
  13097. });
  13098. } */
  13099. var loadPlugin = function (params) {
  13100. //self.log('loading ' + url);
  13101. return new Promise(function (resolve, reject) {
  13102. var tag = 'script', type = 'text/javascript';
  13103. if (params.type == 'script') { tag = 'script'; type = 'text/javascript'; }
  13104. else if (params.type == 'module') { tag = 'script'; type = 'module'; }
  13105. else if (params.type == 'tailwind-config') { tag = 'script'; type = 'tailwind-config'; }
  13106. else if (params.type == 'link') { tag = 'link'; type = 'text/css'; }
  13107. else if (params.type == 'font') { tag = 'link'; type = undefined; }
  13108. //if (!tag)
  13109. // tag = (url.endsWith('.js')) ? 'script' : 'link';
  13110. let obj = document.createElement(tag);
  13111. if (params.content)
  13112. obj.appendChild(document.createTextNode(params.content));
  13113. obj.async = false;
  13114. obj.onload = function () {
  13115. self.pluginsLoaded[params.name] = { version: "1.0.0" };
  13116. self.log('Loaded plugin ' + params.name, 'grey');
  13117. resolve(params.url);
  13118. };
  13119. obj.onerror = function () {
  13120. self.log('Error loading plugin ' + params.url, 'red');
  13121. reject(params.url);
  13122. };
  13123. if (tag === 'script') {
  13124. if (params.url) obj.src = params.url;
  13125. //if (code) obj.text = code;
  13126. obj.location = document.body;
  13127. obj.type = type || 'text/javascript';
  13128. /* if (type == 'tailwind-config') {
  13129. self.log('obj');
  13130. self.log(obj);
  13131. } */
  13132. document.body.appendChild(obj);
  13133. } else if (tag === 'link') {
  13134. obj.rel = params.rel || 'stylesheet';
  13135. obj.location = document.head;
  13136. if (params.url) obj.href = params.url;
  13137. if (type) obj.type = type;
  13138. if (params.as) obj.as = params.as;
  13139. document.head.appendChild(obj);
  13140. }
  13141. });
  13142. };
  13143. /* var loadPlugin = function (url, tag, rel, as) {
  13144. //self.log('loading ' + url);
  13145. //alert(url);
  13146. return new Promise(function(resolve, reject) {
  13147. if (tag == 'js') tag = 'script';
  13148. if (tag == 'css') tag = 'link';
  13149. if (!tag)
  13150. tag = (url.endsWith('.js')) ? 'script' : 'link';
  13151. let obj = document.createElement(tag);
  13152. obj.async = false;
  13153. obj.onload = function() {
  13154. self.log('loaded plugin: '+url);
  13155. resolve(url);
  13156. };
  13157. obj.onerror = function() {
  13158. self.log('error loading: '+url);
  13159. reject(url);
  13160. };
  13161. if (tag === 'script') {
  13162. if (url) obj.src = url;
  13163. //if (code) obj.text = code;
  13164. obj.location = document.body;
  13165. document.body.appendChild(obj);
  13166. } else {
  13167. obj.href = url;
  13168. obj.rel = rel || 'stylesheet';
  13169. if (obj.rel == 'stylesheet')
  13170. obj.type = 'text/css';
  13171. if (as)
  13172. obj.as = as;
  13173. obj.location = document.head;
  13174. document.head.appendChild(obj);
  13175. }
  13176. });
  13177. }
  13178. */
  13179. this.uiLoaded = {};
  13180. this.pluginsLoaded = {};
  13181. //The Firebase Realtime Database lets you store and query user data, and makes it available between users in realtime
  13182. this.findUrl = function (array, url) {
  13183. for (var item of array) {
  13184. if (item.url == url)
  13185. return true;
  13186. }
  13187. };
  13188. /* this.export = function (params) {
  13189. // {name, data}
  13190. if (params && params.name && params.data) {
  13191. let element = document.createElement('a');
  13192. element.style.display = 'none';
  13193. element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(JSON.stringify(params.data)));
  13194. element.setAttribute('download', params.name);
  13195. document.body.appendChild(element);
  13196. element.click();
  13197. document.body.removeChild(element);
  13198. } else {
  13199. self.log('"export" requires name and data attributes');
  13200. }
  13201. } */
  13202. /* this.exportData = function (path) {
  13203. // data
  13204. const fileName = self.replaceAll(path, ' ', '.') + '.json';
  13205. const jsonData = self.element({path: path, root: params.root});
  13206. self.export({name: fileName, data: jsonData});
  13207. }
  13208. */
  13209. this.loadPlugins = function () {
  13210. //self.log('loadPlugins');
  13211. //var setup = json.setup;
  13212. // TEMPORAL API
  13213. // https://cdn.jsdelivr.net/npm/@cogitatio/tc39-temporal@0.0.12-alpha.2/index.js
  13214. // https://cdn.jsdelivr.net/npm/cogitatio-tc39-temporal@1.0.2/index.js
  13215. /* <!-- <script type="module">
  13216. import { initializeApp } from 'https://www.gstatic.com/firebasejs/9.0.2/firebase-app.js'
  13217. // If you enabled Analytics in your project, add the Firebase SDK for Google Analytics
  13218. import { analytics } from 'https://www.gstatic.com/firebasejs/9.0.2/firebase-analytics.js'
  13219. // Add Firebase products that you want to use
  13220. import { auth } from 'https://www.gstatic.com/firebasejs/9.0.2/firebase-auth.js'
  13221. import { firestore } from 'https://www.gstatic.com/firebasejs/9.0.2/firebase-firestore.js'
  13222. </script> --> */
  13223. var filesToLoad = [];
  13224. // plugins
  13225. if (self.json.plugins) {
  13226. for (var index in self.json.plugins) {
  13227. var plugin = self.json.plugins[index];
  13228. //self.log('loading ' + plugin.name + '...');
  13229. var version = plugin.version || '';
  13230. if (!plugin.ondemand) { // V. >= 1.0.2
  13231. if (plugin.url) { // directly loaded
  13232. // plugin.name and version are needed?
  13233. if (!self.findUrl(filesToLoad, plugin.url)) { // not included yet
  13234. filesToLoad.push({ name: plugin.name, url: plugin.url, type: plugin.type });
  13235. }
  13236. } else { // from resources (TO DO: remove)
  13237. var pluginsFiles = plugin.files || self.json.resources.pluginsFiles[plugin.name];
  13238. // moved in loadPlugin = ... onload
  13239. /* self.pluginsLoaded[plugin.name] = {
  13240. version: version
  13241. }; */
  13242. if (!Array.isArray(pluginsFiles))
  13243. pluginsFiles = [pluginsFiles];
  13244. for (item of pluginsFiles) {
  13245. var url = self.replaceAll(item.url, '{version}', version);
  13246. if (plugin.params) url += '?' + plugin.params;
  13247. let pluginName = plugin.name || item.name;
  13248. if (!url || !self.findUrl(filesToLoad, url)) // not included yet
  13249. filesToLoad.push({ name: pluginName, url: url, type: item.type, content: item.content });
  13250. }
  13251. }
  13252. }
  13253. }
  13254. }
  13255. // ui
  13256. /* for (var index in config.ui) {
  13257. var configUI = config.ui[index];
  13258. //self.log('loading ' + configUI.name + '...');
  13259. var version = configUI.version || '';
  13260. var uiFiles = self.json.resources.uiFiles[configUI.name];
  13261. if (!Array.isArray(uiFiles))
  13262. uiFiles = [uiFiles];
  13263. for (item of uiFiles) {
  13264. var url = self.replaceAll(item.url, '{version}', version);
  13265. if (!self.findUrl(filesToLoad, url)) // not included yet
  13266. filesToLoad.push({url: url, type: item.type, content: item.content});
  13267. }
  13268. } */
  13269. // Auto load Google Fonts
  13270. // TO DO: comment
  13271. for (fontName of self.findValues(self.json, 'font-family')) {
  13272. if (self.json.resources.googleFonts.indexOf(fontName) >= 0) {
  13273. //alert(fontName);
  13274. fontName = self.replaceAll(fontName, ' ', '+');
  13275. //filesToLoad.push({type: 'font', url:'https://fonts.googleapis.com/css2?family='+fontName+'&display=swap', rel:'preload', as:'font'});
  13276. filesToLoad.push({ type: 'link', url: 'https://fonts.googleapis.com/css2?family=' + fontName });
  13277. // +'&display=swap' // https://css-tricks.com/almanac/properties/f/font-display/
  13278. }
  13279. }
  13280. // Auto load plugins (firebase only)
  13281. /* if (config.plugins && config.plugins.autoload) {
  13282. self.log('plugins autoload');
  13283. //for (var index in self.json.resources.pluginsFunctions) {
  13284. var pluginFunctions = self.json.resources.pluginsFirebase; // pluginFunctions
  13285. for (var index in self.json.resources.pluginsFirebase) {
  13286. //self.log(index + ':' + self.keyInFiles(index));
  13287. if (self.keyInFiles(index)) {
  13288. if (pluginFunctions[index]) {
  13289. var plugins = [];
  13290. if (Array.isArray(pluginFunctions[index]))
  13291. plugins = pluginFunctions[index];
  13292. else
  13293. plugins = [pluginFunctions[index]];
  13294. for (plugin of plugins) {
  13295. self.log('loading ' + plugin.name + '...');
  13296. self.pluginsLoaded[plugin.name] = version;
  13297. var version = plugin.version || '';
  13298. var pluginsFiles = self.json.resources.pluginsFiles[plugin.name];
  13299. if (!Array.isArray(pluginsFiles))
  13300. pluginsFiles = [pluginsFiles];
  13301. for (item of pluginsFiles) {
  13302. var url = self.replaceAll(item.url, '{version}', version);
  13303. if (!self.findUrl(filesToLoad, url)) // not included yet
  13304. filesToLoad.push({url: url, type: item.type, content: item.content});
  13305. }
  13306. }
  13307. }
  13308. }
  13309. }
  13310. } */
  13311. // load multiple scripts in sequence
  13312. // https://bit.ly/3nT5Ky1
  13313. // one after another
  13314. // https://medium.com/@asimmittal/sequential-script-loading-in-javascript-a0b77ca9467c
  13315. // load multi js and css
  13316. // https://sphacks.io/load-multiple-js-scripts-dynamically-without-jquery/
  13317. // save all Promises as array
  13318. let promises = [];
  13319. //promises.push(loadPlugin("https://fonts.googleapis.com", 'link', 'preconnect'));
  13320. //promises.push(loadPlugin("https://fonts.gstatic.com", 'link', 'preconnect'));
  13321. filesToLoad.forEach(function (item) {
  13322. if (item.url)
  13323. promises.push(loadPlugin({ name: item.name, url: item.url, type: item.type, rel: item.rel, as: item.as, content: item.content }));
  13324. else
  13325. loadPlugin({ name: item.name, url: item.url, type: item.type, rel: item.rel, as: item.as, content: item.content });
  13326. //promises.push(loadPlugin(url));
  13327. });
  13328. //self.log(filesToLoad);
  13329. Promise.all(promises).then(function () {
  13330. self.start();
  13331. }).catch(function (script) {
  13332. self.log('Failed to load');
  13333. self.log(script);
  13334. });
  13335. };
  13336. this.modulesList = function (modulesObj) {
  13337. /* self.log('modulesList');
  13338. self.log('modulesObj');
  13339. self.log(modulesObj);
  13340. */
  13341. var modulesList = [];
  13342. if (modulesObj) {
  13343. for (key in modulesObj) {
  13344. var mod = self.replaceProperties(modulesObj[key]);
  13345. modulesList = modulesList.concat(mod);
  13346. }
  13347. }
  13348. return self.replaceProperties(modulesObj);
  13349. };
  13350. this.loadModules = function () {
  13351. //self.log('loadModules');
  13352. if (self.json.setup.modules) {
  13353. var modules = self.replaceProperties(self.json.setup.modules); // replace {page:id}
  13354. /* self.log('modules');
  13355. self.log(modules); */
  13356. var promises = [];
  13357. modules.forEach(function (item) {
  13358. if (!self.modulesLoading[item.name] && !self.modules[item.name]) {
  13359. promises.push(self.loadModule(item));
  13360. }
  13361. });
  13362. Promise.all(promises).then(function () {
  13363. self.loadPlugins();
  13364. }).catch(function (file) {
  13365. self.log('Failed to load');
  13366. self.log(file);
  13367. });
  13368. } else {
  13369. self.loadPlugins();
  13370. }
  13371. };
  13372. this.moduleExecuted = {};
  13373. this.addModule = function (params) {
  13374. if (!self.modules[params.name]) {
  13375. var promises = [];
  13376. //var ideModule = {name: 'ide', url: 'https://jsonic.io/app/modules/ide.json'};
  13377. promises.push(self.loadModule(params));
  13378. Promise.all(promises).then(function () {
  13379. if (!self.moduleExecuted[params.name]) {
  13380. //self.log('all modules loaded');
  13381. var module = self.modules[params.name];
  13382. if (module.html) {
  13383. self.moduleExecuted[params.name] = true;
  13384. self.html(module.html);
  13385. // TO DO: add also on, funcions ...
  13386. }
  13387. }
  13388. if (params.success)
  13389. self.do(params.success);
  13390. //self.do(params.success);
  13391. }).catch(function (file) {
  13392. self.log('Failed to load');
  13393. self.log(file);
  13394. if (params.error)
  13395. self.do(params.error);
  13396. //self.do(params.error);
  13397. });
  13398. } else {
  13399. if (params.success)
  13400. self.do(params.success);
  13401. //self.do(params.success);
  13402. }
  13403. };
  13404. this.loadModuleGlobal = function () {
  13405. self.log('loadModuleGlobal');
  13406. var promises = [];
  13407. var modules = []; // we need it to keep the order of the modules given in the config
  13408. for (let key in self.json.setup.modules) {
  13409. var mod = self.replaceProperties(self.json.setup.modules[key]);
  13410. modules = modules.concat(self.cloneObject(mod));
  13411. }
  13412. /* self.log('modules');
  13413. self.log(modules); */
  13414. for (let mod of modules)
  13415. promises.push(self.loadModule(mod));
  13416. //var pageModule = {name: 'global', url: '/app/modules/global.json'};
  13417. //var ideModule = {name: 'ide', url: '/app/modules/ide.json'};
  13418. //promises.push(self.loadModule(ideModule)); // if admin
  13419. Promise.all(promises).then(function () {
  13420. //self.log('page module loaded');
  13421. //if (self.json.modules) {
  13422. //self.json.setup.modules = self.cloneObject(self.json.modules); // required modules
  13423. //self.json.setup.modules.app.push(pageModule); // page module
  13424. //self.json.setup.modules.app.push(ideModule); // ide module if admin
  13425. self.loadModules();
  13426. //}
  13427. }).catch(function (file) {
  13428. self.log('Failed to load');
  13429. self.log(file);
  13430. });
  13431. };
  13432. /* this.extendJsonFromModules = function () {
  13433. self.log('extendJsonFromModules');
  13434. for (var mod in self.modules) {
  13435. //self.extendJsonFromElement(self.modules[mod.name]);
  13436. self.extendJson(json, self.modules[mod]);
  13437. }
  13438. } */
  13439. /* DA SISTEMARE - TEMPORANEO */
  13440. this.code = function (params, selectorParams) {
  13441. /* self.log("params");
  13442. self.log(params);
  13443. self.log("selectorParams");
  13444. self.log(selectorParams); */
  13445. let container = self.selector(params.selector || params.container) || self.selector(selectorParams);
  13446. //var container = self.selector(params) || self.selector(selectorParams);
  13447. self.log("this.code");
  13448. self.log("container");
  13449. self.log(container);
  13450. var editorContainer = container.slice(1);
  13451. //if (editorContainer.startsWith('#')) {editorContainer.slice(1);} // remove #
  13452. var editor = ace.edit(editorContainer);
  13453. var value = params.value; // else value = params;
  13454. if (!params.do || (params.do == 'set')) {
  13455. //var langTools = ace.require('ace/ext/language_tools');
  13456. if (params.theme) editor.setTheme(params.theme); // "ace/theme/monokai"
  13457. var editorMode = params.mode || "ace/mode/json";
  13458. editor.getSession().setMode(editorMode);
  13459. var editorStyle = self.extend({
  13460. background: "rgba(255,255,255,0)"
  13461. }, params.style);
  13462. //$(container).css(editorStyle); //editor.container.style
  13463. /* self.css({
  13464. style: editorStyle
  13465. }, {
  13466. container: container
  13467. }); */ // Eventualmente
  13468. var codeOptions = self.extend({
  13469. fontSize: "11pt",
  13470. selectionStyle: "line",
  13471. highlightActiveLine: false,
  13472. wrap: true,
  13473. showLineNumbers: false,
  13474. showGutter: false,
  13475. fixedWidthGutter: false,
  13476. readOnly: true,
  13477. //enableBasicAutocompletion: false,
  13478. //enableSnippets: false,
  13479. //enableLiveAutocompletion: false,
  13480. }, params.options);
  13481. // https://github.com/ajaxorg/ace/wiki/Configuring-Ace
  13482. editor.setOptions(codeOptions);
  13483. var codeString;
  13484. if (typeof value == 'string')
  13485. if (editorMode == "ace/mode/json")
  13486. codeString = JSON.stringify(JSON.parse(value), null, '\t'); // json formatting
  13487. else
  13488. codeString = value;
  13489. else {
  13490. if (editorMode == "ace/mode/json")
  13491. codeString = JSON.stringify(value, null, '\t');
  13492. else {
  13493. var functionObj = self.docElement(value.function);
  13494. var functionParams = value.params;
  13495. codeString = functionObj(functionParams);
  13496. }
  13497. }
  13498. var codeRows = codeString.split(/\r\n|\r|\n/).length;
  13499. // $(container).css({
  13500. // height: Number(21 * codeRows) + 'px'
  13501. // });
  13502. /* self.css({
  13503. style: {
  13504. height: Number(21*codeRows)+"px"
  13505. }
  13506. }, {
  13507. container: container
  13508. }); */ // Eventualmente
  13509. editor.setValue(codeString, -1);
  13510. } else if (params.do == 'get') {
  13511. return editor.getValue();
  13512. } else {
  13513. self.log('"code" function requires value param');
  13514. }
  13515. };
  13516. this.init = function (appString, modulesString) {
  13517. console.log('init');
  13518. // app(String: app url) (Object = json app)
  13519. // modules(String): modules "ui,daisyui,svg"
  13520. /* json = { // the jsonic app tree
  13521. blocks: {},
  13522. parts: {},
  13523. css: {},
  13524. do: {},
  13525. on: {},
  13526. texts: {},
  13527. data: {},
  13528. var: {}
  13529. }; */
  13530. //self.app = self.getParams(); // from url
  13531. if (typeof appString == 'string') {
  13532. let modules = [{ "name": "app", "url": appString }];
  13533. let modulesNames = (modulesString) ? modulesString.split(",") : [];
  13534. for (let modName of modulesNames) {
  13535. modules.push({ "name": modName, "url": "jsonic/modules/" + modName + ".json" });
  13536. }
  13537. self.json.setup = { "modules": modules };
  13538. } else {
  13539. if (appString) self.extendJson(self.json, appString);
  13540. /* // TO DO: remove the requirement of resources.json
  13541. if (!self.json.setup || !self.json.setup.modules) {
  13542. self.json.setup = {
  13543. "modules": [
  13544. {
  13545. "name": "resources",
  13546. "url": "https://jsonic.io/app/modules/lib/resources.json"
  13547. }
  13548. ]
  13549. }
  13550. } */
  13551. if (appString.css) self.defineCss(appString.css); // can be removed?
  13552. }
  13553. self.loadModuleGlobal();
  13554. };
  13555. function toJsonNode(xml) {
  13556. let obj = {};
  13557. if (xml.nodeType == 1) {
  13558. if (xml.attributes.length > 0) {
  13559. obj["attr"] = {};
  13560. for (let j = 0; j < xml.attributes.length; j++) {
  13561. let attribute = xml.attributes.item(j);
  13562. obj["attr"][attribute.nodeName] = attribute.nodeValue;
  13563. }
  13564. }
  13565. }
  13566. if (xml.hasChildNodes()) {
  13567. for (let i = 0; i < xml.childNodes.length; i++) {
  13568. let item = xml.childNodes.item(i);
  13569. let nodeName = item.nodeName;
  13570. if (item.nodeType == 3 && nodeName == "#text") {
  13571. if (/^\s+$/.test(item.nodeValue)) {
  13572. } else obj.text = item.nodeValue;
  13573. } else {
  13574. if (typeof obj[nodeName] == "undefined") {
  13575. obj[nodeName] = toJsonNode(item);
  13576. } else {
  13577. if (!Array.isArray(obj[nodeName]))
  13578. obj[nodeName] = [obj[nodeName]];
  13579. obj[nodeName].push(toJsonNode(item));
  13580. }
  13581. }
  13582. }
  13583. }
  13584. return obj;
  13585. }
  13586. this.htmlToJson = function (text) {
  13587. let xmlDoc = new DOMParser().parseFromString(text, "text/xml");
  13588. return JSON.stringify(toJsonNode(xmlDoc), null, "\t");
  13589. };
  13590. this.elementToJson = function (selector) {
  13591. let el = document.querySelector(selector);
  13592. return self.htmlToJson(el.getHTML());
  13593. };
  13594. function clearSelection() {
  13595. if (window.getSelection) { window.getSelection().removeAllRanges(); }
  13596. else if (document.selection) { document.selection.empty(); }
  13597. }
  13598. this.importHtml = function (htmlText) {
  13599. // use modal and monaco js
  13600. if (!htmlText)
  13601. htmlText = prompt("html/xml");
  13602. if (htmlText) {
  13603. let jsonDoc = self.htmlToJson(htmlText);
  13604. let textarea = document.createElement("textarea");
  13605. textarea.value = jsonDoc;
  13606. textarea.style = "position: absolute; z-index: 999999; background: white; width:100vw; height:100vh";
  13607. //document.body.innerHTML = '';
  13608. document.body.appendChild(textarea);
  13609. //document.execCommand("copy");
  13610. textarea.addEventListener('click', function () {
  13611. textarea.remove();
  13612. navigator.clipboard.writeText(textarea.value).then(() => console.log('copied!'));
  13613. });
  13614. //console.log(JSON.parse(jsonDoc));
  13615. }
  13616. };
  13617. // https://github.com/ktskts/html2json/blob/master/src/html2json.js
  13618. /*
  13619. var Util = {
  13620. div : null,
  13621. attrs: "id,name,style,class,value,src,href,width,height,title,type".split(","),
  13622. getJson: function(childNodes, attrs, length) {
  13623. var result = [];
  13624. for ( var i = 0, len = childNodes.length; i < len; i++) {
  13625. var item = childNodes[i];
  13626. if (item.nodeType == 3) { // textual content in an element or attribute
  13627. result.push({
  13628. text : item.nodeValue
  13629. })
  13630. } else if (item.nodeType == 1) { // element
  13631. var obj = {
  13632. //tag : item.nodeName.toLowerCase(),
  13633. attr : {}
  13634. };
  13635. var flag = false;
  13636. //for ie6
  13637. if (attrs) {
  13638. for (var j = 0; j < length; j++){
  13639. if (attrs[j] == 'style'){
  13640. var sStyle = item.getAttribute('style').cssText;
  13641. if(sStyle){
  13642. obj.attr["style"] = sStyle;
  13643. flag = true;
  13644. }
  13645. } else {
  13646. var attrNode = item.attributes[attrs[j]];
  13647. if(attrNode && attrNode.nodeType === 2){
  13648. var value = attrNode.value;
  13649. if(value && value != 'null'){
  13650. obj.attr[attrs[j]] = value;
  13651. flag = true;
  13652. }
  13653. }
  13654. }
  13655. }
  13656. } else {
  13657. if (item.attributes.length) {
  13658. for ( var n = 0, l = item.attributes.length; n < l; n++) {
  13659. var value = item.attributes[n].value;
  13660. if(value){
  13661. flag = true;
  13662. obj.attr[item.attributes[n].name] = value;
  13663. }
  13664. }
  13665. }
  13666. }
  13667. let nodeOut = {};
  13668. let nodeTag = item.nodeName.toLowerCase();
  13669. let nodeChild = Util.getJson(item.childNodes, attrs, length);
  13670. nodeOut[nodeTag] = {};
  13671. self.log( 'item.childNodes');
  13672. self.log( item.childNodes);
  13673. self.log( 'nodeChild');
  13674. self.log( nodeChild);
  13675. //self.log( item.textContent);
  13676. nodeOut[nodeTag].html = nodeChild;
  13677. if (flag) nodeOut[nodeTag].attr = obj.attr;
  13678. result.push(nodeOut);
  13679. } else {
  13680. // do nothing
  13681. }
  13682. }
  13683. if (result.length == 1) return result[0]
  13684. else if (result.length > 1) return result;
  13685. }
  13686. }
  13687. this.html2json = function(text) {
  13688. if (!Util.div) Util.div = document.createElement('div');
  13689. Util.div.innerHTML = text;
  13690. return {html: Util.getJson(Util.div.childNodes)};
  13691. };
  13692. */
  13693. /* var jsonicOptions = self.extend({
  13694. }, options); */
  13695. if (typeof options == 'object') {
  13696. } else if (options)
  13697. self.init(arguments[0], arguments[1]);
  13698. } // of jsonicObject
  13699. //var jsonicApp = jsonApp;
  13700. var jsonApp = new jsonAppObj();
  13701. var js = jsonApp;
  13702. var jsonic = jsonApp;
  13703. //window.jsonic = new jsonicObject();
  13704. /* var receiveMessage = function (process) {
  13705. if (ThunkableWebviewerExtension)
  13706. ThunkableWebviewerExtension.receiveMessage(process);
  13707. }
  13708. var postMessage = function (message) {
  13709. if (ThunkableWebviewerExtension)
  13710. ThunkableWebviewerExtension.postMessage(message);
  13711. } */
  13712. /* "on": {
  13713. "init": [
  13714. {
  13715. "thunkable": {
  13716. "postMessage": "Hi Rick!"
  13717. }
  13718. },
  13719. {
  13720. "thunkable": {
  13721. "receiveMessage": {
  13722. "alert": "message: {result}"
  13723. }
  13724. }
  13725. }
  13726. ]
  13727. }
  13728. */