Implement bulk operations for regex

523cc36b4667be590d03528c5b77aff77cd5b00c

Cohee <18619528+Cohee1207@users.noreply.github.com>

4 files changed, +101 -18Showing whitespace changes
public/scripts/extensions/regex/dropdown.html+20 -5
@@ -21,13 +21,28 @@
2121 <small data-i18n="ext_regex_import_script">Import</small>
2222 </div>
2323 <input type="file" id="import_regex_file" hidden accept="*.json" multiple />
2424 <divlabel idfor="export_global_regexregex_bulk_edit" class="menu_button menu_button_icon">
25- <i class="fa-solid fa-file-export"></i>
25+ <input id="regex_bulk_edit" type="checkbox" class="displayNone" />
2626 <smalli data-i18nclass="ext_regex_export_globalfa-solid fa-edit">Export Global</smalli>
27+ <small data-i18n="ext_regex_bulk_edit">Bulk Edit</small>
28+ </label>
29+ </div>
30+ <div class="regex_bulk_operations flex-container justifyCenter">
31+ <div id="bulk_enable_regex" class="menu_button menu_button_icon">
32+ <i class="fa-solid fa-toggle-on"></i>
33+ <small data-i18n="Enable">Enable</small>
2734 </div>
2835 <div id="export_scoped_regexbulk_disable_regex" class="menu_button menu_button_icon">
36+ <i class="fa-solid fa-toggle-off"></i>
37+ <small data-i18n="Disable">Disable</small>
38+ </div>
39+ <div id="bulk_export_regex" class="menu_button menu_button_icon">
2940 <i class="fa-solid fa-file-export"></i>
3041 <small data-i18n="ext_regex_export_scopedExport">Export Scoped</small>
42+ </div>
43+ <div id="bulk_delete_regex" class="menu_button menu_button_icon">
44+ <i class="fa-solid fa-trash"></i>
45+ <small data-i18n="Delete">Delete</small>
3146 </div>
3247 </div>
3348 <hr />
public/scripts/extensions/regex/index.js+57 -12
@@ -607,22 +607,67 @@ jQuery(async () => {
607607 $('#import_regex_file').trigger('click');
608608 });
609609
610- $('#export_global_regex').on('click', async function () {
610+ function getSelectedScripts() {
611- const regexScripts = extension_settings?.regex ?? [];
611+ const scripts = getRegexScripts();
612- if (regexScripts.length) {
612+ const selector = '#regex_container .regex-script-label:has(.regex_bulk_checkbox:checked)';
613- const fileName = 'regex-global.json';
613+ const selectedIds = Array.from(document.querySelectorAll(selector)).map(e => e.getAttribute('id')).filter(id => id);
614- const fileData = JSON.stringify(regexScripts, null, 4);
614+ return scripts.filter(script => selectedIds.includes(script.id));
615- download(fileData, fileName, 'application/json');
615+ }
616+
617+ $('#bulk_enable_regex').on('click', async function () {
618+ const scripts = getSelectedScripts().filter(script => script.disabled);
619+ if (scripts.length === 0) {
620+ toastr.warning(t`No regex scripts selected for enabling.`);
621+ return;
616622 }
623+ for (const script of scripts) {
624+ script.disabled = false;
625+ }
626+ saveSettingsDebounced();
627+ await loadRegexScripts();
617628 });
618629
619630 $('#export_scoped_regexbulk_disable_regex').on('click', async function () {
620- const regexScripts = characters[this_chid]?.data?.extensions?.regex_scripts ?? [];
631+ const scripts = getSelectedScripts().filter(script => !script.disabled);
621632 if (regexScriptsscripts.length === 0) {
622- const fileName = `regex-${sanitizeFileName(characters[this_chid].name)}.json`;
633+ toastr.warning(t`No regex scripts selected for disabling.`);
623- const fileData = JSON.stringify(regexScripts, null, 4);
634+ return;
624- download(fileData, fileName, 'application/json');
625635 }
636+ for (const script of scripts) {
637+ script.disabled = true;
638+ }
639+ saveSettingsDebounced();
640+ await loadRegexScripts();
641+ });
642+
643+ $('#bulk_delete_regex').on('click', async function () {
644+ const scripts = getSelectedScripts();
645+ if (scripts.length === 0) {
646+ toastr.warning(t`No regex scripts selected for deletion.`);
647+ return;
648+ }
649+ const confirm = await callGenericPopup('Are you sure you want to delete the selected regex scripts?', POPUP_TYPE.CONFIRM);
650+ if (!confirm) {
651+ return;
652+ }
653+ for (const script of scripts) {
654+ const isScoped = characters[this_chid]?.data?.extensions?.regex_scripts?.some(s => s.id === script.id);
655+ await deleteRegexScript({ id: script.id, isScoped: isScoped });
656+ }
657+ await reloadCurrentChat();
658+ saveSettingsDebounced();
659+ });
660+
661+ $('#bulk_export_regex').on('click', async function () {
662+ const scripts = getSelectedScripts();
663+ if (scripts.length === 0) {
664+ toastr.warning(t`No regex scripts selected for export.`);
665+ return;
666+ }
667+ const fileName = `regex-${new Date().toISOString()}.json`;
668+ const fileData = JSON.stringify(scripts, null, 4);
669+ download(fileData, fileName, 'application/json');
670+ await loadRegexScripts();
626671 });
627672
628673 let sortableDatas = [
public/scripts/extensions/regex/scriptTemplate.html+1 -0
@@ -1,4 +1,5 @@
11<div class="regex-script-label flex-container flexnowrap">
2+ <input type="checkbox" class="regex_bulk_checkbox" />
23 <span class="drag-handle menu-handle">&#9776;</span>
34 <div class="regex_script_name flexGrow overflow-hidden"></div>
45 <div class="flex-container flexnowrap">
public/scripts/extensions/regex/style.css+23 -1
@@ -56,7 +56,7 @@
5656}
5757
5858.regex-script-label {
5959 align-items: centerbaseline;
6060 border: 1px solid var(--SmartThemeBorderColor);
6161 border-radius: 10px;
6262 padding: 0 5px;
@@ -126,3 +126,25 @@ input.enable_scoped {
126126 right: 10px;
127127 transform: translateY(-50%);
128128}
129+
130+.regex_settings label[for="regex_bulk_edit"]:has(#regex_bulk_edit:checked) {
131+ color: var(--golden);
132+}
133+
134+.regex_settings .regex-script-container .regex-script-label .regex_bulk_checkbox {
135+ margin-left: 5px;
136+ margin-right: 5px;
137+}
138+
139+.regex_settings .regex_bulk_operations,
140+.regex_settings .regex_bulk_checkbox {
141+ display: none;
142+}
143+
144+.regex_settings:has(#regex_bulk_edit:checked) .regex_bulk_operations {
145+ display: flex;
146+}
147+
148+.regex_settings:has(#regex_bulk_edit:checked) .regex_bulk_checkbox {
149+ display: inline-grid;
150+}