Last active
June 20, 2024 18:42
-
-
Save kdmcclel/ebff9f99ded58fa1d15752062c70792c to your computer and use it in GitHub Desktop.
This file contains hidden or 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
| // ==UserScript== | |
| // @name F&F Background Notification | |
| // @namespace https://gist.github.com/kdmcclel/ebff9f99ded58fa1d15752062c70792c | |
| // @version 0.11 | |
| // @description Add Notification API settings option to notify when tab is inactive. | |
| // @author Kevin McClellan <kdmcclel@gmail.com> | |
| // @match https://www.forgeandfortune.com/ | |
| // @grant none | |
| // @inject-into page | |
| // @downloadURL https://gist.github.com/kdmcclel/ebff9f99ded58fa1d15752062c70792c/raw | |
| // ==/UserScript== | |
| (function($, window, document) { | |
| 'use strict'; | |
| if (!('Notification' in window)) { | |
| alert('This browser does not support desktop notification'); | |
| return; | |
| } | |
| var crc32 = function(r) { | |
| for (var a, o = [], c = 0; c < 256; c++) { | |
| a = c; | |
| for (var f = 0; f < 8; f++) a = 1 & a ? 3988292384 ^ a >>> 1 : a >>> 1; | |
| o[c] = a | |
| } | |
| for (var n = -1, t = 0; t < r.length; t++) n = n >>> 8 ^ o[255 & (n ^ r.charCodeAt(t))]; | |
| return (-1 ^ n) >>> 0 | |
| }; | |
| if (crc32(window.renderDialogActions.toString()) != 259619873 || crc32(window.ToastManager.renderToast.toString()) != 813550547) { | |
| console.error('renderDialogActions', crc32(window.renderDialogActions.toString()), 259619873); | |
| console.error('ToastManager.renderToast', crc32(window.ToastManager.renderToast.toString()), 813550547); | |
| alert('F&F Background Notification extension is outdated.'); | |
| return; | |
| } | |
| if (!('backgroundNotifications' in window.settings)) { | |
| window.settings.backgroundNotifications = 0; | |
| } | |
| $(document).on("change", ".backgroundPrefSelection", function(e) { | |
| $(e.target).attr("checked", "checked"); | |
| window.settings.backgroundNotifications = parseInt($(e.target).val()); | |
| window.saveSettings(); | |
| }); // Event Functions | |
| let old = window.renderDialogActions; | |
| window.renderDialogActions = function() { | |
| var dialogActions = $("<div/>").addClass("dialogActionsContainer"); | |
| if (arguments[0] === 'settings') { | |
| var settingsTabsContainer = $("<div/>") | |
| .addClass("settingsTabContainer") | |
| .appendTo(dialogActions); | |
| $("<div/>") | |
| .addClass("settingsTab selected") | |
| .attr({ id: "settingTabGeneral" }) | |
| .html("General") | |
| .appendTo(settingsTabsContainer); | |
| $("<div/>") | |
| .addClass("settingsTab") | |
| .attr({ id: "settingTabNotifications" }) | |
| .html("Notifications") | |
| .appendTo(settingsTabsContainer); | |
| $("<div/>") | |
| .addClass("settingsTab") | |
| .attr({ id: "settingTabHotkeys" }) | |
| .html("Hotkeys") | |
| .appendTo(settingsTabsContainer); | |
| var tabGeneral = $("<div/>") | |
| .addClass("settingTabContent selected settings-grid") | |
| .attr({ id: "settingContentGeneral" }) | |
| .appendTo(dialogActions); | |
| var tabNotifications = $("<div/>") | |
| .addClass("settingTabContent settings-grid") | |
| .attr({ id: "settingContentNotifcations" }) | |
| .appendTo(dialogActions); | |
| var tabHotkeys = $("<div/>") | |
| .addClass("settingTabContent settings-grid") | |
| .attr({ id: "settingContentHotkeys" }) | |
| .appendTo(dialogActions); | |
| var hotkeyPref = $("<div/>") | |
| .attr({ id: "settings_hotkeyPref" }) | |
| .addClass("setting-container") | |
| .appendTo(tabHotkeys); | |
| var hotkeyPref_details = { | |
| title: "Hotkeys", | |
| description: "Choose whether hotkeys are triggered.", | |
| }; | |
| window.settingsBoilerplate(hotkeyPref_details, false).appendTo(hotkeyPref); | |
| var hotkeyPrefGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(hotkeyPref); | |
| var hotkeyPrefOptions = [0, 1]; | |
| hotkeyPrefOptions.forEach(function (option, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container hotkeyPrefSelection") | |
| .html(option === 1 ? "Enabled" : "Disabled"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "hotkeyPref", | |
| value: option, | |
| checked: HotKeys.enabled === option ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(hotkeyPrefGrid); | |
| }); | |
| $("<div/>") | |
| .addClass("hotkeyAllDefault actionButton") | |
| .attr({ id: "hotkeyAllDefault" }) | |
| .appendTo(tabHotkeys); | |
| $("<div/>") | |
| .addClass("hotkeyList") | |
| .attr({ id: "hotkeyList" }) | |
| .appendTo(tabHotkeys); | |
| var notificationPref = $("<div/>") | |
| .attr({ id: "settings_notificationPref" }) | |
| .addClass("setting-container") | |
| .appendTo(tabNotifications); | |
| var notificationPref_details = { | |
| title: "Notifications", | |
| description: "Choose whether notifications are rendered.", | |
| }; | |
| window.settingsBoilerplate(notificationPref_details).appendTo(notificationPref); | |
| var notificationPrefGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(notificationPref); | |
| var notificationPrefOptions = [0, 1]; | |
| notificationPrefOptions.forEach(function (option, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container toastPrefSelection") | |
| .html(option === 1 ? "Enabled" : "Disabled"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "notificationPref", | |
| value: option, | |
| checked: settings.toasts === option ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(notificationPrefGrid); | |
| }); | |
| var notificationSize = $("<div/>") | |
| .attr({ id: "settings_notificationSize" }) | |
| .addClass("setting-container") | |
| .appendTo(tabNotifications); | |
| var notificationSize_details = { | |
| title: "Notification Size", | |
| description: | |
| "Choose between a spacious sizing for notifications or a more compact sizing.", | |
| }; | |
| window.settingsBoilerplate(notificationSize_details).appendTo(notificationSize); | |
| var notificationSizeGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(notificationSize); | |
| var sizes = [0, 1]; | |
| sizes.forEach(function (size, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container toastSizeSelection") | |
| .html(size === 1 ? "Comfortable" : "Compact"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "toastSize", | |
| value: size, | |
| checked: size === settings.toastSize ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(notificationSizeGrid); | |
| }); | |
| var notificationDuration = $("<div/>") | |
| .attr({ id: "settings_notificationDuration" }) | |
| .addClass("setting-container") | |
| .appendTo(tabNotifications); | |
| var notificationDuration_details = { | |
| title: "Notification Duration", | |
| description: | |
| "Designates the duration a notification will remain present on the screen.", | |
| }; | |
| window.settingsBoilerplate(notificationDuration_details).appendTo( | |
| notificationDuration | |
| ); | |
| var notificationDurationGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(notificationDuration); | |
| var durations = [1e3, 3e3, 5e3, 1e4, 15e3, 3e4]; | |
| durations.forEach(function (duration, i) { | |
| var time = duration / 1e3; | |
| var label = $("<label/>") | |
| .addClass("selection-container toastDurationSelection") | |
| .html("".concat(time, " ").concat(time > 1 ? "seconds" : "second")); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "toastDuration", | |
| value: duration, | |
| checked: duration === settings.toastDuration ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(notificationDurationGrid); | |
| }); | |
| var notificationLocation = $("<div/>") | |
| .attr({ id: "settings_notificationLocation" }) | |
| .addClass("setting-container") | |
| .appendTo(tabNotifications); | |
| var notificationLocation_details = { | |
| title: "Notification Location", | |
| description: | |
| "Designates where the notifications for various events (such as exceptional crafts) will appear.", | |
| }; | |
| window.settingsBoilerplate(notificationLocation_details).appendTo( | |
| notificationLocation | |
| ); | |
| var selectionsGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(notificationLocation); | |
| var locations = [ | |
| "Top-Left", | |
| "Top-Center", | |
| "Top-Right", | |
| "Bottom-Left", | |
| "Bottom-Center", | |
| "Bottom-Right", | |
| ]; | |
| locations.forEach(function (location, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container toastPositionSelection") | |
| .html(location); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "toast", | |
| value: location.toLowerCase(), | |
| checked: | |
| location.toLowerCase() === settings.toastPosition | |
| ? "checked" | |
| : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(selectionsGrid); | |
| }); | |
| var backgroundPref = $("<div/>") | |
| .attr({ | |
| id: "settings_backgroundPref" | |
| }) | |
| .addClass("setting-container") | |
| .appendTo(tabNotifications); | |
| var backgroundPref_details = { | |
| title: "Background Notifications", | |
| description: "Choose whether background notifications are enabled.", | |
| }; | |
| window.settingsBoilerplate(backgroundPref_details).appendTo(backgroundPref); | |
| var backgroundPrefGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(backgroundPref); | |
| [0, 1].forEach(function(option, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container backgroundPrefSelection") | |
| .html(option === 1 ? "Enabled" : "Disabled"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "backgroundPref", | |
| value: option, | |
| checked: window.settings.backgroundNotifications === option ? "checked" : null, | |
| }) | |
| .click(option === 1 ? () => window.Notification.requestPermission() : null) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(backgroundPrefGrid); | |
| }); | |
| var tooltipPref = $("<div/>") | |
| .attr({ id: "settings_tooltipPref" }) | |
| .addClass("setting-container") | |
| .appendTo(tabGeneral); | |
| var tooltipPref_details = { | |
| title: "Tooltips", | |
| description: | |
| "Choose whether tooltips are rendered when hovering over tooltip-enabled content.", | |
| }; | |
| window.settingsBoilerplate(tooltipPref_details).appendTo(tooltipPref); | |
| var tooltipPrefGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(tooltipPref); | |
| var options = [0, 1]; | |
| options.forEach(function (option, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container tooltipPrefSelection") | |
| .html(option === 1 ? "Enabled" : "Disabled"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "tooltipPref", | |
| value: option, | |
| checked: settings.tpref === option ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(tooltipPrefGrid); | |
| }); | |
| var leaveSite = $("<div/>") | |
| .attr({ id: "settings_leaveSite" }) | |
| .addClass("setting-container") | |
| .appendTo(tabGeneral); | |
| var leaveSite_details = { | |
| title: "End Session Confirmation", | |
| description: | |
| "Will prompt you with a confirmation before closing the window or tab. Changes will take affect on next session.", | |
| }; | |
| window.settingsBoilerplate(leaveSite_details).appendTo(leaveSite); | |
| var leaveSiteGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(leaveSite); | |
| var leaveSiteOptions = [0, 1]; | |
| leaveSiteOptions.forEach(function (option, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container leaveSiteSelection") | |
| .html(option === 1 ? "Enabled" : "Disabled"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "leaveSite", | |
| value: option, | |
| checked: settings.leavesite === option ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(leaveSiteGrid); | |
| }); | |
| var animPref = $("<div/>") | |
| .attr({ id: "settings_animPref" }) | |
| .addClass("setting-container") | |
| .appendTo(tabGeneral); | |
| var animPref_details = { | |
| title: "Animations", | |
| description: | |
| "Choose whether animations are played when navigating through content.", | |
| }; | |
| window.settingsBoilerplate(animPref_details).appendTo(animPref); | |
| var animPrefGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(animPref); | |
| var anims = [0, 1]; | |
| anims.forEach(function (anim, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container animPrefSelection") | |
| .html(anim === 1 ? "Enabled" : "Disabled"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "animPref", | |
| value: anim, | |
| checked: settings.animations === anim ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(animPrefGrid); | |
| }); | |
| var gpuEffectsPref = $("<div/>") | |
| .attr({ id: "settings_gpuEffectsPref" }) | |
| .addClass("setting-container") | |
| .appendTo(tabGeneral); | |
| var gpuEffectsPref_details = { | |
| title: "GPU Effects", | |
| description: | |
| "Choose whether some GPU-intensive effects like background blurs are utilized.", | |
| }; | |
| window.settingsBoilerplate(gpuEffectsPref_details).appendTo(gpuEffectsPref); | |
| var gpuEffectsPrefGrid = $("<div/>") | |
| .addClass("selections-grid") | |
| .appendTo(gpuEffectsPref); | |
| var gpuEffects = [0, 1]; | |
| gpuEffects.forEach(function (effect, i) { | |
| var label = $("<label/>") | |
| .addClass("selection-container gpuEffectsPrefSelection") | |
| .html(effect === 1 ? "Enabled" : "Disabled"); | |
| $("<input/>") | |
| .attr({ | |
| type: "radio", | |
| name: "gpuEffectsPref", | |
| value: effect, | |
| checked: settings.gpuEffects === effect ? "checked" : null, | |
| }) | |
| .appendTo(label); | |
| $("<span/>").addClass("selection").appendTo(label); | |
| label.appendTo(gpuEffectsPrefGrid); | |
| }); | |
| var clearSettings = $("<div/>") | |
| .attr({ id: "settings_clearSettings" }) | |
| .addClass("setting-container") | |
| .appendTo(tabGeneral); | |
| var clearSettings_details = { | |
| title: "Reset All Settings", | |
| description: | |
| "Reset your settings to default values for this browser only. This will reload the game but your progress will not be reset.", | |
| }; | |
| window.settingsBoilerplate(clearSettings_details).appendTo(clearSettings); | |
| $("<button/>") | |
| .attr({ id: "clearSettings" }) | |
| .addClass("actionButton") | |
| .html("Reset All Settings") | |
| .appendTo(clearSettings); | |
| return dialogActions; | |
| } else { | |
| return old.apply(old, arguments); | |
| } | |
| } | |
| let oldRenderToast = window.ToastManager.renderToast; | |
| window.ToastManager.renderToast = function() { | |
| if (window.settings.backgroundNotifications && document.hidden && window.Notification.permission === 'granted') { | |
| let toast = window.ToastManager.idToToast(arguments[0]); | |
| let title = toast.title; | |
| let body = toast.description; | |
| if (arguments[1]) { | |
| title = title.replace("{0}", arguments[1]); | |
| body = body.replace("{0}", arguments[1]); | |
| } | |
| if (arguments[2]) { | |
| title = title.replace("{1}", arguments[2]); | |
| body = body.replace("{1}", arguments[2]); | |
| } | |
| if (arguments[3]) { | |
| title = title.replace("{2}", arguments[3]); | |
| body = body.replace("{2}", arguments[3]); | |
| } | |
| let notification = new window.Notification(title, { | |
| body: body | |
| }); | |
| setTimeout(() => notification.close(), window.ToastManager.toastDuration); | |
| } | |
| return oldRenderToast.bind(window.ToastManager).apply(oldRenderToast, arguments); | |
| } | |
| })(window.jQuery, window, document); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment