Added DMU Flex source

Changed all TheOutfield namesspaces to Umbraco
Added DMU dasboards
Removed ZipUpload dashboards
Added air mimetype to web.config
This commit is contained in:
matt
2011-02-05 12:21:04 +00:00
parent a5527769f3
commit 03f8aac4e5
60 changed files with 2094 additions and 71 deletions

View File

@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="utf-8" standalone="no"?>
<application xmlns="http://ns.adobe.com/air/application/2.0">
<!-- Adobe AIR Application Descriptor File Template.
Specifies parameters for identifying, installing, and launching AIR applications.
xmlns - The Adobe AIR namespace: http://ns.adobe.com/air/application/2.0
The last segment of the namespace specifies the version
of the AIR runtime required for this application to run.
minimumPatchLevel - The minimum patch level of the AIR runtime required to run
the application. Optional.
-->
<!-- A universally unique application identifier. Must be unique across all AIR applications.
Using a reverse DNS-style name as the id is recommended. (Eg. com.example.ExampleApplication.) Required. -->
<id>org.umbraco.DesktopMediaUploader</id>
<!-- Used as the filename for the application. Required. -->
<filename>Desktop Media Uploader</filename>
<!-- The name that is displayed in the AIR application installer.
May have multiple values for each language. See samples or xsd schema file. Optional. -->
<name>Desktop Media Uploader</name>
<!-- An application version designator (such as "v1", "2.5", or "Alpha 1"). Required. -->
<version>v2.0.4</version>
<!-- Description, displayed in the AIR application installer.
May have multiple values for each language. See samples or xsd schema file. Optional. -->
<description>
This application allows you to upload media to an Umbraco website directly from your desktop.
</description>
<!-- Copyright information. Optional -->
<copyright>2010 Umbraco.org</copyright>
<!-- Publisher ID. Used if you're updating an application created prior to 1.5.3 -->
<!-- <publisherID></publisherID> -->
<!-- Settings for the application's initial window. Required. -->
<initialWindow>
<!-- The main SWF or HTML file of the application. Required. -->
<!-- Note: In Flash Builder, the SWF reference is set automatically. -->
<content>DesktopMediaUploader.swf</content>
<!-- The title of the main window. Optional. -->
<!-- <title></title> -->
<!-- The type of system chrome to use (either "standard" or "none"). Optional. Default standard. -->
<!-- <systemChrome></systemChrome> -->
<!-- Whether the window is transparent. Only applicable when systemChrome is none. Optional. Default false. -->
<!-- <transparent></transparent> -->
<!-- Whether the window is initially visible. Optional. Default false. -->
<!-- <visible></visible> -->
<!-- Whether the user can minimize the window. Optional. Default true. -->
<!-- <minimizable></minimizable> -->
<!-- Whether the user can maximize the window. Optional. Default true. -->
<!-- <maximizable></maximizable> -->
<!-- Whether the user can resize the window. Optional. Default true. -->
<!-- <resizable></resizable> -->
<!-- The window's initial width in pixels. Optional. -->
<!-- <width></width> -->
<!-- The window's initial height in pixels. Optional. -->
<!-- <height></height> -->
<!-- The window's initial x position. Optional. -->
<!-- <x></x> -->
<!-- The window's initial y position. Optional. -->
<!-- <y></y> -->
<!-- The window's minimum size, specified as a width/height pair in pixels, such as "400 200". Optional. -->
<!-- <minSize></minSize> -->
<!-- The window's initial maximum size, specified as a width/height pair in pixels, such as "1600 1200". Optional. -->
<!-- <maxSize></maxSize> -->
</initialWindow>
<!-- We recommend omitting the supportedProfiles element, -->
<!-- which in turn permits your application to be deployed to all -->
<!-- devices supported by AIR. If you wish to restrict deployment -->
<!-- (i.e., to only mobile devices) then add this element and list -->
<!-- only the profiles which your application does support. -->
<!-- <supportedProfiles>desktop extendedDesktop mobileDevice extendedMobileDevice</supportedProfiles> -->
<!-- The subpath of the standard default installation location to use. Optional. -->
<!-- <installFolder></installFolder> -->
<!-- The subpath of the Programs menu to use. (Ignored on operating systems without a Programs menu.) Optional. -->
<!-- <programMenuFolder></programMenuFolder> -->
<!-- The icon the system uses for the application. For at least one resolution,
specify the path to a PNG file included in the AIR package. Optional. -->
<icon>
<image16x16>assets/icon-16.png</image16x16>
<image32x32>assets/icon-32.png</image32x32>
<image48x48>assets/icon-48.png</image48x48>
<image128x128>assets/icon-128.png</image128x128>
</icon>
<!-- Whether the application handles the update when a user double-clicks an update version
of the AIR file (true), or the default AIR application installer handles the update (false).
Optional. Default false. -->
<!-- <customUpdateUI></customUpdateUI> -->
<!-- Whether the application can be launched when the user clicks a link in a web browser.
Optional. Default false. -->
<allowBrowserInvocation>true</allowBrowserInvocation>
<!-- Listing of file types for which the application can register. Optional. -->
<!-- <fileTypes> -->
<!-- Defines one file type. Optional. -->
<!-- <fileType> -->
<!-- The name that the system displays for the registered file type. Required. -->
<!-- <name></name> -->
<!-- The extension to register. Required. -->
<!-- <extension></extension> -->
<!-- The description of the file type. Optional. -->
<!-- <description></description> -->
<!-- The MIME content type. -->
<!-- <contentType></contentType> -->
<!-- The icon to display for the file type. Optional. -->
<!-- <icon>
<image16x16></image16x16>
<image32x32></image32x32>
<image48x48></image48x48>
<image128x128></image128x128>
</icon> -->
<!-- </fileType> -->
<!-- </fileTypes> -->
</application>

View File

