* Rewrite of Views functional. WIP more to come
This commit is contained in:
parent
51d15659d5
commit
381ded17a6
|
@ -0,0 +1,66 @@
|
||||||
|
/* jslint node: true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var TextView = require('./text_view.js').TextView;
|
||||||
|
var miscUtil = require('./misc_util.js');
|
||||||
|
var strUtil = require('./string_util.js');
|
||||||
|
var util = require('util');
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
exports.EditTextView = EditTextView;
|
||||||
|
|
||||||
|
function EditTextView(client, options) {
|
||||||
|
options.acceptsFocus = miscUtil.valueWithDefault(options.acceptsFocus, true);
|
||||||
|
options.acceptsInput = miscUtil.valueWithDefault(options.acceptsInput, true);
|
||||||
|
|
||||||
|
TextView.call(this, client, options);
|
||||||
|
|
||||||
|
this.clientBackspace = function() {
|
||||||
|
this.client.term.write('\b \b');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(EditTextView, TextView);
|
||||||
|
|
||||||
|
EditTextView.prototype.onKeyPress = function(key, isSpecial) {
|
||||||
|
assert(this.hasFocus);
|
||||||
|
assert(this.acceptsInput);
|
||||||
|
|
||||||
|
if(isSpecial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(1 === key.length);
|
||||||
|
|
||||||
|
if(this.text.length < this.options.maxLength) {
|
||||||
|
key = strUtil.stylizeString(key, this.textStyle);
|
||||||
|
|
||||||
|
this.text += key;
|
||||||
|
|
||||||
|
if(this.textMaskChar) {
|
||||||
|
this.client.term.write(this.textMaskChar);
|
||||||
|
} else {
|
||||||
|
this.client.term.write(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EditTextView.prototype.onSpecialKeyPress = function(keyName) {
|
||||||
|
assert(this.hasFocus);
|
||||||
|
assert(this.acceptsInput);
|
||||||
|
assert(this.specialKeyMap);
|
||||||
|
|
||||||
|
if(this.isSpecialKeyMapped('backspace', keyName)) {
|
||||||
|
if(this.text.length > 0) {
|
||||||
|
this.text = this.text.substr(0, this.text.length - 1);
|
||||||
|
this.clientBackspace();
|
||||||
|
}
|
||||||
|
} else if(this.isSpecialKeyMapped('enter', keyName)) {
|
||||||
|
if(this.multiLine) {
|
||||||
|
} else {
|
||||||
|
this.emit('action', 'accepted');
|
||||||
|
}
|
||||||
|
} else if(this.isSpecialKeyMapped('next', keyName)) {
|
||||||
|
this.emit('action', 'next');
|
||||||
|
}
|
||||||
|
};
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* jslint node: true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var TextView = require('./text_view.js').TextView;
|
||||||
|
var EditTextView = require('./edit_text_view.js').EditTextView;
|
||||||
|
var assert = require('assert');
|
||||||
|
|
||||||
|
exports.MCIViewFactory = MCIViewFactory;
|
||||||
|
|
||||||
|
function MCIViewFactory(client) {
|
||||||
|
this.client = client;
|
||||||
|
}
|
||||||
|
|
||||||
|
MCIViewFactory.prototype.createFromMCI = function(mci) {
|
||||||
|
assert(mci.code);
|
||||||
|
assert(mci.id > 0);
|
||||||
|
assert(mci.position);
|
||||||
|
|
||||||
|
var view;
|
||||||
|
var options = {
|
||||||
|
id : mci.id,
|
||||||
|
color : mci.color,
|
||||||
|
focusColor : mci.focusColor,
|
||||||
|
position : { x : mci.position[0], y : mci.position[1] },
|
||||||
|
};
|
||||||
|
|
||||||
|
switch(mci.code) {
|
||||||
|
case 'EV' :
|
||||||
|
if(mci.args.length > 0) {
|
||||||
|
options.maxLength = mci.args[0];
|
||||||
|
options.dimens = { width : options.maxLength };
|
||||||
|
}
|
||||||
|
|
||||||
|
if(mci.args.length > 1) {
|
||||||
|
options.textStyle = mci.args[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
view = new EditTextView(this.client, options);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return view;
|
||||||
|
};
|
||||||
|
|
|
@ -33,7 +33,7 @@ function TextView(client, options) {
|
||||||
this.isPasswordTextStyle = 'P' === self.textStyle || 'password' === self.textStyle;
|
this.isPasswordTextStyle = 'P' === self.textStyle || 'password' === self.textStyle;
|
||||||
|
|
||||||
if(this.isPasswordTextStyle) {
|
if(this.isPasswordTextStyle) {
|
||||||
this.passwordMaskChar = miscUtil.valueWithDefault(this.options.passwordMaskChar, '*').substr(0, 1);
|
this.textMaskChar = miscUtil.valueWithDefault(this.options.textMaskChar, '*').substr(0, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,12 +47,20 @@ TextView.prototype.redraw = function() {
|
||||||
this.client.term.write(ansi.sgr(color.flags, color.fg, color.bg));
|
this.client.term.write(ansi.sgr(color.flags, color.fg, color.bg));
|
||||||
|
|
||||||
if(this.isPasswordTextStyle) {
|
if(this.isPasswordTextStyle) {
|
||||||
this.client.term.write(strUtil.pad(new Array(this.text.length).join(this.passwordMaskChar), this.dimens.width));
|
this.client.term.write(strUtil.pad(new Array(this.text.length).join(this.textMaskChar), this.dimens.width));
|
||||||
} else {
|
} else {
|
||||||
this.client.term.write(strUtil.pad(this.text, this.dimens.width));
|
this.client.term.write(strUtil.pad(this.text, this.dimens.width));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TextView.prototype.setFocus = function(focused) {
|
||||||
|
TextView.super_.prototype.setFocus.call(this, focused);
|
||||||
|
|
||||||
|
this.client.term.write(ansi.goto(this.position.x, this.position.y));
|
||||||
|
this.redraw();
|
||||||
|
this.client.term.write(ansi.goto(this.position.x, this.position.y + this.text.length));
|
||||||
|
};
|
||||||
|
|
||||||
TextView.prototype.setText = function(text) {
|
TextView.prototype.setText = function(text) {
|
||||||
this.text = text;
|
this.text = text;
|
||||||
|
|
||||||
|
@ -62,7 +70,7 @@ TextView.prototype.setText = function(text) {
|
||||||
|
|
||||||
this.text = strUtil.stylizeString(this.text, this.textStyle);
|
this.text = strUtil.stylizeString(this.text, this.textStyle);
|
||||||
|
|
||||||
if(!this.multiLine) {
|
if(!this.multiLine && !this.dimens.width) {
|
||||||
this.dimens.width = this.text.length;
|
this.dimens.width = this.text.length;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
27
core/view.js
27
core/view.js
|
@ -26,16 +26,21 @@ function View(client, options) {
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.options = options || {};
|
this.options = options || {};
|
||||||
|
|
||||||
this.acceptsFocus = false;
|
this.acceptsFocus = options.acceptsFocus || false;
|
||||||
this.acceptsInput = false;
|
this.acceptsInput = options.acceptsInput || false;
|
||||||
|
|
||||||
this.position = { x : 0, y : 0 };
|
this.position = { x : 0, y : 0 };
|
||||||
this.dimens = { height : 1, width : 0 };
|
this.dimens = { height : 1, width : 0 };
|
||||||
|
|
||||||
|
if(this.options.id) {
|
||||||
|
this.setId(this.options.id);
|
||||||
|
}
|
||||||
|
|
||||||
if(this.options.position) {
|
if(this.options.position) {
|
||||||
this.setPosition(this.options.position);
|
this.setPosition(this.options.position);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// :TODO: Don't allow width/height > client.term
|
||||||
if(this.options.dimens && this.options.dimens.height) {
|
if(this.options.dimens && this.options.dimens.height) {
|
||||||
this.dimens.height = this.options.dimens.height;
|
this.dimens.height = this.options.dimens.height;
|
||||||
}
|
}
|
||||||
|
@ -50,10 +55,17 @@ function View(client, options) {
|
||||||
if(this.acceptsInput) {
|
if(this.acceptsInput) {
|
||||||
this.specialKeyMap = this.options.specialKeyMap || VIEW_SPECIAL_KEY_MAP_DEFAULT;
|
this.specialKeyMap = this.options.specialKeyMap || VIEW_SPECIAL_KEY_MAP_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.isSpecialKeyMapped = function(keySet, keyName) {
|
||||||
|
return this.specialKeyMap[keySet].indexOf(keyName) > -1;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(View, events.EventEmitter);
|
util.inherits(View, events.EventEmitter);
|
||||||
|
|
||||||
|
View.prototype.setId = function(id) {
|
||||||
|
this.id = id;
|
||||||
|
};
|
||||||
|
|
||||||
View.prototype.setPosition = function(pos) {
|
View.prototype.setPosition = function(pos) {
|
||||||
//
|
//
|
||||||
|
@ -66,14 +78,13 @@ View.prototype.setPosition = function(pos) {
|
||||||
this.position.x = pos.x;
|
this.position.x = pos.x;
|
||||||
this.position.y = pos.y;
|
this.position.y = pos.y;
|
||||||
} else if(2 === arguments.length) {
|
} else if(2 === arguments.length) {
|
||||||
var x = parseInt(arguments[0], 10);
|
this.position.x = parseInt(arguments[0], 10);
|
||||||
var y = parseInt(arguments[1], 10);
|
this.position.y = parseInt(arguments[1], 10);
|
||||||
if(!isNaN(x) && !isNaN(y)) {
|
|
||||||
this.position.x = x;
|
|
||||||
this.position.y = y;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(!(isNaN(this.position.x)));
|
||||||
|
assert(!(isNaN(this.position.y)));
|
||||||
|
|
||||||
assert(this.position.x > 0 && this.position.x < this.client.term.termHeight);
|
assert(this.position.x > 0 && this.position.x < this.client.term.termHeight);
|
||||||
assert(this.position.y > 0 && this.position.y < this.client.term.termWidth);
|
assert(this.position.y > 0 && this.position.y < this.client.term.termWidth);
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
/* jslint node: true */
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var events = require('events');
|
||||||
|
var util = require('util');
|
||||||
|
var assert = require('assert');
|
||||||
|
var MCIViewFactory = require('./mci_view_factory.js').MCIViewFactory;
|
||||||
|
|
||||||
|
exports.ViewController = ViewController;
|
||||||
|
|
||||||
|
function ViewController(client) {
|
||||||
|
events.EventEmitter.call(this);
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
this.client = client;
|
||||||
|
this.views = {}; // map of ID -> view
|
||||||
|
|
||||||
|
this.onClientKeyPress = function(key, isSpecial) {
|
||||||
|
if(isSpecial) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(self.focusedView && self.focusedView.acceptsInput) {
|
||||||
|
key = 'string' === typeof key ? key : key.toString();
|
||||||
|
self.focusedView.onKeyPress(key, isSpecial);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onClientSpecialKeyPress = function(keyName) {
|
||||||
|
if(self.focusedView && self.focusedView.acceptsInput) {
|
||||||
|
self.focusedView.onSpecialKeyPress(keyName);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.onViewAction = function(action) {
|
||||||
|
switch(action) {
|
||||||
|
case 'next' :
|
||||||
|
self.emit('action', { view : this, action : action });
|
||||||
|
self.nextFocus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'accepted' :
|
||||||
|
// :TODO: check if id is submit, etc.
|
||||||
|
self.nextFocus();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.attachClientEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(ViewController, events.EventEmitter);
|
||||||
|
|
||||||
|
ViewController.prototype.attachClientEvents = function() {
|
||||||
|
if(this.attached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.on('key press', this.onClientKeyPress);
|
||||||
|
this.client.on('special key', this.onClientSpecialKeyPress);
|
||||||
|
|
||||||
|
this.attached = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.detachClientEvents = function() {
|
||||||
|
if(!this.attached) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.client.removeListener('key press', this.onClientKeyPress);
|
||||||
|
this.client.removeListener('special key', this.onClientSpecialKeyPress);
|
||||||
|
|
||||||
|
this.attached = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.viewExists = function(id) {
|
||||||
|
return id in this.views;
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.addView = function(view) {
|
||||||
|
assert(!this.viewExists(view.id), 'View with ID ' + view.id + ' already exists');
|
||||||
|
|
||||||
|
this.views[view.id] = view;
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.getView = function(id) {
|
||||||
|
return this.views[id];
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.switchFocus = function(id) {
|
||||||
|
if(this.focusedView && this.focusedView.acceptsFocus) {
|
||||||
|
this.focusedView.setFocus(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
var view = this.getView(id);
|
||||||
|
if(view && view.acceptsFocus) {
|
||||||
|
this.focusedView = view;
|
||||||
|
this.focusedView.setFocus(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// :TODO: Probably log here
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.nextFocus = function() {
|
||||||
|
if(!this.focusedView) {
|
||||||
|
this.switchFocus(this.views[this.firstId].id);
|
||||||
|
} else {
|
||||||
|
var nextId = this.views[this.focusedView.id].nextId;
|
||||||
|
this.switchFocus(nextId);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.setViewOrder = function(order) {
|
||||||
|
var viewIdOrder = order || [];
|
||||||
|
|
||||||
|
if(0 === viewIdOrder.length) {
|
||||||
|
for(var id in this.views) {
|
||||||
|
viewIdOrder.push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
viewIdOrder.sort();
|
||||||
|
}
|
||||||
|
|
||||||
|
var view;
|
||||||
|
var count = viewIdOrder.length - 1;
|
||||||
|
for(var i = 0; i < count; ++i) {
|
||||||
|
this.views[viewIdOrder[i]].nextId = viewIdOrder[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
this.firstId = viewIdOrder[0];
|
||||||
|
var lastId = viewIdOrder[viewIdOrder.length - 1];
|
||||||
|
this.views[lastId].nextId = this.firstId;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
ViewController.prototype.loadFromMCIMap = function(mciMap) {
|
||||||
|
var factory = new MCIViewFactory(this.client);
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
Object.keys(mciMap).forEach(function onMciEntry(name) {
|
||||||
|
var mci = mciMap[name];
|
||||||
|
var view = factory.createFromMCI(mci);
|
||||||
|
|
||||||
|
if(view) {
|
||||||
|
view.on('action', self.onViewAction);
|
||||||
|
self.addView(view);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -9,6 +9,8 @@ var user = require('../core/user.js');
|
||||||
|
|
||||||
//var view = require('../core/view.js');
|
//var view = require('../core/view.js');
|
||||||
var textView = require('../core/text_view.js');
|
var textView = require('../core/text_view.js');
|
||||||
|
var editTextView = require('../core/edit_text_view.js');
|
||||||
|
var viewController = require('../core/view_controller.js');
|
||||||
|
|
||||||
exports.moduleInfo = {
|
exports.moduleInfo = {
|
||||||
name : 'Matrix',
|
name : 'Matrix',
|
||||||
|
@ -34,15 +36,49 @@ function entryPoint(client) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
var tv = new textView.TextView(client, {
|
var tv = new textView.TextView(client, {
|
||||||
position : [5, 5],
|
position : [5, 5],
|
||||||
text : 'Hello, World!',
|
text : 'Hello, World!',
|
||||||
textStyle : 'password',
|
textStyle : 'password',
|
||||||
maxLength : 10
|
maxLength : 10,
|
||||||
|
id : 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
tv.redraw();
|
tv.redraw();
|
||||||
|
|
||||||
|
var etv = new editTextView.EditTextView(client, {
|
||||||
|
position : [10, 10],
|
||||||
|
textStyle : 'upper',
|
||||||
|
maxLength : 20,
|
||||||
|
dimens : { width : 30 },
|
||||||
|
text : 'default',
|
||||||
|
color : { flags : 0, fg : 31, bg : 40 },
|
||||||
|
focusColor : { flags : 1, fg : 37, bg : 44 },
|
||||||
|
id : 2,
|
||||||
|
});
|
||||||
|
|
||||||
|
etv.redraw();*/
|
||||||
|
|
||||||
|
var vc = new viewController.ViewController(client);
|
||||||
|
vc.loadFromMCIMap(mci);
|
||||||
|
vc.setViewOrder();
|
||||||
|
vc.switchFocus(1);
|
||||||
|
//vc.addView(etv);
|
||||||
|
//vc.switchFocus(2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
client.on('key press', function onKp(key, isSpecial) {
|
||||||
|
key = 'string' === typeof key ? key : key.toString();
|
||||||
|
etv.onKeyPress(key, isSpecial);
|
||||||
|
});
|
||||||
|
|
||||||
|
client.on('special key', function onSK(keyName) {
|
||||||
|
etv.onSpecialKeyPress(keyName);
|
||||||
|
});
|
||||||
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
var vc = new view.ViewsController(client);
|
var vc = new view.ViewsController(client);
|
||||||
vc.loadFromMCIMap(mci);
|
vc.loadFromMCIMap(mci);
|
||||||
|
|
Loading…
Reference in New Issue