Merge pull request #3290 from SillyTavern/qr-set-rename QR Set buttons for rename and duplicate
Signed| @@ -46,10 +46,12 @@ | ||
| 46 | 46 | <div class="qr--title" data-i18n="Edit Quick Replies">Edit Quick Replies</div> |
| 47 | 47 | <div class="qr--actions"> |
| 48 | 48 | <select id="qr--set" class="text_pole"></select> |
| 49 | + <div class="qr--add menu_button menu_button_icon fa-solid fa-pencil" id="qr--set-rename" title="Rename quick reply set"></div> | |
| 49 | 50 | <div class="qr--add menu_button menu_button_icon fa-solid fa-plus" id="qr--set-new" title="Create new quick reply set"></div> |
| 50 | 51 | <div class="qr--add menu_button menu_button_icon fa-solid fa-file-import" id="qr--set-import" title="Import quick reply set"></div> |
| 51 | 52 | <input type="file" id="qr--set-importFile" accept=".json" hidden> |
| 52 | 53 | <div class="qr--add menu_button menu_button_icon fa-solid fa-file-export" id="qr--set-export" title="Export quick reply set"></div> |
| 54 | + <div class="qr-add menu_button menu_button_icon fa-solid fa-paste" id="qr--set-duplicate" title="Duplicate quick reply set"></div> | |
| 53 | 55 | <div class="qr--del menu_button menu_button_icon fa-solid fa-trash redWarningBG" id="qr--set-delete" title="Delete quick reply set"></div> |
| 54 | 56 | </div> |
| 55 | 57 | </div> |
| @@ -1,4 +1,4 @@ | ||
| 1 | 1 | import { callPopupPopup } from '../../../../../scriptpopup.js'; |
| 2 | 2 | import { getSortableDelay } from '../../../../utils.js'; |
| 3 | 3 | import { log, warn } from '../../index.js'; |
| 4 | 4 | import { QuickReply } from '../QuickReply.js'; |
| @@ -111,6 +111,7 @@ export class SettingsUi { | ||
| 111 | 111 | |
| 112 | 112 | prepareQrEditor() { |
| 113 | 113 | // qr editor |
| 114 | + this.dom.querySelector('#qr--set-rename').addEventListener('click', async () => this.renameQrSet()); | |
| 114 | 115 | this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet()); |
| 115 | 116 | /**@type {HTMLInputElement}*/ |
| 116 | 117 | const importFile = this.dom.querySelector('#qr--set-importFile'); |
| @@ -120,6 +121,7 @@ export class SettingsUi { | ||
| 120 | 121 | }); |
| 121 | 122 | this.dom.querySelector('#qr--set-import').addEventListener('click', ()=>importFile.click()); |
| 122 | 123 | this.dom.querySelector('#qr--set-export').addEventListener('click', async () => this.exportQrSet()); |
| 124 | + this.dom.querySelector('#qr--set-duplicate').addEventListener('click', async () => this.duplicateQrSet()); | |
| 123 | 125 | this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet()); |
| 124 | 126 | this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{ |
| 125 | 127 | this.currentQrSet.addQuickReply(); |
| @@ -279,7 +281,7 @@ export class SettingsUi { | ||
| 279 | 281 | } |
| 280 | 282 | |
| 281 | 283 | async deleteQrSet() { |
| 282 | 284 | const confirmed = await callPopupPopup.show.confirm('Delete Quick Reply Set', `Are you sure you want to delete the Quick Reply Set "${this.currentQrSet.name}"?<br>This cannot be undone.`, 'confirm'); |
| 283 | 285 | if (confirmed) { |
| 284 | 286 | await this.doDeleteQrSet(this.currentQrSet); |
| 285 | 287 | this.rerender(); |
| @@ -303,12 +305,52 @@ export class SettingsUi { | ||
| 303 | 305 | this.settings.save(); |
| 304 | 306 | } |
| 305 | 307 | |
| 308 | + async renameQrSet() { | |
| 309 | + const newName = await Popup.show.input('Rename Quick Reply Set', 'Enter a new name:', this.currentQrSet.name); | |
| 310 | + if (newName && newName.length > 0) { | |
| 311 | + const existingSet = QuickReplySet.get(newName); | |
| 312 | + if (existingSet) { | |
| 313 | + toastr.error(`A Quick Reply Set named "${newName}" already exists.`); | |
| 314 | + return; | |
| 315 | + } | |
| 316 | + const oldName = this.currentQrSet.name; | |
| 317 | + this.currentQrSet.name = newName; | |
| 318 | + await this.currentQrSet.save(); | |
| 319 | + | |
| 320 | + // Update it in both set lists | |
| 321 | + this.settings.config.setList.forEach(set => { | |
| 322 | + if (set.set.name === oldName) { | |
| 323 | + set.set.name = newName; | |
| 324 | + } | |
| 325 | + }); | |
| 326 | + this.settings.chatConfig?.setList.forEach(set => { | |
| 327 | + if (set.set.name === oldName) { | |
| 328 | + set.set.name = newName; | |
| 329 | + } | |
| 330 | + }); | |
| 331 | + this.settings.save(); | |
| 332 | + | |
| 333 | + // Update the option in the current selected QR dropdown. All others will be refreshed via the prepare calls below. | |
| 334 | + /** @type {HTMLOptionElement} */ | |
| 335 | + const option = this.currentSet.querySelector(`#qr--set option[value="${oldName}"]`); | |
| 336 | + option.value = newName; | |
| 337 | + option.textContent = newName; | |
| 338 | + | |
| 339 | + this.currentSet.value = newName; | |
| 340 | + this.onQrSetChange(); | |
| 341 | + this.prepareGlobalSetList(); | |
| 342 | + this.prepareChatSetList(); | |
| 343 | + | |
| 344 | + console.info(`Quick Reply Set renamed from ""${oldName}" to "${newName}".`); | |
| 345 | + } | |
| 346 | + } | |
| 347 | + | |
| 306 | 348 | async addQrSet() { |
| 307 | 349 | const name = await callPopupPopup.show.input('QuickCreate Replya Setnew Name:World Info', 'inputEnter a name for the new Quick Reply Set:'); |
| 308 | 350 | if (name && name.length > 0) { |
| 309 | 351 | const oldQrs = QuickReplySet.get(name); |
| 310 | 352 | if (oldQrs) { |
| 311 | 353 | const replace = await callPopupPopup.show.confirm('Replace existing World Info', `A Quick Reply Set named "${name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`, 'confirm'); |
| 312 | 354 | if (replace) { |
| 313 | 355 | const idx = QuickReplySet.list.indexOf(oldQrs); |
| 314 | 356 | await this.doDeleteQrSet(oldQrs); |
| @@ -369,7 +411,7 @@ export class SettingsUi { | ||
| 369 | 411 | qrs.init(); |
| 370 | 412 | const oldQrs = QuickReplySet.get(props.name); |
| 371 | 413 | if (oldQrs) { |
| 372 | 414 | const replace = await callPopupPopup.show.confirm('Replace existing World Info', `A Quick Reply Set named "${qrs.name}" already exists.<br>Do you want to overwrite the existing Quick Reply Set?<br>The existing set will be deleted. This cannot be undone.`, 'confirm'); |
| 373 | 415 | if (replace) { |
| 374 | 416 | const idx = QuickReplySet.list.indexOf(oldQrs); |
| 375 | 417 | await this.doDeleteQrSet(oldQrs); |
| @@ -421,6 +463,40 @@ export class SettingsUi { | ||
| 421 | 463 | URL.revokeObjectURL(url); |
| 422 | 464 | } |
| 423 | 465 | |
| 466 | + async duplicateQrSet() { | |
| 467 | + const newName = await Popup.show.input('Duplicate Quick Reply Set', 'Enter a name for the new Quick Reply Set:', `${this.currentQrSet.name} (Copy)`); | |
| 468 | + if (newName && newName.length > 0) { | |
| 469 | + const existingSet = QuickReplySet.get(newName); | |
| 470 | + if (existingSet) { | |
| 471 | + toastr.error(`A Quick Reply Set named "${newName}" already exists.`); | |
| 472 | + return; | |
| 473 | + } | |
| 474 | + const newQrSet = QuickReplySet.from(JSON.parse(JSON.stringify(this.currentQrSet))); | |
| 475 | + newQrSet.name = newName; | |
| 476 | + newQrSet.qrList = this.currentQrSet.qrList.map(qr => QuickReply.from(JSON.parse(JSON.stringify(qr)))); | |
| 477 | + newQrSet.addQuickReply(); | |
| 478 | + const idx = QuickReplySet.list.findIndex(it => it.name.toLowerCase().localeCompare(newName.toLowerCase()) == 1); | |
| 479 | + if (idx > -1) { | |
| 480 | + QuickReplySet.list.splice(idx, 0, newQrSet); | |
| 481 | + } else { | |
| 482 | + QuickReplySet.list.push(newQrSet); | |
| 483 | + } | |
| 484 | + const opt = document.createElement('option'); { | |
| 485 | + opt.value = newQrSet.name; | |
| 486 | + opt.textContent = newQrSet.name; | |
| 487 | + if (idx > -1) { | |
| 488 | + this.currentSet.children[idx].insertAdjacentElement('beforebegin', opt); | |
| 489 | + } else { | |
| 490 | + this.currentSet.append(opt); | |
| 491 | + } | |
| 492 | + } | |
| 493 | + this.currentSet.value = newName; | |
| 494 | + this.onQrSetChange(); | |
| 495 | + this.prepareGlobalSetList(); | |
| 496 | + this.prepareChatSetList(); | |
| 497 | + } | |
| 498 | + } | |
| 499 | + | |
| 424 | 500 | selectQrSet(qrs) { |
| 425 | 501 | this.currentSet.value = qrs.name; |
| 426 | 502 | this.onQrSetChange(); |