Browse Source

Add script-props property to Component

ui-module
Artur Arseniev 5 years ago
parent
commit
59fc111ab4
  1. 17
      src/canvas/view/CanvasView.js
  2. 45
      src/code_manager/model/JsGenerator.js
  3. 60
      src/dom_components/model/Component.js

17
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);

45
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;

60
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;
},

Loading…
Cancel
Save