Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jquery droppable iframe offset

I am trying to use knockout to bind html to an iframe.

The main page contains a draggable and the iframe contains a droppable. The problem I am having is that the item is dropping in the wrong place, e.g.:

The green is where I would like the drop to occur however the red is where the drop actually occurs - it seems to be at the right coordinates but not taking into account the iframes position on the main page. green - where I would like to drop, red - actual drop

I have tried applying the iframefix to both the draggable and droppable however it doesn't help :

iframe.find('.sim-row').droppable({
      iframeFix: true,
      drop: function (event, ui) {
           console.log("dropped");
      }
});

$('#drag').draggable({
     iframeFix: true,
     helper: "clone"
});

It was wondering if there was someway of creating an 'offset' based on the iframes position and pass that through to the draggable so it can calculate its position?

Some fiddles : Main Page - http://jsfiddle.net/D26CQ/1/

iFrame - http://jsfiddle.net/cMfMq/

like image 611
kiwijus Avatar asked Dec 08 '13 10:12

kiwijus


3 Answers

The simplest solution I could find was to modify the jqueryUI draggable function to take into account the offset:

in the $.ui.ddmanager function add the following lines:

        m[i].offset.top -= m[i].element.parents().find("html,body").scrollTop();
        m[i].offset.left -= m[i].element.parents().find("html,body").scrollLeft();

        // iframe positioning 
        if (this.current.options.iframeOffset) {
            m[i].offset.top += this.current.options.iframeOffset.top;
            m[i].offset.left += this.current.options.iframeOffset.left;
        }

just before:

        m[i].proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
like image 185
kiwijus Avatar answered Oct 24 '22 05:10

kiwijus


I can't comment, but....@kiwijus's answer worked perfect for us. One piece of documentation missing is that you have to specify the iframeOffset when calling draggable.

$('.your-draggable-content').draggable({
        helper: "clone",
        iframeFix: true,
        iframeOffset: $('#your-iframe').offset()
 });
like image 26
dtmnash Avatar answered Oct 24 '22 04:10

dtmnash


I had a similar issue when using a iframe in bootstrap, i fixed it by modifying the droppable class to pickup the iframe and store a reference to it and updated the intersect function to detect when the draggable is over the iframe and will adjust the intersect to match the scroll and offset of the iframe.

Demo here : https://dl.dropboxusercontent.com/u/10953135/droppable/index.html

Tested on: Chrome, Firefox and IE10

Please see the following for my changes.

Commit

https://github.com/Azerothian/jquery-ui/commit/57456ff345fbd119b63524df2e2ede72502dcf9a

Diff

@@ -53,7 +53,20 @@ $.widget( "ui.droppable", {

        this.isover = false;
        this.isout = true;
 -
 +      if(o.iframeFix)
 +      {
 +          windowTest = this.window.length && this.window.length > 0 ? this.window[0] : this.window;
 +          if(windowTest !== undefined && windowTest !== null)
 +          {
 +              this.iframe = windowTest.frameElement
 +              if(this.iframe === undefined || this.iframe === null)
 +              {
 +                  throw "[Droppable] You are specifing iframe fix for a object that does not exist inside a iframe";
 +              }
 +          } else {
 +              throw "[IframeFix] Window is not defined.. lets blow up because we are unable to find the iframe.";
 +          }
 +      }
        this.accept = $.isFunction( accept ) ? accept : function( d ) {
            return d.is( accept );
        };
 @@ -244,6 +257,25 @@ $.ui.intersect = (function() {
            t = droppable.offset.top,
            r = l + droppable.proportions().width,
            b = t + droppable.proportions().height;
 +   
 +      if (droppable.options.iframeFix)
 +      {
 +        var iframeOffset = $(droppable.iframe).offset(),
 +              iframeWidth = $(droppable.iframe).width(),
 +              iframeHeight = $(droppable.iframe).height(),
 +              iframeScrollTop = $(droppable.iframe).contents().scrollTop(),
 +              iframeScrollLeft = $(droppable.iframe).contents().scrollLeft();
 +        
 +          if (y1 < iframeOffset.top || x1 < iframeOffset.left || x1 + draggable.helperProportions.width > iframeOffset.left + iframeWidth || y1 + draggable.helperProportions.height > iframeOffset.top + iframeHeight) // outside iframe;
 +          {
 +          return false;
 +          }
 +          l = (iframeOffset.left + droppable.offset.left) - iframeScrollLeft;
 +          r = l + droppable.proportions().width;
 +          t = (iframeOffset.top + droppable.offset.top) - iframeScrollTop;
 +          b = t + droppable.proportions().height;
 +      }
 +

        switch ( toleranceMode ) {
        case "fit":
like image 33
Azerothian Avatar answered Oct 24 '22 05:10

Azerothian