diff --git a/modAssist_main.js b/modAssist_main.js index 507a9c8f..21ccdde7 100644 --- a/modAssist_main.js +++ b/modAssist_main.js @@ -174,6 +174,7 @@ const settingsSchema = { confirm : { type : 'object', default : {}, properties : winDef(750, 500), additionalProperties : false }, debug : { type : 'object', default : {}, properties : winDef(1000, 500), additionalProperties : false }, detail : { type : 'object', default : {}, properties : winDef(800, 500), additionalProperties : false }, + find : { type : 'object', default : {}, properties : winDef(800, 600), additionalProperties : false }, folder : { type : 'object', default : {}, properties : winDef(800, 500), additionalProperties : false }, main : { type : 'object', default : {}, properties : winDef(1000, 700), additionalProperties : false }, notes : { type : 'object', default : {}, properties : winDef(800, 500), additionalProperties : false }, @@ -225,6 +226,7 @@ const windows = { confirm : null, debug : null, detail : null, + find : null, folder : null, load : null, main : null, @@ -272,6 +274,11 @@ mcStore.set('cache_version', app.getVersion()) ( \/\/ )(_ _)( \( )( _ \ ( _ )( \/\/ )/ __) ) ( _)(_ ) ( )(_) ) )(_)( ) ( \__ \ (__/\__)(____)(_)\_)(____/ (_____)(__/\__)(___/ */ +function destroyAndFocus(winName) { + windows[winName] = null + if ( windows.main !== null ) { windows.main.focus() } +} + function getRealCenter(winName) { const realCenter = { x : null, y : null } const winSettings = mcStore.get(`wins.${winName}`) @@ -297,7 +304,7 @@ function createSubWindow(winName, {noSelect = true, show = true, parent = null, const winOptions = { minimizable : !fixed, - alwaysOnTop : fixed && !devDebug, + alwaysOnTop : fixed, maximizable : !fixed, fullscreenable : !fixed, } @@ -382,8 +389,10 @@ function createMainWindow () { } }) windows.main.on('closed', () => { + windows.main = null if ( tray ) { tray.destroy() } windows.load.destroy() + app.quit() }) if ( !devDebug ) { @@ -450,7 +459,7 @@ function createConfirmFav(mods, destinations) { windows.confirm.loadFile(path.join(pathRender, 'confirm-multi.html')) - windows.confirm.on('closed', () => { windows.confirm = null; windows.main.focus() }) + windows.confirm.on('closed', () => { destroyAndFocus('confirm') }) } function createConfirmWindow(type, modRecords, origList) { @@ -469,7 +478,7 @@ function createConfirmWindow(type, modRecords, origList) { windows.confirm.loadFile(path.join(pathRender, file_HTML)) - windows.confirm.on('closed', () => { windows.confirm = null; windows.main.focus() }) + windows.confirm.on('closed', () => { destroyAndFocus('confirm') }) } function createChangeLogWindow() { @@ -481,7 +490,7 @@ function createChangeLogWindow() { windows.change = createSubWindow('change', { parent : 'main', fixed : true, preload : 'aChangelogWindow' }) windows.change.loadFile(path.join(pathRender, 'a_changelog.html')) - windows.change.on('closed', () => { windows.change = null; windows.main.focus() }) + windows.change.on('closed', () => { destroyAndFocus('change') }) } function createFolderWindow() { @@ -498,7 +507,7 @@ function createFolderWindow() { }) windows.folder.loadFile(path.join(pathRender, 'folders.html')) - windows.folder.on('closed', () => { windows.folder = null; windows.main.focus(); processModFolders() }) + windows.folder.on('closed', () => { destroyAndFocus('folder'); processModFolders() }) } function createDetailWindow(thisModRecord) { @@ -519,7 +528,7 @@ function createDetailWindow(thisModRecord) { }) windows.detail.loadFile(path.join(pathRender, 'detail.html')) - windows.detail.on('closed', () => { windows.detail = null; windows.main.focus() }) + windows.detail.on('closed', () => { destroyAndFocus('detail') }) windows.detail.webContents.setWindowOpenHandler(({ url }) => { shell.openExternal(url) @@ -527,6 +536,24 @@ function createDetailWindow(thisModRecord) { }) } +function createFindWindow() { + if ( windows.find ) { + windows.find.focus() + windows.find.webContents.send('fromMain_modRecords', modList) + return + } + + windows.find = createSubWindow('find', { preload : 'findWindow' }) + + windows.find.webContents.on('did-finish-load', async (event) => { + event.sender.send('fromMain_modRecords', modList) + if ( devDebug ) { windows.find.webContents.openDevTools() } + }) + + windows.find.loadFile(path.join(pathRender, 'find.html')) + windows.find.on('closed', () => { destroyAndFocus('find') }) +} + function createDebugWindow() { if ( windows.debug ) { windows.debug.focus() @@ -534,14 +561,14 @@ function createDebugWindow() { return } - windows.debug = createSubWindow('debug', { parent : 'main', preload : 'debugWindow' }) + windows.debug = createSubWindow('debug', { preload : 'debugWindow' }) windows.debug.webContents.on('did-finish-load', (event) => { event.sender.send('fromMain_debugLog', log.htmlLog) }) windows.debug.loadFile(path.join(app.getAppPath(), 'renderer', 'debug.html')) - windows.debug.on('closed', () => { windows.debug = null; windows.main.focus() }) + windows.debug.on('closed', () => { destroyAndFocus('debug') }) } function createPrefsWindow() { @@ -558,7 +585,7 @@ function createPrefsWindow() { }) windows.prefs.loadFile(path.join(pathRender, 'prefs.html')) - windows.prefs.on('closed', () => { windows.prefs = null; windows.main.focus() }) + windows.prefs.on('closed', () => { destroyAndFocus('prefs') }) } function createSavegameWindow(collection) { @@ -576,7 +603,7 @@ function createSavegameWindow(collection) { }) windows.save.loadFile(path.join(pathRender, 'savegame.html')) - windows.save.on('closed', () => { windows.save = null; windows.main.focus() }) + windows.save.on('closed', () => { destroyAndFocus('save') }) } function createNotesWindow(collection) { @@ -594,7 +621,7 @@ function createNotesWindow(collection) { }) windows.notes.loadFile(path.join(pathRender, 'notes.html')) - windows.notes.on('closed', () => { windows.notes = null; windows.main.focus(); processModFolders() }) + windows.notes.on('closed', () => { destroyAndFocus('notes'); processModFolders() }) } function createResolveWindow(modSet, shortName) { @@ -612,7 +639,7 @@ function createResolveWindow(modSet, shortName) { }) windows.resolve.loadFile(path.join(pathRender, 'resolve.html')) - windows.resolve.on('closed', () => { windows.resolve = null; windows.version.focus() }) + windows.resolve.on('closed', () => { destroyAndFocus('resolve') }) } function createVersionWindow() { @@ -630,7 +657,7 @@ function createVersionWindow() { }) windows.version.loadFile(path.join(pathRender, 'versions.html')) - windows.version.on('closed', () => { windows.version = null; windows.main.focus() }) + windows.version.on('closed', () => { destroyAndFocus('version') }) } function loadingWindow_open(l10n) { @@ -908,6 +935,10 @@ ipcMain.on('toMain_startFarmSim', () => { }) /** END: game launcher */ +/** Find window operation */ +ipcMain.on('toMain_openFind', () => { createFindWindow() }) +/** END : Find window operation*/ + /** Preferences window operation */ ipcMain.on('toMain_openPrefs', () => { createPrefsWindow() }) ipcMain.on('toMain_getPref', (event, name) => { event.returnValue = mcStore.get(name) }) diff --git a/renderer/find.html b/renderer/find.html new file mode 100644 index 00000000..9f347f86 --- /dev/null +++ b/renderer/find.html @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + +
+
+
+
+

+
+
+
+
+
+
+ +
+ + + +
+ +
+
+ + + \ No newline at end of file diff --git a/renderer/main.html b/renderer/main.html index d6152701..b1e15485 100644 --- a/renderer/main.html +++ b/renderer/main.html @@ -93,19 +93,16 @@
-

+

+ +

+
-
-
-
- -
-
- -
-
+
+ +
+
+
diff --git a/renderer/preload/preload-findWindow.js b/renderer/preload/preload-findWindow.js new file mode 100644 index 00000000..13ae6c0f --- /dev/null +++ b/renderer/preload/preload-findWindow.js @@ -0,0 +1,52 @@ +/* _______ __ _______ __ __ + | | |.-----.--| | _ |.-----.-----.|__|.-----.| |_ + | || _ | _ | ||__ --|__ --|| ||__ --|| _| + |__|_|__||_____|_____|___|___||_____|_____||__||_____||____| + (c) 2022-present FSG Modding. MIT License. */ + +// Detail window preLoad + +const {contextBridge, ipcRenderer} = require('electron') + +contextBridge.exposeInMainWorld( + 'log', { + log : (text, process) => { ipcRenderer.send('toMain_log', 'debug', `render-${process}`, text) }, + debug : (text, process) => { ipcRenderer.send('toMain_log', 'debug', `render-${process}`, text) }, + info : (text, process) => { ipcRenderer.send('toMain_log', 'info', `render-${process}`, text) }, + notice : (text, process) => { ipcRenderer.send('toMain_log', 'notice', `render-${process}`, text) }, + warning : (text, process) => { ipcRenderer.send('toMain_log', 'warning', `render-${process}`, text) }, + danger : (text, process) => { ipcRenderer.send('toMain_log', 'danger', `render-${process}`, text) }, + } +) + +contextBridge.exposeInMainWorld( + 'l10n', { + getText_send : ( text ) => { ipcRenderer.send('toMain_getText_send', text) }, + receive : ( channel, func ) => { + const validChannels = [ + 'fromMain_getText_return', + 'fromMain_getText_return_title', + 'fromMain_l10n_refresh' + ] + + if ( validChannels.includes( channel ) ) { + ipcRenderer.on( channel, ( event, ...args ) => func( ...args )) + } + }, + } +) + +contextBridge.exposeInMainWorld( + 'mods', { + closeWindow : ( ) => { ipcRenderer.send('toMain_closeSubWindow', 'find') }, + receive : ( channel, func ) => { + const validChannels = [ + 'fromMain_modRecords', + ] + + if ( validChannels.includes( channel ) ) { + ipcRenderer.on( channel, ( event, ...args ) => func( ...args )) + } + }, + } +) \ No newline at end of file diff --git a/renderer/preload/preload-mainWindow.js b/renderer/preload/preload-mainWindow.js index b53a5f12..4377c620 100644 --- a/renderer/preload/preload-mainWindow.js +++ b/renderer/preload/preload-mainWindow.js @@ -43,6 +43,7 @@ contextBridge.exposeInMainWorld( 'mods', { startFarmSim : () => { ipcRenderer.send('toMain_startFarmSim') }, openPreferences : () => { ipcRenderer.send('toMain_openPrefs') }, + openFindAll : () => { ipcRenderer.send('toMain_openFind') }, addFolder : () => { ipcRenderer.send('toMain_addFolder') }, editFolders : () => { ipcRenderer.send('toMain_editFolders') }, refreshFolders : () => { ipcRenderer.send('toMain_refreshFolders') }, diff --git a/renderer/renderJS/find_ui.js b/renderer/renderJS/find_ui.js new file mode 100644 index 00000000..7d0de3a6 --- /dev/null +++ b/renderer/renderJS/find_ui.js @@ -0,0 +1,138 @@ +/* _______ __ _______ __ __ + | | |.-----.--| | _ |.-----.-----.|__|.-----.| |_ + | || _ | _ | ||__ --|__ --|| ||__ --|| _| + |__|_|__||_____|_____|___|___||_____|_____||__||_____||____| + (c) 2022-present FSG Modding. MIT License. */ + +// Main Window UI + +/* global l10n, fsgUtil, bootstrap*/ + + +/* __ ____ ______ + | |_ | | |.-----. + | |_| |_| -- || | + |__|______|______||__|__| */ + +function processL10N() { clientGetL10NEntries() } +function clientChangeL10N() { l10n.langList_change(fsgUtil.byId('language_select').value) } +function clientGetL10NEntries() { + const l10nSendItems = new Set() + + fsgUtil.query('l10n').forEach((thisL10nItem) => { + l10nSendItems.add(fsgUtil.getAttribNullError(thisL10nItem, 'name')) + }) + + l10n.getText_send(l10nSendItems) +} + +window.l10n.receive('fromMain_langList_return', (listData, selected) => { + fsgUtil.byId('language_select').innerHTML = listData.map((x) => { + return fsgUtil.buildSelectOpt(x[0], x[1], selected) + }).join('') +}) +window.l10n.receive('fromMain_getText_return', (data) => { + fsgUtil.query(`l10n[name="${data[0]}"]`).forEach((item) => { item.innerHTML = data[1] }) +}) +window.l10n.receive('fromMain_getText_return_title', (data) => { + fsgUtil.query(`l10n[name="${data[0]}"]`).forEach((item) => { + const buttonItem = item.closest('button') + if ( buttonItem !== null ) { + buttonItem.title = data[1] + new bootstrap.Tooltip(buttonItem) + } else { + item.parentElement.title = data[1] + new bootstrap.Tooltip(item.parentElement) + } + }) +}) +window.l10n.receive('fromMain_l10n_refresh', () => { processL10N() }) + +let fullList = {} +let fullListSort = [] + +window.mods.receive('fromMain_modRecords', (modList) => { + fullList = {} + Object.keys(modList).forEach((collection) => { + + modList[collection].mods.forEach((mod) => { + if ( ! mod.canNotUse ) { + fullList[mod.fileDetail.shortName] ??= { + name : mod.fileDetail.shortName, + title : mod.l10n.title, + author : mod.modDesc.author, + icon : mod.modDesc.iconImageCache, + collect : [], + } + fullList[mod.fileDetail.shortName].collect.push({ + version : mod.modDesc.version, + name : modList[collection].name, + }) + } + }) + }) + + fullListSort = Object.keys(fullList).sort( (a, b) => { + if (a.toLowerCase() < b.toLowerCase()) return -1 + if (a.toLowerCase() > b.toLowerCase()) return 1 + return 0 + }) + + const modTable = [] + + fullListSort.forEach((key) => { + modTable.push(makeModRow(fullList[key])) + }) + + fsgUtil.byId('full_table').innerHTML = modTable.join('') +}) + + +function makeModRow(thisMod) { + const id = `${thisMod.name}__mod` + const versions = [] + + thisMod.collect.forEach((collection) => { + versions.push(`
${collection.name}
${collection.version}
`) + }) + + return ` + + + + +
${thisMod.name}
${thisMod.title} - ${thisMod.author}
+ + +
${versions.join('')}
+ +` +} + +function clientClearInput() { + fsgUtil.byId('mods__filter').value = '' + clientFilter() +} + +function clientFilter() { + const filterText = fsgUtil.byId('mods__filter').value.toLowerCase() + + fsgUtil.byId('mods__filter_clear').classList[( filterText !== '' ) ? 'remove':'add']('d-none') + + fsgUtil.byId('full_table').querySelectorAll('tr').forEach((element) => { + element.classList.remove('d-none') + if ( filterText.length > 1 ) { + const searchText = element.querySelector('.search-string').innerText.toLowerCase() + if ( !searchText.includes(filterText) ) { + element.classList.add('d-none') + } + } + }) +} + +window.addEventListener('DOMContentLoaded', () => { processL10N() }) + +window.addEventListener('click', () => { + fsgUtil.query('.tooltip').forEach((tooltip) => { tooltip.remove() }) +}) + diff --git a/translations/de.json b/translations/de.json index 0fe4945e..dcaf9b24 100644 --- a/translations/de.json +++ b/translations/de.json @@ -260,5 +260,8 @@ "user_pref_blurb_reset_window": "Mod Assistant speichert die Position, Größe und den maximierten Zustand aller Fenster. Verwenden Sie die Schaltfläche unten, um bei Bedarf auf die Standardeinstellungen zurückzusetzen", "user_pref_button_reset_window": "Alle Fenster zurücksetzen", "loading_zip_subtitle": "Bitte warten Sie, das kann eine Minute dauern", - "loading_zip_title": "Mods entpacken" + "loading_zip_title": "Mods entpacken", + "search_all": "", + "search_all__title": "Suche in allen Sammlungen", + "search_all_window": "Alle finden" } \ No newline at end of file diff --git a/translations/en.json b/translations/en.json index 78af8002..b928dcf9 100644 --- a/translations/en.json +++ b/translations/en.json @@ -260,5 +260,8 @@ "user_pref_blurb_reset_window" : "Mod Assistant saves the location, size, and maximized state of all it's windows. Use the button below to reset to the defaults if needed", "user_pref_button_reset_window" : "Reset All Windows", "loading_zip_subtitle" : "Please wait, this could take a minute", - "loading_zip_title" : "Unzipping Mods" + "loading_zip_title" : "Unzipping Mods", + "search_all" : "", + "search_all__title" : "Search in all Collections", + "search_all_window" : "Find All" } \ No newline at end of file diff --git a/translations/es.json b/translations/es.json index ee1baec8..c1e968d0 100644 --- a/translations/es.json +++ b/translations/es.json @@ -260,5 +260,8 @@ "user_pref_blurb_reset_window": "Mod Assistant guarda la ubicación, el tamaño y el estado maximizado de todas sus ventanas. Utiliza el botón de abajo para restablecer los valores predeterminados si es necesario", "user_pref_button_reset_window": "Restablecer todas las ventanas", "loading_zip_subtitle": "Por favor, espere, esto puede tardar un minuto", - "loading_zip_title": "Descomprimiendo Mods" + "loading_zip_title": "Descomprimiendo Mods", + "search_all": "", + "search_all__title": "Buscar en todas las colecciones", + "search_all_window": "Buscar todo" } \ No newline at end of file diff --git a/translations/fr.json b/translations/fr.json index f56d0d6d..5fc7d33b 100644 --- a/translations/fr.json +++ b/translations/fr.json @@ -260,5 +260,8 @@ "user_pref_blurb_reset_window": "Mod Assistant enregistre l'emplacement, la taille et l'état maximisé de toutes ses fenêtres. Utilisez le bouton ci-dessous pour rétablir les valeurs par défaut si nécessaire", "user_pref_button_reset_window": "Réinitialiser toutes les fenêtres", "loading_zip_subtitle": "Veuillez patienter, cela peut prendre une minute", - "loading_zip_title": "Dézipper les mods" + "loading_zip_title": "Dézipper les mods", + "search_all": "", + "search_all__title": "Recherche dans toutes les collections", + "search_all_window": "Trouver tout" } \ No newline at end of file diff --git a/translations/nl.json b/translations/nl.json index 5123bfb8..cfb2f78e 100644 --- a/translations/nl.json +++ b/translations/nl.json @@ -260,5 +260,8 @@ "user_pref_blurb_reset_window": "Mod Assistant bewaart de locatie, grootte en gemaximaliseerde status van alle vensters. Gebruik de onderstaande knop om de standaardwaarden te herstellen indien nodig", "user_pref_button_reset_window": "Reset alle vensters", "loading_zip_subtitle": "Wacht even, dit kan even duren", - "loading_zip_title": "Mods uitpakken" + "loading_zip_title": "Mods uitpakken", + "search_all": "", + "search_all__title": "Zoeken in alle collecties", + "search_all_window": "Alles vinden" } \ No newline at end of file diff --git a/translations/pl.json b/translations/pl.json index 172fc658..d74c035d 100644 --- a/translations/pl.json +++ b/translations/pl.json @@ -260,5 +260,8 @@ "user_pref_blurb_reset_window": "Mod Assistant zapisuje lokalizację, rozmiar i zmaksymalizowany stan wszystkich swoich okien. Użyj poniższego przycisku, aby w razie potrzeby przywrócić ustawienia domyślne", "user_pref_button_reset_window": "Resetuj wszystkie okna", "loading_zip_subtitle": "Proszę czekać, to może potrwać minutę", - "loading_zip_title": "Rozpakowywanie modów" + "loading_zip_title": "Rozpakowywanie modów", + "search_all": "", + "search_all__title": "Szukaj we wszystkich zbiorach", + "search_all_window": "Znajdź wszystkie" } \ No newline at end of file diff --git a/translations/ru.json b/translations/ru.json index a827919c..2539f1b4 100644 --- a/translations/ru.json +++ b/translations/ru.json @@ -260,5 +260,8 @@ "user_pref_blurb_reset_window": "Mod Assistant сохраняет местоположение, размер и развёрнутое состояние всех своих окон. Используйте кнопку ниже, чтобы сбросить на настройки по умолчанию, если это необходимо", "user_pref_button_reset_window": "Сбросить изменения всех окон", "loading_zip_subtitle": "Пожалуйста, подождите, это может занять минуту", - "loading_zip_title": "Распаковка модов" + "loading_zip_title": "Распаковка модов", + "search_all": "", + "search_all__title": "Поиск во всех коллекциях", + "search_all_window": "Найти все" } \ No newline at end of file