3.2.0

Contribution: AW and Draggable DIVs

I mentioned some time ago that I was working on some javascript code as an exercise to allow for draggable and resizable objects that worked with AW.

I've now finished the drag code. Rather than place it here, I've installed it on this page -
http://web.aanet.com.au/devandtest/
which should make it easier to download as well as allowing it to be tested immediately.

For my development, I used FireFox 2, Netscape 7.1 and IE6. I also tested on Netscape 8.2 and Flock 1.1.

I elected to use DIVs but I see no reason why some other suitable objects can't be used. To do so just requires a simple change to the js code where it checks for the tagName.

The example I created used 3 types of positioning with the DIVs - relative (the first 6 and the last one), absolute (the 7th example) and fixed (the 8th example). Statically positioned DIVs turn out not to be draggable. IE 6 doesn't handle fixed positioning and treats it as static.

I support dragging via two mechanisms - either the whole object or via a dragbar. My example includes an AW grid made draggable via either method (DIV 2 and 6). One problem I have with it is that its rather sluggish. I don't know if its due to event issues or whether there's too much redrawing going on when dragging. (Netscape isn't supported by AW and has a problem with a ghost image to the right of the first DIV. This flashes as it gets dragged which is why I suspect rendering is slowing it down.)

As can be seen from the test page above, I tile the first 6 relatively positioned DIVs. IE 6 has a major problem with this. In each case, it made the last DIV in a row lest that 50% of its correct size (irrespective of the displayable width).

While its a bug in IE, I don't expect people would ordinarily do it like this. IE also has a problem with transparent borders. It shows an outline border around the dragbar as a result. The other browsers do it correctly. However, IE's idea about the border being part of the element's size has some merit. It certainly made it easier to get some display issues looking more correct. Compare this to the other browsers where their sizes appear uneven.

One other interesting difference between IE and the others is that IE will only display the page scrollbars if you drag the absolutely positioned DIV down, to the right or diagonally down and right. The others do it for the relatively positioned ones too.

I also set up boundary checking for the left and top. This can be removed by removing the bounds parameter passed to the function as well as the idlist object array and any references to both in the code.

Boundary checking also shows up an interesting bug in the Gecko family of browsers. Dragging any of the relatively positioned DIVs to the left edge and then down until a vertical scrollbar appears causes the DIV to be offset to the left by a few pixels. I wasn't able to fix this.

I haven't tried other AW objects apart from grids but I see no reason why they shouldn't work. If anyone wants to test them and report their findings I would appreciate it.

If anyone tests with other browsers, I would appreciate any reports on problems/fixes etc.

NOTES

Dragbars might be better implemented as an image. At least that would be consistent across browsers. It also means not having to hardcode the border size for the dragbar in the function.

Setting a DIV's position in a CSS declaration means that the position isn't readable the first time by the function. This would cause a DIV to jump on first dragging it to its unpositioned location. This can be solved by setting its position inline. That is -
... style="left:50px;top:50px" ...

or, alternately, setting it via the AW object methods.
Anthony
April 10,
Anthony,

Thank you very much for the excellent example.

One possible improvement - increase z-index after dragging the object so it will stay on top of the others...
Alex (ActiveWidgets)
April 10,
Hi Alex,

I was in two minds about that originally but decided to increase it while dragging so that its on top and then restore it when done. I don't expect people to have many draggable elements visible or to layer them but, if they do, its easy enough to change the code.
Anthony
April 10,
I thought I would would add a tree to one of the DIVs to see how it worked and I've found a slight problem with FireFox.

If you look at the sample page now, the 3rd DIV has a tree with 2 borders around it (one red and the other blue). I did this for illustrative purposes.

The CSS code I used to do this was -
.aw-list-box      {border:5px solid blue}
.aw-ui-list       {width:50%;height:80%;border:5px solid red; background: wheat}

If you click inside the tree area (but not one any of the tree items) to drag the DIV around, a white dotted border appears between the red and blue borders.

I've noticed that FireFox does this with text focus and I'm not sure how to eliminate it.

By the way, what's the right CSS style to use for the tree? Its class is defined as "aw-system-control aw-ui-list aw-list-control aw-flow-vertical aw-text-normal" and .aw-ui-list and .aw-list-control both work.
Anthony
April 11,
Good job Anthony!
Thanks for a complete and clean sample.

I am actually doing grid-dragging with a div placed on top panel (very useful) but using a very large code:

So I tryed your function and added the following code to your example, but couldn't make the container (grid) moving by top-div movement.
Not sure if (for this case ) the drag function need an additional parameter withr the 'id' or object-reference of container to move.

<script> 
var obj = new AW.UI.Grid; 
obj.setId("ten");
obj.setClass("div", "container");
obj.setCellText(function(i, j){return j + "." + i}); 
obj.setHeaderText("header"); 
obj.setColumnCount(10); 
obj.setRowCount(100); 
obj.setCellEditable(true); 
var toolbar = new AW.HTML.DIV; 
toolbar.setId("toolbar"); 
toolbar.setStyle("background", 'blue'); 
toolbar.setStyle("height","23px");
toolbar.setStyle("position", "relative")
toolbar.setClass("div", "dragbar");
toolbar.setStyle("cursor", "move")
toolbar.setEvent("onmousedown", "drag(event, 1)")
toolbar.setContent("input", "10"); 
obj.defineTemplate("topLine", toolbar); 
obj.setLayoutTemplate(new AW.Panels.Horizontal); 
obj.setPanelTemplate(function(i){ 
switch(i){ 
case "center": return this.getScrollTemplate(); 
case "top": return this.getTopLineTemplate(); 
} 
}); 
obj.onPanelWidthChanged = function(width, panel){ 
this.getLayoutTemplate().changePanelWidth(width, panel); 
}; 
obj.onPanelHeightChanged = function(height, panel){ 
this.getLayoutTemplate().changePanelHeight(height, panel); 
}; 
obj.setPanelHeight(23, "top"); //bottom line 
document.write(obj); 
</script>

Thaks again

Carlos
April 11,
Hi Carlos, I had actually looked at using AW panels at one point to do the dragging and resizing before I decided I could make it simpler.

If you look at the drag code, it checks to see if the tagName is DIV and the className matches the pattern drag. It then checks to see if the className is dragbar in order to make the draggable object the parent element.

Your sample meets the criteria of the first part, at least. I'm not sure what AW creates as the parent element. An ordinary grid has a span as the parent. I see no reason why that shouldn't work.

I'll copy your code and investigate if you like. I've gotten very good at using FireBug with FireFox. Expect a reply this weekend sometime (if not sooner).

Anthony
April 11,
Hi again Carlos. As is, the current code will only drag the blue bar around. It matches the first drag criteria but not the second because the class is aw-div-dragbar rather than just dragbar. I can fix that easily with a change to the code to use indexof. Vis -
if (dobj.className.indexOf("dragbar") > -1)

However, the parent element is nested 5 deep. To find the correct parent, you are right, its id will need to be passed.

Note, that you don't need to have this line of code (its not needed) -
obj.setClass("div", "container")

so just delete it.

I changed your code to this -
var obj     = new AW.UI.Grid
    var toolbar = new AW.HTML.DIV
    var myid    = "ten"

    obj.setId(myid)
...
   toolbar.setEvent("onmousedown", "drag(event, 1, myid)")

I had some trouble getting the id set correctly. I'm not sure why but if I used id as the variable name, it get messed up. Calling obj.getId seemed to get the id of the panel template rather than the parent grid id. This might be a bug. Alex?

I then changed the drag code to this -
function        drag(e, bounds, pid)
...
        if (dobj.className.indexOf("dragbar") > -1)
        {
            dragbar = 1
            dobj.style.border = "3px inset gray"
            orgd = dobj
            dobj = AW.ie ? dobj.parentElement : dobj.parentNode
            while (dobj.id != pid)
                dobj = AW.ie ? dobj.parentElement : dobj.parentNode
        }

Where pid is the parent id. Note that this lets it work with your design but its rough. I should test if a parent id is passed and act appropriately.
Anthony
April 11,
Wow !
Many thanks for your help Anthony.

Yes I saw in the past that obj.getId "macro" behaivour when inside quotes.
You can get around it doing string concatenation (strange):
toolbar.setEvent("onmousedown", "drag(event, 1, obj.getId("+")"+")");


I have the feeling that will be back soon to this thread searching (hope contributing also) for more about "dragging AW controls".
Saludos,..
Carlos
April 11,
Hi Carlos, I updated my sample page with the 'fixed' version of the drag script plus a few enhancements (you now can set the bounds value to a negative number to disable boundary checks). I also added extra comments to help people understand it better.

I also replaced the 5th DIV with your code above (I hope you don't mind). So people can now see how that drags around (I also changed the drag code to support any background colour for the drag bar).

One interesting thing to note, if you delete the line -
obj.setStyle("float", "left")

and move the grid scrollbars, they will reset after a drag. This doesn't happen when the float style is set. This issue came up before in a different context. So beware of that.

I also thought that I could get rid of the parent id parameter by attaching the event to the parent element and searching through the child nodes for a draggable object, but I quickly realised that wasn't going to work.

If you try other AW objects and notice problems, just let me know. I'd be happy to look into it.
Anthony
April 12,
Hi Anthony, sure, glad to see it as part of your sample.

Just another curious event, drag and then sort (any column).
Can you corfirm it is moving back to it's original position?
(only IE6 test for now).

Any idea?
Could be a hard task to investigate, but I'll try anyway.
My first tempt to avoid it is place another div around the grid.

I'm sure Alex can easy imagine what's going on in that particular case.


Carlos
April 12,
I made the mistake of downloading and installing IE 7 last night (over 20MB and took forever to install. Makes me wonder why anybody bothers using it). It also overwrote my IE6 version rather than prompting me.

All the bugs I reported above apart from the transparency issue are still there in IE7!

Anyway, your drag/sort problem doesn't happen in IE7. So the grid isn't losing focus. I gather you mean it returns to the starting scroll position.

Oddly enough, the DIV 2 example does lose focus in FF (but not in Netscape). Just scroll it and then drag. DIV 5 (your example) doesn't. I noted yesterday that it does happen if I remove the float style.

Check this thread -
http://www.activewidgets.com/javascript.forum.22124.8/grid-losing-focus-in-firefox.html
for a similar FF grid focus issue. I haven't found a report for IE though.
Anthony
April 13,

This topic is archived.

See also:


Back to support forum