Browse Source

Merge remote-tracking branch 'refs/remotes/artf/dev' into dev

pull/202/head
thecodefish 9 years ago
parent
commit
5819133805
  1. 16
      .eslintrc
  2. 1
      .gitignore
  3. 42
      README.md
  4. 2
      dist/css/grapes.min.css
  5. 6
      dist/grapes.min.js
  6. 307
      index.html
  7. 7
      package.json
  8. 8
      src/asset_manager/config/config.js
  9. 17
      src/asset_manager/index.js
  10. 5
      src/asset_manager/view/AssetsView.js
  11. 6
      src/asset_manager/view/FileUploader.js
  12. 9
      src/block_manager/view/BlockView.js
  13. 14
      src/block_manager/view/BlocksView.js
  14. 28
      src/canvas/config/config.js
  15. 77
      src/canvas/index.js
  16. 77
      src/canvas/view/CanvasView.js
  17. 2
      src/code_manager/model/CssGenerator.js
  18. 15
      src/code_manager/model/JsGenerator.js
  19. 1
      src/commands/index.js
  20. 9
      src/commands/view/SelectComponent.js
  21. 19
      src/css_composer/index.js
  22. 4
      src/css_composer/model/CssRule.js
  23. 12
      src/device_manager/model/Device.js
  24. 21
      src/dom_components/index.js
  25. 91
      src/dom_components/model/Component.js
  26. 20
      src/dom_components/model/ComponentSvg.js
  27. 13
      src/dom_components/model/Components.js
  28. 9
      src/dom_components/view/ComponentSvgView.js
  29. 45
      src/dom_components/view/ComponentView.js
  30. 60
      src/domain_abstract/model/Styleable.js
  31. 10
      src/domain_abstract/ui/InputNumber.js
  32. 170
      src/editor/config/config.js
  33. 46
      src/editor/index.js
  34. 87
      src/editor/model/Editor.js
  35. 4
      src/editor/view/EditorView.js
  36. 21
      src/grapesjs/index.js
  37. 30
      src/navigator/view/ItemView.js
  38. 5
      src/navigator/view/ItemsView.js
  39. 7
      src/selector_manager/view/ClassTagView.js
  40. 5
      src/storage_manager/index.js
  41. 6
      src/storage_manager/model/LocalStorage.js
  42. 18
      src/storage_manager/model/RemoteStorage.js
  43. 21
      src/style_manager/config/config.js
  44. 2
      src/style_manager/model/Layers.js
  45. 1
      src/style_manager/model/Property.js
  46. 13
      src/style_manager/model/PropertyFactory.js
  47. 15
      src/style_manager/view/LayerView.js
  48. 22
      src/style_manager/view/LayersView.js
  49. 2
      src/style_manager/view/PropertyCompositeView.js
  50. 16
      src/style_manager/view/PropertyFileView.js
  51. 3
      src/style_manager/view/PropertyIntegerView.js
  52. 20
      src/style_manager/view/PropertyStackView.js
  53. 205
      src/style_manager/view/PropertyView.js
  54. 23
      src/style_manager/view/SectorsView.js
  55. 8
      src/styles/scss/_gjs_blocks.scss
  56. 454
      src/styles/scss/_gjs_style_manager.scss
  57. 365
      src/styles/scss/main.scss
  58. 339
      src/utils/Sorter.js
  59. 14
      test/helper.js
  60. 4
      test/main.js
  61. 243
      test/specs/selector_manager/e2e/ClassManager.js
  62. 82
      test/specs/selector_manager/index.js
  63. 82
      test/specs/selector_manager/main.js
  64. 76
      test/specs/selector_manager/model/SelectorModels.js
  65. 222
      test/specs/selector_manager/view/ClassTagView.js
  66. 391
      test/specs/selector_manager/view/ClassTagsView.js
  67. 120
      test/specs/storage_manager/index.js
  68. 123
      test/specs/storage_manager/main.js
  69. 223
      test/specs/storage_manager/model/Models.js
  70. 191
      test/specs/style_manager/index.js
  71. 185
      test/specs/style_manager/main.js
  72. 1601
      test/specs/style_manager/model/Models.js
  73. 130
      test/specs/style_manager/view/LayerView.js
  74. 298
      test/specs/style_manager/view/PropertyColorView.js
  75. 452
      test/specs/style_manager/view/PropertyCompositeView.js
  76. 386
      test/specs/style_manager/view/PropertyIntegerView.js
  77. 317
      test/specs/style_manager/view/PropertyRadioView.js
  78. 357
      test/specs/style_manager/view/PropertySelectView.js
  79. 655
      test/specs/style_manager/view/PropertyStackView.js
  80. 427
      test/specs/style_manager/view/PropertyView.js
  81. 181
      test/specs/style_manager/view/SectorView.js
  82. 92
      test/specs/style_manager/view/SectorsView.js
  83. 8
      test/specs/test_utils.js
  84. 23
      test/specs/trait_manager/index.js
  85. 25
      test/specs/trait_manager/main.js
  86. 51
      test/specs/trait_manager/model/TraitsModel.js
  87. 126
      test/specs/trait_manager/view/TraitsView.js
  88. 4
      test/specs/utils/main.js
  89. 457
      yarn.lock

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/

42
README.md

