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

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

Various HADDOCK updates & fixes

See Changelog for details


Project: http://git-wip-us.apache.org/repos/asf/jspwiki/repo
Commit: http://git-wip-us.apache.org/repos/asf/jspwiki/commit/19b54311
Tree: http://git-wip-us.apache.org/repos/asf/jspwiki/tree/19b54311
Diff: http://git-wip-us.apache.org/repos/asf/jspwiki/diff/19b54311

Branch: refs/heads/JSPWIKI-1035
Commit: 19b543113f0f70efcc7e58736d1fd8d529bc3f60
Parents: 014dc67
Author: brushed <di...@gmail.com>
Authored: Sat Dec 17 22:21:21 2016 +0100
Committer: brushed <di...@gmail.com>
Committed: Sat Dec 17 22:21:21 2016 +0100

----------------------------------------------------------------------
 ChangeLog                                       |  42 +
 jspwiki-war/src/main/config/wro/wro.properties  |   4 +-
 .../src/main/java/org/apache/wiki/Release.java  |   2 +-
 .../apache/wiki/plugin/WeblogArchivePlugin.java |  28 +-
 .../org/apache/wiki/plugin/WeblogPlugin.java    |  20 +-
 .../apache/wiki/xmlrpc/MetaWeblogHandler.java   |  34 +-
 .../resources/plugin/PluginResources.properties |   1 +
 .../main/resources/templates/default.properties |  17 +-
 .../src/main/scripts/behaviors/Accordion.js     |   4 +-
 .../src/main/scripts/behaviors/AddCSS.js        |  11 +-
 .../src/main/scripts/behaviors/Columns.js       |   2 +-
 jspwiki-war/src/main/scripts/behaviors/Flip.js  |   2 +-
 .../src/main/scripts/behaviors/GraphBar.js      |   3 +-
 .../src/main/scripts/behaviors/TableX.js        |   5 +-
 .../src/main/scripts/behaviors/Viewer.js        |   4 +-
 .../src/main/scripts/dialog/Dialog.Selection.js |  41 +-
 jspwiki-war/src/main/scripts/dialog/Dialog.js   |  35 +-
 .../scripts/moo-extend/Array.NaturalSort.js     |   2 +-
 .../src/main/scripts/moo-extend/Behavior.js     |  25 +-
 .../src/main/scripts/moo-extend/Color.js        |  21 +-
 .../main/scripts/moo-extend/Element.Extend.js   |   2 +-
 .../main/scripts/moo-extend/String.Extend.js    |  15 +-
 .../src/main/scripts/moo-extend/Textarea.js     |   9 +
 .../main/scripts/wiki-edit/Snipe.Commands.js    |  16 +-
 .../main/scripts/wiki-edit/Snipe.Sections.js    | 150 ++-
 .../src/main/scripts/wiki-edit/Snipe.Snips.js   |  42 +-
 jspwiki-war/src/main/scripts/wiki-edit/Snipe.js | 317 +++---
 .../src/main/scripts/wiki-edit/Undoable.js      |   7 +-
 .../src/main/scripts/wiki-edit/Wiki.Edit.js     | 278 +++---
 .../src/main/scripts/wiki-edit/Wiki.Snips.js    | 962 +++++++++----------
 jspwiki-war/src/main/scripts/wiki/Category.js   |   4 +-
 jspwiki-war/src/main/scripts/wiki/Recents.js    |   2 +-
 .../src/main/scripts/wiki/Wiki.Behaviors.js     |  67 +-
 jspwiki-war/src/main/scripts/wiki/Wiki.js       | 130 ++-
 .../main/styles/haddock/bootstrap/.csscomb.json | 304 ++++++
 .../main/styles/haddock/bootstrap/.csslintrc    |  19 +
 .../main/styles/haddock/bootstrap/alerts.less   |  32 +-
 .../main/styles/haddock/bootstrap/badges.less   |  73 +-
 .../styles/haddock/bootstrap/bootstrap.less     |  31 +-
 .../styles/haddock/bootstrap/breadcrumbs.less   |  25 +-
 .../styles/haddock/bootstrap/button-groups.less |  91 +-
 .../main/styles/haddock/bootstrap/buttons.less  |  73 +-
 .../main/styles/haddock/bootstrap/carousel.less |  82 +-
 .../main/styles/haddock/bootstrap/close.less    |  21 +-
 .../src/main/styles/haddock/bootstrap/code.less |  38 +-
 .../haddock/bootstrap/component-animations.less |  34 +-
 .../styles/haddock/bootstrap/dropdowns.less     |  69 +-
 .../main/styles/haddock/bootstrap/forms.less    | 406 ++++++--
 .../styles/haddock/bootstrap/glyphicons.less    | 112 ++-
 .../src/main/styles/haddock/bootstrap/grid.less |  75 +-
 .../styles/haddock/bootstrap/input-groups.less  | 101 +-
 .../styles/haddock/bootstrap/jumbotron.less     |  46 +-
 .../main/styles/haddock/bootstrap/labels.less   |  22 +-
 .../styles/haddock/bootstrap/list-group.less    |  90 +-
 .../main/styles/haddock/bootstrap/media.less    |  66 ++
 .../main/styles/haddock/bootstrap/mixins.less   | 897 +----------------
 .../styles/haddock/bootstrap/mixins/alerts.less |  14 +
 .../bootstrap/mixins/background-variant.less    |   9 +
 .../haddock/bootstrap/mixins/border-radius.less |  18 +
 .../haddock/bootstrap/mixins/buttons.less       |  65 ++
 .../haddock/bootstrap/mixins/center-block.less  |   7 +
 .../haddock/bootstrap/mixins/clearfix.less      |  22 +
 .../styles/haddock/bootstrap/mixins/forms.less  |  85 ++
 .../haddock/bootstrap/mixins/gradients.less     |  59 ++
 .../bootstrap/mixins/grid-framework.less        |  91 ++
 .../styles/haddock/bootstrap/mixins/grid.less   | 122 +++
 .../haddock/bootstrap/mixins/hide-text.less     |  21 +
 .../styles/haddock/bootstrap/mixins/image.less  |  33 +
 .../styles/haddock/bootstrap/mixins/labels.less |  12 +
 .../haddock/bootstrap/mixins/list-group.less    |  30 +
 .../haddock/bootstrap/mixins/nav-divider.less   |  10 +
 .../bootstrap/mixins/nav-vertical-align.less    |   9 +
 .../haddock/bootstrap/mixins/opacity.less       |   8 +
 .../haddock/bootstrap/mixins/pagination.less    |  24 +
 .../styles/haddock/bootstrap/mixins/panels.less |  24 +
 .../haddock/bootstrap/mixins/progress-bar.less  |  10 +
 .../haddock/bootstrap/mixins/reset-filter.less  |   8 +
 .../haddock/bootstrap/mixins/reset-text.less    |  18 +
 .../styles/haddock/bootstrap/mixins/resize.less |   6 +
 .../bootstrap/mixins/responsive-visibility.less |  15 +
 .../styles/haddock/bootstrap/mixins/size.less   |  10 +
 .../haddock/bootstrap/mixins/tab-focus.less     |   9 +
 .../haddock/bootstrap/mixins/table-row.less     |  28 +
 .../haddock/bootstrap/mixins/text-emphasis.less |   9 +
 .../haddock/bootstrap/mixins/text-overflow.less |   8 +
 .../bootstrap/mixins/vendor-prefixes.less       | 227 +++++
 .../main/styles/haddock/bootstrap/modals.less   |  71 +-
 .../main/styles/haddock/bootstrap/navbar.less   | 154 +--
 .../src/main/styles/haddock/bootstrap/navs.less |  28 +-
 .../styles/haddock/bootstrap/normalize.less     | 318 +++---
 .../main/styles/haddock/bootstrap/pager.less    |  33 +-
 .../styles/haddock/bootstrap/pagination.less    |  38 +-
 .../main/styles/haddock/bootstrap/panels.less   | 217 +++--
 .../main/styles/haddock/bootstrap/popovers.less |  56 +-
 .../main/styles/haddock/bootstrap/print.less    | 216 ++---
 .../styles/haddock/bootstrap/progress-bars.less |  37 +-
 .../haddock/bootstrap/responsive-embed.less     |  35 +
 .../haddock/bootstrap/responsive-utilities.less | 253 +++--
 .../styles/haddock/bootstrap/scaffolding.less   |  72 +-
 .../main/styles/haddock/bootstrap/tables.less   |  55 +-
 .../main/styles/haddock/bootstrap/theme.less    |  90 +-
 .../styles/haddock/bootstrap/thumbnails.less    |  36 +
 .../main/styles/haddock/bootstrap/tooltip.less  |  42 +-
 .../src/main/styles/haddock/bootstrap/type.less | 213 ++--
 .../styles/haddock/bootstrap/utilities.less     |  21 -
 .../styles/haddock/bootstrap/variables.less     | 650 ++++++++-----
 .../main/styles/haddock/bootstrap/wells.less    |  29 +
 .../src/main/styles/haddock/default/.crunch     | 123 +++
 .../main/styles/haddock/default/Calendar.less   |  48 -
 .../src/main/styles/haddock/default/Dialog.less |  19 +-
 .../main/styles/haddock/default/Invisibles.less |   2 +-
 .../haddock/default/RecentChangesPlugin.less    |  10 +-
 .../main/styles/haddock/default/TOCPlugin.less  |  20 +-
 .../haddock/default/Template.Content.less       |   4 +-
 .../styles/haddock/default/Template.Edit.less   | 147 ++-
 .../src/main/styles/haddock/default/Tips.less   |   7 +-
 .../styles/haddock/default/WeblogPlugin.less    |  63 +-
 .../src/main/styles/haddock/default/build.less  |  13 +-
 .../src/main/styles/haddock/default/grid.less   |   2 +-
 .../main/styles/haddock/default/prettify.less   |  14 +-
 .../src/main/styles/haddock/default/type.less   | 145 ++-
 .../main/styles/haddock/default/variables.less  |   8 +-
 .../main/styles/haddock/fontjspwiki/core.less   |  13 +-
 .../main/styles/haddock/fontjspwiki/path.less   |  13 +-
 jspwiki-war/src/main/webapp/Comment.jsp         |   3 +-
 jspwiki-war/src/main/webapp/DeleteGroup.jsp     |  11 +-
 jspwiki-war/src/main/webapp/Install.jsp         |  62 +-
 .../src/main/webapp/XHRMarkup2Wysiwyg.jsp       |  84 ++
 .../webapp/templates/haddock/AttachmentTab.jsp  |   2 +-
 .../webapp/templates/haddock/CommentContent.jsp |  18 +-
 .../main/webapp/templates/haddock/DiffTab.jsp   |   2 +-
 .../webapp/templates/haddock/EditTemplate.jsp   |   2 +-
 .../main/webapp/templates/haddock/Header.jsp    |   2 +-
 .../webapp/templates/haddock/InfoContent.jsp    |   2 +-
 .../src/main/webapp/templates/haddock/Nav.jsp   |  15 +-
 .../main/webapp/templates/haddock/PageTab.jsp   |   2 -
 .../webapp/templates/haddock/PreferencesTab.jsp |  21 +-
 .../webapp/templates/haddock/ProfileTab.jsp     |  10 +-
 .../main/webapp/templates/haddock/Sidebar.jsp   |   8 +-
 .../webapp/templates/haddock/ViewTemplate.jsp   |   3 +-
 .../webapp/templates/haddock/commonheader.jsp   |  11 +-
 .../templates/haddock/editors/CKeditor.jsp      |  65 +-
 .../templates/haddock/editors/TinyMCE.jsp       |  64 +-
 .../webapp/templates/haddock/editors/plain.jsp  | 183 ++--
 .../templates/haddock/editors/wysiwyg.jsp       |  74 +-
 145 files changed, 5846 insertions(+), 4135 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/ChangeLog
