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+"
"},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'
'+r+"
"},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='
',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+='",index++,index%n==0&&index
"):l++}return i+="
"},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+"
"},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'
'+n+"
"},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='
',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+='",d++,d%r==0&&d
"):l++}return i+="
"},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 ''; - } - - 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 '
' + showText + '
'; - }, - // 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 = '
'; - 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 += '' - - index++; - if (index % blockSize == 0 && index < characters.length) - { - block++; - subblock = 1; - html += '
'; - } - 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 ''; + } + + 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 '
' + showText + '
'; + }, + // 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 = '
'; + 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 += ''; + + index++; + if (index % blockSize == 0 && index < characters.length) { + block++; + subblock = 1; + html += '
'; + } 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)