`
const pluginsTable = document.querySelector("#plugin-manager-section .plugins-table")
const pluginNotificationTable = document.querySelector("#plugin-notification-list .notifications-table")
const pluginNoNotification = document.querySelector("#plugin-notification-list .no-notification")
/* notification center */
const pluginNotificationButton = document.getElementById("plugin-notification-button");
const pluginNotificationList = document.getElementById("plugin-notification-list");
const notificationPill = document.getElementById("notification-pill");
const pluginManagerSection = document.getElementById("plugin-manager-section");
let pluginNotifications;
// Add event listener to show/hide the action center
pluginNotificationButton.addEventListener("click", function () {
// Hide the notification pill when the action center is opened
notificationPill.style.display = "none"
pluginNotifications.lastUpdated = Date.now()
// save the notifications
setStorageData('notifications', JSON.stringify(pluginNotifications))
renderPluginNotifications()
if (pluginNotificationList.style.display === "none") {
pluginNotificationList.style.display = "block"
pluginManagerSection.style.display = "none"
} else {
pluginNotificationList.style.display = "none"
pluginManagerSection.style.display = "block"
}
})
document.addEventListener("tabClick", (e) => {
if (e.detail.name == 'plugin') {
pluginNotificationList.style.display = "none"
pluginManagerSection.style.display = "block"
}
})
async function addPluginNotification(pluginNotifications, messageText, error) {
const now = Date.now()
pluginNotifications.entries.unshift({ date: now, text: messageText, error: error }); // add new entry to the beginning of the array
if (pluginNotifications.entries.length > 50) {
pluginNotifications.entries.length = 50 // limit array length to 50 entries
}
pluginNotifications.lastUpdated = now
notificationPill.style.display = "block"
// save the notifications
await setStorageData('notifications', JSON.stringify(pluginNotifications))
}
function timeAgo(inputDate) {
const now = new Date();
const date = new Date(inputDate);
const diffInSeconds = Math.floor((now - date) / 1000);
const units = [
{ name: 'year', seconds: 31536000 },
{ name: 'month', seconds: 2592000 },
{ name: 'week', seconds: 604800 },
{ name: 'day', seconds: 86400 },
{ name: 'hour', seconds: 3600 },
{ name: 'minute', seconds: 60 },
{ name: 'second', seconds: 1 }
];
for (const unit of units) {
const unitValue = Math.floor(diffInSeconds / unit.seconds);
if (unitValue > 0) {
return `${unitValue} ${unit.name}${unitValue > 1 ? 's' : ''} ago`;
}
}
return 'just now';
}
function convertSeconds(seconds) {
const hours = Math.floor(seconds / 3600);
const minutes = Math.floor((seconds % 3600) / 60);
const remainingSeconds = seconds % 60;
let timeParts = [];
if (hours === 1) {
timeParts.push(`${hours} hour`);
} else if (hours > 1) {
timeParts.push(`${hours} hours`);
}
if (minutes === 1) {
timeParts.push(`${minutes} minute`);
} else if (minutes > 1) {
timeParts.push(`${minutes} minutes`);
}
if (remainingSeconds === 1) {
timeParts.push(`${remainingSeconds} second`);
} else if (remainingSeconds > 1) {
timeParts.push(`${remainingSeconds} seconds`);
}
return timeParts.join(', and ');
}
function renderPluginNotifications() {
pluginNotificationTable.innerHTML = ''
if (pluginNotifications.entries?.length > 0) {
pluginNoNotification.style.display = "none"
pluginNotificationTable.style.display = "block"
}
else {
pluginNoNotification.style.display = "block"
pluginNotificationTable.style.display = "none"
}
for (let i = 0; i < pluginNotifications.entries?.length; i++) {
const date = pluginNotifications.entries[i].date
const text = pluginNotifications.entries[i].text
const error = pluginNotifications.entries[i].error
const newRow = document.createElement('div')
newRow.innerHTML = `
${text}
${timeAgo(date)}
`;
pluginNotificationTable.appendChild(newRow)
}
}
/* search box */
function filterPlugins() {
let search = pluginFilter.value.toLowerCase();
let searchTerms = search.split(' ');
let labels = pluginsTable.querySelectorAll("label.plugin-name");
for (let i = 0; i < labels.length; i++) {
let label = labels[i].innerText.toLowerCase();
let match = true;
for (let j = 0; j < searchTerms.length; j++) {
let term = searchTerms[j].trim();
if (term && label.indexOf(term) === -1) {
match = false;
break;
}
}
if (match) {
labels[i].closest('.plugin-container').style.display = "flex";
} else {
labels[i].closest('.plugin-container').style.display = "none";
}
}
}
// Call debounce function on filterImageModifierList function with 200ms wait time. Thanks JeLuf!
const debouncedFilterPlugins = debounce(filterPlugins, 200);
// add the searchbox
pluginsTable.insertAdjacentHTML('beforebegin', ``)
const pluginFilter = document.getElementById("plugin-filter") // search box
// Add the debounced function to the keyup event listener
pluginFilter.addEventListener('keyup', debouncedFilterPlugins);
// select the text on focus
pluginFilter.addEventListener('focus', function (event) {
pluginFilter.select()
});
// empty the searchbox on escape
pluginFilter.addEventListener('keydown', function (event) {
if (event.key === 'Escape') {
pluginFilter.value = '';
filterPlugins();
}
});
// focus on the search box upon tab selection
document.addEventListener("tabClick", (e) => {
if (e.detail.name == 'plugin') {
pluginFilter.focus()
}
})
// refresh link
pluginsTable.insertAdjacentHTML('afterend', `
(Plugin developers, add your plugins to plugins.json)
`)
const refreshPlugins = document.getElementById("refresh-plugins")
refreshPlugins.addEventListener("click", async function (event) {
event.preventDefault()
await initPlugins(true)
})
function showPluginToast(message, duration = 5000, error = false, addNotification = true) {
if (addNotification === true) {
addPluginNotification(pluginNotifications, message, error)
}
try {
showToast(message, duration, error)
} catch (error) {
console.error('Error while trying to show toast:', error);
}
}
function matchPluginFileNames(fileName1, fileName2) {
const regex = /^(.+?)(?:-\d+(\.\d+)*)?\.plugin\.js$/;
const match1 = fileName1.match(regex);
const match2 = fileName2.match(regex);
if (match1 && match2 && match1[1] === match2[1]) {
return true; // the two file names match
} else {
return false; // the two file names do not match
}
}
function extractFilename(filepath) {
// Normalize the path separators to forward slashes and make the file names lowercase
const normalizedFilePath = filepath.replace(/\\/g, "/").toLowerCase();
// Strip off the path from the file name
const fileName = normalizedFilePath.substring(normalizedFilePath.lastIndexOf("/") + 1);
return fileName
}
function checkFileNameInArray(paths, filePath) {
// Strip off the path from the file name
const fileName = extractFilename(filePath);
// Check if the file name exists in the array of paths
return paths.some(path => {
// Strip off the path from the file name
const baseName = extractFilename(path);
// Check if the file names match and return the result as a boolean
return matchPluginFileNames(fileName, baseName);
});
}
function isGitHub(url) {
return url.startsWith("https://raw.githubusercontent.com/") === true
}
/* fill in the plugins table */
function getIncompatiblePlugins(pluginId) {
const enabledPlugins = plugins.filter(plugin => plugin.enabled && plugin.id !== pluginId);
const incompatiblePlugins = enabledPlugins.filter(plugin => plugin.compatIssueIds?.includes(pluginId));
const pluginNames = incompatiblePlugins.map(plugin => plugin.name);
if (pluginNames.length === 0) {
return null;
}
const pluginNamesList = pluginNames.map(name => `