----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 6b998e8..04ba4cc 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,47 @@
 2016-12-13  Dirk Frederickx (brushed AT apache DOT org)
 
+       * 2.10.3-svn-20  Various HADDOCK updates & fixes.
+
+       * JSPWiki BLOGS
+         Final update of the styling of JSPWiki's BLOGs.
+         Also the fancy weblog calendar is now back in the sidebar
+         when viewing a blog post.
+
+       * Add-Comment JSP refactored:
+         When adding a comment to a wiki-page, you will see the content of the main page
+         at the top of the editing screen,  so you know what your are commenting on.
+         Improved hover menu on the SAVE/POST button for entering the change-note and
+         comment-signature fields.
+
+       * Plain Editor:
+         Many JS improvements related to the handling of text snippets.
+         Several style updates to the editor and the auto-suggest dialogs.
+
+       * Small refactoring of the Install.jsp to fit the bootstrap framework.
+
+       * %%columns-<width>: fix the broken width parameter
+
+       * %%graphbars: fix support for HTML-color-names (chrome, FF)
+
+       * [JSPWIKI-979]: fix support for %%small {{{ preformatted text blocks }}}
+
+       * [JSPWIKI-937]: fix handling of broken image links (also for FF)
+         Fix for rendering of the attachement icon, e.g. in RecentChanges page.
+
+       * Improved visualisation of interwiki links for Edit, Raw, Reader and Groups.
+
+       * The Delete group command now gets you back to the Group view pages,  so it is
+         easier for issuing subsequent group commands. (create,edit,delete)
+
+       * Added %%maps to generate google maps viewer by simply including the address.
+
+       * Few html5 FORM improvements: required fields, email input type, ...
+
+       * Updated to bootstrap 3.3.7.
+
+
+2016-12-13  Dirk Frederickx (brushed AT apache DOT org)
+
        * 2.10.3-svn-19
 
        * JSPWIKI-1032 : Use image "src" attribute instead of "href"

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/config/wro/wro.properties
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/config/wro/wro.properties b/jspwiki-war/src/main/config/wro/wro.properties
index 1818c10..7c810dc 100644
--- a/jspwiki-war/src/main/config/wro/wro.properties
+++ b/jspwiki-war/src/main/config/wro/wro.properties
@@ -21,5 +21,5 @@ debug=true
 
 #preProcessors=cssUrlRewriting,cssImport,semicolonAppender
 preProcessors=cssImport,semicolonAppender
-postProcessors=lessCss,yuiCssMin,uglifyJs
-#postProcessors=less4j.less,cssCompressor,uglifyJs
+#postProcessors=lessCss,yuiCssMin,uglifyJs
+postProcessors=less4j,yuiCssMin,uglifyJs

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/java/org/apache/wiki/Release.java
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/java/org/apache/wiki/Release.java b/jspwiki-war/src/main/java/org/apache/wiki/Release.java
index 5b3584d..b37ef14 100644
--- a/jspwiki-war/src/main/java/org/apache/wiki/Release.java
+++ b/jspwiki-war/src/main/java/org/apache/wiki/Release.java
@@ -72,7 +72,7 @@ public final class Release {
      *  <p>
      *  If the build identifier is empty, it is not added.
      */
-    public static final String     BUILD         = "19";
+    public static final String     BUILD         = "20";
 
     /**
      *  This is the generic version string you should use when printing out the version.  It is of

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogArchivePlugin.java
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogArchivePlugin.java b/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogArchivePlugin.java
index 1edd903..ef303ed 100644
--- a/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogArchivePlugin.java
+++ b/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogArchivePlugin.java
@@ -1,4 +1,4 @@
-/* 
+/*
     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
@@ -14,7 +14,7 @@
     "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.  
+    under the License.
  */
 package org.apache.wiki.plugin;
 
@@ -45,7 +45,7 @@ import org.apache.wiki.util.TextUtil;
  *  <ul>
  *  <li><b>page</b> - the page name</li>
  *  </ul>
- *  
+ *
  *  @since 1.9.21
  */
 public class WeblogArchivePlugin implements WikiPlugin
@@ -71,7 +71,7 @@ public class WeblogArchivePlugin implements WikiPlugin
         String weblogName = params.get( PARAM_PAGE );
 
         if( weblogName == null ) weblogName = context.getPage().getName();
-        
+
 
         m_monthUrlFormat = new SimpleDateFormat("'"+
                                                 context.getURL( WikiContext.VIEW, weblogName,
@@ -80,7 +80,7 @@ public class WeblogArchivePlugin implements WikiPlugin
         StringBuilder sb = new StringBuilder();
 
         sb.append( "<div class=\"weblogarchive\">\n" );
-        
+
 
         //
         //  Collect months that have blog entries
@@ -123,7 +123,6 @@ public class WeblogArchivePlugin implements WikiPlugin
             }
 
             sb.append( "</ul>\n" );
-            sb.append( "</div>\n" );
         }
         catch( ProviderException ex )
         {
@@ -131,6 +130,8 @@ public class WeblogArchivePlugin implements WikiPlugin
             sb.append("Cannot get archive: "+ex.getMessage());
         }
 
+        sb.append( "</div>\n" );
+
         return sb.toString();
     }
 
@@ -143,9 +144,9 @@ public class WeblogArchivePlugin implements WikiPlugin
 
         WeblogPlugin pl = new WeblogPlugin();
 
