[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.
This commit is contained in:
@@ -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,
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
<record id="mail.model_mail_mail" model="ir.model">
|
||||
<field name="website_form_default_field_id" ref="mail.field_mail_mail_body_html" />
|
||||
<field name="website_form_access">True</field>
|
||||
<field name="website_form_label">Send an E-mail</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 536 B |
@@ -0,0 +1,470 @@
|
||||
odoo.define('website_form_editor', function (require) {
|
||||
'use strict';
|
||||
|
||||
var core = require('web.core');
|
||||
var ajax = require('web.ajax');
|
||||
var Model = require('web.Model');
|
||||
var base = require('web_editor.base');
|
||||
var options = require('web_editor.snippets.options');
|
||||
|
||||
var qweb = core.qweb;
|
||||
|
||||
qweb.add_template('/website_form_editor/static/src/xml/website_form_editor.xml');
|
||||
|
||||
options.registry['website_form_editor'] = options.Class.extend({
|
||||
|
||||
// Generic modal code
|
||||
build_modal: function(modal_title, modal_body, on_save) {
|
||||
var self = this;
|
||||
|
||||
// Build the form parameters modal
|
||||
var modal = qweb.render("website_form_editor.modal", {
|
||||
modal_title: modal_title,
|
||||
modal_body: modal_body
|
||||
});
|
||||
|
||||
self.$modal = $(modal);
|
||||
self.$modal.appendTo('body');
|
||||
|
||||
// Process the modal on_save then hide it
|
||||
self.$modal.find("#modal-save").on('click', function(){
|
||||
on_save();
|
||||
self.$modal.modal('hide');
|
||||
});
|
||||
|
||||
// Destroy the modal when it is closed, as we will use many of them
|
||||
self.$modal.on('hidden.bs.modal', function (e) {
|
||||
self.$modal.remove();
|
||||
})
|
||||
|
||||
self.$modal.modal();
|
||||
|
||||
return self.$modal;
|
||||
},
|
||||
|
||||
// Return the fields deferred if we already issued a model
|
||||
// fields fetch request, or issue said request.
|
||||
fields: function() {
|
||||
return this.fields_deferred || this.fetch_model_fields();
|
||||
},
|
||||
|
||||
fetch_model_fields: function() {
|
||||
var self = this;
|
||||
var ir_model = new Model("ir.model");
|
||||
|
||||
this.fields_deferred = new $.Deferred();
|
||||
ir_model.call(
|
||||
"search_read",
|
||||
[
|
||||
[['model', '=', this.$target.closest('form').attr('data-model_name')]],
|
||||
['id']
|
||||
],
|
||||
{
|
||||
context: base.get_context()
|
||||
}
|
||||
).then(function(model) {
|
||||
var model_id = model[0].id;
|
||||
|
||||
ir_model.call(
|
||||
"get_authorized_fields",
|
||||
[
|
||||
model_id
|
||||
],
|
||||
{
|
||||
context: base.get_context()
|
||||
}
|
||||
).then(function(fields) {
|
||||
// The get_fields function doesn't return the name
|
||||
// in the field dict since it uses it has the key
|
||||
_.map(fields, function(field, field_name){
|
||||
field.name = field_name;
|
||||
return field;
|
||||
});
|
||||
|
||||
self.fields_deferred.resolve(fields)
|
||||
})
|
||||
})
|
||||
|
||||
return this.fields_deferred;
|
||||
},
|
||||
|
||||
// Choose a model modal
|
||||
website_form_model_modal: function (type, value, $li) {
|
||||
if (type !== 'click') return;
|
||||
|
||||
var self = this;
|
||||
new Model("ir.model").call(
|
||||
"search_read",
|
||||
[
|
||||
[['website_form_access', '=', true]],
|
||||
['id', 'model', 'name', 'website_form_label']
|
||||
],
|
||||
{
|
||||
context: base.get_context()
|
||||
}
|
||||
).then(function(models) {
|
||||
// Models selection input
|
||||
var model_selection = qweb.render("website_form_editor.field_many2one", {
|
||||
field: {
|
||||
name: 'model_selection',
|
||||
string: 'Action',
|
||||
records: _.map(models, function(m){
|
||||
return {
|
||||
id: m.model,
|
||||
display_name: m.website_form_label || m.name,
|
||||
selected: (m.model == self.$target.attr('data-model_name')) ? 1: null
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Success page input
|
||||
var success_page = qweb.render("website_form_editor.field_char", {
|
||||
field: {
|
||||
name: 'success_page',
|
||||
string: 'Success Page',
|
||||
value: self.$target.attr('data-success_page')
|
||||
}
|
||||
});
|
||||
|
||||
// Form parameters modal
|
||||
self.build_modal(
|
||||
"Form Parameters",
|
||||
model_selection + success_page,
|
||||
function(){
|
||||
var model_name = self.$modal.find("[name='model_selection']").val();
|
||||
var success_page = self.$modal.find("[name='success_page']").val();
|
||||
self.init_form(model_name);
|
||||
self.$target.attr('data-success_page', success_page);
|
||||
|
||||
// Add magic email_to input if model is mail.mail
|
||||
self.$target.find("input.form-field[name='email_to']").remove();
|
||||
if (model_name == 'mail.mail') {
|
||||
var email_to = self.$modal.find("input[name='email_to']").val();
|
||||
self.$target.append("<input class='form-field' type='hidden' name='email_to' value=" + email_to + ">");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
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 = $('<div id="editable_select" class="form-control o_website_form_input"/>');
|
||||
_.each(select.children(), function(option) {
|
||||
self.editable_select.append(
|
||||
$('<div id="' + $(option).attr('value') + '" class="o_website_form_select_item">' + $(option).text().trim() + '</div>')
|
||||
);
|
||||
});
|
||||
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.');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
@@ -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('<div id="completlyloaded"></div>');
|
||||
}, 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('<div id="website_form_editor_success_test_tour_'+model+'"></div>');
|
||||
}
|
||||
};
|
||||
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 {};
|
||||
});
|
||||
@@ -0,0 +1,231 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<!-- Generic Modal Layout -->
|
||||
<t t-name="website_form_editor.modal">
|
||||
<div class="modal fade">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">&times;</span>
|
||||
</button>
|
||||
<h4 class="modal-title"><t t-esc="modal_title"/></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" role="form">
|
||||
<t t-raw="modal_body"/>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
<button type="button" class="btn btn-primary" id="modal-save">Save</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Generic Field Layout -->
|
||||
<t t-name="website_form_editor.field">
|
||||
<div t-att-class="'form-group form-field' + (field.custom ? ' o_website_form_custom' : '') + (field.required ? ' o_website_form_required' : '')">
|
||||
<div class="col-md-3 col-sm-4 text-right">
|
||||
<label class="control-label" t-att-for="field.name">
|
||||
<t t-esc="field.string"/>
|
||||
</label>
|
||||
</div>
|
||||
<div class="col-md-7 col-sm-8">
|
||||
<t t-raw="0"/>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<!-- Char Field -->
|
||||
<t t-name="website_form_editor.field_char">
|
||||
<t t-call="website_form_editor.field">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
t-att-required="field.required"
|
||||
t-att-value="field.value"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Text Field -->
|
||||
<t t-name="website_form_editor.field_text">
|
||||
<t t-call="website_form_editor.field">
|
||||
<textarea
|
||||
class="form-control o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
t-att-required="field.required"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- HTML Field -->
|
||||
<t t-name="website_form_editor.field_html">
|
||||
<!--
|
||||
Maybe use web_editor ? Not sure it actually makes
|
||||
sense to have random people editing html in a form...
|
||||
-->
|
||||
<t t-call="website_form_editor.field_text"/>
|
||||
</t>
|
||||
|
||||
<!-- Integer Field -->
|
||||
<t t-name="website_form_editor.field_integer">
|
||||
<t t-call="website_form_editor.field">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
step="1"
|
||||
t-att-required="field.required"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Float Field -->
|
||||
<t t-name="website_form_editor.field_float">
|
||||
<t t-call="website_form_editor.field">
|
||||
<input
|
||||
type="number"
|
||||
class="form-control o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
step="any"
|
||||
t-att-required="field.required"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Datetime Field -->
|
||||
<t t-name="website_form_editor.field_datetime">
|
||||
<t t-call="website_form_editor.field">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control o_website_form_input o_website_form_datetime"
|
||||
t-att-name="field.name"
|
||||
t-att-required="field.required"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Boolean Field -->
|
||||
<t t-name="website_form_editor.field_boolean">
|
||||
<t t-call="website_form_editor.field">
|
||||
<input
|
||||
type="checkbox"
|
||||
value="Yes"
|
||||
class="o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
t-att-required="field.required"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Selection Field -->
|
||||
<t t-name="website_form_editor.field_selection">
|
||||
<t t-call="website_form_editor.field">
|
||||
<div class="o_website_form_flex">
|
||||
<t t-foreach="field.selection" t-as="option">
|
||||
<div class="radio o_website_form_flex_item">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
class="o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
t-att-value="option[0]"
|
||||
t-att-required="field.required"
|
||||
/>
|
||||
<span>
|
||||
<t t-esc="option[1]"/>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Many2One Field -->
|
||||
<t t-name="website_form_editor.field_many2one">
|
||||
<!-- Binary one2many -->
|
||||
<t t-if="field.relation == 'ir.attachment'">
|
||||
<t t-call="website_form_editor.field_binary"/>
|
||||
</t>
|
||||
<!-- Generic one2many -->
|
||||
<t t-if="field.relation != 'ir.attachment'">
|
||||
<t t-call="website_form_editor.field">
|
||||
<select class="form-control o_website_form_input" t-att-name="field.name" t-att-required="field.required">
|
||||
<t t-foreach="field.records" t-as="record">
|
||||
<option t-att-value="record.id" t-att-selected="record.selected">
|
||||
<t t-esc="record.display_name"/>
|
||||
</option>
|
||||
</t>
|
||||
</select>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- One2Many Field -->
|
||||
<t t-name="website_form_editor.field_one2many">
|
||||
<!-- Binary one2many -->
|
||||
<t t-if="field.relation == 'ir.attachment'">
|
||||
<t t-call="website_form_editor.field_binary">
|
||||
<t t-set="multiple" t-value="1"/>
|
||||
</t>
|
||||
</t>
|
||||
<!-- Generic one2many -->
|
||||
<t t-if="field.relation != 'ir.attachment'">
|
||||
<t t-call="website_form_editor.field">
|
||||
<div class="o_website_form_flex">
|
||||
<t t-if="!field.records">
|
||||
<input
|
||||
class="o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
t-att-value="record.id"
|
||||
t-att-required="field.required"
|
||||
placeholder="No matching record !"
|
||||
/>
|
||||
</t>
|
||||
<t t-foreach="field.records" t-as="record">
|
||||
<div class="checkbox o_website_form_flex_item">
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
class="o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
t-att-value="record.id"
|
||||
t-att-required="field.required"
|
||||
/>
|
||||
<span>
|
||||
<t t-esc="record.display_name"/>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
<!-- Many2Many Field -->
|
||||
<t t-name="website_form_editor.field_many2many">
|
||||
<t t-call="website_form_editor.field_one2many"/>
|
||||
</t>
|
||||
|
||||
<!-- Binary Field -->
|
||||
<t t-name="website_form_editor.field_binary">
|
||||
<t t-call="website_form_editor.field">
|
||||
<input
|
||||
type="file"
|
||||
class="form-control o_website_form_input"
|
||||
t-att-name="field.name"
|
||||
t-att-required="field.required"
|
||||
t-att-multiple="multiple"
|
||||
/>
|
||||
</t>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
@@ -0,0 +1 @@
|
||||
import test_website_form_editor
|
||||
@@ -0,0 +1,8 @@
|
||||
import openerp.tests
|
||||
@openerp.tests.common.at_install(False)
|
||||
@openerp.tests.common.post_install(True)
|
||||
class TestWebsiteFormEditor(openerp.tests.HttpCase):
|
||||
def test_tour(self):
|
||||
self.phantom_js("/", "odoo.__DEBUG__.services['web.Tour'].run('website_form_editor_tour', 'test')", "odoo.__DEBUG__.services['web.Tour'].tours.website_form_editor_tour", login="admin")
|
||||
self.phantom_js("/", "odoo.__DEBUG__.services['web.Tour'].run('website_form_editor_tour_submit', 'test')", "odoo.__DEBUG__.services['web.Tour'].tours.website_form_editor_tour_submit")
|
||||
self.phantom_js("/", "odoo.__DEBUG__.services['web.Tour'].run('website_form_editor_tour_results', 'test')", "odoo.__DEBUG__.services['web.Tour'].tours.website_form_editor_tour_results", login="admin")
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="assets_editor" name="Website Form Editor Assets Editor" inherit_id="website.assets_editor">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/website_form_editor/static/src/js/website_form_editor.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<template id="assets_common" name="Website Form Editor Assets Common" inherit_id="web.assets_common">
|
||||
<xpath expr="." position="inside">
|
||||
<script type="text/javascript" src="/website_form_editor/static/src/js/website_form_editor_tour.js"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -0,0 +1,29 @@
|
||||
<odoo>
|
||||
|
||||
<record id="ir_model_view" model="ir.ui.view">
|
||||
<field name="name">website_form_editor.ir.model.view.form</field>
|
||||
<field name="model">ir.model</field>
|
||||
<field name="inherit_id" ref="base.view_model_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group" position="inside">
|
||||
<group>
|
||||
<field name="website_form_access"/>
|
||||
<field name="website_form_label"/>
|
||||
<field name="website_form_default_field_id"/>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="ir_model_fields_view" model="ir.ui.view">
|
||||
<field name="name">website_form_editor.ir.model.fields.view.form</field>
|
||||
<field name="model">ir.model.fields</field>
|
||||
<field name="inherit_id" ref="base.view_model_fields_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='translate']" position="after">
|
||||
<field name="website_form_blacklisted"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,74 @@
|
||||
<odoo>
|
||||
|
||||
<template id="snippet_options" inherit_id="website.snippet_options">
|
||||
<xpath expr="//div" position="after">
|
||||
|
||||
<!-- Form -->
|
||||
<div data-js='website_form_editor' data-selector='.s_website_form' data-drop-in=".oe_structure, [data-oe-type=html]">
|
||||
<li data-website_form_model_modal="">
|
||||
<a>Change Form Parameters</a>
|
||||
</li>
|
||||
<li data-website_form_field_modal="">
|
||||
<a>Add a model field</a>
|
||||
</li>
|
||||
<li class="dropdown-submenu">
|
||||
<a>Add a custom field</a>
|
||||
<ul class="dropdown-menu">
|
||||
<li data-website_form_custom_field="char"><a>Text</a></li>
|
||||
<li data-website_form_custom_field="text"><a>Long Text</a></li>
|
||||
<li data-website_form_custom_field="integer"><a>Number</a></li>
|
||||
<li data-website_form_custom_field="float"><a>Decimal Number</a></li>
|
||||
<li data-website_form_custom_field="boolean"><a>Checkbox</a></li>
|
||||
<li data-website_form_custom_field="selection"><a>Radio Buttons</a></li>
|
||||
<li data-website_form_custom_field="many2one"><a>Selection</a></li>
|
||||
<li data-website_form_custom_field="one2many"><a>Multiple Checkboxes</a></li>
|
||||
<li data-website_form_custom_field="binary"><a>File Upload</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<!-- Field -->
|
||||
<div data-js='website_form_editor' data-selector=".form-field" data-drop-near=".form-field">
|
||||
<!-- <li data-website_form_field_parameters="">
|
||||
<a>Field Parameters</a>
|
||||
</li> -->
|
||||
<!-- <li data-website_form_editor_field_reset="">
|
||||
<a>Reset Field</a>
|
||||
</li> -->
|
||||
<li data-toggle_class="o_website_form_field_hidden">
|
||||
<a>Hidden</a>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<!-- Add move, duplicate and remove controllers to checkboxes and radio buttons -->
|
||||
<div data-selector=".o_website_form_flex_item" data-drop-near=".o_website_form_flex_item"/>
|
||||
|
||||
<!-- Add move and remove controllers to select items -->
|
||||
<div data-selector=".s_website_form .form-field.o_website_form_custom .o_website_form_select_item" data-drop-near=".o_website_form_select_item"/>
|
||||
|
||||
<!-- Required option for fields that are not required fields of the model -->
|
||||
<div data-js='website_form_editor_field' data-selector=".form-field:not(.o_website_form_required)">
|
||||
<li data-website_form_field_require="" data-toggle_class="o_website_form_required_custom">
|
||||
<a>Required</a>
|
||||
</li>
|
||||
</div>
|
||||
|
||||
<!-- Remove the duplicate options of model fields -->
|
||||
<div data-js="website_form_editor_field_model" data-selector=".s_website_form .form-field:not(.o_website_form_custom)"/>
|
||||
|
||||
<!-- Remove the delete options of model required fields -->
|
||||
<div data-js="website_form_editor_field_required" data-selector=".s_website_form .o_website_form_required"/>
|
||||
|
||||
<!-- Remove the duplicate options of radio and checkboxes of model fields -->
|
||||
<div data-js="website_form_editor_field_x2many" data-selector=".s_website_form .form-field:not(.o_website_form_custom) .o_website_form_flex_item"/>
|
||||
|
||||
<!-- Transform the select inputs into editable constructs -->
|
||||
<div data-js="website_form_editor_field_select" data-selector=".s_website_form .form-field:has(select)"/>
|
||||
|
||||
<!-- Remove the duplicate option of model select items -->
|
||||
<div data-js="website_form_editor_field_x2many" data-selector=".s_website_form .form-field:not(.o_website_form_custom) .o_website_form_select_item" data-drop-near=".o_website_form_select_item"/>
|
||||
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
|
||||
<template id="s_website_form" name="Form Builder">
|
||||
<form action="/website_form/" method="post" class="s_website_form form-horizontal container-fluid mt32" enctype="multipart/form-data">
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-3 col-sm-offset-4 col-sm-8 col-md-7">
|
||||
<button class="btn btn-primary btn-lg o_website_form_send">Send</button>
|
||||
<span id="o_website_form_result"/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</template>
|
||||
|
||||
<template id="register_s_website_form" inherit_id="website.snippets" name="Snippet Form Builder">
|
||||
<xpath expr="//div[@id='snippet_feature']/div[contains(@class, 'o_panel_body')]" position="inside">
|
||||
<t t-snippet="website_form_editor.s_website_form" t-thumbnail="/website_form_editor/static/src/img/s_website_form.png"/>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
Reference in New Issue
Block a user