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);