diff --git a/aiserver.py b/aiserver.py
index 28da1d21..50f0e924 100644
--- a/aiserver.py
+++ b/aiserver.py
@@ -86,7 +86,9 @@ class vars:
authornote = "" # Text submitted to Author's Note field
andepth = 3 # How far back in history to append author's note
actions = structures.KoboldStoryRegister() # Actions submitted by user and AI
- worldinfo = [] # Array of World Info key/value objects
+ worldinfo = [] # List of World Info key/value objects
+ wifolders_d = {} # Dictionary of World Info folder UID-info pairs
+ wifolders_l = [] # List of World Info folder UIDs
# badwords = [] # Array of str/chr values that should be removed from output
badwordsids = [[13460], [6880], [50256], [42496], [4613], [17414], [22039], [16410], [27], [29], [38430], [37922], [15913], [24618], [28725], [58], [47175], [36937], [26700], [12878], [16471], [37981], [5218], [29795], [13412], [45160], [3693], [49778], [4211], [20598], [36475], [33409], [44167], [32406], [29847], [29342], [42669], [685], [25787], [7359], [3784], [5320], [33994], [33490], [34516], [43734], [17635], [24293], [9959], [23785], [21737], [28401], [18161], [26358], [32509], [1279], [38155], [18189], [26894], [6927], [14610], [23834], [11037], [14631], [26933], [46904], [22330], [25915], [47934], [38214], [1875], [14692], [41832], [13163], [25970], [29565], [44926], [19841], [37250], [49029], [9609], [44438], [16791], [17816], [30109], [41888], [47527], [42924], [23984], [49074], [33717], [31161], [49082], [30138], [31175], [12240], [14804], [7131], [26076], [33250], [3556], [38381], [36338], [32756], [46581], [17912], [49146]] # Tokenized array of badwords used to prevent AI artifacting
deletewi = -1 # Temporary storage for index to delete
@@ -858,6 +860,8 @@ def download():
"key": wi["key"],
"keysecondary": wi["keysecondary"],
"content": wi["content"],
+ "comment": wi["comment"],
+ "folder": wi["folder"],
"selective": wi["selective"],
"constant": wi["constant"]
})
@@ -1055,17 +1059,49 @@ def get_message(msg):
elif(msg['cmd'] == 'wiinit'):
if(int(msg['data']) < len(vars.worldinfo)):
vars.worldinfo[msg['data']]["init"] = True
- addwiitem()
+ addwiitem(folder_uid=msg['folder'])
+ elif(msg['cmd'] == 'wifolderinit'):
+ addwifolder()
+ elif(msg['cmd'] == 'wimoveitem'):
+ movewiitem(msg['destination'], msg['data'])
+ elif(msg['cmd'] == 'wimovefolder'):
+ movewifolder(msg['destination'], msg['data'])
elif(msg['cmd'] == 'widelete'):
deletewi(msg['data'])
+ elif(msg['cmd'] == 'wifolderdelete'):
+ deletewifolder(msg['data'])
+ elif(msg['cmd'] == 'wiexpand'):
+ assert 0 <= int(msg['data']) < len(vars.worldinfo)
+ emit('from_server', {'cmd': 'wiexpand', 'data': msg['data']}, broadcast=True)
+ elif(msg['cmd'] == 'wiexpandfolder'):
+ assert 0 <= int(msg['data']) < len(vars.worldinfo)
+ emit('from_server', {'cmd': 'wiexpandfolder', 'data': msg['data']}, broadcast=True)
+ elif(msg['cmd'] == 'wiupdate'):
+ num = int(msg['num'])
+ fields = ("key", "keysecondary", "content", "comment")
+ for field in fields:
+ if(field in msg['data'] and type(msg['data'][field]) is str):
+ vars.worldinfo[num][field] = msg['data'][field]
+ emit('from_server', {'cmd': 'wiupdate', 'num': msg['num'], 'data': {field: vars.worldinfo[num][field] for field in fields}}, broadcast=True)
+ elif(msg['cmd'] == 'wifolderupdate'):
+ uid = int(msg['uid'])
+ fields = ("name", "collapsed")
+ for field in fields:
+ if(field in msg['data'] and type(msg['data'][field]) is (str if field != "collapsed" else bool)):
+ vars.wifolders_d[uid][field] = msg['data'][field]
+ emit('from_server', {'cmd': 'wifolderupdate', 'uid': msg['uid'], 'data': {field: vars.wifolders_d[uid][field] for field in fields}}, broadcast=True)
elif(msg['cmd'] == 'wiselon'):
vars.worldinfo[msg['data']]["selective"] = True
+ emit('from_server', {'cmd': 'wiselon', 'data': msg['data']}, broadcast=True)
elif(msg['cmd'] == 'wiseloff'):
vars.worldinfo[msg['data']]["selective"] = False
+ emit('from_server', {'cmd': 'wiseloff', 'data': msg['data']}, broadcast=True)
elif(msg['cmd'] == 'wiconstanton'):
vars.worldinfo[msg['data']]["constant"] = True
+ emit('from_server', {'cmd': 'wiconstanton', 'data': msg['data']}, broadcast=True)
elif(msg['cmd'] == 'wiconstantoff'):
vars.worldinfo[msg['data']]["constant"] = False
+ emit('from_server', {'cmd': 'wiconstantoff', 'data': msg['data']}, broadcast=True)
elif(msg['cmd'] == 'sendwilist'):
commitwi(msg['data'])
elif(msg['cmd'] == 'aidgimport'):
@@ -2104,32 +2140,76 @@ def togglewimode():
#==================================================================#
#
#==================================================================#
-def addwiitem():
- ob = {"key": "", "keysecondary": "", "content": "", "num": len(vars.worldinfo), "init": False, "selective": False, "constant": False}
- vars.worldinfo.append(ob);
+def addwiitem(folder_uid=None):
+ assert folder_uid is None or folder_uid in vars.wifolders_d
+ ob = {"key": "", "keysecondary": "", "content": "", "comment": "", "folder": folder_uid, "num": len(vars.worldinfo), "init": False, "selective": False, "constant": False}
+ vars.worldinfo.append(ob)
emit('from_server', {'cmd': 'addwiitem', 'data': ob}, broadcast=True)
+#==================================================================#
+# Creates a new WI folder with an unused cryptographically secure random UID
+#==================================================================#
+def addwifolder():
+ while(True):
+ uid = int.from_bytes(os.urandom(4), "little", signed=True)
+ if(uid not in vars.wifolders_d):
+ break
+ ob = {"name": "", "collapsed": False}
+ vars.wifolders_d[uid] = ob
+ vars.wifolders_l.append(uid)
+ emit('from_server', {'cmd': 'addwifolder', 'uid': uid, 'data': ob}, broadcast=True)
+ addwiitem(folder_uid=uid)
+
+#==================================================================#
+# Move the WI entry with number src so that it immediately precedes
+# the WI entry with number dst
+#==================================================================#
+def movewiitem(dst, src):
+ vars.worldinfo[src]["folder"] = vars.worldinfo[dst]["folder"]
+ vars.worldinfo.insert(dst - (dst >= src), vars.worldinfo.pop(src))
+ sendwi()
+
+#==================================================================#
+# Move the WI folder with UID src so that it immediately precedes
+# the WI folder with UID dst
+#==================================================================#
+def movewifolder(dst, src):
+ vars.wifolders_l.remove(src)
+ if(dst is None):
+ # If dst is None, that means we should move src to be the last folder
+ vars.wifolders_l.append(src)
+ else:
+ vars.wifolders_l.insert(vars.wifolders_l.index(dst), src)
+ sendwi()
+
#==================================================================#
#
#==================================================================#
def sendwi():
# Cache len of WI
ln = len(vars.worldinfo)
-
+
# Clear contents of WI container
- emit('from_server', {'cmd': 'clearwi', 'data': ''}, broadcast=True)
-
+ emit('from_server', {'cmd': 'wistart', 'wifolders_d': vars.wifolders_d, 'wifolders_l': vars.wifolders_l, 'data': ''}, broadcast=True)
+
+ # Stable-sort WI entries in order of folder
+ stablesortwi()
+
# If there are no WI entries, send an empty WI object
if(ln == 0):
addwiitem()
else:
# Send contents of WI array
+ organizewi()
+ last_folder = ...
for wi in vars.worldinfo:
+ if(wi["folder"] != last_folder):
+ emit('from_server', {'cmd': 'addwifolder', 'uid': wi["folder"], 'data': vars.wifolders_d[wi["folder"]] if wi["folder"] is not None else None}, broadcast=True)
+ last_folder = wi["folder"]
ob = wi
emit('from_server', {'cmd': 'addwiitem', 'data': ob}, broadcast=True)
- # Make sure last WI item is uninitialized
- if(vars.worldinfo[-1]["init"]):
- addwiitem()
+
+ emit('from_server', {'cmd': 'wifinish', 'data': ''}, broadcast=True)
#==================================================================#
# Request current contents of all WI HTML elements
@@ -2140,6 +2220,25 @@ def requestwi():
list.append(wi["num"])
emit('from_server', {'cmd': 'requestwiitem', 'data': list})
+#==================================================================#
+# Stable-sort WI items so that items in the same folder are adjacent,
+# and items in different folders are sorted based on the order of the folders
+#==================================================================#
+def stablesortwi():
+ mapping = {uid: index for index, uid in enumerate(vars.wifolders_l)}
+ vars.worldinfo.sort(key=lambda x: mapping[x["folder"]] if x["folder"] is not None else float("inf"))
+ last_folder = ...
+ last_wi = None
+ for wi in vars.worldinfo:
+ wi["init"] = True
+ if(wi["folder"] != last_folder):
+ if(last_wi is not None and last_folder is not ...):
+ last_wi["init"] = False
+ last_folder = wi["folder"]
+ last_wi = wi
+ if(last_wi) is not None:
+ last_wi["init"] = False
+
#==================================================================#
# Renumber WI items consecutively
#==================================================================#
@@ -2159,12 +2258,13 @@ def commitwi(ar):
vars.worldinfo[ob["num"]]["key"] = ob["key"]
vars.worldinfo[ob["num"]]["keysecondary"] = ob["keysecondary"]
vars.worldinfo[ob["num"]]["content"] = ob["content"]
+ vars.worldinfo[ob["num"]]["comment"] = ob.get("comment", "")
+ vars.worldinfo[ob["num"]]["folder"] = ob.get("folder", None)
vars.worldinfo[ob["num"]]["selective"] = ob["selective"]
vars.worldinfo[ob["num"]]["constant"] = ob.get("constant", False)
# Was this a deletion request? If so, remove the requested index
if(vars.deletewi >= 0):
del vars.worldinfo[vars.deletewi]
- organizewi()
# Send the new WI array structure
sendwi()
# And reset deletewi index
@@ -2180,6 +2280,23 @@ def deletewi(num):
# Get contents of WI HTML inputs
requestwi()
+#==================================================================#
+#
+#==================================================================#
+def deletewifolder(uid):
+ uid = int(uid)
+ del vars.wifolders_d[uid]
+ del vars.wifolders_l[vars.wifolders_l.index(uid)]
+ # Delete uninitialized entries in the folder we're going to delete
+ vars.worldinfo = [wi for wi in vars.worldinfo if wi["folder"] != uid or wi["init"]]
+ # Move WI entries that are inside of the folder we're going to delete
+ # so that they're outside of all folders
+ for wi in vars.worldinfo:
+ if(wi["folder"] == uid):
+ wi["folder"] = None
+
+ sendwi()
+
#==================================================================#
# Look for WI keys in text to generator
#==================================================================#
@@ -2495,6 +2612,8 @@ def saveRequest(savpath):
js["authorsnote"] = vars.authornote
js["actions"] = tuple(vars.actions.values())
js["worldinfo"] = []
+ js["wifolders_d"] = vars.wifolders_d
+ js["wifolders_l"] = vars.wifolders_l
# Extract only the important bits of WI
for wi in vars.worldinfo:
@@ -2503,6 +2622,8 @@ def saveRequest(savpath):
"key": wi["key"],
"keysecondary": wi["keysecondary"],
"content": wi["content"],
+ "comment": wi["comment"],
+ "folder": wi["folder"],
"selective": wi["selective"],
"constant": wi["constant"]
})
@@ -2583,6 +2704,8 @@ def loadRequest(loadpath, filename=None):
vars.prompt = js["prompt"]
vars.memory = js["memory"]
vars.worldinfo = []
+ vars.wifolders_d = {int(k): v for k, v in js.get("wifolders_d", {}).items()}
+ vars.wifolders_l = js.get("wifolders_l", [])
vars.lastact = ""
vars.lastctx = ""
@@ -2615,13 +2738,19 @@ def loadRequest(loadpath, filename=None):
"key": wi["key"],
"keysecondary": wi.get("keysecondary", ""),
"content": wi["content"],
+ "comment": wi.get("comment", ""),
+ "folder": wi.get("folder", None),
"num": num,
"init": True,
"selective": wi.get("selective", False),
"constant": wi.get("constant", False)
})
num += 1
-
+
+ for uid in vars.wifolders_l + [None]:
+ vars.worldinfo.append({"key": "", "keysecondary": "", "content": "", "comment": "", "folder": uid, "num": None, "init": False, "selective": False, "constant": False})
+ stablesortwi()
+
# Save path for save button
vars.savedir = loadpath
@@ -2762,6 +2891,8 @@ def importgame():
vars.authornote = ref["authorsNote"] if type(ref["authorsNote"]) is str else ""
vars.actions = structures.KoboldStoryRegister()
vars.worldinfo = []
+ vars.wifolders_d = {}
+ vars.wifolders_l = []
vars.lastact = ""
vars.lastctx = ""
@@ -2784,6 +2915,8 @@ def importgame():
"key": wi["keys"],
"keysecondary": wi.get("keysecondary", ""),
"content": wi["entry"],
+ "comment": wi.get("comment", ""),
+ "folder": wi.get("folder", None),
"num": num,
"init": True,
"selective": wi.get("selective", False),
@@ -2826,6 +2959,8 @@ def importAidgRequest(id):
vars.authornote = js["authorsNote"]
vars.actions = structures.KoboldStoryRegister()
vars.worldinfo = []
+ vars.wifolders_d = {}
+ vars.wifolders_l = []
vars.lastact = ""
vars.lastctx = ""
@@ -2835,6 +2970,8 @@ def importAidgRequest(id):
"key": wi["keys"],
"keysecondary": wi.get("keysecondary", ""),
"content": wi["entry"],
+ "comment": wi.get("comment", ""),
+ "folder": wi.get("folder", None),
"num": num,
"init": True,
"selective": wi.get("selective", False),
@@ -2873,6 +3010,8 @@ def wiimportrequest():
"key": wi["keys"],
"keysecondary": wi.get("keysecondary", ""),
"content": wi["entry"],
+ "comment": wi.get("comment", ""),
+ "folder": wi.get("folder", None),
"num": num,
"init": True,
"selective": wi.get("selective", False),
@@ -2900,6 +3039,8 @@ def newGameRequest():
vars.authornote = ""
vars.worldinfo = []
+ vars.wifolders_d = {}
+ vars.wifolders_l = []
vars.lastact = ""
vars.lastctx = ""
diff --git a/static/application.js b/static/application.js
index f4d04bea..053c4a32 100644
--- a/static/application.js
+++ b/static/application.js
@@ -71,6 +71,7 @@ var storyname = null;
var memorymode = false;
var memorytext = "";
var gamestarted = false;
+var wiscroll = 0;
var editmode = false;
var connected = false;
var newly_loaded = true;
@@ -78,6 +79,8 @@ var modified_chunks = new Set();
var empty_chunks = new Set();
var gametext_bound = false;
var saved_prompt = "...";
+var wifolders_d = {};
+var wifolders_l = [];
var override_focusout = false;
var sman_allow_delete = false;
var sman_allow_rename = false;
@@ -196,51 +199,99 @@ function addImportLine(ob) {
});
}
+function adjustWiCommentHeight(element) {
+ element.style.height = "0px";
+ element.style.height = element.scrollHeight + "px";
+ element.parentNode.parentNode.style.height = element.scrollHeight + 90 + "px";
+}
+
+function adjustWiFolderNameHeight(element) {
+ element.style.height = "0px";
+ element.style.height = element.scrollHeight + "px";
+ element.parentNode.parentNode.parentNode.style.height = element.scrollHeight + 19 + "px";
+}
+
function addWiLine(ob) {
+ var current_wifolder_element = ob.folder === null ? $(".wisortable-body:not([folder-uid])").last() : $(".wisortable-body[folder-uid="+ob.folder+"]");
if(ob.init) {
if(ob.selective){
- wi_menu.append("
\
+ current_wifolder_element.append("
");
} else {
- wi_menu.append("
\
+ current_wifolder_element.append("
");
}
+ adjustWiCommentHeight($("#wicomment"+ob.num)[0]);
// Send key value to text input
$("#wikey"+ob.num).val(ob.key);
$("#wikeyprimary"+ob.num).val(ob.key);
@@ -251,81 +302,212 @@ function addWiLine(ob) {
});
} else {
// Show WI line item with form fields hidden (uninitialized)
- wi_menu.append("
\
+ current_wifolder_element.append("
");
// Assign function to expand WI item to button
$("#btn_wi"+ob.num).on("click", function () {
- expandWiLine(ob.num);
+ socket.send({'cmd': 'wiexpand', 'data': ob.num});
+ socket.send({'cmd': 'wiinit', 'folder': parseInt($("#wilistitem"+ob.num).parent().attr("folder-uid")) || null, 'data': ob.num});
});
}
// Assign actions to other elements
wientry_onfocus = function () {
+ $("#selective-key-"+ob.num).addClass("selective-key-icon-clickthrough");
$("#constant-key-"+ob.num).addClass("constant-key-icon-clickthrough");
}
wientry_onfocusout = function () {
+ $("#selective-key-"+ob.num).removeClass("selective-key-icon-clickthrough");
$("#constant-key-"+ob.num).removeClass("constant-key-icon-clickthrough");
+ // Tell server about updated WI fields
+ var selective = $("#wilistitem"+ob.num)[0].classList.contains("wilistitem-selective");
+ socket.send({'cmd': 'wiupdate', 'num': ob.num, 'data': {
+ key: selective ? $("#wikeyprimary"+ob.num).val() : $("#wikey"+ob.num).val(),
+ keysecondary: $("#wikeysecondary"+ob.num).val(),
+ content: $("#wientry"+ob.num).val(),
+ comment: $("#wicomment"+ob.num).val(),
+ }});
}
$("#wikey"+ob.num).on("focus", wientry_onfocus);
$("#wikeyprimary"+ob.num).on("focus", wientry_onfocus);
$("#wikeysecondary"+ob.num).on("focus", wientry_onfocus);
+ $("#wientry"+ob.num).on("focus", wientry_onfocus);
+ $("#wicomment"+ob.num).on("focus", wientry_onfocus);
$("#wikey"+ob.num).on("focusout", wientry_onfocusout);
$("#wikeyprimary"+ob.num).on("focusout", wientry_onfocusout);
$("#wikeysecondary"+ob.num).on("focusout", wientry_onfocusout);
+ $("#wientry"+ob.num).on("focusout", wientry_onfocusout);
+ $("#wicomment"+ob.num).on("focusout", wientry_onfocusout);
$("#btn_wican"+ob.num).on("click", function () {
hideWiDeleteConfirm(ob.num);
});
$("#btn_widel"+ob.num).on("click", function () {
socket.send({'cmd': 'widelete', 'data': ob.num});
});
- $("#btn_wiselon"+ob.num).on("click", function () {
- enableWiSelective(ob.num);
- $("#wikey"+ob.num).addClass("wilistitem-selective");
- });
- $("#btn_wiseloff"+ob.num).on("click", function () {
- disableWiSelective(ob.num);
- $("#wikey"+ob.num).removeClass("wilistitem-selective");
+ $("#selective-key-"+ob.num).on("click", function () {
+ var element = $("#selective-key-"+ob.num);
+ if(element.hasClass("selective-key-icon-enabled")) {
+ socket.send({'cmd': 'wiseloff', 'data': ob.num});
+ } else {
+ socket.send({'cmd': 'wiselon', 'data': ob.num});
+ }
});
$("#constant-key-"+ob.num).on("click", function () {
var element = $("#constant-key-"+ob.num);
if(element.hasClass("constant-key-icon-enabled")) {
socket.send({'cmd': 'wiconstantoff', 'data': ob.num});
- element.removeClass("constant-key-icon-enabled");
- $("#wikey"+ob.num).removeClass("wilistitem-constant");
} else {
socket.send({'cmd': 'wiconstanton', 'data': ob.num});
- element.addClass("constant-key-icon-enabled");
- $("#wikey"+ob.num).addClass("wilistitem-constant");
}
});
+ $("#wihandle"+ob.num).off().on("mousedown", wientry_onfocusout);
+}
+
+function addWiFolder(uid, ob) {
+ if(uid !== null) {
+ var uninitialized = $("#wilistfoldercontainer"+null);
+ var html = "
\
+
\
+
\
+ X \
+ ✓ \
+ ⮌ \
+
\
+
\
+
\
+
\
+
\
+ \
+ \
+ \
+ \
+ \
+
\
+
\
+
\
+
\
+
";
+ if(uninitialized.length) {
+ $(html).insertBefore(uninitialized);
+ } else {
+ wi_menu.append(html);
+ }
+ var onfocusout = function () {
+ socket.send({'cmd': 'wifolderupdate', 'uid': uid, 'data': {
+ name: $("#wifoldername"+uid).val(),
+ collapsed: false,
+ }});
+ };
+ $("#btn_wifolder"+uid).on("click", function () {
+ showWiFolderDeleteConfirm(uid);
+ });
+ $("#btn_wifolderdel"+uid).on("click", function () {
+ socket.send({'cmd': 'wifolderdelete', 'data': uid});
+ });
+ $("#btn_wifoldercan"+uid).on("click", function () {
+ hideWiFolderDeleteConfirm(uid);
+ })
+ $("#wifoldername"+uid).on("focusout", onfocusout);
+ $("#wifolderhandle"+uid).off().on("mousedown", onfocusout);
+ adjustWiFolderNameHeight($("#wifoldername"+uid)[0]);
+ } else {
+ wi_menu.append("
\
+
\
+
\
+ + \
+ ✓ \
+ ⮌ \
+
\
+
\
+
\
+
\
+
\
+ \
+ \
+ \
+ \
+ \
+
\
+
\
+
\
+
\
+
");
+ $("#btn_wifolder"+uid).on("click", function () {
+ expandWiFolderLine(uid);
+ });
+ }
}
function expandWiLine(num) {
- show([$("#wikey"+num), $("#wientry"+num), $("#constant-key-"+num), $("#btn_wiselon"+num)]);
+ show([$("#wikey"+num), $("#wientry"+num), $("#wihandle"+num), $("#selective-key-"+num), $("#constant-key-"+num), $("#btn_wiselon"+num), $("#wicomment"+num)]);
+ $("#wihandle"+num).removeClass("wihandle-inactive").addClass("wihandle");
$("#btn_wi"+num).html("X");
$("#btn_wi"+num).off();
+ $("#wilistitem"+num).removeClass("wilistitem-uninitialized").removeClass("wisortable-excluded");
// Tell server the WI entry was initialized
- socket.send({'cmd': 'wiinit', 'data': num});
$("#btn_wi"+num).on("click", function () {
showWiDeleteConfirm(num);
});
+
+ adjustWiCommentHeight($("#wicomment"+num)[0]);
+}
+
+function expandWiFolderLine(num) {
+ socket.send({'cmd': 'wifolderinit', 'data': ''});
}
function showWiDeleteConfirm(num) {
@@ -333,25 +515,51 @@ function showWiDeleteConfirm(num) {
show([$("#btn_widel"+num), $("#btn_wican"+num)]);
}
+function showWiFolderDeleteConfirm(num) {
+ hide([$("#btn_wifolder"+num)]);
+ show([$("#btn_wifolderdel"+num), $("#btn_wifoldercan"+num)]);
+}
+
function hideWiDeleteConfirm(num) {
show([$("#btn_wi"+num)]);
hide([$("#btn_widel"+num), $("#btn_wican"+num)]);
}
+function hideWiFolderDeleteConfirm(num) {
+ show([$("#btn_wifolder"+num)]);
+ hide([$("#btn_wifolderdel"+num), $("#btn_wifoldercan"+num)]);
+}
+
function enableWiSelective(num) {
- hide([$("#btn_wiselon"+num), $("#wikey"+num)]);
- // Tell server the WI entry is now selective
- socket.send({'cmd': 'wiselon', 'data': num});
+ hide([$("#wikey"+num)]);
$("#wikeyprimary"+num).val($("#wikey"+num).val());
- show([$("#wikeyprimary"+num), $("#wikeysecondary"+num), $("#btn_wiseloff"+num)]);
+ show([$("#wikeyprimary"+num), $("#wikeysecondary"+num)]);
+
+ var element = $("#selective-key-"+num);
+ element.addClass("selective-key-icon-enabled");
+ $("#wikey"+num).addClass("wilistitem-selective");
}
function disableWiSelective(num) {
- hide([$("#btn_wiseloff"+num), $("#wikeyprimary"+num), $("#wikeysecondary"+num)]);
- // Tell server the WI entry is now non-selective
- socket.send({'cmd': 'wiseloff', 'data': num});
+ hide([$("#wikeyprimary"+num), $("#wikeysecondary"+num)]);
$("#wikey"+num).val($("#wikeyprimary"+num).val());
- show([$("#btn_wiselon"+num), $("#wikey"+num)]);
+ show([$("#wikey"+num)]);
+
+ var element = $("#selective-key-"+num);
+ element.removeClass("selective-key-icon-enabled");
+ $("#wikey"+num).removeClass("wilistitem-selective");
+}
+
+function enableWiConstant(num) {
+ var element = $("#constant-key-"+num);
+ element.addClass("constant-key-icon-enabled");
+ $("#wikey"+num).addClass("wilistitem-constant");
+}
+
+function disableWiConstant(num) {
+ var element = $("#constant-key-"+num);
+ element.removeClass("constant-key-icon-enabled");
+ $("#wikey"+num).removeClass("wilistitem-constant");
}
function highlightImportLine(ref) {
@@ -491,11 +699,13 @@ function returnWiList(ar) {
var list = [];
var i;
for(i=0; i
:not(.wisortable-excluded):not(.wisortable-excluded-dynamic), #wimenu .wisortable-container[folder-uid]:not(.wisortable-excluded):not(.wisortable-excluded-dynamic)",
+ containment: "#wimenu",
+ connectWith: "#wimenu .wisortable-body",
+ handle: ".wihandle",
+ start: sortableOnStart,
+ stop: sortableOnStop,
+ cursor: "move",
+ tolerance: "pointer",
+ opacity: 0.42,
+ revert: 173,
+ scrollSensitivity: 64,
+ scrollSpeed: 10,
+ });
+ // Restore previously-saved scroll position
+ $("#gamescreen").scrollTop(wiscroll);
+ } else if(msg.cmd == "requestwiitem") {
// Package WI contents and send back to server
returnWiList(msg.data);
} else if(msg.cmd == "saveas") {
@@ -1846,7 +2151,17 @@ $(document).ready(function(){
anote_slider.on("input", function () {
socket.send({'cmd': 'anotedepth', 'data': $(this).val()});
});
-
+
+ // Dynamically change vertical size of world info "Comment" text box
+ wi_menu.on("input", ".wicomment > textarea", function () {
+ adjustWiCommentHeight(this);
+ });
+
+ // Dynamically change vertical size of world info folder name text box
+ wi_menu.on("input", ".wifoldername > div > textarea", function () {
+ adjustWiFolderNameHeight(this);
+ });
+
saveasinput.on("input", function () {
if(saveasinput.val() == "") {
disableButtons([saveas_accept]);
diff --git a/static/custom.css b/static/custom.css
index 9ac2ae65..0949a749 100644
--- a/static/custom.css
+++ b/static/custom.css
@@ -73,6 +73,7 @@ chunk.editing, chunk.editing * {
}
#gamescreen {
+ overflow-x: hidden;
height: 490px;
margin-top: 10px;
display: flex;
@@ -509,6 +510,70 @@ chunk.editing, chunk.editing * {
height: 50%;
}
+.wiheightfull {
+ height: 90%;
+}
+
+.wiheighthalf {
+ height: 45%;
+}
+
+.wicomment {
+ height: 10%;
+ grid-column-start: 2;
+ grid-column-end: 4;
+ padding-top: 10px;
+ padding-bottom: 6px;
+ padding-right: 0px;
+}
+
+.wihandle, .wifolderhandle {
+ grid-row: span 2;
+ line-height: 100%;
+ opacity: 30%;
+ font-size: 8px;
+ position: relative;
+}
+
+.wifoldericon {
+ font-size: 28px;
+ position: relative;
+ grid-row: span 2;
+}
+
+.wicentered {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ -moz-transform: translate(-50%, -50%);
+ -webkit-transform: translate(-50%, -50%);
+ -ms-transform: translate(-50%, -50%);
+ -o-transform: translate(-50%, -50%);
+}
+
+.wicentered-vertical {
+ position: absolute;
+ top: 50%;
+ transform: translate(0%, -50%);
+ -moz-transform: translate(0%, -50%);
+ -webkit-transform: translate(0%, -50%);
+ -ms-transform: translate(0%, -50%);
+ -o-transform: translate(0%, -50%);
+}
+
+.wihandle:hover {
+ cursor: move;
+}
+
+.wisortable-body {
+
+}
+
+.wisortable-dummy {
+ padding: 6px;
+}
+
.helpicon {
display: inline-block;
font-family: sans-serif;
@@ -578,6 +643,45 @@ chunk.editing, chunk.editing * {
position: relative;
}
+.selective-key-icon {
+ position: absolute !important;
+ top: 5px !important;
+ right: 28px !important;
+ z-index: 1;
+ opacity: 20%;
+}
+
+*:hover > .selective-key-icon {
+ opacity: 40%;
+}
+
+.selective-key-icon:hover {
+ opacity: 65%;
+ cursor: pointer;
+}
+
+.selective-key-icon-enabled {
+ color: #3bf723;
+ opacity: 65%
+}
+
+*:hover > .selective-key-icon-enabled {
+ opacity: 65%;
+}
+
+.selective-key-icon-enabled:hover {
+ opacity: 100%
+}
+
+.selective-key-icon-clickthrough {
+ opacity: 0% !important;
+ pointer-events: none;
+}
+
+.selective-key-icon-clickthrough.selective-key-icon-enabled {
+ opacity: 35% !important;
+}
+
.constant-key-icon {
position: absolute !important;
top: 5px !important;
@@ -888,26 +992,62 @@ chunk.editing, chunk.editing * {
}
.wilistitem {
- height: 80px;
+ height: 120px;
display: grid;
- grid-template-columns: 4% 30% 58% 8%;
- margin-bottom: 10px;
+ grid-template-columns: 4% 30% 63.5% 2.5%;
+ margin-bottom: 24px;
+ background-color: #212122;
+}
+
+.wilistfolder {
+ height: 60px;
+ display: grid;
+ grid-template-columns: 4% 5% 88.5% 2.5%;
+ margin-bottom: 24px;
+ background-color: #212122;
}
.wientry {
padding-left: 10px;
- padding-right: 10px;
+ padding-right: 0px;
background-color: #212122;
}
.wientry > textarea {
- height: 100%;
+ height: 90%;
resize: none;
overflow:auto;
background-color: #404040;
color: #ffffff;
}
+.wicomment > textarea {
+ resize: none;
+ height: 0px;
+ overflow: hidden;
+ background-color: #404040;
+ color: #ffffff;
+}
+
+.wifoldername {
+ position: relative;
+ grid-row: span 2;
+}
+
+.wifoldername > div {
+ width: 100%;
+ padding-left: 10px;
+}
+
+.wifoldername > div > textarea {
+ font-size: 20px;
+ resize: none;
+ height: 0px;
+ overflow: hidden;
+ background-color: #404040;
+ color: #ffffff;
+}
+
.wikey {
background-color: #212122;
}
@@ -917,12 +1057,13 @@ chunk.editing, chunk.editing * {
color: #ffffff;
}
+.wiremove {
+ grid-row-start: 1;
+ grid-row-end: 3;
+}
+
.wiremove > button {
width: 80%;
overflow: hidden;
font-size: 12pt;
}
-
-.wiselective > button {
- white-space: normal;
-}
diff --git a/static/jquery-ui.sortable.min.css b/static/jquery-ui.sortable.min.css
new file mode 100644
index 00000000..16b6fd5a
--- /dev/null
+++ b/static/jquery-ui.sortable.min.css
@@ -0,0 +1,6 @@
+/*! jQuery UI - v1.13.0 - 2021-12-02
+* http://jqueryui.com
+* Includes: sortable.css
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+.ui-sortable-handle{-ms-touch-action:none;touch-action:none}
diff --git a/static/jquery-ui.sortable.min.js b/static/jquery-ui.sortable.min.js
new file mode 100644
index 00000000..42ea2ecf
--- /dev/null
+++ b/static/jquery-ui.sortable.min.js
@@ -0,0 +1,6 @@
+/*! jQuery UI - v1.13.0 - 2021-12-02
+* http://jqueryui.com
+* Includes: widget.js, data.js, scroll-parent.js, widgets/sortable.js, widgets/mouse.js
+* Copyright jQuery Foundation and other contributors; Licensed MIT */
+
+!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(f){"use strict";f.ui=f.ui||{};f.ui.version="1.13.0";var o,i=0,r=Array.prototype.hasOwnProperty,h=Array.prototype.slice;f.cleanData=(o=f.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=f._data(i,"events"))&&e.remove&&f(i).triggerHandler("remove");o(t)}),f.widget=function(t,i,e){var s,o,n,r={},h=t.split(".")[0],a=h+"-"+(t=t.split(".")[1]);return e||(e=i,i=f.Widget),Array.isArray(e)&&(e=f.extend.apply(null,[{}].concat(e))),f.expr.pseudos[a.toLowerCase()]=function(t){return!!f.data(t,a)},f[h]=f[h]||{},s=f[h][t],o=f[h][t]=function(t,e){if(!this._createWidget)return new o(t,e);arguments.length&&this._createWidget(t,e)},f.extend(o,s,{version:e.version,_proto:f.extend({},e),_childConstructors:[]}),(n=new i).options=f.widget.extend({},n.options),f.each(e,function(e,s){function o(){return i.prototype[e].apply(this,arguments)}function n(t){return i.prototype[e].apply(this,t)}r[e]="function"==typeof s?function(){var t,e=this._super,i=this._superApply;return this._super=o,this._superApply=n,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:s}),o.prototype=f.widget.extend(n,{widgetEventPrefix:s&&n.widgetEventPrefix||t},r,{constructor:o,namespace:h,widgetName:t,widgetFullName:a}),s?(f.each(s._childConstructors,function(t,e){var i=e.prototype;f.widget(i.namespace+"."+i.widgetName,o,e._proto)}),delete s._childConstructors):i._childConstructors.push(o),f.widget.bridge(t,o),o},f.widget.extend=function(t){for(var e,i,s=h.call(arguments,1),o=0,n=s.length;o",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=f(e||this.defaultElement||this)[0],this.element=f(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=f(),this.hoverable=f(),this.focusable=f(),this.classesElementLookup={},e!==this&&(f.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=f(e.style?e.ownerDocument:e.document||e),this.window=f(this.document[0].defaultView||this.document[0].parentWindow)),this.options=f.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:f.noop,_create:f.noop,_init:f.noop,destroy:function(){var i=this;this._destroy(),f.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:f.noop,widget:function(){return this.element},option:function(t,e){var i,s,o,n=t;if(0===arguments.length)return f.widget.extend({},this.options);if("string"==typeof t)if(n={},t=(i=t.split(".")).shift(),i.length){for(s=n[t]=f.widget.extend({},this.options[t]),o=0;o=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),f.widget("ui.sortable",f.ui.mouse,{version:"1.13.0",widgetEventPrefix:"sort",ready:!1,options:{appendTo:"parent",axis:!1,connectWith:!1,containment:!1,cursor:"auto",cursorAt:!1,dropOnEmpty:!0,forcePlaceholderSize:!1,forceHelperSize:!1,grid:!1,handle:!1,helper:"original",items:"> *",opacity:!1,placeholder:!1,revert:!1,scroll:!0,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1e3,activate:null,beforeStop:null,change:null,deactivate:null,out:null,over:null,receive:null,remove:null,sort:null,start:null,stop:null,update:null},_isOverAxis:function(t,e,i){return e<=t&&t*{ cursor: "+n.cursor+" !important; }").appendTo(o)),n.zIndex&&(this.helper.css("zIndex")&&(this._storedZIndex=this.helper.css("zIndex")),this.helper.css("zIndex",n.zIndex)),n.opacity&&(this.helper.css("opacity")&&(this._storedOpacity=this.helper.css("opacity")),this.helper.css("opacity",n.opacity)),this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName&&(this.overflowOffset=this.scrollParent.offset()),this._trigger("start",t,this._uiHash()),this._preserveHelperProportions||this._cacheHelperProportions(),!i)for(s=this.containers.length-1;0<=s;s--)this.containers[s]._trigger("activate",t,this._uiHash(this));return f.ui.ddmanager&&(f.ui.ddmanager.current=this),f.ui.ddmanager&&!n.dropBehaviour&&f.ui.ddmanager.prepareOffsets(this,t),this.dragging=!0,this._addClass(this.helper,"ui-sortable-helper"),this.helper.parent().is(this.appendTo)||(this.helper.detach().appendTo(this.appendTo),this.offset.parent=this._getParentOffset()),this.position=this.originalPosition=this._generatePosition(t),this.originalPageX=t.pageX,this.originalPageY=t.pageY,this.lastPositionAbs=this.positionAbs=this._convertPositionTo("absolute"),this._mouseDrag(t),!0},_scroll:function(t){var e=this.options,i=!1;return this.scrollParent[0]!==this.document[0]&&"HTML"!==this.scrollParent[0].tagName?(this.overflowOffset.top+this.scrollParent[0].offsetHeight-t.pageYt[this.floating?"width":"height"]?l&&c:n",i.document[0]);return i._addClass(t,"ui-sortable-placeholder",s||i.currentItem[0].className)._removeClass(t,"ui-sortable-helper"),"tbody"===o?i._createTrPlaceholder(i.currentItem.find("tr").eq(0),f("",i.document[0]).appendTo(t)):"tr"===o?i._createTrPlaceholder(i.currentItem,t):"img"===o&&t.attr("src",i.currentItem.attr("src")),s||t.css("visibility","hidden"),t},update:function(t,e){s&&!n.forcePlaceholderSize||(e.height()&&(!n.forcePlaceholderSize||"tbody"!==o&&"tr"!==o)||e.height(i.currentItem.innerHeight()-parseInt(i.currentItem.css("paddingTop")||0,10)-parseInt(i.currentItem.css("paddingBottom")||0,10)),e.width()||e.width(i.currentItem.innerWidth()-parseInt(i.currentItem.css("paddingLeft")||0,10)-parseInt(i.currentItem.css("paddingRight")||0,10)))}}),i.placeholder=f(n.placeholder.element.call(i.element,i.currentItem)),i.currentItem.after(i.placeholder),n.placeholder.update(i,i.placeholder)},_createTrPlaceholder:function(t,e){var i=this;t.children().each(function(){f(" ",i.document[0]).attr("colspan",f(this).attr("colspan")||1).appendTo(e)})},_contactContainers:function(t){for(var e,i,s,o,n,r,h,a,l,c=null,u=null,p=this.containers.length-1;0<=p;p--)f.contains(this.currentItem[0],this.containers[p].element[0])||(this._intersectsWith(this.containers[p].containerCache)?c&&f.contains(this.containers[p].element[0],c.element[0])||(c=this.containers[p],u=p):this.containers[p].containerCache.over&&(this.containers[p]._trigger("out",t,this._uiHash(this)),this.containers[p].containerCache.over=0));if(this.innermostContainer=c)if(1===this.containers.length)this.containers[u].containerCache.over||(this.containers[u]._trigger("over",t,this._uiHash(this)),this.containers[u].containerCache.over=1);else{for(i=1e4,s=null,o=(a=c.floating||this._isFloating(this.currentItem))?"left":"top",n=a?"width":"height",l=a?"pageX":"pageY",e=this.items.length-1;0<=e;e--)f.contains(this.containers[u].element[0],this.items[e].item[0])&&this.items[e].item[0]!==this.currentItem[0]&&(r=this.items[e].item.offset()[o],h=!1,t[l]-r>this.items[e][n]/2&&(h=!0),Math.abs(t[l]-r)this.containment[2]&&(i=this.containment[2]+this.offset.click.left),t.pageY-this.offset.click.top>this.containment[3]&&(s=this.containment[3]+this.offset.click.top)),e.grid&&(t=this.originalPageY+Math.round((s-this.originalPageY)/e.grid[1])*e.grid[1],s=!this.containment||t-this.offset.click.top>=this.containment[1]&&t-this.offset.click.top<=this.containment[3]?t:t-this.offset.click.top>=this.containment[1]?t-e.grid[1]:t+e.grid[1],t=this.originalPageX+Math.round((i-this.originalPageX)/e.grid[0])*e.grid[0],i=!this.containment||t-this.offset.click.left>=this.containment[0]&&t-this.offset.click.left<=this.containment[2]?t:t-this.offset.click.left>=this.containment[0]?t-e.grid[0]:t+e.grid[0])),{top:s-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+("fixed"===this.cssPosition?-this.scrollParent.scrollTop():n?0:o.scrollTop()),left:i-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+("fixed"===this.cssPosition?-this.scrollParent.scrollLeft():n?0:o.scrollLeft())}},_rearrange:function(t,e,i,s){i?i[0].appendChild(this.placeholder[0]):e.item[0].parentNode.insertBefore(this.placeholder[0],"down"===this.direction?e.item[0]:e.item[0].nextSibling),this.counter=this.counter?++this.counter:1;var o=this.counter;this._delay(function(){o===this.counter&&this.refreshPositions(!s)})},_clear:function(t,e){this.reverting=!1;var i,s=[];if(!this._noFinalSort&&this.currentItem.parent().length&&this.placeholder.before(this.currentItem),this._noFinalSort=null,this.helper[0]===this.currentItem[0]){for(i in this._storedCSS)"auto"!==this._storedCSS[i]&&"static"!==this._storedCSS[i]||(this._storedCSS[i]="");this.currentItem.css(this._storedCSS),this._removeClass(this.currentItem,"ui-sortable-helper")}else this.currentItem.show();function o(e,i,s){return function(t){s._trigger(e,t,i._uiHash(i))}}for(this.fromOutside&&!e&&s.push(function(t){this._trigger("receive",t,this._uiHash(this.fromOutside))}),!this.fromOutside&&this.domPosition.prev===this.currentItem.prev().not(".ui-sortable-helper")[0]&&this.domPosition.parent===this.currentItem.parent()[0]||e||s.push(function(t){this._trigger("update",t,this._uiHash())}),this!==this.currentContainer&&(e||(s.push(function(t){this._trigger("remove",t,this._uiHash())}),s.push(function(e){return function(t){e._trigger("receive",t,this._uiHash(this))}}.call(this,this.currentContainer)),s.push(function(e){return function(t){e._trigger("update",t,this._uiHash(this))}}.call(this,this.currentContainer)))),i=this.containers.length-1;0<=i;i--)e||s.push(o("deactivate",this,this.containers[i])),this.containers[i].containerCache.over&&(s.push(o("out",this,this.containers[i])),this.containers[i].containerCache.over=0);if(this.storedCursor&&(this.document.find("body").css("cursor",this.storedCursor),this.storedStylesheet.remove()),this._storedOpacity&&this.helper.css("opacity",this._storedOpacity),this._storedZIndex&&this.helper.css("zIndex","auto"===this._storedZIndex?"":this._storedZIndex),this.dragging=!1,e||this._trigger("beforeStop",t,this._uiHash()),this.placeholder[0].parentNode.removeChild(this.placeholder[0]),this.cancelHelperRemoval||(this.helper[0]!==this.currentItem[0]&&this.helper.remove(),this.helper=null),!e){for(i=0;i
+
-
+
-
+
+