@@ -0,0 +1,90 @@
/* CSS file */
@namespace s "library://ns.adobe.com/flex/spark";
@namespace mx "library://ns.adobe.com/flex/mx";
global
{
focus-color: #EEB470;
selection-color: #EEB470;
roll-over-color: #EEEEEE;
}
mx|Tree
{
textSelectedColor: #ffffff;
textRollOverColor: #000000;
selection-color: #f36f21;
roll-over-color: #cccccc;
}
#grpSignInForm s|Label
{
paddingTop: 5px;
}
#grpSignInForm s|CheckBox s|Label
{
paddingTop: 0;
}
.header
{
borderColor: #7a7a7a;
backgroundColor: #7a7a7a;
paddingTop: 25px;
paddingBottom: 25px;
paddingLeft: 25px;
paddingRight: 25px;
}
.header mx|Label
{
color: #ffffff;
font-size: 16px;
font-weight: bold;
}
.header s|DropDownList
{
skinClass: ClassReference('org.umbraco.desktopmediauploader.skins.HeaderDropDownListSkin');
color: #ffffff;
content-background-color: #7a7a7a;
roll-over-color: #f36f22;
}
.header s|DropDownList s|Label
{
font-size: 12px;
font-weight: normal;
}
#btnSignIn,
#btnUpload
{
cornerRadius: 5px;
borderThickness: 2px;
downSkin: Embed(source="assets/dmu_orange.swf", symbol="Button_downSkin");
overSkin: Embed(source="assets/dmu_orange.swf", symbol="Button_overSkin");
upSkin: Embed(source="assets/dmu_orange.swf", symbol="Button_upSkin");
paddingLeft: 20px;
paddingRight: 20px;
paddingTop: 7px;
paddingBottom: 7px;
color: #ffffff;
font-weight: bold;
font-size: 14px;
text-roll-over-color: #ffffff;
text-selected-color: #ffffff;
text-disabled-color: #cccccc;
}
.signOutButton
{
skinClass: ClassReference('org.umbraco.desktopmediauploader.skins.SignOutButtonSkin');
}
.removeButton
{
skinClass: ClassReference('org.umbraco.desktopmediauploader.skins.RemoveButtonSkin');
}

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="utf-8"?>
<s:WindowedApplication xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
skinClass="org.umbraco.desktopmediauploader.skins.ApplicationSkin"
width="300" height="550" showStatusBar="false"
xmlns:views="org.umbraco.desktopmediauploader.views.*"
windowComplete="init();" >
<fx:Style source="DesktopMediaUploader.css"/>
<fx:Script>
<![CDATA[
import org.umbraco.desktopmediauploader.events.*;
import org.umbraco.desktopmediauploader.util.*;
import mx.controls.Alert;
protected function init():void
{
StageHelper.stage = stage;
NativeApplication.nativeApplication.addEventListener(BrowserInvokeEvent.BROWSER_INVOKE, app_BrowserInvoke);
vwSignIn.addEventListener(SignedInEvent.SIGNED_IN, vwSignIn_SignedIn);
vwUpload.addEventListener(SignedOutEvent.SIGNED_OUT, vwUpload_SignOut);
vwSignIn.init();
}
protected function app_BrowserInvoke(e:BrowserInvokeEvent):void
{
vwSignIn.visible = true;
vwUpload.visible = false;
}
protected function vwSignIn_SignedIn(e:SignedInEvent):void
{
vwSignIn.visible = false;
vwUpload.visible = true;
}
protected function vwUpload_SignOut(e:SignedOutEvent):void
{
vwSignIn.visible = true;
vwUpload.visible = false;
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<views:SignInView id="vwSignIn" left="0" top="0" right="0" bottom="0">
</views:SignInView>
<views:UploadView id="vwUpload" left="0" top="0" bottom="0" right="0"
visible="false">
</views:UploadView>
</s:WindowedApplication>

View File

@@ -0,0 +1,20 @@
package
{
public class Model
{
[Bindable] public static var url:String;
[Bindable] public static var username:String;
[Bindable] public static var password:String;
[Bindable] public static var ticket:String;
[Bindable] public static var displayName:String;
[Bindable] public static var umbracoPath:String;
[Bindable] public static var maxRequestLength:Number;
[Bindable] public static var currentFolder:XML;
[Bindable] public static var folderId:Number = 0;
[Bindable] public static var folderName:String = "";
[Bindable] public static var folderPath:String = "";
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<s:TitleWindow xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="260" height="350" title="Select a folder..." creationComplete="folderPickerDialog_CreationComplete(event)"
close="folderPickerDialog_Close(event)" borderVisible="true" chromeColor="#EEEEEE" borderColor="#666666">
<s:layout>
<s:VerticalLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import org.umbraco.desktopmediauploader.events.*;
import org.umbraco.desktopmediauploader.net.*;
import mx.controls.Alert;
import mx.events.CloseEvent;
import mx.events.FlexEvent;
import mx.managers.*;
protected function folderPickerDialog_CreationComplete(event:FlexEvent):void
{
CursorManager.setBusyCursor();
DmuRequest.makeRequest(DmuRequestAction.FOLDER_LIST,
folderListLoader_Complete,
folderListLoader_Error);
}
protected function folderListLoader_Complete(event:DmuRequestEvent):void
{
CursorManager.removeBusyCursor();
var xml:XML = event.result;
trFolders.dataProvider = xml.folder;
trFolders.labelField = "@name";
trFolders.validateNow();
// Reselect current folder
if (Model.folderId)
{
var node:XMLList = xml..folder.(@id == Model.folderId.toString());
if (node.length() > 0)
{
expandParents(node[0]);
trFolders.selectedItem = node[0];
var idx:int = trFolders.getItemIndex(node[0]);
trFolders.scrollToIndex(idx);
}
else
{
Model.folderId = undefined;
Model.folderName = undefined;
}
}
}
protected function folderListLoader_Error(event:Event):void
{
CursorManager.removeBusyCursor();
Alert.show("Unable to load folder list", "Ooops!");
}
protected function folderPickerDialog_Close(event:CloseEvent):void
{
PopUpManager.removePopUp(this);
}
protected function trFolders_DoubleClick(event:MouseEvent):void
{
var item:XML = trFolders.selectedItem as XML;
Model.currentFolder = item;
Model.folderId = item.@id;
Model.folderName = item.@name;
var pathItem:XML = item;
var path:String = pathItem.@name;
while(pathItem.parent())
{
pathItem = pathItem.parent();
if(pathItem.@name != undefined)
{
path = pathItem.@name +"/"+ path;
}
}
Model.folderPath = path;
PopUpManager.removePopUp(this);
}
private function expandParents(node:XML):void
{
if (node && !trFolders.isItemOpen(node))
{
trFolders.expandItem(node, true);
expandParents(node.parent());
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:Tree width="100%" height="100%" id="trFolders"
defaultLeafIcon="@Embed('assets/folder.png')"
folderClosedIcon="@Embed('assets/folder.png')"
folderOpenIcon="@Embed('assets/folder-open.png')"
paddingLeft="5" paddingRight="5" paddingTop="2" paddingBottom="2"
doubleClickEnabled="true" doubleClick="trFolders_DoubleClick(event)" borderVisible="false"></mx:Tree>
</s:TitleWindow>

View File

@@ -0,0 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
backgroundColor="#e7e7e7" borderColor="#CCCCCC"
width="100%" height="30">
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<fx:Script>
<![CDATA[
[Bindable] public var totalItems:int;
protected function btnUploadRemove_Click(event:MouseEvent):void
{
dispatchEvent(new Event(Event.CANCEL));
}
]]>
</fx:Script>
<mx:Image left="7" source="@Embed('assets/information.png')" width="16" height="16" verticalCenter="0"/>
<mx:Label id="lblUploadName" text="Total of {totalItems} File{(totalItems == 1)? '' : 's'}" fontWeight="bold" fontSize="12" color="#999999" left="27" truncateToFit="true" minWidth="0" right="35" verticalCenter="0"/>
<s:Button id="btnUploadRemove" width="16" height="16" top="5" right="5" useHandCursor="true" buttonMode="true" styleName="removeButton" click="btnUploadRemove_Click(event)" />
</s:BorderContainer>

View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<s:BorderContainer xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
backgroundColor="#F5F5F5" borderColor="#CCCCCC"
borderColor.Error="#C50101" backgroundColor.Error="#F3DBDB"
height.Ready="45" height="60" width="100%">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import org.umbraco.desktopmediauploader.events.*;
import org.umbraco.desktopmediauploader.net.*;
import org.umbraco.desktopmediauploader.util.*;
import flash.desktop.*;
import flash.events.*;
import flash.filesystem.*;
import flash.net.*;
import org.osmf.utils.URL;
[Bindable] public var file:FileReference;
[Bindable] public var path:String;
[Bindable] public var uploading:Boolean = false;;
[Bindable] public var uploaded:Boolean = false;
public function get fullPath():String
{
return path + "/" + file.name;
}
protected function btnUploadRemove_Click(event:MouseEvent):void
{
cancel();
}
protected function file_Complete(event:DataEvent):void
{
uploading = false;
var result:String = StringHelper.cleanXmlString(event.data);
var xml:XML = new XML(result);
if (xml.@success == "true")
{
uploaded = true;
dispatchEvent(new Event(Event.COMPLETE));
}
else
{
file_SecurityError(new SecurityErrorEvent(SecurityErrorEvent.SECURITY_ERROR));
}
}
protected function file_Progress(event:ProgressEvent):void
{
dispatchEvent(event);
}
protected function file_HttpError(event:HTTPStatusEvent):void
{
setCurrentState("Error");
dispatchEvent(event);
}
protected function file_IOError(event:IOErrorEvent):void
{
setCurrentState("Error");
dispatchEvent(event);
}
protected function file_SecurityError(event:SecurityErrorEvent):void
{
setCurrentState("Error");
dispatchEvent(event);
}
public function upload():void
{
setCurrentState("Uploading");
uploading = true;
var vars:URLVariables = new URLVariables();
vars.parentNodeId = Model.folderId;
vars.path = path;
var req:URLRequest = DmuRequest.getRequest(DmuRequestAction.UPLOAD, vars);
file.addEventListener(DataEvent.UPLOAD_COMPLETE_DATA, file_Complete);
file.addEventListener(ProgressEvent.PROGRESS, file_Progress);
file.addEventListener(HTTPStatusEvent.HTTP_STATUS, file_HttpError);
file.addEventListener(IOErrorEvent.IO_ERROR, file_IOError);
file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, file_SecurityError);
file.upload(req);
}
public function pause():void
{
if (uploading)
file.cancel();
uploading = false;
}
public function cancel():void
{
pause();
dispatchEvent(new Event(Event.CANCEL));
}
private function trim( s:String ):String
{
return s.replace( /^([\s|\t|\n]+)?(.*)([\s|\t|\n]+)?$/gm, "$2" );
}
]]>
</fx:Script>
<s:states>
<s:State name="Ready"/>
<s:State name="Uploading"/>
<s:State name="Error"/>
</s:states>
<mx:Image top="6" left="5" source="@Embed('assets/page.png')"/>
<mx:Label id="lblUploadName" text="{file.name}" fontWeight="bold" color="#000000" left="40" top="4" truncateToFit="true" minWidth="0" right="35" />
<s:Button id="btnUploadRemove" width="16" height="16" top="5" right="5" useHandCursor="true" buttonMode="true" click="btnUploadRemove_Click(event)" styleName="removeButton" />
<mx:ProgressBar id="pbUploadProgress" labelPlacement="top" label="" source="{file}" bottom="5" left="5" right="5" excludeFrom="Ready" />
<mx:Label id="lblUploadPath" left="40" top="20" right="35" fontSize="11" color="#CCCCCC" truncateToFit="true" minWidth="0" fontAntiAliasType="advanced" fontGridFitType="pixel" fontThickness="200" fontSharpness="400"
htmlText="&lt;font color='#666666'&gt;{Model.folderPath.replace(/\//g, ' ')}&lt;/font&gt;{path.replace(/\//g, ' ')}"/>
</s:BorderContainer>

View File

@@ -0,0 +1,19 @@
package org.umbraco.desktopmediauploader.events
{
import flash.events.Event;
public class DmuRequestEvent extends Event
{
public static const SUCCESS:String = "success";
public static const ERROR:String = "error";
public var result:XML;
public function DmuRequestEvent(type:String, result:XML = null, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
this.result = result;
}
}
}

View File

@@ -0,0 +1,18 @@
package org.umbraco.desktopmediauploader.events
{
import flash.events.Event;
public class SignedInEvent extends Event
{
public static const SIGNED_IN:String = "signedIn";
public function SignedInEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
override public function clone():Event {
return new SignedInEvent(type, bubbles, cancelable);
}
}
}

View File

@@ -0,0 +1,18 @@
package org.umbraco.desktopmediauploader.events
{
import flash.events.Event;
public class SignedOutEvent extends Event
{
public static const SIGNED_OUT:String = "signedOut";
public function SignedOutEvent(type:String, bubbles:Boolean=false, cancelable:Boolean=false)
{
super(type, bubbles, cancelable);
}
override public function clone():Event {
return new SignedOutEvent(type, bubbles, cancelable);
}
}
}

View File

@@ -0,0 +1,77 @@
package org.umbraco.desktopmediauploader.net
{
import org.umbraco.desktopmediauploader.events.*;
import org.umbraco.desktopmediauploader.util.*;
import flash.events.*;
import flash.net.*;
public class DmuRequest extends EventDispatcher
{
public function DmuRequest(action:String, vars:URLVariables = null, target:IEventDispatcher = null)
{
super(target);
var req:URLRequest = getRequest(action, vars);
var loader:URLLoader = new URLLoader();
loader.addEventListener(Event.COMPLETE, loader_Success);
loader.addEventListener(IOErrorEvent.IO_ERROR, loader_Error);
loader.load(req);
}
private function loader_Success(event:Event):void
{
var loader:URLLoader = event.target as URLLoader;
if (loader != null)
{
var result:String = StringHelper.cleanXmlString(loader.data);
var xml:XML = new XML(result);
if (xml.@success == "true")
{
dispatchEvent(new DmuRequestEvent(DmuRequestEvent.SUCCESS, xml));
}
else
{
loader_Error();
}
}
else
{
loader_Error();
}
}
private function loader_Error(event:IOErrorEvent = null):void
{
dispatchEvent(new DmuRequestEvent(DmuRequestEvent.ERROR));
}
public static function getRequest(action:String, vars:URLVariables = null):URLRequest
{
var loaderUrl:String = Model.url +"/umbraco/webservices/mediauploader.ashx";
if (vars == null)
vars = new URLVariables();
vars.action = action;
vars.username = Model.username;
vars.password = Model.password;
vars.ticket = Model.ticket;
var req:URLRequest = new URLRequest(loaderUrl);
req.data = vars;
req.method = URLRequestMethod.POST;
return req;
}
public static function makeRequest(action:String, successCallback:Function, errorCallback:Function,
vars:URLVariables = null):void
{
var req:DmuRequest = new DmuRequest(action, vars);
req.addEventListener(DmuRequestEvent.SUCCESS, successCallback);
req.addEventListener(DmuRequestEvent.ERROR, errorCallback);
}
}
}

View File

@@ -0,0 +1,9 @@
package org.umbraco.desktopmediauploader.net
{
public class DmuRequestAction
{
public static var CONFIG:String = "config";
public static var FOLDER_LIST:String = "folderList";
public static var UPLOAD:String = "upload";
}
}

View File

@@ -0,0 +1,85 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- http://blog.flexexamples.com/2009/03/13/setting-a-linear-gradient-background-on-an-fxapplication-container-in-flex-gumbo/ -->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
alpha.disabled="0.5"
alpha.disabledWithControlBar="0.5">
<s:states>
<s:State name="normal" />
<s:State name="disabled" />
<s:State name="normalWithControlBar" />
<s:State name="disabledWithControlBar" />
<s:State name="normalAndInactive" />
</s:states>
<fx:Metadata>
<![CDATA[
[HostComponent("spark.components.Application")]
]]>
</fx:Metadata>
<!-- fill -->
<!---
A rectangle with a solid color fill that forms the background of the application.
The color of the fill is set to the Application's backgroundColor property.
-->
<s:Rect id="backgroundRect" left="0" right="0" top="0" bottom="0" >
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="#cccccc" />
<s:GradientEntry color="#eeeeee" ratio="0.2" />
<s:GradientEntry color="#ffffff" ratio="0.8" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<s:Group left="0" right="0" top="0" bottom="0">
<s:layout>
<s:VerticalLayout gap="0" horizontalAlign="justify" />
</s:layout>
<s:Group id="topGroup" minWidth="0" minHeight="0"
includeIn="normalWithControlBar, disabledWithControlBar" >
<!-- layer 0: control bar highlight -->
<s:Rect left="0" right="0" top="0" bottom="1" >
<s:stroke>
<s:LinearGradientStroke rotation="90" weight="1">
<s:GradientEntry color="0xFFFFFF" />
<s:GradientEntry color="0xD8D8D8" />
</s:LinearGradientStroke>
</s:stroke>
</s:Rect>
<!-- layer 1: control bar fill -->
<s:Rect left="1" right="1" top="1" bottom="2" >
<s:fill>
<s:LinearGradient rotation="90">
<s:GradientEntry color="0xEDEDED" />
<s:GradientEntry color="0xCDCDCD" />
</s:LinearGradient>
</s:fill>
</s:Rect>
<!-- layer 2: control bar divider line -->
<s:Rect left="0" right="0" bottom="0" height="1" alpha="0.55">
<s:fill>
<s:SolidColor color="0x000000" />
</s:fill>
</s:Rect>
<!-- layer 3: control bar -->
<s:Group id="controlBarGroup" left="0" right="0" top="1" bottom="1" minWidth="0" minHeight="0">
<s:layout>
<s:HorizontalLayout paddingLeft="10" paddingRight="10" paddingTop="7" paddingBottom="7" gap="10" />
</s:layout>
</s:Group>
</s:Group>
<s:Group id="contentGroup" width="100%" height="100%" minWidth="0" minHeight="0" />
</s:Group>
</s:Skin>

View File

@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
ADOBE SYSTEMS INCORPORATED
Copyright 2009 Adobe Systems Incorporated
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file
in accordance with the terms of the license agreement accompanying it.
-->
<!--- The default skin class for a Spark DefaultItemRenderer class.
@langversion 3.0
@playerversion Flash 10
@playerversion AIR 1.5
@productversion Flex 4
-->
<s:ItemRenderer focusEnabled="false" xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" useHandCursor="true" buttonMode="true">
<s:states>
<s:State name="normal" />
<s:State name="hovered" />
<s:State name="selected" />
<s:State name="normalAndShowsCaret"/>
<s:State name="hoveredAndShowsCaret"/>
<s:State name="selectedAndShowsCaret"/>
</s:states>
<s:Rect left="0" right="0" top="0" bottom="0">
<s:stroke.normalAndShowsCaret>
<s:SolidColorStroke
color="{getStyle('selectionColor')}"
weight="1"/>
</s:stroke.normalAndShowsCaret>
<s:stroke.hoveredAndShowsCaret>
<s:SolidColorStroke
color="{getStyle('selectionColor')}"
weight="1"/>
</s:stroke.hoveredAndShowsCaret>
<s:stroke.selectedAndShowsCaret>
<s:SolidColorStroke
color="{getStyle('selectionColor')}"
weight="1"/>
</s:stroke.selectedAndShowsCaret>
<s:fill>
<s:SolidColor
color.normal="0x9a9a9a"
color.normalAndShowsCaret="0x9a9a9a"
color.hovered="{getStyle('rollOverColor')}"
color.hoveredAndShowsCaret="{getStyle('rollOverColor')}"
color.selected="{getStyle('selectionColor')}"
color.selectedAndShowsCaret="{getStyle('selectionColor')}"
/>
</s:fill>
</s:Rect>
<s:Label id="labelDisplay" verticalCenter="0" left="5" right="5" top="6" bottom="4"/>
</s:ItemRenderer>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
ADOBE SYSTEMS INCORPORATED
Copyright 2009 Adobe Systems Incorporated
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file
in accordance with the terms of the license agreement accompanying it.
-->
<!--- The default skin class for the anchor button on a Spark DropDownList component.
@see spark.components.DropDownList
@see spark.skins.spark.DropDownListSkin
@langversion 3.0
@playerversion Flash 10
@playerversion AIR 1.5
@productversion Flex 4
-->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009" minWidth="21" minHeight="21">
<fx:Metadata>
<![CDATA[
/**
* @copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.Button")]
]]>
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<!-- Layer 2: innerFill -->
<s:Rect id="innerFill" left="0" right="0" top="0" bottom="0" radiusX="0">
<s:fill>
<s:SolidColor color="0x9a9a9a" color.up="0x8a8a8a" />
</s:fill>
</s:Rect>
<!-- layer 8: arrow -->
<!--- The arrow graphic displayed in the anchor button. -->
<s:Path right="6" verticalCenter="0" id="arrow"
data="M 7.03 0.5 C 7.43 0.9 7.43 1.55 7.03 1.95 L 4.64 4.34 C 4.24 4.74 3.59 4.74 3.19 4.34 L 0.8 1.95 C 0.4 1.55 0.4 0.9 0.8 0.5 L 7.03 0.5 Z">
<s:fill>
<s:SolidColor color="0xFFFFFF" />
</s:fill>
</s:Path>
</s:Skin>

View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
ADOBE SYSTEMS INCORPORATED
Copyright 2009 Adobe Systems Incorporated
All Rights Reserved.
NOTICE: Adobe permits you to use, modify, and distribute this file
in accordance with the terms of the license agreement accompanying it.
-->
<!--- The default skin class for the Spark DropDownList component.
The skin for the anchor button for a DropDownList component
is defined by the DropDownListButtonSkin class.
@see spark.components.DropDownList
@see spark.skins.spark.DropDownListButtonSkin
@langversion 3.0
@playerversion Flash 10
@playerversion AIR 1.5
@productversion Flex 4
-->
<s:Skin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009" alpha.disabled=".5">
<!-- host component -->
<fx:Metadata>
<![CDATA[
/**
* @copy spark.skins.spark.ApplicationSkin#hostComponent
*/
[HostComponent("spark.components.DropDownList")]
]]>
</fx:Metadata>
<s:states>
<s:State name="normal" />
<s:State name="open" />
<s:State name="disabled" />
</s:states>
<!---
The PopUpAnchor control that opens the drop-down list.
-->
<s:PopUpAnchor id="popUp" displayPopUp.normal="false" displayPopUp.open="true" includeIn="open"
left="0" right="0" top="0" bottom="0" itemDestructionPolicy="auto"
popUpPosition="below" popUpWidthMatchesAnchorWidth="true">
<!---
The drop down area of the skin.
This includes borders, background colors, scrollers, and filters.
-->
<s:Group id="dropDown" maxHeight="134" >
<!-- fill -->
<!---
Defines the appearance of drop-down list's background fill.
-->
<s:Rect id="background" left="0" right="0" top="0" bottom="0" >
<s:fill>
<!---
The color of the drop down's background fill.
The default color is 0xFFFFFF.
-->
<s:SolidColor id="bgFill" color="0x9a9a9a" />
</s:fill>
</s:Rect>
<s:Scroller id="scroller" left="0" top="0" right="0" bottom="0" hasFocusableChildren="false" minViewportInset="1">
<!---
The container for the data items in the drop-down list.
-->
<s:DataGroup id="dataGroup" itemRenderer="org.umbraco.desktopmediauploader.skins.DefaultItemRenderer">
<s:layout>
<s:VerticalLayout gap="0" horizontalAlign="contentJustify"/>
</s:layout>
</s:DataGroup>
</s:Scroller>
</s:Group>
</s:PopUpAnchor>
<!--- The anchor button used by the DropDownList. The default skin is DropDownListButtonSkin. -->
<s:Button id="openButton" left="0" right="0" top="0" bottom="0" focusEnabled="false"
skinClass="org.umbraco.desktopmediauploader.skins.HeaderDropDownListButtonSkin" />
<!--- The prompt area of the DropDownList. -->
<s:Label id="labelDisplay" verticalAlign="middle" maxDisplayedLines="1"
mouseEnabled="false" mouseChildren="false"
left="5" right="20" top="2" bottom="2" width="75" verticalCenter="1" />
</s:Skin>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="21" minHeight="21" alpha.disabled="0.5">
<!-- host component -->
<fx:Metadata>
<![CDATA[
[HostComponent("spark.components.Button")]
]]>
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<mx:Image source="@Embed('assets/cross-grey.png')"
source.over="@Embed('assets/cross.png')"
/>
</s:SparkSkin>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<s:SparkSkin xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:fb="http://ns.adobe.com/flashbuilder/2009"
xmlns:mx="library://ns.adobe.com/flex/mx"
minWidth="21" minHeight="21" alpha.disabled="0.5">
<!-- host component -->
<fx:Metadata>
<![CDATA[
[HostComponent("spark.components.Button")]
]]>
</fx:Metadata>
<!-- states -->
<s:states>
<s:State name="up" />
<s:State name="over" />
<s:State name="down" />
<s:State name="disabled" />
</s:states>
<mx:Image source="@Embed('assets/power.png')"
source.over="@Embed('assets/power-over.png')"
/>
</s:SparkSkin>

View File

@@ -0,0 +1,176 @@
package org.umbraco.desktopmediauploader.util
{
import flash.utils.ByteArray;
public class Base64
{
private static const _encodeChars:Vector.<int> = InitEncoreChar();
private static const _decodeChars:Vector.<int> = InitDecodeChar();
public static function encode(data:ByteArray):String
{
var out:ByteArray = new ByteArray();
//Presetting the length keep the memory smaller and optimize speed since there is no "grow" needed
out.length = (2 + data.length - ((data.length + 2) % 3)) * 4 / 3; //Preset length //1.6 to 1.5 ms
var i:int = 0;
var r:int = data.length % 3;
var len:int = data.length - r;
var c:int; //read (3) character AND write (4) characters
while (i < len)
{
//Read 3 Characters (8bit * 3 = 24 bits)
c = data[i++] << 16 | data[i++] << 8 | data[i++];
//Cannot optimize this to read int because of the positioning overhead. (as3 bytearray seek is slow)
//Convert to 4 Characters (6 bit * 4 = 24 bits)
c = (_encodeChars[c >>> 18] << 24) | (_encodeChars[c >>> 12 & 0x3f] << 16) | (_encodeChars[c >>> 6 & 0x3f] << 8 ) | _encodeChars[c & 0x3f];
//Optimization: On older and slower computer, do one write Int instead of 4 write byte: 1.5 to 0.71 ms
out.writeInt(c);
/*
out.writeByte(_encodeChars[c >> 18] );
out.writeByte(_encodeChars[c >> 12 & 0x3f]);
out.writeByte(_encodeChars[c >> 6 & 0x3f]);
out.writeByte(_encodeChars[c & 0x3f]);
*/
}
if (r == 1) //Need two "=" padding
{
//Read one char, write two chars, write padding
c = data[i];
c = (_encodeChars[c >>> 2] << 24) | (_encodeChars[(c & 0x03) << 4] << 16) | 61 << 8 | 61;
out.writeInt(c);
}
else if (r == 2) //Need one "=" padding
{
c = data[i++] << 8 | data[i];
c = (_encodeChars[c >>> 10] << 24) | (_encodeChars[c >>> 4 & 0x3f] << 16) | (_encodeChars[(c & 0x0f) << 2] << 8 ) | 61;
out.writeInt(c);
}
out.position = 0;
return out.readUTFBytes(out.length);
}
public static function decode(str:String):ByteArray
{
var c1:int;
var c2:int;
var c3:int;
var c4:int;
var i:int;
var len:int;
var out:ByteArray;
len = str.length;
i = 0;
out = new ByteArray();
var byteString:ByteArray = new ByteArray();
byteString.writeUTFBytes(str);
while (i < len)
{
//c1
do
{
c1 = _decodeChars[byteString[i++]];
} while (i < len && c1 == -1);
if (c1 == -1) break;
//c2
do
{
c2 = _decodeChars[byteString[i++]];
} while (i < len && c2 == -1);
if (c2 == -1) break;
out.writeByte((c1 << 2) | ((c2 & 0x30) >> 4));
//c3
do
{
c3 = byteString[i++];
if (c3 == 61) return out;
c3 = _decodeChars[c3];
} while (i < len && c3 == -1);
if (c3 == -1) break;
out.writeByte(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2));
//c4
do {
c4 = byteString[i++];
if (c4 == 61) return out;
c4 = _decodeChars[c4];
} while (i < len && c4 == -1);
if (c4 == -1) break;
out.writeByte(((c3 & 0x03) << 6) | c4);
}
return out;
}
public static function encodeString(value : String) : String
{
const source : ByteArray = new ByteArray();
source.writeUTFBytes(value);
return encode(source);
}
public static function decodeToString(str : String) : String
{
return decode(str).toString();
}
public static function InitEncoreChar() : Vector.<int>
{
var encodeChars:Vector.<int> = new Vector.<int>();
// We could push the number directly, but i think it's nice to see the characters (with no overhead on encode/decode)
var chars:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (var i:int = 0; i < 64; i++)
{
encodeChars.push(chars.charCodeAt(i));
}
/*
encodeChars.push(
65, 66, 67, 68, 69, 70, 71, 72,
73, 74, 75, 76, 77, 78, 79, 80,
81, 82, 83, 84, 85, 86, 87, 88,
89, 90, 97, 98, 99, 100, 101, 102,
103, 104, 105, 106, 107, 108, 109, 110,
111, 112, 113, 114, 115, 116, 117, 118,
119, 120, 121, 122, 48, 49, 50, 51,
52, 53, 54, 55, 56, 57, 43, 47);
*/
return encodeChars;
}
public static function InitDecodeChar() : Vector.<int>
{
var decodeChars:Vector.<int> = new Vector.<int>();
decodeChars.push(-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1);
return decodeChars;
}
}
}

View File

@@ -0,0 +1,47 @@
package org.umbraco.desktopmediauploader.util
{
import flash.display.Stage;
import flash.events.Event;
public class StageHelper
{
private static var _stage:Stage;
private static var _resizeListenerSet:Boolean = false;
[Bindable]
public static var stageWidth:int = 0;
[Bindable]
public static var stageHeight:int = 0;
public function StageHelper()
{ }
public static function set stage(value:Stage):void
{
_stage = value;
addResizeListener();
stage_resize();
}
private static function addResizeListener():void
{
if (_resizeListenerSet)
return;
if(!_stage)
return;
_stage.addEventListener(Event.RESIZE, stage_resize);
_resizeListenerSet = true;
}
private static function stage_resize(e:Event = null):void
{
stageWidth = _stage.stageWidth;
stageHeight = _stage.stageHeight;
}
}
}

View File

@@ -0,0 +1,16 @@
package org.umbraco.desktopmediauploader.util
{
import mx.utils.*;
public class StringHelper
{
public static function cleanXmlString(str:String):String
{
// Remove any Byte Order Markers
str = str.replace(String.fromCharCode(65279), "");
// Trim whitespace
return StringUtil.trim(str);
}
}
}

View File

@@ -0,0 +1,206 @@
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
width="100%" height="100%"
show="vwSignIn_ShowHandler(event);">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import org.umbraco.desktopmediauploader.events.*;
import org.umbraco.desktopmediauploader.net.*;
import org.umbraco.desktopmediauploader.util.*;
import mx.controls.Alert;
import mx.managers.*;
import mx.events.FlexEvent;
public function init():void
{
NativeApplication.nativeApplication.addEventListener(BrowserInvokeEvent.BROWSER_INVOKE, app_BrowserInvoke);
reset();
if(chkAutoSignIn.selected)
{
doSignIn();
}
}
protected function vwSignIn_ShowHandler(event:FlexEvent):void
{
reset();
}
protected function app_BrowserInvoke(e:BrowserInvokeEvent):void
{
var encLaunchArg:String = unescape(e.arguments[0]);
var launchArg:String = Base64.decodeToString(encLaunchArg);
var launchArgs:Array = launchArg.split(";");
Model.url = parseUrl(launchArgs[0]);
Model.username = launchArgs[1];
Model.password = "";
Model.ticket = launchArgs[2];
// Ok, time to hit the server
CursorManager.setBusyCursor();
this.enabled = false;
// Authenticate credentials
// NB: As every request authenticates anyway, just load config
// and if it fails, assume login was invalid
DmuRequest.makeRequest(DmuRequestAction.CONFIG,
configRequest_Success,
configRequest_Error);
}
protected function reset():void
{
chkRememberMe.selected = (getEncryptedValue("dmu_rememberme") == "true");
chkRememberPassword.selected = (getEncryptedValue("dmu_rememberpassword") == "true");
chkAutoSignIn.selected = (getEncryptedValue("dmu_autosignin") == "true");
if (chkRememberMe.selected)
{
txtUrl.text = getEncryptedValue("dmu_url");
txtUsername.text = getEncryptedValue("dmu_username");
if (chkRememberPassword.selected)
{
txtPassword.text = getEncryptedValue("dmu_password");
}
}
}
protected function txtPassword_Enter(event:Event):void
{
doSignIn();
}
protected function btnSignIn_clickHandler(event:MouseEvent=null):void
{
doSignIn();
}
protected function configRequest_Success(event:DmuRequestEvent):void
{
this.enabled = true;
CursorManager.removeBusyCursor();
var xml:XML = event.result;
// Store config
Model.displayName = xml.displayName;
Model.umbracoPath = xml.umbracoPath;
Model.maxRequestLength = Number(xml.maxRequestLength);
// Remember login
if(!Model.ticket || Model.ticket == "")
{
setEncryptedValue("dmu_url", (chkRememberMe.selected)? Model.url : null);
setEncryptedValue("dmu_username", (chkRememberMe.selected)? Model.username : null);
setEncryptedValue("dmu_password", (chkRememberMe.selected && chkRememberPassword.selected) ? Model.password : null);
setEncryptedValue("dmu_rememberme", chkRememberMe.selected.toString());
setEncryptedValue("dmu_rememberpassword", chkRememberPassword.selected.toString());
setEncryptedValue("dmu_autosignin", chkAutoSignIn.selected.toString());
}
dispatchEvent(new SignedInEvent(SignedInEvent.SIGNED_IN));
}
protected function configRequest_Error(event:Event):void
{
this.enabled = true;
CursorManager.removeBusyCursor();
Alert.show("Invalid login", "Ooops!");
}
private function doSignIn():void
{
Model.url = parseUrl(txtUrl.text);
Model.username = txtUsername.text;
Model.password = txtPassword.text;
Model.ticket = "";
// Ok, time to hit the server
CursorManager.setBusyCursor();
this.enabled = false;
// Authenticate credentials
// NB: As every request authenticates anyway, just load config
// and if it fails, assume login was invalid
DmuRequest.makeRequest(DmuRequestAction.CONFIG,
configRequest_Success,
configRequest_Error);
}
private function parseUrl(url:String):String
{
var urlPattern:RegExp = /^((?P<scheme>https?):\/\/)(?P<hostname>[^:\/\s]+)(?P<port>:([^\/]*))?((?P<path>(\/\w+)*\/)(?P<filename>[-\w.]+[^#?\s]*)?(?P<query>\?([^#]*))?(?P<fragment>#(.*))?)?$/gi;
var result:Array = urlPattern.exec(url.toLowerCase());
if (result != null && result.length > 0)
{
var parsedUrl:String = result.scheme + "://" + result.hostname + result.port + result.path + result.filename;
while(parsedUrl.substr(parsedUrl.length - 1) == "/")
{
parsedUrl = parsedUrl.substr(0, parsedUrl.length - 1);
}
return parsedUrl;
}
return url;
}
private function setEncryptedValue(key:String, value:String):void
{
if (value != null)
{
var data:ByteArray = new ByteArray();
data.writeUTFBytes(value);
EncryptedLocalStore.setItem(key, data);
}
else
{
EncryptedLocalStore.removeItem(key);
}
}
private function getEncryptedValue(key:String):String
{
var data:ByteArray = EncryptedLocalStore.getItem(key);
return (data != null) ? data.readUTFBytes(data.length) : null;
}
]]>
</fx:Script>
<fx:Metadata>
[Event(name="signedIn", type="org.umbraco.desktopmediauploader.events.SignedInEvent")]
</fx:Metadata>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
<mx:Image horizontalCenter="0" source="@Embed('assets/logo.png')" verticalCenter="-145"/>
<s:VGroup id="grpSignInForm" height="200" bottom="105" left="25" right="25">
<s:Label text="URL" fontWeight="bold"/>
<s:TextInput width="100%" id="txtUrl" text="@{Model.url}"/>
<s:Label text="Username" fontWeight="bold"/>
<s:TextInput width="100%" id="txtUsername" text="@{Model.username}"/>
<s:Label text="Password" fontWeight="bold"/>
<s:TextInput width="100%" id="txtPassword" displayAsPassword="true" text="@{Model.password}" enter="txtPassword_Enter(event)" />
<s:CheckBox label="Remember Me" id="chkRememberMe" change="(!chkRememberMe.selected) ? chkRememberPassword.selected = chkAutoSignIn.selected = false : null"/>
<s:CheckBox label="Remember Password" id="chkRememberPassword" enabled="{chkRememberMe.selected}" change="(!chkRememberPassword.selected) ? chkAutoSignIn.selected = false : null"/>
<s:CheckBox label="Sign In Automaticaly" id="chkAutoSignIn" enabled="{chkRememberPassword.selected}"/>
</s:VGroup>
<mx:Button label="Sign In" bottom="25" id="btnSignIn" click="btnSignIn_clickHandler(event)" left="25" right="25" height="35" useHandCursor="true" buttonMode="true" styleName=""/>
</s:Group>

View File

@@ -0,0 +1,330 @@
<?xml version="1.0" encoding="utf-8"?>
<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx"
xmlns:components="org.umbraco.desktopmediauploader.components.*"
width="100%" height="100%"
creationComplete="vwUpload_CreationCompleteHandler(event)"
show="vwUpload_ShowHandler(event);">
<s:layout>
<s:BasicLayout/>
</s:layout>
<fx:Script>
<![CDATA[
import org.umbraco.desktopmediauploader.components.*;
import org.umbraco.desktopmediauploader.events.*;
import org.umbraco.desktopmediauploader.net.*;
import org.umbraco.desktopmediauploader.util.*;
import flash.desktop.*;
import flash.events.*;
import flash.filesystem.File;
import flash.net.*;
import mx.collections.Sort;
import mx.collections.SortField;
import mx.controls.Alert;
import mx.controls.Menu;
import mx.core.ScrollPolicy;
import mx.events.FlexEvent;
import mx.managers.*;
import spark.events.IndexChangeEvent;
[Bindable] public var currentUploadItem:UploadItem;
[Bindable] public var uploadItems:ArrayCollection;
[Bindable] private var uploading:Boolean = false;
protected function vwUpload_CreationCompleteHandler(event:FlexEvent):void
{
uploadItems = new ArrayCollection();
addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER, vwUpload_DragEnter);
addEventListener(NativeDragEvent.NATIVE_DRAG_DROP, vwUpload_DragDrop);
dmuStatus.addEventListener(Event.CANCEL, dmuStatus_Cancel);
}
protected function vwUpload_ShowHandler(event:FlexEvent):void
{
reset();
}
private function vwUpload_DragEnter(e:NativeDragEvent) :void
{
var valid:Boolean = false;
if(e.clipboard.hasFormat(ClipboardFormats.FILE_LIST_FORMAT))
{
// Only allow drop if at least 1 file is valid
var files:Array = e.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
for each (var f:File in files)
{
if (isValidFile(f))
{
valid = true;
break;
}
}
if (valid)
NativeDragManager.acceptDragDrop(this);
}
}
private function vwUpload_DragDrop(e:NativeDragEvent) :void
{
var files:Array = e.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT) as Array;
addFilesToQueue(files);
// Sort alphabeticlly
var sf:SortField = new SortField("fullPath", true);
var s:Sort = new Sort();
s.fields = [sf];
uploadItems.sort = s;
uploadItems.refresh();
for(var i:int = 0; i < uploadItems.length; i++)
{
grpUploadItemContainer.addElement(uploadItems[i]);
}
}
private function reset():void
{
Model.currentFolder = undefined;
Model.folderId = undefined;
Model.folderName = undefined;
Model.folderPath = undefined;
uploading = false;
currentUploadItem == null;
dmuStatus_Cancel();
}
private function isValidFile(file:File, path:String = ""):Boolean
{
var queued:Boolean = false;
var i:int = uploadItems.length;
while(i--)
{
var uploadItem:UploadItem = uploadItems[i] as UploadItem;
if (uploadItem != null && uploadItem.file.name == file.name && uploadItem.path == path && uploadItem.file.size == file.size)
{
queued = true;
break;
}
}
// TODO: Handle .lnk files?
// TODO: What to do with zip files?
return (!file.isSymbolicLink &&
!file.isPackage &&
!file.isHidden &&
!queued &&
file.size <= (Model.maxRequestLength * 1024));
}
private function addFilesToQueue(files:Array, path:String = ""):void
{
for each (var f:File in files)
{
if(f.isDirectory)
{
addFilesToQueue(f.getDirectoryListing(), path + "/" + f.name)
}
else if (isValidFile(f, path))
{
addFileToQueue(FileReference(f), path);
}
}
}
private function addFileToQueue(file:FileReference, path:String):void
{
var uploadItem:UploadItem = new UploadItem();
uploadItem.file = file;
uploadItem.path = path;
uploadItem.addEventListener(Event.COMPLETE, uploadItem_Complete);
uploadItem.addEventListener(Event.CANCEL, uploadItem_Cancel);
uploadItem.addEventListener(HTTPStatusEvent.HTTP_STATUS, uploadItem_Error);
uploadItem.addEventListener(IOErrorEvent.IO_ERROR, uploadItem_Error);
uploadItem.addEventListener(SecurityErrorEvent.SECURITY_ERROR, uploadItem_Error);
grpUploadItemContainer.addElement(uploadItem);
uploadItems.addItem(uploadItem);
}
protected function ddlConnectedTo_Close(e:Event):void
{
var oldIndex:Number = ddlConnectedTo.selectedIndex;
ddlConnectedTo.selectedIndex = -1;
if (oldIndex >= 0)
{
switch(ddlConnectedTo.dataProvider[oldIndex])
{
case "Launch Site":
navigateToURL(new URLRequest(Model.url));
break;
case "Launch Admin":
navigateToURL(new URLRequest(Model.url + Model.umbracoPath + "/"));
break;
}
}
}
protected function btnSignOut_Click(e:Event):void
{
if (uploading)
Alert.show("Unable to sign out whilst uploading files.", "Ooops!");
else
dispatchEvent(new SignedOutEvent(SignedOutEvent.SIGNED_OUT));
}
protected function uploadItem_Complete(e:Event):void
{
uploadItem_Cancel(e);
uploading = false;
currentUploadItem == null;
if (uploadItems.length > 0)
btnUpload_Click();
else
Alert.show("Upload complete.", "Woo hoo!");
}
protected function uploadItem_Cancel(e:Event):void
{
var uploadItem:UploadItem = e.target as UploadItem;
var i:uint = uploadItems.length;
while(i--)
{
var uploadItem2:UploadItem = uploadItems[i] as UploadItem;
if(uploadItem2.file.name == uploadItem.file.name && uploadItem2.path == uploadItem.path)
{
grpUploadItemContainer.removeElement(uploadItem);
uploadItems.removeItemAt(i);
break;
}
}
}
protected function uploadItem_Error(e:Event):void
{
// TODO: Move item to bottom?
}
protected function dmuStatus_Cancel(event:Event = null):void
{
var i:uint = uploadItems.length;
while(i--)
{
uploadItems[i].cancel();
}
}
protected function btnUploadTo_Click(event:MouseEvent):void
{
var win:FolderPickerDialog = PopUpManager.createPopUp(this, FolderPickerDialog, true) as FolderPickerDialog;
PopUpManager.centerPopUp(win);
}
protected function btnUpload_Click(event:MouseEvent = null):void
{
var uploadItem:UploadItem;
var i:int;
if (!uploading)
{
uploading = false;
currentUploadItem = null;
for(i = 0; i < uploadItems.length; i++)
{
uploadItem = uploadItems[i] as UploadItem;
if (!uploadItem.uploaded)
{
currentUploadItem = uploadItem;
currentUploadItem.upload();
uploading = true;
break;
}
}
}
else
{
for(i = 0; i < uploadItems.length; i++)
{
uploadItem = uploadItems[i] as UploadItem;
if (!uploadItem.uploaded)
{
uploadItem.pause();
}
}
uploading = false;
currentUploadItem = null;
}
}
]]>
</fx:Script>
<fx:Metadata>
[Event(name="signedOut", type="org.umbraco.desktopmediauploader.events.SignedOutEvent")]
</fx:Metadata>
<fx:Declarations>
<fx:Array id="uploadMenuItems">
<fx:Object label="Clear Queue" />
<fx:Object type="separator" />
<fx:Object label="Overwrite existing files" type="check" />
<fx:Object label="Auto extract zip files" type="check" />
</fx:Array>
</fx:Declarations>
<s:BorderContainer top="0" left="0" right="0" height="70" styleName="header">
<mx:Image source="@Embed('assets/icon-48.png')" x="10" y="10" />
<mx:Label id="lblName" text="{Model.displayName}" left="64" y="10" right="50" truncateToFit="true" minWidth="0" />
<s:DropDownList id="ddlConnectedTo" prompt="{Model.url}" close="ddlConnectedTo_Close(event)" x="65" y="33" typicalItem="{Model.url}" maxWidth="{StageHelper.stageWidth - 90}" open="ddlConnectedTo.scroller.setStyle('horizontalScrollPolicy', ScrollPolicy.OFF);" useHandCursor="true" buttonMode="true">
<mx:ArrayCollection>
<fx:String>Launch Site</fx:String>
<fx:String>Launch Admin</fx:String>
</mx:ArrayCollection>
</s:DropDownList>
<s:Button id="btnSignOut" width="13" height="15" top="11" right="25" useHandCursor="true" buttonMode="true" styleName="signOutButton" click="btnSignOut_Click(event)" />
</s:BorderContainer>
<s:VGroup top="90" left="25" right="25" gap="5">
<s:Label text="Upload files to..."/>
<s:Button id="btnUploadTo" label="{(Model.folderPath) ? Model.folderPath.replace(/\//g, ' ') : 'Please select...'}" width="100%" click="btnUploadTo_Click(event)" creationComplete="btnUploadTo.labelDisplay.setStyle('textAlign','left')" height="25" useHandCursor="true" buttonMode="true" />
</s:VGroup>
<s:BorderContainer top="150" left="25" right="25" bottom="80" borderColor="#CCCCCC" backgroundColor="#FFFFFF">
<s:Scroller width="100%" height="100%">
<s:Group id="grpUploadItemContainer">
<s:layout>
<s:VerticalLayout paddingLeft="5" paddingRight="5" paddingTop="5" paddingBottom="5" gap="5"/>
</s:layout>
<components:StatusItem id="dmuStatus" visible="{uploadItems.length &gt; 0}" includeInLayout="{uploadItems.length &gt; 0}" totalItems="{uploadItems.length}" />
<s:Label text="Drag Files and Folders Here To Upload" verticalAlign="middle" textAlign="center"
width="100%" height="100%" fontSize="20" color="#CCCCCC" id="lblInstructions"
paddingLeft="20" paddingRight="20" paddingTop="20" paddingBottom="20"
visible="{uploadItems.length == 0}" includeInLayout="{uploadItems.length == 0}"/>
</s:Group>
</s:Scroller>
</s:BorderContainer>
<mx:Button id="btnUpload" label="{!uploading ? 'Upload' : 'Cancel'}" useHandCursor="{btnUpload.enabled}" buttonMode="{btnUpload.enabled}" bottom="25" enabled="{uploadItems.length > 0 &amp;&amp; Model.folderId}" styleName="orange" height="35" left="25" right="25" click="btnUpload_Click(event)"/>
</s:Group>