Browse Source

Merge branch 'big-refactor' into dev

pull/36/head
Artur Arseniev 10 years ago
parent
commit
8971b5f294
  1. 2
      Gruntfile.js
  2. 103
      README.md
  3. 2
      dist/css/grapes.min.css
  4. 26
      dist/grapes.min.js
  5. 2
      src/code_manager/main.js
  6. 8
      src/commands/main.js
  7. 8
      src/commands/view/CommandAbstract.js
  8. 10
      src/commands/view/ExportTemplate.js
  9. 18
      src/commands/view/OpenLayers.js
  10. 10
      src/commands/view/OpenStyleManager.js
  11. 1
      src/commands/view/SelectComponent.js
  12. 698
      src/demo.js
  13. 5
      src/dom_components/main.js
  14. 144
      src/editor/main.js
  15. 13
      src/editor/model/Editor.js
  16. 6
      src/grapesjs/main.js
  17. 2
      src/main.js
  18. 22
      src/panels/main.js
  19. 5
      src/panels/view/ButtonView.js
  20. 2
      src/storage_manager/main.js
  21. 4
      src/style_manager/main.js
  22. 1
      src/style_manager/model/Layer.js
  23. 5
      src/style_manager/model/Property.js
  24. 345
      src/style_manager/model/PropertyFactory.js
  25. 67
      src/style_manager/model/Sector.js
  26. 21
      src/style_manager/view/PropertyStackView.js
  27. 28
      test/specs/grapesjs/main.js
  28. 74
      test/specs/panels/e2e/PanelsE2e.js
  29. 7
      test/specs/panels/main.js
  30. 508
      test/specs/style_manager/model/Models.js

2
Gruntfile.js

