commit fa8599d20d2037c7661fcf11da609e5f885e1301
| author | 斟酌 鵬兄 <tgckpg@gmail.com> |
| date | 2016-02-23T03:25:31Z |
| subject | Heading snippet |
commit fa8599d20d2037c7661fcf11da609e5f885e1301
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date: 2016-02-23T03:25:31Z
Heading snippet
---
.../SmartInput/CandidateAction/Heading.js | 10 +-
.../src/Astro/Blog/AstroEdit/SmartInput/_this.js | 372 +++++++++++++++------
.../Blog/AstroEdit/Visualizer/Snippet/Heading.js | 177 ++++++++++
.../src/Astro/Blog/AstroEdit/Visualizer/_this.js | 1 +
botanjs/src/Astro/Blog/AstroEdit/_this.js | 2 +
botanjs/src/Astro/Blog/Layout/MainFrame.css | 8 -
botanjs/src/Astro/Blog/Layout/MainFrame.js | 1 +
botanjs/src/Astro/Blog/SharedStyle.css | 7 +
botanjs/src/Astro/Blog/SharedStyle.js | 5 +
...o.Blog.AstroEdit.SmartInput.ICandidateAction.js | 2 +
10 files changed, 481 insertions(+), 104 deletions(-)
diff --git a/botanjs/src/Astro/Blog/AstroEdit/SmartInput/CandidateAction/Heading.js b/botanjs/src/Astro/Blog/AstroEdit/SmartInput/CandidateAction/Heading.js
index aa5f836..854bb1b 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/SmartInput/CandidateAction/Heading.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/SmartInput/CandidateAction/Heading.js
@@ -12,17 +12,25 @@
var Dand = __import( "Dandelion" );
/** @type {Astro.Blog.AstroEdit.SmartInput.ICandidateAction} */
- var Heading = function ( visualizer )
+ var Heading = function ( visualizer, key )
{
this.visualizer = visualizer;
+ this.key = key;
};
Heading.prototype.GetCandidates = function( handler )
{
+ return null;
};
Heading.prototype.Process = function( key )
{
+ this.visualizer.insertSnippet( "heading", { "value": key } );
+ };
+
+ Heading.prototype.Retreat = function( sender, e )
+ {
+ return sender.value == "" && e.keyCode == 8; // Backspace
};
ns[ NS_EXPORT ]( EX_CLASS, "Heading", Heading );
diff --git a/botanjs/src/Astro/Blog/AstroEdit/SmartInput/_this.js b/botanjs/src/Astro/Blog/AstroEdit/SmartInput/_this.js
index 19e26a3..6c9fcc3 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/SmartInput/_this.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/SmartInput/_this.js
@@ -27,6 +27,29 @@
var moduleNs = "Astro.Blog.AstroEdit.SmartInput.CandidateAction.";
var service_uri = Config.get( "ServiceUri" );
+ var Destructor = function( target )
+ {
+ this.target = target;
+ this.target.Disposed = false;
+ this.destructSequence = [];
+ };
+
+ Destructor.prototype.Register = function( destruct )
+ {
+ this.destructSequence.push( destruct );
+ };
+
+ Destructor.prototype.Destruct = function()
+ {
+ for( var i in this.destructSequence )
+ {
+ this.destructSequence[i]();
+ }
+
+ this.target.Disposed = true;
+ this.destructSequence = null;
+ };
+
var KeyHandler = function( sender, handler )
{
return function( e )
@@ -39,99 +62,150 @@
};
};
- var LoadModule = function( mod, handler )
+ // {{{ Candidates Class
+ var Candidates = function( title, desc, defs )
{
- var ldr = new Loader( service_uri );
- ldr.load( moduleNs + mod, handler );
+ this.title = title;
+ this.desc = desc;
+ this.__cands = [];
+ this.__defs = defs || {};
+ this.Empty = !defs;
};
- /** @param {Astro.Blog.AstroEdit.Visualizer} */
- var SmartInput = function ( visualizer, CandidatesOvd )
+ Candidates.prototype.Get = function()
{
- var SBarPresent = false;
- var insert = function() { return Dand.textNode( "" ); };
- var __cands = [];
+ if( this.__cands.length ) return this.__cands;
- var CandidateCycle = -1;
- var KeywordTyped = 0;
- var shiftTabbed = false;
+ for( var i in this.__defs )
+ {
+ /** @param {Astro.Blog.AstroEdit.SmartInput.Definition} */
+ var c = this.__defs[i];
+ this.__cands.push( Dand.wrapc( "cn", [ i, Dand.wrapc( "desc", c.desc ) ], new DataKey( "key", i ) ) );
+ }
- var Cands = CandidatesOvd || {
- "Article Reference": { module: "ArticleReference", desc: "Article reference link" }
- , "facts": { module: "Facts", desc: "Facts, a fact bubble popup when mouseover" }
- , "footnote": { module: "Footnote", desc: "Footnote, a footnote displayed at the end of article" }
- , "h1": { module: "Heading", options: 1, desc: "Heading, size 1" }
- , "h2": { module: "Heading", options: 2, desc: "Heading, size 2" }
- , "h3": { module: "Heading", options: 3, desc: "Heading, size 3" }
- , "h4": { module: "Heading", options: 4, desc: "Heading, size 4" }
- , "h5": { module: "Heading", options: 5, desc: "Heading, size 5" }
- };
+ return this.__cands;
+ };
- var GetCandidates = function()
+ Candidates.prototype.Reset = function()
+ {
+ var Cands = this.Get();
+ for( var i in Cands )
+ {
+ var c = IDOMElement( Cands[i] );
+ c.setAttribute( new DataKey( "selected", 0 ) );
+ }
+ };
+
+ Candidates.prototype.Filtered = function()
+ {
+ var Cands = this.Get();
+ var selected = [];
+ for( var i in Cands )
{
- if( __cands.length ) return __cands;
+ var c = IDOMElement( Cands[i] );
+ c.setAttribute( new DataKey( "selected", 0 ) );
- for( var i in Cands )
+ if( c.style.display != "none" )
{
- /** @param {Astro.Blog.AstroEdit.SmartInput.Definition} */
- var c = Cands[i];
- __cands.push( Dand.wrapc( "cn", [ i, Dand.wrapc( "desc", c.desc ) ], new DataKey( "key", i ) ) );
+ selected.push( c );
}
+ }
- return __cands;
- };
+ return selected;
+ };
- var ResetCandidates = function()
+ Candidates.prototype.Selected = function()
+ {
+ var Cands = this.Get();
+ for( var i in Cands )
{
- var Cands = GetCandidates();
- for( var i in Cands )
+ var c = IDOMElement( Cands[i] );
+ if( c.getDAttribute( "selected" ) == "1" )
{
- var c = IDOMElement( Cands[i] );
- c.setAttribute( new DataKey( "selected", 0 ) );
+ return c;
}
- };
+ }
+
+ return null;
+ };
+ // }}}
+
+ /** @param {Astro.Blog.AstroEdit.Visualizer} */
+ var SmartInput = function( visualizer )
+ {
+ this.Present = false;
+ var destructor = new Destructor( this );
+
+ var _self = this;
+ var insert = function() { return Dand.textNode( "" ); };
+
+ var ModLevels = [];
- var FilteredCandidates = function()
+ ModLevels.Cands = function() { return ModLevels[0][0]; };
+ ModLevels.Action = function() { return ModLevels[0][1]; };
+ ModLevels.Retreat = function() { return ModLevels[0][2]; };
+
+ var __title = null;
+ var title = function( reload )
{
- var Cands = GetCandidates();
- var selected = [];
- for( var i in Cands )
+ if( !reload && __title ) return __title;
+
+ var l = ModLevels.length - 1;
+ var t = ModLevels[ l ][0].title;
+
+ for( var i = 0; i < l; i ++ )
{
- var c = IDOMElement( Cands[i] );
- c.setAttribute( new DataKey( "selected", 0 ) );
+ var Mod = ModLevels[i];
+ t = t + " > " + Mod[0].title;
+ }
- if( c.style.display != "none" )
- {
- selected.push( c );
- }
+ if( __title )
+ {
+ __title.textContent = t;
+ }
+ else
+ {
+ __title = Dand.wrape( t );
}
- return selected;
+ return __title;
};
-
- var SelectedCandidate = function()
+ var __stage = null;
+ var stage = function( incoming )
{
- var Cands = GetCandidates();
- for( var i in Cands )
+ if( __stage )
{
- var c = IDOMElement( Cands[i] );
- if( c.getDAttribute( "selected" ) == "1" )
+ if( incoming )
{
- return c;
+ IDOMElement( Dand.wrap() ).lootChildren( __stage[1] );
+
+ var ThisCands = ModLevels.Cands().Get();
+ if( ThisCands.length )
+ {
+ IDOMElement( __stage[1] ).lootChildren( Dand.wrape( ThisCands ) );
+ }
}
+
+ return __stage;
}
+ var Cands = ModLevels.Cands();
- return null;
- };
+ var Command = Dand.wrap(
+ "input", null, "v_snippet_input_single"
+ , null, IKey.quickDef( "type", "text", "placeholder", Cands.desc, "value", "`" )
+ );
- var ModuleLoaded = function( e )
- {
- /** @type {Astro.Blog.AstroEdit.SmartInput.ICandidateAction} */
- var module = new ( __import( e ) )( visualizer );
+ var CandList = Dand.wrap( "div", null, "compx smartbar-candidates", Cands.Get() );
+
+ Command.selectionStart = Command.selectionEnd = 1;
- // XXX
+ return __stage = [ Command, CandList ];
};
+ var CandidateCycle = -1;
+ var KeywordTyped = 0;
+ var shiftTabbed = false;
+
var HandleInput = function( sender, e )
{
// Don't handle if holding shift or ctrl key
@@ -146,6 +220,9 @@
switch( e.keyCode )
{
case 192: // `
+ // If we are not are the first level, do nothing
+ if( 1 < ModLevels.length ) break;
+
// Closing the quote, that means this is a block-quoted text
e.preventDefault();
insert = undefined;
@@ -164,14 +241,19 @@
// Not closing the quote, either a direct text or the first matched action
e.preventDefault();
- var selected = SelectedCandidate();
+ // No candidates, directly pass the input text to the processor
+ if( ModLevels.Cands().Empty && 1 < ModLevels.length )
+ {
+ ModLevels.Action()( sender.value );
+ break;
+ }
+
+ var selected = ModLevels.Cands().Selected();
// Check if matched an action first
if( selected )
{
insert = undefined;
- sender.BindingBox.close();
-
- LoadModule( Cands[ selected.getDAttribute( "key" ) ].module, ModuleLoaded );
+ ModLevels.Action()( selected.getDAttribute( "key" ) );
}
else
{
@@ -190,7 +272,7 @@
// Hitting tab will cycle around the candidates
e.preventDefault();
- var c = FilteredCandidates();
+ var c = ModLevels.Cands().Filtered();
var l = c.length;
if( !l ) break;
@@ -211,20 +293,30 @@
var CyclingKeyword = ThisCandidate.getDAttribute( "key" );
sender.value = "`" + CyclingKeyword;
+
+ // Check if only 1 matched
+ if( c.length == 1 && KeywordTyped == sender.value.length )
+ {
+ insert = undefined;
+ ModLevels.Action()( ThisCandidate.getDAttribute( "key" ) );
+ break;
+ }
+
sender.setSelectionRange( KeywordTyped, sender.value.length );
break;
default:
- FilteredCandidates();
+ ModLevels.Cands().Filtered();
CandidateCycle = -1;
}
};
var TestEmpty = function( sender, e )
{
- if( sender.value == "" )
+ if( ModLevels.Retreat()( sender, e ) )
{
- sender.BindingBox.close();
+ _self.RetreatLevel( sender );
+ if( !ModLevels.length ) return;
}
// Search exact matched Candidates
@@ -244,7 +336,7 @@
KeywordTyped = sender.value.length;
}
- var c = GetCandidates();
+ var c = ModLevels.Cands().Get();
var keyword = sender.value.substr( 1 );
for( var i in c )
{
@@ -263,60 +355,150 @@
var ClosePanel = function( confirmed )
{
- ResetCandidates();
-
- Cycle.next( function() { SBarPresent = false; } );
+ Cycle.next( function() { _self.Present = false; } );
visualizer.restoreSelection();
- if( !confirmed ) return;
-
- if( insert != undefined )
+ if( confirmed && insert != undefined )
visualizer.insertAtCaret( insert() );
+
+ destructor.Destruct();
};
- var ShowSmartBar = function()
+ // Advance the input level by CandidateAction
+ this.advanceLevel = function( Candidates, Action, Retreat )
{
- if( SBarPresent ) return;
- visualizer.saveSelection();
+ if( ModLevels.length )
+ {
+ ModLevels[0].selected = ModLevels.Cands().Selected().getDAttribute( "key" );
+ }
- SBarPresent = true;
+ ModLevels.unshift([ Candidates, Action, Retreat ]);
- var title = "Quick Access ( Prototype )";
+ if( 1 < ModLevels.length )
+ {
+ stage( Candidates );
+ title( true );
+ stage()[0].value = "";
+ stage()[0].setAttribute( "placeholder", ModLevels.Cands().desc );
+ }
+ };
- var Command = Dand.wrap(
- "input", null, "v_snippet_input_single"
- , null, IKey.quickDef( "type", "text", "placeholder", "Command", "value", "`" )
- );
- var Candidates = Dand.wrap( "div", null, "compx smartbar-candidates", GetCandidates() );
+ this.RetreatLevel = function( sender )
+ {
+ if( ModLevels.length == 1 )
+ {
+ sender.BindingBox.close();
+ destructor.Destruct();
+ }
- Command.selectionStart = Command.selectionEnd = 1;
+ ModLevels.shift();
- Command.BindingBox = new MessageBox(
- title
- , Dand.wrape([ Command, Candidates ])
+ if( ModLevels.length )
+ {
+ var Cands = ModLevels.Cands();
+ var input = stage( Cands )[0];
+ title( true );
+ input.value
+ = "`" + Cands.Selected().getDAttribute( "key" );
+
+ input.setAttribute( "placeholder", Cands.desc );
+
+ input.selectionStart = 1;
+ input.selectionEnd = input.value.length;
+ }
+ };
+
+ this.Show = function()
+ {
+ if( _self.Present ) return;
+ visualizer.saveSelection();
+
+ _self.Present = true;
+
+ var MsgBox = new MessageBox(
+ title()
+ , Dand.wrape( stage() )
, "Back", false
, ClosePanel
);
- Command.BindingBox.show();
+ MsgBox.show();
+
+ var Command = stage()[0];
+ Command.BindingBox = MsgBox;
+
Command.focus();
var DCommand = IDOMElement( Command );
- DCommand.addEventListener( "KeyDown", KeyHandler( Command, HandleInput ) );
- DCommand.addEventListener( "KeyUp", KeyHandler( Command, TestEmpty ) );
+ var KDown = KeyHandler( Command, HandleInput );
+ var KUp = KeyHandler( Command, TestEmpty );
+
+ DCommand.addEventListener( "KeyDown", KDown );
+ DCommand.addEventListener( "KeyUp", KUp );
+
+ destructor.Register( function() {
+ DCommand.removeEventListener( "KeyDown", KDown );
+ DCommand.removeEventListener( "KeyUp", KUp );
+ } );
+ };
+ };
+
+ var MasterInput = function( visualizer )
+ {
+ var Cands = {
+ "Article Reference": { module: "ArticleReference", desc: "Article reference link" }
+ , "facts": { module: "Facts", desc: "Facts, a fact bubble popup when mouseover" }
+ , "footnote": { module: "Footnote", desc: "Footnote, a footnote displayed at the end of article" }
+ , "h1": { module: "Heading", options: 1, desc: "Heading, size 1" }
+ , "h2": { module: "Heading", options: 2, desc: "Heading, size 2" }
+ , "h3": { module: "Heading", options: 3, desc: "Heading, size 3" }
+ , "h4": { module: "Heading", options: 4, desc: "Heading, size 4" }
+ , "h5": { module: "Heading", options: 5, desc: "Heading, size 5" }
+ };
+
+ var LoadModule = function( mod )
+ {
+ var ldr = new Loader( service_uri );
+ var ModItem = Cands[ mod ];
+ ldr.load( moduleNs + ModItem.module, function( e ) { ModuleLoaded( mod, e ); } );
+ };
+
+ var InputBox = null;
+ var ModuleLoaded = function( sender, e )
+ {
+ /** @type {Astro.Blog.AstroEdit.SmartInput.ICandidateAction} */
+ var module = new ( __import( e ) )( visualizer, sender );
+
+ var ModItem = Cands[ sender ];
+ InputBox.advanceLevel(
+ new Candidates( ModItem.module, ModItem.desc, module.GetCandidates() )
+ , module.Process.bind( module )
+ , module.Retreat.bind( module )
+ );
};
var BackQuoteBinding = function ( sender, e )
{
- if( !SBarPresent && code == 192 )
+ if( !InputBox || InputBox.Disposed )
+ {
+ InputBox = new SmartInput( visualizer );
+ InputBox.advanceLevel(
+ // First level Candidates
+ new Candidates( "Quick Access", "Keyword", Cands )
+ , LoadModule
+ , function( sender, e ) { return sender.value == ""; }
+ );
+ }
+
+ if( !InputBox.Present && code == 192 )
{
e.preventDefault();
- ShowSmartBar();
+ InputBox.Show();
}
};
IDOMObject( document ).addEventListener( "KeyDown", KeyHandler( document, BackQuoteBinding ), false );
};
- ns[ NS_EXPORT ]( EX_CLASS, "SmartInput", SmartInput );
+ ns[ NS_EXPORT ]( EX_CLASS, "SmartInput", MasterInput );
})();
diff --git a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Heading.js b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Heading.js
new file mode 100644
index 0000000..412ea79
--- /dev/null
+++ b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Heading.js
@@ -0,0 +1,177 @@
+(function ()
+{
+ var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
+
+ /** @type {System.utils.IKey} */
+ var IKey = __import( "System.utils.IKey" );
+ /** @type {System.utils.DataKey} */
+ var DataKey = __import( "System.utils.DataKey" );
+ /** @type {Dandelion.IDOMElement} */
+ var IDOMElement = __import( "Dandelion.IDOMElement" );
+ /** @type {Dandelion} */
+ var Dand = __import( "Dandelion" );
+ /** @type {Components.MessageBox} */
+ var MessageBox = __import( "Components.MessageBox" );
+
+ var escapeStr = ns[ NS_INVOKE ]( "escapeStr" );
+ var compileProp = ns[ NS_INVOKE ]( "compileProp" );
+
+ var heading = function ( insertSnippet, snippetWrap, createContext, override )
+ {
+ var temp, i, j
+ , Sizes = IKey.quickDef(
+ "h1", "h1"
+ , "h2", "h2"
+ , "h3", "h3"
+ , "h4", "h4"
+ , "h5", "h5"
+ )
+
+ // Private methods
+ , compileListItems = function ()
+ {
+ var arr = [];
+ for ( i in Sizes )
+ {
+ arr[ arr.length ] = Dand.wrapne(
+ "option"
+ , Sizes[i].keyName
+ , new IKey( "value", Sizes[i].keyValue )
+ );
+ }
+ return arr;
+ }
+
+ // Snippet Class structure: handler & visualizer
+ , handler = function ()
+ {
+ // Input fields
+ var v_snippetInput = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text") )
+ , v_headingsize = Dand.wrap( "select", null, "v_select flsf", compileListItems() );
+
+ if ( this._stage )
+ {
+ if ( this._size )
+ {
+ for ( i = 0; i < Sizes.length; i ++ )
+ {
+ if ( Sizes[i].keyValue == this._size )
+ {
+ v_headingsize.selectedIndex = i;
+ }
+ }
+ }
+
+ v_snippetInput.value = this._content || "";
+ }
+ else
+ {
+ // Remember the last choice
+ if ( typeof( this.pSnippeHeadingChoice ) == "number" )
+ v_headingsize.selectedIndex = this.pSnippeHeadingChoice;
+ }
+
+ // Popup MessageBox
+ new MessageBox(
+ ( this._stage ? "Edit" : "Insert" ) + " heading text"
+ , Dand.wrapc(
+ "v_trimmer"
+ , [
+ v_snippetInput
+ , Dand.wrapc( "v_instruction", v_headingsize )
+ ]
+ )
+ , "OK", "Cancel"
+ // Switcher
+ , visualizer.bind({ heading:v_snippetInput, size: v_headingsize, stage: this._stage })
+ ).show();
+ }
+
+ , visualizer = function ( submitted, override )
+ {
+ var size, heading
+ , stage = this.stage;
+
+ if ( override )
+ {
+ size = override.size;
+ heading = override.value;
+ }
+ else
+ {
+ size = this.size[this.pSnippeHeadingChoice = this.size.selectedIndex].value;
+ heading = this.heading.value;
+ }
+
+ var size;
+ for( var i in Sizes )
+ {
+ if( Sizes[i].keyValue == size )
+ {
+ size = Sizes[i].keyName;
+ break;
+ }
+ }
+
+ if ( submitted && heading )
+ {
+ if ( !stage )
+ {
+ // Visualize component
+ temp = Dand.wrapne( "span", Dand.wrapne( size, heading ), [
+ new DataKey( "value", heading )
+ , new DataKey( "size", size )
+ ]);
+
+ insertSnippet( j = snippetWrap( "Heading", temp ), Boolean( override ) );
+ }
+ else
+ {
+ IDOMElement( stage ).setAttribute([
+ new DataKey( "value", heading )
+ , new DataKey( "size", size )
+ ]);
+
+ stage.removeChild( stage.firstChild );
+ stage.appendChild( Dand.wrapne( size, heading ) );
+
+ temp = stage;
+ }
+
+ i = { _size: size, _content: heading, _stage: temp };
+
+ // Set context menu
+ createContext( i, j, handler );
+ }
+ }
+ ;
+
+ if ( override )
+ {
+ visualizer( true, override );
+ override = false;
+ }
+ else
+ {
+ return handler;
+ }
+ return true;
+ };
+
+ var compile = function ( stage )
+ {
+ var element = IDOMElement( stage )
+ , props = [ "size" ];
+
+ return "[heading"
+ + compileProp( element, props )
+ + "]"
+ + escapeStr( element.getDAttribute( "value" ) )
+ + "[/heading]"
+ ;
+ };
+
+ __static_method( heading, "compile", compile );
+
+ ns[ NS_EXPORT ]( EX_CLASS, "Heading", heading );
+})();
diff --git a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js
index 9b7c23e..8941ac1 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js
@@ -37,6 +37,7 @@
, "AcquireLib" , "background: black;"
, "Html" , "background: coral;"
, "SiteFile" , "background: royalblue;"
+ , "Heading" , ""
);
var snippetNs = "Astro.Blog.AstroEdit.Visualizer.Snippet.";
diff --git a/botanjs/src/Astro/Blog/AstroEdit/_this.js b/botanjs/src/Astro/Blog/AstroEdit/_this.js
index 91e4ff1..4442063 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/_this.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/_this.js
@@ -27,6 +27,8 @@
// calls the smart bar
var SmartInput = __import( "Astro.Blog.AstroEdit.SmartInput" );
+ // __import( "Astro.Blog.SharedStyle" ); CSS_RESERVATION
+
var wh, ww, cw, html, article;
var init = function ()
diff --git a/botanjs/src/Astro/Blog/Layout/MainFrame.css b/botanjs/src/Astro/Blog/Layout/MainFrame.css
index cc9a361..8669d98 100644
--- a/botanjs/src/Astro/Blog/Layout/MainFrame.css
+++ b/botanjs/src/Astro/Blog/Layout/MainFrame.css
@@ -29,14 +29,6 @@ sup { vertical-align: super; }
a:hover { text-decoration: underline; }
-h1, h2, h3, h4, .h1, .h2, .h3, .h4 { font-family: custom-serif; }
-h1, .h1 { font-size: 2.5em; }
-h2, .h2 { font-size: 2em; }
-h3, .h3 { font-size: 1.5em; }
-h4, .h4 { font-size: 1em; }
-h5, .h5 { font-size: 0.8em; }
-h6, .h6 { font-size: 0.5em; }
-
.clearfix {
clear: both;
padding: 0 !important;
diff --git a/botanjs/src/Astro/Blog/Layout/MainFrame.js b/botanjs/src/Astro/Blog/Layout/MainFrame.js
index 10aba98..70837b4 100644
--- a/botanjs/src/Astro/Blog/Layout/MainFrame.js
+++ b/botanjs/src/Astro/Blog/Layout/MainFrame.js
@@ -28,6 +28,7 @@
// __import( "Dandelion.CSSReset" ); CSS_RESERVATION
// __import( "Dandelion.CSSAnimations" ); CSS_RESERVATION
+ // __import( "Astro.Blog.SharedStyle" ); CSS_RESERVATION
// __import( "Astro.Blog.Element.Layer" ); CSS_RESERVATION
/** @function {System.Net.getData} */
diff --git a/botanjs/src/Astro/Blog/SharedStyle.css b/botanjs/src/Astro/Blog/SharedStyle.css
new file mode 100644
index 0000000..78d6e56
--- /dev/null
+++ b/botanjs/src/Astro/Blog/SharedStyle.css
@@ -0,0 +1,7 @@
+h1, h2, h3, h4, .h1, .h2, .h3, .h4 { font-family: custom-serif; }
+h1, .h1 { font-size: 2.5em; }
+h2, .h2 { font-size: 2em; }
+h3, .h3 { font-size: 1.5em; }
+h4, .h4 { font-size: 1em; }
+h5, .h5 { font-size: 0.8em; }
+h6, .h6 { font-size: 0.5em; }
diff --git a/botanjs/src/Astro/Blog/SharedStyle.js b/botanjs/src/Astro/Blog/SharedStyle.js
new file mode 100644
index 0000000..62e2e73
--- /dev/null
+++ b/botanjs/src/Astro/Blog/SharedStyle.js
@@ -0,0 +1,5 @@
+/*
+(function(){
+ var ns = __namespace( "Astro.Blog.SharedStyle" );
+})();
+*/
diff --git a/botanjs/src/externs/Astro.Blog.AstroEdit.SmartInput.ICandidateAction.js b/botanjs/src/externs/Astro.Blog.AstroEdit.SmartInput.ICandidateAction.js
index 1ab9e35..59c2d04 100644
--- a/botanjs/src/externs/Astro.Blog.AstroEdit.SmartInput.ICandidateAction.js
+++ b/botanjs/src/externs/Astro.Blog.AstroEdit.SmartInput.ICandidateAction.js
@@ -4,3 +4,5 @@ Astro.Blog.AstroEdit.SmartInput.ICandidateAction = function(){};
Astro.Blog.AstroEdit.SmartInput.ICandidateAction.GetCandidates;
/** @type {function} */
Astro.Blog.AstroEdit.SmartInput.ICandidateAction.Process;
+/** @type {function} */
+Astro.Blog.AstroEdit.SmartInput.ICandidateAction.Retreat;