mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2025-12-20 07:12:55 +00:00
Autocomplete input for ghost buttons
This commit is contained in:
@@ -353,12 +353,12 @@
|
|||||||
var/middle = L.len / 2 + 1 // Copy is first,second-1
|
var/middle = L.len / 2 + 1 // Copy is first,second-1
|
||||||
return mergeLists(sortList(L.Copy(0,middle)), sortList(L.Copy(middle))) //second parameter null = to end of list
|
return mergeLists(sortList(L.Copy(0,middle)), sortList(L.Copy(middle))) //second parameter null = to end of list
|
||||||
|
|
||||||
//Mergsorge: uses sortList() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
//Mergsorge: uses sortAssoc() but uses the var's name specifically. This should probably be using mergeAtom() instead
|
||||||
/proc/sortNames(var/list/L)
|
/proc/sortNames(var/list/L)
|
||||||
var/list/Q = new()
|
var/list/Q = new()
|
||||||
for(var/atom/x in L)
|
for(var/atom/x in L)
|
||||||
Q[x.name] = x
|
Q[x.name] = x
|
||||||
return sortList(Q)
|
return sortAssoc(Q)
|
||||||
|
|
||||||
/proc/mergeLists(var/list/L, var/list/R)
|
/proc/mergeLists(var/list/L, var/list/R)
|
||||||
var/Li=1
|
var/Li=1
|
||||||
|
|||||||
@@ -1,71 +1,90 @@
|
|||||||
/proc/input_async(mob/user=usr, prompt, list/choices)
|
/proc/input_async(mob/user=usr, prompt, list/choices)
|
||||||
var/datum/async_input/A = new(choices, prompt)
|
var/datum/async_input/A = new(choices, prompt, , user)
|
||||||
A.show(user)
|
A.show()
|
||||||
return A
|
return A
|
||||||
|
|
||||||
/proc/input_ranked_async(mob/user=usr, prompt="Order by greatest to least preference", list/choices)
|
/proc/input_ranked_async(mob/user=usr, prompt="Order by greatest to least preference", list/choices)
|
||||||
var/datum/async_input/ranked/A = new(choices, prompt)
|
var/datum/async_input/ranked/A = new(choices, prompt, "ranked_input", user)
|
||||||
A.show(user)
|
A.show()
|
||||||
|
return A
|
||||||
|
|
||||||
|
/proc/input_autocomplete_async(mob/user=usr, prompt="Enter text: ", list/choices)
|
||||||
|
var/datum/async_input/autocomplete/A = new(choices, prompt, "ac_input", user)
|
||||||
|
A.show()
|
||||||
return A
|
return A
|
||||||
|
|
||||||
/datum/async_input
|
/datum/async_input
|
||||||
var/datum/browser/popup
|
var/datum/browser/popup
|
||||||
|
// If associative list, key will be used for display, but the final result will be the value
|
||||||
var/list/choices
|
var/list/choices
|
||||||
|
var/datum/callback/onCloseCb
|
||||||
var/flash = TRUE
|
var/flash = TRUE
|
||||||
var/immediate_submit = FALSE
|
var/immediate_submit = FALSE
|
||||||
var/prompt
|
var/prompt
|
||||||
var/result = null
|
var/result = null
|
||||||
var/style = "text-align: center;"
|
var/style = "text-align: center;"
|
||||||
|
var/mob/user
|
||||||
var/window_id
|
var/window_id
|
||||||
var/height = 200
|
var/height = 200
|
||||||
var/width = 400
|
var/width = 400
|
||||||
|
|
||||||
/datum/async_input/New(list/new_choices, new_prompt="Pick an option:", new_window_id="async_input")
|
/datum/async_input/New(list/new_choices, new_prompt="Pick an option:", new_window_id="async_input", mob/new_user=usr)
|
||||||
choices = new_choices
|
choices = new_choices
|
||||||
prompt = new_prompt
|
prompt = new_prompt
|
||||||
window_id = new_window_id
|
window_id = new_window_id
|
||||||
|
user = new_user
|
||||||
|
popup = new(user, window_id, , width, height, src)
|
||||||
|
|
||||||
/datum/async_input/proc/close()
|
/datum/async_input/proc/close()
|
||||||
if(popup)
|
if(popup)
|
||||||
popup.close()
|
popup.close()
|
||||||
|
if(result && choices[result])
|
||||||
|
result = choices[result]
|
||||||
|
if(onCloseCb)
|
||||||
|
onCloseCb.Invoke(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
/datum/async_input/proc/show(mob/user)
|
// Callback function should take the result as the last argument
|
||||||
var/dat = create_ui(user)
|
/datum/async_input/proc/on_close(var/datum/callback/cb)
|
||||||
popup = new(user, window_id, , width, height, src)
|
onCloseCb = cb
|
||||||
popup.set_content(dat)
|
|
||||||
|
/datum/async_input/proc/show()
|
||||||
|
popup.set_content(create_ui())
|
||||||
if(flash && result == null)
|
if(flash && result == null)
|
||||||
window_flash(user.client)
|
window_flash(user.client)
|
||||||
popup.open()
|
popup.open()
|
||||||
|
|
||||||
/datum/async_input/proc/create_ui(mob/user)
|
/datum/async_input/proc/create_ui()
|
||||||
var/dat = "<div style=\"[style]\">"
|
var/dat = "<div style=\"[style]\">"
|
||||||
dat += render_prompt(user)
|
dat += render_prompt()
|
||||||
dat += render_choices(user)
|
dat += render_choices()
|
||||||
dat += "<br>"
|
dat += "<br>"
|
||||||
dat += "<br>"
|
dat += "<br>"
|
||||||
dat += button("Submit", "submit=1", , result == null && !immediate_submit)
|
dat += render_buttons()
|
||||||
dat += "</div>"
|
dat += "</div>"
|
||||||
return dat
|
return dat
|
||||||
|
|
||||||
/datum/async_input/proc/render_prompt(mob/user)
|
/datum/async_input/proc/render_prompt()
|
||||||
return "<h2>[prompt]</h2>"
|
return "<h2>[prompt]</h2>"
|
||||||
|
|
||||||
/datum/async_input/proc/render_choices(mob/user)
|
/datum/async_input/proc/render_choices()
|
||||||
var/dat = " "
|
var/dat = " "
|
||||||
for(var/choice in choices)
|
for(var/choice in choices)
|
||||||
dat += button(choice, "choice=[choice]", choice == result)
|
dat += button(choice, "choice=[choice]", choice == result)
|
||||||
dat += " "
|
dat += " "
|
||||||
return dat
|
return dat
|
||||||
|
|
||||||
/datum/async_input/proc/button(label, topic, on=FALSE, disabled=FALSE)
|
/datum/async_input/proc/render_buttons()
|
||||||
|
return button("Submit", "submit=1", , result == null && !immediate_submit)
|
||||||
|
|
||||||
|
/datum/async_input/proc/button(label, topic, on=FALSE, disabled=FALSE, id="")
|
||||||
var/class = ""
|
var/class = ""
|
||||||
if(on)
|
if(on)
|
||||||
class = "linkOn"
|
class = "linkOn"
|
||||||
if(disabled)
|
if(disabled)
|
||||||
class = "linkOff"
|
class = "linkOff"
|
||||||
topic = ""
|
topic = ""
|
||||||
return "<a class=\"[class]\" href='?src=[UID()];[topic]'>[label]</a>"
|
return "<a class=\"[class]\" id='[id]' href='?src=[UID()];[topic]'>[label]</a>"
|
||||||
|
|
||||||
/datum/async_input/Topic(href, href_list)
|
/datum/async_input/Topic(href, href_list)
|
||||||
if(href_list["submit"] || href_list["close"])
|
if(href_list["submit"] || href_list["close"])
|
||||||
@@ -74,14 +93,14 @@
|
|||||||
|
|
||||||
if(href_list["choice"])
|
if(href_list["choice"])
|
||||||
result = href_list["choice"]
|
result = href_list["choice"]
|
||||||
show(usr)
|
show()
|
||||||
return
|
return
|
||||||
|
|
||||||
/datum/async_input/ranked
|
/datum/async_input/ranked
|
||||||
height = 400
|
height = 400
|
||||||
immediate_submit = TRUE
|
immediate_submit = TRUE
|
||||||
|
|
||||||
/datum/async_input/ranked/render_choices(mob/user)
|
/datum/async_input/ranked/render_choices()
|
||||||
var/dat = "<div>"
|
var/dat = "<div>"
|
||||||
dat += "<table style='margin: auto; text-align: left;'>"
|
dat += "<table style='margin: auto; text-align: left;'>"
|
||||||
for(var/i = 1, i <= choices.len, i++)
|
for(var/i = 1, i <= choices.len, i++)
|
||||||
@@ -103,13 +122,47 @@
|
|||||||
if(href_list["upvote"])
|
if(href_list["upvote"])
|
||||||
var/index = text2num(href_list["upvote"])
|
var/index = text2num(href_list["upvote"])
|
||||||
choices.Swap(index, index - 1)
|
choices.Swap(index, index - 1)
|
||||||
show(usr)
|
show()
|
||||||
return
|
return
|
||||||
|
|
||||||
if(href_list["downvote"])
|
if(href_list["downvote"])
|
||||||
var/index = text2num(href_list["downvote"])
|
var/index = text2num(href_list["downvote"])
|
||||||
choices.Swap(index, index + 1)
|
choices.Swap(index, index + 1)
|
||||||
show(usr)
|
show()
|
||||||
|
return
|
||||||
|
|
||||||
|
..()
|
||||||
|
|
||||||
|
/datum/async_input/autocomplete
|
||||||
|
immediate_submit = TRUE
|
||||||
|
height = 150
|
||||||
|
|
||||||
|
/datum/async_input/autocomplete/New()
|
||||||
|
..()
|
||||||
|
popup.add_script("autocomplete.js", 'html/browser/autocomplete.js')
|
||||||
|
|
||||||
|
/datum/async_input/autocomplete/render_prompt()
|
||||||
|
return "<label for='input'>[prompt]</label>"
|
||||||
|
|
||||||
|
/datum/async_input/autocomplete/render_choices()
|
||||||
|
var/dat = "<input list='choices' id='input' name='choices' oninput='updateTopic()' />"
|
||||||
|
dat += "<datalist id='choices'>"
|
||||||
|
for(var/choice in choices)
|
||||||
|
dat += "<option value='[choice]'>"
|
||||||
|
dat += "</datalist>"
|
||||||
|
return dat
|
||||||
|
|
||||||
|
/datum/async_input/autocomplete/render_buttons()
|
||||||
|
var/dat = button("Submit", "", , result == null && !immediate_submit, "submit-button")
|
||||||
|
dat += button("Cancel", "close=1")
|
||||||
|
return dat
|
||||||
|
|
||||||
|
/datum/async_input/autocomplete/Topic(href, href_list)
|
||||||
|
if(href_list["submit"])
|
||||||
|
// Entering an invalid choice is the same as canceling
|
||||||
|
if(href_list["submit"] in choices)
|
||||||
|
result = href_list["submit"]
|
||||||
|
close()
|
||||||
return
|
return
|
||||||
|
|
||||||
..()
|
..()
|
||||||
|
|||||||
@@ -397,9 +397,10 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
|||||||
to_chat(usr, "Not when you're not dead!")
|
to_chat(usr, "Not when you're not dead!")
|
||||||
return
|
return
|
||||||
|
|
||||||
var/area/A = input("Area to jump to", "BOOYEA") as null|anything in ghostteleportlocs
|
var/datum/async_input/A = input_autocomplete_async(usr, "Area to jump to: ", ghostteleportlocs)
|
||||||
var/area/thearea = ghostteleportlocs[A]
|
A.on_close(CALLBACK(src, .proc/teleport))
|
||||||
|
|
||||||
|
/mob/dead/observer/proc/teleport(area/thearea)
|
||||||
if(!thearea)
|
if(!thearea)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -420,9 +421,8 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
|||||||
set desc = "Follow and orbit a mob."
|
set desc = "Follow and orbit a mob."
|
||||||
|
|
||||||
var/list/mobs = getpois(skip_mindless=1)
|
var/list/mobs = getpois(skip_mindless=1)
|
||||||
var/input = input("Please, select a mob!", "Haunt", null, null) as null|anything in mobs
|
var/datum/async_input/A = input_autocomplete_async(usr, "Please, select a mob: ", mobs)
|
||||||
var/mob/target = mobs[input]
|
A.on_close(CALLBACK(src, .proc/ManualFollow))
|
||||||
ManualFollow(target)
|
|
||||||
|
|
||||||
// This is the ghost's follow verb with an argument
|
// This is the ghost's follow verb with an argument
|
||||||
/mob/dead/observer/proc/ManualFollow(var/atom/movable/target)
|
/mob/dead/observer/proc/ManualFollow(var/atom/movable/target)
|
||||||
@@ -495,24 +495,20 @@ This is the proc mobs get to turn into a ghost. Forked from ghostize due to comp
|
|||||||
set desc = "Teleport to a mob"
|
set desc = "Teleport to a mob"
|
||||||
|
|
||||||
if(isobserver(usr)) //Make sure they're an observer!
|
if(isobserver(usr)) //Make sure they're an observer!
|
||||||
var/list/dest = list() //List of possible destinations (mobs)
|
var/list/dest = getpois(mobs_only=1) //Fill list, prompt user with list
|
||||||
var/target = null //Chosen target.
|
var/datum/async_input/A = input_autocomplete_async(usr, "Enter a mob name: ", dest)
|
||||||
|
A.on_close(CALLBACK(src, .proc/jump_to_mob))
|
||||||
|
|
||||||
dest += getpois(mobs_only=1) //Fill list, prompt user with list
|
/mob/dead/observer/proc/jump_to_mob(mob/M)
|
||||||
target = input("Please, select a mob!", "Jump to Mob", null, null) as null|anything in dest
|
if(!M)
|
||||||
|
return
|
||||||
if(!target) //Make sure we actually have a target
|
var/mob/A = src //Source mob
|
||||||
return
|
var/turf/T = get_turf(M) //Turf of the destination mob
|
||||||
else
|
|
||||||
var/mob/M = dest[target] //Destination mob
|
|
||||||
var/mob/A = src //Source mob
|
|
||||||
var/turf/T = get_turf(M) //Turf of the destination mob
|
|
||||||
|
|
||||||
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
|
|
||||||
A.forceMove(T)
|
|
||||||
else
|
|
||||||
to_chat(A, "This mob is not located in the game world.")
|
|
||||||
|
|
||||||
|
if(T && isturf(T)) //Make sure the turf exists, then move the source to that destination.
|
||||||
|
A.forceMove(T)
|
||||||
|
return
|
||||||
|
to_chat(A, "This mob is not located in the game world.")
|
||||||
|
|
||||||
/* Now a spell. See spells.dm
|
/* Now a spell. See spells.dm
|
||||||
/mob/dead/observer/verb/boo()
|
/mob/dead/observer/verb/boo()
|
||||||
|
|||||||
61
html/browser/autocomplete.js
Normal file
61
html/browser/autocomplete.js
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
var $ = document.querySelector.bind(document);
|
||||||
|
var input;
|
||||||
|
var submitButton;
|
||||||
|
var optionsMap = {};
|
||||||
|
|
||||||
|
function updateTopic() {
|
||||||
|
if (!input || !submitButton) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var hrefList = submitButton.getAttribute('href').split(';');
|
||||||
|
// Topic must come last in the submit button for this to work
|
||||||
|
hrefList = hrefList.slice(0, hrefList.length - 1);
|
||||||
|
hrefList.push(optionsMap[input.value] ? 'submit=' + optionsMap[input.value] : '');
|
||||||
|
submitButton.setAttribute('href', hrefList.join(';'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function clean(name) {
|
||||||
|
// \improper shows up as 2 characters outside of ascii range
|
||||||
|
if (name.charCodeAt(0) > 127) {
|
||||||
|
return name.slice(2);
|
||||||
|
}
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setElements() {
|
||||||
|
input = $('#input');
|
||||||
|
submitButton = $('#submit-button');
|
||||||
|
var choices = $('#choices');
|
||||||
|
|
||||||
|
if (!input || !submitButton || !choices) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (var i = 0; i < choices.options.length; i++) {
|
||||||
|
var name = choices.options[i].value;
|
||||||
|
var cleaned = clean(name);
|
||||||
|
optionsMap[cleaned] = name;
|
||||||
|
choices.options[i].value = cleaned;
|
||||||
|
}
|
||||||
|
|
||||||
|
input.addEventListener('keyup', function(event) {
|
||||||
|
if (event.key !== 'Enter') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(optionsMap).indexOf(input.value) === -1) {
|
||||||
|
// Byond doesn't let you to use enter to select
|
||||||
|
// so we need to prevent unintended submissions
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
submitButton.click();
|
||||||
|
event.preventDefault();
|
||||||
|
});
|
||||||
|
|
||||||
|
input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = setElements;
|
||||||
Reference in New Issue
Block a user