Working options.

This commit is contained in:
ebolam
2022-06-26 16:36:07 -04:00
parent 4c357abd78
commit b906742f61
9 changed files with 339 additions and 296 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -319,7 +319,19 @@ gensettingstf = [
"menu_path": "user", "menu_path": "user",
"classname": "user", "classname": "user",
"name": "debug" "name": "debug"
} },
{
"uitype": "dropdown",
"unit": "text",
"label": "Story Mode",
"id": "actionmode",
"default": 0,
"tooltip": "Choose the mode of KoboldAI",
"menu_path": "Story",
"classname": "story",
"name": "actionmode",
'children': [{'text': 'Story', 'value': 0}, {'text':'Adventure','value':1}, {'text':'Chat', 'value':2}]
}
] ]
gensettingsik =[{ gensettingsik =[{

View File

@@ -1,8 +1,11 @@
from flask_socketio import emit, join_room, leave_room, rooms from flask_socketio import emit, join_room, leave_room, rooms
import os import os, re, time, threading
import re import socketio as socketio_client
socketio = None socketio = None
main_thread_id = threading.get_ident()
rely_clients = {}
def clean_var_for_emit(value): def clean_var_for_emit(value):
if isinstance(value, KoboldStoryRegister): if isinstance(value, KoboldStoryRegister):
@@ -12,19 +15,43 @@ def clean_var_for_emit(value):
else: else:
return value return value
def process_variable_changes(classname, name, value, old_value): def process_variable_changes(classname, name, value, old_value, debug_message=None):
#Special Case for KoboldStoryRegister if socketio is not None:
if isinstance(value, KoboldStoryRegister): if debug_message is not None:
print("resetting") print("{} {}: {} changed from {} to {}".format(debug_message, classname, name, old_value, value))
socketio.emit("reset_story", {}, broadcast=True, room="UI_2") if value != old_value:
for i in range(len(value.actions)): #Special Case for KoboldStoryRegister
socketio.emit("var_changed", {"classname": "actions", "name": "Selected Text", "old_value": None, "value": {"id": i, "text": value[i]}}, broadcast=True, room="UI_2") if isinstance(value, KoboldStoryRegister):
socketio.emit("var_changed", {"classname": "actions", "name": "Options", "old_value": None, "value": {"id": i, "options": value.actions[i]['Options']}}, broadcast=True, room="UI_2") print("We got a story register")
else: print(value)
#print("{}: {} changed from {} to {}".format(classname, name, old_value, value)) socketio.emit("reset_story", {}, broadcast=True, room="UI_2")
#if name == "Selected Text": for i in range(len(value.actions)):
# print({"classname": classname, "name": name, "old_value": clean_var_for_emit(old_value), "value": clean_var_for_emit(value)}) socketio.emit("var_changed", {"classname": "actions", "name": "Selected Text", "old_value": None, "value": {"id": i, "text": value[i]}}, include_self=True, broadcast=True, room="UI_2")
socketio.emit("var_changed", {"classname": classname, "name": name, "old_value": clean_var_for_emit(old_value), "value": clean_var_for_emit(value)}, broadcast=True, room="UI_2") socketio.emit("var_changed", {"classname": "actions", "name": "Options", "old_value": None, "value": {"id": i, "options": value.actions[i]['Options']}}, include_self=True, broadcast=True, room="UI_2")
else:
#If we got a variable change from a thread other than what the app is run it, eventlet seems to block and no further messages are sent. Instead, we'll rely the message to the app and have the main thread send it
if main_thread_id != threading.get_ident():
if threading.get_ident() in rely_clients:
sio = rely_clients[threading.get_ident()]
else:
start_time = time.time()
print("getting client")
sio = socketio_client.Client()
@sio.event
def connect():
print("I'm connected!")
sio.connect('http://localhost:5000/?rely=true')
rely_clients[threading.get_ident()] = sio
print("got client, took {}".format(time.time()-start_time))
#release no longer used clients
for thread in rely_clients:
if thread not in [x.ident for x in threading.enumerate()]:
del rely_clients[thread]
sio.emit("relay", {"emit": "var_changed", "data": {"classname": classname, "name": name, "old_value": clean_var_for_emit(old_value), "value": clean_var_for_emit(value)}, "include_self":True, "broadcast":True, "room":"UI_2"})
else:
socketio.emit("var_changed", {"classname": classname, "name": name, "old_value": clean_var_for_emit(old_value), "value": clean_var_for_emit(value)}, include_self=True, broadcast=True, room="UI_2")
#eventlet.sleep()
#socketio.sleep(0)
class settings(object): class settings(object):
@@ -39,7 +66,6 @@ class settings(object):
class model_settings(settings): class model_settings(settings):
local_only_variables = ['badwordsids', 'apikey', '_class_init'] local_only_variables = ['badwordsids', 'apikey', '_class_init']
settings_name = "model" settings_name = "model"
__class_initialized = False
def __init__(self): def __init__(self):
self.model = "" # Model ID string chosen at startup self.model = "" # Model ID string chosen at startup
self.model_type = "" # Model Type (Automatically taken from the model config) self.model_type = "" # Model Type (Automatically taken from the model config)
@@ -75,26 +101,20 @@ class model_settings(settings):
self.presets = [] # Holder for presets self.presets = [] # Holder for presets
self.selected_preset = "" self.selected_preset = ""
#Must be at end of __init__
self.__class_initialized = True
def __setattr__(self, name, value): def __setattr__(self, name, value):
old_value = getattr(self, name, None) old_value = getattr(self, name, None)
super().__setattr__(name, value) super().__setattr__(name, value)
if self.__class_initialized and name != '__class_initialized': #Put variable change actions here
#Put variable change actions here if name not in self.local_only_variables and name[0] != "_":
if name not in self.local_only_variables and name[0] != "_": process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
#Since I haven't migrated the old_ui to use the new actions class for options, let's sync the metadata and options here
if name == 'actions_metadata':
print(value)
class story_settings(settings): class story_settings(settings):
#local_only_variables = ['generated_tkns']
local_only_variables = [] local_only_variables = []
settings_name = "story" settings_name = "story"
__class_initialized = False
def __init__(self): def __init__(self):
self.lastact = "" # The last action received from the user self.lastact = "" # The last action received from the user
self.submission = "" # Same as above, but after applying input formatting self.submission = "" # Same as above, but after applying input formatting
@@ -138,21 +158,17 @@ class story_settings(settings):
self.dynamicscan = False self.dynamicscan = False
self.recentedit = False self.recentedit = False
#Must be at end of __init__
self.__class_initialized = True
def __setattr__(self, name, value): def __setattr__(self, name, value):
old_value = getattr(self, name, None) old_value = getattr(self, name, None)
super().__setattr__(name, value) super().__setattr__(name, value)
if self.__class_initialized and name != '__class_initialized': #Put variable change actions here
#Put variable change actions here if name not in self.local_only_variables and name[0] != "_":
if name not in self.local_only_variables and name[0] != "_": process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
class user_settings(settings): class user_settings(settings):
local_only_variables = [] local_only_variables = []
settings_name = "user" settings_name = "user"
__class_initialized = False
def __init__(self): def __init__(self):
self.wirmvwhtsp = False # Whether to remove leading whitespace from WI entries self.wirmvwhtsp = False # Whether to remove leading whitespace from WI entries
self.widepth = 3 # How many historical actions to scan for WI hits self.widepth = 3 # How many historical actions to scan for WI hits
@@ -172,22 +188,18 @@ class user_settings(settings):
self.nogenmod = False self.nogenmod = False
self.debug = False # If set to true, will send debug information to the client for display self.debug = False # If set to true, will send debug information to the client for display
#Must be at end of __init__
self.__class_initialized = True
def __setattr__(self, name, value): def __setattr__(self, name, value):
old_value = getattr(self, name, None) old_value = getattr(self, name, None)
super().__setattr__(name, value) super().__setattr__(name, value)
if self.__class_initialized and name != '__class_initialized': #Put variable change actions here
#Put variable change actions here if name not in self.local_only_variables and name[0] != "_":
if name not in self.local_only_variables and name[0] != "_": process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
class system_settings(settings): class system_settings(settings):
local_only_variables = ['lua_state', 'lua_logname', 'lua_koboldbridge', 'lua_kobold', 'lua_koboldcore', 'regex_sl', 'acregex_ai', 'acregex_ui', 'comregex_ai', 'comregex_ui'] local_only_variables = ['lua_state', 'lua_logname', 'lua_koboldbridge', 'lua_kobold', 'lua_koboldcore', 'regex_sl', 'acregex_ai', 'acregex_ui', 'comregex_ai', 'comregex_ui']
settings_name = "system" settings_name = "system"
__class_initialized = False
def __init__(self): def __init__(self):
self.noai = False # Runs the script without starting up the transformers pipeline self.noai = False # Runs the script without starting up the transformers pipeline
self.aibusy = False # Stops submissions while the AI is working self.aibusy = False # Stops submissions while the AI is working
@@ -234,16 +246,13 @@ class system_settings(settings):
self.use_colab_tpu = os.environ.get("COLAB_TPU_ADDR", "") != "" or os.environ.get("TPU_NAME", "") != "" # Whether or not we're in a Colab TPU instance or Kaggle TPU instance and are going to use the TPU rather than the CPU self.use_colab_tpu = os.environ.get("COLAB_TPU_ADDR", "") != "" or os.environ.get("TPU_NAME", "") != "" # Whether or not we're in a Colab TPU instance or Kaggle TPU instance and are going to use the TPU rather than the CPU
self.aria2_port = 6799 #Specify the port on which aria2's RPC interface will be open if aria2 is installed (defaults to 6799) self.aria2_port = 6799 #Specify the port on which aria2's RPC interface will be open if aria2 is installed (defaults to 6799)
#Must be at end of __init__
self.__class_initialized = True
def __setattr__(self, name, value): def __setattr__(self, name, value):
old_value = getattr(self, name, None) old_value = getattr(self, name, None)
super().__setattr__(name, value) super().__setattr__(name, value)
if self.__class_initialized and name != '__class_initialized': #Put variable change actions here
#Put variable change actions here if name not in self.local_only_variables and name[0] != "_":
if name not in self.local_only_variables and name[0] != "_": process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
process_variable_changes(self.__class__.__name__.replace("_settings", ""), name, value, old_value)
class KoboldStoryRegister(object): class KoboldStoryRegister(object):
@@ -330,17 +339,10 @@ class KoboldStoryRegister(object):
self.action_count+=1 self.action_count+=1
if self.action_count in self.actions: if self.action_count in self.actions:
self.actions[self.action_count]["Selected Text"] = text self.actions[self.action_count]["Selected Text"] = text
print("looking for old option that matches")
for item in self.actions[self.action_count]["Options"]: for item in self.actions[self.action_count]["Options"]:
if item['text'] == text: if item['text'] == text:
print("found it")
old_options = self.actions[self.action_count]["Options"] old_options = self.actions[self.action_count]["Options"]
del item del item
print("old: ")
print(old_options)
print()
print("New: ")
print(self.actions[self.action_count]["Options"])
process_variable_changes("actions", "Options", {"id": self.action_count, "options": self.actions[self.action_count]["Options"]}, {"id": self.action_count, "options": old_options}) process_variable_changes("actions", "Options", {"id": self.action_count, "options": self.actions[self.action_count]["Options"]}, {"id": self.action_count, "options": old_options})
else: else:
@@ -348,25 +350,23 @@ class KoboldStoryRegister(object):
process_variable_changes("actions", "Selected Text", {"id": self.action_count, "text": text}, None) process_variable_changes("actions", "Selected Text", {"id": self.action_count, "text": text}, None)
def append_options(self, option_list): def append_options(self, option_list):
print("appending options for {}".format(self.action_count+1))
if self.action_count+1 in self.actions: if self.action_count+1 in self.actions:
print("1") old_options = self.actions[self.action_count+1]["Options"].copy()
old_options = self.actions[self.action_count+1]["Options"]
self.actions[self.action_count+1]['Options'].extend([{"text": x, "Pinned": False, "Previous Selection": False, "Edited": False} for x in option_list]) self.actions[self.action_count+1]['Options'].extend([{"text": x, "Pinned": False, "Previous Selection": False, "Edited": False} for x in option_list])
for item in option_list:
process_variable_changes("actions", "Options", {"id": self.action_count+1, "options": self.actions[self.action_count+1]["Options"]}, {"id": self.action_count+1, "options": old_options})
else: else:
print("2")
old_options = None old_options = None
self.actions[self.action_count+1] = {"Selected Text": "", "Options": [{"text": x, "Pinned": False, "Previous Selection": False, "Edited": False} for x in option_list]} self.actions[self.action_count+1] = {"Selected Text": "", "Options": [{"text": x, "Pinned": False, "Previous Selection": False, "Edited": False} for x in option_list]}
process_variable_changes("actions", "Options", {"id": self.action_count+1, "options": self.actions[self.action_count+1]["Options"]}, {"id": self.action_count+1, "options": old_options}) process_variable_changes("actions", "Options", {"id": self.action_count+1, "options": self.actions[self.action_count+1]["Options"]}, {"id": self.action_count+1, "options": old_options}, debug_message="wtf")
def clear_unused_options(self, pointer=None): def clear_unused_options(self, pointer=None):
print("clearing options for {}".format(self.action_count+1))
new_options = [] new_options = []
old_options = None old_options = None
if pointer is None: if pointer is None:
pointer = self.action_count+1 pointer = self.action_count+1
if pointer in self.actions: if pointer in self.actions:
old_options = self.actions[pointer]["Options"] old_options = self.actions[pointer]["Options"].copy()
self.actions[pointer]["Options"] = [x for x in self.actions[pointer]["Options"] if x["Pinned"] or x["Previous Selection"] or x["Edited"]] self.actions[pointer]["Options"] = [x for x in self.actions[pointer]["Options"] if x["Pinned"] or x["Previous Selection"] or x["Edited"]]
new_options = self.actions[pointer]["Options"] new_options = self.actions[pointer]["Options"]
process_variable_changes("actions", "Options", {"id": pointer, "options": new_options}, {"id": pointer, "options": old_options}) process_variable_changes("actions", "Options", {"id": pointer, "options": new_options}, {"id": pointer, "options": old_options})
@@ -382,20 +382,20 @@ class KoboldStoryRegister(object):
def set_pin(self, action_step, option_number): def set_pin(self, action_step, option_number):
if action_step in self.actions: if action_step in self.actions:
if option_number < len(self.actions[action_step]['Options']): if option_number < len(self.actions[action_step]['Options']):
old_options = self.actions[action_step]["Options"] old_options = self.actions[action_step]["Options"].copy()
self.actions[action_step]['Options'][option_number]['Pinned'] = True self.actions[action_step]['Options'][option_number]['Pinned'] = True
process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options}) process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options})
def unset_pin(self, action_step, option_number): def unset_pin(self, action_step, option_number):
if action_step in self.actions: if action_step in self.actions:
old_options = self.actions[action_step]["Options"] old_options = self.actions[action_step]["Options"].copy()
if option_number < len(self.actions[action_step]['Options']): if option_number < len(self.actions[action_step]['Options']):
self.actions[action_step]['Options'][option_number]['Pinned'] = False self.actions[action_step]['Options'][option_number]['Pinned'] = False
process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options}) process_variable_changes("actions", "Options", {"id": action_step, "options": self.actions[action_step]["Options"]}, {"id": action_step, "options": old_options})
def use_option(self, action_step, option_number): def use_option(self, action_step, option_number):
if action_step in self.actions: if action_step in self.actions:
old_options = self.actions[action_step]["Options"] old_options = self.actions[action_step]["Options"].copy()
old_text = self.actions[action_step]["Selected Text"] old_text = self.actions[action_step]["Selected Text"]
if option_number < len(self.actions[action_step]['Options']): if option_number < len(self.actions[action_step]['Options']):
self.actions[action_step]["Selected Text"] = self.actions[action_step]['Options'][option_number]['text'] self.actions[action_step]["Selected Text"] = self.actions[action_step]['Options'][option_number]['text']
@@ -405,7 +405,7 @@ class KoboldStoryRegister(object):
def delete_action(self, action_id): def delete_action(self, action_id):
if action_id in self.actions: if action_id in self.actions:
old_options = self.actions[action_id]["Options"] old_options = self.actions[action_id]["Options"].copy()
old_text = self.actions[action_id]["Selected Text"] old_text = self.actions[action_id]["Selected Text"]
self.actions[action_id]["Options"].append({"text": self.actions[action_id]["Selected Text"], "Pinned": False, "Previous Selection": True, "Edited": False}) self.actions[action_id]["Options"].append({"text": self.actions[action_id]["Selected Text"], "Pinned": False, "Previous Selection": True, "Edited": False})
self.actions[action_id]["Selected Text"] = "" self.actions[action_id]["Selected Text"] = ""
@@ -468,7 +468,7 @@ class KoboldStoryRegister(object):
return [] return []
else: else:
if self.action_count+1 in self.actions: if self.action_count+1 in self.actions:
return [[x, "pinned" if x['Pinned'] else 'normal'] for x in self.actions[self.action_count+1]["Options"] if x["Edited"] == False and x['Previous Selection'] == False] return [[x['text'], "pinned" if x['Pinned'] else 'normal'] for x in self.actions[self.action_count+1]["Options"] if x["Edited"] == False and x['Previous Selection'] == False]
else: else:
return [] return []
@@ -495,6 +495,12 @@ class KoboldStoryRegister(object):
return [x for x in self.actions[self.action_count+1]['Options'] if x['Pinned'] or x['Previous Selection']] return [x for x in self.actions[self.action_count+1]['Options'] if x['Pinned'] or x['Previous Selection']]
else: else:
return [] return []
def __setattr__(self, name, value):
old_value = getattr(self, name, None)
super().__setattr__(name, value)
if name == 'action_count':
process_variable_changes("actions", "Action Count", value, old_value)

