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 2019/03/09 20:25:55 UTC

[jspwiki] branch master updated: 2.11.0-M3-git-02: editor drag&drop capabilities

This is an automated email from the ASF dual-hosted git repository.

brushed pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jspwiki.git


The following commit(s) were added to refs/heads/master by this push:
     new b69256a   2.11.0-M3-git-02: editor drag&drop capabilities
b69256a is described below

commit b69256a48d2b2e781f41a42c39e1602121ff0b47
Author: brushed <di...@gmail.com>
AuthorDate: Sat Mar 9 21:25:44 2019 +0100

     2.11.0-M3-git-02: editor drag&drop capabilities
---
 ChangeLog                                          |   9 +
 .../src/main/java/org/apache/wiki/Release.java     |   2 +-
 jspwiki-war/src/main/config/wro/wro-haddock.xml    |   5 +-
 jspwiki-war/src/main/config/wro/wro.properties     |   1 +
 .../src/main/scripts/moo-extend/Textarea.js        |  59 +++++-
 .../src/main/scripts/wiki-edit/Html2Wiki.js        | 227 +++++++++++++++++++++
 jspwiki-war/src/main/scripts/wiki-edit/Snipe.js    |  11 +-
 .../src/main/scripts/wiki-edit/Wiki.Edit.js        |  27 ++-
 .../src/main/styles/haddock/default/type.less      |   3 +-
 9 files changed, 323 insertions(+), 21 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index d71fa6c..a9d326b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
 2019-03-09  Dirk Frederickx (brushed AT apache DOT org)
 
+       * 2.11.0-M3-git-02
+
+       * Adding Drag & Drop capabilities to the standard JSPWiki editor:
+         links automatically are converted to [descriptiol|url] format
+         other content (text, tables, etc...) will be converted to wiki-markup.
+
+
+2019-03-09  Dirk Frederickx (brushed AT apache DOT org)
+
        * 2.11.0-M3-git-01
 
        * UserPreferences fixes
diff --git a/jspwiki-main/src/main/java/org/apache/wiki/Release.java b/jspwiki-main/src/main/java/org/apache/wiki/Release.java
index 96f5860..602abbf 100644
--- a/jspwiki-main/src/main/java/org/apache/wiki/Release.java
+++ b/jspwiki-main/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         = "01";
+    public static final String     BUILD         = "02";
 
     /**
      *  This is the generic version string you should use when printing out the version.  It is of
diff --git a/jspwiki-war/src/main/config/wro/wro-haddock.xml b/jspwiki-war/src/main/config/wro/wro-haddock.xml
index 7cb0ccf..623698d 100644
--- a/jspwiki-war/src/main/config/wro/wro-haddock.xml
+++ b/jspwiki-war/src/main/config/wro/wro-haddock.xml
@@ -32,10 +32,10 @@
     <js>/scripts/moo-extend/Function.Extend.js</js>
     <js>/scripts/moo-extend/Behavior.js</js>
     <js>/scripts/moo-extend/String.Extend.js</js>
+    <!--<js>/scripts/moo-extend/Date.Extend.js</js>-->
     <js>/scripts/moo-extend/Array.Extend.js</js>
     <js>/scripts/moo-extend/Array.NaturalSort.js</js>
     <js>/scripts/moo-extend/Element.Extend.js</js>
-    <js>/scripts/moo-extend/Element.Placeholder.js</js>
     <js>/scripts/moo-extend/Color.js</js>
     <js>/scripts/moo-extend/HighlightQuery.js</js>
     <js>/scripts/moo-extend/Accesskey.js</js>
@@ -67,7 +67,6 @@
   </group>
 
   <group name="haddock">
-
     <group-ref>lib</group-ref>
     <group-ref>mooextend</group-ref>
     <group-ref>behaviors</group-ref>
@@ -92,7 +91,6 @@
   </group>
 
   <group name="haddock-edit">
-
     <js>/scripts/moo-extend/Date.Extend.js</js>
     <js>/scripts/moo-extend/Array.Extend.HSV.js</js>
 
@@ -105,6 +103,7 @@
     <js>/scripts/dialog/Dialog.Find.js</js>
 
     <js>/scripts/moo-extend/Textarea.js</js>
+    <js>/scripts/wiki-edit/Html2Wiki.js</js>
     <js>/scripts/wiki-edit/Undoable.js</js>
     <js>/scripts/wiki-edit/Snipe.js</js>
     <js>/scripts/wiki-edit/Snipe.Snips.js</js>
diff --git a/jspwiki-war/src/main/config/wro/wro.properties b/jspwiki-war/src/main/config/wro/wro.properties
index 7c810dc..fdf5c5a 100644
--- a/jspwiki-war/src/main/config/wro/wro.properties
+++ b/jspwiki-war/src/main/config/wro/wro.properties
@@ -23,3 +23,4 @@ debug=true
 preProcessors=cssImport,semicolonAppender
 #postProcessors=lessCss,yuiCssMin,uglifyJs
 postProcessors=less4j,yuiCssMin,uglifyJs
+
diff --git a/jspwiki-war/src/main/scripts/moo-extend/Textarea.js b/jspwiki-war/src/main/scripts/moo-extend/Textarea.js
index 3b084bb..3b36cc5 100644
--- a/jspwiki-war/src/main/scripts/moo-extend/Textarea.js
+++ b/jspwiki-war/src/main/scripts/moo-extend/Textarea.js
@@ -18,10 +18,13 @@
     specific language governing permissions and limitations
     under the License.
 */
