Thus far, this chapter has focused on
dragging objects around on the screen. This
section wraps up the discussion by focusing in on the
dropping part of it all. To get started, let's
first take a look at dojo.dnd.Source
, a special container class
the toolkit provides a drag-and-drop source. A Source
can also act as a target for a drop,
but as we'll see in a moment, you can also specify a "pure" target
with dojo.dnd.Target
. While a
Source
may act as an origin and a
destination, a Target
may only act
as a destination.
Creating a Source
is just
like creating a Moveable
; you call
the constructor function and pass in a node as the first argument and
an Object
of parameters as the
second argument, like so. Table 7-3 lists the relevant
methods.
Table 7-3. Creating and destroying a Source
Name | Comment |
---|---|
| Constructor method for
creation. Valid values for |
| Prepares the |
Table 7-4
summarizes key parameters involved in the creation of a Source
object.
Table 7-4. Configuration parameters for Source's params in Table 7-3
Parameter | Type | Comment |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
A very common use for a Source
is to eliminate some of the
bookkeeping that is involved in dragging and dropping items that are
arranged in a list-like format. The following code example
illustrates:
<html> <head> <title>Fun with Source!</title> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" /> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" /> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dnd.css" /> <link rel="stylesheet" type="text/css" href="dndDefault.css" /> <script type="text/javascript" djConfig="parseOnLoad:true" src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"> </script> <script type="text/javascript"> dojo.require("dojo.dnd.Source"); dojo.require("dojo.parser"); </script> </head> <body> <div dojoType="dojo.dnd.Source" class="container"> <div class="dojoDndItem">foo</div> <div class="dojoDndItem">bar</div> <div class="dojoDndItem">baz</div> <div class="dojoDndItem">quux</div> </div> </body> </html>
Although this initial example may not look like much, there is a
tremendous amount of functionality packed into it. For starters,
notice that the only Dojo class that is directly involved is Source
, and to create a container of items
that are drag-and-droppable within that container, you simply provide
the token dojoType
tag and ensure
that the element is parsed; like most other examples, the parseOnLoad
parameter passed to djConfig
takes care of this task.
Next, take a few moments to tinker around with the example. It might be obvious that you can drag-and-drop single items at a time, but it's important to also note the full gamut of functionality that is offered:
Clicking selects a single element and results in all other elements becoming unselected.
Ctrl-clicking toggles the selection state of an item and allows you to build up multiple items at a time; you can also deselect individual items from a multiple selection situation.
Shift-clicking selects a range of elements from the previous-most selection to the current element being clicked. Any selections before the previous-most selection become unselected.
Ctrl-Shift-clicking selects a range of elements from the previous-most selection to the current element being clicked, but preserves any selections before the previous-most selection.
Holding down the Ctrl key while performing a drop results in the selection(s) being copied. Figure 7-1 illustrates some of these actions.
Figure 7-1. dnd1 shows an initial selection using Ctrl-click; dnd2 is the result of performing a Shift-click on quux; dnd3 is the result of performing a Shift-Ctrl-click on quux; dnd4 depicts a move operation by dragging without the Ctrl key; and dnd5 shows a copy operation by dragging with the Ctrl key applied
As mentioned earlier in the chapter, there are bound to be
plenty of times when you'll need to employ a Target
that can only act as a destination;
once items are placed in it, they may not be moved or reordered.
Make the following trivial modification to the previous code listing
to see a Target
in
action.
<body> <div dojoType="dojo.dnd.Source" class="container"> <div class="dojoDndItem">foo</div> <div class="dojoDndItem">bar</div> <div class="dojoDndItem">baz</div> <div class="dojoDndItem">quux</div> </div> <!-- Items added to targets cannot be removed or reordered --> <div dojoType="dojo.dnd.Target" class="container"></div> </body>
As you may be able to tell by now, a tremendous amount of
functionality is wrapped up into just a few lines of code, and
although div
elements were used
for the example, note that other types of standard HTML elements
work equally well. Unordered lists via the ul
and li
elements are a common choice.
The small icon that temporarily appears when an item from a
Source
is being moved around is
called an avatar. Although the standard avatar
is quite nice, you may want to construct your own at some point. The
following code adjustment illustrates how to define custom text for
an avatar by overriding the creator
method because this method is used
to create an avatar representation of one or more nodes. In this
particular circumstance, we'll choose to override creator
in markup. The layout is also
adjusted to a horizontal specification to simultaneously demonstrate
how to adjust a layout:
<body> <div dojoType="dojo.dnd.Source"horizontal=true
class="container"> <span
class="dojoDndItem ">foo</span
> <span
class="dojoDndItem ">bar</span
> <span
class="dojoDndItem ">baz</span
> <span
class="dojoDndItem ">quux</span
> <script type="dojo/method" event="creator" args="item,hint"> // override the creator function and return the appropriate type var node = dojo.doc.createElement("span"); node.id = dojo.dnd.getUniqueId( ); node.className = "dojoDndItem"; node.innerHTML = "<strong style='color: red'>Custom</strong> "+item; return {node: node, data: item, type: ["text"]}; </script> </div> <div dojoType="dojo.dnd.Target"horizontal=true
class="container"></div> </body>
Note that the arguments passed into creator
are item
and hint
, the actual item being moved and a
value specifying a "hint" for the kind of representation of that
should be created. Unless you implement your own low-level
machinery, hint
will always be
"avatar"
. The creator
function is expected to return an
object representation of item
with keys for an actual DOM node, a data representation, and the
type of representation. Recall that "text"
is the default representation
accepted by a Source
object.
Subscribing and connecting to events via dojo.subscribe
and dojo.connect
works just as easy as with
Moveable
objects. Table 7-5 summarizes public events for pub/sub
and connection-style communications, and a code example
follows.
Table 7-5. Drop events
Type | Event | Parameters | Summary |
---|---|---|---|
|
|
| Published when the
mouse moves over a |
|
|
| Published when a drag
beings. Parameter |
|
|
| Published when a drop
occurs (and a drag officially) ends. Parameter |
|
| N/A | Published when a drop operation is cancelled (for example, when the Esc key is pressed). |
|
|
| Called when a mouse
moves over a |
|
|
| Called when a drag
begins. Parameter |
|
|
| Called when a drop
occurs (and a drag officially) ends. Parameter |
|
| N/A | Called when a drop operation is cancelled (for example, when the Esc key is pressed). |
Go ahead and load up the following full-blown example and use
Firebug to inspect the output that occurs from the various topics
that we subscribe to and log to the console, and remember that you
can drag-and-drop from different Source
containers. Figure 7-2 shows the result. Good
stuff!
<html> <head> <title>More Fun with Drop!</title> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dijit/themes/tundra/tundra.css" /> <link rel="stylesheet" type="text/css" href="http://o.aolcdn.com/dojo/1.1/dojo/resources/dojo.css" /> <link rel="stylesheet" type="text/css" href="dndDefault.css" /> <script type="text/javascript" djConfig="parseOnLoad:true" src="http://o.aolcdn.com/dojo/1.1/dojo/dojo.xd.js"> </script> <script type="text/javascript"> dojo.require("dojo.dnd.Source"); dojo.require("dojo.parser"); dojo.addOnLoad(function( ) { dojo.subscribe("/dnd/source/over", function(source) { console.log("/dnd/source/over", source); }); dojo.subscribe("/dnd/start", function(source, nodes, copy) { console.log("/dnd/start", source, nodes, copy); }); dojo.subscribe("/dnd/drop", function(source, nodes, copy) { console.log("/dnd/drop", source, nodes, copy); }); dojo.subscribe("/dnd/cancel", function( ) { console.log("/dnd/cancel"); }); }); </script> </head> <body> <div id="source1" dojoType="dojo.dnd.Source" class="container"> <div class="dojoDndItem">foo</div> <div class="dojoDndItem">bar</div> <div class="dojoDndItem">baz</div> <div class="dojoDndItem">quux</div> </div> <div id="source2" dojoType="dojo.dnd.Source" class="container"> <div class="dojoDndItem">FOO</div> <div class="dojoDndItem">BAR</div> <div class="dojoDndItem">BAZ</div> <div class="dojoDndItem">QUUX</div> </div> </body> </html>
All it takes to demonstrate some connections is a different
addOnLoad
function. Note that
because we need to have a reference to the Source
that is created (not the DOM node),
we need to programmatically create the Source
instead of relying on the parser to
instantiate widgets that are defined in markup. Substitute the
following, turn off djConfig
's
parseOnLoad
flag, and take a look
at the Firebug console once again:
dojo.addOnLoad(function( ) {
//keep a reference to the Source to use for connecting.
var s1 = new dojo.dnd.Source("source1");
dojo.connect(s1, "onDndSourceOver", function(source) {
console.log("onDndSourceOver for", s1, source);
});
dojo.connect(s1, "onDndStart", function(source, nodes, copy) {
console.log("onDndStart for ", s1, source, nodes, copy);
});
dojo.connect(s1, "onDndStop", function(source, nodes, copy, target) {
console.log("onDndStop for", s1, source, nodes, copy, target);
});
dojo.connect(s1, "onDndCancel", function( ) {
console.log("onDndCancel for ", s1);
});
});
While the previous example demonstrated that you could use the
Source
constructor function to
make a node droppable, there is considerably more functionality you
can achieve via scripting. Table 7-6
summarizes the functionality that Selector
, a lower level class in dojo.dnd
, offers. Because Source
inherits from Selector
, these functions are directly
available to you though Source
,
although you might very well find uses for Selector
in and of itself.
Table 7-6. Selector API
Method | Comment |
---|---|
| Returns an |
| Deselects all of the nodes. |
| Selects all of the nodes. |
| Deletes all selected nodes. |
| Inserts an |
| Prepares the object for garbage collection. |
| Can be connected to
via |
| Can be connected to
via |
| Can be connected to
via |
| Can be connected to
via |
| Can be connected to
via |
Get Dojo: The Definitive Guide now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.