From 59fc111ab44a7d22fb9996df6835d0f5e2bdde9a Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 18 Dec 2020 00:14:43 +0100 Subject: [PATCH] Add script-props property to Component --- src/canvas/view/CanvasView.js | 17 ++++---- src/code_manager/model/JsGenerator.js | 45 ++++++++++++++------ src/dom_components/model/Component.js | 60 +++++++++++++++++---------- 3 files changed, 80 insertions(+), 42 deletions(-) diff --git a/src/canvas/view/CanvasView.js b/src/canvas/view/CanvasView.js index 4ace6d1cf..1767c5cb2 100644 --- a/src/canvas/view/CanvasView.js +++ b/src/canvas/view/CanvasView.js @@ -296,14 +296,17 @@ export default Backbone.View.extend({ // In editor, I make use of setTimeout as during the append process of elements // those will not be available immediately, therefore 'item' variable const script = document.createElement('script'); + const scriptFn = model.getScriptString(); + const scriptFnStr = model.get('script-props') + ? scriptFn + : `function(){${scriptFn};}`; + const scriptProps = JSON.stringify(model.__getScriptProps()); script.innerHTML = ` - setTimeout(function() { - var item = document.getElementById('${id}'); - if (!item) return; - (function(){ - ${model.getScriptString()}; - }.bind(item))() - }, 1);`; + setTimeout(function() { + var item = document.getElementById('${id}'); + if (!item) return; + (${scriptFnStr}.bind(item))(${scriptProps}) + }, 1);`; // #873 // Adding setTimeout will make js components work on init of the editor setTimeout(() => view.scriptContainer.get(0).appendChild(script), 0); diff --git a/src/code_manager/model/JsGenerator.js b/src/code_manager/model/JsGenerator.js index 1f9e2fc12..1790becda 100644 --- a/src/code_manager/model/JsGenerator.js +++ b/src/code_manager/model/JsGenerator.js @@ -15,17 +15,26 @@ export default Backbone.Model.extend({ attr = extend({}, attr, { id }); model.set('attributes', attr, { silent: 1 }); var scrStr = model.getScriptString(script); + const scrProps = model.get('script-props'); // If the script was updated, I'll put its code in a separate container - if (model.get('scriptUpdated')) { + if (model.get('scriptUpdated') && !scrProps) { this.mapJs[type + '-' + id] = { ids: [id], code: scrStr }; } else { - var mapType = this.mapJs[type]; + let props; + const mapType = this.mapJs[type]; + + if (scrProps) { + props = model.__getScriptProps(); + } if (mapType) { mapType.ids.push(id); + if (props) mapType.props[id] = props; } else { - this.mapJs[type] = { ids: [id], code: scrStr }; + const res = { ids: [id], code: scrStr }; + if (props) res.props = { [id]: props }; + this.mapJs[type] = res; } } } @@ -40,17 +49,29 @@ export default Backbone.Model.extend({ build(model) { this.mapJs = {}; this.mapModel(model); + let code = ''; - var code = ''; + for (let type in this.mapJs) { + const mapType = this.mapJs[type]; - for (var type in this.mapJs) { - var mapType = this.mapJs[type]; - var ids = '#' + mapType.ids.join(', #'); - code += ` - var items = document.querySelectorAll('${ids}'); - for (var i = 0, len = items.length; i < len; i++) { - (function(){${mapType.code}}.bind(items[i]))(); - }`; + if (mapType.props) { + code += ` + var props = ${JSON.stringify(mapType.props)}; + var ids = Object.keys(props).map(function(id) { return '#'+id }).join(','); + var els = document.querySelectorAll(ids); + for (var i = 0, len = els.length; i < len; i++) { + var el = els[i]; + (${mapType.code}.bind(el))(props[el.id]); + }`; + } else { + // Deprecated + const ids = '#' + mapType.ids.join(', #'); + code += ` + var items = document.querySelectorAll('${ids}'); + for (var i = 0, len = items.length; i < len; i++) { + (function(){${mapType.code}}.bind(items[i]))(); + }`; + } } return code; diff --git a/src/dom_components/model/Component.js b/src/dom_components/model/Component.js index 314c96554..7b87dbc38 100644 --- a/src/dom_components/model/Component.js +++ b/src/dom_components/model/Component.js @@ -116,6 +116,7 @@ const Component = Backbone.Model.extend(Styleable).extend( style: '', // Component related style classes: '', // Array of classes script: '', + 'script-props': '', 'script-export': '', attributes: '', traits: ['id', 'title'], @@ -1259,6 +1260,15 @@ const Component = Backbone.Model.extend(Styleable).extend( return this.getView(frame); }, + __getScriptProps() { + const modelProps = this.props(); + const scrProps = this.get('script-props') || []; + return scrProps.reduce((acc, prop) => { + acc[prop] = modelProps[prop]; + return acc; + }, {}); + }, + /** * Return script in string format, cleans 'function() {..' from scripts * if it's a function @@ -1267,35 +1277,39 @@ const Component = Backbone.Model.extend(Styleable).extend( * @private */ getScriptString(script) { - var scr = script || this.get('script'); + let scr = script || this.get('script'); if (!scr) { return scr; } - // Need to convert script functions to strings - if (typeof scr == 'function') { - var scrStr = scr.toString().trim(); - scrStr = scrStr - .replace(/^function[\s\w]*\(\)\s?\{/, '') - .replace(/\}$/, ''); - scr = scrStr.trim(); - } - - var config = this.em.getConfig(); - var tagVarStart = escapeRegExp(config.tagVarStart || '{[ '); - var tagVarEnd = escapeRegExp(config.tagVarEnd || ' ]}'); - var reg = new RegExp(`${tagVarStart}([\\w\\d-]*)${tagVarEnd}`, 'g'); - scr = scr.replace(reg, (match, v) => { - // If at least one match is found I have to track this change for a - // better optimization inside JS generator - this.scriptUpdated(); - const result = this.attributes[v] || ''; - return isArray(result) || typeof result == 'object' - ? JSON.stringify(result) - : result; - }); + if (this.get('script-props')) { + scr = scr.toString().trim(); + } else { + // Deprecated + // Need to convert script functions to strings + if (typeof scr == 'function') { + var scrStr = scr.toString().trim(); + scrStr = scrStr + .replace(/^function[\s\w]*\(\)\s?\{/, '') + .replace(/\}$/, ''); + scr = scrStr.trim(); + } + var config = this.em.getConfig(); + var tagVarStart = escapeRegExp(config.tagVarStart || '{[ '); + var tagVarEnd = escapeRegExp(config.tagVarEnd || ' ]}'); + var reg = new RegExp(`${tagVarStart}([\\w\\d-]*)${tagVarEnd}`, 'g'); + scr = scr.replace(reg, (match, v) => { + // If at least one match is found I have to track this change for a + // better optimization inside JS generator + this.scriptUpdated(); + const result = this.attributes[v] || ''; + return isArray(result) || typeof result == 'object' + ? JSON.stringify(result) + : result; + }); + } return scr; },