From 1ab23b94676de24761e50c9a193aefc0edb8cccd Mon Sep 17 00:00:00 2001 From: Julien Mougenot Date: Wed, 24 Aug 2022 11:31:13 +0000 Subject: [PATCH] [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) --- .../src/views/kanban/kanban_controller.scss | 143 +++++++++++------- .../src/views/kanban/kanban_renderer.js | 1 + .../web/static/tests/core/utils/ui_tests.js | 2 +- 3 files changed, 92 insertions(+), 54 deletions(-) diff --git a/addons/web/static/src/views/kanban/kanban_controller.scss b/addons/web/static/src/views/kanban/kanban_controller.scss index 74f6cc1eed9..e20d627e845 100644 --- a/addons/web/static/src/views/kanban/kanban_controller.scss +++ b/addons/web/static/src/views/kanban/kanban_controller.scss @@ -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; diff --git a/addons/web/static/src/views/kanban/kanban_renderer.js b/addons/web/static/src/views/kanban/kanban_renderer.js index 8b235d0b1c1..24611b5c2f6 100644 --- a/addons/web/static/src/views/kanban/kanban_renderer.js +++ b/addons/web/static/src/views/kanban/kanban_renderer.js @@ -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", diff --git a/addons/web/static/tests/core/utils/ui_tests.js b/addons/web/static/tests/core/utils/ui_tests.js index b78114b2d60..9a76689b02a 100644 --- a/addons/web/static/tests/core/utils/ui_tests.js +++ b/addons/web/static/tests/core/utils/ui_tests.js @@ -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 {