Browse Source

Add prettier and run it

pull/758/head
Artur Arseniev 9 years ago
parent
commit
46912b2dfd
  1. 6
      package-lock.json
  2. 4
      package.json
  3. 21
      src/asset_manager/index.js
  4. 16
      src/asset_manager/model/Asset.js
  5. 9
      src/asset_manager/model/AssetImage.js
  6. 30
      src/asset_manager/model/Assets.js
  7. 5
      src/asset_manager/view/AssetImageView.js
  8. 3
      src/asset_manager/view/AssetView.js
  9. 13
      src/asset_manager/view/AssetsView.js
  10. 587
      src/asset_manager/view/FileUploader.js
  11. 4
      src/block_manager/config/config.js
  12. 382
      src/block_manager/index.js
  13. 8
      src/block_manager/model/Block.js
  14. 2
      src/block_manager/model/Blocks.js
  15. 2
      src/block_manager/model/Categories.js
  16. 6
      src/block_manager/model/Category.js
  17. 12
      src/block_manager/view/BlockView.js
  18. 47
      src/block_manager/view/BlocksView.js
  19. 13
      src/block_manager/view/CategoryView.js
  20. 4
      src/canvas/config/config.js
  21. 50
      src/canvas/index.js
  22. 8
      src/canvas/model/Canvas.js
  23. 8
      src/canvas/model/Frame.js
  24. 80
      src/canvas/view/CanvasView.js
  25. 11
      src/canvas/view/FrameView.js
  26. 2
      src/code_manager/config/config.js
  27. 42
      src/code_manager/index.js
  28. 30
      src/code_manager/model/CodeMirrorEditor.js
  29. 12
      src/code_manager/model/CssGenerator.js
  30. 7
      src/code_manager/model/HtmlGenerator.js
  31. 21
      src/code_manager/model/JsGenerator.js
  32. 34
      src/code_manager/model/JsonGenerator.js
  33. 8
      src/code_manager/view/EditorView.js
  34. 3
      src/commands/config/config.js
  35. 51
      src/commands/index.js
  36. 6
      src/commands/model/Command.js
  37. 4
      src/commands/model/Commands.js
  38. 27
      src/commands/view/CommandAbstract.js
  39. 68
      src/commands/view/CreateComponent.js
  40. 44
      src/commands/view/DeleteComponent.js
  41. 9
      src/commands/view/Drag.js
  42. 6
      src/commands/view/ExportTemplate.js
  43. 46
      src/commands/view/Fullscreen.js
  44. 14
      src/commands/view/ImageComponent.js
  45. 15
      src/commands/view/InsertCustom.js
  46. 32
      src/commands/view/MoveComponent.js
  47. 8
      src/commands/view/OpenAssets.js
  48. 3
      src/commands/view/OpenBlocks.js
  49. 10
      src/commands/view/OpenLayers.js
  50. 55
      src/commands/view/OpenStyleManager.js
  51. 23
      src/commands/view/OpenTraitManager.js
  52. 15
      src/commands/view/Preview.js
  53. 6
      src/commands/view/Resize.js
  54. 96
      src/commands/view/SelectComponent.js
  55. 4
      src/commands/view/SelectParent.js
  56. 46
      src/commands/view/SelectPosition.js
  57. 14
      src/commands/view/ShowOffset.js
  58. 4
      src/commands/view/SwitchVisibility.js
  59. 13
      src/commands/view/TextComponent.js
  60. 6
      src/css_composer/config/config.js
  61. 697
      src/css_composer/index.js
  62. 72
      src/css_composer/model/CssRule.js
  63. 15
      src/css_composer/model/CssRules.js
  64. 6
      src/css_composer/view/CssRuleView.js
  65. 21
      src/css_composer/view/CssRulesView.js
  66. 4
      src/device_manager/config/config.js
  67. 176
      src/device_manager/index.js
  68. 6
      src/device_manager/model/Device.js
  69. 2
      src/device_manager/model/Devices.js
  70. 22
      src/device_manager/view/DevicesView.js
  71. 33
      src/dom_components/config/config.js
  72. 93
      src/dom_components/index.js
  73. 1383
      src/dom_components/model/Component.js
  74. 179
      src/dom_components/model/ComponentImage.js
  75. 90
      src/dom_components/model/ComponentLink.js
  76. 180
      src/dom_components/model/ComponentMap.js
  77. 41
      src/dom_components/model/ComponentScript.js
  78. 54
      src/dom_components/model/ComponentSvg.js
  79. 40
      src/dom_components/model/ComponentTable.js
  80. 94
      src/dom_components/model/ComponentTableBody.js
  81. 37
      src/dom_components/model/ComponentTableCell.js
  82. 31
      src/dom_components/model/ComponentTableFoot.js
  83. 31
      src/dom_components/model/ComponentTableHead.js
  84. 45
      src/dom_components/model/ComponentTableRow.js
  85. 9
      src/dom_components/model/ComponentText.js
  86. 43
      src/dom_components/model/ComponentTextNode.js
  87. 560
      src/dom_components/model/ComponentVideo.js
  88. 51
      src/dom_components/model/Components.js
  89. 2
      src/dom_components/model/Toolbar.js
  90. 8
      src/dom_components/model/ToolbarButton.js
  91. 16
      src/dom_components/view/ComponentImageView.js
  92. 4
      src/dom_components/view/ComponentLinkView.js
  93. 8
      src/dom_components/view/ComponentMapView.js
  94. 41
      src/dom_components/view/ComponentScriptView.js
  95. 2
      src/dom_components/view/ComponentSvgView.js
  96. 2
      src/dom_components/view/ComponentTableView.js
  97. 16
      src/dom_components/view/ComponentTextView.js
  98. 13
      src/dom_components/view/ComponentVideoView.js
  99. 59
      src/dom_components/view/ComponentView.js
  100. 25
      src/dom_components/view/ComponentsView.js

6
package-lock.json

@ -8667,6 +8667,12 @@
"integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
"dev": true "dev": true
}, },
"prettier": {
"version": "1.10.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-1.10.1.tgz",
"integrity": "sha512-lPTx4BsvN5v9w/JXBRNlvTXCJBKrr7VW4NOl1rdX00x+YuOLqNYAOGk2x7v+4PI4hx/SyW1Z3AEg9MeB87yYcQ==",
"dev": true
},
"pretty-error": { "pretty-error": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz", "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",

4
package.json

@ -25,7 +25,6 @@
"babel-core": "^6.24.1", "babel-core": "^6.24.1",
"babel-loader": "^7.0.0", "babel-loader": "^7.0.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0", "babel-plugin-transform-object-rest-spread": "^6.26.0",
"promise-polyfill": "^6.0.2",
"babel-preset-env": "^1.6.1", "babel-preset-env": "^1.6.1",
"chai": "^4.1.2", "chai": "^4.1.2",
"cross-env": "^5.0.5", "cross-env": "^5.0.5",
@ -37,6 +36,8 @@
"jsdom": "^11.2.0", "jsdom": "^11.2.0",
"mocha": "^3.1.2", "mocha": "^3.1.2",
"node-sass": "^4.5.3", "node-sass": "^4.5.3",
"prettier": "1.10.1",
"promise-polyfill": "^6.0.2",
"sinon": "^3.2.1", "sinon": "^3.2.1",
"string-replace-loader": "^1.3.0", "string-replace-loader": "^1.3.0",
"webpack": "^3.5.5", "webpack": "^3.5.5",
@ -81,6 +82,7 @@
"build:css": "node-sass src/styles/scss/main.scss dist/css/grapes.min.css --output-style compressed", "build:css": "node-sass src/styles/scss/main.scss dist/css/grapes.min.css --output-style compressed",
"v:patch": "npm version --no-git-tag-version patch", "v:patch": "npm version --no-git-tag-version patch",
"start": "npm run build:css -- -w & webpack-dev-server --open --progress --colors", "start": "npm run build:css -- -w & webpack-dev-server --open --progress --colors",
"format": "prettier --single-quote --write './{src,test}/**/*.js'",
"test": "cross-env NODE_PATH=./src mocha --compilers js:babel-core/register --require test/helper.js --timeout 10000 --recursive test/main.js", "test": "cross-env NODE_PATH=./src mocha --compilers js:babel-core/register --require test/helper.js --timeout 10000 --recursive test/main.js",
"test:dev": "npm test -- -R min -w" "test:dev": "npm test -- -R min -w"
} }

21
src/asset_manager/index.js

@ -47,7 +47,6 @@ module.exports = () => {
let assets, am, fu; let assets, am, fu;
return { return {
/** /**
* Name of the module * Name of the module
* @type {String} * @type {String}
@ -75,8 +74,7 @@ module.exports = () => {
c = config || {}; c = config || {};
for (let name in defaults) { for (let name in defaults) {
if (!(name in c)) if (!(name in c)) c[name] = defaults[name];
c[name] = defaults[name];
} }
const ppfx = c.pStylePrefix; const ppfx = c.pStylePrefix;
@ -92,19 +90,19 @@ module.exports = () => {
// Collection visible in asset manager // Collection visible in asset manager
collection: new Assets([]), collection: new Assets([]),
globalCollection: assets, globalCollection: assets,
config: c, config: c
}; };
fu = new FileUpload(obj); fu = new FileUpload(obj);
obj.fu = fu; obj.fu = fu;
am = new AssetsView(obj); am = new AssetsView(obj);
// Setup the sync between the global and public collections // Setup the sync between the global and public collections
assets.listenTo(assets, 'add', (model) => { assets.listenTo(assets, 'add', model => {
this.getAllVisible().add(model); this.getAllVisible().add(model);
em && em.trigger('asset:add', model); em && em.trigger('asset:add', model);
}); });
assets.listenTo(assets, 'remove', (model) => { assets.listenTo(assets, 'remove', model => {
this.getAllVisible().remove(model); this.getAllVisible().remove(model);
em && em.trigger('asset:remove', model); em && em.trigger('asset:remove', model);
}); });
@ -136,7 +134,6 @@ module.exports = () => {
* }]); * }]);
*/ */
add(asset, opts = {}) { add(asset, opts = {}) {
// Put the model at the beginning // Put the model at the beginning
if (typeof opts.at == 'undefined') { if (typeof opts.at == 'undefined') {
opts.at = 0; opts.at = 0;
@ -153,7 +150,7 @@ module.exports = () => {
* var asset = assetManager.get('http://img.jpg'); * var asset = assetManager.get('http://img.jpg');
*/ */
get(src) { get(src) {
return assets.where({src})[0]; return assets.where({ src })[0];
}, },
/** /**
@ -196,8 +193,7 @@ module.exports = () => {
var obj = {}; var obj = {};
var assets = JSON.stringify(this.getAll().toJSON()); var assets = JSON.stringify(this.getAll().toJSON());
obj[this.storageKey] = assets; obj[this.storageKey] = assets;
if(!noStore && c.stm) if (!noStore && c.stm) c.stm.store(obj);
c.stm.store(obj);
return obj; return obj;
}, },
@ -219,7 +215,7 @@ module.exports = () => {
if (typeof assets == 'string') { if (typeof assets == 'string') {
try { try {
assets = JSON.parse(data[name]); assets = JSON.parse(data[name]);
} catch(err) {} } catch (err) {}
} }
if (assets && assets.length) { if (assets && assets.length) {
@ -357,7 +353,6 @@ module.exports = () => {
*/ */
onDblClick(func) { onDblClick(func) {
c.onDblClick = func; c.onDblClick = func;
}, }
}; };
}; };

16
src/asset_manager/model/Asset.js

@ -1,10 +1,9 @@
module.exports = require('backbone').Model.extend({ module.exports = require('backbone').Model.extend({
idAttribute: 'src', idAttribute: 'src',
defaults: { defaults: {
type: '', type: '',
src: '', src: ''
}, },
/** /**
@ -13,7 +12,9 @@ module.exports = require('backbone').Model.extend({
* @private * @private
* */ * */
getFilename() { getFilename() {
return this.get('src').split('/').pop(); return this.get('src')
.split('/')
.pop();
}, },
/** /**
@ -22,7 +23,8 @@ module.exports = require('backbone').Model.extend({
* @private * @private
* */ * */
getExtension() { getExtension() {
return this.getFilename().split('.').pop(); return this.getFilename()
}, .split('.')
.pop();
}
}); });

9
src/asset_manager/model/AssetImage.js

@ -1,12 +1,11 @@
const Asset = require('./Asset'); const Asset = require('./Asset');
module.exports = Asset.extend({ module.exports = Asset.extend({
defaults: {
defaults: { ...Asset.prototype.defaults, ...Asset.prototype.defaults,
type: 'image', type: 'image',
unitDim: 'px', unitDim: 'px',
height: 0, height: 0,
width: 0, width: 0
}, }
}); });

30
src/asset_manager/model/Assets.js

@ -1,18 +1,22 @@
import TypeableCollection from 'domain_abstract/model/TypeableCollection'; import TypeableCollection from 'domain_abstract/model/TypeableCollection';
module.exports = require('backbone').Collection.extend(TypeableCollection).extend({ module.exports = require('backbone')
types: [{ .Collection.extend(TypeableCollection)
id: 'image', .extend({
model: require('./AssetImage'), types: [
view: require('./../view/AssetImageView'), {
isType(value) { id: 'image',
if (typeof value == 'string') { model: require('./AssetImage'),
return { view: require('./../view/AssetImageView'),
type: 'image', isType(value) {
src: value, if (typeof value == 'string') {
return {
type: 'image',
src: value
};
} }
return value;
} }
return value;
} }
}] ]
}); });

5
src/asset_manager/view/AssetImageView.js

@ -1,9 +1,8 @@
module.exports = require('./AssetView').extend({ module.exports = require('./AssetView').extend({
events: { events: {
'click [data-toggle=asset-remove]': 'onRemove', 'click [data-toggle=asset-remove]': 'onRemove',
click: 'onClick', click: 'onClick',
dblclick: 'onDblClick', dblclick: 'onDblClick'
}, },
getPreview() { getPreview() {
@ -32,7 +31,7 @@ module.exports = require('./AssetView').extend({
init(o) { init(o) {
const pfx = this.pfx; const pfx = this.pfx;
this.className += ` ${pfx}asset-image`; this.className += ` ${pfx}asset-image`;
}, },
/** /**

3
src/asset_manager/view/AssetView.js

@ -1,5 +1,4 @@
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
initialize(o = {}) { initialize(o = {}) {
this.options = o; this.options = o;
this.collection = o.collection; this.collection = o.collection;
@ -55,5 +54,5 @@ module.exports = Backbone.View.extend({
el.innerHTML = this.template(this, this.model); el.innerHTML = this.template(this, this.model);
el.className = this.className; el.className = this.className;
return this; return this;
}, }
}); });

13
src/asset_manager/view/AssetsView.js

@ -3,9 +3,8 @@ var AssetImageView = require('./AssetImageView');
var FileUploader = require('./FileUploader'); var FileUploader = require('./FileUploader');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
events: { events: {
submit: 'handleSubmit', submit: 'handleSubmit'
}, },
template(view) { template(view) {
@ -66,7 +65,7 @@ module.exports = Backbone.View.extend({
if (handleAdd) { if (handleAdd) {
handleAdd(url); handleAdd(url);
} else { } else {
this.options.globalCollection.add(url, {at: 0}); this.options.globalCollection.add(url, { at: 0 });
} }
}, },
@ -86,7 +85,7 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
getAddInput() { getAddInput() {
if(!this.inputUrl || !this.inputUrl.value) if (!this.inputUrl || !this.inputUrl.value)
this.inputUrl = this.el.querySelector(`.${this.pfx}add-asset input`); this.inputUrl = this.el.querySelector(`.${this.pfx}add-asset input`);
return this.inputUrl; return this.inputUrl;
}, },
@ -127,11 +126,11 @@ module.exports = Backbone.View.extend({
const rendered = new model.typeView({ const rendered = new model.typeView({
model, model,
collection, collection,
config, config
}).render().el; }).render().el;
if (fragment) { if (fragment) {
fragment.appendChild( rendered ); fragment.appendChild(rendered);
} else { } else {
const assetsEl = this.getAssetsEl(); const assetsEl = this.getAssetsEl();
if (assetsEl) { if (assetsEl) {
@ -172,7 +171,7 @@ module.exports = Backbone.View.extend({
const assets = this.$el.find(`.${this.pfx}assets`); const assets = this.$el.find(`.${this.pfx}assets`);
assets.empty(); assets.empty();
this.toggleNoAssets(this.collection.length); this.toggleNoAssets(this.collection.length);
this.collection.each((model) => this.addAsset(model, fragment)); this.collection.each(model => this.addAsset(model, fragment));
assets.append(fragment); assets.append(fragment);
}, },

587
src/asset_manager/view/FileUploader.js

@ -1,8 +1,8 @@
import fetch from 'utils/fetch'; import fetch from 'utils/fetch';
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend(
{
template: _.template(` template: _.template(`
<form> <form>
<div id="<%= pfx %>title"><%= title %></div> <div id="<%= pfx %>title"><%= title %></div>
<input type="file" id="<%= uploadId %>" name="file" accept="image/*" <%= disabled ? 'disabled' : '' %> multiple/> <input type="file" id="<%= uploadId %>" name="file" accept="image/*" <%= disabled ? 'disabled' : '' %> multiple/>
@ -10,307 +10,318 @@ module.exports = Backbone.View.extend({
</form> </form>
`), `),
events: {}, events: {},
initialize(opts = {}) { initialize(opts = {}) {
this.options = opts; this.options = opts;
const c = opts.config || {}; const c = opts.config || {};
this.config = c; this.config = c;
this.pfx = c.stylePrefix || ''; this.pfx = c.stylePrefix || '';
this.ppfx = c.pStylePrefix || ''; this.ppfx = c.pStylePrefix || '';
this.target = this.options.globalCollection || {}; this.target = this.options.globalCollection || {};
this.uploadId = this.pfx + 'uploadFile'; this.uploadId = this.pfx + 'uploadFile';
this.disabled = c.disableUpload !== undefined ? c.disableUpload : !c.upload && !c.embedAsBase64; this.disabled =
this.events['change #' + this.uploadId] = 'uploadFile'; c.disableUpload !== undefined
let uploadFile = c.uploadFile; ? c.disableUpload
: !c.upload && !c.embedAsBase64;
if (uploadFile) { this.events['change #' + this.uploadId] = 'uploadFile';
this.uploadFile = uploadFile.bind(this); let uploadFile = c.uploadFile;
} else if (c.embedAsBase64) {
this.uploadFile = this.constructor.embedAsBase64; if (uploadFile) {
} this.uploadFile = uploadFile.bind(this);
} else if (c.embedAsBase64) {
this.delegateEvents(); this.uploadFile = this.constructor.embedAsBase64;
}, }
/**
* Triggered before the upload is started
* @private
*/
onUploadStart() {
const em = this.config.em;
em && em.trigger('asset:upload:start');
},
/**
* Triggered after the upload is ended
* @param {Object|string} res End result
* @private
*/
onUploadEnd(res) {
const em = this.config.em;
em && em.trigger('asset:upload:end', res);
},
/**
* Triggered on upload error
* @param {Object} err Error
* @private
*/
onUploadError(err) {
const em = this.config.em;
console.error(err);
this.onUploadEnd(err);
em && em.trigger('asset:upload:error', err);
},
/**
* Triggered on upload response
* @param {string} text Response text
* @private
*/
onUploadResponse(text) {
const em = this.config.em;
const config = this.config;
const target = this.target;
const json = typeof text === 'string' ? JSON.parse(text) : text;
em && em.trigger('asset:upload:response', json);
if (config.autoAdd && target) {
target.add(json.data, {at: 0});
}
this.onUploadEnd(text);
},
/** this.delegateEvents();
* Upload files },
* @param {Object} e Event
* @return {Promise} /**
* @private * Triggered before the upload is started
* */ * @private
uploadFile(e) { */
const files = e.dataTransfer ? e.dataTransfer.files : e.target.files; onUploadStart() {
const body = new FormData(); const em = this.config.em;
const config = this.config; em && em.trigger('asset:upload:start');
const params = config.params; },
for (let i = 0; i < files.length; i++) { /**
body.append(`${config.uploadName}[]`, files[i]); * Triggered after the upload is ended
} * @param {Object|string} res End result
* @private
*/
onUploadEnd(res) {
const em = this.config.em;
em && em.trigger('asset:upload:end', res);
},
/**
* Triggered on upload error
* @param {Object} err Error
* @private
*/
onUploadError(err) {
const em = this.config.em;
console.error(err);
this.onUploadEnd(err);
em && em.trigger('asset:upload:error', err);
},
/**
* Triggered on upload response
* @param {string} text Response text
* @private
*/
onUploadResponse(text) {
const em = this.config.em;
const config = this.config;
const target = this.target;
const json = typeof text === 'string' ? JSON.parse(text) : text;
em && em.trigger('asset:upload:response', json);
if (config.autoAdd && target) {
target.add(json.data, { at: 0 });
}
for (let param in params) { this.onUploadEnd(text);
body.append(param, params[param]); },
}
/**
* Upload files
* @param {Object} e Event
* @return {Promise}
* @private
* */
uploadFile(e) {
const files = e.dataTransfer ? e.dataTransfer.files : e.target.files;
const body = new FormData();
const config = this.config;
const params = config.params;
for (let i = 0; i < files.length; i++) {
body.append(`${config.uploadName}[]`, files[i]);
}
var target = this.target; for (let param in params) {
const url = config.upload; body.append(param, params[param]);
const headers = config.headers; }
const reqHead = 'X-Requested-With';
if (typeof headers[reqHead] == 'undefined') { var target = this.target;
headers[reqHead] = 'XMLHttpRequest'; const url = config.upload;
} const headers = config.headers;
const reqHead = 'X-Requested-With';
if (url) { if (typeof headers[reqHead] == 'undefined') {
this.onUploadStart(); headers[reqHead] = 'XMLHttpRequest';
return fetch(url, {
method: 'post',
credentials: 'include',
headers,
body,
}).then(res => (res.status/200|0) == 1 ?
res.text() : res.text().then((text) =>
Promise.reject(text)
))
.then((text) => this.onUploadResponse(text))
.catch(err => this.onUploadError(err));
}
},
/**
* Make input file droppable
* @private
* */
initDrop() {
var that = this;
if(!this.uploadForm){
this.uploadForm = this.$el.find('form').get(0);
if( 'draggable' in this.uploadForm ){
var uploadFile = this.uploadFile;
this.uploadForm.ondragover = function(){
this.className = that.pfx + 'hover';
return false;
};
this.uploadForm.ondragleave = function(){
this.className = '';
return false;
};
this.uploadForm.ondrop = function(e){
this.className = '';
e.preventDefault();
that.uploadFile(e);
return;
};
} }
}
},
initDropzone(ev) { if (url) {
let addedCls = 0; this.onUploadStart();
const c = this.config; return fetch(url, {
const em = ev.model; method: 'post',
const edEl = ev.el; credentials: 'include',
const editor = em.get('Editor'); headers,
const container = em.get('Config').el; body
const frameEl = em.get('Canvas').getBody(); })
const ppfx = this.ppfx; .then(
const updatedCls = `${ppfx}dropzone-active`; res =>
const dropzoneCls = `${ppfx}dropzone`; ((res.status / 200) | 0) == 1
const cleanEditorElCls = () => { ? res.text()
edEl.className = edEl.className.replace(updatedCls, '').trim(); : res.text().then(text => Promise.reject(text))
addedCls = 0; )
} .then(text => this.onUploadResponse(text))
const onDragOver = () => { .catch(err => this.onUploadError(err));
if (!addedCls) {
edEl.className += ` ${updatedCls}`;
addedCls = 1;
} }
return false; },
};
const onDragLeave = () => { /**
cleanEditorElCls(); * Make input file droppable
return false; * @private
}; * */
const onDrop = (e) => { initDrop() {
var that = this;
if (!this.uploadForm) {
this.uploadForm = this.$el.find('form').get(0);
if ('draggable' in this.uploadForm) {
var uploadFile = this.uploadFile;
this.uploadForm.ondragover = function() {
this.className = that.pfx + 'hover';
return false;
};
this.uploadForm.ondragleave = function() {
this.className = '';
return false;
};
this.uploadForm.ondrop = function(e) {
this.className = '';
e.preventDefault();
that.uploadFile(e);
return;
};
}
}
},
initDropzone(ev) {
let addedCls = 0;
const c = this.config;
const em = ev.model;
const edEl = ev.el;
const editor = em.get('Editor');
const container = em.get('Config').el;
const frameEl = em.get('Canvas').getBody();
const ppfx = this.ppfx;
const updatedCls = `${ppfx}dropzone-active`;
const dropzoneCls = `${ppfx}dropzone`;
const cleanEditorElCls = () => {
edEl.className = edEl.className.replace(updatedCls, '').trim();
addedCls = 0;
};
const onDragOver = () => {
if (!addedCls) {
edEl.className += ` ${updatedCls}`;
addedCls = 1;
}
return false;
};
const onDragLeave = () => {
cleanEditorElCls();
return false;
};
const onDrop = e => {
cleanEditorElCls();
e.preventDefault();
e.stopPropagation();
this.uploadFile(e);
if (c.openAssetsOnDrop && editor) {
const target = editor.getSelected();
editor.runCommand('open-assets', {
target,
onSelect() {
editor.Modal.close();
editor.AssetManager.setTarget(null);
}
});
}
return false;
};
ev.$el.append(`<div class="${dropzoneCls}">${c.dropzoneContent}</div>`);
cleanEditorElCls(); cleanEditorElCls();
e.preventDefault();
e.stopPropagation(); if ('draggable' in edEl) {
this.uploadFile(e); [edEl, frameEl].forEach(item => {
item.ondragover = onDragOver;
if (c.openAssetsOnDrop && editor) { item.ondragleave = onDragLeave;
const target = editor.getSelected(); item.ondrop = onDrop;
editor.runCommand('open-assets', {
target,
onSelect() {
editor.Modal.close();
editor.AssetManager.setTarget(null);
}
}); });
} }
},
return false;
}; render() {
this.$el.html(
ev.$el.append(`<div class="${dropzoneCls}">${c.dropzoneContent}</div>`); this.template({
cleanEditorElCls(); title: this.config.uploadText,
uploadId: this.uploadId,
if ('draggable' in edEl) { disabled: this.disabled,
[edEl, frameEl].forEach((item) => { pfx: this.pfx
item.ondragover = onDragOver; })
item.ondragleave = onDragLeave; );
item.ondrop = onDrop; this.initDrop();
}); this.$el.attr('class', this.pfx + 'file-uploader');
return this;
} }
}, },
{
embedAsBase64: function(e) {
// List files dropped
const files = e.dataTransfer ? e.dataTransfer.files : e.target.files;
const response = { data: [] };
// Unlikely, widely supported now
if (!FileReader) {
this.onUploadError(
new Error('Unsupported platform, FileReader is not defined')
);
return;
}
render() { const promises = [];
this.$el.html( this.template({ const mimeTypeMatcher = /^(.+)\/(.+)$/;
title: this.config.uploadText,
uploadId: this.uploadId, for (const file of files) {
disabled: this.disabled, // For each file a reader (to read the base64 URL)
pfx: this.pfx // and a promise (to track and merge results and errors)
}) ); const promise = new Promise((resolve, reject) => {
this.initDrop(); const reader = new FileReader();
this.$el.attr('class', this.pfx + 'file-uploader'); reader.addEventListener('load', event => {
return this; let type;
}, const name = file.name;
}, { // Try to find the MIME type of the file.
embedAsBase64: function (e) { const match = mimeTypeMatcher.exec(file.type);
// List files dropped if (match) {
const files = e.dataTransfer ? e.dataTransfer.files : e.target.files; type = match[1]; // The first part in the MIME, "image" in image/png
const response = { data: [] }; } else {
type = file.type;
// Unlikely, widely supported now }
if (!FileReader) {
this.onUploadError(new Error('Unsupported platform, FileReader is not defined')); // If it's an image, try to find its size
return; if (type === 'image') {
} const data = {
src: reader.result,
const promises = []; name,
const mimeTypeMatcher = /^(.+)\/(.+)$/; type,
height: 0,
for (const file of files) { width: 0
// For each file a reader (to read the base64 URL) };
// and a promise (to track and merge results and errors)
const promise = new Promise((resolve, reject) => { const image = new Image();
const reader = new FileReader(); image.addEventListener('error', error => {
reader.addEventListener('load', (event) => { reject(error);
let type; });
const name = file.name; image.addEventListener('load', () => {
data.height = image.height;
// Try to find the MIME type of the file. data.width = image.width;
const match = mimeTypeMatcher.exec(file.type); resolve(data);
if (match) { });
type = match[1]; // The first part in the MIME, "image" in image/png image.src = data.src;
} else { } else if (type) {
type = file.type; // Not an image, but has a type
} resolve({
src: reader.result,
// If it's an image, try to find its size name,
if (type === 'image') { type
const data = { });
src: reader.result, } else {
name, // No type found, resolve with the URL only
type, resolve(reader.result);
height: 0, }
width: 0 });
}; reader.addEventListener('error', error => {
reject(error);
const image = new Image(); });
image.addEventListener('error', (error) => { reader.addEventListener('abort', error => {
reject(error); reject('Aborted');
}); });
image.addEventListener('load', () => {
data.height = image.height; reader.readAsDataURL(file);
data.width = image.width;
resolve(data);
});
image.src = data.src;
} else if (type) {
// Not an image, but has a type
resolve({
src: reader.result,
name,
type
});
} else {
// No type found, resolve with the URL only
resolve(reader.result);
}
});
reader.addEventListener('error', (error) => {
reject(error);
});
reader.addEventListener('abort', (error) => {
reject('Aborted');
}); });
reader.readAsDataURL(file); promises.push(promise);
}); }
promises.push(promise); Promise.all(promises).then(
data => {
response.data = data;
this.onUploadResponse(response);
},
error => {
this.onUploadError(error);
}
);
} }
Promise
.all(promises)
.then((data) => {
response.data = data;
this.onUploadResponse(response);
}, (error) => {
this.onUploadError(error);
});
} }
}); );

4
src/block_manager/config/config.js

@ -1,7 +1,5 @@
module.exports = { module.exports = {
blocks: [], blocks: [],
appendTo: '', appendTo: ''
}; };

382
src/block_manager/index.js

@ -30,201 +30,201 @@
*/ */
module.exports = () => { module.exports = () => {
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
Blocks = require('./model/Blocks'), Blocks = require('./model/Blocks'),
BlockCategories = require('./model/Categories'), BlockCategories = require('./model/Categories'),
BlocksView = require('./view/BlocksView'); BlocksView = require('./view/BlocksView');
var blocks, blocksVisible, blocksView; var blocks, blocksVisible, blocksView;
var categories = []; var categories = [];
return { return {
/**
/** * Name of the module
* Name of the module * @type {String}
* @type {String} * @private
* @private */
*/ name: 'BlockManager',
name: 'BlockManager',
/**
/** * Initialize module. Automatically called with a new instance of the editor
* Initialize module. Automatically called with a new instance of the editor * @param {Object} config Configurations
* @param {Object} config Configurations * @return {this}
* @return {this} * @private
* @private */
*/ init(config) {
init(config) { c = config || {};
c = config || {}; const em = c.em;
const em = c.em;
for (let name in defaults) {
for (let name in defaults) { if (!(name in c)) {
if (!(name in c)) { c[name] = defaults[name];
c[name] = defaults[name];
}
}
// Global blocks collection
blocks = new Blocks([]);
blocksVisible = new Blocks([]);
categories = new BlockCategories(),
blocksView = new BlocksView({
// Visible collection
collection: blocksVisible,
categories,
}, c);
// Setup the sync between the global and public collections
blocks.listenTo(blocks, 'add', model => {
blocksVisible.add(model);
em && em.trigger('block:add', model);
});
blocks.listenTo(blocks, 'remove', model => {
blocksVisible.remove(model);
em && em.trigger('block:remove', model);
});
blocks.listenTo(blocks, 'reset', coll => {
blocksVisible.reset(coll.models);
});
return this;
},
/**
* Get configuration object
* @return {Object}
*/
getConfig() {
return c;
},
/**
* Load default blocks if the collection is empty
*/
onLoad() {
const blocks = this.getAll();
!blocks.length && blocks.reset(c.blocks);
},
/**
* Add new block to the collection.
* @param {string} id Block id
* @param {Object} opts Options
* @param {string} opts.label Name of the block
* @param {string} opts.content HTML content
* @param {string|Object} opts.category Group the block inside a catgegory.
* You should pass objects with id property, eg:
* {id: 'some-uid', label: 'My category'}
* The string will be converted in:
* 'someid' => {id: 'someid', label: 'someid'}
* @param {Object} [opts.attributes={}] Block attributes
* @return {Block} Added block
* @example
* blockManager.add('h1-block', {
* label: 'Heading',
* content: '<h1>Put your title here</h1>',
* category: 'Basic',
* attributes: {
* title: 'Insert h1 block'
* }
* });
*/
add(id, opts) {
var obj = opts || {};
obj.id = id;
return blocks.add(obj);
},
/**
* Return the block by id
* @param {string} id Block id
* @example
* const block = blockManager.get('h1-block');
* console.log(JSON.stringify(block));
* // {label: 'Heading', content: '<h1>Put your ...', ...}
*/
get(id) {
return blocks.get(id);
},
/**
* Return all blocks
* @return {Collection}
* @example
* const blocks = blockManager.getAll();
* console.log(JSON.stringify(blocks));
* // [{label: 'Heading', content: '<h1>Put your ...'}, ...]
*/
getAll() {
return blocks;
},
/**
* Return the visible collection, which containes blocks actually rendered
* @return {Collection}
*/
getAllVisible() {
return blocksVisible;
},
/**
* Remove a block by id
* @param {string} id Block id
* @return {Block} Removed block
*/
remove(id) {
return blocks.remove(id);
},
/**
* Get all available categories.
* It's possible to add categories only within blocks via 'add()' method
* @return {Array|Collection}
*/
getCategories() {
return categories;
},
/**
* Return the Blocks container element
* @return {HTMLElement}
*/
getContainer() {
return blocksView.el;
},
/**
* Render blocks
* @param {Array} blocks Blocks to render, without the argument will render
* all global blocks
* @example
* // Render all blocks (inside the global collection)
* blockManager.render();
*
* // Render new set of blocks
* const blocks = blockManager.getAll();
* blockManager.render(blocks.filter(
* block => block.get('category') == 'sections'
* ));
* // Or a new set from an array
* blockManager.render([
* {label: 'Label text', content: '<div>Content</div>'}
* ]);
*
* // Back to blocks from the global collection
* blockManager.render();
*/
render(blocks) {
const toRender = blocks || this.getAll().models;
if (!blocksView.rendered) {
blocksView.render();
blocksView.rendered = 1;
} }
}
blocksView.collection.reset(toRender);
}, // Global blocks collection
blocks = new Blocks([]);
blocksVisible = new Blocks([]);
(categories = new BlockCategories()),
(blocksView = new BlocksView(
{
// Visible collection
collection: blocksVisible,
categories
},
c
));
// Setup the sync between the global and public collections
blocks.listenTo(blocks, 'add', model => {
blocksVisible.add(model);
em && em.trigger('block:add', model);
});
blocks.listenTo(blocks, 'remove', model => {
blocksVisible.remove(model);
em && em.trigger('block:remove', model);
});
blocks.listenTo(blocks, 'reset', coll => {
blocksVisible.reset(coll.models);
});
return this;
},
/**
* Get configuration object
* @return {Object}
*/
getConfig() {
return c;
},
/**
* Load default blocks if the collection is empty
*/
onLoad() {
const blocks = this.getAll();
!blocks.length && blocks.reset(c.blocks);
},
/**
* Add new block to the collection.
* @param {string} id Block id
* @param {Object} opts Options
* @param {string} opts.label Name of the block
* @param {string} opts.content HTML content
* @param {string|Object} opts.category Group the block inside a catgegory.
* You should pass objects with id property, eg:
* {id: 'some-uid', label: 'My category'}
* The string will be converted in:
* 'someid' => {id: 'someid', label: 'someid'}
* @param {Object} [opts.attributes={}] Block attributes
* @return {Block} Added block
* @example
* blockManager.add('h1-block', {
* label: 'Heading',
* content: '<h1>Put your title here</h1>',
* category: 'Basic',
* attributes: {
* title: 'Insert h1 block'
* }
* });
*/
add(id, opts) {
var obj = opts || {};
obj.id = id;
return blocks.add(obj);
},
/**
* Return the block by id
* @param {string} id Block id
* @example
* const block = blockManager.get('h1-block');
* console.log(JSON.stringify(block));
* // {label: 'Heading', content: '<h1>Put your ...', ...}
*/
get(id) {
return blocks.get(id);
},
/**
* Return all blocks
* @return {Collection}
* @example
* const blocks = blockManager.getAll();
* console.log(JSON.stringify(blocks));
* // [{label: 'Heading', content: '<h1>Put your ...'}, ...]
*/
getAll() {
return blocks;
},
/**
* Return the visible collection, which containes blocks actually rendered
* @return {Collection}
*/
getAllVisible() {
return blocksVisible;
},
/**
* Remove a block by id
* @param {string} id Block id
* @return {Block} Removed block
*/
remove(id) {
return blocks.remove(id);
},
/**
* Get all available categories.
* It's possible to add categories only within blocks via 'add()' method
* @return {Array|Collection}
*/
getCategories() {
return categories;
},
/**
* Return the Blocks container element
* @return {HTMLElement}
*/
getContainer() {
return blocksView.el;
},
/**
* Render blocks
* @param {Array} blocks Blocks to render, without the argument will render
* all global blocks
* @example
* // Render all blocks (inside the global collection)
* blockManager.render();
*
* // Render new set of blocks
* const blocks = blockManager.getAll();
* blockManager.render(blocks.filter(
* block => block.get('category') == 'sections'
* ));
* // Or a new set from an array
* blockManager.render([
* {label: 'Label text', content: '<div>Content</div>'}
* ]);
*
* // Back to blocks from the global collection
* blockManager.render();
*/
render(blocks) {
const toRender = blocks || this.getAll().models;
if (!blocksView.rendered) {
blocksView.render();
blocksView.rendered = 1;
}
blocksView.collection.reset(toRender);
}
}; };
}; };

8
src/block_manager/model/Block.js

@ -2,12 +2,11 @@ var Backbone = require('backbone');
var Category = require('./Category'); var Category = require('./Category');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: { defaults: {
label: '', label: '',
content: '', content: '',
category: '', category: '',
attributes: {}, attributes: {}
}, },
initialize(opts = {}) { initialize(opts = {}) {
@ -17,10 +16,9 @@ module.exports = Backbone.Model.extend({
if (typeof category == 'string') { if (typeof category == 'string') {
var catObj = new Category({ var catObj = new Category({
id: category, id: category,
label: category, label: category
}); });
} }
} }
}, }
}); });

2
src/block_manager/model/Blocks.js

@ -2,5 +2,5 @@ var Backbone = require('backbone');
var Block = require('./Block'); var Block = require('./Block');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
model: Block, model: Block
}); });

2
src/block_manager/model/Categories.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
model: require('./Category'), model: require('./Category')
}); });

