diff --git a/botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.js b/botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.js index ebf699b..62dd35d 100644 --- a/botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.js +++ b/botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.js @@ -223,10 +223,11 @@ // General file, list view /** @param {_AstJson_.AJaxGetFiles} */ - , buildGeneralCanvas = function (e) + , buildGeneralCanvas = function ( e ) { + if( !e ) return; var f = e.files, dateStamp; - resetCanvas("canvasGeneral"); + resetCanvas( "canvasGeneral" ); for(var i in f) { @@ -527,9 +528,13 @@ , requestInsert = function(confirmed) { - if(confirmed) + if( confirmed ) { - var selectedAlbum = IDOMElement(IDOMElement(this.albumList).first(1, function(elem) { return elem.hasAttribute("selected"); })).getDAttribute("id"); + var selectedAlbum = IDOMElement( + IDOMElement( this.albumList ).first( 1, function(elem) { + return elem.hasAttribute("selected"); + } ) ).getDAttribute( "id" ); + postData( processorSet , { "group": "insert", "id": selectedAlbum , "files": this.collection.join(",") } @@ -541,17 +546,17 @@ , delCollection = function (confirmed) { var album_id = IDOMElement(this).getDAttribute("id"); - if(confirmed) + if( confirmed ) { - postData(processorGet, { group: "get", aid: album_id }, getFilestoDelete.bind(this), loadFailed); + postData( processorGet, { group: "get", aid: album_id }, getFilestoDelete.bind( this ), loadFailed ); } else { - postData(processorSet, { group: "remove", id: album_id }, refreshCanvas, loadFailed); + postData( processorSet, { group: "remove", id: album_id }, refreshCanvas, loadFailed ); } } - , getFilestoDelete = function (e) + , getFilestoDelete = function ( e ) { var l = Object.keys(e.files).length , fc = 0 @@ -646,20 +651,29 @@ , f = e.files, first; // button mime/type ( counts ) - for(var i in f) + for( var i in f ) { - var elem = Dand.wrap("span", null, "asl_menuItem", (i + "(" + f[i] + ")"), new DataKey("name", i)); + var elem = Dand.wrap( + "span", null, "asl_menuItem" + , i + "(" + f[i] + ")" + , new DataKey( "name", i ) ); view_index[view_index.length] = [i, elem]; menuBar.appendChild(elem); IDOMElement(elem).addEventListener(new EventKey("Click", switchView.bind(IDOMElement(elem)))); - if(!first) first = [i, elem]; + if( !first ) first = [ i, elem ]; + } + + if( !first ) + { + debug.Info( "No files" ); + return; } // begin load index - refreshCanvas(first[0]); + refreshCanvas( first[0] ); // Set style first[1].setAttribute("current", 1); } diff --git a/botanjs/src/Astro/Blog/AstroEdit/SmartInput.css b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.css new file mode 100644 index 0000000..6497d7c --- /dev/null +++ b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.css @@ -0,0 +1,12 @@ +.smartbar-candidates { + padding: 0.5em; + background-color: rgba( 0, 0, 0, 0.2 ); +} + +.smartbar-candidates .cn { + padding: 0.2em 0.5em; +} + +.smartbar-candidates .cn:hover { + background-color: rgba( 0, 0, 0, 0.2 ); +} diff --git a/botanjs/src/Astro/Blog/AstroEdit/SmartInput.js b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.js new file mode 100644 index 0000000..bd1946d --- /dev/null +++ b/botanjs/src/Astro/Blog/AstroEdit/SmartInput.js @@ -0,0 +1,165 @@ +(function(){ + var ns = __namespace( "Astro.Blog.AstroEdit" ); + + /** @type {Dandelion} */ + var Dand = __import( "Dandelion" ); + /** @type {Dandelion.IDOMElement} */ + var IDOMElement = __import( "Dandelion.IDOMElement" ); + /** @type {Dandelion.IDOMObject} */ + var IDOMObject = __import( "Dandelion.IDOMObject" ); + /** @type {System.Cycle} */ + var Cycle = __import( "System.Cycle" ); + /** @type {System.Debug} */ + var debug = __import( "System.Debug" ); + /** @type {System.utils} */ + var utils = __import( "System.utils" ); + /** @type {System.utils.Perf} */ + var Perf = __import( "System.utils.Perf" ); + /** @type {System.utils.DataKey} */ + var DataKey = __import( "System.utils.DataKey" ); + /** @type {System.utils.EventKey} */ + var EventKey = __import( "System.utils.EventKey" ); + /** @type {System.utils.IKey} */ + var IKey = __import( "System.utils.IKey" ); + /** @type {Components.MessageBox} */ + var MessageBox = __import( "Components.MessageBox" ); + /** @type {Astro.Blog.Config} */ + var Config = __import( "Astro.Blog.Config" ); + + var GetCandidates = function() + { + var c = []; + var Cands = { + "facts": "T" + , "text": "T" + }; + + for( var i in Cands ) + { + c.push( Dand.wrapc( "cn", i ) ); + } + + return c; + }; + + /** @param {Astro.Blog.AstroEdit.Visualizer} */ + var SmartInput = function ( visualizer ) + { + var SBarPresent = false; + var insert = function() { return Dand.textNode( "" ); }; + + 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; + + switch( e.keyCode ) + { + case 192: // ` + // Closing the quote, that means this is a block-quoted text + e.preventDefault(); + + // Hitting ` twice escapes the ` character itself + var v = sender.value.substr( 1 ); + if( v == "" ) insert = function() { return Dand.textNode( "`" ); }; + + // 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(); + + // Check if matched an action first + if( false ) + { + } + else + { + // Insert this text directly + var v = Dand.textNode( sender.value.substr( 1 ) ); + insert = function() { return v; }; + sender.BindingBox.close( true ); + } + break; + case 27: // Esc + sender.BindingBox.close(); + break; + } + }; + + var TestEmpty = function( sender, e ) + { + if( sender.value == "" ) + { + sender.BindingBox.close(); + } + }; + + var ClosePanel = function( confirmed ) + { + Cycle.next( function() { SBarPresent = false; } ); + visualizer.restoreSelection(); + + if( !confirmed ) return; + + if( insert != undefined ) + visualizer.insertAtCaret( insert() ); + }; + + var ShowSmartBar = function() + { + if( SBarPresent ) return; + visualizer.saveSelection(); + + SBarPresent = true; + + var title = "Quick Access"; + + 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() ); + + Command.selectionStart = Command.selectionEnd = 1; + + Command.BindingBox = new MessageBox( + title + , Dand.wrape([ Command, Candidates ]) + , "Back", false + , ClosePanel + ); + + Command.BindingBox.show(); + Command.focus(); + + var DCommand = IDOMElement( Command ); + DCommand.addEventListener( "KeyDown", function( e ) { HandleInput( Command, e ); } ); + DCommand.addEventListener( "KeyUp", function( e ) { TestEmpty( Command, e ); } ); + }; + + var BackQuoteBinding = function ( e ) + { + e = e || window.event; + if ( e.keyCode ) code = e.keyCode; + else if ( e.which ) code = e.which; + + if( !SBarPresent && code == 192 ) + { + e.preventDefault(); + ShowSmartBar(); + } + }; + + IDOMObject( document ).addEventListener( "KeyDown", BackQuoteBinding, false ); + }; + + ns[ NS_EXPORT ]( EX_CLASS, "SmartInput", SmartInput ); +})(); diff --git a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.css b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.css new file mode 100644 index 0000000..bb52996 --- /dev/null +++ b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.css @@ -0,0 +1,12 @@ +.v_boundary[data-inline="on"][data-type="Code"] { + display: inline-block; + background-color: #EEE; +} + +.v_box[data-inline="on"] .v_description { + display: none; +} + +.v_box[data-inline="on"] { + min-height: 0; +} diff --git a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.js b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.js index 564ef6d..6271c37 100644 --- a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.js +++ b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.js @@ -14,6 +14,7 @@ var MessageBox = __import( "Components.MessageBox" ); var escapeStr = ns[ NS_INVOKE ]( "escapeStr" ); + var compileProp = ns[ NS_INVOKE ]( "compileProp" ); var code = function ( insertSnippet, snippetWrap, createContext, override ) { @@ -34,7 +35,7 @@ , "JavaScript" , "js" , "SQL" , "sql" ) - + // Private methods , compileListItems = function () { @@ -55,7 +56,8 @@ { // Input fields var v_snippetInput = Dand.wrap( "textarea", null, "v_snippet_input" ) - , v_codelang = Dand.wrap( "select", null, "v_select flsf", compileListItems() ); + , v_codelang = Dand.wrap( "select", null, "v_select flsf", compileListItems() ) + , input_inline = Dand.wrapna('input', new IKey("type", "checkbox") ); if ( this._stage ) { @@ -69,8 +71,9 @@ } } } - + v_snippetInput.value = this._content || ""; + input_inline.checked = ( this._inline == "on" ); } else { @@ -87,29 +90,31 @@ , [ Dand.wrapc( "v_instruction", v_codelang ) , v_snippetInput + , Dand.wrape([ input_inline, Dand.textNode( "Inline" ) ]) ] ) , "OK", "Cancel" // Switcher - , visualizer.bind({ code:v_snippetInput, lang: v_codelang, stage: this._stage }) + , visualizer.bind({ code:v_snippetInput, inline: input_inline, lang: v_codelang, stage: this._stage }) ).show(); } - - + , visualizer = function ( submitted, override ) { - var lang, code + var lang, code, inline , stage = this.stage; if ( override ) { lang = override.lang; code = override.value; + inline = override.inline; } else { lang = this.lang[this.pSnippeCodeChoice = this.lang.selectedIndex].value; code = this.code.value; + inline = this.inline.checked ? "on" : ""; } var langName; @@ -124,7 +129,7 @@ if ( submitted && code ) { - if (!stage) + if ( !stage ) { // Visualize component temp = Dand.wrapc( @@ -136,8 +141,10 @@ , [ new DataKey( "value", code ) , new DataKey( "lang", lang ) + , new DataKey( "inline", inline ) ] ); + insertSnippet( j = snippetWrap( "Code", temp ), Boolean( override ) ); } else @@ -146,9 +153,10 @@ [ new DataKey( "value", code ) , new DataKey( "lang", lang ) + , new DataKey( "inline", inline ) ] ); - + temp = stage.firstChild; temp.removeChild( temp.firstChild ); stage.firstChild.appendChild( Dand.textNode( code ) ); @@ -160,9 +168,12 @@ temp = stage; } - - i = { _lang: lang, _content: code, _stage: temp }; - + + i = { _inline: inline, _lang: lang, _content: code, _stage: temp }; + + // Set the inline style + IDOMElement( j ).setAttribute( new DataKey( "inline", inline ) ); + // Set context menu createContext( i, j, handler ); } @@ -185,10 +196,11 @@ { // [code lang=\"" + lang + "\"]" + code + "[/code]" var element = IDOMElement( stage ) - , lang = element.getDAttribute( "lang" ); + , props= [ "lang", "inline" ]; return "[code" - + (lang ? (" lang=\"" + lang + "\"") : "") + "]" + + compileProp( element, props ) + + "]" + escapeStr( element.getDAttribute( "value" ) ) + "[/code]" ; diff --git a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Image.js b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Image.js index e387932..7f72294 100644 --- a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Image.js +++ b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Image.js @@ -31,11 +31,11 @@ , input_preferred = Dand.wrapna('input', new IKey("type", "checkbox")) ; - if (this._stage) + if ( this._stage ) { input_url.value = this._url; input_a.value = this._href; - input_preferred.checked = (this._preferred == "on"); + input_preferred.checked = ( this._preferred == "on" ); } // Popup MessageBox diff --git a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Link.js b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Link.js index 67039c3..3fe3c5b 100644 --- a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Link.js +++ b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Link.js @@ -37,8 +37,7 @@ , input_text , Dand.wrapc("v_instruction flsf", "Link to:") , input_a - ] - ) + ]) , "OK", "Cancel", visualizer.bind({text:input_text, href:input_a, stage: this._stage})).show(); } @@ -100,8 +99,7 @@ // Set context menu createContext(i, j, handler); } - } - ; + }; if (override) { diff --git a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js index b4fcced..9b7c23e 100644 --- a/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js +++ b/botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js @@ -165,6 +165,7 @@ var _resSelection = function () { + contentDiv.focus(); if ( selRange ) { if ( window.getSelection ) @@ -186,17 +187,18 @@ { if( !Dand.id( "v_linebreak" ) ) { - insertSnippet( lastLine, true ); + insertElement( lastLine, true ); } else { - insertSnippet( contentDiv.removeChild( lastLine ), true ); + insertElement( contentDiv.removeChild( lastLine ), true ); } }; - var insertAtCaret = function( element ) + var insertAtCaret = function( element, newLine ) { var sel, range; + if( newLine == undefined ) newLine = true; sel = window.getSelection(); if ( sel.getRangeAt && sel.rangeCount ) @@ -212,10 +214,11 @@ } e_document.updateContent(); - ensureLastLinebreak(); + + if( newLine ) ensureLastLinebreak(); }; - var insertSnippet = function( element, override ) + var insertElement = function( element, override ) { if ( override ) { @@ -223,7 +226,6 @@ return; } - contentDiv.focus(); _resSelection(); insertAtCaret( element ); }; @@ -283,7 +285,7 @@ if ( _module ) { // Visualize snippet - new ( _module )( insertSnippet, snippetWrap, createSnippetMenu, temp ); + new ( _module )( insertElement, snippetWrap, createSnippetMenu, temp ); } else { @@ -293,7 +295,7 @@ token.setAttribute( "class", token.getAttribute( "class" ) + " flsf" ); snippetQueue( type ).push([ token, temp ]); - insertSnippet( token, true ); + insertElement( token, true ); } }; @@ -397,7 +399,7 @@ snippetControls.appendChild( temp ); snippetControls.appendChild( Dand.textNode( "\t" ) ); - temp.onclick = new ( _module )( insertSnippet, snippetWrap, createSnippetMenu ); + temp.onclick = new ( _module )( insertElement, snippetWrap, createSnippetMenu ); var queue = snippetQueue( mod_name, _module.alias ); for( var i in queue ) @@ -479,6 +481,18 @@ this.saveSelection = _savSelection; this.restoreSelection = _resSelection; + this.insertAtCaret = insertAtCaret; + + this.insertSnippet = function( type, options ) + { + var _module = loadedModule[ type ]; + + new ( _module )( + // Disables the override + function( e ) { insertElement( e ); } + , snippetWrap, createSnippetMenu, options + ); + }; article.invoke(this); diff --git a/botanjs/src/Astro/Blog/AstroEdit/_this.js b/botanjs/src/Astro/Blog/AstroEdit/_this.js index 6fe4e24..91e4ff1 100644 --- a/botanjs/src/Astro/Blog/AstroEdit/_this.js +++ b/botanjs/src/Astro/Blog/AstroEdit/_this.js @@ -24,6 +24,9 @@ /** @type {Astro.Blog.AstroEdit.SiteLibrary} */ var SiteLibrary = __import( "Astro.Blog.AstroEdit.SiteLibrary" ); + // calls the smart bar + var SmartInput = __import( "Astro.Blog.AstroEdit.SmartInput" ); + var wh, ww, cw, html, article; var init = function () @@ -56,12 +59,15 @@ // Article modules new Draft( article, a_conf.paths.get_drafts ); - new Visualizer( + + var Vis = new Visualizer( article , Dand.id( "ae_visual_snippets" ) , Config.get( "ServiceUri" ) ); + new SmartInput( Vis ); + // Independent modules new Uploader( a_conf.paths.set_file ); new SiteLibrary( diff --git a/botanjs/src/Astro/Blog/Components/Entry/Blog.css b/botanjs/src/Astro/Blog/Components/Entry/Blog.css index aad0417..2eb560c 100644 --- a/botanjs/src/Astro/Blog/Components/Entry/Blog.css +++ b/botanjs/src/Astro/Blog/Components/Entry/Blog.css @@ -2,6 +2,12 @@ max-width: 100%; } +.inline-code { + font-family: monospace; + background-color: #EEE; + padding: 0.2em 0.5em; +} + .b_entry { background-color: #FAFAFA; /* box-shadow: 0 0 8px -2px black; */ diff --git a/botanjs/src/Astro/Blog/Components/Section.css b/botanjs/src/Astro/Blog/Components/Section.css index 12fab2f..b6c0018 100644 --- a/botanjs/src/Astro/Blog/Components/Section.css +++ b/botanjs/src/Astro/Blog/Components/Section.css @@ -11,7 +11,7 @@ opacity: 0.5; } -.section-buttons > a:hover, .section-buttons > a[active]:hover { +.section-buttons > a:hover, .section-buttons > a[data-active="1"]:hover { opacity: 0.8; text-decoration: none; } @@ -50,7 +50,7 @@ .section-buttons > a > span { padding: 0.75em 0.5em; } -.section-buttons > a[active] { +.section-buttons > a[data-active="1"] { opacity: 1; } .section-buttons > a > .count { diff --git a/botanjs/src/Astro/Blog/Layout/Login.js b/botanjs/src/Astro/Blog/Layout/Login.js index 1cf1d8b..133b775 100644 --- a/botanjs/src/Astro/Blog/Layout/Login.js +++ b/botanjs/src/Astro/Blog/Layout/Login.js @@ -26,11 +26,12 @@ var init = function () { + var username; var form = Dand.wrapne('form' , [ // Basic login and password fields , Dand.wrapc("flsf", "Name:") - , Dand.wrapna('input', [ field_username, new IKey("type", "text") ] ) + , username = Dand.wrapna('input', [ field_username, new IKey("type", "text") ] ) , Dand.wrapc("flsf", "Password:") , Dand.wrapna('input', [ field_password, new IKey("type", "password") ] ) @@ -42,13 +43,13 @@ new IKey('action', formAction) , new IKey('method', 'POST') ] - ) - ; - + ); var mbox = new MessageBox( "Blog.Astro", form, "Login", false, submitForm.bind( form ) ).show(); - // Handle enter button + username.focus(); + + // Handle enter button mbox.onkeyup = function( _e ) { if ( submitForm.bind( form )( _e.which == 13 ) ) diff --git a/botanjs/src/Astro/Build/Page/Index.css b/botanjs/src/Astro/Build/Page/Index.css index a448192..6e7945f 100644 --- a/botanjs/src/Astro/Build/Page/Index.css +++ b/botanjs/src/Astro/Build/Page/Index.css @@ -1,7 +1,10 @@ .site-news { font-family: monospace; } .site-news > span { display: block; } -.rbuilds > a { display: block; } +.rbuilds > a { + display: block; + font-family: monospace; +} .rbuilds > a > span { padding: 0 0.5em; } diff --git a/botanjs/src/externs/Astro.Blog.AstroEdit.Visualizer.js b/botanjs/src/externs/Astro.Blog.AstroEdit.Visualizer.js index 4cf2549..e36379c 100644 --- a/botanjs/src/externs/Astro.Blog.AstroEdit.Visualizer.js +++ b/botanjs/src/externs/Astro.Blog.AstroEdit.Visualizer.js @@ -9,4 +9,8 @@ Astro.Blog.AstroEdit.Visualizer.visualizeData; /** @type {Function} */ Astro.Blog.AstroEdit.Visualizer.saveSelection; /** @type {Function} */ +Astro.Blog.AstroEdit.Visualizer.insertAtCaret; +/** @type {Function} */ +Astro.Blog.AstroEdit.Visualizer.insertSnippet; +/** @type {Function} */ Astro.Blog.AstroEdit.Visualizer.restoreSelection;