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 c; + 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 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; }