From 8f6302eabe35a4ecd78b4934a86d8297137a5e4a Mon Sep 17 00:00:00 2001 From: Paul Sawaya Date: Fri, 24 Jun 2011 13:42:46 -0700 Subject: [PATCH] initial --- README.md | 1 + data/auth.html | 20 ++++++++++ data/auth.js | 12 ++++++ data/notifsPageMod.js | 57 +++++++++++++++++++++++++++ doc/main.md | 2 + lib/main.js | 92 +++++++++++++++++++++++++++++++++++++++++++ package.json | 9 +++++ test/test-main.js | 32 +++++++++++++++ 8 files changed, 225 insertions(+) create mode 100644 README.md create mode 100644 data/auth.html create mode 100644 data/auth.js create mode 100644 data/notifsPageMod.js create mode 100644 doc/main.md create mode 100644 lib/main.js create mode 100644 package.json create mode 100644 test/test-main.js diff --git a/README.md b/README.md new file mode 100644 index 0000000..5d7fa0b --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +This is Chrome Notifications in Firefox via Jetpack. Learn more about what's being implemented at http://www.html5rocks.com/en/tutorials/notifications/quick/ \ No newline at end of file diff --git a/data/auth.html b/data/auth.html new file mode 100644 index 0000000..3432596 --- /dev/null +++ b/data/auth.html @@ -0,0 +1,20 @@ + + + + + +
+ This site would like to show you desktop notifications. How do you feel about that? +
+ +
+ + +
+ + \ No newline at end of file diff --git a/data/auth.js b/data/auth.js new file mode 100644 index 0000000..d8fe6c4 --- /dev/null +++ b/data/auth.js @@ -0,0 +1,12 @@ +function userChoice(authed) { + self.postMessage({ + authDecision: authed, + hostname: window.location.host + }); +} + +function init() { + document.getElementById('yesButton').addEventListener('click', function(e) { userChoice(true); },false); + document.getElementById('noButton').addEventListener('click', function(e) { userChoice(false); },false); +} +init(); \ No newline at end of file diff --git a/data/notifsPageMod.js b/data/notifsPageMod.js new file mode 100644 index 0000000..d46c925 --- /dev/null +++ b/data/notifsPageMod.js @@ -0,0 +1,57 @@ +window.notifications = { + createNotification: function createNotification(iconURL,title,text) { + var notifObj = { + show: function show() { + self.postMessage({ type: 'regular', args: { + iconURL: iconURL, + title: title, + text: text + } + }); + } + }; + return notifObj; + }, + createHTMLNotification: function createHTMLNotification(url) { + self.postMessage({ type: 'html', args: arguments }); + }, + checkPermission: function checkPermission() { + // TODO: ask permission. + + // self.postMessage({ type: 'permission', args: { + // + // } }); + + return window.notifications.permissionAllowed; + // return 0; // 0 == PERMISSION_ALLOWED + }, + permissionAllowed: 1, // Real copy of permissions is kept in main.js, this is just used for checkPermission() + permissionCallback: function emptyPermissionCallback() {}, + requestPermission: function requestPermission(callback) { + // TODO: ask permission. + self.postMessage({ + type:'permission', + args: { + } + }); + + this.permissionCallback = callback; + + return true; + } +}; + +self.port.on('authDecision', function (msg) { + if (msg['type'] != 'authresult') return; + + window.notifications.permissionAllowed = msg['value'] ? 0 : 1; + + // TODO: PERMISSION_DENIED + if (msg['value']) + window.notifications.permissionCallback(0); // PERMISSION_ALLOWED + else + window.notifications.permissionCallback(1); // PERMISSION_NOT_ALLOWED +}); + +window.webkitNotifications = window.notifications; +window.mozillaNotifications = window.notifications; \ No newline at end of file diff --git a/doc/main.md b/doc/main.md new file mode 100644 index 0000000..4dff065 --- /dev/null +++ b/doc/main.md @@ -0,0 +1,2 @@ +The main module is a program that creates a widget. When a user clicks on +the widget, the program loads the mozilla.org website in a new tab. diff --git a/lib/main.js b/lib/main.js new file mode 100644 index 0000000..bc289c0 --- /dev/null +++ b/lib/main.js @@ -0,0 +1,92 @@ +// HTML5 Desktop Notifications + +const dataDir = require("self").data; +const notifications = require("notifications"); +const pageMod = require("page-mod"); +const panel = require("panel"); +const tabBrowser = require("tab-browser"); +const url = require("url"); + + +// Dictionary of hostnames that are allowed to show notifications. +var SITES_ALLOWED = {}; + +// Remaining to be done: +// * HTML Notifications +// * Persist SITES_ALLOWED between sessions (simple storage?) so that users don't have to auth every time +// * After notification callback +// * Ability to remove site's notification privileges + +function createNotificationsHook() { + pageMod.PageMod({ + include: "*", + contentScriptFile: dataDir.url('notifsPageMod.js'), + onAttach: function(worker,mod) { + worker.on('message',function(msg) { + if (msg['type'] == 'regular') { + console.log("Can auth: " + this.canAuth()); + if (!this.canAuth) return false; + var msgArgs = msg.args; + var notifObj = { + title: msgArgs['title'] ? msgArgs['title'] : 'Notification', + text: msgArgs['text'] ? msgArgs['text'] : '', + iconURL: msgArgs['iconURL'] ? msgArgs['iconURL'] : undefined, + data: 'data string.', + onClick: function (data) { + console.log(data); + } + }; + notifications.notify(notifObj); + } + else if (msg['type'] == 'permission') { + console.log(msg['args'].win); + var currentWorker = worker; + askNotificationsPermission(function callback(authResult) { + worker.port.emit('authDecision', { + type: 'authresult', + value: authResult + }); + + if (authResult) { + // If the user accepts notifications, authorize entire hostname. + var workerHostname = getHostnameFromURL(worker.tab.url); + SITES_ALLOWED[workerHostname] = true; + } + }); + } + }); + worker.canAuth = function canAuth() { + return SITES_ALLOWED[getHostnameFromURL(this.tab.url)]; + } + } + }); +} +createNotificationsHook(); + +function getHostnameFromURL(_url) { + return url.URL(_url).host; +} + +function askNotificationsPermission(callback) { + var canHidePanel = true; + + var authPanel = panel.Panel({ + contentURL: dataDir.url('auth.html'), + contentScriptFile: dataDir.url('auth.js'), + contentScriptWhen: 'ready', + onMessage: function(msg) { + canHidePanel = true; + this.hide(); + callback(msg['authDecision']); + }, + onHide: function() { + // Cheesy way of making sure the panel doesn't disappear when you click off. + if (!canHidePanel) + this.show(); + }, + }); + + authPanel.show(); + canHidePanel = false; + +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..96b1772 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "chrome-notifications-jetpack", + "license": "MPL 1.1/GPL 2.0/LGPL 2.1", + "author": "", + "version": "0.1", + "fullName": "Chrome Notifications Jetpack", + "id": "jid1-KQQ9iBe5nw7jdA", + "description": "Chrome (Gmail/GTalk) desktop notifications in Firefox." +} diff --git a/test/test-main.js b/test/test-main.js new file mode 100644 index 0000000..98d630b --- /dev/null +++ b/test/test-main.js @@ -0,0 +1,32 @@ +const main = require("main"); + +exports.test_test_run = function(test) { + test.pass("Unit test running!"); +}; + +exports.test_id = function(test) { + test.assert(require("self").id.length > 0); +}; + +exports.test_url = function(test) { + require("request").Request({ + url: "http://www.mozilla.org/", + onComplete: function(response) { + test.assertEqual(response.statusText, "OK"); + test.done(); + } + }).get(); + test.waitUntilDone(20000); +}; + +exports.test_open_tab = function(test) { + const tabs = require("tabs"); + tabs.open({ + url: "http://www.mozilla.org/", + onReady: function(tab) { + test.assertEqual(tab.url, "http://www.mozilla.org/"); + test.done(); + } + }); + test.waitUntilDone(20000); +};