diff --git a/dist/grapes.js b/dist/grapes.js
index c7a20c683..ee13bd33c 100644
--- a/dist/grapes.js
+++ b/dist/grapes.js
@@ -22263,6 +22263,13 @@ module.exports = {
// Custom parameters to pass with the upload request, eg. csrf token
params: {},
+ // The credentials setting for the upload request, eg. 'include', 'omit'
+ credentials: 'include',
+
+ // Allow uploading multiple files per request.
+ // If disabled filename will not have '[]' appended
+ multiUpload: true,
+
// If true, tries to add automatically uploaded assets.
// To make it work the server should respond with a JSON containing assets
// in a data key, eg:
@@ -23190,7 +23197,7 @@ var _fetch2 = _interopRequireDefault(_fetch);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
module.exports = _backbone2.default.View.extend({
- template: _underscore2.default.template('\n
\n '),
+ template: _underscore2.default.template('\n \n '),
events: {},
@@ -23205,6 +23212,7 @@ module.exports = _backbone2.default.View.extend({
this.target = this.options.globalCollection || {};
this.uploadId = this.pfx + 'uploadFile';
this.disabled = c.disableUpload !== undefined ? c.disableUpload : !c.upload && !c.embedAsBase64;
+ this.multiUpload = c.multiUpload !== undefined ? c.multiUpload : true;
this.events['change #' + this.uploadId] = 'uploadFile';
var uploadFile = c.uploadFile;
@@ -23261,7 +23269,13 @@ module.exports = _backbone2.default.View.extend({
var em = this.config.em;
var config = this.config;
var target = this.target;
- var json = typeof text === 'string' ? JSON.parse(text) : text;
+ var json = void 0;
+ try {
+ json = typeof text === 'string' ? JSON.parse(text) : text;
+ } catch (e) {
+ json = text;
+ }
+
em && em.trigger('asset:upload:response', json);
if (config.autoAdd && target) {
@@ -23287,14 +23301,18 @@ module.exports = _backbone2.default.View.extend({
var config = this.config;
var params = config.params;
- for (var i = 0; i < files.length; i++) {
- body.append(config.uploadName + '[]', files[i]);
- }
-
for (var param in params) {
body.append(param, params[param]);
}
+ if (this.multiUpload) {
+ for (var i = 0; i < files.length; i++) {
+ body.append(config.uploadName + '[]', files[i]);
+ }
+ } else if (files.length) {
+ body.append(config.uploadName, files[0]);
+ }
+
var target = this.target;
var url = config.upload;
var headers = config.headers;
@@ -23308,7 +23326,7 @@ module.exports = _backbone2.default.View.extend({
this.onUploadStart();
return (0, _fetch2.default)(url, {
method: 'post',
- credentials: 'include',
+ credentials: config.credentials || 'include',
headers: headers,
body: body
}).then(function (res) {
@@ -23415,6 +23433,7 @@ module.exports = _backbone2.default.View.extend({
title: this.config.uploadText,
uploadId: this.uploadId,
disabled: this.disabled,
+ multiUpload: this.multiUpload,
pfx: this.pfx
}));
this.initDrop();
@@ -23984,12 +24003,14 @@ module.exports = _backbone2.default.View.extend({
initialize: function initialize(o) {
var config = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+ var model = this.model;
this.em = config.em;
this.config = config;
this.endDrag = this.endDrag.bind(this);
this.ppfx = config.pStylePrefix || '';
- this.listenTo(this.model, 'destroy remove', this.remove);
+ this.listenTo(model, 'destroy remove', this.remove);
+ this.listenTo(model, 'change', this.render);
},
@@ -25928,16 +25949,28 @@ module.exports = __webpack_require__(/*! backbone */ "./node_modules/backbone/ba
});
// Get at-rules
- for (var atRule in atRules) {
+
+ var _loop = function _loop(atRule) {
var rulesStr = '';
var mRules = atRules[atRule];
+
mRules.forEach(function (rule) {
- return rulesStr += _this2.buildFromRule(rule, dump, opts);
+ var ruleStr = _this2.buildFromRule(rule, dump, opts);
+
+ if (rule.get('singleAtRule')) {
+ code += atRule + '{' + ruleStr + '}';
+ } else {
+ rulesStr += ruleStr;
+ }
});
if (rulesStr) {
code += atRule + '{' + rulesStr + '}';
}
+ };
+
+ for (var atRule in atRules) {
+ _loop(atRule);
}
em && clearStyles && rules.remove(dump);
@@ -28062,9 +28095,11 @@ module.exports = {
am.onSelect(opts.onSelect);
if (!this.rendered || types) {
- var assets = am.getAll();
+ var assets = am.getAll().filter(function (i) {
+ return 1;
+ });
- if (types) {
+ if (types && types.length) {
assets = assets.filter(function (a) {
return types.indexOf(a.get('type')) !== -1;
});
@@ -28907,14 +28942,27 @@ module.exports = {
resizer = opts.resizer;
var keyHeight = config.keyHeight,
keyWidth = config.keyWidth,
- currentUnit = config.currentUnit;
+ currentUnit = config.currentUnit,
+ keepAutoHeight = config.keepAutoHeight,
+ keepAutoWidth = config.keepAutoWidth;
toggleBodyClass('add', e, opts);
modelToStyle = em.get('StyleManager').getModelToStyle(model);
var computedStyle = getComputedStyle(el);
var modelStyle = modelToStyle.getStyle();
- var currentWidth = modelStyle[keyWidth] || computedStyle[keyWidth];
- var currentHeight = modelStyle[keyHeight] || computedStyle[keyHeight];
+
+ var currentWidth = modelStyle[keyWidth];
+ config.autoWidth = keepAutoWidth && currentWidth === 'auto';
+ if (isNaN(parseFloat(currentWidth))) {
+ currentWidth = computedStyle[keyWidth];
+ }
+
+ var currentHeight = modelStyle[keyHeight];
+ config.autoHeight = keepAutoHeight && currentHeight === 'auto';
+ if (isNaN(parseFloat(currentHeight))) {
+ currentHeight = computedStyle[keyHeight];
+ }
+
resizer.startDim.w = parseFloat(currentWidth);
resizer.startDim.h = parseFloat(currentHeight);
showOffsets = 0;
@@ -28946,18 +28994,22 @@ module.exports = {
selectedHandler = options.selectedHandler,
config = options.config;
var keyHeight = config.keyHeight,
- keyWidth = config.keyWidth;
+ keyWidth = config.keyWidth,
+ autoHeight = config.autoHeight,
+ autoWidth = config.autoWidth,
+ unitWidth = config.unitWidth,
+ unitHeight = config.unitHeight;
var onlyHeight = ['tc', 'bc'].indexOf(selectedHandler) >= 0;
var onlyWidth = ['cl', 'cr'].indexOf(selectedHandler) >= 0;
var style = modelToStyle.getStyle();
if (!onlyHeight) {
- style[keyWidth] = rect.w + config.unitWidth;
+ style[keyWidth] = autoWidth ? 'auto' : '' + rect.w + unitWidth;
}
if (!onlyWidth) {
- style[keyHeight] = rect.h + config.unitHeight;
+ style[keyHeight] = autoHeight ? 'auto' : '' + rect.h + unitHeight;
}
modelToStyle.setStyle(style, { avoidStore: 1 });
@@ -30988,6 +31040,10 @@ module.exports = function () {
id: 'text',
model: __webpack_require__(/*! ./model/ComponentText */ "./src/dom_components/model/ComponentText.js"),
view: __webpack_require__(/*! ./view/ComponentTextView */ "./src/dom_components/view/ComponentTextView.js")
+ }, {
+ id: 'wrapper',
+ model: __webpack_require__(/*! ./model/ComponentWrapper */ "./src/dom_components/model/ComponentWrapper.js"),
+ view: ComponentView
}, {
id: 'default',
model: Component,
@@ -31079,6 +31135,7 @@ module.exports = function () {
var wrapper = _extends({}, c.wrapper);
wrapper['custom-name'] = c.wrapperName;
wrapper.wrapper = 1;
+ wrapper.type = 'wrapper';
// Components might be a wrapper
if (components && components.constructor === Object && components.wrapper) {
@@ -31178,6 +31235,7 @@ module.exports = function () {
*/
load: function load() {
var data = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
+ var em = this.em;
var result = '';
@@ -31185,12 +31243,23 @@ module.exports = function () {
data = c.em.getCacheLoad();
}
- if (data.components) {
- try {
- result = JSON.parse(data.components);
- } catch (err) {}
- } else if (data.html) {
- result = data.html;
+ var _data = data,
+ components = _data.components,
+ html = _data.html;
+
+
+ if (components) {
+ if ((0, _underscore.isObject)(components) || (0, _underscore.isArray)(components)) {
+ result = components;
+ } else {
+ try {
+ result = JSON.parse(components);
+ } catch (err) {
+ em && em.logError(err);
+ }
+ }
+ } else if (html) {
+ result = html;
}
var isObj = result && result.constructor === Object;
@@ -31476,6 +31545,8 @@ var _Styleable2 = _interopRequireDefault(_Styleable);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
+
var Backbone = __webpack_require__(/*! backbone */ "./node_modules/backbone/backbone.js");
var Components = __webpack_require__(/*! ./Components */ "./src/dom_components/model/Components.js");
var Selector = __webpack_require__(/*! selector_manager/model/Selector */ "./src/selector_manager/model/Selector.js");
@@ -31626,9 +31697,14 @@ var Component = Backbone.Model.extend(_Styleable2.default).extend({
this.set('status', '');
// Register global updates for collection properties
- ['classes', 'traits'].forEach(function (name) {
- return _this.listenTo(_this.get(name), 'add remove change', function () {
- return _this.emitUpdate(name);
+ ['classes', 'traits', 'components'].forEach(function (name) {
+ var events = 'add remove ' + (name !== 'components' ? 'change' : '');
+ _this.listenTo(_this.get(name), events.trim(), function () {
+ for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
+ args[_key] = arguments[_key];
+ }
+
+ return _this.emitUpdate.apply(_this, [name].concat(args));
});
});
this.init();
@@ -32287,8 +32363,8 @@ var Component = Backbone.Model.extend(_Styleable2.default).extend({
* @private
*/
toJSON: function toJSON() {
- for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
- args[_key] = arguments[_key];
+ for (var _len2 = arguments.length, args = Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
+ args[_key2] = arguments[_key2];
}
var obj = Backbone.Model.prototype.toJSON.apply(this, args);
@@ -32398,7 +32474,12 @@ var Component = Backbone.Model.extend(_Styleable2.default).extend({
emitUpdate: function emitUpdate(property) {
var em = this.em;
var event = 'component:update' + (property ? ':' + property : '');
- em && em.trigger(event, this);
+
+ for (var _len3 = arguments.length, args = Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
+ args[_key3 - 1] = arguments[_key3];
+ }
+
+ em && em.trigger.apply(em, [event, this].concat(_toConsumableArray(args)));
},
@@ -32422,6 +32503,15 @@ var Component = Backbone.Model.extend(_Styleable2.default).extend({
},
+ /**
+ * Remove the component
+ * @return {this}
+ */
+ remove: function remove() {
+ return this.collection.remove(this);
+ },
+
+
/**
* Reset id of the component and any of its style rule
* @param {Object} [opts={}] Options
@@ -33596,6 +33686,30 @@ module.exports = Component.extend({
/***/ }),
+/***/ "./src/dom_components/model/ComponentWrapper.js":
+/*!******************************************************!*\
+ !*** ./src/dom_components/model/ComponentWrapper.js ***!
+ \******************************************************/
+/*! no static exports found */
+/***/ (function(module, exports, __webpack_require__) {
+
+"use strict";
+
+
+var _Component = __webpack_require__(/*! ./Component */ "./src/dom_components/model/Component.js");
+
+var _Component2 = _interopRequireDefault(_Component);
+
+function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+
+module.exports = _Component2.default.extend({}, {
+ isComponent: function isComponent() {
+ return false;
+ }
+}); // We need this one just to identify better the wrapper type
+
+/***/ }),
+
/***/ "./src/dom_components/model/Components.js":
/*!************************************************!*\
!*** ./src/dom_components/model/Components.js ***!
@@ -34142,12 +34256,13 @@ module.exports = ComponentView.extend({
* @private
* */
enableEditing: function enableEditing(e) {
- e && e.stopPropagation && e.stopPropagation();
- var rte = this.rte;
-
+ // We place this before stopPropagation in case of nested
+ // text components will not block the editing (#1394)
if (this.rteEnabled || !this.model.get('editable')) {
return;
}
+ e && e.stopPropagation && e.stopPropagation();
+ var rte = this.rte;
if (rte) {
try {
@@ -34191,12 +34306,15 @@ module.exports = ComponentView.extend({
model.set('content', content);
} else {
var clean = function clean(model) {
+ var selectable = !model.is('text');
model.set({
editable: 0,
highlightable: 0,
removable: 0,
draggable: 0,
copyable: 0,
+ selectable: selectable,
+ hoverable: selectable,
toolbar: ''
});
model.get('components').each(function (model) {
@@ -36316,6 +36434,12 @@ module.exports = function (config) {
*/
RichTextEditor: em.get('RichTextEditor'),
+ /**
+ * @property {Parser}
+ * @private
+ */
+ Parser: em.get('Parser'),
+
/**
* @property {Utils}
* @private
@@ -36691,6 +36815,54 @@ module.exports = function (config) {
},
+ /**
+ * Replace the default CSS parser with a custom one.
+ * The parser function receives a CSS string as a parameter and expects
+ * an array of CSSRule objects as a result. If you need to remove the
+ * custom parser, pass `null` as the argument
+ * @param {Function|null} parser Parser function
+ * @return {this}
+ * @example
+ * editor.setCustomParserCss(css => {
+ * const result = [];
+ * // ... parse the CSS string
+ * result.push({
+ * selectors: '.someclass, div .otherclass',
+ * style: { color: 'red' }
+ * })
+ * // ...
+ * return result;
+ * });
+ */
+ setCustomParserCss: function setCustomParserCss(parser) {
+ this.Parser.getConfig().parserCss = parser;
+ return this;
+ },
+
+
+ /**
+ * Trigger event log message
+ * @param {*} msg Message to log
+ * @param {Object} [opts={}] Custom options
+ * @param {String} [opts.ns=''] Namespace of the log (eg. to use in plugins)
+ * @param {String} [opts.level='debug'] Level of the log, `debug`, `info`, `warning`, `error`
+ * @return {this}
+ * @example
+ * editor.log('Something done!', { ns: 'from-plugin-x', level: 'info' });
+ * // This will trigger following events
+ * // `log`, `log:info`, `log-from-plugin-x`, `log-from-plugin-x:info`
+ * // Callbacks of those events will always receive the message and
+ * // options, as arguments, eg:
+ * // editor.on('log:info', (msg, opts) => console.info(msg, opts))
+ */
+ log: function log(msg) {
+ var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+
+ em.log(msg, opts);
+ return this;
+ },
+
+
/**
* Attach event
* @param {string} event Event name
@@ -36698,7 +36870,8 @@ module.exports = function (config) {
* @return {this}
*/
on: function on(event, callback) {
- return em.on(event, callback);
+ em.on(event, callback);
+ return this;
},
@@ -36709,7 +36882,8 @@ module.exports = function (config) {
* @return {this}
*/
off: function off(event, callback) {
- return em.off(event, callback);
+ em.off(event, callback);
+ return this;
},
@@ -36719,7 +36893,8 @@ module.exports = function (config) {
* @return {this}
*/
trigger: function trigger(event) {
- return em.trigger.apply(em, arguments);
+ em.trigger.apply(em, arguments);
+ return this;
},
@@ -37007,12 +37182,10 @@ module.exports = Backbone.Model.extend({
var stm = this.get('StorageManager');
var changes = this.get('changesCount');
- if (this.config.noticeOnUnload && changes) {
- window.onbeforeunload = function (e) {
+ if (this.config.noticeOnUnload) {
+ window.onbeforeunload = changes ? function (e) {
return 1;
- };
- } else {
- window.onbeforeunload = null;
+ } : null;
}
if (stm.isAutosave() && changes >= stm.getStepsBeforeSave()) {
@@ -37555,6 +37728,30 @@ module.exports = Backbone.Model.extend({
isEditing: function isEditing() {
return !!this.get('editing');
},
+ log: function log(msg) {
+ var opts = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
+ var ns = opts.ns,
+ _opts$level = opts.level,
+ level = _opts$level === undefined ? 'debug' : _opts$level;
+
+ this.trigger('log', msg, opts);
+ level && this.trigger('log:' + level, msg, opts);
+
+ if (ns) {
+ var logNs = 'log-' + ns;
+ this.trigger(logNs, msg, opts);
+ level && this.trigger(logNs + ':' + level, msg, opts);
+ }
+ },
+ logInfo: function logInfo(msg, opts) {
+ this.log(msg, _extends({}, opts, { level: 'info' }));
+ },
+ logWarning: function logWarning(msg, opts) {
+ this.log(msg, _extends({}, opts, { level: 'warning' }));
+ },
+ logError: function logError(msg, opts) {
+ this.log(msg, _extends({}, opts, { level: 'error' }));
+ },
/**
@@ -37691,7 +37888,7 @@ module.exports = function () {
plugins: plugins,
// Will be replaced on build
- version: '0.14.29',
+ version: '0.14.33',
/**
* Initialize the editor with passed options
@@ -38664,9 +38861,11 @@ module.exports = _backbone2.default.View.extend({
*/
handleEdit: function handleEdit(e) {
e && e.stopPropagation();
+ var em = this.em;
var inputEl = this.getInputName();
inputEl[inputProp] = true;
inputEl.focus();
+ em && em.setEditing(1);
},
@@ -38675,10 +38874,12 @@ module.exports = _backbone2.default.View.extend({
*/
handleEditEnd: function handleEditEnd(e) {
e && e.stopPropagation();
+ var em = this.em;
var inputEl = this.getInputName();
var name = inputEl.textContent;
inputEl[inputProp] = false;
this.model.set({ name: name });
+ em && em.setEditing(0);
},
@@ -39648,9 +39849,10 @@ module.exports = _backbone2.default.View.extend({
this.ppfx = this.config.pStylePrefix || '';
this.id = pfx + this.model.get('id');
this.activeCls = pfx + 'active ' + ppfx + 'four-color';
- this.disableCls = pfx + 'active';
+ this.disableCls = ppfx + 'disabled';
this.btnsVisCls = pfx + 'visible';
this.className = pfx + 'btn' + (cls ? ' ' + cls : '');
+ this.listenTo(this.model, 'change', this.render);
this.listenTo(this.model, 'change:active updateActive', this.updateActive);
this.listenTo(this.model, 'checkActive', this.checkActive);
this.listenTo(this.model, 'change:bntsVis', this.updateBtnsVis);
@@ -39668,8 +39870,13 @@ module.exports = _backbone2.default.View.extend({
* @return void
* */
updateClassName: function updateClassName() {
- var cls = this.model.get('className');
- this.$el.attr('class', this.pfx + 'btn' + (cls ? ' ' + cls : ''));
+ var model = this.model,
+ pfx = this.pfx;
+
+ var cls = model.get('className');
+ var attrCls = model.get('attributes').class;
+ var classStr = (attrCls ? attrCls : '') + ' ' + pfx + 'btn ' + (cls ? cls : '');
+ this.$el.attr('class', classStr.trim());
},
@@ -39680,6 +39887,7 @@ module.exports = _backbone2.default.View.extend({
* */
updateAttributes: function updateAttributes() {
this.$el.attr(this.model.get('attributes'));
+ this.updateClassName();
},
@@ -39734,11 +39942,11 @@ module.exports = _backbone2.default.View.extend({
}
},
updateDisable: function updateDisable() {
- if (this.model.get('disable')) {
- this.$el.addClass(this.disableCls);
- } else {
- this.$el.removeClass(this.disableCls);
- }
+ var disableCls = this.disableCls,
+ model = this.model;
+
+ var disable = model.get('disable');
+ this.$el[disable ? 'addClass' : 'removeClass'](disableCls);
},
@@ -39748,7 +39956,11 @@ module.exports = _backbone2.default.View.extend({
* @return void
* */
checkActive: function checkActive() {
- if (this.model.get('active')) this.$el.addClass(this.activeCls);else this.$el.removeClass(this.activeCls);
+ var model = this.model,
+ $el = this.$el,
+ activeCls = this.activeCls;
+
+ model.get('active') ? $el.addClass(activeCls) : $el.removeClass(activeCls);
},
@@ -39788,9 +40000,12 @@ module.exports = _backbone2.default.View.extend({
render: function render() {
var label = this.model.get('label');
var $el = this.$el;
+
+ $el.empty();
this.updateAttributes();
- $el.attr('class', this.className);
label && $el.append(label);
+ this.checkActive();
+ this.updateDisable();
return this;
}
@@ -40120,7 +40335,13 @@ module.exports = Backbone.View.extend({
module.exports = {
- textTags: ['br', 'b', 'i', 'u', 'a', 'ul', 'ol']
+ textTags: ['br', 'b', 'i', 'u', 'a', 'ul', 'ol'],
+
+ // Custom CSS parser
+ parserCss: null,
+
+ // Custom HTML parser
+ parserHtml: null
};
/***/ }),
@@ -40135,16 +40356,23 @@ module.exports = {
"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; };
+
module.exports = function () {
- var c = {},
+ var conf = {},
defaults = __webpack_require__(/*! ./config/config */ "./src/parser/config/config.js"),
parserCss = __webpack_require__(/*! ./model/ParserCss */ "./src/parser/model/ParserCss.js"),
parserHtml = __webpack_require__(/*! ./model/ParserHtml */ "./src/parser/model/ParserHtml.js");
- var pHtml, pCss;
+ var pHtml = void 0,
+ pCss = void 0;
return {
compTypes: '',
+ parserCss: null,
+
+ parserHtml: null,
+
/**
* Name of the module
* @type {String}
@@ -40152,6 +40380,15 @@ module.exports = function () {
*/
name: 'Parser',
+ /**
+ * Get config object
+ * @return {Object}
+ */
+ getConfig: function getConfig() {
+ return conf;
+ },
+
+
/**
* Initialize module. Automatically called with a new instance of the editor
* @param {Object} config Configurations
@@ -40167,13 +40404,13 @@ module.exports = function () {
* }
* ...
*/
- init: function init(config) {
- c = config || {};
- for (var name in defaults) {
- if (!(name in c)) c[name] = defaults[name];
- }
- pHtml = new parserHtml(c);
- pCss = new parserCss(c);
+ init: function init() {
+ var config = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ conf = _extends({}, defaults, config);
+ conf.Parser = this;
+ pHtml = new parserHtml(conf);
+ pCss = new parserCss(conf);
return this;
},
@@ -40187,6 +40424,13 @@ module.exports = function () {
pHtml.compTypes = this.compTypes;
return pHtml.parse(str, pCss);
},
+
+
+ /**
+ * Parse CSS string and return valid model
+ * @param {string} str CSS string
+ * @return {Array