diff --git a/addons/web_editor/controllers/main.py b/addons/web_editor/controllers/main.py
index 066860dcc75..4370cd19c0a 100644
--- a/addons/web_editor/controllers/main.py
+++ b/addons/web_editor/controllers/main.py
@@ -118,9 +118,19 @@ class Web_Editor(http.Controller):
htmlelem = etree.fromstring("
%s
" % value, etree.HTMLParser())
checked = bool(checked)
- li = htmlelem.find(".//li[@id='checklist-id-" + str(checklistId) + "']")
+ li = htmlelem.find(".//li[@id='%s']" % checklistId)
- if not li or not self._update_checklist_recursive(li, checked, children=True, ancestors=True):
+ if li is None:
+ return value
+
+ classname = li.get('class', '')
+ if ('o_checked' in classname) != checked:
+ if checked:
+ classname = '%s o_checked' % classname
+ else:
+ classname = re.sub(r"\s?o_checked\s?", '', classname)
+ li.set('class', classname)
+ else:
return value
value = etree.tostring(htmlelem[0][0], encoding='utf-8', method='html')[5:-6]
@@ -128,55 +138,6 @@ class Web_Editor(http.Controller):
return value
- def _update_checklist_recursive (self, li, checked, children=False, ancestors=False):
- if 'checklist-id-' not in li.get('id', ''):
- return False
-
- classname = li.get('class', '')
- if ('o_checked' in classname) == checked:
- return False
-
- # check / uncheck
- if checked:
- classname = '%s o_checked' % classname
- else:
- classname = re.sub(r"\s?o_checked\s?", '', classname)
- li.set('class', classname)
-
- # propagate to children
- if children:
- node = li.getnext()
- ul = None
- if node is not None:
- if node.tag == 'ul':
- ul = node
- if node.tag == 'li' and len(node.getchildren()) == 1 and node.getchildren()[0].tag == 'ul':
- ul = node.getchildren()[0]
-
- if ul is not None:
- for child in ul.getchildren():
- if child.tag == 'li':
- self._update_checklist_recursive(child, checked, children=True)
-
- # propagate to ancestors
- if ancestors:
- allSelected = True
- ul = li.getparent()
- if ul.tag == 'li':
- ul = ul.getparent()
-
- for child in ul.getchildren():
- if child.tag == 'li' and 'checklist-id' in child.get('id', '') and 'o_checked' not in child.get('class', ''):
- allSelected = False
-
- node = ul.getprevious()
- if node is None:
- node = ul.getparent().getprevious()
- if node is not None and node.tag == 'li':
- self._update_checklist_recursive(node, allSelected, ancestors=True)
-
- return True
-
@http.route('/web_editor/video_url/data', type='json', auth='user', website=True)
def video_url_data(self, video_url, autoplay=False, loop=False,
hide_controls=False, hide_fullscreen=False, hide_yt_logo=False,
diff --git a/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js b/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js
index dc27e0182f5..5e29b49e064 100644
--- a/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js
+++ b/addons/web_editor/static/lib/odoo-editor/src/OdooEditor.js
@@ -445,6 +445,7 @@ export class OdooEditor extends EventTarget {
this.observer = new MutationObserver(records => {
records = this.filterMutationRecords(records);
if (!records.length) return;
+ this.dispatchEvent(new Event('contentChanged'));
clearTimeout(this.observerTimeout);
if (this._observerTimeoutUnactive.size === 0) {
this.observerTimeout = setTimeout(() => {
diff --git a/addons/web_editor/static/lib/odoo-editor/src/utils/sanitize.js b/addons/web_editor/static/lib/odoo-editor/src/utils/sanitize.js
index f93f8f72769..a62e79fbe2c 100644
--- a/addons/web_editor/static/lib/odoo-editor/src/utils/sanitize.js
+++ b/addons/web_editor/static/lib/odoo-editor/src/utils/sanitize.js
@@ -133,6 +133,11 @@ class Sanitize {
}
}
+ // Ensure unique ids on checklists.
+ if (node.nodeName == 'LI' && node.parentElement && node.parentElement.classList.contains('o_checklist')) {
+ node.setAttribute('id', Math.floor(new Date() * Math.random()));
+ }
+
// FIXME not parse out of editable zone...
this._parse(node.firstChild);
this._parse(node.nextSibling);
diff --git a/addons/web_editor/static/src/js/backend/field_html.js b/addons/web_editor/static/src/js/backend/field_html.js
index dcb8477e3f0..fc0a0fc288d 100644
--- a/addons/web_editor/static/src/js/backend/field_html.js
+++ b/addons/web_editor/static/src/js/backend/field_html.js
@@ -454,27 +454,6 @@ var FieldHtml = basic_fields.DebouncedField.extend(TranslatableFieldMixin, {
*/
_onChange: function (ev) {
this._doDebouncedAction.apply(this, arguments);
-
- var $lis = this.$content.find('.note-editable ul.o_checklist > li:not(:has(> ul.o_checklist))');
- if (!$lis.length) {
- return;
- }
- var max = 0;
- var ids = [];
- $lis.map(function () {
- var checklistId = parseInt(($(this).attr('id') || '0').replace(/^checklist-id-/, ''));
- if (ids.indexOf(checklistId) === -1) {
- if (checklistId > max) {
- max = checklistId;
- }
- ids.push(checklistId);
- } else {
- $(this).removeAttr('id');
- }
- });
- $lis.not('[id]').each(function () {
- $(this).attr('id', 'checklist-id-' + (++max));
- });
},
/**
* Allows Enter keypress in a textarea (source mode)
@@ -503,7 +482,7 @@ var FieldHtml = basic_fields.DebouncedField.extend(TranslatableFieldMixin, {
ev.stopPropagation();
ev.preventDefault();
var checked = $(ev.target).hasClass('o_checked');
- var checklistId = parseInt(($(ev.target).attr('id') || '0').replace(/^checklist-id-/, ''));
+ var checklistId = parseInt($(ev.target).attr('id') || '0');
this._rpc({
route: '/web_editor/checklist',
diff --git a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
index fa4c8221810..5ce049f3a6c 100644
--- a/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
+++ b/addons/web_editor/static/src/js/wysiwyg/wysiwyg.js
@@ -133,6 +133,11 @@ const Wysiwyg = Widget.extend({
plugins: options.editorPlugins,
}, editorCollaborationOptions));
+ this.odooEditor.addEventListener('contentChanged', function () {
+ self.$editable.trigger('content_changed');
+ self.trigger_up('wysiwyg_change');
+ });
+
const $wrapwrap = $('#wrapwrap');
if ($wrapwrap.length) {
$wrapwrap[0].addEventListener('scroll', this.odooEditor.multiselectionRefresh, { passive: true });
@@ -1515,22 +1520,7 @@ const Wysiwyg = Widget.extend({
}
},
_editorOptions: function () {
- var self = this;
- var options = Object.assign({}, this.defaultOptions, this.options);
- options.onChange = function (html, $editable) {
- $editable.trigger('content_changed');
- self.trigger_up('wysiwyg_change');
- };
- options.onUpload = function (attachments) {
- self.trigger_up('wysiwyg_attachment', attachments);
- };
- options.onFocus = function () {
- self.trigger_up('wysiwyg_focus');
- };
- options.onBlur = function () {
- self.trigger_up('wysiwyg_blur');
- };
- return options;
+ return Object.assign({}, this.defaultOptions, this.options);
},
_insertSnippetMenu: function () {
return this.snippetsMenu.insertBefore(this.$el);