enigma-bbs/core/view.js

191 lines
4.7 KiB
JavaScript
Raw Normal View History

2014-10-17 04:03:32 +00:00
/* jslint node: true */
'use strict';
2014-10-22 05:12:44 +00:00
var events = require('events');
2014-10-17 04:03:32 +00:00
var util = require('util');
2014-10-20 03:06:39 +00:00
var assert = require('assert');
2014-10-22 05:12:44 +00:00
var ansi = require('./ansi_term.js');
var _ = require('lodash');
2014-10-17 04:03:32 +00:00
exports.View = View;
exports.VIEW_SPECIAL_KEY_MAP_DEFAULT = VIEW_SPECIAL_KEY_MAP_DEFAULT;
2014-10-20 03:06:39 +00:00
2014-10-22 05:12:44 +00:00
var VIEW_SPECIAL_KEY_MAP_DEFAULT = {
accept : [ 'enter' ],
2014-10-20 03:06:39 +00:00
exit : [ 'esc' ],
backspace : [ 'backspace', 'del' ],
2014-10-22 05:12:44 +00:00
del : [ 'del' ],
2014-10-20 03:06:39 +00:00
next : [ 'tab' ],
2014-11-01 15:50:11 +00:00
up : [ 'up arrow' ],
down : [ 'down arrow' ],
2014-10-20 03:06:39 +00:00
};
function View(options) {
2014-10-22 05:12:44 +00:00
events.EventEmitter.call(this);
2014-10-20 03:06:39 +00:00
assert(_.isObject(options));
assert(_.isObject(options.client));
2014-10-20 03:06:39 +00:00
2014-10-22 05:12:44 +00:00
var self = this;
2014-10-20 03:06:39 +00:00
this.client = options.client;
2014-10-20 05:30:44 +00:00
this.cursor = options.cursor || 'show';
this.acceptsFocus = options.acceptsFocus || false;
this.acceptsInput = options.acceptsInput || false;
2014-10-20 05:30:44 +00:00
//this.submit = this.acceptsInput ? options.acceptsInput || false : false;
2014-10-22 05:12:44 +00:00
this.position = { x : 0, y : 0 };
this.dimens = { height : 1, width : 0 };
2014-10-20 03:06:39 +00:00
this.textStyle = options.textStyle || 'normal';
this.focusTextStyle = options.focusTextStyle || this.textStyle;
2015-04-08 05:15:34 +00:00
if(options.id) {
this.setId(options.id);
}
if(options.position) {
this.setPosition(options.position);
2014-10-20 03:06:39 +00:00
}
2015-04-08 05:15:34 +00:00
// this.isPasswordTextStyle = 'P' === this.textStyle || 'password' === this.textStyle;
// :TODO: Don't allow width/height > client.term
if(options.dimens && options.dimens.height) {
this.dimens.height = options.dimens.height;
2014-10-20 03:06:39 +00:00
}
if(options.dimens && options.dimens.width) {
this.dimens.width = options.dimens.width;
2014-10-20 03:06:39 +00:00
}
this.color = options.color || { flags : 0, fg : 7, bg : 0 };
this.focusColor = options.focusColor || this.color;
2014-10-20 03:06:39 +00:00
2014-10-22 05:12:44 +00:00
if(this.acceptsInput) {
this.specialKeyMap = options.specialKeyMap || VIEW_SPECIAL_KEY_MAP_DEFAULT;
2014-10-20 03:06:39 +00:00
}
this.isSpecialKeyMapped = function(keySet, keyName) {
return this.specialKeyMap[keySet].indexOf(keyName) > -1;
};
this.getANSIColor = function(color) {
var sgr = [ color.flags, color.fg ];
if(color.bg !== color.flags) {
sgr.push(color.bg);
}
return ansi.sgr(sgr);
};
2014-10-20 03:06:39 +00:00
}
2014-10-22 05:12:44 +00:00
util.inherits(View, events.EventEmitter);
2014-10-20 05:30:44 +00:00
View.prototype.setId = function(id) {
this.id = id;
};
2014-10-20 05:30:44 +00:00
View.prototype.getId = function() {
return this.id;
};
2014-10-22 05:12:44 +00:00
View.prototype.setPosition = function(pos) {
//
// We allow [x, y], { x : x, y : y }, or (x, y)
//
if(util.isArray(pos)) {
this.position.x = pos[0];
this.position.y = pos[1];
} else if(pos.x && pos.y) {
this.position.x = pos.x;
this.position.y = pos.y;
} else if(2 === arguments.length) {
this.position.x = parseInt(arguments[0], 10);
this.position.y = parseInt(arguments[1], 10);
2014-10-20 03:06:39 +00:00
}
assert(!(isNaN(this.position.x)));
assert(!(isNaN(this.position.y)));
2014-10-20 03:06:39 +00:00
assert(
this.position.x > 0 && this.position.x <= this.client.term.termHeight,
'X position ' + this.position.x + ' out of terminal range ' + this.client.term.termHeight);
assert(
this.position.y > 0 && this.position.y <= this.client.term.termWidth,
'Y position ' + this.position.y + ' out of terminal range ' + this.client.term.termWidth);
2014-10-20 03:06:39 +00:00
};
View.prototype.setColor = function(color, bgColor, flags) {
if(_.isObject(color)) {
assert(_.has(color, 'fg'));
assert(_.has(color, 'bg'));
assert(_.has(color, 'flags'));
this.color = color;
} else {
if(color) {
this.color.fg = color;
}
if(bgColor) {
this.color.bg = bgColor;
}
if(_.isNumber(flags)) {
this.color.flags = flags;
}
}
// allow strings such as 'red', 'black', etc. to be passed
if(_.isString(this.color.fg)) {
this.color.fg = ansi.getFGColorValue(this.color.fg);
}
if(_.isString(this.color.bg)) {
this.color.bg = ansi.getBGColorValue(this.color.bg);
}
};
2014-10-22 05:12:44 +00:00
View.prototype.getColor = function() {
return this.color;
2014-10-20 05:30:44 +00:00
};
2014-10-22 05:12:44 +00:00
View.prototype.getFocusColor = function() {
return this.focusColor;
2014-10-20 03:06:39 +00:00
};
2014-10-22 05:12:44 +00:00
View.prototype.redraw = function() {
this.client.term.write(ansi.goto(this.position.x, this.position.y));
2014-10-20 03:06:39 +00:00
};
2014-10-22 05:12:44 +00:00
View.prototype.setFocus = function(focused) {
assert(this.acceptsFocus, 'View does not accept focus');
2014-10-20 03:06:39 +00:00
2014-10-22 05:12:44 +00:00
this.hasFocus = focused;
this.client.term.write('show' === this.cursor ? ansi.showCursor() : ansi.hideCursor());
};
View.prototype.onKeyPress = function(key, isSpecial) {
assert(this.hasFocus, 'View does not have focus');
assert(this.acceptsInput, 'View does not accept input');
};
View.prototype.onSpecialKeyPress = function(keyName) {
assert(this.hasFocus, 'View does not have focus');
assert(this.acceptsInput, 'View does not accept input');
assert(this.specialKeyMap, 'No special key map defined');
if(this.isSpecialKeyMapped('accept', keyName)) {
this.emit('action', 'accept');
} else if(this.isSpecialKeyMapped('next', keyName)) {
this.emit('action', 'next');
}
};
View.prototype.getData = function() {
2014-10-20 03:06:39 +00:00
};