neo-blessed/lib/widgets/form.js

271 lines
6.0 KiB
JavaScript

/**
* form.js - form element for blessed
* Copyright (c) 2013-2015, Christopher Jeffrey and contributors (MIT License).
* https://github.com/chjj/blessed
*/
/**
* Modules
*/
var helpers = require('../helpers');
var Node = require('./node');
var Box = require('./box');
/**
* Form
*/
function Form(options) {
var self = this;
if (!(this instanceof Node)) {
return new Form(options);
}
options = options || {};
options.ignoreKeys = true;
Box.call(this, options);
if (options.keys) {
this.screen._listenKeys(this);
this.on('element keypress', function(el, ch, key) {
if ((key.name === 'tab' && !key.shift)
|| (el.type === 'textbox' && options.autoNext && key.name === 'enter')
|| key.name === 'down'
|| (options.vi && key.name === 'j')) {
if (el.type === 'textbox' || el.type === 'textarea') {
if (key.name === 'j') return;
if (key.name === 'tab') {
// Workaround, since we can't stop the tab from being added.
el.emit('keypress', null, { name: 'backspace' });
}
el.emit('keypress', '\x1b', { name: 'escape' });
}
self.focusNext();
return;
}
if ((key.name === 'tab' && key.shift)
|| key.name === 'up'
|| (options.vi && key.name === 'k')) {
if (el.type === 'textbox' || el.type === 'textarea') {
if (key.name === 'k') return;
el.emit('keypress', '\x1b', { name: 'escape' });
}
self.focusPrevious();
return;
}
if (key.name === 'escape') {
self.focus();
return;
}
});
}
}
Form.prototype.__proto__ = Box.prototype;
Form.prototype.type = 'form';
Form.prototype._refresh = function() {
// XXX Possibly remove this if statement and refresh on every focus.
// Also potentially only include *visible* focusable elements.
// This would remove the need to check for _selected.visible in previous()
// and next().
if (!this._children) {
var out = [];
this.children.forEach(function fn(el) {
if (el.keyable) out.push(el);
el.children.forEach(fn);
});
this._children = out;
}
};
Form.prototype._visible = function() {
return !!this._children.filter(function(el) {
return el.visible;
}).length;
};
Form.prototype.next = function() {
this._refresh();
if (!this._visible()) return;
if (!this._selected) {
this._selected = this._children[0];
if (!this._selected.visible) return this.next();
if (this.screen.focused !== this._selected) return this._selected;
}
var i = this._children.indexOf(this._selected);
if (!~i || !this._children[i + 1]) {
this._selected = this._children[0];
if (!this._selected.visible) return this.next();
return this._selected;
}
this._selected = this._children[i + 1];
if (!this._selected.visible) return this.next();
return this._selected;
};
Form.prototype.previous = function() {
this._refresh();
if (!this._visible()) return;
if (!this._selected) {
this._selected = this._children[this._children.length - 1];
if (!this._selected.visible) return this.previous();
if (this.screen.focused !== this._selected) return this._selected;
}
var i = this._children.indexOf(this._selected);
if (!~i || !this._children[i - 1]) {
this._selected = this._children[this._children.length - 1];
if (!this._selected.visible) return this.previous();
return this._selected;
}
this._selected = this._children[i - 1];
if (!this._selected.visible) return this.previous();
return this._selected;
};
Form.prototype.focusNext = function() {
var next = this.next();
if (next) next.focus();
};
Form.prototype.focusPrevious = function() {
var previous = this.previous();
if (previous) previous.focus();
};
Form.prototype.resetSelected = function() {
this._selected = null;
};
Form.prototype.focusFirst = function() {
this.resetSelected();
this.focusNext();
};
Form.prototype.focusLast = function() {
this.resetSelected();
this.focusPrevious();
};
Form.prototype.submit = function() {
var self = this
, out = {};
this.children.forEach(function fn(el) {
if (el.value != null) {
var name = el.name || el.type;
if (Array.isArray(out[name])) {
out[name].push(el.value);
} else if (out[name]) {
out[name] = [out[name], el.value];
} else {
out[name] = el.value;
}
}
el.children.forEach(fn);
});
this.emit('submit', out);
return this.submission = out;
};
Form.prototype.cancel = function() {
this.emit('cancel');
};
Form.prototype.reset = function() {
this.children.forEach(function fn(el) {
switch (el.type) {
case 'screen':
break;
case 'box':
break;
case 'text':
break;
case 'line':
break;
case 'scrollable-box':
break;
case 'list':
el.select(0);
return;
case 'form':
break;
case 'input':
break;
case 'textbox':
el.clearInput();
return;
case 'textarea':
el.clearInput();
return;
case 'button':
delete el.value;
break;
case 'progress-bar':
el.setProgress(0);
break;
case 'file-manager':
el.refresh(el.options.cwd);
return;
case 'checkbox':
el.uncheck();
return;
case 'radio-set':
break;
case 'radio-button':
el.uncheck();
return;
case 'prompt':
break;
case 'question':
break;
case 'message':
break;
case 'info':
break;
case 'loading':
break;
case 'list-bar':
//el.select(0);
break;
case 'dir-manager':
el.refresh(el.options.cwd);
return;
case 'terminal':
el.write('');
return;
case 'image':
//el.clearImage();
return;
}
el.children.forEach(fn);
});
this.emit('reset');
};
/**
* Expose
*/
module.exports = Form;