[IMP] web: Add 'ignore' param to useSortable
This commit adds a new parameter to the 'useSortable' hook that allows HTML elements to prevent a drag sequence. This 'ignore' param can be a string or a function returning a string, that will be a selector targetting the elements that need to prevent drag & drop sequences. Part-of: odoo/odoo#98791
This commit is contained in:
@@ -22,6 +22,8 @@ const { useEffect, useEnv, useExternalListener, onWillUnmount } = owl;
|
||||
* work on group elements during the dragging sequence.
|
||||
* @property {string | () => string} [handle] additional selector for when the dragging
|
||||
* sequence must be initiated when dragging on a certain part of the element.
|
||||
* @property {string | () => string} [ignore] selector targetting elements that must
|
||||
* initiate a drag.
|
||||
* @property {boolean | () => boolean} [connectGroups] whether elements can be dragged
|
||||
* accross different parent groups. Note that it requires a `groups` param to work.
|
||||
* @property {string | () => string} [cursor] cursor style during the dragging sequence.
|
||||
@@ -63,6 +65,7 @@ const SORTABLE_PARAMS = {
|
||||
elements: ["string"],
|
||||
groups: ["string", "function"],
|
||||
handle: ["string", "function"],
|
||||
ignore: ["string", "function"],
|
||||
connectGroups: ["boolean", "function"],
|
||||
cursor: ["string"],
|
||||
};
|
||||
@@ -155,6 +158,11 @@ export function useSortable(params) {
|
||||
* @type {string | null}
|
||||
*/
|
||||
let elementSelector = null;
|
||||
/**
|
||||
* Stores the full selector used to initiate a drag sequence.
|
||||
* @type {string | null}
|
||||
*/
|
||||
let ignoreSelector = null;
|
||||
/**
|
||||
* Stores the full selector used to initiate a drag sequence.
|
||||
* @type {string | null}
|
||||
@@ -339,7 +347,12 @@ export function useSortable(params) {
|
||||
// outside of the window.
|
||||
dragStop(true);
|
||||
|
||||
if (ev.button !== LEFT_CLICK || !enabled || !ev.target.closest(fullSelector)) {
|
||||
if (
|
||||
ev.button !== LEFT_CLICK ||
|
||||
!enabled ||
|
||||
!ev.target.closest(fullSelector) ||
|
||||
(ignoreSelector && ev.target.closest(ignoreSelector))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -407,8 +420,8 @@ export function useSortable(params) {
|
||||
currentContainerRect.height -= ptop + pbottom;
|
||||
|
||||
// Prepares the ghost element
|
||||
ghost = currentElement.cloneNode(true);
|
||||
ghost.style.visibility = "hidden";
|
||||
ghost = currentElement.cloneNode(false);
|
||||
ghost.style = `visibility: hidden; display: block; width: ${width}px; height:${height}px;`;
|
||||
cleanups.push(() => ghost.remove());
|
||||
|
||||
// Binds handlers on eligible groups, if the elements are not confined to
|
||||
@@ -526,6 +539,9 @@ export function useSortable(params) {
|
||||
if (actualParams.handle) {
|
||||
allSelectors.push(actualParams.handle);
|
||||
}
|
||||
if (actualParams.ignore) {
|
||||
ignoreSelector = actualParams.ignore;
|
||||
}
|
||||
fullSelector = allSelectors.join(" ");
|
||||
|
||||
// Connection accross groups
|
||||
|
||||
@@ -201,7 +201,7 @@ QUnit.module("UI", ({ beforeEach }) => {
|
||||
QUnit.test("Dynamically disable sortable feature", async (assert) => {
|
||||
assert.expect(4);
|
||||
|
||||
let state = reactive({ enableSortable: true });
|
||||
const state = reactive({ enableSortable: true });
|
||||
class List extends Component {
|
||||
setup() {
|
||||
this.state = useState(state);
|
||||
@@ -274,4 +274,50 @@ QUnit.module("UI", ({ beforeEach }) => {
|
||||
|
||||
assert.ok(true, "No drag sequence should have been initiated");
|
||||
});
|
||||
|
||||
QUnit.test("Ignore specified elements elements", async (assert) => {
|
||||
assert.expect(6);
|
||||
|
||||
class List extends Component {
|
||||
setup() {
|
||||
useSortable({
|
||||
ref: useRef("root"),
|
||||
elements: ".item",
|
||||
ignore: ".ignored",
|
||||
onStart() {
|
||||
assert.step("drag");
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
List.template = xml`
|
||||
<div t-ref="root" class="root">
|
||||
<ul class="list">
|
||||
<li t-foreach="[1, 2, 3]" t-as="i" t-key="i" class="item">
|
||||
<span class="ignored" t-esc="i" />
|
||||
<span class="not-ignored" t-esc="i" />
|
||||
</li>
|
||||
</ul>
|
||||
</div>`;
|
||||
|
||||
await mount(List, target);
|
||||
|
||||
assert.verifySteps([]);
|
||||
|
||||
// Drag root item element
|
||||
await dragAndDrop(".item:first-child", ".item:nth-child(2)");
|
||||
|
||||
assert.verifySteps(["drag"]);
|
||||
|
||||
// Drag ignored element
|
||||
await dragAndDrop(".item:first-child .not-ignored", ".item:nth-child(2)");
|
||||
|
||||
assert.verifySteps(["drag"]);
|
||||
|
||||
// Drag non-ignored element
|
||||
await dragAndDrop(".item:first-child .ignored", ".item:nth-child(2)");
|
||||
|
||||
assert.verifySteps([]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user