6
src/block_manager/model/Category.js

@ -1,12 +1,10 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: { defaults: {
id: '', id: '',
label: '', label: '',
open: true, open: true,
attributes: {}, attributes: {}
}, }
}); });

12
src/block_manager/view/BlockView.js

@ -1,7 +1,6 @@
import {on, off} from 'utils/mixins'; import { on, off } from 'utils/mixins';
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
events: { events: {
mousedown: 'startDrag' mousedown: 'startDrag'
}, },
@ -23,7 +22,7 @@ module.exports = Backbone.View.extend({
return; return;
} }
if(!this.config.getSorter) { if (!this.config.getSorter) {
return; return;
} }
@ -56,8 +55,9 @@ module.exports = Backbone.View.extend({
const pfx = this.ppfx; const pfx = this.ppfx;
const className = `${pfx}block`; const className = `${pfx}block`;
el.className += ` ${className} ${pfx}one-bg ${pfx}four-color-h`; el.className += ` ${className} ${pfx}one-bg ${pfx}four-color-h`;
el.innerHTML = `<div class="${className}-label">${this.model.get('label')}</div>`; el.innerHTML = `<div class="${className}-label">${this.model.get(
'label'
)}</div>`;
return this; return this;
}, }
}); });

47
src/block_manager/view/BlocksView.js

