[FIX] web: Prevent drag on kanban record dropdown

Before this commit, clicking on any part of a kanban record would
initiate a drag & drop sequence, this included its dropdown. This caused
2 issues:

- You could start to drag & drop records by dragging their still opened
dropdowns ;

- Said dropdowns would remain open when dragging their parent record.

This commit fixes both of these issues by hiding dropdowns during drag
sequences and preventing drag when clicking inside the dropdowns.

closes odoo/odoo#98791

Signed-off-by: Simon Genin (ges@odoo) <ges@odoo.com>
This commit is contained in:
Julien Mougenot
2022-08-25 12:05:15 +02:00
parent cf4a8f198f
commit 1ab23b9467
3 changed files with 92 additions and 54 deletions
@@ -3,15 +3,17 @@
display: flex;
align-content: stretch;
.dropdown, .o_kanban_manage_button_section {
.dropdown,
.o_kanban_manage_button_section {
position: inherit;
}
@include media-breakpoint-down(md) {
padding: 0px!important;
padding: 0px !important;
}
.o_kanban_record > div, .o_kanban_quick_create {
.o_kanban_record > div,
.o_kanban_quick_create {
padding: $o-kanban-inside-vgutter $o-kanban-inside-hgutter;
border: 1px solid $border-color;
background-color: $o-view-background-color;
@@ -19,7 +21,8 @@
@include media-breakpoint-down(md) {
padding: $o-kanban-inside-vgutter $o-kanban-inside-hgutter-mobile;
}
&:focus, &:focus-within {
&:focus,
&:focus-within {
z-index: 1; // show the shadow on top of the previous & next cards in grouped mode
outline: none;
}
@@ -37,7 +40,7 @@
}
.o_kanban_cancel {
color: map-get($grays, '600'); // to make color uniform in community and enterprise
color: map-get($grays, "600"); // to make color uniform in community and enterprise
}
&.o_disabled {
@@ -69,15 +72,17 @@
display: flex;
flex-direction: column;
justify-content: space-between;
width: 100%,
width: 100%;
}
// Inner Sections
.o_kanban_record_top, .o_kanban_record_body {
.o_kanban_record_top,
.o_kanban_record_body {
margin-bottom: $o-kanban-inner-hmargin;
}
.o_kanban_record_top, .o_kanban_record_bottom {
.o_kanban_record_top,
.o_kanban_record_bottom {
display: flex;
}
@@ -109,7 +114,7 @@
.o_kanban_record_subtitle {
display: block;
margin-top: $o-kanban-inner-hmargin*0.5;
margin-top: $o-kanban-inner-hmargin * 0.5;
i.fa[role="img"] {
margin-right: 2px;
@@ -117,7 +122,8 @@
}
.o_kanban_record_bottom {
.oe_kanban_bottom_left, .oe_kanban_bottom_right {
.oe_kanban_bottom_left,
.oe_kanban_bottom_right {
display: flex;
align-items: center;
min-height: 20px;
@@ -135,14 +141,15 @@
font-size: 18px;
}
}
.oe_kanban_bottom_right{
.oe_kanban_bottom_right {
flex: 0 1 auto;
.oe_kanban_avatar {
border-radius: 50%;
object-fit: cover;
}
.oe_kanban_avatar, .o_field_many2one_avatar > .o_m2o_avatar {
.oe_kanban_avatar,
.o_field_many2one_avatar > .o_m2o_avatar {
width: 20px;
height: 20px;
margin-left: 6px;
@@ -151,7 +158,7 @@
.o_link_muted {
color: $body-color;
&:hover {
color: map-get($theme-colors, 'primary');
color: map-get($theme-colors, "primary");
text-decoration: underline;
}
}
@@ -165,12 +172,12 @@
.o_kanban_image_fill_left {
position: relative;
margin-right: $o-kanban-inside-hgutter*2;
margin-right: $o-kanban-inside-hgutter * 2;
@include media-breakpoint-up(sm) {
margin: {
top: $o-kanban-inside-vgutter*-1;
bottom: $o-kanban-inside-vgutter*-1;
left: $o-kanban-inside-hgutter*-1;
top: $o-kanban-inside-vgutter * -1;
bottom: $o-kanban-inside-vgutter * -1;
left: $o-kanban-inside-hgutter * -1;
}
}
flex: 1 0 $o-kanban-image-fill-width;
@@ -179,7 +186,7 @@
size: cover;
position: center;
repeat: no-repeat;
};
}
&.o_kanban_image_full {
background-size: contain;
@@ -191,7 +198,7 @@
// Eg. In partners list we use to fill user picture only, keeping the
// default design for company logos.
.o_kanban_image {
margin-right: $o-kanban-inside-hgutter*2;
margin-right: $o-kanban-inside-hgutter * 2;
flex: 0 0 $o-kanban-image-width;
min-height: $o-kanban-image-width;
align-self: center;
@@ -203,8 +210,12 @@
// On medium screen size, align 'o_kanban_image' to 'o_kanban_image_fill_left' elements.
@include media-breakpoint-up(md) {
$fill-notfill-gap: ($o-kanban-image-fill-width - $o-kanban-inside-hgutter*2) - $o-kanban-image-width;
margin: { left: $fill-notfill-gap*0.5; right: $fill-notfill-gap*2;}
$fill-notfill-gap: ($o-kanban-image-fill-width - $o-kanban-inside-hgutter * 2) -
$o-kanban-image-width;
margin: {
left: $fill-notfill-gap * 0.5;
right: $fill-notfill-gap * 2;
}
}
@include media-breakpoint-down(md) {
@@ -214,16 +225,20 @@
// Reset immedialy after div padding
+ div {
padding-left: 0
padding-left: 0;
}
}
// Images (backgrounds) could accomodate another image inside.
// (eg. Company logo badge inside a contact picture)
.o_kanban_image_fill_left, .o_kanban_image {
.o_kanban_image_fill_left,
.o_kanban_image {
.o_kanban_image_inner_pic {
@include o-position-absolute($right: 0, $bottom:0);
max: { height: 25px; width: 80%;}
@include o-position-absolute($right: 0, $bottom: 0);
max: {
height: 25px;
width: 80%;
}
background: white;
box-shadow: -1px -1px 0 1px white;
}
@@ -235,6 +250,10 @@
@extend .shadow;
transform: rotate(-3deg);
transition: transform 0.6s, box-shadow 0.3s;
.dropdown {
display: none;
}
}
// ------- Compatibility of old (<= v10) Generic layouts -------
@@ -242,7 +261,8 @@
// Kanban Records - Uniform Design
// Provide a basic style for different kanban record layouts
// ---------------------------------------------------------
.oe_kanban_card, .o_kanban_record {
.oe_kanban_card,
.o_kanban_record {
// ------- v11 Layout + generic layouts (~v10) -------
// Kanban Record - Dropdown
.o_dropdown_kanban {
@@ -265,7 +285,8 @@
}
}
&:hover .o_dropdown_kanban, .o_dropdown_kanban.show {
&:hover .o_dropdown_kanban,
.o_dropdown_kanban.show {
visibility: visible;
}
@@ -275,7 +296,8 @@
}
// Kanban Record - Inner elements
.o_field_many2many_tags, .o_kanban_tags {
.o_field_many2many_tags,
.o_kanban_tags {
display: block;
margin-bottom: $o-kanban-inner-hmargin;
line-height: 1.2;
@@ -329,8 +351,12 @@
.o_kanban_button {
margin-top: 15px;
> button, > a {
@include o-position-absolute($right: $o-kanban-record-margin, $bottom: $o-kanban-record-margin);
> button,
> a {
@include o-position-absolute(
$right: $o-kanban-record-margin,
$bottom: $o-kanban-record-margin
);
@include media-breakpoint-down(md) {
right: $o-kanban-inside-hgutter-mobile;
}
@@ -338,11 +364,14 @@
}
// Kanban Record - Utility classes
&.oe_kanban_global_click, &.oe_kanban_global_click_edit,
.oe_kanban_global_click, .oe_kanban_global_click_edit {
&.oe_kanban_global_click,
&.oe_kanban_global_click_edit,
.oe_kanban_global_click,
.oe_kanban_global_click_edit {
cursor: pointer;
&:focus, &:focus-within {
outline: thin solid mix(map-get($theme-colors, 'primary'), map-get($grays, '400'));
&:focus,
&:focus-within {
outline: thin solid mix(map-get($theme-colors, "primary"), map-get($grays, "400"));
outline-offset: -1px;
}
}
@@ -382,7 +411,7 @@
+ div {
padding-left: $o-kanban-image-width + $o-kanban-inside-hgutter;
@include media-breakpoint-down(md) {
padding-left: $o-kanban-image-width + $o-kanban-inside-hgutter-mobile;
padding-left: $o-kanban-image-width + $o-kanban-inside-hgutter-mobile;
}
}
}
@@ -395,7 +424,7 @@
min-width: 0;
ul {
margin-bottom: $o-kanban-inner-hmargin*0.5;;
margin-bottom: $o-kanban-inner-hmargin * 0.5;
padding-left: 0;
list-style: none;
font-size: $font-size-sm;
@@ -416,7 +445,7 @@
}
.oe_kanban_text_red {
color: #A61300;
color: #a61300;
font-weight: $font-weight-bold;
}
@@ -442,20 +471,21 @@
scroll-snap-type: x mandatory;
}
.o_kanban_record, .o_kanban_quick_create {
.o_kanban_record,
.o_kanban_quick_create {
width: 100%;
margin-left: 0;
margin-right: 0;
}
&.o_kanban_small_column .o_kanban_group:not(.o_column_folded) {
flex-basis: $o-kanban-small-record-width + 2*$o-kanban-group-padding;
flex-basis: $o-kanban-small-record-width + 2 * $o-kanban-group-padding;
}
}
// Kanban Grouped Layout - Column default
.o_kanban_group {
flex: 0 0 $o-kanban-default-record-width + 2*$o-kanban-group-padding;
flex: 0 0 $o-kanban-default-record-width + 2 * $o-kanban-group-padding;
padding: 0 $o-kanban-group-padding $o-kanban-group-padding $o-kanban-group-padding;
background-color: inherit;
@@ -475,10 +505,11 @@
.o_kanban_quick_add i {
@include o-kanban-icon;
margin-left: $o-kanban-inside-hgutter*2;
margin-left: $o-kanban-inside-hgutter * 2;
}
&:hover .o_kanban_config, .o_kanban_config.show {
&:hover .o_kanban_config,
.o_kanban_config.show {
visibility: visible;
}
@@ -525,11 +556,15 @@
}
}
> .o_kanban_record, .o_kanban_quick_add, .o_kanban_config, .o_kanban_load_more {
display: none!important;
> .o_kanban_record,
.o_kanban_quick_add,
.o_kanban_config,
.o_kanban_load_more {
display: none !important;
}
&:hover, &.o_kanban_hover {
&:hover,
&.o_kanban_hover {
.o_kanban_header_title {
opacity: 1;
}
@@ -539,19 +574,19 @@
// Kanban Grouped Layout - "Create new column" column
.o_column_quick_create {
flex: 0 0 $o-kanban-small-record-width + 2*$o-kanban-group-padding;
flex: 0 0 $o-kanban-small-record-width + 2 * $o-kanban-group-padding;
.o_quick_create_folded {
cursor: pointer;
padding: 12px 16px;
white-space: nowrap;
font-weight: $font-weight-bold;
@include o-hover-opacity(.7);
@include o-hover-opacity(0.7);
@include o-hover-text-color($text-muted, $body-color);
}
.o_quick_create_unfolded {
margin: $border-width ($o-kanban-inside-hgutter * .5) 0;
margin: $border-width ($o-kanban-inside-hgutter * 0.5) 0;
padding: $o-kanban-inside-vgutter $o-kanban-inside-hgutter;
@include media-breakpoint-down(md) {
@@ -565,23 +600,25 @@
cursor: pointer;
}
input, input:focus, input:hover {
input,
input:focus,
input:hover {
font-size: 16px;
background: transparent;
}
}
.o_kanban_muted_record {
background: map-get($grays, '300');
background: map-get($grays, "300");
height: 70px;
margin: 10px 0px;
}
}
}
@include media-breakpoint-down(md) {
.o_kanban_group, .o_column_quick_create {
.o_kanban_group,
.o_column_quick_create {
flex: 1 0 90%; // don't take full width to give a hint of next/previous column
scroll-snap-align: center;
overflow-y: scroll;
@@ -622,7 +659,7 @@
&.o_kanban_ghost {
height: 0;
border: none;
min-height: 0!important; // to prevent view writers to override this height
min-height: 0 !important; // to prevent view writers to override this height
visibility: hidden;
margin-top: 0;
margin-bottom: 0;
@@ -51,6 +51,7 @@ export class KanbanRenderer extends Component {
// Params
ref: rootRef,
elements: ".o_record_draggable",
ignore: ".dropdown",
groups: () => this.props.list.isGrouped && ".o_kanban_group",
connectGroups: () => this.canMoveRecords,
cursor: "move",
@@ -275,7 +275,7 @@ QUnit.module("UI", ({ beforeEach }) => {
assert.ok(true, "No drag sequence should have been initiated");
});
QUnit.test("Ignore specified elements elements", async (assert) => {
QUnit.test("Ignore specified elements", async (assert) => {
assert.expect(6);
class List extends Component {