@ -22,6 +22,23 @@ Newsletter Demo - http://grapesjs.com/demo-newsletter-editor.html
## Table of contents
* [Features](#features)
* [Installation](#installation)
* [Development](#development)
* [Usage](#usage)
* [Documentation](#documentation)
* [API](#api)
* [Testing](#testing)
* [Plugins](#plugins)
* [Sponsors](#sponsors)
* [Support](#support)
* [License](#license)
## Features
@ -61,7 +78,7 @@ For development purpose you should follow instructions below.
## Development
GrapesJS uses [Webpack2](https://github.com/webpack/webpack) as a module bundler and [Babel](https://github.com/babel/babel) as a compiler.
GrapesJS uses [Webpack](https://github.com/webpack/webpack) as a module bundler and [Babel](https://github.com/babel/babel) as a compiler.
Clone the repository and install all the necessary dependencies
@ -159,6 +176,23 @@ $ npm test
## Plugins
### Extensions
* [grapesjs-plugin-export](https://github.com/artf/grapesjs-plugin-export) - Export GrapesJS templates in a zip archive
* [grapesjs-plugin-filestack](https://github.com/artf/grapesjs-plugin-filestack) - Add Filestack uploader in Asset Manager
* [grapesjs-plugin-ckeditor](https://github.com/artf/grapesjs-plugin-ckeditor) - Replaces the built-in RTE with CKEditor
* [grapesjs-aviary](https://github.com/artf/grapesjs-aviary) - Add the Aviary Image Editor
* [grapesjs-blocks-basic](https://github.com/artf/grapesjs-blocks-basic) - Basic set of blocks
* [grapesjs-plugin-forms](https://github.com/artf/grapesjs-plugin-forms) - Set of form components and blocks
* [grapesjs-navbar](https://github.com/artf/grapesjs-navbar) - Simple navbar component
### Presets
* [grapesjs-preset-newsletter](https://github.com/artf/grapesjs-preset-newsletter) - Newsletter Builder
* [grapesjs-mjml](https://github.com/artf/grapesjs-mjml) - Newsletter Builder with MJML components
## Sponsors
The project is sponsored by
@ -171,11 +205,15 @@ The project is sponsored by
## Support
If you like the project support it with a donation of your choice.
If you like the project support it with a donation of your choice or become a backer/sponsor via [Open Collective](https://opencollective.com/grapesjs)
[![PayPalMe](http://grapesjs.com/img/ppme.png)](https://paypal.me/grapesjs)
<a href="https://opencollective.com/grapesjs/sponsors/0/website" target="_blank"><img src="https://opencollective.com/grapesjs/sponsors/0/avatar"></a>
<a href="https://opencollective.com/grapesjs/sponsors/1/website" target="_blank"><img src="https://opencollective.com/grapesjs/sponsors/1/avatar"></a>
<a href="https://opencollective.com/grapesjs/backers/0/website" target="_blank"><img src="https://opencollective.com/grapesjs/backers/0/avatar"></a>
<a href="https://opencollective.com/grapesjs/backers/1/website" target="_blank"><img src="https://opencollective.com/grapesjs/backers/1/avatar"></a>

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

307
index.html

@ -4,7 +4,7 @@
<meta charset="utf-8">
<title>GrapesJS</title>
<link rel="stylesheet" href="dist/css/grapes.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="node_modules/jquery/dist/jquery.min.js"></script>
<script src="dist/grapes.min.js"></script>
</head>
@ -774,6 +774,26 @@
width: 500px;
}
.row {
display: table;
padding: 10px;
width: 100%;
}
.cell {
width: 8%;
display: table-cell;
height: 75px;
}
.cell30 {
width: 30%;
}
.cell70 {
width: 70%;
}
@media (max-width: 768px){
.foot-form-cont{
width:400px;
@ -781,6 +801,11 @@
.foot-form-title{
width: auto;
}
.cell, .cell30, .cell70 {
width: 100%;
display: block;
}
}
@media (max-width: 480px){
@ -792,6 +817,7 @@
</div>
<script type="text/javascript">
var blkStyle = '.blk-row::after{ content: ""; clear: both; display: block;} .blk-row{padding: 10px;}';
var editor = grapesjs.init(
@ -811,63 +837,6 @@
storeStyles: 1,
},
/*
components: [{
//script: 'var el = this; setInterval(function(){el.style.marginLeft = Math.random() * 50 +"px";}, 1000)',
script: 'loadScript = function(){console.log("loaded INSIDE", $);}',
style: {
background: 'red',
width:'500px',
height:'100px',
margin: '50px auto',
}
},{
script: 'this.innerHTML= "test1";',
style: {
background: 'blue',
width:'500px',
height:'100px',
margin: '50px auto',
}
},{
script: 'this.innerHTML= "test2";',
style: {
background: 'green',
width:'500px',
height:'100px',
margin: '50px auto',
}
},{
style: {
background: 'yellow',
width:'500px',
height:'100px',
margin: '50px auto',
}
},{
type: 'text',
style:{
width:'100px',
height:'100px',
margin: '50px auto',
},
traits: ['title'],
components: [{
type: 'textnode',
content: 'text node row',
},{
type: 'textnode',
content: ', another text node',
},{
type: 'link',
content: 'someLink',
},{
type: 'textnode',
content: " More text node --- ",
}],
}],
*/
commands: {
defaults: [{
id: 'open-github',
@ -889,9 +858,9 @@
}
},{
id: 'clean-all',
run: function(editor, sender){
run: function(editor, sender) {
sender.set('active',false);
if(confirm('Are you sure to clean the canvas?')){
if(confirm('Are you sure to clean the canvas?')) {
var comps = editor.DomComponents.clear();
}
}
@ -916,6 +885,156 @@
]
},
blockManager: {
blocks: [{
id: 'b1',
label: '1 Block',
category: 'Basic',
attributes: {class:'gjs-fonts gjs-f-b1'},
content: `<div class="row" data-gjs-droppable=".cell" data-gjs-custom-name="Row">
<div class="cell" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
</div>`
},{
id: 'b2',
label: '2 Blocks',
category: 'Basic',
attributes: {class:'gjs-fonts gjs-f-b2'},
content: `<div class="row" data-gjs-droppable=".cell" data-gjs-custom-name="Row">
<div class="cell" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
<div class="cell" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
</div>`
},{
id: 'b3',
label: '3 Blocks',
category: 'Basic',
attributes: {class:'gjs-fonts gjs-f-b3'},
content: `<div class="row" data-gjs-droppable=".cell" data-gjs-custom-name="Row">
<div class="cell" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
<div class="cell" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
<div class="cell" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
</div>`
},{
id: 'b4',
label: '3/7 Block',
category: 'Basic',
attributes: {class:'gjs-fonts gjs-f-b37'},
content: `<div class="row" data-gjs-droppable=".cell" data-gjs-custom-name="Row">
<div class="cell cell30" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
<div class="cell cell70" data-gjs-draggable=".row" data-gjs-custom-name="Cell"></div>
</div>`,
},{
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">'+
'<div class="menu-item">BUILDER</div><div class="menu-item">TEMPLATE</div><div class="menu-item">WEB</div>'+
'</nav><div class="clearfix"></div>'+
'<div class="lead-title">Build your templates without coding</div>'+
'<div class="lead-btn">Try it now</div></div></header>',
attributes: {class:'gjs-fonts gjs-f-hero'}
},{
id: 'h1p',
label: 'Text section',
category: 'Typography',
content: `<div>
<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>
</div>`,
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>'+
'<img class="badge-avatar" src="img/team1.jpg">'+
'<div class="badge-body">'+
'<div class="badge-name">Adam Smith</div><div class="badge-role">CEO</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+
'</div>'+
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span></div>'+
'</div>'+
'<div class="badge">'+
'<div class="badge-header"></div>'+
'<img class="badge-avatar" src="img/team2.jpg">'+
'<div class="badge-body">'+
'<div class="badge-name">John Black</div><div class="badge-role">Software Engineer</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+
'</div>'+
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span></div>'+
'</div>'+
'<div class="badge">'+
'<div class="badge-header"></div>'+
'<img class="badge-avatar" src="img/team3.jpg">'+
'<div class="badge-body">'+
'<div class="badge-name">Jessica White</div><div class="badge-role">Web Designer</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+
'</div>'+
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span>'+
'</div>'+
'</div></div>',
attributes: {class:'gjs-fonts gjs-f-3ba'}
},{
id: 'text',
label: 'Text',
attributes: {class:'gjs-fonts gjs-f-text'},
category: 'Basic',
content: {
type:'text',
content:'Insert your text here',
style: {padding: '10px' },
activeOnRender: 1
},
},{
id: 'image',
label: 'Image',
category: 'Basic',
attributes: {class:'gjs-fonts gjs-f-image'},
content: {
style: {color: 'black'},
type:'image',
activeOnRender: 1
},
},{
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',
content:'Link',
style:{color: '#d983a6'}
},
},{
id: 'map',
label: 'Map',
category: 'Extra',
attributes: {class:'fa fa-map-o'},
content: {
type: 'map',
style: {height: '350px'}
},
},{
id: 'video',
label: 'Video',
category: 'Basic',
attributes: {class:'fa fa-youtube-play'},
content: {
type: 'video',
src: 'img/video2.webm',
style: {
height: '350px',
width: '615px',
}
},
}],
},
styleManager : {
sectors: [{
@ -1156,22 +1275,58 @@
}]);
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'
}
},
});
/*
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'
}
},
});*/
var domc = editor.DomComponents;
var defaultType = domc.getType('default');
var defaultModel = defaultType.model;
var defaultView = defaultType.view;
/*
domc.addType('default', {
model: defaultModel.extend({
defaults: Object.assign({}, defaultModel.prototype.defaults, {
traits: [{
name: 'title',
label: 'Título',
placeholder: 'Insira um texto aqui'
}]
}),
}),
});
*/
// 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.on('styleManager:change:text-shadow', function(view) {
var model = view.model;
let targetValue = view.getTargetValue({ignoreDefault: 1});
let computedValue = view.getComputedValue();
let defaultValue = view.getDefaultValue();
console.log('Style of ', model.get('property'), 'Target: ', targetValue, 'Computed:', computedValue, 'Default:', defaultValue);
})
editor.render();
</script>

7
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.8.4",
"version": "0.9.8",
"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"
},

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: '',
};

17
src/asset_manager/index.js

@ -179,11 +179,18 @@ module.exports = () => {
var name = this.storageKey;
if(!d && c.stm)
d = c.stm.load(name);
var assets = [];
try{
assets = JSON.parse(d[name]);
}catch(err){}
this.getAll().add(assets);
var assets = d[name] || [];
if (typeof assets == 'string') {
try {
assets = JSON.parse(d[name]);
} catch(err) {}
}
if (assets && assets.length) {
this.getAll().reset(assets);
}
return assets;
},

5
src/asset_manager/view/AssetsView.js

@ -32,8 +32,9 @@ module.exports = Backbone.View.extend({
this.config = o.config;
this.pfx = this.config.stylePrefix || '';
this.ppfx = this.config.pStylePrefix || '';
this.listenTo( this.collection, 'add', this.addToAsset );
this.listenTo( this.collection, 'deselectAll', this.deselectAll );
this.listenTo(this.collection, 'add', this.addToAsset );
this.listenTo(this.collection, 'deselectAll', this.deselectAll);
this.listenTo(this.collection, 'reset', this.render);
this.className = this.pfx + 'assets';
this.events = {};

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();
},

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);

14
src/block_manager/view/BlocksView.js

@ -43,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,
@ -58,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);
},
/**
@ -78,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);
},
/**
@ -161,6 +168,9 @@ module.exports = Backbone.View.extend({
render() {
var ppfx = this.ppfx;
var frag = document.createDocumentFragment();
this.catsEl = null;
this.blocksEl = null;
this.renderedCategories = [];
this.el.innerHTML = `
<div class="${this.catsClass}"></div>
<div class="${this.noCatClass}">
@ -173,7 +183,7 @@ module.exports = Backbone.View.extend({
}, this);
this.append(frag);
this.$el.addClass(this.blockContClass + 's');
this.$el.addClass(this.blockContClass + 's')
return this;
},

28
src/canvas/config/config.js

@ -6,9 +6,31 @@ 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: [],
/**
* Add custom badge naming strategy
* @example
* customBadgeLabel: function(ComponentModel) {
* return ComponentModel.getName();
* }
*/
customBadgeLabel: '',
};

77
src/canvas/index.js

@ -4,6 +4,7 @@ module.exports = () => {
Canvas = require('./model/Canvas'),
CanvasView = require('./view/CanvasView');
var canvas;
var frameRect;
return {
@ -47,9 +48,20 @@ 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;
},
/**
* Return config object
* @return {Object}
*/
getConfig() {
return c;
},
/**
* Add wrapper
* @param {Object} wrp Wrapper
@ -199,6 +211,18 @@ module.exports = () => {
};
},
/**
* Set custom badge naming strategy
* @param {Function} f
* @example
* canvas.setCustomBadgeLabel(function(model){
* return ComponentModel.getName();
* });
*/
setCustomBadgeLabel(f) {
c.customBadgeLabel = f;
},
/**
* Get element position relative to the canvas
* @param {HTMLElement} el
@ -313,6 +337,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}

77
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;
},
@ -199,17 +244,19 @@ module.exports = Backbone.View.extend({
this.getJsContainer().append(view.scriptContainer.get(0));
}
var id = view.model.cid;
var script = view.model.get('script');
var scrStr = 'function(){' + script + '}';
scrStr = typeof script == 'function' ? script.toString() : scrStr;
var model = view.model;
var id = model.getId();
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}');
if (!item) return;
(function(){${model.getScriptString()}}.bind(item))()
}, 1);
</script>`);
},
/**

2
src/code_manager/model/CssGenerator.js

@ -24,7 +24,7 @@ module.exports = Backbone.Model.extend({
}
if(style && Object.keys(style).length !== 0) {
code += '#' + model.cid + '{';
code += '#' + model.getId() + '{';
for(var prop in style){
if(style.hasOwnProperty(prop))
code += prop + ':' + style[prop] + ';';

15
src/code_manager/model/JsGenerator.js

@ -7,16 +7,14 @@ module.exports = Backbone.Model.extend({
var script = model.get('script');
var type = model.get('type');
var comps = model.get('components');
var id = model.cid;
var id = model.getId();
if (script) {
// If the component has scripts we need to expose his ID
var attr = model.get('attributes');
attr = _.extend({}, attr, {id});
model.set('attributes', attr);
var scrStr = 'function(){' + script + '}';
scrStr = typeof script == 'function' ? script.toString() : scrStr;
var scrStr = model.getScriptString();
// If the script was updated, I'll put its code in a separate container
if (model.get('scriptUpdated')) {
@ -48,10 +46,11 @@ module.exports = Backbone.Model.extend({
for(var type in this.mapJs) {
var mapType = this.mapJs[type];
var ids = '#' + mapType.ids.join(', #');
code += 'var items = document.querySelectorAll("'+ids+'");' +
'for (var i = 0, len = items.length; i < len; i++) {'+
'(' + mapType.code + '.bind(items[i]))();' +
'}';
code += `
var items = document.querySelectorAll('${ids}');
for (var i = 0, len = items.length; i < len; i++) {
(function(){${mapType.code}}.bind(items[i]))();
}`;
}

1
src/commands/index.js

@ -160,7 +160,6 @@ module.exports = () => {
em.set('selectedComponent', sel);
ed.trigger('component:update', sel);
dragger && dragger.blur();
console.log('onEnd ', opts);
};
const onDrag = (e, opts) => {

9
src/commands/view/SelectComponent.js

@ -245,16 +245,21 @@ module.exports = {
* */
updateBadge(el, pos) {
var $el = $(el);
var canvas = this.canvas;
var config = canvas.getConfig();
var customeLabel = config.customBadgeLabel;
this.cacheEl = el;
var model = $el.data("model");
if(!model || !model.get('badgable'))
return;
var badge = this.getBadge();
badge.innerHTML = model.getName();
var badgeLabel = model.getIcon() + model.getName();
badgeLabel = customeLabel ? customeLabel(model) : badgeLabel;
badge.innerHTML = badgeLabel;
var bStyle = badge.style;
var u = 'px';
bStyle.display = 'block';
var canvasPos = this.canvas.getCanvasView().getPosition();
var canvasPos = canvas.getCanvasView().getPosition();
var badgeH = badge ? badge.offsetHeight : 0;
var badgeW = badge ? badge.offsetWidth : 0;
var top = pos.top - badgeH < canvasPos.top ? canvasPos.top : pos.top - badgeH;

19
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());
},
@ -224,8 +221,7 @@ module.exports = () => {
* @return {Array<Model>}
* @private
*/
addCollection(data, opts) {
var opt = opts || {};
addCollection(data, opts = {}) {
var result = [];
var d = data instanceof Array ? data : [data];
@ -245,12 +241,15 @@ module.exports = () => {
newSels.push(selec);
}
var modelExists = this.get(newSels, rule.state, rule.mediaText, rule);
var model = this.add(newSels, rule.state, rule.mediaText, rule);
if (opt.extend) {
var newStyle = _.extend({}, model.get('style'), rule.style || {});
model.set('style', newStyle);
} else {
model.set('style', rule.style || {});
var updateStyle = !modelExists || !opts.avoidUpdateStyle;
const style = rule.style || {};
if (updateStyle) {
let styleUpdate = opts.extend ?
Object.assign({}, model.get('style'), style) : style;
model.set('style', styleUpdate);
}
result.push(model);

4
src/css_composer/model/CssRule.js

@ -1,7 +1,9 @@
import Styleable from 'domain_abstract/model/Styleable';
var Backbone = require('backbone');
var Selectors = require('./Selectors');
module.exports = Backbone.Model.extend({
module.exports = Backbone.Model.extend(Styleable).extend({
defaults: {
// Css selectors

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'));
}
}
});

21
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());
@ -215,8 +217,12 @@ module.exports = () => {
}else if(d.html)
obj = d.html;
if(obj)
this.getComponents().reset(obj);
if (obj && obj.length) {
this.clear();
this.getComponents().reset();
this.getComponents().add(obj);
}
return obj;
},
@ -234,8 +240,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;
},

91
src/dom_components/model/Component.js

@ -1,9 +1,15 @@
import Styleable from 'domain_abstract/model/Styleable';
var Backbone = require('backbone');
var Components = require('./Components');
var Selectors = require('selector_manager/model/Selectors');
var Traits = require('trait_manager/model/Traits');
module.exports = Backbone.Model.extend({
const escapeRegExp = (str) => {
return str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
}
module.exports = Backbone.Model.extend(Styleable).extend({
defaults: {
// HTML tag of the component
@ -58,6 +64,9 @@ module.exports = Backbone.Model.extend({
// Content of the component (not escaped) which will be appended before children rendering
content: '',
// Component icon, this string will be inserted before the name, eg. '<i class="fa fa-square-o"></i>'
icon: '',
// Component related style
style: {},
@ -124,6 +133,7 @@ module.exports = Backbone.Model.extend({
}
}, this);
this.set('status', '');
this.init();
},
@ -244,20 +254,25 @@ module.exports = Backbone.Model.extend({
},
/**
* Get name of the component
* Get the name of the component
* @return {string}
* @private
* */
getName() {
if(!this.name){
var id = this.cid.replace(/\D/g,''),
type = this.get('type');
var tag = this.get('tagName');
tag = tag == 'div' ? 'box' : tag;
tag = type ? type : tag;
this.name = tag.charAt(0).toUpperCase() + tag.slice(1);
}
return this.name;
let customName = this.get('custom-name');
let tag = this.get('tagName');
tag = tag == 'div' ? 'box' : tag;
let name = this.get('type') || tag;
name = name.charAt(0).toUpperCase() + name.slice(1);
return customName || name;
},
/**
* Get the icon string
* @return {string}
*/
getIcon() {
let icon = this.get('icon');
return icon ? icon + ' ' : '';
},
/**
@ -269,17 +284,22 @@ module.exports = Backbone.Model.extend({
toHTML(opts) {
var code = '';
var m = this;
var tag = m.get('tagName'),
sTag = m.get('void'),
attrId = '';
// Build the string of attributes
var tag = m.get('tagName');
var idFound = 0;
var sTag = m.get('void');
var attrId = '';
var strAttr = '';
var attr = this.getAttrToHTML();
for(var prop in attr){
for (var prop in attr) {
if (prop == 'id') {
idFound = 1;
}
var val = attr[prop];
strAttr += typeof val !== undefined && val !== '' ?
' ' + prop + '="' + val + '"' : '';
}
// Build the string of classes
var strCls = '';
m.get('classes').each(m => {
@ -288,9 +308,8 @@ module.exports = Backbone.Model.extend({
strCls = strCls !== '' ? ' class="' + strCls.trim() + '"' : '';
// If style is not empty I need an ID attached to the component
// TODO: need to refactor in case of 'ID Trait'
if(!_.isEmpty(m.get('style')))
attrId = ' id="' + m.cid + '" ';
if(!_.isEmpty(m.get('style')) && !idFound)
attrId = ' id="' + m.getId() + '" ';
code += '<' + tag + strCls + attrId + strAttr + (sTag ? '/' : '') + '>' + m.get('content');
@ -324,6 +343,7 @@ module.exports = Backbone.Model.extend({
toJSON(...args) {
var obj = Backbone.Model.prototype.toJSON.apply(this, args);
var scriptStr = this.getScriptString();
delete obj.toolbar;
if (scriptStr) {
obj.script = scriptStr;
@ -332,6 +352,15 @@ module.exports = Backbone.Model.extend({
return obj;
},
/**
* Return model id
* @return {string}
*/
getId() {
let attrs = this.get('attributes') || {};
return attrs.id || this.cid;
},
/**
* Return script in string format, cleans 'function() {..' from scripts
* if it's a function
@ -342,14 +371,28 @@ module.exports = Backbone.Model.extend({
getScriptString(script) {
var scr = script || this.get('script');
// Need to cast script functions to string
if (!scr) {
return scr;
}
// Need to convert script functions to strings
if (typeof scr == 'function') {
var scrStr = scr.toString().trim();
scrStr = scrStr.replace(/^function\s?\(\)\s?\{/, '');
scrStr = scrStr.replace(/\}$/, '');
scr = scrStr;
scrStr = scrStr.replace(/^function[\s\w]*\(\)\s?\{/, '').replace(/\}$/, '');
scr = scrStr.trim();
}
var config = this.sm.config || {};
var tagVarStart = escapeRegExp(config.tagVarStart || '{[ ');
var tagVarEnd = escapeRegExp(config.tagVarEnd || ' ]}');
var reg = new RegExp(`${tagVarStart}(\\w+)${tagVarEnd}`, 'g');
scr = scr.replace(reg, (match, v) => {
// If at least one match is found I have to track this change for a
// better optimization inside JS generator
this.scriptUpdated();
return this.attributes[v];
})
return scr;
}

20
src/dom_components/model/ComponentSvg.js

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

13
src/dom_components/model/Components.js

@ -47,14 +47,19 @@ module.exports = Backbone.Collection.extend({
},
add(models, opt) {
if(typeof models === 'string'){
add(models, opt = {}) {
if (typeof models === 'string') {
var parsed = this.editor.get('Parser').parseHtml(models);
models = parsed.html;
var cssc = this.editor.get('CssComposer');
if(parsed.css && cssc){
var added = cssc.addCollection(parsed.css, {extend: 1});
if (parsed.css && cssc) {
var {avoidUpdateStyle} = opt;
var added = cssc.addCollection(parsed.css, {
extend: 1,
avoidUpdateStyle
});
}
}

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);
}
});

45
src/dom_components/view/ComponentView.js

@ -100,16 +100,34 @@ module.exports = Backbone.View.extend({
* @private
* */
updateStatus(e) {
var s = this.model.get('status'),
pfx = this.pfx;
switch(s) {
var el = this.el;
var status = this.model.get('status');
var pfx = this.pfx;
var ppfx = this.ppfx;
var selectedCls = pfx + 'selected';
var selectedParentCls = selectedCls + '-parent';
var freezedCls = `${ppfx}freezed`;
var actualCls = el.getAttribute('class') || '';
var cls = '';
switch (status) {
case 'selected':
this.$el.addClass(pfx + 'selected');
break;
case 'moving':
break;
cls = `${actualCls} ${selectedCls}`;
break;
case 'selected-parent':
cls = `${actualCls} ${selectedParentCls}`;
break;
case 'freezed':
cls = `${actualCls} ${freezedCls}`;
break;
default:
this.$el.removeClass(pfx + 'selected');
this.$el.removeClass(`${selectedCls} ${selectedParentCls} ${freezedCls}`);
}
cls = cls.trim();
if (cls) {
el.setAttribute('class', cls);
}
},
@ -290,6 +308,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 +404,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;
},

60
src/domain_abstract/model/Styleable.js

@ -0,0 +1,60 @@
export default {
/**
* To trigger the style change event on models I have to
* pass a new object instance
* @param {Object} prop
* @return {Object}
*/
extendStyle(prop) {
return Object.assign({}, this.getStyle(), prop);
},
/**
* Get style object
* @return {Object}
*/
getStyle() {
return this.get('style');
},
/**
* Set new style object
* @param {Object} prop
* @param {Object} opts
*/
setStyle(prop = {}, opts = {}) {
this.set('style', Object.assign({}, prop), opts);
},
/**
* Add style property
* @param {Object|string} prop
* @param {string} value
* @example
* this.addStyle({color: 'red'});
* this.addStyle('color', 'blue');
*/
addStyle(prop, value = '', opts = {}) {
if (typeof prop == 'string') {
prop = {
prop: value
};
} else {
opts = value || {};
}
prop = this.extendStyle(prop);
this.setStyle(prop, opts);
},
/**
* Remove style property
* @param {string} prop
*/
removeStyle(prop) {
let style = Object.assign({}, this.getStyle());
delete style[prop];
this.setStyle(style);
}
}

10
src/domain_abstract/ui/InputNumber.js

@ -62,6 +62,7 @@ module.exports = Backbone.View.extend({
handleChange(e) {
e.stopPropagation();
this.setValue(this.getInputEl().value);
this.elementUpdated();
},
/**
@ -71,6 +72,14 @@ module.exports = Backbone.View.extend({
e.stopPropagation();
var value = this.getUnitEl().value;
this.model.set('unit', value);
this.elementUpdated();
},
/**
* Fired when the element of the property is updated
*/
elementUpdated() {
this.model.trigger('el:change');
},
/**
@ -185,6 +194,7 @@ module.exports = Backbone.View.extend({
var value = this.prValue - 1;
this.model.set('value', value, {avoidStore: 1})
.set('value', value + 1);
this.elementUpdated();
}
},

170
src/editor/config/config.js

@ -1,4 +1,3 @@
var blkStyle = '.blk-row::after{ content: ""; clear: both; display: block;} .blk-row{padding: 10px;}';
module.exports = {
// Style prefix
stylePrefix: 'gjs-',
@ -38,7 +37,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 +58,16 @@ 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',
// Starting tag for variable inside scripts in Components
tagVarStart: '{[ ',
// Ending tag for variable inside scripts in Components
tagVarEnd: ' ]}',
// This option makes available custom component types also for loaded
// elements inside canvas
loadCompsOnRender: 1,
@ -104,18 +113,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',
}],
},
@ -156,150 +168,6 @@ module.exports = {
},
//Configurations for Block Manager
blockManager: {
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">'+
'<div class="menu-item">BUILDER</div><div class="menu-item">TEMPLATE</div><div class="menu-item">WEB</div>'+
'</nav><div class="clearfix"></div>'+
'<div class="lead-title">Build your templates without coding</div>'+
'<div class="lead-btn">Try it now</div></div></header>',
attributes: {class:'gjs-fonts gjs-f-hero'}
},{
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>'+
'<img class="badge-avatar" src="img/team1.jpg">'+
'<div class="badge-body">'+
'<div class="badge-name">Adam Smith</div><div class="badge-role">CEO</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+
'</div>'+
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span></div>'+
'</div>'+
'<div class="badge">'+
'<div class="badge-header"></div>'+
'<img class="badge-avatar" src="img/team2.jpg">'+
'<div class="badge-body">'+
'<div class="badge-name">John Black</div><div class="badge-role">Software Engineer</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+
'</div>'+
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span></div>'+
'</div>'+
'<div class="badge">'+
'<div class="badge-header"></div>'+
'<img class="badge-avatar" src="img/team3.jpg">'+
'<div class="badge-body">'+
'<div class="badge-name">Jessica White</div><div class="badge-role">Web Designer</div><div class="badge-desc">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore ipsum dolor sit</div>'+
'</div>'+
'<div class="badge-foot"><span class="badge-link">f</span><span class="badge-link">t</span><span class="badge-link">ln</span>'+
'</div>'+
'</div></div>',
attributes: {class:'gjs-fonts gjs-f-3ba'}
},{
id: 'text',
label: 'Text',
attributes: {class:'gjs-fonts gjs-f-text'},
category: 'Basic',
content: {
type:'text',
content:'Insert your text here',
style: {padding: '10px' },
activeOnRender: 1
},
},{
id: 'image',
label: 'Image',
category: 'Basic',
attributes: {class:'gjs-fonts gjs-f-image'},
content: {
style: {color: 'black'},
type:'image',
activeOnRender: 1
},
},{
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',
content:'Link',
style:{color: '#d983a6'}
},
},{
id: 'map',
label: 'Map',
category: 'Extra',
attributes: {class:'fa fa-map-o'},
content: {
type: 'map',
style: {height: '350px'}
},
},{
id: 'video',
label: 'Video',
category: 'Basic',
attributes: {class:'fa fa-youtube-play'},
content: {
type: 'video',
src: 'img/video2.webm',
style: {
height: '350px',
width: '615px',
}
},
}/*,{
id: 'table',
label: 'Table',
attributes: {class:'fa fa-table'},
content: {
type: 'table',
columns: 3,
rows: 5,
style: {height: '150px', width: '100%'}
},
}*/],
},
blockManager: {},
};

46
src/editor/index.js

@ -19,6 +19,7 @@
* * [getContainer](#getcontainer)
* * [refresh](#refresh)
* * [on](#on)
* * [off](#off)
* * [trigger](#trigger)
* * [render](#render)
*
@ -35,6 +36,10 @@
* 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
* styleManager:change - Triggered on style property change from new selected component, the view of the property is passed as an argument to the callback
* styleManager:change:{propertyName} - As above but for a specific style property
* storage: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'))
@ -257,6 +262,10 @@ module.exports = config => {
/**
* Add components
* @param {Array<Object>|Object|string} components HTML string or components model
* @param {Object} opts Options
* @param {Boolean} [opts.avoidUpdateStyle=false] If the HTML string contains styles,
* by default, they will be created and, if already exist, updated. When this option
* is true, styles already created will not be updated.
* @return {Model|Array<Model>}
* @example
* editor.addComponents('<div class="cls">New component</div>');
@ -267,8 +276,8 @@ module.exports = config => {
* content: 'New component'
* });
*/
addComponents(components) {
return this.getComponents().add(components);
addComponents(components, opts) {
return this.getComponents().add(components, opts);
},
/**
@ -298,12 +307,28 @@ module.exports = config => {
/**
* Returns selected component, if there is one
* @return {grapesjs.Component}
* @return {Model}
*/
getSelected() {
return em.getSelected();
},
/**
* Get stylable entity from the selected component.
* If you select the component without classes the entity is the Component
* itself and all changes will go inside its 'style' property. Otherwise,
* if the selected component has one or more classes, the function will
* return the corresponding CSS Rule
* @return {Model}
*/
getSelectedToStyle() {
let selected = em.getSelected();
if (selected) {
return this.StyleManager.getModelToStyle(selected);
}
},
/**
* Set device to the editor. If the device exists it will
* change the canvas to the proper width
@ -376,10 +401,11 @@ module.exports = config => {
/**
* Load data from the current storage
* @param {Function} clb Callback function
* @return {Object} Stored data
*/
load() {
return em.load();
load(clb) {
return em.load(clb);
},
/**
@ -448,6 +474,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

87
src/editor/model/Editor.js

@ -21,6 +21,7 @@ require('trait_manager'),
var Backbone = require('backbone');
var UndoManager = require('backbone-undo');
var key = require('keymaster');
var timedInterval;
module.exports = Backbone.Model.extend({
@ -53,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
@ -135,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);
},
/**
@ -218,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
@ -428,9 +426,11 @@ module.exports = Backbone.Model.extend({
store[el] = obj[el];
});
sm.store(store, clb);
this.set('changesCount', 0);
this.trigger('storage:store', store);
sm.store(store, () => {
clb && clb();
this.set('changesCount', 0);
this.trigger('storage:store', store);
});
return store;
},
@ -442,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);
});
@ -452,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;
@ -474,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();
}

21
src/grapesjs/index.js

@ -48,17 +48,18 @@
c.el = document.querySelector(els);
var editor = new Editor(c).init();
// Execute all plugins
// Execute plugins
var plugs = plugins.getAll();
for (var id in plugs){
// Check if plugin is requested
if(c.plugins.indexOf(id) < 0)
continue;
var opts = c.pluginsOpts[id] || {};
var plug = plugins.get(id);
plug(editor, opts);
}
c.plugins.forEach((pluginId) => {
let plugin = plugins.get(pluginId);
if (plugin) {
plugin(editor, c.pluginsOpts[pluginId] || {});
} else {
console.warn(`Plugin ${pluginId} not found`);
}
});
if(c.autorender)
editor.render();

30
src/navigator/view/ItemView.js

@ -1,4 +1,5 @@
var Backbone = require('backbone');
var ComponentView = require('dom_components/view/ComponentView');
var ItemsView;
module.exports = Backbone.View.extend({
@ -12,6 +13,7 @@ module.exports = Backbone.View.extend({
<div class="<%= prefix %>title <%= addClass %>">
<i id="<%= prefix %>caret" class="fa fa-chevron-right <%= caretCls %>"></i>
<i class="fa fa-pencil <%= editBtnCls %>"></i>
<%= icon %>
<input class="<%= ppfx %>no-app <%= inputNameCls %>" value="<%= title %>" readonly>
</div>
</div>
@ -42,7 +44,6 @@ module.exports = Backbone.View.extend({
this.inputNameCls = this.ppfx + 'nav-comp-name';
this.caretCls = this.ppfx + 'nav-item-caret';
this.titleCls = this.pfx + 'title';
this.customNameProp = 'custom-name';
this.events = {};
this.events['click > #'+this.pfx+'btn-eye'] = 'toggleVisibility';
this.events['click .' + this.caretCls] = 'toggleOpening';
@ -76,7 +77,7 @@ module.exports = Backbone.View.extend({
e.stopPropagation();
var inputName = this.getInputName();
inputName.readOnly = true;
this.model.set(this.customNameProp, inputName.value);
this.model.set('custom-name', inputName.value);
},
/**
@ -174,18 +175,7 @@ module.exports = Backbone.View.extend({
* @param Event
* */
updateStatus(e) {
var status = this.model.get('status');
var cls = this.pfx + 'selected';
var el = this.$el;
switch(status) {
case 'selected':
el.addClass(cls);
break;
case 'moving':
break;
default:
el.removeClass(cls);
}
ComponentView.prototype.updateStatus.apply(this, arguments);
},
/**
@ -265,12 +255,14 @@ module.exports = Backbone.View.extend({
},
render() {
let model = this.model;
var pfx = this.pfx;
var vis = this.isVisible();
var count = this.countChildren(this.model);
var count = this.countChildren(model);
this.$el.html( this.template({
title: this.model.get(this.customNameProp) || this.model.getName(),
title: model.getName(),
icon: model.getIcon(),
addClass: (count ? '' : pfx+'no-chld'),
editBtnCls: this.editBtnCls,
inputNameCls: this.inputNameCls,
@ -285,15 +277,15 @@ module.exports = Backbone.View.extend({
if(typeof ItemsView == 'undefined')
ItemsView = require('./ItemsView');
this.$components = new ItemsView({
collection : this.model.components,
collection : model.components,
config: this.config,
sorter: this.sorter,
opened: this.opt.opened,
parent: this.model
parent: model
}).render().$el;
this.$el.find('.'+ pfx +'children').html(this.$components);
this.$caret = this.$el.find('> .' + pfx + 'title-c > .' + pfx + 'title > #' + pfx + 'caret');
if(!this.model.get('draggable') || !this.config.sortable){
if(!model.get('draggable') || !this.config.sortable){
this.$el.find('> #' + pfx + 'move').detach();
}
if(!vis)

5
src/navigator/view/ItemsView.js

@ -22,6 +22,7 @@ module.exports = Backbone.View.extend({
containerSel: '.' + pfx + 'items',
itemSel: '.' + pfx + 'item',
ppfx: this.ppfx,
ignoreViewChildren: 1,
pfx,
nested: 1
});
@ -34,6 +35,10 @@ module.exports = Backbone.View.extend({
// For the sorter
this.$el.data('collection', this.collection);
if (this.parent) {
this.$el.data('model', this.parent);
}
},
/**

7
src/selector_manager/view/ClassTagView.js

@ -94,14 +94,17 @@ module.exports = Backbone.View.extend({
* @private
*/
updateStatus() {
var chkOn = 'fa-check-square-o';
var chkOff = 'fa-square-o';
if(!this.$chk)
this.$chk = this.$el.find('#' + this.pfx + 'checkbox');
if(this.model.get('active')){
this.$chk.removeClass('fa-circle-o').addClass('fa-dot-circle-o');
this.$chk.removeClass(chkOff).addClass(chkOn);
this.$el.removeClass('opac50');
}else{
this.$chk.removeClass('fa-dot-circle-o').addClass('fa-circle-o');
this.$chk.removeClass(chkOn).addClass(chkOff);
this.$el.addClass('opac50');
}
},

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;
},

21
src/style_manager/config/config.js

@ -9,4 +9,25 @@ module.exports = {
// Hide the property in case it's not stylable for the
// selected component (each component has 'stylable' property)
hideNotStylable: true,
// Highlight changed properties of the selected component
highlightChanged: true,
// Highlight computed properties of the selected component
highlightComputed: true,
// Show computed properties of the selected component, if this value
// is set to false, highlightComputed will not take effect
showComputed: true,
// Adds the possibility to clear property value from the target style
clearProperties: false,
// Properties which are valid to be shown as computed
// (Identified as inherited properties: https://developer.mozilla.org/en-US/docs/Web/CSS/inheritance)
validComputed: ['border-collapse', 'border-spacing', 'caption-side', 'color', 'cursor', 'direction', 'empty-cells',
'font-family', 'font-size', 'font-style', 'font-variant', 'font-weight', 'font-size-adjust', 'font-stretch', 'font',
'letter-spacing', 'line-height', 'list-style-image', 'list-style-position', 'list-style-type', 'list-style', 'orphans',
'quotes', 'tab-size', 'text-align', 'text-align-last', 'text-decoration-color', 'text-indent', 'text-justify',
'text-shadow', 'text-transform', 'visibility', 'white-space', 'widows', 'word-break', 'word-spacing', 'word-wrap'],
};

2
src/style_manager/model/Layers.js

@ -18,6 +18,6 @@ module.exports = Backbone.Collection.extend({
onReset() {
this.idx = 1;
},
}
});

1
src/style_manager/model/Property.js

@ -17,6 +17,7 @@ module.exports = Backbone.Model.extend({
detached: false,
visible: true,
functionName: '',
status: '',
properties: [],
layers: [],
list: [],

13
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
@ -88,9 +95,9 @@ module.exports = () => ({
}
// Defaults
switch(prop){
switch(prop) {
case 'float': case 'background-color':
case 'background-image':
case 'background-image': case 'text-shadow':
obj.defaults = 'none';
break;
case 'display':

15
src/style_manager/view/LayerView.js

@ -19,21 +19,26 @@ module.exports = Backbone.View.extend({
<div style="clear:both"></div>`),
initialize(o) {
let model = this.model;
this.stackModel = o.stackModel || {};
this.config = o.config || {};
this.pfx = this.config.stylePrefix || '';
this.className = this.pfx + 'layer';
this.sorter = o.sorter || null;
this.listenTo(this.model, 'destroy remove', this.remove);
this.listenTo(this.model, 'change:value', this.valueChanged);
this.listenTo(this.model, 'change:props', this.showProps);
this.listenTo(model, 'destroy remove', this.remove);
this.listenTo(model, 'change:value', this.valueChanged);
this.listenTo(model, 'change:props', this.showProps);
this.events['click #' + this.pfx + 'close-layer'] = 'remove';
this.events['mousedown > #' + this.pfx + 'move'] = 'initSorter';
if( !this.model.get('preview') ){
if (!model.get('preview')) {
this.$el.addClass(this.pfx + 'no-preview');
}
this.$el.data('model', this.model);
// For the sorter
model.view = this;
model.set({droppable: 0, draggable: 1});
this.$el.data('model', model);
this.delegateEvents();
},

22
src/style_manager/view/LayersView.js

@ -9,23 +9,29 @@ module.exports = Backbone.View.extend({
this.preview = o.preview;
this.pfx = this.config.stylePrefix || '';
this.ppfx = this.config.pStylePrefix || '';
this.className = this.pfx + 'layers ' + this.ppfx + 'field';
this.listenTo( this.collection, 'add', this.addTo);
this.listenTo( this.collection, 'deselectAll', this.deselectAll );
this.listenTo( this.collection, 'reset', this.render);
let pfx = this.pfx;
let ppfx = this.ppfx;
let collection = this.collection;
this.className = `${pfx}layers ${ppfx}field`;
this.listenTo(collection, 'add', this.addTo);
this.listenTo(collection, 'deselectAll', this.deselectAll );
this.listenTo(collection, 'reset', this.render);
var em = this.config.em || '';
var utils = em ? em.get('Utils') : '';
this.sorter = utils ? new utils.Sorter({
container: this.el,
containerSel: '.' + this.pfx + 'layers',
itemSel: '.' + this.pfx + 'layer',
ignoreViewChildren: 1,
containerSel: `.${pfx}layers`,
itemSel: `.${pfx}layer`,
pfx: this.config.pStylePrefix,
}) : '';
this.$el.data('model', {});
this.$el.data('collection', this.collection);
// For the Sorter
collection.view = this;
this.$el.data('model', collection);
this.$el.data('collection', collection);
},
/**

2
src/style_manager/view/PropertyCompositeView.js

@ -99,7 +99,7 @@ module.exports = PropertyView.extend({
this.props.each((prop, index) => {
str += prop.get('defaults') + prop.get('unit') + ' ';
});
return str.replace(/ +$/,'');
return this.model.get('defaults') || str.replace(/ +$/,'');
},
/**

16
src/style_manager/view/PropertyFileView.js

@ -41,14 +41,15 @@ module.exports = PropertyView.extend({
this.$previewBox = this.$el.find('#' + this.pfx + 'preview-box');
}
if(!this.componentValue || this.componentValue == this.defaultValue)
this.setPreviewView(0);
else
this.setPreviewView(1);
this.setValue(this.componentValue, 0);
},
setValue(value, f) {
PropertyView.prototype.setValue.apply(this, arguments);
this.setPreviewView(value && value != this.getDefaultValue());
this.setPreview(value);
},
/**
* Change visibility of the preview box
* @param bool Visibility
@ -84,11 +85,6 @@ module.exports = PropertyView.extend({
this.$preview.css('background-image', "url(" + url + ")");
},
/** @inheritdoc */
setValue(value, f) {
PropertyView.prototype.setValue.apply(this, arguments);
this.setPreview(value);
},
/** @inheritdoc */
renderTemplate() {

3
src/style_manager/view/PropertyIntegerView.js

@ -6,7 +6,8 @@ module.exports = PropertyView.extend({
initialize(options) {
PropertyView.prototype.initialize.apply(this, arguments);
this.listenTo( this.model ,'change:unit', this.valueChanged);
this.listenTo(this.model, 'change:unit', this.valueChanged);
this.listenTo(this.model, 'el:change', this.elementUpdated);
},
/**

20
src/style_manager/view/PropertyStackView.js

@ -28,18 +28,13 @@ module.exports = PropertyCompositeView.extend({
* so we gonna check all props and fine if there is some differences.
* */
targetUpdated(...args) {
if(!this.model.get('detached'))
if (!this.model.get('detached')) {
PropertyCompositeView.prototype.targetUpdated.apply(this, args);
else {
} else {
this.checkVisibility();
this.refreshLayers();
/*
this.model.get('properties').each(function(prop) {
console.log(prop.get('property'), ' - ', prop.get('value'));
});
*/
}
this.refreshLayers();
},
/**
@ -115,7 +110,7 @@ module.exports = PropertyCompositeView.extend({
// If detached the value in this case is stacked, eg. substack-prop: 1px, 2px, 3px...
if (this.model.get('detached')) {
var targetValue = propView.getTargetValue();
var targetValue = propView.getTargetValue({ignoreCustomValue: 1});
var valist = (targetValue + '').split(',');
result = valist[layerIndex];
result = result ? result.trim() : propView.getDefaultValue();
@ -283,7 +278,10 @@ module.exports = PropertyCompositeView.extend({
fieldName = 'values';
a = this.getLayersFromTarget();
} else {
var v = this.getComponentValue();
//var v = this.getComponentValue();
var v = this.getTargetValue();
var vDef = this.getDefaultValue();
v = v == vDef ? '' : v;
if (v) {
// Remove spaces inside functions:
// eg:

205
src/style_manager/view/PropertyView.js

@ -9,12 +9,15 @@ module.exports = Backbone.View.extend({
templateLabel: _.template(`
<div class="<%= pfx %>label">
<div class="<%= pfx %>icon <%= icon %>" title="<%= info %>">
<span class="<%= pfx %>icon <%= icon %>" title="<%= info %>">
<%= label %>
</div>
</span>
<b class="<%= pfx %>clear">&Cross;</b>
</div>`),
events: {'change': 'valueUpdated'},
events: {
'change': 'valueUpdated'
},
initialize(o) {
this.config = o.config || {};
@ -29,8 +32,9 @@ module.exports = Backbone.View.extend({
this.defaultValue = this.model.get('defaults');
this.property = this.model.get('property');
this.input = this.$input = null;
this.className = this.pfx + 'property';
this.inputHolderId = '#' + this.pfx + 'input-holder';
const pfx = this.pfx;
this.className = pfx + 'property';
this.inputHolderId = '#' + pfx + 'input-holder';
this.sector = this.model.collection && this.model.collection.sector;
if(!this.model.get('value'))
@ -41,46 +45,155 @@ module.exports = Backbone.View.extend({
this.listenTo(this.model, 'change:value', this.valueChanged);
this.listenTo(this.model, 'targetUpdated', this.targetUpdated);
this.listenTo(this.model, 'change:visible', this.updateVisibility);
this.listenTo(this.model, 'change:status', this.updateStatus);
this.events[`click .${pfx}clear`] = 'clear';
this.delegateEvents();
},
updateStatus() {
const status = this.model.get('status');
const pfx = this.pfx;
const ppfx = this.ppfx;
const config = this.config;
const updatedCls = `${ppfx}active-color`;
const computedCls = `${ppfx}warn-color`;
const labelEl = this.$el.find(`> .${pfx}label`);
const clearStyle = this.getClearEl().style;
labelEl.removeClass(`${updatedCls} ${computedCls}`);
clearStyle.display = 'none';
switch (status) {
case 'updated':
labelEl.addClass(updatedCls);
if (config.clearProperties) {
clearStyle.display = 'inline';
}
break;
case 'computed':
labelEl.addClass(computedCls);
break;
}
},
/**
* Clear the property
*/
clear() {
const target = this.getTargetModel();
target.removeStyle(this.model.get('property'));
this.targetUpdated();
},
/**
* Get clear element
* @return {HTMLElement}
*/
getClearEl() {
return this.el.querySelector(`.${this.pfx}clear`);
},
/**
* Returns selected target which should have 'style' property
* @deprecated
* @return {Model|null}
*/
getTarget() {
if(this.selectedComponent)
return this.selectedComponent;
return this.propTarget ? this.propTarget.model : null;
return this.propTarget && this.propTarget.model;
},
/**
* Returns Styleable model
* @return {Model|null}
*/
getTargetModel() {
return this.propTarget && this.propTarget.model;
},
/**
* Returns helper Styleable model
* @return {Model|null}
*/
getHelperModel() {
return this.propTarget && this.propTarget.helper;
},
/**
* Fired when the input value is updated
*/
valueUpdated() {
if(this.$input)
this.model.set('value', this.getInputValue());
this.model.set('value', this.getInputValue());
this.elementUpdated();
},
/**
* Fired when the target is updated
* Fired when the element of the property is updated
*/
elementUpdated() {
this.model.set('status', 'updated');
},
/**
* Fired when the target is changed
* */
targetUpdated() {
this.selectedComponent = this.propTarget.model;
this.helperComponent = this.propTarget.helper;
this.checkVisibility();
if (!this.checkVisibility()) {
return;
}
let value = '';
let status = '';
let targetValue = this.getTargetValue({ignoreDefault: 1});
let defaultValue = this.getDefaultValue();
let computedValue = this.getComputedValue();
const config = this.config;
const em = config.em;
const model = this.model;
if (targetValue) {
value = targetValue;
if (config.highlightChanged) {
status = 'updated';
}
} else if (computedValue && config.showComputed &&
computedValue != defaultValue) {
value = computedValue;
if (config.highlightComputed) {
status = 'computed';
}
} else {
value = defaultValue;
status = '';
}
//value = this.tryFetchFromFunction(value);
this.setValue(value, 1);
this.model.set('status', status);
if (em) {
em.trigger('styleManager:change', this);
em.trigger(`styleManager:change:${model.get('property')}`, this);
}
/*
if(this.getTarget()) {
if(!this.sameValue()){
this.renderInputRequest();
}
}
}*/
},
checkVisibility() {
var result = 1;
// Check if need to hide the property
if (this.config.hideNotStylable) {
if (!this.isTargetStylable() || !this.isComponentStylable()) {
this.hide();
result = 0;
} else {
this.show();
}
@ -89,6 +202,8 @@ module.exports = Backbone.View.extend({
this.sector.trigger('updateVisibility');
}
}
return result;
},
/**
@ -104,12 +219,11 @@ module.exports = Backbone.View.extend({
/**
* Get the value from the selected component of this property
*
* @return {String}
* */
getComponentValue() {
var propModel = this.model;
var target = this.getTarget();
var target = this.getTargetModel();
if(!target)
return;
@ -147,22 +261,31 @@ module.exports = Backbone.View.extend({
* @return string
* @private
*/
getTargetValue(opts) {
getTargetValue(opts = {}) {
var result;
var opt = opts || {};
var model = this.model;
var target = this.getTarget();
var target = this.getTargetModel();
var customFetchValue = this.customValue;
if (!target) {
return result;
}
result = target.get('style')[model.get('property')];
result = target.getStyle()[model.get('property')];
if (!result && !opt.ignoreDefault) {
if (!result && !opts.ignoreDefault) {
result = this.getDefaultValue();
}
if (typeof customFetchValue == 'function' && !opts.ignoreCustomValue) {
let index = model.collection.indexOf(model);
let customValue = customFetchValue(this, index);
if (customValue) {
result = customValue;
}
}
return result;
},
@ -175,6 +298,18 @@ module.exports = Backbone.View.extend({
return this.model.get('defaults');
},
/**
* Returns computed value
* @return {String}
* @private
*/
getComputedValue() {
let computed = this.propTarget.computed;
const valid = this.config.validComputed;
const property = this.model.get('property');
return computed && valid.indexOf(property) >= 0 && computed[property];
},
/**
* Fetch the string from function type value
* @param {String} v Function type value
@ -190,9 +325,10 @@ module.exports = Backbone.View.extend({
return value;
}
var start = value.indexOf("(") + 1;
var end = value.lastIndexOf(")");
return value.substring(start, end);
var valueStr = value + '';
var start = valueStr.indexOf("(") + 1;
var end = valueStr.lastIndexOf(")");
return valueStr.substring(start, end);
},
/**
@ -274,8 +410,9 @@ module.exports = Backbone.View.extend({
target.set('style', targetStyle, { avoidStore : avSt});
if(this.helperComponent)
this.helperComponent.set('style', targetStyle, { avoidStore : avSt});
// Helper exists when is active a State in Style Manager
let helper = this.getHelperModel();
helper && helper.setStyle(targetStyle, {avoidStore: avSt});
},
/**
@ -346,12 +483,13 @@ module.exports = Backbone.View.extend({
},
renderLabel() {
this.$el.html( this.templateLabel({
pfx : this.pfx,
ppfx : this.ppfx,
icon : this.model.get('icon'),
info : this.model.get('info'),
label : this.model.get('name'),
let model = this.model;
this.$el.html(this.templateLabel({
pfx: this.pfx,
ppfx: this.ppfx,
icon: model.get('icon'),
info: model.get('info'),
label: model.get('name'),
}));
},
@ -409,6 +547,7 @@ module.exports = Backbone.View.extend({
this.renderLabel();
this.renderField();
this.$el.attr('class', this.className);
this.updateStatus();
return this;
},

23
src/style_manager/view/SectorsView.js

@ -33,22 +33,31 @@ 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})` : '';
var stateStr = state ? `:${state}` : null;
var view = el.view;
pt.helper = null;
if (view) {
pt.computed = window.getComputedStyle(view.el, stateStr);
}
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 +76,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)

8
src/styles/scss/_gjs_blocks.scss

@ -47,6 +47,14 @@
}
}
.#{$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;

454
src/styles/scss/_gjs_style_manager.scss

@ -0,0 +1,454 @@
.#{$sm-prefix} {
&clear {
font-size: 1rem;
line-height: 0;
cursor: pointer;
}
}
.#{$sm-prefix}close-btn {
display: block;
font-size: 23px;
position: absolute;
cursor: pointer;
right: 5px;
top: 0;
@include opacity(0.2);
&:hover {
@include opacity(0.7);
}
}
.#{$sm-prefix}header {
font-size: 11px;
font-weight: lighter;
padding: 10px;
}
.#{$sm-prefix}sector {
clear: both;
font-weight: lighter;
text-align: left;
##{$sm-prefix}caret {
padding-right: 5px;
font-size: 11px;
}
&.#{$sm-prefix}open {
@extend .#{$app-prefix}category-open;
}
.#{$sm-prefix}title {
@extend .#{$app-prefix}category-title;
}
.#{$sm-prefix}label {
margin: 5px 5px 2px 0;
}
/* ------------------Field-------------------- */
.#{$sm-prefix}field {
width: 100%;
position: relative;
input,
select {
background-color: transparent;
color: $mainLhlColor;
border: none;
width: 100%;
}
input {
box-sizing: border-box;
}
select {
position: relative;
z-index: 1;
@include appearance(none);
&::-ms-expand {
display: none;
}
}
select:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 $mainLhlColor;
}
input:focus,
select:focus {
outline: none;
}
.#{$sm-prefix}unit {
position: absolute;
right: 10px;
top: 3px;
font-size: 10px;
color: $mainLhlColor;
cursor: pointer;
}
.#{$clm-prefix}sel-arrow,
.#{$sm-prefix}int-arrows,
.#{$sm-prefix}sel-arrow {
height: 100%;
width: 9px;
position: absolute;
right: 0;
top: 0;
cursor: ns-resize;
}
.#{$sm-prefix}sel-arrow {
cursor: pointer;
}
.#{$clm-prefix}d-s-arrow,
.#{$sm-prefix}d-arrow,
.#{$sm-prefix}d-s-arrow,
.#{$sm-prefix}u-arrow {
position: absolute;
height: 0;
width: 0;
border-left: 3px solid transparent;
border-right: 4px solid transparent;
cursor: pointer;
}
.#{$sm-prefix}u-arrow {
border-bottom: 4px solid $mainLhlColor;
top: 4px;
}
.#{$clm-prefix}d-s-arrow,
.#{$sm-prefix}d-arrow,
.#{$sm-prefix}d-s-arrow {
border-top: 4px solid $mainLhlColor;
bottom: 4px;
}
.#{$clm-prefix}d-s-arrow,
.#{$sm-prefix}d-s-arrow {
bottom: 7px;
}
&.#{$sm-prefix}color,
&.#{$sm-prefix}input,
&.#{$sm-prefix}integer,
&.#{$sm-prefix}list,
&.#{$sm-prefix}select {
background-color: $mainDkColor;
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 1px 1px 0 $mainLhColor;
color: $mainLhlColor;
border-radius: 2px;
box-sizing: border-box;
padding: 0 5px;
}
&.#{$sm-prefix}composite {
@extend .#{$app-prefix}color-main;
border-radius: 2px;
}
&.#{$sm-prefix}select {
padding: 0;
}
&.#{$sm-prefix}select select {
height: 20px;
}
&.#{$sm-prefix}select option {
padding: 3px 0;
}
&.#{$sm-prefix}composite {
background-color: rgba(0, 0, 0, 0.1);
border: 1px solid rgba(0, 0, 0, 0.25);
}
&.#{$sm-prefix}list {
width: auto;
padding: 0;
overflow: hidden;
float: left;
input {
display: none;
}
label {
cursor: pointer;
padding: 5px;
display: block;
}
.#{$sm-prefix}radio:checked + label {
background-color: rgba(255, 255, 255, 0.2);
}
.#{$sm-prefix}icon {
background-repeat: no-repeat;
background-position: center;
text-shadow: none;
line-height: normal;
//padding: 5px 19px;
}
}
&.#{$sm-prefix}integer select {
width: auto;
padding: 0;
}
}
/* ------------------END Field-------------------- */
.#{$sm-prefix}list .#{$sm-prefix}el {
float: left;
border-left: 1px solid $mainDkColor;
&:first-child {
border: none;
}
&:hover {
background: $mainDkColor;
}
}
.#{$sm-prefix}properties {
font-size: 11px;
padding: 10px 5px;
}
/* ------------------Property-------------------- */
.#{$sm-prefix}property {
box-sizing: border-box;
float: left;
width: 50%;
margin-bottom: 5px;
padding: 0 5px;
&.#{$sm-prefix}composite,
&.#{$sm-prefix}file,
&.#{$sm-prefix}list,
&.#{$sm-prefix}stack {
width: 100%;
}
.#{$sm-prefix}btn {
background-color: lighten($mainDkColor, 13%);
border-radius: 2px;
box-shadow: 1px 1px 0 lighten($mainDkColor, 2%), 1px 1px 0 lighten($mainDkColor, 17%) inset;
padding: 5px;
position: relative;
text-align: center;
height: auto;
width: 100%;
cursor: pointer;
color: $fontColor;
box-sizing: border-box;
text-shadow: -1px -1px 0 $mainDkColor;
border: none;
@include opacity(0.85);
}
.#{$sm-prefix}btn-c {
box-sizing: border-box;
float: left;
width: 100%;
padding: 0 5px;
}
&.#{$sm-prefix}file ##{$sm-prefix}preview-box {
background-color: $lightBorder;
border-radius: 2px;
margin-top: 5px;
position: relative;
overflow: hidden;
&.#{$sm-prefix}show {
border: 1px solid darken($lightBorder, 1%);
padding: 3px 5px;
}
##{$sm-prefix}close {
@extend .#{$sm-prefix}close-btn;
display: block;
}
}
&.#{$sm-prefix}file .#{$sm-prefix}show ##{$sm-prefix}preview-file {
height: 50px;
}
&.#{$sm-prefix}file ##{$sm-prefix}preview-file {
background-size: auto 100%;
background-repeat: no-repeat;
background-position: center center;
}
.#{$sm-prefix}layers {
margin-top: 5px;
min-height: 30px;
}
.#{$sm-prefix}layer {
background-color: rgba(255, 255, 255, 0.055);
border-radius: 2px;
box-shadow: 1px 1px 0 rgba(0, 0, 0, 0.2), 1px 1px 0 rgba(255, 255, 255, 0.055) inset;
margin: 2px;
padding: 7px;
position: relative;
cursor: pointer;
> ##{$sm-prefix}preview-box {
@extend .checker-bg;
height: 15px;
position: absolute;
right: 27px;
top: 6px;
width: 15px;
}
##{$sm-prefix}preview,
##{$sm-prefix}preview-box {
border-radius: 2px;
}
##{$sm-prefix}close-layer {
display: block;
font-size: 23px;
position: absolute;
cursor: pointer;
right: 5px;
top: 0;
@include opacity(0.5);
&:hover {
@include opacity(0.8);
}
}
> ##{$sm-prefix}preview-box ##{$sm-prefix}preview {
background-color: white;
height: 100%;
width: 100%;
background-size: cover !important;
}
&.#{$sm-prefix}active {
background-color: rgba(255, 255, 255, 0.12);
}
&.#{$sm-prefix}no-preview ##{$sm-prefix}preview-box {
display: none;
}
}
}
##{$sm-prefix}text-shadow ##{$sm-prefix}preview::after {
color: #000;
content: "T";
font-weight: 900;
line-height: 17px;
padding: 0 4px;
}
/* ------------------END Property-------------------- */
.#{$sm-prefix}stack .#{$sm-prefix}properties {
padding-top: 5px;
}
.#{$sm-prefix}stack ##{$sm-prefix}add {
@extend .#{$app-prefix}color-main;
background: none;
border: none;
cursor: pointer;
font-size: 22px;
line-height: 10px;
position: absolute;
right: 0;
top: -20px;
opacity: 0.75;
&:hover {
@include opacity(1);
}
}
.#{$sm-prefix}colorp-c {
@extend .#{$app-prefix}bg-main;
height: 100%;
width: 20px;
position: absolute;
right: 0;
top: 0;
box-sizing: border-box;
border-radius: 2px;
padding: 2px;
.#{$app-prefix}checker-bg {
height: 100%;
width: 100%;
border-radius: 1px;
}
}
.#{$sm-prefix}color-picker {
background-color: $fontColor;
cursor: pointer;
height: 16px;
width: 100%;
margin-top: -16px;
box-shadow: 0 0 1px $mainDkColor;
border-radius: 1px;
}
.#{$sm-prefix}btn-upload ##{$sm-prefix}upload {
left: 0;
top: 0;
position: absolute;
width: 100%;
opacity: 0;
cursor: pointer;
}
.#{$sm-prefix}btn-upload ##{$sm-prefix}label {
padding: 2px 0;
}
}
.#{$sm-prefix}layer > ##{$sm-prefix}move {
@include opacity(0.7);
cursor: move;
font-size: 12px;
float: left;
margin: 0 5px 0 0;
&:hover {
@include opacity(0.9);
}
}

