penguin/AstroJS

Javascript framework for my blog

commit e2cda7ca2c5ac82c951cfa40d1693b3910be70ac

author斟酌 鵬兄 <tgckpg@gmail.com>
date2016-02-21T21:53:32Z
subjectChoice Tabbing
commit e2cda7ca2c5ac82c951cfa40d1693b3910be70ac
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2016-02-21T21:53:32Z

    Choice Tabbing
---
 botanjs/src/Astro/Blog/AstroEdit/Article.js      |   5 +-
 botanjs/src/Astro/Blog/AstroEdit/SmartInput.css  |   4 +
 botanjs/src/Astro/Blog/AstroEdit/SmartInput.js   | 171 ++++++++++++++++++++---
 botanjs/src/Astro/Blog/Components/Entry/Blog.css |   2 +
 4 files changed, 159 insertions(+), 23 deletions(-)

diff --git a/botanjs/src/Astro/Blog/AstroEdit/Article.js b/botanjs/src/Astro/Blog/AstroEdit/Article.js
index 6aea58a..b2676bd 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/Article.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/Article.js
@@ -246,7 +246,10 @@
 		{
 			if ( !stay )
 			{
-				window.open( base_path + "article/view/" + ArticleModel.slug + "/") && window.close();
+				var op = window.open( base_path + "article/view/" + ArticleModel.slug + "/" );
+				Cycle.next( function() {
+					if( op ) window.close();
+				});
 			}
 		}
 
diff --git a/botanjs/src/Astro/Blog/AstroEdit/SmartInput.css b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.css
index 6497d7c..0951ceb 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/SmartInput.css
+++ b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.css
@@ -10,3 +10,7 @@
 .smartbar-candidates .cn:hover {
 	background-color: rgba( 0, 0, 0, 0.2 );
 }
+
+.smartbar-candidates .cn[data-selected="1"] {
+	background-color: orangered;
+}
diff --git a/botanjs/src/Astro/Blog/AstroEdit/SmartInput.js b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.js
index bd1946d..4c0dc08 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/SmartInput.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.js
@@ -26,22 +26,89 @@
 	/** @type {Astro.Blog.Config} */
 	var Config                                  = __import( "Astro.Blog.Config" );
 
+	var __cands = [];
 	var GetCandidates = function()
 	{
-		var c = [];
+		if( __cands.length ) return __cands;
+
 		var Cands = {
-			"facts": "T"
+			"Article Reference": "Ref"
+			, "facts": "T"
 			, "text": "T"
+			, "h1": "h1"
+			, "h2": "h2"
+			, "h3": "h3"
+			, "h4": "h4"
+			, "h5": "h5"
 		};
 
 		for( var i in Cands )
 		{
-			c.push( Dand.wrapc( "cn", i ) );
+			__cands.push( Dand.wrapc( "cn", i, new DataKey( "key", Cands[i] ) ) );
+		}
+
+		return __cands;
+	};
+
+	var ResetCandidates = function()
+	{
+		var Cands = GetCandidates();
+		for( var i in Cands )
+		{
+			var c = IDOMElement( Cands[i] );
+			c.setAttribute( new DataKey( "selected", 0 ) );
+		}
+	};
+
+	var FilteredCandidates = function()
+	{
+		var Cands = GetCandidates();
+		var selected = [];
+		for( var i in Cands )
+		{
+			var c = IDOMElement( Cands[i] );
+			c.setAttribute( new DataKey( "selected", 0 ) );
+
+			if( c.style.display != "none" )
+			{
+				selected.push( c );
+			}
 		}
 
-		return c;
+		return selected;
 	};
 