@ -48,7 +48,7 @@ module.exports = function(grunt) {
"else "+
"root.<%= pkg.name %> = root.GrapesJS = factory();"+
"}(this, function () {",
end: "return require('editor/main'); }));"
end: "return require('grapesjs/main'); }));"
},
paths: {

103
README.md

@ -3,15 +3,16 @@
[![Build Status](https://travis-ci.org/artf/grapesjs.svg?branch=master)](https://travis-ci.org/artf/grapesjs)
<p align="center"><img src="http://grapesjs.com/img/grapesjs-demo-template2.jpg" alt="GrapesJS" width="500" align="center"/></p>
<br/>
GrapesJS is a free and open source Web Template Editor for building HTML templates to be used inside sites, webapps, newsletters or anything else related with HTML.
GrapesJS is a free and open source Web Template Builder which helps you building HTML templates to be used inside sites, newsletters or even mobile apps.
Mainly GrapesJS was designed to be used inside a [CMS] to speed up creation of dynamic templates. To better understand this concept check the image below
<br/>
<p align="center"><img src="http://grapesjs.com/img/gjs-concept.png" alt="GrapesJS - Style Manager" height="400" align="center"/></p>
<br/>
Generally any 'template system', that you can find in various applications like CMS, is composed by the **structure** (HTML), **style** (CSS) and **variables**, which are then replaced with other templates and contents on server-side and rendered soon on client.
Generally any 'template system', that you can find in various applications like CMS, is composed by the **structure** (HTML), **style** (CSS) and **variables**, which are then replaced with other templates and contents on server-side and rendered on client.
This demo shows an example of what is possible to achieve: http://grapesjs.com/demo.html
@ -77,7 +78,7 @@ If [Grunt](http://gruntjs.com/) is already installed globally you could change t
## Usage
JQuery is the only hard dependency so you have to include it before use GrapesJS.
JQuery is the only hard dependency so you have to include it before using GrapesJS.
```html
<script src="http://code.jquery.com/jquery-2.2.0.min.js"></script>
@ -87,92 +88,57 @@ After that include scripts from GrapesJS with all your configurations and render
```html
<link rel="stylesheet" href="path/to/grapes.min.css">
<script src="path/to/grapes.min.js"></script>
<div id="gjs"></div>
<script type="text/javascript">
var gjs = new GrapesJS({
var editor = grapesjs.init({
container : '#gjs',
components: '<div class="txt-red">Hello world!</div>',
style: '.txt-red{color: red}',
});
gjs.render();
</script>
```
Unfortunately with the configuration above you wouldn't see a lot. This because GrapesJS it self is simply empty, adding panels, buttons and other stuff will be your job (actually it's not empty but you need buttons to show them up).
The section below will explain some basic configurations but for a more practical example I suggest to look up the code inside this demo: http://grapesjs.com/demo.html
Documentation is under construction here: [wiki]
## Configuration
For now I only show up some general settings, for more details check source or demo. Examples will be available soon
```js
var config = {
// Prefix to use inside local storage name
storagePrefix: 'wte-',
// Where to render editor (eg. #myId)
container: '',
// Enable/Disable the possibility to copy (ctrl + c) and paste (ctrl + v) elements
copyPaste: true,
// Enable/Disable undo manager
undoManager: true,
//Indicates which storage to use. Available: local | remote | none
storageType: 'local',
//Configurations for Asset Manager (check src/asset_manager/config/config.js)
assetManager: {},
You could also grab the content directly from the element with `fromElement` property
//Configurations for Style Manager (check src/style_manager/config/config.js)
styleManager: {},
//Configurations for Layers (check src/navigator/config/config.js)
layers: {},
//Configurations for Storage Manager (check src/storage_manager/config/config.js)
storageManager: {},
```html
<div id="gjs">
<div class="txt-red">Hello world!</div>
<style>.txt-red{color: red}</style>
</div>
//Configurations for Rich Text Editor (check src/rich_text_editor/config/config.js)
rte: {},
<script type="text/javascript">
var editor = grapesjs.init({
container : '#gjs',
fromElement: true,
});
</script>
```
//Configurations for Components (check src/dom_components/config/config.js)
components: {},
Unfortunately with the configuration above you wouldn't see a lot. This because GrapesJS it self is simply empty, adding panels, buttons and other stuff will be your job (actually it's not empty but you need buttons to show them up).
The section below will explain some basic configurations but for a more practical example I suggest to look up the code inside this demo: http://grapesjs.com/demo.html
//Configurations for Panels (check src/panels/config/config.js)
panels: {},
//Configurations for Commands (check src/commands/config/config.js)
commands: {},
## Configuration
};
```
Check the getting started guide here: [wiki]
## API
At the moment `render()` is the only available method but others will be public very soon...
API References (draft) could be found here: [wiki/API-Reference]
## Testing
**ATTENTION: tests are pretty far away from being complete**
Tests are run by [PhantomJS](http://phantomjs.org/) using [Mocha](https://mochajs.org/) (with [Chai](http://chaijs.com/) and [Sinon](http://sinonjs.org/) help)
```sh
$ npm run test
$ npm test
```
## Todos before beta release
## TODOs before beta release
* **Class Manager** (*in development*) - Ability to assign different classes to components and style them (because CSS with only ids is pretty much a pain)
* **Breakpoint Manager** - Resize canvas according to breakpoints established by user (in simple terms, for responsive templates). Will be put into development immediately after Class Manager
* **Style Manager improvements** - Mainly `stack` type is not yet complete
* **Breakpoint Manager** - Resize canvas according to breakpoints established by user (in simple terms, for responsive templates)
## Acknowledgements
@ -189,16 +155,11 @@ GrapesJS is built on top of this amazing open source projects:
## Support
A star/fork is already a huge motivational support and I'd like to thank all of you for that, but if you want to contribute the project economically and you have this possibility you could use the link below :heart:
If you like the project support it with a donation of your choice.
[![PayPalMe](http://grapesjs.com/img/ppme.png)](https://paypal.me/grapesjs)
## Contributing
Any kind of help is welcome. At the moment there is no generic guidelines so use usual pull requests and push to `dev` branch
## License
BSD 3-clause

2
dist/css/grapes.min.css

File diff suppressed because one or more lines are too long

26
dist/grapes.min.js

File diff suppressed because one or more lines are too long

2
src/code_manager/main.js

@ -12,7 +12,7 @@
* Before using methods you should get first the module from the editor instance, in this way:
*
* ```js
* var codeManager = editor.get('CodeManager');
* var codeManager = editor.CodeManager;
* ```
*
* @module CodeManager

8
src/commands/main.js

@ -7,7 +7,7 @@
* You can init the editor with all necessary commands via configuration
*
* ```js
* var editor = new GrapesJS({
* var editor = grapesjs.init({
* ...
* commands: {...} // Check below for the properties
* ...
@ -17,7 +17,7 @@
* Before using methods you should get first the module from the editor instance, in this way:
*
* ```js
* var commandsService = editor.get('Commands');
* var commands = editor.Commands;
* ```
*
* @module Commands
@ -100,7 +100,7 @@ define(function(require) {
* @param {Object} command Object representing you command. Methods `run` and `stop` are required
* @return {this}
* @example
* commandsService.add('myCommand', {
* commands.add('myCommand', {
* run: function(serviceManager, senderBtn){
* alert('Hello world!');
* },
@ -115,7 +115,7 @@ define(function(require) {
* @param {string} id Command's ID
* @return {Object} Object representing the command
* @example
* var myCommand = commandsService.get('myCommand');
* var myCommand = commands.get('myCommand');
* myCommand.run();
* */
get: function(id){

8
src/commands/view/CommandAbstract.js

@ -40,9 +40,7 @@ define(['backbone'],
* @param {Object} sender Button sender
* @private
* */
run: function(em, sender) {
console.warn("No run method found");
},
run: function(em, sender) {},
/**
* Method that stop command
@ -50,9 +48,7 @@ define(['backbone'],
* @param {Object} sender Button sender
* @private
* */
stop: function(em, sender) {
console.warn("No stop method found");
}
stop: function(em, sender) {}
});
});

10
src/commands/view/ExportTemplate.js

@ -5,12 +5,12 @@ define(function() {
* */
return {
run: function(em, sender){
run: function(editor, sender){
this.sender = sender;
this.components = em.get('Canvas').getWrapper().get('components');
this.modal = em.get('Modal') || null;
this.cm = em.get('CodeManager') || null;
this.cssc = em.get('CssComposer') || null;
this.components = editor.Canvas.getWrapper().get('components');
this.modal = editor.Dialog || null;
this.cm = editor.CodeManager || null;
this.cssc = editor.CssComposer || null;
this.enable();
},

18
src/commands/view/OpenLayers.js

@ -8,21 +8,21 @@ define(['Navigator'], function(Layers) {
run: function(em, sender)
{
if(!this.$layers){
var collection = em.get('Components').getComponent().get('components'),
config = em.get('Config'),
panels = em.get('Panels'),
lyStylePfx = config.layers.stylePrefix || 'nv-';
var collection = em.DomComponents.getComponent().get('components'),
config = em.getConfig(),
panels = em.Panels,
lyStylePfx = config.layers.stylePrefix || 'nv-';
config.layers.stylePrefix = config.stylePrefix + lyStylePfx;
config.layers.em = em;
var layers = new Layers(collection, config.layers);
this.$layers = layers.render();
config.layers.em = em.editor;
var layers = new Layers(collection, config.layers);
this.$layers = layers.render();
// Check if panel exists otherwise crate it
if(!panels.getPanel('views-container'))
this.panel = panels.addPanel({ id: 'views-container'});
this.panel = panels.addPanel({id: 'views-container'});
else
this.panel = panels.getPanel('views-container');
this.panel = panels.getPanel('views-container');
this.panel.set('appendContent', this.$layers).trigger('change:appendContent');
}

10
src/commands/view/OpenStyleManager.js

@ -9,12 +9,12 @@ define(['StyleManager'], function(StyleManager) {
{
this.sender = sender;
if(!this.$cn){
var config = em.get('Config'),
panels = em.get('Panels'),
var config = em.getConfig(),
panels = em.Panels,
pfx = config.styleManager.stylePrefix || 'sm-';
config.styleManager.stylePrefix = config.stylePrefix + pfx;
config.styleManager.target = em;
config.styleManager.target = em.editor;
// Main container
this.$cn = $('<div/>');
@ -23,7 +23,7 @@ define(['StyleManager'], function(StyleManager) {
this.$cn.append(this.$cn2);
// Class Manager container
this.clm = em.get('ClassManager');
this.clm = em.ClassManager;
if(this.clm){
this.$clm = new this.clm.ClassTagsView({
collection: new this.clm.ClassTags([]),
@ -54,7 +54,7 @@ define(['StyleManager'], function(StyleManager) {
// Add all containers to the panel
this.panel.set('appendContent', this.$cn).trigger('change:appendContent');
this.target = em;
this.target = em.editor;
this.listenTo( this.target ,'change:selectedComponent', this.toggleSm);
}
this.toggleSm();

1
src/commands/view/SelectComponent.js

@ -74,6 +74,7 @@ define(function() {
this.removeBadge();
this.clean();
this.editorModel.set('selectedComponent',null);
e.preventDefault();
}
},

698
src/demo.js

File diff suppressed because one or more lines are too long

5
src/dom_components/main.js

@ -3,13 +3,14 @@
* - [getWrapper](#getwrapper)
* - [getComponents](#getcomponents)
* - [addComponent](#addcomponent)
* - [clear](#clear)
* - [render](#render)
*
* With this module is possible to manage all the HTML structure inside the canvas
* You can init the editor with initial components via configuration
*
* ```js
* var editor = new GrapesJS({
* var editor = grapesjs.init({
* ...
* components: {...} // Check below for the possible properties
* ...
@ -20,7 +21,7 @@
* Before using methods you should get first the module from the editor instance, in this way:
*
* ```js
* var ComponentsService = editor.get('Components');
* var ComponentsService = editor.Components;
* ```
*
* @module Components

144
src/editor/main.js

@ -1,14 +1,35 @@
/**
*
* * [getConfig](#getconfig)
* * [getHtml](#gethtml)
* * [getCss](#getcss)
* * [getComponents](#getcomponents)
* * [setComponents](#setcomponents)
* * [getStyle](#getstyle)
* * [setStyle](#setstyle)
* * [getSelected](#getselected)
* * [runCommand](#runcommand)
* * [stopCommand](#stopcommand)
* * [store](#store)
* * [load](#load)
* * [render](#render)
*
* Editor class contains the top level API which you'll probably use to custom the editor or extend it with plugins.
* You get the Editor instance on init method
*
* ```js
* var editor = grapesjs.init({...});
* ```
*
* @module Editor
* @param {Object} config Configurations
*/
define(function (require){
/**
* @class Grapes
* @param {Object} Configurations
*
* @return {Object}
* */
var Editor = function(config) {
var c = config || {},
defaults = require('./config/config'),
Editor = require('./model/Editor'),
EditorModel = require('./model/Editor'),
EditorView = require('./view/EditorView');
for (var name in defaults) {
@ -16,9 +37,9 @@ define(function (require){
c[name] = defaults[name];
}
var editorModel = new Editor(c);
var em = new EditorModel(c);
var obj = {
model : editorModel,
model : em,
config : c,
};
@ -26,62 +47,82 @@ define(function (require){
return {
editor: editorModel,
editor: em,
/**
* @property {DomComponents}
*/
DomComponents: editorModel.get('Components'),
DomComponents: em.get('Components'),
/**
* @property {CssComposer}
*/
CssComposer: editorModel.get('CssComposer'),
CssComposer: em.get('CssComposer'),
/**
* @property {StorageManager}
*/
StorageManager: editorModel.get('StorageManager'),
StorageManager: em.get('StorageManager'),
/**
* @property {AssetManager}
*/
AssetManager: editorModel.get('AssetManager'),
AssetManager: em.get('AssetManager'),
/**
* @property {ClassManager}
*/
ClassManager: editorModel.get('ClassManager'),
ClassManager: em.get('ClassManager'),
/**
* @property {CodeManager}
*/
CodeManager: editorModel.get('CodeManager'),
CodeManager: em.get('CodeManager'),
/**
* @property {Commands}
*/
Commands: editorModel.get('Commands'),
Commands: em.get('Commands'),
/**
* @property {Dialog}
*/
Dialog: editorModel.get('Modal'),
Dialog: em.get('Modal'),
/**
* @property {Panels}
*/
Panels: editorModel.get('Panels'),
Panels: em.get('Panels'),
/**
* @property {StyleManager}
*/
StyleManager: editorModel.get('StyleManager'),
StyleManager: em.get('StyleManager'),
/**
* @property {StyleManager}
*/
Canvas: editorModel.get('Canvas'),
Canvas: em.get('Canvas'),
/**
* @property {UndoManager}
*/
UndoManager: em.get('UndoManager'),
/**
* @property {Utils}
*/
Utils: em.get('Utils'),
/**
* Initialize editor model
* @return {this}
* @private
*/
init: function(){
em.init(this);
return this;
},
/**
* Returns configuration object
@ -96,7 +137,7 @@ define(function (require){
* @return {string} HTML string
*/
getHtml: function(){
return editorModel.getHtml();
return em.getHtml();
},
/**
@ -104,7 +145,7 @@ define(function (require){
* @return {string} CSS string
*/
getCss: function(){
return editorModel.getCss();
return em.getCss();
},
/**
@ -112,16 +153,24 @@ define(function (require){
* @return {Object}
*/
getComponents: function(){
return editorModel.get('Components').getComponents();
return em.get('Components').getComponents();
},
/**
* Set components inside editor's canvas. This method overrides actual components
* @param {Array<Object>|Object|string} components HTML string or components model
* @return {this}
* @example
* editor.setComponents('<div class="cls">New component</div>');
* // or
* editor.setComponents({
* type: 'text',
* classes:['cls'],
* content: 'New component'
* });
*/
setComponents: function(components){
editorModel.setComponents(components);
em.setComponents(components);
return this;
},
@ -130,16 +179,23 @@ define(function (require){
* @return {Object}
*/
getStyle: function(){
return editorModel.get('CssComposer').getRules();
return em.get('CssComposer').getRules();
},
/**
* Set style inside editor's canvas. This method overrides actual style
* @param {Array<Object>|Object|string} style CSS string or style model
* @return {this}
* @example
* editor.setStyle('.cls{color: red}');
* //or
* editor.setStyle({
* selectors: ['cls']
* style: { color: 'red' }
* });
*/
setStyle: function(style){
editorModel.setStyle(style);
em.setStyle(style);
return this;
},
@ -148,7 +204,35 @@ define(function (require){
* @return {grapesjs.Component}
*/
getSelected: function(){
return editorModel.getSelected();
return em.getSelected();
},
/**
* Execute command
* @param {string} id Command ID
* @param {Object} options Custom options
* @example
* editor.runCommand('myCommand', {someValue: 1});
*/
runCommand: function(id, options) {
var command = em.get('Commands').get(id);
if(command)
command.run(this, this, options);
},
/**
* Stop the command if stop method was provided
* @param {string} id Command ID
* @param {Object} options Custom options
* @example
* editor.stopCommand('myCommand', {someValue: 1});
*/
stopCommand: function(id, options) {
var command = em.get('Commands').get(id);
if(command)
command.stop(this, this, options);
},
/**
@ -156,7 +240,7 @@ define(function (require){
* @return {Object} Stored data
*/
store: function(){
return editorModel.store();
return em.store();
},
/**
@ -164,7 +248,7 @@ define(function (require){
* @return {Object} Stored data
*/
load: function(){
return editorModel.load();
return em.load();
},
/**

13
src/editor/model/Editor.js

@ -43,7 +43,7 @@ define([
},
initialize: function(c) {
this.config = _.clone(c);
this.config = c;
this.pfx = this.config.storagePrefix;
this.compName = this.pfx + 'components' + this.config.id;
this.rulesName = this.pfx + 'rules' + this.config.id;
@ -70,6 +70,15 @@ define([
this.on('change:selectedComponent', this.componentSelected, this);
},
/**
* Initialize editor model and set editor instance
* @param {Editor} editor Editor instance
* @return {this}
*/
init: function(editor){
this.set('Editor', editor);
},
/**
* Initialize Parser
* */
@ -644,8 +653,6 @@ define([
if(smc.storeStyles)
store.styles = JSON.stringify(this.getStyle());
console.log('Store');
console.log(store);
sm.store(store);
return store;
},

6
src/grapesjs/main.js

@ -45,8 +45,8 @@ define(function (require) {
if(!els)
throw new Error("'container' is required");
config.el = document.querySelector(els);
var editor = new Editor(config);
c.el = document.querySelector(els);
var editor = new Editor(c).init();
// Execute all plugins
var plugs = plugins.getAll();
@ -67,6 +67,6 @@ define(function (require) {
},
};
};
}();
});

2
src/main.js

@ -1,7 +1,7 @@
require(['src/config/require-config.js'], function() {
require(['editor/main'],function (g){
require(['grapesjs/main'],function (g){
return g;
});

22
src/panels/main.js

@ -11,7 +11,7 @@
* You can init the editor with all panels and buttons necessary via configuration
*
* ```js
* var editor = new GrapesJS({
* var editor = grapesjs.init({
* ...
* panels: {...} // Check below for the possible properties
* ...
@ -22,7 +22,7 @@
* Before using methods you should get first the module from the editor instance, in this way:
*
* ```js
* var panelService = editor.get('Panels');
* var panelManager = editor.Panels;
* ```
*
* @module Panels
@ -81,12 +81,12 @@ define(function(require) {
/**
* Add new panel to the collection
* @param {Object|Panel} panel Object with right properties or an instance of Panel
* @return {Panel} Added panel. Useful in case of passed argument was an Object
* @return {Panel} Added panel. Useful in case passed argument was an Object
* @example
* var newPanel = panelService.addPanel({
* id: 'myNewPanel',
* visible : true,
* buttons : [...],
* var newPanel = panelManager.addPanel({
* id: 'myNewPanel',
* visible : true,
* buttons : [...],
* });
*/
addPanel: function(panel){
@ -98,7 +98,7 @@ define(function(require) {
* @param {string} id Id string
* @return {Panel|null}
* @example
* var myPanel = panelService.getPanel('myNewPanel');
* var myPanel = panelManager.getPanel('myNewPanel');
*/
getPanel : function(id){
var res = panels.where({id: id});
@ -109,9 +109,9 @@ define(function(require) {
* Add button to the panel
* @param {string} panelId Panel's ID
* @param {Object|Button} button Button object or instance of Button
* @return {Button|null} Added button. Useful in case of passed button was an Object
* @return {Button|null} Added button. Useful in case passed button was an Object
* @example
* var newButton = panelService.addButton('myNewPanel',{
* var newButton = panelManager.addButton('myNewPanel',{
* id: 'myNewButton',
* className: 'someClass',
* command: 'someCommand',
@ -130,7 +130,7 @@ define(function(require) {
* @param {string} id Button's ID
* @return {Button|null}
* @example
* var button = panelService.getButton('myPanel','myButton');
* var button = panelManager.getButton('myPanel','myButton');
*/
getButton : function(panelId, id){
var pn = this.getPanel(panelId);

5
src/panels/view/ButtonView.js

@ -141,6 +141,7 @@ function(Backbone, require) {
* */
updateActive: function(){
var command = null;
var editor = this.em && this.em.get ? this.em.get('Editor') : null;
if(this.commands)
command = this.commands.get(this.model.get('command'));
@ -154,7 +155,7 @@ function(Backbone, require) {
this.parentM.set('active', true, { silent: true }).trigger('checkActive');
if(command)
command.run(this.em, this.model);
command.run(editor, this.model);
}else{
this.$el.removeClass(this.activeCls);
@ -164,7 +165,7 @@ function(Backbone, require) {
this.parentM.set('active', false, { silent: true }).trigger('checkActive');
if(command)
command.stop(this.em, this.model);
command.stop(editor, this.model);
}
},

2
src/storage_manager/main.js

@ -15,7 +15,7 @@
* Before using methods you should get first the module from the editor instance, in this way:
*
* ```js
* var storageManager = editor.get('StorageManager');
* var storageManager = editor.StorageManager;
* ```
*
* @module StorageManager

4
src/style_manager/main.js

@ -13,7 +13,7 @@
* You can init the editor with all sectors and properties via configuration
*
* ```js
* var editor = new GrapesJS({
* var editor = grapesjs.init({
* ...
* styleManager: {...} // Check below for the possible properties
* ...
@ -23,7 +23,7 @@
* Before using methods you should get first the module from the editor instance, in this way:
*
* ```js
* var styleManager = editor.get('StyleManager');
* var styleManager = editor.StyleManager;
* ```
*
* @module StyleManager

1
src/style_manager/model/Layer.js

@ -7,6 +7,7 @@ define(['backbone'],
index: '',
active: true,
value: '',
values: {},
preview: false,
}

5
src/style_manager/model/Property.js

@ -24,6 +24,11 @@ define(['backbone', './Layers'],
initialize: function(opt) {
var o = opt || {};
var type = this.get('type');
var name = this.get('name');
var prop = this.get('property');
if(!name)
this.set('name', prop.charAt(0).toUpperCase() + prop.slice(1).replace(/-/g,' '));
switch(type){
case 'stack':

345
src/style_manager/model/PropertyFactory.js

@ -0,0 +1,345 @@
define(['backbone'],
function(Backbone) {
return function() {
return {
/**
* Build props object by their name
* @param {Array<string>|string} props Array of properties name
* @return {Array<Object>}
*/
build: function(props){
var objs = [];
if(typeof props === 'string')
props = [props];
for (var i = 0, len = props.length; i < len; i++) {
var obj = {};
var prop = props[i];
obj.property = prop;
// Property
switch(prop){
case 'border-radius-c':
obj.property = 'border-radius';
break;
}
// Type
switch(prop){
case 'float': case 'position':
case 'text-align':
obj.type = 'radio';
break;
case 'display': case 'font-family':
case 'font-weight':
case 'border-style':
case 'box-shadow-type':
case 'background-repeat': case 'background-position': case 'background-attachment': case 'background-size':
obj.type = 'select';
break;
case 'top': case 'right': case 'bottom': case 'left':
case 'margin-top': case 'margin-right': case 'margin-bottom': case 'margin-left':
case 'padding-top': case 'padding-right': case 'padding-bottom': case 'padding-left':
case 'min-height': case 'min-width': case 'max-height': case 'max-width':
case 'width': case 'height':
case 'font-size': case 'letter-spacing': case 'line-height':
case 'text-shadow-h': case 'text-shadow-v': case 'text-shadow-blur':
case 'border-radius-c':
case 'border-top-left-radius': case 'border-top-right-radius': case 'border-bottom-left-radius':case 'border-bottom-right-radius':
case 'border-width':
case 'box-shadow-h': case 'box-shadow-v': case 'box-shadow-blur': case 'box-shadow-spread':
obj.type = 'integer';
break;
case 'margin': case 'padding':
case 'border-radius':
case 'border':
obj.type = 'composite';
break;
case 'color': case 'text-shadow-color':
case 'background-color': case 'border-color': case 'box-shadow-color':
obj.type = 'color';
break;
case 'text-shadow': case 'box-shadow': case 'background':
obj.type = 'stack';
break;
case 'background-image':
obj.type = 'file';
break;
}
// Defaults
switch(prop){
case 'float': case 'background-color':
case 'background-image':
obj.defaults = 'none';
break;
case 'display':
obj.defaults = 'block';
break;
case 'position':
obj.defaults = 'static';
break;
case 'top': case 'right': case 'bottom': case 'left':
case 'margin-top': case 'margin-right': case 'margin-bottom': case 'margin-left':
case 'padding-top': case 'padding-right': case 'padding-bottom': case 'padding-left':
case 'text-shadow-h': case 'text-shadow-v': case 'text-shadow-blur':
case 'border-radius-c':
case 'border-top-left-radius': case 'border-top-right-radius': case 'border-bottom-left-radius':case 'border-bottom-right-radius':
case 'box-shadow-h': case 'box-shadow-v': case 'box-shadow-spread':
obj.defaults = 0;
break;
case 'box-shadow-blur':
obj.defaults = 5;
break;
case 'min-height': case 'min-width': case 'max-height': case 'max-width':
case 'width': case 'height':
case 'background-size':
obj.defaults = 'auto';
break;
case 'font-family':
obj.defaults = 'Arial, Helvetica, sans-serif';
break;
case 'font-size': case 'border-width':
obj.defaults = 'medium';
break;
case 'font-weight':
obj.defaults = '400';
break;
case 'letter-spacing': case 'line-height':
obj.defaults = 'normal';
break;
case 'color': case 'text-shadow-color':
case 'border-color': case 'box-shadow-color':
obj.defaults = 'black';
break;
case 'text-align':
obj.defaults = 'left';
break;
case 'border-style':
obj.defaults = 'solid';
break;
case 'box-shadow-type':
obj.defaults = '';
break;
case 'background-repeat':
obj.defaults = 'repeat';
break;
case 'background-position':
obj.defaults = 'left top';
break;
case 'background-attachment':
obj.defaults = 'scroll';
break;
}
// Units
switch(prop){
case 'top': case 'right': case 'bottom': case 'left':
case 'margin-top': case 'margin-right': case 'margin-bottom': case 'margin-left':
case 'padding-top': case 'padding-right': case 'padding-bottom': case 'padding-left':
case 'min-height': case 'min-width': case 'max-height': case 'max-width':
case 'width': case 'height':
case 'text-shadow-h': case 'text-shadow-v': case 'text-shadow-blur':
case 'border-radius-c':
case 'border-top-left-radius': case 'border-top-right-radius': case 'border-bottom-left-radius':case 'border-bottom-right-radius':
case 'box-shadow-h': case 'box-shadow-v':
obj.units = ['px','%'];
break;
case 'font-size': case 'letter-spacing': case 'line-height':
obj.units = ['px','em', 'rem', '%'];
break;
case 'border-width':
obj.units = ['px','em'];
break;
case 'box-shadow-blur': case 'box-shadow-spread':
obj.units = ['px'];
break;
}
// Min/Max
switch(prop){
case 'min-height': case 'min-width': case 'max-height': case 'max-width':
case 'width': case 'height':
case 'font-size':
case 'text-shadow-blur':
case 'border-radius-c':
case 'border-top-left-radius': case 'border-top-right-radius': case 'border-bottom-left-radius':case 'border-bottom-right-radius':
case 'border-width':
case 'box-shadow-blur':
obj.min = 0;
break;
}
// Preview
switch(prop){
case 'text-shadow': case 'box-shadow': case 'background':
obj.preview = true;
break;
}
// Detached
switch(prop){
case 'background':
obj.detached = true;
break;
}
// Options
switch(prop){
case 'float':
obj.list = [
{value: 'none'},
{value: 'left'},
{value: 'right'},
];
break;
case 'display':
obj.list = [
{value: 'block'},
{value: 'inline'},
{value: 'inline-block'},
{value: 'none'},
];
break;
case 'position':
obj.list = [
{value: 'static'},
{value: 'relative'},
{value: 'absolute'},
{value: 'fixed'},
];
break;
case 'font-family':
var ss = ', sans-serif';
var s = ', serif';
var fonts = ['Arial, Helvetica' + ss, 'Arial Black, Gadget' + ss, 'Brush Script MT' + ss,
'Comic Sans MS, cursive' + ss, 'Courier New, Courier, monospace', 'Georgia, serif', 'Helvetica, serif',
'Impact, Charcoal' + ss, 'Lucida Sans Unicode, Lucida Grande' + ss, 'Tahoma, Geneva' + ss,
'Times New Roman, Times, serif', 'Trebuchet MS, Helvetica' + ss, 'Verdana, Geneva' + ss];
obj.list = [];
for(var j = 0, l = fonts.length; j < l; j++){
var font = {};
font.value = fonts[j];
font.name = fonts[j].split(',')[0];
font.style = 'font-family: ' + fonts[j] + '; font-size:15px';
obj.list.push(font);
}
break;
case 'font-weight':
obj.list = [
{ value : '100', name : 'Thin', },
{ value : '200', name : 'Extra-Light', },
{ value : '300', name : 'Light', },
{ value : '400', name : 'Normal', },
{ value : '500', name : 'Medium',},
{ value : '600', name : 'Semi-Bold',},
{ value : '700', name : 'Bold', },
{ value : '800', name : 'Extra-Bold',},
{ value : '900', name : 'Ultra-Bold', }
];
break;
case 'text-align':
obj.list = [
{ value : 'left'},
{ value : 'center'},
{ value : 'right'},
{ value : 'justify'}
];
break;
case 'border-style':
obj.list = [
{ value : 'none'},
{ value : 'solid'},
{ value : 'dotted'},
{ value : 'dashed'},
{ value : 'double'},
{ value : 'groove'},
{ value : 'ridge'},
{ value : 'inset'},
{ value : 'outset'}
];
break;
case 'box-shadow-type':
obj.list = [
{value : '', name: 'Outside'},
{value : 'inset', name: 'Inside'}
];
break;
case 'background-repeat':
obj.list = [
{ value : 'repeat'},
{ value : 'repeat-x'},
{ value : 'repeat-y'},
{ value : 'no-repeat'}
];
break;
case 'background-position':
obj.list = [
{ value : 'left top',},
{ value : 'left center',},
{ value : 'left bottom',},
{ value : 'right top',},
{ value : 'right center'},
{ value : 'right bottom'},
{ value : 'center top'},
{ value : 'center center'},
{ value : 'center bottom'}
];
break;
case 'background-attachment':
obj.list = [
{ value : 'scroll'},
{ value : 'fixed'},
{ value : 'local'}
];
break;
case 'background-size':
obj.list = [
{ value : 'auto'},
{ value : 'cover'},
{ value : 'contain'}
];
break;
}
// Properties
switch(prop){
case 'margin':
obj.properties = this.build(['margin-top', 'margin-right', 'margin-bottom', 'margin-left']);
break;
case 'padding':
obj.properties = this.build(['padding-top', 'padding-right', 'padding-bottom', 'padding-left']);
break;
case 'text-shadow':
obj.properties = this.build(['text-shadow-h', 'text-shadow-v', 'text-shadow-blur', 'text-shadow-color']);
break;
case 'border':
obj.properties = this.build(['border-width', 'border-style', 'border-color']);
break;
case 'border-radius':
obj.properties = this.build(['border-top-left-radius', 'border-top-right-radius',
'border-bottom-left-radius', 'border-bottom-right-radius']);
break;
case 'box-shadow':
obj.properties = this.build(['box-shadow-h', 'box-shadow-v', 'box-shadow-blur','box-shadow-spread',
'box-shadow-color', 'box-shadow-type']);
break;
case 'background':
obj.properties = this.build(['background-image', 'background-repeat', 'background-position','background-attachment',
'background-size']);
break;
}
objs.push(obj);
}
return objs;
},
};
};
});

67
src/style_manager/model/Sector.js

@ -1,5 +1,5 @@
define(['backbone', './Properties'],
function(Backbone, Properties) {
define(['backbone', './Properties', './PropertyFactory'],
function(Backbone, Properties, PropertyFactory) {
return Backbone.Model.extend({
@ -7,14 +7,75 @@ define(['backbone', './Properties'],
id: '',
name: '',
open: true,
buildProps: '',
extendBuilded: 1,
properties : [],
},
initialize: function(opts) {
var o = opts || {};
var props = o.properties || this.get('properties');
var props = [];
var builded = this.buildProperties(o.buildProps);
if(!builded)
props = this.get('properties');
else
props = this.extendProperties(builded);
this.set('properties', new Properties(props));
},
/**
* Extend properties
* @param {Array<Object>} props Start properties
* @return {Array<Object>} Final props
* @private
*/
extendProperties: function(props){
var pLen = props.length;
var mProps = this.get('properties');
var ext = this.get('extendBuilded');
for (var i = 0, len = mProps.length; i < len; i++){
var mProp = mProps[i];
var found = 0;
for(var j = 0; j < pLen; j++){
var prop = props[j];
if(mProp.property == prop.property){
props[j] = ext ? _.extend(prop, mProp) : mProp;
found = 1;
continue;
}
}
if(!found)
props.push(mProp);
}
return props;
},
/**
* Build properties
* @param {Array<string>} propr Array of props as sting
* @return {Array<Object>}
* @private
*/
buildProperties: function(props){
var r;
var buildP = props || [];
if(!buildP.length)
return;
if(!this.propFactory)
this.propFactory = new PropertyFactory();
r = this.propFactory.build(buildP);
return r;
},
});
});

21
src/style_manager/view/PropertyStackView.js

@ -73,11 +73,13 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
if(that.model.get('detached')){
var propVal = '';
var index = model.collection.indexOf(model);
that.getLayers().each(function(layer){
var vals = layer.get('value').split(' ');
if(vals.length && vals[index])
propVal += (propVal ? ',' : '') + vals[index];
var val = layer.get('values')[model.get('property')];
if(val)
propVal += (propVal ? ',' : '') + val;
});
view.updateTargetStyle(propVal, null, opt);
}else
that.model.set('value', result, opt);
@ -120,6 +122,19 @@ define(['backbone','./PropertyCompositeView', 'text!./../templates/propertyStack
var model = this.getLayers().at(stackIndex);
if(!model)
return;
// Store properties values inside layer, in this way it's more reliable
// to fetch them later
var valObj = {};
this.model.get('properties').each(function(prop){
var v = prop.getValue();
func = prop.get('functionName');
if(func)
v = func + '(' + v + ')';
valObj[prop.get('property')] = v;
});
model.set('values', valObj);
model.set('value', result);
return this.createValue();
},

28
test/specs/grapesjs/main.js

@ -39,7 +39,7 @@ define(['GrapesJS', 'PluginManager', 'chai'],
type:'none'
},
}
obj = new GrapesJS();
obj = GrapesJS;
fixture = $('<div id="' + editorName + '"></div>');
fixture.empty().appendTo(fixtures);
});
@ -143,6 +143,32 @@ define(['GrapesJS', 'PluginManager', 'chai'],
data.html.should.equal(htmlString);
});
it('Execute custom command', function() {
var editor = obj.init(config);
editor.testVal = '';
editor.setComponents(htmlString);
editor.Commands.add('test-command', {
run: function(ed, caller, opts){
ed.testVal = ed.getHtml() + opts.val;
},
});
editor.runCommand('test-command', {val: 5});
editor.testVal.should.equal(htmlString + '5');
});
it('Stop custom command', function() {
var editor = obj.init(config);
editor.testVal = '';
editor.setComponents(htmlString);
editor.Commands.add('test-command', {
stop: function(ed, caller, opts){
ed.testVal = ed.getHtml() + opts.val;
},
});
editor.stopCommand('test-command', {val: 5});
editor.testVal.should.equal(htmlString + '5');
});
});
});

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

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

7
test/specs/panels/main.js

@ -6,7 +6,8 @@ define([
modulePath + '/view/PanelView',
modulePath + '/view/PanelsView',
modulePath + '/view/ButtonView',
modulePath + '/view/ButtonsView'
modulePath + '/view/ButtonsView',
modulePath + '/e2e/PanelsE2e'
],
function(
Panels,
@ -14,7 +15,8 @@ define([
PanelView,
PanelsView,
ButtonView,
ButtonsView
ButtonsView,
e2e
) {
describe('Panels', function() {
@ -111,5 +113,6 @@ define([
PanelsView.run();
ButtonView.run();
ButtonsView.run();
e2e.run();
});
});

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

@ -1,12 +1,14 @@
var path = 'StyleManager/model/';
define([path + 'Sector',
path + 'Sectors',
path + 'PropertyFactory',
path + 'Property',
path + 'Properties',
path + 'Layer',
path + 'Layers'],
function(Sector,
Sectors,
PropertyFactory,
Property,
Properties,
Layer,
@ -18,8 +20,19 @@ define([path + 'Sector',
describe('Sector', function() {
var obj;
var confToExt;
beforeEach(function () {
confToExt = {
buildProps: ['display', 'float'],
properties: [{
property: 'display',
type: 'radio',
},{
property: 'color',
type: 'color',
}]
};
obj = new Sector();
});
@ -42,6 +55,39 @@ define([path + 'Sector',
obj.get('properties').length.should.equal(2);
});
it('Build properties', function() {
var res = obj.buildProperties(['display', 'float']);
res.length.should.equal(2);
res[0].should.deep.equal({
property: 'display',
type: 'select',
defaults: 'block',
list: [
{value: 'block'},
{value: 'inline'},
{value: 'inline-block'},
{value: 'none'},
],
});
});
it('Extend properties', function() {
obj = new Sector(confToExt);
obj.get('properties').length.should.equal(3);
var prop0 = obj.get('properties').at(0);
prop0.get('type').should.equal('radio');
prop0.get('defaults').should.equal('block');
});
it('Do not extend properties', function() {
confToExt.extendBuilded = 0;
obj = new Sector(confToExt);
obj.get('properties').length.should.equal(3);
var prop0 = obj.get('properties').at(0);
prop0.get('type').should.equal('radio');
prop0.get('defaults').should.equal('');
});
});
describe('Sectors', function() {
@ -172,6 +218,468 @@ define([path + 'Sector',
});
describe('PropertyFactory', function() {
var obj;
beforeEach(function () {
obj = new PropertyFactory();
});
afterEach(function () {
delete obj;
});
it('Object exists', function() {
obj.should.be.ok;
});
it('Build single prop', function() {
obj.build('float').should.deep.equal([{
property: 'float',
type: 'radio',
defaults: 'none',
list: [
{value: 'none'},
{value: 'left'},
{value: 'right'},
],
}]);
});
it('Build display', function() {
obj.build('display').should.deep.equal([{
property: 'display',
type: 'select',
defaults: 'block',
list: [
{value: 'block'},
{value: 'inline'},
{value: 'inline-block'},
{value: 'none'},
],
}]);
});
it('Build position', function() {
obj.build('position').should.deep.equal([{
property: 'position',
type: 'radio',
defaults: 'static',
list: [
{value: 'static'},
{value: 'relative'},
{value: 'absolute'},
{value: 'fixed'},
],
}]);
});
it('Build top, left, right, bottom', function() {
var res = {
type: 'integer',
units: ['px','%'],
defaults : 0,
}
res.property = 'top';
obj.build('top').should.deep.equal([res]);
res.property = 'right';
obj.build('right').should.deep.equal([res]);
res.property = 'bottom';
obj.build('bottom').should.deep.equal([res]);
res.property = 'left';
obj.build('left').should.deep.equal([res]);
});
it('Build width e height family', function() {
var res = {
type: 'integer',
units: ['px','%'],
defaults: 'auto',
min: 0,
}
res.property = 'width';
obj.build('width').should.deep.equal([res]);
res.property = 'height';
obj.build('height').should.deep.equal([res]);
res.property = 'min-height';
obj.build('min-height').should.deep.equal([res]);
res.property = 'max-height';
obj.build('max-height').should.deep.equal([res]);
res.property = 'min-width';
obj.build('min-width').should.deep.equal([res]);
res.property = 'max-width';
obj.build('max-width').should.deep.equal([res]);
});
it('Build margin', function() {
var res = {
property: 'margin',
type: 'composite',
properties:[{
property : 'margin-top',
type : 'integer',
units : ['px','%'],
defaults : 0,
},{
property : 'margin-right',
type : 'integer',
units : ['px','%'],
defaults : 0,
},{
property : 'margin-bottom',
type : 'integer',
units : ['px','%'],
defaults : 0,
},{
property : 'margin-left',
type : 'integer',
units : ['px','%'],
defaults : 0,
},],
};
obj.build('margin').should.deep.equal([res]);
});
it('Build padding', function() {
var res = {
property: 'padding',
type: 'composite',
properties:[{
property : 'padding-top',
type : 'integer',
units : ['px','%'],
defaults : 0,
},{
property : 'padding-right',
type : 'integer',
units : ['px','%'],
defaults : 0,
},{
property : 'padding-bottom',
type : 'integer',
units : ['px','%'],
defaults : 0,
},{
property : 'padding-left',
type : 'integer',
units : ['px','%'],
defaults : 0,
},],
};
obj.build('padding').should.deep.equal([res]);
});
it('Build font-family', function() {
var ss = ', sans-serif';
var ms = ', monospace';
var ff = 'font-family: ';
var sty = '; font-size:15px';
var res = {
property: 'font-family',
type: 'select',
defaults: 'Arial, Helvetica' + ss,
list:[
{name: 'Arial', value: 'Arial, Helvetica' + ss, style: ff + 'Arial, Helvetica' + ss + sty},
{name: 'Arial Black', value: 'Arial Black, Gadget' + ss, style: ff + 'Arial Black, Gadget' + ss + sty},
{name: 'Brush Script MT', value: 'Brush Script MT' + ss, style: ff + 'Brush Script MT' + ss + sty},
{name: 'Comic Sans MS', value: 'Comic Sans MS, cursive' + ss, style: ff + 'Comic Sans MS, cursive' + ss + sty},
{name: 'Courier New', value: 'Courier New, Courier' + ms, style: ff + 'Courier New, Courier' + ms + sty},
{name: 'Georgia', value: 'Georgia, serif', style: ff + 'Georgia, serif' + sty},
{name: 'Helvetica', value: 'Helvetica, serif', style: ff + 'Helvetica, serif' + sty},
{name: 'Impact', value: 'Impact, Charcoal' + ss, style: ff + 'Impact, Charcoal' + ss + sty},
{name: 'Lucida Sans Unicode', value: 'Lucida Sans Unicode, Lucida Grande' + ss, style: ff + 'Lucida Sans Unicode, Lucida Grande' + ss + sty},
{name: 'Tahoma', value: 'Tahoma, Geneva' + ss, style: ff + 'Tahoma, Geneva' + ss + sty},
{name: 'Times New Roman', value: 'Times New Roman, Times, serif', style: ff + 'Times New Roman, Times, serif' + sty},
{name: 'Trebuchet MS', value: 'Trebuchet MS, Helvetica' + ss, style: ff + 'Trebuchet MS, Helvetica' + ss + sty},
{name: 'Verdana', value: 'Verdana, Geneva' + ss, style: ff + 'Verdana, Geneva' + ss + sty},
],
};
obj.build('font-family').should.deep.equal([res]);
});
it('Build font-size', function() {
var res = {
type: 'integer',
units: ['px','em', 'rem', '%'],
defaults: 'medium',
min: 0,
};
res.property = 'font-size';
obj.build('font-size').should.deep.equal([res]);
});
it('Build letter-spacing', function() {
var res = {
type: 'integer',
units: ['px','em', 'rem', '%'],
defaults: 'normal',
};
res.property = 'letter-spacing';
obj.build('letter-spacing').should.deep.equal([res]);
});
it('Build font-weight', function() {
var res = {
type: 'select',
defaults: '400',
list: [{ value : '100', name : 'Thin', },
{ value : '200', name : 'Extra-Light', },
{ value : '300', name : 'Light', },
{ value : '400', name : 'Normal', },
{ value : '500', name : 'Medium',},
{ value : '600', name : 'Semi-Bold',},
{ value : '700', name : 'Bold', },
{ value : '800', name : 'Extra-Bold',},
{ value : '900', name : 'Ultra-Bold', }],
};
res.property = 'font-weight';
obj.build('font-weight').should.deep.equal([res]);
});
it('Build color', function() {
var res = {
property: 'color',
type: 'color',
defaults: 'black',
};
obj.build('color').should.deep.equal([res]);
});
it('Build line-height', function() {
var res = {
type: 'integer',
units: ['px','em', 'rem', '%'],
defaults: 'normal',
};
res.property = 'line-height';
obj.build('line-height').should.deep.equal([res]);
});
it('Build text-align', function() {
var res = {
type: 'radio',
defaults: 'left',
list: [{ value : 'left'},
{ value : 'center'},
{ value : 'right'},
{ value : 'justify'}],
};
res.property = 'text-align';
obj.build('text-align').should.deep.equal([res]);
});
it('Build text-shadow', function() {
var res = {
type: 'stack',
preview: true,
properties : [{
property: 'text-shadow-h',
type: 'integer',
units: ['px','%'],
defaults : 0,
},{
property: 'text-shadow-v',
type: 'integer',
units: ['px','%'],
defaults : 0,
},{
property: 'text-shadow-blur',
type: 'integer',
units: ['px','%'],
defaults : 0,
min: 0,
},{
property: 'text-shadow-color',
type: 'color',
defaults: 'black',
},],
};
res.property = 'text-shadow';
obj.build('text-shadow').should.deep.equal([res]);
});
it('Build border-radius-c', function() {
var res = {
type: 'integer',
units: ['px', '%'],
defaults: 0,
min: 0,
};
res.property = 'border-radius';
obj.build('border-radius-c').should.deep.equal([res]);
});
it('Build border-radius', function() {
var res = {
property: 'border-radius',
type: 'composite',
properties: [{
property : 'border-top-left-radius',
type: 'integer',
units: ['px','%'],
defaults: 0,
min: 0,
},{
property: 'border-top-right-radius',
type: 'integer',
units: ['px','%'],
min : 0,
defaults: 0,
},{
property: 'border-bottom-left-radius',
type: 'integer',
units: ['px','%'],
min: 0,
defaults: 0,
},{
property: 'border-bottom-right-radius',
type: 'integer',
units: ['px','%'],
min: 0,
defaults : 0,
},],
};
res.property = 'border-radius';
obj.build('border-radius').should.deep.equal([res]);
});
it('Build background-color', function() {
var res = {
type : 'color',
defaults: 'none'
};
res.property = 'background-color';
obj.build('background-color').should.deep.equal([res]);
});
it('Build border', function() {
var res = {
property: 'border',
type: 'composite',
properties : [{
property: 'border-width',
type: 'integer',
units: ['px','em'],
defaults: 'medium',
min: 0,
},{
property: 'border-style',
type : 'select',
defaults: 'solid',
list: [{ value : 'none'},
{ value : 'solid'},
{ value : 'dotted'},
{ value : 'dashed'},
{ value : 'double'},
{ value : 'groove'},
{ value : 'ridge'},
{ value : 'inset'},
{ value : 'outset'},],
},{
property: 'border-color',
type: 'color',
defaults: 'black',
}],
};
obj.build('border').should.deep.equal([res]);
});
it('Build box-shadow', function() {
var res = {
property: 'box-shadow',
type: 'stack',
preview: true,
properties: [{
property: 'box-shadow-h',
type: 'integer',
units: ['px','%'],
defaults: 0,
},{
property: 'box-shadow-v',
type: 'integer',
units: ['px','%'],
defaults: 0,
},{
property: 'box-shadow-blur',
type: 'integer',
units: ['px'],
defaults: 5,
min: 0,
},{
property: 'box-shadow-spread',
type: 'integer',
units: ['px'],
defaults: 0,
},{
property: 'box-shadow-color',
type: 'color',
defaults: 'black',
},{
property: 'box-shadow-type',
type: 'select',
defaults: '',
list: [{value : '', name: 'Outside' },
{value : 'inset', name: 'Inside' }],
}],
};
obj.build('box-shadow').should.deep.equal([res]);
});
it('Build background', function() {
var res = {
property: 'background',
type: 'stack',
preview: true,
detached: true,
properties : [{
property: 'background-image',
type: 'file',
defaults: 'none',
},{
property: 'background-repeat',
type: 'select',
defaults: 'repeat',
list: [{ value : 'repeat'},
{ value : 'repeat-x'},
{ value : 'repeat-y'},
{ value : 'no-repeat'}],
},{
property: 'background-position',
type: 'select',
defaults: 'left top',
list: [ { value : 'left top',},
{ value : 'left center',},
{ value : 'left bottom',},
{ value : 'right top',},
{ value : 'right center'},
{ value : 'right bottom'},
{ value : 'center top'},
{ value : 'center center'},
{ value : 'center bottom'}
]
},{
property: 'background-attachment',
type: 'select',
defaults: 'scroll',
list: [{ value : 'scroll'},
{ value : 'fixed'},
{ value : 'local'}],
},{
property: 'background-size',
type: 'select',
defaults: 'auto',
list: [{ value : 'auto'},
{ value : 'cover'},
{ value : 'contain'}],
}],
};
obj.build('background').should.deep.equal([res]);
});
});
}
};

Loading…
Cancel
Save