Browse Source

Merge branch 'dev' of https://github.com/artf/grapesjs into 972-added-style-containers

pull/988/head
Val Rudi 9 years ago
parent
commit
634cad4e0e
  1. 236
      dist/grapes.js
  2. 6
      dist/grapes.min.js
  3. 2
      package-lock.json
  4. 2
      package.json
  5. 2
      src/canvas/view/CanvasView.js
  6. 23
      src/commands/index.js
  7. 32
      src/commands/view/CommandAbstract.js
  8. 8
      src/commands/view/SelectComponent.js
  9. 9
      src/css_composer/index.js
  10. 10
      src/dom_components/model/Component.js
  11. 14
      src/dom_components/model/ComponentVideo.js
  12. 5
      src/dom_components/view/ComponentView.js
  13. 25
      src/editor/index.js
  14. 6
      src/editor/model/Editor.js
  15. 25
      src/storage_manager/index.js
  16. 6
      src/style_manager/view/PropertyView.js
  17. 4
      src/styles/scss/_gjs_variables.scss
  18. 9
      src/trait_manager/model/Traits.js
  19. 6
      src/trait_manager/view/TraitsView.js
  20. 35
      src/utils/extender.js
  21. 119
      test/specs/grapesjs/index.js

236
dist/grapes.js

