Browse Source

Merge pull request #1076 from artf/dev

Merge dev branch
pull/1362/head
Artur Arseniev 9 years ago
committed by GitHub
parent
commit
2ad576a6cb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      .github/no-response.yml
  2. 9
      README.md
  3. 91
      dist/grapes.js
  4. 6
      dist/grapes.min.js
  5. 2
      package-lock.json
  6. 2
      package.json
  7. 2
      src/asset_manager/model/AssetImage.js
  8. 2
      src/asset_manager/view/FileUploader.js
  9. 14
      src/code_manager/model/CssGenerator.js
  10. 2
      src/commands/view/CommandAbstract.js
  11. 22
      src/commands/view/OpenAssets.js
  12. 1
      src/commands/view/Resize.js
  13. 36
      src/commands/view/SelectComponent.js
  14. 7
      src/css_composer/index.js
  15. 2
      src/dom_components/view/ComponentImageView.js
  16. 4
      src/domain_abstract/model/Styleable.js
  17. 6
      src/editor/config/config.js
  18. 1
      src/editor/index.js
  19. 17
      src/editor/model/Editor.js
  20. 2
      test/specs/commands/index.js
  21. 83
      test/specs/commands/view/CommandAbstract.js
  22. 38
      test/specs/grapesjs/index.js

13
.github/no-response.yml

@ -0,0 +1,13 @@
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 10
# Label requiring a response
responseRequiredLabel: more-information-needed
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further.

9
README.md

