Chapter 8. Drag and Drop Support

Because almost every graphical operating system environment supports some level of drag and drop functionality, AIR provides an easy way to work with drag and drop gestures across multiple platforms. AIR supports both the dragging out and the dropping in of the standard data types; however, ActionScript and JavaScript deal with these gestures in very different ways.

Dragging Data Out of an Application in ActionScript

Problem

You need to drag a file reference from your application to the desktop.

Solution

Use the NativeDragManager class to control the drag-in gesture in your AIR application.

Discussion

In ActionScript, you manage drag and drop gestures with the NativeDragManager class. To support a drag-out gesture specifically, you use the doDrag static method of the NativeDragManager class. You can pass in five parameters; the first two are required: dragInitiator and clipboard.

The first required parameter, dragInitiator, is the object that initiated the drag action. It is required to be an InteractiveObject or a class that inherits from it. The second parameter, clipboard, is an instance of the Clipboard class or a class inheriting from the Clipboard class. In this case, you actually need to instantiate an instance of the Clipboard class and add the data that needs to be passed with the drag-out gesture.

In this example, the user interface consists of a label, a button, and a list:

<mx:Label id="directoryName"
    fontSize="20" fontWeight="bold" />

<mx:Button label="Select Directory"
    click="{file.browseForDirectory('Select Directory')}" />

<mx:List id="fileList" width="100%" height="100%"
    dataProvider="{files}" labelField="name"
    mouseDown="handleMouseDown(event)" />

When the button is clicked, it prompts the user to select a directory. When the user selects a directory, the list will be populated with all the files in the directory. The code you need is as follows:

<mx:WindowedApplication xmlns:mx="http://www.adobe.com/
2006/mxml" layout="vertical" preinitialize="init();">

