[FW][REF] web: FormView, replace tables with grids
This PR replaces the FormView group tables with css grids. Part of the overall v16 SCSS optimization/restyle, task-2704984 task-2918464 -- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr closes odoo/odoo#101655 Forward-port-of: odoo/odoo#98911 Signed-off-by: Adrien Dieudonné (adr) <adr@odoo.com>
This commit is contained in:
@@ -71,7 +71,7 @@
|
||||
<notebook>
|
||||
<page name="public" string="Work Information">
|
||||
<div id="o_work_employee_container" class="d-lg-flex"> <!-- These two div are used to position org_chart -->
|
||||
<div id="o_work_employee_main">
|
||||
<div id="o_work_employee_main" class="flex-grow-1">
|
||||
<group string="Location" name="location">
|
||||
<field name="address_id"
|
||||
context="{'show_address': 1}"
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
<notebook>
|
||||
<page name="public" string="Work Information">
|
||||
<div id="o_work_employee_container" class="d-lg-flex"> <!-- These two div are used to position org_chart -->
|
||||
<div id="o_work_employee_main">
|
||||
<div id="o_work_employee_main" class="flex-grow-1">
|
||||
<group string="Location">
|
||||
<field name="address_id"
|
||||
context="{'show_address': 1}"
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
<notebook position="inside">
|
||||
<page name="public" string="Work Information">
|
||||
<div id="o_work_employee_container" class="d-lg-flex"> <!-- These two div are used to position org_chart -->
|
||||
<div id="o_work_employee_main">
|
||||
<div id="o_work_employee_main" class="flex-grow-1">
|
||||
<group string="Location">
|
||||
<field name="department_id" attrs="{'readonly': [('can_edit', '=', False)]}"/>
|
||||
<field name="address_id"
|
||||
|
||||
@@ -56,6 +56,12 @@ $utilities: () !default;
|
||||
$utilities: map-merge(
|
||||
$utilities,
|
||||
(
|
||||
"display": map-merge(
|
||||
map-get($utilities, "display"),
|
||||
(
|
||||
values: join(map-get(map-get($utilities, "display"), "values"), contents),
|
||||
),
|
||||
),
|
||||
"position": map-merge(
|
||||
map-get($utilities, "position"),
|
||||
(
|
||||
|
||||
@@ -316,7 +316,7 @@ export class FormCompiler extends ViewCompiler {
|
||||
}
|
||||
|
||||
if (getTag(child, true) === "separator") {
|
||||
forceNewline = true;
|
||||
itemSpan = parseInt(formGroup.getAttribute("maxCols") || 2, 10);
|
||||
}
|
||||
|
||||
let slotContent;
|
||||
@@ -343,9 +343,14 @@ export class FormCompiler extends ViewCompiler {
|
||||
mainSlot.setAttribute("subType", "'item_component'");
|
||||
}
|
||||
} else {
|
||||
if (child.classList.contains("o_td_label") || getTag(child, true) === "label") {
|
||||
// TODO: When every apps will be revamp, we could remove the condition using 'o_td_label' in favor of 'o_wrap_label'
|
||||
if (
|
||||
child.classList.contains("o_wrap_label") ||
|
||||
child.classList.contains("o_td_label") ||
|
||||
getTag(child, true) === "label"
|
||||
) {
|
||||
mainSlot.setAttribute("subType", "'label'");
|
||||
child.classList.remove("o_td_label");
|
||||
child.classList.remove("o_wrap_label");
|
||||
}
|
||||
slotContent = this.compileNode(child, params, false);
|
||||
}
|
||||
|
||||
@@ -28,53 +28,34 @@
|
||||
margin-right: -$o-horizontal-padding;
|
||||
}
|
||||
|
||||
@mixin o-td-label-style {
|
||||
width: 0%;
|
||||
padding: 0 15px 0 0;
|
||||
min-width: 150px;
|
||||
color: $headings-color;
|
||||
}
|
||||
|
||||
// XXS form view specific rules
|
||||
@mixin form-break-table {
|
||||
display: block;
|
||||
grid-template-columns: 1fr;
|
||||
margin-bottom: $o-form-spacing-unit * 4;
|
||||
|
||||
> tbody {
|
||||
display: block;
|
||||
.o_wrap_field {
|
||||
.o_cell {
|
||||
max-width: 100%;
|
||||
|
||||
> tr {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
padding-bottom: map-get($spacers, 3);
|
||||
&.o_wrap_label {
|
||||
line-height: $o-label-font-size-factor;
|
||||
}
|
||||
|
||||
> td {
|
||||
flex: 1 0 auto;
|
||||
display: block;
|
||||
.o_field_widget {
|
||||
margin-bottom: $o-form-spacing-unit * 2;
|
||||
|
||||
> .o_field_widget {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.o_field_boolean {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.o_input_dropdown {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
padding: 0;
|
||||
|
||||
&.o_td_label {
|
||||
width: 94%!important; // The label must be on its own line except if the form field is small enough (checkbox)
|
||||
line-height: $o-label-font-size-factor;
|
||||
}
|
||||
|
||||
.o_field_widget {
|
||||
margin-bottom: $o-form-spacing-unit * 2;
|
||||
|
||||
> .o_field_widget {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.o_field_boolean {
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.o_input_dropdown {
|
||||
width: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -104,11 +85,6 @@
|
||||
}
|
||||
.oe_inline, .o_field_widget.oe_inline > * {
|
||||
width: auto!important;
|
||||
@include media-breakpoint-up(vsm, $o-extra-grid-breakpoints) {
|
||||
&.o_inner_group {
|
||||
width: 1px!important;
|
||||
}
|
||||
}
|
||||
}
|
||||
.oe_left {
|
||||
@extend .oe_inline;
|
||||
@@ -419,48 +395,6 @@
|
||||
|
||||
// Groups
|
||||
.o_group {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 10px 0;
|
||||
|
||||
.o_group {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
// o_group contains nested groups
|
||||
@for $i from 1 through $o-form-group-cols {
|
||||
.o_group_col_#{$i} {
|
||||
display: inline-block;
|
||||
width: floor(100% / 12 * $i);
|
||||
vertical-align: top;
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.o_inner_group {
|
||||
display: inline-table;
|
||||
|
||||
> tbody > tr > td {
|
||||
padding: 0 $o-innergroup-rpadding 0 0;
|
||||
vertical-align: top;
|
||||
|
||||
&.o_td_label {
|
||||
@include o-td-label-style;
|
||||
}
|
||||
}
|
||||
|
||||
.o_field_widget {
|
||||
&.o_field_many2one_avatar {
|
||||
.o_field_many2one_selection {
|
||||
width: calc(100% - 24px);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.o_form_label {
|
||||
font-weight: $font-weight-normal;
|
||||
}
|
||||
@@ -474,19 +408,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
:not(.o_row):not(.o_data_cell) > .o_field_widget,
|
||||
.o_row > .o_field_widget:last-child { // Note: this does not take care
|
||||
// of an invisible last-child but
|
||||
// it does not really matter
|
||||
// Makes extra buttons (e.g. m2o external button) overflow on the
|
||||
// right padding of the parent element
|
||||
.o_input_dropdown {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(vsm, $o-extra-grid-breakpoints) {
|
||||
.o_field_widget {
|
||||
&.o_text_overflow {
|
||||
@@ -509,13 +430,29 @@
|
||||
white-space: normal;
|
||||
}
|
||||
}
|
||||
|
||||
.o_td_label .o_form_label {
|
||||
.o_wrap_label .o_form_label {
|
||||
font-weight: $font-weight-bold;
|
||||
margin-right: $o-form-label-margin-right;
|
||||
}
|
||||
}
|
||||
|
||||
.o_inner_group {
|
||||
--columns: 1;
|
||||
gap: map-get($spacers, 2) $o-horizontal-padding;
|
||||
|
||||
span, .o_field_boolean, .oe_avatar, .o_form_uri {
|
||||
&.o_field_widget {
|
||||
width: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include media-breakpoint-up(sm) {
|
||||
.o_inner_group {
|
||||
grid-template-columns: fit-content(150px) 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
.o_checkbox_optional_field {
|
||||
display: flex;
|
||||
|
||||
@@ -525,7 +462,7 @@
|
||||
}
|
||||
|
||||
> .o_form_label {
|
||||
@include o-td-label-style;
|
||||
color: $headings-color;
|
||||
margin-right: $o-form-label-margin-right;
|
||||
font-weight: $font-weight-bold;
|
||||
}
|
||||
@@ -715,10 +652,7 @@
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
.o_td_label .o_form_label:not(.o_status), .o_checkbox_optional_field > .o_form_label {
|
||||
min-height: 23px;
|
||||
}
|
||||
td:not(.o_field_cell) .o_form_uri > span:first-child {
|
||||
.o_cell:not(.o_field_cell) .o_form_uri > span:first-child {
|
||||
display: inline-block;
|
||||
padding: 1px 0;
|
||||
margin-bottom: 1px;
|
||||
@@ -783,14 +717,15 @@
|
||||
}
|
||||
|
||||
// Specific style classes
|
||||
.o_group.o_inner_group.oe_subtotal_footer {
|
||||
.o_inner_group.oe_subtotal_footer {
|
||||
grid-template-columns: 1fr auto;
|
||||
@extend .oe_right;
|
||||
border-top: 1px solid $border-color;
|
||||
|
||||
> tbody > tr > td {
|
||||
.o_cell {
|
||||
padding: 0;
|
||||
|
||||
&.o_td_label {
|
||||
&.o_wrap_label {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
@@ -811,7 +746,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
> tbody > tr:first-child > td {
|
||||
.o_wrap_field:first-child > .o_cell {
|
||||
padding-top: 4px;
|
||||
}
|
||||
.oe_subtotal_footer_separator {
|
||||
@@ -964,7 +899,7 @@
|
||||
}
|
||||
|
||||
.oe_form_configuration {
|
||||
.o_group .o_form_label {
|
||||
.o_inner_group .o_form_label {
|
||||
white-space: nowrap;
|
||||
}
|
||||
h2 {
|
||||
@@ -1125,7 +1060,7 @@
|
||||
}
|
||||
|
||||
@include media-breakpoint-down(lg) {
|
||||
.o_group.o_inner_group > tbody > tr > td.o_td_label {
|
||||
.o_group.o_inner_group .o_wrap_label {
|
||||
min-width: 100px;
|
||||
}
|
||||
}
|
||||
@@ -1138,7 +1073,7 @@
|
||||
}
|
||||
|
||||
&.modal-sm .o_form_view {
|
||||
.o_group {
|
||||
.o_inner_group {
|
||||
@include form-break-table;
|
||||
}
|
||||
}
|
||||
@@ -1191,12 +1126,12 @@
|
||||
word-break: break-all;
|
||||
}
|
||||
.o_group {
|
||||
&.o_inner_group {
|
||||
@include form-break-table;
|
||||
.o_inner_group {
|
||||
margin-bottom: $o-form-spacing-unit * 4;
|
||||
|
||||
// Target XXS form view on mobile devices in portrait mode
|
||||
@include media-breakpoint-down(md) {
|
||||
&:not(.oe_subtotal_footer) > tbody > tr > td {
|
||||
&:not(.oe_subtotal_footer) > .o_cell {
|
||||
> .o_field_widget {
|
||||
margin-bottom: $o-form-spacing-unit * 4;
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ export class OuterGroup extends Group {
|
||||
return items.map((item) => {
|
||||
const [slotName, slot] = item;
|
||||
const itemSpan = slot.itemSpan || 1;
|
||||
return { name: slotName, size: itemSpan * colSize, newline: slot.newline };
|
||||
return { name: slotName, size: itemSpan * colSize, newline: slot.newline, colspan: itemSpan };
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -34,6 +34,7 @@ OuterGroup.template = "web.Form.OuterGroup";
|
||||
OuterGroup.defaultProps = {
|
||||
...Group.defaultProps,
|
||||
slots: [],
|
||||
hasOuterTemplate: true,
|
||||
};
|
||||
|
||||
export class InnerGroup extends Group {
|
||||
@@ -66,6 +67,9 @@ export class InnerGroup extends Group {
|
||||
const isVisible = !("isVisible" in slot) || slot.isVisible;
|
||||
currentRow.push({ name: slotName, subType, itemSpan, props, isVisible, Component });
|
||||
reservedSpace += itemSpan || 1;
|
||||
|
||||
// Allows to remove the line if the content is not visible instead of leaving an empty line.
|
||||
currentRow.isVisible = isVisible;
|
||||
}
|
||||
rows.push(currentRow);
|
||||
|
||||
|
||||
@@ -2,44 +2,48 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.Form.OuterGroup" owl="1">
|
||||
<div class="o_group" t-attf-class="{{ allClasses }}" t-att-style="props.style">
|
||||
<t t-slot="title" t-if="props.slots.title" />
|
||||
<t t-foreach="getItems()" t-as="item" t-key="item_index" >
|
||||
<br t-if="item.newline" />
|
||||
<t t-slot="{{ item.name }}" className="'o_group_col_' + item.size"/>
|
||||
</t>
|
||||
</div>
|
||||
<div class="o_group row g-2 gx-lg-5 align-items-start" t-attf-class="{{ allClasses }} {{ props.hasOuterTemplate and props.class ? '' : 'my-3' }}" t-att-style="props.style">
|
||||
<t t-slot="title" t-if="props.slots.title" />
|
||||
<t t-foreach="getItems()" t-as="item" t-key="item_index">
|
||||
<span class="o_newline" t-if="item.newline" />
|
||||
<t t-slot="{{ item.name }}" className="item.colspan !== props.maxCols ? 'col-lg-' + item.size : ''"/>
|
||||
</t>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-name="web.Form.InnerGroup" owl="1">
|
||||
<table t-attf-class="{{ allClasses }}" class="o_inner_group o_group" t-if="props.slots" t-att-style="props.style">
|
||||
<tbody>
|
||||
<td t-if="props.slots.title" t-attf-colspan="{{ props.maxCols }}" style="width: 100%">
|
||||
<t t-slot="title" />
|
||||
</td>
|
||||
<tr t-foreach="getRows()" t-as="row" t-key="row_index">
|
||||
<t t-foreach="row" t-as="cell" t-key="cell_index" >
|
||||
<div t-attf-class="{{ allClasses }}" class="o_inner_group grid" t-if="props.slots" t-att-style="props.style">
|
||||
<div t-if="props.slots.title" t-attf-class="g-col-sm-{{ props.maxCols }}">
|
||||
<t t-slot="title" />
|
||||
</div>
|
||||
<div t-foreach="getRows()" t-as="row" t-key="row_index" class="o_wrap_field d-flex d-sm-contents flex-column mb-3 mb-sm-0" t-if="row.isVisible">
|
||||
<t t-foreach="row" t-as="cell" t-key="cell_index">
|
||||
|
||||
<t t-if="cell.subType === 'item_component'" >
|
||||
<td class="o_td_label">
|
||||
<t t-component="cell.Component" t-if="cell.isVisible" t-props="cell.props" />
|
||||
</td>
|
||||
<td t-att-colspan="cell.itemSpan -1 > 1 ? cell.itemSpan - 1 : undefined" t-attf-style="{{ cell.width ? 'width: ' + cell.width + '%' : undefined }}">
|
||||
<t t-if="cell.isVisible" t-slot="{{ cell.name }}" />
|
||||
</td>
|
||||
</t>
|
||||
<t t-if="cell.subType === 'item_component'">
|
||||
<div class="o_cell o_wrap_label flex-grow-1 flex-sm-grow-0 w-100 text-break text-900">
|
||||
<t t-component="cell.Component" t-if="cell.isVisible" t-props="cell.props"/>
|
||||
</div>
|
||||
<div
|
||||
class="o_cell o_wrap_input flex-grow-1 flex-sm-grow-0"
|
||||
t-attf-style="{{ cell.itemSpan -1 > 1 ? 'grid-column: span ' + (cell.itemSpan -1) + ';' : '' }}{{ cell.width ? 'width: ' + cell.width + '%' + ';' : '' }}"
|
||||
>
|
||||
<t t-slot="{{ cell.name }}" />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
<t t-else="">
|
||||
<td t-attf-class="{{ cell.subType === 'label' ? 'o_td_label' : null }}" t-attf-colspan="{{ cell.itemSpan > 1 ? cell.itemSpan : undefined }}"
|
||||
t-attf-style="{{ cell.width ? 'width: ' + cell.width + '%' : undefined }}">
|
||||
<t t-if="cell.isVisible" t-slot="{{ cell.name }}" />
|
||||
</td>
|
||||
</t>
|
||||
<t t-else="">
|
||||
<div
|
||||
class="o_cell flex-grow-1 flex-sm-grow-0"
|
||||
t-attf-style="{{ cell.itemSpan > 1 ? 'grid-column: span ' + cell.itemSpan + ';' : '' }}{{ cell.width ? 'width: ' + cell.width + '%' + ';' : '' }}"
|
||||
t-attf-class="{{ cell.subType === 'label' ? 'o_wrap_label w-100 text-break text-900' : null }}"
|
||||
t-if="cell.isVisible">
|
||||
<t t-slot="{{ cell.name }}" />
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</t>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
|
||||
</templates>
|
||||
|
||||
@@ -5429,7 +5429,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
await click(target.querySelector(".modal-footer button.btn-primary"));
|
||||
|
||||
assert.containsOnce(target, ".modal");
|
||||
assert.containsOnce(target, ".modal tbody label.o_field_invalid");
|
||||
assert.containsOnce(target, ".modal label.o_field_invalid");
|
||||
});
|
||||
|
||||
QUnit.test("one2many list with action button", async function (assert) {
|
||||
|
||||
@@ -919,7 +919,7 @@ QUnit.module("Fields", (hooks) => {
|
||||
</form>`,
|
||||
});
|
||||
|
||||
const groups = target.querySelectorAll(".o_group");
|
||||
const groups = target.querySelectorAll(".o_inner_group");
|
||||
|
||||
assert.containsNone(
|
||||
groups[0],
|
||||
|
||||
@@ -276,7 +276,7 @@ QUnit.module("Views", (hooks) => {
|
||||
assert.containsOnce(target, ".o_field_char input");
|
||||
assert.strictEqual(target.querySelector(".o_field_char input").value, "blip");
|
||||
assert.hasAttrValue(
|
||||
target.querySelector(".o_group .o_group"),
|
||||
target.querySelector(".o_group .o_inner_group"),
|
||||
"style",
|
||||
"background-color: red",
|
||||
"should apply style attribute on groups"
|
||||
@@ -292,7 +292,7 @@ QUnit.module("Views", (hooks) => {
|
||||
assert.containsOnce(target, "div.o_field_one2many table");
|
||||
assert.containsOnce(
|
||||
target,
|
||||
"tbody td:not(.o_list_record_selector) .o-checkbox input:checked"
|
||||
"div.o_cell:not(.o_list_record_selector) .o-checkbox input:checked"
|
||||
);
|
||||
assert.containsNone(target, "label.o_form_label_empty:contains(timmy)");
|
||||
});
|
||||
@@ -825,7 +825,7 @@ QUnit.module("Views", (hooks) => {
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
assert.containsOnce(target, "table.o_inner_group");
|
||||
assert.containsOnce(target, "div.o_inner_group");
|
||||
});
|
||||
|
||||
QUnit.test("group containing both a field and a group", async function (assert) {
|
||||
@@ -854,7 +854,7 @@ QUnit.module("Views", (hooks) => {
|
||||
assert.containsOnce(target, ".o_group .o_inner_group .o_field_widget[name=int_field]");
|
||||
|
||||
assert.hasClass(target.querySelector(".o_field_widget[name=foo]"), "o_field_char");
|
||||
assert.hasClass(target.querySelector(".o_field_widget[name=foo]"), "o_group_col_6");
|
||||
assert.hasClass(target.querySelector(".o_field_widget[name=foo]"), "col-lg-6");
|
||||
});
|
||||
|
||||
QUnit.test("Form and subview with _view_ref contexts", async function (assert) {
|
||||
@@ -1035,8 +1035,8 @@ QUnit.module("Views", (hooks) => {
|
||||
assert.containsNone(target, ".o_form_statusbar button:contains(coucou)");
|
||||
assert.containsOnce(target, ".o_notebook li a:contains(visible)");
|
||||
assert.containsNone(target, ".o_notebook li a:contains(invisible)");
|
||||
assert.containsOnce(target, "table.o_inner_group td:contains(visgroup)");
|
||||
assert.containsNone(target, "table.o_inner_group td:contains(invgroup)");
|
||||
assert.containsOnce(target, "div.o_inner_group:contains(visgroup)");
|
||||
assert.containsNone(target, "div.o_inner_group:contains(invgroup)");
|
||||
});
|
||||
|
||||
QUnit.test(
|
||||
@@ -3962,18 +3962,18 @@ QUnit.module("Views", (hooks) => {
|
||||
);
|
||||
|
||||
assert.hasAttrValue(
|
||||
target.querySelector(".firstgroup td"),
|
||||
"colspan",
|
||||
target.querySelector(".firstgroup div"),
|
||||
"style",
|
||||
undefined,
|
||||
"foo td should have a default colspan (1)"
|
||||
"foo div should have a default colspan (1)"
|
||||
);
|
||||
assert.containsN(target, ".secondgroup tr", 2, "int_field and qux should have same tr");
|
||||
assert.containsN(target, ".secondgroup div.o_wrap_field", 2, "int_field and qux should have same o_wrap_field");
|
||||
|
||||
assert.containsN(
|
||||
target,
|
||||
".secondgroup tr:first td",
|
||||
".secondgroup div.o_wrap_field:first div.o_cell",
|
||||
2,
|
||||
"product_id field should be on its own tr"
|
||||
"product_id field should be on its own o_wrap_field"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4867,8 +4867,8 @@ QUnit.module("Views", (hooks) => {
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
assert.hasClass(target.querySelector(".inner_group"), "o_group_col_6");
|
||||
assert.hasClass(target.querySelector(".inner_div"), "o_group_col_6");
|
||||
assert.hasClass(target.querySelector(".inner_group"), "col-lg-6");
|
||||
assert.hasClass(target.querySelector(".inner_div"), "col-lg-6");
|
||||
});
|
||||
|
||||
QUnit.test("deleting a record", async function (assert) {
|
||||
@@ -7804,10 +7804,10 @@ QUnit.module("Views", (hooks) => {
|
||||
|
||||
// Verify outergroup/innergroup
|
||||
assert.strictEqual($parentGroup[0].tagName, "DIV", ".parent_group should be an outergroup");
|
||||
assert.strictEqual($group4[0].tagName, "TABLE", ".group_4 should be an innergroup");
|
||||
assert.strictEqual($group4[0].tagName, "DIV", ".group_4 should be an innergroup");
|
||||
assert.strictEqual($group3[0].tagName, "DIV", ".group_3 should be an outergroup");
|
||||
assert.strictEqual($group1[0].tagName, "TABLE", ".group_1 should be an innergroup");
|
||||
assert.strictEqual($fieldGroup[0].tagName, "TABLE", ".field_group should be an innergroup");
|
||||
assert.strictEqual($group1[0].tagName, "DIV", ".group_1 should be an innergroup");
|
||||
assert.strictEqual($fieldGroup[0].tagName, "DIV", ".field_group should be an innergroup");
|
||||
|
||||
// Verify .parent_group content
|
||||
var $parentGroupChildren = $parentGroup.children();
|
||||
@@ -7817,174 +7817,131 @@ QUnit.module("Views", (hooks) => {
|
||||
"there should be 2 groups in .parent_group"
|
||||
);
|
||||
assert.ok(
|
||||
$parentGroupChildren.eq(0).is(".o_group_col_6"),
|
||||
$parentGroupChildren.eq(0).is(".col-lg-6"),
|
||||
"first .parent_group group should be 1/2 parent width"
|
||||
);
|
||||
assert.ok(
|
||||
$parentGroupChildren.eq(1).is(".o_group_col_8"),
|
||||
"second .parent_group group should be 2/3 parent width"
|
||||
$parentGroupChildren.eq(1).is(".col-lg-8"),
|
||||
"second .parent_group group should be 3/4 parent width"
|
||||
);
|
||||
|
||||
// Verify .group_4 content
|
||||
var $group4rows = $group4.find("> tbody > tr");
|
||||
var $group4rows = $group4.find("> div.o_wrap_field");
|
||||
assert.strictEqual($group4rows.length, 3, "there should be 3 rows in .group_4");
|
||||
var $group4firstRowTd = $group4rows.eq(0).children("td");
|
||||
assert.strictEqual($group4firstRowTd.length, 1, "there should be 1 td in first row");
|
||||
assert.hasAttrValue($group4firstRowTd, "colspan", "3", "the first td colspan should be 3");
|
||||
var $group4firstRowTd = $group4rows.eq(0).children("div.o_cell");
|
||||
assert.strictEqual($group4firstRowTd.length, 1, "there should be 1 cell in first row");
|
||||
assert.strictEqual($group4firstRowTd.attr("style").substr(0, 19), "grid-column: span 3", "the first cell column span should be 3");
|
||||
assert.strictEqual(
|
||||
$group4firstRowTd.attr("style").substr(0, 9),
|
||||
"width: 75",
|
||||
"the first td should be 75% width"
|
||||
$group4firstRowTd.attr("style").substr(0, 19),
|
||||
"grid-column: span 3",
|
||||
"the first cell should be 75% width"
|
||||
);
|
||||
assert.strictEqual(
|
||||
$group4firstRowTd.children()[0].tagName,
|
||||
"DIV",
|
||||
"the first td should contain a div"
|
||||
);
|
||||
var $group4secondRowTds = $group4rows.eq(1).children("td");
|
||||
assert.strictEqual($group4secondRowTds.length, 2, "there should be 2 tds in second row");
|
||||
assert.hasAttrValue(
|
||||
$group4secondRowTds.eq(0),
|
||||
"colspan",
|
||||
"2",
|
||||
"the first td colspan should be 2"
|
||||
"the first cell should contain a div"
|
||||
);
|
||||
var $group4secondRowTds = $group4rows.eq(1).children("div.o_cell");
|
||||
assert.strictEqual($group4secondRowTds.length, 2, "there should be 2 cells in second row");
|
||||
assert.strictEqual(
|
||||
$group4secondRowTds.eq(0).attr("style").substr(0, 9),
|
||||
"width: 50",
|
||||
"the first td be 50% width"
|
||||
);
|
||||
assert.hasAttrValue(
|
||||
$group4secondRowTds.eq(1),
|
||||
"colspan",
|
||||
undefined,
|
||||
"the second td colspan should be default one (1)"
|
||||
$group4secondRowTds.attr("style").substr(0, 29),
|
||||
"grid-column: span 2;width: 50",
|
||||
"the first cell colspan should be 2 and be 50% width"
|
||||
);
|
||||
assert.strictEqual(
|
||||
$group4secondRowTds.eq(1).attr("style").substr(0, 9),
|
||||
"width: 25",
|
||||
"the second td be 75% width"
|
||||
"the second cell colspan should be default one (no style) and be 25% width"
|
||||
);
|
||||
var $group4thirdRowTd = $group4rows.eq(2).children("td");
|
||||
assert.strictEqual($group4thirdRowTd.length, 1, "there should be 1 td in third row");
|
||||
assert.hasAttrValue($group4thirdRowTd, "colspan", "4", "the first td colspan should be 4");
|
||||
var $group4thirdRowTd = $group4rows.eq(2).children(".o_cell");
|
||||
assert.strictEqual($group4thirdRowTd.length, 1, "there should be 1 cell in third row");
|
||||
assert.strictEqual(
|
||||
$group4thirdRowTd.attr("style").substr(0, 10),
|
||||
"width: 100",
|
||||
"the first td should be 100% width"
|
||||
$group4thirdRowTd.attr("style").substr(0, 30),
|
||||
"grid-column: span 4;width: 100",
|
||||
"the first cell colspan should be 4 and be 100% width"
|
||||
);
|
||||
|
||||
// Verify .group_3 content
|
||||
assert.strictEqual($group3.children().length, 3, ".group_3 should have 3 children");
|
||||
assert.strictEqual(
|
||||
$group3.children(".o_group_col_4").length,
|
||||
$group3.children(".col-lg-4").length,
|
||||
3,
|
||||
".group_3 should have 3 children of 1/3 width"
|
||||
);
|
||||
|
||||
// Verify .group_1 content
|
||||
assert.strictEqual(
|
||||
$group1.find("> tbody > tr").length,
|
||||
$group1.find("> .o_wrap_field").length,
|
||||
3,
|
||||
"there should be 3 rows in .group_1"
|
||||
);
|
||||
|
||||
// Verify .field_group content
|
||||
var $fieldGroupRows = $fieldGroup.find("> tbody > tr");
|
||||
assert.strictEqual($fieldGroupRows.length, 5, "there should be 5 rows in .field_group");
|
||||
var $fieldGroupFirstRowTds = $fieldGroupRows.eq(0).children("td");
|
||||
assert.strictEqual($fieldGroupFirstRowTds.length, 2, "there should be 2 tds in first row");
|
||||
var $fieldGroupRows = $fieldGroup.find("> .o_wrap_field");
|
||||
assert.strictEqual($fieldGroupRows.length, 5, "there should be 5 rows in .o_wrap_field");
|
||||
var $fieldGroupFirstRowTds = $fieldGroupRows.eq(0).children(".o_cell");
|
||||
assert.strictEqual($fieldGroupFirstRowTds.length, 2, "there should be 2 cells in first row");
|
||||
assert.hasClass(
|
||||
$fieldGroupFirstRowTds.eq(0),
|
||||
"o_td_label",
|
||||
"first td should be a label td"
|
||||
);
|
||||
assert.hasAttrValue(
|
||||
$fieldGroupFirstRowTds.eq(1),
|
||||
"colspan",
|
||||
"2",
|
||||
"second td colspan should be given colspan (3) - 1 (label)"
|
||||
"o_wrap_label",
|
||||
"first cell should be a label cell"
|
||||
);
|
||||
assert.strictEqual(
|
||||
$fieldGroupFirstRowTds.eq(1).attr("style").substr(0, 10),
|
||||
"width: 100",
|
||||
"second td width should be 100%"
|
||||
$fieldGroupFirstRowTds.eq(1).attr("style").substr(0, 30),
|
||||
"grid-column: span 2;width: 100",
|
||||
"second cell colspan should be given colspan (3) - 1 (label) and be 100%"
|
||||
);
|
||||
var $fieldGroupSecondRowTds = $fieldGroupRows.eq(1).children("td");
|
||||
var $fieldGroupSecondRowTds = $fieldGroupRows.eq(1).children(".o_cell");
|
||||
assert.strictEqual(
|
||||
$fieldGroupSecondRowTds.length,
|
||||
2,
|
||||
"there should be 2 tds in second row"
|
||||
);
|
||||
assert.hasAttrValue(
|
||||
$fieldGroupSecondRowTds.eq(0),
|
||||
"colspan",
|
||||
undefined,
|
||||
"first td colspan should be default one (1)"
|
||||
"there should be 2 cells in second row"
|
||||
);
|
||||
assert.strictEqual(
|
||||
$fieldGroupSecondRowTds.eq(0).attr("style").substr(0, 9),
|
||||
"width: 33",
|
||||
"first td width should be 33.3333%"
|
||||
);
|
||||
assert.hasAttrValue(
|
||||
$fieldGroupSecondRowTds.eq(1),
|
||||
"colspan",
|
||||
undefined,
|
||||
"second td colspan should be default one (1)"
|
||||
"first cell colspan should be default one (no style) and be 33.3333%"
|
||||
);
|
||||
assert.strictEqual(
|
||||
$fieldGroupSecondRowTds.eq(1).attr("style").substr(0, 9),
|
||||
"width: 33",
|
||||
"second td width should be 33.3333%"
|
||||
"second cell colspan should be default one (no style) and be 33.3333%"
|
||||
);
|
||||
var $fieldGroupThirdRowTds = $fieldGroupRows.eq(2).children("td"); // new row as label/field pair colspan is greater than remaining space
|
||||
assert.strictEqual($fieldGroupThirdRowTds.length, 2, "there should be 2 tds in third row");
|
||||
var $fieldGroupThirdRowTds = $fieldGroupRows.eq(2).children(".o_cell"); // new row as label/field pair colspan is greater than remaining space
|
||||
assert.strictEqual($fieldGroupThirdRowTds.length, 2, "there should be 2 cells in third row");
|
||||
assert.hasClass(
|
||||
$fieldGroupThirdRowTds.eq(0),
|
||||
"o_td_label",
|
||||
"first td should be a label td"
|
||||
);
|
||||
assert.hasAttrValue(
|
||||
$fieldGroupThirdRowTds.eq(1),
|
||||
"colspan",
|
||||
undefined,
|
||||
"second td colspan should be default one (1)"
|
||||
"o_wrap_label",
|
||||
"first cell should be a label cell"
|
||||
);
|
||||
assert.strictEqual(
|
||||
$fieldGroupThirdRowTds.eq(1).attr("style").substr(0, 9),
|
||||
"width: 50",
|
||||
"second td should be 50% width"
|
||||
);
|
||||
var $fieldGroupFourthRowTds = $fieldGroupRows.eq(3).children("td");
|
||||
assert.strictEqual($fieldGroupFourthRowTds.length, 1, "there should be 1 td in fourth row");
|
||||
assert.hasAttrValue(
|
||||
$fieldGroupFourthRowTds,
|
||||
"colspan",
|
||||
"3",
|
||||
"the td should have a colspan equal to 3"
|
||||
"second cell colspan should be default one (no style) and be 50% width"
|
||||
);
|
||||
var $fieldGroupFourthRowTds = $fieldGroupRows.eq(3).children(".o_cell");
|
||||
assert.strictEqual($fieldGroupFourthRowTds.length, 1, "there should be 1 cell in fourth row");
|
||||
assert.strictEqual(
|
||||
$fieldGroupFourthRowTds.attr("style").substr(0, 10),
|
||||
"width: 100",
|
||||
"the td should have 100% width"
|
||||
$fieldGroupFourthRowTds.attr("style").substr(0, 30),
|
||||
"grid-column: span 3;width: 100",
|
||||
"the cell should have a colspan equal to 3 and have 100% width"
|
||||
);
|
||||
var $fieldGroupFifthRowTds = $fieldGroupRows.eq(4).children("td"); // label/field pair can be put after the 1-colspan span
|
||||
assert.strictEqual($fieldGroupFifthRowTds.length, 3, "there should be 3 tds in fourth row");
|
||||
var $fieldGroupFifthRowTds = $fieldGroupRows.eq(4).children(".o_cell"); // label/field pair can be put after the 1-colspan span
|
||||
assert.strictEqual($fieldGroupFifthRowTds.length, 3, "there should be 3 cells in fourth row");
|
||||
assert.strictEqual(
|
||||
$fieldGroupFifthRowTds.eq(0).attr("style").substr(0, 9),
|
||||
"width: 50",
|
||||
"the first td should 50% width"
|
||||
"the first cell should 50% width"
|
||||
);
|
||||
assert.hasClass(
|
||||
$fieldGroupFifthRowTds.eq(1),
|
||||
"o_td_label",
|
||||
"the second td should be a label td"
|
||||
"o_wrap_label",
|
||||
"the second cell should be a label cell"
|
||||
);
|
||||
assert.strictEqual(
|
||||
$fieldGroupFifthRowTds.eq(2).attr("style").substr(0, 9),
|
||||
"width: 50",
|
||||
"the third td should 50% width"
|
||||
"the third cell should 50% width"
|
||||
);
|
||||
});
|
||||
|
||||
@@ -8012,10 +7969,10 @@ QUnit.module("Views", (hooks) => {
|
||||
resId: 1,
|
||||
});
|
||||
|
||||
const rows = document.querySelectorAll(".o_inner_group tr");
|
||||
assert.containsOnce(rows[0], "> td", "Should only contain one cell");
|
||||
const rows = document.querySelectorAll(".o_inner_group > div");
|
||||
assert.containsOnce(rows[0], "> .o_cell", "Should only contain one cell");
|
||||
assert.containsOnce(rows[0], ".o_horizontal_separator");
|
||||
assert.containsN(rows[1], "> td", 2, "Should contain 2 cells");
|
||||
assert.containsN(rows[1], "> .o_cell", 2, "Should contain 2 cells");
|
||||
assert.containsOnce(rows[1], "label[for=display_name]");
|
||||
assert.containsOnce(rows[1], "div[name=display_name]");
|
||||
}
|
||||
@@ -8045,7 +8002,7 @@ QUnit.module("Views", (hooks) => {
|
||||
var $parentGroup = $(target.querySelector(".parent_group"));
|
||||
var $group1 = $(target.querySelector(".group_1"));
|
||||
var $group2 = $(target.querySelector(".group_2"));
|
||||
assert.containsN(target, "table.o_inner_group", 2, "should contain two inner groups");
|
||||
assert.containsN(target, "div.o_inner_group", 2, "should contain two inner groups");
|
||||
assert.strictEqual(
|
||||
$group1.find(".o_horizontal_separator").length,
|
||||
1,
|
||||
@@ -8089,7 +8046,7 @@ QUnit.module("Views", (hooks) => {
|
||||
<group col="3">
|
||||
<!-- col=3 otherwise the test is ok even without the
|
||||
newline code as this will render a <newline/> DOM
|
||||
element with the o_group_col_6 class, leaving no
|
||||
element with the g-col-2 class, leaving no
|
||||
place for the next group on the same line. -->
|
||||
<group class="top_group">
|
||||
<div style="height: 200px;"/>
|
||||
@@ -8107,29 +8064,29 @@ QUnit.module("Views", (hooks) => {
|
||||
// Inner group
|
||||
assert.containsN(
|
||||
target,
|
||||
".main_inner_group > tbody > tr",
|
||||
".main_inner_group > .o_wrap_field",
|
||||
2,
|
||||
"there should be 2 rows in the group"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".main_inner_group > tbody > tr:first > .o_td_label",
|
||||
".main_inner_group > .o_wrap_field:first > .o_wrap_label",
|
||||
"there should be only one label in the first row"
|
||||
);
|
||||
assert.containsOnce(
|
||||
target,
|
||||
".main_inner_group > tbody > tr:first .o_field_widget",
|
||||
".main_inner_group > .o_wrap_field:first .o_field_widget",
|
||||
"there should be only one widget in the first row"
|
||||
);
|
||||
assert.containsN(
|
||||
target,
|
||||
".main_inner_group > tbody > tr:last > .o_td_label",
|
||||
".main_inner_group > .o_wrap_field:last > .o_wrap_label",
|
||||
2,
|
||||
"there should be two labels in the second row"
|
||||
);
|
||||
assert.containsN(
|
||||
target,
|
||||
".main_inner_group > tbody > tr:last .o_field_widget",
|
||||
".main_inner_group > .o_wrap_field:last .o_field_widget",
|
||||
2,
|
||||
"there should be two widgets in the second row"
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user