logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://hacktivis.me/git/pleroma-fe.git

sw.js (4557B)


  1. /* eslint-env serviceworker */
  2. import localForage from 'localforage'
  3. import { parseNotification } from './services/entity_normalizer/entity_normalizer.service.js'
  4. import { prepareNotificationObject } from './services/notification_utils/notification_utils.js'
  5. import { createI18n } from 'vue-i18n'
  6. import messages from './i18n/service_worker_messages.js'
  7. const i18n = createI18n({
  8. // By default, use the browser locale, we will update it if neccessary
  9. locale: 'en',
  10. fallbackLocale: 'en',
  11. messages
  12. })
  13. const state = {
  14. lastFocused: null,
  15. notificationIds: new Set(),
  16. allowedNotificationTypes: null
  17. }
  18. function getWindowClients () {
  19. return clients.matchAll({ includeUncontrolled: true })
  20. .then((clientList) => clientList.filter(({ type }) => type === 'window'))
  21. }
  22. const setSettings = async () => {
  23. const vuexState = await localForage.getItem('vuex-lz')
  24. const locale = vuexState.config.interfaceLanguage || 'en'
  25. i18n.locale = locale
  26. const notificationsNativeArray = Object.entries(vuexState.config.notificationNative)
  27. state.webPushAlwaysShowNotifications = vuexState.config.webPushAlwaysShowNotifications
  28. state.allowedNotificationTypes = new Set(
  29. notificationsNativeArray
  30. .filter(([k, v]) => v)
  31. .map(([k]) => {
  32. switch (k) {
  33. case 'mentions':
  34. return 'mention'
  35. case 'statuses':
  36. return 'status'
  37. case 'likes':
  38. return 'like'
  39. case 'repeats':
  40. return 'repeat'
  41. case 'emojiReactions':
  42. return 'pleroma:emoji_reaction'
  43. case 'reports':
  44. return 'pleroma:report'
  45. case 'followRequest':
  46. return 'follow_request'
  47. case 'follows':
  48. return 'follow'
  49. case 'polls':
  50. return 'poll'
  51. default:
  52. return k
  53. }
  54. })
  55. )
  56. }
  57. const showPushNotification = async (event) => {
  58. const activeClients = await getWindowClients()
  59. await setSettings()
  60. // Only show push notifications if all tabs/windows are closed
  61. if (state.webPushAlwaysShowNotifications || activeClients.length === 0) {
  62. const data = event.data.json()
  63. const url = `${self.registration.scope}api/v1/notifications/${data.notification_id}`
  64. const notification = await fetch(url, { headers: { Authorization: 'Bearer ' + data.access_token } })
  65. const notificationJson = await notification.json()
  66. const parsedNotification = parseNotification(notificationJson)
  67. const res = prepareNotificationObject(parsedNotification, i18n)
  68. if (state.webPushAlwaysShowNotifications || state.allowedNotificationTypes.has(parsedNotification.type)) {
  69. return self.registration.showNotification(res.title, res)
  70. }
  71. }
  72. return Promise.resolve()
  73. }
  74. self.addEventListener('push', async (event) => {
  75. if (event.data) {
  76. // Supposedly, we HAVE to return a promise inside waitUntil otherwise it will
  77. // show (extra) notification that website is updated in background
  78. event.waitUntil(showPushNotification(event))
  79. }
  80. })
  81. self.addEventListener('message', async (event) => {
  82. await setSettings()
  83. const { type, content } = event.data
  84. if (type === 'desktopNotification') {
  85. const { title, ...rest } = content
  86. const { tag, type } = rest
  87. if (state.notificationIds.has(tag)) return
  88. state.notificationIds.add(tag)
  89. setTimeout(() => state.notificationIds.delete(tag), 10000)
  90. if (state.allowedNotificationTypes.has(type)) {
  91. self.registration.showNotification(title, rest)
  92. }
  93. }
  94. if (type === 'desktopNotificationClose') {
  95. const { id, all } = content
  96. const search = all ? null : { tag: id }
  97. const notifications = await self.registration.getNotifications(search)
  98. notifications.forEach(n => n.close())
  99. }
  100. if (type === 'updateFocus') {
  101. state.lastFocused = event.source.id
  102. const notifications = await self.registration.getNotifications()
  103. notifications.forEach(n => n.close())
  104. }
  105. })
  106. self.addEventListener('notificationclick', (event) => {
  107. event.notification.close()
  108. event.waitUntil(getWindowClients().then((list) => {
  109. for (let i = 0; i < list.length; i++) {
  110. const client = list[i]
  111. client.postMessage({ type: 'notificationClicked', id: event.notification.tag })
  112. }
  113. for (let i = 0; i < list.length; i++) {
  114. const client = list[i]
  115. if (state.lastFocused === null || client.id === state.lastFocused) {
  116. if ('focus' in client) return client.focus()
  117. }
  118. }
  119. if (clients.openWindow) return clients.openWindow('/')
  120. }))
  121. })