Merge pull request #4766 from owncloud/fix_3728_with_file_exists_dialog
file upload conflicts dialog
This commit is contained in:
commit
09cfebe936
|
@ -78,7 +78,7 @@ foreach ($_FILES['files']['error'] as $error) {
|
|||
}
|
||||
$files = $_FILES['files'];
|
||||
|
||||
$error = '';
|
||||
$error = false;
|
||||
|
||||
$maxUploadFileSize = $storageStats['uploadMaxFilesize'];
|
||||
$maxHumanFileSize = OCP\Util::humanFileSize($maxUploadFileSize);
|
||||
|
@ -98,23 +98,57 @@ $result = array();
|
|||
if (strpos($dir, '..') === false) {
|
||||
$fileCount = count($files['name']);
|
||||
for ($i = 0; $i < $fileCount; $i++) {
|
||||
$target = OCP\Files::buildNotExistingFileName(stripslashes($dir), $files['name'][$i]);
|
||||
// $path needs to be normalized - this failed within drag'n'drop upload to a sub-folder
|
||||
$target = \OC\Files\Filesystem::normalizePath($target);
|
||||
if (is_uploaded_file($files['tmp_name'][$i]) and \OC\Files\Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) {
|
||||
$meta = \OC\Files\Filesystem::getFileInfo($target);
|
||||
// updated max file size after upload
|
||||
$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
|
||||
if ($meta === false) {
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $l->t('Upload failed')), $storageStats)));
|
||||
exit();
|
||||
if (isset($_POST['resolution']) && $_POST['resolution']==='autorename') {
|
||||
// append a number in brackets like 'filename (2).ext'
|
||||
$target = OCP\Files::buildNotExistingFileName(stripslashes($dir), $files['name'][$i]);
|
||||
} else {
|
||||
$target = \OC\Files\Filesystem::normalizePath(stripslashes($dir).'/'.$files['name'][$i]);
|
||||
}
|
||||
|
||||
if ( ! \OC\Files\Filesystem::file_exists($target)
|
||||
|| (isset($_POST['resolution']) && $_POST['resolution']==='replace')
|
||||
) {
|
||||
// upload and overwrite file
|
||||
if (is_uploaded_file($files['tmp_name'][$i]) and \OC\Files\Filesystem::fromTmpFile($files['tmp_name'][$i], $target)) {
|
||||
|
||||
// updated max file size after upload
|
||||
$storageStats = \OCA\files\lib\Helper::buildFileStorageStatistics($dir);
|
||||
|
||||
$meta = \OC\Files\Filesystem::getFileInfo($target);
|
||||
if ($meta === false) {
|
||||
$error = $l->t('Upload failed. Could not get file info.');
|
||||
} else {
|
||||
$result[] = array('status' => 'success',
|
||||
'mime' => $meta['mimetype'],
|
||||
'mtime' => $meta['mtime'],
|
||||
'size' => $meta['size'],
|
||||
'id' => $meta['fileid'],
|
||||
'name' => basename($target),
|
||||
'originalname' => $files['tmp_name'][$i],
|
||||
'uploadMaxFilesize' => $maxUploadFileSize,
|
||||
'maxHumanFilesize' => $maxHumanFileSize,
|
||||
'permissions' => $meta['permissions'],
|
||||
);
|
||||
}
|
||||
|
||||
} else {
|
||||
$result[] = array('status' => 'success',
|
||||
$error = $l->t('Upload failed. Could not find uploaded file');
|
||||
}
|
||||
|
||||
} else {
|
||||
// file already exists
|
||||
$meta = \OC\Files\Filesystem::getFileInfo($target);
|
||||
if ($meta === false) {
|
||||
$error = $l->t('Upload failed. Could not get file info.');
|
||||
} else {
|
||||
$result[] = array('status' => 'existserror',
|
||||
'mime' => $meta['mimetype'],
|
||||
'mtime' => $meta['mtime'],
|
||||
'size' => $meta['size'],
|
||||
'id' => $meta['fileid'],
|
||||
'name' => basename($target),
|
||||
'originalname' => $files['name'][$i],
|
||||
'originalname' => $files['tmp_name'][$i],
|
||||
'uploadMaxFilesize' => $maxUploadFileSize,
|
||||
'maxHumanFilesize' => $maxHumanFileSize,
|
||||
'permissions' => $meta['permissions'],
|
||||
|
@ -122,10 +156,13 @@ if (strpos($dir, '..') === false) {
|
|||
}
|
||||
}
|
||||
}
|
||||
OCP\JSON::encodedPrint($result);
|
||||
exit();
|
||||
} else {
|
||||
$error = $l->t('Invalid directory.');
|
||||
}
|
||||
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $error), $storageStats)));
|
||||
if ($error === false) {
|
||||
OCP\JSON::encodedPrint($result);
|
||||
exit();
|
||||
} else {
|
||||
OCP\JSON::error(array('data' => array_merge(array('message' => $error), $storageStats)));
|
||||
}
|
||||
|
|
|
@ -360,4 +360,3 @@ table.dragshadow td.size {
|
|||
.mask.transparent{
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
|
||||
#upload {
|
||||
height:27px; padding:0; margin-left:0.2em; overflow:hidden;
|
||||
vertical-align: top;
|
||||
}
|
||||
#upload a {
|
||||
position:relative; display:block; width:100%; height:27px;
|
||||
cursor:pointer; z-index:10;
|
||||
background-image:url('%webroot%/core/img/actions/upload.svg');
|
||||
background-repeat:no-repeat;
|
||||
background-position:7px 6px;
|
||||
opacity:0.65;
|
||||
}
|
||||
.file_upload_target { display:none; }
|
||||
.file_upload_form { display:inline; float:left; margin:0; padding:0; cursor:pointer; overflow:visible; }
|
||||
#file_upload_start {
|
||||
float: left;
|
||||
left:0; top:0; width:28px; height:27px; padding:0;
|
||||
font-size:1em;
|
||||
-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; filter:alpha(opacity=0); opacity:0;
|
||||
z-index:20; position:relative; cursor:pointer; overflow:hidden;
|
||||
}
|
||||
|
||||
#uploadprogresswrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
margin:0.3em;
|
||||
height: 29px;
|
||||
}
|
||||
#uploadprogressbar {
|
||||
position:relative;
|
||||
float: left;
|
||||
margin-left: 12px;
|
||||
width: 130px;
|
||||
height: 26px;
|
||||
display:inline-block;
|
||||
}
|
||||
#uploadprogressbar + stop {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.oc-dialog .fileexists table {
|
||||
width: 100%;
|
||||
}
|
||||
.oc-dialog .fileexists th {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
.oc-dialog .fileexists th input[type='checkbox'] {
|
||||
margin-right: 3px;
|
||||
}
|
||||
.oc-dialog .fileexists th:first-child {
|
||||
width: 230px;
|
||||
}
|
||||
.oc-dialog .fileexists th label {
|
||||
font-weight: normal;
|
||||
color:black;
|
||||
}
|
||||
.oc-dialog .fileexists th .count {
|
||||
margin-left: 3px;
|
||||
}
|
||||
.oc-dialog .fileexists .conflicts .template {
|
||||
display: none;
|
||||
}
|
||||
.oc-dialog .fileexists .conflict {
|
||||
width: 100%;
|
||||
height: 85px;
|
||||
}
|
||||
.oc-dialog .fileexists .conflict .filename {
|
||||
color:#777;
|
||||
word-break: break-all;
|
||||
clear: left;
|
||||
}
|
||||
.oc-dialog .fileexists .icon {
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
margin: 0px 5px 5px 5px;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 64px 64px;
|
||||
float: left;
|
||||
}
|
||||
.oc-dialog .fileexists .replacement {
|
||||
float: left;
|
||||
width: 230px;
|
||||
}
|
||||
.oc-dialog .fileexists .original {
|
||||
float: left;
|
||||
width: 230px;
|
||||
}
|
||||
.oc-dialog .fileexists .conflicts {
|
||||
overflow-y:scroll;
|
||||
max-height: 225px;
|
||||
}
|
||||
.oc-dialog .fileexists .conflict input[type='checkbox'] {
|
||||
float: left;
|
||||
}
|
||||
.oc-dialog .fileexists .toggle {
|
||||
background-image: url('%webroot%/core/img/actions/triangle-e.png');
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.oc-dialog .fileexists #allfileslabel {
|
||||
float:right;
|
||||
}
|
||||
.oc-dialog .fileexists #allfiles {
|
||||
vertical-align: bottom;
|
||||
position: relative;
|
||||
top: -3px;
|
||||
}
|
||||
.oc-dialog .fileexists #allfiles + span{
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.oc-dialog .oc-dialog-buttonrow {
|
||||
width:100%;
|
||||
text-align:right;
|
||||
}
|
||||
.oc-dialog .oc-dialog-buttonrow .cancel {
|
||||
float:left;
|
||||
}
|
|
@ -26,6 +26,7 @@ OCP\User::checkLoggedIn();
|
|||
|
||||
// Load the files we need
|
||||
OCP\Util::addStyle('files', 'files');
|
||||
OCP\Util::addStyle('files', 'upload');
|
||||
OCP\Util::addscript('files', 'file-upload');
|
||||
OCP\Util::addscript('files', 'jquery.iframe-transport');
|
||||
OCP\Util::addscript('files', 'jquery.fileupload');
|
||||
|
|
|
@ -1,3 +1,12 @@
|
|||
/**
|
||||
* The file upload code uses several hooks to interact with blueimps jQuery file upload library:
|
||||
* 1. the core upload handling hooks are added when initializing the plugin,
|
||||
* 2. if the browser supports progress events they are added in a separate set after the initialization
|
||||
* 3. every app can add it's own triggers for fileupload
|
||||
* - files adds d'n'd handlers and also reacts to done events to add new rows to the filelist
|
||||
* - TODO pictures upload button
|
||||
* - TODO music upload button
|
||||
*/
|
||||
|
||||
/**
|
||||
* Function that will allow us to know if Ajax uploads are supported
|
||||
|
@ -26,51 +35,278 @@ function supportAjaxUploadWithProgress() {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* keeps track of uploads in progress and implements callbacks for the conflicts dialog
|
||||
* @type {OC.Upload}
|
||||
*/
|
||||
OC.Upload = {
|
||||
_uploads: [],
|
||||
/**
|
||||
* cancels a single upload,
|
||||
* @deprecated because it was only used when a file currently beeing uploaded was deleted. Now they are added after
|
||||
* they have been uploaded.
|
||||
* @param {string} dir
|
||||
* @param {string} filename
|
||||
* @returns {unresolved}
|
||||
*/
|
||||
cancelUpload:function(dir, filename) {
|
||||
var self = this;
|
||||
var deleted = false;
|
||||
//FIXME _selections
|
||||
jQuery.each(this._uploads, function(i, jqXHR) {
|
||||
if (selection.dir === dir && selection.uploads[filename]) {
|
||||
deleted = self.deleteSelectionUpload(selection, filename);
|
||||
return false; // end searching through selections
|
||||
}
|
||||
});
|
||||
return deleted;
|
||||
},
|
||||
/**
|
||||
* deletes the jqHXR object from a data selection
|
||||
* @param {object} data
|
||||
*/
|
||||
deleteUpload:function(data) {
|
||||
delete data.jqXHR;
|
||||
},
|
||||
/**
|
||||
* cancels all uploads
|
||||
*/
|
||||
cancelUploads:function() {
|
||||
this.log('canceling uploads');
|
||||
jQuery.each(this._uploads,function(i, jqXHR){
|
||||
jqXHR.abort();
|
||||
});
|
||||
this._uploads = [];
|
||||
},
|
||||
rememberUpload:function(jqXHR){
|
||||
if (jqXHR) {
|
||||
this._uploads.push(jqXHR);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Checks the currently known uploads.
|
||||
* returns true if any hxr has the state 'pending'
|
||||
* @returns {boolean}
|
||||
*/
|
||||
isProcessing:function(){
|
||||
var count = 0;
|
||||
|
||||
jQuery.each(this._uploads,function(i, data){
|
||||
if (data.state() === 'pending') {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
return count > 0;
|
||||
},
|
||||
/**
|
||||
* callback for the conflicts dialog
|
||||
* @param {object} data
|
||||
*/
|
||||
onCancel:function(data) {
|
||||
this.cancelUploads();
|
||||
},
|
||||
/**
|
||||
* callback for the conflicts dialog
|
||||
* calls onSkip, onReplace or onAutorename for each conflict
|
||||
* @param {object} conflicts - list of conflict elements
|
||||
*/
|
||||
onContinue:function(conflicts) {
|
||||
var self = this;
|
||||
//iterate over all conflicts
|
||||
jQuery.each(conflicts, function (i, conflict) {
|
||||
conflict = $(conflict);
|
||||
var keepOriginal = conflict.find('.original input[type="checkbox"]:checked').length === 1;
|
||||
var keepReplacement = conflict.find('.replacement input[type="checkbox"]:checked').length === 1;
|
||||
if (keepOriginal && keepReplacement) {
|
||||
// when both selected -> autorename
|
||||
self.onAutorename(conflict.data('data'));
|
||||
} else if (keepReplacement) {
|
||||
// when only replacement selected -> overwrite
|
||||
self.onReplace(conflict.data('data'));
|
||||
} else {
|
||||
// when only original seleted -> skip
|
||||
// when none selected -> skip
|
||||
self.onSkip(conflict.data('data'));
|
||||
}
|
||||
});
|
||||
},
|
||||
/**
|
||||
* handle skipping an upload
|
||||
* @param {object} data
|
||||
*/
|
||||
onSkip:function(data){
|
||||
this.log('skip', null, data);
|
||||
this.deleteUpload(data);
|
||||
},
|
||||
/**
|
||||
* handle replacing a file on the server with an uploaded file
|
||||
* @param {object} data
|
||||
*/
|
||||
onReplace:function(data){
|
||||
this.log('replace', null, data);
|
||||
data.data.append('resolution', 'replace');
|
||||
data.submit();
|
||||
},
|
||||
/**
|
||||
* handle uploading a file and letting the server decide a new name
|
||||
* @param {object} data
|
||||
*/
|
||||
onAutorename:function(data){
|
||||
this.log('autorename', null, data);
|
||||
if (data.data) {
|
||||
data.data.append('resolution', 'autorename');
|
||||
} else {
|
||||
data.formData.push({name:'resolution',value:'autorename'}); //hack for ie8
|
||||
}
|
||||
data.submit();
|
||||
},
|
||||
_trace:false, //TODO implement log handler for JS per class?
|
||||
log:function(caption, e, data) {
|
||||
if (this._trace) {
|
||||
console.log(caption);
|
||||
console.log(data);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* TODO checks the list of existing files prior to uploading and shows a simple dialog to choose
|
||||
* skip all, replace all or choose which files to keep
|
||||
* @param {array} selection of files to upload
|
||||
* @param {object} callbacks - object with several callback methods
|
||||
* @param {function} callbacks.onNoConflicts
|
||||
* @param {function} callbacks.onSkipConflicts
|
||||
* @param {function} callbacks.onReplaceConflicts
|
||||
* @param {function} callbacks.onChooseConflicts
|
||||
* @param {function} callbacks.onCancel
|
||||
*/
|
||||
checkExistingFiles: function (selection, callbacks){
|
||||
// TODO check filelist before uploading and show dialog on conflicts, use callbacks
|
||||
callbacks.onNoConflicts(selection);
|
||||
}
|
||||
};
|
||||
|
||||
$(document).ready(function() {
|
||||
|
||||
if ( $('#file_upload_start').length ) {
|
||||
if ( $('#file_upload_start').exists() ) {
|
||||
|
||||
var file_upload_param = {
|
||||
dropZone: $('#content'), // restrict dropZone to content div
|
||||
autoUpload: false,
|
||||
sequentialUploads: true,
|
||||
//singleFileUploads is on by default, so the data.files array will always have length 1
|
||||
/**
|
||||
* on first add of every selection
|
||||
* - check all files of originalFiles array with files in dir
|
||||
* - on conflict show dialog
|
||||
* - skip all -> remember as single skip action for all conflicting files
|
||||
* - replace all -> remember as single replace action for all conflicting files
|
||||
* - choose -> show choose dialog
|
||||
* - mark files to keep
|
||||
* - when only existing -> remember as single skip action
|
||||
* - when only new -> remember as single replace action
|
||||
* - when both -> remember as single autorename action
|
||||
* - start uploading selection
|
||||
* @param {object} e
|
||||
* @param {object} data
|
||||
* @returns {boolean}
|
||||
*/
|
||||
add: function(e, data) {
|
||||
OC.Upload.log('add', e, data);
|
||||
var that = $(this);
|
||||
|
||||
if(data.files[0].type === '' && data.files[0].size == 4096)
|
||||
{
|
||||
data.textStatus = 'dirorzero';
|
||||
data.errorThrown = t('files','Unable to upload your file as it is a directory or has 0 bytes');
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
fu._trigger('fail', e, data);
|
||||
return true; //don't upload this file but go on with next in queue
|
||||
// we need to collect all data upload objects before starting the upload so we can check their existence
|
||||
// and set individual conflict actions. unfortunately there is only one variable that we can use to identify
|
||||
// the selection a data upload is part of, so we have to collect them in data.originalFiles
|
||||
// turning singleFileUploads off is not an option because we want to gracefully handle server errors like
|
||||
// already exists
|
||||
|
||||
// create a container where we can store the data objects
|
||||
if ( ! data.originalFiles.selection ) {
|
||||
// initialize selection and remember number of files to upload
|
||||
data.originalFiles.selection = {
|
||||
uploads: [],
|
||||
filesToUpload: data.originalFiles.length,
|
||||
totalBytes: 0
|
||||
};
|
||||
}
|
||||
var selection = data.originalFiles.selection;
|
||||
|
||||
// add uploads
|
||||
if ( selection.uploads.length < selection.filesToUpload ){
|
||||
// remember upload
|
||||
selection.uploads.push(data);
|
||||
}
|
||||
|
||||
var totalSize=0;
|
||||
$.each(data.originalFiles, function(i,file){
|
||||
totalSize+=file.size;
|
||||
});
|
||||
//examine file
|
||||
var file = data.files[0];
|
||||
|
||||
if(totalSize>$('#max_upload').val()){
|
||||
if (file.type === '' && file.size === 4096) {
|
||||
data.textStatus = 'dirorzero';
|
||||
data.errorThrown = t('files', 'Unable to upload {filename} as it is a directory or has 0 bytes',
|
||||
{filename: file.name}
|
||||
);
|
||||
}
|
||||
|
||||
// add size
|
||||
selection.totalBytes += file.size;
|
||||
|
||||
//check max upload size
|
||||
if (selection.totalBytes > $('#max_upload').val()) {
|
||||
data.textStatus = 'notenoughspace';
|
||||
data.errorThrown = t('files','Not enough space available');
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
data.errorThrown = t('files', 'Not enough space available');
|
||||
}
|
||||
|
||||
// end upload for whole selection on error
|
||||
if (data.errorThrown) {
|
||||
// trigger fileupload fail
|
||||
var fu = that.data('blueimp-fileupload') || that.data('fileupload');
|
||||
fu._trigger('fail', e, data);
|
||||
return false; //don't upload anything
|
||||
}
|
||||
|
||||
// start the actual file upload
|
||||
var jqXHR = data.submit();
|
||||
// check existing files when all is collected
|
||||
if ( selection.uploads.length >= selection.filesToUpload ) {
|
||||
|
||||
//remove our selection hack:
|
||||
delete data.originalFiles.selection;
|
||||
|
||||
var callbacks = {
|
||||
|
||||
onNoConflicts: function (selection) {
|
||||
$.each(selection.uploads, function(i, upload) {
|
||||
upload.submit();
|
||||
});
|
||||
},
|
||||
onSkipConflicts: function (selection) {
|
||||
//TODO mark conflicting files as toskip
|
||||
},
|
||||
onReplaceConflicts: function (selection) {
|
||||
//TODO mark conflicting files as toreplace
|
||||
},
|
||||
onChooseConflicts: function (selection) {
|
||||
//TODO mark conflicting files as chosen
|
||||
},
|
||||
onCancel: function (selection) {
|
||||
$.each(selection.uploads, function(i, upload) {
|
||||
upload.abort();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
OC.Upload.checkExistingFiles(selection, callbacks);
|
||||
|
||||
// remember jqXHR to show warning to user when he navigates away but an upload is still in progress
|
||||
if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') {
|
||||
var dirName = data.context.data('file');
|
||||
if(typeof uploadingFiles[dirName] === 'undefined') {
|
||||
uploadingFiles[dirName] = {};
|
||||
}
|
||||
uploadingFiles[dirName][data.files[0].name] = jqXHR;
|
||||
} else {
|
||||
uploadingFiles[data.files[0].name] = jqXHR;
|
||||
}
|
||||
|
||||
return true; // continue adding files
|
||||
},
|
||||
/**
|
||||
* called after the first add, does NOT have the data param
|
||||
* @param {object} e
|
||||
*/
|
||||
start: function(e) {
|
||||
OC.Upload.log('start', e, null);
|
||||
},
|
||||
submit: function(e, data) {
|
||||
OC.Upload.rememberUpload(data);
|
||||
if ( ! data.formData ) {
|
||||
// noone set update parameters, we set the minimum
|
||||
data.formData = {
|
||||
|
@ -79,13 +315,8 @@ $(document).ready(function() {
|
|||
};
|
||||
}
|
||||
},
|
||||
/**
|
||||
* called after the first add, does NOT have the data param
|
||||
* @param e
|
||||
*/
|
||||
start: function(e) {
|
||||
},
|
||||
fail: function(e, data) {
|
||||
OC.Upload.log('fail', e, data);
|
||||
if (typeof data.textStatus !== 'undefined' && data.textStatus !== 'success' ) {
|
||||
if (data.textStatus === 'abort') {
|
||||
$('#notification').text(t('files', 'Upload cancelled.'));
|
||||
|
@ -99,14 +330,15 @@ $(document).ready(function() {
|
|||
$('#notification').fadeOut();
|
||||
}, 5000);
|
||||
}
|
||||
delete uploadingFiles[data.files[0].name];
|
||||
OC.Upload.deleteUpload(data);
|
||||
},
|
||||
/**
|
||||
* called for every successful upload
|
||||
* @param e
|
||||
* @param data
|
||||
* @param {object} e
|
||||
* @param {object} data
|
||||
*/
|
||||
done:function(e, data) {
|
||||
OC.Upload.log('done', e, data);
|
||||
// handle different responses (json or body from iframe for ie)
|
||||
var response;
|
||||
if (typeof data.result === 'string') {
|
||||
|
@ -117,33 +349,34 @@ $(document).ready(function() {
|
|||
}
|
||||
var result=$.parseJSON(response);
|
||||
|
||||
if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
|
||||
var filename = result[0].originalname;
|
||||
delete data.jqXHR;
|
||||
|
||||
// delete jqXHR reference
|
||||
if (typeof data.context !== 'undefined' && data.context.data('type') === 'dir') {
|
||||
var dirName = data.context.data('file');
|
||||
delete uploadingFiles[dirName][filename];
|
||||
if ($.assocArraySize(uploadingFiles[dirName]) == 0) {
|
||||
delete uploadingFiles[dirName];
|
||||
}
|
||||
} else {
|
||||
delete uploadingFiles[filename];
|
||||
}
|
||||
var file = result[0];
|
||||
} else {
|
||||
if(typeof result[0] === 'undefined') {
|
||||
data.textStatus = 'servererror';
|
||||
data.errorThrown = t('files', result.data.message);
|
||||
data.errorThrown = t('files', 'Could not get result from server.');
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
fu._trigger('fail', e, data);
|
||||
} else if (result[0].status === 'existserror') {
|
||||
//show "file already exists" dialog
|
||||
var original = result[0];
|
||||
var replacement = data.files[0];
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
OC.dialogs.fileexists(data, original, replacement, OC.Upload, fu);
|
||||
} else if (result[0].status !== 'success') {
|
||||
//delete data.jqXHR;
|
||||
data.textStatus = 'servererror';
|
||||
data.errorThrown = result.data.message; // error message has been translated on server
|
||||
var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
|
||||
fu._trigger('fail', e, data);
|
||||
}
|
||||
},
|
||||
/**
|
||||
* called after last upload
|
||||
* @param e
|
||||
* @param data
|
||||
* @param {object} e
|
||||
* @param {object} data
|
||||
*/
|
||||
stop: function(e, data) {
|
||||
OC.Upload.log('stop', e, data);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -155,6 +388,7 @@ $(document).ready(function() {
|
|||
|
||||
// add progress handlers
|
||||
fileupload.on('fileuploadadd', function(e, data) {
|
||||
OC.Upload.log('progress handle fileuploadadd', e, data);
|
||||
//show cancel button
|
||||
//if(data.dataType !== 'iframe') { //FIXME when is iframe used? only for ie?
|
||||
// $('#uploadprogresswrapper input.stop').show();
|
||||
|
@ -162,23 +396,29 @@ $(document).ready(function() {
|
|||
});
|
||||
// add progress handlers
|
||||
fileupload.on('fileuploadstart', function(e, data) {
|
||||
OC.Upload.log('progress handle fileuploadstart', e, data);
|
||||
$('#uploadprogresswrapper input.stop').show();
|
||||
$('#uploadprogressbar').progressbar({value:0});
|
||||
$('#uploadprogressbar').fadeIn();
|
||||
});
|
||||
fileupload.on('fileuploadprogress', function(e, data) {
|
||||
OC.Upload.log('progress handle fileuploadprogress', e, data);
|
||||
//TODO progressbar in row
|
||||
});
|
||||
fileupload.on('fileuploadprogressall', function(e, data) {
|
||||
OC.Upload.log('progress handle fileuploadprogressall', e, data);
|
||||
var progress = (data.loaded / data.total) * 100;
|
||||
$('#uploadprogressbar').progressbar('value', progress);
|
||||
});
|
||||
fileupload.on('fileuploadstop', function(e, data) {
|
||||
OC.Upload.log('progress handle fileuploadstop', e, data);
|
||||
|
||||
$('#uploadprogresswrapper input.stop').fadeOut();
|
||||
$('#uploadprogressbar').fadeOut();
|
||||
|
||||
});
|
||||
fileupload.on('fileuploadfail', function(e, data) {
|
||||
OC.Upload.log('progress handle fileuploadfail', e, data);
|
||||
//if user pressed cancel hide upload progress bar and cancel button
|
||||
if (data.errorThrown === 'abort') {
|
||||
$('#uploadprogresswrapper input.stop').fadeOut();
|
||||
|
@ -201,9 +441,9 @@ $(document).ready(function() {
|
|||
};
|
||||
|
||||
// warn user not to leave the page while upload is in progress
|
||||
$(window).bind('beforeunload', function(e) {
|
||||
if ($.assocArraySize(uploadingFiles) > 0) {
|
||||
return t('files','File upload is in progress. Leaving the page now will cancel the upload.');
|
||||
$(window).on('beforeunload', function(e) {
|
||||
if (OC.Upload.isProcessing()) {
|
||||
return t('files', 'File upload is in progress. Leaving the page now will cancel the upload.');
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -392,4 +632,5 @@ $(document).ready(function() {
|
|||
$('#new>a').click();
|
||||
});
|
||||
});
|
||||
window.file_upload_param = file_upload_param;
|
||||
});
|
||||
|
|
|
@ -177,7 +177,7 @@ $(document).ready(function () {
|
|||
FileActions.register('all', 'Delete', OC.PERMISSION_DELETE, function () {
|
||||
return OC.imagePath('core', 'actions/delete');
|
||||
}, function (filename) {
|
||||
if (Files.cancelUpload(filename)) {
|
||||
if (OC.Upload.cancelUpload($('#dir').val(), filename)) {
|
||||
if (filename.substr) {
|
||||
filename = [filename];
|
||||
}
|
||||
|
|
|
@ -680,153 +680,167 @@ $(document).ready(function(){
|
|||
|
||||
// handle upload events
|
||||
var file_upload_start = $('#file_upload_start');
|
||||
|
||||
file_upload_start.on('fileuploaddrop', function(e, data) {
|
||||
// only handle drop to dir if fileList exists
|
||||
if ($('#fileList').length > 0) {
|
||||
var dropTarget = $(e.originalEvent.target).closest('tr');
|
||||
if(dropTarget && dropTarget.data('type') === 'dir') { // drag&drop upload to folder
|
||||
var dirName = dropTarget.data('file');
|
||||
// update folder in form
|
||||
data.formData = function(form) {
|
||||
var formArray = form.serializeArray();
|
||||
// array index 0 contains the max files size
|
||||
// array index 1 contains the request token
|
||||
// array index 2 contains the directory
|
||||
var parentDir = formArray[2]['value'];
|
||||
if (parentDir === '/') {
|
||||
formArray[2]['value'] += dirName;
|
||||
} else {
|
||||
formArray[2]['value'] += '/'+dirName;
|
||||
}
|
||||
return formArray;
|
||||
OC.Upload.log('filelist handle fileuploaddrop', e, data);
|
||||
|
||||
var dropTarget = $(e.originalEvent.target).closest('tr');
|
||||
if(dropTarget && dropTarget.data('type') === 'dir') { // drag&drop upload to folder
|
||||
|
||||
// remember as context
|
||||
data.context = dropTarget;
|
||||
|
||||
var dir = dropTarget.data('file');
|
||||
|
||||
// update folder in form
|
||||
data.formData = function(form) {
|
||||
var formArray = form.serializeArray();
|
||||
// array index 0 contains the max files size
|
||||
// array index 1 contains the request token
|
||||
// array index 2 contains the directory
|
||||
var parentDir = formArray[2]['value'];
|
||||
if (parentDir === '/') {
|
||||
formArray[2]['value'] += dir;
|
||||
} else {
|
||||
formArray[2]['value'] += '/' + dir;
|
||||
}
|
||||
}
|
||||
|
||||
return formArray;
|
||||
};
|
||||
}
|
||||
|
||||
});
|
||||
file_upload_start.on('fileuploadadd', function(e, data) {
|
||||
// only add to fileList if it exists
|
||||
if ($('#fileList').length > 0) {
|
||||
OC.Upload.log('filelist handle fileuploadadd', e, data);
|
||||
|
||||
if(FileList.deleteFiles && FileList.deleteFiles.indexOf(data.files[0].name)!=-1){//finish delete if we are uploading a deleted file
|
||||
FileList.finishDelete(null, true); //delete file before continuing
|
||||
//finish delete if we are uploading a deleted file
|
||||
if(FileList.deleteFiles && FileList.deleteFiles.indexOf(data.files[0].name)!==-1){
|
||||
FileList.finishDelete(null, true); //delete file before continuing
|
||||
}
|
||||
|
||||
// add ui visualization to existing folder
|
||||
if(data.context && data.context.data('type') === 'dir') {
|
||||
// add to existing folder
|
||||
|
||||
// update upload counter ui
|
||||
var uploadtext = data.context.find('.uploadtext');
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads += 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
|
||||
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
|
||||
if(currentUploads === 1) {
|
||||
var img = OC.imagePath('core', 'loading.gif');
|
||||
data.context.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text(translatedText);
|
||||
uploadtext.show();
|
||||
} else {
|
||||
uploadtext.text(translatedText);
|
||||
}
|
||||
}
|
||||
|
||||
// add ui visualization to existing folder or as new stand-alone file?
|
||||
var dropTarget = $(e.originalEvent.target).closest('tr');
|
||||
if(dropTarget && dropTarget.data('type') === 'dir') {
|
||||
// add to existing folder
|
||||
var dirName = dropTarget.data('file');
|
||||
});
|
||||
/*
|
||||
* when file upload done successfully add row to filelist
|
||||
* update counter when uploading to sub folder
|
||||
*/
|
||||
file_upload_start.on('fileuploaddone', function(e, data) {
|
||||
OC.Upload.log('filelist handle fileuploaddone', e, data);
|
||||
|
||||
// set dir context
|
||||
data.context = $('tr').filterAttr('data-type', 'dir').filterAttr('data-file', dirName);
|
||||
var response;
|
||||
if (typeof data.result === 'string') {
|
||||
response = data.result;
|
||||
} else {
|
||||
// fetch response from iframe
|
||||
response = data.result[0].body.innerText;
|
||||
}
|
||||
var result=$.parseJSON(response);
|
||||
|
||||
if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
|
||||
var file = result[0];
|
||||
|
||||
if (data.context && data.context.data('type') === 'dir') {
|
||||
|
||||
// update upload counter ui
|
||||
var uploadtext = data.context.find('.uploadtext');
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads += 1;
|
||||
currentUploads -= 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
var translatedText = n('files', 'Uploading %n file', 'Uploading %n files', currentUploads);
|
||||
if(currentUploads === 1) {
|
||||
var img = OC.imagePath('core', 'loading.gif');
|
||||
if(currentUploads === 0) {
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
data.context.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text(translatedText);
|
||||
uploadtext.show();
|
||||
uploadtext.hide();
|
||||
} else {
|
||||
uploadtext.text(translatedText);
|
||||
}
|
||||
|
||||
// update folder size
|
||||
var size = parseInt(data.context.data('size'));
|
||||
size += parseInt(file.size);
|
||||
data.context.attr('data-size', size);
|
||||
data.context.find('td.filesize').text(humanFileSize(size));
|
||||
|
||||
} else {
|
||||
|
||||
// add as stand-alone row to filelist
|
||||
var uniqueName = getUniqueName(data.files[0].name);
|
||||
var size=t('files','Pending');
|
||||
if(data.files[0].size>=0){
|
||||
var size=t('files', 'Pending');
|
||||
if (data.files[0].size>=0){
|
||||
size=data.files[0].size;
|
||||
}
|
||||
var date=new Date();
|
||||
var param = {};
|
||||
if ($('#publicUploadRequestToken').length) {
|
||||
param.download_url = document.location.href + '&download&path=/' + $('#dir').val() + '/' + uniqueName;
|
||||
param.download_url = document.location.href + '&download&path=/' + $('#dir').val() + '/' + file.name;
|
||||
}
|
||||
// create new file context
|
||||
data.context = FileList.addFile(uniqueName,size,date,true,false,param);
|
||||
//should the file exist in the list remove it
|
||||
FileList.remove(file.name);
|
||||
|
||||
// create new file context
|
||||
data.context = FileList.addFile(file.name, file.size, date, false, false, param);
|
||||
|
||||
// update file data
|
||||
data.context.attr('data-mime',file.mime).attr('data-id',file.id);
|
||||
|
||||
var permissions = data.context.data('permissions');
|
||||
if(permissions != file.permissions) {
|
||||
data.context.attr('data-permissions', file.permissions);
|
||||
data.context.data('permissions', file.permissions);
|
||||
}
|
||||
FileActions.display(data.context.find('td.filename'));
|
||||
|
||||
var path = getPathForPreview(file.name);
|
||||
lazyLoadPreview(path, file.mime, function(previewpath){
|
||||
data.context.find('td.filename').attr('style','background-image:url('+previewpath+')');
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
file_upload_start.on('fileuploaddone', function(e, data) {
|
||||
// only update the fileList if it exists
|
||||
if ($('#fileList').length > 0) {
|
||||
var response;
|
||||
if (typeof data.result === 'string') {
|
||||
response = data.result;
|
||||
} else {
|
||||
// fetch response from iframe
|
||||
response = data.result[0].body.innerText;
|
||||
}
|
||||
var result=$.parseJSON(response);
|
||||
file_upload_start.on('fileuploadstop', function(e, data) {
|
||||
OC.Upload.log('filelist handle fileuploadstop', e, data);
|
||||
|
||||
if(typeof result[0] !== 'undefined' && result[0].status === 'success') {
|
||||
var file = result[0];
|
||||
|
||||
if (data.context.data('type') === 'file') {
|
||||
// update file data
|
||||
data.context.attr('data-mime',file.mime).attr('data-id',file.id);
|
||||
var size = data.context.data('size');
|
||||
if(size!=file.size){
|
||||
data.context.attr('data-size', file.size);
|
||||
data.context.find('td.filesize').text(humanFileSize(file.size));
|
||||
}
|
||||
var permissions = data.context.data('permissions');
|
||||
if(permissions != file.permissions) {
|
||||
data.context.attr('data-permissions', file.permissions);
|
||||
data.context.data('permissions', file.permissions);
|
||||
}
|
||||
FileActions.display(data.context.find('td.filename'));
|
||||
if (FileList.loadingDone) {
|
||||
FileList.loadingDone(file.name, file.id);
|
||||
}
|
||||
} else {
|
||||
// update upload counter ui
|
||||
var uploadtext = data.context.find('.uploadtext');
|
||||
var currentUploads = parseInt(uploadtext.attr('currentUploads'));
|
||||
currentUploads -= 1;
|
||||
uploadtext.attr('currentUploads', currentUploads);
|
||||
if(currentUploads === 0) {
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
data.context.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text('');
|
||||
uploadtext.hide();
|
||||
} else {
|
||||
uploadtext.text(currentUploads + ' ' + t('files', 'files uploading'));
|
||||
}
|
||||
|
||||
// update folder size
|
||||
var size = parseInt(data.context.data('size'));
|
||||
size += parseInt(file.size);
|
||||
data.context.attr('data-size', size);
|
||||
data.context.find('td.filesize').text(humanFileSize(size));
|
||||
|
||||
}
|
||||
}
|
||||
//if user pressed cancel hide upload chrome
|
||||
if (data.errorThrown === 'abort') {
|
||||
//cleanup uploading to a dir
|
||||
var uploadtext = $('tr .uploadtext');
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
uploadtext.parents('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.fadeOut();
|
||||
uploadtext.attr('currentUploads', 0);
|
||||
}
|
||||
});
|
||||
file_upload_start.on('fileuploadfail', function(e, data) {
|
||||
// only update the fileList if it exists
|
||||
// cleanup files, error notification has been shown by fileupload code
|
||||
var tr = data.context;
|
||||
if (typeof tr === 'undefined') {
|
||||
tr = $('tr').filterAttr('data-file', data.files[0].name);
|
||||
}
|
||||
if (tr.attr('data-type') === 'dir') {
|
||||
OC.Upload.log('filelist handle fileuploadfail', e, data);
|
||||
|
||||
//if user pressed cancel hide upload chrome
|
||||
if (data.errorThrown === 'abort') {
|
||||
//cleanup uploading to a dir
|
||||
var uploadtext = tr.find('.uploadtext');
|
||||
var uploadtext = $('tr .uploadtext');
|
||||
var img = OC.imagePath('core', 'filetypes/folder.png');
|
||||
tr.find('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.text('');
|
||||
uploadtext.hide(); //TODO really hide already
|
||||
} else {
|
||||
//remove file
|
||||
tr.fadeOut();
|
||||
tr.remove();
|
||||
uploadtext.parents('td.filename').attr('style','background-image:url('+img+')');
|
||||
uploadtext.fadeOut();
|
||||
uploadtext.attr('currentUploads', 0);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,31 +1,4 @@
|
|||
var uploadingFiles = {};
|
||||
Files={
|
||||
cancelUpload:function(filename) {
|
||||
if(uploadingFiles[filename]) {
|
||||
uploadingFiles[filename].abort();
|
||||
delete uploadingFiles[filename];
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
cancelUploads:function() {
|
||||
$.each(uploadingFiles,function(index,file) {
|
||||
if(typeof file['abort'] === 'function') {
|
||||
file.abort();
|
||||
var filename = $('tr').filterAttr('data-file',index);
|
||||
filename.hide();
|
||||
filename.find('input[type="checkbox"]').removeAttr('checked');
|
||||
filename.removeClass('selected');
|
||||
} else {
|
||||
$.each(file,function(i,f) {
|
||||
f.abort();
|
||||
delete file[i];
|
||||
});
|
||||
}
|
||||
delete uploadingFiles[index];
|
||||
});
|
||||
procesSelection();
|
||||
},
|
||||
updateMaxUploadFilesize:function(response) {
|
||||
if(response == undefined) {
|
||||
return;
|
||||
|
@ -208,7 +181,8 @@ $(document).ready(function() {
|
|||
|
||||
// Trigger cancelling of file upload
|
||||
$('#uploadprogresswrapper .stop').on('click', function() {
|
||||
Files.cancelUploads();
|
||||
OC.Upload.cancelUploads();
|
||||
procesSelection();
|
||||
});
|
||||
|
||||
// Show trash bin
|
||||
|
@ -530,7 +504,7 @@ var folderDropOptions={
|
|||
$('#notification').fadeIn();
|
||||
}
|
||||
} else {
|
||||
OC.dialogs.alert(t('Error moving file'), t('core', 'Error'));
|
||||
OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -568,7 +542,7 @@ var crumbDropOptions={
|
|||
$('#notification').fadeIn();
|
||||
}
|
||||
} else {
|
||||
OC.dialogs.alert(t('Error moving file'), t('core', 'Error'));
|
||||
OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -658,15 +632,25 @@ function getPathForPreview(name) {
|
|||
return path;
|
||||
}
|
||||
|
||||
function lazyLoadPreview(path, mime, ready) {
|
||||
getMimeIcon(mime,ready);
|
||||
var x = $('#filestable').data('preview-x');
|
||||
var y = $('#filestable').data('preview-y');
|
||||
var previewURL = OC.Router.generate('core_ajax_preview', {file: encodeURIComponent(path), x:x, y:y});
|
||||
$.get(previewURL, function() {
|
||||
previewURL = previewURL.replace('(','%28');
|
||||
previewURL = previewURL.replace(')','%29');
|
||||
ready(previewURL + '&reload=true');
|
||||
function lazyLoadPreview(path, mime, ready, width, height) {
|
||||
// get mime icon url
|
||||
getMimeIcon(mime, function(iconURL) {
|
||||
ready(iconURL); // set mimeicon URL
|
||||
|
||||
// now try getting a preview thumbnail URL
|
||||
if ( ! width ) {
|
||||
width = $('#filestable').data('preview-x');
|
||||
}
|
||||
if ( ! height ) {
|
||||
height = $('#filestable').data('preview-y');
|
||||
}
|
||||
var previewURL = OC.Router.generate('core_ajax_preview', {file: encodeURIComponent(path), x:width, y:height});
|
||||
$.get(previewURL, function() {
|
||||
previewURL = previewURL.replace('(', '%28');
|
||||
previewURL = previewURL.replace(')', '%29');
|
||||
//set preview thumbnail URL
|
||||
ready(previewURL + '&reload=true');
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* jQuery Iframe Transport Plugin 1.3
|
||||
* jQuery Iframe Transport Plugin 1.7
|
||||
* https://github.com/blueimp/jQuery-File-Upload
|
||||
*
|
||||
* Copyright 2011, Sebastian Tschan
|
||||
|
@ -30,27 +30,45 @@
|
|||
// The iframe transport accepts three additional options:
|
||||
// options.fileInput: a jQuery collection of file input fields
|
||||
// options.paramName: the parameter name for the file form data,
|
||||
// overrides the name property of the file input field(s)
|
||||
// overrides the name property of the file input field(s),
|
||||
// can be a string or an array of strings.
|
||||
// options.formData: an array of objects with name and value properties,
|
||||
// equivalent to the return data of .serializeArray(), e.g.:
|
||||
// [{name: 'a', value: 1}, {name: 'b', value: 2}]
|
||||
$.ajaxTransport('iframe', function (options) {
|
||||
if (options.async && (options.type === 'POST' || options.type === 'GET')) {
|
||||
if (options.async) {
|
||||
var form,
|
||||
iframe;
|
||||
iframe,
|
||||
addParamChar;
|
||||
return {
|
||||
send: function (_, completeCallback) {
|
||||
form = $('<form style="display:none;"></form>');
|
||||
form.attr('accept-charset', options.formAcceptCharset);
|
||||
addParamChar = /\?/.test(options.url) ? '&' : '?';
|
||||
// XDomainRequest only supports GET and POST:
|
||||
if (options.type === 'DELETE') {
|
||||
options.url = options.url + addParamChar + '_method=DELETE';
|
||||
options.type = 'POST';
|
||||
} else if (options.type === 'PUT') {
|
||||
options.url = options.url + addParamChar + '_method=PUT';
|
||||
options.type = 'POST';
|
||||
} else if (options.type === 'PATCH') {
|
||||
options.url = options.url + addParamChar + '_method=PATCH';
|
||||
options.type = 'POST';
|
||||
}
|
||||
// javascript:false as initial iframe src
|
||||
// prevents warning popups on HTTPS in IE6.
|
||||
// IE versions below IE8 cannot set the name property of
|
||||
// elements that have already been added to the DOM,
|
||||
// so we set the name along with the iframe HTML markup:
|
||||
counter += 1;
|
||||
iframe = $(
|
||||
'<iframe src="javascript:false;" name="iframe-transport-' +
|
||||
(counter += 1) + '"></iframe>'
|
||||
counter + '"></iframe>'
|
||||
).bind('load', function () {
|
||||
var fileInputClones;
|
||||
var fileInputClones,
|
||||
paramNames = $.isArray(options.paramName) ?
|
||||
options.paramName : [options.paramName];
|
||||
iframe
|
||||
.unbind('load')
|
||||
.bind('load', function () {
|
||||
|
@ -79,7 +97,12 @@
|
|||
// (happens on form submits to iframe targets):
|
||||
$('<iframe src="javascript:false;"></iframe>')
|
||||
.appendTo(form);
|
||||
form.remove();
|
||||
window.setTimeout(function () {
|
||||
// Removing the form in a setTimeout call
|
||||
// allows Chrome's developer tools to display
|
||||
// the response result
|
||||
form.remove();
|
||||
}, 0);
|
||||
});
|
||||
form
|
||||
.prop('target', iframe.prop('name'))
|
||||
|
@ -101,8 +124,11 @@
|
|||
return fileInputClones[index];
|
||||
});
|
||||
if (options.paramName) {
|
||||
options.fileInput.each(function () {
|
||||
$(this).prop('name', options.paramName);
|
||||
options.fileInput.each(function (index) {
|
||||
$(this).prop(
|
||||
'name',
|
||||
paramNames[index] || options.paramName
|
||||
);
|
||||
});
|
||||
}
|
||||
// Appending the file input fields to the hidden form
|
||||
|
@ -144,20 +170,34 @@
|
|||
});
|
||||
|
||||
// The iframe transport returns the iframe content document as response.
|
||||
// The following adds converters from iframe to text, json, html, and script:
|
||||
// The following adds converters from iframe to text, json, html, xml
|
||||
// and script.
|
||||
// Please note that the Content-Type for JSON responses has to be text/plain
|
||||
// or text/html, if the browser doesn't include application/json in the
|
||||
// Accept header, else IE will show a download dialog.
|
||||
// The Content-Type for XML responses on the other hand has to be always
|
||||
// application/xml or text/xml, so IE properly parses the XML response.
|
||||
// See also
|
||||
// https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation
|
||||
$.ajaxSetup({
|
||||
converters: {
|
||||
'iframe text': function (iframe) {
|
||||
return $(iframe[0].body).text();
|
||||
return iframe && $(iframe[0].body).text();
|
||||
},
|
||||
'iframe json': function (iframe) {
|
||||
return $.parseJSON($(iframe[0].body).text());
|
||||
return iframe && $.parseJSON($(iframe[0].body).text());
|
||||
},
|
||||
'iframe html': function (iframe) {
|
||||
return $(iframe[0].body).html();
|
||||
return iframe && $(iframe[0].body).html();
|
||||
},
|
||||
'iframe xml': function (iframe) {
|
||||
var xmlDoc = iframe && iframe[0];
|
||||
return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc :
|
||||
$.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) ||
|
||||
$(xmlDoc.body).html());
|
||||
},
|
||||
'iframe script': function (iframe) {
|
||||
return $.globalEval($(iframe[0].body).text());
|
||||
return iframe && $.globalEval($(iframe[0].body).text());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<div id="{dialog_name}" title="{title}" class="fileexists">
|
||||
<span class="why">{why}<!-- Which files do you want to keep --></span><br/>
|
||||
<span class="what">{what}<!-- If you select both versions, the copied file will have a number added to its name. --></span><br/>
|
||||
<br/>
|
||||
<table>
|
||||
<th><label><input class="allnewfiles" type="checkbox" />New Files<span class="count"></span></label></th>
|
||||
<th><label><input class="allexistingfiles" type="checkbox" />Already existing files<span class="count"></span></label></th>
|
||||
</table>
|
||||
<div class="conflicts">
|
||||
<div class="template">
|
||||
<div class="filename"></div>
|
||||
<div class="replacement">
|
||||
<input type="checkbox" />
|
||||
<span class="svg icon"></span>
|
||||
<div class="mtime"></div>
|
||||
<div class="size"></div>
|
||||
</div>
|
||||
<div class="original">
|
||||
<input type="checkbox" />
|
||||
<span class="svg icon"></span>
|
||||
<div class="mtime"></div>
|
||||
<div class="size"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -62,6 +62,9 @@ $(document).ready(function() {
|
|||
$('#controls').append($('#additional_controls div#uploadprogresswrapper'));
|
||||
|
||||
// Cancel upload trigger
|
||||
$('#cancel_upload_button').click(Files.cancelUploads);
|
||||
$('#cancel_upload_button').click(function() {
|
||||
OC.Upload.cancelUploads();
|
||||
procesSelection();
|
||||
});
|
||||
|
||||
});
|
||||
|
|
|
@ -170,6 +170,7 @@ if (isset($path)) {
|
|||
$tmpl->assign('dir', $getPath);
|
||||
|
||||
OCP\Util::addStyle('files', 'files');
|
||||
OCP\Util::addStyle('files', 'upload');
|
||||
OCP\Util::addScript('files', 'files');
|
||||
OCP\Util::addScript('files', 'filelist');
|
||||
OCP\Util::addscript('files', 'keyboardshortcuts');
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 174 B |
|
@ -0,0 +1,4 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://www.w3.org/2000/svg" height="16px" width="16px" version="1.1" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<path style="block-progression:tb;color:#000000;text-transform:none;text-indent:0" d="m4 12 8-4-7.989-4z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 395 B |
|
@ -103,6 +103,9 @@
|
|||
}
|
||||
$.each(value, function(idx, val) {
|
||||
var $button = $('<button>').text(val.text);
|
||||
if (val.classes) {
|
||||
$button.addClass(val.classes);
|
||||
}
|
||||
if(val.defaultButton) {
|
||||
$button.addClass('primary');
|
||||
self.$defaultButton = $button;
|
||||
|
|
|
@ -220,6 +220,245 @@ var OCdialogs = {
|
|||
}
|
||||
});
|
||||
},
|
||||
_fileexistsshown: false,
|
||||
/**
|
||||
* Displays file exists dialog
|
||||
* @param {object} data upload object
|
||||
* @param {object} original file with name, size and mtime
|
||||
* @param {object} replacement file with name, size and mtime
|
||||
* @param {object} controller with onCancel, onSkip, onReplace and onRename methods
|
||||
*/
|
||||
fileexists:function(data, original, replacement, controller) {
|
||||
var self = this;
|
||||
|
||||
var getCroppedPreview = function(file) {
|
||||
var deferred = new $.Deferred();
|
||||
// Only process image files.
|
||||
var type = file.type.split('/').shift();
|
||||
if (window.FileReader && type === 'image') {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function (e) {
|
||||
var blob = new Blob([e.target.result]);
|
||||
window.URL = window.URL || window.webkitURL;
|
||||
var originalUrl = window.URL.createObjectURL(blob);
|
||||
var image = new Image();
|
||||
image.src = originalUrl;
|
||||
image.onload = function () {
|
||||
var url = crop(image);
|
||||
deferred.resolve(url);
|
||||
}
|
||||
};
|
||||
reader.readAsArrayBuffer(file);
|
||||
} else {
|
||||
deferred.reject();
|
||||
}
|
||||
return deferred;
|
||||
};
|
||||
|
||||
var crop = function(img) {
|
||||
var canvas = document.createElement('canvas'),
|
||||
width = img.width,
|
||||
height = img.height,
|
||||
x, y, size;
|
||||
|
||||
// calculate the width and height, constraining the proportions
|
||||
if (width > height) {
|
||||
y = 0;
|
||||
x = (width - height) / 2;
|
||||
} else {
|
||||
y = (height - width) / 2;
|
||||
x = 0;
|
||||
}
|
||||
size = Math.min(width, height);
|
||||
|
||||
// resize the canvas and draw the image data into it
|
||||
canvas.width = 64;
|
||||
canvas.height = 64;
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.drawImage(img, x, y, size, size, 0, 0, 64, 64);
|
||||
return canvas.toDataURL("image/png", 0.7);
|
||||
};
|
||||
|
||||
var addConflict = function(conflicts, original, replacement) {
|
||||
|
||||
var conflict = conflicts.find('.template').clone().removeClass('template').addClass('conflict');
|
||||
|
||||
conflict.data('data',data);
|
||||
|
||||
conflict.find('.filename').text(original.name);
|
||||
conflict.find('.original .size').text(humanFileSize(original.size));
|
||||
conflict.find('.original .mtime').text(formatDate(original.mtime*1000));
|
||||
// ie sucks
|
||||
if (replacement.size && replacement.lastModifiedDate) {
|
||||
conflict.find('.replacement .size').text(humanFileSize(replacement.size));
|
||||
conflict.find('.replacement .mtime').text(formatDate(replacement.lastModifiedDate));
|
||||
}
|
||||
var path = getPathForPreview(original.name);
|
||||
lazyLoadPreview(path, original.type, function(previewpath){
|
||||
conflict.find('.original .icon').css('background-image','url('+previewpath+')');
|
||||
}, 96, 96);
|
||||
getCroppedPreview(replacement).then(
|
||||
function(path){
|
||||
conflict.find('.replacement .icon').css('background-image','url(' + path + ')');
|
||||
}, function(){
|
||||
getMimeIcon(replacement.type,function(path){
|
||||
conflict.find('.replacement .icon').css('background-image','url(' + path + ')');
|
||||
});
|
||||
}
|
||||
);
|
||||
conflicts.append(conflict);
|
||||
|
||||
//set more recent mtime bold
|
||||
// ie sucks
|
||||
if (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() > original.mtime*1000) {
|
||||
conflict.find('.replacement .mtime').css('font-weight', 'bold');
|
||||
} else if (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() < original.mtime*1000) {
|
||||
conflict.find('.original .mtime').css('font-weight', 'bold');
|
||||
} else {
|
||||
//TODO add to same mtime collection?
|
||||
}
|
||||
|
||||
// set bigger size bold
|
||||
if (replacement.size && replacement.size > original.size) {
|
||||
conflict.find('.replacement .size').css('font-weight', 'bold');
|
||||
} else if (replacement.size && replacement.size < original.size) {
|
||||
conflict.find('.original .size').css('font-weight', 'bold');
|
||||
} else {
|
||||
//TODO add to same size collection?
|
||||
}
|
||||
|
||||
//TODO show skip action for files with same size and mtime in bottom row
|
||||
|
||||
};
|
||||
//var selection = controller.getSelection(data.originalFiles);
|
||||
//if (selection.defaultAction) {
|
||||
// controller[selection.defaultAction](data);
|
||||
//} else {
|
||||
var dialog_name = 'oc-dialog-fileexists-content';
|
||||
var dialog_id = '#' + dialog_name;
|
||||
if (this._fileexistsshown) {
|
||||
// add conflict
|
||||
|
||||
var conflicts = $(dialog_id+ ' .conflicts');
|
||||
addConflict(conflicts, original, replacement);
|
||||
|
||||
var count = $(dialog_id+ ' .conflict').length;
|
||||
var title = n('files',
|
||||
'{count} file conflict',
|
||||
'{count} file conflicts',
|
||||
count,
|
||||
{count:count}
|
||||
);
|
||||
$(dialog_id).parent().children('.oc-dialog-title').text(title);
|
||||
|
||||
//recalculate dimensions
|
||||
$(window).trigger('resize');
|
||||
|
||||
} else {
|
||||
//create dialog
|
||||
this._fileexistsshown = true;
|
||||
$.when(this._getFileExistsTemplate()).then(function($tmpl) {
|
||||
var title = t('files','One file conflict');
|
||||
var $dlg = $tmpl.octemplate({
|
||||
dialog_name: dialog_name,
|
||||
title: title,
|
||||
type: 'fileexists',
|
||||
|
||||
why: t('files','Which files do you want to keep?'),
|
||||
what: t('files','If you select both versions, the copied file will have a number added to its name.')
|
||||
});
|
||||
$('body').append($dlg);
|
||||
|
||||
var conflicts = $($dlg).find('.conflicts');
|
||||
addConflict(conflicts, original, replacement);
|
||||
|
||||
buttonlist = [{
|
||||
text: t('core', 'Cancel'),
|
||||
classes: 'cancel',
|
||||
click: function(){
|
||||
if ( typeof controller.onCancel !== 'undefined') {
|
||||
controller.onCancel(data);
|
||||
}
|
||||
$(dialog_id).ocdialog('close');
|
||||
}
|
||||
},
|
||||
{
|
||||
text: t('core', 'Continue'),
|
||||
classes: 'continue',
|
||||
click: function(){
|
||||
if ( typeof controller.onContinue !== 'undefined') {
|
||||
controller.onContinue($(dialog_id + ' .conflict'));
|
||||
}
|
||||
$(dialog_id).ocdialog('close');
|
||||
}
|
||||
}];
|
||||
|
||||
$(dialog_id).ocdialog({
|
||||
width: 500,
|
||||
closeOnEscape: true,
|
||||
modal: true,
|
||||
buttons: buttonlist,
|
||||
closeButton: null,
|
||||
close: function(event, ui) {
|
||||
self._fileexistsshown = false;
|
||||
$(this).ocdialog('destroy').remove();
|
||||
}
|
||||
});
|
||||
|
||||
$(dialog_id).css('height','auto');
|
||||
|
||||
//add checkbox toggling actions
|
||||
$(dialog_id).find('.allnewfiles').on('click', function() {
|
||||
var checkboxes = $(dialog_id).find('.conflict .replacement input[type="checkbox"]');
|
||||
checkboxes.prop('checked', $(this).prop('checked'));
|
||||
});
|
||||
$(dialog_id).find('.allexistingfiles').on('click', function() {
|
||||
var checkboxes = $(dialog_id).find('.conflict .original input[type="checkbox"]');
|
||||
checkboxes.prop('checked', $(this).prop('checked'));
|
||||
});
|
||||
$(dialog_id).find('.conflicts').on('click', '.replacement,.original', function() {
|
||||
var checkbox = $(this).find('input[type="checkbox"]');
|
||||
checkbox.prop('checked', !checkbox.prop('checked'));
|
||||
});
|
||||
$(dialog_id).find('.conflicts').on('click', 'input[type="checkbox"]', function() {
|
||||
var checkbox = $(this);
|
||||
checkbox.prop('checked', !checkbox.prop('checked'));
|
||||
});
|
||||
|
||||
//update counters
|
||||
$(dialog_id).on('click', '.replacement,.allnewfiles', function() {
|
||||
var count = $(dialog_id).find('.conflict .replacement input[type="checkbox"]:checked').length;
|
||||
if (count === $(dialog_id+ ' .conflict').length) {
|
||||
$(dialog_id).find('.allnewfiles').prop('checked', true);
|
||||
$(dialog_id).find('.allnewfiles + .count').text(t('files','(all selected)'));
|
||||
} else if (count > 0) {
|
||||
$(dialog_id).find('.allnewfiles').prop('checked', false);
|
||||
$(dialog_id).find('.allnewfiles + .count').text(t('files','({count} selected)',{count:count}));
|
||||
} else {
|
||||
$(dialog_id).find('.allnewfiles').prop('checked', false);
|
||||
$(dialog_id).find('.allnewfiles + .count').text('');
|
||||
}
|
||||
});
|
||||
$(dialog_id).on('click', '.original,.allexistingfiles', function(){
|
||||
var count = $(dialog_id).find('.conflict .original input[type="checkbox"]:checked').length;
|
||||
if (count === $(dialog_id+ ' .conflict').length) {
|
||||
$(dialog_id).find('.allexistingfiles').prop('checked', true);
|
||||
$(dialog_id).find('.allexistingfiles + .count').text(t('files','(all selected)'));
|
||||
} else if (count > 0) {
|
||||
$(dialog_id).find('.allexistingfiles').prop('checked', false);
|
||||
$(dialog_id).find('.allexistingfiles + .count').text(t('files','({count} selected)',{count:count}));
|
||||
} else {
|
||||
$(dialog_id).find('.allexistingfiles').prop('checked', false);
|
||||
$(dialog_id).find('.allexistingfiles + .count').text('');
|
||||
}
|
||||
});
|
||||
})
|
||||
.fail(function() {
|
||||
alert(t('core', 'Error loading file exists template'));
|
||||
});
|
||||
}
|
||||
//}
|
||||
},
|
||||
_getFilePickerTemplate: function() {
|
||||
var defer = $.Deferred();
|
||||
if(!this.$filePickerTemplate) {
|
||||
|
@ -253,6 +492,22 @@ var OCdialogs = {
|
|||
}
|
||||
return defer.promise();
|
||||
},
|
||||
_getFileExistsTemplate: function () {
|
||||
var defer = $.Deferred();
|
||||
if (!this.$fileexistsTemplate) {
|
||||
var self = this;
|
||||
$.get(OC.filePath('files', 'templates', 'fileexists.html'), function (tmpl) {
|
||||
self.$fileexistsTemplate = $(tmpl);
|
||||
defer.resolve(self.$fileexistsTemplate);
|
||||
})
|
||||
.fail(function () {
|
||||
defer.reject();
|
||||
});
|
||||
} else {
|
||||
defer.resolve(this.$fileexistsTemplate);
|
||||
}
|
||||
return defer.promise();
|
||||
},
|
||||
_getFileList: function(dir, mimeType) {
|
||||
if (typeof(mimeType) === "string") {
|
||||
mimeType = [mimeType];
|
||||
|
|
Loading…
Reference in New Issue