Implement bulk operations for regex

523cc36b4667be590d03528c5b77aff77cd5b00c

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

4 files changed, +101 -18Ignore whitespace
public/scripts/extensions/regex/dropdown.html+20 -5
@@ -21,13 +21,28 @@
21 <small data-i18n="ext_regex_import_script">Import</small>21 <small data-i18n="ext_regex_import_script">Import</small>
22 </div>22 </div>
23 <input type="file" id="import_regex_file" hidden accept="*.json" multiple />23 <input type="file" id="import_regex_file" hidden accept="*.json" multiple />
24 <div id="export_global_regex" class="menu_button menu_button_icon">24 <label for="regex_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" />
26 <small data-i18n="ext_regex_export_global">Export Global</small>26 <i class="fa-solid fa-edit"></i>
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>
27 </div>34 </div>
28 <div id="export_scoped_regex" class="menu_button menu_button_icon">35 <div id="bulk_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">
29 <i class="fa-solid fa-file-export"></i>40 <i class="fa-solid fa-file-export"></i>
30 <small data-i18n="ext_regex_export_scoped">Export Scoped</small>41 <small data-i18n="Export">Export</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>
31 </div>46 </div>
32 </div>47 </div>
33 <hr />48 <hr />
public/scripts/extensions/regex/index.js+57 -12
@@ -607,22 +607,67 @@ jQuery(async () => {
607 $('#import_regex_file').trigger('click');607 $('#import_regex_file').trigger('click');
608 });608 });
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;
616 }622 }
623 for (const script of scripts) {
624 script.disabled = false;
625 }
626 saveSettingsDebounced();
627 await loadRegexScripts();
617 });628 });
618629
619 $('#export_scoped_regex').on('click', async function () {630 $('#bulk_disable_regex').on('click', async function () {
620 const regexScripts = characters[this_chid]?.data?.extensions?.regex_scripts ?? [];631 const scripts = getSelectedScripts().filter(script => !script.disabled);
621 if (regexScripts.length) {632 if (scripts.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');635 }
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 });
625 }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();
626 });671 });
627672
628 let sortableDatas = [673 let sortableDatas = [
public/scripts/extensions/regex/scriptTemplate.html+1 -0
@@ -1,4 +1,5 @@
1<div class="regex-script-label flex-container flexnowrap">1<div class="regex-script-label flex-container flexnowrap">
2 <input type="checkbox" class="regex_bulk_checkbox" />
2 <span class="drag-handle menu-handle">&#9776;</span>3 <span class="drag-handle menu-handle">&#9776;</span>
3 <div class="regex_script_name flexGrow overflow-hidden"></div>4 <div class="regex_script_name flexGrow overflow-hidden"></div>
4 <div class="flex-container flexnowrap">5 <div class="flex-container flexnowrap">
public/scripts/extensions/regex/style.css+23 -1
@@ -56,7 +56,7 @@
56}56}
5757
58.regex-script-label {58.regex-script-label {
59 align-items: center;59 align-items: baseline;
60 border: 1px solid var(--SmartThemeBorderColor);60 border: 1px solid var(--SmartThemeBorderColor);
61 border-radius: 10px;61 border-radius: 10px;
62 padding: 0 5px;62 padding: 0 5px;
@@ -126,3 +126,25 @@ input.enable_scoped {
126 right: 10px;126 right: 10px;
127 transform: translateY(-50%);127 transform: translateY(-50%);
128}128}
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}