diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 400d6961ae7..1ab93c49bad 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -239,25 +239,35 @@ var/list/blood_splatter_icons = list()
/atom/proc/blood_splatter_index()
return "\ref[initial(icon)]-[initial(icon_state)]"
+/atom/proc/add_blood_list(mob/living/carbon/M)
+ // Returns 1 if we had blood already
+ if(!istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it.
+ blood_DNA = list()
+ //if this blood isn't already in the list, add it
+ if(blood_DNA[M.dna.unique_enzymes])
+ return 0 //already bloodied with this blood. Cannot add more.
+ blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
+ return 1
+
//returns 1 if made bloody, returns 0 otherwise
/atom/proc/add_blood(mob/living/carbon/M)
if(rejects_blood())
return 0
- if(!initial(icon) || !initial(icon_state))
- return 0
if(!istype(M))
return 0
if(!check_dna_integrity(M)) //check dna is valid and create/setup if necessary
return 0 //no dna!
- if(!istype(blood_DNA, /list)) //if our list of DNA doesn't exist yet (or isn't a list) initialise it.
- blood_DNA = list()
return
-/obj/item/add_blood(mob/living/carbon/M)
- if(..() == 0) return 0
+/obj/add_blood(mob/living/carbon/M)
+ if(..() == 0) return 0
+ return add_blood_list(M)
+/obj/item/add_blood(mob/living/carbon/M)
+ var/blood_count = blood_DNA == null ? 0 : blood_DNA.len
+ if(..() == 0) return 0
//apply the blood-splatter overlay if it isn't already in there
- if(!blood_DNA.len)
+ if(!blood_count && initial(icon) && initial(icon_state))
//try to find a pre-processed blood-splatter. otherwise, make a new one
var/index = blood_splatter_index()
var/icon/blood_splatter_icon = blood_splatter_icons[index]
@@ -268,11 +278,6 @@ var/list/blood_splatter_icons = list()
blood_splatter_icon = fcopy_rsc(blood_splatter_icon)
blood_splatter_icons[index] = blood_splatter_icon
overlays += blood_splatter_icon
-
- //if this blood isn't already in the list, add it
- if(blood_DNA[M.dna.unique_enzymes])
- return 0 //already bloodied with this blood. Cannot add more.
- blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
return 1 //we applied blood to the item
/turf/simulated/add_blood(mob/living/carbon/M)
@@ -280,15 +285,12 @@ var/list/blood_splatter_icons = list()
var/obj/effect/decal/cleanable/blood/B = locate() in contents //check for existing blood splatter
if(!B) B = new /obj/effect/decal/cleanable/blood(src) //make a bloood splatter if we couldn't find one
- B.blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
+ B.add_blood_list(M)
return 1 //we bloodied the floor
/mob/living/carbon/human/add_blood(mob/living/carbon/M)
if(..() == 0) return 0
-
- if(blood_DNA[M.dna.unique_enzymes])
- return 0 //already bloodied with this blood. Cannot add more.
- blood_DNA[M.dna.unique_enzymes] = M.dna.blood_type
+ add_blood_list(M)
update_inv_gloves() //handles bloody hands overlays and updating
return 1 //we applied blood to the item
diff --git a/code/game/machinery/cryo.dm b/code/game/machinery/cryo.dm
index c8498e2bdd2..c3ab2b9b429 100644
--- a/code/game/machinery/cryo.dm
+++ b/code/game/machinery/cryo.dm
@@ -94,7 +94,7 @@
*
* @return nothing
*/
-/obj/machinery/atmospherics/unary/cryo_cell/ui_interact(mob/user, ui_key = "main")
+/obj/machinery/atmospherics/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
if(user == occupant || user.stat)
return
@@ -141,20 +141,20 @@
for(var/datum/reagent/R in beaker:reagents.reagent_list)
beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
-
- var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
if (!ui)
- // the ui does not exist, so we'll create a new one
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 410)
- // When the UI is first opened this is the data it will use
- ui.set_initial_data(data)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
ui.open()
- // Auto update every Master Controller tick
+ // auto update every Master Controller tick
ui.set_auto_update(1)
- else
- // The UI is already open so push the new data to it
- ui.push_data(data)
- return
+
//user.set_machine(src)
/obj/machinery/atmospherics/unary/cryo_cell/Topic(href, href_list)
diff --git a/code/game/machinery/recycler.dm b/code/game/machinery/recycler.dm
index 5d111fa7cdf..466a2f52338 100644
--- a/code/game/machinery/recycler.dm
+++ b/code/game/machinery/recycler.dm
@@ -12,7 +12,7 @@ var/const/SAFETY_COOLDOWN = 100
var/grinding = 0
var/icon_name = "grinder-o"
var/blood = 0
- var/eat_from = WEST
+ var/eat_dir = WEST
/obj/machinery/recycler/New()
// On us
@@ -30,7 +30,7 @@ var/const/SAFETY_COOLDOWN = 100
..()
update_icon()
-/*
+
/obj/machinery/recycler/attackby(var/obj/item/I, var/mob/user)
if(istype(I, /obj/item/weapon/card/emag) && !emagged)
emagged = 1
@@ -44,7 +44,8 @@ var/const/SAFETY_COOLDOWN = 100
user << "You reset the crusher to its default factory settings."
else
..()
-*/
+ return
+ add_fingerprint(user)
/obj/machinery/recycler/update_icon()
..()
@@ -53,9 +54,15 @@ var/const/SAFETY_COOLDOWN = 100
is_powered = 0
icon_state = icon_name + "[is_powered]" + "[(blood ? "bld" : "")]" // add the blood tag at the end
+// This is purely for admin possession !FUN!.
+/obj/machinery/recycler/Bump(var/atom/movable/AM)
+ ..()
+ if(AM)
+ Bumped(AM)
+
+
/obj/machinery/recycler/Bumped(var/atom/movable/AM)
- // Crossed didn't like people lying down.
if(stat & (BROKEN|NOPOWER))
return
if(safety_mode)
@@ -69,7 +76,7 @@ var/const/SAFETY_COOLDOWN = 100
return
var/move_dir = get_dir(loc, AM.loc)
- if(move_dir == eat_from)
+ if(move_dir == eat_dir)
if(isliving(AM))
if(emagged)
eat(AM)
@@ -81,7 +88,7 @@ var/const/SAFETY_COOLDOWN = 100
playsound(src.loc, 'sound/machines/buzz-sigh.ogg', 50, 0)
AM.loc = src.loc
-/obj/machinery/recycler/proc/recycle(var/obj/item/I)
+/obj/machinery/recycler/proc/recycle(var/obj/item/I, var/sound = 1)
I.loc = src.loc
if(!istype(I, /obj/item/weapon/disk/nuclear))
del(I)
@@ -93,7 +100,8 @@ var/const/SAFETY_COOLDOWN = 100
new /obj/item/stack/sheet/plasteel(loc)
if(prob(1))
new /obj/item/stack/sheet/rglass(loc)
- playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
+ if(sound)
+ playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
/obj/machinery/recycler/proc/stop(var/mob/living/L)
@@ -110,20 +118,39 @@ var/const/SAFETY_COOLDOWN = 100
/obj/machinery/recycler/proc/eat(var/mob/living/L)
L.loc = src.loc
+
if(issilicon(L))
playsound(src.loc, 'sound/items/Welder.ogg', 50, 1)
else
playsound(src.loc, 'sound/effects/splat.ogg', 50, 1)
- if(ishuman(L))
- L.say("ARRRRRRRRRRRGH!!!")
+ var/gib = 1
+ // By default, the emagged recycler will gib all non-carbons. (human simple animal mobs don't count)
+ if(iscarbon(L))
+ gib = 0
+ if(L.stat == CONSCIOUS)
+ L.say("ARRRRRRRRRRRGH!!!")
+ add_blood(L)
- L.gib()
-
- if(!blood)
+ if(!blood && !issilicon(L))
blood = 1
update_icon()
+ // Remove and recycle the equipped items.
+ for(var/obj/item/I in L.get_equipped_items())
+ L.drop_from_inventory(I)
+ recycle(I, 0)
+
+ // Instantly lie down, also go unconscious from the pain, before you die.
+ L.Paralyse(5)
+
+ // For admin fun, var edit emagged to 2.
+ if(gib || emagged == 2)
+ L.gib()
+ else if(emagged == 1)
+ L.adjustBruteLoss(1000)
+
+
/obj/item/weapon/paper/recycler
name = "paper - 'garbage duty instructions'"
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 87930516848..bf2afb319a8 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -88,7 +88,7 @@
T.Entered(W)
W.dropped(src)
- update_icons()
+ //update_icons() // Redundant as u_equip will handle updating the specific overlay
return 1
return 0
diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm
index f6da8c3b022..058f20b00db 100644
--- a/code/modules/mob/mob.dm
+++ b/code/modules/mob/mob.dm
@@ -770,16 +770,19 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/proc/Stun(amount)
if(status_flags & CANSTUN)
stunned = max(max(stunned,amount),0) //can't go below 0, getting a low amount of stun doesn't lower your current stun
+ update_canmove()
return
/mob/proc/SetStunned(amount) //if you REALLY need to set stun to a set amount without the whole "can't go below current stunned"
if(status_flags & CANSTUN)
stunned = max(amount,0)
+ update_canmove()
return
/mob/proc/AdjustStunned(amount)
if(status_flags & CANSTUN)
stunned = max(stunned + amount,0)
+ update_canmove()
return
/mob/proc/Weaken(amount)
@@ -803,38 +806,47 @@ note dizziness decrements automatically in the mob's Life() proc.
/mob/proc/Paralyse(amount)
if(status_flags & CANPARALYSE)
paralysis = max(max(paralysis,amount),0)
+ update_canmove()
return
/mob/proc/SetParalysis(amount)
if(status_flags & CANPARALYSE)
paralysis = max(amount,0)
+ update_canmove()
return
/mob/proc/AdjustParalysis(amount)
if(status_flags & CANPARALYSE)
paralysis = max(paralysis + amount,0)
+ update_canmove()
return
/mob/proc/Sleeping(amount)
sleeping = max(max(sleeping,amount),0)
+ update_canmove()
return
/mob/proc/SetSleeping(amount)
sleeping = max(amount,0)
+ update_canmove()
return
/mob/proc/AdjustSleeping(amount)
sleeping = max(sleeping + amount,0)
+ update_canmove()
return
/mob/proc/Resting(amount)
resting = max(max(resting,amount),0)
+ update_canmove()
return
/mob/proc/SetResting(amount)
resting = max(amount,0)
+ update_canmove()
return
/mob/proc/AdjustResting(amount)
resting = max(resting + amount,0)
+ update_canmove()
return
\ No newline at end of file
diff --git a/code/modules/nano/nanoexternal.dm b/code/modules/nano/nanoexternal.dm
index 8ceb45e6adc..2331debd9be 100644
--- a/code/modules/nano/nanoexternal.dm
+++ b/code/modules/nano/nanoexternal.dm
@@ -31,11 +31,12 @@
* ui_interact is currently defined for /atom/movable
*
* @param user /mob The mob who is interacting with this ui
- * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
+ * @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
+ * @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
*
* @return nothing
*/
-/atom/movable/proc/ui_interact(mob/user, ui_key = "main")
+/atom/movable/proc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
return
// Used by the Nano UI Manager (/datum/nanomanager) to track UIs opened by this mob
diff --git a/code/modules/nano/nanomanager.dm b/code/modules/nano/nanomanager.dm
index c1be3cca799..b7b45060bb7 100644
--- a/code/modules/nano/nanomanager.dm
+++ b/code/modules/nano/nanomanager.dm
@@ -1,8 +1,9 @@
// This is the window/UI manager for Nano UI
// There should only ever be one (global) instance of nanomanger
/datum/nanomanager
- // the list of current open /nanoui UIs
+ // a list of current open /nanoui UIs, grouped by src_object and ui_key
var/open_uis[0]
+ // a list of current open /nanoui UIs, not grouped, for use in processing
var/list/processing_uis = list()
/**
@@ -13,6 +14,29 @@
/datum/nanomanager/New()
return
+ /**
+ * Get an open /nanoui ui for the current user, src_object and ui_key and try to update it with data
+ *
+ * @param user /mob The mob who opened/owns the ui
+ * @param src_object /obj|/mob The obj or mob which the ui belongs to
+ * @param ui_key string A string key used for the ui
+ * @param ui /datum/nanoui An existing instance of the ui (can be null)
+ * @param data list The data to be passed to the ui, if it exists
+ *
+ * @return /nanoui Returns the found ui, for null if none exists
+ */
+/datum/nanomanager/proc/try_update_ui(var/mob/user, src_object, ui_key, var/datum/nanoui/ui, data)
+ if (isnull(ui)) // no ui has been passed, so we'll search for one
+ {
+ ui = get_open_ui(user, src_object, ui_key)
+ }
+ if (!isnull(ui))
+ // The UI is already open so push the data to it
+ ui.push_data(data)
+ return ui
+
+ return null
+
/**
* Get an open /nanoui ui for the current user, src_object and ui_key
*
@@ -20,7 +44,7 @@
* @param src_object /obj|/mob The obj or mob which the ui belongs to
* @param ui_key string A string key used for the ui
*
- * @return /nanoui Returns the found ui, for null if none exists
+ * @return /nanoui Returns the found ui, or null if none exists
*/
/datum/nanomanager/proc/get_open_ui(var/mob/user, src_object, ui_key)
var/src_object_key = "\ref[src_object]"
@@ -38,7 +62,7 @@
/**
* Update all /nanoui uis attached to src_object
*
- * @param src_object /obj|/mob The obj or mob which the uis belong to
+ * @param src_object /obj|/mob The obj or mob which the uis are attached to
*
* @return int The number of uis updated
*/
@@ -54,6 +78,48 @@
ui.process(1)
update_count++
return update_count
+
+ /**
+ * Update /nanoui uis belonging to user
+ *
+ * @param user /mob The mob who owns the uis
+ * @param src_object /obj|/mob If src_object is provided, only update uis which are attached to src_object (optional)
+ * @param ui_key string If ui_key is provided, only update uis with a matching ui_key (optional)
+ *
+ * @return int The number of uis updated
+ */
+/datum/nanomanager/proc/update_user_uis(var/mob/user, src_object = null, ui_key = null)
+ if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
+ return 0 // has no open uis
+
+ var/update_count = 0
+ for (var/datum/nanoui/ui in user.open_uis)
+ if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
+ ui.process(1)
+ update_count++
+
+ return update_count
+
+ /**
+ * Close /nanoui uis belonging to user
+ *
+ * @param user /mob The mob who owns the uis
+ * @param src_object /obj|/mob If src_object is provided, only close uis which are attached to src_object (optional)
+ * @param ui_key string If ui_key is provided, only close uis with a matching ui_key (optional)
+ *
+ * @return int The number of uis closed
+ */
+/datum/nanomanager/proc/close_user_uis(var/mob/user, src_object = null, ui_key = null)
+ if (isnull(user.open_uis) || !istype(user.open_uis, /list) || open_uis.len == 0)
+ return 0 // has no open uis
+
+ var/close_count = 0
+ for (var/datum/nanoui/ui in user.open_uis)
+ if ((isnull(src_object) || !isnull(src_object) && ui.src_object == src_object) && (isnull(ui_key) || !isnull(ui_key) && ui.ui_key == ui_key))
+ ui.close()
+ close_count++
+
+ return close_count
/**
* Add a /nanoui ui to the list of open uis
@@ -106,11 +172,7 @@
//
/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();
+ return close_user_uis(user)
/**
* This is called when a player transfers from one mob to another
@@ -133,5 +195,6 @@
newMob.open_uis.Add(ui)
oldMob.open_uis.Cut()
-
+
+ return 1 // success
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index d488e8b5c70..7b684aefb25 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -92,8 +92,8 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/add_common_assets()
add_script("libraries.min.js") // The jQuery library
+ add_script("nano_config.js") // The NanoConfig JS, this is used to store configuration values.
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
@@ -256,8 +256,12 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/get_header()
var/head_content = ""
+
+ for (var/filename in scripts)
+ head_content += " "
+
for (var/filename in stylesheets)
- head_content += ""
+ head_content += " "
var/templatel_data[0]
for (var/key in templates)
@@ -277,35 +281,24 @@ nanoui is used to open and update nano browser uis
- [head_content]
-
-
+ [head_content]
+
+
[title ? "
[title]
" : ""]
+
Initiating...
"}
/**
@@ -314,13 +307,8 @@ nanoui is used to open and update nano browser uis
* @return string HTML footer content
*/
/datum/nanoui/proc/get_footer()
- var/scriptsContent = ""
-
- for (var/filename in scripts)
- scriptsContent += ""
return {"
- [scriptsContent]
@@ -349,7 +337,7 @@ nanoui is used to open and update nano browser uis
window_size = "size=[width]x[height];"
update_status(0)
user << browse(get_html(), "window=[window_id];[window_size][window_options]")
- winset(user, "mapwindow.map", "focus=true") // Return keyboard focus to map.
+ winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map
on_close_winset()
//onclose(user, window_id)
nanomanager.ui_opened(src)
@@ -388,6 +376,7 @@ nanoui is used to open and update nano browser uis
return // Cannot update UI, no visibility
data = add_default_data(data)
+ //user << list2json(data) // used for debugging
user << output(list2params(list(list2json(data))),"[window_id].browser:receiveUpdateData")
/**
@@ -414,8 +403,12 @@ nanoui is used to open and update nano browser uis
* @return nothing
*/
/datum/nanoui/proc/process(update = 0)
+ if (!src_object || !user)
+ close()
+ return
+
if (status && (update || is_auto_updating))
- src_object.ui_interact(user, ui_key) // Update the UI (update_status() is called whenever a UI is updated)
+ src_object.ui_interact(user, ui_key, src) // Update the UI (update_status() is called whenever a UI is updated)
else
update_status(1) // Not updating UI, so lets check here if status has changed
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 2243c00e0dc..49ad20adbaf 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -503,7 +503,7 @@
return 0 // 0 = User is not a Malf AI
-/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main")
+/obj/machinery/power/apc/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
if(!user)
return
@@ -552,20 +552,19 @@
)
)
)
-
- var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
if (!ui)
- // the ui does not exist, so we'll create a new one
- ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 500, data["siliconUser"] ? 465 : 390)
- // When the UI is first opened this is the data it will use
- ui.set_initial_data(data)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "apc.tmpl", "[area.name] - APC", 520, data["siliconUser"] ? 465 : 420)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
ui.open()
- // Auto update every Master Controller tick
+ // auto update every Master Controller tick
ui.set_auto_update(1)
- else
- // The UI is already open so push the new data to it
- ui.push_data(data)
- return
/obj/machinery/power/apc/proc/report()
return "[area.name] : [equipment]/[lighting]/[environ] ([lastused_equip+lastused_light+lastused_environ]) : [cell? cell.percent() : "N/C"] ([charging])"
diff --git a/code/modules/reagents/Chemistry-Machinery.dm b/code/modules/reagents/Chemistry-Machinery.dm
index 2dae88713c9..32d989485b2 100644
--- a/code/modules/reagents/Chemistry-Machinery.dm
+++ b/code/modules/reagents/Chemistry-Machinery.dm
@@ -77,7 +77,7 @@
*
* @return nothing
*/
-/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main")
+/obj/machinery/chem_dispenser/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null)
if(stat & (BROKEN)) return
if(user.stat || user.restrained()) return
@@ -109,18 +109,17 @@
if(temp)
chemicals.Add(list(list("title" = temp.name, "id" = temp.id, "commands" = list("dispense" = temp.id)))) // list in a list because Byond merges the first list...
data["chemicals"] = chemicals
-
- var/datum/nanoui/ui = nanomanager.get_open_ui(user, src, ui_key)
+
+ // update the ui if it exists, returns null if no ui is passed/found
+ ui = nanomanager.try_update_ui(user, src, ui_key, ui, data)
if (!ui)
- // the ui does not exist, so we'll create a new one
- ui = new(user, src, ui_key, "chem_dispenser.tmpl", "Chem Dispenser 5000", 370, 590)
- // When the UI is first opened this is the data it will use
- ui.set_initial_data(data)
+ // the ui does not exist, so we'll create a new() one
+ // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
+ ui = new(user, src, ui_key, "chem_dispenser.tmpl", "Chem Dispenser 5000", 390, 610)
+ // when the ui is first opened this is the data it will use
+ ui.set_initial_data(data)
+ // open the new ui window
ui.open()
- else
- // The UI is already open so push the new data to it
- ui.push_data(data)
- return
/obj/machinery/chem_dispenser/Topic(href, href_list)
if(stat & (BROKEN))
diff --git a/html/changelog.html b/html/changelog.html
index 2d96d561d53..7cd6c4329b9 100644
--- a/html/changelog.html
+++ b/html/changelog.html
@@ -52,28 +52,47 @@ should be listed in the changelog upon commit tho. Thanks. -->
-
+
+
+
+
11 January 2014
+
Errorage updated:
+
+
Cyborg modules now use a new UI, which is much quicker than a menu.
+
+
Giacom updated:
+
+
The game will now have all background operations disabled, this will result in smoother gameplay but may result in some spike lags, before being set back to normal. The gradually increasing lag should now be gone.
+
You can now emag the crusher, in disposals, to remove the safety. You can use a screwdriver to reset it to the default factory settings.
+
The toxin compensation symptom will stop giving you toxin damage while at full health.
+
+
Cheridan updated:
+
+
You can now upgrade laser pointers with micro laser parts. It will increase the chance of blinding people.
+
+
JJRCop updated:
+
+
The new nuke toy can now be found in your local arcade machine.
+
+
10 January 2014
Giacom updated:
-
+
You can whisper while in critical, but you will immediately die afterwards DRAMATICALLY. The closer you are to death, the less you can say.
The wizard won't spawn so much smoke after they blink.
The detective's forensic scanner was upgraded so that it can now scan from afar.
-
Made the ghost's follow button less buggy.
-
-
+
Made the ghost's follow button less buggy. Please make an issue report if it still bugs out.
+
ChuckTheSheep updated:
Morgue Trays can detect players in their bodies and will now change colour depending on a few things. Red = Dead body with no player inside. Orange = No body but items. Green = A dead body with a player inside.
a";cd=b3.getElementsByTagName("*")||[];cb=b3.getElementsByTagName("a")[0];if(!cb||!cb.style||!cd.length){return ce}cc=l.createElement("select");b5=cc.appendChild(l.createElement("option"));ca=b3.getElementsByTagName("input")[0];cb.style.cssText="top:1px;float:left;opacity:.5";ce.getSetAttribute=b3.className!=="t";ce.leadingWhitespace=b3.firstChild.nodeType===3;ce.tbody=!b3.getElementsByTagName("tbody").length;ce.htmlSerialize=!!b3.getElementsByTagName("link").length;ce.style=/top/.test(cb.getAttribute("style"));ce.hrefNormalized=cb.getAttribute("href")==="/a";ce.opacity=/^0.5/.test(cb.style.opacity);ce.cssFloat=!!cb.style.cssFloat;ce.checkOn=!!ca.value;ce.optSelected=b5.selected;ce.enctype=!!l.createElement("form").enctype;ce.html5Clone=l.createElement("nav").cloneNode(true).outerHTML!=="<:nav>";ce.inlineBlockNeedsLayout=false;ce.shrinkWrapBlocks=false;ce.pixelPosition=false;ce.deleteExpando=true;ce.noCloneEvent=true;ce.reliableMarginRight=true;ce.boxSizingReliable=true;ca.checked=true;ce.noCloneChecked=ca.cloneNode(true).checked;cc.disabled=true;ce.optDisabled=!b5.disabled;try{delete b3.test}catch(b8){ce.deleteExpando=false}ca=l.createElement("input");ca.setAttribute("value","");ce.input=ca.getAttribute("value")==="";ca.value="t";ca.setAttribute("type","radio");ce.radioValue=ca.value==="t";ca.setAttribute("checked","t");ca.setAttribute("name","t");b9=l.createDocumentFragment();b9.appendChild(ca);ce.appendChecked=ca.checked;ce.checkClone=b9.cloneNode(true).cloneNode(true).lastChild.checked;if(b3.attachEvent){b3.attachEvent("onclick",function(){ce.noCloneEvent=false});b3.cloneNode(true).click()}for(b6 in {submit:true,change:true,focusin:true}){b3.setAttribute(b7="on"+b6,"t");ce[b6+"Bubbles"]=b7 in a1||b3.attributes[b7].expando===false}b3.style.backgroundClip="content-box";b3.cloneNode(true).style.backgroundClip="";ce.clearCloneStyle=b3.style.backgroundClip==="content-box";for(b6 in bI(ce)){break}ce.ownLast=b6!=="0";bI(function(){var cf,ci,ch,cg="padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;",e=l.getElementsByTagName("body")[0];if(!e){return}cf=l.createElement("div");cf.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px";e.appendChild(cf).appendChild(b3);b3.innerHTML="
").append(bI.parseHTML(ca)).find(e):ca)}).complete(b9&&function(cb,ca){b3.each(b9,b4||[cb.responseText,ca,cb])})}return this};bI.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,b3){bI.fn[b3]=function(b4){return this.on(b3,b4)}});bI.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:W,type:"GET",isLocal:A.test(b1[1]),global:true,processData:true,async:true,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":aU,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":true,"text json":bI.parseJSON,"text xml":bI.parseXML},flatOptions:{url:true,context:true}},ajaxSetup:function(b3,e){return e?r(r(b3,bI.ajaxSettings),e):r(bI.ajaxSettings,b3)},ajaxPrefilter:bK(v),ajaxTransport:bK(a6),ajax:function(b7,b4){if(typeof b7==="object"){b4=b7;b7=aE}b4=b4||{};var cg,ci,b8,cn,cc,b3,cj,b5,cb=bI.ajaxSetup({},b4),cp=cb.context||cb,ce=cb.context&&(cp.nodeType||cp.jquery)?bI(cp):bI.event,co=bI.Deferred(),cl=bI.Callbacks("once memory"),b9=cb.statusCode||{},cf={},cm={},b6=0,ca="canceled",ch={readyState:0,getResponseHeader:function(cq){var e;if(b6===2){if(!b5){b5={};while((e=ae.exec(cn))){b5[e[1].toLowerCase()]=e[2]}}e=b5[cq.toLowerCase()]}return e==null?null:e},getAllResponseHeaders:function(){return b6===2?cn:null},setRequestHeader:function(cq,cr){var e=cq.toLowerCase();if(!b6){cq=cm[e]=cm[e]||cq;cf[cq]=cr}return this},overrideMimeType:function(e){if(!b6){cb.mimeType=e}return this},statusCode:function(cq){var e;if(cq){if(b6<2){for(e in cq){b9[e]=[b9[e],cq[e]]}}else{ch.always(cq[ch.status])}}return this},abort:function(cq){var e=cq||ca;if(cj){cj.abort(e)}cd(0,e);return this}};co.promise(ch).complete=cl.add;ch.success=ch.done;ch.error=ch.fail;cb.url=((b7||cb.url||W)+"").replace(an,"").replace(aF,b1[1]+"//");cb.type=b4.method||b4.type||cb.method||cb.type;cb.dataTypes=bI.trim(cb.dataType||"*").toLowerCase().match(aa)||[""];if(cb.crossDomain==null){cg=aS.exec(cb.url.toLowerCase());cb.crossDomain=!!(cg&&(cg[1]!==b1[1]||cg[2]!==b1[2]||(cg[3]||(cg[1]==="http:"?"80":"443"))!==(b1[3]||(b1[1]==="http:"?"80":"443"))))}if(cb.data&&cb.processData&&typeof cb.data!=="string"){cb.data=bI.param(cb.data,cb.traditional)}n(v,cb,b4,ch);if(b6===2){return ch}b3=cb.global;if(b3&&bI.active++===0){bI.event.trigger("ajaxStart")}cb.type=cb.type.toUpperCase();cb.hasContent=!o.test(cb.type);b8=cb.url;if(!cb.hasContent){if(cb.data){b8=(cb.url+=(ax.test(b8)?"&":"?")+cb.data);delete cb.data}if(cb.cache===false){cb.url=M.test(b8)?b8.replace(M,"$1_="+bN++):b8+(ax.test(b8)?"&":"?")+"_="+bN++}}if(cb.ifModified){if(bI.lastModified[b8]){ch.setRequestHeader("If-Modified-Since",bI.lastModified[b8])}if(bI.etag[b8]){ch.setRequestHeader("If-None-Match",bI.etag[b8])}}if(cb.data&&cb.hasContent&&cb.contentType!==false||b4.contentType){ch.setRequestHeader("Content-Type",cb.contentType)}ch.setRequestHeader("Accept",cb.dataTypes[0]&&cb.accepts[cb.dataTypes[0]]?cb.accepts[cb.dataTypes[0]]+(cb.dataTypes[0]!=="*"?", "+aU+"; q=0.01":""):cb.accepts["*"]);for(ci in cb.headers){ch.setRequestHeader(ci,cb.headers[ci])}if(cb.beforeSend&&(cb.beforeSend.call(cp,ch,cb)===false||b6===2)){return ch.abort()}ca="abort";for(ci in {success:1,error:1,complete:1}){ch[ci](cb[ci])}cj=n(a6,cb,b4,ch);if(!cj){cd(-1,"No Transport")}else{ch.readyState=1;if(b3){ce.trigger("ajaxSend",[ch,cb])}if(cb.async&&cb.timeout>0){cc=setTimeout(function(){ch.abort("timeout")},cb.timeout)}try{b6=1;cj.send(cf,cd)}catch(ck){if(b6<2){cd(-1,ck)}else{throw ck}}}function cd(cu,cq,cv,cs){var e,cy,cw,ct,cx,cr=cq;if(b6===2){return}b6=2;if(cc){clearTimeout(cc)}cj=aE;cn=cs||"";ch.readyState=cu>0?4:0;e=cu>=200&&cu<300||cu===304;if(cv){ct=g(cb,ch,cv)}ct=ad(cb,ct,ch,e);if(e){if(cb.ifModified){cx=ch.getResponseHeader("Last-Modified");if(cx){bI.lastModified[b8]=cx}cx=ch.getResponseHeader("etag");if(cx){bI.etag[b8]=cx}}if(cu===204||cb.type==="HEAD"){cr="nocontent"}else{if(cu===304){cr="notmodified"}else{cr=ct.state;cy=ct.data;cw=ct.error;e=!cw}}}else{cw=cr;if(cu||!cr){cr="error";if(cu<0){cu=0}}}ch.status=cu;ch.statusText=(cq||cr)+"";if(e){co.resolveWith(cp,[cy,cr,ch])}else{co.rejectWith(cp,[ch,cr,cw])}ch.statusCode(b9);b9=aE;if(b3){ce.trigger(e?"ajaxSuccess":"ajaxError",[ch,cb,e?cy:cw])}cl.fireWith(cp,[ch,cr]);if(b3){ce.trigger("ajaxComplete",[ch,cb]);if(!(--bI.active)){bI.event.trigger("ajaxStop")}}}return ch},getJSON:function(e,b3,b4){return bI.get(e,b3,b4,"json")},getScript:function(e,b3){return bI.get(e,aE,b3,"script")}});bI.each(["get","post"],function(e,b3){bI[b3]=function(b4,b6,b7,b5){if(bI.isFunction(b6)){b5=b5||b7;b7=b6;b6=aE}return bI.ajax({url:b4,type:b3,dataType:b5,data:b6,success:b7})}});function g(ca,b9,b6){var e,b5,b4,b7,b3=ca.contents,b8=ca.dataTypes;while(b8[0]==="*"){b8.shift();if(b5===aE){b5=ca.mimeType||b9.getResponseHeader("Content-Type")}}if(b5){for(b7 in b3){if(b3[b7]&&b3[b7].test(b5)){b8.unshift(b7);break}}}if(b8[0] in b6){b4=b8[0]}else{for(b7 in b6){if(!b8[0]||ca.converters[b7+" "+b8[0]]){b4=b7;break}if(!e){e=b7}}b4=b4||e}if(b4){if(b4!==b8[0]){b8.unshift(b4)}return b6[b4]}}function ad(ce,b6,cb,b4){var b3,b9,cc,b7,b5,cd={},ca=ce.dataTypes.slice();if(ca[1]){for(cc in ce.converters){cd[cc.toLowerCase()]=ce.converters[cc]}}b9=ca.shift();while(b9){if(ce.responseFields[b9]){cb[ce.responseFields[b9]]=b6}if(!b5&&b4&&ce.dataFilter){b6=ce.dataFilter(b6,ce.dataType)}b5=b9;b9=ca.shift();if(b9){if(b9==="*"){b9=b5}else{if(b5!=="*"&&b5!==b9){cc=cd[b5+" "+b9]||cd["* "+b9];if(!cc){for(b3 in cd){b7=b3.split(" ");if(b7[1]===b9){cc=cd[b5+" "+b7[0]]||cd["* "+b7[0]];if(cc){if(cc===true){cc=cd[b3]}else{if(cd[b3]!==true){b9=b7[0];ca.unshift(b7[1])}}break}}}}if(cc!==true){if(cc&&ce["throws"]){b6=cc(b6)}else{try{b6=cc(b6)}catch(b8){return{state:"parsererror",error:cc?b8:"No conversion from "+b5+" to "+b9}}}}}}}}return{state:"success",data:b6}}bI.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){bI.globalEval(e);return e}}});bI.ajaxPrefilter("script",function(e){if(e.cache===aE){e.cache=false}if(e.crossDomain){e.type="GET";e.global=false}});bI.ajaxTransport("script",function(b4){if(b4.crossDomain){var e,b3=l.head||bI("head")[0]||l.documentElement;return{send:function(b5,b6){e=l.createElement("script");e.async=true;if(b4.scriptCharset){e.charset=b4.scriptCharset}e.src=b4.url;e.onload=e.onreadystatechange=function(b8,b7){if(b7||!e.readyState||/loaded|complete/.test(e.readyState)){e.onload=e.onreadystatechange=null;if(e.parentNode){e.parentNode.removeChild(e)}e=null;if(!b7){b6(200,"success")}}};b3.insertBefore(e,b3.firstChild)},abort:function(){if(e){e.onload(aE,true)}}}}});var bp=[],a4=/(=)\?(?=&|$)|\?\?/;bI.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=bp.pop()||(bI.expando+"_"+(bN++));this[e]=true;return e}});bI.ajaxPrefilter("json jsonp",function(b5,e,b6){var b8,b3,b4,b7=b5.jsonp!==false&&(a4.test(b5.url)?"url":typeof b5.data==="string"&&!(b5.contentType||"").indexOf("application/x-www-form-urlencoded")&&a4.test(b5.data)&&"data");if(b7||b5.dataTypes[0]==="jsonp"){b8=b5.jsonpCallback=bI.isFunction(b5.jsonpCallback)?b5.jsonpCallback():b5.jsonpCallback;if(b7){b5[b7]=b5[b7].replace(a4,"$1"+b8)}else{if(b5.jsonp!==false){b5.url+=(ax.test(b5.url)?"&":"?")+b5.jsonp+"="+b8}}b5.converters["script json"]=function(){if(!b4){bI.error(b8+" was not called")}return b4[0]};b5.dataTypes[0]="json";b3=a1[b8];a1[b8]=function(){b4=arguments};b6.always(function(){a1[b8]=b3;if(b5[b8]){b5.jsonpCallback=e.jsonpCallback;bp.push(b8)}if(b4&&bI.isFunction(b3)){b3(b4[0])}b4=b3=aE});return"script"}});var af,av,aw=0,aN=a1.ActiveXObject&&function(){var e;for(e in af){af[e](aE,true)}};function bC(){try{return new a1.XMLHttpRequest()}catch(b3){}}function bd(){try{return new a1.ActiveXObject("Microsoft.XMLHTTP")}catch(b3){}}bI.ajaxSettings.xhr=a1.ActiveXObject?function(){return !this.isLocal&&bC()||bd()}:bC;av=bI.ajaxSettings.xhr();bI.support.cors=!!av&&("withCredentials" in av);av=bI.support.ajax=!!av;if(av){bI.ajaxTransport(function(e){if(!e.crossDomain||bI.support.cors){var b3;return{send:function(b9,b4){var b7,b5,b8=e.xhr();if(e.username){b8.open(e.type,e.url,e.async,e.username,e.password)}else{b8.open(e.type,e.url,e.async)}if(e.xhrFields){for(b5 in e.xhrFields){b8[b5]=e.xhrFields[b5]}}if(e.mimeType&&b8.overrideMimeType){b8.overrideMimeType(e.mimeType)}if(!e.crossDomain&&!b9["X-Requested-With"]){b9["X-Requested-With"]="XMLHttpRequest"}try{for(b5 in b9){b8.setRequestHeader(b5,b9[b5])}}catch(b6){}b8.send((e.hasContent&&e.data)||null);b3=function(cc,cb){var ca,cd,cg,ce;try{if(b3&&(cb||b8.readyState===4)){b3=aE;if(b7){b8.onreadystatechange=bI.noop;if(aN){delete af[b7]}}if(cb){if(b8.readyState!==4){b8.abort()}}else{ce={};ca=b8.status;cd=b8.getAllResponseHeaders();if(typeof b8.responseText==="string"){ce.text=b8.responseText}try{cg=b8.statusText}catch(cf){cg=""}if(!ca&&e.isLocal&&!e.crossDomain){ca=ce.text?200:404}else{if(ca===1223){ca=204}}}}}catch(ch){if(!cb){b4(-1,ch)}}if(ce){b4(ca,cg,ce,cd)}};if(!e.async){b3()}else{if(b8.readyState===4){setTimeout(b3)}else{b7=++aw;if(aN){if(!af){af={};bI(a1).unload(aN)}af[b7]=b3}b8.onreadystatechange=b3}}},abort:function(){if(b3){b3(aE,true)}}}}})}var J,ab,bQ=/^(?:toggle|show|hide)$/,bJ=new RegExp("^(?:([+-])=|)("+bz+")([a-z%]*)$","i"),bP=/queueHooks$/,az=[h],aY={"*":[function(e,b8){var ca=this.createTween(e,b8),b6=ca.cur(),b5=bJ.exec(b8),b9=b5&&b5[3]||(bI.cssNumber[e]?"":"px"),b3=(bI.cssNumber[e]||b9!=="px"&&+b6)&&bJ.exec(bI.css(ca.elem,e)),b4=1,b7=20;if(b3&&b3[3]!==b9){b9=b9||b3[3];b5=b5||[];b3=+b6||1;do{b4=b4||".5";b3=b3/b4;bI.style(ca.elem,e,b3+b9)}while(b4!==(b4=ca.cur()/b6)&&b4!==1&&--b7)}if(b5){b3=ca.start=+b3||+b6||0;ca.unit=b9;ca.end=b5[1]?b3+(b5[1]+1)*b5[2]:+b5[2]}return ca}]};function bl(){setTimeout(function(){J=aE});return(J=bI.now())}function ba(b6,b8,b5){var b3,b7=(aY[b8]||[]).concat(aY["*"]),e=0,b4=b7.length;for(;e-1,cb={},ca={},b4,b6;if(cd){ca=b7.position();b4=ca.top;b6=ca.left}else{b4=parseFloat(e)||0;b6=parseFloat(cc)||0}if(bI.isFunction(ce)){ce=ce.call(b5,b8,b3)}if(ce.top!=null){cb.top=(ce.top-b3.top)+b4}if(ce.left!=null){cb.left=(ce.left-b3.left)+b6}if("using" in ce){ce.using.call(b5,cb)}else{b7.css(cb)}}};bI.fn.extend({position:function(){if(!this[0]){return}var b4,b5,e={top:0,left:0},b3=this[0];if(bI.css(b3,"position")==="fixed"){b5=b3.getBoundingClientRect()}else{b4=this.offsetParent();b5=this.offset();if(!bI.nodeName(b4[0],"html")){e=b4.offset()}e.top+=bI.css(b4[0],"borderTopWidth",true);e.left+=bI.css(b4[0],"borderLeftWidth",true)}return{top:b5.top-e.top-bI.css(b3,"marginTop",true),left:b5.left-e.left-bI.css(b3,"marginLeft",true)}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||bV;while(e&&(!bI.nodeName(e,"html")&&bI.css(e,"position")==="static")){e=e.offsetParent}return e||bV})}});bI.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b4,b3){var e=/Y/.test(b3);bI.fn[b4]=function(b5){return bI.access(this,function(b6,b9,b8){var b7=bo(b6);if(b8===aE){return b7?(b3 in b7)?b7[b3]:b7.document.documentElement[b9]:b6[b9]}if(b7){b7.scrollTo(!e?b8:bI(b7).scrollLeft(),e?b8:bI(b7).scrollTop())}else{b6[b9]=b8}},b4,b5,arguments.length,null)}});function bo(e){return bI.isWindow(e)?e:e.nodeType===9?e.defaultView||e.parentWindow:false}bI.each({Height:"height",Width:"width"},function(e,b3){bI.each({padding:"inner"+e,content:b3,"":"outer"+e},function(b4,b5){bI.fn[b5]=function(b9,b8){var b7=arguments.length&&(b4||typeof b9!=="boolean"),b6=b4||(b9===true||b8===true?"margin":"border");return bI.access(this,function(cb,ca,cc){var cd;if(bI.isWindow(cb)){return cb.document.documentElement["client"+e]}if(cb.nodeType===9){cd=cb.documentElement;return Math.max(cb.body["scroll"+e],cd["scroll"+e],cb.body["offset"+e],cd["offset"+e],cd["client"+e])}return cc===aE?bI.css(cb,ca,b6):bI.style(cb,ca,cc,b6)},b3,b7?b9:aE,b7,null)}})});bI.fn.size=function(){return this.length};bI.fn.andSelf=bI.fn.addBack;if(typeof module==="object"&&module&&typeof module.exports==="object"){module.exports=bI}else{a1.jQuery=a1.$=bI;if(typeof define==="function"&&define.amd){define("jquery",[],function(){return bI})}}})(window);
-/*! JsRender v1.0.0-beta: http://github.com/BorisMoore/jsrender and http://jsviews.com/jsviews */
-(function(a,w,p){if(w&&w.views||a.jsviews){return}var af="v1.0.0-beta",L,ab,s,x,n="{",m="{",g="}",f="}",X="^",y=/^(?:null|true|false|\d[\d.]*|([\w$]+|\.|~([\w$]+)|#(view|([\w$]+))?)([\w$.^]*?)(?:[.[^]([\w$]+)\]?)?)$/g,Y=/(\()(?=\s*\()|(?:([([])\s*)?(?:(\^?)([#~]?[\w$.^]+)?\s*((\+\+|--)|\+|-|&&|\|\||===|!==|==|!=|<=|>=|[<>%*!:?\/]|(=))\s*|([#~]?[\w$.^]+)([([])?)|(,\s*)|(\(?)\\?(?:(')|("))|(?:\s*(([)\]])(?=\s*\.|\s*\^)|[)\]])([([]?))|(\s+)/g,S=/[ \t]*(\r\n|\n|\r)/g,e=/\\(['"])/g,ad=/['"\\]/g,o=/\x08(~)?([^\x08]+)\x08/g,j=/^if\s/,r=/<(\w+)[>\s]/,N=/[\x00`><"'&]/g,I=N,ag=0,ae=0,K={"&":"&","<":"<",">":">","\x00":"","'":"'",'"':""","`":"`"},V="data-jsv-tmpl",O={},R={template:{compile:b},tag:{compile:q},helper:{},converter:{}},M={jsviews:af,render:O,settings:{delimiters:u,debugMode:true,tryCatch:true},sub:{View:ac,Error:D,tmplFn:B,parse:v,extend:t,error:F,syntaxError:Q},_cnvt:G,_tag:c,_err:function(ah){return T.debugMode?("Error: "+(ah.message||ah))+". ":""}};function D(ai,ah){if(ah&&ah.onError){if(ah.onError(ai)===false){return}}this.name="JsRender Error";this.message=ai||"JsRender error"}function t(aj,ai){var ah;aj=aj||{};for(ah in ai){aj[ah]=ai[ah]}return aj}(D.prototype=new Error()).constructor=D;function u(ah,aj,ai){if(!U.rTag||arguments.length){n=ah?ah.charAt(0):n;m=ah?ah.charAt(1):m;g=aj?aj.charAt(0):g;f=aj?aj.charAt(1):f;X=ai||X;ah="\\"+n+"(\\"+X+")?\\"+m;aj="\\"+g+"\\"+f;s="(?:(?:(\\w+(?=[\\/\\s\\"+g+"]))|(?:(\\w+)?(:)|(>)|!--((?:[^-]|-(?!-))*)--|(\\*)))\\s*((?:[^\\"+g+"]|\\"+g+"(?!\\"+f+"))*?)";U.rTag=s+")";s=new RegExp(ah+s+"(\\/)?|(?:\\/(\\w+)))"+aj,"g");x=new RegExp("<.*>|([^\\\\]|^)[{}]|"+ah+".*"+aj)}return[n,m,g,f,X]}function J(al,an){if(!an){an=al;al=p}var ak,am,aj,ao,ai=this,ah=!an||an==="root";if(al){ao=ai.type===an?ai:p;if(!ao){ak=ai.views;if(ai._.useKey){for(am in ak){if(ao=ak[am].get(al,an)){break}}}else{for(am=0,aj=ak.length;!ao&&am0){try{aj=aq.nodeType>0?aq:!x.test(aq)&&w&&w(a.document).find(aq)[0]}catch(ar){}if(aj){aq=aj.getAttribute(V);ah=ah||aq;aq=E[aq];if(!aq){ah=ah||"_"+ag++;aj.setAttribute(V,ah);aq=E[ah]=b(ah,aj.innerHTML,ao,am,ai,ap)}}return aq}}var al,aj;an=an||"";al=ak(an);ap=ap||(an.markup?an:{});ap.tmplName=ah;if(ao){ap._parentTmpl=ao}if(!al&&an.markup&&(al=ak(an.markup))){if(al.fn&&(al.debug!==an.debug||al.allowCode!==an.allowCode)){al=al.markup}}if(al!==p){if(ah&&!ao){O[ah]=function(){return an.render.apply(an,arguments)}}if(al.fn||an.fn){if(al.fn){if(ah&&ah!==al.tmplName){an=aa(ap,al)}else{an=al}}}else{an=h(al,ap);B(al,an)}k(ap);return an}}function h(ak,al){var ah,ai=T.wrapMap||{},aj=t({markup:ak,tmpls:[],links:{},tags:{},bnds:[],_is:"template",render:l},al);if(!al.htmlTag){ah=r.exec(ak);aj.htmlTag=ah?ah[1].toLowerCase():""}ah=ai[aj.htmlTag];if(ah&&ah!==ai.div){aj.markup=L.trim(aj.markup);aj._elCnt=true}return aj}function d(aj,ai){function ak(al,an,ar){var am,aq,ap,ao;if(al&&""+al!==al&&!al.nodeType&&!al.markup){for(ap in al){ak(ap,al[ap],an)}return M}if(an===p){an=al;al=p}if(al&&""+al!==al){ar=an;an=al;al=p}ao=ar?ar[ah]=ar[ah]||{}:ak;aq=ai.compile;if(am=U.onBeforeStoreItem){aq=am(ao,al,an,aq)||aq}if(!al){an=aq(p,an)}else{if(an===null){delete ao[al]}else{ao[al]=aq?(an=aq(al,an,ar,aj,ai)):an}}if(aq&&an){an._is=aj}if(am=U.onStoreItem){am(ao,al,an,aq)}return an}var ah=aj+"s";M[ah]=ak;R[aj]=ai}function l(aC,aj,ak,aD,am,al){var ax,aw,ao,az,aB,au,at,ap,ai,aA,ay,ah,an,av=this,ar=!av.attr||av.attr==="html",aq="";if(aD===true){at=true;aD=0}if(av.tag){ap=av;av=av.tag;aA=av._;ah=av.tagName;an=ap.tmpl;aj=aa(aj,av.ctx);ai=ap.content;if(ap.props.link===false){aj=aj||{};aj.link=false}ak=ak||ap.view;aC=aC===p?ak:aC}else{an=av.jquery&&(av[0]||F('Unknown template: "'+av.selector+'"'))||av}if(an){if(!ak&&aC&&aC._is==="view"){ak=aC}if(ak){ai=ai||ak.content;al=al||ak._.onRender;if(aC===ak){aC=ak.data;am=true}aj=aa(aj,ak.ctx)}if(!ak||ak.data===p){(aj=aj||{}).root=aC}if(!an.fn){an=E[an]||E(an)}if(an){al=(aj&&aj.link)!==false&&ar&&al;ay=al;if(al===true){ay=p;al=ak._.onRender}if(L.isArray(aC)&&!am){az=at?ak:(aD!==p&&ak)||ac(aj,"array",ak,aC,an,aD,ai,al);for(ax=0,aw=aC.length;ax":aM+ap}if(ah){ay="prm"+aG;ah="try{var "+ay+"=["+aL+"][0];}catch(e){"+ay+'="";}\n';aL=ay}}else{if(aC){ar=h(aI,aw);ar.tmplName=ai+"/"+ap;A(aC,ar);aq.push(ar)}if(!aH){aE=ap;al=ak;ak=""}at=av[aG+1];at=at&&at[0]==="else"}an+=",args:["+aL+"]}";if(aO&&aN||aM&&ap!==">"){aF=new Function("data,view,j,u"," // "+ai+" "+aK+" "+ap+"\n"+ah+"return {"+an+";");aF.paths=aN;aF._ctxs=ap;if(au){return aF}az=1}ak+=(aO?"\n"+(aN?"":ah)+(au?"return ":"ret+=")+(az?(az=0,ao=true,'c("'+aM+'",view,'+(aN?((aj[aK-1]=aF),aK):"{"+an)+");"):ap===">"?(am=true,"h("+aL+");"):(aD=true,"(v="+aL+")!="+(au?"=":"")+'u?v:"";')):(aP=true,"{tmpl:"+(aC?aq.length:"0")+","+an+","));if(aE&&!at){ak="["+ak.slice(0,-1)+"]";if(au||aN){ak=new Function("data,view,j,u"," // "+ai+" "+aK+" "+aE+"\nreturn "+ak+";");if(aN){(aj[aK-1]=ak).paths=aN}ak._ctxs=ap;if(au){return ak}}ak=al+'\nret+=t("'+aE+'",view,this,'+(aK||ak)+");";aN=0;aE=0}}}}ak="// "+ai+"\nvar j=j||"+(w?"jQuery.":"js")+"views"+(aD?",v":"")+(aP?",t=j._tag":"")+(ao?",c=j._cnvt":"")+(am?",h=j.converters.html":"")+(au?";\n":',ret="";\n')+(T.tryCatch?"try{\n":"")+(aw.debug?"debugger;":"")+ak+(au?"\n":"\nreturn ret;\n")+(T.tryCatch?"\n}catch(e){return j._err(e);}":"");try{ak=new Function("data,view,j,u",ak)}catch(aJ){Q("Compiled template code:\n\n"+ak,aJ)}if(ax){ax.fn=ak}return ak}function v(am,ai,ar){function at(ay,aP,aA,av,aH,aF,aB,aQ,aw,aG,aO,aN,aJ,aM,aD,aK,az,aL,aC,aE){var ax;aF=aF||"";aA=aA||aP||aN;aH=aH||aw;aG=aG||az||"";function aI(aU,aT,aW,aR,aY,aX,aV){if(aT){if(ai){if(an==="linkTo"){au=ai.to=ai.to||[];au.push(aH)}if(!an||ao){ai.push(aH)}}if(aT!=="."){var aS=(aW?'view.hlp("'+aW+'")':aR?"view":"data")+(aV?(aY?"."+aY:aW?"":(aR?"":"."+aT))+(aX||""):(aV=aW?"":aR?aY||"":aT,""));aS=aS+(aV?"."+aV:"");return aS.slice(0,9)==="view.data"?aS.slice(5):aS}}return aU}if(aB){Q(am)}else{if(ai&&aK&&!ap&&!al){if(!an||ao||au){ax=aq[aj];if(aE.length-2>aC-ax){ax=aE.slice(ax,aC+1);aK=m+":"+ax+g;aK=ak[aK]=ak[aK]||B(n+aK+f,ar,true);if(!aK.paths){v(ax,aK.paths=[],ar)}(au||ai).push({_jsvOb:aK})}}}return(ap?(ap=!aJ,(ap?ay:'"')):al?(al=!aM,(al?ay:'"')):((aA?(aj++,aq[aj]=aC++,aA):"")+(aL?(aj?"":an?(an=ao=au=false,"\b"):","):aQ?(aj&&Q(am),an=aH,ao=av,"\b"+aH+":"):aH?(aH.split("^").join(".").replace(y,aI)+(aG?(ah[++aj]=true,aH.charAt(0)!=="."&&(aq[aj]=aC),aG):aF)):aF?aF:aD?((ah[aj--]=false,aD)+(aG?(ah[++aj]=true,aG):"")):aO?(ah[aj]||Q(am),","):aP?"":(ap=aJ,al=aM,'"'))))}}var an,au,ao,ak=ar.links,ah={},aq={0:-1},aj=0,al=false,ap=false;return(am+" ").replace(Y,at)}function aa(ai,ah){return ai&&ai!==ah?(ah?t(t({},ah),ai):ai):ah&&t({},ah)}function i(ah){return K[ah]||(K[ah]=""+ah.charCodeAt(0)+";")}for(ab in R){d(ab,R[ab])}var E=M.templates,Z=M.converters,C=M.helpers,P=M.tags,U=M.sub,T=M.settings;if(w){L=w;L.fn.render=l}else{L=a.jsviews={};L.isArray=Array&&Array.isArray||function(ah){return Object.prototype.toString.call(ah)==="[object Array]"}}L.render=O;L.views=M;L.templates=E=M.templates;P({"else":function(){},"if":{render:function(aj){var ah=this,ai=(ah.rendering.done||!aj&&(arguments.length||!ah.tagCtx.index))?"":(ah.rendering.done=true,ah.selected=ah.tagCtx.index,ah.tagCtx.render());return ai},onUpdate:function(al,ak,aj){var ai,ah,am;for(ai=0;(ah=this.tagCtxs[ai])&&ah.args.length;ai++){ah=ah.args[0];am=!ah!==!aj[ai].args[0];if(!!ah||am){return am}}return false},flow:true},"for":{render:function(am){var ak=this,aj=ak.tagCtx,al=!arguments.length,ah="",ai=al||0;if(!ak.rendering.done){if(al){ah=p}else{if(am!==p){ah+=aj.render(am);ai+=L.isArray(am)?am.length:1}}if(ak.rendering.done=ai){ak.selected=aj.index}}return ah},onArrayChange:function(ak,ai){var aj,ah=this,al=ai.change;if(this.tagCtxs[1]&&(al==="insert"&&ak.target.length===ai.items.length||al==="remove"&&!ak.target.length||al==="refresh"&&!ai.oldItems.length!==!ak.target.length)){this.refresh()}else{for(aj in ah._.arrVws){aj=ah._.arrVws[aj];if(aj.data===ak.target){aj._.onArrayChange.apply(aj,arguments)}}}ak.done=true},flow:true},include:{flow:true},"*":{render:function(ah){return ah},flow:true}});Z({html:function(ah){return ah!=p?String(ah).replace(I,i):""},attr:function(ah){return ah!=p?String(ah).replace(N,i):ah===null?null:""},url:function(ah){return ah!=p?encodeURI(String(ah)):ah===null?null:""}});u()})(this,this.jQuery);
-/*! JsObservable v1.0.0-alpha: http://github.com/BorisMoore/jsviews and http://jsviews.com/jsviews */
-(function(y,f,k){if(!f){throw"requires jQuery or JsRender"}if(f.observable){return}var c="v1.0.0-alpha",w,n,H,t,A=f.event.special,s=f.views?f.views.sub:{},l=1,G=[].splice,j=[].concat,p=f.isArray,C=f.expando,q="object",E=s.propChng=s.propChng||"propertyChange",e=s.arrChng=s.arrChng||"arrayChange",x=s._cbBnds=s._cbBnds||{},g=E+".observe",u=f.isFunction,i=1,r=1,h=f.hasData;function v(I){return p(I)?new a(I):new b(I)}function b(I){this._data=I;return this}function a(I){this._data=I;return this}function B(I){return p(I)?[I]:I}function m(I){if(typeof I!=="number"){throw"Invalid index."}}function d(P,J){P=p(P)?P:[P];var N,O,L=J,M=L,I=P.length,K=[];for(N=0;N-1){ah=ah[L];continue}}if(L==="*"){if(u(ah)){if(O=ah.depends){o(O,M,I||P)}}else{S(ai,L)}break}else{if(L&&!(u(O=ah[L])&&O.depends)){S(ai+"."+L,T.join("."))}}}L=L?ah[L]:ah}if(u(L)){if(O=L.depends){o(ah,d(O,ah),M,N,I||B(P))}break}ah=L}}aa(ah,I);if(V){F(ae,V)}return{cbId:V,bnd:ae,leaf:ah}}function D(){[].push.call(arguments,true);return o.apply(this,arguments)}f.observable=v;v.Object=b;v.Array=a;v.observe=o;v.unobserve=D;b.prototype={_data:null,data:function(){return this._data},observe:function(I,J){return o(this._data,I,J)},unobserve:function(I,J){return D(this._data,I,J)},setProperty:function(Q,N,L){var M,O,J,K,P=this,I=P._data;Q=Q||"";if(I){if(p(Q)){O=Q.length;while(O--){J=Q[O];P.setProperty(J.name,J.value,L===k||L)}}else{if(""+Q!==Q){for(O in Q){P.setProperty(O,Q[O],N)}}else{if(Q.indexOf(C)<0){K=Q.split(".");while(I&&K.length>1){I=I[K.shift()]}P._setProperty(I,K.join("."),N,L)}}}}return P},_setProperty:function(J,N,M,L){var O,I,K=N?J[N]:J;if(u(K)){if(K.set){I=K;O=K.set===true?K:K.set;K=K.call(J)}}if(K!==M||L&&K!=M){if(!(K instanceof Date)||K>M||K1){J=p(J)?J:[J];if(J.length){this._insert(I,J)}}return this},_insert:function(I,J){t=this._data;H=t.length;G.apply(t,[I,0].concat(J));this._trigger({change:"insert",index:I,items:J})},remove:function(J,K){m(J);K=(K===k||K===null)?1:K;if(K&&J>-1){var I=this._data.slice(J,J+K);K=I.length;if(K){this._remove(J,K,I)}}return this},_remove:function(J,K,I){t=this._data;H=t.length;t.splice(J,K);this._trigger({change:"remove",index:J,items:I})},move:function(L,K,I){m(L);m(K);I=(I===k||I===null)?1:I;if(I){var J=this._data.slice(L,L+I);this._move(L,K,I,J)}return this},_move:function(L,K,I,J){t=this._data;H=t.length;t.splice(L,I);t.splice.apply(t,[K,0].concat(J));this._trigger({change:"move",oldIndex:L,index:K,items:J})},refresh:function(I){var J=this._data.slice(0);this._refresh(J,I);return this},_refresh:function(J,I){t=this._data;H=t.length;G.apply(t,[0,t.length].concat(I));this._trigger({change:"refresh",oldItems:J})},_trigger:function(I){var K=t.length,J=f([t]);J.triggerHandler(e,I);if(K!==H){J.triggerHandler(E,{path:"length",value:K,oldValue:H})}}};A[E]=A[e]={remove:function(I){if((I=I.data)&&(I.off=1,I=I.cb)){w=x[n=I._bnd]}},teardown:function(I){if(w){delete w[f.data(this,"obId")];F(w,n)}}}})(this,this.jQuery||this.jsviews);
-/*! JsViews v1.0.0-alpha: http://github.com/BorisMoore/jsviews and http://jsviews.com/jsviews */
-(function(r,az,u){if(!az){throw"requires jQuery"}if(!az.views){throw"requires JsRender"}if(!az.observable){throw"requires jquery.observable"}if(az.link){return}var g="v1.0.0-alpha",V,aG,aP,e,au,at,M,L,ax,b,Q=r.document,h=az.views,K=h.sub,m=h.settings,n=K.extend,O=K.View(u,"top"),d=az.isFunction,l=h.templates,S=az.observable,aO=S.observe,af="data-jsv",ab=m.linkAttr||"data-link",q=m.propChng=m.propChng||"propertyChange",Z=K.arrChng=K.arrChng||"arrayChange",aH=K._cbBnds=K._cbBnds||{},P="change.jsv",y="onBeforeChange",x="onAfterChange",aB="onAfterCreate",c='"><\/script>',aE='',
- openScript = ' - data-linked tag, close marker
- preceding = id
- ? (preceding + endOfElCnt + spaceBefore + openScript + id + closeScript + spaceAfter + tag)
- : endOfElCnt || all;
- }
- if (tag) {
- // If there are ids (markers since the last tag), move them to the defer string
- tagStack.unshift(parentTag);
- parentTag = tag.slice(1);
- if (tagStack[0] === badParent[parentTag]) {
- // TODO: move this to design-time validation check
- error('"' + parentTag + '" has incorrect parent tag');
- }
- if ((elCnt = elContent[parentTag]) && !prevElCnt) {
- deferStack.unshift(defer);
- defer = "";
- }
- prevElCnt = elCnt;
-//TODO Consider providing validation which throws if you place as child of
, etc. - since if not caught,
-//this can cause errors subsequently which are difficult to debug.
-// if (elContent[tagStack[0]]>2 && !elCnt) {
-// error(parentTag + " in " + tagStack[0]);
-// }
- if (defer && elCnt) {
- defer += "+"; // Will be used for stepping back through deferred tokens
- }
- }
- return preceding;
- }
-
- function processViewInfos(vwInfos, targetParent) {
- // If targetParent, we are processing viewInfos (which may include navigation through '+-' paths) and hooking up to the right parentElem etc.
- // (and elem may also be defined - the next node)
- // If no targetParent, then we are processing viewInfos on newly inserted content
- var deferPath, deferChar, bindChar, parentElem, id, onAftCr, deep,
- addedBindEls = [];
-
- // In elCnt context (element-only content model), prevNode is the first node after the open, nextNode is the first node after the close.
- // If both are null/undefined, then open and close are at end of parent content, so the view is empty, and its placeholder is the
- // 'lastChild' of the parentNode. If there is a prevNode, then it is either the first node in the view, or the view is empty and
- // its placeholder is the 'previousSibling' of the prevNode, which is also the nextNode.
- if (vwInfos) {
- //targetParent = targetParent || targetElem && targetElem.previousSibling;
- //targetParent = targetElem ? targetElem.previousSibling : targetParent;
- len = vwInfos.length;
- if (vwInfos.tokens.charAt(0) === "@") {
- // This is a special script element that was created in convertMarkers() to process deferred bindings, and inserted following the
- // target parent element - because no element tags were encountered to carry those binding tokens.
- targetParent = elem.previousSibling;
- elem.parentNode.removeChild(elem);
- elem = null;
- }
- len = vwInfos.length;
- while (len--) {
- vwInfo = vwInfos[len];
- //if (prevIds.indexOf(vwInfo.token) < 0) { // This token is a newly created view or tag binding
- bindChar = vwInfo.ch;
- if (deferPath = vwInfo.path) {
- // We have a 'deferred path'
- j = deferPath.length - 1;
- while (deferChar = deferPath.charAt(j--)) {
- // Use the "+" and"-" characters to navigate the path back to the original parent node where the deferred bindings ocurred
- if (deferChar === "+") {
- if (deferPath.charAt(j) === "-") {
- j--;
- targetParent = targetParent.previousSibling;
- } else {
- targetParent = targetParent.parentNode;
- }
- } else {
- targetParent = targetParent.lastChild;
- }
- // Note: Can use previousSibling and lastChild, not previousElementSibling and lastElementChild,
- // since we have removed white space within elCnt. Hence support IE < 9
- }
- }
- if (bindChar === "^") {
- if (tag = bindingStore[id = vwInfo.id]) {
- // The binding may have been deleted, for example in a different handler to an array collectionChange event
- // This is a tag binding
- deep = targetParent && (!elem || elem.parentNode !== targetParent);
- if (!elem || deep) {
- tag.parentElem = targetParent;
- }
- if (vwInfo.elCnt) {
- if (vwInfo.open) {
- if (targetParent) {
- // This is an 'open view' node (preceding script marker node,
- // or if elCnt, the first element in the view, with a data-jsv annotation) for binding
- targetParent._dfr = "#" + id + bindChar + (targetParent._dfr || "");
- }
- } else if (deep) {
- // There is no ._nxt so add token to _dfr. It is deferred.
- targetParent._dfr = "/" + id + bindChar + (targetParent._dfr || "");
- }
- }
- // This is an open or close marker for a data-linked tag {^{...}}. Add it to bindEls.
- addedBindEls.push([deep ? null : elem, vwInfo]);
- }
- } else if (view = viewStore[id = vwInfo.id]) {
- // The view may have been deleted, for example in a different handler to an array collectionChange event
- if (!view.link) {
- // If view is not already extended for JsViews, extend and initialize the view object created in JsRender, as a JsViews view
- view.parentElem = targetParent || elem && elem.parentNode || parentNode;
- $extend(view, LinkedView);
- view._.onRender = addBindingMarkers;
- view._.onArrayChange = arrayChangeHandler;
- setArrayChangeLink(view);
- }
- parentElem = view.parentElem;
- if (vwInfo.open) {
- // This is an 'open view' node (preceding script marker node,
- // or if elCnt, the first element in the view, with a data-jsv annotation) for binding
- view._elCnt = vwInfo.elCnt;
- if (targetParent) {
- targetParent._dfr = "#" + id + bindChar + (targetParent._dfr || "");
- } else {
- // No targetParent, so there is a ._nxt elem (and this is processing tokens on the elem)
- if (!view._prv) {
- parentElem._dfr = removeSubStr(parentElem._dfr, "#" + id + bindChar);
- }
- view._prv = elem;
- }
- } else {
- // This is a 'close view' marker node for binding
- if (targetParent && (!elem || elem.parentNode !== targetParent)) {
- // There is no ._nxt so add token to _dfr. It is deferred.
- targetParent._dfr = "/" + id + bindChar + (targetParent._dfr || "");
- view._nxt = undefined;
- } else if (elem) {
- // This view did not have a ._nxt, but has one now, so token may be in _dfr, and must be removed. (No longer deferred)
- if (!view._nxt) {
- parentElem._dfr = removeSubStr(parentElem._dfr, "/" + id + bindChar);
- }
- view._nxt = elem;
- }
- linkCtx = view.linkCtx;
- if (onAftCr = onAfterCreate || (view.ctx && view.ctx.onAfterCreate)) {
- onAftCr.call(linkCtx, view);
- }
- }
- //}
- }
- }
- len = addedBindEls.length;
- while (len--) {
- // These were added in reverse order to addedBindEls. We push them in BindEls in the correct order.
- bindEls.push(addedBindEls[len]);
- }
- }
- return !vwInfos || vwInfos.elCnt;
- }
-
- function getViewInfos(vwInfos) {
- // Used by view.childTags() and tag.childTags()
- // Similar to processViewInfos in how it steps through bindings to find tags. Only finds data-linked tags.
- var level, parentTag;
-
- if (len = vwInfos && vwInfos.length) {
- for (j = 0; j < len; j++) {
- vwInfo = vwInfos[j];
- if (get.id) {
- get.id = get.id !== vwInfo.id && get.id;
- } else {
- // This is an open marker for a data-linked tag {^{...}}, within the content of the tag whose id is get.id. Add it to bindEls.
- parentTag = tag = bindingStore[vwInfo.id].linkCtx.tag;
- if (!tag.flow) {
- if (!deep) {
- level = 1;
- while (parentTag = parentTag.parent) {
- level++;
- }
- tagDepth = tagDepth || level; // The level of the first tag encountered.
- }
- if ((deep || level === tagDepth) && (!tagName || tag.tagName === tagName)) {
- // Filter on top-level or tagName as appropriate
- tags.push(tag);
- }
- }
- }
- }
- }
- }
-
- function dataLink() {
- //================ Data-link and fixup of data-jsv annotations ================
- elems = qsa ? parentNode.querySelectorAll(linkViewsSel) : $(linkViewsSel, parentNode).get();
- l = elems.length;
-
- // The prevNode will be in the returned query, since we called markPrevOrNextNode() on it.
- // But it may have contained nodes that satisfy the selector also.
- if (prevNode) {
- // Find the last contained node of prevNode, to use as the prevNode - so we only link subsequent elems in the query
- prevNodes = qsa ? prevNode.querySelectorAll(linkViewsSel) : $(linkViewsSel, prevNode).get();
- prevNode = prevNodes.length ? prevNodes[prevNodes.length - 1] : prevNode;
- }
- tagDepth = 0;
- for (i = 0; i < l; i++) {
- elem = elems[i];
- if (prevNode && !found) {
- // If prevNode is set, not false, skip linking. If this element is the prevNode, set to false so subsequent elements will link.
- found = (elem === prevNode);
- } else if (nextNode && elem === nextNode) {
- // If nextNode is set then break when we get to nextNode
- break;
- } else if (elem.parentNode
- // elem has not been removed from DOM
- && processInfos(viewInfos(elem, undefined, tags && rOpenTagMarkers))
- // If a link() call, processViewInfos() adds bindings to bindEls, and returns true for non-script nodes, for adding data-link bindings
- // If a childTags() call getViewInfos adds tag bindings to tags array.
- && elem.getAttribute($viewsLinkAttr)) {
- bindEls.push([elem]);
- }
- }
-
- // Remove temporary marker script nodes they were added by markPrevOrNextNode
- unmarkPrevOrNextNode(prevNode, elCnt);
- unmarkPrevOrNextNode(nextNode, elCnt);
-
- if (get) {
- lazyLink && lazyLink.resolve();
- return;
- }
-
- if (elCnt && defer + ids) {
- // There are some views with elCnt, for which the open or close did not precede any HTML tag - so they have not been processed yet
- elem = nextNode;
- if (defer) {
- if (nextNode) {
- processViewInfos(viewInfos(defer + "+", true), nextNode);
- } else {
- processViewInfos(viewInfos(defer, true), parentNode);
- }
- }
- processViewInfos(viewInfos(ids, true), parentNode);
- // If there were any tokens on nextNode which have now been associated with inserted HTML tags, remove them from nextNode
- if (nextNode) {
- tokens = nextNode.getAttribute(jsvAttrStr);
- if (l = tokens.indexOf(prevIds) + 1) {
- tokens = tokens.slice(l + prevIds.length - 1);
- }
- nextNode.setAttribute(jsvAttrStr, ids + tokens);
- }
- }
-
- //================ Bind the data-linked elements and tags ================
- l = bindEls.length;
- for (i = 0; i < l; i++) {
- elem = bindEls[i];
- linkInfo = elem[1];
- elem = elem[0];
- if (linkInfo) {
- tag = bindingStore[linkInfo.id];
- linkCtx = tag.linkCtx;
- tag = linkCtx ? linkCtx.tag : tag;
- // The tag may have been stored temporarily on the bindingStore - or may have already been replaced by the actual binding
- if (linkInfo.open) {
- // This is an 'open linked tag' binding annotation for a data-linked tag {^{...}}
- if (elem) {
- tag.parentElem = elem.parentNode;
- tag._prv = elem;
- }
- tag._elCnt = linkInfo.elCnt;
- if (tag && (!tag.onBeforeLink || tag.onBeforeLink() !== false) && !tag._.bound) {
- // By default we data-link depth-first ("on the way in"), which is better for perf. But if a tag needs nested tags to be linked (refreshed)
- // first, before linking its content, then make onBeforeLink() return false. In that case we data-link depth-first, so nested tags will have already refreshed.
- tag._.bound = true;
- view = tag.tagCtx.view;
- addDataBinding(undefined, tag._prv, view, view.data||outerData, linkInfo.id);
- }
-
- tag._.linking = true;
- } else {
- tag._nxt = elem;
- if (tag._.linking) {
- // This is a 'close linked tag' binding annotation
- // Add data binding
- tagCtx = tag.tagCtx;
- view = tagCtx.view;
- tag.contents = getContents;
- tag.nodes = getNodes;
- tag.childTags = getChildTags;
-
- delete tag._.linking;
- callAfterLink(tag, tagCtx);
- if (!tag._.bound) {
- tag._.bound = true;
- addDataBinding(undefined, tag._prv, view, view.data||outerData, linkInfo.id);
- }
- }
- }
- } else {
- view = $view(elem);
- // Add data binding for a data-linked element (with data-link attribute)
- addDataBinding(elem.getAttribute($viewsLinkAttr), elem, view, view.data||outerData);
- }
- }
- lazyLink && lazyLink.resolve();
- }
- //==== /end of nested functions ====
-
- var linkCtx, tag, i, l, j, len, elems, elem, view, vwInfos, vwInfo, linkInfo, prevNodes, token, prevView, nextView, node, tags, deep, tagName, tagCtx, cvt,
- tagDepth, get, depth, fragment, copiedNode, firstTag, parentTag, wrapper, div, tokens, elCnt, prevElCnt, htmlTag, ids, prevIds, found, lazyLink, linkedElem,
- noDomLevel0 = $viewsSettings.noDomLevel0,
- self = this,
- thisId = self._.id + "_",
- defer = "",
- // The marker ids for which no tag was encountered (empty views or final closing markers) which we carry over to container tag
- bindEls = [],
- tagStack = [],
- deferStack = [],
- onAfterCreate = self.hlp(onAfterCreateStr),
- processInfos = processViewInfos;
-
- if (refresh) {
- lazyLink = refresh.lazyLink && $.Deferred();
- if (refresh.tmpl) {
- // refresh is the prevView, passed in from addViews()
- prevView = "/" + refresh._.id + "_";
- } else {
- get = refresh.get;
- if (refresh.tag) {
- thisId = refresh.tag + "^";
- refresh = true;
- }
- }
- refresh = refresh === true;
- }
-
- if (get) {
- processInfos = getViewInfos;
- tags = get.tags;
- deep = get.deep;
- tagName = get.name;
- }
-
- parentNode = parentNode
- ? ("" + parentNode === parentNode
- ? $(parentNode)[0] // It is a string, so treat as selector
- : parentNode.jquery
- ? parentNode[0] // A jQuery object - take first element.
- : parentNode)
- : (self.parentElem // view.link()
- || document.body); // link(null, data) to link the whole document
-
- parentTag = parentNode.tagName.toLowerCase();
- elCnt = !!elContent[parentTag];
-
- prevNode = prevNode && markPrevOrNextNode(prevNode, elCnt);
- nextNode = nextNode && markPrevOrNextNode(nextNode, elCnt) || null;
-
- if (html !== undefined) {
- //================ Insert html into DOM using documentFragments (and wrapping HTML appropriately). ================
- // Also convert markers to DOM annotations, based on content model.
- // Corresponds to nextNode ? $(nextNode).before(html) : $(parentNode).html(html);
- // but allows insertion to wrap correctly even with inserted script nodes. jQuery version will fail e.g. under tbody or select.
- // This version should also be slightly faster
- div = document.createElement("div");
- wrapper = div;
- prevIds = ids = "";
- htmlTag = parentNode.namespaceURI === "http://www.w3.org/2000/svg" ? "svg" : (firstTag = rFirstElem.exec(html)) && firstTag[1] || "";
- if (noDomLevel0 && firstTag && firstTag[2]) {
- error("Unsupported: " + firstTag[2]); // For security reasons, don't allow insertion of elements with onFoo attributes.
- }
- if (elCnt) {
- // Now look for following view, and find its tokens, or if not found, get the parentNode._dfr tokens
- node = nextNode;
- while (node && !(nextView = viewInfos(node))) {
- node = node.nextSibling;
- }
- if (tokens = nextView ? nextView.tokens : parentNode._dfr) {
- token = prevView || "";
- if (refresh || !prevView) {
- token += "#" + thisId;
- }
- j = tokens.indexOf(token);
- if (j + 1) {
- j += token.length;
- // Transfer the initial tokens to inserted nodes, by setting them as the ids variable, picked up in convertMarkers
- prevIds = ids = tokens.slice(0, j);
- tokens = tokens.slice(j);
- if (nextView) {
- node.setAttribute(jsvAttrStr, tokens);
- } else {
- parentNode._dfr = tokens;
- }
- }
- }
- }
-
- //================ Convert the markers to DOM annotations, based on content model. ================
-// oldElCnt = elCnt;
- html = ("" + html).replace(rConvertMarkers, convertMarkers);
-// if (!!oldElCnt !== !!elCnt) {
-// error("Parse: " + html); // Parse error. Content not well-formed?
-// }
- // Append wrapper element to doc fragment
- safeFragment.appendChild(div);
-
- // Go to html and back, then peel off extra wrappers
- // Corresponds to jQuery $(nextNode).before(html) or $(parentNode).html(html);
- // but supports svg elements, and other features missing from jQuery version (and this version should also be slightly faster)
- htmlTag = wrapMap[htmlTag] || wrapMap.div;
- depth = htmlTag[0];
- wrapper.innerHTML = htmlTag[1] + html + htmlTag[2];
- while (depth--) {
- wrapper = wrapper.lastChild;
- }
- safeFragment.removeChild(div);
- fragment = document.createDocumentFragment();
- while (copiedNode = wrapper.firstChild) {
- fragment.appendChild(copiedNode);
- }
- // Insert into the DOM
- parentNode.insertBefore(fragment, nextNode);
- }
-
- if (lazyLink) {
- setTimeout(dataLink, 0);
- } else {
- dataLink();
- }
-
- return lazyLink && lazyLink.promise();
- }
-
- function addDataBinding(linkMarkup, node, currentView, data, boundTagId) {
- // Add data binding for data-linked elements or {^{...}} data-linked tags
- var tmpl, tokens, attr, convertBack, params, trimLen, tagExpr, linkFn, linkCtx, tag, rTagIndex;
-
- if (boundTagId) {
- // {^{...}} data-linked tag. So only one linkTag in linkMarkup
- tag = bindingStore[boundTagId];
- tag = tag.linkCtx ? tag.linkCtx.tag : tag;
-
- linkCtx = tag.linkCtx || {
- data: data, // source
- elem: tag._elCnt ? tag.parentElem : node, // target
- view: currentView,
- ctx: currentView.ctx,
- attr: "html", // Script marker nodes are associated with {^{ and always target HTML.
- fn: tag._.bnd,
- tag: tag,
- // Pass the boundTagId in the linkCtx, so that it can be picked up in observeAndBind
- _bndId: boundTagId
- };
- bindDataLinkTarget(linkCtx, linkCtx.fn);
- } else if (linkMarkup && node) {
- // Compiled linkFn expressions could be stored in the tmpl.links array of the template
- // TODO - consider also caching globally so that if {{:foo}} or data-link="foo" occurs in different places,
- // the compiled template for this is cached and only compiled once...
- //links = currentView.links || currentView.tmpl.links;
-
- tmpl = currentView.tmpl;
-
-// if (!(linkTags = links[linkMarkup])) {
- // This is the first time this view template has been linked, so we compile the data-link expressions, and store them on the template.
-
- linkMarkup = normalizeLinkTag(linkMarkup, node);
- rTag.lastIndex = 0;
- while (tokens = rTag.exec(linkMarkup)) { // TODO require } to be followed by whitespace or $, and remove the \}(!\}) option.
- // Iterate over the data-link expressions, for different target attrs,
- // (only one if there is a boundTagId - the case of data-linked tag {^{...}})
- // e.g. )|!--((?:[^-]|-(?!-))*)--|(\*)))\s*((?:[^}]|}(?!}))*?))})
- return this;
- })();
-
- //===============
- // Public helpers
- //===============
-
- $viewsSub.viewInfos = viewInfos;
- // Expose viewInfos() as public helper method
-
- //====================================
- // Additional members for linked views
- //====================================
-
- function transferViewTokens(prevNode, nextNode, parentElem, id, viewOrTagChar, refresh) {
- // Transfer tokens on prevNode of viewToRemove/viewToRefresh to nextNode or parentElem._dfr
- var i, l, vwInfos, vwInfo, viewOrTag, viewId, tokens,
- precedingLength = 0,
- emptyView = prevNode === nextNode;
-
- if (prevNode) {
- // prevNode is either the first node in the viewOrTag, or has been replaced by the vwInfos tokens string
- vwInfos = viewInfos(prevNode) || [];
- for (i = 0, l = vwInfos.length; i < l; i++) {
- // Step through views or tags on the prevNode
- vwInfo = vwInfos[i];
- viewId = vwInfo.id;
- if (viewId === id && vwInfo.ch === viewOrTagChar) {
- if (refresh) {
- // This is viewOrTagToRefresh, this is the last viewOrTag to process...
- l = 0;
- } else {
- // This is viewOrTagToRemove, so we are done...
- break;
- }
- }
- if (!emptyView) {
- viewOrTag = vwInfo.ch === "_"
- ? viewStore[viewId]
- : bindingStore[viewId].linkCtx.tag;
- if (vwInfo.open) {
- // A "#m" token
- viewOrTag._prv = nextNode;
- } else if (vwInfo.close) {
- // A "/m" token
- viewOrTag._nxt = nextNode;
- }
- }
- precedingLength += viewId.length + 2;
- }
-
- if (precedingLength) {
- prevNode.setAttribute(jsvAttrStr, prevNode.getAttribute(jsvAttrStr).slice(precedingLength));
- }
- tokens = nextNode ? nextNode.getAttribute(jsvAttrStr) : parentElem._dfr;
- if (l = tokens.indexOf("/" + id + viewOrTagChar) + 1) {
- tokens = vwInfos.tokens.slice(0, precedingLength) + tokens.slice(l + (refresh ? -1 : id.length + 1));
- }
- if (tokens) {
- if (nextNode) {
- // If viewOrTagToRemove was an empty viewOrTag, we will remove both #n and /n
- // (and any intervening tokens) from the nextNode (=== prevNode)
- // If viewOrTagToRemove was not empty, we will take tokens preceding #n from prevNode,
- // and concatenate with tokens following /n on nextNode
- nextNode.setAttribute(jsvAttrStr, tokens);
- } else {
- parentElem._dfr = tokens;
- }
- }
- } else {
- // !prevNode, so there may be a deferred nodes token on the parentElem. Remove it.
- parentElem._dfr = removeSubStr(parentElem._dfr, "#" + id + viewOrTagChar);
- if (!refresh && !nextNode) {
- // If this viewOrTag is being removed, and there was no .nxt, remove closing token from deferred tokens
- parentElem._dfr = removeSubStr(parentElem._dfr, "/" + id + viewOrTagChar);
- }
- }
- }
-
- LinkedView = {
- // Note: a linked view will also, after linking have nodes[], _prv (prevNode), _nxt (nextNode) ...
- addViews: function(index, dataItems, tmpl) {
- // if view is not an array view, do nothing
- var i, viewsCount,
- self = this,
- itemsCount = dataItems.length,
- views = self.views;
-
- if (!self._.useKey && itemsCount && (tmpl = self.tmpl)) {
- // view is of type "array"
- // Use passed-in template if provided, since self added view may use a different template than the original one used to render the array.
- viewsCount = views.length + itemsCount;
-
- if (renderAndLink(self, index, tmpl, views, dataItems, self.ctx) !== false) {
- for (i = index + itemsCount; i < viewsCount; i++) {
- $observable(views[i]).setProperty("index", i);
- //This is fixing up index, but not key, and not index on child views. From child views, use view.get("item").index.
- }
- }
- }
- return self;
- },
-
- removeViews: function(index, itemsCount, keepNodes) {
- // view.removeViews() removes all the child views
- // view.removeViews( index ) removes the child view with specified index or key
- // view.removeViews( index, count ) removes the specified nummber of child views, starting with the specified index
- function removeView(index) {
- var id, bindId, parentElem, prevNode, nextNode, nodesToRemove,
- viewToRemove = views[index];
-
- if (viewToRemove && viewToRemove.link) {
- id = viewToRemove._.id;
- if (!keepNodes) {
- // Remove the HTML nodes from the DOM, unless they have already been removed, including nodes of child views
- nodesToRemove = viewToRemove.nodes();
- }
-
- // Remove child views, without removing nodes
- viewToRemove.removeViews(undefined, undefined, true);
-
- viewToRemove.data = undefined; // Set data to undefined: used as a flag that this view is being removed
- prevNode = viewToRemove._prv;
- nextNode = viewToRemove._nxt;
- parentElem = viewToRemove.parentElem;
- // If prevNode and nextNode are the same, the view is empty
- if (!keepNodes) {
- // Remove the HTML nodes from the DOM, unless they have already been removed, including nodes of child views
- if (viewToRemove._elCnt) {
- // if keepNodes is false (and transferring of tokens has not already been done at a higher level)
- // then transfer tokens from prevNode which is being removed, to nextNode.
- transferViewTokens(prevNode, nextNode, parentElem, id, "_");
- }
- $(nodesToRemove).remove();
- }
- if (!viewToRemove._elCnt) {
- prevNode.parentNode && parentElem.removeChild(prevNode);
- nextNode.parentNode && parentElem.removeChild(nextNode);
- }
- setArrayChangeLink(viewToRemove);
- for (bindId in viewToRemove._.bnds) {
- removeViewBinding(bindId);
- }
- delete viewStore[id];
- }
- }
-
- var current, view, viewsCount,
- self = this,
- isArray = !self._.useKey,
- views = self.views;
-
- if (isArray) {
- viewsCount = views.length;
- }
- if (index === undefined) {
- // Remove all child views
- if (isArray) {
- // views and data are arrays
- current = viewsCount;
- while (current--) {
- removeView(current);
- }
- self.views = [];
- } else {
- // views and data are objects
- for (view in views) {
- // Remove by key
- removeView(view);
- }
- self.views = {};
- }
- } else {
- if (itemsCount === undefined) {
- if (isArray) {
- // The parentView is data array view.
- // Set itemsCount to 1, to remove this item
- itemsCount = 1;
- } else {
- // Remove child view with key 'index'
- removeView(index);
- delete views[index];
- }
- }
- if (isArray && itemsCount) {
- current = index + itemsCount;
- // Remove indexed items (parentView is data array view);
- while (current-- > index) {
- removeView(current);
- }
- views.splice(index, itemsCount);
- if (viewsCount = views.length) {
- // Fixup index on following view items...
- while (index < viewsCount) {
- $observable(views[index]).setProperty("index", index++);
- }
- }
- }
- }
- return this;
- },
-
- refresh: function(context) {
- var self = this,
- parent = self.parent;
-
- if (parent) {
- renderAndLink(self, self.index, self.tmpl, parent.views, self.data, context, true);
- setArrayChangeLink(self);
- }
- return self;
- },
-
- nodes: getNodes,
- contents: getContents,
- childTags: getChildTags,
- link: viewLink
- };
-
- //=========================
- // Extend $.views.settings
- //=========================
-
- $viewsSettings.merge = {
- input: {
- from: { fromAttr: inputAttrib }, to: { toAttr: "value" }
- },
- textarea: valueBinding,
- select: valueBinding,
- optgroup: {
- from: { fromAttr: "label" }, to: { toAttr: "label" }
- }
- };
-
- if ($viewsSettings.debugMode) {
- // In debug mode create global for accessing views, etc
- validate = !$viewsSettings.noValidate;
- global._jsv = {
- views: viewStore,
- bindings: bindingStore
- };
- }
-
- //========================
- // Extend jQuery namespace
- //========================
-
- $extend($, {
-
- //=======================
- // jQuery $.view() plugin
- //=======================
-
- view: $views.view = $view = function(node, inner, type) {
- // $.view() returns top view
- // $.view(node) returns view that contains node
- // $.view(selector) returns view that contains first selected element
- // $.view(nodeOrSelector, type) returns nearest containing view of given type
- // $.view(nodeOrSelector, "root") returns root containing view (child of top view)
- // $.view(nodeOrSelector, true, type) returns nearest inner (contained) view of given type
-
- if (inner !== !!inner) {
- // inner not boolean, so this is view(nodeOrSelector, type)
- type = inner;
- inner = undefined;
- }
- var view, vwInfos, i, j, k, l, elem, elems,
- level = 0,
- body = document.body;
-
- if (node && node !== body && topView._.useKey > 1) {
- // Perf optimization for common cases
-
- node = "" + node === node
- ? $(node)[0]
- : node.jquery
- ? node[0]
- : node;
-
- if (node) {
- if (inner) {
- // Treat supplied node as a container element and return the first view encountered.
- elems = qsa ? node.querySelectorAll(bindElsSel) : $(bindElsSel, node).get();
- l = elems.length;
- for (i = 0; i < l; i++) {
- elem = elems[i];
- vwInfos = viewInfos(elem, undefined, rOpenViewMarkers);
-
- for (j = 0, k = vwInfos.length; j < k; j++) {
- view = vwInfos[j];
- if (view = viewStore[view.id]) {
- view = view && type ? view.get(true, type) : view;
- if (view) {
- return view;
- }
- }
- }
- }
- } else {
- while (node) {
- // Move back through siblings and up through parents to find preceding node which is a _prv (prevNode)
- // script marker node for a non-element-content view, or a _prv (first node) for an elCnt view
- if (vwInfos = viewInfos(node, undefined, rViewMarkers)) {
- l = vwInfos.length;
- while (l--) {
- view = vwInfos[l];
- if (view.open) {
- if (level < 1) {
- view = viewStore[view.id];
- return view && type ? view.get(type) : view || topView;
- }
- level--;
- } else {
- // level starts at zero. If we hit a view.close, then we move level to 1, and we don't return a view until
- // we are back at level zero (or a parent view with level < 0)
- level++;
- }
- }
- }
- node = node.previousSibling || node.parentNode;
- }
- }
- }
- }
- return inner ? undefined : topView;
- },
-
- link: $views.link = $link,
- unlink: $views.unlink = $unlink,
-
- //=====================
- // override $.cleanData
- //=====================
- cleanData: function(elems) {
- if (elems.length) {
- // Remove JsViews bindings. Also, remove from the DOM any corresponding script marker nodes
- clean(elems);
- // (elems HTMLCollection no longer includes removed script marker nodes)
- oldCleanData.call($, elems);
- }
- }
- });
-
- //===============================
- // Extend jQuery instance plugins
- //===============================
-
- $extend($.fn, {
- link: function(expr, from, context, parentView, prevNode, nextNode) {
- return $link(expr, this, from, context, parentView, prevNode, nextNode);
- },
- unlink: function(expr) {
- return $unlink(expr, this);
- },
- view: function(type) {
- return $view(this[0], type);
- }
- });
-
- //===============
- // Extend topView
- //===============
-
- $extend(topView, { tmpl: { links: {}, tags: {} }});
- $extend(topView, LinkedView);
- topView._.onRender = addBindingMarkers;
-
-})(this, this.jQuery);
diff --git a/nano/js/nano_base_helpers.js b/nano/js/nano_base_helpers.js
index 721795c09e4..53b539f75ac 100644
--- a/nano/js/nano_base_helpers.js
+++ b/nano/js/nano_base_helpers.js
@@ -14,14 +14,17 @@ NanoBaseHelpers = function ()
var initHelpers = function ()
{
- $.views.helpers({
+ $.views.helpers({
+
// Generate a Byond link
link: function( text, icon, parameters, status, elementClass, elementId) {
var iconHtml = '';
+ var iconClass = 'noIcon';
if (typeof icon != 'undefined' && icon)
{
- iconHtml = '';
+ iconHtml = '';
+ iconClass = 'hasIcon';
}
if (typeof elementClass == 'undefined' || !elementClass)
@@ -37,10 +40,10 @@ NanoBaseHelpers = function ()
if (typeof status != 'undefined' && status)
{
- return '
' + iconHtml + text + '
';
+ return '
' + iconHtml + text + '
';
}
- return '
' + iconHtml + text + '
';
+ return '
' + iconHtml + text + '
';
},
// Round a number to the nearest integer
round: function(number) {
@@ -114,9 +117,63 @@ NanoBaseHelpers = function ()
var percentage = Math.round((value - rangeMin) / (rangeMax - rangeMin) * 100);
return '
' + showText + '
';
+ },
+ // Display DNA Blocks (for the DNA Modifier UI)
+ displayDNABlocks: function(dnaString, selectedBlock, selectedSubblock, blockSize, paramKey) {
+ if (!dnaString)
+ {
+ return '
Please place a valid subject into the DNA modifier.
';
+ }
+
+ var characters = dnaString.split('');
+
+ var html = '
1
';
+ var block = 1;
+ var subblock = 1;
+ for (index in characters)
+ {
+ if (!characters.hasOwnProperty(index) || typeof characters[index] === 'object')
+ {
+ continue;
+ }
+
+ var parameters;
+ if (paramKey.toUpperCase() == 'UI')
+ {
+ parameters = { 'selectUIBlock' : block, 'selectUISubblock' : subblock };
+ }
+ else
+ {
+ parameters = { 'selectSEBlock' : block, 'selectSESubblock' : subblock };
+ }
+
+ var status = 'linkActive';
+ if (block == selectedBlock && subblock == selectedSubblock)
+ {
+ status = 'selected';
+ }
+
+ html += '
' + characters[index] + '
'
+
+ index++;
+ if (index % blockSize == 0 && index < characters.length)
+ {
+ block++;
+ subblock = 1;
+ html += '
';
+
+ return html;
}
});
- }
+ };
// generate a Byond href, combines _urlParameters with parameters
var generateHref = function (parameters)
@@ -147,7 +204,7 @@ NanoBaseHelpers = function ()
}
}
return queryString;
- }
+ };
return {
init: function ()
diff --git a/nano/js/nano_config.js b/nano/js/nano_config.js
index 7766b64a4b5..8352b197ccf 100644
--- a/nano/js/nano_config.js
+++ b/nano/js/nano_config.js
@@ -4,7 +4,12 @@ var NanoConfig = function ()
return {
init: function ()
{
-
+ if (typeof jQuery == 'undefined') {
+ alert('ERROR: jQuery failed to load!');
+ }
+ if (typeof $.views == 'undefined') {
+ alert('ERROR: JSRender failed to load!');
+ }
}
}
} ();
@@ -32,7 +37,7 @@ if (!Array.prototype.indexOf)
}
return -1;
};
-}
+};
if (!String.prototype.format)
{
@@ -54,7 +59,7 @@ if (!String.prototype.format)
});
};
String.prototype.format.regex = new RegExp("{-?[0-9]+}", "g");
-}
+};
Object.size = function(obj) {
var size = 0, key;
@@ -70,7 +75,7 @@ if(!window.console) {
return false;
}
};
-}
+};
String.prototype.toTitleCase = function () {
var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|vs?\.?|via)$/i;
diff --git a/nano/js/nano_update.js b/nano/js/nano_update.js
index 47f1ee6ee52..cb2eee021d7 100644
--- a/nano/js/nano_update.js
+++ b/nano/js/nano_update.js
@@ -23,6 +23,8 @@ NanoUpdate = function ()
// this function sets up the templates and base functionality
var init = function ()
{
+ $('#uiNoJavaScript').html('Loading...');
+
// this callback is triggered after new data is processed
// it updates the status/visibility icon and adds click event handling to buttons/links
NanoUpdate.addAfterUpdateCallback(function (updateData) {
@@ -71,9 +73,9 @@ NanoUpdate = function ()
// We store initialData and templateData in the body tag, it's as good a place as any
var body = $('body');
var templateData = body.data('templateData');
- _data = body.data('initialData');
+ var initialData = body.data('initialData');
- if (!templateData || !_data)
+ if (templateData == null || !initialData == null)
{
alert('Error: Initial data did not load correctly.');
}
@@ -88,44 +90,52 @@ NanoUpdate = function ()
}
}
- // load each template file and render it using _data
+ if (!templateCount)
+ {
+ alert('ERROR: No templates listed!');
+ }
+
+ // load markup for each template and register it
for (var key in templateData)
{
if (templateData.hasOwnProperty(key))
{
$.when($.get(templateData[key]))
- .done(function(templateData) {
+ .done(function(templateMarkup) {
if (_templates == null)
{
_templates = {};
}
- templateData += ''
+ templateMarkup = templateMarkup.replace(/ +\) *\}\}/g, ')}}');
+
+ templateMarkup += ''
try
{
- _templates[key] = $.templates(templateData);
- _templates[key].link( "#mainTemplate", _data ); // initial data gets applied first, before any updates
+ _templates[key] = $.templates(key, templateMarkup);
templateCount--;
if (templateCount <= 0)
{
+ if (_earlyUpdateData !== null) // Newer data has already arrived, so update
+ {
+ renderTemplates(_earlyUpdateData);
+ }
+ else
+ {
+ renderTemplates(initialData);
+ }
_isInitialised = true;
+ $('#uiNoJavaScript').hide();
}
-
- if (_earlyUpdateData !== null) // Newer data has already arrived, so update
- {
- observedDataUpdateRecursive(_earlyUpdateData, _data);
- }
executeCallbacks(_afterUpdateCallbacks, _data);
-
- //alert($("#mainTemplate").html());
}
catch(error)
{
- alert('An error occurred while loading the UI: ' + error.message);
+ alert('ERROR: An error occurred while loading the UI: ' + error.message);
return;
}
});
@@ -149,50 +159,43 @@ NanoUpdate = function ()
}
- if (_isInitialised) // templates have been loaded and are observing the data. We need to update it recursively
+ if (_isInitialised) // all templates have been registered, so render them
{
executeCallbacks(_beforeUpdateCallbacks, updateData);
- observedDataUpdateRecursive(updateData, _data);
+ renderTemplates(updateData);
executeCallbacks(_afterUpdateCallbacks, updateData);
}
else
{
- _earlyUpdateData = updateData; // templates have not been loaded, therefor they are not observing the data. We set _earlyUpdateData which will be applied after the template is loaded with the initial data
+ _earlyUpdateData = updateData; // all templates have not been registered. We set _earlyUpdateData which will be applied after the template is loaded with the initial data
}
- }
+ };
- // This function updates the observed data recursively
+ // This function renders the template with the latest data
// It has to be done recursively as each piece of data is observed individually and needs to be updated individually
- var observedDataUpdateRecursive = function (updateData, data, path)
+ var renderTemplates = function (data)
{
- if (path === null || typeof path === 'undefined')
+ if (!_templates.hasOwnProperty("main"))
{
- path = '';
+ alert('Error: Main template not found.');
}
- else
+
+ _data = data;
+
+ try
{
- path += '.';
+ $("#mainTemplate").html(_templates["main"].render(_data));
}
- for (var key in updateData)
+ catch(error)
{
- if (updateData.hasOwnProperty(key))
- {
- var currentPath = path + key;
- if (updateData[key] != null && typeof updateData[key] === 'object' && !$.isArray(updateData[key]))
- {
- observedDataUpdateRecursive(updateData[key], data, currentPath)
- }
- else
- {
- $.observable(data).setProperty(currentPath, updateData[key]);
- }
- }
- }
- }
+ alert('ERROR: An error occurred while rendering the UI: ' + error.message);
+ return;
+ }
+ };
- // execute all callbacks in the callbacks array/object provided, updateData is passed to them for processing
+ // Execute all callbacks in the callbacks array/object provided, updateData is passed to them for processing
var executeCallbacks = function (callbacks, updateData)
{
for (var index in callbacks)
@@ -201,7 +204,7 @@ NanoUpdate = function ()
}
return updateData;
- }
+ };
return {
init: function ()
diff --git a/nano/templates/TemplatesGuide.txt b/nano/templates/TemplatesGuide.txt
index 3cef9b91287..3b042edd0b0 100644
--- a/nano/templates/TemplatesGuide.txt
+++ b/nano/templates/TemplatesGuide.txt
@@ -7,7 +7,4 @@ to easily add conditionals (if statements), loops (for loops) and custom formatt
Templates are stored in the /nano/templates folder and the file extension is .tmpl.
-This guide is a work in progress. However the templating system is "JSRender", and documentation for it's
-markup syntax can be found here: http://www.jsviews.com/#jsrtags
-
-
+This guide is being replaced with a wiki entry, found here: http://baystation12.net/wiki/index.php?title=NanoUI
\ No newline at end of file
diff --git a/nano/templates/apc.tmpl b/nano/templates/apc.tmpl
index b57829f397f..ec7a576fc8e 100644
--- a/nano/templates/apc.tmpl
+++ b/nano/templates/apc.tmpl
@@ -1,14 +1,14 @@
{{else}}
- {^{if locked}}
+ {{if locked}}
Swipe an ID card to unlock this interface.
{{else}}
Swipe an ID card to lock this interface.
@@ -18,162 +18,162 @@
\ No newline at end of file
diff --git a/nano/templates/chem_dispenser.tmpl b/nano/templates/chem_dispenser.tmpl
index 9d9f6525fd4..10f1e1206f0 100644
--- a/nano/templates/chem_dispenser.tmpl
+++ b/nano/templates/chem_dispenser.tmpl
@@ -7,7 +7,7 @@ Used In File(s): \code\modules\reagents\Chemistry-Machinery.dm
Energy:
- {^{:~displayBar(energy, 0, maxEnergy, 'good', energy + ' Units')}}
+ {{:~displayBar(energy, 0, maxEnergy, 'good', energy + ' Units')}}
@@ -16,11 +16,11 @@ Used In File(s): \code\modules\reagents\Chemistry-Machinery.dm
Dispense: