mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
add import and export of QR sets
This commit is contained in:
@ -43,8 +43,11 @@
|
|||||||
<div class="qr--title">Edit Quick Replies</div>
|
<div class="qr--title">Edit Quick Replies</div>
|
||||||
<div class="qr--actions">
|
<div class="qr--actions">
|
||||||
<select id="qr--set" class="text_pole"></select>
|
<select id="qr--set" class="text_pole"></select>
|
||||||
<div class="qr--del menu_button menu_button_icon fa-solid fa-trash" id="qr--set-delete" title="Delete quick reply set"></div>
|
|
||||||
<div class="qr--add menu_button menu_button_icon fa-solid fa-plus" id="qr--set-new" title="Create new quick reply set"></div>
|
<div class="qr--add menu_button menu_button_icon fa-solid fa-plus" id="qr--set-new" title="Create new quick reply set"></div>
|
||||||
|
<div class="qr--add menu_button menu_button_icon fa-solid fa-file-import" id="qr--set-import" title="Import quick reply set"></div>
|
||||||
|
<input type="file" id="qr--set-importFile" accept=".json" hidden>
|
||||||
|
<div class="qr--add menu_button menu_button_icon fa-solid fa-file-export" id="qr--set-export" title="Export quick reply set"></div>
|
||||||
|
<div class="qr--del menu_button menu_button_icon fa-solid fa-trash redWarningBG" id="qr--set-delete" title="Delete quick reply set"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="qr--set-settings">
|
<div id="qr--set-settings">
|
||||||
|
@ -169,6 +169,7 @@ export class QuickReply {
|
|||||||
del.classList.add('menu_button_icon');
|
del.classList.add('menu_button_icon');
|
||||||
del.classList.add('fa-solid');
|
del.classList.add('fa-solid');
|
||||||
del.classList.add('fa-trash-can');
|
del.classList.add('fa-trash-can');
|
||||||
|
del.classList.add('redWarningBG');
|
||||||
del.title = 'Remove quick reply';
|
del.title = 'Remove quick reply';
|
||||||
del.addEventListener('click', ()=>this.delete());
|
del.addEventListener('click', ()=>this.delete());
|
||||||
actions.append(del);
|
actions.append(del);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { callPopup } from '../../../../../script.js';
|
import { callPopup } from '../../../../../script.js';
|
||||||
import { getSortableDelay } from '../../../../utils.js';
|
import { getSortableDelay } from '../../../../utils.js';
|
||||||
import { warn } from '../../index.js';
|
import { log, warn } from '../../index.js';
|
||||||
|
import { QuickReply } from '../QuickReply.js';
|
||||||
import { QuickReplySet } from '../QuickReplySet.js';
|
import { QuickReplySet } from '../QuickReplySet.js';
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
import { QuickReplySettings } from '../QuickReplySettings.js';
|
import { QuickReplySettings } from '../QuickReplySettings.js';
|
||||||
@ -103,8 +104,16 @@ export class SettingsUi {
|
|||||||
|
|
||||||
prepareQrEditor() {
|
prepareQrEditor() {
|
||||||
// qr editor
|
// qr editor
|
||||||
this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet());
|
|
||||||
this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet());
|
this.dom.querySelector('#qr--set-new').addEventListener('click', async()=>this.addQrSet());
|
||||||
|
/**@type {HTMLInputElement}*/
|
||||||
|
const importFile = this.dom.querySelector('#qr--set-importFile');
|
||||||
|
importFile.addEventListener('change', async()=>{
|
||||||
|
await this.importQrSet(importFile.files);
|
||||||
|
importFile.value = null;
|
||||||
|
});
|
||||||
|
this.dom.querySelector('#qr--set-import').addEventListener('click', ()=>importFile.click());
|
||||||
|
this.dom.querySelector('#qr--set-export').addEventListener('click', async()=>this.exportQrSet());
|
||||||
|
this.dom.querySelector('#qr--set-delete').addEventListener('click', async()=>this.deleteQrSet());
|
||||||
this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{
|
this.dom.querySelector('#qr--set-add').addEventListener('click', async()=>{
|
||||||
this.currentQrSet.addQuickReply();
|
this.currentQrSet.addQuickReply();
|
||||||
});
|
});
|
||||||
@ -278,6 +287,77 @@ export class SettingsUi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async importQrSet(/**@type {FileList}*/files) {
|
||||||
|
for (let i = 0; i < files.length; i++) {
|
||||||
|
await this.importSingleQrSet(files.item(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async importSingleQrSet(/**@type {File}*/file) {
|
||||||
|
log('FILE', file);
|
||||||
|
try {
|
||||||
|
const text = await file.text();
|
||||||
|
const props = JSON.parse(text);
|
||||||
|
if (!Number.isInteger(props.version) || typeof props.name != 'string') {
|
||||||
|
toastr.error(`The file "${file.name}" does not appear to be a valid quick reply set.`);
|
||||||
|
warn(`The file "${file.name}" does not appear to be a valid quick reply set.`);
|
||||||
|
} else {
|
||||||
|
/**@type {QuickReplySet}*/
|
||||||
|
const qrs = QuickReplySet.from(JSON.parse(JSON.stringify(props)));
|
||||||
|
qrs.qrList = props.qrList.map(it=>QuickReply.from(it));
|
||||||
|
qrs.init();
|
||||||
|
const oldQrs = QuickReplySet.get(props.name);
|
||||||
|
if (oldQrs) {
|
||||||
|
const replace = await callPopup(`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');
|
||||||
|
if (replace) {
|
||||||
|
const idx = QuickReplySet.list.indexOf(oldQrs);
|
||||||
|
await this.doDeleteQrSet(oldQrs);
|
||||||
|
QuickReplySet.list.splice(idx, 0, qrs);
|
||||||
|
await qrs.save();
|
||||||
|
this.rerender();
|
||||||
|
this.currentSet.value = qrs.name;
|
||||||
|
this.onQrSetChange();
|
||||||
|
this.prepareGlobalSetList();
|
||||||
|
this.prepareChatSetList();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const idx = QuickReplySet.list.findIndex(it=>it.name.localeCompare(qrs.name) == 1);
|
||||||
|
if (idx > -1) {
|
||||||
|
QuickReplySet.list.splice(idx, 0, qrs);
|
||||||
|
} else {
|
||||||
|
QuickReplySet.list.push(qrs);
|
||||||
|
}
|
||||||
|
await qrs.save();
|
||||||
|
const opt = document.createElement('option'); {
|
||||||
|
opt.value = qrs.name;
|
||||||
|
opt.textContent = qrs.name;
|
||||||
|
if (idx > -1) {
|
||||||
|
this.currentSet.children[idx].insertAdjacentElement('beforebegin', opt);
|
||||||
|
} else {
|
||||||
|
this.currentSet.append(opt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.currentSet.value = qrs.name;
|
||||||
|
this.onQrSetChange();
|
||||||
|
this.prepareGlobalSetList();
|
||||||
|
this.prepareChatSetList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
warn(ex);
|
||||||
|
toastr.error(`Failed to import "${file.name}":\n\n${ex.message}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exportQrSet() {
|
||||||
|
const blob = new Blob([JSON.stringify(this.currentQrSet)], { type:'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a'); {
|
||||||
|
a.href = url;
|
||||||
|
a.download = `${this.currentQrSet.name}.json`;
|
||||||
|
a.click();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
selectQrSet(qrs) {
|
selectQrSet(qrs) {
|
||||||
this.currentSet.value = qrs.name;
|
this.currentSet.value = qrs.name;
|
||||||
this.onQrSetChange();
|
this.onQrSetChange();
|
||||||
|
Reference in New Issue
Block a user