You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@whimsical.apache.org by Sam Ruby <ru...@apache.org> on 2015/12/14 23:41:19 UTC

[whimsy.git] [1/1] Commit db1f067: rough in UI for drag/drop

Commit db1f067edc85ab91fd37f34aa011f6326b1c4fe0:
    rough in UI for drag/drop


Branch: refs/heads/secmail
Author: Sam Ruby <ru...@intertwingly.net>
Committer: Sam Ruby <ru...@intertwingly.net>
Pusher: rubys <ru...@apache.org>

------------------------------------------------------------
www/secmail/Gemfile                                          | + -
www/secmail/public/secmail.css                               | ++++++ 
www/secmail/views/parts.js.rb                                | +++++++++ -
------------------------------------------------------------
78 changes: 74 additions, 4 deletions.
------------------------------------------------------------


diff --git a/www/secmail/Gemfile b/www/secmail/Gemfile
index 5bd4995..7acaa05 100644
--- a/www/secmail/Gemfile
+++ b/www/secmail/Gemfile
@@ -7,7 +7,7 @@ gem 'whimsy-asf'
 gem 'sinatra'
 gem 'sanitize'
 gem 'wunderbar', '~> 1.0.10'
-gem 'ruby2js', '~> 2.0.10'
+gem 'ruby2js', '~> 2.0.11'
 gem 'execjs'
 
 group :demo do
diff --git a/www/secmail/public/secmail.css b/www/secmail/public/secmail.css
index c904fe5..b39134c 100644
--- a/www/secmail/public/secmail.css
+++ b/www/secmail/public/secmail.css
@@ -7,6 +7,12 @@
   background-color: yellow;
 }
 
+.drop-target {
+  border: 2px solid green;
+  border-radius: 1em;
+  padding: 0.5em;
+}
+
 .deleted {
   opacity: 0.5;
 }
diff --git a/www/secmail/views/parts.js.rb b/www/secmail/views/parts.js.rb
index 5851fa8..aff1b4b 100644
--- a/www/secmail/views/parts.js.rb
+++ b/www/secmail/views/parts.js.rb
@@ -4,9 +4,22 @@ def initialize
   end
 
   def render
+    # common options for all list items
+    options = {
+      draggable: 'true',
+      onDragStart: self.dragStart,
+      onDragEnter: self.dragEnter,
+      onDragOver: self.dragOver,
+      onDragLeave: self.dragLeave,
+      onDragEnd: self.dragEnd,
+      onDrop: self.drop,
+      onContextMenu: self.menu,
+    }
+
     _ul @@attachments do |attachment|
-      _li onContextMenu: self.menu do
-        _a attachment.name, href: attachment.name, target: 'content'
+      _li options do
+        _a attachment.name, href: attachment.name, target: 'content',
+          draggable: 'false'
       end
     end
 
@@ -31,7 +44,6 @@ def menu(event)
     $menu.style.display = :block
     event.preventDefault()
   end
-
   # hide context menu whenever a click is received outside the menu
   def click(event)
     target = event.target
@@ -41,4 +53,56 @@ def click(event)
     end
     $menu.style.display = :none
   end
+
+  #
+  # drag/drop support.  Note: support varies by browser (in particular,
+  # when events are called and whether or not a particular event has
+  # access to dataTransfer data.)  Accordingly, the below is coded in
+  # a way that is mildly redundant and uses React.js state data in lieu of
+  # dataTransfer.  Oddly, with some browsers, drag and drop isn't possible
+  # without setting something in dataTransfer, so that data is set too, even
+  # though it is not used.
+  #
+
+  # start by capturing the 'href' attribute
+  def dragStart(event)
+    @drag = event.currentTarget.querySelector('a').getAttribute('href')
+    event.dataTransfer.setData('text', @drag)
+  end
+
+  # show item as valid drop target when a dragged element is over it
+  def dragEnter(event)
+    href = event.currentTarget.querySelector('a').getAttribute('href')
+    if @drag and @drag != href
+      event.currentTarget.classList.add 'drop-target'
+    end
+  end
+
+  # check for valid drag/drop operations (different href)
+  def dragOver(event)
+    href = event.currentTarget.querySelector('a').getAttribute('href')
+    if @drag and @drag != href
+      event.currentTarget.classList.add 'drop-target'
+      event.preventDefault()
+    end
+  end
+
+  # unmark item as selected when a dragged element is no longer over it
+  def dragLeave(event)
+    event.currentTarget.classList.remove 'drop-target'
+  end
+
+  # complete drop operation
+  def drop(event)
+    href = event.currentTarget.querySelector('a').getAttribute('href')
+    alert("drop #{@drag} onto #{href}")
+    @drag = nil
+    event.currentTarget.classList.remove 'drop-target'
+    event.preventDefault()
+  end
+
+  # cancel drag operation
+  def dragEnd(event)
+    @drag = nil
+  end
 end