Browse Source

Merge branch 'dev'

pull/311/head
Artur Arseniev 9 years ago
parent
commit
3ca747dc95
  1. 42
      README.md
  2. 2
      dist/css/grapes.min.css
  3. 6
      dist/grapes.min.js
  4. 301
      index.html
  5. 11
      package.json
  6. 10
      src/asset_manager/config/config.js
  7. 19
      src/asset_manager/index.js
  8. 5
      src/asset_manager/view/AssetsView.js
  9. 68
      src/asset_manager/view/FileUploader.js
  10. 9
      src/block_manager/index.js
  11. 2
      src/block_manager/view/BlockView.js
  12. 9
      src/canvas/config/config.js
  13. 20
      src/canvas/index.js
  14. 11
      src/canvas/view/CanvasView.js
  15. 2
      src/code_manager/model/CssGenerator.js
  16. 15
      src/code_manager/model/JsGenerator.js
  17. 9
      src/commands/view/SelectComponent.js
  18. 16
      src/css_composer/index.js
  19. 4
      src/css_composer/model/CssRule.js
  20. 3
      src/dom_components/index.js
  21. 90
      src/dom_components/model/Component.js
  22. 4
      src/dom_components/model/ComponentSvg.js
  23. 13
      src/dom_components/model/Components.js
  24. 36
      src/dom_components/view/ComponentView.js
  25. 60
      src/domain_abstract/model/Styleable.js
  26. 5
      src/domain_abstract/ui/InputColor.js
  27. 10
      src/domain_abstract/ui/InputNumber.js
  28. 153
      src/editor/config/config.js
  29. 48
      src/editor/index.js
  30. 17
      src/editor/model/Editor.js
  31. 1
      src/editor/view/EditorView.js
  32. 27
      src/grapesjs/index.js
  33. 30
      src/navigator/view/ItemView.js
  34. 5
      src/navigator/view/ItemsView.js
  35. 2
      src/parser/model/ParserHtml.js
  36. 7
      src/rich_text_editor/config/config.js
  37. 10
      src/rich_text_editor/index.js
  38. 7
      src/selector_manager/view/ClassTagView.js
  39. 21
      src/style_manager/config/config.js
  40. 2
      src/style_manager/model/Layers.js
  41. 1
      src/style_manager/model/Property.js
  42. 4
      src/style_manager/model/PropertyFactory.js
  43. 15
      src/style_manager/view/LayerView.js
  44. 22
      src/style_manager/view/LayersView.js
  45. 2
      src/style_manager/view/PropertyCompositeView.js
  46. 33
      src/style_manager/view/PropertyFileView.js
  47. 3
      src/style_manager/view/PropertyIntegerView.js
  48. 23
      src/style_manager/view/PropertyStackView.js
  49. 205
      src/style_manager/view/PropertyView.js
  50. 6
      src/style_manager/view/SectorsView.js
  51. 117
      src/styles/scss/_gjs_assets.scss
  52. 454
      src/styles/scss/_gjs_style_manager.scss
  53. 487
      src/styles/scss/main.scss
  54. 307
      src/utils/Sorter.js
  55. 10
      test/specs/parser/model/ParserHtml.js
  56. 1
      test/specs/style_manager/model/Models.js
  57. 6
      test/specs/style_manager/view/PropertyColorView.js
  58. 6
      test/specs/style_manager/view/PropertyIntegerView.js
  59. 6
      test/specs/style_manager/view/PropertyRadioView.js
  60. 7
      test/specs/style_manager/view/PropertySelectView.js
  61. 25
      test/specs/style_manager/view/PropertyView.js
  62. 247
      yarn.lock

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

301
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(
@ -806,68 +832,11 @@
clearOnRender: 0,
storageManager:{
autoload: 1,
autoload: 0,
storeComponents: 1,
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,24 +1275,43 @@
}]);
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);
@ -1181,7 +1319,14 @@
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>

11
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.8.19",
"version": "0.9.12",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",
@ -26,11 +26,12 @@
"babel-loader": "^7.0.0",
"babel-preset-es2015": "^6.24.1",
"chai": "^3.5.0",
"cross-env": "^5.0.4",
"documentation": "^4.0.0-beta2",
"eslint": "^4.1.1",
"expect": "^1.20.2",
"istanbul": "^0.4.2",
"jsdom": "^11.0.0",
"jsdom": "^11.1.0",
"mocha": "^3.1.2",
"node-sass": "^3.4.2",
"sinon": "^1.17.6",
@ -58,11 +59,11 @@
},
"scripts": {
"lint": "eslint src",
"build": "WEBPACK_ENV=prod && npm run lint && npm run test && npm run v:patch && webpack && npm run build:css",
"build": "cross-env WEBPACK_ENV=prod && npm run lint && npm run test && npm run v:patch && webpack && npm run build:css",
"build:css": "node-sass src/styles/scss/main.scss dist/css/grapes.min.css --output-style compressed",
"v:patch": "npm version --no-git-tag-version patch",
"start": "WEBPACK_ENV=dev webpack-dev-server --progress --colors & npm run build:css -- -w",
"test": "NODE_PATH=./src mocha --compilers js:babel-core/register --require test/helper.js --timeout 10000 --recursive test/main.js",
"start": "cross-env WEBPACK_ENV=dev webpack-dev-server --progress --colors & npm run build:css -- -w",
"test": "cross-env NODE_PATH=./src mocha --compilers js:babel-core/register --require test/helper.js --timeout 10000 --recursive test/main.js",
"test:dev": "npm test -- -R min -w"
}
}

10
src/asset_manager/config/config.js

