Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
KoboldAI
GitHub Repository: KoboldAI/KoboldAI-Client
Path: blob/main/static/application.js
473 views
1
//=================================================================//
2
// VARIABLES
3
//=================================================================//
4
5
// Socket IO Object
6
var socket;
7
8
// UI references for jQuery
9
var connect_status;
10
var button_loadmodel;
11
var button_newgame;
12
var button_rndgame;
13
var button_save;
14
var button_saveas;
15
var button_savetofile;
16
var button_load;
17
var button_import;
18
var button_importwi;
19
var button_impaidg;
20
var button_settings;
21
var button_format;
22
var button_softprompt;
23
var button_userscripts;
24
var button_samplers;
25
var button_mode;
26
var button_mode_label;
27
var button_send;
28
var button_actmem;
29
var button_actback;
30
var button_actfwd;
31
var button_actretry;
32
var button_actwi;
33
var game_text;
34
var input_text;
35
var message_text;
36
var chat_name;
37
var settings_menu;
38
var format_menu;
39
var wi_menu;
40
var anote_menu;
41
var anote_input;
42
var anote_labelcur;
43
var anote_slider;
44
var debug_area;
45
var popup;
46
var popup_title;
47
var popup_content;
48
var popup_accept;
49
var popup_close;
50
var aidgpopup;
51
var aidgpromptnum;
52
var aidg_accept;
53
var aidg_close;
54
var saveaspopup;
55
var saveasinput;
56
var savepins;
57
var topic;
58
var saveas_accept;
59
var saveas_close;
60
var loadmodelpopup;
61
var loadpopup;
62
var loadcontent;
63
var load_accept;
64
var load_close;
65
var sppopup;
66
var spcontent;
67
var sp_accept;
68
var sp_close;
69
var uspopup;
70
var uscontent;
71
var us_accept;
72
var us_close;
73
var nspopup;
74
var ns_accept;
75
var ns_close;
76
var rspopup;
77
var rs_accept;
78
var rs_close;
79
var seqselmenu;
80
var seqselcontents;
81
var stream_preview;
82
var token_prob_container;
83
84
var storyname = null;
85
var memorymode = false;
86
var memorytext = "";
87
var gamestarted = false;
88
var wiscroll = 0;
89
var editmode = false;
90
var connected = false;
91
var newly_loaded = true;
92
var all_modified_chunks = new Set();
93
var modified_chunks = new Set();
94
var empty_chunks = new Set();
95
var gametext_bound = false;
96
var saved_prompt = "...";
97
var wifolders_d = {};
98
var wifolders_l = [];
99
var override_focusout = false;
100
var sman_allow_delete = false;
101
var sman_allow_rename = false;
102
var allowsp = false;
103
var remote = false;
104
var gamestate = "";
105
var gamesaved = true;
106
var modelname = null;
107
var model = "";
108
var ignore_stream = false;
109
110
//timer for loading CLUSTER models
111
var online_model_timmer;
112
113
// This is true iff [we're in macOS and the browser is Safari] or [we're in iOS]
114
var using_webkit_patch = true;
115
116
// Key states
117
var shift_down = false;
118
var do_clear_ent = false;
119
120
// Whether or not an entry in the Userscripts menu is being dragged
121
var us_dragging = false;
122
123
// Whether or not an entry in the Samplers menu is being dragged
124
var samplers_dragging = false;
125
126
// Display vars
127
var allowtoggle = false;
128
var formatcount = 0;
129
var allowedit = true; // Whether clicking on chunks will edit them
130
131
// Adventure
132
var action_mode = 0; // 0: story, 1: action
133
var adventure = false;
134
135
// Chatmode
136
var chatmode = false;
137
138
var sliders_throttle = getThrottle(200);
139
var submit_throttle = null;
140
141
//=================================================================//
142
// METHODS
143
//=================================================================//
144
145
/**
146
* Returns a function that will automatically wait for X ms before executing the callback
147
* The timer is reset each time the returned function is called
148
* Useful for methods where something is overridden too fast
149
* @param ms milliseconds to wait before executing the callback
150
* @return {(function(*): void)|*} function that takes the ms to wait and a callback to execute after the timer
151
*/
152
function getThrottle(ms) {
153
var timer = {};
154
155
return function (id, callback) {
156
if (timer[id]) {
157
clearTimeout(timer[id]);
158
}
159
timer[id] = setTimeout(function () {
160
callback();
161
delete timer[id];
162
}, ms);
163
}
164
}
165
166
function reset_menus() {
167
settings_menu.html("");
168
format_menu.html("");
169
wi_menu.html("");
170
}
171
172
function addSetting(ob) {
173
// Add setting block to Settings Menu
174
if(ob.uitype == "slider"){
175
settings_menu.append("<div class=\"settingitem\">\
176
<div class=\"settinglabel\">\
177
<div class=\"justifyleft\">\
178
"+ob.label+" <span class=\"helpicon\">?<span class=\"helptext\">"+ob.tooltip+"</span></span>\
179
</div>\
180
<input inputmode=\""+(ob.unit === "float" ? "decimal" : "numeric")+"\" class=\"justifyright flex-push-right\" id=\""+ob.id+"cur\" value=\""+ob.default+"\">\
181
</div>\
182
<div>\
183
<input type=\"range\" class=\"form-range airange\" min=\""+ob.min+"\" max=\""+ob.max+"\" step=\""+ob.step+"\" id=\""+ob.id+"\">\
184
</div>\
185
<div class=\"settingminmax\">\
186
<div class=\"justifyleft\">\
187
"+ob.min+"\
188
</div>\
189
<div class=\"justifyright\">\
190
"+ob.max+"\
191
</div>\
192
</div>\
193
</div>");
194
// Set references to HTML objects
195
var refin = $("#"+ob.id);
196
var reflb = $("#"+ob.id+"cur");
197
window["setting_"+ob.id] = refin; // Is this still needed?
198
window["label_"+ob.id] = reflb; // Is this still needed?
199
// Add event function to input
200
var updateLabelColor = function () {
201
var value = (ob.unit === "float" ? parseFloat : parseInt)(reflb.val());
202
if(value > ob.max || value < ob.min) {
203
reflb.addClass("setting-value-warning");
204
} else {
205
reflb.removeClass("setting-value-warning");
206
}
207
}
208
var send = function () {
209
sliders_throttle(ob.id, function () {
210
socket.send({'cmd': $(refin).attr('id'), 'data': $(reflb).val()});
211
});
212
}
213
refin.on("input", function (event) {
214
reflb.val(refin.val());
215
updateLabelColor();
216
send();
217
}).on("change", updateLabelColor);
218
reflb.on("change", function (event) {
219
var value = (ob.unit === "float" ? parseFloat : parseInt)(event.target.value);
220
if(Number.isNaN(value) || (ob.min >= 0 && value < 0)) {
221
event.target.value = refin.val();
222
return;
223
}
224
if (ob.unit === "float") {
225
value = parseFloat(value.toFixed(3)); // Round to 3 decimal places to help avoid the number being too long to fit in the box
226
}
227
refin.val(value);
228
reflb.val(value);
229
updateLabelColor();
230
send();
231
});
232
} else if(ob.uitype == "toggle"){
233
settings_menu.append("<div class=\"settingitem\">\
234
<input type=\"checkbox\" data-toggle=\"toggle\" data-onstyle=\"success\" id=\""+ob.id+"\">\
235
<span class=\"formatlabel\">"+ob.label+" </span>\
236
<span class=\"helpicon\">?<span class=\"helptext\">"+ob.tooltip+"</span></span>\
237
</div>");
238
// Tell Bootstrap-Toggle to render the new checkbox
239
$("input[type=checkbox]").bootstrapToggle();
240
$("#"+ob.id).on("change", function () {
241
if(allowtoggle) {
242
socket.send({'cmd': $(this).attr('id'), 'data': $(this).prop('checked')});
243
}
244
if(ob.id == "setadventure"){
245
setadventure($(this).prop('checked'));
246
}
247
248
});
249
}
250
251
if (ob.id === "setshowbudget") {
252
$("#setshowbudget").on("change", function () {
253
for (const el of document.getElementsByClassName("input-token-usage")) {
254
if (this.checked) {
255
el.classList.remove("hidden");
256
} else {
257
el.classList.add("hidden");
258
}
259
}
260
});
261
262
if (!$("#setshowbudget")[0].checked) {
263
for (const el of document.getElementsByClassName("input-token-usage")) {
264
el.classList.add("hidden");
265
}
266
}
267
}
268
}
269
270
function refreshTitle() {
271
var title = gamesaved ? "" : "\u2731 ";
272
if(storyname !== null) {
273
title += storyname + " \u2014 ";
274
}
275
title += "KoboldAI Client";
276
if(modelname !== null) {
277
title += " (" + modelname + ")";
278
}
279
document.title = title;
280
}
281
282
function setGameSaved(state) {
283
gamesaved = !!state;
284
refreshTitle();
285
}
286
287
function addFormat(ob) {
288
// Check if we need to make a new column for this button
289
if(formatcount == 0) {
290
format_menu.append("<div class=\"formatcolumn\"></div>");
291
}
292
// Get reference to the last child column
293
var ref = $("#formatmenu > div").last();
294
// Add format block to Format Menu
295
ref.append("<div class=\"formatrow\">\
296
<input type=\"checkbox\" data-toggle=\"toggle\" data-onstyle=\"success\" id=\""+ob.id+"\">\
297
<span class=\"formatlabel\">"+ob.label+" </span>\
298
<span class=\"helpicon\">?<span class=\"helptext\">"+ob.tooltip+"</span></span>\
299
</div>");
300
// Tell Bootstrap-Toggle to render the new checkbox
301
$("input[type=checkbox]").bootstrapToggle();
302
// Add event to input
303
$("#"+ob.id).on("change", function () {
304
if(allowtoggle) {
305
socket.send({'cmd': $(this).attr('id'), 'data': $(this).prop('checked')});
306
}
307
});
308
// Increment display variable
309
formatcount++;
310
if(formatcount == 2) {
311
formatcount = 0;
312
}
313
}
314
315
function addImportLine(ob) {
316
popup_content.append("<div class=\"popuplistitem\" id=\"import"+ob.num+"\">\
317
<div>"+ob.title+"</div>\
318
<div>"+ob.acts+"</div>\
319
<div>"+ob.descr+"</div>\
320
</div>");
321
$("#import"+ob.num).on("click", function () {
322
socket.send({'cmd': 'importselect', 'data': $(this).attr('id')});
323
highlightImportLine($(this));
324
});
325
}
326
327
function adjustWiCommentHeight(element) {
328
element.style.height = "0px";
329
element.style.height = element.scrollHeight + "px";
330
element.parentNode.parentNode.style.height = element.scrollHeight + 90 + "px";
331
}
332
333
function adjustWiFolderNameHeight(element) {
334
element.style.height = "0px";
335
element.style.height = element.scrollHeight + "px";
336
element.parentNode.parentNode.parentNode.style.height = element.scrollHeight + 19 + "px";
337
}
338
339
function addWiLine(ob) {
340
var current_wifolder_element = ob.folder === null ? $(".wisortable-body:not([folder-uid])").last() : $(".wisortable-body[folder-uid="+ob.folder+"]");
341
if(ob.init) {
342
if(ob.selective){
343
current_wifolder_element.append("<div class=\"wilistitem wilistitem-selective "+(ob.constant ? "wilistitem-constant" : "")+"\" num=\""+ob.num+"\" uid=\""+ob.uid+"\" id=\"wilistitem"+ob.num+"\">\
344
<div class=\"wicomment\">\
345
<textarea class=\"form-control\" placeholder=\"Comment\" id=\"wicomment"+ob.num+"\">"+ob.comment+"</textarea>\
346
</div>\
347
<div class=\"wihandle\" id=\"wihandle"+ob.num+"\">\
348
<div class=\"wicentered\">\
349
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
350
<br/>\
351
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
352
<br/>\
353
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
354
<br/>\
355
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
356
<br/>\
357
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
358
<br/>\
359
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
360
<br/>\
361
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
362
</div>\
363
</div>\
364
<div class=\"wiremove\">\
365
<button type=\"button\" class=\"btn btn-primary heightfull\" id=\"btn_wi"+ob.num+"\">X</button>\
366
<button type=\"button\" class=\"btn btn-success heighthalf hidden\" id=\"btn_widel"+ob.num+"\">✓</button>\
367
<button type=\"button\" class=\"btn btn-danger heighthalf hidden\" id=\"btn_wican"+ob.num+"\">⮌</button>\
368
</div>\
369
<div class=\"icon-container wikey\">\
370
<input class=\"form-control wiheightfull hidden\" type=\"text\" placeholder=\"Key(s)\" id=\"wikey"+ob.num+"\">\
371
<input class=\"form-control wiheighthalf\" type=\"text\" placeholder=\"Primary Key(s)\" id=\"wikeyprimary"+ob.num+"\">\
372
<input class=\"form-control wiheighthalf\" type=\"text\" placeholder=\"Secondary Key(s)\" id=\"wikeysecondary"+ob.num+"\">\
373
<span class=\"selective-key-icon "+(ob.selective ? "selective-key-icon-enabled" : "")+" oi oi-layers\" id=\"selective-key-"+ob.num+"\" title=\"Toggle Selective Key mode (if enabled, this world info entry will be included in memory only if at least one PRIMARY KEY and at least one SECONDARY KEY are both present in the story)\" aria-hidden=\"true\"></span>\
374
<span class=\"constant-key-icon "+(ob.constant ? "constant-key-icon-enabled" : "")+" oi oi-pin\" id=\"constant-key-"+ob.num+"\" title=\"Toggle Constant Key mode (if enabled, this world info entry will always be included in memory)\" aria-hidden=\"true\"></span>\
375
</div>\
376
<div class=\"wientry\">\
377
<textarea class=\"layer-bottom form-control\" id=\"wientry"+ob.num+"\" placeholder=\"What To Remember\">"+ob.content+"</textarea>\
378
</div>\
379
</div>");
380
} else {
381
current_wifolder_element.append("<div class=\"wilistitem "+(ob.constant ? "wilistitem-constant" : "")+"\" num=\""+ob.num+"\" uid=\""+ob.uid+"\" id=\"wilistitem"+ob.num+"\">\
382
<div class=\"wicomment\">\
383
<textarea class=\"form-control\" placeholder=\"Comment\" id=\"wicomment"+ob.num+"\">"+ob.comment+"</textarea>\
384
</div>\
385
<div class=\"wihandle\" id=\"wihandle"+ob.num+"\">\
386
<div class=\"wicentered\">\
387
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
388
<br/>\
389
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
390
<br/>\
391
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
392
<br/>\
393
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
394
<br/>\
395
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
396
<br/>\
397
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
398
<br/>\
399
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
400
</div>\
401
</div>\
402
<div class=\"wiremove\">\
403
<button type=\"button\" class=\"btn btn-primary heightfull\" id=\"btn_wi"+ob.num+"\">X</button>\
404
<button type=\"button\" class=\"btn btn-success heighthalf hidden\" id=\"btn_widel"+ob.num+"\">✓</button>\
405
<button type=\"button\" class=\"btn btn-danger heighthalf hidden\" id=\"btn_wican"+ob.num+"\">⮌</button>\
406
</div>\
407
<div class=\"icon-container wikey\">\
408
<input class=\"form-control wiheightfull\" type=\"text\" placeholder=\"Key(s)\" id=\"wikey"+ob.num+"\">\
409
<input class=\"form-control wiheighthalf hidden\" type=\"text\" placeholder=\"Primary Key(s)\" id=\"wikeyprimary"+ob.num+"\">\
410
<input class=\"form-control wiheighthalf hidden\" type=\"text\" placeholder=\"Secondary Key(s)\" id=\"wikeysecondary"+ob.num+"\">\
411
<span class=\"selective-key-icon "+(ob.selective ? "selective-key-icon-enabled" : "")+" oi oi-layers\" id=\"selective-key-"+ob.num+"\" title=\"Toggle Selective Key mode (if enabled, this world info entry will be included in memory only if at least one PRIMARY KEY and at least one SECONDARY KEY are both present in the story)\" aria-hidden=\"true\"></span>\
412
<span class=\"constant-key-icon "+(ob.constant ? "constant-key-icon-enabled" : "")+" oi oi-pin\" id=\"constant-key-"+ob.num+"\" title=\"Toggle Constant Key mode (if enabled, this world info entry will always be included in memory)\" aria-hidden=\"true\"></span>\
413
</div>\
414
<div class=\"wientry\">\
415
<textarea class=\"form-control\" id=\"wientry"+ob.num+"\" placeholder=\"What To Remember\">"+ob.content+"</textarea>\
416
</div>\
417
</div>");
418
}
419
adjustWiCommentHeight($("#wicomment"+ob.num)[0]);
420
// Send key value to text input
421
$("#wikey"+ob.num).val(ob.key);
422
$("#wikeyprimary"+ob.num).val(ob.key);
423
$("#wikeysecondary"+ob.num).val(ob.keysecondary);
424
// Assign delete event to button
425
$("#btn_wi"+ob.num).on("click", function () {
426
showWiDeleteConfirm(ob.num);
427
});
428
} else {
429
// Show WI line item with form fields hidden (uninitialized)
430
current_wifolder_element.append("<div class=\"wilistitem wilistitem-uninitialized wisortable-excluded\" num=\""+ob.num+"\" uid=\""+ob.uid+"\" id=\"wilistitem"+ob.num+"\">\
431
<div class=\"wicomment\">\
432
<textarea class=\"form-control hidden\" placeholder=\"Comment\" id=\"wicomment"+ob.num+"\">"+ob.comment+"</textarea>\
433
</div>\
434
<div class=\"wihandle-inactive hidden\" id=\"wihandle"+ob.num+"\">\
435
<div class=\"wicentered\">\
436
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
437
<br/>\
438
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
439
<br/>\
440
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
441
<br/>\
442
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
443
<br/>\
444
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
445
<br/>\
446
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
447
<br/>\
448
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
449
</div>\
450
</div>\
451
<div class=\"wiremove\">\
452
<button type=\"button\" class=\"btn btn-primary heightfull\" id=\"btn_wi"+ob.num+"\">+</button>\
453
<button type=\"button\" class=\"btn btn-success heighthalf hidden\" id=\"btn_widel"+ob.num+"\">✓</button>\
454
<button type=\"button\" class=\"btn btn-danger heighthalf hidden\" id=\"btn_wican"+ob.num+"\">X</button>\
455
</div>\
456
<div class=\"icon-container wikey\">\
457
<input class=\"form-control wiheightfull hidden\" type=\"text\" placeholder=\"Key(s)\" id=\"wikey"+ob.num+"\">\
458
<input class=\"form-control wiheighthalf hidden\" type=\"text\" placeholder=\"Primary Key(s)\" id=\"wikeyprimary"+ob.num+"\">\
459
<input class=\"form-control wiheighthalf hidden\" type=\"text\" placeholder=\"Secondary Key(s)\" id=\"wikeysecondary"+ob.num+"\">\
460
<span class=\"selective-key-icon oi oi-layers hidden\" id=\"selective-key-"+ob.num+"\" title=\"Toggle Selective Key mode (if enabled, this world info entry will be included in memory only if at least one PRIMARY KEY and at least one SECONDARY KEY are both present in the story)\" aria-hidden=\"true\"></span>\
461
<span class=\"constant-key-icon oi oi-pin hidden\" id=\"constant-key-"+ob.num+"\" title=\"Toggle Constant Key mode (if enabled, this world info entry will always be included in memory)\" aria-hidden=\"true\"></span>\
462
</div>\
463
<div class=\"wientry\">\
464
<textarea class=\"layer-bottom form-control hidden\" id=\"wientry"+ob.num+"\" placeholder=\"What To Remember\">"+ob.content+"</textarea>\
465
</div>\
466
</div>");
467
// Assign function to expand WI item to button
468
$("#btn_wi"+ob.num).on("click", function () {
469
var folder = $("#wilistitem"+ob.num).parent().attr("folder-uid");
470
if(folder === undefined) {
471
folder = null;
472
} else {
473
folder = parseInt(folder);
474
}
475
socket.send({'cmd': 'wiexpand', 'data': ob.num});
476
socket.send({'cmd': 'wiinit', 'folder': folder, 'data': ob.num});
477
});
478
}
479
// Assign actions to other elements
480
wientry_onfocus = function () {
481
$("#selective-key-"+ob.num).addClass("selective-key-icon-clickthrough");
482
$("#constant-key-"+ob.num).addClass("constant-key-icon-clickthrough");
483
}
484
wientry_onfocusout = function () {
485
$("#selective-key-"+ob.num).removeClass("selective-key-icon-clickthrough");
486
$("#constant-key-"+ob.num).removeClass("constant-key-icon-clickthrough");
487
// Tell server about updated WI fields
488
var selective = $("#wilistitem"+ob.num)[0].classList.contains("wilistitem-selective");
489
socket.send({'cmd': 'wiupdate', 'num': ob.num, 'data': {
490
key: selective ? $("#wikeyprimary"+ob.num).val() : $("#wikey"+ob.num).val(),
491
keysecondary: $("#wikeysecondary"+ob.num).val(),
492
content: $("#wientry"+ob.num).val(),
493
comment: $("#wicomment"+ob.num).val(),
494
}});
495
}
496
$("#wikey"+ob.num).on("focus", wientry_onfocus);
497
$("#wikeyprimary"+ob.num).on("focus", wientry_onfocus);
498
$("#wikeysecondary"+ob.num).on("focus", wientry_onfocus);
499
$("#wientry"+ob.num).on("focus", wientry_onfocus);
500
$("#wicomment"+ob.num).on("focus", wientry_onfocus);
501
$("#wikey"+ob.num).on("focusout", wientry_onfocusout);
502
$("#wikeyprimary"+ob.num).on("focusout", wientry_onfocusout);
503
$("#wikeysecondary"+ob.num).on("focusout", wientry_onfocusout);
504
$("#wientry"+ob.num).on("focusout", wientry_onfocusout);
505
$("#wicomment"+ob.num).on("focusout", wientry_onfocusout);
506
$("#btn_wican"+ob.num).on("click", function () {
507
hideWiDeleteConfirm(ob.num);
508
});
509
$("#btn_widel"+ob.num).on("click", function () {
510
socket.send({'cmd': 'widelete', 'data': ob.uid});
511
});
512
$("#selective-key-"+ob.num).on("click", function () {
513
var element = $("#selective-key-"+ob.num);
514
if(element.hasClass("selective-key-icon-enabled")) {
515
socket.send({'cmd': 'wiseloff', 'data': ob.num});
516
} else {
517
socket.send({'cmd': 'wiselon', 'data': ob.num});
518
}
519
});
520
$("#constant-key-"+ob.num).on("click", function () {
521
var element = $("#constant-key-"+ob.num);
522
if(element.hasClass("constant-key-icon-enabled")) {
523
socket.send({'cmd': 'wiconstantoff', 'data': ob.num});
524
} else {
525
socket.send({'cmd': 'wiconstanton', 'data': ob.num});
526
}
527
});
528
$("#wihandle"+ob.num).off().on("mousedown", function () {
529
wientry_onfocusout()
530
$(".wisortable-container").addClass("wisortable-excluded");
531
// Prevent WI entries with extremely long comments from filling the screen and preventing scrolling
532
$(this).parent().css("max-height", "200px").find(".wicomment").find(".form-control").css("max-height", "110px");
533
}).on("mouseup", function () {
534
$(".wisortable-excluded-dynamic").removeClass("wisortable-excluded-dynamic");
535
$(this).parent().css("max-height", "").find(".wicomment").find(".form-control").css("max-height", "");
536
});
537
538
for (const wientry of document.getElementsByClassName("wientry")) {
539
// If we are uninitialized, skip.
540
if ($(wientry).closest(".wilistitem-uninitialized").length) continue;
541
542
// add() will not add if the class is already present
543
wientry.classList.add("tokens-counted");
544
}
545
546
registerTokenCounters();
547
}
548
549
function addWiFolder(uid, ob) {
550
if(uid !== null) {
551
var uninitialized = $("#wilistfoldercontainer"+null);
552
var html = "<div class=\"wisortable-container "+(ob.collapsed ? "" : "folder-expanded")+"\" id=\"wilistfoldercontainer"+uid+"\" folder-uid=\""+uid+"\">\
553
<div class=\"wilistfolder\" id=\"wilistfolder"+uid+"\">\
554
<div class=\"wiremove\">\
555
<button type=\"button\" class=\"btn btn-primary heightfull\" id=\"btn_wifolder"+uid+"\">X</button>\
556
<button type=\"button\" class=\"btn btn-success heighthalf hidden\" id=\"btn_wifolderdel"+uid+"\">✓</button>\
557
<button type=\"button\" class=\"btn btn-danger heighthalf hidden\" id=\"btn_wifoldercan"+uid+"\">⮌</button>\
558
</div>\
559
<div class=\"wifoldericon\">\
560
<div class=\"wicentered\">\
561
<span class=\"oi oi-folder folder-expand "+(ob.collapsed ? "" : "folder-expanded")+"\" id=\"btn_wifolderexpand"+uid+"\" aria-hidden=\"true\"></span>\
562
</div>\
563
</div>\
564
<div class=\"wifoldername\">\
565
<div class=\"wicentered-vertical\">\
566
<textarea class=\"form-control\" placeholder=\"Untitled Folder\" id=\"wifoldername"+uid+"\">"+ob.name+"</textarea>\
567
</div>\
568
</div>\
569
<div class=\"wihandle wifolderhandle\" id=\"wifolderhandle"+uid+"\">\
570
<div class=\"wicentered\">\
571
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
572
<br/>\
573
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
574
<br/>\
575
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
576
</div>\
577
</div>\
578
</div>\
579
<div class=\"wifoldergutter-container\" id=\"wifoldergutter"+uid+"\">\
580
<div class=\"wifoldergutter\"></div>\
581
</div>\
582
<div class=\"wisortable-body\" folder-uid=\""+uid+"\">\
583
<div class=\"wisortable-dummy\"></div>\
584
</div>\
585
</div>";
586
if(uninitialized.length) {
587
$(html).insertBefore(uninitialized);
588
} else {
589
wi_menu.append(html);
590
}
591
var onfocusout = function () {
592
socket.send({'cmd': 'wifolderupdate', 'uid': uid, 'data': {
593
name: $("#wifoldername"+uid).val(),
594
collapsed: !$("#btn_wifolderexpand"+uid).hasClass("folder-expanded"),
595
}});
596
};
597
$("#wifoldergutter"+uid).on("click", function () {
598
$(this).siblings(".wilistfolder")[0].scrollIntoView();
599
});
600
$("#btn_wifolder"+uid).on("click", function () {
601
showWiFolderDeleteConfirm(uid);
602
});
603
$("#btn_wifolderdel"+uid).on("click", function () {
604
socket.send({'cmd': 'wifolderdelete', 'data': uid});
605
});
606
$("#btn_wifoldercan"+uid).on("click", function () {
607
hideWiFolderDeleteConfirm(uid);
608
})
609
$("#wifoldername"+uid).on("focusout", onfocusout);
610
$("#wifolderhandle"+uid).off().on("mousedown", function () {
611
onfocusout();
612
$(".wilistitem, .wisortable-dummy").addClass("wisortable-excluded-dynamic");
613
// Prevent WI folders with extremely long names from filling the screen and preventing scrolling
614
$(this).parent().parent().find(".wisortable-body").addClass("hidden");
615
$(this).parent().css("max-height", "200px").find(".wifoldername").find(".form-control").css("max-height", "181px");
616
}).on("mouseup", function () {
617
$(".wisortable-excluded-dynamic").removeClass("wisortable-excluded-dynamic");
618
$(this).parent().parent().find(".wisortable-body").removeClass("hidden");
619
$(this).parent().css("max-height", "").find(".wifoldername").find(".form-control").css("max-height", "");
620
});
621
$("#btn_wifolderexpand"+uid).on("click", function () {
622
if($(this).hasClass("folder-expanded")) {
623
socket.send({'cmd': 'wifoldercollapsecontent', 'data': uid});
624
} else {
625
socket.send({'cmd': 'wifolderexpandcontent', 'data': uid});
626
}
627
})
628
adjustWiFolderNameHeight($("#wifoldername"+uid)[0]);
629
if(ob.collapsed) {
630
setTimeout(function() {
631
var container = $("#wilistfoldercontainer"+uid);
632
hide([container.find(".wifoldergutter-container"), container.find(".wisortable-body")]);
633
}, 2);
634
}
635
} else {
636
wi_menu.append("<div class=\"wisortable-container folder-expanded\" id=\"wilistfoldercontainer"+uid+"\">\
637
<div class=\"wilistfolder\" id=\"wilistfolder"+uid+"\">\
638
<div class=\"wiremove\">\
639
<button type=\"button\" class=\"btn btn-primary heightfull\" id=\"btn_wifolder"+uid+"\">+</button>\
640
<button type=\"button\" class=\"btn btn-success heighthalf hidden\" id=\"btn_wifolderdel"+uid+"\">✓</button>\
641
<button type=\"button\" class=\"btn btn-danger heighthalf hidden\" id=\"btn_wifoldercan"+uid+"\">⮌</button>\
642
</div>\
643
<div class=\"wifoldericon\">\
644
<div class=\"wicentered\">\
645
<span class=\"oi oi-folder folder-expand folder-expanded\" id=\"btn_wifolderexpand"+uid+"\" aria-hidden=\"true\"></span>\
646
</div>\
647
</div>\
648
<div class=\"wifoldername\">\
649
<div class=\"wicentered-vertical\">\
650
<textarea class=\"form-control hidden\" placeholder=\"Untitled Folder\" id=\"wifoldername"+uid+"\"></textarea>\
651
</div>\
652
</div>\
653
<div class=\"wihandle-inactive wifolderhandle hidden\" id=\"wifolderhandle"+uid+"\">\
654
<div class=\"wicentered\">\
655
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
656
<br/>\
657
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
658
<br/>\
659
<span class=\"oi oi-grid-two-up\" aria-hidden=\"true\"></span>\
660
</div>\
661
</div>\
662
</div>\
663
<div class=\"wisortable-body\">\
664
<div class=\"wisortable-dummy\"></div>\
665
</div>\
666
</div>");
667
$("#btn_wifolder"+uid).on("click", function () {
668
expandWiFolderLine(uid);
669
});
670
}
671
}
672
673
function expandWiLine(num) {
674
show([$("#wikey"+num), $("#wientry"+num), $("#wihandle"+num), $("#selective-key-"+num), $("#constant-key-"+num), $("#btn_wiselon"+num), $("#wicomment"+num)]);
675
$("#wihandle"+num).removeClass("wihandle-inactive").addClass("wihandle");
676
$("#btn_wi"+num).html("X");
677
$("#btn_wi"+num).off();
678
$("#wilistitem"+num).removeClass("wilistitem-uninitialized").removeClass("wisortable-excluded");
679
$("#btn_wi"+num).on("click", function () {
680
showWiDeleteConfirm(num);
681
});
682
683
adjustWiCommentHeight($("#wicomment"+num)[0]);
684
}
685
686
function expandWiFolderLine(num) {
687
socket.send({'cmd': 'wifolderinit', 'data': ''});
688
}
689
690
function showWiDeleteConfirm(num) {
691
hide([$("#btn_wi"+num)]);
692
show([$("#btn_widel"+num), $("#btn_wican"+num)]);
693
}
694
695
function showWiFolderDeleteConfirm(num) {
696
hide([$("#btn_wifolder"+num)]);
697
show([$("#btn_wifolderdel"+num), $("#btn_wifoldercan"+num)]);
698
}
699
700
function hideWiDeleteConfirm(num) {
701
show([$("#btn_wi"+num)]);
702
hide([$("#btn_widel"+num), $("#btn_wican"+num)]);
703
}
704
705
function hideWiFolderDeleteConfirm(num) {
706
show([$("#btn_wifolder"+num)]);
707
hide([$("#btn_wifolderdel"+num), $("#btn_wifoldercan"+num)]);
708
}
709
710
function collapseWiFolderContent(uid) {
711
hide([$("#wifoldergutter"+uid), $(".wisortable-body[folder-uid="+uid+"]")]);
712
$("#btn_wifolderexpand"+uid).removeClass("folder-expanded");
713
$("#wilistfoldercontainer"+uid).removeClass("folder-expanded");
714
}
715
716
function expandWiFolderContent(uid) {
717
show([$("#wifoldergutter"+uid), $(".wisortable-body[folder-uid="+uid+"]")]);
718
$("#btn_wifolderexpand"+uid).addClass("folder-expanded");
719
$("#wilistfoldercontainer"+uid).addClass("folder-expanded");
720
}
721
722
function enableWiSelective(num) {
723
hide([$("#wikey"+num)]);
724
$("#wikeyprimary"+num).val($("#wikey"+num).val());
725
show([$("#wikeyprimary"+num), $("#wikeysecondary"+num)]);
726
727
var element = $("#selective-key-"+num);
728
element.addClass("selective-key-icon-enabled");
729
$("#wikey"+num).addClass("wilistitem-selective");
730
}
731
732
function disableWiSelective(num) {
733
hide([$("#wikeyprimary"+num), $("#wikeysecondary"+num)]);
734
$("#wikey"+num).val($("#wikeyprimary"+num).val());
735
show([$("#wikey"+num)]);
736
737
var element = $("#selective-key-"+num);
738
element.removeClass("selective-key-icon-enabled");
739
$("#wikey"+num).removeClass("wilistitem-selective");
740
}
741
742
function enableWiConstant(num) {
743
var element = $("#constant-key-"+num);
744
element.addClass("constant-key-icon-enabled");
745
$("#wikey"+num).addClass("wilistitem-constant");
746
}
747
748
function disableWiConstant(num) {
749
var element = $("#constant-key-"+num);
750
element.removeClass("constant-key-icon-enabled");
751
$("#wikey"+num).removeClass("wilistitem-constant");
752
}
753
754
function highlightImportLine(ref) {
755
$("#popupcontent > div").removeClass("popuplistselected");
756
ref.addClass("popuplistselected");
757
enableButtons([popup_accept]);
758
}
759
760
function enableButtons(refs) {
761
for(i=0; i<refs.length; i++) {
762
refs[i].prop("disabled",false);
763
refs[i].removeClass("btn-secondary");
764
refs[i].addClass("btn-primary");
765
}
766
}
767
768
function disableButtons(refs) {
769
for(i=0; i<refs.length; i++) {
770
refs[i].prop("disabled",true);
771
refs[i].removeClass("btn-primary");
772
refs[i].addClass("btn-secondary");
773
}
774
}
775
776
function enableSendBtn() {
777
button_send.removeClass("wait");
778
button_send.addClass("btn-primary");
779
button_send.html("Submit");
780
}
781
782
function disableSendBtn() {
783
button_send.removeClass("btn-primary");
784
button_send.addClass("wait");
785
button_send.html("");
786
}
787
788
function showMessage(msg) {
789
message_text.removeClass();
790
message_text.addClass("color_green");
791
message_text.html(msg);
792
}
793
794
function errMessage(msg, type="error") {
795
message_text.removeClass();
796
message_text.addClass(type == "warn" ? "color_orange" : "color_red");
797
message_text.html(msg);
798
}
799
800
function hideMessage() {
801
message_text.html("");
802
message_text.removeClass();
803
}
804
805
function showWaitAnimation() {
806
hideWaitAnimation();
807
$("#inputrowright").append("<img id=\"waitanim\" src=\"static/thinking.gif\"/>");
808
}
809
810
function hideWaitAnimation() {
811
$('#waitanim').remove();
812
}
813
814
function scrollToBottom() {
815
setTimeout(function () {
816
game_text.stop(true).animate({scrollTop: game_text.prop('scrollHeight')}, 500);
817
}, 5);
818
}
819
820
function hide(refs) {
821
for(i=0; i<refs.length; i++) {
822
refs[i].addClass("hidden");
823
}
824
}
825
826
function show(refs) {
827
for(i=0; i<refs.length; i++) {
828
refs[i].removeClass("hidden");
829
}
830
}
831
832
function popupShow(state) {
833
if(state) {
834
popup.removeClass("hidden");
835
popup.addClass("flex");
836
disableButtons([popup_accept]);
837
} else {
838
popup.removeClass("flex");
839
popup.addClass("hidden");
840
}
841
}
842
843
function enterEditMode() {
844
editmode = true;
845
}
846
847
function exitEditMode() {
848
editmode = false;
849
}
850
851
function enterMemoryMode() {
852
memorymode = true;
853
setmodevisibility(false);
854
setchatnamevisibility(false);
855
showMessage("Edit the memory to be sent with each request to the AI.");
856
button_actmem.html("Cancel");
857
hide([button_actback, button_actfwd, button_actretry, button_actwi]);
858
// Display Author's Note field
859
anote_menu.slideDown("fast");
860
}
861
862
function exitMemoryMode() {
863
memorymode = false;
864
setmodevisibility(adventure);
865
setchatnamevisibility(chatmode);
866
hideMessage();
867
button_actmem.html("Memory");
868
show([button_actback, button_actfwd, button_actretry, button_actwi]);
869
input_text.val("");
870
updateInputBudget(input_text[0]);
871
// Hide Author's Note field
872
anote_menu.slideUp("fast");
873
}
874
875
function enterWiMode() {
876
showMessage("World Info will be added to memory only when the key appears in submitted text or the last action.");
877
button_actwi.html("Accept");
878
hide([button_actback, button_actfwd, button_actmem, button_actretry, game_text]);
879
setchatnamevisibility(false);
880
show([wi_menu]);
881
disableSendBtn();
882
$("#gamescreen").addClass("wigamescreen");
883
}
884
885
function exitWiMode() {
886
hideMessage();
887
button_actwi.html("W Info");
888
hide([wi_menu]);
889
setchatnamevisibility(chatmode);
890
show([button_actback, button_actfwd, button_actmem, button_actretry, game_text]);
891
enableSendBtn();
892
$("#gamescreen").removeClass("wigamescreen");
893
}
894
895
function returnWiList(ar) {
896
var list = [];
897
var i;
898
for(i=0; i<ar.length; i++) {
899
var folder = $("#wilistitem"+ar[i]).parent().attr("folder-uid");
900
if(folder === undefined) {
901
folder = null;
902
} else {
903
folder = parseInt(folder);
904
}
905
var ob = {"key": "", "keysecondary": "", "content": "", "comment": "", "folder": null, "uid": parseInt($("#wilistitem"+ar[i]).attr("uid")), "selective": false, "constant": false};
906
ob.selective = $("#wikeyprimary"+ar[i]).css("display") != "none"
907
ob.key = ob.selective ? $("#wikeyprimary"+ar[i]).val() : $("#wikey"+ar[i]).val();
908
ob.keysecondary = $("#wikeysecondary"+ar[i]).val();
909
ob.content = $("#wientry"+ar[i]).val();
910
ob.comment = $("#wicomment"+i).val();
911
ob.folder = folder;
912
ob.constant = $("#constant-key-"+ar[i]).hasClass("constant-key-icon-enabled");
913
list.push(ob);
914
}
915
socket.send({'cmd': 'sendwilist', 'data': list});
916
}
917
918
function formatChunkInnerText(chunk) {
919
var text = chunk.innerText.replace(/\u00a0/g, " ");
920
if((chunk.nextSibling === null || chunk.nextSibling.nodeType !== 1 || chunk.nextSibling.tagName !== "CHUNK") && text.slice(-1) === '\n') {
921
return text.slice(0, -1);
922
}
923
return text;
924
}
925
926
function dosubmit(disallow_abort) {
927
beginStream();
928
submit_start = Date.now();
929
var txt = input_text.val().replace(/\u00a0/g, " ");
930
if((disallow_abort || gamestate !== "wait") && !memorymode && !gamestarted && ((!adventure || !action_mode) && txt.trim().length == 0)) {
931
return;
932
}
933
chunkOnFocusOut("override");
934
// Wait for editor changes to be applied before submitting
935
submit_throttle = getThrottle(70);
936
submit_throttle.txt = txt;
937
submit_throttle.disallow_abort = disallow_abort;
938
submit_throttle(0, _dosubmit);
939
}
940
941
function _dosubmit() {
942
beginStream();
943
var txt = submit_throttle.txt;
944
var disallow_abort = submit_throttle.disallow_abort;
945
submit_throttle = null;
946
input_text.val("");
947
hideMessage();
948
hidegenseqs();
949
socket.send({'cmd': 'submit', 'allowabort': !disallow_abort, 'actionmode': adventure ? action_mode : 0, 'chatname': chatmode ? chat_name.val() : undefined, 'data': txt});
950
}
951
952
function changemode() {
953
if(gamestarted) {
954
action_mode += 1;
955
action_mode %= 2; // Total number of action modes (Story and Action)
956
} else {
957
action_mode = 0; // Force "Story" mode if game is not started
958
}
959
960
switch (action_mode) {
961
case 0: button_mode_label.html("Story"); break;
962
case 1: button_mode_label.html("Action"); break;
963
}
964
}
965
966
function newTextHighlight(ref) {
967
ref.addClass("edit-flash");
968
setTimeout(function () {
969
ref.addClass("colorfade");
970
ref.removeClass("edit-flash");
971
setTimeout(function () {
972
ref.removeClass("colorfade");
973
}, 1000);
974
}, 50);
975
}
976
977
function showAidgPopup() {
978
aidgpopup.removeClass("hidden");
979
aidgpopup.addClass("flex");
980
aidgpromptnum.focus();
981
}
982
983
function hideAidgPopup() {
984
aidgpopup.removeClass("flex");
985
aidgpopup.addClass("hidden");
986
}
987
988
function sendAidgImportRequest() {
989
socket.send({'cmd': 'aidgimport', 'data': aidgpromptnum.val()});
990
hideAidgPopup();
991
aidgpromptnum.val("");
992
}
993
994
function showSaveAsPopup() {
995
disableButtons([saveas_accept]);
996
saveaspopup.removeClass("hidden");
997
saveaspopup.addClass("flex");
998
saveasinput.focus();
999
}
1000
1001
function hideSaveAsPopup() {
1002
saveaspopup.removeClass("flex");
1003
saveaspopup.addClass("hidden");
1004
saveasinput.val("");
1005
hide([$(".saveasoverwrite"), $(".popuperror")]);
1006
}
1007
1008
function sendSaveAsRequest() {
1009
socket.send({'cmd': 'saveasrequest', 'data': {"name": saveasinput.val(), "pins": savepins.prop('checked')}});
1010
}
1011
1012
function showLoadModelPopup() {
1013
loadmodelpopup.removeClass("hidden");
1014
loadmodelpopup.addClass("flex");
1015
}
1016
1017
function hideLoadModelPopup() {
1018
loadmodelpopup.removeClass("flex");
1019
loadmodelpopup.addClass("hidden");
1020
loadmodelcontent.html("");
1021
}
1022
1023
function showLoadPopup() {
1024
loadpopup.removeClass("hidden");
1025
loadpopup.addClass("flex");
1026
}
1027
1028
function hideLoadPopup() {
1029
loadpopup.removeClass("flex");
1030
loadpopup.addClass("hidden");
1031
loadcontent.html("");
1032
}
1033
1034
function showSPPopup() {
1035
sppopup.removeClass("hidden");
1036
sppopup.addClass("flex");
1037
}
1038
1039
function hideSPPopup() {
1040
sppopup.removeClass("flex");
1041
sppopup.addClass("hidden");
1042
spcontent.html("");
1043
}
1044
1045
function showUSPopup() {
1046
uspopup.removeClass("hidden");
1047
uspopup.addClass("flex");
1048
}
1049
1050
function hideUSPopup() {
1051
uspopup.removeClass("flex");
1052
uspopup.addClass("hidden");
1053
spcontent.html("");
1054
}
1055
1056
function showSamplersPopup() {
1057
samplerspopup.removeClass("hidden");
1058
samplerspopup.addClass("flex");
1059
}
1060
1061
function hideSamplersPopup() {
1062
samplerspopup.removeClass("flex");
1063
samplerspopup.addClass("hidden");
1064
}
1065
1066
1067
function buildLoadModelList(ar, menu, breadcrumbs, showdelete) {
1068
disableButtons([load_model_accept]);
1069
loadmodelcontent.html("");
1070
$("#loadmodellistbreadcrumbs").html("");
1071
$("#custommodelname").addClass("hidden");
1072
var i;
1073
for(i=0; i<breadcrumbs.length; i++) {
1074
$("#loadmodellistbreadcrumbs").append("<button class=\"breadcrumbitem\" id='model_breadcrumbs"+i+"' name='"+ar[0][1]+"' value='"+breadcrumbs[i][0]+"'>"+breadcrumbs[i][1]+"</button><font color=white>\\</font>");
1075
$("#model_breadcrumbs"+i).off("click").on("click", (function () {
1076
return function () {
1077
socket.send({'cmd': 'selectmodel', 'data': $(this).attr("name"), 'folder': $(this).attr("value")});
1078
disableButtons([load_model_accept]);
1079
}
1080
})(i));
1081
}
1082
if (breadcrumbs.length > 0) {
1083
$("#loadmodellistbreadcrumbs").append("<hr size='1'>")
1084
}
1085
//If we're in the custom load menu (we need to send the path data back in that case)
1086
if(['NeoCustom', 'GPT2Custom'].includes(menu)) {
1087
$("#loadmodel"+i).off("click").on("click", (function () {
1088
return function () {
1089
socket.send({'cmd': 'selectmodel', 'data': $(this).attr("name"), 'path': $(this).attr("pretty_name")});
1090
highlightLoadLine($(this));
1091
}
1092
})(i));
1093
$("#custommodelname").removeClass("hidden");
1094
$("#custommodelname")[0].setAttribute("menu", menu);
1095
}
1096
1097
for(i=0; i<ar.length; i++) {
1098
if (Array.isArray(ar[i][0])) {
1099
full_path = ar[i][0][0];
1100
folder = ar[i][0][1];
1101
} else {
1102
full_path = "";
1103
folder = ar[i][0];
1104
}
1105
1106
var html
1107
html = "<div class=\"flex\">\
1108
<div class=\"loadlistpadding\"></div>"
1109
//if the menu item is a link to another menu
1110
console.log(ar[i]);
1111
if((ar[i][3]) || (['Load a model from its directory', 'Load an old GPT-2 model (eg CloverEdition)'].includes(ar[i][0]))) {
1112
html = html + "<span class=\"loadlisticon loadmodellisticon-folder oi oi-folder allowed\" aria-hidden=\"true\"></span>"
1113
} else {
1114
//this is a model
1115
html = html + "<div class=\"loadlisticon oi oi-caret-right allowed\"></div>&nbsp;&nbsp;&nbsp;"
1116
}
1117
1118
//now let's do the delete icon if applicable
1119
if (['NeoCustom', 'GPT2Custom'].includes(menu) && !ar[i][3] && showdelete) {
1120
html = html + "<span class=\"loadlisticon loadmodellisticon-folder oi oi-x allowed\" aria-hidden=\"true\" onclick='if(confirm(\"This will delete the selected folder with all contents. Are you sure?\")) { socket.send({\"cmd\": \"delete_model\", \"data\": \""+full_path.replaceAll("\\", "\\\\")+"\", \"menu\": \""+menu+"\"});}'></span>"
1121
} else {
1122
html = html + "<div class=\"loadlistpadding\"></div>"
1123
}
1124
1125
html = html + "<div class=\"loadlistpadding\"></div>\
1126
<div class=\"loadlistitem\" id=\"loadmodel"+i+"\" name=\""+ar[i][1]+"\" pretty_name=\""+full_path+"\">\
1127
<div>"+folder+"</div>\
1128
<div class=\"flex-push-right\">"+ar[i][2]+"</div>\
1129
</div>\
1130
</div>"
1131
loadmodelcontent.append(html);
1132
//If this is a menu
1133
console.log(ar[i]);
1134
if(ar[i][3]) {
1135
$("#loadmodel"+i).off("click").on("click", (function () {
1136
return function () {
1137
socket.send({'cmd': 'list_model', 'data': $(this).attr("name"), 'pretty_name': $(this).attr("pretty_name")});
1138
disableButtons([load_model_accept]);
1139
}
1140
})(i));
1141
//Normal load
1142
} else {
1143
if (['NeoCustom', 'GPT2Custom'].includes(menu)) {
1144
$("#loadmodel"+i).off("click").on("click", (function () {
1145
return function () {
1146
$("#use_gpu_div").addClass("hidden");
1147
$("#modelkey").addClass("hidden");
1148
$("#modellayers").addClass("hidden");
1149
socket.send({'cmd': 'selectmodel', 'data': $(this).attr("name"), 'path': $(this).attr("pretty_name")});
1150
highlightLoadLine($(this));
1151
}
1152
})(i));
1153
} else {
1154
$("#loadmodel"+i).off("click").on("click", (function () {
1155
return function () {
1156
$("#use_gpu_div").addClass("hidden");
1157
$("#modelkey").addClass("hidden");
1158
$("#modellayers").addClass("hidden");
1159
socket.send({'cmd': 'selectmodel', 'data': $(this).attr("name")});
1160
highlightLoadLine($(this));
1161
}
1162
})(i));
1163
}
1164
}
1165
}
1166
}
1167
1168
function buildLoadList(ar) {
1169
disableButtons([load_accept]);
1170
loadcontent.html("");
1171
showLoadPopup();
1172
var i;
1173
for(i=0; i<ar.length; i++) {
1174
loadcontent.append("<div class=\"flex\">\
1175
<div class=\"loadlistpadding\"></div>\
1176
<span class=\"loadlisticon loadlisticon-delete oi oi-x "+(sman_allow_delete ? "allowed" : "")+"\" id=\"loaddelete"+i+"\" "+(sman_allow_delete ? "title=\"Delete story\"" : "")+" aria-hidden=\"true\"></span>\
1177
<div class=\"loadlistpadding\"></div>\
1178
<span class=\"loadlisticon loadlisticon-rename oi oi-pencil "+(sman_allow_rename ? "allowed" : "")+"\" id=\"loadrename"+i+"\" "+(sman_allow_rename ? "title=\"Rename story\"" : "")+" aria-hidden=\"true\"></span>\
1179
<div class=\"loadlistpadding\"></div>\
1180
<div class=\"loadlistitem\" id=\"load"+i+"\" name=\""+ar[i].name+"\">\
1181
<div>"+ar[i].name+"</div>\
1182
<div class=\"flex-push-right\">"+ar[i].actions+"</div>\
1183
</div>\
1184
</div>");
1185
$("#load"+i).on("click", function () {
1186
enableButtons([load_accept]);
1187
socket.send({'cmd': 'loadselect', 'data': $(this).attr("name")});
1188
highlightLoadLine($(this));
1189
});
1190
1191
$("#loaddelete"+i).off("click").on("click", (function (name) {
1192
return function () {
1193
if(!sman_allow_delete) {
1194
return;
1195
}
1196
$("#loadcontainerdelete-storyname").text(name);
1197
$("#btn_dsaccept").off("click").on("click", (function (name) {
1198
return function () {
1199
hide([$(".saveasoverwrite"), $(".popuperror")]);
1200
socket.send({'cmd': 'deletestory', 'data': name});
1201
}
1202
})(name));
1203
$("#loadcontainerdelete").removeClass("hidden").addClass("flex");
1204
}
1205
})(ar[i].name));
1206
1207
$("#loadrename"+i).off("click").on("click", (function (name) {
1208
return function () {
1209
if(!sman_allow_rename) {
1210
return;
1211
}
1212
$("#newsavename").val("")
1213
$("#loadcontainerrename-storyname").text(name);
1214
var submit = (function (name) {
1215
return function () {
1216
hide([$(".saveasoverwrite"), $(".popuperror")]);
1217
socket.send({'cmd': 'renamestory', 'data': name, 'newname': $("#newsavename").val()});
1218
}
1219
})(name);
1220
$("#btn_rensaccept").off("click").on("click", submit);
1221
$("#newsavename").off("keydown").on("keydown", function (ev) {
1222
if (ev.which == 13 && $(this).val() != "") {
1223
submit();
1224
}
1225
});
1226
$("#loadcontainerrename").removeClass("hidden").addClass("flex");
1227
$("#newsavename").val(name).select();
1228
}
1229
})(ar[i].name));
1230
}
1231
}
1232
1233
function buildSPList(ar) {
1234
disableButtons([sp_accept]);
1235
spcontent.html("");
1236
showSPPopup();
1237
ar.push({filename: '', name: "[None]"})
1238
for(var i = 0; i < ar.length; i++) {
1239
var author = !ar[i].author
1240
? ''
1241
: ar[i].author.constructor === Array
1242
? ar[i].author.join(', ')
1243
: ar[i].author;
1244
var n_tokens = !ar[i].n_tokens || !Number.isSafeInteger(ar[i].n_tokens) || ar[i].n_tokens < 1
1245
? ''
1246
: "(" + ar[i].n_tokens + " tokens)";
1247
var filename = ar[i].filename.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;').replace(/(?=\r|\n)\r?\n?/g, '<br/>');
1248
var name = ar[i].name || ar[i].filename;
1249
name = name.length > 120 ? name.slice(0, 117) + '...' : name;
1250
name = name.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;').replace(/(?=\r|\n)\r?\n?/g, '<br/>');
1251
var desc = ar[i].description || '';
1252
desc = desc.length > 500 ? desc.slice(0, 497) + '...' : desc;
1253
desc = desc.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;').replace(/(?=\r|\n)\r?\n?/g, '<br/>');
1254
spcontent.append("<div class=\"flex\">\
1255
<div class=\"splistitem flex-row-container\" id=\"sp"+i+"\" name=\""+ar[i].filename+"\">\
1256
<div class=\"flex-row\">\
1257
<div>"+name+"</div>\
1258
<div class=\"flex-push-right splistitemsub\">"+filename+"</div>\
1259
</div>\
1260
<div class=\"flex-row\">\
1261
<div>"+desc+"</div>\
1262
<div class=\"flex-push-right splistitemsub\">" + author + "<br/>" + n_tokens + "</div>\
1263
</div>\
1264
</div>\
1265
</div>");
1266
$("#sp"+i).on("click", function () {
1267
enableButtons([sp_accept]);
1268
socket.send({'cmd': 'spselect', 'data': $(this).attr("name")});
1269
highlightSPLine($(this));
1270
});
1271
}
1272
}
1273
1274
function buildUSList(unloaded, loaded) {
1275
usunloaded.html("");
1276
usloaded.html("");
1277
showUSPopup();
1278
var i;
1279
var j;
1280
var el = usunloaded;
1281
var ar = unloaded;
1282
for(j=0; j<2; j++) {
1283
for(i=0; i<ar.length; i++) {
1284
el.append("<div class=\"flex\">\
1285
<div class=\"uslistitem flex-row-container\" name=\""+ar[i].filename+"\">\
1286
<div class=\"flex-row\">\
1287
<div>"+ar[i].modulename+"</div>\
1288
<div class=\"flex-push-right uslistitemsub\">&lt;"+ar[i].filename+"&gt;</div>\
1289
</div>\
1290
<div class=\"flex-row\">\
1291
<div>"+ar[i].description+"</div>\
1292
</div>\
1293
</div>\
1294
</div>");
1295
}
1296
el = usloaded;
1297
ar = loaded;
1298
}
1299
}
1300
1301
function buildSamplerList(samplers) {
1302
samplerslist.html("");
1303
showSamplersPopup();
1304
var i;
1305
var samplers_lookup_table = [
1306
"Top-k Sampling",
1307
"Top-a Sampling",
1308
"Top-p Sampling",
1309
"Tail-free Sampling",
1310
"Typical Sampling",
1311
"Temperature",
1312
"Repetition Penalty",
1313
]
1314
for(i=0; i<samplers.length; i++) {
1315
samplerslist.append("<div class=\"flex\">\
1316
<div class=\"samplerslistitem flex-row-container\" sid=\""+samplers[i]+"\">\
1317
<div class=\"flex-row\">\
1318
<div>"+(samplers[i] < samplers_lookup_table.length ? samplers_lookup_table[samplers[i]] : "Unknown sampler #" + samplers[i])+"</div>\
1319
</div>\
1320
</div>\
1321
</div>");
1322
}
1323
}
1324
1325
function highlightLoadLine(ref) {
1326
$("#loadlistcontent > div > div.popuplistselected").removeClass("popuplistselected");
1327
$("#loadmodellistcontent > div > div.popuplistselected").removeClass("popuplistselected");
1328
ref.addClass("popuplistselected");
1329
}
1330
1331
function highlightSPLine(ref) {
1332
$("#splistcontent > div > div.popuplistselected").removeClass("popuplistselected");
1333
ref.addClass("popuplistselected");
1334
}
1335
1336
function showNewStoryPopup() {
1337
nspopup.removeClass("hidden");
1338
nspopup.addClass("flex");
1339
}
1340
1341
function hideNewStoryPopup() {
1342
nspopup.removeClass("flex");
1343
nspopup.addClass("hidden");
1344
}
1345
1346
function showRandomStoryPopup() {
1347
rspopup.removeClass("hidden");
1348
rspopup.addClass("flex");
1349
if($("#setrngpersist").prop("checked")) {
1350
$("#rngmemory").val(memorytext);
1351
}
1352
}
1353
1354
function hideRandomStoryPopup() {
1355
rspopup.removeClass("flex");
1356
rspopup.addClass("hidden");
1357
}
1358
1359
function statFlash(ref) {
1360
ref.addClass("status-flash");
1361
setTimeout(function () {
1362
ref.addClass("colorfade");
1363
ref.removeClass("status-flash");
1364
setTimeout(function () {
1365
ref.removeClass("colorfade");
1366
}, 1000);
1367
}, 50);
1368
}
1369
1370
function updateUSStatItems(items, flash) {
1371
var stat_us = $("#stat-us");
1372
var stat_usactive = $("#stat-usactive");
1373
if(flash || stat_usactive.find("li").length != items.length) {
1374
statFlash(stat_us.closest(".statusicon").add("#usiconlabel"));
1375
}
1376
stat_usactive.html("");
1377
if(items.length == 0) {
1378
stat_us.html("No userscripts active");
1379
$("#usiconlabel").html("");
1380
stat_us.closest(".statusicon").removeClass("active");
1381
return;
1382
}
1383
stat_us.html("Active userscripts:");
1384
stat_us.closest(".statusicon").addClass("active");
1385
var i;
1386
for(i = 0; i < items.length; i++) {
1387
stat_usactive.append($("<li filename=\""+items[i].filename+"\">"+items[i].modulename+" &lt;"+items[i].filename+"&gt;</li>"));
1388
}
1389
$("#usiconlabel").html(items.length);
1390
}
1391
1392
function updateSPStatItems(items) {
1393
var stat_sp = $("#stat-sp");
1394
var stat_spactive = $("#stat-spactive");
1395
var key = null;
1396
var old_val = stat_spactive.html();
1397
Object.keys(items).forEach(function(k) {key = k;});
1398
if(key === null) {
1399
stat_sp.html("No soft prompt active");
1400
stat_sp.closest(".statusicon").removeClass("active");
1401
stat_spactive.html("");
1402
} else {
1403
stat_sp.html("Active soft prompt (" + items[key].n_tokens + " tokens):");
1404
stat_sp.closest(".statusicon").addClass("active");
1405
stat_spactive.html((items[key].name || key)+" &lt;"+key+"&gt;");
1406
}
1407
if(stat_spactive.html() !== old_val) {
1408
statFlash(stat_sp.closest(".statusicon"));
1409
}
1410
}
1411
1412
function setStartState() {
1413
enableSendBtn();
1414
enableButtons([button_actmem, button_actwi]);
1415
disableButtons([button_actback, button_actfwd, button_actretry]);
1416
hide([wi_menu]);
1417
show([game_text, button_actmem, button_actwi, button_actback, button_actfwd, button_actretry]);
1418
hideMessage();
1419
hideWaitAnimation();
1420
button_actmem.html("Memory");
1421
button_actwi.html("W Info");
1422
hideAidgPopup();
1423
hideSaveAsPopup();
1424
hideLoadPopup();
1425
hideNewStoryPopup();
1426
hidegenseqs();
1427
}
1428
1429
function parsegenseqs(seqs) {
1430
seqselcontents.html("");
1431
var i;
1432
for(i=0; i<seqs.length; i++) {
1433
//setup selection data
1434
text_data = "<table><tr><td width=100%><div class=\"seqselitem\" id=\"seqsel"+i+"\" n=\""+i+"\">"+seqs[i][0]+"</div></td><td width=10>"
1435
1436
//Now do the icon (pin/redo)
1437
1438
if (seqs[i][1] == "redo") {
1439
text_data = text_data + "<span style=\"color: white\" class=\"oi oi-loop-circular\" title=\"Redo\" aria-hidden=\"true\" id=\"seqselpin"+i+"\" n=\""+i+"\"></span>"
1440
} else if (seqs[i][1] == "pinned") {
1441
text_data = text_data + "<span style=\"color: white\" class=\"oi oi-pin\" title=\"Pin\" aria-hidden=\"true\" id=\"seqselpin"+i+"\" n=\""+i+"\"></span>"
1442
} else {
1443
text_data = text_data + "<span style=\"color: grey\" class=\"oi oi-pin\" title=\"Pin\" aria-hidden=\"true\" id=\"seqselpin"+i+"\" n=\""+i+"\"></span>"
1444
}
1445
text_data = text_data + "</td></tr></table>"
1446
seqselcontents.append(text_data);
1447
1448
//setup on-click actions
1449
$("#seqsel"+i).on("click", function () {
1450
socket.send({'cmd': 'seqsel', 'data': $(this).attr("n")});
1451
});
1452
1453
//onclick for pin only
1454
if (seqs[i][1] != "redo") {
1455
$("#seqselpin"+i).on("click", function () {
1456
socket.send({'cmd': 'seqpin', 'data': $(this).attr("n")});
1457
if ($(this).attr("style") == "color: grey") {
1458
console.log($(this).attr("style"));
1459
$(this).css({"color": "white"});
1460
console.log($(this).attr("style"));
1461
} else {
1462
console.log($(this).attr("style"));
1463
$(this).css({"color": "grey"});
1464
console.log($(this).attr("style"));
1465
}
1466
});
1467
}
1468
}
1469
$('#seqselmenu').slideDown("slow");
1470
}
1471
1472
function hidegenseqs() {
1473
$('#seqselmenu').slideUp("slow", function() {
1474
seqselcontents.html("");
1475
});
1476
scrollToBottom();
1477
}
1478
1479
function setmodevisibility(state) {
1480
if(state){ // Enabling
1481
show([button_mode]);
1482
$("#inputrow").addClass("show_mode");
1483
} else{ // Disabling
1484
hide([button_mode]);
1485
$("#inputrow").removeClass("show_mode");
1486
}
1487
}
1488
1489
function setchatnamevisibility(state) {
1490
if(state){ // Enabling
1491
show([chat_name]);
1492
} else{ // Disabling
1493
hide([chat_name]);
1494
}
1495
}
1496
1497
function setadventure(state) {
1498
adventure = state;
1499
if(state) {
1500
game_text.addClass("adventure");
1501
} else {
1502
game_text.removeClass("adventure");
1503
}
1504
if(!memorymode){
1505
setmodevisibility(state);
1506
}
1507
}
1508
1509
function setchatmode(state) {
1510
chatmode = state;
1511
setchatnamevisibility(state);
1512
}
1513
1514
function autofocus(event) {
1515
if(connected) {
1516
event.target.focus();
1517
} else {
1518
event.preventDefault();
1519
}
1520
}
1521
1522
function sortableOnStart(event, ui) {
1523
}
1524
1525
function sortableOnStop(event, ui) {
1526
if(ui.item.hasClass("wilistitem")) {
1527
// When a WI entry is dragged and dropped, tell the server which WI
1528
// entry was dropped and which WI entry comes immediately after the
1529
// dropped position so that the server can internally move around
1530
// the WI entries
1531
var next_sibling = ui.item.next(".wilistitem").attr("uid");
1532
if(next_sibling === undefined) {
1533
next_sibling = ui.item.next().next().attr("uid");
1534
}
1535
next_sibling = parseInt(next_sibling);
1536
if(Number.isNaN(next_sibling)) {
1537
$(this).sortable("cancel");
1538
return;
1539
}
1540
socket.send({'cmd': 'wimoveitem', 'destination': next_sibling, 'data': parseInt(ui.item.attr("uid"))});
1541
} else {
1542
// Do the same thing for WI folders
1543
var next_sibling = ui.item.next(".wisortable-container").attr("folder-uid");
1544
if(next_sibling === undefined) {
1545
next_sibling = null;
1546
} else {
1547
next_sibling = parseInt(next_sibling);
1548
}
1549
if(Number.isNaN(next_sibling)) {
1550
$(this).sortable("cancel");
1551
return;
1552
}
1553
socket.send({'cmd': 'wimovefolder', 'destination': next_sibling, 'data': parseInt(ui.item.attr("folder-uid"))});
1554
}
1555
}
1556
1557
function chunkOnTextInput(event) {
1558
// The enter key does not behave correctly in almost all non-Firefox
1559
// browsers, so we (attempt to) shim all enter keystrokes here to behave the
1560
// same as in Firefox
1561
if(event.originalEvent.data.slice(-1) === '\n') {
1562
event.preventDefault();
1563
var s = getSelection(); // WARNING: Do not use rangy.getSelection() instead of getSelection()
1564
var r = s.getRangeAt(0);
1565
1566
// We prefer using document.execCommand here because it works best on
1567
// mobile devices, but the other method is also here as
1568
// a fallback
1569
if(document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertHTML')) {
1570
document.execCommand('insertHTML', false, event.originalEvent.data.slice(0, -1).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;').replace(/(?=\r|\n)\r?\n?/g, '<br/>') + '<br id="_EDITOR_LINEBREAK_"/><span id="_EDITOR_SENTINEL_">|</span>');
1571
var t = $('#_EDITOR_SENTINEL_').contents().filter(function() { return this.nodeType === 3; })[0];
1572
} else {
1573
var t = document.createTextNode('|');
1574
var b = document.createElement('br');
1575
b.id = "_EDITOR_LINEBREAK_";
1576
r.insertNode(b);
1577
r.collapse(false);
1578
r.insertNode(t);
1579
}
1580
1581
r.selectNodeContents(t);
1582
s.removeAllRanges();
1583
s.addRange(r);
1584
if(document.queryCommandSupported && document.execCommand && document.queryCommandSupported('forwardDelete')) {
1585
r.collapse(true);
1586
document.execCommand('forwardDelete');
1587
} else {
1588
// deleteContents() sometimes breaks using the left
1589
// arrow key in some browsers so we prefer the
1590
// document.execCommand method
1591
r.deleteContents();
1592
}
1593
1594
// In Chrome and Safari the added <br/> will go outside of the chunks if we press
1595
// enter at the end of the story in the editor, so this is here
1596
// to put the <br/> back in the right place
1597
var br = $("#_EDITOR_LINEBREAK_")[0];
1598
if(br.parentNode === game_text[0]) {
1599
var parent = br.previousSibling;
1600
if(br.previousSibling.nodeType !== 1) {
1601
parent = br.previousSibling.previousSibling;
1602
br.previousSibling.previousSibling.appendChild(br.previousSibling);
1603
}
1604
if(parent.lastChild.tagName === "BR") {
1605
parent.lastChild.remove(); // Chrome and Safari also insert an extra <br/> in this case for some reason so we need to remove it
1606
if(using_webkit_patch) {
1607
// Safari on iOS has a bug where it selects all text in the last chunk of the story when this happens so we collapse the selection to the end of the chunk in that case
1608
setTimeout(function() {
1609
var s = getSelection();
1610
var r = s.getRangeAt(0);
1611
r.selectNodeContents(parent);
1612
r.collapse(false);
1613
s.removeAllRanges();
1614
s.addRange(r);
1615
}, 2);
1616
}
1617
}
1618
br.previousSibling.appendChild(br);
1619
r.selectNodeContents(br.parentNode);
1620
s.removeAllRanges();
1621
s.addRange(r);
1622
r.collapse(false);
1623
}
1624
br.id = "";
1625
if(game_text[0].lastChild.tagName === "BR") {
1626
br.parentNode.appendChild(game_text[0].lastChild);
1627
}
1628
return;
1629
}
1630
}
1631
1632
// This gets run when one or more chunks are edited. The event occurs before
1633
// the actual edits are made by the browser, so we are free to check which
1634
// nodes are selected or stop the event from occurring.
1635
function chunkOnBeforeInput(event) {
1636
// Register all selected chunks as having been modified
1637
applyChunkDeltas(getSelectedNodes());
1638
1639
// Fix editing across chunks and paragraphs in Firefox 93.0 and higher
1640
if(event.originalEvent.inputType === "deleteContentBackward" && document.queryCommandSupported && document.execCommand && document.queryCommandSupported('delete')) {
1641
event.preventDefault();
1642
document.execCommand('delete');
1643
}
1644
var s = rangy.getSelection();
1645
1646
if(buildChunkSetFromNodeArray(getSelectedNodes()).size === 0) {
1647
var s = rangy.getSelection();
1648
var r = s.getRangeAt(0);
1649
var rand = Math.random();
1650
if(document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertHTML')) {
1651
document.execCommand('insertHTML', false, '<span id="_EDITOR_SENTINEL_' + rand + '_">|</span>');
1652
} else {
1653
var t = document.createTextNode('|');
1654
var b = document.createElement('span');
1655
b.id = "_EDITOR_SENTINEL_" + rand + "_";
1656
b.insertNode(t);
1657
r.insertNode(b);
1658
}
1659
setTimeout(function() {
1660
var sentinel = document.getElementById("_EDITOR_SENTINEL_" + rand + "_");
1661
if(sentinel.nextSibling && sentinel.nextSibling.tagName === "CHUNK") {
1662
r.selectNodeContents(sentinel.nextSibling);
1663
r.collapse(true);
1664
} else if(sentinel.previousSibling && sentinel.previousSibling.tagName === "CHUNK") {
1665
r.selectNodeContents(sentinel.previousSibling);
1666
r.collapse(false);
1667
}
1668
s.removeAllRanges();
1669
s.addRange(r);
1670
sentinel.parentNode.removeChild(sentinel);
1671
}, 1);
1672
}
1673
}
1674
1675
function chunkOnKeyDown(event) {
1676
// Make escape commit the changes (Originally we had Enter here to but its not required and nicer for users if we let them type freely
1677
// You can add the following after 27 if you want it back to committing on enter : || (!event.shiftKey && event.keyCode == 13)
1678
if(event.keyCode == 27) {
1679
override_focusout = true;
1680
game_text.blur();
1681
event.preventDefault();
1682
return;
1683
}
1684
1685
// Don't allow any edits if not connected to server
1686
if(!connected) {
1687
event.preventDefault();
1688
return;
1689
}
1690
1691
// Prevent CTRL+B, CTRL+I and CTRL+U when editing chunks
1692
if(event.ctrlKey || event.metaKey) { // metaKey is macOS's command key
1693
switch(event.keyCode) {
1694
case 66:
1695
case 98:
1696
case 73:
1697
case 105:
1698
case 85:
1699
case 117:
1700
event.preventDefault();
1701
return;
1702
}
1703
}
1704
}
1705
1706
function downloadStory(format) {
1707
var filename_without_extension = storyname !== null ? storyname : "untitled";
1708
1709
var anchor = document.createElement('a');
1710
1711
var actionlist = $("chunk");
1712
var actionlist_compiled = [];
1713
for(var i = 0; i < actionlist.length; i++) {
1714
actionlist_compiled.push(actionlist[i].innerText.replace(/\u00a0/g, " "));
1715
}
1716
var last = actionlist_compiled[actionlist_compiled.length-1];
1717
if(last && last.slice(-1) === '\n') {
1718
actionlist_compiled[actionlist_compiled.length-1] = last.slice(0, -1);
1719
}
1720
1721
if(format == "plaintext") {
1722
var objectURL = URL.createObjectURL(new Blob(actionlist_compiled, {type: "text/plain; charset=UTF-8"}));
1723
anchor.setAttribute('href', objectURL);
1724
anchor.setAttribute('download', filename_without_extension + ".txt");
1725
anchor.click();
1726
URL.revokeObjectURL(objectURL);
1727
return;
1728
}
1729
1730
var wilist = $(".wilistitem");
1731
var wilist_compiled = [];
1732
for(var i = 0; i < wilist.length; i++) {
1733
if(wilist[i].classList.contains("wilistitem-uninitialized")) {
1734
continue;
1735
}
1736
var selective = wilist[i].classList.contains("wilistitem-selective");
1737
var folder = $("#wilistitem"+i).parent().attr("folder-uid");
1738
if(folder === undefined) {
1739
folder = null;
1740
} else {
1741
folder = parseInt(folder);
1742
}
1743
wilist_compiled.push({
1744
key: selective ? $("#wikeyprimary"+i).val() : $("#wikey"+i).val(),
1745
keysecondary: $("#wikeysecondary"+i).val(),
1746
content: $("#wientry"+i).val(),
1747
comment: $("#wicomment"+i).val(),
1748
folder: folder,
1749
selective: selective,
1750
constant: wilist[i].classList.contains("wilistitem-constant"),
1751
});
1752
}
1753
1754
var prompt = actionlist_compiled.shift();
1755
if(prompt === undefined) {
1756
prompt = "";
1757
}
1758
var objectURL = URL.createObjectURL(new Blob([JSON.stringify({
1759
gamestarted: gamestarted,
1760
prompt: prompt,
1761
memory: memorytext,
1762
authorsnote: $("#anoteinput").val(),
1763
anotetemplate: $("#anotetemplate").val(),
1764
actions: actionlist_compiled,
1765
worldinfo: wilist_compiled,
1766
wifolders_d: wifolders_d,
1767
wifolders_l: wifolders_l,
1768
}, null, 3)], {type: "application/json; charset=UTF-8"}));
1769
anchor.setAttribute('href', objectURL);
1770
anchor.setAttribute('download', filename_without_extension + ".json");
1771
anchor.click();
1772
URL.revokeObjectURL(objectURL);
1773
}
1774
1775
function buildChunkSetFromNodeArray(nodes) {
1776
var set = new Set();
1777
for(var i = 0; i < nodes.length; i++) {
1778
node = nodes[i];
1779
while(node !== null && node.tagName !== "CHUNK") {
1780
node = node.parentNode;
1781
}
1782
if(node === null) {
1783
continue;
1784
}
1785
set.add(node.getAttribute("n"));
1786
}
1787
return set;
1788
}
1789
1790
function getSelectedNodes() {
1791
var range = rangy.getSelection().getRangeAt(0); // rangy is not a typo
1792
var nodes = range.getNodes([1,3]);
1793
nodes.push(range.startContainer);
1794
nodes.push(range.endContainer);
1795
return nodes
1796
}
1797
1798
function applyChunkDeltas(nodes) {
1799
var chunks = Array.from(buildChunkSetFromNodeArray(nodes));
1800
for(var i = 0; i < chunks.length; i++) {
1801
modified_chunks.add(chunks[i]);
1802
all_modified_chunks.add(chunks[i]);
1803
}
1804
setTimeout(function() {
1805
var chunks = Array.from(modified_chunks);
1806
var selected_chunks = buildChunkSetFromNodeArray(getSelectedNodes());
1807
for(var i = 0; i < chunks.length; i++) {
1808
var chunk = document.getElementById("n" + chunks[i]);
1809
if(chunk && formatChunkInnerText(chunk).trim().length != 0 && chunks[i] != '0') {
1810
if(!selected_chunks.has(chunks[i])) {
1811
modified_chunks.delete(chunks[i]);
1812
socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(chunk)});
1813
if(submit_throttle !== null) {
1814
submit_throttle(0, _dosubmit);
1815
}
1816
}
1817
empty_chunks.delete(chunks[i]);
1818
} else {
1819
if(!selected_chunks.has(chunks[i])) {
1820
modified_chunks.delete(chunks[i]);
1821
socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(chunk)});
1822
if(submit_throttle !== null) {
1823
submit_throttle(0, _dosubmit);
1824
}
1825
}
1826
empty_chunks.add(chunks[i]);
1827
}
1828
}
1829
}, 2);
1830
}
1831
1832
function syncAllModifiedChunks(including_selected_chunks=false) {
1833
var chunks = Array.from(modified_chunks);
1834
var selected_chunks = buildChunkSetFromNodeArray(getSelectedNodes());
1835
for(var i = 0; i < chunks.length; i++) {
1836
if(including_selected_chunks || !selected_chunks.has(chunks[i])) {
1837
modified_chunks.delete(chunks[i]);
1838
var chunk = document.getElementById("n" + chunks[i]);
1839
var data = chunk ? formatChunkInnerText(document.getElementById("n" + chunks[i])) : "";
1840
if(data.length == 0) {
1841
empty_chunks.add(chunks[i]);
1842
} else {
1843
empty_chunks.delete(chunks[i]);
1844
}
1845
socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': data});
1846
if(submit_throttle !== null) {
1847
submit_throttle(0, _dosubmit);
1848
}
1849
}
1850
}
1851
}
1852
1853
function restorePrompt() {
1854
if($("#n0").length && formatChunkInnerText($("#n0")[0]).length === 0) {
1855
$("#n0").remove();
1856
}
1857
var shadow_text = $("<b>" + game_text.html() + "</b>");
1858
var detected = false;
1859
var ref = null;
1860
try {
1861
if(shadow_text.length && shadow_text[0].firstChild && (shadow_text[0].firstChild.nodeType === 3 || shadow_text[0].firstChild.tagName === "BR")) {
1862
detected = true;
1863
ref = shadow_text;
1864
} else if(game_text.length && game_text[0].firstChild && (game_text[0].firstChild.nodeType === 3 || game_text[0].firstChild.tagName === "BR")) {
1865
detected = true;
1866
ref = game_text;
1867
}
1868
} catch (e) {
1869
detected = false;
1870
}
1871
if(detected) {
1872
unbindGametext();
1873
var text = [];
1874
while(true) {
1875
if(ref.length && ref[0].firstChild && ref[0].firstChild.nodeType === 3) {
1876
text.push(ref[0].firstChild.textContent.replace(/\u00a0/g, " "));
1877
} else if(ref.length && ref[0].firstChild && ref[0].firstChild.tagName === "BR") {
1878
text.push("\n");
1879
} else {
1880
break;
1881
}
1882
ref[0].removeChild(ref[0].firstChild);
1883
}
1884
text = text.join("").trim();
1885
if(text.length) {
1886
saved_prompt = text;
1887
}
1888
game_text[0].innerHTML = "";
1889
bindGametext();
1890
}
1891
game_text.children().each(function() {
1892
if(this.tagName !== "CHUNK") {
1893
this.parentNode.removeChild(this);
1894
}
1895
});
1896
if(!detected) {
1897
game_text.children().each(function() {
1898
if(this.innerText.trim().length) {
1899
saved_prompt = this.innerText.trim();
1900
socket.send({'cmd': 'inlinedelete', 'data': this.getAttribute("n")});
1901
if(submit_throttle !== null) {
1902
submit_throttle(0, _dosubmit);
1903
}
1904
this.parentNode.removeChild(this);
1905
return false;
1906
}
1907
socket.send({'cmd': 'inlinedelete', 'data': this.getAttribute("n")});
1908
if(submit_throttle !== null) {
1909
submit_throttle(0, _dosubmit);
1910
}
1911
this.parentNode.removeChild(this);
1912
});
1913
}
1914
var prompt_chunk = document.createElement("chunk");
1915
prompt_chunk.setAttribute("n", "0");
1916
prompt_chunk.setAttribute("id", "n0");
1917
prompt_chunk.setAttribute("tabindex", "-1");
1918
prompt_chunk.innerText = saved_prompt;
1919
unbindGametext();
1920
game_text[0].prepend(prompt_chunk);
1921
bindGametext();
1922
modified_chunks.delete('0');
1923
empty_chunks.delete('0');
1924
socket.send({'cmd': 'inlineedit', 'chunk': '0', 'data': saved_prompt});
1925
if(submit_throttle !== null) {
1926
submit_throttle(0, _dosubmit);
1927
}
1928
}
1929
1930
function deleteEmptyChunks() {
1931
var chunks = Array.from(empty_chunks);
1932
for(var i = 0; i < chunks.length; i++) {
1933
empty_chunks.delete(chunks[i]);
1934
if(chunks[i] === "0") {
1935
// Don't delete the prompt
1936
restorePrompt();
1937
} else {
1938
socket.send({'cmd': 'inlinedelete', 'data': chunks[i]});
1939
if(submit_throttle !== null) {
1940
submit_throttle(0, _dosubmit);
1941
}
1942
}
1943
}
1944
if(modified_chunks.has('0')) {
1945
modified_chunks.delete(chunks[i]);
1946
socket.send({'cmd': 'inlineedit', 'chunk': chunks[i], 'data': formatChunkInnerText(document.getElementById("n0"))});
1947
if(submit_throttle !== null) {
1948
submit_throttle(0, _dosubmit);
1949
}
1950
}
1951
if(gamestarted) {
1952
saved_prompt = formatChunkInnerText($("#n0")[0]);
1953
}
1954
}
1955
1956
function highlightEditingChunks() {
1957
var chunks = $('chunk.editing').toArray();
1958
var selected_chunks = buildChunkSetFromNodeArray(getSelectedNodes());
1959
for(var i = 0; i < chunks.length; i++) {
1960
var chunk = chunks[i];
1961
if(!selected_chunks.has(chunks[i].getAttribute("n"))) {
1962
unbindGametext();
1963
$(chunk).removeClass('editing');
1964
bindGametext();
1965
}
1966
}
1967
chunks = Array.from(selected_chunks);
1968
for(var i = 0; i < chunks.length; i++) {
1969
var chunk = $("#n"+chunks[i]);
1970
unbindGametext();
1971
chunk.addClass('editing');
1972
bindGametext();
1973
}
1974
}
1975
1976
function cleanupChunkWhitespace() {
1977
unbindGametext();
1978
1979
var chunks = Array.from(all_modified_chunks);
1980
for(var i = 0; i < chunks.length; i++) {
1981
var original_chunk = document.getElementById("n" + chunks[i]);
1982
if(original_chunk === null || original_chunk.innerText.trim().length === 0) {
1983
all_modified_chunks.delete(chunks[i]);
1984
modified_chunks.delete(chunks[i]);
1985
empty_chunks.add(chunks[i]);
1986
}
1987
}
1988
1989
// Merge empty chunks with the next chunk
1990
var chunks = Array.from(empty_chunks);
1991
chunks.sort(function(e) {parseInt(e)});
1992
for(var i = 0; i < chunks.length; i++) {
1993
if(chunks[i] == "0") {
1994
continue;
1995
}
1996
var original_chunk = document.getElementById("n" + chunks[i]);
1997
if(original_chunk === null) {
1998
continue;
1999
}
2000
var chunk = original_chunk.nextSibling;
2001
while(chunk) {
2002
if(chunk.tagName === "CHUNK") {
2003
break;
2004
}
2005
chunk = chunk.nextSibling;
2006
}
2007
if(chunk) {
2008
chunk.innerText = original_chunk.innerText + chunk.innerText;
2009
if(original_chunk.innerText.length != 0 && !modified_chunks.has(chunk.getAttribute("n"))) {
2010
modified_chunks.add(chunk.getAttribute("n"));
2011
}
2012
}
2013
original_chunk.innerText = "";
2014
}
2015
// Move whitespace at the end of non-empty chunks into the beginning of the next non-empty chunk
2016
var chunks = Array.from(all_modified_chunks);
2017
chunks.sort(function(e) {parseInt(e)});
2018
for(var i = 0; i < chunks.length; i++) {
2019
var original_chunk = document.getElementById("n" + chunks[i]);
2020
var chunk = original_chunk.nextSibling;
2021
while(chunk) {
2022
if(chunk.tagName === "CHUNK" && !empty_chunks.has(chunk.getAttribute("n"))) {
2023
break;
2024
}
2025
chunk = chunk.nextSibling;
2026
}
2027
var ln = original_chunk.innerText.trimEnd().length;
2028
if (chunk) {
2029
chunk.innerText = original_chunk.innerText.substring(ln) + chunk.innerText;
2030
if(ln != original_chunk.innerText.length && !modified_chunks.has(chunk.getAttribute("n"))) {
2031
modified_chunks.add(chunk.getAttribute("n"));
2032
}
2033
}
2034
original_chunk.innerText = original_chunk.innerText.substring(0, ln);
2035
}
2036
2037
bindGametext();
2038
}
2039
2040
// This gets run every time the text in a chunk is edited
2041
// or a chunk is deleted
2042
function chunkOnDOMMutate(mutations, observer) {
2043
if(!gametext_bound || !allowedit) {
2044
return;
2045
}
2046
var nodes = [];
2047
for(var i = 0; i < mutations.length; i++) {
2048
var mutation = mutations[i];
2049
nodes = nodes.concat(Array.from(mutation.addedNodes), Array.from(mutation.removedNodes));
2050
nodes.push(mutation.target);
2051
}
2052
applyChunkDeltas(nodes);
2053
}
2054
2055
// This gets run every time you try to paste text into the editor
2056
function chunkOnPaste(event) {
2057
// Register the chunk we're pasting in as having been modified
2058
applyChunkDeltas(getSelectedNodes());
2059
2060
// If possible, intercept paste events into the editor in order to always
2061
// paste as plaintext
2062
if(event.originalEvent.clipboardData && document.queryCommandSupported && document.execCommand && document.queryCommandSupported('insertHTML')) {
2063
event.preventDefault();
2064
document.execCommand('insertHTML', false, event.originalEvent.clipboardData.getData('text/plain').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;').replace(/(?=\r|\n)\r?\n?/g, '<br/>'));
2065
} else if (event.originalEvent.clipboardData) {
2066
event.preventDefault();
2067
var s = getSelection(); // WARNING: Do not use rangy.getSelection() instead of getSelection()
2068
var r = s.getRangeAt(0);
2069
r.deleteContents();
2070
var nodes = Array.from($('<span>' + event.originalEvent.clipboardData.getData('text/plain').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#039;').replace(/(?=\r|\n)\r?\n?/g, '<br/>') + '</span>')[0].childNodes);
2071
for(var i = 0; i < nodes.length; i++) {
2072
r.insertNode(nodes[i]);
2073
r.collapse(false);
2074
}
2075
}
2076
}
2077
2078
// This gets run every time the caret moves in the editor
2079
function _chunkOnSelectionChange(event, do_blur_focus) {
2080
if(!gametext_bound || !allowedit || override_focusout) {
2081
override_focusout = false;
2082
return;
2083
}
2084
setTimeout(function() {
2085
syncAllModifiedChunks();
2086
setTimeout(function() {
2087
highlightEditingChunks();
2088
// Attempt to prevent Chromium-based browsers on Android from
2089
// scrolling away from the current selection
2090
if(do_blur_focus && !using_webkit_patch) {
2091
setTimeout(function() {
2092
game_text.blur();
2093
game_text.focus();
2094
}, 144);
2095
}
2096
}, 2);
2097
}, 2);
2098
}
2099
2100
function chunkOnSelectionChange(event) {
2101
return _chunkOnSelectionChange(event, true);
2102
}
2103
2104
function chunkOnKeyDownSelectionChange(event) {
2105
return _chunkOnSelectionChange(event, false);
2106
}
2107
2108
// This gets run when you defocus the editor by clicking
2109
// outside of the editor or by pressing escape or tab
2110
function chunkOnFocusOut(event) {
2111
if(event !== "override" && (!gametext_bound || !allowedit || event.target !== game_text[0])) {
2112
return;
2113
}
2114
setTimeout(function() {
2115
if(document.activeElement === game_text[0] || game_text[0].contains(document.activeElement)) {
2116
return;
2117
}
2118
cleanupChunkWhitespace();
2119
all_modified_chunks = new Set();
2120
syncAllModifiedChunks(true);
2121
setTimeout(function() {
2122
var blurred = game_text[0] !== document.activeElement;
2123
if(blurred) {
2124
deleteEmptyChunks();
2125
}
2126
setTimeout(function() {
2127
$("chunk").removeClass('editing');
2128
}, 2);
2129
}, 2);
2130
}, 2);
2131
}
2132
2133
function bindGametext() {
2134
mutation_observer.observe(game_text[0], {characterData: true, childList: true, subtree: true});
2135
gametext_bound = true;
2136
}
2137
2138
function unbindGametext() {
2139
mutation_observer.disconnect();
2140
gametext_bound = false;
2141
}
2142
2143
function beginStream() {
2144
ignore_stream = false;
2145
token_prob_container[0].innerHTML = "";
2146
}
2147
2148
function endStream() {
2149
// Clear stream, the real text is about to be displayed.
2150
ignore_stream = true;
2151
if (stream_preview) {
2152
stream_preview.remove();
2153
stream_preview = null;
2154
}
2155
}
2156
2157
function update_gpu_layers() {
2158
var gpu_layers
2159
gpu_layers = 0;
2160
for (let i=0; i < $("#gpu_count")[0].value; i++) {
2161
gpu_layers += parseInt($("#gpu_layers"+i)[0].value);
2162
$("#gpu_layers_box_"+i)[0].value=$("#gpu_layers"+i)[0].value;
2163
}
2164
if ($("#disk_layers").length > 0) {
2165
gpu_layers += parseInt($("#disk_layers")[0].value);
2166
$("#disk_layers_box")[0].value=$("#disk_layers")[0].value;
2167
}
2168
if (gpu_layers > parseInt(document.getElementById("gpu_layers_max").innerHTML)) {
2169
disableButtons([load_model_accept]);
2170
$("#gpu_layers_current").html("<span style='color: red'>"+gpu_layers+"/"+ document.getElementById("gpu_layers_max").innerHTML +"</span>");
2171
} else {
2172
enableButtons([load_model_accept]);
2173
$("#gpu_layers_current").html(gpu_layers+"/"+document.getElementById("gpu_layers_max").innerHTML);
2174
}
2175
}
2176
2177
2178
function RemoveAllButFirstOption(selectElement) {
2179
var i, L = selectElement.options.length - 1;
2180
for(i = L; i >= 1; i--) {
2181
selectElement.remove(i);
2182
}
2183
}
2184
2185
function interpolateRGB(color0, color1, t) {
2186
return [
2187
color0[0] + ((color1[0] - color0[0]) * t),
2188
color0[1] + ((color1[1] - color0[1]) * t),
2189
color0[2] + ((color1[2] - color0[2]) * t),
2190
]
2191
}
2192
2193
function updateInputBudget(inputElement) {
2194
let budgetElement = document.getElementById("setshowbudget");
2195
if (budgetElement && !budgetElement.checked) return;
2196
2197
let data = {"unencoded": inputElement.value, "field": inputElement.id};
2198
2199
if (inputElement.id === "anoteinput") {
2200
data["anotetemplate"] = $("#anotetemplate").val();
2201
}
2202
2203
socket.send({"cmd": "getfieldbudget", "data": data});
2204
}
2205
2206
function registerTokenCounters() {
2207
// Add token counters to all input containers with the class of "tokens-counted",
2208
// if a token counter is not already a child of said container.
2209
for (const el of document.getElementsByClassName("tokens-counted")) {
2210
if (el.getElementsByClassName("input-token-usage").length) continue;
2211
2212
let span = document.createElement("span");
2213
span.classList.add("input-token-usage");
2214
el.appendChild(span);
2215
2216
let inputElement = el.querySelector("input, textarea");
2217
2218
inputElement.addEventListener("input", function() {
2219
updateInputBudget(this);
2220
});
2221
2222
updateInputBudget(inputElement);
2223
}
2224
}
2225
2226
//=================================================================//
2227
// READY/RUNTIME
2228
//=================================================================//
2229
2230
$(document).ready(function(){
2231
2232
// Bind UI references
2233
connect_status = $('#connectstatus');
2234
button_loadmodel = $('#btn_loadmodel');
2235
button_showmodel = $('#btn_showmodel');
2236
button_newgame = $('#btn_newgame');
2237
button_rndgame = $('#btn_rndgame');
2238
button_save = $('#btn_save');
2239
button_saveas = $('#btn_saveas');
2240
button_savetofile = $('#btn_savetofile');
2241
button_download = $('#btn_download');
2242
button_downloadtxt= $('#btn_downloadtxt');
2243
button_load = $('#btn_load');
2244
button_loadfrfile = $('#btn_loadfromfile');
2245
button_import = $("#btn_import");
2246
button_importwi = $("#btn_importwi");
2247
button_impaidg = $("#btn_impaidg");
2248
button_settings = $('#btn_settings');
2249
button_format = $('#btn_format');
2250
button_softprompt = $("#btn_softprompt");
2251
button_userscripts= $("#btn_userscripts");
2252
button_samplers = $("#btn_samplers");
2253
button_mode = $('#btnmode')
2254
button_mode_label = $('#btnmode_label')
2255
button_send = $('#btnsend');
2256
button_actmem = $('#btn_actmem');
2257
button_actback = $('#btn_actundo');
2258
button_actfwd = $('#btn_actredo');
2259
button_actretry = $('#btn_actretry');
2260
button_actwi = $('#btn_actwi');
2261
game_text = $('#gametext');
2262
input_text = $('#input_text');
2263
message_text = $('#messagefield');
2264
chat_name = $('#chatname');
2265
settings_menu = $("#settingsmenu");
2266
format_menu = $('#formatmenu');
2267
anote_menu = $('#anoterowcontainer');
2268
debug_area = $('#debugcontainer');
2269
wi_menu = $('#wimenu');
2270
anote_input = $('#anoteinput');
2271
anote_labelcur = $('#anotecur');
2272
anote_slider = $('#anotedepth');
2273
popup = $("#popupcontainer");
2274
popup_title = $("#popuptitletext");
2275
popup_content = $("#popupcontent");
2276
popup_accept = $("#btn_popupaccept");
2277
popup_close = $("#btn_popupclose");
2278
aidgpopup = $("#aidgpopupcontainer");
2279
aidgpromptnum = $("#aidgpromptnum");
2280
aidg_accept = $("#btn_aidgpopupaccept");
2281
aidg_close = $("#btn_aidgpopupclose");
2282
saveaspopup = $("#saveascontainer");
2283
saveasinput = $("#savename");
2284
savepins = $("#savepins");
2285
topic = $("#topic");
2286
saveas_accept = $("#btn_saveasaccept");
2287
saveas_close = $("#btn_saveasclose");
2288
loadpopup = $("#loadcontainer");
2289
loadmodelpopup = $("#loadmodelcontainer");
2290
loadcontent = $("#loadlistcontent");
2291
loadmodelcontent = $("#loadmodellistcontent");
2292
load_accept = $("#btn_loadaccept");
2293
load_close = $("#btn_loadclose");
2294
load_model_accept = $("#btn_loadmodelaccept");
2295
load_model_close = $("#btn_loadmodelclose");
2296
sppopup = $("#spcontainer");
2297
spcontent = $("#splistcontent");
2298
sp_accept = $("#btn_spaccept");
2299
sp_close = $("#btn_spclose");
2300
uspopup = $("#uscontainer");
2301
usunloaded = $("#uslistunloaded");
2302
usloaded = $("#uslistloaded");
2303
us_accept = $("#btn_usaccept");
2304
us_close = $("#btn_usclose");
2305
samplerspopup = $("#samplerscontainer");
2306
samplerslist = $("#samplerslist");
2307
samplers_accept = $("#btn_samplersaccept");
2308
samplers_close = $("#btn_samplersclose");
2309
nspopup = $("#newgamecontainer");
2310
ns_accept = $("#btn_nsaccept");
2311
ns_close = $("#btn_nsclose");
2312
rspopup = $("#rndgamecontainer");
2313
rs_accept = $("#btn_rsaccept");
2314
rs_close = $("#btn_rsclose");
2315
seqselmenu = $("#seqselmenu");
2316
seqselcontents = $("#seqselcontents");
2317
token_prob_container = $("#token_prob_container");
2318
token_prob_menu = $("#token_prob_menu");
2319
2320
// Connect to SocketIO server
2321
socket = io.connect(window.document.origin, {transports: ['polling', 'websocket'], closeOnBeforeunload: false});
2322
socket.on('load_popup', function(data){load_popup(data);});
2323
socket.on('popup_items', function(data){popup_items(data);});
2324
socket.on('popup_breadcrumbs', function(data){popup_breadcrumbs(data);});
2325
socket.on('popup_edit_file', function(data){popup_edit_file(data);});
2326
socket.on('error_popup', function(data){error_popup(data);});
2327
2328
socket.on('from_server', function(msg) {
2329
//console.log(msg);
2330
if(msg.cmd == "connected") {
2331
// Connected to Server Actions
2332
sman_allow_delete = msg.hasOwnProperty("smandelete") && msg.smandelete;
2333
sman_allow_rename = msg.hasOwnProperty("smanrename") && msg.smanrename;
2334
connected = true;
2335
if(msg.hasOwnProperty("modelname")) {
2336
modelname = msg.modelname;
2337
}
2338
refreshTitle();
2339
connect_status.html("<b>Connected to KoboldAI!</b>");
2340
connect_status.removeClass("color_orange");
2341
connect_status.addClass("color_green");
2342
// Reset Menus
2343
reset_menus();
2344
// Set up "Allow Editing"
2345
$('body').on('input', autofocus);
2346
$('#allowediting').prop('checked', allowedit).prop('disabled', false).change().off('change').on('change', function () {
2347
if(allowtoggle) {
2348
allowedit = gamestarted && $(this).prop('checked');
2349
game_text.attr('contenteditable', allowedit);
2350
}
2351
});
2352
// A simple feature detection test to determine whether the user interface
2353
// is using WebKit (Safari browser's rendering engine) because WebKit
2354
// requires special treatment to work correctly with the KoboldAI editor
2355
(function() {
2356
var active_element = document.activeElement;
2357
var c = document.createElement("chunk");
2358
var t = document.createTextNode("KoboldAI");
2359
c.appendChild(t);
2360
game_text[0].appendChild(c);
2361
var r = rangy.createRange();
2362
r.setStart(t, 6);
2363
r.collapse(true);
2364
var s = rangy.getSelection();
2365
s.removeAllRanges();
2366
s.addRange(r);
2367
game_text.blur();
2368
game_text.focus();
2369
using_webkit_patch = rangy.getSelection().focusOffset !== 6;
2370
c.removeChild(t);
2371
game_text[0].removeChild(c);
2372
document.activeElement.blur();
2373
active_element.focus();
2374
})();
2375
$("body").addClass("connected");
2376
} else if (msg.cmd == "streamtoken") {
2377
// Sometimes the stream_token messages will come in too late, after
2378
// we have recieved the full text. This leads to some stray tokens
2379
// appearing after the output. To combat this, we only allow tokens
2380
// to be displayed after requesting and before recieving text.
2381
if (ignore_stream) return;
2382
2383
let streamingEnabled = $("#setoutputstreaming")[0].checked;
2384
let probabilitiesEnabled = $("#setshowprobs")[0].checked;
2385
2386
if (!streamingEnabled && !probabilitiesEnabled) return;
2387
2388
if (!stream_preview && streamingEnabled) {
2389
stream_preview = document.createElement("span");
2390
game_text.append(stream_preview);
2391
}
2392
2393
for (const token of msg.data) {
2394
if (streamingEnabled) stream_preview.innerText += token.decoded;
2395
2396
if (probabilitiesEnabled) {
2397
// Probability display
2398
let probDiv = document.createElement("div");
2399
probDiv.classList.add("token-probs");
2400
2401
let probTokenSpan = document.createElement("span");
2402
probTokenSpan.classList.add("token-probs-header");
2403
probTokenSpan.innerText = token.decoded.replaceAll("\n", "\\n");
2404
probDiv.appendChild(probTokenSpan);
2405
2406
let probTable = document.createElement("table");
2407
let probTBody = document.createElement("tbody");
2408
probTable.appendChild(probTBody);
2409
2410
for (const probToken of token.probabilities) {
2411
let tr = document.createElement("tr");
2412
let rgb = interpolateRGB(
2413
[255, 255, 255],
2414
[0, 255, 0],
2415
probToken.score
2416
).map(Math.round);
2417
let color = `rgb(${rgb.join(", ")})`;
2418
2419
if (probToken.decoded === token.decoded) {
2420
tr.classList.add("token-probs-final-token");
2421
}
2422
2423
let tds = {};
2424
2425
for (const property of ["tokenId", "decoded", "score"]) {
2426
let td = document.createElement("td");
2427
td.style.color = color;
2428
tds[property] = td;
2429
tr.appendChild(td);
2430
}
2431
2432
tds.tokenId.innerText = probToken.tokenId;
2433
tds.decoded.innerText = probToken.decoded.toString().replaceAll("\n", "\\n");
2434
tds.score.innerText = (probToken.score * 100).toFixed(2) + "%";
2435
2436
probTBody.appendChild(tr);
2437
}
2438
2439
probDiv.appendChild(probTable);
2440
token_prob_container.append(probDiv);
2441
}
2442
}
2443
2444
scrollToBottom();
2445
} else if(msg.cmd == "updatescreen") {
2446
var _gamestarted = gamestarted;
2447
gamestarted = msg.gamestarted;
2448
if(_gamestarted != gamestarted) {
2449
action_mode = 0;
2450
changemode();
2451
}
2452
unbindGametext();
2453
allowedit = gamestarted && $("#allowediting").prop('checked');
2454
game_text.attr('contenteditable', allowedit);
2455
all_modified_chunks = new Set();
2456
modified_chunks = new Set();
2457
empty_chunks = new Set();
2458
game_text.html(msg.data);
2459
if(game_text[0].lastChild !== null && game_text[0].lastChild.tagName === "CHUNK") {
2460
game_text[0].lastChild.appendChild(document.createElement("br"));
2461
}
2462
bindGametext();
2463
if(gamestarted) {
2464
saved_prompt = formatChunkInnerText($("#n0")[0]);
2465
}
2466
// Scroll to bottom of text
2467
if(newly_loaded) {
2468
scrollToBottom();
2469
}
2470
newly_loaded = false;
2471
} else if(msg.cmd == "scrolldown") {
2472
scrollToBottom();
2473
} else if(msg.cmd == "updatechunk") {
2474
hideMessage();
2475
game_text.attr('contenteditable', allowedit);
2476
var index = msg.data.index;
2477
var html = msg.data.html;
2478
var existingChunk = game_text.children('#n' + index);
2479
var newChunk = $(html);
2480
unbindGametext();
2481
if (existingChunk.length > 0) {
2482
// Update existing chunk
2483
if(existingChunk[0].nextSibling === null || existingChunk[0].nextSibling.nodeType !== 1 || existingChunk[0].nextSibling.tagName !== "CHUNK") {
2484
newChunk[0].appendChild(document.createElement("br"));
2485
}
2486
existingChunk.before(newChunk);
2487
existingChunk.remove();
2488
} else if (!empty_chunks.has(index.toString())) {
2489
// Append at the end
2490
unbindGametext();
2491
2492
// game_text can contain things other than chunks (stream
2493
// preview), so we use querySelector to get the last chunk.
2494
var lc = game_text[0].querySelector("chunk:last-of-type");
2495
2496
if(lc.tagName === "CHUNK" && lc.lastChild !== null && lc.lastChild.tagName === "BR") {
2497
lc.removeChild(lc.lastChild);
2498
}
2499
newChunk[0].appendChild(document.createElement("br"));
2500
game_text.append(newChunk);
2501
bindGametext();
2502
}
2503
bindGametext();
2504
hide([$('#curtain')]);
2505
} else if(msg.cmd == "removechunk") {
2506
hideMessage();
2507
var index = msg.data;
2508
var element = game_text.children('#n' + index);
2509
if(element.length) {
2510
unbindGametext();
2511
if(
2512
(element[0].nextSibling === null || element[0].nextSibling.nodeType !== 1 || element[0].nextSibling.tagName !== "CHUNK")
2513
&& element[0].previousSibling !== null
2514
&& element[0].previousSibling.tagName === "CHUNK"
2515
) {
2516
element[0].previousSibling.appendChild(document.createElement("br"));
2517
}
2518
element.remove(); // Remove the chunk
2519
bindGametext();
2520
}
2521
hide([$('#curtain')]);
2522
} else if(msg.cmd == "setgamestate") {
2523
// Enable or Disable buttons
2524
if(msg.data == "ready") {
2525
endStream();
2526
enableSendBtn();
2527
enableButtons([button_actmem, button_actwi, button_actback, button_actfwd, button_actretry]);
2528
hideWaitAnimation();
2529
gamestate = "ready";
2530
favicon.stop_swap();
2531
} else if(msg.data == "wait") {
2532
gamestate = "wait";
2533
disableSendBtn();
2534
disableButtons([button_actmem, button_actwi, button_actback, button_actfwd, button_actretry]);
2535
showWaitAnimation();
2536
favicon.start_swap();
2537
} else if(msg.data == "start") {
2538
setStartState();
2539
gamestate = "ready";
2540
favicon.stop_swap();
2541
}
2542
} else if(msg.cmd == "allowsp") {
2543
allowsp = !!msg.data;
2544
if(allowsp) {
2545
button_softprompt.removeClass("hidden");
2546
} else {
2547
button_softprompt.addClass("hidden");
2548
}
2549
} else if(msg.cmd == "setstoryname") {
2550
storyname = msg.data;
2551
refreshTitle();
2552
} else if(msg.cmd == "editmode") {
2553
// Enable or Disable edit mode
2554
if(msg.data == "true") {
2555
enterEditMode();
2556
} else {
2557
exitEditMode();
2558
}
2559
} else if(msg.cmd == "setinputtext") {
2560
// Set input box text for memory mode
2561
if(memorymode) {
2562
memorytext = msg.data;
2563
input_text.val(msg.data);
2564
}
2565
updateInputBudget(input_text[0]);
2566
} else if(msg.cmd == "setmemory") {
2567
memorytext = msg.data;
2568
if(memorymode) {
2569
input_text.val(msg.data);
2570
}
2571
} else if(msg.cmd == "memmode") {
2572
// Enable or Disable memory edit mode
2573
if(msg.data == "true") {
2574
enterMemoryMode();
2575
} else {
2576
exitMemoryMode();
2577
}
2578
} else if(msg.cmd == "errmsg") {
2579
// Send error message
2580
errMessage(msg.data, "error");
2581
} else if(msg.cmd == "warnmsg") {
2582
// Send warning message
2583
errMessage(msg.data, "warn");
2584
} else if(msg.cmd == "hidemsg") {
2585
hideMessage();
2586
} else if(msg.cmd == "texteffect") {
2587
// Apply color highlight to line of text
2588
newTextHighlight($("#n"+msg.data))
2589
} else if(msg.cmd == "updatetemp") {
2590
// Send current temp value to input
2591
$("#settempcur").val(msg.data);
2592
$("#settemp").val(parseFloat(msg.data)).trigger("change");
2593
} else if(msg.cmd == "updatetopp") {
2594
// Send current top p value to input
2595
$("#settoppcur").val(msg.data);
2596
$("#settopp").val(parseFloat(msg.data)).trigger("change");
2597
} else if(msg.cmd == "updatetopk") {
2598
// Send current top k value to input
2599
$("#settopkcur").val(msg.data);
2600
$("#settopk").val(parseFloat(msg.data)).trigger("change");
2601
} else if(msg.cmd == "updatetfs") {
2602
// Send current tfs value to input
2603
$("#settfscur").val(msg.data);
2604
$("#settfs").val(parseFloat(msg.data)).trigger("change");
2605
} else if(msg.cmd == "updatetypical") {
2606
// Send current typical value to input
2607
$("#settypicalcur").val(msg.data);
2608
$("#settypical").val(parseFloat(msg.data)).trigger("change");
2609
} else if(msg.cmd == "updatetopa") {
2610
// Send current top a value to input
2611
$("#settopacur").val(msg.data);
2612
$("#settopa").val(parseFloat(msg.data)).trigger("change");
2613
} else if(msg.cmd == "updatereppen") {
2614
// Send current rep pen value to input
2615
$("#setreppencur").val(msg.data);
2616
$("#setreppen").val(parseFloat(msg.data)).trigger("change");
2617
} else if(msg.cmd == "updatereppenslope") {
2618
// Send current rep pen value to input
2619
$("#setreppenslopecur").val(msg.data);
2620
$("#setreppenslope").val(parseFloat(msg.data)).trigger("change");
2621
} else if(msg.cmd == "updatereppenrange") {
2622
// Send current rep pen value to input
2623
$("#setreppenrangecur").val(msg.data);
2624
$("#setreppenrange").val(parseFloat(msg.data)).trigger("change");
2625
} else if(msg.cmd == "updateoutlen") {
2626
// Send current output amt value to input
2627
$("#setoutputcur").val(msg.data);
2628
$("#setoutput").val(parseInt(msg.data)).trigger("change");
2629
} else if(msg.cmd == "updatetknmax") {
2630
// Send current max tokens value to input
2631
$("#settknmaxcur").val(msg.data);
2632
$("#settknmax").val(parseInt(msg.data)).trigger("change");
2633
} else if(msg.cmd == "updateikgen") {
2634
// Send current max tokens value to input
2635
$("#setikgencur").val(msg.data);
2636
$("#setikgen").val(parseInt(msg.data)).trigger("change");
2637
} else if(msg.cmd == "setlabeltemp") {
2638
// Update setting label with value from server
2639
$("#settempcur").val(msg.data);
2640
} else if(msg.cmd == "setlabeltopp") {
2641
// Update setting label with value from server
2642
$("#settoppcur").val(msg.data);
2643
} else if(msg.cmd == "setlabeltopk") {
2644
// Update setting label with value from server
2645
$("#settopkcur").val(msg.data);
2646
} else if(msg.cmd == "setlabeltfs") {
2647
// Update setting label with value from server
2648
$("#settfscur").val(msg.data);
2649
} else if(msg.cmd == "setlabeltypical") {
2650
// Update setting label with value from server
2651
$("#settypicalcur").val(msg.data);
2652
} else if(msg.cmd == "setlabeltypical") {
2653
// Update setting label with value from server
2654
$("#settopa").val(msg.data);
2655
} else if(msg.cmd == "setlabelreppen") {
2656
// Update setting label with value from server
2657
$("#setreppencur").val(msg.data);
2658
} else if(msg.cmd == "setlabelreppenslope") {
2659
// Update setting label with value from server
2660
$("#setreppenslopecur").val(msg.data);
2661
} else if(msg.cmd == "setlabelreppenrange") {
2662
// Update setting label with value from server
2663
$("#setreppenrangecur").val(msg.data);
2664
} else if(msg.cmd == "setlabeloutput") {
2665
// Update setting label with value from server
2666
$("#setoutputcur").val(msg.data);
2667
} else if(msg.cmd == "setlabeltknmax") {
2668
// Update setting label with value from server
2669
$("#settknmaxcur").val(msg.data);
2670
} else if(msg.cmd == "setlabelikgen") {
2671
// Update setting label with value from server
2672
$("#setikgencur").val(msg.data);
2673
} else if(msg.cmd == "updateanotedepth") {
2674
// Send current Author's Note depth value to input
2675
anote_slider.val(parseInt(msg.data));
2676
anote_labelcur.html(msg.data);
2677
} else if(msg.cmd == "setlabelanotedepth") {
2678
// Update setting label with value from server
2679
anote_labelcur.html(msg.data);
2680
} else if(msg.cmd == "getanote") {
2681
// Request contents of Author's Note field
2682
var txt = anote_input.val();
2683
socket.send({'cmd': 'anote', 'template': $("#anotetemplate").val(), 'data': txt});
2684
} else if(msg.cmd == "setanote") {
2685
// Set contents of Author's Note field
2686
anote_input.val(msg.data);
2687
updateInputBudget(anote_input[0]);
2688
} else if(msg.cmd == "setanotetemplate") {
2689
// Set contents of Author's Note Template field
2690
$("#anotetemplate").val(msg.data);
2691
} else if(msg.cmd == "reset_menus") {
2692
reset_menus();
2693
} else if(msg.cmd == "addsetting") {
2694
// Add setting controls
2695
addSetting(msg.data);
2696
} else if(msg.cmd == "addformat") {
2697
// Add setting controls
2698
addFormat(msg.data);
2699
} else if(msg.cmd == "updatefrmttriminc") {
2700
// Update toggle state
2701
$("#frmttriminc").prop('checked', msg.data).change();
2702
} else if(msg.cmd == "updatefrmtrmblln") {
2703
// Update toggle state
2704
$("#frmtrmblln").prop('checked', msg.data).change();
2705
} else if(msg.cmd == "updatefrmtrmspch") {
2706
// Update toggle state
2707
$("#frmtrmspch").prop('checked', msg.data).change();
2708
} else if(msg.cmd == "updatefrmtadsnsp") {
2709
// Update toggle state
2710
$("#frmtadsnsp").prop('checked', msg.data).change();
2711
} else if(msg.cmd == "updatesingleline") {
2712
// Update toggle state
2713
$("#singleline").prop('checked', msg.data).change();
2714
} else if(msg.cmd == "updateoutputstreaming") {
2715
// Update toggle state
2716
$("#setoutputstreaming").prop('checked', msg.data).change();
2717
} else if(msg.cmd == "updateshowbudget") {
2718
// Update toggle state
2719
$("#setshowbudget").prop('checked', msg.data).change();
2720
} else if(msg.cmd == "updateshowprobs") {
2721
$("#setshowprobs").prop('checked', msg.data).change();
2722
2723
if(msg.data) {
2724
token_prob_menu.removeClass("hidden");
2725
} else {
2726
token_prob_menu.addClass("hidden");
2727
}
2728
} else if(msg.cmd == "allowtoggle") {
2729
// Allow toggle change states to propagate
2730
allowtoggle = msg.data;
2731
} else if(msg.cmd == "usstatitems") {
2732
updateUSStatItems(msg.data, msg.flash);
2733
} else if(msg.cmd == "spstatitems") {
2734
updateSPStatItems(msg.data);
2735
} else if(msg.cmd == "popupshow") {
2736
// Show/Hide Popup
2737
popupShow(msg.data);
2738
} else if(msg.cmd == "hidepopupdelete") {
2739
// Hide the dialog box that asks you to confirm deletion of a story
2740
$("#loadcontainerdelete").removeClass("flex").addClass("hidden");
2741
hide([$(".saveasoverwrite"), $(".popuperror")]);
2742
} else if(msg.cmd == "hidepopuprename") {
2743
// Hide the story renaming dialog box
2744
$("#loadcontainerrename").removeClass("flex").addClass("hidden");
2745
hide([$(".saveasoverwrite"), $(".popuperror")]);
2746
} else if(msg.cmd == "addimportline") {
2747
// Add import popup entry
2748
addImportLine(msg.data);
2749
} else if(msg.cmd == "clearpopup") {
2750
// Clear previous contents of popup
2751
popup_content.html("");
2752
} else if(msg.cmd == "wimode") {
2753
// Enable or Disable WI edit mode
2754
if(msg.data == "true") {
2755
enterWiMode();
2756
} else {
2757
exitWiMode();
2758
}
2759
} else if(msg.cmd == "wiupdate") {
2760
var selective = $("#wilistitem"+msg.num)[0].classList.contains("wilistitem-selective");
2761
if(selective) {
2762
$("#wikeyprimary"+msg.num).val(msg.data.key);
2763
} else {
2764
$("#wikey"+msg.num).val(msg.data.key);
2765
}
2766
$("#wikeysecondary"+msg.num).val(msg.data.keysecondary);
2767
$("#wientry"+msg.num).val(msg.data.content);
2768
$("#wicomment"+msg.num).val(msg.data.comment);
2769
adjustWiCommentHeight($("#wicomment"+msg.num)[0]);
2770
} else if(msg.cmd == "wifolderupdate") {
2771
$("#wifoldername"+msg.uid).val(msg.data.name);
2772
adjustWiFolderNameHeight($("#wifoldername"+msg.uid)[0]);
2773
} else if(msg.cmd == "wiexpand") {
2774
expandWiLine(msg.data);
2775
} else if(msg.cmd == "wiexpandfolder") {
2776
expandWiFolderLine(msg.data);
2777
} else if(msg.cmd == "wifoldercollapsecontent") {
2778
collapseWiFolderContent(msg.data);
2779
} else if(msg.cmd == "wifolderexpandcontent") {
2780
expandWiFolderContent(msg.data);
2781
} else if(msg.cmd == "wiselon") {
2782
enableWiSelective(msg.data);
2783
} else if(msg.cmd == "wiseloff") {
2784
disableWiSelective(msg.data);
2785
} else if(msg.cmd == "wiconstanton") {
2786
enableWiConstant(msg.data);
2787
} else if(msg.cmd == "wiconstantoff") {
2788
disableWiConstant(msg.data);
2789
} else if(msg.cmd == "addwiitem") {
2790
// Add WI entry to WI Menu
2791
addWiLine(msg.data);
2792
} else if(msg.cmd == "addwifolder") {
2793
addWiFolder(msg.uid, msg.data);
2794
} else if(msg.cmd == "wistart") {
2795
// Save scroll position for later so we can restore it later
2796
wiscroll = $("#gamescreen").scrollTop();
2797
// Clear previous contents of WI list
2798
wi_menu.html("");
2799
// Save wifolders_d and wifolders_l
2800
wifolders_d = msg.wifolders_d;
2801
wifolders_l = msg.wifolders_l;
2802
} else if(msg.cmd == "wifinish") {
2803
// Allow drag-and-drop rearranging of world info entries (via JQuery UI's "sortable widget")
2804
$("#gamescreen").sortable({
2805
items: "#wimenu .wisortable-body > :not(.wisortable-excluded):not(.wisortable-excluded-dynamic), #wimenu .wisortable-container[folder-uid]:not(.wisortable-excluded):not(.wisortable-excluded-dynamic)",
2806
containment: "#wimenu",
2807
connectWith: "#wimenu .wisortable-body",
2808
handle: ".wihandle",
2809
start: sortableOnStart,
2810
stop: sortableOnStop,
2811
placeholder: "wisortable-placeholder",
2812
delay: 2,
2813
cursor: "move",
2814
tolerance: "pointer",
2815
opacity: 0.21,
2816
revert: 173,
2817
scrollSensitivity: 64,
2818
scrollSpeed: 10,
2819
});
2820
// Restore previously-saved scroll position
2821
$("#gamescreen").scrollTop(wiscroll);
2822
} else if(msg.cmd == "requestwiitem") {
2823
// Package WI contents and send back to server
2824
returnWiList(msg.data);
2825
} else if(msg.cmd == "saveas") {
2826
// Show Save As prompt
2827
showSaveAsPopup();
2828
} else if(msg.cmd == "gamesaved") {
2829
setGameSaved(msg.data);
2830
} else if(msg.cmd == "hidesaveas") {
2831
// Hide Save As prompt
2832
hideSaveAsPopup();
2833
} else if(msg.cmd == "buildload") {
2834
// Send array of save files to load UI
2835
buildLoadList(msg.data);
2836
} else if(msg.cmd == "buildsp") {
2837
buildSPList(msg.data);
2838
} else if(msg.cmd == "buildus") {
2839
buildUSList(msg.data.unloaded, msg.data.loaded);
2840
} else if(msg.cmd == "buildsamplers") {
2841
buildSamplerList(msg.data);
2842
} else if(msg.cmd == "askforoverwrite") {
2843
// Show overwrite warning
2844
show([$(".saveasoverwrite")]);
2845
} else if(msg.cmd == "popuperror") {
2846
// Show error in the current dialog box
2847
$(".popuperror").text(msg.data);
2848
show([$(".popuperror")]);
2849
} else if(msg.cmd == "genseqs") {
2850
// Parse generator sequences to UI
2851
parsegenseqs(msg.data);
2852
} else if(msg.cmd == "hidegenseqs") {
2853
// Collapse genseqs menu
2854
hidegenseqs();
2855
} else if(msg.cmd == "setchatname") {
2856
chat_name.val(msg.data);
2857
} else if(msg.cmd == "setlabelnumseq") {
2858
// Update setting label with value from server
2859
$("#setnumseqcur").val(msg.data);
2860
} else if(msg.cmd == "updatenumseq") {
2861
// Send current max tokens value to input
2862
$("#setnumseqcur").val(msg.data);
2863
$("#setnumseq").val(parseInt(msg.data)).trigger("change");
2864
} else if(msg.cmd == "setlabelwidepth") {
2865
// Update setting label with value from server
2866
$("#setwidepthcur").val(msg.data);
2867
} else if(msg.cmd == "updatewidepth") {
2868
// Send current max tokens value to input
2869
$("#setwidepthcur").val(msg.data);
2870
$("#setwidepth").val(parseInt(msg.data)).trigger("change");
2871
} else if(msg.cmd == "updateuseprompt") {
2872
// Update toggle state
2873
$("#setuseprompt").prop('checked', msg.data).change();
2874
} else if(msg.cmd == "updateadventure") {
2875
// Update toggle state
2876
$("#setadventure").prop('checked', msg.data).change();
2877
// Update adventure state
2878
setadventure(msg.data);
2879
} else if(msg.cmd == "updatechatmode") {
2880
// Update toggle state
2881
$("#setchatmode").prop('checked', msg.data).change();
2882
// Update chatmode state
2883
setchatmode(msg.data);
2884
} else if(msg.cmd == "updatedynamicscan") {
2885
// Update toggle state
2886
$("#setdynamicscan").prop('checked', msg.data).change();
2887
} else if(msg.cmd == "updatenopromptgen") {
2888
// Update toggle state
2889
$("#setnopromptgen").prop('checked', msg.data).change();
2890
} else if(msg.cmd == "updateautosave") {
2891
// Update toggle state
2892
$("#autosave").prop('checked', msg.data).change();
2893
} else if(msg.cmd == "updaterngpersist") {
2894
// Update toggle state
2895
$("#setrngpersist").prop('checked', msg.data).change();
2896
if(!$("#setrngpersist").prop("checked")) {
2897
$("#rngmemory").val("");
2898
}
2899
} else if(msg.cmd == "updatenogenmod") {
2900
// Update toggle state
2901
$("#setnogenmod").prop('checked', msg.data).change();
2902
} else if(msg.cmd == "updatefulldeterminism") {
2903
// Update toggle state
2904
$("#setfulldeterminism").prop('checked', msg.data).change();
2905
} else if(msg.cmd == "runs_remotely") {
2906
remote = true;
2907
hide([button_savetofile, button_import, button_importwi]);
2908
} else if(msg.cmd == "debug_info") {
2909
$("#debuginfo").val(msg.data);
2910
} else if(msg.cmd == "set_debug") {
2911
if(msg.data) {
2912
debug_area.removeClass("hidden");
2913
} else {
2914
debug_area.addClass("hidden");
2915
}
2916
} else if(msg.cmd == 'show_model_menu') {
2917
//console.log(msg)
2918
$("#use_gpu_div").addClass("hidden");
2919
$("#modelkey").addClass("hidden");
2920
$("#modellayers").addClass("hidden");
2921
$("#oaimodel").addClass("hidden")
2922
buildLoadModelList(msg.data, msg.menu, msg.breadcrumbs, msg.showdelete);
2923
} else if(msg.cmd == 'selected_model_info') {
2924
console.log(msg);
2925
enableButtons([load_model_accept]);
2926
$("#oaimodel").addClass("hidden")
2927
$("#oaimodel")[0].options[0].selected = true;
2928
if (msg.key) {
2929
$("#modelkey").removeClass("hidden");
2930
$("#modelkey")[0].value = msg.key_value;
2931
if (msg.models_on_url) {
2932
$("#modelkey")[0].oninput = function() {clearTimeout(online_model_timmer);
2933
online_model_timmer = setTimeout(function() {
2934
socket.send({'cmd': 'Cluster_Key_Update', 'key': document.getElementById("modelkey").value,
2935
'url': document.getElementById("modelurl").value});
2936
}, 1000);
2937
}
2938
$("#modelkey")[0].onblur = function () {socket.send({'cmd': 'Cluster_Key_Update', 'key': this.value, 'url': document.getElementById("modelurl").value});};
2939
$("#modelurl")[0].onblur = function () {socket.send({'cmd': 'Cluster_Key_Update', 'key': document.getElementById("modelkey").value, 'url': this.value});};
2940
} else {
2941
$("#modelkey")[0].onblur = function () {socket.send({'cmd': 'OAI_Key_Update', 'key': $('#modelkey')[0].value});};
2942
$("#modelurl")[0].onblur = null;
2943
}
2944
//if we're in the API list, disable to load button until the model is selected (after the API Key is entered)
2945
disableButtons([load_model_accept]);
2946
} else {
2947
$("#modelkey").addClass("hidden");
2948
}
2949
2950
console.log(msg.multi_online_models);
2951
if (msg.multi_online_models) {
2952
$("#oaimodel")[0].setAttribute("multiple", "");
2953
$("#oaimodel")[0].options[0].textContent = "All"
2954
} else {
2955
$("#oaimodel")[0].removeAttribute("multiple");
2956
$("#oaimodel")[0].options[0].textContent = "Select Model(s)"
2957
}
2958
2959
2960
2961
if (msg.url) {
2962
$("#modelurl").removeClass("hidden");
2963
if (msg.default_url != null) {
2964
document.getElementById("modelurl").value = msg.default_url;
2965
}
2966
} else {
2967
$("#modelurl").addClass("hidden");
2968
}
2969
if (msg.gpu) {
2970
$("#use_gpu_div").removeClass("hidden");
2971
} else {
2972
$("#use_gpu_div").addClass("hidden");
2973
}
2974
if (msg.breakmodel) {
2975
var html;
2976
$("#modellayers").removeClass("hidden");
2977
html = "";
2978
for (let i = 0; i < msg.gpu_names.length; i++) {
2979
html += "GPU " + i + " " + msg.gpu_names[i] + ": ";
2980
html += '<input inputmode="numeric" id="gpu_layers_box_'+i+'" class="justifyright flex-push-right model_layers" value="'+msg.break_values[i]+'" ';
2981
html += 'onblur=\'$("#gpu_layers'+i+'")[0].value=$("#gpu_layers_box_'+i+'")[0].value;update_gpu_layers();\'>';
2982
html += "<input type='range' class='form-range airange' min='0' max='"+msg.layer_count+"' step='1' value='"+msg.break_values[i]+"' id='gpu_layers"+i+"' onchange='update_gpu_layers();'>";
2983
}
2984
html += "Disk cache: ";
2985
html += '<input inputmode="numeric" id="disk_layers_box" class="justifyright flex-push-right model_layers" value="'+msg.disk_break_value+'" ';
2986
html += 'onblur=\'$("#disk_layers")[0].value=$("#disk_layers_box")[0].value;update_gpu_layers();\'>';
2987
html += "<input type='range' class='form-range airange' min='0' max='"+msg.layer_count+"' step='1' value='"+msg.disk_break_value+"' id='disk_layers' onchange='update_gpu_layers();'>";
2988
$("#model_layer_bars").html(html);
2989
$("#gpu_layers_max").html(msg.layer_count);
2990
$("#gpu_count")[0].value = msg.gpu_count;
2991
update_gpu_layers();
2992
} else {
2993
$("#modellayers").addClass("hidden");
2994
}
2995
} else if(msg.cmd == 'oai_engines') {
2996
$("#oaimodel").removeClass("hidden")
2997
enableButtons([load_model_accept]);
2998
selected_item = 0;
2999
length = $("#oaimodel")[0].options.length;
3000
for (let i = 0; i < length; i++) {
3001
$("#oaimodel")[0].options.remove(1);
3002
}
3003
msg.data.forEach(function (item, index) {
3004
var option = document.createElement("option");
3005
option.value = item[0];
3006
option.text = item[1];
3007
if(msg.online_model == item[0]) {
3008
selected_item = index+1;
3009
}
3010
$("#oaimodel")[0].appendChild(option);
3011
if(selected_item != "") {
3012
$("#oaimodel")[0].options[selected_item].selected = true;
3013
}
3014
})
3015
} else if(msg.cmd == 'show_model_name') {
3016
$("#showmodelnamecontent").html("<div class=\"flex\"><div class=\"loadlistpadding\"></div><div class=\"loadlistitem\">" + msg.data + "</div></div>");
3017
$("#showmodelnamecontainer").removeClass("hidden");
3018
} else if(msg.cmd == 'hide_model_name') {
3019
$("#showmodelnamecontainer").addClass("hidden");
3020
$(window).off('beforeunload');
3021
location.reload();
3022
//console.log("Closing window");
3023
} else if(msg.cmd == 'model_load_status') {
3024
$("#showmodelnamecontent").html("<div class=\"flex\"><div class=\"loadlistpadding\"></div><div class=\"loadlistitem\" style='align: left'>" + msg.data + "</div></div>");
3025
$("#showmodelnamecontainer").removeClass("hidden");
3026
//console.log(msg.data);
3027
} else if(msg.cmd == 'oai_engines') {
3028
RemoveAllButFirstOption($("#oaimodel")[0]);
3029
for (const engine of msg.data) {
3030
var opt = document.createElement('option');
3031
opt.value = engine[0];
3032
opt.innerHTML = engine[1];
3033
$("#oaimodel")[0].appendChild(opt);
3034
}
3035
} else if(msg.cmd == 'showfieldbudget') {
3036
let inputElement = document.getElementById(msg.data.field);
3037
let tokenBudgetElement = inputElement.parentNode.getElementsByClassName("input-token-usage")[0];
3038
if (msg.data.max === null) {
3039
tokenBudgetElement.innerText = "";
3040
} else {
3041
let tokenLength = msg.data.length ?? "?";
3042
let tokenMax = msg.data.max ?? "?";
3043
tokenBudgetElement.innerText = `${tokenLength}/${tokenMax} Tokens`;
3044
}
3045
}
3046
enableButtons([load_model_accept]);
3047
});
3048
3049
socket.on('disconnect', function() {
3050
connected = false;
3051
$("body").removeClass("connected");
3052
connect_status.html("<b>Lost connection...</b>");
3053
connect_status.removeClass("color_green");
3054
connect_status.addClass("color_orange");
3055
updateUSStatItems([], false);
3056
updateSPStatItems({});
3057
});
3058
3059
// Register editing events
3060
game_text.on('textInput',
3061
chunkOnTextInput
3062
).on('beforeinput',
3063
chunkOnBeforeInput
3064
).on('keydown',
3065
chunkOnKeyDown
3066
).on('paste',
3067
chunkOnPaste
3068
).on('click',
3069
chunkOnSelectionChange
3070
).on('keydown',
3071
chunkOnKeyDownSelectionChange
3072
).on('focusout',
3073
chunkOnFocusOut
3074
);
3075
mutation_observer = new MutationObserver(chunkOnDOMMutate);
3076
$("#gamescreen").on('click', function(e) {
3077
if(this !== e.target) {
3078
return;
3079
}
3080
document.activeElement.blur();
3081
});
3082
3083
// This is required for the editor to work correctly in Firefox on desktop
3084
// because the gods of HTML and JavaScript say so
3085
$(document.body).on('focusin', function(event) {
3086
setTimeout(function() {
3087
if(document.activeElement !== game_text[0] && game_text[0].contains(document.activeElement)) {
3088
game_text[0].focus();
3089
}
3090
}, 2);
3091
});
3092
3093
var us_click_handler = function(ev) {
3094
setTimeout(function() {
3095
if (us_dragging) {
3096
return;
3097
}
3098
var target = $(ev.target).closest(".uslistitem")[0];
3099
if ($.contains(document.getElementById("uslistunloaded"), target)) {
3100
document.getElementById("uslistloaded").appendChild(target);
3101
} else {
3102
document.getElementById("uslistunloaded").appendChild(target);
3103
}
3104
}, 10);
3105
}
3106
3107
var samplers_click_handler = function(ev) {
3108
setTimeout(function() {
3109
if (samplers_dragging) {
3110
return;
3111
}
3112
var target = $(ev.target).closest(".samplerslistitem");
3113
var next = target.parent().next().find(".samplerslistitem");
3114
if (!next.length) {
3115
return;
3116
}
3117
next.parent().after(target.parent());
3118
}, 10);
3119
}
3120
3121
// Make the userscripts menu sortable
3122
var us_sortable_settings = {
3123
placeholder: "ussortable-placeholder",
3124
start: function() { us_dragging = true; },
3125
stop: function() { us_dragging = false; },
3126
delay: 2,
3127
cursor: "move",
3128
tolerance: "pointer",
3129
opacity: 0.21,
3130
revert: 173,
3131
scrollSensitivity: 64,
3132
scrollSpeed: 10,
3133
}
3134
usunloaded.sortable($.extend({
3135
connectWith: "#uslistloaded",
3136
}, us_sortable_settings)).on("click", ".uslistitem", us_click_handler);
3137
usloaded.sortable($.extend({
3138
connectWith: "#uslistunloaded",
3139
}, us_sortable_settings)).on("click", ".uslistitem", us_click_handler);
3140
3141
// Make the samplers menu sortable
3142
var samplers_sortable_settings = {
3143
placeholder: "samplerssortable-placeholder",
3144
start: function() { samplers_dragging = true; },
3145
stop: function() { samplers_dragging = false; },
3146
delay: 2,
3147
cursor: "move",
3148
tolerance: "pointer",
3149
opacity: 0.21,
3150
revert: 173,
3151
scrollSensitivity: 64,
3152
scrollSpeed: 10,
3153
}
3154
samplerslist.sortable($.extend({
3155
}, samplers_sortable_settings)).on("click", ".samplerslistitem", samplers_click_handler);
3156
3157
// Bind actions to UI buttons
3158
button_send.on("click", function(ev) {
3159
dosubmit();
3160
});
3161
3162
button_mode.on("click", function(ev) {
3163
changemode();
3164
});
3165
3166
button_actretry.on("click", function(ev) {
3167
beginStream();
3168
hideMessage();
3169
socket.send({'cmd': 'retry', 'chatname': chatmode ? chat_name.val() : undefined, 'data': ''});
3170
hidegenseqs();
3171
});
3172
3173
button_actback.on("click", function(ev) {
3174
hideMessage();
3175
socket.send({'cmd': 'back', 'data': ''});
3176
hidegenseqs();
3177
});
3178
3179
button_actfwd.on("click", function(ev) {
3180
hideMessage();
3181
//hidegenseqs();
3182
socket.send({'cmd': 'redo', 'data': ''});
3183
});
3184
3185
button_actmem.on("click", function(ev) {
3186
socket.send({'cmd': 'memory', 'data': ''});
3187
});
3188
3189
button_savetofile.on("click", function(ev) {
3190
socket.send({'cmd': 'savetofile', 'data': ''});
3191
});
3192
3193
button_loadfrfile.on("click", function(ev) {
3194
if(remote) {
3195
$("#remote-save-select").click();
3196
} else {
3197
socket.send({'cmd': 'loadfromfile', 'data': ''});
3198
}
3199
});
3200
3201
$("#remote-save-select").on("change", function() {
3202
var reader = new FileReader();
3203
var file = $("#remote-save-select")[0].files[0];
3204
reader.addEventListener("load", function(response) {
3205
socket.send({'cmd': 'loadfromstring', 'filename': file.name, 'data': response.target.result});
3206
}, false);
3207
reader.readAsText(file);
3208
});
3209
3210
button_import.on("click", function(ev) {
3211
socket.send({'cmd': 'import', 'data': ''});
3212
});
3213
3214
button_importwi.on("click", function(ev) {
3215
socket.send({'cmd': 'importwi', 'data': ''});
3216
});
3217
3218
button_settings.on("click", function(ev) {
3219
$('#settingsmenu').slideToggle("slow");
3220
});
3221
3222
button_format.on("click", function(ev) {
3223
$('#formatmenu').slideToggle("slow");
3224
});
3225
3226
popup_close.on("click", function(ev) {
3227
socket.send({'cmd': 'importcancel', 'data': ''});
3228
});
3229
3230
popup_accept.on("click", function(ev) {
3231
socket.send({'cmd': 'importaccept', 'data': ''});
3232
});
3233
3234
button_actwi.on("click", function(ev) {
3235
socket.send({'cmd': 'wi', 'data': ''});
3236
});
3237
3238
button_impaidg.on("click", function(ev) {
3239
if(connected) {
3240
showAidgPopup();
3241
}
3242
});
3243
3244
aidg_close.on("click", function(ev) {
3245
hideAidgPopup();
3246
});
3247
3248
aidg_accept.on("click", function(ev) {
3249
sendAidgImportRequest();
3250
});
3251
3252
button_save.on("click", function(ev) {
3253
socket.send({'cmd': 'saverequest', 'data': ''});
3254
});
3255
3256
button_saveas.on("click", function(ev) {
3257
if(connected) {
3258
showSaveAsPopup();
3259
}
3260
});
3261
3262
saveas_close.on("click", function(ev) {
3263
hideSaveAsPopup();
3264
socket.send({'cmd': 'clearoverwrite', 'data': ''});
3265
});
3266
3267
saveas_accept.on("click", function(ev) {
3268
sendSaveAsRequest();
3269
});
3270
3271
button_download.on("click", function(ev) {
3272
downloadStory('json');
3273
});
3274
3275
button_downloadtxt.on("click", function(ev) {
3276
if(connected) {
3277
downloadStory('plaintext');
3278
}
3279
});
3280
3281
button_load.on("click", function(ev) {
3282
socket.send({'cmd': 'loadlistrequest', 'data': ''});
3283
});
3284
3285
button_softprompt.on("click", function(ev) {
3286
socket.send({'cmd': 'splistrequest', 'data': ''});
3287
});
3288
3289
button_userscripts.on("click", function(ev) {
3290
socket.send({'cmd': 'uslistrequest', 'data': ''});
3291
});
3292
3293
button_samplers.on("click", function(ev) {
3294
socket.send({'cmd': 'samplerlistrequest', 'data': ''});
3295
});
3296
3297
load_close.on("click", function(ev) {
3298
hideLoadPopup();
3299
});
3300
3301
load_model_close.on("click", function(ev) {
3302
$("#modellayers").addClass("hidden");
3303
hideLoadModelPopup();
3304
});
3305
3306
load_accept.on("click", function(ev) {
3307
hideMessage();
3308
newly_loaded = true;
3309
socket.send({'cmd': 'loadrequest', 'data': ''});
3310
hideLoadPopup();
3311
});
3312
3313
load_model_accept.on("click", function(ev) {
3314
hideMessage();
3315
var gpu_layers;
3316
var message;
3317
if($("#modellayers")[0].classList.contains('hidden')) {
3318
gpu_layers = ","
3319
} else {
3320
gpu_layers = ""
3321
for (let i=0; i < $("#gpu_count")[0].value; i++) {
3322
gpu_layers += $("#gpu_layers"+i)[0].value + ",";
3323
}
3324
}
3325
var disk_layers = $("#disk_layers").length > 0 ? $("#disk_layers")[0].value : 0;
3326
models = getSelectedOptions(document.getElementById('oaimodel'));
3327
if (models.length == 1) {
3328
models = models[0];
3329
}
3330
message = {'cmd': 'load_model', 'use_gpu': $('#use_gpu')[0].checked, 'key': $('#modelkey')[0].value, 'gpu_layers': gpu_layers.slice(0, -1), 'disk_layers': disk_layers, 'url': $('#modelurl')[0].value, 'online_model': models};
3331
socket.send(message);
3332
loadmodelcontent.html("");
3333
hideLoadModelPopup();
3334
});
3335
3336
sp_close.on("click", function(ev) {
3337
hideSPPopup();
3338
});
3339
3340
sp_accept.on("click", function(ev) {
3341
hideMessage();
3342
socket.send({'cmd': 'sprequest', 'data': ''});
3343
hideSPPopup();
3344
});
3345
3346
us_close.on("click", function(ev) {
3347
socket.send({'cmd': 'usloaded', 'data': usloaded.find(".uslistitem").map(function() { return $(this).attr("name"); }).toArray()});
3348
hideUSPopup();
3349
});
3350
3351
us_accept.on("click", function(ev) {
3352
hideMessage();
3353
socket.send({'cmd': 'usloaded', 'data': usloaded.find(".uslistitem").map(function() { return $(this).attr("name"); }).toArray()});
3354
socket.send({'cmd': 'usload', 'data': ''});
3355
hideUSPopup();
3356
});
3357
3358
samplers_close.on("click", function(ev) {
3359
hideSamplersPopup();
3360
});
3361
3362
samplers_accept.on("click", function(ev) {
3363
hideMessage();
3364
socket.send({'cmd': 'samplers', 'data': samplerslist.find(".samplerslistitem").map(function() { return parseInt($(this).attr("sid")); }).toArray()});
3365
hideSamplersPopup();
3366
});
3367
3368
button_loadmodel.on("click", function(ev) {
3369
showLoadModelPopup();
3370
socket.send({'cmd': 'list_model', 'data': 'mainmenu'});
3371
});
3372
button_showmodel.on("click", function(ev) {
3373
socket.send({'cmd': 'show_model', 'data': ''});
3374
});
3375
3376
button_newgame.on("click", function(ev) {
3377
if(connected) {
3378
showNewStoryPopup();
3379
}
3380
});
3381
3382
ns_accept.on("click", function(ev) {
3383
hideMessage();
3384
socket.send({'cmd': 'newgame', 'data': ''});
3385
hideNewStoryPopup();
3386
});
3387
3388
ns_close.on("click", function(ev) {
3389
hideNewStoryPopup();
3390
});
3391
3392
$("#btn_dsclose").on("click", function () {
3393
$("#loadcontainerdelete").removeClass("flex").addClass("hidden");
3394
hide([$(".saveasoverwrite"), $(".popuperror")]);
3395
});
3396
3397
$("#newsavename").on("input", function (ev) {
3398
if($(this).val() == "") {
3399
disableButtons([$("#btn_rensaccept")]);
3400
} else {
3401
enableButtons([$("#btn_rensaccept")]);
3402
}
3403
hide([$(".saveasoverwrite"), $(".popuperror")]);
3404
});
3405
3406
$("#btn_rensclose").on("click", function () {
3407
$("#loadcontainerrename").removeClass("flex").addClass("hidden");
3408
hide([$(".saveasoverwrite"), $(".popuperror")]);
3409
});
3410
3411
button_rndgame.on("click", function(ev) {
3412
if(connected) {
3413
showRandomStoryPopup();
3414
}
3415
});
3416
3417
rs_accept.on("click", function(ev) {
3418
beginStream();
3419
hideMessage();
3420
socket.send({'cmd': 'rndgame', 'memory': $("#rngmemory").val(), 'data': topic.val()});
3421
hideRandomStoryPopup();
3422
});
3423
3424
rs_close.on("click", function(ev) {
3425
hideRandomStoryPopup();
3426
});
3427
3428
anote_slider.on("input", function () {
3429
socket.send({'cmd': 'anotedepth', 'data': $(this).val()});
3430
});
3431
3432
// Dynamically change vertical size of world info "Comment" text box
3433
wi_menu.on("input", ".wicomment > textarea", function () {
3434
adjustWiCommentHeight(this);
3435
});
3436
3437
// Dynamically change vertical size of world info folder name text box
3438
wi_menu.on("input", ".wifoldername > div > textarea", function () {
3439
adjustWiFolderNameHeight(this);
3440
});
3441
3442
saveasinput.on("input", function () {
3443
if(saveasinput.val() == "") {
3444
disableButtons([saveas_accept]);
3445
} else {
3446
enableButtons([saveas_accept]);
3447
}
3448
hide([$(".saveasoverwrite"), $(".popuperror")]);
3449
});
3450
3451
// Bind Enter button to submit
3452
input_text.keydown(function (ev) {
3453
if (ev.which == 13 && !shift_down) {
3454
do_clear_ent = true;
3455
dosubmit(true);
3456
} else if(ev.which == 16) {
3457
shift_down = true;
3458
}
3459
});
3460
3461
// Enter to submit, but not if holding shift
3462
input_text.keyup(function (ev) {
3463
if (ev.which == 13 && do_clear_ent) {
3464
input_text.val("");
3465
do_clear_ent = false;
3466
} else if(ev.which == 16) {
3467
shift_down = false;
3468
}
3469
});
3470
3471
aidgpromptnum.keydown(function (ev) {
3472
if (ev.which == 13) {
3473
sendAidgImportRequest();
3474
}
3475
});
3476
3477
saveasinput.keydown(function (ev) {
3478
if (ev.which == 13 && saveasinput.val() != "") {
3479
sendSaveAsRequest();
3480
}
3481
});
3482
3483
$([input_text, anote_input, $("#gamescreen")]).map($.fn.toArray).on("input", function() {
3484
setGameSaved(false);
3485
});
3486
3487
$(window).on("beforeunload", function() {
3488
if(!gamesaved) {
3489
return true;
3490
}
3491
});
3492
3493
// Shortcuts
3494
$(window).keydown(function (ev) {
3495
if (ev.altKey)
3496
switch (ev.key) {
3497
// Alt+Z - Back
3498
case "z":
3499
button_actback.click();
3500
break;
3501
// Alt+Y - Forward
3502
case "y":
3503
button_actfwd.click();
3504
break;
3505
// Alt+R - Retry
3506
case "r":
3507
button_actretry.click();
3508
break;
3509
default:
3510
return;
3511
} else {
3512
return;
3513
}
3514
ev.preventDefault();
3515
});
3516
3517
$("#anotetemplate").on("input", function() {
3518
updateInputBudget(anote_input[0]);
3519
})
3520
3521
registerTokenCounters();
3522
3523
updateInputBudget(input_text[0]);
3524
3525
});
3526
3527
3528
3529
var popup_deleteable = false;
3530
var popup_editable = false;
3531
var popup_renameable = false;
3532
3533
function load_popup(data) {
3534
document.getElementById('spcontainer').classList.add('hidden');
3535
document.getElementById('uscontainer').classList.add('hidden');
3536
popup_deleteable = data.deleteable;
3537
popup_editable = data.editable;
3538
popup_renameable = data.renameable;
3539
var popup = document.getElementById("popup");
3540
var popup_title = document.getElementById("popup_title");
3541
popup_title.textContent = data.popup_title;
3542
var popup_list = document.getElementById("popup_list");
3543
//first, let's clear out our existing data
3544
while (popup_list.firstChild) {
3545
popup_list.removeChild(popup_list.firstChild);
3546
}
3547
var breadcrumbs = document.getElementById('popup_breadcrumbs');
3548
while (breadcrumbs.firstChild) {
3549
breadcrumbs.removeChild(breadcrumbs.firstChild);
3550
}
3551
3552
if (data.upload) {
3553
const dropArea = document.getElementById('popup_list');
3554
dropArea.addEventListener('dragover', (event) => {
3555
event.stopPropagation();
3556
event.preventDefault();
3557
// Style the drag-and-drop as a "copy file" operation.
3558
event.dataTransfer.dropEffect = 'copy';
3559
});
3560
3561
dropArea.addEventListener('drop', (event) => {
3562
event.stopPropagation();
3563
event.preventDefault();
3564
const fileList = event.dataTransfer.files;
3565
for (file of fileList) {
3566
reader = new FileReader();
3567
reader.onload = function (event) {
3568
socket.emit("upload_file", {'filename': file.name, "data": event.target.result});
3569
};
3570
reader.readAsArrayBuffer(file);
3571
}
3572
});
3573
} else {
3574
3575
}
3576
3577
popup.classList.remove("hidden");
3578
3579
//adjust accept button
3580
if (data.call_back == "") {
3581
document.getElementById("popup_accept").classList.add("hidden");
3582
} else {
3583
document.getElementById("popup_accept").classList.remove("hidden");
3584
var accept = document.getElementById("popup_accept");
3585
accept.classList.add("disabled");
3586
accept.setAttribute("emit", data.call_back);
3587
accept.setAttribute("selected_value", "");
3588
accept.onclick = function () {
3589
socket.emit(this.emit, this.getAttribute("selected_value"));
3590
document.getElementById("popup").classList.add("hidden");
3591
};
3592
}
3593
3594
}
3595
3596
function popup_items(data) {
3597
var popup_list = document.getElementById('popup_list');
3598
//first, let's clear out our existing data
3599
while (popup_list.firstChild) {
3600
popup_list.removeChild(popup_list.firstChild);
3601
}
3602
document.getElementById('popup_upload_input').value = "";
3603
3604
for (item of data) {
3605
var list_item = document.createElement("span");
3606
list_item.classList.add("item");
3607
3608
//create the folder icon
3609
var folder_icon = document.createElement("span");
3610
folder_icon.classList.add("folder_icon");
3611
if (item[0]) {
3612
folder_icon.classList.add("oi");
3613
folder_icon.setAttribute('data-glyph', "folder");
3614
}
3615
list_item.append(folder_icon);
3616
3617
//create the edit icon
3618
var edit_icon = document.createElement("span");
3619
edit_icon.classList.add("edit_icon");
3620
if ((popup_editable) && !(item[0])) {
3621
edit_icon.classList.add("oi");
3622
edit_icon.setAttribute('data-glyph', "spreadsheet");
3623
edit_icon.title = "Edit"
3624
edit_icon.id = item[1];
3625
edit_icon.onclick = function () {
3626
socket.emit("popup_edit", this.id);
3627
};
3628
}
3629
list_item.append(edit_icon);
3630
3631
//create the rename icon
3632
var rename_icon = document.createElement("span");
3633
rename_icon.classList.add("rename_icon");
3634
if ((popup_renameable) && !(item[0])) {
3635
rename_icon.classList.add("oi");
3636
rename_icon.setAttribute('data-glyph', "pencil");
3637
rename_icon.title = "Rename"
3638
rename_icon.id = item[1];
3639
rename_icon.setAttribute("filename", item[2]);
3640
rename_icon.onclick = function () {
3641
var new_name = prompt("Please enter new filename for \n"+ this.getAttribute("filename"));
3642
if (new_name != null) {
3643
socket.emit("popup_rename", {"file": this.id, "new_name": new_name});
3644
}
3645
};
3646
}
3647
list_item.append(rename_icon);
3648
3649
//create the delete icon
3650
var delete_icon = document.createElement("span");
3651
delete_icon.classList.add("delete_icon");
3652
if (popup_deleteable) {
3653
delete_icon.classList.add("oi");
3654
delete_icon.setAttribute('data-glyph', "x");
3655
delete_icon.title = "Delete"
3656
delete_icon.id = item[1];
3657
delete_icon.setAttribute("folder", item[0]);
3658
delete_icon.onclick = function () {
3659
if (this.getAttribute("folder") == "true") {
3660
if (window.confirm("Do you really want to delete this folder and ALL files under it?")) {
3661
socket.emit("popup_delete", this.id);
3662
}
3663
} else {
3664
if (window.confirm("Do you really want to delete this file?")) {
3665
socket.emit("popup_delete", this.id);
3666
}
3667
}
3668
};
3669
}
3670
list_item.append(delete_icon);
3671
3672
//create the actual item
3673
var popup_item = document.createElement("span");
3674
popup_item.classList.add("file");
3675
popup_item.id = item[1];
3676
popup_item.setAttribute("folder", item[0]);
3677
popup_item.setAttribute("valid", item[3]);
3678
popup_item.textContent = item[2];
3679
popup_item.onclick = function () {
3680
var accept = document.getElementById("popup_accept");
3681
if (this.getAttribute("valid") == "true") {
3682
accept.classList.remove("disabled");
3683
accept.setAttribute("selected_value", this.id);
3684
} else {
3685
console.log("not valid");
3686
accept.setAttribute("selected_value", "");
3687
accept.classList.add("disabled");
3688
if (this.getAttribute("folder") == "true") {
3689
console.log("folder");
3690
socket.emit("popup_change_folder", this.id);
3691
}
3692
}
3693
};
3694
list_item.append(popup_item);
3695
3696
3697
popup_list.append(list_item);
3698
3699
3700
}
3701
}
3702
3703
function popup_breadcrumbs(data) {
3704
var breadcrumbs = document.getElementById('popup_breadcrumbs')
3705
while (breadcrumbs.firstChild) {
3706
breadcrumbs.removeChild(breadcrumbs.firstChild);
3707
}
3708
3709
for (item of data) {
3710
var button = document.createElement("button");
3711
button.id = item[0];
3712
button.textContent = item[1];
3713
button.classList.add("breadcrumbitem");
3714
button.onclick = function () {
3715
socket.emit("popup_change_folder", this.id);
3716
};
3717
breadcrumbs.append(button);
3718
var span = document.createElement("span");
3719
span.textContent = "\\";
3720
breadcrumbs.append(span);
3721
}
3722
}
3723
3724
function popup_edit_file(data) {
3725
var popup_list = document.getElementById('popup_list');
3726
var accept = document.getElementById("popup_accept");
3727
accept.classList.add("btn-secondary");
3728
accept.classList.remove("btn-primary");
3729
accept.textContent = "Save";
3730
//first, let's clear out our existing data
3731
while (popup_list.firstChild) {
3732
popup_list.removeChild(popup_list.firstChild);
3733
}
3734
var accept = document.getElementById("popup_accept");
3735
accept.setAttribute("selected_value", "");
3736
accept.onclick = function () {
3737
var textarea = document.getElementById("filecontents");
3738
socket.emit("popup_change_file", {"file": textarea.getAttribute("filename"), "data": textarea.value});
3739
document.getElementById("popup").classList.add("hidden");
3740
this.classList.add("hidden");
3741
};
3742
3743
var textarea = document.createElement("textarea");
3744
textarea.classList.add("fullwidth");
3745
textarea.rows = 25;
3746
textarea.id = "filecontents"
3747
textarea.setAttribute("filename", data.file);
3748
textarea.value = data.text;
3749
textarea.onblur = function () {
3750
var accept = document.getElementById("popup_accept");
3751
accept.classList.remove("hidden");
3752
accept.classList.remove("btn-secondary");
3753
accept.classList.add("btn-primary");
3754
};
3755
popup_list.append(textarea);
3756
3757
}
3758
3759
function error_popup(data) {
3760
alert(data);
3761
}
3762
3763
function upload_file(file_box) {
3764
var fileList = file_box.files;
3765
for (file of fileList) {
3766
reader = new FileReader();
3767
reader.onload = function (event) {
3768
socket.emit("upload_file", {'filename': file.name, "data": event.target.result});
3769
};
3770
reader.readAsArrayBuffer(file);
3771
}
3772
}
3773
3774
function getSelectedOptions(element) {
3775
// validate element
3776
if(!element || !element.options)
3777
return []; //or null?
3778
3779
// return HTML5 implementation of selectedOptions instead.
3780
if (element.selectedOptions) {
3781
selectedOptions = element.selectedOptions;
3782
} else {
3783
// you are here because your browser doesn't have the HTML5 selectedOptions
3784
var opts = element.options;
3785
var selectedOptions = [];
3786
for(var i = 0; i < opts.length; i++) {
3787
if(opts[i].selected) {
3788
selectedOptions.push(opts[i]);
3789
}
3790
}
3791
}
3792
output = []
3793
for (item of selectedOptions) {
3794
output.push(item.value);
3795
}
3796
return output;
3797
}
3798
3799