diff --git a/components/DesktopMediaUploader/.actionScriptProperties b/components/DesktopMediaUploader/.actionScriptProperties new file mode 100644 index 0000000000..8953c4fad6 --- /dev/null +++ b/components/DesktopMediaUploader/.actionScriptProperties @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/.flexProperties b/components/DesktopMediaUploader/.flexProperties new file mode 100644 index 0000000000..0f603b0c3e --- /dev/null +++ b/components/DesktopMediaUploader/.flexProperties @@ -0,0 +1,2 @@ + + diff --git a/components/DesktopMediaUploader/.project b/components/DesktopMediaUploader/.project new file mode 100644 index 0000000000..a099199c4b --- /dev/null +++ b/components/DesktopMediaUploader/.project @@ -0,0 +1,24 @@ + + + DesktopMediaUploader + + + + + + com.adobe.flexbuilder.project.flexbuilder + + + + + com.adobe.flexbuilder.project.apollobuilder + + + + + + com.adobe.flexbuilder.project.apollonature + com.adobe.flexbuilder.project.flexnature + com.adobe.flexbuilder.project.actionscriptnature + + diff --git a/components/DesktopMediaUploader/.settings/org.eclipse.core.resources.prefs b/components/DesktopMediaUploader/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000000..b572705183 --- /dev/null +++ b/components/DesktopMediaUploader/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +#Tue Jul 20 11:35:49 BST 2010 +eclipse.preferences.version=1 +encoding/=utf-8 diff --git a/components/DesktopMediaUploader/dc/DesktopMediaUploader.p12 b/components/DesktopMediaUploader/dc/DesktopMediaUploader.p12 new file mode 100644 index 0000000000..b4f4eae0c0 Binary files /dev/null and b/components/DesktopMediaUploader/dc/DesktopMediaUploader.p12 differ diff --git a/components/DesktopMediaUploader/src/DesktopMediaUploader-app.xml b/components/DesktopMediaUploader/src/DesktopMediaUploader-app.xml new file mode 100644 index 0000000000..0ce82e6192 --- /dev/null +++ b/components/DesktopMediaUploader/src/DesktopMediaUploader-app.xml @@ -0,0 +1,154 @@ + + + + + + + org.umbraco.DesktopMediaUploader + + + Desktop Media Uploader + + + Desktop Media Uploader + + + v2.1.0 + + + + This application allows you to upload media to an Umbraco website directly from your desktop. + + + + 2010 Umbraco.org + + + + + + + + + DesktopMediaUploader.swf + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + assets/icon-16.png + + assets/icon-32.png + + assets/icon-48.png + + assets/icon-128.png + + + + + + + + true + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/DesktopMediaUploader.css b/components/DesktopMediaUploader/src/DesktopMediaUploader.css new file mode 100644 index 0000000000..8b71dd6de0 --- /dev/null +++ b/components/DesktopMediaUploader/src/DesktopMediaUploader.css @@ -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'); +} diff --git a/components/DesktopMediaUploader/src/DesktopMediaUploader.mxml b/components/DesktopMediaUploader/src/DesktopMediaUploader.mxml new file mode 100644 index 0000000000..9d10d7f53e --- /dev/null +++ b/components/DesktopMediaUploader/src/DesktopMediaUploader.mxml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/Model.as b/components/DesktopMediaUploader/src/Model.as new file mode 100644 index 0000000000..133aef3404 --- /dev/null +++ b/components/DesktopMediaUploader/src/Model.as @@ -0,0 +1,21 @@ +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 = ""; + [Bindable] public static var replaceExisting:Boolean = false; + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/assets/badge.psd b/components/DesktopMediaUploader/src/assets/badge.psd new file mode 100644 index 0000000000..682d83c68c Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/badge.psd differ diff --git a/components/DesktopMediaUploader/src/assets/cross-grey.png b/components/DesktopMediaUploader/src/assets/cross-grey.png new file mode 100644 index 0000000000..212e51435c Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/cross-grey.png differ diff --git a/components/DesktopMediaUploader/src/assets/cross.png b/components/DesktopMediaUploader/src/assets/cross.png new file mode 100644 index 0000000000..1514d51a3c Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/cross.png differ diff --git a/components/DesktopMediaUploader/src/assets/dmu_orange.fla b/components/DesktopMediaUploader/src/assets/dmu_orange.fla new file mode 100644 index 0000000000..aa4bb6a083 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/dmu_orange.fla differ diff --git a/components/DesktopMediaUploader/src/assets/dmu_orange.swf b/components/DesktopMediaUploader/src/assets/dmu_orange.swf new file mode 100644 index 0000000000..ab9833db43 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/dmu_orange.swf differ diff --git a/components/DesktopMediaUploader/src/assets/folder-open.png b/components/DesktopMediaUploader/src/assets/folder-open.png new file mode 100644 index 0000000000..48e012cec4 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/folder-open.png differ diff --git a/components/DesktopMediaUploader/src/assets/folder.png b/components/DesktopMediaUploader/src/assets/folder.png new file mode 100644 index 0000000000..5d856b09c8 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/folder.png differ diff --git a/components/DesktopMediaUploader/src/assets/icon-128-old.png b/components/DesktopMediaUploader/src/assets/icon-128-old.png new file mode 100644 index 0000000000..e0ca8e6f46 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/icon-128-old.png differ diff --git a/components/DesktopMediaUploader/src/assets/icon-128.png b/components/DesktopMediaUploader/src/assets/icon-128.png new file mode 100644 index 0000000000..69d8e81372 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/icon-128.png differ diff --git a/components/DesktopMediaUploader/src/assets/icon-128.psd b/components/DesktopMediaUploader/src/assets/icon-128.psd new file mode 100644 index 0000000000..dd14d7e45b Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/icon-128.psd differ diff --git a/components/DesktopMediaUploader/src/assets/icon-16.png b/components/DesktopMediaUploader/src/assets/icon-16.png new file mode 100644 index 0000000000..ae5203f94d Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/icon-16.png differ diff --git a/components/DesktopMediaUploader/src/assets/icon-32.png b/components/DesktopMediaUploader/src/assets/icon-32.png new file mode 100644 index 0000000000..dd5dfabd22 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/icon-32.png differ diff --git a/components/DesktopMediaUploader/src/assets/icon-48.png b/components/DesktopMediaUploader/src/assets/icon-48.png new file mode 100644 index 0000000000..1af5900369 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/icon-48.png differ diff --git a/components/DesktopMediaUploader/src/assets/information.png b/components/DesktopMediaUploader/src/assets/information.png new file mode 100644 index 0000000000..12cd1aef90 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/information.png differ diff --git a/components/DesktopMediaUploader/src/assets/logo.png b/components/DesktopMediaUploader/src/assets/logo.png new file mode 100644 index 0000000000..88238558bc Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/logo.png differ diff --git a/components/DesktopMediaUploader/src/assets/logo.psd b/components/DesktopMediaUploader/src/assets/logo.psd new file mode 100644 index 0000000000..b5941d0280 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/logo.psd differ diff --git a/components/DesktopMediaUploader/src/assets/page.png b/components/DesktopMediaUploader/src/assets/page.png new file mode 100644 index 0000000000..cf3fc49b8c Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/page.png differ diff --git a/components/DesktopMediaUploader/src/assets/power-over.png b/components/DesktopMediaUploader/src/assets/power-over.png new file mode 100644 index 0000000000..1c5771552f Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/power-over.png differ diff --git a/components/DesktopMediaUploader/src/assets/power.png b/components/DesktopMediaUploader/src/assets/power.png new file mode 100644 index 0000000000..5ccf098b04 Binary files /dev/null and b/components/DesktopMediaUploader/src/assets/power.png differ diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/FolderPickerDialog.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/FolderPickerDialog.mxml new file mode 100644 index 0000000000..30808b282b --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/FolderPickerDialog.mxml @@ -0,0 +1,122 @@ + + + + + + + + 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()); + } + } + + ]]> + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/StatusItem.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/StatusItem.mxml new file mode 100644 index 0000000000..1097604501 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/StatusItem.mxml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/UploadItem.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/UploadItem.mxml new file mode 100644 index 0000000000..ff6b81c7ca --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/components/UploadItem.mxml @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/DmuRequestEvent.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/DmuRequestEvent.as new file mode 100644 index 0000000000..d8103e58f8 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/DmuRequestEvent.as @@ -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; + } + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/SignedInEvent.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/SignedInEvent.as new file mode 100644 index 0000000000..5f622afb2d --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/SignedInEvent.as @@ -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); + } + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/SignedOutEvent.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/SignedOutEvent.as new file mode 100644 index 0000000000..933e6e90a3 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/events/SignedOutEvent.as @@ -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); + } + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/net/DmuRequest.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/net/DmuRequest.as new file mode 100644 index 0000000000..20432e2b44 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/net/DmuRequest.as @@ -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); + } + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/net/DmuRequestAction.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/net/DmuRequestAction.as new file mode 100644 index 0000000000..a13f8dc070 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/net/DmuRequestAction.as @@ -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"; + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/ApplicationSkin.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/ApplicationSkin.mxml new file mode 100644 index 0000000000..009687019f --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/ApplicationSkin.mxml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/DefaultItemRenderer.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/DefaultItemRenderer.mxml new file mode 100644 index 0000000000..f4ddde3463 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/DefaultItemRenderer.mxml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/HeaderDropDownListButtonSkin.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/HeaderDropDownListButtonSkin.mxml new file mode 100644 index 0000000000..2f3f498141 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/HeaderDropDownListButtonSkin.mxml @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/HeaderDropDownListSkin.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/HeaderDropDownListSkin.mxml new file mode 100644 index 0000000000..f79e79a59b --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/HeaderDropDownListSkin.mxml @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/RemoveButtonSkin.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/RemoveButtonSkin.mxml new file mode 100644 index 0000000000..159ff5cc09 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/RemoveButtonSkin.mxml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/SignOutButtonSkin.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/SignOutButtonSkin.mxml new file mode 100644 index 0000000000..d4a75b2bcd --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/skins/SignOutButtonSkin.mxml @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/Base64.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/Base64.as new file mode 100644 index 0000000000..1135a8439d --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/Base64.as @@ -0,0 +1,176 @@ +package org.umbraco.desktopmediauploader.util +{ + import flash.utils.ByteArray; + + public class Base64 + { + private static const _encodeChars:Vector. = InitEncoreChar(); + private static const _decodeChars:Vector. = 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. + { + var encodeChars:Vector. = new Vector.(); + + // 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. + { + var decodeChars:Vector. = new Vector.(); + + 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; + } + } + +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/StageHelper.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/StageHelper.as new file mode 100644 index 0000000000..27a71831ef --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/StageHelper.as @@ -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; + } + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/StringHelper.as b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/StringHelper.as new file mode 100644 index 0000000000..c6e2ace3df --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/util/StringHelper.as @@ -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); + } + } +} \ No newline at end of file diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/views/SignInView.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/views/SignInView.mxml new file mode 100644 index 0000000000..a802d55028 --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/views/SignInView.mxml @@ -0,0 +1,206 @@ + + + + + + + + + https?):\/\/)(?P[^:\/\s]+)(?P:([^\/]*))?((?P(\/\w+)*\/)(?P[-\w.]+[^#?\s]*)?(?P\?([^#]*))?(?P#(.*))?)?$/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; + } + + ]]> + + + + [Event(name="signedIn", type="org.umbraco.desktopmediauploader.events.SignedInEvent")] + + + + + + + + + + + + + + + + + + + + + diff --git a/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/views/UploadView.mxml b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/views/UploadView.mxml new file mode 100644 index 0000000000..3376fb595e --- /dev/null +++ b/components/DesktopMediaUploader/src/org/umbraco/desktopmediauploader/views/UploadView.mxml @@ -0,0 +1,331 @@ + + + + + + + + + = 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; + } + } + + ]]> + + + + [Event(name="signedOut", type="org.umbraco.desktopmediauploader.events.SignedOutEvent")] + + + + + + + + + + + + + + + + + Launch Site + Launch Admin + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/foreign dlls/Nibble.Umb.ZipUpload.dll b/foreign dlls/Nibble.Umb.ZipUpload.dll deleted file mode 100644 index 706dce3e4a..0000000000 Binary files a/foreign dlls/Nibble.Umb.ZipUpload.dll and /dev/null differ diff --git a/umbraco/businesslogic/IO/SystemDirectories.cs b/umbraco/businesslogic/IO/SystemDirectories.cs index 6d70c59fe1..9db0e398e1 100644 --- a/umbraco/businesslogic/IO/SystemDirectories.cs +++ b/umbraco/businesslogic/IO/SystemDirectories.cs @@ -20,6 +20,14 @@ namespace umbraco.IO } } + public static string Base + { + get + { + return IOHelper.returnPath("umbracoBaseDirectory", "~/base"); + } + } + public static string Config { get @@ -27,7 +35,7 @@ namespace umbraco.IO return IOHelper.returnPath("umbracoConfigDirectory", "~/config"); } } - + public static string Css { get diff --git a/umbraco/cms/businesslogic/media/IMediaFactory.cs b/umbraco/cms/businesslogic/media/IMediaFactory.cs new file mode 100644 index 0000000000..f3eb25d3e1 --- /dev/null +++ b/umbraco/cms/businesslogic/media/IMediaFactory.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using umbraco.BusinessLogic; + +namespace umbraco.cms.businesslogic.media +{ + public interface IMediaFactory + { + List Extensions { get; } + int Priority { get; } + + bool CanHandleMedia(int parentNodeId, PostedMediaFile postedFile, User user); + + Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user); + Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user, bool replaceExisting); + } +} diff --git a/umbraco/cms/businesslogic/media/MediaFactory.cs b/umbraco/cms/businesslogic/media/MediaFactory.cs new file mode 100644 index 0000000000..e44d957889 --- /dev/null +++ b/umbraco/cms/businesslogic/media/MediaFactory.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using umbraco.BusinessLogic; +using umbraco.BusinessLogic.Utils; + +namespace umbraco.cms.businesslogic.media +{ + public class MediaFactory + { + private static readonly List Factories = new List(); + + static MediaFactory() + { + Initialize(); + } + + private static void Initialize() + { + var types = TypeFinder.FindClassesOfType(); + + foreach (var t in types) + { + IMediaFactory typeInstance = null; + + try + { + if (t.IsVisible) + { + typeInstance = Activator.CreateInstance(t) as IMediaFactory; + } + } + catch { } + + if (typeInstance != null) + { + try + { + Factories.Add(typeInstance); + } + catch (Exception ee) + { + Log.Add(LogTypes.Error, -1, "Can't import MediaFactory '" + t.FullName + "': " + ee); + } + } + } + + Factories.Sort((f1, f2) => f1.Priority.CompareTo(f2.Priority)); + } + + public static IMediaFactory GetMediaFactory(int parentId, PostedMediaFile postedFile, User user) + { + var ext = Path.GetExtension(postedFile.FileName); + if (ext == null) + return null; + + var factories = Factories.Where(mf => mf.Extensions.Contains(ext.ToLower().TrimStart('.'))).ToList(); + + if (factories.Count == 0) + factories = Factories.Where(mf => mf.Extensions.Contains("*")).ToList(); + + if (factories.Count > 0) + return factories.FirstOrDefault(factory => factory.CanHandleMedia(parentId, postedFile, user)); + + return null; + } + } + + public class PostedMediaFile + { + public string FileName { get; set; } + public string ContentType { get; set; } + public int ContentLength { get; set; } + public Stream InputStream { get; set; } + + public void SaveAs(string filename) + { + var s = new FileStream(filename, FileMode.Create); + try + { + int readCount; + var buffer = new byte[8192]; + + if (InputStream.CanSeek) + InputStream.Seek(0, SeekOrigin.Begin); + + while ((readCount = InputStream.Read(buffer, 0, buffer.Length)) != 0) + s.Write(buffer, 0, readCount); + + s.Flush(); + } + finally + { + s.Close(); + } + } + } +} diff --git a/umbraco/cms/businesslogic/media/UmbracoFileMediaFactory.cs b/umbraco/cms/businesslogic/media/UmbracoFileMediaFactory.cs new file mode 100644 index 0000000000..ba1005d32c --- /dev/null +++ b/umbraco/cms/businesslogic/media/UmbracoFileMediaFactory.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using umbraco.BusinessLogic; + +namespace umbraco.cms.businesslogic.media +{ + public class UmbracoFileMediaFactory : UmbracoMediaFactory + { + public override string MediaTypeAlias + { + get { return "File"; } + } + + public override List Extensions + { + get { return new List { "*" }; } + } + + public override void DoHandleMedia(Media media, PostedMediaFile uploadedFile, User user) + { + // Get umbracoFile property + var propertyId = media.getProperty("umbracoFile").Id; + + // Get paths + var destFileName = ConstructDestFileName(propertyId, uploadedFile.FileName); + var destPath = ConstructDestPath(propertyId); + var destFilePath = VirtualPathUtility.Combine(destPath, destFileName); + var ext = VirtualPathUtility.GetExtension(destFileName).Substring(1); + + var absoluteDestPath = HttpContext.Current.Server.MapPath(destPath); + var absoluteDestFilePath = HttpContext.Current.Server.MapPath(destFilePath); + + // Set media properties + media.getProperty("umbracoFile").Value = destFilePath; + media.getProperty("umbracoBytes").Value = uploadedFile.ContentLength; + + if (media.getProperty("umbracoExtension") != null) + media.getProperty("umbracoExtension").Value = ext; + + if (media.getProperty("umbracoExtensio") != null) + media.getProperty("umbracoExtensio").Value = ext; + + // Create directory + if (UmbracoSettings.UploadAllowDirectories) + Directory.CreateDirectory(absoluteDestPath); + + // Save file + uploadedFile.SaveAs(absoluteDestFilePath); + + // Close stream + uploadedFile.InputStream.Close(); + + // Save media + media.Save(); + } + } +} diff --git a/umbraco/cms/businesslogic/media/UmbracoImageMediaFactory.cs b/umbraco/cms/businesslogic/media/UmbracoImageMediaFactory.cs new file mode 100644 index 0000000000..d14aebc2b5 --- /dev/null +++ b/umbraco/cms/businesslogic/media/UmbracoImageMediaFactory.cs @@ -0,0 +1,172 @@ +using System; +using System.Collections.Generic; +using System.Drawing; +using System.Drawing.Drawing2D; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Web; +using umbraco.BasePages; +using umbraco.BusinessLogic; +using umbraco.cms.businesslogic.datatype; +using Encoder = System.Text.Encoder; + +namespace umbraco.cms.businesslogic.media +{ + public class UmbracoImageMediaFactory : UmbracoMediaFactory + { + public override string MediaTypeAlias + { + get { return "Image"; } + } + + public override List Extensions + { + get { return new List { "jpeg", "jpg", "gif", "bmp", "png", "tiff", "tif" }; } + } + + public override void DoHandleMedia(Media media, PostedMediaFile postedFile, BusinessLogic.User user) + { + // Get Image object, width and height + var image = System.Drawing.Image.FromStream(postedFile.InputStream); + var fileWidth = image.Width; + var fileHeight = image.Height; + + // Get umbracoFile property + var propertyId = media.getProperty("umbracoFile").Id; + + // Get paths + var destFileName = ConstructDestFileName(propertyId, postedFile.FileName); + var destPath = ConstructDestPath(propertyId); + var destFilePath = VirtualPathUtility.Combine(destPath, destFileName); + var ext = VirtualPathUtility.GetExtension(destFileName).Substring(1); + + var absoluteDestPath = HttpContext.Current.Server.MapPath(destPath); + var absoluteDestFilePath = HttpContext.Current.Server.MapPath(destFilePath); + + // Set media properties + media.getProperty("umbracoFile").Value = destFilePath; + media.getProperty("umbracoWidth").Value = fileWidth; + media.getProperty("umbracoHeight").Value = fileHeight; + media.getProperty("umbracoBytes").Value = postedFile.ContentLength; + + if (media.getProperty("umbracoExtension") != null) + media.getProperty("umbracoExtension").Value = ext; + + if (media.getProperty("umbracoExtensio") != null) + media.getProperty("umbracoExtensio").Value = ext; + + // Create directory + if (UmbracoSettings.UploadAllowDirectories) + Directory.CreateDirectory(absoluteDestPath); + + // Generate thumbnail + var thumbDestFilePath = Path.Combine(absoluteDestPath, Path.GetFileNameWithoutExtension(destFileName) + "_thumb"); + GenerateThumbnail(image, 100, fileWidth, fileHeight, thumbDestFilePath + ".jpg"); + + // Generate additional thumbnails based on PreValues set in DataTypeDefinition uploadField + GenerateAdditionalThumbnails(image, fileWidth, fileHeight, thumbDestFilePath); + + image.Dispose(); + + // Save file + postedFile.SaveAs(absoluteDestFilePath); + + // Close stream + postedFile.InputStream.Close(); + + // Save media + media.Save(); + } + + private static void GenerateAdditionalThumbnails(Image image, int fileWidth, int fileHeight, string destFilePath) + { + var uploadFieldDataTypeId = new Guid("5032a6e6-69e3-491d-bb28-cd31cd11086c"); + + DataTypeDefinition dataTypeDef = null; + + try + { + // Get DataTypeDefinition of upload field + dataTypeDef = DataTypeDefinition.GetByDataTypeId(uploadFieldDataTypeId); + } + catch { } + + if (dataTypeDef != null) + { + // Get PreValues + var preValues = PreValues.GetPreValues(dataTypeDef.Id); + + var thumbnails = ""; + if (preValues.Count > 0) + thumbnails = ((PreValue)preValues[0]).Value; + + if (thumbnails != "") + { + var thumbnailSizes = thumbnails.Split(";".ToCharArray()); + foreach (var thumb in thumbnailSizes.Where(thumb => thumb != "")) + { + GenerateThumbnail(image, int.Parse(thumb), fileWidth, fileHeight, + destFilePath + "_" + thumb + ".jpg"); + } + } + } + } + + private static void GenerateThumbnail(Image image, int maxWidthHeight, int fileWidth, int fileHeight, string thumbnailFileName) + { + // Generate thumbnailee + var fx = (float)fileWidth / maxWidthHeight; + var fy = (float)fileHeight / maxWidthHeight; + + // must fit in thumbnail size + var f = Math.Max(fx, fy); //if (f < 1) f = 1; + var widthTh = (int)Math.Round(fileWidth / f); + var heightTh = (int)Math.Round(fileHeight / f); + + // fixes for empty width or height + if (widthTh == 0) + widthTh = 1; + if (heightTh == 0) + heightTh = 1; + + // Create new image with best quality settings + var bp = new Bitmap(widthTh, heightTh); + var g = Graphics.FromImage(bp); + g.SmoothingMode = SmoothingMode.HighQuality; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.PixelOffsetMode = PixelOffsetMode.HighQuality; + + // Copy the old image to the new and resized + var rect = new Rectangle(0, 0, widthTh, heightTh); + g.DrawImage(image, rect, 0, 0, image.Width, image.Height, GraphicsUnit.Pixel); + + // Copy metadata + var codecs = ImageCodecInfo.GetImageEncoders(); + ImageCodecInfo codec = null; + for (var i = 0; codec == null && i < codecs.Length; i++) + { + if (codecs[i].MimeType.Equals("image/jpeg")) + codec = codecs[i]; + } + + // Set compresion ratio to 90% + var ep = new EncoderParameters(); + ep.Param[0] = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, 90L); + + // Save the new image + if (codec != null) + { + bp.Save(thumbnailFileName, codec, ep); + } + else + { + // Log error + Log.Add(LogTypes.Error, UmbracoEnsuredPage.CurrentUser, -1, "Multiple file upload: Can't find appropriate codec"); + } + + bp.Dispose(); + g.Dispose(); + } + } +} diff --git a/umbraco/cms/businesslogic/media/UmbracoMediaFactory.cs b/umbraco/cms/businesslogic/media/UmbracoMediaFactory.cs new file mode 100644 index 0000000000..43a15b79da --- /dev/null +++ b/umbraco/cms/businesslogic/media/UmbracoMediaFactory.cs @@ -0,0 +1,116 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using System.Xml; +using umbraco.BusinessLogic; + +namespace umbraco.cms.businesslogic.media +{ + public abstract class UmbracoMediaFactory : IMediaFactory + { + public abstract List Extensions { get; } + public virtual int Priority { get { return 1000; } } + public abstract string MediaTypeAlias { get; } + + public virtual bool CanHandleMedia(int parentNodeId, PostedMediaFile postedFile, User user) + { + try + { + var parentNode = new Media(parentNodeId); + + return parentNodeId > -1 ? + user.Applications.Any(app => app.alias.ToLower() == "media") && (user.StartMediaId <= 0 || ("," + parentNode.Path + ",").Contains("," + user.StartMediaId + ",")) && parentNode.ContentType.AllowedChildContentTypeIDs.Contains(MediaType.GetByAlias(MediaTypeAlias).Id) : + true; + } + catch + { + return false; + } + } + + public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user) + { + return HandleMedia(parentNodeId, postedFile, user, false); + } + + public Media HandleMedia(int parentNodeId, PostedMediaFile postedFile, User user, bool replaceExisting) + { + // Check to see if a file exists + Media media; + + if(replaceExisting && TryFindExistingMedia(parentNodeId, postedFile.FileName, out media)) + { + // Do nothing as existing media is returned + } + else + { + media = Media.MakeNew(postedFile.FileName, + MediaType.GetByAlias(MediaTypeAlias), + user, + parentNodeId); + } + + if (postedFile.ContentLength > 0) + DoHandleMedia(media, postedFile, user); + + media.XmlGenerate(new XmlDocument()); + + return media; + } + + public abstract void DoHandleMedia(Media media, PostedMediaFile uploadedFile, User user); + + #region Helper Methods + + public string ConstructDestPath(int propertyId) + { + if (UmbracoSettings.UploadAllowDirectories) + { + var path = VirtualPathUtility.Combine(VirtualPathUtility.AppendTrailingSlash(IO.SystemDirectories.Media), propertyId.ToString()); + + return VirtualPathUtility.ToAbsolute(VirtualPathUtility.AppendTrailingSlash(path)); + } + + return VirtualPathUtility.ToAbsolute(VirtualPathUtility.AppendTrailingSlash(IO.SystemDirectories.Media)); + } + + public string ConstructDestFileName(int propertyId, string filename) + { + if (UmbracoSettings.UploadAllowDirectories) + return filename; + + return propertyId + "-" + filename; + } + + public bool TryFindExistingMedia(int parentNodeId, string fileName, out Media existingMedia) + { + var children = parentNodeId == -1 ? Media.GetRootMedias() : new Media(parentNodeId).Children; + foreach (var childMedia in children) + { + if (childMedia.ContentType.Alias == MediaTypeAlias) + { + var prop = childMedia.getProperty("umbracoFile"); + if (prop != null) + { + var destFileName = ConstructDestFileName(prop.Id, fileName); + var destPath = ConstructDestPath(prop.Id); + var destFilePath = VirtualPathUtility.Combine(destPath, destFileName); + + if (prop.Value.ToString() == destFilePath) + { + existingMedia = childMedia; + return true; + } + } + } + } + + existingMedia = null; + return false; + } + + #endregion + } +} diff --git a/umbraco/cms/umbraco.cms.csproj b/umbraco/cms/umbraco.cms.csproj index a333f50e7c..973af42f33 100644 --- a/umbraco/cms/umbraco.cms.csproj +++ b/umbraco/cms/umbraco.cms.csproj @@ -122,6 +122,7 @@ System.Data + System.Security @@ -215,6 +216,11 @@ + + + + + True True diff --git a/umbraco/presentation/config/Dashboard.config b/umbraco/presentation/config/Dashboard.config index 5d59760924..63668eee88 100644 --- a/umbraco/presentation/config/Dashboard.config +++ b/umbraco/presentation/config/Dashboard.config @@ -35,7 +35,7 @@ /umbraco/dashboard/mediadashboardintro.ascx - /umbraco/dashboard/zipupload.ascx + /umbraco/dashboard/desktopmediauploader.ascx /umbraco/dashboard/mediadashboardvideos.ascx diff --git a/umbraco/presentation/umbraco.presentation.csproj b/umbraco/presentation/umbraco.presentation.csproj index 4eb7eb118b..b4ba57b464 100644 --- a/umbraco/presentation/umbraco.presentation.csproj +++ b/umbraco/presentation/umbraco.presentation.csproj @@ -110,9 +110,6 @@ C:\Users\Shannon\Documents\Visual Studio 2008\Projects\Umbraco\Branch-4.1\foreign dlls\Lucene.Net.dll - - ..\..\foreign dlls\Nibble.Umb.ZipUpload.dll - System @@ -554,6 +551,13 @@ ChangePassword.ascx + + DesktopMediaUploader.ascx + ASPXCodeBehind + + + DesktopMediaUploader.ascx + DeveloperDashboardIntro.ascx @@ -1400,6 +1404,9 @@ MacroContainerService.asmx Component + + MediaUploader.ashx + TagsAutoCompleteHandler.ashx @@ -1642,6 +1649,16 @@ + + + + + + + + + + @@ -1769,7 +1786,6 @@ - @@ -2365,6 +2381,7 @@ SettingsSingleFileGenerator Settings1.Designer.cs + @@ -3087,6 +3104,7 @@ + diff --git a/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx b/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx new file mode 100644 index 0000000000..09f6a270f7 --- /dev/null +++ b/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx @@ -0,0 +1,48 @@ +<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="DesktopMediaUploader.ascx.cs" Inherits="umbraco.presentation.umbraco.dashboard.DesktopMediaUploader" %> + +
+