<mx:Script>
    <![CDATA[

import mx.core.UIComponent;
import mx.collections.ArrayCollection;
import flash.filesystem.File;

[Bindable]
private var files:ArrayCollection = new ArrayCollection();
private var file:File = new File();


private function init():void {
    file.addEventListener( Event.SELECT, handleDirectorySelect );
}

private function handleDirectorySelect( event:Event ):void {
    files = new ArrayCollection( file.getDirectoryListing() );
    directoryName.text = file.name;
}

When the user performs a mouseDown gesture on the list, the handleMouseDown method is called. First, a new instance of the Clipboard class is created. The instance of the File class is passed into the instance of the Clipboard with the setData method. It is passed in as a one-element array because the ClipboardFormats.FILE_LIST_FORMAT is expecting an array. Next, a new instance of the BitmapData class is instantiated. This will contain the image that will be dragged. For the example, the BitmapData instance draws the list item that is being dragged. Finally, the doDrag method is called, and the list item, the instance of the Clipboard class, and the instance of the BitmapData class are passed in as parameters. The code for this is as follows:

private function handleMouseDown( event:MouseEvent ):void {
    if (fileList.selectedItem) {
        var data:Clipboard = new Clipboard();
        data.setData( ClipboardFormats.FILE_LIST_FORMAT, [ fileList.selectedItem ] );
        var bmd:BitmapData = new BitmapData( InteractiveObject( event.target 
).width, InteractiveObject( event.target ).height );
        bmd.draw( InteractiveObject( event.target ) );
        NativeDragManager.doDrag( event.target as InteractiveObject, data, bmd );
  }
}

Just as with the clipboard, you can add multiple types of data to a draggable object, enabling the receiving application to select the type of data that is most relevant.

Dragging Data Out of an Application in JavaScript

Problem

You need to drag a file reference from your application onto the desktop.

Solution

Listen to the dragstart event within the HTML in your AIR application.

Discussion

In JavaScript, dragging and dropping is handled by listening for specific events on an element. When dragging out, you listen specifically for the dragstart event. In the method that is listening for the event, you define the actual data that gets passed with the drag gesture.

To demonstrate the drag-out gesture in JavaScript, the following example provides a modest user interface that consists of three elements: a header div, a button that enables the user to select a directory, and a div that contains a list of the files in that directory.

<html>
<head>
    <title>Entry 8.2 - JavaScript</title>

    <script type="text/javascript" src="AIRAliases.js"></script>

    <style type="text/css">
        #files {width: 300px;height: 200px;overflow: auto;}
        #header{ font-weight: bold;font-size: 20px;}
        .listing {background-color: #efefef; padding: 3px;margin: 3px 0;-webkit-
user-drag: element;}
    </style>

</head>

<body onload="init()" style="margin: 10px;">
    <div id="header">Select a Directory</div>
    <input type="button" value="Select Directory" onclick="handleSelectButton()"/>
    <div id="files"></div>
</body>
</html>

Before the individual files can be dragged out of the application, the previously mentioned items need to be listed in the div named files. When clicked, the Select Directory button launches the directory selection window, and when a directory is selected, the directorySelected method is called. This clears the files div and adds a new div for each file. The important item to notice here is that an event listener is being configured for each div that is listening for the dragstart event. This is the event that is dispatched when the user performs a mouseDown gesture on the object.

In addition, each new div that is created is assigned a property called fileReference. The actual instance of the File class for each file is assigned to this property. This assignment enables the instance to be passed with the object when dragged.

var file = new air.File();
var directoryFiles = {};

function init() {
    file.addEventListener(air.Event.SELECT, directorySelected);
}

function handleSelectButton() {
    file.browseForDirectory("Select a directory");
}

function directorySelected(event) {
    directoryFiles = file.getDirectoryListing();
    var header = document.getElementById( 'header' );
    header.innerHTML = file.name;
    var files = document.getElementById( 'files' );
    while( files.hasChildNodes() ) {
        files.removeChild( listing.firstChild );
    }
    for (i = 0; i < directoryFiles.length; i++) {
        var item = document.createElement( 'div' );
        item.innerHTML = directoryFiles[i].name;
        item.className = "listing";
        item.fileReference = directoryFiles[i];
        item.addEventListener( "dragstart", handleDragStart );
        files.appendChild( item );
  }
}

After each file div is configured to listen for the dragstart event, you can add data to the drag object. For this example, the data is copied, as you can see by the String value copy assigned to the effectAllowed property of the dataTransfer object in the event. Next, the data is added to the drag object with the setData method just as with the clipboard. The format and the actual data are both passed in.

Because the data format is air.ClipboardFormats.FILE_LIST_FORMAT, the data needs to be in an array variable. It will have only a single element, which is the fileReference property of the dragged object that was assigned earlier.

function handleDragStart(event) {
    event.dataTransfer.effectAllowed = "copy";
    event.dataTransfer.setData(air.ClipboardFormats.FILE_LIST_FORMAT,new Array( 
event.target.fileReference ) );
}

With just these lines of code, the application now supports the drag-out gesture. In this case, if one of the file listings is dragged from the application to the desktop, a new copy of the file will appear on the desktop.

Working with other types of clipboard data is similar. You can add multiple types of data to the dataTransfer object, and an application that has been written to receive dragged-in content can be configured to handle the different data formats.

Dragging Data Into an Application in ActionScript

Problem

You want to be able to drag text into your AIR application from another application.

Solution

AIR provides the capability to support the drag-in gesture in both ActionScript and JavaScript.

Discussion

In ActionScript, the NativeDragManager class handles the drag-in gesture. Its static method acceptDragDrop enables you to define whether you will accept the dragged data based on its contents.

In this example, the user interface consists of a box that functions as the target area and a text area that will be used to display the text data from the drag-in gesture:

<mx:WindowedApplication xmlns="http://www.adobe.com/2006/mxml"
    layout="vertical" creationComplete="init()">

    <mx:Script>
    ...
    </mx:Script>

    <mx:Box id="target" width="200" height="200" backgroundColor="#efefef"
        nativeDragEnter="handleDragEnter(event)" 
nativeDragDrop="handleDrop(event)"
        horizontalAlign="center" verticalAlign="middle">

        <mx:Label text="Target Area" fontSize="20" fontWeight="bold" 
color="#666666" />

    </mx:Box>

    <mx:TextArea id="content" width="100%" height="100%"/>

</mx:WindowedApplication>

The target area box contains event listeners configured for the nativeDragEnter and nativeDragDrop events. The nativeDragEnter event is dispatched when dragged data is brought over an object. If you plan to accept only certain types of dropped data, you need to add logic to this method to check the data formats. The NativeDragEvent contains a property named clipboard that is an instance of the Clipboard class and that contains all the data for the dragged object. You can use the hasFormat method of this property to determine whether the needed data is present. Once you are sure that the needed data is present, you can call the NativeDragManager.acceptDragDrop method and pass in the target area as the parameter.

private function handleDragEnter( event:NativeDragEvent ):void {
    if( event.clipboard.hasFormat( ClipboardFormats.TEXT_FORMAT ) ) {
        NativeDragManager.acceptDragDrop( target );
    }
}

If the acceptDragDrop method is called, then the nativeDragDrop method is dispatched when the object is dropped onto the target area. In this case, once the data is dropped, any data in the ClipboardFormats.TEXT_FORMAT format is extracted and placed into the text area.

private function handleDrop( event:NativeDragEvent ):void {
    content.text = event.clipboard.getData( ClipboardFormats.TEXT_FORMAT ) as 
String;
}

Dragging Data Into an Application in JavaScript

Problem

You want to be able to drag text into your AIR application from another application.

Solution

Listen to the dragenter, dragover, and drop events within the HTML of your AIR application.

Discussion

In JavaScript, the drag-in gesture is supported by listening for specific events. If you want to use a div as a target for the drag in, you need to listen for three specific events: dragenter, dragover, and drop. By default, you cannot use a noneditable region as a drop target, but if you listen for the dragenter and dragover events and call the event.preventDefault method, you can use noneditable regions as drop targets.

To perform the drop, you need to listen for the drop event. The drop event contains a dataTransfer object that works like the Clipboard class. You can call the event.dataTransfer.getData method and pass in the data type. It then returns the data from the drag-in gesture in that format.

In this example, the user interface consists of two div elements. The first div with an id of targetArea is used as the drop target. The second div with an id of content is updated with the value of the dropped text.

<html>
<head>
    <title>Entry 8.4 - JavaScript</title>

    <style type="text/css">
        #targetArea { width: 250px;height: 250px;background-color: 
#efefef;border: 1px solid #cccccc; color: #cccccc;text-align: center;font-size: 
20px; }
        #content { font-size: 11px; }
    </style>

</head>

<body onload="init()" style="margin: 10px;">
    <div id="targetArea">Drop Target</div>
    <div id="content"></div>
</body>
</html>

The event listeners that are needed for the drag-in gesture are added in the init method, which is called in response to the onload event. Also, the method handleDefaultEvents calls the event.preventDefault method to allow the targetArea to be used as a drop target.

function init() {
    var targetArea = document.getElementById( 'targetArea' );
    targetArea.addEventListener( "dragenter", handleDefaultEvents );
    targetArea.addEventListener( "dragover", handleDefaultEvents );
    targetArea.addEventListener( "drop", handleDrop );
}

function handleDefaultEvents( event ) {
    event.preventDefault();
}

The handleDrop method responds to the drop event. In this method, the text data is extracted from the event by calling the event.dataTransfer.getData method and passing in the air.ClipboardFormats.TEXT_FORMAT value. This text is then added to the div named content.

function handleDrop( event ) {
    var dragText = event.dataTransfer.getData( air.ClipboardFormats.TEXT_FORMAT );
    var content = document.getElementById( 'content' );
    content.innerHTML = dragText;
}

Dragging and Dropping Within an Application in ActionScript

Problem

You need to enable drag and drop gestures that work both within your application and outside your application.

Solution

Use the NativeDragManager’s static methods to enable both drag-in and drag-out gestures.

Discussion

In ActionScript, you can use both static methods of the NativeDragManager class to achieve drag and drop functionality within your application. In this example, the user interface consists of two VBox components that function as drop targets. Each VBox contains three labels that function as the drag objects. Each Label is configured with an event listener that listens for the mouseDown event. Each VBox is configured with an event handler for the nativeDragEnter and nativeDragDrop events.

<mx:Style>
    .target { backgroundColor: #ffffff; borderStyle: solid; borderColor: #666666; }
</mx:Style>

<mx:Label text="Drag and Drop" fontSize="20" fontWeight="bold" />

<mx:HBox>

    <mx:VBox id="target1" width="250" nativeDragEnter="handleDragEnter(event)" 
nativeDragDrop="handleDrop(event)" styleName="target">
        <mx:Label text="One" mouseDown="handleMouseDown(event)" />
        <mx:Label text="Two" mouseDown="handleMouseDown(event)" />
        <mx:Label text="Three" mouseDown="handleMouseDown(event)" />
    </mx:VBox>

    <mx:VBox id="target2" width="250" nativeDragEnter="handleDragEnter(event)" 
nativeDragDrop="handleDrop(event)" styleName="target">
        <mx:Label text="Four" mouseDown="handleMouseDown(event)" />
        <mx:Label text="Five" mouseDown="handleMouseDown(event)" />
        <mx:Label text="Six" mouseDown="handleMouseDown(event)" />
  </mx:VBox>

</mx:HBox>

The handleMouseDown method performs three specific functions:

  • It creates a new instance of the Clipboard class and adds the text property of the Label as text data.

  • An instance of the BitmapData class draws the Label.

  • Calling the acceptDragDrop method of the NativeDragManager and passing it the Label, the instance of the Clipboard class, and the instance of the BitmapData class initiates the drag gesture.

The code you need is as follows:

private function handleMouseDown( event:MouseEvent ):void {
    var data:Clipboard = new Clipboard();
    var labelToDrag:Label = Label(event.currentTarget);
    data.setData( ClipboardFormats.TEXT_FORMAT, labelToDrag.text );
    var bmpProxy:BitmapData = new BitmapData(labelToDrag.width, labelToDrag.height );
    bmd.draw(labelToDrag);
    NativeDragManager.doDrag(labelToDrag, data, bmpProxy);
}

The handleDragEnter method that is triggered by the VBox components performs one specific function: accepting the drag-in gesture. The static NativeDragManager.acceptDragDrop method must be called so the drag object knows the target is willing to accept its data. To ensure this text is plain-text data, the hasFormat method of the Clipboard class is called.

private function handleDragEnter( event:NativeDragEvent ):void {
    if( event.clipboard.hasFormat( ClipboardFormats.TEXT_FORMAT ) )
        NativeDragManager.acceptDragDrop(VBox(event.currentTarget));
}

The handleDrop method takes the data that was dropped and creates a new Label in the target VBox identical to the drag object:

private function handleDrop( event:NativeDragEvent ):void {
    var newLabel:Label = new Label();
    newLabel.text = event.clipboard.getData( ClipboardFormats.TEXT_FORMAT ) as 
String;
    newLabel.addEventListener( MouseEvent.MOUSE_DOWN, handleMouseDown );
    VBox( event.target ).addChild( newLabel );
}

With this simple application, you now can drag the label to either target, and the application will be replicated. In addition, you can drag any of these drag objects outside the application to any application that supports plain-text data. The VBox drag targets will also accept text dragged in from outside the AIR application.

Dragging and Dropping Within an Application in JavaScript

Problem

You need to enable drag and drop gestures that work both within your application and outside your application.

Solution

Listen to the dragenter, dragover, dragstart, and drop events from the HTML within your AIR application.

Discussion

In JavaScript, you can perform drag and drop operations by listening to the dragenter, dragover, dragstart, and drop events. In this example, the user interface consists of two div elements that function as drop targets. Each div contains three div elements that function as drag objects. The target div elements have event listeners for the dragover, dragenter, and drop events. The drag objects have an event listener for the dragstart event. For example:

<html>
<head>
    <title>Entry 8.6 - JavaScript</title>

    <script type="text/javascript" src="AIRAliases.js"></script>
    <script type="text/javascript" src="AIRIntrospector.js"></script>
    <script type="text/javascript">
        function init() {
            var target1 = document.getElementById( 'target1' );
            target1.addEventListener( "dragenter", handleDefaultEvents );
            target1.addEventListener( "dragover", handleDefaultEvents );
            target1.addEventListener( "drop", handleDrop );
            var target2 = document.getElementById( 'target2' );
            target2.addEventListener( "dragenter", handleDefaultEvents );
            target2.addEventListener( "dragover", handleDefaultEvents );
            target2.addEventListener( "drop", handleDrop );
        }

    </script>

    <style type="text/css">
        .target {  width: 150px;height: 250px;border: 1px solid #cccccc; 
color: #cccccc;text-align: center;font-size: 20px; margin: 5px; }
        #content { font-size: 11px; }
        #sourceArea { background-color: #efefef;-webkit-user-drag: element; }
        .listItem {background-color: #efefef;-webkit-user-drag: element; font-
size: 11px;margin: 3px;padding:3px;}
    </style>

</head>

<body onload="init()" style="margin: 10px;">
    <h1>Drag and Drop</h1>
    <div id="target1" class="target" style="float: left;">
        <div class="listItem" ondragstart="handleDragStart(event)">One</div>
        <div class="listItem" ondragstart="handleDragStart(event)">Two</div>
        <div class="listItem" ondragstart="handleDragStart(event)">Three</div>
    </div>
    <div id="target2" class="target" style="float: left;">
        <div class="listItem" ondragstart="handleDragStart(event)">Four</div>
        <div class="listItem" ondragstart="handleDragStart(event)">Five</div>
        <div class="listItem" ondragstart="handleDragStart(event)">Six</div>
    </div>
</body>
</html>

The handleDefaultEvents method that is triggered by the drop target div elements calls the event.preventDefault method to enable them to function as drop targets:

function handleDefaultEvents( event ) {
    event.preventDefault();
}

The handleDragStart method that is triggered when you drag one of the drag objects calls dataTransfer.setData, passing the innerHTML property of the object to be dragged as the drag data. This will be used to create a duplicate div when the drag object is dropped onto a drop target.

function handleDragStart( event ) {
    event.dataTransfer.setData( air.ClipboardFormats.TEXT_FORMAT, 
event.target.innerHTML );
}

The handleDrop method creates a new div with the same innerHTML as the drag object and adds it to the drop target. An event listener is added for the dragstart event so the new div can function as a drag object as well.

function handleDrop( event ) {
    var newDiv = document.createElement( 'div' );
    newDiv.innerHTML = event.dataTransfer.getData( air.ClipboardFormats.TEXT_FORMAT );
    newDiv.className = 'listItem';
    newDiv.addEventListener( "dragstart", handleDragStart );
    event.currentTarget.appendChild( newDiv );
}

By using AIR’s drag and drop support, you can drag objects within the application or outside the application to any application that supports plain text.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset