From 4054566493a982f16642d3d59a5e281f8a362a14 Mon Sep 17 00:00:00 2001 From: Saq Imtiaz Date: Thu, 24 Feb 2022 12:06:18 +0100 Subject: [PATCH] Extend $draggable to support an optional drag handle (#6480) * feat: extend to support a selector attribute identifying the DOM element to be used as the drag handle * fix: remove redundant variable declaration * fix: remove extranneous variable declaration --- core/modules/utils/dom/dragndrop.js | 12 +++++---- core/modules/widgets/draggable.js | 25 ++++++++++++------- .../tiddlers/widgets/DraggableWidget.tid | 10 +++++--- 3 files changed, 30 insertions(+), 17 deletions(-) diff --git a/core/modules/utils/dom/dragndrop.js b/core/modules/utils/dom/dragndrop.js index 9536fb9c8..b0d286e97 100644 --- a/core/modules/utils/dom/dragndrop.js +++ b/core/modules/utils/dom/dragndrop.js @@ -16,21 +16,23 @@ Browser data transfer utilities, used with the clipboard and drag and drop Options: domNode: dom node to make draggable +selector: CSS selector to identify element within domNode to be used as drag handle (optional) dragImageType: "pill", "blank" or "dom" (the default) dragTiddlerFn: optional function to retrieve the title of tiddler to drag dragFilterFn: optional function to retreive the filter defining a list of tiddlers to drag -widget: widget to use as the contect for the filter +widget: widget to use as the context for the filter */ exports.makeDraggable = function(options) { var dragImageType = options.dragImageType || "dom", dragImage, - domNode = options.domNode; + domNode = options.domNode, + dragHandle = options.selector && domNode.querySelector(options.selector) || domNode; // Make the dom node draggable (not necessary for anchor tags) if((domNode.tagName || "").toLowerCase() !== "a") { - domNode.setAttribute("draggable","true"); + dragHandle.setAttribute("draggable","true"); } // Add event handlers - $tw.utils.addEventListeners(domNode,[ + $tw.utils.addEventListeners(dragHandle,[ {name: "dragstart", handlerFunction: function(event) { if(event.dataTransfer === undefined) { return false; @@ -45,7 +47,7 @@ exports.makeDraggable = function(options) { } var titleString = $tw.utils.stringifyList(titles); // Check that we've something to drag - if(titles.length > 0 && event.target === domNode) { + if(titles.length > 0 && event.target === dragHandle) { // Mark the drag in progress $tw.dragInProgress = domNode; // Set the dragging class on the element being dragged diff --git a/core/modules/widgets/draggable.js b/core/modules/widgets/draggable.js index 66f85132d..61fd81c35 100644 --- a/core/modules/widgets/draggable.js +++ b/core/modules/widgets/draggable.js @@ -27,7 +27,10 @@ DraggableWidget.prototype = new Widget(); Render this widget into the DOM */ DraggableWidget.prototype.render = function(parent,nextSibling) { - var self = this; + var self = this, + tag, + domNode, + classes = []; // Save the parent dom node this.parentDomNode = parent; // Compute our attributes @@ -35,18 +38,23 @@ DraggableWidget.prototype.render = function(parent,nextSibling) { // Execute our logic this.execute(); // Sanitise the specified tag - var tag = this.draggableTag; + tag = this.draggableTag; if($tw.config.htmlUnsafeElements.indexOf(tag) !== -1) { tag = "div"; } // Create our element - var domNode = this.document.createElement(tag); + domNode = this.document.createElement(tag); // Assign classes - var classes = ["tc-draggable"]; if(this.draggableClasses) { classes.push(this.draggableClasses); } + if(!this.dragHandleSelector) { + classes.push("tc-draggable"); + } domNode.setAttribute("class",classes.join(" ")); + // Insert the node into the DOM and render any children + parent.insertBefore(domNode,nextSibling); + this.renderChildren(domNode,null); // Add event handlers $tw.utils.makeDraggable({ domNode: domNode, @@ -55,11 +63,9 @@ DraggableWidget.prototype.render = function(parent,nextSibling) { startActions: self.startActions, endActions: self.endActions, dragImageType: self.dragImageType, - widget: this + widget: this, + selector: self.dragHandleSelector }); - // Insert the link into the DOM and render any children - parent.insertBefore(domNode,nextSibling); - this.renderChildren(domNode,null); this.domNodes.push(domNode); }; @@ -72,7 +78,8 @@ DraggableWidget.prototype.execute = function() { this.draggableClasses = this.getAttribute("class"); this.startActions = this.getAttribute("startactions"); this.endActions = this.getAttribute("endactions"); - this.dragImageType = this.getAttribute("dragimagetype"); + this.dragImageType = this.getAttribute("dragimagetype"); + this.dragHandleSelector = this.getAttribute("selector"); // Make the child widgets this.makeChildWidgets(); }; diff --git a/editions/tw5.com/tiddlers/widgets/DraggableWidget.tid b/editions/tw5.com/tiddlers/widgets/DraggableWidget.tid index 4db490537..719e719c2 100644 --- a/editions/tw5.com/tiddlers/widgets/DraggableWidget.tid +++ b/editions/tw5.com/tiddlers/widgets/DraggableWidget.tid @@ -1,6 +1,6 @@ caption: draggable created: 20170406081938627 -modified: 20211009122105437 +modified: 20220223145136863 tags: Widgets TriggeringWidgets title: DraggableWidget type: text/vnd.tiddlywiki @@ -16,8 +16,10 @@ See DragAndDropMechanism for an overview. |!Attribute |!Description | |tiddler |Optional title of the payload tiddler for the drag | |filter |Optional filter defining the payload tiddlers for the drag | -|class |Optional CSS classes to assign to the draggable element. The class `tc-draggable` is added automatically, and the class `tc-dragging` is applied while the element is being dragged | -|tag |Optional tag to override the default "div" element | +|tag |Optional tag to override the default "div" element created by the widget| +|selector|<<.from-version 5.2.2>> Optional CSS Selector to identify a DOM element within the widget that will be used as the drag handle | +|class |Optional CSS classes to assign to the DOM element created by the widget. The class `tc-draggable` is added to the drag handle, which is the same as the DOM element created by the widget unless the <<.param selector>> attribute is used. The class `tc-dragging` is applied to the drag handle while the element is being dragged | + |startactions |Optional action string that gets invoked when dragging ''starts'' | |endactions |Optional action string that gets invoked when dragging ''ends'' | |dragimagetype |<<.from-version "5.2.0">> Optional type of drag image: `dom` (the default) or `blank` to disable the drag image | @@ -28,5 +30,7 @@ The [[actionTiddler Variable]] is accessible in both //startactions// and //enda <<.tip """Note that the [[actionTiddler Variable]] holds a [[Title List]] quoted with double square brackets. This is unlike the DroppableWidget which uses the same variable to pass a single unquoted title.""">> +<<.tip """When specifying a DOM node to use as the drag handle with the <<.param selector>> attribute, give it the class `tc-draggable` in order for it to have the appropriate cursor.""">> + The LinkWidget incorporates the functionality of the DraggableWidget via the ''draggable'' attribute.