2022-03-30 13:52:24 +08:00
// DO NOT IMPORT window.config HERE!
// to make sure the error handler always works, we should never import `window.config`, because some user's custom template breaks it.
// This sets up the URL prefix used in webpack's chunk loading.
// This file must be imported before any lazy-loading is being attempted.
2023-08-31 04:46:44 +02:00
_ _webpack _public _path _ _ = ` ${ window . config ? . assetUrlPrefix ? ? '/assets' } / ` ;
2022-03-30 13:52:24 +08:00
export function showGlobalErrorMessage ( msg ) {
const pageContent = document . querySelector ( '.page-content' ) ;
if ( ! pageContent ) return ;
2024-01-21 22:23:08 +08:00
// compact the message to a data attribute to avoid too many duplicated messages
const msgCompact = msg . replace ( /\W/g , '' ) . trim ( ) ;
let msgDiv = pageContent . querySelector ( ` .js-global-error[data-global-error-msg-compact=" ${ msgCompact } "] ` ) ;
if ( ! msgDiv ) {
const el = document . createElement ( 'div' ) ;
el . innerHTML = ` <div class="ui container negative message center aligned js-global-error" style="white-space: pre-line;"></div> ` ;
msgDiv = el . childNodes [ 0 ] ;
}
// merge duplicated messages into "the message (count)" format
const msgCount = Number ( msgDiv . getAttribute ( ` data-global-error-msg-count ` ) ) + 1 ;
msgDiv . setAttribute ( ` data-global-error-msg-compact ` , msgCompact ) ;
msgDiv . setAttribute ( ` data-global-error-msg-count ` , msgCount . toString ( ) ) ;
msgDiv . textContent = msg + ( msgCount > 1 ? ` ( ${ msgCount } ) ` : '' ) ;
pageContent . prepend ( msgDiv ) ;
2022-03-30 13:52:24 +08:00
}
/**
* @param {ErrorEvent} e
*/
function processWindowErrorEvent ( e ) {
2024-02-22 22:21:43 +01:00
const err = e . error ? ? e . reason ;
const assetBaseUrl = String ( new URL ( _ _webpack _public _path _ _ , window . location . origin ) ) ;
// error is likely from browser extension or inline script. Do not show these in production builds.
if ( ! err . stack ? . includes ( assetBaseUrl ) && window . config ? . runModeIsProd ) return ;
let message ;
2023-08-22 11:30:02 +09:00
if ( e . type === 'unhandledrejection' ) {
2024-02-22 22:21:43 +01:00
message = ` JavaScript promise rejection: ${ err . message } . ` ;
} else {
message = ` JavaScript error: ${ e . message } ( ${ e . filename } @ ${ e . lineno } : ${ e . colno } ). ` ;
2023-08-22 11:30:02 +09:00
}
2024-02-22 22:21:43 +01:00
2022-07-05 20:27:13 +08:00
if ( ! e . error && e . lineno === 0 && e . colno === 0 && e . filename === '' && window . navigator . userAgent . includes ( 'FxiOS/' ) ) {
// At the moment, Firefox (iOS) (10x) has an engine bug. See https://github.com/go-gitea/gitea/issues/20240
// If a script inserts a newly created (and content changed) element into DOM, there will be a nonsense error event reporting: Script error: line 0, col 0.
return ; // ignore such nonsense error event
}
2022-10-16 00:04:00 +02:00
2024-02-22 22:21:43 +01:00
showGlobalErrorMessage ( ` ${ message } Open browser console to see more details. ` ) ;
2022-03-30 13:52:24 +08:00
}
function initGlobalErrorHandler ( ) {
2023-08-22 11:30:02 +09:00
if ( window . _globalHandlerErrors ? . _inited ) {
showGlobalErrorMessage ( ` The global error handler has been initialized, do not initialize it again ` ) ;
return ;
}
2022-03-30 13:52:24 +08:00
if ( ! window . config ) {
showGlobalErrorMessage ( ` Gitea JavaScript code couldn't run correctly, please check your custom templates ` ) ;
}
// we added an event handler for window error at the very beginning of <script> of page head
// the handler calls `_globalHandlerErrors.push` (array method) to record all errors occur before this init
// then in this init, we can collect all error events and show them
for ( const e of window . _globalHandlerErrors || [ ] ) {
processWindowErrorEvent ( e ) ;
}
// then, change _globalHandlerErrors to an object with push method, to process further error events directly
2023-08-22 11:30:02 +09:00
window . _globalHandlerErrors = { _inited : true , push : ( e ) => processWindowErrorEvent ( e ) } ;
2022-03-30 13:52:24 +08:00
}
initGlobalErrorHandler ( ) ;