mirror of https://github.com/GooseMod/GooseMod
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
615 lines
16 KiB
615 lines
16 KiB
import * as GoosemodChangelog from '../goosemodChangelog';
|
|
|
|
export default (goosemodScope, gmSettings, Items) => {
|
|
let oldItems = goosemodScope.settings.items;
|
|
goosemodScope.settings.items = [];
|
|
|
|
goosemodScope.settings.createHeading('GooseMod');
|
|
|
|
const changeSetting = async (key, value) => {
|
|
switch (key) {
|
|
case 'changelog': {
|
|
if (value) {
|
|
const items = [
|
|
['item', goosemodScope.i18n.discordStrings.CHANGE_LOG, [''], async () => {
|
|
GoosemodChangelog.show();
|
|
}, false]
|
|
];
|
|
|
|
if (gmSettings.get().separators) items.unshift(['separator']);
|
|
|
|
goosemodScope.settings.items.splice(goosemodScope.settings.items.indexOf(goosemodScope.settings.items.find(x => x[1] === 'Themes')) + 1, 0,
|
|
...items
|
|
);
|
|
} else {
|
|
goosemodScope.settings.items.splice(goosemodScope.settings.items.indexOf(goosemodScope.settings.items.find(x => x[1] === 'Change Log')), gmSettings.get().separators ? 2 : 1);
|
|
}
|
|
|
|
await goosemodScope.settings.reopenSettings();
|
|
goosemodScope.settings.openSettingItem('Settings');
|
|
|
|
break;
|
|
}
|
|
|
|
case 'devchannel': {
|
|
if (value) {
|
|
goosemod.storage.set('goosemodUntetheredBranch', 'dev');
|
|
} else {
|
|
goosemod.storage.remove('goosemodUntetheredBranch');
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case 'separators': {
|
|
if (value) {
|
|
if (!gmSettings.get().home) goosemod.settings.items.splice(2, 0, ['separator']);
|
|
if (gmSettings.get().changelog) goosemod.settings.items.splice(4, 0, ['separator']);
|
|
} else {
|
|
let main = true;
|
|
|
|
goosemodScope.settings.items = goosemodScope.settings.items.filter((x, i) => {
|
|
if (goosemodScope.settings.items[i + 1] && goosemodScope.settings.items[i + 1][1] && goosemodScope.settings.items[i + 1][1] === 'GooseMod Modules') main = false;
|
|
|
|
return !(x[0] === 'separator' && main);
|
|
});
|
|
}
|
|
|
|
await goosemodScope.settings.reopenSettings();
|
|
goosemodScope.settings.openSettingItem('Settings');
|
|
|
|
break;
|
|
}
|
|
|
|
case 'gmBadges': {
|
|
goosemodScope.gmBadges[value ? 'addBadges' : 'removeBadges']();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
gmSettings.set(key, value);
|
|
};
|
|
|
|
const refreshPrompt = async () => {
|
|
if (await goosemodScope.confirmDialog('Refresh', 'Refresh Required', 'This setting **requires a refresh to take effect**. You **may experience some strange behaviour** in this session before refreshing.')) {
|
|
location.reload();
|
|
}
|
|
};
|
|
|
|
let settingDebugShowing = false;
|
|
|
|
goosemodScope.settings.createItem(goosemodScope.i18n.discordStrings.SETTINGS, ['',
|
|
{
|
|
type: 'header',
|
|
text: 'Settings'
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
text: 'GooseMod Change Log',
|
|
subtext: 'Show GooseMod "Change Log" setting',
|
|
|
|
onToggle: (c) => changeSetting('changelog', c),
|
|
isToggled: () => gmSettings.get().changelog
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
text: 'Main Separators',
|
|
subtext: 'Show separators between main GooseMod settings',
|
|
|
|
onToggle: (c) => changeSetting('separators', c),
|
|
isToggled: () => gmSettings.get().separators
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
experimental: true,
|
|
text: 'Force Theme Settings',
|
|
subtext: 'Force auto-generated settings for all themes',
|
|
|
|
onToggle: (c) => {
|
|
changeSetting('allThemeSettings', c);
|
|
refreshPrompt();
|
|
},
|
|
isToggled: () => gmSettings.get().allThemeSettings
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
text: 'Store In Home',
|
|
subtext: 'Put GooseMod Store options in home instead of in settings',
|
|
|
|
onToggle: (c) => {
|
|
changeSetting('home', c);
|
|
refreshPrompt();
|
|
},
|
|
isToggled: () => gmSettings.get().home
|
|
},
|
|
|
|
{
|
|
type: 'header',
|
|
text: 'Store'
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
text: 'Auto Update',
|
|
subtext: 'Automatically update repos and modules every hour',
|
|
|
|
onToggle: (c) => changeSetting('autoupdate', c),
|
|
isToggled: () => gmSettings.get().autoupdate
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
experimental: true,
|
|
text: 'Snippets',
|
|
subtext: 'Enable Snippets tab in Store',
|
|
|
|
onToggle: (c) => {
|
|
changeSetting('snippets', c);
|
|
refreshPrompt();
|
|
},
|
|
isToggled: () => gmSettings.get().snippets
|
|
},
|
|
|
|
{
|
|
type: 'header',
|
|
text: 'Internals'
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
experimental: true,
|
|
text: 'Development Channel',
|
|
subtext: 'Use experimental development GooseMod builds',
|
|
|
|
onToggle: (c) => {
|
|
changeSetting('devchannel', c);
|
|
refreshPrompt();
|
|
},
|
|
isToggled: () => goosemod.storage.get('goosemodUntetheredBranch') === 'dev'
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
experimental: true,
|
|
text: 'Data Attributes',
|
|
subtext: 'Add data attributes to some elements for some themes to use',
|
|
|
|
onToggle: (c) => {
|
|
changeSetting('attrs', c);
|
|
refreshPrompt();
|
|
},
|
|
isToggled: () => gmSettings.get().attrs
|
|
},
|
|
|
|
{
|
|
type: 'header',
|
|
text: 'Appearance'
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
text: 'GooseMod Badges',
|
|
subtext: 'Shows GooseMod\'s badges',
|
|
|
|
onToggle: (c) => changeSetting('gmBadges', c),
|
|
isToggled: () => gmSettings.get().gmBadges
|
|
},
|
|
|
|
{
|
|
type: 'header',
|
|
text: 'Utilities'
|
|
},
|
|
|
|
{
|
|
type: 'text-and-danger-button',
|
|
|
|
text: 'Reset GooseMod',
|
|
subtext: 'Resets GooseMod completely: removes all preferences and modules; like a first-time install',
|
|
buttonText: 'Reset',
|
|
|
|
onclick: async () => {
|
|
if (await goosemodScope.confirmDialog('Reset', 'Reset GooseMod', 'Confirming will completely reset GooseMod, removing all preferences and modules; as if you had installed GooseMod for the first time. This is irreversible.')) {
|
|
goosemodScope.remove();
|
|
window.location.reload();
|
|
}
|
|
}
|
|
},
|
|
|
|
{
|
|
type: 'text-and-button',
|
|
|
|
text: 'Purge Caches',
|
|
subtext: 'Purges (completely removes) most caches GooseMod uses',
|
|
buttonText: 'Purge',
|
|
|
|
onclick: async () => {
|
|
// Like remove's dynamic local storage removal, but only remove GooseMod keys with "Cache" in
|
|
goosemod.storage.keys().filter((x) => x.toLowerCase().startsWith('goosemod') && x.includes('Cache')).forEach((x) => goosemod.storage.remove(x));
|
|
|
|
refreshPrompt();
|
|
}
|
|
},
|
|
|
|
{
|
|
type: 'text-and-button',
|
|
|
|
text: 'Start Tour',
|
|
subtext: 'Go through GooseMod\'s startup tour again',
|
|
buttonText: 'Tour',
|
|
|
|
onclick: async () => {
|
|
goosemodScope.ootb.start();
|
|
}
|
|
},
|
|
|
|
{
|
|
type: 'header',
|
|
text: 'Backup'
|
|
},
|
|
|
|
{
|
|
type: 'text-and-button',
|
|
|
|
text: 'Create Backup',
|
|
subtext: 'Creates a file for backup of your GooseMod modules and settings',
|
|
buttonText: 'Backup',
|
|
|
|
onclick: () => {
|
|
const obj = goosemod.storage.keys().filter((x) => x.toLowerCase().startsWith('goosemod') && !x.includes('Cache')).reduce((acc, k) => {
|
|
acc[k] = goosemod.storage.get(k);
|
|
return acc;
|
|
}, {});
|
|
|
|
const toSave = JSON.stringify(obj);
|
|
|
|
const el = document.createElement("a");
|
|
el.style.display = 'none';
|
|
|
|
const file = new Blob([ toSave ], { type: 'application/json' });
|
|
|
|
el.href = URL.createObjectURL(file);
|
|
el.download = `goosemodBackup.json`;
|
|
|
|
document.body.appendChild(el);
|
|
|
|
el.click();
|
|
|
|
el.remove();
|
|
}
|
|
},
|
|
|
|
{
|
|
type: 'text-and-button',
|
|
|
|
text: 'Restore Backup',
|
|
subtext: 'Restore your GooseMod modules and settings via a backup file, **only restore backups you trust**',
|
|
buttonText: 'Restore',
|
|
|
|
onclick: async () => {
|
|
const el = document.createElement('input');
|
|
el.style.display = 'none';
|
|
el.type = 'file';
|
|
|
|
el.click();
|
|
|
|
await new Promise((res) => { el.onchange = () => { res(); }; });
|
|
|
|
const file = el.files[0];
|
|
if (!file) return;
|
|
|
|
const reader = new FileReader();
|
|
|
|
reader.onload = () => {
|
|
const obj = JSON.parse(reader.result);
|
|
|
|
for (const k in obj) {
|
|
if (!k.startsWith('goosemod')) continue; // Don't set if not goosemod key for some security
|
|
|
|
goosemod.storage.set(k, obj[k]);
|
|
}
|
|
|
|
location.reload();
|
|
};
|
|
|
|
reader.readAsText(file);
|
|
}
|
|
},
|
|
|
|
{
|
|
type: 'header',
|
|
text: 'Debug',
|
|
experimental: true
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
debug: true,
|
|
text: 'Add Debug Setting',
|
|
subtext: 'Shows debug setting to test settings (per session, refresh to remove)',
|
|
|
|
onToggle: () => {
|
|
settingDebugShowing = true;
|
|
|
|
goosemodScope.settings.createItem('Debug', ['',
|
|
...Object.keys(Items).filter((x) => x !== 'card').map((x) => ({
|
|
type: x,
|
|
|
|
text: x,
|
|
label: x,
|
|
|
|
subtext: 'subtext',
|
|
|
|
buttonText: 'button text',
|
|
placeholder: 'placeholder',
|
|
|
|
initialValue: () => 'value',
|
|
options: ['option 1', 'option 2', 'option 3'],
|
|
isToggled: () => true,
|
|
|
|
sort: () => 0,
|
|
|
|
element: () => {
|
|
const el = document.createElement('div');
|
|
el.textContent = 'element text content';
|
|
return el;
|
|
}
|
|
}))
|
|
]);
|
|
},
|
|
isToggled: () => settingDebugShowing,
|
|
disabled: () => settingDebugShowing
|
|
},
|
|
|
|
{
|
|
type: 'toggle',
|
|
|
|
debug: true,
|
|
text: 'Show Debug Toasts',
|
|
subtext: 'Shows some debug toasts on some events',
|
|
|
|
onToggle: (c) => changeSetting('debugToasts', c),
|
|
isToggled: () => gmSettings.get().debugToasts
|
|
},
|
|
|
|
{ type: 'gm-footer' }
|
|
]);
|
|
|
|
if (gmSettings.get().separators && !gmSettings.get().home) goosemodScope.settings.createSeparator();
|
|
|
|
let sortedVal = 'Stars';
|
|
let authorVal = 'All';
|
|
let searchQuery = '';
|
|
|
|
const updateModuleStoreUI = () => {
|
|
const cards = document.getElementsByClassName('gm-store-card');
|
|
|
|
const fuzzyReg = new RegExp(`.*${searchQuery}.*`, 'i');
|
|
|
|
const importedVal = document.querySelector('.selected-3s45Ha').textContent;
|
|
|
|
for (let c of cards) {
|
|
const titles = c.getElementsByClassName('title-31JmR4');
|
|
|
|
const title = titles[1];
|
|
|
|
const authors = [...titles[0].getElementsByClassName('author')].map((x) => x.textContent.split('#')[0]);
|
|
const name = title.childNodes[0].wholeText;
|
|
|
|
const description = c.getElementsByClassName('description-3_Ncsb')[0].innerText;
|
|
|
|
const matches = (fuzzyReg.test(name) || fuzzyReg.test(description));
|
|
|
|
const importedSelector = !c.getElementsByClassName('container-3auIfb')[0].classList.contains('hide-toggle') ? 'Imported' : 'Store';
|
|
|
|
// const tags = [...c.classList].map((t) => t.replace(/\|/g, ' ').toLowerCase());
|
|
|
|
switch (sortedVal) {
|
|
case 'A-Z': { // Already pre-sorted to A-Z
|
|
c.style.order = '';
|
|
|
|
break;
|
|
}
|
|
|
|
case 'Last Updated': {
|
|
const module = goosemodScope.moduleStoreAPI.modules.find((x) => x.name === name.trim());
|
|
|
|
c.style.order = 3000000000 - module.lastUpdated;
|
|
|
|
break;
|
|
}
|
|
|
|
case 'Stars': {
|
|
c.style.order = 10000 - parseInt(c.children[4].children[0].children[0].textContent);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
c.style.display = matches
|
|
&& (importedVal === 'Store' || importedVal === importedSelector)
|
|
&& (authorVal === 'All' || authors.includes(authorVal.split(' (').slice(0, -1).join(' (')))
|
|
? 'block' : 'none';
|
|
}
|
|
|
|
const noInput = searchQuery === '' && importedVal === 'Store' && authorVal === 'All';
|
|
|
|
[...document.getElementsByClassName('gm-store-category')].forEach((x) => x.style.display = noInput ? 'block' : 'none');
|
|
|
|
// Keep all header but make height 0 so it breaks flex row
|
|
const allHeader = document.querySelector(':not(.gm-store-category) > .gm-store-header');
|
|
|
|
allHeader.style.height = !noInput ? '0px' : '';
|
|
allHeader.style.opacity = !noInput ? '0' : '';
|
|
allHeader.style.margin = !noInput ? '0' : '';
|
|
};
|
|
|
|
goosemodScope.settings.updateModuleStoreUI = updateModuleStoreUI;
|
|
|
|
const genCurrentDate = new Date();
|
|
|
|
const upcomingVal = (x) => {
|
|
const daysSinceUpdate = (genCurrentDate - (x.lastUpdated * 1000)) / 1000 / 60 / 60 / 24;
|
|
|
|
return (x.github.stars / daysSinceUpdate) - (x.github.stars / 2) + (1 - daysSinceUpdate);
|
|
};
|
|
|
|
[goosemodScope.i18n.goosemodStrings.settings.itemNames.plugins, goosemodScope.i18n.goosemodStrings.settings.itemNames.themes].forEach((x) => goosemodScope.settings.createItem(x, ['',
|
|
{
|
|
type: 'search',
|
|
|
|
placeholder: `${goosemodScope.i18n.discordStrings.SEARCH} ${x}`,
|
|
|
|
onchange: (query) => {
|
|
searchQuery = query;
|
|
|
|
updateModuleStoreUI();
|
|
},
|
|
|
|
storeSpecific: true
|
|
},
|
|
|
|
{
|
|
type: 'dropdown-individual',
|
|
|
|
label: 'Sort by',
|
|
|
|
options: [
|
|
'Stars',
|
|
'A-Z',
|
|
'Last Updated'
|
|
],
|
|
|
|
onchange: (val) => {
|
|
sortedVal = val;
|
|
|
|
updateModuleStoreUI();
|
|
}
|
|
},
|
|
|
|
{
|
|
type: 'dropdown-individual',
|
|
|
|
label: 'Author',
|
|
|
|
options: () => {
|
|
const idCache = goosemodScope.moduleStoreAPI.idCache.getCache();
|
|
|
|
const authors = [...goosemodScope.moduleStoreAPI.modules.reduce((acc, x) => {
|
|
let authors = x.authors;
|
|
|
|
if (!Array.isArray(authors)) authors = [ authors ];
|
|
|
|
for (const a of authors) {
|
|
let key = a;
|
|
|
|
if (typeof a === 'object') {
|
|
key = a.n;
|
|
} else if (a.match(/^[0-9]{17,18}$/)) {
|
|
key = idCache[a]?.data?.username;
|
|
} else {
|
|
const idMatch = a.match(/(.*) \(([0-9]{17,18})\)/); // "<name> (<id>)"
|
|
|
|
if (idMatch !== null) {
|
|
key = idMatch[1];
|
|
}
|
|
}
|
|
|
|
if (!key) continue;
|
|
|
|
acc.set(key, (acc.get(key) || 0) + 1);
|
|
}
|
|
|
|
return acc;
|
|
}, new Map()).entries()].sort((a, b) => b[1] - a[1]).map((x) => `${x[0]} (${x[1]})`);
|
|
|
|
authors.unshift('All');
|
|
|
|
return authors;
|
|
},
|
|
|
|
onchange: (val) => {
|
|
authorVal = val;
|
|
|
|
updateModuleStoreUI();
|
|
}
|
|
},
|
|
|
|
{
|
|
type: 'store-category',
|
|
text: 'Top Starred',
|
|
sort: (a, b) => b.github.stars - a.github.stars
|
|
},
|
|
|
|
{
|
|
type: 'store-category',
|
|
text: 'Recently Updated',
|
|
sort: (a, b) => b.lastUpdated - a.lastUpdated
|
|
},
|
|
|
|
{
|
|
type: 'store-category',
|
|
text: 'Upcoming',
|
|
sort: (a, b) => upcomingVal(b) - upcomingVal(a)
|
|
},
|
|
|
|
{
|
|
type: 'store-header',
|
|
text: `All ${x}`
|
|
},
|
|
|
|
{ type: 'gm-footer' }
|
|
]));
|
|
|
|
goosemodScope.settings.createItem('Snippets', ['',
|
|
{
|
|
type: 'search',
|
|
|
|
placeholder: 'Search Snippets',
|
|
|
|
onchange: (query) => {
|
|
const cards = document.getElementsByClassName('gm-store-card');
|
|
|
|
const fuzzyReg = new RegExp(`.*${query}.*`, 'i');
|
|
|
|
for (const c of cards) {
|
|
const description = c.getElementsByClassName('markdown-11q6EU')[0].textContent;
|
|
|
|
const matches = (fuzzyReg.test(description));
|
|
|
|
c.style.display = matches ? '' : 'none';
|
|
}
|
|
},
|
|
|
|
storeSpecific: true
|
|
}
|
|
]);
|
|
|
|
if (gmSettings.get().changelog) {
|
|
if (gmSettings.get().separators) goosemodScope.settings.createSeparator();
|
|
|
|
goosemodScope.settings.createItem(goosemodScope.i18n.discordStrings.CHANGE_LOG, [""], async () => {
|
|
GoosemodChangelog.show();
|
|
});
|
|
}
|
|
|
|
goosemodScope.settings.createSeparator();
|
|
|
|
goosemodScope.settings.createHeading(goosemodScope.i18n.goosemodStrings.settings.itemNames.goosemodModules);
|
|
|
|
goosemodScope.settings.items = goosemodScope.settings.items.concat(oldItems);
|
|
}; |