[REF] web, website: FormView, review and simplify scss
Review, simplify SCSS and adapt legacy code. Part of the overall v16 SCSS optimization/restyle, task-2704984 task-2918464 closes odoo/odoo#98101 Related: odoo/enterprise#30421 Signed-off-by: Adrien Dieudonné (adr) <adr@odoo.com>
This commit is contained in:
@@ -1,16 +1,14 @@
|
||||
.o-form-buttonbox {
|
||||
position: relative;
|
||||
display: block;
|
||||
--o-input-border-color: #{map-get($grays, '600')};
|
||||
margin-bottom: $o-sheet-vpadding;
|
||||
margin-top: -$o-sheet-vpadding;
|
||||
@include o-form-sheet-negative-margin;
|
||||
text-align: right;
|
||||
// Use box-shadow instead of border-bottom because some button boxes are
|
||||
// empty in some cases and we do not want to see a floating border in
|
||||
// that cases.
|
||||
box-shadow: inset 0 -1px 0 $border-color;
|
||||
|
||||
.btn.oe_stat_button {
|
||||
.btn.oe_stat_button, > .o_field_widget {
|
||||
flex: 0 0 auto;
|
||||
width: percentage(1/3); // Adapt the number of visible buttons for each screen width
|
||||
@include media-breakpoint-up(md) {
|
||||
@@ -24,25 +22,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
&.o_full > *:first-child {
|
||||
border-left: none !important;
|
||||
box-shadow: -1px 0 0 $border-color;
|
||||
}
|
||||
|
||||
.btn.oe_stat_button {
|
||||
color: $o-main-text-color;
|
||||
height: $o-statbutton-height;
|
||||
// Use !important to avoid touch_device style
|
||||
padding: 0 $o-statbutton-spacing 0 0 !important; // padding-left will be achieved through margin-left of content
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
background-color: transparent;
|
||||
border-radius: 0px;
|
||||
margin-bottom: 0; // If the button comes from a field
|
||||
|
||||
&:hover, &:focus {
|
||||
background-color: rgba(black, 0.03);
|
||||
color: inherit;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
> .o_button_icon {
|
||||
margin-left: $o-statbutton-spacing; // To create the button padding left (firefox bug)
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
line-height: $o-statbutton-height;
|
||||
@@ -127,8 +115,6 @@
|
||||
.o_dropdown_more {
|
||||
width: 150px;
|
||||
> .dropdown-item {
|
||||
border: none;
|
||||
border-bottom: 1px solid $border-color;
|
||||
.oe_stat_button {
|
||||
border: none;
|
||||
width: 100%;
|
||||
@@ -136,4 +122,4 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,12 @@
|
||||
<t t-set="allButtons" t-value="getButtons()" />
|
||||
<t t-set="visibleButtons" t-value="allButtons['visible']" />
|
||||
<t t-set="additionalButtons" t-value="allButtons['additional']" />
|
||||
<div class="o-form-buttonbox oe_button_box" t-attf-class="{{ visibleButtons.length >= getMaxButtons() ? 'o_full' : 'o_not_full'}} {{this.props.class}}">
|
||||
<t t-slot="{{ button_value }}" t-foreach="visibleButtons" t-as="button" t-key="button_value" />
|
||||
|
||||
<div class="o-form-buttonbox oe_button_box position-relative text-end" t-attf-class="{{ visibleButtons.length >= getMaxButtons() ? 'o_full' : 'o_not_full'}} {{this.props.class}}">
|
||||
<t t-slot="{{ button_value }}" t-foreach="visibleButtons" t-as="button" t-key="button_value"/>
|
||||
<t t-if="additionalButtons.length" >
|
||||
<Dropdown togglerClass="'btn o_button_more'" menuClass="'o_dropdown_more p-0'" class="'btn oe_stat_button'">
|
||||
<Dropdown togglerClass="'btn btn-light o_button_more border-0 border-start border-bottom'" menuClass="'o_dropdown_more position-absolute start-0 top-100 w-100 p-0 border-0'" class="'oe_stat_button btn position-relative p-0 border-0'">
|
||||
<t t-set-slot="toggler"><span>More</span></t>
|
||||
<DropdownItem t-foreach="additionalButtons" t-as="button" t-key="button_value" class="'p-0'">
|
||||
<DropdownItem t-foreach="additionalButtons" t-as="button" t-key="button_value" class="'d-flex flex-column p-0'">
|
||||
<t t-slot="{{ button_value }}" />
|
||||
</DropdownItem>
|
||||
</Dropdown>
|
||||
|
||||
@@ -148,8 +148,11 @@ export class FormCompiler extends ViewCompiler {
|
||||
? `!evalDomainFromRecord(props.record,${JSON.stringify(invisible)})`
|
||||
: true,
|
||||
});
|
||||
if (child.tagName === "button") {
|
||||
child.classList.add("oe_stat_button");
|
||||
if (child.tagName === "button" || child.children.tagName === "button") {
|
||||
child.classList.add("oe_stat_button", "btn-light", "flex-shrink-0", "mb-0", "py-0", "border-0", "border-start", "border-bottom", "rounded-0", "text-start", "text-nowrap", "text-capitalize");
|
||||
}
|
||||
if (child.tagName === "field") {
|
||||
child.classList.add("d-inline-block", "mb-0");
|
||||
}
|
||||
append(mainSlot, this.compileNode(child, params, false));
|
||||
append(buttonBox, mainSlot);
|
||||
@@ -361,7 +364,7 @@ export class FormCompiler extends ViewCompiler {
|
||||
*/
|
||||
compileHeader(el, params) {
|
||||
const statusBar = createElement("div");
|
||||
statusBar.className = "o_form_statusbar";
|
||||
statusBar.className = "o_form_statusbar position-relative d-flex justify-content-between border-bottom";
|
||||
const buttons = [];
|
||||
const others = [];
|
||||
for (const child of el.childNodes) {
|
||||
|
||||
@@ -428,7 +428,7 @@ export class FormController extends Component {
|
||||
if (size <= SIZES.XS) {
|
||||
sizeClass = "o_xxs_form_view";
|
||||
} else if (size === SIZES.XXL) {
|
||||
sizeClass = "o_xxl_form_view";
|
||||
sizeClass = "o_xxl_form_view h-100";
|
||||
}
|
||||
return {
|
||||
[this.props.className]: true,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Define left and right padding according to screen resolution
|
||||
@mixin o-form-sheet-inner-left-padding {
|
||||
padding-left: $o-horizontal-padding;
|
||||
@include media-breakpoint-between(lg, $o-extra-grid-breakpoints) {
|
||||
@include media-breakpoint-up(lg, $o-extra-grid-breakpoints) {
|
||||
padding-left: $o-horizontal-padding*2;
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@
|
||||
}
|
||||
@mixin o-form-sheet-inner-right-padding {
|
||||
padding-right: $o-horizontal-padding;
|
||||
@include media-breakpoint-between(lg, $o-extra-grid-breakpoints) {
|
||||
@include media-breakpoint-up(lg, $o-extra-grid-breakpoints) {
|
||||
padding-right: $o-horizontal-padding*2;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@
|
||||
@mixin o-form-sheet-negative-margin {
|
||||
margin-left: -$o-horizontal-padding;
|
||||
margin-right: -$o-horizontal-padding;
|
||||
@include media-breakpoint-between(lg, $o-extra-grid-breakpoints) {
|
||||
@include media-breakpoint-up(lg, $o-extra-grid-breakpoints) {
|
||||
margin-left: -$o-horizontal-padding*2;
|
||||
margin-right: -$o-horizontal-padding*2;
|
||||
}
|
||||
@@ -192,14 +192,10 @@ $o-form-label-margin-right: 0px;
|
||||
|
||||
// Statusbar
|
||||
.o_form_statusbar {
|
||||
position: relative; // Needed for the "More" dropdown
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
padding-left: $o-horizontal-padding;
|
||||
border-bottom: 1px solid $border-color;
|
||||
background-color: $o-view-background-color;
|
||||
|
||||
> .o_statusbar_buttons, > .o_statusbar_status {
|
||||
> .o_statusbar_status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
align-content: space-around;
|
||||
@@ -211,8 +207,6 @@ $o-form-label-margin-right: 0px;
|
||||
}
|
||||
|
||||
> .o_statusbar_buttons {
|
||||
flex-flow: row wrap;
|
||||
|
||||
> .btn, .o_widget > .btn {
|
||||
$o-statusbar-buttons-vmargin: 4px;
|
||||
min-height: $o-statusbar-height - 2 * $o-statusbar-buttons-vmargin;
|
||||
@@ -380,10 +374,6 @@ $o-form-label-margin-right: 0px;
|
||||
|
||||
// Separators
|
||||
.o_horizontal_separator {
|
||||
font-size: $font-size-sm;
|
||||
font-weight: $font-weight-bold;
|
||||
margin: 1.2em ($grid-gutter-width * .5) .8em 0;
|
||||
|
||||
&:not(:empty) {
|
||||
box-shadow: 0 $border-width 0 $o-form-separator-color;
|
||||
}
|
||||
@@ -405,8 +395,7 @@ $o-form-label-margin-right: 0px;
|
||||
|
||||
// Labels
|
||||
.o_form_label {
|
||||
margin: 0 $o-form-spacing-unit 0 0;
|
||||
color: $headings-color;
|
||||
margin-right: $o-form-spacing-unit;
|
||||
font-size: $font-size-base; // The label muse have the same size whatever their position
|
||||
line-height: $line-height-base;
|
||||
font-weight: $font-weight-bold;
|
||||
@@ -482,7 +471,7 @@ $o-form-label-margin-right: 0px;
|
||||
|
||||
.o_form_label {
|
||||
padding-right: 20px;
|
||||
|
||||
margin-right: 0;
|
||||
min-width: 0;
|
||||
white-space: nowrap;
|
||||
&:after {
|
||||
@@ -500,11 +489,10 @@ $o-form-label-margin-right: 0px;
|
||||
> tbody > tr:first-child > td {
|
||||
padding-top: 4px;
|
||||
}
|
||||
|
||||
.oe_subtotal_footer_separator {
|
||||
width: 100%;
|
||||
text-align: right;
|
||||
border-top: 1px solid map-get($grays, '300');
|
||||
border-top: 1px solid $border-color;
|
||||
font-weight: $font-weight-bold;
|
||||
font-size: 1.3em;
|
||||
}
|
||||
@@ -757,6 +745,7 @@ $o-form-label-margin-right: 0px;
|
||||
> tr {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
padding-bottom: map-get($spacers, 3);
|
||||
|
||||
> td {
|
||||
flex: 1 0 auto;
|
||||
@@ -792,7 +781,6 @@ $o-form-label-margin-right: 0px;
|
||||
|
||||
.o_xxl_form_view {
|
||||
flex-flow: row nowrap;
|
||||
height: 100%;
|
||||
|
||||
.o_form_sheet_bg {
|
||||
flex: 1 1 auto; // Side chatter is disabled if this has to shrink but this was added for safety
|
||||
|
||||
@@ -55,6 +55,6 @@ export class FormLabel extends Component {
|
||||
}
|
||||
FormLabel.template = xml`
|
||||
<label class="o_form_label" t-att-for="props.id" t-att-class="className" >
|
||||
<t t-esc="props.string"/><sup class="btn-link p-2" t-if="hasTooltip" t-att="{'data-tooltip-template': 'web.FieldTooltip', 'data-tooltip-info': tooltipInfo, 'data-tooltip-touch-tap-to-show': 'true'}">?</sup>
|
||||
<t t-esc="props.string"/><sup class="btn-link p-1" t-if="hasTooltip" t-att="{'data-tooltip-template': 'web.FieldTooltip', 'data-tooltip-info': tooltipInfo, 'data-tooltip-touch-tap-to-show': 'true'}">?</sup>
|
||||
</label>
|
||||
`;
|
||||
|
||||
@@ -97,7 +97,6 @@ $o-td-label-padding-right: 8px;
|
||||
// Separators
|
||||
.o_horizontal_separator {
|
||||
color: $o-brand-primary;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
// Specific style classes
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="web.StatusBarButtons" owl="1">
|
||||
<div class="o_statusbar_buttons">
|
||||
<div class="o_statusbar_buttons d-flex align-items-center align-content-around">
|
||||
<t t-set="slots" t-value="visibleSlotNames" />
|
||||
<t t-if="env.isSmall and slots.length > 1">
|
||||
<Dropdown togglerClass="'btn btn-primary'">
|
||||
|
||||
@@ -217,7 +217,7 @@ export function isTextNode(node) {
|
||||
*/
|
||||
export function makeSeparator(title) {
|
||||
const separator = createElement("div");
|
||||
separator.className = "o_horizontal_separator";
|
||||
separator.className = "o_horizontal_separator mt-4 mb-3 text-uppercase fw-bolder small";
|
||||
separator.textContent = title;
|
||||
return separator;
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ QUnit.module("Form Compiler", () => {
|
||||
const expected = /*xml*/ `
|
||||
<t>
|
||||
<div t-att-class="props.class" t-attf-class="{{props.record.isInEdition ? 'o_form_editable' : 'o_form_readonly'}} d-block" class="o_form_nosheet" t-ref="compiled_view_root">
|
||||
<div class="o_form_statusbar"><StatusBarButtons readonly="!props.record.isInEdition"/></div>
|
||||
<div class="o_form_statusbar position-relative d-flex justify-content-between border-bottom"><StatusBarButtons readonly="!props.record.isInEdition"/></div>
|
||||
<div>someDiv</div>
|
||||
</div>
|
||||
</t>`;
|
||||
@@ -168,7 +168,7 @@ QUnit.module("Form Compiler", () => {
|
||||
<t>
|
||||
<div t-att-class="props.class" t-attf-class="{{props.record.isInEdition ? 'o_form_editable' : 'o_form_readonly'}} d-flex {{ uiService.size < 6 ? "flex-column" : "flex-nowrap h-100" }}" t-ref="compiled_view_root">
|
||||
<div class="o_form_sheet_bg">
|
||||
<div class="o_form_statusbar"><StatusBarButtons readonly="!props.record.isInEdition"/></div>
|
||||
<div class="o_form_statusbar position-relative d-flex justify-content-between border-bottom"><StatusBarButtons readonly="!props.record.isInEdition"/></div>
|
||||
<div>someDiv</div>
|
||||
<div class="o_form_sheet position-relative">
|
||||
<div>inside sheet</div>
|
||||
@@ -228,7 +228,7 @@ QUnit.module("Form Compiler", () => {
|
||||
</form>`;
|
||||
|
||||
const expected = /*xml*/ `
|
||||
<div class="o_form_statusbar">
|
||||
<div class="o_form_statusbar position-relative d-flex justify-content-between border-bottom">
|
||||
<StatusBarButtons readonly="!props.record.isInEdition">
|
||||
<t t-set-slot="button_0" isVisible="true" displayInReadOnly="false">
|
||||
<div>someDiv</div>
|
||||
@@ -246,7 +246,7 @@ QUnit.module("Form Compiler", () => {
|
||||
</form>`;
|
||||
|
||||
const expected = /*xml*/ `
|
||||
<div class="o_form_statusbar">
|
||||
<div class="o_form_statusbar position-relative d-flex justify-content-between border-bottom">
|
||||
<StatusBarButtons readonly="!props.record.isInEdition"/>
|
||||
</div>`;
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<templates xml:space="preserve">
|
||||
|
||||
<t t-name="website.RedirectField" owl="1">
|
||||
<button type="button" class="btn oe_stat_button"
|
||||
<button type="button" class="oe_stat_button btn btn-light w-100 mb-0 py-0 border-0 border-start border-bottom rounded-0 text-start text-nowrap text-capitalize"
|
||||
t-on-click="onClick"
|
||||
t-att-aria-label="info"
|
||||
t-att-title="info">
|
||||
|
||||
Reference in New Issue
Block a user