[REF] *: BS5: Migrate forms and inputs

- BS5 uses native inputs instead of pseudo-element for some
  input like checkbox, radio, ...
  in BS5 input checkbox don't have "virtual visual" checkbox anymore
  (::before), so we remove the relative's rules

- removed `.custom-control` class

- `form-switch` use a new layout system in BS5 we adapt the code to
  match the Bootstrap approach (inline SVG).

- In tests, we don't check the exact value of the background as it
  change in community/enterprise, and it's difficult to check the value
  of an SVG.

- Overflow in progressbar is now hidden.
  -> we had to restore it.

- In BS5 margins in forms/inputs has been changed
  -> we had to restore it (e.g. 'mb-3')

- .form-group, .form-row, .form-inline
> Dropped form-specific layout classes for our grid system.
> Use our grid and utilities instead of .form-group, .form-row,
> or .form-inline.

- .input-group-append and .input-group-prepend
> Dropped .input-group-append and .input-group-prepend.
> You can now just add buttons and .input-group-text as direct
> children of the input groups.

Ref:
[1] https://getbootstrap.com/docs/5.1/migration/#forms

Task ID: 2766483

Part-of: odoo/odoo#95450
This commit is contained in:
Romeo Fragomeli
2022-07-07 13:30:18 +02:00
parent b82ba2a8fd
commit 9ea1351334
56 changed files with 251 additions and 407 deletions
@@ -43,11 +43,9 @@
<div class="mx-3 mt-2 mb-3">
<div class="input-group">
<input class="form-control" type="text" t-att-value="channelInvitationForm.thread.invitationLink" readonly="" t-on-focus="channelInvitationForm.onFocusInvitationLinkInput" />
<div class="input-group-append">
<button class="btn btn-primary" t-on-click="channelInvitationForm.onClickCopy">
<i class="fa fa-copy"/>
</button>
</div>
<button class="btn btn-primary" t-on-click="channelInvitationForm.onClickCopy">
<i class="fa fa-copy"/>
</button>
</div>
<t t-if="channelInvitationForm.accessRestrictedToGroupText">
<div class="o_ChannelInvitationForm_accessRestrictedToGroup mt-2" t-esc="channelInvitationForm.accessRestrictedToGroupText"/>
+2 -6
View File
@@ -47,12 +47,8 @@
<div class="o_mail_group" t-att-data-id="group.id" t-att-data-is-member="force_unsubscribe or is_member">
<div class="input-group o_mg_subscribe_form">
<input type="email" name="email" class="o_mg_subscribe_email form-control" t-att-value="email" placeholder="your email..." t-att-readonly="int(bool(email))"/>
<div t-if="force_unsubscribe or is_member" class="input-group-append">
<button href="#" class="btn btn-outline-primary o_mg_subscribe_btn">Unsubscribe</button>
</div>
<div t-else="" class="input-group-append">
<button href="#" class="btn btn-primary o_mg_subscribe_btn">Subscribe</button>
</div>
<button t-if="force_unsubscribe or is_member" href="#" class="btn btn-outline-primary o_mg_subscribe_btn">Unsubscribe</button>
<button t-else="" href="#" class="btn btn-primary o_mg_subscribe_btn">Subscribe</button>
</div>
</div>
</div>
+11 -15
View File
@@ -321,23 +321,19 @@
</div>
<form t-if="searchbar_inputs" class="form-inline o_portal_search_panel ml-lg-4 col-xl-4 col-md-5">
<div class="input-group input-group-sm w-100">
<div class="input-group-prepend">
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown"/>
<div class="dropdown-menu" role="menu">
<t t-foreach='searchbar_inputs' t-as='input'>
<a t-att-href="'#' + input_value['input']"
t-attf-class="dropdown-item#{search_in == input_value['input'] and ' active' or ''}">
<span t-out="input_value['label']"/>
</a>
</t>
</div>
<button type="button" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown"/>
<div class="dropdown-menu" role="menu">
<t t-foreach='searchbar_inputs' t-as='input'>
<a t-att-href="'#' + input_value['input']"
t-attf-class="dropdown-item#{search_in == input_value['input'] and ' active' or ''}">
<span t-out="input_value['label']"/>
</a>
</t>
</div>
<input type="text" class="form-control form-control-sm" placeholder="Search" t-att-value='search' name="search"/>
<span class="input-group-append">
<button class="btn btn-secondary o_wait_lazy_js" type="submit">
<span class="fa fa-search"/>
</button>
</span>
<button class="btn btn-secondary o_wait_lazy_js" type="submit">
<span class="fa fa-search"/>
</button>
</div>
</form>
</div>
@@ -5,11 +5,9 @@
<span>
<div class="input-group">
<input type="number" name="qty_to_add" class="o_input o_product_qty form-control text-right" value="1" min="1"/>
<div class="input-group-append">
<button class="btn btn-secondary o_add_qty text-right form-control" type="submit" title="Add a quantity">
<i class="fa fa-plus"/>
</button>
</div>
<button class="btn btn-secondary o_add_qty text-right form-control" type="submit" title="Add a quantity">
<i class="fa fa-plus"/>
</button>
</div>
<span class="o_badges">
<t t-set="quantities" t-value="widget.quantities"/>
@@ -75,22 +75,18 @@
<t t-if="sale_order.state in ['draft', 'sent'] and line.sale_order_option_ids">
<div class="input-group js_quantity_container pull-right">
<div class="input-group-prepend d-print-none">
<span class="input-group-text d-none d-md-inline-block">
<a t-att-data-line-id="line.id" t-att-data-remove="True" href="#" class="js_update_line_json" aria-label="Remove one" title="Remove one">
<span class="fa fa-minus"/>
</a>
</span>
</div>
<span class="d-print-none input-group-text d-none d-md-inline-block">
<a t-att-data-line-id="line.id" t-att-data-remove="True" href="#" class="js_update_line_json" aria-label="Remove one" title="Remove one">
<span class="fa fa-minus"/>
</a>
</span>
<!-- TODO add uom in this case too -->
<input type="text" class="js_quantity form-control" t-att-data-line-id="line.id" t-att-value="line.product_uom_qty"/>
<div class="input-group-append d-print-none">
<span class="input-group-text d-none d-md-inline-block">
<a t-att-data-line-id="line.id" href="#" class="js_update_line_json" aria-label="Add one" title="Add one">
<span class="fa fa-plus"/>
</a>
</span>
</div>
<span class="d-print-none input-group-text d-none d-md-inline-block">
<a t-att-data-line-id="line.id" href="#" class="js_update_line_json" aria-label="Add one" title="Add one">
<span class="fa fa-plus"/>
</a>
</span>
</div>
</t>
<t t-else="">
@@ -8,17 +8,13 @@
<template id="product_quantity_config">
<div class="css_quantity input-group">
<div class="input-group-prepend">
<button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
<i class="fa fa-minus"></i>
</button>
</div>
<button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
<i class="fa fa-minus"></i>
</button>
<input type="text" class="js_quantity form-control quantity" data-min="1" name="add_qty" t-att-value="add_qty or 1"/>
<div class="input-group-append">
<button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
<i class="fa fa-plus"></i>
</button>
</div>
<button t-attf-href="#" class="btn btn-primary float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
<i class="fa fa-plus"></i>
</button>
</div>
</template>
@@ -19,13 +19,11 @@ var FormDescriptionPage = FieldChar.extend({
this.$el.addClass('col');
var $inputGroup = $('<div class="input-group">');
this.$el = $inputGroup.append(this.$el);
var $button = $(
'<div class="input-group-append">\
<button type="button" title="Open section" class="btn oe_edit_only o_icon_button">\
<i class="fa fa-fw o_button_icon fa-external-link"/>\
</button>\
</div>'
);
var $button = $(`
<button type="button" title="Open section" class="btn oe_edit_only o_icon_button">
<i class="fa fa-fw o_button_icon fa-external-link"/>
</button>
`);
this.$el = this.$el.append($button);
$button.on('click', this._onClickEdit.bind(this));
@@ -114,7 +114,7 @@ _::-webkit-full-page-media, _:future, :root .o_survey_wrap {
}
}
.o_survey_form_date .input-group-append {
.o_survey_form_date [data-toggle="datetimepicker"] {
right: 0;
bottom: 5px;
top: auto;
+5 -9
View File
@@ -381,9 +381,7 @@
t-att-name="question.id" t-att-placeholder="question.question_placeholder"
t-att-value="format_date(answer_lines[0].value_date) if answer_lines else None"
t-att-data-question-type="question.question_type"/>
<div t-if="not survey_form_readonly" class="input-group-append position-absolute" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker">
<div class="input-group-text text-primary border-0 bg-transparent p-0"><i class="fa fa-calendar"></i></div>
</div>
<div t-if="not survey_form_readonly" class="position-absolute input-group-text text-primary border-0 bg-transparent p-0" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker"><i class="fa fa-calendar"></i></div>
</div>
</template>
@@ -396,9 +394,7 @@
t-att-name="question.id" t-att-placeholder="question.question_placeholder"
t-att-value="format_datetime(answer_lines[0].value_datetime) if answer_lines else None"
t-att-data-question-type="question.question_type"/>
<div t-if="not survey_form_readonly" class="input-group-append position-absolute" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker">
<div class="input-group-text text-primary border-0 bg-transparent p-0"><i class="fa fa-calendar"></i></div>
</div>
<div t-if="not survey_form_readonly" class="position-absolute input-group-text text-primary border-0 bg-transparent p-0" t-attf-data-target="#datetimepicker_#{question.id}" data-toggle="datetimepicker"><i class="fa fa-calendar"></i></div>
</div>
</template>
@@ -460,7 +456,7 @@
</div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_comments col-lg-12" >
<div class="d-flex flex-wrap">
<label t-att-class="'o_survey_choice_btn mr-2 py-1 px-3 rounded %s' % ('o_survey_selected' if comment_line else '')">
<label t-att-class="'o_survey_choice_btn form-label mr-2 py-1 px-3 rounded %s' % ('o_survey_selected' if comment_line else '')">
<t t-set="item_idx" t-value="item_idx + 1"/>
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class" t-value="'position-relative o_survey_radio_btn float-left d-flex'"/>
@@ -505,7 +501,7 @@
<t t-set="answer_class" t-elif="is_correct" t-value="'bg-success'" />
<t t-set="answer_class" t-elif="not is_correct" t-value="'bg-danger'" />
<label t-att-class="'o_survey_choice_btn mr-2 py-1 px-3 rounded %s %s' % (answer_class, 'o_survey_selected' if answer_line else '')">
<label t-att-class="'o_survey_choice_btn form-label mr-2 py-1 px-3 rounded %s %s' % (answer_class, 'o_survey_selected' if answer_line else '')">
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class" t-value="'position-relative float-left d-flex'"/>
</t>
@@ -529,7 +525,7 @@
</div>
<div t-if='question.comments_allowed and question.comment_count_as_answer' class="js_ck_comments col-lg-12" >
<div class="d-flex flex-wrap">
<label t-att-class="'o_survey_choice_btn mr-2 py-1 px-3 rounded %s' % ('o_survey_selected' if comment_line else '')">
<label t-att-class="'o_survey_choice_btn form-label mr-2 py-1 px-3 rounded %s' % ('o_survey_selected' if comment_line else '')">
<t t-set="item_idx" t-value="item_idx + 1"/>
<t t-call="survey.survey_selection_key">
<t t-set="selection_key_class" t-value="'position-relative float-left d-flex'"/>
@@ -96,7 +96,7 @@
<div t-if="show_bar_chart or show_text_answers">
<div class="progress" title="Attendees are answering the question...">
<div class="progress-bar o_survey_session_progress_small font-weight-bold"
role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
style="overflow: visible" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
<span class="px-2">0 / <t t-esc="survey.session_answer_count" /></span>
</div>
</div>
@@ -2,18 +2,9 @@
// ============================================================================
.custom-control.custom-checkbox .custom-control-input {
// Force default bts default border color
&:not(:checked):not(:indeterminate):not(:disabled) ~ .custom-control-label:before {
border-color: $custom-control-indicator-border-color;
}
&:disabled {
~ .custom-control-label {
cursor: not-allowed;
&:before {
border-color: $custom-control-indicator-checked-disabled-bg;
}
}
&:checked ~ .custom-control-label:after {
@@ -7,11 +7,9 @@
<div class="o_command_palette_search input-group mb-2 px-4 py-3 border-bottom">
<span t-if="state.namespace !== 'default'" class="o_namespace d-flex align-items-center mr-1" t-out="state.namespace"/>
<input class="form-control border-0 p-0" type="text" data-allow-hotkeys="true" t-att-value="state.searchValue" t-ref="autofocus" t-att-placeholder="state.placeholder" t-on-input="onSearchInput" t-on-keydown="onKeyDown"/>
<span class="input-group-append">
<div class="input-group-text border-0 bg-transparent">
<i t-att-title="state.placeholder" role="img" t-att-aria-label="state.placeholder" class="oi oi-search"/>
</div>
</span>
<div class="input-group-text border-0 bg-transparent">
<i t-att-title="state.placeholder" role="img" t-att-aria-label="state.placeholder" class="oi oi-search"/>
</div>
</div>
<div t-ref="listbox" class="o_command_palette_listbox position-relative overflow-auto">
@@ -24,9 +24,7 @@
<label class="custom-control-label" for="profile_traces_async">Record traces</label>
</span>
<div t-if="profiling.isCollectorEnabled('traces_async')" class="input-group input-group-sm mt-2" t-on-click.stop.prevent="">
<div class="input-group-prepend">
<div class="input-group-text">Interval</div>
</div>
<div class="input-group-text">Interval</div>
<select class="profile_param form-control" t-on-change="(ev) => this.changeParam('traces_async_interval', ev)">
<t t-set="interval" t-value="profiling.state.params.traces_async_interval"/>
<option value="">Default</option>
@@ -43,7 +43,7 @@ var FieldBoolean = AbstractField.extend({
// the one rendered by the widget itself. Even though the event might
// have been fired on the non-widget version of this field, we can still
// test the presence of its custom class.
if (activated && options && options.event && $(options.event.target).closest('.custom-control.custom-checkbox').length) {
if (activated && options && options.event && $(options.event.target).closest('.custom-checkbox').length) {
this._setValue(!this.value); // Toggle the checkbox
}
return activated;
+3 -3
View File
@@ -480,16 +480,16 @@ var dom = {
renderCheckbox: function (options) {
var id = _.uniqueId('checkbox-');
var $container = $('<div/>', {
class: 'custom-control custom-checkbox',
class: 'form-check',
});
var $input = $('<input/>', {
type: 'checkbox',
id: id,
class: 'custom-control-input',
class: 'form-check-input',
});
var $label = $('<label/>', {
for: id,
class: 'custom-control-label',
class: 'form-check-label',
text: options && options.text || '',
});
if (!options || !options.text) {
@@ -2993,7 +2993,7 @@ var LabelSelection = AbstractField.extend({
var BooleanToggle = FieldBoolean.extend({
description: _lt("Toggle"),
className: FieldBoolean.prototype.className + ' o_boolean_toggle',
className: FieldBoolean.prototype.className + ' o_boolean_toggle form-switch',
isQuickEditable: true,
events: {
'click': '_onClick'
@@ -3014,13 +3014,6 @@ var BooleanToggle = FieldBoolean.extend({
*/
async _render() {
await this._super(...arguments);
const classToApply = this.value ? 'fa-check-circle' : 'fa-times-circle';
if (this.el.querySelector('i')) {
this.el.querySelector('i').remove();
}
const i = document.createElement("i");
i.setAttribute('class', `fa ${classToApply}`);
this.el.querySelector('label').appendChild(i);
const isReadonly = this.record.evalModifiers(this.attrs.modifiers).readonly || false;
this.$input.prop('disabled', isReadonly);
},
@@ -70,7 +70,7 @@ odoo.define('web.basic_fields_owl', function (require) {
// The event might have been fired on the non field version of
// this field, we can still test the presence of its custom class.
if (activated && options && options.event && options.event.target
.closest('.custom-control.custom-checkbox')) {
.closest('.custom-checkbox')) {
this._setValue(!this.value); // Toggle the checkbox
}
return activated;
@@ -212,3 +212,21 @@ $code-color: $o-main-code-color!default;
$kbd-color: $o-gray-700 !default;
$kbd-bg: $o-gray-100 !default;
$kbd-box-shadow: 0px 1px 1px rgba($o-black, 0.2), inset 0px -1px 1px 1px rgba($o-gray-200, 0.8), inset 0px 2px 0px 0px rgba($o-white, 0.8) !default;
// Input
$input-bg: $o-white !default;
$form-check-input-border-radius: 0 !default;
$form-check-input-checked-color: $o-brand-lightsecondary !default;
$form-check-input-checked-border-color: $o-brand-primary !default;
$form-check-input-checked-bg-color: $o-brand-primary !default;
$form-switch-color: rgba($black, .25) !default;
$form-switch-checked-color: $o-brand-primary !default;
$form-switch-circle-bg-color: $input-bg !default;
$form-switch-circle-checked-bg-color: $input-bg !default;
$form-switch-icon-color: $form-switch-color !default;
$form-switch-icon-checked-color: $form-switch-checked-color !default;
$form-switch-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-circle-bg-color}'/><line x1='-1.5' y1='-1.5' x2='1.5' y2='1.5' stroke='#{$form-switch-icon-color}' stroke-width='0.75'/><line x1='1.5' y1='-1.5' x2='-1.5' y2='1.5' stroke='#{$form-switch-icon-color}' stroke-width='0.75'/></svg>") !default;
$form-switch-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-circle-checked-bg-color}'/><path d='m-2.125,-0.5l1.75,1.75l2.5,-2.5' fill='none' stroke='#{$form-switch-icon-checked-color}' stroke-width='0.75'/></svg>") !default;
-12
View File
@@ -102,18 +102,6 @@
right: auto#{"/*rtl:ignore*/"};
}
// Review input group: BS allows to control button and input dimensions
// individually but fails to make input-group correctly in all cases (for some
// strange reasons they made it work well for sm and lg but not for the normal
// sizing).
.input-group-prepend,
.input-group-append {
> .btn {
@include button-size($input-padding-y, $input-padding-x, $input-font-size, $input-line-height, $input-border-radius);
border-width: $input-border-width;
}
}
// Review $link-decoration behavior
@if $link-decoration and $link-decoration != none {
.btn:not(.btn-link), .nav-link, .dropdown-item, .page-link, .breadcrumb-item > a, .badge, .fa {
+1 -1
View File
@@ -92,7 +92,7 @@
</t>
<t t-name="web.CustomCheckbox" owl="1">
<div class="custom-control custom-checkbox" t-att-class="props.class">
<div t-attf-class="{{ props.text ? 'custom-control form-check' : '' }}" t-att-class="props.class">
<input
t-att-id="props.id or _id"
type="checkbox"
+1 -3
View File
@@ -54,9 +54,7 @@
<div class="o_kanban_header">
<div class="input-group">
<input type="text" class="form-control o_input" placeholder="Column title"/>
<span class="input-group-append">
<button class="btn btn-primary o_kanban_add" type="button">Add</button>
</span>
<button class="btn btn-primary o_kanban_add" type="button">Add</button>
</div>
<span t-if="!widget.isMobile" class="o_discard_msg text-muted float-right">Esc to discard</span>
<t t-if="widget.examples &amp;&amp; !widget.isMobile">
@@ -15,7 +15,7 @@
<CustomCheckbox disabled="mode === 'readonly'"
value="state.days[day].value"
id="state.days[day].id"
class="'o_recurrent_weekday_checkbox text-center'"
class="'text-center'"
onChange="(checked) => this._onChange(checked, state.days[day].id)"/>
</td>
</tr>
@@ -16,9 +16,7 @@
<label for="password" class="col-md-4 col-form-label">Password</label>
<div class="col-md-8 input-group">
<input id="password" type="password" name="password" class="form-control" required="required" autocomplete="off"/>
<div class="input-group-append">
<span class="fa fa-eye o_little_eye input-group-text" aria-hidden="true" style="cursor: pointer;"></span>
</div>
<span class="fa fa-eye o_little_eye input-group-text" aria-hidden="true" style="cursor: pointer;"></span>
</div>
</div>
<div class="form-group row">
@@ -25,9 +25,7 @@
autofocus="autofocus"
type="password"
autocomplete="current-password" />
<div class="input-group-append">
<span class="fa fa-eye o_little_eye input-group-text" aria-hidden="true" style="cursor: pointer;"></span>
</div>
<span class="fa fa-eye o_little_eye input-group-text" aria-hidden="true" style="cursor: pointer;"></span>
</div>
</div>
</t>
@@ -176,9 +176,7 @@
<label for="master_pwd_new" class="col-form-label">New Master Password</label>
<div class="input-group">
<input id="master_pwd_new" type="password" name="master_pwd_new" class="form-control" required="required" autocomplete="new-password"/>
<div class="input-group-append">
<span class="fa fa-eye o_little_eye input-group-text" aria-hidden="true" style="cursor: pointer;"></span>
</div>
<span class="fa fa-eye o_little_eye input-group-text" aria-hidden="true" style="cursor: pointer;"></span>
</div>
</div>
</div>
+2 -45
View File
@@ -29,51 +29,8 @@ html, body {
outline: none;
}
// Boolean Toggle widget
div.o_boolean_toggle.custom-control.custom-checkbox {
$line-height-computed: $line-height-base * $font-size-base;
$slider-width: $line-height-computed * 1.5;
$font-size: $font-size-base * 1.2;
display: inline-block;
padding-left: $slider-width + 0.25rem;
> label.custom-control-label {
> i {
color: white;
cursor: pointer;
font-size: $font-size;
position: absolute;
top: 2px;
&.fa-times-circle {
right: 15px;
}
&.fa-check-circle {
right: 7px;
}
}
&::before,
&::after {
content: "";
top: 0;
left: -($slider-width + 0.25rem);
}
&::before {
width: $slider-width;
height: 100%;
background-color: #a0a0a0 !important;
border-radius: 100px;
outline: none !important;
}
}
> input.custom-control-input:checked + label.custom-control-label {
&::before {
background-color: $o-brand-primary !important;
}
&::after {
background-image: none;
}
}
div.o_boolean_toggle.form-switch.form-check > input.form-check-input:not(:checked) {
background-color: $form-switch-color;
}
// User input typically entered via keyboard
@@ -408,7 +408,7 @@ QUnit.module('Legacy basic_fields', {
QUnit.module('FieldBooleanToggle');
QUnit.test('use boolean toggle widget in form view', async function (assert) {
assert.expect(3);
assert.expect(7);
var form = await createView({
View: FormView,
@@ -417,14 +417,25 @@ QUnit.module('Legacy basic_fields', {
arch: '<form><field name="bar" widget="boolean_toggle"/></form>',
res_id: 2,
});
assert.containsOnce(form, ".custom-checkbox.o_boolean_toggle", "Boolean toggle widget applied to boolean field");
assert.containsOnce(form, ".custom-checkbox.o_boolean_toggle .fa-check-circle",
"Boolean toggle should have fa-check-circle icon");
// We don't check the exact value of the background as it change in community/enterprise,
// and it's difficult to check the value of an SVG
assert.containsOnce(form, ".form-check.o_boolean_toggle", "Boolean toggle widget applied to boolean field");
let checkElement = document.querySelector('.form-check.o_boolean_toggle .form-check-input');
assert.ok(checkElement.matches(':checked'), "Boolean toggle should be checked");
let style = window.getComputedStyle(checkElement);
const backgroundImage = style.backgroundImage;
const backgroundColor = style.backgroundColor;
assert.ok(backgroundImage && backgroundColor, "Boolean toggle should have a background image and a background color");
await testUtils.dom.click(form.$('.o_field_widget[name=bar]'));
assert.containsOnce(form, ".custom-checkbox.o_boolean_toggle .fa-times-circle",
"Boolean toggle should have fa-times-circle icon");
checkElement = document.querySelector('.form-check.o_boolean_toggle .form-check-input');
assert.notOk(checkElement.matches(':checked'), "Boolean toggle shouldn't be checked");
style = window.getComputedStyle(checkElement);
const newBackgroundImage = style.backgroundImage;
const newBackgroundColor = style.backgroundColor;
assert.ok(backgroundImage && backgroundColor, "Boolean toggle should have a background image and a background color");
assert.notEqual(backgroundImage, newBackgroundImage, "Background image should be different");
assert.notEqual(backgroundColor, newBackgroundColor, "Background color should be different");
form.destroy();
});
@@ -79,14 +79,14 @@ odoo.define('web.week_days_tests', function (require) {
},
});
assert.containsN(form, '.custom-control input:disabled', 7,
assert.containsN(form, 'input:disabled', 7,
"all inputs should be disabled in readonly mode");
const labelsTexts = [...form.el.querySelectorAll('.o_recurrent_weekday_label')].map(el => el.innerText.trim());
assert.deepEqual(labelsTexts, ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
"labels should be short week names");
await testUtils.form.clickEdit(form);
assert.containsNone(form, '.custom-control input:disabled', 7,
assert.containsNone(form, 'input:disabled', 7,
"all inputs should be enabled in readonly mode");
await testUtils.dom.click(form.el.querySelector('input[id^="sun"]'));
+1 -3
View File
@@ -137,9 +137,7 @@
<label for="db" class="col-form-label">Database</label>
<div t-attf-class="input-group {{'input-group-sm' if form_small else ''}}">
<input type="text" name="db" t-att-value="request.db" id="db" t-attf-class="form-control #{'form-control-sm' if form_small else ''}" required="required" readonly="readonly"/>
<span class="input-group-append">
<a role="button" href="/web/database/selector" class="btn btn-secondary">Select <i class="fa fa-database" role="img" aria-label="Database" title="Database"></i></a>
</span>
<a role="button" href="/web/database/selector" class="btn btn-secondary">Select <i class="fa fa-database" role="img" aria-label="Database" title="Database"></i></a>
</div>
</div>
@@ -599,18 +599,6 @@ a.o_underline {
> .input-group.ml-2 {
margin-left: 0 !important;
> .input-group-append {
width: 100%;
> .btn {
width: 100%;
}
> .ml-2 {
margin-left: 0 !important;
}
}
}
}
@@ -106,9 +106,7 @@
<label class="col-sm-2 col-form-label" for="pin_address">API Key</label>
<div class="col">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text"><i class="fa fa-key"/></div>
</div>
<div class="input-group-text"><i class="fa fa-key"/></div>
<input type="text" class="form-control" id="api_key_input"
t-att-value="apiKey or ''"
placeholder="BSgzTvR5L1GB9jriT451iTN4huVPxHmltG6T6eo"/>
@@ -203,9 +203,7 @@
t-att-placeholder="field.placeholder"
t-att-id="field.id"
/>
<div class="input-group-append" t-attf-data-target="##{datepickerID}" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
</div>
<div class="input-group-text" t-attf-data-target="##{datepickerID}" data-toggle="datetimepicker"><i class="fa fa-calendar"></i></div>
</div>
</t>
</t>
@@ -225,9 +223,7 @@
t-att-placeholder="field.placeholder"
t-att-id="field.id"
/>
<div class="input-group-append" t-attf-data-target="##{datetimepickerID}" data-toggle="datetimepicker">
<div class="input-group-text"><i class="fa fa-calendar"></i></div>
</div>
<div class="input-group-text" t-attf-data-target="##{datetimepickerID}" data-toggle="datetimepicker"><i class="fa fa-calendar"></i></div>
</div>
</t>
</t>
+9 -13
View File
@@ -2205,11 +2205,9 @@
<input type="hidden" name="url" t-att-value="path" />
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<input type="password" id="password" class="form-control" required="required" name="visibility_password" />
<div class="input-group-append">
<button class="btn btn-secondary" type="button" id="showPass">
<i class="fa fa-eye"></i>
</button>
</div>
<button class="btn btn-secondary" type="button" id="showPass">
<i class="fa fa-eye"></i>
</button>
</div>
</div>
<button type="submit" class="h4 btn btn-primary btn-block">Access to this page</button>
@@ -2360,14 +2358,12 @@ Sitemap: <t t-esc="url_root"/>sitemap.xml
<div t-attf-class="input-group #{_classes}" role="search">
<t t-set="search_placeholder">Search...</t>
<input type="search" name="search" t-att-class="'search-query form-control oe_search_box %s' % _input_classes" t-att-placeholder="placeholder if placeholder else search_placeholder" t-att-value="search"/>
<div class="input-group-append">
<button type="submit" t-att-class="'btn oe_search_button %s' % (_submit_classes or 'btn-primary')" aria-label="Search" title="Search">
<i class="fa fa-search"/>
<span t-if="search" class="oe_search_found">
<small>(<t t-out="search_count or 0"/> found)</small>
</span>
</button>
</div>
<button type="submit" t-att-class="'btn oe_search_button %s' % (_submit_classes or 'btn-primary')" aria-label="Search" title="Search">
<i class="fa fa-search"/>
<span t-if="search" class="oe_search_found">
<small>(<t t-out="search_count or 0"/> found)</small>
</span>
</button>
</div>
</template>
+3 -5
View File
@@ -372,11 +372,9 @@
</div>
<div class="o_search input-group ml-auto col-8 col-sm-6 col-md-4 col-xl-3" role="search">
<input type="search" name="search" class="form-control border-info" placeholder="Name, id or key"/>
<div class="input-group-append">
<button type="submit" class="btn btn-info" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</div>
<button type="submit" class="btn btn-info" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</div>
</nav>
@@ -624,9 +624,7 @@
<div class="form-row align-items-center">
<div class="col-auto flex-grow-1">
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text"><span class="text-nowrap" t-esc="opportunity.company_currency.symbol"/></div>
</div>
<div class="input-group-text"><span class="text-nowrap" t-esc="opportunity.company_currency.symbol"/></div>
<input type="text" name="expected_revenue" class="form-control expected_revenue" t-att-value="opportunity.expected_revenue" placeholder="Planned Revenue"/>
</div>
</div>
@@ -634,9 +632,7 @@
<div class="col-auto">
<div class="input-group">
<input type="text" name="probability" class="form-control probability" t-att-value="opportunity.probability" placeholder="Probability"/>
<div class="input-group-append">
<div class="input-group-text">%</div>
</div>
<div class="input-group-text">%</div>
</div>
</div>
</div>
@@ -672,11 +668,9 @@
<div class="input-group date" id="exp_closing_div" data-target-input="nearest">
<t t-set='date_formatted'><t t-options='{"widget": "date"}' t-esc="opportunity.date_deadline"/></t>
<input type="text" name="date_deadline" data-target="#exp_closing_div" t-att-value="date_formatted" class="datetimepicker-input form-control date_deadline" t-att-name="prefix"/>
<div class="input-group-append" data-target="#exp_closing_div" data-toggle="datetimepicker">
<span class="input-group-text">
<span class="fa fa-calendar" role="img" aria-label="Calendar"></span>
</span>
</div>
<span class="input-group-text" data-target="#exp_closing_div" data-toggle="datetimepicker">
<span class="fa fa-calendar" role="img" aria-label="Calendar"></span>
</span>
</div>
</div>
</div>
@@ -699,11 +693,9 @@
<div class="input-group date" id="next_activity_div" data-target-input="nearest">
<t t-set='date_formatted'><t t-options='{"widget": "date"}' t-esc="user_activity.date_deadline"/></t>
<input type="text" name="activity_date_deadline" data-target="#next_activity_div" t-att-value="date_formatted" class="form-control activity_date_deadline datetimepicker-input" t-att-name="prefix"/>
<div class="input-group-append" data-target="#next_activity_div" data-toggle="datetimepicker">
<span class="input-group-text">
<span class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"></span>
</span>
</div>
<span class="input-group-text" data-target="#next_activity_div" data-toggle="datetimepicker">
<span class="fa fa-calendar" role="img" aria-label="Calendar" title="Calendar"></span>
</span>
</div>
</div>
</div>
@@ -98,11 +98,9 @@
<!-- search -->
<form t-attf-action="#{'/event/%s/community/leaderboard/results' % (slug(event))}" role="search" method="get">
<div class="input-group ml-1 position-relative">
<span class="input-group-prepend">
<button class="btn btn-link text-white rounded-0 pr-1" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"></i>
</button>
</span>
<button class="btn btn-link text-white rounded-0 pr-1" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"></i>
</button>
<input type="text" class="form-control rounded-0" name="search" placeholder="Search Attendees" t-att-value="searched_name or ''"/>
</div>
</form>
@@ -118,11 +116,9 @@
<form class="px-3" t-attf-action="#{'/event/%s/community/leaderboard' % (slug(event))}" role="search" method="get">
<div class="input-group">
<input type="text" class="form-control" name="search" placeholder="Search courses"/>
<span class="input-group-append">
<button class="btn btn-primary" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</span>
<button class="btn btn-primary" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</div>
</form>
</div>
@@ -335,7 +335,7 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
countFlaggedPosts.classList.add('bg-danger');
countFlaggedPosts.innerText = parseInt(countFlaggedPosts.innerText, 10) + 1;
}
$(elem).next('#flag_validator').removeClass('d-none');
$(elem).nextAll('.flag_validator').removeClass('d-none');
} else if (data.success === 'post_flagged_non_moderator') {
const forumAnswer = elem.closest('.forum_answer');
elem.innerText = _t(' Flagged');
@@ -521,8 +521,8 @@ publicWidget.registry.websiteForum = publicWidget.Widget.extend({
method: currentTarget.dataset.action,
args: [parseInt(currentTarget.dataset.postId)],
});
currentTarget.parentElement.classList.toggle('d-none');
const flaggedButton = currentTarget.parentElement.previousElementSibling,
currentTarget.parentElement.querySelectorAll('.flag_validator').forEach((element) => element.classList.toggle('d-none'));
const flaggedButton = currentTarget.parentElement.firstElementChild,
child = flaggedButton.firstElementChild,
countFlaggedPosts = this.el.querySelector('#count_flagged_posts'),
count = parseInt(countFlaggedPosts.innerText, 10) - 1;
+24 -26
View File
@@ -5,14 +5,12 @@
<!-- Editor custom -->
<!-- helper -->
<template id="show_flag_validator">
<div id="flag_validator" t-attf-class="input-group-append #{'ml-1' if object.state == 'flagged' else 'd-none'}">
<a href="#" t-att-data-post-id="object.id" t-attf-data-action="validate" class="badge badge-light my-2 mr-2 o_wforum_flag_validator" title="Validate" data-toggle="tooltip">
<i class="fa fa-check text-success"/>
</a>
<a href="#" t-attf-data-action="/forum/#{object.id}/ask_for_mark_as_offensive" class="badge badge-light my-2 mr-2 o_wforum_flag_mark_as_offensive" title="Mark as Offensive" data-toggle="tooltip">
<i class="fa fa-times text-danger"/>
</a>
</div>
<a href="#" t-att-data-post-id="object.id" t-attf-data-action="validate" t-attf-class="#{'' if object.state == 'flagged' else 'd-none'} flag_validator badge badge-light my-2 mr-2 o_wforum_flag_validator" title="Validate" data-bs-toggle="tooltip">
<i class="fa fa-check text-success"/>
</a>
<a href="#" t-attf-data-action="/forum/#{object.id}/ask_for_mark_as_offensive" t-attf-class="#{'' if object.state == 'flagged' else 'd-none'} flag_validator badge badge-light my-2 mr-2 o_wforum_flag_mark_as_offensive" title="Mark as Offensive" data-bs-toggle="tooltip">
<i class="fa fa-times text-danger"/>
</a>
</template>
<template id="link_button">
@@ -828,8 +826,8 @@
</div>
<form t-else="" t-attf-action="/forum/#{slug(forum)}/new" method="post" role="form" class="tag_text js_website_submit_form js_wforum_submit_form o_wforum_readable">
<div class="form-group">
<label for="content">Title</label>
<div class="mb-3">
<label class="form-label" for="content">Title</label>
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="text" name="post_name" required="required" pattern=".*\S.*" t-attf-value="#{post_name}"
class="form-control form-control-lg" placeholder="A clear, explicit and concise title" title="Title must not be empty"/>
@@ -849,15 +847,15 @@
</div>
</div>
</div>
<div class="form-group">
<label for="content">Description</label>
<div class="mb-3">
<label class="form-label" for="content">Description</label>
<div class="small form-text text-muted d-inline">, consider <b>adding an example</b>. </div>
<textarea name="content" required="required" id="content" class="form-control o_wysiwyg_loader" t-att-data-karma="forum.karma_editor">
<t t-esc="question_content"/>
</textarea>
</div>
<div class="form-group">
<label for="post_tags">Tags</label>
<div class="mb-3">
<label class="form-label" for="post_tags">Tags</label>
<input type="hidden" name="karma_tag_create" t-attf-value="#{forum.karma_tag_create}" id="karma_tag_create"/>
<input type="hidden" name="karma_edit_retag" t-attf-value="#{forum.karma_edit_retag}" id="karma_edit_retag"/>
<input type="hidden" name="post_tags" placeholder="Tags" class="form-control js_select2"/>
@@ -882,8 +880,8 @@
</article>
<form t-attf-action="/forum/#{slug(forum)}/post/#{slug(post)}/save" method="post" role="form" class="tag_text js_website_submit_form js_wforum_submit_form o_wforum_readable">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div t-if="not is_answer" class="form-group">
<label for="post_name">Title</label>
<div t-if="not is_answer" class="mb-3">
<label class="form-label" for="post_name">Title</label>
<input type="text" name="post_name" required="required" pattern=".*\S.*" t-attf-value="#{post.name}"
class="form-control form-control-lg" placeholder="Edit your Post" title="Title must not be empty"/>
<div class="form-text small text-muted">
@@ -902,17 +900,17 @@
</div>
</div>
</div>
<div class="form-group">
<label t-if="not is_answer" for="content">Description</label>
<label t-else="">Your Answer</label>
<div class="mb-3">
<label t-if="not is_answer" class="form-label" for="content">Description</label>
<label t-else="" class="form-label">Your Answer</label>
<div t-if="not is_answer" class="small form-text text-muted d-inline">, consider <b>adding an example</b>. </div>
<textarea name="content" id="content" required="required" class="form-control o_wysiwyg_loader" t-att-data-karma="forum.karma_editor">
<t t-esc="post.content"/>
</textarea>
</div>
<input type="hidden" name="karma" t-attf-value="#{user.karma}" id="karma"/>
<div t-if="not is_answer" class="form-group">
<label for="post_tags">Tags</label>
<div t-if="not is_answer" class="mb-3">
<label class="form-label" for="post_tags">Tags</label>
<input type="hidden" name="karma_tag_create" t-attf-value="#{forum.karma_tag_create}" id="karma_tag_create"/>
<input type="hidden" name="karma_edit_retag" t-attf-value="#{forum.karma_edit_retag}" id="karma_edit_retag"/>
<t t-set="edit_tags_karma_fail" t-value="user.karma &lt; forum.karma_edit_retag"/>
@@ -947,19 +945,19 @@
<form t-attf-action="/forum/#{ slug(forum) }/#{offensive and 'post' or 'question'}/#{slug(question)}/#{offensive and 'mark_as_offensive' or 'close'}" method="post" role="form" class="mt32 js_website_submit_form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input name="post_id" t-att-value="question.id" type="hidden"/>
<div class="form-group">
<label for="post">Post:</label>
<div class="mb-3">
<label class="form-label" for="post">Post:</label>
<input type="text" disabled="True" class="form-control-plaintext" name="post" t-att-value="question.name if not question.parent_id else question.parent_id.name"/>
</div>
<div class="form-group mb-4">
<label for="reason"><t t-if="offensive">Offensive</t><t t-if="not offensive">Closing</t> Reason:</label>
<div class="mb-4">
<label class="form-label" for="reason"><t t-if="offensive">Offensive</t><t t-if="not offensive">Closing</t> Reason:</label>
<select class="form-control custom-select custom-select-lg" name="reason_id">
<t t-foreach="reasons or []" t-as="reason">
<option t-att-value="reason.id" t-att-selected="reason.id == question.closed_reason_id.id"><t t-esc="reason.name"/></option>
</t>
</select>
</div>
<div class="form-group">
<div class="mb-3">
<button type="submit" class="btn btn-danger">
<t t-if="offensive">Mark as offensive</t>
<t t-if="not offensive">Close post</t>
+1 -1
View File
@@ -44,7 +44,7 @@ publicWidget.registry.follow = publicWidget.Widget.extend({
// not if editable mode to allow designer to edit
if (!this.editableMode) {
$('.js_follow > .input-group-append.d-none').removeClass('d-none');
$('.js_follow > .d-none').removeClass('d-none');
this.$target.find('.js_follow_btn, .js_unfollow_btn').on('click', function (event) {
event.preventDefault();
self._onClick(event);
@@ -22,10 +22,10 @@
</div>
</button>
</div>
<div t-else="" t-attf-class="#{request.env.user.has_group('base.group_public') and 'input-group-append'}">
<t t-else="">
<button href="#" t-attf-class="btn btn-secondary js_unfollow_btn">Unsubscribe</button>
<button href="#" t-attf-class="btn btn-primary js_follow_btn">Subscribe</button>
</div>
</t>
</div>
</template>
</odoo>
@@ -5,9 +5,7 @@
data-id="0" data-object="mail.group" data-follow="off">
<div class="input-group o_mg_subscribe_form">
<input class="o_mg_subscribe_email form-control" type="email" name="email" placeholder="your email..."/>
<span class="input-group-append">
<button href="#" class="btn btn-primary o_mg_subscribe_btn">Subscribe</button>
</span>
<button href="#" class="btn btn-primary o_mg_subscribe_btn">Subscribe</button>
</div>
</div>
</template>
@@ -28,10 +28,8 @@
<div class="s_newsletter_subscribe_form js_subscribe" data-vxml="001" data-list-id="0" data-name="Newsletter Form">
<div class="input-group">
<input type="email" name="email" class="js_subscribe_email form-control" placeholder="your email..."/>
<span class="input-group-append">
<a role="button" href="#" class="btn btn-primary js_subscribe_btn o_submit">Subscribe</a>
<a role="button" href="#" class="btn btn-success js_subscribed_btn d-none o_submit" disabled="disabled">Thanks</a>
</span>
<a role="button" href="#" class="btn btn-primary js_subscribe_btn o_submit">Subscribe</a>
<a role="button" href="#" class="btn btn-success js_subscribed_btn d-none o_submit" disabled="disabled">Thanks</a>
</div>
</div>
</template>
@@ -21,11 +21,9 @@
<!-- search -->
<form t-attf-action="/profile/users" role="search" method="get">
<div class="input-group o_wprofile_course_nav_search ml-1 position-relative">
<span class="input-group-prepend">
<button class="btn btn-link text-white border-1 rounded-0 pr-1 mr-2" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search border-1"></i>
</button>
</span>
<button class="btn btn-link text-white border-1 rounded-0 pr-1 mr-2" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search border-1"></i>
</button>
<input type="text" class="form-control border-0 rounded-0 bg-transparent text-white ml-auto" name="search" placeholder="Search users"/>
</div>
</form>
@@ -50,11 +48,9 @@
<form class="px-3" t-attf-action="/profile/users" role="search" method="get">
<div class="input-group">
<input type="text" class="form-control" name="search" placeholder="Search courses"/>
<span class="input-group-append">
<button class="btn btn-primary" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</span>
<button class="btn btn-primary" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</div>
</form>
</div>
@@ -831,7 +831,7 @@ publicWidget.registry.WebsiteSaleLayout = publicWidget.Widget.extend({
selector: '.oe_website_sale',
disabledInEditableMode: false,
events: {
'change .o_wsale_apply_layout': '_onApplyShopLayoutChange',
'change .o_wsale_apply_layout input': '_onApplyShopLayoutChange',
},
//--------------------------------------------------------------------------
@@ -847,12 +847,13 @@ publicWidget.registry.WebsiteSaleLayout = publicWidget.Widget.extend({
if (wysiwyg) {
wysiwyg.odooEditor.observerUnactive('_onApplyShopLayoutChange');
}
var switchToList = $(ev.currentTarget).find('.o_wsale_apply_list input').is(':checked');
var clickedValue = $(ev.target).val();
var isList = clickedValue === 'list';
if (!this.editableMode) {
this._rpc({
route: '/shop/save_shop_layout_mode',
params: {
'layout_mode': switchToList ? 'list' : 'grid',
'layout_mode': isList ? 'list' : 'grid',
},
});
}
@@ -862,7 +863,7 @@ publicWidget.registry.WebsiteSaleLayout = publicWidget.Widget.extend({
// TODO should probably be improved to allow disabling transitions
// altogether with a class/option.
$grid.find('*').css('transition', 'none');
$grid.toggleClass('o_wsale_layout_list', switchToList);
$grid.toggleClass('o_wsale_layout_list', isList);
void $grid[0].offsetWidth;
$grid.find('*').css('transition', '');
if (wysiwyg) {
@@ -185,12 +185,14 @@ $o-wsale-products-layout-grid-gutter-width: min($grid-gutter-width / 2, $o-wsale
color: gray('500');
background-color: transparent;
border-radius: 0%;
}
&.active, &:focus {
color: gray('600');
background-color: gray('200');
box-shadow: none !important;
}
.o_wsale_apply_layout > .btn-check:checked + .btn,
.o_wsale_apply_layout > .btn:focus
{
color: gray('600');
background-color: gray('200');
box-shadow: none !important;
}
}
+23 -35
View File
@@ -275,7 +275,7 @@
<t t-call="website_sale.products_breadcrumb">
<t t-set="_classes" t-valuef="w-100"/>
</t>
<div class="products_header form-inline flex-md-nowrap justify-content-end mb-4">
<div class="products_header d-flex flex-md-nowrap justify-content-end mb-4">
<t t-call="website_sale.search">
<t t-set="_classes" t-valuef="w-100 w-md-auto mr-auto mb-2"/>
<t t-set="search" t-value="original_search or search"/>
@@ -413,13 +413,11 @@
<template id="add_grid_or_list_option" inherit_id="website_sale.products" active="True" name="Grid or List button">
<xpath expr="//div[hasclass('products_header')]" position="inside">
<div class="btn-group btn-group-toggle ml-3 mb-2 d-inline-flex o_wsale_apply_layout" data-toggle="buttons">
<label t-attf-class="btn btn-light border-0 #{'active' if layout_mode != 'list' else None} fa fa-th-large o_wsale_apply_grid" title="Grid">
<input type="radio" name="wsale_products_layout" t-att-checked="'checked' if layout_mode != 'list' else None"/>
</label>
<label t-attf-class="btn btn-light border-0 #{'active' if layout_mode == 'list' else None} fa fa-th-list o_wsale_apply_list" title="List">
<input type="radio" name="wsale_products_layout" t-att-checked="'checked' if layout_mode == 'list' else None"/>
</label>
<div class="ms-3 mb-2 d-inline-flex o_wsale_apply_layout">
<input type="radio" class="btn-check" name="wsale_products_layout" id="o_wsale_apply_grid" t-att-checked="'checked' if layout_mode != 'list' else None" value="grid"/>
<label t-attf-class="btn btn-light border-0 #{'active' if layout_mode != 'list' else None} fa fa-th-large o_wsale_apply_grid" title="Grid" for="o_wsale_apply_grid"/>
<input type="radio" class="btn-check" name="wsale_products_layout" id="o_wsale_apply_list" t-att-checked="'checked' if layout_mode == 'list' else None" value="list"/>
<label t-attf-class="btn btn-light border-0 #{'active' if layout_mode == 'list' else None} fa fa-th-list o_wsale_apply_list" title="List" for="o_wsale_apply_list"/>
</div>
</xpath>
</template>
@@ -807,17 +805,13 @@
</xpath>
<xpath expr="//div[@id='add_to_cart_wrap']" position="before">
<div t-attf-class="css_quantity input-group d-inline-flex mr-2 mb-2 align-middle #{'input-group-lg' if ctaSizeBig else ''}" contenteditable="false">
<div class="input-group-prepend">
<a t-attf-href="#" class="btn btn-link js_add_cart_json" aria-label="Remove one" title="Remove one">
<i class="fa fa-minus"></i>
</a>
</div>
<a t-attf-href="#" class="btn btn-link js_add_cart_json" aria-label="Remove one" title="Remove one">
<i class="fa fa-minus"></i>
</a>
<input type="text" class="form-control quantity text-center" data-min="1" name="add_qty" t-att-value="add_qty or 1"/>
<div class="input-group-append">
<a t-attf-href="#" class="btn btn-link float_left js_add_cart_json" aria-label="Add one" title="Add one">
<i class="fa fa-plus"></i>
</a>
</div>
<a t-attf-href="#" class="btn btn-link float_left js_add_cart_json" aria-label="Add one" title="Add one">
<i class="fa fa-plus"></i>
</a>
</div>
</xpath>
</template>
@@ -1105,22 +1099,18 @@
<div class="css_quantity input-group mx-auto justify-content-center">
<t t-if="not line._is_not_sellable_line()">
<t t-if="show_qty">
<div class="input-group-prepend">
<a t-attf-href="#" class="btn btn-link js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
<i class="fa fa-minus"></i>
</a>
</div>
<a t-attf-href="#" class="btn btn-link js_add_cart_json d-none d-md-inline-block" aria-label="Remove one" title="Remove one">
<i class="fa fa-minus"></i>
</a>
<input type="text" class="js_quantity form-control quantity" t-att-data-line-id="line.id" t-att-data-product-id="line.product_id.id" t-att-value="int(line.product_uom_qty) == line.product_uom_qty and int(line.product_uom_qty) or line.product_uom_qty" />
<div class="input-group-append">
<div t-if="line._get_shop_warning(clear=False)" class="input-group-append">
<a t-attf-href="#" class="btn btn-link">
<i class='fa fa-warning text-warning' t-att-title="line._get_shop_warning()" role="img" aria-label="Warning"/>
</a>
</div>
<a t-else='' t-attf-href="#" class="btn btn-link float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
<i class="fa fa-plus"></i>
<t t-if="line._get_shop_warning(clear=False)">
<a t-attf-href="#" class="btn btn-link">
<i class='fa fa-warning text-warning' t-att-title="line._get_shop_warning()" role="img" aria-label="Warning"/>
</a>
</div>
</t>
<a t-else='' t-attf-href="#" class="btn btn-link float_left js_add_cart_json d-none d-md-inline-block" aria-label="Add one" title="Add one">
<i class="fa fa-plus"></i>
</a>
</t>
<t t-else="">
<input type="hidden" class="js_quantity form-control quantity" t-att-data-line-id="line.id" t-att-data-product-id="line.product_id.id" t-att-value="int(line.product_uom_qty) == line.product_uom_qty and int(line.product_uom_qty) or line.product_uom_qty" />
@@ -1308,9 +1298,7 @@
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()" />
<div class="input-group w-100">
<input name="promo" class="form-control" type="text" placeholder="code..." t-att-value="website_sale_order.pricelist_id.code or None"/>
<div class="input-group-append">
<a href="#" role="button" class="btn btn-secondary a-submit">Apply</a>
</div>
<a href="#" role="button" class="btn btn-secondary a-submit">Apply</a>
</div>
</form>
<t t-if="request.params.get('code_not_available')" name="code_not_available">
@@ -5,9 +5,7 @@
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="input-group w-100">
<input name="promo" class="form-control" type="text" required="required" placeholder="Gift card code..."/>
<div class="input-group-append">
<button href="#" type="submit" role="button" class="btn btn-secondary a-submit">Pay</button>
</div>
<button href="#" type="submit" role="button" class="btn btn-secondary a-submit">Pay</button>
</div>
</form>
</template>
@@ -5,10 +5,8 @@
<div t-attf-class="o_wsildes_quiz_question_input mt-3 #{!widget.update ? 'col' : ''}" t-att-data-id="widget.question.id || ''">
<form class="mb-3">
<div class="o_wslides_quiz_question row align-items-center mr-0 mb-2">
<div class="input-group ml-3">
<div class="input-group-prepend">
<span class="input-group-text o_wslides_quiz_question_sequence"><t t-esc="widget.sequence"/></span>
</div>
<div class="input-group">
<span class="input-group-text o_wslides_quiz_question_sequence"><t t-esc="widget.sequence"/></span>
<input type="text" name="question-name" class="form-control col-11" placeholder='e.g. "Which animal cannot fly?"'
t-att-value="widget.question.text"/>
</div>
@@ -44,9 +42,9 @@
<div class="o_wslides_js_quiz_answer row align-items-center mb-1" t-attf-data-answer-id="#{answer ? answer.id : ''}" >
<div class="col ml-3 ml-md-5">
<div class="row align-items-center">
<div class="input-group col-9 p-0">
<input type="text" class="o_wslides_js_quiz_answer_value form-control" t-attf-placeholder='e.g. "{{placeholder || "another animal"}}"' t-attf-value="#{answer ? answer.text_value : ''}"/>
<div class="input-group-append">
<div class="col-9 p-0">
<div class="input-group">
<input type="text" class="o_wslides_js_quiz_answer_value form-control" t-attf-placeholder='e.g. "{{placeholder || "another animal"}}"' t-attf-value="#{answer ? answer.text_value : ''}"/>
<div class="input-group-text">
<a class="o_wslides_js_quiz_is_correct" title="This is the correct answer">
<label class="my-0">
@@ -58,9 +56,9 @@
</div>
</div>
</div>
<i t-attf-class="o_wslides_js_quiz_icon o_wslides_js_quiz_comment_answer fa fa-lg fa-info-circle p-md-2 py-2 pl-2 pr-1 #{answer &amp;&amp; answer.comment ? 'text-primary' : 'text-muted'}" title="Add comment on this answer" />
<i class="o_wslides_js_quiz_icon o_wslides_js_quiz_add_answer fa fa-lg fa-plus-circle p-md-2 py-2 px-1 text-muted" title="Add an answer below this one" />
<i class="o_wslides_js_quiz_icon o_wslides_js_quiz_remove_answer fa fa-lg fa-trash-o p-md-2 py-2 px-1 text-muted" title="Remove this answer" />
<i t-attf-class="o_wslides_js_quiz_icon o_wslides_js_quiz_comment_answer fa fa-lg fa-info-circle col-auto p-md-2 py-2 pl-2 pr-1 #{answer &amp;&amp; answer.comment ? 'text-primary' : 'text-muted'}" title="Add comment on this answer" />
<i class="o_wslides_js_quiz_icon o_wslides_js_quiz_add_answer fa fa-lg fa-plus-circle col-auto p-md-2 py-2 px-1 text-muted" title="Add an answer below this one" />
<i class="o_wslides_js_quiz_icon o_wslides_js_quiz_remove_answer fa fa-lg fa-trash-o col-auto p-md-2 py-2 px-1 text-muted" title="Remove this answer" />
</div>
<div class="o_wslides_js_quiz_answer_comment row align-items-center d-none">
<input type="text" class="form-control col-8 offset-1 mt-1" placeholder="This is the correct answer, congratulations"
@@ -20,11 +20,9 @@
<h5 class="mt-0 mb-2">Share Link</h5>
<div class="input-group">
<input type="text" class="form-control o_wslides_js_share_link" t-att-value="widget.slide.websiteShareUrl" readonly="readonly" onClick="this.select();" />
<div class="input-group-append">
<button class="btn btn-sm btn-primary o_clipboard_button" style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;" >
<span class="fa fa-clipboard"> Copy Link</span>
</button>
</div>
<button class="btn btn-sm btn-primary o_clipboard_button" style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;" >
<span class="fa fa-clipboard"> Copy Link</span>
</button>
</div>
</div>
<div t-attf-class="col-12 col-lg-6">
@@ -39,14 +37,12 @@
<form class="form-group o_wslides_js_share_email" role="form">
<div class="input-group">
<input type="email" class="form-control" placeholder="your-friend@domain.com"/>
<span class="input-group-append">
<button class="btn btn-primary" type="button"
data-loading-text="Sending..."
t-attf-data-slide-id="#{widget.slide.id}"
style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;">
<i class="fa fa-envelope-o"/> Send Email
</button>
</span>
<button class="btn btn-primary" type="button"
data-loading-text="Sending..."
t-attf-data-slide-id="#{widget.slide.id}"
style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;">
<i class="fa fa-envelope-o"/> Send Email
</button>
</div>
</form>
</div>
@@ -55,4 +51,5 @@
</div>
</t>
</templates>
</templates>
@@ -11,11 +11,9 @@
<t t-name="slides.course.unsubscribe.modal.subscription">
<form class="clearfix">
<div class="form-group row">
<div class="controls mt8 ml-3">
<input id="subscribed" name="subscribed" type="checkbox"/>
<label for="subscribed" class="col-form-label font-weight-normal">Be notified when a new content is added.</label>
</div>
<div class="controls mt8">
<input id="subscribed" name="subscribed" type="checkbox"/>
<label for="subscribed" class="col-form-label font-weight-normal">Be notified when a new content is added.</label>
</div>
</form>
</t>
@@ -74,9 +74,7 @@
<label for="duration" class="col-form-label">Estimated Completion Time</label>
<div class="input-group">
<input type="number" id="duration" min="0" name="duration" placeholder='e.g. "15"' class="form-control" autocomplete="off"/>
<div class="input-group-prepend">
<span class="input-group-text">Minutes</span>
</div>
<span class="input-group-text">Minutes</span>
</div>
</div>
</t>
@@ -663,11 +663,9 @@
<form t-attf-action="/slides/#{slug(channel)}" role="search" method="get" class="form-inline my-2 my-lg-0">
<div class="input-group position-relative">
<input type="text" class="form-control border" name="search" placeholder="Search in content" t-att-value="search"/>
<div class="input-group-append">
<button class="btn border" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</div>
<button class="btn border" type="submit" aria-label="Search" title="Search">
<i class="fa fa-search"/>
</button>
</div>
</form>
</div>
@@ -743,7 +741,7 @@
</div>
<div class="row mx-n2">
<t t-foreach="category['slides']" t-as="slide">
<div class="col-12 col-sm-6 col-lg-4 px-2 d-flex flex-grow-1" t-call="website_slides.lesson_card"/>
<div class="col-12 col-sm-6 col-lg-4 px-2 d-flex" t-call="website_slides.lesson_card"/>
</t>
</div>
</div>
@@ -80,7 +80,7 @@
<a class="d-none d-lg-block" t-att-href="'/profile/user/%s' % user.id">View</a>
<a class="d-lg-none btn btn-sm bg-white border" href="#" data-toggle="collapse" data-target="#o_wslides_home_aside_content">More info</a>
</div>
<hr class="d-none d-lg-block mt-2 pt-2 mb-1"/>
<hr class="d-none d-lg-block mt-2 mb-2 mb-1"/>
</div>
<div id="o_wslides_home_aside_content" class="collapse d-lg-block">
<div class="row no-gutters mb-5 mt-3 mt-lg-0">
@@ -432,7 +432,7 @@
<div class="col">
<a t-if="users" href="/profile/users" class="float-right">View all</a>
<h5 class="m-0">Leaderboard</h5>
<hr class="mt-2 pt-2"/>
<hr class="mt-2 mb-2"/>
</div>
</div>
<div class="row">
@@ -489,7 +489,7 @@
<div class="col">
<a href="/profile/ranks_badges?badge_category=slides" class="float-right">View all</a>
<h5 class="m-0">Badges</h5>
<hr class="mt-2 pt-2"/>
<hr class="mt-2 mt-2"/>
</div>
</div>
<t t-foreach="challenges" t-as="challenge">
@@ -544,8 +544,8 @@
</template>
<template id="lesson_content_quiz_add_buttons" name="Lesson: Quiz Add Buttons template">
<div class="o_wslides_js_lesson_quiz_new_question row mt-3">
<a t-attf-class="o_wslides_js_quiz_add o_wslides_js_quiz_add_quiz btn btn-light border ml-3 #{'d-none ' if slide.question_ids else ''}" role="button">
<div class="o_wslides_js_lesson_quiz_new_question mt-3">
<a t-attf-class="o_wslides_js_quiz_add o_wslides_js_quiz_add_quiz btn btn-light border #{'d-none ' if slide.question_ids else ''}" role="button">
<i class="fa fa-plus mr-2"/>
<span>Add Quiz</span>
</a>
@@ -559,18 +559,16 @@
<!-- Slide sub-template: share: send by email -->
<template id='slide_social_email' name="Share by Email">
<h5 class="mt-4">Share by mail</h5>
<div t-if="not is_public_user" class="form-inline">
<div t-if="not is_public_user" class="d-flex">
<form class="form-group oe_slide_js_share_email" role="form">
<div class="input-group">
<input type="email" class="form-control" placeholder="your-friend@domain.com"/>
<span class="input-group-append">
<button class="btn btn-primary" type="button"
data-loading-text="Sending..."
t-attf-data-slide-id="#{slide.id}"
style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;">
<i class="fa fa-envelope"/> Send Email
</button>
</span>
<button class="btn btn-primary" type="button"
data-loading-text="Sending..."
t-attf-data-slide-id="#{slide.id}"
style="border-top-right-radius: 4px;border-bottom-right-radius: 4px;">
<i class="fa fa-envelope"/> Send Email
</button>
</div>
<span class="form-text text-muted d-block w-100">Send presentation through email</span>
</form>
@@ -95,9 +95,7 @@
<div class="col-3 d-flex align-items-center">
<div class="input-group input-group-sm flex-nowrap" style="max-width: 100px">
<input type="number" class="form-control text-center" id="page_number" style="min-width: 60px"/>
<div class="input-group-append">
<span class="input-group-text" id="page_count"/>
</div>
<span class="input-group-text" id="page_count"/>
</div>
<span id="zoomout" class="d-none d-sm-inline ml-2 mr-2" title="Zoom out" aria-label="Zoom out" role="button">
<i class="fa fa-search-minus" />
@@ -64,11 +64,9 @@
<div class="input-group">
<input type="text" t-att-id="'wslides_share_link_id_%s' % record.id" class="form-control o_wslides_js_share_link" readonly="readonly" onclick="this.select();"
t-att-value="website_share_url"/>
<div class="input-group-append">
<button t-att-id="'share_link_clipboard_button_id_%s' % record.id" class="btn btn-sm btn-primary o_clipboard_button" >
<span class="fa fa-clipboard"> Copy Text</span>
</button>
</div>
<button t-att-id="'share_link_clipboard_button_id_%s' % record.id" class="btn btn-sm btn-primary o_clipboard_button" >
<span class="fa fa-clipboard"> Copy Text</span>
</button>
</div>
</template>