365
src/styles/scss/main.scss

@ -88,7 +88,20 @@ $fontV: 20;//random(1000)
transform: $v;
}
//.#{$app-prefix}fonts {}
$colorActive: #71b7f1;
$colorWarn: #ffca6f;
.#{$app-prefix}active {
&-color {
color: $colorActive;
}
}
.#{$app-prefix}warn {
&-color {
color: $colorWarn;
}
}
.#{$app-prefix}fonts::before {
display: block;
@ -149,12 +162,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 {
@ -528,6 +543,10 @@ ol.example li.placeholder:before {position: absolute;}
/************* Navigator *************/
.#{$nv-prefix}selected-parent {
border: 1px solid $colorYell;
}
.#{$nv-prefix}opac50{
@include opacity(0.50);
}
@ -734,345 +753,9 @@ $lightBorder: rgba(255, 255, 255, 0.05);
/********* Style Manager **********/
.#{$sm-prefix}close-btn{
display:block;
font-size: 23px;
position: absolute;
cursor: pointer;
right: 5px;
top: 0;
@include opacity(0.2);
&:hover{ @include opacity(0.7); }
}
.#{$sm-prefix}header {
font-size: 11px;
font-weight: lighter;
padding: 10px;
}
.#{$sm-prefix}sector {
clear:both;
font-weight: lighter;
text-align:left;
##{$sm-prefix}caret{
padding-right: 5px;
font-size: 11px;
}
&.#{$sm-prefix}open {
@extend .#{$app-prefix}category-open;
}
.#{$sm-prefix}title {
@extend .#{$app-prefix}category-title;
}
.#{$sm-prefix}label {
margin: 5px 5px 2px 0;
}
/*------------------Field--------------------*/
.#{$sm-prefix}field {
width: 100%;
position:relative;
input, select {
background-color: transparent;
color: $mainLhlColor;
border:none;
width: 100%;
}
input {
box-sizing: border-box;
}
select {
position: relative;
z-index:1;
@include appearance(none);
&::-ms-expand { display: none;}
}
select:-moz-focusring{
color: transparent;
text-shadow: 0 0 0 $mainLhlColor;
}
select:focus, input:focus{
outline: none;
}
.#{$sm-prefix}unit {
position: absolute;
right: 10px; top: 3px;
font-size: 10px;
color: $mainLhlColor;
cursor:pointer;
}
.#{$sm-prefix}int-arrows, .#{$sm-prefix}sel-arrow, .#{$clm-prefix}sel-arrow{
height: 100%; width: 9px;
position: absolute;
right: 0; top: 0;
cursor: ns-resize;
}
.#{$sm-prefix}sel-arrow{ cursor:pointer }
.#{$sm-prefix}u-arrow, .#{$sm-prefix}d-arrow, .#{$sm-prefix}d-s-arrow, .#{$clm-prefix}d-s-arrow{
position: absolute;
height: 0; width: 0;
border-left: 3px solid transparent;
border-right: 4px solid transparent;
cursor:pointer;
}
.#{$sm-prefix}u-arrow {
border-bottom: 4px solid $mainLhlColor;
top: 4px;
}
.#{$sm-prefix}d-arrow, .#{$sm-prefix}d-s-arrow, .#{$clm-prefix}d-s-arrow{
border-top: 4px solid $mainLhlColor;
bottom: 4px;
}
.#{$sm-prefix}d-s-arrow, .#{$clm-prefix}d-s-arrow{ bottom: 7px; }
&.#{$sm-prefix}integer, &.#{$sm-prefix}select, &.#{$sm-prefix}list, &.#{$sm-prefix}color, &.#{$sm-prefix}input {
background-color: $mainDkColor;/*353535*/
border: 1px solid rgba(0, 0, 0, 0.1);/*292929*/
box-shadow: 1px 1px 0 $mainLhColor;/*575757*/
color: $mainLhlColor;
border-radius: 2px;
box-sizing: border-box;
padding: 0 5px;
}
&.#{$sm-prefix}composite{
@extend .#{$app-prefix}color-main;
border-radius: 2px;
}
&.#{$sm-prefix}select{ padding:0; }
&.#{$sm-prefix}select select{ height: 20px; }
&.#{$sm-prefix}select option { padding: 3px 0;}
&.#{$sm-prefix}composite{
background-color: rgba(0,0,0,0.1);
border: 1px solid rgba(0, 0, 0, 0.25);
}
&.#{$sm-prefix}list{
width:auto;
padding:0;
overflow: hidden;
float:left;
input{ display:none; }
label{ cursor:pointer; padding: 5px; display:block;}
.#{$sm-prefix}radio:checked + label{
background-color: rgba(255, 255, 255, 0.2);/*5b5b5b*/
}
.#{$sm-prefix}icon{
background-repeat: no-repeat;
background-position:center;
text-shadow: none;
line-height: normal;
//padding: 5px 19px;
}
}
&.#{$sm-prefix}integer select{ width:auto; padding: 0;}
@import "gjs_style_manager";
}
/*------------------END Field--------------------*/
.#{$sm-prefix}list .#{$sm-prefix}el{
float:left;
border-left: 1px solid $mainDkColor;
&:first-child{border:none}
&:hover{background: $mainDkColor; }
}
.#{$sm-prefix}properties {
font-size: 11px;
padding: 10px 5px;
}
/*------------------Property--------------------*/
.#{$sm-prefix}property{
box-sizing: border-box;
float:left; width:50%;
margin-bottom: 5px;
padding: 0 5px;
&.#{$sm-prefix}file, &.#{$sm-prefix}composite, &.#{$sm-prefix}stack, &.#{$sm-prefix}list{
width:100%;
}
.#{$sm-prefix}btn{
background-color: lighten($mainDkColor, 13%);/*#5d5d5d*/
border-radius: 2px;
box-shadow: 1px 1px 0 lighten($mainDkColor, 2%), 1px 1px 0 lighten($mainDkColor, 17%) inset;
padding: 5px;
position: relative;
text-align: center;
height: auto; width: 100%;
cursor: pointer;
color: $fontColor;
box-sizing: border-box;
text-shadow: -1px -1px 0 $mainDkColor;
border: none;
@include opacity(0.85);
}
.#{$sm-prefix}btn-c {
box-sizing: border-box;
float: left;
width: 100%;
padding: 0 5px;
}
&.#{$sm-prefix}file ##{$sm-prefix}preview-box {
background-color: $lightBorder;
border-radius: 2px;
margin-top: 5px;
position:relative;
overflow: hidden;
&.#{$sm-prefix}show{
border: 1px solid darken($lightBorder,1%);
padding: 3px 5px;
}
##{$sm-prefix}close{
@extend .#{$sm-prefix}close-btn;
display:block;
}
}
&.#{$sm-prefix}file .#{$sm-prefix}show ##{$sm-prefix}preview-file{ height: 50px;}
&.#{$sm-prefix}file ##{$sm-prefix}preview-file {
background-size: auto 100%;
background-repeat: no-repeat;
background-position: center center;
}
.#{$sm-prefix}layers {
margin-top: 5px;
min-height: 30px;
}
.#{$sm-prefix}layer {
background-color: rgba(255, 255, 255, 0.055);
border-radius: 2px;
box-shadow: 1px 1px 0 rgba(0,0,0,0.2), 1px 1px 0 rgba(255, 255, 255, 0.055) inset;
margin: 2px;
padding: 7px;
position: relative;
cursor: pointer;
> ##{$sm-prefix}preview-box {
@extend .checker-bg;
height: 15px;
position: absolute;
right: 27px;
top: 6px;
width: 15px;
}
##{$sm-prefix}preview-box, ##{$sm-prefix}preview{
border-radius:2px;
}
##{$sm-prefix}close-layer{
display:block;
font-size: 23px;
position: absolute;
cursor: pointer;
right: 5px;
top: 0;
@include opacity(0.5);
&:hover{
@include opacity(0.8);
}
}
> ##{$sm-prefix}preview-box ##{$sm-prefix}preview {
background-color: white;
height: 100%;
width: 100%;
background-size: cover !important;
}
&.#{$sm-prefix}active {
background-color: rgba(255, 255, 255, 0.12);
}
&.#{$sm-prefix}no-preview ##{$sm-prefix}preview-box{
display:none;
}
}
}
##{$sm-prefix}text-shadow ##{$sm-prefix}preview::after {
color: #000;
content: "T";
font-weight: 900;
line-height: 17px;
padding: 0 4px;
}
/*------------------END Property--------------------*/
.#{$sm-prefix}stack .#{$sm-prefix}properties{padding-top: 5px;}
.#{$sm-prefix}stack ##{$sm-prefix}add {
@extend .#{$app-prefix}color-main;
background: none;
border: none;
cursor: pointer;
font-size: 22px;
line-height: 10px;
position: absolute;
right: 0; top: -20px;
opacity: 0.75;
&:hover{ @include opacity(1); }
}
.#{$sm-prefix}colorp-c {
@extend .#{$app-prefix}bg-main;
height: 100%; width: 20px;
position: absolute;
right: 0; top: 0;
box-sizing: border-box;
border-radius: 2px;
padding: 2px;
.#{$app-prefix}checker-bg{
height: 100%; width: 100%;
border-radius: 1px;
}
}
.#{$sm-prefix}color-picker {
background-color: $fontColor;
cursor: pointer;
height: 16px;
width: 100%;
margin-top: -16px;
box-shadow: 0 0 1px $mainDkColor;
border-radius: 1px;
}
.#{$sm-prefix}btn-upload ##{$sm-prefix}upload {
left: 0; top: 0;
position: absolute;
width: 100%;
opacity: 0;
cursor: pointer;
}
.#{$sm-prefix}btn-upload ##{$sm-prefix}label { padding: 2px 0;}
}
.#{$sm-prefix}layer > ##{$sm-prefix}move {
@include opacity(0.7);
cursor: move;
font-size: 12px;
float: left;
margin: 0 5px 0 0;
&:hover{
@include opacity(0.9);
}
}
/********* END Style Manager **********/
/********* Blocks **********/
@import "gjs_blocks";

339
src/utils/Sorter.js

