Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery UI dropzone wrong offset inside scrolled iframe

I'm having an issue with jQuery-UI draggables and droppables. I need to drag an draggable inside an droppable which is placed inside an iframe. This works ok until I scroll the iframe. The droppable coordinates are not updated.

The issue is demonstrated in this fiddle

I'm using the workaround below to make drag and dropping to iframes possible in the first place. It calculates the right offsets but does not use the iframe's scroll offsets. I tried but couldn't get it tweaked so it would take scroll offsets into account.

// Create new object to cache iframe offsets
$.ui.ddmanager.frameOffsets = {};

// Override the native `prepareOffsets` method. This is almost
// identical to the un-edited method, except for the last part!
$.ui.ddmanager.prepareOffsets = function (t, event) {
    var i, j,
        m = $.ui.ddmanager.droppables[t.options.scope] || [],
        type = event ? event.type : null, // workaround for #2317
        list = (t.currentItem || t.element).find(":data(ui-droppable)").addBack(),
        doc, frameOffset;

    droppablesLoop: for (i = 0; i < m.length; i++) {

        //No disabled and non-accepted
        if (m[i].options.disabled || (t && !m[i].accept.call(m[i].element[0], (t.currentItem || t.element)))) {
            continue;
        }

        // Filter out elements in the current dragoged item
        for (j = 0; j < list.length; j++) {
            if (list[j] === m[i].element[0]) {
                m[i].proportions().height = 0;
                continue droppablesLoop;
            }
        }

        m[i].visible = m[i].element.css("display") !== "none";
        if (!m[i].visible) {
            continue;
        }

        //Activate the droppable if used directly from draggables
        if (type === "mousedown") {
            m[i]._activate.call(m[i], event);
        }

        // Re-calculate offset
        m[i].offset = m[i].element.offset();

        // Re-calculate proportions (jQuery UI ~1.10 introduced a `proportions` cache method, so support both here!)
        proportions = { width: m[i].element[0].offsetWidth, height: m[i].element[0].offsetHeight };
        typeof m[i].proportions === 'function' ? m[i].proportions(proportions) : (m[i].proportions = proportions);

        /* ============ Here comes the fun bit! =============== */

        // If the element is within an another document...
        if ((doc = m[i].document[0]) !== document) {
            // Determine in the frame offset using cached offset (if already calculated)
            frameOffset = $.ui.ddmanager.frameOffsets[doc];
            if (!frameOffset) {
                // Calculate and cache the offset in our new `$.ui.ddmanager.frameOffsets` object
                frameOffset = $.ui.ddmanager.frameOffsets[doc] = $(
                    // Different browsers store it on different properties (IE...)
                    (doc.defaultView || doc.parentWindow).frameElement
                ).offset();
            }

            // Add the frame offset to the calculated offset
            m[i].offset.left += frameOffset.left;
            m[i].offset.top += frameOffset.top;
        }
    }
}

Does anyone have an suggestion to fix the issue. Recommendations to achieve the same thing another way are also more than welcome.

like image 726
Boyd Avatar asked Apr 22 '15 21:04

Boyd


1 Answers

You can change the proportions's height depending on the scroll amount in the iframe. The amount can be achieved using $("iframe").contents().scrollTop() as you have used it to change the scroll amount:

proportions = {
      width: m[i].element[0].offsetWidth,
      height: m[i].element[0].offsetHeight - $("iframe").contents().scrollTop()
};

Here's the DEMO.

like image 173
Raein Hashemi Avatar answered Oct 20 '22 11:10

Raein Hashemi