From 14abd1ca1d7b8edc961857a05cd35074c4a5e8d5 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Thu, 12 Jun 2025 21:56:21 +0100 Subject: [PATCH 01/12] Implement user defined function interface and refactor pointer events --- src/core/main.js | 42 ++++++++------- src/events/pointer.js | 122 +++++++++++++++++++++++------------------- 2 files changed, 89 insertions(+), 75 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index a5c9a6c93d..afc37350d6 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -65,22 +65,14 @@ class p5 { this._initializeInstanceVariables(); this._events = { // keep track of user-events for unregistering later - pointerdown: null, - pointerup: null, - pointermove: null, - dragend: null, - dragover: null, - click: null, - dblclick: null, - mouseover: null, - mouseout: null, keydown: null, keyup: null, keypress: null, - wheel: null, resize: null, blur: null }; + this._removeAbortController = new AbortController(); + this._removeSignal = this._removeAbortController.signal; this._millisStart = -1; this._recording = false; @@ -208,6 +200,20 @@ class p5 { } } + _userDefinedFunctions = {}; + userDefinedFunctions = new Proxy({}, { + get: (target, prop) => { + if(!this._userDefinedFunctions[prop]){ + const context = this._isGlobal ? window : this; + if(typeof context[prop] === 'function'){ + this._userDefinedFunctions[prop] = context[prop].bind(this); + } + } + + return this._userDefinedFunctions[prop]; + } + }) + async #_start() { if (this.hitCriticalError) return; // Find node if id given @@ -247,18 +253,13 @@ class p5 { } if (this.hitCriticalError) return; - // unhide any hidden canvases that were created const canvases = document.getElementsByTagName('canvas'); - - // Apply touchAction = 'none' to canvases if pointer events exist - if (Object.keys(this._events).some(event => event.startsWith('pointer'))) { - for (const k of canvases) { - k.style.touchAction = 'none'; - } - } - - for (const k of canvases) { + // Apply touchAction = 'none' to canvases to prevent scrolling + // when dragging on canvas elements + k.style.touchAction = 'none'; + + // unhide any hidden canvases that were created if (k.dataset.hidden === 'true') { k.style.visibility = ''; delete k.dataset.hidden; @@ -384,6 +385,7 @@ class p5 { for (const ev in this._events) { window.removeEventListener(ev, this._events[ev]); } + this._removeAbortController.abort(); // remove DOM elements created by p5, and listeners for (const e of this._elements) { diff --git a/src/events/pointer.js b/src/events/pointer.js index ce942ff0ec..6bdc505141 100644 --- a/src/events/pointer.js +++ b/src/events/pointer.js @@ -8,7 +8,26 @@ import * as constants from '../core/constants'; -function pointer(p5, fn){ +function pointer(p5, fn, lifecycles){ + lifecycles.presetup = function(){ + const events = [ + "pointerdown", + "pointerup", + "pointermove", + "dragend", + "dragover", + "click", + "dblclick", + "wheel" + ]; + for(const event of events){ + window.addEventListener(event, this[`_on${event}`].bind(this), { + passive: false, + signal: this._removeSignal + }); + } + }; + /** * A `Number` system variable that tracks the mouse's horizontal movement. * @@ -765,7 +784,7 @@ function pointer(p5, fn){ center: false }; - /** + /** * An `Array` of all the current touch points on a touchscreen device. * * The `touches` array is empty by default. When the user touches their @@ -848,8 +867,8 @@ function pointer(p5, fn){ * * */ - fn.touches = []; - fn._activePointers = new Map(); + fn.touches = []; + fn._activePointers = new Map(); /** * A `Boolean` system variable that's `true` if the mouse is pressed and @@ -937,7 +956,7 @@ function pointer(p5, fn){ this._hasMouseInteracted = true; } } - }; + }; fn._updateMouseCoords = function() { this.pmouseX = this.mouseX; @@ -955,31 +974,31 @@ function pointer(p5, fn){ winX: evt.clientX, winY: evt.clientY, }; - } + } - function getTouchInfo(canvas, sx, sy, touch) { - const rect = canvas.getBoundingClientRect(); - return { - x: (touch.clientX - rect.left) / sx, - y: (touch.clientY - rect.top) / sy, - winX: touch.clientX, - winY: touch.clientY, - id: touch.pointerId, - }; -} + function getTouchInfo(canvas, sx, sy, touch) { + const rect = canvas.getBoundingClientRect(); + return { + x: (touch.clientX - rect.left) / sx, + y: (touch.clientY - rect.top) / sy, + winX: touch.clientX, + winY: touch.clientY, + id: touch.pointerId, + }; + } -fn._setMouseButton = function(e) { - // Check all active touches to determine button states - this.mouseButton.left = Array.from(this._activePointers.values()).some(touch => - (touch.buttons & 1) !== 0 - ); - this.mouseButton.center = Array.from(this._activePointers.values()).some(touch => - (touch.buttons & 4) !== 0 - ); - this.mouseButton.right = Array.from(this._activePointers.values()).some(touch => - (touch.buttons & 2) !== 0 - ); -}; + fn._setMouseButton = function(e) { + // Check all active touches to determine button states + this.mouseButton.left = Array.from(this._activePointers.values()).some(touch => + (touch.buttons & 1) !== 0 + ); + this.mouseButton.center = Array.from(this._activePointers.values()).some(touch => + (touch.buttons & 4) !== 0 + ); + this.mouseButton.right = Array.from(this._activePointers.values()).some(touch => + (touch.buttons & 2) !== 0 + ); + }; /** * A function that's called when the mouse moves. @@ -1155,24 +1174,22 @@ fn._setMouseButton = function(e) { * */ fn._onpointermove = function(e) { - const context = this._isGlobal ? window : this; let executeDefault; this._updatePointerCoords(e); this._activePointers.set(e.pointerId, e); this._setMouseButton(e); - - if (!this.mouseIsPressed && typeof context.mouseMoved === 'function') { - executeDefault = context.mouseMoved(e); - if (executeDefault === false) { - e.preventDefault(); - } - } else if (this.mouseIsPressed && typeof context.mouseDragged === 'function') { - executeDefault = context.mouseDragged(e); - if (executeDefault === false) { - e.preventDefault(); - } + if (!this.mouseIsPressed && this.userDefinedFunctions.mouseMoved) { + executeDefault = this.userDefinedFunctions.mouseMoved(e); + if (executeDefault === false) { + e.preventDefault(); } + } else if (this.mouseIsPressed && this.userDefinedFunctions.mouseDragged) { + executeDefault = this.userDefinedFunctions.mouseDragged(e); + if (executeDefault === false) { + e.preventDefault(); + } + } }; /** @@ -1318,7 +1335,6 @@ fn._setMouseButton = function(e) { * */ fn._onpointerdown = function(e) { - const context = this._isGlobal ? window : this; let executeDefault; this.mouseIsPressed = true; @@ -1326,8 +1342,8 @@ fn._setMouseButton = function(e) { this._setMouseButton(e); this._updatePointerCoords(e); - if (typeof context.mousePressed === 'function') { - executeDefault = context.mousePressed(e); + if (this.userDefinedFunctions.mousePressed) { + executeDefault = this.userDefinedFunctions.mousePressed(e); if (executeDefault === false) { e.preventDefault(); } @@ -1478,7 +1494,6 @@ fn._setMouseButton = function(e) { * */ fn._onpointerup = function(e) { - const context = this._isGlobal ? window : this; let executeDefault; this.mouseIsPressed = false; @@ -1487,8 +1502,8 @@ fn._setMouseButton = function(e) { this._updatePointerCoords(e); - if (typeof context.mouseReleased === 'function') { - executeDefault = context.mouseReleased(e); + if (this.userDefinedFunctions.mouseReleased) { + executeDefault = this.userDefinedFunctions.mouseReleased(e); if (executeDefault === false) { e.preventDefault(); } @@ -1642,9 +1657,8 @@ fn._setMouseButton = function(e) { * */ fn._onclick = function(e) { - const context = this._isGlobal ? window : this; - if (typeof context.mouseClicked === 'function') { - const executeDefault = context.mouseClicked(e); + if (this.userDefinedFunctions.mouseClicked) { + const executeDefault = this.userDefinedFunctions.mouseClicked(e); if (executeDefault === false) { e.preventDefault(); } @@ -1773,9 +1787,8 @@ fn._setMouseButton = function(e) { */ fn._ondblclick = function(e) { - const context = this._isGlobal ? window : this; - if (typeof context.doubleClicked === 'function') { - const executeDefault = context.doubleClicked(e); + if (this.userDefinedFunctions.doubleClicked) { + const executeDefault = this.userDefinedFunctions.doubleClicked(e); if (executeDefault === false) { e.preventDefault(); } @@ -1921,11 +1934,10 @@ fn._setMouseButton = function(e) { * */ fn._onwheel = function(e) { - const context = this._isGlobal ? window : this; this._mouseWheelDeltaY = e.deltaY; - if (typeof context.mouseWheel === 'function') { + if (this.userDefinedFunctions.mouseWheel) { e.delta = e.deltaY; - const executeDefault = context.mouseWheel(e); + const executeDefault = this.userDefinedFunctions.mouseWheel(e); if (executeDefault === false) { e.preventDefault(); } From 41e378524c9095478eb1a20fd9c80347a7a7fe49 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Sun, 29 Jun 2025 14:11:07 +0100 Subject: [PATCH 02/12] Styling --- src/events/pointer.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/events/pointer.js b/src/events/pointer.js index 6bdc505141..2be9e9273e 100644 --- a/src/events/pointer.js +++ b/src/events/pointer.js @@ -11,14 +11,14 @@ import * as constants from '../core/constants'; function pointer(p5, fn, lifecycles){ lifecycles.presetup = function(){ const events = [ - "pointerdown", - "pointerup", - "pointermove", - "dragend", - "dragover", - "click", - "dblclick", - "wheel" + 'pointerdown', + 'pointerup', + 'pointermove', + 'dragend', + 'dragover', + 'click', + 'dblclick', + 'wheel' ]; for(const event of events){ window.addEventListener(event, this[`_on${event}`].bind(this), { @@ -117,6 +117,7 @@ function pointer(p5, fn, lifecycles){ * */ fn.movedY = 0; + /* * This is a flag which is false until the first time * we receive a mouse event. The pmouseX and pmouseY From e3652137f8687bee485e2ca95e8de84fc9e762a1 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Sun, 29 Jun 2025 17:14:16 +0100 Subject: [PATCH 03/12] Convert keyboard events to new API --- src/core/main.js | 6 +----- src/events/keyboard.js | 49 ++++++++++++++++++++++++++---------------- src/events/pointer.js | 42 ++++++++++++++++++------------------ 3 files changed, 53 insertions(+), 44 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index afc37350d6..3c0b87e586 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -65,11 +65,7 @@ class p5 { this._initializeInstanceVariables(); this._events = { // keep track of user-events for unregistering later - keydown: null, - keyup: null, - keypress: null, - resize: null, - blur: null + resize: null }; this._removeAbortController = new AbortController(); this._removeSignal = this._removeAbortController.signal; diff --git a/src/events/keyboard.js b/src/events/keyboard.js index 1e9eaaebd7..d1b69de2dd 100644 --- a/src/events/keyboard.js +++ b/src/events/keyboard.js @@ -9,7 +9,7 @@ export function isCode(input) { 'Alt', 'Shift', 'Control', - 'Meta', + 'Meta' ]; if (leftRightKeys.includes(input)) { return false; @@ -19,7 +19,24 @@ export function isCode(input) { } return input.length > 1; } -function keyboard(p5, fn){ + +function keyboard(p5, fn, lifecycles){ + lifecycles.presetup = function(){ + const events = [ + 'keydown', + 'keyup', + 'keypress', + 'blur' + ]; + + for(const event of events){ + window.addEventListener(event, this[`_on${event}`].bind(this), { + passive: false, + signal: this._removeSignal + }); + } + }; + /** * A `Boolean` system variable that's `true` if any key is currently pressed * and `false` if not. @@ -109,7 +126,6 @@ function keyboard(p5, fn){ * * */ - fn.keyIsPressed = false; fn.code = null; @@ -470,9 +486,8 @@ function keyboard(p5, fn){ this._downKeyCodes[e.code] = true; this._downKeys[e.key] = true; - const context = this._isGlobal ? window : this; - if (typeof context.keyPressed === 'function' && !e.charCode) { - const executeDefault = context.keyPressed(e); + if (this.userDefinedFunctions.keyPressed && !e.charCode) { + const executeDefault = this.userDefinedFunctions.keyPressed(e); if (executeDefault === false) { e.preventDefault(); } @@ -636,15 +651,13 @@ function keyboard(p5, fn){ * */ fn._onkeyup = function(e) { - - const context = this._isGlobal ? window : this; - if (typeof context.keyReleased === 'function') { - const executeDefault = context.keyReleased(e); + if (this.userDefinedFunctions.keyReleased) { + const executeDefault = this.userDefinedFunctions.keyReleased(e); if (executeDefault === false) { e.preventDefault(); } } - + delete this._downKeyCodes[e.code]; delete this._downKeys[e.key]; @@ -801,14 +814,14 @@ function keyboard(p5, fn){ this._lastKeyCodeTyped = e.which; // track last keyCode this.key = e.key || String.fromCharCode(e.which) || e.which; - const context = this._isGlobal ? window : this; - if (typeof context.keyTyped === 'function') { - const executeDefault = context.keyTyped(e); + if (this.userDefinedFunctions.keyTyped) { + const executeDefault = this.userDefinedFunctions.keyTyped(e); if (executeDefault === false) { e.preventDefault(); } } }; + /** * The onblur function is called when the user is no longer focused * on the p5 element. Because the keyup events will not fire if the user is @@ -936,23 +949,23 @@ function keyboard(p5, fn){ * * */ - fn.keyIsDown = function(input) { if (isCode(input)) { return this._downKeyCodes[input] || this._downKeys[input] || false; } else { return this._downKeys[input] || this._downKeyCodes[input] || false; } - } + }; + /** * The _areDownKeys function returns a boolean true if any keys pressed * and a false if no keys are currently pressed. - + * * Helps avoid instances where multiple keys are pressed simultaneously and * releasing a single key will then switch the * keyIsPressed property to true. * @private - **/ + */ fn._areDownKeys = function() { for (const key in this._downKeys) { if (this._downKeys.hasOwnProperty(key) && this._downKeys[key] === true) { diff --git a/src/events/pointer.js b/src/events/pointer.js index 2be9e9273e..c7e15573fe 100644 --- a/src/events/pointer.js +++ b/src/events/pointer.js @@ -936,13 +936,13 @@ function pointer(p5, fn, lifecycles){ const sx = canvas.scrollWidth / this.width || 1; const sy = canvas.scrollHeight / this.height || 1; - if (e.pointerType == 'touch') { - const touches = []; - for (const touch of this._activePointers.values()) { - touches.push(getTouchInfo(canvas, sx, sy, touch)); - } - this.touches = touches; - } + if (e.pointerType === 'touch') { + const touches = []; + for (const touch of this._activePointers.values()) { + touches.push(getTouchInfo(canvas, sx, sy, touch)); + } + this.touches = touches; + } const mousePos = getMouseInfo(canvas, sx, sy, e); this.movedX = e.movementX || 0; @@ -952,10 +952,10 @@ function pointer(p5, fn, lifecycles){ this.winMouseX = mousePos.winX; this.winMouseY = mousePos.winY; - if (!this._hasMouseInteracted) { - this._updateMouseCoords(); - this._hasMouseInteracted = true; - } + if (!this._hasMouseInteracted) { + this._updateMouseCoords(); + this._hasMouseInteracted = true; + } } }; @@ -970,21 +970,21 @@ function pointer(p5, fn, lifecycles){ function getMouseInfo(canvas, sx, sy, evt) { const rect = canvas.getBoundingClientRect(); return { - x: (evt.clientX - rect.left) / sx, - y: (evt.clientY - rect.top) / sy, - winX: evt.clientX, - winY: evt.clientY, + x: (evt.clientX - rect.left) / sx, + y: (evt.clientY - rect.top) / sy, + winX: evt.clientX, + winY: evt.clientY }; } function getTouchInfo(canvas, sx, sy, touch) { const rect = canvas.getBoundingClientRect(); return { - x: (touch.clientX - rect.left) / sx, - y: (touch.clientY - rect.top) / sy, - winX: touch.clientX, - winY: touch.clientY, - id: touch.pointerId, + x: (touch.clientX - rect.left) / sx, + y: (touch.clientY - rect.top) / sy, + winX: touch.clientX, + winY: touch.clientY, + id: touch.pointerId }; } @@ -1179,7 +1179,7 @@ function pointer(p5, fn, lifecycles){ this._updatePointerCoords(e); this._activePointers.set(e.pointerId, e); this._setMouseButton(e); - + if (!this.mouseIsPressed && this.userDefinedFunctions.mouseMoved) { executeDefault = this.userDefinedFunctions.mouseMoved(e); if (executeDefault === false) { From 82262710c1d903b1fc35a4add5fd1dbe17220255 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Sun, 29 Jun 2025 18:32:24 +0100 Subject: [PATCH 04/12] Convert window resize event to use new API --- docs/parameterData.json | 2 +- src/core/environment.js | 22 +++++++++++++++++----- src/core/main.js | 10 ++-------- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/docs/parameterData.json b/docs/parameterData.json index b99217ebe8..3fc79dbeed 100644 --- a/docs/parameterData.json +++ b/docs/parameterData.json @@ -325,7 +325,7 @@ "windowResized": { "overloads": [ [ - "UIEvent?" + "Event?" ] ] }, diff --git a/src/core/environment.js b/src/core/environment.js index 7f117993c7..c4e9ad2f8a 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -9,7 +9,7 @@ import * as C from './constants'; import { Vector } from '../math/p5.Vector'; -function environment(p5, fn){ +function environment(p5, fn, lifecycles){ const standardCursors = [C.ARROW, C.CROSS, C.HAND, C.MOVE, C.TEXT, C.WAIT]; fn._frameRate = 0; @@ -19,6 +19,19 @@ function environment(p5, fn){ const _windowPrint = window.print; let windowPrintDisabled = false; + lifecycles.presetup = function(){ + const events = [ + 'resize' + ]; + + for(const event of events){ + window.addEventListener(event, this[`_on${event}`].bind(this), { + passive: false, + signal: this._removeSignal + }); + } + }; + /** * Displays text in the web browser's console. * @@ -715,7 +728,7 @@ function environment(p5, fn){ * can be used for debugging or other purposes. * * @method windowResized - * @param {UIEvent} [event] optional resize Event. + * @param {Event} [event] optional resize Event. * @example *
* @@ -770,10 +783,9 @@ function environment(p5, fn){ fn._onresize = function(e) { this.windowWidth = getWindowWidth(); this.windowHeight = getWindowHeight(); - const context = this._isGlobal ? window : this; let executeDefault; - if (typeof context.windowResized === 'function') { - executeDefault = context.windowResized(e); + if (this.userDefinedFunctions.windowResized) { + executeDefault = this.userDefinedFunctions.windowResized(e); if (executeDefault !== undefined && !executeDefault) { e.preventDefault(); } diff --git a/src/core/main.js b/src/core/main.js index 3c0b87e586..5e85a68f68 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -65,7 +65,8 @@ class p5 { this._initializeInstanceVariables(); this._events = { // keep track of user-events for unregistering later - resize: null + deviceorientation: null, + devicemotion: null }; this._removeAbortController = new AbortController(); this._removeSignal = this._removeAbortController.signal; @@ -76,13 +77,6 @@ class p5 { this._lcg_random_state = null; // NOTE: move to random.js this._gaussian_previous = false; // NOTE: move to random.js - if (window.DeviceOrientationEvent) { - this._events.deviceorientation = null; - } - if (window.DeviceMotionEvent && !window._isNodeWebkit) { - this._events.devicemotion = null; - } - // ensure correct reporting of window dimensions this._updateWindowSize(); From 53ecc9d235e5ffd8e07ff57320cc6e739ca5da2a Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Sun, 29 Jun 2025 22:20:09 +0100 Subject: [PATCH 05/12] Convert acceleration events to use new API --- src/core/main.js | 24 ++++-------------------- src/events/acceleration.js | 37 ++++++++++++++++++++++++++----------- 2 files changed, 30 insertions(+), 31 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 5e85a68f68..13b7c268de 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -64,9 +64,6 @@ class p5 { this._startListener = null; this._initializeInstanceVariables(); this._events = { - // keep track of user-events for unregistering later - deviceorientation: null, - devicemotion: null }; this._removeAbortController = new AbortController(); this._removeSignal = this._removeAbortController.signal; @@ -138,16 +135,6 @@ class p5 { p5._checkForUserDefinedFunctions(this); } - // Bind events to window (not using container div bc key events don't work) - for (const e in this._events) { - const f = this[`_on${e}`]; - if (f) { - const m = f.bind(this); - window.addEventListener(e, m, { passive: false }); - this._events[e] = m; - } - } - const focusHandler = () => { this.focused = true; }; @@ -371,10 +358,7 @@ class p5 { window.cancelAnimationFrame(this._requestAnimId); } - // unregister events sketch-wide - for (const ev in this._events) { - window.removeEventListener(ev, this._events[ev]); - } + // Send sketch remove signal this._removeAbortController.abort(); // remove DOM elements created by p5, and listeners @@ -382,9 +366,9 @@ class p5 { if (e.elt && e.elt.parentNode) { e.elt.parentNode.removeChild(e.elt); } - for (const elt_ev in e._events) { - e.elt.removeEventListener(elt_ev, e._events[elt_ev]); - } + // for (const elt_ev in e._events) { + // e.elt.removeEventListener(elt_ev, e._events[elt_ev]); + // } } // Run `remove` hooks diff --git a/src/events/acceleration.js b/src/events/acceleration.js index 3b0d5d8dc7..3b12fa7d8c 100644 --- a/src/events/acceleration.js +++ b/src/events/acceleration.js @@ -6,7 +6,21 @@ * @main Events */ -function acceleration(p5, fn){ +function acceleration(p5, fn, lifecycles){ + lifecycles.presetup = function(){ + const events = [ + 'deviceorientation', + 'devicemotion' + ]; + + for(const event of events){ + window.addEventListener(event, this[`_on${event}`].bind(this), { + passive: false, + signal: this._removeSignal + }); + } + }; + /** * The system variable deviceOrientation always contains the orientation of * the device. The value of this variable will either be set 'landscape' @@ -614,7 +628,6 @@ function acceleration(p5, fn){ * *
*/ - fn._ondeviceorientation = function (e) { this._updatePRotations(); @@ -624,6 +637,7 @@ function acceleration(p5, fn){ this.rotationZ = this._fromDegrees(e.alpha); this._handleMotion(); }; + fn._ondevicemotion = function (e) { this._updatePAccelerations(); this.accelerationX = e.acceleration.x * 2; @@ -631,6 +645,7 @@ function acceleration(p5, fn){ this.accelerationZ = e.acceleration.z * 2; this._handleMotion(); }; + fn._handleMotion = function () { if (window.orientation === 90 || window.orientation === -90) { this.deviceOrientation = 'landscape'; @@ -639,18 +654,18 @@ function acceleration(p5, fn){ } else if (window.orientation === undefined) { this.deviceOrientation = 'undefined'; } - const context = this._isGlobal ? window : this; - if (typeof context.deviceMoved === 'function') { + + if (this.userDefinedFunctions.deviceMoved) { if ( Math.abs(this.accelerationX - this.pAccelerationX) > move_threshold || Math.abs(this.accelerationY - this.pAccelerationY) > move_threshold || Math.abs(this.accelerationZ - this.pAccelerationZ) > move_threshold ) { - context.deviceMoved(); + this.userDefinedFunctions.deviceMoved(); } } - if (typeof context.deviceTurned === 'function') { + if (this.userDefinedFunctions.deviceTurned) { // The angles given by rotationX etc is from range [-180 to 180]. // The following will convert them to [0 to 360] for ease of calculation // of cases when the angles wrapped around. @@ -671,7 +686,7 @@ function acceleration(p5, fn){ if (Math.abs(wRX - wSAX) > 90 && Math.abs(wRX - wSAX) < 270) { wSAX = wRX; this.turnAxis = 'X'; - context.deviceTurned(); + this.userDefinedFunctions.deviceTurned(); } this.pRotateDirectionX = rotateDirectionX; startAngleX = wSAX - 180; @@ -691,7 +706,7 @@ function acceleration(p5, fn){ if (Math.abs(wRY - wSAY) > 90 && Math.abs(wRY - wSAY) < 270) { wSAY = wRY; this.turnAxis = 'Y'; - context.deviceTurned(); + this.userDefinedFunctions.deviceTurned(); } this.pRotateDirectionY = rotateDirectionY; startAngleY = wSAY - 180; @@ -720,12 +735,12 @@ function acceleration(p5, fn){ ) { startAngleZ = rotZ; this.turnAxis = 'Z'; - context.deviceTurned(); + this.userDefinedFunctions.deviceTurned(); } this.pRotateDirectionZ = rotateDirectionZ; this.turnAxis = undefined; } - if (typeof context.deviceShaken === 'function') { + if (this.userDefinedFunctions.deviceShaken) { let accelerationChangeX; let accelerationChangeY; // Add accelerationChangeZ if acceleration change on Z is needed @@ -734,7 +749,7 @@ function acceleration(p5, fn){ accelerationChangeY = Math.abs(this.accelerationY - this.pAccelerationY); } if (accelerationChangeX + accelerationChangeY > shake_threshold) { - context.deviceShaken(); + this.userDefinedFunctions.deviceShaken(); } } }; From e28243274c740122ed92578214d588d61c096028 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Sun, 29 Jun 2025 23:03:17 +0100 Subject: [PATCH 06/12] Automatically remove DOM event listener on sketch removal --- src/core/main.js | 5 +---- src/dom/p5.Element.js | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 13b7c268de..0136c6e3d1 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -361,14 +361,11 @@ class p5 { // Send sketch remove signal this._removeAbortController.abort(); - // remove DOM elements created by p5, and listeners + // remove DOM elements created by p5 for (const e of this._elements) { if (e.elt && e.elt.parentNode) { e.elt.parentNode.removeChild(e.elt); } - // for (const elt_ev in e._events) { - // e.elt.removeEventListener(elt_ev, e._events[elt_ev]); - // } } // Run `remove` hooks diff --git a/src/dom/p5.Element.js b/src/dom/p5.Element.js index 0265a64c42..b824d4ce71 100644 --- a/src/dom/p5.Element.js +++ b/src/dom/p5.Element.js @@ -67,23 +67,22 @@ class Element { // `_elements` array. But when an element lives inside an off-screen // `p5.Graphics` layer, `this._pInst` is that wrapper Graphics object // instead. The wrapper keeps a back–pointer (`_pInst`) to the real - // sketch but has no `_elements` array of its own. - - let sketch = this._pInst; - + // sketch but has no `_elements` array of its own. + + let sketch = this._pInst; + // If `sketch` doesn’t own an `_elements` array it means - // we’re still at the graphics-layer “wrapper”. + // we’re still at the graphics-layer “wrapper”. // Jump one level up to the real p5 sketch stored in sketch._pInst. if (sketch && !sketch._elements && sketch._pInst) { - sketch = sketch._pInst; // climb one level up + sketch = sketch._pInst; // climb one level up } - + if (sketch && sketch._elements) { // only if the array exists const i = sketch._elements.indexOf(this); if (i !== -1) sketch._elements.splice(i, 1); } - // deregister events for (let ev in this._events) { @@ -1865,7 +1864,7 @@ class Element { return this; } - /** + /** * Calls a function when a file is dragged over the element. * * Calling `myElement.dragOver(false)` disables the function. @@ -2416,7 +2415,10 @@ class Element { Element._detachListener(ev, ctx); } const f = fxn.bind(ctx); - ctx.elt.addEventListener(ev, f, false); + ctx.elt.addEventListener(ev, f, { + capture: false, + signal: ctx._pInst._removeSignal + }); ctx._events[ev] = f; } From f7150c2958f3bf780cc911a1bed0c3c33afc97f2 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Sun, 29 Jun 2025 23:15:30 +0100 Subject: [PATCH 07/12] Switch deprecated interface to new supported one --- src/events/acceleration.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/events/acceleration.js b/src/events/acceleration.js index 3b12fa7d8c..a8228e107c 100644 --- a/src/events/acceleration.js +++ b/src/events/acceleration.js @@ -463,9 +463,7 @@ function acceleration(p5, fn, lifecycles){ * * */ - fn.setMoveThreshold = function (val) { - // p5._validateParameters('setMoveThreshold', arguments); move_threshold = val; }; @@ -505,9 +503,7 @@ function acceleration(p5, fn, lifecycles){ * * */ - fn.setShakeThreshold = function (val) { - // p5._validateParameters('setShakeThreshold', arguments); shake_threshold = val; }; @@ -647,11 +643,17 @@ function acceleration(p5, fn, lifecycles){ }; fn._handleMotion = function () { - if (window.orientation === 90 || window.orientation === -90) { + if ( + screen.orientation.type === 'landscape-primary' || + screen.orientation.type === 'landscape-secondary' + ) { this.deviceOrientation = 'landscape'; - } else if (window.orientation === 0) { + } else if ( + screen.orientation.type === 'portrait-primary' || + screen.orientation.type === 'portrait-secondary' + ) { this.deviceOrientation = 'portrait'; - } else if (window.orientation === undefined) { + } else { this.deviceOrientation = 'undefined'; } From 848e619dbe1ccb5846c3a597c5e44916a34dbd2f Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Tue, 8 Jul 2025 18:50:45 +0100 Subject: [PATCH 08/12] Await all lifecycle hook functions in parallel --- src/core/main.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 0136c6e3d1..d1622983a0 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -395,9 +395,9 @@ class p5 { } async _runLifecycleHook(hookName) { - for(const hook of p5.lifecycleHooks[hookName]){ - await hook.call(this); - } + await Promise.all(p5.lifecycleHooks[hookName].map(hook => { + return hook.call(this); + })); } _initializeInstanceVariables() { From 3d5c2cf39f90fa6475fc39fc721d48564a21d56b Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Mon, 21 Jul 2025 15:07:20 +0100 Subject: [PATCH 09/12] Change name to customActions --- src/core/environment.js | 4 ++-- src/core/main.js | 12 ++++++------ src/events/acceleration.js | 16 ++++++++-------- src/events/keyboard.js | 12 ++++++------ src/events/pointer.js | 32 ++++++++++++++++---------------- 5 files changed, 38 insertions(+), 38 deletions(-) diff --git a/src/core/environment.js b/src/core/environment.js index c4e9ad2f8a..7a5aa0fa78 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -784,8 +784,8 @@ function environment(p5, fn, lifecycles){ this.windowWidth = getWindowWidth(); this.windowHeight = getWindowHeight(); let executeDefault; - if (this.userDefinedFunctions.windowResized) { - executeDefault = this.userDefinedFunctions.windowResized(e); + if (this.customActions.windowResized) { + executeDefault = this.customActions.windowResized(e); if (executeDefault !== undefined && !executeDefault) { e.preventDefault(); } diff --git a/src/core/main.js b/src/core/main.js index d1622983a0..51538b0f6b 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -177,19 +177,19 @@ class p5 { } } - _userDefinedFunctions = {}; - userDefinedFunctions = new Proxy({}, { + #customActions = {}; + customActions = new Proxy({}, { get: (target, prop) => { - if(!this._userDefinedFunctions[prop]){ + if(!this.#customActions[prop]){ const context = this._isGlobal ? window : this; if(typeof context[prop] === 'function'){ - this._userDefinedFunctions[prop] = context[prop].bind(this); + this.#customActions[prop] = context[prop].bind(this); } } - return this._userDefinedFunctions[prop]; + return this.#customActions[prop]; } - }) + }); async #_start() { if (this.hitCriticalError) return; diff --git a/src/events/acceleration.js b/src/events/acceleration.js index a8228e107c..08168855cc 100644 --- a/src/events/acceleration.js +++ b/src/events/acceleration.js @@ -657,17 +657,17 @@ function acceleration(p5, fn, lifecycles){ this.deviceOrientation = 'undefined'; } - if (this.userDefinedFunctions.deviceMoved) { + if (this.customActions.deviceMoved) { if ( Math.abs(this.accelerationX - this.pAccelerationX) > move_threshold || Math.abs(this.accelerationY - this.pAccelerationY) > move_threshold || Math.abs(this.accelerationZ - this.pAccelerationZ) > move_threshold ) { - this.userDefinedFunctions.deviceMoved(); + this.customActions.deviceMoved(); } } - if (this.userDefinedFunctions.deviceTurned) { + if (this.customActions.deviceTurned) { // The angles given by rotationX etc is from range [-180 to 180]. // The following will convert them to [0 to 360] for ease of calculation // of cases when the angles wrapped around. @@ -688,7 +688,7 @@ function acceleration(p5, fn, lifecycles){ if (Math.abs(wRX - wSAX) > 90 && Math.abs(wRX - wSAX) < 270) { wSAX = wRX; this.turnAxis = 'X'; - this.userDefinedFunctions.deviceTurned(); + this.customActions.deviceTurned(); } this.pRotateDirectionX = rotateDirectionX; startAngleX = wSAX - 180; @@ -708,7 +708,7 @@ function acceleration(p5, fn, lifecycles){ if (Math.abs(wRY - wSAY) > 90 && Math.abs(wRY - wSAY) < 270) { wSAY = wRY; this.turnAxis = 'Y'; - this.userDefinedFunctions.deviceTurned(); + this.customActions.deviceTurned(); } this.pRotateDirectionY = rotateDirectionY; startAngleY = wSAY - 180; @@ -737,12 +737,12 @@ function acceleration(p5, fn, lifecycles){ ) { startAngleZ = rotZ; this.turnAxis = 'Z'; - this.userDefinedFunctions.deviceTurned(); + this.customActions.deviceTurned(); } this.pRotateDirectionZ = rotateDirectionZ; this.turnAxis = undefined; } - if (this.userDefinedFunctions.deviceShaken) { + if (this.customActions.deviceShaken) { let accelerationChangeX; let accelerationChangeY; // Add accelerationChangeZ if acceleration change on Z is needed @@ -751,7 +751,7 @@ function acceleration(p5, fn, lifecycles){ accelerationChangeY = Math.abs(this.accelerationY - this.pAccelerationY); } if (accelerationChangeX + accelerationChangeY > shake_threshold) { - this.userDefinedFunctions.deviceShaken(); + this.customActions.deviceShaken(); } } }; diff --git a/src/events/keyboard.js b/src/events/keyboard.js index d1b69de2dd..61c897a0a3 100644 --- a/src/events/keyboard.js +++ b/src/events/keyboard.js @@ -486,8 +486,8 @@ function keyboard(p5, fn, lifecycles){ this._downKeyCodes[e.code] = true; this._downKeys[e.key] = true; - if (this.userDefinedFunctions.keyPressed && !e.charCode) { - const executeDefault = this.userDefinedFunctions.keyPressed(e); + if (this.customActions.keyPressed && !e.charCode) { + const executeDefault = this.customActions.keyPressed(e); if (executeDefault === false) { e.preventDefault(); } @@ -651,8 +651,8 @@ function keyboard(p5, fn, lifecycles){ * */ fn._onkeyup = function(e) { - if (this.userDefinedFunctions.keyReleased) { - const executeDefault = this.userDefinedFunctions.keyReleased(e); + if (this.customActions.keyReleased) { + const executeDefault = this.customActions.keyReleased(e); if (executeDefault === false) { e.preventDefault(); } @@ -814,8 +814,8 @@ function keyboard(p5, fn, lifecycles){ this._lastKeyCodeTyped = e.which; // track last keyCode this.key = e.key || String.fromCharCode(e.which) || e.which; - if (this.userDefinedFunctions.keyTyped) { - const executeDefault = this.userDefinedFunctions.keyTyped(e); + if (this.customActions.keyTyped) { + const executeDefault = this.customActions.keyTyped(e); if (executeDefault === false) { e.preventDefault(); } diff --git a/src/events/pointer.js b/src/events/pointer.js index c7e15573fe..126bc36e41 100644 --- a/src/events/pointer.js +++ b/src/events/pointer.js @@ -1180,13 +1180,13 @@ function pointer(p5, fn, lifecycles){ this._activePointers.set(e.pointerId, e); this._setMouseButton(e); - if (!this.mouseIsPressed && this.userDefinedFunctions.mouseMoved) { - executeDefault = this.userDefinedFunctions.mouseMoved(e); + if (!this.mouseIsPressed && this.customActions.mouseMoved) { + executeDefault = this.customActions.mouseMoved(e); if (executeDefault === false) { e.preventDefault(); } - } else if (this.mouseIsPressed && this.userDefinedFunctions.mouseDragged) { - executeDefault = this.userDefinedFunctions.mouseDragged(e); + } else if (this.mouseIsPressed && this.customActions.mouseDragged) { + executeDefault = this.customActions.mouseDragged(e); if (executeDefault === false) { e.preventDefault(); } @@ -1343,12 +1343,12 @@ function pointer(p5, fn, lifecycles){ this._setMouseButton(e); this._updatePointerCoords(e); - if (this.userDefinedFunctions.mousePressed) { - executeDefault = this.userDefinedFunctions.mousePressed(e); + if (this.customActions.mousePressed) { + executeDefault = this.customActions.mousePressed(e); if (executeDefault === false) { e.preventDefault(); } - } + } }; /** @@ -1502,9 +1502,9 @@ function pointer(p5, fn, lifecycles){ this._setMouseButton(e); this._updatePointerCoords(e); - - if (this.userDefinedFunctions.mouseReleased) { - executeDefault = this.userDefinedFunctions.mouseReleased(e); + + if (this.customActions.mouseReleased) { + executeDefault = this.customActions.mouseReleased(e); if (executeDefault === false) { e.preventDefault(); } @@ -1658,8 +1658,8 @@ function pointer(p5, fn, lifecycles){ * */ fn._onclick = function(e) { - if (this.userDefinedFunctions.mouseClicked) { - const executeDefault = this.userDefinedFunctions.mouseClicked(e); + if (this.customActions.mouseClicked) { + const executeDefault = this.customActions.mouseClicked(e); if (executeDefault === false) { e.preventDefault(); } @@ -1788,8 +1788,8 @@ function pointer(p5, fn, lifecycles){ */ fn._ondblclick = function(e) { - if (this.userDefinedFunctions.doubleClicked) { - const executeDefault = this.userDefinedFunctions.doubleClicked(e); + if (this.customActions.doubleClicked) { + const executeDefault = this.customActions.doubleClicked(e); if (executeDefault === false) { e.preventDefault(); } @@ -1936,9 +1936,9 @@ function pointer(p5, fn, lifecycles){ */ fn._onwheel = function(e) { this._mouseWheelDeltaY = e.deltaY; - if (this.userDefinedFunctions.mouseWheel) { + if (this.customActions.mouseWheel) { e.delta = e.deltaY; - const executeDefault = this.userDefinedFunctions.mouseWheel(e); + const executeDefault = this.customActions.mouseWheel(e); if (executeDefault === false) { e.preventDefault(); } From 1f296c15fa3f9ae02eaf071b4d63c40f133bbab7 Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Mon, 21 Jul 2025 15:18:57 +0100 Subject: [PATCH 10/12] Use prefix _ convention to prevent unintended global exposure of custom actions --- src/core/environment.js | 4 ++-- src/core/main.js | 4 ++-- src/events/acceleration.js | 16 ++++++++-------- src/events/keyboard.js | 12 ++++++------ src/events/pointer.js | 28 ++++++++++++++-------------- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/core/environment.js b/src/core/environment.js index 7a5aa0fa78..bac5b82277 100644 --- a/src/core/environment.js +++ b/src/core/environment.js @@ -784,8 +784,8 @@ function environment(p5, fn, lifecycles){ this.windowWidth = getWindowWidth(); this.windowHeight = getWindowHeight(); let executeDefault; - if (this.customActions.windowResized) { - executeDefault = this.customActions.windowResized(e); + if (this._customActions.windowResized) { + executeDefault = this._customActions.windowResized(e); if (executeDefault !== undefined && !executeDefault) { e.preventDefault(); } diff --git a/src/core/main.js b/src/core/main.js index 51538b0f6b..2ce94a0a91 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -99,7 +99,7 @@ class p5 { console.log(`You just changed the value of "${property}", which was a p5 global value. This could cause problems later if you're not careful.`); } } - }) + }); }; // If the user has created a global setup or draw function, // assume "global" mode and make everything global (i.e. on the window) @@ -178,7 +178,7 @@ class p5 { } #customActions = {}; - customActions = new Proxy({}, { + _customActions = new Proxy({}, { get: (target, prop) => { if(!this.#customActions[prop]){ const context = this._isGlobal ? window : this; diff --git a/src/events/acceleration.js b/src/events/acceleration.js index 08168855cc..dfa6927485 100644 --- a/src/events/acceleration.js +++ b/src/events/acceleration.js @@ -657,17 +657,17 @@ function acceleration(p5, fn, lifecycles){ this.deviceOrientation = 'undefined'; } - if (this.customActions.deviceMoved) { + if (this._customActions.deviceMoved) { if ( Math.abs(this.accelerationX - this.pAccelerationX) > move_threshold || Math.abs(this.accelerationY - this.pAccelerationY) > move_threshold || Math.abs(this.accelerationZ - this.pAccelerationZ) > move_threshold ) { - this.customActions.deviceMoved(); + this._customActions.deviceMoved(); } } - if (this.customActions.deviceTurned) { + if (this._customActions.deviceTurned) { // The angles given by rotationX etc is from range [-180 to 180]. // The following will convert them to [0 to 360] for ease of calculation // of cases when the angles wrapped around. @@ -688,7 +688,7 @@ function acceleration(p5, fn, lifecycles){ if (Math.abs(wRX - wSAX) > 90 && Math.abs(wRX - wSAX) < 270) { wSAX = wRX; this.turnAxis = 'X'; - this.customActions.deviceTurned(); + this._customActions.deviceTurned(); } this.pRotateDirectionX = rotateDirectionX; startAngleX = wSAX - 180; @@ -708,7 +708,7 @@ function acceleration(p5, fn, lifecycles){ if (Math.abs(wRY - wSAY) > 90 && Math.abs(wRY - wSAY) < 270) { wSAY = wRY; this.turnAxis = 'Y'; - this.customActions.deviceTurned(); + this._customActions.deviceTurned(); } this.pRotateDirectionY = rotateDirectionY; startAngleY = wSAY - 180; @@ -737,12 +737,12 @@ function acceleration(p5, fn, lifecycles){ ) { startAngleZ = rotZ; this.turnAxis = 'Z'; - this.customActions.deviceTurned(); + this._customActions.deviceTurned(); } this.pRotateDirectionZ = rotateDirectionZ; this.turnAxis = undefined; } - if (this.customActions.deviceShaken) { + if (this._customActions.deviceShaken) { let accelerationChangeX; let accelerationChangeY; // Add accelerationChangeZ if acceleration change on Z is needed @@ -751,7 +751,7 @@ function acceleration(p5, fn, lifecycles){ accelerationChangeY = Math.abs(this.accelerationY - this.pAccelerationY); } if (accelerationChangeX + accelerationChangeY > shake_threshold) { - this.customActions.deviceShaken(); + this._customActions.deviceShaken(); } } }; diff --git a/src/events/keyboard.js b/src/events/keyboard.js index 61c897a0a3..0daeb74d2a 100644 --- a/src/events/keyboard.js +++ b/src/events/keyboard.js @@ -486,8 +486,8 @@ function keyboard(p5, fn, lifecycles){ this._downKeyCodes[e.code] = true; this._downKeys[e.key] = true; - if (this.customActions.keyPressed && !e.charCode) { - const executeDefault = this.customActions.keyPressed(e); + if (this._customActions.keyPressed && !e.charCode) { + const executeDefault = this._customActions.keyPressed(e); if (executeDefault === false) { e.preventDefault(); } @@ -651,8 +651,8 @@ function keyboard(p5, fn, lifecycles){ * */ fn._onkeyup = function(e) { - if (this.customActions.keyReleased) { - const executeDefault = this.customActions.keyReleased(e); + if (this._customActions.keyReleased) { + const executeDefault = this._customActions.keyReleased(e); if (executeDefault === false) { e.preventDefault(); } @@ -814,8 +814,8 @@ function keyboard(p5, fn, lifecycles){ this._lastKeyCodeTyped = e.which; // track last keyCode this.key = e.key || String.fromCharCode(e.which) || e.which; - if (this.customActions.keyTyped) { - const executeDefault = this.customActions.keyTyped(e); + if (this._customActions.keyTyped) { + const executeDefault = this._customActions.keyTyped(e); if (executeDefault === false) { e.preventDefault(); } diff --git a/src/events/pointer.js b/src/events/pointer.js index 126bc36e41..cceee7b21d 100644 --- a/src/events/pointer.js +++ b/src/events/pointer.js @@ -1180,13 +1180,13 @@ function pointer(p5, fn, lifecycles){ this._activePointers.set(e.pointerId, e); this._setMouseButton(e); - if (!this.mouseIsPressed && this.customActions.mouseMoved) { - executeDefault = this.customActions.mouseMoved(e); + if (!this.mouseIsPressed && this._customActions.mouseMoved) { + executeDefault = this._customActions.mouseMoved(e); if (executeDefault === false) { e.preventDefault(); } - } else if (this.mouseIsPressed && this.customActions.mouseDragged) { - executeDefault = this.customActions.mouseDragged(e); + } else if (this.mouseIsPressed && this._customActions.mouseDragged) { + executeDefault = this._customActions.mouseDragged(e); if (executeDefault === false) { e.preventDefault(); } @@ -1343,8 +1343,8 @@ function pointer(p5, fn, lifecycles){ this._setMouseButton(e); this._updatePointerCoords(e); - if (this.customActions.mousePressed) { - executeDefault = this.customActions.mousePressed(e); + if (this._customActions.mousePressed) { + executeDefault = this._customActions.mousePressed(e); if (executeDefault === false) { e.preventDefault(); } @@ -1503,8 +1503,8 @@ function pointer(p5, fn, lifecycles){ this._updatePointerCoords(e); - if (this.customActions.mouseReleased) { - executeDefault = this.customActions.mouseReleased(e); + if (this._customActions.mouseReleased) { + executeDefault = this._customActions.mouseReleased(e); if (executeDefault === false) { e.preventDefault(); } @@ -1658,8 +1658,8 @@ function pointer(p5, fn, lifecycles){ * */ fn._onclick = function(e) { - if (this.customActions.mouseClicked) { - const executeDefault = this.customActions.mouseClicked(e); + if (this._customActions.mouseClicked) { + const executeDefault = this._customActions.mouseClicked(e); if (executeDefault === false) { e.preventDefault(); } @@ -1788,8 +1788,8 @@ function pointer(p5, fn, lifecycles){ */ fn._ondblclick = function(e) { - if (this.customActions.doubleClicked) { - const executeDefault = this.customActions.doubleClicked(e); + if (this._customActions.doubleClicked) { + const executeDefault = this._customActions.doubleClicked(e); if (executeDefault === false) { e.preventDefault(); } @@ -1936,9 +1936,9 @@ function pointer(p5, fn, lifecycles){ */ fn._onwheel = function(e) { this._mouseWheelDeltaY = e.deltaY; - if (this.customActions.mouseWheel) { + if (this._customActions.mouseWheel) { e.delta = e.deltaY; - const executeDefault = this.customActions.mouseWheel(e); + const executeDefault = this._customActions.mouseWheel(e); if (executeDefault === false) { e.preventDefault(); } From 8b3871a59c1c225716dff69801a7caddfb461d2a Mon Sep 17 00:00:00 2001 From: limzykenneth Date: Mon, 21 Jul 2025 16:42:33 +0100 Subject: [PATCH 11/12] Add documentation for custom actions and event signal --- contributor_docs/creating_libraries.md | 38 ++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/contributor_docs/creating_libraries.md b/contributor_docs/creating_libraries.md index 38de55461e..4836dd7bb5 100644 --- a/contributor_docs/creating_libraries.md +++ b/contributor_docs/creating_libraries.md @@ -282,6 +282,31 @@ if (typeof p5 !== undefined) { In the above snippet, an additional `if` condition is added around the call to `p5.registerAddon()`. This is done to support both direct usage in ESM modules (where users can directly import your addon function then call `p5.registerAddon()` themselves) and after bundling support regular `