You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by br...@apache.org on 2016/12/17 21:21:41 UTC

[6/7] jspwiki git commit: Various HADDOCK updates & fixes

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki-edit/Undoable.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Undoable.js b/jspwiki-war/src/main/scripts/wiki-edit/Undoable.js
index 8adf99b..047739c 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Undoable.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Undoable.js
@@ -23,10 +23,9 @@ Class: UndoRedo
     Abstract class implements a simple undo/redo stack to save and restore
     the state of an "undo-able" object.
     The object needs to provide a {{getState()}} and a {{putState(obj)}} methods.
-    Prior to any changes, it should fire a "berforChange" event.
+    Prior to any changes, it should fire a "beforeChange" event.
     The undo and redo event trigger the corresponding actions.
 
-
 Options:
     maxundo - integer , maximal size of the undo and redo stack (default 20)
     redo - (optional) DOM element, will get a click handler to the redo() function
@@ -70,7 +69,7 @@ function swap(from, to){
 
     if( from[0] ){
 
-        to.push( this.getState() ); //current state
+        to[to.length] = this.getState(); //current state
         this.putState( from.pop() ); //new state
 
     }
@@ -102,7 +101,7 @@ this.Undoable = new Class({
 
                 //console.log("Undoable beforeChange:", undo.length);
 
-                undo.push( state || self.getState() );
+                undo[undo.length]= state || self.getState();
                 self.redo = [];
 
                 if( undo[maxundo] ){ undo.shift(); }

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Edit.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Edit.js b/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Edit.js
index 88e8a30..52ca266 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Edit.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Edit.js
@@ -23,7 +23,7 @@ Class: Wiki.Edit
     Wiki.Edit implements the JSPWiki plain editor, with support
     for JSPWIki's markup, suggestion popups, ajax based page preview, etc...
 
-    It uses an enhanced textarea based on the [Snipe] class.
+    It uses [Snipe] to enhance the plain textarea.
 */
 
 /*eslint-env browser*/
@@ -31,199 +31,207 @@ Class: Wiki.Edit
 
 !function( wiki ){
 
-var editform,
-    textarea,
-    snipe,
-    preview,
-    previewcache,
-    isLivePreview,
-    sectionsDropDown;
 
-wiki.add("#editform", function( element ){
+wiki.add("textarea#editorarea", function( main ){
 
-    editform = element;
-    textarea = getFormElement(".editor");
-    preview = getFormElement(".ajaxpreview");
-    isLivePreview = getFormElement("[data-cmd=livepreview]") || {};
+    var form = main.form, snipe, preview;
 
-    onbeforeunload( );
+    function getFormElem( selector ){  return form.getElement( selector );  }
 
-    if(!textarea) return;
+    onbeforeunload( window, main );
 
-    snipe = new Snipe( textarea, {
+    if( snipe = getFormElem("textarea.snipeable") ){
 
-        container: editform,
-        undoBtns: {
-            undo: getFormElement("[data-cmd=undo]"),
-            redo: getFormElement("[data-cmd=redo]")
-        },
-        snippets: wiki.Snips,
-        directsnips: wiki.DirectSnips,
-        onChange: livepreview.debounce(500)
+        snipe = new Snipe( snipe, {
+            container: form,
+            undoBtns: {
+                undo: getFormElem("[data-cmd=undo]"),
+                redo: getFormElem("[data-cmd=redo]")
+            },
+            snippets: wiki.Snips,
+            directsnips: wiki.DirectSnips
+        });
 
-    });
+        wiki.configPrefs(form, function(cmd, isChecked){
+            snipe.set(cmd, isChecked);
+        });
 
-    if( sectionsDropDown = getFormElement(".sections") ){
+        if( preview = getFormElem(".ajaxpreview") ){
 
-        new Snipe.Sections( sectionsDropDown, {
-           snipe: snipe,
-           parser: jspwikiSectionParser  //callback
+            snipe.addEvent("change", livepreview.pass([
+                preview,
+                getFormElem("[data-cmd=livepreview]") || {}
+            ], snipe));
+
+        }
+
+        new Snipe.Sections( snipe, {
+            main: main,
+            menu: getFormElem(".sections > ul"),
+            parser: jspwikiSectionParser
         });
+
     }
 
-    wiki.configPrefs( editform, function(cmd, isChecked){
-        snipe.set(cmd, isChecked); //and snipe will fire the change event
-    });
+});
 
-    wiki.resizer( snipe.toElement(), function(h){ preview.setStyle("height", h); });
 
-});
+/*
+Function: onbeforeunload
+    Install an onbeforeunload handler, which is called prior to unloading the page.
+    The user will get a warning in case the textarea was changed, without saving.
 
+    The onbeforeunload handler then gets removed on regular exit of the page.
 
-    /*
-    Function: getFormElement
-        Helper function : lookup first matching descendant DOM element from the editform
-    */
-    function getFormElement( selector ){
+*/
+function onbeforeunload( window, main ){
 
-        return editform.getElement( selector );
+    window.onbeforeunload = function(){
 
-    }
+        if( main.value != main.defaultValue ){
+
+            return "edit.areyousure".localize();
+
+        }
+    };
+
+    main.form.addEvent("submit", function(){
 
-    /*
-    Function: onbeforeunload
-        Install an onbeforeunload handler, which is called ""before"" the page unloads.
-        The user gets a warning in case the textarea was changed, without saving.
+        window.onbeforeunload = null;
 
-        The onbeforeunload handler then gets removed on regular exit of the page.
+    });
+}
 
-        wiki.editOBU(textarea);
 
-    */
-    function onbeforeunload( ){
+   /*
+Function: livepreview
+    Linked as onChange handler to Snipe.
+    Make AJAX call to the wiki server to convert the contents of the textarea
+    (wiki markup) to HTML.
+*/
 
-        window.onbeforeunload = function(){
+function livepreview(preview, previewToggle){
 
-            if( textarea.value != textarea.defaultValue ){
+    var content = this.get("value").trim(),
+        isEmpty = content == "",
+        name, link;
 
-                return "edit.areyousure".localize();
+    //console.log("**** change event", new Date().getSeconds() );
 
-            }
-        };
+    function updateWiki( hasBeenUpdated ){
 
-        editform.addEvent("submit", function(){
-            window.onbeforeunload = null;
-        });
-    }
+        preview.ifClass(!hasBeenUpdated, "loading");
+        if( hasBeenUpdated ){ wiki.update(); }
 
+    }
 
-   /*
-    Function: livepreview
-        Linked as onChange handler to the SnipEditor.
-        Make AJAX call to the backend to convert the contents of the textarea
-        (wiki markup) to HTML.
-        TODO: should work bothways. wysiwyg <-> wikimarkup
+    if( !previewToggle.checked ){
 
-    */
-    function livepreview( ){
+        //reset the preview area
+        if( preview.cache ){
+            preview.empty();
+            preview.cache = null;
+        }
 
-        var text = snipe.toElement().get("value"),
-            loading = "loading";
+    } else if( preview.cache != content ){
 
-        console.log("**** change event", new Date().getSeconds() );
+        preview.cache = content;
 
-        if( !isLivePreview.checked ){
+        preview.ifClass( isEmpty, "empty" );
 
-            //cleanup the preview area
-            console.log("cleanup");
-            if( previewcache ){
-                preview.empty();
-                previewcache = null;
-            }
+        if( isEmpty ){
 
-        } else if( previewcache != text ){
+            preview.innerHTML =  "preview.zone".localize();
+            return;
 
-            previewcache = text;
-            //return preview.set("html",preview.get("html")+" Lorem ipsum"); //test code
+        }
 
-            //console.log("**** invoke Request.HTML ",previewcache, wiki.XHRPreview)
-            new Request.HTML({
-                url: wiki.XHRPreview,
-                data: {
-                    page: wiki.PageName,
-                    wikimarkup: text
-                },
-                update: preview,
-                onRequest: function(){ preview.addClass(loading); },
-                onComplete: function(){
+        if( wiki.Context == "comment" ){
 
-                    preview.removeClass(loading);
-                    wiki.update();
+            name = $("authorname").value || wiki.UserName || "AnonymousCoward";
+            link = $("link").value;
+            if( link ){ name = "[{0}|{1}]".xsubs(name, link); }
 
-                }
-            }).send();
+            //add the comment signature to the preview;  simulating Comment.jsp
+            content += "\n\n%%signature\n{0}, [\\{CurrentTimePlugin}]\n/%\n".xsubs( name );
 
         }
-    }
 
-    /*
-    Function: jspwikiSectionParser
-        Convert a jspwiki-markup page into an array of page sections.
-        Sections are marked by jspwiki headers:  !, !!  or !!!
+        //return preview.set("html",preview.get("html")+" Lorem ipsum"); //test code
+
+        //console.log("**** invoke Request.HTML ",previewcache, wiki.XHRPreview)
+        new Request.HTML({
+            url: wiki.XHRPreview,
+            data: {
+                page: wiki.PageName,
+                wikimarkup: content
+            },
+            update: preview,
+            onRequest: updateWiki,
+            onComplete: updateWiki.pass(true)
 
-        This function is used as a callback for [Snip.Sections]
+        }).send();
+
+    }
+}
 
-    Returns:
-        This function returns a array of objects [{title, start, depth}]
-        title - (string) plain title of the section (no wiki markup)
-        start - (number) offset within the text string where this section starts
-        depth - (number) nesting level of the section 0,1...n
-    */
-    function jspwikiSectionParser( text ){
+/*
+Function: jspwikiSectionParser
+    Convert a jspwiki-markup page into an array of page sections.
+    Sections are marked by jspwiki headers:  !, !!  or !!!
 
-        var result = [],
-            DELIM = "\u00a4",
+    This function is used as a callback for [Snip.Sections]
 
-            tt = text
+Returns:
+    This function returns a array of objects [{title, start, depth}]
+    title - (string) plain title of the section (no wiki markup)
+    start - (number) offset within the text string where this section starts
+    depth - (number) nesting level of the section 0,1...n
+*/
+function jspwikiSectionParser( text ){
 
-                // mask confusing header markup inside a {{{ ... }}} but keep length of the text unchanged!
-                .replace(/\{\{\{([\s\S]*?)\}\}\}/g, function(match){
-                    return match.replace( /^!/mg, " " );
-                })
+    var result = [],
+        DELIM = "\u00a4",
 
-                // break string up into array of headers and section-bodies :
-                // [0] : text prior to the first header
-                // [1,odd] : header markup !, !! or !!!
-                // [2,even] : remainder of the section, starting with header title
-                .replace( /^([!]{1,3})/mg, DELIM + "$1" + DELIM )
+        tt = text
 
-                .split(DELIM),
+            // mask confusing header markup inside a {{{ ... }}} but keep length of the text unchanged!
+            .replace(/\{\{\{([\s\S]*?)\}\}\}/g, function(match){
+                return match.replace( /^!/mg, " " );
+            })
 
-            pos = tt.shift().length,  //get length of the first element, prior to first section
-            count = tt.length,
-            i, hlen, title;
+            // break string up into array of headers and section-bodies :
+            // [0] : text prior to the first header
+            // [1,odd] : header markup !, !! or !!!
+            // [2,even] : remainder of the section, starting with header title
+            .replace( /^([!]{1,3})/mg, DELIM + "$1" + DELIM )
 
-        for( i = 0; i < count; i = i + 2 ){
+            .split(DELIM),
 
-            hlen = tt[i].length;
-            //take first line
-            title = tt[i + 1].split(/[\r\n]/)[0]
+        pos = tt.shift().length,  //get length of the first element, prior to first section
+        count = tt.length,
+        i, hlen, title;
 
-                //remove unescaped(~) inline wiki markup __,"",{{,}}, %%(*), /%
-                .replace(/(^|[^~])(__|""|\{\{|\}\}|%%\([^\)]+\)|%%\S+\s|%%\([^\)]+\)|\/%)/g, "$1")
+    for( i = 0; i < count; i = i + 2 ){
 
-                //and remove wiki-markup escape chars ~
-                .replace(/~([^~])/g, "$1");
+        hlen = tt[i].length;
+        //take first line
+        title = tt[i + 1].split(/[\r\n]/)[0]
 
-            //depth: convert length of header markup (!!!,!!,!) into #depth-level:  3,2,1 => 0,1,2
-            result.push({ title: title, start: pos, depth: 3 - hlen });
-            pos += hlen + tt[i + 1].length;
+            //remove unescaped(~) inline wiki markup __,"",{{,}}, %%(*), /%
+            .replace(/(^|[^~])(__|""|\{\{|\}\}|%%\([^\)]+\)|%%\S+\s|%%\([^\)]+\)|\/%)/g, "$1")
 
-        }
+            //and remove wiki-markup escape chars ~
+            .replace(/~([^~])/g, "$1");
 
-        return result;
+        //depth: convert length of header markup (!!!,!!,!) into #depth-level:  3,2,1 => 0,1,2
+        result[ i/2 ] = { title: title, start: pos, depth: 3 - hlen };
+        pos += hlen + tt[i + 1].length;
 
     }
 
+    return result;
+
+}
 
 }( Wiki );

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Snips.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Snips.js b/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Snips.js
index 917e0bc..fe1a1ce 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Snips.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Snips.js
@@ -29,554 +29,532 @@ Wiki.DirectSnips = {
     '[' : ']',
     '{' : '}',
     "'" : {
-        snippet: "'",
-        scope: {
-            "[{" : "}]"  //plugin parameters
-          }
+    snippet: "'",
+    scope: {
+        "[{" : "}]"  //plugin parameters
+      }
     }
 };
 
 /*
 Function: snippets
 
-        Definitions for the JSPWiki editor commands.
+    Definitions for the JSPWiki editor commands.
 */
 
 Wiki.Snips = {
 
-        // Snipe predefined commands
-        find: { key: "f" },
-        undo: { event: "undo" },
-        redo: { event: "redo" },
-
-        // Configuration commands
-        wysiwyg: { event: 'config' },
-        smartpairs: { event: 'config' },
-        livepreview: { event: 'config' },
-        autosuggest: { event: 'config' },
-        tabcompletion: { event: 'config' },
-        previewcolumn: { event: 'config' },
-
-
-        // Simple shortcuts
-        br: {
-            key: "shift+enter",
-            snippet: "\\\\\n"
-        },
-        hr: "\n----\n",
-        lorem: "This is just some sample. Don\u2019t even bother reading it; you will just waste your time. Why do you keep reading? Do I have to use Lorem Ipsum to stop you? OK, here goes: Lorem ipsum dolor sit amet, consectetur adipi sicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Still reading? Gosh, you\u2019re impossible. I\u2019ll stop here to spare you.",
-        Lorem: { alias: "lorem" },
-
-
-        // simple inline tab completion commands
-        bold:   { key: "b", snippet: "__{bold}__" },
-        italic: { key: "i", snippet: "''{italic}''" },
-
-        mono:   { key: "m", snippet: "{{{monospaced text}}} " },
-        sub:    "%%sub {subscript text}/% ",
-        sup:    "%%sup {superscript text}/% ",
-        strike: "%%strike {strikethrough text}/% ",
-
-        // simple block tab completion commands
-        quote:  "\n%%quote\n{Quoted text}\n/%\n",
-        dl:     "\n;{term}:definition-text ",
-        pre:    "\n{{{\n{some preformatted block}\n}}}\n",
-        code:   "\n%%prettify \n{{{\n{/* some code block */}\n}}}\n/%\n",
-        table:  "\n||{heading-1} ||heading-2\n|cell11     |cell12\n|cell21     |cell22\n",
-        t: { alias: "table" },
-
-        me: { alias: "sign"},
-        sign: function(){
-            var name = Wiki.UserName || 'UserName';
-            return "\n\\\\ &mdash;" + name + ", "+ new Date().toISOString() + "\\\\ \n";
-        },
-
-        hDlg: {
-            suggest: { pfx:"(^|\n)([!]{1,3})$", match:"^([!]{1,3})(?:[^!])"},
-            hDlg: [Dialog.Selection, {
-                match: "=",  //exact match
-                body: {
-                    "!!!": "<span style='font-size:30px;xline-height:1;'>Header</span>",
-                    "!!": "<span style='font-size:24px;xline-height:30px;'>Title</span>",
-                    "!": "<span style='font-size:18px;xline-height:30px;'>Sub-title</span>",
-                    "{text}": "Normal Paragraph"
-                }
-            }]
-        },
-
-        now: { alias: "date" },
-        date: function( ){
-            return new Date().toISOString()+' ';
-            //return "[{Date value='" + d.toISOString() + "' }]"
-            //return "[{Date " + d.toISOString() + " }]"
-        },
-
-        tabs: {
-            nScope: {
-                "%%(":")",
-                "%%tabbedSection":"/%"
-            },
-            snippet:"%%tabbedSection \n%%tab-{tabTitle1}\ntab content 1\n/%\n%%tab-tabTitle2\ntab content 2\n/%\n/%\n "
-        },
-
-        img: "\n[{Image src='{img.jpg}' width='400px' height='300px' align='left' }]\n ",
-
-        imgSrcDlg:{
-            scope: { "[{Image":"}]" },
-            suggest: { pfx:"src='([^']*)'?$", match: "^([^']*)" },
-            imgSrcDlg: [ Dialog.Selection, {
-
-                caption: "Image Source",
-                onOpen: function( dialog ){
-
-                    var key = dialog.getValue();
-
-                    if( !key || (key.trim()=='') ){ key = Wiki.PageName + '/'; }
-
-                    Wiki.jsonrpc("/search/suggestions", [key, 30], function( result ){
-
-                        //console.log('jsonrpc result', result );
-                        if( result[1] /*length>1*/ ){
-
-                            dialog.setBody( result );
-
-                        } else {
-
-                            dialog.hide();
-
-                        }
-                    });
-                }
-            }]
-        },
-
-        imgAlignDlg: {
-            scope: { "[{Image":"}]" },
-            suggest: "align='\\w+'",
-            imgAlignDlg: "left|center|right"
+    // Snipe predefined commands
+    find: { key: "f" },
+    undo: { event: "undo" },
+    redo: { event: "redo" },
+
+    // Configuration commands
+    wysiwyg: { event: 'config' },
+    smartpairs: { event: 'config' },
+    livepreview: { event: 'config' },
+    autosuggest: { event: 'config' },
+    tabcompletion: { event: 'config' },
+    previewcolumn: { event: 'config' },
+
+
+    // Simple shortcuts
+    br: {
+        key: "shift+enter",
+        snippet: "\\\\\n"
+    },
+    hr: "\n----\n",
+    lorem: "This is just some sample. Don\u2019t even bother reading it; you will just waste your time. Why do you keep reading? Do I have to use Lorem Ipsum to stop you? OK, here goes: Lorem ipsum dolor sit amet, consectetur adipi sicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Still reading? Gosh, you\u2019re impossible. I\u2019ll stop here to spare you.",
+    Lorem: { alias: "lorem" },
+
+
+    // simple inline tab completion commands
+    bold:   { key: "b", snippet: "__{bold}__" },
+    italic: { key: "i", snippet: "''{italic}''" },
+
+    mono:   { key: "m", snippet: "{{{monospaced text}}} " },
+    sub:    "%%sub {subscript text}/% ",
+    sup:    "%%sup {superscript text}/% ",
+    strike: "%%strike {strikethrough text}/% ",
+
+    // simple block tab completion commands
+    quote:  "\n%%quote\n{Quoted text}\n/%\n",
+    dl:     "\n;{term}:definition-text ",
+    def: { alias: "dl" },
+    pre:    "\n{{{\n{some preformatted block}\n}}}\n",
+    code:   "\n%%prettify \n{{{\n{/* some code block */}\n}}}\n/%\n",
+    table:  "\n||{heading-1} ||heading-2\n|cell11     |cell12\n|cell21     |cell22\n",
+
+    me: { alias: "sign"},
+    sign: function(){
+        var name = Wiki.UserName || 'UserName';
+        return "\n%%signature\n" + name + ", "+ new Date().toISOString() + "\n/%\n";
+    },
+
+    now: { alias: "date" },
+    date: function( ){
+
+        //FIXME: better use the date&time preference
+        return new Date().toISOString()+' ';
+
+        //return "[{Date value='" + d.toISOString() + "' }]"
+        //return "[{Date " + d.toISOString() + " }]"
+    },
+
+    tabs: {
+        nScope: {
+        "%%(":")",
+        "%%tabbedSection":"/%"
         },
-
-        font: {
-            nScope: { "%%(":")" },
-            snippet: "%%(font-family:{font};) body /% "
-        },
-
-        fontDlg: {
-            scope: { "%%(":")" },
-            suggest: { pfx: "font-family:([^;\\)\\n\\r]*)$", match:"^([^;\\)\\n\\r]*)" },
-            fontDlg: [Dialog.Font, {}]
+        snippet:"%%tabbedSection \n%%tab-{tabTitle1}\ntab content 1\n/%\n%%tab-tabTitle2\ntab content 2\n/%\n/%\n "
+    },
+
+    img: "\n[{Image src='{img.jpg}' width='400px' height='300px' align='left' }]\n ",
+
+    imgSrcDlg:{
+        scope: { "[{Image":"}]" },
+        suggest: { lback:"src='([^']*)'?$", match: "^([^']*)" },
+        imgSrcDlg: Wiki.pageDialog("Image", "/search/suggestions")
+    },
+
+    imgAlignDlg: {
+        scope: { "[{Image":"}]" },
+        suggest: "align='\\w+'",
+        imgAlignDlg: "left|center|right"
+    },
+
+    font: {
+        nScope: { "%%(":")" },
+        snippet: "%%(font-family:{font};) body /% "
+    },
+
+    fontDlg: {
+        scope: { "%%(":")" },
+        suggest: {
+        lback: "font-family:([^;\\)\\n\\r]*)$",
+        match:"^([^;\\)\\n\\r]*)"
         },
+        fontDlg: [Dialog.Font, {}]
+    },
 
-        color: "%%(color:{#000000}; background:#ffffff;) {some text} /%",
+    color: "%%(color:{#000000}; background:#ffffff;) ${some text} /%",
 
-        colorDlg: {
-            scope: { '%%(': ')' },
-            suggest:"#[0-9a-fA-F]{0,6}",
-            colorDlg: [ Dialog.Color , {} ]
-         },
+    colorDlg: {
+        scope: { '%%(': ')' },
+        //  /\B#(?:[0-9a-f]{3}){1,2}\b/i
+        suggest:"\B#(?:[0-9a-f]{3}){1,2}\b",
+        colorDlg: [ Dialog.Color , {} ]
+     },
 
-        symbol: { alias: "chars" },
-        chars: "&entity;",
+    symbol: { alias: "chars" },
+    chars: "&entity;",
 
-        charsDlg: {
-            suggest: '&\\w+;?',
-            charsDlg: [ Dialog.Chars, { caption:"Special Chars".localize() }]
+    charsDlg: {
+        suggest: {
+        lback: /&\w*;?$/,
+        match: /^&\w*;?/
         },
-
-        icon: "%%icon-{}search /%",
-        iconDlg: {
-            scope: { "%%":"/%" },
-            suggest: "icon-\\S*",
-            iconDlg: [Dialog.Selection, {
-                cssClass:".dialog-horizontal",
-                body:{
-                    "icon-search":"<div class='icon-search'></div>",
-                    "icon-user":"<div class='icon-user'></div>",
-                    "icon-home":"<div class='icon-home'></div>",
-                    "icon-refresh":"<div class='icon-refresh'></div>",
-                    "icon-repeat":"<div class='icon-repeat'></div>",
-                    "icon-bookmark":"<div class='icon-bookmark'></div>",
-                    "icon-tint":"<div class='icon-tint'></div>",
-                    "icon-plus":"<div class='icon-plus'></div>",
-                    "icon-external-link":"<div class='icon-external-link'></div>",
-
-                    "icon-signin":"<div class='icon-signin'></div>",
-                    "icon-signout":"<div class='icon-signout'></div>",
-                    "icon-rss":"<div class='icon-rss'></div>",
-                    "icon-wrench":"<div class='icon-wrench'></div>",
-                    "icon-filter":"<div class='icon-filter'></div>",
-                    "icon-link":"<div class='icon-link'></div>",
-                    "icon-paper-clip":"<div class='icon-paper-clip'></div>",
-                    "icon-undo":"<div class='icon-undo'></div>",
-                    "icon-euro":"<div class='icon-euro'></div>",
-                    "icon-slimbox":"<div class='icon-slimbox'></div>",
-                    "icon-picture":"<div class='icon-picture'></div>",
-                    "icon-columns":"<div class='icon-columns'></div>"
-                }
-            }]
+        dialog: [ Dialog.Chars, {
+            caption:"dialog.character.entities".localize()
+        }]
+    },
+
+    icon: "%%icon-{!search} /%",
+    iconDlg: {
+        scope: { "%%":"/%" },
+        suggest: "icon-\\S*",
+        iconDlg: [Dialog.Selection, {
+        cssClass:".dialog-horizontal",
+        body:{
+            "icon-search":"<div class='icon-search'></div>",
+            "icon-user":"<div class='icon-user'></div>",
+            "icon-home":"<div class='icon-home'></div>",
+            "icon-refresh":"<div class='icon-refresh'></div>",
+            "icon-repeat":"<div class='icon-repeat'></div>",
+            "icon-bookmark":"<div class='icon-bookmark'></div>",
+            "icon-tint":"<div class='icon-tint'></div>",
+            "icon-plus":"<div class='icon-plus'></div>",
+            "icon-external-link":"<div class='icon-external-link'></div>",
+
+            "icon-signin":"<div class='icon-signin'></div>",
+            "icon-signout":"<div class='icon-signout'></div>",
+            "icon-rss":"<div class='icon-rss'></div>",
+            "icon-wrench":"<div class='icon-wrench'></div>",
+            "icon-filter":"<div class='icon-filter'></div>",
+            "icon-link":"<div class='icon-link'></div>",
+            "icon-paper-clip":"<div class='icon-paper-clip'></div>",
+            "icon-undo":"<div class='icon-undo'></div>",
+            "icon-euro":"<div class='icon-euro'></div>",
+            "icon-slimbox":"<div class='icon-slimbox'></div>",
+            "icon-picture":"<div class='icon-picture'></div>",
+            "icon-columns":"<div class='icon-columns'></div>"
+        }
+        }]
+    },
+
+    contextText: {
+        scope: { "%%":"/%" },
+        suggest: {
+        lback: /%%text-(\w*)$/,
+        //match: "^default|success|info|warning|danger|capitalize|lowercase|uppercase|smallcaps"
+        match: /^\w*/
         },
-
-        contextText: {
-            scope: { "%%":"/%" },
-            suggest: {pfx: "%%text-(\\w*)$", match: "^default|success|info|warning|danger" },
-            contextText: [Dialog.Selection, {
-                cssClass:".dialog-horizontal",
-                body:{
-                    primary:"<span class='text-primary'>primary</span>",
-                    success:"<span class='text-success'>success</span>",
-                    info:"<span class='text-info'>info</span>",
-                    warning:"<span class='text-warning'>warning</span>",
-                    danger:"<span class='text-danger'>danger</span>"
-                }
-            }]
+        contextText: [Dialog.Selection, {
+        cssClass:".dialog-horizontal",
+        body:{
+            primary:"<span class='text-primary'>primary</span>",
+            success:"<span class='text-success'>success</span>",
+            info:"<span class='text-info'>info</span>",
+            warning:"<span class='text-warning'>warning</span>",
+            danger:"<span class='text-danger'>danger</span>",
+            "":"",
+            capitalize:"<span class='text-capitalize'>capitalize</span>",
+            lowercase:"<span class='text-lowercase'>lowercase</span>",
+            uppercase:"<span class='text-uppercase'>uppercase</span>",
+            smallcaps:"<span class='text-smallcaps'>Small Caps</span>"
+        }
+        }]
+    },
+
+    contextBG: {
+        scope: { "%%":"/%" },
+        suggest: {
+        //lback: /%%(default|success|info|warning|error)$/,
+        //match: /^\w+/
+        lback: /%%(\w*)$/,
+        match: /^(default|success|info|warning|error)/
         },
-
-        contextBG: {
-            scope: { "%%":"/%" },
-            suggest: {pfx:"%%(default|success|info|warning|error)$", match:"^default|success|info|warning|error"},
-            contextBG: [Dialog.Selection, {
-                cssClass:".dialog-horizontal",
-                body:{
-                    "default":"<span class='default'>default</span>",
-                    success:"<span class='success'>success</span>",
-                    info:"<span class='info'>info</span>",
-                    warning:"<span class='warning'>warning</span>",
-                    error:"<span class='error'>error</span>"
-                }
-            }]
+        contextBG: [Dialog.Selection, {
+        cssClass:".dialog-horizontal",
+        body:{
+            "default":"<span class='default'>default</span>",
+            success:"<span class='success'>success</span>",
+            info:"<span class='info'>info</span>",
+            warning:"<span class='warning'>warning</span>",
+            error:"<span class='error'>error</span>"
+        }
+        }]
+    },
+
+    labelDlg: {
+        scope: { "%%":"/%" },
+        suggest: {
+        lback: /%%label-(\w*)$/,
+        //match: "^default|success|info|warning|danger"
+        match: /^\w*/
         },
+        labelDlg: [Dialog.Selection, {
+        cssClass:".dialog-horizontal",
+        body:{
+            "default":"<span class='label label-default'>default</span>",
+            primary:"<span class='label label-primary'>primary</span>",
+            success:"<span class='label label-success'>success</span>",
+            info:"<span class='label label-info'>info</span>",
+            warning:"<span class='label label-warning'>warning</span>",
+            danger:"<span class='label label-danger'>danger</span>"
+        }
+        }]
+    },
+
+    listDlg: {
+        scope: { "%%list-":"/%" },
+        suggest: {lback: "list-(?:[\\w-]+-)?(\\w*)$", match: "^\\w*" },
+        listDlg: [Dialog.Selection, {
+        cssClass:".dialog-horizontal",
+        body: "nostyle|unstyled|hover|group"
+        }]
+    },
+
+    tableDlg: {
+        scope: { "%%table-":"/%" },
+        suggest: {lback: "table-(?:[\\w-]+-)?(\\w*)$", match: "^\\w*" },
+        tableDlg: [Dialog.Selection, {
+        cssClass:".dialog-horizontal",
+        body: "sort|filter|striped|bordered|hover|condensed|fit"
+        }]
+    },
+
+    cssDlg: {
+        scope: { "%%":"/%" },
+        suggest: {lback:"%%([\\da-zA-Z-_]*)$", match:"^[\\da-zA-Z-_]+"},
+        cssDlg: [Dialog.Selection, {
+        caption: "dialog.styles".localize(),
+        cssClass: ".dialog-filtered",
+        body: {
+        "(css:value;)":"any css definitions",
+        "default":"Contextual <span class='info'>backgrounds</span>",
+        "text-{default}":"Contextual colors and other text styles",
+        "label-{default}":"<span class='label label-success'>Contextual labels</span>",
+        "badge":"Badges <span class='badge'>007</span>",
+        //"btn-default":"<span class='btn btn-xs btn-default'>Buttons</span>",
+        "collapse":"<b class='bullet'></b>Collapsible lists",
+        "list-{nostyle}":"List styles",
+        "table-{fit}":"Table styles",
+        "":"",
+        "add-css":"Add CSS",
+        alert: "Alert Box",
+        "accordion\n!Tab1\n{body1}\n!Tab2\nbody2\n": "Accordion",  //leftAccordion, rightAccordion, pillsAccordion, accordion-primary...
+        category: "<span class='category-link'>Category Link</span>",
+        carousel: "Carousel viewer",
+        columns: "Multi-column layout",
+        commentbox: "Comment Box",
+        graphBar: "Graph Bars",
+        lead:"<span class='lead-item'>LEAD text</span>",
+        "pills\n!Tab1\n{body1}\n!Tab2\nbody2\n":"Pills",
+        prettify: "Prettify syntax highlighter",
+        progress:"Progress Bars",
+        quote: "<div class='quote-item'>Quoted paragraph</div>",
+        scrollable: "Scrollable <span style='font-family:monospace; white-space:pre;'>preformatted</span> block",
+        "scrollable-image": "Scrollable Wide Images",
+        //reflection: "Image with reflection",
+        "under-construction":"<span class='under-construction small' style='display:inline-block;height:auto;margin-bottom:0'/>",
+        slimbox: "Slimbox viewer <span class='icon-slimbox'></span>",
+        "tabs\n!Tab1\n{body1}\n!Tab2\nbody2\n":"Tabs",
+        viewer: "Media viewer"
+
+        //"drop-caps":"Drop Caps",
+        //xflow:"wide content with scroll bars"
+        }
+        }]
+    },
 
-        labelDlg: {
-            scope: { "%%":"/%" },
-            suggest: {pfx: "%%label-(\\w*)$", match: "^default|success|info|warning|danger" },
-            labelDlg: [Dialog.Selection, {
-                cssClass:".dialog-horizontal",
-                body:{
-                    "default":"<span class='label label-default'>default</span>",
-                    primary:"<span class='label label-primary'>primary</span>",
-                    success:"<span class='label label-success'>success</span>",
-                    info:"<span class='label label-info'>info</span>",
-                    warning:"<span class='label label-warning'>warning</span>",
-                    danger:"<span class='label label-danger'>danger</span>"
-                }
-            }]
-        },
+    link: {
+        key:'l',
+        wysiwyg:'createlink',
+        snippet: "[description|{pagename or url}|link-attributes] "
+    },
 
-        listDlg: {
-            scope: { "%%list-":"/%" },
-            suggest: {pfx: "list-(?:[\\w-]+-)?(\\w*)$", match: "^\\w*" },
-            listDlg: [Dialog.Selection, {
-                cssClass:".dialog-horizontal",
-                body: "nostyle|unstyled|hover|group"
-            }]
-        },
 
-        tableDlg: {
-            scope: { "%%table-":"/%" },
-            suggest: {pfx: "table-(?:[\\w-]+-)?(\\w*)$", match: "^\\w*" },
-            tableDlg: [Dialog.Selection, {
-                cssClass:".dialog-horizontal",
-                body: "sort|filter|striped|bordered|hover|condensed|fit"
-            }]
+    linkPart3:{
+        suggest: {
+        lback: "\\[(?:[^\\|\\]]+\\|[^\\|\\]]+\\|)([^\\|\\[\\]\\n\\r]*)$",
+        match: "^[^\\|\\]\\n\\r]*"
         },
+        linkPart3: [ Dialog.Selection, {
+
+        caption: "dialog.link.attributes".localize(),
+        body: {
+            "link-attributes": "<i>no attributes</i>",
+            //"class='category'": "<span class='category-link'>Category Link</span>",
+            "class='viewer'": "Embedded Viewer",
+            "class='slimbox'": "Add a Slimbox Link <span class='icon-slimbox'/> ",
+            "class='slimbox-link'": "Change to Slimbox Link <span class='icon-slimbox'/> ",
+            "divider1": "",
+            "class='btn btn-primary'": "Button style (normal)",
+            "class='btn btn-xs btn-primary'": "Button style (small)",
+            "divider2": "",
+            "target='_blank'": "Open link in new tab"
+        }
+        }]
 
-        cssDlg: {
-            scope: { "%%":"/%" },
-            suggest: {pfx:"%%([\\da-zA-Z-_]*)$", match:"^[\\da-zA-Z-_]+"},
-            cssDlg: {
-                "(css:value;)":"any css definitions",
-                "default":"contextual backgrounds",
-                "text-default":"contextual text color",
-                "label-default":"<span class='label label-default'>contextual labels</span>",
-                "badge":"badges <span class='badge'>13</span>",
-                //"btn-default":"<span class='btn btn-xs btn-default'>Buttons</span>",
-                "collapse":"collapsable lists",
-                "list-nostyle":"list styles",
-                //progress:"Progress Bars",
-                "table-fit":"table styles",
-                "":"",
-                "add-css":"Add CSS",
-                alert: "Alert Box",
-                accordion: "Accordion",  //leftAccordion, rightAccordion, pillsAccordion, accordion-primary...
-                category: "Category Links",
-                carousel: "Carousel",
-                columns: "Multi-column layout",
-                commentbox: "Comment Box",
-                //graphBar
-                pills:"Pills",
-                prettify: "Prettify syntax highlighter",
-                scrollable: "Scrollable Preformatted block",
-                "scrollable-image": "Scrollable Wide Images",
-                //reflection: "Image with reflection",
-                slimbox: "Slimbox Viewer <span class='icon-slimbox'></span>",
-                //"under-construction": "<div class='under-construction'> </div>",
-                tabs:"Tabs",
-                viewer: "Media Viewer"
-
-//block styles
-//                quote:"<div class='quote'>Quoted paragraph</div>",
-//                lead:"<span class='lead'>LEAD text</span>",
-//                "drop-caps":"Drop Caps",
-                //xflow:"wide content with scroll bars"
-            }
-        },
+    },
 
-        link: {
-            key:'l',
-            wysiwyg:'createlink',
-            snippet: "[description|{pagename or url}|options] "
+    linkDlg: {
+        //match [link],  do not match [{, [[
+        //do not include the [ in the matched string
+        suggest: {
+        lback: /\[([^\|\[{\]\n\r]*)$/,
+        match: /^([^\|\[{\]\n\r]*)(?:[\]\n\r])/
         },
+        linkDlg: Wiki.pageDialog("Wiki Link", "/search/suggestions")
 
+    },
 
-        linkPart3:{
-            suggest: {
-                pfx: "\\[(?:[^\\|\\]]+\\|[^\\|\\]]+\\|)([^\\|\\[\\]\\n\\r]*)$",
-                match: "^[^\\|\\]\\n\\r]*"
-            },
-            linkPart3: {
-                //"class='category'": "Category link",
-                "class='viewer'": "Embedded Viewer",
-                "class='slimbox'": "Add a Slimbox Link <span class='icon-slimbox'/> ",
-                "class='slimbox-link'": "Change to Slimbox Link <span class='icon-slimbox'/> ",
-                "divide1": "",
-                "class='btn btn-primary'": "Button style (normal)",
-                "class='btn btn-xs btn-primary'": "Button style (small)",
-                "divide2": "",
-                "target='_blank'": "Open link in new tab"
-            }
-
+    linkPart2: {
+        //match [description|link], [description|link|...
+        //do not match [{, [[
+        //do not include the [ in the matched string
+        suggest: {
+        lback: /\[(?:[^\|\]]+\|)([^\|\[{\]\n\r]*)$/,
+        match: /^([^\|\[{\]\n\r]*)(?:[\]\|\n\r])/
         },
+        linkPart2: Wiki.pageDialog("Wiki Link", "/search/suggestions")
+    },
 
-        linkDlg: {
-
-            //match [description|link], [link] or [link,  do not match [{, [[
-            //match '[' + 'any char except \n, [, { or ]' at end of the string
-            //note: do not include the [ in the matched string
-            suggest: {
-                pfx: "\\[(?:[^\\|\\]]+\\|)?([^\\|\\[{\\]\\n\\r]*)$",
-                match: "^([^\\|\\[{\\]\\n\\r]*)(?:\\]|\\|)"
-            },
-
-            linkDlg: [ Dialog.Selection, {
 
-                caption: "Wiki Link",
-                onOpen: function( dialog ){
+    variableDlg: {
+        scope:{ '[{$':'}]'},
+        suggest: "\\w+",
+        variableDlg: "applicationname|baseurl|encoding|inlinedimages|interwikilinks|jspwikiversion|loginstatus|uptime|pagename|pageprovider|pageproviderdescription|page-styles|requestcontext|totalpages|username"
+    },
 
-                    var //dialog = this,
-                        key = dialog.getValue();
+    // Page access rights
+    allow: { alias: "acl" },
+    acl: "\n[{ALLOW {permission} principal }]\n",
 
-                    //if empty link, than fetch list of attachments of this page
-                    if( !key || (key.trim()=='') ){ key = Wiki.PageName + "/"; }
+    permission: {
+        scope:{ '[{ALLOW':'}]'},
+        suggest: { lback:"ALLOW (\\w*)$", match:"^\\w+" },
+        permission: [Dialog.Selection, {
+            caption: "dialog.permission".localize(),
+            cssClass:".dialog-horizontal",
+            body:"view|edit|modify|comment|rename|upload|delete"
+        }]
+    },
+    principal: {
+        scope:{ '[{ALLOW':'}]'},
+        suggest: { lback:"ALLOW \\w+ (?:[\\w,]+,)?(\\w*)$", match:"^\\w*" },
 
-                    Wiki.jsonrpc("/search/suggestions", [key, 30], function( result ){
+        principal: [ Dialog.Selection, {
 
-                        //console.log("jsonrpc result", result );
-                        if( result[0] /* length > 0 */ ){
+        caption: "dialog.principal".localize(),
+        onOpen: function( dialog ){
 
-                            dialog.setBody( result );
+            new Request({
+            url: Wiki.XHRPreview,
+            data: { page: Wiki.PageName, wikimarkup: "[{Groups}]" },
+            onSuccess: function(responseText){
 
-                        } else {
+                var body = "Anonymous|Asserted|Authenticated|All";
+                responseText = responseText.replace( /<[^>]+>/g,'').replace(/\s*,\s*/g,'|' ).trim();
+                if(responseText != ""){ body = body + '||' + responseText; }
 
-                            dialog.hide();
+                dialog.setBody(body);
 
-                        }
-                    });
-                }
-            }]
-        },
-
-        variableDlg: {
-            scope:{ '[{$':'}]'},
-            suggest: "\\w+",
-            variableDlg: "applicationname|baseurl|encoding|inlinedimages|interwikilinks|jspwikiversion|loginstatus|uptime|pagename|pageprovider|pageproviderdescription|page-styles|requestcontext|totalpages|username"
-        },
+            }
+            }).send();
 
-        // Page access rights
-        allow: { alias: "acl" },
-        acl: "\n[{ALLOW {permission} principal }]\n",
-
-        permission: {
-            scope:{ '[{ALLOW':'}]'},
-            suggest: { pfx:"ALLOW (\\w*)$", match:"^\\w+" },
-            permission: [Dialog.Selection, {
-                cssClass:".dialog-horizontal",
-                body:"view|edit|modify|comment|rename|upload|delete"
-            }]
+        }
+        }]
+
+    },
+
+    toc: {
+        nScope: { "[{":"}]" },
+        snippet:"\n[~{TableOfContents }]\n"
+    },
+
+    tocParams: {
+        scope:{ '[{TableOfContents':'}]'},
+        suggest: "\\s",
+        tocParams: [Dialog.Selection, {
+            caption: "dialog.toc.options".localize(),
+            body:{
+            " title='{Page contents}' ":"title",
+            " numbered='true' ":"numbered",
+            " prefix='{Chap. }' ":"chapter prefix"
+            }
+        }]
+    },
+
+    plugin: "\n[{{plugin} \n{=body}\n}]\n",
+
+    pluginDlg: {
+        //match [{plugin}]  do not match [[{
+        //match '[{' + 'any char except \n, or }]' at end of the string
+        //note: do not include the [ in the matched string
+        suggest: {
+            lback: "(^|[^\\[])\\[{(\\w*)(?:\\|\\])?$",
+            //lback: "(^|[^\\[])\\[{([^\\[\\]\\n\\r]*)(?:\\|\\])?$",
+            match: "^([^\\[\\]\\n\\r]*)\\}\\]"
         },
-        principal: {
-            scope:{ '[{ALLOW':'}]'},
-            suggest: { pfx:"ALLOW \\w+ (?:[\\w,]+,)?(\\w*)$", match:"^\\w*" },
-
-            principal: [ Dialog.Selection, {
+        pluginDlg: [ Dialog.Selection, {
+        caption: "dialog.plugin".localize(),
+        body: {
+        "ALLOW {permission} principal ": "Page Access Rights <span class='icon-unlock-alt' />",
+        "SET {name}='value'":"Set a Wiki variable",
+        "${varname}":"Get a Wiki variable",
+        "If name='{value}' page='pagename' exists='true' contains='regexp'\n\nbody\n":"IF plugin",
+        "SET alias='{pagename}'":"Set Page Alias",
+        "SET page-styles='prettify-nonum table-condensed-fit'":"Set Page Styles",
+        "SET sidebar='off'":"Hide Sidebar",
+        //"Table":"Advanced Tables",
+        //"Groups":"View all Wiki Groups",
+        "":"",
+        "Counter":"Insert a simple counter",
+        "PageViewPlugin":"Count Views of this page",
+        "CurrentTimePlugin format='yyyy mmm-dd'":"Insert Current Time",
+        "Denounce":"Denounce a link",
+        "Image src='{image.jpg}'":"Insert an Image <span class='icon-picture'></span>",
+        "IndexPlugin":"Index of all pages",
+
+        "InsertPage page='{pagename}'":"Insert another Page",
+        "ListLocksPlugin":"List page locks",
+        "RecentChangesPlugin":"Displays the recent changed pages",
+        "ReferredPagesPlugin page='{pagename}' type='local|external|attachment' depth='1..8' include='regexp' exclude='regexp'":"Incoming Links (referred pages)",
+        "ReferringPagesPlugin page='{pagename}' separator=',' include='regexp' exclude='regexp'":"Outgoing Links (referring pages)",
+        "Search query='{Janne}' max='10'":"Insert a Search query",
+        "TableOfContents ":"Table Of Contents ",
+        "UndefinedPagesPlugin":"List pages that are missing",
+        "UnusedPagesPlugin":"List pages that have been orphaned",
+        "WeblogArchivePlugin":"Displays a list of older weblog entries",
+        "WeblogEntryPlugin":"Makes a new weblog entry",
+        "WeblogPlugin page='{pagename}' startDate='300604' days='30' maxEntries='30' allowComments='false'":"Builds a weblog"
+        }
+        }]
 
-                caption: "Roles, Groups or Users",
-                onOpen: function( dialog ){
+    },
 
-                    new Request({
-                        url: Wiki.XHRPreview,
-                        data: { page: Wiki.PageName, wikimarkup: "[{Groups}]" },
-                        onSuccess: function(responseText){
 
-                            var body = "Anonymous|Asserted|Authenticated|All";
-                            responseText = responseText.replace( /<[^>]+>/g,'').replace(/\s*,\s*/g,'|' ).trim();
-                            if(responseText != ""){ body = body + '||' + responseText; }
+    lipstick: {
 
-                            dialog.setBody(body);
+        key: "control+enter",
+        snippet: "{format}",
+        nscope: { "[":"]" },
 
-                        }
-                    }).send();
+        suggest: function(textarea, caret /*, fromStart*/){
 
-                }
-            }]
+            return caret.thin ? null : { lback: "", match: textarea.getSelection() };
 
+        },
 
+        lipstick: [Dialog.Selection, {
 
-        },
+        cssClass: ".dialog-horizontal",
 
-        toc: {
-            nScope: { "[{":"}]" },
-            snippet:"\n[~{TableOfContents }]\n"
-        },
+        onBeforeOpen: function( dialog ){
 
-        tocParams: {
-            scope:{ '[{TableOfContents':'}]'},
-            suggest: "\\s",
-            tocParams: [Dialog.Selection, {
-                caption: "TOC options",
-                body:{
-                " title='{Page contents}' ":"title",
-                " numbered='true' ":"numbered",
-                " prefix='{Chap. }' ":"chapter prefix"
-                }
-            }]
-        },
+            var body = {},
+            textarea = dialog.options.relativeTo,
+            caret = textarea.getSelectionRange();
 
-        plugin: "\n[{{plugin}}]\n",
-
-        pluginDlg: {
-            //match [{plugin}]  do not match [[{
-            //match '[{' + 'any char except \n, or }]' at end of the string
-            //note: do not include the [ in the matched string
-            suggest: {
-                pfx: "(^|[^\\[])\\[{(\\w*)(?:\\|\\])?$",
-                //pfx: "(^|[^\\[])\\[{([^\\[\\]\\n\\r]*)(?:\\|\\])?$",
-                match: "^([^\\[\\]\\n\\r]*)\\}\\]"
-            },
-            pluginDlg: [ Dialog.Selection, {
-                caption: "Plugin",
-                body: {
-                "ALLOW {permission} principal ": "Page Access Rights <span class='icon-unlock-alt' />",
-                "SET {name}='value'":"Set a Wiki variable",
-                "${varname}":"Get a Wiki variable",
-                "If name='{value}' page='pagename' exists='true' contains='regexp'\n\nbody\n":"IF plugin",
-                "SET alias='${pagename}'":"Set Page Alias",
-                "SET page-styles='prettify-nonum table-condensed-fit'":"Set Page Styles",
-                "SET sidebar='off'":"Hide Sidebar",
-                //"Table":"Advanced Tables",
-                //"Groups":"View all Wiki Groups",
-                "":"",
-                "Counter":"Insert a simple counter",
-                "PageViewPlugin":"Count Views of this page",
-                "CurrentTimePlugin format='yyyy mmm-dd'":"Insert Current Time",
-                "Denounce":"Denounce a link",
-                "Image src='${image.jpg}'":"Insert an Image <span class='icon-picture'></span>",
-                "IndexPlugin":"Index of all pages",
-
-                "InsertPage page='${pagename}'":"Insert another Page",
-                "ListLocksPlugin":"List page locks",
-                "RecentChangesPlugin":"Displays the recent changed pages",
-                "ReferredPagesPlugin page='{pagename}' type='local|external|attachment' depth='1..8' include='regexp' exclude='regexp'":"Incoming Links (referred pages)",
-                "ReferringPagesPlugin page='{pagename}' separator=',' include='regexp' exclude='regexp'":"Outgoing Links (referring pages)",
-                "Search query='{Janne}' max='10'":"Insert a Search query",
-                "TableOfContents ":"Table Of Contents ",
-                "UndefinedPagesPlugin":"List pages that are missing",
-                "UnusedPagesPlugin":"List pages that have been orphaned",
-                "WeblogArchivePlugin":"Displays a list of older weblog entries",
-                "WeblogEntryPlugin":"Makes a new weblog entry",
-                "WeblogPlugin page='{pagename}' startDate='300604' days='30' maxEntries='30' allowComments='false'":"Builds a weblog"
-                }
-            }]
+            if( textarea.isCaretAtStartOfLine() ){
+                Object.append(body, {
+                    "\n{!!!}": "<span title='header'>H1</span>",
+                    "\n{!!}": "<span title='title'>H2</span>",
+                    "\n{!}": "<span title='sub-title'>H3</span>",
+                    "\n* {list item}": "<span class='icon-list-ul'/>",
+                    "\n# {list-item}": "<span class='icon-list-ol'/>",
+                    "divider-sol": ""
+                });
+            }
 
-        },
+            Object.append(body, {
+                "__{bold}__": "<span style='font-family:serif;'><b>B</b></span>",
+                "''{italic}''": "<span style='font-family:serif;'><i>I</i></span>",
+                "{{{monospaced}}} ": "<tt>&lt;/&gt;</tt>",
+                "{{{{code}}}}": "<span class='small' style='font-family:monospace;'>code</span>",
+                "divider1": "",
+                "[{link}]": "<span class='icon-link'/>",
+                //"[description|{link}|options]": "<span class='icon-link'/>",
+                "[{Image src='{image.jpg}'}]": "<span class='icon-picture'/>",
+                "[{{plugin}}]": "<span class='icon-puzzle-piece'></span>",
+                "%%style {body} /%":"<span style='font-family:monospace;'>%%</span>",
+                "divider2": "",
+                "%%(font-family:{font};) body /%":"<span style='font-family:serif;'>A</span><span style='font-family:sans-serif'>a</span>",
+                "&{entity};" : "<span style='font-family:cursive;'>&amp;</span>",
+                //"%%sub {subscript}/% ": "a<span class='sub'>n</span>",
+                //"%%sup {superscript}/% ": "a<span class='sup'>m</span>",
+                //"%%strike {strikethrough}/% ":"<span class='strike'>S</span>",
+                //"divider3": "",
+                "[{ALLOW {permission} principal }]":"<span class='icon-unlock-alt'></span>",
+                "\\\\\n":"<b>&para;</b>"
+            });
+
+            if( textarea.isCaretAtStartOfLine()
+            &&  textarea.isCaretAtEndOfLine()
+            &&  textarea.slice(caret.start,caret.end-1).indexOf("\n") > -1 ){
+                Object.append(body, {
+                "divider-code": "",
+                    "\n%%prettify\n{{{\n/* code block */\n{code}\n}}}\n/%\n": "<span class='small' style='font-family:monospace;'>code block</span>",
+                    "\n%%prettify\n{{{\n{pretiffied code block}\n}}}/%\n": "<span class='small pun' style='font-family:monospace;'>prettify</span>",
+                    "\n%%scrollable\n{{{\n{code block}\n}}}/%\n": "<span class='small' style='font-family:monospace;'>scrollable-code</span>"
+                });
+            }
 
-        selectBlock: {
-            suggest: function(workarea, caret /*, fromStart*/){
-
-                var selection = workarea.getSelection();
-
-                if( !caret.thin
-                  && workarea.isCaretAtStartOfLine()
-                  && workarea.isCaretAtEndOfLine()
-                  && selection.slice(0,-1).indexOf("\n") > -1 ){
-
-                     //console.log("got block selection" );
-                     return { pfx:"", match:workarea.getSelection() }
-                }
-            },
-
-            selectBlock: [Dialog.Selection, {
-                cssClass: ".dialog-horizontal",
-                body:{
-                    "\n{{{\n{code block}\n}}}\n": "<span style='font-family:monospace;'>code</span>",
-                    "\n%%scrollable\n{{{\n{code block}\n}}}/%\n": "<span style='font-family:monospace;'>scrollable-code</span>",
-                    "\n%%prettify\n{{{\n{pretiffied code block}\n}}}/%\n": "<span class='pun' style='font-family:monospace;'>prettify</span>"
-                }
-            }]
-        },
+            dialog.setBody(body);
 
-        selectStartOfLine: {
-            suggest: function(workarea, caret/*, fromStart*/ ){
-
-                var selection = workarea.getSelection();
-
-                if( !caret.thin
-                  && workarea.isCaretAtStartOfLine()
-                  && workarea.isCaretAtEndOfLine() ){
-
-                     //console.log("got start of line selection", caret);
-                     return { pfx:"", match:selection }
-                }
-            },
-
-            selectStartOfLine: [Dialog.Selection, {
-                cssClass: ".dialog-horizontal",
-                body:{
-                    "\n!!!{header}": "H1",
-                    "\n!!{header}": "H2",
-                    "\n!{header}": "H3",
-                    "__{bold}__": "<b>bold</b>",
-                    "''{italic}''": "<i>italic</i>",
-                    "{{{monospaced text}}} ": "<tt>mono</tt>",
-                    "{{{{code}}}}\n": "<span style='font-family:monospace;'>code</span>",
-                    "[description|{link}|options]": "<span class='icon-link'/>",
-                    "[{Image src='${image.jpg}'}]": "<span class='icon-picture'/>",
-                    "\n[{{plugin}}]\n": "<span class='icon-puzzle-piece'></span>"
-                }
-            }]
-        },
-        //Commands triggered by the selection of substrings:
-        //    lowest priority vs. other snippets
-        selectInline: {
-            suggest: function(workarea, caret/*, fromStart*/ ){
-
-                if(!caret.thin){
-                     //console.log("got selection", caret);
-                     return { pfx:"", match:workarea.getSelection() }
-                }
-            },
-
-            selectInline: [Dialog.Selection, {
-                cssClass: ".dialog-horizontal",
-                body:{
-                    "__{bold}__":"<b>bold</b>",
-                    "''{italic}''":"<i>italic</i>",
-                    "{{{monospaced text}}}":"<tt>mono</tt>",
-                    "{{{{code}}}}\n": "<span style='font-family:monospace;'>code</span>",
-                    "[description|{pagename or url}|options]":"<span class='icon-link'/>",
-                    "[{Image src='{image.jpg}'}]":"<span class='icon-picture'/>"
-                }
-            }]
         }
-
+        }]
+    }
 }
-

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki/Category.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki/Category.js b/jspwiki-war/src/main/scripts/wiki/Category.js
index 805dc06..da24d8c 100644
--- a/jspwiki-war/src/main/scripts/wiki/Category.js
+++ b/jspwiki-war/src/main/scripts/wiki/Category.js
@@ -61,7 +61,9 @@ Wiki.Category = function(element, pagename, xhrURL){
             url: xhrURL, //+"?page="+pagename,
             data: { page: decodeURIComponent(pagename) },
             update: popup,
-            onSuccess: function(){ popup.swapClass("loading", "active"); }
+            onSuccess: function(){
+                popup.swapClass("loading", "active");
+            }
         }).send();
     }
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki/Recents.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki/Recents.js b/jspwiki-war/src/main/scripts/wiki/Recents.js
index e9eab57..a9624c6 100644
--- a/jspwiki-war/src/main/scripts/wiki/Recents.js
+++ b/jspwiki-war/src/main/scripts/wiki/Recents.js
@@ -109,7 +109,7 @@ Wiki.Recents = new Class({
         if( items.indexOf( value ) < 0 ){
 
             //insert new item at the start of the list, and cap list on max 10 items
-            if( items.unshift(value) > 9){ items = items.slice(0, 9); }
+            items = [value].concat( items.slice(0, 8) );
             self.fireEvent("change", [self.items = items] );
 
         }

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki/Wiki.Behaviors.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki/Wiki.Behaviors.js b/jspwiki-war/src/main/scripts/wiki/Wiki.Behaviors.js
index 69320d7..3f4a65a 100644
--- a/jspwiki-war/src/main/scripts/wiki/Wiki.Behaviors.js
+++ b/jspwiki-war/src/main/scripts/wiki/Wiki.Behaviors.js
@@ -67,6 +67,27 @@ var TheSlimbox, T = TableX;
 
 
 /*
+Behavior: Broken images
+    Replace broken image browser icons
+*/
+wiki.once( "img", function(imgs){
+
+    imgs.addEvent("error", function(){
+
+        var img = $(this);
+        [ "span.danger.img-error", {
+            text: "broken.image".localize() //Broken Image!
+        }, [
+            "span", { text: img.alt || img.src }
+            ]
+        ].slick().replaces(img);
+
+    });
+
+});
+
+
+/*
 Behavior: GraphBars, Progress-bars
 
 %%progress 50 /%
@@ -88,13 +109,13 @@ wiki.add("*[class^=progress]", function(element){
         maxv = RegExp.$2;
     }
 
-    ( element.get("tag") + clazz + "-maxv" + maxv ).slick().wraps(element);
+    ( element.get("tag") + clazz + "-minv0-maxv" + maxv  ).slick().wraps(element);
     element.className = "gBar";
 
 
 /*
-%%progress-red-striped 50/%  =>  %%graphBars-progress-red-striped-maxv100 %%gBar 50/% /%
-%%progress-red-striped 50/75 /%  =>  %%graphBars-progress-red-striped-maxv75 %%gBar 50/% /%
+%%progress-red-striped 50/%  =>  %%graphBars-progress-red-striped-minv0-maxv100 %%gBar 50/% /%
+%%progress-red-striped 50/75 /%  =>  %%graphBars-progress-red-striped-minv0-maxv75 %%gBar 50/% /%
 
 */
 
@@ -207,7 +228,7 @@ Behavior: Viewer
 >     %%viewer [link to youtube, vimeo, some-wiki-page, http://some-external-site ..] /%
 >     [description | url to youtube... | class="viewer"]
 */
-    .add("a.viewer, div.viewer a", function( a ){
+    .add("a.viewer, div.viewer a, span.viewer a", function( a ){
 
         Viewer.preload(a.href, { width: 800, height: 600 }, function( element ){
 
@@ -218,6 +239,18 @@ Behavior: Viewer
 
         });
 
+    })
+    .add("div.maps, span.maps", function( map ){
+
+        var address = map.get("text").trim(),
+            url = "https://maps.google.com/maps?q=" +encodeURIComponent( address );
+
+        Viewer.preload(url, { width: 800, height: 600 }, function( element ){
+
+            element.addClass("viewport").replaces(map);
+
+        });
+
     });
 
 
@@ -278,12 +311,14 @@ function filterJSPWikiLinks(element){
         element.getElements( element.match(".slimbox-attachments") ?
             "a[href].attachment" :
             // otherwise,  catch several different cases in one go
+            //    img:not([href$=/attachment_small.png]):not(.outlink)  ::jspwiki small icons
             //    img:not([src$=/attachment_small.png]):not(.outlink)  ::jspwiki small icons
             //    a[href].attachment,
             //    a[href].external,
             //    a[href].wikipage,
             //    a[href].interwiki
-            "img:not([src$=/attachment_small.png]):not(.outlink),a[href].attachment,a[href].external,a[href].wikipage, a[href].interwiki"
+            //    .recentchanges td:not(:nth-child(3)) a:first-child
+            "img:not([href$=/attachment_small.png]):not([src$=/attachment_small.png]):not(.outlink),a[href].attachment,a[href].external,a[href].wikipage, a[href].interwiki, .recentchanges td:not(:nth-child(3n)) a:first-child"
         );
 }
 
@@ -411,7 +446,7 @@ Behavior:Columns
 
 >    %%columns(-width) .. /%
 */
-    .add( "div[class~=columns]", Columns, { prefix: "columns" } )
+    .add( "div[class^=columns]", Columns, { prefix: "columns" } )
 
 /*
 Dynamic Style: Code-Prettifier
@@ -428,18 +463,19 @@ Example:
 >    }}} /%
 
 */
-    .add("div.prettify pre, div.prettify code", function(element){
+    .add("div.prettify:not(.prettyprint) pre, div.prettify:not(.prettyprint) code", function(element){
 
         element.addClass("prettyprint");
 
         //brute-force line-number injection
-        "pre.prettylines".slick({
+        "div".slick().wraps(element).grab(
+            "pre.prettylines".slick({
 
-            html: element.innerHTML.trim().split("\n").map( function(line, i){
-                return i + 1; }
-            ).join("\n")
+                html: element.innerHTML.trim().split("\n").map( function(line, i){
+                    return i + 1; }
+                ).join("\n")
 
-        }).inject(element, "before");
+            }),"top");
 
     })
     .add("[class~=prettify-nonum] pre, [class~=prettify-nonum] code", function(element){
@@ -510,7 +546,7 @@ Behavior: Table behaviors
                 ztoa: "sort.descending"
             }, String.localize);
 
-        while( args[0] ){
+        while( args && args[0] ){
 
             arg = args.shift();
 
@@ -655,7 +691,7 @@ Behavior: DropCaps
 
         var content, node = element.firstChild;
 
-        if( node.nodeType == 3 ){   // this is a text-node
+        if( node.nodeType == 3 ){   // aha, this is a text-node
 
             content = node.textContent.trim();
             node.textContent = content.slice(1);  //remove first character
@@ -675,7 +711,6 @@ Behavior: Add-CSS
     .add(".add-css", AddCSS)
 
 
-
 /*
 Behavior: Invisibles
     Show hidden characters such as tabs and line breaks.
@@ -692,7 +727,7 @@ CSS:
 .token.lf:before { content: '\240A'; }
 (end)
 */
-    .add(".invisibles pre", function(element){
+    .add(".invisibles pre, .reveal pre", function(element){
 
         var token = "<span class='token {0}'>$&</span>";
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki/Wiki.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki/Wiki.js b/jspwiki-war/src/main/scripts/wiki/Wiki.js
index 841c39c..7455244 100644
--- a/jspwiki-war/src/main/scripts/wiki/Wiki.js
+++ b/jspwiki-war/src/main/scripts/wiki/Wiki.js
@@ -77,8 +77,6 @@ var Wiki = {
 
             .add( "[accesskey]", Accesskey )
 
-            //.add("input[placeholder]", function(element){ element.placeholderX(); })
-
             //toggle effect:  toggle .active class on this element when clicking toggle element
             //.add("[data-toggle]", "onToggle", {attr:"data-toggle"})
             .add( "[data-toggle]", function(element){
@@ -94,24 +92,30 @@ var Wiki = {
 
             //generate modal confirmation boxes, eg prompting to execute
             //an unrecoverable action such as deleting a page or attachment
-            //.add("[data-toggle]", "onModal", {attr:"data-modal"})
+            //.add("[data-modal]", "onModal", {attr:"data-modal"})
             .add( "[data-modal]", function(element){
                 element.onModal( element.get("data-modal") );
             })
 
-            //hover effects: show/hide this element when hovering over its parent element
+            //hover effects: show/hide this element when hovering over the parent element
             //.add("[data-toggle]", "onHover", {attr:"data-hover-parent"})
             .add( "[data-hover-parent]", function(element){
                 element.onHover( element.get("data-hover-parent") );
             })
 
+            //resize the "data-resize" elements when dragging this element
+            //.add( "[data-resize]", wiki.resizer.bind(wiki) )
+            .add( "[data-resize]", function(element){
+                wiki.resizer(element, $$(element.get("data-resize")) );
+            })
+
             //make navigation bar sticky (simulate position:sticky; )
             //.add(".sticky", "onSticky" )
             .add( ".sticky", function(element){
                 element.onSticky();
             })
 
-            //highlight previous search query in cookie or referrer page
+            //highlight previous search query retreived from a cookie or referrer page
             .add( ".page-content", function(element){
 
                 var previousQuery = "PrevQuery";
@@ -178,13 +182,18 @@ var Wiki = {
 
     caniuse: function( body ){
 
+        //Is not really needed anymore,  since we added a css "hack" to workaround an IE bug
+        //Still kept here as a placeholder for future feature-sniffing
+
+
         //Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
         var hasNativeFlex = document.createElement('b');
 
         hasNativeFlex.style.cssText = "flex-basis:1px;";
-        if(!!hasNativeFlex.style.length){
+        if( hasNativeFlex.style.length ){
             body.addClass("can-flex");
-        };
+        }
+
 
     },
 
@@ -218,6 +227,7 @@ var Wiki = {
 
 
         //wiki.url = null;  //CHECK:  why this is needed?
+        //console.log( wiki.prefs.get("SectionEditing") , wiki.EditPermission ,wiki.Context );
         if( wiki.prefs.get("SectionEditing") && wiki.EditPermission && (wiki.Context != "preview") ){
 
             wiki.addEditLinks( wiki.toUrl( wiki.PageName, true ) );
@@ -337,8 +347,8 @@ var Wiki = {
 
     /*
     Function: dropdowns
-        Parse wikipages such ase MoreMenu, HomeMenu to act as bootstrap
-        compatible dropdown menu items.
+        Parse special wikipages such ase MoreMenu, HomeMenu
+        and format them as bootstrap compatible dropdown menus.
     */
     dropdowns: function(){
 
@@ -366,18 +376,18 @@ var Wiki = {
 
         /* (deprecated) "pre-HADDOCK" moremenu style
               Consists of a list of links, with \\ delimitters
-              Each <p> becomes a set of li, one for each link
-              The block is terminated with a divider, if more <p's> are coming
+              Each <p> becomes a set of <li>, one for each link
+              The block is terminated with a divider, if more <p>'s are coming
         */
         $$( "ul.dropdown-menu > li.more-menu > p" ).each( function(element){
 
             var parentLi = element.getParent();
 
             element.getElements('a').each( function(link){
-                ['li',[link]].slick().inject(parentLi, "before");
+                ["li",[link]].slick().inject(parentLi, "before");
             });
-            if( element.getNext('p *,hr') ){
-                'li.divider'.slick().inject(parentLi, "before") ;
+            if( element.getNext("p *,hr") ){
+                "li.divider".slick().inject(parentLi, "before") ;
             }
             element.dispose();
 
@@ -390,7 +400,9 @@ var Wiki = {
         Returns the list of all section headers, excluding the header of the Table Of Contents.
     */
     getSections: function(){
+
         return $$(".page-content [id^=section]:not(#section-TOC)");
+
     },
 
     /*
@@ -500,7 +512,9 @@ var Wiki = {
 
         //Persist the selected editor type in the pref cookie
         form.getElements("a.editor-type").addEvent("click", function(){
+
             wiki.prefs.set("editor", this.get("text"));
+
         });
 
     },
@@ -544,7 +558,6 @@ var Wiki = {
 
             }
         }
-
     },
 
     getXHRPreview: function( getContent, previewElement ){
@@ -575,7 +588,7 @@ var Wiki = {
     },
 
     /*
-    Function: resizer
+    Behavior: resizer
         Resize the target element, by dragging a .resizer handle.
         Multiple elements can be resized via the callback.
         The .resizer element can specify a prefs cookie to retrieve/store the height.
@@ -590,38 +603,86 @@ var Wiki = {
         textarea - resizable textarea (DOM element)
         preview - preview (DOM element)
     */
-    resizer: function( target, callback ){
+    /*
+    wiki.add(".resizer",function(element){...}
+
+
+    [data-resize] : resize target,  can be multiple elements
+
+    div.resizer[data-resize=".pagecontent"] => for add-comment sections
+    div.resizer[data-resize=".ajaxpreview,.snipeable"][data-pref=editorHeight]
+    */
+    resizer: function( handle, targets, dragCallback ){
+
+        var pref = handle.get("data-pref"),
+            prefs = this.prefs,
+            target;
 
-        var prefs = this.prefs,
-            handle = document.getElement(".resizer"),
-            pref = handle.getAttribute("data-pref"),
-            h;
+        function showDragState(add){ handle.ifClass(add, "dragging"); }
 
-        function helpdragging(add){ handle.ifClass(add, "dragging"); }
+        if( !targets[0] ){ return; }
 
-        //targets.setStyle(height, options.initial || "100%" );
+        //set the initial size of the targets
         if( pref ){
-            h = prefs.get(pref) || 300;
-            target.setStyle("height", h );
-            callback( h );
+            targets.setStyle("height", prefs.get(pref) || 300 );
         }
 
+        target = targets.pop();
+
         target.makeResizable({
             handle: handle,
             modifiers: { x: null },
             onDrag: function(){
-                h = this.value.now.y;
-                callback(h);
-                if(pref){ prefs.set(pref, h); }
+                var h = this.value.now.y;
+                if( pref ){ prefs.set(pref, h); }
+                if( targets ){ targets.setStyle("height", h); }
+                if( dragCallback ){ dragCallback(h); }
             },
-            onBeforeStart: helpdragging.pass(true),
-            onComplete: helpdragging.pass(false),
-            onCancel: helpdragging.pass(false)
+            onBeforeStart: showDragState.pass(true),
+            onComplete: showDragState.pass(false),
+            onCancel: showDragState.pass(false)
         });
 
     },
 
 
+    pageDialog: function( caption, method ){
+
+        var wiki = this;
+
+        return [ Dialog.Selection, {
+
+            caption: caption,
+
+            onOpen: function( dialog ){
+
+                var key = dialog.getValue();
+
+                //if empty link, than fetch list of attachments of the open page
+                if( !key || (key.trim()=='') ){
+
+                    key = wiki.PageName + "/";
+
+                }
+
+                wiki.jsonrpc( method, [key, 30], function( result ){
+
+                    //console.log("jsonrpc result", result, !!result[0] );
+                    if( result[0] /* length > 0 */ ){
+
+                        dialog.setBody( result );
+
+                    } else {
+
+                        dialog.hide();
+
+                    }
+                });
+            }
+        }];
+
+    },
+
     /*
     Function: jsonrpc
         Generic json-rpc routines to talk to the backend jspwiki-engine.
@@ -652,10 +713,11 @@ var Wiki = {
                 url: this.JsonUrl + method,
                 //method:"post"     //defaults to "POST"
                 //urlEncoded: true, //content-type header = www-form-urlencoded + encoding
-                //encoding: utf-8,
+                //encoding: "utf-8",
+                //encoding: "ISO-8859-1",
                 onSuccess: function( responseText ){
 
-                    //console.log(responseText, JSON.parse( responseText ) );
+                    console.log(responseText, JSON.parse( responseText ), responseText.charCodeAt(8),responseText.codePointAt(8), (encodeURIComponent(responseText)), encodeURIComponent("�"), encodeURIComponent("�")  );
                     callback( JSON.parse( responseText ) )
 
                 },

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/styles/haddock/bootstrap/.csscomb.json
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/styles/haddock/bootstrap/.csscomb.json b/jspwiki-war/src/main/styles/haddock/bootstrap/.csscomb.json
new file mode 100755
index 0000000..40695a4
--- /dev/null
+++ b/jspwiki-war/src/main/styles/haddock/bootstrap/.csscomb.json
@@ -0,0 +1,304 @@
+{
+  "always-semicolon": true,
+  "block-indent": 2,
+  "color-case": "lower",
+  "color-shorthand": true,
+  "element-case": "lower",
+  "eof-newline": true,
+  "leading-zero": false,
+  "remove-empty-rulesets": true,
+  "space-after-colon": 1,
+  "space-after-combinator": 1,
+  "space-before-selector-delimiter": 0,
+  "space-between-declarations": "\n",
+  "space-after-opening-brace": "\n",
+  "space-before-closing-brace": "\n",
+  "space-before-colon": 0,
+  "space-before-combinator": 1,
+  "space-before-opening-brace": 1,
+  "strip-spaces": true,
+  "unitless-zero": true,
+  "vendor-prefix-align": true,
+  "sort-order": [
+    [
+      "position",
+      "top",
+      "right",
+      "bottom",
+      "left",
+      "z-index",
+      "display",
+      "float",
+      "width",
+      "min-width",
+      "max-width",
+      "height",
+      "min-height",
+      "max-height",
+      "-webkit-box-sizing",
+      "-moz-box-sizing",
+      "box-sizing",
+      "-webkit-appearance",
+      "padding",
+      "padding-top",
+      "padding-right",
+      "padding-bottom",
+      "padding-left",
+      "margin",
+      "margin-top",
+      "margin-right",
+      "margin-bottom",
+      "margin-left",
+      "overflow",
+      "overflow-x",
+      "overflow-y",
+      "-webkit-overflow-scrolling",
+      "-ms-overflow-x",
+      "-ms-overflow-y",
+      "-ms-overflow-style",
+      "clip",
+      "clear",
+      "font",
+      "font-family",
+      "font-size",
+      "font-style",
+      "font-weight",
+      "font-variant",
+      "font-size-adjust",
+      "font-stretch",
+      "font-effect",
+      "font-emphasize",
+      "font-emphasize-position",
+      "font-emphasize-style",
+      "font-smooth",
+      "-webkit-hyphens",
+      "-moz-hyphens",
+      "hyphens",
+      "line-height",
+      "color",
+      "text-align",
+      "-webkit-text-align-last",
+      "-moz-text-align-last",
+      "-ms-text-align-last",
+      "text-align-last",
+      "text-emphasis",
+      "text-emphasis-color",
+      "text-emphasis-style",
+      "text-emphasis-position",
+      "text-decoration",
+      "text-indent",
+      "text-justify",
+      "text-outline",
+      "-ms-text-overflow",
+      "text-overflow",
+      "text-overflow-ellipsis",
+      "text-overflow-mode",
+      "text-shadow",
+      "text-transform",
+      "text-wrap",
+      "-webkit-text-size-adjust",
+      "-ms-text-size-adjust",
+      "letter-spacing",
+      "-ms-word-break",
+      "word-break",
+      "word-spacing",
+      "-ms-word-wrap",
+      "word-wrap",
+      "-moz-tab-size",
+      "-o-tab-size",
+      "tab-size",
+      "white-space",
+      "vertical-align",
+      "list-style",
+      "list-style-position",
+      "list-style-type",
+      "list-style-image",
+      "pointer-events",
+      "-ms-touch-action",
+      "touch-action",
+      "cursor",
+      "visibility",
+      "zoom",
+      "flex-direction",
+      "flex-order",
+      "flex-pack",
+      "flex-align",
+      "table-layout",
+      "empty-cells",
+      "caption-side",
+      "border-spacing",
+      "border-collapse",
+      "content",
+      "quotes",
+      "counter-reset",
+      "counter-increment",
+      "resize",
+      "-webkit-user-select",
+      "-moz-user-select",
+      "-ms-user-select",
+      "-o-user-select",
+      "user-select",
+      "nav-index",
+      "nav-up",
+      "nav-right",
+      "nav-down",
+      "nav-left",
+      "background",
+      "background-color",
+      "background-image",
+      "-ms-filter:\\'progid:DXImageTransform.Microsoft.gradient",
+      "filter:progid:DXImageTransform.Microsoft.gradient",
+      "filter:progid:DXImageTransform.Microsoft.AlphaImageLoader",
+      "filter",
+      "background-repeat",
+      "background-attachment",
+      "background-position",
+      "background-position-x",
+      "background-position-y",
+      "-webkit-background-clip",
+      "-moz-background-clip",
+      "background-clip",
+      "background-origin",
+      "-webkit-background-size",
+      "-moz-background-size",
+      "-o-background-size",
+      "background-size",
+      "border",
+      "border-color",
+      "border-style",
+      "border-width",
+      "border-top",
+      "border-top-color",
+      "border-top-style",
+      "border-top-width",
+      "border-right",
+      "border-right-color",
+      "border-right-style",
+      "border-right-width",
+      "border-bottom",
+      "border-bottom-color",
+      "border-bottom-style",
+      "border-bottom-width",
+      "border-left",
+      "border-left-color",
+      "border-left-style",
+      "border-left-width",
+      "border-radius",
+      "border-top-left-radius",
+      "border-top-right-radius",
+      "border-bottom-right-radius",
+      "border-bottom-left-radius",
+      "-webkit-border-image",
+      "-moz-border-image",
+      "-o-border-image",
+      "border-image",
+      "-webkit-border-image-source",
+      "-moz-border-image-source",
+      "-o-border-image-source",
+      "border-image-source",
+      "-webkit-border-image-slice",
+      "-moz-border-image-slice",
+      "-o-border-image-slice",
+      "border-image-slice",
+      "-webkit-border-image-width",
+      "-moz-border-image-width",
+      "-o-border-image-width",
+      "border-image-width",
+      "-webkit-border-image-outset",
+      "-moz-border-image-outset",
+      "-o-border-image-outset",
+      "border-image-outset",
+      "-webkit-border-image-repeat",
+      "-moz-border-image-repeat",
+      "-o-border-image-repeat",
+      "border-image-repeat",
+      "outline",
+      "outline-width",
+      "outline-style",
+      "outline-color",
+      "outline-offset",
+      "-webkit-box-shadow",
+      "-moz-box-shadow",
+      "box-shadow",
+      "filter:progid:DXImageTransform.Microsoft.Alpha(Opacity",
+      "-ms-filter:\\'progid:DXImageTransform.Microsoft.Alpha",
+      "opacity",
+      "-ms-interpolation-mode",
+      "-webkit-transition",
+      "-moz-transition",
+      "-ms-transition",
+      "-o-transition",
+      "transition",
+      "-webkit-transition-delay",
+      "-moz-transition-delay",
+      "-ms-transition-delay",
+      "-o-transition-delay",
+      "transition-delay",
+      "-webkit-transition-timing-function",
+      "-moz-transition-timing-function",
+      "-ms-transition-timing-function",
+      "-o-transition-timing-function",
+      "transition-timing-function",
+      "-webkit-transition-duration",
+      "-moz-transition-duration",
+      "-ms-transition-duration",
+      "-o-transition-duration",
+      "transition-duration",
+      "-webkit-transition-property",
+      "-moz-transition-property",
+      "-ms-transition-property",
+      "-o-transition-property",
+      "transition-property",
+      "-webkit-transform",
+      "-moz-transform",
+      "-ms-transform",
+      "-o-transform",
+      "transform",
+      "-webkit-transform-origin",
+      "-moz-transform-origin",
+      "-ms-transform-origin",
+      "-o-transform-origin",
+      "transform-origin",
+      "-webkit-animation",
+      "-moz-animation",
+      "-ms-animation",
+      "-o-animation",
+      "animation",
+      "-webkit-animation-name",
+      "-moz-animation-name",
+      "-ms-animation-name",
+      "-o-animation-name",
+      "animation-name",
+      "-webkit-animation-duration",
+      "-moz-animation-duration",
+      "-ms-animation-duration",
+      "-o-animation-duration",
+      "animation-duration",
+      "-webkit-animation-play-state",
+      "-moz-animation-play-state",
+      "-ms-animation-play-state",
+      "-o-animation-play-state",
+      "animation-play-state",
+      "-webkit-animation-timing-function",
+      "-moz-animation-timing-function",
+      "-ms-animation-timing-function",
+      "-o-animation-timing-function",
+      "animation-timing-function",
+      "-webkit-animation-delay",
+      "-moz-animation-delay",
+      "-ms-animation-delay",
+      "-o-animation-delay",
+      "animation-delay",
+      "-webkit-animation-iteration-count",
+      "-moz-animation-iteration-count",
+      "-ms-animation-iteration-count",
+      "-o-animation-iteration-count",
+      "animation-iteration-count",
+      "-webkit-animation-direction",
+      "-moz-animation-direction",
+      "-ms-animation-direction",
+      "-o-animation-direction",
+      "animation-direction"
+    ]
+  ]
+}

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/styles/haddock/bootstrap/.csslintrc
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/styles/haddock/bootstrap/.csslintrc b/jspwiki-war/src/main/styles/haddock/bootstrap/.csslintrc
new file mode 100755
index 0000000..005b862
--- /dev/null
+++ b/jspwiki-war/src/main/styles/haddock/bootstrap/.csslintrc
@@ -0,0 +1,19 @@
+{
+  "adjoining-classes": false,
+  "box-sizing": false,
+  "box-model": false,
+  "compatible-vendor-prefixes": false,
+  "floats": false,
+  "font-sizes": false,
+  "gradients": false,
+  "important": false,
+  "known-properties": false,
+  "outline-none": false,
+  "qualified-headings": false,
+  "regex-selectors": false,
+  "shorthand": false,
+  "text-indent": false,
+  "unique-headings": false,
+  "universal-selector": false,
+  "unqualified-attributes": false
+}

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/styles/haddock/bootstrap/alerts.less
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/styles/haddock/bootstrap/alerts.less b/jspwiki-war/src/main/styles/haddock/bootstrap/alerts.less
index 8da200a..c4199db 100755
--- a/jspwiki-war/src/main/styles/haddock/bootstrap/alerts.less
+++ b/jspwiki-war/src/main/styles/haddock/bootstrap/alerts.less
@@ -1,23 +1,3 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
 //
 // Alerts
 // --------------------------------------------------
@@ -38,6 +18,7 @@
     // Specified for the h4 to prevent conflicts of changing @headings-color
     color: inherit;
   }
+
   // Provide class for links that match alerts
   .alert-link {
     font-weight: @alert-link-font-weight;
@@ -48,17 +29,19 @@
   > ul {
     margin-bottom: 0;
   }
+
   > p + p {
     margin-top: 5px;
   }
 }
 
-// Dismissable alerts
+// Dismissible alerts
 //
 // Expand the right padding and account for the close button's positioning.
 
-.alert-dismissable {
- padding-right: (@alert-padding + 20);
+.alert-dismissable, // The misspelled .alert-dismissable was deprecated in 3.2.0.
+.alert-dismissible {
+  padding-right: (@alert-padding + 20);
 
   // Adjust close link position
   .close {
@@ -76,12 +59,15 @@
 .alert-success {
   .alert-variant(@alert-success-bg; @alert-success-border; @alert-success-text);
 }
+
 .alert-info {
   .alert-variant(@alert-info-bg; @alert-info-border; @alert-info-text);
 }
+
 .alert-warning {
   .alert-variant(@alert-warning-bg; @alert-warning-border; @alert-warning-text);
 }
+
 .alert-danger {
   .alert-variant(@alert-danger-bg; @alert-danger-border; @alert-danger-text);
 }

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/styles/haddock/bootstrap/badges.less
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/styles/haddock/bootstrap/badges.less b/jspwiki-war/src/main/styles/haddock/bootstrap/badges.less
index 8dc0616..6ee16dc 100755
--- a/jspwiki-war/src/main/styles/haddock/bootstrap/badges.less
+++ b/jspwiki-war/src/main/styles/haddock/bootstrap/badges.less
@@ -1,29 +1,9 @@
-/*
- *
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- *
-*/
 //
 // Badges
 // --------------------------------------------------
 
 
-// Base classes
+// Base class
 .badge {
   display: inline-block;
   min-width: 10px;
@@ -32,7 +12,7 @@
   font-weight: @badge-font-weight;
   color: @badge-color;
   line-height: @badge-line-height;
-  vertical-align: baseline;
+  vertical-align: middle;
   white-space: nowrap;
   text-align: center;
   background-color: @badge-bg;
@@ -48,24 +28,39 @@
     position: relative;
     top: -1px;
   }
-}
 
-// Hover state, but only for links
-a.badge {
-  &:hover,
-  &:focus {
-    color: @badge-link-hover-color;
-    text-decoration: none;
-    cursor: pointer;
+  .btn-xs &,
+  .btn-group-xs > .btn & {
+    top: 0;
+    padding: 1px 5px;
   }
-}
 
-// Account for counters in navs
-a.list-group-item.active > .badge,
-.nav-pills > .active > a > .badge {
-  color: @badge-active-color;
-  background-color: @badge-active-bg;
-}
-.nav-pills > li > a > .badge {
-  margin-left: 3px;
+  // Hover state, but only for links
+  a& {
+    &:hover,
+    &:focus {
+      color: @badge-link-hover-color;
+      text-decoration: none;
+      cursor: pointer;
+    }
+  }
+
+  // Account for badges in navs
+  .list-group-item.active > &,
+  .nav-pills > .active > a > & {
+    color: @badge-active-color;
+    background-color: @badge-active-bg;
+  }
+
+  .list-group-item > & {
+    float: right;
+  }
+
+  .list-group-item > & + & {
+    margin-right: 5px;
+  }
+
+  .nav-pills > li > a > & {
+    margin-left: 3px;
+  }
 }