11/* list of default strings to remove */
22let defaultStrings = [
3- "Foundry Virtual Tabletop requires a minimum screen resolution " ,
3+ "Foundry Virtual Tabletop requires" ,
44 "not displayed because the game Canvas is disabled" ,
55 "is unmaintained and may introduce stability issues"
66] ;
77
88let removeStrings = [ ]
99
10+ // CONFIG.debug.hooks = true
11+
1012const W_R_ID = 'warning-remove' ;
1113
12- Hooks . on ( 'ready ' , ( ) => {
14+ Hooks . on ( 'init ' , ( ) => {
1315 game . settings . register ( W_R_ID , 'qty' , {
1416 name : 'Number of messages to remove' ,
1517 hint : 'default: 3' ,
@@ -93,60 +95,59 @@ Hooks.on('ready', () => {
9395 *
9496 * This function should be run during the "ready" Hook call.
9597 */
96- function InitNotificationsProxy ( patternsToHide = [ ] ) {
97- // Do nothing if no patterns are provided.
98- if ( ! patternsToHide . length ) { return ; }
99-
100- // Get the original array of queued notifications, and store a constant reference to it
101- const notificationQueue = ui . notifications . queue ;
102-
103- // Convert the provided patterns into regular expressions
104- const regExpPatterns = patternsToHide . map ( ( pattern ) => new RegExp ( pattern ) ) ;
105-
106- // Define a handler for the proxy that will be used to intercept notifications
107- const handler = {
108- set : function ( target , property , value ) {
109- // Handle changes to the array length property
110- if ( property === "length" ) {
111- // Perform the default behavior for length changes
112- target . length = value ;
113- return true ; // Indicate success
114- }
115- // Handle directly setting the value for non-index properties (necessary for array methods like 'next')
116- else if ( typeof property === "string" && isNaN ( Number ( property ) ) ) {
117- // Perform the default behavior for non-index properties.
118- target [ property ] = value ;
119- return true ; // Indicate success
120- }
121- // Handle setting array indices
122- else if ( ! isNaN ( Number ( property ) ) ) {
123- // If the value is a notification and its content matches one of the provided patterns ...
124- if ( value
125- && typeof value === "object"
126- && "message" in value
127- && typeof value . message === "string"
128- && regExpPatterns . some ( ( pattern ) => pattern . exec ( value . message ) ) ) {
129- // ... edit the notification to:
130- Object . assign ( value , {
131- console : false , // ... prevent logging it to the console
132- permanent : false , // ... ensure the notification element is removed automatically
133- type : "do-not-display" // ... 'hack' the type to add the 'do-not-display' class
134- } ) ;
98+ Hooks . once ( "canvasReady" , ( ) => {
99+ if ( ! ui . notifications ) {
100+ console . error ( "ui.notifications is not initialized. Skipping notification interception." ) ;
101+ return ;
102+ }
103+
104+ // List of patterns to block
105+ const patternsToBlock = removeStrings ;
106+
107+ console . log ( "Patterns to block:" , removeStrings ) ;
108+
109+ // Convert patterns to regular expressions
110+ const regExpPatterns = patternsToBlock . map ( pattern => new RegExp ( pattern , "i" ) ) ;
111+
112+ // Save the original notify method
113+ const originalNotify = ui . notifications . notify ;
114+
115+ // Override the notify method
116+ ui . notifications . notify = function ( message , type = "info" , opts = { } ) {
117+ // Shallow-copy options so we don't mutate the caller's object
118+ const options = foundry . utils . mergeObject ( { localize : false , escape : true , clean : true , format : null } , opts , { inplace : false } ) ;
119+
120+ // 1) Normalize to string (or Error.message)
121+ let text = message instanceof Error ? message . message : String ( message ) ;
122+
123+ // 2) Apply formatting placeholders if present
124+ if ( options . format ) {
125+ if ( options . escape ) {
126+ for ( let k of Object . keys ( options . format ) ) {
127+ options . format [ k ] = foundry . utils . escapeHTML ( options . format [ k ] ) ;
135128 }
136- // Otherwise, perform the default behavior for setting index properties.
137- target [ Number ( property ) ] = value ;
138- return true ; // Indicate success
129+ // If it’s a real localization key, no extra cleaning
130+ if ( game . i18n . has ( text ) ) options . clean = false ;
139131 }
140- return false ; // Indicate failure for all other cases
132+ text = game . i18n . format ( text , options . format ) ;
133+ }
134+ // 3) Otherwise localize if requested
135+ else if ( options . localize ) {
136+ if ( game . i18n . has ( text ) ) options . clean = false ;
137+ text = game . i18n . localize ( text ) ;
141138 }
139+ // 4) Finally clean HTML if still flagged
140+ if ( options . clean ) text = foundry . utils . cleanHTML ( text ) ;
141+
142+ // Check if the message matches any of the patterns
143+ if ( regExpPatterns . some ( pattern => pattern . test ( text ) ) ) {
144+ console . warn ( `Blocked notification [${ type } ]: ${ text } ` ) ;
145+ return ; // Prevent the notification from being displayed
146+ }
147+
148+ // Call the original notify method for non-blocked messages
149+ return originalNotify . call ( this , message , type , options ) ;
142150 } ;
143151
144- // Replace the notifications queue array with a Proxy defined by the above handler.
145- ui . notifications . queue = new Proxy ( notificationQueue , handler ) ;
146- }
147- // Initialize the notifications proxy during the 'ready' hook, after ui.notifications has been defined
148- Hooks . once ( "ready" , ( ) => {
149- // I've hard-coded the two notifications I want to hide, but this could easily be a
150- // user setting, allowing users to customize which notifications are silenced.
151- InitNotificationsProxy ( removeStrings ) ;
152+ console . log ( "Notification interception initialized." ) ;
152153} ) ;
0 commit comments