diff --git a/MarmoUI-Chrome/manifest.json b/MarmoUI-Chrome/manifest.json index 68691d6..e548181 100644 --- a/MarmoUI-Chrome/manifest.json +++ b/MarmoUI-Chrome/manifest.json @@ -13,7 +13,13 @@ "content_scripts": [ { "matches": ["https://marmoset.student.cs.uwaterloo.ca/*"], - "js": ["script.js"] + "js": ["scripts/script.js"] } - ] + ], + + "background": { + "persistent": false, + "scripts": ["scripts/notifications.js"] + }, + "permissions": ["notifications"] } \ No newline at end of file diff --git a/MarmoUI-Chrome/scripts/notifications.js b/MarmoUI-Chrome/scripts/notifications.js new file mode 100644 index 0000000..3140b59 --- /dev/null +++ b/MarmoUI-Chrome/scripts/notifications.js @@ -0,0 +1,82 @@ +// Notifications which have not been closed yet +var activeNotifications = {}; + +chrome.runtime.onMessage.addListener(function(request, sender) { + + if (request.type == "notification") { + // Check if we have permission + chrome.notifications.getPermissionLevel(function(level) { + if(level == "denied") { + console.warn("Notification suppressed; Permission denied.") + return; + } + + chrome.windows.get(sender.tab.windowId, function(win) { + // Don't show notification if user is still on marmoset + if (win.focused && sender.tab.active) return; + + chrome.notifications.create('', request.notification, + function(notificationId) { + // Add URL to activeNotifications so we can access it + // on button click + request.sender = sender; + activeNotifications[notificationId] = request; + }); + }); + }); + } +}); + +// Button handler for "View Results" +function openResults(notificationId, buttonIndex) { + + // Open a new tab with the results + chrome.tabs.create(activeNotifications[notificationId].options, function(tab) { + + // Focus new tab's window + chrome.windows.update(tab.windowId, {focused: true}, function (){ }); + }); + + // Close notification + chrome.notifications.clear(notificationId, function() {}); +} + +function notificationDeactivated(notificationId) { + delete activeNotifications[notificationId]; +} + +function focusMarmoUI(notificationId) { + var windowId = activeNotifications[notificationId].sender.tab.windowId; + var tabId = activeNotifications[notificationId].sender.tab.id; + var pageUrl = activeNotifications[notificationId].sender.url; + + //check if window still exists + chrome.windows.get(windowId, function() { + if(!chrome.runtime.lastError) { + // focus + chrome.windows.update(windowId, {focused: true}, function (){}); + } + }); + + // check if tab still exists + chrome.tabs.get(tabId, function() { + if(!chrome.runtime.lastError) { + // set active + chrome.tabs.update(tabId, {active: true}, function () {}); + } else { + // otherwise open results at previous url + chrome.tabs.create({url: pageUrl}, function(tab) { + // Focus new tab's window + chrome.windows.update(tab.windowId, {focused: true}, function (){ }); + }); + } + }); + + // Close notification + chrome.notifications.clear(notificationId, function() {}); +} + +// Registering listeners +chrome.notifications.onButtonClicked.addListener(openResults) +chrome.notifications.onClosed.addListener(notificationDeactivated); +chrome.notifications.onClicked.addListener(focusMarmoUI); \ No newline at end of file diff --git a/MarmoUI-Chrome/script.js b/MarmoUI-Chrome/scripts/script.js similarity index 98% rename from MarmoUI-Chrome/script.js rename to MarmoUI-Chrome/scripts/script.js index 69e0035..0160725 100644 --- a/MarmoUI-Chrome/script.js +++ b/MarmoUI-Chrome/scripts/script.js @@ -524,6 +524,23 @@ function runMarmoUI() function applyChangesProblemsList() { + + //After testing, loadSubmission and notify + function loadSubmissionAfterAsyncReload(tableCell, requestResult, requestURL) { + loadSubmission(tableCell, requestResult, requestURL); + + // If finished testing, display notification + if(tableCell.find("a:contains('Not tested')").length == 0) { + var $a = tableCell.find("a"); + + notifyTestingComplete({ + test: tableCell.parent().children().first().text().trim(), + result: $a.text().trim(), + url: 'https://marmoset.student.cs.uwaterloo.ca' + $a.attr('href') + }); + } + } + //When async callbacks, decrypt the result from the page and integrate into the page function loadSubmission(tableCell, requestResult, requestURL) { @@ -550,7 +567,7 @@ function runMarmoUI() if(firstLine.find("td:contains('tested yet')").length > 0) { tableCell.find("a").html("Not tested (reload in s)"); - queueAsyncReload(tableCell, requestURL, loadSubmission, reload_time); + queueAsyncReload(tableCell, requestURL, loadSubmissionAfterAsyncReload, reload_time); } //Check if latest solution failed to compile //If failed to compile, show it as uncompiled and exits @@ -725,6 +742,9 @@ function runMarmoUI() } else { + notifyTestingComplete({ + test: $(".nav").children().last().text() + }) //No more untested solutions, reload to see results document.location.reload(true); } @@ -859,8 +879,13 @@ function runMarmoUI() }); } - //Start of actual executing code + // Creates desktop notification + function notifyTestingComplete(notification) { + notification.type = "resultsNotification"; + window.postMessage(notification, "*"); + } + //Start of actual executing code //Find out which page we're on var path = $(location).attr("href"); //Check which page we're on @@ -940,4 +965,32 @@ function runMarmoUI() } } +// Listener to handle desktop notifications +// (notification goes from page context -> content-script -> background page (notifications.js)) +window.addEventListener("message", function(event) { + // We only accept messages from ourselves + if (event.source != window) + return; + + if (event.data.type && (event.data.type == "resultsNotification")) { + var toSend = {type: "notification", + notification: { + type: "basic", + iconUrl: chrome.extension.getURL("image/icon128.png"), + title: event.data.test + " Testing Complete", + message: (event.data.result ? "Result: " + event.data.result : "") + }, + options: {} + }; + + // Notification has "View results" button + if(event.data.url) { + toSend.notification.buttons = [{title: "View results"}]; + toSend.options.url = event.data.url + } + chrome.runtime.sendMessage(toSend); + } +}, false); + + loadMarmoUI(runMarmoUI);