diff --git a/code/game/objects/items/devices/PDA/PDA.dm b/code/game/objects/items/devices/PDA/PDA.dm index 1332ce7370..1f754ff2ca 100644 --- a/code/game/objects/items/devices/PDA/PDA.dm +++ b/code/game/objects/items/devices/PDA/PDA.dm @@ -653,8 +653,9 @@ var/global/list/obj/item/device/pda/PDAs = list() // the ui does not exist, so we'll create a new() one // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm ui = new(user, src, ui_key, "pda.tmpl", title, 520, 400, state = inventory_state) + // add templates for screens in common with communicator. + ui.add_template("atmosphericScan", "atmospheric_scan.tmpl") // when the ui is first opened this is the data it will use - ui.set_initial_data(data) // open the new ui window ui.open() diff --git a/code/game/objects/items/devices/communicator/UI.dm b/code/game/objects/items/devices/communicator/UI.dm index f2d3fd39b6..4d6ff75c50 100644 --- a/code/game/objects/items/devices/communicator/UI.dm +++ b/code/game/objects/items/devices/communicator/UI.dm @@ -118,6 +118,8 @@ // the ui does not exist, so we'll create a new() one // for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm ui = new(user, src, ui_key, "communicator.tmpl", "Communicator", 475, 700, state = key_state) + // add templates for screens in common with communicator. + ui.add_template("atmosphericScan", "atmospheric_scan.tmpl") // when the ui is first opened this is the data it will use ui.set_initial_data(data) // open the new ui window diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm index 310bbfa9c5..ec003a813e 100644 --- a/code/modules/nano/nanoui.dm +++ b/code/modules/nano/nanoui.dm @@ -519,8 +519,3 @@ nanoui is used to open and update nano browser uis */ /datum/nanoui/proc/update(var/force_open = 0) src_object.ui_interact(user, ui_key, src, force_open, master_ui, state) - -/datum/nanoui/proc/append_template(var/key, var/filename) - add_template(key, filename) - open() - update(1) diff --git a/nano/README.md b/nano/README.md new file mode 100644 index 0000000000..5497050a2e --- /dev/null +++ b/nano/README.md @@ -0,0 +1,39 @@ +# NanoUI Templates + +NanoUI uses doT (https://olado.github.io/doT/index.html) as its templating engine. + +## Template Markup Tags + +Markup tags are used to add dynamic content to the template. +TODO - This documentation is incomplete. + +### Print Tag +- The print tag outputs variable as text to the UI. +`{{:data.variable}}` + +### If Tag +- The if tag displays content conditionally based on the provided expression being true. +- When combined with the else tag the if tag can also show content if the provided expression is false. +- The else tag can optionally have an expression provided (e.g. "`{{else expression2}}`"), giving it "elseif" functionality. + +`{{if expression}} {{/if}}` +`{{if expression}} {{else}} {{/if}}` +`{{if expression1}} {{else expression2}} {{/if}}` + +### For Tag +- Loop through entries in an array (an array is a list with a numeric index (it does not use strings as keys). +- Each time the `for` tag iterates though the array it sets a variable (default "value") to the data of the current entry (another variable, default "index", contains the index). An example of this is using the print tag to print the contents (e.g. `{{:value.key1}}` and `{{:value.key2}}`). +- If combined with an `empty` tag the for tag can display content when the array is empty. + +`{{for array}} {{/for}}` +`{{for array}} {{empty}} {{/for}}` + + +### Tansclusion Tag +- Include the contents of another template which has been added to the ui. +`{{#def.atmosphericScan}}` + +- You first must have added a template to the ui server side in your DM code: +`ui.add_template("atmosphericScan", "atmospheric_scan.tmpl")` + +- Then you can reference it in the main template. The tag will be replaced by the contents of the named template. All tags in the named template are evaluated as normal. diff --git a/nano/js/nano_state.js b/nano/js/nano_state.js index e211895cee..92965d1ab2 100644 --- a/nano/js/nano_state.js +++ b/nano/js/nano_state.js @@ -7,7 +7,8 @@ function NanoStateClass() { return; } - this.key = this.key.toLowerCase(); + this.key = this.key.toLowerCase(); + NanoStateManager.addState(this);*/ } @@ -17,99 +18,102 @@ NanoStateClass.prototype.contentRendered = false; NanoStateClass.prototype.mapInitialised = false; NanoStateClass.prototype.isCurrent = function () { - return NanoStateManager.getCurrentState() == this; + 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(); + // 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(); + // 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 + // 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'])) - { - var content = ""; - var keys = NanoTemplate.getKeys(); - for (i = 0; i < keys.length; i++) { - if(keys[i] == "layout"){ continue; } - content += NanoTemplate.parse(keys[i], data); - } - $("#uiContent").html(content); // 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(); - $('#uiMapTooltip') - .off('click') - .on('click', function (event) { - event.preventDefault(); - $(this).fadeOut(400); - }); - this.mapInitialised = true; - } + // Do not add code here, add it to the 'default' state (nano_state_defaut.js) or create a new state and override this function - $("#uiMapContent").html(NanoTemplate.parse('mapContent', data)); // render the 'mapContent' template to the #uiMapContent div + try + { + if (!this.layoutRendered || (data['config'].hasOwnProperty('autoUpdateLayout') && data['config']['autoUpdateLayout'])) + { + $("#uiLayout").html(NanoTemplate.parse('layout', data)); // render the 'layout' template to the #uiLayout div + this.layoutRendered = true; + } + if (!this.contentRendered || (data['config'].hasOwnProperty('autoUpdateContent') && data['config']['autoUpdateContent'])) + { + $("#uiContent").html(NanoTemplate.parse('main', data)); // render the 'main' template to the #uiContent div + this.contentRendered = true; + } + if (NanoTemplate.templateExists('mapContent')) + { + if (!this.mapInitialised) + { + // Add drag functionality to the map ui + $('#uiMap').draggable(); - 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; - } + $('#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); + // 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); + // 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/js/nano_template.js b/nano/js/nano_template.js index b2f894fd07..f8f5d26594 100644 --- a/nano/js/nano_template.js +++ b/nano/js/nano_template.js @@ -1,15 +1,15 @@ var NanoTemplate = function () { - var _templateData = {}; + var _templateData = {}; - var _templates = {}; - var _compiledTemplates = {}; + var _templates = {}; + var _compiledTemplates = {}; var _helpers = {}; - var init = function () { - // We store templateData in the body tag, it's as good a place as any + 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) @@ -18,101 +18,94 @@ var NanoTemplate = function () { } 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); + 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; - } + if (!templateCount) + { + $(document).trigger('templatesLoaded'); + return; + } - // load markup for each template and register it - for (var key in _templateData) - { - if (!_templateData.hasOwnProperty(key)) - { - continue; - } + // 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) { + $.when($.ajax({ + url: _templateData[key], + cache: false, + dataType: 'text' + })) + .done(function(templateMarkup) { - templateMarkup += '
'; + templateMarkup += '
'; - try - { - NanoTemplate.addTemplate(key, templateMarkup); - } - catch(error) - { - alert('ERROR: An error occurred while loading the UI: ' + error.message); - return; - } + try + { + NanoTemplate.addTemplate(key, templateMarkup); + } + catch(error) + { + alert('ERROR: An error occurred while loading the UI: ' + error.message); + return; + } - delete _templateData[key]; + delete _templateData[key]; - loadNextTemplate(); - }) - .fail(function () { - alert('ERROR: Loading template ' + key + '(' + _templateData[key] + ') failed!'); - }); + loadNextTemplate(); + }) + .fail(function () { + alert('ERROR: Loading template ' + key + '(' + _templateData[key] + ') failed!'); + }); - return; - } - } + return; + } + } - var compileTemplates = function () { + var compileTemplates = function () { - for (var key in _templates) { - try { - _compiledTemplates[key] = doT.template(_templates[key], null, _templates) - } - catch (error) { - alert(error.message); - } - } - }; + 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); - }, - getKeys: function () { - var _keys = []; - for(var key in _templates) { - _keys.push(key); - } - return _keys; - }, - parse: function (templateKey, data) { - if (!_compiledTemplates.hasOwnProperty(templateKey) || !_compiledTemplates[templateKey]) { - if (!_templates.hasOwnProperty(templateKey)) { - alert('ERROR: Template "' + templateKey + '" does not exist in _compiledTemplates!'); - return '

