Browse Source

Merge branch 'no-jquery' into dev

pull/406/head
Artur Arseniev 9 years ago
parent
commit
572b181db0
  1. 8
      dist/grapes.min.js
  2. 4
      index.html
  3. 7
      package.json
  4. 3
      src/asset_manager/view/AssetsView.js
  5. 115
      src/block_manager/index.js
  6. 2
      src/block_manager/view/BlockView.js
  7. 12
      src/block_manager/view/BlocksView.js
  8. 17
      src/canvas/index.js
  9. 70
      src/canvas/view/CanvasView.js
  10. 2
      src/code_manager/view/EditorView.js
  11. 188
      src/commands/view/CommandAbstract.js
  12. 4
      src/commands/view/CreateComponent.js
  13. 4
      src/commands/view/DeleteComponent.js
  14. 4
      src/commands/view/ExportTemplate.js
  15. 16
      src/commands/view/MoveComponent.js
  16. 28
      src/commands/view/OpenBlocks.js
  17. 3
      src/commands/view/OpenLayers.js
  18. 17
      src/commands/view/OpenStyleManager.js
  19. 4
      src/commands/view/OpenTraitManager.js
  20. 53
      src/commands/view/SelectComponent.js
  21. 2
      src/commands/view/SelectPosition.js
  22. 24
      src/commands/view/ShowOffset.js
  23. 12
      src/dom_components/view/ComponentTextView.js
  24. 17
      src/dom_components/view/ComponentView.js
  25. 63
      src/domain_abstract/ui/Input.js
  26. 45
      src/domain_abstract/ui/InputColor.js
  27. 68
      src/domain_abstract/ui/InputNumber.js
  28. 5
      src/editor/index.js
  29. 77
      src/editor/model/Editor.js
  30. 2
      src/editor/view/EditorView.js
  31. 14
      src/grapesjs/index.js
  32. 15
      src/modal_dialog/view/ModalView.js
  33. 99
      src/navigator/view/ItemView.js
  34. 2
      src/panels/view/ButtonView.js
  35. 3
      src/rich_text_editor/index.js
  36. 4
      src/rich_text_editor/view/CommandButtonSelectView.js
  37. 15
      src/rich_text_editor/view/TextEditorView.js
  38. 28
      src/selector_manager/view/ClassTagView.js
  39. 4
      src/selector_manager/view/ClassTagsView.js
  40. 5
      src/storage_manager/config/config.js
  41. 3
      src/storage_manager/index.js
  42. 165
      src/storage_manager/model/RemoteStorage.js
  43. 25
      src/style_manager/model/Layer.js
  44. 99
      src/style_manager/model/Layers.js
  45. 34
      src/style_manager/model/Properties.js
  46. 3
      src/style_manager/model/PropertyComposite.js
  47. 12
      src/style_manager/model/PropertyStack.js
  48. 242
      src/style_manager/view/LayerView.js
  49. 23
      src/style_manager/view/LayersView.js
  50. 18
      src/style_manager/view/PropertiesView.js
  51. 8
      src/style_manager/view/PropertyColorView.js
  52. 5
      src/style_manager/view/PropertyCompositeView.js
  53. 13
      src/style_manager/view/PropertyFileView.js
  54. 4
      src/style_manager/view/PropertyIntegerView.js
  55. 34
      src/style_manager/view/PropertyRadioView.js
  56. 10
      src/style_manager/view/PropertySelectView.js
  57. 313
      src/style_manager/view/PropertyStackView.js
  58. 7
      src/style_manager/view/PropertyView.js
  59. 24
      src/style_manager/view/SectorView.js
  60. 4
      src/style_manager/view/SectorsView.js
  61. 4
      src/trait_manager/view/TraitSelectView.js
  62. 43
      src/trait_manager/view/TraitView.js
  63. 2321
      src/utils/ColorPicker.js
  64. 2
      src/utils/Dragger.js
  65. 2
      src/utils/Resizer.js
  66. 2
      src/utils/Sorter.js
  67. 303
      src/utils/extender.js
  68. 19
      src/utils/mixins.js
  69. 21
      test/helper.js
  70. 2
      test/main.js
  71. 4
      test/specs/asset_manager/index.js
  72. 43
      test/specs/asset_manager/view/AssetImageView.js
  73. 13
      test/specs/asset_manager/view/AssetView.js
  74. 55
      test/specs/asset_manager/view/AssetsView.js
  75. 29
      test/specs/asset_manager/view/FileUploader.js
  76. 3
      test/specs/block_manager/index.js
  77. 17
      test/specs/block_manager/view/BlocksView.js
  78. 2
      test/specs/css_composer/e2e/CssComposer.js
  79. 22
      test/specs/css_composer/view/CssRuleView.js
  80. 13
      test/specs/css_composer/view/CssRulesView.js
  81. 17
      test/specs/device_manager/view/DevicesView.js
  82. 11
      test/specs/dom_components/index.js
  83. 1
      test/specs/dom_components/model/Component.js
  84. 15
      test/specs/dom_components/view/ComponentImageView.js
  85. 22
      test/specs/dom_components/view/ComponentTextView.js
  86. 31
      test/specs/dom_components/view/ComponentV.js
  87. 13
      test/specs/dom_components/view/ComponentsView.js
  88. 13
      test/specs/grapesjs/index.js
  89. 15
      test/specs/modal/view/ModalView.js
  90. 4
      test/specs/panels/e2e/PanelsE2e.js
  91. 13
      test/specs/panels/index.js
  92. 19
      test/specs/panels/view/ButtonView.js
  93. 17
      test/specs/panels/view/ButtonsView.js
  94. 24
      test/specs/panels/view/PanelView.js
  95. 16
      test/specs/panels/view/PanelsView.js
  96. 98
      test/specs/selector_manager/e2e/ClassManager.js
  97. 9
      test/specs/selector_manager/index.js
  98. 21
      test/specs/selector_manager/view/ClassTagView.js
  99. 26
      test/specs/selector_manager/view/ClassTagsView.js
  100. 48
      test/specs/storage_manager/model/Models.js

8
dist/grapes.min.js

File diff suppressed because one or more lines are too long

4
index.html

