summaryrefslogtreecommitdiff
path: root/addons/web_editor/static/src/js/editor
diff options
context:
space:
mode:
Diffstat (limited to 'addons/web_editor/static/src/js/editor')
-rw-r--r--addons/web_editor/static/src/js/editor/rte.js22
-rw-r--r--addons/web_editor/static/src/js/editor/rte.summernote.js3
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.editor.js11
-rw-r--r--addons/web_editor/static/src/js/editor/snippets.options.js112
-rw-r--r--addons/web_editor/static/src/js/editor/summernote.js9
5 files changed, 126 insertions, 31 deletions
diff --git a/addons/web_editor/static/src/js/editor/rte.js b/addons/web_editor/static/src/js/editor/rte.js
index bfd7994b161..529bf68887e 100644
--- a/addons/web_editor/static/src/js/editor/rte.js
+++ b/addons/web_editor/static/src/js/editor/rte.js
@@ -323,11 +323,20 @@ var RTEWidget = Widget.extend({
});
// start element observation
- $(document).on('content_changed', '.o_editable', function (ev) {
+ $(document).on('content_changed', function (ev) {
self.trigger_up('rte_change', {target: ev.target});
+
+ // Add the dirty flag to the element that changed by either adding
+ // it on the highest editable ancestor or, if there is no editable
+ // ancestor, on the element itself (that element may not be editable
+ // but if it received a content_changed event, it should be marked
+ // as dirty to allow for custom savings).
if (!ev.__isDirtyHandled) {
- $(this).addClass('o_dirty');
ev.__isDirtyHandled = true;
+
+ var el = ev.target;
+ var dirty = el.closest('.o_editable') || el;
+ dirty.classList.add('o_dirty');
}
});
@@ -586,11 +595,16 @@ var RTEWidget = Widget.extend({
* page element)
*/
_saveElement: function ($el, context, withLang) {
+ var viewID = $el.data('oe-id');
+ if (!viewID) {
+ return Promise.resolve();
+ }
+
return this._rpc({
model: 'ir.ui.view',
method: 'save',
args: [
- $el.data('oe-id'),
+ viewID,
this._getEscapedElement($el).prop('outerHTML'),
$el.data('oe-xpath') || null,
],
@@ -720,7 +734,7 @@ var RTEWidget = Widget.extend({
// selected too)
//
// The triple click behavior is reimplemented for all browsers here
- if (ev.originalEvent.detail === 3) {
+ if (ev.originalEvent && ev.originalEvent.detail === 3) {
// Select the whole content inside the deepest DOM element that was
// triple-clicked
range.create(ev.target, 0, ev.target, ev.target.childNodes.length).select();
diff --git a/addons/web_editor/static/src/js/editor/rte.summernote.js b/addons/web_editor/static/src/js/editor/rte.summernote.js
index b5b74f64466..95ce86572ae 100644
--- a/addons/web_editor/static/src/js/editor/rte.summernote.js
+++ b/addons/web_editor/static/src/js/editor/rte.summernote.js
@@ -452,6 +452,9 @@ eventHandler.modules.linkDialog.showLinkDialog = function ($editable, $dialog, l
$editable.data('range').select();
$editable.data('NoteHistory').recordUndo();
+ var link = linkInfo.range.commonAncestor().closest('a');
+ linkInfo.className = link && link.className;
+
var def = new $.Deferred();
core.bus.trigger('link_dialog_demand', {
$editable: $editable,
diff --git a/addons/web_editor/static/src/js/editor/snippets.editor.js b/addons/web_editor/static/src/js/editor/snippets.editor.js
index c9571f59c51..b94c7108122 100644
--- a/addons/web_editor/static/src/js/editor/snippets.editor.js
+++ b/addons/web_editor/static/src/js/editor/snippets.editor.js
@@ -77,7 +77,16 @@ var SnippetEditor = Widget.extend({
return $clone;
},
start: this._onDragAndDropStart.bind(this),
- stop: this._onDragAndDropStop.bind(this),
+ stop: function () {
+ // Delay our stop handler so that some summernote handlers
+ // which occur on mouseup (and are themself delayed) are
+ // executed first (this prevents the library to crash
+ // because our stop handler may change the DOM).
+ var args = arguments;
+ setTimeout(function () {
+ self._onDragAndDropStop.apply(self, args);
+ }, 0);
+ },
});
} else {
this.$('.o_move_handle').addClass('d-none');
diff --git a/addons/web_editor/static/src/js/editor/snippets.options.js b/addons/web_editor/static/src/js/editor/snippets.options.js
index f124d1841f0..eec85058ebc 100644
--- a/addons/web_editor/static/src/js/editor/snippets.options.js
+++ b/addons/web_editor/static/src/js/editor/snippets.options.js
@@ -700,6 +700,17 @@ registry.colorpicker = SnippetOption.extend({
this.$el.find('we-collapse').append($pt);
}
+
+ // TODO refactor in master
+ // The primary and secondary are hardcoded here (but marked as hidden)
+ // so they can be removed from snippets when selecting another color.
+ // Normally, the chosable colors do not contain them, which prevents
+ // them to be removed. Indeed, normally, the 'alpha' and 'beta' colors
+ // (which are the same) are displayed instead... but not for all themes.
+ var $colorpicker = this.$el.find('.colorpicker');
+ $colorpicker.append($('<button/>', {'class': 'd-none', 'data-color': 'primary'}));
+ $colorpicker.append($('<button/>', {'class': 'd-none', 'data-color': 'secondary'}));
+
var classes = [];
this.$el.find('.colorpicker button').each(function () {
var $color = $(this);
@@ -838,23 +849,18 @@ registry.background = SnippetOption.extend({
* @see this.selectClass for parameters
*/
chooseImage: function (previewMode, value, $opt) {
- // Put fake image in the DOM, edit it and use it as background-image
- var $image = $('<img/>', {class: 'd-none', src: value === 'true' ? '' : value}).appendTo(this.$target);
+ var options = this._getMediaDialogOptions();
+ var media = this._getEditableMedia();
- var $editable = this.$target.closest('.o_editable');
- var _editor = new weWidgets.MediaDialog(this, {
- 'onlyImages': true,
- 'firstFilters': ['background'],
- 'res_model': $editable.data('oe-model'),
- 'res_id': $editable.data('oe-id'),
- }, $image[0]).open();
-
- _editor.on('save', this, function () {
- this._setCustomBackground($image.attr('src'));
+ var _editor = new weWidgets.MediaDialog(this, options, media).open();
+ _editor.on('save', this, data => {
+ this._onSaveMediaDialog(data);
this.$target.trigger('content_changed');
});
- _editor.on('closed', this, function () {
- $image.remove();
+ _editor.on('closed', this, () => {
+ if (media.classList.contains('o_we_fake_image')) {
+ media.parentNode.removeChild(media);
+ }
});
},
@@ -871,16 +877,7 @@ registry.background = SnippetOption.extend({
return;
}
this.$target.off('.background-option')
- .on('background-color-event.background-option', (function (e, previewMode) {
- e.stopPropagation();
- if (e.currentTarget !== e.target) {
- return;
- }
- if (previewMode === false) {
- this.__customImageSrc = undefined;
- }
- this.background(previewMode);
- }).bind(this));
+ .on('background-color-event.background-option', this._onBackgroundColorUpdate.bind(this));
},
/**
* @override
@@ -897,6 +894,37 @@ registry.background = SnippetOption.extend({
//--------------------------------------------------------------------------
/**
+ * Returns a media element the media dialog will be able to edit to use
+ * the result as the snippet's background somehow.
+ *
+ * @private
+ * @returns {HTMLElement}
+ */
+ _getEditableMedia: function () {
+ var $image = $('<img/>', {
+ class: 'd-none o_we_fake_image',
+ }).appendTo(this.$target);
+ return $image[0];
+ },
+ /**
+ * Returns the options to be given to the MediaDialog instance when choosing
+ * a snippet's background.
+ *
+ * @private
+ * @returns {Object}
+ */
+ _getMediaDialogOptions: function () {
+ var $editable = this.$target.closest('.o_editable');
+ return {
+ noDocuments: true,
+ noIcons: true,
+ noVideos: true,
+ firstFilters: ['background'],
+ res_model: $editable.data('oe-model'),
+ res_id: $editable.data('oe-id'),
+ };
+ },
+ /**
* Returns the src value from a css value related to a background image
* (e.g. "url('blabla')" => "blabla" / "none" => "").
*
@@ -941,6 +969,42 @@ registry.background = SnippetOption.extend({
this._setActive();
this.$target.trigger('snippet-option-change', [this]);
},
+
+ //--------------------------------------------------------------------------
+ // Handlers
+ //--------------------------------------------------------------------------
+
+ /**
+ * Called on background-color update (useful to remove the background to be
+ * able to see the chosen color).
+ *
+ * @private
+ * @param {Event} ev
+ * @param {boolean|string} previewMode
+ * @returns {boolean} true if the color has been applied (removing the
+ * background)
+ */
+ _onBackgroundColorUpdate: function (ev, previewMode) {
+ ev.stopPropagation();
+ if (ev.currentTarget !== ev.target) {
+ return false;
+ }
+ if (previewMode === false) {
+ this.__customImageSrc = undefined;
+ }
+ this.background(previewMode);
+ return true;
+ },
+ /**
+ * Called on media dialog save (when choosing a snippet's background) ->
+ * sets the resulting media as the snippet's background somehow.
+ *
+ * @private
+ * @param {Object} data
+ */
+ _onSaveMediaDialog: function (data) {
+ this._setCustomBackground(data.src);
+ },
});
/**
diff --git a/addons/web_editor/static/src/js/editor/summernote.js b/addons/web_editor/static/src/js/editor/summernote.js
index 6c62758142d..c2cf0d68d6c 100644
--- a/addons/web_editor/static/src/js/editor/summernote.js
+++ b/addons/web_editor/static/src/js/editor/summernote.js
@@ -1790,6 +1790,7 @@ $.summernote.pluginEvents.insertUnorderedList = function (event, editor, layoutI
}
r.clean().select();
event.preventDefault();
+
return false;
};
$.summernote.pluginEvents.insertOrderedList = function (event, editor, layoutInfo) {
@@ -1797,6 +1798,7 @@ $.summernote.pluginEvents.insertOrderedList = function (event, editor, layoutInf
};
$.summernote.pluginEvents.insertCheckList = function (event, editor, layoutInfo) {
$.summernote.pluginEvents.insertUnorderedList(event, editor, layoutInfo, "checklist");
+ $(range.create().sc.parentNode).trigger('input'); // to update checklist-id
};
$.summernote.pluginEvents.indent = function (event, editor, layoutInfo, outdent) {
var $editable = layoutInfo.editable();
@@ -2469,6 +2471,7 @@ function mouseDownChecklist (e) {
if (!dom.isLi(e.target) || !$(e.target).parent('ul.o_checklist').length || e.offsetX > 0) {
return;
}
+ e.stopPropagation();
e.preventDefault();
var checked = $(e.target).hasClass('o_checked');
$(e.target).toggleClass('o_checked', !checked);
@@ -2478,12 +2481,14 @@ function mouseDownChecklist (e) {
});
if (checked) {
$sublevel.removeClass('o_checked');
- $parents.prev('ul.o_checklist li').removeClass('o_checked');
+ do {
+ $parents = $parents.prev('ul.o_checklist li').removeClass('o_checked');
+ } while ($parents.length);
} else {
$sublevel.addClass('o_checked');
var $lis;
do {
- $lis = $parents.not(':has(li:not(.o_checked))').prev('ul.o_checklist li:not(.o_checked)');
+ $lis = $parents.not(':has(li[id^="checklist-id"]:not(.o_checked))').prev('ul.o_checklist li:not(.o_checked)');
$lis.addClass('o_checked');
} while ($lis.length);
}