[MERGE] website_form: add some usability imp to the form builder

Note: the form builder will be refactored in a deeper way in a next update.
See sub-commits for details.

task-1874350

Thanks to @dbh-odoo @pna-odoo and @dja-odoo for the work on this task.

closes odoo/odoo#30595

Signed-off-by: Quentin Smetz (qsm) <qsm@odoo.com>
This commit is contained in:
Odoo's Mergebot
2019-11-07 11:51:35 +01:00
committed by GitHub
5 changed files with 152 additions and 52 deletions
@@ -32,6 +32,10 @@ odoo.define('website_form_editor', function (require) {
close: true
}],
}, options));
this.opened(() => {
this.$modal.find('.o_website_form_input, .modal-footer .btn').first().focus();
});
},
//----------------------------------------------------------------------
@@ -309,6 +313,12 @@ odoo.define('website_form_editor', function (require) {
append_field: function (field) {
var self = this;
// Copy formatting classes of last row (field)
var $lastField = this.$target.find('.form-field.row:last');
field.formatInfo = {
labelClass: $lastField.find('> div:first').attr('class'),
contentClass: $lastField.find('> div:last').attr('class'),
};
this.render_field(field).then(function (field){
self.$target.find(".form-group:has('.o_website_form_send')").before(field);
});
@@ -359,32 +369,56 @@ odoo.define('website_form_editor', function (require) {
init_form: function () {
var self = this;
var modelName = this.activeForm.model;
var currentModel = this.$target.attr('data-model_name');
var formKey = this.activeForm.website_form_key;
if (modelName !== this.$target.attr('data-model_name')) {
this.$target.attr('data-model_name', modelName);
this.$target.find(".form-field:not(:has('.o_website_form_send')), .o_form_heading").remove();
if (!currentModel) {
// Directly change the parameters if model is being set for the first time
this.changeFormParameters(modelName, formKey);
} else if (modelName !== currentModel) {
var warningMessage = _t("Are you sure you want to change the parameters of your form? All the current fields will be discarded.");
new Dialog(this, {
title: _t("Warning"),
size: 'medium',
$content: $('<div>', {text: warningMessage}),
buttons: [{
text: _t("Ok"),
classes: 'btn-primary',
click: function () {
self.changeFormParameters(modelName, formKey);
},
close: true,
}, {
text: _t("Discard"),
close: true,
}],
}).open({shouldFocusButtons: true});
}
},
if (formKey) {
var formInfo = FormEditorRegistry.get(formKey);
ajax.loadXML(formInfo.defaultTemplatePath, qweb).then(function () {
// Append form title
$('<h1>', {
class: 'o_form_heading',
text: self.activeForm.website_form_label,
}).prependTo(self.$target.find('.container'));
self.$target.find('.form-group:has(".o_website_form_send")').before($(qweb.render(formInfo.defaultTemplateName)));
changeFormParameters: function (modelName, formKey) {
var self = this;
this.$target.attr('data-model_name', modelName);
this.$target.find(".form-field:not(:has('.o_website_form_send')), .o_form_heading").remove();
if (formKey) {
var formInfo = FormEditorRegistry.get(formKey);
ajax.loadXML(formInfo.defaultTemplatePath, qweb).then(function () {
// Append form title
$('<h1>', {
class: 'o_form_heading',
text: self.activeForm.website_form_label,
}).prependTo(self.$target.find('.container'));
self.$target.find('.form-group:has(".o_website_form_send")').before($(qweb.render(formInfo.defaultTemplateName)));
});
} else {
// 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);
}
});
} else {
// 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);
}
});
});
}
});
}
},
@@ -434,6 +468,34 @@ odoo.define('website_form_editor', function (require) {
}
});
// radio / checkboxes field option to display them horizontally or vertically
options.registry['website_form_editor_choice_field_display'] = options.Class.extend({
xmlDependencies: ['/website_form/static/src/xml/website_form_editor.xml'],
/**
* @see this.selectClass for parameters
*/
website_form_choice_field_display: function (previewMode, value, $opt) {
this.$target.toggleClass('o_website_form_flex_fw', value === 'vertical');
this.$target[0].dataset.display = value;
},
//----------------------------------------------------------------------
// Private
//----------------------------------------------------------------------
/**
* @override
*/
_setActive: function () {
this._super(...arguments);
this.$el.find('[data-website_form_choice_field_display]')
.removeClass('active')
.filter('[data-website_form_choice_field_display=' + this.$target.attr('data-display') + ']')
.addClass('active');
},
});
// Generic custom field options
options.registry['website_form_editor_field'] = options.Class.extend({
xmlDependencies: ['/website_form/static/src/xml/website_form_editor.xml'],
@@ -475,6 +537,10 @@ odoo.define('website_form_editor', function (require) {
string: this.$target.find('.col-form-label').text().trim(),
required: self.$target.hasClass('o_website_form_required'),
custom: self.$target.hasClass('o_website_form_custom'),
formatInfo: {
labelClass: this.$target.find('> div:first').attr('class'),
contentClass: this.$target.find('> div:last').attr('class'),
},
};
// Build the new records list from the editable select field
@@ -497,10 +563,6 @@ odoo.define('website_form_editor', function (require) {
if (this.$target.hasClass('o_website_form_field_hidden')) {
$new_select.addClass('o_website_form_field_hidden');
}
var labelClasses = this.$target.find('> div:first').attr('class');
var inputClasses = this.$target.find('> div:last').attr('class');
$new_select.find('> div:first').attr('class', labelClasses);
$new_select.find('> div:last').attr('class', inputClasses);
this.$target.replaceWith($new_select);
}
}
@@ -2,21 +2,24 @@
.o_website_form_flex {
display: flex;
flex-wrap: wrap;
}
.o_website_form_flex_item {
// col-lg-4
flex-basis: 33%;
// col-md-6
@include media-breakpoint-down(md) {
flex-basis: 50%;
}
// col-12
@include media-breakpoint-down(sm) {
&.o_website_form_flex_fw > .o_website_form_flex_item {
flex-basis: 100%;
}
&:not(.o_website_form_flex_fw) > .o_website_form_flex_item {
// col-lg-4
flex-basis: 33%;
// col-md-6
@include media-breakpoint-down(md) {
flex-basis: 50%;
}
// col-12
@include media-breakpoint-down(sm) {
flex-basis: 100%;
}
}
}
// Hidden field is only partially hidden in editor
@@ -4,12 +4,12 @@
<!-- Generic Field Layout -->
<t t-name="website_form.field">
<div t-att-class="'row form-group form-field' + (field.custom ? ' o_website_form_custom' : '') + (field.required ? ' o_website_form_required' : '')">
<div class="col-lg-3 col-md-4">
<div t-att-class="field.formatInfo and field.formatInfo.labelClass || 'col-lg-3 col-md-4'">
<label class="col-form-label" t-att-for="field.name">
<t t-esc="field.string"/>
</label>
</div>
<div class="col-lg-7 col-md-8">
<div t-att-class="field.formatInfo and field.formatInfo.contentClass || 'col-lg-7 col-md-8'">
<t t-raw="0"/>
</div>
</div>
@@ -39,6 +39,18 @@
</t>
</t>
<!-- Email Field -->
<t t-name="website_form.field_email">
<t t-call="website_form.field">
<input
type="email"
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.field_html">
<!--
@@ -115,23 +127,25 @@
<!-- Boolean Field -->
<t t-name="website_form.field_boolean">
<t t-call="website_form.field">
<input
type="checkbox"
value="Yes"
class="o_website_form_input"
t-att-name="field.name"
t-att-required="field.required"
/>
<div class="col-form-label">
<input
type="checkbox"
value="Yes"
class="o_website_form_input"
t-att-name="field.name"
t-att-required="field.required"
/>
</div>
</t>
</t>
<!-- Selection Field -->
<t t-name="website_form.field_selection">
<t t-call="website_form.field">
<div class="o_website_form_flex">
<div class="o_website_form_flex" data-display="horizontal">
<t t-foreach="field.selection" t-as="option">
<div class="radio o_website_form_flex_item">
<label>
<label class="col-form-label">
<input
type="radio"
class="o_website_form_input"
@@ -180,7 +194,7 @@
<!-- Generic one2many -->
<t t-if="field.relation != 'ir.attachment'">
<t t-call="website_form.field">
<div class="o_website_form_flex">
<div class="o_website_form_flex" data-display="horizontal">
<t t-if="!field.records">
<input
class="o_website_form_input"
@@ -192,7 +206,7 @@
</t>
<t t-foreach="field.records" t-as="record">
<div class="checkbox o_website_form_flex_item">
<label>
<label class="col-form-label">
<input
type="checkbox"
class="o_website_form_input"
@@ -240,10 +240,19 @@ odoo.define('website_form_editor.tour', function(require) {
content: "Click on Required",
trigger: "[data-website_form_field_require]"
},
{
content: "Click on first Check Box",
trigger: "label:contains('Iphone') span",
},
{
content: "Click on 'Vertical' in menu 'Display'",
trigger: "we-button:contains('Vertical')",
},
{
content: "Check the resulting field",
trigger: ".form-field.o_website_form_custom.o_website_form_required_custom" +
":has(.col-form-label:contains('Products'))" +
":has(.o_website_form_flex[data-display='vertical'])" +
":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]))" +
+12
View File
@@ -37,6 +37,7 @@
<we-collapse data-no-preview="true">
<we-button data-website_form_custom_field="char">Text</we-button>
<we-button data-website_form_custom_field="text">Long Text</we-button>
<we-button data-website_form_custom_field="email">Email</we-button>
<we-button data-website_form_custom_field="integer">Number</we-button>
<we-button data-website_form_custom_field="float">Decimal Number</we-button>
<we-button data-website_form_custom_field="boolean">Checkbox</we-button>
@@ -55,6 +56,17 @@
<we-button data-toggle-class="o_website_form_field_hidden" data-no-preview="true">Hidden</we-button>
</div>
<!-- Add an option to display radio buttons / checkboxes horizontally or vertically -->
<div data-js='website_form_editor_choice_field_display' data-selector=".o_website_form_flex">
<we-collapse-area>
<we-toggler>Display</we-toggler>
<we-collapse data-no-preview="true">
<we-button data-website_form_choice_field_display="horizontal">Horizontal</we-button>
<we-button data-website_form_choice_field_display="vertical">Vertical</we-button>
</we-collapse>
</we-collapse-area>
</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"/>