Browse Source

Merge branch 'dev'

pull/311/head
Artur Arseniev 9 years ago
parent
commit
5a17145546
  1. 16
      .eslintrc
  2. 1
      .gitignore
  3. 2
      dist/css/grapes.min.css
  4. 6
      dist/grapes.min.js
  5. 109
      index.html
  6. 9
      package.json
  7. 8
      src/asset_manager/config/config.js
  8. 4
      src/asset_manager/index.js
  9. 6
      src/asset_manager/view/FileUploader.js
  10. 4
      src/block_manager/config/config.js
  11. 26
      src/block_manager/index.js
  12. 17
      src/block_manager/model/Block.js
  13. 5
      src/block_manager/model/Categories.js
  14. 12
      src/block_manager/model/Category.js
  15. 9
      src/block_manager/view/BlockView.js
  16. 82
      src/block_manager/view/BlocksView.js
  17. 82
      src/block_manager/view/CategoryView.js
  18. 19
      src/canvas/config/config.js
  19. 61
      src/canvas/index.js
  20. 79
      src/canvas/view/CanvasView.js
  21. 51
      src/commands/index.js
  22. 34
      src/commands/view/Drag.js
  23. 1
      src/commands/view/Preview.js
  24. 10
      src/commands/view/Resize.js
  25. 2
      src/commands/view/SelectComponent.js
  26. 3
      src/css_composer/index.js
  27. 12
      src/device_manager/model/Device.js
  28. 20
      src/dom_components/index.js
  29. 5
      src/dom_components/model/Component.js
  30. 18
      src/dom_components/model/ComponentSvg.js
  31. 9
      src/dom_components/view/ComponentSvgView.js
  32. 25
      src/dom_components/view/ComponentView.js
  33. 7
      src/dom_components/view/ToolbarButtonView.js
  34. 32
      src/editor/config/config.js
  35. 13
      src/editor/index.js
  36. 117
      src/editor/model/Editor.js
  37. 4
      src/editor/view/EditorView.js
  38. 2
      src/grapesjs/index.js
  39. 1
      src/panels/config/config.js
  40. 52
      src/panels/view/PanelView.js
  41. 25
      src/panels/view/PanelsView.js
  42. 2
      src/rich_text_editor/view/TextEditorView.js
  43. 5
      src/storage_manager/index.js
  44. 6
      src/storage_manager/model/LocalStorage.js
  45. 18
      src/storage_manager/model/RemoteStorage.js
  46. 9
      src/style_manager/model/PropertyFactory.js
  47. 6
      src/style_manager/view/PropertyCompositeView.js
  48. 17
      src/style_manager/view/SectorsView.js
  49. 74
      src/styles/scss/_gjs_blocks.scss
  50. 25
      src/styles/scss/_gjs_canvas.scss
  51. 98
      src/styles/scss/main.scss
  52. 323
      src/utils/Dragger.js
  53. 40
      src/utils/Resizer.js
  54. 52
      src/utils/Sorter.js
  55. 8
      src/utils/index.js
  56. 44
      test/helper.js
  57. 23
      test/main.js
  58. 38
      test/specs/asset_manager/index.js
  59. 12
      test/specs/asset_manager/model/Asset.js
  60. 8
      test/specs/asset_manager/model/AssetImage.js
  61. 20
      test/specs/asset_manager/model/Assets.js
  62. 10
      test/specs/asset_manager/view/AssetImageView.js
  63. 8
      test/specs/asset_manager/view/AssetView.js
  64. 14
      test/specs/asset_manager/view/AssetsView.js
  65. 14
      test/specs/asset_manager/view/FileUploader.js
  66. 75
      test/specs/block_manager/index.js
  67. 74
      test/specs/block_manager/main.js
  68. 153
      test/specs/block_manager/view/BlocksView.js
  69. 43
      test/specs/code_manager/index.js
  70. 47
      test/specs/code_manager/main.js
  71. 439
      test/specs/code_manager/model/CodeModels.js
  72. 41
      test/specs/commands/index.js
  73. 44
      test/specs/commands/main.js
  74. 63
      test/specs/commands/model/CommandModels.js
  75. 379
      test/specs/css_composer/e2e/CssComposer.js
  76. 167
      test/specs/css_composer/index.js
  77. 167
      test/specs/css_composer/main.js
  78. 141
      test/specs/css_composer/model/CssModels.js
  79. 210
      test/specs/css_composer/view/CssRuleView.js
  80. 108
      test/specs/css_composer/view/CssRulesView.js
  81. 67
      test/specs/device_manager/index.js
  82. 70
      test/specs/device_manager/main.js
  83. 136
      test/specs/device_manager/view/DevicesView.js
  84. 115
      test/specs/dom_components/index.js
  85. 125
      test/specs/dom_components/main.js
  86. 510
      test/specs/dom_components/model/Component.js
  87. 114
      test/specs/dom_components/view/ComponentImageView.js
  88. 108
      test/specs/dom_components/view/ComponentTextView.js
  89. 282
      test/specs/dom_components/view/ComponentV.js
  90. 108
      test/specs/dom_components/view/ComponentsView.js
  91. 221
      test/specs/grapesjs/index.js
  92. 217
      test/specs/grapesjs/main.js
  93. 65
      test/specs/modal/index.js
  94. 67
      test/specs/modal/main.js
  95. 116
      test/specs/modal/view/ModalView.js
  96. 121
      test/specs/panels/e2e/PanelsE2e.js
  97. 104
      test/specs/panels/index.js
  98. 102
      test/specs/panels/main.js
  99. 209
      test/specs/panels/model/PanelModels.js
  100. 120
      test/specs/panels/view/ButtonView.js

16
.eslintrc

@ -0,0 +1,16 @@
{
"env": {
"browser": true,
"node": true
},
"parserOptions": {
"sourceType": "module"
},
"rules": {
"strict": 0,
"quotes": [0, "single"],
"eol-last": [0],
"no-mixed-requires": [0],
"no-underscore-dangle": [0]
}
}

1
.gitignore

@ -2,7 +2,6 @@
.settings/
.sass-cache/
.project
.eslintrc
npm-debug.log
style/.sass-cache/

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

6
dist/grapes.min.js

File diff suppressed because one or more lines are too long

109
index.html

@ -12,8 +12,7 @@
body, html{ height: 100%; margin: 0;}
</style>
<body>
<div id="gjs" style="height:0px; overflow:hidden">
<div id="gjs" style="height:0px; overflow:hidden;">
<header class="header-banner">
<div class="container-width">
<div class="logo-container">
@ -807,7 +806,7 @@
clearOnRender: 0,
storageManager:{
autoload: 0,
autoload: 1,
storeComponents: 1,
storeStyles: 1,
},
@ -870,33 +869,33 @@
*/
commands: {
defaults : [{
id: 'open-github',
run: function(editor, sender){
sender.set('active',false);
window.open('https://github.com/artf/grapesjs','_blank');
}
},{
id: 'undo',
run: function(editor, sender){
sender.set('active',false);
editor.UndoManager.undo(true);
}
},{
id: 'redo',
run: function(editor, sender){
sender.set('active',false);
editor.UndoManager.redo(true);
}
},{
id: 'clean-all',
run: function(editor, sender){
sender.set('active',false);
if(confirm('Are you sure to clean the canvas?')){
var comps = editor.DomComponents.clear();
}
}
}],
defaults: [{
id: 'open-github',
run: function(editor, sender){
sender.set('active',false);
window.open('https://github.com/artf/grapesjs','_blank');
}
},{
id: 'undo',
run: function(editor, sender){
sender.set('active',false);
editor.UndoManager.undo(true);
}
},{
id: 'redo',
run: function(editor, sender){
sender.set('active',false);
editor.UndoManager.redo(true);
}
},{
id: 'clean-all',
run: function(editor, sender){
sender.set('active',false);
if(confirm('Are you sure to clean the canvas?')){
var comps = editor.DomComponents.clear();
}
}
}],
},
assetManager: {
@ -904,17 +903,17 @@
storeOnChange : true,
storeAfterUpload : true,
assets : [
{ type: 'image', src : 'http://placehold.it/350x250/78c5d6/fff/image1.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/459ba8/fff/image2.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/79c267/fff/image3.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/c5d647/fff/image4.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/f28c33/fff/image5.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/e868a2/fff/image6.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/cc4360/fff/image7.jpg', height:350, width:250},
{ type: 'image', src : './img/work-desk.jpg', date: '2015-02-01',height:1080, width:1728},
{ type: 'image', src : './img/phone-app.png', date: '2015-02-01',height:650, width:320},
{ type: 'image', src : './img/bg-gr-v.png', date: '2015-02-01',height:1, width:1728},
]
{ type: 'image', src : 'http://placehold.it/350x250/78c5d6/fff/image1.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/459ba8/fff/image2.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/79c267/fff/image3.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/c5d647/fff/image4.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/f28c33/fff/image5.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/e868a2/fff/image6.jpg', height:350, width:250},
{ type: 'image', src : 'http://placehold.it/350x250/cc4360/fff/image7.jpg', height:350, width:250},
{ type: 'image', src : './img/work-desk.jpg', date: '2015-02-01',height:1080, width:1728},
{ type: 'image', src : './img/phone-app.png', date: '2015-02-01',height:650, width:320},
{ type: 'image', src : './img/bg-gr-v.png', date: '2015-02-01',height:1, width:1728},
]
},
@ -1156,6 +1155,34 @@
attributes: { title: 'Empty canvas' }
}]);
var bm = editor.BlockManager;
bm.add('link-block', {
label: 'Link Block',
attributes: {class:'fa fa-link'},
category: 'Basic',
content: {
type:'link',
editable: false,
droppable: true,
style:{
display: 'inline-block',
padding: '5px',
'min-height': '50px',
'min-width': '50px'
}
},
});
/*
// Store and load events
editor.on('storage:load', function(e) {
console.log('LOAD ', e);
})
editor.on('storage:store', function(e) {
console.log('STORE ', e);
})
*/
editor.render();
</script>
</body>

9
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.7.6",
"version": "0.8.19",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",
@ -27,16 +27,13 @@
"babel-preset-es2015": "^6.24.1",
"chai": "^3.5.0",
"documentation": "^4.0.0-beta2",
"eslint": "^4.1.1",
"expect": "^1.20.2",
"istanbul": "^0.4.2",
"jsdom": "^11.0.0",
"mocha": "^3.1.2",
"node-sass": "^3.4.2",
"sinon": "^1.17.6",
"svg2ttf": "^4.0.1",
"ttf2eot": "^2.0.0",
"ttf2woff": "^2.0.1",
"ttf2woff2": "^2.0.3",
"webpack": "^2.6.1",
"webpack-dev-server": "^2.4.5"
},
@ -65,7 +62,7 @@
"build:css": "node-sass src/styles/scss/main.scss dist/css/grapes.min.css --output-style compressed",
"v:patch": "npm version --no-git-tag-version patch",
"start": "WEBPACK_ENV=dev webpack-dev-server --progress --colors & npm run build:css -- -w",
"test": "NODE_PATH=./src mocha --compilers js:babel-core/register --require test/helper.js --recursive test/main.js",
"test": "NODE_PATH=./src mocha --compilers js:babel-core/register --require test/helper.js --timeout 10000 --recursive test/main.js",
"test:dev": "npm test -- -R min -w"
}
}

8
src/asset_manager/config/config.js

@ -13,4 +13,12 @@ module.exports = {
// Label for the add button
addBtnText: 'Add image',
// Custom uploadFile function
// @example
// uploadFile: function(e) {
// var files = e.dataTransfer ? e.dataTransfer.files : e.target.files;
// // ...send somewhere
// }
uploadFile: '',
};

4
src/asset_manager/index.js

@ -180,10 +180,12 @@ module.exports = () => {
if(!d && c.stm)
d = c.stm.load(name);
var assets = [];
try{
assets = JSON.parse(d[name]);
}catch(err){}
this.getAll().add(assets);
this.getAll().reset(assets);
return assets;
},

6
src/asset_manager/view/FileUploader.js

