diff --git a/code/modules/client/client defines.dm b/code/modules/client/client defines.dm
index 34227334aa5..8b315661a34 100644
--- a/code/modules/client/client defines.dm
+++ b/code/modules/client/client defines.dm
@@ -48,7 +48,7 @@
preload_rsc = 1 // This is 0 so we can set it to an URL once the player logs in and have them download the resources from a different server.
var/global/obj/screen/click_catcher/void
-
+
var/karma = 0
var/karma_spent = 0
var/karma_tab = 0
@@ -76,4 +76,6 @@
"off" = "borgmacro")
)
- var/reset_stretch = 0 //Used by things that fiddle with client's stretch-to-fit.
\ No newline at end of file
+ var/reset_stretch = 0 //Used by things that fiddle with client's stretch-to-fit.
+
+ var/topic_debugging = 0 //if set to true, allows client to see nanoUI errors -- yes i realize this is messy but it'll make live testing infinitely easier
\ No newline at end of file
diff --git a/code/modules/client/client procs.dm b/code/modules/client/client procs.dm
index eb514bddba2..6ddc2d51241 100644
--- a/code/modules/client/client procs.dm
+++ b/code/modules/client/client procs.dm
@@ -29,11 +29,12 @@
#if defined(TOPIC_DEBUGGING)
world << "[src]'s Topic: [href] destined for [hsrc]."
+ #endif
if(href_list["nano_err"]) //nano throwing errors
- world << "## NanoUI, Subject [src]: " + html_decode(href_list["nano_err"]) //NANO DEBUG HOOK
+ if(topic_debugging)
+ src << "## NanoUI: " + html_decode(href_list["nano_err"]) //NANO DEBUG HOOK
- #endif
if(href_list["asset_cache_confirm_arrival"])
//src << "ASSET JOB [href_list["asset_cache_confirm_arrival"]] ARRIVED."
diff --git a/nano/Gulpfile.coffee b/nano/Gulpfile.coffee
index 804f2d1fe4e..fbd8abd45fc 100644
--- a/nano/Gulpfile.coffee
+++ b/nano/Gulpfile.coffee
@@ -51,11 +51,17 @@ gulp.task "fonts", ["clean"], ->
gulp.task "scripts", ["clean"], ->
lib = gulp.src glob input.scripts.lib
+ .pipe g.order(["jquery.js",
+ "jquery*.js",
+ "*.js"])
.pipe g.concat(output.scripts.lib)
.pipe g.if(s.min, g.uglify().on('error', util.log))
.pipe gulp.dest output.dir
main = gulp.src glob input.scripts.main
+ .pipe g.order(["nano_utility.js",
+ "nano_state_manager.js"
+ "*.js"])
.pipe g.concat(output.scripts.main)
.pipe g.if(s.min, g.uglify().on('error', util.log))
.pipe gulp.dest output.dir
diff --git a/nano/assets/nano.js b/nano/assets/nano.js
index 7e8190f4176..b685fdfc0f0 100644
--- a/nano/assets/nano.js
+++ b/nano/assets/nano.js
@@ -1 +1 @@
-function NanoStateClass(){}function NanoStateDefaultClass(){this.key="default",this.key=this.key.toLowerCase(),NanoStateManager.addState(this)}var NanoUtility=function(){var e={};return{init:function(){var t=$("body");e=t.data("urlParameters")},generateHref:function(t){var a="?";for(var n in e)e.hasOwnProperty(n)&&("?"!==a&&(a+=";"),a+=n+"="+e[n]);for(var n in t)t.hasOwnProperty(n)&&("?"!==a&&(a+=";"),a+=n+"="+t[n]);return a}}}();"undefined"==typeof jQuery&&alert("ERROR: Javascript library failed to load!"),"undefined"==typeof doT&&alert("ERROR: Template engine failed to load!"),function(){var e=window.alert;window.alert=function(t){window.location="byond://?nano_err="+encodeURIComponent(t),e(t)}}(),$(document).ready(function(){NanoUtility.init(),NanoStateManager.init(),NanoTemplate.init()}),Array.prototype.indexOf||(Array.prototype.indexOf=function(e){var t=this.length,a=Number(arguments[1])||0;for(a=0>a?Math.ceil(a):Math.floor(a),0>a&&(a+=t);t>a;a++)if(a in this&&this[a]===e)return a;return-1}),String.prototype.format||(String.prototype.format=function(e){var t=this;return t.replace(String.prototype.format.regex,function(t){var a,n=parseInt(t.substring(1,t.length-1));return a=n>=0?e[n]:-1===n?"{":-2===n?"}":""})},String.prototype.format.regex=new RegExp("{-?[0-9]+}","g")),Object.size=function(e){var t,a=0;for(var t in e)e.hasOwnProperty(t)&&a++;return a},window.console||(window.console={log:function(e){return!1}}),String.prototype.toTitleCase=function(){var e=/^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|vs?\.?|via)$/i;return this.replace(/([^\W_]+[^\s-]*) */g,function(t,a,n,r){return n>0&&n+a.length!==r.length&&a.search(e)>-1&&":"!==r.charAt(n-2)&&r.charAt(n-1).search(/[^\s-]/)<0?t.toLowerCase():a.substr(1).search(/[A-Z]|\../)>-1?t:t.charAt(0).toUpperCase()+t.substr(1)})},$.ajaxSetup({cache:!1}),Function.prototype.inheritsFrom=function(e){return this.prototype=new e,this.prototype.constructor=this,this.prototype.parent=e.prototype,this},String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),String.prototype.ckey||(String.prototype.ckey=function(){return this.replace(/\W/g,"").toLowerCase()});var NanoTemplate=function(){var e={},t={},a={},n={},r=function(){e=$("body").data("templateData"),null==e&&alert("Error: Template data did not load correctly."),o()},o=function(){var t=Object.size(e);if(!t)return void $(document).trigger("templatesLoaded");for(var a in e)if(e.hasOwnProperty(a))return void $.when($.ajax({url:e[a],cache:!1,dataType:"text"})).done(function(t){t+='
';try{NanoTemplate.addTemplate(a,t)}catch(n){return void alert("ERROR: An error occurred while loading the UI: "+n.message)}delete e[a],o()}).fail(function(){alert("ERROR: Loading template "+a+"("+e[a]+") failed!")})},i=function(){for(var e in t)try{a[e]=doT.template(t[e],null,t)}catch(n){alert(n.message)}};return{init:function(){r()},addTemplate:function(e,a){t[e]=a},templateExists:function(e){return t.hasOwnProperty(e)},parse:function(e,r){if(!a.hasOwnProperty(e)||!a[e]){if(!t.hasOwnProperty(e))return alert('ERROR: Template "'+e+'" does not exist in _compiledTemplates!'),"Template error (does not exist)
";i()}return"function"!=typeof a[e]?(alert(a[e]),alert('ERROR: Template "'+e+'" failed to compile!'),"Template error (failed to compile)
"):a[e].call(this,r.data,r.config,n)},addHelper:function(e,t){return jQuery.isFunction(t)?void(n[e]=t):void alert("NanoTemplate.addHelper failed to add "+e+" as it is not a function.")},addHelpers:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.addHelper(t,e[t])},removeHelper:function(e){helpers.hasOwnProperty(e)&&delete n[e]}}}();NanoStateManager=function(){var e=!1,t=null,a={},n={},r={},o=null,i=function(){t=$("body").data("initialData"),null!=t&&t.hasOwnProperty("config")&&t.hasOwnProperty("data")||alert("Error: Initial data did not load correctly.");var a="default";t.config.hasOwnProperty("stateKey")&&t.config.stateKey&&(a=t.config.stateKey.toLowerCase()),NanoStateManager.setCurrentState(a),$(document).on("templatesLoaded",function(){l(t),e=!0})},s=function(a){var n;try{n=jQuery.parseJSON(a)}catch(r){return void alert("recieveUpdateData failed.
Error name: "+r.name+"
Error Message: "+r.message)}n.hasOwnProperty("data")||(t&&t.hasOwnProperty("data")?n.data=t.data:n.data={}),e?l(n):t=n},l=function(e){if(null!=o){if(e=o.onBeforeUpdate(e),e===!1)return void alert("data is false, return");t=e,o.onUpdate(t),o.onAfterUpdate(t)}},d=function(e,t){for(var a in e)e.hasOwnProperty(a)&&jQuery.isFunction(e[a])&&(t=e[a].call(this,t));return t};return{init:function(){i()},receiveUpdateData:function(e){s(e)},addBeforeUpdateCallback:function(e,t){a[e]=t},addBeforeUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addBeforeUpdateCallback(t,e[t])},removeBeforeUpdateCallback:function(e){a.hasOwnProperty(e)&&delete a[e]},executeBeforeUpdateCallbacks:function(e){return d(a,e)},addAfterUpdateCallback:function(e,t){n[e]=t},addAfterUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addAfterUpdateCallback(t,e[t])},removeAfterUpdateCallback:function(e){n.hasOwnProperty(e)&&delete n[e]},executeAfterUpdateCallbacks:function(e){return d(n,e)},addState:function(e){return e instanceof NanoStateClass?e.key?void(r[e.key]=e):void alert("ERROR: Attempted to add a state with an invalid stateKey"):void alert("ERROR: Attempted to add a state which is not instanceof NanoStateClass")},setCurrentState:function(e){if("undefined"==typeof e||!e)return alert("ERROR: No state key was passed!"),!1;if(!r.hasOwnProperty(e))return alert("ERROR: Attempted to set a current state which does not exist: "+e),!1;var t=o;return o=r[e],null!=t&&t.onRemove(o),o.onAdd(t),!0},getCurrentState:function(){return o}}}(),NanoStateClass.prototype.key=null,NanoStateClass.prototype.layoutRendered=!1,NanoStateClass.prototype.contentRendered=!1,NanoStateClass.prototype.mapInitialised=!1,NanoStateClass.prototype.isCurrent=function(){return NanoStateManager.getCurrentState()==this},NanoStateClass.prototype.onAdd=function(e){NanoBaseCallbacks.addCallbacks(),NanoBaseHelpers.addHelpers()},NanoStateClass.prototype.onRemove=function(e){NanoBaseCallbacks.removeCallbacks(),NanoBaseHelpers.removeHelpers()},NanoStateClass.prototype.onBeforeUpdate=function(e){return e=NanoStateManager.executeBeforeUpdateCallbacks(e)},NanoStateClass.prototype.onUpdate=function(e){try{(!this.layoutRendered||e.config.hasOwnProperty("autoUpdateLayout")&&e.config.autoUpdateLayout)&&($("#uiLayout").html(NanoTemplate.parse("layout",e)),this.layoutRendered=!0),(!this.contentRendered||e.config.hasOwnProperty("autoUpdateContent")&&e.config.autoUpdateContent)&&($("#uiContent").html(NanoTemplate.parse("main",e)),this.contentRendered=!0),NanoTemplate.templateExists("mapContent")&&(this.mapInitialised||($("#uiMap").draggable(),$("#uiMapTooltip").off("click").on("click",function(e){e.preventDefault(),$(this).fadeOut(400)}),this.mapInitialised=!0),$("#uiMapContent").html(NanoTemplate.parse("mapContent",e)),e.config.hasOwnProperty("showMap")&&e.config.showMap?($("#uiContent").addClass("hidden"),$("#uiMapWrapper").removeClass("hidden")):($("#uiMapWrapper").addClass("hidden"),$("#uiContent").removeClass("hidden"))),NanoTemplate.templateExists("mapHeader")&&$("#uiMapHeader").html(NanoTemplate.parse("mapHeader",e)),NanoTemplate.templateExists("mapFooter")&&$("#uiMapFooter").html(NanoTemplate.parse("mapFooter",e))}catch(t){return void alert("ERROR: An error occurred while rendering the UI: "+t.message)}},NanoStateClass.prototype.onAfterUpdate=function(e){NanoStateManager.executeAfterUpdateCallbacks(e)},NanoStateClass.prototype.alertText=function(e){alert(e)},NanoStateDefaultClass.inheritsFrom(NanoStateClass);var NanoStateDefault=new NanoStateDefaultClass;NanoBaseCallbacks=function(){var e=!0,t={},a={status:function(t){var a;return 2==t.config.status?(a="good",$(".linkActive").removeClass("inactive")):1==t.config.status?(a="average",$(".linkActive").addClass("inactive")):(a="bad",$(".linkActive").addClass("inactive")),$(".statusicon").each(function(e,t){t.className=t.className.replace(/good|bad|average/g,""),t.classList.add(a)}),$(".linkActive").stopTime("linkPending"),$(".linkActive").removeClass("linkPending"),$(".linkActive").off("click").on("click",function(a){a.preventDefault();var n=$(this).data("href");null!=n&&e&&(e=!1,$("body").oneTime(300,"enableClick",function(){e=!0}),2==t.config.status&&$(this).oneTime(300,"linkPending",function(){$(this).addClass("linkPending")}),window.location.href=n)}),t},nanomap:function(e){return $(".mapIcon").off("mouseenter mouseleave").on("mouseenter",function(e){$("#uiMapTooltip").html($(this).children(".tooltip").html()).show().stopTime().oneTime(5e3,"hideTooltip",function(){$(this).fadeOut(500)})}),$(".zoomLink").off("click").on("click",function(e){e.preventDefault();var t=$(this).data("zoomLevel"),a=$("#uiMap"),n=a.width()*t,r=a.height()*t;a.css({zoom:t,left:"50%",top:"50%",marginLeft:"-"+Math.floor(n/2)+"px",marginTop:"-"+Math.floor(r/2)+"px"})}),$("#uiMapImage").attr("src","nanomap_z"+e.config.mapZLevel+".png"),e}};return{addCallbacks:function(){NanoStateManager.addBeforeUpdateCallbacks(t),NanoStateManager.addAfterUpdateCallbacks(a)},removeCallbacks:function(){for(var e in t)t.hasOwnProperty(e)&&NanoStateManager.removeBeforeUpdateCallback(e);for(var e in a)a.hasOwnProperty(e)&&NanoStateManager.removeAfterUpdateCallback(e)}}}(),NanoBaseHelpers=function(){var e={syndicateMode:function(){return $("body").css("background-color","#8f1414"),$("body").css("background-image","url('uiBackground-Syndicate.png')"),$("body").css("background-position","50% 0"),$("body").css("background-repeat","repeat-x"),$("#uiTitleFluff").css("background-image","url('uiTitleFluff-Syndicate.png')"),$("#uiTitleFluff").css("background-position","50% 50%"),$("#uiTitleFluff").css("background-repeat","no-repeat"),""},combine:function(e,t){return e&&t?e.concat(t):e||t},dump:function(e){return JSON.stringify(e)},link:function(e,t,a,n,r,o){var i="",s="noIcon";"undefined"!=typeof t&&t&&(i='',s="hasIcon"),"undefined"!=typeof r&&r||(r="link");var l="";return"undefined"!=typeof o&&o&&(l='id="'+o+'"'),"undefined"!=typeof n&&n?'"+i+e+"
":'"+i+e+"
"},xor:function(e,t){return e^t},precisionRound:function(e,t){if(0==t)return Math.round(number);var a=Math.pow(10,t);return Math.round(e*a)/a},round:function(e){return Math.round(e)},fixed:function(e){return Math.round(10*e)/10},floor:function(e){return Math.floor(e)},ceil:function(e){return Math.ceil(e)},string:function(){if(0==arguments.length)return"";if(1==arguments.length)return arguments[0];if(arguments.length>1){stringArgs=[];for(var e=1;et?t>e?e=t:e>a&&(e=a):e>t?e=t:a>e&&(e=a),"undefined"!=typeof n&&n||(n=""),"undefined"!=typeof r&&r||(r="");var o=Math.round((e-t)/(a-t)*100);return'"},dangerToClass:function(e){return 0==e?"good":1==e?"average":"bad"},dangerToSpan:function(e){return 0==e?'"Good"':1==e?'"Minor Alert"':'"Major Alert"'},generateHref:function(e){var t=$("body");_urlParameters=t.data("urlParameters");var a="?";for(var n in _urlParameters)_urlParameters.hasOwnProperty(n)&&("?"!==a&&(a+=";"),a+=n+"="+_urlParameters[n]);for(var n in e)e.hasOwnProperty(n)&&("?"!==a&&(a+=";"),a+=n+"="+e[n]);return a},displayDNABlocks:function(e,t,a,n,r){if(!e)return'Please place a valid subject into the DNA modifier.
';var o=e.split(""),i='1
',s=1,l=1;for(index in o)if(o.hasOwnProperty(index)&&"object"!=typeof o[index]){var d;d="UI"==r.toUpperCase()?{selectUIBlock:s,selectUISubblock:l}:{selectSEBlock:s,selectSESubblock:l};var c="linkActive";s==t&&l==a&&(c="selected"),i+='
'+o[index]+"
",index++,index%n==0&&index
"},cMirror:function(e){if(!e)return"ERR - NO domID provided";var t='"}};return{addHelpers:function(){NanoTemplate.addHelpers(e)},removeHelpers:function(){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.removeHelper(t)}}}();
\ No newline at end of file
+function NanoStateDefaultClass(){this.key="default",this.key=this.key.toLowerCase(),NanoStateManager.addState(this)}function NanoStateClass(){}var NanoUtility=function(){var e={};return{init:function(){var t=$("body");e=t.data("urlParameters")},generateHref:function(t){var a="?";for(var r in e)e.hasOwnProperty(r)&&("?"!==a&&(a+=";"),a+=r+"="+e[r]);for(var r in t)t.hasOwnProperty(r)&&("?"!==a&&(a+=";"),a+=r+"="+t[r]);return a}}}();"undefined"==typeof jQuery&&reportError("ERROR: Javascript library failed to load!"),"undefined"==typeof doT&&reportError("ERROR: Template engine failed to load!");var reportError=function(e){window.location="byond://?nano_err="+encodeURIComponent(e),alert(e)};$(document).ready(function(){NanoUtility.init(),NanoStateManager.init(),NanoTemplate.init()}),Array.prototype.indexOf||(Array.prototype.indexOf=function(e){var t=this.length,a=Number(arguments[1])||0;for(a=0>a?Math.ceil(a):Math.floor(a),0>a&&(a+=t);t>a;a++)if(a in this&&this[a]===e)return a;return-1}),String.prototype.format||(String.prototype.format=function(e){var t=this;return t.replace(String.prototype.format.regex,function(t){var a,r=parseInt(t.substring(1,t.length-1));return a=r>=0?e[r]:-1===r?"{":-2===r?"}":""})},String.prototype.format.regex=new RegExp("{-?[0-9]+}","g")),Object.size=function(e){var t,a=0;for(var t in e)e.hasOwnProperty(t)&&a++;return a},window.console||(window.console={log:function(e){return!1}}),String.prototype.toTitleCase=function(){var e=/^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|vs?\.?|via)$/i;return this.replace(/([^\W_]+[^\s-]*) */g,function(t,a,r,n){return r>0&&r+a.length!==n.length&&a.search(e)>-1&&":"!==n.charAt(r-2)&&n.charAt(r-1).search(/[^\s-]/)<0?t.toLowerCase():a.substr(1).search(/[A-Z]|\../)>-1?t:t.charAt(0).toUpperCase()+t.substr(1)})},$.ajaxSetup({cache:!1}),Function.prototype.inheritsFrom=function(e){return this.prototype=new e,this.prototype.constructor=this,this.prototype.parent=e.prototype,this},String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),String.prototype.ckey||(String.prototype.ckey=function(){return this.replace(/\W/g,"").toLowerCase()}),NanoStateManager=function(){var e=!1,t=null,a={},r={},n={},o=null,i=function(){t=$("body").data("initialData"),null!=t&&t.hasOwnProperty("config")&&t.hasOwnProperty("data")||reportError("Error: Initial data did not load correctly.");var a="default";t.config.hasOwnProperty("stateKey")&&t.config.stateKey&&(a=t.config.stateKey.toLowerCase()),NanoStateManager.setCurrentState(a),$(document).on("templatesLoaded",function(){l(t),e=!0})},s=function(a){var r;try{r=jQuery.parseJSON(a)}catch(n){return void reportError("recieveUpdateData failed.
Error name: "+n.name+"
Error Message: "+n.message)}r.hasOwnProperty("data")||(t&&t.hasOwnProperty("data")?r.data=t.data:r.data={}),e?l(r):t=r},l=function(e){if(null!=o){if(e=o.onBeforeUpdate(e),e===!1)return void reportError("data is false, return");t=e,o.onUpdate(t),o.onAfterUpdate(t)}},d=function(e,t){for(var a in e)e.hasOwnProperty(a)&&jQuery.isFunction(e[a])&&(t=e[a].call(this,t));return t};return{init:function(){i()},receiveUpdateData:function(e){s(e)},addBeforeUpdateCallback:function(e,t){a[e]=t},addBeforeUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addBeforeUpdateCallback(t,e[t])},removeBeforeUpdateCallback:function(e){a.hasOwnProperty(e)&&delete a[e]},executeBeforeUpdateCallbacks:function(e){return d(a,e)},addAfterUpdateCallback:function(e,t){r[e]=t},addAfterUpdateCallbacks:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoStateManager.addAfterUpdateCallback(t,e[t])},removeAfterUpdateCallback:function(e){r.hasOwnProperty(e)&&delete r[e]},executeAfterUpdateCallbacks:function(e){return d(r,e)},addState:function(e){return e instanceof NanoStateClass?e.key?void(n[e.key]=e):void reportError("ERROR: Attempted to add a state with an invalid stateKey"):void reportError("ERROR: Attempted to add a state which is not instanceof NanoStateClass")},setCurrentState:function(e){if("undefined"==typeof e||!e)return reportError("ERROR: No state key was passed!"),!1;if(!n.hasOwnProperty(e))return reportError("ERROR: Attempted to set a current state which does not exist: "+e),!1;var t=o;return o=n[e],null!=t&&t.onRemove(o),o.onAdd(t),!0},getCurrentState:function(){return o}}}(),NanoBaseCallbacks=function(){var e=!0,t={},a={status:function(t){var a;return 2==t.config.status?(a="good",$(".linkActive").removeClass("inactive")):1==t.config.status?(a="average",$(".linkActive").addClass("inactive")):(a="bad",$(".linkActive").addClass("inactive")),$(".statusicon").each(function(e,t){t.className=t.className.replace(/good|bad|average/g,""),t.classList.add(a)}),$(".linkActive").stopTime("linkPending"),$(".linkActive").removeClass("linkPending"),$(".linkActive").off("click").on("click",function(a){a.preventDefault();var r=$(this).data("href");null!=r&&e&&(e=!1,$("body").oneTime(300,"enableClick",function(){e=!0}),2==t.config.status&&$(this).oneTime(300,"linkPending",function(){$(this).addClass("linkPending")}),window.location.href=r)}),t},nanomap:function(e){return $(".mapIcon").off("mouseenter mouseleave").on("mouseenter",function(e){$("#uiMapTooltip").html($(this).children(".tooltip").html()).show().stopTime().oneTime(5e3,"hideTooltip",function(){$(this).fadeOut(500)})}),$(".zoomLink").off("click").on("click",function(e){e.preventDefault();var t=$(this).data("zoomLevel"),a=$("#uiMap"),r=a.width()*t,n=a.height()*t;a.css({zoom:t,left:"50%",top:"50%",marginLeft:"-"+Math.floor(r/2)+"px",marginTop:"-"+Math.floor(n/2)+"px"})}),$("#uiMapImage").attr("src","nanomap_z"+e.config.mapZLevel+".png"),e}};return{addCallbacks:function(){NanoStateManager.addBeforeUpdateCallbacks(t),NanoStateManager.addAfterUpdateCallbacks(a)},removeCallbacks:function(){for(var e in t)t.hasOwnProperty(e)&&NanoStateManager.removeBeforeUpdateCallback(e);for(var e in a)a.hasOwnProperty(e)&&NanoStateManager.removeAfterUpdateCallback(e)}}}(),NanoBaseHelpers=function(){var e={syndicateMode:function(){return $("body").css("background-color","#8f1414"),$("body").css("background-image","url('uiBackground-Syndicate.png')"),$("body").css("background-position","50% 0"),$("body").css("background-repeat","repeat-x"),$("#uiTitleFluff").css("background-image","url('uiTitleFluff-Syndicate.png')"),$("#uiTitleFluff").css("background-position","50% 50%"),$("#uiTitleFluff").css("background-repeat","no-repeat"),""},combine:function(e,t){return e&&t?e.concat(t):e||t},dump:function(e){return JSON.stringify(e)},link:function(e,t,a,r,n,o){var i="",s="noIcon";"undefined"!=typeof t&&t&&(i='',s="hasIcon"),"undefined"!=typeof n&&n||(n="link");var l="";return"undefined"!=typeof o&&o&&(l='id="'+o+'"'),"undefined"!=typeof r&&r?'"+i+e+"
":'"+i+e+"
"},xor:function(e,t){return e^t},precisionRound:function(e,t){if(0==t)return Math.round(number);var a=Math.pow(10,t);return Math.round(e*a)/a},round:function(e){return Math.round(e)},fixed:function(e){return Math.round(10*e)/10},floor:function(e){return Math.floor(e)},ceil:function(e){return Math.ceil(e)},string:function(){if(0==arguments.length)return"";if(1==arguments.length)return arguments[0];if(arguments.length>1){stringArgs=[];for(var e=1;et?t>e?e=t:e>a&&(e=a):e>t?e=t:a>e&&(e=a),"undefined"!=typeof r&&r||(r=""),"undefined"!=typeof n&&n||(n="");var o=Math.round((e-t)/(a-t)*100);return'"},dangerToClass:function(e){return 0==e?"good":1==e?"average":"bad"},dangerToSpan:function(e){return 0==e?'"Good"':1==e?'"Minor Alert"':'"Major Alert"'},generateHref:function(e){var t=$("body");_urlParameters=t.data("urlParameters");var a="?";for(var r in _urlParameters)_urlParameters.hasOwnProperty(r)&&("?"!==a&&(a+=";"),a+=r+"="+_urlParameters[r]);for(var r in e)e.hasOwnProperty(r)&&("?"!==a&&(a+=";"),a+=r+"="+e[r]);return a},displayDNABlocks:function(e,t,a,r,n){if(!e)return'Please place a valid subject into the DNA modifier.
';var o=e.split(""),i='1
',s=1,l=1;for(var d in o)if(o.hasOwnProperty(d)&&"object"!=typeof o[d]){var c;c="UI"==n.toUpperCase()?{selectUIBlock:s,selectUISubblock:l}:{selectSEBlock:s,selectSESubblock:l};var u="linkActive";s==t&&l==a&&(u="selected"),i+='
'+o[d]+"
",d++,d%r==0&&d
"},cMirror:function(e){CodeMirror.fromTextArea(document.getElementById(e),{lineNumbers:!0,indentUnit:4,indentWithTabs:!0,theme:"lesser-dark"})}};return{addHelpers:function(){NanoTemplate.addHelpers(e)},removeHelpers:function(){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.removeHelper(t)}}}(),NanoStateDefaultClass.inheritsFrom(NanoStateClass);var NanoStateDefault=new NanoStateDefaultClass;NanoStateClass.prototype.key=null,NanoStateClass.prototype.layoutRendered=!1,NanoStateClass.prototype.contentRendered=!1,NanoStateClass.prototype.mapInitialised=!1,NanoStateClass.prototype.isCurrent=function(){return NanoStateManager.getCurrentState()==this},NanoStateClass.prototype.onAdd=function(e){NanoBaseCallbacks.addCallbacks(),NanoBaseHelpers.addHelpers()},NanoStateClass.prototype.onRemove=function(e){NanoBaseCallbacks.removeCallbacks(),NanoBaseHelpers.removeHelpers()},NanoStateClass.prototype.onBeforeUpdate=function(e){return e=NanoStateManager.executeBeforeUpdateCallbacks(e)},NanoStateClass.prototype.onUpdate=function(e){try{(!this.layoutRendered||e.config.hasOwnProperty("autoUpdateLayout")&&e.config.autoUpdateLayout)&&($("#uiLayout").html(NanoTemplate.parse("layout",e)),this.layoutRendered=!0),(!this.contentRendered||e.config.hasOwnProperty("autoUpdateContent")&&e.config.autoUpdateContent)&&($("#uiContent").html(NanoTemplate.parse("main",e)),this.contentRendered=!0),NanoTemplate.templateExists("mapContent")&&(this.mapInitialised||($("#uiMap").draggable(),$("#uiMapTooltip").off("click").on("click",function(e){e.preventDefault(),$(this).fadeOut(400)}),this.mapInitialised=!0),$("#uiMapContent").html(NanoTemplate.parse("mapContent",e)),e.config.hasOwnProperty("showMap")&&e.config.showMap?($("#uiContent").addClass("hidden"),$("#uiMapWrapper").removeClass("hidden")):($("#uiMapWrapper").addClass("hidden"),$("#uiContent").removeClass("hidden"))),NanoTemplate.templateExists("mapHeader")&&$("#uiMapHeader").html(NanoTemplate.parse("mapHeader",e)),NanoTemplate.templateExists("mapFooter")&&$("#uiMapFooter").html(NanoTemplate.parse("mapFooter",e))}catch(t){return void reportError("ERROR: An error occurred while rendering the UI: "+t.message)}},NanoStateClass.prototype.onAfterUpdate=function(e){NanoStateManager.executeAfterUpdateCallbacks(e)},NanoStateClass.prototype.alertText=function(e){alert(e)};var NanoTemplate=function(){var e={},t={},a={},r={},n=function(){e=$("body").data("templateData"),null==e&&reportError("Error: Template data did not load correctly."),o()},o=function(){var t=Object.size(e);if(!t)return void $(document).trigger("templatesLoaded");for(var a in e)if(e.hasOwnProperty(a))return void $.when($.ajax({url:e[a],cache:!1,dataType:"text"})).done(function(t){t+='';try{NanoTemplate.addTemplate(a,t)}catch(r){return void reportError("ERROR: An error occurred while loading the UI: "+r.message)}delete e[a],o()}).fail(function(){reportError("ERROR: Loading template "+a+"("+e[a]+") failed!")})},i=function(){for(var e in t)try{a[e]=doT.template(t[e],null,t)}catch(r){reportError(r.message)}};return{init:function(){n()},addTemplate:function(e,a){t[e]=a},templateExists:function(e){return t.hasOwnProperty(e)},parse:function(e,n){if(!a.hasOwnProperty(e)||!a[e]){if(!t.hasOwnProperty(e))return reportError('ERROR: Template "'+e+'" does not exist in _compiledTemplates!'),"Template error (does not exist)
";i()}return"function"!=typeof a[e]?(reportError(a[e]),reportError('ERROR: Template "'+e+'" failed to compile!'),"Template error (failed to compile)
"):a[e].call(this,n.data,n.config,r)},addHelper:function(e,t){return jQuery.isFunction(t)?void(r[e]=t):void reportError("NanoTemplate.addHelper failed to add "+e+" as it is not a function.")},addHelpers:function(e){for(var t in e)e.hasOwnProperty(t)&&NanoTemplate.addHelper(t,e[t])},removeHelper:function(e){helpers.hasOwnProperty(e)&&delete r[e]}}}();
\ No newline at end of file
diff --git a/nano/package.json b/nano/package.json
index 5230b30eb14..5bceb412fae 100644
--- a/nano/package.json
+++ b/nano/package.json
@@ -14,12 +14,13 @@
"gulp-if": "^2.0.0",
"gulp-less": "^3.0.5",
"gulp-load-plugins": "^1.1.0",
+ "gulp-order": "^1.1.1",
"gulp-postcss": "^6.0.1",
"gulp-replace": "^0.5.4",
"gulp-uglify": "^1.5.1",
"gulp-util": "^3.0.7",
- "merge-stream": "^1.0.0",
"main-bower-files": "^2.9.0",
+ "merge-stream": "^1.0.0",
"pleeease-filters": "^2.0.0",
"postcss-color-rgba-fallback": "git+https://github.com/postcss/postcss-color-rgba-fallback",
"postcss-filter-gradient": "^0.2.1",
diff --git a/nano/reload.bat b/nano/reload.bat
new file mode 100644
index 00000000000..a330006173f
--- /dev/null
+++ b/nano/reload.bat
@@ -0,0 +1,9 @@
+@echo off
+
+for /f "tokens=3* delims= " %%a in (
+ 'reg query "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" /v "Personal"'
+) do (
+ set documents=%%a
+)
+
+copy assets\* "%documents%\BYOND\cache" /y
diff --git a/nano/scripts/libraries/3_doT.js b/nano/scripts/libraries/doT.js
similarity index 100%
rename from nano/scripts/libraries/3_doT.js
rename to nano/scripts/libraries/doT.js
diff --git a/nano/scripts/libraries/1_jquery-ui.js b/nano/scripts/libraries/jquery-ui.js
similarity index 100%
rename from nano/scripts/libraries/1_jquery-ui.js
rename to nano/scripts/libraries/jquery-ui.js
diff --git a/nano/scripts/libraries/0_jquery.js b/nano/scripts/libraries/jquery.js
similarity index 100%
rename from nano/scripts/libraries/0_jquery.js
rename to nano/scripts/libraries/jquery.js
diff --git a/nano/scripts/libraries/2_jquery.timers.js b/nano/scripts/libraries/jquery.timers.js
similarity index 100%
rename from nano/scripts/libraries/2_jquery.timers.js
rename to nano/scripts/libraries/jquery.timers.js
diff --git a/nano/scripts/nano/2_nano_state_manager.js b/nano/scripts/nano/2_nano_state_manager.js
deleted file mode 100644
index 223cebf1460..00000000000
--- a/nano/scripts/nano/2_nano_state_manager.js
+++ /dev/null
@@ -1,224 +0,0 @@
-// NanoStateManager handles data from the server and uses it to render templates
-NanoStateManager = function ()
-{
- // _isInitialised is set to true when all of this ui's templates have been processed/rendered
- var _isInitialised = false;
-
- // the data for this ui
- var _data = null;
-
- // this is an array of callbacks which are called when new data arrives, before it is processed
- var _beforeUpdateCallbacks = {};
- // this is an array of callbacks which are called when new data arrives, before it is processed
- var _afterUpdateCallbacks = {};
-
- // this is an array of state objects, these can be used to provide custom javascript logic
- var _states = {};
-
- var _currentState = null;
-
- // the init function is called when the ui has loaded
- // this function sets up the templates and base functionality
- var init = function ()
- {
- // We store initialData and templateData in the body tag, it's as good a place as any
- _data = $('body').data('initialData');
-
- if (_data == null || !_data.hasOwnProperty('config') || !_data.hasOwnProperty('data'))
- {
- alert('Error: Initial data did not load correctly.');
- }
-
- var stateKey = 'default';
- if (_data['config'].hasOwnProperty('stateKey') && _data['config']['stateKey'])
- {
- stateKey = _data['config']['stateKey'].toLowerCase();
- }
-
- NanoStateManager.setCurrentState(stateKey);
-
- $(document).on('templatesLoaded', function () {
- doUpdate(_data);
-
- _isInitialised = true;
- });
- };
-
- // Receive update data from the server
- var receiveUpdateData = function (jsonString)
- {
- var updateData;
-
- // alert("recieveUpdateData called." + "
Type: " + typeof jsonString); //debug hook
- try
- {
- // parse the JSON string from the server into a JSON object
- updateData = jQuery.parseJSON(jsonString);
- }
- catch (error)
- {
- alert("recieveUpdateData failed. " + "
Error name: " + error.name + "
Error Message: " + error.message);
- return;
- }
-
- // alert("recieveUpdateData passed trycatch block."); //debug hook
-
- if (!updateData.hasOwnProperty('data'))
- {
- if (_data && _data.hasOwnProperty('data'))
- {
- updateData['data'] = _data['data'];
- }
- else
- {
- updateData['data'] = {};
- }
- }
-
- if (_isInitialised) // all templates have been registered, so render them
- {
- doUpdate(updateData);
- }
- else
- {
- _data = updateData; // all templates have not been registered. We set _data directly here which will be applied after the template is loaded with the initial data
- }
- };
-
- // This function does the update by calling the methods on the current state
- var doUpdate = function (data)
- {
- if (_currentState == null)
- {
- return;
- }
-
- data = _currentState.onBeforeUpdate(data);
-
- if (data === false)
- {
- alert('data is false, return');
- return; // A beforeUpdateCallback returned a false value, this prevents the render from occuring
- }
-
- _data = data;
-
- _currentState.onUpdate(_data);
-
- _currentState.onAfterUpdate(_data);
- };
-
- // Execute all callbacks in the callbacks array/object provided, updateData is passed to them for processing and potential modification
- var executeCallbacks = function (callbacks, data)
- {
- for (var key in callbacks)
- {
- if (callbacks.hasOwnProperty(key) && jQuery.isFunction(callbacks[key]))
- {
- data = callbacks[key].call(this, data);
- }
- }
-
- return data;
- };
-
- return {
- init: function ()
- {
- init();
- },
- receiveUpdateData: function (jsonString)
- {
- receiveUpdateData(jsonString);
- },
- addBeforeUpdateCallback: function (key, callbackFunction)
- {
- _beforeUpdateCallbacks[key] = callbackFunction;
- },
- addBeforeUpdateCallbacks: function (callbacks) {
- for (var callbackKey in callbacks) {
- if (!callbacks.hasOwnProperty(callbackKey))
- {
- continue;
- }
- NanoStateManager.addBeforeUpdateCallback(callbackKey, callbacks[callbackKey]);
- }
- },
- removeBeforeUpdateCallback: function (key)
- {
- if (_beforeUpdateCallbacks.hasOwnProperty(key))
- {
- delete _beforeUpdateCallbacks[key];
- }
- },
- executeBeforeUpdateCallbacks: function (data) {
- return executeCallbacks(_beforeUpdateCallbacks, data);
- },
- addAfterUpdateCallback: function (key, callbackFunction)
- {
- _afterUpdateCallbacks[key] = callbackFunction;
- },
- addAfterUpdateCallbacks: function (callbacks) {
- for (var callbackKey in callbacks) {
- if (!callbacks.hasOwnProperty(callbackKey))
- {
- continue;
- }
- NanoStateManager.addAfterUpdateCallback(callbackKey, callbacks[callbackKey]);
- }
- },
- removeAfterUpdateCallback: function (key)
- {
- if (_afterUpdateCallbacks.hasOwnProperty(key))
- {
- delete _afterUpdateCallbacks[key];
- }
- },
- executeAfterUpdateCallbacks: function (data) {
- return executeCallbacks(_afterUpdateCallbacks, data);
- },
- addState: function (state)
- {
- if (!(state instanceof NanoStateClass))
- {
- alert('ERROR: Attempted to add a state which is not instanceof NanoStateClass');
- return;
- }
- if (!state.key)
- {
- alert('ERROR: Attempted to add a state with an invalid stateKey');
- return;
- }
- _states[state.key] = state;
- },
- setCurrentState: function (stateKey)
- {
- if (typeof stateKey == 'undefined' || !stateKey) {
- alert('ERROR: No state key was passed!');
- return false;
- }
- if (!_states.hasOwnProperty(stateKey))
- {
- alert('ERROR: Attempted to set a current state which does not exist: ' + stateKey);
- return false;
- }
-
- var previousState = _currentState;
-
- _currentState = _states[stateKey];
-
- if (previousState != null) {
- previousState.onRemove(_currentState);
- }
-
- _currentState.onAdd(previousState);
-
- return true;
- },
- getCurrentState: function ()
- {
- return _currentState;
- }
- };
-} ();
-
\ No newline at end of file
diff --git a/nano/scripts/nano/6_nano_base_helpers.js b/nano/scripts/nano/6_nano_base_helpers.js
deleted file mode 100644
index 3f93a63934e..00000000000
--- a/nano/scripts/nano/6_nano_base_helpers.js
+++ /dev/null
@@ -1,281 +0,0 @@
-// NanoBaseHelpers is where the base template helpers (common to all templates) are stored
-NanoBaseHelpers = function ()
-{
- var _baseHelpers = {
- // change ui styling to "syndicate mode"
- syndicateMode: function() {
- $('body').css("background-color","#8f1414");
- $('body').css("background-image","url('uiBackground-Syndicate.png')");
- $('body').css("background-position","50% 0");
- $('body').css("background-repeat","repeat-x");
-
- $('#uiTitleFluff').css("background-image","url('uiTitleFluff-Syndicate.png')");
- $('#uiTitleFluff').css("background-position","50% 50%");
- $('#uiTitleFluff').css("background-repeat", "no-repeat");
-
- return '';
- },
- combine: function( arr1, arr2 ) {
- return arr1 && arr2 ? arr1.concat(arr2) : arr1 || arr2;
- },
- dump: function( arr1 ) {
- return JSON.stringify(arr1);
- },
- // Generate a Byond link
- link: function( text, icon, parameters, status, elementClass, elementId) {
-
- var iconHtml = '';
- var iconClass = 'noIcon';
- if (typeof icon != 'undefined' && icon)
- {
- iconHtml = '';
- iconClass = 'hasIcon';
- }
-
- if (typeof elementClass == 'undefined' || !elementClass)
- {
- elementClass = 'link';
- }
-
- var elementIdHtml = '';
- if (typeof elementId != 'undefined' && elementId)
- {
- elementIdHtml = 'id="' + elementId + '"';
- }
-
- if (typeof status != 'undefined' && status)
- {
- return '' + iconHtml + text + '
';
- }
-
- return '' + iconHtml + text + '
';
- },
- // Since jsrender breaks the ^ operator
- xor: function(number,bit) {
- return number ^ bit;
- },
- precisionRound: function (value, places) {
- if(places==0)
- return Math.round(number);
- var multiplier = Math.pow(10, places);
- return (Math.round(value * multiplier) / multiplier);
- },
- // Round a number to the nearest integer
- round: function(number) {
- return Math.round(number);
- },
- fixed: function(number) {
- return Math.round(number * 10) / 10;
- },
- // Round a number down to integer
- floor: function(number) {
- return Math.floor(number);
- },
- // Round a number up to integer
- ceil: function(number) {
- return Math.ceil(number);
- },
- // Format a string (~string("Hello {0}, how are {1}?", 'Martin', 'you') becomes "Hello Martin, how are you?")
- string: function() {
- if (arguments.length == 0)
- {
- return '';
- }
- else if (arguments.length == 1)
- {
- return arguments[0];
- }
- else if (arguments.length > 1)
- {
- stringArgs = [];
- for (var i = 1; i < arguments.length; i++)
- {
- stringArgs.push(arguments[i]);
- }
- return arguments[0].format(stringArgs);
- }
- return '';
- },
- formatNumber: function(x) {
- // From http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
- var parts = x.toString().split(".");
- parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
- return parts.join(".");
- },
- // Capitalize the first letter of a string. From http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
- capitalizeFirstLetter: function(string) {
- return string.charAt(0).toUpperCase() + string.slice(1);
- },
- // Display a bar. Used to show health, capacity, etc.
- displayBar: function(value, rangeMin, rangeMax, styleClass, showText) {
-
- if (rangeMin < rangeMax)
- {
- if (value < rangeMin)
- {
- value = rangeMin;
- }
- else if (value > rangeMax)
- {
- value = rangeMax;
- }
- }
- else
- {
- if (value > rangeMin)
- {
- value = rangeMin;
- }
- else if (value < rangeMax)
- {
- value = rangeMax;
- }
- }
-
- if (typeof styleClass == 'undefined' || !styleClass)
- {
- styleClass = '';
- }
-
- if (typeof showText == 'undefined' || !showText)
- {
- showText = '';
- }
-
- var percentage = Math.round((value - rangeMin) / (rangeMax - rangeMin) * 100);
-
- return '';
- },
- // Convert danger level to class (for the air alarm)
- dangerToClass: function(level) {
- if(level==0) return 'good';
- if(level==1) return 'average';
- return 'bad';
- },
- dangerToSpan: function(level) {
- if(level==0) return '"Good"';
- if(level==1) return '"Minor Alert"';
- return '"Major Alert"';
- },
- generateHref: function (parameters) {
- var body = $('body'); // We store data in the body tag, it's as good a place as any
- _urlParameters = body.data('urlParameters');
- var queryString = '?';
-
- for (var key in _urlParameters)
- {
- if (_urlParameters.hasOwnProperty(key))
- {
- if (queryString !== '?')
- {
- queryString += ';';
- }
- queryString += key + '=' + _urlParameters[key];
- }
- }
-
- for (var key in parameters)
- {
- if (parameters.hasOwnProperty(key))
- {
- if (queryString !== '?')
- {
- queryString += ';';
- }
- queryString += key + '=' + parameters[key];
- }
- }
- return queryString;
- },
- // 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 += '
' + block + '
';
- }
- else
- {
- subblock++;
- }
- }
-
- html += '
';
-
- return html;
- },
- cMirror: function(domID) {
- if(!domID)
- {
- return "ERR - NO domID provided";
- }
-
- var html = ''
- return html;
- }
- };
-
- return {
- addHelpers: function ()
- {
- NanoTemplate.addHelpers(_baseHelpers);
- },
- removeHelpers: function ()
- {
- for (var helperKey in _baseHelpers)
- {
- if (_baseHelpers.hasOwnProperty(helperKey))
- {
- NanoTemplate.removeHelper(helperKey);
- }
- }
- }
- };
-} ();
-
-
-
-
-
-
-
diff --git a/nano/scripts/nano/5_nano_base_callbacks.js b/nano/scripts/nano/nano_base_callbacks.js
similarity index 93%
rename from nano/scripts/nano/5_nano_base_callbacks.js
rename to nano/scripts/nano/nano_base_callbacks.js
index 47582ad69a2..708a67fd963 100644
--- a/nano/scripts/nano/5_nano_base_callbacks.js
+++ b/nano/scripts/nano/nano_base_callbacks.js
@@ -3,9 +3,7 @@ NanoBaseCallbacks = function ()
{
// _canClick is used to disable clicks for a short period after each click (to avoid mis-clicks)
var _canClick = true;
-
- var _baseBeforeUpdateCallbacks = {}
-
+ var _baseBeforeUpdateCallbacks = {};
var _baseAfterUpdateCallbacks = {
// this callback is triggered after new data is processed
// it updates the status/visibility icon and adds click event handling to buttons/links
@@ -23,7 +21,7 @@ NanoBaseCallbacks = function ()
}
else
{
- uiStatusClass = 'bad'
+ uiStatusClass = 'bad';
$('.linkActive').addClass('inactive');
}
$('.statusicon').each( function(i, obj) {
@@ -103,27 +101,16 @@ NanoBaseCallbacks = function ()
NanoStateManager.addAfterUpdateCallbacks(_baseAfterUpdateCallbacks);
},
removeCallbacks: function () {
- for (var callbackKey in _baseBeforeUpdateCallbacks)
- {
- if (_baseBeforeUpdateCallbacks.hasOwnProperty(callbackKey))
- {
+ for (var callbackKey in _baseBeforeUpdateCallbacks) {
+ if (_baseBeforeUpdateCallbacks.hasOwnProperty(callbackKey)) {
NanoStateManager.removeBeforeUpdateCallback(callbackKey);
}
}
- for (var callbackKey in _baseAfterUpdateCallbacks)
- {
- if (_baseAfterUpdateCallbacks.hasOwnProperty(callbackKey))
- {
+ for (var callbackKey in _baseAfterUpdateCallbacks) {
+ if (_baseAfterUpdateCallbacks.hasOwnProperty(callbackKey)) {
NanoStateManager.removeAfterUpdateCallback(callbackKey);
}
}
}
};
-} ();
-
-
-
-
-
-
-
+}();
diff --git a/nano/scripts/nano/nano_base_helpers.js b/nano/scripts/nano/nano_base_helpers.js
new file mode 100644
index 00000000000..83969a0b987
--- /dev/null
+++ b/nano/scripts/nano/nano_base_helpers.js
@@ -0,0 +1,268 @@
+// NanoBaseHelpers is where the base template helpers (common to all templates) are stored
+NanoBaseHelpers = function ()
+{
+ var _baseHelpers = {
+ // change ui styling to "syndicate mode"
+ syndicateMode: function() {
+ $('body').css("background-color","#8f1414");
+ $('body').css("background-image","url('uiBackground-Syndicate.png')");
+ $('body').css("background-position","50% 0");
+ $('body').css("background-repeat","repeat-x");
+
+ $('#uiTitleFluff').css("background-image","url('uiTitleFluff-Syndicate.png')");
+ $('#uiTitleFluff').css("background-position","50% 50%");
+ $('#uiTitleFluff').css("background-repeat", "no-repeat");
+
+ return '';
+ },
+
+ combine: function( arr1, arr2 ) {
+ return arr1 && arr2 ? arr1.concat(arr2) : arr1 || arr2;
+ },
+ dump: function( arr1 ) {
+ return JSON.stringify(arr1);
+ },
+
+ // Generate a Byond link
+ link: function( text, icon, parameters, status, elementClass, elementId ) {
+ var iconHtml = '';
+ var iconClass = 'noIcon';
+ if (typeof icon != 'undefined' && icon)
+ {
+ iconHtml = '';
+ iconClass = 'hasIcon';
+ }
+
+ if (typeof elementClass == 'undefined' || !elementClass)
+ {
+ elementClass = 'link';
+ }
+
+ var elementIdHtml = '';
+ if (typeof elementId != 'undefined' && elementId)
+ {
+ elementIdHtml = 'id="' + elementId + '"';
+ }
+
+ if (typeof status != 'undefined' && status)
+ {
+ return '' + iconHtml + text + '
';
+ }
+
+ return '' + iconHtml + text + '
';
+ },
+
+ xor: function (number,bit) {
+ return number ^ bit;
+ },
+
+ precisionRound: function (value, places) {
+ if(places == 0){
+ return Math.round(number);
+ }
+ var multiplier = Math.pow(10, places);
+ return (Math.round(value * multiplier) / multiplier);
+ },
+
+ // Round a number to the nearest integer
+ round: function(number) {
+ return Math.round(number);
+ },
+ fixed: function(number) {
+ return Math.round(number * 10) / 10;
+ },
+ // Round a number down to integer
+ floor: function(number) {
+ return Math.floor(number);
+ },
+ // Round a number up to integer
+ ceil: function(number) {
+ return Math.ceil(number);
+ },
+
+ // Format a string (~string("Hello {0}, how are {1}?", 'Martin', 'you') becomes "Hello Martin, how are you?")
+ string: function() {
+ if (arguments.length == 0)
+ {
+ return '';
+ }
+ else if (arguments.length == 1)
+ {
+ return arguments[0];
+ }
+ else if (arguments.length > 1)
+ {
+ stringArgs = [];
+ for (var i = 1; i < arguments.length; i++)
+ {
+ stringArgs.push(arguments[i]);
+ }
+ return arguments[0].format(stringArgs);
+ }
+ return '';
+ },
+ formatNumber: function(x) {
+ // From http://stackoverflow.com/questions/2901102/how-to-print-a-number-with-commas-as-thousands-separators-in-javascript
+ var parts = x.toString().split(".");
+ parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+ return parts.join(".");
+ },
+ // Capitalize the first letter of a string. From http://stackoverflow.com/questions/1026069/capitalize-the-first-letter-of-string-in-javascript
+ capitalizeFirstLetter: function( string ) {
+ return string.charAt(0).toUpperCase() + string.slice(1);
+ },
+ // Display a bar. Used to show health, capacity, etc.
+ displayBar: function( value, rangeMin, rangeMax, styleClass, showText ) {
+
+ if (rangeMin < rangeMax)
+ {
+ if (value < rangeMin)
+ {
+ value = rangeMin;
+ }
+ else if (value > rangeMax)
+ {
+ value = rangeMax;
+ }
+ }
+ else
+ {
+ if (value > rangeMin)
+ {
+ value = rangeMin;
+ }
+ else if (value < rangeMax)
+ {
+ value = rangeMax;
+ }
+ }
+
+ if (typeof styleClass == 'undefined' || !styleClass)
+ {
+ styleClass = '';
+ }
+
+ if (typeof showText == 'undefined' || !showText)
+ {
+ showText = '';
+ }
+
+ var percentage = Math.round((value - rangeMin) / (rangeMax - rangeMin) * 100);
+
+ return '';
+ },
+ // Convert danger level to class (for the air alarm)
+ dangerToClass: function(level) {
+ if(level == 0) return 'good';
+ if(level == 1) return 'average';
+ return 'bad';
+ },
+ dangerToSpan: function(level) {
+ if(level == 0) return '"Good"';
+ if(level == 1) return '"Minor Alert"';
+ return '"Major Alert"';
+ },
+ generateHref: function (parameters) {
+ var body = $('body'); // For some fucking reason, data is stored in the body tag.
+ _urlParameters = body.data('urlParameters');
+ var queryString = '?';
+
+ for (var key in _urlParameters)
+ {
+ if (_urlParameters.hasOwnProperty(key))
+ {
+ if (queryString !== '?')
+ {
+ queryString += ';';
+ }
+ queryString += key + '=' + _urlParameters[key];
+ }
+ }
+
+ for (var key in parameters)
+ {
+ if (parameters.hasOwnProperty(key))
+ {
+ if (queryString !== '?')
+ {
+ queryString += ';';
+ }
+ queryString += key + '=' + parameters[key];
+ }
+ }
+ return queryString;
+ },
+ // 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 (var 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 += '
' + block + '
';
+ } else {
+ subblock++;
+ }
+ }
+
+ html += '
';
+
+ return html;
+ },
+ cMirror: function(textbox) {
+ var editor = CodeMirror.fromTextArea(document.getElementById(textbox), {
+ lineNumbers: true,
+ indentUnit: 4,
+ indentWithTabs: true,
+ theme: "lesser-dark"
+ });
+ }
+ };
+
+ return {
+ addHelpers: function ()
+ {
+ NanoTemplate.addHelpers(_baseHelpers);
+ },
+
+ removeHelpers: function ()
+ {
+ for (var helperKey in _baseHelpers)
+ {
+ if (_baseHelpers.hasOwnProperty(helperKey))
+ {
+ NanoTemplate.removeHelper(helperKey);
+ }
+ }
+ }
+ };
+}();
diff --git a/nano/scripts/nano/3_nano_state.js b/nano/scripts/nano/nano_state.js
similarity index 92%
rename from nano/scripts/nano/3_nano_state.js
rename to nano/scripts/nano/nano_state.js
index 3e9ef3ab1ff..db7fcf92a11 100644
--- a/nano/scripts/nano/3_nano_state.js
+++ b/nano/scripts/nano/nano_state.js
@@ -1,16 +1,6 @@
// This is the base state class, it is not to be used directly
-function NanoStateClass() {
- /*if (typeof this.key != 'string' || !this.key.length)
- {
- alert('ERROR: Tried to create a state with an invalid state key: ' + this.key);
- return;
- }
-
- this.key = this.key.toLowerCase();
-
- NanoStateManager.addState(this);*/
-}
+function NanoStateClass() {}
NanoStateClass.prototype.key = null;
NanoStateClass.prototype.layoutRendered = false;
@@ -99,7 +89,7 @@ NanoStateClass.prototype.onUpdate = function (data) {
}
catch(error)
{
- alert('ERROR: An error occurred while rendering the UI: ' + error.message);
+ reportError('ERROR: An error occurred while rendering the UI: ' + error.message);
return;
}
};
@@ -115,5 +105,3 @@ NanoStateClass.prototype.alertText = function (text) {
alert(text);
};
-
-
diff --git a/nano/scripts/nano/4_nano_state_default.js b/nano/scripts/nano/nano_state_default.js
similarity index 99%
rename from nano/scripts/nano/4_nano_state_default.js
rename to nano/scripts/nano/nano_state_default.js
index 65493b8c87e..ee7bd521e63 100644
--- a/nano/scripts/nano/4_nano_state_default.js
+++ b/nano/scripts/nano/nano_state_default.js
@@ -11,4 +11,4 @@ function NanoStateDefaultClass() {
this.key = this.key.toLowerCase();
NanoStateManager.addState(this);
-}
\ No newline at end of file
+}
diff --git a/nano/scripts/nano/nano_state_manager.js b/nano/scripts/nano/nano_state_manager.js
new file mode 100644
index 00000000000..b310bdb3ec4
--- /dev/null
+++ b/nano/scripts/nano/nano_state_manager.js
@@ -0,0 +1,222 @@
+// NanoStateManager handles data from the server and uses it to render templates
+NanoStateManager = function ()
+{
+ // _isInitialised is set to true when all of this ui's templates have been processed/rendered
+ var _isInitialised = false;
+ // the data for this ui
+ var _data = null;
+
+ // this is an array of callbacks which are called when new data arrives, before it is processed
+ var _beforeUpdateCallbacks = {};
+ // this is an array of callbacks which are called when new data arrives, before it is processed
+ var _afterUpdateCallbacks = {};
+
+ // this is an array of state objects, these can be used to provide custom javascript logic
+ var _states = {};
+ var _currentState = null;
+
+ // the init function is called when the ui has loaded
+ // this function sets up the templates and base functionality
+ var init = function ()
+ {
+ // We store initialData and templateData in the body tag, it's as good a place as any
+ _data = $('body').data('initialData');
+
+ if (_data == null || !_data.hasOwnProperty('config') || !_data.hasOwnProperty('data'))
+ {
+ reportError('Error: Initial data did not load correctly.');
+ }
+
+ var stateKey = 'default';
+ if (_data['config'].hasOwnProperty('stateKey') && _data['config']['stateKey'])
+ {
+ stateKey = _data['config']['stateKey'].toLowerCase();
+ }
+
+ NanoStateManager.setCurrentState(stateKey);
+
+ $(document).on('templatesLoaded', function () {
+ doUpdate(_data);
+
+ _isInitialised = true;
+ });
+ };
+
+ // Receive update data from the server
+ var receiveUpdateData = function (jsonString)
+ {
+ var updateData;
+
+ // reportError("recieveUpdateData called." + "
Type: " + typeof jsonString); //debug hook
+ try
+ {
+ // parse the JSON string from the server into a JSON object
+ updateData = jQuery.parseJSON(jsonString);
+ }
+ catch (error)
+ {
+ reportError("recieveUpdateData failed. " + "
Error name: " + error.name + "
Error Message: " + error.message);
+ return;
+ }
+
+ // reportError("recieveUpdateData passed trycatch block."); //debug hook
+
+ if (!updateData.hasOwnProperty('data'))
+ {
+ if (_data && _data.hasOwnProperty('data'))
+ {
+ updateData['data'] = _data['data'];
+ }
+ else
+ {
+ updateData['data'] = {};
+ }
+ }
+
+ if (_isInitialised) // all templates have been registered, so render them
+ {
+ doUpdate(updateData);
+ }
+ else
+ {
+ _data = updateData; // all templates have not been registered. We set _data directly here which will be applied after the template is loaded with the initial data
+ }
+ };
+
+ // This function does the update by calling the methods on the current state
+ var doUpdate = function (data)
+ {
+ if (_currentState == null)
+ {
+ return;
+ }
+
+ data = _currentState.onBeforeUpdate(data);
+
+ if (data === false)
+ {
+ reportError('data is false, return');
+ return; // A beforeUpdateCallback returned a false value, this prevents the render from occuring
+ }
+
+ _data = data;
+
+ _currentState.onUpdate(_data);
+
+ _currentState.onAfterUpdate(_data);
+ };
+
+ // Execute all callbacks in the callbacks array/object provided, updateData is passed to them for processing and potential modification
+ var executeCallbacks = function (callbacks, data)
+ {
+ for (var key in callbacks)
+ {
+ if (callbacks.hasOwnProperty(key) && jQuery.isFunction(callbacks[key]))
+ {
+ data = callbacks[key].call(this, data);
+ }
+ }
+
+ return data;
+ };
+
+ return {
+ init: function ()
+ {
+ init();
+ },
+ receiveUpdateData: function (jsonString)
+ {
+ receiveUpdateData(jsonString);
+ },
+ addBeforeUpdateCallback: function (key, callbackFunction)
+ {
+ _beforeUpdateCallbacks[key] = callbackFunction;
+ },
+ addBeforeUpdateCallbacks: function (callbacks) {
+ for (var callbackKey in callbacks) {
+ if (!callbacks.hasOwnProperty(callbackKey))
+ {
+ continue;
+ }
+ NanoStateManager.addBeforeUpdateCallback(callbackKey, callbacks[callbackKey]);
+ }
+ },
+ removeBeforeUpdateCallback: function (key)
+ {
+ if (_beforeUpdateCallbacks.hasOwnProperty(key))
+ {
+ delete _beforeUpdateCallbacks[key];
+ }
+ },
+ executeBeforeUpdateCallbacks: function (data) {
+ return executeCallbacks(_beforeUpdateCallbacks, data);
+ },
+ addAfterUpdateCallback: function (key, callbackFunction)
+ {
+ _afterUpdateCallbacks[key] = callbackFunction;
+ },
+ addAfterUpdateCallbacks: function (callbacks) {
+ for (var callbackKey in callbacks) {
+ if (!callbacks.hasOwnProperty(callbackKey))
+ {
+ continue;
+ }
+ NanoStateManager.addAfterUpdateCallback(callbackKey, callbacks[callbackKey]);
+ }
+ },
+ removeAfterUpdateCallback: function (key)
+ {
+ if (_afterUpdateCallbacks.hasOwnProperty(key))
+ {
+ delete _afterUpdateCallbacks[key];
+ }
+ },
+ executeAfterUpdateCallbacks: function (data) {
+ return executeCallbacks(_afterUpdateCallbacks, data);
+ },
+ addState: function (state)
+ {
+ if (!(state instanceof NanoStateClass))
+ {
+ reportError('ERROR: Attempted to add a state which is not instanceof NanoStateClass');
+ return;
+ }
+ if (!state.key)
+ {
+ reportError('ERROR: Attempted to add a state with an invalid stateKey');
+ return;
+ }
+ _states[state.key] = state;
+ },
+ setCurrentState: function (stateKey)
+ {
+ if (typeof stateKey == 'undefined' || !stateKey) {
+ reportError('ERROR: No state key was passed!');
+ return false;
+ }
+ if (!_states.hasOwnProperty(stateKey))
+ {
+ reportError('ERROR: Attempted to set a current state which does not exist: ' + stateKey);
+ return false;
+ }
+
+ var previousState = _currentState;
+
+ _currentState = _states[stateKey];
+
+ if (previousState != null) {
+ previousState.onRemove(_currentState);
+ }
+
+ _currentState.onAdd(previousState);
+
+ return true;
+ },
+ getCurrentState: function ()
+ {
+ return _currentState;
+ }
+ };
+} ();
+
\ No newline at end of file
diff --git a/nano/scripts/nano/1_nano_template.js b/nano/scripts/nano/nano_template.js
similarity index 57%
rename from nano/scripts/nano/1_nano_template.js
rename to nano/scripts/nano/nano_template.js
index f8f5d265948..7350e62d48d 100644
--- a/nano/scripts/nano/1_nano_template.js
+++ b/nano/scripts/nano/nano_template.js
@@ -5,19 +5,19 @@ var NanoTemplate = function () {
var _templates = {};
var _compiledTemplates = {};
-
- var _helpers = {};
+
+ var _helpers = {};
var init = function () {
// We store templateData in the body tag, it's as good a place as any
- _templateData = $('body').data('templateData');
+ _templateData = $('body').data('templateData');
- if (_templateData == null)
- {
- alert('Error: Template data did not load correctly.');
- }
+ if (_templateData == null)
+ {
+ reportError('Error: Template data did not load correctly.');
+ }
- loadNextTemplate();
+ loadNextTemplate();
};
var loadNextTemplate = function () {
@@ -43,40 +43,36 @@ var NanoTemplate = function () {
cache: false,
dataType: 'text'
}))
- .done(function(templateMarkup) {
+ .done( function(templateMarkup) {
templateMarkup += '';
- try
- {
+ try {
NanoTemplate.addTemplate(key, templateMarkup);
}
- catch(error)
- {
- alert('ERROR: An error occurred while loading the UI: ' + error.message);
+ catch(error) {
+ reportError('ERROR: An error occurred while loading the UI: ' + error.message);
return;
}
delete _templateData[key];
-
loadNextTemplate();
})
- .fail(function () {
- alert('ERROR: Loading template ' + key + '(' + _templateData[key] + ') failed!');
+ .fail( function () {
+ reportError('ERROR: Loading template ' + key + '(' + _templateData[key] + ') failed!');
});
return;
}
- }
+ };
var compileTemplates = function () {
-
for (var key in _templates) {
try {
- _compiledTemplates[key] = doT.template(_templates[key], null, _templates)
+ _compiledTemplates[key] = doT.template(_templates[key], null, _templates);
}
catch (error) {
- alert(error.message);
+ reportError(error.message);
}
}
};
@@ -94,42 +90,40 @@ var NanoTemplate = function () {
parse: function (templateKey, data) {
if (!_compiledTemplates.hasOwnProperty(templateKey) || !_compiledTemplates[templateKey]) {
if (!_templates.hasOwnProperty(templateKey)) {
- alert('ERROR: Template "' + templateKey + '" does not exist in _compiledTemplates!');
+ reportError('ERROR: Template "' + templateKey + '" does not exist in _compiledTemplates!');
return 'Template error (does not exist)
';
}
compileTemplates();
}
if (typeof _compiledTemplates[templateKey] != 'function') {
- alert(_compiledTemplates[templateKey]);
- alert('ERROR: Template "' + templateKey + '" failed to compile!');
+ reportError(_compiledTemplates[templateKey]);
+ reportError('ERROR: Template "' + templateKey + '" failed to compile!');
return 'Template error (failed to compile)
';
}
return _compiledTemplates[templateKey].call(this, data['data'], data['config'], _helpers);
},
- addHelper: function (helperName, helperFunction) {
- if (!jQuery.isFunction(helperFunction)) {
- alert('NanoTemplate.addHelper failed to add ' + helperName + ' as it is not a function.');
- return;
- }
-
- _helpers[helperName] = helperFunction;
- },
- addHelpers: function (helpers) {
- for (var helperName in helpers) {
- if (!helpers.hasOwnProperty(helperName))
- {
- continue;
- }
- NanoTemplate.addHelper(helperName, helpers[helperName]);
- }
- },
- removeHelper: function (helperName) {
- if (helpers.hasOwnProperty(helperName))
- {
- delete _helpers[helperName];
- }
- }
- }
+ addHelper: function (helperName, helperFunction) {
+ if (!jQuery.isFunction(helperFunction)) {
+ reportError('NanoTemplate.addHelper failed to add ' + helperName + ' as it is not a function.');
+ return;
+ }
+
+ _helpers[helperName] = helperFunction;
+ },
+ addHelpers: function (helpers) {
+ for (var helperName in helpers) {
+ if (!helpers.hasOwnProperty(helperName))
+ {
+ continue;
+ }
+ NanoTemplate.addHelper(helperName, helpers[helperName]);
+ }
+ },
+ removeHelper: function (helperName) {
+ if (helpers.hasOwnProperty(helperName))
+ {
+ delete _helpers[helperName];
+ }
+ }
+ };
}();
-
-
diff --git a/nano/scripts/nano/0_nano_utility.js b/nano/scripts/nano/nano_utility.js
similarity index 68%
rename from nano/scripts/nano/0_nano_utility.js
rename to nano/scripts/nano/nano_utility.js
index e65b7bbd138..bae16149874 100644
--- a/nano/scripts/nano/0_nano_utility.js
+++ b/nano/scripts/nano/nano_utility.js
@@ -1,68 +1,56 @@
// NanoUtility is the place to store utility functions
-var NanoUtility = function ()
-{
+var NanoUtility = function () {
var _urlParameters = {}; // This is populated with the base url parameters (used by all links), which is probaby just the "src" parameter
- return {
- init: function ()
- {
- var body = $('body'); // We store data in the body tag, it's as good a place as any
-
- _urlParameters = body.data('urlParameters');
+ return {
+ init: function () {
+ var body = $('body'); // We store data in the body tag, it's as good a place as any
+ _urlParameters = body.data('urlParameters');
},
- // generate a Byond href, combines _urlParameters with parameters
- generateHref: function (parameters)
- {
- var queryString = '?';
+ // generate a Byond href, combines _urlParameters with parameters
+ generateHref: function (parameters) {
+ var queryString = '?';
- for (var key in _urlParameters)
- {
- if (_urlParameters.hasOwnProperty(key))
- {
- if (queryString !== '?')
- {
- queryString += ';';
- }
- queryString += key + '=' + _urlParameters[key];
- }
- }
+ for (var key in _urlParameters) {
+ if (_urlParameters.hasOwnProperty(key)) {
+ if (queryString !== '?') {
+ queryString += ';';
+ }
+ queryString += key + '=' + _urlParameters[key];
+ }
+ }
- for (var key in parameters)
- {
- if (parameters.hasOwnProperty(key))
- {
- if (queryString !== '?')
- {
- queryString += ';';
- }
- queryString += key + '=' + parameters[key];
- }
- }
- return queryString;
- }
+ for (var key in parameters)
+ {
+ if (parameters.hasOwnProperty(key)) {
+ if (queryString !== '?') {
+ queryString += ';';
+ }
+ queryString += key + '=' + parameters[key];
+ }
+ }
+ return queryString;
+ }
}
-} ();
+} ();
if (typeof jQuery == 'undefined') {
- alert('ERROR: Javascript library failed to load!');
+ reportError('ERROR: Javascript library failed to load!');
}
if (typeof doT == 'undefined') {
- alert('ERROR: Template engine failed to load!');
-}
+ reportError('ERROR: Template engine failed to load!');
+}
-(function() {
- var _alert = window.alert;
- window.alert = function(str) {
- window.location = "byond://?nano_err=" + encodeURIComponent(str);
- _alert(str);
- };
-})();
+var reportError = function (str) {
+ window.location = "byond://?nano_err=" + encodeURIComponent(str);
+ alert(str);
+}
// All scripts are initialised here, this allows control of init order
$(document).ready(function () {
- NanoUtility.init();
- NanoStateManager.init();
- NanoTemplate.init();
+ NanoUtility.init();
+ NanoStateManager.init();
+ NanoTemplate.init();
});
if (!Array.prototype.indexOf)