Heading snippet

This commit is contained in:
斟酌 鵬兄 2016-02-23 11:25:31 +08:00
parent 33c515cd08
commit fa8599d20d
10 changed files with 506 additions and 129 deletions

View File

@ -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 );

View File

@ -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;
if( this.__cands.length ) return this.__cands;
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 ) ) );
}
return this.__cands;
};
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 )
{
var c = IDOMElement( Cands[i] );
c.setAttribute( new DataKey( "selected", 0 ) );
if( c.style.display != "none" )
{
selected.push( c );
}
}
return selected;
};
Candidates.prototype.Selected = function()
{
var Cands = this.Get();
for( var i in Cands )
{
var c = IDOMElement( Cands[i] );
if( c.getDAttribute( "selected" ) == "1" )
{
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 __cands = [];
var ModLevels = [];
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 )
{
if( !reload && __title ) return __title;
var l = ModLevels.length - 1;
var t = ModLevels[ l ][0].title;
for( var i = 0; i < l; i ++ )
{
var Mod = ModLevels[i];
t = t + " > " + Mod[0].title;
}
if( __title )
{
__title.textContent = t;
}
else
{
__title = Dand.wrape( t );
}
return __title;
};
var __stage = null;
var stage = function( incoming )
{
if( __stage )
{
if( incoming )
{
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();
var Command = Dand.wrap(
"input", null, "v_snippet_input_single"
, null, IKey.quickDef( "type", "text", "placeholder", Cands.desc, "value", "`" )
);
var CandList = Dand.wrap( "div", null, "compx smartbar-candidates", Cands.Get() );
Command.selectionStart = Command.selectionEnd = 1;
return __stage = [ Command, CandList ];
};
var CandidateCycle = -1;
var KeywordTyped = 0;
var shiftTabbed = false;
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" }
};
var GetCandidates = function()
{
if( __cands.length ) return __cands;
for( var i in Cands )
{
/** @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 ) ) );
}
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 ModuleLoaded = function( e )
{
/** @type {Astro.Blog.AstroEdit.SmartInput.ICandidateAction} */
var module = new ( __import( e ) )( visualizer );
// XXX
};
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;
if( ModLevels.length )
{
ModLevels[0].selected = ModLevels.Cands().Selected().getDAttribute( "key" );
}
ModLevels.unshift([ Candidates, Action, Retreat ]);
if( 1 < ModLevels.length )
{
stage( Candidates );
title( true );
stage()[0].value = "";
stage()[0].setAttribute( "placeholder", ModLevels.Cands().desc );
}
};
this.RetreatLevel = function( sender )
{
if( ModLevels.length == 1 )
{
sender.BindingBox.close();
destructor.Destruct();
}
ModLevels.shift();
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();
SBarPresent = true;
_self.Present = true;
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, "compx smartbar-candidates", GetCandidates() );
Command.selectionStart = Command.selectionEnd = 1;
Command.BindingBox = new MessageBox(
title
, Dand.wrape([ Command, Candidates ])
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 );
})();

View File

@ -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 );
})();

View File

@ -37,6 +37,7 @@
, "AcquireLib" , "background: black;"
, "Html" , "background: coral;"
, "SiteFile" , "background: royalblue;"
, "Heading" , ""
);
var snippetNs = "Astro.Blog.AstroEdit.Visualizer.Snippet.";

View File

@ -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 ()

View File

@ -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;

View File

@ -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} */

View File

@ -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; }

View File

@ -0,0 +1,5 @@
/*
(function(){
var ns = __namespace( "Astro.Blog.SharedStyle" );
})();
*/

View File

@ -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;