-        List blogEntries = pl.findBlogEntries( engine.getPageManager(),
+        List blogEntries = pl.findBlogEntries( engine,
                                                page, new Date(0L), new Date() );
-        
+
         for( Iterator i = blogEntries.iterator(); i.hasNext(); )
         {
             WikiPage p = (WikiPage) i.next();
@@ -188,7 +189,7 @@ public class WeblogArchivePlugin implements WikiPlugin
 
     }
 
-    
+
     /**
      * This is a simple comparator for ordering weblog archive entries.
      * Two dates in the same month are considered equal.
@@ -197,14 +198,14 @@ public class WeblogArchivePlugin implements WikiPlugin
         implements Comparator
     {
 
-        public int compare( Object a, Object b ) 
+        public int compare( Object a, Object b )
         {
-            if( a == null || b == null || 
+            if( a == null || b == null ||
                 !(a instanceof Calendar) || !(b instanceof Calendar) )
             {
                 throw new ClassCastException( "Invalid calendar supplied for comparison." );
             }
-                    
+
             Calendar ca = (Calendar) a;
             Calendar cb = (Calendar) b;
             if( ca.get( Calendar.YEAR ) == cb.get( Calendar.YEAR ) &&
@@ -213,7 +214,8 @@ public class WeblogArchivePlugin implements WikiPlugin
                 return 0;
             }
 
-            return cb.getTime().before( ca.getTime() ) ? 1 : -1;
+            //sort recent dates first
+            return cb.getTime().before( ca.getTime() ) ? -1 : 1;
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogPlugin.java
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogPlugin.java b/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogPlugin.java
index d134900..48685ff 100644
--- a/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogPlugin.java
+++ b/jspwiki-war/src/main/java/org/apache/wiki/plugin/WeblogPlugin.java
@@ -30,6 +30,7 @@ import java.util.Comparator;
 import java.util.Date;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 import java.util.Map;
 import java.util.ResourceBundle;
 import java.util.regex.Matcher;
@@ -268,7 +269,7 @@ public class WeblogPlugin
 
         try
         {
-            List<WikiPage> blogEntries = findBlogEntries( engine.getPageManager(),
+            List<WikiPage> blogEntries = findBlogEntries( engine,
                                                           weblogName,
                                                           startTime.getTime(),
                                                           stopTime.getTime() );
@@ -375,7 +376,7 @@ public class WeblogPlugin
             author = "AnonymousCoward";
         }
 
-        buffer.append("By "+author+"&nbsp;&nbsp;");
+        buffer.append( MessageFormat.format( rb.getString("weblogentryplugin.postedby"), author));
         buffer.append( "<a href=\""+entryCtx.getURL(WikiContext.VIEW, entry.getName())+"\">"+rb.getString("weblogentryplugin.permalink")+"</a>" );
         String commentPageName = TextUtil.replaceString( entry.getName(),
                                                          "blogentry",
@@ -428,35 +429,34 @@ public class WeblogPlugin
      *  Attempts to locate all pages that correspond to the
      *  blog entry pattern.  Will only consider the days on the dates; not the hours and minutes.
      *
-     *  @param mgr A PageManager which is used to get the pages
+     *  @param engine WikiEngine which is used to get the pages
      *  @param baseName The basename (e.g. "Main" if you want "Main_blogentry_xxxx")
      *  @param start The date which is the first to be considered
      *  @param end   The end date which is the last to be considered
      *  @return a list of pages with their FIRST revisions.
      *  @throws ProviderException If something goes wrong
      */
-    public List findBlogEntries( PageManager mgr,
+    public List findBlogEntries( WikiEngine engine,
                                  String baseName, Date start, Date end )
         throws ProviderException
     {
-        Collection everyone = mgr.getAllPages();
+        PageManager mgr = engine.getPageManager();
+        Set allPages = engine.getReferenceManager().findCreated();
+
         ArrayList<WikiPage> result = new ArrayList<WikiPage>();
 
         baseName = makeEntryPage( baseName );
         SimpleDateFormat fmt = new SimpleDateFormat(DEFAULT_DATEFORMAT);
 
-        for( Iterator i = everyone.iterator(); i.hasNext(); )
+        for( Iterator i = allPages.iterator(); i.hasNext(); )
         {
-            WikiPage p = (WikiPage)i.next();
-
-            String pageName = p.getName();
+            String pageName = (String)i.next();
 
             if( pageName.startsWith( baseName ) )
             {
                 try
                 {
                     WikiPage firstVersion = mgr.getPageInfo( pageName, 1 );
-
                     Date d = firstVersion.getLastModified();
 
                     if( d.after(start) && d.before(end) )

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/java/org/apache/wiki/xmlrpc/MetaWeblogHandler.java
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/java/org/apache/wiki/xmlrpc/MetaWeblogHandler.java b/jspwiki-war/src/main/java/org/apache/wiki/xmlrpc/MetaWeblogHandler.java
index ff2c045..42acb4e 100644
--- a/jspwiki-war/src/main/java/org/apache/wiki/xmlrpc/MetaWeblogHandler.java
+++ b/jspwiki-war/src/main/java/org/apache/wiki/xmlrpc/MetaWeblogHandler.java
@@ -1,4 +1,4 @@
-/* 
+/*
     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
@@ -14,7 +14,7 @@
     "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.  
+    under the License.
  */
 package org.apache.wiki.xmlrpc;
 
@@ -56,10 +56,10 @@ import org.apache.xmlrpc.XmlRpcException;
 public class MetaWeblogHandler
     implements WikiRPCHandler
 {
-    private static Logger log = Logger.getLogger( MetaWeblogHandler.class ); 
+    private static Logger log = Logger.getLogger( MetaWeblogHandler.class );
 
     private WikiContext m_context;
-    
+
     /**
      *  {@inheritDoc}
      */
@@ -87,13 +87,13 @@ public class MetaWeblogHandler
         {
             AuthenticationManager amm = m_context.getEngine().getAuthenticationManager();
             AuthorizationManager mgr = m_context.getEngine().getAuthorizationManager();
-        
+
             if( amm.login( m_context.getWikiSession(), m_context.getHttpRequest(), username, password ) )
             {
                 if( !mgr.checkPermission( m_context.getWikiSession(), PermissionFactory.getPagePermission( page, permission ) ))
                 {
                     throw new XmlRpcException( 1, "No permission" );
-                }   
+                }
             }
             else
             {
@@ -110,7 +110,7 @@ public class MetaWeblogHandler
     /**
      *  JSPWiki does not support categories, therefore JSPWiki
      *  always returns an empty list for categories.
-     *  
+     *
      *  @param blogid The id of the blog.
      *  @param username The username to use
      *  @param password The password
@@ -165,7 +165,7 @@ public class MetaWeblogHandler
         {
             title = pageText.substring( 0, firstLine );
         }
-            
+
         if( title.trim().length() == 0 ) title = page.getName();
 
         // Remove wiki formatting
@@ -179,7 +179,7 @@ public class MetaWeblogHandler
 
     /**
      *  Returns a list of the recent posts to this weblog.
-     *  
+     *
      *  @param blogid The id of the blog.
      *  @param username The username to use
      *  @param password The password
@@ -210,7 +210,7 @@ public class MetaWeblogHandler
         {
             WeblogPlugin plugin = new WeblogPlugin();
 
-            List<WikiPage> changed = plugin.findBlogEntries(m_context.getEngine().getPageManager(), 
+            List<WikiPage> changed = plugin.findBlogEntries(m_context.getEngine(),
                                                             blogid,
                                                             new Date(0L),
                                                             new Date());
@@ -238,13 +238,13 @@ public class MetaWeblogHandler
 
     /**
      *  Adds a new post to the blog.
-     *  
+     *
      *  @param blogid The id of the blog.
      *  @param username The username to use
      *  @param password The password
      *  @param content As per Metaweblogapi contract
      *  @param publish This parameter is ignored for JSPWiki.
-     *  @return Returns an empty string 
+     *  @return Returns an empty string
      *  @throws XmlRpcException If something goes wrong
      */
     public String newPost( String blogid,
@@ -256,7 +256,7 @@ public class MetaWeblogHandler
     {
         log.info("metaWeblog.newPost() called");
         WikiEngine engine = m_context.getEngine();
-        
+
         WikiPage page = engine.getPage( blogid );
         checkPermissions( page, username, password, "createPages" );
 
@@ -293,16 +293,16 @@ public class MetaWeblogHandler
      *  Creates an attachment and adds it to the blog.  The attachment
      *  is created into the main blog page, not the actual post page,
      *  because we do not know it at this point.
-     *  
+     *
      *  @param blogid The id of the blog.
      *  @param username The username to use
      *  @param password The password
      *  @param content As per the MetaweblogAPI contract
-     *  @return As per the MetaweblogAPI contract 
+     *  @return As per the MetaweblogAPI contract
      *  @throws XmlRpcException If something goes wrong
-     *  
+     *
      */
-    public Hashtable newMediaObject( String blogid, 
+    public Hashtable newMediaObject( String blogid,
                                      String username,
                                      String password,
                                      Hashtable content )

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/resources/plugin/PluginResources.properties
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/resources/plugin/PluginResources.properties b/jspwiki-war/src/main/resources/plugin/PluginResources.properties
index ad61c39..4902ef5 100644
--- a/jspwiki-war/src/main/resources/plugin/PluginResources.properties
+++ b/jspwiki-war/src/main/resources/plugin/PluginResources.properties
@@ -46,6 +46,7 @@ currenttimeplugin.badformat = You specified a bad format
 # WeblogEntryPlugin
 
 weblogentryplugin.newentry = <span class="icon-plus"></span> New entry
+weblogentryplugin.postedby = Posted by {0}&nbsp;&nbsp;
 weblogentryplugin.permalink = Permalink
 weblogentryplugin.addcomment = <span class="icon-plus"></span> Add new comment ({0})
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/resources/templates/default.properties
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/resources/templates/default.properties b/jspwiki-war/src/main/resources/templates/default.properties
index 2ce3437..3583e28 100644
--- a/jspwiki-war/src/main/resources/templates/default.properties
+++ b/jspwiki-war/src/main/resources/templates/default.properties
@@ -516,10 +516,11 @@ view.title.view={0}: {1}
 
 # The built-in editors also have their localized strings in this file.
 
-editor.plain.name=Your <span class='accesskey'>n</span>ame
+editor.plain.name=Name
 editor.plain.remember=Remember me?
-editor.plain.email=Homepage or email
+editor.plain.email=Link to homepage or email
 editor.plain.save.submit=Save
+editor.plain.save.submit.comment=Post Comment
 editor.plain.save.title=Save [ s ]
 editor.plain.preview.submit=Preview
 editor.plain.preview.title=Preview [ v ]
@@ -558,6 +559,7 @@ editor.plain.sneakpreview.title=Sneak Preview. \
     Click outside the textarea to refresh the sneak preview area.
 editor.plain.sidebysidepreview=Side by Side Preview
 editor.plain.edit.resize=Drag to resize the text and preview area
+editor.plain.comment.resize=Drag to resize the main page area
 
 editor.plain.tbLink.title=link - Insert wiki link
 editor.plain.tbH1.title=h1 - Insert heading1
@@ -604,6 +606,7 @@ blog.permalink=Permalink
 #
 #  The Javascript stuff
 #
+javascript.broken.image=Content unavailable! (broken link)
 javascript.sbox.clearrecent=Clear Recent Searches
 javascript.sbox.clone =Clone this page
 javascript.sbox.create =Create {0}
@@ -616,6 +619,16 @@ javascript.edit.toolbar.makeSelection=Please make first a selection.
 javascript.edit.resize=Drag to resize the text area
 javascript.edit.areyousure=Without clicking the Save button, your changes will be lost. \
     Are you sure you want to exit this page?
+javascript.preview.zone = Preview Zone
+
+javascript.dialog.character.entities = Character entities
+javascript.dialog.link.attributes = Wiki Link Attributes
+javascript.dialog.plugin = Plugin
+javascript.dialog.permission = Page Permission
+javascript.dialog.principal = Roles, Groups or Users
+javascript.dialog.styles = Additional Styles
+javascript.dialog.toc.options = TOC options
+
 
 javascript.favs.show=Click to show Favorites
 javascript.favs.hide=Click to hide Favorites

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/behaviors/Accordion.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/behaviors/Accordion.js b/jspwiki-war/src/main/scripts/behaviors/Accordion.js
index 8b24b9d..3f3fa74 100644
--- a/jspwiki-war/src/main/scripts/behaviors/Accordion.js
+++ b/jspwiki-war/src/main/scripts/behaviors/Accordion.js
@@ -131,8 +131,8 @@ var Accordion = new Class({
 
             }
 
-            toggles.push( toggle );
-            contents.push( "div".slick().wraps( pane.addClass("panel-body") ) );
+            toggles[toggles.length] = toggle;
+            contents[contents.length] = "div".slick().wraps( pane.addClass("panel-body") );
 
         }
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/behaviors/AddCSS.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/behaviors/AddCSS.js b/jspwiki-war/src/main/scripts/behaviors/AddCSS.js
index 2a8c8b5..3e3eb28 100644
--- a/jspwiki-war/src/main/scripts/behaviors/AddCSS.js
+++ b/jspwiki-war/src/main/scripts/behaviors/AddCSS.js
@@ -35,7 +35,8 @@ function AddCSS( element ){
 
     function insertStyle ( elements ){
 
-        var css = "", item;
+        var css = "",
+            item;
 
         //collect all css to be inserted
         while( item = elements.shift() ){ css += item.innerHTML; }
@@ -45,6 +46,11 @@ function AddCSS( element ){
 
         //magic to replace the inline wiki-image links to css url()
         //xss protection: remove invalid url's;  only allow url([wiki-attachement])
+
+        //tocheck: allow attached font files <a class=attachment href=xxx.woff><a class=infolink ....>
+        css = css.replace( /url\(<a class="attachment" href="([^"]+.woff)".*><\/a>\)/gi,'url(<ifont href="$1"/>)' );
+        css = css.replace( /url\(<a class="attachment" href="([^"]+.ttf)".*><\/a>\)/gi,'url(<ifont href="$1"/>)' );
+
         css = css.replace( /url\(\<[^i][^)]*\)/gi, "url(invalid)" ); //remove url(<a...)
         css = css.replace( /url\([^<][^)]*\)/gi, "url(invalid)" );  //remove url(xxx)
 
@@ -55,9 +61,10 @@ function AddCSS( element ){
         css = css.replace( /@imp@rt/g, "@import url(https://fonts.googleapis.com/css?family=");
 
         //xss protection: remove IE dynamic properties
-        css = css.replace( /expression|behavior/gi,"invalid" );
+        css = css.replace( /expression|behavior/gi, "invalid" );
 
         css = css.replace( /url\(<img class="inline" .*?src="([^"]+)[^>]*>\)/gi, "url($1)" );
+        css = css.replace( /url\(<ifont href="([^"]+)"\/>\)/gi, "url($1)" );
 
         css = css.replace( /<p>|<\/p>/gi, "" ); //jspwiki inserts <p/> for empty lines
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/behaviors/Columns.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/behaviors/Columns.js b/jspwiki-war/src/main/scripts/behaviors/Columns.js
index 881c117..5bada6c 100644
--- a/jspwiki-war/src/main/scripts/behaviors/Columns.js
+++ b/jspwiki-war/src/main/scripts/behaviors/Columns.js
@@ -56,7 +56,7 @@ function Columns(element, options){
     if( columnCount /*>0*/ ){
 
         columnCount++;
-        width = ( args[0] ) ? args[0] / columnCount + "px" : 100 / columnCount + "%";
+        width = args[0] ? args[0] + "px" : 100 / columnCount + "%";
 
         element
             .addClass("columns")

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/behaviors/Flip.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/behaviors/Flip.js b/jspwiki-war/src/main/scripts/behaviors/Flip.js
index 87073a7..e695124 100644
--- a/jspwiki-war/src/main/scripts/behaviors/Flip.js
+++ b/jspwiki-war/src/main/scripts/behaviors/Flip.js
@@ -52,7 +52,7 @@ function Flip(element, options){
             arg = args.pop();
             if( !arg.indexOf("w") /*index==0*/ ){ css.width = arg.slice(1).toInt(); }
             else if( !arg.indexOf("h") /*index==0*/ ){ css.height = arg.slice(1).toInt(); }
-            else if( arg.test(/none|default|success|info|warning|danger/ )){ frontback.push(arg); }
+            else if( arg.test(/none|default|success|info|warning|danger/ )){ frontback[frontback.length] = arg; }
 
         }
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/behaviors/GraphBar.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/behaviors/GraphBar.js b/jspwiki-war/src/main/scripts/behaviors/GraphBar.js
index 1443539..f17374b 100644
--- a/jspwiki-war/src/main/scripts/behaviors/GraphBar.js
+++ b/jspwiki-war/src/main/scripts/behaviors/GraphBar.js
@@ -136,8 +136,8 @@ var GraphBar = new Class({
 
                 }
 
+                //console.log(data, options.minv, options.maxv);
                 data = data.scale(options.minv, options.maxv)
-                console.log(data);
 
                 for( i = 0; i < len; i++){
 
@@ -245,6 +245,7 @@ var GraphBar = new Class({
             [offset + size, val + "%", (100 - val) + "%"] :
                 [offset + val / 100 * (/*offset + */ size), "100%" ];
 
+
         //then convert sizes to bar css styles
         css = css.map( function(barsize){
             return options.isHorizontal ? {width: barsize} : {height: barsize, width: 20, "vertical-align":"text-bottom"};

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/behaviors/TableX.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/behaviors/TableX.js b/jspwiki-war/src/main/scripts/behaviors/TableX.js
index 55d6cb1..2e2735a 100644
--- a/jspwiki-war/src/main/scripts/behaviors/TableX.js
+++ b/jspwiki-war/src/main/scripts/behaviors/TableX.js
@@ -102,9 +102,10 @@ var TableX = new Class({
                 if( $(r.cells[col]).get('text').trim() == fieldName ){
 
                     //take this COLUMN
-                    for( i=1; i < tlen; i++)
+                    for( i=1; i < tlen; i++){
                         //result.push( new Element('span').wraps(table.rows[i].cells[col]) );
-                        result.push( rows[i].cells[col] );
+                        result[result.length] = rows[i].cells[col];
+                    }
                     return result;
                 }
             }

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/behaviors/Viewer.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/behaviors/Viewer.js b/jspwiki-war/src/main/scripts/behaviors/Viewer.js
index 494eb9f..f28db02 100644
--- a/jspwiki-war/src/main/scripts/behaviors/Viewer.js
+++ b/jspwiki-war/src/main/scripts/behaviors/Viewer.js
@@ -48,7 +48,6 @@ this.Viewer = {
         var result = {};
 
         if( typeOf(url) == "element" ){ url = url.src || url.href; }
-
         this.LIB.some( function(item){
 
             return url.test( item[0], "i" )
@@ -62,7 +61,6 @@ this.Viewer = {
         //console.log(options.type);
         if( options.type && !result[options.type] ){ return false; }
 
-
         return result;
     },
 
@@ -134,7 +132,7 @@ this.Viewer = {
             h = options.height;
 
         function preloadCallback(preload, width, height){
-                preloads.push( preload );
+                preloads[preloads.length] = preload ;
                 w = w.max(width);
                 h = h.max(height.toInt());
                 //console.log("preloads.length, w,h);

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js b/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js
index f11146f..ac4a89a 100644
--- a/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js
+++ b/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js
@@ -70,9 +70,16 @@ Dialog.Selection = new Class({
 
     initialize:function( options ){
 
-        this.setClass(".selection",options);
-        this.selected = options.selected || "";
-        this.parent( options );
+        var self = this;
+
+        self.setClass(".selection",options);
+        self.selected = options.selected || "";
+        self.parent( options );
+
+        self.element.addEvent("click:relay(.item)", function(e){
+            e.stop();
+            self.action( this.get("title") );
+        });
 
         //console.log("Dialog.Selection ", this.element.className);
     },
@@ -107,14 +114,9 @@ Dialog.Selection = new Class({
 
         if( typeOf( content ) == "element" ){
 
-            //first move the content elements into the body and highlight the selected item
-            self.parent( content ).setValue( self.selected );
-
-            //then add the click & hover event handlers
-            self.element.addEvent("click:relay(.item)", function(e){
-                e.stop();
-                self.action( this.get("title") );
-            });
+            //first move the content elements into the body and then highlight the selected item
+            self.parent( content )
+                .setValue( self.selected );
 
         }
 
@@ -128,13 +130,24 @@ Dialog.Selection = new Class({
     */
     setValue: function( value ){
 
-        var self = this, selected = "selected", element;
+        var self = this, selected = "selected", element,
+            target = ".item[title" + self.options.match + value + "]";
+
+        /*ffs
+        if( self.hasClass("dialog-filtered") ){
 
+            if( value == "" ){
+                this.element.getElements(".item,.divider").show();
+            } else {
+                this.element.getElements(".item,.divider").hide();
+                this.element.getElements(target).show();
+            }
+        }
+        */
         element = self.get("." + selected);
         if( element ){ element.removeClass(selected); }
 
-        //console.log("Dialog.Selection setValue", value);
-        element = self.get( ".item[title" + self.options.match + value + "]" );
+        element = self.get( target );
         if( element ){ element.addClass(selected); }
 
         self[selected] = value;

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/dialog/Dialog.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/dialog/Dialog.js b/jspwiki-war/src/main/scripts/dialog/Dialog.js
index 4d23e79..145b547 100644
--- a/jspwiki-war/src/main/scripts/dialog/Dialog.js
+++ b/jspwiki-war/src/main/scripts/dialog/Dialog.js
@@ -111,17 +111,17 @@ var Dialog = new Class({
 
         var self = this, el;
 
-        this.setClass(".dialog",options);
+        this.setClass(".dialog", options);
         this.setOptions( options );
 
-        console.log("Dialog.initialize"   );
+        //console.log("Dialog.initialize" );
         options = self.options;
 
         el = self.element = options.dialog || self.build(options);
 
         el.getElements(".close").addEvent("click", self.hide.bind(self) );
 
-        //make dialog draggable; only possible when el is position absolute
+        //make dialog draggable; only possible when el has an absolute position
         if( (el.getStyle("position") == "absolute") && options.draggable ){
 
             new Drag(el,{
@@ -132,7 +132,6 @@ var Dialog = new Class({
 
         self[ options.showNow ? "show": "hide"]();
 
-
     },
 
     toElement: function(){
@@ -154,10 +153,22 @@ var Dialog = new Class({
 
     },
 
+    hasClass: function(clazz){
+        return this.element.hasClass(clazz);
+    },
+
+    ifClass: function(flag, trueClass, falseClass){
+
+        var body = this.element;
+        if( body ){ body.ifClass(flag, trueClass, falseClass); }
+        return this;
+
+    },
+
     setClass: function(clazz, options){
 
+        console.log("Dialog.setClass", options.cssClass );
         options.cssClass = clazz + (options.cssClass || "");
-        console.log("Dialog.setClass ", options.cssClass );
 
     },
 
@@ -213,25 +224,15 @@ var Dialog = new Class({
 
     },
 
-    /*
-    Function: action
-        Fires the ""action"" event.
-        When the autoClose option is set, the dialog will also be hidden.
-    */
     action: function(value){
-        console.log("Dialog action: ",value," close:"+this.options.autoClose);
+        //console.log("Dialog action: ",value," close:"+this.options.autoClose);
         this.fireEvent("action", value);
         if( this.options.autoClose ){ this.hide(); }
     },
 
-    /*
-    Function: build
-        Build new dialog frame based on caption and body options.
-    */
     build: function( options ){
 
-        console.log("DIALOG build ",options.cssClass, options.styles);
-
+        //console.log("DIALOG build ",options.cssClass, options.styles);
         var element = this.element = [
             "div" + options.cssClass, {styles: options.styles}, [
                 "a.close",{ html: "&#215;"},

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js b/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js
index f7baac8..d91185c 100644
--- a/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js
+++ b/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js
@@ -138,7 +138,7 @@ Array.implement({
 
         }
 
-        //console.log("[", kmgt ? "kmgt" : dmy ? "dmy" : num ? "num" : nat ? "nat" : "no conversion", "] ");
+        console.log("[", kmgt ? "kmgt" : dmy ? "dmy" : num ? "num" : nat ? "nat" : "no conversion", "] ");
 
         return kmgt || dmy || num || nat || this.slice();
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/moo-extend/Behavior.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/moo-extend/Behavior.js b/jspwiki-war/src/main/scripts/moo-extend/Behavior.js
index bff1dab..e022326 100644
--- a/jspwiki-war/src/main/scripts/moo-extend/Behavior.js
+++ b/jspwiki-war/src/main/scripts/moo-extend/Behavior.js
@@ -65,11 +65,12 @@ var Behavior = new Class({
     update: function(){
 
         var cache = "_bhvr", updated, type, isClass, isFunction,
-            nodes, node, i = 0, j, item, behavior, options;
+            nodes, node, i = 0, j, item, behavior, options, items;
 
         while( item = this.behaviors[ i++ ] ){
 
             //console.log("BEHAVIOR ", item.once?"ONCE ":"", nodes.length, item.s, typeOf(item.b) );
+            once = [];
             options = item.o;
             behavior = item.b;
             type = typeOf(behavior);
@@ -80,27 +81,33 @@ var Behavior = new Class({
 
             if( nodes[0] ){
 
-                if( item.once ){
+                for( j=0; node = nodes[ j++ ]; ){
 
-                    if( isClass ){ new behavior(nodes, options); }
-                    else if( isFunction ){ behavior(nodes, options); }
+                    updated = node[cache] || (node[cache] = []);
 
-                } else {
+                    if ( updated.indexOf(item) < 0 ){
 
-                    for( j=0; node = nodes[ j++ ]; ){
+                        if( item.once ){
 
-                        updated = node[cache] || (node[cache] = []);
+                            once.push( node );
 
-                        if ( updated.indexOf(item) < 0 ){
+                        } else {
 
                             //if( isString ) node[behavior](options);
                             if( isClass ){ new behavior(node, options); }
                             else if( isFunction ){ behavior.call(node, node, options); }
 
-                            updated.push( item );
                         }
+                        updated.push( item );
                     }
                 }
+
+                if( once[0] ){
+                    //console.log("ONCE", item.s , once.length);
+                    if( isClass ){ new behavior($$(once), options); }
+                    else if( isFunction ){ behavior($$(once), options); }
+
+                }
             }
         }
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/moo-extend/Color.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/moo-extend/Color.js b/jspwiki-war/src/main/scripts/moo-extend/Color.js
index c953146..3b0dc05 100644
--- a/jspwiki-war/src/main/scripts/moo-extend/Color.js
+++ b/jspwiki-war/src/main/scripts/moo-extend/Color.js
@@ -24,7 +24,7 @@ Class: Color
     This is a minimized variant of the Color class, based Mootools.More,
     written for jspwiki.
     It adds supports for html color names. (ref. http://en.wikipedia.org/wiki/Web_colors)
-�
+
 Arguments:
     color - (mixed) A string or an array representation of a color.
 
@@ -47,9 +47,7 @@ Examples:
 
 !function(){
 
-var VGA = "black#000 green#008000 silver#c0c0c0 lime#0f0 gray#808080 olive#808000 white#fff yellow#ff0 maroon#800000 navy#000080 red#f00 blue#00f purple#800080 teal#008080 fuchsia#f0f aqua#0ff",
-    c0l0r = 'i'.slick(),
-
+var c0l0r = 'i'.slick(),
     Color = this.Color = new Type('Color', function(color){
 
     if (arguments.length >= 3){
@@ -58,16 +56,16 @@ var VGA = "black#000 green#008000 silver#c0c0c0 lime#0f0 gray#808080 olive#80800
 
     } else if (typeof color == 'string'){
 
-        if(color.test(/^[\da-f]{3,6}$/i)){ color = "#"+color; }
-        c0l0r.setStyle('color',''); //reset the template
-        color = ( VGA.test( RegExp(color+"(#\\S+)","i" ) ) ? RegExp.$1 :
-            color.match(/rgb/i) ? color.rgbToHex() :
-                c0l0r.setStyle('color',color).getStyle('color') ).hexToRgb(true);
+        c0l0r.inject(document.body);
+        color = ( color.test(/^[\da-f]{3,6}$/i) ?  ("#" + color) :
+                 c0l0r.setStyle('color',color).getComputedStyle('color').rgbToHex() ).hexToRgb(true);  //[r,g,b]
+        c0l0r.remove();
 
     }
     if(!color){ return null; }
     color.rgb = color.slice(0, 3);
     color.hex = color.rgbToHex();
+
     return Object.append(color, this);
 });
 
@@ -94,11 +92,8 @@ Color.implement({
 
     invert: function(){
 
-        return new Color(255-this[0],255-this[1],255-this[2]);
+        return new Color(255-this[0], 255-this[1], 255-this[2]);
 
-        /*return new Color(this.map(function(value){
-            return 255 - value;
-        }));*/
     }
 
 });

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js b/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js
index e36316b..70161f1 100644
--- a/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js
+++ b/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js
@@ -358,7 +358,7 @@ Element.implement({
 
                 Array.from(this.options).each( function(option){
 
-                    if (option.defaultSelected){ values.push(option.value || option.text); }
+                    if (option.defaultSelected){ values[values.length] = option.value || option.text; }
 
                 });
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/moo-extend/String.Extend.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/moo-extend/String.Extend.js b/jspwiki-war/src/main/scripts/moo-extend/String.Extend.js
index ed5ce1b..12f34db 100644
--- a/jspwiki-war/src/main/scripts/moo-extend/String.Extend.js
+++ b/jspwiki-war/src/main/scripts/moo-extend/String.Extend.js
@@ -57,6 +57,14 @@ String.implement({
         return this.replace(/([a-z\xe0-\xfd])([A-Z\xc0-\xdd])/g,"$1 $2");
     },
 
+	//ES6 polyfill
+	startsWith: function( match ){
+		return !this.indexOf(match);
+	},
+	endsWith: function( match ){
+		return this.slice( -match.length ) == match ;
+	},
+
     /*
     Function: trunc
         Truncate a string to a maximum length
@@ -202,6 +210,9 @@ String.implement({
         > "zebra".sliceArgs( "zebra-eee-ffa" ); //returns ['eee','ffa']
         > "zebra".sliceArgs( "horse" );  //returns null
         > "zebra".sliceArgs( "zebra" );  //returns []
+        > "zebra".sliceArgs( "horse zebra-eee-ffa" ); //returns ['eee','ffa']
+        > "zebra".sliceArgs( "zebra-eee-ffa monkey" ); //returns ['eee','ffa']
+        > "zebra".sliceArgs( "horse zebra-eee-ffa monkey" ); //returns ['eee','ffa']
 
     */
     sliceArgs: function(element, regexp){
@@ -223,8 +234,8 @@ String.implement({
         Return a (string) classname to invoke the contextual colors.
 
     Example
-    >    'panel'.fetchContext( 'accordion-danger') => 'panel panel-danger'
-    >    'panel'.fetchContext( 'commentbox-success') => 'panel panel-success'
+    >    "panel".fetchContext( "accordion-danger") => 'panel panel-danger'
+    >    "panel".fetchContext( "commentbox-success") => 'panel panel-success'
 
     */
     fetchContext : function(element){

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/moo-extend/Textarea.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/moo-extend/Textarea.js b/jspwiki-war/src/main/scripts/moo-extend/Textarea.js
index 49b465a..07b1b9c 100644
--- a/jspwiki-war/src/main/scripts/moo-extend/Textarea.js
+++ b/jspwiki-war/src/main/scripts/moo-extend/Textarea.js
@@ -78,6 +78,9 @@ var Textarea = new Class({
     toElement: function(){
         return this.ta;
     },
+    focus: function(){
+        this.ta.focus();
+    },
 
     /*
     Function: getValue
@@ -86,6 +89,12 @@ var Textarea = new Class({
     getValue: function(){
         return this.ta.value;
     },
+
+    setValue: function(value){
+        this.ta.value = value;
+        this.setSelectionRange(0,0);
+        return this;
+    },
     /*
     Function: slice
         Invokes slice(..) on the value of the textarea

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Commands.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Commands.js b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Commands.js
index 309aafb..42fba89 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Commands.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Commands.js
@@ -86,7 +86,6 @@ Snipe.Commands = new Class({
             dialog,
             dialogs = options.dialogs || {};
 
-
         //add click buttons and dialogs
         container.addEvent("click:relay([" + dataCmd + "])", function(event){
 
@@ -98,6 +97,7 @@ Snipe.Commands = new Class({
             // input fields (eg checkboxes) keep the default behaviour; other click events are disabled
             if( !this.match("input") ){ event.stop(); }
 
+
         });
 
         //see if there are any dialogs linked to a button. Eg: "div.dialog.<command>"
@@ -234,9 +234,17 @@ Snipe.Commands = new Class({
 
         //console.log("Snipe.Commands: createDialog() " + command + " ",dialog );
 
-        if( typeOf(dialog) != "array" ){ dialog = [ Dialog.Selection, { body: dialog } ]; }
+        if( typeOf(dialog) != "array" ){
+
+            dialog = [ Dialog.Selection, { body: dialog } ];
+
+        }
+
+        if( !dialog[1].relativeTo ){
+
+            dialog[1].relativeTo = this.options.relativeTo || document.body;
 
-        if( !dialog[1].relativeTo ){ dialog[1].relativeTo = this.options.relativeTo || document.body; }
+        }
 
         dialog[1].autoClose = false;
 
@@ -262,7 +270,6 @@ Snipe.Commands = new Class({
             button = self.btns[command];
 
         //console.log("Snipe.Commands: openDialog() " + command + " " + activeDlg);
-
         if( activeDlg && (activeDlg != newDlg) ){ activeDlg.hide(); }
         self.activeDlg = self.dlgs[command];
 
@@ -284,7 +291,6 @@ Snipe.Commands = new Class({
             button = self.btns[command];
 
         //console.log("Snipe.Commands: closeDialog() " + command )
-
         if( self.dlgs[command] == self.activeDlg ){ self.activeDlg = null; }
 
         if( button ){ button.removeClass("active"); }

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Sections.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Sections.js b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Sections.js
index 7e2a4cb..940e483 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Sections.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Sections.js
@@ -18,19 +18,18 @@
 /*eslint-env browser*/
 /*global $, Class, Events, Snipe  */
 /*
-Class: SnipEditor.Sections
-    This dialog displays the list of page sections.
+Class: Snipe.Sections
+    This class implement section based editing in Snipe.
+    Based on the selected section, the Snipe textarea will be filled with a
+    part of the full content of the main textarea.
+    At all times the main textarea will contain the full text.
 
-    (all) - allows to select all sections (auto generated)
-    start-of-page - only present when first section starts on an offset > 0
-    section1..n - section titles, with indentation level depending on their weight
+    This class keeps track for the current list of page section titles.
 
-    The set of sections is generated by the parseSections() callback handler.
-    This parser returns an array of section "descriptors":
+    The set of sections is generated by the parser() callback handler.
+    That parser returns an array of section "descriptors":
 >    [ {title:text, start:char-offset, indent:indentation-level}, ... ]
 
-    Clicking an entry triggers the updateSections() callback handler.
-    FIXME: why not fire an onAction event (similar to other dialogs)
 
 Depends:
     Snipe
@@ -38,18 +37,19 @@ Depends:
 Example:
 (start code)
     div.cage
-      div.btn.btn-link
-        span.icon-bookmark
-            span.caret
-      ul.dropdown-menu [data-sections="div"][data-hover-parent=".cage"]
-        li  a first
-        li  a ..
-        li  a.dropdown-divider
-        li  a ..
-
-
-    new Snipe.Sections( sectionDropDown, {
-        snipe: snipe,
+      div.sections
+        button.btn.btn-default
+          span.icon-bookmark
+          span.caret
+        ul.dropdown-menu[data-hover-parent="div"]
+          li  a first
+          li  a ..
+          li  a.dropdown-divider
+          li  a ..
+
+    new Snipe.Sections( snipe, {
+        main: <main textarea>
+        menu: <ul dropdownmenu>,
         parser: function(text){ .. return [[{title, start, depth}],..]; }
     });
 (end)
@@ -61,31 +61,34 @@ Snipe.Sections = new Class({
     Binds: ["show","update","action"],
 
     options: {
-        //snipe: snip-editor
+        //main
+        //menu
         //parser: function(text){ returns [[title,start,depth]..] }
         all: "( all )".localize(),
+        sections: ".sections",
         startOfPage: "Start of Page".localize()
     },
 
-    initialize: function(element, options){
+    initialize: function(snipe, options){
 
-        var self = this,
-            snipe = options.snipe;
+        var self = this;
 
-        self.container = element;
+        self.snipe = snipe;
+        self.main = options.main;
         self.parser = options.parser;
 
-        self.list = element.getElement("ul").addEvent("click:relay(a)", self.action);
+        if( options.menu ){
 
-        self.main = snipe.get("mainarea");
-        self.work = $( snipe.get("textarea") );
+            self.list = options.menu.addEvent("click:relay(a)", self.action);
 
-        snipe.addEvent( "change", self.update.debounce(500) );
+        }
 
         self.parse();
         self.action( location.search );  //url?section=0..n
-        self.show();
+        self.menu();
 
+        //finally, connect to the update event of snipe !
+        snipe.addEvent( "change", self.update );
     },
 
     /*
@@ -97,14 +100,14 @@ Snipe.Sections = new Class({
         >        0 : start-of-page (if applicable) => title=s-1 => cursor=-1
         >        1..n : page sections              => title=s0..sn => cursor=0..n
     */
-    parse: function(){
+    parse: function( ){
 
         this.sections = this.parser( this.main.value );
 
     },
 
     /*
-    Function: show
+    Function: menu
         UPDATE/RFEFRESH the section dropdown-menu.
         Highlight the current item.
 
@@ -124,97 +127,95 @@ Snipe.Sections = new Class({
                 a.indent-0.section99 Title-Section-2
     (end)
     */
-    show: function( ){
+    menu: function( ){
 
-        //console.log("Sections show",this.current, this.sections.length, this.sections[3]);
+        //console.log("menu", this.current, this.sections.length, this.sections);
 
         var data = [],
+            list = this.list,
             options = this.options,
             current = this.current,
             sections = this.sections,
 
-            addItem = function(indent,name,offset){
-
-                data.push("li" + (offset==current ? ".active" : ""),[
-                    "a.indent-" + indent + ".section" + offset, { html:name }
+            addItem = function(item, index){
+                data.push("li" + (index == current ? ".active" : ""),[
+                    "a.indent-" + item.depth + ".section" + index, { html:item.title }
                 ]);
-
             };
 
-        addItem(0, options.all ,-2);
+        if( list ){
 
-        if( sections[0] ){
+            addItem({ depth:0, title:options.all }, -2);
 
-            if( sections[0].start > 0 ){ addItem(0, options.startOfPage, -1); }
+            if( sections[0] ){
 
-            data.push( "li.divider" );
-
-            sections.each( function(item, idx){
+                if( sections[0].start > 0 ){
+                    addItem({ depth:0, title:options.startOfPage }, -1);
+                }
+                data.push( "li.divider" );
+                sections.each( addItem );
+            }
 
-                addItem( item.depth, item.title/*.trunc(36)*/, idx );
+            list.empty().adopt( data.slick() );
 
-            });
+            list.getParent().ifClass( current >= -1, "section-selected");
 
         }
 
-        this.list.empty().adopt( data.slick() );
-
     },
 
     /*
     Function: update
-        Make sure that changes to the work textarea are propagated to the main textarea.
-        This function handles the propagation of changes into the main textarea.
+        This function handles the propagation of changes from snipe to the main textarea.
+        It is triggered by a change event on snipe.
     */
     update: function(){
 
-        //console.log("****Snipe.Sections : change main");
-
         var self = this,
             main = self.main,
-            work = self.work.value,
+            work = self.snipe.get("value"),
             s = main.value;
 
         //insert \n to ensure the next section always starts on a new line.
         if( work.slice(-1) != "\n" ){ work +="\n"; }
 
         //console.log("change txta: from="+self.begin+ " end="+self.end);
-        main.value = s.slice(0, self.begin) + work  + s.slice(self.end);
+        if( work != s.slice(self.begin, self.end) ){
 
-        self.end = self.begin + work.length;
+            main.value = s.slice(0, self.begin) + work  + s.slice(self.end);
 
-        self.parse();
-        self.show();
+            self.end = self.begin + work.length;
 
+            self.parse();
+        }
+        self.menu(); //always update menu, independent of the content of main
     },
 
     /*
     Function: action
-        This function copies the selected section from the main to the work textarea.
-        It is invoked at initialization and through the dialog onAction click handler.
+        This function copies the selected section from the main to the snipe textarea.
+        It is invoked at initialization and through click handlers in the
+        section dropdown menu.
 
     Arguments:
-        item - index of selected section: all, -1, 0..n
+        item - index of selected section: all(-2), -1, 0..n
     */
-    action:function( item ){
+    action: function( item ){
 
-        //console.log("Sections: action",item);
         var self = this,
             main = self.main.value,
-            work = self.work,
             sections = self.sections,
             begin = 0,
             end = main.length;
 
         if( item ){
 
-            //item.target => event.target; this is an onclick invocation
+            //item.target => event.target; this is an onclick invocation!
             if( item.target ){ item = item.target.className; }
 
             //section-2=All, section-1=StartOfPage, section0..section99=rest
             item = ( item.match( /section=?(-?\d+)/ )||[,-2])[1].toInt();
 
-
             if( item == -1 ){
 
                 //show the Start Of Page, prior to the first real section
@@ -223,7 +224,7 @@ Snipe.Sections = new Class({
             } else if(item >= 0  && sections[item] ){
 
                 begin = sections[item].start;
-                if( sections[item+1] ){ end = sections[item+1].start; }
+                if( sections[item + 1] ){ end = sections[item + 1].start; }
 
             }
 
@@ -231,19 +232,12 @@ Snipe.Sections = new Class({
 
         }
 
-        //work.value = "";  //FIXME google chrome  43.0.2357.65 bug -- if omitted, the textarea is displayed EMPTY!! ??
-        work.value = main.slice(begin, end);
-        work.setSelectionRange(0,0); //why not go via Textarea()..., for better bw compat.
         self.begin = begin;
         self.end = end;
 
-        //section-selected class : turn bookmark icon red or blue
-        self.container.ifClass( item >= -1, "section-selected");
-
-        //update the dropdown menu, and highlight the current item
-        self.show();
-
-        work.fireEvent("change");  //needed to rerun page preview
+        //finally set the new snipe value
+        //note: this triggers a change event, and calls update()
+        self.snipe.set("value", main.slice(begin, end) );
 
         return false; //stop click event propagation
 

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js
index 9ffade6..a8d3b8e 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.Snips.js
@@ -76,22 +76,23 @@ Snipe.Snips = new Class({
                 if( typeOf(suggest) == "string" ){
 
                     snip.suggest = {
-                        pfx: RegExp( suggest + "$" ),
+                        lback: RegExp( suggest + "$" ),
                         match: RegExp( "^" + suggest )
                     }
-                    //console.log( snip.suggest );
+
                 }
 
                 self.suggestions[cmd] = snip;
 
-            } else {
-
-                //otherwise regular snippet
+             //otherwise regular snippet
+             //} else {
 
             }
 
             //check for snip dialogs -- they have the same name as the command
-            if( snip[cmd] ){ self.dialogs[cmd] = snip[cmd]; }
+            //TODO better:  use the dialog property !
+            if( snip[cmd] ){ self.dialogs[cmd] = snip[cmd]; }  //deprecated
+            if( snip.dialog ){ self.dialogs[cmd] = snip.dialog; }
 
             snips[cmd] = snip;
 
@@ -110,7 +111,7 @@ Snipe.Snips = new Class({
 
         for( cmd in this.snips ){
 
-            if( fromStart.test( cmd + "$" ) ){ return cmd; }
+            if( fromStart.endsWith( cmd ) ){ return cmd; }
 
         }
 
@@ -120,7 +121,7 @@ Snipe.Snips = new Class({
 
     /*
     Function: matchSuggest
-        Lookup a cmd enter just in front of the caret/cursor of the workarea..
+        Lookup a cmd which matches the suggestion look-back and match reg-exps.
 
         snip.suggest => {
             start: (number) start position,
@@ -130,17 +131,12 @@ Snipe.Snips = new Class({
     */
     matchSuggest: function(){
 
-        var cmd, snip, pfx, match, result, suggest,
+        var cmd, snip, lback, match, result, suggest,
             suggestions = this.suggestions,
             workarea = this.workarea,
             caret = workarea.getSelectionRange(),
             fromStart = workarea.getFromStart();
 
-        //"selectInline", "selectBlock", "selectStartOfLine";
-
-        //var SOL = workarea.isCaretAtStartOfLine();
-        //var EOL = workarea.isCaretAtEndOfLine();
-
         for( cmd in suggestions ){
 
             snip = suggestions[cmd];
@@ -149,23 +145,23 @@ Snipe.Snips = new Class({
 
                 suggest = snip.suggest;
 
-                if( suggest.pfx ){
+                if( suggest.lback ){
 
-                    pfx = fromStart.match( suggest.pfx );
+                    lback = fromStart.match( suggest.lback );
 
-                    if( pfx ){
+                    if( lback ){
 
-                        console.log("SUGGEST Prefix ", cmd, suggest.pfx, pfx.getLast() );
-                        pfx = pfx.getLast(); //match last (x)
+                        //console.log("SUGGEST Look-Back ", cmd, suggest.lback, lback.getLast() );
+                        lback = lback.getLast(); //match last (x)
 
-                        match = workarea.slice( caret.start - pfx.length )
+                        match = workarea.slice( caret.start - lback.length )
                                          .match( suggest.match );
 
-                        console.log("SUGGEST Match ", suggest.match, match );
+                        //console.log("SUGGEST Match ", suggest.match, match );
 
                         if( match ){
 
-                            result = { pfx: pfx, match: match.getLast() } ;
+                            result = { lback: lback, match: match.getLast() } ;
 
                         }
 
@@ -251,9 +247,9 @@ Snipe.Snips = new Class({
             for( pattern in patterns ){
 
                 pos = text.lastIndexOf( pattern );
+
                 if( (pos > -1) && (text.indexOf( patterns[pattern], pos ) == -1) ){
                         return inscope;
-
                 }
             }
             return !inscope;

http://git-wip-us.apache.org/repos/asf/jspwiki/blob/19b54311/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js
----------------------------------------------------------------------
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js
index 2b090e8..19ddc5b 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js
@@ -102,7 +102,7 @@ var Snipe = new Class({
         sectionParser: function(){ return {}; }
     },
 
-    initialize: function(el, options){
+    initialize: function(element, options){
 
         options = this.setOptions(options).options;
 
@@ -117,13 +117,15 @@ var Snipe = new Class({
             The main textarea is hidden and contains always the complete document.
             On submit, the mainarea is send back to the server.
             */
-            main = self.mainarea = $(el),
-            work = main.clone().erase("name").inject( main.hide(), "before" ),
-            container = options.container || work.form,
+            //main = self.mainarea = $(el),
+            //work = main.clone().erase("name").inject( main.hide(), "before" ).addClass("snipe-work"),
+            container = options.container || $(element).form,
 
             // Augment the textarea element with extra capabilities
             // Make sure the content of the mainarea is always in sync with the workarea
-            textarea = self.textarea = new Textarea( work );
+            //textarea = self.textarea = new Textarea( work );
+            textarea = self.textarea = new Textarea( element );
+
 
         self.directsnips = new Snipe.Snips( textarea, options.directsnips );
         self.snippets    = new Snipe.Snips( textarea, options.snippets );
@@ -133,14 +135,14 @@ var Snipe = new Class({
                 //feed the find dialog with searchable content
                 get: function(){
                     var selection = textarea.getSelection();
-                    return (selection=="") ? work.value : selection;
+                    return (selection=="") ? element.value : selection;
                     //return (selection=="") ? textarea.getValue() : selection;
                 },
                 set: function(v){
                     var s = textarea.getSelectionRange();
-                    //self.fireEvent("beforeChange");
+                    self.fireEvent("beforeChange"); //make undoable
                     //textarea[ s.thin ? "setValue" : "setSelection" ](v);
-                    s.thin ? work.value = v : textarea.setSelection(v);
+                    s.thin ? element.value = v : textarea.setSelection(v);
                     self.fireEvent("change");
                 }
             }
@@ -150,8 +152,8 @@ var Snipe = new Class({
         //Commands are entered via tab-completion, button clicks, or a dialog.
         //Snipe.Commands ensures that at most one dialog is open at the same time.
         self.commands = new Snipe.Commands( container, {
-            //onOpen: function( /*command*/ ){ work.focus(); },
-            onClose: function( /*command*/ ){ work.focus(); },
+            onOpen: function( /*command*/ ){ element.focus(); },
+            onClose: function( /*command*/ ){ element.focus(); },
             onAction: self.action,
             dialogs: self.snippets.dialogs,
             relativeTo: textarea
@@ -160,7 +162,7 @@ var Snipe = new Class({
 
         self.reset();
 
-        work.addEvents({
+        element.addEvents({
 
             keydown: self.keystroke,
             keypress: self.keystroke,
@@ -171,7 +173,7 @@ var Snipe = new Class({
             click: self.suggest.debounce(),
 
             input: (function( ){
-                console.log("***Snipe: dom textarea input :");
+                //console.log("change event on input");
                 self.fireEvent("change");
             }).debounce()
 
@@ -193,7 +195,7 @@ var Snipe = new Class({
 
     */
     toElement: function(){
-        return $(this.textarea);
+        return this.textarea.toElement();
     },
 
     /*
@@ -205,7 +207,8 @@ var Snipe = new Class({
     */
     get: function(item){
 
-        return( /mainarea|textarea/.test(item) ? this[item] :
+        return( "value" == item ? this.textarea.getValue() :
+                /mainarea|textarea/.test(item) ? this[item] :
                 /snippets|directsnips|autosuggest|tabcompletion|smartpairs/.test(item) ? this.options[item] :
                 null );
 
@@ -214,6 +217,7 @@ var Snipe = new Class({
     /*
     Function: set
         Set/Reset some of the options of the snip-editor.
+        Also use to set/reset the content of the textarea. (eg section editing)
 
     Arguments:
         item - snippets|directsnips|autosuggest|tabcompletion|smartpair
@@ -223,9 +227,18 @@ var Snipe = new Class({
     */
     set: function(item, value){
 
-        if( /snippets|directsnips|autosuggest|tabcompletion|smartpairs/.test(item) ){
+        if( item == "value" ){
+
+            this.textarea.setValue( value );
+            this.fireEvent("beforeChange"); //make undoable
+            this.textarea.focus();
+
+        } else if( /snippets|directsnips|autosuggest|tabcompletion|smartpairs/.test(item) ){
+
             this.options[item] = value;
+
         }
+
         return this.fireEvent("change");
     },
 
@@ -242,7 +255,7 @@ var Snipe = new Class({
     */
     shortcut: function(e){
 
-        var key, keycmd;
+        var key, cmd;
 
         if( e.shift || e.control || e.meta || e.alt ){
 
@@ -252,14 +265,14 @@ var Snipe = new Class({
                         (e.alt ? "alt+":"") +
                           e.key,
 
-            //console.log("shortcut ",key);
-            keycmd = this.snippets.keys[key];
+            console.log("shortcut ",key);
+            cmd = this.snippets.keys[key];
 
-            if ( keycmd ){
+            if ( cmd ){
 
-                //console.log("Snipe shortcut",key,keycmd,e.code);
+                //console.log("Snipe shortcut", key, cmd, se.code);
                 e.stop();
-                this.commands.action( keycmd );
+                this.commands.action( cmd );
 
             }
         }
@@ -310,11 +323,10 @@ var Snipe = new Class({
 
         var self = this,
             txta = self.textarea,
-            //el = txta.toElement(),
             key = e.key,
             caret = txta.getSelectionRange();
 
-        txta.toElement().focus();
+        txta.focus();
 
         if( /up|down|esc/.test(key) ){
 
@@ -512,7 +524,6 @@ var Snipe = new Class({
     Function: setContext
         Store the active snip. (state)
         EG, subsequent handling of dialogs.
-        As long as a snippet is active, the textarea gets the css class {{.activeSnip}}.
 
     Arguments:
         snip - snippet object to make active
@@ -527,7 +538,6 @@ var Snipe = new Class({
 
         //console.log("Snipe.setContext",snip,suggest);
         this.context = { snip:snip, suggest:suggest };
-        this.toElement().addClass("activeSnip");
 
     },
 
@@ -538,9 +548,9 @@ var Snipe = new Class({
     */
     reset: function(){
 
-        //console.log("Snipe:reset", this.context);
-        this.context = {};
-        this.toElement().removeClass("activeSnip").focus();
+        console.log("Snipe:reset", this.context);
+        this.context = null;
+        this.textarea.focus();
         this.commands.close();
 
     },
@@ -618,11 +628,10 @@ var Snipe = new Class({
 
                 console.log( "Snipe.suggest ",suggest );
                 this.setContext( null/*snip*/, suggest );
-                return this.commands.action( suggest.cmd , suggest.pfx );
+                return this.commands.action( suggest.cmd , suggest.lback );
 
             }
-
-            this.commands.close();
+            this.reset();
         }
     },
 
@@ -630,160 +639,222 @@ var Snipe = new Class({
     /*
     Function: action
         This function executes the command action.
-        It will insert the snippet and update the selection and caret.
+        It will coordinate to get the snippet inserted and move the
+        caret to the proper position after insertion.
 
-        It looks up and processes the snippet.
-        - insert the snippet text at the caret in the textarea.
-        - when text was selected (prior to the click or keyup event):
-            - the snippet text will replace the selection
-            - the selection will be passed as a parameter into the snippet
-            - if the snippet has ONE parameter, the snippet text will be toggled:
-              i.e. remove the snippet when already present, otherwise insert the snippet
+        Actions can be triggered via:
+        - tab-completion
+        - click-event from the [data-cmd] DOM element
+        - short-cut key
+        - matched suggestion (with look-back and match strings)
 
     Arguments:
         cmd - (string) used to loopup the snippet
         args - (optional) additional snippet arguments (eg value passed via a dialog)
     */
-    action: function( cmd ){
+    action: function( cmd /*, more command arguments */ ){
 
         var self = this,
             args = Array.slice(arguments, 1),
             snip = self.snippets.get( cmd ),
-            //snippet = snip.snippet,
-            s = snip.snippet,
-            suggest = snip.suggest && self.context.suggest,
-
             txta = self.textarea,
-            caret = txta.getSelectionRange(),
-            hasCaret = !caret.thin,
-            caretStart = caret.start,
+            caret,
+            snipXL,
+            snippet = snip.suggest ? args.join() : snip.snippet,
+            suggest = snip.suggest && self.context && self.context.suggest;
+
+        function unesc(s){ return s.replace(/~\{/g, "{"); }
 
-            pfx, sel, sfx, snipArr, selectionLength,
-            /* match "pfx{selection}sfx" into ["pfx","selection","sfx"] */
-            /* do not match "pfx~{do-not-match}sfx"  */
-            snipSelection = /(^|[\S\s]*[^~])\{([^\{\}]+)\}([\S\s]*)/,
-            snipEscapeChar = /~\{/g;
+        console.log("Snipe:action ", cmd, "snippet=",snippet, "args=",args, "suggest=",suggest );
 
-        function setCaret(start,end){ txta.setSelectionRange(start, end); }
-        function removeEscapeChar(s){ return s.replace(snipEscapeChar, "{"); }
+        if( !snip ) return;
 
-        console.log("Snipe:action ", snip, s, cmd, args,suggest );
+        if( snip.event ){
+            //console.log("Snipe:action Event: ",snip.event);
+            self.fireEvent(snip.event, arguments);
 
-        if( snip ){
+        } else {
 
-            if( snip.event ){
+            self.fireEvent("beforeChange"); //make action undoable
 
-                //console.log("Snipe:action() fire-event: ",snip.event);
-                return self.fireEvent(snip.event, arguments);
+            if( suggest ){
+
+                snippet = self.suggestAction( txta, snippet, suggest.lback, suggest.match);
 
             }
 
-            this.fireEvent("beforeChange"); //CHECKME
 
-            //adjust caret based on suggestion context
-            if( suggest ){
+            /*
+            Match "pfx{=copy-selection}sfx" and replace by "pfx<selection>sfx"
+            snippet = snippet.replace(/..../, function(match, target){
+                if(selection){
+                    target = selection; selection = "";
+                }
+                return target;  //alse removing the {= and }
+            });
+            */
 
-                s = args.join();  //result of the suggest dialog
-                selectionLength = suggest.match.length;
 
-                if( s.startsWith(suggest.pfx) ){
+            /*
+            Match "pfx{selection}sfx"
 
-                    s = s.slice(suggest.pfx.length);
-                    selectionLength -= suggest.pfx.length;
+            snippet = snippet.replace( /regexp/, selection || RegExp.$1 );
 
-                } else {
+            and also handle toggle !!?
+            */
 
-                    caretStart -= suggest.pfx.length;
 
-                }
+            // match "pfx{selection}sfx" into ["pfx","selection","sfx"]
+            // do not match "pfx~{do-not-match}sfx"
+            if( snipXL = snippet.match( /(^|[\S\s]*[^~])\{([^!\{\}][^\{\}]*)\}([\S\s]*)/ ) ){
+            //if( snipXL = snippet.match( /(^|[\S\s]*[^~])\{([^\{\}]+)\}([\S\s]*)/ ) ){
+
+                //console.log("Snipe:action complex snippet 'pfx{selection}sfx' ", pfx, sel, sfx, caret.thin );
+                self.injectXL( txta,
+                               snippet,
+                               unesc( snipXL[1] ), //pfx
+                               snipXL[2],          //sel
+                               unesc( snipXL[3] )  //sfx
+                );
 
-                //move the caret according to suggest pfx and match
-                setCaret( caretStart, caretStart +  selectionLength );
-                hasCaret = selectionLength > 0;
+            } else {
+
+                //if no selection, just insert and move caret after inserted snippet
+                caret = txta.getSelectionRange();
+                snippet = unesc(snippet);
+
+                //console.log("Snipe:action simple snippet", caret.thin, snippet );
+                self.inject( txta,
+                             snippet,
+                             caret.start + (caret.thin ? snippet.length : 0),
+                             caret.thin ? 0 : snippet.length );
             }
 
-            if( (snipArr = s.match( snipSelection )) ){
+        }
 
-                pfx = removeEscapeChar( snipArr[1] );
-                sel = hasCaret ?  txta.getSelection() : snipArr[2] ;
-                sfx = removeEscapeChar( snipArr[3] );
+        self.reset();
+        self.fireEvent("change");
+        self.suggest.delay(1, self); //allow some time to finish any actions, before opening a new suggestion dialog
 
-                console.log("found a 'pfx{selection}sfx' snippet", snipArr, pfx, sel, sfx,hasCaret );
+    },
 
-                if( hasCaret ) {
+    /*
+    Function: suggestAction
+        Adjust the snippet and the caret based on the suggestion context.
+        The selection is set to the matched suggestion string, to prepare for the later
+        snippet replacement.
+        When the snippet starts with the look-back string; only the last part
+        of the matched suggestion string should be replaced by the snippet.
+        Returns a adjusted snippet.
+
+    Example:  ($==caret position)
+        [te$st] => lback = "te", match = "test",  snippet ="wiki-page"
+            Selection will become "test",  and snippet will become "wiki-page"
+        [te$st] => lback = "te", match = "test",  snippet ="team-page"
+            Selection will become "st",  and snippet will become "am-page"
+    */
+    suggestAction: function( txta, snippet, lback, match){
 
-                    if( sel.startsWith(pfx) && sel.endsWith(sfx) ){
+        var start = txta.getSelectionRange().start,
+            len = match.length;
 
-                        console.log("TOGGLE: pfx/sfx matched inside the selection",caret.start,caret.end);
-                        sel = sel.slice( pfx.length, -sfx.length );
-                        pfx = sfx = "";
+        //console.log("Snipe:suggestAction ",snippet,lback,match );
+        if( snippet.startsWith( lback ) ){
 
-                    } else if( txta.getFromStart().endsWith(pfx)
-                            && txta.getTillEnd().startsWith(sfx) ){
+            //remove the look-back part of the snippet
+            snippet = snippet.slice( lback.length );
+            len -= lback.length;
 
-                        console.log("TOGGLE: pfx/sfx matched outside the selection",caret.start,caret.end);
-                        caretStart -= pfx.length;
-                        setCaret( caretStart, caret.end + sfx.length); //enlarge the selection
-                        pfx = sfx = "";
+        } else {
 
-                    }
-                }
+            //move the cursor to the start of the match
+            start -= lback.length;
 
-                s = pfx + sel + sfx;
-                caretStart += pfx.length;
-                selectionLength = sel.length;
+        }
 
-            } else {
+        txta.setSelectionRange(start, start + len); //move the cursor
 
-                console.log("plain text snippet", hasCaret,s );
-                s = removeEscapeChar( s );
-                caretStart += hasCaret ? 0 : s.length;
-                selectionLength = hasCaret ? s.length : 0;
+        return snippet;
 
-            }
+    },
 
-            self.inject(s, caretStart, selectionLength);
-            self.reset();
+    /*
+    Function: injectXL
+        Inject a complex snippet.
+        Complex snippet match this pattern: "pfx{selection}sfx".
+        The part inside the "{..}" should be replaced by the selection.
+        If the selection has already the pfx/sfx strings,  they should be toggled.
+    Example
+        snippet: "__{bold}__", no selection
+            Snippet "__bold__" will be inserted, selection will become "bold"
+        snippet: "__{bold}__", selection:"pipo"
+            Snippet "__pipo__" will be inserted, selection will become "pipo"
+        snippet: "__{bold}__", selection:__"pipo"__
+            Snippet "pipo" will replace "__pipo__", selection will become "pipo"
+        snippet: "__{bold}__", selection:"__pipo__"
+            Snippet "pipo" will replace selection, selection will become "pipo"
+    */
+    injectXL: function( txta, snippet, pfx, sel, sfx){
+
+        var caret = txta.getSelectionRange(),
+            start = caret.start;
+
+        if( !caret.thin ) {
 
-            self.fireEvent("change");
-            //allow to finish the actions, before opening a new suggestion dialog
-            self.suggest.delay(10, self);
+            sel = txta.getSelection();
 
+            if( sel.startsWith(pfx) && sel.endsWith(sfx) ){
+
+                //console.log("TOGGLE: pfx/sfx matched inside the selection",caret.start,caret.end);
+                sel = sel.slice( pfx.length, -sfx.length );
+                pfx = sfx = "";
+
+            } else if( txta.getFromStart().endsWith(pfx)
+                    && txta.getTillEnd().startsWith(sfx) ){
+
+                //console.log("TOGGLE: pfx/sfx matched outside the selection",caret.start,caret.end);
+                start -= pfx.length;
+                txta.setSelectionRange(start , caret.end + sfx.length);
+                pfx = sfx = "";
+
+            }
         }
 
+        this.inject( txta, pfx + sel + sfx, start + pfx.length, sel.length);
+
     },
 
-    inject: function( snippet, start, selectionLength ){
+    /*
+    Function: inject
+        Replace the selection by the snippet and set a new selection.
+        Collapse leading and trailing \n characters
+        Autoindent the (multi-line) snippet.
+    */
+    inject: function( txta, snippet, start, selectionLen ){
 
-        var self = this,
-            txta = self.textarea,
-            fromStart = txta.getFromStart(),
+        var fromStart = txta.getFromStart(),
             prevline = fromStart.split(/\r?\n/).pop(),
-            indentation = prevline.match(/^\s+/);
-
-        //console.log(snippet,start,selectionLength);
+            indent = prevline.match(/^\s+/);
 
-        //process whitespace before and after the snippet
-        //collapse \n of previous line if the snippet starts with \n
         if( snippet.test(/^\n/) && ( fromStart.test( /(^|[\n\r]\s*)$/ ) ) ) {
-            //console.log("remove leading \\n", snippet);
+            //console.log("collapse leading \\n", snippet);
             snippet = snippet.slice( 1 );
             start--;
         }
 
-        //collapse \n of the next line when the snippet ends with a \n
         if( snippet.test(/\n$/) && ( txta.getTillEnd().test( /^\s*[\n\r]/ ) ) ) {
-            //console.log("remove trailing \\n", snippet);
+            //console.log("collapse trailing \\n", snippet);
             snippet = snippet.slice(0, -1);
+            start--;
         }
 
-        //finally auto-indent the snippets internal newlines \n
-        if( indentation ){
-            snippet = snippet.replace( /\n/g, "\n" + indentation[0] );
+        if( indent ){
+            //console.log("auto-indent internal newlines \n");
+            snippet = snippet.replace( /\n/g, "\n" + indent[0] );
         }
 
         txta.setSelection( snippet )
-            .setSelectionRange( start, start + selectionLength );
+            .setSelectionRange( start, start + selectionLen );
 
     },
 
@@ -801,7 +872,7 @@ var Snipe = new Class({
             el = txta.toElement();
 
         return {
-            main: this.mainarea.value,
+            //main: this.mainarea.value,
             value: el.get("value"),
             cursor: txta.getSelectionRange(),
             scrollTop: el.scrollTop,
@@ -823,7 +894,7 @@ var Snipe = new Class({
             el = txta.toElement();
 
         self.reset();
-        self.mainarea.value = state.main;
+        //self.mainarea.value = state.main;
         el.value = state.value;
         el.scrollTop = state.scrollTop;
         el.scrollLeft = state.scrollLeft;