@@ -452,7 +452,15 @@ class Activity {
452452 this . hideBlocksContainer = null ;
453453 this . collapseBlocksContainer = null ;
454454
455+ // --- DOM reads (batched to avoid forced synchronous layout) ---
455456 this . searchWidget = document . getElementById ( "search" ) ;
457+ this . progressBar = document . getElementById ( "myProgress" ) ;
458+ const pasteEl = document . getElementById ( "paste" ) ;
459+ new createjs . DOMElement ( pasteEl ) ;
460+ this . paste = pasteEl ;
461+ this . toolbarHeight = document . getElementById ( "toolbars" ) . offsetHeight ;
462+
463+ // --- DOM writes (after all reads complete) ---
456464 this . searchWidget . style . visibility = "hidden" ;
457465 this . searchWidget . placeholder = _ ( "Search for blocks" ) ;
458466
@@ -461,15 +469,9 @@ class Activity {
461469 this . helpfulSearchWidget . style . visibility = "hidden" ;
462470 this . helpfulSearchWidget . placeholder = _ ( "Search for blocks" ) ;
463471 this . helpfulSearchWidget . classList . add ( "ui-autocomplete" ) ;
464- this . progressBar = document . getElementById ( "myProgress" ) ;
465472 this . progressBar . style . visibility = "hidden" ;
466-
467- new createjs . DOMElement ( document . getElementById ( "paste" ) ) ;
468- this . paste = document . getElementById ( "paste" ) ;
469473 this . paste . style . visibility = "hidden" ;
470474
471- this . toolbarHeight = document . getElementById ( "toolbars" ) . offsetHeight ;
472-
473475 this . helpfulWheelItems = [ ] ;
474476
475477 this . setHelpfulSearchDiv ( ) ;
@@ -2633,47 +2635,55 @@ class Activity {
26332635 * Handles touch start event on the canvas.
26342636 * @param {TouchEvent } event - The touch event object.
26352637 */
2636- myCanvas . addEventListener ( "touchstart" , event => {
2637- if ( event . touches . length === 2 ) {
2638- for ( let i = 0 ; i < 2 ; i ++ ) {
2639- initialTouches [ i ] [ 0 ] = event . touches [ i ] . clientY ;
2640- initialTouches [ i ] [ 1 ] = event . touches [ i ] . clientX ;
2638+ myCanvas . addEventListener (
2639+ "touchstart" ,
2640+ event => {
2641+ if ( event . touches . length === 2 ) {
2642+ for ( let i = 0 ; i < 2 ; i ++ ) {
2643+ initialTouches [ i ] [ 0 ] = event . touches [ i ] . clientY ;
2644+ initialTouches [ i ] [ 1 ] = event . touches [ i ] . clientX ;
2645+ }
26412646 }
2642- }
2643- } ) ;
2647+ } ,
2648+ { passive : true }
2649+ ) ;
26442650
26452651 /**
26462652 * Handles touch move event on the canvas.
26472653 * @param {TouchEvent } event - The touch event object.
26482654 */
2649- myCanvas . addEventListener ( "touchmove" , event => {
2650- if ( event . touches . length === 2 ) {
2651- for ( let i = 0 ; i < 2 ; i ++ ) {
2652- const touchY = event . touches [ i ] . clientY ;
2653- const touchX = event . touches [ i ] . clientX ;
2654-
2655- if ( initialTouches [ i ] [ 0 ] !== null && initialTouches [ i ] [ 1 ] !== null ) {
2656- const deltaY = touchY - initialTouches [ i ] [ 0 ] ;
2657- const deltaX = touchX - initialTouches [ i ] [ 1 ] ;
2658-
2659- if ( deltaY !== 0 ) {
2660- closeAnyOpenMenusAndLabels ( ) ;
2661- that . blocksContainer . y -= deltaY ;
2662- }
2655+ myCanvas . addEventListener (
2656+ "touchmove" ,
2657+ event => {
2658+ if ( event . touches . length === 2 ) {
2659+ for ( let i = 0 ; i < 2 ; i ++ ) {
2660+ const touchY = event . touches [ i ] . clientY ;
2661+ const touchX = event . touches [ i ] . clientX ;
2662+
2663+ if ( initialTouches [ i ] [ 0 ] !== null && initialTouches [ i ] [ 1 ] !== null ) {
2664+ const deltaY = touchY - initialTouches [ i ] [ 0 ] ;
2665+ const deltaX = touchX - initialTouches [ i ] [ 1 ] ;
2666+
2667+ if ( deltaY !== 0 ) {
2668+ closeAnyOpenMenusAndLabels ( ) ;
2669+ that . blocksContainer . y -= deltaY ;
2670+ }
26632671
2664- if ( that . scrollBlockContainer && deltaX !== 0 ) {
2665- closeAnyOpenMenusAndLabels ( ) ;
2666- that . blocksContainer . x -= deltaX ;
2667- }
2672+ if ( that . scrollBlockContainer && deltaX !== 0 ) {
2673+ closeAnyOpenMenusAndLabels ( ) ;
2674+ that . blocksContainer . x -= deltaX ;
2675+ }
26682676
2669- initialTouches [ i ] [ 0 ] = touchY ;
2670- initialTouches [ i ] [ 1 ] = touchX ;
2677+ initialTouches [ i ] [ 0 ] = touchY ;
2678+ initialTouches [ i ] [ 1 ] = touchX ;
2679+ }
26712680 }
2672- }
26732681
2674- that . refreshCanvas ( ) ;
2675- }
2676- } ) ;
2682+ that . refreshCanvas ( ) ;
2683+ }
2684+ } ,
2685+ { passive : true }
2686+ ) ;
26772687
26782688 /**
26792689 * Handles touch end event on the canvas.
@@ -2946,8 +2956,12 @@ class Activity {
29462956 window . addEventListener ( "mousemove" , resetIdleTimer ) ;
29472957 window . addEventListener ( "mousedown" , resetIdleTimer ) ;
29482958 window . addEventListener ( "keydown" , resetIdleTimer ) ;
2949- window . addEventListener ( "touchstart" , resetIdleTimer ) ;
2950- window . addEventListener ( "wheel" , resetIdleTimer ) ;
2959+ window . addEventListener ( "touchstart" , resetIdleTimer , {
2960+ passive : true
2961+ } ) ;
2962+ window . addEventListener ( "wheel" , resetIdleTimer , {
2963+ passive : true
2964+ } ) ;
29512965
29522966 // Periodic check for idle state
29532967 setInterval ( ( ) => {
@@ -6865,15 +6879,16 @@ class Activity {
68656879
68666880 const img = new Image ( ) ;
68676881 img . src = "data:image/svg+xml;base64," + window . btoa ( base64Encode ( name ) ) ;
6882+ // Accessibility: derive alt text from the button label
6883+ const altText = label ? label . replace ( / \s * \[ .* \] $ / , "" ) : "Toolbar button" ;
6884+ img . setAttribute ( "alt" , altText ) ;
68686885
6886+ // Batch DOM reads before writes to avoid forced synchronous layout
6887+ const rightPos = document . body . clientWidth - x ;
68696888 container . appendChild ( img ) ;
68706889 container . setAttribute (
68716890 "style" ,
6872- "position: absolute; right:" +
6873- ( document . body . clientWidth - x ) +
6874- "px; top: " +
6875- y +
6876- "px;"
6891+ "position: absolute; right:" + rightPos + "px; top: " + y + "px;"
68776892 ) ;
68786893 document . getElementById ( "buttoncontainerBOTTOM" ) . appendChild ( container ) ;
68796894 return container ;
@@ -7291,14 +7306,17 @@ class Activity {
72917306 * Inits everything. The main function.
72927307 */
72937308 this . init = async ( ) => {
7309+ // Batch DOM reads before any writes to avoid forced synchronous layout
72947310 this . _clientWidth = document . body . clientWidth ;
72957311 this . _clientHeight = document . body . clientHeight ;
72967312 this . _innerWidth = window . innerWidth ;
72977313 this . _innerHeight = window . innerHeight ;
72987314 this . _outerWidth = window . outerWidth ;
72997315 this . _outerHeight = window . outerHeight ;
7316+ const loaderEl = document . getElementById ( "loader" ) ;
73007317
7301- document . getElementById ( "loader" ) . className = "loader" ;
7318+ // DOM write: apply class after all geometry reads
7319+ loaderEl . className = "loader" ;
73027320
73037321 /*
73047322 * Run browser check before implementing onblur -->
0 commit comments