From f2972c0800b1b5c35361eb4a3da7491ee92f79f0 Mon Sep 17 00:00:00 2001 From: cyrilchukwuebuka Date: Sat, 1 Apr 2023 22:58:09 +0100 Subject: [PATCH] settings: Fixed spellchecker language selection --- app/renderer/css/preference.css | 14 +- .../js/pages/preference/general-section.ts | 174 +++++++++++------- 2 files changed, 106 insertions(+), 82 deletions(-) diff --git a/app/renderer/css/preference.css b/app/renderer/css/preference.css index 89f1c0436..39ef594b3 100644 --- a/app/renderer/css/preference.css +++ b/app/renderer/css/preference.css @@ -372,6 +372,7 @@ img.server-info-icon { margin: 6px; } +.note, #note { font-size: 10px; } @@ -742,6 +743,8 @@ i.open-network-button { .lang-menu { font-size: 13px; + padding-left: 6px; + padding-right: 6px; font-weight: bold; background: rgb(78 191 172 / 100%); width: 100px; @@ -749,14 +752,3 @@ i.open-network-button { color: rgb(255 255 255 / 100%); border-color: rgb(0 0 0 / 0%); } - -/* stylelint-disable-next-line selector-class-pattern */ -.tagify__input { - min-width: 130px !important; -} - -/* stylelint-disable-next-line selector-class-pattern */ -.tagify__input::before { - top: 0; - bottom: 0; -} diff --git a/app/renderer/js/pages/preference/general-section.ts b/app/renderer/js/pages/preference/general-section.ts index 3ebcd5e3d..1b094aa37 100644 --- a/app/renderer/js/pages/preference/general-section.ts +++ b/app/renderer/js/pages/preference/general-section.ts @@ -5,9 +5,7 @@ import process from "node:process"; import * as remote from "@electron/remote"; import {app, dialog, session} from "@electron/remote"; -import Tagify from "@yaireo/tagify"; import ISO6391 from "iso-639-1"; -import {z} from "zod"; import supportedLocales from "../../../../../public/translations/supported-locales.json"; import * as ConfigUtil from "../../../../common/config-util.js"; @@ -133,13 +131,29 @@ export function initGeneralSection({$root}: GeneralSectionProps): void {
+ > +
+
+ ${t.__("Spellchecker Languages")} +
+
+
+
+
-
${t.__("Advanced")}
@@ -148,14 +162,12 @@ export function initGeneralSection({$root}: GeneralSectionProps): void {
-
${t.__("App language (requires restart)")}
-
${t.__("Add custom CSS")}
@@ -428,11 +440,12 @@ export function initGeneralSection({$root}: GeneralSectionProps): void { ConfigUtil.setConfigItem("enableSpellchecker", newValue); ipcRenderer.send("configure-spell-checker"); enableSpellchecker(); - const spellcheckerLanguageInput: HTMLElement = - $root.querySelector("#spellcheck-langs")!; + const spellcheckerLanguageDiv: HTMLElement = $root.querySelector( + "#spellcheck-langs-container", + )!; const spellcheckerNote: HTMLElement = $root.querySelector("#note")!; - spellcheckerLanguageInput.style.display = - spellcheckerLanguageInput.style.display === "none" ? "" : "none"; + spellcheckerLanguageDiv.style.display = + spellcheckerLanguageDiv.style.display === "none" ? "" : "none"; spellcheckerNote.style.display = spellcheckerNote.style.display === "none" ? "" : "none"; }, @@ -470,7 +483,7 @@ export function initGeneralSection({$root}: GeneralSectionProps): void { } function setLocale(): void { - const langDiv: HTMLSelectElement = $root.querySelector(".lang-div")!; + const langDiv: HTMLSelectElement = $root.querySelector("#lang-div")!; const langListHtml = generateSelectHtml(supportedLocales, "lang-menu"); langDiv.innerHTML += langListHtml.html; // `langMenu` is the select-option dropdown menu formed after executing the previous command @@ -591,6 +604,29 @@ export function initGeneralSection({$root}: GeneralSectionProps): void { }); } + // Filters out old selections, leaving the 3 most recent selected languages + function selectedLanguages( + value: string, + spellcheckerLanguages: string[], + ): string[] { + const languageSet = new Set(spellcheckerLanguages); + languageSet.add(value); + if (languageSet.size <= 3) { + return [...languageSet]; + } + + const trimmedSpellcheckerLanguages = [...languageSet].slice( + languageSet.size - 3, + ); + return trimmedSpellcheckerLanguages; + } + + function mapIsoToLanguage(languagePairs: Record): string[] { + const langsIso = + ConfigUtil.getConfigItem("spellcheckerLanguages", []) ?? []; + return langsIso.map((iso) => languagePairs[iso]); + } + function initSpellChecker(): void { // The elctron API is a no-op on macOS and macOS default spellchecker is used. if (process.platform === "darwin") { @@ -607,84 +643,80 @@ export function initGeneralSection({$root}: GeneralSectionProps): void { note.append( t.__("You can select a maximum of 3 languages for spellchecking."), ); - const spellDiv: HTMLElement = $root.querySelector("#spellcheck-langs")!; - spellDiv.innerHTML += html` -
${t.__("Spellchecker Languages")}
- - `.html; const availableLanguages = session.fromPartition( "persist:webviewsession", ).availableSpellCheckerLanguages; - let languagePairs = new Map(); + const languagePairs: Record = {}; for (const l of availableLanguages) { if (ISO6391.validate(l)) { - languagePairs.set(ISO6391.getName(l), l); + languagePairs[l] = ISO6391.getName(l); } } // Manually set names for languages not available in ISO6391 - languagePairs.set("English (AU)", "en-AU"); - languagePairs.set("English (CA)", "en-CA"); - languagePairs.set("English (GB)", "en-GB"); - languagePairs.set("English (US)", "en-US"); - languagePairs.set("Spanish (Latin America)", "es-419"); - languagePairs.set("Spanish (Argentina)", "es-AR"); - languagePairs.set("Spanish (Mexico)", "es-MX"); - languagePairs.set("Spanish (US)", "es-US"); - languagePairs.set("Portuguese (Brazil)", "pt-BR"); - languagePairs.set("Portuguese (Portugal)", "pt-PT"); - languagePairs.set("Serbo-Croatian", "sh"); - - languagePairs = new Map( - [...languagePairs].sort((a, b) => (a[0] < b[0] ? -1 : 1)), + languagePairs["en-AU"] = "English (AU)"; + languagePairs["en-CA"] = "English (CA)"; + languagePairs["en-GB"] = "English (GB)"; + languagePairs["en-US"] = "English (US)"; + languagePairs["es-419"] = "Spanish (Latin America)"; + languagePairs["es-AR"] = "Spanish (Argentina)"; + languagePairs["es-MX"] = "Spanish (Mexico)"; + languagePairs["es-US"] = "Spanish (US)"; + languagePairs["pt-BR"] = "Portuguese (Brazil)"; + languagePairs["pt-PT"] = "Portuguese (Portugal)"; + languagePairs.sh = "Serbo-Croatian"; + + const spellCheckerLangDiv: HTMLSelectElement = $root.querySelector( + "#spellcheck-lang-div", + )!; + const spellCheckerLangListHtml = generateSelectHtml( + languagePairs, + "lang-menu", + "spellchecker-lang-menu", ); - - const tagField: HTMLInputElement = $root.querySelector( - "input[name=spellcheck]", + spellCheckerLangDiv.innerHTML += spellCheckerLangListHtml.html; + // `spellcheckerlangMenu` is the select-option dropdown menu formed after executing the previous command + const spellcheckerlangMenu: HTMLSelectElement = $root.querySelector( + "#spellchecker-lang-menu", )!; - const tagify = new Tagify(tagField, { - whitelist: [...languagePairs.keys()], - enforceWhitelist: true, - maxTags: 3, - dropdown: { - enabled: 0, - maxItems: Number.POSITIVE_INFINITY, - closeOnSelect: false, - highlightFirst: true, - }, - }); - const configuredLanguages: string[] = ( - ConfigUtil.getConfigItem("spellcheckerLanguages", null) ?? [] - ).map( - (code: string) => - [...languagePairs].find((pair) => pair[1] === code)![0], + // The next three lines set the selected language visible on the dropdown button + let spellcheckerLanguages = + ConfigUtil.getConfigItem("spellcheckerLanguages", null) ?? []; + spellcheckerLanguages = spellcheckerLanguages.filter((language) => + spellcheckerlangMenu.options.namedItem(language), ); - tagify.addTags(configuredLanguages); - - tagField.addEventListener("change", () => { - if (tagField.value.length === 0) { - ConfigUtil.setConfigItem("spellcheckerLanguages", []); - ipcRenderer.send("configure-spell-checker"); - } else { - const data: unknown = JSON.parse(tagField.value); - const spellLangs: string[] = z - .array(z.object({value: z.string()})) - .parse(data) - .map((elt) => languagePairs.get(elt.value)!); - ConfigUtil.setConfigItem("spellcheckerLanguages", spellLangs); - ipcRenderer.send("configure-spell-checker"); - } + + for (const language of spellcheckerLanguages) { + spellcheckerlangMenu.options.namedItem(language)!.selected = true; + } + + const spellcheckerLangList: HTMLElement = $root.querySelector( + "#spellcheck-lang-list", + )!; + + spellcheckerLangList.textContent = + mapIsoToLanguage(languagePairs).join(", "); + + spellcheckerlangMenu.addEventListener("change", () => { + ConfigUtil.setConfigItem( + "spellcheckerLanguages", + selectedLanguages(spellcheckerlangMenu.value, spellcheckerLanguages), + ); + ipcRenderer.send("configure-spell-checker"); + spellcheckerLangList.textContent = + mapIsoToLanguage(languagePairs).join(", "); }); } // Do not display the spellchecker input and note if it is disabled if (!ConfigUtil.getConfigItem("enableSpellchecker", true)) { - const spellcheckerLanguageInput: HTMLElement = - $root.querySelector("#spellcheck-langs")!; + const spellcheckerLanguageDiv: HTMLElement = $root.querySelector( + "#spellcheck-langs-container", + )!; const spellcheckerNote: HTMLElement = $root.querySelector("#note")!; - spellcheckerLanguageInput.style.display = "none"; + spellcheckerLanguageDiv.style.display = "none"; spellcheckerNote.style.display = "none"; } }