Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #5771 (reopened enhancement)

Opened 3 years ago

Last modified 2 years ago

[PATCH] Drag draggables outside an overflow:auto div to an external droppable container

Reported by: woranl@gmail.com Assigned to: Rails
Priority: normal Milestone: 1.2.7
Component: script.aculo.us Version:
Severity: normal Keywords: overflow, draggable, droppable
Cc:

Description

I am using the patch/extension post by Sergey Kojin in the Effect Treasure Chest under the title "overflow: scroll hack and draggable element substitution" http://wiki.script.aculo.us/scriptaculous/show/EffectsTreasureChest

What I am able to do: I've a div set to overflow:auto. Inside it, there are many draggables. Using the extension below, I'm able to drag my draggables outside the overflow:auto div to an external droppable container.

Each of my draggable is set as follow:

<script type=\"text/javascript\">new SubsDraggable('MyDraggable1', {dragelement:getDragElement})</script>
<script type=\"text/javascript\">new SubsDraggable('MyDraggable2', {dragelement:getDragElement})</script>

The extentions post by Sergey Kojin is as follow, just copy this to the end of dragdrop.js:

// extentions for scriptaculous dragdrop.js
Object.extend(Class, {
    superrise: function(obj, names){
        names.each( function(n){ obj['super_' + n] = obj[n] } )
        return obj;
    }
})

// Draggable that allows substitution of draggable element
var SubsDraggable = Class.create();
SubsDraggable.prototype = Object.extend({}, Draggable.prototype);
Class.superrise(SubsDraggable.prototype, ['initialize', 'initDrag', 'finishDrag'])
Object.extend( SubsDraggable.prototype , {
    initialize: function(event) {
		this.super_initialize.apply(this, arguments);
        if( typeof(this.options.dragelement) == 'undefined' ) this.options.dragelement = false;
    },
    initDrag: function(event) {
		if( this.options.dragelement ){
            this._originalElement = this.element;
            this.element = this.options.dragelement(this.element);
            Position.absolutize(this.element);
            Position.clone(this._originalElement, this.element);
        }
		this.super_initDrag(event);
    },
	
    finishDrag: function(event, success) {
		this.super_finishDrag(event, success);
        if( this.options.dragelement ){
            Element.remove(this.element);
            this.element = this._originalElement;
            this._originalElement = null;
        }
    }
})

Problem 1: Under Firefox, when I drag the draggable, but not placing it to an outside droppable; the clone will disappear. This behaviour is what I wanted. However, here is the problem, when I click on the draggable and not dragging it (just click it); the clone will not disappear. In fact the clone will remain in the browser, and I've to refresh the browser in order to remove it.

Problem 2: Under IE, problem 1 occur exactly the same. In addition, when I drag the draggable, stop dragging for a while, and then I start to drag again; the mouse cursor indicates that the draggable can no longer be dragged.

I think this is a very good extention. Unfortunately, I don't know javascript well enough to fix the two problems stated above. Hopefully someone will know a solution to this.

Change History

08/09/06 08:04:55 changed by woranl@gmail.com

I forgot the post the getDragElement function. Here it is:

<script type=\"text/javascript\">
function getDragElement(element)
{var el = element.cloneNode(true);
 el.id = 'sub'+element.id;
 el.style.position = 'relative';
 $('fakeiFrame').appendChild(el);
 return el;
}
</script>

08/09/06 08:10:27 changed by anonymous

  • owner changed from David to Rails.
  • priority changed from high to normal.
  • component changed from ActiveRecord to script.aculo.us.

09/04/06 21:42:49 changed by madrobby

  • status changed from new to closed.
  • resolution set to untested.

Anyone: Please feel free to solve the problems and add proper tests (probably only functional tests, wish DOM events could be easily simulated cross-browser).

03/12/07 12:15:03 changed by ssinghi

  • status changed from closed to reopened.
  • resolution deleted.
  • milestone set to 1.2.3.

The modified code below fixes this problem. There are no tests at this point, but hopefully it is a step towards the solution.

