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=",
"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": {
"version": "2.1.1",
"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-loader": "^7.0.0",
"babel-plugin-transform-object-rest-spread": "^6.26.0",
"promise-polyfill": "^6.0.2",
"babel-preset-env": "^1.6.1",
"chai": "^4.1.2",
"cross-env": "^5.0.5",
@ -37,6 +36,8 @@
"jsdom": "^11.2.0",
"mocha": "^3.1.2",
"node-sass": "^4.5.3",
"prettier": "1.10.1",
"promise-polyfill": "^6.0.2",
"sinon": "^3.2.1",
"string-replace-loader": "^1.3.0",
"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",
"v:patch": "npm version --no-git-tag-version patch",
"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:dev": "npm test -- -R min -w"
}

21
src/asset_manager/index.js

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

16
src/asset_manager/model/Asset.js

@ -1,10 +1,9 @@
module.exports = require('backbone').Model.extend({
idAttribute: 'src',
defaults: {
type: '',
src: '',
type: '',
src: ''
},
/**
@ -13,7 +12,9 @@ module.exports = require('backbone').Model.extend({
* @private
* */
getFilename() {
return this.get('src').split('/').pop();
return this.get('src')
.split('/')
.pop();
},
/**
@ -22,7 +23,8 @@ module.exports = require('backbone').Model.extend({
* @private
* */
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');
module.exports = Asset.extend({
defaults: { ...Asset.prototype.defaults,
defaults: {
...Asset.prototype.defaults,
type: 'image',
unitDim: 'px',
height: 0,
width: 0,
},
width: 0
}
});

30
src/asset_manager/model/Assets.js

@ -1,18 +1,22 @@
import TypeableCollection from 'domain_abstract/model/TypeableCollection';
module.exports = require('backbone').Collection.extend(TypeableCollection).extend({
types: [{
id: 'image',
model: require('./AssetImage'),
view: require('./../view/AssetImageView'),
isType(value) {
if (typeof value == 'string') {
return {
type: 'image',
src: value,
module.exports = require('backbone')
.Collection.extend(TypeableCollection)
.extend({
types: [
{
id: 'image',
model: require('./AssetImage'),
view: require('./../view/AssetImageView'),
isType(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({
events: {
'click [data-toggle=asset-remove]': 'onRemove',
click: 'onClick',
dblclick: 'onDblClick',
dblclick: 'onDblClick'
},
getPreview() {
@ -32,7 +31,7 @@ module.exports = require('./AssetView').extend({
init(o) {
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({
initialize(o = {}) {
this.options = o;
this.collection = o.collection;
@ -55,5 +54,5 @@ module.exports = Backbone.View.extend({
el.innerHTML = this.template(this, this.model);
el.className = this.className;
return this;
},
}
});

13
src/asset_manager/view/AssetsView.js

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

587
src/asset_manager/view/FileUploader.js

@ -1,8 +1,8 @@
import fetch from 'utils/fetch';
module.exports = Backbone.View.extend({
template: _.template(`
module.exports = Backbone.View.extend(
{
template: _.template(`
<form>
<div id="<%= pfx %>title"><%= title %></div>
<input type="file" id="<%= uploadId %>" name="file" accept="image/*" <%= disabled ? 'disabled' : '' %> multiple/>
@ -10,307 +10,318 @@ module.exports = Backbone.View.extend({
</form>
`),
events: {},
initialize(opts = {}) {
this.options = opts;
const c = opts.config || {};
this.config = c;
this.pfx = c.stylePrefix || '';
this.ppfx = c.pStylePrefix || '';
this.target = this.options.globalCollection || {};
this.uploadId = this.pfx + 'uploadFile';
this.disabled = c.disableUpload !== undefined ? c.disableUpload : !c.upload && !c.embedAsBase64;
this.events['change #' + this.uploadId] = 'uploadFile';
let uploadFile = c.uploadFile;
if (uploadFile) {
this.uploadFile = uploadFile.bind(this);
} else if (c.embedAsBase64) {
this.uploadFile = this.constructor.embedAsBase64;
}
this.delegateEvents();
},
/**
* 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);
},
events: {},
initialize(opts = {}) {
this.options = opts;
const c = opts.config || {};
this.config = c;
this.pfx = c.stylePrefix || '';
this.ppfx = c.pStylePrefix || '';
this.target = this.options.globalCollection || {};
this.uploadId = this.pfx + 'uploadFile';
this.disabled =
c.disableUpload !== undefined
? c.disableUpload
: !c.upload && !c.embedAsBase64;
this.events['change #' + this.uploadId] = 'uploadFile';
let uploadFile = c.uploadFile;
if (uploadFile) {
this.uploadFile = uploadFile.bind(this);
} else if (c.embedAsBase64) {
this.uploadFile = this.constructor.embedAsBase64;
}
/**
* 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]);
}
this.delegateEvents();
},
/**
* 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 });
}
for (let param in params) {
body.append(param, params[param]);
}
this.onUploadEnd(text);
},
/**
* 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;
const url = config.upload;
const headers = config.headers;
const reqHead = 'X-Requested-With';
for (let param in params) {
body.append(param, params[param]);
}
if (typeof headers[reqHead] == 'undefined') {
headers[reqHead] = 'XMLHttpRequest';
}
var target = this.target;
const url = config.upload;
const headers = config.headers;
const reqHead = 'X-Requested-With';
if (url) {
this.onUploadStart();
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;
};
if (typeof headers[reqHead] == 'undefined') {
headers[reqHead] = 'XMLHttpRequest';
}
}
},
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;
if (url) {
this.onUploadStart();
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));
}
return false;
};
const onDragLeave = () => {
cleanEditorElCls();
return false;
};
const onDrop = (e) => {
},
/**
* 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) {
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();
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);
}
if ('draggable' in edEl) {
[edEl, frameEl].forEach(item => {
item.ondragover = onDragOver;
item.ondragleave = onDragLeave;
item.ondrop = onDrop;
});
}
return false;
};
ev.$el.append(`<div class="${dropzoneCls}">${c.dropzoneContent}</div>`);
cleanEditorElCls();
if ('draggable' in edEl) {
[edEl, frameEl].forEach((item) => {
item.ondragover = onDragOver;
item.ondragleave = onDragLeave;
item.ondrop = onDrop;
});
},
render() {
this.$el.html(
this.template({
title: this.config.uploadText,
uploadId: this.uploadId,
disabled: this.disabled,
pfx: this.pfx
})
);
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() {
this.$el.html( this.template({
title: this.config.uploadText,
uploadId: this.uploadId,
disabled: this.disabled,
pfx: this.pfx
}) );
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;
}
const promises = [];
const mimeTypeMatcher = /^(.+)\/(.+)$/;
for (const file of files) {
// 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 reader = new FileReader();
reader.addEventListener('load', (event) => {
let type;
const name = file.name;
// Try to find the MIME type of the file.
const match = mimeTypeMatcher.exec(file.type);
if (match) {
type = match[1]; // The first part in the MIME, "image" in image/png
} else {
type = file.type;
}
// If it's an image, try to find its size
if (type === 'image') {
const data = {
src: reader.result,
name,
type,
height: 0,
width: 0
};
const image = new Image();
image.addEventListener('error', (error) => {
reject(error);
});
image.addEventListener('load', () => {
data.height = image.height;
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');
const promises = [];
const mimeTypeMatcher = /^(.+)\/(.+)$/;
for (const file of files) {
// 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 reader = new FileReader();
reader.addEventListener('load', event => {
let type;
const name = file.name;
// Try to find the MIME type of the file.
const match = mimeTypeMatcher.exec(file.type);
if (match) {
type = match[1]; // The first part in the MIME, "image" in image/png
} else {
type = file.type;
}
// If it's an image, try to find its size
if (type === 'image') {
const data = {
src: reader.result,
name,
type,
height: 0,
width: 0
};
const image = new Image();
image.addEventListener('error', error => {
reject(error);
});
image.addEventListener('load', () => {
data.height = image.height;
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);
});
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 = {
blocks: [],
appendTo: '',
appendTo: ''
};

382
src/block_manager/index.js

@ -30,201 +30,201 @@
*/
module.exports = () => {
var c = {},
defaults = require('./config/config'),
Blocks = require('./model/Blocks'),
BlockCategories = require('./model/Categories'),
BlocksView = require('./view/BlocksView');
defaults = require('./config/config'),
Blocks = require('./model/Blocks'),
BlockCategories = require('./model/Categories'),
BlocksView = require('./view/BlocksView');
var blocks, blocksVisible, blocksView;
var categories = [];
return {
/**
* Name of the module
* @type {String}
* @private
*/
name: 'BlockManager',
/**
* Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
* @return {this}
* @private
*/
init(config) {
c = config || {};
const em = c.em;
for (let name in defaults) {
if (!(name in c)) {
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;
/**
* Name of the module
* @type {String}
* @private
*/
name: 'BlockManager',
/**
* Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
* @return {this}
* @private
*/
init(config) {
c = config || {};
const em = c.em;
for (let name in defaults) {
if (!(name in c)) {
c[name] = defaults[name];
}
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');
module.exports = Backbone.Model.extend({
defaults: {
label: '',
content: '',
category: '',
attributes: {},
attributes: {}
},
initialize(opts = {}) {
@ -17,10 +16,9 @@ module.exports = Backbone.Model.extend({
if (typeof category == 'string') {
var catObj = new 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');
module.exports = Backbone.Collection.extend({
model: Block,
model: Block
});

2
src/block_manager/model/Categories.js

@ -1,5 +1,5 @@
var Backbone = require('backbone');
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');
module.exports = Backbone.Model.extend({
defaults: {
id: '',
label: '',
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({
events: {
mousedown: 'startDrag'
},
@ -23,7 +22,7 @@ module.exports = Backbone.View.extend({
return;
}
if(!this.config.getSorter) {
if (!this.config.getSorter) {
return;
}
@ -56,8 +55,9 @@ module.exports = Backbone.View.extend({
const pfx = this.ppfx;
const className = `${pfx}block`;
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;
},
}
});

47
src/block_manager/view/BlocksView.js

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

13
src/block_manager/view/CategoryView.js

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

4
src/canvas/config/config.js

@ -1,5 +1,4 @@
module.exports = {
stylePrefix: 'cv-',
// Coming soon
@ -31,6 +30,5 @@ module.exports = {
* 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 = () => {
var c = {},
defaults = require('./config/config'),
Canvas = require('./model/Canvas'),
CanvasView = require('./view/CanvasView');
defaults = require('./config/config'),
Canvas = require('./model/Canvas'),
CanvasView = require('./view/CanvasView');
var canvas;
var frameRect;
return {
/**
* Used inside RTE
* @private
@ -32,23 +31,20 @@ module.exports = () => {
init(config) {
c = config || {};
for (var name in defaults) {
if (!(name in c))
c[name] = defaults[name];
if (!(name in c)) c[name] = defaults[name];
}
var ppfx = c.pStylePrefix;
if(ppfx)
c.stylePrefix = ppfx + c.stylePrefix;
if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
canvas = new Canvas(config);
CanvasView = new CanvasView({
CanvasView = new CanvasView({
model: canvas,
config: c,
config: c
});
var cm = c.em.get('DomComponents');
if(cm)
this.setWrapper(cm);
if (cm) this.setWrapper(cm);
this.startAutoscroll = this.startAutoscroll.bind(this);
this.stopAutoscroll = this.stopAutoscroll.bind(this);
@ -200,11 +196,11 @@ module.exports = () => {
},
/**
* Get the offset of the element
* @param {HTMLElement} el
* @return {Object}
* @private
*/
* Get the offset of the element
* @param {HTMLElement} el
* @return {Object}
* @private
*/
offset(el) {
return CanvasView.offset(el);
},
@ -257,11 +253,11 @@ module.exports = () => {
var elTop = pos.top - targetHeight;
var elLeft = pos.left;
elLeft += toRight ? pos.width : 0;
elLeft = toRight ? (elLeft - targetWidth) : elLeft;
elLeft = toRight ? elLeft - targetWidth : elLeft;
var leftPos = elLeft < canvasPos.left ? canvasPos.left : elLeft;
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 = {
top: topPos,
@ -273,11 +269,11 @@ module.exports = () => {
targetWidth: target.offsetWidth,
targetHeight: target.offsetHeight,
canvasTop: canvasPos.top,
canvasLeft: canvasPos.left,
canvasLeft: canvasPos.left
};
// 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);
}
@ -311,7 +307,7 @@ module.exports = () => {
return {
y: e.clientY + addTop - yOffset,
x: e.clientX + addLeft - xOffset,
x: e.clientX + addLeft - xOffset
};
},
@ -331,7 +327,7 @@ module.exports = () => {
return {
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;
if (clientY < limitTop) {
nextTop -= (limitTop - clientY);
nextTop -= limitTop - clientY;
}
if (clientY > limitBottom) {
nextTop += (clientY - limitBottom);
nextTop += clientY - limitBottom;
}
//console.log(`actualTop: ${actualTop} clientY: ${clientY} nextTop: ${nextTop} frameHeigh: ${frameRect.height}`);
@ -404,6 +400,6 @@ module.exports = () => {
*/
getFrameWrapperEl() {
return CanvasView.frame.getWrapper();
},
}
};
};

8
src/canvas/model/Canvas.js

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

8
src/canvas/model/Frame.js

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

80
src/canvas/view/CanvasView.js

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

2
src/code_manager/config/config.js

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

42
src/code_manager/index.js

@ -18,23 +18,21 @@
* @module CodeManager
*/
module.exports = () => {
var c = {},
defaults = require('./config/config'),
gHtml = require('./model/HtmlGenerator'),
gCss = require('./model/CssGenerator'),
gJson = require('./model/JsonGenerator'),
gJs = require('./model/JsGenerator'),
eCM = require('./model/CodeMirrorEditor'),
editorView = require('./view/EditorView');
defaults = require('./config/config'),
gHtml = require('./model/HtmlGenerator'),
gCss = require('./model/CssGenerator'),
gJson = require('./model/JsonGenerator'),
gJs = require('./model/JsGenerator'),
eCM = require('./model/CodeMirrorEditor'),
editorView = require('./view/EditorView');
var generators = {},
defGenerators = {},
viewers = {},
defViewers = {};
defGenerators = {},
viewers = {},
defViewers = {};
return {
getConfig() {
return c;
},
@ -57,16 +55,14 @@ module.exports = () => {
init(config) {
c = config || {};
for (var name in defaults) {
if (!(name in c))
c[name] = defaults[name];
if (!(name in c)) c[name] = defaults[name];
}
var ppfx = c.pStylePrefix;
if(ppfx)
c.stylePrefix = ppfx + c.stylePrefix;
if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
defGenerators.html = new gHtml();
defGenerators.css = new gCss();
defGenerators.css = new gCss();
defGenerators.json = new gJson();
defGenerators.js = new gJs();
defViewers.CodeMirror = new eCM();
@ -183,7 +179,7 @@ module.exports = () => {
* */
getCode(model, genId, opt = {}) {
opt.em = c.em;
var generator = this.getGenerator(genId);
var generator = this.getGenerator(genId);
return generator ? generator.build(model, opt) : '';
},
@ -193,8 +189,7 @@ module.exports = () => {
* @private
* */
loadDefaultGenerators() {
for (var id in defGenerators)
this.addGenerator(id, defGenerators[id]);
for (var id in defGenerators) this.addGenerator(id, defGenerators[id]);
return this;
},
@ -205,12 +200,9 @@ module.exports = () => {
* @private
* */
loadDefaultViewers() {
for (var id in defViewers)
this.addViewer(id, defViewers[id]);
for (var id in defViewers) this.addViewer(id, defViewers[id]);
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');
module.exports = Backbone.Model.extend({
defaults: {
input : '',
label : '',
codeName : '',
theme : '',
readOnly : true,
lineNumbers : true,
input: '',
label: '',
codeName: '',
theme: '',
readOnly: true,
lineNumbers: true
},
/** @inheritdoc */
init(el) {
this.editor = CodeMirror.fromTextArea(el, {
this.editor = CodeMirror.fromTextArea(el, {
dragDrop: false,
lineWrapping: true,
mode: this.get('codeName'),
...this.attributes,
...this.attributes
});
return this;
@ -29,14 +28,15 @@ module.exports = Backbone.Model.extend({
/** @inheritdoc */
setContent(v) {
if(!this.editor)
return;
if (!this.editor) return;
this.editor.setValue(v);
if(this.editor.autoFormatRange){
if (this.editor.autoFormatRange) {
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);
}
},
}
});

12
src/code_manager/model/CssGenerator.js

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

7
src/code_manager/model/HtmlGenerator.js

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

21
src/code_manager/model/JsGenerator.js

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

34
src/code_manager/model/JsonGenerator.js

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

8
src/code_manager/view/EditorView.js

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

3
src/commands/config/config.js

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

6
src/commands/model/Command.js

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

4
src/commands/model/Commands.js

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

68
src/commands/view/CreateComponent.js

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

44
src/commands/view/DeleteComponent.js

@ -1,17 +1,17 @@
const SelectComponent = require('./SelectComponent');
const $ = Backbone.$;
module.exports = _.extend({},SelectComponent,{
module.exports = _.extend({}, SelectComponent, {
init(o) {
_.bindAll(this, 'startDelete', 'stopDelete', 'onDelete');
this.hoverClass = this.pfx + 'hover-delete';
this.badgeClass = this.pfx + 'badge-red';
this.hoverClass = this.pfx + 'hover-delete';
this.badgeClass = this.pfx + 'badge-red';
},
enable() {
var that = this;
this.$el.find('*')
this.$el
.find('*')
.mouseover(this.startDelete)
.mouseout(this.stopDelete)
.click(this.onDelete);
@ -23,15 +23,14 @@ module.exports = _.extend({},SelectComponent,{
* @private
*/
startDelete(e) {
e.stopPropagation();
var $this = $(e.target);
// Show badge if possible
if($this.data('model').get('removable')){
$this.addClass(this.hoverClass);
this.attachBadge($this.get(0));
}
e.stopPropagation();
var $this = $(e.target);
// 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
*/
stopDelete(e) {
e.stopPropagation();
var $this = $(e.target);
$this.removeClass(this.hoverClass);
e.stopPropagation();
var $this = $(e.target);
$this.removeClass(this.hoverClass);
// Hide badge if possible
if(this.badge)
this.badge.css({ left: -1000, top:-1000 });
// Hide badge if possible
if (this.badge) this.badge.css({ left: -1000, top: -1000 });
},
/**
@ -59,8 +57,7 @@ module.exports = _.extend({},SelectComponent,{
var $this = $(e.target);
// Do nothing in case can't remove
if(!$this.data('model').get('removable'))
return;
if (!$this.data('model').get('removable')) return;
$this.data('model').destroy();
this.removeBadge();
@ -73,7 +70,6 @@ module.exports = _.extend({},SelectComponent,{
* @private
* */
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 = {
run(editor, sender, opts) {
var el = (opts && opts.el) || '';
var canvas = editor.Canvas;
@ -11,7 +10,7 @@ module.exports = {
options.posFetcher = canvasView.getElementPos.bind(canvasView);
// Create the resizer for the canvas if not yet created
if(!dragger) {
if (!dragger) {
dragger = editor.Utils.Dragger.init(options);
this.dragger = dragger;
}
@ -27,8 +26,6 @@ module.exports = {
},
stop() {
if(this.canvasResizer)
this.canvasResizer.blur();
},
if (this.canvasResizer) this.canvasResizer.blur();
}
};

6
src/commands/view/ExportTemplate.js

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

46
src/commands/view/Fullscreen.js

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

14
src/commands/view/ImageComponent.js

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

15
src/commands/view/InsertCustom.js

@ -2,7 +2,6 @@ var Backbone = require('backbone');
var CreateComponent = require('./CreateComponent');
module.exports = _.extend({}, CreateComponent, {
init(...args) {
CreateComponent.init.apply(this, args);
_.bindAll(this, 'insertComponent');
@ -37,15 +36,15 @@ module.exports = _.extend({}, CreateComponent, {
this.beforeInsert(object);
var index = this.sorter.lastPos.index;
// 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);
else
this.enable();
else this.enable();
if(!model)
return;
if (!model) return;
this.afterInsert(model, this);
},
@ -72,5 +71,5 @@ module.exports = _.extend({}, CreateComponent, {
* */
buildContent() {
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 SelectPosition = require('./SelectPosition');
const $ = Backbone.$;
module.exports = _.extend({}, SelectPosition, SelectComponent, {
init(o) {
SelectComponent.init.apply(this, arguments);
_.bindAll(this, 'initSorter','rollback', 'onEndMove');
_.bindAll(this, 'initSorter', 'rollback', 'onEndMove');
this.opt = o;
this.hoverClass = this.ppfx + 'highlighter-warning';
this.badgeClass = this.ppfx + 'badge-warning';
this.noSelClass = this.ppfx + 'no-select';
this.hoverClass = this.ppfx + 'highlighter-warning';
this.badgeClass = this.ppfx + 'badge-warning';
this.noSelClass = this.ppfx + 'no-select';
},
enable(...args) {
@ -20,7 +19,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
this.getBadgeEl().addClass(this.badgeClass);
this.getHighlighterEl().addClass(this.hoverClass);
var wp = this.$wrapper;
wp.css('cursor','move');
wp.css('cursor', 'move');
wp.on('mousedown', this.initSorter);
// Avoid strange moving behavior
@ -41,8 +40,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
initSorter(e) {
var el = $(e.target).data('model');
var drag = el.get('draggable');
if(!drag)
return;
if (!drag) return;
// Avoid badge showing on move
this.cacheEl = null;
@ -61,8 +59,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
*/
initSorterFromModel(model) {
var drag = model.get('draggable');
if(!drag)
return;
if (!drag) return;
// Avoid badge showing on move
this.cacheEl = null;
var el = model.view.el;
@ -111,7 +108,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
* */
rollback(e, force) {
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.endMove();
}
@ -124,8 +121,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
* @private
*/
getBadgeEl() {
if(!this.$badge)
this.$badge = $(this.getBadge());
if (!this.$badge) this.$badge = $(this.getBadge());
return this.$badge;
},
@ -135,8 +131,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
* @private
*/
getHighlighterEl() {
if(!this.$hl)
this.$hl = $(this.canvas.getHighlighter());
if (!this.$hl) this.$hl = $(this.canvas.getHighlighter());
return this.$hl;
},
@ -145,6 +140,9 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
this.getBadgeEl().removeClass(this.badgeClass);
this.getHighlighterEl().removeClass(this.hoverClass);
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 = {
run(editor, sender, opts = {}) {
const modal = editor.Modal;
const am = editor.AssetManager;
@ -12,15 +11,12 @@ module.exports = {
am.onSelect(opts.onSelect);
if (!this.rendered) {
am.render(am.getAll().filter(
asset => asset.get('type') == 'image'
));
am.render(am.getAll().filter(asset => asset.get('type') == 'image'));
this.rendered = 1;
}
modal.setTitle(title);
modal.setContent(am.getContainer());
modal.open();
},
}
};

3
src/commands/view/OpenBlocks.js

@ -1,5 +1,4 @@
module.exports = {
run(editor, sender) {
const bm = editor.BlockManager;
const pn = editor.Panels;
@ -8,7 +7,7 @@ module.exports = {
bm.render();
const id = 'views-container';
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());
panels.set('appendContent', blocks).trigger('change:appendContent');
this.blocks = blocks;

10
src/commands/view/OpenLayers.js

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

55
src/commands/view/OpenStyleManager.js

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

23
src/commands/view/OpenTraitManager.js

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

15
src/commands/view/Preview.js

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

6
src/commands/view/Resize.js

@ -1,5 +1,4 @@
module.exports = {
run(editor, sender, opts) {
var opt = opts || {};
var el = opt.el || '';
@ -14,7 +13,7 @@ module.exports = {
options.mousePosFetcher = canvas.getMouseRelativePos;
// 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);
canvasResizer = this.canvasResizer;
}
@ -27,6 +26,5 @@ module.exports = {
stop() {
const resizer = this.canvasResizer;
resizer && resizer.blur();
},
}
};

96
src/commands/view/SelectComponent.js

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

4
src/commands/view/SelectParent.js

@ -1,15 +1,13 @@
module.exports = {
run(editor) {
const sel = editor.getSelected();
let comp = sel && sel.parent();
// 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 && editor.select(comp);
}
};

46
src/commands/view/SelectPosition.js

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

14
src/commands/view/ShowOffset.js

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

4
src/commands/view/SwitchVisibility.js

@ -1,11 +1,9 @@
module.exports = {
run(ed) {
ed.Canvas.getBody().className = this.ppfx + 'dashed';
},
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');
module.exports = _.extend({}, CreateComponent, {
/**
* This event is triggered at the beginning of a draw operation
* @param {Object} component Object component before creation
@ -10,8 +9,7 @@ module.exports = _.extend({}, CreateComponent, {
* */
beforeDraw(component) {
component.type = 'text';
if(!component.style)
component.style = {};
if (!component.style) component.style = {};
component.style.padding = '10px';
},
@ -21,11 +19,8 @@ module.exports = _.extend({}, CreateComponent, {
* @private
* */
afterDraw(model) {
if(!model || !model.set)
return;
if (!model || !model.set) return;
model.trigger('focus');
if(this.sender)
this.sender.set('active', false);
},
if (this.sender) this.sender.set('active', false);
}
});

6
src/css_composer/config/config.js

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

697
src/css_composer/index.js

@ -19,375 +19,352 @@
module.exports = () => {
let em;
var c = {},
defaults = require('./config/config'),
CssRule = require('./model/CssRule'),
CssRules = require('./model/CssRules'),
CssRulesView = require('./view/CssRulesView');
defaults = require('./config/config'),
CssRule = require('./model/CssRule'),
CssRules = require('./model/CssRules'),
CssRulesView = require('./view/CssRulesView');
const Selectors = require('selector_manager/model/Selectors');
const Selector = require('selector_manager/model/Selector');
var rules, rulesView;
return {
Selectors,
/**
* Name of the module
* @type {String}
* @private
*/
name: 'CssComposer',
/**
* Mandatory for the storage manager
* @type {String}
* @private
*/
storageKey() {
var keys = [];
var smc = (c.stm && c.stm.getConfig()) || {};
if(smc.storeCss)
keys.push('css');
if(smc.storeStyles)
keys.push('styles');
return keys;
},
/**
* Initializes module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
* @private
*/
init(config) {
c = config || {};
for (var name in defaults) {
if (!(name in c))
c[name] = defaults[name];
}
var ppfx = c.pStylePrefix;
if(ppfx)
c.stylePrefix = ppfx + c.stylePrefix;
var elStyle = (c.em && c.em.config.style) || '';
c.rules = elStyle || c.rules;
c.sm = c.em;
em = c.em;
rules = new CssRules([], c);
rulesView = new CssRulesView({
collection: rules,
config: c,
});
return this;
},
/**
* On load callback
* @private
*/
onLoad() {
rules.add(c.rules);
},
/**
* Do stuff after load
* @param {Editor} em
* @private
*/
postLoad(em) {
const ev = 'add remove';
const rules = this.getAll();
em.stopListening(rules, ev, this.handleChange);
em.listenTo(rules, ev, this.handleChange);
rules.each(rule => this.handleChange(rule));
},
/**
* Handle rule changes
* @private
*/
handleChange(model) {
const ev = 'change:style';
const um = em.get('UndoManager');
um && um.add(model);
const handleUpdates = em.handleUpdates.bind(em);
em.stopListening(model, ev, handleUpdates);
em.listenTo(model, ev, handleUpdates);
},
/**
* Load data from the passed object, if the object is empty will try to fetch them
* autonomously from the storage manager.
* The fetched data will be added to the collection
* @param {Object} data Object of data to load
* @return {Object} Loaded rules
*/
load(data) {
var d = data || '';
if (!d && c.stm) {
d = c.em.getCacheLoad();
}
var obj = d.styles || '';
if(d.styles) {
try {
obj = JSON.parse(d.styles);
} catch (err) {}
} else if (d.css) {
obj = c.em.get('Parser').parseCss(d.css);
Selectors,
/**
* Name of the module
* @type {String}
* @private
*/
name: 'CssComposer',
/**
* Mandatory for the storage manager
* @type {String}
* @private
*/
storageKey() {
var keys = [];
var smc = (c.stm && c.stm.getConfig()) || {};
if (smc.storeCss) keys.push('css');
if (smc.storeStyles) keys.push('styles');
return keys;
},
/**
* Initializes module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
* @private
*/
init(config) {
c = config || {};
for (var name in defaults) {
if (!(name in c)) c[name] = defaults[name];
}
var ppfx = c.pStylePrefix;
if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
var elStyle = (c.em && c.em.config.style) || '';
c.rules = elStyle || c.rules;
c.sm = c.em;
em = c.em;
rules = new CssRules([], c);
rulesView = new CssRulesView({
collection: rules,
config: c
});
return this;
},
/**
* On load callback
* @private
*/
onLoad() {
rules.add(c.rules);
},
/**
* Do stuff after load
* @param {Editor} em
* @private
*/
postLoad(em) {
const ev = 'add remove';
const rules = this.getAll();
em.stopListening(rules, ev, this.handleChange);
em.listenTo(rules, ev, this.handleChange);
rules.each(rule => this.handleChange(rule));
},
/**
* Handle rule changes
* @private
*/
handleChange(model) {
const ev = 'change:style';
const um = em.get('UndoManager');
um && um.add(model);
const handleUpdates = em.handleUpdates.bind(em);
em.stopListening(model, ev, handleUpdates);
em.listenTo(model, ev, handleUpdates);
},
/**
* Load data from the passed object, if the object is empty will try to fetch them
* autonomously from the storage manager.
* The fetched data will be added to the collection
* @param {Object} data Object of data to load
* @return {Object} Loaded rules
*/
load(data) {
var d = data || '';
if (!d && c.stm) {
d = c.em.getCacheLoad();
}
var obj = d.styles || '';
if (d.styles) {
try {
obj = JSON.parse(d.styles);
} catch (err) {}
} else if (d.css) {
obj = c.em.get('Parser').parseCss(d.css);
}
if (obj) {
rules.reset(obj);
}
return obj;
},
/**
* 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) {
rules.reset(obj);
}
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 || {};
return obj;
},
/**
* 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);
}
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);
if (updateStyle) {
let styleUpdate = opts.extend
? { ...model.get('style'), ...style }
: style;
model.set('style', styleUpdate);
}
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
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} The new/updated rule
* @example
* const rule = cc.setIdRule('myid', { color: 'red' });
* const ruleHover = cc.setIdRule('myid', { color: 'blue' }, { state: 'hover' });
* // This will add current CSS:
* // #myid { color: red }
* // #myid:hover { color: blue }
*/
setIdRule(name, style = {}, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
const sm = em.get('SelectorManager');
const selector = sm.add({ name, type: Selector.TYPE_ID });
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'
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule}
* @example
* const rule = cc.getIdRule('myid');
* const ruleHover = cc.setIdRule('myid', { state: 'hover' });
*/
getIdRule(name, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
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
* @param {string} name Class selector name, eg. 'my-class'
* @param {Object} style Style properties and values
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} The new/updated rule
* @example
* const rule = cc.setClassRule('myclass', { color: 'red' });
* const ruleHover = cc.setClassRule('myclass', { color: 'blue' }, { state: 'hover' });
* // This will add current CSS:
* // .myclass { color: red }
* // .myclass:hover { color: blue }
*/
setClassRule(name, style = {}, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
const sm = em.get('SelectorManager');
const selector = sm.add({ name, type: Selector.TYPE_CLASS });
const rule = this.add(selector, state, media);
rule.setStyle(style, opts);
return rule;
},
/**
* Get the CSS rule by class selector
* @param {string} name Class selector name, eg. 'my-class'
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule}
* @example
* const rule = cc.getClassRule('myclass');
* const ruleHover = cc.getClassRule('myclass', { state: 'hover' });
*/
getClassRule(name, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
const selector = em.get('SelectorManager').get(name, Selector.TYPE_CLASS);
return selector && this.get(selector, state, media);
},
/**
* Render the block of CSS rules
* @return {HTMLElement}
* @private
*/
render() {
return rulesView.render().el;
},
};
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
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} The new/updated rule
* @example
* const rule = cc.setIdRule('myid', { color: 'red' });
* const ruleHover = cc.setIdRule('myid', { color: 'blue' }, { state: 'hover' });
* // This will add current CSS:
* // #myid { color: red }
* // #myid:hover { color: blue }
*/
setIdRule(name, style = {}, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
const sm = em.get('SelectorManager');
const selector = sm.add({ name, type: Selector.TYPE_ID });
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'
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule}
* @example
* const rule = cc.getIdRule('myid');
* const ruleHover = cc.setIdRule('myid', { state: 'hover' });
*/
getIdRule(name, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
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
* @param {string} name Class selector name, eg. 'my-class'
* @param {Object} style Style properties and values
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule} The new/updated rule
* @example
* const rule = cc.setClassRule('myclass', { color: 'red' });
* const ruleHover = cc.setClassRule('myclass', { color: 'blue' }, { state: 'hover' });
* // This will add current CSS:
* // .myclass { color: red }
* // .myclass:hover { color: blue }
*/
setClassRule(name, style = {}, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
const sm = em.get('SelectorManager');
const selector = sm.add({ name, type: Selector.TYPE_CLASS });
const rule = this.add(selector, state, media);
rule.setStyle(style, opts);
return rule;
},
/**
* Get the CSS rule by class selector
* @param {string} name Class selector name, eg. 'my-class'
* @param {Object} [opts={}] Custom options, like `state` and `mediaText`
* @return {CssRule}
* @example
* const rule = cc.getClassRule('myclass');
* const ruleHover = cc.getClassRule('myclass', { state: 'hover' });
*/
getClassRule(name, opts = {}) {
const state = opts.state || '';
const media = opts.mediaText || em.getCurrentMedia();
const selector = em.get('SelectorManager').get(name, Selector.TYPE_CLASS);
return selector && this.get(selector, state, media);
},
/**
* Render the block of CSS rules
* @return {HTMLElement}
* @private
*/
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');
module.exports = Backbone.Model.extend(Styleable).extend({
defaults: {
defaults: {
// Css selectors
selectors: {},
@ -27,9 +26,8 @@ module.exports = Backbone.Model.extend(Styleable).extend({
// If true, sets '!important' on all properties
// You can use an array to specify properties to set important
// Used in view
important: 0,
},
important: 0
},
initialize(c, opt = {}) {
this.config = c || {};
@ -40,7 +38,7 @@ module.exports = Backbone.Model.extend(Styleable).extend({
if (em) {
const sm = em.get('SelectorManager');
const slct = [];
selectors.forEach((selector) => {
selectors.forEach(selector => {
slct.push(sm.add(selector));
});
selectors = slct;
@ -49,7 +47,6 @@ module.exports = Backbone.Model.extend(Styleable).extend({
this.set('selectors', new Selectors(selectors));
},
/**
* Return selectors fo the rule as a string
* @return {string}
@ -65,7 +62,6 @@ module.exports = Backbone.Model.extend(Styleable).extend({
return result.join(', ');
},
/**
* Returns CSS string of the rule
* @param {Object} [opts={}] Options
@ -88,7 +84,6 @@ module.exports = Backbone.Model.extend(Styleable).extend({
return result;
},
/**
* Compare the actual model with parameters
* @param {Object} selectors Collection of selectors
@ -99,42 +94,35 @@ module.exports = Backbone.Model.extend(Styleable).extend({
* @private
*/
compare(selectors, state, width, ruleProps) {
var otherRule = ruleProps || {};
var st = state || '';
var wd = width || '';
var selectorsAdd = otherRule.selectorsAdd || '';
var cId = 'cid';
//var a1 = _.pluck(selectors.models || selectors, cId);
//var a2 = _.pluck(this.get('selectors').models, cId);
if(!(selectors instanceof Array) && !selectors.models)
selectors = [selectors];
var a1 = _.map((selectors.models || selectors), model => model.get('name'));
var a2 = _.map(this.get('selectors').models, model => model.get('name'));
var f = false;
if(a1.length !== a2.length)
return f;
for (var i = 0; i < a1.length; i++) {
var re = 0;
for (var j = 0; j < a2.length; j++) {
if (a1[i] === a2[j])
re = 1;
}
if(re === 0)
return f;
var otherRule = ruleProps || {};
var st = state || '';
var wd = width || '';
var selectorsAdd = otherRule.selectorsAdd || '';
var cId = 'cid';
//var a1 = _.pluck(selectors.models || selectors, cId);
//var a2 = _.pluck(this.get('selectors').models, cId);
if (!(selectors instanceof Array) && !selectors.models)
selectors = [selectors];
var a1 = _.map(selectors.models || selectors, model => model.get('name'));
var a2 = _.map(this.get('selectors').models, model => model.get('name'));
var f = false;
if (a1.length !== a2.length) return f;
for (var i = 0; i < a1.length; i++) {
var re = 0;
for (var j = 0; j < a2.length; j++) {
if (a1[i] === a2[j]) re = 1;
}
if (re === 0) return f;
}
if(this.get('state') !== st)
return f;
if(this.get('mediaText') !== wd)
return f;
if (this.get('state') !== st) return f;
if(this.get('selectorsAdd') !== selectorsAdd)
return f;
if (this.get('mediaText') !== wd) 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');
module.exports = Backbone.Collection.extend({
initialize(models, opt) {
// Inject editor
if(opt && opt.sm)
this.editor = opt.sm;
if (opt && opt.sm) this.editor = opt.sm;
// Not used
this.model = (attrs, options) => {
var model;
if(!options.sm && opt && opt.sm)
options.sm = opt.sm;
if (!options.sm && opt && opt.sm) options.sm = opt.sm;
switch(1){
switch (1) {
default:
model = new CssRule(attrs, options);
}
return model;
return model;
};
},
add(models, opt = {}) {
@ -31,6 +27,5 @@ module.exports = Backbone.Collection.extend({
}
opt.em = this.editor;
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);
},
render() {
const model = this.model;
const important = model.get('important');
this.el.innerHTML = this.model.toCSS({important});
this.el.innerHTML = this.model.toCSS({ important });
return this;
},
}
});

21
src/css_composer/view/CssRulesView.js

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

4
src/device_manager/config/config.js

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

176
src/device_manager/index.js

@ -9,104 +9,100 @@
*/
module.exports = () => {
var c = {},
defaults = require('./config/config'),
Devices = require('./model/Devices'),
DevicesView = require('./view/DevicesView');
defaults = require('./config/config'),
Devices = require('./model/Devices'),
DevicesView = require('./view/DevicesView');
var devices, view;
return {
/**
* Name of the module
* @type {String}
* @private
*/
name: 'DeviceManager',
/**
* Name of the module
* @type {String}
* @private
*/
name: 'DeviceManager',
/**
* Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
* @param {Array<Object>} [config.devices=[]] Default devices
* @example
* ...
* {
* 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];
}
/**
* Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
* @param {Array<Object>} [config.devices=[]] Default devices
* @example
* ...
* {
* 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({
collection: devices,
config: c
});
return this;
},
devices = new Devices(c.devices);
view = new DevicesView({
collection: devices,
config: c
});
return this;
},
/**
* Add new device to the collection. URLs are supposed to be unique
* @param {string} name Device name
* @param {string} width Width of the device
* @param {Object} opts Custom options
* @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
* @param {string} name Device name
* @param {string} width Width of the device
* @param {Object} opts Custom options
* @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);
},
/**
* Return device by name
* @param {string} name Name of the device
* @example
* var device = deviceManager.get('Tablet');
* console.log(JSON.stringify(device));
* // {name: 'Tablet', width: '900px'}
*/
get(name) {
return devices.get(name);
},
/**
* Return device by name
* @param {string} name Name of the device
* @example
* var device = deviceManager.get('Tablet');
* console.log(JSON.stringify(device));
* // {name: 'Tablet', width: '900px'}
*/
get(name) {
return devices.get(name);
},
/**
* 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;
},
/**
* 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;
}
};
};

6
src/device_manager/model/Device.js

@ -1,10 +1,9 @@
var Backbone = require('backbone');
module.exports = Backbone.Model.extend({
idAttribute: 'name',
defaults :{
defaults: {
name: '',
// 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,
// If empty the width will be used
widthMedia: null,
widthMedia: null
},
initialize() {
@ -23,5 +22,4 @@ module.exports = Backbone.Model.extend({
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');
module.exports = Backbone.Collection.extend({
model: Device,
model: Device
});

22
src/device_manager/view/DevicesView.js

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

33
src/dom_components/config/config.js

@ -12,9 +12,15 @@ module.exports = {
draggable: false,
components: [],
traits: [],
stylable: ['background','background-color','background-image',
'background-repeat','background-attachment','background-position',
'background-size'],
stylable: [
'background',
'background-color',
'background-image',
'background-repeat',
'background-attachment',
'background-position',
'background-size'
]
},
// Could be used for default components
@ -32,7 +38,22 @@ module.exports = {
storeWrapper: 0,
// List of void elements
voidElements: ['area', 'base', 'br', 'col', 'embed', 'hr', 'img',
'input', 'keygen', 'link', 'menuitem', 'meta', 'param', 'source',
'track', 'wbr'],
voidElements: [
'area',
'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',
model: require('./model/ComponentTableCell'),
view: require('./view/ComponentTableCellView'),
view: require('./view/ComponentTableCellView')
},
{
id: 'row',
model: require('./model/ComponentTableRow'),
view: require('./view/ComponentTableRowView'),
view: require('./view/ComponentTableRowView')
},
{
id: 'table',
model: require('./model/ComponentTable'),
view: require('./view/ComponentTableView'),
view: require('./view/ComponentTableView')
},
{
id: 'thead',
model: require('./model/ComponentTableHead'),
view: require('./view/ComponentTableHeadView'),
view: require('./view/ComponentTableHeadView')
},
{
id: 'tbody',
model: require('./model/ComponentTableBody'),
view: require('./view/ComponentTableBodyView'),
view: require('./view/ComponentTableBodyView')
},
{
id: 'tfoot',
model: require('./model/ComponentTableFoot'),
view: require('./view/ComponentTableFootView'),
view: require('./view/ComponentTableFootView')
},
{
id: 'map',
model: require('./model/ComponentMap'),
view: require('./view/ComponentMapView'),
view: require('./view/ComponentMapView')
},
{
id: 'link',
model: require('./model/ComponentLink'),
view: require('./view/ComponentLinkView'),
view: require('./view/ComponentLinkView')
},
{
id: 'video',
model: require('./model/ComponentVideo'),
view: require('./view/ComponentVideoView'),
view: require('./view/ComponentVideoView')
},
{
id: 'image',
model: require('./model/ComponentImage'),
view: require('./view/ComponentImageView'),
view: require('./view/ComponentImageView')
},
{
id: 'script',
model: require('./model/ComponentScript'),
view: require('./view/ComponentScriptView'),
view: require('./view/ComponentScriptView')
},
{
id: 'svg',
model: require('./model/ComponentSvg'),
view: require('./view/ComponentSvgView'),
view: require('./view/ComponentSvgView')
},
{
id: 'textnode',
model: require('./model/ComponentTextNode'),
view: require('./view/ComponentTextNodeView'),
view: require('./view/ComponentTextNodeView')
},
{
id: 'text',
model: require('./model/ComponentText'),
view: require('./view/ComponentTextView'),
view: require('./view/ComponentTextView')
},
{
id: 'default',
model: Component,
view: ComponentView,
},
view: ComponentView
}
];
return {
Component,
Components,
@ -143,7 +142,7 @@ module.exports = () => {
* @private
*/
getConfig() {
return c;
return c;
},
/**
@ -154,10 +153,8 @@ module.exports = () => {
storageKey() {
var keys = [];
var smc = (c.stm && c.stm.getConfig()) || {};
if(smc.storeHtml)
keys.push('html');
if(smc.storeComponents)
keys.push('components');
if (smc.storeHtml) keys.push('html');
if (smc.storeComponents) keys.push('components');
return keys;
},
@ -176,13 +173,11 @@ module.exports = () => {
}
for (var name in defaults) {
if (!(name in c))
c[name] = defaults[name];
if (!(name in c)) c[name] = defaults[name];
}
var ppfx = c.pStylePrefix;
if(ppfx)
c.stylePrefix = ppfx + c.stylePrefix;
if (ppfx) c.stylePrefix = ppfx + c.stylePrefix;
// Load dependencies
if (em) {
@ -199,7 +194,11 @@ module.exports = () => {
wrapper.wrapper = 1;
// Components might be a wrapper
if (components && components.constructor === Object && components.wrapper) {
if (
components &&
components.constructor === Object &&
components.wrapper
) {
wrapper = { ...components };
components = components.components || [];
wrapper.components = [];
@ -214,14 +213,14 @@ module.exports = () => {
component = new Component(wrapper, {
sm: em,
config: c,
componentTypes,
componentTypes
});
component.set({ attributes: {id: 'wrapper'}});
component.set({ attributes: { id: 'wrapper' } });
componentView = new ComponentView({
model: component,
config: c,
componentTypes,
componentTypes
});
return this;
},
@ -243,7 +242,6 @@ module.exports = () => {
this.handleChanges(this.getWrapper(), null, { avoidStore: 1 });
},
/**
* Handle component changes
* @private
@ -258,10 +256,11 @@ module.exports = () => {
um && comps && um.add(comps);
const evn = 'change:style change:content change:attributes change:src';
[ [model, evn, handleUpdates],
[
[model, evn, handleUpdates],
[comps, 'add', handleChanges],
[comps, 'remove', handleRemoves],
[model.get('classes'), 'add remove', handleUpdates],
[model.get('classes'), 'add remove', handleUpdates]
].forEach(els => {
em.stopListening(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));
},
/**
* Triggered when some component is removed
* @private
@ -280,7 +278,6 @@ module.exports = () => {
!opts.avoidStore && em.handleUpdates(model, value, opts);
},
/**
* Load components from the passed object, if the object is empty will try to fetch them
* autonomously from the selected storage
@ -311,8 +308,11 @@ module.exports = () => {
// If the result is an object I consider it the wrapper
if (isObj) {
this.getWrapper().set(result)
.initComponents().initClasses().loadTraits();
this.getWrapper()
.set(result)
.initComponents()
.initClasses()
.loadTraits();
} else {
this.getComponents().add(result);
}
@ -327,7 +327,7 @@ module.exports = () => {
* @return {Object} Data to store
*/
store(noStore) {
if(!c.stm) {
if (!c.stm) {
return;
}
@ -339,8 +339,9 @@ module.exports = () => {
}
if (keys.indexOf('components') >= 0) {
const toStore = c.storeWrapper ?
this.getWrapper() : this.getComponents();
const toStore = c.storeWrapper
? this.getWrapper()
: this.getComponents();
obj.components = JSON.stringify(toStore);
}
@ -454,8 +455,7 @@ module.exports = () => {
*/
clear() {
var c = this.getComponents();
for(var i = 0, len = c.length; i < len; i++)
c.pop();
for (var i = 0, len = c.length; i < len; i++) c.pop();
return this;
},
@ -477,7 +477,7 @@ module.exports = () => {
*/
addType(type, methods) {
var compType = this.getType(type);
if(compType) {
if (compType) {
compType.model = methods.model;
compType.view = methods.view;
} else {
@ -496,7 +496,7 @@ module.exports = () => {
for (var it = 0; it < df.length; it++) {
var dfId = df[it].id;
if(dfId == type) {
if (dfId == type) {
return df[it];
}
}
@ -516,12 +516,11 @@ module.exports = () => {
if (previousModel) {
previousModel.set({
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');
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,
type: 'image',
tagName: 'img',
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);
},
initialize(o, opt) {
Component.prototype.initialize.apply(this, arguments);
var attr = this.get('attributes');
if (attr.src) this.set('src', attr.src);
},
initToolbar(...args) {
Component.prototype.initToolbar.apply(this, args);
initToolbar(...args) {
Component.prototype.initToolbar.apply(this, args);
if (this.sm && this.sm.get) {
var cmd = this.sm.get('Commands');
var cmdName = 'image-editor';
if (this.sm && this.sm.get) {
var cmd = this.sm.get('Commands');
var cmdName = 'image-editor';
// Add Image Editor button only if the default command exists
if (cmd.has(cmdName)) {
var tb = this.get('toolbar');
tb.push({
attributes: {class: 'fa fa-pencil'},
command: cmdName,
});
this.set('toolbar', tb);
// Add Image Editor button only if the default command exists
if (cmd.has(cmdName)) {
var tb = this.get('toolbar');
tb.push({
attributes: { class: 'fa fa-pencil' },
command: cmdName
});
this.set('toolbar', tb);
}
}
}
},
},
/**
* Returns object of attributes for HTML
* @return {Object}
* @private
*/
getAttrToHTML(...args) {
var attr = Component.prototype.getAttrToHTML.apply(this, args);
delete attr.onmousedown;
var src = this.get('src');
if(src)
attr.src = src;
return attr;
},
/**
* Returns object of attributes for HTML
* @return {Object}
* @private
*/
getAttrToHTML(...args) {
var attr = Component.prototype.getAttrToHTML.apply(this, args);
delete attr.onmousedown;
var src = this.get('src');
if (src) attr.src = src;
return attr;
},
/**
* Parse uri
* @param {string} uri
* @return {object}
* @private
*/
parseUri(uri) {
var el = document.createElement('a');
el.href = uri;
var query = {};
var qrs = el.search.substring(1).split('&');
for (var i = 0; i < qrs.length; i++) {
var pair = qrs[i].split('=');
var name = decodeURIComponent(pair[0]);
if(name)
query[name] = decodeURIComponent(pair[1]);
/**
* Parse uri
* @param {string} uri
* @return {object}
* @private
*/
parseUri(uri) {
var el = document.createElement('a');
el.href = uri;
var query = {};
var qrs = el.search.substring(1).split('&');
for (var i = 0; i < qrs.length; i++) {
var pair = qrs[i].split('=');
var name = decodeURIComponent(pair[0]);
if (name) 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
* from the element will be returned
* @param {HTMLElement}
* @return {Object}
* @private
*/
isComponent(el) {
var result = '';
if(el.tagName == 'IMG'){
result = {type: 'image'};
{
/**
* 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 == 'IMG') {
result = { type: 'image' };
}
return result;
}
return result;
},
});
}
);

90
src/dom_components/model/ComponentLink.js

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

180
src/dom_components/model/ComponentMap.js

@ -1,9 +1,9 @@
var Component = require('./ComponentImage');
var OComponent = require('./Component');
module.exports = Component.extend({
defaults: _.extend({}, Component.prototype.defaults, {
module.exports = Component.extend(
{
defaults: _.extend({}, Component.prototype.defaults, {
type: 'map',
void: 0,
mapUrl: 'https://maps.google.com/maps',
@ -11,97 +11,97 @@ module.exports = Component.extend({
mapType: 'q',
address: '',
zoom: '1',
attributes: {frameborder: 0},
attributes: { frameborder: 0 },
toolbar: OComponent.prototype.defaults.toolbar,
traits: [{
label: 'Address',
name: 'address',
placeholder: 'eg. London, UK',
changeProp: 1,
},{
type: 'select',
label: 'Map type',
name: 'mapType',
changeProp: 1,
options: [
{value: 'q', name: 'Roadmap'},
{value: 'w', name: 'Satellite'}
]
},{
label: 'Zoom',
name: 'zoom',
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());
},
traits: [
{
label: 'Address',
name: 'address',
placeholder: 'eg. London, UK',
changeProp: 1
},
{
type: 'select',
label: 'Map type',
name: 'mapType',
changeProp: 1,
options: [
{ value: 'q', name: 'Roadmap' },
{ value: 'w', name: 'Satellite' }
]
},
{
label: 'Zoom',
name: 'zoom',
type: 'range',
min: '1',
max: '20',
changeProp: 1
}
]
}),
/**
* 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;
},
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
);
},
/**
* Set attributes by src string
* @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);
},
updateSrc() {
this.set('src', this.getMapUrl());
},
},{
/**
* 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.
* 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};
/**
* Set attributes by src string
* @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);
}
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');
module.exports = Component.extend({
defaults: _.extend({}, Component.prototype.defaults, {
type: 'script',
droppable: false,
draggable: false,
layerable: false,
}),
}, {
module.exports = Component.extend(
{
defaults: _.extend({}, Component.prototype.defaults, {
type: 'script',
droppable: false,
draggable: false,
layerable: false
})
},
{
isComponent(el) {
if (el.tagName == 'SCRIPT') {
var result = { type: 'script' };
isComponent(el) {
if (el.tagName == 'SCRIPT') {
var result = {type: 'script'};
if (el.src) {
result.src = el.src;
result.onload = el.onload;
}
if (el.src) {
result.src = el.src;
result.onload = el.onload;
return result;
}
return result;
}
},
});
}
);

54
src/dom_components/model/ComponentSvg.js

@ -1,33 +1,33 @@
var Component = require('./Component');
module.exports = Component.extend({
module.exports = Component.extend(
{
defaults: {
...Component.prototype.defaults,
highlightable: 0
},
defaults: { ...Component.prototype.defaults,
highlightable: 0,
},
getName() {
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
};
getName() {
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
};
}
}
}
);

40
src/dom_components/model/ComponentTable.js

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

94
src/dom_components/model/ComponentTableBody.js

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

37
src/dom_components/model/ComponentTableCell.js

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

31
src/dom_components/model/ComponentTableFoot.js

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

31
src/dom_components/model/ComponentTableHead.js

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

45
src/dom_components/model/ComponentTableRow.js

@ -1,33 +1,34 @@
const Component = require('./Component');
module.exports = Component.extend({
defaults: { ...Component.prototype.defaults,
module.exports = Component.extend(
{
defaults: {
...Component.prototype.defaults,
type: 'row',
tagName: 'tr',
draggable: ['thead', 'tbody', 'tfoot'],
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);
}
},
}, {
isComponent(el) {
let result = '';
initialize(o, opt) {
Component.prototype.initialize.apply(this, arguments);
if (el.tagName == 'TR') {
result = { type: 'row' };
// 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);
}
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');
module.exports = Component.extend({
defaults: { ...Component.prototype.defaults,
defaults: {
...Component.prototype.defaults,
type: 'text',
droppable: false,
editable: true,
},
editable: true
}
});

43
src/dom_components/model/ComponentTextNode.js

@ -1,27 +1,26 @@
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, {
droppable: false,
editable: true,
}),
toHTML() {
return this.get('content');
},
}, {
isComponent(el) {
var result = '';
if(el.nodeType === 3){
result = {
type: 'textnode',
content: el.textContent
};
toHTML() {
return this.get('content');
}
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 vi = 'vi';
module.exports = Component.extend({
defaults: { ...Component.prototype.defaults,
module.exports = Component.extend(
{
defaults: {
...Component.prototype.defaults,
type: 'video',
tagName: 'video',
videoId: '',
@ -19,302 +20,295 @@ module.exports = Component.extend({
controls: 1,
color: '',
sources: [],
attributes:{allowfullscreen:'allowfullscreen'},
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);
},
attributes: { allowfullscreen: 'allowfullscreen' },
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);
},
initToolbar(...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:
}
},
initToolbar(...args) {
OComponent.prototype.initToolbar.apply(this, args);
},
/**
* Update src on change of video ID
* @private
*/
updateSrc() {
var prov = this.get('provider');
switch (prov) {
case yt:
this.set('src',this.getYoutubeSrc());
break;
case vi:
this.set('src',this.getVimeoSrc());
break;
}
},
/**
* 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:
}
},
/**
* Returns object of attributes for HTML
* @return {Object}
* @private
*/
getAttrToHTML(...args) {
var attr = Component.prototype.getAttrToHTML.apply(this, args);
var prov = this.get('provider');
switch (prov) {
case yt: case vi:
break;
default:
if(this.get('loop'))
attr.loop = 'loop';
if(this.get('autoplay'))
attr.autoplay = 'autoplay';
if(this.get('controls'))
attr.controls = 'controls';
}
return attr;
},
/**
* Update src on change of video ID
* @private
*/
updateSrc() {
var prov = this.get('provider');
switch (prov) {
case yt:
this.set('src', this.getYoutubeSrc());
break;
case vi:
this.set('src', this.getVimeoSrc());
break;
}
},
/**
* 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');
},
/**
* Returns object of attributes for HTML
* @return {Object}
* @private
*/
getAttrToHTML(...args) {
var attr = Component.prototype.getAttrToHTML.apply(this, args);
var prov = this.get('provider');
switch (prov) {
case yt:
case vi:
break;
default:
if (this.get('loop')) attr.loop = 'loop';
if (this.get('autoplay')) attr.autoplay = 'autoplay';
if (this.get('controls')) attr.controls = 'controls';
}
return attr;
},
// 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');
},
/**
* 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'}
]
};
},
// Listen provider change and switch traits, in TraitView listen traits change
/**
* Return traits for the source provider
* @return {Array<Object>}
* @private
*/
getSourceTraits() {
return [
this.getProviderTrait(), {
label: 'Source',
name: 'src',
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',
/**
* Return the provider trait
* @return {Object}
* @private
*/
getProviderTrait() {
return {
type: 'select',
label: 'Provider',
name: 'provider',
changeProp: 1,
},
this.getAutoplayTrait(),
this.getLoopTrait(),
this.getControlsTrait()
];
},
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 {Array<Object>}
* @private
*/
getVimeoTraits() {
return [
this.getProviderTrait(), {
label: 'Video ID',
name: 'videoId',
placeholder: 'eg. 123456789',
changeProp: 1,
},{
label: 'Color',
name: 'color',
placeholder: 'eg. FF0000',
changeProp: 1,
},
this.getAutoplayTrait(),
this.getLoopTrait(),
this.getControlsTrait()];
},
/**
* Return traits for the source provider
* @return {Array<Object>}
* @private
*/
getSourceTraits() {
return [
this.getProviderTrait(),
{
label: 'Source',
name: 'src',
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
},
this.getAutoplayTrait(),
this.getLoopTrait(),
this.getControlsTrait()
];
},
/**
* Return object trait
* @return {Object}
* @private
*/
getAutoplayTrait() {
return {
type: 'checkbox',
label: 'Autoplay',
name: 'autoplay',
changeProp: 1,
};
},
/**
* Return traits for the source provider
* @return {Array<Object>}
* @private
*/
getVimeoTraits() {
return [
this.getProviderTrait(),
{
label: 'Video ID',
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}
* @private
*/
getLoopTrait() {
return {
type: 'checkbox',
label: 'Loop',
name: 'loop',
changeProp: 1,
};
},
/**
* Return object trait
* @return {Object}
* @private
*/
getAutoplayTrait() {
return {
type: 'checkbox',
label: 'Autoplay',
name: 'autoplay',
changeProp: 1
};
},
/**
* Return object trait
* @return {Object}
* @private
*/
getControlsTrait() {
return {
type: 'checkbox',
label: 'Controls',
name: 'controls',
changeProp: 1,
};
},
/**
* Return object trait
* @return {Object}
* @private
*/
getLoopTrait() {
return {
type: 'checkbox',
label: 'Loop',
name: 'loop',
changeProp: 1
};
},
/**
* Return object trait
* @return {Object}
* @private
*/
getControlsTrait() {
return {
type: 'checkbox',
label: 'Controls',
name: 'controls',
changeProp: 1
};
},
/**
* Returns url to youtube video
* @return {string}
* @private
*/
getYoutubeSrc() {
var url = this.get('ytUrl');
url += this.get('videoId') + '?';
url += this.get('autoplay') ? '&autoplay=1' : '';
url += !this.get('controls') ? '&controls=0' : '';
url += this.get('loop') ? '&loop=1' : '';
return url;
},
/**
* Returns url to youtube video
* @return {string}
* @private
*/
getYoutubeSrc() {
var url = this.get('ytUrl');
url += this.get('videoId') + '?';
url += this.get('autoplay') ? '&autoplay=1' : '';
url += !this.get('controls') ? '&controls=0' : '';
url += this.get('loop') ? '&loop=1' : '';
return url;
},
/**
* Returns url to vimeo video
* @return {string}
* @private
*/
getVimeoSrc() {
var url = this.get('viUrl');
url += this.get('videoId') + '?';
url += this.get('autoplay') ? '&autoplay=1' : '';
url += this.get('loop') ? '&loop=1' : '';
url += !this.get('controls') ? '&title=0&portrait=0&badge=0' : '';
url += this.get('color') ? '&color=' + this.get('color') : '';
return url;
/**
* Returns url to vimeo video
* @return {string}
* @private
*/
getVimeoSrc() {
var url = this.get('viUrl');
url += this.get('videoId') + '?';
url += this.get('autoplay') ? '&autoplay=1' : '';
url += this.get('loop') ? '&loop=1' : '';
url += !this.get('controls') ? '&title=0&portrait=0&badge=0' : '';
url += this.get('color') ? '&color=' + this.get('color') : '';
return url;
}
},
},{
/**
* 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 = '';
var isYtProv = /youtube\.com\/embed/.test(el.src);
var isViProv = /player\.vimeo\.com\/video/.test(el.src);
var isExtProv = isYtProv || isViProv;
if(el.tagName == 'VIDEO' ||
(el.tagName == 'IFRAME' && isExtProv) ){
result = {type: 'video'};
if(el.src)
result.src = el.src;
if(isExtProv){
if(isYtProv)
result.provider = yt;
else if(isViProv)
result.provider = vi;
{
/**
* 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 = '';
var isYtProv = /youtube\.com\/embed/.test(el.src);
var isViProv = /player\.vimeo\.com\/video/.test(el.src);
var isExtProv = isYtProv || isViProv;
if (el.tagName == 'VIDEO' || (el.tagName == 'IFRAME' && isExtProv)) {
result = { type: 'video' };
if (el.src) 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');
module.exports = Backbone.Collection.extend({
initialize(models, opt) {
this.on('add', this.onAdd);
this.config = opt && opt.config ? opt.config : null;
// Inject editor
if(opt && (opt.sm || opt.em))
this.editor = opt.sm || opt.em;
if (opt && (opt.sm || opt.em)) this.editor = opt.sm || opt.em;
this.model = (attrs, options) => {
this.model = (attrs, options) => {
var model;
if(!options.sm && opt && opt.sm)
options.sm = opt.sm;
if (!options.sm && opt && opt.sm) options.sm = opt.sm;
if(!options.em && opt && opt.em)
options.em = opt.em;
if (!options.em && opt && opt.em) options.em = opt.em;
if(opt && opt.config)
options.config = opt.config;
if (opt && opt.config) options.config = opt.config;
if(opt && opt.componentTypes)
options.componentTypes = opt.componentTypes;
if (opt && opt.componentTypes)
options.componentTypes = opt.componentTypes;
var df = opt.componentTypes;
for (var it = 0; it < df.length; it++) {
var dfId = df[it].id;
if(dfId == attrs.type) {
if (dfId == attrs.type) {
model = df[it].model;
break;
}
}
if(!model) {
if (!model) {
// get the last one
model = df[df.length - 1].model;
}
return new model(attrs, options);
};
},
add(models, opt = {}) {
@ -57,7 +50,7 @@ module.exports = Backbone.Collection.extend({
var cssc = this.editor.get('CssComposer');
if (parsed.css && cssc) {
var {avoidUpdateStyle} = opt;
var { avoidUpdateStyle } = opt;
var added = cssc.addCollection(parsed.css, {
extend: 1,
avoidUpdateStyle
@ -73,15 +66,19 @@ module.exports = Backbone.Collection.extend({
const style = model.get('style');
const avoidInline = em && em.getConfig('avoidInlineStyle');
if (!isEmpty(style) && !avoidInline &&
em && em.get && em.get('Config').forceClass) {
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);
if (
!isEmpty(style) &&
!avoidInline &&
em &&
em.get &&
em.get('Config').forceClass
) {
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 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');
module.exports = Backbone.Model.extend({
defaults: {
command: '',
attributes: {},
},
command: '',
attributes: {}
}
});

16
src/dom_components/view/ComponentImageView.js

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

4
src/dom_components/view/ComponentLinkView.js

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

8
src/dom_components/view/ComponentMapView.js

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

41
src/dom_components/view/ComponentScriptView.js

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

2
src/dom_components/view/ComponentSvgView.js

@ -1,9 +1,7 @@
const ComponentView = require('./ComponentView');
module.exports = ComponentView.extend({
_createElement: function(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');
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');
module.exports = ComponentView.extend({
events: {
'dblclick': 'enableEditing',
dblclick: 'enableEditing'
},
initialize(o) {
@ -76,10 +75,10 @@ module.exports = ComponentView.extend({
removable: 0,
draggable: 0,
copyable: 0,
toolbar: '',
})
toolbar: ''
});
model.get('components').each(model => clean(model));
}
};
// Avoid re-render on reset with silent option
model.trigger('change:content', model);
@ -108,7 +107,7 @@ module.exports = ComponentView.extend({
*/
toggleEvents(enable) {
var method = enable ? 'on' : 'off';
const mixins = {on, off};
const mixins = { on, off };
// The ownerDocument is from the frame
var elDocs = [this.el.ownerDocument, document];
@ -118,6 +117,5 @@ module.exports = ComponentView.extend({
// Avoid closing edit mode on component click
this.$el.off('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');
module.exports = ComponentView.extend({
tagName: 'div',
events: {},
@ -11,7 +10,11 @@ module.exports = ComponentView.extend({
initialize(o) {
OComponentView.prototype.initialize.apply(this, arguments);
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);
},
@ -52,7 +55,8 @@ module.exports = ComponentView.extend({
var videoEl = this.videoEl;
var md = this.model;
switch (prov) {
case 'yt': case 'vi':
case 'yt':
case 'vi':
this.model.trigger('change:videoId');
break;
default:
@ -115,6 +119,5 @@ module.exports = ComponentView.extend({
var prov = this.model.get('provider');
this.el.appendChild(this.renderByProvider(prov));
return this;
},
}
});

59
src/dom_components/view/ComponentView.js

@ -3,7 +3,6 @@ import { isArray } from 'underscore';
const ComponentsView = require('./ComponentsView');
module.exports = Backbone.View.extend({
className() {
return this.getClasses();
},
@ -64,7 +63,6 @@ module.exports = Backbone.View.extend({
}
},
/**
* Import, if possible, classes inside main container
* @private
@ -72,14 +70,13 @@ module.exports = Backbone.View.extend({
importClasses() {
var clm = this.config.em.get('SelectorManager');
if(clm){
if (clm) {
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
* @param {Event} e
@ -89,14 +86,13 @@ module.exports = Backbone.View.extend({
var cl = 'hc-state';
var state = this.model.get('state');
if(state){
if (state) {
this.$el.addClass(cl);
}else{
} else {
this.$el.removeClass(cl);
}
},
/**
* Update item on status change
* @param {Event} e
@ -114,17 +110,19 @@ module.exports = Backbone.View.extend({
var cls = '';
switch (status) {
case 'selected':
cls = `${actualCls} ${selectedCls}`;
break;
case 'selected-parent':
cls = `${actualCls} ${selectedParentCls}`;
break;
case 'freezed':
cls = `${actualCls} ${freezedCls}`;
break;
default:
this.$el.removeClass(`${selectedCls} ${selectedParentCls} ${freezedCls}`);
case 'selected':
cls = `${actualCls} ${selectedCls}`;
break;
case 'selected-parent':
cls = `${actualCls} ${selectedParentCls}`;
break;
case 'freezed':
cls = `${actualCls} ${freezedCls}`;
break;
default:
this.$el.removeClass(
`${selectedCls} ${selectedParentCls} ${freezedCls}`
);
}
cls = cls.trim();
@ -134,7 +132,6 @@ module.exports = Backbone.View.extend({
}
},
/**
* Update highlight attribute
* @private
@ -144,7 +141,6 @@ module.exports = Backbone.View.extend({
this.setAttribute('data-highlightable', hl ? 1 : '');
},
/**
* Update style attribute
* @private
@ -161,13 +157,15 @@ module.exports = Backbone.View.extend({
}
},
/**
* Update classe attribute
* @private
* */
updateClasses() {
const str = this.model.get('classes').pluck('name').join(' ');
const str = this.model
.get('classes')
.pluck('name')
.join(' ');
this.setAttribute('class', str);
// Regenerate status class
@ -192,8 +190,8 @@ module.exports = Backbone.View.extend({
* @private
* */
getClasses() {
var attr = this.model.get("attributes"),
classes = attr['class'] || [];
var attr = this.model.get('attributes'),
classes = attr['class'] || [];
classes = isArray(classes) ? classes : [classes];
if (classes.length) {
@ -209,7 +207,7 @@ module.exports = Backbone.View.extend({
* */
updateAttributes() {
const model = this.model;
const attrs = {}
const attrs = {};
const attr = model.get('attributes');
const src = model.get('src');
@ -250,7 +248,7 @@ module.exports = Backbone.View.extend({
}
var em = this.em;
if(em) {
if (em) {
var canvas = em.get('Canvas');
canvas.getCanvasView().updateScript(this);
}
@ -301,14 +299,14 @@ module.exports = Backbone.View.extend({
const view = new ComponentsView({
collection: this.model.get('components'),
config: this.config,
componentTypes: this.opts.componentTypes,
componentTypes: this.opts.componentTypes
});
view.render(container);
this.childrenView = view;
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());
}
@ -341,6 +339,5 @@ module.exports = Backbone.View.extend({
this.renderChildren();
this.updateScript();
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({
initialize(o) {
this.opts = o || {};
this.config = o.config || {};
@ -38,10 +37,9 @@ module.exports = Backbone.View.extend({
* @private
* */
addToCollection(model, fragmentEl, index) {
if(!this.compView)
this.compView = require('./ComponentView');
var fragment = fragmentEl || null,
viewObject = this.compView;
if (!this.compView) this.compView = require('./ComponentView');
var fragment = fragmentEl || null,
viewObject = this.compView;
var dt = this.opts.componentTypes;
@ -49,7 +47,7 @@ module.exports = Backbone.View.extend({
for (var it = 0; it < dt.length; it++) {
var dtId = dt[it].id;
if(dtId == type) {
if (dtId == type) {
viewObject = dt[it].view;
break;
}
@ -59,16 +57,16 @@ module.exports = Backbone.View.extend({
var view = new viewObject({
model,
config: this.config,
componentTypes: dt,
componentTypes: dt
});
var rendered = view.render().el;
if(view.model.get('type') == 'textnode')
rendered = document.createTextNode(view.model.get('content'));
var rendered = view.render().el;
if (view.model.get('type') == 'textnode')
rendered = document.createTextNode(view.model.get('content'));
if (fragment) {
fragment.appendChild(rendered);
} else {
const parent = this.parentEl;
const parent = this.parentEl;
const children = parent.childNodes;
if (!isUndefined(index)) {
@ -102,11 +100,10 @@ module.exports = Backbone.View.extend({
render(parent) {
const el = this.el;
const frag = document.createDocumentFragment();
this.parentEl = parent || this.el;
this.parentEl = parent || this.el;
this.collection.each(model => this.addToCollection(model, frag));
el.innerHTML = '';
el.appendChild(frag);
return this;
}
});

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

Loading…
Cancel
Save