📜 ⬆️ ⬇️

Photo uploader as vkontakte on Flex

A week ago, my knowledge of action script was limited to how to add an onclick event to a banner before being uploaded to a banner network. As a file loader, I used swfupload, and really didn’t want to get inside the swf-nick and understand the code. I don’t like flash, I’m never a designer and get lost when I see all these layers, frames, tools for drawing stars and motion guides.

Then I stumbled upon this this stunningly beautiful thing, and found out that there is flex . And that flex is awesome, because even such a super-beginner like me, from scratch in a few days was able to write a photo uploader with a preview, resize on the client and an upload-bar, something like the one used on the vkontakte.ru website.

There are three reasons why I decided to use flash to upload photos. These are FileReference, FileReferenceList and flash.display.Bitmap. In the 10th version of the flash player, FileReference has a load () function, with which you can view selected photos in a video clip locally without uploading to the server. FileReferenceList allows you to select multiple photos in the file dialog using shift. Bitmap resizes images before sending to the server. All this can not be done in pure javascript.
')
So, we write the photo uploader as vkontakte on flex (a step-by-step guide for quite beginners).

First of all, you need to install flex builder 3 ( there is a version that can be used for 60 days) and upgrade the flash player to the 10th version. Create a new flex project. Application type - web application, server type - none. Immediately you need to fix the project compiler, for this we select Project-> Properties-> Flex Compiler and change the parameter "Require Flash Player version" to 10.0.0. If this is not done, the load () function on the FileReference object will not work.

First arrange all the necessary elements on the page, and then we will write a script. Let's set the fixed dimensions of the workspace (application tag), put the panel inside, inside the panel - TileList, ProgressBar and ControlBar with the buttons “Select photos”, “Start loading” and “Clear”. After TileList, add an HBox with ProgressBar elements and a “cancel” button. That's what happens.
<? xml version ="1.0" encoding ="utf-8" ? >
< mx:Application xmlns:mx ="http://www.adobe.com/2006/mxml" layout ="absolute" width ="540" height ="465" >

< mx:Panel title =" "
paddingTop ="10" paddingLeft ="10" paddingBottom ="10" paddingRight ="10"
width ="100%" height ="100%" >

< mx:TileList
alternatingItemColors ="[#FFFFFF,#CCCCCC,#AAAAAA]"
verticalScrollPolicy ="on"
columnWidth ="120" columnCount ="4" rowHeight ="110" rowCount ="3" />

< mx:HBox horizontalAlign ="center" width ="100%" >
< mx:ProgressBar />
< mx:Button label ="" />
</ mx:HBox >

< mx:ControlBar horizontalAlign ="right" >
< mx:Button label =" " />
< mx:Button label =" " />
< mx:Button label ="" />
</ mx:ControlBar >
</ mx:Panel >
</ mx:Application >


* This source code was highlighted with Source Code Highlighter .


We will hide the ProgressBar and show it only when we click on the button “start download (visible =" false "). We make enabled =" false "on the buttons" start loading "and" clear "(they will be active only when the list of photos is not empty). Add id-shniki to all important elements.

Add the <mx: Script> tag and write code in it. Let's connect flash.net.FileReferenceList and mx.collections.ArrayCollection and set up the main global variable of photos like ArrayCollection.
< mx:Script >
<! [CDATA[

import flash.net.FileReferenceList;
import mx.collections.ArrayCollection;

[Bindable]
private var photos:ArrayCollection = new ArrayCollection;

]] >
</ mx:Script >


* This source code was highlighted with Source Code Highlighter .

[Bindable] means that the photos variable can be linked to other elements. We specify it as the dataProvider to the TileList, and then all changes in the photos array will be automatically reflected in the TileList.

Add a global variable frList of type FileReferenceList. On clicking on the button “Select photos” we will add the selectPhotos function. In order to catch the event, when the selection of photos is completed in the file dialog in frList.browse (), fErList needs to specify addEventListener (Event.COMPLETE, addPhotos). The optional parameter of the frList.browse () function is an array of FileFilter objects, where you can set a mask for file names. Finally, we write the addPhotos function, which will go through all the files selected in frList.fileList and add them to the photos array. That's what happens.
import mx.events.CollectionEvent;
import flash.net.FileReferenceList;
import mx.collections.ArrayCollection;

[Bindable]
private var photos:ArrayCollection = new ArrayCollection;
private var frList:FileReferenceList = new FileReferenceList;

private function init(): void
{
frList.addEventListener(Event.SELECT,addPhotos);
}

private function selectPhotos(): void
{
frList.browse([ new FileFilter( " jpeg" , "*.jpg;*.jpeg" )]);
}

private function addPhotos(): void
{
for ( var i: uint = 0; i < frList.fileList.length; i++)
{
var elem:Object = new Object;
elem.fr:FileReference = FileReference(frList.fileList[i]);
photos.addItem(elem);
}
}

* This source code was highlighted with Source Code Highlighter .

It is necessary that the “Start Download” and “Cancel” buttons be active only when the photos array is not empty. Add a handler to the Initialization function:
photos.addEventListener(CollectionEvent.COLLECTION_CHANGE,function()
{
startUploadButton.enabled = (photos.length>0);
clearPhotosButton.enabled = (photos.length>0);
});

* This source code was highlighted with Source Code Highlighter .

