diff --git a/src/vaadin-dialog-draggable-mixin.html b/src/vaadin-dialog-draggable-mixin.html index a2f0e42..7120300 100644 --- a/src/vaadin-dialog-draggable-mixin.html +++ b/src/vaadin-dialog-draggable-mixin.html @@ -55,8 +55,14 @@ const isResizerContainer = e.target === resizerContainer; const isResizerContainerScrollbar = e.offsetX > resizerContainer.clientWidth || e.offsetY > resizerContainer.clientHeight; const isContentPart = e.target === this.$.overlay.$.content; - const isDraggable = e.composedPath().some(node => { - return node.classList && node.classList.contains(this.__dragHandleClassName || 'draggable'); + + const isDraggable = e.composedPath().some((node, index) => { + if (node.classList) { + const isDraggableNode = node.classList.contains(this.__dragHandleClassName || 'draggable'); + const isDraggableLeafOnly = node.classList.contains('draggable-leaf-only'); + const isLeafNode = index === 0; + return (isDraggableLeafOnly && isLeafNode) || (isDraggableNode && (!isDraggableLeafOnly || isLeafNode)); + } }); if ((isResizerContainer && !isResizerContainerScrollbar) || isContentPart || isDraggable) { diff --git a/src/vaadin-dialog.html b/src/vaadin-dialog.html index 81bb16f..204325f 100644 --- a/src/vaadin-dialog.html +++ b/src/vaadin-dialog.html @@ -237,7 +237,12 @@ * * By default, only the overlay area can be used to drag the element. But, * a child element can be marked as a draggable area by adding a - * "`draggable`" class to it. + * "`draggable`" class to it, this will by default make all of its children draggable also. + * If you want a child element to be draggable + * but still have its children non-draggable (by default), mark it with + * "`draggable-leaf-only`" class name. + * + * @type {boolean} */ draggable: { type: Boolean, diff --git a/test/vaadin-dialog_draggable-resizable-test.html b/test/vaadin-dialog_draggable-resizable-test.html index 6e3c498..c39396e 100644 --- a/test/vaadin-dialog_draggable-resizable-test.html +++ b/test/vaadin-dialog_draggable-resizable-test.html @@ -441,7 +441,10 @@ before(() => { customElements.define('internally-draggable', class extends Polymer.Element { static get template() { - return Polymer.html`
draggable
`; + return Polymer.html` +
+ draggable +
`; } }); }); @@ -483,6 +486,56 @@ expect(Math.floor(draggedBounds.left)).to.be.eql(Math.floor(bounds.left + dx)); }); + it('should not drag by a draggable-leaf-only if it is not the drag event target', () => { + const draggable = dialog.$.overlay.querySelector('internally-draggable').shadowRoot.querySelector('.draggable'); + draggable.classList.add('draggable-leaf-only'); + const child = draggable.firstElementChild; + drag(child); + const draggedBounds = container.getBoundingClientRect(); + expect(Math.floor(draggedBounds.top)).to.be.eql(Math.floor(bounds.top)); + expect(Math.floor(draggedBounds.left)).to.be.eql(Math.floor(bounds.left)); + }); + + it('should drag by a draggable-leaf-only if it is directly the dragged element', () => { + const draggable = dialog.$.overlay.querySelector('internally-draggable').shadowRoot.querySelector('.draggable'); + draggable.classList.add('draggable-leaf-only'); + drag(draggable); + const draggedBounds = container.getBoundingClientRect(); + expect(Math.floor(draggedBounds.top)).to.be.eql(Math.floor(bounds.top + dx)); + expect(Math.floor(draggedBounds.left)).to.be.eql(Math.floor(bounds.left + dx)); + }); + + it('should drag by a draggable-leaf-only child if it is marked as draggable', () => { + const draggable = dialog.$.overlay.querySelector('internally-draggable').shadowRoot.querySelector('.draggable'); + draggable.classList.add('draggable-leaf-only'); + const child = draggable.firstElementChild; + child.classList.add('draggable'); + drag(child); + const draggedBounds = container.getBoundingClientRect(); + expect(Math.floor(draggedBounds.top)).to.be.eql(Math.floor(bounds.top + dx)); + expect(Math.floor(draggedBounds.left)).to.be.eql(Math.floor(bounds.left + dx)); + }); + + it('should drag by a draggable-leaf-only child if it is marked as draggable-leaf-only', () => { + const draggable = dialog.$.overlay.querySelector('internally-draggable').shadowRoot.querySelector('.draggable'); + draggable.classList.add('draggable-leaf-only'); + const child = draggable.firstElementChild; + child.classList.add('draggable-leaf-only'); + drag(child); + const draggedBounds = container.getBoundingClientRect(); + expect(Math.floor(draggedBounds.top)).to.be.eql(Math.floor(bounds.top + dx)); + expect(Math.floor(draggedBounds.left)).to.be.eql(Math.floor(bounds.left + dx)); + }); + + it('should drag by a child of a draggable node ', () => { + const draggable = dialog.$.overlay.querySelector('internally-draggable').shadowRoot.querySelector('.draggable'); + const child = draggable.firstElementChild; + drag(child); + const draggedBounds = container.getBoundingClientRect(); + expect(Math.floor(draggedBounds.top)).to.be.eql(Math.floor(bounds.top + dx)); + expect(Math.floor(draggedBounds.left)).to.be.eql(Math.floor(bounds.left + dx)); + }); + it('should drag and move dialog after resizing', () => { resize(container.querySelector('.s'), 0, dx); const bounds = container.getBoundingClientRect();