diff --git a/addons/barcodes/static/src/js/form_view_barcode_handler.js b/addons/barcodes/static/src/js/form_view_barcode_handler.js index ffc6dfc7383..fd0a84166f5 100644 --- a/addons/barcodes/static/src/js/form_view_barcode_handler.js +++ b/addons/barcodes/static/src/js/form_view_barcode_handler.js @@ -27,6 +27,8 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, { this.__quantity_listener = _.bind(this._set_quantity_listener, this); BarcodeHandlerMixin.init.apply(this, arguments); + this.process_barcode_mutex = new utils.Mutex(); + return this._super.apply(this, arguments); }, @@ -136,25 +138,35 @@ var FormViewBarcodeHandler = common.AbstractField.extend(BarcodeHandlerMixin, { else if (this.form_view.get('actual_mode') === 'view') this._display_no_edit_mode_warning(); else { - // Call hook method possibly implemented by subclass - this.pre_onchange_hook(barcode).then(function(proceed) { - if (proceed === true) { - // Wait for hypothetical ongoing onchange to finish - self.form_view.onchanges_mutex.exec(function() { - // A real onchange is triggered when a value actually changes (which can correspond - // to a widget's blur event per example). Commit the value of fields before - // programmatically triggering an onchange to be consistent with this. - var mutex_commit_value = new utils.Mutex(); - _.each(self.form_view.fields, function(field) { - mutex_commit_value.exec(_.bind(field.commit_value, field)); - }); - return mutex_commit_value.def.then(function(){ - // Trigger the barcode onchange - self.set_value(barcode); - }); - }); + var process_barcode = function () { + // this function can be passed to `Mutex.exec` in order to make sure + // that every ongoing onchanges in the form view are done + var form_onchanges_mutex = function () { + return self.form_view.onchanges_mutex.def; } - }); + + // before setting the barcode field with the received barcode, we commit + // every fields of the form view and we wait for their hypothetical ongoing + // onchanges to finish + var commit_mutex = new utils.Mutex(); + _.each(self.form_view.fields, function (field) { + commit_mutex.exec(function () { + return field.commit_value(); + }); + commit_mutex.exec(form_onchanges_mutex); + }); + + return commit_mutex.def.then(function () { + return self.pre_onchange_hook(barcode).then(function (proceed) { + if (proceed) { + self.set_value(barcode); // set the barcode field with the received one + return form_onchanges_mutex(); // wait for its onchange to finish + } + }); + }); + }; + + this.process_barcode_mutex.exec(process_barcode); } }, diff --git a/addons/web/static/src/js/views/list_view_editable.js b/addons/web/static/src/js/views/list_view_editable.js index 6f8e4b973a4..221383f6890 100644 --- a/addons/web/static/src/js/views/list_view_editable.js +++ b/addons/web/static/src/js/views/list_view_editable.js @@ -641,7 +641,8 @@ ListView.include(/** @lends instance.web.ListView# */{ if (saveInfo.created) { return self.start_edition(); } - var record = self.records[next_record](saveInfo.record); + var options = { wraparound: !self.is_action_enabled('create') }; + var record = self.records[next_record](saveInfo.record, options); if (record === undefined) { return self.start_edition(); } diff --git a/addons/web_editor/static/src/js/backend.js b/addons/web_editor/static/src/js/backend.js index 36cd33c60fd..3585ddfdb9a 100644 --- a/addons/web_editor/static/src/js/backend.js +++ b/addons/web_editor/static/src/js/backend.js @@ -161,6 +161,11 @@ var FieldTextHtmlSimple = widget.extend({ return !this.get('value') || this.get('value') === "


" || !this.get('value').match(/\S/); }, commit_value: function () { + /* Switch to WYSIWYG mode if currently in code view */ + if (session.debug) { + var layoutInfo = this.$textarea.data('layoutInfo'); + $.summernote.pluginEvents.codeview(undefined, undefined, layoutInfo, false); + } if (this.options['style-inline']) { transcoder.class_to_style(this.$content); transcoder.font_to_img(this.$content); @@ -374,6 +379,11 @@ var FieldTextHtml = widget.extend({ this._dirty_flag = false; return this.editor.save(); } else if (this._dirty_flag && this.editor && this.editor.buildingBlock) { + /* Switch to WYSIWYG mode if currently in code view */ + if (session.debug) { + var layoutInfo = this.editor.rte.editable().data('layoutInfo'); + $.summernote.pluginEvents.codeview(undefined, undefined, layoutInfo, false); + } this.editor.buildingBlock.clean_for_save(); this.internal_set_value( this.$content.html() ); } diff --git a/addons/web_editor/static/src/js/rte.summernote.js b/addons/web_editor/static/src/js/rte.summernote.js index 73565e19743..97574c0cb86 100644 --- a/addons/web_editor/static/src/js/rte.summernote.js +++ b/addons/web_editor/static/src/js/rte.summernote.js @@ -539,12 +539,32 @@ function prettify_html(html) { } return result; } -$.summernote.pluginEvents.codeview = function (event, editor, layoutInfo) { + +/* + * This override when clicking on the 'Code View' button has two aims: + * + * - have our own code view implementation for FieldTextHtml + * - add an 'enable' paramater to call the function directly and allow us to + * disable (false) or enable (true) the code view mode. + */ +$.summernote.pluginEvents.codeview = function (event, editor, layoutInfo, enable) { + if (layoutInfo === undefined) { + return; + } if (layoutInfo.toolbar) { + // if editor inline (FieldTextHtmlSimple) + var is_activated = $.summernote.eventHandler.modules.codeview.isActivated(layoutInfo); + if (is_activated === enable) { + return; + } return eventHandler.modules.codeview.toggle(layoutInfo); } else { + // if editor iframe (FieldTextHtml) var $editor = layoutInfo.editor(); var $textarea = $editor.prev('textarea'); + if ($textarea.is('textarea') === enable) { + return; + } if (!$textarea.length) { // init and create texarea diff --git a/addons/web_editor/static/src/js/tour.rte.js b/addons/web_editor/static/src/js/tour.rte.js index 2d85600e578..5ca69cd0e13 100644 --- a/addons/web_editor/static/src/js/tour.rte.js +++ b/addons/web_editor/static/src/js/tour.rte.js @@ -403,6 +403,51 @@ Tour.register({ }); +Tour.register({ + id: 'rte_backend_inline', + name: "Test RTE in backend view", + mode: 'test', + steps: [ + { + title: "Beginning test", + }, + { + title: "Click on edit button", + element: '.o_form_button_edit, .oe_form_button_edit', + }, + { + title: "Add text to inline html field and save", + element: '.o_form_button_save, .oe_form_button_save', + onload: function(){ + $('.oe_form_field_html_text .note-editable > p').append('world'); + }, + }, + { + title: "Verify saved data after edition then click on edit button", + waitFor: '.oe_form_field_html_text p > i:last-child:contains(world)', + element: '.o_form_button_edit, .oe_form_button_edit', + }, + { + title: "Switch to code view mode", + element: 'button[data-event="codeview"]', + }, + { + title: "Modify code view content and save", + element: '.o_form_button_save, .oe_form_button_save', + onload: function(){ + $('.oe_form_field_html_text textarea.note-codable').val(function(_, val){ + return val.replace('

', '!

'); + }); + }, + }, + { + title: "Verify saved data after code view edition", + waitFor: '.oe_form_field_html_text p > u:last-child:contains(!)', + }, + ] +}); + + }); }); diff --git a/addons/web_editor/tests/__init__.py b/addons/web_editor/tests/__init__.py index ee3fba301a9..7c583996806 100644 --- a/addons/web_editor/tests/__init__.py +++ b/addons/web_editor/tests/__init__.py @@ -1,3 +1,4 @@ # -*- coding: utf-8 -*- import test_ui import test_converter +import test_backend_view diff --git a/addons/web_editor/tests/test_backend_view.py b/addons/web_editor/tests/test_backend_view.py new file mode 100644 index 00000000000..cceb2af3adf --- /dev/null +++ b/addons/web_editor/tests/test_backend_view.py @@ -0,0 +1,15 @@ +from openerp.api import Environment +import openerp.tests + +@openerp.tests.common.at_install(False) +@openerp.tests.common.post_install(True) +class TestBackendView(openerp.tests.HttpCase): + + def test_01_rte_backend_inline(self): + """ Test saving inline editor in or out of code view mode. """ + with self.registry.cursor() as test_cursor: + env = Environment(test_cursor, self.uid, {}) + test_record = env['web_editor.converter.test'].create({'html': '

hello

'}) + form_url = "/web?debug#id={}&view_type=form&model=web_editor.converter.test".format(test_record.id) + + self.phantom_js(form_url, "odoo.__DEBUG__.services['web.Tour'].run('rte_backend_inline', 'test')", "odoo.__DEBUG__.services['web.Tour'].tours.rte", login="admin")