294 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			294 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /**
 | |
|  **      ==============================
 | |
|  **       O           O      O   OOOO
 | |
|  **       O           O     O O  O   O
 | |
|  **       O           O     O O  O   O
 | |
|  **       OOOO   OOOO O     OOO  OOOO
 | |
|  **       O   O       O    O   O O   O
 | |
|  **       O   O       O    O   O O   O
 | |
|  **       OOOO        OOOO O   O OOOO
 | |
|  **      ==============================
 | |
|  **      Dr. Stefan Bosse http://www.bsslab.de
 | |
|  **
 | |
|  **      COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED
 | |
|  **                 BY THE AUTHOR(S).
 | |
|  **                 THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED,
 | |
|  **                 MODIFIED, OR OTHERWISE USED IN A CONTEXT
 | |
|  **                 OUTSIDE OF THE SOFTWARE SYSTEM.
 | |
|  **
 | |
|  **    $AUTHORS:     Christopher Jeffrey, Stefan Bosse
 | |
|  **    $INITIAL:     (C) 2013-2015, Christopher Jeffrey and contributors
 | |
|  **    $MODIFIED:    by sbosse
 | |
|  **    $REVESIO:     1.2.1
 | |
|  **
 | |
|  **    $INFO:
 | |
|  **
 | |
|  **    form.js - form element for blessed
 | |
|  **
 | |
|  **    $ENDOFINFO
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * Modules
 | |
|  */
 | |
| var Comp = Require('com/compat');
 | |
| 
 | |
| var Node = Require('term/widgets/node');
 | |
| var Box = Require('term/widgets/box');
 | |
| 
 | |
| /**
 | |
|  * Form
 | |
|  */
 | |
| 
 | |
| function Form(options) {
 | |
|   var self = this;
 | |
| 
 | |
|   if (!instanceOf(this,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;
 | |
| inheritPrototype(Form,Box),
 | |
| 
 | |
| 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 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;
 |