@ -3,7 +3,6 @@ var BlockView = require('./BlockView');
var CategoryView = require('./CategoryView'); var CategoryView = require('./CategoryView');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
initialize(opts, config) { initialize(opts, config) {
_.bindAll(this, 'getSorter', 'onDrag', 'onDrop'); _.bindAll(this, 'getSorter', 'onDrag', 'onDrop');
this.config = config || {}; this.config = config || {};
@ -21,7 +20,7 @@ module.exports = Backbone.View.extend({
this.tac = 'test-tac'; this.tac = 'test-tac';
this.grabbingCls = this.ppfx + 'grabbing'; this.grabbingCls = this.ppfx + 'grabbing';
if(this.em){ if (this.em) {
this.config.getSorter = this.getSorter; this.config.getSorter = this.getSorter;
this.canvas = this.em.get('Canvas'); this.canvas = this.em.get('Canvas');
} }
@ -32,9 +31,8 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
getSorter() { getSorter() {
if(!this.em) if (!this.em) return;
return; if (!this.sorter) {
if(!this.sorter){
var utils = this.em.get('Utils'); var utils = this.em.get('Utils');
var canvas = this.canvas; var canvas = this.canvas;
this.sorter = new utils.Sorter({ this.sorter = new utils.Sorter({
@ -51,7 +49,7 @@ module.exports = Backbone.View.extend({
wmargin: 1, wmargin: 1,
nested: 1, nested: 1,
em: this.em, em: this.em,
canvasRelative: 1, canvasRelative: 1
}); });
} }
return this.sorter; return this.sorter;
@ -79,7 +77,7 @@ module.exports = Backbone.View.extend({
em.runDefault(); em.runDefault();
if (model && model.get) { if (model && model.get) {
if(model.get('activeOnRender')) { if (model.get('activeOnRender')) {
model.trigger('active'); model.trigger('active');
model.set('activeOnRender', 0); model.set('activeOnRender', 0);
} }
@ -105,10 +103,13 @@ module.exports = Backbone.View.extend({
* */ * */
add(model, fragment) { add(model, fragment) {
var frag = fragment || null; var frag = fragment || null;
var view = new BlockView({ var view = new BlockView(
model, {
attributes: model.get('attributes'), model,
}, this.config); attributes: model.get('attributes')
},
this.config
);
var rendered = view.render().el; var rendered = view.render().el;
var category = model.get('category'); var category = model.get('category');
@ -128,9 +129,12 @@ module.exports = Backbone.View.extend({
model.set('category', catModel); model.set('category', catModel);
if (!catView && categories) { if (!catView && categories) {
catView = new CategoryView({ catView = new CategoryView(
model: catModel {
}, this.config).render(); model: catModel
},
this.config
).render();
this.renderedCategories[catId] = catView; this.renderedCategories[catId] = catView;
categories.appendChild(catView.el); categories.appendChild(catView.el);
} }
@ -139,10 +143,8 @@ module.exports = Backbone.View.extend({
return; return;
} }
if(frag) if (frag) frag.appendChild(rendered);
frag.appendChild(rendered); else this.append(rendered);
else
this.append(rendered);
}, },
getCategoriesEl() { getCategoriesEl() {
@ -155,7 +157,9 @@ module.exports = Backbone.View.extend({
getBlocksEl() { getBlocksEl() {
if (!this.blocksEl) { if (!this.blocksEl) {
this.blocksEl = this.el.querySelector(`.${this.noCatClass} .${this.blockContClass}`); this.blocksEl = this.el.querySelector(
`.${this.noCatClass} .${this.blockContClass}`
);
} }
return this.blocksEl; return this.blocksEl;
@ -180,8 +184,7 @@ module.exports = Backbone.View.extend({
this.collection.each(model => this.add(model, frag)); this.collection.each(model => this.add(model, frag));
this.append(frag); this.append(frag);
this.$el.addClass(this.blockContClass + 's') this.$el.addClass(this.blockContClass + 's');
return this; return this;
}, }
}); });

13
src/block_manager/view/CategoryView.js

@ -1,7 +1,6 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
template: _.template(` template: _.template(`
<div class="<%= pfx %>title"> <div class="<%= pfx %>title">
<i class="<%= pfx %>caret-icon"></i> <i class="<%= pfx %>caret-icon"></i>
@ -21,16 +20,14 @@ module.exports = Backbone.View.extend({
this.iconClass = `${pfx}caret-icon`; this.iconClass = `${pfx}caret-icon`;
this.activeClass = `${pfx}open`; this.activeClass = `${pfx}open`;
this.className = `${pfx}block-category`; this.className = `${pfx}block-category`;
this.events[`click .${pfx}title`] = 'toggle'; this.events[`click .${pfx}title`] = 'toggle';
this.listenTo(this.model, 'change:open', this.updateVisibility); this.listenTo(this.model, 'change:open', this.updateVisibility);
this.delegateEvents(); this.delegateEvents();
}, },
updateVisibility() { updateVisibility() {
if(this.model.get('open')) if (this.model.get('open')) this.open();
this.open(); else this.close();
else
this.close();
}, },
open() { open() {
@ -73,10 +70,10 @@ module.exports = Backbone.View.extend({
render() { render() {
this.el.innerHTML = this.template({ this.el.innerHTML = this.template({
pfx: this.pfx, pfx: this.pfx,
label: this.model.get('label'), label: this.model.get('label')
}); });
this.el.className = this.className; this.el.className = this.className;
this.updateVisibility(); this.updateVisibility();
return this; return this;
}, }
}); });

4
src/canvas/config/config.js

@ -1,5 +1,4 @@
module.exports = { module.exports = {
stylePrefix: 'cv-', stylePrefix: 'cv-',
// Coming soon // Coming soon
@ -31,6 +30,5 @@ module.exports = {
* return ComponentModel.getName(); * return ComponentModel.getName();
* } * }
*/ */
customBadgeLabel: '', customBadgeLabel: ''
}; };

50
src/canvas/index.js

@ -1,15 +1,14 @@
import {on, off} from 'utils/mixins' import { on, off } from 'utils/mixins';
module.exports = () => { module.exports = () => {
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
Canvas = require('./model/Canvas'), Canvas = require('./model/Canvas'),
CanvasView = require('./view/CanvasView'); CanvasView = require('./view/CanvasView');
var canvas; var canvas;
var frameRect; var frameRect;
return { return {
/** /**
* Used inside RTE * Used inside RTE
* @private * @private
@ -32,23 +31,20 @@ module.exports = () => {
init(config) { init(config) {
c = config || {}; c = config || {};
for (var name in defaults) { for (var name in defaults) {
if (!(name in c)) if (!(name in c)) c[name] = defaults[name];
c[name] = defaults[name];
} }
var ppfx = c.pStylePrefix; var ppfx = c.pStylePrefix;
if(ppfx) if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
c.stylePrefix = ppfx + c.stylePrefix;
canvas = new Canvas(config); canvas = new Canvas(config);
CanvasView = new CanvasView({ CanvasView = new CanvasView({
model: canvas, model: canvas,
config: c, config: c
}); });
var cm = c.em.get('DomComponents'); var cm = c.em.get('DomComponents');
if(cm) if (cm) this.setWrapper(cm);
this.setWrapper(cm);
this.startAutoscroll = this.startAutoscroll.bind(this); this.startAutoscroll = this.startAutoscroll.bind(this);
this.stopAutoscroll = this.stopAutoscroll.bind(this); this.stopAutoscroll = this.stopAutoscroll.bind(this);
@ -200,11 +196,11 @@ module.exports = () => {
}, },
/** /**
* Get the offset of the element * Get the offset of the element
* @param {HTMLElement} el * @param {HTMLElement} el
* @return {Object} * @return {Object}
* @private * @private
*/ */
offset(el) { offset(el) {
return CanvasView.offset(el); return CanvasView.offset(el);
}, },
@ -257,11 +253,11 @@ module.exports = () => {
var elTop = pos.top - targetHeight; var elTop = pos.top - targetHeight;
var elLeft = pos.left; var elLeft = pos.left;
elLeft += toRight ? pos.width : 0; elLeft += toRight ? pos.width : 0;
elLeft = toRight ? (elLeft - targetWidth) : elLeft; elLeft = toRight ? elLeft - targetWidth : elLeft;
var leftPos = elLeft < canvasPos.left ? canvasPos.left : elLeft; var leftPos = elLeft < canvasPos.left ? canvasPos.left : elLeft;
var topPos = elTop < canvasPos.top ? canvasPos.top : elTop; var topPos = elTop < canvasPos.top ? canvasPos.top : elTop;
topPos = topPos > (pos.top + pos.height) ? (pos.top + pos.height) : topPos; topPos = topPos > pos.top + pos.height ? pos.top + pos.height : topPos;
var result = { var result = {
top: topPos, top: topPos,
@ -273,11 +269,11 @@ module.exports = () => {
targetWidth: target.offsetWidth, targetWidth: target.offsetWidth,
targetHeight: target.offsetHeight, targetHeight: target.offsetHeight,
canvasTop: canvasPos.top, canvasTop: canvasPos.top,
canvasLeft: canvasPos.left, canvasLeft: canvasPos.left
}; };
// In this way I can catch data and also change the position strategy // In this way I can catch data and also change the position strategy
if(eventToTrigger && c.em) { if (eventToTrigger && c.em) {
c.em.trigger(eventToTrigger, result); c.em.trigger(eventToTrigger, result);
} }
@ -311,7 +307,7 @@ module.exports = () => {
return { return {
y: e.clientY + addTop - yOffset, y: e.clientY + addTop - yOffset,
x: e.clientX + addLeft - xOffset, x: e.clientX + addLeft - xOffset
}; };
}, },
@ -331,7 +327,7 @@ module.exports = () => {
return { return {
y: e.clientY + addTop + yOffset, y: e.clientY + addTop + yOffset,
x: e.clientX + addLeft + xOffset, x: e.clientX + addLeft + xOffset
}; };
}, },
@ -371,11 +367,11 @@ module.exports = () => {
let limitBottom = frameRect.height - limitTop; let limitBottom = frameRect.height - limitTop;
if (clientY < limitTop) { if (clientY < limitTop) {
nextTop -= (limitTop - clientY); nextTop -= limitTop - clientY;
} }
if (clientY > limitBottom) { if (clientY > limitBottom) {
nextTop += (clientY - limitBottom); nextTop += clientY - limitBottom;
} }
//console.log(`actualTop: ${actualTop} clientY: ${clientY} nextTop: ${nextTop} frameHeigh: ${frameRect.height}`); //console.log(`actualTop: ${actualTop} clientY: ${clientY} nextTop: ${nextTop} frameHeigh: ${frameRect.height}`);
@ -404,6 +400,6 @@ module.exports = () => {
*/ */
getFrameWrapperEl() { getFrameWrapperEl() {
return CanvasView.frame.getWrapper(); return CanvasView.frame.getWrapper();
}, }
}; };
}; };

8
src/canvas/model/Canvas.js

@ -2,16 +2,14 @@ var Backbone = require('backbone');
var Frame = require('./Frame'); var Frame = require('./Frame');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: {
defaults :{
frame: '', frame: '',
wrapper: '', wrapper: '',
rulers: false, rulers: false
}, },
initialize(config) { initialize(config) {
var conf = this.conf || {}; var conf = this.conf || {};
this.set('frame', new Frame(conf.frame)); this.set('frame', new Frame(conf.frame));
}, }
}); });

8
src/canvas/model/Frame.js

@ -1,12 +1,10 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: {
defaults :{
wrapper: '', wrapper: '',
width: '', width: '',
height: '', height: '',
attributes: {}, attributes: {}
}, }
}); });

80
src/canvas/view/CanvasView.js

@ -2,14 +2,13 @@ const FrameView = require('./FrameView');
const $ = Backbone.$; const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
initialize(o) { initialize(o) {
_.bindAll(this, 'renderBody', 'onFrameScroll', 'clearOff'); _.bindAll(this, 'renderBody', 'onFrameScroll', 'clearOff');
window.onscroll = this.clearOff window.onscroll = this.clearOff;
this.config = o.config || {}; this.config = o.config || {};
this.em = this.config.em || {}; this.em = this.config.em || {};
this.ppfx = this.config.pStylePrefix || ''; this.ppfx = this.config.pStylePrefix || '';
this.className = this.config.stylePrefix + 'canvas'; this.className = this.config.stylePrefix + 'canvas';
this.listenTo(this.em, 'change:canvasOffset', this.clearOff); this.listenTo(this.em, 'change:canvasOffset', this.clearOff);
this.frame = new FrameView({ this.frame = new FrameView({
model: this.model.get('frame'), model: this.model.get('frame'),
@ -17,7 +16,6 @@ module.exports = Backbone.View.extend({
}); });
}, },
/** /**
* Checks if the element is visible in the canvas's viewport * Checks if the element is visible in the canvas's viewport
* @param {HTMLElement} el * @param {HTMLElement} el
@ -28,8 +26,12 @@ module.exports = Backbone.View.extend({
const frameRect = this.getFrameOffset(1); const frameRect = this.getFrameOffset(1);
const rTop = rect.top; const rTop = rect.top;
const rLeft = rect.left; const rLeft = rect.left;
return rTop >= 0 && rLeft >= 0 && return (
rTop <= frameRect.height && rLeft <= frameRect.width; rTop >= 0 &&
rLeft >= 0 &&
rTop <= frameRect.height &&
rLeft <= frameRect.width
);
}, },
/** /**
@ -49,26 +51,26 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
renderScripts() { renderScripts() {
var frame = this.frame; var frame = this.frame;
var that = this; var that = this;
frame.el.onload = () => { frame.el.onload = () => {
var scripts = that.config.scripts.slice(0), // clone var scripts = that.config.scripts.slice(0), // clone
counter = 0; counter = 0;
function appendScript(scripts) { function appendScript(scripts) {
if (scripts.length > 0) { if (scripts.length > 0) {
var script = document.createElement('script'); var script = document.createElement('script');
script.type = 'text/javascript'; script.type = 'text/javascript';
script.src = scripts.shift(); script.src = scripts.shift();
script.onerror = script.onload = appendScript.bind(null, scripts); script.onerror = script.onload = appendScript.bind(null, scripts);
frame.el.contentDocument.head.appendChild(script); frame.el.contentDocument.head.appendChild(script);
} else { } else {
that.renderBody(); that.renderBody();
}
} }
appendScript(scripts); }
}; appendScript(scripts);
};
}, },
/** /**
@ -78,7 +80,7 @@ module.exports = Backbone.View.extend({
renderBody() { renderBody() {
var wrap = this.model.get('frame').get('wrapper'); var wrap = this.model.get('frame').get('wrapper');
var em = this.config.em; var em = this.config.em;
if(wrap) { if (wrap) {
var ppfx = this.ppfx; var ppfx = this.ppfx;
//var body = this.frame.$el.contents().find('body'); //var body = this.frame.$el.contents().find('body');
var body = $(this.frame.el.contentWindow.document.body); var body = $(this.frame.el.contentWindow.document.body);
@ -88,7 +90,7 @@ module.exports = Backbone.View.extend({
var protCss = conf.protectedCss; var protCss = conf.protectedCss;
var externalStyles = ''; var externalStyles = '';
confCanvas.styles.forEach((style) => { confCanvas.styles.forEach(style => {
externalStyles += `<link rel="stylesheet" href="${style}"/>`; externalStyles += `<link rel="stylesheet" href="${style}"/>`;
}); });
@ -203,7 +205,7 @@ module.exports = Backbone.View.extend({
// the keyCode/which will be always `0`. Even if it's an old/deprecated // the keyCode/which will be always `0`. Even if it's an old/deprecated
// property keymaster (and many others) still use it... using `defineProperty` // property keymaster (and many others) still use it... using `defineProperty`
// hack seems the only way // hack seems the only way
const createCustomEvent = (e) => { const createCustomEvent = e => {
var oEvent = new KeyboardEvent(e.type, e); var oEvent = new KeyboardEvent(e.type, e);
oEvent.keyCodeVal = e.keyCode; oEvent.keyCodeVal = e.keyCode;
['keyCode', 'which'].forEach(prop => { ['keyCode', 'which'].forEach(prop => {
@ -214,7 +216,7 @@ module.exports = Backbone.View.extend({
}); });
}); });
return oEvent; return oEvent;
} };
fdoc.addEventListener('keydown', e => { fdoc.addEventListener('keydown', e => {
doc.dispatchEvent(createCustomEvent(e)); doc.dispatchEvent(createCustomEvent(e));
}); });
@ -236,7 +238,7 @@ module.exports = Backbone.View.extend({
top: rect.top + docBody.scrollTop, top: rect.top + docBody.scrollTop,
left: rect.left + docBody.scrollLeft, left: rect.left + docBody.scrollLeft,
width: rect.width, width: rect.width,
height: rect.height, height: rect.height
}; };
}, },
@ -255,8 +257,7 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
getFrameOffset(force = 0) { getFrameOffset(force = 0) {
if(!this.frmOff || force) if (!this.frmOff || force) this.frmOff = this.offset(this.frame.el);
this.frmOff = this.offset(this.frame.el);
return this.frmOff; return this.frmOff;
}, },
@ -266,8 +267,7 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
getCanvasOffset() { getCanvasOffset() {
if(!this.cvsOff) if (!this.cvsOff) this.cvsOff = this.offset(this.el);
this.cvsOff = this.offset(this.el);
return this.cvsOff; return this.cvsOff;
}, },
@ -316,7 +316,7 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
updateScript(view) { updateScript(view) {
if(!view.scriptContainer) { if (!view.scriptContainer) {
view.scriptContainer = $('<div>'); view.scriptContainer = $('<div>');
this.getJsContainer().append(view.scriptContainer.get(0)); this.getJsContainer().append(view.scriptContainer.get(0));
} }
@ -350,11 +350,10 @@ module.exports = Backbone.View.extend({
return this.jsContainer; return this.jsContainer;
}, },
render() { render() {
this.wrapper = this.model.get('wrapper'); this.wrapper = this.model.get('wrapper');
if(this.wrapper && typeof this.wrapper.render == 'function'){ if (this.wrapper && typeof this.wrapper.render == 'function') {
this.model.get('frame').set('wrapper', this.wrapper); this.model.get('frame').set('wrapper', this.wrapper);
this.$el.append(this.frame.render().el); this.$el.append(this.frame.render().el);
var frame = this.frame; var frame = this.frame;
@ -392,6 +391,5 @@ module.exports = Backbone.View.extend({
this.toolsEl = toolsEl; this.toolsEl = toolsEl;
this.el.className = this.className; this.el.className = this.className;
return this; return this;
}, }
}); });

11
src/canvas/view/FrameView.js

@ -1,9 +1,9 @@
import { bindAll } from 'underscore' import { bindAll } from 'underscore';
const motionsEv = 'transitionend oTransitionEnd transitionend webkitTransitionEnd'; const motionsEv =
'transitionend oTransitionEnd transitionend webkitTransitionEnd';
module.exports = require('backbone').View.extend({ module.exports = require('backbone').View.extend({
tagName: 'iframe', tagName: 'iframe',
attributes: { attributes: {
@ -58,8 +58,7 @@ module.exports = require('backbone').View.extend({
}, },
render() { render() {
this.$el.attr({class: this.ppfx + 'frame'}); this.$el.attr({ class: this.ppfx + 'frame' });
return this; return this;
}, }
}); });

2
src/code_manager/config/config.js

@ -2,5 +2,5 @@ module.exports = {
// Style prefix // Style prefix
stylePrefix: 'cm-', stylePrefix: 'cm-',
inlineCss: false, inlineCss: false
}; };

42
src/code_manager/index.js

@ -18,23 +18,21 @@
* @module CodeManager * @module CodeManager
*/ */
module.exports = () => { module.exports = () => {
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
gHtml = require('./model/HtmlGenerator'), gHtml = require('./model/HtmlGenerator'),
gCss = require('./model/CssGenerator'), gCss = require('./model/CssGenerator'),
gJson = require('./model/JsonGenerator'), gJson = require('./model/JsonGenerator'),
gJs = require('./model/JsGenerator'), gJs = require('./model/JsGenerator'),
eCM = require('./model/CodeMirrorEditor'), eCM = require('./model/CodeMirrorEditor'),
editorView = require('./view/EditorView'); editorView = require('./view/EditorView');
var generators = {}, var generators = {},
defGenerators = {}, defGenerators = {},
viewers = {}, viewers = {},
defViewers = {}; defViewers = {};
return { return {
getConfig() { getConfig() {
return c; return c;
}, },
@ -57,16 +55,14 @@ module.exports = () => {
init(config) { init(config) {
c = config || {}; c = config || {};
for (var name in defaults) { for (var name in defaults) {
if (!(name in c)) if (!(name in c)) c[name] = defaults[name];
c[name] = defaults[name];
} }
var ppfx = c.pStylePrefix; var ppfx = c.pStylePrefix;
if(ppfx) if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
c.stylePrefix = ppfx + c.stylePrefix;
defGenerators.html = new gHtml(); defGenerators.html = new gHtml();
defGenerators.css = new gCss(); defGenerators.css = new gCss();
defGenerators.json = new gJson(); defGenerators.json = new gJson();
defGenerators.js = new gJs(); defGenerators.js = new gJs();
defViewers.CodeMirror = new eCM(); defViewers.CodeMirror = new eCM();
@ -183,7 +179,7 @@ module.exports = () => {
* */ * */
getCode(model, genId, opt = {}) { getCode(model, genId, opt = {}) {
opt.em = c.em; opt.em = c.em;
var generator = this.getGenerator(genId); var generator = this.getGenerator(genId);
return generator ? generator.build(model, opt) : ''; return generator ? generator.build(model, opt) : '';
}, },
@ -193,8 +189,7 @@ module.exports = () => {
* @private * @private
* */ * */
loadDefaultGenerators() { loadDefaultGenerators() {
for (var id in defGenerators) for (var id in defGenerators) this.addGenerator(id, defGenerators[id]);
this.addGenerator(id, defGenerators[id]);
return this; return this;
}, },
@ -205,12 +200,9 @@ module.exports = () => {
* @private * @private
* */ * */
loadDefaultViewers() { loadDefaultViewers() {
for (var id in defViewers) for (var id in defViewers) this.addViewer(id, defViewers[id]);
this.addViewer(id, defViewers[id]);
return this; return this;
}, }
}; };
}; };

30
src/code_manager/model/CodeMirrorEditor.js

@ -5,23 +5,22 @@ var cssMode = require('codemirror/mode/css/css');
var formatting = require('codemirror-formatting'); var formatting = require('codemirror-formatting');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: { defaults: {
input : '', input: '',
label : '', label: '',
codeName : '', codeName: '',
theme : '', theme: '',
readOnly : true, readOnly: true,
lineNumbers : true, lineNumbers: true
}, },
/** @inheritdoc */ /** @inheritdoc */
init(el) { init(el) {
this.editor = CodeMirror.fromTextArea(el, { this.editor = CodeMirror.fromTextArea(el, {
dragDrop: false, dragDrop: false,
lineWrapping: true, lineWrapping: true,
mode: this.get('codeName'), mode: this.get('codeName'),
...this.attributes, ...this.attributes
}); });
return this; return this;
@ -29,14 +28,15 @@ module.exports = Backbone.Model.extend({
/** @inheritdoc */ /** @inheritdoc */
setContent(v) { setContent(v) {
if(!this.editor) if (!this.editor) return;
return;
this.editor.setValue(v); this.editor.setValue(v);
if(this.editor.autoFormatRange){ if (this.editor.autoFormatRange) {
CodeMirror.commands.selectAll(this.editor); CodeMirror.commands.selectAll(this.editor);
this.editor.autoFormatRange(this.editor.getCursor(true), this.editor.getCursor(false) ); this.editor.autoFormatRange(
this.editor.getCursor(true),
this.editor.getCursor(false)
);
CodeMirror.commands.goDocStart(this.editor); CodeMirror.commands.goDocStart(this.editor);
} }
}, }
}); });

12
src/code_manager/model/CssGenerator.js

@ -1,5 +1,4 @@
module.exports = require('backbone').Model.extend({ module.exports = require('backbone').Model.extend({
initialize() { initialize() {
this.compCls = []; this.compCls = [];
this.ids = []; this.ids = [];
@ -30,11 +29,10 @@ module.exports = require('backbone').Model.extend({
} }
const components = model.components(); const components = model.components();
components.each(model => code += this.buildFromModel(model, opts)); components.each(model => (code += this.buildFromModel(model, opts)));
return code; return code;
}, },
build(model, opts = {}) { build(model, opts = {}) {
const cssc = opts.cssc; const cssc = opts.cssc;
this.em = opts.em || ''; this.em = opts.em || '';
@ -67,13 +65,12 @@ module.exports = require('backbone').Model.extend({
for (let media in mediaRules) { for (let media in mediaRules) {
let rulesStr = ''; let rulesStr = '';
const mRules = mediaRules[media]; const mRules = mediaRules[media];
mRules.forEach(rule => rulesStr += this.buildFromRule(rule)); mRules.forEach(rule => (rulesStr += this.buildFromRule(rule)));
if (rulesStr) { if (rulesStr) {
code += `@media ${media}{${rulesStr}}`; code += `@media ${media}{${rulesStr}}`;
} }
} }
} }
return code; return code;
@ -87,7 +84,7 @@ module.exports = require('backbone').Model.extend({
buildFromRule(rule) { buildFromRule(rule) {
let result = ''; let result = '';
const selectorStr = rule.selectorsToString(); const selectorStr = rule.selectorsToString();
const selectorStrNoAdd = rule.selectorsToString({skipAdd: 1}); const selectorStrNoAdd = rule.selectorsToString({ skipAdd: 1 });
let found; let found;
// This will not render a rule if there is no its component // This will not render a rule if there is no its component
@ -107,6 +104,5 @@ module.exports = require('backbone').Model.extend({
} }
return result; return result;
}, }
}); });

7
src/code_manager/model/HtmlGenerator.js

@ -1,13 +1,13 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
build(model, opts = {}) { build(model, opts = {}) {
const models = model.get('components'); const models = model.get('components');
if (opts.exportWrapper) { if (opts.exportWrapper) {
return opts.wrappesIsBody ? return opts.wrappesIsBody
`<body>${this.buildModels(models)}</body>` : model.toHTML(); ? `<body>${this.buildModels(models)}</body>`
: model.toHTML();
} }
return this.buildModels(models); return this.buildModels(models);
@ -20,5 +20,4 @@ module.exports = Backbone.Model.extend({
}); });
return code; return code;
} }
}); });

21
src/code_manager/model/JsGenerator.js

@ -1,31 +1,30 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
mapModel(model) { mapModel(model) {
var code = ''; var code = '';
var script = model.get('script'); var script = model.get('script');
var type = model.get('type'); var type = model.get('type');
var comps = model.get('components'); var comps = model.get('components');
var id = model.getId(); var id = model.getId();
if (script) { if (script) {
// If the component has scripts we need to expose his ID // If the component has scripts we need to expose his ID
var attr = model.get('attributes'); var attr = model.get('attributes');
attr = _.extend({}, attr, {id}); attr = _.extend({}, attr, { id });
model.set('attributes', attr); model.set('attributes', attr);
var scrStr = model.getScriptString(); var scrStr = model.getScriptString();
// If the script was updated, I'll put its code in a separate container // If the script was updated, I'll put its code in a separate container
if (model.get('scriptUpdated')) { if (model.get('scriptUpdated')) {
this.mapJs[type+'-'+id] = {ids: [id], code: scrStr}; this.mapJs[type + '-' + id] = { ids: [id], code: scrStr };
} else { } else {
var mapType = this.mapJs[type]; var mapType = this.mapJs[type];
if(mapType) { if (mapType) {
mapType.ids.push(id); mapType.ids.push(id);
} else { } else {
this.mapJs[type] = {ids: [id], code: scrStr}; this.mapJs[type] = { ids: [id], code: scrStr };
} }
} }
} }
@ -43,7 +42,7 @@ module.exports = Backbone.Model.extend({
var code = ''; var code = '';
for(var type in this.mapJs) { for (var type in this.mapJs) {
var mapType = this.mapJs[type]; var mapType = this.mapJs[type];
var ids = '#' + mapType.ids.join(', #'); var ids = '#' + mapType.ids.join(', #');
code += ` code += `
@ -53,8 +52,6 @@ module.exports = Backbone.Model.extend({
}`; }`;
} }
return code; return code;
}, }
}); });

34
src/code_manager/model/JsonGenerator.js

@ -1,26 +1,29 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
/** @inheritdoc */ /** @inheritdoc */
build(model) { build(model) {
var json = model.toJSON(); var json = model.toJSON();
this.beforeEach(json); this.beforeEach(json);
_.each(json,function(v, attr){ _.each(
var obj = json[attr]; json,
if(obj instanceof Backbone.Model){ function(v, attr) {
json[attr] = this.build(obj); var obj = json[attr];
}else if(obj instanceof Backbone.Collection){ if (obj instanceof Backbone.Model) {
var coll = obj; json[attr] = this.build(obj);
json[attr] = []; } else if (obj instanceof Backbone.Collection) {
if(coll.length){ var coll = obj;
coll.each(function (el, index) { json[attr] = [];
json[attr][index] = this.build(el); if (coll.length) {
}, this); coll.each(function(el, index) {
json[attr][index] = this.build(el);
}, this);
}
} }
} },
}, this); this
);
return json; return json;
}, },
@ -32,5 +35,4 @@ module.exports = Backbone.Model.extend({
beforeEach(obj) { beforeEach(obj) {
delete obj.status; delete obj.status;
} }
}); });

8
src/code_manager/view/EditorView.js

@ -1,7 +1,6 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
template: _.template(` template: _.template(`
<div class="<%= pfx %>editor" id="<%= pfx %><%= codeName %>"> <div class="<%= pfx %>editor" id="<%= pfx %><%= codeName %>">
<div id="<%= pfx %>title"><%= label %></div> <div id="<%= pfx %>title"><%= label %></div>
@ -16,10 +15,9 @@ module.exports = Backbone.View.extend({
render() { render() {
var obj = this.model.toJSON(); var obj = this.model.toJSON();
obj.pfx = this.pfx; obj.pfx = this.pfx;
this.$el.html( this.template(obj) ); this.$el.html(this.template(obj));
this.$el.attr('class', this.pfx + 'editor-c'); this.$el.attr('class', this.pfx + 'editor-c');
this.$el.find('#'+this.pfx+'code').append(this.model.get('input')); this.$el.find('#' + this.pfx + 'code').append(this.model.get('input'));
return this; return this;
}, }
}); });

3
src/commands/config/config.js

@ -1,5 +1,4 @@
module.exports = { module.exports = {
ESCAPE_KEY: 27, ESCAPE_KEY: 27,
stylePrefix: 'com-', stylePrefix: 'com-',
@ -19,5 +18,5 @@ module.exports = {
minComponentH: 50, minComponentH: 50,
// Minimum width (in px) of component on creation // Minimum width (in px) of component on creation
minComponentW: 50, minComponentW: 50
}; };

51
src/commands/index.js

@ -43,10 +43,10 @@ import { isFunction } from 'underscore';
module.exports = () => { module.exports = () => {
let em; let em;
var c = {}, var c = {},
commands = {}, commands = {},
defaultCommands = {}, defaultCommands = {},
defaults = require('./config/config'), defaults = require('./config/config'),
AbsCommands = require('./view/CommandAbstract'); AbsCommands = require('./view/CommandAbstract');
// Need it here as it would be used below // Need it here as it would be used below
var add = function(id, obj) { var add = function(id, obj) {
@ -60,7 +60,6 @@ module.exports = () => {
}; };
return { return {
/** /**
* Name of the module * Name of the module
* @type {String} * @type {String}
@ -76,19 +75,16 @@ module.exports = () => {
init(config) { init(config) {
c = config || {}; c = config || {};
for (var name in defaults) { for (var name in defaults) {
if (!(name in c)) if (!(name in c)) c[name] = defaults[name];
c[name] = defaults[name];
} }
em = c.em; em = c.em;
var ppfx = c.pStylePrefix; var ppfx = c.pStylePrefix;
if(ppfx) if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
c.stylePrefix = ppfx + c.stylePrefix;
// Load commands passed via configuration // Load commands passed via configuration
for( var k in c.defaults) { for (var k in c.defaults) {
var obj = c.defaults[k]; var obj = c.defaults[k];
if(obj.id) if (obj.id) this.add(obj.id, obj);
this.add(obj.id, obj);
} }
const ViewCode = require('./view/ExportTemplate'); const ViewCode = require('./view/ExportTemplate');
@ -117,31 +113,31 @@ module.exports = () => {
run(ed) { run(ed) {
var sel = ed.getSelected(); var sel = ed.getSelected();
if(!sel || !sel.get('removable')) { if (!sel || !sel.get('removable')) {
console.warn('The element is not removable'); console.warn('The element is not removable');
return; return;
} }
ed.select(null); ed.select(null);
sel.destroy(); sel.destroy();
}, }
}; };
defaultCommands['tlb-clone'] = { defaultCommands['tlb-clone'] = {
run(ed) { run(ed) {
var sel = ed.getSelected(); var sel = ed.getSelected();
if(!sel || !sel.get('copyable')) { if (!sel || !sel.get('copyable')) {
console.warn('The element is not clonable'); console.warn('The element is not clonable');
return; return;
} }
var collection = sel.collection; var collection = sel.collection;
var index = collection.indexOf(sel); var index = collection.indexOf(sel);
const added = collection.add(sel.clone(), {at: index + 1}); const added = collection.add(sel.clone(), { at: index + 1 });
sel.emitUpdate(); sel.emitUpdate();
ed.trigger('component:clone', added); ed.trigger('component:clone', added);
}, }
}; };
defaultCommands['tlb-move'] = { defaultCommands['tlb-move'] = {
@ -149,7 +145,7 @@ module.exports = () => {
var sel = ed.getSelected(); var sel = ed.getSelected();
var dragger; var dragger;
if(!sel || !sel.get('draggable')) { if (!sel || !sel.get('draggable')) {
console.warn('The element is not draggable'); console.warn('The element is not draggable');
return; return;
} }
@ -165,7 +161,7 @@ module.exports = () => {
const onEnd = (e, opts) => { const onEnd = (e, opts) => {
em.runDefault(); em.runDefault();
em.set('selectedComponent', sel); em.set('selectedComponent', sel);
sel.emitUpdate() sel.emitUpdate();
dragger && dragger.blur(); dragger && dragger.blur();
}; };
@ -196,9 +192,8 @@ module.exports = () => {
cmdMove.initSorterFromModel(sel); cmdMove.initSorterFromModel(sel);
} }
sel.set('status', 'selected'); sel.set('status', 'selected');
}, }
}; };
// Core commands // Core commands
@ -228,10 +223,9 @@ module.exports = () => {
} }
}; };
if(c.em) if (c.em) c.model = c.em.get('Canvas');
c.model = c.em.get('Canvas');
this.loadDefaultCommands() this.loadDefaultCommands();
return this; return this;
}, },
@ -267,9 +261,9 @@ module.exports = () => {
get(id) { get(id) {
var el = commands[id]; var el = commands[id];
if(typeof el == 'function'){ if (typeof el == 'function') {
el = new el(c); el = new el(c);
commands[id] = el; commands[id] = el;
} }
return el; return el;
@ -291,11 +285,10 @@ module.exports = () => {
* */ * */
loadDefaultCommands() { loadDefaultCommands() {
for (var id in defaultCommands) { for (var id in defaultCommands) {
this.add(id, defaultCommands[id]); this.add(id, defaultCommands[id]);
} }
return this; return this;
}, }
}; };
}; };

6
src/commands/model/Command.js

@ -1,9 +1,7 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: {
defaults :{ id: ''
id: '',
} }
}); });

4
src/commands/model/Commands.js

@ -2,7 +2,5 @@ var Backbone = require('backbone');
var Command = require('./Command'); var Command = require('./Command');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
model: Command
model: Command,
}); });

27
src/commands/view/CommandAbstract.js

@ -1,28 +1,26 @@
const $ = Backbone.$ const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
/** /**
* Initialize method that can't be removed * Initialize method that can't be removed
* @param {Object} o Options * @param {Object} o Options
* @private * @private
* */ * */
initialize(o) { initialize(o) {
this.config = o || {}; this.config = o || {};
this.editorModel = this.em = this.config.em || {}; this.editorModel = this.em = this.config.em || {};
this.pfx = this.config.stylePrefix; this.pfx = this.config.stylePrefix;
this.ppfx = this.config.pStylePrefix; this.ppfx = this.config.pStylePrefix;
this.hoverClass = this.pfx + 'hover'; this.hoverClass = this.pfx + 'hover';
this.badgeClass = this.pfx + 'badge'; this.badgeClass = this.pfx + 'badge';
this.plhClass = this.pfx + 'placeholder'; this.plhClass = this.pfx + 'placeholder';
this.freezClass = this.ppfx + 'freezed'; this.freezClass = this.ppfx + 'freezed';
this.canvas = this.em.get && this.em.get('Canvas'); this.canvas = this.em.get && this.em.get('Canvas');
if(this.em.get) if (this.em.get) this.setElement(this.getCanvas());
this.setElement(this.getCanvas());
if(this.canvas){ if (this.canvas) {
this.$canvas = this.$el; this.$canvas = this.$el;
this.$wrapper = $(this.getCanvasWrapper()); this.$wrapper = $(this.getCanvasWrapper());
this.frameEl = this.canvas.getFrameEl(); this.frameEl = this.canvas.getFrameEl();
@ -106,6 +104,5 @@ module.exports = Backbone.View.extend({
* @param {Object} sender Button sender * @param {Object} sender Button sender
* @private * @private
* */ * */
stop(em, sender) {}, stop(em, sender) {}
}); });

68
src/commands/view/CreateComponent.js

@ -2,9 +2,8 @@ const SelectPosition = require('./SelectPosition');
const $ = Backbone.$; const $ = Backbone.$;
module.exports = _.extend({}, SelectPosition, { module.exports = _.extend({}, SelectPosition, {
init(opt) { init(opt) {
_.bindAll(this,'startDraw','draw','endDraw','rollback'); _.bindAll(this, 'startDraw', 'draw', 'endDraw', 'rollback');
this.config = opt || {}; this.config = opt || {};
this.hType = this.config.newFixedH ? 'height' : 'min-height'; this.hType = this.config.newFixedH ? 'height' : 'min-height';
this.allowDraw = 1; this.allowDraw = 1;
@ -16,9 +15,8 @@ module.exports = _.extend({}, SelectPosition, {
* */ * */
enable(...args) { enable(...args) {
SelectPosition.enable.apply(this, args); SelectPosition.enable.apply(this, args);
this.$wr.css('cursor','crosshair'); this.$wr.css('cursor', 'crosshair');
if(this.allowDraw) if (this.allowDraw) this.$wr.on('mousedown', this.startDraw);
this.$wr.on('mousedown', this.startDraw);
this.ghost = this.canvas.getGhostEl(); this.ghost = this.canvas.getGhostEl();
}, },
@ -33,11 +31,11 @@ module.exports = _.extend({}, SelectPosition, {
this.ghost.style.display = 'block'; this.ghost.style.display = 'block';
this.frameOff = this.getOffsetDim(); this.frameOff = this.getOffsetDim();
this.startPos = { this.startPos = {
top : e.pageY + this.frameOff.top, top: e.pageY + this.frameOff.top,
left: e.pageX + this.frameOff.left left: e.pageX + this.frameOff.left
}; };
this.isDragged = false; this.isDragged = false;
this.tempComponent = {style: {}}; this.tempComponent = { style: {} };
this.beforeDraw(this.tempComponent); this.beforeDraw(this.tempComponent);
this.updateSize(this.startPos.top, this.startPos.left, 0, 0); this.updateSize(this.startPos.top, this.startPos.left, 0, 0);
this.toggleEvents(1); this.toggleEvents(1);
@ -75,11 +73,16 @@ module.exports = _.extend({}, SelectPosition, {
this.toggleEvents(); this.toggleEvents();
var model = {}; var model = {};
// Only if the mouse was moved // Only if the mouse was moved
if(this.isDragged){ if (this.isDragged) {
this.updateComponentSize(e); this.updateComponentSize(e);
this.setRequirements(this.tempComponent); this.setRequirements(this.tempComponent);
var lp = this.sorter.lastPos; var lp = this.sorter.lastPos;
model = this.create(this.sorter.target, this.tempComponent, lp.index, lp.method); model = this.create(
this.sorter.target,
this.tempComponent,
lp.index,
lp.method
);
this.sorter.prevTarget = null; this.sorter.prevTarget = null;
} }
this.ghost.style.display = 'none'; this.ghost.style.display = 'none';
@ -103,10 +106,8 @@ module.exports = _.extend({}, SelectPosition, {
var trgCollection = $trg.data('collection'); var trgCollection = $trg.data('collection');
var droppable = trgModel ? trgModel.get('droppable') : 1; var droppable = trgModel ? trgModel.get('droppable') : 1;
opt.at = index; opt.at = index;
if(trgCollection && droppable) if (trgCollection && droppable) return trgCollection.add(component, opt);
return trgCollection.add(component, opt); else console.warn('Invalid target position');
else
console.warn("Invalid target position");
}, },
/** /**
@ -116,29 +117,29 @@ module.exports = _.extend({}, SelectPosition, {
* @private * @private
* */ * */
setRequirements(component) { setRequirements(component) {
var c = this.config; var c = this.config;
var compStl = component.style; var compStl = component.style;
// Check min width // Check min width
if(compStl.width.replace(/\D/g,'') < c.minComponentW) if (compStl.width.replace(/\D/g, '') < c.minComponentW)
compStl.width = c.minComponentW +'px'; compStl.width = c.minComponentW + 'px';
// Check min height // Check min height
if(compStl[this.hType].replace(/\D/g,'') < c.minComponentH) if (compStl[this.hType].replace(/\D/g, '') < c.minComponentH)
compStl[this.hType] = c.minComponentH +'px'; compStl[this.hType] = c.minComponentH + 'px';
// Set overflow in case of fixed height // Set overflow in case of fixed height
if(c.newFixedH) if (c.newFixedH) compStl.overflow = 'auto';
compStl.overflow = 'auto'; if (!this.absoluteMode) {
if(!this.absoluteMode){
delete compStl.left; delete compStl.left;
delete compStl.top; delete compStl.top;
}else } else compStl.position = 'absolute';
compStl.position = 'absolute';
var lp = this.sorter.lastPos; var lp = this.sorter.lastPos;
if(this.nearFloat(lp.index, lp.method, this.sorter.lastDims)) if (this.nearFloat(lp.index, lp.method, this.sorter.lastDims))
compStl.float = 'left'; compStl.float = 'left';
if(this.config.firstCentered && if (
this.getCanvasWrapper() == this.sorter.target){ this.config.firstCentered &&
this.getCanvasWrapper() == this.sorter.target
) {
compStl.margin = '0 auto'; compStl.margin = '0 auto';
} }
@ -152,12 +153,12 @@ module.exports = _.extend({}, SelectPosition, {
* */ * */
updateComponentSize(e) { updateComponentSize(e) {
var y = e.pageY + this.frameOff.top; var y = e.pageY + this.frameOff.top;
var x = e.pageX + this.frameOff.left; var x = e.pageX + this.frameOff.left;
var start = this.startPos; var start = this.startPos;
var top = start.top; var top = start.top;
var left = start.left; var left = start.left;
var height = y - top; var height = y - top;
var width = x - left; var width = x - left;
if (x < left) { if (x < left) {
left = x; left = x;
width = start.left - x; width = start.left - x;
@ -180,7 +181,7 @@ module.exports = _.extend({}, SelectPosition, {
ghStl.top = compStl.top = top + u; ghStl.top = compStl.top = top + u;
ghStl.left = compStl.left = left + u; ghStl.left = compStl.left = left + u;
ghStl.width = compStl.width = width + u; ghStl.width = compStl.width = width + u;
ghStl[this.hType] = compStl[this.hType] = height + u; ghStl[this.hType] = compStl[this.hType] = height + u;
}, },
/** /**
@ -191,7 +192,7 @@ module.exports = _.extend({}, SelectPosition, {
* */ * */
rollback(e, force) { rollback(e, force) {
var key = e.which || e.keyCode; var key = e.which || e.keyCode;
if(key == this.config.ESCAPE_KEY || force){ if (key == this.config.ESCAPE_KEY || force) {
this.isDragged = false; this.isDragged = false;
this.endDraw(); this.endDraw();
} }
@ -204,7 +205,7 @@ module.exports = _.extend({}, SelectPosition, {
* @private * @private
* */ * */
beforeDraw(component) { beforeDraw(component) {
component.editable = false;//set this component editable component.editable = false; //set this component editable
}, },
/** /**
@ -214,17 +215,16 @@ module.exports = _.extend({}, SelectPosition, {
* */ * */
afterDraw(model) {}, afterDraw(model) {},
run(editor, sender, opts) { run(editor, sender, opts) {
this.editor = editor; this.editor = editor;
this.sender = sender; this.sender = sender;
this.$wr = this.$wrapper; this.$wr = this.$wrapper;
this.enable(); this.enable();
}, },
stop() { stop() {
this.stopSelectPosition(); this.stopSelectPosition();
this.$wrapper.css('cursor',''); this.$wrapper.css('cursor', '');
this.$wrapper.unbind(); this.$wrapper.unbind();
} }
}); });

44
src/commands/view/DeleteComponent.js

@ -1,17 +1,17 @@
const SelectComponent = require('./SelectComponent'); const SelectComponent = require('./SelectComponent');
const $ = Backbone.$; const $ = Backbone.$;
module.exports = _.extend({},SelectComponent,{ module.exports = _.extend({}, SelectComponent, {
init(o) { init(o) {
_.bindAll(this, 'startDelete', 'stopDelete', 'onDelete'); _.bindAll(this, 'startDelete', 'stopDelete', 'onDelete');
this.hoverClass = this.pfx + 'hover-delete'; this.hoverClass = this.pfx + 'hover-delete';
this.badgeClass = this.pfx + 'badge-red'; this.badgeClass = this.pfx + 'badge-red';
}, },
enable() { enable() {
var that = this; var that = this;
this.$el.find('*') this.$el
.find('*')
.mouseover(this.startDelete) .mouseover(this.startDelete)
.mouseout(this.stopDelete) .mouseout(this.stopDelete)
.click(this.onDelete); .click(this.onDelete);
@ -23,15 +23,14 @@ module.exports = _.extend({},SelectComponent,{
* @private * @private
*/ */
startDelete(e) { startDelete(e) {
e.stopPropagation(); e.stopPropagation();
var $this = $(e.target); var $this = $(e.target);
// Show badge if possible
if($this.data('model').get('removable')){
$this.addClass(this.hoverClass);
this.attachBadge($this.get(0));
}
// Show badge if possible
if ($this.data('model').get('removable')) {
$this.addClass(this.hoverClass);
this.attachBadge($this.get(0));
}
}, },
/** /**
@ -40,13 +39,12 @@ module.exports = _.extend({},SelectComponent,{
* @private * @private
*/ */
stopDelete(e) { stopDelete(e) {
e.stopPropagation(); e.stopPropagation();
var $this = $(e.target); var $this = $(e.target);
$this.removeClass(this.hoverClass); $this.removeClass(this.hoverClass);
// Hide badge if possible // Hide badge if possible
if(this.badge) if (this.badge) this.badge.css({ left: -1000, top: -1000 });
this.badge.css({ left: -1000, top:-1000 });
}, },
/** /**
@ -59,8 +57,7 @@ module.exports = _.extend({},SelectComponent,{
var $this = $(e.target); var $this = $(e.target);
// Do nothing in case can't remove // Do nothing in case can't remove
if(!$this.data('model').get('removable')) if (!$this.data('model').get('removable')) return;
return;
$this.data('model').destroy(); $this.data('model').destroy();
this.removeBadge(); this.removeBadge();
@ -73,7 +70,6 @@ module.exports = _.extend({},SelectComponent,{
* @private * @private
* */ * */
updateBadgeLabel(model) { updateBadgeLabel(model) {
this.badge.html( 'Remove ' + model.getName() ); this.badge.html('Remove ' + model.getName());
}, }
}); });

9
src/commands/view/Drag.js

@ -1,5 +1,4 @@
module.exports = { module.exports = {
run(editor, sender, opts) { run(editor, sender, opts) {
var el = (opts && opts.el) || ''; var el = (opts && opts.el) || '';
var canvas = editor.Canvas; var canvas = editor.Canvas;
@ -11,7 +10,7 @@ module.exports = {
options.posFetcher = canvasView.getElementPos.bind(canvasView); options.posFetcher = canvasView.getElementPos.bind(canvasView);
// Create the resizer for the canvas if not yet created // Create the resizer for the canvas if not yet created
if(!dragger) { if (!dragger) {
dragger = editor.Utils.Dragger.init(options); dragger = editor.Utils.Dragger.init(options);
this.dragger = dragger; this.dragger = dragger;
} }
@ -27,8 +26,6 @@ module.exports = {
}, },
stop() { stop() {
if(this.canvasResizer) if (this.canvasResizer) this.canvasResizer.blur();
this.canvasResizer.blur(); }
},
}; };

6
src/commands/view/ExportTemplate.js

@ -1,7 +1,6 @@
const $ = Backbone.$; const $ = Backbone.$;
module.exports = { module.exports = {
run(editor, sender, opts = {}) { run(editor, sender, opts = {}) {
sender && sender.set && sender.set('active', 0); sender && sender.set && sender.set('active', 0);
const config = editor.getConfig(); const config = editor.getConfig();
@ -9,7 +8,6 @@ module.exports = {
const pfx = config.stylePrefix; const pfx = config.stylePrefix;
this.cm = editor.CodeManager || null; this.cm = editor.CodeManager || null;
if (!this.$editors) { if (!this.$editors) {
const oHtmlEd = this.buildEditor('htmlmixed', 'hopscotch', 'HTML'); const oHtmlEd = this.buildEditor('htmlmixed', 'hopscotch', 'HTML');
const oCsslEd = this.buildEditor('css', 'hopscotch', 'CSS'); const oCsslEd = this.buildEditor('css', 'hopscotch', 'CSS');
@ -40,7 +38,7 @@ module.exports = {
label, label,
codeName, codeName,
theme, theme,
input, input
}); });
const $el = new this.cm.EditorView({ const $el = new this.cm.EditorView({
@ -51,5 +49,5 @@ module.exports = {
el.init(input); el.init(input);
return { el, $el }; return { el, $el };
}, }
}; };

46
src/commands/view/Fullscreen.js

@ -5,10 +5,13 @@ module.exports = {
*/ */
isEnabled() { isEnabled() {
var d = document; var d = document;
if(d.fullscreenElement || d.webkitFullscreenElement || d.mozFullScreenElement) if (
d.fullscreenElement ||
d.webkitFullscreenElement ||
d.mozFullScreenElement
)
return 1; return 1;
else else return 0;
return 0;
}, },
/** /**
@ -18,18 +21,15 @@ module.exports = {
*/ */
enable(el) { enable(el) {
var pfx = ''; var pfx = '';
if (el.requestFullscreen) if (el.requestFullscreen) el.requestFullscreen();
el.requestFullscreen();
else if (el.webkitRequestFullscreen) { else if (el.webkitRequestFullscreen) {
pfx = 'webkit'; pfx = 'webkit';
el.webkitRequestFullscreen(); el.webkitRequestFullscreen();
}else if (el.mozRequestFullScreen) { } else if (el.mozRequestFullScreen) {
pfx = 'moz'; pfx = 'moz';
el.mozRequestFullScreen(); el.mozRequestFullScreen();
}else if (el.msRequestFullscreen) } else if (el.msRequestFullscreen) el.msRequestFullscreen();
el.msRequestFullscreen(); else console.warn('Fullscreen not supported');
else
console.warn('Fullscreen not supported');
return pfx; return pfx;
}, },
@ -38,14 +38,10 @@ module.exports = {
*/ */
disable() { disable() {
var d = document; var d = document;
if (d.exitFullscreen) if (d.exitFullscreen) d.exitFullscreen();
d.exitFullscreen(); else if (d.webkitExitFullscreen) d.webkitExitFullscreen();
else if (d.webkitExitFullscreen) else if (d.mozCancelFullScreen) d.mozCancelFullScreen();
d.webkitExitFullscreen(); else if (d.msExitFullscreen) d.msExitFullscreen();
else if (d.mozCancelFullScreen)
d.mozCancelFullScreen();
else if (d.msExitFullscreen)
d.msExitFullscreen();
}, },
/** /**
@ -53,11 +49,11 @@ module.exports = {
* it's enabled * it's enabled
* @param {strinf} pfx Browser prefix * @param {strinf} pfx Browser prefix
* @param {Event} e * @param {Event} e
*/ */
fsChanged(pfx, e) { fsChanged(pfx, e) {
var d = document; var d = document;
var ev = (pfx || '') + 'fullscreenchange'; var ev = (pfx || '') + 'fullscreenchange';
if(!this.isEnabled()){ if (!this.isEnabled()) {
this.stop(null, this.sender); this.stop(null, this.sender);
document.removeEventListener(ev, this.fsChanged); document.removeEventListener(ev, this.fsChanged);
} }
@ -68,16 +64,12 @@ module.exports = {
var pfx = this.enable(editor.getContainer()); var pfx = this.enable(editor.getContainer());
this.fsChanged = this.fsChanged.bind(this, pfx); this.fsChanged = this.fsChanged.bind(this, pfx);
document.addEventListener(pfx + 'fullscreenchange', this.fsChanged); document.addEventListener(pfx + 'fullscreenchange', this.fsChanged);
if(editor) if (editor) editor.trigger('change:canvasOffset');
editor.trigger('change:canvasOffset');
}, },
stop(editor, sender) { stop(editor, sender) {
if(sender && sender.set) if (sender && sender.set) sender.set('active', false);
sender.set('active', false);
this.disable(); this.disable();
if(editor) if (editor) editor.trigger('change:canvasOffset');
editor.trigger('change:canvasOffset');
} }
}; };

14
src/commands/view/ImageComponent.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var InsertCustom = require('./InsertCustom'); var InsertCustom = require('./InsertCustom');
module.exports = _.extend({}, InsertCustom, { module.exports = _.extend({}, InsertCustom, {
/** /**
* Trigger before insert * Trigger before insert
* @param {Object} object * @param {Object} object
@ -14,8 +13,10 @@ module.exports = _.extend({}, InsertCustom, {
object.style = {}; object.style = {};
object.attributes = {}; object.attributes = {};
object.attributes.onmousedown = 'return false'; object.attributes.onmousedown = 'return false';
if (this.config.firstCentered && if (
this.getCanvasWrapper() == this.sorter.target ) { this.config.firstCentered &&
this.getCanvasWrapper() == this.sorter.target
) {
object.style.margin = '0 auto'; object.style.margin = '0 auto';
} }
}, },
@ -27,9 +28,6 @@ module.exports = _.extend({}, InsertCustom, {
* */ * */
afterInsert(model) { afterInsert(model) {
model.trigger('dblclick'); model.trigger('dblclick');
if(this.sender) if (this.sender) this.sender.set('active', false);
this.sender.set('active', false); }
},
}); });

15
src/commands/view/InsertCustom.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var CreateComponent = require('./CreateComponent'); var CreateComponent = require('./CreateComponent');
module.exports = _.extend({}, CreateComponent, { module.exports = _.extend({}, CreateComponent, {
init(...args) { init(...args) {
CreateComponent.init.apply(this, args); CreateComponent.init.apply(this, args);
_.bindAll(this, 'insertComponent'); _.bindAll(this, 'insertComponent');
@ -37,15 +36,15 @@ module.exports = _.extend({}, CreateComponent, {
this.beforeInsert(object); this.beforeInsert(object);
var index = this.sorter.lastPos.index; var index = this.sorter.lastPos.index;
// By default, collections do not trigger add event, so silent is used // By default, collections do not trigger add event, so silent is used
var model = this.create(this.sorter.target, object, index, null, {silent: false}); var model = this.create(this.sorter.target, object, index, null, {
silent: false
});
if(this.opt.terminateAfterInsert && this.sender) if (this.opt.terminateAfterInsert && this.sender)
this.sender.set('active', false); this.sender.set('active', false);
else else this.enable();
this.enable();
if(!model) if (!model) return;
return;
this.afterInsert(model, this); this.afterInsert(model, this);
}, },
@ -72,5 +71,5 @@ module.exports = _.extend({}, CreateComponent, {
* */ * */
buildContent() { buildContent() {
return this.opt.content || {}; return this.opt.content || {};
}, }
}); });

32
src/commands/view/MoveComponent.js

@ -1,18 +1,17 @@
import {on, off} from 'utils/mixins' import { on, off } from 'utils/mixins';
const SelectComponent = require('./SelectComponent'); const SelectComponent = require('./SelectComponent');
const SelectPosition = require('./SelectPosition'); const SelectPosition = require('./SelectPosition');
const $ = Backbone.$; const $ = Backbone.$;
module.exports = _.extend({}, SelectPosition, SelectComponent, { module.exports = _.extend({}, SelectPosition, SelectComponent, {
init(o) { init(o) {
SelectComponent.init.apply(this, arguments); SelectComponent.init.apply(this, arguments);
_.bindAll(this, 'initSorter','rollback', 'onEndMove'); _.bindAll(this, 'initSorter', 'rollback', 'onEndMove');
this.opt = o; this.opt = o;
this.hoverClass = this.ppfx + 'highlighter-warning'; this.hoverClass = this.ppfx + 'highlighter-warning';
this.badgeClass = this.ppfx + 'badge-warning'; this.badgeClass = this.ppfx + 'badge-warning';
this.noSelClass = this.ppfx + 'no-select'; this.noSelClass = this.ppfx + 'no-select';
}, },
enable(...args) { enable(...args) {
@ -20,7 +19,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
this.getBadgeEl().addClass(this.badgeClass); this.getBadgeEl().addClass(this.badgeClass);
this.getHighlighterEl().addClass(this.hoverClass); this.getHighlighterEl().addClass(this.hoverClass);
var wp = this.$wrapper; var wp = this.$wrapper;
wp.css('cursor','move'); wp.css('cursor', 'move');
wp.on('mousedown', this.initSorter); wp.on('mousedown', this.initSorter);
// Avoid strange moving behavior // Avoid strange moving behavior
@ -41,8 +40,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
initSorter(e) { initSorter(e) {
var el = $(e.target).data('model'); var el = $(e.target).data('model');
var drag = el.get('draggable'); var drag = el.get('draggable');
if(!drag) if (!drag) return;
return;
// Avoid badge showing on move // Avoid badge showing on move
this.cacheEl = null; this.cacheEl = null;
@ -61,8 +59,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
*/ */
initSorterFromModel(model) { initSorterFromModel(model) {
var drag = model.get('draggable'); var drag = model.get('draggable');
if(!drag) if (!drag) return;
return;
// Avoid badge showing on move // Avoid badge showing on move
this.cacheEl = null; this.cacheEl = null;
var el = model.view.el; var el = model.view.el;
@ -111,7 +108,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
* */ * */
rollback(e, force) { rollback(e, force) {
var key = e.which || e.keyCode; var key = e.which || e.keyCode;
if(key == this.opt.ESCAPE_KEY || force){ if (key == this.opt.ESCAPE_KEY || force) {
this.sorter.moved = false; this.sorter.moved = false;
this.sorter.endMove(); this.sorter.endMove();
} }
@ -124,8 +121,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
* @private * @private
*/ */
getBadgeEl() { getBadgeEl() {
if(!this.$badge) if (!this.$badge) this.$badge = $(this.getBadge());
this.$badge = $(this.getBadge());
return this.$badge; return this.$badge;
}, },
@ -135,8 +131,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
* @private * @private
*/ */
getHighlighterEl() { getHighlighterEl() {
if(!this.$hl) if (!this.$hl) this.$hl = $(this.canvas.getHighlighter());
this.$hl = $(this.canvas.getHighlighter());
return this.$hl; return this.$hl;
}, },
@ -145,6 +140,9 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
this.getBadgeEl().removeClass(this.badgeClass); this.getBadgeEl().removeClass(this.badgeClass);
this.getHighlighterEl().removeClass(this.hoverClass); this.getHighlighterEl().removeClass(this.hoverClass);
var wp = this.$wrapper; var wp = this.$wrapper;
wp.css('cursor', '').unbind().removeClass(this.noSelClass); wp
.css('cursor', '')
.unbind()
.removeClass(this.noSelClass);
} }
}); });

8
src/commands/view/OpenAssets.js

@ -1,5 +1,4 @@
module.exports = { module.exports = {
run(editor, sender, opts = {}) { run(editor, sender, opts = {}) {
const modal = editor.Modal; const modal = editor.Modal;
const am = editor.AssetManager; const am = editor.AssetManager;
@ -12,15 +11,12 @@ module.exports = {
am.onSelect(opts.onSelect); am.onSelect(opts.onSelect);
if (!this.rendered) { if (!this.rendered) {
am.render(am.getAll().filter( am.render(am.getAll().filter(asset => asset.get('type') == 'image'));
asset => asset.get('type') == 'image'
));
this.rendered = 1; this.rendered = 1;
} }
modal.setTitle(title); modal.setTitle(title);
modal.setContent(am.getContainer()); modal.setContent(am.getContainer());
modal.open(); modal.open();
}, }
}; };

3
src/commands/view/OpenBlocks.js

@ -1,5 +1,4 @@
module.exports = { module.exports = {
run(editor, sender) { run(editor, sender) {
const bm = editor.BlockManager; const bm = editor.BlockManager;
const pn = editor.Panels; const pn = editor.Panels;
@ -8,7 +7,7 @@ module.exports = {
bm.render(); bm.render();
const id = 'views-container'; const id = 'views-container';
const blocks = document.createElement('div'); const blocks = document.createElement('div');
const panels = pn.getPanel(id) || pn.addPanel({id}); const panels = pn.getPanel(id) || pn.addPanel({ id });
blocks.appendChild(bm.getContainer()); blocks.appendChild(bm.getContainer());
panels.set('appendContent', blocks).trigger('change:appendContent'); panels.set('appendContent', blocks).trigger('change:appendContent');
this.blocks = blocks; this.blocks = blocks;

10
src/commands/view/OpenLayers.js

@ -2,7 +2,6 @@ const Layers = require('navigator');
const $ = Backbone.$; const $ = Backbone.$;
module.exports = { module.exports = {
run(em, sender) { run(em, sender) {
if (!this.toAppend) { if (!this.toAppend) {
var collection = em.DomComponents.getComponent().get('components'); var collection = em.DomComponents.getComponent().get('components');
@ -13,14 +12,13 @@ module.exports = {
config.layers.stylePrefix = config.stylePrefix + lyStylePfx; config.layers.stylePrefix = config.stylePrefix + lyStylePfx;
config.layers.pStylePrefix = config.stylePrefix; config.layers.pStylePrefix = config.stylePrefix;
config.layers.em = em.editor; config.layers.em = em.editor;
config.layers.opened = em.editor.get('opened'); config.layers.opened = em.editor.get('opened');
// Check if panel exists otherwise crate it // Check if panel exists otherwise crate it
if(!panels.getPanel('views-container')) if (!panels.getPanel('views-container'))
this.panel = panels.addPanel({id: 'views-container'}); this.panel = panels.addPanel({ id: 'views-container' });
else else this.panel = panels.getPanel('views-container');
this.panel = panels.getPanel('views-container');
const toAppend = $(`<div class="${pfx}layers"></div>`); const toAppend = $(`<div class="${pfx}layers"></div>`);
this.panel.set('appendContent', toAppend).trigger('change:appendContent'); this.panel.set('appendContent', toAppend).trigger('change:appendContent');

55
src/commands/view/OpenStyleManager.js

@ -3,12 +3,11 @@ const Backbone = require('backbone');
const $ = Backbone.$; const $ = Backbone.$;
module.exports = { module.exports = {
run(em, sender) { run(em, sender) {
this.sender = sender; this.sender = sender;
if (!this.$cn) { if (!this.$cn) {
var config = em.getConfig(), var config = em.getConfig(),
panels = em.Panels; panels = em.Panels;
// Main container // Main container
this.$cn = $('<div></div>'); this.$cn = $('<div></div>');
// Secondary container // Secondary container
@ -17,34 +16,36 @@ module.exports = {
// Device Manager // Device Manager
var dvm = em.DeviceManager; var dvm = em.DeviceManager;
if(dvm && config.showDevices){ if (dvm && config.showDevices) {
var devicePanel = panels.addPanel({ id: 'devices-c'}); var devicePanel = panels.addPanel({ id: 'devices-c' });
devicePanel.set('appendContent', dvm.render()).trigger('change:appendContent'); devicePanel
.set('appendContent', dvm.render())
.trigger('change:appendContent');
} }
// Class Manager container // Class Manager container
var clm = em.SelectorManager; var clm = em.SelectorManager;
if(clm) if (clm) this.$cn2.append(clm.render([]));
this.$cn2.append(clm.render([]));
this.$cn2.append(em.StyleManager.render()); this.$cn2.append(em.StyleManager.render());
var smConfig = em.StyleManager.getConfig(); var smConfig = em.StyleManager.getConfig();
const pfx = smConfig.stylePrefix; const pfx = smConfig.stylePrefix;
// Create header // Create header
this.$header = $(`<div class="${pfx}header">${smConfig.textNoElement}</div>`); this.$header = $(
`<div class="${pfx}header">${smConfig.textNoElement}</div>`
);
this.$cn.append(this.$header); this.$cn.append(this.$header);
// Create panel if not exists // Create panel if not exists
if(!panels.getPanel('views-container')) if (!panels.getPanel('views-container'))
this.panel = panels.addPanel({ id: 'views-container'}); this.panel = panels.addPanel({ id: 'views-container' });
else else this.panel = panels.getPanel('views-container');
this.panel = panels.getPanel('views-container');
// Add all containers to the panel // Add all containers to the panel
this.panel.set('appendContent', this.$cn).trigger('change:appendContent'); this.panel.set('appendContent', this.$cn).trigger('change:appendContent');
this.target = em.editor; this.target = em.editor;
this.listenTo( this.target ,'change:selectedComponent', this.toggleSm); this.listenTo(this.target, 'change:selectedComponent', this.toggleSm);
} }
this.toggleSm(); this.toggleSm();
}, },
@ -54,25 +55,23 @@ module.exports = {
* @private * @private
*/ */
toggleSm() { toggleSm() {
const sender = this.sender; const sender = this.sender;
if (sender && sender.get && !sender.get('active')) return; if (sender && sender.get && !sender.get('active')) return;
if (this.target.get('selectedComponent')) { if (this.target.get('selectedComponent')) {
this.$cn2.show(); this.$cn2.show();
this.$header.hide(); this.$header.hide();
} else { } else {
this.$cn2.hide(); this.$cn2.hide();
this.$header.show(); this.$header.show();
} }
}, },
stop() { stop() {
// Hide secondary container if exists // Hide secondary container if exists
if(this.$cn2) if (this.$cn2) this.$cn2.hide();
this.$cn2.hide();
// Hide header container if exists // Hide header container if exists
if(this.$header) if (this.$header) this.$header.hide();
this.$header.hide();
} }
}; };

23
src/commands/view/OpenTraitManager.js

@ -1,24 +1,28 @@
const $ = Backbone.$; const $ = Backbone.$;
module.exports = { module.exports = {
run(editor, sender) { run(editor, sender) {
var config = editor.Config; var config = editor.Config;
var pfx = config.stylePrefix; var pfx = config.stylePrefix;
var tm = editor.TraitManager; var tm = editor.TraitManager;
var panelC; var panelC;
if(!this.obj){ if (!this.obj) {
var tmView = tm.getTraitsViewer(); var tmView = tm.getTraitsViewer();
var confTm = tm.getConfig(); var confTm = tm.getConfig();
this.obj = $('<div></div>') this.obj = $('<div></div>')
.append('<div class="'+pfx+'traits-label">' + confTm.labelContainer + '</div>') .append(
.get(0); '<div class="' +
pfx +
'traits-label">' +
confTm.labelContainer +
'</div>'
)
.get(0);
this.obj.appendChild(tmView.render().el); this.obj.appendChild(tmView.render().el);
var panels = editor.Panels; var panels = editor.Panels;
if(!panels.getPanel('views-container')) if (!panels.getPanel('views-container'))
panelC = panels.addPanel({id: 'views-container'}); panelC = panels.addPanel({ id: 'views-container' });
else else panelC = panels.getPanel('views-container');
panelC = panels.getPanel('views-container');
panelC.set('appendContent', this.obj).trigger('change:appendContent'); panelC.set('appendContent', this.obj).trigger('change:appendContent');
} }
@ -26,7 +30,6 @@ module.exports = {
}, },
stop() { stop() {
if(this.obj) if (this.obj) this.obj.style.display = 'none';
this.obj.style.display = 'none';
} }
}; };

15
src/commands/view/Preview.js

@ -1,21 +1,20 @@
module.exports = { module.exports = {
getPanels(editor) { getPanels(editor) {
if(!this.panels) if (!this.panels) this.panels = editor.Panels.getPanelsEl();
this.panels = editor.Panels.getPanelsEl();
return this.panels; return this.panels;
}, },
tglPointers(editor, v) { tglPointers(editor, v) {
var elP = editor.Canvas.getBody().querySelectorAll('.' + this.ppfx + 'no-pointer'); var elP = editor.Canvas.getBody().querySelectorAll(
'.' + this.ppfx + 'no-pointer'
);
_.each(elP, item => { _.each(elP, item => {
item.style.pointerEvents = v ? '' : 'all'; item.style.pointerEvents = v ? '' : 'all';
}); });
}, },
run(editor, sender) { run(editor, sender) {
if(sender && sender.set) if (sender && sender.set) sender.set('active', false);
sender.set('active', false);
editor.stopCommand('sw-visibility'); editor.stopCommand('sw-visibility');
editor.getModel().stopDefault(); editor.getModel().stopDefault();
var that = this; var that = this;
@ -23,7 +22,7 @@ module.exports = {
var canvas = editor.Canvas.getElement(); var canvas = editor.Canvas.getElement();
var editorEl = editor.getEl(); var editorEl = editor.getEl();
var pfx = editor.Config.stylePrefix; var pfx = editor.Config.stylePrefix;
if(!this.helper) { if (!this.helper) {
this.helper = document.createElement('span'); this.helper = document.createElement('span');
this.helper.className = pfx + 'off-prv fa fa-eye-slash'; this.helper.className = pfx + 'off-prv fa fa-eye-slash';
editorEl.appendChild(this.helper); editorEl.appendChild(this.helper);
@ -57,7 +56,7 @@ module.exports = {
panels.style.display = 'block'; panels.style.display = 'block';
var canvas = editor.Canvas.getElement(); var canvas = editor.Canvas.getElement();
canvas.setAttribute('style', ''); canvas.setAttribute('style', '');
if(this.helper) { if (this.helper) {
this.helper.style.display = 'none'; this.helper.style.display = 'none';
} }
editor.trigger('change:canvasOffset'); editor.trigger('change:canvasOffset');

6
src/commands/view/Resize.js

@ -1,5 +1,4 @@
module.exports = { module.exports = {
run(editor, sender, opts) { run(editor, sender, opts) {
var opt = opts || {}; var opt = opts || {};
var el = opt.el || ''; var el = opt.el || '';
@ -14,7 +13,7 @@ module.exports = {
options.mousePosFetcher = canvas.getMouseRelativePos; options.mousePosFetcher = canvas.getMouseRelativePos;
// Create the resizer for the canvas if not yet created // Create the resizer for the canvas if not yet created
if(!canvasResizer || opt.forceNew) { if (!canvasResizer || opt.forceNew) {
this.canvasResizer = editor.Utils.Resizer.init(options); this.canvasResizer = editor.Utils.Resizer.init(options);
canvasResizer = this.canvasResizer; canvasResizer = this.canvasResizer;
} }
@ -27,6 +26,5 @@ module.exports = {
stop() { stop() {
const resizer = this.canvasResizer; const resizer = this.canvasResizer;
resizer && resizer.blur(); resizer && resizer.blur();
}, }
}; };

96
src/commands/view/SelectComponent.js

@ -1,5 +1,5 @@
import { bindAll } from 'underscore'; import { bindAll } from 'underscore';
import { on, off, getUnitFromValue} from 'utils/mixins'; import { on, off, getUnitFromValue } from 'utils/mixins';
const ToolbarView = require('dom_components/view/ToolbarView'); const ToolbarView = require('dom_components/view/ToolbarView');
const Toolbar = require('dom_components/model/Toolbar'); const Toolbar = require('dom_components/model/Toolbar');
@ -8,15 +8,13 @@ const $ = require('backbone').$;
let showOffsets; let showOffsets;
module.exports = { module.exports = {
init(o) { init(o) {
bindAll(this, 'onHover', 'onOut', 'onClick', 'onKeyPress', 'onFrameScroll'); bindAll(this, 'onHover', 'onOut', 'onClick', 'onKeyPress', 'onFrameScroll');
}, },
enable() { enable() {
this.frameOff = this.canvasOff = this.adjScroll = null; this.frameOff = this.canvasOff = this.adjScroll = null;
var config = this.config.em.get('Config'); var config = this.config.em.get('Config');
this.startSelectComponent(); this.startSelectComponent();
var em = this.config.em; var em = this.config.em;
showOffsets = 1; showOffsets = 1;
@ -30,7 +28,7 @@ module.exports = {
* @private * @private
* */ * */
startSelectComponent() { startSelectComponent() {
this.toggleSelectComponent(1); this.toggleSelectComponent(1);
}, },
/** /**
@ -38,7 +36,7 @@ module.exports = {
* @private * @private
* */ * */
stopSelectComponent() { stopSelectComponent() {
this.toggleSelectComponent(); this.toggleSelectComponent();
}, },
/** /**
@ -48,7 +46,7 @@ module.exports = {
toggleSelectComponent(enable) { toggleSelectComponent(enable) {
const em = this.em; const em = this.em;
const method = enable ? 'on' : 'off'; const method = enable ? 'on' : 'off';
const methods = {on, off}; const methods = { on, off };
const body = this.getCanvasBody(); const body = this.getCanvasBody();
const win = this.getContentWindow(); const win = this.getContentWindow();
methods[method](body, 'mouseover', this.onHover); methods[method](body, 'mouseover', this.onHover);
@ -69,13 +67,11 @@ module.exports = {
var focused = this.frameEl.contentDocument.activeElement.tagName !== 'BODY'; var focused = this.frameEl.contentDocument.activeElement.tagName !== 'BODY';
// On CANC (46) or Backspace (8) // On CANC (46) or Backspace (8)
if(key == 8 || key == 46) { if (key == 8 || key == 46) {
if(!focused) if (!focused) e.preventDefault();
e.preventDefault(); if (comp && !focused) {
if(comp && !focused) { if (!comp.get('removable')) return;
if(!comp.get('removable')) comp.set('status', '');
return;
comp.set('status','');
comp.destroy(); comp.destroy();
this.hideBadge(); this.hideBadge();
this.clean(); this.clean();
@ -135,14 +131,13 @@ module.exports = {
var $el = $(el); var $el = $(el);
var model = $el.data('model'); var model = $el.data('model');
if ( (model && model.get('status') == 'selected') || if ((model && model.get('status') == 'selected') || !showOffsets) {
!showOffsets){
return; return;
} }
this.editor.runCommand('show-offset', { this.editor.runCommand('show-offset', {
el, el,
elPos: pos, elPos: pos
}); });
}, },
@ -164,7 +159,7 @@ module.exports = {
this.editor.runCommand('show-offset', { this.editor.runCommand('show-offset', {
el, el,
elPos: pos, elPos: pos,
state: 'Fixed', state: 'Fixed'
}); });
}, },
@ -174,8 +169,7 @@ module.exports = {
* @param {Object} pos * @param {Object} pos
*/ */
hideFixedElementOffset(el, pos) { hideFixedElementOffset(el, pos) {
if(this.editor) if (this.editor) this.editor.stopCommand('show-offset', { state: 'Fixed' });
this.editor.stopCommand('show-offset', {state: 'Fixed'});
}, },
/** /**
@ -199,7 +193,7 @@ module.exports = {
if (model.get('selectable')) { if (model.get('selectable')) {
editor.select(model); editor.select(model);
} else { } else {
let parent = model.parent(); let parent = model.parent();
while (parent && !parent.get('selectable')) parent = parent.parent(); while (parent && !parent.get('selectable')) parent = parent.parent();
parent && editor.select(parent); parent && editor.select(parent);
} }
@ -218,9 +212,8 @@ module.exports = {
var config = canvas.getConfig(); var config = canvas.getConfig();
var customeLabel = config.customBadgeLabel; var customeLabel = config.customBadgeLabel;
this.cacheEl = el; this.cacheEl = el;
var model = $el.data("model"); var model = $el.data('model');
if(!model || !model.get('badgable')) if (!model || !model.get('badgable')) return;
return;
var badge = this.getBadge(); var badge = this.getBadge();
var badgeLabel = model.getIcon() + model.getName(); var badgeLabel = model.getIcon() + model.getName();
badgeLabel = customeLabel ? customeLabel(model) : badgeLabel; badgeLabel = customeLabel ? customeLabel(model) : badgeLabel;
@ -231,7 +224,8 @@ module.exports = {
var canvasPos = canvas.getCanvasView().getPosition(); var canvasPos = canvas.getCanvasView().getPosition();
var badgeH = badge ? badge.offsetHeight : 0; var badgeH = badge ? badge.offsetHeight : 0;
var badgeW = badge ? badge.offsetWidth : 0; var badgeW = badge ? badge.offsetWidth : 0;
var top = pos.top - badgeH < canvasPos.top ? canvasPos.top : pos.top - badgeH; var top =
pos.top - badgeH < canvasPos.top ? canvasPos.top : pos.top - badgeH;
var left = pos.left + badgeW < canvasPos.left ? canvasPos.left : pos.left; var left = pos.left + badgeW < canvasPos.left ? canvasPos.left : pos.left;
bStyle.top = top + u; bStyle.top = top + u;
bStyle.left = left + u; bStyle.left = left + u;
@ -247,7 +241,11 @@ module.exports = {
var $el = $(el); var $el = $(el);
var model = $el.data('model'); var model = $el.data('model');
if(!model || !model.get("hoverable") || model.get('status') == 'selected') { if (
!model ||
!model.get('hoverable') ||
model.get('status') == 'selected'
) {
return; return;
} }
@ -302,15 +300,17 @@ module.exports = {
var toggleBodyClass = (method, e, opts) => { var toggleBodyClass = (method, e, opts) => {
const docs = opts.docs; const docs = opts.docs;
docs && docs.forEach(doc => { docs &&
const body = doc.body; docs.forEach(doc => {
const cls = body.className || ''; const body = doc.body;
body.className = (method == 'add' ? const cls = body.className || '';
`${cls} ${resizeClass}` : cls.replace(resizeClass, '')).trim(); body.className = (method == 'add'
}); ? `${cls} ${resizeClass}`
: cls.replace(resizeClass, '')
).trim();
});
}; };
if (editor && resizable) { if (editor && resizable) {
options = { options = {
// Here the resizer is updated with the current element height and width // Here the resizer is updated with the current element height and width
@ -322,7 +322,8 @@ module.exports = {
const computedStyle = getComputedStyle(el); const computedStyle = getComputedStyle(el);
const modelStyle = modelToStyle.getStyle(); const modelStyle = modelToStyle.getStyle();
const currentWidth = modelStyle[keyWidth] || computedStyle[keyWidth]; const currentWidth = modelStyle[keyWidth] || computedStyle[keyWidth];
const currentHeight = modelStyle[keyHeight] || computedStyle[keyHeight]; const currentHeight =
modelStyle[keyHeight] || computedStyle[keyHeight];
resizer.startDim.w = parseFloat(currentWidth); resizer.startDim.w = parseFloat(currentWidth);
resizer.startDim.h = parseFloat(currentHeight); resizer.startDim.h = parseFloat(currentHeight);
showOffsets = 0; showOffsets = 0;
@ -349,7 +350,7 @@ module.exports = {
return; return;
} }
const { store, selectedHandler, config} = options; const { store, selectedHandler, config } = options;
const { keyHeight, keyWidth } = config; const { keyHeight, keyWidth } = config;
const onlyHeight = ['tc', 'bc'].indexOf(selectedHandler) >= 0; const onlyHeight = ['tc', 'bc'].indexOf(selectedHandler) >= 0;
const onlyWidth = ['cl', 'cr'].indexOf(selectedHandler) >= 0; const onlyWidth = ['cl', 'cr'].indexOf(selectedHandler) >= 0;
@ -363,9 +364,12 @@ module.exports = {
style[keyHeight] = rect.h + config.unitHeight; style[keyHeight] = rect.h + config.unitHeight;
} }
modelToStyle.setStyle(style, {avoidStore: 1}); modelToStyle.setStyle(style, { avoidStore: 1 });
const updateEvent = `update:component:style`; const updateEvent = `update:component:style`;
em && em.trigger(`${updateEvent}:${keyHeight} ${updateEvent}:${keyWidth}`); em &&
em.trigger(
`${updateEvent}:${keyHeight} ${updateEvent}:${keyWidth}`
);
if (store) { if (store) {
modelToStyle.trigger('change:style', modelToStyle, style, {}); modelToStyle.trigger('change:style', modelToStyle, style, {});
@ -377,7 +381,7 @@ module.exports = {
options = { ...options, ...resizable }; options = { ...options, ...resizable };
} }
editor.runCommand('resize', {el, options}); editor.runCommand('resize', { el, options });
// On undo/redo the resizer rect is not updating, need somehow to call // On undo/redo the resizer rect is not updating, need somehow to call
// this.updateRect on undo/redo action // this.updateRect on undo/redo action
@ -409,7 +413,7 @@ module.exports = {
if (showToolbar && toolbar && toolbar.length) { if (showToolbar && toolbar && toolbar.length) {
toolbarStyle.opacity = ''; toolbarStyle.opacity = '';
toolbarStyle.display = ''; toolbarStyle.display = '';
if(!this.toolbar) { if (!this.toolbar) {
toolbarEl.innerHTML = ''; toolbarEl.innerHTML = '';
this.toolbar = new Toolbar(toolbar); this.toolbar = new Toolbar(toolbar);
var toolbarView = new ToolbarView({ var toolbarView = new ToolbarView({
@ -440,7 +444,7 @@ module.exports = {
toolbarStyle.display = 'block'; toolbarStyle.display = 'block';
var pos = this.canvas.getTargetToElementDim(toolbarEl, el, { var pos = this.canvas.getTargetToElementDim(toolbarEl, el, {
elPos, elPos,
event: 'toolbarPosUpdate', event: 'toolbarPosUpdate'
}); });
var leftPos = pos.left + pos.elementWidth - pos.targetWidth; var leftPos = pos.left + pos.elementWidth - pos.targetWidth;
toolbarStyle.top = pos.top + unit; toolbarStyle.top = pos.top + unit;
@ -461,8 +465,7 @@ module.exports = {
* @private * @private
* */ * */
clean() { clean() {
if(this.selEl) if (this.selEl) this.selEl.removeClass(this.hoverClass);
this.selEl.removeClass(this.hoverClass);
}, },
/** /**
@ -529,10 +532,11 @@ module.exports = {
* @private * @private
*/ */
cleanPrevious(model) { cleanPrevious(model) {
model && model.set({ model &&
status: '', model.set({
state: '', status: '',
}); state: ''
});
}, },
/** /**

4
src/commands/view/SelectParent.js

@ -1,15 +1,13 @@
module.exports = { module.exports = {
run(editor) { run(editor) {
const sel = editor.getSelected(); const sel = editor.getSelected();
let comp = sel && sel.parent(); let comp = sel && sel.parent();
// Recurse through the parent() chain until a selectable parent is found // Recurse through the parent() chain until a selectable parent is found
while (comp && !comp.get("selectable")) { while (comp && !comp.get('selectable')) {
comp = comp.parent(); comp = comp.parent();
} }
comp && editor.select(comp); comp && editor.select(comp);
} }
}; };

46
src/commands/view/SelectPosition.js

@ -1,7 +1,6 @@
const $ = Backbone.$; const $ = Backbone.$;
module.exports = { module.exports = {
/** /**
* Start select position event * Start select position event
* @param {HTMLElement} trg * @param {HTMLElement} trg
@ -10,7 +9,7 @@ module.exports = {
startSelectPosition(trg, doc) { startSelectPosition(trg, doc) {
this.isPointed = false; this.isPointed = false;
var utils = this.editorModel.get('Utils'); var utils = this.editorModel.get('Utils');
if(utils && !this.sorter) if (utils && !this.sorter)
this.sorter = new utils.Sorter({ this.sorter = new utils.Sorter({
container: this.getCanvasBody(), container: this.getCanvasBody(),
placer: this.canvas.getPlacerEl(), placer: this.canvas.getPlacerEl(),
@ -22,7 +21,7 @@ module.exports = {
wmargin: 1, wmargin: 1,
nested: 1, nested: 1,
em: this.editorModel, em: this.editorModel,
canvasRelative: 1, canvasRelative: 1
}); });
this.sorter.startSort(trg); this.sorter.startSort(trg);
}, },
@ -46,17 +45,27 @@ module.exports = {
* */ * */
stopSelectPosition() { stopSelectPosition() {
this.posTargetCollection = null; this.posTargetCollection = null;
this.posIndex = this.posMethod=='after' && this.cDim.length!==0 ? this.posIndex + 1 : this.posIndex; //Normalize this.posIndex =
if(this.sorter){ this.posMethod == 'after' && this.cDim.length !== 0
? this.posIndex + 1
: this.posIndex; //Normalize
if (this.sorter) {
this.sorter.moved = 0; this.sorter.moved = 0;
this.sorter.endMove(); this.sorter.endMove();
} }
if(this.cDim){ if (this.cDim) {
this.posIsLastEl = this.cDim.length!==0 && this.posMethod=='after' && this.posIndex==this.cDim.length; this.posIsLastEl =
this.posTargetEl = (this.cDim.length===0 ? $(this.outsideElem) : this.cDim.length !== 0 &&
(!this.posIsLastEl && this.cDim[this.posIndex] ? $(this.cDim[this.posIndex][5]).parent() : $(this.outsideElem) )); this.posMethod == 'after' &&
this.posTargetModel = this.posTargetEl.data("model"); this.posIndex == this.cDim.length;
this.posTargetCollection = this.posTargetEl.data("model-comp"); this.posTargetEl =
this.cDim.length === 0
? $(this.outsideElem)
: !this.posIsLastEl && this.cDim[this.posIndex]
? $(this.cDim[this.posIndex][5]).parent()
: $(this.outsideElem);
this.posTargetModel = this.posTargetEl.data('model');
this.posTargetCollection = this.posTargetEl.data('model-comp');
} }
}, },
@ -80,23 +89,24 @@ module.exports = {
var i = index || 0; var i = index || 0;
var m = method || 'before'; var m = method || 'before';
var len = dims.length; var len = dims.length;
var isLast = len !== 0 && m == 'after' && i == len; var isLast = len !== 0 && m == 'after' && i == len;
if(len !== 0 && ( if (
(!isLast && !dims[i][4]) || len !== 0 &&
(dims[i-1] && !dims[i-1][4]) || ((!isLast && !dims[i][4]) ||
(isLast && !dims[i-1][4]) ) ) (dims[i - 1] && !dims[i - 1][4]) ||
(isLast && !dims[i - 1][4]))
)
return 1; return 1;
return 0; return 0;
}, },
run() { run() {
this.enable(); this.enable();
}, },
stop() { stop() {
this.stopSelectPosition(); this.stopSelectPosition();
this.$wrapper.css('cursor',''); this.$wrapper.css('cursor', '');
this.$wrapper.unbind(); this.$wrapper.unbind();
} }
}; };

14
src/commands/view/ShowOffset.js

@ -1,7 +1,6 @@
const $ = Backbone.$; const $ = Backbone.$;
module.exports = { module.exports = {
getOffsetMethod(state) { getOffsetMethod(state) {
var method = state || ''; var method = state || '';
return 'get' + method + 'OffsetViewerEl'; return 'get' + method + 'OffsetViewerEl';
@ -12,8 +11,10 @@ module.exports = {
var state = opt.state || ''; var state = opt.state || '';
var config = editor.getConfig(); var config = editor.getConfig();
if (!config.showOffsets || if (
(!config.showOffsetsSelected && state == 'Fixed') ) { !config.showOffsets ||
(!config.showOffsetsSelected && state == 'Fixed')
) {
return; return;
} }
@ -36,7 +37,7 @@ module.exports = {
var padL = this['padL' + state]; var padL = this['padL' + state];
var padR = this['padR' + state]; var padR = this['padR' + state];
if(!this[stateVar]) { if (!this[stateVar]) {
var stateLow = state.toLowerCase(); var stateLow = state.toLowerCase();
var marginName = stateLow + 'margin-v'; var marginName = stateLow + 'margin-v';
var paddingName = stateLow + 'padding-v'; var paddingName = stateLow + 'padding-v';
@ -125,7 +126,7 @@ module.exports = {
pbStyle.top = pos.top + pos.height - padBot + unit; pbStyle.top = pos.top + pos.height - padBot + unit;
pbStyle.left = posLeft + unit; pbStyle.left = posLeft + unit;
var padSideH = (pos.height - padBot - padTop) + unit; var padSideH = pos.height - padBot - padTop + unit;
var padSideT = pos.top + padTop + unit; var padSideT = pos.top + padTop + unit;
plStyle.height = padSideH; plStyle.height = padSideH;
plStyle.width = style.paddingLeft; plStyle.width = style.paddingLeft;
@ -146,6 +147,5 @@ module.exports = {
var canvas = editor.Canvas; var canvas = editor.Canvas;
var offsetViewer = canvas[method](); var offsetViewer = canvas[method]();
offsetViewer.style.display = 'none'; offsetViewer.style.display = 'none';
}, }
}; };

4
src/commands/view/SwitchVisibility.js

@ -1,11 +1,9 @@
module.exports = { module.exports = {
run(ed) { run(ed) {
ed.Canvas.getBody().className = this.ppfx + 'dashed'; ed.Canvas.getBody().className = this.ppfx + 'dashed';
}, },
stop(ed) { stop(ed) {
ed.Canvas.getBody().className = ""; ed.Canvas.getBody().className = '';
} }
}; };

13
src/commands/view/TextComponent.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var CreateComponent = require('./CreateComponent'); var CreateComponent = require('./CreateComponent');
module.exports = _.extend({}, CreateComponent, { module.exports = _.extend({}, CreateComponent, {
/** /**
* This event is triggered at the beginning of a draw operation * This event is triggered at the beginning of a draw operation
* @param {Object} component Object component before creation * @param {Object} component Object component before creation
@ -10,8 +9,7 @@ module.exports = _.extend({}, CreateComponent, {
* */ * */
beforeDraw(component) { beforeDraw(component) {
component.type = 'text'; component.type = 'text';
if(!component.style) if (!component.style) component.style = {};
component.style = {};
component.style.padding = '10px'; component.style.padding = '10px';
}, },
@ -21,11 +19,8 @@ module.exports = _.extend({}, CreateComponent, {
* @private * @private
* */ * */
afterDraw(model) { afterDraw(model) {
if(!model || !model.set) if (!model || !model.set) return;
return;
model.trigger('focus'); model.trigger('focus');
if(this.sender) if (this.sender) this.sender.set('active', false);
this.sender.set('active', false); }
},
}); });

6
src/css_composer/config/config.js

@ -1,12 +1,10 @@
module.exports = { module.exports = {
// Style prefix // Style prefix
stylePrefix: 'css-', stylePrefix: 'css-',
// Custom CSS string to render on top // Custom CSS string to render on top
'staticRules': '', staticRules: '',
// Default CSS style // Default CSS style
rules: [], rules: []
}; };

697
src/css_composer/index.js

@ -19,375 +19,352 @@
module.exports = () => { module.exports = () => {
let em; let em;
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
CssRule = require('./model/CssRule'), CssRule = require('./model/CssRule'),
CssRules = require('./model/CssRules'), CssRules = require('./model/CssRules'),
CssRulesView = require('./view/CssRulesView'); CssRulesView = require('./view/CssRulesView');
const Selectors = require('selector_manager/model/Selectors'); const Selectors = require('selector_manager/model/Selectors');
const Selector = require('selector_manager/model/Selector'); const Selector = require('selector_manager/model/Selector');
var rules, rulesView; var rules, rulesView;
return { return {
Selectors,
Selectors,
/**
/** * Name of the module
* Name of the module * @type {String}
* @type {String} * @private
* @private */
*/ name: 'CssComposer',
name: 'CssComposer',
/**
/** * Mandatory for the storage manager
* Mandatory for the storage manager * @type {String}
* @type {String} * @private
* @private */
*/ storageKey() {
storageKey() { var keys = [];
var keys = []; var smc = (c.stm && c.stm.getConfig()) || {};
var smc = (c.stm && c.stm.getConfig()) || {}; if (smc.storeCss) keys.push('css');
if(smc.storeCss) if (smc.storeStyles) keys.push('styles');
keys.push('css'); return keys;
if(smc.storeStyles) },
keys.push('styles');
return keys; /**
}, * Initializes module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
/** * @private
* Initializes module. Automatically called with a new instance of the editor */
* @param {Object} config Configurations init(config) {
* @private c = config || {};
*/ for (var name in defaults) {
init(config) { if (!(name in c)) c[name] = defaults[name];
c = config || {}; }
for (var name in defaults) {
if (!(name in c)) var ppfx = c.pStylePrefix;
c[name] = defaults[name]; if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
}
var elStyle = (c.em && c.em.config.style) || '';
var ppfx = c.pStylePrefix; c.rules = elStyle || c.rules;
if(ppfx)
c.stylePrefix = ppfx + c.stylePrefix; c.sm = c.em;
em = c.em;
var elStyle = (c.em && c.em.config.style) || ''; rules = new CssRules([], c);
c.rules = elStyle || c.rules; rulesView = new CssRulesView({
collection: rules,
c.sm = c.em; config: c
em = c.em; });
rules = new CssRules([], c); return this;
rulesView = new CssRulesView({ },
collection: rules,
config: c, /**
}); * On load callback
return this; * @private
}, */
onLoad() {
/** rules.add(c.rules);
* On load callback },
* @private
*/ /**
onLoad() { * Do stuff after load
rules.add(c.rules); * @param {Editor} em
}, * @private
*/
postLoad(em) {
/** const ev = 'add remove';
* Do stuff after load const rules = this.getAll();
* @param {Editor} em em.stopListening(rules, ev, this.handleChange);
* @private em.listenTo(rules, ev, this.handleChange);
*/ rules.each(rule => this.handleChange(rule));
postLoad(em) { },
const ev = 'add remove';
const rules = this.getAll(); /**
em.stopListening(rules, ev, this.handleChange); * Handle rule changes
em.listenTo(rules, ev, this.handleChange); * @private
rules.each(rule => this.handleChange(rule)); */
}, handleChange(model) {
const ev = 'change:style';
const um = em.get('UndoManager');
/** um && um.add(model);
* Handle rule changes const handleUpdates = em.handleUpdates.bind(em);
* @private em.stopListening(model, ev, handleUpdates);
*/ em.listenTo(model, ev, handleUpdates);
handleChange(model) { },
const ev = 'change:style';
const um = em.get('UndoManager'); /**
um && um.add(model); * Load data from the passed object, if the object is empty will try to fetch them
const handleUpdates = em.handleUpdates.bind(em); * autonomously from the storage manager.
em.stopListening(model, ev, handleUpdates); * The fetched data will be added to the collection
em.listenTo(model, ev, handleUpdates); * @param {Object} data Object of data to load
}, * @return {Object} Loaded rules
*/
load(data) {
/** var d = data || '';
* Load data from the passed object, if the object is empty will try to fetch them
* autonomously from the storage manager. if (!d && c.stm) {
* The fetched data will be added to the collection d = c.em.getCacheLoad();
* @param {Object} data Object of data to load }
* @return {Object} Loaded rules
*/ var obj = d.styles || '';
load(data) {
var d = data || ''; if (d.styles) {
try {
if (!d && c.stm) { obj = JSON.parse(d.styles);
d = c.em.getCacheLoad(); } catch (err) {}
} } else if (d.css) {
obj = c.em.get('Parser').parseCss(d.css);
var obj = d.styles || ''; }
if(d.styles) { if (obj) {
try { rules.reset(obj);
obj = JSON.parse(d.styles); }
} catch (err) {}
} else if (d.css) { return obj;
obj = c.em.get('Parser').parseCss(d.css); },
/**
* Store data to the selected storage
* @param {Boolean} noStore If true, won't store
* @return {Object} Data to store
*/
store(noStore) {
if (!c.stm) return;
var obj = {};
var keys = this.storageKey();
if (keys.indexOf('css') >= 0) obj.css = c.em.getCss();
if (keys.indexOf('styles') >= 0) obj.styles = JSON.stringify(rules);
if (!noStore) c.stm.store(obj);
return obj;
},
/**
* Add new rule to the collection, if not yet exists with the same selectors
* @param {Array<Selector>} selectors Array of selectors
* @param {String} state Css rule state
* @param {String} width For which device this style is oriented
* @param {Object} opts Other options for the rule
* @return {Model}
* @example
* var sm = editor.SelectorManager;
* var sel1 = sm.add('myClass1');
* var sel2 = sm.add('myClass2');
* var rule = cssComposer.add([sel1, sel2], 'hover');
* rule.set('style', {
* width: '100px',
* color: '#fff',
* });
* */
add(selectors, state, width, opts) {
var s = state || '';
var w = width || '';
var opt = opts || {};
var rule = this.get(selectors, s, w, opt);
if (rule) return rule;
else {
opt.state = s;
opt.mediaText = w;
opt.selectors = '';
rule = new CssRule(opt, c);
rule.get('selectors').add(selectors);
rules.add(rule);
return rule;
}
},
/**
* Get the rule
* @param {Array<Selector>} selectors Array of selectors
* @param {String} state Css rule state
* @param {String} width For which device this style is oriented
* @param {Object} ruleProps Other rule props
* @return {Model|null}
* @example
* var sm = editor.SelectorManager;
* var sel1 = sm.add('myClass1');
* var sel2 = sm.add('myClass2');
* var rule = cssComposer.get([sel1, sel2], 'hover');
* // Update the style
* rule.set('style', {
* width: '300px',
* color: '#000',
* });
* */
get(selectors, state, width, ruleProps) {
var rule = null;
rules.each(m => {
if (rule) return;
if (m.compare(selectors, state, width, ruleProps)) rule = m;
});
return rule;
},
/**
* Get the collection of rules
* @return {Collection}
* */
getAll() {
return rules;
},
/**
* Remove all rules
* @return {this}
*/
clear() {
this.getAll().reset();
return this;
},
/**
* Add a raw collection of rule objects
* This method overrides styles, in case, of already defined rule
* @param {Array<Object>} data Array of rule objects, eg . [{selectors: ['class1'], style: {....}}, ..]
* @param {Object} opts Options
* @return {Array<Model>}
* @private
*/
addCollection(data, opts = {}) {
var result = [];
var d = data instanceof Array ? data : [data];
for (var i = 0, l = d.length; i < l; i++) {
var rule = d[i] || {};
if (!rule.selectors) continue;
var sm = c.em && c.em.get('SelectorManager');
if (!sm) console.warn('Selector Manager not found');
var sl = rule.selectors;
var sels = sl instanceof Array ? sl : [sl];
var newSels = [];
for (var j = 0, le = sels.length; j < le; j++) {
var selec = sm.add(sels[j]);
newSels.push(selec);
} }
if (obj) { var modelExists = this.get(newSels, rule.state, rule.mediaText, rule);
rules.reset(obj); var model = this.add(newSels, rule.state, rule.mediaText, rule);
} var updateStyle = !modelExists || !opts.avoidUpdateStyle;
const style = rule.style || {};
return obj; if (updateStyle) {
}, let styleUpdate = opts.extend
? { ...model.get('style'), ...style }
/** : style;
* Store data to the selected storage model.set('style', styleUpdate);
* @param {Boolean} noStore If true, won't store
* @return {Object} Data to store
*/
store(noStore) {
if(!c.stm)
return;
var obj = {};
var keys = this.storageKey();
if(keys.indexOf('css') >= 0)
obj.css = c.em.getCss();
if(keys.indexOf('styles') >= 0)
obj.styles = JSON.stringify(rules);
if(!noStore)
c.stm.store(obj);
return obj;
},
/**
* Add new rule to the collection, if not yet exists with the same selectors
* @param {Array<Selector>} selectors Array of selectors
* @param {String} state Css rule state
* @param {String} width For which device this style is oriented
* @param {Object} opts Other options for the rule
* @return {Model}
* @example
* var sm = editor.SelectorManager;
* var sel1 = sm.add('myClass1');
* var sel2 = sm.add('myClass2');
* var rule = cssComposer.add([sel1, sel2], 'hover');
* rule.set('style', {
* width: '100px',
* color: '#fff',
* });
* */
add(selectors, state, width, opts) {
var s = state || '';
var w = width || '';
var opt = opts || {};
var rule = this.get(selectors, s, w, opt);
if(rule)
return rule;
else {
opt.state = s;
opt.mediaText = w;
opt.selectors = '';
rule = new CssRule(opt, c);
rule.get('selectors').add(selectors);
rules.add(rule);
return rule;
}
},
/**
* Get the rule
* @param {Array<Selector>} selectors Array of selectors
* @param {String} state Css rule state
* @param {String} width For which device this style is oriented
* @param {Object} ruleProps Other rule props
* @return {Model|null}
* @example
* var sm = editor.SelectorManager;
* var sel1 = sm.add('myClass1');
* var sel2 = sm.add('myClass2');
* var rule = cssComposer.get([sel1, sel2], 'hover');
* // Update the style
* rule.set('style', {
* width: '300px',
* color: '#000',
* });
* */
get(selectors, state, width, ruleProps) {
var rule = null;
rules.each(m => {
if(rule)
return;
if(m.compare(selectors, state, width, ruleProps))
rule = m;
});
return rule;
},
/**
* Get the collection of rules
* @return {Collection}
* */
getAll() {
return rules;
},
/**
* Remove all rules
* @return {this}
*/
clear() {
this.getAll().reset();
return this;
},
/**
* Add a raw collection of rule objects
* This method overrides styles, in case, of already defined rule
* @param {Array<Object>} data Array of rule objects, eg . [{selectors: ['class1'], style: {....}}, ..]
* @param {Object} opts Options
* @return {Array<Model>}
* @private
*/
addCollection(data, opts = {}) {
var result = [];
var d = data instanceof Array ? data : [data];
for (var i = 0, l = d.length; i < l; i++) {
var rule = d[i] || {};
if(!rule.selectors)
continue;
var sm = c.em && c.em.get('SelectorManager');
if(!sm)
console.warn('Selector Manager not found');
var sl = rule.selectors;
var sels = sl instanceof Array ? sl : [sl];
var newSels = [];
for (var j = 0, le = sels.length; j < le; j++) {
var selec = sm.add(sels[j]);
newSels.push(selec);
}
var modelExists = this.get(newSels, rule.state, rule.mediaText, rule);
var model = this.add(newSels, rule.state, rule.mediaText, rule);
var updateStyle = !modelExists || !opts.avoidUpdateStyle;
const style = rule.style || {};
if (updateStyle) {
let styleUpdate = opts.extend ? { ...model.get('style'), ...style } : style;
model.set('style', styleUpdate);
}
result.push(model);
} }
return result; result.push(model);
}, }
return result;
/** },
* Add/update the CSS rule with id selector
* @param {string} name Id selector name, eg. 'my-id' /**
* @param {Object} style Style properties and values * Add/update the CSS rule with id selector
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @param {string} name Id selector name, eg. 'my-id'
* @return {CssRule} The new/updated rule * @param {Object} style Style properties and values
* @example * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* const rule = cc.setIdRule('myid', { color: 'red' }); * @return {CssRule} The new/updated rule
* const ruleHover = cc.setIdRule('myid', { color: 'blue' }, { state: 'hover' }); * @example
* // This will add current CSS: * const rule = cc.setIdRule('myid', { color: 'red' });
* // #myid { color: red } * const ruleHover = cc.setIdRule('myid', { color: 'blue' }, { state: 'hover' });
* // #myid:hover { color: blue } * // This will add current CSS:
*/ * // #myid { color: red }
setIdRule(name, style = {}, opts = {}) { * // #myid:hover { color: blue }
const state = opts.state || ''; */
const media = opts.mediaText || em.getCurrentMedia(); setIdRule(name, style = {}, opts = {}) {
const sm = em.get('SelectorManager'); const state = opts.state || '';
const selector = sm.add({ name, type: Selector.TYPE_ID }); const media = opts.mediaText || em.getCurrentMedia();
const rule = this.add(selector, state, media); const sm = em.get('SelectorManager');
rule.setStyle(style, opts); const selector = sm.add({ name, type: Selector.TYPE_ID });
return rule; const rule = this.add(selector, state, media);
}, rule.setStyle(style, opts);
return rule;
},
/**
* Get the CSS rule by id selector /**
* @param {string} name Id selector name, eg. 'my-id' * Get the CSS rule by id selector
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @param {string} name Id selector name, eg. 'my-id'
* @return {CssRule} * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @example * @return {CssRule}
* const rule = cc.getIdRule('myid'); * @example
* const ruleHover = cc.setIdRule('myid', { state: 'hover' }); * const rule = cc.getIdRule('myid');
*/ * const ruleHover = cc.setIdRule('myid', { state: 'hover' });
getIdRule(name, opts = {}) { */
const state = opts.state || ''; getIdRule(name, opts = {}) {
const media = opts.mediaText || em.getCurrentMedia(); const state = opts.state || '';
const selector = em.get('SelectorManager').get(name, Selector.TYPE_ID); const media = opts.mediaText || em.getCurrentMedia();
return selector && this.get(selector, state, media); const selector = em.get('SelectorManager').get(name, Selector.TYPE_ID);
}, return selector && this.get(selector, state, media);
},
/** /**
* Add/update the CSS rule with class selector * Add/update the CSS rule with class selector
* @param {string} name Class selector name, eg. 'my-class' * @param {string} name Class selector name, eg. 'my-class'
* @param {Object} style Style properties and values * @param {Object} style Style properties and values
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} The new/updated rule * @return {CssRule} The new/updated rule
* @example * @example
* const rule = cc.setClassRule('myclass', { color: 'red' }); * const rule = cc.setClassRule('myclass', { color: 'red' });
* const ruleHover = cc.setClassRule('myclass', { color: 'blue' }, { state: 'hover' }); * const ruleHover = cc.setClassRule('myclass', { color: 'blue' }, { state: 'hover' });
* // This will add current CSS: * // This will add current CSS:
* // .myclass { color: red } * // .myclass { color: red }
* // .myclass:hover { color: blue } * // .myclass:hover { color: blue }
*/ */
setClassRule(name, style = {}, opts = {}) { setClassRule(name, style = {}, opts = {}) {
const state = opts.state || ''; const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia(); const media = opts.mediaText || em.getCurrentMedia();
const sm = em.get('SelectorManager'); const sm = em.get('SelectorManager');
const selector = sm.add({ name, type: Selector.TYPE_CLASS }); const selector = sm.add({ name, type: Selector.TYPE_CLASS });
const rule = this.add(selector, state, media); const rule = this.add(selector, state, media);
rule.setStyle(style, opts); rule.setStyle(style, opts);
return rule; return rule;
}, },
/**
/** * Get the CSS rule by class selector
* Get the CSS rule by class selector * @param {string} name Class selector name, eg. 'my-class'
* @param {string} name Class selector name, eg. 'my-class' * @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @param {Object} [opts={}] Custom options, like `state` and `mediaText` * @return {CssRule}
* @return {CssRule} * @example
* @example * const rule = cc.getClassRule('myclass');
* const rule = cc.getClassRule('myclass'); * const ruleHover = cc.getClassRule('myclass', { state: 'hover' });
* const ruleHover = cc.getClassRule('myclass', { state: 'hover' }); */
*/ getClassRule(name, opts = {}) {
getClassRule(name, opts = {}) { const state = opts.state || '';
const state = opts.state || ''; const media = opts.mediaText || em.getCurrentMedia();
const media = opts.mediaText || em.getCurrentMedia(); const selector = em.get('SelectorManager').get(name, Selector.TYPE_CLASS);
const selector = em.get('SelectorManager').get(name, Selector.TYPE_CLASS); return selector && this.get(selector, state, media);
return selector && this.get(selector, state, media); },
},
/**
* Render the block of CSS rules
/** * @return {HTMLElement}
* Render the block of CSS rules * @private
* @return {HTMLElement} */
* @private render() {
*/ return rulesView.render().el;
render() { }
return rulesView.render().el; };
},
};
}; };

72
src/css_composer/model/CssRule.js

@ -4,8 +4,7 @@ var Backbone = require('backbone');
var Selectors = require('selector_manager/model/Selectors'); var Selectors = require('selector_manager/model/Selectors');
module.exports = Backbone.Model.extend(Styleable).extend({ module.exports = Backbone.Model.extend(Styleable).extend({
defaults: {
defaults: {
// Css selectors // Css selectors
selectors: {}, selectors: {},
@ -27,9 +26,8 @@ module.exports = Backbone.Model.extend(Styleable).extend({
// If true, sets '!important' on all properties // If true, sets '!important' on all properties
// You can use an array to specify properties to set important // You can use an array to specify properties to set important
// Used in view // Used in view
important: 0, important: 0
}, },
initialize(c, opt = {}) { initialize(c, opt = {}) {
this.config = c || {}; this.config = c || {};
@ -40,7 +38,7 @@ module.exports = Backbone.Model.extend(Styleable).extend({
if (em) { if (em) {
const sm = em.get('SelectorManager'); const sm = em.get('SelectorManager');
const slct = []; const slct = [];
selectors.forEach((selector) => { selectors.forEach(selector => {
slct.push(sm.add(selector)); slct.push(sm.add(selector));
}); });
selectors = slct; selectors = slct;
@ -49,7 +47,6 @@ module.exports = Backbone.Model.extend(Styleable).extend({
this.set('selectors', new Selectors(selectors)); this.set('selectors', new Selectors(selectors));
}, },
/** /**
* Return selectors fo the rule as a string * Return selectors fo the rule as a string
* @return {string} * @return {string}
@ -65,7 +62,6 @@ module.exports = Backbone.Model.extend(Styleable).extend({
return result.join(', '); return result.join(', ');
}, },
/** /**
* Returns CSS string of the rule * Returns CSS string of the rule
* @param {Object} [opts={}] Options * @param {Object} [opts={}] Options
@ -88,7 +84,6 @@ module.exports = Backbone.Model.extend(Styleable).extend({
return result; return result;
}, },
/** /**
* Compare the actual model with parameters * Compare the actual model with parameters
* @param {Object} selectors Collection of selectors * @param {Object} selectors Collection of selectors
@ -99,42 +94,35 @@ module.exports = Backbone.Model.extend(Styleable).extend({
* @private * @private
*/ */
compare(selectors, state, width, ruleProps) { compare(selectors, state, width, ruleProps) {
var otherRule = ruleProps || {}; var otherRule = ruleProps || {};
var st = state || ''; var st = state || '';
var wd = width || ''; var wd = width || '';
var selectorsAdd = otherRule.selectorsAdd || ''; var selectorsAdd = otherRule.selectorsAdd || '';
var cId = 'cid'; var cId = 'cid';
//var a1 = _.pluck(selectors.models || selectors, cId); //var a1 = _.pluck(selectors.models || selectors, cId);
//var a2 = _.pluck(this.get('selectors').models, cId); //var a2 = _.pluck(this.get('selectors').models, cId);
if(!(selectors instanceof Array) && !selectors.models) if (!(selectors instanceof Array) && !selectors.models)
selectors = [selectors]; selectors = [selectors];
var a1 = _.map((selectors.models || selectors), model => model.get('name')); var a1 = _.map(selectors.models || selectors, model => model.get('name'));
var a2 = _.map(this.get('selectors').models, model => model.get('name')); var a2 = _.map(this.get('selectors').models, model => model.get('name'));
var f = false; var f = false;
if(a1.length !== a2.length) if (a1.length !== a2.length) return f;
return f;
for (var i = 0; i < a1.length; i++) {
for (var i = 0; i < a1.length; i++) { var re = 0;
var re = 0; for (var j = 0; j < a2.length; j++) {
for (var j = 0; j < a2.length; j++) { if (a1[i] === a2[j]) re = 1;
if (a1[i] === a2[j])
re = 1;
}
if(re === 0)
return f;
} }
if (re === 0) return f;
}
if(this.get('state') !== st) if (this.get('state') !== st) return f;
return f;
if(this.get('mediaText') !== wd)
return f;
if(this.get('selectorsAdd') !== selectorsAdd) if (this.get('mediaText') !== wd) return f;
return f;
return true; if (this.get('selectorsAdd') !== selectorsAdd) return f;
},
return true;
}
}); });

15
src/css_composer/model/CssRules.js

@ -2,27 +2,23 @@ var Backbone = require('backbone');
var CssRule = require('./CssRule'); var CssRule = require('./CssRule');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
initialize(models, opt) { initialize(models, opt) {
// Inject editor // Inject editor
if(opt && opt.sm) if (opt && opt.sm) this.editor = opt.sm;
this.editor = opt.sm;
// Not used // Not used
this.model = (attrs, options) => { this.model = (attrs, options) => {
var model; var model;
if(!options.sm && opt && opt.sm) if (!options.sm && opt && opt.sm) options.sm = opt.sm;
options.sm = opt.sm;
switch(1){ switch (1) {
default: default:
model = new CssRule(attrs, options); model = new CssRule(attrs, options);
} }
return model; return model;
}; };
}, },
add(models, opt = {}) { add(models, opt = {}) {
@ -31,6 +27,5 @@ module.exports = Backbone.Collection.extend({
} }
opt.em = this.editor; opt.em = this.editor;
return Backbone.Collection.prototype.add.apply(this, [models, opt]); return Backbone.Collection.prototype.add.apply(this, [models, opt]);
}, }
}); });

6
src/css_composer/view/CssRuleView.js

@ -10,12 +10,10 @@ module.exports = require('backbone').View.extend({
this.listenTo(model.get('selectors'), 'change', this.render); this.listenTo(model.get('selectors'), 'change', this.render);
}, },
render() { render() {
const model = this.model; const model = this.model;
const important = model.get('important'); const important = model.get('important');
this.el.innerHTML = this.model.toCSS({important}); this.el.innerHTML = this.model.toCSS({ important });
return this; return this;
}, }
}); });

21
src/css_composer/view/CssRulesView.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var CssRuleView = require('./CssRuleView'); var CssRuleView = require('./CssRuleView');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
initialize(o) { initialize(o) {
const config = o.config || {}; const config = o.config || {};
this.config = config; this.config = config;
@ -10,8 +9,8 @@ module.exports = Backbone.View.extend({
this.pfx = config.stylePrefix || ''; this.pfx = config.stylePrefix || '';
this.className = this.pfx + 'rules'; this.className = this.pfx + 'rules';
const coll = this.collection; const coll = this.collection;
this.listenTo(coll, 'add', this.addTo ); this.listenTo(coll, 'add', this.addTo);
this.listenTo(coll, 'reset', this.render ); this.listenTo(coll, 'reset', this.render);
}, },
/** /**
@ -31,19 +30,17 @@ module.exports = Backbone.View.extend({
* @private * @private
* */ * */
addToCollection(model, fragmentEl) { addToCollection(model, fragmentEl) {
var fragment = fragmentEl || null; var fragment = fragmentEl || null;
var viewObject = CssRuleView; var viewObject = CssRuleView;
var view = new viewObject({ var view = new viewObject({
model, model,
config: this.config, config: this.config
}); });
var rendered = view.render().el; var rendered = view.render().el;
if(fragment) if (fragment) fragment.appendChild(rendered);
fragment.appendChild( rendered ); else this.$el.append(rendered);
else
this.$el.append(rendered);
return rendered; return rendered;
}, },

4
src/device_manager/config/config.js

@ -1,7 +1,5 @@
module.exports = { module.exports = {
devices: [], devices: [],
deviceLabel: 'Device', deviceLabel: 'Device'
}; };

176
src/device_manager/index.js

@ -9,104 +9,100 @@
*/ */
module.exports = () => { module.exports = () => {
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
Devices = require('./model/Devices'), Devices = require('./model/Devices'),
DevicesView = require('./view/DevicesView'); DevicesView = require('./view/DevicesView');
var devices, view; var devices, view;
return { return {
/**
* Name of the module
* @type {String}
* @private
*/
name: 'DeviceManager',
/** /**
* Name of the module * Initialize module. Automatically called with a new instance of the editor
* @type {String} * @param {Object} config Configurations
* @private * @param {Array<Object>} [config.devices=[]] Default devices
*/ * @example
name: 'DeviceManager', * ...
* {
* devices: [
* {name: 'Desktop', width: ''}
* {name: 'Tablet', width: '991px'}
* ],
* }
* ...
* @return {this}
* @private
*/
init(config) {
c = config || {};
for (var name in defaults) {
if (!(name in c)) c[name] = defaults[name];
}
/** devices = new Devices(c.devices);
* Initialize module. Automatically called with a new instance of the editor view = new DevicesView({
* @param {Object} config Configurations collection: devices,
* @param {Array<Object>} [config.devices=[]] Default devices config: c
* @example });
* ... return this;
* { },
* devices: [
* {name: 'Desktop', width: ''}
* {name: 'Tablet', width: '991px'}
* ],
* }
* ...
* @return {this}
* @private
*/
init(config) {
c = config || {};
for (var name in defaults) {
if (!(name in c))
c[name] = defaults[name];
}
devices = new Devices(c.devices); /**
view = new DevicesView({ * Add new device to the collection. URLs are supposed to be unique
collection: devices, * @param {string} name Device name
config: c * @param {string} width Width of the device
}); * @param {Object} opts Custom options
return this; * @return {Device} Added device
}, * @example
* deviceManager.add('Tablet', '900px');
* deviceManager.add('Tablet2', '900px', {
* height: '300px',
* widthMedia: '810px', // the width that will be used for the CSS media
* });
*/
add(name, width, opts) {
var obj = opts || {};
obj.name = name;
obj.width = width;
return devices.add(obj);
},
/** /**
* Add new device to the collection. URLs are supposed to be unique * Return device by name
* @param {string} name Device name * @param {string} name Name of the device
* @param {string} width Width of the device * @example
* @param {Object} opts Custom options * var device = deviceManager.get('Tablet');
* @return {Device} Added device * console.log(JSON.stringify(device));
* @example * // {name: 'Tablet', width: '900px'}
* deviceManager.add('Tablet', '900px'); */
* deviceManager.add('Tablet2', '900px', { get(name) {
* height: '300px', return devices.get(name);
* widthMedia: '810px', // the width that will be used for the CSS media },
* });
*/
add(name, width, opts) {
var obj = opts || {};
obj.name = name;
obj.width = width;
return devices.add(obj);
},
/** /**
* Return device by name * Return all devices
* @param {string} name Name of the device * @return {Collection}
* @example * @example
* var device = deviceManager.get('Tablet'); * var devices = deviceManager.getAll();
* console.log(JSON.stringify(device)); * console.log(JSON.stringify(devices));
* // {name: 'Tablet', width: '900px'} * // [{name: 'Desktop', width: ''}, ...]
*/ */
get(name) { getAll() {
return devices.get(name); return devices;
}, },
/**
* Return all devices
* @return {Collection}
* @example
* var devices = deviceManager.getAll();
* console.log(JSON.stringify(devices));
* // [{name: 'Desktop', width: ''}, ...]
*/
getAll() {
return devices;
},
/**
* Render devices
* @return {string} HTML string
* @private
*/
render() {
return view.render().el;
},
/**
* Render devices
* @return {string} HTML string
* @private
*/
render() {
return view.render().el;
}
}; };
}; };

6
src/device_manager/model/Device.js

@ -1,10 +1,9 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
idAttribute: 'name', idAttribute: 'name',
defaults :{ defaults: {
name: '', name: '',
// Width to set for the editor iframe // Width to set for the editor iframe
@ -15,7 +14,7 @@ module.exports = Backbone.Model.extend({
// The width which will be used in media queries, // The width which will be used in media queries,
// If empty the width will be used // If empty the width will be used
widthMedia: null, widthMedia: null
}, },
initialize() { initialize() {
@ -23,5 +22,4 @@ module.exports = Backbone.Model.extend({
this.set('widthMedia', this.get('width')); this.set('widthMedia', this.get('width'));
} }
} }
}); });

2
src/device_manager/model/Devices.js

@ -2,5 +2,5 @@ var Backbone = require('backbone');
var Device = require('./Device'); var Device = require('./Device');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
model: Device, model: Device
}); });

22
src/device_manager/view/DevicesView.js

@ -1,7 +1,6 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
template: _.template(` template: _.template(`
<div class="<%= ppfx %>device-label"><%= deviceLabel %></div> <div class="<%= ppfx %>device-label"><%= deviceLabel %></div>
<div class="<%= ppfx %>field <%= ppfx %>select"> <div class="<%= ppfx %>field <%= ppfx %>select">
@ -15,7 +14,7 @@ module.exports = Backbone.View.extend({
<button style="display:none" class="<%= ppfx %>add-trasp">+</button>`), <button style="display:none" class="<%= ppfx %>add-trasp">+</button>`),
events: { events: {
'change': 'updateDevice' change: 'updateDevice'
}, },
initialize(o) { initialize(o) {
@ -40,7 +39,7 @@ module.exports = Backbone.View.extend({
*/ */
updateDevice() { updateDevice() {
var em = this.em; var em = this.em;
if(em){ if (em) {
var devEl = this.devicesEl; var devEl = this.devicesEl;
var val = devEl ? devEl.val() : ''; var val = devEl ? devEl.val() : '';
em.set('device', val); em.set('device', val);
@ -54,7 +53,7 @@ module.exports = Backbone.View.extend({
updateSelect() { updateSelect() {
var em = this.em; var em = this.em;
var devEl = this.devicesEl; var devEl = this.devicesEl;
if(em && em.getDeviceModel && devEl){ if (em && em.getDeviceModel && devEl) {
var device = em.getDeviceModel(); var device = em.getDeviceModel();
var name = device ? device.get('name') : ''; var name = device ? device.get('name') : '';
devEl.val(name); devEl.val(name);
@ -70,21 +69,22 @@ module.exports = Backbone.View.extend({
var result = ''; var result = '';
this.collection.each(device => { this.collection.each(device => {
var name = device.get('name'); var name = device.get('name');
result += '<option value="' + name+ '">' + name + '</option>'; result += '<option value="' + name + '">' + name + '</option>';
}); });
return result; return result;
}, },
render() { render() {
var pfx = this.ppfx; var pfx = this.ppfx;
this.$el.html(this.template({ this.$el.html(
ppfx: pfx, this.template({
deviceLabel: this.config.deviceLabel ppfx: pfx,
})); deviceLabel: this.config.deviceLabel
})
);
this.devicesEl = this.$el.find('.' + pfx + 'devices'); this.devicesEl = this.$el.find('.' + pfx + 'devices');
this.devicesEl.append(this.getOptions()); this.devicesEl.append(this.getOptions());
this.el.className = pfx + 'devices-c'; this.el.className = pfx + 'devices-c';
return this; return this;
}, }
}); });

33
src/dom_components/config/config.js

@ -12,9 +12,15 @@ module.exports = {
draggable: false, draggable: false,
components: [], components: [],
traits: [], traits: [],
stylable: ['background','background-color','background-image', stylable: [
'background-repeat','background-attachment','background-position', 'background',
'background-size'], 'background-color',
'background-image',
'background-repeat',
'background-attachment',
'background-position',
'background-size'
]
}, },
// Could be used for default components // Could be used for default components
@ -32,7 +38,22 @@ module.exports = {
storeWrapper: 0, storeWrapper: 0,
// List of void elements // List of void elements
voidElements: ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', voidElements: [
'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source', 'area',
'track', 'wbr'], 'base',
'br',
'col',
'embed',
'hr',
'img',
'input',
'keygen',
'link',
'menuitem',
'meta',
'param',
'source',
'track',
'wbr'
]
}; };

93
src/dom_components/index.js

@ -46,82 +46,81 @@ module.exports = () => {
{ {
id: 'cell', id: 'cell',
model: require('./model/ComponentTableCell'), model: require('./model/ComponentTableCell'),
view: require('./view/ComponentTableCellView'), view: require('./view/ComponentTableCellView')
}, },
{ {
id: 'row', id: 'row',
model: require('./model/ComponentTableRow'), model: require('./model/ComponentTableRow'),
view: require('./view/ComponentTableRowView'), view: require('./view/ComponentTableRowView')
}, },
{ {
id: 'table', id: 'table',
model: require('./model/ComponentTable'), model: require('./model/ComponentTable'),
view: require('./view/ComponentTableView'), view: require('./view/ComponentTableView')
}, },
{ {
id: 'thead', id: 'thead',
model: require('./model/ComponentTableHead'), model: require('./model/ComponentTableHead'),
view: require('./view/ComponentTableHeadView'), view: require('./view/ComponentTableHeadView')
}, },
{ {
id: 'tbody', id: 'tbody',
model: require('./model/ComponentTableBody'), model: require('./model/ComponentTableBody'),
view: require('./view/ComponentTableBodyView'), view: require('./view/ComponentTableBodyView')
}, },
{ {
id: 'tfoot', id: 'tfoot',
model: require('./model/ComponentTableFoot'), model: require('./model/ComponentTableFoot'),
view: require('./view/ComponentTableFootView'), view: require('./view/ComponentTableFootView')
}, },
{ {
id: 'map', id: 'map',
model: require('./model/ComponentMap'), model: require('./model/ComponentMap'),
view: require('./view/ComponentMapView'), view: require('./view/ComponentMapView')
}, },
{ {
id: 'link', id: 'link',
model: require('./model/ComponentLink'), model: require('./model/ComponentLink'),
view: require('./view/ComponentLinkView'), view: require('./view/ComponentLinkView')
}, },
{ {
id: 'video', id: 'video',
model: require('./model/ComponentVideo'), model: require('./model/ComponentVideo'),
view: require('./view/ComponentVideoView'), view: require('./view/ComponentVideoView')
}, },
{ {
id: 'image', id: 'image',
model: require('./model/ComponentImage'), model: require('./model/ComponentImage'),
view: require('./view/ComponentImageView'), view: require('./view/ComponentImageView')
}, },
{ {
id: 'script', id: 'script',
model: require('./model/ComponentScript'), model: require('./model/ComponentScript'),
view: require('./view/ComponentScriptView'), view: require('./view/ComponentScriptView')
}, },
{ {
id: 'svg', id: 'svg',
model: require('./model/ComponentSvg'), model: require('./model/ComponentSvg'),
view: require('./view/ComponentSvgView'), view: require('./view/ComponentSvgView')
}, },
{ {
id: 'textnode', id: 'textnode',
model: require('./model/ComponentTextNode'), model: require('./model/ComponentTextNode'),
view: require('./view/ComponentTextNodeView'), view: require('./view/ComponentTextNodeView')
}, },
{ {
id: 'text', id: 'text',
model: require('./model/ComponentText'), model: require('./model/ComponentText'),
view: require('./view/ComponentTextView'), view: require('./view/ComponentTextView')
}, },
{ {
id: 'default', id: 'default',
model: Component, model: Component,
view: ComponentView, view: ComponentView
}, }
]; ];
return { return {
Component, Component,
Components, Components,
@ -143,7 +142,7 @@ module.exports = () => {
* @private * @private
*/ */
getConfig() { getConfig() {
return c; return c;
}, },
/** /**
@ -154,10 +153,8 @@ module.exports = () => {
storageKey() { storageKey() {
var keys = []; var keys = [];
var smc = (c.stm && c.stm.getConfig()) || {}; var smc = (c.stm && c.stm.getConfig()) || {};
if(smc.storeHtml) if (smc.storeHtml) keys.push('html');
keys.push('html'); if (smc.storeComponents) keys.push('components');
if(smc.storeComponents)
keys.push('components');
return keys; return keys;
}, },
@ -176,13 +173,11 @@ module.exports = () => {
} }
for (var name in defaults) { for (var name in defaults) {
if (!(name in c)) if (!(name in c)) c[name] = defaults[name];
c[name] = defaults[name];
} }
var ppfx = c.pStylePrefix; var ppfx = c.pStylePrefix;
if(ppfx) if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
c.stylePrefix = ppfx + c.stylePrefix;
// Load dependencies // Load dependencies
if (em) { if (em) {
@ -199,7 +194,11 @@ module.exports = () => {
wrapper.wrapper = 1; wrapper.wrapper = 1;
// Components might be a wrapper // Components might be a wrapper
if (components && components.constructor === Object && components.wrapper) { if (
components &&
components.constructor === Object &&
components.wrapper
) {
wrapper = { ...components }; wrapper = { ...components };
components = components.components || []; components = components.components || [];
wrapper.components = []; wrapper.components = [];
@ -214,14 +213,14 @@ module.exports = () => {
component = new Component(wrapper, { component = new Component(wrapper, {
sm: em, sm: em,
config: c, config: c,
componentTypes, componentTypes
}); });
component.set({ attributes: {id: 'wrapper'}}); component.set({ attributes: { id: 'wrapper' } });
componentView = new ComponentView({ componentView = new ComponentView({
model: component, model: component,
config: c, config: c,
componentTypes, componentTypes
}); });
return this; return this;
}, },
@ -243,7 +242,6 @@ module.exports = () => {
this.handleChanges(this.getWrapper(), null, { avoidStore: 1 }); this.handleChanges(this.getWrapper(), null, { avoidStore: 1 });
}, },
/** /**
* Handle component changes * Handle component changes
* @private * @private
@ -258,10 +256,11 @@ module.exports = () => {
um && comps && um.add(comps); um && comps && um.add(comps);
const evn = 'change:style change:content change:attributes change:src'; const evn = 'change:style change:content change:attributes change:src';
[ [model, evn, handleUpdates], [
[model, evn, handleUpdates],
[comps, 'add', handleChanges], [comps, 'add', handleChanges],
[comps, 'remove', handleRemoves], [comps, 'remove', handleRemoves],
[model.get('classes'), 'add remove', handleUpdates], [model.get('classes'), 'add remove', handleUpdates]
].forEach(els => { ].forEach(els => {
em.stopListening(els[0], els[1], els[2]); em.stopListening(els[0], els[1], els[2]);
em.listenTo(els[0], els[1], els[2]); em.listenTo(els[0], els[1], els[2]);
@ -271,7 +270,6 @@ module.exports = () => {
comps.each(model => this.handleChanges(model, value, opts)); comps.each(model => this.handleChanges(model, value, opts));
}, },
/** /**
* Triggered when some component is removed * Triggered when some component is removed
* @private * @private
@ -280,7 +278,6 @@ module.exports = () => {
!opts.avoidStore && em.handleUpdates(model, value, opts); !opts.avoidStore && em.handleUpdates(model, value, opts);
}, },
/** /**
* Load components from the passed object, if the object is empty will try to fetch them * Load components from the passed object, if the object is empty will try to fetch them
* autonomously from the selected storage * autonomously from the selected storage
@ -311,8 +308,11 @@ module.exports = () => {
// If the result is an object I consider it the wrapper // If the result is an object I consider it the wrapper
if (isObj) { if (isObj) {
this.getWrapper().set(result) this.getWrapper()
.initComponents().initClasses().loadTraits(); .set(result)
.initComponents()
.initClasses()
.loadTraits();
} else { } else {
this.getComponents().add(result); this.getComponents().add(result);
} }
@ -327,7 +327,7 @@ module.exports = () => {
* @return {Object} Data to store * @return {Object} Data to store
*/ */
store(noStore) { store(noStore) {
if(!c.stm) { if (!c.stm) {
return; return;
} }
@ -339,8 +339,9 @@ module.exports = () => {
} }
if (keys.indexOf('components') >= 0) { if (keys.indexOf('components') >= 0) {
const toStore = c.storeWrapper ? const toStore = c.storeWrapper
this.getWrapper() : this.getComponents(); ? this.getWrapper()
: this.getComponents();
obj.components = JSON.stringify(toStore); obj.components = JSON.stringify(toStore);
} }
@ -454,8 +455,7 @@ module.exports = () => {
*/ */
clear() { clear() {
var c = this.getComponents(); var c = this.getComponents();
for(var i = 0, len = c.length; i < len; i++) for (var i = 0, len = c.length; i < len; i++) c.pop();
c.pop();
return this; return this;
}, },
@ -477,7 +477,7 @@ module.exports = () => {
*/ */
addType(type, methods) { addType(type, methods) {
var compType = this.getType(type); var compType = this.getType(type);
if(compType) { if (compType) {
compType.model = methods.model; compType.model = methods.model;
compType.view = methods.view; compType.view = methods.view;
} else { } else {
@ -496,7 +496,7 @@ module.exports = () => {
for (var it = 0; it < df.length; it++) { for (var it = 0; it < df.length; it++) {
var dfId = df[it].id; var dfId = df[it].id;
if(dfId == type) { if (dfId == type) {
return df[it]; return df[it];
} }
} }
@ -516,12 +516,11 @@ module.exports = () => {
if (previousModel) { if (previousModel) {
previousModel.set({ previousModel.set({
status: '', status: '',
state: '', state: ''
}); });
} }
model && model.set('status','selected'); model && model.set('status', 'selected');
} }
}; };
}; };

1383
src/dom_components/model/Component.js

File diff suppressed because it is too large

179
src/dom_components/model/ComponentImage.js

@ -1,103 +1,100 @@
var Component = require('./Component'); var Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: {
...Component.prototype.defaults,
type: 'image',
tagName: 'img',
src: '',
void: 1,
droppable: 0,
editable: 1,
highlightable: 0,
resizable: 1,
traits: ['alt']
},
defaults: { ...Component.prototype.defaults, initialize(o, opt) {
type: 'image', Component.prototype.initialize.apply(this, arguments);
tagName: 'img', var attr = this.get('attributes');
src: '', if (attr.src) this.set('src', attr.src);
void: 1, },
droppable: 0,
editable: 1,
highlightable: 0,
resizable: 1,
traits: ['alt']
},
initialize(o, opt) {
Component.prototype.initialize.apply(this, arguments);
var attr = this.get('attributes');
if(attr.src)
this.set('src', attr.src);
},
initToolbar(...args) { initToolbar(...args) {
Component.prototype.initToolbar.apply(this, args); Component.prototype.initToolbar.apply(this, args);
if (this.sm && this.sm.get) { if (this.sm && this.sm.get) {
var cmd = this.sm.get('Commands'); var cmd = this.sm.get('Commands');
var cmdName = 'image-editor'; var cmdName = 'image-editor';
// Add Image Editor button only if the default command exists // Add Image Editor button only if the default command exists
if (cmd.has(cmdName)) { if (cmd.has(cmdName)) {
var tb = this.get('toolbar'); var tb = this.get('toolbar');
tb.push({ tb.push({
attributes: {class: 'fa fa-pencil'}, attributes: { class: 'fa fa-pencil' },
command: cmdName, command: cmdName
}); });
this.set('toolbar', tb); this.set('toolbar', tb);
}
} }
} },
},
/** /**
* Returns object of attributes for HTML * Returns object of attributes for HTML
* @return {Object} * @return {Object}
* @private * @private
*/ */
getAttrToHTML(...args) { getAttrToHTML(...args) {
var attr = Component.prototype.getAttrToHTML.apply(this, args); var attr = Component.prototype.getAttrToHTML.apply(this, args);
delete attr.onmousedown; delete attr.onmousedown;
var src = this.get('src'); var src = this.get('src');
if(src) if (src) attr.src = src;
attr.src = src; return attr;
return attr; },
},
/** /**
* Parse uri * Parse uri
* @param {string} uri * @param {string} uri
* @return {object} * @return {object}
* @private * @private
*/ */
parseUri(uri) { parseUri(uri) {
var el = document.createElement('a'); var el = document.createElement('a');
el.href = uri; el.href = uri;
var query = {}; var query = {};
var qrs = el.search.substring(1).split('&'); var qrs = el.search.substring(1).split('&');
for (var i = 0; i < qrs.length; i++) { for (var i = 0; i < qrs.length; i++) {
var pair = qrs[i].split('='); var pair = qrs[i].split('=');
var name = decodeURIComponent(pair[0]); var name = decodeURIComponent(pair[0]);
if(name) if (name) query[name] = decodeURIComponent(pair[1]);
query[name] = decodeURIComponent(pair[1]); }
return {
hostname: el.hostname,
pathname: el.pathname,
protocol: el.protocol,
search: el.search,
hash: el.hash,
port: el.port,
query
};
} }
return {
hostname: el.hostname,
pathname: el.pathname,
protocol: el.protocol,
search: el.search,
hash: el.hash,
port: el.port,
query,
};
}, },
{
},{ /**
* Detect if the passed element is a valid component.
/** * In case the element is valid an object abstracted
* Detect if the passed element is a valid component. * from the element will be returned
* In case the element is valid an object abstracted * @param {HTMLElement}
* from the element will be returned * @return {Object}
* @param {HTMLElement} * @private
* @return {Object} */
* @private isComponent(el) {
*/ var result = '';
isComponent(el) { if (el.tagName == 'IMG') {
var result = ''; result = { type: 'image' };
if(el.tagName == 'IMG'){ }
result = {type: 'image'}; return result;
} }
return result; }
}, );
});

90
src/dom_components/model/ComponentLink.js

@ -1,53 +1,53 @@
const Component = require('./ComponentText'); const Component = require('./ComponentText');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: { ...Component.prototype.defaults, defaults: {
...Component.prototype.defaults,
type: 'link', type: 'link',
tagName: 'a', tagName: 'a',
traits: ['title', 'href', 'target'], traits: ['title', 'href', 'target']
}, },
/** /**
* Returns object of attributes for HTML * Returns object of attributes for HTML
* @return {Object} * @return {Object}
* @private * @private
*/ */
getAttrToHTML(...args) { getAttrToHTML(...args) {
const attr = Component.prototype.getAttrToHTML.apply(this, args); const attr = Component.prototype.getAttrToHTML.apply(this, args);
delete attr.onmousedown; delete attr.onmousedown;
return attr; return attr;
}
}, },
{
}, { isComponent(el) {
let result;
isComponent(el) { let avoidEdit;
let result;
let avoidEdit; if (el.tagName == 'A') {
result = {
if (el.tagName == 'A') { type: 'link',
result = { editable: 0
type: 'link', };
editable: 0,
}; // The link is editable only if, at least, one of its
// children is a text node (not empty one)
// The link is editable only if, at least, one of its const children = el.childNodes;
// children is a text node (not empty one) const len = children.length;
const children = el.childNodes; if (!len) delete result.editable;
const len = children.length;
if (!len) delete result.editable; for (let i = 0; i < len; i++) {
const child = children[i];
for (let i = 0; i < len; i++) {
const child = children[i]; if (child.nodeType == 3 && child.textContent.trim() != '') {
delete result.editable;
if (child.nodeType == 3 && child.textContent.trim() != '') { break;
delete result.editable; }
break;
} }
} }
}
return result; return result;
}, }
}
}); );

180
src/dom_components/model/ComponentMap.js

@ -1,9 +1,9 @@
var Component = require('./ComponentImage'); var Component = require('./ComponentImage');
var OComponent = require('./Component'); var OComponent = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: _.extend({}, Component.prototype.defaults, { defaults: _.extend({}, Component.prototype.defaults, {
type: 'map', type: 'map',
void: 0, void: 0,
mapUrl: 'https://maps.google.com/maps', mapUrl: 'https://maps.google.com/maps',
@ -11,97 +11,97 @@ module.exports = Component.extend({
mapType: 'q', mapType: 'q',
address: '', address: '',
zoom: '1', zoom: '1',
attributes: {frameborder: 0}, attributes: { frameborder: 0 },
toolbar: OComponent.prototype.defaults.toolbar, toolbar: OComponent.prototype.defaults.toolbar,
traits: [{ traits: [
label: 'Address', {
name: 'address', label: 'Address',
placeholder: 'eg. London, UK', name: 'address',
changeProp: 1, placeholder: 'eg. London, UK',
},{ changeProp: 1
type: 'select', },
label: 'Map type', {
name: 'mapType', type: 'select',
changeProp: 1, label: 'Map type',
options: [ name: 'mapType',
{value: 'q', name: 'Roadmap'}, changeProp: 1,
{value: 'w', name: 'Satellite'} options: [
] { value: 'q', name: 'Roadmap' },
},{ { value: 'w', name: 'Satellite' }
label: 'Zoom', ]
name: 'zoom', },
type: 'range', {
min: '1', label: 'Zoom',
max: '20', name: 'zoom',
changeProp: 1, type: 'range',
}], min: '1',
}), max: '20',
changeProp: 1
}
initialize(o, opt) { ]
if(this.get('src')) }),
this.parseFromSrc();
else
this.updateSrc();
Component.prototype.initialize.apply(this, arguments);
this.listenTo(this, 'change:address change:zoom change:mapType', this.updateSrc);
},
updateSrc() {
this.set('src', this.getMapUrl());
},
/** initialize(o, opt) {
* Returns url of the map if (this.get('src')) this.parseFromSrc();
* @return {string} else this.updateSrc();
* @private Component.prototype.initialize.apply(this, arguments);
*/ this.listenTo(
getMapUrl() { this,
var md = this; 'change:address change:zoom change:mapType',
var addr = md.get('address'); this.updateSrc
var zoom = md.get('zoom'); );
var type = md.get('mapType'); },
var size = '';
addr = addr ? '&q=' + addr : '';
zoom = zoom ? '&z=' + zoom : '';
type = type ? '&t=' + type : '';
var result = md.get('mapUrl')+'?' + addr + zoom + type;
result += '&output=embed';
return result;
},
/** updateSrc() {
* Set attributes by src string this.set('src', this.getMapUrl());
* @private },
*/
parseFromSrc() {
var uri = this.parseUri(this.get('src'));
var qr = uri.query;
if(qr.q)
this.set('address', qr.q);
if(qr.z)
this.set('zoom', qr.z);
if(qr.t)
this.set('mapType', qr.t);
},
},{ /**
* Returns url of the map
* @return {string}
* @private
*/
getMapUrl() {
var md = this;
var addr = md.get('address');
var zoom = md.get('zoom');
var type = md.get('mapType');
var size = '';
addr = addr ? '&q=' + addr : '';
zoom = zoom ? '&z=' + zoom : '';
type = type ? '&t=' + type : '';
var result = md.get('mapUrl') + '?' + addr + zoom + type;
result += '&output=embed';
return result;
},
/** /**
* Detect if the passed element is a valid component. * Set attributes by src string
* In case the element is valid an object abstracted * @private
* from the element will be returned */
* @param {HTMLElement} parseFromSrc() {
* @return {Object} var uri = this.parseUri(this.get('src'));
* @private var qr = uri.query;
*/ if (qr.q) this.set('address', qr.q);
isComponent(el) { if (qr.z) this.set('zoom', qr.z);
var result = ''; if (qr.t) this.set('mapType', qr.t);
if(el.tagName == 'IFRAME' &&
/maps\.google\.com/.test(el.src) ){
result = {type: 'map', src: el.src};
} }
return result;
}, },
{
}); /**
* Detect if the passed element is a valid component.
* In case the element is valid an object abstracted
* from the element will be returned
* @param {HTMLElement}
* @return {Object}
* @private
*/
isComponent(el) {
var result = '';
if (el.tagName == 'IFRAME' && /maps\.google\.com/.test(el.src)) {
result = { type: 'map', src: el.src };
}
return result;
}
}
);

41
src/dom_components/model/ComponentScript.js

@ -1,27 +1,26 @@
var Component = require('./Component'); var Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: _.extend({}, Component.prototype.defaults, { defaults: _.extend({}, Component.prototype.defaults, {
type: 'script', type: 'script',
droppable: false, droppable: false,
draggable: false, draggable: false,
layerable: false, layerable: false
}), })
},
}, { {
isComponent(el) {
if (el.tagName == 'SCRIPT') {
var result = { type: 'script' };
isComponent(el) { if (el.src) {
if (el.tagName == 'SCRIPT') { result.src = el.src;
var result = {type: 'script'}; result.onload = el.onload;
}
if (el.src) { return result;
result.src = el.src;
result.onload = el.onload;
} }
return result;
} }
}, }
);
});

54
src/dom_components/model/ComponentSvg.js

@ -1,33 +1,33 @@
var Component = require('./Component'); var Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: {
...Component.prototype.defaults,
highlightable: 0
},
defaults: { ...Component.prototype.defaults, getName() {
highlightable: 0, let name = this.get('tagName');
}, let customName = this.get('custom-name');
name = name.charAt(0).toUpperCase() + name.slice(1);
getName() { return customName || name;
let name = this.get('tagName');
let customName = this.get('custom-name');
name = name.charAt(0).toUpperCase() + name.slice(1);
return customName || name;
},
}, {
isComponent(el) {
if (SVGElement && el instanceof SVGElement) {
// Some SVG elements require uppercase letters (eg. <linearGradient>)
const tagName = el.tagName;
// Make the root resizable
const resizable = tagName == 'svg' ? true : false;
return {
tagName,
type: 'svg',
resizable
};
} }
}, },
{
isComponent(el) {
if (SVGElement && el instanceof SVGElement) {
// Some SVG elements require uppercase letters (eg. <linearGradient>)
const tagName = el.tagName;
// Make the root resizable
const resizable = tagName == 'svg' ? true : false;
}); return {
tagName,
type: 'svg',
resizable
};
}
}
}
);

40
src/dom_components/model/ComponentTable.js

@ -1,29 +1,29 @@
const Component = require('./Component'); const Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: { ...Component.prototype.defaults, defaults: {
...Component.prototype.defaults,
type: 'table', type: 'table',
tagName: 'table', tagName: 'table',
droppable: ['tbody', 'thead', 'tfoot'], droppable: ['tbody', 'thead', 'tfoot']
}, },
initialize(o, opt) { initialize(o, opt) {
Component.prototype.initialize.apply(this, arguments); Component.prototype.initialize.apply(this, arguments);
const components = this.get('components'); const components = this.get('components');
!components.length && components.add({ type: 'tbody' }); !components.length && components.add({ type: 'tbody' });
}
}, },
{
isComponent(el) {
let result = '';
}, { if (el.tagName == 'TABLE') {
result = { type: 'table' };
isComponent(el) { }
let result = '';
if (el.tagName == 'TABLE') { return result;
result = { type: 'table' };
} }
}
return result; );
},
});

94
src/dom_components/model/ComponentTableBody.js

@ -1,58 +1,58 @@
const Component = require('./Component'); const Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: { ...Component.prototype.defaults, defaults: {
type: 'tbody', ...Component.prototype.defaults,
tagName: 'tbody', type: 'tbody',
draggable: ['table'], tagName: 'tbody',
droppable: ['tr'], draggable: ['table'],
columns: 1, droppable: ['tr'],
rows: 1, columns: 1,
}, rows: 1
},
initialize(o, opt) {
Component.prototype.initialize.apply(this, arguments); initialize(o, opt) {
const components = this.get('components'); Component.prototype.initialize.apply(this, arguments);
let columns = this.get('columns'); const components = this.get('components');
let rows = this.get('rows'); let columns = this.get('columns');
let rows = this.get('rows');
// Init components if empty
if (!components.length) { // Init components if empty
const rowsToAdd = []; if (!components.length) {
const rowsToAdd = [];
while (rows--) {
const columnsToAdd = []; while (rows--) {
let clm = columns; const columnsToAdd = [];
let clm = columns;
while (clm--) {
columnsToAdd.push({ while (clm--) {
type: 'cell', columnsToAdd.push({
classes: ['cell'] type: 'cell',
classes: ['cell']
});
}
rowsToAdd.push({
type: 'row',
classes: ['row'],
components: columnsToAdd
}); });
} }
rowsToAdd.push({ components.add(rowsToAdd);
type: 'row',
classes: ['row'],
components: columnsToAdd
});
} }
components.add(rowsToAdd);
} }
}, },
{
isComponent(el) {
let result = '';
},{ if (el.tagName == 'TBODY') {
result = { type: 'tbody' };
isComponent(el) { }
let result = '';
if (el.tagName == 'TBODY') { return result;
result = { type: 'tbody' };
} }
}
return result; );
},
});

37
src/dom_components/model/ComponentTableCell.js

@ -1,26 +1,27 @@
const Component = require('./Component'); const Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: { ...Component.prototype.defaults, defaults: {
...Component.prototype.defaults,
type: 'cell', type: 'cell',
tagName: 'td', tagName: 'td',
draggable: ['tr'], draggable: ['tr']
}
}, },
{
isComponent(el) {
let result = '';
const tag = el.tagName;
}, { if (tag == 'TD' || tag == 'TH') {
isComponent(el) { result = {
let result = ''; type: 'cell',
const tag = el.tagName; tagName: tag.toLowerCase()
};
}
if (tag == 'TD' || tag == 'TH') { return result;
result = {
type: 'cell',
tagName: tag.toLowerCase()
};
} }
}
return result; );
},
});

31
src/dom_components/model/ComponentTableFoot.js

@ -1,21 +1,22 @@
const ComponentTableBody = require('./ComponentTableBody'); const ComponentTableBody = require('./ComponentTableBody');
module.exports = ComponentTableBody.extend({ module.exports = ComponentTableBody.extend(
{
defaults: { ...ComponentTableBody.prototype.defaults, defaults: {
type: 'tfoot', ...ComponentTableBody.prototype.defaults,
tagName: 'tfoot', type: 'tfoot',
tagName: 'tfoot'
}
}, },
{
isComponent(el) {
let result = '';
},{ if (el.tagName == 'TFOOT') {
isComponent(el) { result = { type: 'tfoot' };
let result = ''; }
if (el.tagName == 'TFOOT') { return result;
result = { type: 'tfoot' };
} }
}
return result; );
},
});

31
src/dom_components/model/ComponentTableHead.js

@ -1,21 +1,22 @@
const ComponentTableBody = require('./ComponentTableBody'); const ComponentTableBody = require('./ComponentTableBody');
module.exports = ComponentTableBody.extend({ module.exports = ComponentTableBody.extend(
{
defaults: { ...ComponentTableBody.prototype.defaults, defaults: {
type: 'thead', ...ComponentTableBody.prototype.defaults,
tagName: 'thead' type: 'thead',
tagName: 'thead'
}
}, },
{
isComponent(el) {
let result = '';
}, { if (el.tagName == 'THEAD') {
isComponent(el) { result = { type: 'thead' };
let result = ''; }
if (el.tagName == 'THEAD') { return result;
result = { type: 'thead' };
} }
}
return result; );
},
});

45
src/dom_components/model/ComponentTableRow.js

@ -1,33 +1,34 @@
const Component = require('./Component'); const Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: { ...Component.prototype.defaults, defaults: {
...Component.prototype.defaults,
type: 'row', type: 'row',
tagName: 'tr', tagName: 'tr',
draggable: ['thead', 'tbody', 'tfoot'], draggable: ['thead', 'tbody', 'tfoot'],
droppable: ['th', 'td'] droppable: ['th', 'td']
}, },
initialize(o, opt) {
Component.prototype.initialize.apply(this, arguments);
// Clean the row from non cell components
const cells = [];
const components = this.get('components');
components.each(model => model.is('cell') && cells.push(model));
components.reset(cells);
}
}, { initialize(o, opt) {
isComponent(el) { Component.prototype.initialize.apply(this, arguments);
let result = '';
if (el.tagName == 'TR') { // Clean the row from non cell components
result = { type: 'row' }; const cells = [];
const components = this.get('components');
components.each(model => model.is('cell') && cells.push(model));
components.reset(cells);
} }
return result;
}, },
{
isComponent(el) {
let result = '';
if (el.tagName == 'TR') {
result = { type: 'row' };
}
}); return result;
}
}
);

9
src/dom_components/model/ComponentText.js

@ -1,11 +1,10 @@
const Component = require('./Component'); const Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend({
defaults: {
defaults: { ...Component.prototype.defaults, ...Component.prototype.defaults,
type: 'text', type: 'text',
droppable: false, droppable: false,
editable: true, editable: true
}, }
}); });

43
src/dom_components/model/ComponentTextNode.js

@ -1,27 +1,26 @@
var Component = require('./Component'); var Component = require('./Component');
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: _.extend({}, Component.prototype.defaults, {
droppable: false,
editable: true
}),
defaults: _.extend({}, Component.prototype.defaults, { toHTML() {
droppable: false, return this.get('content');
editable: true,
}),
toHTML() {
return this.get('content');
},
}, {
isComponent(el) {
var result = '';
if(el.nodeType === 3){
result = {
type: 'textnode',
content: el.textContent
};
} }
return result;
}, },
{
}); isComponent(el) {
var result = '';
if (el.nodeType === 3) {
result = {
type: 'textnode',
content: el.textContent
};
}
return result;
}
}
);

560
src/dom_components/model/ComponentVideo.js

@ -3,9 +3,10 @@ const OComponent = require('./Component');
const yt = 'yt'; const yt = 'yt';
const vi = 'vi'; const vi = 'vi';
module.exports = Component.extend({ module.exports = Component.extend(
{
defaults: { ...Component.prototype.defaults, defaults: {
...Component.prototype.defaults,
type: 'video', type: 'video',
tagName: 'video', tagName: 'video',
videoId: '', videoId: '',
@ -19,302 +20,295 @@ module.exports = Component.extend({
controls: 1, controls: 1,
color: '', color: '',
sources: [], sources: [],
attributes:{allowfullscreen:'allowfullscreen'}, attributes: { allowfullscreen: 'allowfullscreen' },
toolbar: OComponent.prototype.defaults.toolbar, toolbar: OComponent.prototype.defaults.toolbar
}, },
initialize(o, opt) {
var traits = [];
var prov = this.get('provider');
switch (prov) {
case yt:
traits = this.getYoutubeTraits();
break;
case vi:
traits = this.getVimeoTraits();
break;
default:
traits = this.getSourceTraits();
}
if(this.get('src'))
this.parseFromSrc();
this.set('traits', traits);
Component.prototype.initialize.apply(this, arguments);
this.listenTo(this, 'change:provider', this.updateTraits);
this.listenTo(this, 'change:videoId', this.updateSrc);
},
initialize(o, opt) {
var traits = [];
var prov = this.get('provider');
switch (prov) {
case yt:
traits = this.getYoutubeTraits();
break;
case vi:
traits = this.getVimeoTraits();
break;
default:
traits = this.getSourceTraits();
}
if (this.get('src')) this.parseFromSrc();
this.set('traits', traits);
Component.prototype.initialize.apply(this, arguments);
this.listenTo(this, 'change:provider', this.updateTraits);
this.listenTo(this, 'change:videoId', this.updateSrc);
},
initToolbar(...args) { initToolbar(...args) {
OComponent.prototype.initToolbar.apply(this, args); OComponent.prototype.initToolbar.apply(this, args);
}, },
/**
* Set attributes by src string
*/
parseFromSrc() {
var prov = this.get('provider');
var uri = this.parseUri(this.get('src'));
var qr = uri.query;
switch (prov) {
case yt: case vi:
var videoId = uri.pathname.split('/').pop();
this.set('videoId', videoId);
if(qr.autoplay)
this.set('autoplay', 1);
if(qr.loop)
this.set('loop', 1);
if(parseInt(qr.controls) === 0)
this.set('controls', 0);
if(qr.color)
this.set('color', qr.color);
break;
default:
}
},
/** /**
* Update src on change of video ID * Set attributes by src string
* @private */
*/ parseFromSrc() {
updateSrc() { var prov = this.get('provider');
var prov = this.get('provider'); var uri = this.parseUri(this.get('src'));
switch (prov) { var qr = uri.query;
case yt: switch (prov) {
this.set('src',this.getYoutubeSrc()); case yt:
break; case vi:
case vi: var videoId = uri.pathname.split('/').pop();
this.set('src',this.getVimeoSrc()); this.set('videoId', videoId);
break; if (qr.autoplay) this.set('autoplay', 1);
} if (qr.loop) this.set('loop', 1);
}, if (parseInt(qr.controls) === 0) this.set('controls', 0);
if (qr.color) this.set('color', qr.color);
break;
default:
}
},
/** /**
* Returns object of attributes for HTML * Update src on change of video ID
* @return {Object} * @private
* @private */
*/ updateSrc() {
getAttrToHTML(...args) { var prov = this.get('provider');
var attr = Component.prototype.getAttrToHTML.apply(this, args); switch (prov) {
var prov = this.get('provider'); case yt:
switch (prov) { this.set('src', this.getYoutubeSrc());
case yt: case vi: break;
break; case vi:
default: this.set('src', this.getVimeoSrc());
if(this.get('loop')) break;
attr.loop = 'loop'; }
if(this.get('autoplay')) },
attr.autoplay = 'autoplay';
if(this.get('controls'))
attr.controls = 'controls';
}
return attr;
},
/** /**
* Update traits by provider * Returns object of attributes for HTML
* @private * @return {Object}
*/ * @private
updateTraits() { */
var prov = this.get('provider'); getAttrToHTML(...args) {
var traits = this.getSourceTraits(); var attr = Component.prototype.getAttrToHTML.apply(this, args);
switch (prov) { var prov = this.get('provider');
case yt: switch (prov) {
this.set('tagName', 'iframe'); case yt:
traits = this.getYoutubeTraits(); case vi:
break; break;
case vi: default:
this.set('tagName', 'iframe'); if (this.get('loop')) attr.loop = 'loop';
traits = this.getVimeoTraits(); if (this.get('autoplay')) attr.autoplay = 'autoplay';
break; if (this.get('controls')) attr.controls = 'controls';
default: }
this.set('tagName', 'video'); return attr;
} },
this.loadTraits(traits);
this.sm.trigger('change:selectedComponent');
},
// Listen provider change and switch traits, in TraitView listen traits change /**
* Update traits by provider
* @private
*/
updateTraits() {
var prov = this.get('provider');
var traits = this.getSourceTraits();
switch (prov) {
case yt:
this.set('tagName', 'iframe');
traits = this.getYoutubeTraits();
break;
case vi:
this.set('tagName', 'iframe');
traits = this.getVimeoTraits();
break;
default:
this.set('tagName', 'video');
}
this.loadTraits(traits);
this.sm.trigger('change:selectedComponent');
},
/** // Listen provider change and switch traits, in TraitView listen traits change
* Return the provider trait
* @return {Object}
* @private
*/
getProviderTrait() {
return {
type: 'select',
label: 'Provider',
name: 'provider',
changeProp: 1,
value: this.get('provider'),
options: [
{value: 'so', name: 'HTML5 Source'},
{value: yt, name: 'Youtube'},
{value: vi, name: 'Vimeo'}
]
};
},
/** /**
* Return traits for the source provider * Return the provider trait
* @return {Array<Object>} * @return {Object}
* @private * @private
*/ */
getSourceTraits() { getProviderTrait() {
return [ return {
this.getProviderTrait(), { type: 'select',
label: 'Source', label: 'Provider',
name: 'src', name: 'provider',
placeholder: 'eg. ./media/video.mp4',
changeProp: 1,
},
this.getAutoplayTrait(),
this.getLoopTrait(),
this.getControlsTrait()];
},
/**
* Return traits for the source provider
* @return {Array<Object>}
* @private
*/
getYoutubeTraits() {
return [
this.getProviderTrait(), {
label: 'Video ID',
name: 'videoId',
placeholder: 'eg. jNQXAC9IVRw',
changeProp: 1, changeProp: 1,
}, value: this.get('provider'),
this.getAutoplayTrait(), options: [
this.getLoopTrait(), { value: 'so', name: 'HTML5 Source' },
this.getControlsTrait() { value: yt, name: 'Youtube' },
]; { value: vi, name: 'Vimeo' }
}, ]
};
},
/** /**
* Return traits for the source provider * Return traits for the source provider
* @return {Array<Object>} * @return {Array<Object>}
* @private * @private
*/ */
getVimeoTraits() { getSourceTraits() {
return [ return [
this.getProviderTrait(), { this.getProviderTrait(),
label: 'Video ID', {
name: 'videoId', label: 'Source',
placeholder: 'eg. 123456789', name: 'src',
changeProp: 1, placeholder: 'eg. ./media/video.mp4',
},{ changeProp: 1
label: 'Color', },
name: 'color', this.getAutoplayTrait(),
placeholder: 'eg. FF0000', this.getLoopTrait(),
changeProp: 1, this.getControlsTrait()
}, ];
this.getAutoplayTrait(), },
this.getLoopTrait(), /**
this.getControlsTrait()]; * Return traits for the source provider
}, * @return {Array<Object>}
* @private
*/
getYoutubeTraits() {
return [
this.getProviderTrait(),
{
label: 'Video ID',
name: 'videoId',
placeholder: 'eg. jNQXAC9IVRw',
changeProp: 1
},
this.getAutoplayTrait(),
this.getLoopTrait(),
this.getControlsTrait()
];
},
/** /**
* Return object trait * Return traits for the source provider
* @return {Object} * @return {Array<Object>}
* @private * @private
*/ */
getAutoplayTrait() { getVimeoTraits() {
return { return [
type: 'checkbox', this.getProviderTrait(),
label: 'Autoplay', {
name: 'autoplay', label: 'Video ID',
changeProp: 1, name: 'videoId',
}; placeholder: 'eg. 123456789',
}, changeProp: 1
},
{
label: 'Color',
name: 'color',
placeholder: 'eg. FF0000',
changeProp: 1
},
this.getAutoplayTrait(),
this.getLoopTrait(),
this.getControlsTrait()
];
},
/** /**
* Return object trait * Return object trait
* @return {Object} * @return {Object}
* @private * @private
*/ */
getLoopTrait() { getAutoplayTrait() {
return { return {
type: 'checkbox', type: 'checkbox',
label: 'Loop', label: 'Autoplay',
name: 'loop', name: 'autoplay',
changeProp: 1, changeProp: 1
}; };
}, },
/** /**
* Return object trait * Return object trait
* @return {Object} * @return {Object}
* @private * @private
*/ */
getControlsTrait() { getLoopTrait() {
return { return {
type: 'checkbox', type: 'checkbox',
label: 'Controls', label: 'Loop',
name: 'controls', name: 'loop',
changeProp: 1, changeProp: 1
}; };
}, },
/**
* Return object trait
* @return {Object}
* @private
*/
getControlsTrait() {
return {
type: 'checkbox',
label: 'Controls',
name: 'controls',
changeProp: 1
};
},
/** /**
* Returns url to youtube video * Returns url to youtube video
* @return {string} * @return {string}
* @private * @private
*/ */
getYoutubeSrc() { getYoutubeSrc() {
var url = this.get('ytUrl'); var url = this.get('ytUrl');
url += this.get('videoId') + '?'; url += this.get('videoId') + '?';
url += this.get('autoplay') ? '&autoplay=1' : ''; url += this.get('autoplay') ? '&autoplay=1' : '';
url += !this.get('controls') ? '&controls=0' : ''; url += !this.get('controls') ? '&controls=0' : '';
url += this.get('loop') ? '&loop=1' : ''; url += this.get('loop') ? '&loop=1' : '';
return url; return url;
}, },
/** /**
* Returns url to vimeo video * Returns url to vimeo video
* @return {string} * @return {string}
* @private * @private
*/ */
getVimeoSrc() { getVimeoSrc() {
var url = this.get('viUrl'); var url = this.get('viUrl');
url += this.get('videoId') + '?'; url += this.get('videoId') + '?';
url += this.get('autoplay') ? '&autoplay=1' : ''; url += this.get('autoplay') ? '&autoplay=1' : '';
url += this.get('loop') ? '&loop=1' : ''; url += this.get('loop') ? '&loop=1' : '';
url += !this.get('controls') ? '&title=0&portrait=0&badge=0' : ''; url += !this.get('controls') ? '&title=0&portrait=0&badge=0' : '';
url += this.get('color') ? '&color=' + this.get('color') : ''; url += this.get('color') ? '&color=' + this.get('color') : '';
return url; return url;
}
}, },
{
},{ /**
* Detect if the passed element is a valid component.
/** * In case the element is valid an object abstracted
* Detect if the passed element is a valid component. * from the element will be returned
* In case the element is valid an object abstracted * @param {HTMLElement}
* from the element will be returned * @return {Object}
* @param {HTMLElement} * @private
* @return {Object} */
* @private isComponent(el) {
*/ var result = '';
isComponent(el) { var isYtProv = /youtube\.com\/embed/.test(el.src);
var result = ''; var isViProv = /player\.vimeo\.com\/video/.test(el.src);
var isYtProv = /youtube\.com\/embed/.test(el.src); var isExtProv = isYtProv || isViProv;
var isViProv = /player\.vimeo\.com\/video/.test(el.src); if (el.tagName == 'VIDEO' || (el.tagName == 'IFRAME' && isExtProv)) {
var isExtProv = isYtProv || isViProv; result = { type: 'video' };
if(el.tagName == 'VIDEO' || if (el.src) result.src = el.src;
(el.tagName == 'IFRAME' && isExtProv) ){ if (isExtProv) {
result = {type: 'video'}; if (isYtProv) result.provider = yt;
if(el.src) else if (isViProv) result.provider = vi;
result.src = el.src; }
if(isExtProv){
if(isYtProv)
result.provider = yt;
else if(isViProv)
result.provider = vi;
} }
return result;
} }
return result; }
}, );
});

51
src/dom_components/model/Components.js

@ -3,50 +3,43 @@ import { isEmpty } from 'underscore';
const Backbone = require('backbone'); const Backbone = require('backbone');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
initialize(models, opt) { initialize(models, opt) {
this.on('add', this.onAdd); this.on('add', this.onAdd);
this.config = opt && opt.config ? opt.config : null; this.config = opt && opt.config ? opt.config : null;
// Inject editor // Inject editor
if(opt && (opt.sm || opt.em)) if (opt && (opt.sm || opt.em)) this.editor = opt.sm || opt.em;
this.editor = opt.sm || opt.em;
this.model = (attrs, options) => { this.model = (attrs, options) => {
var model; var model;
if(!options.sm && opt && opt.sm) if (!options.sm && opt && opt.sm) options.sm = opt.sm;
options.sm = opt.sm;
if(!options.em && opt && opt.em) if (!options.em && opt && opt.em) options.em = opt.em;
options.em = opt.em;
if(opt && opt.config) if (opt && opt.config) options.config = opt.config;
options.config = opt.config;
if(opt && opt.componentTypes) if (opt && opt.componentTypes)
options.componentTypes = opt.componentTypes; options.componentTypes = opt.componentTypes;
var df = opt.componentTypes; var df = opt.componentTypes;
for (var it = 0; it < df.length; it++) { for (var it = 0; it < df.length; it++) {
var dfId = df[it].id; var dfId = df[it].id;
if(dfId == attrs.type) { if (dfId == attrs.type) {
model = df[it].model; model = df[it].model;
break; break;
} }
} }
if(!model) { if (!model) {
// get the last one // get the last one
model = df[df.length - 1].model; model = df[df.length - 1].model;
} }
return new model(attrs, options); return new model(attrs, options);
}; };
}, },
add(models, opt = {}) { add(models, opt = {}) {
@ -57,7 +50,7 @@ module.exports = Backbone.Collection.extend({
var cssc = this.editor.get('CssComposer'); var cssc = this.editor.get('CssComposer');
if (parsed.css && cssc) { if (parsed.css && cssc) {
var {avoidUpdateStyle} = opt; var { avoidUpdateStyle } = opt;
var added = cssc.addCollection(parsed.css, { var added = cssc.addCollection(parsed.css, {
extend: 1, extend: 1,
avoidUpdateStyle avoidUpdateStyle
@ -73,15 +66,19 @@ module.exports = Backbone.Collection.extend({
const style = model.get('style'); const style = model.get('style');
const avoidInline = em && em.getConfig('avoidInlineStyle'); const avoidInline = em && em.getConfig('avoidInlineStyle');
if (!isEmpty(style) && !avoidInline && if (
em && em.get && em.get('Config').forceClass) { !isEmpty(style) &&
var cssC = this.editor.get('CssComposer'); !avoidInline &&
var newClass = this.editor.get('SelectorManager').add(model.cid); em &&
model.set({style:{}}); em.get &&
model.get('classes').add(newClass); em.get('Config').forceClass
var rule = cssC.add(newClass); ) {
rule.set('style', style); var cssC = this.editor.get('CssComposer');
var newClass = this.editor.get('SelectorManager').add(model.cid);
model.set({ style: {} });
model.get('classes').add(newClass);
var rule = cssC.add(newClass);
rule.set('style', style);
} }
}, }
}); });

2
src/dom_components/model/Toolbar.js

@ -1,4 +1,4 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
var ToolbarButton = require('./ToolbarButton'); var ToolbarButton = require('./ToolbarButton');
module.exports = Backbone.Collection.extend({model: ToolbarButton}); module.exports = Backbone.Collection.extend({ model: ToolbarButton });

8
src/dom_components/model/ToolbarButton.js

@ -1,10 +1,8 @@
var Backbone = require('backbone'); var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: { defaults: {
command: '', command: '',
attributes: {}, attributes: {}
}, }
}); });

16
src/dom_components/view/ComponentImageView.js

@ -2,12 +2,11 @@ var Backbone = require('backbone');
var ComponentView = require('./ComponentView'); var ComponentView = require('./ComponentView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
tagName: 'img', tagName: 'img',
events: { events: {
'dblclick': 'openModal', dblclick: 'openModal',
'click': 'initResize', click: 'initResize'
}, },
initialize(o) { initialize(o) {
@ -21,19 +20,17 @@ module.exports = ComponentView.extend({
config.am && (this.am = config.am); config.am && (this.am = config.am);
}, },
/** /**
* Update src attribute * Update src attribute
* @private * @private
* */ * */
updateSrc() { updateSrc() {
const src = this.model.get("src"); const src = this.model.get('src');
const el = this.$el; const el = this.$el;
el.attr('src', src); el.attr('src', src);
el[src ? 'removeClass' : 'addClass'](this.classEmpty); el[src ? 'removeClass' : 'addClass'](this.classEmpty);
}, },
/** /**
* Open dialog for image changing * Open dialog for image changing
* @param {Object} e Event * @param {Object} e Event
@ -43,7 +40,7 @@ module.exports = ComponentView.extend({
var em = this.opts.config.em; var em = this.opts.config.em;
var editor = em ? em.get('Editor') : ''; var editor = em ? em.get('Editor') : '';
if(editor && this.model.get('editable')) { if (editor && this.model.get('editable')) {
editor.runCommand('open-assets', { editor.runCommand('open-assets', {
target: this.model, target: this.model,
onSelect() { onSelect() {
@ -54,17 +51,16 @@ module.exports = ComponentView.extend({
} }
}, },
render() { render() {
this.updateAttributes(); this.updateAttributes();
this.updateClasses(); this.updateClasses();
var actCls = this.$el.attr('class') || ''; var actCls = this.$el.attr('class') || '';
if(!this.model.get('src')) if (!this.model.get('src'))
this.$el.attr('class', (actCls + ' ' + this.classEmpty).trim()); this.$el.attr('class', (actCls + ' ' + this.classEmpty).trim());
// Avoid strange behaviours while try to drag // Avoid strange behaviours while try to drag
this.$el.attr('onmousedown', 'return false'); this.$el.attr('onmousedown', 'return false');
return this; return this;
}, }
}); });

4
src/dom_components/view/ComponentLinkView.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var ComponentView = require('./ComponentTextView'); var ComponentView = require('./ComponentTextView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
render(...args) { render(...args) {
ComponentView.prototype.render.apply(this, args); ComponentView.prototype.render.apply(this, args);
@ -11,6 +10,5 @@ module.exports = ComponentView.extend({
this.el.addEventListener('click', this.prevDef, true); this.el.addEventListener('click', this.prevDef, true);
return this; return this;
}, }
}); });

8
src/dom_components/view/ComponentMapView.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var ComponentView = require('./ComponentImageView'); var ComponentView = require('./ComponentImageView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
tagName: 'div', tagName: 'div',
events: {}, events: {},
@ -21,8 +20,8 @@ module.exports = ComponentView.extend({
}, },
getIframe() { getIframe() {
if(!this.iframe){ if (!this.iframe) {
var ifrm = document.createElement("iframe"); var ifrm = document.createElement('iframe');
ifrm.src = this.model.get('src'); ifrm.src = this.model.get('src');
ifrm.frameBorder = 0; ifrm.frameBorder = 0;
ifrm.style.height = '100%'; ifrm.style.height = '100%';
@ -38,6 +37,5 @@ module.exports = ComponentView.extend({
this.updateClasses(); this.updateClasses();
this.el.appendChild(this.getIframe()); this.el.appendChild(this.getIframe());
return this; return this;
}, }
}); });

41
src/dom_components/view/ComponentScriptView.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var ComponentView = require('./ComponentImageView'); var ComponentView = require('./ComponentImageView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
tagName: 'script', tagName: 'script',
events: {}, events: {},
@ -15,20 +14,35 @@ module.exports = ComponentView.extend({
var content = ''; var content = '';
// If it's an external script // If it's an external script
if(src) { if (src) {
var onload = model.get('onload'); var onload = model.get('onload');
var svar = 'script' + scriptCount; var svar = 'script' + scriptCount;
var svarNext = 'script' + (scriptCount + 1); var svarNext = 'script' + (scriptCount + 1);
content = "var "+svar+" = document.createElement('script');\n" + content =
svar+".onload = function(){\n" + 'var ' +
(onload ? onload + "();\n" : '') + svar +
"typeof "+svarNext+"Start == 'function' && "+svarNext+"Start();\n" + " = document.createElement('script');\n" +
"};\n" + svar +
svar+".src = '" + src + "';\n"+ '.onload = function(){\n' +
"function "+svar+"Start() { document.body.appendChild("+svar+"); };\n" + (onload ? onload + '();\n' : '') +
(!scriptCount ? svar+"Start();" : ''); 'typeof ' +
if(em){ svarNext +
em.set('scriptCount', scriptCount + 1); "Start == 'function' && " +
svarNext +
'Start();\n' +
'};\n' +
svar +
".src = '" +
src +
"';\n" +
'function ' +
svar +
'Start() { document.body.appendChild(' +
svar +
'); };\n' +
(!scriptCount ? svar + 'Start();' : '');
if (em) {
em.set('scriptCount', scriptCount + 1);
} }
} else { } else {
content = model.get('content'); content = model.get('content');
@ -36,6 +50,5 @@ module.exports = ComponentView.extend({
this.el.innerHTML = content; this.el.innerHTML = content;
return this; return this;
}, }
}); });

2
src/dom_components/view/ComponentSvgView.js

@ -1,9 +1,7 @@
const ComponentView = require('./ComponentView'); const ComponentView = require('./ComponentView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
_createElement: function(tagName) { _createElement: function(tagName) {
return document.createElementNS('http://www.w3.org/2000/svg', tagName); return document.createElementNS('http://www.w3.org/2000/svg', tagName);
} }
}); });

2
src/dom_components/view/ComponentTableView.js

@ -2,5 +2,5 @@ var Backbone = require('backbone');
var ComponentView = require('./ComponentView'); var ComponentView = require('./ComponentView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
events: {}, events: {}
}); });

16
src/dom_components/view/ComponentTextView.js

@ -1,11 +1,10 @@
import {on, off} from 'utils/mixins' import { on, off } from 'utils/mixins';
const ComponentView = require('./ComponentView'); const ComponentView = require('./ComponentView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
events: { events: {
'dblclick': 'enableEditing', dblclick: 'enableEditing'
}, },
initialize(o) { initialize(o) {
@ -76,10 +75,10 @@ module.exports = ComponentView.extend({
removable: 0, removable: 0,
draggable: 0, draggable: 0,
copyable: 0, copyable: 0,
toolbar: '', toolbar: ''
}) });
model.get('components').each(model => clean(model)); model.get('components').each(model => clean(model));
} };
// Avoid re-render on reset with silent option // Avoid re-render on reset with silent option
model.trigger('change:content', model); model.trigger('change:content', model);
@ -108,7 +107,7 @@ module.exports = ComponentView.extend({
*/ */
toggleEvents(enable) { toggleEvents(enable) {
var method = enable ? 'on' : 'off'; var method = enable ? 'on' : 'off';
const mixins = {on, off}; const mixins = { on, off };
// The ownerDocument is from the frame // The ownerDocument is from the frame
var elDocs = [this.el.ownerDocument, document]; var elDocs = [this.el.ownerDocument, document];
@ -118,6 +117,5 @@ module.exports = ComponentView.extend({
// Avoid closing edit mode on component click // Avoid closing edit mode on component click
this.$el.off('mousedown', this.disablePropagation); this.$el.off('mousedown', this.disablePropagation);
this.$el[method]('mousedown', this.disablePropagation); this.$el[method]('mousedown', this.disablePropagation);
}, }
}); });

13
src/dom_components/view/ComponentVideoView.js

@ -3,7 +3,6 @@ var ComponentView = require('./ComponentImageView');
var OComponentView = require('./ComponentView'); var OComponentView = require('./ComponentView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
tagName: 'div', tagName: 'div',
events: {}, events: {},
@ -11,7 +10,11 @@ module.exports = ComponentView.extend({
initialize(o) { initialize(o) {
OComponentView.prototype.initialize.apply(this, arguments); OComponentView.prototype.initialize.apply(this, arguments);
this.listenTo(this.model, 'change:src', this.updateSrc); this.listenTo(this.model, 'change:src', this.updateSrc);
this.listenTo(this.model, 'change:loop change:autoplay change:controls change:color', this.updateVideo); this.listenTo(
this.model,
'change:loop change:autoplay change:controls change:color',
this.updateVideo
);
this.listenTo(this.model, 'change:provider', this.updateProvider); this.listenTo(this.model, 'change:provider', this.updateProvider);
}, },
@ -52,7 +55,8 @@ module.exports = ComponentView.extend({
var videoEl = this.videoEl; var videoEl = this.videoEl;
var md = this.model; var md = this.model;
switch (prov) { switch (prov) {
case 'yt': case 'vi': case 'yt':
case 'vi':
this.model.trigger('change:videoId'); this.model.trigger('change:videoId');
break; break;
default: default:
@ -115,6 +119,5 @@ module.exports = ComponentView.extend({
var prov = this.model.get('provider'); var prov = this.model.get('provider');
this.el.appendChild(this.renderByProvider(prov)); this.el.appendChild(this.renderByProvider(prov));
return this; return this;
}, }
}); });

59
src/dom_components/view/ComponentView.js

@ -3,7 +3,6 @@ import { isArray } from 'underscore';
const ComponentsView = require('./ComponentsView'); const ComponentsView = require('./ComponentsView');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
className() { className() {
return this.getClasses(); return this.getClasses();
}, },
@ -64,7 +63,6 @@ module.exports = Backbone.View.extend({
} }
}, },
/** /**
* Import, if possible, classes inside main container * Import, if possible, classes inside main container
* @private * @private
@ -72,14 +70,13 @@ module.exports = Backbone.View.extend({
importClasses() { importClasses() {
var clm = this.config.em.get('SelectorManager'); var clm = this.config.em.get('SelectorManager');
if(clm){ if (clm) {
this.model.get('classes').each(m => { this.model.get('classes').each(m => {
clm.add(m.get('name')); clm.add(m.get('name'));
}); });
} }
}, },
/** /**
* Fires on state update. If the state is not empty will add a helper class * Fires on state update. If the state is not empty will add a helper class
* @param {Event} e * @param {Event} e
@ -89,14 +86,13 @@ module.exports = Backbone.View.extend({
var cl = 'hc-state'; var cl = 'hc-state';
var state = this.model.get('state'); var state = this.model.get('state');
if(state){ if (state) {
this.$el.addClass(cl); this.$el.addClass(cl);
}else{ } else {
this.$el.removeClass(cl); this.$el.removeClass(cl);
} }
}, },
/** /**
* Update item on status change * Update item on status change
* @param {Event} e * @param {Event} e
@ -114,17 +110,19 @@ module.exports = Backbone.View.extend({
var cls = ''; var cls = '';
switch (status) { switch (status) {
case 'selected': case 'selected':
cls = `${actualCls} ${selectedCls}`; cls = `${actualCls} ${selectedCls}`;
break; break;
case 'selected-parent': case 'selected-parent':
cls = `${actualCls} ${selectedParentCls}`; cls = `${actualCls} ${selectedParentCls}`;
break; break;
case 'freezed': case 'freezed':
cls = `${actualCls} ${freezedCls}`; cls = `${actualCls} ${freezedCls}`;
break; break;
default: default:
this.$el.removeClass(`${selectedCls} ${selectedParentCls} ${freezedCls}`); this.$el.removeClass(
`${selectedCls} ${selectedParentCls} ${freezedCls}`
);
} }
cls = cls.trim(); cls = cls.trim();
@ -134,7 +132,6 @@ module.exports = Backbone.View.extend({
} }
}, },
/** /**
* Update highlight attribute * Update highlight attribute
* @private * @private
@ -144,7 +141,6 @@ module.exports = Backbone.View.extend({
this.setAttribute('data-highlightable', hl ? 1 : ''); this.setAttribute('data-highlightable', hl ? 1 : '');
}, },
/** /**
* Update style attribute * Update style attribute
* @private * @private
@ -161,13 +157,15 @@ module.exports = Backbone.View.extend({
} }
}, },
/** /**
* Update classe attribute * Update classe attribute
* @private * @private
* */ * */
updateClasses() { updateClasses() {
const str = this.model.get('classes').pluck('name').join(' '); const str = this.model
.get('classes')
.pluck('name')
.join(' ');
this.setAttribute('class', str); this.setAttribute('class', str);
// Regenerate status class // Regenerate status class
@ -192,8 +190,8 @@ module.exports = Backbone.View.extend({
* @private * @private
* */ * */
getClasses() { getClasses() {
var attr = this.model.get("attributes"), var attr = this.model.get('attributes'),
classes = attr['class'] || []; classes = attr['class'] || [];
classes = isArray(classes) ? classes : [classes]; classes = isArray(classes) ? classes : [classes];
if (classes.length) { if (classes.length) {
@ -209,7 +207,7 @@ module.exports = Backbone.View.extend({
* */ * */
updateAttributes() { updateAttributes() {
const model = this.model; const model = this.model;
const attrs = {} const attrs = {};
const attr = model.get('attributes'); const attr = model.get('attributes');
const src = model.get('src'); const src = model.get('src');
@ -250,7 +248,7 @@ module.exports = Backbone.View.extend({
} }
var em = this.em; var em = this.em;
if(em) { if (em) {
var canvas = em.get('Canvas'); var canvas = em.get('Canvas');
canvas.getCanvasView().updateScript(this); canvas.getCanvasView().updateScript(this);
} }
@ -301,14 +299,14 @@ module.exports = Backbone.View.extend({
const view = new ComponentsView({ const view = new ComponentsView({
collection: this.model.get('components'), collection: this.model.get('components'),
config: this.config, config: this.config,
componentTypes: this.opts.componentTypes, componentTypes: this.opts.componentTypes
}); });
view.render(container); view.render(container);
this.childrenView = view; this.childrenView = view;
const childNodes = Array.prototype.slice.call(view.el.childNodes); const childNodes = Array.prototype.slice.call(view.el.childNodes);
for (var i = 0, len = childNodes.length ; i < len; i++) { for (var i = 0, len = childNodes.length; i < len; i++) {
container.appendChild(childNodes.shift()); container.appendChild(childNodes.shift());
} }
@ -341,6 +339,5 @@ module.exports = Backbone.View.extend({
this.renderChildren(); this.renderChildren();
this.updateScript(); this.updateScript();
return this; return this;
}, }
}); });

25
src/dom_components/view/ComponentsView.js

@ -1,7 +1,6 @@
import { isUndefined } from 'underscore' import { isUndefined } from 'underscore';
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
initialize(o) { initialize(o) {
this.opts = o || {}; this.opts = o || {};
this.config = o.config || {}; this.config = o.config || {};
@ -38,10 +37,9 @@ module.exports = Backbone.View.extend({
* @private * @private
* */ * */
addToCollection(model, fragmentEl, index) { addToCollection(model, fragmentEl, index) {
if(!this.compView) if (!this.compView) this.compView = require('./ComponentView');
this.compView = require('./ComponentView'); var fragment = fragmentEl || null,
var fragment = fragmentEl || null, viewObject = this.compView;
viewObject = this.compView;
var dt = this.opts.componentTypes; var dt = this.opts.componentTypes;
@ -49,7 +47,7 @@ module.exports = Backbone.View.extend({
for (var it = 0; it < dt.length; it++) { for (var it = 0; it < dt.length; it++) {
var dtId = dt[it].id; var dtId = dt[it].id;
if(dtId == type) { if (dtId == type) {
viewObject = dt[it].view; viewObject = dt[it].view;
break; break;
} }
@ -59,16 +57,16 @@ module.exports = Backbone.View.extend({
var view = new viewObject({ var view = new viewObject({
model, model,
config: this.config, config: this.config,
componentTypes: dt, componentTypes: dt
}); });
var rendered = view.render().el; var rendered = view.render().el;
if(view.model.get('type') == 'textnode') if (view.model.get('type') == 'textnode')
rendered = document.createTextNode(view.model.get('content')); rendered = document.createTextNode(view.model.get('content'));
if (fragment) { if (fragment) {
fragment.appendChild(rendered); fragment.appendChild(rendered);
} else { } else {
const parent = this.parentEl; const parent = this.parentEl;
const children = parent.childNodes; const children = parent.childNodes;
if (!isUndefined(index)) { if (!isUndefined(index)) {
@ -102,11 +100,10 @@ module.exports = Backbone.View.extend({
render(parent) { render(parent) {
const el = this.el; const el = this.el;
const frag = document.createDocumentFragment(); const frag = document.createDocumentFragment();
this.parentEl = parent || this.el; this.parentEl = parent || this.el;
this.collection.each(model => this.addToCollection(model, frag)); this.collection.each(model => this.addToCollection(model, frag));
el.innerHTML = ''; el.innerHTML = '';
el.appendChild(frag); el.appendChild(frag);
return this; return this;
} }
}); });

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save