diff --git a/core/ansi_term.js b/core/ansi_term.js index 39430955..d69cf1e1 100644 --- a/core/ansi_term.js +++ b/core/ansi_term.js @@ -54,7 +54,10 @@ var CONTROL = { blinkToBrightIntensity : '?33h', blinkNormal : '?33l', - emulationSpeed : '*r' // Set output emulation speed. See cterm.txt + emulationSpeed : '*r', // Set output emulation speed. See cterm.txt + + hideCursor : '?25l', // Nonstandard - cterm.txt + showCursor : '?25h', // Nonstandard - cterm.txt }; /* diff --git a/core/button_view.js b/core/button_view.js index 80557525..37215e87 100644 --- a/core/button_view.js +++ b/core/button_view.js @@ -8,12 +8,13 @@ var assert = require('assert'); exports.ButtonView = ButtonView; -function ButtonView(client, options) { +function ButtonView(options) { options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); options.justify = miscUtil.valueWithDefault(options.justify, 'center'); + options.cursor = miscUtil.valueWithDefault(options.cursor, 'hide'); - TextView.call(this, client, options); + TextView.call(this, options); } util.inherits(ButtonView, TextView); diff --git a/core/edit_text_view.js b/core/edit_text_view.js index 22a62789..c771c5bf 100644 --- a/core/edit_text_view.js +++ b/core/edit_text_view.js @@ -9,14 +9,11 @@ var assert = require('assert'); exports.EditTextView = EditTextView; -function EditTextView(client, options) { +function EditTextView(options) { options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); - options.inputType = miscUtil.valueWithDefault(options.inputType, 'normal'); - TextView.call(this, client, options); - - assert(this.inputType in EditTextView.InputTypes); + TextView.call(this, options); this.clientBackspace = function() { this.client.term.write( @@ -26,27 +23,6 @@ function EditTextView(client, options) { util.inherits(EditTextView, TextView); -EditTextView.InputTypes = { - normal : 1, - email : 2, - numeric : 3, - alpha : 4, - alphaNumeric : 5, - phone : 6, -}; -Object.freeze(EditTextView.InputTypes); - -EditTextView.prototype.isKeyValidForInputType = function(key) { - // :TODO: add in the actual validations: - switch(this.inputType) { - case 'normal' : return true; - case 'email' : return true; // :TODO: validate based on char + position - case 'numeric' : return !isNaN(key); - } - - return true; -}; - EditTextView.prototype.onKeyPress = function(key, isSpecial) { if(isSpecial) { return; @@ -54,13 +30,9 @@ EditTextView.prototype.onKeyPress = function(key, isSpecial) { assert(1 === key.length); - if(!this.isKeyValidForInputType(key)) { - return; - } - // :TODO: how to handle justify left/center? - if(this.text.length < this.options.maxLength) { + if(this.text.length < this.maxLength) { key = strUtil.stylizeString(key, this.textStyle); this.text += key; diff --git a/core/mask_edit_text_view.js b/core/mask_edit_text_view.js new file mode 100644 index 00000000..6469bea5 --- /dev/null +++ b/core/mask_edit_text_view.js @@ -0,0 +1,59 @@ +/* jslint node: true */ +'use strict'; + +var TextView = require('./text_view.js').TextView; +var miscUtil = require('./misc_util.js'); + +var util = require('util'); +var assert = require('assert'); + +function MaskEditTextView(client, options) { + options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); + options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); + + TextView.call(this, client, options); + + var self = this; + + this.mask = options.mask || ''; + +} + +util.inherits(MaskEditTextView, TextView); + +MaskEditTextView.MaskCharacterRegEx = { + '#' : /[0-9]/, + '?' : /[a-zA-Z]/, + '&' : /[\w\d\s]/, // 32-126, 128-255 + 'A' : /[0-9a-zA-Z]/, +}; + +MaskEditTextView.prototype.setMask = function(mask) { + this.mask = mask; +}; + +MaskEditTextView.prototype.onKeyPress = function(key, isSpecial) { + if(isSpecial) { + return; + } + + assert(1 === key.length); + + + + MaskEditTextView.super_.prototype.onKeyPress(this, key, isSpecial); +}; + +MaskEditTextView.prototype.onSpecialKeyPress = function(keyName) { + + if(this.isSpecialKeyMapped('backspace', keyName)) { + /* + if(this.text.length > 0) { + this.text = this.text.substr(0, this.text.length - 1); + this.clientBackspace(); + } + */ + } + + MaskEditTextView.super_.prototype.onSpecialKeyPress.call(this, keyName); +}; \ No newline at end of file diff --git a/core/mci_view_factory.js b/core/mci_view_factory.js index fbfb175c..aa1b6306 100644 --- a/core/mci_view_factory.js +++ b/core/mci_view_factory.js @@ -33,6 +33,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { var view; var options = { + client : this.client, id : mci.id, color : mci.color, focusColor : mci.focusColor, @@ -63,7 +64,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { options.dimens = { width : options.maxLength }; } - view = new TextView(this.client, options); + view = new TextView(options); break; case 'ET' : @@ -76,7 +77,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { setFocusOption(0, 'focusTextStyle'); - view = new EditTextView(this.client, options); + view = new EditTextView(options); break; case 'PL' : @@ -91,7 +92,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { options.dimens = { width : options.maxLength }; } - view = new TextView(this.client, options); + view = new TextView(options); } } break; @@ -106,7 +107,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { setFocusOption(0, 'focusTextStyle'); - view = new ButtonView(this.client, options); + view = new ButtonView(options); break; case 'VM' : @@ -116,7 +117,7 @@ MCIViewFactory.prototype.createFromMCI = function(mci) { setFocusOption(0, 'focusTextStyle'); - view = new VerticalMenuView(this.client, options); + view = new VerticalMenuView(options); break; } diff --git a/core/menu_view.js b/core/menu_view.js index 7708c29f..1ffdb2ab 100644 --- a/core/menu_view.js +++ b/core/menu_view.js @@ -9,31 +9,31 @@ var assert = require('assert'); exports.MenuView = MenuView; -function MenuView(client, options) { +function MenuView(options) { options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true); options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true); - View.call(this, client, options); + View.call(this, options); var self = this; - if(this.options.items) { - this.setItems(this.options.items); + if(options.items) { + this.setItems(options.items); } else { this.items = []; } - this.focusedItemIndex = this.options.focusedItemIndex || 0; + this.focusedItemIndex = options.focusedItemIndex || 0; this.focusedItemIndex = this.items.length >= this.focusedItemIndex ? this.focusedItemIndex : 0; - this.itemSpacing = this.options.itemSpacing || 1; + this.itemSpacing = options.itemSpacing || 1; this.itemSpacing = parseInt(this.itemSpacing, 10); - this.focusPrefix = this.options.focusPrefix || ''; - this.focusSuffix = this.options.focusSuffix || ''; + this.focusPrefix = options.focusPrefix || ''; + this.focusSuffix = options.focusSuffix || ''; - this.fillChar = miscUtil.valueWithDefault(this.options.fillChar, ' ').substr(0, 1); - this.justify = this.options.justify || 'none'; + this.fillChar = miscUtil.valueWithDefault(options.fillChar, ' ').substr(0, 1); + this.justify = options.justify || 'none'; this.moveSelection = function(fromIndex, toIndex) { assert(!self.positionCacheExpired); diff --git a/core/text_view.js b/core/text_view.js index fb206f8d..f09596e7 100644 --- a/core/text_view.js +++ b/core/text_view.js @@ -10,19 +10,19 @@ var assert = require('assert'); exports.TextView = TextView; -function TextView(client, options) { - View.call(this, client, options); +function TextView(options) { + View.call(this, options); var self = this; - if(this.options.maxLength) { - this.maxLength = this.options.maxLength; + if(options.maxLength) { + this.maxLength = options.maxLength; } - this.multiLine = this.options.multiLine || false; - this.fillChar = miscUtil.valueWithDefault(this.options.fillChar, ' ').substr(0, 1); - this.justify = this.options.justify || 'right'; - this.inputType = this.options.inputType || 'normal'; + this.multiLine = options.multiLine || false; + this.fillChar = miscUtil.valueWithDefault(options.fillChar, ' ').substr(0, 1); + this.justify = options.justify || 'right'; + //this.inputType = options.inputType || 'normal'; this.isPasswordTextStyle = 'P' === this.textStyle || 'password' === this.textStyle; @@ -56,7 +56,7 @@ function TextView(client, options) { } }; - this.setText(this.options.text || ''); + this.setText(options.text || ''); if(this.isPasswordTextStyle) { this.textMaskChar = miscUtil.valueWithDefault(this.textMaskChar, '*').substr(0, 1); diff --git a/core/ticker_text_view.js b/core/ticker_text_view.js index bbd1710c..8e73c9f3 100644 --- a/core/ticker_text_view.js +++ b/core/ticker_text_view.js @@ -10,13 +10,13 @@ var assert = require('assert'); exports.TickerTextView = TickerTextView; -function TickerTextView(client, options) { - View.call(this, client, options); +function TickerTextView(options) { + View.call(this, options); var self = this; - this.text = this.options.text || ''; - this.tickerStyle = this.options.tickerStyle || 'rightToLeft'; + this.text = options.text || ''; + this.tickerStyle = options.tickerStyle || 'rightToLeft'; assert(this.tickerStyle in TickerTextView.TickerStyles); // :TODO: Ticker |text| should have ANSI stripped before calculating any lengths/etc. diff --git a/core/vertical_menu_view.js b/core/vertical_menu_view.js index a70e0262..859ce5e1 100644 --- a/core/vertical_menu_view.js +++ b/core/vertical_menu_view.js @@ -9,8 +9,10 @@ var assert = require('assert'); exports.VerticalMenuView = VerticalMenuView; -function VerticalMenuView(client, options) { - MenuView.call(this, client, options); +function VerticalMenuView(options) { + options.cursor = options.cursor || 'hide'; + + MenuView.call(this, options); var self = this; diff --git a/core/view.js b/core/view.js index 4941f719..b8b52cdd 100644 --- a/core/view.js +++ b/core/view.js @@ -5,6 +5,7 @@ var events = require('events'); var util = require('util'); var assert = require('assert'); var ansi = require('./ansi_term.js'); +var _ = require('lodash'); exports.View = View; exports.VIEW_SPECIAL_KEY_MAP_DEFAULT = VIEW_SPECIAL_KEY_MAP_DEFAULT; @@ -19,16 +20,18 @@ var VIEW_SPECIAL_KEY_MAP_DEFAULT = { down : [ 'down arrow' ], }; -function View(client, options) { +function View(options) { events.EventEmitter.call(this); - assert(client); + assert(_.isObject(options)); + assert(_.isObject(options.client)); var self = this; - this.client = client; - this.options = options || {}; + this.client = options.client; + this.cursor = options.cursor || 'show'; + this.acceptsFocus = options.acceptsFocus || false; this.acceptsInput = options.acceptsInput || false; @@ -37,34 +40,34 @@ function View(client, options) { this.position = { x : 0, y : 0 }; this.dimens = { height : 1, width : 0 }; - this.textStyle = this.options.textStyle || 'normal'; - this.focusTextStyle = this.options.focusTextStyle || this.textStyle; + this.textStyle = options.textStyle || 'normal'; + this.focusTextStyle = options.focusTextStyle || this.textStyle; - if(this.options.id) { - this.setId(this.options.id); + if(options.id) { + this.setId(options.id); } - if(this.options.position) { - this.setPosition(this.options.position); + if(options.position) { + this.setPosition(options.position); } // this.isPasswordTextStyle = 'P' === this.textStyle || 'password' === this.textStyle; // :TODO: Don't allow width/height > client.term - if(this.options.dimens && this.options.dimens.height) { - this.dimens.height = this.options.dimens.height; + if(options.dimens && options.dimens.height) { + this.dimens.height = options.dimens.height; } - if(this.options.dimens && this.options.dimens.width) { - this.dimens.width = this.options.dimens.width; + if(options.dimens && options.dimens.width) { + this.dimens.width = options.dimens.width; } - this.color = this.options.color || { flags : 0, fg : 7, bg : 0 }; - this.focusColor = this.options.focusColor || this.color; + this.color = options.color || { flags : 0, fg : 7, bg : 0 }; + this.focusColor = options.focusColor || this.color; if(this.acceptsInput) { - this.specialKeyMap = this.options.specialKeyMap || VIEW_SPECIAL_KEY_MAP_DEFAULT; + this.specialKeyMap = options.specialKeyMap || VIEW_SPECIAL_KEY_MAP_DEFAULT; } this.isSpecialKeyMapped = function(keySet, keyName) { @@ -129,6 +132,7 @@ View.prototype.setFocus = function(focused) { assert(this.acceptsFocus, 'View does not accept focus'); this.hasFocus = focused; + this.client.term.write('show' === this.cursor ? ansi.showCursor() : ansi.hideCursor()); }; View.prototype.onKeyPress = function(key, isSpecial) {