@ -21,4 +21,14 @@ module.exports = {
// // ...send somewhere
// }
uploadFile: '',
// Enable an upload dropzone on the entire editor (not document) when dragging
// files over it
dropzone: 1,
// Open the asset manager once files are been dropped via the dropzone
openAssetsOnDrop: 1,
// Any dropzone content to append inside dropzone element
dropzoneContent: '',
};

19
src/asset_manager/index.js

@ -179,13 +179,18 @@ module.exports = () => {
var name = this.storageKey;
if(!d && c.stm)
d = c.stm.load(name);
var assets = [];
var assets = d[name] || [];
try{
assets = JSON.parse(d[name]);
}catch(err){}
if (typeof assets == 'string') {
try {
assets = JSON.parse(d[name]);
} catch(err) {}
}
if (assets && assets.length) {
this.getAll().reset(assets);
}
this.getAll().reset(assets);
return assets;
},
@ -201,6 +206,10 @@ module.exports = () => {
return this.rendered;
},
postRender(editorView) {
fu.initDropzone(editorView);
},
//-------
/**

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 = {};

68
src/asset_manager/view/FileUploader.js

@ -13,15 +13,17 @@ module.exports = Backbone.View.extend({
events: {},
initialize(o) {
this.options = o || {};
this.config = o.config || {};
this.pfx = this.config.stylePrefix || '';
this.target = this.collection || {};
this.uploadId = this.pfx + 'uploadFile';
this.disabled = !this.config.upload;
initialize(opts = {}) {
this.options = opts;
const c = opts.config || {};
this.config = c;
this.pfx = c.stylePrefix || '';
this.ppfx = c.pStylePrefix || '';
this.target = this.collection || {};
this.uploadId = this.pfx + 'uploadFile';
this.disabled = !c.upload;
this.events['change #' + this.uploadId] = 'uploadFile';
let uploadFile = this.config.uploadFile;
let uploadFile = c.uploadFile;
if (uploadFile) {
this.uploadFile = uploadFile.bind(this);
@ -94,6 +96,56 @@ module.exports = Backbone.View.extend({
}
},
initDropzone(ev) {
let addedCls = 0;
const c = this.config;
const em = ev.model;
const edEl = ev.el;
const editor = em && em.get('Editor');
const frameEl = ev.model.get('Canvas').getBody();
const ppfx = this.ppfx;
const updatedCls = `${ppfx}dropzone-active`;
const dropzoneCls = `${ppfx}dropzone`;
const cleanEditorElCls = () => {
edEl.className = edEl.className.replace(updatedCls, '').trim();
addedCls = 0;
}
const onDragOver = () => {
if (!addedCls) {
edEl.className += ` ${updatedCls}`;
addedCls = 1;
}
return false;
};
const onDragLeave = () => {
cleanEditorElCls();
return false;
};
const onDrop = (e) => {
cleanEditorElCls();
e.preventDefault();
this.uploadFile(e);
if (c.openAssetsOnDrop && editor) {
const target = editor.getSelected();
editor.runCommand('open-assets', {target});
}
return false;
};
ev.$el.append(`<div class="${dropzoneCls}">${c.dropzoneContent}</div>`);
cleanEditorElCls();
if (c.dropzone && 'draggable' in edEl) {
[edEl, frameEl].forEach((item) => {
item.ondragover = onDragOver;
item.ondragleave = onDragLeave;
item.ondrop = onDrop;
});
}
},
render() {
this.$el.html( this.template({
title: this.config.uploadText,

9
src/block_manager/index.js

@ -135,6 +135,15 @@ module.exports = () => {
return view.render().el;
},
/**
* Remove block by id
* @param {string} id Block id
* @return {Block} Removed block
*/
remove(id) {
return blocks.remove(id);
},
};
};

2
src/block_manager/view/BlockView.js