+
 /*eslint-env browser*/
 /*global Class, Options, Events  */
 /*exported Textarea */
 
+/*exported Textarea */
+
 /*
 Class: Textarea
     The textarea class enriches a TEXTAREA element, and provides cross browser
@@ -43,11 +46,8 @@ var Textarea = new Class({
     initialize: function(el, options){
 
         var self = this,
-            ta = self.ta = document.id(el),
-            fireChange = function( event ){
-                console.log('hi');
-                self.fireEvent("change", event);
-            };
+            ta = self.ta = document.id(el);
+            //fireChange = function( event ){ self.fireEvent("change", event); };
 
         self.setOptions(options);
 
@@ -369,9 +369,56 @@ var Textarea = new Class({
         w = el.offsetWidth;
         h = el.offsetHeight;
 
-        console.log(offset, ta.offsetTop, "top: "+t, ta.offsetLeft, "left: "+l, "width: "+w, "height: "+h, "right: "+(l + w), "bottom: "+(t + h) );
+        //console.log(offset, ta.offsetTop, "top: "+t, ta.offsetLeft, "left: "+l, "width: "+w, "height: "+h, "right: "+(l + w), "bottom: "+(t + h) );
         return { top: t, left: l, width: w, height: h, right: l + w, bottom: t + h };
 
+    },
+
+
+    /*
+    Function: onDragAndDrop
+        Add Drag&Drop handlers on the Textarea
+        Inspired by https://github.com/github/paste-markdown
+
+    */
+    onDragAndDrop: function(processData, onSuccess){
+
+        var self = this,
+            ta = this.ta;
+
+        ta.addEventListener('dragover', function(event /*DragEvent*/){
+
+            var dataTransfer = event.dataTransfer;
+            if (dataTransfer){ dataTransfer.dropEffect = 'copy'; }
+        });
+
+        ta.addEventListener('drop', function(event /*DragEvent*/){
+
+            var dataTransfer = event.dataTransfer;
+            if (dataTransfer && (dataTransfer.files.length == 0)){
+                insertData(event, dataTransfer);
+            }
+        });
+
+        ta.addEventListener('paste', function(event /*ClipboardEvent*/){
+
+            insertData(event, event.clipboardData);
+        });
+
+        function insertData(event, dataTransfer){
+
+            var content = processData(dataTransfer);
+
+            if ( content ) {
+
+                event.stopPropagation();
+                event.preventDefault();
+                self.insertAfter(content);
+
+                if( onSuccess ){ onSuccess(); }
+            }
+        }
     }
 
