Skip to content

Instantly share code, notes, and snippets.

@kdmcclel
Last active June 20, 2024 18:42
Show Gist options
  • Select an option

  • Save kdmcclel/ebff9f99ded58fa1d15752062c70792c to your computer and use it in GitHub Desktop.

Select an option

Save kdmcclel/ebff9f99ded58fa1d15752062c70792c to your computer and use it in GitHub Desktop.
// ==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