@ -4,6 +4,8 @@
[![Chat](https://img.shields.io/badge/chat-discord-7289da.svg)](https://discord.gg/QAbgGXq)
[![CDNJS](https://img.shields.io/cdnjs/v/grapesjs.svg)](https://cdnjs.com/libraries/grapesjs)
[![npm](https://img.shields.io/npm/v/grapesjs.svg)](https://www.npmjs.com/package/grapesjs)
[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=QksxaStYaGI3eE5VMDlPTEh0Z3hYOXEwRWNMc1ZYT0lNbEJxMWdOZWFDZz0tLWlqcFVWb05PMmlQMmU3emFIZkFNWVE9PQ==--e89345be5e303d515276e3accd6f1316dfa857ab)](https://www.browserstack.com/automate/public-build/QksxaStYaGI3eE5VMDlPTEh0Z3hYOXEwRWNMc1ZYT0lNbEJxMWdOZWFDZz0tLWlqcFVWb05PMmlQMmU3emFIZkFNWVE9PQ==--e89345be5e303d515276e3accd6f1316dfa857ab)
<p align="center"><img src="http://grapesjs.com/img/grapesjs-front-page-m.jpg" alt="GrapesJS" width="500" align="center"/></p>
@ -229,7 +231,14 @@ If you like the project support it with a donation of your choice or become a ba
<a href="https://opencollective.com/grapesjs/backers/7/website"><img src="https://opencollective.com/grapesjs/backers/7/avatar"></a>
<a href="https://opencollective.com/grapesjs/backers/8/website"><img src="https://opencollective.com/grapesjs/backers/8/avatar"></a>
<a href="https://opencollective.com/grapesjs/backers/9/website"><img src="https://opencollective.com/grapesjs/backers/9/avatar"></a>
<a href="https://opencollective.com/grapesjs/backers/10/website"><img src="https://opencollective.com/grapesjs/backers/10/avatar"></a>
<a href="https://opencollective.com/grapesjs/backers/11/website"><img src="https://opencollective.com/grapesjs/backers/11/avatar"></a>
<a href="https://opencollective.com/grapesjs/backers/12/website"><img src="https://opencollective.com/grapesjs/backers/12/avatar"></a>
<br>
[![BrowserStack](https://user-images.githubusercontent.com/11614725/39406324-4ef89c40-4bb5-11e8-809a-113d9432e5a5.png)](https://www.browserstack.com)<br/>
Thanks to [BrowserStack](https://www.browserstack.com) for providing us browser testing services
## License

91
dist/grapes.js

@ -16899,6 +16899,8 @@ module.exports = ComponentView.extend({
if (editor && this.model.get('editable')) {
editor.runCommand('open-assets', {
target: this.model,
types: ['image'],
accept: 'image/*',
onSelect: function onSelect() {
editor.Modal.close();
editor.AssetManager.setTarget(null);
@ -17742,6 +17744,7 @@ module.exports = {
if (model) {
if (model.get('selectable')) {
editor.select(model);
this.initResize(model);
} else {
var parent = model.parent();
while (parent && !parent.get('selectable')) {
@ -17817,7 +17820,8 @@ module.exports = {
* @private
* */
onSelect: function onSelect() {
var editor = this.editor;
// Get the selected model directly from the Editor as the event might
// be triggered manually without the model
var model = this.em.getSelected();
this.updateToolbar(model);
@ -17828,27 +17832,28 @@ module.exports = {
this.hideHighlighter();
this.initResize(el);
} else {
editor.stopCommand('resize');
this.editor.stopCommand('resize');
}
},
/**
* Init resizer on the element if possible
* @param {HTMLElement} el
* @param {HTMLElement|Component} elem
* @private
*/
initResize: function initResize(el) {
initResize: function initResize(elem) {
var em = this.em;
var editor = em ? em.get('Editor') : '';
var config = em ? em.get('Config') : '';
var pfx = config.stylePrefix || '';
var attrName = 'data-' + pfx + 'handler';
var resizeClass = pfx + 'resizing';
var model = em.get('selectedComponent');
var model = !(0, _underscore.isElement)(elem) ? elem : em.getSelected();
var resizable = model.get('resizable');
var el = (0, _underscore.isElement)(elem) ? elem : model.getEl();
var options = {};
var modelToStyle;
var modelToStyle = void 0;
var toggleBodyClass = function toggleBodyClass(method, e, opts) {
var docs = opts.docs;
@ -17935,11 +17940,12 @@ module.exports = {
if ((typeof resizable === 'undefined' ? 'undefined' : _typeof(resizable)) == 'object') {
options = _extends({}, options, resizable);
}
editor.runCommand('resize', { el: el, options: options });
// On undo/redo the resizer rect is not updating, need somehow to call
// this.updateRect on undo/redo action
} else {
editor.stopCommand('resize');
}
},
@ -18793,7 +18799,6 @@ module.exports = function (config) {
* @return {Array<Object>}
*/
parseNode: function parseNode(el) {
var config = c.em && c.em.get('Config') || {};
var result = [];
var nodes = el.childNodes;
@ -21637,7 +21642,7 @@ var _fetch2 = _interopRequireDefault(_fetch);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
module.exports = Backbone.View.extend({
template: _.template('\n <form>\n <div id="<%= pfx %>title"><%= title %></div>\n <input type="file" id="<%= uploadId %>" name="file" accept="image/*" <%= disabled ? \'disabled\' : \'\' %> multiple/>\n <div style="clear:both;"></div>\n </form>\n '),
template: _.template('\n <form>\n <div id="<%= pfx %>title"><%= title %></div>\n <input type="file" id="<%= uploadId %>" name="file" accept="*/*" <%= disabled ? \'disabled\' : \'\' %> multiple/>\n <div style="clear:both;"></div>\n </form>\n '),
events: {},
@ -22262,8 +22267,8 @@ exports.default = {
var em = _this.em;
_this.trigger('change:style:' + pr);
if (em) {
em.trigger('styleable:change');
em.trigger('styleable:change:' + pr);
em.trigger('styleable:change', _this, pr);
em.trigger('styleable:change:' + pr, _this, pr);
}
});
@ -23640,7 +23645,7 @@ module.exports = function () {
plugins: plugins,
// Will be replaced on build
version: '0.14.9',
version: '0.14.10',
/**
* Initializes an editor based on passed options
@ -24251,6 +24256,7 @@ module.exports = function (config) {
* * `component:styleUpdate` - Triggered when the style of the component is updated, the model is passed as an argument to the callback
* * `component:styleUpdate:{propertyName}` - Listen for a specific style property change, the model is passed as an argument to the callback
* * `component:selected` - New component selected, the selected model is passed as an argument to the callback
* * `component:deselected` - Component deselected, the deselected model is passed as an argument to the callback
* ## Blocks
* * `block:add` - New block added
* * `block:remove` - Block removed
@ -24544,8 +24550,10 @@ module.exports = {
traitManager: {},
// Texts
textViewCode: 'Code',
textViewCode: 'Code'
// Keep unused styles within the editor
keepUnusedStyles: 0
};
/***/ }),
@ -24759,13 +24767,10 @@ module.exports = Backbone.Model.extend({
* @param {Object} Options
* @private
* */
componentSelected: function componentSelected(model, val, options) {
if (!this.get('selectedComponent')) {
this.trigger('deselect-comp');
} else {
this.trigger('select-comp', [model, val, options]);
this.trigger('component:selected', arguments);
}
componentSelected: function componentSelected(editor, selected, options) {
var prev = this.previous('selectedComponent');
prev && this.trigger('component:deselected', prev, options);
selected && this.trigger('component:selected', selected, options);
},
@ -24880,13 +24885,15 @@ module.exports = Backbone.Model.extend({
var config = this.config;
var wrappesIsBody = config.wrappesIsBody;
var avoidProt = opts.avoidProtected;
var keepUnusedStyles = !(0, _underscore.isUndefined)(opts.keepUnusedStyles) ? opts.keepUnusedStyles : config.keepUnusedStyles;
var cssc = this.get('CssComposer');
var wrp = this.get('DomComponents').getComponent();
var protCss = !avoidProt ? config.protectedCss : '';
return protCss + this.get('CodeManager').getCode(wrp, 'css', {
cssc: cssc,
wrappesIsBody: wrappesIsBody
wrappesIsBody: wrappesIsBody,
keepUnusedStyles: keepUnusedStyles
});
},
@ -33480,7 +33487,7 @@ module.exports = __webpack_require__(0).Model.extend({
return;
}
code += _this2.buildFromRule(rule, dump);
code += _this2.buildFromRule(rule, dump, opts);
});
// Get at-rules
@ -33488,7 +33495,7 @@ module.exports = __webpack_require__(0).Model.extend({
var rulesStr = '';
var mRules = atRules[atRule];
mRules.forEach(function (rule) {
return rulesStr += _this2.buildFromRule(rule, dump);
return rulesStr += _this2.buildFromRule(rule, dump, opts);
});
if (rulesStr) {
@ -33512,6 +33519,8 @@ module.exports = __webpack_require__(0).Model.extend({
buildFromRule: function buildFromRule(rule, dump) {
var _this3 = this;
var opts = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
var result = '';
var selectorStrNoAdd = rule.selectorsToString({ skipAdd: 1 });
var selectorsAdd = rule.get('selectorsAdd');
@ -33521,7 +33530,7 @@ module.exports = __webpack_require__(0).Model.extend({
// This will not render a rule if there is no its component
rule.get('selectors').each(function (selector) {
var name = selector.getFullName();
if (_this3.compCls.indexOf(name) >= 0 || _this3.ids.indexOf(name) >= 0) {
if (_this3.compCls.indexOf(name) >= 0 || _this3.ids.indexOf(name) >= 0 || opts.keepUnusedStyles) {
found = 1;
}
});
@ -41247,10 +41256,12 @@ module.exports = function () {
var ev = 'add remove';
var rules = this.getAll();
var um = em.get('UndoManager');
um && um.add(rules);
em.stopListening(rules, ev, this.handleChange);
em.listenTo(rules, ev, this.handleChange);
rules.each(function (rule) {
return _this.handleChange(rule);
return _this.handleChange(rule, { avoidStore: 1 });
});
},
@ -41260,12 +41271,15 @@ module.exports = function () {
* @private
*/
handleChange: function handleChange(model) {
var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
var ev = 'change:style';
var um = em.get('UndoManager');
um && um.add(model);
var handleUpdates = em.handleUpdates.bind(em);
em.stopListening(model, ev, handleUpdates);
em.listenTo(model, ev, handleUpdates);
!opts.avoidStore && handleUpdates('', '', opts);
},
@ -45702,6 +45716,7 @@ module.exports = Backbone.View.extend({
var result = this.run(editor, editor, options);
editor.trigger('run:' + id, result, options);
return result;
},
@ -45718,6 +45733,7 @@ module.exports = Backbone.View.extend({
editor.trigger('stop:' + id + ':before', options);
var result = this.stop(editor, editor, options);
editor.trigger('stop:' + id, result, options);
return result;
},
@ -46458,22 +46474,36 @@ module.exports = {
var modal = editor.Modal;
var am = editor.AssetManager;
var config = am.getConfig();
var amContainer = am.getContainer();
var title = opts.modalTitle || config.modalTitle || '';
var types = opts.types;
var accept = opts.accept;
am.setTarget(opts.target);
am.onClick(opts.onClick);
am.onDblClick(opts.onDblClick);
am.onSelect(opts.onSelect);
if (!this.rendered) {
am.render(am.getAll().filter(function (asset) {
return asset.get('type') == 'image';
}));
if (!this.rendered || types) {
var assets = am.getAll();
if (types) {
assets = assets.filter(function (a) {
return types.indexOf(a.get('type')) !== -1;
});
}
am.render(assets);
this.rendered = 1;
}
if (accept) {
var uploadEl = amContainer.querySelector('input#' + config.stylePrefix + 'uploadFile');
uploadEl && uploadEl.setAttribute('accept', accept);
}
modal.setTitle(title);
modal.setContent(am.getContainer());
modal.setContent(amContainer);
modal.open();
}
};
@ -46824,6 +46854,7 @@ module.exports = {
}
canvasResizer.setOptions(options);
canvasResizer.blur();
canvasResizer.focus(el);
return canvasResizer;
},

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.9",
"version": "0.14.10",
"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.9",
"version": "0.14.10",
"author": "Artur Arseniev",
"license": "BSD-3-Clause",
"homepage": "http://grapesjs.com",

2
src/asset_manager/model/AssetImage.js

@ -7,5 +7,5 @@ module.exports = Asset.extend({
unitDim: 'px',
height: 0,
width: 0
}
},
});

2
src/asset_manager/view/FileUploader.js

@ -5,7 +5,7 @@ module.exports = Backbone.View.extend(
template: _.template(`
<form>
<div id="<%= pfx %>title"><%= title %></div>
<input type="file" id="<%= uploadId %>" name="file" accept="image/*" <%= disabled ? 'disabled' : '' %> multiple/>
<input type="file" id="<%= uploadId %>" name="file" accept="*/*" <%= disabled ? 'disabled' : '' %> multiple/>
<div style="clear:both;"></div>
</form>
`),

14
src/code_manager/model/CssGenerator.js

@ -59,14 +59,16 @@ module.exports = require('backbone').Model.extend({
return;
}
code += this.buildFromRule(rule, dump);
code += this.buildFromRule(rule, dump, opts);
});
// Get at-rules
for (let atRule in atRules) {
let rulesStr = '';
const mRules = atRules[atRule];
mRules.forEach(rule => (rulesStr += this.buildFromRule(rule, dump)));
mRules.forEach(
rule => (rulesStr += this.buildFromRule(rule, dump, opts))
);
if (rulesStr) {
code += `${atRule}{${rulesStr}}`;
@ -84,7 +86,7 @@ module.exports = require('backbone').Model.extend({
* @param {Model} rule
* @return {string} CSS string
*/
buildFromRule(rule, dump) {
buildFromRule(rule, dump, opts = {}) {
let result = '';
const selectorStrNoAdd = rule.selectorsToString({ skipAdd: 1 });
const selectorsAdd = rule.get('selectorsAdd');
@ -94,7 +96,11 @@ module.exports = require('backbone').Model.extend({
// This will not render a rule if there is no its component
rule.get('selectors').each(selector => {
const name = selector.getFullName();
if (this.compCls.indexOf(name) >= 0 || this.ids.indexOf(name) >= 0) {
if (
this.compCls.indexOf(name) >= 0 ||
this.ids.indexOf(name) >= 0 ||
opts.keepUnusedStyles
) {
found = 1;
}
});

2
src/commands/view/CommandAbstract.js

@ -107,6 +107,7 @@ module.exports = Backbone.View.extend({
const result = this.run(editor, editor, options);
editor.trigger(`run:${id}`, result, options);
return result;
},
/**
@ -120,6 +121,7 @@ module.exports = Backbone.View.extend({
editor.trigger(`stop:${id}:before`, options);
const result = this.stop(editor, editor, options);
editor.trigger(`stop:${id}`, result, options);
return result;
},
/**

22
src/commands/view/OpenAssets.js

@ -3,20 +3,36 @@ module.exports = {
const modal = editor.Modal;
const am = editor.AssetManager;
const config = am.getConfig();
const amContainer = am.getContainer();
const title = opts.modalTitle || config.modalTitle || '';
const types = opts.types;
const accept = opts.accept;
am.setTarget(opts.target);
am.onClick(opts.onClick);
am.onDblClick(opts.onDblClick);
am.onSelect(opts.onSelect);
if (!this.rendered) {
am.render(am.getAll().filter(asset => asset.get('type') == 'image'));
if (!this.rendered || types) {
let assets = am.getAll();
if (types) {
assets = assets.filter(a => types.indexOf(a.get('type')) !== -1);
}
am.render(assets);
this.rendered = 1;
}
if (accept) {
const uploadEl = amContainer.querySelector(
`input#${config.stylePrefix}uploadFile`
);
uploadEl && uploadEl.setAttribute('accept', accept);
}
modal.setTitle(title);
modal.setContent(am.getContainer());
modal.setContent(amContainer);
modal.open();
}
};

1
src/commands/view/Resize.js

@ -19,6 +19,7 @@ module.exports = {
}
canvasResizer.setOptions(options);
canvasResizer.blur();
canvasResizer.focus(el);
return canvasResizer;
},

36
src/commands/view/SelectComponent.js

@ -1,4 +1,4 @@
import { bindAll } from 'underscore';
import { bindAll, isElement } from 'underscore';
import { on, off, getUnitFromValue } from 'utils/mixins';
const ToolbarView = require('dom_components/view/ToolbarView');
@ -186,6 +186,7 @@ module.exports = {
if (model) {
if (model.get('selectable')) {
editor.select(model);
this.initResize(model);
} else {
let parent = model.parent();
while (parent && !parent.get('selectable')) parent = parent.parent();
@ -262,7 +263,8 @@ module.exports = {
* @private
* */
onSelect() {
const editor = this.editor;
// Get the selected model directly from the Editor as the event might
// be triggered manually without the model
const model = this.em.getSelected();
this.updateToolbar(model);
@ -273,26 +275,27 @@ module.exports = {
this.hideHighlighter();
this.initResize(el);
} else {
editor.stopCommand('resize');
this.editor.stopCommand('resize');
}
},
/**
* Init resizer on the element if possible
* @param {HTMLElement} el
* @param {HTMLElement|Component} elem
* @private
*/
initResize(el) {
var em = this.em;
var editor = em ? em.get('Editor') : '';
var config = em ? em.get('Config') : '';
var pfx = config.stylePrefix || '';
var attrName = `data-${pfx}handler`;
var resizeClass = `${pfx}resizing`;
var model = em.get('selectedComponent');
var resizable = model.get('resizable');
var options = {};
var modelToStyle;
initResize(elem) {
const em = this.em;
const editor = em ? em.get('Editor') : '';
const config = em ? em.get('Config') : '';
const pfx = config.stylePrefix || '';
const attrName = `data-${pfx}handler`;
const resizeClass = `${pfx}resizing`;
const model = !isElement(elem) ? elem : em.getSelected();
const resizable = model.get('resizable');
const el = isElement(elem) ? elem : model.getEl();
let options = {};
let modelToStyle;
var toggleBodyClass = (method, e, opts) => {
const docs = opts.docs;
@ -376,11 +379,12 @@ module.exports = {
if (typeof resizable == 'object') {
options = { ...options, ...resizable };
}
editor.runCommand('resize', { el, options });
// On undo/redo the resizer rect is not updating, need somehow to call
// this.updateRect on undo/redo action
} else {
editor.stopCommand('resize');
}
},

7
src/css_composer/index.js

@ -94,22 +94,25 @@ module.exports = () => {
postLoad(em) {
const ev = 'add remove';
const rules = this.getAll();
const um = em.get('UndoManager');
um && um.add(rules);
em.stopListening(rules, ev, this.handleChange);
em.listenTo(rules, ev, this.handleChange);
rules.each(rule => this.handleChange(rule));
rules.each(rule => this.handleChange(rule, { avoidStore: 1 }));
},
/**
* Handle rule changes
* @private
*/
handleChange(model) {
handleChange(model, opts = {}) {
const ev = 'change:style';
const um = em.get('UndoManager');
um && um.add(model);
const handleUpdates = em.handleUpdates.bind(em);
em.stopListening(model, ev, handleUpdates);
em.listenTo(model, ev, handleUpdates);
!opts.avoidStore && handleUpdates('', '', opts);
},
/**

2
src/dom_components/view/ComponentImageView.js

@ -67,6 +67,8 @@ module.exports = ComponentView.extend({
if (editor && this.model.get('editable')) {
editor.runCommand('open-assets', {
target: this.model,
types: ['image'],
accept: 'image/*',
onSelect() {
editor.Modal.close();
editor.AssetManager.setTarget(null);

4
src/domain_abstract/model/Styleable.js

@ -43,8 +43,8 @@ export default {
const em = this.em;
this.trigger(`change:style:${pr}`);
if (em) {
em.trigger(`styleable:change`);
em.trigger(`styleable:change:${pr}`);
em.trigger(`styleable:change`, this, pr);
em.trigger(`styleable:change:${pr}`, this, pr);
}
});

6
src/editor/config/config.js

@ -98,7 +98,7 @@ module.exports = {
// When false, removes empty text nodes when parsed, unless they contain a space
keepEmptyTextNodes: 0,
// Return JS of components inside HTML from 'editor.getHtml()'
jsInHtml: true,
@ -279,6 +279,8 @@ module.exports = {
traitManager: {},
// Texts
textViewCode: 'Code',
textViewCode: 'Code'
// Keep unused styles within the editor
keepUnusedStyles: 0
};

1
src/editor/index.js

@ -17,6 +17,7 @@
* * `component:styleUpdate` - Triggered when the style of the component is updated, the model is passed as an argument to the callback
* * `component:styleUpdate:{propertyName}` - Listen for a specific style property change, the model is passed as an argument to the callback
* * `component:selected` - New component selected, the selected model is passed as an argument to the callback
* * `component:deselected` - Component deselected, the deselected model is passed as an argument to the callback
* ## Blocks
* * `block:add` - New block added
* * `block:remove` - Block removed

17
src/editor/model/Editor.js

@ -197,13 +197,10 @@ module.exports = Backbone.Model.extend({
* @param {Object} Options
* @private
* */
componentSelected(model, val, options) {
if (!this.get('selectedComponent')) {
this.trigger('deselect-comp');
} else {
this.trigger('select-comp', [model, val, options]);
this.trigger('component:selected', arguments);
}
componentSelected(editor, selected, options) {
const prev = this.previous('selectedComponent');
prev && this.trigger('component:deselected', prev, options);
selected && this.trigger('component:selected', selected, options);
},
/**
@ -305,6 +302,9 @@ module.exports = Backbone.Model.extend({
const config = this.config;
const wrappesIsBody = config.wrappesIsBody;
const avoidProt = opts.avoidProtected;
const keepUnusedStyles = !isUndefined(opts.keepUnusedStyles)
? opts.keepUnusedStyles
: config.keepUnusedStyles;
const cssc = this.get('CssComposer');
const wrp = this.get('DomComponents').getComponent();
const protCss = !avoidProt ? config.protectedCss : '';
@ -313,7 +313,8 @@ module.exports = Backbone.Model.extend({
protCss +
this.get('CodeManager').getCode(wrp, 'css', {
cssc,
wrappesIsBody
wrappesIsBody,
keepUnusedStyles
})
);
},

2
test/specs/commands/index.js

@ -1,5 +1,6 @@
var Commands = require('commands');
var Models = require('./model/CommandModels');
var CommandAbstract = require('./view/CommandAbstract');
describe('Commands', () => {
describe('Main', () => {
@ -61,3 +62,4 @@ describe('Commands', () => {
});
Models.run();
CommandAbstract.run();

83
test/specs/commands/view/CommandAbstract.js

@ -0,0 +1,83 @@
const CommandAbstract = require('commands/view/CommandAbstract');
const Editor = require('editor/model/Editor');
module.exports = {
run() {
describe('CommandAbstract', () => {
let editor, editorTriggerSpy, command;
beforeEach(() => {
editor = new Editor();
editorTriggerSpy = sinon.spy(editor, 'trigger');
command = new CommandAbstract();
command.id = 'test';
});
afterEach(() => {
command = null;
editorTriggerSpy = null;
editor = null;
});
it('callRun returns result when no "abort" option specified', () => {
const runStub = sinon.stub(command, 'run').returns('result');
const result = command.callRun(editor);
expect(editorTriggerSpy.calledTwice).toEqual(true);
expect(editorTriggerSpy.getCall(0).args).toEqual([
'run:test:before',
{}
]);
expect(editorTriggerSpy.getCall(1).args).toEqual([
'run:test',
'result',
{}
]);
expect(result).toEqual('result');
expect(runStub.calledOnce).toEqual(true);
});
it('callRun returns undefined when "abort" option is specified', () => {
const runStub = sinon.stub(command, 'run').returns('result');
const result = command.callRun(editor, { abort: true });
expect(editorTriggerSpy.calledTwice).toEqual(true);
expect(editorTriggerSpy.getCall(0).args).toEqual([
'run:test:before',
{ abort: true }
]);
expect(editorTriggerSpy.getCall(1).args).toEqual([
'abort:test',
{ abort: true }
]);
expect(result).toEqual(undefined);
expect(runStub.notCalled).toEqual(true);
});
it('callStop returns result', () => {
const stopStub = sinon.stub(command, 'stop').returns('stopped');
const result = command.callStop(editor);
expect(editorTriggerSpy.calledTwice).toEqual(true);
expect(editorTriggerSpy.getCall(0).args).toEqual([
'stop:test:before',
{}
]);
expect(editorTriggerSpy.getCall(1).args).toEqual([
'stop:test',
'stopped',
{}
]);
expect(result).toEqual('stopped');
expect(stopStub.calledOnce).toEqual(true);
});
});
}
};

38
test/specs/grapesjs/index.js

@ -376,5 +376,43 @@ describe('GrapesJS', () => {
editor = obj.init(config);
expect(editor.Commands.get('export-template').test).toEqual(1);
});
it('Keep unused css classes/selectors option for getCSS method', () => {
config.fromElement = 1;
config.storageManager = { type: 0 };
fixture.innerHTML = documentEl;
const editor = obj.init(config);
const css = editor.getCss({ keepUnusedStyles: 1 });
const protCss = editor.getConfig().protectedCss;
expect(editor.getStyle().length).toEqual(2);
expect(css).toEqual(`${protCss}.test2{color:red;}.test3{color:blue;}`);
});
it('Keep unused css classes/selectors option for media rules', () => {
cssString =
'.test2{color:red}.test3{color:blue} @media only screen and (max-width: 620px) { .notused { color: red; } } ';
documentEl = '<style>' + cssString + '</style>' + htmlString;
config.fromElement = 1;
config.storageManager = { type: 0 };
fixture.innerHTML = documentEl;
const editor = obj.init(config);
const css = editor.getCss({ keepUnusedStyles: 1 });
const protCss = editor.getConfig().protectedCss;
expect(editor.getStyle().length).toEqual(3);
expect(css).toEqual(
`${protCss}.test2{color:red;}.test3{color:blue;}@media only screen and (max-width: 620px){.notused{color:red;}}`
);
});
it('Keep unused css classes/selectors option for init method', () => {
config.fromElement = 1;
config.storageManager = { type: 0 };
fixture.innerHTML = documentEl;
const editor = obj.init({ ...config, keepUnusedStyles: 1 });
const css = editor.getCss();
const protCss = editor.getConfig().protectedCss;
expect(editor.getStyle().length).toEqual(2);
expect(css).toEqual(`${protCss}.test2{color:red;}.test3{color:blue;}`);
});
});
});

Loading…
Cancel
Save