View File

@@ -1359,7 +1359,6 @@ function setStartState() {
function parsegenseqs(seqs) { function parsegenseqs(seqs) {
seqselcontents.html(""); seqselcontents.html("");
console.log(seqs);
var i; var i;
for(i=0; i<seqs.length; i++) { for(i=0; i<seqs.length; i++) {
//setup selection data //setup selection data
@@ -2081,7 +2080,7 @@ $(document).ready(function(){
seqselcontents = $("#seqselcontents"); seqselcontents = $("#seqselcontents");
// Connect to SocketIO server // Connect to SocketIO server
socket = io.connect(window.document.origin, {transports: ['polling', 'websocket'], closeOnBeforeunload: false}); socket = io.connect(window.document.origin, {transports: ['polling', 'websocket'], closeOnBeforeunload: false, query:{"ui": "1"}});
socket.on('from_server', function(msg) { socket.on('from_server', function(msg) {
//console.log(msg); //console.log(msg);

View File

@@ -251,7 +251,7 @@
filter: brightness(85%); filter: brightness(85%);
} }
.settings_menu select { .settings_select {
color: black; color: black;
margin-left: auto; margin-left: auto;
margin-right: 25px; margin-right: 25px;
@@ -341,9 +341,9 @@ body {
/* grid-template-areas: "menuicon gamescreen lefticon" /* grid-template-areas: "menuicon gamescreen lefticon"
"menuicon actions lefticon" "menuicon actions lefticon"
"menuicon inputrow lefticon";*/ "menuicon inputrow lefticon";*/
grid-template-areas: "menuicon gamescreen lefticon" grid-template-areas: "menuicon gamescreen options lefticon"
"menuicon inputrow lefticon"; "menuicon inputrow inputrow lefticon";
grid-template-columns: 30px auto 20px; grid-template-columns: 30px auto fit-content(30%) 20px;
/* grid-template-rows: auto 40px 100px;*/ /* grid-template-rows: auto 40px 100px;*/
grid-template-rows: auto 100px; grid-template-rows: auto 100px;
} }
@@ -380,6 +380,11 @@ body {
color: var(--text_edit); color: var(--text_edit);
} }
.sequence {
margin-top: 10px;
grid-area: options;
background-color: var(--gamescreen_background);
}
table.sequence { table.sequence {
width: 100%; width: 100%;

View File

@@ -3,7 +3,9 @@ socket = io.connect(window.location.origin, {transports: ['polling', 'websocket'
//Let's register our server communications //Let's register our server communications
socket.on('connect', function(){connect();}); socket.on('connect', function(){connect();});
socket.on('disconnect', function(){disconnect();}); socket.on("disconnect", (reason, details) => {
console.log("Lost connection from: "+reason); // "transport error"
});
socket.on('reset_story', function(){reset_story();}); socket.on('reset_story', function(){reset_story();});
socket.on('var_changed', function(data){var_changed(data);}); socket.on('var_changed', function(data){var_changed(data);});
//socket.onAny(function(event_name, data) {console.log({"event": event_name, "data": data});}); //socket.onAny(function(event_name, data) {console.log({"event": event_name, "data": data});});
@@ -20,6 +22,7 @@ function disconnect() {
} }
function reset_story() { function reset_story() {
console.log("Resetting story");
var story_area = document.getElementById('Selected Text'); var story_area = document.getElementById('Selected Text');
while (story_area.firstChild) { while (story_area.firstChild) {
story_area.removeChild(story_area.firstChild); story_area.removeChild(story_area.firstChild);
@@ -43,7 +46,7 @@ function fix_text(val) {
} }
function create_options(data) { function create_options(data) {
console.log(data.value.options); console.log(data);
if (document.getElementById("Select Options Chunk "+data.value.id)) { if (document.getElementById("Select Options Chunk "+data.value.id)) {
var option_chunk = document.getElementById("Select Options Chunk "+data.value.id) var option_chunk = document.getElementById("Select Options Chunk "+data.value.id)
} else { } else {
@@ -200,7 +203,7 @@ function var_changed(data) {
} else { } else {
var elements_to_change = document.getElementsByClassName("var_sync_"+data.classname+"_"+data.name); var elements_to_change = document.getElementsByClassName("var_sync_"+data.classname+"_"+data.name);
for (item of elements_to_change) { for (item of elements_to_change) {
if (item.tagName.toLowerCase() === 'input') { if ((item.tagName.toLowerCase() === 'input') || (item.tagName.toLowerCase() === 'select')) {
item.value = fix_text(data.value); item.value = fix_text(data.value);
} else { } else {
item.textContent = fix_text(data.value); item.textContent = fix_text(data.value);

File diff suppressed because one or more lines are too long

View File

@@ -37,8 +37,9 @@
<span id="prompt" class="var_sync_story_prompt rawtext"></span> <span id="prompt" class="var_sync_story_prompt rawtext"></span>
<span id="Selected Text" class="rawtext"></span> <span id="Selected Text" class="rawtext"></span>
</div> </div>
<div id="selectoptions" class="sequence"></div>
</div> </div>
<!------------ Sequences --------------------->
<div id="Select Options" class="sequence"></div>
<!------------ Input Area---------------------> <!------------ Input Area--------------------->
<div class="inputrow"> <div class="inputrow">
<textarea id="input_text" placeholder="Enter text here"></textarea> <textarea id="input_text" placeholder="Enter text here"></textarea>
@@ -54,9 +55,7 @@
<!------------ Right Flyout Menu---------------------> <!------------ Right Flyout Menu--------------------->
<div id="rightSideMenu" class="rightSideMenu"> Status:<hr> <div id="rightSideMenu" class="rightSideMenu"> Status:<hr>
options:
<div id="Select Options"></div>
<br/>
</div> </div>
</body> </body>

View File

@@ -26,8 +26,8 @@
{% elif item["uitype"] == "toggle" %} {% elif item["uitype"] == "toggle" %}
<input type=checkbox id="{{ item['classname'] }}_{{ item['name'] }}" class="setting_item_input var_sync_{{ item['classname'] }}_{{ item['name'] }}" <input type=checkbox id="{{ item['classname'] }}_{{ item['name'] }}" class="setting_item_input var_sync_{{ item['classname'] }}_{{ item['name'] }}"
data-size="mini" data-onstyle="success" data-toggle="toggle" onchange='socket.emit("var_change", {"ID": this.id, "value": this.checked});'> data-size="mini" data-onstyle="success" data-toggle="toggle" onchange='socket.emit("var_change", {"ID": this.id, "value": this.checked});'>
{% elif item['uuitype'] == "dropdown" %} {% elif item['uitype'] == "dropdown" %}
<select id="{{ item['classname'] }}_{{ item['name'] }}" class="setting_item_input var_sync_{{ item['classname'] }}_{{ item['name'] }}" onclick='socket.emit("var_change", {"ID": this.id, "value": this.value});'> <select id="{{ item['classname'] }}_{{ item['name'] }}" class="settings_select var_sync_{{ item['classname'] }}_{{ item['name'] }}" onclick='socket.emit("var_change", {"ID": this.id, "value": this.value});'>
{% for option in item['children'] %} {% for option in item['children'] %}
<option value="{{ option['value'] }}">{{ option["text"] }}</option> <option value="{{ option['value'] }}">{{ option["text"] }}</option>
{% endfor %} {% endfor %}