forked from Botanical/BotanJS
		
	
		
			
				
	
	
		
			172 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			172 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| (function(){
 | |
| 	var ns = __namespace( "Components.Vim" );
 | |
| 
 | |
| 	/** @type {Dandelion.IDOMElement} */
 | |
| 	var IDOMElement                             = __import( "Dandelion.IDOMElement" );
 | |
| 	/** @type {System.utils.DataKey} */
 | |
| 	var DataKey                                 = __import( "System.utils.DataKey" );
 | |
| 	/** @type {System.Cycle} */
 | |
| 	var Cycle                                   = __import( "System.Cycle" );
 | |
| 	/** @type {System.Debug} */
 | |
| 	var debug                                   = __import( "System.Debug" );
 | |
| 
 | |
| 	/** @type {Components.Vim.State.Registers} */
 | |
| 	var Registers                                 = __import( "Components.Vim.State.Registers" );
 | |
| 	/** @type {Components.Vim.Syntax.Analyzer} */
 | |
| 	var SyntaxAnalyzer                            = __import( "Components.Vim.Syntax.Analyzer" );
 | |
| 
 | |
| 	/** @type {Components.Vim.LineFeeder} */
 | |
| 	var LineFeeder = ns[ NS_INVOKE ]( "LineFeeder" );
 | |
| 	/** @type {Components.Vim.StatusBar} */
 | |
| 	var StatusBar = ns[ NS_INVOKE ]( "StatusBar" );
 | |
| 
 | |
| 	var VimControls = ns[ NS_INVOKE ]( "Controls" );
 | |
| 	var InputEvent = ns[ NS_INVOKE ]( "InputEvent" );
 | |
| 	var mesg = ns[ NS_INVOKE ]( "Message" );
 | |
| 
 | |
| 	var Insts = [];
 | |
| 
 | |
| 	var KeyHandler = function( sender, handler )
 | |
| 	{
 | |
| 		return function( e )
 | |
| 		{
 | |
| 			e = e || window.event;
 | |
| 			if ( e.keyCode ) code = e.keyCode;
 | |
| 			else if ( e.which ) code = e.which;
 | |
| 
 | |
| 			handler( sender, new InputEvent( sender, e ) );
 | |
| 		};
 | |
| 	};
 | |
| 
 | |
| 	/* stage @param {Dandelion.IDOMElement} */
 | |
| 	var VimArea = function( stage )
 | |
| 	{
 | |
| 		if( !stage ) return;
 | |
| 
 | |
| 		var element = stage.element;
 | |
| 
 | |
| 		if( element.nodeName != "TEXTAREA" )
 | |
| 		{
 | |
| 			debug.Error( "Element is not compatible for VimArea" );
 | |
| 			return;
 | |
| 		}
 | |
| 
 | |
| 		stage.setAttribute( new DataKey( "vimarea", 1 ) );
 | |
| 
 | |
| 		this.stage = stage;
 | |
| 		this.rows = element.rows;
 | |
| 		this.cols = element.cols;
 | |
| 
 | |
| 		this.__active = false;
 | |
| 
 | |
| 		var _self = this;
 | |
| 
 | |
| 		stage.addEventListener( "Focus", function() { _self.__active = true; } );
 | |
| 		stage.addEventListener( "Blur", function() { _self.__active = false; } );
 | |
| 
 | |
| 		// Init
 | |
| 		this.VisualizeVimFrame( element.value );
 | |
| 
 | |
| 		// Push this instance
 | |
| 		Insts.push( this );
 | |
| 	};
 | |
| 
 | |
| 	VimArea.prototype.select = function( sel )
 | |
| 	{
 | |
| 		if( !this.__active ) return;
 | |
| 		var textarea = this.stage.element;
 | |
| 
 | |
| 		if( sel )
 | |
| 		{
 | |
| 			textarea.selectionStart = sel.start;
 | |
| 			textarea.selectionEnd = sel.end;
 | |
| 		}
 | |
| 	};
 | |
| 
 | |
| 	VimArea.prototype.VisualizeVimFrame = function( content )
 | |
| 	{
 | |
| 		var _self = this;
 | |
| 
 | |
| 		var element = this.stage.element;
 | |
| 		var r = this.rows;
 | |
| 		var c = this.cols;
 | |
| 
 | |
| 		// StatusFeeder always consumes at least 1 line
 | |
| 		var cRange = r - 1;
 | |
| 
 | |
| 		// Content feeder
 | |
| 		var cfeeder = new LineFeeder( cRange, c );
 | |
|         var contentAnalyzer = new SyntaxAnalyzer( cfeeder );
 | |
| 
 | |
| 		// Feed the contents to content feeder
 | |
| 		// This "\n" fixes the last line "\n" not displaying
 | |
| 		// it will be trimmed after saving
 | |
| 		cfeeder.init( content + "\n" );
 | |
| 
 | |
| 		// Status can consumes up to full screen, I think
 | |
| 		sfeeder = new LineFeeder( r, c );
 | |
| 		sfeeder.setRender( false );
 | |
| 
 | |
| 		// Set the Vim instance
 | |
| 		cfeeder.cursor.Vim = this;
 | |
| 		sfeeder.cursor.Vim = this;
 | |
| 
 | |
| 		// Set the stamps
 | |
| 		var statusBar = new StatusBar( c );
 | |
| 		statusBar.stamp( -18, function(){ return cfeeder.lineStat; } );
 | |
| 		statusBar.stamp( -3, function(){ return mesg( cfeeder.docPos ); } );
 | |
| 		statusBar.stamp( 0, function(){ return cfeeder.cursor.message; } );
 | |
| 
 | |
| 		sfeeder.init( statusBar.statusText );
 | |
| 
 | |
| 		var Update = function()
 | |
| 		{
 | |
| 			sfeeder.init( statusBar.statusText );
 | |
| 
 | |
| 			element.value =
 | |
| 				cfeeder.render( 0, r - sfeeder.linesOccupied )
 | |
| 				+ "\n" + sfeeder.render();
 | |
| 
 | |
| 			_self.__blink = false;
 | |
| 			_self.select( cfeeder.cursor.position );
 | |
| 		};
 | |
| 
 | |
| 		cfeeder.dispatcher.addEventListener( "VisualUpdate", Update );
 | |
| 		Update();
 | |
| 
 | |
| 		this.contentFeeder = cfeeder;
 | |
|         this.contentAnalyzer = contentAnalyzer;
 | |
| 		this.statusFeeder = sfeeder;
 | |
| 		this.statusBar = statusBar;
 | |
| 		this.registers = new Registers();
 | |
| 
 | |
| 		this.__cursor = cfeeder.cursor;
 | |
| 
 | |
| 		this.__blink = true;
 | |
| 		Cycle.perma( "VimCursorBlinkCycle" + element.id, function()
 | |
| 		{
 | |
| 			_self.select(
 | |
| 				!_self.__cursor.blink || ( _self.__blink = !_self.__blink )
 | |
| 					? _self.__cursor.position
 | |
| 					: { start: 0, end: 0 }
 | |
| 			);
 | |
| 		}, 600 );
 | |
| 
 | |
| 		var controls = new VimControls( this );
 | |
| 		this.stage.addEventListener(
 | |
| 			"KeyDown"
 | |
| 			, KeyHandler( this, controls.handler.bind( controls ) )
 | |
| 		);
 | |
| 	};
 | |
| 
 | |
| 	__readOnly( VimArea, "Instances", function() {
 | |
| 		return Insts.slice();
 | |
| 	} );
 | |
| 
 | |
| 	__readOnly( VimArea.prototype, "content", function() {
 | |
| 		return this.contentFeeder.content.slice( 0, -1 );
 | |
| 	} );
 | |
| 
 | |
| 	ns[ NS_EXPORT ]( EX_CLASS, "VimArea", VimArea );
 | |
| })();
 |