... drag an embedded window the dragging window image jumps so that it is positioned where the mouse position is at top left. ... Can I override this default drag shape behaviour?
Yes we can, we can override it by override the ghost function and getDrop function in Class zk.DnD, described as follows:
zk.afterLoad("zk", function () {
// store the old ghost and getDrop function
var oldGhost = zk.DnD.ghost;
var oldGetDrop = zk.DnD.getDrop;
zk.DnD.ghost = function (drag, ofs, msg) {
if (jq(drag.node).hasClass('z-window-embedded')) {
// the dgelm is the drag node follows the mouse cursor,
var dgelm = document.createElement("div");
dgelm.id = "zk_ddghost";
zk.copy(dgelm.style, {
position: "absolute", left: ofs[0] + "px",
top: ofs[1] + "px"
});
dgelm.appendChild(getVisualGhost (drag, ofs));
jq(dgelm).addClass("z-drag-ghost");
document.body.appendChild(dgelm);
return dgelm;
} else // call old ghost if not embedded window
return oldGhost.apply(this, arguments);
};
// called while end drag
zk.DnD.getDrop = function (drag, pt, evt) {
if (jq(drag.node).hasClass('z-window-embedded')) {
restoreWindow(drag, pt);
} else // call old getDrop if not embedded window
return oldGetDrop.apply(this, arguments);
};
});
The fragment above denotes 'do the special for embedded window, do original otherwise'.
The ghost function is called when drag start, it will return a HTML Dom node and make it follow the mouse cursor, our goal is create a dom node, let the cloned window follow that node with calculated offset and hide the original window.
The getDrop function is called when drag finish (release the mouse button), it get the target that the mouse cursor on it, our goal is display the original window with new position.
// get the visual ghost node
function getVisualGhost (drag, ofs) {
// span is a child with position=relative in drag node,
// node is a clone of dragged widget,
// with position=absolute in span
var span = document.createElement("span"),
wgt = drag.node,
node = jq(wgt).clone()[0],
nstyle = node.style;
// need a relative positioned span
// to absolute position the cloned window
span.style.position = 'relative';
nstyle.position = 'absolute';
nstyle.left = wgt.offsetLeft - ofs[0] + 'px';
nstyle.top = wgt.offsetTop - ofs[1] + 'px';
// save the diffX and diffY for end drag
// for update the position in restoreWindow
wgt.diffX = wgt.offsetLeft - ofs[0]+7;
wgt.diffY = wgt.offsetTop - ofs[1]+5;
// hide the original window
wgt.style.display = 'none';
span.appendChild(node);
return span;
}
This fragment clone the window and make it follow the drag node, the span with relative position is required for absolute position the cloned window, then we calculate the left and top of the cloned window, and store it with a little bias '+7, +5' because the position of drag node will be changed later.
// update the position of original window,
// and show it
function restoreWindow(drag, pt) {
var wgt = drag.control,
n = wgt.$n(),
wstyle = n.style,
diffX = n.diffX,
diffY = n.diffY;
if ((typeof diffX) == 'number' && (typeof diffY) == 'number') {
wstyle.left = pt[0] + diffX + 'px';
wstyle.top = pt[1] + diffY + 'px';
wstyle.display = 'block';
n.diffX = n.diffY = null;
drag.control._fireOnMove();
}
}
This fragment display the original window with new position, and fire the move event to notice the server position is changed.
The full zul file is as below:
<zk>
<script type="text/javascript"><![CDATA[
zk.afterLoad("zk", function () {
// store the old ghost and getDrop function
var oldGhost = zk.DnD.ghost;
var oldGetDrop = zk.DnD.getDrop;
zk.DnD.ghost = function (drag, ofs, msg) {
if (jq(drag.node).hasClass('z-window-embedded')) {
// the dgelm is the drag node follows the mouse cursor,
var dgelm = document.createElement("div");
dgelm.id = "zk_ddghost";
zk.copy(dgelm.style, {
position: "absolute", left: ofs[0] + "px",
top: ofs[1] + "px"
});
dgelm.appendChild(getVisualGhost (drag, ofs));
jq(dgelm).addClass("z-drag-ghost");
document.body.appendChild(dgelm);
return dgelm;
} else // call old ghost if not embedded window
return oldGhost.apply(this, arguments);
};
// called while end drag
zk.DnD.getDrop = function (drag, pt, evt) {
if (jq(drag.node).hasClass('z-window-embedded')) {
restoreWindow(drag, pt);
}
// call old getDrop if not embedded window
return oldGetDrop.apply(this, arguments);
};
});
// get the visual ghost node
function getVisualGhost (drag, ofs) {
// span is a child with position=relative in drag node,
// node is a clone of dragged widget,
// with position=absolute in span
var span = document.createElement("span"),
wgt = drag.node,
node = jq(wgt).clone()[0],
nstyle = node.style;
// need a relative positioned span
// to absolute position the cloned window
span.style.position = 'relative';
nstyle.position = 'absolute';
nstyle.left = wgt.offsetLeft - ofs[0] + 'px';
nstyle.top = wgt.offsetTop - ofs[1] + 'px';
// save the diffX and diffY for end drag
// for update the position in restoreWindow
wgt.diffX = wgt.offsetLeft - ofs[0]+7;
wgt.diffY = wgt.offsetTop - ofs[1]+5;
// hide the original window
wgt.style.display = 'none';
span.appendChild(node);
return span;
}
// update the position of original window,
// and show it
function restoreWindow(drag, pt) {
var wgt = drag.control,
n = wgt.$n(),
wstyle = n.style,
diffX = n.diffX,
diffY = n.diffY;
if ((typeof diffX) == 'number' && (typeof diffY) == 'number') {
wstyle.left = pt[0] + diffX + 'px';
wstyle.top = pt[1] + diffY + 'px';
wstyle.display = 'block';
n.diffX = n.diffY = null;
drag.control._fireOnMove();
}
}
]]></script>
<vbox>
<hbox>
<div height="350px" width="350px" style="background-color: red;">
<button label="test" draggable="true" ></button>
</div>
<div height="350px" width="350px" style="background-color: green;">
<label id="posX" value="position left: " style="font-size: 20px;" />
<div></div>
<label id="posY" value="position top: " style="font-size: 20px;" />
</div>
</hbox>
<hbox>
<div height="350px" width="350px" style="background-color: brown;"></div>
<div height="350px" width="350px" style="background-color: blue;"></div>
</hbox>
</vbox>
<window width="300px" height="300px" border="normal"
title="test" draggable="true"
style="position: absolute; left: 100px; top: 100px;">
<attribute name="onMove">
posX.setValue("position left: " + event.getLeft());
posY.setValue("position top: " + event.getTop());
</attribute>
</window>
</zk>
Download:
drag_embedded_window_everywhere.zul
https://github.com/benbai123/ZK_Practice/tree/master/Components/projects/Components_Practice/WebContent
before_customized__not_desirable_dragging_positioning.swf
after_customized__drag_everywhere.swf
https://github.com/benbai123/ZK_Practice/tree/master/Components/demos/drag_embedded_window_everywhere
Hi ben How can we know which css used by AbsoluteChildren ? As i saw http://books.zkoss.org/wiki/ZK_Style_Guide i didnot get anything about AbsoluteChildren . I want to override .z-absolutechildren-focus( i am not sure if it is present ) style class. Can it be possible?
ReplyDeleteI think absolutechildren does not handle focus, you need to make it focusable manually, see
Deletehttp://ben-bai.blogspot.tw/2012/04/zk-make-unfocusable-component-focusable.html