1- /*
2- * Global letiables
3- */
4- let _notifCounter = 0
5- const _delayUpdate = 60 * 1000
6- // Used by the popup
7- let _currentDom = null
8- let _contentDiv = null
9- // If the user is connected
10- let _connected = false
11- // If we want to see popup letiables
12- let _showNotification = false
1+ /* global chrome XMLHttpRequest:true */
2+ /* eslint-disable no-console */
3+ const debugMode = false
4+ const NOT_CONNECTED = 401
5+ const CONNECTED = 200
6+
7+ // TODO move this
8+ var connected = false
9+ var notifCounter = 0
10+ var currentDom = null
11+ let contentDiv = null
12+
13+ // Load preferences
14+ const updateDelay = 60 * 1000
15+ let showPopupNotification = false
1316chrome . storage . local . get ( 'notify' , ( res ) => {
14- _showNotification = res . notify || false
17+ showPopupNotification = res . notify || false
1518} )
16- // If we are in debug mode
17- const _debug = true
18- let baseUrl = 'https://zestedesavoir.com/'
19- const _token = 'zds-notifier'
20- if ( _debug ) baseUrl = 'https://beta.zestedesavoir.com/'
2119
22- function escapeHTML ( str ) { return str . replace ( / [ & ' ' < > ] / g, ( m ) => escapeHTML . replacements [ m ] ) }
23- escapeHTML . replacements = { '&' : '&' , '\'' : '"' , '"' : ''' , '<' : '<' , '>' : '>' }
20+ let baseUrl = 'https://zestedesavoir.com/'
21+ if ( debugMode ) baseUrl = 'https://beta.zestedesavoir.com/'
22+ const token = 'zds-notifier'
2423
2524/**
26- * getNotificationsFromAPI
27- */
25+ * Get notifications from https://zestedesavoir.com via the API
26+ */
2827function getNotificationsFromAPI ( ) {
29- _contentDiv = document . createElement ( 'div' )
30- const target = baseUrl + 'api/notifications/?page_size=30&ordering=-pubdate&Authorization=' + _token
28+ contentDiv = document . createElement ( 'div' )
29+ const options = `page_size=30&ordering=-pubdate&Authorization=${ token } `
30+ const target = `${ baseUrl } api/notifications/?${ options } `
31+ // TODO use fetch instead
3132 const xhr = new XMLHttpRequest ( )
3233 xhr . open ( 'GET' , target , true )
3334 xhr . onload = function ( e ) {
3435 if ( xhr . readyState === 4 ) {
3536 const result = xhr . status
36- if ( result === 401 ) {
37- _connected = false
38- if ( _debug ) console . log ( 'Not connected' )
39- // Change popup image
40- chrome . browserAction . setIcon ( { path :'icons/notconnected.png' } )
41- } else if ( result === 200 ) {
42- _connected = true
37+ if ( result === NOT_CONNECTED ) {
38+ connected = false
39+ if ( debugMode ) console . log ( 'Not connected' )
40+ chrome . browserAction . setIcon ( { path : 'icons/notconnected.png' } )
41+ } else if ( result === CONNECTED ) {
42+ connected = true
4343 const rootDOM = JSON . parse ( xhr . response )
4444 if ( rootDOM . details ) {
45- if ( _debug ) console . log ( 'Error while parsing ' )
45+ if ( debugMode ) console . log ( 'can\'t parse incorrect JSON ' )
4646 } else {
47- // Get new notifications
48- const resultsNotification = rootDOM . results
49- let countNotifications = 0
50- for ( let notif = 0 ; notif < resultsNotification . length ; ++ notif ) {
51- // If a notification is new we have is_read === False
52- if ( ! resultsNotification [ notif ] . is_read ) {
53- countNotifications += 1
54- const titleNotif = resultsNotification [ notif ] . title
55- const senderNotif = resultsNotification [ notif ] . sender . username
56- const senderAvatarNotif = resultsNotification [ notif ] . sender . avatar_url
57- const dateNotif = resultsNotification [ notif ] . pubdate
58- const date = new Date ( ( dateNotif || '' ) . replace ( / - / g, '/' ) . replace ( / [ T Z ] / g, ' ' ) )
59- let minutes = `${ date . getMinutes ( ) } `
60- if ( minutes . length < 2 ) {
61- minutes = `0${ minutes } `
62- }
63- let formatedDate = `le ${ [ date . getDate ( ) ,
64- date . getMonth ( ) + 1 ] . join ( '/' ) } à ${ [ date . getHours ( ) ,
65- minutes ] . join ( 'h' ) } `
66- const actualDate = new Date ( )
67- if ( date . getDate ( ) === actualDate . getDate ( ) &&
68- date . getMonth ( ) === actualDate . getMonth ( ) &&
69- date . getYear ( ) === actualDate . getYear ( ) ) {
70- formatedDate = 'Aujourd\'hui'
71- } else {
72- const yesterday = actualDate
73- yesterday . setDate ( actualDate . getDate ( ) - 1 )
74- if ( date . getDate ( ) === yesterday . getDate ( ) &&
75- date . getMonth ( ) === yesterday . getMonth ( ) &&
76- date . getYear ( ) === yesterday . getYear ( ) ) {
77- formatedDate = 'Hier'
78- }
79- }
80- const urlNotif = `https://zestedesavoir.com${ resultsNotification [ notif ] . url } `
81- if ( _debug ) console . log ( `${ urlNotif } by ${ senderNotif } ` )
82- addNotification ( titleNotif , senderNotif , senderAvatarNotif , formatedDate , urlNotif )
83- }
84- }
85- // Notify the user
86- if ( countNotifications > _notifCounter ) {
87- if ( _debug ) console . log ( `Nouvelles notifications : ${ countNotifications } ` )
88- chrome . browserAction . setIcon ( { path : 'icons/icone_n_20.png' } )
89- const title = 'Zds-notificateur : Nouvelle notification !'
90- let content = `Vous avez ${ countNotifications } notification`
91- if ( countNotifications > 1 ) content += 's'
92- notifyMe ( title , content )
93- } else if ( countNotifications === 0 ) {
94- chrome . browserAction . setIcon ( { path : 'icons/clem_48.png' } )
95- }
96- _notifCounter = countNotifications
47+ parseNotifications ( rootDOM . results )
9748 }
98- } else if ( _debug ) {
49+ } else if ( debugMode ) {
9950 console . log ( result )
10051 }
10152 }
10253
103-
104- if ( ! _notifCounter ) {
105- const divNoNotif = document . createElement ( 'div' )
106- divNoNotif . id = 'noNotif'
107- divNoNotif . innerHTML = 'Aucune notification'
108- _contentDiv . appendChild ( divNoNotif )
109- if ( _debug ) console . log ( 'Aucune notification' )
110- }
111- const body = document . body
112- body . appendChild ( _contentDiv )
113- // Remove useless nodes
114- while ( body . childNodes . length > 2 ) {
115- body . removeChild ( body . childNodes [ 1 ] )
116- }
117- _currentDom = body
54+ buildPopup ( )
11855 }
11956
12057 xhr . onerror = function ( e ) {
12158 console . error ( xhr . statusText )
122- _connected = false
59+ connected = false
12360 }
12461 xhr . send ( null )
12562}
12663
127- /*
128- * Add a notification to the DOM
129- */
130- function addNotification ( title , sender , senderAvatar , date , url ) {
131- // Design popup
132- const a = document . createElement ( 'a' )
133- a . href = url
134- a . target = '_blank'
135- const divNotif = document . createElement ( 'div' )
136- divNotif . id = 'notification'
137- const imgAvatar = document . createElement ( 'img' )
138- imgAvatar . src = senderAvatar
64+ /**
65+ * Build the DOM of the popup
66+ */
67+ function buildPopup ( ) {
68+ if ( ! notifCounter ) {
69+ const divNoNotif = document . createElement ( 'div' )
70+ divNoNotif . id = 'noNotif'
71+ divNoNotif . innerText = 'Aucune notification'
72+ contentDiv . appendChild ( divNoNotif )
73+ if ( debugMode ) console . log ( divNoNotif . innerText )
74+ }
75+ const body = document . body
76+ body . appendChild ( contentDiv )
77+ // Remove useless nodes
78+ while ( body . childNodes . length > 2 ) {
79+ body . removeChild ( body . childNodes [ 1 ] )
80+ }
81+ currentDom = body
82+ }
83+
84+ /**
85+ * Parse the JSON returned by the API
86+ * @param results the JSON object
87+ */
88+ function parseNotifications ( results ) {
89+ // Get new notifications
90+ let notificationsCounter = 0
91+ for ( const notif of results ) {
92+ // If a notification is new we have is_read === False
93+ if ( ! notif . is_read ) {
94+ notificationsCounter += 1
95+ const title = notif . title
96+ const author = notif . sender . username
97+ const authorAvatar = notif . sender . avatar_url
98+
99+ const urlNotif = `${ baseUrl } ${ notif . url } `
100+ if ( debugMode ) console . log ( `${ urlNotif } by ${ author } ` )
101+ addNotification ( title , author , authorAvatar , formatDate ( notif . pubdate ) , urlNotif )
102+ }
103+ }
104+ // Notify the user
105+ if ( notificationsCounter > notifCounter ) {
106+ if ( debugMode ) console . log ( `New notification: ${ notificationsCounter } ` )
107+ chrome . browserAction . setIcon ( { path : 'icons/icone_n_20.png' } )
108+ const title = 'Zds-notificateur : Nouvelle notification !'
109+ let content = `Vous avez ${ notificationsCounter } notification`
110+ if ( notificationsCounter > 1 ) content += 's'
111+ popupNotification ( title , content )
112+ } else if ( notificationsCounter === 0 ) {
113+ chrome . browserAction . setIcon ( { path : 'icons/clem_48.png' } )
114+ }
115+ notifCounter = notificationsCounter
116+ }
117+
118+ /**
119+ * Pretty print a publication date
120+ * @param pubdate
121+ */
122+ function formatDate ( pubdate ) {
123+ const date = new Date ( ( pubdate || '' ) . replace ( / - / g, '/' ) . replace ( / [ T Z ] / g, ' ' ) )
124+
125+ const actualDate = new Date ( )
126+ if ( date . toDateString ( ) === actualDate . toDateString ( ) ) {
127+ return 'Aujourd\'hui'
128+ }
129+
130+ const yesterday = actualDate
131+ yesterday . setDate ( actualDate . getDate ( ) - 1 )
132+ if ( date . toDateString ( ) === yesterday . toDateString ( ) ) {
133+ return 'Hier'
134+ }
135+
136+ let minutes = `${ date . getMinutes ( ) } `
137+ if ( minutes . length < 2 ) {
138+ minutes = `0${ minutes } `
139+ }
140+ const shortDate = [ date . getDate ( ) , date . getMonth ( ) + 1 ] . join ( '/' )
141+ const time = [ date . getHours ( ) , minutes ] . join ( 'h' )
142+ return `le ${ shortDate } à ${ time } `
143+ }
144+
145+ /**
146+ * Add a notification entry
147+ * @param title of the subject
148+ * @param author
149+ * @param authorAvatar
150+ * @param date
151+ * @param url
152+ */
153+ function addNotification ( title , author , authorAvatar , date , url ) {
139154 const divBlocNotif = document . createElement ( 'div' )
140155 divBlocNotif . id = 'blocNotif'
141156 const divDate = document . createElement ( 'div' )
142157 divDate . id = 'date'
143- divDate . innerHTML = escapeHTML ( date )
158+ divDate . innerText = date
144159 const divPseudo = document . createElement ( 'div' )
145160 divPseudo . id = 'pseudo'
146- divPseudo . innerHTML = escapeHTML ( sender )
161+ divPseudo . innerText = author
147162 const divTitle = document . createElement ( 'div' )
148163 divTitle . id = 'title'
149- divTitle . innerHTML = escapeHTML ( title )
164+ divTitle . innerText = title
165+ const imgAvatar = document . createElement ( 'img' )
166+ imgAvatar . src = authorAvatar
167+ const divNotif = document . createElement ( 'div' )
168+ divNotif . id = 'notification'
169+ const a = document . createElement ( 'a' )
170+ a . href = url
171+ a . target = '_blank' // Open the notification in a new window
150172
151173 divBlocNotif . appendChild ( divDate )
152174 divBlocNotif . appendChild ( divPseudo )
153175 divBlocNotif . appendChild ( divTitle )
154176 divNotif . appendChild ( imgAvatar )
155177 divNotif . appendChild ( divBlocNotif )
156178 a . appendChild ( divNotif )
157- _contentDiv . appendChild ( a )
179+ contentDiv . appendChild ( a )
158180}
159181
160- /*
161- * Create a notification
162- */
163- function notifyMe ( title , content ) {
164- if ( _showNotification ) {
182+ /**
183+ * Show a popup notification
184+ * @param title of the popup
185+ * @param content
186+ */
187+ function popupNotification ( title , content ) {
188+ if ( showPopupNotification ) {
165189 chrome . notifications . create ( {
166190 'type' : 'basic' ,
167191 'iconUrl' : chrome . extension . getURL ( 'icons/icone_n_20.png' ) ,
@@ -172,5 +196,5 @@ function notifyMe (title, content) {
172196}
173197
174198// Update the popup
175- setInterval ( getNotificationsFromAPI , _delayUpdate )
199+ setInterval ( getNotificationsFromAPI , updateDelay )
176200getNotificationsFromAPI ( )
0 commit comments