(function(){ var ns = __namespace( "Astro.Blog.AstroEdit" ); /** @type {Dandelion} */ var Dand = __import( "Dandelion" ); /** @type {Dandelion.IDOMElement} */ var IDOMElement = __import( "Dandelion.IDOMElement" ); /** @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 {System.Net.ClassLoader} */ var Loader = __import( "System.Net.ClassLoader" ); /** @type {Components.MessageBox} */ var MessageBox = __import( "Components.MessageBox" ); /** @type {Components.Mouse.ContextMenu} */ var ContextMenu = __import( "Components.Mouse.ContextMenu" ); /** @type {Astro.Blog.Config} */ var Config = __import( "Astro.Blog.Config" ); var snippetList = IKey.quickDef( "Code" , "background: white; color: cornflowerblue;" , "Image" , "background: #ff0084;" , "Sound" , "background: YellowGreen;" , "Video" , "background: Crimson;" , "Spoiler" , "background: cornflowerblue;" , "Swf" , "background: #333;" , "Link" , "background: blue;" , "AcquireLib" , "background: black;" , "Html" , "background: coral;" , "SiteFile" , "background: royalblue;" ); var snippetNs = "Astro.Blog.AstroEdit.Visualizer.Snippet."; //// Document Visualizer visualize snippets, used in AstroEdit and comments var Visualizer = function ( e_document, snippetControls, service_uri ) { var Article = ns[ NS_INVOKE ]( "Article" ); var loadedModule = {}; //// Constants var article; // "[^]" does not work in IE var stackMatch = /\[([a-z][0-9a-z]*?)([\s\S]*?)\]([\s\S]*?)\[\/\1\]/ig; var typeMatch = /([a-z][0-9a-z]*)\=\"([^"]+)\"/ig; var snippetTokenQueue = {}; if ( e_document instanceof Article ) { article = e_document; // Allow Html snippet } else if ( e_document instanceof CeDocument ) { article = e_document; } else return; ////// Variables var contentDiv = Dand.wrap() var selRange; var snippetExists = false; var lastOffset = 0; var raw; ///// private methods var snippetWrap = function( snippetType, element, editable, _with ) { var snippet = Dand.wrap( _with || "div" , Perf.uuid , "comp v_boundary" , element , [ new IKey( "contentEditable", editable ? "true" : "false" ) , new DataKey( "type", snippetType ) ] ); return snippet; }; var appendLinebreak = function () { this.parentNode.insertBefore(Dand.wrap("br"), this.nextSibling); } var insertLinebreak = function () { this.parentNode.insertBefore(Dand.wrap("br"), this); }; var snippetDelete = function () { this.parentNode.removeChild(this); }; var snippetBBCode = function() { var snippet = IDOMElement( this ); var type = snippet.getDAttribute( "type" ).toLowerCase(); /** @type {Astro.Blog.AstroEdit.Visualizer.Snippet.Model} */ var module = loadedModule[ type ]; var title = "An error occurred"; var message = "No such module"; if( module ) { title = "BBCode for Snippet: " + type; message = module.compile( this.firstChild ); } new MessageBox( title, Dand.wrapne( "pre", message ) ).show(); }; var createSnippetMenu = function ( snippetProp, snippet, editHandler, snippetActions ) { var contextItems = [ editHandler && new EventKey( "Edit", editHandler.bind( snippetProp ) ) , new EventKey( "Insert a linebreak", insertLinebreak.bind( snippet ) ) , new EventKey( "Append a linebreak", appendLinebreak.bind( snippet ) ) , new EventKey( "Delete", snippetDelete.bind( snippet ) ) , new EventKey( "View BBCode", snippetBBCode.bind( snippet ) ) ]; e_document.updateContent(); if ( snippetActions instanceof Array ) { contextItems = snippetActions.concat( contextItems ); } return new ContextMenu( snippet, contextItems, "RMB" ); }; var _savSelection = function () { contentDiv.focus(); if ( window.getSelection ) { var sel = window.getSelection(); if ( sel.getRangeAt && sel.rangeCount ) { selRange = sel.getRangeAt(0); } } else if ( document.selection && document.selection.createRange ) { selRange = document.selection.createRange(); } else { selRange = null; } }; var _resSelection = function () { if ( selRange ) { if ( window.getSelection ) { var sel = window.getSelection(); sel.removeAllRanges(); sel.addRange( selRange ); } else if ( document.selection && selRange.select ) { selRange.select(); } } }; var lastLine = Dand.wrap( "br", "v_linebreak" ); var ensureLastLinebreak = function () { if( !Dand.id( "v_linebreak" ) ) { insertSnippet( lastLine, true ); } else { insertSnippet( contentDiv.removeChild( lastLine ), true ); } }; var insertAtCaret = function( element ) { var sel, range; sel = window.getSelection(); if ( sel.getRangeAt && sel.rangeCount ) { range = sel.getRangeAt(0); range.deleteContents(); range.insertNode( element ); range.setStartAfter( element ); range.setEndAfter( element ); range.collapse( false ); sel.removeAllRanges(); sel.addRange( range ); } e_document.updateContent(); ensureLastLinebreak(); }; var insertSnippet = function( element, override ) { if ( override ) { contentDiv.appendChild( element ); return; } contentDiv.focus(); _resSelection(); insertAtCaret( element ); }; var replaceToken = function( element ) { contentDiv.insertBefore( element, this.token ); contentDiv.removeChild( this.token ); }; var parseKeys = function ( match, name, value ) { this[ name ] = value; }; var snippetQueue = function( type, alias ) { var q = snippetTokenQueue[ type ] || []; if( alias ) { if( !( alias instanceof Array ) ) alias = [ alias ]; for( var i in alias ) { q = snippetTokenQueue[ alias[i] ] || []; if( q.length ) return q; } } return ( snippetTokenQueue[ type ] = q ); }; var parseSnippet = function( match, type, properties, _value, offset ) { var temp, i, j; // Texts goes first if ( lastOffset != offset ) { // innerText does not work in firefox:( temp = Dand.wrape( raw.substr( lastOffset, offset - lastOffset ) ); // innerHTML will escape html entities, now replace linebreaks to br temp.innerHTML = temp.innerHTML.replace(/[\r\n]/g, "
"); IDOMElement( contentDiv ).lootChildren( temp ); } lastOffset = offset + match.length; // Snippet Args temp = { value: _value }; // to ekeys properties.replace( typeMatch, parseKeys.bind( temp ) ); // Now deal with snippet /** @type {Astro.Blog.AstroEdit.Visualizer.Snippet.Model} */ var _module = loadedModule[ type ]; if ( _module ) { // Visualize snippet new ( _module )( insertSnippet, snippetWrap, createSnippetMenu, temp ); } else { // no such module, or module is not loaded yet debug.Info( "[Visualizer] Queueing: " + type ); var token = snippetWrap( "token", type, false ); token.setAttribute( "class", token.getAttribute( "class" ) + " flsf" ); snippetQueue( type ).push([ token, temp ]); insertSnippet( token, true ); } }; var linebreakNodes = ["P", "DIV"]; var linebreakNode = function( name ) { if( -1 < linebreakNodes.indexOf( name.toUpperCase() ) ) return "\n"; return ""; }; var ensureGoodness = function () { _savSelection(); ensureLastLinebreak(); }; var stepContent = function ( element, level ) { var j , snippetType , elements = element.childNodes , output = ""; for (var i = 0, l = elements.length; i < l; i ++) { j = elements[i]; // do nothing on lastline if (j == lastLine) continue; if (j.nodeType == 1) { snippetType = IDOMElement( j ).getDAttribute( "type" ); if( snippetType && loadedModule[ snippetType = snippetType.toLowerCase() ] ) { output += loadedModule[ snippetType ].compile( j.firstChild ); } else if ( j.firstChild ) { // Text output += linebreakNode( j.nodeName ) + stepContent(j, ++level); } else { // Handle special

=> one line break if(l == 1 && j.nodeName.toUpperCase() == "BR") continue; // Line breaks output += "\n"; } } // Text else if (j.nodeType == 3) { output += j.nodeValue; } } return output; }; ///// Initializations var snippetReady = function ( e ) { // Initialize modules var mod_name = e.substr( e.lastIndexOf(".") + 1, e.length ).toLowerCase() /** @type {Astro.Blog.AstroEdit.Visualizer.Snippet.Model} */ var _module = __import( e ); var alias = _module.alias; // Implement module if valid and available if ( _module && _module.compile ) { loadedModule[ mod_name ] = _module; debug.Info( "[Visualizer] Module loaded: " + mod_name ); // Set alias if ( alias ) { alias = ( alias instanceof Array ) ? alias : [ alias ]; for ( var k in alias ) { loadedModule[ alias[k] ] = _module; debug.Info( "[Visualizer] Alias: " + mod_name + " => " + alias ); } } // Append module"s control temp = Dand.wrapne( "span" , mod_name , new IKey( "style" , utils.objSearch( snippetList /** @param {System.utils.IKey} a */ , function( a ) { return a.keyName.toLowerCase() == mod_name } , "keyValue" ) ) ); snippetControls.appendChild( temp ); snippetControls.appendChild( Dand.textNode( "\t" ) ); temp.onclick = new ( _module )( insertSnippet, snippetWrap, createSnippetMenu ); var queue = snippetQueue( mod_name, _module.alias ); for( var i in queue ) { var token = queue[i]; new ( _module )( replaceToken.bind({ token: token[0] }), snippetWrap, createSnippetMenu, token[1] ); delete queue[i]; } } else { if ( _module ) { delete loadedModule[ mod_name ]; debug.Info( "[Visualizer] Module discarded: invalid module \"" + mod_name + "\"" ); } else { debug.Info( "[Visualizer] Module \"" + mod_name + "\" does not exists" ); } } }; this.setContentDiv = function( element ) { contentDiv = element; // listeners that return values cannot use addEventListener contentDiv.onkeypress = function(e) { if (e.which == 13) { insertAtCaret( Dand.wrap( "br" ) ); _savSelection(); return false; } return true; }; temp = IDOMElement( contentDiv ); temp.addEventListener( "Input", ensureGoodness ); temp.addEventListener( "KeyUp", ensureGoodness ); temp.addEventListener( "Click", ensureGoodness ); contentDiv.focus(); ensureGoodness(); try { document.execCommand( "insertBrOnReturn", false, "true" ); } catch(e) { debug.Info( "Not firefox" ); } }; this.saveRaw = function () { return stepContent( contentDiv, 0 ); }; this.visualizeData = function ( data ) { if ( !data ) return; lastOffset = 0; // clear content contentDiv.innerHTML = ""; ( raw = data ).replace( stackMatch, parseSnippet ); if ( lastOffset != raw.length ) { // innerText does not work in firefox:( temp = Dand.wrape( raw.substr( lastOffset, raw.length - lastOffset ) ); // innerHTML will escape html entities, now replace linebreaks to br temp.innerHTML = temp.innerHTML.replace( /[\r\n]/g, "
" ); IDOMElement( contentDiv ).lootChildren( temp ); } temp = null; raw = null; }; this.saveSelection = _savSelection; this.restoreSelection = _resSelection; article.invoke(this); var modules = []; for( var i in snippetList ) { modules[ modules.length ] = snippetNs + snippetList[i].keyName; } var ldr = new Loader( service_uri, "r" ); ldr.load( modules, snippetReady ); }; ns[ NS_EXPORT ]( EX_CLASS, "Visualizer", Visualizer ); })();