+
 });
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Html2Wiki.js b/jspwiki-war/src/main/scripts/wiki-edit/Html2Wiki.js
new file mode 100644
index 0000000..7afa0d4
--- /dev/null
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Html2Wiki.js
@@ -0,0 +1,227 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    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"); fyou 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.
+*/
+
+/*eslint-env browser*/
+/*global Wiki*/
+
+/*
+Html2Wiki
+    Mini html to wiki markup convertor for JSPWiki.
+    Used by the Wiki.Edit.js to handle html which is input via drap&drop, or copy&paste.
+
+    It uses a brute-force find&replace approach,  rather then a fine-grained walk the dome tree approach.
+    It gets the job done 90% of the time.
+
+*/
+!(function( wiki, document ){
+
+    //convert url to wiki link
+    wiki.url2links = function( links ){
+
+        return links ? links.split("\r\n").map(function(link){
+
+            return "\n[" + link + "]\n";
+
+        }) : links;
+
+    }
+
+    //convert html to wiki-markup
+    wiki.html2wiki = function( html ){
+
+        if( !html ) return;
+
+        //console.log(html);
+
+        //make temporary dom element to convert html to wiki markup
+        var dom = "div".slick({html:html});
+
+        forEachTextNode(dom, /\[/g, "[[");  //url's in text nodes are converted to [link]
+        forEachNode(dom, "style", removeElement);
+
+        //inline elements
+        substituteEachNode(dom, "b,strong", "__{0}__" );
+        substituteEachNode(dom, "i", "''{0}''" );
+        substituteEachNode(dom, "sup", "%%sup {0}/%");
+        substituteEachNode(dom, "sub", "%%sub {0}/%");
+        forEachNode(dom, "a", replaceHtmlA);
+        substituteEachNode(dom, "tt", "{{{0}}}" );
+        substituteEachNode(dom, "pre,code", "\n{{{\n{0}\n}}}\n" );
+
+        //block elements
+        substituteEachNode(dom, "hr", "\n----\n");
+        substituteEachNode(dom, "br", " \\\\ ");
+        substituteEachNode(dom, "h1,h2", "\n!!! {0}\n");
+        substituteEachNode(dom, "h3", "\n!! {0}\n");
+        substituteEachNode(dom, "h4", "\n! {0}\n");
+        substituteEachNode(dom, "dl dt", "\n;{0}:");
+
+        forEachNode(dom, "li", replaceHtmlLI);
+
+        forEachNode(dom, "tr", replaceHtmlTR);
+        substituteEachNode(dom, "p", "\n{0}\n");
+
+        return dom.textContent.replace(/^\s*(.*)\s*$/,"$1")+"\n";
+    }
+
+
+// Helper functions
+/*
+Function: forEachTextNode
+    Iterate over all descendent text nodes and replace their contents.
+
+Example
+    forEachTextNode( document, " ", "&nbsp;" );
+    forEachTextNode( some_node, /\[/g, "[[");
+*/
+function forEachTextNode(node, substrOrHandle, newSubstr){
+
+    var n,
+        isHandle = typeof substrOrHandle === "function",
+        walk = document.createTreeWalker(node, 4 /*NodeFilter.SHOW_TEXT*/, null, false);
+
+    while(( n = walk.nextNode() )){
+        isHandle ? substrOrHandle(n) : replaceTextContent(n, substrOrHandle, newSubstr);
+    }
+    return node;
+}
+
+/*
+Function: forEachNode
+    Loop over each selected node and invoke a function
+
+Example:
+    forEachNode( document, "p p", function(p){ p.className = "nested_par"; });
+*/
+function forEachNode(node, selector, callback){
+
+    ( node.querySelectorAll(selector) || [] ).forEach(callback);
+    return node;
+}
+
+/*
+Function: substituteEachNode
+    Loop over each selected node, and replace it contents.
+    Use paramater "{0}" to refer to the textContent
+
+Example:
+    forEachNode( document, "p", "\n{0}\n");
+*/
+function substituteEachNode(node, selector, pattern){
+
+    return forEachNode(node, selector, function(n){
+        replaceNodeByText(n, pattern.xsubs(n.textContent) );
+    });
+}
+
+/*
+Function: replaceNodeByText
+    Replace a Node by a Text-Node
+*/
+function replaceNodeByText(node, text){
+
+    node.parentNode.replaceChild( document.createTextNode(text), node );
+
+}
+
+/*
+Function: replaceTextContent
+    Replace the content of a node
+
+Example
+    replaceTextContent( some_node, /\[/g, "[[");
+*/
+function replaceTextContent(node, substrOrRegExp, newSubstr){
+
+    node.textContent = node.textContent.replace(substrOrRegExp, newSubstr);
+
+}
+
+/*
+Function: removeElement
+*/
+function removeElement(node){
+
+    node.parentNode.removeChild(node);
+
+}
+
+/*
+Function: getAncestors
+    Return array of all ancestors, matching the selector
+
+Example
+    getAncestors( some_li_element, "ul,ol" );
+*/
+function getAncestors(node, selector){
+
+    var ancestors = [];
+
+    while(( node = node.parentElement )){
+        if( node.matches(selector) ){ ancestors.push(node); }
+    }
+    return ancestors;
+}
+
+
+// Wiki Html-to-Markup helper functions
+
+// convert <a href="...">description</a>  into [description|url]
+function replaceHtmlA( link ){
+
+    var href = link.href,
+        description = link.textContent;
+
+    //escape the [ and ] characters inside the link-description text
+    description = description.replace(/\[\[/g,"&lsqb;").replace(/\]/g,"&rsqb;");
+
+    replaceNodeByText( link, " [" + description + "|" + href + "] ");
+}
+
+// convert <tr>...</tr>  in wiki table rows with a | or || prefix
+function replaceHtmlTR( row ){
+
+    var s = "\n", c, cell;
+
+    for(c=0; (cell = row.cells[c]); c++){
+
+        s += ( cell.tagName.test( /th/i ) ? "||" : "|") +
+             ( cell.textContent.trim() || '&nbsp;');
+//             ( cell.textContent.trim().replace(/\|/g, '~|') || '&nbsp;');
+    }
+    replaceNodeByText(row, s );
+}
+
+// convert <li> in wiki list items with a * or # prefix
+function replaceHtmlLI( li ){
+
+    var listType = li.parentElement.tagName,
+        markup = listType.test(/ul/i) ? "*" : listType.test(/ol/i) ? "#" : "*",
+        depth = getAncestors(li, "ul,ol").length;
+
+    if(( li = li.firstChild )){
+        replaceTextContent(li, /.*/, "\n" + markup.repeat(depth) + " "+ "$&");
+    }
+}
+
+
+})( Wiki, document );
+
diff --git a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js
index 61d27c6..ee4edb1 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Snipe.js
@@ -162,6 +162,15 @@ var Snipe = new Class({
         });
 
 
+        //add drag&drop handler: drag or paste data into the textarea
+        if( options.dragAndDrop ){
+
+            textarea.onDragAndDrop(options.dragAndDrop, function(){
+                self.fireEvent("change")
+            });
+        }
+
+
         self.reset();
 
         element.addEvents({
@@ -708,7 +717,7 @@ var Snipe = new Class({
 
             // 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]*)/ ) )){
             //if( snipXL = snippet.match( /(^|[\S\s]*[^~])\{([^\{\}]+)\}([\S\s]*)/ ) ){
 
                 //console.log("Snipe:action complex snippet 'pfx{selection}sfx' ", pfx, sel, sfx, caret.thin );
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 74a1653..f5a8730 100644
--- a/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Edit.js
+++ b/jspwiki-war/src/main/scripts/wiki-edit/Wiki.Edit.js
@@ -27,7 +27,7 @@ Class: Wiki.Edit
 */
 
 /*eslint-env browser*/
-/*global Wiki, Snipe, Request */
+/*global $, Wiki, Snipe, Request */
 
 !(function( wiki ){
 
@@ -43,7 +43,7 @@ wiki.add("textarea#editorarea", function( main ){
 
     onbeforeunload( window, main );
 
-    if( snipe = getFormElem("textarea.snipeable") ){
+    if(( snipe = getFormElem("textarea.snipeable") )){
 
         snipe = new Snipe( snipe, {
             container: form,
@@ -52,14 +52,15 @@ wiki.add("textarea#editorarea", function( main ){
                 redo: getFormElem("[data-cmd=redo]")
             },
             snippets: wiki.Snips,
-            directsnips: wiki.DirectSnips
+            directsnips: wiki.DirectSnips,
+            dragAndDrop: processDragAndDropData
         });
 
         wiki.configPrefs(form, function(cmd, isChecked){
             snipe.set(cmd, isChecked);
         });
 
-        if( preview = getFormElem(".ajaxpreview") ){
+        if(( preview = getFormElem(".ajaxpreview") )){
 
             var snipeHasChanged = false;
 
@@ -105,7 +106,7 @@ wiki.add("textarea#editorarea", function( main ){
     }
 
 
-}).add("textarea[name=htmlPageText]", function( main){
+}).add("textarea[name=htmlPageText]", function( /*main*/ ){
 
     LocalCache = "wiki" + wiki.PageName;
     if(LocalCache in localStorage){
@@ -114,8 +115,6 @@ wiki.add("textarea#editorarea", function( main ){
 
 })
 
-
-
 /*
 Function: onbeforeunload
     Install an onbeforeunload handler, which is called prior to unloading the page.
@@ -266,7 +265,7 @@ function jspwikiSectionParser( text ){
         title = tt[i + 1].split(/[\r\n]/)[0]
 
             //remove unescaped(~) inline wiki markup __,"",{{,}}, %%(*), /%
-            .replace(/(^|[^~])(__|""|\{\{|\}\}|%%\([^\)]+\)|%%\S+\s|%%\([^\)]+\)|\/%)/g, "$1")
+            .replace(/(^|[^~])(__|""|\{\{|\}\}|%%\([^)]+\)|%%\S+\s|%%\([^)]+\)|\/%)/g, "$1")
 
             //and remove wiki-markup escape chars ~
             .replace(/~([^~])/g, "$1");
@@ -281,6 +280,18 @@ function jspwikiSectionParser( text ){
 
 }
 
+/*
+Function
+    Call back handler, invoked when data is dragged or copied into the editor textarea.
+    Call Html2Wiki.js to process the incoming data & convert to wiki markup
+
+*/
+function processDragAndDropData( dataTransfer ){
+
+    return wiki.url2links( dataTransfer.getData('text/uri-list') )
+        || wiki.html2wiki( dataTransfer.getData('text/html') );
+
+}
 
 
 })( Wiki );
diff --git a/jspwiki-war/src/main/styles/haddock/default/type.less b/jspwiki-war/src/main/styles/haddock/default/type.less
index 55b33d6..0c83ac8 100644
--- a/jspwiki-war/src/main/styles/haddock/default/type.less
+++ b/jspwiki-war/src/main/styles/haddock/default/type.less
@@ -57,11 +57,10 @@ DOM structure:
 .editsection, .hashlink {
 
     .btn; .btn-default; .btn-xs;
-    line-height:1;
     margin-right: .25em;
     .transition(all 1s ease);
     &:hover { .opacity(1); border-color:transparent; }
-
+	user-select:none;
 }
 
 h2,h3,h4 {