From 2543102e220acd5b9f4fb4c647c671eaf64e1d92 Mon Sep 17 00:00:00 2001 From: capGoblin Date: Mon, 25 Sep 2023 22:28:50 +0530 Subject: [PATCH 01/11] add hooks --- src/core/main.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/main.js b/src/core/main.js index f7f94dfbd6..81ead84f89 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -231,6 +231,11 @@ class p5 { this._events.devicemotion = null; } + this._beforePreload = function () {}; + this._afterPreload = function () {}; + this._beforeSetup = function () {}; + this._afterSetup = function () {}; + this._start = () => { // Find node if id given if (this._userNode) { @@ -241,6 +246,7 @@ class p5 { const context = this._isGlobal ? window : this; if (context.preload) { + this._beforePreload(); // Setup loading screen // Set loading screen into dom if not present // Otherwise displays and removes user provided loading screen @@ -271,8 +277,11 @@ class p5 { context.preload(); this._runIfPreloadsAreDone(); + this._afterPreload(); } else { + this._beforeSetup(); this._setup(); + this._afterSetup(); if (!this._recording) { this._draw(); } From 50163a2b5b2c76a0a363f321de7b2d7ee0317fa7 Mon Sep 17 00:00:00 2001 From: capGoblin Date: Tue, 26 Sep 2023 19:06:01 +0530 Subject: [PATCH 02/11] Refactor hooks --- src/core/main.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 81ead84f89..385ddc58b2 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -231,6 +231,7 @@ class p5 { this._events.devicemotion = null; } + // before and after hooks for preload and setup this._beforePreload = function () {}; this._afterPreload = function () {}; this._beforeSetup = function () {}; @@ -277,11 +278,8 @@ class p5 { context.preload(); this._runIfPreloadsAreDone(); - this._afterPreload(); } else { - this._beforeSetup(); this._setup(); - this._afterSetup(); if (!this._recording) { this._draw(); } @@ -304,6 +302,7 @@ class p5 { } } } + this._afterPreload(); }; this._decrementPreload = function() { @@ -331,6 +330,7 @@ class p5 { }; this._setup = () => { + this._beforeSetup(); // Always create a default canvas. // Later on if the user calls createCanvas, this default one // will be replaced @@ -378,6 +378,7 @@ class p5 { if (this._accessibleOutputs.grid || this._accessibleOutputs.text) { this._updateAccsOutput(); } + this._afterSetup(); }; this._draw = () => { From 6b161996d27703b48e47548e66487154b77c8f61 Mon Sep 17 00:00:00 2001 From: capGoblin Date: Wed, 27 Sep 2023 18:09:58 +0530 Subject: [PATCH 03/11] add callRegisteredHooksFor --- src/core/main.js | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 385ddc58b2..d5d54eab07 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -231,11 +231,18 @@ class p5 { this._events.devicemotion = null; } - // before and after hooks for preload and setup - this._beforePreload = function () {}; - this._afterPreload = function () {}; - this._beforeSetup = function () {}; - this._afterSetup = function () {}; + // Function to call registered before and after hooks for preload and setup + function callRegisteredHooksFor(hookName) { + const target = this || p5.prototype; + if (target._registeredMethods.hasOwnProperty(hookName)) { + const methods = target._registeredMethods[hookName]; + for (const method of methods) { + if (typeof method === 'function') { + method.call(this); + } + } + } + } this._start = () => { // Find node if id given @@ -247,7 +254,7 @@ class p5 { const context = this._isGlobal ? window : this; if (context.preload) { - this._beforePreload(); + callRegisteredHooksFor('beforePreload'); // Setup loading screen // Set loading screen into dom if not present // Otherwise displays and removes user provided loading screen @@ -293,6 +300,7 @@ class p5 { if (loadingScreen) { loadingScreen.parentNode.removeChild(loadingScreen); } + callRegisteredHooksFor('afterPreload'); if (!this._setupDone) { this._lastTargetFrameTime = window.performance.now(); this._lastRealFrameTime = window.performance.now(); @@ -302,7 +310,6 @@ class p5 { } } } - this._afterPreload(); }; this._decrementPreload = function() { @@ -330,7 +337,7 @@ class p5 { }; this._setup = () => { - this._beforeSetup(); + callRegisteredHooksFor('beforeSetup'); // Always create a default canvas. // Later on if the user calls createCanvas, this default one // will be replaced @@ -378,7 +385,7 @@ class p5 { if (this._accessibleOutputs.grid || this._accessibleOutputs.text) { this._updateAccsOutput(); } - this._afterSetup(); + callRegisteredMethods('afterSetup'); }; this._draw = () => { From 25d9cb47d6b0daf90408385218749c6c2dc72e41 Mon Sep 17 00:00:00 2001 From: capGoblin Date: Wed, 27 Sep 2023 18:36:23 +0530 Subject: [PATCH 04/11] corrected a typo --- src/core/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/main.js b/src/core/main.js index d5d54eab07..fab8543f5a 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -385,7 +385,7 @@ class p5 { if (this._accessibleOutputs.grid || this._accessibleOutputs.text) { this._updateAccsOutput(); } - callRegisteredMethods('afterSetup'); + callRegisteredHooksFor('afterSetup'); }; this._draw = () => { From 6bb0e6fcd17cebfdecf644e5c1a82e1d93c7fd7c Mon Sep 17 00:00:00 2001 From: capGoblin Date: Wed, 27 Sep 2023 20:42:12 +0530 Subject: [PATCH 05/11] update callRegisteredHooksFor to use context --- src/core/main.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index fab8543f5a..401199d873 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -231,14 +231,15 @@ class p5 { this._events.devicemotion = null; } - // Function to call registered before and after hooks for preload and setup + // Function to invoke registered hooks before or after events such as preload, setup, and pre/post draw. function callRegisteredHooksFor(hookName) { const target = this || p5.prototype; + const context = this._isGlobal ? window : this; if (target._registeredMethods.hasOwnProperty(hookName)) { const methods = target._registeredMethods[hookName]; for (const method of methods) { if (typeof method === 'function') { - method.call(this); + method.call(context); } } } From 5514eaaa259e2d53833bb656cc68ce176f50f00b Mon Sep 17 00:00:00 2001 From: capGoblin Date: Wed, 27 Sep 2023 20:43:59 +0530 Subject: [PATCH 06/11] use callRegisteredHooksFor for pre/post draw --- src/core/structure.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/core/structure.js b/src/core/structure.js index 85f66004dc..459e6b7bed 100644 --- a/src/core/structure.js +++ b/src/core/structure.js @@ -6,7 +6,7 @@ */ import p5 from './main'; - +import callRegisteredHooksFor from './main'; /** * Stops p5.js from continuously executing the code within draw(). * If loop() is called, the code in draw() @@ -471,9 +471,6 @@ p5.prototype.redraw = function(n) { if (typeof context.setup === 'undefined') { context.scale(context._pixelDensity, context._pixelDensity); } - const callMethod = f => { - f.call(context); - }; for (let idxRedraw = 0; idxRedraw < numberOfRedraws; idxRedraw++) { context.resetMatrix(); if (this._accessibleOutputs.grid || this._accessibleOutputs.text) { @@ -483,14 +480,14 @@ p5.prototype.redraw = function(n) { context._renderer._update(); } context._setProperty('frameCount', context.frameCount + 1); - context._registeredMethods.pre.forEach(callMethod); + callRegisteredHooksFor.call(context, 'pre'); this._inUserDraw = true; try { context.draw(); } finally { this._inUserDraw = false; } - context._registeredMethods.post.forEach(callMethod); + callRegisteredHooksFor.call(context, 'post'); } } }; From fa06c9c95c43135b206249b070f184825a27757c Mon Sep 17 00:00:00 2001 From: capGoblin Date: Wed, 27 Sep 2023 21:05:12 +0530 Subject: [PATCH 07/11] isGlobal is not read inside callRegisteredHooksFor --- src/core/main.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/main.js b/src/core/main.js index 401199d873..817e29f320 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -232,9 +232,9 @@ class p5 { } // Function to invoke registered hooks before or after events such as preload, setup, and pre/post draw. + const context = this._isGlobal ? window : this; function callRegisteredHooksFor(hookName) { const target = this || p5.prototype; - const context = this._isGlobal ? window : this; if (target._registeredMethods.hasOwnProperty(hookName)) { const methods = target._registeredMethods[hookName]; for (const method of methods) { From ff32bbd6a95242922a270201d5ee46b3d975aa10 Mon Sep 17 00:00:00 2001 From: capGoblin Date: Wed, 27 Sep 2023 21:46:34 +0530 Subject: [PATCH 08/11] fix tests fails --- src/core/main.js | 14 +++++++------- src/core/structure.js | 5 ++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/src/core/main.js b/src/core/main.js index 817e29f320..4e4e37cef5 100644 --- a/src/core/main.js +++ b/src/core/main.js @@ -232,9 +232,9 @@ class p5 { } // Function to invoke registered hooks before or after events such as preload, setup, and pre/post draw. - const context = this._isGlobal ? window : this; - function callRegisteredHooksFor(hookName) { + p5.prototype.callRegisteredHooksFor = function (hookName) { const target = this || p5.prototype; + const context = this._isGlobal ? window : this; if (target._registeredMethods.hasOwnProperty(hookName)) { const methods = target._registeredMethods[hookName]; for (const method of methods) { @@ -243,7 +243,7 @@ class p5 { } } } - } + }; this._start = () => { // Find node if id given @@ -255,7 +255,7 @@ class p5 { const context = this._isGlobal ? window : this; if (context.preload) { - callRegisteredHooksFor('beforePreload'); + this.callRegisteredHooksFor('beforePreload'); // Setup loading screen // Set loading screen into dom if not present // Otherwise displays and removes user provided loading screen @@ -301,7 +301,7 @@ class p5 { if (loadingScreen) { loadingScreen.parentNode.removeChild(loadingScreen); } - callRegisteredHooksFor('afterPreload'); + this.callRegisteredHooksFor('afterPreload'); if (!this._setupDone) { this._lastTargetFrameTime = window.performance.now(); this._lastRealFrameTime = window.performance.now(); @@ -338,7 +338,7 @@ class p5 { }; this._setup = () => { - callRegisteredHooksFor('beforeSetup'); + this.callRegisteredHooksFor('beforeSetup'); // Always create a default canvas. // Later on if the user calls createCanvas, this default one // will be replaced @@ -386,7 +386,7 @@ class p5 { if (this._accessibleOutputs.grid || this._accessibleOutputs.text) { this._updateAccsOutput(); } - callRegisteredHooksFor('afterSetup'); + this.callRegisteredHooksFor('afterSetup'); }; this._draw = () => { diff --git a/src/core/structure.js b/src/core/structure.js index 459e6b7bed..539a9c1192 100644 --- a/src/core/structure.js +++ b/src/core/structure.js @@ -6,7 +6,6 @@ */ import p5 from './main'; -import callRegisteredHooksFor from './main'; /** * Stops p5.js from continuously executing the code within draw(). * If loop() is called, the code in draw() @@ -480,14 +479,14 @@ p5.prototype.redraw = function(n) { context._renderer._update(); } context._setProperty('frameCount', context.frameCount + 1); - callRegisteredHooksFor.call(context, 'pre'); + this.callRegisteredHooksFor('pre'); this._inUserDraw = true; try { context.draw(); } finally { this._inUserDraw = false; } - callRegisteredHooksFor.call(context, 'post'); + this.callRegisteredHooksFor('post'); } } }; From a9394b71e901d9db51ae1324045aadeadcca072b Mon Sep 17 00:00:00 2001 From: capGoblin Date: Thu, 28 Sep 2023 11:20:10 +0530 Subject: [PATCH 09/11] add tests for hooks --- test/unit/core/main.js | 87 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/test/unit/core/main.js b/test/unit/core/main.js index bc73fab76c..705cbced3a 100644 --- a/test/unit/core/main.js +++ b/test/unit/core/main.js @@ -1,4 +1,4 @@ -const { expect } = require('chai'); +const { expect, assert } = require('chai'); suite('Core', function() { suite('p5.prototype.registerMethod', function() { @@ -31,6 +31,91 @@ suite('Core', function() { p5.prototype._registeredMethods.init = originalInit; } }); + test('should register and call before and after "preload" hooks', function() { + return new Promise(resolve => { + let beforePreloadCalled = false; + let preloadCalled = false; + let afterPreloadCalled = false; + + p5.prototype.registerMethod('beforePreload', () => { + beforePreloadCalled = true; + }); + + p5.prototype.registerMethod('preload', () => { + assert.equal(beforePreloadCalled, true); + preloadCalled = true; + }); + + p5.prototype.registerMethod('afterPreload', () => { + if(beforePreloadCalled && preloadCalled) + afterPreloadCalled = true; + }); + + myp5 = new p5(function(sketch) { + sketch.preload = () => {}; + sketch.setup = () => { + assert.equal(afterPreloadCalled, true); + }; + resolve(); + }); + }); + }); + test('should register and call before and after "setup" hooks', function() { + return new Promise(resolve => { + let beforeSetupCalled = false; + let setupCalled = false; + let afterSetupCalled = false; + + p5.prototype.registerMethod('beforeSetup', () => { + beforeSetupCalled = true; + }); + + p5.prototype.registerMethod('setup', () => { + assert.equal(beforeSetupCalled, true); + setupCalled = true; + }); + + p5.prototype.registerMethod('afterSetup', () => { + if(beforeSetupCalled && setupCalled) + afterSetupCalled = true; + }); + + myp5 = new p5(function(sketch) { + sketch.setup = () => {}; + sketch.draw = () => { + assert.equal(afterSetupCalled, true); + resolve(); + }; + }); + }); + }); + test('should register and call pre and post "draw" hooks', function() { + return new Promise(resolve => { + let preDrawCalled = false; + let drawCalled = false; + let postDrawCalled = false; + + p5.prototype.registerMethod('pre', () => { + preDrawCalled = true; + }); + + p5.prototype.registerMethod('draw', () => { + assert.equal(preDrawCalled, true); + drawCalled = true; + }); + + p5.prototype.registerMethod('post', () => { + if(preDrawCalled && drawCalled) + postDrawCalled = true; + }); + + myp5 = new p5(function(sketch) { + sketch.draw = () => {}; + }); + assert.equal(postDrawCalled, true); + resolve(); + }); + }); }); suite('new p5() / global mode', function() { From c0d63496034dc496b894dd1f2729dfc62159dcb3 Mon Sep 17 00:00:00 2001 From: capGoblin Date: Tue, 3 Oct 2023 20:26:38 +0530 Subject: [PATCH 10/11] refactor the tests --- test/unit/core/main.js | 152 +++++++++++++++++++++-------------------- 1 file changed, 78 insertions(+), 74 deletions(-) diff --git a/test/unit/core/main.js b/test/unit/core/main.js index 705cbced3a..7df683542f 100644 --- a/test/unit/core/main.js +++ b/test/unit/core/main.js @@ -1,37 +1,41 @@ const { expect, assert } = require('chai'); -suite('Core', function() { - suite('p5.prototype.registerMethod', function() { - test('should register and call "init" methods', function() { - var originalInit = p5.prototype._registeredMethods.init; - var myp5, myInitCalled; - +suite('Core', function () { + suite('p5.prototype.registerMethod', function () { + teardown(function() { p5.prototype._registeredMethods.init = []; + p5.prototype._registeredMethods.beforePreload = []; + p5.prototype._registeredMethods.preload = []; + p5.prototype._registeredMethods.afterPreload = []; + p5.prototype._registeredMethods.beforeSetup = []; + p5.prototype._registeredMethods.setup = []; + p5.prototype._registeredMethods.afterSetup = []; + p5.prototype._registeredMethods.pre = []; + p5.prototype._registeredMethods.draw = []; + p5.prototype._registeredMethods.post = []; + }); + test('should register and call "init" methods', function () { + var myp5, myInitCalled; + p5.prototype.registerMethod('init', function myInit() { + assert( + !myInitCalled, + 'myInit should only be called once during test suite' + ); + myInitCalled = true; - try { - p5.prototype.registerMethod('init', function myInit() { - assert( - !myInitCalled, - 'myInit should only be called once during test suite' - ); - myInitCalled = true; - - this.myInitCalled = true; - }); + this.myInitCalled = true; + }); - myp5 = new p5(function(sketch) { - assert(sketch.hasOwnProperty('myInitCalled')); - assert(sketch.myInitCalled); + myp5 = new p5(function (sketch) { + assert(sketch.hasOwnProperty('myInitCalled')); + assert(sketch.myInitCalled); - sketch.sketchFunctionCalled = true; - }); + sketch.sketchFunctionCalled = true; + }); - assert(myp5.sketchFunctionCalled); - } finally { - p5.prototype._registeredMethods.init = originalInit; - } + assert(myp5.sketchFunctionCalled); }); - test('should register and call before and after "preload" hooks', function() { + test('should register and call before and after "preload" hooks', function () { return new Promise(resolve => { let beforePreloadCalled = false; let preloadCalled = false; @@ -47,20 +51,19 @@ suite('Core', function() { }); p5.prototype.registerMethod('afterPreload', () => { - if(beforePreloadCalled && preloadCalled) - afterPreloadCalled = true; + if (beforePreloadCalled && preloadCalled) afterPreloadCalled = true; }); - myp5 = new p5(function(sketch) { + myp5 = new p5(function (sketch) { sketch.preload = () => {}; sketch.setup = () => { assert.equal(afterPreloadCalled, true); + resolve(); }; - resolve(); }); }); }); - test('should register and call before and after "setup" hooks', function() { + test('should register and call before and after "setup" hooks', function () { return new Promise(resolve => { let beforeSetupCalled = false; let setupCalled = false; @@ -76,11 +79,10 @@ suite('Core', function() { }); p5.prototype.registerMethod('afterSetup', () => { - if(beforeSetupCalled && setupCalled) - afterSetupCalled = true; + if (beforeSetupCalled && setupCalled) afterSetupCalled = true; }); - myp5 = new p5(function(sketch) { + myp5 = new p5(function (sketch) { sketch.setup = () => {}; sketch.draw = () => { assert.equal(afterSetupCalled, true); @@ -89,7 +91,7 @@ suite('Core', function() { }); }); }); - test('should register and call pre and post "draw" hooks', function() { + test('should register and call pre and post "draw" hooks', function () { return new Promise(resolve => { let preDrawCalled = false; let drawCalled = false; @@ -105,49 +107,51 @@ suite('Core', function() { }); p5.prototype.registerMethod('post', () => { - if(preDrawCalled && drawCalled) - postDrawCalled = true; + if (preDrawCalled && drawCalled) postDrawCalled = true; }); - myp5 = new p5(function(sketch) { - sketch.draw = () => {}; + myp5 = new p5(function (sketch) { + sketch.draw = () => { + if (sketch.frameCount === 2) { + assert.equal(postDrawCalled, true); + resolve(); + } + }; }); - assert.equal(postDrawCalled, true); - resolve(); }); }); }); - suite('new p5() / global mode', function() { + suite('new p5() / global mode', function () { var iframe; - teardown(function() { + teardown(function () { if (iframe) { iframe.teardown(); iframe = null; } }); - test('is triggered when "setup" is in window', function() { - return new Promise(function(resolve, reject) { + test('is triggered when "setup" is in window', function () { + return new Promise(function (resolve, reject) { iframe = createP5Iframe(); - iframe.elt.contentWindow.setup = function() { + iframe.elt.contentWindow.setup = function () { resolve(); }; }); }); - test('is triggered when "draw" is in window', function() { - return new Promise(function(resolve, reject) { + test('is triggered when "draw" is in window', function () { + return new Promise(function (resolve, reject) { iframe = createP5Iframe(); - iframe.elt.contentWindow.draw = function() { + iframe.elt.contentWindow.draw = function () { resolve(); }; }); }); - test('works when p5.js is loaded asynchronously', function() { - return new Promise(function(resolve, reject) { + test('works when p5.js is loaded asynchronously', function () { + return new Promise(function (resolve, reject) { iframe = createP5Iframe(`