@ -10,7 +10,7 @@ module.exports = Backbone.View.extend({
_.bindAll(this, 'onDrop');
this.config = config || {};
this.ppfx = this.config.pStylePrefix || '';
this.listenTo(this.model, 'destroy', this.remove);
this.listenTo(this.model, 'destroy remove', this.remove);
this.doc = $(document);
},

9
src/canvas/config/config.js

@ -24,4 +24,13 @@ module.exports = {
*/
styles: [],
/**
* Add custom badge naming strategy
* @example
* customBadgeLabel: function(ComponentModel) {
* return ComponentModel.getName();
* }
*/
customBadgeLabel: '',
};

20
src/canvas/index.js

@ -54,6 +54,14 @@ module.exports = () => {
return this;
},
/**
* Return config object
* @return {Object}
*/
getConfig() {
return c;
},
/**
* Add wrapper
* @param {Object} wrp Wrapper
@ -203,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

11
src/canvas/view/CanvasView.js

@ -244,20 +244,17 @@ 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('');
// In editor, I make use of setTimeout as during the append process of elements
// those will not be available immediatly, therefore 'item' variable
view.scriptContainer.append(`<script>
setTimeout(function() {
var item = document.getElementById('${id}');
(${scrStr}.bind(item))()
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]))();
}`;
}

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.getCurrentName();
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;

16
src/css_composer/index.js

@ -221,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];
@ -242,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

3
src/dom_components/index.js

@ -216,7 +216,8 @@ module.exports = () => {
}catch(err){}
}else if(d.html)
obj = d.html;
if (obj) {
if (obj && obj.length) {
this.clear();
this.getComponents().reset();
this.getComponents().add(obj);

90
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: {},
@ -245,24 +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;
},
getCurrentName() {
return this.get('custom-name') || this.getName();
/**
* Get the icon string
* @return {string}
*/
getIcon() {
let icon = this.get('icon');
return icon ? icon + ' ' : '';
},
/**
@ -274,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 => {
@ -293,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');
@ -329,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;
@ -337,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
@ -347,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;
}

4
src/dom_components/model/ComponentSvg.js

@ -4,7 +4,9 @@ module.exports = Component.extend({
getName() {
let name = this.get('tagName');
return name.charAt(0).toUpperCase() + name.slice(1);
let customName = this.get('custom-name');
name = name.charAt(0).toUpperCase() + name.slice(1);
return customName || name;
},
}, {

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

36
src/dom_components/view/ComponentView.js

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

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

5
src/domain_abstract/ui/InputColor.js

@ -47,6 +47,11 @@ module.exports = Input.extend({
var colorEl = $('<div>', {class: this.colorCls});
var cpStyle = colorEl.get(0).style;
var elToAppend = this.target && this.target.config ? this.target.config.el : '';
if (typeof colorEl.spectrum == 'undefined') {
throw 'Spectrum missing, probably you load jQuery twice';
}
colorEl.spectrum({
appendTo: elToAppend || 'body',
maxSelectionSize: 8,

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

153
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-',
@ -63,6 +62,12 @@ module.exports = {
// 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,
@ -163,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: {},
};

48
src/editor/index.js

@ -10,6 +10,7 @@
* * [getStyle](#getstyle)
* * [setStyle](#setstyle)
* * [getSelected](#getselected)
* * [getSelectedToStyle](#getselectedtostyle)
* * [setDevice](#setdevice)
* * [getDevice](#getdevice)
* * [runCommand](#runcommand)
@ -36,6 +37,8 @@
* component:update:{propertyName} - Listen any property change
* component:styleUpdate - Triggered when the style of the component is updated
* component:styleUpdate:{propertyName} - Listen for a specific style property change
* 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
@ -82,10 +85,9 @@ module.exports = config => {
if (!(name in c))
c[name] = defaults[name];
}
c.pStylePrefix = c.stylePrefix;
c.pStylePrefix = c.stylePrefix;
var em = new EditorModel(c);
var editorView = new EditorView({
model: em,
config: c,
@ -260,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>');
@ -270,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);
},
/**
@ -301,12 +307,28 @@ module.exports = config => {
/**
* Returns selected component, if there is one
* @return {grapesjs.Component}
* @return {Model}
*/
getSelected() {
return em.getSelected();
},
/**
* Get a stylable entity from the selected component.
* If you select a component without classes the entity is the Component
* itself and all changes will go inside its 'style' attribute. 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
@ -379,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);
},
/**
@ -493,7 +516,16 @@ module.exports = config => {
* @return {HTMLElement}
*/
render() {
return editorView.render().el;
// Do post render stuff after the iframe is loaded otherwise it'll
// be empty during tests
em.on('loaded', () => {
em.get('modules').forEach((module) => {
module.postRender && module.postRender(editorView);
});
});
editorView.render();
return editorView.el;
},
};

17
src/editor/model/Editor.js

