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">
<title>GrapesJS</title>
<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>
</head>
@ -1328,7 +1328,7 @@
console.log('STORE ', e);
})
editor.on('styleManager:change:border-width', function(view) {
editor.on('styleManager:change:text-shadow', function(view) {
var model = view.model;
let targetValue = view.getTargetValue({ignoreDefault: 1});
let computedValue = view.getComputedValue();

7
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.10.8",
"version": "0.11.4",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",
@ -13,6 +13,7 @@
"dependencies": {
"backbone": "^1.3.3",
"backbone-undo": "^0.2.5",
"cash-dom": "^1.3.5",
"codemirror": "^5.21.0",
"codemirror-formatting": "^1.0.0",
"font-awesome": "^4.7.0",
@ -39,7 +40,8 @@
"sinon": "^3.2.1",
"string-replace-loader": "^1.3.0",
"webpack": "^3.5.5",
"webpack-dev-server": "^2.7.1"
"webpack-dev-server": "^2.7.1",
"whatwg-fetch": "^2.0.3"
},
"keywords": [
"wte",
@ -64,6 +66,7 @@
"scripts": {
"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-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",
"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",

3
src/asset_manager/view/AssetsView.js

@ -153,7 +153,8 @@ module.exports = Backbone.View.extend({
if (hide) {
assetsEl.empty();
} 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)
* * [get](#get)
* * [getAll](#getall)
* * [getAllVisible](#getallvisible)
* * [getCategories](#getcategories)
* * [getContainer](#getcontainer)
* * [render](#render)
*
* 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'),
BlockCategories = require('./model/Categories'),
BlocksView = require('./view/BlocksView');
var blocks, view;
var blocks, blocksVisible, blocksView;
var categories = [];
return {
@ -52,19 +54,58 @@ module.exports = () => {
*/
init(config) {
c = config || {};
for (var name in defaults) {
if (!(name in c))
const em = c.em;
for (let name in defaults) {
if (!(name in c)) {
c[name] = defaults[name];
}
}
blocks = new Blocks(c.blocks);
// Global blocks collection
blocks = new Blocks([]);
blocksVisible = new Blocks([]);
categories = new BlockCategories(),
view = new BlocksView({
collection: blocks,
blocksView = new BlocksView({
// Visible collection
collection: blocksVisible,
categories,
}, c);
// Setup the sync between the global and public collections
blocks.listenTo(blocks, 'add', model => {
blocksVisible.add(model);
em && em.trigger('block:add', model);
});
blocks.listenTo(blocks, 'remove', model => {
blocksVisible.remove(model);
em && em.trigger('block:remove', model);
});
blocks.listenTo(blocks, 'reset', coll => {
blocksVisible.reset(coll.models);
});
return this;
},
/**
* Get configuration object
* @return {Object}
*/
getConfig() {
return c;
},
/**
* Loading blocks with `onLoad` allows to init starting collection
* from plugins
*/
onLoad() {
this.getAll().reset(c.blocks);
},
/**
* Add new block to the collection.
* @param {string} id Block id
@ -98,7 +139,7 @@ module.exports = () => {
* Return the block by id
* @param {string} id Block id
* @example
* var block = blockManager.get('h1-block');
* const block = blockManager.get('h1-block');
* console.log(JSON.stringify(block));
* // {label: 'Heading', content: '<h1>Put your ...', ...}
*/
@ -110,7 +151,7 @@ module.exports = () => {
* Return all blocks
* @return {Collection}
* @example
* var blocks = blockManager.getAll();
* const blocks = blockManager.getAll();
* console.log(JSON.stringify(blocks));
* // [{label: 'Heading', content: '<h1>Put your ...'}, ...]
*/
@ -118,9 +159,26 @@ module.exports = () => {
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.
* 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}
*/
getCategories() {
@ -128,20 +186,43 @@ module.exports = () => {
},
/**
* Render blocks
* Return the Blocks container element
* @return {HTMLElement}
*/
render() {
return view.render().el;
getContainer() {
return blocksView.el;
},
/**
* Remove block by id
* @param {string} id Block id
* @return {Block} Removed block
* Render blocks
* @param {Array} blocks Blocks to render, without the argument will render
* all global blocks
* @example
* // Render all blocks (inside the global collection)
* blockManager.render();
*
* // Render new set of blocks
* const blocks = blockManager.getAll();
* blockManager.render(blocks.filter(
* block => block.get('category') == 'sections'
* ));
* // Or a new set from an array
* blockManager.render([
* {label: 'Label text', content: '<div>Content</div>'}
* ]);
*
* // Back to blocks from the global collection
* blockManager.render();
*/
remove(id) {
return blocks.remove(id);
render(blocks) {
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({

12
src/block_manager/view/BlocksView.js

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

17
src/canvas/index.js

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

70
src/canvas/view/CanvasView.js

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

2
src/code_manager/view/EditorView.js

@ -18,7 +18,7 @@ module.exports = Backbone.View.extend({
obj.pfx = this.pfx;
this.$el.html( this.template(obj) );
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;
},

188
src/commands/view/CommandAbstract.js

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

4
src/commands/view/CreateComponent.js

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

4
src/commands/view/DeleteComponent.js

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

4
src/commands/view/ExportTemplate.js

@ -1,3 +1,5 @@
const $ = Backbone.$;
module.exports = {
run(editor, sender) {
@ -50,7 +52,7 @@ module.exports = {
var oCsslEd = this.buildEditor('css', 'hopscotch', 'CSS');
this.htmlEditor = oHtmlEd.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);
}

16
src/commands/view/MoveComponent.js

@ -1,6 +1,8 @@
var Backbone = require('backbone');
var SelectComponent = require('./SelectComponent');
var SelectPosition = require('./SelectPosition');
import {on, off} from 'utils/mixins'
const SelectComponent = require('./SelectComponent');
const SelectPosition = require('./SelectPosition');
const $ = Backbone.$;
module.exports = _.extend({}, SelectPosition, SelectComponent, {
@ -49,7 +51,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
this.sorter.onEndMove = this.onEndMove.bind(this);
this.stopSelectComponent();
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.getContentWindow().on('keydown', this.rollback);
on(this.getContentWindow(), 'keydown', this.rollback);
},
onEndMoveFromModel() {
this.getContentWindow().off('keydown', this.rollback);
off(this.getContentWindow(), 'keydown', this.rollback);
},
/**
@ -90,7 +92,7 @@ module.exports = _.extend({}, SelectPosition, SelectComponent, {
*/
onEndMove() {
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 = {
run(editor, sender) {
var config = editor.Config;
var pfx = config.stylePrefix;
var bm = editor.BlockManager;
var panelC;
if(!this.blocks){
this.blocks = $('<div/>').get(0);
this.blocks.appendChild(bm.render());
var panels = editor.Panels;
if(!panels.getPanel('views-container'))
panelC = panels.addPanel({id: 'views-container'});
else
panelC = panels.getPanel('views-container');
panelC.set('appendContent', this.blocks).trigger('change:appendContent');
const bm = editor.BlockManager;
const pn = editor.Panels;
if (!this.blocks) {
bm.render();
const id = 'views-container';
const blocks = document.createElement('div');
const panels = pn.getPanel(id) || pn.addPanel({id});
blocks.appendChild(bm.getContainer());
panels.set('appendContent', blocks).trigger('change:appendContent');
this.blocks = blocks;
}
this.blocks.style.display = 'block';
},
stop() {
if(this.blocks)
this.blocks.style.display = 'none';
const blocks = this.blocks;
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 = {

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

4
src/commands/view/OpenTraitManager.js

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

53
src/commands/view/SelectComponent.js

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

2
src/commands/view/SelectPosition.js

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

24
src/commands/view/ShowOffset.js

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

12
src/dom_components/view/ComponentTextView.js

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

17
src/dom_components/view/ComponentView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone');
var ComponentsView = require('./ComponentsView');
const ComponentsView = require('./ComponentsView');
const $ = Backbone.$;
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', this.handleChange);
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;
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)
this.importClasses();

63
src/domain_abstract/ui/Input.js

@ -1,4 +1,4 @@
var Backbone = require('backbone');
const $ = Backbone.$;
module.exports = Backbone.View.extend({
@ -6,24 +6,35 @@ module.exports = Backbone.View.extend({
'change': 'handleChange',
},
template: _.template(`<span class='<%= holderClass %>'></span>`),
template() {
const holderClass = this.holderClass;
return `<span class="${holderClass}"></span>`;
},
initialize(opts) {
var opt = opts || {};
var ppfx = opt.ppfx || '';
this.target = opt.target || {};
initialize(opts = {}) {
const ppfx = opts.ppfx || '';
this.target = opts.target || {};
this.inputClass = ppfx + 'field';
this.inputHolderClass = ppfx + 'input-holder';
this.holderClass = `${ppfx}input-holder`;
this.ppfx = ppfx;
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
*/
handleChange(e) {
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 {Object} opts
*/
setValue(value, opts) {
var opt = opts || {};
var model = this.model;
model.set({
value: value || model.get('defaults')
}, 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);
}
setValue(value, opts = {}) {
const model = this.model;
let val = value || model.get('defaults');
const input = this.getInputEl();
input && (input.value = val);
},
/**
* Updates the view when the model is changed
* */
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() {
if(!this.inputEl) {
this.inputEl = $('<input>', {
type: 'text',
class: this.inputCls,
placeholder: this.model.get('defaults')
});
const plh = this.model.get('defaults');
const cls = this.inputCls;
this.inputEl = $(`<input type="text" class="${cls}" placeholder="${plh}">`);
}
return this.inputEl.get(0);
},
render() {
var el = this.$el;
const el = this.$el;
const ppfx = this.ppfx;
const holderClass = this.holderClass;
el.addClass(this.inputClass);
el.html(this.template({
holderClass: this.inputHolderClass,
ppfx: this.ppfx
}));
el.find('.'+ this.inputHolderClass).html(this.getInputEl());
el.html(this.template());
el.find(`.${holderClass}`).append(this.getInputEl());
return this;
}

45
src/domain_abstract/ui/InputColor.js

@ -1,20 +1,25 @@
var Backbone = require('backbone');
var Input = require('./Input');
var Spectrum = require('spectrum-colorpicker');
const Input = require('./Input');
//require('spectrum-colorpicker');
require('utils/ColorPicker');
const $ = Backbone.$;
module.exports = Input.extend({
template: _.template(`
<div class='<%= ppfx %>input-holder'></div>
<div class="<%= ppfx %>field-colorp">
<div class="<%= ppfx %>field-colorp-c">
<div class="<%= ppfx %>checker-bg"></div>
</div>
</div>`),
template() {
const ppfx = this.ppfx;
return `
<div class="${ppfx}input-holder"></div>
<div class="${ppfx}field-colorp">
<div class="${ppfx}field-colorp-c">
<div class="${ppfx}checker-bg"></div>
</div>
</div>
`;
},
initialize(opts) {
Input.prototype.initialize.apply(this, arguments);
var ppfx = this.ppfx;
const ppfx = this.ppfx;
this.colorCls = `${ppfx}field-color-picker`;
this.inputClass = `${ppfx}field ${ppfx}field-color`;
this.colorHolderClass = `${ppfx}field-colorp-c`;
@ -55,14 +60,10 @@ module.exports = Input.extend({
if (!this.colorEl) {
const self = this;
var model = this.model;
var colorEl = $('<div>', {class: this.colorCls});
var colorEl = $(`<div class="${this.colorCls}"></div>`);
var cpStyle = colorEl.get(0).style;
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 => {
let cl = color.getAlpha() == 1 ? color.toHexString() : color.toRgbString();
return cl.replace(/ /g, '');
@ -70,6 +71,8 @@ module.exports = Input.extend({
let changed = 0;
let previousСolor;
this.$el.find(`.${this.colorHolderClass}`).append(colorEl);
colorEl.spectrum({
appendTo: elToAppend || 'body',
maxSelectionSize: 8,
@ -106,14 +109,16 @@ module.exports = Input.extend({
}
}
});
this.colorEl = colorEl;
}
return this.colorEl;
},
render(...args) {
Input.prototype.render.apply(this, args);
this.$el.find('.' + this.colorHolderClass).html(this.getColorEl());
render() {
Input.prototype.render.call(this);
// This will make the color input available on render
this.getColorEl();
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(`
<span class='<%= ppfx %>input-holder'></span>
@ -18,16 +19,16 @@ module.exports = Backbone.View.extend({
var ppfx = opt.ppfx || '';
var contClass = opt.contClass || (`${ppfx}field ${ppfx}field-integer`);
this.ppfx = ppfx;
this.docEl = $(document);
this.doc = document;
this.inputCls = ppfx + 'field-number';
this.unitCls = ppfx + 'input-unit';
this.contClass = contClass;
this.events['click .' + ppfx + 'field-arrow-u'] = 'upArrowClick';
this.events['click .' + ppfx + 'field-arrow-d'] = 'downArrowClick';
this.events['mousedown .' + ppfx + 'field-arrows'] = 'downIncrement';
this.events['change .' + this.inputCls] = 'handleChange';
this.events['change .' + this.unitCls] = 'handleUnitChange';
this.events = {};
this.events[`click .${ppfx}field-arrow-u`] = 'upArrowClick';
this.events[`click .${ppfx}field-arrow-d`] = 'downArrowClick';
this.events[`mousedown .${ppfx}field-arrows`] = 'downIncrement';
this.events[`change .${this.inputCls}`] = 'handleChange';
this.events[`change .${this.unitCls}`] = 'handleUnitChange';
this.listenTo(this.model, 'change:unit change:value', this.handleModelChange);
this.delegateEvents();
},
@ -100,12 +101,10 @@ module.exports = Backbone.View.extend({
* @return {HTMLElement}
*/
getInputEl() {
if(!this.inputEl) {
this.inputEl = $('<input>', {
type: 'text',
class: this.inputCls,
placeholder: this.model.get('defaults')
});
if (!this.inputEl) {
const cls = this.inputCls;
const plh = this.model.get('defaults');
this.inputEl = $(`<input type="text" class="${cls}" placeholder="${plh}">`);
}
return this.inputEl.get(0);
},
@ -125,10 +124,12 @@ module.exports = Backbone.View.extend({
unitStr += '<option ' + selected + ' >' + unit + '</option>';
});
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 step = model.get('step');
let value = model.get('value');
//value = isNaN(value) ? 1 * step : parseFloat(value);
value = this.normalizeValue(value + step);
var valid = this.validateInputValue(value);
model.set('value', valid.value);
@ -169,9 +169,9 @@ module.exports = Backbone.View.extend({
this.moved = 0;
var value = this.model.get('value');
value = this.normalizeValue(value);
var current = {y: e.pageY, val: value};
this.docEl.mouseup(current, this.upIncrement);
this.docEl.mousemove(current, this.moveIncrement);
this.current = {y: e.pageY, val: value};
on(this.doc, 'mousemove', this.moveIncrement);
on(this.doc, 'mouseup', this.upIncrement);
},
/** While the increment is clicked, moving the mouse will update input value
@ -183,7 +183,8 @@ module.exports = Backbone.View.extend({
this.moved = 1;
const model = this.model;
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;
model.set('value', this.prValue, {avoidStore: 1});
return false;
@ -191,15 +192,12 @@ module.exports = Backbone.View.extend({
/**
* Stop moveIncrement method
* @param Object
*
* @return void
* */
upIncrement(e) {
upIncrement() {
const model = this.model;
const step = model.get('step');
this.docEl.off('mouseup', this.upIncrement);
this.docEl.off('mousemove', this.moveIncrement);
off(this.doc, 'mouseup', this.upIncrement);
off(this.doc, 'mousemove', this.moveIncrement);
if(this.prValue && this.moved) {
var value = this.prValue - step;
@ -280,11 +278,13 @@ module.exports = Backbone.View.extend({
},
render() {
var ppfx = this.ppfx;
this.$el.html(this.template({ppfx}));
this.$el.find('.'+ ppfx +'input-holder').html(this.getInputEl());
this.$el.find('.' + ppfx + 'field-units').html(this.getUnitEl());
this.$el.addClass(this.contClass);
const ppfx = this.ppfx;
const el = this.$el;
el.html(this.template({ppfx}));
el.find(`.${ppfx}input-holder`).append(this.getInputEl());
const unit = this.getUnitEl();
unit && el.find(`.${ppfx}field-units`).get(0).appendChild(unit);
el.addClass(this.contClass);
return this;
}

5
src/editor/index.js

@ -38,6 +38,8 @@
* * `component:styleUpdate` - Triggered when the style of the component is updated
* * `component:styleUpdate:{propertyName}` - Listen for a specific style property change
* * `component:selected` - New component selected
* * `block:add` - New block added
* * `block:remove` - Block removed
* * `asset:add` - New asset added
* * `asset:remove` - Asset removed
* * `asset:upload:start` - Before the upload is started
@ -46,8 +48,11 @@
* * `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:{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: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
* * `canvasScroll` - Triggered when the canvas is scrolled
* * `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 = [
require('utils'),
require('storage_manager'),
require('device_manager'),
require('parser'),
require('selector_manager'),
require('modal_dialog'),
require('code_manager'),
require('panels'),
require('rich_text_editor'),
require('style_manager'),
require('asset_manager'),
require('css_composer'),
require('dom_components'),
require('canvas'),
require('commands'),
require('block_manager'),
require('trait_manager'),
import { isUndefined, defaults } from 'underscore';
const deps = [
require('utils'),
require('storage_manager'),
require('device_manager'),
require('parser'),
require('selector_manager'),
require('modal_dialog'),
require('code_manager'),
require('panels'),
require('rich_text_editor'),
require('style_manager'),
require('asset_manager'),
require('css_composer'),
require('dom_components'),
require('canvas'),
require('commands'),
require('block_manager'),
require('trait_manager'),
];
var Backbone = require('backbone');
var UndoManager = require('backbone-undo');
var key = require('keymaster');
var timedInterval;
const Backbone = require('backbone');
const UndoManager = require('backbone-undo');
const key = require('keymaster');
let timedInterval;
if (!Backbone.$) {
Backbone.$ = $;
}
require('utils/extender')({
Backbone: Backbone,
$: Backbone.$
});
const $ = Backbone.$;
module.exports = Backbone.Model.extend({
@ -607,4 +612,26 @@ module.exports = Backbone.Model.extend({
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({
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 = (() => {
const defaultConfig = require('./config/config');
@ -9,13 +10,15 @@ module.exports = (() => {
return {
// Will be replaced on build
version: '<# VERSION #>',
$,
editors,
plugins,
// Will be replaced on build
version: '<# VERSION #>',
/**
* Initializes an editor based on passed options
* @param {Object} config Configuration object
@ -37,11 +40,6 @@ module.exports = (() => {
init(config = {}) {
const els = config.container;
// Make a missing $ more verbose
if (isUndefined($)) {
throw 'jQuery not found';
}
if (!els) {
throw new Error("'container' is required");
}

15
src/modal_dialog/view/ModalView.js

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

2
src/panels/view/ButtonView.js

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

3
src/rich_text_editor/index.js

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

4
src/rich_text_editor/view/CommandButtonSelectView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone');
var CommandButtonView = require('./CommandButtonView');
const CommandButtonView = require('./CommandButtonView');
const $ = Backbone.$;
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 loader = $.Deferred(),
fReader = new FileReader();
@ -106,7 +109,7 @@ $.fn.wysiwyg = function (userOptions) {
input.data(options.selectionMarker, color);
},
bindToolbar = (toolbar, options) => {
toolbar.find(toolbarBtnSelector).unbind().click(function () {
toolbar.find(toolbarBtnSelector).off('click').on('click',function () {
restoreSelection();
//editor.focus(); // cause defocus on selects
var doc = editor.get(0).ownerDocument;
@ -121,7 +124,7 @@ $.fn.wysiwyg = function (userOptions) {
}
saveSelection();
});
toolbar.find('[data-toggle=dropdown]').click(restoreSelection);
toolbar.find('[data-toggle=dropdown]').on('click', restoreSelection);
var dName = '[data-' + options.commandRole + ']';
toolbar.find('select'+dName).on('webkitspeechchange change', function(){
var newValue = this.value;
@ -153,7 +156,7 @@ $.fn.wysiwyg = function (userOptions) {
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();
if (this.type === 'file' && this.files && this.files.length > 0) {
insertFiles(this.files);
@ -176,8 +179,8 @@ $.fn.wysiwyg = function (userOptions) {
/** Disable the editor
* @date 2015-03-19 */
if(typeof userOptions=='string' && userOptions=='destroy'){
editor.attr('contenteditable', false).unbind('mouseup keyup mouseout dragenter dragover');
$(window).unbind('touchend');
editor.attr('contenteditable', false).off('mouseup keyup mouseout dragenter dragover');
$(window).off('touchend');
return this;
}
options = $.extend({}, $.fn.wysiwyg.defaults, userOptions);
@ -192,7 +195,7 @@ $.fn.wysiwyg = function (userOptions) {
saveSelection();
updateToolbar();
});
$(window).bind('touchend', e => {
$(window).on('touchend', e => {
var isInside = (editor.is(e.target) || editor.has(e.target).length > 0),
currentRange = getCurrentRange(),
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 id="<%= pfx %>close">&Cross;</span>`),
events: {},
initialize(o) {
this.config = o.config || {};
this.coll = o.coll || null;
@ -22,6 +20,7 @@ module.exports = Backbone.View.extend({
this.closeId = this.pfx + 'close';
this.chkId = this.pfx + 'checkbox';
this.labelId = this.pfx + 'tag-label';
this.events = {};
this.events['click #' + this.closeId ] = 'removeTag';
this.events['click #' + this.chkId ] = 'changeStatus';
this.events['dblclick #' + this.labelId ] = 'startEditTag';
@ -77,17 +76,15 @@ module.exports = Backbone.View.extend({
* @private
*/
removeTag(e) {
var comp = this.target.get('selectedComponent');
if(comp)
comp.get('classes').remove(this.model);
if(this.coll){
this.coll.remove(this.model);
this.target.trigger('targetClassRemoved');
}
this.remove();
const em = this.target;
const model = this.model;
const coll = this.coll;
const el = this.el;
const sel = em && em.get('selectedComponent');
sel && sel.get & sel.get('classes').remove(model);
coll && coll.remove(model);
setTimeout(() => this.remove(), 0);
em && em.trigger('targetClassRemoved');
},
/**
@ -115,8 +112,11 @@ module.exports = Backbone.View.extend({
* @private
*/
updateInputLabel() {
if(!this.$labelInput)
if(!this.$labelInput) {
this.$labelInput = this.$el.find('input');
}
this.$labelInput.prop(this.inputProp, true);
var size = this.$labelInput.val().length - 1;
size = size < 1 ? 1 : size;
this.$labelInput.attr('size', size);

4
src/selector_manager/view/ClassTagsView.js

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

5
src/storage_manager/config/config.js

@ -32,9 +32,12 @@ module.exports = {
checkLocal: 1,
// 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: {},
// Custom headers for the remote storage request
headers: {},
// Endpoint where to save all stuff
urlStore: '',

3
src/storage_manager/index.js

@ -57,7 +57,8 @@ module.exports = () => {
*/
init(config) {
c = config || {};
for (var name in defaults){
for (var name in defaults) {
if (!(name in c))
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: {
urlStore: '',
@ -12,67 +15,121 @@ module.exports = Backbone.Model.extend({
},
/**
* Triggered before the request is started
* @private
*/
store(data, clb) {
var fd = {},
params = this.get('params');
for(var k in data)
fd[k] = data[k];
for(var key in params)
fd[key] = params[key];
let req = $.ajax({
url: this.get('urlStore'),
beforeSend: this.get('beforeSend'),
complete: this.get('onComplete'),
method: 'POST',
dataType: 'json',
contentType: this.get('contentTypeJson') ? 'application/json; charset=utf-8': 'x-www-form-urlencoded',
data: this.get('contentTypeJson') ? JSON.stringify(fd): fd,
});
// Assign always callback when possible
req && req.always && req.always(() => {
if (typeof clb == 'function') {
clb();
}
});
onStart() {
const em = this.get('em');
const before = this.get('beforeSend');
before && before();
em && em.trigger('storage:start');
},
/**
* Triggered on request error
* @param {Object} err Error
* @private
*/
onError(err) {
const em = this.get('em');
console.error(err);
em && em.trigger('storage:error', err);
this.onEnd(err);
},
/**
* Triggered after the request is ended
* @param {Object|string} res End result
* @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) {
var result = {},
fd = {},
params = this.get('params');
for(var key in params)
fd[key] = params[key];
fd.keys = keys;
let req = $.ajax({
url: this.get('urlLoad'),
beforeSend: this.get('beforeSend'),
complete: this.get('onComplete'),
data: fd,
async: false,
method: 'GET',
}).done(d => {
result = d;
});
// Assign always callback when possible
req && req.always && req.always((res) => {
if (typeof clb == 'function') {
clb(res);
this.request(this.get('urlLoad'), {body: {keys}}, clb);
},
/**
* Execute remote request
* @param {string} url Url
* @param {Object} [opts={}] Options
* @param {[type]} [clb=null] Callback
* @private
*/
request(url, opts = {}, clb = null) {
const typeJson = this.get('contentTypeJson');
const headers = this.get('headers') || {};
const params = this.get('params');
const reqHead = 'X-Requested-With';
const typeHead = 'Content-Type';
const bodyObj = opts.body || {};
let body;
for (let param in params) {
bodyObj[param] = params[param];
}
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({
defaults: {
index: '',
value: '',
values: {},
active: true,
active: false,
preview: false,
properties: [],
},
initialize() {
const Properties = require('./Properties');
const properties = this.get('properties');
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
// 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');
var Layer = require('./Layer');
const Layer = require('./Layer');
module.exports = Backbone.Collection.extend({
@ -18,6 +17,102 @@ module.exports = Backbone.Collection.extend({
onReset() {
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;
}
}
]
],
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 = '';
this.get('properties').each(prop => result += `${prop.getFullValue()} `);
return result.trim();
return this.get('properties').getFullValue();
},
});

12
src/style_manager/model/PropertyStack.js

@ -14,17 +14,13 @@ module.exports = Property.extend({
init() {
Property.prototype.init.apply(this, arguments);
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() {
if (this.get('detached')) {
return '';
}
const layers = this.get('layers');
let val = layers.length ? layers.pluck('value').join(', ') : '';
return val.trim();
return this.get('detached') ? '' : this.get('layers').getFullValue();
},
});

242
src/style_manager/view/LayerView.js

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

23
src/style_manager/view/LayersView.js

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

18
src/style_manager/view/PropertiesView.js

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

8
src/style_manager/view/PropertyColorView.js

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

5
src/style_manager/view/PropertyCompositeView.js

@ -1,4 +1,5 @@
const PropertyView = require('./PropertyView');
const $ = Backbone.$;
module.exports = PropertyView.extend({
@ -26,7 +27,7 @@ module.exports = PropertyView.extend({
if (props.length) {
if (!this.$input) {
this.$input = $('<input>', {value: 0, type: 'hidden' });
this.$input = $('<input type="hidden" value="0">');
this.input = this.$input.get(0);
}
@ -47,7 +48,7 @@ module.exports = PropertyView.extend({
var PropertiesView = require('./PropertiesView');
var propsView = new PropertiesView(this.getPropsConfig());
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');
var PropertyView = require('./PropertyView');
const PropertyView = require('./PropertyView');
const $ = Backbone.$;
module.exports = PropertyView.extend({
@ -26,9 +26,9 @@ module.exports = PropertyView.extend({
},
init() {
this.assets = this.target.get('assets');
this.modal = this.target.get('Modal');
this.am = this.target.get('AssetManager');
const em = this.em;
this.modal = em.get('Modal');
this.am = em.get('AssetManager');
this.events['click #'+this.pfx+'close'] = 'removeFile';
this.events['click #'+this.pfx+'images'] = 'openAssetManager';
this.delegateEvents();
@ -36,7 +36,8 @@ module.exports = PropertyView.extend({
onRender() {
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) {

4
src/style_manager/view/PropertyIntegerView.js

@ -1,4 +1,5 @@
const InputNumber = require('domain_abstract/ui/InputNumber');
const $ = Backbone.$;
module.exports = require('./PropertyView').extend({
@ -28,7 +29,8 @@ module.exports = require('./PropertyView').extend({
const fields = this.el.querySelector(`.${ppfx}fields`);
fields.appendChild(input.el);
this.$input = input.inputEl;
this.$unit = input.unitEl;
this.unit = input.unitEl;
this.$unit = $(this.unit);
this.input = this.$input.get(0);
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 options = model.get('list') || model.get('options') || [];
if (!this.$input) {
if (!this.input) {
if(options && options.length) {
let inputStr = '';
@ -31,31 +31,39 @@ module.exports = require('./PropertyView').extend({
<div class="${ppfx}radio-item">
<input type="radio" class="${pfx}radio" id="${id}" name="${prop}" value="${el.value}"/>
<label class="${cl || itemCls}" ${titleAttr} for="${id}">${cl ? '' : labelTxt}</label>
</div>`;
</div>
`;
});
this.$inputEl = $(inputStr);
this.input = this.$inputEl.get(0);
this.$el.find(`#${pfx}input-holder`).html(this.$inputEl);
this.$input = this.$inputEl.find(`input[name="${prop}"]`);
const inputHld = this.el.querySelector(`#${pfx}input-holder`);
inputHld.innerHTML = `<div>${inputStr}</div>`;
this.input = inputHld.firstChild;
}
}
},
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) {
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) {
v = value;
if (inputIn) {
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({
templateInput() {
@ -18,7 +20,7 @@ module.exports = require('./PropertyView').extend({
const model = this.model;
const options = model.get('list') || model.get('options') || [];
if (!this.$input) {
if (!this.input) {
let optionsStr = '';
options.forEach(option => {
@ -29,9 +31,9 @@ module.exports = require('./PropertyView').extend({
optionsStr += `<option value="${value}" ${styleAttr}>${name}</option>`;
});
this.$input = $(`<select>${optionsStr}</select>`);
this.input = this.$input.get(0);
this.$el.find(`#${pfx}input-holder`).html(this.$input);
const inputH = this.el.querySelector(`#${pfx}input-holder`);
inputH.innerHTML = `<select>${optionsStr}</select>`;
this.input = inputH.firstChild;
}
},

313
src/style_manager/view/PropertyStackView.js

@ -1,7 +1,5 @@
var Backbone = require('backbone');
var PropertyCompositeView = require('./PropertyCompositeView');
var Layers = require('./../model/Layers');
var LayersView = require('./LayersView');
const PropertyCompositeView = require('./PropertyCompositeView');
const LayersView = require('./LayersView');
module.exports = PropertyCompositeView.extend({
@ -10,8 +8,8 @@ module.exports = PropertyCompositeView.extend({
const ppfx = this.ppfx;
return `
<div class="${pfx}field ${pfx}stack">
<button type="button" id="${pfx}add">+</button>
<span id="${pfx}input-holder"></span>
<button type="button" id="${pfx}add" data-add-layer>+</button>
<div data-layers-wrapper></div>
</div>
`;
},
@ -20,7 +18,7 @@ module.exports = PropertyCompositeView.extend({
const model = this.model;
const pfx = this.pfx;
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, 'updateValue', this.inputValueChanged);
this.delegateEvents();
@ -29,7 +27,7 @@ module.exports = PropertyCompositeView.extend({
/**
* Fired when the target is updated.
* 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) {
if (!this.model.get('detached')) {
@ -58,259 +56,120 @@ module.exports = PropertyCompositeView.extend({
* @return {Object}
* */
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 propModel = propView && propView.model;
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;
this.getLayers().active(model.get('stackIndex'));
},
/**
* Build composite value
* @private
* */
build(...args) {
let value = '';
let values = {};
addLayer() {
const model = this.model;
const stackIndex = model.get('stackIndex');
const properties = model.get('properties');
if (stackIndex === null) {
return;
}
const layers = this.getLayers();
const properties = model.get('properties').deepClone();
properties.each(property => property.set('value', ''));
const layer = layers.add({properties});
// Store properties values inside layer, in this way it's more reliable
// to fetch them later
properties.each(prop => {
const propValue = prop.getFullValue();
values[prop.get('property')] = propValue;
value += `${propValue} `;
});
// In detached mode inputValueChanged will add new 'layer value'
// to all subprops
this.inputValueChanged();
const layerModel = this.getLayers().at(stackIndex);
layerModel && layerModel.set({values, value});
// This will set subprops with a new default values
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() {
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')) {
model.set('value', this.createValue());
model.set('value', this.getLayerValues());
} else {
model.get('properties').each(prop => {
prop.trigger('change:value');
});
model.get('properties').each(prop => prop.trigger('change:value'))
}
},
/**
* Create value by layers
* @return string
* */
createValue() {
return this.getStackValues().join(', ');
},
* There is no need to handle input update by the property itself,
* this will be done by layers
* @private
*/
setValue() {},
/**
* Render layers
* @return self
* Create value by layers
* @return string
* */
renderLayers() {
if (!this.fieldEl) {
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;
getLayerValues() {
return this.getLayers().getFullValue();
},
/**
* Refresh layers
* */
refreshLayers() {
var n = [];
var a = [];
var fieldName = 'value';
var detached = this.model.get('detached');
let layersObj = [];
const model = this.model;
const layers = this.getLayers();
const detached = model.get('detached');
// With detached layers values will be assigned to their properties
if (detached) {
fieldName = 'values';
a = this.getLayersFromTarget();
const target = this.getTarget();
const style = target ? target.getStyle() : {};
layersObj = layers.getLayersFromStyle(style);
} else {
var v = this.getTargetValue();
var vDef = this.model.getDefaultValue();
v = v == vDef ? '' : v;
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(', ');
}
let value = this.getTargetValue();
value = value == model.getDefaultValue() ? '' : value;
layersObj = layers.getLayersFromValue(value);
}
_.each(a, e => {
var o = {};
o[fieldName] = e;
n.push(o);
},this);
this.$props.detach();
var layers = this.getLayers();
layers.reset();
layers.add(n);
// Avoid updating with detached as it will cause issues on next change
if (!detached) {
this.inputValueChanged();
}
this.model.set({stackIndex: null}, {silent: true});
layers.add(layersObj);
model.set({stackIndex: null}, {silent: true});
},
onRender(...args) {
PropertyCompositeView.prototype.onRender.apply(this, args);
this.refreshLayers();
this.renderLayers();
onRender() {
const self = this;
const model = this.model;
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({
template(model) {
@ -50,7 +48,7 @@ module.exports = Backbone.View.extend({
this.customValue = o.customValue || {};
const model = this.model;
this.property = model.get('property');
this.input = this.$input = null;
this.input = null;
const pfx = this.pfx;
this.inputHolderId = '#' + pfx + 'input-holder';
this.sector = model.collection && model.collection.sector;
@ -84,7 +82,7 @@ module.exports = Backbone.View.extend({
const config = this.config;
const updatedCls = `${ppfx}color-hl`;
const computedCls = `${ppfx}color-warn`;
const labelEl = this.$el.find(`> .${pfx}label`);
const labelEl = this.$el.children(`.${pfx}label`);
const clearStyle = this.getClearEl().style;
labelEl.removeClass(`${updatedCls} ${computedCls}`);
clearStyle.display = 'none';
@ -444,6 +442,7 @@ module.exports = Backbone.View.extend({
const onRender = this.onRender && this.onRender.bind(this);
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({
template: _.template(`
<div class="<%= pfx %>title">
<div class="<%= pfx %>title" data-sector-title>
<i id="<%= pfx %>caret" class="fa"></i>
<%= label %>
</div>`),
events:{},
events:{
'click [data-sector-title]': 'toggle'
},
initialize(o) {
this.config = o.config || {};
this.pfx = this.config.stylePrefix || '';
this.target = o.target || {};
this.propTarget = o.propTarget || {};
this.open = this.model.get('open');
this.caretR = 'fa-caret-right';
this.caretD = 'fa-caret-down';
this.listenTo(this.model, 'change:open', this.updateOpen);
this.listenTo(this.model, 'updateVisibility', this.updateVisibility);
this.events['click .' + this.pfx + 'title'] = 'toggle';
this.delegateEvents();
const model = this.model;
this.listenTo(model, 'change:open', this.updateOpen);
this.listenTo(model, 'updateVisibility', this.updateVisibility);
},
/**
@ -53,7 +53,7 @@ module.exports = Backbone.View.extend({
* */
show() {
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);
},
@ -62,14 +62,18 @@ module.exports = Backbone.View.extend({
* */
hide() {
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);
},
getPropertiesEl() {
return this.$el.find(`.${this.pfx}properties`).get(0);
},
/**
* Toggle visibility
* */
toggle() {
toggle(e) {
var v = this.model.get('open') ? 0 : 1;
this.model.set('open', v);
},

4
src/style_manager/view/SectorsView.js

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

4
src/trait_manager/view/TraitSelectView.js

@ -1,5 +1,5 @@
var Backbone = require('backbone');
var TraitView = require('./TraitView');
const TraitView = require('./TraitView');
const $ = Backbone.$;
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({
@ -81,21 +81,28 @@ module.exports = Backbone.View.extend({
var md = this.model;
var trg = this.target;
var name = md.get('name');
var opts = {
placeholder: md.get('placeholder') || md.get('default'),
type: md.get('type') || 'text'
};
if(md.get('changeProp')){
opts.value = trg.get(name);
}else{
var attrs = trg.get('attributes');
opts.value = md.get('value') || attrs[name];
const plh = md.get('placeholder') || md.get('default') || '';
const type = md.get('type') || 'text';
const attrs = trg.get('attributes');
const min = md.get('min');
const max = md.get('max');
const value = md.get('changeProp') ?
trg.get(name) : md.get('value') || attrs[name];
const input = $(`<input type="${type}" placeholder="${plh}">`);
if (value) {
input.prop('value', value);
}
if (min) {
input.prop('min', min);
}
if(md.get('min'))
opts.min = md.get('min');
if(md.get('max'))
opts.max = md.get('max');
this.$input = $('<input>', opts);
if (max) {
input.prop('max', max);
}
this.$input = input;
}
return this.$input.get(0);
},
@ -123,8 +130,10 @@ module.exports = Backbone.View.extend({
renderField() {
if(!this.$input){
this.$el.append(this.tmpl);
var el = this.getInputEl();
this.$el.find('.' + this.inputhClass).prepend(el);
const el = this.getInputEl();
// 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 w = win || window;
var rect = el.getBoundingClientRect();

2
src/utils/Resizer.js

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

2
src/utils/Sorter.js

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

2
test/main.js

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

4
test/specs/asset_manager/index.js

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

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

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

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

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

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

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

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

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

3
test/specs/block_manager/index.js

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

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

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

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

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

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

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

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

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

11
test/specs/dom_components/index.js

@ -113,9 +113,12 @@ describe('DOM Components', () => {
});
ComponentModels.run();
ComponentView.run();
ComponentsView.run();
ComponentTextView.run();
ComponentImageView.run();
describe('Views', () => {
ComponentView.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 ComponentVideo = require('dom_components/model/ComponentVideo');
const Components = require('dom_components/model/Components');
const $ = Backbone.$;
module.exports = {
run() {

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

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

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

@ -6,35 +6,26 @@ module.exports = {
describe('ComponentTextView', () => {
var $fixtures;
var $fixture;
var fixtures;
var model;
var view;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(() => {
model = new Component();
view = new ComponentTextView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
document.body.innerHTML = '<div id="fixtures"></div>';
fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
});
afterEach(() => {
view.remove();
});
after(() => {
$fixture.remove();
});
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', () => {
@ -47,7 +38,8 @@ module.exports = {
it('Init with content', () => {
model = new Component({ content: 'test' });
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', () => {
var $fixtures;
var $fixture;
var fixtures;
var model;
var view;
var hClass = 'hc-state';
var dcomp;
var compOpts;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(() => {
dcomp = new DomComponents();
compOpts = {
@ -29,36 +23,33 @@ module.exports = {
view = new ComponentView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
document.body.innerHTML = '<div id="fixtures"></div>';
fixtures = document.body.querySelector('#fixtures');
fixtures.appendChild(view.render().el);
});
afterEach(() => {
view.remove();
});
after(() => {
$fixture.remove();
});
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', () => {
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', () => {
model.set('state', 'test');
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', () => {
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', () => {
@ -117,6 +108,8 @@ module.exports = {
it('Init with different tag', () => {
model = new Component({ tagName: 'span' });
view = new ComponentView({ model });
fixtures.innerHTML = '';
fixtures.appendChild(view.render().el);
expect(view.render().el.tagName).toEqual('SPAN');
});
@ -131,7 +124,9 @@ module.exports = {
model,
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 compOpts;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(() => {
dcomp = new DomComponents();
compOpts = {
@ -28,18 +23,14 @@ module.exports = {
collection: model,
componentTypes: dcomp.componentTypes,
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
document.body.innerHTML = '<div id="fixtures"></div>';
document.body.querySelector('#fixtures').appendChild(view.render().el);
});
afterEach(() => {
view.collection.reset();
});
after(() => {
$fixture.remove();
});
it("Collection is empty", () => {
expect(view.$el.html()).toNotExist();
});

13
test/specs/grapesjs/index.js

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

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

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

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

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

13
test/specs/panels/index.js

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

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

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

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

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

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

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

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

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

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

@ -5,28 +5,35 @@ module.exports = {
run() {
describe('E2E tests', () => {
var instClassTagViewer = ctx => {
var $clm;
var clm = ctx.gjs.editor.get('SelectorManager');
if(clm){
$clm = new ClassTagsView({
var fixtures;
var components;
var tagEl;
var gjs;
var instClassTagViewer = (gjs, fixtures) => {
var tagEl;
var clm = gjs.editor.get('SelectorManager');
if (clm) {
tagEl = new ClassTagsView({
collection: new Selectors([]),
config: {
em: ctx.gjs.editor
},
config: {em: gjs.editor}
}).render();
ctx.$fixture.append($clm.el);
fixtures.appendChild(tagEl.el);
}
return $clm;
};
return tagEl;
};
/*
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div id="SelectorManager-fixture"></div>');
});
*/
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: '',
storageManager: { autoload: 0, type:'none' },
assetManager: {
@ -34,82 +41,67 @@ module.exports = {
},
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', () => {
beforeEach(function () {
this.wrapper = this.gjs.editor.get('DomComponents').getWrapper().get('components');
this.$clm = instClassTagViewer(this);
});
afterEach(function () {
delete this.wrapper;
delete this.$clm;
components = gjs.editor.get('DomComponents').getWrapper().get('components');
tagEl = instClassTagViewer(gjs, fixtures);
});
it('Assign correctly new class to component', function() {
var model = this.wrapper.add({});
var model = components.add({});
expect(model.get('classes').length).toEqual(0);
this.gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test');
gjs.editor.set('selectedComponent', model);
tagEl.addNewTag('test');
expect(model.get('classes').length).toEqual(1);
expect(model.get('classes').at(0).get('name')).toEqual('test');
});
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', '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() {
var model = this.wrapper.add({ classes: ['test1'] });
var model = components.add({ classes: ['test1'] });
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);
});
it('Can assign only one time the same class on selected component and the class viewer', function() {
var model = this.wrapper.add({});
this.gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test');
this.$clm.addNewTag('test');
var model = components.add({});
gjs.editor.set('selectedComponent', model);
tagEl.addNewTag('test');
tagEl.addNewTag('test');
expect(model.get('classes').length).toEqual(1);
expect(model.get('classes').at(0).get('name')).toEqual('test');
expect(this.$clm.collection.length).toEqual(1);
expect(this.$clm.collection.at(0).get('name')).toEqual('test');
expect(tagEl.collection.length).toEqual(1);
expect(tagEl.collection.at(0).get('name')).toEqual('test');
});
it('Removing from container removes also from selected component', function() {
var model = this.wrapper.add({});
this.gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test');
this.$clm.getClasses().find('.tag #close').trigger('click')
var model = components.add({});
gjs.editor.set('selectedComponent', model);
tagEl.addNewTag('test');
tagEl.getClasses().find('.tag #close').trigger('click')
expect(model.get('classes').length).toEqual(0);
});
it("Trigger correctly event on target with new class add", function() {
var spy = sinon.spy();
var model = this.wrapper.add({});
this.gjs.editor.set('selectedComponent', model);
this.$clm.addNewTag('test');
this.gjs.editor.on("targetClassAdded", spy);
this.$clm.addNewTag('test');
var model = components.add({});
gjs.editor.set('selectedComponent', model);
tagEl.addNewTag('test');
gjs.editor.on("targetClassAdded", spy);
tagEl.addNewTag('test');
expect(spy.called).toEqual(false);
this.$clm.addNewTag('test2');
tagEl.addNewTag('test2');
expect(spy.called).toEqual(true);
});

9
test/specs/selector_manager/index.js

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

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

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

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

@ -13,10 +13,15 @@ module.exports = {
var target;
before(() => {
fixtures = $("#fixtures");
document.body.innerHTML = '<div id="fixtures"></div>';
fixtures = document.body.querySelector('#fixtures');
fixture = $('<div class="classtag-fixture"></div>');
});
after(() => {
fixture.remove();
});
beforeEach(function () {
target = { get() {} };
coll = new Selectors();
@ -35,9 +40,10 @@ module.exports = {
get() { return { add() {} };}
};
fixtures.innerHTML = '';
fixture.empty().appendTo(fixtures);
fixture.html(view.render().el);
this.btnAdd = view.$el.find('#' + view.addBtnId);
fixture.append(view.render().el);
this.btnAdd = view.$addBtn;
this.input = view.$el.find('input#' + view.newInputId);
this.$tags = fixture.find('#tags-c');
this.$states = fixture.find('#states');
@ -48,10 +54,6 @@ module.exports = {
delete view.collection;
});
after(() => {
fixture.remove();
});
it('Object exists', () => {
expect(ClassTagsView).toExist();
});
@ -67,15 +69,15 @@ module.exports = {
});
it('Start new tag creation', function() {
this.btnAdd.click();
this.btnAdd.trigger('click');
expect(this.btnAdd.css('display')).toEqual('none');
expect(this.input.css('display')).toNotEqual('none');
});
it.skip('Stop tag creation', function() {
this.btnAdd.click();
this.btnAdd.trigger('click');
this.input.val('test')
this.input.blur();
this.input.trigger('blur');
//(this.btnAdd.css('display') !== 'none').should.equal(true);
//(this.input.css('display') == 'none').should.equal(true);
//this.input.val().should.equal('');
@ -84,7 +86,7 @@ module.exports = {
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();
sinon.stub(view, "addNewTag");
this.input.trigger({
@ -94,7 +96,7 @@ module.exports = {
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();
sinon.stub(view, "endNewTag");
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 RemoteStorage = require('storage_manager/model/RemoteStorage');
@ -57,6 +59,12 @@ module.exports = {
var params = { test: 'testValue' };
var storageOptions;
var data;
var mockResponse = (body = {}) => {
return new window.Response(JSON.stringify(body), {
status: 200,
headers: { 'Content-type': 'application/json' }
});
}
beforeEach(() => {
data = {
@ -69,44 +77,28 @@ module.exports = {
params,
};
obj = new RemoteStorage(storageOptions);
sinon.stub(obj, 'fetch').returns(
Promise.resolve(mockResponse({data: 1}))
);
});
afterEach(() => {
$.ajax.restore();
obj.fetch.restore();
obj = null;
});
// Stubbing will not return the original object so
// .always will not work
it.skip('Store data', () => {
sinon.stub($, "ajax");
for(var k in params)
data[k] = params[k];
it('Store data', () => {
obj.store(data);
$.ajax.calledWithMatch({
url: endpointStore,
data,
}).should.equal(true);
const callResult = obj.fetch;
expect(callResult.called).toEqual(true);
expect(callResult.firstCall.args[0]).toEqual(endpointStore);
});
it('Load data', () => {
sinon.stub($, "ajax").returns({
done() {}
});
var dt = {};
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);
obj.load(['item1', 'item2']);
const callResult = obj.fetch;
expect(callResult.called).toEqual(true);
expect(callResult.firstCall.args[0]).toEqual(endpointLoad);
});
});

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

Loading…
Cancel
Save