diff options
-rw-r--r-- | inc/lang/en/lang.php | 16 | ||||
-rw-r--r-- | inc/media.php | 55 | ||||
-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 |
12 files changed, 529 insertions, 138 deletions
diff --git a/inc/lang/en/lang.php b/inc/lang/en/lang.php index 2a330ea46..527eaa7d2 100644 --- a/inc/lang/en/lang.php +++ b/inc/lang/en/lang.php @@ -229,4 +229,20 @@ $lang['i_pol2'] = 'Closed Wiki (read, write, upload for registered users o $lang['i_retry'] = 'Retry'; +$lang['mu_intro'] = 'Here you can upload multiple files at once. Click the browse button to add them to the queue. Press upload when done.'; +$lang['js']['mu_btn'] = 'Upload multiple files at once'; +$lang['mu_gridname'] = 'Filename'; +$lang['mu_gridsize'] = 'Size'; +$lang['mu_gridstat'] = 'Status'; +$lang['mu_namespace'] = 'Namespace'; +$lang['mu_browse'] = 'Browse'; +$lang['mu_toobig'] = 'too big'; +$lang['mu_ready'] = 'ready for upload'; +$lang['mu_done'] = 'complete'; +$lang['mu_fail'] = 'failed'; +$lang['mu_authfail'] = 'session expired'; +$lang['mu_progress'] = '@PCT@% uploaded'; +$lang['mu_filetypes'] = 'Allowed Filetypes'; + + //Setup VIM: ex: et ts=2 enc=utf-8 : diff --git a/inc/media.php b/inc/media.php index 663a35051..a65b94e26 100644 --- a/inc/media.php +++ b/inc/media.php @@ -189,7 +189,7 @@ function media_delete($id,$auth){ * Handles media file uploads * * This generates an action event and delegates to _media_upload_action(). - * Action plugins are allowed to pre/postprocess the uploaded file. + * Action plugins are allowed to pre/postprocess the uploaded file. * (The triggered event is preventable.) * * Event data: @@ -239,7 +239,7 @@ function media_upload($ns,$auth){ // because a temp file was created already if(preg_match('/\.('.$regex.')$/i',$fn)){ //check for overwrite - if(@file_exists($fn) && (!$_POST['ow'] || $auth < AUTH_DELETE)){ + if(@file_exists($fn) && (!$_REQUEST['ow'] || $auth < AUTH_DELETE)){ msg($lang['uploadexist'],0); return false; } @@ -568,8 +568,9 @@ function media_uploadform($ns, $auth){ if($auth < AUTH_UPLOAD) return; //fixme print info on missing permissions? - print '<div class="upload">' . $lang['mediaupload'] . '</div>'; + // The default HTML upload form $form = new Doku_Form('dw__upload', DOKU_BASE.'lib/exe/mediamanager.php', false, 'multipart/form-data'); + $form->addElement('<div class="upload">' . $lang['mediaupload'] . '</div>'); $form->addElement(formSecurityToken()); $form->addHidden('ns', hsc($ns)); $form->addElement(form_makeOpenTag('p')); @@ -585,8 +586,54 @@ function media_uploadform($ns, $auth){ $form->addElement(form_makeCheckboxField('ow', 1, $lang['txt_overwrt'], 'dw__ow', 'check')); $form->addElement(form_makeCloseTag('p')); } - html_form('upload', $form); + + // prepare flashvars for multiupload + $opt = array( + 'L_gridname' => $lang['mu_gridname'] , + 'L_gridsize' => $lang['mu_gridsize'] , + 'L_gridstat' => $lang['mu_gridstat'] , + 'L_namespace' => $lang['mu_namespace'] , + 'L_overwrite' => $lang['txt_overwrt'], + 'L_browse' => $lang['mu_browse'], + 'L_upload' => $lang['btn_upload'], + 'L_toobig' => $lang['mu_toobig'], + 'L_ready' => $lang['mu_ready'], + 'L_done' => $lang['mu_done'], + 'L_fail' => $lang['mu_fail'], + 'L_authfail' => $lang['mu_authfail'], + 'L_progress' => $lang['mu_progress'], + 'L_filetypes' => $lang['mu_filetypes'], + + 'O_ns' => ":$ns", + 'O_backend' => 'mediamanager.php?'.session_name().'='.session_id(), + 'O_size' => php_to_byte(ini_get('upload_max_filesize')), + 'O_extensions'=> join('|',array_keys(getMimeTypes())), + 'O_overwrite' => ($auth >= AUTH_DELETE), + 'O_sectok' => getSecurityToken(), + 'O_authtok' => auth_createToken(), + ); + $var = buildURLparams($opt,'&'); + // output the flash uploader + ?> + <div id="dw__flashupload" style="display:none"> + <div class="upload"><?php echo $lang['mu_intro']?></div> + <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="100%" height="100%" + codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab"> + <param name="movie" value="multipleUpload.swf?t=<?=time()?>" /> + <param name="quality" value="high" /> + <param name="bgcolor" value="#ffffff" /> + <param name="FlashVars" value="<?php echo $var?>" /> + <embed src="multipleUpload.swf?t=<?=time()?>" quality="high" bgcolor="#ffffff" + width="100%" height="100%" name="fileUpload" align="middle" + play="true" loop="false" quality="high" FlashVars="<?php echo $var?>" + allowScriptAccess="sameDomain" + type="application/x-shockwave-flash" + pluginspage="http://www.macromedia.com/go/getflashplayer"> + </embed> + </object> + </div> + <?php } /** 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; |