diff --git a/core/mask_edit_text_view.js b/core/mask_edit_text_view.js index c6dd8bcd..36a90eb5 100644 --- a/core/mask_edit_text_view.js +++ b/core/mask_edit_text_view.js @@ -21,6 +21,12 @@ exports.MaskEditTextView = MaskEditTextView; // styleSGR2: Literals (focused) // styleSGR3: fillChar +// +// :TODO: +// * Hint, e.g. YYYY/MM/DD +// * Return values with literals in place +// + function MaskEditTextView(options) { options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); @@ -168,4 +174,22 @@ MaskEditTextView.prototype.setPropertyValue = function(propName, value) { } MaskEditTextView.super_.prototype.setPropertyValue.call(this, propName, value); -}; \ No newline at end of file +}; + +MaskEditTextView.prototype.getData = function() { + var rawData = MaskEditTextView.super_.prototype.getData.call(this); + var data = ''; + + assert(rawData.length <= this.patternArray.length); + + var p = 0; + for(var i = 0; i < this.patternArray.length; ++i) { + if(_.isRegExp(this.patternArray[i])) { + data += rawData[p++]; + } else { + data += this.patternArray[i]; + } + } + + return data; +}; diff --git a/core/mci_view_factory.js b/core/mci_view_factory.js index 4a3cf3b8..4e10517f 100644 --- a/core/mci_view_factory.js +++ b/core/mci_view_factory.js @@ -28,7 +28,6 @@ function MCIViewFactory(client) { } MCIViewFactory.prototype.getPredefinedViewLabel = function(code) { - return { BN : Config.general.boardName, VL : 'ENiGMA½ v' + packageJson.version, @@ -39,7 +38,8 @@ MCIViewFactory.prototype.getPredefinedViewLabel = function(code) { UG : _.values(this.client.user.groups).join(', '), UR : this.client.user.properties.real_name, LO : this.client.user.properties.location, - UA : this.client.user.properties.age, + UA : this.client.user.getAge().toString(), + UB : this.client.user.getFormattedBirthDate('medium'), US : this.client.user.properties.sex, UE : this.client.user.properties.email_address, UW : this.client.user.properties.web_address, diff --git a/core/menu_module.js b/core/menu_module.js index 39e84af2..a5f060a7 100644 --- a/core/menu_module.js +++ b/core/menu_module.js @@ -102,8 +102,8 @@ function MenuModule(options) { // Prompts *must* have art. If it's missing it's an error // :TODO: allow inline prompts in the future, e.g. @inline:memberName -> { "memberName" : { "text" : "stuff", ... } } var promptConfig = self.menuConfig.promptConfig; - self.displayArtAsset(promptConfig.art, function displayed(err, mciMap) { - mciData.prompt = mciMap; + self.displayArtAsset(promptConfig.art, function displayed(err, artData) { + mciData.prompt = artData.mciMap; callback(err); }); } else { diff --git a/core/menu_util.js b/core/menu_util.js index f66112bc..413416bc 100644 --- a/core/menu_util.js +++ b/core/menu_util.js @@ -53,7 +53,7 @@ function getMenuConfig(name, cb) { function locatePromptConfig(promptJson, callback) { if(promptJson) { if(_.has(promptJson, [ 'prompts', menuConfig.prompt ])) { - menuConfig.promptConfig = promptJson[menuConfig.prompt]; + menuConfig.promptConfig = promptJson.prompts[menuConfig.prompt]; } else { callback(new Error('No prompt entry for \'' + menuConfig.prompt + '\'')); return; @@ -138,9 +138,10 @@ function getFormConfigByIDAndMap(menuConfig, formId, mciMap, cb) { } var formForId = menuConfig.form[formId]; + var mciReqKey = _.pluck(_.sortBy(mciMap, 'code'), 'code').join(''); - var mciReqKey = _.sortBy(Object.keys(mciMap), String).join(''); Log.trace( { mciKey : mciReqKey }, 'Looking for MCI configuration key'); + if(_.isObject(formForId[mciReqKey])) { cb(null, formForId[mciReqKey]); return; @@ -151,7 +152,7 @@ function getFormConfigByIDAndMap(menuConfig, formId, mciMap, cb) { return; } - cb(new Error('No matching form configuration found')); + cb(new Error('No matching form configuration found for key \'' + mciReqKey + '\'')); } function handleAction(client, formData, conf) { diff --git a/core/multi_line_edit_text_view.js b/core/multi_line_edit_text_view.js index 048f9236..bf0c9e78 100644 --- a/core/multi_line_edit_text_view.js +++ b/core/multi_line_edit_text_view.js @@ -1037,7 +1037,7 @@ MultiLineEditTextView.prototype.setFocus = function(focused) { }; MultiLineEditTextView.prototype.setText = function(text) { - text = require('fs').readFileSync('/home/bashby/Downloads/test_text.txt', { encoding : 'utf-8'}); + //text = require('fs').readFileSync('/home/nuskooler/Downloads/test_text.txt', { encoding : 'utf-8'}); this.insertRawText(text); this.cursorEndOfDocument(); diff --git a/core/servers/telnet.js b/core/servers/telnet.js index 79a31ebc..e0457bda 100644 --- a/core/servers/telnet.js +++ b/core/servers/telnet.js @@ -404,7 +404,7 @@ function parseCommand(bufs, i, event) { //return COMMAND_IMPLS[command](bufs, i + 1, event); return handler(bufs, i + 1, event); } else { - assert(2 == bufs.length); // IAC + COMMAND + assert(2 == bufs.length, 'Expected bufs length of 2, got ' + bufs.length); // IAC + COMMAND event.buf = bufs.splice(0, 2).toBuffer(); return event; } diff --git a/core/text_view.js b/core/text_view.js index c58ee86f..0d1425cb 100644 --- a/core/text_view.js +++ b/core/text_view.js @@ -152,4 +152,4 @@ TextView.prototype.setPropertyValue = function(propName, value) { } TextView.super_.prototype.setPropertyValue.call(this, propName, value); -}; \ No newline at end of file +}; diff --git a/core/user.js b/core/user.js index 219c7114..5788ff4d 100644 --- a/core/user.js +++ b/core/user.js @@ -319,6 +319,33 @@ User.prototype.persistProperties = function(cb) { }); }; +// :TODO: A general purpose date/time formatting class or lib would be better here.... +User.prototype.getFormattedBirthDate = function(style) { + style = style || 'medium'; + + switch(style) { + + case 'medium' : + return _.has(this.properties, 'birthdate') ? + new Date(Date.parse(this.properties.birthdate)).toJSON().slice(0, 10) : + null; + } +}; + +User.prototype.getAge = function() { + var birthDate = new Date(Date.parse(this.properties.birthdate)); + if(!isNaN(birthDate)) { + var today = new Date(); + var age = today.getFullYear() - birthDate.getFullYear(); + var m = today.getMonth() - birthDate.getMonth(); + if(m < 0 || (m === 0 && today.getDate() < birthDate.getDate())) { + age--; + } + + return age; + } +}; + /////////////////////////////////////////////////////////////////////////////// // Exported methods /////////////////////////////////////////////////////////////////////////////// diff --git a/core/view_controller.js b/core/view_controller.js index a39b0dd5..f1d9b4b7 100644 --- a/core/view_controller.js +++ b/core/view_controller.js @@ -628,7 +628,7 @@ ViewController.prototype.getFormData = function() { } } } catch(e) { - self.client.log.error(e); // :TODO: Log better ;) + this.client.log.error(e); // :TODO: Log better ;) } } diff --git a/mods/apply.js b/mods/apply.js index 8ea55b7f..8aa0615e 100644 --- a/mods/apply.js +++ b/mods/apply.js @@ -31,6 +31,11 @@ function validateApplicationData(formData, cb) { return; } + if(isNaN(Date.parse(formData.value.birthdate))) { + cb('Invalid birthdate!'); + return; + } + if(formData.value.password.length < Config.users.passwordMin) { cb('Password too short!', [ 9, 10 ]); return; @@ -81,7 +86,7 @@ function submitApplication(callingMenu, formData, extraArgs) { newUser.properties = { real_name : formData.value.realName, - birthday : formData.value.birthday, + birthdate : new Date(Date.parse(formData.value.birthdate)).toISOString(), sex : formData.value.sex, location : formData.value.location, affiliation : formData.value.affils, diff --git a/mods/art/demo_mask_edit_text_view1.ans b/mods/art/demo_mask_edit_text_view1.ans index 12a5cbdb..f7c194c5 100644 Binary files a/mods/art/demo_mask_edit_text_view1.ans and b/mods/art/demo_mask_edit_text_view1.ans differ diff --git a/mods/menu.json b/mods/menu.json index 1021e846..4d9b4c2f 100644 --- a/mods/menu.json +++ b/mods/menu.json @@ -46,7 +46,7 @@ "art" : "matrix", "form" : { "0" : { // :TODO: Make form "0" the default if missing (e.g. optional)... not sure how with current structure though - "VM1" : { + "VM" : { "mci" : { "VM1" : { "submit" : true, @@ -110,7 +110,7 @@ "next" : "newUserActive", "form" : { "0" : { - "BT12BT13ET1ET10ET2ET4ET5ET6ET7ET8ET9ME3TL11" : { + "BTBTETETETETETETETETETMETL" : { "mci" : { "ET1" : { "focus" : true, @@ -122,7 +122,7 @@ "maxLength" : 32 }, "ME3" : { - "argName" : "birthday", + "argName" : "birthdate", //"width" : 8, "maskPattern" : "####/##/##" }, @@ -204,7 +204,7 @@ "options" : { "cls" : true }, "form" : { "0" : { - "VM1" : { + "VM" : { "mci" : { "VM1" : { "items" : [ @@ -266,7 +266,7 @@ "options" : { "cls" : true }, "form" : { "0" : { - "BT5ET1ET2ET3ET4" : { + "BTETETETET" : { "mci" : { "ET1" : { "width" : 20, @@ -316,7 +316,7 @@ "options" : { "cls" : true }, "form" : { "0" : { - "BT8SM1SM2TM3" : { + "BTSMSMTM" : { "mci" : { "SM1" : { "items" : [ "Henry Morgan", "François l'Ollonais", "Roche Braziliano", "Black Bart", "Blackbeard" ] @@ -356,12 +356,14 @@ "options" : { "cls" : true }, "form" : { "0" : { - "BT5ME1ME2" : { + "BTMEME" : { "mci" : { "ME1" : { "maskPattern" : "##/##/##", "styleSGR1" : "|00|30|01", - "styleSGR2" : "|00|45|01" + //"styleSGR2" : "|00|45|01", + "styleSGR3" : "|00|30|35", + "fillChar" : "#" }, "BT5" : { "text" : "< Back" @@ -390,13 +392,14 @@ "options" : { "cls" : true }, "form" : { "0" : { - "BT5MT1" : { + "BTMT" : { "mci" : { "MT1" : { "width" : 70, "height" : 17, - "text" : "@art:demo_multi_line_edit_text_view_text.txt", - //"text" : "Hints:\n * Press CTRL-Y to clear a line\n * Arrow keys to move around\n\nTry editing the text below:\nThis\tis\ttabbbed!\nLet me be sick... I want to get up. Get me something to be sick in... Stop the film... Please stop it... I can't stand it any more. Stop it please... please.\n\nWell, that was a very promising start. By my calculations, you should be starting to feel alright again. Yes? Dr. Brodsky's pleased with you. Now \ttomorrow \tthere'll \tbe \ttwo \tsessions, \tof\t course, morning and afternoon.\n\nYou mean, I have to viddy two sessions in one day?\n\nI imagine you'll be feeling a little bit limp by the end of the day. But we have to be hard on you. You have to be cured.\n", + //"text" : "@art:demo_multi_line_edit_text_view_text.txt", + // "text" : "@systemMethod:textFromFile" + "text" : "Hints:\n\t* Insert / CTRL-V toggles overtype mode\n\t* CTRL-Y deletes the current line\n\t* Try Page Up / Page Down\n\t* Home goes to the start of line text\n\t* End goes to the end of a line\n\n\nTab handling:\n-------------------------------------------------\n\tA\tB\tC\tD\tE\tF\nA\tB\tC\tD\tE\tF\tG\tH\n\tA\tB\tC\tD\tE\tF\nA\tB\tC\tD\tE\tF\tG\tH\nA0\tBB\t1\tCCC\t2\tDDD\t3EEEE\nW\t\tX\t\tY\t\tZ\n\nAn excerpt from A Clockwork Orange:\n\"What sloochatted then, of course, was that my cellmates woke up and started joining in, tolchocking a bit wild in the near-dark, and the shoom seemed to wake up the whole tier, so that you could slooshy a lot of creeching and banging about with tin mugs on the wall, as though all the plennies in all the cells thought a big break was about to commence, O my brothers.\n", "focus" : true }, "BT5" : { @@ -426,7 +429,7 @@ "options" : { "cls" : true }, "form" : { "0" : { - "BT5HM1HM2" : { + "BTHMHM" : { "mci" : { "HM1" : { "items" : [ "One", "Two", "Three" ], @@ -463,7 +466,7 @@ "options" : { "cls" : true }, "form" : { "0" : { - "VM1" : { + "VM" : { "mci" : { "VM1" : { "items" : [ @@ -526,7 +529,7 @@ }, "form" : { "0" : { - "ET1ET2ET3" : { + "ETETET" : { "mci" : { "ET1" : { // :TODO: from/to may be set by args @@ -557,7 +560,7 @@ } }, "1" : { - "MT1" : { + "MT" : { "mci" : { "MT1" : { "width" : 79, @@ -583,7 +586,7 @@ } }, "2" : { - "TL1TL2" : { + "TLTL" : { "mci" : { "TL1" : { "width" : 5 @@ -595,7 +598,7 @@ } }, "3" : { - "HM1" : { + "HM" : { "mci" : { "HM1" : { // :TODO: Continue, Save, Discard, Clear, Quote, Help diff --git a/mods/prompt.json b/mods/prompt.json index 0d634322..f176d250 100644 --- a/mods/prompt.json +++ b/mods/prompt.json @@ -1,7 +1,7 @@ { "prompts" : { - "art" : "usercred", "userCredentials" : { + "art" : "usercred", "mci" : { "ET1" : { "argName" : "username", diff --git a/mods/themes/NU-MAYA/theme.json b/mods/themes/NU-MAYA/theme.json index 3124197a..483310dc 100644 --- a/mods/themes/NU-MAYA/theme.json +++ b/mods/themes/NU-MAYA/theme.json @@ -29,7 +29,8 @@ //"ET3" : { "width" : 21 }, "ME3" : { "styleSGR1" : "|00|30|01", - "styleSGR2" : "|00|37" + "styleSGR2" : "|00|37", + "fillChar" : "#" }, "ET4" : { "width" : 1 }, "ET5" : { "width" : 21 },