- Legend to Symbols

-
Interface nokia.maps.dom.DragEventTarget
This class is a virtual interface that does exist for documentation purposes. Each class implementing this interface delcares that it can act as the target for certain events. Each event in this interface (and therefore also within the classes implementing the interface) represents an event of a specific type.
The following example shows event handling for events of the type "click":
// Note that "obj" can be either a DOM node or any other JavaScript object.
var obj = nokia.maps.dom.EventTarget( {} );
obj.addListener("click", function (evt) {
console.log("This is the '"+evt.type+"' event!");
});
obj.dispatch( new nokia.maps.dom.Event({
type: "click"
});
The example creates an instant of nokia.maps.dom.EventTarget, adds a listener
for "click" events to it, and dispatches a "click" event to all registered listeners (in
this case one) - the listeners receive the object that represents the target of the event.
For more information about dispatching events, please refer to the documentation of the nokia.maps.dom.EventTarget.
Drag and drop in a nutshell
The following description discusses event handling for drag and drop events. These are likely to be the most complex events, although once you have understood them, you should find them quite straightforward to process. The W3C homepage offers a very detailed explanation of drag and drop - please see http://dev.w3.org/html5/spec/dnd.html. Our text attempts to capture the information you need in a nutshell, plus it covers some information about the non-standard not lifted dragging, which is an arbitrary extension to the W3C specification and should help you use drag and drop events for certain special cases (such as implementing sliders).
Drag and drop concerns seven events, three of them (dragstart, drag
and dragend) are fired at the DOM node that is dragged and four (dragenter,
dragover, dragleave and drop) are fired at the DOM
node over which the source node is dragged or onto which the source node is dropped (this
does not occur in not lifted dragging, but more about that later).
Before we start
First, however, please note that the following code is always expected to be executed before the small code examples we provide below:
// Create a few shortcuts. var Page = nokia.maps.dom.Page, EventTarget = nokia.maps.dom.EventTarget; // Query page support for the document. This is very // important, but needs only to be done once. Page(document);
Dragging Basics The first step is to ensure that the DOM node to be dragged is draggable. The class nokia.maps.dom.EventTarget offers support in this respect through a method that takes care of all browser-specific details:
// Make a DOM node an event target and draggable. EventTarget(node).enableDrag();
This simple code guarantess that the browser fires a dragstart event as
soon as the user tries to drag node or any of its children. What is more,
this is valid for touch screens (for example the iPhone). If the event is canceled,
then dragging is disallowed, otherwise it is allowed (by default). While a drag
operation is in progress, no other mouse, touch or keyboard events are fired.
Note that the above applies also to the mouseup and click
events. You can get a mousedown event, but no mouseup
or click event follow it if the mousedown event started a
drag operation and dragstart event is not canceled with a call to
preventDefault(). Therefore, it is best not only to register a
listener for mousedown and mouseup (assuming you want to
track these two events), but also for dragend in the capture phase.
A mousedown followed by a dragend indicates the mouse
button has been released -- a mouseup is not generated. This means
you can simply use the dragend as a mouseup event. If you
recieved a mousedown at a node, you can be sure that you will receive a
dragend at the same node at least within the capture phase.
Each of the seven drag events has a special property called dataTransfer,
which holds an instance of nokia.maps.dom.DataTransfer.
This object contains information about the drag operation and is used to control it.
In addition, the object can be used to transfer data between the different drag
listeners, as it is guaranteed that the object itself is attached to all drag events
from dragstart to dragend. However, the next drag sequence
has a new dataTransfer object associated with it (so you cannot transfer
data between to separate drag sequences).
Dragging from the point of view of drag target
The eventdragstart has a property named effectAllowed.
It determines what kind of operation can be performed on the dragged object, for
example, whether the object can be copied, linked and/or moved. The value of this
property is set by the event handler to one of the following strings: "uninitialized",
"none", "copy", "copyLink", "copyMove", "all", "link", "linkMove" or "move". The
default value is "uninitialized" and has the same meaning as "all".
The dragstart event allows you to define the visual feedback of the drag
as well. There are two methods available on the data transfer object for this purpose:
setDragImage(node, offsetX, offsetY) and addElement(node).
You can only have one drag image (a picture visible while dragging is in progress),
so a second call to setDragImage() overwrites the previously set image
node. addElement() adds an unlimited number of additional elements
to the visual feedback. The visual feedback (all added elements and/or the drag image)
is rendered relative to the hot spot of the mouse cursor or the touch point of the
finger on a touch screen and is shown stretching to the right and down from the
mouse pointer or the dragging finger. You can fine-tune where the drag image appears
via its offset coordinates. The offset has no effect for the elements added using the
addElement(), but their style property position can be set
to "absolute" and then they can be offset using the CSS properties style.left
and style.top.
While dragging is in progress, the brower fires a "drag" event every few milliseconds
at the source node that is being dragged. If the event is canceled (preventDefault
is called), dragging is aborted, otherwise it continues. In most cases, the drag
event can be ignored, except, for example, for not lifted dragging to which we
return shortly.
When dragging is finished, the source node (the drag target) receives a dragend
event with information reflecting the action that was performed when the dragged object
reached the drop zone. The information is stored in the property dropEffect
of the data transfer object and is "none", "copy", "move" or "link". If the drop was
aborted or failed, the effect is none. This is important information in the
example that follows, because if the dragged element was not moved, the node must be
re-inserted into the document at the position it occupied before draggin began:
// This function makes an image node draggable.
var makeImageDraggable = function ( node ) {
// Create a closure so that every call to this method
// can handle it's own node.
(function (node) {
// Make the image draggable.
EventTarget(node).enableDrag();
// These variables are used later to put the image
// back where it was should dragging fail.
var sourceNodeParent;
var sourceNodeNextSibling;
// Register a dragstart listener.
node.addListener("dragstart", function (evt) {
// Remember the parent node and next sibling of the image.
sourceNodeParent = node.parentNode;
sourceNodeNextSilbing = sourceNode.nextSilbing;
// Detach the image from the document.
sourceNodeParent.removeChild (node);
// Attach the image to the cursor so that it is dragged around.
evt.dataTransfer.setDragImage( sourceNode, -evt.targetX || 0, -evt.targetY || 0);
// Allow all kinds of drag operations.
evt.dataTransfer.effectAllowed = "all";
// Prevent any other drag handlers from receiving this event,
// but do not cancel the event, because that would abort
// dragging.
evt.stopImmediatePropagation();
}, false);
// Register a dragend listener.
node.addListener("dragend", function (evt) {
// If the image was not moved somewhere else
if (evt.dataTransfer.dropEffect!=="move") {
// we have to move the image back to where it was.
if (sourceNodeNextSilbing)
sourceNodeParent.insertBefore(node, sourceNodeNextSilbing);
else
sourceNodeParent.appendChild(node);
}
// Note: If the image was moved, we don't need to do anything!
// Let's cancel the event now that we have processed it. The event
// must not be processed by the browser or any other listener.
event.cancel();
}, false);
})(node);
};
So far we have explained one aspect of drag and drop: what you need to do if you want to make a DOM node draggable. Next, we consider how to create a drop zone, where the dragged object can be dropped. Our next example extends the previous one by allowing the image to be dropped anywhere within the document.
The drag from the drop target perspective
A dropzone can be any DOM node or JavaScript object that is an instance of
nokia.maps.dom.EventTarget. Whenever the mouse is moved
onto such a node, the browser fires a dragenter event at that
node. If the event is not canceled (by calling preventDefault),
the browser estimates that a drop is not handled by the node and disallows a
drop to it. If the event is canceled (preventDefault has been
called), the listener must set the property dropEffect on the
data transfer object to indicate the operation that the node wants to perform
with the dragged element. If an image is dragged, dropEffect
must be said to "move".
The next event to be fired is dragover. It is fired regularly
like the drag event, but it is fired at the current drop target.
This event must be canceled (by calling preventDefault) and the
property dropEffect on the data transfer object must be updated
to indicate the desired operation ("none", "copy", "link" or "move". If the
event is not canceled, the drop is denied and the dropEffect is
set to "none".
Finally if the user releases the mouse button or finger (touch screen) above
a drop target that has set the dropEffect to "copy", "link" or
"move", a drop event is fired at the drop target. The drop handler
executes the required drop effect and cancels the event (by calling
preventDefault). If the event is not canceled, the browser
automatically executes the drop action (which only works for very specific
nodes).
The following code shows a complete drag and drop example for the image:
<html>
<head>
<!-- please load the API here -->
<script language="JavaScript">
// NOTE: This is very important, otherwise no event handling at all
// is possible!
var page = nokia.maps.dom.Page(document);
// Create a shortcut to the event target class.
var EventTarget = nokia.maps.dom.EventTarget;
// This function makes an image node draggable.
var makeImageDraggable = function ( node ) {
// Create a closure so that every call to this method
// can handle its own node.
(function (node) {
// Make the image draggable.
EventTarget(node).enableDrag();
// These variables are used later to put the image
// back to where it was originally, if dragging fails.
var sourceNodeParent;
var sourceNodeNextSibling;
// Register a dragstart listener.
node.addListener("dragstart", function (evt) {
// Remember the parent node and next sibling of the image.
sourceNodeParent = node.parentNode;
sourceNodeNextSilbing = node.nextSilbing;
// Detach the image from the document
sourceNodeParent.removeChild (node);
// Attach the image to the cursor so that it is dragged around.
evt.dataTransfer.setDragImage( node, -evt.targetX || 0, -evt.targetY || 0);
// Allow all drag operations.
evt.dataTransfer.effectAllowed = "all";
// Add the image node into the data transfer for the drop zone.
evt.dataTransfer.setData("image/gif", node);
// Prevent that any other drag handler to receive this event,
// but we must not cancel the event, otherwise the
// dragging is aborted.
evt.stopImmediatePropagation();
}, false);
// Register a dragend listener.
node.addListener("dragend", function (evt) {
// If the image was not moved somewhere else
if (evt.dataTransfer.dropEffect!=="move") {
// we have to move the image back to where it was.
if (sourceNodeNextSilbing)
sourceNodeParent.insertBefore(node, sourceNodeNextSilbing);
else
sourceNodeParent.appendChild(node);
}
// Note: If the image was moved, we don't need to do anything!
// Let's cancel the event now that we have processed it. The event
// must not be processed by the browser or any other listener.
evt.cancel();
}, false);
})(node);
};
function initDnD() {
// First of all make the image draggable.
makeImageDraggable (document.getElementById("draggableImage") );
// Get the DOM node for our drop zone.
var dropZone = EventTarget(document.getElementById("dropzone"));
// If the draggable image is dragged into our drop zone
dropZone.addListener("dragenter", function (evt) {
// Allow all GIF images to be moved here.
if (evt.dataTransfer.hasData("image/gif")) {
evt.dataTransfer.dropEffect = "move";
evt.cancel();
}
}, false);
// While the draggable image is moved onto the drop zone
dropZone.addListener("dragover", function (evt) {
// Allow all GIF images to be moved here.
if (evt.dataTransfer.hasData("image/gif")) {
evt.dataTransfer.dropEffect = "move";
evt.cancel();
}
}, false);
// If the draggable image is dropped onto our drop zone
dropZone.addListener("drop", function (evt) {
// If the GIF image is dropped here, add it into our drop zone
// and set the drop effect to "move".
if (evt.dataTransfer.hasData("image/gif")) {
dropZone.appendChild (evt.dataTransfer.getData("image/gif"));
evt.dataTransfer.dropEffect = "move";
evt.cancel();
}
}, false);
}
</script>
</head>
<body onload="initDnD()">
<div>
<img id="draggableImage" src="http://www.w3.org/Icons/WWW/w3c_home_nb.gif" />
</div>
<div id="dropzone" style="width:400px; height:300px; background-color:#eee;">
<p>Drop the image here</p>
</div>
</body>
</html>
The not lifted drag and drop
The not lifted drag and drop is a simplified and optimized drag and drop. It is useful if you want to
make draggable an element that is confined to a specific area and cannot leave that area, such as the thumb
shift of a scroll bar -- once dragging begins, it must not follow the mouse freely, but must move only along
the scroll bar. You can make this happen by setting the property lift on the data transfer
object of the dragstart event to false. This causes three things:
-
The
dragenter,dragover,dragleaveanddropevents are no longer be fired, therefore there is no drop zone for the dragged element. -
The cursor visible while dragging can be defined by the listener of the
dragstartanddragevent, ignoring theeffectAllowedanddropEffectproperties. This can be done by modifying the propertycursorproperty of thedataTransferobject. - A not lifted drag is always a pure soft event, which means simulated. The native browser drag and drop events are not be used, therefore such an event is confined to the document in which it is fired and no other element or external application can 'notice' the drag.
The following example shows how not lifted drag can be used to implement a slider:
<html>
<head>
<!-- please load API here -->
<script language="JavaScript">
// NOTE: This is very important, otherwise no event handling is possible!
var page = nokia.maps.dom.Page(document);
// Create a shortcut to the event target class.
var EventTarget = nokia.maps.dom.EventTarget;
function initDnD() {
// Let's make the scrollbar and the thumb shift draggable.
var scrollbar = EventTarget(page.$("scrollbar") ).enableDrag();
var knob = EventTarget(page.$("knob") ).enableDrag();
// Attach a dragstart listener to the scrollbar.
scrollbar.addListener("dragstart", function (evt) {
// If the know is being dragged.
if (evt.target===knob) {
// Remember that the thumb shift is dragged and set the value to the offset
// of the dragstart relative to the top-left corner of the target.
evt.dataTransfer.setData("application/slider", evt.targetY || 0);
// Switch to not lifted dragging and make the cursor a hand.
evt.dataTransfer.lift = false;
evt.dataTransfer.cursor = "hand";
} else
// If the user tries to drag the scalebar, cancel the event and
// disallow dragging
evt.cancel();
}, false);
// Attach a drag listener to the scrollbar.
scrollbar.addListener("drag", function (evt) {
// If the know is dragged
if (evt.dataTransfer.hasData("application/slider")) {
var targetY = evt.dataTransfer.getData("application/slider");
// Calculate the absolute position of the scrollbar
// within the document.
var scrollbarPos = page.getClientRect(scrollbar);
// Calculate the position of the thumb shift relative
// to the scrollbar, parallel to the mouse cursor.
var y = evt.pageY - scrollbarPos.top - targetY;
// Do not allow the thumb shift to be moved outside of the scrollbar.
if (y<0) y = 0;
if (y+knob.offsetHeight >= scrollbar.offsetHeight)
y = scrollbar.offsetHeight - knob.offsetHeight - 1;
// Move the thumb shift.
knob.style.top = y+"px";
}
}, false);
}
</script>
</head>
<body onload="initDnD()">
<div id="scrollbar" style="position:absolute; top:10px; left:10px; width:30px; height: 200px; background-color:#eee; border:1px solid black;">
<div id="knob" style="position:absolute; top:0; left:3px; width:24px; height:40px; background-color:black;"> </div>
</div>
</body>
</html>
dragstart event while a
drag operation is in propgress. This event is fired every few milliseconds during the
drag operation. The relatedTarget property
contains a reference to the object that is currently under the mouse/finger (only for
simulated drag events, not for the native onces).
Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.
| {nokia.maps.dom.DragEvent} | evt | An object representing the event |
dragstart event). The event is fired if the drop
was aborted, failed or successful. The event signals the end of a drag operation.
The state of the drop operation can be read from the dropEffect which
can be "none", "move", "copy" or "link" and reflects the action performed at the
drop target. This information can be used either to remove the dragged object
(for "move") or to do nothing (for the other drop effects).
Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.
| {nokia.maps.dom.DragEvent} | evt | An object representing the event |
preventDefault method was called at the event
object), a drop at the target is allowed, otherwise a drop is cannot occur.
If the drop is allowed, the target becomes the current drop target.
Note that despite the event name, its behavior is more similar to that of mouseover than
mouseenter.
Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.
| {nokia.maps.dom.DragEvent} | evt | An object representing the event |
mouseout than mouseleave.
Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.
| {nokia.maps.dom.DragEvent} | evt | An object representing the event |
dragenter event must be canceled (preventDefault
must be called) to make the object the current drop target. So if the dragenter
event is not canceled, then no dragover events are fired at all. This is event
is fired every few milliseconds as long as the mouse cursor is on/above the drop target. If
this event is not canceled (via preventDefault) the dropEffect
property is set to "none", which disallows a drop into the drop target. If the event is
canceled and the dropEffect is not "none", then a drop into this drop target
is allowed.
Note that in spite of the name of this event, its behavior is very different from the behavior
of the mouseover event.
Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.
| {nokia.maps.dom.DragEvent} | evt | An object representing the event |
draggable set
to true and after a mousedown/touch has occurred and the mouse/finger
was moved at least three pixels. If the event is not canceled (preventDefault
of the event was not called), the drag operation is permitted. The property
dataTransfer can be used to keep track of information while a drag
operation is in progress.
Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.
| {nokia.maps.dom.DragEvent} | evt | An object representing the event |
dragenter event and the dragover
events were canceled, so their preventDefault methods were called and the
allowedEffect property matches the dropEffect property.
If the event is not canceled (preventDefault is called) and the drop target
is a text field (for example, a textarea or input element), then the content of the
"text/plain" format is inserted into the area to which the mouse point is pointing
or added to the end of that area. Otherwise, the dropEffect is set to "none"
and no action takes place. If preventDefault was called, the sequence described
above does not take place.
Note: Please refer to the class documentation of the nokia.maps.dom.DragEvent for a more detailed description of this and other drag events.
| {nokia.maps.dom.DragEvent} | evt | An object representing the event |