summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/_fla/.htaccess3
-rw-r--r--lib/_fla/MultipleUpload.as274
-rw-r--r--lib/_fla/README1
-rw-r--r--lib/_fla/multipleUpload.flabin0 -> 1812992 bytes
-rw-r--r--lib/exe/mediamanager.php16
-rw-r--r--lib/exe/multipleUpload.swfbin0 -> 64353 bytes
-rw-r--r--lib/images/multiupload.pngbin0 -> 698 bytes
-rw-r--r--lib/scripts/helpers.js278
-rw-r--r--lib/scripts/media.js21
-rw-r--r--lib/tpl/default/media.css3
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 += '&sectok='+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
new file mode 100644
index 000000000..a04237c1c
--- /dev/null
+++ b/lib/_fla/multipleUpload.fla
Binary files differ
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
new file mode 100644
index 000000000..6921cbb45
--- /dev/null
+++ b/lib/exe/multipleUpload.swf
Binary files differ
diff --git a/lib/images/multiupload.png b/lib/images/multiupload.png
new file mode 100644
index 000000000..1e8efa063
--- /dev/null
+++ b/lib/images/multiupload.png
Binary files differ
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;