text: /*
   * JQuery zTree keyboard navigation extension
   * zTree v3.5.42 or later
   * http://www.xbrlquery.com/
   *
   * Copyright (c) 2019 Bill Seddon
   *
   * Licensed same as jquery - MIT License
   * http://www.opensource.org/licenses/mit-license.php
   *
   * Date: 2020-02-18
   */
  
  ( function ($) 
  {
  	/**
  	 * Creates a function that adds keyboard navigation:
  	 * Home: home key (keycode 36)				Goes to the first root element is visible
  	 * End: end key (keycode 35)				Goes to the last leaf node and will expand nodes and scroll the element into view
  	 * Down: right cursor key (keycode 39)		Goes to the next visible node in the tree following the hierarchy
  	 * Next: down cursor key (keycode 40)		Goes to the next visible node at the same level
  	 * Up: up cursor key (keycode 37)			Goes to the prior visible node at the same level
  	 * Previous: left cursor key (keycode 38)	Goes to the prior visible node following the hierarchy
  	 * Toggle: space key (keycode 32)			Toggles the expand/collapse state of a parent node
  	 */
  	$.fn.zTreeKeyboardNavigation = function(zTree, element)
  		{
  			if (typeof element === 'string' || element instanceof String)
  			{
  				element = $(element);
  			}
  
  			var rootNodes = zTree.getNodes();
  			if ( ! rootNodes ) return;
  
  			var focusSelectedNode = function()
  			{
  				if( ( selectedNodes = zTree.getSelectedNodes() ) && selectedNodes.length )
  				{
  					$("#" + selectedNodes[0].tId ).focus();
  				}
  			}
  
  			$(element).bind( 'keydown', function( e )
  				{
  					var selectedNodes = zTree.getSelectedNodes();
  					var selectedNode = selectedNodes.length ? selectedNodes[0] : null;
  
  					var processSpace = function()
  					{
  						// If there are no nodes or the selected node is not a parent, get out
  						if ( selectedNode && selectedNode.isParent )
  						{
  							// Toggle the node
  							zTree.expandNode( selectedNode, null, null, null, false );
  						}
  					}
  					
  					var processHome = function()
  					{
  						zTree.selectNode( rootNodes[0], false, true );
  					}
  
  					var processEnd = function()
  					{
  						var nodes = zTree.transformToArray(rootNodes);
  						// Select the last node
  						zTree.selectNode( nodes[ nodes.length - 1 ] );
  					}
  					
  					var processUp = function()
  					{
  						var priorNode;
  						if ( selectedNode )
  						{
  							priorNode = selectedNode.getPreNode();
  							if ( ! priorNode ) return;
  						}
  						else
  						{
  							processEnd();
  						}
  
  						if ( ! priorNode ) return;
  
  						zTree.selectNode( priorNode );
  					}
  
  					var processDown = function()
  					{
  						var nextNode;
  						if ( selectedNode )
  						{
  							nextNode = selectedNode.getNextNode();
  							if ( ! nextNode ) return;
  						}
  						else
  						{
  							processHome();
  						}
  
  						if ( ! nextNode ) return;
  
  						zTree.selectNode( nextNode );
  					}
  
  					var processOut = function()
  					{
  						if ( ! selectedNode ) return;
  
  						var parentNode = selectedNode.getParentNode();
  						var priorNode = selectedNode.getPreNode();
  						if ( ! parentNode && ! priorNode ) return; // Must have been the root node
  
  						if ( priorNode )
  						{
  							if ( priorNode.isParent )
  							{
  								// There is a prior node, now the the question is where is the last open node?
  								while ( priorNode )
  								{
  									if ( ! priorNode.isParent || ! priorNode.open || ! priorNode.children ) break;
  
  									priorNode = priorNode.children[ priorNode.children.length -1 ];
  								}
  
  								zTree.selectNode( priorNode );
  								return;
  							}
  							else
  							{
  								zTree.selectNode( priorNode );
  								return;
  							}
  						}
  
  						// Find the parent node with a valid prior sibling
  						if ( parentNode )
  						{
  							// This call should be silent otherwise (in my view a bug in) 
  							// selectNode causes the root node to blur
  							zTree.selectNode( parentNode, false, true );
  						}						
  					}
  
  					var processIn = function()
  					{
  						if ( ! selectedNode ) return;
  
  						if ( selectedNode.isParent && selectedNode.open && selectedNode.children )
  						{
  							zTree.selectNode( selectedNode.children[0] );
  							return;
  						}
  
  						var nextNode = selectedNode.getNextNode();
  						if ( nextNode )
  						{
  							zTree.selectNode( nextNode );
  						}
  						else
  						{
  							// Cannot be root if there is a selected node that is not a parent
  							var node = selectedNode;
  							// Find the parent node with a valid next sibling
  							while( node = node.getParentNode() )
  							{
  								var nextNode = node.getNextNode();
  								if ( nextNode )
  								{
  									zTree.selectNode( nextNode );
  									break;
  								}
  							}
  						}
  					}
  
  					var processLetter = function( keyCode )
  					{
  						if ( ! Array.from( {length: 26}, (v, i) => i + 65 ).includes( keyCode & 95 ) ) return false;
  
  						var nodes = zTree.transformToArray(rootNodes);
  						nodes = nodes.filter( node => 
  						{
  							return 'accesskey' in node &&  node.accesskey.length && ( node.accesskey.charCodeAt(0) & 95 ) == keyCode;
  						} );
  						
  						if ( ! nodes.length ) return false;
  						
  						var selectedNodes = zTree.getSelectedNodes();
  						if ( ! selectedNodes.length ) return false;
  
  						if ( selectedNodes[0] == nodes[0] ) return false;
  
  						zTree.selectNode( nodes[0] );
  
  						return true;
  					}
  
  					// console.log('before');
  					// console.log(document.activeElement);
  
  					switch ( e.keyCode )
  					{
  						case 32: /* Toggle parent nodes */
  							processSpace();
  							return;
  
  						case 36: /* Home - go to the root node */
  							processHome();
  							break;
  
  						case 35: /* End - go to the last node */ 
  							processEnd();
  							break;
  
  						case 33: /* PageUp */
  							// Do nothing
  							break;
  
  						case 34: /* PageDown */ 
  							// Do nothing
  							break;
  
  						case 37: /* Left */
  							processOut();
  							break;
  
  						case 38: /* Up */
  							processUp();
  							break;
  
  						case 39: /* Right */
  							processIn();
  							break;
  
  						case 40: /* Down */ 
  							processDown();
  							break;
  
  						default:
  							if ( ! processLetter( e.keyCode & 95 ) ) return;
  							break;
  					}
  
  					// console.log('after');
  					// console.log(document.activeElement);
  					focusSelectedNode();
  				} );
  
  			$(element).trigger({ type : 'keydown', which : 36, keyCode: 36 });
  			focusSelectedNode();
  		}
  
  } )(jQuery);