diff --git a/app/assets/javascripts/admin/addon/controllers/modals/admin-watched-word-test.js b/app/assets/javascripts/admin/addon/controllers/modals/admin-watched-word-test.js index 3ce120419c0..3ea2618acb2 100644 --- a/app/assets/javascripts/admin/addon/controllers/modals/admin-watched-word-test.js +++ b/app/assets/javascripts/admin/addon/controllers/modals/admin-watched-word-test.js @@ -18,33 +18,45 @@ export default Controller.extend(ModalFunctionality, { ) matches(value, regexpString, words, isReplace, isTag, isLink) { if (!value || !regexpString) { - return; + return []; } - const regexp = new RegExp(regexpString, "ig"); - const matches = value.match(regexp) || []; - if (isReplace || isLink) { - return matches.map((match) => ({ - match, - replacement: words.find((word) => - new RegExp(word.regexp, "ig").test(match) - ).replacement, - })); - } else if (isTag) { - return matches.map((match) => { - const tags = new Set(); - - words.forEach((word) => { - if (new RegExp(word.regexp, "ig").test(match)) { - word.replacement.split(",").forEach((tag) => tags.add(tag)); - } - }); - - return { match, tags: Array.from(tags) }; + const matches = []; + words.forEach((word) => { + const regexp = new RegExp(word.regexp, "gi"); + let match; + while ((match = regexp.exec(value)) !== null) { + matches.push({ + match: match[1], + replacement: word.replacement, + }); + } }); - } + return matches; + } else if (isTag) { + const matches = {}; + words.forEach((word) => { + const regexp = new RegExp(word.regexp, "gi"); + let match; + while ((match = regexp.exec(value)) !== null) { + if (!matches[match[1]]) { + matches[match[1]] = new Set(); + } - return matches; + let tags = matches[match[1]]; + word.replacement.split(",").forEach((tag) => { + tags.add(tag); + }); + } + }); + + return Object.entries(matches).map((entry) => ({ + match: entry[0], + tags: Array.from(entry[1]), + })); + } else { + return value.match(new RegExp(regexpString, "ig")) || []; + } }, }); diff --git a/app/assets/javascripts/admin/addon/templates/watched-words-action.hbs b/app/assets/javascripts/admin/addon/templates/watched-words-action.hbs index 005e4b759b0..6860ac16d3d 100644 --- a/app/assets/javascripts/admin/addon/templates/watched-words-action.hbs +++ b/app/assets/javascripts/admin/addon/templates/watched-words-action.hbs @@ -26,6 +26,10 @@ <p class="about">{{actionDescription}}</p> +{{#if siteSettings.watched_words_regular_expressions}} + <p>{{html-safe (i18n "admin.watched_words.regex_warning" basePath=(base-path))}}</p> +{{/if}} + {{watched-word-form actionKey=actionNameKey action=(action "recordAdded") diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index c4a18377be1..ca725af3940 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4752,6 +4752,7 @@ en: clear_all: Clear All clear_all_confirm: "Are you sure you want to clear all watched words for the %{action} action?" invalid_regex: 'The watched word "%{word}" is an invalid regular expression.' + regex_warning: '<a href="%{basePath}/admin/site_settings/category/all_results?filter=watched%20words%20regular%20expressions%20">Watched words are regular expressions</a> and they do not automatically include word boundaries. If you want the regular expression to match whole words, include <code>\b</code> at the start and end of your regular expression.' actions: block: "Block" censor: "Censor"