@ -4,7 +4,7 @@
<meta charset="utf-8"> <meta charset="utf-8">
<title>GrapesJS</title> <title>GrapesJS</title>
<link rel="stylesheet" href="dist/css/grapes.min.css"> <link rel="stylesheet" href="dist/css/grapes.min.css">
<script src="node_modules/jquery/dist/jquery.min.js"></script> <!-- script src="node_modules/jquery/dist/jquery.min.js"></script -->
<script src="dist/grapes.min.js"></script> <script src="dist/grapes.min.js"></script>
</head> </head>
@ -1328,7 +1328,7 @@
console.log('STORE ', e); console.log('STORE ', e);
}) })
editor.on('styleManager:change:border-width', function(view) { editor.on('styleManager:change:text-shadow', function(view) {
var model = view.model; var model = view.model;
let targetValue = view.getTargetValue({ignoreDefault: 1}); let targetValue = view.getTargetValue({ignoreDefault: 1});
let computedValue = view.getComputedValue(); let computedValue = view.getComputedValue();

7
package.json

@ -1,7 +1,7 @@
{ {
"name": "grapesjs", "name": "grapesjs",
"description": "Free and Open Source Web Builder Framework", "description": "Free and Open Source Web Builder Framework",
"version": "0.10.8", "version": "0.11.4",
"author": "Artur Arseniev", "author": "Artur Arseniev",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"homepage": "http://grapesjs.com", "homepage": "http://grapesjs.com",
@ -13,6 +13,7 @@
"dependencies": { "dependencies": {
"backbone": "^1.3.3", "backbone": "^1.3.3",
"backbone-undo": "^0.2.5", "backbone-undo": "^0.2.5",
"cash-dom": "^1.3.5",
"codemirror": "^5.21.0", "codemirror": "^5.21.0",
"codemirror-formatting": "^1.0.0", "codemirror-formatting": "^1.0.0",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
@ -39,7 +40,8 @@
"sinon": "^3.2.1", "sinon": "^3.2.1",
"string-replace-loader": "^1.3.0", "string-replace-loader": "^1.3.0",
"webpack": "^3.5.5", "webpack": "^3.5.5",
"webpack-dev-server": "^2.7.1" "webpack-dev-server": "^2.7.1",
"whatwg-fetch": "^2.0.3"
}, },
"keywords": [ "keywords": [
"wte", "wte",
@ -64,6 +66,7 @@
"scripts": { "scripts": {
"lint": "eslint src", "lint": "eslint src",
"build": "cross-env WEBPACK_ENV=prod && npm run lint && npm run test && npm run v:patch && webpack && npm run build:css", "build": "cross-env WEBPACK_ENV=prod && npm run lint && npm run test && npm run v:patch && webpack && npm run build:css",
"build-n": "cross-env WEBPACK_ENV=prod && npm run lint && npm run test && webpack && npm run build:css",
"build:css": "node-sass src/styles/scss/main.scss dist/css/grapes.min.css --output-style compressed", "build:css": "node-sass src/styles/scss/main.scss dist/css/grapes.min.css --output-style compressed",
"v:patch": "npm version --no-git-tag-version patch", "v:patch": "npm version --no-git-tag-version patch",
"start": "cross-env WEBPACK_ENV=dev webpack-dev-server --progress --colors & npm run build:css -- -w", "start": "cross-env WEBPACK_ENV=dev webpack-dev-server --progress --colors & npm run build:css -- -w",

3
src/asset_manager/view/AssetsView.js

@ -153,7 +153,8 @@ module.exports = Backbone.View.extend({
if (hide) { if (hide) {
assetsEl.empty(); assetsEl.empty();
} else { } else {
assetsEl.append(this.config.noAssets); const noAssets = this.config.noAssets;
noAssets && assetsEl.append(noAssets);
} }
}, },

115
src/block_manager/index.js

@ -2,7 +2,9 @@
* * [add](#add) * * [add](#add)
* * [get](#get) * * [get](#get)
* * [getAll](#getall) * * [getAll](#getall)
* * [getAllVisible](#getallvisible)
* * [getCategories](#getcategories) * * [getCategories](#getcategories)
* * [getContainer](#getcontainer)
* * [render](#render) * * [render](#render)
* *
* Block manager helps managing various, draggable, piece of contents that could be easily reused inside templates. * Block manager helps managing various, draggable, piece of contents that could be easily reused inside templates.
@ -32,7 +34,7 @@ module.exports = () => {
Blocks = require('./model/Blocks'), Blocks = require('./model/Blocks'),
BlockCategories = require('./model/Categories'), BlockCategories = require('./model/Categories'),
BlocksView = require('./view/BlocksView'); BlocksView = require('./view/BlocksView');
var blocks, view; var blocks, blocksVisible, blocksView;
var categories = []; var categories = [];
return { return {
@ -52,19 +54,58 @@ module.exports = () => {
*/ */
init(config) { init(config) {
c = config || {}; c = config || {};
for (var name in defaults) { const em = c.em;
if (!(name in c))
for (let name in defaults) {
if (!(name in c)) {
c[name] = defaults[name]; c[name] = defaults[name];
}
} }
blocks = new Blocks(c.blocks);
// Global blocks collection
blocks = new Blocks([]);
blocksVisible = new Blocks([]);
categories = new BlockCategories(), categories = new BlockCategories(),
view = new BlocksView({ blocksView = new BlocksView({
collection: blocks, // Visible collection
collection: blocksVisible,
categories, categories,
}, c); }, 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; return this;
}, },
/**
* Get configuration object
* @return {Object}
*/
getConfig() {
return c;
},
/**
* Loading blocks with `onLoad` allows to init starting collection
* from plugins
*/
onLoad() {
this.getAll().reset(c.blocks);
},
/** /**
* Add new block to the collection. * Add new block to the collection.
* @param {string} id Block id * @param {string} id Block id
@ -98,7 +139,7 @@ module.exports = () => {
* Return the block by id * Return the block by id
* @param {string} id Block id * @param {string} id Block id
* @example * @example
* var block = blockManager.get('h1-block'); * const block = blockManager.get('h1-block');
* console.log(JSON.stringify(block)); * console.log(JSON.stringify(block));
* // {label: 'Heading', content: '<h1>Put your ...', ...} * // {label: 'Heading', content: '<h1>Put your ...', ...}
*/ */
@ -110,7 +151,7 @@ module.exports = () => {
* Return all blocks * Return all blocks
* @return {Collection} * @return {Collection}
* @example * @example
* var blocks = blockManager.getAll(); * const blocks = blockManager.getAll();
* console.log(JSON.stringify(blocks)); * console.log(JSON.stringify(blocks));
* // [{label: 'Heading', content: '<h1>Put your ...'}, ...] * // [{label: 'Heading', content: '<h1>Put your ...'}, ...]
*/ */
@ -118,9 +159,26 @@ module.exports = () => {
return blocks; 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. * Get all available categories.
* Is possible to add categories only with blocks via 'add()' method * It's possible to add categories only within blocks via 'add()' method
* @return {Array|Collection} * @return {Array|Collection}
*/ */
getCategories() { getCategories() {
@ -128,20 +186,43 @@ module.exports = () => {
}, },
/** /**
* Render blocks * Return the Blocks container element
* @return {HTMLElement} * @return {HTMLElement}
*/ */
render() { getContainer() {
return view.render().el; return blocksView.el;
}, },
/** /**
* Remove block by id * Render blocks
* @param {string} id Block id * @param {Array} blocks Blocks to render, without the argument will render
* @return {Block} Removed block * 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();
*/ */
remove(id) { render(blocks) {
return blocks.remove(id); const toRender = blocks || this.getAll().models;
if (!blocksView.rendered) {
blocksView.render();
blocksView.rendered = 1;
}
blocksView.collection.reset(toRender);
}, },
}; };

2
src/block_manager/view/BlockView.js

@ -1,4 +1,4 @@
var Backbone = require('backbone'); const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({

12
src/block_manager/view/BlocksView.js

@ -14,7 +14,9 @@ module.exports = Backbone.View.extend({
this.noCatClass = `${ppfx}blocks-no-cat`; this.noCatClass = `${ppfx}blocks-no-cat`;
this.blockContClass = `${ppfx}blocks-c`; this.blockContClass = `${ppfx}blocks-c`;
this.catsClass = `${ppfx}block-categories`; this.catsClass = `${ppfx}block-categories`;
this.listenTo(this.collection, 'add', this.addTo); const coll = this.collection;
this.listenTo(coll, 'add', this.addTo);
this.listenTo(coll, 'reset', this.render);
this.em = this.config.em; this.em = this.config.em;
this.tac = 'test-tac'; this.tac = 'test-tac';
this.grabbingCls = this.ppfx + 'grabbing'; this.grabbingCls = this.ppfx + 'grabbing';
@ -167,8 +169,7 @@ module.exports = Backbone.View.extend({
}, },
render() { render() {
var ppfx = this.ppfx; const frag = document.createDocumentFragment();
var frag = document.createDocumentFragment();
this.catsEl = null; this.catsEl = null;
this.blocksEl = null; this.blocksEl = null;
this.renderedCategories = []; this.renderedCategories = [];
@ -179,10 +180,7 @@ module.exports = Backbone.View.extend({
</div> </div>
`; `;
this.collection.each(function(model){ this.collection.each(model => this.add(model, frag));
this.add(model, frag);
}, this);
this.append(frag); this.append(frag);
this.$el.addClass(this.blockContClass + 's') this.$el.addClass(this.blockContClass + 's')
return this; return this;

17
src/canvas/index.js

@ -1,3 +1,5 @@
import {on, off} from 'utils/mixins'
module.exports = () => { module.exports = () => {
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
@ -353,8 +355,8 @@ module.exports = () => {
this.dragging = 1; this.dragging = 1;
let toListen = this.getScrollListeners(); let toListen = this.getScrollListeners();
frameRect = CanvasView.getFrameOffset(1); frameRect = CanvasView.getFrameOffset(1);
toListen.on('mousemove', this.autoscroll); on(toListen, 'mousemove', this.autoscroll);
toListen.on('mouseup', this.stopAutoscroll); on(toListen, 'mouseup', this.stopAutoscroll);
}, },
autoscroll(e) { autoscroll(e) {
@ -386,17 +388,12 @@ module.exports = () => {
stopAutoscroll() { stopAutoscroll() {
this.dragging = 0; this.dragging = 0;
let toListen = this.getScrollListeners(); let toListen = this.getScrollListeners();
toListen.off('mousemove', this.autoscroll); off(toListen, 'mousemove', this.autoscroll);
toListen.off('mouseup', this.stopAutoscroll); off(toListen, 'mouseup', this.stopAutoscroll);
}, },
getScrollListeners() { getScrollListeners() {
if (!this.scrollListeners) { return [this.getFrameEl().contentWindow, this.getElement()];
this.scrollListeners =
$(this.getFrameEl().contentWindow, this.getElement());
}
return this.scrollListeners;
}, },
/** /**

70
src/canvas/view/CanvasView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); const FrameView = require('./FrameView');
var FrameView = require('./FrameView'); const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
@ -311,13 +311,14 @@ module.exports = Backbone.View.extend({
view.scriptContainer.html(''); view.scriptContainer.html('');
// In editor, I make use of setTimeout as during the append process of elements // In editor, I make use of setTimeout as during the append process of elements
// those will not be available immediatly, therefore 'item' variable // those will not be available immediatly, therefore 'item' variable
view.scriptContainer.append(`<script> const script = document.createElement('script');
script.innerText = `
setTimeout(function() { setTimeout(function() {
var item = document.getElementById('${id}'); var item = document.getElementById('${id}');
if (!item) return; if (!item) return;
(function(){${model.getScriptString()}}.bind(item))() (function(){${model.getScriptString()}}.bind(item))()
}, 1); }, 1);`;
</script>`); view.scriptContainer.get(0).appendChild(script);
}, },
/** /**
@ -326,7 +327,7 @@ module.exports = Backbone.View.extend({
*/ */
getJsContainer() { getJsContainer() {
if (!this.jsContainer) { if (!this.jsContainer) {
this.jsContainer = $('<div>', {class: this.ppfx + 'js-cont'}).get(0); this.jsContainer = $(`<div class="${this.ppfx}js-cont">`).get(0);
} }
return this.jsContainer; return this.jsContainer;
}, },
@ -346,33 +347,40 @@ module.exports = Backbone.View.extend({
} }
} }
var ppfx = this.ppfx; var ppfx = this.ppfx;
var toolsEl = $('<div>', { id: ppfx + 'tools' }).get(0); this.$el.append(`
this.hlEl = $('<div>', { class: ppfx + 'highlighter' }).get(0); <div id="${ppfx}tools" style="pointer-events:none">
this.badgeEl = $('<div>', {class: ppfx + 'badge'}).get(0); <div class="${ppfx}highlighter"></div>
this.placerEl = $('<div>', {class: ppfx + 'placeholder'}).get(0); <div class="${ppfx}badge"></div>
this.placerIntEl = $('<div>', {class: ppfx + 'placeholder-int'}).get(0); <div class="${ppfx}placeholder">
this.ghostEl = $('<div>', {class: ppfx + 'ghost'}).get(0); <div class="${ppfx}placeholder-int"></div>
this.toolbarEl = $('<div>', {class: ppfx + 'toolbar'}).get(0); </div>
this.resizerEl = $('<div>', {class: ppfx + 'resizer'}).get(0); <div class="${ppfx}ghost"></div>
this.offsetEl = $('<div>', {class: ppfx + 'offset-v'}).get(0); <div class="${ppfx}toolbar" style="pointer-events:all"></div>
this.fixedOffsetEl = $('<div>', {class: ppfx + 'offset-fixed-v'}).get(0); <div class="${ppfx}resizer"></div>
this.placerEl.appendChild(this.placerIntEl); <div class="${ppfx}offset-v"></div>
toolsEl.appendChild(this.hlEl); <div class="${ppfx}offset-fixed-v"></div>
toolsEl.appendChild(this.badgeEl); </div>
toolsEl.appendChild(this.placerEl); `);
toolsEl.appendChild(this.ghostEl); const el = this.el;
toolsEl.appendChild(this.toolbarEl); const rte = this.em.get('rte');
toolsEl.appendChild(this.resizerEl); const toolsEl = el.querySelector(`#${ppfx}tools`);
toolsEl.appendChild(this.offsetEl); this.hlEl = el.querySelector(`.${ppfx}highlighter`);
toolsEl.appendChild(this.fixedOffsetEl); this.badgeEl = el.querySelector(`.${ppfx}badge`);
this.$el.append(toolsEl); this.placerEl = el.querySelector(`.${ppfx}placeholder`);
var rte = this.em.get('rte'); this.ghostEl = el.querySelector(`.${ppfx}ghost`);
this.toolbarEl = el.querySelector(`.${ppfx}toolbar`);
if(rte) this.resizerEl = el.querySelector(`.${ppfx}resizer`);
toolsEl.appendChild(rte.render()); this.offsetEl = el.querySelector(`.${ppfx}offset-v`);
this.fixedOffsetEl = el.querySelector(`.${ppfx}offset-fixed-v`);
if (rte) {
const rteEl = rte.render();
rteEl.style.pointerEvents = 'all';
toolsEl.appendChild(rteEl);
}
this.toolsEl = toolsEl; this.toolsEl = toolsEl;
this.$el.attr({class: this.className}); this.el.className = this.className;
return this; return this;
}, },

2
src/code_manager/view/EditorView.js

@ -18,7 +18,7 @@ module.exports = Backbone.View.extend({
obj.pfx = this.pfx; obj.pfx = this.pfx;
this.$el.html( this.template(obj) ); this.$el.html( this.template(obj) );
this.$el.attr('class', this.pfx + 'editor-c'); this.$el.attr('class', this.pfx + 'editor-c');
this.$el.find('#'+this.pfx+'code').html(this.model.get('input')); this.$el.find('#'+this.pfx+'code').append(this.model.get('input'));
return this; return this;
}, },

188
src/commands/view/CommandAbstract.js

@ -1,78 +1,78 @@
var Backbone = require('backbone'); const $ = Backbone.$
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
/** /**
* Initialize method that can't be removed * Initialize method that can't be removed
* @param {Object} o Options * @param {Object} o Options
* @private * @private
* */ * */
initialize(o) { initialize(o) {
this.config = o || {}; this.config = o || {};
this.editorModel = this.em = this.config.em || {}; this.editorModel = this.em = this.config.em || {};
this.pfx = this.config.stylePrefix; this.pfx = this.config.stylePrefix;
this.ppfx = this.config.pStylePrefix; this.ppfx = this.config.pStylePrefix;
this.hoverClass = this.pfx + 'hover'; this.hoverClass = this.pfx + 'hover';
this.badgeClass = this.pfx + 'badge'; this.badgeClass = this.pfx + 'badge';
this.plhClass = this.pfx + 'placeholder'; this.plhClass = this.pfx + 'placeholder';
this.freezClass = this.ppfx + 'freezed'; this.freezClass = this.ppfx + 'freezed';
this.canvas = this.em.get && this.em.get('Canvas'); this.canvas = this.em.get && this.em.get('Canvas');
if(this.em.get) if(this.em.get)
this.setElement(this.getCanvas()); this.setElement(this.getCanvas());
if(this.canvas){ if(this.canvas){
this.$canvas = this.$el; this.$canvas = this.$el;
this.$wrapper = $(this.getCanvasWrapper()); this.$wrapper = $(this.getCanvasWrapper());
this.frameEl = this.canvas.getFrameEl(); this.frameEl = this.canvas.getFrameEl();
this.canvasTool = this.getCanvasTools(); this.canvasTool = this.getCanvasTools();
this.bodyEl = this.getCanvasBody(); this.bodyEl = this.getCanvasBody();
} }
this.init(this.config); this.init(this.config);
}, },
/** /**
* On frame scroll callback * On frame scroll callback
* @param {[type]} e [description] * @param {[type]} e [description]
* @return {[type]} [description] * @return {[type]} [description]
*/ */
onFrameScroll(e) {}, onFrameScroll(e) {},
/** /**
* Returns canval element * Returns canval element
* @return {HTMLElement} * @return {HTMLElement}
*/ */
getCanvas() { getCanvas() {
return this.canvas.getElement(); return this.canvas.getElement();
}, },
/** /**
* Get canvas body element * Get canvas body element
* @return {HTMLElement} * @return {HTMLElement}
*/ */
getCanvasBody() { getCanvasBody() {
return this.canvas.getBody(); return this.canvas.getBody();
}, },
/** /**
* Get canvas wrapper element * Get canvas wrapper element
* @return {HTMLElement} * @return {HTMLElement}
*/ */
getCanvasWrapper() { getCanvasWrapper() {
return this.canvas.getWrapperEl(); return this.canvas.getWrapperEl();
}, },
/** /**
* Get canvas wrapper element * Get canvas wrapper element
* @return {HTMLElement} * @return {HTMLElement}
*/ */
getCanvasTools() { getCanvasTools() {
return this.canvas.getToolsEl(); return this.canvas.getToolsEl();
}, },
/** /**
* Get the offset of the element * Get the offset of the element
* @param {HTMLElement} el * @param {HTMLElement} el
* @return {Object} * @return {Object}
@ -85,27 +85,27 @@ module.exports = Backbone.View.extend({
}; };
}, },
/** /**
* Callback triggered after initialize * Callback triggered after initialize
* @param {Object} o Options * @param {Object} o Options
* @private * @private
* */ * */
init(o) {}, init(o) {},
/** /**
* Method that run command * Method that run command
* @param {Object} em Editor model * @param {Object} em Editor model
* @param {Object} sender Button sender * @param {Object} sender Button sender
* @private * @private
* */ * */
run(em, sender) {}, run(em, sender) {},
/** /**
* Method that stop command * Method that stop command
* @param {Object} em Editor model * @param {Object} em Editor model
* @param {Object} sender Button sender * @param {Object} sender Button sender
* @private * @private
* */ * */
stop(em, sender) {}, stop(em, sender) {},
}); });

4
src/commands/view/CreateComponent.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); const SelectPosition = require('./SelectPosition');
var SelectPosition = require('./SelectPosition'); const $ = Backbone.$;
module.exports = _.extend({}, SelectPosition, { module.exports = _.extend({}, SelectPosition, {

4
src/commands/view/DeleteComponent.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); const SelectComponent = require('./SelectComponent');
var SelectComponent = require('./SelectComponent'); const $ = Backbone.$;
module.exports = _.extend({},SelectComponent,{ module.exports = _.extend({},SelectComponent,{

4
src/commands/view/ExportTemplate.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = { module.exports = {
run(editor, sender) { run(editor, sender) {
@ -50,7 +52,7 @@ module.exports = {
var oCsslEd = this.buildEditor('css', 'hopscotch', 'CSS'); var oCsslEd = this.buildEditor('css', 'hopscotch', 'CSS');
this.htmlEditor = oHtmlEd.el; this.htmlEditor = oHtmlEd.el;
this.cssEditor = oCsslEd.el; this.cssEditor = oCsslEd.el;
this.$editors = $('<div>', {class: this.pfx + 'export-dl'}); this.$editors = $(`<div class="${this.pfx}export-dl">`);
this.$editors.append(oHtmlEd.$el).append(oCsslEd.$el); this.$editors.append(oHtmlEd.$el).append(oCsslEd.$el);
} }

16
src/commands/view/MoveComponent.js

@ -1,6 +1,8 @@
var Backbone = require('backbone'); import {on, off} from 'utils/mixins'
var SelectComponent = require('./SelectComponent');
var SelectPosition = require('./SelectPosition'); const SelectComponent = require('./SelectComponent');
const SelectPosition = require('./SelectPosition');
const $ = Backbone.$;
module.exports = _.extend({}, SelectPosition, SelectComponent, { module.exports = _.extend({}, SelectPosition, SelectComponent, {
@ -49,7 +51,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
this.sorter.onEndMove = this.onEndMove.bind(this); this.sorter.onEndMove = this.onEndMove.bind(this);
this.stopSelectComponent(); this.stopSelectComponent();
this.$wrapper.off('mousedown', this.initSorter); this.$wrapper.off('mousedown', this.initSorter);
this.getContentWindow().on('keydown', this.rollback); on(this.getContentWindow(), 'keydown', this.rollback);
}, },
/** /**
@ -77,11 +79,11 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
*/ */
this.stopSelectComponent(); this.stopSelectComponent();
this.getContentWindow().on('keydown', this.rollback); on(this.getContentWindow(), 'keydown', this.rollback);
}, },
onEndMoveFromModel() { onEndMoveFromModel() {
this.getContentWindow().off('keydown', this.rollback); off(this.getContentWindow(), 'keydown', this.rollback);
}, },
/** /**
@ -90,7 +92,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
*/ */
onEndMove() { onEndMove() {
this.enable(); this.enable();
this.getContentWindow().off('keydown', this.rollback); off(this.getContentWindow(), 'keydown', this.rollback);
}, },
/** /**

28
src/commands/view/OpenBlocks.js

@ -1,26 +1,24 @@
module.exports = { module.exports = {
run(editor, sender) { run(editor, sender) {
var config = editor.Config; const bm = editor.BlockManager;
var pfx = config.stylePrefix; const pn = editor.Panels;
var bm = editor.BlockManager;
var panelC; if (!this.blocks) {
if(!this.blocks){ bm.render();
this.blocks = $('<div/>').get(0); const id = 'views-container';
this.blocks.appendChild(bm.render()); const blocks = document.createElement('div');
var panels = editor.Panels; const panels = pn.getPanel(id) || pn.addPanel({id});
if(!panels.getPanel('views-container')) blocks.appendChild(bm.getContainer());
panelC = panels.addPanel({id: 'views-container'}); panels.set('appendContent', blocks).trigger('change:appendContent');
else this.blocks = blocks;
panelC = panels.getPanel('views-container');
panelC.set('appendContent', this.blocks).trigger('change:appendContent');
} }
this.blocks.style.display = 'block'; this.blocks.style.display = 'block';
}, },
stop() { stop() {
if(this.blocks) const blocks = this.blocks;
this.blocks.style.display = 'none'; blocks && (blocks.style.display = 'none');
} }
}; };

3
src/commands/view/OpenLayers.js

@ -1,4 +1,5 @@
var Layers = require('navigator'); const Layers = require('navigator');
const $ = Backbone.$;
module.exports = { module.exports = {

17
src/commands/view/OpenStyleManager.js

@ -1,16 +1,18 @@
var StyleManager = require('style_manager'); const StyleManager = require('style_manager');
const Backbone = require('backbone');
const $ = Backbone.$;
module.exports = { module.exports = {
run(em, sender) { run(em, sender) {
this.sender = sender; this.sender = sender;
if(!this.$cn){ if (!this.$cn) {
var config = em.getConfig(), var config = em.getConfig(),
panels = em.Panels; panels = em.Panels;
// Main container // Main container
this.$cn = $('<div/>'); this.$cn = $('<div></div>');
// Secondary container // Secondary container
this.$cn2 = $('<div/>'); this.$cn2 = $('<div></div>');
this.$cn.append(this.$cn2); this.$cn.append(this.$cn2);
// Device Manager // Device Manager
@ -27,12 +29,9 @@ module.exports = {
this.$cn2.append(em.StyleManager.render()); this.$cn2.append(em.StyleManager.render());
var smConfig = em.StyleManager.getConfig(); var smConfig = em.StyleManager.getConfig();
const pfx = smConfig.stylePrefix;
// Create header // Create header
this.$header = $('<div>', { this.$header = $(`<div class="${pfx}header">${smConfig.textNoElement}</div>`);
class: smConfig.stylePrefix + 'header',
text: smConfig.textNoElement,
});
//this.$cn = this.$cn.add(this.$header);
this.$cn.append(this.$header); this.$cn.append(this.$header);
// Create panel if not exists // Create panel if not exists

4
src/commands/view/OpenTraitManager.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = { module.exports = {
run(editor, sender) { run(editor, sender) {
@ -8,7 +10,7 @@ module.exports = {
if(!this.obj){ if(!this.obj){
var tmView = tm.getTraitsViewer(); var tmView = tm.getTraitsViewer();
var confTm = tm.getConfig(); var confTm = tm.getConfig();
this.obj = $('<div/>') this.obj = $('<div></div>')
.append('<div class="'+pfx+'traits-label">' + confTm.labelContainer + '</div>') .append('<div class="'+pfx+'traits-label">' + confTm.labelContainer + '</div>')
.get(0); .get(0);
this.obj.appendChild(tmView.render().el); this.obj.appendChild(tmView.render().el);

53
src/commands/view/SelectComponent.js

@ -1,7 +1,11 @@
var ToolbarView = require('dom_components/view/ToolbarView'); import {on, off} from 'utils/mixins'
var Toolbar = require('dom_components/model/Toolbar');
var key = require('keymaster'); const ToolbarView = require('dom_components/view/ToolbarView');
const Toolbar = require('dom_components/model/Toolbar');
const key = require('keymaster');
const Backbone = require('backbone');
let showOffsets; let showOffsets;
const $ = Backbone.$;
module.exports = { module.exports = {
@ -65,16 +69,6 @@ module.exports = {
} }
}, },
/**
* Returns canavs body el
*/
getCanvasBodyEl() {
if(!this.$bodyEl) {
this.$bodyEl = $(this.getCanvasBody());
}
return this.$bodyEl;
},
/** /**
* Start select component event * Start select component event
* @private * @private
@ -96,16 +90,15 @@ module.exports = {
* @private * @private
* */ * */
toggleSelectComponent(enable) { toggleSelectComponent(enable) {
var el = '*'; const method = enable ? 'on' : 'off';
var method = enable ? 'on' : 'off'; const methods = {on, off};
this.getCanvasBodyEl() const body = this.getCanvasBody();
[method]('mouseover', el, this.onHover) const win = this.getContentWindow();
[method]('mouseout', el, this.onOut) methods[method](body, 'mouseover', this.onHover);
[method]('click', el, this.onClick); methods[method](body, 'mouseout', this.onOut);
methods[method](body, 'click', this.onClick);
var cw = this.getContentWindow(); methods[method](win, 'scroll', this.onFrameScroll);
cw[method]('scroll', this.onFrameScroll); methods[method](win, 'keydown', this.onKeyPress);
cw[method]('keydown', this.onKeyPress);
}, },
/** /**
@ -144,7 +137,7 @@ module.exports = {
var trg = e.target; var trg = e.target;
// Adjust tools scroll top // Adjust tools scroll top
if(!this.adjScroll){ if (!this.adjScroll) {
this.adjScroll = 1; this.adjScroll = 1;
this.onFrameScroll(e); this.onFrameScroll(e);
this.updateAttached(); this.updateAttached();
@ -282,6 +275,7 @@ module.exports = {
updateHighlighter(el, pos) { updateHighlighter(el, pos) {
var $el = $(el); var $el = $(el);
var model = $el.data('model'); var model = $el.data('model');
if(!model || (model && model.get('status') == 'selected')) { if(!model || (model && model.get('status') == 'selected')) {
return; return;
} }
@ -333,12 +327,7 @@ module.exports = {
var modelToStyle; var modelToStyle;
var toggleBodyClass = (method, e, opts) => { var toggleBodyClass = (method, e, opts) => {
var handlerAttr = e.target.getAttribute(attrName); opts.docs && opts.docs.find('body')[method](resizeClass);
var resizeHndClass = pfx + 'resizing-' + handlerAttr;
var classToAdd = resizeClass;// + ' ' +resizeHndClass;
if (opts.docs) {
opts.docs.find('body')[method](classToAdd);
}
}; };
@ -553,9 +542,7 @@ module.exports = {
* @private * @private
*/ */
getContentWindow() { getContentWindow() {
if(!this.contWindow) return this.frameEl.contentWindow;
this.contWindow = $(this.frameEl.contentWindow);
return this.contWindow;
}, },
run(editor) { run(editor) {

2
src/commands/view/SelectPosition.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = { module.exports = {
/** /**

24
src/commands/view/ShowOffset.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = { module.exports = {
getOffsetMethod(state) { getOffsetMethod(state) {
@ -38,18 +40,20 @@ module.exports = {
var stateLow = state.toLowerCase(); var stateLow = state.toLowerCase();
var marginName = stateLow + 'margin-v'; var marginName = stateLow + 'margin-v';
var paddingName = stateLow + 'padding-v'; var paddingName = stateLow + 'padding-v';
var marginV = $('<div>', {class: ppfx + marginName}).get(0); var marginV = $(`<div class="${ppfx}marginName">`).get(0);
var paddingV = $('<div>', {class: ppfx + paddingName}).get(0); var paddingV = $(`<div class="${ppfx}paddingName">`).get(0);
var marginEls = ppfx + marginName + '-el'; var marginEls = ppfx + marginName + '-el';
var paddingEls = ppfx + paddingName + '-el'; var paddingEls = ppfx + paddingName + '-el';
marginT = $('<div>', {class: ppfx + marginName + '-top ' + marginEls}).get(0); const fullMargName = `${marginEls} ${ppfx + marginName}`;
marginB = $('<div>', {class: ppfx + marginName + '-bottom ' + marginEls}).get(0); const fullPadName = `${paddingEls} ${ppfx + paddingName}`;
marginL = $('<div>', {class: ppfx + marginName + '-left ' + marginEls}).get(0); marginT = $(`<div class="${fullMargName}-top"></div>`).get(0);
marginR = $('<div>', {class: ppfx + marginName + '-right ' + marginEls}).get(0); marginB = $(`<div class="${fullMargName}-bottom"></div>`).get(0);
padT = $('<div>', {class: ppfx + paddingName + '-top ' + paddingEls}).get(0); marginL = $(`<div class="${fullMargName}-left"></div>`).get(0);
padB = $('<div>', {class: ppfx + paddingName + '-bottom ' + paddingEls}).get(0); marginR = $(`<div class="${fullMargName}-right"></div>`).get(0);
padL = $('<div>', {class: ppfx + paddingName + '-left ' + paddingEls}).get(0); padT = $(`<div class="${fullPadName}-top"></div>`).get(0);
padR = $('<div>', {class: ppfx + paddingName + '-right ' + paddingEls}).get(0); padB = $(`<div class="${fullPadName}-bottom"></div>`).get(0);
padL = $(`<div class="${fullPadName}-left"></div>`).get(0);
padR = $(`<div class="${fullPadName}-right"></div>`).get(0);
this['marginT' + state] = marginT; this['marginT' + state] = marginT;
this['marginB' + state] = marginB; this['marginB' + state] = marginB;
this['marginL' + state] = marginL; this['marginL' + state] = marginL;

12
src/dom_components/view/ComponentTextView.js

@ -1,5 +1,6 @@
var Backbone = require('backbone'); import {on, off} from 'utils/mixins'
var ComponentView = require('./ComponentView');
const ComponentView = require('./ComponentView');
module.exports = ComponentView.extend({ module.exports = ComponentView.extend({
@ -100,11 +101,12 @@ module.exports = ComponentView.extend({
*/ */
toggleEvents(enable) { toggleEvents(enable) {
var method = enable ? 'on' : 'off'; var method = enable ? 'on' : 'off';
const mixins = {on, off};
// The ownerDocument is from the frame // The ownerDocument is from the frame
var elDocs = [this.el.ownerDocument, document, this.rte]; var elDocs = [this.el.ownerDocument, document];
$(elDocs).off('mousedown', this.disableEditing); mixins.off(elDocs, 'mousedown', this.disableEditing);
$(elDocs)[method]('mousedown', this.disableEditing); mixins[method](elDocs, 'mousedown', this.disableEditing);
// Avoid closing edit mode on component click // Avoid closing edit mode on component click
this.$el.off('mousedown', this.disablePropagation); this.$el.off('mousedown', this.disablePropagation);

17
src/dom_components/view/ComponentView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); const ComponentsView = require('./ComponentsView');
var ComponentsView = require('./ComponentsView'); const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
@ -29,9 +29,18 @@ module.exports = Backbone.View.extend({
this.listenTo(model, 'change:script', this.render); this.listenTo(model, 'change:script', this.render);
this.listenTo(model, 'change', this.handleChange); this.listenTo(model, 'change', this.handleChange);
this.listenTo(model.get('classes'), 'add remove change', this.updateClasses); this.listenTo(model.get('classes'), 'add remove change', this.updateClasses);
this.$el.data('model', model);
const $el = this.$el;
const el = this.el;
const em = this.em;
$el.data('model', model);
$el.data('collection', this.components);
model.view = this; model.view = this;
this.$el.data("collection", this.components);
if (em) {
em.data(el, 'model', model);
em.data(el, 'collection', model.get('components'));
}
if(model.get('classes').length) if(model.get('classes').length)
this.importClasses(); this.importClasses();

63
src/domain_abstract/ui/Input.js

@ -1,4 +1,4 @@
var Backbone = require('backbone'); const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
@ -6,24 +6,35 @@ module.exports = Backbone.View.extend({
'change': 'handleChange', 'change': 'handleChange',
}, },
template: _.template(`<span class='<%= holderClass %>'></span>`), template() {
const holderClass = this.holderClass;
return `<span class="${holderClass}"></span>`;
},
initialize(opts) { initialize(opts = {}) {
var opt = opts || {}; const ppfx = opts.ppfx || '';
var ppfx = opt.ppfx || ''; this.target = opts.target || {};
this.target = opt.target || {};
this.inputClass = ppfx + 'field'; this.inputClass = ppfx + 'field';
this.inputHolderClass = ppfx + 'input-holder'; this.inputHolderClass = ppfx + 'input-holder';
this.holderClass = `${ppfx}input-holder`;
this.ppfx = ppfx; this.ppfx = ppfx;
this.listenTo(this.model, 'change:value', this.handleModelChange); this.listenTo(this.model, 'change:value', this.handleModelChange);
}, },
/**
* Fired when the element of the property is updated
*/
elementUpdated() {
this.model.trigger('el:change');
},
/** /**
* Handled when the view is changed * Handled when the view is changed
*/ */
handleChange(e) { handleChange(e) {
e.stopPropagation(); e.stopPropagation();
this.setValue(this.getInputEl().value); this.model.set('value', this.getInputEl().value);
this.elementUpdated();
}, },
/** /**
@ -31,25 +42,18 @@ module.exports = Backbone.View.extend({
* @param {string} value * @param {string} value
* @param {Object} opts * @param {Object} opts
*/ */
setValue(value, opts) { setValue(value, opts = {}) {
var opt = opts || {}; const model = this.model;
var model = this.model; let val = value || model.get('defaults');
model.set({ const input = this.getInputEl();
value: value || model.get('defaults') input && (input.value = val);
}, opt);
// Generally I get silent when I need to reflect data to view without
// reupdating the target
if(opt.silent) {
this.handleModelChange(model, value, opt);
}
}, },
/** /**
* Updates the view when the model is changed * Updates the view when the model is changed
* */ * */
handleModelChange(model, value, opts) { handleModelChange(model, value, opts) {
this.getInputEl().value = this.model.get('value'); this.setValue(value, opts);
}, },
/** /**
@ -58,23 +62,20 @@ module.exports = Backbone.View.extend({
*/ */
getInputEl() { getInputEl() {
if(!this.inputEl) { if(!this.inputEl) {
this.inputEl = $('<input>', { const plh = this.model.get('defaults');
type: 'text', const cls = this.inputCls;
class: this.inputCls, this.inputEl = $(`<input type="text" class="${cls}" placeholder="${plh}">`);
placeholder: this.model.get('defaults')
});
} }
return this.inputEl.get(0); return this.inputEl.get(0);
}, },
render() { render() {
var el = this.$el; const el = this.$el;
const ppfx = this.ppfx;
const holderClass = this.holderClass;
el.addClass(this.inputClass); el.addClass(this.inputClass);
el.html(this.template({ el.html(this.template());
holderClass: this.inputHolderClass, el.find(`.${holderClass}`).append(this.getInputEl());
ppfx: this.ppfx
}));
el.find('.'+ this.inputHolderClass).html(this.getInputEl());
return this; return this;
} }

45
src/domain_abstract/ui/InputColor.js

@ -1,20 +1,25 @@
var Backbone = require('backbone'); const Input = require('./Input');
var Input = require('./Input'); //require('spectrum-colorpicker');
var Spectrum = require('spectrum-colorpicker'); require('utils/ColorPicker');
const $ = Backbone.$;
module.exports = Input.extend({ module.exports = Input.extend({
template: _.template(` template() {
<div class='<%= ppfx %>input-holder'></div> const ppfx = this.ppfx;
<div class="<%= ppfx %>field-colorp"> return `
<div class="<%= ppfx %>field-colorp-c"> <div class="${ppfx}input-holder"></div>
<div class="<%= ppfx %>checker-bg"></div> <div class="${ppfx}field-colorp">
</div> <div class="${ppfx}field-colorp-c">
</div>`), <div class="${ppfx}checker-bg"></div>
</div>
</div>
`;
},
initialize(opts) { initialize(opts) {
Input.prototype.initialize.apply(this, arguments); Input.prototype.initialize.apply(this, arguments);
var ppfx = this.ppfx; const ppfx = this.ppfx;
this.colorCls = `${ppfx}field-color-picker`; this.colorCls = `${ppfx}field-color-picker`;
this.inputClass = `${ppfx}field ${ppfx}field-color`; this.inputClass = `${ppfx}field ${ppfx}field-color`;
this.colorHolderClass = `${ppfx}field-colorp-c`; this.colorHolderClass = `${ppfx}field-colorp-c`;
@ -55,14 +60,10 @@ module.exports = Input.extend({
if (!this.colorEl) { if (!this.colorEl) {
const self = this; const self = this;
var model = this.model; var model = this.model;
var colorEl = $('<div>', {class: this.colorCls});
var colorEl = $(`<div class="${this.colorCls}"></div>`);
var cpStyle = colorEl.get(0).style; var cpStyle = colorEl.get(0).style;
var elToAppend = this.target && this.target.config ? this.target.config.el : ''; var elToAppend = this.target && this.target.config ? this.target.config.el : '';
if (typeof colorEl.spectrum == 'undefined') {
throw 'Spectrum missing, probably you load jQuery twice';
}
const getColor = color => { const getColor = color => {
let cl = color.getAlpha() == 1 ? color.toHexString() : color.toRgbString(); let cl = color.getAlpha() == 1 ? color.toHexString() : color.toRgbString();
return cl.replace(/ /g, ''); return cl.replace(/ /g, '');
@ -70,6 +71,8 @@ module.exports = Input.extend({
let changed = 0; let changed = 0;
let previousСolor; let previousСolor;
this.$el.find(`.${this.colorHolderClass}`).append(colorEl);
colorEl.spectrum({ colorEl.spectrum({
appendTo: elToAppend || 'body', appendTo: elToAppend || 'body',
maxSelectionSize: 8, maxSelectionSize: 8,
@ -106,14 +109,16 @@ module.exports = Input.extend({
} }
} }
}); });
this.colorEl = colorEl; this.colorEl = colorEl;
} }
return this.colorEl; return this.colorEl;
}, },
render(...args) { render() {
Input.prototype.render.apply(this, args); Input.prototype.render.call(this);
this.$el.find('.' + this.colorHolderClass).html(this.getColorEl()); // This will make the color input available on render
this.getColorEl();
return this; return this;
} }

68
src/domain_abstract/ui/InputNumber.js

@ -1,8 +1,9 @@
var Backbone = require('backbone'); import {on, off} from 'utils/mixins'
module.exports = Backbone.View.extend({ const Backbone = require('backbone');
const $ = Backbone.$;
events: {}, module.exports = Backbone.View.extend({
template: _.template(` template: _.template(`
<span class='<%= ppfx %>input-holder'></span> <span class='<%= ppfx %>input-holder'></span>
@ -18,16 +19,16 @@ module.exports = Backbone.View.extend({
var ppfx = opt.ppfx || ''; var ppfx = opt.ppfx || '';
var contClass = opt.contClass || (`${ppfx}field ${ppfx}field-integer`); var contClass = opt.contClass || (`${ppfx}field ${ppfx}field-integer`);
this.ppfx = ppfx; this.ppfx = ppfx;
this.docEl = $(document); this.doc = document;
this.inputCls = ppfx + 'field-number'; this.inputCls = ppfx + 'field-number';
this.unitCls = ppfx + 'input-unit'; this.unitCls = ppfx + 'input-unit';
this.contClass = contClass; this.contClass = contClass;
this.events['click .' + ppfx + 'field-arrow-u'] = 'upArrowClick'; this.events = {};
this.events['click .' + ppfx + 'field-arrow-d'] = 'downArrowClick'; this.events[`click .${ppfx}field-arrow-u`] = 'upArrowClick';
this.events['mousedown .' + ppfx + 'field-arrows'] = 'downIncrement'; this.events[`click .${ppfx}field-arrow-d`] = 'downArrowClick';
this.events['change .' + this.inputCls] = 'handleChange'; this.events[`mousedown .${ppfx}field-arrows`] = 'downIncrement';
this.events['change .' + this.unitCls] = 'handleUnitChange'; this.events[`change .${this.inputCls}`] = 'handleChange';
this.events[`change .${this.unitCls}`] = 'handleUnitChange';
this.listenTo(this.model, 'change:unit change:value', this.handleModelChange); this.listenTo(this.model, 'change:unit change:value', this.handleModelChange);
this.delegateEvents(); this.delegateEvents();
}, },
@ -100,12 +101,10 @@ module.exports = Backbone.View.extend({
* @return {HTMLElement} * @return {HTMLElement}
*/ */
getInputEl() { getInputEl() {
if(!this.inputEl) { if (!this.inputEl) {
this.inputEl = $('<input>', { const cls = this.inputCls;
type: 'text', const plh = this.model.get('defaults');
class: this.inputCls, this.inputEl = $(`<input type="text" class="${cls}" placeholder="${plh}">`);
placeholder: this.model.get('defaults')
});
} }
return this.inputEl.get(0); return this.inputEl.get(0);
}, },
@ -125,10 +124,12 @@ module.exports = Backbone.View.extend({
unitStr += '<option ' + selected + ' >' + unit + '</option>'; unitStr += '<option ' + selected + ' >' + unit + '</option>';
}); });
unitStr += '</select>'; unitStr += '</select>';
this.unitEl = $(unitStr); const temp = document.createElement('div');
temp.innerHTML = unitStr;
this.unitEl = temp.firstChild;
} }
} }
return this.unitEl && this.unitEl.get(0); return this.unitEl;
}, },
/** /**
@ -138,7 +139,6 @@ module.exports = Backbone.View.extend({
const model = this.model; const model = this.model;
const step = model.get('step'); const step = model.get('step');
let value = model.get('value'); let value = model.get('value');
//value = isNaN(value) ? 1 * step : parseFloat(value);
value = this.normalizeValue(value + step); value = this.normalizeValue(value + step);
var valid = this.validateInputValue(value); var valid = this.validateInputValue(value);
model.set('value', valid.value); model.set('value', valid.value);
@ -169,9 +169,9 @@ module.exports = Backbone.View.extend({
this.moved = 0; this.moved = 0;
var value = this.model.get('value'); var value = this.model.get('value');
value = this.normalizeValue(value); value = this.normalizeValue(value);
var current = {y: e.pageY, val: value}; this.current = {y: e.pageY, val: value};
this.docEl.mouseup(current, this.upIncrement); on(this.doc, 'mousemove', this.moveIncrement);
this.docEl.mousemove(current, this.moveIncrement); on(this.doc, 'mouseup', this.upIncrement);
}, },
/** While the increment is clicked, moving the mouse will update input value /** While the increment is clicked, moving the mouse will update input value
@ -183,7 +183,8 @@ module.exports = Backbone.View.extend({
this.moved = 1; this.moved = 1;
const model = this.model; const model = this.model;
const step = model.get('step'); const step = model.get('step');
var pos = this.normalizeValue(ev.data.val + (ev.data.y - ev.pageY) * step); const data = this.current;
var pos = this.normalizeValue(data.val + (data.y - ev.pageY) * step);
this.prValue = this.validateInputValue(pos).value; this.prValue = this.validateInputValue(pos).value;
model.set('value', this.prValue, {avoidStore: 1}); model.set('value', this.prValue, {avoidStore: 1});
return false; return false;
@ -191,15 +192,12 @@ module.exports = Backbone.View.extend({
/** /**
* Stop moveIncrement method * Stop moveIncrement method
* @param Object
*
* @return void
* */ * */
upIncrement(e) { upIncrement() {
const model = this.model; const model = this.model;
const step = model.get('step'); const step = model.get('step');
this.docEl.off('mouseup', this.upIncrement); off(this.doc, 'mouseup', this.upIncrement);
this.docEl.off('mousemove', this.moveIncrement); off(this.doc, 'mousemove', this.moveIncrement);
if(this.prValue && this.moved) { if(this.prValue && this.moved) {
var value = this.prValue - step; var value = this.prValue - step;
@ -280,11 +278,13 @@ module.exports = Backbone.View.extend({
}, },
render() { render() {
var ppfx = this.ppfx; const ppfx = this.ppfx;
this.$el.html(this.template({ppfx})); const el = this.$el;
this.$el.find('.'+ ppfx +'input-holder').html(this.getInputEl()); el.html(this.template({ppfx}));
this.$el.find('.' + ppfx + 'field-units').html(this.getUnitEl()); el.find(`.${ppfx}input-holder`).append(this.getInputEl());
this.$el.addClass(this.contClass); const unit = this.getUnitEl();
unit && el.find(`.${ppfx}field-units`).get(0).appendChild(unit);
el.addClass(this.contClass);
return this; return this;
} }

5
src/editor/index.js

@ -38,6 +38,8 @@
* * `component:styleUpdate` - Triggered when the style of the component is updated * * `component:styleUpdate` - Triggered when the style of the component is updated
* * `component:styleUpdate:{propertyName}` - Listen for a specific style property change * * `component:styleUpdate:{propertyName}` - Listen for a specific style property change
* * `component:selected` - New component selected * * `component:selected` - New component selected
* * `block:add` - New block added
* * `block:remove` - Block removed
* * `asset:add` - New asset added * * `asset:add` - New asset added
* * `asset:remove` - Asset removed * * `asset:remove` - Asset removed
* * `asset:upload:start` - Before the upload is started * * `asset:upload:start` - Before the upload is started
@ -46,8 +48,11 @@
* * `asset:upload:response` - On upload response, passes the result as an argument * * `asset:upload:response` - On upload response, passes the result as an argument
* * `styleManager:change` - Triggered on style property change from new selected component, the view of the property is passed as an argument to the callback * * `styleManager:change` - Triggered on style property change from new selected component, the view of the property is passed as an argument to the callback
* * `styleManager:change:{propertyName}` - As above but for a specific style property * * `styleManager:change:{propertyName}` - As above but for a specific style property
* * `storage:start` - Before the storage request is started
* * `storage:load` - Triggered when something was loaded from the storage, loaded object passed as an argumnet * * `storage:load` - Triggered when something was loaded from the storage, loaded object passed as an argumnet
* * `storage:store` - Triggered when something is stored to the storage, stored object passed as an argumnet * * `storage:store` - Triggered when something is stored to the storage, stored object passed as an argumnet
* * `storage:end` - After the storage request is ended
* * `storage:error` - On any error on storage request, passes the error as an argument
* * `selector:add` - Triggers when a new selector/class is created * * `selector:add` - Triggers when a new selector/class is created
* * `canvasScroll` - Triggered when the canvas is scrolled * * `canvasScroll` - Triggered when the canvas is scrolled
* * `run:{commandName}` - Triggered when some command is called to run (eg. editor.runCommand('preview')) * * `run:{commandName}` - Triggered when some command is called to run (eg. editor.runCommand('preview'))

77
src/editor/model/Editor.js

@ -1,31 +1,36 @@
var deps = [ import { isUndefined, defaults } from 'underscore';
require('utils'),
require('storage_manager'), const deps = [
require('device_manager'), require('utils'),
require('parser'), require('storage_manager'),
require('selector_manager'), require('device_manager'),
require('modal_dialog'), require('parser'),
require('code_manager'), require('selector_manager'),
require('panels'), require('modal_dialog'),
require('rich_text_editor'), require('code_manager'),
require('style_manager'), require('panels'),
require('asset_manager'), require('rich_text_editor'),
require('css_composer'), require('style_manager'),
require('dom_components'), require('asset_manager'),
require('canvas'), require('css_composer'),
require('commands'), require('dom_components'),
require('block_manager'), require('canvas'),
require('trait_manager'), require('commands'),
require('block_manager'),
require('trait_manager'),
]; ];
var Backbone = require('backbone'); const Backbone = require('backbone');
var UndoManager = require('backbone-undo'); const UndoManager = require('backbone-undo');
var key = require('keymaster'); const key = require('keymaster');
var timedInterval; let timedInterval;
if (!Backbone.$) { require('utils/extender')({
Backbone.$ = $; Backbone: Backbone,
} $: Backbone.$
});
const $ = Backbone.$;
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
@ -607,4 +612,26 @@ module.exports = Backbone.Model.extend({
w.getSelection().removeAllRanges(); w.getSelection().removeAllRanges();
}, },
/**
* Set/get data from the HTMLElement
* @param {HTMLElement} el
* @param {string} name Data name
* @param {any} value Date value
* @return {any}
* @private
*/
data(el, name, value) {
const varName = '_gjs-data';
if (!el[varName]) {
el[varName] = {};
}
if (isUndefined(value)) {
return el[varName][name];
} else {
el[varName][name] = value;
}
}
}); });

2
src/editor/view/EditorView.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
initialize() { initialize() {

14
src/grapesjs/index.js

@ -1,4 +1,5 @@
import { isUndefined, defaults } from 'underscore'; import $ from 'cash-dom';
import { defaults } from 'underscore';
module.exports = (() => { module.exports = (() => {
const defaultConfig = require('./config/config'); const defaultConfig = require('./config/config');
@ -9,13 +10,15 @@ module.exports = (() => {
return { return {
// Will be replaced on build $,
version: '<# VERSION #>',
editors, editors,
plugins, plugins,
// Will be replaced on build
version: '<# VERSION #>',
/** /**
* Initializes an editor based on passed options * Initializes an editor based on passed options
* @param {Object} config Configuration object * @param {Object} config Configuration object
@ -37,11 +40,6 @@ module.exports = (() => {
init(config = {}) { init(config = {}) {
const els = config.container; const els = config.container;
// Make a missing $ more verbose
if (isUndefined($)) {
throw 'jQuery not found';
}
if (!els) { if (!els) {
throw new Error("'container' is required"); throw new Error("'container' is required");
} }

15
src/modal_dialog/view/ModalView.js

@ -48,8 +48,12 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
getContent() { getContent() {
if(!this.$content) const pfx = this.pfx;
this.$content = this.$el.find('.'+this.pfx+'content #'+this.pfx+'c');
if (!this.$content) {
this.$content = this.$el.find(`.${pfx}content #${pfx}c`);
}
return this.$content; return this.$content;
}, },
@ -70,8 +74,11 @@ module.exports = Backbone.View.extend({
* */ * */
updateContent() { updateContent() {
var content = this.getContent(); var content = this.getContent();
this.getCollector().append(content.children()); const children = content.children();
content.html(this.model.get('content')); const coll = this.getCollector();
const body = this.model.get('content');
children.length && coll.append(children);
content.empty().append(body);
}, },
/** /**

99
src/navigator/view/ItemView.js

@ -36,29 +36,32 @@ module.exports = Backbone.View.extend({
this.ppfx = this.em.get('Config').stylePrefix; this.ppfx = this.em.get('Config').stylePrefix;
this.sorter = o.sorter || ''; this.sorter = o.sorter || '';
this.pfx = this.config.stylePrefix; this.pfx = this.config.stylePrefix;
if(typeof this.model.get('open') == 'undefined') const pfx = this.pfx;
this.model.set('open',false); const ppfx = this.ppfx;
this.listenTo(this.model.get('components'), 'remove add change reset', this.checkChildren); const model = this.model;
this.listenTo(this.model, 'destroy remove', this.remove); const components = model.get('components');
this.listenTo(this.model, 'change:status', this.updateStatus); model.set('open', false);
this.listenTo(this.model, 'change:open', this.updateOpening); this.listenTo(components, 'remove add change reset', this.checkChildren);
this.className = this.pfx + 'item no-select'; this.listenTo(model, 'destroy remove', this.remove);
this.editBtnCls = this.pfx + 'nav-item-edit'; this.listenTo(model, 'change:status', this.updateStatus);
this.inputNameCls = this.ppfx + 'nav-comp-name'; this.listenTo(model, 'change:open', this.updateOpening);
this.caretCls = this.ppfx + 'nav-item-caret'; this.className = `${pfx}item no-select`;
this.titleCls = this.pfx + 'title'; this.editBtnCls = `${pfx}nav-item-edit`;
this.inputNameCls = `${ppfx}nav-comp-name`;
this.caretCls = `${ppfx}nav-item-caret`;
this.titleCls = `${pfx}title`;
this.events = {}; this.events = {};
this.events['click > #'+this.pfx+'btn-eye'] = 'toggleVisibility'; this.events[`click #${pfx}btn-eye`] = 'toggleVisibility';
this.events['click .' + this.caretCls] = 'toggleOpening'; this.events['click .' + this.caretCls] = 'toggleOpening';
this.events['click .' + this.titleCls] = 'handleSelect'; this.events['click .' + this.titleCls] = 'handleSelect';
this.events['click .' + this.editBtnCls] = 'handleEdit'; this.events['click .' + this.editBtnCls] = 'handleEdit';
this.events['blur .' + this.inputNameCls] = 'handleEditEnd'; this.events['blur .' + this.inputNameCls] = 'handleEditEnd';
this.$el.data('model', this.model); this.$el.data('model', model);
this.$el.data('collection', this.model.get('components')); this.$el.data('collection', components);
if(o.config.sortable) if(o.config.sortable)
this.events['mousedown > #'+this.pfx+'move'] = 'startSort'; this.events['mousedown #'+pfx+'move'] = 'startSort';
this.delegateEvents(); this.delegateEvents();
}, },
@ -102,13 +105,15 @@ module.exports = Backbone.View.extend({
updateOpening() { updateOpening() {
var opened = this.opt.opened || {}; var opened = this.opt.opened || {};
var model = this.model; var model = this.model;
if(model.get('open')){ const chvDown = 'fa-chevron-down';
this.$el.addClass("open");
this.getCaret().addClass('fa-chevron-down'); if (model.get('open')) {
this.$el.addClass('open');
this.getCaret().addClass(chvDown);
opened[model.cid] = model; opened[model.cid] = model;
}else{ } else {
this.$el.removeClass("open"); this.$el.removeClass("open");
this.getCaret().removeClass('fa-chevron-down'); this.getCaret().removeClass(chvDown);
delete opened[model.cid]; delete opened[model.cid];
} }
}, },
@ -183,8 +188,11 @@ module.exports = Backbone.View.extend({
* @return void * @return void
* */ * */
toggleVisibility(e) { toggleVisibility(e) {
e.stopPropagation();
const pfx = this.pfx;
if(!this.$eye) if(!this.$eye)
this.$eye = this.$el.find('> #'+this.pfx+'btn-eye'); this.$eye = this.$el.children(`#${pfx}btn-eye`);
var cCss = _.clone(this.model.get('style')), var cCss = _.clone(this.model.get('style')),
hClass = this.pfx + 'hide'; hClass = this.pfx + 'hide';
@ -219,18 +227,23 @@ module.exports = Backbone.View.extend({
* @return void * @return void
* */ * */
checkChildren() { checkChildren() {
var c = this.countChildren(this.model), const model = this.model;
pfx = this.pfx, const c = this.countChildren(model);
tC = '> .' + pfx + 'title-c > .' + pfx + 'title'; const pfx = this.pfx;
if(!this.$counter) const noChildCls = `${pfx}no-chld`;
this.$counter = this.$el.find('> #' + pfx + 'counter'); const title = this.$el.children(`.${pfx}title-c`).children(`.${pfx}title`);
if(c){ //tC = `> .${pfx}title-c > .${pfx}title`;
this.$el.find(tC).removeClass(pfx + 'no-chld'); if (!this.$counter) {
this.$counter = this.$el.children(`#${pfx}counter`);
}
if (c) {
title.removeClass(noChildCls);
this.$counter.html(c); this.$counter.html(c);
}else{ } else {
this.$el.find(tC).addClass(pfx + 'no-chld'); title.addClass(noChildCls);
this.$counter.empty(); this.$counter.empty();
this.model.set('open',0); model.set('open', 0);
} }
}, },
@ -255,8 +268,9 @@ module.exports = Backbone.View.extend({
getCaret() { getCaret() {
if (!this.caret) { if (!this.caret) {
const pfx = this.pfx; const pfx = this.pfx;
this.caret = this.$el.find(`> .${pfx}title-c > .${pfx}title > .${pfx}title-inn > #${pfx}caret`); this.caret = this.$el.children(`.${pfx}title-c`).find(`#${pfx}caret`);
} }
return this.caret; return this.caret;
}, },
@ -265,9 +279,10 @@ module.exports = Backbone.View.extend({
var pfx = this.pfx; var pfx = this.pfx;
var vis = this.isVisible(); var vis = this.isVisible();
var count = this.countChildren(model); var count = this.countChildren(model);
const el = this.$el;
const level = this.level + 1; const level = this.level + 1;
this.$el.html( this.template({ el.html( this.template({
title: model.getName(), title: model.getName(),
icon: model.getIcon(), icon: model.getIcon(),
addClass: (count ? '' : pfx+'no-chld'), addClass: (count ? '' : pfx+'no-chld'),
@ -282,9 +297,11 @@ module.exports = Backbone.View.extend({
level level
})); }));
if(typeof ItemsView == 'undefined') if (typeof ItemsView == 'undefined') {
ItemsView = require('./ItemsView'); ItemsView = require('./ItemsView');
this.$components = new ItemsView({ }
const children = new ItemsView({
collection: model.get('components'), collection: model.get('components'),
config: this.config, config: this.config,
sorter: this.sorter, sorter: this.sorter,
@ -292,13 +309,15 @@ module.exports = Backbone.View.extend({
parent: model, parent: model,
level level
}).render().$el; }).render().$el;
this.$el.find('.'+ pfx +'children').html(this.$components); el.find(`.${pfx}children`).append(children);
if(!model.get('draggable') || !this.config.sortable){
this.$el.find('> #' + pfx + 'move').detach(); if(!model.get('draggable') || !this.config.sortable) {
el.children(`#${pfx}move`).remove();
} }
if(!vis) if(!vis)
this.className += ' ' + pfx + 'hide'; this.className += ' ' + pfx + 'hide';
this.$el.attr('class', _.result(this, 'className')); el.attr('class', _.result(this, 'className'));
this.updateOpening(); this.updateOpening();
this.updateStatus(); this.updateStatus();
return this; return this;

2
src/panels/view/ButtonView.js

@ -1,4 +1,4 @@
var Backbone = require('backbone'); const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({

3
src/rich_text_editor/index.js

@ -21,12 +21,15 @@
* http://www.quirksmode.org/dom/execCommand.html * http://www.quirksmode.org/dom/execCommand.html
* @module RichTextEditor * @module RichTextEditor
*/ */
const $ = Backbone.$;
module.exports = () => { module.exports = () => {
var c = {}, var c = {},
defaults = require('./config/config'), defaults = require('./config/config'),
rte = require('./view/TextEditorView'), rte = require('./view/TextEditorView'),
CommandButtons = require('./model/CommandButtons'), CommandButtons = require('./model/CommandButtons'),
CommandButtonsView = require('./view/CommandButtonsView'); CommandButtonsView = require('./view/CommandButtonsView');
const $ = require('backbone').$;
var tlbPfx, toolbar, commands; var tlbPfx, toolbar, commands;
var mainSelf; var mainSelf;

4
src/rich_text_editor/view/CommandButtonSelectView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); const CommandButtonView = require('./CommandButtonView');
var CommandButtonView = require('./CommandButtonView'); const $ = Backbone.$;
module.exports = CommandButtonView.extend({ module.exports = CommandButtonView.extend({

15
src/rich_text_editor/view/TextEditorView.js

@ -1,3 +1,6 @@
const Backbone = require('backbone');
const $ = Backbone.$;
var readFileIntoDataUrl = fileInfo => { var readFileIntoDataUrl = fileInfo => {
var loader = $.Deferred(), var loader = $.Deferred(),
fReader = new FileReader(); fReader = new FileReader();
@ -106,7 +109,7 @@ $.fn.wysiwyg = function (userOptions) {
input.data(options.selectionMarker, color); input.data(options.selectionMarker, color);
}, },
bindToolbar = (toolbar, options) => { bindToolbar = (toolbar, options) => {
toolbar.find(toolbarBtnSelector).unbind().click(function () { toolbar.find(toolbarBtnSelector).off('click').on('click',function () {
restoreSelection(); restoreSelection();
//editor.focus(); // cause defocus on selects //editor.focus(); // cause defocus on selects
var doc = editor.get(0).ownerDocument; var doc = editor.get(0).ownerDocument;
@ -121,7 +124,7 @@ $.fn.wysiwyg = function (userOptions) {
} }
saveSelection(); saveSelection();
}); });
toolbar.find('[data-toggle=dropdown]').click(restoreSelection); toolbar.find('[data-toggle=dropdown]').on('click', restoreSelection);
var dName = '[data-' + options.commandRole + ']'; var dName = '[data-' + options.commandRole + ']';
toolbar.find('select'+dName).on('webkitspeechchange change', function(){ toolbar.find('select'+dName).on('webkitspeechchange change', function(){
var newValue = this.value; var newValue = this.value;
@ -153,7 +156,7 @@ $.fn.wysiwyg = function (userOptions) {
markSelection(input, false); markSelection(input, false);
} }
}); });
toolbar.find('input[type=file][data-' + options.commandRole + ']').change(function () { toolbar.find('input[type=file][data-' + options.commandRole + ']').on('change', function () {
restoreSelection(); restoreSelection();
if (this.type === 'file' && this.files && this.files.length > 0) { if (this.type === 'file' && this.files && this.files.length > 0) {
insertFiles(this.files); insertFiles(this.files);
@ -176,8 +179,8 @@ $.fn.wysiwyg = function (userOptions) {
/** Disable the editor /** Disable the editor
* @date 2015-03-19 */ * @date 2015-03-19 */
if(typeof userOptions=='string' && userOptions=='destroy'){ if(typeof userOptions=='string' && userOptions=='destroy'){
editor.attr('contenteditable', false).unbind('mouseup keyup mouseout dragenter dragover'); editor.attr('contenteditable', false).off('mouseup keyup mouseout dragenter dragover');
$(window).unbind('touchend'); $(window).off('touchend');
return this; return this;
} }
options = $.extend({}, $.fn.wysiwyg.defaults, userOptions); options = $.extend({}, $.fn.wysiwyg.defaults, userOptions);
@ -192,7 +195,7 @@ $.fn.wysiwyg = function (userOptions) {
saveSelection(); saveSelection();
updateToolbar(); updateToolbar();
}); });
$(window).bind('touchend', e => { $(window).on('touchend', e => {
var isInside = (editor.is(e.target) || editor.has(e.target).length > 0), var isInside = (editor.is(e.target) || editor.has(e.target).length > 0),
currentRange = getCurrentRange(), currentRange = getCurrentRange(),
clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset); clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset);

28
src/selector_manager/view/ClassTagView.js

@ -9,8 +9,6 @@ module.exports = Backbone.View.extend({
</span> </span>
<span id="<%= pfx %>close">&Cross;</span>`), <span id="<%= pfx %>close">&Cross;</span>`),
events: {},
initialize(o) { initialize(o) {
this.config = o.config || {}; this.config = o.config || {};
this.coll = o.coll || null; this.coll = o.coll || null;
@ -22,6 +20,7 @@ module.exports = Backbone.View.extend({
this.closeId = this.pfx + 'close'; this.closeId = this.pfx + 'close';
this.chkId = this.pfx + 'checkbox'; this.chkId = this.pfx + 'checkbox';
this.labelId = this.pfx + 'tag-label'; this.labelId = this.pfx + 'tag-label';
this.events = {};
this.events['click #' + this.closeId ] = 'removeTag'; this.events['click #' + this.closeId ] = 'removeTag';
this.events['click #' + this.chkId ] = 'changeStatus'; this.events['click #' + this.chkId ] = 'changeStatus';
this.events['dblclick #' + this.labelId ] = 'startEditTag'; this.events['dblclick #' + this.labelId ] = 'startEditTag';
@ -77,17 +76,15 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
removeTag(e) { removeTag(e) {
var comp = this.target.get('selectedComponent'); const em = this.target;
const model = this.model;
if(comp) const coll = this.coll;
comp.get('classes').remove(this.model); const el = this.el;
const sel = em && em.get('selectedComponent');
if(this.coll){ sel && sel.get & sel.get('classes').remove(model);
this.coll.remove(this.model); coll && coll.remove(model);
this.target.trigger('targetClassRemoved'); setTimeout(() => this.remove(), 0);
} em && em.trigger('targetClassRemoved');
this.remove();
}, },
/** /**
@ -115,8 +112,11 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
updateInputLabel() { updateInputLabel() {
if(!this.$labelInput) if(!this.$labelInput) {
this.$labelInput = this.$el.find('input'); this.$labelInput = this.$el.find('input');
}
this.$labelInput.prop(this.inputProp, true);
var size = this.$labelInput.val().length - 1; var size = this.$labelInput.val().length - 1;
size = size < 1 ? 1 : size; size = size < 1 ? 1 : size;
this.$labelInput.attr('size', size); this.$labelInput.attr('size', size);

4
src/selector_manager/view/ClassTagsView.js

@ -97,7 +97,7 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
startNewTag(e) { startNewTag(e) {
this.$addBtn.hide(); this.$addBtn.get(0).style.display = 'none';
this.$input.show().focus(); this.$input.show().focus();
}, },
@ -107,7 +107,7 @@ module.exports = Backbone.View.extend({
* @private * @private
*/ */
endNewTag(e) { endNewTag(e) {
this.$addBtn.show(); this.$addBtn.get(0).style.display = '';
this.$input.hide().val(''); this.$input.hide().val('');
}, },

5
src/storage_manager/config/config.js

@ -32,9 +32,12 @@ module.exports = {
checkLocal: 1, checkLocal: 1,
// ONLY FOR REMOTE STORAGE // ONLY FOR REMOTE STORAGE
// Custom params that should be passed with each store/load request // Custom parameters to pass with the remote storage request, eg. csrf token
params: {}, params: {},
// Custom headers for the remote storage request
headers: {},
// Endpoint where to save all stuff // Endpoint where to save all stuff
urlStore: '', urlStore: '',

3
src/storage_manager/index.js

@ -57,7 +57,8 @@ module.exports = () => {
*/ */
init(config) { init(config) {
c = config || {}; c = config || {};
for (var name in defaults){
for (var name in defaults) {
if (!(name in c)) if (!(name in c))
c[name] = defaults[name]; c[name] = defaults[name];
} }

165
src/storage_manager/model/RemoteStorage.js

@ -1,6 +1,9 @@
var Backbone = require('backbone'); import fetch from 'utils/fetch';
import { isUndefined } from 'underscore';
module.exports = Backbone.Model.extend({ module.exports = require('backbone').Model.extend({
fetch,
defaults: { defaults: {
urlStore: '', urlStore: '',
@ -12,67 +15,121 @@ module.exports = Backbone.Model.extend({
}, },
/** /**
* Triggered before the request is started
* @private * @private
*/ */
store(data, clb) { onStart() {
var fd = {}, const em = this.get('em');
params = this.get('params'); const before = this.get('beforeSend');
before && before();
for(var k in data) em && em.trigger('storage:start');
fd[k] = data[k]; },
for(var key in params) /**
fd[key] = params[key]; * Triggered on request error
* @param {Object} err Error
let req = $.ajax({ * @private
url: this.get('urlStore'), */
beforeSend: this.get('beforeSend'), onError(err) {
complete: this.get('onComplete'), const em = this.get('em');
method: 'POST', console.error(err);
dataType: 'json', em && em.trigger('storage:error', err);
contentType: this.get('contentTypeJson') ? 'application/json; charset=utf-8': 'x-www-form-urlencoded', this.onEnd(err);
data: this.get('contentTypeJson') ? JSON.stringify(fd): fd,
});
// Assign always callback when possible
req && req.always && req.always(() => {
if (typeof clb == 'function') {
clb();
}
});
}, },
/** /**
* Triggered after the request is ended
* @param {Object|string} res End result
* @private * @private
*/ */
onEnd(res) {
const em = this.get('em');
em && em.trigger('storage:end', res);
},
/**
* Triggered on request response
* @param {string} text Response text
* @private
*/
onResponse(text, clb) {
const em = this.get('em');
const complete = this.get('onComplete');
const typeJson = this.get('contentTypeJson');
const res = typeJson && typeof text === 'string' ? JSON.parse(text): text;
complete && complete(res);
clb && clb(res);
em && em.trigger('storage:response', res);
this.onEnd(text);
},
store(data, clb) {
const body = {};
for (let key in data) {
body[key] = data[key];
}
this.request(this.get('urlStore'), {body}, clb);
},
load(keys, clb) { load(keys, clb) {
var result = {}, this.request(this.get('urlLoad'), {body: {keys}}, clb);
fd = {}, },
params = this.get('params');
/**
for(var key in params) * Execute remote request
fd[key] = params[key]; * @param {string} url Url
* @param {Object} [opts={}] Options
fd.keys = keys; * @param {[type]} [clb=null] Callback
* @private
let req = $.ajax({ */
url: this.get('urlLoad'), request(url, opts = {}, clb = null) {
beforeSend: this.get('beforeSend'), const typeJson = this.get('contentTypeJson');
complete: this.get('onComplete'), const headers = this.get('headers') || {};
data: fd, const params = this.get('params');
async: false, const reqHead = 'X-Requested-With';
method: 'GET', const typeHead = 'Content-Type';
}).done(d => { const bodyObj = opts.body || {};
result = d; let body;
});
for (let param in params) {
// Assign always callback when possible bodyObj[param] = params[param];
req && req.always && req.always((res) => { }
if (typeof clb == 'function') {
clb(res); if (isUndefined(headers[reqHead])) {
headers[reqHead] = 'XMLHttpRequest';
}
// With `fetch`, have to send FormData without any 'Content-Type'
// https://stackoverflow.com/questions/39280438/fetch-missing-boundary-in-multipart-form-data-post
if (isUndefined(headers[typeHead]) && typeJson) {
headers[typeHead] = 'application/json; charset=utf-8';
}
if (typeJson) {
body = JSON.stringify(bodyObj);
} else {
body = new FormData();
for (let bodyKey in bodyObj) {
body.append(bodyKey, bodyObj[bodyKey]);
} }
}); }
return result;
this.onStart();
this.fetch(url, {
method: opts.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.onResponse(text, clb))
.catch(err => this.onError(err));
}, },
}); });

25
src/style_manager/model/Layer.js

@ -1,17 +1,20 @@
var Backbone = require('backbone');
module.exports = Backbone.Model.extend({ module.exports = Backbone.Model.extend({
defaults: { defaults: {
index: '', index: '',
value: '', value: '',
values: {}, values: {},
active: true, active: false,
preview: false, preview: false,
properties: [],
}, },
initialize() { initialize() {
const Properties = require('./Properties');
const properties = this.get('properties');
var value = this.get('value'); var value = this.get('value');
this.set('properties', properties instanceof Properties ?
properties : new Properties(properties));
// If there is no value I'll try to get it from values // If there is no value I'll try to get it from values
// I need value setted to make preview working // I need value setted to make preview working
@ -27,4 +30,20 @@ module.exports = Backbone.Model.extend({
} }
}, },
getPropertyValue(property) {
let result = '';
this.get('properties').each(prop => {
if (prop.get('property') == property) {
result = prop.getFullValue();
}
});
return result;
},
getFullValue() {
let result = [];
this.get('properties').each(prop => result.push(prop.getFullValue()));
return result.join(' ');
}
}); });

99
src/style_manager/model/Layers.js

@ -1,5 +1,4 @@
var Backbone = require('backbone'); const Layer = require('./Layer');
var Layer = require('./Layer');
module.exports = Backbone.Collection.extend({ module.exports = Backbone.Collection.extend({
@ -18,6 +17,102 @@ module.exports = Backbone.Collection.extend({
onReset() { onReset() {
this.idx = 1; this.idx = 1;
},
/**
* Get layers from a value string (for not detached properties),
* example of input:
* `layer1Value, layer2Value, layer3Value, ...`
* @param {string} value
* @return {Array}
* @private
*/
getLayersFromValue(value) {
const layers = [];
// Remove spaces inside functions, eg:
// From: 1px 1px rgba(2px, 2px, 2px), 2px 2px rgba(3px, 3px, 3px)
// To: 1px 1px rgba(2px,2px,2px), 2px 2px rgba(3px,3px,3px)
value.replace(/\(([\w\s,.]*)\)/g, match => {
var cleaned = match.replace(/,\s*/g, ',');
value = value.replace(match, cleaned);
});
const layerValues = value ? value.split(', ') : [];
layerValues.forEach(layerValue => {
layers.push({properties: this.properties.parseValue(layerValue)});
});
return layers;
},
/**
* Get layers from a style object (for detached properties),
* example of input:
* {
* subPropname1: sub-propvalue11, sub-propvalue12, sub-propvalue13, ...
* subPropname2: sub-propvalue21, sub-propvalue22, sub-propvalue23, ...
* subPropname3: sub-propvalue31, sub-propvalue32, sub-propvalue33, ...
* }
* @param {Object} styleObj
* @return {Array}
* @private
*/
getLayersFromStyle(styleObj) {
const layers = [];
const properties = this.properties;
const propNames = properties.pluck('property');
properties.each(propModel => {
const style = styleObj[propModel.get('property')];
const values = style ? style.split(', ') : [];
values.forEach((value, i) => {
value = propModel.parseValue(value.trim());
const layer = layers[i];
const propertyObj = Object.assign({}, propModel.attributes, {value});
if (layer) {
layer.properties.push(propertyObj);
} else {
layers[i] = {
properties: [propertyObj]
};
}
});
});
// Now whit all layers in, will check missing properties
layers.forEach(layer => {
const layerProprs = layer.properties.map(prop => prop.property);
properties.each(propModel => {
const propertyName = propModel.get('property');
if (layerProprs.indexOf(propertyName) < 0) {
layer.properties.push(Object.assign({}, propModel.attributes))
}
})
});
return layers;
},
active(index) {
this.each(layer => layer.set('active', 0));
const layer = this.at(index);
layer && layer.set('active', 1);
},
getFullValue() {
let result = [];
this.each(layer => result.push(layer.getFullValue()));
return result.join(', ');
},
getPropertyValues(property) {
const result = [];
this.each(layer => {
const value = layer.getPropertyValue(property);
value && result.push(value);
});
return result.join(', ');
} }
}); });

34
src/style_manager/model/Properties.js

@ -84,5 +84,37 @@ module.exports = require('backbone').Collection.extend(TypeableCollection).exten
return value; return value;
} }
} }
] ],
deepClone() {
const collection = this.clone();
collection.reset(collection.map(model => {
const cloned = model.clone();
cloned.typeView = model.typeView;
return cloned;
}));
return collection;
},
/**
* Parse a value and return an array splitted by properties
* @param {string} value
* @return {Array}
* @return
*/
parseValue(value) {
const properties = [];
const values = value.split(' ');
values.forEach((value, i) => {
const property = this.at(i);
properties.push(Object.assign({}, property.attributes, {value}));
});
return properties;
},
getFullValue() {
let result = '';
this.each(model => result += `${model.getFullValue()} `);
return result.trim();
}
}); });

3
src/style_manager/model/PropertyComposite.js

@ -48,8 +48,7 @@ module.exports = Property.extend({
} }
let result = ''; let result = '';
this.get('properties').each(prop => result += `${prop.getFullValue()} `); return this.get('properties').getFullValue();
return result.trim();
}, },
}); });

12
src/style_manager/model/PropertyStack.js

@ -14,17 +14,13 @@ module.exports = Property.extend({
init() { init() {
Property.prototype.init.apply(this, arguments); Property.prototype.init.apply(this, arguments);
const layers = this.get('layers'); const layers = this.get('layers');
this.set('layers', new Layers(layers)); const layersColl = new Layers(layers);
layersColl.properties = this.get('properties');
this.set('layers', layersColl);
}, },
getFullValue() { getFullValue() {
if (this.get('detached')) { return this.get('detached') ? '' : this.get('layers').getFullValue();
return '';
}
const layers = this.get('layers');
let val = layers.length ? layers.pluck('value').join(', ') : '';
return val.trim();
}, },
}); });

242
src/style_manager/view/LayerView.js

@ -1,35 +1,42 @@
var Backbone = require('backbone');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
events:{ events: {
'click': 'updateIndex', click: 'active',
'click [data-close-layer]': 'remove',
'mousedown [data-move-layer]': 'initSorter'
},
template(model) {
const pfx = this.pfx;
const label = `Layer ${model.get('index')}`;
return `
<div id="${pfx}move" data-move-layer>
<i class="fa fa-arrows"></i>
</div>
<div id="${pfx}label">${label}</div>
<div id="${pfx}preview-box">
<div id="${pfx}preview" data-preview></div>
</div>
<div id="${pfx}close-layer" class="${pfx}btn-close" data-close-layer>
&Cross;
</div>
<div id="${pfx}inputs" data-properties></div>
<div style="clear:both"></div>
`
}, },
template: _.template(` initialize(o = {}) {
<div id="<%= pfx %>move">
<i class="fa fa-arrows"></i>
</div>
<div id="<%= pfx %>label"><%= label %></div>
<div id="<%= pfx %>preview-box">
<div id="<%= pfx %>preview"></div>
</div>
<div id="<%= pfx %>close-layer" class="<%= pfx %>btn-close">&Cross;</div>
<div id="<%= pfx %>inputs"></div>
<div style="clear:both"></div>`),
initialize(o) {
let model = this.model; let model = this.model;
this.stackModel = o.stackModel || {}; this.stackModel = o.stackModel || {};
this.config = o.config || {}; this.config = o.config || {};
this.pfx = this.config.stylePrefix || ''; this.pfx = this.config.stylePrefix || '';
this.className = this.pfx + 'layer';
this.sorter = o.sorter || null; this.sorter = o.sorter || null;
this.propsConfig = o.propsConfig || {};
this.customPreview = o.onPreview;
this.listenTo(model, 'destroy remove', this.remove); this.listenTo(model, 'destroy remove', this.remove);
this.listenTo(model, 'change:value', this.valueChanged); this.listenTo(model, 'change:active', this.updateVisibility);
this.listenTo(model, 'change:props', this.showProps); this.listenTo(model.get('properties'), 'change', this.updatePreview);
this.events['click #' + this.pfx + 'close-layer'] = 'remove';
this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter';
if (!model.get('preview')) { if (!model.get('preview')) {
this.$el.addClass(this.pfx + 'no-preview'); this.$el.addClass(this.pfx + 'no-preview');
@ -39,7 +46,6 @@ module.exports = Backbone.View.extend({
model.view = this; model.view = this;
model.set({droppable: 0, draggable: 1}); model.set({droppable: 0, draggable: 1});
this.$el.data('model', model); this.$el.data('model', model);
this.delegateEvents();
}, },
/** /**
@ -51,36 +57,24 @@ module.exports = Backbone.View.extend({
this.sorter.startSort(this.el); this.sorter.startSort(this.el);
}, },
/**
* Returns properties
* @return {Collection|null}
*/
getProps() {
if(this.stackModel.get)
return this.stackModel.get('properties');
else
return null;
},
/** remove(e) {
* Emitted when the value is changed if(e && e.stopPropagation)
*/ e.stopPropagation();
valueChanged() {
var preview = this.model.get('preview'); const model = this.model;
const collection = model.collection;
if(!preview) const stackModel = this.stackModel;
return;
Backbone.View.prototype.remove.apply(this, arguments);
if(!this.$preview)
this.$preview = this.$el.find('#' + this.pfx + 'preview'); if (collection.contains(model)) {
collection.remove(model);
var prw = ''; }
var props = this.getProps();
var previewEl = this.$preview; if (stackModel && stackModel.set) {
if (typeof preview === 'function') { stackModel.set({stackIndex: null}, {silent: true});
preview(props, previewEl); stackModel.trigger('updateValue');
} else {
this.onPreview(props, previewEl);
} }
}, },
@ -89,102 +83,88 @@ module.exports = Backbone.View.extend({
* @param {Collection} props * @param {Collection} props
* @param {Element} $el * @param {Element} $el
*/ */
onPreview(props, $el) { onPreview(value) {
var aV = this.model.get('value').split(' '); const values = value.split(' ');
var lim = 3; const lim = 3;
var nV = ''; const result = [];
props.each((p, index) => { this.model.get('properties').each((prop, index) => {
var v = aV[index] || ''; var value = values[index] || '';
if(v){
if(p.get('type') == 'integer'){ if (value) {
var vI = parseInt(v, 10), if (prop.get('type') == 'integer') {
u = v.replace(vI,''); let valueInt = parseInt(value, 10);
vI = !isNaN(vI) ? vI : 0; let unit = value.replace(valueInt,'');
if(vI > lim) valueInt = !isNaN(valueInt) ? valueInt : 0;
vI = lim; valueInt = valueInt > lim ? lim : valueInt;
if(vI < -lim) valueInt = valueInt < -lim ? -lim : valueInt;
vI = -lim; value = valueInt + unit;
v = vI + u;
} }
} }
nV += v + ' ';
result.push(value);
}); });
if(this.stackModel.get){ return result.join(' ');
var property = this.stackModel.get('property');
if(property)
this.$preview.get(0).style[property] = nV;
}
}, },
/** updatePreview() {
* Show inputs on this layer const stackModel = this.stackModel;
* */ const customPreview = this.customPreview;
showProps() { const previewEl = this.getPreviewEl();
this.$props = this.model.get('props'); const value = this.model.getFullValue();
this.$el.find('#' + this.pfx + 'inputs').html(this.$props.show()); const preview = customPreview ? customPreview(value) : this.onPreview(value);
this.model.set({props: null }, {silent: true });
},
/** @inheritdoc */
remove(e) {
// Prevent from revoming all events on props
if(this.$props)
this.$props.detach();
if(e && e.stopPropagation)
e.stopPropagation();
Backbone.View.prototype.remove.apply(this, arguments);
//--- if (preview && stackModel && previewEl) {
if(this.model.collection.contains(this.model)) previewEl.style[stackModel.get('property')] = preview;
this.model.collection.remove(this.model);
if(this.stackModel && this.stackModel.set){
this.stackModel.set({stackIndex: null}, {silent: true});
this.stackModel.trigger('updateValue');
} }
}, },
/** getPropertiesWrapper() {
* Update index if (!this.propsWrapEl) {
* @param Event this.propsWrapEl = this.el.querySelector('[data-properties]');
* }
* @return void return this.propsWrapEl;
* */
updateIndex(e) {
var i = this.getIndex();
this.stackModel.set('stackIndex', i);
if(this.model.collection)
this.model.collection.trigger('deselectAll');
this.$el.addClass(this.pfx + 'active');
}, },
/** getPreviewEl() {
* Fetch model index if (!this.previewEl) {
* @return {number} Index this.previewEl = this.el.querySelector('[data-preview]');
*/
getIndex() {
var index = 0;
var model = this.model;
if (model.collection) {
index = model.collection.indexOf(model);
} }
return this.previewEl;
},
active() {
const model = this.model;
const collection = model.collection;
collection.active(collection.indexOf(model));
},
return index; updateVisibility() {
const pfx = this.pfx;
const wrapEl = this.getPropertiesWrapper();
const active = this.model.get('active');
wrapEl.style.display = active ? '' : 'none';
this.$el[active ? 'addClass' : 'removeClass'](`${pfx}active`);
}, },
render() { render() {
this.$el.html( this.template({ const PropertiesView = require('./PropertiesView');
label: 'Layer ' + this.model.get('index'), const propsConfig = this.propsConfig;
pfx: this.pfx, const className = `${this.pfx}layer`;
})); const model = this.model;
this.$el.attr('class', this.className); const el = this.el;
this.valueChanged(); const properties = new PropertiesView({
collection: model.get('properties'),
config: this.config,
customValue: propsConfig.customValue,
propTarget: propsConfig.propTarget,
onChange: propsConfig.onChange,
}).render().el;
el.innerHTML = this.template(model);
el.className = className;
this.getPropertiesWrapper().appendChild(properties);
this.updateVisibility();
this.updatePreview();
return this; return this;
}, },

23
src/style_manager/view/LayersView.js

@ -9,6 +9,7 @@ module.exports = Backbone.View.extend({
this.preview = o.preview; this.preview = o.preview;
this.pfx = this.config.stylePrefix || ''; this.pfx = this.config.stylePrefix || '';
this.ppfx = this.config.pStylePrefix || ''; this.ppfx = this.config.pStylePrefix || '';
this.propsConfig = o.propsConfig;
let pfx = this.pfx; let pfx = this.pfx;
let ppfx = this.ppfx; let ppfx = this.ppfx;
let collection = this.collection; let collection = this.collection;
@ -55,23 +56,27 @@ module.exports = Backbone.View.extend({
* */ * */
addToCollection(model, fragmentEl, index) { addToCollection(model, fragmentEl, index) {
var fragment = fragmentEl || null; var fragment = fragmentEl || null;
var viewObject = LayerView; const stackModel = this.stackModel;
const config = this.config;
const sorter = this.sorter;
const propsConfig = this.propsConfig;
if(typeof this.preview !== 'undefined'){ if(typeof this.preview !== 'undefined'){
model.set('preview', this.preview); model.set('preview', this.preview);
} }
var view = new viewObject({ var view = new LayerView({
model, model,
stackModel: this.stackModel, config,
config: this.config, sorter,
sorter: this.sorter stackModel,
propsConfig
}); });
var rendered = view.render().el; var rendered = view.render().el;
if(fragment){ if (fragment) {
fragment.appendChild( rendered ); fragment.appendChild(rendered);
}else{ } else {
if(typeof index != 'undefined'){ if(typeof index != 'undefined'){
var method = 'before'; var method = 'before';
// If the added model is the last of collection // If the added model is the last of collection

18
src/style_manager/view/PropertiesView.js

@ -1,12 +1,11 @@
var Backbone = require('backbone'); const PropertyView = require('./PropertyView');
var PropertyView = require('./PropertyView'); const PropertyIntegerView = require('./PropertyIntegerView');
var PropertyIntegerView = require('./PropertyIntegerView'); const PropertyRadioView = require('./PropertyRadioView');
var PropertyRadioView = require('./PropertyRadioView'); const PropertySelectView = require('./PropertySelectView');
var PropertySelectView = require('./PropertySelectView'); const PropertyColorView = require('./PropertyColorView');
var PropertyColorView = require('./PropertyColorView'); const PropertyFileView = require('./PropertyFileView');
var PropertyFileView = require('./PropertyFileView'); const PropertyCompositeView = require('./PropertyCompositeView');
var PropertyCompositeView = require('./PropertyCompositeView'); const PropertyStackView = require('./PropertyStackView');
var PropertyStackView = require('./PropertyStackView');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
@ -44,7 +43,6 @@ module.exports = Backbone.View.extend({
}); });
this.$el.append(fragment); this.$el.append(fragment);
this.$el.append($('<div>', {class: "clear"}));
this.$el.attr('class', this.pfx + 'properties'); this.$el.attr('class', this.pfx + 'properties');
return this; return this;
} }

8
src/style_manager/view/PropertyColorView.js

@ -1,5 +1,4 @@
var Backbone = require('backbone'); const InputColor = require('domain_abstract/ui/InputColor');
var InputColor = require('domain_abstract/ui/InputColor');
module.exports = require('./PropertyIntegerView').extend({ module.exports = require('./PropertyIntegerView').extend({
@ -10,13 +9,14 @@ module.exports = require('./PropertyIntegerView').extend({
onRender() { onRender() {
if (!this.input) { if (!this.input) {
const ppfx = this.ppfx;
const inputColor = new InputColor({ const inputColor = new InputColor({
target: this.target, target: this.target,
model: this.model, model: this.model,
ppfx: this.ppfx ppfx
}); });
const input = inputColor.render(); const input = inputColor.render();
this.$el.append(input.$el); this.el.querySelector(`.${ppfx}fields`).appendChild(input.el);
this.$input = input.inputEl; this.$input = input.inputEl;
this.$color = input.colorEl; this.$color = input.colorEl;
this.input = this.$input.get(0); this.input = this.$input.get(0);

5
src/style_manager/view/PropertyCompositeView.js

@ -1,4 +1,5 @@
const PropertyView = require('./PropertyView'); const PropertyView = require('./PropertyView');
const $ = Backbone.$;
module.exports = PropertyView.extend({ module.exports = PropertyView.extend({
@ -26,7 +27,7 @@ module.exports = PropertyView.extend({
if (props.length) { if (props.length) {
if (!this.$input) { if (!this.$input) {
this.$input = $('<input>', {value: 0, type: 'hidden' }); this.$input = $('<input type="hidden" value="0">');
this.input = this.$input.get(0); this.input = this.$input.get(0);
} }
@ -47,7 +48,7 @@ module.exports = PropertyView.extend({
var PropertiesView = require('./PropertiesView'); var PropertiesView = require('./PropertiesView');
var propsView = new PropertiesView(this.getPropsConfig()); var propsView = new PropertiesView(this.getPropsConfig());
this.$props = propsView.render().$el; this.$props = propsView.render().$el;
this.$el.find('#'+ this.pfx +'input-holder').html(this.$props); this.$el.find(`#${this.pfx}input-holder`).append(this.$props);
} }
} }
}, },

13
src/style_manager/view/PropertyFileView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); const PropertyView = require('./PropertyView');
var PropertyView = require('./PropertyView'); const $ = Backbone.$;
module.exports = PropertyView.extend({ module.exports = PropertyView.extend({
@ -26,9 +26,9 @@ module.exports = PropertyView.extend({
}, },
init() { init() {
this.assets = this.target.get('assets'); const em = this.em;
this.modal = this.target.get('Modal'); this.modal = em.get('Modal');
this.am = this.target.get('AssetManager'); this.am = em.get('AssetManager');
this.events['click #'+this.pfx+'close'] = 'removeFile'; this.events['click #'+this.pfx+'close'] = 'removeFile';
this.events['click #'+this.pfx+'images'] = 'openAssetManager'; this.events['click #'+this.pfx+'images'] = 'openAssetManager';
this.delegateEvents(); this.delegateEvents();
@ -36,7 +36,8 @@ module.exports = PropertyView.extend({
onRender() { onRender() {
if (!this.$input) { if (!this.$input) {
this.$input = $('<input>', {placeholder: this.model.getDefaultValue(), type: 'text' }); const plh = this.model.getDefaultValue();
this.$input = $(`<input placeholder="${plh}">`);
} }
if (!this.$preview) { if (!this.$preview) {

4
src/style_manager/view/PropertyIntegerView.js

@ -1,4 +1,5 @@
const InputNumber = require('domain_abstract/ui/InputNumber'); const InputNumber = require('domain_abstract/ui/InputNumber');
const $ = Backbone.$;
module.exports = require('./PropertyView').extend({ module.exports = require('./PropertyView').extend({
@ -28,7 +29,8 @@ module.exports = require('./PropertyView').extend({
const fields = this.el.querySelector(`.${ppfx}fields`); const fields = this.el.querySelector(`.${ppfx}fields`);
fields.appendChild(input.el); fields.appendChild(input.el);
this.$input = input.inputEl; this.$input = input.inputEl;
this.$unit = input.unitEl; this.unit = input.unitEl;
this.$unit = $(this.unit);
this.input = this.$input.get(0); this.input = this.$input.get(0);
this.inputInst = input; this.inputInst = input;
} }

34
src/style_manager/view/PropertyRadioView.js

@ -18,7 +18,7 @@ module.exports = require('./PropertyView').extend({
const prop = model.get('property'); const prop = model.get('property');
const options = model.get('list') || model.get('options') || []; const options = model.get('list') || model.get('options') || [];
if (!this.$input) { if (!this.input) {
if(options && options.length) { if(options && options.length) {
let inputStr = ''; let inputStr = '';
@ -31,31 +31,39 @@ module.exports = require('./PropertyView').extend({
<div class="${ppfx}radio-item"> <div class="${ppfx}radio-item">
<input type="radio" class="${pfx}radio" id="${id}" name="${prop}" value="${el.value}"/> <input type="radio" class="${pfx}radio" id="${id}" name="${prop}" value="${el.value}"/>
<label class="${cl || itemCls}" ${titleAttr} for="${id}">${cl ? '' : labelTxt}</label> <label class="${cl || itemCls}" ${titleAttr} for="${id}">${cl ? '' : labelTxt}</label>
</div>`; </div>
`;
}); });
this.$inputEl = $(inputStr); const inputHld = this.el.querySelector(`#${pfx}input-holder`);
this.input = this.$inputEl.get(0); inputHld.innerHTML = `<div>${inputStr}</div>`;
this.$el.find(`#${pfx}input-holder`).html(this.$inputEl); this.input = inputHld.firstChild;
this.$input = this.$inputEl.find(`input[name="${prop}"]`);
} }
} }
}, },
getInputValue() { getInputValue() {
return this.$input ? this.$el.find('input:checked').val() : ''; const inputChk = this.getCheckedEl();
return inputChk ? inputChk.value : '';
},
getCheckedEl() {
const input = this.getInputEl();
return input ? input.querySelector('input:checked') : '';
}, },
setValue(value) { setValue(value) {
const model = this.model; const model = this.model;
var v = model.get('value') || model.getDefaultValue(); let val = value || model.get('value') || model.getDefaultValue();
const input = this.getInputEl();
const inputIn = input ? input.querySelector(`[value="${val}"]`) : '';
if (value) { if (inputIn) {
v = value; inputIn.checked = true;
} else {
const inputChk = this.getCheckedEl();
inputChk && (inputChk.checked = false);
} }
if(this.$input)
this.$input.filter(`[value="${v}"]`).prop('checked', true);
}, },
}); });

10
src/style_manager/view/PropertySelectView.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = require('./PropertyView').extend({ module.exports = require('./PropertyView').extend({
templateInput() { templateInput() {
@ -18,7 +20,7 @@ module.exports = require('./PropertyView').extend({
const model = this.model; const model = this.model;
const options = model.get('list') || model.get('options') || []; const options = model.get('list') || model.get('options') || [];
if (!this.$input) { if (!this.input) {
let optionsStr = ''; let optionsStr = '';
options.forEach(option => { options.forEach(option => {
@ -29,9 +31,9 @@ module.exports = require('./PropertyView').extend({
optionsStr += `<option value="${value}" ${styleAttr}>${name}</option>`; optionsStr += `<option value="${value}" ${styleAttr}>${name}</option>`;
}); });
this.$input = $(`<select>${optionsStr}</select>`); const inputH = this.el.querySelector(`#${pfx}input-holder`);
this.input = this.$input.get(0); inputH.innerHTML = `<select>${optionsStr}</select>`;
this.$el.find(`#${pfx}input-holder`).html(this.$input); this.input = inputH.firstChild;
} }
}, },

313
src/style_manager/view/PropertyStackView.js

@ -1,7 +1,5 @@
var Backbone = require('backbone'); const PropertyCompositeView = require('./PropertyCompositeView');
var PropertyCompositeView = require('./PropertyCompositeView'); const LayersView = require('./LayersView');
var Layers = require('./../model/Layers');
var LayersView = require('./LayersView');
module.exports = PropertyCompositeView.extend({ module.exports = PropertyCompositeView.extend({
@ -10,8 +8,8 @@ module.exports = PropertyCompositeView.extend({
const ppfx = this.ppfx; const ppfx = this.ppfx;
return ` return `
<div class="${pfx}field ${pfx}stack"> <div class="${pfx}field ${pfx}stack">
<button type="button" id="${pfx}add">+</button> <button type="button" id="${pfx}add" data-add-layer>+</button>
<span id="${pfx}input-holder"></span> <div data-layers-wrapper></div>
</div> </div>
`; `;
}, },
@ -20,7 +18,7 @@ module.exports = PropertyCompositeView.extend({
const model = this.model; const model = this.model;
const pfx = this.pfx; const pfx = this.pfx;
model.set('stackIndex', null); model.set('stackIndex', null);
this.events[`click #${pfx}add`] = 'addLayer'; this.events[`click [data-add-layer]`] = 'addLayer';
this.listenTo(model, 'change:stackIndex', this.indexChanged); this.listenTo(model, 'change:stackIndex', this.indexChanged);
this.listenTo(model, 'updateValue', this.inputValueChanged); this.listenTo(model, 'updateValue', this.inputValueChanged);
this.delegateEvents(); this.delegateEvents();
@ -29,7 +27,7 @@ module.exports = PropertyCompositeView.extend({
/** /**
* Fired when the target is updated. * Fired when the target is updated.
* With detached mode the component will be always empty as its value * With detached mode the component will be always empty as its value
* so we gonna check all props and fine if there is some differences. * so we gonna check all props and find if it has any difference
* */ * */
targetUpdated(...args) { targetUpdated(...args) {
if (!this.model.get('detached')) { if (!this.model.get('detached')) {
@ -58,259 +56,120 @@ module.exports = PropertyCompositeView.extend({
* @return {Object} * @return {Object}
* */ * */
indexChanged(e) { indexChanged(e) {
var model = this.model;
var layer = this.getLayers().at(model.get('stackIndex'));
layer.set('props', this.$props);
model.get('properties').each(prop => prop.trigger('targetUpdated'));
},
/**
* Get array of values from layers
* @return Array
* */
getStackValues() {
return this.getLayers().pluck('value');
},
/** @inheritDoc */
getPropsConfig(opts) {
const model = this.model;
const detached = model.get('detached');
var result = PropertyCompositeView.prototype.getPropsConfig.apply(this, arguments);
result.onChange = (el, view, opt) => {
const subModel = view.model;
const subProperty = subModel.get('property');
this.build();
if (detached) {
var propVal = '';
var index = subModel.collection.indexOf(subModel);
this.getLayers().each(layer => {
var val = layer.get('values')[subProperty];
if (val) {
propVal += (propVal ? ',' : '') + val;
}
});
view.updateTargetStyle(propVal, null, opt);
} else {
model.set('value', model.getFullValue(), opt);
}
};
return result;
},
/**
* Extract string from the composite value of the target
* @param {integer} index Property index
* @param {View} propView Property view
* @return string
* @private
* */
valueOnIndex(index, propView) {
let result;
const model = this.model; const model = this.model;
const propModel = propView && propView.model; this.getLayers().active(model.get('stackIndex'));
const layerIndex = model.get('stackIndex');
// If detached the value in this case is stacked, eg. substack-prop: 1px, 2px, 3px...
if (model.get('detached')) {
var targetValue = propView.getTargetValue({ignoreCustomValue: 1});
var valist = (targetValue + '').split(',');
result = valist[layerIndex];
result = result ? result.trim() : propModel.getDefaultValue();
result = propModel.parseValue(result);
} else {
var aStack = this.getStackValues();
var strVar = aStack[layerIndex];
if(!strVar)
return;
var a = strVar.split(' ');
if(a.length && a[index]){
result = a[index];
}
}
return result;
}, },
/** addLayer() {
* Build composite value
* @private
* */
build(...args) {
let value = '';
let values = {};
const model = this.model; const model = this.model;
const stackIndex = model.get('stackIndex'); const layers = this.getLayers();
const properties = model.get('properties'); const properties = model.get('properties').deepClone();
properties.each(property => property.set('value', ''));
if (stackIndex === null) { const layer = layers.add({properties});
return;
}
// Store properties values inside layer, in this way it's more reliable // In detached mode inputValueChanged will add new 'layer value'
// to fetch them later // to all subprops
properties.each(prop => { this.inputValueChanged();
const propValue = prop.getFullValue();
values[prop.get('property')] = propValue;
value += `${propValue} `;
});
const layerModel = this.getLayers().at(stackIndex); // This will set subprops with a new default values
layerModel && layerModel.set({values, value}); model.set('stackIndex', layers.indexOf(layer));
}, },
/**
* Add new layer
* */
addLayer() {
if (this.getTarget()) {
const layers = this.getLayers();
const layer = layers.add({name: 'New'});
const index = layers.indexOf(layer);
const model = this.model;
layer.set('value', model.getDefaultValue(1));
// In detached mode inputValueChanged will add new 'layer value'
// to all subprops
this.inputValueChanged();
// This will set subprops with a new default values
model.set('stackIndex', index);
}
},
inputValueChanged() { inputValueChanged() {
var model = this.model; const model = this.model;
this.elementUpdated();
// If not detached I'll just put all the values from layers to property
// eg. background: layer1Value, layer2Value, layer3Value, ...
if (!model.get('detached')) { if (!model.get('detached')) {
model.set('value', this.createValue()); model.set('value', this.getLayerValues());
} else { } else {
model.get('properties').each(prop => { model.get('properties').each(prop => prop.trigger('change:value'))
prop.trigger('change:value');
});
} }
}, },
/** /**
* Create value by layers * There is no need to handle input update by the property itself,
* @return string * this will be done by layers
* */ * @private
createValue() { */
return this.getStackValues().join(', '); setValue() {},
},
/** /**
* Render layers * Create value by layers
* @return self * @return string
* */ * */
renderLayers() { getLayerValues() {
if (!this.fieldEl) { return this.getLayers().getFullValue();
this.fieldEl = this.el.querySelector(`.${this.pfx}field`);
}
if(!this.$layers)
this.$layers = new LayersView({
collection: this.getLayers(),
stackModel: this.model,
preview: this.model.get('preview'),
config: this.config
});
this.fieldEl.appendChild(this.$layers.render().el);
this.$props.hide();
},
/**
* Returns array suitale for layers from target style
* Only for detached stacks
* @return {Array<string>}
*/
getLayersFromTarget() {
var arr = [];
var target = this.getTarget();
if(!target)
return arr;
var trgStyle = target.get('style');
this.model.get('properties').each(prop => {
var style = trgStyle[prop.get('property')];
if (style) {
var list = style.split(',');
for(var i = 0, len = list.length; i < len; i++){
var val = list[i].trim();
if(arr[i]){
arr[i][prop.get('property')] = val;
}else{
var vals = {};
vals[prop.get('property')] = val;
arr[i] = vals;
}
}
}
});
return arr;
}, },
/** /**
* Refresh layers * Refresh layers
* */ * */
refreshLayers() { refreshLayers() {
var n = []; let layersObj = [];
var a = []; const model = this.model;
var fieldName = 'value'; const layers = this.getLayers();
var detached = this.model.get('detached'); const detached = model.get('detached');
// With detached layers values will be assigned to their properties
if (detached) { if (detached) {
fieldName = 'values'; const target = this.getTarget();
a = this.getLayersFromTarget(); const style = target ? target.getStyle() : {};
layersObj = layers.getLayersFromStyle(style);
} else { } else {
var v = this.getTargetValue(); let value = this.getTargetValue();
var vDef = this.model.getDefaultValue(); value = value == model.getDefaultValue() ? '' : value;
v = v == vDef ? '' : v; layersObj = layers.getLayersFromValue(value);
if (v) {
// Remove spaces inside functions:
// eg:
// From: 1px 1px rgba(2px, 2px, 2px), 2px 2px rgba(3px, 3px, 3px)
// To: 1px 1px rgba(2px,2px,2px), 2px 2px rgba(3px,3px,3px)
v.replace(/\(([\w\s,.]*)\)/g, match => {
var cleaned = match.replace(/,\s*/g, ',');
v = v.replace(match, cleaned);
});
a = v.split(', ');
}
} }
_.each(a, e => {
var o = {};
o[fieldName] = e;
n.push(o);
},this);
this.$props.detach();
var layers = this.getLayers();
layers.reset(); layers.reset();
layers.add(n); layers.add(layersObj);
model.set({stackIndex: null}, {silent: true});
// Avoid updating with detached as it will cause issues on next change
if (!detached) {
this.inputValueChanged();
}
this.model.set({stackIndex: null}, {silent: true});
}, },
onRender(...args) { onRender() {
PropertyCompositeView.prototype.onRender.apply(this, args); const self = this;
this.refreshLayers(); const model = this.model;
this.renderLayers(); const fieldEl = this.el.querySelector('[data-layers-wrapper]');
const PropertiesView = require('./PropertiesView');
const propsConfig = {
propTarget: this.propTarget,
// Things to do when a single sub-property is changed
onChange(el, view, opt) {
const subModel = view.model;
if (model.get('detached')) {
const subProp = subModel.get('property');
const values = self.getLayers().getPropertyValues(subProp);
view.updateTargetStyle(values, null, opt);
} else {
model.set('value', model.getFullValue(), opt);
}
},
};
const layers = new LayersView({
collection: this.getLayers(),
stackModel: model,
preview: model.get('preview'),
config: this.config,
propsConfig,
}).render().el;
// Will use it to propogate changes
new PropertiesView({
collection: this.model.get('properties'),
stackModel: model,
config: this.config,
onChange: propsConfig.onChange,
propTarget: propsConfig.propTarget,
customValue: propsConfig.customValue,
}).render();
//model.get('properties')
fieldEl.appendChild(layers);
}, },
}); });

7
src/style_manager/view/PropertyView.js

@ -1,5 +1,3 @@
var Backbone = require('backbone');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
template(model) { template(model) {
@ -50,7 +48,7 @@ module.exports = Backbone.View.extend({
this.customValue = o.customValue || {}; this.customValue = o.customValue || {};
const model = this.model; const model = this.model;
this.property = model.get('property'); this.property = model.get('property');
this.input = this.$input = null; this.input = null;
const pfx = this.pfx; const pfx = this.pfx;
this.inputHolderId = '#' + pfx + 'input-holder'; this.inputHolderId = '#' + pfx + 'input-holder';
this.sector = model.collection && model.collection.sector; this.sector = model.collection && model.collection.sector;
@ -84,7 +82,7 @@ module.exports = Backbone.View.extend({
const config = this.config; const config = this.config;
const updatedCls = `${ppfx}color-hl`; const updatedCls = `${ppfx}color-hl`;
const computedCls = `${ppfx}color-warn`; const computedCls = `${ppfx}color-warn`;
const labelEl = this.$el.find(`> .${pfx}label`); const labelEl = this.$el.children(`.${pfx}label`);
const clearStyle = this.getClearEl().style; const clearStyle = this.getClearEl().style;
labelEl.removeClass(`${updatedCls} ${computedCls}`); labelEl.removeClass(`${updatedCls} ${computedCls}`);
clearStyle.display = 'none'; clearStyle.display = 'none';
@ -444,6 +442,7 @@ module.exports = Backbone.View.extend({
const onRender = this.onRender && this.onRender.bind(this); const onRender = this.onRender && this.onRender.bind(this);
onRender && onRender(); onRender && onRender();
this.setValue(model.get('value'), {targetUpdate: 1});
}, },
}); });

24
src/style_manager/view/SectorView.js

@ -4,25 +4,25 @@ var PropertiesView = require('./PropertiesView');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
template: _.template(` template: _.template(`
<div class="<%= pfx %>title"> <div class="<%= pfx %>title" data-sector-title>
<i id="<%= pfx %>caret" class="fa"></i> <i id="<%= pfx %>caret" class="fa"></i>
<%= label %> <%= label %>
</div>`), </div>`),
events:{}, events:{
'click [data-sector-title]': 'toggle'
},
initialize(o) { initialize(o) {
this.config = o.config || {}; this.config = o.config || {};
this.pfx = this.config.stylePrefix || ''; this.pfx = this.config.stylePrefix || '';
this.target = o.target || {}; this.target = o.target || {};
this.propTarget = o.propTarget || {}; this.propTarget = o.propTarget || {};
this.open = this.model.get('open');
this.caretR = 'fa-caret-right'; this.caretR = 'fa-caret-right';
this.caretD = 'fa-caret-down'; this.caretD = 'fa-caret-down';
this.listenTo(this.model, 'change:open', this.updateOpen); const model = this.model;
this.listenTo(this.model, 'updateVisibility', this.updateVisibility); this.listenTo(model, 'change:open', this.updateOpen);
this.events['click .' + this.pfx + 'title'] = 'toggle'; this.listenTo(model, 'updateVisibility', this.updateVisibility);
this.delegateEvents();
}, },
/** /**
@ -53,7 +53,7 @@ module.exports = Backbone.View.extend({
* */ * */
show() { show() {
this.$el.addClass(this.pfx + "open"); this.$el.addClass(this.pfx + "open");
this.$el.find('.' + this.pfx + 'properties').show(); this.getPropertiesEl().style.display = '';
this.$caret.removeClass(this.caretR).addClass(this.caretD); this.$caret.removeClass(this.caretR).addClass(this.caretD);
}, },
@ -62,14 +62,18 @@ module.exports = Backbone.View.extend({
* */ * */
hide() { hide() {
this.$el.removeClass(this.pfx + "open"); this.$el.removeClass(this.pfx + "open");
this.$el.find('.' + this.pfx + 'properties').hide(); this.getPropertiesEl().style.display = 'none';
this.$caret.removeClass(this.caretD).addClass(this.caretR); this.$caret.removeClass(this.caretD).addClass(this.caretR);
}, },
getPropertiesEl() {
return this.$el.find(`.${this.pfx}properties`).get(0);
},
/** /**
* Toggle visibility * Toggle visibility
* */ * */
toggle() { toggle(e) {
var v = this.model.get('open') ? 0 : 1; var v = this.model.get('open') ? 0 : 1;
this.model.set('open', v); this.model.set('open', v);
}, },

4
src/style_manager/view/SectorsView.js

@ -1,5 +1,4 @@
var Backbone = require('backbone'); const SectorView = require('./SectorView');
var SectorView = require('./SectorView');
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
@ -117,7 +116,6 @@ module.exports = Backbone.View.extend({
* */ * */
addToCollection(model, fragmentEl) { addToCollection(model, fragmentEl) {
var fragment = fragmentEl || null; var fragment = fragmentEl || null;
var view = new SectorView({ var view = new SectorView({
model, model,
id: this.pfx + model.get('name').replace(' ','_').toLowerCase(), id: this.pfx + model.get('name').replace(' ','_').toLowerCase(),

4
src/trait_manager/view/TraitSelectView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone'); const TraitView = require('./TraitView');
var TraitView = require('./TraitView'); const $ = Backbone.$;
module.exports = TraitView.extend({ module.exports = TraitView.extend({

43
src/trait_manager/view/TraitView.js

@ -1,4 +1,4 @@
var Backbone = require('backbone'); const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({
@ -81,21 +81,28 @@ module.exports = Backbone.View.extend({
var md = this.model; var md = this.model;
var trg = this.target; var trg = this.target;
var name = md.get('name'); var name = md.get('name');
var opts = { const plh = md.get('placeholder') || md.get('default') || '';
placeholder: md.get('placeholder') || md.get('default'), const type = md.get('type') || 'text';
type: md.get('type') || 'text' const attrs = trg.get('attributes');
}; const min = md.get('min');
if(md.get('changeProp')){ const max = md.get('max');
opts.value = trg.get(name); const value = md.get('changeProp') ?
}else{ trg.get(name) : md.get('value') || attrs[name];
var attrs = trg.get('attributes'); const input = $(`<input type="${type}" placeholder="${plh}">`);
opts.value = md.get('value') || attrs[name];
if (value) {
input.prop('value', value);
}
if (min) {
input.prop('min', min);
} }
if(md.get('min'))
opts.min = md.get('min'); if (max) {
if(md.get('max')) input.prop('max', max);
opts.max = md.get('max'); }
this.$input = $('<input>', opts);
this.$input = input;
} }
return this.$input.get(0); return this.$input.get(0);
}, },
@ -123,8 +130,10 @@ module.exports = Backbone.View.extend({
renderField() { renderField() {
if(!this.$input){ if(!this.$input){
this.$el.append(this.tmpl); this.$el.append(this.tmpl);
var el = this.getInputEl(); const el = this.getInputEl();
this.$el.find('.' + this.inputhClass).prepend(el); // I use prepand expecially for checkbox traits
const inputWrap = this.el.querySelector(`.${this.inputhClass}`);
inputWrap.insertBefore(el, inputWrap.childNodes[0]);
} }
}, },

2321
src/utils/ColorPicker.js

File diff suppressed because it is too large

2
src/utils/Dragger.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
var getBoundingRect = (el, win) => { var getBoundingRect = (el, win) => {
var w = win || window; var w = win || window;
var rect = el.getBoundingClientRect(); var rect = el.getBoundingClientRect();

2
src/utils/Resizer.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
var defaults = { var defaults = {
// Function which returns custom X and Y coordinates of the mouse // Function which returns custom X and Y coordinates of the mouse
mousePosFetcher: null, mousePosFetcher: null,

2
src/utils/Sorter.js

@ -1,4 +1,4 @@
var Backbone = require('backbone'); const $ = Backbone.$;
module.exports = Backbone.View.extend({ module.exports = Backbone.View.extend({

303
src/utils/extender.js

@ -0,0 +1,303 @@
module.exports = ({$, Backbone}) => {
if (Backbone) {
const ViewProt = Backbone.View.prototype;
const eventNsMap = {};
ViewProt.eventNsMap = eventNsMap;
ViewProt.delegate = function(eventName, selector, listener) {
const vid = '.delegateEvents' + this.cid;
this.$el.on(eventName, selector, listener);
//return this;
let eventMap = eventNsMap[vid];
if (!eventMap) {
eventMap = [];
eventNsMap[vid] = eventMap;
}
eventMap.push({eventName, selector, listener});
return this;
};
ViewProt.undelegateEvents = function() {
const vid = '.delegateEvents' + this.cid;
if (this.$el) {
//this.$el.off(); return this;
let eventMap = eventNsMap[vid];
if (eventMap) {
eventMap.forEach(({eventName, selector, listener}) => {
this.$el.off(eventName);
});
}
}
return this;
};
ViewProt.undelegate = function(ev, sel, list) {
const vid = '.delegateEvents' + this.cid;
//this.$el.off(ev, sel, list); return this;
let eventMap = eventNsMap[vid];
if (eventMap) {
eventMap.forEach(({eventName, selector, listener}) => {
if (eventName == ev && selector == sel) {
this.$el.off(eventName);
}
});
}
return this;
};
}
if ($) {
const fn = $.fn;
const splitNamespace = function(name) {
const namespaceArray = name.split('.')
return ( name.indexOf('.') !== 0 ? [namespaceArray[0], namespaceArray.slice(1)] : [null, namespaceArray] );
}
/*
const CashEvent = function(node, eventName, namespaces, delegate, originalCallback, runOnce) {
const eventCache = getData(node,'_cashEvents') || setData(node, '_cashEvents', {});
const remove = function(c, namespace){
if ( c && originalCallback !== c ) { return; }
if ( namespace && this.namespaces.indexOf(namespace) < 0 ) { return; }
node.removeEventListener(eventName, callback);
};
const callback = function(e) {
var t = this;
if (delegate) {
t = e.target;
while (t && !matches(t, delegate)) {
if (t === this) {
return (t = false);
}
t = t.parentNode;
}
}
if (t) {
originalCallback.call(t, e, e.data);
if ( runOnce ) { remove(); }
}
};
this.remove = remove;
this.namespaces = namespaces;
node.addEventListener(eventName, callback);
eventCache[eventName] = eventCache[eventName] || [];
eventCache[eventName].push(this);
return this;
}
*/
const on = $.prototype.on;
const off = $.prototype.off;
const trigger = $.prototype.trigger;
const offset = $.prototype.offset;
const getEvents = (eventName) => eventName.split(/[,\s]+/g);
const getNamespaces = (eventName) => eventName.split('.');
fn.on = function(eventName, delegate, callback, runOnce) {
if (typeof eventName == 'string') {
const events = getEvents(eventName);
if (events.length == 1) {
eventName = events[0];
let namespaces = getNamespaces(eventName);
if (eventName.indexOf('.') !== 0) {
eventName = namespaces[0];
}
namespaces = namespaces.slice(1);
if (namespaces.length) {
//console.log('Found event with namespaces', namespaces, eventName, delegate, this);
const cashNs = this.data('_cashNs') || [];
// cashNs[namespace]
this.data('_cashNs', namespaces); // for each ns need to store '.store' => eventName, delegate, callback
}
return on.call(this, eventName, delegate, callback, runOnce);
} else {
events.forEach((eventName) =>
this.on(eventName, delegate, callback, runOnce));
return this;
}
} else {
return on.call(this, eventName, delegate, callback, runOnce)
}
}
fn.off = function(eventName, callback) {
if (typeof eventName == 'string') {
const events = getEvents(eventName);
if (events.length == 1) {
eventName = events[0];
let namespaces = getNamespaces(eventName);
if (eventName.indexOf('.') !== 0) {
eventName = namespaces[0];
}
namespaces = namespaces.slice(1);
if (namespaces.length) {
// Have to off only with the same namespace
}
return off.call(this, eventName, callback);
} else {
events.forEach((eventName) => this.off(eventName, callback));
return this;
}
} else {
return off.call(this, eventName, callback);
}
}
fn.trigger = function(eventName, data) {
if (eventName instanceof $.Event) {
return this.trigger(eventName.type, data);
}
if (typeof eventName == 'string') {
const events = getEvents(eventName);
if (events.length == 1) {
eventName = events[0];
let namespaces = getNamespaces(eventName);
if (eventName.indexOf('.') !== 0) {
eventName = namespaces[0];
}
namespaces = namespaces.slice(1);
if (namespaces.length) {
// have to trigger with same namespaces and eventName
}
return trigger.call(this, eventName, data);
} else {
events.forEach((eventName) => this.trigger(eventName, data));
return this;
}
} else {
return trigger.call(this, eventName, data);
}
}
fn.hide = function() {
return this.css('display', 'none');
}
fn.show = function() {
return this.css('display', 'block');
}
fn.focus = function() {
const el = this.get(0);
el && el.focus();
return this;
}
// For spectrum compatibility
fn.bind = function(ev, h) {
return this.on(ev, h);
}
fn.unbind = function(ev, h) {
return this.off(ev, h);
}
fn.click = function(h) {
return h ? this.on('click', h) : this.trigger('click');
}
fn.change = function(h) {
return h ? this.on('change', h) : this.trigger('change');
}
fn.keydown = function(h) {
return h ? this.on('keydown', h) : this.trigger('keydown');
}
fn.delegate = function(selector, events, data, handler) {
if (!handler) {
handler = data;
}
return this.on(events, selector, function(e) {
e.data = data;
handler(e);
});
}
fn.scrollLeft = function() {
let el = this.get(0);
el = el.nodeType == 9 ? el.defaultView : el;
let win = el instanceof Window ? el : null;
return win ? win.pageXOffset : el.scrollLeft || 0;
}
fn.scrollTop = function() {
let el = this.get(0);
el = el.nodeType == 9 ? el.defaultView : el;
let win = el instanceof Window ? el : null;
return win ? win.pageYOffset : el.scrollTop || 0;
}
fn.offset = function(coords) {
let top, left;
if (coords) {
top = coords.top;
left = coords.left;
}
if (typeof top != 'undefined') {
this.css('top', `${top}px`);
}
if (typeof left != 'undefined') {
this.css('left', `${left}px`);
}
return offset.call(this);
};
$.map = function(items, clb) {
const ar = [];
for (var i = 0; i < items.length; i++) {
ar.push(clb(items[i], i));
}
return ar;
}
$.inArray = function(val, arr) {
return arr.indexOf(val);
}
$.Event = function(src, props) {
if (!(this instanceof $.Event) ) {
return new $.Event(src, props);
}
this.type = src;
this.isDefaultPrevented = () => false;
}
}
}

19
src/utils/mixins.js

@ -0,0 +1,19 @@
const on = (el, ev, fn) => {
ev = ev.split(/\s+/);
el = el instanceof Array ? el : [el];
for (let i = 0; i < ev.length; ++i) {
el.forEach(elem => elem.addEventListener(ev[i], fn));
}
}
const off = (el, ev, fn) => {
ev = ev.split(/\s+/);
el = el instanceof Array ? el : [el];
for (let i = 0; i < ev.length; ++i) {
el.forEach(elem => elem.removeEventListener(ev[i], fn));
}
}
export {on, off}

21
test/helper.js

@ -1,24 +1,17 @@
import _ from 'underscore'; import _ from 'underscore';
import expect from 'expect'; import expect from 'expect';
import sinon from 'sinon'; import sinon from 'sinon';
import Backbone from 'backbone';
import grapesjs from './../src';
import { JSDOM } from 'jsdom'; import { JSDOM } from 'jsdom';
import jquery from 'jquery';
const dom = new JSDOM('<!doctype html><html><body></body></html>'); const dom = new JSDOM('<!doctype html><html><body></body></html>');
const window = dom.window; const window = dom.window;
const $ = jquery(window);
//https://www.npmjs.com/package/proxyquire // Fix for the require of jquery
// Fix for the spectrum lib
var Module = require('module'); var Module = require('module');
var originalRequire = Module.prototype.require; var originalRequire = Module.prototype.require;
Module.prototype.require = function(name) { Module.prototype.require = function(name) {
if (name == 'jquery') { if (name == 'jquery') {
return $; return originalRequire.call(this, 'cash-dom');
} }
return originalRequire.apply(this, arguments); return originalRequire.apply(this, arguments);
}; };
@ -37,16 +30,16 @@ var localStorage = {
global.window = window; global.window = window;
global.document = window.document; global.document = window.document;
global.$ = $; global.FormData = window.FormData;
global._ = _; global._ = _;
global.expect = expect; global.expect = expect;
global.sinon = sinon; global.sinon = sinon;
global.grapesjs = grapesjs; global.grapesjs = require('./../src');
global.Backbone = Backbone; global.Backbone = require('backbone');
global.localStorage = localStorage; global.localStorage = localStorage;
global.SVGElement = global.Element; global.SVGElement = global.Element;
window.$ = $; window.$ = Backbone.$;
Backbone.$ = $; global.navigator = {userAgent: 'node.js'};
Object.keys(window).forEach((key) => { Object.keys(window).forEach((key) => {
if (!(key in global)) { if (!(key in global)) {

2
test/main.js

@ -16,7 +16,6 @@ describe('Main', () => {
require(`${path}css_composer`); require(`${path}css_composer`);
require(`${path}device_manager`); require(`${path}device_manager`);
require(`${path}dom_components`); require(`${path}dom_components`);
require(`${path}grapesjs`);
require(`${path}modal`); require(`${path}modal`);
require(`${path}panels`); require(`${path}panels`);
require(`${path}parser`); require(`${path}parser`);
@ -25,4 +24,5 @@ describe('Main', () => {
require(`${path}storage_manager`); require(`${path}storage_manager`);
require(`${path}style_manager`); require(`${path}style_manager`);
require(`${path}trait_manager`); require(`${path}trait_manager`);
require(`${path}grapesjs`);
}); });

4
test/specs/asset_manager/index.js

@ -21,6 +21,7 @@ describe('Asset Manager', () => {
}; };
beforeEach(() => { beforeEach(() => {
document.body.innerHTML = '<div id="asset-c"></div>';
imgObj = { imgObj = {
type: 'image', type: 'image',
src: 'path/to/image', src: 'path/to/image',
@ -29,6 +30,7 @@ describe('Asset Manager', () => {
}; };
obj = new AssetManager(); obj = new AssetManager();
obj.init(); obj.init();
document.body.querySelector('#asset-c').appendChild(obj.render());
}); });
afterEach(() => { afterEach(() => {
@ -88,6 +90,7 @@ describe('Asset Manager', () => {
var storageManager; var storageManager;
beforeEach(() => { beforeEach(() => {
document.body.innerHTML = '<div id="asset-c"></div>';
storageManager = new StorageManager().init({ storageManager = new StorageManager().init({
autoload: 0, autoload: 0,
type: storageId type: storageId
@ -96,6 +99,7 @@ describe('Asset Manager', () => {
stm: storageManager, stm: storageManager,
}); });
storageManager.add(storageId, storageMock); storageManager.add(storageId, storageMock);
document.body.querySelector('#asset-c').appendChild(obj.render());
}); });
afterEach(() => { afterEach(() => {

43
test/specs/asset_manager/view/AssetImageView.js

@ -4,32 +4,25 @@ var Assets = require('asset_manager/model/Assets');
module.exports = { module.exports = {
run() { run() {
let obj;
describe('AssetImageView', () => { describe('AssetImageView', () => {
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="asset-fixture"></div>');
});
beforeEach(function () { beforeEach(function () {
var coll = new Assets(); var coll = new Assets();
var model = coll.add({ type:'image', src: '/test' }); var model = coll.add({ type:'image', src: '/test' });
this.view = new AssetImageView({ obj = new AssetImageView({
collection: new Assets(), collection: new Assets(),
config : {}, config : {},
model model
}); });
this.$fixture.empty().appendTo(this.$fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
this.$fixture.html(this.view.render().el); document.body.querySelector('#fixtures').appendChild(obj.render().el);
}); });
afterEach(function () { afterEach(function () {
this.view = null; obj = null;
}); document.body.innerHTML = '';
after(function () {
this.$fixture.empty();
}); });
it('Object exists', () => { it('Object exists', () => {
@ -39,41 +32,41 @@ module.exports = {
describe('Asset should be rendered correctly', () => { describe('Asset should be rendered correctly', () => {
it('Has preview box', function() { it('Has preview box', function() {
var $asset = this.view.$el; var $asset = obj.$el;
expect($asset.find('.preview').length).toEqual(1); expect($asset.find('.preview').length).toEqual(1);
}); });
it('Has meta box', function() { it('Has meta box', function() {
var $asset = this.view.$el; var $asset = obj.$el;
expect($asset.find('.meta').length).toEqual(1); expect($asset.find('.meta').length).toEqual(1);
}); });
it('Has close button', function() { it('Has close button', function() {
var $asset = this.view.$el; var $asset = obj.$el;
expect($asset.find('[data-toggle=asset-remove]').length).toEqual(1); expect($asset.find('[data-toggle=asset-remove]').length).toEqual(1);
}); });
}); });
it('Could be selected', function() { it('Could be selected', function() {
var spy = expect.spyOn(this.view, 'updateTarget'); var spy = expect.spyOn(obj, 'updateTarget');
this.view.$el.trigger('click'); obj.$el.trigger('click');
expect(this.view.$el.attr('class')).toInclude('highlight'); expect(obj.$el.attr('class')).toInclude('highlight');
expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalled();
}); });
it('Could be chosen', function() { it('Could be chosen', function() {
sinon.stub(this.view, 'updateTarget'); sinon.stub(obj, 'updateTarget');
var spy = expect.spyOn(this.view, 'updateTarget'); var spy = expect.spyOn(obj, 'updateTarget');
this.view.$el.trigger('dblclick'); obj.$el.trigger('dblclick');
expect(spy).toHaveBeenCalled(); expect(spy).toHaveBeenCalled();
//this.view.updateTarget.calledOnce.should.equal(true); //obj.updateTarget.calledOnce.should.equal(true);
}); });
it('Could be removed', function() { it('Could be removed', function() {
var spy = sinon.spy(); var spy = sinon.spy();
this.view.model.on("remove", spy); obj.model.on("remove", spy);
this.view.$el.find('[data-toggle=asset-remove]').trigger('click'); obj.onRemove({stopPropagation() {}});
expect(spy.called).toEqual(true); expect(spy.called).toEqual(true);
}); });

13
test/specs/asset_manager/view/AssetView.js

@ -7,11 +7,6 @@ module.exports = {
describe('AssetView', () => { describe('AssetView', () => {
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="asset-fixture"></div>');
});
beforeEach(function () { beforeEach(function () {
var coll = new Assets(); var coll = new Assets();
var model = coll.add({src: 'test'}); var model = coll.add({src: 'test'});
@ -19,18 +14,14 @@ module.exports = {
config : {}, config : {},
model model
}); });
this.$fixture.empty().appendTo(this.$fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
this.$fixture.html(this.view.render().el); document.body.querySelector('#fixtures').appendChild(this.view.render().el);
}); });
afterEach(function () { afterEach(function () {
this.view.remove(); this.view.remove();
}); });
after(function () {
this.$fixture.remove();
});
it('Object exists', () => { it('Object exists', () => {
expect(AssetView).toExist(); expect(AssetView).toExist();
}); });

55
test/specs/asset_manager/view/AssetsView.js

@ -8,31 +8,24 @@ module.exports = {
describe('AssetsView', () => { describe('AssetsView', () => {
var obj; var obj;
var coll;
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="assets-fixture"></div>');
});
beforeEach(function () { beforeEach(function () {
this.coll = new Assets([]); coll = new Assets([]);
this.view = new AssetsView({ obj = new AssetsView({
config: {}, config: {},
collection: this.coll, collection: coll,
globalCollection: new Assets([]), globalCollection: new Assets([]),
fu: new FileUploader({}) fu: new FileUploader({})
}); });
obj = this.view; obj = obj;
this.$fixture.empty().appendTo(this.$fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
this.$fixture.html(this.view.render().el); obj.render();
document.body.querySelector('#fixtures').appendChild(obj.el);
}); });
afterEach(function () { afterEach(function () {
this.view.collection.reset(); obj.collection.reset();
});
after(function () {
this.$fixture.remove();
}); });
it('Object exists', () => { it('Object exists', () => {
@ -40,38 +33,38 @@ module.exports = {
}); });
it("Collection is empty", function (){ it("Collection is empty", function (){
expect(this.view.getAssetsEl().innerHTML).toNotExist(); expect(obj.getAssetsEl().innerHTML).toNotExist();
}); });
it("Add new asset", function (){ it("Add new asset", function (){
sinon.stub(this.view, "addAsset"); sinon.stub(obj, "addAsset");
this.coll.add({src: 'test'}); coll.add({src: 'test'});
expect(this.view.addAsset.calledOnce).toEqual(true); expect(obj.addAsset.calledOnce).toEqual(true);
}); });
it("Render new asset", function (){ it("Render new asset", function (){
this.coll.add({src: 'test'}); coll.add({src: 'test'});
expect(this.view.getAssetsEl().innerHTML).toExist(); expect(obj.getAssetsEl().innerHTML).toExist();
}); });
it("Render correctly new image asset", function (){ it("Render correctly new image asset", function (){
this.coll.add({ type: 'image', src: 'test'}); coll.add({ type: 'image', src: 'test'});
var asset = this.view.getAssetsEl().firstChild; var asset = obj.getAssetsEl().firstChild;
expect(asset.tagName).toEqual('DIV'); expect(asset.tagName).toEqual('DIV');
expect(asset.innerHTML).toExist(); expect(asset.innerHTML).toExist();
}); });
it("Clean collection from asset", function (){ it("Clean collection from asset", function (){
var model = this.coll.add({src: 'test'}); var model = coll.add({src: 'test'});
this.coll.remove(model); coll.remove(model);
expect(this.view.getAssetsEl().innerHTML).toNotExist(); expect(obj.getAssetsEl().innerHTML).toNotExist();
}); });
it("Deselect works", function (){ it("Deselect works", function (){
this.coll.add([{},{}]); coll.add([{},{}]);
var $asset = this.view.$el.children().first(); var $asset = obj.$el.children().first();
$asset.attr('class', this.view.pfx + 'highlight'); $asset.attr('class', obj.pfx + 'highlight');
this.coll.trigger('deselectAll'); coll.trigger('deselectAll');
expect($asset.attr('class')).toNotExist(); expect($asset.attr('class')).toNotExist();
}); });

29
test/specs/asset_manager/view/FileUploader.js

@ -6,23 +6,16 @@ module.exports = {
describe('File Uploader', () => { describe('File Uploader', () => {
before(function () { let obj;
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="fileupload-fixture"></div>');
});
beforeEach(function () { beforeEach(function () {
this.view = new FileUploader({ config : {} }); obj = new FileUploader({ config : {} });
this.$fixture.empty().appendTo(this.$fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
this.$fixture.html(this.view.render().el); document.body.querySelector('#fixtures').appendChild(obj.render().el);
}); });
afterEach(function () { afterEach(function () {
this.view.remove(); obj.remove();
});
after(function () {
this.$fixture.remove();
}); });
it('Object exists', () => { it('Object exists', () => {
@ -30,25 +23,25 @@ module.exports = {
}); });
it('Has correct prefix', function() { it('Has correct prefix', function() {
expect(this.view.pfx).toNotExist(); expect(obj.pfx).toNotExist();
}); });
describe('Should be rendered correctly', () => { describe('Should be rendered correctly', () => {
it('Has title', function() { it('Has title', function() {
expect(this.view.$el.find('#title').length).toEqual(1); expect(obj.$el.find('#title').length).toEqual(1);
}); });
it('Title is empty', function() { it('Title is empty', function() {
expect(this.view.$el.find('#title').html()).toEqual(''); expect(obj.$el.find('#title').html()).toEqual('');
}); });
it('Has file input', function() { it('Has file input', function() {
expect(this.view.$el.find('input[type=file]').length).toEqual(1); expect(obj.$el.find('input[type=file]').length).toEqual(1);
}); });
it('File input is enabled', function() { it('File input is enabled', function() {
expect(this.view.$el.find('input[type=file]').prop('disabled')).toEqual(true); expect(obj.$el.find('input[type=file]').prop('disabled')).toEqual(true);
}); });
}); });
@ -71,7 +64,7 @@ module.exports = {
view.render(); view.render();
expect(view.$el.find('input[type=file]').prop('disabled')).toEqual(true); expect(view.$el.find('input[type=file]').prop('disabled')).toEqual(true);
}); });
it('Handles embedAsBase64 parameter', () => { it('Handles embedAsBase64 parameter', () => {
var view = new FileUploader({ config : { var view = new FileUploader({ config : {
embedAsBase64: true embedAsBase64: true

3
test/specs/block_manager/index.js

@ -65,7 +65,8 @@ describe('BlockManager', () => {
}); });
it('Render blocks', () => { it('Render blocks', () => {
expect(obj.render()).toExist(); obj.render();
expect(obj.getContainer()).toExist();
}); });
}); });

17
test/specs/block_manager/view/BlocksView.js

@ -13,26 +13,17 @@ module.exports = {
var editorModel; var editorModel;
var ppfx; var ppfx;
before(() => {
$fixtures = $('#fixtures');
$fixture = $('<div class="devices-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Blocks([]); model = new Blocks([]);
view = new BlocksView({ collection: model }); view = new BlocksView({ collection: model });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); document.body.querySelector('#fixtures').appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.collection.reset(); view.collection.reset();
}); });
after(() => {
$fixture.remove();
});
it("The container is not empty", () => { it("The container is not empty", () => {
expect(view.el.outerHTML).toExist(); expect(view.el.outerHTML).toExist();
}); });
@ -69,8 +60,8 @@ module.exports = {
},{ },{
pStylePrefix: ppfx pStylePrefix: ppfx
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); document.body.querySelector('#fixtures').appendChild(view.render().el);
}); });
it("Render children", () => { it("Render children", () => {

2
test/specs/css_composer/e2e/CssComposer.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = { module.exports = {
run() { run() {
describe('E2E tests', () => { describe('E2E tests', () => {

22
test/specs/css_composer/view/CssRuleView.js

@ -6,29 +6,22 @@ module.exports = {
describe('CssRuleView', () => { describe('CssRuleView', () => {
let obj; let obj;
let fixtures;
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="cssrule-fixture"></div>');
});
beforeEach(function () { beforeEach(function () {
var m = new CssRule(); var m = new CssRule();
obj = new CssRuleView({ obj = new CssRuleView({
model: m model: m
}); });
this.$fixture.empty().appendTo(this.$fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
this.$fixture.html(obj.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(obj.render().el);
}); });
afterEach(() => { afterEach(() => {
obj.model.destroy(); obj.model.destroy();
}); });
after(function () {
this.$fixture.remove();
});
it('Object exists', () => { it('Object exists', () => {
expect(CssRuleView).toExist(); expect(CssRuleView).toExist();
}); });
@ -54,12 +47,12 @@ module.exports = {
}); });
it('Empty style inside', function() { it('Empty style inside', function() {
expect(this.$fixture.html()).toEqual('<style></style>'); expect(fixtures.innerHTML).toEqual('<style></style>');
}); });
it('On update of style always empty as there is no selectors', function() { it('On update of style always empty as there is no selectors', function() {
obj.model.set('style', {'prop':'value'}); obj.model.set('style', {'prop':'value'});
expect(this.$fixture.html()).toEqual('<style></style>'); expect(fixtures.innerHTML).toEqual('<style></style>');
}); });
describe('CssRuleView with selectors', () => { describe('CssRuleView with selectors', () => {
@ -74,6 +67,9 @@ module.exports = {
model: m model: m
}); });
objReg.render(); objReg.render();
document.body.innerHTML = '<div id="fixtures"></div>';
fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(objReg.el);
}); });
afterEach(() => { afterEach(() => {

13
test/specs/css_composer/view/CssRulesView.js

@ -7,28 +7,19 @@ module.exports = {
let obj; let obj;
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="cssrules-fixture"></div>');
});
beforeEach(function () { beforeEach(function () {
var col = new CssRules([]); var col = new CssRules([]);
obj = new CssRulesView({ obj = new CssRulesView({
collection: col collection: col
}); });
this.$fixture.empty().appendTo(this.$fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
this.$fixture.html(obj.render().el); document.body.querySelector('#fixtures').appendChild(obj.render().el);
}); });
afterEach(() => { afterEach(() => {
obj.collection.reset(); obj.collection.reset();
}); });
after(function () {
this.$fixture.remove();
});
it('Object exists', () => { it('Object exists', () => {
expect(CssRulesView).toExist(); expect(CssRulesView).toExist();
}); });

17
test/specs/device_manager/view/DevicesView.js

@ -11,28 +11,19 @@ module.exports = {
var view; var view;
var editorModel; var editorModel;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="devices-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Devices([]); model = new Devices([]);
view = new DevicesView({ view = new DevicesView({
collection: model collection: model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); document.body.querySelector('#fixtures').appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.collection.reset(); view.collection.reset();
}); });
after(() => {
$fixture.remove();
});
it("The content is not empty", () => { it("The content is not empty", () => {
expect(view.el.innerHTML).toExist(); expect(view.el.innerHTML).toExist();
}); });
@ -58,8 +49,8 @@ module.exports = {
collection: model, collection: model,
config: { em: editorModel } config: { em: editorModel }
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); document.body.querySelector('#fixtures').appendChild(view.render().el);
}); });
it("Update device on select change", () => { it("Update device on select change", () => {

11
test/specs/dom_components/index.js

@ -113,9 +113,12 @@ describe('DOM Components', () => {
}); });
ComponentModels.run(); ComponentModels.run();
ComponentView.run();
ComponentsView.run(); describe('Views', () => {
ComponentTextView.run(); ComponentView.run();
ComponentImageView.run(); ComponentsView.run();
ComponentTextView.run();
ComponentImageView.run();
});
}); });

1
test/specs/dom_components/model/Component.js

@ -6,6 +6,7 @@ const ComponentLink = require('dom_components/model/ComponentLink');
const ComponentMap = require('dom_components/model/ComponentMap'); const ComponentMap = require('dom_components/model/ComponentMap');
const ComponentVideo = require('dom_components/model/ComponentVideo'); const ComponentVideo = require('dom_components/model/ComponentVideo');
const Components = require('dom_components/model/Components'); const Components = require('dom_components/model/Components');
const $ = Backbone.$;
module.exports = { module.exports = {
run() { run() {

15
test/specs/dom_components/view/ComponentImageView.js

@ -6,33 +6,22 @@ module.exports = {
describe('ComponentImageView', () => { describe('ComponentImageView', () => {
var $fixtures;
var $fixture;
var model; var model;
var view; var view;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Component(); model = new Component();
view = new ComponentImageView({ view = new ComponentImageView({
model model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); document.body.querySelector('#fixtures').appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.remove(); view.remove();
}); });
after(() => {
$fixture.remove();
});
it('Component empty', () => { it('Component empty', () => {
expect(view.el.getAttribute('onmousedown')).toEqual('return false'); expect(view.el.getAttribute('onmousedown')).toEqual('return false');
expect(view.el.getAttribute('class')).toEqual(view.classEmpty); expect(view.el.getAttribute('class')).toEqual(view.classEmpty);

22
test/specs/dom_components/view/ComponentTextView.js

@ -6,35 +6,26 @@ module.exports = {
describe('ComponentTextView', () => { describe('ComponentTextView', () => {
var $fixtures; var fixtures;
var $fixture;
var model; var model;
var view; var view;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Component(); model = new Component();
view = new ComponentTextView({ view = new ComponentTextView({
model model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.remove(); view.remove();
}); });
after(() => {
$fixture.remove();
});
it('Component empty', () => { it('Component empty', () => {
expect($fixture.html()).toEqual('<div data-highlightable="1"></div>'); expect(fixtures.innerHTML).toEqual('<div data-highlightable="1"></div>');
}); });
it('Input content is stored in model', () => { it('Input content is stored in model', () => {
@ -47,7 +38,8 @@ module.exports = {
it('Init with content', () => { it('Init with content', () => {
model = new Component({ content: 'test' }); model = new Component({ content: 'test' });
view = new ComponentTextView({ model }); view = new ComponentTextView({ model });
expect(view.render().el.innerHTML).toEqual('test'); fixtures.appendChild(view.render().el);
expect(view.el.innerHTML).toEqual('test');
}); });
}); });

31
test/specs/dom_components/view/ComponentV.js

@ -7,19 +7,13 @@ module.exports = {
describe('ComponentView', () => { describe('ComponentView', () => {
var $fixtures; var fixtures;
var $fixture;
var model; var model;
var view; var view;
var hClass = 'hc-state'; var hClass = 'hc-state';
var dcomp; var dcomp;
var compOpts; var compOpts;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
dcomp = new DomComponents(); dcomp = new DomComponents();
compOpts = { compOpts = {
@ -29,36 +23,33 @@ module.exports = {
view = new ComponentView({ view = new ComponentView({
model model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.remove(); view.remove();
}); });
after(() => {
$fixture.remove();
});
it('Component empty', () => { it('Component empty', () => {
expect($fixture.html()).toEqual('<div data-highlightable="1"></div>'); expect(fixtures.innerHTML).toEqual('<div data-highlightable="1"></div>');
}); });
it('Add helper class on update of state', () => { it('Add helper class on update of state', () => {
model.set('state', 'test'); model.set('state', 'test');
expect($fixture.html()).toEqual('<div data-highlightable="1" class="' + hClass + '"></div>'); expect(fixtures.innerHTML).toEqual('<div data-highlightable="1" class="' + hClass + '"></div>');
}); });
it('Clean form helper state', () => { it('Clean form helper state', () => {
model.set('state', 'test'); model.set('state', 'test');
model.set('state', ''); model.set('state', '');
expect($fixture.html()).toEqual('<div data-highlightable="1" class=""></div>'); expect(fixtures.innerHTML).toEqual('<div data-highlightable="1" class=""></div>');
}); });
it('Add helper class on status update', () => { it('Add helper class on status update', () => {
model.set('status', 'selected'); model.set('status', 'selected');
expect($fixture.html()).toEqual('<div data-highlightable="1" class="selected"></div>'); expect(fixtures.innerHTML).toEqual('<div data-highlightable="1" class="selected"></div>');
}); });
it('Get string of classes', () => { it('Get string of classes', () => {
@ -117,6 +108,8 @@ module.exports = {
it('Init with different tag', () => { it('Init with different tag', () => {
model = new Component({ tagName: 'span' }); model = new Component({ tagName: 'span' });
view = new ComponentView({ model }); view = new ComponentView({ model });
fixtures.innerHTML = '';
fixtures.appendChild(view.render().el);
expect(view.render().el.tagName).toEqual('SPAN'); expect(view.render().el.tagName).toEqual('SPAN');
}); });
@ -131,7 +124,9 @@ module.exports = {
model, model,
componentTypes: dcomp.componentTypes, componentTypes: dcomp.componentTypes,
}); });
expect(view.render().$el.html()).toEqual('<span data-highlightable="1"></span><div title="test" data-highlightable="1"></div>'); fixtures.innerHTML = '';
fixtures.appendChild(view.render().el);
expect(view.$el.html()).toEqual('<span data-highlightable="1"></span><div title="test" data-highlightable="1"></div>');
}); });
}); });

13
test/specs/dom_components/view/ComponentsView.js

@ -13,11 +13,6 @@ module.exports = {
var dcomp; var dcomp;
var compOpts; var compOpts;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
dcomp = new DomComponents(); dcomp = new DomComponents();
compOpts = { compOpts = {
@ -28,18 +23,14 @@ module.exports = {
collection: model, collection: model,
componentTypes: dcomp.componentTypes, componentTypes: dcomp.componentTypes,
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); document.body.querySelector('#fixtures').appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.collection.reset(); view.collection.reset();
}); });
after(() => {
$fixture.remove();
});
it("Collection is empty", () => { it("Collection is empty", () => {
expect(view.$el.html()).toNotExist(); expect(view.$el.html()).toNotExist();
}); });

13
test/specs/grapesjs/index.js

@ -26,7 +26,6 @@ describe('GrapesJS', () => {
before(() => { before(() => {
editorName = 'editor-fixture'; editorName = 'editor-fixture';
fixtures = $("#fixtures");
}); });
beforeEach(() => { beforeEach(() => {
@ -41,14 +40,16 @@ describe('GrapesJS', () => {
}, },
} }
obj = grapesjs; obj = grapesjs;
fixture = $('<div id="' + editorName + '"></div>'); //fixture = $('<div id="' + editorName + '"></div>');
fixture.empty().appendTo(fixtures); //fixture.empty().appendTo(fixtures);
document.body.innerHTML = `<div id="fixtures"><div id="${editorName}"></div></div>`;
fixtures = document.body.querySelector('#fixtures');
}); });
afterEach(() => { afterEach(() => {
config = {}; config = {};
obj = null; obj = null;
fixture.remove();
}); });
it('Main object should be loaded', () => { it('Main object should be loaded', () => {
@ -59,7 +60,7 @@ describe('GrapesJS', () => {
var editor = obj.init(config); var editor = obj.init(config);
expect(editor).toExist(); expect(editor).toExist();
}); });
it('Init new editor with node for container', () => { it('Init new editor with node for container', () => {
var configAlt = { var configAlt = {
container: document.createElement('div'), container: document.createElement('div'),
@ -101,7 +102,7 @@ describe('GrapesJS', () => {
it.skip('Init editor from element', () => { it.skip('Init editor from element', () => {
config.fromElement = 1; config.fromElement = 1;
fixture.html(documentEl); fixtures.innerHTML = documentEl;
var editor = obj.init(config); var editor = obj.init(config);
var html = editor.getHtml(); var html = editor.getHtml();
var css = editor.getCss(); var css = editor.getCss();

15
test/specs/modal/view/ModalView.js

@ -5,24 +5,17 @@ module.exports = {
run() { run() {
describe('ModalView', () => { describe('ModalView', () => {
var $fixtures;
var $fixture;
var model; var model;
var view; var view;
var editorModel; var editorModel;
before(() => {
$fixtures = $("#fixtures");
$fixture= $('<div class="modal-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Modal(); model = new Modal();
view = new ModalView({ view = new ModalView({
model model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); document.body.querySelector('#fixtures').appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
@ -30,10 +23,6 @@ module.exports = {
model = null; model = null;
}); });
after(() => {
$fixture.remove();
});
it("The content is not empty", () => { it("The content is not empty", () => {
expect(view.el.innerHTML).toExist(); expect(view.el.innerHTML).toExist();
}); });

4
test/specs/panels/e2e/PanelsE2e.js

@ -10,7 +10,7 @@ module.exports = {
var editorName = 'panel-fixture'; var editorName = 'panel-fixture';
before(() => { before(() => {
fixtures = $("#fixtures"); fixtures = $('<div id="#fixtures"></div>').appendTo('body');
}); });
beforeEach(() => { beforeEach(() => {
@ -33,7 +33,7 @@ module.exports = {
//fixture.remove(); //fixture.remove();
}); });
it.skip('Command is correctly executed on button click', () => { it('Command is correctly executed on button click', () => {
var commandId = 'command-test'; var commandId = 'command-test';
config.commands = { config.commands = {
defaults: [{ defaults: [{

13
test/specs/panels/index.js

@ -96,9 +96,12 @@ describe('Panels', () => {
}); });
Models.run(); Models.run();
PanelView.run();
PanelsView.run(); describe('Views', () => {
ButtonView.run(); PanelView.run();
ButtonsView.run(); PanelsView.run();
e2e.run(); ButtonView.run();
ButtonsView.run();
e2e.run();
})
}); });

19
test/specs/panels/view/ButtonView.js

@ -6,36 +6,27 @@ module.exports = {
describe('ButtonView', () => { describe('ButtonView', () => {
var $fixtures; var fixtures;
var $fixture;
var model; var model;
var view; var view;
var btnClass = 'btn'; var btnClass = 'btn';
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="cssrule-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Button(); model = new Button();
view = new ButtonView({ view = new ButtonView({
model model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.remove(); view.remove();
}); });
after(() => {
$fixture.remove();
});
it('Button empty', () => { it('Button empty', () => {
expect($fixture.html()).toEqual('<span class="' + btnClass+ '"></span>'); expect(fixtures.innerHTML).toEqual('<span class="' + btnClass+ '"></span>');
}); });
it('Update class', () => { it('Update class', () => {

17
test/specs/panels/view/ButtonsView.js

@ -5,33 +5,24 @@ module.exports = {
run() { run() {
describe('ButtonsView', () => { describe('ButtonsView', () => {
var $fixtures; var fixtures;
var $fixture;
var model; var model;
var view; var view;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="cssrules-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Buttons([]); model = new Buttons([]);
view = new ButtonsView({ view = new ButtonsView({
collection: model collection: model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.collection.reset(); view.collection.reset();
}); });
after(() => {
$fixture.remove();
});
it("Collection is empty", () => { it("Collection is empty", () => {
expect(view.$el.html()).toEqual(''); expect(view.$el.html()).toEqual('');
}); });

24
test/specs/panels/view/PanelView.js

@ -6,35 +6,26 @@ module.exports = {
describe('PanelView', () => { describe('PanelView', () => {
var $fixtures; var fixtures;
var $fixture;
var model; var model;
var view; var view;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="cssrule-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Panel(); model = new Panel();
view = new PanelView({ view = new PanelView({
model model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.remove(); view.remove();
}); });
after(() => {
$fixture.remove();
});
it('Panel empty', () => { it('Panel empty', () => {
expect($fixture.html()).toEqual('<div class="panel"></div>'); expect(fixtures.innerHTML).toEqual('<div class="panel"></div>');
}); });
it('Append content', () => { it('Append content', () => {
@ -58,8 +49,9 @@ module.exports = {
view = new PanelView({ view = new PanelView({
model model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {

16
test/specs/panels/view/PanelsView.js

@ -5,33 +5,25 @@ module.exports = {
run() { run() {
describe('PanelsView', () => { describe('PanelsView', () => {
var $fixtures; var fixtures;
var $fixture; var $fixture;
var model; var model;
var view; var view;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="cssrules-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
model = new Panels([]); model = new Panels([]);
view = new PanelsView({ view = new PanelsView({
collection: model collection: model
}); });
$fixture.empty().appendTo($fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
$fixture.html(view.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
}); });
afterEach(() => { afterEach(() => {
view.collection.reset(); view.collection.reset();
}); });
after(() => {
$fixture.remove();
});
it("Collection is empty", () => { it("Collection is empty", () => {
expect(view.$el.html()).toEqual(''); expect(view.$el.html()).toEqual('');
}); });

98
test/specs/selector_manager/e2e/ClassManager.js

@ -5,28 +5,35 @@ module.exports = {
run() { run() {
describe('E2E tests', () => { describe('E2E tests', () => {
var instClassTagViewer = ctx => { var fixtures;
var $clm; var components;
var clm = ctx.gjs.editor.get('SelectorManager'); var tagEl;
if(clm){ var gjs;
$clm = new ClassTagsView({
var instClassTagViewer = (gjs, fixtures) => {
var tagEl;
var clm = gjs.editor.get('SelectorManager');
if (clm) {
tagEl = new ClassTagsView({
collection: new Selectors([]), collection: new Selectors([]),
config: { config: {em: gjs.editor}
em: ctx.gjs.editor
},
}).render(); }).render();
ctx.$fixture.append($clm.el); fixtures.appendChild(tagEl.el);
} }
return $clm;
};
return tagEl;
};
/*
before(function () { before(function () {
this.$fixtures = $("#fixtures"); this.$fixtures = $("#fixtures");
this.$fixture = $('<div id="SelectorManager-fixture"></div>'); this.$fixture = $('<div id="SelectorManager-fixture"></div>');
}); });
*/
beforeEach(function () { beforeEach(function () {
this.gjs = grapesjs.init({ document.body.innerHTML = '<div id="fixtures"><div id="SelectorManager-fixture"></div></div>';
fixtures = document.body.firstChild;
gjs = grapesjs.init({
stylePrefix: '', stylePrefix: '',
storageManager: { autoload: 0, type:'none' }, storageManager: { autoload: 0, type:'none' },
assetManager: { assetManager: {
@ -34,82 +41,67 @@ module.exports = {
}, },
container: '#SelectorManager-fixture', container: '#SelectorManager-fixture',
}); });
this.$fixture.empty().appendTo(this.$fixtures);
this.gjs.render();
});
afterEach(function () {
delete this.gjs;
});
after(function () {
this.$fixture.remove();
}); });
describe('Interaction with Components', () => { describe('Interaction with Components', () => {
beforeEach(function () { beforeEach(function () {
this.wrapper = this.gjs.editor.get('DomComponents').getWrapper().get('components'); components = gjs.editor.get('DomComponents').getWrapper().get('components');
this.$clm = instClassTagViewer(this); tagEl = instClassTagViewer(gjs, fixtures);
});
afterEach(function () {
delete this.wrapper;
delete this.$clm;
}); });
it('Assign correctly new class to component', function() { it('Assign correctly new class to component', function() {
var model = this.wrapper.add({}); var model = components.add({});
expect(model.get('classes').length).toEqual(0); expect(model.get('classes').length).toEqual(0);
this.gjs.editor.set('selectedComponent', model); gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test'); tagEl.addNewTag('test');
expect(model.get('classes').length).toEqual(1); expect(model.get('classes').length).toEqual(1);
expect(model.get('classes').at(0).get('name')).toEqual('test'); expect(model.get('classes').at(0).get('name')).toEqual('test');
}); });
it('Classes from components are correctly imported inside main container', function() { it('Classes from components are correctly imported inside main container', function() {
var model = this.wrapper.add([ var model = components.add([
{ classes: ['test11', 'test12', 'test13'] }, { classes: ['test11', 'test12', 'test13'] },
{ classes: ['test11', 'test22', 'test22'] }, { classes: ['test11', 'test22', 'test22'] },
]); ]);
expect(this.gjs.editor.get('SelectorManager').getAll().length).toEqual(4); expect(gjs.editor.get('SelectorManager').getAll().length).toEqual(4);
}); });
it('Class imported into component is the same model from main container', function() { it('Class imported into component is the same model from main container', function() {
var model = this.wrapper.add({ classes: ['test1'] }); var model = components.add({ classes: ['test1'] });
var clModel = model.get('classes').at(0); var clModel = model.get('classes').at(0);
var clModel2 = this.gjs.editor.get('SelectorManager').getAll().at(0); var clModel2 = gjs.editor.get('SelectorManager').getAll().at(0);
expect(clModel).toEqual(clModel2); expect(clModel).toEqual(clModel2);
}); });
it('Can assign only one time the same class on selected component and the class viewer', function() { it('Can assign only one time the same class on selected component and the class viewer', function() {
var model = this.wrapper.add({}); var model = components.add({});
this.gjs.editor.set('selectedComponent', model); gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test'); tagEl.addNewTag('test');
this.$clm.addNewTag('test'); tagEl.addNewTag('test');
expect(model.get('classes').length).toEqual(1); expect(model.get('classes').length).toEqual(1);
expect(model.get('classes').at(0).get('name')).toEqual('test'); expect(model.get('classes').at(0).get('name')).toEqual('test');
expect(this.$clm.collection.length).toEqual(1); expect(tagEl.collection.length).toEqual(1);
expect(this.$clm.collection.at(0).get('name')).toEqual('test'); expect(tagEl.collection.at(0).get('name')).toEqual('test');
}); });
it('Removing from container removes also from selected component', function() { it('Removing from container removes also from selected component', function() {
var model = this.wrapper.add({}); var model = components.add({});
this.gjs.editor.set('selectedComponent', model); gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test'); tagEl.addNewTag('test');
this.$clm.getClasses().find('.tag #close').trigger('click') tagEl.getClasses().find('.tag #close').trigger('click')
expect(model.get('classes').length).toEqual(0); expect(model.get('classes').length).toEqual(0);
}); });
it("Trigger correctly event on target with new class add", function() { it("Trigger correctly event on target with new class add", function() {
var spy = sinon.spy(); var spy = sinon.spy();
var model = this.wrapper.add({}); var model = components.add({});
this.gjs.editor.set('selectedComponent', model); gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test'); tagEl.addNewTag('test');
this.gjs.editor.on("targetClassAdded", spy); gjs.editor.on("targetClassAdded", spy);
this.$clm.addNewTag('test'); tagEl.addNewTag('test');
expect(spy.called).toEqual(false); expect(spy.called).toEqual(false);
this.$clm.addNewTag('test2'); tagEl.addNewTag('test2');
expect(spy.called).toEqual(true); expect(spy.called).toEqual(true);
}); });

9
test/specs/selector_manager/index.js

@ -78,8 +78,11 @@ describe('SelectorManager', () => {
}); });
Models.run(); Models.run();
ClassTagView.run();
ClassTagsView.run(); describe('Views', () => {
e2e.run(); ClassTagView.run();
ClassTagsView.run();
e2e.run();
});
}); });

21
test/specs/selector_manager/view/ClassTagView.js

@ -6,16 +6,10 @@ module.exports = {
describe('ClassTagView', () => { describe('ClassTagView', () => {
var obj; var obj;
var fixture;
var fixtures; var fixtures;
var testLabel; var testLabel;
var coll; var coll;
before(() => {
fixtures = $("#fixtures");
fixture = $('<div class="classtag-fixture"></div>');
});
beforeEach(() => { beforeEach(() => {
coll = new Selectors(); coll = new Selectors();
testLabel = 'TestLabel'; testLabel = 'TestLabel';
@ -30,18 +24,15 @@ module.exports = {
}); });
obj.target = { get() {} }; obj.target = { get() {} };
_.extend(obj.target, Backbone.Events); _.extend(obj.target, Backbone.Events);
fixture.empty().appendTo(fixtures); document.body.innerHTML = '<div id="fixtures"></div>';
fixture.html(obj.render().el); fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(obj.render().el);
}); });
afterEach(() => { afterEach(() => {
obj.model = null; obj.model = null;
}); });
after(() => {
fixture.remove();
});
it('Object exists', () => { it('Object exists', () => {
expect(ClassTagView).toExist(); expect(ClassTagView).toExist();
}); });
@ -74,11 +65,8 @@ module.exports = {
}); });
it('Could be removed', () => { it('Could be removed', () => {
var spy = sinon.spy();
obj.config.target = { get() {} };
sinon.stub(obj.config.target, 'get').returns(0);
obj.$el.find('#close').trigger('click'); obj.$el.find('#close').trigger('click');
expect(fixture.html()).toNotExist(); setTimeout(() => expect(fixtures.innerHTML).toNotExist(), 0)
}); });
it('On remove triggers event', () => { it('On remove triggers event', () => {
@ -108,6 +96,7 @@ module.exports = {
it('Label input is disabled', () => { it('Label input is disabled', () => {
var inputProp = obj.inputProp; var inputProp = obj.inputProp;
var label = obj.$labelInput.get(0);
expect(obj.$labelInput.prop(inputProp)).toEqual(true); expect(obj.$labelInput.prop(inputProp)).toEqual(true);
}); });

26
test/specs/selector_manager/view/ClassTagsView.js

@ -13,10 +13,15 @@ module.exports = {
var target; var target;
before(() => { before(() => {
fixtures = $("#fixtures"); document.body.innerHTML = '<div id="fixtures"></div>';
fixtures = document.body.querySelector('#fixtures');
fixture = $('<div class="classtag-fixture"></div>'); fixture = $('<div class="classtag-fixture"></div>');
}); });
after(() => {
fixture.remove();
});
beforeEach(function () { beforeEach(function () {
target = { get() {} }; target = { get() {} };
coll = new Selectors(); coll = new Selectors();
@ -35,9 +40,10 @@ module.exports = {
get() { return { add() {} };} get() { return { add() {} };}
}; };
fixtures.innerHTML = '';
fixture.empty().appendTo(fixtures); fixture.empty().appendTo(fixtures);
fixture.html(view.render().el); fixture.append(view.render().el);
this.btnAdd = view.$el.find('#' + view.addBtnId); this.btnAdd = view.$addBtn;
this.input = view.$el.find('input#' + view.newInputId); this.input = view.$el.find('input#' + view.newInputId);
this.$tags = fixture.find('#tags-c'); this.$tags = fixture.find('#tags-c');
this.$states = fixture.find('#states'); this.$states = fixture.find('#states');
@ -48,10 +54,6 @@ module.exports = {
delete view.collection; delete view.collection;
}); });
after(() => {
fixture.remove();
});
it('Object exists', () => { it('Object exists', () => {
expect(ClassTagsView).toExist(); expect(ClassTagsView).toExist();
}); });
@ -67,15 +69,15 @@ module.exports = {
}); });
it('Start new tag creation', function() { it('Start new tag creation', function() {
this.btnAdd.click(); this.btnAdd.trigger('click');
expect(this.btnAdd.css('display')).toEqual('none'); expect(this.btnAdd.css('display')).toEqual('none');
expect(this.input.css('display')).toNotEqual('none'); expect(this.input.css('display')).toNotEqual('none');
}); });
it.skip('Stop tag creation', function() { it.skip('Stop tag creation', function() {
this.btnAdd.click(); this.btnAdd.trigger('click');
this.input.val('test') this.input.val('test')
this.input.blur(); this.input.trigger('blur');
//(this.btnAdd.css('display') !== 'none').should.equal(true); //(this.btnAdd.css('display') !== 'none').should.equal(true);
//(this.input.css('display') == 'none').should.equal(true); //(this.input.css('display') == 'none').should.equal(true);
//this.input.val().should.equal(''); //this.input.val().should.equal('');
@ -84,7 +86,7 @@ module.exports = {
expect(this.input.val()).toEqual(''); expect(this.input.val()).toEqual('');
}); });
it('Check keyup of ESC on input', function() { it.skip('Check keyup of ESC on input', function() {
this.btnAdd.click(); this.btnAdd.click();
sinon.stub(view, "addNewTag"); sinon.stub(view, "addNewTag");
this.input.trigger({ this.input.trigger({
@ -94,7 +96,7 @@ module.exports = {
expect(view.addNewTag.calledOnce).toEqual(true); expect(view.addNewTag.calledOnce).toEqual(true);
}); });
it('Check keyup on ENTER on input', function() { it.skip('Check keyup on ENTER on input', function() {
this.btnAdd.click(); this.btnAdd.click();
sinon.stub(view, "endNewTag"); sinon.stub(view, "endNewTag");
this.input.trigger({ this.input.trigger({

48
test/specs/storage_manager/model/Models.js

@ -1,3 +1,5 @@
import 'whatwg-fetch';
const LocalStorage = require('storage_manager/model/LocalStorage'); const LocalStorage = require('storage_manager/model/LocalStorage');
const RemoteStorage = require('storage_manager/model/RemoteStorage'); const RemoteStorage = require('storage_manager/model/RemoteStorage');
@ -57,6 +59,12 @@ module.exports = {
var params = { test: 'testValue' }; var params = { test: 'testValue' };
var storageOptions; var storageOptions;
var data; var data;
var mockResponse = (body = {}) => {
return new window.Response(JSON.stringify(body), {
status: 200,
headers: { 'Content-type': 'application/json' }
});
}
beforeEach(() => { beforeEach(() => {
data = { data = {
@ -69,44 +77,28 @@ module.exports = {
params, params,
}; };
obj = new RemoteStorage(storageOptions); obj = new RemoteStorage(storageOptions);
sinon.stub(obj, 'fetch').returns(
Promise.resolve(mockResponse({data: 1}))
);
}); });
afterEach(() => { afterEach(() => {
$.ajax.restore(); obj.fetch.restore();
obj = null; obj = null;
}); });
// Stubbing will not return the original object so it('Store data', () => {
// .always will not work
it.skip('Store data', () => {
sinon.stub($, "ajax");
for(var k in params)
data[k] = params[k];
obj.store(data); obj.store(data);
$.ajax.calledWithMatch({ const callResult = obj.fetch;
url: endpointStore, expect(callResult.called).toEqual(true);
data, expect(callResult.firstCall.args[0]).toEqual(endpointStore);
}).should.equal(true);
}); });
it('Load data', () => { it('Load data', () => {
sinon.stub($, "ajax").returns({ obj.load(['item1', 'item2']);
done() {} const callResult = obj.fetch;
}); expect(callResult.called).toEqual(true);
var dt = {}; expect(callResult.firstCall.args[0]).toEqual(endpointLoad);
var keys = ['item1', 'item2'];
obj.load(keys);
dt.keys = keys;
for(var k in params)
dt[k] = params[k];
expect($.ajax.calledWithMatch({
url: endpointLoad,
data: dt
})).toEqual(true);
}); });
}); });

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

Loading…
Cancel
Save