2022-01-29 00:00:11 +03:00
import $ from 'jquery' ;
2024-03-16 04:56:17 +03:00
import { GET } from '../modules/fetch.js' ;
2020-04-24 06:57:38 +03:00
2024-03-16 04:56:17 +03:00
const { appSubUrl , notificationSettings , assetVersionEncoded } = window . config ;
2021-07-17 19:18:10 +03:00
let notificationSequenceNumber = 0 ;
2020-04-24 06:57:38 +03:00
export function initNotificationsTable ( ) {
2023-05-25 05:31:26 +03:00
const table = document . getElementById ( 'notification_table' ) ;
if ( ! table ) return ;
// when page restores from bfcache, delete previously clicked items
window . addEventListener ( 'pageshow' , ( e ) => {
if ( e . persisted ) { // page was restored from bfcache
const table = document . getElementById ( 'notification_table' ) ;
const unreadCountEl = document . querySelector ( '.notifications-unread-count' ) ;
let unreadCount = parseInt ( unreadCountEl . textContent ) ;
for ( const item of table . querySelectorAll ( '.notifications-item[data-remove="true"]' ) ) {
item . remove ( ) ;
unreadCount -= 1 ;
}
unreadCountEl . textContent = unreadCount ;
}
} ) ;
// mark clicked unread links for deletion on bfcache restore
for ( const link of table . querySelectorAll ( '.notifications-item[data-status="1"] .notifications-link' ) ) {
link . addEventListener ( 'click' , ( e ) => {
e . target . closest ( '.notifications-item' ) . setAttribute ( 'data-remove' , 'true' ) ;
} ) ;
}
2020-04-24 06:57:38 +03:00
}
2020-07-03 12:55:36 +03:00
async function receiveUpdateCount ( event ) {
try {
const data = JSON . parse ( event . data ) ;
2022-08-03 22:58:27 +03:00
for ( const count of document . querySelectorAll ( '.notification_count' ) ) {
2023-02-13 20:59:59 +03:00
count . classList . toggle ( 'gt-hidden' , data . Count === 0 ) ;
2022-08-03 22:58:27 +03:00
count . textContent = ` ${ data . Count } ` ;
2020-07-03 12:55:36 +03:00
}
await updateNotificationTable ( ) ;
} catch ( error ) {
console . error ( error , event ) ;
}
}
2021-11-09 12:27:25 +03:00
export function initNotificationCount ( ) {
2024-03-16 15:22:16 +03:00
const $notificationCount = $ ( '.notification_count' ) ;
2020-05-08 00:49:00 +03:00
2024-03-16 15:22:16 +03:00
if ( ! $notificationCount . length ) {
2020-04-24 06:57:38 +03:00
return ;
}
2022-08-03 22:58:27 +03:00
let usingPeriodicPoller = false ;
const startPeriodicPoller = ( timeout , lastCount ) => {
if ( timeout <= 0 || ! Number . isFinite ( timeout ) ) return ;
usingPeriodicPoller = true ;
2024-03-16 15:22:16 +03:00
lastCount = lastCount ? ? $notificationCount . text ( ) ;
2022-08-03 22:58:27 +03:00
setTimeout ( async ( ) => {
await updateNotificationCountWithCallback ( startPeriodicPoller , timeout , lastCount ) ;
} , timeout ) ;
} ;
if ( notificationSettings . EventSourceUpdateTime > 0 && window . EventSource && window . SharedWorker ) {
2020-07-03 12:55:36 +03:00
// Try to connect to the event source via the shared worker first
2022-08-23 15:58:04 +03:00
const worker = new SharedWorker ( ` ${ _ _webpack _public _path _ _ } js/eventsource.sharedworker.js?v= ${ assetVersionEncoded } ` , 'notification-worker' ) ;
2020-12-27 17:24:27 +03:00
worker . addEventListener ( 'error' , ( event ) => {
2022-08-03 22:58:27 +03:00
console . error ( 'worker error' , event ) ;
2020-12-27 17:24:27 +03:00
} ) ;
2021-08-17 08:32:48 +03:00
worker . port . addEventListener ( 'messageerror' , ( ) => {
2022-08-03 22:58:27 +03:00
console . error ( 'unable to deserialize message' ) ;
2021-08-17 08:32:48 +03:00
} ) ;
2020-12-27 17:24:27 +03:00
worker . port . postMessage ( {
type : 'start' ,
2021-10-21 10:37:43 +03:00
url : ` ${ window . location . origin } ${ appSubUrl } /user/events ` ,
2020-12-27 17:24:27 +03:00
} ) ;
worker . port . addEventListener ( 'message' , ( event ) => {
if ( ! event . data || ! event . data . type ) {
2022-08-03 22:58:27 +03:00
console . error ( 'unknown worker message event' , event ) ;
2020-12-27 17:24:27 +03:00
return ;
}
if ( event . data . type === 'notification-count' ) {
2021-11-09 12:27:25 +03:00
const _promise = receiveUpdateCount ( event . data ) ;
2022-08-03 22:58:27 +03:00
} else if ( event . data . type === 'no-event-source' ) {
// browser doesn't support EventSource, falling back to periodic poller
if ( ! usingPeriodicPoller ) startPeriodicPoller ( notificationSettings . MinTimeout ) ;
2020-12-27 17:24:27 +03:00
} else if ( event . data . type === 'error' ) {
2022-08-03 22:58:27 +03:00
console . error ( 'worker port event error' , event . data ) ;
2020-12-27 17:24:27 +03:00
} else if ( event . data . type === 'logout' ) {
2021-04-08 02:48:13 +03:00
if ( event . data . data !== 'here' ) {
2020-07-03 12:55:36 +03:00
return ;
}
worker . port . postMessage ( {
type : 'close' ,
} ) ;
worker . port . close ( ) ;
2024-03-02 15:02:34 +03:00
window . location . href = ` ${ appSubUrl } / ` ;
2021-04-05 00:37:50 +03:00
} else if ( event . data . type === 'close' ) {
worker . port . postMessage ( {
type : 'close' ,
} ) ;
worker . port . close ( ) ;
2020-12-27 17:24:27 +03:00
}
} ) ;
worker . port . addEventListener ( 'error' , ( e ) => {
2022-08-03 22:58:27 +03:00
console . error ( 'worker port error' , e ) ;
2020-12-27 17:24:27 +03:00
} ) ;
worker . port . start ( ) ;
window . addEventListener ( 'beforeunload' , ( ) => {
worker . port . postMessage ( {
type : 'close' ,
2020-07-03 12:55:36 +03:00
} ) ;
2020-12-27 17:24:27 +03:00
worker . port . close ( ) ;
} ) ;
2020-04-24 06:57:38 +03:00
2020-12-27 17:24:27 +03:00
return ;
2020-04-24 06:57:38 +03:00
}
2020-05-08 00:49:00 +03:00
2022-08-03 22:58:27 +03:00
startPeriodicPoller ( notificationSettings . MinTimeout ) ;
2020-04-24 06:57:38 +03:00
}
async function updateNotificationCountWithCallback ( callback , timeout , lastCount ) {
const currentCount = $ ( '.notification_count' ) . text ( ) ;
if ( lastCount !== currentCount ) {
2021-10-21 10:37:43 +03:00
callback ( notificationSettings . MinTimeout , currentCount ) ;
2020-04-24 06:57:38 +03:00
return ;
}
const newCount = await updateNotificationCount ( ) ;
let needsUpdate = false ;
if ( lastCount !== newCount ) {
needsUpdate = true ;
2021-10-21 10:37:43 +03:00
timeout = notificationSettings . MinTimeout ;
} else if ( timeout < notificationSettings . MaxTimeout ) {
timeout += notificationSettings . TimeoutStep ;
2020-04-24 06:57:38 +03:00
}
callback ( timeout , newCount ) ;
2020-05-08 00:49:00 +03:00
if ( needsUpdate ) {
await updateNotificationTable ( ) ;
}
}
2020-04-24 06:57:38 +03:00
2020-05-08 00:49:00 +03:00
async function updateNotificationTable ( ) {
2024-03-16 16:25:27 +03:00
const notificationDiv = document . getElementById ( 'notification_div' ) ;
if ( notificationDiv ) {
2024-03-16 04:56:17 +03:00
try {
const params = new URLSearchParams ( window . location . search ) ;
params . set ( 'div-only' , true ) ;
params . set ( 'sequence-number' , ++ notificationSequenceNumber ) ;
const url = ` ${ appSubUrl } /notifications? ${ params . toString ( ) } ` ;
const response = await GET ( url ) ;
if ( ! response . ok ) {
throw new Error ( 'Failed to fetch notification table' ) ;
2020-04-24 06:57:38 +03:00
}
2024-03-16 04:56:17 +03:00
const data = await response . text ( ) ;
if ( $ ( data ) . data ( 'sequence-number' ) === notificationSequenceNumber ) {
2024-03-16 16:25:27 +03:00
notificationDiv . outerHTML = data ;
2024-03-16 04:56:17 +03:00
initNotificationsTable ( ) ;
}
} catch ( error ) {
console . error ( error ) ;
2021-07-17 19:18:10 +03:00
}
2020-04-24 06:57:38 +03:00
}
}
async function updateNotificationCount ( ) {
2024-03-16 04:56:17 +03:00
try {
const response = await GET ( ` ${ appSubUrl } /notifications/new ` ) ;
2020-04-24 06:57:38 +03:00
2024-03-16 04:56:17 +03:00
if ( ! response . ok ) {
throw new Error ( 'Failed to fetch notification count' ) ;
}
2020-04-24 06:57:38 +03:00
2024-03-16 04:56:17 +03:00
const data = await response . json ( ) ;
2020-04-24 06:57:38 +03:00
2024-03-16 15:22:16 +03:00
const $notificationCount = $ ( '.notification_count' ) ;
2024-03-16 04:56:17 +03:00
if ( data . new === 0 ) {
2024-03-16 15:22:16 +03:00
$notificationCount . addClass ( 'gt-hidden' ) ;
2024-03-16 04:56:17 +03:00
} else {
2024-03-16 15:22:16 +03:00
$notificationCount . removeClass ( 'gt-hidden' ) ;
2024-03-16 04:56:17 +03:00
}
2020-04-24 06:57:38 +03:00
2024-03-16 15:22:16 +03:00
$notificationCount . text ( ` ${ data . new } ` ) ;
2020-04-24 06:57:38 +03:00
2024-03-16 04:56:17 +03:00
return ` ${ data . new } ` ;
} catch ( error ) {
console . error ( error ) ;
return '0' ;
}
2020-04-24 06:57:38 +03:00
}