").append( jQuery.parseHTML( responseText ) ).find( selector ) :
-
- // Otherwise use the full result
- responseText );
-
- }).complete( callback && function( jqXHR, status ) {
- self.each( callback, response || [ jqXHR.responseText, status, jqXHR ] );
- });
- }
-
- return this;
-};
-
-
-
-
-// Attach a bunch of functions for handling common AJAX events
-jQuery.each( [ "ajaxStart", "ajaxStop", "ajaxComplete", "ajaxError", "ajaxSuccess", "ajaxSend" ], function( i, type ) {
- jQuery.fn[ type ] = function( fn ) {
- return this.on( type, fn );
- };
-});
-
-
-
-
-jQuery.expr.filters.animated = function( elem ) {
- return jQuery.grep(jQuery.timers, function( fn ) {
- return elem === fn.elem;
- }).length;
-};
-
-
-
-
-
-var docElem = window.document.documentElement;
-
-/**
- * Gets a window from an element
- */
-function getWindow( elem ) {
- return jQuery.isWindow( elem ) ?
- elem :
- elem.nodeType === 9 ?
- elem.defaultView || elem.parentWindow :
- false;
-}
-
-jQuery.offset = {
- setOffset: function( elem, options, i ) {
- var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
- position = jQuery.css( elem, "position" ),
- curElem = jQuery( elem ),
- props = {};
-
- // set position first, in-case top/left are set even on static elem
- if ( position === "static" ) {
- elem.style.position = "relative";
- }
-
- curOffset = curElem.offset();
- curCSSTop = jQuery.css( elem, "top" );
- curCSSLeft = jQuery.css( elem, "left" );
- calculatePosition = ( position === "absolute" || position === "fixed" ) &&
- jQuery.inArray("auto", [ curCSSTop, curCSSLeft ] ) > -1;
-
- // need to be able to calculate position if either top or left is auto and position is either absolute or fixed
- if ( calculatePosition ) {
- curPosition = curElem.position();
- curTop = curPosition.top;
- curLeft = curPosition.left;
- } else {
- curTop = parseFloat( curCSSTop ) || 0;
- curLeft = parseFloat( curCSSLeft ) || 0;
- }
-
- if ( jQuery.isFunction( options ) ) {
- options = options.call( elem, i, curOffset );
- }
-
- if ( options.top != null ) {
- props.top = ( options.top - curOffset.top ) + curTop;
- }
- if ( options.left != null ) {
- props.left = ( options.left - curOffset.left ) + curLeft;
- }
-
- if ( "using" in options ) {
- options.using.call( elem, props );
- } else {
- curElem.css( props );
- }
- }
-};
-
-jQuery.fn.extend({
- offset: function( options ) {
- if ( arguments.length ) {
- return options === undefined ?
- this :
- this.each(function( i ) {
- jQuery.offset.setOffset( this, options, i );
- });
- }
-
- var docElem, win,
- box = { top: 0, left: 0 },
- elem = this[ 0 ],
- doc = elem && elem.ownerDocument;
-
- if ( !doc ) {
- return;
- }
-
- docElem = doc.documentElement;
-
- // Make sure it's not a disconnected DOM node
- if ( !jQuery.contains( docElem, elem ) ) {
- return box;
- }
-
- // If we don't have gBCR, just use 0,0 rather than error
- // BlackBerry 5, iOS 3 (original iPhone)
- if ( typeof elem.getBoundingClientRect !== strundefined ) {
- box = elem.getBoundingClientRect();
- }
- win = getWindow( doc );
- return {
- top: box.top + ( win.pageYOffset || docElem.scrollTop ) - ( docElem.clientTop || 0 ),
- left: box.left + ( win.pageXOffset || docElem.scrollLeft ) - ( docElem.clientLeft || 0 )
- };
- },
-
- position: function() {
- if ( !this[ 0 ] ) {
- return;
- }
-
- var offsetParent, offset,
- parentOffset = { top: 0, left: 0 },
- elem = this[ 0 ];
-
- // fixed elements are offset from window (parentOffset = {top:0, left: 0}, because it is its only offset parent
- if ( jQuery.css( elem, "position" ) === "fixed" ) {
- // we assume that getBoundingClientRect is available when computed position is fixed
- offset = elem.getBoundingClientRect();
- } else {
- // Get *real* offsetParent
- offsetParent = this.offsetParent();
-
- // Get correct offsets
- offset = this.offset();
- if ( !jQuery.nodeName( offsetParent[ 0 ], "html" ) ) {
- parentOffset = offsetParent.offset();
- }
-
- // Add offsetParent borders
- parentOffset.top += jQuery.css( offsetParent[ 0 ], "borderTopWidth", true );
- parentOffset.left += jQuery.css( offsetParent[ 0 ], "borderLeftWidth", true );
- }
-
- // Subtract parent offsets and element margins
- // note: when an element has margin: auto the offsetLeft and marginLeft
- // are the same in Safari causing offset.left to incorrectly be 0
- return {
- top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
- left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true)
- };
- },
-
- offsetParent: function() {
- return this.map(function() {
- var offsetParent = this.offsetParent || docElem;
-
- while ( offsetParent && ( !jQuery.nodeName( offsetParent, "html" ) && jQuery.css( offsetParent, "position" ) === "static" ) ) {
- offsetParent = offsetParent.offsetParent;
- }
- return offsetParent || docElem;
- });
- }
-});
-
-// Create scrollLeft and scrollTop methods
-jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
- var top = /Y/.test( prop );
-
- jQuery.fn[ method ] = function( val ) {
- return access( this, function( elem, method, val ) {
- var win = getWindow( elem );
-
- if ( val === undefined ) {
- return win ? (prop in win) ? win[ prop ] :
- win.document.documentElement[ method ] :
- elem[ method ];
- }
-
- if ( win ) {
- win.scrollTo(
- !top ? val : jQuery( win ).scrollLeft(),
- top ? val : jQuery( win ).scrollTop()
- );
-
- } else {
- elem[ method ] = val;
- }
- }, method, val, arguments.length, null );
- };
-});
-
-// Add the top/left cssHooks using jQuery.fn.position
-// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
-// getComputedStyle returns percent when specified for top/left/bottom/right
-// rather than make the css module depend on the offset module, we just check for it here
-jQuery.each( [ "top", "left" ], function( i, prop ) {
- jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
- function( elem, computed ) {
- if ( computed ) {
- computed = curCSS( elem, prop );
- // if curCSS returns percentage, fallback to offset
- return rnumnonpx.test( computed ) ?
- jQuery( elem ).position()[ prop ] + "px" :
- computed;
- }
- }
- );
-});
-
-
-// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
-jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
- jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name }, function( defaultExtra, funcName ) {
- // margin is only for outerHeight, outerWidth
- jQuery.fn[ funcName ] = function( margin, value ) {
- var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
- extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
-
- return access( this, function( elem, type, value ) {
- var doc;
-
- if ( jQuery.isWindow( elem ) ) {
- // As of 5/8/2012 this will yield incorrect results for Mobile Safari, but there
- // isn't a whole lot we can do. See pull request at this URL for discussion:
- // https://github.com/jquery/jquery/pull/764
- return elem.document.documentElement[ "client" + name ];
- }
-
- // Get document width or height
- if ( elem.nodeType === 9 ) {
- doc = elem.documentElement;
-
- // Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height], whichever is greatest
- // unfortunately, this causes bug #3838 in IE6/8 only, but there is currently no good, small way to fix it.
- return Math.max(
- elem.body[ "scroll" + name ], doc[ "scroll" + name ],
- elem.body[ "offset" + name ], doc[ "offset" + name ],
- doc[ "client" + name ]
- );
- }
-
- return value === undefined ?
- // Get width or height on the element, requesting but not forcing parseFloat
- jQuery.css( elem, type, extra ) :
-
- // Set width or height on the element
- jQuery.style( elem, type, value, extra );
- }, type, chainable ? margin : undefined, chainable, null );
- };
- });
-});
-
-
-// The number of elements contained in the matched element set
-jQuery.fn.size = function() {
- return this.length;
-};
-
-jQuery.fn.andSelf = jQuery.fn.addBack;
-
-
-
-
-// Register as a named AMD module, since jQuery can be concatenated with other
-// files that may use define, but not via a proper concatenation script that
-// understands anonymous AMD modules. A named AMD is safest and most robust
-// way to register. Lowercase jquery is used because AMD module names are
-// derived from file names, and jQuery is normally delivered in a lowercase
-// file name. Do this after creating the global so that if an AMD module wants
-// to call noConflict to hide this version of jQuery, it will work.
-
-// Note that for maximum portability, libraries that are not jQuery should
-// declare themselves as anonymous modules, and avoid setting a global if an
-// AMD loader is present. jQuery is a special case. For more information, see
-// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
-
-if ( typeof define === "function" && define.amd ) {
- define( "jquery", [], function() {
- return jQuery;
- });
-}
-
-
-
-
-var
- // Map over jQuery in case of overwrite
- _jQuery = window.jQuery,
-
- // Map over the $ in case of overwrite
- _$ = window.$;
-
-jQuery.noConflict = function( deep ) {
- if ( window.$ === jQuery ) {
- window.$ = _$;
- }
-
- if ( deep && window.jQuery === jQuery ) {
- window.jQuery = _jQuery;
- }
-
- return jQuery;
-};
-
-// Expose jQuery and $ identifiers, even in
-// AMD (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
-// and CommonJS for browser emulators (#13566)
-if ( typeof noGlobal === strundefined ) {
- window.jQuery = window.$ = jQuery;
-}
-
-
-
-
-return jQuery;
-
-}));
-
-
-/**
- * jQuery.timers - Timer abstractions for jQuery
- * Written by Blair Mitchelmore (blair DOT mitchelmore AT gmail DOT com)
- * Licensed under the WTFPL (http://sam.zoy.org/wtfpl/).
- * Date: 2009/10/16
- *
- * @author Blair Mitchelmore
- * @version 1.2
- *
- **/
-
-jQuery.fn.extend({
- everyTime: function(interval, label, fn, times) {
- return this.each(function() {
- jQuery.timer.add(this, interval, label, fn, times);
- });
- },
- oneTime: function(interval, label, fn) {
- return this.each(function() {
- jQuery.timer.add(this, interval, label, fn, 1);
- });
- },
- stopTime: function(label, fn) {
- return this.each(function() {
- jQuery.timer.remove(this, label, fn);
- });
- }
-});
-
-jQuery.extend({
- timer: {
- global: [],
- guid: 1,
- dataKey: "jQuery.timer",
- regex: /^([0-9]+(?:\.[0-9]*)?)\s*(.*s)?$/,
- powers: {
- // Yeah this is major overkill...
- 'ms': 1,
- 'cs': 10,
- 'ds': 100,
- 's': 1000,
- 'das': 10000,
- 'hs': 100000,
- 'ks': 1000000
- },
- timeParse: function(value) {
- if (value == undefined || value == null)
- return null;
- var result = this.regex.exec(jQuery.trim(value.toString()));
- if (result[2]) {
- var num = parseFloat(result[1]);
- var mult = this.powers[result[2]] || 1;
- return num * mult;
- } else {
- return value;
- }
- },
- add: function(element, interval, label, fn, times) {
- var counter = 0;
-
- if (jQuery.isFunction(label)) {
- if (!times)
- times = fn;
- fn = label;
- label = interval;
- }
-
- interval = jQuery.timer.timeParse(interval);
-
- if (typeof interval != 'number' || isNaN(interval) || interval < 0)
- return;
-
- if (typeof times != 'number' || isNaN(times) || times < 0)
- times = 0;
-
- times = times || 0;
-
- var timers = jQuery.data(element, this.dataKey) || jQuery.data(element, this.dataKey, {});
-
- if (!timers[label])
- timers[label] = {};
-
- fn.timerID = fn.timerID || this.guid++;
-
- var handler = function() {
- if ((++counter > times && times !== 0) || fn.call(element, counter) === false)
- jQuery.timer.remove(element, label, fn);
- };
-
- handler.timerID = fn.timerID;
-
- if (!timers[label][fn.timerID])
- timers[label][fn.timerID] = window.setInterval(handler,interval);
-
- this.global.push( element );
-
- },
- remove: function(element, label, fn) {
- var timers = jQuery.data(element, this.dataKey), ret;
-
- if ( timers ) {
-
- if (!label) {
- for ( label in timers )
- this.remove(element, label, fn);
- } else if ( timers[label] ) {
- if ( fn ) {
- if ( fn.timerID ) {
- window.clearInterval(timers[label][fn.timerID]);
- delete timers[label][fn.timerID];
- }
- } else {
- for ( var fn in timers[label] ) {
- window.clearInterval(timers[label][fn]);
- delete timers[label][fn];
- }
- }
-
- for ( ret in timers[label] ) break;
- if ( !ret ) {
- ret = null;
- delete timers[label];
- }
- }
-
- for ( ret in timers ) break;
- if ( !ret )
- jQuery.removeData(element, this.dataKey);
- }
- }
- }
-});
-
-jQuery(window).bind("unload", function() {
- jQuery.each(jQuery.timer.global, function(index, item) {
- jQuery.timer.remove(item);
- });
-});
\ No newline at end of file
diff --git a/nano/scripts/main.coffee b/nano/scripts/main.coffee
new file mode 100644
index 00000000000..5a0a6d2af15
--- /dev/null
+++ b/nano/scripts/main.coffee
@@ -0,0 +1,10 @@
+document.when "ready", =>
+ coderbus = {}
+
+ @nanoui = new @NanoUI coderbus, document
+ @nanowindow = new @Window coderbus, document
+
+ coderbus.emit "memes"
+
+ @NanoBus = coderbus
+ return
diff --git a/nano/scripts/nano_base_callbacks.js b/nano/scripts/nano_base_callbacks.js
deleted file mode 100644
index fb5a86ee3db..00000000000
--- a/nano/scripts/nano_base_callbacks.js
+++ /dev/null
@@ -1,126 +0,0 @@
-// NanoBaseCallbacks is where the base callbacks (common to all templates) are stored
-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 _baseAfterUpdateCallbacks = {
- // this callback is triggered after new data is processed
- // it updates the status/visibility icon and adds click event handling to buttons/links
- status: function (updateData) {
- var uiStatusClass;
- if (updateData['config']['status'] == 2)
- {
- uiStatusClass = 'icon24 uiStatusGood';
- $('.linkActive').removeClass('inactive');
- }
- else if (updateData['config']['status'] == 1)
- {
- uiStatusClass = 'icon24 uiStatusAverage';
- $('.linkActive').addClass('inactive');
- }
- else
- {
- uiStatusClass = 'icon24 uiStatusBad'
- $('.linkActive').addClass('inactive');
- }
- $('#uiStatusIcon').attr('class', uiStatusClass);
-
- $('.linkActive').stopTime('linkPending');
- $('.linkActive').removeClass('linkPending');
-
- $('.linkActive')
- .off('click')
- .on('click', function (event) {
- event.preventDefault();
- var href = $(this).data('href');
- if (href != null && _canClick)
- {
- _canClick = false;
- $('body').oneTime(300, 'enableClick', function () {
- _canClick = true;
- });
- if (updateData['config']['status'] == 2)
- {
- $(this).oneTime(300, 'linkPending', function () {
- $(this).addClass('linkPending');
- });
- }
- window.location.href = href;
- }
- });
-
- return updateData;
- },
- nanomap: function (updateData) {
- $('.mapIcon')
- .off('mouseenter mouseleave')
- .on('mouseenter',
- function (event) {
- var self = this;
- $('#uiMapTooltip')
- .html($(this).children('.tooltip').html())
- .show()
- .stopTime()
- .oneTime(5000, 'hideTooltip', function () {
- $(this).fadeOut(500);
- });
- }
- );
-
- $('.zoomLink')
- .off('click')
- .on('click', function (event) {
- event.preventDefault();
- var zoomLevel = $(this).data('zoomLevel');
- var uiMapObject = $('#uiMap');
- var uiMapWidth = uiMapObject.width() * zoomLevel;
- var uiMapHeight = uiMapObject.height() * zoomLevel;
-
- uiMapObject.css({
- zoom: zoomLevel,
- left: '50%',
- top: '50%',
- marginLeft: '-' + Math.floor(uiMapWidth / 2) + 'px',
- marginTop: '-' + Math.floor(uiMapHeight / 2) + 'px'
- });
- });
-
- $('#uiMapImage').attr('src', 'nanomap_z' + updateData['config']['mapZLevel'] + '.png');
-
- return updateData;
- }
- };
-
- return {
- addCallbacks: function () {
- NanoStateManager.addBeforeUpdateCallbacks(_baseBeforeUpdateCallbacks);
- NanoStateManager.addAfterUpdateCallbacks(_baseAfterUpdateCallbacks);
- },
- removeCallbacks: function () {
- for (var callbackKey in _baseBeforeUpdateCallbacks)
- {
- if (_baseBeforeUpdateCallbacks.hasOwnProperty(callbackKey))
- {
- NanoStateManager.removeBeforeUpdateCallback(callbackKey);
- }
- }
- for (var callbackKey in _baseAfterUpdateCallbacks)
- {
- if (_baseAfterUpdateCallbacks.hasOwnProperty(callbackKey))
- {
- NanoStateManager.removeAfterUpdateCallback(callbackKey);
- }
- }
- }
- };
-} ();
-
-
-
-
-
-
-
diff --git a/nano/scripts/nano_base_helpers.js b/nano/scripts/nano_base_helpers.js
deleted file mode 100644
index 20e6160fed4..00000000000
--- a/nano/scripts/nano_base_helpers.js
+++ /dev/null
@@ -1,213 +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 '';
- },
- // 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 + '
';
- },
- // Round a number to the nearest integer
- round: function(number) {
- return Math.round(number);
- },
- // Returns the number fixed to 1 decimal
- 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 '
';
- },
- // 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;
- }
- };
-
- 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_config.js b/nano/scripts/nano_config.js
deleted file mode 100644
index 8352b197ccf..00000000000
--- a/nano/scripts/nano_config.js
+++ /dev/null
@@ -1,100 +0,0 @@
-// NanoConfig is the place to store utility functions
-var NanoConfig = function ()
-{
- return {
- init: function ()
- {
- if (typeof jQuery == 'undefined') {
- alert('ERROR: jQuery failed to load!');
- }
- if (typeof $.views == 'undefined') {
- alert('ERROR: JSRender failed to load!');
- }
- }
- }
-} ();
-
-NanoConfig.init();
-
-if (!Array.prototype.indexOf)
-{
- Array.prototype.indexOf = function(elt /*, from*/)
- {
- var len = this.length;
-
- var from = Number(arguments[1]) || 0;
- from = (from < 0)
- ? Math.ceil(from)
- : Math.floor(from);
- if (from < 0)
- from += len;
-
- for (; from < len; from++)
- {
- if (from in this &&
- this[from] === elt)
- return from;
- }
- return -1;
- };
-};
-
-if (!String.prototype.format)
-{
- String.prototype.format = function (args) {
- var str = this;
- return str.replace(String.prototype.format.regex, function(item) {
- var intVal = parseInt(item.substring(1, item.length - 1));
- var replace;
- if (intVal >= 0) {
- replace = args[intVal];
- } else if (intVal === -1) {
- replace = "{";
- } else if (intVal === -2) {
- replace = "}";
- } else {
- replace = "";
- }
- return replace;
- });
- };
- String.prototype.format.regex = new RegExp("{-?[0-9]+}", "g");
-};
-
-Object.size = function(obj) {
- var size = 0, key;
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) size++;
- }
- return size;
-};
-
-if(!window.console) {
- window.console = {
- log : function(str) {
- return false;
- }
- };
-};
-
-String.prototype.toTitleCase = function () {
- var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|vs?\.?|via)$/i;
-
- return this.replace(/([^\W_]+[^\s-]*) */g, function (match, p1, index, title) {
- if (index > 0 && index + p1.length !== title.length &&
- p1.search(smallWords) > -1 && title.charAt(index - 2) !== ":" &&
- title.charAt(index - 1).search(/[^\s-]/) < 0) {
- return match.toLowerCase();
- }
-
- if (p1.substr(1).search(/[A-Z]|\../) > -1) {
- return match;
- }
-
- return match.charAt(0).toUpperCase() + match.substr(1);
- });
-};
-
-$.ajaxSetup({
- cache: false
-});
\ No newline at end of file
diff --git a/nano/scripts/nano_state.js b/nano/scripts/nano_state.js
deleted file mode 100644
index 198fa451246..00000000000
--- a/nano/scripts/nano_state.js
+++ /dev/null
@@ -1,121 +0,0 @@
-// 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);*/
-}
-
-NanoStateClass.prototype.key = null;
-NanoStateClass.prototype.layoutRendered = false;
-NanoStateClass.prototype.contentRendered = false;
-NanoStateClass.prototype.mapInitialised = false;
-
-NanoStateClass.prototype.isCurrent = function () {
- return NanoStateManager.getCurrentState() == this;
-};
-
-NanoStateClass.prototype.onAdd = function (previousState) {
- // Do not add code here, add it to the 'default' state (nano_state_defaut.js) or create a new state and override this function
-
- NanoBaseCallbacks.addCallbacks();
- NanoBaseHelpers.addHelpers();
-};
-
-NanoStateClass.prototype.onRemove = function (nextState) {
- // Do not add code here, add it to the 'default' state (nano_state_defaut.js) or create a new state and override this function
-
- NanoBaseCallbacks.removeCallbacks();
- NanoBaseHelpers.removeHelpers();
-};
-
-NanoStateClass.prototype.onBeforeUpdate = function (data) {
- // Do not add code here, add it to the 'default' state (nano_state_defaut.js) or create a new state and override this function
-
- data = NanoStateManager.executeBeforeUpdateCallbacks(data);
-
- return data; // Return data to continue, return false to prevent onUpdate and onAfterUpdate
-};
-
-NanoStateClass.prototype.onUpdate = function (data) {
- // Do not add code here, add it to the 'default' state (nano_state_defaut.js) or create a new state and override this function
-
- try
- {
- if (!this.layoutRendered || (data['config'].hasOwnProperty('autoUpdateLayout') && data['config']['autoUpdateLayout']))
- {
- $("#uiLayout").html(NanoTemplate.parse('layout', data)); // render the 'mail' template to the #mainTemplate div
- this.layoutRendered = true;
- }
- if (!this.contentRendered || (data['config'].hasOwnProperty('autoUpdateContent') && data['config']['autoUpdateContent']))
- {
- $("#uiContent").html(NanoTemplate.parse('main', data)); // render the 'mail' template to the #mainTemplate div
- this.contentRendered = true;
- }
- if (NanoTemplate.templateExists('mapContent'))
- {
- if (!this.mapInitialised)
- {
- // Add drag functionality to the map ui
- $('#uiMap').draggable({
- handle : '#uiMapImage'
- });
-
- $('#uiMapTooltip')
- .off('click')
- .on('click', function (event) {
- event.preventDefault();
- $(this).fadeOut(400);
- });
-
- this.mapInitialised = true;
- }
-
- $("#uiMapContent").html(NanoTemplate.parse('mapContent', data)); // render the 'mapContent' template to the #uiMapContent div
-
- if (data['config'].hasOwnProperty('showMap') && data['config']['showMap'])
- {
- $('#uiContent').addClass('hidden');
- $('#uiMapWrapper').removeClass('hidden');
- }
- else
- {
- $('#uiMapWrapper').addClass('hidden');
- $('#uiContent').removeClass('hidden');
- }
- }
- if (NanoTemplate.templateExists('mapHeader'))
- {
- $("#uiMapHeader").html(NanoTemplate.parse('mapHeader', data)); // render the 'mapHeader' template to the #uiMapHeader div
- }
- if (NanoTemplate.templateExists('mapFooter'))
- {
- $("#uiMapFooter").html(NanoTemplate.parse('mapFooter', data)); // render the 'mapFooter' template to the #uiMapFooter div
- }
- }
- catch(error)
- {
- alert('ERROR: An error occurred while rendering the UI: ' + error.message);
- return;
- }
-};
-
-NanoStateClass.prototype.onAfterUpdate = function (data) {
- // Do not add code here, add it to the 'default' state (nano_state_defaut.js) or create a new state and override this function
-
- NanoStateManager.executeAfterUpdateCallbacks(data);
-};
-
-NanoStateClass.prototype.alertText = function (text) {
- // Do not add code here, add it to the 'default' state (nano_state_defaut.js) or create a new state and override this function
-
- alert(text);
-};
-
-
diff --git a/nano/scripts/nano_state_default.js b/nano/scripts/nano_state_default.js
deleted file mode 100644
index 65493b8c87e..00000000000
--- a/nano/scripts/nano_state_default.js
+++ /dev/null
@@ -1,14 +0,0 @@
-
-NanoStateDefaultClass.inheritsFrom(NanoStateClass);
-var NanoStateDefault = new NanoStateDefaultClass();
-
-function NanoStateDefaultClass() {
-
- this.key = 'default';
-
- //this.parent.constructor.call(this);
-
- this.key = this.key.toLowerCase();
-
- NanoStateManager.addState(this);
-}
\ No newline at end of file
diff --git a/nano/scripts/nano_state_manager.js b/nano/scripts/nano_state_manager.js
deleted file mode 100644
index 84de1d1c89e..00000000000
--- a/nano/scripts/nano_state_manager.js
+++ /dev/null
@@ -1,220 +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;
- try
- {
- // parse the JSON string from the server into a JSON object
- updateData = jQuery.parseJSON(jsonString);
- }
- catch (error)
- {
- alert(error.Message);
- return;
- }
-
- 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_template.js b/nano/scripts/nano_template.js
deleted file mode 100644
index f8f5d265948..00000000000
--- a/nano/scripts/nano_template.js
+++ /dev/null
@@ -1,135 +0,0 @@
-
-var NanoTemplate = function () {
-
- var _templateData = {};
-
- var _templates = {};
- var _compiledTemplates = {};
-
- var _helpers = {};
-
- var init = function () {
- // We store templateData in the body tag, it's as good a place as any
- _templateData = $('body').data('templateData');
-
- if (_templateData == null)
- {
- alert('Error: Template data did not load correctly.');
- }
-
- loadNextTemplate();
- };
-
- var loadNextTemplate = function () {
- // we count the number of templates for this ui so that we know when they've all been rendered
- var templateCount = Object.size(_templateData);
-
- if (!templateCount)
- {
- $(document).trigger('templatesLoaded');
- return;
- }
-
- // load markup for each template and register it
- for (var key in _templateData)
- {
- if (!_templateData.hasOwnProperty(key))
- {
- continue;
- }
-
- $.when($.ajax({
- url: _templateData[key],
- cache: false,
- dataType: 'text'
- }))
- .done(function(templateMarkup) {
-
- templateMarkup += '
';
-
- try
- {
- NanoTemplate.addTemplate(key, templateMarkup);
- }
- catch(error)
- {
- alert('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!');
- });
-
- return;
- }
- }
-
- var compileTemplates = function () {
-
- for (var key in _templates) {
- try {
- _compiledTemplates[key] = doT.template(_templates[key], null, _templates)
- }
- catch (error) {
- alert(error.message);
- }
- }
- };
-
- return {
- init: function () {
- init();
- },
- addTemplate: function (key, templateString) {
- _templates[key] = templateString;
- },
- templateExists: function (key) {
- return _templates.hasOwnProperty(key);
- },
- parse: function (templateKey, data) {
- if (!_compiledTemplates.hasOwnProperty(templateKey) || !_compiledTemplates[templateKey]) {
- if (!_templates.hasOwnProperty(templateKey)) {
- alert('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!');
- 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];
- }
- }
- }
-}();
-
-
diff --git a/nano/scripts/nano_update.js b/nano/scripts/nano_update.js
deleted file mode 100644
index cb2eee021d7..00000000000
--- a/nano/scripts/nano_update.js
+++ /dev/null
@@ -1,236 +0,0 @@
-// NanoUpdate handles data from the server and uses it to render templates
-NanoUpdate = function ()
-{
- // _isInitialised is set to true when all of this ui's templates have been processed/rendered
- var _isInitialised = false;
-
- // the array of template names to use for this ui
- var _templates = null;
- // the data for this ui
- var _data = null;
- // new data which arrives before _isInitialised is true is stored here for processing later
- var _earlyUpdateData = 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 = [];
-
- // _canClick is used to disable clicks for a short period after each click (to avoid mis-clicks)
- var _canClick = true;
-
- // the init function is called when the ui has loaded
- // this function sets up the templates and base functionality
- var init = function ()
- {
- $('#uiNoJavaScript').html('Loading...');
-
- // this callback is triggered after new data is processed
- // it updates the status/visibility icon and adds click event handling to buttons/links
- NanoUpdate.addAfterUpdateCallback(function (updateData) {
- var uiStatusClass;
- if (updateData['ui']['status'] == 2)
- {
- uiStatusClass = 'icon24 uiStatusGood';
- $('.linkActive').removeClass('inactive');
- }
- else if (updateData['ui']['status'] == 1)
- {
- uiStatusClass = 'icon24 uiStatusAverage';
- $('.linkActive').addClass('inactive');
- }
- else
- {
- uiStatusClass = 'icon24 uiStatusBad'
- $('.linkActive').addClass('inactive');
- }
- $('#uiStatusIcon').attr('class', uiStatusClass);
-
- $('.linkActive').stopTime('linkPending');
- $('.linkActive').removeClass('linkPending');
-
- $('.linkActive').off('click');
- $('.linkActive').on('click', function (event) {
- event.preventDefault();
- var href = $(this).data('href');
- if (href != null && _canClick)
- {
- _canClick = false;
- $('body').oneTime(300, 'enableClick', function () {
- _canClick = true;
- });
- if (updateData['ui']['status'] == 2)
- {
- $(this).oneTime(300, 'linkPending', function () {
- $(this).addClass('linkPending');
- });
- }
- window.location.href = href;
- }
- });
- });
-
- // We store initialData and templateData in the body tag, it's as good a place as any
- var body = $('body');
- var templateData = body.data('templateData');
- var initialData = body.data('initialData');
-
- if (templateData == null || !initialData == null)
- {
- alert('Error: Initial data did not load correctly.');
- }
-
- // we count the number of templates for this ui so that we know when they've all been rendered
- var templateCount = 0;
- for (var key in templateData)
- {
- if (templateData.hasOwnProperty(key))
- {
- templateCount++;
- }
- }
-
- if (!templateCount)
- {
- alert('ERROR: No templates listed!');
- }
-
- // load markup for each template and register it
- for (var key in templateData)
- {
- if (templateData.hasOwnProperty(key))
- {
- $.when($.get(templateData[key]))
- .done(function(templateMarkup) {
- if (_templates == null)
- {
- _templates = {};
- }
-
- templateMarkup = templateMarkup.replace(/ +\) *\}\}/g, ')}}');
-
- templateMarkup += '
'
-
- try
- {
- _templates[key] = $.templates(key, templateMarkup);
-
- templateCount--;
-
- if (templateCount <= 0)
- {
- if (_earlyUpdateData !== null) // Newer data has already arrived, so update
- {
- renderTemplates(_earlyUpdateData);
- }
- else
- {
- renderTemplates(initialData);
- }
- _isInitialised = true;
- $('#uiNoJavaScript').hide();
- }
-
- executeCallbacks(_afterUpdateCallbacks, _data);
- }
- catch(error)
- {
- alert('ERROR: An error occurred while loading the UI: ' + error.message);
- return;
- }
- });
- }
- }
- };
-
- // Receive update data from the server
- var receiveUpdateData = function (jsonString)
- {
- var updateData;
- try
- {
- // parse the JSON string from the server into a JSON object
- updateData = jQuery.parseJSON(jsonString);
- }
- catch (error)
- {
- alert(error.Message);
- return;
- }
-
-
- if (_isInitialised) // all templates have been registered, so render them
- {
- executeCallbacks(_beforeUpdateCallbacks, updateData);
-
- renderTemplates(updateData);
-
- executeCallbacks(_afterUpdateCallbacks, updateData);
- }
- else
- {
- _earlyUpdateData = updateData; // all templates have not been registered. We set _earlyUpdateData which will be applied after the template is loaded with the initial data
- }
- };
-
- // This function renders the template with the latest data
- // It has to be done recursively as each piece of data is observed individually and needs to be updated individually
- var renderTemplates = function (data)
- {
- if (!_templates.hasOwnProperty("main"))
- {
- alert('Error: Main template not found.');
- }
-
- _data = data;
-
- try
- {
- $("#mainTemplate").html(_templates["main"].render(_data));
- }
- catch(error)
- {
- alert('ERROR: An error occurred while rendering the UI: ' + error.message);
- return;
- }
- };
-
- // Execute all callbacks in the callbacks array/object provided, updateData is passed to them for processing
- var executeCallbacks = function (callbacks, updateData)
- {
- for (var index in callbacks)
- {
- callbacks[index].call(this, updateData);
- }
-
- return updateData;
- };
-
- return {
- init: function ()
- {
- init();
- },
- isInitialised: function ()
- {
- return _isInitialised;
- },
- receiveUpdateData: function (jsonString)
- {
- receiveUpdateData(jsonString);
- },
- addBeforeUpdateCallback: function (callbackFunction)
- {
- _beforeUpdateCallbacks.push(callbackFunction);
- },
- addAfterUpdateCallback: function (callbackFunction)
- {
- _afterUpdateCallbacks.push(callbackFunction);
- }
- };
-} ();
-
-$(document).ready(function()
-{
- NanoUpdate.init();
-});
\ No newline at end of file
diff --git a/nano/scripts/nano_utility.js b/nano/scripts/nano_utility.js
deleted file mode 100644
index 59a4b2a24a6..00000000000
--- a/nano/scripts/nano_utility.js
+++ /dev/null
@@ -1,161 +0,0 @@
-// NanoUtility is the place to store utility functions
-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');
- },
- // 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 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!');
-}
-if (typeof doT == 'undefined') {
- alert('ERROR: Template engine failed to load!');
-}
-
-// All scripts are initialised here, this allows control of init order
-$(document).ready(function () {
- NanoUtility.init();
- NanoStateManager.init();
- NanoTemplate.init();
-});
-
-if (!Array.prototype.indexOf)
-{
- Array.prototype.indexOf = function(elt /*, from*/)
- {
- var len = this.length;
-
- var from = Number(arguments[1]) || 0;
- from = (from < 0)
- ? Math.ceil(from)
- : Math.floor(from);
- if (from < 0)
- from += len;
-
- for (; from < len; from++)
- {
- if (from in this &&
- this[from] === elt)
- return from;
- }
- return -1;
- };
-};
-
-if (!String.prototype.format)
-{
- String.prototype.format = function (args) {
- var str = this;
- return str.replace(String.prototype.format.regex, function(item) {
- var intVal = parseInt(item.substring(1, item.length - 1));
- var replace;
- if (intVal >= 0) {
- replace = args[intVal];
- } else if (intVal === -1) {
- replace = "{";
- } else if (intVal === -2) {
- replace = "}";
- } else {
- replace = "";
- }
- return replace;
- });
- };
- String.prototype.format.regex = new RegExp("{-?[0-9]+}", "g");
-};
-
-Object.size = function(obj) {
- var size = 0, key;
- for (var key in obj) {
- if (obj.hasOwnProperty(key)) size++;
- }
- return size;
-};
-
-if(!window.console) {
- window.console = {
- log : function(str) {
- return false;
- }
- };
-};
-
-String.prototype.toTitleCase = function () {
- var smallWords = /^(a|an|and|as|at|but|by|en|for|if|in|of|on|or|the|to|vs?\.?|via)$/i;
-
- return this.replace(/([^\W_]+[^\s-]*) */g, function (match, p1, index, title) {
- if (index > 0 && index + p1.length !== title.length &&
- p1.search(smallWords) > -1 && title.charAt(index - 2) !== ":" &&
- title.charAt(index - 1).search(/[^\s-]/) < 0) {
- return match.toLowerCase();
- }
-
- if (p1.substr(1).search(/[A-Z]|\../) > -1) {
- return match;
- }
-
- return match.charAt(0).toUpperCase() + match.substr(1);
- });
-};
-
-$.ajaxSetup({
- cache: false
-});
-
-Function.prototype.inheritsFrom = function (parentClassOrObject) {
- this.prototype = new parentClassOrObject;
- this.prototype.constructor = this;
- this.prototype.parent = parentClassOrObject.prototype;
- return this;
-};
-
-if (!String.prototype.trim) {
- String.prototype.trim = function () {
- return this.replace(/^\s+|\s+$/g, '');
- };
-}
-
-// Replicate the ckey proc from BYOND
-if (!String.prototype.ckey) {
- String.prototype.ckey = function () {
- return this.replace(/\W/g, '').toLowerCase();
- };
-}
\ No newline at end of file
diff --git a/nano/scripts/nanoui.coffee b/nano/scripts/nanoui.coffee
new file mode 100644
index 00000000000..5fb4e2cd426
--- /dev/null
+++ b/nano/scripts/nanoui.coffee
@@ -0,0 +1,88 @@
+class @NanoUI
+ constructor: (@bus, @fragment = document) ->
+ @bus.on "serverUpdate", @serverUpdate
+ @bus.on "update", @update
+ @bus.on "render", @render
+ @bus.on "memes", @render
+
+ @initialized = false
+
+ @data = {}
+ @initialData = JSON.parse @fragment.query("#data").data "initial"
+
+ unless @initialData? or
+ not ("data" of @initialData or "config" of @initalData)
+ @error "Initial data did not load correctly."
+
+ serverUpdate: (dataString) =>
+ try
+ data = JSON.parse(dataString)
+ catch error
+ @error error
+
+ @bus.emit "update", data
+ return
+
+ update: (data) =>
+ unless data.data?
+ if @data.data?
+ data.data = @data.data
+ else
+ data.data = {}
+
+ @data = data
+
+ @bus.emit "render", @data if @initialized
+ @bus.emit "updated"
+ return
+
+ render: (data) =>
+ data = @initialData unless @initialized
+
+ try
+ if not @initialized
+ layout = @fragment.query("#layout")
+ layout.innerHTML = TMPL[data.config.templates.layout]\
+ (data.data, data.config, helpers)
+
+ content = @fragment.query("#content")
+ content.innerHTML = TMPL[data.config.templates.content]\
+ (data.data, data.config, helpers)
+
+ catch error
+ @error error
+ return
+
+ @bus.emit "rendered", data
+ if not @initialized
+ @initialized = true
+ @data = @initialData
+ @bus.emit "initialized", data
+
+ act: (action, params = {}) =>
+ params.src = @data.config.ref
+ params.nano = action
+ location.href = util.href null, params
+
+ error: (error) ->
+ error = "#{error.fileName}:#{error.lineNumber} #{error.message}" if error instanceof Error
+ params =
+ nano_error: error
+ location.href = util.href null, params
+
+ log: (message) ->
+ params =
+ nano_log: message
+ location.href = util.href null, params
+
+ close: =>
+ params =
+ command: "nanoclose #{@data.config.ref}"
+ @winset "is-visible", "false"
+ location.href = util.href "winset", params
+
+ winset: (key, value, window) =>
+ window = @data.config.window.ref unless window?
+ params =
+ "#{window}.#{key}": value
+ location.href = util.href "winset", params
diff --git a/nano/scripts/util.coffee b/nano/scripts/util.coffee
new file mode 100644
index 00000000000..777490d93f2
--- /dev/null
+++ b/nano/scripts/util.coffee
@@ -0,0 +1,15 @@
+@util =
+ extend: (first, second) ->
+ Object.keys(second).forEach (key) ->
+ secondVal = second[key]
+ if secondVal and Object::toString.call(secondVal) is "[object Object]"
+ first[key] = first[key] or {}
+ util.extend first[key], secondVal
+ else
+ first[key] = secondVal
+ first
+
+ href: (url = "", params = {}) ->
+ url = new Url("byond://#{url}")
+ util.extend url.query, params
+ url
diff --git a/nano/scripts/window.coffee b/nano/scripts/window.coffee
new file mode 100644
index 00000000000..6c173b2cac9
--- /dev/null
+++ b/nano/scripts/window.coffee
@@ -0,0 +1,120 @@
+class @Window
+ constructor: (@bus, @fragment = document) ->
+ @dragging = false
+ @resizing = false
+
+ @bus.once "initialized", (data) =>
+ setTimeout @focusMap, 100 # Return focus once we're set up.
+ return unless data.config.user.fancy # Bail here if we're not to go chromeless.
+ @fancyChrome()
+ @calcOffset()
+ @attachButtons()
+ @attachDrag()
+ @attachResize()
+
+ @bus.on "rendered", @updateStatus
+ @bus.on "rendered", @updateLinks
+ @bus.on "rendered", @attachLinks
+ @fragment.on "keydown", @focusMap # If we get input, return focus.
+
+ setPos: (x, y) ->
+ nanoui.winset "pos", "#{x},#{y}"
+
+ setSize: (w, h) ->
+ nanoui.winset "size", "#{w},#{h}"
+
+ focusMap: ->
+ nanoui.winset "focus", 1, "mapwindow.map"
+
+ fancyChrome: =>
+ nanoui.winset "titlebar", 0
+ nanoui.winset "can-resize", 0
+ fancy = @fragment.queryAll ".fancy"
+ fancy.forEach (element) ->
+ element.style.display = 'inherit'
+
+ calcOffset: =>
+ @xOriginal = window.screenLeft
+ @yOriginal = window.screenTop
+ @setPos 0, 0 # Move to 0,0 to measure offsets.
+ @xOffset = window.screenLeft
+ @yOffset = window.screenTop
+ @setPos @xOriginal - @xOffset, @yOriginal - @yOffset # Put the window back.
+
+ attachButtons: =>
+ close = -> nanoui.close()
+ minimize = -> nanoui.winset "is-minimized", "true"
+
+ closers = @fragment.queryAll ".close"
+ closers.forEach (closer) ->
+ closer.on "click", close
+ minimizers = @fragment.queryAll ".minimize"
+ minimizers.forEach (minimizer) ->
+ minimizer.on "click", minimize
+
+ attachDrag: =>
+ titlebar = @fragment.query "#titlebar"
+ @fragment.on "mousemove", @drag
+ titlebar.on "mousedown", => @dragging = true
+ @fragment.on "mouseup", => @dragging = false
+
+ drag: (event = window.event) =>
+ return unless @dragging
+
+ @xDrag = event.screenX unless @xDrag?
+ @yDrag = event.screenY unless @yDrag?
+
+ x = (event.screenX - @xDrag) + (window.screenLeft - @xOffset)
+ y = (event.screenY - @yDrag) + (window.screenTop - @yOffset)
+ @setPos x, y
+
+ @xDrag = event.screenX
+ @yDrag = event.screenY
+
+ attachResize: =>
+ handle = @fragment.query "#resize"
+ @fragment.on "mousemove", @resize
+ handle.on "mousedown", => @resizing = true
+ @fragment.on "mouseup", => @resizing = false
+
+ resize: (event = window.event) =>
+ return unless @resizing
+
+ @xResize = event.screenX unless @xResize?
+ @yResize = event.screenY unless @yResize?
+
+ x = (event.screenX - @xResize) + window.innerWidth
+ y = (event.screenY - @yResize) + window.innerHeight
+ @setSize x, y
+
+ @xResize = event.screenX
+ @yResize = event.screenY
+
+ updateStatus: (data) =>
+ statusicons = @fragment.queryAll ".statusicon"
+ statusicons.forEach (statusicon) ->
+ statusicon.className = statusicon.className.replace /good|bad|average/g, ""
+ switch data.config.status
+ when NANO.INTERACTIVE
+ klass = "good"
+ when NANO.UPDATE
+ klass = "average"
+ else
+ klass = "bad"
+ statusicon.classList.add klass
+
+ updateLinks: (data) =>
+ links = @fragment.queryAll ".link"
+ if data.config.status isnt NANO.INTERACTIVE
+ links.forEach (element) ->
+ element.className = "link disabled"
+
+ attachLinks: (data) =>
+ onClick = ->
+ action = @data "action"
+ params = JSON.parse @data "params"
+ if action? and params? and data.config.status is NANO.INTERACTIVE
+ nanoui.act action, params
+
+ @fragment.queryAll(".link.active").forEach (link) ->
+ link.on "click", onClick
diff --git a/nano/styles/_bar.less b/nano/styles/_bar.less
new file mode 100644
index 00000000000..50e074f1b6e
--- /dev/null
+++ b/nano/styles/_bar.less
@@ -0,0 +1,48 @@
+@import "_config";
+@import "_util";
+
+
+.bar {
+ display: inline-block;
+ position: relative;
+ top: 4px; // Because this is an empty div, hack it so that it lines up.
+ vertical-align: top;
+ box-sizing: border-box;
+ width: 100%;
+ height: 20px; // Buttons are 22px, but look 20px because of their dark borders.
+ margin: 1px;
+ padding: 1px;
+
+ border: 1px solid @normal;
+
+ background: @dark;
+
+ .barText {
+ position: absolute;
+ top: 1px;
+ right: 3px;
+
+ .fontReset;
+ }
+
+ .barFill {
+ display: block;
+ height: 100%;
+
+ overflow: hidden;
+
+ background: @normal;
+ &.good {
+ background: @good;
+ }
+ &.average {
+ background: @average;
+ }
+ &.bad {
+ background: @bad;
+ }
+ &.highlight {
+ background: @highlight;
+ }
+ }
+}
diff --git a/nano/styles/_config.less b/nano/styles/_config.less
new file mode 100644
index 00000000000..3a0585d4989
--- /dev/null
+++ b/nano/styles/_config.less
@@ -0,0 +1,35 @@
+// Fonts
+@font: Verdana, Geneva, sans-serif;
+@fontsize: 12px;
+
+// Global Colors
+@normal: #40628a;
+@good: #537d29;
+@average: #be6209;
+@bad: #b00e0e;
+@highlight: #8ba5c4;
+@info: #e9C183;
+@label: @highlight;
+@dark: #272727;
+
+// Body Colors
+@title: #98b0c3;
+@text: white;
+@textinverse: black;
+@titlebar: #363636;
+@background-start: #2a2a2a;
+@background-end: #202020;
+@resize: #363636;
+
+// Component Colors
+@border: @dark;
+@rule: @normal;
+@notice1: #bb9b68;
+@notice2: #b1905d;
+
+// Link Colors
+@hover: 10%;
+@selected: #2f943c;
+@caution: #9a9d00;
+@danger: #9d0808;
+@disabled: #999999;
diff --git a/nano/styles/_document.less b/nano/styles/_document.less
new file mode 100644
index 00000000000..19c0e8cf4e2
--- /dev/null
+++ b/nano/styles/_document.less
@@ -0,0 +1,36 @@
+@import "_config";
+@import "_util";
+
+
+html {
+ min-height: 100%;
+
+ cursor: default; // Reset the cursor.
+}
+
+body {
+ min-height: 100%;
+
+ font-family: @font;
+ font-size: @fontsize;
+ color: @text;
+}
+
+h1 {
+ font-size: @fontsize + 6px;
+ margin: 0;
+ padding: 6px 0;
+}
+h2 {
+ &:extend(h1);
+ font-size: @fontsize + 4px;
+}
+h3 {
+ &:extend(h1);
+ font-size: @fontsize + 2px;
+}
+
+hr {
+ background-color: @rule;
+ border: none;
+}
diff --git a/nano/styles/_interface.less b/nano/styles/_interface.less
new file mode 100644
index 00000000000..6f771590332
--- /dev/null
+++ b/nano/styles/_interface.less
@@ -0,0 +1,94 @@
+@import "_config";
+@import "_util";
+
+
+article.display {
+ display: flex;
+ flex-flow: column nowrap;
+ width: auto;
+ padding: 4px;
+ margin: 6px 2px;
+
+ background-color: rgba(0, 0, 0, 0.33); // Transparent background.
+ box-shadow: inset 0 0 5px rgba(0, 0, 0, 0.5);
+
+ header {
+ padding-left: 4px;
+ margin-bottom: 6px;
+
+ border-bottom: 2px solid @rule;
+ }
+
+ section {
+ width: 100%;
+ padding: 3px 0;
+ }
+
+ .cell() {
+ display: inline-block;
+ margin: 0;
+ }
+
+ .label {
+ .cell;
+ width: 33%;
+
+ color: @label;
+ }
+
+ .content {
+ .cell;
+ width: 66%;
+ }
+
+ .line {
+ .cell;
+ width: 100%;
+ }
+
+ .buttoninfo {
+ margin-left: 5px;
+ }
+
+ table {
+ width: auto;
+
+ border-collapse: collapse;
+ }
+
+ table.grow {
+ width: 100%;
+ }
+
+ th {
+ vertical-align: top;
+ padding: 4px 16px 4px 0;
+ text-align: left;
+
+ .fontReset;
+ color: @label;
+ }
+
+ td {
+ &:extend(th);
+ padding: 2px 2px 0 0;
+ vertical-align: top;
+ }
+}
+
+article.notice {
+ &:extend(article.display all);
+ margin: 8px 2px;
+
+ box-shadow: none;
+
+ color: @textinverse;
+ font-weight: bold;
+ font-style: italic;
+
+ .label {
+ color: @textinverse;
+ }
+
+ .noticeStripes;
+}
diff --git a/nano/styles/_link.less b/nano/styles/_link.less
new file mode 100644
index 00000000000..12d0fe6cf35
--- /dev/null
+++ b/nano/styles/_link.less
@@ -0,0 +1,49 @@
+@import "_config";
+@import "_util";
+
+
+.active(@color) {
+ background-color: @color;
+ &:hover {
+ background-color: lighten(@color, @hover);
+ }
+}
+
+
+// Basic Link (Button) Element
+span.link {
+ display: inline-block;
+ box-sizing: border-box;
+ height: 22px;
+ margin: 1px;
+ padding: 2px 3px;
+ white-space: nowrap;
+
+ border: 1px solid @border;
+
+ .fontReset; // Reset font settings.
+
+ // Tweak spacing to fit icons.
+ .fa { margin-right: 3px; }
+ .iconed { padding-left: 3px; }
+
+ // Link colors:
+ background-color: @normal;
+ &.active {
+ .active(@normal);
+ &.selected { .active(@selected); }
+ &.caution { .active(@caution); }
+ &.danger { .active(@danger); }
+ }
+ &.inactive {
+ background-color: @disabled;
+ &.selected { background-color: @selected; }
+ &.caution { background-color: @caution; }
+ &.danger { background-color: @danger; }
+ }
+ &.disabled { background-color: @disabled; }
+
+ &.gridable {
+ width: 125px;
+ }
+}
diff --git a/nano/styles/_util.less b/nano/styles/_util.less
new file mode 100644
index 00000000000..bca0e8155b4
--- /dev/null
+++ b/nano/styles/_util.less
@@ -0,0 +1,57 @@
+@import "_config";
+
+
+// Colors
+.color(@color) { // Explort a given color as a class.
+ &.@{color} {
+ color: @@color;
+ }
+}
+
+.color(normal);
+.color(good);
+.color(average);
+.color(bad);
+.color(label);
+.color(highlight);
+.color(dark);
+
+// Text Styles
+.bold { font-weight: bold; }
+.italic { font-style: italic; }
+.fontReset {
+ color: @text;
+ font-size: @fontsize;
+ font-weight: normal;
+ font-style: normal;
+ text-decoration: none;
+}
+
+// Fancy "Notice Me" Stripes
+.noticeStripes {
+ background-color: @notice1; // Fallback for old browers.
+ background-image: repeating-linear-gradient(
+ -45deg,
+ @notice1,
+ @notice1 10px,
+ @notice2 10px,
+ @notice2 20px
+ );
+}
+
+// General Helpers
+.hidden { display: none; }
+
+.clearBoth { clear: both; }
+.clearLeft { clear: left; }
+.clearRight { clear: right; }
+
+.floatNone { float: none; }
+.floatLeft { float: left; }
+.floatRight { float: right; }
+
+.alignTop { vertical-align: top; }
+.alignBottom { vertical-align: bottom; }
+.alignLeft { text-align: left; }
+.alignCenter { text-align: center; }
+.alignRight { text-align: right; }
diff --git a/nano/styles/common.less b/nano/styles/common.less
new file mode 100644
index 00000000000..5bb5a44fe7c
--- /dev/null
+++ b/nano/styles/common.less
@@ -0,0 +1,86 @@
+@import "_config";
+@import "_document";
+@import "_util";
+@import "_interface";
+@import "_link";
+@import "_bar";
+
+
+.fancy {
+ display: none;
+}
+
+
+div.loading {
+ .noticeStripes;
+
+ padding: 8px;
+}
+
+div.content {
+ margin: 32px 4px 0 4px;
+ &.titlebared {
+ padding-top: 3px;
+ }
+}
+
+header.titlebar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 32px;
+
+ background-color: @titlebar;
+ box-shadow: 0 3px 3px rgba(0, 0, 0, 0.1);
+
+ .statusicon {
+ position: absolute;
+ top: 4px;
+ left: 12px;
+ }
+
+ .title {
+ position: absolute;
+ top: 6px;
+ left: 46px;
+
+ color: @title;
+ font-size: 16px;
+ white-space: nowrap;
+ }
+
+ .titlebutton() {
+ color: @title;
+
+ &:hover {
+ color: lighten(@title, @hover);
+ }
+ }
+ .minimize {
+ .titlebutton;
+ position: absolute;
+ top: 6px;
+ right: 46px;
+ }
+ .close {
+ .titlebutton;
+ position: absolute;
+ top: 4px;
+ right: 12px;
+ }
+}
+
+div.resize {
+ position: fixed;
+ bottom: 0;
+ right: 0;
+ width: 0;
+ height: 0;
+
+ border-style: solid;
+ border-width: 0 0 30px 30px;
+ border-color: transparent transparent @resize transparent;
+
+ transform: rotate(360deg);
+}
diff --git a/nano/styles/generic.less b/nano/styles/generic.less
new file mode 100644
index 00000000000..8f9f725f50c
--- /dev/null
+++ b/nano/styles/generic.less
@@ -0,0 +1,8 @@
+@import "_config";
+
+
+body {
+ background: linear-gradient(to bottom,
+ @background-start 0%,
+ @background-end 100%);
+}
diff --git a/nano/styles/icons.css b/nano/styles/icons.css
deleted file mode 100644
index be288fc1e81..00000000000
--- a/nano/styles/icons.css
+++ /dev/null
@@ -1,314 +0,0 @@
-/* Icons
-----------------------------------*/
-
-.icon24
-{
- width: 24px;
- height: 24px;
-}
-
-.icon24.uiStatusGood
-{
- background: url(uiIcons24.png) 0 0 no-repeat;
-}
-
-.icon24.uiStatusAverage
-{
- background: url(uiIcons24.png) 0 -24px no-repeat;
-}
-
-.icon24.uiStatusBad
-{
- background: url(uiIcons24.png) 0 -48px no-repeat;
-}
-
-/* states and images */
-.uiIcon16 {
- float: left;
- width: 16px;
- height: 16px;
- margin: 2px 2px 0 2px;
- background-image: url(uiIcons16.png);
-}
-
-.uiLinkPendingIcon {
- display: none;
- float: left;
- width: 16px;
- height: 16px;
- margin: 2px 2px 0 2px;
- background-image: url(uiLinkPendingIcon.gif);
-}
-
-.linkPending .uiIcon16 {
- display: none;
-}
-
-.linkPending .uiLinkPendingIcon {
- display: block;
-}
-
-/* positioning */
-.uiIcon16.icon-blank { background-position: 16px 16px; }
-.uiIcon16.icon-carat-1-n { background-position: 0 0; }
-.uiIcon16.icon-carat-1-ne { background-position: -16px 0; }
-.uiIcon16.icon-carat-1-e { background-position: -32px 0; }
-.uiIcon16.icon-carat-1-se { background-position: -48px 0; }
-.uiIcon16.icon-carat-1-s { background-position: -64px 0; }
-.uiIcon16.icon-carat-1-sw { background-position: -80px 0; }
-.uiIcon16.icon-carat-1-w { background-position: -96px 0; }
-.uiIcon16.icon-carat-1-nw { background-position: -112px 0; }
-.uiIcon16.icon-carat-2-n-s { background-position: -128px 0; }
-.uiIcon16.icon-carat-2-e-w { background-position: -144px 0; }
-.uiIcon16.icon-triangle-1-n { background-position: 0 -16px; }
-.uiIcon16.icon-triangle-1-ne { background-position: -16px -16px; }
-.uiIcon16.icon-triangle-1-e { background-position: -32px -16px; }
-.uiIcon16.icon-triangle-1-se { background-position: -48px -16px; }
-.uiIcon16.icon-triangle-1-s { background-position: -64px -16px; }
-.uiIcon16.icon-triangle-1-sw { background-position: -80px -16px; }
-.uiIcon16.icon-triangle-1-w { background-position: -96px -16px; }
-.uiIcon16.icon-triangle-1-nw { background-position: -112px -16px; }
-.uiIcon16.icon-triangle-2-n-s { background-position: -128px -16px; }
-.uiIcon16.icon-triangle-2-e-w { background-position: -144px -16px; }
-.uiIcon16.icon-arrow-1-n { background-position: 0 -32px; }
-.uiIcon16.icon-arrow-1-ne { background-position: -16px -32px; }
-.uiIcon16.icon-arrow-1-e { background-position: -32px -32px; }
-.uiIcon16.icon-arrow-1-se { background-position: -48px -32px; }
-.uiIcon16.icon-arrow-1-s { background-position: -64px -32px; }
-.uiIcon16.icon-arrow-1-sw { background-position: -80px -32px; }
-.uiIcon16.icon-arrow-1-w { background-position: -96px -32px; }
-.uiIcon16.icon-arrow-1-nw { background-position: -112px -32px; }
-.uiIcon16.icon-arrow-2-n-s { background-position: -128px -32px; }
-.uiIcon16.icon-arrow-2-ne-sw { background-position: -144px -32px; }
-.uiIcon16.icon-arrow-2-e-w { background-position: -160px -32px; }
-.uiIcon16.icon-arrow-2-se-nw { background-position: -176px -32px; }
-.uiIcon16.icon-arrowstop-1-n { background-position: -192px -32px; }
-.uiIcon16.icon-arrowstop-1-e { background-position: -208px -32px; }
-.uiIcon16.icon-arrowstop-1-s { background-position: -224px -32px; }
-.uiIcon16.icon-arrowstop-1-w { background-position: -240px -32px; }
-.uiIcon16.icon-arrowthick-1-n { background-position: 0 -48px; }
-.uiIcon16.icon-arrowthick-1-ne { background-position: -16px -48px; }
-.uiIcon16.icon-arrowthick-1-e { background-position: -32px -48px; }
-.uiIcon16.icon-arrowthick-1-se { background-position: -48px -48px; }
-.uiIcon16.icon-arrowthick-1-s { background-position: -64px -48px; }
-.uiIcon16.icon-arrowthick-1-sw { background-position: -80px -48px; }
-.uiIcon16.icon-arrowthick-1-w { background-position: -96px -48px; }
-.uiIcon16.icon-arrowthick-1-nw { background-position: -112px -48px; }
-.uiIcon16.icon-arrowthick-2-n-s { background-position: -128px -48px; }
-.uiIcon16.icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
-.uiIcon16.icon-arrowthick-2-e-w { background-position: -160px -48px; }
-.uiIcon16.icon-arrowthick-2-se-nw { background-position: -176px -48px; }
-.uiIcon16.icon-arrowthickstop-1-n { background-position: -192px -48px; }
-.uiIcon16.icon-arrowthickstop-1-e { background-position: -208px -48px; }
-.uiIcon16.icon-arrowthickstop-1-s { background-position: -224px -48px; }
-.uiIcon16.icon-arrowthickstop-1-w { background-position: -240px -48px; }
-.uiIcon16.icon-arrowreturnthick-1-w { background-position: 0 -64px; }
-.uiIcon16.icon-arrowreturnthick-1-n { background-position: -16px -64px; }
-.uiIcon16.icon-arrowreturnthick-1-e { background-position: -32px -64px; }
-.uiIcon16.icon-arrowreturnthick-1-s { background-position: -48px -64px; }
-.uiIcon16.icon-arrowreturn-1-w { background-position: -64px -64px; }
-.uiIcon16.icon-arrowreturn-1-n { background-position: -80px -64px; }
-.uiIcon16.icon-arrowreturn-1-e { background-position: -96px -64px; }
-.uiIcon16.icon-arrowreturn-1-s { background-position: -112px -64px; }
-.uiIcon16.icon-arrowrefresh-1-w { background-position: -128px -64px; }
-.uiIcon16.icon-arrowrefresh-1-n { background-position: -144px -64px; }
-.uiIcon16.icon-arrowrefresh-1-e { background-position: -160px -64px; }
-.uiIcon16.icon-arrowrefresh-1-s { background-position: -176px -64px; }
-.uiIcon16.icon-arrow-4 { background-position: 0 -80px; }
-.uiIcon16.icon-arrow-4-diag { background-position: -16px -80px; }
-.uiIcon16.icon-extlink { background-position: -32px -80px; }
-.uiIcon16.icon-newwin { background-position: -48px -80px; }
-.uiIcon16.icon-refresh { background-position: -64px -80px; }
-.uiIcon16.icon-shuffle { background-position: -80px -80px; }
-.uiIcon16.icon-transfer-e-w { background-position: -96px -80px; }
-.uiIcon16.icon-transferthick-e-w { background-position: -112px -80px; }
-.uiIcon16.icon-radiation { background-position: -128px -80px; }
-.uiIcon16.icon-folder-collapsed { background-position: 0 -96px; }
-.uiIcon16.icon-folder-open { background-position: -16px -96px; }
-.uiIcon16.icon-document { background-position: -32px -96px; }
-.uiIcon16.icon-document-b { background-position: -48px -96px; }
-.uiIcon16.icon-note { background-position: -64px -96px; }
-.uiIcon16.icon-mail-closed { background-position: -80px -96px; }
-.uiIcon16.icon-mail-open { background-position: -96px -96px; }
-.uiIcon16.icon-suitcase { background-position: -112px -96px; }
-.uiIcon16.icon-comment { background-position: -128px -96px; }
-.uiIcon16.icon-person { background-position: -144px -96px; }
-.uiIcon16.icon-print { background-position: -160px -96px; }
-.uiIcon16.icon-trash { background-position: -176px -96px; }
-.uiIcon16.icon-locked { background-position: -192px -96px; }
-.uiIcon16.icon-unlocked { background-position: -208px -96px; }
-.uiIcon16.icon-bookmark { background-position: -224px -96px; }
-.uiIcon16.icon-tag { background-position: -240px -96px; }
-.uiIcon16.icon-home { background-position: 0 -112px; }
-.uiIcon16.icon-flag { background-position: -16px -112px; }
-.uiIcon16.icon-calendar { background-position: -32px -112px; }
-.uiIcon16.icon-cart { background-position: -48px -112px; }
-.uiIcon16.icon-pencil { background-position: -64px -112px; }
-.uiIcon16.icon-clock { background-position: -80px -112px; }
-.uiIcon16.icon-disk { background-position: -96px -112px; }
-.uiIcon16.icon-calculator { background-position: -112px -112px; }
-.uiIcon16.icon-zoomin { background-position: -128px -112px; }
-.uiIcon16.icon-zoomout { background-position: -144px -112px; }
-.uiIcon16.icon-search { background-position: -160px -112px; }
-.uiIcon16.icon-wrench { background-position: -176px -112px; }
-.uiIcon16.icon-gear { background-position: -192px -112px; }
-.uiIcon16.icon-heart { background-position: -208px -112px; }
-.uiIcon16.icon-star { background-position: -224px -112px; }
-.uiIcon16.icon-link { background-position: -240px -112px; }
-.uiIcon16.icon-cancel { background-position: 0 -128px; }
-.uiIcon16.icon-plus { background-position: -16px -128px; }
-.uiIcon16.icon-plusthick { background-position: -32px -128px; }
-.uiIcon16.icon-minus { background-position: -48px -128px; }
-.uiIcon16.icon-minusthick { background-position: -64px -128px; }
-.uiIcon16.icon-close { background-position: -80px -128px; }
-.uiIcon16.icon-closethick { background-position: -96px -128px; }
-.uiIcon16.icon-key { background-position: -112px -128px; }
-.uiIcon16.icon-lightbulb { background-position: -128px -128px; }
-.uiIcon16.icon-scissors { background-position: -144px -128px; }
-.uiIcon16.icon-clipboard { background-position: -160px -128px; }
-.uiIcon16.icon-copy { background-position: -176px -128px; }
-.uiIcon16.icon-contact { background-position: -192px -128px; }
-.uiIcon16.icon-image { background-position: -208px -128px; }
-.uiIcon16.icon-video { background-position: -224px -128px; }
-.uiIcon16.icon-script { background-position: -240px -128px; }
-.uiIcon16.icon-alert { background-position: 0 -144px; }
-.uiIcon16.icon-info { background-position: -16px -144px; }
-.uiIcon16.icon-notice { background-position: -32px -144px; }
-.uiIcon16.icon-help { background-position: -48px -144px; }
-.uiIcon16.icon-check { background-position: -64px -144px; }
-.uiIcon16.icon-bullet { background-position: -80px -144px; }
-.uiIcon16.icon-radio-on { background-position: -96px -144px; }
-.uiIcon16.icon-radio-off { background-position: -112px -144px; }
-.uiIcon16.icon-pin-w { background-position: -128px -144px; }
-.uiIcon16.icon-pin-s { background-position: -144px -144px; }
-.uiIcon16.icon-play { background-position: 0 -160px; }
-.uiIcon16.icon-pause { background-position: -16px -160px; }
-.uiIcon16.icon-seek-next { background-position: -32px -160px; }
-.uiIcon16.icon-seek-prev { background-position: -48px -160px; }
-.uiIcon16.icon-seek-end { background-position: -64px -160px; }
-.uiIcon16.icon-seek-start { background-position: -80px -160px; }
-/* uiIcon-seek-first is deprecated, use uiIcon-seek-start instead */
-.uiIcon16.icon-seek-first { background-position: -80px -160px; }
-.uiIcon16.icon-stop { background-position: -96px -160px; }
-.uiIcon16.icon-eject { background-position: -112px -160px; }
-.uiIcon16.icon-volume-off { background-position: -128px -160px; }
-.uiIcon16.icon-volume-on { background-position: -144px -160px; }
-.uiIcon16.icon-power { background-position: 0 -176px; }
-.uiIcon16.icon-signal-diag { background-position: -16px -176px; }
-.uiIcon16.icon-signal { background-position: -32px -176px; }
-.uiIcon16.icon-battery-0 { background-position: -48px -176px; }
-.uiIcon16.icon-battery-1 { background-position: -64px -176px; }
-.uiIcon16.icon-battery-2 { background-position: -80px -176px; }
-.uiIcon16.icon-battery-3 { background-position: -96px -176px; }
-.uiIcon16.icon-circle-plus { background-position: 0 -192px; }
-.uiIcon16.icon-circle-minus { background-position: -16px -192px; }
-.uiIcon16.icon-circle-close { background-position: -32px -192px; }
-.uiIcon16.icon-circle-triangle-e { background-position: -48px -192px; }
-.uiIcon16.icon-circle-triangle-s { background-position: -64px -192px; }
-.uiIcon16.icon-circle-triangle-w { background-position: -80px -192px; }
-.uiIcon16.icon-circle-triangle-n { background-position: -96px -192px; }
-.uiIcon16.icon-circle-arrow-e { background-position: -112px -192px; }
-.uiIcon16.icon-circle-arrow-s { background-position: -128px -192px; }
-.uiIcon16.icon-circle-arrow-w { background-position: -144px -192px; }
-.uiIcon16.icon-circle-arrow-n { background-position: -160px -192px; }
-.uiIcon16.icon-circle-zoomin { background-position: -176px -192px; }
-.uiIcon16.icon-circle-zoomout { background-position: -192px -192px; }
-.uiIcon16.icon-circle-check { background-position: -208px -192px; }
-.uiIcon16.icon-circlesmall-plus { background-position: 0 -208px; }
-.uiIcon16.icon-circlesmall-minus { background-position: -16px -208px; }
-.uiIcon16.icon-circlesmall-close { background-position: -32px -208px; }
-.uiIcon16.icon-squaresmall-plus { background-position: -48px -208px; }
-.uiIcon16.icon-squaresmall-minus { background-position: -64px -208px; }
-.uiIcon16.icon-squaresmall-close { background-position: -80px -208px; }
-.uiIcon16.icon-grip-dotted-vertical { background-position: 0 -224px; }
-.uiIcon16.icon-grip-dotted-horizontal { background-position: -16px -224px; }
-.uiIcon16.icon-grip-solid-vertical { background-position: -32px -224px; }
-.uiIcon16.icon-grip-solid-horizontal { background-position: -48px -224px; }
-.uiIcon16.icon-gripsmall-diagonal-se { background-position: -64px -224px; }
-.uiIcon16.icon-grip-diagonal-se { background-position: -80px -224px; }
-.uiIcon16.icon-batt_full { background-image: url(c_max.gif); background-position: 0px 0px }
-.uiIcon16.icon-batt_disc { background-image: url(c_discharging.gif); background-position: 0px 0px }
-.uiIcon16.icon-batt_chrg { background-image: url(c_charging.gif); background-position: 0px 0px }
-
-.mapIcon16 {
- position: absolute;
- width: 16px;
- height: 16px;
- background-image: url(uiIcons16Green.png);
- background-position: -144px -96px;
- background-repeat: no-repeat;
- zoom: 0.125;
- margin-left: -1px;
- /*margin-bottom: -1px;*/
-}
-.mapIcon16.dead {
- background-image: url(uiIcons16Red.png);
-}
-
-/* Command Positions */
-.mapIcon16.rank-captain {
- background-position: -224px -112px;
-}
-.mapIcon16.rank-headofpersonnel {
- background-position: -112px -96px;
-}
-.mapIcon16.rank-headofsecurity {
- background-position: -112px -128px;
-}
-.mapIcon16.rank-chiefengineer {
- background-position: -176px -112px;
-}
-.mapIcon16.rank-researchdirector {
- background-position: -128px -128px;
-}
-.mapIcon16.rank-chiefmedicalofficer {
- background-position: -32px -128px;
-}
-
-/* Engineering Positions */
-.mapIcon16.rank-stationengineer {
- background-position: -176px -112px;
-}
-.mapIcon16.rank-atmospherictechnician {
- background-position: -176px -112px;
-}
-
-/* Medical Positions */
-.mapIcon16.rank-medicaldoctor {
- background-position: -32px -128px;
-}
-.mapIcon16.rank-geneticist {
- background-position: -32px -128px;
-}
-.mapIcon16.rank-psychiatrist {
- background-position: -32px -128px;
-}
-.mapIcon16.rank-chemist {
- background-position: -32px -128px;
-}
-
-/* Science Positions */
-.mapIcon16.rank-scientist {
- background-position: -128px -128px;
-}
-.mapIcon16.rank-geneticist {
- background-position: -128px -128px;
-}
-.mapIcon16.rank-roboticist {
- background-position: -128px -128px;
-}
-.mapIcon16.rank-xenobiologist {
- background-position: -128px -128px;
-}
-
-/* Security Positions */
-.mapIcon16.rank-warden {
- background-position: -112px -128px;
-}
-.mapIcon16.rank-detective {
- background-position: -112px -128px;
-}
-.mapIcon16.rank-securityofficer {
- background-position: -112px -128px;
-}
-
diff --git a/nano/styles/nanotrasen.less b/nano/styles/nanotrasen.less
new file mode 100644
index 00000000000..3ae88d052e3
--- /dev/null
+++ b/nano/styles/nanotrasen.less
@@ -0,0 +1,9 @@
+@import "_config";
+
+
+body {
+ background: data-uri('nanotrasen.svg') no-repeat fixed center/70% 70%,
+ linear-gradient(to bottom,
+ @background-start 0%,
+ @background-end 100%) no-repeat fixed center/100% 100%;
+}
diff --git a/nano/styles/normalize.css b/nano/styles/normalize.css
deleted file mode 100644
index 458eea1ea3d..00000000000
--- a/nano/styles/normalize.css
+++ /dev/null
@@ -1,427 +0,0 @@
-/*! normalize.css v3.0.2 | MIT License | git.io/normalize */
-
-/**
- * 1. Set default font family to sans-serif.
- * 2. Prevent iOS text size adjust after orientation change, without disabling
- * user zoom.
- */
-
-html {
- font-family: sans-serif; /* 1 */
- -ms-text-size-adjust: 100%; /* 2 */
- -webkit-text-size-adjust: 100%; /* 2 */
-}
-
-/**
- * Remove default margin.
- */
-
-body {
- margin: 0;
-}
-
-/* HTML5 display definitions
- ========================================================================== */
-
-/**
- * Correct `block` display not defined for any HTML5 element in IE 8/9.
- * Correct `block` display not defined for `details` or `summary` in IE 10/11
- * and Firefox.
- * Correct `block` display not defined for `main` in IE 11.
- */
-
-article,
-aside,
-details,
-figcaption,
-figure,
-footer,
-header,
-hgroup,
-main,
-menu,
-nav,
-section,
-summary {
- display: block;
-}
-
-/**
- * 1. Correct `inline-block` display not defined in IE 8/9.
- * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera.
- */
-
-audio,
-canvas,
-progress,
-video {
- display: inline-block; /* 1 */
- vertical-align: baseline; /* 2 */
-}
-
-/**
- * Prevent modern browsers from displaying `audio` without controls.
- * Remove excess height in iOS 5 devices.
- */
-
-audio:not([controls]) {
- display: none;
- height: 0;
-}
-
-/**
- * Address `[hidden]` styling not present in IE 8/9/10.
- * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22.
- */
-
-[hidden],
-template {
- display: none;
-}
-
-/* Links
- ========================================================================== */
-
-/**
- * Remove the gray background color from active links in IE 10.
- */
-
-a {
- background-color: transparent;
-}
-
-/**
- * Improve readability when focused and also mouse hovered in all browsers.
- */
-
-a:active,
-a:hover {
- outline: 0;
-}
-
-/* Text-level semantics
- ========================================================================== */
-
-/**
- * Address styling not present in IE 8/9/10/11, Safari, and Chrome.
- */
-
-abbr[title] {
- border-bottom: 1px dotted;
-}
-
-/**
- * Address style set to `bolder` in Firefox 4+, Safari, and Chrome.
- */
-
-b,
-strong {
- font-weight: bold;
-}
-
-/**
- * Address styling not present in Safari and Chrome.
- */
-
-dfn {
- font-style: italic;
-}
-
-/**
- * Address variable `h1` font-size and margin within `section` and `article`
- * contexts in Firefox 4+, Safari, and Chrome.
- */
-
-h1 {
- font-size: 2em;
- margin: 0.67em 0;
-}
-
-/**
- * Address styling not present in IE 8/9.
- */
-
-mark {
- background: #ff0;
- color: #000;
-}
-
-/**
- * Address inconsistent and variable font size in all browsers.
- */
-
-small {
- font-size: 80%;
-}
-
-/**
- * Prevent `sub` and `sup` affecting `line-height` in all browsers.
- */
-
-sub,
-sup {
- font-size: 75%;
- line-height: 0;
- position: relative;
- vertical-align: baseline;
-}
-
-sup {
- top: -0.5em;
-}
-
-sub {
- bottom: -0.25em;
-}
-
-/* Embedded content
- ========================================================================== */
-
-/**
- * Remove border when inside `a` element in IE 8/9/10.
- */
-
-img {
- border: 0;
-}
-
-/**
- * Correct overflow not hidden in IE 9/10/11.
- */
-
-svg:not(:root) {
- overflow: hidden;
-}
-
-/* Grouping content
- ========================================================================== */
-
-/**
- * Address margin not present in IE 8/9 and Safari.
- */
-
-figure {
- margin: 1em 40px;
-}
-
-/**
- * Address differences between Firefox and other browsers.
- */
-
-hr {
- -moz-box-sizing: content-box;
- box-sizing: content-box;
- height: 0;
-}
-
-/**
- * Contain overflow in all browsers.
- */
-
-pre {
- overflow: auto;
-}
-
-/**
- * Address odd `em`-unit font size rendering in all browsers.
- */
-
-code,
-kbd,
-pre,
-samp {
- font-family: monospace, monospace;
- font-size: 1em;
-}
-
-/* Forms
- ========================================================================== */
-
-/**
- * Known limitation: by default, Chrome and Safari on OS X allow very limited
- * styling of `select`, unless a `border` property is set.
- */
-
-/**
- * 1. Correct color not being inherited.
- * Known issue: affects color of disabled elements.
- * 2. Correct font properties not being inherited.
- * 3. Address margins set differently in Firefox 4+, Safari, and Chrome.
- */
-
-button,
-input,
-optgroup,
-select,
-textarea {
- color: inherit; /* 1 */
- font: inherit; /* 2 */
- margin: 0; /* 3 */
-}
-
-/**
- * Address `overflow` set to `hidden` in IE 8/9/10/11.
- */
-
-button {
- overflow: visible;
-}
-
-/**
- * Address inconsistent `text-transform` inheritance for `button` and `select`.
- * All other form control elements do not inherit `text-transform` values.
- * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera.
- * Correct `select` style inheritance in Firefox.
- */
-
-button,
-select {
- text-transform: none;
-}
-
-/**
- * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio`
- * and `video` controls.
- * 2. Correct inability to style clickable `input` types in iOS.
- * 3. Improve usability and consistency of cursor style between image-type
- * `input` and others.
- */
-
-button,
-html input[type="button"], /* 1 */
-input[type="reset"],
-input[type="submit"] {
- -webkit-appearance: button; /* 2 */
- cursor: pointer; /* 3 */
-}
-
-/**
- * Re-set default cursor for disabled elements.
- */
-
-button[disabled],
-html input[disabled] {
- cursor: default;
-}
-
-/**
- * Remove inner padding and border in Firefox 4+.
- */
-
-button::-moz-focus-inner,
-input::-moz-focus-inner {
- border: 0;
- padding: 0;
-}
-
-/**
- * Address Firefox 4+ setting `line-height` on `input` using `!important` in
- * the UA stylesheet.
- */
-
-input {
- line-height: normal;
-}
-
-/**
- * It's recommended that you don't attempt to style these elements.
- * Firefox's implementation doesn't respect box-sizing, padding, or width.
- *
- * 1. Address box sizing set to `content-box` in IE 8/9/10.
- * 2. Remove excess padding in IE 8/9/10.
- */
-
-input[type="checkbox"],
-input[type="radio"] {
- box-sizing: border-box; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Fix the cursor style for Chrome's increment/decrement buttons. For certain
- * `font-size` values of the `input`, it causes the cursor style of the
- * decrement button to change from `default` to `text`.
- */
-
-input[type="number"]::-webkit-inner-spin-button,
-input[type="number"]::-webkit-outer-spin-button {
- height: auto;
-}
-
-/**
- * 1. Address `appearance` set to `searchfield` in Safari and Chrome.
- * 2. Address `box-sizing` set to `border-box` in Safari and Chrome
- * (include `-moz` to future-proof).
- */
-
-input[type="search"] {
- -webkit-appearance: textfield; /* 1 */
- -moz-box-sizing: content-box;
- -webkit-box-sizing: content-box; /* 2 */
- box-sizing: content-box;
-}
-
-/**
- * Remove inner padding and search cancel button in Safari and Chrome on OS X.
- * Safari (but not Chrome) clips the cancel button when the search input has
- * padding (and `textfield` appearance).
- */
-
-input[type="search"]::-webkit-search-cancel-button,
-input[type="search"]::-webkit-search-decoration {
- -webkit-appearance: none;
-}
-
-/**
- * Define consistent border, margin, and padding.
- */
-
-fieldset {
- border: 1px solid #c0c0c0;
- margin: 0 2px;
- padding: 0.35em 0.625em 0.75em;
-}
-
-/**
- * 1. Correct `color` not being inherited in IE 8/9/10/11.
- * 2. Remove padding so people aren't caught out if they zero out fieldsets.
- */
-
-legend {
- border: 0; /* 1 */
- padding: 0; /* 2 */
-}
-
-/**
- * Remove default vertical scrollbar in IE 8/9/10/11.
- */
-
-textarea {
- overflow: auto;
-}
-
-/**
- * Don't inherit the `font-weight` (applied by a rule above).
- * NOTE: the default cannot safely be changed in Chrome and Safari on OS X.
- */
-
-optgroup {
- font-weight: bold;
-}
-
-/* Tables
- ========================================================================== */
-
-/**
- * Remove most spacing between table cells.
- */
-
-table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-
-td,
-th {
- padding: 0;
-}
diff --git a/nano/styles/shared.css b/nano/styles/shared.css
deleted file mode 100644
index 080ba46b550..00000000000
--- a/nano/styles/shared.css
+++ /dev/null
@@ -1,592 +0,0 @@
-body {
- padding: 0;
- margin: 0;
- font-size: 12px;
- color: #ffffff;
- line-height: 170%;
- font-family: Verdana, Geneva, sans-serif;
- background: #272727;
-}
-
-#uiNoScript {
- margin: 33% auto;
- width: 50%;
- height: 33%;
- background: #ffffff;
- border: 2px solid #ff0000;
- color: #000000;
- font-size: 10px;
- font-weight: bold;
- z-index: 9999;
- padding: 0px 10px;
- text-align: center;
-}
-
-#uiNoScript h1 {
- color: #000000;
-}
-
-hr {
- background-color: #40628a;
- height: 1px;
- border: none;
-}
-
-.link, .linkOn, .linkOff, .selected, .disabled, .yellowButton, .redButton {
- float: left;
- min-width: 15px;
- height: 16px;
- text-align: center;
- color: #ffffff;
- text-decoration: none;
- background: #40628a;
- border: 1px solid #161616;
- padding: 0px 4px 4px 4px;
- margin: 0 2px 2px 0;
- cursor: default;
- white-space: nowrap;
- display: inline-block;
-}
-
-.hasIcon {
- padding: 0px 4px 4px 0px;
-}
-
-a:hover, .zoomLink:hover, .linkActive:hover {
- background: #507aac;
-}
-
-.linkPending, .linkPending:hover {
- color: #ffffff;
- background: #507aac;
-}
-
-a.white, a.white:link, a.white:visited, a.white:active {
- color: #40628a;
- text-decoration: none;
- background: #ffffff;
- border: 1px solid #161616;
- padding: 1px 4px 1px 4px;
- margin: 0 2px 0 0;
- cursor: default;
-}
-
-a.white:hover {
- color: #ffffff;
- background: #40628a;
-}
-
-.hidden {
- display: none;
-}
-
-.linkOn, a.linkOn:link, a.linkOn:visited, a.linkOn:active, a.linkOn:hover, .selected, a.selected:link, a.selected:visited, a.selected:active, a.selected:hover {
- color: #ffffff;
- background: #2f943c;
-}
-
-.linkOff, a.linkOff:link, a.linkOff:visited, a.linkOff:active, a.linkOff:hover, .disabled, a.disabled:link, a.disabled:visited, a.disabled:active, a.disabled:hover {
- color: #ffffff;
- background: #999999;
- border-color: #666666;
-}
-
-a.icon, .linkOn.icon, .linkOff.icon, .selected.icon, .disabled.icon {
- position: relative;
- padding: 1px 4px 2px 20px;
-}
-
-a.icon img, .linkOn.icon img, .linkOff.icon img, .selected.icon img, .disabled.icon img {
- position: absolute;
- top: 0;
- left: 0;
- width: 18px;
- height: 18px;
-}
-
-.linkDanger, a.linkDanger:link, a.linkDanger:visited, a.linkDanger:active {
- color: #ffffff;
- background-color: #ff0000;
- border-color: #aa0000;
-}
-
-.linkDanger:hover {
- background-color: #ff6666;
-}
-
-ul {
- padding: 4px 0 0 10px;
- margin: 0;
- list-style-type: none;
-}
-
-li {
- padding: 0 0 2px 0;
-}
-
-img, a img {
- border-style: none;
-}
-
-h1, h2, h3, h4, h5, h6 {
- margin: 0;
- padding: 6px 0 6px 0;
- color: #FFFFFF;
- clear: both;
-}
-
-h1 {
- font-size: 18px;
-}
-
-h2 {
- font-size: 16px;
-}
-
-h3 {
- font-size: 14px;
-}
-
-h4 {
- font-size: 12px;
-}
-
-.white {
- color: white;
- font-weight: bold;
-}
-
-.good {
- color: #4f7529;
- font-weight: bold;
-}
-
-.average {
- color: #cd6500;
- font-weight: bold;
-}
-
-.bad {
- color: #ee0000;
- font-weight: bold;
-}
-
-.idle {
- color: #272727;
- font-weight: bold;
-}
-
-.redButton {
- background: #ea0000;
-}
-
-.yellowButton {
- background: #cacc00;
-}
-
-.highlight {
- color: #8BA5C4;
-}
-
-.dark {
- color: #272727;
-}
-
-.caption {
- font-size: 10px;
- font-weight: bold;
- padding: 5px;
-}
-
-.footer {
- font-size: 10px;
-}
-
-.noticePlaceholder {
- position: relative;
- font-size: 12px;
- font-style: italic;
- font-weight: bold;
- padding: 3px 4px 3px 4px;
- margin: 4px 0;
-}
-
-.notice {
- position: relative;
- background: url(uiNoticeBackground.jpg) 50% 50%;
- color: #000000;
- font-size: 12px;
- font-style: italic;
- font-weight: bold;
- padding: 3px 4px 3px 4px;
- margin: 4px 0;
-}
-
-.notice.icon {
- padding: 2px 4px 0 20px;
-}
-
-.notice img {
- position: absolute;
- top: 0;
- left: 0;
- width: 16px;
- height: 16px;
-}
-
-div.notice {
- clear: both;
-}
-
-.itemGroup {
- border: 1px solid #e9c183;
- background: #2c2c2c;
- padding: 4px;
- clear: both;
-}
-
-.item {
- display: inline-block;
- width: 100%;
- clear: both;
-}
-
-.itemContentNarrow, .itemContent {
- float: left;
-}
-
-.itemContentNarrow {
- width: 30%;
-}
-
-.itemContent {
- width: 69%;
-}
-
-.itemLabelNarrow, .itemLabel, .itemLabelWide, .itemLabelWider, .itemLabelWidest {
- float: left;
- color: #e9c183;
-}
-
-.itemLabelNarrow {
- width: 20%;
-}
-
-.itemLabel {
- width: 30%;
-}
-
-.itemLabelWide {
- width: 45%;
-}
-
-.itemLabelWider {
- width: 69%;
-}
-
-.itemLabelWidest {
- width: 100%;
-}
-
-.itemContentWide {
- float: left;
- width: 79%;
-}
-
-.itemContentSmall {
- float: left;
- width: 33%;
-}
-
-.itemContentMedium {
- float: left;
- width: 55%;
-}
-
-.statusDisplay {
- display: block;
- position: relative;
- background: #000000;
- color: #ffffff;
- border: 1px solid #40628a;
- padding: 4px;
- margin: 4px 0;
-}
-
-.statusDisplay .itemLabelNarrow, .statusDisplay .itemLabel, .statusDisplay .itemLabelWide, .statusDisplay .itemLabelWider, .statusDisplay .itemLabelWidest {
- color: #98B0C3;
-}
-
-.statusDisplayRecords {
- background: #000000;
- color: #ffffff;
- border: 1px solid #40628a;
- padding: 4px;
- margin: 3px 0;
- overflow-x: hidden;
- overflow-y: auto;
-}
-
-.block {
- padding: 8px;
- margin: 10px 4px 4px 4px;
- border: 1px solid #40628a;
- background-color: #202020;
-}
-
-.block h3 {
- padding: 0;
-}
-
-.displayBar {
- position: relative;
- width: 236px;
- height: 16px;
- border: 1px solid #666666;
- float: left;
- margin: 0 5px 0 0;
- overflow: hidden;
- background: #000000;
-}
-
-.displayBarText {
- position: absolute;
- top: -2px;
- left: 5px;
- width: 100%;
- height: 100%;
- color: #ffffff;
- font-weight: normal;
-}
-
-.displayBarFill {
- width: 0%;
- height: 100%;
- background: #40628a;
- overflow: hidden;
- float: left;
-}
-
-.displayBarFill.alignRight {
- float: right;
-}
-
-.displayBarFill.good {
- color: #ffffff;
- background: #4f7529;
-}
-
-.displayBarFill.average {
- color: #ffffff;
- background: #cd6500;
-}
-
-.displayBarFill.bad {
- color: #ffffff;
- background: #ee0000;
-}
-
-.displayBarFill.highlight {
- color: #ffffff;
- background: #8BA5C4;
-}
-
-.clearBoth {
- clear: both;
-}
-
-.clearLeft {
- clear: left;
-}
-
-.clearRight {
- clear: right;
-}
-
-.line {
- width: 100%;
- clear: both;
-}
-
-.inactive, a.inactive:link, a.inactive:visited, a.inactive:active, a.inactive:hover {
- color: #ffffff;
- background: #999999;
- border-color: #666666;
-}
-
-.fixedLeft {
- width: 110px;
- float: left;
-}
-
-.fixedLeftWide {
- width: 165px;
- float: left;
-}
-
-.fixedLeftWider {
- width: 220px;
- float: left;
-}
-
-.fixedLeftWidest {
- width: 250px;
- float: left;
-}
-
-.fixedLeftWiderRed {
- width: 220px;
- float: left;
- background: #ee0000;
-}
-
-.floatRight {
- float: right;
-}
-
-.alignTop {
- vertical-align: top;
-}
-
-/* Used in PDA */
-.wholeScreen {
- position: absolute;
- color: #517087;
- font-size: 16px;
- font-weight: bold;
- text-align: center;
-}
-
-.pdalink {
- float: left;
- white-space: nowrap;
-}
-
-/* DNA Modifier UI (dna_modifier.tmpl) */
-
-.dnaBlock {
- float: left;
- width: 90px;
- padding: 0 0 5px 0;
-}
-
-.dnaBlockNumber {
- font-family: Fixed, monospace;
- float: left;
- color: #ffffff;
- background: #363636;
- min-width: 20px;
- height: 20px;
- padding: 0;
- text-align: center;
-}
-
-.dnaSubBlock {
- font-family: Fixed, monospace;
- float: left;
- padding: 0;
- min-width: 16px;
- height: 20px;
- text-align: center;
-}
-
-.mask {
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- background: url(uiMaskBackground.png);
-}
-
-.maskContent {
- width: 100%;
- height: 200px;
- margin: 200px 0;
- text-align: center;
-}
-
-table.fixed {
- table-layout:fixed;
-}
-
-table.fixed td {
- overflow: hidden;
-}
-
-/* Table stuffs for power monitor */
-table.pmon {
- border: 2px solid RoyalBlue;
-}
-
-table.pmon td, table.pmon th {
- border-bottom: 1px dotted black;
- padding: 0px 5px 0px 5px;
-}
-
-/* Table Stuffs for manifest*/
-
-th.command {
- background: #3333FF;
- font-weight: bold;
- color: #ffffff;
-}
-
-th.sec {
- background: #8e0000;
- font-weight: bold;
- color: #ffffff;
-}
-
-th.med {
- background: #006600;
- font-weight: bold;
- color: #ffffff;
-}
-
-th.eng {
- background: #b27300;
- font-weight: bold;
- color: #ffffff;
-}
-
-th.sci {
- background: #a65ba6;
- font-weight: bold;
- color: #ffffff;
-}
-
-th.civ {
- background: #a32800;
- font-weight: bold;
- color: #ffffff;
-}
-
-th.misc {
- background: #666666;
- font-weight: bold;
- color: #ffffff;
-}
-
-/* Damage colors for crew monitoring computer */
-
-.burn {
- color: orange;
-}
-
-.brute {
- color: red;
-}
-
-.toxin {
- color: green;
-}
-
-.oxyloss {
- color: blue;
-}
-
-/* 75px width used in power monitoring console buttons */
-.width75btn {
- width: 75px;
-}
\ No newline at end of file
diff --git a/nano/templates/_generic.dot b/nano/templates/_generic.dot
new file mode 100644
index 00000000000..d8a52576f66
--- /dev/null
+++ b/nano/templates/_generic.dot
@@ -0,0 +1,14 @@
+
+
+
+ {{=config.title}}
+
+
+
+
+
+
+
+
diff --git a/nano/templates/_nanotrasen.dot b/nano/templates/_nanotrasen.dot
new file mode 100644
index 00000000000..d8a52576f66
--- /dev/null
+++ b/nano/templates/_nanotrasen.dot
@@ -0,0 +1,14 @@
+
+
+
+ {{=config.title}}
+
+
+
+
+
+
+
+
diff --git a/nano/templates/air_alarm.dot b/nano/templates/air_alarm.dot
new file mode 100644
index 00000000000..69f9a9cdf6f
--- /dev/null
+++ b/nano/templates/air_alarm.dot
@@ -0,0 +1,233 @@
+
+ {{? data.siliconUser}}
+
+ Interface Lock:
+
+ {{=helper.link('Engaged', 'lock', 'toggleaccess', null, data.locked ? 'selected' : null)}}
+ {{=helper.link('Disengaged', 'unlock', 'toggleaccess', null, data.locked ? null : 'selected')}}
+
+
+ {{??}}
+ {{? data.locked}}
+ Swipe an ID card to unlock this interface.
+ {{??}}
+ Swipe an ID card to lock this interface.
+ {{?}}
+ {{?}}
+
+
+
+ {{? data.environment_data}}
+ {{~ data.environment_data:info:i}}
+
+ {{=info.name}}:
+
+ {{? info.danger_level == 2}}
+
+ {{?? info.danger_level == 1}}
+
+ {{??}}
+
+ {{?}}
+ {{=helper.fixed(info.value, 2)}}{{=info.unit}}
+
+
+ {{~}}
+
+ Local Status:
+
+ {{? data.danger_level == 2}}
+ Danger (Internals Required)
+ {{?? data.danger_level == 1}}
+ Caution
+ {{??}}
+ Optimal
+ {{?}}
+
+
+
+ Area Status:
+
+ {{? data.atmos_alarm}}
+ Atmosphere Alarm
+ {{?? data.fire_alarm}}
+ Fire Alarm
+ {{??}}
+ Nominal
+ {{?}}
+
+
+ {{??}}
+
+ Warning: Cannot obtain air sample for analysis.
+
+ {{?}}
+ {{? data.dangerous}}
+
+
+ Warning: Safety measures offline. Device may exhibit abnormal behavior.
+
+ {{?}}
+
+{{? (!data.locked || data.siliconUser)}}
+ {{? data.screen != 1}}
+ {{=helper.link('Back', 'arrow-left', 'screen', {'screen': 1})}}
+ {{?}}
+ {{? data.screen == 1}}
+
+
+
+
+
+
+
+
+
+ {{?? data.screen == 2}}
+ {{~ data.vents:vent:i}}
+
+
+
+ Power:
+
+ {{? vent.power}}
+ {{=helper.link('On', 'power-off', 'adjust', {'id_tag': vent.id_tag, 'command': 'power', 'val': 0}, null, null)}}
+ {{??}}
+ {{=helper.link('Off', 'close', 'adjust', {'id_tag': vent.id_tag, 'command': 'power', 'val': 1}, null, 'danger')}}
+ {{?}}
+
+
+
+ Mode:
+
+ {{? vent.direction == "release"}}
+ Pressurizing
+ {{??}}
+ Siphoning
+ {{?}}
+
+
+
+ Pressure Checks:
+
+ {{=helper.link('Internal', 'sign-in', 'adjust', {'id_tag': vent.id_tag, 'command': 'incheck', 'val': vent.checks}, null, vent.incheck ? 'selected' : null)}}
+ {{=helper.link('External', 'sign-out', 'adjust', {'id_tag': vent.id_tag, 'command': 'excheck', 'val': vent.checks}, null, vent.excheck ? 'selected' : null)}}
+
+
+
+ Set Pressure:
+
+ {{=helper.link(helper.fixed(vent.external), 'pencil', 'adjust', {'id_tag': vent.id_tag, 'command': 'set_external_pressure'})}}
+ {{=helper.link('Reset', 'refresh', 'adjust', {'id_tag': vent.id_tag, 'command': 'reset_external_pressure'}, vent.extdefault ? 'disabled' : null)}}
+
+
+
+ {{~}}
+ {{? !data.vents.length}}
+
No vents connected.
+ {{?}}
+ {{?? data.screen == 3}}
+ {{~ data.scrubbers:scrubber:i}}
+
+
+
+ Power:
+
+ {{? scrubber.power}}
+ {{=helper.link('On', 'power-off', 'adjust', {'id_tag': scrubber.id_tag, 'command': 'power', 'val': 0}, null, null)}}
+ {{??}}
+ {{=helper.link('Off', 'close', 'adjust', {'id_tag': scrubber.id_tag, 'command': 'power', 'val': 1}, null, 'danger')}}
+ {{?}}
+
+
+
+ Mode:
+
+ {{? scrubber.scrubbing}}
+ {{=helper.link('Scrubbing', 'filter', 'adjust', {'id_tag': scrubber.id_tag, 'command': 'scrubbing', 'val': 0}, null, null)}}
+ {{??}}
+ {{=helper.link('Siphoning', 'sign-in', 'adjust', {'id_tag': scrubber.id_tag, 'command': 'scrubbing', 'val': 1}, null, 'danger')}}
+ {{?}}
+
+
+
+ Range:
+
+ {{? scrubber.widenet}}
+ {{=helper.link('Extended', 'expand', 'adjust', {'id_tag': scrubber.id_tag, 'command': 'widenet', 'val': 0}, null, 'caution')}}
+ {{??}}
+ {{=helper.link('Normal', 'compress', 'adjust', {'id_tag': scrubber.id_tag, 'command': 'widenet', 'val': 1}, null, null)}}
+ {{?}}
+
+
+
+ Filters:
+
+ {{=helper.link("CO2", scrubber.filter_co2 ? 'check-square-o' : 'square-o', 'adjust', {'id_tag': scrubber.id_tag, 'command': "co2_scrub", 'val': scrubber.filter_co2 ? 0 : 1}, null, scrubber.filter_co2 ? 'selected' : null)}}
+ {{=helper.link("N2O", scrubber.filter_n2o ? 'check-square-o' : 'square-o', 'adjust', {'id_tag': scrubber.id_tag, 'command': "n2o_scrub", 'val': scrubber.filter_n2o ? 0 : 1}, null, scrubber.filter_n2o ? 'selected' : null)}}
+ {{=helper.link("Plasma", scrubber.filter_toxins ? 'check-square-o' : 'square-o', 'adjust', {'id_tag': scrubber.id_tag, 'command': "tox_scrub", 'val': scrubber.filter_toxins ? 0 : 1}, null, scrubber.filter_toxins ? 'selected' : null)}}
+
+
+
+ {{~}}
+ {{? !data.scrubbers.length}}
+
No scrubbers connected.
+ {{?}}
+ {{?? data.screen == 4}}
+
+
+ {{~ data.modes:mode:i}}
+
+ {{~}}
+
+ {{?? data.screen == 5}}
+
+
+
+
+
+ |
+ min2 |
+ min1 |
+ max1 |
+ max2 |
+
+
+
+ {{~ data.thresholds:threshold:i}}
+
+ | {{=threshold.name}} |
+ {{~ threshold.settings:setting:j}}
+
+ {{=helper.link(setting.selected >= 0 ? helper.round(setting.selected*100)/100 : "Off", null, 'adjust', {'command': 'set_threshold', 'env': setting.env, 'var': setting.val})}}
+ |
+ {{~}}
+
+ {{~}}
+
+
+
+ {{?}}
+{{?}}
diff --git a/nano/templates/airlock_electronics.dot b/nano/templates/airlock_electronics.dot
new file mode 100644
index 00000000000..5edfb225e5b
--- /dev/null
+++ b/nano/templates/airlock_electronics.dot
@@ -0,0 +1,33 @@
+
+
+ {{? data.oneAccess}}
+ {{=helper.link('One Required', 'unlock', 'one_access')}}
+ {{??}}
+ {{=helper.link('All Required', 'lock', 'one_access')}}
+ {{?}}
+ {{=helper.link('Clear', 'refresh', 'clear')}}
+
+
+
+
+ {{~ data.regions :region:i}}
+ |
+ {{=region.name}}
+ |
+ {{~}}
+
+
+
+
+ {{~ data.regions :region:i}}
+
+ {{~ region.accesses :access:j}}
+ {{=helper.link(access.name, access.req ? 'check-square-o' : 'square-o', 'set', {'access': access.id}, null, access.req ? 'selected' : null)}}
+
+ {{~}}
+ |
+ {{~}}
+
+
+
+
diff --git a/nano/templates/apc.dot b/nano/templates/apc.dot
new file mode 100644
index 00000000000..d767e18ff60
--- /dev/null
+++ b/nano/templates/apc.dot
@@ -0,0 +1,157 @@
+
+ {{? data.siliconUser}}
+
+ Interface Lock:
+
+ {{=helper.link('Engaged', 'lock', 'toggleaccess', null, data.locked ? 'selected' : null)}}
+ {{=helper.link('Disengaged', 'unlock', 'toggleaccess', null, data.malfStatus >= 2 ? 'linkOff' : (data.locked ? null : 'selected'))}}
+
+
+ {{??}}
+ {{? data.locked}}
+ Swipe an ID card to unlock this interface.
+ {{??}}
+ Swipe an ID card to lock this interface.
+ {{?}}
+ {{?}}
+
+
+
+
+ Main Breaker:
+
+ {{? data.locked && !data.siliconUser}}
+ {{? data.isOperating}}
+ On
+ {{??}}
+ Off
+ {{?}}
+ {{??}}
+ {{=helper.link('On', 'power-off', 'breaker', null, data.isOperating ? 'selected' : null)}}
+ {{=helper.link('Off', 'close', 'breaker', null, data.isOperating ? null : 'selected')}}
+ {{?}}
+
+
+
+ External Power:
+
+ {{? data.externalPower == 2}}
+ Good
+ {{?? data.externalPower == 1}}
+ Low
+ {{??}}
+ None
+ {{?}}
+
+
+
+ Power Cell:
+
+ {{? data.powerCellStatus != null}}
+ {{=helper.bar(data.powerCellStatus, 0, 100, data.powerCellStatus >= 50 ? "good" : data.powerCellStatus >= 25 ? "average" : "bad", helper.fixed(data.powerCellStatus) + "%")}}
+ {{??}}
+ Power cell removed.
+ {{?}}
+
+
+ {{? data.powerCellStatus != null}}
+
+ Charge Mode:
+
+ {{? data.locked && !data.siliconUser}}
+ {{? data.chargeMode}}
+ Auto
+ {{??}}
+ Off
+ {{?}}
+ {{??}}
+ {{=helper.link('Auto', 'refresh', 'chargemode', null, data.chargeMode ? 'selected' : null)}}
+ {{=helper.link('Off', 'close', 'chargemode', null, data.chargeMode ? null : 'selected')}}
+ {{?}}
+
+ {{? data.chargingStatus > 1}}
+ [Fully Charged]
+ {{?? data.chargingStatus == 1}}
+ [Charging]
+ {{??}}
+ [Not Charging]
+ {{?}}
+
+
+ {{?}}
+
+
+
+
+ {{~ data.powerChannels :channel:i}}
+
+ | {{=channel.title}}: |
+ {{=channel.powerLoad}} W |
+
+ {{? channel.status <= 1}}
+ Off
+ {{?? channel.status >= 2}}
+ On
+ {{?}}
+ |
+
+ {{? channel.status == 1 || channel.status == 3}}
+ [Auto]
+ {{??}}
+ [Manual]
+ {{?}}
+ |
+
+ {{? !data.locked || data.siliconUser}}
+ {{=helper.link('Auto', 'refresh', 'channel', channel.topicParams.auto, (channel.status == 1 || channel.status == 3) ? 'selected' : null)}}
+ {{=helper.link('On', 'power-off', 'channel', channel.topicParams.on, (channel.status == 2) ? 'selected' : null)}}
+ {{=helper.link('Off', 'close', 'channel', channel.topicParams.off, (channel.status == 0) ? 'selected' : null)}}
+ {{?}}
+ |
+
+ {{~}}
+
+ | Total Load: |
+ {{=data.totalLoad}} W |
+ |
+ |
+ |
+
+
+
+{{? data.siliconUser}}
+
+
+
+ {{=helper.link('Overload Lighting Circuit', 'lightbulb-o', 'overload')}}
+
+
+ {{? data.malfStatus == 1}}
+ {{=helper.link('Override Programming', 'terminal', 'hack')}}
+ {{?? data.malfStatus == 2}}
+ {{=helper.link('Shunt Core Processes', 'caret-square-o-down', 'occupy')}}
+ {{?? data.malfStatus == 3}}
+ {{=helper.link('Return to Main Core', 'carat-square-o-left', 'deoccupy')}}
+ {{?? data.malfStatus == 4}}
+ {{=helper.link('Shunt Core Processes', 'caret-square-o-down')}}
+ {{?}}
+
+
+{{?}}
+
+
+ Cover Lock:
+
+ {{? data.locked && !data.siliconUser}}
+ {{? data.coverLocked}}
+ Engaged
+ {{??}}
+ Disengaged
+ {{?}}
+ {{??}}
+ {{=helper.link('Engaged', 'lock', 'lock', null, data.coverLocked ? 'selected' : null)}}
+ {{=helper.link('Disengaged', 'unlock', 'lock', null, data.coverLocked ? null : 'selected')}}
+ {{?}}
+
+
+
diff --git a/nano/templates/atmos_filter.dot b/nano/templates/atmos_filter.dot
new file mode 100644
index 00000000000..80fc3855b75
--- /dev/null
+++ b/nano/templates/atmos_filter.dot
@@ -0,0 +1,27 @@
+
+
+ Power:
+
+ {{=helper.link(data.on? 'On' : 'Off', data.on ? 'power-off' : 'close', 'power')}}
+
+
+
+ Output Pressure:
+
+ {{=helper.link('Set', 'pencil', 'pressure', {'set': 'custom'})}}
+ {{=helper.link('Max', 'plus', 'pressure', {'set': 'max'}, data.set_pressure == data.max_pressure ? 'disabled' : null)}}
+ {{=data.set_pressure}} kPa
+
+
+
+ Filter:
+
+ {{=helper.link('Nothing', null, 'filter', {'mode': -1}, data.filter_type == -1 ? 'selected' : null)}}
+ {{=helper.link('Plasma', null, 'filter', {'mode': 0}, data.filter_type == 0 ? 'selected' : null)}}
+ {{=helper.link('O2', null, 'filter', {'mode': 1}, data.filter_type == 1 ? 'selected' : null)}}
+ {{=helper.link('N2', null, 'filter', {'mode': 2}, data.filter_type == 2 ? 'selected' : null)}}
+ {{=helper.link('CO2', null, 'filter', {'mode': 3}, data.filter_type == 3 ? 'selected' : null)}}
+ {{=helper.link('N2O', null, 'filter', {'mode': 4}, data.filter_type == 4 ? 'selected' : null)}}
+
+
+
diff --git a/nano/templates/atmos_mixer.dot b/nano/templates/atmos_mixer.dot
new file mode 100644
index 00000000000..684d3f9e3f7
--- /dev/null
+++ b/nano/templates/atmos_mixer.dot
@@ -0,0 +1,36 @@
+
+
+ Power:
+
+ {{=helper.link(data.on? 'On' : 'Off', data.on? 'power-off' : 'close', 'power')}}
+
+
+
+ Output Pressure:
+
+ {{=helper.link('Set', 'pencil', 'pressure', {'set': 'custom'})}}
+ {{=helper.link('Max', 'plus', 'pressure', {'set': 'max'}, data.set_pressure == data.max_pressure ? 'disabled' : null)}}
+ {{=data.set_pressure}} kPa
+
+
+
+ Node 1:
+
+ {{=helper.link('', 'fast-backward', 'node1', {'concentration' : '-0.1'}, null)}}
+ {{=helper.link('', 'backward', 'node1', {'concentration' : '-0.01'}, null)}}
+ {{=helper.link('', 'forward', 'node1', {'concentration' : '0.01'}, null)}}
+ {{=helper.link('', 'fast-forward', 'node1', {'concentration' : '0.1'}, null)}}
+ {{=data.node1_concentration}}%
+
+
+
+ Node 2:
+
+ {{=helper.link('', 'fast-backward', 'node2', {'concentration' : '-0.1'}, null)}}
+ {{=helper.link('', 'backward', 'node2', {'concentration' : '-0.01'}, null)}}
+ {{=helper.link('', 'forward', 'node2', {'concentration' : '0.01'}, null)}}
+ {{=helper.link('', 'fast-forward', 'node2', {'concentration' : '0.1'}, null)}}
+ {{=data.node2_concentration}}%
+
+
+
diff --git a/nano/templates/atmos_pump.dot b/nano/templates/atmos_pump.dot
new file mode 100644
index 00000000000..70f1c48aa49
--- /dev/null
+++ b/nano/templates/atmos_pump.dot
@@ -0,0 +1,27 @@
+
+
+ Power:
+
+ {{=helper.link(data.on? 'On' : 'Off', data.on? 'power-off' : 'close', 'power')}}
+
+
+ {{? data.max_rate}}
+
+ Transfer Rate:
+
+ {{=helper.link('Set', 'pencil', 'transfer', {'set': 'custom'})}}
+ {{=helper.link('Max', 'plus', 'transfer', {'set' : 'max'}, data.transfer_rate == data.max_rate ? 'disabled' : null)}}
+ {{=data.transfer_rate}} L/s
+
+
+ {{??}}
+
+ Output Pressure:
+
+ {{=helper.link('Set', 'pencil', 'pressure', {'set': 'custom'})}}
+ {{=helper.link('Max', 'plus', 'pressure', {'set' : 'max'}, data.set_pressure == data.max_pressure ? 'disabled' : null)}}
+ {{=data.set_pressure}} kPa
+
+
+ {{?}}
+
diff --git a/nano/templates/canister.dot b/nano/templates/canister.dot
new file mode 100644
index 00000000000..20cad52be96
--- /dev/null
+++ b/nano/templates/canister.dot
@@ -0,0 +1,80 @@
+
+ {{? data.hasHoldingTank }}
+ The regulator is connected to a tank.
+ {{??}}
+ The regulator is not connected to a tank.
+ {{?}}
+
+
+
+
+ {{=helper.link('Relabel', 'pencil', 'relabel', null, data.canLabel ? null : 'disabled')}}
+
+
+ Pressure:
+
+ {{=data.tankPressure}} kPa
+
+
+
+
+ Port:
+
+
+ {{? data.portConnected}}
+ Connected
+ {{??}}
+ Disconnected
+ {{?}}
+
+
+
+
+
+
+ Release Pressure:
+
+ {{=helper.bar(data.releasePressure, data.minReleasePressure, data.maxReleasePressure, null, data.releasePressure + ' kPa')}}
+
+
+
+ Pressure Regulator:
+
+ {{=helper.link('Reset', 'refresh', 'pressure', {'set': 'reset'}, (data.releasePressure != data.defaultReleasePressure) ? null : 'disabled')}}
+ {{=helper.link('Min', 'minus', 'pressure', {'set': 'min'}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
+ {{=helper.link('Set', 'pencil', 'pressure', {'set': 'custom'}, null)}}
+ {{=helper.link('Max', 'plus', 'pressure', {'set': 'max'}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
+
+
+
+ Valve:
+
+ {{=helper.link('Open', 'unlock', 'valve', null, data.valveOpen ? 'selected' : null)}}
+ {{=helper.link('Close', 'lock', 'valve', null, data.valveOpen ? null : 'selected')}}
+
+
+
+
+
+ {{? data.hasHoldingTank}}
+
+ {{=helper.link('Eject', 'eject', 'eject')}}
+
+
+ Label:
+
+ {{=data.holdingTank.name}}
+
+
+
+ Tank Pressure:
+
+ {{=data.holdingTank.tankPressure}} kPa
+
+
+ {{??}}
+
+ {{?}}
+
diff --git a/nano/templates/chem_dispenser.dot b/nano/templates/chem_dispenser.dot
new file mode 100644
index 00000000000..d3e48e5204a
--- /dev/null
+++ b/nano/templates/chem_dispenser.dot
@@ -0,0 +1,55 @@
+
+
+
+ Energy:
+
+ {{=helper.bar(data.energy, 0, data.maxEnergy, null, data.energy + ' Units')}}
+
+
+
+ Amount:
+
+ {{~ data.beakerTransferAmounts :amount:i}}
+ {{=helper.link(amount, 'plus', 'amount', {'set': amount}, (data.amount == amount) ? 'selected' : null)}}
+ {{~}}
+
+
+
+
+
+
+ {{~ data.chemicals :chem:i}}
+ {{=helper.link(chem.title, 'tint', 'dispense', chem.commands, null, 'gridable')}}
+ {{~}}
+
+
+
+
+
+
+ {{=helper.link('Eject', 'eject', 'eject', null, data.isBeakerLoaded ? null : 'disabled')}}
+
+
+ {{~ data.beakerTransferAmounts :amount:i}}
+ {{=helper.link(amount, 'minus', 'remove', {'amount': amount})}}
+ {{~}}
+
+
+
+ Contents:
+
+ {{? data.isBeakerLoaded}}
+ {{? data.beakerContents.length}}
+ {{=data.beakerCurrentVolume}}/{{=data.beakerMaxVolume}} Units
+ {{~ data.beakerContents :reagent:i}}
+ {{=reagent.volume}} units of {{=reagent.name}}
+ {{~}}
+ {{??}}
+ Beaker Empty
+ {{?}}
+ {{??}}
+ No Beaker Loaded
+ {{?}}
+
+
+
diff --git a/nano/templates/chem_heater.dot b/nano/templates/chem_heater.dot
new file mode 100644
index 00000000000..b1bf72b3472
--- /dev/null
+++ b/nano/templates/chem_heater.dot
@@ -0,0 +1,38 @@
+
+
+
+ Power:
+
+ {{=helper.link(data.isActive ? 'On' : 'Off', data.isActive ? 'power-off' : 'close', 'power', null, data.isBeakerLoaded ? null : 'disabled')}}
+
+
+
+ Target:
+
+ {{=helper.link(data.targetTemp + 'K', 'pencil', 'temperature')}}
+
+
+
+
+
+
+ {{=helper.link('Eject', 'eject', 'eject', null, data.isBeakerLoaded ? null : 'disabled')}}
+
+
+ Contents:
+
+ {{? data.isBeakerLoaded}}
+ Temperature: {{=data.currentTemp}}K
+ {{? data.beakerContents.length}}
+ {{~ data.beakerContents :reagent:i}}
+ {{=reagent.volume}} units of {{=reagent.name}}
+ {{~}}
+ {{??}}
+ Beaker Empty
+ {{?}}
+ {{??}}
+ No Beaker Loaded
+ {{?}}
+
+
+
diff --git a/nano/templates/cryo.dot b/nano/templates/cryo.dot
new file mode 100644
index 00000000000..dd182abce5c
--- /dev/null
+++ b/nano/templates/cryo.dot
@@ -0,0 +1,121 @@
+
+
+
+ Occupant:
+
+ {{? data.hasOccupant}}
+ {{=data.occupant.name}}
+ {{??}}
+ No Occupant
+ {{?}}
+
+
+ {{? data.hasOccupant}}
+
+ State:
+
+ {{? data.occupant.stat == 0}}
+ Conscious
+ {{?? data.occupant.stat == 1}}
+ Unconscious
+ {{??}}
+ Dead
+ {{?}}
+
+
+
+ Temperature:
+
+ {{=helper.round(data.occupant.bodyTemperature)}} K
+
+
+ {{?}}
+ {{? data.hasOccupant && data.occupant.stat < 2}}
+
+ Health:
+
+ {{=helper.bar(data.occupant.health, data.occupant.minHealth, data.occupant.Maxhealth, data.occupant.health >= 0 ? 'good' : 'average', helper.round(data.occupant.health))}}
+
+
+
+ Brute:
+
+ {{=helper.bar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad', helper.round(data.occupant.bruteLoss))}}
+
+
+
+ Respiratory:
+
+ {{=helper.bar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad', helper.round(data.occupant.oxyLoss))}}
+
+
+
+ Toxin:
+
+ {{=helper.bar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad', helper.round(data.occupant.toxLoss))}}
+
+
+
+ Burn:
+
+ {{=helper.bar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad', helper.round(data.occupant.fireLoss))}}
+
+
+ {{?}}
+
+
+
+
+ Power:
+
+ {{? data.isOperating}}
+ {{=helper.link('On', 'power-off', 'off')}}
+ {{??}}
+ {{=helper.link('Off', 'close', 'on')}}
+ {{?}}
+
+
+
+ Temperature:
+
+ {{=data.cellTemperature}} K
+
+
+
+ Door:
+
+ {{? data.isOpen}}
+ {{=helper.link('Open', 'unlock', 'close')}}
+ {{??}}
+ {{=helper.link('Closed', 'lock', 'open')}}
+ {{?}}
+ {{? data.autoEject}}
+ {{=helper.link('Auto', 'sign-out', 'autoeject')}}
+ {{??}}
+ {{=helper.link('Manual', 'sign-in', 'autoeject')}}
+ {{?}}
+
+
+
+
+
+
+ {{=helper.link('Eject', 'eject', 'ejectbeaker', null, data.isBeakerLoaded ? null : 'disabled')}}
+
+
+ Contents:
+
+ {{? data.isBeakerLoaded}}
+ {{? data.beakerContents.length}}
+ {{~ data.beakerContents :reagent:i}}
+ {{=reagent.volume}} units of {{=reagent.name}}
+ {{~}}
+ {{??}}
+ Beaker Empty
+ {{?}}
+ {{??}}
+ No Beaker Loaded
+ {{?}}
+
+
+
diff --git a/nano/templates/smes.dot b/nano/templates/smes.dot
new file mode 100644
index 00000000000..442ceb87e93
--- /dev/null
+++ b/nano/templates/smes.dot
@@ -0,0 +1,89 @@
+
+
+
+ Stored Energy:
+
+ {{=helper.bar(data.capacityPercent, 0, 100, data.capacityPercent >= 50 ? 'good' : data.capacityPercent >= 15 ? 'average' : 'bad', helper.round(data.capacityPercent) + '%')}}
+
+
+
+
+
+
+ Charge Mode:
+
+ {{=helper.link('Auto', 'refresh', 'tryinput', null, data.inputAttempt ? 'selected' : null)}}
+ {{=helper.link('Off', 'close', 'tryinput', null, data.inputAttempt ? null : 'selected')}}
+
+ {{? data.capacityPercent >= 99}}
+ [Fully Charged]
+ {{?? data.inputting}}
+ [Charging]
+ {{??}}
+ [Not Charging]
+ {{?}}
+
+
+
+ Input Setting:
+
+ {{=helper.bar(data.inputLevel, 0, data.inputLevelMax, null, data.inputLevel + ' W')}}
+
+
+
+ Adjust Input:
+
+ {{=helper.link('', 'fast-backward', 'input', {'set': 'min'}, data.inputLevel ? null : 'selected')}}
+ {{=helper.link('', 'backward', 'input', {'set': 'minus'}, data.inputLevel ? null : 'disabled')}}
+ {{=helper.link('Set', 'pencil', 'input', {'set': 'custom'}, null)}}
+ {{=helper.link('', 'forward', 'input', {'set': 'plus'}, data.inputLevel == data.inputLevelMax ? 'disabled' : null)}}
+ {{=helper.link('', 'fast-forward', 'input', {'set': 'max'}, data.inputLevel == data.inputLevelMax ? 'selected' : null)}}
+
+
+
+ Available:
+
+ {{=data.inputAvailable}} W
+
+
+
+
+
+
+ Charge Mode:
+
+ {{=helper.link('On', 'power-off', 'tryoutput', null, data.outputAttempt ? 'selected' : null)}}
+ {{=helper.link('Off', 'close', 'tryoutput', null, data.outputAttempt ? null : 'selected')}}
+
+ {{? data.outputting}}
+ [Sending]
+ {{?? data.charge > 0}}
+ [Not Sending]
+ {{??}}
+ [No Charge]
+ {{?}}
+
+
+
+ Output Setting:
+
+ {{=helper.bar(data.outputLevel, 0, data.outputLevelMax, null, data.outputLevel + ' W')}}
+
+
+
+ Adjust Output:
+
+ {{=helper.link('', 'fast-backward', 'output', {'set': 'min'}, data.outputLevel ? null : 'selected')}}
+ {{=helper.link('', 'backward', 'output', {'set': 'minus'}, data.outputLevel ? null : 'disabled')}}
+ {{=helper.link('Set', 'pencil', 'output', {'set': 'custom'}, null)}}
+ {{=helper.link('', 'forward', 'output', {'set': 'plus'}, data.outputLevel == data.outputLevelMax ? 'disabled' : null)}}
+ {{=helper.link('', 'fast-forward', 'output', {'set': 'max'}, data.outputLevel == data.outputLevelMax ? 'selected' : null)}}
+
+
+
+ Outputting:
+
+ {{=data.outputUsed}} W
+
+
+
diff --git a/nano/templates/solar_control.dot b/nano/templates/solar_control.dot
new file mode 100644
index 00000000000..1b19e87b1f1
--- /dev/null
+++ b/nano/templates/solar_control.dot
@@ -0,0 +1,85 @@
+
+
+
+ Generated Power:
+
+ {{=data.generated}} W
+
+
+
+ Orientation:
+
+ {{=data.angle}}° ({{=data.direction}})
+
+
+
+ Adjust:
+
+ {{=helper.link('15°', 'step-backward', 'control', {'cdir': '-15'})}}
+ {{=helper.link('1°', 'backward', 'control', {'cdir': '-1'})}}
+ {{=helper.link('1°', 'forward', 'control', {'cdir': '1'})}}
+ {{=helper.link('15°', 'step-forward', 'control', {'cdir': '15'})}}
+
+
+
+
+
+
+ Tracker Mode:
+
+ {{=helper.link('Off', 'close', 'tracking', {'mode': '0'}, (data.tracking_state == 0) ? 'selected' : '')}}
+ {{=helper.link('Timed', 'clock-o', 'tracking', {'mode': '1'}, (data.tracking_state == 1) ? 'selected' : '')}}
+ {{? data.connected_tracker}}
+ {{=helper.link('Auto', 'refresh', 'tracking', {'mode': '2'}, (data.tracking_state == 2) ? 'selected' : '')}}
+ {{??}}
+ {{=helper.link('Auto', 'refresh', null, null, 'disabled')}}
+ {{?}}
+
+
+
+ Tracking Rate:
+
+ {{=data.tracking_rate}} deg/h ({{=data.rotating_way}})
+
+
+
+ Adjust:
+
+ {{=helper.link('180°', 'fast-backward', 'control', {'tdir': '-180'})}}
+ {{=helper.link('30°', 'step-backward', 'control', {'tdir': '-30'})}}
+ {{=helper.link('1°', 'backward', 'control', {'tdir': '-1'})}}
+ {{=helper.link('1°', 'forward', 'control', {'tdir': '1'})}}
+ {{=helper.link('30°', 'step-forward', 'control', {'tdir': '30'})}}
+ {{=helper.link('180°', 'fast-forward', 'control', {'tdir': '180'})}}
+
+
+
+
+
+
+ Search:
+
+ {{=helper.link('Refresh', 'refresh', 'refresh')}}
+
+
+
+
+ Solar Tracker:
+
+
+ {{? data.connected_tracker}}
+ Found
+ {{??}}
+ Not Found
+ {{?}}
+
+
+
+
+ Solars Panels:
+
+
+ {{=data.connected_panels}} Connected
+
+
+
diff --git a/nano/templates/space_heater.dot b/nano/templates/space_heater.dot
new file mode 100644
index 00000000000..46622e843d4
--- /dev/null
+++ b/nano/templates/space_heater.dot
@@ -0,0 +1,79 @@
+
+
+
+ Power:
+
+ {{=helper.link('On', 'power-off', 'power', null, data.on ? 'selected' : null)}}
+ {{=helper.link('Off', 'close', 'power', null, data.on ? null : 'selected')}}
+
+
+
+ Stored Energy:
+
+ {{? data.hasPowercell}}
+ {{=helper.bar(data.powerLevel, 0, 100, 'good', data.powerLevel + '%')}}
+ {{??}}
+ No power cell loaded.
+ {{?}}
+
+
+ {{? data.open}}
+
+ Cell:
+
+ {{? data.hasPowercell}}
+ {{=helper.link('Eject', 'eject', 'ejectcell')}}
+ {{??}}
+ {{=helper.link('Install', 'eject', 'installcell')}}
+ {{?}}
+
+
+ {{?}}
+
+
+
+
+ Current Temp:
+
+ {{=data.currentTemp}}°C
+
+
+
+ Target Temp:
+
+ {{=data.targetTemp}}°C
+
+
+ {{? data.open}}
+
+ Adjustment:
+
+ {{=helper.link('', 'fast-backward', 'temp', {'set': -20}, data.targetTemp > data.minTemp ? null : 'disabled')}}
+ {{=helper.link('', 'backward', 'temp', {'set': -5}, data.targetTemp > data.minTemp ? null : 'disabled')}}
+ {{=helper.link('Set', 'pencil', 'temp', {'set': 'custom'}, null)}}
+ {{=helper.link('', 'forward', 'temp', {'set': 5}, data.targetTemp < data.maxTemp ? null : 'disabled')}}
+ {{=helper.link('', 'fast-forward', 'temp', {'set': 20}, data.targetTemp < data.maxTemp ? null : 'disabled')}}
+
+
+ {{?}}
+
+
+ Operational Mode:
+
+
+ {{? data.open}}
+ {{=helper.link('Heat', 'long-arrow-up', 'mode', {'mode': 'heat'}, data.mode != "heat" ? null : 'selected')}}
+ {{=helper.link('Cool', 'long-arrow-down', 'mode', {'mode': 'cool'}, data.mode != "cool" ? null : 'selected')}}
+ {{=helper.link('Auto', 'arrows-v', 'mode', {'mode': 'auto'}, (data.mode == "heat" || data.mode == "cool") ? null : 'selected')}}
+ {{??}}
+ {{? data.mode == "heat"}}
+ Heat
+ {{?? data.mode == "cool"}}
+ Cool
+ {{??}}
+ Auto
+ {{?}}
+ {{?}}
+
+
+
diff --git a/nano/templates/tanks.dot b/nano/templates/tanks.dot
new file mode 100644
index 00000000000..f3c33725104
--- /dev/null
+++ b/nano/templates/tanks.dot
@@ -0,0 +1,37 @@
+
+ {{? data.hasHoldingTank }}
+ The regulator is connected to a mask.
+ {{??}}
+ The regulator is not connected to a mask.
+ {{?}}
+
+
+
+ Tank Pressure:
+
+ {{=helper.bar(data.tankPressure, 0, 1013, (data.tankPressure > 200) ? 'good' : ((data.tankPressure > 100) ? 'average' : 'bad'), data.tankPressure + ' kPa')}}
+
+
+
+ Release Pressure:
+
+ {{=helper.bar(data.releasePressure, data.minReleasePressure, data.maxReleasePressure, null, data.releasePressure + ' kPa')}}
+
+
+
+ Pressure Regulator:
+
+ {{=helper.link('Reset', 'refresh', 'pressure', {'set': 'reset'}, (data.releasePressure != data.defaultReleasePressure) ? null : 'disabled')}}
+ {{=helper.link('Min', 'minus', 'pressure', {'set': 'min'}, (data.releasePressure > data.minReleasePressure) ? null : 'disabled')}}
+ {{=helper.link('Set', 'pencil', 'pressure', {'set': 'custom'}, null)}}
+ {{=helper.link('Max', 'plus', 'pressure', {'set': 'max'}, (data.releasePressure < data.maxReleasePressure) ? null : 'disabled')}}
+
+
+
+ Valve:
+
+ {{=helper.link('Open', 'unlock', 'valve', null, data.maskConnected ? (data.valveOpen ? 'selected' : null) : 'disabled')}}
+ {{=helper.link('Close', 'lock', 'valuve', null, data.valveOpen ? null : 'selected')}}
+
+
+
diff --git a/tgstation.dme b/tgstation.dme
index c1e24a867bb..997dc3956f4 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -377,6 +377,7 @@
#include "code\game\gamemodes\meteor\meteors.dm"
#include "code\game\gamemodes\monkey\monkey.dm"
#include "code\game\gamemodes\nuclear\nuclear.dm"
+#include "code\game\gamemodes\nuclear\nuclear_challenge.dm"
#include "code\game\gamemodes\nuclear\nuclearbomb.dm"
#include "code\game\gamemodes\nuclear\pinpointer.dm"
#include "code\game\gamemodes\revolution\revolution.dm"
@@ -1105,9 +1106,6 @@
#include "code\modules\hydroponics\seed_extractor.dm"
#include "code\modules\hydroponics\seeds.dm"
#include "code\modules\json\json.dm"
-#include "code\modules\json\json_reader.dm"
-#include "code\modules\json\json_token.dm"
-#include "code\modules\json\json_writer.dm"
#include "code\modules\library\lib_items.dm"
#include "code\modules\library\lib_machines.dm"
#include "code\modules\library\lib_readme.dm"
@@ -1465,6 +1463,7 @@
#include "code\modules\projectiles\guns\energy.dm"
#include "code\modules\projectiles\guns\grenade_launcher.dm"
#include "code\modules\projectiles\guns\magic.dm"
+#include "code\modules\projectiles\guns\medbeam.dm"
#include "code\modules\projectiles\guns\projectile.dm"
#include "code\modules\projectiles\guns\syringe_gun.dm"
#include "code\modules\projectiles\guns\energy\laser.dm"