From d84f28304b295e7cd8a932f996b94e6922d02775 Mon Sep 17 00:00:00 2001 From: mark van tilburg Date: Wed, 24 Sep 2025 12:43:01 +0200 Subject: [PATCH 1/4] Create pointer.js A quick port of mouse.js to pointer events --- ui/widgets/pointer.js | 209 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 ui/widgets/pointer.js diff --git a/ui/widgets/pointer.js b/ui/widgets/pointer.js new file mode 100644 index 0000000000..1854a37ef1 --- /dev/null +++ b/ui/widgets/pointer.js @@ -0,0 +1,209 @@ +/*! + * jQuery UI Pointer @VERSION + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Pointer +//>>group: Widgets +//>>description: Abstracts pointer-based interactions to assist in creating certain widgets. +//>>docs: https://api.jqueryui.com/pointer/ + +( function( factory ) { + "use strict"; + + if ( typeof define === "function" && define.amd ) { + + // AMD. Register as an anonymous module. + define( [ + "jquery", + "../version", + "../widget" + ], factory ); + } else { + + // Browser globals + factory( jQuery ); + } +} )( function( $ ) { +"use strict"; + +var pointerHandled = false; +$( document ).on( "pointerup", function() { + pointerHandled = false; +} ); + +return $.widget( "ui.mouse", { + version: "@VERSION", + options: { + cancel: "input, textarea, button, select, option", + distance: 1, + delay: 0 + }, + _pointerInit: function() { + var that = this; + + this.element + .on( "pointerdown." + this.widgetName, function( event ) { + return that._pointerDown( event ); + } ) + .on( "click." + this.widgetName, function( event ) { + if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) { + $.removeData( event.target, that.widgetName + ".preventClickEvent" ); + event.stopImmediatePropagation(); + return false; + } + } ); + + this.started = false; + }, + + _pointerDestroy: function() { + this.element.off( "." + this.widgetName ); + if ( this._pointerMoveDelegate ) { + this.document + .off( "pointermove." + this.widgetName, this._pointerMoveDelegate ) + .off( "pointerup." + this.widgetName, this._pointerUpDelegate ); + } + }, + + _pointerDown: function( event ) { + if ( pointerHandled ) { + return; + } + + this._pointerMoved = false; + + if ( this._pointerStarted ) { + this._pointerUp( event ); + } + + this._pointerDownEvent = event; + + var that = this, + btnIsLeft = event.button === 0, + elIsCancel = typeof this.options.cancel === "string" ? + $( event.target ).closest( this.options.cancel ).length : + false; + if ( !btnIsLeft || elIsCancel || !this._pointerCapture( event ) ) { + return true; + } + + this.pointerDelayMet = !this.options.delay; + if ( !this.pointerDelayMet ) { + this._pointerDelayTimer = setTimeout( function() { + that.pointerDelayMet = true; + }, this.options.delay ); + } + + if ( this._pointerDistanceMet( event ) && this._pointerDelayMet( event ) ) { + this._pointerStarted = ( this._pointerStart( event ) !== false ); + if ( !this._pointerStarted ) { + event.preventDefault(); + return true; + } + } + + if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) { + $.removeData( event.target, this.widgetName + ".preventClickEvent" ); + } + + this._pointerMoveDelegate = function( event ) { + return that._pointerMove( event ); + }; + this._pointerUpDelegate = function( event ) { + return that._pointerUp( event ); + }; + + this.document + .on( "pointermove." + this.widgetName, this._pointerMoveDelegate ) + .on( "pointerup." + this.widgetName, this._pointerUpDelegate ); + + event.preventDefault(); + + pointerHandled = true; + return true; + }, + + _pointerMove: function( event ) { + if ( this._pointerMoved && event.buttons === 0 ) { + if ( event.altKey || event.ctrlKey || + event.metaKey || event.shiftKey ) { + this.ignoreMissingButtons = true; + } else if ( !this.ignoreMissingButtons ) { + return this._pointerUp( event ); + } + } + + if ( event.buttons || event.button ) { + this._pointerMoved = true; + } + + if ( this._pointerStarted ) { + this._pointerDrag( event ); + return event.preventDefault(); + } + + if ( this._pointerDistanceMet( event ) && this._pointerDelayMet( event ) ) { + this._pointerStarted = + ( this._pointerStart( this._pointerDownEvent, event ) !== false ); + if ( this._pointerStarted ) { + this._pointerDrag( event ); + } else { + this._pointerUp( event ); + } + } + + return !this._pointerStarted; + }, + + _pointerUp: function( event ) { + this.document + .off( "pointermove." + this.widgetName, this._pointerMoveDelegate ) + .off( "pointerup." + this.widgetName, this._pointerUpDelegate ); + + if ( this._pointerStarted ) { + this._pointerStarted = false; + + if ( event.target === this._pointerDownEvent.target ) { + $.data( event.target, this.widgetName + ".preventClickEvent", true ); + } + + this._pointerStop( event ); + } + + if ( this._pointerDelayTimer ) { + clearTimeout( this._pointerDelayTimer ); + delete this._pointerDelayTimer; + } + + this.ignoreMissingButtons = false; + pointerHandled = false; + event.preventDefault(); + }, + + _pointerDistanceMet: function( event ) { + return ( Math.max( + Math.abs( this._pointerDownEvent.pageX - event.pageX ), + Math.abs( this._pointerDownEvent.pageY - event.pageY ) + ) >= this.options.distance + ); + }, + + _pointerDelayMet: function( /* event */ ) { + return this.pointerDelayMet; + }, + + // These are placeholder methods, to be overriden by extending plugin + _pointerStart: function( /* event */ ) {}, + _pointerDrag: function( /* event */ ) {}, + _pointerStop: function( /* event */ ) {}, + _pointerCapture: function( /* event */ ) { + return true; + } +} ); + +} ); From ab6a305392175456a102a5023c029b80dbc2f13b Mon Sep 17 00:00:00 2001 From: mark van tilburg Date: Wed, 24 Sep 2025 12:46:04 +0200 Subject: [PATCH 2/4] Update pointer.js missed a mouse --- ui/widgets/pointer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/widgets/pointer.js b/ui/widgets/pointer.js index 1854a37ef1..51839c4821 100644 --- a/ui/widgets/pointer.js +++ b/ui/widgets/pointer.js @@ -36,7 +36,7 @@ $( document ).on( "pointerup", function() { pointerHandled = false; } ); -return $.widget( "ui.mouse", { +return $.widget( "ui.pointer", { version: "@VERSION", options: { cancel: "input, textarea, button, select, option", From e154738c4474320a47af312487101acb49b852b3 Mon Sep 17 00:00:00 2001 From: mark van tilburg Date: Tue, 27 Jan 2026 10:07:56 +0100 Subject: [PATCH 3/4] Update pointer.js Remove "ignoreMissingButtons" boolean and change the if to remove the custom safari code --- ui/widgets/pointer.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ui/widgets/pointer.js b/ui/widgets/pointer.js index 51839c4821..60f1f6a5da 100644 --- a/ui/widgets/pointer.js +++ b/ui/widgets/pointer.js @@ -130,12 +130,7 @@ return $.widget( "ui.pointer", { _pointerMove: function( event ) { if ( this._pointerMoved && event.buttons === 0 ) { - if ( event.altKey || event.ctrlKey || - event.metaKey || event.shiftKey ) { - this.ignoreMissingButtons = true; - } else if ( !this.ignoreMissingButtons ) { return this._pointerUp( event ); - } } if ( event.buttons || event.button ) { @@ -180,7 +175,6 @@ return $.widget( "ui.pointer", { delete this._pointerDelayTimer; } - this.ignoreMissingButtons = false; pointerHandled = false; event.preventDefault(); }, From 1a2106367a7c3737d5c110c7b44c82c531e236e1 Mon Sep 17 00:00:00 2001 From: mark van tilburg Date: Mon, 9 Mar 2026 15:16:36 +0100 Subject: [PATCH 4/4] Update pointer.js In _pointerInit, the code used this.started = false, but everywhere else the code uses this._pointerStarted --- ui/widgets/pointer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/widgets/pointer.js b/ui/widgets/pointer.js index 60f1f6a5da..ce66c8df22 100644 --- a/ui/widgets/pointer.js +++ b/ui/widgets/pointer.js @@ -58,7 +58,7 @@ return $.widget( "ui.pointer", { } } ); - this.started = false; + this._pointerStarted = false; }, _pointerDestroy: function() {