@ -3853,7 +3853,8 @@ module.exports = Backbone.View.extend({
if (em && em.get('avoidInlineStyle')) {
this.el.id = model.getId();
model.setStyle(model.getStyle());
var style = model.getStyle();
!(0, _underscore.isEmpty)(style) && model.setStyle(style);
} else {
this.setAttribute('style', model.styleToString());
}
@ -4817,11 +4818,9 @@ var Component = Backbone.Model.extend(_Styleable2.default).extend({
}
var obj = Backbone.Model.prototype.toJSON.apply(this, args);
var scriptStr = this.getScriptString();
obj.attributes = this.getAttributes();
delete obj.attributes.class;
delete obj.toolbar;
scriptStr && (obj.script = scriptStr);
return obj;
},
@ -17583,13 +17582,7 @@ module.exports = {
if (key == 8 || key == 46) {
if (!focused) e.preventDefault();
if (comp && !focused) {
if (!comp.get('removable')) return;
comp.set('status', '');
comp.destroy();
this.hideBadge();
this.clean();
this.hideHighlighter();
this.editorModel.set('selectedComponent', null);
this.editor.runCommand('core:component-delete');
}
}
},
@ -23683,7 +23676,7 @@ module.exports = function () {
plugins: plugins,
// Will be replaced on build
version: '0.14.6',
version: '0.14.8',
/**
* Initializes an editor based on passed options
@ -24094,14 +24087,13 @@ module.exports = function (config) {
* @example
* editor.runCommand('myCommand', {someValue: 1});
*/
runCommand: function runCommand(id, options) {
var result;
runCommand: function runCommand(id) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var result = void 0;
var command = em.get('Commands').get(id);
if (command) result = command.callRun(this, options);
if (command) {
result = command.run(this, this, options);
this.trigger('run:' + id);
}
return result;
},
@ -24114,14 +24106,13 @@ module.exports = function (config) {
* @example
* editor.stopCommand('myCommand', {someValue: 1});
*/
stopCommand: function stopCommand(id, options) {
var result;
stopCommand: function stopCommand(id) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var result = void 0;
var command = em.get('Commands').get(id);
if (command) result = command.callStop(this, options);
if (command) {
result = command.stop(this, this, options);
this.trigger('stop:' + id);
}
return result;
},
@ -24337,6 +24328,9 @@ module.exports = function (config) {
* ## Commands
* * `run:{commandName}` - Triggered when some command is called to run (eg. editor.runCommand('preview'))
* * `stop:{commandName}` - Triggered when some command is called to stop (eg. editor.stopCommand('preview'))
* * `run:{commandName}:before` - Triggered before the command is called
* * `stop:{commandName}:before` - Triggered before the command is called to stop
* * `abort:{commandName}` - Triggered when the command execution is aborted (`editor.on(`run:preview:before`, opts => opts.abort = 1);`)
* ## General
* * `canvasScroll` - Triggered when the canvas is scrolle
* * `undo` - Undo executed
@ -24409,6 +24403,12 @@ module.exports = {
// Width for the editor container
width: '100%',
// By default Grapes injects base CSS into the canvas. For example, it sets body margin to 0
// and sets a default background color of white. This CSS is desired in most cases.
// use this property if you wish to overwrite the base CSS to your own CSS. This is most
// useful if for example your template is not based off a document with 0 as body margin.
baseCss: '\n * {\n box-sizing: border-box;\n }\n html, body, #wrapper {\n min-height: 100%;\n }\n body {\n margin: 0;\n height: 100%;\n background-color: #fff\n }\n #wrapper {\n overflow: auto;\n overflow-x: hidden;\n }\n \n * ::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.1)\n }\n\n * ::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2)\n }\n\n * ::-webkit-scrollbar {\n width: 10px\n }\n ',
// CSS that could only be seen (for instance, inside the code viewer)
protectedCss: '* { box-sizing: border-box; } body {margin: 0;}',
@ -24668,7 +24668,7 @@ module.exports = Backbone.Model.extend({
clb && clb();
};
if (sm && sm.getConfig().autoload) {
if (sm && sm.canAutoload()) {
this.load(postLoad);
} else {
postLoad();
@ -25003,7 +25003,9 @@ module.exports = Backbone.Model.extend({
sm.load(load, function (res) {
_this6.cacheLoad = res;
clb && clb(res);
_this6.trigger('storage:load', res);
setTimeout(function () {
return _this6.trigger('storage:load', res);
}, 0);
});
},
@ -30351,6 +30353,15 @@ module.exports = function () {
},
/**
* Get configuration object
* @return {Object}
* */
getConfig: function getConfig() {
return c;
},
/**
* Checks if autosave is enabled
* @return {Boolean}
@ -30529,12 +30540,22 @@ module.exports = function () {
/**
* Get configuration object
* @return {Object}
* Get current storage
* @return {Storage}
* */
getCurrentStorage: function getCurrentStorage() {
return this.get(this.getCurrent());
},
/**
* Check if autoload is possible
* @return {Boolean}
* @private
* */
getConfig: function getConfig() {
return c;
canAutoload: function canAutoload() {
var storage = this.getCurrentStorage();
return storage && this.getConfig().autoload;
}
};
};
@ -36610,7 +36631,7 @@ var RichTextEditor = function () {
btn.className = btn.className.replace(active, '').trim();
// doc.queryCommandValue(name) != 'false'
if (doc.queryCommandState(name)) {
if (doc.queryCommandSupported(name) && doc.queryCommandState(name)) {
btn.className += ' ' + active;
}
@ -41263,25 +41284,26 @@ module.exports = Backbone.View.extend({
"use strict";
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; /**
* This module contains and manage CSS rules for the template inside the canvas
* Before using the methods you should get first the module from the editor instance, in this way:
*
* ```js
* var cssComposer = editor.CssComposer;
* ```
*
* @module CssComposer
* @param {Object} config Configurations
* @param {string|Array<Object>} [config.rules=[]] CSS string or an array of rule objects
* @example
* ...
* CssComposer: {
* rules: '.myClass{ color: red}',
* }
*/
/**
* This module contains and manage CSS rules for the template inside the canvas
* Before using the methods you should get first the module from the editor instance, in this way:
*
* ```js
* var cssComposer = editor.CssComposer;
* ```
*
* @module CssComposer
* @param {Object} config Configurations
* @param {string|Array<Object>} [config.rules=[]] CSS string or an array of rule objects
* @example
* ...
* CssComposer: {
* rules: '.myClass{ color: red}',
* }
*/
var _underscore = __webpack_require__(1);
module.exports = function () {
var em = void 0;
@ -41411,7 +41433,9 @@ module.exports = function () {
obj = c.em.get('Parser').parseCss(d.css);
}
if (obj) {
if ((0, _underscore.isArray)(obj)) {
obj.length && rules.reset(obj);
} else if (obj) {
rules.reset(obj);
}
@ -41452,10 +41476,12 @@ module.exports = function () {
* color: '#fff',
* });
* */
add: function add(selectors, state, width, opts) {
add: function add(selectors, state, width) {
var opts = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
var s = state || '';
var w = width || '';
var opt = opts || {};
var opt = _extends({}, opts);
var rule = this.get(selectors, s, w, opt);
if (rule) return rule;else {
opt.state = s;
@ -43719,7 +43745,7 @@ module.exports = Component.extend({
name: 'color',
placeholder: 'eg. FF0000',
changeProp: 1
}, this.getAutoplayTrait(), this.getLoopTrait(), this.getControlsTrait()];
}, this.getAutoplayTrait(), this.getLoopTrait()];
},
@ -43774,11 +43800,14 @@ module.exports = Component.extend({
* @private
*/
getYoutubeSrc: function getYoutubeSrc() {
var id = this.get('videoId');
var url = this.get('ytUrl');
url += this.get('videoId') + '?';
url += id + '?';
url += this.get('autoplay') ? '&autoplay=1' : '';
url += !this.get('controls') ? '&controls=0' : '';
url += this.get('loop') ? '&loop=1' : '';
url += !this.get('controls') ? '&controls=0&showinfo=0' : '';
// Loop works only with playlist enabled
// https://stackoverflow.com/questions/25779966/youtube-iframe-loop-doesnt-work
url += this.get('loop') ? '&loop=1&playlist=' + id : '';
return url;
},
@ -44754,15 +44783,15 @@ var Droppable = function () {
}
} else if (dragContent) {
content = dragContent;
} else if (types.indexOf('text/html') >= 0) {
} else if ((0, _underscore.indexOf)(types, 'text/html') >= 0) {
content = dataTransfer.getData('text/html').replace(/<\/?meta[^>]*>/g, '');
} else if (types.indexOf('text/uri-list') >= 0) {
} else if ((0, _underscore.indexOf)(types, 'text/uri-list') >= 0) {
content = {
type: 'link',
attributes: { href: content },
content: content
};
} else if (types.indexOf('text/json') >= 0) {
} else if ((0, _underscore.indexOf)(types, 'text/json') >= 0) {
var json = dataTransfer.getData('text/json');
json && (content = JSON.parse(json));
}
@ -44969,7 +44998,7 @@ module.exports = Backbone.View.extend({
var colorWarn = '#ffca6f';
var baseCss = '\n * {\n box-sizing: border-box;\n }\n html, body, #wrapper {\n min-height: 100%;\n }\n body {\n margin: 0;\n height: 100%;\n background-color: #fff\n }\n #wrapper {\n overflow: auto;\n overflow-x: hidden;\n }\n ';
// I need all this styles to make the editor work properly
// Remove `html { height: 100%;}` from the baseCss as it gives jumpings
// effects (on ENTER) with RTE like CKEditor (maybe some bug there?!?)
// With `body {height: auto;}` jumps in CKEditor are removed but in
@ -44977,9 +45006,7 @@ module.exports = Backbone.View.extend({
// `body {height: 100%;}`.
// For the moment I give the priority to Firefox as it might be
// CKEditor's issue
// I need all this styles to make the editor work properly
var frameCss = '\n ' + baseCss + '\n\n .' + ppfx + 'dashed *[data-highlightable] {\n outline: 1px dashed rgba(170,170,170,0.7);\n outline-offset: -2px;\n }\n\n .' + ppfx + 'comp-selected {\n outline: 3px solid #3b97e3 !important;\n outline-offset: -3px;\n }\n\n .' + ppfx + 'comp-selected-parent {\n outline: 2px solid ' + colorWarn + ' !important\n }\n\n .' + ppfx + 'no-select {\n user-select: none;\n -webkit-user-select:none;\n -moz-user-select: none;\n }\n\n .' + ppfx + 'freezed {\n opacity: 0.5;\n pointer-events: none;\n }\n\n .' + ppfx + 'no-pointer {\n pointer-events: none;\n }\n\n .' + ppfx + 'plh-image {\n background: #f5f5f5;\n border: none;\n height: 50px;\n width: 50px;\n display: block;\n outline: 3px solid #ffca6f;\n cursor: pointer;\n outline-offset: -2px\n }\n\n .' + ppfx + 'grabbing {\n cursor: grabbing;\n cursor: -webkit-grabbing;\n }\n\n * ::-webkit-scrollbar-track {\n background: rgba(0, 0, 0, 0.1)\n }\n\n * ::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.2)\n }\n\n * ::-webkit-scrollbar {\n width: 10px\n }\n\n ' + (conf.canvasCss || '') + '\n ' + (protCss || '') + '\n ';
var frameCss = '\n ' + (em.config.baseCss || '') + '\n\n .' + ppfx + 'dashed *[data-highlightable] {\n outline: 1px dashed rgba(170,170,170,0.7);\n outline-offset: -2px;\n }\n\n .' + ppfx + 'comp-selected {\n outline: 3px solid #3b97e3 !important;\n outline-offset: -3px;\n }\n\n .' + ppfx + 'comp-selected-parent {\n outline: 2px solid ' + colorWarn + ' !important\n }\n\n .' + ppfx + 'no-select {\n user-select: none;\n -webkit-user-select:none;\n -moz-user-select: none;\n }\n\n .' + ppfx + 'freezed {\n opacity: 0.5;\n pointer-events: none;\n }\n\n .' + ppfx + 'no-pointer {\n pointer-events: none;\n }\n\n .' + ppfx + 'plh-image {\n background: #f5f5f5;\n border: none;\n height: 50px;\n width: 50px;\n display: block;\n outline: 3px solid #ffca6f;\n cursor: pointer;\n outline-offset: -2px\n }\n\n .' + ppfx + 'grabbing {\n cursor: grabbing;\n cursor: -webkit-grabbing;\n }\n\n ' + (conf.canvasCss || '') + '\n ' + (protCss || '') + '\n ';
if (externalStyles) {
body.append(externalStyles);
@ -45002,7 +45029,13 @@ module.exports = Backbone.View.extend({
// property keymaster (and many others) still use it... using `defineProperty`
// hack seems the only way
var createCustomEvent = function createCustomEvent(e, cls) {
var oEvent = new window[cls](e.type, e);
var oEvent = void 0;
try {
oEvent = new window[cls](e.type, e);
} catch (e) {
oEvent = document.createEvent(cls);
oEvent.initEvent(e.type, true, true);
}
oEvent.keyCodeVal = e.keyCode;
['keyCode', 'which'].forEach(function (prop) {
Object.defineProperty(oEvent, prop, {
@ -45129,7 +45162,7 @@ module.exports = Backbone.View.extend({
updateScript: function updateScript(view) {
if (!view.scriptContainer) {
view.scriptContainer = $('<div>');
this.getJsContainer().append(view.scriptContainer.get(0));
this.getJsContainer().appendChild(view.scriptContainer.get(0));
}
var model = view.model;
@ -45281,6 +45314,7 @@ module.exports = function () {
}
delete obj.initialize;
obj.id = id;
commands[id] = AbsCommands.extend(obj);
return this;
};
@ -45337,15 +45371,7 @@ module.exports = function () {
defaultCommands['tlb-delete'] = {
run: function run(ed) {
var sel = ed.getSelected();
if (!sel || !sel.get('removable')) {
console.warn('The element is not removable');
return;
}
ed.select(null);
sel.destroy();
return ed.runCommand('core:component-delete');
}
};
@ -45373,7 +45399,7 @@ module.exports = function () {
var event = opts && opts.event;
var sel = ed.getSelected();
var toolbarStyle = ed.Canvas.getToolbarEl().style;
var nativeDrag = event.type == 'dragstart';
var nativeDrag = event && event.type == 'dragstart';
var hideTlb = function hideTlb() {
toolbarStyle.display = 'none';
@ -45466,6 +45492,20 @@ module.exports = function () {
coll.add(clp.clone(), { at: at });
}
};
defaultCommands['core:component-delete'] = function (ed, sender) {
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var component = opts.component || ed.getSelected();
if (!component || !component.get('removable')) {
console.warn('The element is not removable');
return;
}
ed.select(null);
component.destroy();
return component;
};
if (c.em) c.model = c.em.get('Canvas');
@ -45716,6 +45756,44 @@ module.exports = Backbone.View.extend({
init: function init(o) {},
/**
* Method that run command
* @param {Object} editor Editor instance
* @param {Object} [options={}] Options
* @private
* */
callRun: function callRun(editor) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var id = this.id;
editor.trigger('run:' + id + ':before', options);
if (options && options.abort) {
editor.trigger('abort:' + id, options);
return;
}
var result = this.run(editor, editor, options);
editor.trigger('run:' + id, result, options);
},
/**
* Method that run command
* @param {Object} editor Editor instance
* @param {Object} [options={}] Options
* @private
* */
callStop: function callStop(editor) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var id = this.id;
editor.trigger('stop:' + id + ':before', options);
var result = this.stop(editor, editor, options);
editor.trigger('stop:' + id, result, options);
},
/**
* Method that run command
* @param {Object} em Editor model
@ -47128,16 +47206,13 @@ module.exports = function () {
"use strict";
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
module.exports = _defineProperty({
module.exports = {
// Specify the element to use as a container, string (query) or HTMLElement
// With the empty value, nothing will be rendered
appendTo: '',
blocks: []
}, 'appendTo', '');
};
/***/ }),
/* 211 */
@ -47446,7 +47521,8 @@ module.exports = Backbone.View.extend({
// Note: data are not available on dragenter for security reason,
// but will use dragContent as I need it for the Sorter context
ev.dataTransfer.setData(type, data);
// IE11 supports only 'text' data type
ev.dataTransfer.setData('text', data);
this.em.set('dragContent', content);
},
handleDragEnd: function handleDragEnd() {

6
dist/grapes.min.js

File diff suppressed because one or more lines are too long

2
package-lock.json

@ -1,6 +1,6 @@
{
"name": "grapesjs",
"version": "0.14.6",
"version": "0.14.8",
"lockfileVersion": 1,
"requires": true,
"dependencies": {

2
package.json

@ -1,7 +1,7 @@
{
"name": "grapesjs",
"description": "Free and Open Source Web Builder Framework",
"version": "0.14.6",
"version": "0.14.8",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",

2
src/canvas/view/CanvasView.js

@ -303,7 +303,7 @@ module.exports = Backbone.View.extend({
updateScript(view) {
if (!view.scriptContainer) {
view.scriptContainer = $('<div>');
this.getJsContainer().append(view.scriptContainer.get(0));
this.getJsContainer().appendChild(view.scriptContainer.get(0));
}
const model = view.model;

23
src/commands/index.js

@ -55,6 +55,7 @@ module.exports = () => {
}
delete obj.initialize;
obj.id = id;
commands[id] = AbsCommands.extend(obj);
return this;
};
@ -111,15 +112,7 @@ module.exports = () => {
defaultCommands['tlb-delete'] = {
run(ed) {
var sel = ed.getSelected();
if (!sel || !sel.get('removable')) {
console.warn('The element is not removable');
return;
}
ed.select(null);
sel.destroy();
return ed.runCommand('core:component-delete');
}
};
@ -234,6 +227,18 @@ module.exports = () => {
coll.add(clp.clone(), { at });
}
};
defaultCommands['core:component-delete'] = (ed, sender, opts = {}) => {
let component = opts.component || ed.getSelected();
if (!component || !component.get('removable')) {
console.warn('The element is not removable');
return;
}
ed.select(null);
component.destroy();
return component;
};
if (c.em) c.model = c.em.get('Canvas');

32
src/commands/view/CommandAbstract.js

@ -90,6 +90,38 @@ module.exports = Backbone.View.extend({
* */
init(o) {},
/**
* Method that run command
* @param {Object} editor Editor instance
* @param {Object} [options={}] Options
* @private
* */
callRun(editor, options = {}) {
const id = this.id;
editor.trigger(`run:${id}:before`, options);
if (options && options.abort) {
editor.trigger(`abort:${id}`, options);
return;
}
const result = this.run(editor, editor, options);
editor.trigger(`run:${id}`, result, options);
},
/**
* Method that run command
* @param {Object} editor Editor instance
* @param {Object} [options={}] Options
* @private
* */
callStop(editor, options = {}) {
const id = this.id;
editor.trigger(`stop:${id}:before`, options);
const result = this.stop(editor, editor, options);
editor.trigger(`stop:${id}`, result, options);
},
/**
* Method that run command
* @param {Object} em Editor model

8
src/commands/view/SelectComponent.js

@ -70,13 +70,7 @@ module.exports = {
if (key == 8 || key == 46) {
if (!focused) e.preventDefault();
if (comp && !focused) {
if (!comp.get('removable')) return;
comp.set('status', '');
comp.destroy();
this.hideBadge();
this.clean();
this.hideHighlighter();
this.editorModel.set('selectedComponent', null);
this.editor.runCommand('core:component-delete');
}
}
},

9
src/css_composer/index.js

@ -15,6 +15,7 @@
* rules: '.myClass{ color: red}',
* }
*/
import { isArray } from 'underscore';
module.exports = () => {
let em;
@ -135,7 +136,9 @@ module.exports = () => {
obj = c.em.get('Parser').parseCss(d.css);
}
if (obj) {
if (isArray(obj)) {
obj.length && rules.reset(obj);
} else if (obj) {
rules.reset(obj);
}
@ -174,10 +177,10 @@ module.exports = () => {
* color: '#fff',
* });
* */
add(selectors, state, width, opts) {
add(selectors, state, width, opts = {}) {
var s = state || '';
var w = width || '';
var opt = opts || {};
var opt = { ...opts };
var rule = this.get(selectors, s, w, opt);
if (rule) return rule;
else {

10
src/dom_components/model/Component.js

@ -186,8 +186,12 @@ const Component = Backbone.Model.extend(Styleable).extend(
this.initComponents();
this.initToolbar();
this.set('status', '');
this.listenTo(this.get('classes'), 'add remove change', () =>
this.emitUpdate('classes')
// Register global updates for collection properties
['classes', 'traits'].forEach(name =>
this.listenTo(this.get(name), 'add remove change', () =>
this.emitUpdate(name)
)
);
this.init();
},
@ -714,11 +718,9 @@ const Component = Backbone.Model.extend(Styleable).extend(
*/
toJSON(...args) {
const obj = Backbone.Model.prototype.toJSON.apply(this, args);
const scriptStr = this.getScriptString();
obj.attributes = this.getAttributes();
delete obj.attributes.class;
delete obj.toolbar;
scriptStr && (obj.script = scriptStr);
return obj;
},

14
src/dom_components/model/ComponentVideo.js

@ -210,8 +210,7 @@ module.exports = Component.extend(
changeProp: 1
},
this.getAutoplayTrait(),
this.getLoopTrait(),
this.getControlsTrait()
this.getLoopTrait()
];
},
@ -263,11 +262,14 @@ module.exports = Component.extend(
* @private
*/
getYoutubeSrc() {
var url = this.get('ytUrl');
url += this.get('videoId') + '?';
const id = this.get('videoId');
let url = this.get('ytUrl');
url += id + '?';
url += this.get('autoplay') ? '&autoplay=1' : '';
url += !this.get('controls') ? '&controls=0' : '';
url += this.get('loop') ? '&loop=1' : '';
url += !this.get('controls') ? '&controls=0&showinfo=0' : '';
// Loop works only with playlist enabled
// https://stackoverflow.com/questions/25779966/youtube-iframe-loop-doesnt-work
url += this.get('loop') ? `&loop=1&playlist=${id}` : '';
return url;
},

5
src/dom_components/view/ComponentView.js

@ -1,4 +1,4 @@
import { isArray } from 'underscore';
import { isArray, isEmpty } from 'underscore';
const ComponentsView = require('./ComponentsView');
@ -151,7 +151,8 @@ module.exports = Backbone.View.extend({
if (em && em.get('avoidInlineStyle')) {
this.el.id = model.getId();
model.setStyle(model.getStyle());
const style = model.getStyle();
!isEmpty(style) && model.setStyle(style);
} else {
this.setAttribute('style', model.styleToString());
}

25
src/editor/index.js

@ -58,6 +58,9 @@
* ## Commands
* * `run:{commandName}` - Triggered when some command is called to run (eg. editor.runCommand('preview'))
* * `stop:{commandName}` - Triggered when some command is called to stop (eg. editor.stopCommand('preview'))
* * `run:{commandName}:before` - Triggered before the command is called
* * `stop:{commandName}:before` - Triggered before the command is called to stop
* * `abort:{commandName}` - Triggered when the command execution is aborted (`editor.on(`run:preview:before`, opts => opts.abort = 1);`)
* ## General
* * `canvasScroll` - Triggered when the canvas is scrolle
* * `undo` - Undo executed
@ -426,14 +429,11 @@ module.exports = config => {
* @example
* editor.runCommand('myCommand', {someValue: 1});
*/
runCommand(id, options) {
var result;
var command = em.get('Commands').get(id);
runCommand(id, options = {}) {
let result;
const command = em.get('Commands').get(id);
if (command) result = command.callRun(this, options);
if (command) {
result = command.run(this, this, options);
this.trigger('run:' + id);
}
return result;
},
@ -445,14 +445,11 @@ module.exports = config => {
* @example
* editor.stopCommand('myCommand', {someValue: 1});
*/
stopCommand(id, options) {
var result;
var command = em.get('Commands').get(id);
stopCommand(id, options = {}) {
let result;
const command = em.get('Commands').get(id);
if (command) result = command.callStop(this, options);
if (command) {
result = command.stop(this, this, options);
this.trigger('stop:' + id);
}
return result;
},

6
src/editor/model/Editor.js

@ -93,7 +93,7 @@ module.exports = Backbone.Model.extend({
clb && clb();
};
if (sm && sm.getConfig().autoload) {
if (sm && sm.canAutoload()) {
this.load(postLoad);
} else {
postLoad();
@ -346,7 +346,7 @@ module.exports = Backbone.Model.extend({
for (var el in obj) store[el] = obj[el];
});
sm.store(store, (res) => {
sm.store(store, res => {
clb && clb(res);
this.set('changesCount', 0);
this.trigger('storage:store', store);
@ -394,7 +394,7 @@ module.exports = Backbone.Model.extend({
sm.load(load, res => {
this.cacheLoad = res;
clb && clb(res);
this.trigger('storage:load', res);
setTimeout(() => this.trigger('storage:load', res), 0);
});
},

25
src/storage_manager/index.js

@ -54,6 +54,14 @@ module.exports = () => {
return this;
},
/**
* Get configuration object
* @return {Object}
* */
getConfig() {
return c;
},
/**
* Checks if autosave is enabled
* @return {Boolean}
@ -220,12 +228,21 @@ module.exports = () => {
},
/**
* Get configuration object
* @return {Object}
* Get current storage
* @return {Storage}
* */
getCurrentStorage() {
return this.get(this.getCurrent());
},
/**
* Check if autoload is possible
* @return {Boolean}
* @private
* */
getConfig() {
return c;
canAutoload() {
const storage = this.getCurrentStorage();
return storage && this.getConfig().autoload;
}
};
};

6
src/style_manager/view/PropertyView.js

@ -123,7 +123,11 @@ module.exports = Backbone.View.extend({
* @return {HTMLElement}
*/
getClearEl() {
return this.el.querySelector(`[${clearProp}]`);
if (!this.clearEl) {
this.clearEl = this.el.querySelector(`[${clearProp}]`);
}
return this.clearEl;
},
/**

4
src/styles/scss/_gjs_variables.scss

@ -73,6 +73,6 @@ $animSpeed: 0.2s !default;
$mainFont: Helvetica, sans-serif !default;
$fontPath: '../fonts' !default;
$fontName: 'main-fonts' !default;
$fontSize: 0.7rem;
$fontSizeS: 0.75rem;
$fontSize: 0.7rem !default;
$fontSizeS: 0.75rem !default;
$fontV: 20 !default;//random(1000)

9
src/trait_manager/model/Traits.js

@ -8,6 +8,15 @@ module.exports = Backbone.Collection.extend({
initialize(coll, options = {}) {
this.em = options.em || '';
this.listenTo(this, 'add', this.handleAdd);
},
handleAdd(model) {
const target = this.target;
if (target) {
model.target = target;
}
},
setTarget(target) {

6
src/trait_manager/view/TraitsView.js

@ -23,7 +23,8 @@ module.exports = DomainViews.extend({
this.pfx = config.stylePrefix || '';
this.ppfx = config.pStylePrefix || '';
this.className = this.pfx + 'traits';
this.listenTo(this.em, 'change:selectedComponent', this.updatedCollection);
const toListen = 'component:selected component:update:traits';
this.listenTo(this.em, toListen, this.updatedCollection);
this.updatedCollection();
},
@ -33,8 +34,9 @@ module.exports = DomainViews.extend({
*/
updatedCollection() {
const ppfx = this.ppfx;
const comp = this.em.getSelected();
this.el.className = `${this.className} ${ppfx}one-bg ${ppfx}two-color`;
var comp = this.em.get('selectedComponent');
if (comp) {
this.collection = comp.get('traits');
this.render();

35
src/utils/extender.js

@ -1,4 +1,4 @@
import { isObject } from 'underscore';
import { isObject, isString, each, isUndefined } from 'underscore';
module.exports = ({ $, Backbone }) => {
if (Backbone) {
@ -177,11 +177,36 @@ module.exports = ({ $, Backbone }) => {
return this;
};
(fn.remove = function() {
return this.each(node => {
return node.parentNode && node.parentNode.removeChild(node);
});
// For SVGs in IE
(fn.removeClass = function(c) {
if (!arguments.length) {
return this.attr('class', '');
}
const classes = isString(c) && c.match(/\S+/g);
return classes
? this.each(function(el) {
each(classes, function(c) {
if (el.classList) {
el.classList.remove(c);
} else {
const val = el.className;
const bval = el.className.baseVal;
if (!isUndefined(bval)) {
val.baseVal = bval.replace(c, '');
} else {
el.className = val.replace(c, '');
}
}
});
})
: this;
}),
(fn.remove = function() {
return this.each(node => {
return node.parentNode && node.parentNode.removeChild(node);
});
}),
// For spectrum compatibility
(fn.bind = function(ev, h) {
return this.on(ev, h);

119
test/specs/grapesjs/index.js

@ -28,6 +28,7 @@ describe('GrapesJS', () => {
});
beforeEach(() => {
storage = {};
htmlString = '<div class="test1"></div><div class="test2"></div>';
cssString = '.test2{color:red}.test3{color:blue}';
documentEl = '<style>' + cssString + '</style>' + htmlString;
@ -36,15 +37,22 @@ describe('GrapesJS', () => {
storageManager: {
autoload: 0,
autosave: 0,
type: ''
type: 0
}
};
obj = grapesjs;
//fixture = $('<div id="' + editorName + '"></div>');
//fixture.empty().appendTo(fixtures);
document.body.innerHTML = `<div id="fixtures"><div id="${editorName}"></div></div>`;
fixtures = document.body.querySelector('#fixtures');
fixture = document.body.querySelector(`#${editorName}`);
});
afterEach(() => {
var plugins = obj.plugins.getAll();
for (let id in plugins) {
if (plugins.hasOwnProperty(id)) {
delete plugins[id];
}
}
});
it('Main object should be loaded', () => {
@ -133,25 +141,19 @@ describe('GrapesJS', () => {
).toEqual('test2');
});
it.skip('Init editor from element', () => {
it('Init editor from element', () => {
config.fromElement = 1;
fixtures.innerHTML = documentEl;
var editor = obj.init(config);
var html = editor.getHtml();
var css = editor.getCss();
var protCss = editor.getConfig().protectedCss;
/*
(html ? html : '').should.equal(htmlString);
(css ? css : '').should.equal(protCss + '.test2{color:red;}');// .test3 is discarded in css
editor.getComponents().length.should.equal(2);
editor.getStyle().length.should.equal(2);
*/
expect(html ? html : '').toEqual(htmlString);
config.storageManager = { type: 0 };
fixture.innerHTML = documentEl;
const editor = obj.init(config);
const html = editor.getHtml();
const css = editor.getCss();
const protCss = editor.getConfig().protectedCss;
expect(html).toEqual(htmlString);
expect(editor.getComponents().length).toEqual(2);
// .test3 is discarded in css
expect(css ? css : '').toEqual(protCss + '.test2{color:red;}');
// bust is still here
// .test3 is discarded in CSS
expect(css).toEqual(`${protCss}.test2{color:red;}`);
// but it's still there
expect(editor.getStyle().length).toEqual(2);
});
@ -197,13 +199,13 @@ describe('GrapesJS', () => {
});
it.skip('Adds new storage as plugin and store data there', done => {
var pluginName = storageId + '-plugin';
obj.plugins.add(pluginName, edt => {
edt.StorageManager.add(storageId, storageMock);
});
const pluginName = storageId + '-p2';
obj.plugins.add(pluginName, e =>
e.StorageManager.add(storageId, storageMock)
);
config.storageManager.type = storageId;
config.plugins = [pluginName];
var editor = obj.init(config);
const editor = obj.init(config);
editor.setComponents(htmlString);
editor.store(() => {
editor.load(data => {
@ -213,6 +215,45 @@ describe('GrapesJS', () => {
});
});
it('Adds a new storage and fetch correctly data from it', done => {
fixture.innerHTML = documentEl;
const styleResult = { color: 'white', display: 'block' };
const style = [
{
selectors: [{ name: 'sclass1' }],
style: { color: 'green' }
},
{
selectors: [{ name: 'test2' }],
style: styleResult
},
{
selectors: [{ name: 'test3' }],
style: { color: 'black', display: 'block' }
}
];
storage = {
css: '* { box-sizing: border-box; } body {margin: 0;}',
styles: JSON.stringify(style)
};
const pluginName = storageId + '-p';
obj.plugins.add(pluginName, e =>
e.StorageManager.add(storageId, storageMock)
);
config.fromElement = 1;
config.storageManager.type = storageId;
config.plugins = [pluginName];
config.storageManager.autoload = 1;
const editor = obj.init(config);
editor.on('load', () => {
const cc = editor.CssComposer;
expect(cc.getAll().length).toEqual(style.length);
// expect(cc.setClassRule('test2').getStyle()).toEqual(styleResult);
done();
});
});
it('Execute plugins with custom options', () => {
var pluginName = storageId + '-plugin-opts';
obj.plugins.add(pluginName, (edt, opts) => {
@ -252,6 +293,32 @@ describe('GrapesJS', () => {
expect(editor.testVal).toEqual(htmlString + '5');
});
it('Trigger custom command events', () => {
const id = 'test-command';
const editor = obj.init(config);
const result = {};
editor.on(`run:${id}`, () => (result.run = 1));
editor.on(`run:${id}:before`, () => (result.runBefore = 1));
editor.on(`stop:${id}`, () => (result.stop = 1));
editor.on(`stop:${id}:before`, () => (result.stopBefore = 1));
editor.on(`abort:${id}`, () => (result.abort = 1));
editor.Commands.add(id, {
run() {},
stop() {}
});
editor.runCommand(id);
editor.stopCommand(id);
editor.on(`run:${id}:before`, opts => (opts.abort = 1));
editor.runCommand(id);
expect(result).toEqual({
run: 1,
runBefore: 1,
stop: 1,
stopBefore: 1,
abort: 1
});
});
it('Set default devices', () => {
config.deviceManager = {};
config.deviceManager.devices = [

Loading…
Cancel
Save