BS12 -> Ponies merge

This commit is contained in:
ZomgPonies
2013-09-09 10:51:16 -04:00
parent b389395c0e
commit c1222034ee
125 changed files with 18129 additions and 1673 deletions
+205
View File
@@ -0,0 +1,205 @@
json_token
var
value
New(v)
src.value = v
text
number
word
symbol
eof
json_reader
var
list
string = list("'", "\"")
symbols = list("{", "}", "\[", "]", ":", "\"", "'", ",")
sequences = list("b" = 8, "t" = 9, "n" = 10, "f" = 12, "r" = 13)
tokens
json
i = 1
proc
// scanner
ScanJson(json)
src.json = json
. = new/list()
src.i = 1
while(src.i <= lentext(json))
var/char = get_char()
if(is_whitespace(char))
i++
continue
if(string.Find(char))
. += read_string(char)
else if(symbols.Find(char))
. += new/json_token/symbol(char)
else if(is_digit(char))
. += read_number()
else
. += read_word()
i++
. += new/json_token/eof()
read_word()
var/val = ""
while(i <= lentext(json))
var/char = get_char()
if(is_whitespace(char) || symbols.Find(char))
i-- // let scanner handle this character
return new/json_token/word(val)
val += char
i++
read_string(delim)
var
escape = FALSE
val = ""
while(++i <= lentext(json))
var/char = get_char()
if(escape)
switch(char)
if("\\", "'", "\"", "/", "u")
val += char
else
// TODO: support octal, hex, unicode sequences
ASSERT(sequences.Find(char))
val += ascii2text(sequences[char])
else
if(char == delim)
return new/json_token/text(val)
else if(char == "\\")
escape = TRUE
else
val += char
CRASH("Unterminated string.")
read_number()
var/val = ""
var/char = get_char()
while(is_digit(char) || char == "." || lowertext(char) == "e")
val += char
i++
char = get_char()
i-- // allow scanner to read the first non-number character
return new/json_token/number(text2num(val))
check_char()
ASSERT(args.Find(get_char()))
get_char()
return copytext(json, i, i+1)
is_whitespace(char)
return char == " " || char == "\t" || char == "\n" || text2ascii(char) == 13
is_digit(char)
var/c = text2ascii(char)
return 48 <= c && c <= 57 || char == "+" || char == "-"
// parser
ReadObject(list/tokens)
src.tokens = tokens
. = new/list()
i = 1
read_token("{", /json_token/symbol)
while(i <= tokens.len)
var/json_token/K = get_token()
check_type(/json_token/word, /json_token/text)
next_token()
read_token(":", /json_token/symbol)
.[K.value] = read_value()
var/json_token/S = get_token()
check_type(/json_token/symbol)
switch(S.value)
if(",")
next_token()
continue
if("}")
next_token()
return
else
die()
get_token()
return tokens[i]
next_token()
return tokens[++i]
read_token(val, type)
var/json_token/T = get_token()
if(!(T.value == val && istype(T, type)))
CRASH("Expected '[val]', found '[T.value]'.")
next_token()
return T
check_type(...)
var/json_token/T = get_token()
for(var/type in args)
if(istype(T, type))
return
CRASH("Bad token type: [T.type].")
check_value(...)
var/json_token/T = get_token()
ASSERT(args.Find(T.value))
read_key()
var/char = get_char()
if(char == "\"" || char == "'")
return read_string(char)
read_value()
var/json_token/T = get_token()
switch(T.type)
if(/json_token/text, /json_token/number)
next_token()
return T.value
if(/json_token/word)
next_token()
switch(T.value)
if("true")
return TRUE
if("false")
return FALSE
if("null")
return null
if(/json_token/symbol)
switch(T.value)
if("\[")
return read_array()
if("{")
return ReadObject(tokens.Copy(i))
die()
read_array()
read_token("\[", /json_token/symbol)
. = new/list()
var/list/L = .
while(i <= tokens.len)
// Avoid using Add() or += in case a list is returned.
L.len++
L[L.len] = read_value()
var/json_token/T = get_token()
check_type(/json_token/symbol)
switch(T.value)
if(",")
next_token()
continue
if("]")
next_token()
return
else
die()
next_token()
CRASH("Unterminated array.")
die(json_token/T)
if(!T) T = get_token()
CRASH("Unexpected token: [T.value].")
+54
View File
@@ -0,0 +1,54 @@
json_writer
proc
WriteObject(list/L)
. = "{"
var/i = 1
for(var/k in L)
var/val = L[k]
. += {"\"[k]\":[write(val)]"}
if(i++ < L.len)
. += ","
.+= "}"
write(val)
if(isnum(val))
return num2text(val, 100)
else if(isnull(val))
return "null"
else if(istype(val, /list))
if(is_associative(val))
return WriteObject(val)
else
return write_array(val)
else
. += write_string("[val]")
write_array(list/L)
. = "\["
for(var/i = 1 to L.len)
. += write(L[i])
if(i < L.len)
. += ","
. += "]"
write_string(txt)
var/static/list/json_escape = list("\\", "\"", "'", "\n")
for(var/targ in json_escape)
var/start = 1
while(start <= lentext(txt))
var/i = findtext(txt, targ, start)
if(!i)
break
if(targ == "\n")
txt = copytext(txt, 1, i) + "\\n" + copytext(txt, i+1)
else
txt = copytext(txt, 1, i) + "\\" + copytext(txt, i)
start = i + 2
return {""[txt]""}
is_associative(list/L)
for(var/key in L)
// if the key is a list that means it's actually an array of lists (stupid Byond...)
if(!isnum(key) && !istype(key, /list))
return TRUE
+12
View File
@@ -0,0 +1,12 @@
/*
n_Json v11.3.21
*/
proc
json2list(json)
var/static/json_reader/_jsonr = new()
return _jsonr.ReadObject(_jsonr.ScanJson(json))
list2json(list/L)
var/static/json_writer/_jsonw = new()
return _jsonw.WriteObject(L)
+6
View File
@@ -0,0 +1,6 @@
// All movable things can have a Nano UI, always use ui_interact to open/interact with a Nano UI
/atom/movable/proc/ui_interact(mob/user, ui_key = "main")
return
// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
/mob/var/list/open_uis = list()
+69
View File
@@ -0,0 +1,69 @@
// This is the window/UI manager for Nano UI
// There should only ever be one (global) instance of nanomanger
/datum/nanomanager
var/open_uis[0]
var/list/processing_uis = list()
/datum/nanomanager/New()
return
/datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return null
else if (isnull(open_uis[src_object_key][ui_key]) || !istype(open_uis[src_object_key][ui_key], /list))
return null
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if (ui.user == user)
return ui
return null
/datum/nanomanager/proc/update_uis(src_object)
var/src_object_key = "\ref[src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0
var/update_count = 0
for (var/ui_key in open_uis[src_object_key])
for (var/datum/nanoui/ui in open_uis[src_object_key][ui_key])
if(ui && ui.src_object && ui.user)
ui.process()
update_count++
return update_count
/datum/nanomanager/proc/ui_opened(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
open_uis[src_object_key] = list(ui.ui_key = list())
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
open_uis[src_object_key][ui.ui_key] = list();
ui.user.open_uis.Add(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
uis.Add(ui)
processing_uis.Add(ui)
/datum/nanomanager/proc/ui_closed(var/datum/nanoui/ui)
var/src_object_key = "\ref[ui.src_object]"
if (isnull(open_uis[src_object_key]) || !istype(open_uis[src_object_key], /list))
return 0 // wasn't open
else if (isnull(open_uis[src_object_key][ui.ui_key]) || !istype(open_uis[src_object_key][ui.ui_key], /list))
return 0 // wasn't open
processing_uis.Remove(ui)
ui.user.open_uis.Remove(ui)
var/list/uis = open_uis[src_object_key][ui.ui_key]
return uis.Remove(ui)
// user has logged out (or is switching mob) so close/clear all uis
/datum/nanomanager/proc/user_logout(var/mob/user)
if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
return 0 // has no open uis
for (var/datum/nanoui/ui in user.open_uis)
ui.close();
+251
View File
@@ -0,0 +1,251 @@
/datum/nanoui
var/mob/user
var/atom/movable/src_object
var/title
var/ui_key
var/window_id // window_id is used as the window name for browse and onclose
var/width = 0
var/height = 0
var/atom/ref = null
var/on_close_logic = 1
var/window_options = "focus=0;can_close=1;can_minimize=1;can_maximize=0;can_resize=1;titlebar=1;" // window option is set using window_id
var/list/stylesheets = list()
var/list/scripts = list()
var/templates[0]
var/title_image
var/head_elements
var/body_elements
var/head_content = ""
var/content = "<div id='mainTemplate'></div>" // the #mainTemplate div will contain the compiled "main" template html
var/list/initial_data[0]
var/is_auto_updating = 0
var/status = 2
/datum/nanoui/New(nuser, nsrc_object, nui_key, ntemplate, ntitle = 0, nwidth = 0, nheight = 0, var/atom/nref = null)
user = nuser
src_object = nsrc_object
ui_key = nui_key
window_id = "[ui_key]\ref[src_object]"
add_template("main", ntemplate)
if (ntitle)
title = ntitle
if (nwidth)
width = nwidth
if (nheight)
height = nheight
if (nref)
ref = nref
add_common_assets()
/datum/nanoui/proc/add_common_assets()
add_script("libraries.min.js") // The jQuery library
add_script("nano_update.js") // The NanoUpdate JS, this is used to receive updates and apply them.
add_script("nano_config.js") // The NanoUpdate JS, this is used to receive updates and apply them.
add_script("nano_base_helpers.js") // The NanoBaseHelpers JS, this is used to set up template helpers which are common to all templates
add_stylesheet("shared.css") // this CSS sheet is common to all UIs
add_stylesheet("icons.css") // this CSS sheet is common to all UIs
/datum/nanoui/proc/set_status(state)
if (state != status)
status = state
push_data(list(), 1) // Update the UI
else
status = state
/datum/nanoui/proc/set_auto_update(state = 1)
is_auto_updating = state
/datum/nanoui/proc/set_initial_data(data)
initial_data = modify_data(data)
/datum/nanoui/proc/add_head_content(nhead_content)
head_content = nhead_content
/datum/nanoui/proc/set_window_options(nwindow_options)
window_options = nwindow_options
/datum/nanoui/proc/set_title_image(ntitle_image)
//title_image = ntitle_image
/datum/nanoui/proc/add_stylesheet(file)
stylesheets.Add(file)
/datum/nanoui/proc/add_script(file)
scripts.Add(file)
/datum/nanoui/proc/add_template(name, file)
templates[name] = file
/datum/nanoui/proc/set_content(ncontent)
content = ncontent
/datum/nanoui/proc/add_content(ncontent)
content += ncontent
/datum/nanoui/proc/use_on_close_logic(nsetting)
on_close_logic = nsetting
/datum/nanoui/proc/get_header()
for (var/filename in stylesheets)
head_content += "<link rel='stylesheet' type='text/css' href='[filename]'>"
var/title_attributes = "id='uiTitle'"
if (title_image)
title_attributes = "id='uiTitle icon' style='background-image: url([title_image]);'"
var/templatel_data[0]
for (var/key in templates)
templatel_data[key] = templates[key];
var/template_data_json = "{}" // An empty JSON object
if (templatel_data.len > 0)
template_data_json = list2json(templatel_data)
var/initial_data_json = "{}" // An empty JSON object
if (initial_data.len > 0)
initial_data_json = list2json(initial_data)
var/url_parameters_json = list2json(list("src" = "\ref[src_object]"))
return {"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<head>
[head_content]
</head>
<body scroll=auto data-url-parameters='[url_parameters_json]' data-template-data='[template_data_json]' data-initial-data='[initial_data_json]'>
<script type='text/javascript'>
function receiveUpdateData(jsonString)
{
// We need both jQuery and NanoUpdate to be able to recieve data
if (typeof NanoUpdate != 'undefined' && typeof jQuery != 'undefined')
{
NanoUpdate.receiveUpdateData(jsonString);
}
else
{
alert('receiveUpdateData error: something is not defined!');
if (typeof NanoUpdate == 'undefined')
{
alert('NanoUpdate not defined!');
}
if (typeof jQuery == 'undefined')
{
alert('jQuery not defined!');
}
}
// At the moment any data received before those libraries are loaded will be lost
}
</script>
<div id='uiWrapper'>
[title ? "<div id='uiTitleWrapper'><div id='uiStatusIcon' class='icon24 uiStatusGood'></div><div [title_attributes]>[title]</div><div id='uiTitleFluff'></div></div>" : ""]
<div id='uiContent'>
"}
/datum/nanoui/proc/get_footer()
var/scriptsContent = ""
for (var/filename in scripts)
scriptsContent += "<script type='text/javascript' src='[filename]'></script>"
return {"
[scriptsContent]
</div>
</div>
</body>
</html>"}
/datum/nanoui/proc/get_content()
return {"
[get_header()]
[content]
[get_footer()]
"}
/datum/nanoui/proc/open()
var/window_size = ""
if (width && height)
window_size = "size=[width]x[height];"
user << browse(get_content(), "window=[window_id];[window_size][window_options]")
on_close_winset()
//onclose(user, window_id)
nanomanager.ui_opened(src)
/datum/nanoui/proc/close()
is_auto_updating = 0
nanomanager.ui_closed(src)
user << browse(null, "window=[window_id]")
/datum/nanoui/proc/on_close_winset()
if(!user.client)
world << "ERROR: No user.client!?"
return
var/params = "\ref[src]"
winset(user, window_id, "on-close=\"nanoclose [params]\"")
/datum/nanoui/proc/process(update = 0)
var/dist = get_dist(src_object, user)
if (dist <= 1)
set_status(2) // interactive
else if (dist <= 2)
set_status(1) // update only
else if (dist <= 3)
set_status(0) // no updates, completely disabled
return // don't auto update
else
close()
return
if (update || is_auto_updating)
src_object.ui_interact(user, ui_key)
/datum/nanoui/proc/modify_data(data)
data["ui"] = list(
"status" = status,
"user" = list("name" = user.name)
)
//user << list2json(data)
return data
/datum/nanoui/proc/push_data(data, force_push = 0)
if (!status && !force_push)
user << "Cannot update UI, user out of range (status [status])"
return
data = modify_data(data)
user << output(list2params(list(list2json(data))),"[window_id].browser:receiveUpdateData")
on_close_winset()
/client/verb/nanoclose(var/uiref as text)
set hidden = 1 // hide this verb from the user's panel
set name = "nanoclose" // no autocomplete on cmd line
//world << "world [src] looking for [uiref]"
var/datum/nanoui/ui = locate(uiref)
if (ui)
//world << "[src] UI found [ui.window_id]"
ui.close()
if (ui.on_close_logic)
if(ui.ref)
var/href = "close=1"
//world << "[src] Topic [href] [ui.ref]"
src.Topic(href, params2list(href), ui.ref) // this will direct to the atom's
// Topic() proc via client.Topic()
else
// no atomref specified (or not found)
// so just reset the user mob's machine var
if(src && src.mob)
//world << "[src] was [src.mob.machine], setting to null"
src.mob.unset_machine()
else
world << "[src] UI not found"
return