// extentions for scriptaculous dragdrop.js
Object.extend(Class, {
    superrise: function(obj, names){
        names.each( function(n){ obj['super_' + n] = obj[n] } )
        return obj;
    }
})

// Draggable that allows substitution of draggable element
var SubsDraggable = Class.create();
SubsDraggable.prototype = Object.extend({}, Draggable.prototype);
Class.superrise(SubsDraggable.prototype, ['initialize', 'startDrag', 'finishDrag'])
Object.extend( SubsDraggable.prototype , {
    initialize: function(event) {
        this.super_initialize.apply(this, arguments);
        if( typeof(this.options.dragelement) == 'undefined' ) this.options.dragelement = false;
    },
    startDrag: function(event) {
      if( this.options.dragelement ){
            this._originalElement = this.element;
            this.element = this.options.dragelement(this.element);
            Position.absolutize(this.element);
            Position.clone(this._originalElement, this.element);
      }
      console.debug('here');
      this.super_startDrag(event);
    },
    finishDrag: function(event, success) {
        this.super_finishDrag(event, success);

        if(this.options.dragelement){
            Element.remove(this.element);
            this.element = this._originalElement;
            this._originalElement = null;
        }
    }
})

03/12/07 12:31:43 changed by ssinghi

This patch below when applied fixes this ticket. But unfortunately still no tests.

Index: public/javascripts/dragdrop.js
===================================================================
--- public/javascripts/dragdrop.js	(revision 253)
+++ public/javascripts/dragdrop.js	(working copy)
@@ -309,30 +310,37 @@
         src.tagName=='OPTION' ||
         src.tagName=='BUTTON' ||
         src.tagName=='TEXTAREA')) return;
-        
+
       var pointer = [Event.pointerX(event), Event.pointerY(event)];
       var pos     = Position.cumulativeOffset(this.element);
       this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) });
-      
       Draggables.activate(this);
       Event.stop(event);
     }
   },
-  
+
   startDrag: function(event) {
     this.dragging = true;
-    
+
     if(this.options.zindex) {
       this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0);
       this.element.style.zIndex = this.options.zindex;
     }
-    
+
     if(this.options.ghosting) {
-      this._clone = this.element.cloneNode(true);
-      Position.absolutize(this.element);
-      this.element.parentNode.insertBefore(this._clone, this.element);
+      if(this.options.dragelement){
+        this._originalElement = this.element;
+        this.element = this.options.dragelement(this.element);
+        Position.absolutize(this.element);
+        Position.clone(this._originalElement, this.element);
+      }
+      else {
+        this._clone = this.element.cloneNode(true);
+        Position.absolutize(this.element);
+        this.element.parentNode.insertBefore(this._clone, this.element);
+      }
     }
-    
+
     if(this.options.scroll) {
       if (this.options.scroll == window) {
         var where = this._getWindowScroll(this.options.scroll);
@@ -378,20 +386,27 @@
       if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity);
       this.startScrolling(speed);
     }
-    
+
     // fix AppleWebKit rendering
     if(navigator.appVersion.indexOf('AppleWebKit')>0) window.scrollBy(0,0);
-    
+
     Event.stop(event);
   },
-  
+
   finishDrag: function(event, success) {
     this.dragging = false;
 
     if(this.options.ghosting) {
-      Position.relativize(this.element);
-      Element.remove(this._clone);
-      this._clone = null;
+      if(this.options.dragelement){
+        Element.remove(this.element);
+        this.element = this._originalElement;
+        this._originalElement = null;
+      }
+      else {
+        Position.relativize(this.element);
+        Element.remove(this._clone);
+        this._clone = null;
+      }
     }
 
     if(success) Droppables.fire(event, this.element);

03/12/07 12:33:12 changed by ssinghi

See ticket 5423 for some previous discussion. http://dev.rubyonrails.org/ticket/5423

04/19/07 15:45:05 changed by camwest

this isn't working at all in safari. has a number of visual glitches