Created
July 30, 2016 11:24
-
-
Save magemore/15437254dc99179876b8307d4b99cb6c to your computer and use it in GitHub Desktop.
kinda pretty but still cryptic
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
((t, n, r) -> | |
i = typeof require == 'function' and require | |
s = (o, u) -> | |
if !n[o] | |
if !t[o] | |
a = typeof require == 'function' and require | |
if !u and a | |
return a(o, !0) | |
if i | |
return i(o, !0) | |
f = new Error('Cannot find module \'' + o + '\'') | |
throw f.code = 'MODULE_NOT_FOUND' | |
f | |
l = n[o] = exports: {} | |
t[o][0].call l.exports, ((e) -> | |
`var n` | |
n = t[o][1][e] | |
s if n then n else e | |
), l, l.exports, e, t, n, r | |
n[o].exports | |
o = 0 | |
while o < r.length | |
s r[o] | |
o++ | |
s | |
) { | |
1: [ | |
(require, module, exports) -> | |
# no_unit_test | |
module.exports = | |
visible: (client) -> | |
client.visibilityState == 'visible' | |
topLevel: (client) -> | |
client.frameType == 'top-level' | |
focused: (client) -> | |
client.focused | |
urlEndsWith: (endsWith) -> | |
(client) -> | |
client.url.endsWith endsWith | |
return | |
{} | |
] | |
2: [ | |
(require, module, exports) -> | |
clientFilters = require('app/workers/client_filters') | |
utils = require('app/workers/utils') | |
# Focus and trigger an event on client if available | |
# Otherwise, open the URL provided by the notification | |
dmNotificationClickHandler = (data) -> | |
utils.getClients().then (clientList) -> | |
activeClient = clientList[0] | |
if activeClient and activeClient.focus | |
activeClient.focus() | |
utils.triggerOnClient activeClient, 'uiDMNotificationClicked', data.notificationData | |
Promise.resolve() | |
else | |
utils.openURL data.url or '/' | |
defaultNotificationClickHandler = (data) -> | |
endsWithFilter = clientFilters.urlEndsWith(data.url) | |
utils.getClients([ endsWithFilter ]).then (clientList) -> | |
client = clientList[0] | |
Promise.resolve if client and client.focus then client.focus() else utils.openURL(data.url) | |
notificationClickHandlers = | |
'dm': dmNotificationClickHandler | |
'default': defaultNotificationClickHandler | |
module.exports = notificationClickHandlers | |
return | |
{ | |
'app/workers/client_filters': 1 | |
'app/workers/utils': 7 | |
} | |
] | |
3: [ | |
(require, module, exports) -> | |
utils = require('app/workers/utils') | |
dmNotificationDisplayHandler = (notification, visibleClient) -> | |
utils.triggerOnClient visibleClient, 'dataDMPushReceived', notification.data.notificationData | |
return | |
# Suppress error notification if there's a visible client | |
errorNotificationHandler = -> | |
return | |
notificationDisplayHandlers = | |
'dm': dmNotificationDisplayHandler | |
'error': errorNotificationHandler | |
'default': utils.displayNotification | |
module.exports = notificationDisplayHandlers | |
return | |
{ 'app/workers/utils': 7 } | |
] | |
4: [ | |
(require, module, exports) -> | |
### | |
# To bundle service worker file, run `npm run build:service-worker` in `web-resources` directory | |
### | |
utils = require('app/workers/utils') | |
clientFilters = require('app/workers/client_filters') | |
notificationClickHandlers = require('app/workers/notification_click_handlers') | |
notificationDisplayHandlers = require('app/workers/notification_display_handlers') | |
scribeHelper = require('app/workers/scribe') | |
NOTIFICATIONS_ENDPOINT = '/i/push_notifications' | |
WORKER_API_VERSION = 1 | |
DB = undefined | |
PushServiceWorker = -> | |
@scribe = scribeHelper | |
### | |
# | |
# Logic for fetching the JSON notifications from the endpoint | |
# dealing with the response and displaying the notifications | |
# | |
### | |
@displayNotifications = (notifications) -> | |
if !notifications | |
return Promise.resolve() | |
Promise.all notifications.map(((notification) -> | |
@scribe { | |
element: if notification.data and notification.data.scribeElementName then notification.data.scribeElementName else 'other' | |
action: 'impression' | |
}, event_value: notification.data.pushId | |
# Chrome requires that a notification be shown before the push event is completed | |
# unless theres's a visible client window so we only delegate display handling in that case | |
utils.getClients([ clientFilters.visible ]).then (clientList) -> | |
visibleClient = clientList[0] | |
notificationType = notification.data.notificationType | |
displayHandler = visibleClient and notificationDisplayHandlers[notificationType] or notificationDisplayHandlers['default'] | |
displayHandler notification, visibleClient | |
).bind(this)) | |
@fetchNotifications = (cursors, pushId) -> | |
params = [ | |
'apiv=' + WORKER_API_VERSION | |
cursors.dm and 'dm_cursor=' + encodeURIComponent(cursors.dm) | |
cursors.interactions and 'min_position=' + encodeURIComponent(cursors.interactions) | |
].filter((param) -> | |
! !param | |
) | |
self.fetch(NOTIFICATIONS_ENDPOINT + '?' + params.join('&'), credentials: 'include').then((response) -> | |
response.json() | |
).then((data) -> | |
if data.error or !data.notifications then Promise.reject('Invalid API response') else data | |
).then(((data) -> | |
@storeCursorsFromResponse data | |
).bind(this)).then((data) -> | |
data.notifications.forEach (notification) -> | |
notification.data.pushId = pushId | |
return | |
data.notifications | |
).catch ((err) -> | |
# Unable to fetch data for some reason, most likely they are logged out | |
@scribe { action: 'fetch_failure' }, | |
event_value: pushId | |
message: err.message | |
return | |
).bind(this) | |
@pushHandler = (pushEvent) -> | |
pushId = utils.generatePushId() | |
@scribe { action: 'received' }, event_value: pushId | |
pushEvent.waitUntil @openIndexedDB('notification_cursors').then(((db) -> | |
@getCursors db | |
).bind(this)).then(((cursors) -> | |
@fetchNotifications cursors, pushId | |
).bind(this)).then(((notifications) -> | |
@displayNotifications notifications | |
).bind(this)) | |
return | |
@notificationcloseHandler = (event) -> | |
data = event.notification.data | |
@scribe { | |
element: if data then data.scribeElementName else 'other' | |
action: 'dismiss' | |
}, event_value: data.pushId | |
return | |
@notificationclickHandler = (event) -> | |
event.notification.close() | |
data = event.notification.data | |
@scribe { | |
element: if data then data.scribeElementName else 'other' | |
action: 'click' | |
}, event_value: data.pushId | |
clickHandler = notificationClickHandlers[data.notificationType] or notificationClickHandlers['default'] | |
event.waitUntil clickHandler(data) | |
return | |
### | |
# Indexed DB Interface | |
### | |
@openIndexedDB = (name) -> | |
new Promise((resolve, reject) -> | |
if DB | |
resolve DB | |
else | |
request = self.indexedDB.open(name) | |
request.onsuccess = (event) -> | |
DB = event.target.result | |
DB.onversionchange = (event) -> | |
DB.close() | |
DB = null | |
return | |
resolve DB | |
return | |
request.onerror = request.onblocked = reject | |
return | |
) | |
@getCursors = (db) -> | |
new Promise((resolve, reject) -> | |
request = db.transaction('cursors').objectStore('cursors').openCursor() | |
cursors = {} | |
request.onsuccess = (event) -> | |
cursor = event.target.result | |
if cursor | |
cursors[cursor.value.name] = cursor.value.cursor | |
cursor.continue() | |
else | |
resolve cursors | |
return | |
request.onerror = reject | |
return | |
) | |
@storeCursorsFromResponse = (data) -> | |
@openIndexedDB('notification_cursors').then (db) -> | |
if data.dmCursor | |
db.transaction([ 'cursors' ], 'readwrite').objectStore('cursors').put | |
name: 'dm' | |
cursor: data.dmCursor | |
if data.interactionsCursor | |
db.transaction([ 'cursors' ], 'readwrite').objectStore('cursors').put | |
name: 'interactions' | |
cursor: data.interactionsCursor | |
data | |
### | |
# Service worker interface | |
### | |
@initialize = -> | |
self.addEventListener 'push', @pushHandler.bind(this) | |
self.addEventListener 'notificationclose', @notificationcloseHandler.bind(this) | |
self.addEventListener 'notificationclick', @notificationclickHandler.bind(this) | |
# Make this worker active as soon as it's fetched instead of waiting for page close like normal | |
self.addEventListener 'install', (event) -> | |
event.waitUntil self.skipWaiting() | |
self.addEventListener 'activate', (event) -> | |
event.waitUntil self.clients.claim() | |
return | |
return | |
module.exports = new PushServiceWorker | |
return | |
{ | |
'app/workers/client_filters': 1 | |
'app/workers/notification_click_handlers': 2 | |
'app/workers/notification_display_handlers': 3 | |
'app/workers/scribe': 6 | |
'app/workers/utils': 7 | |
} | |
] | |
5: [ | |
(require, module, exports) -> | |
# no_unit_test | |
pushServiceWorker = require('app/workers/push_service_worker') | |
pushServiceWorker.initialize() | |
return | |
{ 'app/workers/push_service_worker': 4 } | |
] | |
6: [ | |
(require, module, exports) -> | |
# no_unit_test | |
utils = require('app/workers/utils') | |
CLIENT_APP_ID = 268278 | |
### | |
# Lightweight scribe interface for logging display and clicks | |
### | |
scribe = (terms, data) -> | |
data = data or {} | |
if !terms or !terms.action | |
throw new Error('You must specify an action term in your client_event.') | |
# http://go/clienteventnamespace for details | |
eventNamespace = | |
client: 'web' | |
page: 'service_worker' | |
section: terms.section or '' | |
component: terms.component or '' | |
element: terms.element or '' | |
action: terms.action | |
json = Object.assign({}, data, | |
event_namespace: eventNamespace | |
_category_: 'client_event' | |
triggered_on: utils.getDate() | |
format_version: 2 | |
client_app_id: CLIENT_APP_ID) | |
self.fetch '/i/jot', | |
credentials: 'include' | |
method: 'post' | |
headers: | |
'Accept': 'application/x-www-form-urlencoded' | |
'Content-Type': 'application/x-www-form-urlencoded' | |
body: 'log=' + encodeURIComponent(JSON.stringify(json)) | |
return | |
module.exports = scribe | |
return | |
{ 'app/workers/utils': 7 } | |
] | |
7: [ | |
(require, module, exports) -> | |
clientFilters = require('app/workers/client_filters') | |
### Service Worker utils ### | |
module.exports = | |
displayNotification: (notification) -> | |
self.registration.showNotification notification.title, notification | |
getDate: Date.now | |
generatePushId: -> | |
parseInt Math.random() * Number.MAX_SAFE_INTEGER, 10 | |
combineFilters: (filters) -> | |
(item) -> | |
filters.every (filter) -> | |
filter item | |
getClients: (filters) -> | |
filters = filters or [] | |
filters.push clientFilters.topLevel | |
combinedFilter = @combineFilters(filters) | |
self.clients.matchAll(type: 'window').then (clientList) -> | |
clientList.filter combinedFilter | |
triggerOnClient: (client, eventName, eventData) -> | |
client.postMessage JSON.stringify( | |
event: eventName | |
data: eventData) | |
openURL: (url, client) -> | |
url = url or '/' | |
if client and client.navigate | |
client.focus and client.focus() | |
client.navigate url | |
else if self.clients.openWindow | |
self.clients.openWindow url | |
else | |
Promise.reject 'Opening a URL via service worker is not supported in this browser' | |
return | |
{ 'app/workers/client_filters': 1 } | |
] | |
}, {}, [ 5 ] | |
# --- | |
# generated by js2coffee 2.2.0 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I stumbled on this today as well,