@ -32,6 +32,7 @@ module.exports = Backbone.Model.extend({
previousModel: null,
changesCount: 0,
storables: [],
modules: [],
toLoad: [],
opened: {},
device: '',
@ -40,6 +41,7 @@ module.exports = Backbone.Model.extend({
initialize(c) {
this.config = c;
this.set('Config', c);
this.set('modules', []);
if(c.el && c.fromElement)
this.config.components = c.el.innerHTML;
@ -117,6 +119,7 @@ module.exports = Backbone.Model.extend({
if(M.onLoad)
this.get('toLoad').push(M);
this.get('modules').push(M);
return this;
},
@ -161,6 +164,12 @@ module.exports = Backbone.Model.extend({
* @private
* */
componentsUpdated(model, val, opt) {
var temp = opt ? opt.temporary : 0;
if (temp) {
//component has been added temporarily - do not update storage or record changes
return;
}
timedInterval && clearInterval(timedInterval);
timedInterval = setTimeout(() => {
var count = this.get('changesCount') + 1;
@ -276,12 +285,12 @@ module.exports = Backbone.Model.extend({
this.stopListening(classes, 'add remove', this.componentsUpdated);
this.listenTo(classes, 'add remove', this.componentsUpdated);
var evn = 'change:style change:content';
var evn = 'change:style change:content change:attributes';
this.stopListening(model, evn, this.componentsUpdated);
this.listenTo(model, evn, this.componentsUpdated);
if(!avSt)
this.componentsUpdated();
this.componentsUpdated(model, val, opt);
},
/**
@ -310,7 +319,7 @@ module.exports = Backbone.Model.extend({
var avSt = opt ? opt.avoidStore : 0;
if(!avSt)
this.componentsUpdated();
this.componentsUpdated(model, val, opt);
},
/**
@ -428,9 +437,9 @@ module.exports = Backbone.Model.extend({
sm.store(store, () => {
clb && clb();
this.set('changesCount', 0);
this.trigger('storage:store', store);
});
this.set('changesCount', 0);
return store;
},

1
src/editor/view/EditorView.js

@ -3,6 +3,7 @@ var Backbone = require('backbone');
module.exports = Backbone.View.extend({
initialize() {
this.model.view = this;
this.pn = this.model.get('Panels');
this.conf = this.model.config;
this.className = this.conf.stylePrefix + 'editor';

27
src/grapesjs/index.js

@ -1,5 +1,4 @@
module.exports = (config => {
var c = config || {},
defaults = require('./config/config'),
Editor = require('editor'),
@ -36,6 +35,11 @@
var c = config || {};
var els = c.container;
// Make a missing $ more verbose
if (typeof $ == 'undefined') {
throw 'jQuery not found';
}
// Set default options
for (var name in defaults) {
if (!(name in c))
@ -48,17 +52,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);
}
},
/**

2
src/parser/model/ParserHtml.js

@ -25,7 +25,7 @@ module.exports = config => {
if(!decl)
continue;
var prop = decl.split(':');
result[prop[0].trim()] = prop[1].trim();
result[prop[0].trim()] = prop.slice(1).join(':').trim();
}
return result;
},

7
src/rich_text_editor/config/config.js

@ -1,7 +1,12 @@
module.exports = {
stylePrefix : 'rte-',
toolbarId : 'toolbar',
containerId : 'wrapper',
// If true, moves the toolbar below the element when the top canvas
// edge is reached
adjustToolbar: 1,
// Default toolbar commands
commands : [{
command: 'bold',
title: 'Bold',

10
src/rich_text_editor/index.js

@ -113,7 +113,7 @@ module.exports = () => {
},
/**
* Triggered when the offset of the editro is changed
* Triggered when the offset of the editor is changed
* @private
*/
udpatePosition() {
@ -122,6 +122,14 @@ module.exports = () => {
var pos = canvas.getTargetToElementDim(toolbar.el, this.lastEl, {
event: 'rteToolbarPosUpdate',
});
if (c.adjustToolbar) {
// Move the toolbar down when the top canvas edge is reached
if (pos.top <= pos.canvasTop) {
pos.top = pos.elementTop + pos.elementHeight;
}
}
var toolbarStyle = toolbar.el.style;
toolbarStyle.top = pos.top + u;
toolbarStyle.left = pos.left + u;

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

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: [],

4
src/style_manager/model/PropertyFactory.js

@ -95,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(/ +$/,'');
},
/**

33
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() {
@ -124,15 +120,20 @@ module.exports = PropertyView.extend({
* */
openAssetManager(e) {
var that = this;
if(this.modal && this.am){
var em = this.em;
var editor = em ? em.get('Editor') : '';
if(editor) {
this.modal.setTitle('Select image');
this.modal.setContent(this.am.render());
this.am.setTarget(null);
this.modal.open();
this.am.onSelect(model => {
that.modal.close();
that.spreadUrl(model.get('src'));
that.valueChanged(e);
editor.runCommand('open-assets', {
target: this.model,
onSelect(target) {
that.modal.close();
that.spreadUrl(target.get('src'));
that.valueChanged(e);
}
});
}
},

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

23
src/style_manager/view/PropertyStackView.js

@ -7,7 +7,7 @@ module.exports = PropertyCompositeView.extend({
template: _.template(`
<div class="<%= pfx %>field <%= pfx %>stack">
<button id='<%= pfx %>add'>+</button>
<button type="button" id='<%= pfx %>add'>+</button>
<span id='<%= pfx %>input-holder'></span>
</div>
<div style="clear:both"></div>`),
@ -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:
@ -321,6 +319,7 @@ module.exports = PropertyCompositeView.extend({
this.renderField();
this.renderLayers();
this.$el.attr('class', this.className);
this.updateStatus();
return this;
},

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}color-hl`;
const computedCls = `${ppfx}color-warn`;
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;
},

6
src/style_manager/view/SectorsView.js

@ -48,8 +48,14 @@ module.exports = Backbone.View.extend({
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 = em.get('CssComposer');
var valid = _.filter(classes.models, item => item.get('active'));

117
src/styles/scss/_gjs_assets.scss

@ -0,0 +1,117 @@
.#{$app-prefix}dropzone {
display: none;
opacity: 0;
position: absolute;
top: 0;
left: 0;
z-index: 5;
width: 100%;
height: 100%;
transition: opacity 0.25s;
pointer-events: none;
}
.#{$app-prefix}dropzone-active {
.#{$app-prefix}dropzone {
display: block;
opacity: 1;
}
}
.#{$am-prefix}assets {
height: 290px;
overflow: auto;
clear: both;
}
.#{$am-prefix}assets-header {
padding: 5px;
}
.#{$am-prefix}add-asset {
.#{$am-prefix}add-field {
width: 70%;
float: left;
}
button{
width: 25%;
float: right;
}
}
.#{$am-prefix}add-field input {
padding: 6px;
}
.#{$am-prefix}assets-cont {
background-color: $mainDklColor;
border-radius: 3px;
box-sizing: border-box;
padding: 10px;
width: 45%;
float:right;
height: 325px;
overflow: hidden;
##{$am-prefix}preview-cont{
position: relative;
height: 70px; width: 30%;
background-color: $mainColor;
border-radius: 2px;
float: left;
overflow: hidden;
}
##{$am-prefix}preview{
position: absolute;
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
height: 100%;
width: 100%;
z-index: 1;
}
##{$am-prefix}preview-bg{
position: absolute;
height: 100%;
width: 100%;
@include opacity(0.5);
z-index: 0;
}
.#{$am-prefix}highlight {
background-color: $mainLhColor;
}
.#{$am-prefix}asset {
border-bottom: 1px solid darken($mainDkColor, 3%);
padding: 5px;
cursor:pointer;
position: relative;
&:hover ##{$am-prefix}close { display: block;}
}
##{$am-prefix}close {
@extend .btn-cl;
position: absolute;
right: 5px;
top: 0;
display: none;
}
##{$am-prefix}meta {
width: 70%;
float: left;
font-size: 12px;
padding: 5px 0 0 5px;
box-sizing: border-box;
> div { margin-bottom: 5px;}
##{$am-prefix}dimensions {
font-size: 10px;
@include opacity(0.5);
}
}
}

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

487
src/styles/scss/main.scss

@ -88,7 +88,37 @@ $fontV: 20;//random(1000)
transform: $v;
}
//.#{$app-prefix}fonts {}
/* Color Helpers */
$colorHighlight: #71b7f1;
$colorWarn: #ffca6f;
.#{$app-prefix}bg {
&-main {
background-color: $mainColor;
}
}
.#{$app-prefix}color {
&-main {
color: $fontColor;
fill: $fontColor;
}
&-active {
color: $fontColorActive;
fill: $fontColorActive;
}
&-warn {
color: $colorWarn;
fill: $colorWarn;
}
&-hl {
color: $colorHighlight;
fill: $colorHighlight;
}
}
.#{$app-prefix}fonts::before {
display: block;
@ -145,20 +175,6 @@ $fontV: 20;//random(1000)
pointer-events: none;
}
.#{$app-prefix}bg-main{
background-color: $mainColor;
}
.#{$app-prefix}color-main {
color: $fontColor;
fill: $fontColor;
}
.#{$app-prefix}color-active {
color: $fontColorActive;
fill: $fontColorActive;
}
.#{$app-prefix}bdrag {
pointer-events: none !important;
position: absolute !important;
@ -530,6 +546,10 @@ ol.example li.placeholder:before {position: absolute;}
/************* Navigator *************/
.#{$nv-prefix}selected-parent {
border: 1px solid $colorYell;
}
.#{$nv-prefix}opac50{
@include opacity(0.50);
}
@ -736,345 +756,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;
}
@import "gjs_style_manager";
&.#{$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;}
}
/*------------------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";
@ -1238,103 +922,8 @@ $paddElClm: 5px 6px;
}
/********* Assets Manager **********/
.#{$am-prefix}assets {
height: 290px;
overflow: auto;
clear: both;
}
.#{$am-prefix}assets-header {
padding: 5px;
}
.#{$am-prefix}add-asset {
.#{$am-prefix}add-field {
width: 70%;
float: left;
}
button{
width: 25%;
float: right;
}
}
.#{$am-prefix}add-field input {
padding: 6px;
}
.#{$am-prefix}assets-cont {
background-color: $mainDklColor;
border-radius: 3px;
box-sizing: border-box;
padding: 10px;
width: 45%;
float:right;
height: 325px;
overflow: hidden;
##{$am-prefix}preview-cont{
position: relative;
height: 70px; width: 30%;
background-color: $mainColor;
border-radius: 2px;
float: left;
overflow: hidden;
}
##{$am-prefix}preview{
position: absolute;
background-position: center center;
background-size: cover;
background-repeat: no-repeat;
height: 100%;
width: 100%;
z-index: 1;
}
##{$am-prefix}preview-bg{
position: absolute;
height: 100%;
width: 100%;
@include opacity(0.5);
z-index: 0;
}
.#{$am-prefix}highlight {
background-color: $mainLhColor;
}
.#{$am-prefix}asset {
border-bottom: 1px solid darken($mainDkColor, 3%);
padding: 5px;
cursor:pointer;
position: relative;
&:hover ##{$am-prefix}close { display: block;}
}
##{$am-prefix}close {
@extend .btn-cl;
position: absolute;
right: 5px;
top: 0;
display: none;
}
##{$am-prefix}meta {
width: 70%;
float: left;
font-size: 12px;
padding: 5px 0 0 5px;
box-sizing: border-box;
> div { margin-bottom: 5px;}
##{$am-prefix}dimensions {
font-size: 10px;
@include opacity(0.5);
}
}
}
@import "gjs_assets";
/********* File uploader **********/

307
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;
@ -134,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;
@ -218,24 +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(trg && !this.matches(trg, this.itemSel + ',' + this.containerSel))
this.eV = this.closest(trg, this.itemSel);
if(src && !this.matches(src, this.itemSel + ',' + this.containerSel))
src = this.closest(src, 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(trg) {
var className = trg.getAttribute('class');
trg.setAttribute('class', `${className} ${this.freezeClass}`);
if (src) {
var srcModel = this.getSourceModel();
srcModel && srcModel.set && srcModel.set('status', 'freezed');
this.$document.on('mouseup', this.endMove);
}
@ -258,16 +265,45 @@ module.exports = Backbone.View.extend({
* Get the model from HTMLElement target
* @return {Model|null}
*/
getModelFromTarget(el) {
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, temporary: 1});
dropModel = comps.remove(tempModel, {temporary: 1});
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', '');
@ -307,7 +343,7 @@ module.exports = Backbone.View.extend({
var dims = this.dimsFromTarget(e.target, rX, rY);
let targetModel = this.getModelFromTarget(this.target);
let targetModel = this.getTargetModel(this.target);
this.selectTargetModel(targetModel);
this.lastDims = dims;
@ -393,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
@ -403,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);
@ -439,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;
},
@ -460,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;
@ -482,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;
@ -507,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;
},
@ -655,15 +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');
let trg = this.eV;
let src = this.eV;
if (trg) {
var className = (trg.getAttribute('class')+'').replace(clsReg, '');
trg.setAttribute('class', className);
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, trg, this.lastPos);
created = this.move(this.target, src, this.lastPos);
if(this.plh)
this.plh.style.display = 'none';
@ -689,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;
},

10
test/specs/parser/model/ParserHtml.js

@ -57,6 +57,16 @@ module.exports = {
expect(obj.parseStyle(str)).toEqual(result)
});
it('Parse style string with values containing colon to object', () => {
var str = 'background-image:url("https://some-website.ex"); test:value;';
var result = {
'background-image': 'url("https://some-website.ex")',
'test': 'value',
};
expect(obj.parseStyle(str)).toEqual(result)
});
it('Parse class string to array', () => {
var str = 'test1 test2 test3 test-4';
var result = ['test1', 'test2', 'test3', 'test-4'];

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

@ -522,6 +522,7 @@ module.exports = {
var res = {
type: 'stack',
preview: true,
defaults: "none",
properties : [{
property: 'text-shadow-h',
type: 'integer',

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

@ -13,6 +13,7 @@ module.exports = {
var target;
var model;
var view;
var propTarget;
var propName = 'testprop';
var propValue = '#fff';
var defValue = 'test2value';
@ -30,8 +31,11 @@ module.exports = {
type: 'color',
property: propName
});
propTarget = Object.assign({}, Backbone.Events);
propTarget.model = component;
view = new PropertyColorView({
model
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);

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

@ -13,6 +13,7 @@ module.exports = {
var target;
var model;
var view;
var propTarget;
var propName = 'testprop';
var intValue = '55';
var unitValue = 'px';
@ -36,8 +37,11 @@ module.exports = {
units,
property: propName
});
propTarget = Object.assign({}, Backbone.Events);
propTarget.model = component;
view = new PropertyIntegerView({
model
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);

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

@ -13,6 +13,7 @@ module.exports = {
var target;
var model;
var view;
var propTarget;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
@ -34,8 +35,11 @@ module.exports = {
list: options,
property: propName
});
propTarget = Object.assign({}, Backbone.Events);
propTarget.model = component;
view = new PropertyRadioView({
model
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);

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

@ -13,6 +13,8 @@ module.exports = {
var target;
var model;
var view;
var propTarget;
var options;
var propName = 'testprop';
var propValue = 'test1value';
var defValue = 'test2value';
@ -27,6 +29,7 @@ module.exports = {
});
beforeEach(() => {
propTarget = Object.assign({}, Backbone.Events);
target = new Component();
component = new Component();
model = new Property({
@ -34,8 +37,10 @@ module.exports = {
list: options,
property: propName
});
propTarget.model = component;
view = new PropertySelectView({
model
model,
propTarget
});
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);

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

@ -13,6 +13,8 @@ module.exports = {
var target;
var model;
var view;
var propTarget;
var options;
var propName = 'testprop';
var propValue = 'testvalue';
var defValue = 'testDefault';
@ -23,12 +25,16 @@ module.exports = {
});
beforeEach(() => {
propTarget = Object.assign({}, Backbone.Events);
target = new Component();
component = new Component();
model = new Property({property: propName});
view = new PropertyView({
model
});
propTarget.model = component;
options = {
model,
propTarget
};
view = new PropertyView(options);
$fixture.empty().appendTo($fixtures);
$fixture.html(view.render().el);
});
@ -82,34 +88,30 @@ module.exports = {
});
it('Update target on value change', () => {
view.selectedComponent = component;
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var compStyle = view.getTargetModel().get('style');
var assertStyle = {};
assertStyle[propName] = propValue;
expect(compStyle).toEqual(assertStyle);
});
it('Update target on value change with functionName', () => {
view.selectedComponent = component;
view.model.set('functionName', 'testfunc');
view.model.set('value', propValue);
var compStyle = view.selectedComponent.get('style');
var compStyle = view.getTargetModel().get('style');
var assertStyle = {};
assertStyle[propName] = 'testfunc(' + propValue + ')';
expect(compStyle).toEqual(assertStyle);
});
it('Clean target from the property if its value is empty', () => {
view.selectedComponent = component;
view.model.set('value', propValue);
view.model.set('value', '');
var compStyle = view.selectedComponent.get('style');
var compStyle = view.getTargetModel().get('style');
expect(compStyle).toEqual({});
});
it('Check stylable element', () => {
view.selectedComponent = component;
expect(view.isTargetStylable()).toEqual(true);
component.set('stylable', false);
expect(view.isTargetStylable()).toEqual(false);
@ -122,12 +124,10 @@ module.exports = {
});
it('Target style is empty without values', () => {
view.selectedComponent = component;
expect(view.getComponentValue()).toNotExist();
});
it('Target style is correct', () => {
view.selectedComponent = component;
var style = {};
style[propName] = propValue;
component.set('style', style);
@ -135,7 +135,6 @@ module.exports = {
});
it('Target style is empty with an other style', () => {
view.selectedComponent = component;
var style = {};
style[propName + '2'] = propValue;
component.set('style', style);

247
yarn.lock

@ -127,7 +127,7 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0"
readable-stream "^2.0.0 || ^1.1.13"
argparse@^1.0.6, argparse@^1.0.7:
argparse@^1.0.7:
version "1.0.9"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86"
dependencies:
@ -994,10 +994,6 @@ binary-extensions@^1.0.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.7.0.tgz#6c1610db163abfb34edfe42fa423343a1e01185d"
bindings@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.2.1.tgz#14ad6113812d2d37d72e67b4cacb4bb726505f11"
block-stream@*:
version "0.0.9"
resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
@ -1132,12 +1128,6 @@ buffer@^4.3.0:
ieee754 "^1.1.4"
isarray "^1.0.0"
bufferstreams@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/bufferstreams/-/bufferstreams-1.1.1.tgz#0161373060ac5988eff99058731114f6e195d51e"
dependencies:
readable-stream "^2.0.2"
builtin-modules@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f"
@ -1362,15 +1352,7 @@ concat-map@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
concat-stream@^1.0.0, concat-stream@^1.5.0, concat-stream@~1.5.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
dependencies:
inherits "~2.0.1"
readable-stream "~2.0.0"
typedarray "~0.0.5"
concat-stream@^1.6.0:
concat-stream@^1.0.0, concat-stream@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7"
dependencies:
@ -1378,6 +1360,14 @@ concat-stream@^1.6.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
concat-stream@^1.5.0, concat-stream@~1.5.0:
version "1.5.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266"
dependencies:
inherits "~2.0.1"
readable-stream "~2.0.0"
typedarray "~0.0.5"
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"
@ -1455,6 +1445,13 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
safe-buffer "^5.0.1"
sha.js "^2.4.8"
cross-env@^5.0.4:
version "5.0.4"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-5.0.4.tgz#af93f5ce541ca9de49250b988104112e31c22563"
dependencies:
cross-spawn "^5.1.0"
is-windows "^1.0.0"
cross-spawn@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
@ -1462,6 +1459,14 @@ cross-spawn@^3.0.0:
lru-cache "^4.0.1"
which "^1.2.9"
cross-spawn@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
dependencies:
lru-cache "^4.0.1"
shebang-command "^1.2.0"
which "^1.2.9"
cryptiles@2.x.x:
version "2.0.5"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
@ -1493,10 +1498,6 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
dependencies:
cssom "0.3.x"
cubic2quad@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/cubic2quad/-/cubic2quad-1.1.0.tgz#78abec71b1b0244fdca863910ced8e07446a90e7"
currently-unhandled@^0.4.1:
version "0.4.1"
resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
@ -1535,13 +1536,13 @@ debug@2.2.0, debug@~2.2.0:
dependencies:
ms "0.7.1"
debug@2.6.7, debug@^2.0.0, debug@^2.1.1, debug@^2.2.0:
debug@2.6.7, debug@^2.1.1:
version "2.6.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e"
dependencies:
ms "2.0.0"
debug@^2.6.8:
debug@^2.0.0, debug@^2.2.0, debug@^2.6.8:
version "2.6.8"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
dependencies:
@ -2331,7 +2332,7 @@ glob-stream@^5.3.2:
to-absolute-glob "^0.1.1"
unique-stream "^2.0.2"
glob@7.0.5, glob@^7.0.0, glob@^7.0.3:
glob@7.0.5:
version "7.0.5"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95"
dependencies:
@ -2362,18 +2363,7 @@ glob@^6.0.1:
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.0.5, glob@~7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8"
dependencies:
fs.realpath "^1.0.0"
inflight "^1.0.4"
inherits "2"
minimatch "^3.0.2"
once "^1.3.0"
path-is-absolute "^1.0.0"
glob@^7.1.2:
glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.2, glob@~7.1.1:
version "7.1.2"
resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15"
dependencies:
@ -2388,11 +2378,7 @@ globals-docs@2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/globals-docs/-/globals-docs-2.2.0.tgz#28d9e2937cb9a6bce7e786510a5d4e337d61d3ef"
globals@^9.0.0:
version "9.14.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034"
globals@^9.17.0:
globals@^9.0.0, globals@^9.17.0:
version "9.18.0"
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
@ -2846,16 +2832,7 @@ is-hexadecimal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/is-hexadecimal/-/is-hexadecimal-1.0.0.tgz#5c459771d2af9a2e3952781fd54fcb1bcfe4113c"
is-my-json-valid@^2.12.4:
version "2.15.0"
resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b"
dependencies:
generate-function "^2.0.0"
generate-object-property "^1.1.0"
jsonpointer "^4.0.0"
xtend "^4.0.0"
is-my-json-valid@^2.16.0:
is-my-json-valid@^2.12.4, 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:
@ -2964,6 +2941,10 @@ is-windows@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c"
is-windows@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.1.tgz#310db70f742d259a16a369202b51af84233310d9"
isarray@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf"
@ -3023,20 +3004,20 @@ js-tokens@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7"
js-yaml@3.x, js-yaml@^3.3.1:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
dependencies:
argparse "^1.0.7"
esprima "^2.6.0"
js-yaml@^3.8.4:
js-yaml@3.x, 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"
js-yaml@^3.3.1:
version "3.7.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80"
dependencies:
argparse "^1.0.7"
esprima "^2.6.0"
jsbn@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd"
@ -3045,9 +3026,9 @@ 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"
jsdom@^11.1.0:
version "11.1.0"
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.1.0.tgz#6c48d7a48ffc5c300283c312904d15da8360509b"
dependencies:
abab "^1.0.3"
acorn "^4.0.4"
@ -3058,7 +3039,7 @@ jsdom@^11.0.0:
cssstyle ">= 0.2.37 < 0.3.0"
escodegen "^1.6.1"
html-encoding-sniffer "^1.0.1"
nwmatcher ">= 1.3.9 < 2.0.0"
nwmatcher "^1.4.1"
parse5 "^3.0.2"
pn "^1.0.0"
request "^2.79.0"
@ -3068,7 +3049,7 @@ jsdom@^11.0.0:
tough-cookie "^2.3.2"
webidl-conversions "^4.0.0"
whatwg-encoding "^1.0.1"
whatwg-url "^4.3.0"
whatwg-url "^6.1.0"
xml-name-validator "^2.0.1"
jsesc@^1.3.0:
@ -3256,14 +3237,18 @@ lodash.keys@^3.0.0:
lodash.isarguments "^3.0.0"
lodash.isarray "^3.0.0"
lodash@^4.0.0, lodash@^4.11.1, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.2.0, lodash@^4.6.1:
version "4.17.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"
lodash.sortby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
lodash@^4.17.4, lodash@^4.3.0:
lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.17.2, 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.11.1, lodash@^4.2.0:
version "4.17.2"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.2.tgz#34a3055babe04ce42467b607d700072c7ff6bf42"
lodash@~4.16.4:
version "4.16.6"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777"
@ -3383,10 +3368,6 @@ methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
microbuffer@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/microbuffer/-/microbuffer-1.0.0.tgz#8b3832ed40c87d51f47bb234913a698a756d19d2"
micromatch@^2.1.5, micromatch@^2.1.6, micromatch@^2.3.11, micromatch@^2.3.7:
version "2.3.11"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565"
@ -3448,18 +3429,18 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@~3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
dependencies:
brace-expansion "^1.0.0"
minimatch@^3.0.4:
"minimatch@2 || 3", minimatch@^3.0.4, minimatch@~3.0.2:
version "3.0.4"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
dependencies:
brace-expansion "^1.1.7"
minimatch@^3.0.0, minimatch@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774"
dependencies:
brace-expansion "^1.0.0"
minimist@0.0.8, minimist@~0.0.1:
version "0.0.8"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
@ -3525,7 +3506,7 @@ 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:
nan@^2.3.0, nan@^2.3.2:
version "2.4.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.4.0.tgz#fb3c59d45fe4effe215f0b890f8adf6eb32d2232"
@ -3537,7 +3518,7 @@ negotiator@0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9"
node-gyp@^3.0.3, node-gyp@^3.3.1:
node-gyp@^3.3.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.4.0.tgz#dda558393b3ecbbe24c9e6b8703c71194c63fa36"
dependencies:
@ -3672,9 +3653,9 @@ number-is-nan@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
"nwmatcher@>= 1.3.9 < 2.0.0":
version "1.4.0"
resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.0.tgz#b4389362170e7ef9798c3c7716d80ebc0106fccf"
nwmatcher@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.1.tgz#7ae9b07b0ea804db7e25f05cb5fe4097d4e4949f"
oauth-sign@~0.8.1:
version "0.8.2"
@ -3807,10 +3788,6 @@ osenv@0:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
pako@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.3.tgz#5f515b0c6722e1982920ae8005eacb0b7ca73ccf"
pako@~0.2.0:
version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
@ -4133,16 +4110,16 @@ read-pkg@^1.0.0:
isarray "0.0.1"
string_decoder "~0.10.x"
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@~2.1.0, readable-stream@~2.1.4:
version "2.1.5"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0"
readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.5, 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:
buffer-shims "^1.0.0"
buffer-shims "~1.0.0"
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~0.10.x"
string_decoder "~1.0.0"
util-deprecate "~1.0.1"
readable-stream@^2.0.2, readable-stream@~2.0.0:
@ -4156,16 +4133,16 @@ readable-stream@^2.0.2, readable-stream@~2.0.0:
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
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"
readable-stream@^2.0.4, readable-stream@~2.1.0, readable-stream@~2.1.4:
version "2.1.5"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0"
dependencies:
buffer-shims "~1.0.0"
buffer-shims "^1.0.0"
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "~1.0.0"
process-nextick-args "~1.0.6"
string_decoder "~1.0.0"
string_decoder "~0.10.x"
util-deprecate "~1.0.1"
readdirp@^2.0.0:
@ -4529,6 +4506,16 @@ sha.js@^2.4.0, sha.js@^2.4.8:
dependencies:
inherits "^2.0.1"
shebang-command@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
dependencies:
shebang-regex "^1.0.0"
shebang-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
shellsubstitute@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/shellsubstitute/-/shellsubstitute-1.2.0.tgz#e4f702a50c518b0f6fe98451890d705af29b6b70"
@ -4801,21 +4788,6 @@ supports-color@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
svg2ttf@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/svg2ttf/-/svg2ttf-4.0.2.tgz#5e37123c7e9bf3dc6c7f26b141392a19fcec7a57"
dependencies:
argparse "^1.0.6"
cubic2quad "^1.0.0"
lodash "^4.6.1"
microbuffer "^1.0.0"
svgpath "^2.1.5"
xmldom "~0.1.22"
svgpath@^2.1.5:
version "2.2.0"
resolved "https://registry.yarnpkg.com/svgpath/-/svgpath-2.2.0.tgz#6bbe4c4cad9170e3f338cc746cc2e0c0fc7a5064"
symbol-tree@^3.2.1:
version "3.2.2"
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
@ -4966,30 +4938,6 @@ 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"
dependencies:
argparse "^1.0.6"
microbuffer "^1.0.0"
ttf2woff2@^2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/ttf2woff2/-/ttf2woff2-2.0.3.tgz#5e020afe6e643287f3ad7687abed20fe654eb329"
dependencies:
bindings "^1.2.1"
bufferstreams "^1.1.0"
nan "^2.1.0"
node-gyp "^3.0.3"
ttf2woff@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/ttf2woff/-/ttf2woff-2.0.1.tgz#871832240024b09db9570904c7c1928b8057c969"
dependencies:
argparse "^1.0.6"
microbuffer "^1.0.0"
pako "^1.0.0"
tty-browserify@0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@ -5278,11 +5226,7 @@ wbuf@^1.1.0, wbuf@^1.7.2:
dependencies:
minimalistic-assert "^1.0.0"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
webidl-conversions@^4.0.0:
webidl-conversions@^4.0.0, webidl-conversions@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.1.tgz#8015a17ab83e7e1b311638486ace81da6ce206a0"
@ -5366,12 +5310,13 @@ whatwg-encoding@^1.0.1:
dependencies:
iconv-lite "0.4.13"
whatwg-url@^4.3.0:
version "4.8.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0"
whatwg-url@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.1.0.tgz#5fc8279b93d75483b9ced8b26239854847a18578"
dependencies:
lodash.sortby "^4.7.0"
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
webidl-conversions "^4.0.1"
which-module@^1.0.0:
version "1.0.0"
@ -5431,10 +5376,6 @@ 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"
xmldom@~0.1.22:
version "0.1.22"
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.22.tgz#10de4e5e964981f03c8cc72fadc08d14b6c3aa26"
"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"

Loading…
Cancel
Save