From 6815b491d6553b02ad2902141e587379231e6fcf Mon Sep 17 00:00:00 2001 From: David Monjoie Date: Tue, 25 Aug 2015 20:47:26 +0200 Subject: [PATCH 01/59] [ADD] website_form_editor: editor for website_form forms Contains the new ajax post function introduced by e8d58dd in the community version of web that comes from mdo's original code and that I was not able to get rid of. --- __init__.py | 0 __openerp__.py | 22 + data/website_form_mail.xml | 10 + static/src/img/s_website_form.png | Bin 0 -> 536 bytes static/src/js/website_form_editor.js | 470 ++++++++++++++++ static/src/js/website_form_editor_tour.js | 620 ++++++++++++++++++++++ static/src/xml/website_form_editor.xml | 231 ++++++++ tests/__init__.py | 1 + tests/test_website_form_editor.py | 8 + views/assets.xml | 18 + views/ir_model_view.xml | 29 + views/snippet_options.xml | 74 +++ views/snippets.xml | 23 + 13 files changed, 1506 insertions(+) create mode 100644 __init__.py create mode 100644 __openerp__.py create mode 100644 data/website_form_mail.xml create mode 100644 static/src/img/s_website_form.png create mode 100644 static/src/js/website_form_editor.js create mode 100644 static/src/js/website_form_editor_tour.js create mode 100644 static/src/xml/website_form_editor.xml create mode 100644 tests/__init__.py create mode 100644 tests/test_website_form_editor.py create mode 100644 views/assets.xml create mode 100644 views/ir_model_view.xml create mode 100644 views/snippet_options.xml create mode 100644 views/snippets.xml diff --git a/__init__.py b/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/__openerp__.py b/__openerp__.py new file mode 100644 index 00000000000..9ee446a08fa --- /dev/null +++ b/__openerp__.py @@ -0,0 +1,22 @@ +{ + 'name': 'Website Form Editor', + 'category': 'Website', + 'summary': 'Build custom web forms using the website builder', + 'version': '1.0', + 'description': """ +Odoo Form Editor +==================== + +Allows you to build web forms on the website using the website builder. + """, + 'depends': ['website_form'], + 'data': [ + 'views/assets.xml', + 'views/snippets.xml', + 'views/ir_model_view.xml', + 'views/snippet_options.xml', + 'data/website_form_mail.xml', + ], + 'installable': True, + 'auto_install': False, +} diff --git a/data/website_form_mail.xml b/data/website_form_mail.xml new file mode 100644 index 00000000000..081bd674fe0 --- /dev/null +++ b/data/website_form_mail.xml @@ -0,0 +1,10 @@ + + + + + + True + Send an E-mail + + + diff --git a/static/src/img/s_website_form.png b/static/src/img/s_website_form.png new file mode 100644 index 0000000000000000000000000000000000000000..3df58edabd1bb6aeed0e31839e7ecf0cc834da75 GIT binary patch literal 536 zcmV+z0_XjSP)Px#0%A)?L;(MXkIcUS000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2j2)85hXd8 z&&DPI00EpyL_t(o!|mC>PJ=)k2k)U|J-H5 zaCoI@2=mh~`Gd1-Xok7jHF75F;nNqlBaGxDqnTZ+fpaNxEJnyA&-jsrkz$D~jTGD4 zWu#cI6BEULF&ZcYD_*ZqlohQ)QoD2tO@Y)XL{)fL2|%PE%X@pgC6YGk*aWtzMr|N< z8wrPSBJ#OlN2J=m6wJs>0i6mVGCKph6+)!i=5;7OUFP@KeTq+*d96quL@J"); + } + } + ); + + self.toggle_email_to(); + + self.$modal.find("[name='model_selection']").on('change', function() { + self.toggle_email_to(); + }); + }) + }, + + // Choose a field modal + website_form_field_modal: function (type, value, $li) { + if (type !== 'click') return; + + var self = this; + var ir_model = new Model("ir.model"); + + this.fields().then(function(fields) { + // Make a nice array to render the select input + var fields_array = _.map(fields, function(v, k){return {id: k, name: v.name, display_name: v.string}}); + // Filter the fields to remove the ones already in the form + var fields_in_form = _.map(self.$target.find('.control-label'), function(label){return label.getAttribute('for')}); + var available_fields = _.filter(fields_array, function(field){return !_.contains(fields_in_form, field.name)}) + // Render the select input + var field_selection = qweb.render("website_form_editor.field_many2one", { + field: { + name: 'field_selection', + string: 'Field', + records: _.sortBy(available_fields, 'display_name') + } + }); + + // Form parameters modal + self.build_modal( + "Field Parameters", + field_selection, + function(){ + var selected_field_name = self.$modal.find("[name='field_selection']").val(); + var selected_field = fields[selected_field_name]; + self.append_field(selected_field); + } + ); + + self.$modal.find("[name='field_selection']").on('change', function() { + console.log('changed'); + }); + }); + }, + + // Create a custom field + website_form_custom_field: function(type, value, $li) { + if (type !== 'click') return; + + var default_field_name = 'Custom ' + $li.text(); + this.append_field({ + name: default_field_name, + string: default_field_name, + custom: true, + type: value, + // Default values for x2many fields + records: [ + { + id: 'Option 1', + display_name: 'Option 1' + }, + { + id: 'Option 2', + display_name: 'Option 2' + }, + { + id: 'Option 3', + display_name: 'Option 3' + } + ], + // Default values for selection fields + selection: [ + [ + 'Option 1', + 'Option 1' + ], + [ + 'Option 2', + 'Option 2' + ], + [ + 'Option 3', + 'Option 3' + ], + ] + }); + }, + + // Re-render the field and replace the current one + // website_form_editor_field_reset: function(type, value, $li) { + // if (type !== 'click') return; + // var self = this; + // var target_field_name = this.$target.find('.control-label').attr('for'); + // this.fields().then(function(fields){ + // self.render_field(fields[target_field_name]).done(function(field){ + // self.$target.replaceWith(field); + // }) + // }); + // }, + + toggle_email_to: function() { + // Display or remove the magic email_to field for model mail.mail + var selected_model_name = this.$modal.find("[name='model_selection']").val(); + if (selected_model_name != 'mail.mail') { + this.$modal.find(".form-field:has(input[name='email_to'])").remove(); + } else { + this.$modal.find("form").append( + // Email To input + $(qweb.render("website_form_editor.field_char", { + field: { + name: 'email_to', + string: 'Recipient email', + required: true, + value: this.$target.find("input[name='email_to']").val() + } + })) + ); + } + }, + + append_field: function(field) { + var self = this; + this.render_field(field).done(function(field){ + self.$target.find(".form-group:has('.o_website_form_send')").before(field); + }); + }, + + render_field: function(field) { + var self = this; + var field_rendered = $.Deferred(); + + // Convert the required boolean to a value directly usable + // in qweb js to avoid duplicating this in the templates + field.required = field.required ? 1 : null; + + // Fetch possible values for relation fields + var fetch_field_relation = $.Deferred(); + if(field.relation && field.relation != 'ir.attachment') { + ajax.jsonRpc('/web/dataset/call_kw', 'call', { + model: field.relation, + method: 'search_read', + args: [ + field.domain, + ['display_name'] + ], + kwargs:{"context": base.get_context()} + }).then(function (records) { + field.records = records; + fetch_field_relation.resolve(); + }); + } + else { + fetch_field_relation.resolve(); + } + + fetch_field_relation.done(function() { + field_rendered.resolve( + qweb.render("website_form_editor.field_" + field.type, {field: field}) + ); + }); + + return field_rendered; + }, + + drop_and_build_snippet: function () { + // Open the parameters modal on snippet drop + this.website_form_model_modal('click', null, null); + }, + + init_form: function(model_name) { + var self = this; + if (model_name != this.$target.attr('data-model_name')) { + // Reset the form + this.$target.attr('data-model_name', model_name); + this.$target.find(".form-field:not(:has('.o_website_form_send'))").remove(); + + // Force fetch the fields of the new model + // and render all model required fields + this.fetch_model_fields().then(function(fields) { + _.each(fields, function(field, field_name){ + if (field.required) { + self.append_field(field); + } + }); + }); + } + }, + + clean_for_save: function () { + // Prevent saving of the error colors // TODO: would be better on Edit + this.$target.find('.has-error').removeClass('has-error'); + + // Prevent saving of the status message // TODO: would be better on Edit + this.$target.find('#o_website_form_result').empty(); + + // Update values of custom inputs to mirror their labels + var custom_inputs = this.$target.find('.o_website_form_custom .o_website_form_input'); + _.each(custom_inputs, function(input, index) { + // Change the custom field name according to their label + var field_label = $(input).closest('.form-field').find('label:first'); + input.name = field_label.text().trim(); + field_label.attr('for', input.name); + + // Change the custom radio or checkboxes values according to their label + if (input.type == 'radio' || input.type =='checkbox') { + var checkbox_label = $(input).closest('label').text().trim(); + if (checkbox_label) { + input.value = checkbox_label; + } + } + }); + } + }); + + // Generic custom field options + options.registry['website_form_editor_field'] = options.Class.extend({ + // Option to toggle inputs required attribute + website_form_field_require: function(type, value, $li) { + if (type !== 'click') return; + + this.$target.find('.o_website_form_input').each(function(index, input) { + input.required = !input.required; + }); + } + }); + + // Dirty hack to transform select fields into an editable construct + options.registry['website_form_editor_field_select'] = options.Class.extend({ + start: function() { + if (!this.$target.find('#editable_select').length) { + var self = this; + var select = this.$target.find('select') + select.hide(); + this.editable_select = $('
'); + _.each(select.children(), function(option) { + self.editable_select.append( + $('
' + $(option).text().trim() + '
') + ); + }); + select.after(this.editable_select); + } + }, + + clean_for_save: function() { + if (this.$target.find('#editable_select').length) { + var self = this; + // Reconstruct the field from the select tag + var select = this.$target.find('select'); + var field = { + name: select.attr('name'), + string: this.$target.find('.control-label').text().trim(), + required: self.$target.hasClass('o_website_form_required'), + custom: self.$target.hasClass('o_website_form_custom'), + } + + // Build the new records list from the editable select field + var records = []; + var editable_options = this.$target.find('#editable_select .o_website_form_select_item'); + _.each(editable_options, function(option) { + records.push({ + id: self.$target.hasClass('o_website_form_custom') ? $(option).text().trim() : $(option).attr('id'), + display_name: $(option).text().trim() + }); + }); + field.records = records; + + // Replace this field by the new one + var $new_select = $(qweb.render("website_form_editor.field_many2one", {field: field})); + // Reapply the custom style classes + if (this.$target.hasClass('o_website_form_required_custom')) { + $new_select.addClass('o_website_form_required_custom'); + } + if (this.$target.hasClass('o_website_form_field_hidden')) { + $new_select.addClass('o_website_form_field_hidden'); + } + this.$target.replaceWith($new_select); + } + } + }); + + // Superclass for options that need to disable a button from the snippet overlay + var disable_overlay_button_option = options.Class.extend({ + // Disable a button of the snippet overlay + disable_button: function(button_name, message) { + this.$overlay.on('click', '.oe_snippet_' + button_name, this.prevent_button); + var remove_button = this.$overlay.find('.oe_snippet_' + button_name); + remove_button.css('background-color', 'lightgray'); + remove_button.attr('title', message); + }, + + prevent_button: function(event) { + // Snippet options bind their functions before the editor, so we + // can't cleanly unbind the editor on_remove function from here + event.preventDefault(); + event.stopImmediatePropagation(); + } + }); + + // Disable duplicate button for model fields + options.registry['website_form_editor_field_model'] = disable_overlay_button_option.extend({ + start: function() { + this.disable_button('clone', 'You can\'t duplicate a model field.'); + } + }); + + // Disable delete button for model required fields + options.registry['website_form_editor_field_required'] = disable_overlay_button_option.extend({ + start: function() { + this.disable_button('remove', 'You can\'t remove a field that is required by the model itself.'); + } + }); + + // Disable duplicate button for non-custom checkboxes and radio buttons + options.registry['website_form_editor_field_x2many'] =disable_overlay_button_option.extend({ + start: function() { + this.disable_button('clone', 'You can\'t duplicate an item which refers to an actual record.'); + } + }); + +}); \ No newline at end of file diff --git a/static/src/js/website_form_editor_tour.js b/static/src/js/website_form_editor_tour.js new file mode 100644 index 00000000000..0423b6c05a5 --- /dev/null +++ b/static/src/js/website_form_editor_tour.js @@ -0,0 +1,620 @@ +odoo.define('website_form_editor.tour', function(require) { + 'use strict'; + + var base = require('web_editor.base'); + var core = require('web.core'); + var Tour = require('web.Tour'); + var Model = require('web.Model'); + var Session = require('web.Session'); + + base.ready().done(function () { + Tour.register({ + id: 'website_form_editor_tour', + name: "Try to create some forms", + path: '/', + mode: 'test', + steps: [ + // Drop a form builder snippet and configure it + { + title: "Enter edit mode", + element: "button[data-action=edit]" + }, + { + title: "Drop the form snippet", + snippet: "#snippet_feature .oe_snippet[name='Form Builder']" + }, + { + title: "Check if the snippet is dropped and if the modal is opened", + waitFor: "body:has(form[action*='/website_form/'])" + + ":has(.modal-body:has(select[name='model_selection'])" + + ":has(input[name='success_page']))" + }, + { + title: "Change the action to create issues", + element: ".modal-body select", + sampleText: "project.issue" + + }, + { + title: "Change the action to Send an E-mail", + // waitFor: ".modal-body .o_form-action-mailto:hidden", + element: ".modal-body select", + sampleText: "mail.mail" + }, + { + title: "Complete Recipient E-mail", + waitFor: ".modal-body input[name='email_to']", + element: ".modal-body input[name='email_to']", + sampleText: "test@test.test" + }, + { + title: "Click on Save", + element: ".modal-footer #modal-save" + }, + // Add the display_name field + { + title: "Click on Form snippet", + element: ".s_website_form[data-model_name]" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Add a model field", + element: ".oe_overlay_options:visible li[data-website_form_field_modal] a" + }, + { + title: "Select the display_name field", + element: "select[name='field_selection']", + sampleText: "display_name" + }, + { + title: "Click on Save", + element: ".modal-footer #modal-save" + }, + + // Customize display_name field + { + title: "Change the label", + element: ".control-label[for='display_name']", + sampleText: "Name" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Required", + element: ".oe_overlay_options:visible li[data-website_form_field_require] a" + }, + { + title: "Check the resulting field", + waitFor: ".form-field.o_website_form_required_custom" + + ":has(input[type=text][name=display_name][required])" + + ":has(label:contains('Name'))" + }, + + // Add record_name field + { + title: "Click on Form snippet", + element: ".s_website_form[data-model_name]" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Add a model field", + element: ".oe_overlay_options:visible li[data-website_form_field_modal] a" + }, + { + title: "Select the display_name field", + element: "select[name='field_selection']", + sampleText: "record_name" + }, + { + title: "Click on Save", + element: ".modal-footer #modal-save" + }, + + // Customize record_name field + { + title: "Change the label", + element: ".control-label[for='record_name']", + sampleText: "Awesome Label" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Hidden", + element: ".oe_overlay_options:visible li[data-toggle_class='o_website_form_field_hidden'] a" + }, + { + title: "Check the resulting field", + waitFor: ".form-field.o_website_form_field_hidden" + + ":has(input:not([required])[type=text][name=record_name])" + + ":has(label:contains('Awesome Label'))" + }, + + + // Add body_html field + { + title: "Click on Form snippet", + element: ".s_website_form[data-model_name]" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Add a model field", + element: ".oe_overlay_options:visible li[data-website_form_field_modal] a" + }, + { + title: "Select the display_name field", + element: "select[name='field_selection']", + sampleText: "body_html" + }, + { + title: "Click on Save", + element: ".modal-footer #modal-save" + }, + + // Customize display_name field + { + title: "Change the label", + element: ".control-label[for='body_html']", + sampleText: "Your Message" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Required", + element: ".oe_overlay_options:visible li[data-website_form_field_require] a" + }, + { + title: "Check the resulting field", + waitFor: ".form-field.o_website_form_required_custom" + + ":has(textarea[name=body_html][required])" + + ":has(label:contains('Your Message'))" + }, + + // Add a custom multiple checkboxes field + { + title: "Click on Form snippet", + element: ".s_website_form[data-model_name]", + onend: function() { + // I didn't find any other way to make that submenu element appear + $(".oe_options > ul > li:has(ul) > ul").css("display", "block"); + } + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Multiple Checkboxes in menu Add a custom field", + element: ".oe_options li a:contains('Multiple Checkboxes')" + }, + + // Customize custom multiple checkboxes field + { + title: "Change the label", + element: ".control-label[for='Custom Multiple Checkboxes']", + sampleText: "Products" + }, + { + title: "Change Option 1 label", + element: "label:contains('Option 1') span", + sampleText: "Iphone" + }, + { + title: "Change Option 2 label", + element: "label:contains('Option 2') span", + sampleText: "Galaxy S" + }, + { + title: "Click on Option 3", + element: "label:contains('Option 3') span", + }, + { + title: "Duplicate Option 3", + element: ".oe_overlay_options:visible .oe_snippet_clone", + }, + { + title: "Change first Option 3 label", + element: "label:contains('Option 3'):first span", + sampleText: "Xperia" + }, + { + title: "Change last Option label", + element: "label:contains('Option 3') span", + sampleText: "Wiko Stairway" + }, + { + title: "Click on field", + element: ".control-label:contains('Products')" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Required", + element: ".oe_overlay_options:visible li[data-website_form_field_require] a" + }, + { + title: "Check the resulting field", + waitFor: ".form-field.o_website_form_custom.o_website_form_required_custom" + + ":has(.control-label:contains('Products'))" + + ":has(.checkbox label:contains('Iphone'):has(input[type='checkbox'][required]))" + + ":has(.checkbox label:contains('Galaxy S'):has(input[type='checkbox'][required]))" + + ":has(.checkbox label:contains('Xperia'):has(input[type='checkbox'][required]))" + + ":has(.checkbox label:contains('Wiko Stairway'):has(input[type='checkbox'][required]))" + }, + + // Add a custom radio field + { + title: "Click on Form snippet", + element: ".s_website_form[data-model_name]", + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Radio Buttons in menu Add a custom field", + element: ".oe_options li a:contains('Radio Buttons')" + }, + + // Customize custom multiple checkboxes field + { + title: "Change the label", + element: ".control-label[for='Custom Radio Buttons']", + sampleText: "Service" + }, + { + title: "Change Option 1 label", + element: "label:contains('Option 1') span", + sampleText: "After-sales Service" + }, + { + title: "Change Option 2 label", + element: "label:contains('Option 2') span", + sampleText: "Invoicing Service" + }, + { + title: "Click on Option 3", + element: "label:contains('Option 3') span", + }, + { + title: "Duplicate Option 3", + element: ".oe_overlay_options:visible .oe_snippet_clone", + }, + { + title: "Change first Option 3 label", + element: "label:contains('Option 3'):first span", + sampleText: "Development Service" + }, + { + title: "Change last Option label", + element: "label:contains('Option 3') span", + sampleText: "Management Service" + }, + { + title: "Click on field", + element: ".control-label:contains('Service')" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Required", + element: ".oe_overlay_options:visible li[data-website_form_field_require] a" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Required", + element: ".oe_overlay_options:visible li[data-website_form_field_require] a" + }, + { + title: "Check the resulting field", + waitFor: ".form-field.o_website_form_custom:not(.o_website_form_required_custom)" + + ":has(.control-label:contains('Service'))" + + ":has(.radio label:contains('After-sales Service'):has(input[type='radio']:not([required])))" + + ":has(.radio label:contains('Invoicing Service'):has(input[type='radio']:not([required])))" + + ":has(.radio label:contains('Development Service'):has(input[type='radio']:not([required])))" + + ":has(.radio label:contains('Management Service'):has(input[type='radio']:not([required])))" + }, + + + // Add a custom selection field + { + title: "Click on Form snippet", + element: ".s_website_form[data-model_name]", + onend: function() { + // I didn't find any other way to make that submenu element appear + $(".oe_options > ul > li:has(ul) > ul").css("display", "block"); + } + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Selection in menu Add a custom field", + element: ".oe_options li a:contains('Selection')" + }, + + // Customize custom selection field + { + title: "Change the label", + element: ".control-label[for='Custom Selection']", + sampleText: "State" + }, + { + title: "Change Option 1 Label", + element: ".o_website_form_select_item:contains('Option 1')", + sampleText: "Germany" + }, + { + title: "Change Option 2 Label", + element: ".o_website_form_select_item:contains('Option 2')", + sampleText: "Belgium" + }, + { + title: "Click on Option 3", + element: ".o_website_form_select_item:contains('Option 3')", + }, + { + title: "Duplicate Option 3", + element: ".oe_overlay_options:visible .oe_snippet_clone", + }, + { + title: "Change first Option 3 label", + element: ".o_website_form_select_item:contains('Option 3'):first", + sampleText: "France" + }, + { + title: "Change last Option label", + element: ".o_website_form_select_item:contains('Option 3')", + sampleText: "Canada" + }, + { + title: "Click on Germany Option", + element: ".o_website_form_select_item:contains('Germany')", + }, + { + title: "Remove Germany Option", + element: ".oe_overlay_options:visible .oe_snippet_remove", + }, + { + title: "Click on field", + element: ".control-label:contains('State')" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Required", + element: ".oe_overlay_options:visible li[data-website_form_field_require] a" + }, + { + title: "Check the resulting snippet", + waitFor: ".form-field.o_website_form_custom.o_website_form_required_custom" + + ":has(label:contains('State'))" + + ":has(select[required]:hidden)" + + ":has(.o_website_form_select_item:contains('Belgium'))" + + ":has(.o_website_form_select_item:contains('France'))" + + ":has(.o_website_form_select_item:contains('Canada'))" + + ":not(:has(.o_website_form_select_item:contains('Germany')))" + }, + + // Add attachment_ids field + { + title: "Click on Form snippet", + element: ".s_website_form[data-model_name]" + }, + { + title: "Click on Customize", + element: ".oe_overlay_options:visible a[title='Customize']" + }, + { + title: "Click on Add a model field", + element: ".oe_overlay_options:visible li[data-website_form_field_modal] a" + }, + { + title: "Select the display_name field", + element: "select[name='field_selection']", + sampleText: "attachment_ids" + }, + { + title: "Click on Save", + element: ".modal-footer #modal-save" + }, + + // Customize attachment_ids field + { + title: "Change the label", + element: ".control-label[for='attachment_ids']", + sampleText: "Invoice Scan" + }, + { + title: "Check the resulting field", + waitFor: ".form-field" + + ":has(input[type=file][name=attachment_ids])" + + ":has(label:contains('Invoice Scan'))" + }, + + // Save the page + { + title: "Save the page", + element: "button[data-action=save]", + onload: function (tour) { + setTimeout(function(){ + $('html').append('
'); + }, 1000); + } + }, + { + title: "Wait reloading...", + waitFor: "#completlyloaded", + onload: function (tour) { + $("#completlyloaded").remove(); + } + } + ] + }); + + Tour.register({ + id: 'website_form_editor_tour_submit', + name: "Check created form works correctly", + path: '', + mode: 'test', + steps: [ + { + title: "Try to send empty form", + waitFor: "form[data-model_name='mail.mail']" + + "[data-success_page='']" + + ":has(.form-field:has(label:contains('Name')):has(input[type='text'][name='display_name'][required]))" + + ":has(.form-field:has(label:contains('Awesome Label')):hidden)" + + ":has(.form-field:has(label:contains('Your Message')):has(textarea[name='body_html'][required]))" + + ":has(.form-field:has(label:contains('Products')):has(input[type='checkbox'][name='Products'][value='Iphone'][required]))" + + ":has(.form-field:has(label:contains('Products')):has(input[type='checkbox'][name='Products'][value='Galaxy S'][required]))" + + ":has(.form-field:has(label:contains('Products')):has(input[type='checkbox'][name='Products'][value='Xperia'][required]))" + + ":has(.form-field:has(label:contains('Products')):has(input[type='checkbox'][name='Products'][value='Wiko Stairway'][required]))" + + ":has(.form-field:has(label:contains('Service')):has(input[type='radio'][name='Service'][value='After-sales Service']:not([required])))" + + ":has(.form-field:has(label:contains('Service')):has(input[type='radio'][name='Service'][value='Invoicing Service']:not([required])))" + + ":has(.form-field:has(label:contains('Service')):has(input[type='radio'][name='Service'][value='Development Service']:not([required])))" + + ":has(.form-field:has(label:contains('Service')):has(input[type='radio'][name='Service'][value='Management Service']:not([required])))" + + ":has(.form-field:has(label:contains('State')):has(select[name='State'][required]:has(option[value='Belgium'])))" + + ":has(.form-field.o_website_form_required_custom:has(label:contains('State')):has(select[name='State'][required]:has(option[value='France'])))" + + ":has(.form-field:has(label:contains('State')):has(select[name='State'][required]:has(option[value='Canada'])))" + + ":has(.form-field:has(label:contains('Invoice Scan')))" + + ":has(input.form-field[name='email_to'][value='test@test.test'])", + element: ".o_website_form_send" + }, + { + title: "Check if required fields were detected and complete the Name field", + waitFor: "form:has(#o_website_form_result.text-danger)" + + ":has(.form-field:has(label:contains('Name')).has-error)" + + ":has(.form-field:has(label:contains('Your Message')).has-error)" + + ":has(.form-field:has(label:contains('Products')).has-error)" + + ":has(.form-field:has(label:contains('Service')):not(.has-error))" + + ":has(.form-field:has(label:contains('State')):not(.has-error))" + + ":has(.form-field:has(label:contains('Invoice Scan')):not(.has-error))", + element: "input[name=display_name]", + sampleText: "Jane Smith" + }, + { + title: "Update required field status by trying to Send again", + element: ".o_website_form_send" + }, + { + title: "Check if required fields were detected and complete the Message field", + waitFor: "form:has(#o_website_form_result.text-danger)" + + ":has(.form-field:has(label:contains('Name')):not(.has-error))" + + ":has(.form-field:has(label:contains('Your Message')).has-error)" + + ":has(.form-field:has(label:contains('Products')).has-error)" + + ":has(.form-field:has(label:contains('Service')):not(.has-error))" + + ":has(.form-field:has(label:contains('State')):not(.has-error))" + + ":has(.form-field:has(label:contains('Invoice Scan')):not(.has-error))", + element: "textarea[name=body_html]", + sampleText: "A useless message" + }, + { + title: "Update required field status by trying to Send again", + element: ".o_website_form_send" + }, + { + title: "Check if required fields was detected and check a product", + waitFor: "form:has(#o_website_form_result.text-danger)" + + ":has(.form-field:has(label:contains('Name')):not(.has-error))" + + ":has(.form-field:has(label:contains('Your Message')):not(.has-error))" + + ":has(.form-field:has(label:contains('Products')).has-error)" + + ":has(.form-field:has(label:contains('Service')):not(.has-error))" + + ":has(.form-field:has(label:contains('State')):not(.has-error))" + + ":has(.form-field:has(label:contains('Invoice Scan')):not(.has-error))", + element: "input[name=Products][value='Wiko Stairway']" + }, + { + title: "Check another product", + element: "input[name='Products'][value='Xperia']" + }, + { + title: "Check a service", + element: "input[name='Service'][value='Development Service']" + }, + { + title: "Send the form", + element: ".o_website_form_send" + }, + { + title: "Check form is submitted without errors", + waitFor: "form:has(#o_website_form_result.text-success)" + + ":has(.form-field:has(label:contains('Name')):not(.has-error))" + + ":has(.form-field:has(label:contains('Your Message')):not(.has-error))" + + ":has(.form-field:has(label:contains('Products')):not(.has-error))" + + ":has(.form-field:has(label:contains('Service')):not(.has-error))" + + ":has(.form-field:has(label:contains('State')):not(.has-error))" + + ":has(.form-field:has(label:contains('Invoice Scan')):not(.has-error))" + } + ] + }); + + Tour.register({ + id: 'website_form_editor_tour_results', + name: "Check records have been created", + path: '', + mode: 'test', + steps: [ + { + title: "Check mail.mail records have been created", + waitFor: ".o-apps", + onload: function (tour) { + var mailDef = new Model("mail.mail").call( + "search_read", + [ + // TODO: add other fields in domain ! + [ + ['email_to', '=', 'test@test.test'], + ['body_html', 'like', 'A useless message'], + ['body_html', 'like', 'Service : Development Service'], + ['body_html', 'like', 'State : Belgium'], + ['body_html', 'like', 'Products : Xperia,Wiko Stairway'] + ], + [] + ] + ); + var success = function(model, data) { + if(data.length) { + $('body').append('
'); + } + }; + mailDef.then(_.bind(success, this, 'mail_mail')); + } + }, + { + title: "Check mail.mail records have been created", + waitFor: "#website_form_editor_success_test_tour_mail_mail" + }, + { + title: "Final Step", + waitFor: "html" + } + ] + }); + }); + + return {}; +}); diff --git a/static/src/xml/website_form_editor.xml b/static/src/xml/website_form_editor.xml new file mode 100644 index 00000000000..ebea1000ad9 --- /dev/null +++ b/static/src/xml/website_form_editor.xml @@ -0,0 +1,231 @@ + + + + + + + + + + +
+
+ +
+
+ +
+
+
+ + + + + + + + + + + +