@ -26,6 +26,8 @@ module.exports = Backbone.View.extend({
this.direction = o.direction || 'v'; // v (vertical), h (horizontal), a (auto)
this.onMoveClb = o.onMove || '';
this.relative = o.relative || 0;
this.ignoreViewChildren = o.ignoreViewChildren || 0;
this.ignoreModels = o.ignoreModels || 0;
this.plh = o.placer || '';
// Frame offset
this.wmargin = o.wmargin || 0;
@ -81,11 +83,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 +112,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;
@ -132,10 +136,12 @@ module.exports = Backbone.View.extend({
* @param {Event} e
*/
moveDragHelper(e) {
if(!this.dragHelper) {
var doc = e.target.ownerDocument;
if(!this.dragHelper || !doc) {
return;
}
var doc = e.target.ownerDocument;
var win = doc.defaultView || doc.parentWindow;
var addTop = 0;
var addLeft = 0;
@ -216,23 +222,27 @@ module.exports = Backbone.View.extend({
/**
* Picking component to move
* @param {HTMLElement} trg
* @param {HTMLElement} src
* */
startSort(trg) {
startSort(src) {
this.dropModel = null;
this.moved = 0;
this.eV = trg;
//this.$document = $([document, trg.ownerDocument]);
if(src && !this.matches(src, this.itemSel + ',' + this.containerSel))
src = this.closest(src, this.itemSel);
if(trg && !this.matches(trg, this.itemSel + ',' + this.containerSel))
this.eV = this.closest(trg, this.itemSel);
this.eV = src;
// Create placeholder if not exists
if(!this.plh) {
if (!this.plh) {
this.plh = this.createPlaceholder();
this.getContainerEl().appendChild(this.plh);
}
if(this.eV) {
this.eV.className += ' ' + this.freezeClass;
if (src) {
var srcModel = this.getSourceModel();
srcModel && srcModel.set && srcModel.set('status', 'freezed');
this.$document.on('mouseup', this.endMove);
}
@ -251,6 +261,60 @@ module.exports = Backbone.View.extend({
this.toggleSortCursor(1);
},
/**
* Get the model from HTMLElement target
* @return {Model|null}
*/
getTargetModel(el) {
let elem = el || this.target;
return $(elem).data('model');
},
/**
* Get the model of the current source element (element to drag)
* @return {Model}
*/
getSourceModel() {
var src = this.eV;
let dropContent = this.dropContent;
let dropModel = this.dropModel;
const em = this.em;
if (dropContent && em) {
if (!dropModel) {
let comps = em.get('DomComponents').getComponents();
let tempModel = comps.add(dropContent, {avoidUpdateStyle: 1});
dropModel = comps.remove(tempModel);
this.dropModel = dropModel instanceof Array ? dropModel[0] : dropModel;
}
return dropModel;
}
if (src) {
return $(src).data('model');
}
},
/**
* Highlight target
* @param {Model|null} model
*/
selectTargetModel(model) {
if (model instanceof Backbone.Collection) {
return;
}
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 +342,10 @@ module.exports = Backbone.View.extend({
}
var dims = this.dimsFromTarget(e.target, rX, rY);
let targetModel = this.getTargetModel(this.target);
this.selectTargetModel(targetModel);
this.lastDims = dims;
var pos = this.findPosition(dims, rX, rY);
// If there is a significant changes with the pointer
@ -361,6 +429,51 @@ module.exports = Backbone.View.extend({
return;
},
/**
* Check if the target is valid with the actual source
* @param {HTMLElement} trg
* @return {Boolean}
*/
validTarget(trg) {
let srcModel = this.getSourceModel();
let src = srcModel && srcModel.view && srcModel.view.el;
let trgModel = this.getTargetModel(trg);
trg = trgModel && trgModel.view && trgModel.view.el;
let result = {
valid: true,
src,
srcModel,
trg,
trgModel
};
if (!src || !trg) {
result.valid = false;
return result;
}
// Check if the target could accept the source
let droppable = trgModel.get('droppable');
droppable = droppable instanceof Backbone.Collection ? 1 : droppable;
droppable = droppable instanceof Array ? droppable.join(', ') : droppable;
result.dropInfo = droppable;
droppable = typeof droppable === 'string' ? src.matches(droppable) : droppable;
result.droppable = droppable;
// check if the source is draggable in target
let draggable = srcModel.get('draggable');
draggable = draggable instanceof Array ? draggable.join(', ') : draggable;
result.dragInfo = draggable;
draggable = typeof draggable === 'string' ? trg.matches(draggable) : draggable;
result.draggable = draggable;
if (!droppable || !draggable) {
result.valid = false;
}
return result;
},
/**
* Get dimensions of nodes relative to the coordinates
* @param {HTMLElement} target
@ -371,30 +484,39 @@ module.exports = Backbone.View.extend({
dimsFromTarget(target, rX, rY) {
var dims = [];
if (!target) {
return dims;
}
// Select the first valuable target
// TODO: avoid this check for every standard component,
// which generally is ok
if(!this.matches(target, this.itemSel + ',' + this.containerSel))
if (!target.matches(`${this.itemSel}, ${this.containerSel}`)) {
target = this.closest(target, this.itemSel);
}
// If draggable is an array the target will be one of those
if(this.draggable instanceof Array){
target = this.closest(target, this.draggable.join(','));
if (this.draggable instanceof Array) {
target = this.closest(target, this.draggable.join(','));
}
if(!target)
if (!target) {
return dims;
}
// Check if the target is different from the previous one
if(this.prevTarget){
if(this.prevTarget != target){
if (this.prevTarget && this.prevTarget != target) {
this.prevTarget = null;
}
}
// New target encountered
if(!this.prevTarget){
// New target found
if (!this.prevTarget) {
this.targetP = this.closest(target, this.containerSel);
// Check if the source is valid with the target
let validResult = this.validTarget(target);
if (!validResult.valid && this.targetP) {
return this.dimsFromTarget(this.targetP, rX, rY);
}
this.prevTarget = target;
this.prevTargetDim = this.getDim(target);
this.cacheDimsP = this.getChildrenDim(this.targetP);
@ -407,13 +529,18 @@ module.exports = Backbone.View.extend({
// Target when I will drop element to sort
this.target = this.prevTarget;
// Generally also on every new target the poiner enters near
// to borders, so have to to check always
if(this.nearBorders(this.prevTargetDim, rX, rY) ||
(!this.nested && !this.cacheDims.length)){
dims = this.cacheDimsP;
this.target = this.targetP;
(!this.nested && !this.cacheDims.length)) {
if (!this.validTarget(this.targetP).valid) {
return this.dimsFromTarget(this.targetP, rX, rY);
}
dims = this.cacheDimsP;
this.target = this.targetP;
}
this.lastPos = null;
return dims;
},
@ -428,10 +555,15 @@ module.exports = Backbone.View.extend({
if (this.canvasRelative && this.em) {
var pos = this.em.get('Canvas').getElementPos(el);
top = pos.top;
left = pos.left;
height = pos.height;
width = pos.width;
var styles = window.getComputedStyle(el);
var marginTop = parseFloat(styles['marginTop']);
var marginBottom = parseFloat(styles['marginBottom']);
var marginRight = parseFloat(styles['marginRight']);
var marginLeft = parseFloat(styles['marginLeft']);
top = pos.top - marginTop;
left = pos.left - marginLeft;
height = pos.height + marginTop + marginBottom;
width = pos.width + marginLeft + marginRight;
} else {
var o = this.offset(el);
top = this.relative ? el.offsetTop : o.top - (this.wmargin ? -1 : 1) * this.elT;
@ -450,23 +582,26 @@ module.exports = Backbone.View.extend({
* @param {HTMLELement} el Element root
* @retun {Array}
* */
getChildrenDim(elem) {
getChildrenDim(trg) {
var dims = [];
if(!elem)
if(!trg)
return dims;
// Get children based on getChildrenContainer
var $elem = $(elem);
var elemData = $elem.data('model');
if (elemData && elemData.view) {
elem = elemData.view.getChildrenContainer();
var trgModel = this.getTargetModel(trg);
if (trgModel && trgModel.view && !this.ignoreViewChildren) {
trg = trgModel.view.getChildrenContainer();
}
var ch = elem.children; //TODO filter match
var ch = trg.children;
for (var i = 0, len = ch.length; i < len; i++) {
var el = ch[i];
if(!this.matches(el, this.itemSel))
if (!el.matches(this.itemSel)) {
continue;
}
var dim = this.getDim(el);
var dir = this.direction;
@ -475,12 +610,13 @@ module.exports = Backbone.View.extend({
else if(dir == 'h')
dir = false;
else
dir = this.isInFlow(el, elem);
dir = this.isInFlow(el, trg);
dim.push(dir);
dim.push(el);
dims.push(dim);
}
return dims;
},
@ -623,10 +759,18 @@ 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 src = this.eV;
if (src) {
var srcModel = this.getSourceModel();
if (srcModel && srcModel.set) {
srcModel.set('status', '');
srcModel.set('status', 'selected');
}
}
if(this.moved)
created = this.move(this.target, this.eV, this.lastPos);
created = this.move(this.target, src, this.lastPos);
if(this.plh)
this.plh.style.display = 'none';
@ -634,10 +778,13 @@ module.exports = Backbone.View.extend({
this.onEndMove(created);
var dragHelper = this.dragHelper;
if(dragHelper) {
dragHelper.remove();
this.dragHelper = null;
}
this.selectTargetModel();
this.toggleSortCursor();
},
@ -649,101 +796,63 @@ module.exports = Backbone.View.extend({
* */
move(dst, src, pos) {
var em = this.em;
if (em) em.trigger('component:dragEnd:before', dst, src, pos);
em && em.trigger('component:dragEnd:before', dst, src, pos);
var warns = [];
var modelToDrop, modelTemp, created;
var index = pos.index;
var model = $(src).data('model');
var $dst = $(dst);
var targetModel;
while ($dst.length && !targetModel) {
targetModel = $dst.data('model');
dst = $dst.get(0);
if (targetModel && targetModel.view)
dst = targetModel.view.el;
if (!targetModel)
$dst = $dst.parent();
}
var targetCollection = $dst.data('collection');
// Check if the elemenet is DRAGGABLE to the target
var drag = model && model.get('draggable');
var draggable = typeof drag !== 'undefined' ? drag : 1;
var toDrag = draggable;
if (this.dropContent instanceof Object) {
draggable = this.dropContent.draggable;
draggable = typeof draggable !== 'undefined' ? draggable : 1;
} else if (typeof this.dropContent === 'string' && targetCollection) {
var sandboxOpts = {silent: true};
var sandboxModel = targetCollection.add(this.dropContent, sandboxOpts);
draggable = sandboxModel.get && sandboxModel.get('draggable');
draggable = typeof draggable !== 'undefined' ? draggable : 1;
targetCollection.remove(sandboxModel, sandboxOpts);
}
if(draggable instanceof Array) {
toDrag = draggable.join(', ');
draggable = this.matches(dst, toDrag);
}else if(typeof draggable === 'string') {
toDrag = draggable;
draggable = this.matches(dst, toDrag, 1);
}
// Check if the target could accept the element to be DROPPED inside
var accepted = 1;
var droppable = targetModel && targetModel.get ? targetModel.get('droppable') : 1;
var toDrop = draggable;
if(droppable instanceof Array) {
// When I drag blocks src is the HTMLElement of the block
toDrop = droppable.join(', ');
accepted = this.matches(src, toDrop);
}else if(typeof droppable === 'string') {
toDrop = droppable;
accepted = this.matches(src, toDrop);
}
if(targetCollection && droppable && accepted && draggable) {
var modelToDrop, modelTemp, created;
var validResult = this.validTarget(dst);
var targetCollection = $(dst).data('collection');
var model = validResult.srcModel;
var droppable = validResult.droppable;
var draggable = validResult.draggable;
var dropInfo = validResult.dropInfo;
var dragInfo = validResult.dragInfo;
var dropContent = this.dropContent;
droppable = validResult.trgModel instanceof Backbone.Collection ? 1 : droppable;
if (targetCollection && droppable && draggable) {
index = pos.method === 'after' ? index + 1 : index;
var opts = {at: index, noIncrement: 1};
if(!this.dropContent){
if (!dropContent) {
modelTemp = targetCollection.add({}, opts);
if(model)
modelToDrop = model.collection.remove(model);
}else{
modelToDrop = this.dropContent;
if (model) {
modelToDrop = model.collection.remove(model);
}
} else {
modelToDrop = dropContent;
opts.silent = false;
opts.avoidUpdateStyle = 1;
}
created = targetCollection.add(modelToDrop, opts);
if(!this.dropContent){
if (!dropContent) {
targetCollection.remove(modelTemp);
}else{
} else {
this.dropContent = null;
}
// This will cause to recalculate children dimensions
this.prevTarget = null;
} else {
if(!targetCollection){
warns.push('target collection not found');
}
if(!droppable){
warns.push('target is not droppable');
if (!targetCollection) {
warns.push('Target collection not found');
}
if(!draggable){
warns.push('component not draggable, accepted only by [' + toDrag + ']');
if (!droppable) {
warns.push(`Target is not droppable, accepts [${dropInfo}]`);
}
if(!accepted){
warns.push('target accepts only [' + toDrop + ']');
if (!draggable) {
warns.push(`Component not draggable, acceptable by [${dragInfo}]`);
}
console.warn('Invalid target position: ' + warns.join(', '));
}
if (em)
em.trigger('component:dragEnd', targetCollection, modelToDrop, warns);
em && em.trigger('component:dragEnd', targetCollection, modelToDrop, warns);
return created;
},

14
test/helper.js

@ -23,6 +23,18 @@ Module.prototype.require = function(name) {
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.$ = $;
@ -31,6 +43,8 @@ global.expect = expect;
global.sinon = sinon;
global.grapesjs = grapesjs;
global.Backbone = Backbone;
global.localStorage = localStorage;
global.SVGElement = global.Element;
window.$ = $;
Backbone.$ = $;

4
test/main.js

@ -21,4 +21,8 @@ describe('Main', () => {
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`);
});

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

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

82
test/specs/selector_manager/index.js

@ -0,0 +1,82 @@
var SelectorManager = require('selector_manager');
var Models = require('./model/SelectorModels');
var ClassTagView = require('./view/ClassTagView');
var ClassTagsView = require('./view/ClassTagsView');
var e2e = require('./e2e/ClassManager');
describe('SelectorManager', () => {
describe('Main', () => {
var obj;
beforeEach(() => {
obj = new SelectorManager().init();
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(obj).toExist();
});
it('No selectors inside', () => {
expect(obj.getAll().length).toEqual(0);
});
it('Able to add default selectors', () => {
var cm = new SelectorManager().init({
selectors: ['test1', 'test2', 'test3'],
});
expect(cm.getAll().length).toEqual(3);
});
it('Add new selector', () => {
obj.add('test');
expect(obj.getAll().length).toEqual(1);
});
it('Default new selector is a class type', () => {
obj.add('test');
expect(obj.get('test').get('type')).toEqual('class');
});
it('Check name property', () => {
var name = 'test';
var sel = obj.add(name);
expect(sel.get('name')).toEqual(name);
expect(sel.get('label')).toEqual(name);
});
it('Add 2 selectors', () => {
obj.add('test');
obj.add('test2');
expect(obj.getAll().length).toEqual(2);
});
it('Adding 2 selectors with the same name is not possible', () => {
obj.add('test');
obj.add('test');
expect(obj.getAll().length).toEqual(1);
});
it('Get selector', () => {
var name = 'test';
var sel = obj.add(name);
expect(obj.get(name)).toEqual(sel);
});
it('Get empty class', () => {
expect(obj.get('test')).toEqual(undefined);
});
});
Models.run();
ClassTagView.run();
ClassTagsView.run();
e2e.run();
});

82
test/specs/selector_manager/main.js

@ -1,82 +0,0 @@
define(function(require, exports, module){
'use strict';
var SelectorManager = require('SelectorManager');
var e2e = require('undefined');
describe('SelectorManager', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new SelectorManager().init();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
obj.should.be.exist;
});
it('No selectors inside', function() {
obj.getAll().length.should.equal(0);
});
it('Able to add default selectors', function() {
var cm = new SelectorManager().init({
selectors: ['test1', 'test2', 'test3'],
});
cm.getAll().length.should.equal(3);
});
it('Add new selector', function() {
obj.add('test');
obj.getAll().length.should.equal(1);
});
it('Default new selector is a class type', function() {
obj.add('test');
obj.get('test').get('type').should.equal('class');
});
it('Check name property', function() {
var name = 'test';
var sel = obj.add(name);
sel.get('name').should.equal(name);
sel.get('label').should.equal(name);
});
it('Add 2 selectors', function() {
obj.add('test');
obj.add('test2');
obj.getAll().length.should.equal(2);
});
it('Adding 2 selectors with the same name is not possible', function() {
obj.add('test');
obj.add('test');
obj.getAll().length.should.equal(1);
});
it('Get selector', function() {
var name = 'test';
var sel = obj.add(name);
obj.get(name).should.deep.equal(sel);
});
it('Get empty class', function() {
(obj.get('test') === undefined).should.equal(true);
});
});
Models.run();
ClassTagView.run();
ClassTagsView.run();
e2e.run();
});
});

76
test/specs/selector_manager/model/SelectorModels.js

@ -1,52 +1,50 @@
define(function(require, exports, module){
'use strict';
var Selectors = require('undefined');
const Selector = require('selector_manager/model/Selector');
const Selectors = require('selector_manager/model/Selectors');
module.exports = {
run : function(){
describe('Selector', function() {
module.exports = {
run() {
describe('Selector', () => {
var obj;
beforeEach(function () {
this.obj = new Selector();
});
afterEach(function () {
delete this.obj;
});
it('Has name property', function() {
this.obj.has('name').should.equal(true);
});
beforeEach(() => {
obj = new Selector();
});
it('Has label property', function() {
this.obj.has('label').should.equal(true);
});
afterEach(() => {
obj = null;
});
it('Has active property', function() {
this.obj.has('active').should.equal(true);
});
it('Has name property', () => {
expect(obj.has('name')).toEqual(true);
});
it('escapeName test', function() {
this.obj.escapeName('@Te sT*').should.equal('-Te-sT-');
});
it('Has label property', () => {
expect(obj.has('label')).toEqual(true);
});
it('Name is corrected at instantiation', function() {
this.obj = new Selector({ name: '@Te sT*'});
this.obj.get('name').should.equal('-Te-sT-');
});
it('Has active property', () => {
expect(obj.has('active')).toEqual(true);
});
it('escapeName test', () => {
expect(obj.escapeName('@Te sT*')).toEqual('-Te-sT-');
});
it('Name is corrected at instantiation', () => {
obj = new Selector({ name: '@Te sT*'});
expect(obj.get('name')).toEqual('-Te-sT-');
});
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);
});
}
};
});
});
}
};

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

@ -1,133 +1,129 @@
define(function(require, exports, module){
'use strict';
var ClassTagView = require('undefined');
var Selectors = require('SelectorManager/model/Selectors');
module.exports = {
run : function(){
describe('ClassTagView', function() {
var obj;
var fixture;
var fixtures;
var testLabel;
var coll;
before(function () {
fixtures = $("#fixtures");
fixture = $('<div class="classtag-fixture"></div>');
});
const ClassTagView = require('selector_manager/view/ClassTagView');
const Selectors = require('selector_manager/model/Selectors');
module.exports = {
run() {
describe('ClassTagView', () => {
var obj;
var fixture;
var fixtures;
var testLabel;
var coll;
before(() => {
fixtures = $("#fixtures");
fixture = $('<div class="classtag-fixture"></div>');
});
beforeEach(function () {
coll = new Selectors();
testLabel = 'TestLabel';
var model = coll.add({
name: 'test',
label: testLabel,
});
obj = new ClassTagView({
config : {},
model: model,
coll: coll
});
obj.target = { get:function(){} };
_.extend(obj.target, Backbone.Events);
fixture.empty().appendTo(fixtures);
fixture.html(obj.render().el);
});
beforeEach(() => {
coll = new Selectors();
testLabel = 'TestLabel';
var model = coll.add({
name: 'test',
label: testLabel,
});
obj = new ClassTagView({
config : {},
model,
coll
});
obj.target = { get() {} };
_.extend(obj.target, Backbone.Events);
fixture.empty().appendTo(fixtures);
fixture.html(obj.render().el);
});
afterEach(function () {
delete obj.model;
});
afterEach(() => {
obj.model = null;
});
after(function () {
fixture.remove();
});
after(() => {
fixture.remove();
});
it('Object exists', function() {
ClassTagView.should.be.exist;
});
it('Object exists', () => {
expect(ClassTagView).toExist();
});
it('Not empty', () => {
var $el = obj.$el;
expect($el.html()).toExist();
});
it('Not empty', () => {
var $el = obj.$el;
expect($el.html()).toContain(testLabel);
});
describe('Should be rendered correctly', () => {
it('Not empty', function() {
it('Has close button', () => {
var $el = obj.$el;
$el.html().should.not.be.empty;
expect($el.find('#close')[0]).toExist();
});
it('Not empty', function() {
it('Has checkbox', () => {
var $el = obj.$el;
$el.html().should.contain(testLabel);
expect($el.find('#checkbox')[0]).toExist();
});
describe('Should be rendered correctly', function() {
it('Has close button', function() {
var $el = obj.$el;
$el.find('#close').should.have.property(0);
});
it('Has checkbox', function() {
var $el = obj.$el;
$el.find('#checkbox').should.have.property(0);
});
it('Has label', function() {
var $el = obj.$el;
$el.find('#tag-label').should.have.property(0);
});
it('Has label', () => {
var $el = obj.$el;
expect($el.find('#tag-label')[0]).toExist();
});
it('Could be removed', function() {
var spy = sinon.spy();
obj.config.target = { get:function(){} };
sinon.stub(obj.config.target, 'get').returns(0);
obj.$el.find('#close').trigger('click');
fixture.html().should.be.empty;
});
});
it('On remove triggers event', function() {
var spy = sinon.spy();
sinon.stub(obj.target, 'get').returns(0);
obj.target.on("targetClassRemoved", spy);
obj.$el.find('#close').trigger('click');
spy.called.should.equal(true);
});
it('Could be removed', () => {
var spy = sinon.spy();
obj.config.target = { get() {} };
sinon.stub(obj.config.target, 'get').returns(0);
obj.$el.find('#close').trigger('click');
expect(fixture.html()).toNotExist();
});
it('Checkbox toggles status', function() {
var spy = sinon.spy();
obj.model.on("change:active", spy);
obj.model.set('active', true);
obj.$el.find('#checkbox').trigger('click');
obj.model.get('active').should.equal(false);
spy.called.should.equal(true);
});
it('On remove triggers event', () => {
var spy = sinon.spy();
sinon.stub(obj.target, 'get').returns(0);
obj.target.on("targetClassRemoved", spy);
obj.$el.find('#close').trigger('click');
expect(spy.called).toEqual(true);
});
it('On toggle triggers event', function() {
var spy = sinon.spy();
sinon.stub(obj.target, 'get').returns(0);
obj.target.on("targetClassUpdated", spy);
obj.$el.find('#checkbox').trigger('click');
spy.called.should.equal(true);
});
it('Checkbox toggles status', () => {
var spy = sinon.spy();
obj.model.on("change:active", spy);
obj.model.set('active', true);
obj.$el.find('#checkbox').trigger('click');
expect(obj.model.get('active')).toEqual(false);
expect(spy.called).toEqual(true);
});
it('Label input is disabled', function() {
var inputProp = obj.inputProp;
obj.$labelInput.prop(inputProp).should.equal(true);
});
it('On toggle triggers event', () => {
var spy = sinon.spy();
sinon.stub(obj.target, 'get').returns(0);
obj.target.on("targetClassUpdated", spy);
obj.$el.find('#checkbox').trigger('click');
expect(spy.called).toEqual(true);
});
it('On double click label input is enable', function() {
var inputProp = obj.inputProp;
obj.$el.find('#tag-label').trigger('dblclick');
obj.$labelInput.prop(inputProp).should.equal(false);
});
it('Label input is disabled', () => {
var inputProp = obj.inputProp;
expect(obj.$labelInput.prop(inputProp)).toEqual(true);
});
it('On blur label input turns back disabled', function() {
var inputProp = obj.inputProp;
obj.$el.find('#tag-label').trigger('dblclick');
obj.endEditTag();
obj.$labelInput.prop(inputProp).should.equal(true);
});
it('On double click label input is enable', () => {
var inputProp = obj.inputProp;
obj.$el.find('#tag-label').trigger('dblclick');
expect(obj.$labelInput.prop(inputProp)).toEqual(false);
});
it('On blur label input turns back disabled', () => {
var inputProp = obj.inputProp;
obj.$el.find('#tag-label').trigger('dblclick');
obj.endEditTag();
expect(obj.$labelInput.prop(inputProp)).toEqual(true);
});
}
};
});
});
}
};

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

@ -1,196 +1,195 @@
define(function(require, exports, module){
'use strict';
var ClassTagsView = require('undefined');
var Selectors = require('SelectorManager/model/Selectors');
module.exports = {
run : function(){
describe('ClassTagsView', function() {
var view;
var fixture;
var fixtures;
var testLabel;
var coll;
var target;
before(function () {
fixtures = $("#fixtures");
fixture = $('<div class="classtag-fixture"></div>');
});
beforeEach(function () {
target = { get: function(){} };
coll = new Selectors();
_.extend(target, Backbone.Events);
view = new ClassTagsView({
config : { em: target },
collection: coll
});
this.targetStub = {
add: function(v){ return {name: v}; }
};
this.compTargetStub = {
get: function(){ return { add: function(){} }}
};
fixture.empty().appendTo(fixtures);
fixture.html(view.render().el);
this.btnAdd = view.$el.find('#' + view.addBtnId);
this.input = view.$el.find('input#' + view.newInputId);
this.$tags = fixture.find('#tags-c');
this.$states = fixture.find('#states');
this.$statesC = fixture.find('#input-c');
});
afterEach(function () {
delete view.collection;
});
after(function () {
fixture.remove();
});
it('Object exists', function() {
ClassTagsView.should.be.exist;
});
it('Not tags inside', function() {
this.$tags.html().should.equal('');
});
it('Add new tag triggers correct method', function() {
sinon.stub(view, "addToClasses");
coll.add({ name: 'test' });
view.addToClasses.calledOnce.should.equal(true);
});
it('Start new tag creation', function() {
this.btnAdd.click();
(this.btnAdd.css('display') == 'none').should.equal(true);
(this.input.css('display') !== 'none').should.equal(true);
});
it('Stop tag creation', function() {
this.btnAdd.click();
this.input.val('test')
this.input.blur();
(this.btnAdd.css('display') !== 'none').should.equal(true);
(this.input.css('display') == 'none').should.equal(true);
this.input.val().should.equal('');
});
it('Check keyup of ESC on input', function() {
this.btnAdd.click();
sinon.stub(view, "addNewTag");
this.input.trigger({
type: 'keyup',
keyCode: 13
});
view.addNewTag.calledOnce.should.equal(true);
});
it('Check keyup on ENTER on input', function() {
this.btnAdd.click();
sinon.stub(view, "endNewTag");
this.input.trigger({
type: 'keyup',
keyCode: 27
});
view.endNewTag.calledOnce.should.equal(true);
});
it('Collection changes on update of target', function() {
coll.add({ name: 'test' });
target.trigger('change:selectedComponent');
coll.length.should.equal(0);
});
it('Collection reacts on reset', function() {
coll.add([{ name: 'test1' }, { name: 'test2' }]);
sinon.stub(view, "addToClasses");
coll.trigger('reset');
view.addToClasses.calledTwice.should.equal(true);
});
it("Don't accept empty tags", function() {
view.addNewTag('');
this.$tags.html().should.equal('');
});
it("Accept new tags", function() {
sinon.stub(target, "get").returns(this.targetStub);
view.compTarget = this.compTargetStub;
view.addNewTag('test');
view.compTarget = this.compTargetStub;
view.addNewTag('test2');
this.$tags.children().length.should.equal(2);
});
it("New tag correctly added", function() {
coll.add({ label: 'test' });
this.$tags.children().first().find('#tag-label input').val().should.equal('test');
});
it("States are hidden in case no tags", function() {
view.updateStateVis();
this.$statesC.css('display').should.equal('none');
});
it("States are visible in case of more tags inside", function() {
coll.add({ label: 'test' });
view.updateStateVis();
this.$statesC.css('display').should.equal('block');
});
it("Update state visibility on new tag", function() {
sinon.stub(view, "updateStateVis");
sinon.stub(target, "get").returns(this.targetStub);
view.compTarget = this.compTargetStub;
view.addNewTag('test');
view.updateStateVis.called.should.equal(true);
});
it("Update state visibility on removing of the tag", function() {
sinon.stub(target, "get").returns(this.targetStub);
view.compTarget = this.compTargetStub;
view.addNewTag('test');
sinon.stub(view, "updateStateVis");
coll.remove(coll.at(0));
view.updateStateVis.calledOnce.should.equal(true);
});
it("Output correctly state options", function() {
var view = new ClassTagsView({
config : {
em: target,
states: [ { name: 'testName', label: 'testLabel' } ],
},
collection: coll
});
view.getStateOptions().should.equal('<option value="testName">testLabel</option>');
});
describe('Should be rendered correctly', function() {
it('Has label', function() {
view.$el.find('#label').should.have.property(0);
});
it('Has tags container', function() {
view.$el.find('#tags-c').should.have.property(0);
});
it('Has add button', function() {
view.$el.find('#add-tag').should.have.property(0);
});
it('Has states input', function() {
view.$el.find('#states').should.have.property(0);
});
});
});
}
};
});
const ClassTagsView = require('selector_manager/view/ClassTagsView');
const Selectors = require('selector_manager/model/Selectors');
module.exports = {
run() {
describe('ClassTagsView', () => {
var view;
var fixture;
var fixtures;
var testLabel;
var coll;
var target;
before(() => {
fixtures = $("#fixtures");
fixture = $('<div class="classtag-fixture"></div>');
});
beforeEach(function () {
target = { get() {} };
coll = new Selectors();
_.extend(target, Backbone.Events);
view = new ClassTagsView({
config : { em: target },
collection: coll
});
this.targetStub = {
add(v) { return {name: v}; }
};
this.compTargetStub = {
get() { return { add() {} };}
};
fixture.empty().appendTo(fixtures);
fixture.html(view.render().el);
this.btnAdd = view.$el.find('#' + view.addBtnId);
this.input = view.$el.find('input#' + view.newInputId);
this.$tags = fixture.find('#tags-c');
this.$states = fixture.find('#states');
this.$statesC = fixture.find('#input-c');
});
afterEach(() => {
delete view.collection;
});
after(() => {
fixture.remove();
});
it('Object exists', () => {
expect(ClassTagsView).toExist();
});
it('Not tags inside', function() {
expect(this.$tags.html()).toEqual('');
});
it('Add new tag triggers correct method', () => {
sinon.stub(view, "addToClasses");
coll.add({ name: 'test' });
expect(view.addToClasses.calledOnce).toEqual(true);
});
it('Start new tag creation', function() {
this.btnAdd.click();
expect(this.btnAdd.css('display')).toEqual('none');
expect(this.input.css('display')).toNotEqual('none');
});
it.skip('Stop tag creation', function() {
this.btnAdd.click();
this.input.val('test')
this.input.blur();
//(this.btnAdd.css('display') !== 'none').should.equal(true);
//(this.input.css('display') == 'none').should.equal(true);
//this.input.val().should.equal('');
expect(this.btnAdd.css('display')).toNotEqual('none');
expect(this.input.css('display')).toEqual('none');
expect(this.input.val()).toEqual('');
});
it('Check keyup of ESC on input', function() {
this.btnAdd.click();
sinon.stub(view, "addNewTag");
this.input.trigger({
type: 'keyup',
keyCode: 13
});
expect(view.addNewTag.calledOnce).toEqual(true);
});
it('Check keyup on ENTER on input', function() {
this.btnAdd.click();
sinon.stub(view, "endNewTag");
this.input.trigger({
type: 'keyup',
keyCode: 27
});
expect(view.endNewTag.calledOnce).toEqual(true);
});
it('Collection changes on update of target', () => {
coll.add({ name: 'test' });
target.trigger('change:selectedComponent');
expect(coll.length).toEqual(0);
});
it('Collection reacts on reset', () => {
coll.add([{ name: 'test1' }, { name: 'test2' }]);
sinon.stub(view, "addToClasses");
coll.trigger('reset');
expect(view.addToClasses.calledTwice).toEqual(true);
});
it("Don't accept empty tags", function() {
view.addNewTag('');
expect(this.$tags.html()).toEqual('');
});
it("Accept new tags", function() {
sinon.stub(target, "get").returns(this.targetStub);
view.compTarget = this.compTargetStub;
view.addNewTag('test');
view.compTarget = this.compTargetStub;
view.addNewTag('test2');
expect(this.$tags.children().length).toEqual(2);
});
it("New tag correctly added", function() {
coll.add({ label: 'test' });
expect(this.$tags.children().first().find('#tag-label input').val()).toEqual('test');
});
it("States are hidden in case no tags", function() {
view.updateStateVis();
expect(this.$statesC.css('display')).toEqual('none');
});
it("States are visible in case of more tags inside", function() {
coll.add({ label: 'test' });
view.updateStateVis();
expect(this.$statesC.css('display')).toEqual('block');
});
it("Update state visibility on new tag", function() {
sinon.stub(view, "updateStateVis");
sinon.stub(target, "get").returns(this.targetStub);
view.compTarget = this.compTargetStub;
view.addNewTag('test');
expect(view.updateStateVis.called).toEqual(true);
});
it("Update state visibility on removing of the tag", function() {
sinon.stub(target, "get").returns(this.targetStub);
view.compTarget = this.compTargetStub;
view.addNewTag('test');
sinon.stub(view, "updateStateVis");
coll.remove(coll.at(0));
expect(view.updateStateVis.calledOnce).toEqual(true);
});
it("Output correctly state options", () => {
var view = new ClassTagsView({
config : {
em: target,
states: [ { name: 'testName', label: 'testLabel' } ],
},
collection: coll
});
expect(view.getStateOptions()).toEqual('<option value="testName">testLabel</option>');
});
describe('Should be rendered correctly', () => {
it('Has label', () => {
expect(view.$el.find('#label')[0]).toExist();
});
it('Has tags container', () => {
expect(view.$el.find('#tags-c')[0]).toExist();
});
it('Has add button', () => {
expect(view.$el.find('#add-tag')[0]).toExist();
});
it('Has states input', () => {
expect(view.$el.find('#states')[0]).toExist();
});
});
});
}
};

120
test/specs/storage_manager/index.js

@ -0,0 +1,120 @@
const StorageManager = require('storage_manager');
const Models = require('./model/Models');
describe('Storage Manager', () => {
describe('Main', () => {
var obj;
beforeEach(() => {
obj = new StorageManager().init();
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(StorageManager).toExist();
});
it('Autosave is active by default', () => {
expect(obj.isAutosave()).toEqual(true);
});
it('Change autosave', () => {
obj.setAutosave(0);
expect(obj.isAutosave()).toEqual(false);
});
it('Steps before save are set as default', () => {
expect(obj.getStepsBeforeSave()).toEqual(1);
});
it('Change steps before save', () => {
obj.setStepsBeforeSave(5);
expect(obj.getStepsBeforeSave()).toEqual(5);
});
it('No storages inside', () => {
expect(obj.getStorages()).toEqual({});
});
it('Add and get new storage', () => {
obj.add('test', 'gen');
expect(obj.get('test')).toEqual('gen');
});
it('LocalStorage is set as default', () => {
expect(obj.getCurrent()).toEqual('local');
});
it('Change storage type', () => {
obj.setCurrent('remote');
expect(obj.getCurrent()).toEqual('remote');
});
it('Store do not execute if empty', () => {
expect(obj.store({item:'test'})).toEqual(null);
});
it('Load do not execute if empty', () => {
expect(obj.load(['item'])).toEqual({});
});
it('Load default storages ', () => {
obj.loadDefaultProviders();
expect(obj.get('local')).toExist();
expect(obj.get('remote')).toExist();
expect(obj.get('test')).toNotExist();
});
describe('With custom storage', () => {
var storeValue;
var storageId = 'testStorage';
var storage = {
store(data) {
storeValue = data;
},
load(keys) {
return storeValue;
},
};
beforeEach(() => {
storeValue = [];
obj = new StorageManager().init({
type: storageId,
});
obj.add(storageId, storage);
});
afterEach(() => {
obj = null;
});
it('Store and load data', () => {
var data = {
item: 'testData',
item2: 'testData2',
};
var data2 = {};
var id = obj.getConfig().id;
data2[id + 'item'] = 'testData';
data2[id + 'item2'] = 'testData2';
obj.store(data);
var load = obj.load(['item', 'item2']);
expect(storeValue).toEqual(data2);
expect(load).toEqual(data);
});
});
});
Models.run();
});

123
test/specs/storage_manager/main.js

@ -1,123 +0,0 @@
define(function(require, exports, module){
'use strict';
var StorageManager = require('StorageManager');
var Models = require('undefined');
describe('Storage Manager', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new StorageManager().init();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
StorageManager.should.be.exist;
});
it('Autosave is active by default', function() {
obj.isAutosave().should.equal(true);
});
it('Change autosave', function() {
obj.setAutosave(0);
obj.isAutosave().should.equal(false);
});
it('Steps before save are set as default', function() {
obj.getStepsBeforeSave().should.equal(1);
});
it('Change steps before save', function() {
obj.setStepsBeforeSave(5);
obj.getStepsBeforeSave().should.equal(5);
});
it('No storages inside', function() {
obj.getStorages().should.be.empty;
});
it('Add and get new storage', function() {
obj.add('test', 'gen');
obj.get('test').should.equal('gen');
});
it('LocalStorage is set as default', function() {
obj.getCurrent().should.equal('local');
});
it('Change storage type', function() {
obj.setCurrent('remote');
obj.getCurrent().should.equal('remote');
});
it('Store do not execute if empty', function() {
(obj.store({item:'test'}) === null).should.equal(true);
});
it('Load do not execute if empty', function() {
obj.load(['item']).should.be.empty;
});
it('Load default storages ', function() {
obj.loadDefaultProviders();
obj.get('local').should.not.be.empty;
obj.get('remote').should.not.be.empty;
(obj.get('test') === null).should.equal(true);
});
describe('With custom storage', function() {
var storeValue;
var storageId = 'testStorage';
var storage = {
store: function(data){
storeValue = data;
},
load: function(keys){
return storeValue;
},
};
beforeEach(function () {
storeValue = [];
obj = new StorageManager().init({
type: storageId,
});
obj.add(storageId, storage);
});
afterEach(function () {
delete obj;
});
it('Store and load data', function() {
var data = {
item: 'testData',
item2: 'testData2',
};
var data2 = {};
var id = obj.getConfig().id;
data2[id + 'item'] = 'testData';
data2[id + 'item2'] = 'testData2';
obj.store(data);
var load = obj.load(['item', 'item2']);
storeValue.should.deep.equal(data2);
load.should.deep.equal(data);
});
});
});
Models.run();
});
});

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

@ -1,119 +1,116 @@
define(function(require, exports, module){
'use strict';
var RemoteStorage = require('undefined');
module.exports = {
run : function(){
describe('LocalStorage', function() {
var obj;
var itemName = 'testItem';
var data = {
'item1': 'value1',
'item2': 'value2',
};
beforeEach(function () {
obj = new LocalStorage();
});
afterEach(function () {
delete obj;
});
it('Store and load items', function() {
obj.store(data);
var result = obj.load(['item1', 'item2']);
result.should.deep.equal(data);
});
it('Store, update and load items', function() {
obj.store(data);
obj.store({item3: 'value3'});
obj.store({item2: 'value22'});
var result = obj.load(['item1', 'item2', 'item3']);
result.should.deep.equal({
'item1': 'value1',
'item2': 'value22',
'item3': 'value3',
});
});
it('Remove items', function() {
var items = ['item1', 'item2', 'item3'];
obj.store(data);
obj.remove(items);
obj.load(items).should.be.empty;
});
const LocalStorage = require('storage_manager/model/LocalStorage');
const RemoteStorage = require('storage_manager/model/RemoteStorage');
module.exports = {
run() {
describe('LocalStorage', () => {
var obj;
var itemName = 'testItem';
var data = {
'item1': 'value1',
'item2': 'value2',
};
beforeEach(() => {
obj = new LocalStorage();
});
afterEach(() => {
obj = null;
});
it('Store and load items', () => {
obj.store(data);
var result = obj.load(['item1', 'item2']);
expect(result).toEqual(data);
});
it('Store, update and load items', () => {
obj.store(data);
obj.store({item3: 'value3'});
obj.store({item2: 'value22'});
var result = obj.load(['item1', 'item2', 'item3']);
expect(result).toEqual({
'item1': 'value1',
'item2': 'value22',
'item3': 'value3',
});
});
it('Remove items', () => {
var items = ['item1', 'item2', 'item3'];
obj.store(data);
obj.remove(items);
expect(obj.load(items)).toEqual({});
});
});
describe('RemoteStorage', () => {
var obj;
var itemName = 'testItem';
var endpointStore = 'testStoreEndpoint';
var endpointLoad = 'testLoadEndpoint';
var params = { test: 'testValue' };
var storageOptions;
var data;
beforeEach(() => {
data = {
'item1': 'value1',
'item2': 'value2',
};
storageOptions = {
urlStore: endpointStore,
urlLoad: endpointLoad,
params,
};
obj = new RemoteStorage(storageOptions);
});
afterEach(() => {
$.ajax.restore();
obj = null;
});
// Stubbing will not return the original object so
// .always will not work
it.skip('Store data', () => {
sinon.stub($, "ajax");
for(var k in params)
data[k] = params[k];
obj.store(data);
$.ajax.calledWithMatch({
url: endpointStore,
data,
}).should.equal(true);
});
it('Load data', () => {
sinon.stub($, "ajax").returns({
done() {}
});
var dt = {};
var keys = ['item1', 'item2'];
obj.load(keys);
dt.keys = keys;
describe('RemoteStorage', function() {
var obj;
var itemName = 'testItem';
var endpointStore = 'testStoreEndpoint';
var endpointLoad = 'testLoadEndpoint';
var params = { test: 'testValue' };
var storageOptions;
var data;
beforeEach(function () {
data = {
'item1': 'value1',
'item2': 'value2',
};
storageOptions = {
urlStore: endpointStore,
urlLoad: endpointLoad,
params: params,
};
obj = new RemoteStorage(storageOptions);
});
afterEach(function () {
$.ajax.restore();
delete obj;
});
// Stubbing will not return the original object so
// .always will not work
it.skip('Store data', function() {
sinon.stub($, "ajax");
for(var k in params)
data[k] = params[k];
obj.store(data);
$.ajax.calledWithMatch({
url: endpointStore,
data: data,
}).should.equal(true);
});
it('Load data', function() {
sinon.stub($, "ajax").returns({
done: function(){}
});
var dt = {};
var keys = ['item1', 'item2'];
obj.load(keys);
dt.keys = keys;
for(var k in params)
dt[k] = params[k];
$.ajax.calledWithMatch({
url: endpointLoad,
data: dt
}).should.equal(true);
});
for(var k in params)
dt[k] = params[k];
});
expect($.ajax.calledWithMatch({
url: endpointLoad,
data: dt
})).toEqual(true);
});
}
});
};
}
});
};

191
test/specs/style_manager/index.js

@ -0,0 +1,191 @@
const StyleManager = require('style_manager');
const Models = require('./model/Models');
const SectorView = require('./view/SectorView');
const SectorsView = require('./view/SectorsView');
const PropertyView = require('./view/PropertyView');
const PropertySelectView = require('./view/PropertySelectView');
const PropertyRadioView = require('./view/PropertyRadioView');
const PropertyIntegerView = require('./view/PropertyIntegerView');
const PropertyColorView = require('./view/PropertyColorView');
const PropertyCompositeView = require('./view/PropertyCompositeView');
const PropertyStackView = require('./view/PropertyStackView');
const LayerView = require('./view/LayerView');
describe('StyleManager', () => {
describe('Main', () => {
var obj;
beforeEach(() => {
obj = new StyleManager().init({
sectors: []
});
});
afterEach(() => {
obj = null;
});
it('Object exists', () => {
expect(obj).toExist();
});
it('No sectors', () => {
expect(obj.getSectors().length).toEqual(0);
});
it('Add sector', () => {
obj.addSector('test', {
name: 'Test name'
});
var sector = obj.getSectors().at(0);
expect(obj.getSectors().length).toEqual(1);
expect(sector.get('id')).toEqual('test');
expect(sector.get('name')).toEqual('Test name');
});
it('Add sectors', () => {
obj.addSector('test', {});
obj.addSector('test2', {});
expect(obj.getSectors().length).toEqual(2);
});
it("Can't create more than one sector with the same id", () => {
var sect1 = obj.addSector('test', {});
var sect2 = obj.addSector('test', {});
expect(obj.getSectors().length).toEqual(1);
expect(sect1).toEqual(sect2);
});
it('Get inexistent sector', () => {
expect(obj.getSector('test')).toEqual(null);
});
it('Get sector', () => {
var sect1 = obj.addSector('test', { name: 'Test' });
var sect2 = obj.getSector('test');
expect(sect1).toEqual(sect2);
});
it('Add property to inexistent sector', () => {
expect(obj.addProperty('test', {})).toEqual(null);
});
it('Add property', () => {
obj.addSector('test', {});
expect(obj.addProperty('test', {})).toExist();
expect(obj.getProperties('test').length).toEqual(1);
});
it('Check added property', () => {
obj.addSector('test', {});
var prop = obj.addProperty('test', {
'name': 'test',
});
expect(prop.get('name')).toEqual('test');
});
it('Add properties', () => {
obj.addSector('test', {});
obj.addProperty('test', [{}, {}]);
expect(obj.getProperties('test').length).toEqual(2);
});
it('Get property from inexistent sector', () => {
expect(obj.getProperty('test', 'test-prop')).toEqual(null);
});
it("Can't get properties without proper name", () => {
obj.addSector('test', {});
obj.addProperty('test', [{}, {}]);
expect(obj.getProperty('test', 'test-prop')).toEqual([]);
});
it("Get property with proper name", () => {
obj.addSector('test', {});
var prop1 = obj.addProperty('test', {property: 'test-prop'});
var prop2 = obj.getProperty('test', 'test-prop');
expect(prop1).toEqual(prop2);
});
it("Get properties with proper name", () => {
obj.addSector('test', {});
var prop1 = obj.addProperty('test',[
{property: 'test-prop'},
{property: 'test-prop'}
]);
expect(obj.getProperty('test', 'test-prop').length).toEqual(2);
});
it('Get inexistent properties', () => {
expect(obj.getProperties('test')).toEqual(null);
expect(obj.getProperties()).toEqual(null);
});
it('Renders correctly', () => {
expect(obj.render()).toExist();
});
describe('Init with configuration', () => {
beforeEach(() => {
obj = new StyleManager().init({
sectors: [{
id: 'dim',
name: 'Dimension',
properties: [{
name: 'Width',
property: 'width',
},{
name: 'Height',
property: 'height',
}],
},{
id: 'pos',
name: 'position',
properties: [{
name: 'Width',
property: 'width',
}],
}],
});
});
afterEach(() => {
obj = null;
});
it('Sectors added', () => {
expect(obj.getSectors().length).toEqual(2);
var sect1 = obj.getSector('dim');
expect(sect1.get('name')).toEqual('Dimension');
});
it('Properties added', () => {
var sect1 = obj.getSector('dim');
var sect2 = obj.getSector('pos');
expect(sect1.get('properties').length).toEqual(2);
expect(sect2.get('properties').length).toEqual(1);
});
it('Property is correct', () => {
var prop1 = obj.getProperty('dim', 'width');
expect(prop1.get('name')).toEqual('Width');
});
});
Models.run();
SectorView.run();
SectorsView.run();
PropertyView.run();
PropertySelectView.run();
PropertyRadioView.run();
PropertyIntegerView.run();
PropertyColorView.run();
PropertyCompositeView.run();
PropertyStackView.run();
LayerView.run();
});
});

185
test/specs/style_manager/main.js

@ -1,185 +0,0 @@
define(function(require, exports, module){
'use strict';
var StyleManager = require('StyleManager');
var LayerView = require('undefined');
describe('StyleManager', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new StyleManager().init({
sectors: []
});
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
obj.should.be.ok;
});
it('No sectors', function() {
obj.getSectors().length.should.equal(0);
});
it('Add sector', function() {
obj.addSector('test', {
name: 'Test name'
});
obj.getSectors().length.should.equal(1);
var sector = obj.getSectors().at(0);
sector.get('id').should.equal('test');
sector.get('name').should.equal('Test name');
});
it('Add sectors', function() {
obj.addSector('test', {});
obj.addSector('test2', {});
obj.getSectors().length.should.equal(2);
});
it("Can't create more than one sector with the same id", function() {
var sect1 = obj.addSector('test', {});
var sect2 = obj.addSector('test', {});
obj.getSectors().length.should.equal(1);
sect1.should.deep.equal(sect2);
});
it('Get inexistent sector', function() {
(obj.getSector('test') == null).should.equal(true);
});
it('Get sector', function() {
var sect1 = obj.addSector('test', { name: 'Test' });
var sect2 = obj.getSector('test');
sect1.should.deep.equal(sect2);
});
it('Add property to inexistent sector', function() {
(obj.addProperty('test', {}) == null).should.equal(true);
});
it('Add property', function() {
obj.addSector('test', {});
(obj.addProperty('test', {}) == null).should.equal(false);
obj.getProperties('test').length.should.equal(1);
});
it('Check added property', function() {
obj.addSector('test', {});
var prop = obj.addProperty('test', {
'name': 'test',
});
prop.get('name').should.equal('test');
});
it('Add properties', function() {
obj.addSector('test', {});
obj.addProperty('test', [{}, {}]);
obj.getProperties('test').length.should.equal(2);
});
it('Get property from inexistent sector', function() {
(obj.getProperty('test', 'test-prop') == null).should.equal(true);
});
it("Can't get properties without proper name", function() {
obj.addSector('test', {});
obj.addProperty('test', [{}, {}]);
obj.getProperty('test', 'test-prop').should.be.empty;
});
it("Get property with proper name", function() {
obj.addSector('test', {});
var prop1 = obj.addProperty('test', {property: 'test-prop'});
var prop2 = obj.getProperty('test', 'test-prop');
prop1.should.deep.equal(prop2);
});
it("Get properties with proper name", function() {
obj.addSector('test', {});
var prop1 = obj.addProperty('test',[
{property: 'test-prop'},
{property: 'test-prop'}
]);
obj.getProperty('test', 'test-prop').length.should.equal(2);
});
it('Get inexistent properties', function() {
(obj.getProperties('test') == null).should.equal(true);
(obj.getProperties() == null).should.equal(true);
});
it('Renders correctly', function() {
obj.render().should.be.ok;
});
describe('Init with configuration', function() {
beforeEach(function () {
obj = new StyleManager().init({
sectors: [{
id: 'dim',
name: 'Dimension',
properties: [{
name: 'Width',
property: 'width',
},{
name: 'Height',
property: 'height',
}],
},{
id: 'pos',
name: 'position',
properties: [{
name: 'Width',
property: 'width',
}],
}],
});
});
afterEach(function () {
delete obj;
});
it('Sectors added', function() {
obj.getSectors().length.should.equal(2);
var sect1 = obj.getSector('dim');
sect1.get('name').should.equal('Dimension');
});
it('Properties added', function() {
var sect1 = obj.getSector('dim');
var sect2 = obj.getSector('pos');
sect1.get('properties').length.should.equal(2);
sect2.get('properties').length.should.equal(1);
});
it('Property is correct', function() {
var prop1 = obj.getProperty('dim', 'width');
prop1.get('name').should.equal('Width');
});
});
Models.run();
SectorView.run();
SectorsView.run();
PropertyView.run();
PropertySelectView.run();
PropertyRadioView.run();
PropertyIntegerView.run();
PropertyColorView.run();
PropertyCompositeView.run();
PropertyStackView.run();
LayerView.run();
});
});
});

1601
test/specs/style_manager/model/Models.js

File diff suppressed because it is too large

130
test/specs/style_manager/view/LayerView.js

@ -1,81 +1,77 @@
define(function(require, exports, module){
'use strict';
var LayerView = require('undefined');
var Layers = require('StyleManager/model/Layers');
const LayerView = require('style_manager/view/LayerView');
const Layers = require('style_manager/model/Layers');
module.exports = {
run : function(){
module.exports = {
run() {
describe('LayerView', function() {
describe('LayerView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="layer-fixture"></div>');
});
beforeEach(function () {
var coll = new Layers();
model = coll.add({});
view = new LayerView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="layer-fixture"></div>');
});
afterEach(function () {
view.remove();
});
beforeEach(() => {
var coll = new Layers();
model = coll.add({});
view = new LayerView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
delete component;
delete view;
delete model;
});
afterEach(() => {
view.remove();
});
it('Rendered correctly', function() {
var layer = view.el;
$fixture.get(0).querySelector('.layer').should.be.ok;
layer.querySelector('#label').should.be.ok;
layer.querySelector('#close-layer').should.be.ok;
layer.querySelector('#inputs').should.be.ok;
layer.querySelector('#inputs').innerHTML.should.be.empty;
layer.querySelector('#preview').should.be.ok;
});
after(() => {
$fixture.remove();
component = null;
view = null;
model = null;
});
it('getIndex returns default value', function() {
view.getIndex().should.equal(0);
});
it('Rendered correctly', () => {
var layer = view.el;
expect($fixture.get(0).querySelector('.layer')).toExist();
expect(layer.querySelector('#label')).toExist();
expect(layer.querySelector('#close-layer')).toExist();
expect(layer.querySelector('#inputs')).toExist();
expect(layer.querySelector('#inputs').innerHTML).toNotExist();
expect(layer.querySelector('#preview')).toExist();
});
it('No preview', function() {
var style = view.el.querySelector('#preview').style;
style.cssText.should.be.empty;
});
it('getIndex returns default value', () => {
expect(view.getIndex()).toEqual(0);
});
it('Changes on value trigger onPreview', function() {
var called = 0;
view.onPreview = function(){called = 1};
view.model.set('preview', true);
view.model.set('value', 'test');
called.should.equal(1);
});
it('No preview', () => {
var style = view.el.querySelector('#preview').style;
expect(style.cssText).toNotExist();
});
it('Update props', function() {
view.model.set('props', $('<div>'));
view.el.querySelector('#inputs').innerHTML.should.not.be.empty;
(view.model.get('props') === null).should.equal(true);
});
it('Changes on value trigger onPreview', () => {
var called = 0;
view.onPreview = () => {called = 1};
view.model.set('preview', true);
view.model.set('value', 'test');
expect(called).toEqual(1);
});
it('Update props', () => {
view.model.set('props', $('<div>'));
expect(view.el.querySelector('#inputs').innerHTML).toExist();
expect(view.model.get('props')).toEqual(null);
});
}
};
});
});
}
};

298
test/specs/style_manager/view/PropertyColorView.js

@ -1,166 +1,166 @@
define(function(require, exports, module){
'use strict';
var PropertyColorView = require('undefined');
var Property = require('StyleManager/model/Property');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('PropertyColorView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = '#fff';
var defValue = 'test2value';
before(function () {
$.fn.spectrum = function(){};
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
const PropertyColorView = require('style_manager/view/PropertyColorView');
const Property = require('style_manager/model/Property');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('PropertyColorView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propTarget;
var propName = 'testprop';
var propValue = '#fff';
var defValue = 'test2value';
before(() => {
$.fn.spectrum = () => {};
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
model = new Property({
type: 'color',
property: propName
});
view = new PropertyColorView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
beforeEach(() => {
target = new Component();
component = new Component();
model = new Property({
type: 'color',
property: propName
});
propTarget = Object.assign({}, Backbone.Events);
propTarget.model = component;
view = new PropertyColorView({
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
//view.remove(); // strange errors ???
});
afterEach(() => {
//view.remove(); // strange errors ???
});
after(function () {
$fixture.remove();
delete component;
delete view;
delete model;
});
after(() => {
$fixture.remove();
component = null;
view = null;
model = null;
});
it('Rendered correctly', function() {
var prop = view.el;
$fixture.get(0).querySelector('.property').should.be.ok;
prop.querySelector('.label').should.be.ok;
prop.querySelector('.field').should.be.ok;
});
it('Rendered correctly', () => {
var prop = view.el;
expect($fixture.get(0).querySelector('.property')).toExist();
expect(prop.querySelector('.label')).toExist();
expect(prop.querySelector('.field')).toExist();
});
it('Inputs rendered', function() {
var prop = view.el;
prop.querySelector('input[type=text]').should.be.ok;
prop.querySelector('.field-color-picker').should.be.ok;
});
it('Inputs rendered', () => {
var prop = view.el;
expect(prop.querySelector('input[type=text]')).toExist();
expect(prop.querySelector('.field-color-picker')).toExist();
});
it('Inputs should exist', function() {
view.$input.should.be.ok;
view.$color.should.be.ok;
});
it('Inputs should exist', () => {
expect(view.$input).toExist();
expect(view.$color).toExist();
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
view.$input.val().should.be.empty;
});
it('Input value is empty', () => {
expect(view.model.get('value')).toNotExist();
expect(view.$input.val()).toNotExist();
});
it('Update model on setValue', function() {
view.setValue(propValue);
view.model.get('value').should.equal(propValue);
view.$input.val().should.equal(propValue);
});
it('Update model on setValue', () => {
view.setValue(propValue);
expect(view.model.get('value')).toEqual(propValue);
expect(view.$input.val()).toEqual(propValue);
});
it('Update model on input change', function() {
view.$input.val(propValue).trigger('change');
view.model.get('value').should.equal(propValue);
});
it('Update model on input change', () => {
view.$input.val(propValue).trigger('change');
expect(view.model.get('value')).toEqual(propValue);
});
it('Update input on value change', function() {
view.model.set('value', propValue);
view.getInputValue().should.equal(propValue);
});
it('Update input on value change', () => {
view.model.set('value', propValue);
expect(view.getInputValue()).toEqual(propValue);
});
it('Update target on value change', function() {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
compStyle.should.deep.equal(assertStyle);
});
it('Update target on value change', () => {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
expect(compStyle).toEqual(assertStyle);
});
describe('With target setted', function() {
beforeEach(function () {
target.model = component;
view = new PropertyColorView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal(propValue);
view.getInputValue().should.equal(propValue);
});
it('Update value after multiple swaps', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = '#123123';
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal('#123123');
view.$input.val().should.equal('#123123');
});
})
describe('Init property', function() {
beforeEach(function () {
component = new Component();
model = new Property({
type: 'color',
property: propName,
defaults: propValue,
});
view = new PropertyColorView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', function() {
view.model.get('value').should.equal(propValue);
});
it('Input value is as default', function() {
view.$input.val().should.equal(propValue);
});
describe('With target setted', () => {
beforeEach(() => {
target.model = component;
view = new PropertyColorView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual(propValue);
expect(view.getInputValue()).toEqual(propValue);
});
it('Update value after multiple swaps', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = '#123123';
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual('#123123');
expect(view.getInputValue()).toEqual('#123123');
});
})
describe('Init property', () => {
beforeEach(() => {
component = new Component();
model = new Property({
type: 'color',
property: propName,
defaults: propValue,
});
view = new PropertyColorView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', () => {
expect(view.model.get('value')).toEqual(propValue);
});
it('Input value is as default', () => {
expect(view.$input.val()).toEqual(propValue);
});
});
}
};
});
});
}
};

452
test/specs/style_manager/view/PropertyCompositeView.js

@ -1,242 +1,238 @@
define(function(require, exports, module){
'use strict';
var PropertyCompositeView = require('undefined');
var Property = require('StyleManager/model/Property');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('PropertyCompositeView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var properties = [
{property: 'subprop1'},
{
type: 'integer',
property: 'subprop2',
defaults: 0,
units: ['%', 'px']
},
{
type: 'select',
property: 'subprop3',
defaults: 'val2',
list: [
{value:'val1'},
{value:'val2'},
{value:'val3'},
]
},
];
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
target.model = component;
model = new Property({
type: 'composite',
property: propName,
properties: properties
});
view = new PropertyCompositeView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
const PropertyCompositeView = require('style_manager/view/PropertyCompositeView');
const Property = require('style_manager/model/Property');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('PropertyCompositeView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var properties = [
{property: 'subprop1'},
{
type: 'integer',
property: 'subprop2',
defaults: 0,
units: ['%', 'px']
},
{
type: 'select',
property: 'subprop3',
defaults: 'val2',
list: [
{value:'val1'},
{value:'val2'},
{value:'val3'},
]
},
];
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
afterEach(function () {
//view.remove(); // strange errors ???
});
beforeEach(() => {
target = new Component();
component = new Component();
target.model = component;
model = new Property({
type: 'composite',
property: propName,
properties
});
view = new PropertyCompositeView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
delete component;
delete view;
delete model;
});
afterEach(() => {
//view.remove(); // strange errors ???
});
it('Rendered correctly', function() {
var prop = view.el;
$fixture.get(0).querySelector('.property').should.be.ok;
prop.querySelector('.label').should.be.ok;
prop.querySelector('.field').should.be.ok;
});
after(() => {
$fixture.remove();
component = null;
view = null;
model = null;
});
it('Properties rendered', function() {
var prop = view.el;
prop.querySelector('.properties').should.be.ok;
});
it('Rendered correctly', () => {
var prop = view.el;
expect($fixture.get(0).querySelector('.property')).toExist();
expect(prop.querySelector('.label')).toExist();
expect(prop.querySelector('.field')).toExist();
});
it('Properties rendered correctly', function() {
var children = view.el.querySelector('.properties').children;
children.length.should.equal(properties.length + 1);
children[0].id.should.equal(properties[0].property);
children[1].id.should.equal(properties[1].property);
children[2].id.should.equal(properties[2].property);
});
it('Properties rendered', () => {
var prop = view.el;
expect(prop.querySelector('.properties')).toExist();
});
it('Props should exist', function() {
view.$props.should.be.ok;
});
it('Properties rendered correctly', () => {
var children = view.el.querySelector('.properties').children;
expect(children.length).toEqual(properties.length + 1);
expect(children[0].id).toEqual(properties[0].property);
expect(children[1].id).toEqual(properties[1].property);
expect(children[2].id).toEqual(properties[2].property);
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
});
it('Props should exist', () => {
expect(view.$props).toExist();
});
it('Update input on value change', function() {
view.model.set('value', propValue);
view.$input.val().should.equal(propValue);
});
it('Input value is empty', () => {
expect(view.model.get('value')).toNotExist();
});
describe('With target setted', function() {
var prop2Val;
var prop3Val;
var prop2Unit;
var finalResult;
var $prop1;
var $prop2;
var $prop3;
beforeEach(function () {
model = new Property({
type: 'composite',
property: propName,
properties: properties
});
view = new PropertyCompositeView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
prop3Val = properties[2].list[2].value;
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
finalResult = propValue + ' ' + prop2Val + prop2Unit +' ' + prop3Val;
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
});
it('Update model on input change', function() {
$prop1.val(propValue).trigger('change');
$prop3.val(prop3Val).trigger('change');
view.model.get('value').should.equal(finalResult);
});
it('Update value on models change', function() {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
view.model.get('value').should.equal(finalResult);
});
it('Update target on value change', function() {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[propName] = propValue + ' 0% val2';
compStyle.should.deep.equal(assertStyle);
});
it('Update target on detached value change', function() {
model = new Property({
type: 'composite',
property: propName,
properties: properties,
detached: true,
});
view = new PropertyCompositeView({
model: model,
propTarget: target
});
$fixture.html(view.render().el);
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[properties[0].property] = $prop1.val();
compStyle.should.deep.equal(assertStyle);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
$prop1.val().should.equal(propValue);
$prop3.val().should.equal(prop3Val);
});
it('Update value after multiple swaps', function() {
var style = {};
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = propValue + '2 ' + prop2Val + '2' + prop2Unit + ' ' + 'val1';
component.set('style', style);
view.propTarget.trigger('update');
$prop1.val().should.equal(propValue + '2');
$prop2.val().should.equal('2');
$prop3.val().should.equal('val1');
});
it('The value is correctly extracted from the composite string', function() {
var style = {};
style[propName] = 'value1 value2 value3 value4';
component.set('style', style);
view.valueOnIndex(2).should.equal('value3');
view.valueOnIndex(0).should.equal('value1');
(view.valueOnIndex(4) === null).should.equal(true);
});
it('Build value from properties', function() {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
view.build().should.equal(finalResult);
});
})
describe('Init property', function() {
beforeEach(function () {
model = new Property({
type: 'composite',
property: propName,
properties: properties,
defaults: defValue,
});
view = new PropertyCompositeView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', function() {
view.model.get('value').should.equal(defValue);
});
it('Update input on value change', () => {
view.model.set('value', propValue);
expect(view.$input.val()).toEqual(propValue);
});
describe('With target setted', () => {
var prop2Val;
var prop3Val;
var prop2Unit;
var finalResult;
var $prop1;
var $prop2;
var $prop3;
beforeEach(() => {
model = new Property({
type: 'composite',
property: propName,
properties
});
view = new PropertyCompositeView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
prop3Val = properties[2].list[2].value;
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
finalResult = propValue + ' ' + prop2Val + prop2Unit +' ' + prop3Val;
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
});
it('Update model on input change', () => {
$prop1.val(propValue).trigger('change');
$prop3.val(prop3Val).trigger('change');
expect(view.model.get('value')).toEqual(finalResult);
});
it('Update value on models change', () => {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
expect(view.model.get('value')).toEqual(finalResult);
});
it('Update target on value change', () => {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[propName] = propValue + ' 0% val2';
expect(compStyle).toEqual(assertStyle);
});
it('Update target on detached value change', () => {
model = new Property({
type: 'composite',
property: propName,
properties,
detached: true,
});
view = new PropertyCompositeView({
model,
propTarget: target
});
$fixture.html(view.render().el);
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[properties[0].property] = $prop1.val();
expect(compStyle).toEqual(assertStyle);
});
it('Update value and input on target swap', () => {
var style = {};
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
expect($prop1.val()).toEqual(propValue);
expect($prop3.val()).toEqual(prop3Val);
});
it('Update value after multiple swaps', () => {
var style = {};
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = propValue + '2 ' + prop2Val + '2' + prop2Unit + ' ' + 'val1';
component.set('style', style);
view.propTarget.trigger('update');
expect($prop1.val()).toEqual(propValue + '2');
expect($prop2.val()).toEqual('2');
expect($prop3.val()).toEqual('val1');
});
it('The value is correctly extracted from the composite string', () => {
var style = {};
style[propName] = 'value1 value2 value3 value4';
component.set('style', style);
expect(view.valueOnIndex(2)).toEqual('value3');
expect(view.valueOnIndex(0)).toEqual('value1');
expect(view.valueOnIndex(4)).toEqual(null);
});
it('Build value from properties', () => {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
expect(view.build()).toEqual(finalResult);
});
})
describe('Init property', () => {
beforeEach(() => {
model = new Property({
type: 'composite',
property: propName,
properties,
defaults: defValue,
});
view = new PropertyCompositeView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', () => {
expect(view.model.get('value')).toEqual(defValue);
});
});
}
};
});
});
}
};

386
test/specs/style_manager/view/PropertyIntegerView.js

@ -1,211 +1,211 @@
define(function(require, exports, module){
'use strict';
var PropertyIntegerView = require('undefined');
var Property = require('StyleManager/model/Property');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('PropertyIntegerView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var intValue = '55';
var unitValue = 'px';
var propValue = intValue + unitValue;
var defValue = 'test2value';
var units = ['px', '%', 'em'];
var minValue = -15;
var maxValue = 75;
var unitsElSel = '.field-units select';
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
model = new Property({
type: 'integer',
units: units,
property: propName
});
view = new PropertyIntegerView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
const PropertyIntegerView = require('style_manager/view/PropertyIntegerView');
const Property = require('style_manager/model/Property');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('PropertyIntegerView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propTarget;
var propName = 'testprop';
var intValue = '55';
var unitValue = 'px';
var propValue = intValue + unitValue;
var defValue = 'test2value';
var units = ['px', '%', 'em'];
var minValue = -15;
var maxValue = 75;
var unitsElSel = '.field-units select';
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
afterEach(function () {
//view.remove(); // strange errors ???
});
beforeEach(() => {
target = new Component();
component = new Component();
model = new Property({
type: 'integer',
units,
property: propName
});
propTarget = Object.assign({}, Backbone.Events);
propTarget.model = component;
view = new PropertyIntegerView({
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
delete component;
delete view;
delete model;
});
afterEach(() => {
//view.remove(); // strange errors ???
});
it('Rendered correctly', function() {
var prop = view.el;
$fixture.get(0).querySelector('.property').should.be.ok;
prop.querySelector('.label').should.be.ok;
prop.querySelector('.field').should.be.ok;
});
after(() => {
$fixture.remove();
component = null;
view = null;
model = null;
});
it('Inputs rendered', function() {
var prop = view.el;
prop.querySelector('input[type=text]').should.be.ok;
prop.querySelector(unitsElSel).should.be.ok;
});
it('Rendered correctly', () => {
var prop = view.el;
expect($fixture.get(0).querySelector('.property')).toExist();
expect(prop.querySelector('.label')).toExist();
expect(prop.querySelector('.field')).toExist();
});
it('Units rendered', function() {
var select = view.el.querySelector(unitsElSel);
select.children.length.should.equal(units.length);
});
it('Inputs rendered', () => {
var prop = view.el;
expect(prop.querySelector('input[type=text]')).toExist();
expect(prop.querySelector(unitsElSel)).toExist();
});
it('Units rendered correctly', function() {
var children = view.el.querySelector(unitsElSel).children;
children[0].textContent.should.equal(units[0]);
children[1].textContent.should.equal(units[1]);
children[2].textContent.should.equal(units[2]);
});
it('Units rendered', () => {
var select = view.el.querySelector(unitsElSel);
expect(select.children.length).toEqual(units.length);
});
it('Inputs should exist', function() {
view.$input.should.be.ok;
view.$unit.should.be.ok;
});
it('Units rendered correctly', () => {
var children = view.el.querySelector(unitsElSel).children;
expect(children[0].textContent).toEqual(units[0]);
expect(children[1].textContent).toEqual(units[1]);
expect(children[2].textContent).toEqual(units[2]);
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
view.model.get('unit').should.equal('px');
});
it('Inputs should exist', () => {
expect(view.$input).toExist();
expect(view.$unit).toExist();
});
it('Update model on setValue', function() {
view.setValue(intValue + unitValue);
view.model.get('value').should.equal(parseFloat(intValue));
view.model.get('unit').should.equal(unitValue);
view.$input.val().should.equal(intValue);
view.$unit.val().should.equal(unitValue);
});
it('Input value is empty', () => {
expect(view.model.get('value')).toNotExist();
expect(view.model.get('unit')).toEqual('px');
});
it('Update model on input change', function() {
view.$input.val(123).trigger('change');
view.model.get('value').should.equal(123);
});
it('Update model on setValue', () => {
view.setValue(intValue + unitValue);
expect(view.model.get('value')).toEqual(parseFloat(intValue));
expect(view.model.get('unit')).toEqual(unitValue);
expect(view.$input.val()).toEqual(intValue);
expect(view.$unit.val()).toEqual(unitValue);
});
it('Update model on unit change', function() {
view.$unit.val(units[1]).trigger('change');
view.model.get('unit').should.equal(units[1]);
});
it('Update model on input change', () => {
view.$input.val(123).trigger('change');
expect(view.model.get('value')).toEqual(123);
});
it('Update input on value change', function() {
view.model.set('value', intValue);
view.getInputValue().should.equal(intValue);
});
it('Update model on unit change', () => {
view.$unit.val(units[1]).trigger('change');
expect(view.model.get('unit')).toEqual(units[1]);
});
it('Update target on value change', function() {
view.selectedComponent = component;
view.model.set('value', intValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
compStyle.should.deep.equal(assertStyle);
});
it('Update input on value change', () => {
view.model.set('value', intValue);
expect(view.getInputValue()).toEqual(intValue);
});
describe('With target setted', function() {
beforeEach(function () {
target.model = component;
view = new PropertyIntegerView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal(parseFloat(intValue));
view.getInputValue().should.equal(intValue);
});
it('Update value after multiple swaps', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = '20em';
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal(20);
view.model.get('unit').should.equal('em');
view.$input.val().should.equal('20');
view.$unit.val().should.equal('em');
});
})
describe('Init property', function() {
beforeEach(function () {
component = new Component();
model = new Property({
type: 'integer',
units: units,
property: propName,
defaults: intValue,
min: minValue,
max: maxValue,
unit: units[1],
});
view = new PropertyIntegerView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', function() {
view.model.get('value').should.equal(parseInt(intValue));
view.model.get('unit').should.equal(units[1]);
});
it('Input value is as default', function() {
view.$input.val().should.equal(intValue);
view.$unit.val().should.equal(units[1]);
});
it('Input follows min', function() {
view.$input.val(minValue - 50).trigger('change');
view.model.get('value').should.equal(minValue);
view.$input.val().should.equal(minValue + "");
});
it('Input follows max', function() {
view.$input.val(maxValue + 50).trigger('change');
view.model.get('value').should.equal(maxValue);
view.$input.val().should.equal(maxValue + "");
});
it('Update target on value change', () => {
view.selectedComponent = component;
view.model.set('value', intValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
expect(compStyle).toEqual(assertStyle);
});
});
describe('With target setted', () => {
beforeEach(() => {
target.model = component;
view = new PropertyIntegerView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual(parseFloat(intValue));
expect(view.getInputValue()).toEqual(intValue);
});
it('Update value after multiple swaps', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = '20em';
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual(20);
expect(view.model.get('unit')).toEqual('em');
expect(view.$input.val()).toEqual('20');
expect(view.$unit.val()).toEqual('em');
});
})
describe('Init property', () => {
beforeEach(() => {
component = new Component();
model = new Property({
type: 'integer',
units,
property: propName,
defaults: intValue,
min: minValue,
max: maxValue,
unit: units[1],
});
view = new PropertyIntegerView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', () => {
expect(view.model.get('value')).toEqual(parseInt(intValue));
expect(view.model.get('unit')).toEqual(units[1]);
});
it('Input value is as default', () => {
expect(view.$input.val()).toEqual(intValue);
expect(view.$unit.val()).toEqual(units[1]);
});
it('Input follows min', () => {
view.$input.val(minValue - 50).trigger('change');
expect(view.model.get('value')).toEqual(minValue);
expect(view.$input.val()).toEqual(minValue + "");
});
it('Input follows max', () => {
view.$input.val(maxValue + 50).trigger('change');
expect(view.model.get('value')).toEqual(maxValue);
expect(view.$input.val()).toEqual(maxValue + "");
});
});
}
};
});
});
}
};

317
test/specs/style_manager/view/PropertyRadioView.js

@ -1,177 +1,176 @@
define(function(require, exports, module){
'use strict';
var PropertyRadioView = require('undefined');
var Property = require('StyleManager/model/Property');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('PropertyRadioView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var options = [
{ value: 'test1value', 'title': 'testtitle'},
{ name: 'test2', value: 'test2value'}
];
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
const PropertyRadioView = require('style_manager/view/PropertyRadioView');
const Property = require('style_manager/model/Property');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('PropertyRadioView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propTarget;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var options = [
{ value: 'test1value', 'title': 'testtitle'},
{ name: 'test2', value: 'test2value'}
];
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
model = new Property({
type: 'radio',
list: options,
property: propName
});
view = new PropertyRadioView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
beforeEach(() => {
target = new Component();
component = new Component();
model = new Property({
type: 'radio',
list: options,
property: propName
});
propTarget = Object.assign({}, Backbone.Events);
propTarget.model = component;
view = new PropertyRadioView({
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
//view.remove(); // strange errors ???
});
afterEach(() => {
//view.remove(); // strange errors ???
});
after(function () {
$fixture.remove();
delete component;
});
after(() => {
$fixture.remove();
component = null;
});
it('Rendered correctly', function() {
var prop = view.el;
$fixture.get(0).querySelector('.property').should.be.ok;
prop.querySelector('.label').should.be.ok;
prop.querySelector('.field').should.be.ok;
});
it('Rendered correctly', () => {
var prop = view.el;
expect($fixture.get(0).querySelector('.property')).toExist();
expect(prop.querySelector('.label')).toExist();
expect(prop.querySelector('.field')).toExist();
});
it('Radio rendered', function() {
var prop = view.el;
prop.querySelector('input[type=radio]').should.be.ok;
});
it('Radio rendered', () => {
var prop = view.el;
expect(prop.querySelector('input[type=radio]')).toExist();
});
it('Options rendered', function() {
var input = view.el.querySelector('#input-holder');
input.children.length.should.equal(options.length);
});
it('Options rendered', () => {
var input = view.el.querySelector('#input-holder');
expect(input.children.length).toEqual(options.length);
});
it('Options rendered correctly', function() {
var children = view.el.querySelector('#input-holder').children;
children[0].querySelector('label').textContent.should.equal('test1value');
children[1].querySelector('label').textContent.should.equal('test2');
children[0].querySelector('input').value.should.equal(options[0].value);
children[1].querySelector('input').value.should.equal(options[1].value);
children[0].querySelector('label').getAttribute('title').should.equal(options[0].title);
(children[1].querySelector('label').getAttribute('title') == null)
.should.equal(true);
});
it('Options rendered correctly', () => {
var children = view.el.querySelector('#input-holder').children;
expect(children[0].querySelector('label').textContent).toEqual('test1value');
expect(children[1].querySelector('label').textContent).toEqual('test2');
expect(children[0].querySelector('input').value).toEqual(options[0].value);
expect(children[1].querySelector('input').value).toEqual(options[1].value);
expect(children[0].querySelector('label').getAttribute('title')).toEqual(options[0].title);
expect(children[1].querySelector('label').getAttribute('title')).toEqual(null);
});
it('Input should exist', function() {
view.$input.should.be.ok;
});
it('Input should exist', () => {
expect(view.$input).toExist();
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
});
it('Input value is empty', () => {
expect(view.model.get('value')).toNotExist();
});
it('Update model on input change', function() {
view.setValue(propValue);
view.model.get('value').should.equal(propValue);
view.getInputValue().should.equal(propValue);
});
it('Update model on input change', () => {
view.setValue(propValue);
expect(view.model.get('value')).toEqual(propValue);
expect(view.getInputValue()).toEqual(propValue);
});
it('Update input on value change', function() {
view.model.set('value', propValue);
view.getInputValue().should.equal(propValue);
});
it('Update input on value change', () => {
view.model.set('value', propValue);
expect(view.getInputValue()).toEqual(propValue);
});
it('Update target on value change', function() {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
compStyle.should.deep.equal(assertStyle);
});
it('Update target on value change', () => {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
expect(compStyle).toEqual(assertStyle);
});
describe('With target setted', function() {
beforeEach(function () {
target.model = component;
view = new PropertyRadioView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal(propValue);
view.getInputValue().should.equal(propValue);
});
it('Update value after multiple swaps', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = 'test2value';
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal('test2value');
view.getInputValue().should.equal('test2value');
});
})
describe('Init property', function() {
beforeEach(function () {
component = new Component();
model = new Property({
type: 'select',
list: options,
defaults: defValue,
property: propName
});
view = new PropertyRadioView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', function() {
view.model.get('value').should.equal(defValue);
});
it('Input value is as default', function() {
view.getInputValue().should.equal(defValue);
});
describe('With target setted', () => {
beforeEach(() => {
target.model = component;
view = new PropertyRadioView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual(propValue);
expect(view.getInputValue()).toEqual(propValue);
});
it('Update value after multiple swaps', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = 'test2value';
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual('test2value');
expect(view.getInputValue()).toEqual('test2value');
});
})
describe('Init property', () => {
beforeEach(() => {
component = new Component();
model = new Property({
type: 'select',
list: options,
defaults: defValue,
property: propName
});
view = new PropertyRadioView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', () => {
expect(view.model.get('value')).toEqual(defValue);
});
it('Input value is as default', () => {
expect(view.getInputValue()).toEqual(defValue);
});
});
}
};
});
});
}
};

357
test/specs/style_manager/view/PropertySelectView.js

@ -1,196 +1,197 @@
define(function(require, exports, module){
'use strict';
var PropertySelectView = require('undefined');
var Property = require('StyleManager/model/Property');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('PropertySelectView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var options = [
{value: 'test1value', style: 'test:style'},
{name: 'test2', value: 'test2value'}
];
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
const PropertySelectView = require('style_manager/view/PropertySelectView');
const Property = require('style_manager/model/Property');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('PropertySelectView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propTarget;
var options;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var options = [
{value: 'test1value', style: 'test:style'},
{name: 'test2', value: 'test2value'}
];
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
model = new Property({
type: 'select',
list: options,
property: propName
});
view = new PropertySelectView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
beforeEach(() => {
propTarget = Object.assign({}, Backbone.Events);
target = new Component();
component = new Component();
model = new Property({
type: 'select',
list: options,
property: propName
});
propTarget.model = component;
view = new PropertySelectView({
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
//view.remove(); // strange errors ???
});
afterEach(() => {
//view.remove(); // strange errors ???
});
after(function () {
$fixture.remove();
delete component;
});
after(() => {
$fixture.remove();
component = null;
});
it('Rendered correctly', function() {
var prop = view.el;
$fixture.get(0).querySelector('.property').should.be.ok;
prop.querySelector('.label').should.be.ok;
prop.querySelector('.field').should.be.ok;
});
it('Rendered correctly', () => {
var prop = view.el;
expect($fixture.get(0).querySelector('.property')).toExist();
expect(prop.querySelector('.label')).toExist();
expect(prop.querySelector('.field')).toExist();
});
it('Select rendered', function() {
var prop = view.el;
prop.querySelector('select').should.be.ok;
});
it('Select rendered', () => {
var prop = view.el;
expect(prop.querySelector('select')).toExist();
});
it('Options rendered', function() {
var select = view.el.querySelector('select');
select.children.length.should.equal(options.length);
});
it('Options rendered', () => {
var select = view.el.querySelector('select');
expect(select.children.length).toEqual(options.length);
});
it('Options rendered correctly', function() {
var select = view.el.querySelector('select');
var children = select.children;
children[0].value.should.equal(options[0].value);
children[1].value.should.equal(options[1].value);
children[0].textContent.should.equal(options[0].value);
children[1].textContent.should.equal(options[1].name);
children[0].getAttribute('style').should.equal(options[0].style);
(children[1].getAttribute('style') == null).should.equal(true);
});
it('Options rendered correctly', () => {
var select = view.el.querySelector('select');
var children = select.children;
expect(children[0].value).toEqual(options[0].value);
expect(children[1].value).toEqual(options[1].value);
expect(children[0].textContent).toEqual(options[0].value);
expect(children[1].textContent).toEqual(options[1].name);
expect(children[0].getAttribute('style')).toEqual(options[0].style);
expect(children[1].getAttribute('style')).toEqual(null);
});
it('Input should exist', function() {
view.$input.should.be.ok;
});
it('Input should exist', () => {
expect(view.$input).toExist();
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
});
it('Input value is empty', () => {
expect(view.model.get('value')).toNotExist();
});
it('Update model on input change', function() {
view.$input.val(propValue).trigger('change');
view.model.get('value').should.equal(propValue);
});
it('Update model on input change', () => {
view.$input.val(propValue).trigger('change');
expect(view.model.get('value')).toEqual(propValue);
});
it('Update input on value change', function() {
view.model.set('value', propValue);
view.$input.val().should.equal(propValue);
});
it('Update input on value change', () => {
view.model.set('value', propValue);
expect(view.$input.val()).toEqual(propValue);
});
it('Update target on value change', function() {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
compStyle.should.deep.equal(assertStyle);
});
it('Update target on value change', () => {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
expect(compStyle).toEqual(assertStyle);
});
describe('With target setted', function() {
beforeEach(function () {
target.model = component;
view = new PropertySelectView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal(propValue);
view.$input.val().should.equal(propValue);
});
it('Update value after multiple swaps', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = 'test2value';
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal('test2value');
view.$input.val().should.equal('test2value');
});
})
describe('Init property', function() {
beforeEach(function () {
component = new Component();
model = new Property({
type: 'select',
list: options,
defaults: defValue,
property: propName
});
view = new PropertySelectView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', function() {
view.model.get('value').should.equal(defValue);
});
it('Empty value as default', function() {
options = [
{value: 'test1value', name: 'test1'},
{value: 'test2value', name: 'test2'},
{value: '', name: 'TestDef'}
];
component = new Component();
model = new Property({
type: 'select',
list: options,
defaults: '',
property: 'emptyDefault'
});
view = new PropertySelectView({
model: model
});
$fixture.html(view.render().el);
view.$input.val().should.equal('');
});
it('Input value is as default', function() {
view.$input.val().should.equal(defValue);
});
describe('With target setted', () => {
beforeEach(() => {
target.model = component;
view = new PropertySelectView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Update value and input on target swap', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual(propValue);
expect(view.$input.val()).toEqual(propValue);
});
it('Update value after multiple swaps', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = 'test2value';
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual('test2value');
expect(view.$input.val()).toEqual('test2value');
});
})
describe('Init property', () => {
beforeEach(() => {
component = new Component();
model = new Property({
type: 'select',
list: options,
defaults: defValue,
property: propName
});
view = new PropertySelectView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', () => {
expect(view.model.get('value')).toEqual(defValue);
});
it('Empty value as default', () => {
options = [
{value: 'test1value', name: 'test1'},
{value: 'test2value', name: 'test2'},
{value: '', name: 'TestDef'}
];
component = new Component();
model = new Property({
type: 'select',
list: options,
defaults: '',
property: 'emptyDefault'
});
view = new PropertySelectView({
model
});
$fixture.html(view.render().el);
expect(view.$input.val()).toEqual('');
});
it('Input value is as default', () => {
expect(view.$input.val()).toEqual(defValue);
});
});
}
};
});
});
}
};

655
test/specs/style_manager/view/PropertyStackView.js

@ -1,350 +1,347 @@
define(function(require, exports, module){
'use strict';
var PropertyStackView = require('undefined');
var Property = require('StyleManager/model/Property');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('PropertyStackView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var layers = [
{value: 'lval1'},
{value: 'lval2 lval22'},
{value: 'lval3 lval32 lval33'}
];
var properties = [
{property: 'subprop1'},
{
type: 'integer',
property: 'subprop2',
defaults: 0,
units: ['%', 'px']
},
{
type: 'select',
property: 'subprop3',
defaults: 'val2',
list: [
{value:'val1'},
{value:'val2'},
{value:'val3'},
]
},
];
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
const PropertyStackView = require('style_manager/view/PropertyStackView');
const Property = require('style_manager/model/Property');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('PropertyStackView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
var layers = [
{value: 'lval1'},
{value: 'lval2 lval22'},
{value: 'lval3 lval32 lval33'}
];
var properties = [
{property: 'subprop1'},
{
type: 'integer',
property: 'subprop2',
defaults: 0,
units: ['%', 'px']
},
{
type: 'select',
property: 'subprop3',
defaults: 'val2',
list: [
{value:'val1'},
{value:'val2'},
{value:'val3'},
]
},
];
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
target.model = component;
model = new Property({
type: 'stack',
property: propName,
properties: properties
});
view = new PropertyStackView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
beforeEach(() => {
target = new Component();
component = new Component();
target.model = component;
model = new Property({
type: 'stack',
property: propName,
properties
});
view = new PropertyStackView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
//view.remove(); // strange errors ???
});
afterEach(() => {
//view.remove(); // strange errors ???
});
after(function () {
$fixture.remove();
delete component;
delete view;
delete model;
});
after(() => {
$fixture.remove();
component = null;
view = null;
model = null;
});
it('Rendered correctly', function() {
var prop = view.el;
$fixture.get(0).querySelector('.property').should.be.ok;
prop.querySelector('.label').should.be.ok;
prop.querySelector('.field').should.be.ok;
prop.querySelector('#add').should.be.ok;
});
it('Rendered correctly', () => {
var prop = view.el;
expect($fixture.get(0).querySelector('.property')).toExist();
expect(prop.querySelector('.label')).toExist();
expect(prop.querySelector('.field')).toExist();
expect(prop.querySelector('#add')).toExist();
});
it('Layers rendered', function() {
view.el.querySelector('.layers').should.be.ok;
});
it('Layers rendered', () => {
expect(view.el.querySelector('.layers')).toExist();
});
it('Layers should exist', function() {
view.$props.should.be.ok;
});
it('Layers should exist', () => {
expect(view.$props).toExist();
});
it('Layers rendered correctly', function() {
var children = view.$props.get(0).children;
children.length.should.equal(properties.length + 1);
children[0].id.should.equal(properties[0].property);
children[1].id.should.equal(properties[1].property);
children[2].id.should.equal(properties[2].property);
});
it('Layers rendered correctly', () => {
var children = view.$props.get(0).children;
expect(children.length).toEqual(properties.length + 1);
expect(children[0].id).toEqual(properties[0].property);
expect(children[1].id).toEqual(properties[1].property);
expect(children[2].id).toEqual(properties[2].property);
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
});
it('Input value is empty', () => {
expect(view.model.get('value')).toNotExist();
});
it('Layers container is empty', function() {
var layers = view.el.querySelector('.layers');
layers.innerHTML.should.be.empty;
});
it('Layers container is empty', () => {
var layers = view.el.querySelector('.layers');
expect(layers.innerHTML).toNotExist();
});
describe('With layers', function() {
beforeEach(function () {
model = new Property({
type: 'stack',
property: propName,
properties: properties,
});
view = new PropertyStackView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
model.get('layers').add(layers);
});
it('Layers inserted', function() {
view.getLayers().length.should.equal(layers.length);
});
it('Get value on index', function() {
view.model.set('stackIndex', 1);
view.valueOnIndex(1).should.equal('lval22');
});
it('createValue merges layers', function() {
view.createValue().should.equal('lval1, lval2 lval22, lval3 lval32 lval33');
});
it('Add layer', function() {
view.addLayer();
view.getLayers().length.should.equal(layers.length+1);
});
describe('With layers', () => {
beforeEach(() => {
model = new Property({
type: 'stack',
property: propName,
properties,
});
view = new PropertyStackView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
model.get('layers').add(layers);
});
it('Layers inserted', () => {
expect(view.getLayers().length).toEqual(layers.length);
});
it('Get value on index', () => {
view.model.set('stackIndex', 1);
expect(view.valueOnIndex(1)).toEqual('lval22');
});
it('createValue merges layers', () => {
expect(view.createValue()).toEqual('lval1, lval2 lval22, lval3 lval32 lval33');
});
describe('With target setted', function() {
var prop2Val;
var prop3Val;
var prop2Unit;
var finalResult;
var $prop1;
var $prop2;
var $prop3;
beforeEach(function () {
model = new Property({
type: 'stack',
property: propName,
properties: properties
});
view = new PropertyStackView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
prop3Val = properties[2].list[2].value;
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
finalResult = propValue + ' ' + prop2Val + prop2Unit +' ' + prop3Val;
view.addLayer();
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
});
it('Update model on input change', function() {
$prop1.val(propValue).trigger('change');
$prop3.val(prop3Val).trigger('change');
view.model.get('value').should.equal(finalResult);
});
it('Update value on models change', function() {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
view.model.get('value').should.equal(finalResult);
});
it('Update target on value change', function() {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[propName] = propValue + ' 0% val2';
compStyle.should.deep.equal(assertStyle);
});
it('Update value and input on target swap', function() {
var style = {};
var finalResult2 = 'A B C';
style[propName] = finalResult + ', ' + finalResult2;
component.set('style', style);
view.propTarget.trigger('update');
var layers = view.getLayers();
layers.at(0).get('value').should.equal(finalResult);
layers.at(1).get('value').should.equal(finalResult2);
});
it('Update value after multiple swaps', function() {
var style = {};
var finalResult2 = 'A2 B2 C2';
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = finalResult + ', ' + finalResult2;
component.set('style', style);
view.propTarget.trigger('update');
var layers = view.getLayers();
layers.at(0).get('value').should.equal(finalResult);
layers.at(1).get('value').should.equal(finalResult2);
});
it('The value is correctly extracted from the composite string', function() {
var style = {};
style[propName] = 'value1 value2, value3 value4';
component.set('style', style);
view.propTarget.trigger('update');
view.model.set('stackIndex', 1);
view.valueOnIndex(0).should.equal('value3');
view.valueOnIndex(1).should.equal('value4');
(view.valueOnIndex(2) === null).should.equal(true);
});
it('The value is correctly extracted from the string with functions', function() {
var style = {};
style[propName] = 'func(a1a, s2a,d3a) value1 value2, func(4ddb, aAS5b, sS.6b) value3';
component.set('style', style);
view.propTarget.trigger('update');
view.model.set('stackIndex', 1);
view.valueOnIndex(0).should.equal('func(4ddb,aAS5b,sS.6b)');
view.valueOnIndex(1).should.equal('value3');
(view.valueOnIndex(2) === null).should.equal(true);
});
it('Build value from properties', function() {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
view.build().should.equal(finalResult);
});
it('Add layer', () => {
view.addLayer();
expect(view.getLayers().length).toEqual(layers.length + 1);
});
});
describe('With target setted', () => {
var prop2Val;
var prop3Val;
var prop2Unit;
var finalResult;
var $prop1;
var $prop2;
var $prop3;
beforeEach(() => {
model = new Property({
type: 'stack',
property: propName,
properties
});
view = new PropertyStackView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
prop3Val = properties[2].list[2].value;
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
finalResult = propValue + ' ' + prop2Val + prop2Unit +' ' + prop3Val;
view.addLayer();
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
});
it('Update model on input change', () => {
$prop1.val(propValue).trigger('change');
$prop3.val(prop3Val).trigger('change');
expect(view.model.get('value')).toEqual(finalResult);
});
it('Update value on models change', () => {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
expect(view.model.get('value')).toEqual(finalResult);
});
it('Update target on value change', () => {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[propName] = propValue + ' 0% val2';
expect(compStyle).toEqual(assertStyle);
});
it('Update value and input on target swap', () => {
var style = {};
var finalResult2 = 'A B C';
style[propName] = finalResult + ', ' + finalResult2;
component.set('style', style);
view.propTarget.trigger('update');
var layers = view.getLayers();
expect(layers.at(0).get('value')).toEqual(finalResult);
expect(layers.at(1).get('value')).toEqual(finalResult2);
});
it('Update value after multiple swaps', () => {
var style = {};
var finalResult2 = 'A2 B2 C2';
style[propName] = finalResult;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = finalResult + ', ' + finalResult2;
component.set('style', style);
view.propTarget.trigger('update');
var layers = view.getLayers();
expect(layers.at(0).get('value')).toEqual(finalResult);
expect(layers.at(1).get('value')).toEqual(finalResult2);
});
it('The value is correctly extracted from the composite string', () => {
var style = {};
style[propName] = 'value1 value2, value3 value4';
component.set('style', style);
view.propTarget.trigger('update');
view.model.set('stackIndex', 1);
expect(view.valueOnIndex(0)).toEqual('value3');
expect(view.valueOnIndex(1)).toEqual('value4');
expect(view.valueOnIndex(2)).toEqual(null);
});
it('The value is correctly extracted from the string with functions', () => {
var style = {};
style[propName] = 'func(a1a, s2a,d3a) value1 value2, func(4ddb, aAS5b, sS.6b) value3';
component.set('style', style);
view.propTarget.trigger('update');
view.model.set('stackIndex', 1);
expect(view.valueOnIndex(0)).toEqual('func(4ddb,aAS5b,sS.6b)');
expect(view.valueOnIndex(1)).toEqual('value3');
expect(view.valueOnIndex(2)).toEqual(null);
});
it('Build value from properties', () => {
view.model.get('properties').at(0).set('value', propValue);
view.model.get('properties').at(2).set('value', prop3Val);
expect(view.build()).toEqual(finalResult);
});
describe('Detached with target setted', function() {
var prop2Val;
var prop3Val;
var prop2Unit;
var finalResult;
var $prop1;
var $prop2;
var $prop3;
var compStyle = {
subprop1: '1px, 20px, 30px',
subprop2: 'A, B, C',
subprop3: 'W, X, Y',
subprop555: 'T, T, T',
};
beforeEach(function () {
model = new Property({
type: 'stack',
property: propName,
properties: properties,
detached: true,
});
view = new PropertyStackView({
model: model,
propTarget: target
});
$fixture.html(view.render().el);
prop3Val = properties[2].list[2].value;
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
finalResult = propValue + ' ' + prop2Val + prop2Unit +' ' + prop3Val;
view.addLayer();
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
});
it('Returns correctly layers array from target', function() {
component.set('style', compStyle);
var result = [{
subprop1: '1px',
subprop2: 'A',
subprop3: 'W',
},{
subprop1: '20px',
subprop2: 'B',
subprop3: 'X',
},{
subprop1: '30px',
subprop2: 'C',
subprop3: 'Y',
}];
view.getLayersFromTarget().should.deep.equal(result);
});
it('Update target on detached value change', function() {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[properties[0].property] = $prop1.val();
assertStyle[properties[1].property] = '0%';
assertStyle[properties[2].property] = properties[2].defaults;
compStyle.should.deep.equal(assertStyle);
});
it('Update value and input on target swap', function() {
var style = {};
component.set('style', compStyle);
view.propTarget.trigger('update');
var layers = view.getLayers();
layers.length.should.equal(3);
layers.at(0).get('values').should.deep.equal({
subprop1: '1px',
subprop2: 'A',
subprop3: 'W',
});
layers.at(1).get('values').should.deep.equal({
subprop1: '20px',
subprop2: 'B',
subprop3: 'X',
});
layers.at(2).get('values').should.deep.equal({
subprop1: '30px',
subprop2: 'C',
subprop3: 'Y',
});
});
});
describe('Detached with target setted', () => {
var prop2Val;
var prop3Val;
var prop2Unit;
var finalResult;
var $prop1;
var $prop2;
var $prop3;
var compStyle = {
subprop1: '1px, 20px, 30px',
subprop2: 'A, B, C',
subprop3: 'W, X, Y',
subprop555: 'T, T, T',
};
beforeEach(() => {
model = new Property({
type: 'stack',
property: propName,
properties,
detached: true,
});
view = new PropertyStackView({
model,
propTarget: target
});
$fixture.html(view.render().el);
prop3Val = properties[2].list[2].value;
prop2Val = properties[1].defaults;
prop2Unit = properties[1].units[0];
finalResult = propValue + ' ' + prop2Val + prop2Unit +' ' + prop3Val;
view.addLayer();
$prop1 = view.$props.find('#' + properties[0].property + ' input');
$prop2 = view.$props.find('#' + properties[1].property + ' input');
$prop3 = view.$props.find('#' + properties[2].property + ' select');
});
it('Returns correctly layers array from target', () => {
component.set('style', compStyle);
var result = [{
subprop1: '1px',
subprop2: 'A',
subprop3: 'W',
},{
subprop1: '20px',
subprop2: 'B',
subprop3: 'X',
},{
subprop1: '30px',
subprop2: 'C',
subprop3: 'Y',
}];
expect(view.getLayersFromTarget()).toEqual(result);
});
it('Update target on detached value change', () => {
$prop1.val(propValue).trigger('change');
var compStyle = view.getTarget().get('style');
var assertStyle = {};
assertStyle[properties[0].property] = $prop1.val();
assertStyle[properties[1].property] = '0%';
assertStyle[properties[2].property] = properties[2].defaults;
expect(compStyle).toEqual(assertStyle);
});
it('Update value and input on target swap', () => {
var style = {};
component.set('style', compStyle);
view.propTarget.trigger('update');
var layers = view.getLayers();
expect(layers.length).toEqual(3);
expect(layers.at(0).get('values')).toEqual({
subprop1: '1px',
subprop2: 'A',
subprop3: 'W',
});
expect(layers.at(1).get('values')).toEqual({
subprop1: '20px',
subprop2: 'B',
subprop3: 'X',
});
expect(layers.at(2).get('values')).toEqual({
subprop1: '30px',
subprop2: 'C',
subprop3: 'Y',
});
});
});
}
};
});
});
}
};

427
test/specs/style_manager/view/PropertyView.js

@ -1,238 +1,233 @@
define(function(require, exports, module){
'use strict';
var PropertyView = require('undefined');
var Property = require('StyleManager/model/Property');
var Component = require('DomComponents/model/Component');
module.exports = {
run : function(){
describe('PropertyView', function() {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propName = 'testprop';
var propValue = 'testvalue';
var defValue = 'testDefault';
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
beforeEach(function () {
target = new Component();
component = new Component();
model = new Property({property: propName});
view = new PropertyView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
const PropertyView = require('style_manager/view/PropertyView');
const Property = require('style_manager/model/Property');
const Component = require('dom_components/model/Component');
module.exports = {
run() {
describe('PropertyView', () => {
var component;
var $fixtures;
var $fixture;
var target;
var model;
var view;
var propTarget;
var options;
var propName = 'testprop';
var propValue = 'testvalue';
var defValue = 'testDefault';
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sm-fixture"></div>');
});
afterEach(function () {
//view.remove(); // strange errors ???
});
beforeEach(() => {
propTarget = Object.assign({}, Backbone.Events);
target = new Component();
component = new Component();
model = new Property({property: propName});
propTarget.model = component;
options = {
model,
propTarget
};
view = new PropertyView(options);
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
delete component;
});
afterEach(() => {
//view.remove(); // strange errors ???
});
it('Rendered correctly', function() {
var prop = view.el;
$fixture.get(0).querySelector('.property').should.be.ok;
prop.querySelector('.label').should.be.ok;
prop.querySelector('.field').should.be.ok;
});
after(() => {
$fixture.remove();
component = null;
});
it('Input should exist', function() {
view.$input.should.be.ok;
});
it('Rendered correctly', () => {
var prop = view.el;
expect($fixture.get(0).querySelector('.property')).toExist();
expect(prop.querySelector('.label')).toExist();
expect(prop.querySelector('.field')).toExist();
});
it('Input value is empty', function() {
view.model.get('value').should.be.empty;
view.$input.val().should.be.empty;
});
it('Input should exist', () => {
expect(view.$input).toExist();
});
it('Model not change without update trigger', function() {
view.$input.val(propValue);
view.model.get('value').should.be.empty;
});
it('Input value is empty', () => {
expect(view.model.get('value')).toNotExist();
expect(view.$input.val()).toNotExist();
});
// Tests valueUpdated()
it('Update model on input change', function() {
view.$input.val(propValue).trigger('change');
view.model.get('value').should.equal(propValue);
});
it('Model not change without update trigger', () => {
view.$input.val(propValue);
expect(view.model.get('value')).toNotExist();
});
// Tests getValueForTarget()
it('Get value for target', function() {
view.model.set('value', propValue);
view.getValueForTarget().should.equal(propValue);
});
// Tests valueUpdated()
it('Update model on input change', () => {
view.$input.val(propValue).trigger('change');
expect(view.model.get('value')).toEqual(propValue);
});
// Tests valueChanged() -> ...
it('Update input on value change', function() {
view.model.set('value', propValue);
view.$input.val().should.equal(propValue);
});
// Tests getValueForTarget()
it('Get value for target', () => {
view.model.set('value', propValue);
expect(view.getValueForTarget()).toEqual(propValue);
});
it('Update target on value change', function() {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
compStyle.should.deep.equal(assertStyle);
});
// Tests valueChanged() -> ...
it('Update input on value change', () => {
view.model.set('value', propValue);
expect(view.$input.val()).toEqual(propValue);
});
it('Update target on value change with functionName', function() {
view.selectedComponent = component;
view.model.set('functionName', 'testfunc');
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var assertStyle = {};
assertStyle[propName] = 'testfunc(' + propValue + ')';
compStyle.should.deep.equal(assertStyle);
});
it('Update target on value change', () => {
view.model.set('value', propValue);
var compStyle = view.getTargetModel().get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
expect(compStyle).toEqual(assertStyle);
});
it('Clean target from the property if its value is empty', function() {
view.selectedComponent = component;
view.model.set('value', propValue);
view.model.set('value', '');
var compStyle = view.selectedComponent.get('style');
compStyle.should.deep.equal({});
});
it('Update target on value change with functionName', () => {
view.model.set('functionName', 'testfunc');
view.model.set('value', propValue);
var compStyle = view.getTargetModel().get('style');
var assertStyle = {};
assertStyle[propName] = 'testfunc(' + propValue + ')';
expect(compStyle).toEqual(assertStyle);
});
it('Check stylable element', function() {
view.selectedComponent = component;
view.isTargetStylable().should.equal(true);
component.set('stylable', false);
view.isTargetStylable().should.equal(false);
component.set('stylable', [propName]);
view.isTargetStylable().should.equal(true);
component.set('stylable', ['test1', propName]);
view.isTargetStylable().should.equal(true);
component.set('stylable', ['test1', 'test2']);
view.isTargetStylable().should.equal(false);
});
it('Clean target from the property if its value is empty', () => {
view.model.set('value', propValue);
view.model.set('value', '');
var compStyle = view.getTargetModel().get('style');
expect(compStyle).toEqual({});
});
it('Target style is empty without values', function() {
view.selectedComponent = component;
view.getComponentValue().should.be.empty;
});
it('Check stylable element', () => {
expect(view.isTargetStylable()).toEqual(true);
component.set('stylable', false);
expect(view.isTargetStylable()).toEqual(false);
component.set('stylable', [propName]);
expect(view.isTargetStylable()).toEqual(true);
component.set('stylable', ['test1', propName]);
expect(view.isTargetStylable()).toEqual(true);
component.set('stylable', ['test1', 'test2']);
expect(view.isTargetStylable()).toEqual(false);
});
it('Target style is correct', function() {
view.selectedComponent = component;
var style = {};
style[propName] = propValue;
component.set('style', style);
view.getComponentValue().should.equal(propValue);
});
it('Target style is empty without values', () => {
expect(view.getComponentValue()).toNotExist();
});
it('Target style is empty with an other style', function() {
view.selectedComponent = component;
var style = {};
style[propName + '2'] = propValue;
component.set('style', style);
view.getComponentValue().should.be.empty;
});
it('Target style is correct', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
expect(view.getComponentValue()).toEqual(propValue);
});
it('Fetch value from function', function() {
view.selectedComponent = component;
var style = {};
style[propName] = 'testfun(' + propValue + ')';
component.set('style', style);
view.model.set('functionName', 'testfun');
view.getComponentValue().should.equal(propValue);
});
it('Target style is empty with an other style', () => {
var style = {};
style[propName + '2'] = propValue;
component.set('style', style);
expect(view.getComponentValue()).toNotExist();
});
describe('With target setted', function() {
beforeEach(function () {
target.model = component;
view = new PropertyView({
model: model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('updateTargetStyle', function() {
view.updateTargetStyle(propValue);
var style = {};
style[propName] = propValue;
component.get('style').should.deep.equal(style);
});
it('updateTargetStyle with custom property', function() {
view.updateTargetStyle(propValue, propName + '2');
var style = {};
style[propName + '2'] = propValue;
component.get('style').should.deep.equal(style);
});
it('Update value and input on target swap', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal(propValue);
view.$input.val().should.equal(propValue);
});
it('Update value after multiple swaps', function() {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = propValue + '2';
component.set('style', style);
view.propTarget.trigger('update');
view.model.get('value').should.equal(propValue + '2');
view.$input.val().should.equal(propValue + '2');
});
})
describe('Init property', function() {
beforeEach(function () {
component = new Component();
model = new Property({
property: propName,
defaults: defValue
});
view = new PropertyView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', function() {
view.model.get('value').should.equal(defValue);
});
it('Placeholder as default', function() {
view.$input.attr('placeholder').should.equal(defValue);
});
it('Input value is empty', function() {
view.$input.val().should.equal(defValue);
});
it('Fetch value from function', () => {
view.selectedComponent = component;
var style = {};
style[propName] = 'testfun(' + propValue + ')';
component.set('style', style);
view.model.set('functionName', 'testfun');
expect(view.getComponentValue()).toEqual(propValue);
});
});
describe('With target setted', () => {
beforeEach(() => {
target.model = component;
view = new PropertyView({
model,
propTarget: target
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('updateTargetStyle', () => {
view.updateTargetStyle(propValue);
var style = {};
style[propName] = propValue;
expect(component.get('style')).toEqual(style);
});
it('updateTargetStyle with custom property', () => {
view.updateTargetStyle(propValue, propName + '2');
var style = {};
style[propName + '2'] = propValue;
expect(component.get('style')).toEqual(style);
});
it('Update value and input on target swap', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual(propValue);
expect(view.$input.val()).toEqual(propValue);
});
it('Update value after multiple swaps', () => {
var style = {};
style[propName] = propValue;
component.set('style', style);
view.propTarget.trigger('update');
style[propName] = propValue + '2';
component.set('style', style);
view.propTarget.trigger('update');
expect(view.model.get('value')).toEqual(propValue + '2');
expect(view.$input.val()).toEqual(propValue + '2');
});
})
describe('Init property', () => {
beforeEach(() => {
component = new Component();
model = new Property({
property: propName,
defaults: defValue
});
view = new PropertyView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
it('Value as default', () => {
expect(view.model.get('value')).toEqual(defValue);
});
it('Placeholder as default', () => {
expect(view.$input.attr('placeholder')).toEqual(defValue);
});
it('Input value is empty', () => {
expect(view.$input.val()).toEqual(defValue);
});
});
}
};
});
});
}
};

181
test/specs/style_manager/view/SectorView.js

@ -1,109 +1,104 @@
define(function(require, exports, module){
'use strict';
var SectorView = require('undefined');
var Sector = require('StyleManager/model/Sector');
const SectorView = require('style_manager/view/SectorView');
const Sector = require('style_manager/model/Sector');
module.exports = {
run : function(){
module.exports = {
run() {
describe('SectorView', function() {
describe('SectorView', () => {
var $fixtures;
var $fixture;
var model;
var view;
var $fixtures;
var $fixture;
var model;
var view;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sector-fixture"></div>');
});
beforeEach(function () {
model = new Sector();
view = new SectorView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sector-fixture"></div>');
});
afterEach(function () {
view.remove();
});
beforeEach(() => {
model = new Sector();
view = new SectorView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
after(function () {
$fixture.remove();
});
afterEach(() => {
view.remove();
});
it('Rendered correctly', function() {
var sector = view.el;
sector.should.be.ok;
sector.querySelector('.title').should.be.ok;
var props = sector.querySelector('.properties');
props.should.be.ok;
sector.classList.contains('open').should.equal(true);
});
after(() => {
$fixture.remove();
});
it('No properties', function() {
var props = view.el.querySelector('.properties');
props.innerHTML.should.equal('<div class="clear"></div>');
});
it('Rendered correctly', () => {
var sector = view.el;
expect(sector.querySelector('.title')).toExist();
var props = sector.querySelector('.properties');
expect(props).toExist();
expect(sector.classList.contains('open')).toEqual(true);
});
it('Update on open', function() {
var sector = view.el;
var props = sector.querySelector('.properties');
model.set('open', false);
sector.classList.contains('open').should.equal(false);
props.style.display.should.equal('none');
});
it('No properties', () => {
var props = view.el.querySelector('.properties');
expect(props.innerHTML).toEqual('<div class="clear"></div>');
});
it('Toggle on click', function() {
var sector = view.el;
view.$el.find('.title').click();
sector.classList.contains('open').should.equal(false);
});
it('Update on open', () => {
var sector = view.el;
var props = sector.querySelector('.properties');
model.set('open', false);
expect(sector.classList.contains('open')).toEqual(false);
expect(props.style.display).toEqual('none');
});
describe('Init with options', function() {
beforeEach(function () {
model = new Sector({
open: false,
name: 'TestName',
properties: [
{type:'integer'},
{type:'integer'},
{type:'integer'},
]
});
view = new SectorView({
model: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
view.remove();
});
it('Rendered correctly2', function() {
var sector = view.el;
var props = sector.querySelector('.properties');
sector.querySelector('.title').innerHTML.should.contain('TestName');
props.should.be.ok;
sector.classList.contains('open').should.equal(false);
props.style.display.should.equal('none');
});
it('Has properties', function() {
var props = view.el.querySelector('.properties');
props.children.length.should.equal(4); // Last one is 'clear' element
});
it('Toggle on click', () => {
var sector = view.el;
view.$el.find('.title').click();
expect(sector.classList.contains('open')).toEqual(false);
});
describe('Init with options', () => {
beforeEach(() => {
model = new Sector({
open: false,
name: 'TestName',
properties: [
{type:'integer'},
{type:'integer'},
{type:'integer'},
]
});
view = new SectorView({
model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(() => {
view.remove();
});
it('Rendered correctly2', () => {
var sector = view.el;
var props = sector.querySelector('.properties');
expect(sector.querySelector('.title').innerHTML).toContain('TestName');
expect(props).toExist();
expect(sector.classList.contains('open')).toEqual(false);
expect(props.style.display).toEqual('none');
});
it('Has properties', () => {
var props = view.el.querySelector('.properties');
expect(props.children.length).toEqual(4); // Last one is 'clear' element
});
});
}
};
});
});
}
};

92
test/specs/style_manager/view/SectorsView.js

@ -1,51 +1,47 @@
define(function(require, exports, module){
'use strict';
var SectorsView = require('undefined');
var Sectors = require('StyleManager/model/Sectors');
module.exports = {
run : function(){
describe('SectorsView', function() {
var $fixtures;
var $fixture;
var model;
var view;
before(function () {
$fixtures = $("#fixtures");
$fixture = $('<div class="sectors-fixture"></div>');
});
beforeEach(function () {
model = new Sectors([]);
view = new SectorsView({
collection: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(function () {
view.collection.reset();
});
after(function () {
$fixture.remove();
});
it("Collection is empty", function (){
view.el.innerHTML.should.be.empty;
});
it("Add new sectors", function (){
view.collection.add([{}, {}]);
view.el.children.length.should.equal(2);
});
const SectorsView = require('style_manager/view/SectorsView');
const Sectors = require('style_manager/model/Sectors');
module.exports = {
run() {
describe('SectorsView', () => {
var $fixtures;
var $fixture;
var model;
var view;
before(() => {
$fixtures = $("#fixtures");
$fixture = $('<div class="sectors-fixture"></div>');
});
beforeEach(() => {
model = new Sectors([]);
view = new SectorsView({
collection: model
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
afterEach(() => {
view.collection.reset();
});
after(() => {
$fixture.remove();
});
it("Collection is empty", () => {
expect(view.el.innerHTML).toEqual('');
});
it("Add new sectors", () => {
view.collection.add([{}, {}]);
expect(view.el.children.length).toEqual(2);
});
}
};
});
});
}
};

8
test/specs/test_utils.js

@ -1,15 +1,15 @@
module.exports = {
storageMock: function() {
storageMock() {
var db = {};
return {
id: 'testStorage',
store: function(data){
store(data) {
db = data;
},
load: function(keys){
load(keys) {
return db;
},
getDb: function(){
getDb() {
return db;
},
};

23
test/specs/trait_manager/index.js

@ -0,0 +1,23 @@
const TraitManager = require('trait_manager');
const TraitsModel = require('./model/TraitsModel');
const TraitsView = require('./view/TraitsView');
describe('TraitManager', () => {
describe('Main', () => {
var obj;
beforeEach(() => {
obj = new TraitManager().init();
});
afterEach(() => {
obj = null;
});
});
TraitsModel.run();
TraitsView.run();
});

25
test/specs/trait_manager/main.js

@ -1,25 +0,0 @@
define(function(require, exports, module){
'use strict';
var TraitManager = require('TraitManager');
var TraitsView = require('undefined');
describe('TraitManager', function() {
describe('Main', function() {
var obj;
beforeEach(function () {
obj = new TraitManager().init();
});
afterEach(function () {
delete obj;
});
});
TraitsModel.run();
TraitsView.run();
});
});

51
test/specs/trait_manager/model/TraitsModel.js

@ -1,34 +1,31 @@
define(function(require, exports, module){
'use strict';
var Trait = require('TraitManager/model/Trait');
var Component = require('DomComponents/model/Component');
const Trait = require('trait_manager/model/Trait');
const Component = require('dom_components/model/Component');
module.exports = {
run: function(){
module.exports = {
run() {
describe('TraitModels', function() {
describe('TraitModels', () => {
var obj;
var target;
var modelName = 'title';
var obj;
var target;
var modelName = 'title';
beforeEach(function () {
target = new Component();
obj = new Trait({
name: modelName,
target: target,
});
});
beforeEach(() => {
target = new Component();
obj = new Trait({
name: modelName,
target,
});
});
afterEach(function () {
delete obj;
});
afterEach(() => {
obj = null;
});
it('Object exists', function() {
Trait.should.be.exist;
});
it('Object exists', () => {
expect(Trait).toExist();
});
});
}
}
});
});
}
}

126
test/specs/trait_manager/view/TraitsView.js

@ -1,75 +1,73 @@
define(function(require, exports, module){
'use strict';
var Trait = require('undefined');
var Component = require('DomComponents/model/Component');
const Trait = require('trait_manager/model/Trait');
const TraitView = require('trait_manager/view/TraitView');
const Component = require('dom_components/model/Component');
module.exports = {
run: function(){
module.exports = {
run() {
describe('TraitView', function() {
describe('TraitView', () => {
var obj;
var model;
var modelName = 'title';
var target;
var obj;
var model;
var modelName = 'title';
var target;
beforeEach(function () {
target = new Component();
model = new Trait({
name: modelName,
target: target,
});
obj = new TraitView({
model: model,
});
});
beforeEach(() => {
target = new Component();
model = new Trait({
name: modelName,
target,
});
obj = new TraitView({
model,
});
});
afterEach(function () {
delete obj;
delete model;
delete target;
});
afterEach(() => {
obj = null;
model = null;
target = null;
});
it('Object exists', function() {
Trait.should.be.exist;
});
it('Object exists', () => {
expect(Trait).toExist();
});
it('Target has no attributes on init', function() {
target.get('attributes').should.deep.equal({});
});
it('Target has no attributes on init', () => {
expect(target.get('attributes')).toEqual({});
});
it('On update of the value updates the target attributes', function() {
model.set('value', 'test');
var eq = {};
eq[modelName] = 'test';
target.get('attributes').should.deep.equal(eq);
});
it('On update of the value updates the target attributes', () => {
model.set('value', 'test');
var eq = {};
eq[modelName] = 'test';
expect(target.get('attributes')).toEqual(eq);
});
it('Updates on different models do not alter other targets', function() {
var target1 = new Component();
var target2 = new Component();
var model1 = new Trait({
name: modelName,
target: target1,
});
var model2 = new Trait({
name: modelName,
target: target2,
});
var obj1 = new TraitView({model: model1});
var obj2 = new TraitView({model: model2});
it('Updates on different models do not alter other targets', () => {
var target1 = new Component();
var target2 = new Component();
var model1 = new Trait({
name: modelName,
target: target1,
});
var model2 = new Trait({
name: modelName,
target: target2,
});
var obj1 = new TraitView({model: model1});
var obj2 = new TraitView({model: model2});
model1.set('value', 'test1');
model2.set('value', 'test2');
var eq1 = {};
eq1[modelName] = 'test1';
var eq2 = {};
eq2[modelName] = 'test2';
target1.get('attributes').should.deep.equal(eq1);
target2.get('attributes').should.deep.equal(eq2);
});
model1.set('value', 'test1');
model2.set('value', 'test2');
var eq1 = {};
eq1[modelName] = 'test1';
var eq2 = {};
eq2[modelName] = 'test2';
expect(target1.get('attributes')).toEqual(eq1);
expect(target2.get('attributes')).toEqual(eq2);
});
});
}
}
});
});
}
}

4
test/specs/utils/main.js

@ -1,9 +1,9 @@
define(function(require, exports, module){
define((require, exports, module) => {
'use strict';
var Utils = require('Utils');
var Sorter = require('undefined');
describe('Utils', function() {
describe('Utils', () => {
Sorter.run();

457
yarn.lock

@ -40,7 +40,13 @@ acorn-globals@^3.1.0:
dependencies:
acorn "^4.0.4"
acorn@^3.1.0:
acorn-jsx@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
dependencies:
acorn "^3.0.4"
acorn@^3.0.4, acorn@^3.1.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
@ -48,11 +54,11 @@ acorn@^4.0.3, acorn@^4.0.4:
version "4.0.13"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
acorn@^5.0.0:
acorn@^5.0.0, acorn@^5.0.1:
version "5.0.3"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d"
ajv-keywords@^1.1.1:
ajv-keywords@^1.0.0, ajv-keywords@^1.1.1:
version "1.5.1"
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
@ -79,6 +85,10 @@ ansi-escapes@^1.0.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e"
ansi-escapes@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-2.0.0.tgz#5bae52be424878dd9783e8910e3fc2922e83c81b"
ansi-html@0.0.5:
version "0.0.5"
resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.5.tgz#0dcaa5a081206866bc240a3b773a184ea3b88b64"
@ -91,6 +101,10 @@ ansi-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.0.0.tgz#c5061b6e0ef8a81775e50f5d66151bf6bf371107"
ansi-regex@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
ansi-styles@^2.0.1, ansi-styles@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
@ -214,10 +228,6 @@ async@^2.1.2:
dependencies:
lodash "^4.14.0"
async@~0.2.6:
version "0.2.10"
resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
asynckit@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
@ -958,6 +968,10 @@ balanced-match@^0.4.1:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
balanced-match@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base64-js@^1.0.2:
version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
@ -1022,6 +1036,13 @@ brace-expansion@^1.0.0:
balanced-match "^0.4.1"
concat-map "0.0.1"
brace-expansion@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292"
dependencies:
balanced-match "^1.0.0"
concat-map "0.0.1"
braces@^1.8.2:
version "1.8.5"
resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7"
@ -1137,6 +1158,16 @@ bytes@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339"
caller-path@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f"
dependencies:
callsites "^0.2.0"
callsites@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
camelcase-keys@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
@ -1179,7 +1210,7 @@ chai@^3.5.0:
deep-eql "^0.1.3"
type-detect "^1.0.0"
chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1:
chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
dependencies:
@ -1226,12 +1257,26 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
dependencies:
inherits "^2.0.1"
circular-json@^0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d"
cli-cursor@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987"
dependencies:
restore-cursor "^1.0.1"
cli-cursor@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
dependencies:
restore-cursor "^2.0.0"
cli-width@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a"
cliui@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
@ -1325,6 +1370,14 @@ concat-stream@^1.0.0, concat-stream@^1.5.0, concat-stream@~1.5.0:
readable-stream "~2.0.0"
typedarray "~0.0.5"
concat-stream@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
dependencies:
inherits "^2.0.3"
readable-stream "^2.2.2"
typedarray "^0.0.6"
connect-history-api-fallback@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169"
@ -1523,6 +1576,18 @@ defined@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
del@^2.0.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8"
dependencies:
globby "^5.0.0"
is-path-cwd "^1.0.0"
is-path-in-cwd "^1.0.0"
object-assign "^4.0.1"
pify "^2.0.0"
pinkie-promise "^2.0.0"
rimraf "^2.2.8"
delayed-stream@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
@ -1595,6 +1660,13 @@ doctrine@^1.1.0:
esutils "^2.0.2"
isarray "^1.0.0"
doctrine@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63"
dependencies:
esutils "^2.0.2"
isarray "^1.0.0"
documentation@^4.0.0-beta2:
version "4.0.0-beta9"
resolved "https://registry.yarnpkg.com/documentation/-/documentation-4.0.0-beta9.tgz#8221b25286ce9563c7c9bb7710241255ccd2ee79"
@ -1773,7 +1845,7 @@ escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2:
escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
@ -1788,14 +1860,87 @@ escodegen@1.8.x, escodegen@^1.6.1:
optionalDependencies:
source-map "~0.2.0"
eslint-scope@^3.7.1:
version "3.7.1"
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8"
dependencies:
esrecurse "^4.1.0"
estraverse "^4.1.1"
eslint@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.1.1.tgz#facbdfcfe3e0facd3a8b80dc98c4e6c13ae582df"
dependencies:
babel-code-frame "^6.22.0"
chalk "^1.1.3"
concat-stream "^1.6.0"
debug "^2.6.8"
doctrine "^2.0.0"
eslint-scope "^3.7.1"
espree "^3.4.3"
esquery "^1.0.0"
estraverse "^4.2.0"
esutils "^2.0.2"
file-entry-cache "^2.0.0"
glob "^7.1.2"
globals "^9.17.0"
ignore "^3.3.3"
imurmurhash "^0.1.4"
inquirer "^3.0.6"
is-my-json-valid "^2.16.0"
is-resolvable "^1.0.0"
js-yaml "^3.8.4"
json-stable-stringify "^1.0.1"
levn "^0.3.0"
lodash "^4.17.4"
minimatch "^3.0.2"
mkdirp "^0.5.1"
natural-compare "^1.4.0"
optionator "^0.8.2"
path-is-inside "^1.0.2"
pluralize "^4.0.0"
progress "^2.0.0"
require-uncached "^1.0.3"
strip-json-comments "~2.0.1"
table "^4.0.1"
text-table "~0.2.0"
espree@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374"
dependencies:
acorn "^5.0.1"
acorn-jsx "^3.0.0"
esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esprima@^3.1.1:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
esquery@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa"
dependencies:
estraverse "^4.0.0"
esrecurse@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163"
dependencies:
estraverse "^4.1.0"
object-assign "^4.0.1"
estraverse@^1.9.1:
version "1.9.3"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44"
estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
esutils@^2.0.0, esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
@ -1895,6 +2040,14 @@ extend@^3.0.0, extend@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
external-editor@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972"
dependencies:
iconv-lite "^0.4.17"
jschardet "^1.4.2"
tmp "^0.0.31"
extglob@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1"
@ -1921,6 +2074,19 @@ faye-websocket@~0.11.0:
dependencies:
websocket-driver ">=0.5.1"
figures@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
dependencies:
escape-string-regexp "^1.0.5"
file-entry-cache@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361"
dependencies:
flat-cache "^1.2.1"
object-assign "^4.0.1"
filename-regex@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775"
@ -1966,6 +2132,15 @@ first-chunk-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz#59bfb50cd905f60d7c394cd3d9acaab4e6ad934e"
flat-cache@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96"
dependencies:
circular-json "^0.3.1"
del "^2.0.2"
graceful-fs "^4.1.2"
write "^0.2.1"
font-awesome@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/font-awesome/-/font-awesome-4.7.0.tgz#8fa8cf0411a1a31afd07b06d2902bb9fc815a133"
@ -2198,6 +2373,17 @@ glob@^7.0.5, glob@~7.1.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.2:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.4"
once "^1.3.0"
path-is-absolute "^1.0.0"
globals-docs@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/globals-docs/-/globals-docs-2.2.0.tgz#28d9e2937cb9a6bce7e786510a5d4e337d61d3ef"
@ -2206,6 +2392,10 @@ globals@^9.0.0:
version "9.14.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034"
globals@^9.17.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
globby@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-4.1.0.tgz#080f54549ec1b82a6c60e631fc82e1211dbe95f8"
@ -2217,6 +2407,17 @@ globby@^4.0.0:
pify "^2.0.0"
pinkie-promise "^2.0.0"
globby@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d"
dependencies:
array-union "^1.0.1"
arrify "^1.0.0"
glob "^7.0.3"
object-assign "^4.0.1"
pify "^2.0.0"
pinkie-promise "^2.0.0"
globule@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f"
@ -2421,10 +2622,22 @@ iconv-lite@0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2"
iconv-lite@^0.4.17:
version "0.4.18"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2"
ieee754@^1.1.4:
version "1.1.8"
resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4"
ignore@^3.3.3:
version "3.3.3"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d"
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
in-publish@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
@ -2446,7 +2659,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.1:
inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
@ -2458,6 +2671,25 @@ ini@^1.3.3, ini@~1.3.0:
version "1.3.4"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e"
inquirer@^3.0.6:
version "3.1.1"
resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.1.1.tgz#87621c4fba4072f48a8dd71c9f9df6f100b2d534"
dependencies:
ansi-escapes "^2.0.0"
chalk "^1.0.0"
cli-cursor "^2.1.0"
cli-width "^2.0.0"
external-editor "^2.0.4"
figures "^2.0.0"
lodash "^4.3.0"
mute-stream "0.0.7"
run-async "^2.2.0"
rx-lite "^4.0.8"
rx-lite-aggregates "^4.0.8"
string-width "^2.0.0"
strip-ansi "^3.0.0"
through "^2.3.6"
interpret@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90"
@ -2590,6 +2822,10 @@ is-fullwidth-code-point@^1.0.0:
dependencies:
number-is-nan "^1.0.0"
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
is-generator-function@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.6.tgz#9e71653cd15fff341c79c4151460a131d31e9fc4"
@ -2619,6 +2855,15 @@ is-my-json-valid@^2.12.4:
jsonpointer "^4.0.0"
xtend "^4.0.0"
is-my-json-valid@^2.16.0:
version "2.16.0"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693"
dependencies:
generate-function "^2.0.0"
generate-object-property "^1.1.0"
jsonpointer "^4.0.0"
xtend "^4.0.0"
is-number-object@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.3.tgz#f265ab89a9f445034ef6aff15a8f00b00f551799"
@ -2629,6 +2874,22 @@ is-number@^2.0.2, is-number@^2.1.0:
dependencies:
kind-of "^3.0.2"
is-path-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d"
is-path-in-cwd@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc"
dependencies:
is-path-inside "^1.0.0"
is-path-inside@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f"
dependencies:
path-is-inside "^1.0.1"
is-posix-bracket@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
@ -2637,6 +2898,10 @@ is-primitive@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
is-promise@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
is-property@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
@ -2653,6 +2918,12 @@ is-relative@^0.2.1:
dependencies:
is-unc-path "^0.1.1"
is-resolvable@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62"
dependencies:
tryit "^1.0.1"
is-ssh@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.0.tgz#ebea1169a2614da392a63740366c3ce049d8dff6"
@ -2759,10 +3030,21 @@ js-yaml@3.x, js-yaml@^3.3.1:
argparse "^1.0.7"
esprima "^2.6.0"
js-yaml@^3.8.4:
version "3.8.4"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6"
dependencies:
argparse "^1.0.7"
esprima "^3.1.1"
jsbn@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd"
jschardet@^1.4.2:
version "1.4.2"
resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.4.2.tgz#2aa107f142af4121d145659d44f50830961e699a"
jsdom@^11.0.0:
version "11.0.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.0.0.tgz#1ee507cb2c0b16c875002476b1a8557d951353e5"
@ -2873,7 +3155,7 @@ lcid@^1.0.0:
dependencies:
invert-kv "^1.0.0"
levn@~0.3.0:
levn@^0.3.0, levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
dependencies:
@ -2978,6 +3260,10 @@ lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, l
version "4.17.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"
lodash@^4.17.4, lodash@^4.3.0:
version "4.17.4"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
lodash@~4.16.4:
version "4.16.6"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
@ -3134,13 +3420,13 @@ mime-db@~1.25.0:
version "1.25.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.25.0.tgz#c18dbd7c73a5dbf6f44a024dc0d165a1e7b1c392"
mime-types@^2.1.12, mime-types@~2.1.7:
mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.7:
version "2.1.13"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.13.tgz#e07aaa9c6c6b9a7ca3012c69003ad25a39e92a88"
dependencies:
mime-db "~1.25.0"
mime-types@~2.1.11, mime-types@~2.1.15:
mime-types@~2.1.15:
version "2.1.15"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed"
dependencies:
@ -3150,6 +3436,10 @@ mime@1.3.4, mime@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
mimic-fn@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18"
minimalistic-assert@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3"
@ -3164,6 +3454,12 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
dependencies:
brace-expansion "^1.0.0"
minimatch@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
minimist@0.0.8, minimist@~0.0.1:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
@ -3225,10 +3521,18 @@ ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
mute-stream@0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
nan@^2.1.0, nan@^2.3.0, nan@^2.3.2:
version "2.4.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232"
natural-compare@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
@ -3434,6 +3738,12 @@ onetime@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789"
onetime@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
dependencies:
mimic-fn "^1.0.0"
opn@4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95"
@ -3448,7 +3758,7 @@ optimist@^0.6.1:
minimist "~0.0.1"
wordwrap "~0.0.2"
optionator@^0.8.1:
optionator@^0.8.1, optionator@^0.8.2:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
dependencies:
@ -3486,7 +3796,7 @@ os-locale@^1.4.0:
dependencies:
lcid "^1.0.0"
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@ -3602,6 +3912,10 @@ path-is-absolute@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
path-is-inside@^1.0.1, path-is-inside@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
path-platform@~0.11.15:
version "0.11.15"
resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2"
@ -3654,6 +3968,10 @@ plur@^2.0.0:
dependencies:
irregular-plurals "^1.0.0"
pluralize@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-4.0.0.tgz#59b708c1c0190a2f692f1c7618c446b052fd1762"
pn@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/pn/-/pn-1.0.0.tgz#1cf5a30b0d806cd18f88fc41a6b5d4ad615b3ba9"
@ -3686,6 +4004,10 @@ process@^0.11.0:
version "0.11.10"
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
progress@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f"
protocols@^1.1.0, protocols@^1.4.0:
version "1.4.3"
resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.3.tgz#635b1c0785f0b389e8a012df1b1afffda9608b76"
@ -3834,7 +4156,7 @@ readable-stream@^2.0.2, readable-stream@~2.0.0:
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readable-stream@^2.2.6, readable-stream@^2.2.9:
readable-stream@^2.2.2, readable-stream@^2.2.6, readable-stream@^2.2.9:
version "2.2.9"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8"
dependencies:
@ -4038,10 +4360,21 @@ require-main-filename@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
require-uncached@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
dependencies:
caller-path "^0.1.0"
resolve-from "^1.0.0"
requires-port@1.0.x, requires-port@1.x.x:
version "1.0.0"
resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
resolve-from@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226"
resolve@1.1.7, resolve@1.1.x, resolve@^1.1.3, resolve@^1.1.6:
version "1.1.7"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
@ -4053,6 +4386,13 @@ restore-cursor@^1.0.1:
exit-hook "^1.0.0"
onetime "^1.0.0"
restore-cursor@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
dependencies:
onetime "^2.0.0"
signal-exit "^3.0.2"
right-align@^0.1.1:
version "0.1.3"
resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
@ -4063,7 +4403,7 @@ rimraf@2:
version "2.2.8"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
rimraf@~2.5.1, rimraf@~2.5.4:
rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4:
version "2.5.4"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04"
dependencies:
@ -4076,6 +4416,22 @@ ripemd160@^2.0.0, ripemd160@^2.0.1:
hash-base "^2.0.0"
inherits "^2.0.1"
run-async@^2.2.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
dependencies:
is-promise "^2.1.0"
rx-lite-aggregates@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be"
dependencies:
rx-lite "*"
rx-lite@*, rx-lite@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444"
safe-buffer@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
@ -4181,6 +4537,10 @@ signal-exit@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.1.tgz#5a4c884992b63a7acd9badb7894c3ee9cfccad81"
signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
sinon@^1.17.6:
version "1.17.6"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-1.17.6.tgz#a43116db59577c8296356afee13fafc2332e58e1"
@ -4194,6 +4554,10 @@ slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
sntp@1.x.x:
version "1.0.9"
resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198"
@ -4354,6 +4718,13 @@ string-width@^1.0.0, string-width@^1.0.1, string-width@^1.0.2:
is-fullwidth-code-point "^1.0.0"
strip-ansi "^3.0.0"
string-width@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.0.tgz#030664561fc146c9423ec7d978fe2457437fe6d0"
dependencies:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string_decoder@^0.10.25, string_decoder@~0.10.x:
version "0.10.31"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
@ -4381,6 +4752,12 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1:
dependencies:
ansi-regex "^2.0.0"
strip-ansi@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
dependencies:
ansi-regex "^3.0.0"
strip-bom-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/strip-bom-stream/-/strip-bom-stream-1.0.0.tgz#e7144398577d51a6bed0fa1994fa05f43fd988ee"
@ -4400,7 +4777,7 @@ strip-indent@^1.0.1:
dependencies:
get-stdin "^4.0.1"
strip-json-comments@^2.0.0:
strip-json-comments@^2.0.0, strip-json-comments@~2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
@ -4443,6 +4820,17 @@ symbol-tree@^3.2.1:
version "3.2.2"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
table@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/table/-/table-4.0.1.tgz#a8116c133fac2c61f4a420ab6cdf5c4d61f0e435"
dependencies:
ajv "^4.7.0"
ajv-keywords "^1.0.0"
chalk "^1.1.1"
lodash "^4.0.0"
slice-ansi "0.0.4"
string-width "^2.0.0"
tapable@^0.2.5, tapable@~0.2.5:
version "0.2.6"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d"
@ -4468,7 +4856,7 @@ tar@^2.0.0, tar@~2.2.1:
fstream "^1.0.2"
inherits "2"
text-table@^0.2.0:
text-table@^0.2.0, text-table@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
@ -4493,7 +4881,7 @@ through2@^2.0.0, through2@~2.0.0:
readable-stream "~2.0.0"
xtend "~4.0.0"
"through@>=2.2.7 <3":
"through@>=2.2.7 <3", through@^2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
@ -4518,6 +4906,12 @@ tmatch@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-2.0.1.tgz#0c56246f33f30da1b8d3d72895abaf16660f38cf"
tmp@^0.0.31:
version "0.0.31"
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
dependencies:
os-tmpdir "~1.0.1"
to-absolute-glob@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/to-absolute-glob/-/to-absolute-glob-0.1.1.tgz#1cdfa472a9ef50c239ee66999b662ca0eb39937f"
@ -4568,6 +4962,10 @@ trim@0.0.1, trim@^0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
tryit@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb"
ttf2eot@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ttf2eot/-/ttf2eot-2.0.0.tgz#8e6337a585abd1608a0c84958ab483ce69f6654b"
@ -4625,20 +5023,11 @@ type-is@~1.6.10, type-is@~1.6.15:
media-typer "0.3.0"
mime-types "~2.1.15"
typedarray@~0.0.5:
typedarray@^0.0.6, typedarray@~0.0.5:
version "0.0.6"
resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
uglify-js@^2.6:
version "2.7.5"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8"
dependencies:
async "~0.2.6"
source-map "~0.5.1"
uglify-to-browserify "~1.0.0"
yargs "~3.10.0"
uglify-js@^2.8.27:
uglify-js@^2.6, uglify-js@^2.8.27:
version "2.8.27"
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.27.tgz#47787f912b0f242e5b984343be8e35e95f694c9c"
dependencies:
@ -5032,6 +5421,12 @@ wrappy@1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
write@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757"
dependencies:
mkdirp "^0.5.1"
xml-name-validator@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"

Loading…
Cancel
Save