SitePoint Sponsor

User Tag List

Results 1 to 6 of 6
  1. #1
    SitePoint Enthusiast
    Join Date
    Oct 2006
    Posts
    33
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Draggable Windows w/IFrames

    Hello all,

    I've been adapting the drag-n-drop code in The JavaScript Anthology to do an R-and-D project for an intranet application that involves draggable and resizable divs with iframes inside each one. I've gotten it so that it works pretty well, but three small problems remain, particularly in IE7:

    The two experimental divs with iframes often "stutter" so that the mouse goes off the div border, but the event handler stays attached so that when you move the mouse back over the div, it starts moving again, even though you're not dragging anymore. I tried attaching code to the target div's mouseout event that would unhook the move/resize event handlers, but to no avail.

    It seems more difficult to grab the west and east borders than it does to grab the corners to resize. The same border and thresholds apply, so it's a mystery to me. I don't want to enlarge the div margins too much, but if that's what I need to do, please advise.

    When the mouse fails to grab the border (as above), often the text in the iframe or div is selected. Any way to stop this behavior?

    I've taken the standard functions from the anthology (attach and detach listeners, addLoadListener, stopEvent, getEventTarget, stopDefaultAction, and getScrollingPosition) and put them into a separate w3c_events.js file to shorten the attached code. The Frame1 and Frame3 html files can be blank, so I won't attach them either to save space.

    Now, I did just find the x examples at cross-browser.com. If the general consensus is "just use those", I'd be happy to. It's just that if I've gone this far down the road, it'd be nice to not have to rip everything out.

    Thanks in advance,

    Jim Stanley
    NTI Group
    ==============
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

    <HTML>
    <HEAD>
    <TITLE>Untitled</TITLE>
    <script type="text/javascript" src="w3c_events.js"></script>
    <STYLE TYPE="text/css">

    body {
    text-align: center;
    }
    #frame1 {
    display: block;
    margin: 10 auto;
    }

    #frame2 {
    display: block;
    margin: 10 auto;
    }

    #frame3 {
    display: block;
    margin: 10 auto;
    }

    #frame4 {
    display: block;
    margin: 10 auto;
    }

    </STYLE>
    <SCRIPT LANGUAGE="JavaScript">

    function divDefaultMouseMove(event) {
    if (typeof event == "undefined") {
    event = window.event;
    }

    var target = getEventTarget(event);
    while (target.nodeName.toLowerCase() != "div")
    target = target.parentNode;

    if (typeof event.pageX == "undefined") {
    event.pageX = event.clientX + getScrollingPosition()[0];
    event.pageY = event.clientY + getScrollingPosition()[1];
    }

    var relativeX = event.clientX - target.offsetLeft;
    var relativeY = event.clientY - target.offsetTop;

    // check for mouse position for cursor type
    if ((Math.abs((target.offsetWidth / 2) - relativeX ) < 20) && (relativeY < 15))
    target.style.cursor = "move";
    else if ((relativeX > target.offsetWidth - 15) && (relativeY > target.offsetHeight - 15))
    target.style.cursor = "se-resize";
    else if ((relativeX > target.offsetWidth - 15) && (relativeY < 15))
    target.style.cursor = "ne-resize";
    else if ((relativeX < 15) && (relativeY < 15))
    target.style.cursor = "nw-resize";
    else if ((relativeX < 15) && (relativeY > target.offsetHeight - 15))
    target.style.cursor = "sw-resize";
    else if (relativeX < 15)
    target.style.cursor = "w-resize";
    else if (relativeX > target.offsetWidth - 15)
    target.style.cursor = "e-resize";
    else if (relativeY < 15)
    target.style.cursor = "n-resize";
    else if (relativeY > target.offsetHeight - 15)
    target.style.cursor = "s-resize";
    else
    target.style.cursor = "default";
    }

    function divOnMouseDown(event) {

    if (typeof event == "undefined") {
    event = window.event;
    }

    var target = getEventTarget(event);
    while (target.nodeName.toLowerCase() != "div")
    target = target.parentNode;

    document.currentTarget = target;

    if (typeof event.pageX == "undefined") {
    event.pageX = event.clientX + getScrollingPosition()[0];
    event.pageY = event.clientY + getScrollingPosition()[1];
    }

    var currentLeft = parseInt(target.style.left);
    var currentTop = parseInt(target.style.top);

    if (isNaN(currentLeft)) currentLeft = "0";
    if (isNaN(currentTop)) currentTop = "0";


    if (typeof target.originLeft == "undefined") {
    target.originLeft = currentLeft;
    target.originTop = currentTop;
    }

    target.clickOriginX = event.pageX;
    target.clickOriginY = event.pageY;
    target.differenceX = currentLeft - event.pageX;
    target.differenceY = currentTop - event.pageY;
    target.clickOriginWidth = parseInt(target.style.width);
    target.clickOriginHeight = parseInt(target.style.height);

    switch(target.style.cursor) {
    case "move":
    case "e-resize":
    case "w-resize":
    case "se-resize":
    case "ne-resize":
    case "sw-resize":
    case "nw-resize":
    case "n-resize":
    case "s-resize":
    attachEventListener(document, "mousemove", mousemoveCheckThreshold, false);
    attachEventListener(document, "mouseup", mouseupCancelThreshold, false);
    break;
    default:
    // alert(target.style.cursor);
    break;
    }

    // make sure the div is on top
    var arrDivs = document.getElementsByTagName("div");
    for (var i = 0; i < arrDivs.length; i++) {
    arrDivs[i].style.zIndex = "0";
    // alert(arrDivs[obj].name);
    }
    target.style.zIndex = "1";
    stopDefaultAction(event);
    }

    function mousemoveCheckThreshold(event) {
    if (typeof event == "undefined")
    event = window.event;
    if (typeof event.pageX == "undefined") {
    event.pageX = event.clientX + getScrollingPosition()[0];
    event.pageY = event.clientY + getScrollingPosition()[1];
    }

    var target = document.currentTarget;
    if (Math.abs(target.clickOriginX - event.PageX) > 2 ||
    Math.abs(target.clickOriginY - event.pageY) > 2) {
    detachEventListener(document, "mousemove", mousemoveCheckThreshold, false);
    detachEventListener(document, "mouseup", mouseupCancelThreshold, false);

    switch(target.style.cursor) {
    case "move":
    attachEventListener(document, "mousemove", mousemoveDrag, false);
    attachEventListener(document, "mouseup", mouseupEndDrag, false);
    attachEventListener(target, "mouseout", mouseupCancelThreshold, false);
    break;
    case "se-resize":
    case "e-resize":
    case "w-resize":
    case "se-resize":
    case "ne-resize":
    case "sw-resize":
    case "nw-resize":
    case "n-resize":
    case "s-resize":
    attachEventListener(document, "mousemove", mousemoveResize, false);
    attachEventListener(document, "mouseup", mouseupEndResize, false);
    attachEventListener(target, "mouseout", mouseupCancelThreshold, false);
    break;
    }
    }
    stopDefaultAction(event);
    }

    function mouseupCancelThreshold(event) {
    detachEventListener(document, "mousemove", mousemoveCheckThreshold, false);
    detachEventListener(document, "mouseup", mouseupCancelThreshold, false);
    return false;
    }

    function mousemoveDrag(event) {
    if (typeof event == "undefined")
    event = window.event;
    if (typeof event.pageX == "undefined") {
    event.pageX = event.clientX + getScrollingPosition()[0];
    event.pageY = event.clientY + getScrollingPosition()[1];
    }

    var target = document.currentTarget;
    target.style.left = event.pageX + target.differenceX + "px";
    target.style.top = event.pageY + target.differenceY + "px";
    stopDefaultAction(event);
    return true;
    }

    function mouseupEndDrag(event) {
    detachEventListener(document, "mousemove", mousemoveDrag, false);
    detachEventListener(document, "mouseup", mouseupEndDrag, false);
    }

    function mousemoveResize(event) {
    if (typeof event == "undefined")
    event = window.event;
    if (typeof event.pageX == "undefined") {
    event.pageX = event.clientX + getScrollingPosition()[0];
    event.pageY = event.clientY + getScrollingPosition()[1];
    }

    var target = document.currentTarget;

    if (target == null) return false;

    document.getElementById("Position").innerHTML = "width: " + (target.clickOriginWidth
    - (event.pageX - target.clickOriginX))
    + "px";
    switch (target.style.cursor) {
    case "e-resize":
    case "se-resize":
    case "ne-resize":
    target.style.width = event.clientX - target.offsetLeft + "px";
    break;
    case "sw-resize":
    case "nw-resize":
    case "w-resize":
    target.style.left = event.pageX + target.differenceX + "px";
    target.style.width = (target.clickOriginWidth - (event.pageX - target.clickOriginX)) + "px";
    break;

    }

    switch(target.style.cursor) {
    case "se-resize":
    case "sw-resize":
    case "s-resize":
    target.style.height = event.clientY - target.offsetTop + "px";
    break;
    case "ne-resize":
    case "nw-resize":
    case "n-resize":
    target.style.top = event.pageY + target.differenceY + "px";
    target.style.height = (target.clickOriginHeight - (event.pageY - target.clickOriginY)) + "px";
    break;
    }

    // resize the inner IFRAME if there is one
    if (target.firstChild.id != null) {
    document.getElementById("theAnswer").innerHTML = target.firstChild.id.toString();
    target.firstChild.style.width = (parseInt(target.style.width) - 20) + "px";
    target.firstChild.style.height = (parseInt(target.style.height) - 20) + "px";
    }

    stopDefaultAction(event);
    }

    function mouseupEndResize(event) {
    detachEventListener(document, "mousemove", mousemoveResize, false);
    detachEventListener(document, "mouseup", mouseupEndResize, false);
    }

    function initEvents() {
    var arrDivs = document.getElementsByTagName("div");
    for (obj in arrDivs) {
    attachEventListener(arrDivs[obj], "mousemove", divDefaultMouseMove, false);
    attachEventListener(arrDivs[obj], "mousedown", divOnMouseDown, false);
    }
    }

    addLoadListener(initEvents);

    </SCRIPT>
    </HEAD>
    <BODY>
    <DIV ID="Div1" STYLE="position:absolute; left:10; top:10; width:400; height:610; background-color:#FF8888;"><IFRAME SRC="Frame1.html" ID="Frame1" NAME="Frame1" ID="Frame1" SCROLLING="No" ALIGN="middle" WIDTH="380" HEIGHT="590" FRAMEBORDER="no" ></IFRAME>
    </DIV>
    <DIV ID="Div2" STYLE="position:absolute; left:420; top:10; width:620; height:300; background-color:#88FF88;">Div 2<BR><SPAN ID="Position"></SPAN><BR><BR><BR><SPAN ID="theAnswer" NAME="theAnswer">Results:</SPAN>
    </DIV>
    <DIV ID="Div3" STYLE="position:absolute; left:420; top:320; width:300; height:300; background-color:#8888FF;"><IFRAME SRC="Frame3.html" ID="Frame3" NAME="Frame3" ID="Frame3" SCROLLING="no" ALIGN="center" WIDTH="280" HEIGHT="280" FRAMEBORDER="no"></IFRAME>
    </DIV>
    <DIV ID="Div4" STYLE="position:absolute; left:730; top:320; width:310; height:300; background-color:#F888FF;">Div 4
    </DIV>
    </BODY>
    </HTML>

  2. #2
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    You've applied top and bottom margin to the iframe, but no left and right margin. The mousedown event can only occur on the very edge of the element.

    You should note that this script makes all DIVs on the page draggable.

    Dragging has its problems. Dragging a div with an iframe adds more problems. As the mouse moves over the iframe, mouse events are no longer sent to the iframe container - they are sent to the document in the iframe. One idea is to cover the iframe with a div ('grey out' the iframe) during the drag.

  3. #3
    SitePoint Enthusiast
    Join Date
    Oct 2006
    Posts
    33
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mike,

    Thanks much for the reply. You're right that all the divs are draggable at this point. I think I'll set a custom attribute for the divs containing a frame so the code can apply to just those divs for further work.

    I twiddled with the margin settings and still wasn't able to get the sides going, even though I did see where the code was firing. I tried commenting out the threshold check before setting the event handlers and voila! I can't see any unwelcome side effects of not doing the threshold check, so if you know of any, please let me know.

    Covering up the iframes makes perfect sense now that you mention it (another reason to specify which frames are draggable!). I suspect that *all* the iframes need to be covered up whenever one is dragged as I note the resizing stops if I resize too fast over another iframe.

    Would you suggest creating the divs up front and positioning them when needed, or dynamic creation and removal?

    Thanks again for pointing me in the right direction.

    Jim Stanley
    NTI Group

  4. #4
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Hi Jim, you are very welcome

    I can't say that I completely get everything in that code. But the threshold seems to be hard-coded at 2... ?

    I would probably create the divs up front - but as you note there are several other ways of doing it.

  5. #5
    SitePoint Enthusiast
    Join Date
    Oct 2006
    Posts
    33
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Mike, thanks again! I jiggered the code to create two transparent divs when dragging: one atop the iframe, and the other beneath the other divs. It's nearly perfect (the mouse can switch how it resizes in mid-drag but that's not really a problem) and the (internal) clients I've shown it to are quite impressed.

    Jim Stanley
    NTI Group

  6. #6
    I'll take mine raw silver trophy MikeFoster's Avatar
    Join Date
    Dec 2002
    Location
    Alabama, USA
    Posts
    2,560
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Great! Good work, Jim


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •