diff options
| author | Hazelnoot <acomputerdog@gmail.com> | 2025-05-10 22:32:19 -0400 |
|---|---|---|
| committer | Hazelnoot <acomputerdog@gmail.com> | 2025-05-10 22:32:19 -0400 |
| commit | 32b860c352615d3c2d0902c1efeb24aee30a09cf (patch) | |
| tree | 9697ccfe48b1c555e54cdd7f560f626ef3988a27 | |
| parent | allow checkWordMute to accept raw strings (diff) | |
| download | sharkey-32b860c352615d3c2d0902c1efeb24aee30a09cf.tar.gz sharkey-32b860c352615d3c2d0902c1efeb24aee30a09cf.tar.bz2 sharkey-32b860c352615d3c2d0902c1efeb24aee30a09cf.zip | |
add UI for testing word mutes
| -rw-r--r-- | locales/index.d.ts | 24 | ||||
| -rw-r--r-- | packages/frontend/src/pages/settings/mute-block.word-mute.vue | 105 | ||||
| -rw-r--r-- | sharkey-locales/en-US.yml | 7 |
3 files changed, 102 insertions, 34 deletions
diff --git a/locales/index.d.ts b/locales/index.d.ts index 9679cc3acf..2beb0ae454 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -12969,6 +12969,30 @@ export interface Locale extends ILocale { */ "text": string; }; + /** + * Test word mutes + */ + "wordMuteTestLabel": string; + /** + * Enter some text here to test your word mute patterns. The matched words, if any, will be displayed below. + */ + "wordMuteTestDescription": string; + /** + * Test + */ + "wordMuteTestTest": string; + /** + * Matched words: {words} + */ + "wordMuteTestMatch": ParameterizedString<"words">; + /** + * No results yet, enter some text and click "Test" to check it. + */ + "wordMuteTestNoResults": string; + /** + * Text does not match any word mutes. + */ + "wordMuteTestNoMatch": string; } declare const locales: { [lang: string]: Locale; diff --git a/packages/frontend/src/pages/settings/mute-block.word-mute.vue b/packages/frontend/src/pages/settings/mute-block.word-mute.vue index f5837abe98..52aa2ff230 100644 --- a/packages/frontend/src/pages/settings/mute-block.word-mute.vue +++ b/packages/frontend/src/pages/settings/mute-block.word-mute.vue @@ -11,16 +11,33 @@ SPDX-License-Identifier: AGPL-3.0-only <template #caption>{{ i18n.ts._wordMute.muteWordsDescription }}<br>{{ i18n.ts._wordMute.muteWordsDescription2 }}</template> </MkTextarea> </div> + + <MkFolder> + <template #label>{{ i18n.ts.wordMuteTestLabel }}</template> + + <div class="_gaps"> + <MkTextarea v-model="testWords"> + <template #caption>{{ i18n.ts.wordMuteTestDescription }}</template> + </MkTextarea> + <div><MkButton :disabled="!testWords" @click="testWordMutes">{{ i18n.ts.wordMuteTestTest }}</MkButton></div> + <div v-if="testMatches == null">{{ i18n.ts.wordMuteTestNoResults}}</div> + <div v-else-if="testMatches === ''">{{ i18n.ts.wordMuteTestNoMatch }}</div> + <div v-else>{{ i18n.tsx.wordMuteTestMatch({ words: testMatches }) }}</div> + </div> + </MkFolder> + <MkButton primary inline :disabled="!changed" @click="save()"><i class="ti ti-device-floppy"></i> {{ i18n.ts.save }}</MkButton> </div> </template> <script lang="ts" setup> -import { ref, watch } from 'vue'; +import { computed, ref, watch } from 'vue'; import MkTextarea from '@/components/MkTextarea.vue'; import MkButton from '@/components/MkButton.vue'; import * as os from '@/os.js'; import { i18n } from '@/i18n.js'; +import MkFolder from '@/components/MkFolder.vue'; +import { checkWordMute } from '@/utility/check-word-mute'; const props = defineProps<{ muted: (string[] | string)[]; @@ -30,7 +47,7 @@ const emit = defineEmits<{ (ev: 'save', value: (string[] | string)[]): void; }>(); -const render = (mutedWords) => mutedWords.map(x => { +const render = (mutedWords: (string | string[])[]) => mutedWords.map(x => { if (Array.isArray(x)) { return x.join(' '); } else { @@ -40,53 +57,73 @@ const render = (mutedWords) => mutedWords.map(x => { const mutedWords = ref(render(props.muted)); const changed = ref(false); +const testWords = ref<string | null>(null); + +const testMatches = ref<string | null>(null); computed(() => { +}); watch(mutedWords, () => { changed.value = true; }); -async function save() { - const parseMutes = (mutes) => { - // split into lines, remove empty lines and unnecessary whitespace - let lines = mutes.trim().split('\n').map(line => line.trim()).filter(line => line !== ''); +function parseMutes(mutes: string) { + // split into lines, remove empty lines and unnecessary whitespace + const lines = mutes.trim().split('\n').map(line => line.trim()).filter(line => line !== ''); + const outLines = Array.from(lines) as (string | string[])[]; - // check each line if it is a RegExp or not - for (let i = 0; i < lines.length; i++) { - const line = lines[i]; - const regexp = line.match(/^\/(.+)\/(.*)$/); - if (regexp) { - // check that the RegExp is valid - try { - new RegExp(regexp[1], regexp[2]); - // note that regex lines will not be split by spaces! - } catch (err: any) { - // invalid syntax: do not save, do not reset changed flag - os.alert({ - type: 'error', - title: i18n.ts.regexpError, - text: i18n.tsx.regexpErrorDescription({ tab: 'word mute', line: i + 1 }) + '\n' + err.toString(), - }); - // re-throw error so these invalid settings are not saved - throw err; - } - } else { - lines[i] = line.split(' '); + // check each line if it is a RegExp or not + for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + const regexp = line.match(/^\/(.+)\/(.*)$/); + if (regexp) { + // check that the RegExp is valid + try { + new RegExp(regexp[1], regexp[2]); + // note that regex lines will not be split by spaces! + } catch (err: any) { + // invalid syntax: do not save, do not reset changed flag + os.alert({ + type: 'error', + title: i18n.ts.regexpError, + text: i18n.tsx.regexpErrorDescription({ tab: 'word mute', line: i + 1 }) + '\n' + err.toString(), + }); + // re-throw error so these invalid settings are not saved + throw err; } + } else { + outLines[i] = line.split(' '); } + } - return lines; - }; + return outLines; +} - let parsed; +async function save() { try { - parsed = parseMutes(mutedWords.value); - } catch (err) { + const parsed = parseMutes(mutedWords.value); + + emit('save', parsed); + + changed.value = false; + } catch { // already displayed error message in parseMutes return; } +} - emit('save', parsed); +function testWordMutes() { + if (!testWords.value || !mutedWords.value) { + testMatches.value = null; + return; + } - changed.value = false; + try { + const mutes = parseMutes(mutedWords.value); + const matches = checkWordMute(testWords.value, null, mutes); + testMatches.value = matches ? matches.flat(2).join(', ') : ''; + } catch { + // Error is displayed by above function + testMatches.value = null; + } } </script> diff --git a/sharkey-locales/en-US.yml b/sharkey-locales/en-US.yml index 034d995b01..a42486c4d1 100644 --- a/sharkey-locales/en-US.yml +++ b/sharkey-locales/en-US.yml @@ -543,3 +543,10 @@ enableProxyAccountDescription: "If disabled, then the proxy account will not be _confirmPollEdit: title: Are you sure you want to edit this poll text: Editing this poll will cause it to lose all previous votes + +wordMuteTestLabel: "Test word mutes" +wordMuteTestDescription: "Enter some text here to test your word mute patterns. The matched words, if any, will be displayed below." +wordMuteTestTest: "Test" +wordMuteTestMatch: "Matched words: {words}" +wordMuteTestNoResults: "No results yet, enter some text and click \"Test\" to check it." +wordMuteTestNoMatch: "Text does not match any word mutes." |