Make extention acceptable by Edge Add-Ons website
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.yarn
|
||||
node_modules
|
||||
build
|
BIN
.yarn/install-state.gz
Normal file
1
.yarnrc.yml
Normal file
@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
23
README.md
Normal file
@ -0,0 +1,23 @@
|
||||
# A Toasty Owa <img src="public/icons/icon_128.png" style="float:right">
|
||||
|
||||
Show desktop notifications for new mail and calendar alerts.
|
||||
|
||||
## Features
|
||||
|
||||
- Show notifications for new mail and calendar alerts
|
||||
- Add quick switch buttons for Inbox, Calendar, People and Tasks
|
||||
|
||||
## Install
|
||||
|
||||
### Chrome
|
||||
### Edge
|
||||
|
||||
TODO
|
||||
|
||||
### Development
|
||||
|
||||
|
||||
|
||||
## Contribution
|
||||
|
||||
Suggestions and pull requests are welcomed!.
|
@ -1,80 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
console.log("Loading background script....");
|
||||
|
||||
let notificationMap = {};
|
||||
|
||||
chrome.runtime.onMessage.addListener(
|
||||
function (message, sender) {
|
||||
if (message.type === 'quick-links') {
|
||||
chrome.storage.sync.get('showQuickLinks', (data) => {
|
||||
if (data.showQuickLinks) {
|
||||
chrome.tabs.executeScript(sender.tab.id, { code: "$('#quick-links').show()" });
|
||||
}
|
||||
});
|
||||
} else if (message.type === 'email') {
|
||||
const { from, subject, body } = message;
|
||||
chrome.notifications.create(null, {
|
||||
type: "basic",
|
||||
iconUrl: "images/email.png",
|
||||
title: subject,
|
||||
message: `From: ${from}\n${body}`,
|
||||
requireInteraction: true
|
||||
}, (notificationId) => {
|
||||
notificationMap[notificationId] = { type: 'email', tabId: sender.tab.id, windowId: sender.tab.windowId };
|
||||
startCloseNotificationTimer(notificationId, 'email');
|
||||
});
|
||||
} else {
|
||||
const { title, duration } = message;
|
||||
chrome.notifications.create(null, {
|
||||
type: "basic",
|
||||
iconUrl: "images/calendar.png",
|
||||
title,
|
||||
message: duration,
|
||||
requireInteraction: true
|
||||
}, (notificationId) => {
|
||||
notificationMap[notificationId] = { type: 'calendar', tabId: sender.tab.id, windowId: sender.tab.windowId };
|
||||
startCloseNotificationTimer(notificationId, 'calendar');
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
chrome.notifications.onClicked.addListener((notificationId) => {
|
||||
if (notificationMap[notificationId]) {
|
||||
const { type, tabId, windowId } = notificationMap[notificationId];
|
||||
chrome.tabs.update(tabId, { active: true, highlighted: true });
|
||||
chrome.windows.update(windowId, { focused: true });
|
||||
chrome.notifications.clear(notificationId);
|
||||
if (type === 'email') {
|
||||
chrome.tabs.executeScript(tabId, { code: `$('#quick-link-mail')[0].click()` });
|
||||
} else {
|
||||
chrome.tabs.executeScript(tabId, { code: `$('#quick-link-calendar')[0].click()` });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
chrome.runtime.onInstalled.addListener(function() {
|
||||
chrome.storage.sync.set({emailDelay: -1, calendarDelay: -1, showQuickLinks: true});
|
||||
|
||||
chrome.declarativeContent.onPageChanged.removeRules(undefined, function() {
|
||||
chrome.declarativeContent.onPageChanged.addRules([{
|
||||
conditions: [new chrome.declarativeContent.PageStateMatcher({
|
||||
css: ["body[aria-label='Outlook']"]
|
||||
})],
|
||||
actions: [new chrome.declarativeContent.ShowPageAction()]
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
function startCloseNotificationTimer(notificationId, type) {
|
||||
chrome.storage.sync.get(`${type}Delay`, (data) => {
|
||||
const delay = data[`${type}Delay`];
|
||||
if (delay > 0 ) {
|
||||
console.log(`Showing notification for ${delay} seconds`);
|
||||
setTimeout(() => {
|
||||
chrome.notifications.clear(notificationId);
|
||||
}, delay * 1000);
|
||||
}
|
||||
});
|
||||
}
|
10
config/paths.js
Normal file
@ -0,0 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
|
||||
const PATHS = {
|
||||
src: path.resolve(__dirname, '../src'),
|
||||
build: path.resolve(__dirname, '../build'),
|
||||
};
|
||||
|
||||
module.exports = PATHS;
|
58
config/webpack.common.js
Normal file
@ -0,0 +1,58 @@
|
||||
'use strict';
|
||||
|
||||
const SizePlugin = require('size-plugin');
|
||||
const CopyWebpackPlugin = require('copy-webpack-plugin');
|
||||
|
||||
const PATHS = require('./paths');
|
||||
const { ProvidePlugin } = require('webpack');
|
||||
|
||||
// To re-use webpack configuration across templates,
|
||||
// CLI maintains a common webpack configuration file - `webpack.common.js`.
|
||||
// Whenever user creates an extension, CLI adds `webpack.common.js` file
|
||||
// in template's `config` folder
|
||||
const common = {
|
||||
output: {
|
||||
// the build folder to output bundles and assets in.
|
||||
path: PATHS.build,
|
||||
// the filename template for entry chunks
|
||||
filename: '[name].js',
|
||||
},
|
||||
devtool: 'source-map',
|
||||
stats: {
|
||||
all: false,
|
||||
errors: true,
|
||||
builtAt: true,
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
// Check for images imported in .js files and
|
||||
{
|
||||
test: /\.(png|jpe?g|gif)$/i,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
outputPath: 'images',
|
||||
name: '[name].[ext]',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
// Print file sizes
|
||||
new SizePlugin(),
|
||||
// Copy static assets from `public` folder to `build` folder
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
{
|
||||
from: '**/*',
|
||||
context: 'public',
|
||||
},
|
||||
]
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = common;
|
18
config/webpack.config.js
Normal file
@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
|
||||
const { merge } = require('webpack-merge');
|
||||
|
||||
const common = require('./webpack.common.js');
|
||||
const PATHS = require('./paths');
|
||||
|
||||
// Merge webpack configuration files
|
||||
const config = merge(common, {
|
||||
entry: {
|
||||
popup: PATHS.src + '/popup.js',
|
||||
service_worker: PATHS.src + '/service_worker.js',
|
||||
contentScript: PATHS.src + '/contentScript.js',
|
||||
jquery: 'jquery',
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = config;
|
22
package.json
Normal file
@ -0,0 +1,22 @@
|
||||
{
|
||||
"name": "a-toasty-owa",
|
||||
"version": "1.0.2",
|
||||
"description": "Show desktop notifications for new mail and calendar alerts",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"watch": "yarn run webpack --mode=development --watch --config config/webpack.config.js",
|
||||
"build": "yarn run webpack --mode=production --config config/webpack.config.js"
|
||||
},
|
||||
"packageManager": "yarn@4.4.1",
|
||||
"devDependencies": {
|
||||
"copy-webpack-plugin": "^6.4.1",
|
||||
"file-loader": "^6.2.0",
|
||||
"size-plugin": "^2.0.2",
|
||||
"webpack": "^5.94.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-merge": "^5.10.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"jquery": "^3.7.1"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 717 B After Width: | Height: | Size: 717 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 429 B After Width: | Height: | Size: 429 B |
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
@ -1,23 +1,27 @@
|
||||
{
|
||||
"manifest_version": 3,
|
||||
"name": "A Toasty OWA",
|
||||
"version": "1.0.1",
|
||||
"version": "1.0.2",
|
||||
"description": "Show desktop notifications for new mail and calendar alerts",
|
||||
"icons": {
|
||||
"32": "icons/icon_32.png",
|
||||
"48": "icons/icon_48.png",
|
||||
"128": "icons/icon_128.png"
|
||||
},
|
||||
"permissions": [
|
||||
"activeTab",
|
||||
"declarativeContent",
|
||||
"storage",
|
||||
"notifications",
|
||||
"tabs",
|
||||
"http://*/*",
|
||||
"https://*/*"
|
||||
"scripting"
|
||||
],
|
||||
"host_permissions": [
|
||||
"https://*/owa/*"
|
||||
],
|
||||
"background": {
|
||||
"scripts": [
|
||||
"background.js"
|
||||
],
|
||||
"persistent": false
|
||||
"service_worker": "service_worker.js"
|
||||
},
|
||||
"page_action": {
|
||||
"action": {
|
||||
"default_popup": "popup.html"
|
||||
},
|
||||
"content_scripts": [
|
||||
@ -26,15 +30,8 @@
|
||||
"https://*/owa/*"
|
||||
],
|
||||
"js": [
|
||||
"jquery.3.3.1.slim.js",
|
||||
"contentScript.js"
|
||||
]
|
||||
}
|
||||
],
|
||||
"icons": {
|
||||
"32": "images/icon_32.png",
|
||||
"48": "images/icon_48.png",
|
||||
"128": "images/icon_128.png"
|
||||
},
|
||||
"manifest_version": 2
|
||||
]
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif
|
||||
font-family: 'Trebuchet MS', 'Lucida Sans Unicode', 'Lucida Grande', 'Lucida Sans', Arial, sans-serif;
|
||||
margin: 10px;
|
||||
width: 220px;
|
||||
}
|
1
size-plugin.json
Normal file
@ -0,0 +1 @@
|
||||
[{"timestamp":1725286622851,"files":[{"filename":"options.html","previous":530,"size":530,"diff":0},{"filename":"popup.html","previous":543,"size":543,"diff":0},{"filename":"popup.js","previous":287,"size":30655,"diff":30368},{"filename":"service_worker.js","previous":849,"size":815,"diff":-34},{"filename":"contentScript.js","previous":0,"size":31387,"diff":31387},{"filename":"jquery.js","previous":0,"size":30459,"diff":30459}]},{"timestamp":1724674251968,"files":[{"filename":"options.html","previous":530,"size":530,"diff":0},{"filename":"popup.html","previous":543,"size":543,"diff":0},{"filename":"popup.js","previous":287,"size":287,"diff":0},{"filename":"service_worker.js","previous":804,"size":849,"diff":45}]},{"timestamp":1724672835507,"files":[{"filename":"app.js","previous":286,"size":0,"diff":-286},{"filename":"options.html","previous":530,"size":530,"diff":0},{"filename":"popup.html","previous":543,"size":543,"diff":0},{"filename":"background.js","previous":797,"size":0,"diff":-797},{"filename":"popup.js","previous":0,"size":287,"diff":287},{"filename":"service_worker.js","previous":0,"size":804,"diff":804}]},{"timestamp":1724672752620,"files":[{"filename":"app.js","previous":286,"size":286,"diff":0},{"filename":"options.html","previous":530,"size":530,"diff":0},{"filename":"popup.html","previous":543,"size":543,"diff":0},{"filename":"service_worker.js","previous":797,"size":0,"diff":-797},{"filename":"background.js","previous":0,"size":797,"diff":797}]},{"timestamp":1724672366631,"files":[{"filename":"app.js","previous":286,"size":286,"diff":0},{"filename":"options.html","previous":530,"size":530,"diff":0},{"filename":"popup.html","previous":543,"size":543,"diff":0},{"filename":"service_worker.js","previous":800,"size":797,"diff":-3}]},{"timestamp":1724672146257,"files":[{"filename":"app.js","previous":286,"size":286,"diff":0},{"filename":"service_worker.js","previous":800,"size":0,"diff":-800},{"filename":"options.html","previous":530,"size":530,"diff":0},{"filename":"popup.html","previous":543,"size":543,"diff":0},{"filename":"service_worker.js","previous":0,"size":800,"diff":800}]},{"timestamp":1724327326539,"files":[{"filename":"app.js","previous":0,"size":286,"diff":286},{"filename":"service_worker.js","previous":0,"size":800,"diff":800},{"filename":"options.html","previous":0,"size":530,"diff":530},{"filename":"popup.html","previous":0,"size":543,"diff":543}]}]
|
@ -1,3 +1,5 @@
|
||||
const $ = require('jquery');
|
||||
|
||||
const MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
|
||||
const bodyObserver = new MutationObserver(bodyMutationHandler);
|
||||
const popUpObserver = new MutationObserver(popUpAreaHandler);
|
||||
@ -5,8 +7,10 @@ const obsConfig = { childList: true };
|
||||
let insertedQuickLinks = false;
|
||||
|
||||
bodyObserver.observe($('body').get()[0], obsConfig);
|
||||
window.$ = $;
|
||||
|
||||
$('body').append(`
|
||||
<script src="jquery.js"></script>
|
||||
<style>
|
||||
.quick-links-container {
|
||||
display: none;
|
@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const $ = require('jquery');
|
||||
|
||||
$('#emailDelay').change((event) => {
|
||||
chrome.storage.sync.set({ emailDelay: parseInt(event.target.value) });
|
||||
});
|
@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
const $ = require('jquery');
|
||||
|
||||
$('#emailDelay').change((event) => {
|
||||
chrome.storage.sync.set({ emailDelay: parseInt(event.target.value) });
|
||||
});
|
89
src/service_worker.js
Normal file
@ -0,0 +1,89 @@
|
||||
'use strict';
|
||||
|
||||
console.log("Loading service worker....");
|
||||
|
||||
let notificationMap = {};
|
||||
|
||||
chrome.runtime.onInstalled.addListener(() => {
|
||||
chrome.storage.sync.set({ emailDelay: -1, calendarDelay: -1, showQuickLinks: true });
|
||||
|
||||
chrome.declarativeContent.onPageChanged.removeRules(undefined, function () {
|
||||
chrome.declarativeContent.onPageChanged.addRules([{
|
||||
conditions: [new chrome.declarativeContent.PageStateMatcher({
|
||||
css: ["body[aria-label='Outlook']"]
|
||||
})],
|
||||
actions: [new chrome.declarativeContent.ShowPageAction()]
|
||||
}]);
|
||||
});
|
||||
});
|
||||
|
||||
chrome.runtime.onMessage.addListener((message, sender) => {
|
||||
if (message.type === 'quick-links') {
|
||||
chrome.storage.sync.get('showQuickLinks', (data) => {
|
||||
if (data.showQuickLinks) {
|
||||
chrome.scripting.executeScript({
|
||||
target: { tabId: sender.tab.id },
|
||||
func: () => { $('#quick-links').show() }
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (message.type === 'email') {
|
||||
const { from, subject, body } = message;
|
||||
chrome.notifications.create(null, {
|
||||
type: "basic",
|
||||
iconUrl: "images/email.png",
|
||||
title: subject,
|
||||
message: `From: ${from}\n${body}`,
|
||||
requireInteraction: true
|
||||
}, (notificationId) => {
|
||||
notificationMap[notificationId] = { type: 'email', tabId: sender.tab.id, windowId: sender.tab.windowId };
|
||||
startCloseNotificationTimer(notificationId, 'email');
|
||||
});
|
||||
} else {
|
||||
const { title, duration } = message;
|
||||
chrome.notifications.create(null, {
|
||||
type: "basic",
|
||||
iconUrl: "images/calendar.png",
|
||||
title,
|
||||
message: duration,
|
||||
requireInteraction: true
|
||||
}, (notificationId) => {
|
||||
notificationMap[notificationId] = { type: 'calendar', tabId: sender.tab.id, windowId: sender.tab.windowId };
|
||||
startCloseNotificationTimer(notificationId, 'calendar');
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
chrome.notifications.onClicked.addListener((notificationId) => {
|
||||
if (notificationMap[notificationId]) {
|
||||
const { type, tabId, windowId } = notificationMap[notificationId];
|
||||
chrome.tabs.update(tabId, { active: true, highlighted: true });
|
||||
chrome.windows.update(windowId, { focused: true });
|
||||
chrome.notifications.clear(notificationId);
|
||||
if (type === 'email') {
|
||||
chrome.scripting.executeScript({
|
||||
target: { tabId: tabId },
|
||||
func: () => { $('#quick-link-mail')[0].click() }
|
||||
});
|
||||
} else {
|
||||
chrome.scripting.executeScript({
|
||||
target: { tabId: tabId },
|
||||
tabId,
|
||||
func: () => { $('#quick-link-calendar')[0].click() }
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function startCloseNotificationTimer(notificationId, type) {
|
||||
chrome.storage.sync.get(`${type}Delay`, (data) => {
|
||||
const delay = data[`${type}Delay`];
|
||||
if (delay > 0) {
|
||||
console.log(`Showing notification for ${delay} seconds`);
|
||||
setTimeout(() => {
|
||||
chrome.notifications.clear(notificationId);
|
||||
}, delay * 1000);
|
||||
}
|
||||
});
|
||||
}
|