Merge pull request #3648 from SillyTavern/regex-info-block Add info block for find regex flags
Signed| @@ -16,6 +16,13 @@ | ||
| 16 | 16 | </small> |
| 17 | 17 | <hr /> |
| 18 | 18 | |
| 19 | + <div id="regex_info_block_wrapper"> | |
| 20 | + <div id="regex_info_block" class="info-block"></div> | |
| 21 | + <a id="regex_info_block_flags_hint" href="http://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_expressions#advanced_searching_with_flags" target="_blank" rel="noopener noreferrer"> | |
| 22 | + <i class="fa-solid fa-circle-info" title="Click here to learn more about regex flags."></i> | |
| 23 | + </a> | |
| 24 | + </div> | |
| 25 | + | |
| 19 | 26 | <div id="regex_test_mode" class="flex1 flex-container displayNone"> |
| 20 | 27 | <div class="flex1"> |
| 21 | 28 | <label class="title_restorable" for="regex_test_input"> |
| @@ -7,7 +7,7 @@ import { ARGUMENT_TYPE, SlashCommandArgument, SlashCommandNamedArgument } from ' | ||
| 7 | 7 | import { enumIcons } from '../../slash-commands/SlashCommandCommonEnumsProvider.js'; |
| 8 | 8 | import { SlashCommandEnumValue, enumTypes } from '../../slash-commands/SlashCommandEnumValue.js'; |
| 9 | 9 | import { SlashCommandParser } from '../../slash-commands/SlashCommandParser.js'; |
| 10 | 10 | import { download, getFileText, getSortableDelay, regexFromString, setInfoBlock, uuidv4 } from '../../utils.js'; |
| 11 | 11 | import { regex_placement, runRegexScript, substitute_find_regex } from './engine.js'; |
| 12 | 12 | import { t } from '../../i18n.js'; |
| 13 | 13 | import { accountStorage } from '../../util/AccountStorage.js'; |
| @@ -258,6 +258,8 @@ async function onRegexEditorOpenClick(existingId, isScoped) { | ||
| 258 | 258 | }); |
| 259 | 259 | |
| 260 | 260 | function updateTestResult() { |
| 261 | + updateInfoBlock(editorHtml); | |
| 262 | + | |
| 261 | 263 | if (!editorHtml.find('#regex_test_mode').is(':visible')) { |
| 262 | 264 | return; |
| 263 | 265 | } |
| @@ -276,6 +278,7 @@ async function onRegexEditorOpenClick(existingId, isScoped) { | ||
| 276 | 278 | } |
| 277 | 279 | |
| 278 | 280 | editorHtml.find('input, textarea, select').on('input', updateTestResult); |
| 281 | + updateInfoBlock(editorHtml); | |
| 279 | 282 | |
| 280 | 283 | const popupResult = await callPopup(editorHtml, 'confirm', undefined, { okButton: t`Save` }); |
| 281 | 284 | if (popupResult) { |
| @@ -305,6 +308,40 @@ async function onRegexEditorOpenClick(existingId, isScoped) { | ||
| 305 | 308 | } |
| 306 | 309 | } |
| 307 | 310 | |
| 311 | +/** | |
| 312 | + * Updates the info block in the regex editor with hints regarding the find regex. | |
| 313 | + * @param {JQuery<HTMLElement>} editorHtml The editor HTML | |
| 314 | + */ | |
| 315 | +function updateInfoBlock(editorHtml) { | |
| 316 | + const infoBlock = editorHtml.find('.info-block').get(0); | |
| 317 | + const infoBlockFlagsHint = editorHtml.find('#regex_info_block_flags_hint'); | |
| 318 | + const findRegex = String(editorHtml.find('.find_regex').val()); | |
| 319 | + | |
| 320 | + infoBlockFlagsHint.hide(); | |
| 321 | + | |
| 322 | + // Clear the info block if the find regex is empty | |
| 323 | + if (!findRegex) { | |
| 324 | + setInfoBlock(infoBlock, t`Find Regex is empty`, 'info'); | |
| 325 | + return; | |
| 326 | + } | |
| 327 | + | |
| 328 | + try { | |
| 329 | + const regex = regexFromString(findRegex); | |
| 330 | + if (!regex) { | |
| 331 | + throw new Error(t`Invalid Find Regex`); | |
| 332 | + } | |
| 333 | + | |
| 334 | + const flagInfo = []; | |
| 335 | + flagInfo.push(regex.flags.includes('g') ? t`Applies to all matches` : t`Applies to the first match`); | |
| 336 | + flagInfo.push(regex.flags.includes('i') ? t`Case insensitive` : t`Case sensitive`); | |
| 337 | + | |
| 338 | + setInfoBlock(infoBlock, flagInfo.join('. '), 'hint'); | |
| 339 | + infoBlockFlagsHint.show(); | |
| 340 | + } catch (error) { | |
| 341 | + setInfoBlock(infoBlock, error.message, 'error'); | |
| 342 | + } | |
| 343 | +} | |
| 344 | + | |
| 308 | 345 | // Common settings migration function. Some parts will eventually be removed |
| 309 | 346 | // TODO: Maybe migrate placement to strings? |
| 310 | 347 | function migrateSettings() { |
| @@ -105,3 +105,24 @@ input.enable_scoped { | ||
| 105 | 105 | .disable_regex:not(:checked) ~ .regex-toggle-on { |
| 106 | 106 | display: block; |
| 107 | 107 | } |
| 108 | + | |
| 109 | +#regex_info_block_wrapper { | |
| 110 | + position: relative; | |
| 111 | +} | |
| 112 | + | |
| 113 | +#regex_info_block { | |
| 114 | + margin: 10px 0; | |
| 115 | + padding: 5px 20px; | |
| 116 | + font-size: 0.9em; | |
| 117 | +} | |
| 118 | + | |
| 119 | +#regex_info_block_wrapper:has(#regex_info_block:empty) { | |
| 120 | + display: none; | |
| 121 | +} | |
| 122 | + | |
| 123 | +#regex_info_block_flags_hint { | |
| 124 | + position: absolute; | |
| 125 | + top: 50%; | |
| 126 | + right: 10px; | |
| 127 | + transform: translateY(-50%); | |
| 128 | +} | |