Templateerror (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); - }, + 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.'); @@ -136,7 +129,7 @@ var NanoTemplate = function () { delete _helpers[helperName]; } } - } + } }(); diff --git a/nano/templates/atmospheric_scan.tmpl b/nano/templates/atmospheric_scan.tmpl new file mode 100644 index 0000000000..df1f6bf06a --- /dev/null +++ b/nano/templates/atmospheric_scan.tmpl @@ -0,0 +1,57 @@ +
+ {{if data.aircontents.reading == 1}} +
+ Pressure: +
+
+ {{:helper.string('{1} kPa', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good' , data.aircontents.pressure)}} +
+
+ Temperature: +
+
+ {{:helper.string('{1} °C', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , data.aircontents.temp)}} +
+
+
+ Oxygen: +
+
+ {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good' , data.aircontents.oxygen)}} +
+
+ Nitrogen: +
+
+ {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good' , data.aircontents.nitrogen)}} +
+ {{if data.aircontents.carbon_dioxide > 0}} +
+ Carbon Dioxide: +
+
+ {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good' , data.aircontents.carbon_dioxide)}} +
+ {{/if}} + {{if data.aircontents.phoron > 0}} +
+ Phoron: +
+
+ {{:helper.string('{1}%', data.aircontents.phoron > 0 ? 'bad' : 'good' , data.aircontents.phoron)}} +
+ {{/if}} + {{if data.aircontents.other > 0}} +
+ Unknown: +
+
+ {{:data.aircontents.other}}% +
+ {{/if}} + {{else}} +
+ Unable to get air reading +
+ {{/if}} +
\ No newline at end of file diff --git a/nano/templates/communicator.tmpl b/nano/templates/communicator.tmpl index 6ef7de1607..716034a7f4 100644 --- a/nano/templates/communicator.tmpl +++ b/nano/templates/communicator.tmpl @@ -243,63 +243,7 @@ Used In File(s): code\game\objects\items\devices\communicator\communicator.dm
{{:helper.link('Home', 'home', {'switch_tab' : 1})}}

Current Conditions:

-
- {{if data.aircontents.reading == 1}} -
- Pressure: -
-
- {{:helper.string('{1} kPa', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good' , data.aircontents.pressure)}} -
-
- Temperature: -
-
- {{:helper.string('{1} °C', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , data.aircontents.temp)}} -
-
-
- Oxygen: -
-
- {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good' , data.aircontents.oxygen)}} -
-
- Nitrogen: -
-
- {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good' , data.aircontents.nitrogen)}} -
- {{if data.aircontents.carbon_dioxide > 0}} -
- Carbon Dioxide: -
-
- {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good' , data.aircontents.carbon_dioxide)}} -
- {{/if}} - {{if data.aircontents.phoron > 0}} -
- Phoron: -
-
- {{:helper.string('{1}%', data.aircontents.phoron > 0 ? 'bad' : 'good' , data.aircontents.phoron)}} -
- {{/if}} - {{if data.aircontents.other > 0}} -
- Unknown: -
-
- {{:data.aircontents.other}}% -
- {{/if}} - {{else}} -
- Unable to get air reading -
- {{/if}} -
+ {{#def.atmosphericScan}}

Weather Reports:

{{for data.weather}} diff --git a/nano/templates/pda.tmpl b/nano/templates/pda.tmpl index 1e6a5f2d82..04ee2abfd9 100644 --- a/nano/templates/pda.tmpl +++ b/nano/templates/pda.tmpl @@ -318,60 +318,7 @@ Used In File(s): \code\game\objects\items\devices\PDA\PDA.dm {{else data.mode == 3}}

Atmospheric Scan

-
- {{if data.aircontents.reading == 1}} -
- Pressure: -
-
- {{:helper.string('{1} kPa', data.aircontents.pressure < 80 || data.aircontents.pressure > 120 ? 'bad' : data.aircontents.pressure < 95 || data.aircontents.pressure > 110 ? 'average' : 'good' , data.aircontents.pressure)}} -
-
- Temperature: -
-
- {{:helper.string('{1} °C', data.aircontents.temp < 5 || data.aircontents.temp > 35 ? 'bad' : data.aircontents.temp < 15 || data.aircontents.temp > 25 ? 'average' : 'good' , data.aircontents.temp)}} -
-
-
- Oxygen: -
-
- {{:helper.string('{1}%', data.aircontents.oxygen < 17 ? 'bad' : data.aircontents.oxygen < 19 ? 'average' : 'good' , data.aircontents.oxygen)}} -
-
- Nitrogen: -
-
- {{:helper.string('{1}%', data.aircontents.nitrogen > 82 ? 'bad' : data.aircontents.nitrogen > 80 ? 'average' : 'good' , data.aircontents.nitrogen)}} -
-
- Carbon Dioxide: -
-
- {{:helper.string('{1}%', data.aircontents.carbon_dioxide > 5 ? 'bad' : 'good' , data.aircontents.carbon_dioxide)}} -
-
- Phoron: -
-
- {{:helper.string('{1}%', data.aircontents.phoron > 0 ? 'bad' : 'good' , data.aircontents.phoron)}} - -
- {{if data.aircontents.other > 0}} -
- Unknown: -
-
- {{:data.aircontents.other}}% -
- {{/if}} - {{else}} -
- Unable to get air reading -
- {{/if}} -
+ {{#def.atmosphericScan}}