mirror of
https://github.com/ksyasuda/SubMiner.git
synced 2026-02-27 18:22:41 -08:00
195 lines
8.1 KiB
JavaScript
195 lines
8.1 KiB
JavaScript
/*
|
|
* Copyright (C) 2024-2025 Yomitan Authors
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
import {fetchJson} from '../../core/fetch-utilities.js';
|
|
import {log} from '../../core/log.js';
|
|
import {querySelectorNotNull} from '../../dom/query-selector.js';
|
|
|
|
export class RecommendedSettingsController {
|
|
/**
|
|
* @param {import('./settings-controller.js').SettingsController} settingsController
|
|
*/
|
|
constructor(settingsController) {
|
|
/** @type {import('./settings-controller.js').SettingsController} */
|
|
this._settingsController = settingsController;
|
|
/** @type {HTMLElement} */
|
|
this._recommendedSettingsModal = querySelectorNotNull(document, '#recommended-settings-modal');
|
|
/** @type {HTMLInputElement} */
|
|
this._languageSelect = querySelectorNotNull(document, '#language-select');
|
|
/** @type {HTMLInputElement} */
|
|
this._applyButton = querySelectorNotNull(document, '#recommended-settings-apply-button');
|
|
/** @type {Map<string, import('settings-controller').RecommendedSetting>} */
|
|
this._recommendedSettings = new Map();
|
|
}
|
|
|
|
/** */
|
|
async prepare() {
|
|
this._languageSelect.addEventListener('change', this._onLanguageSelectChanged.bind(this), false);
|
|
this._applyButton.addEventListener('click', this._onApplyButtonClicked.bind(this), false);
|
|
}
|
|
|
|
/**
|
|
* @param {Event} _e
|
|
*/
|
|
async _onLanguageSelectChanged(_e) {
|
|
const setLanguage = this._languageSelect.value;
|
|
if (typeof setLanguage !== 'string') { return; }
|
|
|
|
const recommendedSettings = await this._getRecommendedSettings(setLanguage);
|
|
if (typeof recommendedSettings !== 'undefined') {
|
|
const settingsList = querySelectorNotNull(document, '#recommended-settings-list');
|
|
settingsList.innerHTML = '';
|
|
this._recommendedSettings = new Map();
|
|
|
|
for (const [index, setting] of recommendedSettings.entries()) {
|
|
this._recommendedSettings.set(index.toString(), setting);
|
|
|
|
const {description} = setting;
|
|
const template = this._settingsController.instantiateTemplate('recommended-settings-list-item');
|
|
|
|
// Render label
|
|
this._renderLabel(template, setting);
|
|
|
|
// Render description
|
|
const descriptionElement = querySelectorNotNull(template, '.settings-item-description');
|
|
if (description !== 'undefined') {
|
|
descriptionElement.textContent = description;
|
|
}
|
|
|
|
// Render checkbox
|
|
const checkbox = /** @type {HTMLInputElement} */ (querySelectorNotNull(template, 'input[type="checkbox"]'));
|
|
checkbox.value = index.toString();
|
|
|
|
settingsList.append(template);
|
|
}
|
|
this._recommendedSettingsModal.hidden = false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {string} language
|
|
* @returns {Promise<import('settings-controller').RecommendedSetting[]>}
|
|
*/
|
|
async _getRecommendedSettings(language) {
|
|
if (typeof this._recommendedSettingsByLanguage === 'undefined') {
|
|
/** @type {import('settings-controller').RecommendedSettingsByLanguage} */
|
|
this._recommendedSettingsByLanguage = await fetchJson('/data/recommended-settings.json');
|
|
}
|
|
|
|
return this._recommendedSettingsByLanguage[language];
|
|
}
|
|
|
|
/**
|
|
* @param {MouseEvent} e
|
|
*/
|
|
_onApplyButtonClicked(e) {
|
|
e.preventDefault();
|
|
/** @type {NodeListOf<HTMLInputElement>} */
|
|
const enabledCheckboxes = querySelectorNotNull(document, '#recommended-settings-list').querySelectorAll('input[type="checkbox"]:checked');
|
|
if (enabledCheckboxes.length > 0) {
|
|
const modifications = [];
|
|
for (const checkbox of enabledCheckboxes) {
|
|
const index = checkbox.value;
|
|
const setting = this._recommendedSettings.get(index);
|
|
if (typeof setting === 'undefined') { continue; }
|
|
modifications.push(setting.modification);
|
|
}
|
|
void this._settingsController.modifyProfileSettings(modifications).then(
|
|
(results) => {
|
|
for (const result of results) {
|
|
if (Object.hasOwn(result, 'error')) {
|
|
log.error(new Error(`Failed to apply recommended setting: ${JSON.stringify(result)}`));
|
|
}
|
|
}
|
|
},
|
|
);
|
|
void this._settingsController.refresh();
|
|
}
|
|
this._recommendedSettingsModal.hidden = true;
|
|
}
|
|
|
|
/**
|
|
* @param {Element} template
|
|
* @param {import('settings-controller').RecommendedSetting} setting
|
|
*/
|
|
_renderLabel(template, setting) {
|
|
const label = querySelectorNotNull(template, '.settings-item-label');
|
|
|
|
const {modification} = setting;
|
|
switch (modification.action) {
|
|
case 'set': {
|
|
const {path, value} = modification;
|
|
const pathCodeElement = document.createElement('code');
|
|
pathCodeElement.textContent = path;
|
|
const valueCodeElement = document.createElement('code');
|
|
valueCodeElement.textContent = JSON.stringify(value, null, 2);
|
|
|
|
label.appendChild(document.createTextNode('Setting '));
|
|
label.appendChild(pathCodeElement);
|
|
label.appendChild(document.createTextNode(' = '));
|
|
label.appendChild(valueCodeElement);
|
|
break;
|
|
}
|
|
case 'delete': {
|
|
const {path} = modification;
|
|
const pathCodeElement = document.createElement('code');
|
|
pathCodeElement.textContent = path;
|
|
|
|
label.appendChild(document.createTextNode('Deleting '));
|
|
label.appendChild(pathCodeElement);
|
|
break;
|
|
}
|
|
case 'swap': {
|
|
const {path1, path2} = modification;
|
|
const path1CodeElement = document.createElement('code');
|
|
path1CodeElement.textContent = path1;
|
|
const path2CodeElement = document.createElement('code');
|
|
path2CodeElement.textContent = path2;
|
|
|
|
label.appendChild(document.createTextNode('Swapping '));
|
|
label.appendChild(path1CodeElement);
|
|
label.appendChild(document.createTextNode(' and '));
|
|
label.appendChild(path2CodeElement);
|
|
break;
|
|
}
|
|
case 'splice': {
|
|
const {path, start, deleteCount, items} = modification;
|
|
const pathCodeElement = document.createElement('code');
|
|
pathCodeElement.textContent = path;
|
|
|
|
label.appendChild(document.createTextNode('Splicing '));
|
|
label.appendChild(pathCodeElement);
|
|
label.appendChild(document.createTextNode(` at ${start} deleting ${deleteCount} items and inserting ${items.length} items`));
|
|
break;
|
|
}
|
|
case 'push': {
|
|
const {path, items} = modification;
|
|
const pathCodeElement = document.createElement('code');
|
|
pathCodeElement.textContent = path;
|
|
|
|
label.appendChild(document.createTextNode(`Pushing ${items.length} items to `));
|
|
label.appendChild(pathCodeElement);
|
|
break;
|
|
}
|
|
default: {
|
|
log.error(new Error(`Unknown modification: ${modification}`));
|
|
}
|
|
}
|
|
}
|
|
}
|