+	var SelectedCandidate = function()
+	{
+		var Cands = GetCandidates();
+		for( var i in Cands )
+		{
+			var c = IDOMElement( Cands[i] );
+			if( c.getDAttribute( "selected" ) == "1" )
+			{
+				return c;
+			}
+		}
+
+		return null;
+	};
+
+	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, e );
+		};
+	};
+
+	var CandidateCycle = -1;
+	var KeywordTyped = 0;
+	var shiftTabbed = false;
+
 	/** @param {Astro.Blog.AstroEdit.Visualizer} */
 	var SmartInput = function ( visualizer )
 	{
@@ -50,12 +117,14 @@
 
 		var HandleInput = function( sender, e )
 		{
-			e = e || window.event;
-			if ( e.keyCode ) code = e.keyCode;
-			else if ( e.which ) code = e.which;
-
 			// Don't handle if holding shift or ctrl key
-			if( e.shiftKey || e.ctrlKey ) return;
+			if( e.shiftKey || e.ctrlKey )
+			{
+				// Except the Shift + Tab, we need to cycle this
+				shiftTabbed = e.shiftKey && e.keyCode == 9;
+
+				if( !shiftTabbed ) return;
+			}
 
 			switch( e.keyCode )
 			{
@@ -67,18 +136,21 @@
 					var v = sender.value.substr( 1 );
 					if( v == "" ) insert = function() { return Dand.textNode( "`" ); };
 
+					insert = undefined;
+					sender.BindingBox.close( true );
+
 					// Insert the code snippet with inline flag
 					visualizer.insertSnippet( "code", { "inline": "on", "lang": "plain", "value": v } );
-
-					sender.BindingBox.close( true );
 					break;
 				case 13: // Enter
 					// Not closing the quote, either a direct text or the first matched action
 					e.preventDefault();
 
+					var selected = SelectedCandidate();
 					// Check if matched an action first
-					if( false )
+					if( selected )
 					{
+
 					}
 					else
 					{
@@ -91,6 +163,36 @@
 				case 27: // Esc
 					sender.BindingBox.close();
 					break;
+				case 9: // Tab
+					// Hitting tab will cycle around the candidates
+					e.preventDefault();
+
+					var c = FilteredCandidates();
+					var l = c.length;
+					if( !l ) break;
+
+					CandidateCycle += e.shiftKey ? -1 : 1;
+
+					if( CandidateCycle == l )
+					{
+						CandidateCycle = 0;
+					}
+					else if( CandidateCycle == -1 )
+					{
+						CandidateCycle = c.length - 1;
+					}
+
+					var ThisCandidate = c[ CandidateCycle ];
+					ThisCandidate.setAttribute( new DataKey( "selected", 1 ) );
+
+					var CyclingKeyword = ThisCandidate.element.textContent;
+
+					sender.value = "`" + CyclingKeyword;
+					sender.setSelectionRange( KeywordTyped, sender.value.length );
+					break;
+				default:
+					FilteredCandidates();
+					CandidateCycle = -1;
 			}
 		};
 
@@ -100,10 +202,39 @@
 			{
 				sender.BindingBox.close();
 			}
+
+			// Search exact matched Candidates
+			switch( e.keyCode )
+			{
+				case 9: // Tab, do nothing
+					break;
+				case 16: // Shift, check if shiftTabbed
+					if( shiftTabbed )
+					{
+						shiftTabbed = false;
+						break;
+					}
+				default:
+					if( CandidateCycle == -1 )
+					{
+						KeywordTyped = sender.value.length;
+					}
+
+					var c = GetCandidates();
+					var keyword = sender.value.substr( 1 );
+					for( var i in c )
+					{
+						var Cand = c[i];
+						var t = Cand.textContent;
+						Cand.style.display = t.match( new RegExp( "^" + keyword, "i" ) ) ? "" : "none";
+					}
+			}
 		};
 
 		var ClosePanel = function( confirmed )
 		{
+			ResetCandidates();
+
 			Cycle.next( function() { SBarPresent = false; } );
 			visualizer.restoreSelection();
 
@@ -120,13 +251,13 @@
 
 			SBarPresent = true;
 
-			var title = "Quick Access";
+			var title = "Quick Access ( Prototype )";
 
 			var Command = Dand.wrap(
 				"input", null, "v_snippet_input_single"
 				, null, IKey.quickDef( "type", "text", "placeholder", "Command", "value", "`" )
 			);
-			var Candidates = Dand.wrap( "div", null, "smartbar-candidates", GetCandidates() );
+			var Candidates = Dand.wrap( "div", null, "compx smartbar-candidates", GetCandidates() );
 
 			Command.selectionStart = Command.selectionEnd = 1;
 
@@ -141,16 +272,12 @@
 			Command.focus();
 
 			var DCommand = IDOMElement( Command );
-			DCommand.addEventListener( "KeyDown", function( e ) { HandleInput( Command, e ); } );
-			DCommand.addEventListener( "KeyUp", function( e ) { TestEmpty( Command, e ); } );
+			DCommand.addEventListener( "KeyDown", KeyHandler( Command, HandleInput ) );
+			DCommand.addEventListener( "KeyUp", KeyHandler( Command, TestEmpty ) );
 		};
 
-		var BackQuoteBinding = function ( e )
+		var BackQuoteBinding = function ( sender, e )
 		{
-			e = e || window.event;
-			if ( e.keyCode ) code = e.keyCode;
-			else if ( e.which ) code = e.which;
-
 			if( !SBarPresent && code == 192 )
 			{
 				e.preventDefault();
@@ -158,7 +285,7 @@
 			}
 		};
 
-		IDOMObject( document ).addEventListener( "KeyDown", BackQuoteBinding, false );
+		IDOMObject( document ).addEventListener( "KeyDown", KeyHandler( document, BackQuoteBinding ), false );
 	};
 
 	ns[ NS_EXPORT ]( EX_CLASS, "SmartInput", SmartInput );
diff --git a/botanjs/src/Astro/Blog/Components/Entry/Blog.css b/botanjs/src/Astro/Blog/Components/Entry/Blog.css
index 2eb560c..8e63474 100644
--- a/botanjs/src/Astro/Blog/Components/Entry/Blog.css
+++ b/botanjs/src/Astro/Blog/Components/Entry/Blog.css
@@ -4,6 +4,8 @@
 
 .inline-code {
 	font-family: monospace;
+	font-size: 1.12em;
+
 	background-color: #EEE;
 	padding: 0.2em 0.5em;
 }