Now write itemRenderer for our TileList. itemRenderer is responsible for how to display an element of the photos array in the TileList cell. We take out the itemRenderer code in a separate MXML component. Make File-> New-> MXML Component named photoThumb, based on Canvas width 120 height 110. Add a itemRenderer property with value PhotoThumb to the TileList.

Now we will write the component code. We will do so that when you hover over each photo, a panel with control buttons will appear on it (we will only have one “delete” button). The corresponding element of the array, to which itemRenderer is called, is in the global variable data. With us every such element is an object with a single fRe property of type FileReference. Accordingly, in order to indicate the file name in the cell, you need to write <mx: Label text = "{data.fr.name}" />. Public parent functions are called via parentDocument. Here is the complete itemRenderer code, the background of the parent Canvas is set so that rollOver is correctly processed.
<? xml version ="1.0" encoding ="utf-8" ? >
< mx:Canvas xmlns:mx ="http://www.adobe.com/2006/mxml"
width ="120" height ="110"
backgroundColor ="#FFFFFF" backgroundAlpha ="0"
rollOver ="{controls.visible=true}" rollOut ="{controls.visible=false}" >

< mx:VBox width ="100%" height ="75" y ="5" horizontalAlign ="center" >
< mx:Image source ="{data.fr.data}" maxWidth ="100" maxHeight ="75" horizontalAlign ="center" verticalAlign ="middle" />
</ mx:VBox >
< mx:Label text ="{data.fr.name}" width ="100%" truncateToFit ="true" bottom ="0" textAlign ="center" />

< mx:VBox id ="controls" visible ="false" y ="65" right ="10" horizontalAlign ="right" >
< mx:Button label ="X" click ="parentDocument.clearPhoto(data)" fontSize ="6" width ="30" height ="15" />
</ mx:VBox >
</ mx:Canvas >


* This source code was highlighted with Source Code Highlighter .

Everything works except that when selecting large photos, they do not have time to boot, and TileList does not show them. To fix this, add the TileList update to the addPhotos function after loading each photo:
private function addPhotos(e:Event): void
{
for ( var i: uint = 0; i < frList.fileList.length; i++)
{
var elem:Object = new Object;
elem.fr = FileReference(frList.fileList[i]);
elem.fr.load();
elem.fr.addEventListener(Event.COMPLETE,refreshThumb);
photos.addItem(elem);
}
}

private function refreshThumb(e:Event): void
{
photosList.invalidateList();
}


* This source code was highlighted with Source Code Highlighter .

Add simple functions to remove all photos and delete the selected photo using the removeAll, removeItemAt and getItemIndex methods of the ArrayCollection class. At the same time, the function that is called from itemRender must be public.
private function clearPhotos(): void
{
photos.removeAll();
}

public function clearPhoto(data:Object): void
{
photos.removeItemAt(photos.getItemIndex(data));
}

* This source code was highlighted with Source Code Highlighter .

At this stage, a working application is received that shows file icons and works locally. Multiselekt when selecting files also works. It remains to add the download of the selected files to the server and use the ProgressBar. It's simple. When you click on the “Start download” button, we will take the first element from the photos, create a URLRequest, call the upload method in FileReference and add event listeners that will manage the progress bar and track when the file loads. After downloading, delete the first element from the photos and run it all over again. Here is the code:
private function startUpload(): void
{
photosProgressContainer.visible = true ;

var fr:FileReference = photos.getItemAt(0).fr;
fr.cancel();
fr.addEventListener(ProgressEvent.PROGRESS,uploadProgress);
fr.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA,uploadComplete);
fr.upload( new URLRequest( "http://ragneta.com/tests/flexupload/upload.php" ));
}

private function uploadProgress(e:ProgressEvent): void
{
photosProgress.setProgress(e.bytesLoaded,e.bytesTotal);
}

private function uploadComplete(e:DataEvent): void
{
photos.removeItemAt(0);
if (photos.length > 0)
startUpload();
else
photosProgressContainer.visible = false ;
}


* This source code was highlighted with Source Code Highlighter .

That's all, here is the complete code: Uploader.mxml , photoThumb.mxml . Next, you need to pass some authorization to the video, I pass the session identifier through flashvars, respectively, the flex variables passed are in the Application.application.parameters array. Then in the initialization I do HTTPRequest, send the session and get the name of the user, his albums and everything else. You also need to catch errors and exceptions, parse the server's response, and so on. Only the minimum required is written here.

If you do not need to download the source of photos, you can do a resize before sending to the server. This is done using flash.display.Bitmap, here is an example .

In the process of preparing the post found a strange bug. The progress bar and the FileReference.cancel () event do not work correctly on WinVista + FF 3.5.7 + Flash Player 10.0.42, but on the same WinXP + FF 3.5.7 + Flash Player 10.0.42 everything is fine.

Also, until I solved the problem with the rotation of images. First of all, I didn’t find how to do an animated transformation through setting a new image.transform.matrix. The second problem - my Rotate is not applied to the data that is passed to the itemRenderer, but to the itemRenderera tag itself. If you rotate the picture, and then delete it and load a new one in its place, it will be rotated. In this case, the initialize event of each cell occurs only once. It is necessary to hang the itemRenderer on the dataChange to turn to 0, although it would be enough if TileList could completely destroy the cells when deleting data, and then re-initialize.

Source: https://habr.com/ru/post/80954/


All Articles