From c0a03234753dbcace3021d0a19d5ea11bdefba49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Ronvel?= Date: Thu, 18 Feb 2021 21:15:18 +0100 Subject: [PATCH] Now Node.js v14 is required ; ColumnMenu now supports submenu (still beta) (#151) --- CHANGELOG | 7 ++ lib/document/BaseMenu.js | 112 ++++++++++++++++++-- lib/document/ColumnMenu.js | 89 +--------------- lib/terminfo/terminfo.js | 6 +- package.json | 2 +- sample/document/column-menu-submenu-test.js | 2 + sample/document/column-menu-test.js | 2 +- 7 files changed, 123 insertions(+), 97 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 8f78f559..8fc03759 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,11 @@ +v1.49.0 +------- + +Now Node.js v14 is required +ColumnMenu now supports submenu (still beta) (#151) + + v1.48.1 ------- diff --git a/lib/document/BaseMenu.js b/lib/document/BaseMenu.js index 7f1f8329..511a747e 100644 --- a/lib/document/BaseMenu.js +++ b/lib/document/BaseMenu.js @@ -73,14 +73,14 @@ function BaseMenu( options = {} ) { // Things to clear or to force internal: true , parent: null , - items: null , - x: undefined , outputX: undefined , - y: undefined , outputY: undefined , + items: null + //x: undefined , outputX: undefined , + //y: undefined , outputY: undefined , //width: undefined , outputWidth: undefined , //height: undefined , outputHeight: undefined , //submenu: false } ) ; - + if ( options.submenu && typeof options.submenu === 'object' ) { Object.assign( this.submenuOptions , options.submenu ) ; } @@ -90,6 +90,7 @@ function BaseMenu( options = {} ) { this.onButtonToggle = this.onButtonToggle.bind( this ) ; this.onButtonFocus = this.onButtonFocus.bind( this ) ; this.onButtonBlinked = this.onButtonBlinked.bind( this ) ; + this.onSubmenuSubmit = this.onSubmenuSubmit.bind( this ) ; this.onKey = this.onKey.bind( this ) ; this.onWheel = this.onWheel.bind( this ) ; this.onFocus = this.onFocus.bind( this ) ; @@ -286,6 +287,20 @@ BaseMenu.prototype.onKey = function( key , trash , data ) { this.toPage( this.maxPage , 'cycle' ) ; } break ; + case 'parentMenu' : + if ( this.isSubmenu ) { + // Back up the parent, because current instance can be destroyed by parent.closeSubmenu() + let parent = this.parent ; + if ( this.parent.submenuOptions.hideParent ) { this.parent.closeSubmenu() ; } + parent.document.giveFocusTo( parent ) ; + } + break ; + case 'submenu' : + if ( this.hasSubmenu && this.focusChild?.def?.items ) { + this.openSubmenu( this.focusChild.value , this.focusChild ) ; + if ( this.submenu ) { this.document.giveFocusTo( this.submenu ) ; } + } + break ; default : return ; // Bubble up } @@ -330,7 +345,7 @@ BaseMenu.prototype.onButtonSubmit = function( buttonValue , action , button ) { if ( this.submenuOptions.openOn === 'parentSubmit' ) { this.openSubmenu( button.value , button ) ; } - + if ( this.submenu ) { this.document.giveFocusTo( this.submenu ) ; } @@ -378,6 +393,92 @@ BaseMenu.prototype.onButtonFocus = function( focus , type , button ) { +BaseMenu.prototype.onSubmenuSubmit = function( buttonValue , action , button ) { + button.once( 'blinked' , ( buttonValue_ , reserved , button_ ) => { + if ( this.submenuOptions.closeOn === 'childSubmit' ) { + this.closeSubmenu() ; + this.document.giveFocusTo( this.submenuParentButton || this ) ; + } + this.emit( 'blinked' , buttonValue_ , reserved , this ) ; + } ) ; + + this.emit( 'submit' , buttonValue , action , this ) ; +} ; + + + +// Userland: .submenu( itemValue ) +// Internal: .submenu( itemValue , button ) +BaseMenu.prototype.openSubmenu = function( itemValue , button = null ) { + var x , y , width , height , + itemDef = button ? this.itemsDef.find( it => it === button.def ) : + this.itemsDef.find( it => it.value === itemValue ) ; + + if ( ! itemDef || ! itemDef.items || ! itemDef.items.length ) { return ; } + + if ( this.submenu ) { + if ( this.submenu.def === itemDef ) { return ; } + this.closeSubmenu() ; + } + + this.submenuParentButton = button ; + + switch ( this.submenuOptions.disposition ) { + case 'overwrite' : + x = this.outputX ; + y = this.outputY ; + //width = this.outputWidth ; + width = this.submenuOptions.width ; + //height = this.outputHeight ; + height = this.submenuOptions.height ; + break ; + case 'right' : + default : + x = this.outputX + this.outputWidth ; + y = this.outputY ; + width = this.submenuOptions.width || this.outputWidth ; + break ; + } + + if ( this.submenuOptions.hideParent ) { + this.children.forEach( e => e.hidden = true ) ; + } + + //this.submenu = new ColumnMenu( Object.assign( {} , this.submenuOptions , { + this.submenu = new this.constructor( Object.assign( {} , this.submenuOptions , { + internal: true , + parent: this , + isSubmenu: true , + def: itemDef , + outputX: x , + outputY: y , + outputWidth: width , + outputHeight: height , + items: itemDef.items , + noDraw: true + } ) ) ; + + this.redraw() ; + + if ( this.submenuOptions.focusOnOpen ) { + this.document.giveFocusTo( this.submenu ) ; + } + + this.submenu.on( 'submit' , this.onSubmenuSubmit ) ; +} ; + + + +BaseMenu.prototype.closeSubmenu = function() { + if ( ! this.submenu ) { return false ; } + if ( this.submenuOptions.hideParent ) { this.children.forEach( e => e.hidden = false ) ; } + this.submenu.destroy() ; + this.submenu = null ; + return true ; +} ; + + + // Should be redefined in the derivative class BaseMenu.prototype.defaultOptions = {} ; BaseMenu.prototype.keyBindings = {} ; @@ -387,6 +488,5 @@ BaseMenu.prototype.toggleButtonKeyBindings = {} ; BaseMenu.prototype.toggleButtonActionKeyBindings = {} ; BaseMenu.prototype.initPage = function() {} ; BaseMenu.prototype.onButtonToggle = function() {} ; -BaseMenu.prototype.submenu = function() {} ; BaseMenu.prototype.childUseParentKeyValue = false ; diff --git a/lib/document/ColumnMenu.js b/lib/document/ColumnMenu.js index a406f846..00d47ea4 100644 --- a/lib/document/ColumnMenu.js +++ b/lib/document/ColumnMenu.js @@ -42,7 +42,6 @@ function ColumnMenu( options ) { options = ! options ? {} : options.internal ? options : Object.create( options ) ; options.internal = true ; - this.onSubmenuSubmit = this.onSubmenuSubmit.bind( this ) ; this.onParentResize = this.onParentResize.bind( this ) ; // Overwritten by Element() when .autoWidth is set @@ -135,7 +134,9 @@ ColumnMenu.prototype.keyBindings = { // ENTER: 'submit' , // KP_ENTER: 'submit' , ALT_ENTER: 'submit' , - ESC: 'parent' + ESC: 'parentMenu' , + LEFT: 'parentMenu' , + RIGHT: 'submenu' } ; ColumnMenu.prototype.buttonKeyBindings = { @@ -430,90 +431,6 @@ ColumnMenu.prototype.initPage = function( page = this.page ) { -// Userland: .submenu( itemValue ) -// Internal: .submenu( itemValue , button ) -ColumnMenu.prototype.openSubmenu = function( itemValue , button = null ) { - var x , y , width , height , - itemDef = button ? this.itemsDef.find( it => it === button.def ) : - this.itemsDef.find( it => it.value === itemValue ) ; - - if ( ! itemDef || ! itemDef.items || ! itemDef.items.length ) { return ; } - - if ( this.submenu ) { - if ( this.submenu.def === itemDef ) { return ; } - else { this.closeSubmenu() ; } - } - - this.submenuParentButton = button ; - - switch ( this.submenuOptions.disposition ) { - case 'overwrite' : - x = this.outputX ; - y = this.outputY ; - width = this.outputWidth ; - height = this.outputHeight ; - break ; - case 'right' : - default : - x = this.outputX + this.outputWidth ; - y = this.outputY ; - width = this.submenuOptions.width || this.outputWidth ; - break ; - } - - if ( this.submenuOptions.hideParent ) { - this.children.forEach( e => e.hidden = true ) ; - } - - this.submenu = new ColumnMenu( Object.assign( {} , this.submenuOptions , { - internal: true , - parent: this , - isSubmenu: true , - def: itemDef , - outputX: x , - outputY: y , - outputWidth: width , - outputHeight: height , - items: itemDef.items , - noDraw: true - } ) ) ; - - this.redraw() ; - - if ( this.submenuOptions.focusOnOpen ) { - this.document.giveFocusTo( this.submenu ) ; - } - - this.submenu.on( 'submit' , this.onSubmenuSubmit ) ; -} ; - - - -ColumnMenu.prototype.closeSubmenu = function() { - if ( ! this.submenu ) { return false ; } - this.submenu.destroy() ; - this.submenu = null ; - return true ; -} ; - - - -ColumnMenu.prototype.onSubmenuSubmit = function( buttonValue , action , button ) { - button.once( 'blinked' , ( buttonValue_ , reserved , button_ ) => { - if ( this.submenuOptions.hideParent ) { this.children.forEach( e => e.hidden = false ) ; } - if ( this.submenuOptions.closeOn === 'childSubmit' ) { - this.closeSubmenu() ; - this.document.giveFocusTo( this.submenuParentButton || this ) ; - //this.document.giveFocusTo( this ) ; - } - this.emit( 'blinked' , buttonValue_ , reserved , this ) ; - } ) ; - - this.emit( 'submit' , buttonValue , action , this ) ; -} ; - - - ColumnMenu.prototype.onParentResize = function() { if ( ! this.autoWidth && ! this.autoHeight ) { return ; } diff --git a/lib/terminfo/terminfo.js b/lib/terminfo/terminfo.js index 5c1382ca..c0255b28 100644 --- a/lib/terminfo/terminfo.js +++ b/lib/terminfo/terminfo.js @@ -100,7 +100,7 @@ function getTerminfoBuffer( termName ) { function parseTermBuffer( bufPair , termName ) { - var i , getInt , intSize , + var i , j , getInt , intSize , buf = bufPair.buf , offset = 0 ; @@ -148,8 +148,8 @@ function parseTermBuffer( bufPair , termName ) { } */ - boolOptions.forEach( ( opt , i ) => { - result[opt] = Boolean( buf.readInt8( offset + i ) ) ; + boolOptions.forEach( ( opt , j ) => { + result[ opt ] = Boolean( buf.readInt8( offset + j ) ) ; } ) ; offset += result.boolSize ; diff --git a/package.json b/package.json index 038cba23..b315c6a9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "terminal-kit", - "version": "1.48.1", + "version": "1.49.0", "description": "256 colors, keys and mouse, input field, progress bars, screen buffer (including 32-bit composition and image loading), text buffer, and many more... Whether you just need colors and styles, build a simple interactive command line tool or a complexe terminal app: this is the absolute terminal lib for Node.js!", "main": "lib/termkit.js", "directories": { diff --git a/sample/document/column-menu-submenu-test.js b/sample/document/column-menu-submenu-test.js index 15478091..01fc86bf 100755 --- a/sample/document/column-menu-submenu-test.js +++ b/sample/document/column-menu-submenu-test.js @@ -57,8 +57,10 @@ var columnMenu = new termkit.ColumnMenu( { disposition: 'overwrite' , hideParent: true , openOn: 'parentBlinked' , + closeOn: 'childSubmit' , focusOnOpen: true , //*/ + //* disposition: 'right' , hideParent: false , diff --git a/sample/document/column-menu-test.js b/sample/document/column-menu-test.js index 9f8ffc47..32a67b86 100755 --- a/sample/document/column-menu-test.js +++ b/sample/document/column-menu-test.js @@ -124,7 +124,7 @@ var submitCount = 0 , focusCount = 0 ; function onSubmit( buttonValue , action ) { //console.error( 'Submitted: ' , value ) ; - if ( buttonValue === 'view' ) { columnMenu.setItem( buttonValue , { content: 'bob' } ) ; } + //if ( buttonValue === 'view' ) { columnMenu.setItem( buttonValue , { content: 'bob' } ) ; } term.saveCursor() ; term.moveTo.styleReset.eraseLine( 1 , 22 , 'Submitted #%i: %s %s\n' , submitCount ++ , buttonValue , action ) ;