diff --git a/core/modules/utils/dom/dom.js b/core/modules/utils/dom/dom.js index df4c93b73..299011136 100644 --- a/core/modules/utils/dom/dom.js +++ b/core/modules/utils/dom/dom.js @@ -22,6 +22,10 @@ exports.domContains = function(a,b) { !!(a.compareDocumentPosition(b) & 16); }; +exports.domMatchesSelector = function(node,selector) { + return node.matches ? node.matches(selector) : node.msMatchesSelector(selector); +}; + exports.removeChildren = function(node) { while(node.hasChildNodes()) { node.removeChild(node.firstChild); diff --git a/core/modules/widgets/eventcatcher.js b/core/modules/widgets/eventcatcher.js index c014f8997..0b32689a1 100644 --- a/core/modules/widgets/eventcatcher.js +++ b/core/modules/widgets/eventcatcher.js @@ -47,38 +47,46 @@ EventWidget.prototype.render = function(parent,nextSibling) { domNode.addEventListener(type,function(event) { var selector = self.getAttribute("selector"), actions = self.getAttribute("actions-"+type), + stopPropagation = self.getAttribute("stopPropagation","onaction"), selectedNode = event.target, selectedNodeRect, catcherNodeRect, variables = {}; + // Firefox can fire dragover and dragenter events on text nodes instead of their parents + if(selectedNode.nodeType === 3) { + selectedNode = selectedNode.parentNode; + } if(selector) { // Search ancestors for a node that matches the selector - while(!selectedNode.matches(selector) && selectedNode !== domNode) { + while(!$tw.utils.domMatchesSelector(selectedNode,selector) && selectedNode !== domNode) { selectedNode = selectedNode.parentNode; } // If we found one, copy the attributes as variables, otherwise exit - if(selectedNode.matches(selector)) { - $tw.utils.each(selectedNode.attributes,function(attribute) { - variables["dom-" + attribute.name] = attribute.value.toString(); - }); - //Add a variable with a popup coordinate string for the selected node - variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")"; - - //Add variables for offset of selected node - variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString(); - variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString(); - variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString(); - variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString(); + if($tw.utils.domMatchesSelector(selectedNode,selector)) { + // Only set up variables if we have actions to invoke + if(actions) { + $tw.utils.each(selectedNode.attributes,function(attribute) { + variables["dom-" + attribute.name] = attribute.value.toString(); + }); + //Add a variable with a popup coordinate string for the selected node + variables["tv-popup-coords"] = "(" + selectedNode.offsetLeft + "," + selectedNode.offsetTop +"," + selectedNode.offsetWidth + "," + selectedNode.offsetHeight + ")"; - //Add variables for event X and Y position relative to selected node - selectedNodeRect = selectedNode.getBoundingClientRect(); - variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString(); - variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString(); + //Add variables for offset of selected node + variables["tv-selectednode-posx"] = selectedNode.offsetLeft.toString(); + variables["tv-selectednode-posy"] = selectedNode.offsetTop.toString(); + variables["tv-selectednode-width"] = selectedNode.offsetWidth.toString(); + variables["tv-selectednode-height"] = selectedNode.offsetHeight.toString(); - //Add variables for event X and Y position relative to event catcher node - catcherNodeRect = self.domNode.getBoundingClientRect(); - variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString(); - variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString(); + //Add variables for event X and Y position relative to selected node + selectedNodeRect = selectedNode.getBoundingClientRect(); + variables["event-fromselected-posx"] = (event.clientX - selectedNodeRect.left).toString(); + variables["event-fromselected-posy"] = (event.clientY - selectedNodeRect.top).toString(); + + //Add variables for event X and Y position relative to event catcher node + catcherNodeRect = self.domNode.getBoundingClientRect(); + variables["event-fromcatcher-posx"] = (event.clientX - catcherNodeRect.left).toString(); + variables["event-fromcatcher-posy"] = (event.clientY - catcherNodeRect.top).toString(); + } } else { return false; } @@ -106,6 +114,8 @@ EventWidget.prototype.render = function(parent,nextSibling) { variables["event-detail"] = event.detail.toString(); } self.invokeActionString(actions,self,event,variables); + } + if((actions && stopPropagation === "onaction") || stopPropagation === "always") { event.preventDefault(); event.stopPropagation(); return true; diff --git a/editions/tw5.com/tiddlers/widgets/EventCatcherWidget.tid b/editions/tw5.com/tiddlers/widgets/EventCatcherWidget.tid index 33aa06db8..aeda1450f 100644 --- a/editions/tw5.com/tiddlers/widgets/EventCatcherWidget.tid +++ b/editions/tw5.com/tiddlers/widgets/EventCatcherWidget.tid @@ -1,5 +1,5 @@ created: 20201123113532200 -modified: 20201202200719126 +modified: 20210520162813234 tags: Widgets title: EventCatcherWidget type: text/vnd.tiddlywiki @@ -30,6 +30,7 @@ The content of the `<$eventcatcher>` widget is displayed normally. |actions-* |Action strings to be invoked when a matching event is trapped. Each event is mapped to an action attribute name of the form actions-event where event represents the type of the event. For example: `actions-click` or `actions-dblclick` | |tag |Optional. The HTML element the widget creates to capture the events, defaults to:
» `span` when parsed in inline-mode
» `div` when parsed in block-mode | |class |Optional. A CSS class name (or names) to be assigned to the widget HTML element | +|stopPropagation |<<.from-version "5.1.24">> Optional. Set to "always" to always stop event propagation even if there are no corresponding actions to invoke, "never" to never stop event propagation, or the default value "onaction" with which event propagation is only stopped if there are corresponding actions that are invoked. | ! Variables