@ -21,6 +21,12 @@ module.exports = Backbone.View.extend({
this.uploadId = this.pfx + 'uploadFile';
this.disabled = !this.config.upload;
this.events['change #' + this.uploadId] = 'uploadFile';
let uploadFile = this.config.uploadFile;
if (uploadFile) {
this.uploadFile = uploadFile.bind(this);
}
this.delegateEvents();
},

4
src/block_manager/config/config.js

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

26
src/block_manager/index.js

@ -2,6 +2,7 @@
* * [add](#add)
* * [get](#get)
* * [getAll](#getall)
* * [getCategories](#getcategories)
* * [render](#render)
*
* Block manager helps managing various, draggable, piece of contents that could be easily reused inside templates.
@ -29,8 +30,10 @@ module.exports = () => {
var c = {},
defaults = require('./config/config'),
Blocks = require('./model/Blocks'),
BlockCategories = require('./model/Categories'),
BlocksView = require('./view/BlocksView');
var blocks, view;
var categories = [];
return {
@ -54,7 +57,11 @@ module.exports = () => {
c[name] = defaults[name];
}
blocks = new Blocks(c.blocks);
view = new BlocksView({ collection: blocks }, c);
categories = new BlockCategories(),
view = new BlocksView({
collection: blocks,
categories,
}, c);
return this;
},
@ -64,12 +71,18 @@ module.exports = () => {
* @param {Object} opts Options
* @param {string} opts.label Name of the block
* @param {string} opts.content HTML content
* @param {string|Object} opts.category Group the block inside a catgegory.
* You should pass objects with id property, eg:
* {id: 'some-uid', label: 'My category'}
* The string will be converted in:
* 'someid' => {id: 'someid', label: 'someid'}
* @param {Object} [opts.attributes={}] Block attributes
* @return {Block} Added block
* @example
* blockManager.add('h1-block', {
* label: 'Heading',
* content: '<h1>Put your title here</h1>',
* category: 'Basic',
* attributes: {
* title: 'Insert h1 block'
* }
@ -82,7 +95,7 @@ module.exports = () => {
},
/**
* Return block by id
* Return the block by id
* @param {string} id Block id
* @example
* var block = blockManager.get('h1-block');
@ -105,6 +118,15 @@ module.exports = () => {
return blocks;
},
/**
* Get all available categories.
* Is possible to add categories only with blocks via 'add()' method
* @return {Array|Collection}
*/
getCategories() {
return categories;
},
/**
* Render blocks
* @return {HTMLElement}

17
src/block_manager/model/Block.js

@ -1,11 +1,26 @@
var Backbone = require('backbone');
var Category = require('./Category');
module.exports = Backbone.Model.extend({
defaults :{
defaults: {
label: '',
content: '',
category: '',
attributes: {},
},
initialize(opts = {}) {
let category = this.get('category');
if (category) {
if (typeof category == 'string') {
var catObj = new Category({
id: category,
label: category,
});
}
}
},
});

5
src/block_manager/model/Categories.js

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

12
src/block_manager/model/Category.js

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

9
src/block_manager/view/BlockView.js

@ -19,8 +19,15 @@ module.exports = Backbone.View.extend({
* @private
*/
onDrag(e) {
if(!this.config.getSorter)
//Right or middel click
if (e.button !== 0) {
return;
}
if(!this.config.getSorter) {
return;
}
this.config.em.refreshCanvas();
var sorter = this.config.getSorter();
sorter.setDragHelper(this.el, e);

82
src/block_manager/view/BlocksView.js

@ -1,12 +1,19 @@
var Backbone = require('backbone');
var BlockView = require('./BlockView');
var CategoryView = require('./CategoryView');
module.exports = Backbone.View.extend({
initialize(opts, config) {
_.bindAll(this, 'getSorter', 'onDrag', 'onDrop');
this.config = config || {};
this.ppfx = this.config.pStylePrefix || '';
this.categories = opts.categories || '';
this.renderedCategories = [];
var ppfx = this.config.pStylePrefix || '';
this.ppfx = ppfx;
this.noCatClass = `${ppfx}blocks-no-cat`;
this.blockContClass = `${ppfx}blocks-c`;
this.catsClass = `${ppfx}block-categories`;
this.listenTo(this.collection, 'add', this.addTo);
this.em = this.config.em;
this.tac = 'test-tac';
@ -36,6 +43,7 @@ module.exports = Backbone.View.extend({
pfx: this.ppfx,
onStart: this.onDrag,
onEndMove: this.onDrop,
onMove: this.onMove,
document: canvas.getFrameEl().contentDocument,
direction: 'a',
wmargin: 1,
@ -51,8 +59,13 @@ module.exports = Backbone.View.extend({
* Callback when block is on drag
* @private
*/
onDrag() {
onDrag(e) {
this.em.stopDefault();
this.em.trigger('block:drag:start', e);
},
onMove(e) {
this.em.trigger('block:drag:move', e);
},
/**
@ -71,6 +84,7 @@ module.exports = Backbone.View.extend({
// Register all its components (eg. for the Undo Manager)
this.em.initChildrenComp(model);
}
this.em.trigger('block:drag:stop', model);
},
/**
@ -95,25 +109,81 @@ module.exports = Backbone.View.extend({
attributes: model.get('attributes'),
}, this.config);
var rendered = view.render().el;
var category = model.get('category');
// Check for categories
if (category && this.categories) {
if (typeof category == 'string') {
category = {
id: category,
label: category
};
}
var catModel = this.categories.add(category);
var catId = catModel.get('id');
var catView = this.renderedCategories[catId];
var categories = this.getCategoriesEl();
model.set('category', catModel);
if (!catView && categories) {
catView = new CategoryView({
model: catModel
}, this.config).render();
this.renderedCategories[catId] = catView;
categories.appendChild(catView.el);
}
catView && catView.append(rendered);
return;
}
if(frag)
frag.appendChild(rendered);
else
this.$el.append(rendered);
this.append(rendered);
},
getCategoriesEl() {
if (!this.catsEl) {
this.catsEl = this.el.querySelector(`.${this.catsClass}`);
}
return this.catsEl;
},
getBlocksEl() {
if (!this.blocksEl) {
this.blocksEl = this.el.querySelector(`.${this.noCatClass} .${this.blockContClass}`);
}
return this.blocksEl;
},
append(el) {
let blocks = this.getBlocksEl();
blocks && blocks.appendChild(el);
},
render() {
var ppfx = this.ppfx;
var frag = document.createDocumentFragment();
this.$el.empty();
this.catsEl = null;
this.blocksEl = null;
this.renderedCategories = [];
this.el.innerHTML = `
<div class="${this.catsClass}"></div>
<div class="${this.noCatClass}">
<div class="${this.blockContClass}"></div>
</div>
`;
this.collection.each(function(model){
this.add(model, frag);
}, this);
this.$el.append(frag);
this.$el.addClass(this.ppfx + 'blocks-c');
this.append(frag);
this.$el.addClass(this.blockContClass + 's')
return this;
},

82
src/block_manager/view/CategoryView.js

@ -0,0 +1,82 @@
var Backbone = require('backbone');
module.exports = Backbone.View.extend({
template: _.template(`
<div class="<%= pfx %>title">
<i class="<%= pfx %>caret-icon"></i>
<%= label %>
</div>
<div class="<%= pfx %>blocks-c"></div>
`),
events: {},
initialize(o = {}, config = {}) {
this.config = config;
const pfx = this.config.pStylePrefix || '';
this.pfx = pfx;
this.caretR = 'fa fa-caret-right';
this.caretD = 'fa fa-caret-down';
this.iconClass = `${pfx}caret-icon`;
this.activeClass = `${pfx}open`;
this.className = `${pfx}block-category`;
this.events[`click .${pfx}title`] = 'toggle';
this.listenTo(this.model, 'change:open', this.updateVisibility);
this.delegateEvents();
},
updateVisibility() {
if(this.model.get('open'))
this.open();
else
this.close();
},
open() {
this.el.className = `${this.className} ${this.activeClass}`;
this.getIconEl().className = `${this.iconClass} ${this.caretD}`;
this.getBlocksEl().style.display = '';
},
close() {
this.el.className = this.className;
this.getIconEl().className = `${this.iconClass} ${this.caretR}`;
this.getBlocksEl().style.display = 'none';
},
toggle() {
var model = this.model;
model.set('open', !model.get('open'));
},
getIconEl() {
if (!this.iconEl) {
this.iconEl = this.el.querySelector('.' + this.iconClass);
}
return this.iconEl;
},
getBlocksEl() {
if (!this.blocksEl) {
this.blocksEl = this.el.querySelector('.' + this.pfx + 'blocks-c');
}
return this.blocksEl;
},
append(el) {
this.getBlocksEl().appendChild(el);
},
render() {
this.el.innerHTML = this.template({
pfx: this.pfx,
label: this.model.get('label'),
});
this.el.className = this.className;
this.updateVisibility();
return this;
},
});

19
src/canvas/config/config.js

@ -6,9 +6,22 @@ module.exports = {
rulers: false,
/*
* append scripts in head of iframe before renderBody content
* need to manually maintain the same scripts in cms's render template
* Append external scripts in head of the iframe before renderBody content
* In this case, you have to add them manually later in the final HTML page
* @example
* scripts: [
* 'https://...',
* ]
*/
scripts: []
scripts: [],
/*
* Append external styles. This styles won't be added to the final HTML/CSS
* @example
* styles: [
* 'https://...',
* ]
*/
styles: [],
};

61
src/canvas/index.js

@ -4,6 +4,7 @@ module.exports = () => {
Canvas = require('./model/Canvas'),
CanvasView = require('./view/CanvasView');
var canvas;
var frameRect;
return {
@ -47,6 +48,9 @@ module.exports = () => {
if(cm)
this.setWrapper(cm);
this.startAutoscroll = this.startAutoscroll.bind(this);
this.stopAutoscroll = this.stopAutoscroll.bind(this);
this.autoscroll = this.autoscroll.bind(this);
return this;
},
@ -204,8 +208,8 @@ module.exports = () => {
* @param {HTMLElement} el
* @return {Object}
*/
getElementPos(el) {
return CanvasView.getElementPos(el);
getElementPos(el, opts) {
return CanvasView.getElementPos(el, opts);
},
/**
@ -313,6 +317,59 @@ module.exports = () => {
};
},
/**
* Start autoscroll
*/
startAutoscroll() {
this.dragging = 1;
let toListen = this.getScrollListeners();
frameRect = CanvasView.getFrameOffset(1);
toListen.on('mousemove', this.autoscroll);
toListen.on('mouseup', this.stopAutoscroll);
},
autoscroll(e) {
e.preventDefault();
if (this.dragging) {
let frameWindow = this.getFrameEl().contentWindow;
let actualTop = frameWindow.document.body.scrollTop;
let nextTop = actualTop;
let clientY = e.clientY;
let limitTop = 50;
let limitBottom = frameRect.height - limitTop;
if (clientY < limitTop) {
nextTop -= (limitTop - clientY);
}
if (clientY > limitBottom) {
nextTop += (clientY - limitBottom);
}
//console.log(`actualTop: ${actualTop} clientY: ${clientY} nextTop: ${nextTop} frameHeigh: ${frameRect.height}`);
frameWindow.scrollTo(0, nextTop);
}
},
/**
* Stop autoscroll
*/
stopAutoscroll() {
this.dragging = 0;
let toListen = this.getScrollListeners();
toListen.off('mousemove', this.autoscroll);
toListen.off('mouseup', this.stopAutoscroll);
},
getScrollListeners() {
if (!this.scrollListeners) {
this.scrollListeners =
$(this.getFrameEl().contentWindow, this.getElement());
}
return this.scrollListeners;
},
/**
* Returns wrapper element
* @return {HTMLElement}

79
src/canvas/view/CanvasView.js

@ -67,13 +67,50 @@ module.exports = Backbone.View.extend({
var body = this.frame.$el.contents().find('body');
var cssc = em.get('CssComposer');
var conf = em.get('Config');
body.append(wrap.render()).append(cssc.render());
var confCanvas = this.config;
var protCss = conf.protectedCss;
var externalStyles = '';
confCanvas.styles.forEach((style) => {
externalStyles += `<link rel="stylesheet" href="${style}"/>`;
});
// rgb(255, 202, 111)
const colorWarn = '#ffca6f';
let baseCss = `
* {
box-sizing: border-box;
}
html, body, #wrapper {
min-height: 100%;
}
html {
height: 100%;
}
body {
margin: 0;
height: auto;
background-color: #fff
}
#wrapper {
overflow: auto
}
`;
let layoutCss = `
.${ppfx}comp-selected{
outline: 3px solid #3b97e3 !important
}
.${ppfx}comp-selected-parent{
outline: 2px solid ${colorWarn} !important
}
`;
// I need all this styles to make the editor work properly
var frameCss = '* {box-sizing: border-box;} body{margin:0;height:auto;background-color:#fff} #wrapper{min-height:100%; overflow:auto}' +
var frameCss = baseCss +
'.' + ppfx + 'dashed :not([contenteditable]) > *[data-highlightable]{outline: 1px dashed rgba(170,170,170,0.7); outline-offset: -2px}' +
'.' + ppfx + 'comp-selected{outline: 3px solid #3b97e3 !important}' +
layoutCss +
'.' + ppfx + 'no-select{user-select: none; -webkit-user-select:none; -moz-user-select: none}'+
'.' + ppfx + 'freezed{opacity: 0.5; pointer-events: none}' +
'.' + ppfx + 'no-pointer{pointer-events: none}' +
@ -84,7 +121,13 @@ module.exports = Backbone.View.extend({
'* ::-webkit-scrollbar {width: 10px}' +
(conf.canvasCss || '');
frameCss += protCss || '';
if (externalStyles) {
body.append(externalStyles);
}
body.append('<style>' + frameCss + '</style>');
body.append(wrap.render()).append(cssc.render());
body.append(this.getJsContainer());
em.trigger('loaded');
this.frame.el.contentWindow.onscroll = this.onFrameScroll;
@ -113,7 +156,9 @@ module.exports = Backbone.View.extend({
var docBody = el.ownerDocument.body;
return {
top: rect.top + docBody.scrollTop,
left: rect.left + docBody.scrollLeft
left: rect.left + docBody.scrollLeft,
width: rect.width,
height: rect.height,
};
},
@ -131,8 +176,8 @@ module.exports = Backbone.View.extend({
* @return {Object}
* @private
*/
getFrameOffset() {
if(!this.frmOff)
getFrameOffset(force = 0) {
if(!this.frmOff || force)
this.frmOff = this.offset(this.frame.el);
return this.frmOff;
},
@ -154,12 +199,17 @@ module.exports = Backbone.View.extend({
* @return {Object}
* @private
*/
getElementPos(el) {
getElementPos(el, opts) {
var opt = opts || {};
var frmOff = this.getFrameOffset();
var cvsOff = this.getCanvasOffset();
var eo = this.offset(el);
var top = eo.top + frmOff.top - cvsOff.top;
var left = eo.left + frmOff.left - cvsOff.left;
var frmTop = opt.avoidFrameOffset ? 0 : frmOff.top;
var frmLeft = opt.avoidFrameOffset ? 0 : frmOff.left;
var top = eo.top + frmTop - cvsOff.top;
var left = eo.left + frmLeft - cvsOff.left;
return {
top,
left,
@ -202,9 +252,14 @@ module.exports = Backbone.View.extend({
view.el.id = id;
view.scriptContainer.html('');
view.scriptContainer.append('<script>' +
'var item = document.getElementById("'+id+'");' +
'(' + scrStr + '.bind(item))()</script>');
// 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>
setTimeout(function() {
var item = document.getElementById('${id}');
(${scrStr}.bind(item))()
}, 1);
</script>`);
},
/**

51
src/commands/index.js

@ -103,6 +103,7 @@ module.exports = () => {
defaultCommands.fullscreen = require('./view/Fullscreen');
defaultCommands.preview = require('./view/Preview');
defaultCommands.resize = require('./view/Resize');
defaultCommands.drag = require('./view/Drag');
defaultCommands['tlb-delete'] = {
run(ed) {
@ -137,27 +138,59 @@ module.exports = () => {
};
defaultCommands['tlb-move'] = {
run(ed) {
run(ed, sender, opts) {
var sel = ed.getSelected();
var dragger;
if(!sel || !sel.get('draggable')) {
console.warn('The element is not draggable');
return;
}
var toolbarEl = ed.Canvas.getToolbarEl();
var cmdMove = ed.Commands.get('move-comp');
const onStart = (e, opts) => {
console.log('start mouse pos ', opts.start);
console.log('el rect ', opts.elRect);
var el = opts.el;
el.style.position = 'absolute';
el.style.margin = 0;
};
cmdMove.onEndMoveFromModel = () => {
ed.editor.runDefault();
ed.editor.set('selectedComponent', sel);
const onEnd = (e, opts) => {
em.runDefault();
em.set('selectedComponent', sel);
ed.trigger('component:update', sel);
dragger && dragger.blur();
};
ed.editor.stopDefault();
cmdMove.initSorterFromModel(sel);
sel.set('status', 'selected');
const onDrag = (e, opts) => {
console.log('Delta ', opts.delta);
console.log('Current ', opts.current);
};
var toolbarEl = ed.Canvas.getToolbarEl();
toolbarEl.style.display = 'none';
var em = ed.getModel();
em.stopDefault();
if (em.get('designerMode')) {
// TODO move grabbing func in editor/canvas from the Sorter
dragger = editor.runCommand('drag', {
el: sel.view.el,
options: {
event: opts && opts.event,
onStart,
onDrag,
onEnd
}
});
} else {
var cmdMove = ed.Commands.get('move-comp');
cmdMove.onEndMoveFromModel = onEnd;
cmdMove.initSorterFromModel(sel);
}
sel.set('status', 'selected');
},
};

34
src/commands/view/Drag.js

@ -0,0 +1,34 @@
module.exports = {
run(editor, sender, opts) {
var el = (opts && opts.el) || '';
var canvas = editor.Canvas;
var dragger = this.dragger;
var options = opts.options || {};
var canvasView = canvas.getCanvasView();
options.prefix = editor.getConfig().stylePrefix;
options.mousePosFetcher = canvas.getMouseRelativePos;
options.posFetcher = canvasView.getElementPos.bind(canvasView);
// Create the resizer for the canvas if not yet created
if(!dragger) {
dragger = editor.Utils.Dragger.init(options);
this.dragger = dragger;
}
dragger.setOptions(options);
dragger.focus(el);
if (options.event) {
dragger.start(options.event);
}
return dragger;
},
stop() {
if(this.canvasResizer)
this.canvasResizer.blur();
},
};

1
src/commands/view/Preview.js

@ -17,6 +17,7 @@ module.exports = {
if(sender && sender.set)
sender.set('active', false);
editor.stopCommand('sw-visibility');
editor.getModel().stopDefault();
var that = this;
var panels = this.getPanels(editor);
var canvas = editor.Canvas.getElement();

10
src/commands/view/Resize.js

@ -1,14 +1,15 @@
module.exports = {
run(editor, sender, opts) {
var el = (opts && opts.el) || '';
var opt = opts || {};
var el = opt.el || '';
var canvas = editor.Canvas;
var canvasResizer = this.canvasResizer;
var options = opts.options || {};
var options = opt.options || {};
var canvasView = canvas.getCanvasView();
// Create the resizer for the canvas if not yet created
if(!canvasResizer) {
var canvasView = canvas.getCanvasView();
if(!canvasResizer || opt.forceNew) {
options.ratioDefault = 1;
options.appendTo = canvas.getResizerEl();
options.prefix = editor.getConfig().stylePrefix;
@ -20,6 +21,7 @@ module.exports = {
canvasResizer.setOptions(options);
canvasResizer.focus(el);
return canvasResizer;
},
stop() {

2
src/commands/view/SelectComponent.js

@ -250,7 +250,7 @@ module.exports = {
if(!model || !model.get('badgable'))
return;
var badge = this.getBadge();
badge.innerHTML = model.getName();
badge.innerHTML = model.getCurrentName();
var bStyle = badge.style;
var u = 'px';
bStyle.display = 'block';

3
src/css_composer/index.js

@ -93,9 +93,6 @@ module.exports = () => {
* @private
*/
onLoad() {
if(c.stm && c.stm.getConfig().autoload)
this.load();
if(c.stm && c.stm.isAutosave())
c.em.listenRules(this.getAll());
},

12
src/device_manager/model/Device.js

@ -6,7 +6,19 @@ module.exports = Backbone.Model.extend({
defaults :{
name: '',
// Width to set for the editor iframe
width: '',
// The width which will be used in media queries,
// If empty the width will be used
widthMedia: null,
},
initialize() {
if (this.get('widthMedia') == null) {
this.set('widthMedia', this.get('width'));
}
}
});

20
src/dom_components/index.js

@ -81,6 +81,11 @@ module.exports = () => {
model: require('./model/ComponentScript'),
view: require('./view/ComponentScriptView'),
},
{
id: 'svg',
model: require('./model/ComponentSvg'),
view: require('./view/ComponentSvgView'),
},
{
id: 'textnode',
model: require('./model/ComponentTextNode'),
@ -187,9 +192,6 @@ module.exports = () => {
* @private
*/
onLoad() {
if(c.stm && c.stm.getConfig().autoload)
this.load();
if(c.stm && c.stm.isAutosave()){
c.em.initUndoManager();
c.em.initChildrenComp(this.getWrapper());
@ -214,9 +216,12 @@ module.exports = () => {
}catch(err){}
}else if(d.html)
obj = d.html;
if (obj) {
this.clear();
this.getComponents().reset();
this.getComponents().add(obj);
}
if(obj)
this.getComponents().reset(obj);
return obj;
},
@ -234,8 +239,11 @@ module.exports = () => {
obj.html = c.em.getHtml();
if(keys.indexOf('components') >= 0)
obj.components = JSON.stringify(c.em.getComponents());
if(!noStore)
if (!noStore) {
c.stm.store(obj);
}
return obj;
},

5
src/dom_components/model/Component.js

@ -124,6 +124,7 @@ module.exports = Backbone.Model.extend({
}
}, this);
this.set('status', '');
this.init();
},
@ -260,6 +261,10 @@ module.exports = Backbone.Model.extend({
return this.name;
},
getCurrentName() {
return this.get('custom-name') || this.getName();
},
/**
* Return HTML string of the component
* @param {Object} opts Options

18
src/dom_components/model/ComponentSvg.js

@ -0,0 +1,18 @@
var Component = require('./Component');
module.exports = Component.extend({
getName() {
let name = this.get('tagName');
return name.charAt(0).toUpperCase() + name.slice(1);
},
}, {
isComponent(el) {
if (SVGElement && el instanceof SVGElement) {
return {type: 'svg'};
}
},
});

9
src/dom_components/view/ComponentSvgView.js

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

25
src/dom_components/view/ComponentView.js

@ -100,16 +100,22 @@ module.exports = Backbone.View.extend({
* @private
* */
updateStatus(e) {
var s = this.model.get('status'),
pfx = this.pfx;
var s = this.model.get('status');
var pfx = this.pfx;
var selectedClass = pfx + 'selected';
var selectedParentClass = selectedClass + '-parent';
switch(s) {
case 'selected':
this.$el.addClass(pfx + 'selected');
this.$el.addClass(selectedClass);
break;
case 'selected-parent':
this.$el.addClass(selectedParentClass);
break;
case 'moving':
break;
default:
this.$el.removeClass(pfx + 'selected');
this.$el.removeClass(`${selectedClass} ${selectedParentClass}`);
}
},
@ -290,6 +296,10 @@ module.exports = Backbone.View.extend({
* @private
*/
updateScript() {
if (!this.model.get('script')) {
return;
}
var em = this.em;
if(em) {
var canvas = em.get('Canvas');
@ -382,12 +392,7 @@ module.exports = Backbone.View.extend({
var container = this.getChildrenContainer();
container.innerHTML = model.get('content');
this.renderChildren();
// Render script
if(model.get('script')) {
this.updateScript();
}
this.updateScript();
return this;
},

7
src/dom_components/view/ToolbarButtonView.js

@ -13,15 +13,16 @@ module.exports = Backbone.View.extend({
this.editor = opts.config.editor;
},
handleClick() {
handleClick(event) {
var opts = {event};
var command = this.model.get('command');
if (typeof command === 'function') {
command(this.editor);
command(this.editor, null, opts);
}
if (typeof command === 'string') {
this.editor.runCommand(command);
this.editor.runCommand(command, opts);
}
},

32
src/editor/config/config.js

@ -38,7 +38,7 @@ module.exports = {
width: '100%',
// CSS that could only be seen (for instance, inside the code viewer)
protectedCss: '',
protectedCss: '*{box-sizing: border-box;} body{margin: 0;}',
// CSS for the iframe which containing the canvas, useful if you need to custom something inside
// (eg. the style of the selected component)
@ -59,6 +59,10 @@ module.exports = {
// When enabled, on device change media rules won't be created
devicePreviewMode: 0,
// THe condition to use for media queries, eg. 'max-width'
// Comes handy for mobile-first cases
mediaCondition: 'max-width',
// This option makes available custom component types also for loaded
// elements inside canvas
loadCompsOnRender: 1,
@ -104,18 +108,21 @@ module.exports = {
//Configurations for Device Manager
deviceManager: {
'devices': [{
devices: [{
name: 'Desktop',
width: '',
},{
name: 'Tablet',
width: '992px',
width: '768px',
widthMedia: '992px',
},{
name: 'Mobile landscape',
width: '768px',
width: '568px',
widthMedia: '768px',
},{
name: 'Mobile portrait',
width: '480px',
width: '320px',
widthMedia: '480px',
}],
},
@ -157,29 +164,34 @@ module.exports = {
//Configurations for Block Manager
blockManager: {
'blocks': [{
blocks: [{
id: 'b1',
label: '1 Block',
category: 'Basic',
content: '<div class="blk-row"><div class="blk1"></div></div><style>'+ blkStyle +'.blk1{width: 100%;padding: 10px;min-height: 75px;}</style>',
attributes: {class:'gjs-fonts gjs-f-b1'}
},{
id: 'b2',
label: '2 Blocks',
category: 'Basic',
content: '<div class="blk-row"><div class="blk2"></div><div class="blk2"></div></div><style>'+ blkStyle +'.blk2{float: left;width: 50%;padding: 10px;min-height: 75px;}</style>',
attributes: {class:'gjs-fonts gjs-f-b2'}
},{
id: 'b3',
label: '3 Blocks',
category: 'Basic',
content: '<div class="blk-row"><div class="blk3"></div><div class="blk3"></div><div class="blk3"></div></div><style>'+ blkStyle +'.blk3{float: left;width: 33.3333%;padding: 10px;min-height: 75px;}</style>',
attributes: {class:'gjs-fonts gjs-f-b3'}
},{
id: 'b4',
label: '3/7 Block',
category: 'Basic',
content: '<div class="blk-row"><div class="blk37l"></div><div class="blk37r"></div></div></div><style>'+ blkStyle +'.blk37l{float: left;width: 30%;padding: 10px;min-height: 75px;}.blk37r{float: left;width: 70%;padding: 10px;min-height: 75px;}</style>',
attributes: {class:'gjs-fonts gjs-f-b37'}
},{
id: 'hero',
label: 'Hero section',
category: 'Section',
content: '<header class="header-banner"> <div class="container-width">'+
'<div class="logo-container"><div class="logo">GrapesJS</div></div>'+
'<nav class="navbar">'+
@ -191,11 +203,13 @@ module.exports = {
},{
id: 'h1p',
label: 'Text section',
category: 'Typography',
content: '<h1 class="heading">Insert title here</h1><p class="paragraph">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua</p>',
attributes: {class:'gjs-fonts gjs-f-h1p'}
},{
id: '3ba',
label: 'Badges',
category: 'Section',
content: '<div class="badges">'+
'<div class="badge">'+
'<div class="badge-header"></div>'+
@ -227,6 +241,7 @@ module.exports = {
id: 'text',
label: 'Text',
attributes: {class:'gjs-fonts gjs-f-text'},
category: 'Basic',
content: {
type:'text',
content:'Insert your text here',
@ -236,6 +251,7 @@ module.exports = {
},{
id: 'image',
label: 'Image',
category: 'Basic',
attributes: {class:'gjs-fonts gjs-f-image'},
content: {
style: {color: 'black'},
@ -245,11 +261,13 @@ module.exports = {
},{
id: 'quo',
label: 'Quote',
category: 'Typography',
content: '<blockquote class="quote">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</blockquote>',
attributes: {class:'fa fa-quote-right'}
},{
id: 'link',
label: 'Link',
category: 'Basic',
attributes: {class:'fa fa-link'},
content: {
type:'link',
@ -259,6 +277,7 @@ module.exports = {
},{
id: 'map',
label: 'Map',
category: 'Extra',
attributes: {class:'fa fa-map-o'},
content: {
type: 'map',
@ -267,6 +286,7 @@ module.exports = {
},{
id: 'video',
label: 'Video',
category: 'Basic',
attributes: {class:'fa fa-youtube-play'},
content: {
type: 'video',

13
src/editor/index.js

@ -19,6 +19,7 @@
* * [getContainer](#getcontainer)
* * [refresh](#refresh)
* * [on](#on)
* * [off](#off)
* * [trigger](#trigger)
* * [render](#render)
*
@ -35,6 +36,8 @@
* component:update:{propertyName} - Listen any property change
* component:styleUpdate - Triggered when the style of the component is updated
* component:styleUpdate:{propertyName} - Listen for a specific style property change
* 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
* canvasScroll - Triggered when the canvas is scrolled
* run:{commandName} - Triggered when some command is called to run (eg. editor.runCommand('preview'))
* stop:{commandName} - Triggered when some command is called to stop (eg. editor.stopCommand('preview'))
@ -448,6 +451,16 @@ module.exports = config => {
return em.on(event, callback);
},
/**
* Detach event
* @param {string} event Event name
* @param {Function} callback Callback function
* @return {this}
*/
off(event, callback) {
return em.off(event, callback);
},
/**
* Trigger event
* @param {string} event Event to trigger

117
src/editor/model/Editor.js

@ -1,5 +1,5 @@
var deps = [
require('Utils'),
require('utils'),
require('storage_manager'),
require('device_manager'),
require('parser'),
@ -18,28 +18,11 @@ require('block_manager'),
require('trait_manager'),
];
require('backbone');
require('backbone-undo');
var Backbone = require('backbone');
var UndoManager = require('backbone-undo');
var key = require('keymaster');
/*
require('Utils');
require('StorageManager');
require('DeviceManager');
require('Parser');
require('SelectorManager');
require('ModalDialog');
require('CodeManager');
require('Panels');
require('RichTextEditor');
require('StyleManager');
require('AssetManager');
require('CssComposer');
require('DomComponents');
require('Canvas');
require('Commands');
require('BlockManager');
require('TraitManager');
*/
var timedInterval;
module.exports = Backbone.Model.extend({
defaults: {
@ -71,12 +54,25 @@ module.exports = Backbone.Model.extend({
M.onLoad();
});
this.loadOnStart();
this.initUndoManager();
this.on('change:selectedComponent', this.componentSelected, this);
this.on('change:changesCount', this.updateBeforeUnload, this);
},
/**
* Load on start if it was requested
* @private
*/
loadOnStart() {
const sm = this.get('StorageManager');
if (sm && sm.getConfig().autoload) {
this.load();
}
},
/**
* Set the alert before unload in case it's requested
* and there are unsaved changes
@ -153,28 +149,33 @@ module.exports = Backbone.Model.extend({
* @private
*/
listenRule(model) {
this.stopListening(model, 'change:style', this.ruleUpdated);
this.listenTo(model, 'change:style', this.ruleUpdated);
this.stopListening(model, 'change:style', this.componentsUpdated);
this.listenTo(model, 'change:style', this.componentsUpdated);
},
/**
* Triggered when rule is updated
* Triggered when something in components is changed
* @param {Object} model
* @param {Mixed} val Value
* @param {Object} opt Options
* @private
* */
ruleUpdated(model, val, opt) {
var count = this.get('changesCount') + 1,
avSt = opt ? opt.avoidStore : 0;
this.set('changesCount', count);
var stm = this.get('StorageManager');
if(stm.isAutosave() && count < stm.getStepsBeforeSave())
return;
if(!avSt){
this.store();
}
componentsUpdated(model, val, opt) {
timedInterval && clearInterval(timedInterval);
timedInterval = setTimeout(() => {
var count = this.get('changesCount') + 1;
var avoidStore = opt ? opt.avoidStore : 0;
var stm = this.get('StorageManager');
this.set('changesCount', count);
if (!stm.isAutosave() || count < stm.getStepsBeforeSave()) {
return;
}
if (!avoidStore) {
this.store();
}
}, 0);
},
/**
@ -187,7 +188,7 @@ module.exports = Backbone.Model.extend({
var cmp = this.get('DomComponents');
if(cmp && this.config.undoManager){
var that = this;
this.um = new Backbone.UndoManager({
this.um = new UndoManager({
register: [cmp.getComponents(), this.get('CssComposer').getAll()],
track: true
});
@ -202,9 +203,9 @@ module.exports = Backbone.Model.extend({
that.trigger('component:update');
});
Backbone.UndoManager.removeUndoType("change");
UndoManager.removeUndoType("change");
var beforeCache;
Backbone.UndoManager.addUndoType("change:style", {
UndoManager.addUndoType("change:style", {
"on": function (model, value, opts) {
var opt = opts || {};
if(!beforeCache){
@ -236,27 +237,6 @@ module.exports = Backbone.Model.extend({
}
},
/**
* Triggered when components are updated
* @param {Object} model
* @param {Mixed} val Value
* @param {Object} opt Options
* @private
* */
componentsUpdated(model, val, opt) {
var updatedCount = this.get('changesCount') + 1,
avSt = opt ? opt.avoidStore : 0;
this.set('changesCount', updatedCount);
var stm = this.get('StorageManager');
if(stm.isAutosave() && updatedCount < stm.getStepsBeforeSave()){
return;
}
if(!avSt){
this.store();
}
},
/**
* Callback on component selection
* @param {Object} Model
@ -446,9 +426,11 @@ module.exports = Backbone.Model.extend({
store[el] = obj[el];
});
sm.store(store, clb);
sm.store(store, () => {
clb && clb();
this.trigger('storage:store', store);
});
this.set('changesCount', 0);
this.trigger('storage:store', store);
return store;
},
@ -460,7 +442,7 @@ module.exports = Backbone.Model.extend({
* @private
*/
load(clb) {
var result = this.getCacheLoad(1);
var result = this.getCacheLoad(1, clb);
this.get('storables').forEach(m => {
m.load(result);
});
@ -470,10 +452,11 @@ module.exports = Backbone.Model.extend({
/**
* Returns cached load
* @param {Boolean} force Force to reload
* @param {Function} clb Callback function
* @return {Object}
* @private
*/
getCacheLoad(force) {
getCacheLoad(force, clb) {
var f = force ? 1 : 0;
if(this.cacheLoad && !f)
return this.cacheLoad;
@ -492,8 +475,10 @@ module.exports = Backbone.Model.extend({
});
});
this.cacheLoad = sm.load(load);
this.trigger('storage:load', this.cacheLoad);
this.cacheLoad = sm.load(load, (loaded) => {
clb && clb(loaded);
this.trigger('storage:load', loaded);
});
return this.cacheLoad;
},

4
src/editor/view/EditorView.js

@ -23,8 +23,10 @@ module.exports = Backbone.View.extend({
if (config.clearOnRender) {
dComps.clear();
}
dComps.getComponents().add(config.components);
dComps.getComponents().reset(config.components);
model.loadOnStart();
um.clear();
// This will init loaded components
dComps.onLoad();
}

2
src/grapesjs/index.js

@ -5,8 +5,6 @@
Editor = require('editor'),
PluginManager = require('plugin_manager');
window['_'] = require('underscore');
var plugins = new PluginManager();
var editors = [];

1
src/panels/config/config.js

@ -30,7 +30,6 @@ module.exports = {
className: 'fa fa-eye',
command: prv,
context: prv,
stopDefaultCommand: 1,
attributes: { title: 'Preview' },
},{
id: ful,

52
src/panels/view/PanelView.js

@ -27,20 +27,68 @@ module.exports = Backbone.View.extend({
this.$el.html(this.model.get('content'));
},
initResize() {
const em = this.config.em;
const editor = em ? em.get('Editor') : '';
const resizable = this.model.get('resizable');
if (editor && resizable) {
var resz = resizable === true ? [1, 1, 1, 1] : resizable;
var resLen = resz.length;
var tc, cr, bc, cl = 0;
// Choose which sides of the panel are resizable
if (resLen == 2) {
tc = resz[0];
bc = resz[0];
cr = resz[1];
cl = resz[1];
} else if (resLen == 4) {
tc = resz[0];
cr = resz[1];
bc = resz[2];
cl = resz[3];
}
var resizer = editor.Utils.Resizer.init({
tc,
cr,
bc,
cl,
tl: 0,
tr: 0,
bl: 0,
br: 0,
appendTo: this.el,
prefix: editor.getConfig().stylePrefix,
posFetcher: (el) => {
var rect = el.getBoundingClientRect();
return {
left: 0, top: 0,
width: rect.width,
height: rect.height
};
}
});
resizer.blur = () => {};
resizer.focus(this.el);
}
},
render() {
this.$el.attr('class', _.result(this, 'className'));
this.$el.attr('class', this.className);
if(this.id)
this.$el.attr('id', this.id);
if(this.buttons.length){
if (this.buttons.length) {
var buttons = new ButtonsView({
collection: this.buttons,
config: this.config,
});
this.$el.append(buttons.render().el);
}
this.$el.append(this.model.get('content'));
return this;
},

25
src/panels/view/PanelsView.js

@ -7,8 +7,8 @@ module.exports = Backbone.View.extend({
this.opt = o || {};
this.config = this.opt.config || {};
this.pfx = this.config.stylePrefix || '';
this.listenTo( this.collection, 'add', this.addTo );
this.listenTo( this.collection, 'reset', this.render );
this.listenTo(this.collection, 'add', this.addTo );
this.listenTo(this.collection, 'reset', this.render );
this.className = this.pfx + 'panels';
},
@ -34,20 +34,25 @@ module.exports = Backbone.View.extend({
* */
addToCollection(model, fragmentEl) {
var fragment = fragmentEl || null;
var viewObject = PanelView;
var view = new viewObject({
var view = new PanelView({
model,
config: this.config,
});
var rendered = view.render().el;
var appendTo = model.get('appendTo');
if(fragment){
fragment.appendChild(rendered);
}else{
this.$el.append(rendered);
if (appendTo) {
var appendEl = document.querySelector(appendTo);
appendEl.appendChild(rendered);
} else {
if (fragment) {
fragment.appendChild(rendered);
} else {
this.$el.append(rendered);
}
}
view.initResize();
return rendered;
},
@ -60,7 +65,7 @@ module.exports = Backbone.View.extend({
}, this);
this.$el.append(fragment);
this.$el.attr('class', _.result(this, 'className'));
this.$el.attr('class', this.className);
return this;
}
});

2
src/rich_text_editor/view/TextEditorView.js

@ -1,5 +1,3 @@
var $ = require('jquery');
var readFileIntoDataUrl = fileInfo => {
var loader = $.Deferred(),
fReader = new FileReader();

5
src/storage_manager/index.js

@ -196,6 +196,7 @@ module.exports = () => {
/**
* Load resource from the current storage by keys
* @param {string|Array<string>} keys Keys to load
* @param {Function} clb Callback function
* @return {Object|null} Loaded resources
* @example
* var data = storageManager.load(['item1', 'item2']);
@ -203,7 +204,7 @@ module.exports = () => {
* var data2 = storageManager.load('item1');
* // data2 -> {item1: value1}
* */
load(keys) {
load(keys, clb) {
var st = this.get(this.getCurrent());
var keysF = [];
var result = {};
@ -214,7 +215,7 @@ module.exports = () => {
for (var i = 0, len = keys.length; i < len; i++)
keysF.push(c.id + keys[i]);
var loaded = st ? st.load(keysF) : {};
var loaded = st ? st.load(keysF, clb) : {};
// Restore keys name
for (var itemKey in loaded){

6
src/storage_manager/model/LocalStorage.js

@ -23,7 +23,7 @@ module.exports = Backbone.Model.extend({
/**
* @private
*/
load(keys) {
load(keys, clb) {
this.checkStorageEnvironment();
var result = {};
@ -33,6 +33,10 @@ module.exports = Backbone.Model.extend({
result[keys[i]] = value;
}
if (typeof clb == 'function') {
clb(result);
}
return result;
},

18
src/storage_manager/model/RemoteStorage.js

@ -24,7 +24,7 @@ module.exports = Backbone.Model.extend({
for(var key in params)
fd[key] = params[key];
$.ajax({
let req = $.ajax({
url: this.get('urlStore'),
beforeSend: this.get('beforeSend'),
complete: this.get('onComplete'),
@ -32,7 +32,10 @@ module.exports = Backbone.Model.extend({
dataType: 'json',
contentType: this.get('contentTypeJson') ? 'application/json; charset=utf-8': 'x-www-form-urlencoded',
data: this.get('contentTypeJson') ? JSON.stringify(fd): fd,
}).always(() => {
});
// Assign always callback when possible
req && req.always && req.always(() => {
if (typeof clb == 'function') {
clb();
}
@ -42,7 +45,7 @@ module.exports = Backbone.Model.extend({
/**
* @private
*/
load(keys) {
load(keys, clb) {
var result = {},
fd = {},
params = this.get('params');
@ -52,7 +55,7 @@ module.exports = Backbone.Model.extend({
fd.keys = keys;
$.ajax({
let req = $.ajax({
url: this.get('urlLoad'),
beforeSend: this.get('beforeSend'),
complete: this.get('onComplete'),
@ -62,6 +65,13 @@ module.exports = Backbone.Model.extend({
}).done(d => {
result = d;
});
// Assign always callback when possible
req && req.always && req.always((res) => {
if (typeof clb == 'function') {
clb(res);
}
});
return result;
},

9
src/style_manager/model/PropertyFactory.js

@ -26,13 +26,20 @@ module.exports = () => ({
}
// Fixed values
switch(prop){
switch(prop) {
case 'margin-top': case 'margin-right': case 'margin-bottom': case 'margin-left':
case 'padding-top': case 'padding-right': case 'padding-bottom': case 'padding-left':
case 'width': case 'max-width': case 'min-width':
case 'height': case 'max-height': case 'min-height':
obj.fixedValues = ['initial', 'inherit', 'auto'];
break;
case 'font-size':
obj.fixedValues = ['medium', 'xx-small', 'x-small', 'small', 'large',
'x-large', 'xx-large', 'smaller', 'larger', 'length', 'initial', 'inherit'];
break;
case 'letter-spacing': case 'line-height':
obj.fixedValues = ['normal', 'initial', 'inherit'];
break;
}
// Type

6
src/style_manager/view/PropertyCompositeView.js

@ -130,10 +130,10 @@ module.exports = PropertyView.extend({
* @return {string}
* */
build(selectedEl, propertyView, opts) {
var result = '';
var result = '';
this.model.get('properties').each(prop => {
var v = prop.getValue();
func = prop.get('functionName');
var v = prop.getValue();
var func = prop.get('functionName');
if(func)
v = func + '(' + v + ')';

17
src/style_manager/view/SectorsView.js

@ -33,22 +33,25 @@ module.exports = Backbone.View.extend({
* @private
*/
targetUpdated() {
var el = this.target.get('selectedComponent');
var em = this.target;
var el = em.get('selectedComponent');
if(!el)
return;
var previewMode = this.target.get('Config').devicePreviewMode;
const config = em.get('Config');
var previewMode = config.devicePreviewMode;
var classes = el.get('classes');
var pt = this.propTarget;
var device = this.target.getDeviceModel();
var device = em.getDeviceModel();
var state = !previewMode ? el.get('state') : '';
var mediaText = device && !previewMode && device.get('width')?
'(max-width: ' + device.get('width') + ')' : '';
var widthMedia = device && device.get('widthMedia');
var mediaText = device && !previewMode && widthMedia ?
`(${config.mediaCondition}: ${widthMedia})` : '';
pt.helper = null;
if(classes.length){
var cssC = this.target.get('CssComposer');
var cssC = em.get('CssComposer');
var valid = _.filter(classes.models, item => item.get('active'));
var iContainer = cssC.get(valid, state, mediaText);
@ -67,7 +70,7 @@ module.exports = Backbone.View.extend({
// If the state is not empty, there should be a helper rule in play
// The helper rule will get the same style of the iContainer
if(state){
var clm = this.target.get('SelectorManager');
var clm = em.get('SelectorManager');
var helperClass = clm.add('hc-state');
var helperRule = cssC.get([helperClass]);
if(!helperRule)

74
src/styles/scss/_gjs_blocks.scss

@ -0,0 +1,74 @@
.#{$app-prefix}blocks-c {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.#{$app-prefix}block-category {
width: 100%;
&.#{$app-prefix}open {
@extend .#{$app-prefix}category-open;
}
.#{$app-prefix}title {
@extend .#{$app-prefix}category-title;
}
.#{$app-prefix}caret-icon {
margin-right: 5px;
}
}
.#{$app-prefix}block {
@include user-select(none);
@extend .#{$app-prefix}bg-main;
width: 45%;
padding: 1em;
box-sizing: border-box;
height: 90px;
cursor: all-scroll;
font-size: 11px;
font-weight: lighter;
display: flex;
flex-direction: column;
justify-content: flex-end;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 3px;
margin: 10px 2.5% 5px;
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.15);
transition: all 0.2s ease 0s;
transition-property: box-shadow, color;
&:hover {
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15);
}
}
.#{$app-prefix}block-svg {
width: 61%;
}
.#{$app-prefix}block-svg-path {
@extend .#{$app-prefix}color-main;
}
.#{$app-prefix}block.fa {
font-size: 2em;
line-height: 2em;
padding: 11px;
}
.#{$app-prefix}block-label {
line-height: normal;
font-size: 0.65rem;
font-weight: normal;
font-family: Helvetica, sans-serif;
}
.#{$app-prefix}block.#{$app-prefix}bdrag {
width: auto;
padding: 0;
}

25
src/styles/scss/_gjs_canvas.scss

@ -185,6 +185,31 @@ $hndlMargin: -5px;
cursor: nwse-resize;
}
.#{$pn-prefix}panel {
.#{$app-prefix}resizer-h {
background-color: rgba(0, 0, 0, 0.2);
border: none;
opacity: 0;
transition: opacity 0.25s;
&:hover {
opacity: 1;
}
}
.#{$app-prefix}resizer-h-tc,
.#{$app-prefix}resizer-h-bc {
margin: 0 auto;
width: 100%;
}
.#{$app-prefix}resizer-h-cr,
.#{$app-prefix}resizer-h-cl {
margin: auto 0;
height: 100%;
}
}
.#{$app-prefix}resizing .#{$app-prefix}highlighter,
.#{$app-prefix}resizing .#{$app-prefix}badge {
display: none !important;

98
src/styles/scss/main.scss

@ -149,12 +149,14 @@ $fontV: 20;//random(1000)
background-color: $mainColor;
}
.#{$app-prefix}color-main{
.#{$app-prefix}color-main {
color: $fontColor;
fill: $fontColor;
}
.#{$app-prefix}color-active{
.#{$app-prefix}color-active {
color: $fontColorActive;
fill: $fontColorActive;
}
.#{$app-prefix}bdrag {
@ -712,6 +714,26 @@ $lightBorder: rgba(255, 255, 255, 0.05);
/********* END Device Manager **********/
/********* General **********/
.#{$app-prefix}category-open {
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
}
.#{$app-prefix}category-title {
@extend .no-select;
font-weight: lighter;
background-color: $mainDklColor;
font-size: 13px;
letter-spacing: 1px;
padding: 9px 10px 9px 20px;
border-bottom: 1px solid rgba(0, 0, 0, 0.25);
text-align: left;
position: relative;
cursor: pointer;
}
/********* Style Manager **********/
.#{$sm-prefix}close-btn{
@ -732,22 +754,20 @@ $lightBorder: rgba(255, 255, 255, 0.05);
}
.#{$sm-prefix}sector {
clear:both;
border-bottom: 1px solid $mainDkColor;
font-weight: lighter;
text-align:left;
##{$sm-prefix}caret{
##{$sm-prefix}caret{
padding-right: 5px;
font-size: 11px;
}
.#{$sm-prefix}title{
background-color: $mainDklColor;
font-size: 13px;
letter-spacing: 1px;
padding: 12px 10px 12px 20px;
border-top: 1px solid $mainLhColor;
cursor:pointer;
&.#{$sm-prefix}open {
@extend .#{$app-prefix}category-open;
}
.#{$sm-prefix}title {
@extend .#{$app-prefix}category-title;
}
.#{$sm-prefix}label {
@ -1056,61 +1076,7 @@ $lightBorder: rgba(255, 255, 255, 0.05);
}
/********* END Style Manager **********/
/********* Block manager **********/
.#{$app-prefix}blocks-c {
display: flex;
flex-wrap: wrap;
justify-content: flex-start;
}
.#{$app-prefix}block {
@include user-select(none);
@extend .#{$app-prefix}bg-main;
width: 45%;
padding: 1em;
box-sizing: border-box;
height: 90px;
cursor:all-scroll;
font-size: 11px;
font-weight: lighter;
display: flex;
flex-direction: column;
justify-content: flex-end;
border: 1px solid rgba(0, 0, 0, 0.2);
border-radius: 3px;
margin: 10px 2.5% 5px;
box-shadow: 0 1px 0 0 rgba(0, 0, 0, 0.15);
transition: all 0.2s ease 0s;
transition-property: box-shadow, color;
&:hover {
box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.15);
}
}
.#{$app-prefix}block.fa {
font-size: 2em;
line-height: 2em;
padding: 11px;
}
.#{$app-prefix}block-label {
line-height: normal;
font-size: 0.65rem;
font-weight: normal;
font-family: Helvetica, sans-serif;
}
.#{$app-prefix}block.#{$app-prefix}bdrag{
width: auto;
padding: 0;
}
/********* END Block manager **********/
@import "gjs_blocks";

323
src/utils/Dragger.js

@ -0,0 +1,323 @@
var getBoundingRect = (el, win) => {
var w = win || window;
var rect = el.getBoundingClientRect();
return {
left: rect.left + w.pageXOffset,
top: rect.top + w.pageYOffset,
width: rect.width,
height: rect.height
};
};
module.exports = {
// TODO move to opts
setKey(keys, command) {
//key(keys, command);
},
/**
* Return element position
* @param {HTMLElement} el
* @return {Object}
*/
getElementRect(el) {
var posFetcher = this.opts.posFetcher || '';
return posFetcher ? posFetcher(el, {
avoidFrameOffset: 1,
}) : getBoundingRect(el);
},
/**
* Init the resizer
* @param {Object} opts
*/
init(opts) {
this.setOptions(opts);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.drag = this.drag.bind(this);
this.move = this.move.bind(this);
this.stop = this.stop.bind(this);
this.setKey('up, right, down, left', this.handleKey);
return this;
},
/**
* Update options
* @param {Object} options
*/
setOptions(opts) {
this.opts = opts || {};
},
/**
* Focus dragger on the element
* @param {HTMLElement} el
*/
focus(el) {
// Avoid focusing on already focused element
if (el && el === this.el) {
return;
}
this.getDocumentEl(el);
this.blur();
this.el = el;
this.handlers = this.opts.dragHandlers || [el];
var elRect = this.getElementRect(el); //<-- TODO have wrong top:left
this.elRect = elRect;
this.startTop = elRect.top;
this.startLeft = elRect.left;
// TODO init snapper
this.getDocumentEl().on('mousedown', this.handleMouseDown);
},
/**
* Blur from the focused element
*/
blur() {
this.getDocumentEl().off('mousedown', this.handleMouseDown);
this.el = null;
},
/**
* Start dragging
* @param {Event} e
*/
start(e) {
this.startPos = this.getMousePos(e);
var docs = this.getDocumentEl();
docs.on('mousemove', this.drag);
docs.on('mouseup', this.stop);
// Start callback
var onStart = this.opts.onStart;
if(typeof onStart === 'function') {
onStart(e, {
docs,
el: this.el,
start: this.startPos,
elRect: this.elRect,
});
}
this.drag(e);
},
/**
* Stop dragging
*/
stop(e) {
var docs = this.getDocumentEl();
docs.off('mousemove', this.drag);
docs.off('mouseup', this.stop);
this.lockedAxis = null;
// Stop callback
var onEnd = this.opts.onEnd;
if(typeof onEnd === 'function') {
onEnd(e, {
docs,
delta: this.delta,
end: {
x: this.startLeft + this.delta.x,
y: this.startTop + this.delta.y,
}
});
}
},
/**
* Handle mousedown to check if it's possible to drag
* @param {Event} e
*/
handleMouseDown(e) {
var el = e.target;
if (this.isHandler(el)) {
this.start(e);
}
},
/**
* Detects if the clicked element is a valid handler
* @param {HTMLElement} el
* @return {Boolean}
*/
isHandler(el) {
var handlers = this.handlers;
for (var n in handlers) {
if (handlers[n] === el) return true;
}
return false;
},
/**
* Handle key press
* @param {Event} e
* @param {Object} handler
*/
handleKey(e, handler) {
switch (handler.shortcut) {
case 'up':
this.move(0, -1);
break;
case 'right':
this.move(1, 0);
break;
case 'down':
this.move(0, 1);
break;
case 'left':
this.move(-1, 0);
break;
}
},
/**
* Returns documents
*/
getDocumentEl(el) {
var el = el || this.el;
if (!this.$doc) {
var docs = [document];
if (el) {
docs.push(el.ownerDocument);
}
this.$doc = $(docs);
}
return this.$doc;
},
/**
* Get mouse coordinates
* @param {Event} event
* @return {Object}
*/
getMousePos(e) {
var mouseFetch = this.opts.mousePosFetcher;
return mouseFetch ? mouseFetch(e) : {
x: e.clientX,
y: e.clientY
};
},
/**
* Drag event
* @param {Event} event
*/
drag(e) {
var lockedAxis = this.lockedAxis;
var currentPos = this.getMousePos(e);
var delta = {
x: currentPos.x - this.startPos.x,
y: currentPos.y - this.startPos.y
};
// Lock one axis
if (e.shiftKey) {
if (!lockedAxis) {
var relX = delta.x;
var relY = delta.y;
var absX = Math.abs(relX);
var absY = Math.abs(relY);
// Vertical or Horizontal lock
if (relY >= absX || relY <= -absX) {
lockedAxis = 'x';
} else if (relX > absY || relX < -absY) {
lockedAxis = 'y';
}
}
} else {
lockedAxis = null;
}
if (lockedAxis === 'x') {
delta.x = this.startPos.x;
}
if (lockedAxis === 'y') {
delta.y = this.startPos.y;
}
this.lockedAxis = lockedAxis;
this.delta = delta;
this.move(delta.x, delta.y);
// Drag callback
const onDrag = this.opts.onDrag;
if(typeof onDrag === 'function') {
onDrag(e, {
delta,
current: {
x: this.startLeft + delta.x,
y: this.startTop + delta.y
},
lockedAxis
});
}
// In case the mouse button was released outside of the window
if (e.which === 0) {
this.stop(e);
}
},
/**
* Move the element
* @param {integer} x
* @param {integer} y
*/
move: function(x, y) {
this.moveX(x);
this.moveY(y);
},
/**
* Move in x direction
* @param {integer} x
*/
moveX(x) {
var el = this.el;
var opts = this.opts;
var xPos = this.startLeft + x;
const setX = this.opts.setX;
if (typeof setX === 'function') {
setX(xPos, {
el,
start: this.startLeft,
delta: x,
});
} else {
el.style.left = xPos + 'px';
}
},
/**
* Move in y direction
* @param {integer} y
*/
moveY(y) {
var el = this.el;
var opts = this.opts;
var yPos = this.startTop + y;
const setY = this.opts.setY;
if (typeof setY === 'function') {
setY(yPos, {
el,
start: this.startTop,
delta: y,
});
} else {
el.style.top = yPos + 'px';
}
},
};

40
src/utils/Resizer.js

@ -38,14 +38,13 @@ var getBoundingRect = (el, win) => {
};
};
module.exports = {
class Resizer {
/**
* Init the Resizer with options
* @param {Object} options
*/
init(options) {
var opts = options || {};
constructor(opts = {}) {
var pfx = opts.prefix || '';
var appendTo = opts.appendTo || document.body;
@ -90,7 +89,7 @@ module.exports = {
this.onEnd = opts.onEnd;
return this;
},
}
/**
* Update options
@ -104,7 +103,7 @@ module.exports = {
this[opt] = opts[opt];
}
}
},
}
/**
* Detects if the passed element is a resize handler
@ -119,7 +118,7 @@ module.exports = {
}
return false;
},
}
/**
* Returns the focused element
@ -127,7 +126,7 @@ module.exports = {
*/
getFocusedEl() {
return this.el;
},
}
/**
* Returns documents
@ -137,7 +136,7 @@ module.exports = {
this.$doc = $([this.el.ownerDocument, document]);
}
return this.$doc;
},
}
/**
* Return element position
@ -147,7 +146,7 @@ module.exports = {
getElementPos(el) {
var posFetcher = this.posFetcher || '';
return posFetcher ? posFetcher(el) : getBoundingRect(el);
},
}
/**
* Focus resizer on the element, attaches handlers to it
@ -171,7 +170,7 @@ module.exports = {
this.container.style.display = 'block';
this.getDocumentEl().on('mousedown', this.handleMouseDown);
},
}
/**
* Blur from element
@ -183,7 +182,7 @@ module.exports = {
this.getDocumentEl().off('mousedown', this.handleMouseDown);
this.el = null;
}
},
}
/**
* Start resizing
@ -229,7 +228,7 @@ module.exports = {
if(typeof this.onStart === 'function') {
this.onStart(e, {docs: doc});
}
},
}
/**
* While resizing
@ -266,7 +265,7 @@ module.exports = {
if (e.which === 0) {
this.stop(e);
}
},
}
/**
* Stop resizing
@ -283,7 +282,7 @@ module.exports = {
if(typeof this.onEnd === 'function') {
this.onEnd(e, {docs: doc});
}
},
}
/**
* Update rect
@ -309,7 +308,7 @@ module.exports = {
conStyle.top = rectEl.top + unit;
conStyle.width = rectEl.width + unit;
conStyle.height = rectEl.height + unit;
},
}
/**
* Handle ESC key
@ -321,7 +320,7 @@ module.exports = {
this.rectDim = this.startDim;
this.stop(e);
}
},
}
/**
* Handle mousedown to check if it's possible to start resizing
@ -334,7 +333,7 @@ module.exports = {
}else if(el !== this.el){
this.blur();
}
},
}
/**
* All positioning logic
@ -386,6 +385,11 @@ module.exports = {
}
return box;
},
}
}
module.exports = {
init(opts) {
return new Resizer(opts);
}
};

52
src/utils/Sorter.js

@ -81,11 +81,13 @@ module.exports = Backbone.View.extend({
var sortCls = pfx + 'grabbing';
var emBody = em ? em.get('Canvas').getBody() : '';
if(active) {
em && em.get('Canvas').startAutoscroll();
body.className += ' ' + sortCls;
if(em) {
emBody.className += ' ' + sortCls;
}
} else {
em && em.get('Canvas').stopAutoscroll();
body.className = body.className.replace(sortCls, '').trim();
if(em) {
emBody.className = emBody.className.replace(sortCls, '').trim();
@ -108,7 +110,7 @@ module.exports = Backbone.View.extend({
for(var i = 0; i < o.length; i++) {
style += o[i] + ':' + o.getPropertyValue(o[i])+';';
}
clonedEl.style = style;
clonedEl.setAttribute('style', style);
clonedEl.className += ' ' + this.pfx + 'bdrag';
document.body.appendChild(clonedEl);
this.dragHelper = clonedEl;
@ -231,8 +233,9 @@ module.exports = Backbone.View.extend({
this.getContainerEl().appendChild(this.plh);
}
if(this.eV) {
this.eV.className += ' ' + this.freezeClass;
if(trg) {
var className = trg.getAttribute('class');
trg.setAttribute('class', `${className} ${this.freezeClass}`);
this.$document.on('mouseup', this.endMove);
}
@ -251,6 +254,31 @@ module.exports = Backbone.View.extend({
this.toggleSortCursor(1);
},
/**
* Get the model from HTMLElement target
* @return {Model|null}
*/
getModelFromTarget(el) {
let elem = el || this.target;
return $(elem).data('model');
},
/**
* Highlight target
* @param {Model|null} model
*/
selectTargetModel(model) {
var prevModel = this.targetModel;
if (prevModel) {
prevModel.set('status', '');
}
if (model && model.set) {
model.set('status', 'selected-parent');
this.targetModel = model;
}
},
/**
* During move
* @param {Event} e
@ -278,6 +306,10 @@ module.exports = Backbone.View.extend({
}
var dims = this.dimsFromTarget(e.target, rX, rY);
let targetModel = this.getModelFromTarget(this.target);
this.selectTargetModel(targetModel);
this.lastDims = dims;
var pos = this.findPosition(dims, rX, rY);
// If there is a significant changes with the pointer
@ -623,10 +655,15 @@ module.exports = Backbone.View.extend({
this.$document.off('keydown', this.rollback);
this.plh.style.display = 'none';
var clsReg = new RegExp('(?:^|\\s)'+this.freezeClass+'(?!\\S)', 'gi');
if(this.eV)
this.eV.className = this.eV.className.replace(clsReg, '');
let trg = this.eV;
if (trg) {
var className = (trg.getAttribute('class')+'').replace(clsReg, '');
trg.setAttribute('class', className);
}
if(this.moved)
created = this.move(this.target, this.eV, this.lastPos);
created = this.move(this.target, trg, this.lastPos);
if(this.plh)
this.plh.style.display = 'none';
@ -634,10 +671,13 @@ module.exports = Backbone.View.extend({
this.onEndMove(created);
var dragHelper = this.dragHelper;
if(dragHelper) {
dragHelper.remove();
this.dragHelper = null;
}
this.selectTargetModel();
this.toggleSortCursor();
},

8
src/utils/index.js

@ -1,8 +1,8 @@
module.exports = () => {
var Sorter = require('./Sorter');
var Resizer = require('./Resizer');
const Sorter = require('./Sorter');
const Resizer = require('./Resizer');
const Dragger = require('./Dragger');
return {
/**
@ -20,7 +20,7 @@ module.exports = () => {
},
Sorter,
Resizer,
Dragger,
};
};

44
test/helper.js

@ -1,18 +1,52 @@
import _ from 'underscore';
import expect from 'expect';
import sinon from 'sinon';
import jquery from 'jquery';
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>');
global.window = dom.window;
global.document = dom.window.document;
const window = dom.window;
const $ = jquery(window);
//https://www.npmjs.com/package/proxyquire
// Fix for the spectrum lib
var Module = require('module');
var originalRequire = Module.prototype.require;
Module.prototype.require = function(name) {
if (name == 'jquery') {
return $;
}
return originalRequire.apply(this, arguments);
};
var localStorage = {
getItem(key) {
return this[key];
},
setItem(key, value) {
this[key] = value;
},
removeItem(key, value) {
delete this[key];
}
};
global.window = window;
global.document = window.document;
global.$ = $;
global._ = _;
global.expect = expect;
global.sinon = sinon;
dom.window.$ = jquery(dom.window);
Backbone.$ = dom.window.$;
global.grapesjs = grapesjs;
global.Backbone = Backbone;
global.localStorage = localStorage;
global.SVGElement = global.Element;
window.$ = $;
Backbone.$ = $;
Object.keys(window).forEach((key) => {
if (!(key in global)) {

23
test/main.js

@ -1,15 +1,28 @@
import grapesjs from './../src';
//import AssetManager from './specs/asset_manager';
//import grapesjs from './../src';
describe('Main', () => {
describe('Startup', () => {
it('Main object should be loaded', () => {
//Grapes = require('editor/main');
expect(grapesjs).toExist();
});
});
require('./specs/asset_manager/main.js');
const path = './specs/';
require(`${path}asset_manager`);
require(`${path}block_manager`);
require(`${path}code_manager`);
require(`${path}commands`);
require(`${path}css_composer`);
require(`${path}device_manager`);
require(`${path}dom_components`);
require(`${path}grapesjs`);
require(`${path}modal`);
require(`${path}panels`);
require(`${path}parser`);
require(`${path}plugin_manager`);
require(`${path}selector_manager`);
require(`${path}storage_manager`);
require(`${path}style_manager`);
require(`${path}trait_manager`);
});

38
test/specs/asset_manager/main.js → test/specs/asset_manager/index.js

@ -2,9 +2,9 @@ var StorageManager = require('storage_manager');
var AssetManager = require('asset_manager');
var FileUploader = require('./view/FileUploader');
describe('Asset Manager', function() {
describe('Asset Manager', () => {
describe('Main', function() {
describe('Main', () => {
var obj;
var imgObj;
@ -12,15 +12,15 @@ describe('Asset Manager', function() {
var storage;
var storageId = 'testStorage';
var storageMock = {
store: function(data){
store(data) {
storage = data;
},
load: function(keys){
load(keys) {
return storage;
},
};
beforeEach(function () {
beforeEach(() => {
imgObj = {
type: 'image',
src: 'path/to/image',
@ -31,24 +31,24 @@ describe('Asset Manager', function() {
obj.init();
});
afterEach(function () {
afterEach(() => {
obj = null;
});
it('Object exists', function() {
it('Object exists', () => {
expect(obj).toExist();
});
it('No assets inside', function() {
it('No assets inside', () => {
expect(obj.getAll().length).toEqual(0);
});
it('Add new asset', function() {
it('Add new asset', () => {
obj.add(imgObj);
expect(obj.getAll().length).toEqual(1);
});
it('Added asset has correct data', function() {
it('Added asset has correct data', () => {
obj.add(imgObj);
var asset = obj.get(imgObj.src);
expect(asset.get('width')).toEqual(imgObj.width);
@ -56,14 +56,14 @@ describe('Asset Manager', function() {
expect(asset.get('type')).toEqual(imgObj.type);
});
it('Add asset with src', function() {
it('Add asset with src', () => {
obj.add(imgObj.src);
var asset = obj.get(imgObj.src);
expect(asset.get('type')).toEqual('image');
expect(asset.get('src')).toEqual(imgObj.src);
});
it('Add asset with more src', function() {
it('Add asset with more src', () => {
obj.add([imgObj.src, imgObj.src + '2']);
expect(obj.getAll().length).toEqual(2);
var asset1 = obj.getAll().at(0);
@ -72,28 +72,28 @@ describe('Asset Manager', function() {
expect(asset2.get('src')).toEqual(imgObj.src + '2');
});
it('Src is unique', function() {
it('Src is unique', () => {
obj.add(imgObj);
obj.add(imgObj);
expect(obj.getAll().length).toEqual(1);
});
it('Remove asset', function() {
it('Remove asset', () => {
obj.add(imgObj);
obj.remove(imgObj.src);
expect(obj.getAll().length).toEqual(0);
});
it('Render assets', function() {
it('Render assets', () => {
obj.add(imgObj);
expect(obj.render()).toExist();
});
describe('With storage', function() {
describe('With storage', () => {
var storageManager;
beforeEach(function () {
beforeEach(() => {
storageManager = new StorageManager().init({
autoload: 0,
type: storageId
@ -104,11 +104,11 @@ describe('Asset Manager', function() {
storageManager.add(storageId, storageMock);
});
afterEach(function () {
afterEach(() => {
storageManager = null;
});
it('Store and load data', function() {
it('Store and load data', () => {
obj.add(imgObj);
obj.store();
obj.remove(imgObj.src);

12
test/specs/asset_manager/model/Asset.js

@ -1,14 +1,14 @@
var Asset = require('asset_manager/model/Asset');
module.exports = {
run: function(){
run() {
describe('Asset', function() {
it('Object exists', function() {
describe('Asset', () => {
it('Object exists', () => {
expect(Asset).toExist();
});
it('Has default values', function() {
it('Has default values', () => {
var obj = new Asset({});
expect(obj.get('type')).toNotExist();
expect(obj.get('src')).toNotExist();
@ -16,14 +16,14 @@ module.exports = {
expect(obj.getFilename()).toNotExist();
});
it('Test getFilename', function() {
it('Test getFilename', () => {
var obj = new Asset({ type:'image', src: 'ch/eck/t.e.s.t'});
expect(obj.getFilename()).toEqual('t.e.s.t');
var obj = new Asset({ type:'image', src: 'ch/eck/1234abc'});
expect(obj.getFilename()).toEqual('1234abc');
});
it('Test getExtension', function() {
it('Test getExtension', () => {
var obj = new Asset({ type:'image', src: 'ch/eck/t.e.s.t'});
expect(obj.getExtension()).toEqual('t');
var obj = new Asset({ type:'image', src: 'ch/eck/1234abc.'});

8
test/specs/asset_manager/model/AssetImage.js

@ -1,14 +1,14 @@
var AssetImage = require('asset_manager/model/AssetImage');
module.exports = {
run: function() {
run() {
describe('AssetImage', function() {
it('Object exists', function() {
describe('AssetImage', () => {
it('Object exists', () => {
expect(AssetImage).toExist();
});
it('Has default values', function() {
it('Has default values', () => {
var obj = new AssetImage({});
expect(obj.get('type')).toEqual('image');
expect(obj.get('src')).toNotExist();

20
test/specs/asset_manager/model/Assets.js

@ -1,45 +1,45 @@
var Assets = require('asset_manager/model/Assets');
module.exports = {
run: function() {
describe('Assets', function() {
run() {
describe('Assets', () => {
var obj;
beforeEach(function () {
beforeEach(() => {
obj = new Assets();
});
afterEach(function () {
afterEach(() => {
obj = null;
});
it('Object exists', function() {
it('Object exists', () => {
expect(obj).toExist();
});
it('Collection is empty', function() {
it('Collection is empty', () => {
expect(obj.length).toEqual(0);
});
it("Can't insert assets without src", function() {
it("Can't insert assets without src", () => {
obj.add({});
expect(obj.length).toEqual(0);
obj.add([{},{},{}]);
expect(obj.length).toEqual(0);
});
it("Insert assets only with src", function() {
it("Insert assets only with src", () => {
obj.add([{},{src:'test'},{}]);
expect(obj.length).toEqual(1);
});
it('addImg creates new asset', function() {
it('addImg creates new asset', () => {
obj.addImg('/img/path');
expect(obj.length).toEqual(1);
});
it('addImg asset is correct', function() {
it('addImg asset is correct', () => {
obj.addImg('/img/path');
var asset = obj.at(0);
expect(asset.get('type')).toEqual('image');

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

@ -3,9 +3,9 @@ var AssetImage = require('asset_manager/model/AssetImage');
var Assets = require('asset_manager/model/Assets');
module.exports = {
run: function() {
run() {
describe('AssetImageView', function() {
describe('AssetImageView', () => {
before(function () {
this.$fixtures = $("#fixtures");
@ -17,7 +17,7 @@ module.exports = {
var model = coll.add({ type:'image', src: '/test' });
this.view = new AssetImageView({
config : {},
model: model
model
});
this.$fixture.empty().appendTo(this.$fixtures);
this.$fixture.html(this.view.render().el);
@ -31,11 +31,11 @@ module.exports = {
this.$fixture.empty();
});
it('Object exists', function() {
it('Object exists', () => {
expect(AssetImageView).toExist();
});
describe('Asset should be rendered correctly', function() {
describe('Asset should be rendered correctly', () => {
it('Has preview box', function() {
var $asset = this.view.$el;

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

@ -3,9 +3,9 @@ var Asset = require('asset_manager/model/Asset');
var Assets = require('asset_manager/model/Assets');
module.exports = {
run: function() {
run() {
describe('AssetView', function() {
describe('AssetView', () => {
before(function () {
this.$fixtures = $("#fixtures");
@ -17,7 +17,7 @@ module.exports = {
var model = coll.add({src: 'test'});
this.view = new AssetView({
config : {},
model: model
model
});
this.$fixture.empty().appendTo(this.$fixtures);
this.$fixture.html(this.view.render().el);
@ -31,7 +31,7 @@ module.exports = {
this.$fixture.remove();
});
it('Object exists', function() {
it('Object exists', () => {
expect(AssetView).toExist();
});

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

@ -2,9 +2,9 @@ var AssetsView = require('asset_manager/view/AssetsView');
var Assets = require('asset_manager/model/Assets');
module.exports = {
run: function() {
run() {
describe('AssetsView', function() {
describe('AssetsView', () => {
var obj;
@ -32,7 +32,7 @@ module.exports = {
this.$fixture.remove();
});
it('Object exists', function() {
it('Object exists', () => {
expect(AssetsView).toExist();
});
@ -72,18 +72,18 @@ module.exports = {
expect($asset.attr('class')).toNotExist();
});
it("Returns not empty assets element", function (){
it("Returns not empty assets element", () => {
expect(obj.getAssetsEl()).toExist();
});
it("Returns not empty url input", function (){
it("Returns not empty url input", () => {
expect(obj.getInputUrl()).toExist();
});
it("Add image asset from input string", function (){
it("Add image asset from input string", () => {
obj.getInputUrl().value = "test";
obj.addFromStr({
preventDefault: function(){}
preventDefault() {}
});
var asset = obj.collection.at(0);
expect(asset.get('src')).toEqual('test');

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

@ -1,9 +1,9 @@
var FileUploader = require('asset_manager/view/FileUploader');
module.exports = {
run: function() {
run() {
describe('File Uploader', function() {
describe('File Uploader', () => {
before(function () {
this.$fixtures = $("#fixtures");
@ -24,7 +24,7 @@ module.exports = {
this.$fixture.remove();
});
it('Object exists', function() {
it('Object exists', () => {
expect(FileUploader).toExist();
});
@ -32,7 +32,7 @@ module.exports = {
expect(this.view.pfx).toNotExist();
});
describe('Should be rendered correctly', function() {
describe('Should be rendered correctly', () => {
it('Has title', function() {
expect(this.view.$el.find('#title').length).toEqual(1);
@ -52,9 +52,9 @@ module.exports = {
});
describe('Interprets configurations correctly', function() {
describe('Interprets configurations correctly', () => {
it('Has correct title', function() {
it('Has correct title', () => {
var view = new FileUploader({ config : {
uploadText : 'Test',
} });
@ -62,7 +62,7 @@ module.exports = {
expect(view.$el.find('#title').html()).toEqual('Test');
});
it('Could be disabled', function() {
it('Could be disabled', () => {
var view = new FileUploader({ config : {
disableUpload: true,
} });

75
test/specs/block_manager/index.js

@ -0,0 +1,75 @@
var BlockManager = require('block_manager');
var BlocksView = require('./view/BlocksView');
describe('BlockManager', () => {
describe('Main', () => {
var obj;
var idTest;
var optsTest;
beforeEach(() => {
idTest = 'h1-block';
optsTest = {
label: 'Heading',
content: '<h1>Test</h1>'
};
obj = new BlockManager().init();
obj.render();
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(obj).toExist();
});
it('No blocks inside', () => {
expect(obj.getAll().length).toEqual(0);
});
it('No categories inside', () => {
expect(obj.getCategories().length).toEqual(0);
});
it('Add new block', () => {
var model = obj.add(idTest, optsTest);
expect(obj.getAll().length).toEqual(1);
});
it('Added block has correct data', () => {
var model = obj.add(idTest, optsTest);
expect(model.get('label')).toEqual(optsTest.label);
expect(model.get('content')).toEqual(optsTest.content);
});
it('Add block with attributes', () => {
optsTest.attributes = {'class':'test'};
var model = obj.add(idTest, optsTest);
expect(model.get('attributes').class).toEqual('test');
});
it('The id of the block is unique', () => {
var model = obj.add(idTest, optsTest);
var model2 = obj.add(idTest, {other: 'test'});
expect(model).toEqual(model2);
});
it('Get block by id', () => {
var model = obj.add(idTest, optsTest);
var model2 = obj.get(idTest);
expect(model).toEqual(model2);
});
it('Render blocks', () => {
expect(obj.render()).toExist();
});
});
BlocksView.run();
});

74
test/specs/block_manager/main.js

@ -1,74 +0,0 @@
define(function(require, exports, module){
'use strict';
var BlockManager = require('BlockManager');
var BlocksView = require('undefined');
describe('BlockManager', function() {
describe('Main', function() {
var obj;
var idTest;
var optsTest;
beforeEach(function () {
idTest = 'h1-block';
optsTest = {
label: 'Heading',
content: '<h1>Test</h1>'
};
obj = new BlockManager().init();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
obj.should.be.exist;
});
it('No blocks inside', function() {
var coll = obj.getAll();
coll.length.should.equal(0);
});
it('Add new block', function() {
var model = obj.add(idTest, optsTest);
obj.getAll().length.should.equal(1);
});
it('Added block has correct data', function() {
var model = obj.add(idTest, optsTest);
model.get('label').should.equal(optsTest.label);
model.get('content').should.equal(optsTest.content);
});
it('Add block with attributes', function() {
optsTest.attributes = {'class':'test'};
var model = obj.add(idTest, optsTest);
model.get('attributes').class.should.equal('test');
});
it('The id of the block is unique', function() {
var model = obj.add(idTest, optsTest);
var model2 = obj.add(idTest, {other: 'test'});
model.should.deep.equal(model2);
});
it('Get block by id', function() {
var model = obj.add(idTest, optsTest);
var model2 = obj.get(idTest);
model.should.deep.equal(model2);
});
it('Render blocks', function() {
obj.render().should.be.ok;
});
});
BlocksView.run();
});
});

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

@ -1,91 +1,88 @@
define(function(require, exports, module){
'use strict';
var BlocksView = require('undefined');
var Blocks = require('BlockManager/model/Blocks');
module.exports = {
run : function(){
describe('BlocksView', function() {
var $fixtures;
var $fixture;
var model;
var view;
var editorModel;
var ppfx;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="devices-fixture"></div>');
});
var Backbone = require('backbone');
var BlocksView = require('block_manager/view/BlocksView');
var Blocks = require('block_manager/model/Blocks');
module.exports = {
run() {
describe('BlocksView', () => {
var $fixtures;
var $fixture;
var model;
var view;
var editorModel;
var ppfx;
before(() => {
$fixtures = $('#fixtures');
$fixture = $('<div class="devices-fixture"></div>');
});
beforeEach(function () {
model = new Blocks([]);
view = new BlocksView({ collection: model });
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
beforeEach(() => {
model = new Blocks([]);
view = new BlocksView({ collection: model });
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
view.collection.reset();
});
afterEach(() => {
view.collection.reset();
});
after(function () {
$fixture.remove();
});
after(() => {
$fixture.remove();
});
it("The container is not empty", function (){
view.el.outerHTML.should.be.not.empty;
});
it("The container is not empty", () => {
expect(view.el.outerHTML).toExist();
});
it("No children inside", function (){
view.el.children.length.should.equal(0);
});
it("No children inside", () => {
expect(view.getBlocksEl().children.length).toEqual(0);
});
it("Render children on add", function (){
model.add({});
view.el.children.length.should.equal(1);
model.add([{},{}]);
view.el.children.length.should.equal(3);
});
it("Render children on add", () => {
model.add({});
expect(view.getBlocksEl().children.length).toEqual(1);
model.add([{},{}]);
expect(view.getBlocksEl().children.length).toEqual(3);
});
it("Destroy children on remove", () => {
model.add([{},{}]);
expect(view.getBlocksEl().children.length).toEqual(2);
model.at(0).destroy();
expect(view.getBlocksEl().children.length).toEqual(1);
});
it("Destroy children on remove", function (){
model.add([{},{}]);
view.el.children.length.should.equal(2);
model.at(0).destroy();
view.el.children.length.should.equal(1);
describe('With configs', () => {
beforeEach(() => {
ppfx = 'pfx-t-';
editorModel = new Backbone.Model();
model = new Blocks([
{name:'test1'},
{name:'test2'}
]);
view = new BlocksView({
collection: model,
},{
pStylePrefix: ppfx
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
describe('With configs', function() {
beforeEach(function () {
ppfx = 'pfx-t-';
editorModel = new Backbone.Model();
model = new Blocks([
{name:'test1'},
{name:'test2'}
]);
view = new BlocksView({
collection: model,
},{
pStylePrefix: ppfx
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it("Render children", function (){
view.el.children.length.should.equal(2);
});
it("Render container", function (){
view.el.getAttribute('class').should.equal(ppfx + 'blocks-c');
});
it("Render children", () => {
expect(view.getBlocksEl().children.length).toEqual(2);
});
});
it("Render container", () => {
expect(view.getBlocksEl().getAttribute('class')).toEqual(ppfx + 'blocks-c');
});
});
}
};
});
});
}
};

43
test/specs/code_manager/index.js

@ -0,0 +1,43 @@
var CodeManager = require('code_manager');
var Models = require('./model/CodeModels');
describe('Code Manager', () => {
describe('Main', () => {
let obj;
beforeEach(() => {
obj = new CodeManager();
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(CodeManager).toExist();
});
it('No code generators inside', () => {
expect(obj.getGenerators()).toEqual({});
});
it('No code viewers inside', () => {
expect(obj.getViewers()).toEqual({});
});
it('Add and get code generator', () => {
obj.addGenerator('test', 'gen');
expect(obj.getGenerator('test')).toEqual('gen');
});
it('Add and get code viewer', () => {
obj.addViewer('test', 'view');
expect(obj.getViewer('test')).toEqual('view');
});
});
Models.run();
});

47
test/specs/code_manager/main.js

@ -1,47 +0,0 @@
define(function(require, exports, module){
'use strict';
var CodeManager = require('CodeManager');
var Models = require('undefined');
describe('Code Manager', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new CodeManager();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
CodeManager.should.be.exist;
});
it('No code generators inside', function() {
obj.getGenerators().should.be.empty;
});
it('No code viewers inside', function() {
obj.getViewers().should.be.empty;
});
it('Add and get code generator', function() {
obj.addGenerator('test', 'gen');
obj.getGenerator('test').should.equal('gen');
});
it('Add and get code viewer', function() {
obj.addViewer('test', 'view');
obj.getViewer('test').should.equal('view');
});
});
Models.run();
});
});

439
test/specs/code_manager/model/CodeModels.js

@ -1,221 +1,218 @@
define(function(require, exports, module){
'use strict';
var CssGenerator = require('undefined');
var DomComponents = require('DomComponents');
var Component = require('DomComponents/model/Component');
var CssComposer = require('CssComposer');
module.exports = {
run : function(){
var comp;
describe('HtmlGenerator', function() {
beforeEach(function () {
this.obj = new HtmlGenerator();
var dcomp = new DomComponents();
comp = new Component({}, {
defaultTypes: dcomp.componentTypes,
});
});
afterEach(function () {
delete this.obj;
});
it('Build correctly one component', function() {
this.obj.build(comp).should.equal('');
});
it('Build correctly empty component inside', function() {
var m1 = comp.get('components').add({});
this.obj.build(comp).should.equal('<div></div>');
});
it('Build correctly not empty component inside', function() {
var m1 = comp.get('components').add({
tagName: 'article',
attributes: {
'data-test1': 'value1',
'data-test2': 'value2'
}
});
this.obj.build(comp).should.equal('<article data-test1="value1" data-test2="value2"></article>');
});
it('Build correctly component with classes', function() {
var m1 = comp.get('components').add({
tagName: 'article',
attributes: {
'data-test1': 'value1',
'data-test2': 'value2'
}
});
['class1', 'class2'].forEach(function(item){
m1.get('classes').add({name: item});
});
this.obj.build(comp).should.equal('<article class="class1 class2" data-test1="value1" data-test2="value2"></article>');
});
});
describe('CssGenerator', function() {
var newCssComp = function(){
return new CssComposer().init();
};
beforeEach(function () {
this.obj = new CssGenerator();
var dcomp = new DomComponents();
comp = new Component({}, {
defaultTypes: dcomp.componentTypes,
});
});
afterEach(function () {
delete this.obj;
});
it('Build correctly one component', function() {
this.obj.build(comp).should.equal('');
});
it('Build correctly empty component inside', function() {
var m1 = comp.get('components').add({tagName: 'article'});
this.obj.build(comp).should.equal('');
});
it('Build correctly component with style inside', function() {
var m1 = comp.get('components').add({
tagName: 'article',
style: {
'prop1': 'value1',
'prop2': 'value2'
}
});
this.obj.build(comp).should.equal('#' + m1.cid +'{prop1:value1;prop2:value2;}');
});
it('Build correctly component with class styled', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cssc = newCssComp();
var rule = cssc.add(cls1);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
this.obj.build(comp, cssc).should.equal('.class1{prop1:value1;prop2:value2;}');
});
it('Build correctly component styled with class and state', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cssc = newCssComp();
var rule = cssc.add(cls1);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('state', 'hover');
this.obj.build(comp, cssc).should.equal('.class1:hover{prop1:value1;prop2:value2;}');
});
it('Build correctly with more classes', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
this.obj.build(comp, cssc).should.equal('.class1.class2{prop1:value1;prop2:value2;}');
});
it('Build rules with mixed classes', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('selectorsAdd', '.class1 .class2, div > .class4');
this.obj.build(comp, cssc).should.equal('.class1.class2, .class1 .class2, div > .class4{prop1:value1;prop2:value2;}');
});
it('Build rules with only not class based selectors', function() {
var cssc = newCssComp();
var rule = cssc.add([]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('selectorsAdd', '.class1 .class2, div > .class4');
this.obj.build(comp, cssc).should.equal('.class1 .class2, div > .class4{prop1:value1;prop2:value2;}');
});
it('Build correctly with class styled out', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
var rule2 = cssc.add(cls2);
rule2.set('style',{'prop2':'value2'});
this.obj.build(comp, cssc).should.equal('.class1.class2{prop1:value1;}.class2{prop2:value2;}');
});
it('Rule with media query', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
rule.set('mediaText', '(max-width: 999px)');
this.obj.build(comp, cssc).should.equal('@media (max-width: 999px){.class1.class2{prop1:value1;}}');
});
it('Rules mixed with media queries', function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
var rule2 = cssc.add(cls2);
rule2.set('style',{'prop2':'value2'});
var rule3 = cssc.add(cls1, '', '(max-width: 999px)');
rule3.set('style',{'prop3':'value3'});
var rule4 = cssc.add(cls2, '', '(max-width: 999px)');
rule4.set('style',{'prop4':'value4'});
var rule5 = cssc.add(cls1, '', '(max-width: 100px)');
rule5.set('style',{'prop5':'value5'});
this.obj.build(comp, cssc).should.equal('.class1.class2{prop1:value1;}.class2{prop2:value2;}'+
'@media (max-width: 999px){.class1{prop3:value3;}.class2{prop4:value4;}}'+
'@media (max-width: 100px){.class1{prop5:value5;}}');
});
it("Avoid useless code", function() {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cssc = newCssComp();
var rule = cssc.add(cls1);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
comp.get('components').remove(m1);
this.obj.build(comp, cssc).should.equal('');
});
})
}
};
});
const CssGenerator = require('code_manager/model/CssGenerator');
const HtmlGenerator = require('code_manager/model/HtmlGenerator');
const DomComponents = require('dom_components');
const Component = require('dom_components/model/Component');
const CssComposer = require('css_composer');
module.exports = {
run() {
let comp;
let obj;
describe('HtmlGenerator', () => {
beforeEach(() => {
obj = new HtmlGenerator();
var dcomp = new DomComponents();
comp = new Component({}, {
defaultTypes: dcomp.componentTypes,
});
});
afterEach(() => {
obj = null;
});
it('Build correctly one component', () => {
expect(obj.build(comp)).toEqual('');
});
it('Build correctly empty component inside', () => {
var m1 = comp.get('components').add({});
expect(obj.build(comp)).toEqual('<div></div>');
});
it('Build correctly not empty component inside', () => {
var m1 = comp.get('components').add({
tagName: 'article',
attributes: {
'data-test1': 'value1',
'data-test2': 'value2'
}
});
expect(obj.build(comp)).toEqual('<article data-test1="value1" data-test2="value2"></article>');
});
it('Build correctly component with classes', () => {
var m1 = comp.get('components').add({
tagName: 'article',
attributes: {
'data-test1': 'value1',
'data-test2': 'value2'
}
});
['class1', 'class2'].forEach(item => {
m1.get('classes').add({name: item});
});
expect(obj.build(comp)).toEqual('<article class="class1 class2" data-test1="value1" data-test2="value2"></article>');
});
});
describe('CssGenerator', () => {
var newCssComp = () => new CssComposer().init();
beforeEach(() => {
obj = new CssGenerator();
var dcomp = new DomComponents();
comp = new Component({}, {
defaultTypes: dcomp.componentTypes,
});
});
afterEach(() => {
obj = null;
});
it('Build correctly one component', () => {
expect(obj.build(comp)).toEqual('');
});
it('Build correctly empty component inside', () => {
var m1 = comp.get('components').add({tagName: 'article'});
expect(obj.build(comp)).toEqual('');
});
it('Build correctly component with style inside', () => {
var m1 = comp.get('components').add({
tagName: 'article',
style: {
'prop1': 'value1',
'prop2': 'value2'
}
});
expect(obj.build(comp)).toEqual('#' + m1.cid +'{prop1:value1;prop2:value2;}');
});
it('Build correctly component with class styled', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cssc = newCssComp();
var rule = cssc.add(cls1);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
expect(obj.build(comp, cssc)).toEqual('.class1{prop1:value1;prop2:value2;}');
});
it('Build correctly component styled with class and state', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cssc = newCssComp();
var rule = cssc.add(cls1);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('state', 'hover');
expect(obj.build(comp, cssc)).toEqual('.class1:hover{prop1:value1;prop2:value2;}');
});
it('Build correctly with more classes', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
expect(obj.build(comp, cssc)).toEqual('.class1.class2{prop1:value1;prop2:value2;}');
});
it('Build rules with mixed classes', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('selectorsAdd', '.class1 .class2, div > .class4');
expect(obj.build(comp, cssc)).toEqual('.class1.class2, .class1 .class2, div > .class4{prop1:value1;prop2:value2;}');
});
it('Build rules with only not class based selectors', () => {
var cssc = newCssComp();
var rule = cssc.add([]);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
rule.set('selectorsAdd', '.class1 .class2, div > .class4');
expect(obj.build(comp, cssc)).toEqual('.class1 .class2, div > .class4{prop1:value1;prop2:value2;}');
});
it('Build correctly with class styled out', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
var rule2 = cssc.add(cls2);
rule2.set('style',{'prop2':'value2'});
expect(obj.build(comp, cssc)).toEqual('.class1.class2{prop1:value1;}.class2{prop2:value2;}');
});
it('Rule with media query', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
rule.set('mediaText', '(max-width: 999px)');
expect(obj.build(comp, cssc)).toEqual('@media (max-width: 999px){.class1.class2{prop1:value1;}}');
});
it('Rules mixed with media queries', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cls2 = m1.get('classes').add({name: 'class2'});
var cssc = newCssComp();
var rule = cssc.add([cls1, cls2]);
rule.set('style',{'prop1':'value1'});
var rule2 = cssc.add(cls2);
rule2.set('style',{'prop2':'value2'});
var rule3 = cssc.add(cls1, '', '(max-width: 999px)');
rule3.set('style',{'prop3':'value3'});
var rule4 = cssc.add(cls2, '', '(max-width: 999px)');
rule4.set('style',{'prop4':'value4'});
var rule5 = cssc.add(cls1, '', '(max-width: 100px)');
rule5.set('style',{'prop5':'value5'});
expect(obj.build(comp, cssc)).toEqual('.class1.class2{prop1:value1;}.class2{prop2:value2;}'+
'@media (max-width: 999px){.class1{prop3:value3;}.class2{prop4:value4;}}'+
'@media (max-width: 100px){.class1{prop5:value5;}}');
});
it('Avoid useless code', () => {
var m1 = comp.get('components').add({tagName: 'article'});
var cls1 = m1.get('classes').add({name: 'class1'});
var cssc = newCssComp();
var rule = cssc.add(cls1);
rule.set('style',{'prop1':'value1', 'prop2':'value2'});
comp.get('components').remove(m1);
expect(obj.build(comp, cssc)).toEqual('');
});
})
}
};

41
test/specs/commands/index.js

@ -0,0 +1,41 @@
var Commands = require('commands');
var Models = require('./model/CommandModels');
describe('Commands', () => {
describe('Main', () => {
let obj;
beforeEach(() => {
obj = new Commands().init();
});
afterEach(() => {
obj = null;
});
it('No commands inside', () => {
expect(obj.get('test')).toEqual(null);
});
it('Push new command', () => {
var comm = { test: 'test'};
obj.add('test', comm);
expect(obj.get('test').test).toEqual('test');
});
it('No default commands at init', () => {
expect(obj.get('select-comp')).toEqual(null);
});
it('Default commands after loadDefaultCommands', () => {
obj.loadDefaultCommands();
expect(obj.get('select-comp')).toNotEqual(null);
});
});
});
Models.run();

44
test/specs/commands/main.js

@ -1,44 +0,0 @@
define(function(require, exports, module){
'use strict';
var Commands = require('Commands');
var Models = require('undefined');
describe('Commands', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new Commands().init();
});
afterEach(function () {
delete obj;
});
it('No commands inside', function() {
(obj.get('test') == null).should.equal(true);
});
it('Push new command', function() {
var comm = { test: 'test'};
obj.add('test', comm);
(obj.get('test').test == 'test').should.equal(true);
});
it('No default commands at init', function() {
(obj.get('select-comp') == null).should.equal(true);
});
it('Default commands after loadDefaultCommands', function() {
obj.loadDefaultCommands();
(obj.get('select-comp') == null).should.equal(false);
});
});
});
Models.run();
});

63
test/specs/commands/model/CommandModels.js

@ -1,44 +1,41 @@
define(function(require, exports, module){
'use strict';
var Commands = require('undefined');
const Command = require('commands/model/Command');
const Commands = require('commands');
module.exports = {
run : function(){
describe('Command', function() {
var obj;
module.exports = {
run() {
describe('Command', () => {
let obj;
beforeEach(function () {
obj = new Command();
});
beforeEach(() => {
obj = new Command();
});
afterEach(function () {
delete obj;
});
afterEach(() => {
obj = null;
});
it('Has id property', function() {
obj.has('id').should.equal(true);
});
it('Has id property', () => {
expect(obj.has('id')).toEqual(true);
});
});
});
describe('Commands', function() {
var obj;
describe('Commands', () => {
var obj;
beforeEach(function () {
obj = new Commands();
});
beforeEach(() => {
obj = new Commands();
});
afterEach(function () {
delete obj;
});
afterEach(() => {
obj = null;
});
it('Object is ok', function() {
obj.should.be.ok;
});
it('Object is ok', () => {
expect(obj).toExist();
});
});
});
}
};
});
}
};

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

@ -1,208 +1,201 @@
define(function(require, exports, module){
'use strict';
var GrapesJS = require('GrapesJS');
module.exports = {
run : function(){
describe('E2E tests', function() {
var fixtures;
var fixture;
var grapesjs;
var gjs;
var cssc, clsm, domc;
var rulesSet;
var rulesSet2;
before(function () {
fixtures = $("#fixtures");
fixture = $('<div class="csscomposer-fixture"></div>');
});
beforeEach(function () {
grapesjs = GrapesJS;
gjs = grapesjs.init({
stylePrefix: '',
storageManager: { autoload: 0, type:'none' },
assetManager: { storageType: 'none', },
container: 'csscomposer-fixture',
});
cssc = gjs.CssComposer;
clsm = gjs.SelectorManager;
domc = gjs.DomComponents;
fixture.empty().appendTo(fixtures);
gjs.render();
rulesSet = [
{ selectors: [{name: 'test1'}, {name: 'test2'}] },
{ selectors: [{name: 'test2'}, {name: 'test3'}] },
{ selectors: [{name: 'test3'}] }
];
rulesSet2 = [
{ selectors: [{name: 'test1'}, {name: 'test2'}], state:':active' },
{ selectors: [{name: 'test2'}, {name: 'test3'}] },
{ selectors: [{name: 'test3'}], mediaText:'(max-width: 900px)' }
];
});
afterEach(function () {
delete grapesjs;
delete gjs;
delete cssc;
delete clsm;
});
module.exports = {
run() {
describe('E2E tests', () => {
var fixtures;
var fixture;
var gjs;
var cssc;
var clsm;
var domc;
var rulesSet;
var rulesSet2;
before(() => {
fixtures = $("#fixtures");
fixture = $('<div class="csscomposer-fixture"></div>');
});
after(function () {
fixture.remove();
});
beforeEach(done => {
//this.timeout(5000);
gjs = grapesjs.init({
stylePrefix: '',
storageManager: { autoload: 0, type:'none' },
assetManager: { storageType: 'none', },
container: 'csscomposer-fixture',
});
cssc = gjs.CssComposer;
clsm = gjs.SelectorManager;
domc = gjs.DomComponents;
fixture.empty().appendTo(fixtures);
gjs.render();
rulesSet = [
{ selectors: [{name: 'test1'}, {name: 'test2'}] },
{ selectors: [{name: 'test2'}, {name: 'test3'}] },
{ selectors: [{name: 'test3'}] }
];
rulesSet2 = [
{ selectors: [{name: 'test1'}, {name: 'test2'}], state:':active' },
{ selectors: [{name: 'test2'}, {name: 'test3'}] },
{ selectors: [{name: 'test3'}], mediaText:'(max-width: 900px)' }
];
done();
});
it('Rules are correctly imported from default property', function() {
var gj = new grapesjs.init({
stylePrefix: '',
storageManager: { autoload: 0, type:'none' },
assetManager: { storageType: 'none', },
cssComposer: { rules: rulesSet},
container: 'csscomposer-fixture',
});
var cssc = gj.editor.get('CssComposer');
cssc.getAll().length.should.equal(rulesSet.length);
var cls = gj.editor.get('SelectorManager').getAll();
cls.length.should.equal(3);
});
afterEach(() => {
gjs = null;
cssc = null;
clsm = null;
});
after(() => {
fixture.remove();
});
it('New rule adds correctly the class inside selector manager', function() {
var rules = cssc.getAll();
rules.add({ selectors: [{name: 'test1'}] });
clsm.getAll().at(0).get('name').should.equal('test1');
});
it('Rules are correctly imported from default property', () => {
var gj = grapesjs.init({
stylePrefix: '',
storageManager: { autoload: 0, type:'none' },
assetManager: { storageType: 'none', },
cssComposer: { rules: rulesSet},
container: 'csscomposer-fixture',
});
var cssc = gj.editor.get('CssComposer');
expect(cssc.getAll().length).toEqual(rulesSet.length);
var cls = gj.editor.get('SelectorManager').getAll();
expect(cls.length).toEqual(3);
});
it('New rules are correctly imported inside selector manager', function() {
var rules = cssc.getAll();
rulesSet.forEach(function(item){
rules.add(item);
});
var cls = clsm.getAll();
cls.length.should.equal(3);
cls.at(0).get('name').should.equal('test1');
cls.at(1).get('name').should.equal('test2');
cls.at(2).get('name').should.equal('test3');
});
it('Add rules from the new component added as a string with style tag', function() {
var comps = domc.getComponents();
var rules = cssc.getAll();
comps.add("<div>Test</div><style>.test{color: red} .test2{color: blue}</style>");
comps.length.should.equal(1);
rules.length.should.equal(2);
});
it('New rule adds correctly the class inside selector manager', () => {
var rules = cssc.getAll();
rules.add({ selectors: [{name: 'test1'}] });
expect(clsm.getAll().at(0).get('name')).toEqual('test1');
});
it('Add raw rule objects with addCollection', function() {
cssc.addCollection(rulesSet);
cssc.getAll().length.should.equal(3);
clsm.getAll().length.should.equal(3);
});
it('New rules are correctly imported inside selector manager', () => {
var rules = cssc.getAll();
rulesSet.forEach(item => {
rules.add(item);
});
var cls = clsm.getAll();
expect(cls.length).toEqual(3);
expect(cls.at(0).get('name')).toEqual('test1');
expect(cls.at(1).get('name')).toEqual('test2');
expect(cls.at(2).get('name')).toEqual('test3');
});
it('Add raw rule objects twice with addCollection do not duplucate rules', function() {
var rulesSet2Copy = JSON.parse(JSON.stringify(rulesSet2));
var coll1 = cssc.addCollection(rulesSet2);
var coll2 = cssc.addCollection(rulesSet2Copy);
cssc.getAll().length.should.equal(3);
clsm.getAll().length.should.equal(3);
coll1.should.deep.equal(coll2);
});
it('Add rules from the new component added as a string with style tag', () => {
var comps = domc.getComponents();
var rules = cssc.getAll();
comps.add("<div>Test</div><style>.test{color: red} .test2{color: blue}</style>");
expect(comps.length).toEqual(1);
expect(rules.length).toEqual(2);
});
it("Extend css rule style, if requested", function() {
var style1 = {color: 'red', width: '10px'};
var style2 = {height: '20px', width: '20px'};
var rule1 = {
selectors: ['test1'],
style: style1,
};
var rule2 = {
selectors: ['test1'],
style: style2,
};
var ruleOut = cssc.addCollection(rule1)[0];
// ruleOut is a Model
ruleOut = JSON.parse(JSON.stringify(ruleOut));
var ruleResult = {
mediaText: '',
selectors: [{
active: true,
label: 'test1',
name: 'test1',
type: 'class',
}],
selectorsAdd: '',
state: '',
stylable: true,
style: {
color: 'red',
width: '10px'
}
};
ruleOut.should.deep.equal(ruleResult);
var ruleOut = cssc.addCollection(rule2, {extend: 1})[0];
ruleOut = JSON.parse(JSON.stringify(ruleOut));
ruleResult.style = {
color: 'red',
height: '20px',
width: '20px',
}
ruleOut.should.deep.equal(ruleResult);
it('Add raw rule objects with addCollection', () => {
cssc.addCollection(rulesSet);
expect(cssc.getAll().length).toEqual(3);
expect(clsm.getAll().length).toEqual(3);
});
});
it('Add raw rule objects twice with addCollection do not duplucate rules', () => {
var rulesSet2Copy = JSON.parse(JSON.stringify(rulesSet2));
var coll1 = cssc.addCollection(rulesSet2);
var coll2 = cssc.addCollection(rulesSet2Copy);
expect(cssc.getAll().length).toEqual(3);
expect(clsm.getAll().length).toEqual(3);
expect(coll1).toEqual(coll2);
});
it("Do not extend with different selectorsAdd", function() {
var style1 = {color: 'red', width: '10px'};
var style2 = {height: '20px', width: '20px'};
var rule1 = {
selectors: [],
selectorsAdd: '*',
style: style1,
};
var rule2 = {
selectors: [],
selectorsAdd: 'p',
style: style2,
};
var rule1Out = cssc.addCollection(rule1, {extend: 1})[0];
var rule2Out = cssc.addCollection(rule2, {extend: 1})[0];
rule1Out = JSON.parse(JSON.stringify(rule1Out));
rule2Out = JSON.parse(JSON.stringify(rule2Out));
var rule1Result = {
mediaText: '',
selectors: [],
selectorsAdd: '*',
state: '',
stylable: true,
style: {
color: 'red',
width: '10px'
}
};
var rule2Result = {
mediaText: '',
selectors: [],
selectorsAdd: 'p',
state: '',
stylable: true,
style: {
height: '20px',
width: '20px',
}
};
rule1Out.should.deep.equal(rule1Result);
rule2Out.should.deep.equal(rule2Result);
});
it("Extend css rule style, if requested", () => {
var style1 = {color: 'red', width: '10px'};
var style2 = {height: '20px', width: '20px'};
var rule1 = {
selectors: ['test1'],
style: style1,
};
var rule2 = {
selectors: ['test1'],
style: style2,
};
var ruleOut = cssc.addCollection(rule1)[0];
// ruleOut is a Model
ruleOut = JSON.parse(JSON.stringify(ruleOut));
var ruleResult = {
mediaText: '',
selectors: [{
active: true,
label: 'test1',
name: 'test1',
type: 'class',
}],
selectorsAdd: '',
state: '',
stylable: true,
style: {
color: 'red',
width: '10px'
}
};
expect(ruleOut).toEqual(ruleResult);
var ruleOut = cssc.addCollection(rule2, {extend: 1})[0];
ruleOut = JSON.parse(JSON.stringify(ruleOut));
ruleResult.style = {
color: 'red',
height: '20px',
width: '20px',
}
expect(ruleOut).toEqual(ruleResult);
it('Add raw rule objects with width via addCollection', function() {
var coll1 = cssc.addCollection(rulesSet2);
coll1[2].get('mediaText').should.equal(rulesSet2[2].mediaText);
});
});
it("Do not extend with different selectorsAdd", () => {
var style1 = {color: 'red', width: '10px'};
var style2 = {height: '20px', width: '20px'};
var rule1 = {
selectors: [],
selectorsAdd: '*',
style: style1,
};
var rule2 = {
selectors: [],
selectorsAdd: 'p',
style: style2,
};
var rule1Out = cssc.addCollection(rule1, {extend: 1})[0];
var rule2Out = cssc.addCollection(rule2, {extend: 1})[0];
rule1Out = JSON.parse(JSON.stringify(rule1Out));
rule2Out = JSON.parse(JSON.stringify(rule2Out));
var rule1Result = {
mediaText: '',
selectors: [],
selectorsAdd: '*',
state: '',
stylable: true,
style: {
color: 'red',
width: '10px'
}
};
var rule2Result = {
mediaText: '',
selectors: [],
selectorsAdd: 'p',
state: '',
stylable: true,
style: {
height: '20px',
width: '20px',
}
};
expect(rule1Out).toEqual(rule1Result);
expect(rule2Out).toEqual(rule2Result);
});
}
};
});
it('Add raw rule objects with width via addCollection', () => {
var coll1 = cssc.addCollection(rulesSet2);
expect(coll1[2].get('mediaText')).toEqual(rulesSet2[2].mediaText);
});
});
}
};

167
test/specs/css_composer/index.js

@ -0,0 +1,167 @@
var Models = require('./model/CssModels');
var CssRuleView = require('./view/CssRuleView');
var CssRulesView = require('./view/CssRulesView');
var CssComposer = require('css_composer');
var e2e = require('./e2e/CssComposer');
var utils = require('./../test_utils.js');
describe('Css Composer', () => {
describe('Main', () => {
var obj;
var config;
var storagMock = utils.storageMock();
var editorModel = {
getCss() {return 'testCss';},
getCacheLoad() {
return storagMock.load();
}
};
var setSmConfig = () => {
config.stm = storagMock;
config.stm.getConfig = () => ({
storeCss: 1,
storeStyles: 1
});
};
var setEm = () => {
config.em = editorModel;
}
beforeEach(() => {
config = {};
obj = new CssComposer().init(config);
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(CssComposer).toExist();
});
it('storageKey returns array', () => {
expect(obj.storageKey() instanceof Array).toEqual(true);
});
it('storageKey returns correct composition', () => {
setSmConfig();
expect(obj.storageKey()).toEqual(['css', 'styles']);
});
it('Store data', () => {
setSmConfig();
setEm();
var expected = { css: 'testCss', styles: '[]',};
expect(obj.store(1)).toEqual(expected);
});
it("Rules are empty", () => {
expect(obj.getAll().length).toEqual(0);
});
it('Create new rule with correct selectors', () => {
var sel = new obj.Selectors();
var s1 = sel.add({name: 'test1'});
var rule = obj.add(sel.models);
expect(rule.get('selectors').at(0)).toEqual(s1);
});
it('Create new rule correctly', () => {
var sel = new obj.Selectors();
var s1 = sel.add({name: 'test1'});
var rule = obj.add(sel.models, 'state1', 'width1');
expect(rule.get('state')).toEqual('state1');
expect(rule.get('mediaText')).toEqual('width1');
});
it("Add rule to collection", () => {
var sel = new obj.Selectors([{name: 'test1'}]);
var rule = obj.add(sel.models);
expect(obj.getAll().length).toEqual(1);
expect(obj.getAll().at(0).get('selectors').at(0).get('name')).toEqual('test1');
});
it("Returns correct rule with the same selector", () => {
var sel = new obj.Selectors([{name: 'test1'}]);
var rule1 = obj.add(sel.models);
var rule2 = obj.get(sel.models);
expect(rule1).toEqual(rule2);
});
it("Returns correct rule with the same selectors", () => {
var sel1 = new obj.Selectors([{name: 'test1'}]);
var rule1 = obj.add(sel1.models);
var sel2 = new obj.Selectors([{name: 'test21'}, {name: 'test22'}]);
var rule2 = obj.add(sel2.models);
var rule3 = obj.get(sel2.models);
expect(rule3).toEqual(rule2);
});
it("Do not create multiple rules with the same name selectors", () => {
var sel1 = new obj.Selectors([{name: 'test21'}, {name: 'test22'}]);
var rule1 = obj.add(sel1.models);
var sel2 = new obj.Selectors([{name: 'test22'}, {name: 'test21'}]);
var rule2 = obj.add(sel2.models);
expect(rule2).toEqual(rule1);
});
it("Don't duplicate rules", () => {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var s2 = sel.add({name: 'test2'});
var s3 = sel.add({name: 'test3'});
var rule1 = obj.add([s1, s3]);
var rule2 = obj.add([s3, s1]);
expect(rule2).toEqual(rule1);
});
it("Returns correct rule with the same mixed selectors", () => {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var s2 = sel.add({name: 'test2'});
var s3 = sel.add({name: 'test3'});
var rule1 = obj.add([s1, s3]);
var rule2 = obj.get([s3, s1]);
expect(rule2).toEqual(rule1);
});
it("Returns correct rule with the same selectors and state", () => {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var s2 = sel.add({name: 'test2'});
var s3 = sel.add({name: 'test3'});
var rule1 = obj.add([s1, s3], 'hover');
var rule2 = obj.get([s3, s1], 'hover');
expect(rule2).toEqual(rule1);
});
it("Returns correct rule with the same selectors, state and width", () => {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var rule1 = obj.add([s1], 'hover','1');
var rule2 = obj.get([s1], 'hover', '1');
expect(rule2).toEqual(rule1);
});
it("Renders correctly", () => {
expect(obj.render()).toExist();
});
});
Models.run();
CssRuleView.run();
CssRulesView.run();
e2e.run();
});

167
test/specs/css_composer/main.js

@ -1,167 +0,0 @@
define(function(require, exports, module){
'use strict';
var CssComposer = require('CssComposer');
var e2e = require('undefined');
var utils = require('./../test_utils.js');
describe('Css Composer', function() {
describe('Main', function() {
var obj;
var config;
var storagMock = utils.storageMock();
var editorModel = {
getCss: function(){return 'testCss';},
getCacheLoad: function(){
return storagMock.load();
}
};
var setSmConfig = function(){
config.stm = storagMock;
config.stm.getConfig = function(){
return { storeCss: 1, storeStyles: 1}
};
};
var setEm = function(){
config.em = editorModel;
}
beforeEach(function () {
config = {};
obj = new CssComposer().init(config);
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
CssComposer.should.be.exist;
});
it('storageKey returns array', function() {
obj.storageKey().should.be.instanceOf(Array);
});
it('storageKey returns correct composition', function() {
setSmConfig();
obj.storageKey().should.eql(['css', 'styles']);
});
it('Store data', function() {
setSmConfig();
setEm();
var expected = { css: 'testCss', styles: '[]',};
obj.store(1).should.deep.equal(expected);
});
it("Rules are empty", function() {
obj.getAll().length.should.equal(0);
});
it('Create new rule with correct selectors', function() {
var sel = new obj.Selectors();
var s1 = sel.add({name: 'test1'});
var rule = obj.add(sel.models);
rule.get('selectors').at(0).should.deep.equal(s1);
});
it('Create new rule correctly', function() {
var sel = new obj.Selectors();
var s1 = sel.add({name: 'test1'});
var rule = obj.add(sel.models, 'state1', 'width1');
rule.get('state').should.equal('state1');
rule.get('mediaText').should.equal('width1');
});
it("Add rule to collection", function() {
var sel = new obj.Selectors([{name: 'test1'}]);
var rule = obj.add(sel.models);
obj.getAll().length.should.equal(1);
obj.getAll().at(0).get('selectors').at(0).get('name').should.equal('test1');
});
it("Returns correct rule with the same selector", function() {
var sel = new obj.Selectors([{name: 'test1'}]);
var rule1 = obj.add(sel.models);
var rule2 = obj.get(sel.models);
rule1.should.deep.equal(rule2);
});
it("Returns correct rule with the same selectors", function() {
var sel1 = new obj.Selectors([{name: 'test1'}]);
var rule1 = obj.add(sel1.models);
var sel2 = new obj.Selectors([{name: 'test21'}, {name: 'test22'}]);
var rule2 = obj.add(sel2.models);
var rule3 = obj.get(sel2.models);
rule3.should.deep.equal(rule2);
});
it("Do not create multiple rules with the same name selectors", function() {
var sel1 = new obj.Selectors([{name: 'test21'}, {name: 'test22'}]);
var rule1 = obj.add(sel1.models);
var sel2 = new obj.Selectors([{name: 'test22'}, {name: 'test21'}]);
var rule2 = obj.add(sel2.models);
rule2.should.deep.equal(rule1);
});
it("Don't duplicate rules", function() {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var s2 = sel.add({name: 'test2'});
var s3 = sel.add({name: 'test3'});
var rule1 = obj.add([s1, s3]);
var rule2 = obj.add([s3, s1]);
rule2.should.deep.equal(rule1);
});
it("Returns correct rule with the same mixed selectors", function() {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var s2 = sel.add({name: 'test2'});
var s3 = sel.add({name: 'test3'});
var rule1 = obj.add([s1, s3]);
var rule2 = obj.get([s3, s1]);
rule2.should.deep.equal(rule1);
});
it("Returns correct rule with the same selectors and state", function() {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var s2 = sel.add({name: 'test2'});
var s3 = sel.add({name: 'test3'});
var rule1 = obj.add([s1, s3], 'hover');
var rule2 = obj.get([s3, s1], 'hover');
rule2.should.deep.equal(rule1);
});
it("Returns correct rule with the same selectors, state and width", function() {
var sel = new obj.Selectors([]);
var s1 = sel.add({name: 'test1'});
var rule1 = obj.add([s1], 'hover','1');
var rule2 = obj.get([s1], 'hover', '1');
rule2.should.deep.equal(rule1);
});
it("Renders correctly", function() {
obj.render().should.be.ok;
});
});
Models.run();
CssRuleView.run();
CssRulesView.run();
e2e.run();
});
});

141
test/specs/css_composer/model/CssModels.js

@ -1,82 +1,81 @@
define(function(require, exports, module){
'use strict';
var Selectors = require('undefined');
var Selector = require('SelectorManager/model/Selector');
module.exports = {
run : function(){
describe('CssRule', function() {
beforeEach(function () {
this.obj = new CssRule();
});
afterEach(function () {
delete this.obj;
});
it('Has selectors property', function() {
this.obj.has('selectors').should.equal(true);
});
it('Has style property', function() {
this.obj.has('style').should.equal(true);
});
it('Has state property', function() {
this.obj.has('state').should.equal(true);
});
it('No default selectors', function() {
this.obj.get('selectors').length.should.equal(0);
});
it('Compare returns true with the same selectors', function() {
var s1 = this.obj.get('selectors').add({ name: 'test1' });
var s2 = this.obj.get('selectors').add({ name: 'test2' });
this.obj.compare([s1, s2]).should.equal(true);
});
it('Compare with different state', function() {
var s1 = this.obj.get('selectors').add({ name: 'test1' });
var s2 = this.obj.get('selectors').add({ name: 'test2' });
this.obj.set('state','hover');
this.obj.compare([s1, s2]).should.equal(false);
this.obj.compare([s1, s2], 'hover').should.equal(true);
});
it('Compare with different mediaText', function() {
var s1 = this.obj.get('selectors').add({ name: 'test1' });
var s2 = this.obj.get('selectors').add({ name: 'test2' });
this.obj.set('state','hover');
this.obj.set('mediaText','1000');
this.obj.compare([s1, s2]).should.equal(false);
this.obj.compare([s1, s2], 'hover').should.equal(false);
this.obj.compare([s2, s1], 'hover', '1000').should.equal(true);
});
var CssRule = require('css_composer/model/CssRule');
var CssRules = require('css_composer/model/CssRules');
var Selectors = require('selector_manager/model/Selectors');
var Selector = require('selector_manager/model/Selector');
module.exports = {
run() {
describe('CssRule', () => {
let obj;
beforeEach(() => {
obj = new CssRule();
});
afterEach(() => {
obj = null;
});
it('Has selectors property', () => {
expect(obj.has('selectors')).toEqual(true);
});
it('Has style property', () => {
expect(obj.has('style')).toEqual(true);
});
it('Has state property', () => {
expect(obj.has('state')).toEqual(true);
});
it('No default selectors', () => {
expect(obj.get('selectors').length).toEqual(0);
});
it('Compare returns true with the same selectors', () => {
var s1 = obj.get('selectors').add({ name: 'test1' });
var s2 = obj.get('selectors').add({ name: 'test2' });
expect(obj.compare([s1, s2])).toEqual(true);
});
it('Compare with different state', () => {
var s1 = obj.get('selectors').add({ name: 'test1' });
var s2 = obj.get('selectors').add({ name: 'test2' });
obj.set('state','hover');
expect(obj.compare([s1, s2])).toEqual(false);
expect(obj.compare([s1, s2], 'hover')).toEqual(true);
});
it('Compare with different mediaText', () => {
var s1 = obj.get('selectors').add({ name: 'test1' });
var s2 = obj.get('selectors').add({ name: 'test2' });
obj.set('state','hover');
obj.set('mediaText','1000');
expect(obj.compare([s1, s2])).toEqual(false);
expect(obj.compare([s1, s2], 'hover')).toEqual(false);
expect(obj.compare([s2, s1], 'hover', '1000')).toEqual(true);
});
describe('CssRules', function() {
});
it('Creates collection item correctly', function() {
var c = new CssRules();
var m = c.add({});
m.should.be.an.instanceOf(CssRule);
});
describe('CssRules', () => {
it('Creates collection item correctly', () => {
var c = new CssRules();
var m = c.add({});
expect(m instanceof CssRule).toEqual(true);
});
describe('Selectors', function() {
});
it('Creates collection item correctly', function() {
var c = new Selectors();
var m = c.add({});
m.should.be.an.instanceOf(Selector);
});
describe('Selectors', () => {
it('Creates collection item correctly', () => {
var c = new Selectors();
var m = c.add({});
expect(m instanceof Selector).toEqual(true);
});
}
};
});
});
}
};

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

@ -1,121 +1,121 @@
define(function(require, exports, module){
'use strict';
var CssRuleView = require('undefined');
var CssRule = require('CssComposer/model/CssRule');
module.exports = {
run : function(){
describe('CssRuleView', function() {
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="cssrule-fixture"></div>');
});
var CssRuleView = require('css_composer/view/CssRuleView');
var CssRule = require('css_composer/model/CssRule');
beforeEach(function () {
var m = new CssRule();
this.view = new CssRuleView({
model: m
});
this.$fixture.empty().appendTo(this.$fixtures);
this.$fixture.html(this.view.render().el);
});
module.exports = {
run() {
describe('CssRuleView', () => {
afterEach(function () {
this.view.model.destroy();
});
let obj;
after(function () {
this.$fixture.remove();
});
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="cssrule-fixture"></div>');
});
it('Object exists', function() {
CssRuleView.should.be.exist;
});
beforeEach(function () {
var m = new CssRule();
obj = new CssRuleView({
model: m
});
this.$fixture.empty().appendTo(this.$fixtures);
this.$fixture.html(obj.render().el);
});
it('Correct behaviour of renderSelectors with single selector', function() {
this.view.model.get('selectors').add({name: 'test'});
this.view.renderSelectors().should.equal('.test');
});
afterEach(() => {
obj.model.destroy();
});
it('Correct behaviour of renderSelectors with multiple selectors', function() {
this.view.model.get('selectors').add([{name: 'test2'}, {name: 'test1'}]);
this.view.renderSelectors().should.equal('.test2.test1');
});
after(function () {
this.$fixture.remove();
});
it('Correct behaviour of renderProperties with single property', function() {
this.view.model.set('style', {'prop': 'value'});
this.view.renderProperties().should.equal('prop:value;');
});
it('Object exists', () => {
expect(CssRuleView).toExist();
});
it('Correct behaviour of renderProperties with multiple properties', function() {
this.view.model.set('style', {'prop2': 'value2', 'prop3': 'value3'});
this.view.renderProperties().should.equal('prop2:value2;prop3:value3;');
});
it('Correct behaviour of renderSelectors with single selector', () => {
obj.model.get('selectors').add({name: 'test'});
expect(obj.renderSelectors()).toEqual('.test');
});
it('Empty style inside', function() {
this.$fixture.html().should.equal('<style></style>');
});
it('Correct behaviour of renderSelectors with multiple selectors', () => {
obj.model.get('selectors').add([{name: 'test2'}, {name: 'test1'}]);
expect(obj.renderSelectors()).toEqual('.test2.test1');
});
it('On update of style always empty as there is no selectors', function() {
this.view.model.set('style', {'prop':'value'});
this.$fixture.html().should.equal('<style></style>');
});
it('Correct behaviour of renderProperties with single property', () => {
obj.model.set('style', {'prop': 'value'});
expect(obj.renderProperties()).toEqual('prop:value;');
});
describe('CssRuleView with selectors', function() {
beforeEach(function () {
var m = new CssRule({
selectors: [{name:'test1'}, {name:'test2'}]
});
this.regView = new CssRuleView({
model: m
});
this.regView.render();
});
afterEach(function () {
this.regView.model.destroy();
});
it('Empty with no style', function() {
this.regView.$el.html().should.equal('');
});
it('Not empty on update of style', function() {
this.regView.model.set('style', {'prop':'value'});
this.regView.$el.html().should.equal('.test1.test2{prop:value;}');
});
it('State correctly rendered', function() {
this.regView.model.set('style', {'prop':'value'});
this.regView.model.set('state', 'hover');
this.regView.$el.html().should.equal('.test1.test2:hover{prop:value;}');
});
it('State render changes on update', function() {
this.regView.model.set('style', {'prop':'value'});
this.regView.model.set('state', 'hover');
this.regView.model.set('state', '');
this.regView.$el.html().should.equal('.test1.test2{prop:value;}');
});
it('Render media queries', function() {
this.regView.model.set('style', {'prop':'value'});
this.regView.model.set('mediaText', '(max-width: 999px)');
this.regView.$el.html().should.equal('@media (max-width: 999px){.test1.test2{prop:value;}}');
});
it('Empty on clear', function() {
this.regView.model.set('style', {'prop':'value'});
this.regView.model.set('style', {});
this.regView.$el.html().should.equal('');
});
it('Correct behaviour of renderProperties with multiple properties', () => {
obj.model.set('style', {'prop2': 'value2', 'prop3': 'value3'});
expect(obj.renderProperties()).toEqual('prop2:value2;prop3:value3;');
});
it('Empty style inside', function() {
expect(this.$fixture.html()).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>');
});
describe('CssRuleView with selectors', () => {
let objReg;
beforeEach(() => {
var m = new CssRule({
selectors: [{name:'test1'}, {name:'test2'}]
});
objReg = new CssRuleView({
model: m
});
objReg.render();
});
afterEach(() => {
objReg.model.destroy();
});
it('Empty with no style', () => {
expect(objReg.$el.html()).toEqual('');
});
it('Not empty on update of style', () => {
objReg.model.set('style', {'prop':'value'});
expect(objReg.$el.html()).toEqual('.test1.test2{prop:value;}');
});
it('State correctly rendered', () => {
objReg.model.set('style', {'prop':'value'});
objReg.model.set('state', 'hover');
expect(objReg.$el.html()).toEqual('.test1.test2:hover{prop:value;}');
});
it('State render changes on update', () => {
objReg.model.set('style', {'prop':'value'});
objReg.model.set('state', 'hover');
objReg.model.set('state', '');
expect(objReg.$el.html()).toEqual('.test1.test2{prop:value;}');
});
it('Render media queries', () => {
objReg.model.set('style', {'prop':'value'});
objReg.model.set('mediaText', '(max-width: 999px)');
expect(objReg.$el.html()).toEqual('@media (max-width: 999px){.test1.test2{prop:value;}}');
});
it('Empty on clear', () => {
objReg.model.set('style', {'prop':'value'});
objReg.model.set('style', {});
expect(objReg.$el.html()).toEqual('');
});
});
}
};
});
});
}
};

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

@ -1,55 +1,53 @@
define(function(require, exports, module){
'use strict';
var CssRulesView = require('undefined');
var CssRules = require('CssComposer/model/CssRules');
module.exports = {
run : function(){
describe('CssRulesView', function() {
before(function () {
this.$fixtures = $("#fixtures");
this.$fixture = $('<div class="cssrules-fixture"></div>');
});
beforeEach(function () {
var col = new CssRules([]);
this.view = new CssRulesView({
collection: col
});
this.$fixture.empty().appendTo(this.$fixtures);
this.$fixture.html(this.view.render().el);
});
afterEach(function () {
this.view.collection.reset();
});
after(function () {
this.$fixture.remove();
});
it('Object exists', function() {
CssRulesView.should.be.exist;
});
it("Collection is empty", function (){
this.view.$el.html().should.be.empty;
});
it("Add new rule", function (){
sinon.stub(this.view, "addToCollection");
this.view.collection.add({});
this.view.addToCollection.calledOnce.should.equal(true);
});
it("Render new rule", function (){
this.view.collection.add({});
this.view.$el.html().should.not.be.empty;
});
});
}
};
});
var CssRulesView = require('css_composer/view/CssRulesView');
var CssRules = require('css_composer/model/CssRules');
module.exports = {
run() {
describe('CssRulesView', () => {
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);
});
afterEach(() => {
obj.collection.reset();
});
after(function () {
this.$fixture.remove();
});
it('Object exists', () => {
expect(CssRulesView).toExist();
});
it("Collection is empty", () => {
expect(obj.$el.html()).toNotExist();
});
it("Add new rule", () => {
sinon.stub(obj, "addToCollection");
obj.collection.add({});
expect(obj.addToCollection.calledOnce).toExist(true);
});
it("Render new rule", () => {
obj.collection.add({});
expect(obj.$el.html()).toExist();
});
});
}
};

67
test/specs/device_manager/index.js

@ -0,0 +1,67 @@
const DeviceManager = require('device_manager');
const DevicesView = require('./view/DevicesView');
describe('DeviceManager', () => {
describe('Main', () => {
var obj;
var testNameDevice;
var testWidthDevice;
beforeEach(() => {
testNameDevice = 'Tablet';
testWidthDevice = '100px';
obj = new DeviceManager().init();
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(obj).toExist();
});
it('No device inside', () => {
var coll = obj.getAll();
expect(coll.length).toEqual(0);
});
it('Add new device', () => {
var model = obj.add(testNameDevice, testWidthDevice);
expect(obj.getAll().length).toEqual(1);
});
it('Added device has correct data', () => {
var model = obj.add(testNameDevice, testWidthDevice);
expect(model.get('name')).toEqual(testNameDevice);
expect(model.get('width')).toEqual(testWidthDevice);
});
it('Add device width options', () => {
var model = obj.add(testNameDevice, testWidthDevice, {opt: 'value'});
expect(model.get('opt')).toEqual('value');
});
it('The name of the device is unique', () => {
var model = obj.add(testNameDevice, testWidthDevice);
var model2 = obj.add(testNameDevice, '2px');
expect(model).toEqual(model2);
});
it('Get device by name', () => {
var model = obj.add(testNameDevice, testWidthDevice);
var model2 = obj.get(testNameDevice);
expect(model).toEqual(model2);
});
it('Render devices', () => {
expect(obj.render()).toExist();
});
});
DevicesView.run();
});

70
test/specs/device_manager/main.js

@ -1,70 +0,0 @@
define(function(require, exports, module){
'use strict';
var DeviceManager = require('DeviceManager');
var DevicesView = require('undefined');
describe('DeviceManager', function() {
describe('Main', function() {
var obj;
var testNameDevice;
var testWidthDevice;
beforeEach(function () {
testNameDevice = 'Tablet';
testWidthDevice = '100px';
obj = new DeviceManager().init();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
obj.should.be.exist;
});
it('No device inside', function() {
var coll = obj.getAll();
coll.length.should.equal(0);
});
it('Add new device', function() {
var model = obj.add(testNameDevice, testWidthDevice);
obj.getAll().length.should.equal(1);
});
it('Added device has correct data', function() {
var model = obj.add(testNameDevice, testWidthDevice);
model.get('name').should.equal(testNameDevice);
model.get('width').should.equal(testWidthDevice);
});
it('Add device width options', function() {
var model = obj.add(testNameDevice, testWidthDevice, {opt: 'value'});
model.get('opt').should.equal('value');
});
it('The name of the device is unique', function() {
var model = obj.add(testNameDevice, testWidthDevice);
var model2 = obj.add(testNameDevice, '2px');
model.should.deep.equal(model2);
});
it('Get device by name', function() {
var model = obj.add(testNameDevice, testWidthDevice);
var model2 = obj.get(testNameDevice);
model.should.deep.equal(model2);
});
it('Render devices', function() {
obj.render().should.be.ok;
});
});
DevicesView.run();
});
});

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

@ -1,83 +1,79 @@
define(function(require, exports, module){
'use strict';
var DevicesView = require('undefined');
var Devices = require('DeviceManager/model/Devices');
module.exports = {
run : function(){
describe('DevicesView', function() {
var $fixtures;
var $fixture;
var model;
var view;
var editorModel;
const DevicesView = require('device_manager/view/DevicesView');
const Devices = require('device_manager/model/Devices');
module.exports = {
run() {
describe('DevicesView', () => {
var $fixtures;
var $fixture;
var model;
var view;
var editorModel;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="devices-fixture"></div>');
});
before(function () {
$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);
});
beforeEach(function () {
model = new Devices([]);
view = new DevicesView({
collection: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(() => {
view.collection.reset();
});
afterEach(function () {
view.collection.reset();
});
after(() => {
$fixture.remove();
});
after(function () {
$fixture.remove();
});
it("The content is not empty", () => {
expect(view.el.innerHTML).toExist();
});
it("The content is not empty", function (){
view.el.innerHTML.should.be.not.empty;
});
it("No options without devices", () => {
expect(view.getOptions()).toEqual('');
});
it("No options without devices", function (){
view.getOptions().should.equal('');
});
it("Render new button", () => {
view.collection.add({});
expect(view.$el.html()).toExist();
});
it("Render new button", function (){
view.collection.add({});
view.$el.html().should.not.be.empty;
describe('With configs', () => {
beforeEach(() => {
editorModel = new Backbone.Model();
model = new Devices([
{name:'test1'},
{name:'test2'}
]);
view = new DevicesView({
collection: model,
config: { em: editorModel }
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
describe('With configs', function() {
it("Update device on select change", () => {
view.$el.find('select').val('test2');
view.updateDevice();
expect(view.config.em.get('device')).toEqual('test2');
});
beforeEach(function () {
editorModel = new Backbone.Model();
model = new Devices([
{name:'test1'},
{name:'test2'}
]);
view = new DevicesView({
collection: model,
config: { em: editorModel }
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it("Update device on select change", function (){
view.$el.find('select').val('test2');
view.updateDevice();
view.config.em.get('device').should.equal('test2');
});
it("Render options", function (){
view.getOptions().should.equal('<option value="test1">test1</option><option value="test2">test2</option>');
});
});
it("Render options", () => {
expect(view.getOptions()).toEqual('<option value="test1">test1</option><option value="test2">test2</option>');
});
});
}
};
});
});
}
};

115
test/specs/dom_components/index.js

@ -0,0 +1,115 @@
const DomComponents = require('dom_components');
const ComponentModels = require('./model/Component');
const ComponentView = require('./view/ComponentV');
const ComponentsView = require('./view/ComponentsView');
const ComponentTextView = require('./view/ComponentTextView');
const ComponentImageView = require('./view/ComponentImageView');
const utils = require('./../test_utils.js');
describe('DOM Components', () => {
describe('Main', () => {
var obj;
var config;
var storagMock = utils.storageMock();
var editorModel = {
config: {
loadCompsOnRender: 0,
},
get() {return;},
getHtml() {return 'testHtml';},
getComponents() {return {test: 1};},
getCacheLoad() {
return storagMock.load();
}
};
// Methods
var setSmConfig = () => {
config.stm = storagMock;
config.stm.getConfig = () => ({
storeHtml: 1,
storeComponents: 1
});
};
var setEm = () => {
config.em = editorModel;
}
beforeEach(() => {
config = {};
obj = new DomComponents().init(config);
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(DomComponents).toExist();
});
it('storageKey returns array', () => {
expect(obj.storageKey() instanceof Array).toEqual(true);
});
it('storageKey returns correct composition', () => {
config.stm = {
getConfig() {
return {
storeHtml: 1,
storeComponents: 1,
}
}
};
expect(obj.storageKey()).toEqual(['html', 'components']);
});
it('Store data', () => {
setSmConfig();
setEm();
var expected = {
html: 'testHtml',
components: '{"test":1}',
};
expect(obj.store(1)).toEqual(expected);
});
it('Store and load data', () => {
setSmConfig();
setEm();
obj.store();
expect(obj.load()).toEqual({test: 1});
});
it('Wrapper exists', () => {
expect(obj.getWrapper()).toExist();
});
it('No components inside', () => {
expect(obj.getComponents().length).toEqual(0);
});
it('Add new component', () => {
var comp = obj.addComponent({});
expect(obj.getComponents().length).toEqual(1);
});
it('Add more components at once', () => {
var comp = obj.addComponent([{},{}]);
expect(obj.getComponents().length).toEqual(2);
});
it('Render wrapper', () => {
expect(obj.render()).toExist();
});
});
ComponentModels.run();
ComponentView.run();
ComponentsView.run();
ComponentTextView.run();
ComponentImageView.run();
});

125
test/specs/dom_components/main.js

@ -1,125 +0,0 @@
define(function(require, exports, module){
'use strict';
var DomComponents = require('DomComponents');
var ComponentImageView = require('undefined');
var utils = require('./../test_utils.js');
describe('DOM Components', function() {
describe('Main', function() {
var obj;
var config;
var storagMock = utils.storageMock();
var editorModel = {
config: {
loadCompsOnRender: 0,
},
get: function(){return;},
getHtml: function(){return 'testHtml';},
getComponents: function(){return {test: 1};},
getCacheLoad: function(){
return storagMock.load();
}
};
// Methods
var setSmConfig = function(){
config.stm = storagMock;
config.stm.getConfig = function(){
return {
storeHtml: 1,
storeComponents: 1,
}
};
};
var setEm = function(){
config.em = editorModel;
}
beforeEach(function () {
config = {};
obj = new DomComponents().init(config);
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
DomComponents.should.be.exist;
});
it('storageKey returns array', function() {
obj.storageKey().should.be.instanceOf(Array);
});
it('storageKey returns correct composition', function() {
config.stm = {
getConfig: function(){
return {
storeHtml: 1,
storeComponents: 1,
}
}
};
obj.storageKey().should.eql(['html', 'components']);
});
it('Store data', function() {
setSmConfig();
setEm();
var expected = {
html: 'testHtml',
components: '{"test":1}',
};
obj.store(1).should.deep.equal(expected);
});
it('Store and load data', function() {
setSmConfig();
setEm();
obj.store();
// Load object between html and components
obj.load().should.deep.equal({test: 1});
});
it('Wrapper exists', function() {
obj.getWrapper().should.not.be.empty;
});
it('No components inside', function() {
obj.getComponents().length.should.equal(0);
});
it('Add new component', function() {
var comp = obj.addComponent({});
obj.getComponents().length.should.equal(1);
});
it('Add more components at once', function() {
var comp = obj.addComponent([{},{}]);
obj.getComponents().length.should.equal(2);
});
it('Render wrapper', function() {
obj.render().should.be.ok;
});
it.skip('Add components at init', function() {
obj = new DomComponents().init({
components : [{}, {}, {}]
});
obj.getComponents().length.should.equal(3);
});
});
ComponentModels.run();
ComponentView.run();
ComponentsView.run();
ComponentTextView.run();
ComponentImageView.run();
});
});

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

@ -1,285 +1,281 @@
define(function(require, exports, module){
'use strict';
var DomComponents = require('DomComponents');
var Component = require('DomComponents/model/Component');
var ComponentImage = require('DomComponents/model/ComponentImage');
var ComponentText = require('DomComponents/model/ComponentText');
var ComponentLink = require('DomComponents/model/ComponentLink');
var ComponentMap = require('DomComponents/model/ComponentMap');
var ComponentVideo = require('DomComponents/model/ComponentVideo');
var Components = require('DomComponents/model/Components');
module.exports = {
run : function(){
var obj;
var dcomp;
var compOpts;
describe('Component', function() {
beforeEach(function () {
obj = new Component();
dcomp = new DomComponents();
compOpts = {
defaultTypes: dcomp.componentTypes,
};
});
afterEach(function () {
delete obj;
});
it('Has no children', function() {
obj.get('components').length.should.equal(0);
});
it.skip('Clones correctly', function() {
var sAttr = obj.attributes;
var cloned = obj.clone();
var eAttr = cloned.attributes;
eAttr.components = {};
sAttr.components = {};
eAttr.traits = {};
sAttr.traits = {};
sAttr.should.deep.equal(eAttr);
});
it('Clones correctly with traits', function() {
obj.get('traits').at(0).set('value', 'testTitle');
var cloned = obj.clone();
cloned.set('stylable', 0);
cloned.get('traits').at(0).set('value', 'testTitle2');
obj.get('traits').at(0).get('value').should.equal('testTitle');
obj.get('stylable').should.equal(true);
});
it('Has expected name', function() {
obj.getName().should.equal('Box');
});
it('Has expected name 2', function() {
obj.cid = 'c999';
obj.set('type','testType');
obj.getName().should.equal('TestType');
});
it('Component toHTML', function() {
obj.toHTML().should.equal('<div></div>');
});
it('Component toHTML with attributes', function() {
obj = new Component({
tagName: 'article',
attributes: {
'data-test1': 'value1',
'data-test2': 'value2'
}
});
obj.toHTML().should.equal('<article data-test1="value1" data-test2="value2"></article>');
});
it('Component toHTML with classes', function() {
obj = new Component({
tagName: 'article'
});
['class1', 'class2'].forEach(function(item){
obj.get('classes').add({name: item});
});
obj.toHTML().should.equal('<article class="class1 class2"></article>');
});
it('Component toHTML with children', function() {
obj = new Component({tagName: 'article'}, compOpts);
obj.get('components').add({tagName: 'span'});
obj.toHTML().should.equal('<article><span></span></article>');
});
it('Component toHTML with more children', function() {
obj = new Component({tagName: 'article'}, compOpts);
obj.get('components').add([{tagName: 'span'}, {tagName: 'div'}]);
obj.toHTML().should.equal('<article><span></span><div></div></article>');
});
it('Component toHTML with no closing tag', function() {
obj = new Component({void: 1});
obj.toHTML().should.equal('<div/>');
});
it('Component parse empty div', function() {
var el = document.createElement('div');
obj = Component.isComponent(el);
obj.should.deep.equal({tagName: 'div'});
});
it('Component parse span', function() {
var el = document.createElement('span');
obj = Component.isComponent(el);
obj.should.deep.equal({tagName: 'span'});
});
});
describe('Image Component', function() {
beforeEach(function () {
obj = new ComponentImage();
});
afterEach(function () {
delete obj;
});
it('Has src property', function() {
obj.has('src').should.equal(true);
});
it('Not droppable', function() {
obj.get('droppable').should.equal(false);
});
it('ComponentImage toHTML', function() {
obj = new ComponentImage();
obj.toHTML().should.equal('<img/>');
});
it('Component toHTML with attributes', function() {
obj = new ComponentImage({
attributes: {'alt': 'AltTest'},
src: 'testPath'
});
obj.toHTML().should.equal('<img alt="AltTest" src="testPath"/>');
});
it('Refuse not img element', function() {
var el = document.createElement('div');
obj = ComponentImage.isComponent(el);
obj.should.equal('');
});
it('Component parse img element', function() {
var el = document.createElement('img');
obj = ComponentImage.isComponent(el);
obj.should.deep.equal({type: 'image'});
});
it('Component parse img element with src', function() {
var el = document.createElement('img');
el.src = 'http://localhost/';
obj = ComponentImage.isComponent(el);
obj.should.deep.equal({type: 'image'});
});
});
describe('Text Component', function() {
beforeEach(function () {
obj = new ComponentText();
});
afterEach(function () {
delete obj;
});
it('Has content property', function() {
obj.has('content').should.equal(true);
});
it('Not droppable', function() {
obj.get('droppable').should.equal(false);
});
it('Component toHTML with attributes', function() {
obj = new ComponentText({
attributes: {'data-test': 'value'},
content: 'test content'
});
obj.toHTML().should.equal('<div data-test="value">test content</div>');
});
const DomComponents = require('dom_components');
const Component = require('dom_components/model/Component');
const ComponentImage = require('dom_components/model/ComponentImage');
const ComponentText = require('dom_components/model/ComponentText');
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');
module.exports = {
run() {
var obj;
var dcomp;
var compOpts;
describe('Component', () => {
beforeEach(() => {
obj = new Component();
dcomp = new DomComponents();
compOpts = {
defaultTypes: dcomp.componentTypes,
};
});
afterEach(() => {
obj = null;
});
describe('Link Component', function() {
it('Has no children', () => {
expect(obj.get('components').length).toEqual(0);
});
it('Component parse a element', function() {
var el = document.createElement('a');
obj = ComponentLink.isComponent(el);
obj.should.deep.equal({type: 'link'});
});
it('Clones correctly', () => {
var sAttr = obj.attributes;
var cloned = obj.clone();
var eAttr = cloned.attributes;
eAttr.components = {};
sAttr.components = {};
eAttr.traits = {};
sAttr.traits = {};
expect(sAttr.length).toEqual(eAttr.length);
});
it('Clones correctly with traits', () => {
obj.get('traits').at(0).set('value', 'testTitle');
var cloned = obj.clone();
cloned.set('stylable', 0);
cloned.get('traits').at(0).set('value', 'testTitle2');
expect(obj.get('traits').at(0).get('value')).toEqual('testTitle');
expect(obj.get('stylable')).toEqual(true);
});
it('Has expected name', () => {
expect(obj.getName()).toEqual('Box');
});
it('Has expected name 2', () => {
obj.cid = 'c999';
obj.set('type','testType');
expect(obj.getName()).toEqual('TestType');
});
describe('Map Component', function() {
it('Component toHTML', () => {
expect(obj.toHTML()).toEqual('<div></div>');
});
it('Component parse map iframe', function() {
var src = 'https://maps.google.com/maps?&q=London,UK&z=11&t=q&output=embed';
var el = $('<iframe src="' + src + '"></iframe>');
obj = ComponentMap.isComponent(el.get(0));
obj.should.deep.equal({type: 'map', src: src});
it('Component toHTML with attributes', () => {
obj = new Component({
tagName: 'article',
attributes: {
'data-test1': 'value1',
'data-test2': 'value2'
}
});
expect(obj.toHTML()).toEqual('<article data-test1="value1" data-test2="value2"></article>');
});
it('Component parse not map iframe', function() {
var el = $('<iframe src="https://www.youtube.com/watch?v=jNQXAC9IVRw"></iframe>');
obj = ComponentMap.isComponent(el.get(0));
obj.should.equal('');
it('Component toHTML with classes', () => {
obj = new Component({
tagName: 'article'
});
['class1', 'class2'].forEach(item => {
obj.get('classes').add({name: item});
});
expect(obj.toHTML()).toEqual('<article class="class1 class2"></article>');
});
it('Component toHTML with children', () => {
obj = new Component({tagName: 'article'}, compOpts);
obj.get('components').add({tagName: 'span'});
expect(obj.toHTML()).toEqual('<article><span></span></article>');
});
describe('Video Component', function() {
it('Component toHTML with more children', () => {
obj = new Component({tagName: 'article'}, compOpts);
obj.get('components').add([{tagName: 'span'}, {tagName: 'div'}]);
expect(obj.toHTML()).toEqual('<article><span></span><div></div></article>');
});
it('Component parse video', function() {
var src = 'http://localhost/';
var el = $('<video src="' + src + '"></video>');
obj = ComponentVideo.isComponent(el.get(0));
obj.should.deep.equal({type: 'video'}); //src: src
});
it('Component toHTML with no closing tag', () => {
obj = new Component({void: 1});
expect(obj.toHTML()).toEqual('<div/>');
});
it('Component parse youtube video iframe', function() {
var src = 'http://www.youtube.com/embed/jNQXAC9IVRw?';
var el = $('<iframe src="' + src + '"></video>');
obj = ComponentVideo.isComponent(el.get(0));
obj.should.deep.equal({type: 'video', provider: 'yt', src: src});
});
it('Component parse empty div', () => {
var el = document.createElement('div');
obj = Component.isComponent(el);
expect(obj).toEqual({tagName: 'div'});
});
it('Component parse span', () => {
var el = document.createElement('span');
obj = Component.isComponent(el);
expect(obj).toEqual({tagName: 'span'});
});
});
describe('Image Component', () => {
beforeEach(() => {
obj = new ComponentImage();
});
afterEach(() => {
obj = null;
});
it('Has src property', () => {
expect(obj.has('src')).toEqual(true);
});
it('Not droppable', () => {
expect(obj.get('droppable')).toEqual(false);
});
it('ComponentImage toHTML', () => {
obj = new ComponentImage();
expect(obj.toHTML()).toEqual('<img/>');
});
it('Component parse vimeo video iframe', function() {
var src = 'http://player.vimeo.com/video/2?';
var el = $('<iframe src="' + src + '"></video>');
obj = ComponentVideo.isComponent(el.get(0));
obj.should.deep.equal({type: 'video', provider: 'vi', src: src});
it('Component toHTML with attributes', () => {
obj = new ComponentImage({
attributes: {'alt': 'AltTest'},
src: 'testPath'
});
expect(obj.toHTML()).toEqual('<img alt="AltTest" src="testPath"/>');
});
it('Refuse not img element', () => {
var el = document.createElement('div');
obj = ComponentImage.isComponent(el);
expect(obj).toEqual('');
});
describe('Components', function() {
it('Component parse img element', () => {
var el = document.createElement('img');
obj = ComponentImage.isComponent(el);
expect(obj).toEqual({type: 'image'});
});
it('Component parse img element with src', () => {
var el = document.createElement('img');
el.src = 'http://localhost/';
obj = ComponentImage.isComponent(el);
expect(obj).toEqual({type: 'image'});
});
});
describe('Text Component', () => {
beforeEach(() => {
obj = new ComponentText();
});
afterEach(() => {
obj = null;
});
it('Has content property', () => {
expect(obj.has('content')).toEqual(true);
});
it('Not droppable', () => {
expect(obj.get('droppable')).toEqual(false);
});
it('Component toHTML with attributes', () => {
obj = new ComponentText({
attributes: {'data-test': 'value'},
content: 'test content'
});
expect(obj.toHTML()).toEqual('<div data-test="value">test content</div>');
});
beforeEach(function () {
dcomp = new DomComponents();
compOpts = {
defaultTypes: dcomp.componentTypes,
}
});
});
it('Creates component correctly', function() {
var c = new Components({}, compOpts);
var m = c.add({});
m.should.be.an.instanceOf(Component);
});
describe('Link Component', () => {
it('Creates image component correctly', function() {
var c = new Components({}, compOpts);
var m = c.add({ type: 'image' });
m.should.be.an.instanceOf(ComponentImage);
});
it('Component parse a element', () => {
var el = document.createElement('a');
obj = ComponentLink.isComponent(el);
expect(obj).toEqual({type: 'link'});
});
it('Creates text component correctly', function() {
var c = new Components({}, compOpts);
var m = c.add({ type: 'text' });
m.should.be.an.instanceOf(ComponentText);
});
});
describe('Map Component', () => {
it('Component parse map iframe', () => {
var src = 'https://maps.google.com/maps?&q=London,UK&z=11&t=q&output=embed';
var el = $('<iframe src="' + src + '"></iframe>');
obj = ComponentMap.isComponent(el.get(0));
expect(obj).toEqual({type: 'map', src});
});
it('Component parse not map iframe', () => {
var el = $('<iframe src="https://www.youtube.com/watch?v=jNQXAC9IVRw"></iframe>');
obj = ComponentMap.isComponent(el.get(0));
expect(obj).toEqual('');
});
});
describe('Video Component', () => {
it('Component parse video', () => {
var src = 'http://localhost/';
var el = $('<video src="' + src + '"></video>');
obj = ComponentVideo.isComponent(el.get(0));
expect(obj).toEqual({type: 'video', src});
});
it('Component parse youtube video iframe', () => {
var src = 'http://www.youtube.com/embed/jNQXAC9IVRw?';
var el = $('<iframe src="' + src + '"></video>');
obj = ComponentVideo.isComponent(el.get(0));
expect(obj).toEqual({type: 'video', provider: 'yt', src});
});
it('Component parse vimeo video iframe', () => {
var src = 'http://player.vimeo.com/video/2?';
var el = $('<iframe src="' + src + '"></video>');
obj = ComponentVideo.isComponent(el.get(0));
expect(obj).toEqual({type: 'video', provider: 'vi', src});
});
});
describe('Components', () => {
beforeEach(() => {
dcomp = new DomComponents();
compOpts = {
defaultTypes: dcomp.componentTypes,
}
});
it('Creates component correctly', () => {
var c = new Components({}, compOpts);
var m = c.add({});
expect(m instanceof Component).toEqual(true);
});
it('Creates image component correctly', () => {
var c = new Components({}, compOpts);
var m = c.add({ type: 'image' });
expect(m instanceof ComponentImage).toEqual(true);
});
it('Creates text component correctly', () => {
var c = new Components({}, compOpts);
var m = c.add({ type: 'text' });
expect(m instanceof ComponentText).toEqual(true);
});
}
};
});
});
}
};

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

@ -1,59 +1,55 @@
define(function(require, exports, module){
'use strict';
var ComponentImageView = require('undefined');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('ComponentImageView', function() {
var $fixtures;
var $fixture;
var model;
var view;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(function () {
model = new Component();
view = new ComponentImageView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
view.remove();
});
after(function () {
$fixture.remove();
});
it('Component empty', function() {
view.el.getAttribute('onmousedown').should.equal('return false');
view.el.getAttribute('class').should.equal(view.classEmpty);
});
it('TagName is <img>', function() {
view.el.tagName.should.equal('IMG');
});
it('Update src attribute', function() {
model.set('src','./');
view.el.getAttribute('src').should.equal('./');
});
it('Renders correctly', function() {
view.render().should.be.ok;
});
});
}
};
});
const ComponentImageView = require('dom_components/view/ComponentImageView');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
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);
});
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);
});
it('TagName is <img>', () => {
expect(view.el.tagName).toEqual('IMG');
});
it('Update src attribute', () => {
model.set('src', './');
expect(view.el.getAttribute('src')).toEqual('./');
});
it('Renders correctly', () => {
expect(view.render()).toExist();
});
});
}
};

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

@ -1,59 +1,55 @@
define(function(require, exports, module){
'use strict';
var ComponentTextView = require('undefined');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('ComponentTextView', function() {
var $fixtures;
var $fixture;
var model;
var view;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(function () {
model = new Component();
view = new ComponentTextView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
view.remove();
});
after(function () {
$fixture.remove();
});
it('Component empty', function() {
$fixture.html().should.equal('<div data-highlightable="1"></div>');
});
it('Input content is stored in model', function() {
//view.enableEditing();
view.el.innerHTML = 'test';
//view.disableEditing();
//model.get('content').should.equal('test');
});
it('Init with content', function() {
model = new Component({ content: 'test' });
view = new ComponentTextView({ model: model });
view.render().el.innerHTML.should.equal('test');
});
const ComponentTextView = require('dom_components/view/ComponentTextView');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('ComponentTextView', () => {
var $fixtures;
var $fixture;
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);
});
afterEach(() => {
view.remove();
});
after(() => {
$fixture.remove();
});
it('Component empty', () => {
expect($fixture.html()).toEqual('<div data-highlightable="1"></div>');
});
it('Input content is stored in model', () => {
//view.enableEditing();
view.el.innerHTML = 'test';
//view.disableEditing();
//model.get('content').should.equal('test');
});
it('Init with content', () => {
model = new Component({ content: 'test' });
view = new ComponentTextView({ model });
expect(view.render().el.innerHTML).toEqual('test');
});
}
};
});
});
}
};

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

@ -1,143 +1,139 @@
define(function(require, exports, module){
'use strict';
var ComponentView = require('undefined');
var Component = require('DomComponents/model/Component');
var DomComponents = require('DomComponents');
module.exports = {
run : function(){
describe('ComponentView', function() {
var $fixtures;
var $fixture;
var model;
var view;
var hClass = 'hc-state';
var dcomp;
var compOpts;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(function () {
dcomp = new DomComponents();
compOpts = {
defaultTypes: dcomp.componentTypes,
};
model = new Component();
view = new ComponentView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
view.remove();
});
after(function () {
$fixture.remove();
});
it('Component empty', function() {
$fixture.html().should.equal('<div data-highlightable="1"></div>');
});
it('Add helper class on update of state', function() {
model.set('state', 'test');
$fixture.html().should.equal('<div data-highlightable="1" class="' + hClass + '"></div>');
});
it('Clean form helper state', function() {
model.set('state', 'test');
model.set('state', '');
$fixture.html().should.equal('<div data-highlightable="1" class=""></div>');
});
it('Add helper class on status update', function() {
model.set('status', 'selected');
$fixture.html().should.equal('<div data-highlightable="1" class="selected"></div>');
});
it('Get string of classes', function() {
model.set('attributes', { class: ['test', 'test2']});
view.getClasses().should.equal('test test2');
});
it('Update attributes', function() {
model.set('attributes', {
title: 'value',
'data-test': 'value2',
});
view.el.getAttribute('title').should.equal('value');
view.el.getAttribute('data-test').should.equal('value2');
});
it('Update style', function() {
model.set('style', {
color: 'red',
float: 'left'
});
view.el.getAttribute('style').should.equal('color:red;float:left;');
});
it('Clean style', function() {
model.set('style', { color: 'red'});
model.set('style', {});
view.el.getAttribute('style').should.equal('');
});
it('Get style string', function() {
model.set('style', {
color: 'red',
float: 'left'
});
view.getStyleString().should.equal('color:red;float:left;');
});
it('Add class', function() {
model.get('classes').add({name: 'test'});
view.el.getAttribute('class').should.equal('test');
});
it('Add classes', function() {
model.get('classes').add([{name: 'test'}, {name: 'test2'}]);
view.el.getAttribute('class').should.equal('test test2');
});
it('Update on remove of some class', function() {
var cls1 = model.get('classes').add({name: 'test'});
var cls12 = model.get('classes').add({name: 'test2'});
model.get('classes').remove(cls1);
view.el.getAttribute('class').should.equal('test2');
});
it('Init with different tag', function() {
model = new Component({ tagName: 'span' });
view = new ComponentView({ model: model });
view.render().el.tagName.should.equal('SPAN');
});
it('Init with nested components', function() {
model = new Component({
components: [
{ tagName: 'span'},
{ attributes: { title: 'test'}}
]
}, compOpts);
view = new ComponentView({
model: model,
defaultTypes: dcomp.componentTypes,
});
view.render().$el.html().should.equal('<span data-highlightable="1"></span><div title="test" data-highlightable="1"></div>');
});
});
}
};
});
const ComponentView = require('dom_components/view/ComponentView');
const Component = require('dom_components/model/Component');
const DomComponents = require('dom_components');
module.exports = {
run() {
describe('ComponentView', () => {
var $fixtures;
var $fixture;
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 = {
defaultTypes: dcomp.componentTypes,
};
model = new Component();
view = new ComponentView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(() => {
view.remove();
});
after(() => {
$fixture.remove();
});
it('Component empty', () => {
expect($fixture.html()).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>');
});
it('Clean form helper state', () => {
model.set('state', 'test');
model.set('state', '');
expect($fixture.html()).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>');
});
it('Get string of classes', () => {
model.set('attributes', { class: ['test', 'test2']});
expect(view.getClasses()).toEqual('test test2');
});
it('Update attributes', () => {
model.set('attributes', {
title: 'value',
'data-test': 'value2',
});
expect(view.el.getAttribute('title')).toEqual('value');
expect(view.el.getAttribute('data-test')).toEqual('value2');
});
it('Update style', () => {
model.set('style', {
color: 'red',
float: 'left'
});
expect(view.el.getAttribute('style')).toEqual('color:red;float:left;');
});
it('Clean style', () => {
model.set('style', { color: 'red'});
model.set('style', {});
expect(view.el.getAttribute('style')).toEqual('');
});
it('Get style string', () => {
model.set('style', {
color: 'red',
float: 'left'
});
expect(view.getStyleString()).toEqual('color:red;float:left;');
});
it('Add class', () => {
model.get('classes').add({name: 'test'});
expect(view.el.getAttribute('class')).toEqual('test');
});
it('Add classes', () => {
model.get('classes').add([{name: 'test'}, {name: 'test2'}]);
expect(view.el.getAttribute('class')).toEqual('test test2');
});
it('Update on remove of some class', () => {
var cls1 = model.get('classes').add({name: 'test'});
var cls12 = model.get('classes').add({name: 'test2'});
model.get('classes').remove(cls1);
expect(view.el.getAttribute('class')).toEqual('test2');
});
it('Init with different tag', () => {
model = new Component({ tagName: 'span' });
view = new ComponentView({ model });
expect(view.render().el.tagName).toEqual('SPAN');
});
it('Init with nested components', () => {
model = new Component({
components: [
{ tagName: 'span'},
{ attributes: { title: 'test'}}
]
}, compOpts);
view = new ComponentView({
model,
defaultTypes: dcomp.componentTypes,
});
expect(view.render().$el.html()).toEqual('<span data-highlightable="1"></span><div title="test" data-highlightable="1"></div>');
});
});
}
};

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

@ -1,64 +1,60 @@
define(function(require, exports, module){
'use strict';
var DomComponents = require('DomComponents');
var ComponentsView = require('undefined');
var Components = require('DomComponents/model/Components');
module.exports = {
run : function(){
describe('ComponentsView', function() {
var $fixtures;
var $fixture;
var model;
var view;
var dcomp;
var compOpts;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
beforeEach(function () {
dcomp = new DomComponents();
compOpts = {
defaultTypes: dcomp.componentTypes,
};
model = new Components([], compOpts);
view = new ComponentsView({
collection: model,
defaultTypes: dcomp.componentTypes,
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
const DomComponents = require('dom_components');
const ComponentsView = require('dom_components/view/ComponentsView');
const Components = require('dom_components/model/Components');
module.exports = {
run() {
describe('ComponentsView', () => {
var $fixtures;
var $fixture;
var model;
var view;
var dcomp;
var compOpts;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="components-fixture"></div>');
});
afterEach(function () {
view.collection.reset();
});
beforeEach(() => {
dcomp = new DomComponents();
compOpts = {
defaultTypes: dcomp.componentTypes,
};
model = new Components([], compOpts);
view = new ComponentsView({
collection: model,
defaultTypes: dcomp.componentTypes,
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
});
afterEach(() => {
view.collection.reset();
});
it("Collection is empty", function (){
view.$el.html().should.be.empty;
});
after(() => {
$fixture.remove();
});
it("Add new component", function (){
sinon.stub(view, "addToCollection");
view.collection.add({});
view.addToCollection.calledOnce.should.equal(true);
});
it("Collection is empty", () => {
expect(view.$el.html()).toNotExist();
});
it("Render new component", function (){
view.collection.add({});
view.$el.html().should.not.be.empty;
});
it("Add new component", () => {
sinon.stub(view, "addToCollection");
view.collection.add({});
expect(view.addToCollection.calledOnce).toEqual(true);
});
it("Render new component", () => {
view.collection.add({});
expect(view.$el.html()).toExist();
});
}
};
});
});
}
};

221
test/specs/grapesjs/index.js

@ -0,0 +1,221 @@
const PluginManager = require('plugin_manager');
describe('GrapesJS', () => {
describe('Main', () => {
var obj;
var fixtures;
var fixture;
var editorName;
var htmlString;
var config;
var cssString;
var documentEl;
var storage;
var storageId = 'testStorage';
var storageMock = {
store(data) {
storage = data;
},
load(keys) {
return storage;
},
};
before(() => {
editorName = 'editor-fixture';
fixtures = $("#fixtures");
});
beforeEach(() => {
htmlString = '<div class="test1"></div><div class="test2"></div>';
cssString = '.test2{color:red}.test3{color:blue}';
documentEl = '<style>' + cssString + '</style>' + htmlString;
config = {
container: '#' + editorName,
storageManager: {
autoload: 0,
type:'none'
},
}
obj = grapesjs;
fixture = $('<div id="' + editorName + '"></div>');
fixture.empty().appendTo(fixtures);
});
afterEach(() => {
config = {};
obj = null;
fixture.remove();
});
it('Main object should be loaded', () => {
expect(obj).toExist();
});
it('Init new editor', () => {
var editor = obj.init(config);
expect(editor).toExist();
});
it('New editor is empty', () => {
var editor = obj.init(config);
var html = editor.getHtml();
var css = editor.getCss();
var protCss = editor.getConfig().protectedCss;
expect((html ? html : '')).toNotExist();
expect((css ? css : '')).toEqual(protCss);
expect(editor.getComponents().length).toEqual(0);
expect(editor.getStyle().length).toEqual(0);
});
it('Init editor with html', () => {
config.components = htmlString;
var editor = obj.init(config);
var comps = editor.DomComponents.getComponents();
expect(comps.length).toEqual(2);
expect(comps.at(0).get('classes').at(0).get('name')).toEqual('test1');
});
it('Init editor with css', () => {
config.style = cssString;
var editor = obj.init(config);
var rules = editor.CssComposer.getAll();
expect(rules.length).toEqual(2);
expect(rules.at(0).get('selectors').at(0).get('name')).toEqual('test2');
});
it.skip('Init editor from element', () => {
config.fromElement = 1;
fixture.html(documentEl);
var editor = obj.init(config);
var html = editor.getHtml();
var css = editor.getCss();
var protCss = editor.getConfig().protectedCss;
/*
(html ? html : '').should.equal(htmlString);
(css ? css : '').should.equal(protCss + '.test2{color:red;}');// .test3 is discarded in css
editor.getComponents().length.should.equal(2);
editor.getStyle().length.should.equal(2);
*/
expect((html ? html : '')).toEqual(htmlString);
expect(editor.getComponents().length).toEqual(2);
// .test3 is discarded in css
expect((css ? css : '')).toEqual(protCss + '.test2{color:red;}');
// bust is still here
expect(editor.getStyle().length).toEqual(2);
});
it('Set components as HTML', () => {
var editor = obj.init(config);
editor.setComponents(htmlString);
expect(editor.getComponents().length).toEqual(2);
});
it('Set components as array of objects', () => {
var editor = obj.init(config);
editor.setComponents([{}, {}, {}]);
expect(editor.getComponents().length).toEqual(3);
});
it('Set style as CSS', () => {
var editor = obj.init(config);
editor.setStyle(cssString);
editor.setStyle(cssString);
var styles = editor.getStyle();
expect(styles.length).toEqual(2);
expect(styles.at(1).get('selectors').at(0).get('name')).toEqual('test3');
});
it('Set style as as array of objects', () => {
var editor = obj.init(config);
editor.setStyle([
{selectors: ['test4']},
{selectors: ['test5']}
]);
var styles = editor.getStyle();
expect(styles.length).toEqual(2);
expect(styles.at(1).get('selectors').at(0).get('name')).toEqual('test5');
});
it('Adds new storage as plugin and store data there', () => {
var pluginName = storageId + '-plugin';
obj.plugins.add(pluginName, edt => {
edt.StorageManager.add(storageId, storageMock);
});
config.storageManager.type = storageId;
config.plugins = [pluginName];
var editor = obj.init(config);
editor.setComponents(htmlString);
editor.store();
var data = editor.load();
expect(data.html).toEqual(htmlString);
});
it('Execute plugins with custom options', () => {
var pluginName = storageId + '-plugin-opts';
obj.plugins.add(pluginName, (edt, opts) => {
var opts = opts || {};
edt.customValue = opts.cVal || '';
});
config.plugins = [pluginName];
config.pluginsOpts = {};
config.pluginsOpts[pluginName] = {cVal: 'TEST'};
var editor = obj.init(config);
expect(editor.customValue).toEqual('TEST');
});
// Problems with iframe loading
it.skip('Execute custom command', () => {
var editor = obj.init(config);
editor.testVal = '';
editor.setComponents(htmlString);
editor.Commands.add('test-command', {
run(ed, caller, opts) {
ed.testVal = ed.getHtml() + opts.val;
},
});
editor.runCommand('test-command', {val: 5});
expect(editor.testVal).toEqual(htmlString + '5');
});
it.skip('Stop custom command', () => {
var editor = obj.init(config);
editor.testVal = '';
editor.setComponents(htmlString);
editor.Commands.add('test-command', {
stop(ed, caller, opts) {
ed.testVal = ed.getHtml() + opts.val;
},
});
editor.stopCommand('test-command', {val: 5});
expect(editor.testVal).toEqual(htmlString + '5');
});
it('Set default devices', () => {
config.deviceManager = {};
config.deviceManager.devices = [
{name:'1', width: '2'},
{name:'3', width: '4'},
];
var editor = obj.init(config);
expect(editor.DeviceManager.getAll().length).toEqual(2);
});
it('There is no active device', () => {
var editor = obj.init(config);
expect(editor.getDevice()).toNotExist();
});
it('Active another device', () => {
var editor = obj.init(config);
editor.setDevice('Tablet');
expect(editor.getDevice()).toEqual('Tablet');
});
});
});

217
test/specs/grapesjs/main.js

@ -1,217 +0,0 @@
define(function(require, exports, module){
'use strict';
var GrapesJS = require('GrapesJS');
var PluginManager = require('PluginManager');
var chai = require('chai');
describe('GrapesJS', function() {
describe('Main', function() {
var obj;
var fixtures;
var fixture;
var editorName;
var htmlString;
var config;
var storage;
var storageId = 'testStorage';
var storageMock = {
store: function(data){
storage = data;
},
load: function(keys){
return storage;
},
};
before(function () {
editorName = 'editor-fixture';
fixtures = $("#fixtures");
});
beforeEach(function () {
htmlString = '<div class="test1"></div><div class="test2"></div>';
cssString = '.test2{color:red}.test3{color:blue}';
documentEl = '<style>' + cssString + '</style>' + htmlString;
config = {
container: '#' + editorName,
storageManager: {
autoload: 0,
type:'none'
},
}
obj = GrapesJS;
fixture = $('<div id="' + editorName + '"></div>');
fixture.empty().appendTo(fixtures);
});
afterEach(function () {
config = {};
delete obj;
delete config;
fixture.remove();
});
it('main object should be loaded', function() {
obj.should.be.exist;
});
it('Init new editor', function() {
var editor = obj.init(config);
editor.should.not.be.empty;
});
it('New editor is empty', function() {
var editor = obj.init(config);
var html = editor.getHtml();
var css = editor.getCss();
var protCss = editor.getConfig().protectedCss;
(html ? html : '').should.be.empty;
(css ? css : '').should.equal(protCss);
editor.getComponents().length.should.equal(0);
editor.getStyle().length.should.equal(0);
});
it('Init editor with html', function() {
config.components = htmlString;
var editor = obj.init(config);
var comps = editor.DomComponents.getComponents();
comps.length.should.equal(2);
comps.at(0).get('classes').at(0).get('name').should.equal('test1');
});
it('Init editor with css', function() {
config.style = cssString;
var editor = obj.init(config);
var rules = editor.CssComposer.getAll();
rules.length.should.equal(2);
rules.at(0).get('selectors').at(0).get('name').should.equal('test2');
});
it('Init editor from element', function() {
config.fromElement = 1;
fixture.html(documentEl);
var editor = obj.init(config);
var html = editor.getHtml();
var css = editor.getCss();
var protCss = editor.getConfig().protectedCss;
(html ? html : '').should.equal(htmlString);
(css ? css : '').should.equal(protCss + '.test2{color:red;}');// .test3 is discarded in css
editor.getComponents().length.should.equal(2);
editor.getStyle().length.should.equal(2);// .test3 is still here
});
it('Set components as HTML', function() {
var editor = obj.init(config);
editor.setComponents(htmlString);
editor.getComponents().length.should.equal(2);
});
it('Set components as array of objects', function() {
var editor = obj.init(config);
editor.setComponents([{}, {}, {}]);
editor.getComponents().length.should.equal(3);
});
it('Set style as CSS', function() {
var editor = obj.init(config);
editor.setStyle(cssString);
editor.setStyle(cssString);
var styles = editor.getStyle();
styles.length.should.equal(2);
styles.at(1).get('selectors').at(0).get('name').should.equal('test3');
});
it('Set style as as array of objects', function() {
var editor = obj.init(config);
editor.setStyle([
{selectors: ['test4']},
{selectors: ['test5']}
]);
var styles = editor.getStyle();
styles.length.should.equal(2);
styles.at(1).get('selectors').at(0).get('name').should.equal('test5');
});
it('Adds new storage as plugin and store data there', function() {
var pluginName = storageId + '-plugin';
obj.plugins.add(pluginName, function(edt){
edt.StorageManager.add(storageId, storageMock);
});
config.storageManager.type = storageId;
config.plugins = [pluginName];
var editor = obj.init(config);
editor.setComponents(htmlString);
editor.store();
var data = editor.load();
data.html.should.equal(htmlString);
});
it('Execute plugins with custom options', function() {
var pluginName = storageId + '-plugin-opts';
obj.plugins.add(pluginName, function(edt, opts){
var opts = opts || {};
edt.customValue = opts.cVal || '';
});
config.plugins = [pluginName];
config.pluginsOpts = {};
config.pluginsOpts[pluginName] = {cVal: 'TEST'};
var editor = obj.init(config);
editor.customValue.should.equal('TEST');
});
it('Execute custom command', function() {
var editor = obj.init(config);
editor.testVal = '';
editor.setComponents(htmlString);
editor.Commands.add('test-command', {
run: function(ed, caller, opts){
ed.testVal = ed.getHtml() + opts.val;
},
});
editor.runCommand('test-command', {val: 5});
editor.testVal.should.equal(htmlString + '5');
});
it('Stop custom command', function() {
var editor = obj.init(config);
editor.testVal = '';
editor.setComponents(htmlString);
editor.Commands.add('test-command', {
stop: function(ed, caller, opts){
ed.testVal = ed.getHtml() + opts.val;
},
});
editor.stopCommand('test-command', {val: 5});
editor.testVal.should.equal(htmlString + '5');
});
it('Set default devices', function() {
config.deviceManager = {};
config.deviceManager.devices = [
{name:'1', width: '2'},
{name:'3', width: '4'},
];
var editor = obj.init(config);
editor.DeviceManager.getAll().length.should.equal(2);
});
it('There is no active device', function() {
var editor = obj.init(config);
editor.getDevice().should.be.empty;
});
it('Active another device', function() {
var editor = obj.init(config);
editor.setDevice('Tablet');
editor.getDevice().should.equal('Tablet');
});
});
});
});

65
test/specs/modal/index.js

@ -0,0 +1,65 @@
const Modal = require('modal_dialog');
const ModalView = require('./view/ModalView');
describe('Modal dialog', () => {
describe('Main', () => {
var obj;
beforeEach(() => {
obj = new Modal().init();
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(obj).toExist();
});
it('Is close by default', () => {
expect(obj.isOpen()).toEqual(false);
});
it('Title is empty', () => {
expect(obj.getTitle()).toEqual('');
});
it('Content is empty', () => {
expect(obj.getContent()).toEqual('');
});
it('Set title', () => {
obj.setTitle('Test');
expect(obj.getTitle()).toEqual('Test');
});
it('Set content', () => {
obj.setContent('Test');
expect(obj.getContent()).toEqual('Test');
});
it('Set HTML content', () => {
obj.setContent('<h1>Test</h1>');
expect(obj.getContent()).toEqual('<h1>Test</h1>');
});
it('Open modal', () => {
obj.open();
expect(obj.isOpen()).toEqual(true);
});
it('Close modal', () => {
obj.open();
obj.close();
expect(obj.isOpen()).toEqual(false);
});
});
ModalView.run();
});

67
test/specs/modal/main.js

@ -1,67 +0,0 @@
define(function(require, exports, module){
'use strict';
var Modal = require('ModalDialog');
var ModalView = require('undefined');
describe('Modal dialog', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new Modal().init();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
obj.should.be.exist;
});
it('Is close by default', function() {
obj.isOpen().should.equal(false);
});
it('Title is empty', function() {
obj.getTitle().should.equal('');
});
it('Content is empty', function() {
obj.getContent().should.equal('');
});
it('Set title', function() {
obj.setTitle('Test');
obj.getTitle().should.equal('Test');
});
it('Set content', function() {
obj.setContent('Test');
obj.getContent().should.equal('Test');
});
it('Set HTML content', function() {
obj.setContent('<h1>Test</h1>');
obj.getContent().should.equal('<h1>Test</h1>');
});
it('Open modal', function() {
obj.open();
obj.isOpen().should.equal(true);
});
it('Close modal', function() {
obj.open();
obj.close();
obj.isOpen().should.equal(false);
});
});
ModalView.run();
});
});

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

@ -1,75 +1,71 @@
define(function(require, exports, module){
'use strict';
var ModalView = require('undefined');
var Modal = require('ModalDialog/model/Modal');
const ModalView = require('modal_dialog/view/ModalView');
const Modal = require('modal_dialog/model/Modal');
module.exports = {
run : function(){
describe('ModalView', function() {
module.exports = {
run() {
describe('ModalView', () => {
var $fixtures;
var $fixture;
var model;
var view;
var editorModel;
var $fixtures;
var $fixture;
var model;
var view;
var editorModel;
before(function () {
$fixtures = $("#fixtures");
$fixture= $('<div class="modal-fixture"></div>');
});
beforeEach(function () {
model = new Modal();
view = new ModalView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
before(() => {
$fixtures = $("#fixtures");
$fixture= $('<div class="modal-fixture"></div>');
});
afterEach(function () {
delete view;
delete model;
});
beforeEach(() => {
model = new Modal();
view = new ModalView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
});
afterEach(() => {
view = null;
model = null;
});
it("The content is not empty", function (){
view.el.innerHTML.should.be.not.empty;
});
after(() => {
$fixture.remove();
});
it("Get content", function (){
view.getContent().should.be.ok;
});
it("The content is not empty", () => {
expect(view.el.innerHTML).toExist();
});
it("Update content", function (){
model.set('content', 'test');
view.getContent().get(0).innerHTML.should.equal('test');
});
it("Get content", () => {
expect(view.getContent()).toExist();
});
it("Get title", function (){
view.getTitle().should.be.ok;
});
it("Update content", () => {
model.set('content', 'test');
expect(view.getContent().get(0).innerHTML).toEqual('test');
});
it("Update title", function (){
model.set('title', 'test');
view.getTitle().innerHTML.should.equal('test');
});
it("Get title", () => {
expect(view.getTitle()).toExist();
});
it("Close by default", function (){
view.updateOpen();
view.el.style.display.should.equal('none');
});
it("Update title", () => {
model.set('title', 'test');
expect(view.getTitle().innerHTML).toEqual('test');
});
it("Open dialog", function (){
model.set('open', 1);
view.el.style.display.should.equal('');
});
it("Close by default", () => {
view.updateOpen();
expect(view.el.style.display).toEqual('none');
});
it("Open dialog", () => {
model.set('open', 1);
expect(view.el.style.display).toEqual('');
});
}
};
});
});
}
};

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

@ -1,74 +1,69 @@
define(function(require, exports, module){
'use strict';
var GrapesJS = require('GrapesJS');
module.exports = {
run() {
module.exports = {
run : function(){
describe('E2E tests', () => {
describe('E2E tests', function() {
var fixtures;
var fixture;
var obj;
var config;
var editorName = 'panel-fixture';
var fixtures;
var fixture;
var obj;
var editorName = 'panel-fixture';
before(function () {
fixtures = $("#fixtures");
});
beforeEach(function () {
obj = GrapesJS;
config = {
container: '#' + editorName,
storage: { autoload: 0, type:'none' },
};
fixture = $('<div id="' + editorName + '"></div>');
fixture.empty().appendTo(fixtures);
});
before(() => {
fixtures = $("#fixtures");
});
afterEach(function () {
delete obj;
delete config;
fixture.remove();
});
beforeEach(() => {
obj = grapesjs;
config = {
container: '#' + editorName,
storageManager: { autoload: 0, type:'none' },
};
fixture = $('<div id="' + editorName + '"></div>');
fixture.empty().appendTo(fixtures);
});
after(function () {
fixture.remove();
});
afterEach(() => {
obj = null;
config = null;
fixture.remove();
});
it('Command is correctly executed on button click', function() {
var commandId = 'command-test';
config.commands = {
defaults: [{
id: commandId,
run: function(ed, caller){
ed.testValue = 'testValue';
caller.set('active', false);
}
}]
};
config.panels = {
defaults : [{
id : 'toolbar-test',
buttons : [{
id : 'button-test',
className : 'fa fa-smile-o',
command : commandId,
}],
}],
};
var editor = obj.init(config);
editor.testValue = '';
var button = editor.Panels.getButton('toolbar-test', 'button-test');
button.set('active', 1);
editor.testValue.should.equal('testValue');
button.get('active').should.equal(false);
});
after(() => {
//fixture.remove();
});
it.skip('Command is correctly executed on button click', () => {
var commandId = 'command-test';
config.commands = {
defaults: [{
id: commandId,
run(ed, caller) {
ed.testValue = 'testValue';
caller.set('active', false);
}
}]
};
config.panels = {
defaults: [{
id : 'toolbar-test',
buttons : [{
id : 'button-test',
className : 'fa fa-smile-o',
command : commandId,
}],
}],
};
var editor = obj.init(config);
editor.testValue = '';
var button = editor.Panels.getButton('toolbar-test', 'button-test');
button.set('active', 1);
expect(editor.testValue).toEqual('testValue');
expect(button.get('active')).toEqual(false);
});
}
});
};
}
});
};

104
test/specs/panels/index.js

@ -0,0 +1,104 @@
const Panels = require('panels');
const e2e = require('./e2e/PanelsE2e');
const Models = require('./model/PanelModels');
const PanelView = require('./view/PanelView');
const PanelsView = require('./view/PanelsView');
const ButtonView = require('./view/ButtonView');
const ButtonsView = require('./view/ButtonsView');
describe('Panels', () => {
describe('Main', () => {
var obj;
beforeEach(() => {
obj = new Panels().init();
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(obj).toExist();
});
it("No panels inside", () => {
expect(obj.getPanels().length).toEqual(3);
});
it("Adds new panel correctly via object", () => {
var panel = obj.addPanel({id: 'test'});
expect(panel.get('id')).toEqual('test');
});
it("New panel has no buttons", () => {
var panel = obj.addPanel({id: 'test'});
expect(panel.get('buttons').length).toEqual(0);
});
it("Adds new panel correctly via Panel instance", () => {
var oPanel = new obj.Panel({id: 'test'});
var panel = obj.addPanel(oPanel);
expect(panel).toEqual(oPanel);
expect(panel.get('id')).toEqual('test');
});
it("getPanel returns null in case there is no requested panel", () => {
expect(obj.getPanel('test')).toEqual(null);
});
it("getPanel returns correctly the panel", () => {
var panel = obj.addPanel({id: 'test'});
expect(obj.getPanel('test')).toEqual(panel);
});
it("Can't add button to non existent panel", () => {
expect(obj.addButton('test', {id:'btn'})).toEqual(null);
});
it("Add button correctly", () => {
var panel = obj.addPanel({id: 'test'});
var btn = obj.addButton('test', {id:'btn'});
expect(panel.get('buttons').length).toEqual(1);
expect(panel.get('buttons').at(0).get('id')).toEqual('btn');
});
it("getButton returns null in case there is no requested panel", () => {
expect(obj.addButton('test', 'btn')).toEqual(null);
});
it("getButton returns null in case there is no requested button", () => {
var panel = obj.addPanel({id: 'test'});
expect(obj.getButton('test', 'btn')).toEqual(null);
});
it("getButton returns correctly the button", () => {
var panel = obj.addPanel({id: 'test'});
var btn = obj.addButton('test', {id:'btn'});
expect(obj.getButton('test', 'btn')).toEqual(btn);
});
it("Renders correctly", () => {
expect(obj.render()).toExist();
});
it("Active correctly activable buttons", () => {
var spy = sinon.spy();
var panel = obj.addPanel({id: 'test'});
var btn = obj.addButton('test', {id:'btn', active: true});
btn.on('updateActive', spy);
obj.active();
expect(spy.called).toEqual(true);
});
});
Models.run();
PanelView.run();
PanelsView.run();
ButtonView.run();
ButtonsView.run();
e2e.run();
});

102
test/specs/panels/main.js

@ -1,102 +0,0 @@
define(function(require, exports, module){
'use strict';
var Panels = require('Panels');
var e2e = require('undefined');
describe('Panels', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new Panels().init();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
obj.should.be.exist;
});
it("No panels inside", function() {
obj.getPanels().length.should.equal(3);
});
it("Adds new panel correctly via object", function() {
var panel = obj.addPanel({id: 'test'});
panel.get('id').should.equal('test');
});
it("New panel has no buttons", function() {
var panel = obj.addPanel({id: 'test'});
panel.get('buttons').length.should.equal(0);
});
it("Adds new panel correctly via Panel instance", function() {
var oPanel = new obj.Panel({id: 'test'});
var panel = obj.addPanel(oPanel);
panel.should.deep.equal(oPanel);
panel.get('id').should.equal('test');
});
it("getPanel returns null in case there is no requested panel", function() {
(obj.getPanel('test') == null).should.equal(true);
});
it("getPanel returns correctly the panel", function() {
var panel = obj.addPanel({id: 'test'});
obj.getPanel('test').should.deep.equal(panel);
});
it("Can't add button to non existent panel", function() {
(obj.addButton('test', {id:'btn'}) == null).should.equal(true);
});
it("Add button correctly", function() {
var panel = obj.addPanel({id: 'test'});
var btn = obj.addButton('test', {id:'btn'});
panel.get('buttons').length.should.equal(1);
panel.get('buttons').at(0).get('id').should.equal('btn');
});
it("getButton returns null in case there is no requested panel", function() {
(obj.getButton('test', 'btn') == null).should.equal(true);
});
it("getButton returns null in case there is no requested button", function() {
var panel = obj.addPanel({id: 'test'});
(obj.getButton('test', 'btn') == null).should.equal(true);
});
it("getButton returns correctly the button", function() {
var panel = obj.addPanel({id: 'test'});
var btn = obj.addButton('test', {id:'btn'});
obj.getButton('test', 'btn').should.deep.equal(btn);
});
it("Renders correctly", function() {
obj.render().should.be.ok;
});
it("Active correctly activable buttons", function() {
var spy = sinon.spy();
var panel = obj.addPanel({id: 'test'});
var btn = obj.addButton('test', {id:'btn', active: true});
btn.on('updateActive', spy);
obj.active();
spy.called.should.equal(true);
});
});
Models.run();
PanelView.run();
PanelsView.run();
ButtonView.run();
ButtonsView.run();
e2e.run();
});
});

209
test/specs/panels/model/PanelModels.js

@ -1,120 +1,119 @@
define(function(require, exports, module){
'use strict';
var Panels = require('undefined');
const Panels = require('panels');
const Button = require('panels/model/Button');
const Buttons = require('panels/model/Buttons');
const Panel = require('panels/model/Panel');
module.exports = {
run : function(){
describe('Button', function() {
module.exports = {
run() {
describe('Button', () => {
var obj;
var obj;
beforeEach(function () {
obj = new Button();
});
beforeEach(() => {
obj = new Button();
});
afterEach(function () {
delete obj;
});
afterEach(() => {
obj = null;
});
it('Has buttons instance', function() {
obj.has('buttons').should.equal(true);
});
it('Has buttons instance', () => {
expect(obj.has('buttons')).toEqual(true);
});
it('Has no buttons', function() {
obj.get('buttons').length.should.equal(0);
});
it('Init with other buttons inside correctly', function() {
obj = new Button({
buttons: [{}]
});
obj.get('buttons').should.be.instanceOf(Buttons);
obj.get('buttons').length.should.equal(1);
});
});
describe('Buttons', function() {
var obj;
beforeEach(function () {
obj = new Buttons();
});
afterEach(function () {
delete obj;
});
it('Deactivates buttons', function() {
obj.add({ active: true });
obj.deactivateAll();
obj.at(0).get('active').should.equal(false);
});
it('Deactivates buttons with context', function() {
obj.add({ active: true });
obj.deactivateAll('someContext');
obj.at(0).get('active').should.equal(true);
});
it('Deactivates except one', function() {
var btn = obj.add({ active: true });
obj.deactivateAllExceptOne();
obj.at(0).get('active').should.equal(false);
});
it('Deactivates except one with model', function() {
var btn = obj.add({ active: true });
obj.deactivateAllExceptOne(btn);
obj.at(0).get('active').should.equal(true);
});
it('Has no buttons', () => {
expect(obj.get('buttons').length).toEqual(0);
});
it('Init with other buttons inside correctly', () => {
obj = new Button({
buttons: [{}]
});
describe('Panel', function() {
var obj;
beforeEach(function () {
obj = new Panel();
});
afterEach(function () {
delete obj;
});
it('Has buttons instance', function() {
obj.has('buttons').should.equal(true);
obj.get('buttons').should.be.instanceOf(Buttons);
});
it('Has no buttons', function() {
obj.get('buttons').length.should.equal(0);
});
it('Init with buttons inside correctly', function() {
obj = new Panel({
buttons: [{}]
});
obj.get('buttons').should.be.instanceOf(Buttons);
obj.get('buttons').length.should.equal(1);
});
expect(obj.get('buttons') instanceof Buttons).toEqual(true);
expect(obj.get('buttons').length).toEqual(1);
});
});
describe('Buttons', () => {
var obj;
beforeEach(() => {
obj = new Buttons();
});
afterEach(() => {
obj = null;
});
it('Deactivates buttons', () => {
obj.add({ active: true });
obj.deactivateAll();
expect(obj.at(0).get('active')).toEqual(false);
});
it('Deactivates buttons with context', () => {
obj.add({ active: true });
obj.deactivateAll('someContext');
expect(obj.at(0).get('active')).toEqual(true);
});
it('Deactivates except one', () => {
var btn = obj.add({ active: true });
obj.deactivateAllExceptOne();
expect(obj.at(0).get('active')).toEqual(false);
});
it('Deactivates except one with model', () => {
var btn = obj.add({ active: true });
obj.deactivateAllExceptOne(btn);
expect(obj.at(0).get('active')).toEqual(true);
});
});
describe('Panel', () => {
var obj;
beforeEach(() => {
obj = new Panel();
});
afterEach(() => {
obj = null;
});
it('Has buttons instance', () => {
expect(obj.has('buttons')).toEqual(true);
expect(obj.get('buttons') instanceof Buttons).toEqual(true);
});
it('Has no buttons', () => {
expect(obj.get('buttons').length).toEqual(0);
});
it('Init with buttons inside correctly', () => {
obj = new Panel({
buttons: [{}]
});
expect(obj.get('buttons') instanceof Buttons).toEqual(true);
expect(obj.get('buttons').length).toEqual(1);
});
describe('Panels', function() {
var obj;
});
beforeEach(function () {
obj = new Panel();
});
describe('Panels', () => {
var obj;
afterEach(function () {
delete obj;
});
beforeEach(() => {
obj = new Panel();
});
});
afterEach(() => {
obj = null;
});
}
};
});
});
}
};

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

@ -1,77 +1,73 @@
define(function(require, exports, module){
'use strict';
var ButtonView = require('undefined');
var Button = require('Panels/model/Button');
const ButtonView = require('panels/view/ButtonView');
const Button = require('panels/model/Button');
module.exports = {
run : function(){
module.exports = {
run() {
describe('ButtonView', function() {
describe('ButtonView', () => {
var $fixtures;
var $fixture;
var model;
var view;
var btnClass = 'btn';
var $fixtures;
var $fixture;
var model;
var view;
var btnClass = 'btn';
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="cssrule-fixture"></div>');
});
beforeEach(function () {
model = new Button();
view = new ButtonView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="cssrule-fixture"></div>');
});
afterEach(function () {
view.remove();
});
beforeEach(() => {
model = new Button();
view = new ButtonView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
});
afterEach(() => {
view.remove();
});
it('Button empty', function() {
$fixture.html().should.be.equal('<span class="' + btnClass+ '"></span>');
});
after(() => {
$fixture.remove();
});
it('Update class', function() {
model.set('className','test');
view.el.getAttribute('class').should.be.equal(btnClass + ' test');
});
it('Button empty', () => {
expect($fixture.html()).toEqual('<span class="' + btnClass+ '"></span>');
});
it('Update attributes', function() {
model.set('attributes',{
'data-test': 'test-value'
});
view.el.getAttribute('data-test').should.be.equal('test-value');
});
it('Update class', () => {
model.set('className','test');
expect(view.el.getAttribute('class')).toEqual(btnClass + ' test');
});
it('Check enable active', function() {
model.set('active', true, {silent: true});
view.checkActive();
view.el.getAttribute('class').should.be.equal(btnClass + ' active');
});
it('Update attributes', () => {
model.set('attributes',{
'data-test': 'test-value'
});
expect(view.el.getAttribute('data-test')).toEqual('test-value');
});
it('Check disable active', function() {
model.set('active', true, {silent: true});
view.checkActive();
model.set('active', false, {silent: true});
view.checkActive();
view.el.getAttribute('class').should.be.equal(btnClass);
});
it('Check enable active', () => {
model.set('active', true, {silent: true});
view.checkActive();
expect(view.el.getAttribute('class')).toEqual(btnClass + ' active');
});
it('Renders correctly', function() {
view.render().should.be.ok;
});
it('Check disable active', () => {
model.set('active', true, {silent: true});
view.checkActive();
model.set('active', false, {silent: true});
view.checkActive();
expect(view.el.getAttribute('class')).toEqual(btnClass);
});
it('Renders correctly', () => {
expect(view.render()).toExist();
});
}
};
});
});
}
};

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

Loading…
Cancel
Save