Desktop Media Uploader

+ Umbraco +

Desktop Media Uploader is a small desktop application that you can install on your computer which allows you to easily upload media items directly to the media section.

+

The badge below will auto configure itself based upon whether you already have Desktop Media Uploader installed or not.

+

Just click the Install Now / Upgrade Now / Launch Now link to perform that action.

+
+
+
+ + + +

+

+ Download Desktop Media Uploader now.

This application requires Adobe® AIR™ to be installed for Mac OS or Windows. +
+

+ +
+
+
+
+
\ No newline at end of file diff --git a/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx.cs b/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx.cs new file mode 100644 index 0000000000..4aa65271a3 --- /dev/null +++ b/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Security; +using System.Web.UI; +using System.Web.UI.WebControls; +using umbraco.BasePages; + +namespace umbraco.presentation.umbraco.dashboard +{ + public partial class DesktopMediaUploader : System.Web.UI.UserControl + { + protected void Page_Load(object sender, EventArgs e) + { + + } + + protected string FullyQualifiedAppPath + { + get + { + var appPath = ""; + var context = HttpContext.Current; + + if (context != null) + { + appPath = string.Format("{0}://{1}{2}{3}", + context.Request.Url.Scheme, + context.Request.Url.Host, + (context.Request.Url.Port == 80) ? string.Empty : ":" + context.Request.Url.Port, + context.Request.ApplicationPath); + } + + if (!appPath.EndsWith("/")) + appPath += "/"; + + return appPath; + } + } + + protected string AppLaunchArg + { + get + { + //var ticket = ((FormsIdentity) HttpContext.Current.User.Identity).Ticket; + var ticket = new FormsAuthenticationTicket(1, + UmbracoEnsuredPage.CurrentUser.LoginName, + DateTime.Now, + DateTime.Now, + false, + ""); + + return HttpUtility.UrlEncode(Base64Encode(string.Format("{0};{1};{2}", + FullyQualifiedAppPath.TrimEnd('/'), + UmbracoEnsuredPage.CurrentUser.LoginName, + FormsAuthentication.Encrypt(ticket) + ))); + } + } + + private string Base64Encode(string input) + { + byte[] toEncodeAsBytes = UTF8Encoding.UTF8.GetBytes(input); + + return Convert.ToBase64String(toEncodeAsBytes); + } + } +} \ No newline at end of file diff --git a/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx.designer.cs b/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx.designer.cs new file mode 100644 index 0000000000..3b39f7a09a --- /dev/null +++ b/umbraco/presentation/umbraco/dashboard/DesktopMediaUploader.ascx.designer.cs @@ -0,0 +1,33 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace umbraco.presentation.umbraco.dashboard { + + + public partial class DesktopMediaUploader { + + /// + /// Panel1 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel Panel1; + + /// + /// Panel2 control. + /// + /// + /// Auto-generated field. + /// To modify move field declaration from designer file to code-behind file. + /// + protected global::System.Web.UI.WebControls.Panel Panel2; + } +} diff --git a/umbraco/presentation/umbraco/dashboard/MediaDashboardIntro.ascx b/umbraco/presentation/umbraco/dashboard/MediaDashboardIntro.ascx index b541b26635..b5fbfe8d4c 100644 --- a/umbraco/presentation/umbraco/dashboard/MediaDashboardIntro.ascx +++ b/umbraco/presentation/umbraco/dashboard/MediaDashboardIntro.ascx @@ -8,7 +8,7 @@

Get started with Media right now

- Use the tool below to upload a ZIP file of your images or documents to a media folder. + Use the tool below to upload your images or documents to a media folder.

Follow these steps:

@@ -16,15 +16,13 @@
    -
  • Create a media folder by right-clicking on the Media root folder, selecting Create, - then give your folder a name, select the Media Type Folder, and click create
  • -
  • Select the created folder by click the Choose link
  • -
  • Use the Browse button below to select a ZIP file containing your images (you can - even organize them into folders and the tool will create these for you)
  • -
  • Click the Upload zip file button
  • -
  • Refresh the Media section by right-clicking the Media root folder and selecting - Reload Nodes
  • +
  • Click Install and follow the on screen instructions to install the Desktop Media Uploader
  • +
  • Enter your login details for the site and click Sign In
  • +
  • Choose a media folder to upload files to from the Upload files to... dropdown list
  • +
  • Drag the files and folders you wish to upload directly into the Desktop Media Uploader application
  • +
  • Click Upload to start uploading
+

For a more thorough guide on how to use the Desktop Media Uploader, checkout this video.

diff --git a/umbraco/presentation/umbraco/dashboard/air/DesktopMediaUploader.air b/umbraco/presentation/umbraco/dashboard/air/DesktopMediaUploader.air new file mode 100644 index 0000000000..6716c2c96b Binary files /dev/null and b/umbraco/presentation/umbraco/dashboard/air/DesktopMediaUploader.air differ diff --git a/umbraco/presentation/umbraco/dashboard/images/dmu-badge.jpg b/umbraco/presentation/umbraco/dashboard/images/dmu-badge.jpg new file mode 100644 index 0000000000..f3acad7bae Binary files /dev/null and b/umbraco/presentation/umbraco/dashboard/images/dmu-badge.jpg differ diff --git a/umbraco/presentation/umbraco/dashboard/images/dmu.png b/umbraco/presentation/umbraco/dashboard/images/dmu.png new file mode 100644 index 0000000000..f4cb2889d9 Binary files /dev/null and b/umbraco/presentation/umbraco/dashboard/images/dmu.png differ diff --git a/umbraco/presentation/umbraco/dashboard/scripts/swfobject.js b/umbraco/presentation/umbraco/dashboard/scripts/swfobject.js new file mode 100644 index 0000000000..08fb27000e --- /dev/null +++ b/umbraco/presentation/umbraco/dashboard/scripts/swfobject.js @@ -0,0 +1,5 @@ +/* SWFObject v2.1 + Copyright (c) 2007-2008 Geoff Stearns, Michael Williams, and Bobby van der Sluis + This software is released under the MIT License +*/ +var swfobject=function(){var b="undefined",Q="object",n="Shockwave Flash",p="ShockwaveFlash.ShockwaveFlash",P="application/x-shockwave-flash",m="SWFObjectExprInst",j=window,K=document,T=navigator,o=[],N=[],i=[],d=[],J,Z=null,M=null,l=null,e=false,A=false;var h=function(){var v=typeof K.getElementById!=b&&typeof K.getElementsByTagName!=b&&typeof K.createElement!=b,AC=[0,0,0],x=null;if(typeof T.plugins!=b&&typeof T.plugins[n]==Q){x=T.plugins[n].description;if(x&&!(typeof T.mimeTypes!=b&&T.mimeTypes[P]&&!T.mimeTypes[P].enabledPlugin)){x=x.replace(/^.*\s+(\S+\s+\S+$)/,"$1");AC[0]=parseInt(x.replace(/^(.*)\..*$/,"$1"),10);AC[1]=parseInt(x.replace(/^.*\.(.*)\s.*$/,"$1"),10);AC[2]=/r/.test(x)?parseInt(x.replace(/^.*r(.*)$/,"$1"),10):0}}else{if(typeof j.ActiveXObject!=b){var y=null,AB=false;try{y=new ActiveXObject(p+".7")}catch(t){try{y=new ActiveXObject(p+".6");AC=[6,0,21];y.AllowScriptAccess="always"}catch(t){if(AC[0]==6){AB=true}}if(!AB){try{y=new ActiveXObject(p)}catch(t){}}}if(!AB&&y){try{x=y.GetVariable("$version");if(x){x=x.split(" ")[1].split(",");AC=[parseInt(x[0],10),parseInt(x[1],10),parseInt(x[2],10)]}}catch(t){}}}}var AD=T.userAgent.toLowerCase(),r=T.platform.toLowerCase(),AA=/webkit/.test(AD)?parseFloat(AD.replace(/^.*webkit\/(\d+(\.\d+)?).*$/,"$1")):false,q=false,z=r?/win/.test(r):/win/.test(AD),w=r?/mac/.test(r):/mac/.test(AD);/*@cc_on q=true;@if(@_win32)z=true;@elif(@_mac)w=true;@end@*/return{w3cdom:v,pv:AC,webkit:AA,ie:q,win:z,mac:w}}();var L=function(){if(!h.w3cdom){return }f(H);if(h.ie&&h.win){try{K.write("