diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/_fla/.htaccess | 3 | ||||
-rw-r--r-- | lib/_fla/MultipleUpload.as | 274 | ||||
-rw-r--r-- | lib/_fla/README | 1 | ||||
-rw-r--r-- | lib/_fla/multipleUpload.fla | bin | 0 -> 1812992 bytes | |||
-rw-r--r-- | lib/exe/mediamanager.php | 16 | ||||
-rw-r--r-- | lib/exe/multipleUpload.swf | bin | 0 -> 64353 bytes | |||
-rw-r--r-- | lib/images/multiupload.png | bin | 0 -> 698 bytes | |||
-rw-r--r-- | lib/scripts/helpers.js | 278 | ||||
-rw-r--r-- | lib/scripts/media.js | 21 | ||||
-rw-r--r-- | lib/tpl/default/media.css | 3 |
10 files changed, 462 insertions, 134 deletions
diff --git a/lib/_fla/.htaccess b/lib/_fla/.htaccess new file mode 100644 index 000000000..9a7d38c12 --- /dev/null +++ b/lib/_fla/.htaccess @@ -0,0 +1,3 @@ +## no access to the fla directory +order allow,deny +deny from all diff --git a/lib/_fla/MultipleUpload.as b/lib/_fla/MultipleUpload.as new file mode 100644 index 000000000..8e7e0b008 --- /dev/null +++ b/lib/_fla/MultipleUpload.as @@ -0,0 +1,274 @@ +/** + * Flash Multi Upload + * + * Based on a example from Alastair Dawson + * + * @link http://blog.vixiom.com/2006/09/08/multiple-file-upload-with-flash-and-ruby-on-rails/ + * @author Alastair Dawson + * @author Andreas Gohr <andi@splitbrain.org> + */ + +// delegate +import mx.utils.Delegate; +// ui components +import mx.controls.DataGrid; +import mx.controls.gridclasses.DataGridColumn +import mx.controls.Button; +import mx.controls.TextInput; +import mx.controls.CheckBox; +import mx.controls.Label; +// file reference +import flash.net.FileReferenceList; +import flash.net.FileReference; + +class MultipleUpload { + + private var fileRef:FileReferenceList; + private var fileRefListener:Object; + private var list:Array; + private var dp:Array; + + private var files_dg:DataGrid; + private var browse_btn:Button; + private var upload_btn:Button; + private var ns_input:TextInput; + private var ns_label:Label; + private var overwrite_cb:CheckBox; + + /** + * Constructor. + * + * Initializes the needed objects and stage objects + */ + public function MultipleUpload(fdg:DataGrid, bb:Button, ub:Button, nsi:TextInput, nsl:Label, ob:CheckBox) { + // references for objects on the stage + files_dg = fdg; + browse_btn = bb; + upload_btn = ub; + ns_input = nsi; + ns_label = nsl; + overwrite_cb = ob; + + // file list references & listener + fileRef = new FileReferenceList(); + fileRefListener = new Object(); + fileRef.addListener(fileRefListener); + + // setup + iniUI(); + inifileRefListener(); + } + + /** + * Initializes the User Interface + * + * Uses flashvars to access possibly localized names + */ + private function iniUI() { + // register button handlers + browse_btn.onRelease = Delegate.create(this, this.browse); + upload_btn.onRelease = Delegate.create(this, this.upload); + + // columns for dataGrid + var col:DataGridColumn; + col = new DataGridColumn('name'); + col.headerText = ( _root.L_gridname ? _root.L_gridname : 'Filename' ); + col.sortable = false; + files_dg.addColumn(col); + col = new DataGridColumn('size'); + col.headerText = ( _root.L_gridsize ? _root.L_gridsize : 'Size' ); + col.sortable = false; + files_dg.addColumn(col); + col = new DataGridColumn('status'); + col.headerText = ( _root.L_gridstat ? _root.L_gridstat : 'Status' ); + col.sortable = false; + files_dg.addColumn(col); + + // label translations + if(_root.L_overwrite) overwrite_cb.label = _root.L_overwrite; + if(_root.L_browse) browse_btn.label = _root.L_browse; + if(_root.L_upload) upload_btn.label = _root.L_upload; + if(_root.L_namespace) ns_label.text = _root.L_namespace; + + // prefill input field + if(_root.O_ns) ns_input.text = _root.O_ns; + + // disable buttons + upload_btn.enabled = false; + if(!_root.O_overwrite) overwrite_cb.visible = false; + + // initalize the data provider list + dp = new Array(); + list = new Array(); + files_dg.spaceColumnsEqually(); + } + + /** + * Open files selection dialog + * + * Adds the allowed file types + */ + private function browse() { + if(_root.O_extensions){ + var exts:Array = _root.O_extensions.split('|'); + var filter:Object = new Object(); + filter.description = (_root.L_filetypes ? _root.L_filetypes : 'Allowed filetypes'); + filter.extension = ''; + for(var i:Number = 0; i<exts.length; i++){ + filter.extension += '*.'+exts[i]+';'; + } + filter.extension = filter.extension.substr(0,filter.extension.length-1); + var apply:Array = new Array(); + apply.push(filter); + fileRef.browse(apply); + }else{ + fileRef.browse(); + } + } + + /** + * Upload selected files + */ + private function upload() { + // prepare backend URL + var url:String; + url = _root.O_backend; // from flashvars + url += '&ns='+escape(ns_input.text); + + // prepare upload url + var upurl:String; + upurl = url; + upurl += '§ok='+escape(_root.O_sectok); + upurl += '&authtok='+escape(_root.O_authtok); + if(overwrite_cb.selected) upurl += '&ow=1'; + + // disable buttons + upload_btn.enabled = false; + browse_btn.enabled = false; + ns_input.enabled = false; + overwrite_cb.enabled = false; + + // upload the files + for(var i:Number = 0; i < list.length; i++) { + var file = list[i]; + file.addListener(fileRefListener); + file.upload(upurl); + } + + // when done redirect + getURL(url,'_self'); + } + + /** + * Set the status of a given file in the data grid + */ + private function setStatus(file,msg){ + for(var i:Number = 0; i < list.length; i++) { + if (list[i].name == file.name) { + files_dg.editField(i, 'status', msg); + } + } + } + + /** + * Initialize the file reference listener + */ + private function inifileRefListener() { + fileRefListener.onSelect = Delegate.create(this, this.onSelect); + fileRefListener.onCancel = Delegate.create(this, this.onCancel); + fileRefListener.onOpen = Delegate.create(this, this.onOpen); + fileRefListener.onProgress = Delegate.create(this, this.onProgress); + fileRefListener.onComplete = Delegate.create(this, this.onComplete); + fileRefListener.onHTTPError = Delegate.create(this, this.onHTTPError); + fileRefListener.onIOError = Delegate.create(this, this.onIOError); + fileRefListener.onSecurityError = Delegate.create(this, this.onSecurityError); + } + + /** + * Handle file selection + * + * Files are added as in a list of references and beautified into the data grid dataprovider array + * + * Multiple browses will add to the list + */ + private function onSelect(fileRefList:FileReferenceList) { + var sel = fileRefList.fileList; + for(var i:Number = 0; i < sel.length; i++) { + // check size + var stat:String; + if(_root.O_maxsize && sel[i].size > _root.O_maxsize){ + stat = (_root.L_toobig ? _root.L_toobig : 'too big'); + }else{ + stat = (_root.L_ready ? _root.L_ready : 'ready for upload'); + } + // add to grid + dp.push({name:sel[i].name, size:Math.round(sel[i].size / 1000) + " kb", status:stat}); + // add to reference list + list.push(sel[i]); + } + // update dataGrid + files_dg.dataProvider = dp; + files_dg.spaceColumnsEqually(); + + if(list.length > 0) upload_btn.enabled = true; + } + + /** + * Does nothing + */ + private function onCancel() { + } + + /** + * Does nothing + */ + private function onOpen(file:FileReference) { + } + + /** + * Set the upload progress + */ + private function onProgress(file:FileReference, bytesLoaded:Number, bytesTotal:Number) { + var percentDone = Math.round((bytesLoaded / bytesTotal) * 100); + var msg:String = 'uploading @PCT@%'; + if(_root.L_progress) msg = _root.L_progress; + msg = msg.split('@PCT@').join(percentDone); + this.setStatus(file,msg); + } + + /** + * Handle upload completion + */ + private function onComplete(file:FileReference) { + this.setStatus(file,(_root.L_done ? _root.L_done : 'complete')); + } + + /** + * Handle upload errors + */ + private function onHTTPError(file:FileReference, httpError:Number) { + if(httpError == 400){ + this.setStatus(file,(_root.L_fail ? _root.L_fail : 'failed')); + }else if(httpError == 401){ + this.setStatus(file,(_root.L_authfail ? _root.L_authfail : 'auth failed')); + }else{ + this.setStatus(file,"HTTP Error " + httpError); + } + } + + /** + * Handle IO errors + */ + private function onIOError(file:FileReference) { + this.setStatus(file,"IO Error"); + } + + /** + * Handle Security errors + */ + private function onSecurityError(file:FileReference, errorString:String) { + this.setStatus(file,"SecurityError: " + errorString); + } + + +} diff --git a/lib/_fla/README b/lib/_fla/README new file mode 100644 index 000000000..beaa15d02 --- /dev/null +++ b/lib/_fla/README @@ -0,0 +1 @@ +Flash source files. Those will not be included in the tarball releases. diff --git a/lib/_fla/multipleUpload.fla b/lib/_fla/multipleUpload.fla Binary files differnew file mode 100644 index 000000000..a04237c1c --- /dev/null +++ b/lib/_fla/multipleUpload.fla diff --git a/lib/exe/mediamanager.php b/lib/exe/mediamanager.php index 32849be62..c3754d309 100644 --- a/lib/exe/mediamanager.php +++ b/lib/exe/mediamanager.php @@ -1,6 +1,8 @@ <?php if(!defined('DOKU_INC')) define('DOKU_INC',dirname(__FILE__).'/../../'); define('DOKU_MEDIAMANAGER',1); + + require_once(DOKU_INC.'inc/init.php'); require_once(DOKU_INC.'inc/lang/en/lang.php'); require_once(DOKU_INC.'inc/lang/'.$conf['lang'].'/lang.php'); @@ -13,6 +15,7 @@ // handle passed message if($_REQUEST['msg1']) msg(hsc($_REQUEST['msg1']),1); + if($_REQUEST['err']) msg(hsc($_REQUEST['err']),-1); // get namespace to display (either direct or from deletion order) @@ -37,6 +40,19 @@ // create the given namespace (just for beautification) if($AUTH >= AUTH_UPLOAD) { io_createNamespace("$NS:xxx", 'media'); } + // handle flash upload + if($_FILES['Filedata']['tmp_name']){ + $_FILES['upload'] =& $_FILES['Filedata']; + $JUMPTO = media_upload($NS,$AUTH); + if($JUMPTO == false){ + header("HTTP/1.0 400 Bad Request"); + echo 'Upload failed'; + } + echo 'ok'; + exit; + } + + // handle upload if($_FILES['upload']['tmp_name']){ $JUMPTO = media_upload($NS,$AUTH); diff --git a/lib/exe/multipleUpload.swf b/lib/exe/multipleUpload.swf Binary files differnew file mode 100644 index 000000000..6921cbb45 --- /dev/null +++ b/lib/exe/multipleUpload.swf diff --git a/lib/images/multiupload.png b/lib/images/multiupload.png Binary files differnew file mode 100644 index 000000000..1e8efa063 --- /dev/null +++ b/lib/images/multiupload.png diff --git a/lib/scripts/helpers.js b/lib/scripts/helpers.js index 7b500c226..8d4f3ea78 100644 --- a/lib/scripts/helpers.js +++ b/lib/scripts/helpers.js @@ -1,132 +1,146 @@ -/**
- * $Id: helpers.js 156 2006-12-23 08:48:25Z wingedfox $
- * $HeadURL: https://svn.debugger.ru/repos/jslibs/BrowserExtensions/trunk/helpers.js $
- *
- * File contains differrent helper functions
- *
- * @author Ilya Lebedev <ilya@lebedev.net>
- * @license LGPL
- * @version $Rev: 156 $
- */
-//-----------------------------------------------------------------------------
-// Variable/property checks
-//-----------------------------------------------------------------------------
-/**
- * Checks if property is undefined
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isUndefined (prop /* :Object */) /* :Boolean */ {
- return (typeof prop == 'undefined');
-}
-/**
- * Checks if property is function
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isFunction (prop /* :Object */) /* :Boolean */ {
- return (typeof prop == 'function');
-}
-/**
- * Checks if property is string
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isString (prop /* :Object */) /* :Boolean */ {
- return (typeof prop == 'string');
-}
-/**
- * Checks if property is number
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isNumber (prop /* :Object */) /* :Boolean */ {
- return (typeof prop == 'number');
-}
-/**
- * Checks if property is the calculable number
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isNumeric (prop /* :Object */) /* :Boolean */ {
- return isNumber(prop)&&!isNaN(prop)&&isFinite(prop);
-}
-/**
- * Checks if property is array
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isArray (prop /* :Object */) /* :Boolean */ {
- return (prop instanceof Array);
-}
-/**
- * Checks if property is regexp
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isRegExp (prop /* :Object */) /* :Boolean */ {
- return (prop instanceof RegExp);
-}
-/**
- * Checks if property is a boolean value
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isBoolean (prop /* :Object */) /* :Boolean */ {
- return ('boolean' == typeof prop);
-}
-/**
- * Checks if property is a scalar value (value that could be used as the hash key)
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isScalar (prop /* :Object */) /* :Boolean */ {
- return isNumeric(prop)||isString(prop);
-}
-/**
- * Checks if property is empty
- *
- * @param {Object} prop value to check
- * @return {Boolean} true if matched
- * @scope public
- */
-function isEmpty (prop /* :Object */) /* :Boolean */ {
- if (isBoolean(prop)) return false;
- if (isRegExp(prop) && new RegExp("").toString() == prop.toString()) return true;
- if (isString(prop) || isNumber(prop)) return !prop;
- if (Boolean(prop)&&false != prop) {
- for (var i in prop) if(prop.hasOwnProperty(i)) return false
- }
- return true;
-}
-
-/*
-* Checks if property is derived from prototype, applies method if it is not exists
-*
-* @param string property name
-* @return bool true if prototyped
-* @access public
-*/
-if ('undefined' == typeof Object.hasOwnProperty) {
- Object.prototype.hasOwnProperty = function (prop) {
- return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]);
- }
-}
+/** + * Differrent helper functions + * + * @author Ilya Lebedev <ilya@lebedev.net> + * @license LGPL + */ +//----------------------------------------------------------------------------- +// Variable/property checks +//----------------------------------------------------------------------------- +/** + * Checks if property is undefined + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isUndefined (prop /* :Object */) /* :Boolean */ { + return (typeof prop == 'undefined'); +} +/** + * Checks if property is function + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isFunction (prop /* :Object */) /* :Boolean */ { + return (typeof prop == 'function'); +} +/** + * Checks if property is string + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isString (prop /* :Object */) /* :Boolean */ { + return (typeof prop == 'string'); +} +/** + * Checks if property is number + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isNumber (prop /* :Object */) /* :Boolean */ { + return (typeof prop == 'number'); +} +/** + * Checks if property is the calculable number + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isNumeric (prop /* :Object */) /* :Boolean */ { + return isNumber(prop)&&!isNaN(prop)&&isFinite(prop); +} +/** + * Checks if property is array + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isArray (prop /* :Object */) /* :Boolean */ { + return (prop instanceof Array); +} +/** + * Checks if property is regexp + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isRegExp (prop /* :Object */) /* :Boolean */ { + return (prop instanceof RegExp); +} +/** + * Checks if property is a boolean value + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isBoolean (prop /* :Object */) /* :Boolean */ { + return ('boolean' == typeof prop); +} +/** + * Checks if property is a scalar value (value that could be used as the hash key) + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isScalar (prop /* :Object */) /* :Boolean */ { + return isNumeric(prop)||isString(prop); +} +/** + * Checks if property is empty + * + * @param {Object} prop value to check + * @return {Boolean} true if matched + * @scope public + */ +function isEmpty (prop /* :Object */) /* :Boolean */ { + if (isBoolean(prop)) return false; + if (isRegExp(prop) && new RegExp("").toString() == prop.toString()) return true; + if (isString(prop) || isNumber(prop)) return !prop; + if (Boolean(prop)&&false != prop) { + for (var i in prop) if(prop.hasOwnProperty(i)) return false + } + return true; +} + +/** + * Checks if property is derived from prototype, applies method if it is not exists + * + * @param string property name + * @return bool true if prototyped + * @access public + */ +if ('undefined' == typeof Object.hasOwnProperty) { + Object.prototype.hasOwnProperty = function (prop) { + return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]); + } +} + +/** + * Very simplistic Flash plugin check, probably works for Flash 8 and higher only + */ +function hasFlash(version){ + var ver = 0; + try{ + if(navigator.plugins != null && navigator.plugins.length > 0){ + ver = navigator.plugins["Shockwave Flash"].description.split(' ')[2].split('.')[0]; + }else{ + var axo = new ActiveXObject("ShockwaveFlash.ShockwaveFlash"); + ver = axo.GetVariable("$version").split(' ')[1].split(',')[0]; + } + }catch(e){ } + + if(ver >= version) return true; + return false; +} diff --git a/lib/scripts/media.js b/lib/scripts/media.js index f616f8741..ebfd01322 100644 --- a/lib/scripts/media.js +++ b/lib/scripts/media.js @@ -265,12 +265,31 @@ media = { text = text.substr(text.lastIndexOf('/')+1); text = text.substr(text.lastIndexOf('\\')+1); name.value = text; - } + }, + + initFlashUpload: function(){ + if(!hasFlash(8)) return; + var oform = $('dw__upload'); + var oflash = $('dw__flashupload'); + if(!oform || !oflash) return; + + var clicky = document.createElement('img'); + clicky.src = DOKU_BASE+'lib/images/multiupload.png'; + clicky.title = LANG['mu_btn']; + clicky.alt = LANG['mu_btn']; + clicky.style.cursor = 'pointer'; + clicky.onclick = function(){ + oform.style.display = 'none'; + oflash.style.display = ''; + }; + oform.appendChild(clicky); + } }; addInitEvent(function(){ media.treeattach($('media__tree')); media.selectorattach($('media__content')); media.attachoptions($('media__opts')); + media.initFlashUpload(); }); diff --git a/lib/tpl/default/media.css b/lib/tpl/default/media.css index 143595ba1..81a439289 100644 --- a/lib/tpl/default/media.css +++ b/lib/tpl/default/media.css @@ -137,7 +137,8 @@ it's dirty, so any "real" fixes are welcome */ padding: 0 0.5em 0.5em 0.5em; } -#media__content form#dw__upload { +#media__content form#dw__upload, +#media__content div#dw__flashupload { display: block; border-bottom: solid 1px __border__; padding: 0 0.5em 1em 0.5em; |