aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--apps/files/ajax/list.php20
-rw-r--r--apps/files/ajax/newfile.php16
-rw-r--r--apps/files/ajax/newfolder.php4
-rw-r--r--apps/files/ajax/rawlist.php54
-rw-r--r--apps/files/ajax/upload.php47
-rw-r--r--apps/files/index.php41
-rw-r--r--apps/files/js/breadcrumb.js242
-rw-r--r--apps/files/js/file-upload.js61
-rw-r--r--apps/files/js/fileactions.js4
-rw-r--r--apps/files/js/filelist.js740
-rw-r--r--apps/files/js/files.js216
-rw-r--r--apps/files/lib/app.php20
-rw-r--r--apps/files/lib/helper.php94
-rw-r--r--apps/files/templates/index.php15
-rw-r--r--apps/files/templates/part.breadcrumb.php17
-rw-r--r--apps/files/templates/part.list.php67
-rw-r--r--apps/files/tests/ajax_rename.php30
-rw-r--r--apps/files/tests/js/breadcrumbSpec.js248
-rw-r--r--apps/files/tests/js/fileactionsSpec.js58
-rw-r--r--apps/files/tests/js/filelistSpec.js798
-rw-r--r--apps/files_sharing/ajax/list.php91
-rw-r--r--apps/files_sharing/css/public.css5
-rw-r--r--apps/files_sharing/js/public.js69
-rw-r--r--apps/files_sharing/js/share.js24
-rw-r--r--apps/files_sharing/lib/helper.php114
-rw-r--r--apps/files_sharing/public.php90
-rw-r--r--apps/files_trashbin/ajax/list.php29
-rw-r--r--apps/files_trashbin/ajax/preview.php2
-rw-r--r--apps/files_trashbin/ajax/undelete.php2
-rw-r--r--apps/files_trashbin/css/trash.css3
-rw-r--r--apps/files_trashbin/index.php42
-rw-r--r--apps/files_trashbin/js/disableDefaultActions.js1
-rw-r--r--apps/files_trashbin/js/filelist.js137
-rw-r--r--apps/files_trashbin/js/trash.js114
-rw-r--r--apps/files_trashbin/lib/helper.php83
-rw-r--r--apps/files_trashbin/templates/index.php9
-rw-r--r--apps/files_trashbin/templates/part.breadcrumb.php19
-rw-r--r--apps/files_trashbin/templates/part.list.php79
-rw-r--r--core/css/styles.css7
-rw-r--r--core/js/js.js1
-rw-r--r--core/js/oc-dialogs.js15
41 files changed, 2359 insertions, 1369 deletions
diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php
index 3bb35579d5f..0ffae22ec31 100644
--- a/apps/files/ajax/list.php
+++ b/apps/files/ajax/list.php
@@ -12,32 +12,16 @@ if (!$dirInfo->getType() === 'dir') {
exit();
}
-$doBreadcrumb = isset($_GET['breadcrumb']);
$data = array();
$baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir=';
$permissions = $dirInfo->getPermissions();
-// Make breadcrumb
-if($doBreadcrumb) {
- $breadcrumb = \OCA\Files\Helper::makeBreadcrumb($dir);
-
- $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', '');
- $breadcrumbNav->assign('breadcrumb', $breadcrumb, false);
- $breadcrumbNav->assign('baseURL', $baseUrl);
-
- $data['breadcrumb'] = $breadcrumbNav->fetchPage();
-}
-
// make filelist
$files = \OCA\Files\Helper::getFiles($dir);
-$list = new OCP\Template("files", "part.list", "");
-$list->assign('files', $files, false);
-$list->assign('baseURL', $baseUrl, false);
-$list->assign('downloadURL', OCP\Util::linkToRoute('download', array('file' => '/')));
-$list->assign('isPublic', false);
-$data['files'] = $list->fetchPage();
+$data['directory'] = $dir;
+$data['files'] = \OCA\Files\Helper::formatFileInfos($files);
$data['permissions'] = $permissions;
OCP\JSON::success(array('data' => $data));
diff --git a/apps/files/ajax/newfile.php b/apps/files/ajax/newfile.php
index 1234cf11394..7d6be59beab 100644
--- a/apps/files/ajax/newfile.php
+++ b/apps/files/ajax/newfile.php
@@ -112,9 +112,8 @@ if($source) {
}
if($result) {
$meta = \OC\Files\Filesystem::getFileInfo($target);
- $mime=$meta['mimetype'];
- $id = $meta['fileid'];
- $eventSource->send('success', array('mime' => $mime, 'size' => \OC\Files\Filesystem::filesize($target), 'id' => $id, 'etag' => $meta['etag']));
+ $data = \OCA\Files\Helper::formatFileInfo($meta);
+ $eventSource->send('success', $data);
} else {
$eventSource->send('error', array('message' => $l10n->t('Error while downloading %s to %s', array($source, $target))));
}
@@ -139,16 +138,7 @@ if($source) {
if($success) {
$meta = \OC\Files\Filesystem::getFileInfo($target);
- $id = $meta['fileid'];
- $mime = $meta['mimetype'];
- $size = $meta['size'];
- OCP\JSON::success(array('data' => array(
- 'id' => $id,
- 'mime' => $mime,
- 'size' => $size,
- 'content' => $content,
- 'etag' => $meta['etag'],
- )));
+ OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
exit();
}
}
diff --git a/apps/files/ajax/newfolder.php b/apps/files/ajax/newfolder.php
index 032447460f3..89c241189d7 100644
--- a/apps/files/ajax/newfolder.php
+++ b/apps/files/ajax/newfolder.php
@@ -58,8 +58,8 @@ if(\OC\Files\Filesystem::mkdir($target)) {
$path = '/'.$foldername;
}
$meta = \OC\Files\Filesystem::getFileInfo($path);
- $id = $meta['fileid'];
- OCP\JSON::success(array('data' => array('id' => $id)));
+ $meta['type'] = 'dir'; // missing ?!
+ OCP\JSON::success(array('data' => \OCA\Files\Helper::formatFileInfo($meta)));
exit();
}
diff --git a/apps/files/ajax/rawlist.php b/apps/files/ajax/rawlist.php
deleted file mode 100644
index f18bbffb74a..00000000000
--- a/apps/files/ajax/rawlist.php
+++ /dev/null
@@ -1,54 +0,0 @@
-<?php
-
-OCP\JSON::checkLoggedIn();
-\OC::$session->close();
-
-// Load the files
-$dir = isset($_GET['dir']) ? $_GET['dir'] : '';
-$mimetypes = isset($_GET['mimetypes']) ? json_decode($_GET['mimetypes'], true) : '';
-
-// Clean up duplicates from array and deal with non-array requests
-if (is_array($mimetypes)) {
- $mimetypes = array_unique($mimetypes);
-} elseif (is_null($mimetypes)) {
- $mimetypes = array($_GET['mimetypes']);
-}
-
-// make filelist
-$files = array();
-/**
- * @var \OCP\Files\FileInfo[] $files
- */
-// If a type other than directory is requested first load them.
-if ($mimetypes && !in_array('httpd/unix-directory', $mimetypes)) {
- $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir, 'httpd/unix-directory'));
-}
-
-if (is_array($mimetypes) && count($mimetypes)) {
- foreach ($mimetypes as $mimetype) {
- $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir, $mimetype));
- }
-} else {
- $files = array_merge($files, \OC\Files\Filesystem::getDirectoryContent($dir));
-}
-// Sort by name
-usort($files, array('\OCA\Files\Helper', 'fileCmp'));
-
-$result = array();
-foreach ($files as $file) {
- $fileData = array();
- $fileData['directory'] = $dir;
- $fileData['name'] = $file->getName();
- $fileData['type'] = $file->getType();
- $fileData['path'] = $file['path'];
- $fileData['id'] = $file->getId();
- $fileData['size'] = $file->getSize();
- $fileData['mtime'] = $file->getMtime();
- $fileData['mimetype'] = $file->getMimetype();
- $fileData['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($file->getMimetype());
- $fileData["date"] = OCP\Util::formatDate($file->getMtime());
- $fileData['mimetype_icon'] = \OCA\Files\Helper::determineIcon($file);
- $result[] = $fileData;
-}
-
-OC_JSON::success(array('data' => $result));
diff --git a/apps/files/ajax/upload.php b/apps/files/ajax/upload.php
index 4ed51c52775..b21a9dfba2e 100644
--- a/apps/files/ajax/upload.php
+++ b/apps/files/ajax/upload.php
@@ -20,6 +20,10 @@ if (empty($_POST['dirToken'])) {
die();
}
} else {
+ // TODO: ideally this code should be in files_sharing/ajax/upload.php
+ // and the upload/file transfer code needs to be refactored into a utility method
+ // that could be used there
+
// return only read permissions for public upload
$allowedPermissions = OCP\PERMISSION_READ;
$public_directory = !empty($_POST['subdir']) ? $_POST['subdir'] : '/';
@@ -141,19 +145,14 @@ if (strpos($dir, '..') === false) {
$error = $l->t('The target folder has been moved or deleted.');
$errorCode = 'targetnotfound';
} else {
- $result[] = array('status' => 'success',
- 'mime' => $meta['mimetype'],
- 'mtime' => $meta['mtime'],
- 'size' => $meta['size'],
- 'id' => $meta['fileid'],
- 'name' => basename($target),
- 'etag' => $meta['etag'],
- 'originalname' => $files['tmp_name'][$i],
- 'uploadMaxFilesize' => $maxUploadFileSize,
- 'maxHumanFilesize' => $maxHumanFileSize,
- 'permissions' => $meta['permissions'] & $allowedPermissions,
- 'directory' => $directory,
- );
+ $data = \OCA\Files\Helper::formatFileInfo($meta);
+ $data['status'] = 'success';
+ $data['originalname'] = $files['tmp_name'][$i];
+ $data['uploadMaxFilesize'] = $maxUploadFileSize;
+ $data['maxHumanFilesize'] = $maxHumanFileSize;
+ $data['permissions'] = $meta['permissions'] & $allowedPermissions;
+ $data['directory'] = $directory;
+ $result[] = $data;
}
} else {
@@ -169,19 +168,15 @@ if (strpos($dir, '..') === false) {
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),
- 'etag' => $meta['etag'],
- 'originalname' => $files['tmp_name'][$i],
- 'uploadMaxFilesize' => $maxUploadFileSize,
- 'maxHumanFilesize' => $maxHumanFileSize,
- 'permissions' => $meta['permissions'] & $allowedPermissions,
- 'directory' => $directory,
- );
+ $data = \OCA\Files\Helper::formatFileInfo($meta);
+ $data['permissions'] = $data['permissions'] & $allowedPermissions;
+ $data['status'] = 'existserror';
+ $data['originalname'] = $files['tmp_name'][$i];
+ $data['uploadMaxFilesize'] = $maxUploadFileSize;
+ $data['maxHumanFilesize'] = $maxHumanFileSize;
+ $data['permissions'] = $meta['permissions'] & $allowedPermissions;
+ $data['directory'] = $directory;
+ $result[] = $data;
}
}
}
diff --git a/apps/files/index.php b/apps/files/index.php
index 4d765b69e41..a575e02348a 100644
--- a/apps/files/index.php
+++ b/apps/files/index.php
@@ -32,6 +32,7 @@ OCP\Util::addscript('files', 'file-upload');
OCP\Util::addscript('files', 'jquery.iframe-transport');
OCP\Util::addscript('files', 'jquery.fileupload');
OCP\Util::addscript('files', 'jquery-visibility');
+OCP\Util::addscript('files', 'breadcrumb');
OCP\Util::addscript('files', 'filelist');
OCP\App::setActiveNavigationEntry('files_index');
@@ -60,37 +61,12 @@ if ($isIE8 && isset($_GET['dir'])){
exit();
}
-$ajaxLoad = false;
-$files = array();
$user = OC_User::getUser();
-if ($isIE8){
- // after the redirect above, the URL will have a format
- // like "files#?dir=path" which means that no path was given
- // (dir is not set). In that specific case, we don't return any
- // files because the client will take care of switching the dir
- // to the one from the hash, then ajax-load the initial file list
- $files = array();
- $ajaxLoad = true;
-}
-else{
- $files = \OCA\Files\Helper::getFiles($dir);
-}
$config = \OC::$server->getConfig();
-// Make breadcrumb
-$breadcrumb = \OCA\Files\Helper::makeBreadcrumb($dir);
-
-// make breadcrumb und filelist markup
-$list = new OCP\Template('files', 'part.list', '');
-$list->assign('files', $files);
-$list->assign('baseURL', OCP\Util::linkTo('files', 'index.php') . '?dir=');
-$list->assign('downloadURL', OCP\Util::linkToRoute('download', array('file' => '/')));
-$list->assign('isPublic', false);
-$breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', '');
-$breadcrumbNav->assign('breadcrumb', $breadcrumb);
-$breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files', 'index.php') . '?dir=');
-
+// needed for share init, permissions will be reloaded
+// anyway with ajax load
$permissions = $dirInfo->getPermissions();
// information about storage capacities
@@ -112,20 +88,12 @@ if ($trashEnabled) {
$trashEmpty = \OCA\Files_Trashbin\Trashbin::isEmpty($user);
}
-$isCreatable = \OC\Files\Filesystem::isCreatable($dir . '/');
-$fileHeader = (!isset($files) or count($files) > 0);
-$emptyContent = ($isCreatable and !$fileHeader) or $ajaxLoad;
-
OCP\Util::addscript('files', 'fileactions');
OCP\Util::addscript('files', 'files');
OCP\Util::addscript('files', 'keyboardshortcuts');
$tmpl = new OCP\Template('files', 'index', 'user');
-$tmpl->assign('fileList', $list->fetchPage());
-$tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage());
$tmpl->assign('dir', $dir);
-$tmpl->assign('isCreatable', $isCreatable);
$tmpl->assign('permissions', $permissions);
-$tmpl->assign('files', $files);
$tmpl->assign('trash', $trashEnabled);
$tmpl->assign('trashEmpty', $trashEmpty);
$tmpl->assign('uploadMaxFilesize', $maxUploadFilesize); // minimium of freeSpace and uploadLimit
@@ -141,8 +109,5 @@ $tmpl->assign("mailNotificationEnabled", $config->getAppValue('core', 'shareapi_
$tmpl->assign("allowShareWithLink", $config->getAppValue('core', 'shareapi_allow_links', 'yes'));
$tmpl->assign("encryptionInitStatus", $encryptionInitStatus);
$tmpl->assign('disableSharing', false);
-$tmpl->assign('ajaxLoad', $ajaxLoad);
-$tmpl->assign('emptyContent', $emptyContent);
-$tmpl->assign('fileHeader', $fileHeader);
$tmpl->printPage();
diff --git a/apps/files/js/breadcrumb.js b/apps/files/js/breadcrumb.js
new file mode 100644
index 00000000000..21010c7dc11
--- /dev/null
+++ b/apps/files/js/breadcrumb.js
@@ -0,0 +1,242 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+/* global OC */
+/* global SVGSupport, replaceSVG */
+(function() {
+ /**
+ * Creates an breadcrumb element in the given container
+ */
+ var BreadCrumb = function(options){
+ this.$el = $('<div class="breadcrumb"></div>');
+ options = options || {};
+ if (options.onClick) {
+ this.onClick = options.onClick;
+ }
+ if (options.onDrop) {
+ this.onDrop = options.onDrop;
+ }
+ if (options.getCrumbUrl) {
+ this.getCrumbUrl = options.getCrumbUrl;
+ }
+ };
+ BreadCrumb.prototype = {
+ $el: null,
+ dir: null,
+
+ lastWidth: 0,
+ hiddenBreadcrumbs: 0,
+ totalWidth: 0,
+ breadcrumbs: [],
+ onClick: null,
+ onDrop: null,
+
+ /**
+ * Sets the directory to be displayed as breadcrumb.
+ * This will re-render the breadcrumb.
+ * @param dir path to be displayed as breadcrumb
+ */
+ setDirectory: function(dir) {
+ dir = dir || '/';
+ if (dir !== this.dir) {
+ this.dir = dir;
+ this.render();
+ }
+ },
+
+ /**
+ * Returns the full URL to the given directory
+ * @param part crumb data as map
+ * @param index crumb index
+ * @return full URL
+ */
+ getCrumbUrl: function(part, index) {
+ return '#';
+ },
+
+ /**
+ * Renders the breadcrumb elements
+ */
+ render: function() {
+ var parts = this._makeCrumbs(this.dir || '/');
+ var $crumb;
+ this.$el.empty();
+ this.breadcrumbs = [];
+
+ for (var i = 0; i < parts.length; i++) {
+ var part = parts[i];
+ var $image;
+ var $link = $('<a></a>').attr('href', this.getCrumbUrl(part, i));
+ $link.text(part.name);
+ $crumb = $('<div class="crumb"></div>');
+ $crumb.append($link);
+ $crumb.attr('data-dir', part.dir);
+
+ if (part.img) {
+ $image = $('<img class="svg"></img>');
+ $image.attr('src', part.img);
+ $link.append($image);
+ }
+ this.breadcrumbs.push($crumb);
+ this.$el.append($crumb);
+ if (this.onClick) {
+ $crumb.on('click', this.onClick);
+ }
+ }
+ $crumb.addClass('last');
+
+ // in case svg is not supported by the browser we need to execute the fallback mechanism
+ if (!SVGSupport()) {
+ replaceSVG();
+ }
+
+ // setup drag and drop
+ if (this.onDrop) {
+ this.$el.find('.crumb:not(.last)').droppable({
+ drop: this.onDrop,
+ tolerance: 'pointer'
+ });
+ }
+
+ this._updateTotalWidth();
+ this.resize($(window).width(), true);
+ },
+
+ /**
+ * Makes a breadcrumb structure based on the given path
+ * @param dir path to split into a breadcrumb structure
+ * @return array of map {dir: path, name: displayName}
+ */
+ _makeCrumbs: function(dir) {
+ var crumbs = [];
+ var pathToHere = '';
+ // trim leading and trailing slashes
+ dir = dir.replace(/^\/+|\/+$/g, '');
+ var parts = dir.split('/');
+ if (dir === '') {
+ parts = [];
+ }
+ // root part
+ crumbs.push({
+ dir: '/',
+ name: '',
+ img: OC.imagePath('core', 'places/home.svg')
+ });
+ for (var i = 0; i < parts.length; i++) {
+ var part = parts[i];
+ pathToHere = pathToHere + '/' + part;
+ crumbs.push({
+ dir: pathToHere,
+ name: part
+ });
+ }
+ return crumbs;
+ },
+
+ _updateTotalWidth: function () {
+ var self = this;
+
+ this.lastWidth = 0;
+
+ // initialize with some extra space
+ this.totalWidth = 64;
+ // FIXME: this class should not know about global elements
+ if ( $('#navigation').length ) {
+ this.totalWidth += $('#navigation').get(0).offsetWidth;
+ }
+ this.hiddenBreadcrumbs = 0;
+
+ for (var i = 0; i < this.breadcrumbs.length; i++ ) {
+ this.totalWidth += $(this.breadcrumbs[i]).get(0).offsetWidth;
+ }
+
+ $.each($('#controls .actions>div'), function(index, action) {
+ self.totalWidth += $(action).get(0).offsetWidth;
+ });
+
+ },
+
+ /**
+ * Show/hide breadcrumbs to fit the given width
+ */
+ resize: function (width, firstRun) {
+ var i, $crumb;
+
+ if (width === this.lastWidth) {
+ return;
+ }
+
+ // window was shrinked since last time or first run ?
+ if ((width < this.lastWidth || firstRun) && width < this.totalWidth) {
+ if (this.hiddenBreadcrumbs === 0 && this.breadcrumbs.length > 1) {
+ // start by hiding the first breadcrumb after home,
+ // that one will have extra three dots displayed
+ $crumb = this.breadcrumbs[1];
+ this.totalWidth -= $crumb.get(0).offsetWidth;
+ $crumb.find('a').addClass('hidden');
+ $crumb.append('<span class="ellipsis">...</span>');
+ this.totalWidth += $crumb.get(0).offsetWidth;
+ this.hiddenBreadcrumbs = 2;
+ }
+ i = this.hiddenBreadcrumbs;
+ // hide subsequent breadcrumbs if the space is still not enough
+ while (width < this.totalWidth && i > 1 && i < this.breadcrumbs.length - 1) {
+ $crumb = this.breadcrumbs[i];
+ this.totalWidth -= $crumb.get(0).offsetWidth;
+ $crumb.addClass('hidden');
+ this.hiddenBreadcrumbs = i;
+ i++;
+ }
+ // window is bigger than last time
+ } else if (width > this.lastWidth && this.hiddenBreadcrumbs > 0) {
+ i = this.hiddenBreadcrumbs;
+ while (width > this.totalWidth && i > 0) {
+ if (this.hiddenBreadcrumbs === 1) {
+ // special handling for last one as it has the three dots
+ $crumb = this.breadcrumbs[1];
+ if ($crumb) {
+ this.totalWidth -= $crumb.get(0).offsetWidth;
+ $crumb.find('.ellipsis').remove();
+ $crumb.find('a').removeClass('hidden');
+ this.totalWidth += $crumb.get(0).offsetWidth;
+ }
+ } else {
+ $crumb = this.breadcrumbs[i];
+ $crumb.removeClass('hidden');
+ this.totalWidth += $crumb.get(0).offsetWidth;
+ if (this.totalWidth > width) {
+ this.totalWidth -= $crumb.get(0).offsetWidth;
+ $crumb.addClass('hidden');
+ break;
+ }
+ }
+ i--;
+ this.hiddenBreadcrumbs = i;
+ }
+ }
+
+ this.lastWidth = width;
+ }
+ };
+
+ window.BreadCrumb = BreadCrumb;
+})();
+
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index 371c83e742c..e5d1eacbd14 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -180,7 +180,7 @@ OC.Upload = {
},
init: function() {
- if ( $('#file_upload_start').exists() && $('#file_upload_start').is(':visible')) {
+ if ( $('#file_upload_start').exists() ) {
var file_upload_param = {
dropZone: $('#content'), // restrict dropZone to content div
@@ -483,28 +483,6 @@ OC.Upload = {
$('#file_upload_start').attr('multiple', 'multiple');
}
- //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder
- var crumb=$('div.crumb').first();
- while($('div.controls').height() > 40 && crumb.next('div.crumb').length > 0) {
- crumb.children('a').text('...');
- crumb = crumb.next('div.crumb');
- }
- //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent
- var crumb = $('div.crumb').first();
- var next = crumb.next('div.crumb');
- while($('div.controls').height()>40 && next.next('div.crumb').length > 0) {
- crumb.remove();
- crumb = next;
- next = crumb.next('div.crumb');
- }
- //still not enough, start shorting down the current folder name
- var crumb=$('div.crumb>a').last();
- while($('div.controls').height() > 40 && crumb.text().length > 6) {
- var text=crumb.text();
- text = text.substr(0,text.length-6)+'...';
- crumb.text(text);
- }
-
$(document).click(function(ev) {
// do not close when clicking in the dropdown
if ($(ev.target).closest('#new').length){
@@ -617,21 +595,7 @@ OC.Upload = {
{dir:$('#dir').val(), filename:name},
function(result) {
if (result.status === 'success') {
- var date = new Date();
- // TODO: ideally addFile should be able to receive
- // all attributes and set them automatically,
- // and also auto-load the preview
- var tr = FileList.addFile(name, 0, date, false, hidden);
- tr.attr('data-size', result.data.size);
- tr.attr('data-mime', result.data.mime);
- tr.attr('data-id', result.data.id);
- tr.attr('data-etag', result.data.etag);
- tr.find('.filesize').text(humanFileSize(result.data.size));
- var path = getPathForPreview(name);
- Files.lazyLoadPreview(path, result.data.mime, function(previewpath) {
- tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
- }, null, null, result.data.etag);
- FileActions.display(tr.find('td.filename'), true);
+ FileList.add(result.data, {hidden: hidden, insert: true});
} else {
OC.dialogs.alert(result.data.message, t('core', 'Could not create file'));
}
@@ -644,10 +608,7 @@ OC.Upload = {
{dir:$('#dir').val(), foldername:name},
function(result) {
if (result.status === 'success') {
- var date=new Date();
- FileList.addDir(name, 0, date, hidden);
- var tr = FileList.findFileEl(name);
- tr.attr('data-id', result.data.id);
+ FileList.add(result.data, {hidden: hidden, insert: true});
} else {
OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
}
@@ -682,20 +643,10 @@ OC.Upload = {
}
});
eventSource.listen('success',function(data) {
- var mime = data.mime;
- var size = data.size;
- var id = data.id;
+ var file = data;
$('#uploadprogressbar').fadeOut();
- var date = new Date();
- FileList.addFile(localName, size, date, false, hidden);
- var tr = FileList.findFileEl(localName);
- tr.data('mime', mime).data('id', id);
- tr.attr('data-id', id);
- var path = $('#dir').val()+'/'+localName;
- Files.lazyLoadPreview(path, mime, function(previewpath) {
- tr.find('td.filename').attr('style', 'background-image:url('+previewpath+')');
- }, null, null, data.etag);
- FileActions.display(tr.find('td.filename'), true);
+
+ FileList.add(file, {hidden: hidden, insert: true});
});
eventSource.listen('error',function(error) {
$('#uploadprogressbar').fadeOut();
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 732690f047a..631aebea954 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -8,7 +8,7 @@
*
*/
-/* global OC, FileList */
+/* global OC, FileList, Files */
/* global trashBinApp */
var FileActions = {
actions: {},
@@ -214,7 +214,7 @@ $(document).ready(function () {
FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () {
return OC.imagePath('core', 'actions/download');
}, function (filename) {
- var url = FileList.getDownloadUrl(filename);
+ var url = Files.getDownloadUrl(filename);
if (url) {
OC.redirect(url);
}
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index cda4e823a73..509929d0e55 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -8,17 +8,104 @@
*
*/
-/* global OC, t, n, FileList, FileActions, Files */
-/* global procesSelection, dragOptions, SVGSupport, replaceSVG */
-window.FileList={
+/* global OC, t, n, FileList, FileActions, Files, BreadCrumb */
+/* global procesSelection, dragOptions, SVGSupport */
+window.FileList = {
appName: t('files', 'Files'),
+ isEmpty: true,
useUndo:true,
- postProcessList: function() {
- $('#fileList tr').each(function() {
- //little hack to set unescape filenames in attribute
- $(this).attr('data-file',decodeURIComponent($(this).attr('data-file')));
+ $el: $('#filestable'),
+ $fileList: $('#fileList'),
+ breadcrumb: null,
+ initialized: false,
+
+ /**
+ * Initialize the file list and its components
+ */
+ initialize: function() {
+ var self = this;
+ if (this.initialized) {
+ return;
+ }
+
+ // TODO: FileList should not know about global elements
+ this.$el = $('#filestable');
+ this.$fileList = $('#fileList');
+
+ this.breadcrumb = new BreadCrumb({
+ onClick: this._onClickBreadCrumb,
+ onDrop: this._onDropOnBreadCrumb,
+ getCrumbUrl: function(part, index) {
+ return self.linkTo(part.dir);
+ }
+ });
+
+ $('#controls').prepend(this.breadcrumb.$el);
+
+ $(window).resize(function() {
+ // TODO: debounce this ?
+ var width = $(this).width();
+ FileList.breadcrumb.resize(width, false);
+ });
+ },
+
+ /**
+ * Event handler when clicking on a bread crumb
+ */
+ _onClickBreadCrumb: function(e) {
+ var $el = $(e.target).closest('.crumb'),
+ $targetDir = $el.data('dir');
+
+ if ($targetDir !== undefined) {
+ e.preventDefault();
+ FileList.changeDirectory($targetDir);
+ }
+ },
+
+ /**
+ * Event handler when dropping on a breadcrumb
+ */
+ _onDropOnBreadCrumb: function( event, ui ) {
+ var target=$(this).data('dir');
+ var dir = FileList.getCurrentDirectory();
+ while(dir.substr(0,1) === '/') {//remove extra leading /'s
+ dir=dir.substr(1);
+ }
+ dir = '/' + dir;
+ if (dir.substr(-1,1) !== '/') {
+ dir = dir + '/';
+ }
+ if (target === dir || target+'/' === dir) {
+ return;
+ }
+ var files = ui.helper.find('tr');
+ $(files).each(function(i,row) {
+ var dir = $(row).data('dir');
+ var file = $(row).data('filename');
+ //slapdash selector, tracking down our original element that the clone budded off of.
+ var origin = $('tr[data-id=' + $(row).data('origin') + ']');
+ var td = origin.children('td.filename');
+ var oldBackgroundImage = td.css('background-image');
+ td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')');
+ $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) {
+ if (result) {
+ if (result.status === 'success') {
+ FileList.remove(file);
+ procesSelection();
+ $('#notification').hide();
+ } else {
+ $('#notification').hide();
+ $('#notification').text(result.data.message);
+ $('#notification').fadeIn();
+ }
+ } else {
+ OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
+ }
+ td.css('background-image', oldBackgroundImage);
+ });
});
},
+
/**
* Sets a new page title
*/
@@ -36,64 +123,133 @@ window.FileList={
},
/**
* Returns the tr element for a given file name
+ * @param fileName file name
*/
findFileEl: function(fileName){
// use filterAttr to avoid escaping issues
- return $('#fileList tr').filterAttr('data-file', fileName);
+ return this.$fileList.find('tr').filterAttr('data-file', fileName);
},
- update:function(fileListHtml) {
- var $fileList = $('#fileList');
- $fileList.empty().html(fileListHtml);
- FileList.updateEmptyContent();
- $fileList.find('tr').each(function () {
- FileActions.display($(this).children('td.filename'));
- });
- $fileList.trigger(jQuery.Event("fileActionsReady"));
- FileList.postProcessList();
+ /**
+ * Sets the files to be displayed in the list.
+ * This operation will rerender the list and update the summary.
+ * @param filesArray array of file data (map)
+ */
+ setFiles:function(filesArray) {
+ // detach to make adding multiple rows faster
+ this.$fileList.detach();
+
+ this.$fileList.empty();
+
+ this.isEmpty = filesArray.length === 0;
+ for (var i = 0; i < filesArray.length; i++) {
+ this.add(filesArray[i], {updateSummary: false});
+ }
+
+ this.$el.find('thead').after(this.$fileList);
+
+ this.updateEmptyContent();
+ this.$fileList.trigger(jQuery.Event("fileActionsReady"));
// "Files" might not be loaded in extending apps
if (window.Files) {
Files.setupDragAndDrop();
}
- FileList.updateFileSummary();
+ this.updateFileSummary();
procesSelection();
-
$(window).scrollTop(0);
- $fileList.trigger(jQuery.Event("updated"));
+
+ this.$fileList.trigger(jQuery.Event("updated"));
+ },
+ /**
+ * If SVG is not supported, replaces the given images's extension
+ * from ".svg" to ".png".
+ * If SVG is supported, return the image path as is.
+ * @param icon image path
+ * @return fixed image path
+ */
+ _replaceSVG: function(icon) {
+ if (!SVGSupport()) {
+ var i = icon.lastIndexOf('.svg');
+ if (i >= 0) {
+ icon = icon.substr(0, i) + '.png' + icon.substr(i+4);
+ }
+ }
+ return icon;
},
- createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) {
- var td, simpleSize, basename, extension;
+ /**
+ * Creates a new table row element using the given file data.
+ * @param fileData map of file attributes
+ * @param options map of attribute "loading" whether the entry is currently loading
+ * @return new tr element (not appended to the table)
+ */
+ _createRow: function(fileData, options) {
+ var td, simpleSize, basename, extension, sizeColor,
+ icon = FileList._replaceSVG(fileData.icon),
+ name = fileData.name,
+ type = fileData.type || 'file',
+ mtime = parseInt(fileData.mtime, 10) || new Date().getTime(),
+ mime = fileData.mimetype,
+ linkUrl;
+ options = options || {};
+
+ if (type === 'dir') {
+ mime = mime || 'httpd/unix-directory';
+ }
//containing tr
var tr = $('<tr></tr>').attr({
+ "data-id" : fileData.id,
"data-type": type,
- "data-size": size,
+ "data-size": fileData.size,
"data-file": name,
- "data-permissions": permissions
+ "data-mime": mime,
+ "data-mtime": mtime,
+ "data-etag": fileData.etag,
+ "data-permissions": fileData.permissions || this.getDirectoryPermissions()
});
+
+ if (type === 'dir') {
+ // use default folder icon
+ icon = icon || OC.imagePath('core', 'filetypes/folder');
+ }
+ else {
+ icon = icon || OC.imagePath('core', 'filetypes/file');
+ }
+
// filename td
td = $('<td></td>').attr({
- "class": "filename svg",
- "style": 'background-image:url('+iconurl+'); background-size: 32px;'
+ "class": "filename",
+ "style": 'background-image:url(' + icon + '); background-size: 32px;'
});
- var rand = Math.random().toString(16).slice(2);
- td.append('<input id="select-'+rand+'" type="checkbox" /><label for="select-'+rand+'"></label>');
+
+ // linkUrl
+ if (type === 'dir') {
+ linkUrl = FileList.linkTo(FileList.getCurrentDirectory() + '/' + name);
+ }
+ else {
+ linkUrl = Files.getDownloadUrl(name, FileList.getCurrentDirectory());
+ }
+ td.append('<input id="select-' + fileData.id + '" type="checkbox" /><label for="select-' + fileData.id + '"></label>');
var link_elem = $('<a></a>').attr({
"class": "name",
- "href": linktarget
+ "href": linkUrl
});
- //split extension from filename for non dirs
+
+ // from here work on the display name
+ name = fileData.displayName || name;
+
+ // split extension from filename for non dirs
if (type !== 'dir' && name.indexOf('.') !== -1) {
- basename=name.substr(0,name.lastIndexOf('.'));
- extension=name.substr(name.lastIndexOf('.'));
+ basename = name.substr(0, name.lastIndexOf('.'));
+ extension = name.substr(name.lastIndexOf('.'));
} else {
- basename=name;
- extension=false;
+ basename = name;
+ extension = false;
}
var name_span=$('<span></span>').addClass('nametext').text(basename);
link_elem.append(name_span);
if (extension) {
name_span.append($('<span></span>').addClass('extension').text(extension));
}
- //dirs can show the number of uploaded files
+ // dirs can show the number of uploaded files
if (type === 'dir') {
link_elem.append($('<span></span>').attr({
'class': 'uploadtext',
@@ -103,99 +259,123 @@ window.FileList={
td.append(link_elem);
tr.append(td);
- //size column
- if (size !== t('files', 'Pending')) {
- simpleSize = humanFileSize(size);
+ // size column
+ if (typeof(fileData.size) !== 'undefined' && fileData.size >= 0) {
+ simpleSize = humanFileSize(parseInt(fileData.size, 10));
+ sizeColor = Math.round(160-Math.pow((fileData.size/(1024*1024)),2));
} else {
- simpleSize=t('files', 'Pending');
+ simpleSize = t('files', 'Pending');
}
- var sizeColor = Math.round(160-Math.pow((size/(1024*1024)),2));
- var lastModifiedTime = Math.round(lastModified.getTime() / 1000);
+ var lastModifiedTime = Math.round(mtime / 1000);
td = $('<td></td>').attr({
"class": "filesize",
- "style": 'color:rgb('+sizeColor+','+sizeColor+','+sizeColor+')'
+ "style": 'color:rgb(' + sizeColor + ',' + sizeColor + ',' + sizeColor + ')'
}).text(simpleSize);
tr.append(td);
// date column
- var modifiedColor = Math.round((Math.round((new Date()).getTime() / 1000)-lastModifiedTime)/60/60/24*5);
+ var modifiedColor = Math.round((Math.round((new Date()).getTime() / 1000) - mtime)/60/60/24*5);
td = $('<td></td>').attr({ "class": "date" });
td.append($('<span></span>').attr({
"class": "modified",
- "title": formatDate(lastModified),
+ "title": formatDate(mtime),
"style": 'color:rgb('+modifiedColor+','+modifiedColor+','+modifiedColor+')'
- }).text( relative_modified_date(lastModified.getTime() / 1000) ));
+ }).text( relative_modified_date(mtime / 1000) ));
+ tr.find('.filesize').text(simpleSize);
tr.append(td);
return tr;
},
- addFile:function(name, size, lastModified, loading, hidden, param) {
- var imgurl;
+ /**
+ * Adds an entry to the files table using the data from the given file data
+ * @param fileData map of file attributes
+ * @param options map of attributes:
+ * - "insert" true to insert in a sorted manner, false to append (default)
+ * - "updateSummary" true to update the summary after adding (default), false otherwise
+ * @return new tr element (not appended to the table)
+ */
+ add: function(fileData, options) {
+ options = options || {};
+ var type = fileData.type || 'file',
+ mime = fileData.mimetype,
+ permissions = parseInt(fileData.permissions, 10) || 0;
- if (!param) {
- param = {};
+ if (type === 'dir') {
+ mime = mime || 'httpd/unix-directory';
}
+ var tr = this._createRow(
+ fileData,
+ options
+ );
+ var filenameTd = tr.find('td.filename');
- var download_url = null;
- if (!param.download_url) {
- download_url = OC.generateUrl(
- 'apps/files/download{file}',
- { file: $('#dir').val()+'/'+name });
- } else {
- download_url = param.download_url;
+ // sorted insert is expensive, so needs to be explicitly
+ // requested
+ if (options.insert) {
+ this.insertElement(fileData.name, type, tr);
}
+ else {
+ this.$fileList.append(tr);
+ }
+ FileList.isEmpty = false;
- if (loading) {
- imgurl = OC.imagePath('core', 'loading.gif');
- } else {
- imgurl = OC.imagePath('core', 'filetypes/file');
- }
- var tr = this.createRow(
- 'file',
- name,
- imgurl,
- download_url,
- size,
- lastModified,
- $('#permissions').val()
- );
+ // TODO: move dragging to FileActions ?
+ // enable drag only for deletable files
+ if (permissions & OC.PERMISSION_DELETE) {
+ filenameTd.draggable(dragOptions);
+ }
+ // allow dropping on folders
+ if (fileData.type === 'dir') {
+ filenameTd.droppable(folderDropOptions);
+ }
- FileList.insertElement(name, 'file', tr);
- if (loading) {
- tr.data('loading', true);
- } else {
- tr.find('td.filename').draggable(dragOptions);
+ if (options.hidden) {
+ tr.addClass('hidden');
}
- if (hidden) {
- tr.hide();
+
+ // display actions
+ FileActions.display(filenameTd, false);
+
+ if (fileData.isPreviewAvailable) {
+ // lazy load / newly inserted td ?
+ if (!fileData.icon) {
+ Files.lazyLoadPreview(getPathForPreview(fileData.name), mime, function(url) {
+ filenameTd.css('background-image', 'url(' + url + ')');
+ }, null, null, fileData.etag);
+ }
+ else {
+ // set the preview URL directly
+ var urlSpec = {
+ file: FileList.getCurrentDirectory() + '/' + fileData.name,
+ c: fileData.etag
+ };
+ var previewUrl = Files.generatePreviewUrl(urlSpec);
+ previewUrl = previewUrl.replace('(', '%28').replace(')', '%29');
+ filenameTd.css('background-image', 'url(' + previewUrl + ')');
+ }
}
- return tr;
- },
- addDir:function(name, size, lastModified, hidden) {
-
- var tr = this.createRow(
- 'dir',
- name,
- OC.imagePath('core', 'filetypes/folder'),
- OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent($('#dir').val()+'/'+name).replace(/%2F/g, '/'),
- size,
- lastModified,
- $('#permissions').val()
- );
- FileList.insertElement(name, 'dir', tr);
- var td = tr.find('td.filename');
- td.draggable(dragOptions);
- td.droppable(folderDropOptions);
- if (hidden) {
- tr.hide();
+ // defaults to true if not defined
+ if (typeof(options.updateSummary) === 'undefined' || !!options.updateSummary) {
+ this.updateFileSummary();
+ this.updateEmptyContent();
}
- FileActions.display(tr.find('td.filename'), true);
return tr;
},
+ /**
+ * Returns the current directory
+ * @return current directory
+ */
getCurrentDirectory: function(){
return $('#dir').val() || '/';
},
/**
+ * Returns the directory permissions
+ * @return permission value as integer
+ */
+ getDirectoryPermissions: function() {
+ return parseInt($('#permissions').val(), 10);
+ },
+ /**
* @brief Changes the current directory and reload the file list.
* @param targetDir target directory (non URL encoded)
* @param changeUrl false if the URL must not be changed (defaults to true)
@@ -209,7 +389,7 @@ window.FileList={
if (!force && currentDir === targetDir) {
return;
}
- FileList.setCurrentDir(targetDir, changeUrl);
+ FileList._setCurrentDir(targetDir, changeUrl);
$('#fileList').trigger(
jQuery.Event('changeDirectory', {
dir: targetDir,
@@ -221,7 +401,13 @@ window.FileList={
linkTo: function(dir) {
return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
},
- setCurrentDir: function(targetDir, changeUrl) {
+
+ /**
+ * Sets the current directory name and updates the breadcrumb.
+ * @param targetDir directory to display
+ * @param changeUrl true to also update the URL, false otherwise (default)
+ */
+ _setCurrentDir: function(targetDir, changeUrl) {
var url,
baseDir = OC.basename(targetDir);
@@ -243,6 +429,7 @@ window.FileList={
window.location.hash = '?dir='+ encodeURIComponent(targetDir).replace(/%2F/g, '/');
}
}
+ this.breadcrumb.setDirectory(this.getCurrentDirectory());
},
/**
* @brief Reloads the file list using ajax call
@@ -253,10 +440,9 @@ window.FileList={
FileList._reloadCall.abort();
}
FileList._reloadCall = $.ajax({
- url: OC.filePath('files','ajax','list.php'),
+ url: Files.getAjaxUrl('list'),
data: {
- dir : $('#dir').val(),
- breadcrumb: true
+ dir : $('#dir').val()
},
error: function(result) {
FileList.reloadCallback(result);
@@ -269,8 +455,8 @@ window.FileList={
reloadCallback: function(result) {
var $controls = $('#controls');
- delete FileList._reloadCall;
- FileList.hideMask();
+ delete this._reloadCall;
+ this.hideMask();
if (!result || result.status === 'error') {
OC.Notification.show(result.data.message);
@@ -279,7 +465,11 @@ window.FileList={
if (result.status === 404) {
// go back home
- FileList.changeDirectory('/');
+ this.changeDirectory('/');
+ return;
+ }
+ // aborted ?
+ if (result.status === 0){
return;
}
@@ -288,24 +478,10 @@ window.FileList={
Files.updateStorageStatistics(true);
if (result.data.permissions) {
- FileList.setDirectoryPermissions(result.data.permissions);
- }
-
- if (typeof(result.data.breadcrumb) !== 'undefined') {
- $controls.find('.crumb').remove();
- $controls.prepend(result.data.breadcrumb);
-
- var width = $(window).width();
- Files.initBreadCrumbs();
- Files.resizeBreadcrumbs(width, true);
-
- // in case svg is not supported by the browser we need to execute the fallback mechanism
- if (!SVGSupport()) {
- replaceSVG();
- }
+ this.setDirectoryPermissions(result.data.permissions);
}
- FileList.update(result.data.files);
+ this.setFiles(result.data.files);
},
setDirectoryPermissions: function(permissions) {
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
@@ -322,10 +498,14 @@ window.FileList={
$('.actions,#file_action_panel').toggleClass('hidden', !show);
if (show){
// make sure to display according to permissions
- var permissions = $('#permissions').val();
+ var permissions = this.getDirectoryPermissions();
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
$('.creatable').toggleClass('hidden', !isCreatable);
$('.notCreatable').toggleClass('hidden', isCreatable);
+ // remove old style breadcrumbs (some apps might create them)
+ $('#controls .crumb').remove();
+ // refresh breadcrumbs in case it was replaced by an app
+ this.breadcrumb.render();
}
else{
$('.creatable, .notCreatable').addClass('hidden');
@@ -341,22 +521,32 @@ window.FileList={
this.showActions(!show);
$('#filestable').toggleClass('hidden', show);
},
- remove:function(name){
+ /**
+ * Removes a file entry from the list
+ * @param name name of the file to remove
+ * @param options optional options as map:
+ * "updateSummary": true to update the summary (default), false otherwise
+ */
+ remove:function(name, options){
+ options = options || {};
var fileEl = FileList.findFileEl(name);
if (fileEl.data('permissions') & OC.PERMISSION_DELETE) {
// file is only draggable when delete permissions are set
fileEl.find('td.filename').draggable('destroy');
}
fileEl.remove();
- FileList.updateFileSummary();
- if ( ! $('tr[data-file]').exists() ) {
- $('#emptycontent').removeClass('hidden');
- $('#filescontent th').addClass('hidden');
+ // TODO: improve performance on batch update
+ FileList.isEmpty = !this.$fileList.find('tr:not(.summary)').length;
+ if (typeof(options.updateSummary) === 'undefined' || !!options.updateSummary) {
+ FileList.updateEmptyContent();
+ FileList.updateFileSummary();
}
+ return fileEl;
},
insertElement:function(name, type, element) {
- //find the correct spot to insert the file or folder
- var pos, fileElements=$('tr[data-file][data-type="'+type+'"]:visible');
+ // find the correct spot to insert the file or folder
+ var pos,
+ fileElements = this.$fileList.find('tr[data-file][data-type="'+type+'"]:not(.hidden)');
if (name.localeCompare($(fileElements[0]).attr('data-file')) < 0) {
pos = -1;
} else if (name.localeCompare($(fileElements[fileElements.length-1]).attr('data-file')) > 0) {
@@ -376,35 +566,18 @@ window.FileList={
} else {
$(fileElements[pos]).after(element);
}
- } else if (type === 'dir' && $('tr[data-file]').exists()) {
- $('tr[data-file]').first().before(element);
- } else if (type === 'file' && $('tr[data-file]').exists()) {
- $('tr[data-file]').last().before(element);
+ } else if (type === 'dir' && !FileList.isEmpty) {
+ this.$fileList.find('tr[data-file]:first').before(element);
+ } else if (type === 'file' && !FileList.isEmpty) {
+ this.$fileList.find('tr[data-file]:last').before(element);
} else {
- $('#fileList').append(element);
+ this.$fileList.append(element);
}
- $('#emptycontent').addClass('hidden');
- $('#filestable th').removeClass('hidden');
+ FileList.isEmpty = false;
+ FileList.updateEmptyContent();
FileList.updateFileSummary();
},
- loadingDone:function(name, id) {
- var mime, tr = FileList.findFileEl(name);
- tr.data('loading', false);
- mime = tr.data('mime');
- tr.attr('data-mime', mime);
- if (id) {
- tr.attr('data-id', id);
- }
- var path = getPathForPreview(name);
- Files.lazyLoadPreview(path, mime, function(previewpath) {
- tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
- }, null, null, tr.attr('data-etag'));
- tr.find('td.filename').draggable(dragOptions);
- },
- isLoading:function(file) {
- return FileList.findFileEl(file).data('loading');
- },
- rename:function(oldname) {
+ rename: function(oldname) {
var tr, td, input, form;
tr = FileList.findFileEl(oldname);
tr.data('renaming',true);
@@ -438,6 +611,7 @@ window.FileList={
event.preventDefault();
try {
var newname = input.val();
+ var directory = FileList.getCurrentDirectory();
if (newname !== oldname) {
checkInput();
// save background image, because it's replaced by a spinner while async request
@@ -480,12 +654,12 @@ window.FileList={
tr.attr('data-mime', fileInfo.mime);
tr.attr('data-etag', fileInfo.etag);
if (fileInfo.isPreviewAvailable) {
- Files.lazyLoadPreview(fileInfo.directory + '/' + fileInfo.name, result.data.mime, function(previewpath) {
+ Files.lazyLoadPreview(directory + '/' + fileInfo.name, result.data.mime, function(previewpath) {
tr.find('td.filename').attr('style','background-image:url('+previewpath+')');
}, null, null, result.data.etag);
}
else {
- tr.find('td.filename').removeClass('preview').attr('style','background-image:url('+fileInfo.icon+')');
+ tr.find('td.filename').removeClass('preview').attr('style','background-image:url('+FileList._replaceSVG(fileInfo.icon)+')');
}
}
// reinsert row
@@ -554,58 +728,12 @@ window.FileList={
inList:function(file) {
return FileList.findFileEl(file).length;
},
- replace:function(oldName, newName, isNewFile) {
- // Finish any existing actions
- var oldFileEl = FileList.findFileEl(oldName);
- var newFileEl = FileList.findFileEl(newName);
- oldFileEl.hide();
- newFileEl.hide();
- var tr = oldFileEl.clone();
- tr.attr('data-replace', 'true');
- tr.attr('data-file', newName);
- var td = tr.children('td.filename');
- td.children('a.name .span').text(newName);
- var path = td.children('a.name').attr('href');
- td.children('a.name').attr('href', path.replace(encodeURIComponent(oldName), encodeURIComponent(newName)));
- var basename = newName;
- if (newName.indexOf('.') > 0) {
- basename = newName.substr(0, newName.lastIndexOf('.'));
- }
- td.children('a.name').empty();
- var span = $('<span class="nametext"></span>');
- span.text(basename);
- td.children('a.name').append(span);
- if (newName.indexOf('.') > 0) {
- span.append($('<span class="extension">'+newName.substr(newName.lastIndexOf('.'))+'</span>'));
- }
- FileList.insertElement(newName, tr.data('type'), tr);
- tr.show();
- FileList.replaceCanceled = false;
- FileList.replaceOldName = oldName;
- FileList.replaceNewName = newName;
- FileList.replaceIsNewFile = isNewFile;
- FileList.lastAction = function() {
- FileList.finishReplace();
- };
- if (!isNewFile) {
- OC.Notification.showHtml(t('files', 'replaced {new_name} with {old_name}', {new_name: newName}, {old_name: oldName})+'<span class="undo">'+t('files', 'undo')+'</span>');
- }
- },
- finishReplace:function() {
- if (!FileList.replaceCanceled && FileList.replaceOldName && FileList.replaceNewName) {
- $.ajax({url: OC.filePath('files', 'ajax', 'rename.php'), async: false, data: { dir: $('#dir').val(), newname: FileList.replaceNewName, file: FileList.replaceOldName }, success: function(result) {
- if (result && result.status === 'success') {
- $('tr[data-replace="true"').removeAttr('data-replace');
- } else {
- OC.dialogs.alert(result.data.message, 'Error moving file');
- }
- FileList.replaceCanceled = true;
- FileList.replaceOldName = null;
- FileList.replaceNewName = null;
- FileList.lastAction = null;
- }});
- }
- },
+ /**
+ * Delete the given files from the given dir
+ * @param files file names list (without path)
+ * @param dir directory in which to delete the files, defaults to the current
+ * directory
+ */
do_delete:function(files, dir) {
var params;
if (files && files.substr) {
@@ -622,7 +750,7 @@ window.FileList={
FileList.lastAction();
}
- var params = {
+ params = {
dir: dir || FileList.getCurrentDirectory()
};
if (files) {
@@ -643,10 +771,9 @@ window.FileList={
}
else {
$.each(files,function(index,file) {
- var files = FileList.findFileEl(file);
- files.remove();
- files.find('input[type="checkbox"]').removeAttr('checked');
- files.removeClass('selected');
+ var fileEl = FileList.remove(file, {updateSummary: false});
+ fileEl.find('input[type="checkbox"]').prop('checked', false);
+ fileEl.removeClass('selected');
});
}
procesSelection();
@@ -680,7 +807,7 @@ window.FileList={
});
},
createFileSummary: function() {
- if( $('#fileList tr').exists() ) {
+ if ( !FileList.isEmpty ) {
var summary = this._calculateFileSummary();
// Get translations
@@ -702,7 +829,7 @@ window.FileList={
}
var $summary = $('<tr class="summary" data-file="undefined"><td><span class="info">'+info+'</span></td>'+fileSize+'<td></td></tr>');
- $('#fileList').append($summary);
+ this.$fileList.append($summary);
var $dirInfo = $summary.find('.dirinfo');
var $fileInfo = $summary.find('.fileinfo');
@@ -710,12 +837,12 @@ window.FileList={
// Show only what's necessary, e.g.: no files: don't show "0 files"
if (summary.totalDirs === 0) {
- $dirInfo.hide();
- $connector.hide();
+ $dirInfo.addClass('hidden');
+ $connector.addClass('hidden');
}
if (summary.totalFiles === 0) {
- $fileInfo.hide();
- $connector.hide();
+ $fileInfo.addClass('hidden');
+ $connector.addClass('hidden');
}
}
},
@@ -740,10 +867,13 @@ window.FileList={
return result;
},
updateFileSummary: function() {
- var $summary = $('.summary');
+ var $summary = this.$el.find('.summary');
+
+ // always make it the last element
+ this.$fileList.append($summary.detach());
// Check if we should remove the summary to show "Upload something"
- if ($('#fileList tr').length === 1 && $summary.length === 1) {
+ if (this.isEmpty && $summary.length === 1) {
$summary.remove();
}
// If there's no summary create one (createFileSummary checks if there's data)
@@ -751,7 +881,7 @@ window.FileList={
FileList.createFileSummary();
}
// There's a summary and data -> Update the summary
- else if ($('#fileList tr').length > 1 && $summary.length === 1) {
+ else if (!this.isEmpty && $summary.length === 1) {
var fileSummary = this._calculateFileSummary();
var $dirInfo = $('.summary .dirinfo');
var $fileInfo = $('.summary .fileinfo');
@@ -764,19 +894,19 @@ window.FileList={
// Show only what's necessary (may be hidden)
if (fileSummary.totalDirs === 0) {
- $dirInfo.hide();
- $connector.hide();
+ $dirInfo.addClass('hidden');
+ $connector.addClass('hidden');
} else {
- $dirInfo.show();
+ $dirInfo.removeClass('hidden');
}
if (fileSummary.totalFiles === 0) {
- $fileInfo.hide();
- $connector.hide();
+ $fileInfo.addClass('hidden');
+ $connector.addClass('hidden');
} else {
- $fileInfo.show();
+ $fileInfo.removeClass('hidden');
}
if (fileSummary.totalDirs > 0 && fileSummary.totalFiles > 0) {
- $connector.show();
+ $connector.removeClass('hidden');
}
}
},
@@ -784,10 +914,14 @@ window.FileList={
var $fileList = $('#fileList');
var permissions = $('#permissions').val();
var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0;
- var exists = $fileList.find('tr:first').exists();
- $('#emptycontent').toggleClass('hidden', !isCreatable || exists);
- $('#filestable th').toggleClass('hidden', !exists);
+ $('#emptycontent').toggleClass('hidden', !isCreatable || !FileList.isEmpty);
+ $('#filestable thead th').toggleClass('hidden', FileList.isEmpty);
},
+ /**
+ * Shows the loading mask.
+ *
+ * @see #hideMask
+ */
showMask: function() {
// in case one was shown before
var $mask = $('#content .mask');
@@ -795,23 +929,23 @@ window.FileList={
return;
}
+ this.$el.addClass('hidden');
+
$mask = $('<div class="mask transparent"></div>');
$mask.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')');
$mask.css('background-repeat', 'no-repeat');
$('#content').append($mask);
- // block UI, but only make visible in case loading takes longer
- FileList._maskTimeout = window.setTimeout(function() {
- // reset opacity
- $mask.removeClass('transparent');
- }, 250);
+ $mask.removeClass('transparent');
},
+ /**
+ * Hide the loading mask.
+ * @see #showMask
+ */
hideMask: function() {
- var $mask = $('#content .mask').remove();
- if (FileList._maskTimeout) {
- window.clearTimeout(FileList._maskTimeout);
- }
+ $('#content .mask').remove();
+ this.$el.removeClass('hidden');
},
scrollTo:function(file) {
//scroll to and highlight preselected file
@@ -850,29 +984,11 @@ window.FileList={
*/
isAllSelected: function() {
return $('#select_all').prop('checked');
- },
-
- /**
- * Returns the download URL of the given file
- * @param filename file name of the file
- * @param dir optional directory in which the file name is, defaults to the current directory
- */
- getDownloadUrl: function(filename, dir) {
- var files = filename;
- if ($.isArray(filename)) {
- files = JSON.stringify(filename);
- }
- var params = {
- dir: dir || FileList.getCurrentDirectory(),
- files: files
- };
- return OC.filePath('files', 'ajax', 'download.php') + '?' + OC.buildQueryString(params);
}
};
$(document).ready(function() {
- var baseDir,
- isPublic = !!$('#isPublic').val();
+ FileList.initialize();
// handle upload events
var file_upload_start = $('#file_upload_start');
@@ -907,8 +1023,13 @@ $(document).ready(function() {
{name: 'requesttoken', value: oc_requesttoken}
];
};
+ } else {
+ // cancel uploads to current dir if no permission
+ var isCreatable = (FileList.getDirectoryPermissions() & OC.PERMISSION_CREATE) !== 0;
+ if (!isCreatable) {
+ return false;
+ }
}
-
});
file_upload_start.on('fileuploadadd', function(e, data) {
OC.Upload.log('filelist handle fileuploadadd', e, data);
@@ -993,31 +1114,11 @@ $(document).ready(function() {
if (data.files[0].size>=0) {
size=data.files[0].size;
}
- var date=new Date();
- var param = {};
- if ($('#publicUploadRequestToken').exists()) {
- param.download_url = document.location.href + '&download&path=/' + $('#dir').val() + '/' + file.name;
- }
//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).attr('data-etag', file.etag);
-
- 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'), true);
-
- var path = getPathForPreview(file.name);
- Files.lazyLoadPreview(path, file.mime, function(previewpath) {
- data.context.find('td.filename').attr('style','background-image:url('+previewpath+')');
- }, null, null, file.etag);
+ data.context = FileList.add(file, {insert: true});
}
}
});
@@ -1049,31 +1150,6 @@ $(document).ready(function() {
});
$('#notification').hide();
- $('#notification').on('click', '.undo', function() {
- if (FileList.deleteFiles) {
- $.each(FileList.deleteFiles,function(index,file) {
- FileList.findFileEl(file).show();
- });
- FileList.deleteCanceled=true;
- FileList.deleteFiles=null;
- } else if (FileList.replaceOldName && FileList.replaceNewName) {
- if (FileList.replaceIsNewFile) {
- // Delete the new uploaded file
- FileList.deleteCanceled = false;
- FileList.deleteFiles = [FileList.replaceOldName];
- } else {
- FileList.findFileEl(FileList.replaceOldName).show();
- }
- $('tr[data-replace="true"').remove();
- FileList.findFileEl(FileList.replaceNewName).show();
- FileList.replaceCanceled = true;
- FileList.replaceOldName = null;
- FileList.replaceNewName = null;
- FileList.replaceIsNewFile = null;
- }
- FileList.lastAction = null;
- OC.Notification.hide();
- });
$('#notification:first-child').on('click', '.replace', function() {
OC.Notification.hide(function() {
FileList.replace($('#notification > span').attr('data-oldName'), $('#notification > span').attr('data-newName'), $('#notification > span').attr('data-isNewFile'));
@@ -1081,7 +1157,7 @@ $(document).ready(function() {
});
$('#notification:first-child').on('click', '.suggest', function() {
var file = $('#notification > span').attr('data-oldName');
- FileList.findFileEl(file).show();
+ FileList.findFileEl(file).removeClass('hidden');
OC.Notification.hide();
});
$('#notification:first-child').on('click', '.cancel', function() {
@@ -1130,34 +1206,32 @@ $(document).ready(function() {
}
// disable ajax/history API for public app (TODO: until it gets ported)
- if (!isPublic) {
- // fallback to hashchange when no history support
- if (!window.history.pushState) {
- $(window).on('hashchange', function() {
- FileList.changeDirectory(parseCurrentDirFromUrl(), false);
- });
+ // fallback to hashchange when no history support
+ if (!window.history.pushState) {
+ $(window).on('hashchange', function() {
+ FileList.changeDirectory(parseCurrentDirFromUrl(), false);
+ });
+ }
+ window.onpopstate = function(e) {
+ var targetDir;
+ if (e.state && e.state.dir) {
+ targetDir = e.state.dir;
}
- window.onpopstate = function(e) {
- var targetDir;
- if (e.state && e.state.dir) {
- targetDir = e.state.dir;
- }
- else{
- // read from URL
- targetDir = parseCurrentDirFromUrl();
- }
- if (targetDir) {
- FileList.changeDirectory(targetDir, false);
- }
- };
-
- if (parseInt($('#ajaxLoad').val(), 10) === 1) {
- // need to initially switch the dir to the one from the hash (IE8)
- FileList.changeDirectory(parseCurrentDirFromUrl(), false, true);
+ else{
+ // read from URL
+ targetDir = parseCurrentDirFromUrl();
+ }
+ if (targetDir) {
+ FileList.changeDirectory(targetDir, false);
}
+ };
- FileList.setCurrentDir(parseCurrentDirFromUrl(), false);
- }
+ var dir = parseCurrentDirFromUrl();
+ // trigger ajax load, deferred to let sub-apps do their overrides first
+ setTimeout(function() {
+ FileList.changeDirectory(dir, false, true);
+ }, 0);
FileList.createFileSummary();
});
+
diff --git a/apps/files/js/files.js b/apps/files/js/files.js
index 1137364db4a..4c2d87d808c 100644
--- a/apps/files/js/files.js
+++ b/apps/files/js/files.js
@@ -161,80 +161,33 @@ var Files = {
});
},
- lastWidth: 0,
-
- initBreadCrumbs: function () {
- var $controls = $('#controls');
-
- Files.lastWidth = 0;
- Files.breadcrumbs = [];
-
- // initialize with some extra space
- Files.breadcrumbsWidth = 64;
- if ( document.getElementById("navigation") ) {
- Files.breadcrumbsWidth += $('#navigation').get(0).offsetWidth;
+ /**
+ * Returns the download URL of the given file(s)
+ * @param filename string or array of file names to download
+ * @param dir optional directory in which the file name is, defaults to the current directory
+ */
+ getDownloadUrl: function(filename, dir) {
+ if ($.isArray(filename)) {
+ filename = JSON.stringify(filename);
}
- Files.hiddenBreadcrumbs = 0;
-
- $.each($('.crumb'), function(index, breadcrumb) {
- Files.breadcrumbs[index] = breadcrumb;
- Files.breadcrumbsWidth += $(breadcrumb).get(0).offsetWidth;
- });
-
- $.each($('#controls .actions>div'), function(index, action) {
- Files.breadcrumbsWidth += $(action).get(0).offsetWidth;
- });
-
- // event handlers for breadcrumb items
- $controls.find('.crumb a').on('click', onClickBreadcrumb);
-
- // setup drag and drop
- $controls.find('.crumb:not(.last)').droppable(crumbDropOptions);
+ var params = {
+ dir: dir || FileList.getCurrentDirectory(),
+ files: filename
+ };
+ return this.getAjaxUrl('download', params);
},
- resizeBreadcrumbs: function (width, firstRun) {
- if (width !== Files.lastWidth) {
- if ((width < Files.lastWidth || firstRun) && width < Files.breadcrumbsWidth) {
- if (Files.hiddenBreadcrumbs === 0) {
- bc = $(Files.breadcrumbs[1]).get(0);
- if (typeof bc != 'undefined') {
- Files.breadcrumbsWidth -= bc.offsetWidth;
- $(Files.breadcrumbs[1]).find('a').hide();
- $(Files.breadcrumbs[1]).append('<span>...</span>');
- Files.breadcrumbsWidth += bc.offsetWidth;
- Files.hiddenBreadcrumbs = 2;
- }
- }
- var i = Files.hiddenBreadcrumbs;
- while (width < Files.breadcrumbsWidth && i > 1 && i < Files.breadcrumbs.length - 1) {
- Files.breadcrumbsWidth -= $(Files.breadcrumbs[i]).get(0).offsetWidth;
- $(Files.breadcrumbs[i]).hide();
- Files.hiddenBreadcrumbs = i;
- i++;
- }
- } else if (width > Files.lastWidth && Files.hiddenBreadcrumbs > 0) {
- var i = Files.hiddenBreadcrumbs;
- while (width > Files.breadcrumbsWidth && i > 0) {
- if (Files.hiddenBreadcrumbs === 1) {
- Files.breadcrumbsWidth -= $(Files.breadcrumbs[1]).get(0).offsetWidth;
- $(Files.breadcrumbs[1]).find('span').remove();
- $(Files.breadcrumbs[1]).find('a').show();
- Files.breadcrumbsWidth += $(Files.breadcrumbs[1]).get(0).offsetWidth;
- } else {
- $(Files.breadcrumbs[i]).show();
- Files.breadcrumbsWidth += $(Files.breadcrumbs[i]).get(0).offsetWidth;
- if (Files.breadcrumbsWidth > width) {
- Files.breadcrumbsWidth -= $(Files.breadcrumbs[i]).get(0).offsetWidth;
- $(Files.breadcrumbs[i]).hide();
- break;
- }
- }
- i--;
- Files.hiddenBreadcrumbs = i;
- }
- }
- Files.lastWidth = width;
+ /**
+ * Returns the ajax URL for a given action
+ * @param action action string
+ * @param params optional params map
+ */
+ getAjaxUrl: function(action, params) {
+ var q = '';
+ if (params) {
+ q = '?' + OC.buildQueryString(params);
}
+ return OC.filePath('files', 'ajax', action + '.php') + q;
}
};
$(document).ready(function() {
@@ -245,14 +198,10 @@ $(document).ready(function() {
Files.displayEncryptionWarning();
Files.bindKeyboardShortcuts(document, jQuery);
- FileList.postProcessList();
Files.setupDragAndDrop();
$('#file_action_panel').attr('activeAction', false);
- // allow dropping on the "files" app icon
- $('ul#apps li:first-child').data('dir','').droppable(crumbDropOptions);
-
// Triggers invisible file input
$('#upload a').on('click', function() {
$(this).parent().children('#file_upload_start').trigger('click');
@@ -311,7 +260,7 @@ $(document).ready(function() {
var filename=$(this).parent().parent().attr('data-file');
var tr = FileList.findFileEl(filename);
var renaming=tr.data('renaming');
- if (!renaming && !FileList.isLoading(filename)) {
+ if (!renaming) {
FileActions.currentFile = $(this).parent();
var mime=FileActions.getCurrentMimeType();
var type=FileActions.getCurrentType();
@@ -377,15 +326,15 @@ $(document).ready(function() {
dir = OC.dirname(dir) || '/';
}
else {
- files = getSelectedFilesTrash('name');
+ files = Files.getSelectedFiles('name');
}
OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
- OC.redirect(FileList.getDownloadUrl(files, dir));
+ OC.redirect(Files.getDownloadUrl(files, dir));
return false;
});
$('.delete-selected').click(function(event) {
- var files=getSelectedFilesTrash('name');
+ var files = Files.getSelectedFiles('name');
event.preventDefault();
if (FileList.isAllSelected()) {
files = null;
@@ -403,16 +352,6 @@ $(document).ready(function() {
//do a background scan if needed
scanFiles();
- Files.initBreadCrumbs();
-
- $(window).resize(function() {
- var width = $(this).width();
- Files.resizeBreadcrumbs(width, false);
- });
-
- var width = $(this).width();
- Files.resizeBreadcrumbs(width, true);
-
// display storage warnings
setTimeout(Files.displayStorageWarnings, 100);
OC.Notification.setDefault(Files.displayStorageWarnings);
@@ -503,7 +442,7 @@ var createDragShadow = function(event) {
$(event.target).parents('tr').find('td input:first').prop('checked',true);
}
- var selectedFiles = getSelectedFilesTrash();
+ var selectedFiles = Files.getSelectedFiles();
if (!isDragSelected && selectedFiles.length === 1) {
//revert the selection
@@ -619,52 +558,8 @@ var folderDropOptions={
tolerance: 'pointer'
};
-var crumbDropOptions={
- drop: function( event, ui ) {
- var target=$(this).data('dir');
- var dir = $('#dir').val();
- while(dir.substr(0,1) === '/') {//remove extra leading /'s
- dir=dir.substr(1);
- }
- dir = '/' + dir;
- if (dir.substr(-1,1) !== '/') {
- dir = dir + '/';
- }
- if (target === dir || target+'/' === dir) {
- return;
- }
- var files = ui.helper.find('tr');
- $(files).each(function(i,row) {
- var dir = $(row).data('dir');
- var file = $(row).data('filename');
- //slapdash selector, tracking down our original element that the clone budded off of.
- var origin = $('tr[data-id=' + $(row).data('origin') + ']');
- var td = origin.children('td.filename');
- var oldBackgroundImage = td.css('background-image');
- td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')');
- $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) {
- if (result) {
- if (result.status === 'success') {
- FileList.remove(file);
- procesSelection();
- $('#notification').hide();
- } else {
- $('#notification').hide();
- $('#notification').text(result.data.message);
- $('#notification').fadeIn();
- }
- } else {
- OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error'));
- }
- td.css('background-image', oldBackgroundImage);
- });
- });
- },
- tolerance: 'pointer'
-};
-
function procesSelection() {
- var selected = getSelectedFilesTrash();
+ var selected = Files.getSelectedFiles();
var selectedFiles = selected.filter(function(el) {
return el.type==='file';
});
@@ -714,7 +609,7 @@ function procesSelection() {
* if property is set, an array with that property for each file is returnd
* if it's ommited an array of objects with all properties is returned
*/
-function getSelectedFilesTrash(property) {
+Files.getSelectedFiles = function(property) {
var elements=$('td.filename input:checkbox:checked').parent().parent();
var files=[];
elements.each(function(i,element) {
@@ -755,25 +650,30 @@ function getPathForPreview(name) {
return path;
}
+/**
+ * Generates a preview URL based on the URL space.
+ * @param urlSpec map with {x: width, y: height, file: file path}
+ * @return preview URL
+ */
+Files.generatePreviewUrl = function(urlSpec) {
+ urlSpec = urlSpec || {};
+ if (!urlSpec.x) {
+ urlSpec.x = $('#filestable').data('preview-x');
+ }
+ if (!urlSpec.y) {
+ urlSpec.y = $('#filestable').data('preview-y');
+ }
+ urlSpec.forceIcon = 0;
+ return OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
+}
+
Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
// get mime icon url
Files.getMimeIcon(mime, function(iconURL) {
- var urlSpec = {};
var previewURL;
+ urlSpec = {};
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');
- }
- // note: the order of arguments must match the one
- // from the server's template so that the browser
- // knows it's the same file for caching
- urlSpec.x = width;
- urlSpec.y = height;
urlSpec.file = Files.fixPath(path);
if (etag){
@@ -784,15 +684,9 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) {
console.warn('Files.lazyLoadPreview(): missing etag argument');
}
- if ( $('#isPublic').length ) {
- urlSpec.t = $('#dirToken').val();
- previewURL = OC.generateUrl('/publicpreview.png?') + $.param(urlSpec);
- } else {
- previewURL = OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
- }
+ previewURL = Files.generatePreviewUrl(urlSpec);
previewURL = previewURL.replace('(', '%28');
previewURL = previewURL.replace(')', '%29');
- previewURL += '&forceIcon=0';
// preload image to prevent delay
// this will make the browser cache the image
@@ -841,14 +735,8 @@ function checkTrashStatus() {
});
}
-function onClickBreadcrumb(e) {
- var $el = $(e.target).closest('.crumb'),
- $targetDir = $el.data('dir'),
- isPublic = !!$('#isPublic').val();
-
- if ($targetDir !== undefined && !isPublic) {
- e.preventDefault();
- FileList.changeDirectory(decodeURIComponent($targetDir));
- }
+// override core's fileDownloadPath (legacy)
+function fileDownloadPath(dir, file) {
+ return Files.getDownloadUrl(file, dir);
}
diff --git a/apps/files/lib/app.php b/apps/files/lib/app.php
index fea88faa92a..adfca669577 100644
--- a/apps/files/lib/app.php
+++ b/apps/files/lib/app.php
@@ -84,25 +84,7 @@ class App {
) {
// successful rename
$meta = $this->view->getFileInfo($dir . '/' . $newname);
- if ($meta['mimetype'] === 'httpd/unix-directory') {
- $meta['type'] = 'dir';
- }
- else {
- $meta['type'] = 'file';
- }
- // these need to be set for determineIcon()
- $meta['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($meta['mimetype']);
- $meta['directory'] = $dir;
- $fileinfo = array(
- 'id' => $meta['fileid'],
- 'mime' => $meta['mimetype'],
- 'size' => $meta['size'],
- 'etag' => $meta['etag'],
- 'directory' => $meta['directory'],
- 'name' => $newname,
- 'isPreviewAvailable' => $meta['isPreviewAvailable'],
- 'icon' => \OCA\Files\Helper::determineIcon($meta)
- );
+ $fileinfo = \OCA\Files\Helper::formatFileInfo($meta);
$result['success'] = true;
$result['data'] = $fileinfo;
} else {
diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php
index c41e2d15581..b765fdaf3e3 100644
--- a/apps/files/lib/helper.php
+++ b/apps/files/lib/helper.php
@@ -19,11 +19,17 @@ class Helper
'usedSpacePercent' => (int)$storageInfo['relative']);
}
+ /**
+ * Determine icon for a given file
+ *
+ * @param \OC\Files\FileInfo $file file info
+ * @return string icon URL
+ */
public static function determineIcon($file) {
if($file['type'] === 'dir') {
$dir = $file['directory'];
$icon = \OC_Helper::mimetypeIcon('dir');
- $absPath = \OC\Files\Filesystem::getView()->getAbsolutePath($dir.'/'.$file['name']);
+ $absPath = $file->getPath();
$mount = \OC\Files\Filesystem::getMountManager()->find($absPath);
if (!is_null($mount)) {
$sid = $mount->getStorageId();
@@ -38,11 +44,7 @@ class Helper
}
}
}else{
- if($file['isPreviewAvailable']) {
- $pathForPreview = $file['directory'] . '/' . $file['name'];
- return \OC_Helper::previewIcon($pathForPreview) . '&c=' . $file['etag'];
- }
- $icon = \OC_Helper::mimetypeIcon($file['mimetype']);
+ $icon = \OC_Helper::mimetypeIcon($file->getMimetype());
}
return substr($icon, 0, -3) . 'svg';
@@ -69,52 +71,58 @@ class Helper
}
/**
- * Retrieves the contents of the given directory and
- * returns it as a sorted array.
- * @param string $dir path to the directory
- * @return array of files
+ * Formats the file info to be returned as JSON to the client.
+ *
+ * @param \OCP\Files\FileInfo file info
+ * @return array formatted file info
*/
- public static function getFiles($dir) {
- $content = \OC\Files\Filesystem::getDirectoryContent($dir);
- $files = array();
+ public static function formatFileInfo($i) {
+ $entry = array();
- foreach ($content as $i) {
- $i['date'] = \OCP\Util::formatDate($i['mtime']);
- if ($i['type'] === 'file') {
- $fileinfo = pathinfo($i['name']);
- $i['basename'] = $fileinfo['filename'];
- if (!empty($fileinfo['extension'])) {
- $i['extension'] = '.' . $fileinfo['extension'];
- } else {
- $i['extension'] = '';
- }
- }
- $i['directory'] = $dir;
- $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']);
- $i['icon'] = \OCA\Files\Helper::determineIcon($i);
- $files[] = $i;
+ $entry['id'] = $i['fileid'];
+ $entry['date'] = \OCP\Util::formatDate($i['mtime']);
+ $entry['mtime'] = $i['mtime'] * 1000;
+ // only pick out the needed attributes
+ $entry['icon'] = \OCA\Files\Helper::determineIcon($i);
+ if (\OC::$server->getPreviewManager()->isMimeSupported($i['mimetype'])) {
+ $entry['isPreviewAvailable'] = true;
+ }
+ $entry['name'] = $i['name'];
+ $entry['permissions'] = $i['permissions'];
+ $entry['mimetype'] = $i['mimetype'];
+ $entry['size'] = $i['size'];
+ $entry['type'] = $i['type'];
+ $entry['etag'] = $i['etag'];
+ if (isset($i['displayname_owner'])) {
+ $entry['shareOwner'] = $i['displayname_owner'];
}
+ return $entry;
+ }
- usort($files, array('\OCA\Files\Helper', 'fileCmp'));
+ /**
+ * Format file info for JSON
+ * @param \OCP\Files\FileInfo[] $fileInfos file infos
+ */
+ public static function formatFileInfos($fileInfos) {
+ $files = array();
+ foreach ($fileInfos as $i) {
+ $files[] = self::formatFileInfo($i);
+ }
return $files;
}
/**
- * Splits the given path into a breadcrumb structure.
- * @param string $dir path to process
- * @return array where each entry is a hash of the absolute
- * directory path and its name
+ * Retrieves the contents of the given directory and
+ * returns it as a sorted array of FileInfo.
+ *
+ * @param string $dir path to the directory
+ * @return \OCP\Files\FileInfo[] files
*/
- public static function makeBreadcrumb($dir){
- $breadcrumb = array();
- $pathtohere = '';
- foreach (explode('/', $dir) as $i) {
- if ($i !== '') {
- $pathtohere .= '/' . $i;
- $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i);
- }
- }
- return $breadcrumb;
+ public static function getFiles($dir) {
+ $content = \OC\Files\Filesystem::getDirectoryContent($dir);
+
+ usort($content, array('\OCA\Files\Helper', 'fileCmp'));
+ return $content;
}
}
diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php
index 34acd9c4f51..95edd625cb3 100644
--- a/apps/files/templates/index.php
+++ b/apps/files/templates/index.php
@@ -1,6 +1,5 @@
<div id="controls">
- <?php print_unescaped($_['breadcrumb']); ?>
- <div class="actions creatable <?php if (!$_['isCreatable']):?>hidden<?php endif; ?>">
+ <div class="actions creatable hidden">
<?php if(!isset($_['dirToken'])):?>
<div id="new" class="button">
<a><?php p($l->t('New'));?></a>
@@ -48,20 +47,20 @@
</div>
</div>
<div id="file_action_panel"></div>
- <div class="notCreatable notPublic <?php if ($_['isCreatable'] or $_['isPublic'] ):?>hidden<?php endif; ?>">
+ <div class="notCreatable notPublic hidden">
<?php p($l->t('You don’t have permission to upload or create files here'))?>
</div>
<input type="hidden" name="permissions" value="<?php p($_['permissions']); ?>" id="permissions">
</div>
-<div id="emptycontent" <?php if (!$_['emptyContent']):?>class="hidden"<?php endif; ?>><?php p($l->t('Nothing in here. Upload something!'))?></div>
+<div id="emptycontent" class="hidden"><?php p($l->t('Nothing in here. Upload something!'))?></div>
<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>" />
<table id="filestable" data-allow-public-upload="<?php p($_['publicUploadEnabled'])?>" data-preview-x="36" data-preview-y="36">
<thead>
<tr>
- <th <?php if (!$_['fileHeader']):?>class="hidden"<?php endif; ?> id='headerName'>
+ <th class="hidden" id='headerName'>
<div id="headerName-container">
<input type="checkbox" id="select_all" />
<label for="select_all"></label>
@@ -77,8 +76,8 @@
</span>
</div>
</th>
- <th <?php if (!$_['fileHeader']):?>class="hidden"<?php endif; ?> id="headerSize"><?php p($l->t('Size')); ?></th>
- <th <?php if (!$_['fileHeader']):?>class="hidden"<?php endif; ?> id="headerDate">
+ <th class="hidden" id="headerSize"><?php p($l->t('Size')); ?></th>
+ <th class="hidden" id="headerDate">
<span id="modified"><?php p($l->t( 'Modified' )); ?></span>
<?php if ($_['permissions'] & OCP\PERMISSION_DELETE): ?>
<span class="selectedActions"><a href="" class="delete-selected">
@@ -91,7 +90,6 @@
</tr>
</thead>
<tbody id="fileList">
- <?php print_unescaped($_['fileList']); ?>
</tbody>
</table>
<div id="editor"></div><!-- FIXME Do not use this div in your app! It is deprecated and will be removed in the future! -->
@@ -111,7 +109,6 @@
<!-- config hints for javascript -->
<input type="hidden" name="filesApp" id="filesApp" value="1" />
-<input type="hidden" name="ajaxLoad" id="ajaxLoad" value="<?php p($_['ajaxLoad']); ?>" />
<input type="hidden" name="allowZipDownload" id="allowZipDownload" value="<?php p($_['allowZipDownload']); ?>" />
<input type="hidden" name="usedSpacePercent" id="usedSpacePercent" value="<?php p($_['usedSpacePercent']); ?>" />
<?php if (!$_['isPublic']) :?>
diff --git a/apps/files/templates/part.breadcrumb.php b/apps/files/templates/part.breadcrumb.php
deleted file mode 100644
index 69b4cbca10d..00000000000
--- a/apps/files/templates/part.breadcrumb.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<div class="crumb svg <?php if(!count($_["breadcrumb"])) p('last');?>" data-dir=''>
- <a href="<?php print_unescaped($_['baseURL']); ?>">
- <?php if(isset($_['rootBreadCrumb'])):
- echo $_['rootBreadCrumb'];
- else:?>
- <img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
- <?php endif;?>
- </a>
-</div>
-<?php for($i=0; $i<count($_["breadcrumb"]); $i++):
- $crumb = $_["breadcrumb"][$i];
- $dir = \OCP\Util::encodePath($crumb["dir"]); ?>
- <div class="crumb <?php if($i == count($_["breadcrumb"])-1) p('last');?> svg"
- data-dir='<?php p($dir);?>'>
- <a href="<?php p($_['baseURL'].$dir); ?>"><?php p($crumb["name"]); ?></a>
- </div>
-<?php endfor;
diff --git a/apps/files/templates/part.list.php b/apps/files/templates/part.list.php
deleted file mode 100644
index 8a7a1e370eb..00000000000
--- a/apps/files/templates/part.list.php
+++ /dev/null
@@ -1,67 +0,0 @@
-<?php $totalfiles = 0;
-$totaldirs = 0;
-$totalsize = 0; ?>
-<?php foreach($_['files'] as $file):
- // the bigger the file, the darker the shade of grey; megabytes*2
- $simple_size_color = intval(160-$file['size']/(1024*1024)*2);
- if($simple_size_color<0) $simple_size_color = 0;
- $relative_modified_date = OCP\relative_modified_date($file['mtime']);
- // the older the file, the brighter the shade of grey; days*14
- $relative_date_color = round((time()-$file['mtime'])/60/60/24*14);
- if($relative_date_color>160) $relative_date_color = 160;
- $name = \OCP\Util::encodePath($file['name']);
- $directory = \OCP\Util::encodePath($file['directory']); ?>
- <tr data-id="<?php p($file['fileid']); ?>"
- data-file="<?php p($name);?>"
- data-type="<?php ($file['type'] == 'dir')?p('dir'):p('file')?>"
- data-mime="<?php p($file['mimetype'])?>"
- data-size="<?php p($file['size']);?>"
- data-etag="<?php p($file['etag']);?>"
- data-permissions="<?php p($file['permissions']); ?>"
-
- <?php if(isset($file['displayname_owner'])): ?>
- data-share-owner="<?php p($file['displayname_owner']) ?>"
- <?php endif; ?>
- >
-
- <?php if(isset($file['isPreviewAvailable']) and $file['isPreviewAvailable']): ?>
- <td class="filename svg preview-icon"
- <?php else: ?>
- <td class="filename svg"
- <?php endif; ?>
- style="background-image:url(<?php print_unescaped($file['icon']); ?>)"
- >
- <?php if(!isset($_['readonly']) || !$_['readonly']): ?>
- <input id="select-<?php p($file['fileid']); ?>" type="checkbox" />
- <label for="select-<?php p($file['fileid']); ?>"></label>
- <?php endif; ?>
- <?php if($file['type'] == 'dir'): ?>
- <a class="name" href="<?php p(rtrim($_['baseURL'],'/').'/'.trim($directory,'/').'/'.$name); ?>" title="">
- <span class="nametext">
- <?php print_unescaped(htmlspecialchars($file['name']));?>
- </span>
- <span class="uploadtext" currentUploads="0">
- </span>
- </a>
- <?php else: ?>
- <a class="name" href="<?php p(rtrim($_['downloadURL'],'/').'/'.trim($directory,'/').'/'.$name); ?>">
- <label class="filetext" title="" for="select-<?php p($file['fileid']); ?>"></label>
- <span class="nametext"><?php print_unescaped(htmlspecialchars($file['basename']));?><span class='extension'><?php p($file['extension']);?></span></span>
- </a>
- <?php endif; ?>
- </td>
- <td class="filesize"
- style="color:rgb(<?php p($simple_size_color.','.$simple_size_color.','.$simple_size_color) ?>)">
- <?php print_unescaped(OCP\human_file_size($file['size'])); ?>
- </td>
- <td class="date">
- <span class="modified"
- title="<?php p($file['date']); ?>"
- style="color:rgb(<?php p($relative_date_color.','
- .$relative_date_color.','
- .$relative_date_color) ?>)">
- <?php p($relative_modified_date); ?>
- </span>
- </td>
- </tr>
-<?php endforeach;
diff --git a/apps/files/tests/ajax_rename.php b/apps/files/tests/ajax_rename.php
index e53c0fb3dd1..cb62d22a7e2 100644
--- a/apps/files/tests/ajax_rename.php
+++ b/apps/files/tests/ajax_rename.php
@@ -92,28 +92,32 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
$this->viewMock->expects($this->any())
->method('getFileInfo')
- ->will($this->returnValue(array(
+ ->will($this->returnValue(new \OC\Files\FileInfo(
+ '/test',
+ null,
+ '/test',
+ array(
'fileid' => 123,
'type' => 'dir',
'mimetype' => 'httpd/unix-directory',
+ 'mtime' => 0,
+ 'permissions' => 31,
'size' => 18,
'etag' => 'abcdef',
'directory' => '/',
'name' => 'new_name',
- )));
+ ))));
$result = $this->files->rename($dir, $oldname, $newname);
$this->assertTrue($result['success']);
$this->assertEquals(123, $result['data']['id']);
$this->assertEquals('new_name', $result['data']['name']);
- $this->assertEquals('/test', $result['data']['directory']);
$this->assertEquals(18, $result['data']['size']);
- $this->assertEquals('httpd/unix-directory', $result['data']['mime']);
+ $this->assertEquals('httpd/unix-directory', $result['data']['mimetype']);
$icon = \OC_Helper::mimetypeIcon('dir');
$icon = substr($icon, 0, -3) . 'svg';
$this->assertEquals($icon, $result['data']['icon']);
- $this->assertFalse($result['data']['isPreviewAvailable']);
}
/**
@@ -148,29 +152,33 @@ class Test_OC_Files_App_Rename extends \PHPUnit_Framework_TestCase {
$this->viewMock->expects($this->any())
->method('getFileInfo')
- ->will($this->returnValue(array(
+ ->will($this->returnValue(new \OC\Files\FileInfo(
+ '/',
+ null,
+ '/',
+ array(
'fileid' => 123,
'type' => 'dir',
'mimetype' => 'httpd/unix-directory',
+ 'mtime' => 0,
+ 'permissions' => 31,
'size' => 18,
'etag' => 'abcdef',
'directory' => '/',
'name' => 'new_name',
- )));
+ ))));
$result = $this->files->rename($dir, $oldname, $newname);
$this->assertTrue($result['success']);
$this->assertEquals(123, $result['data']['id']);
- $this->assertEquals('newname', $result['data']['name']);
- $this->assertEquals('/', $result['data']['directory']);
+ $this->assertEquals('new_name', $result['data']['name']);
$this->assertEquals(18, $result['data']['size']);
- $this->assertEquals('httpd/unix-directory', $result['data']['mime']);
+ $this->assertEquals('httpd/unix-directory', $result['data']['mimetype']);
$this->assertEquals('abcdef', $result['data']['etag']);
$icon = \OC_Helper::mimetypeIcon('dir');
$icon = substr($icon, 0, -3) . 'svg';
$this->assertEquals($icon, $result['data']['icon']);
- $this->assertFalse($result['data']['isPreviewAvailable']);
}
/**
diff --git a/apps/files/tests/js/breadcrumbSpec.js b/apps/files/tests/js/breadcrumbSpec.js
new file mode 100644
index 00000000000..1bfe5308a27
--- /dev/null
+++ b/apps/files/tests/js/breadcrumbSpec.js
@@ -0,0 +1,248 @@
+/**
+* ownCloud
+*
+* @author Vincent Petry
+* @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+*
+* This library is free software; you can redistribute it and/or
+* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+* License as published by the Free Software Foundation; either
+* version 3 of the License, or any later version.
+*
+* This library is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+*
+* You should have received a copy of the GNU Affero General Public
+* License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*
+*/
+
+/* global BreadCrumb */
+describe('BreadCrumb tests', function() {
+ describe('Rendering', function() {
+ var bc;
+ beforeEach(function() {
+ bc = new BreadCrumb({
+ getCrumbUrl: function(part, index) {
+ // for testing purposes
+ return part.dir + '#' + index;
+ }
+ });
+ });
+ afterEach(function() {
+ bc = null;
+ });
+ it('Renders its own container', function() {
+ bc.render();
+ expect(bc.$el.hasClass('breadcrumb')).toEqual(true);
+ });
+ it('Renders root by default', function() {
+ var $crumbs;
+ bc.render();
+ $crumbs = bc.$el.find('.crumb');
+ expect($crumbs.length).toEqual(1);
+ expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0');
+ expect($crumbs.eq(0).find('img').length).toEqual(1);
+ expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
+ });
+ it('Renders root when switching to root', function() {
+ var $crumbs;
+ bc.setDirectory('/somedir');
+ bc.setDirectory('/');
+ $crumbs = bc.$el.find('.crumb');
+ expect($crumbs.length).toEqual(1);
+ expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
+ });
+ it('Renders last crumb with "last" class', function() {
+ bc.setDirectory('/abc/def');
+ expect(bc.$el.find('.crumb:last').hasClass('last')).toEqual(true);
+ });
+ it('Renders single path section', function() {
+ var $crumbs;
+ bc.setDirectory('/somedir');
+ $crumbs = bc.$el.find('.crumb');
+ expect($crumbs.length).toEqual(2);
+ expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0');
+ expect($crumbs.eq(0).find('img').length).toEqual(1);
+ expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
+ expect($crumbs.eq(1).find('a').attr('href')).toEqual('/somedir#1');
+ expect($crumbs.eq(1).find('img').length).toEqual(0);
+ expect($crumbs.eq(1).attr('data-dir')).toEqual('/somedir');
+ });
+ it('Renders multiple path sections and special chars', function() {
+ var $crumbs;
+ bc.setDirectory('/somedir/with space/abc');
+ $crumbs = bc.$el.find('.crumb');
+ expect($crumbs.length).toEqual(4);
+ expect($crumbs.eq(0).find('a').attr('href')).toEqual('/#0');
+ expect($crumbs.eq(0).find('img').length).toEqual(1);
+ expect($crumbs.eq(0).attr('data-dir')).toEqual('/');
+
+ expect($crumbs.eq(1).find('a').attr('href')).toEqual('/somedir#1');
+ expect($crumbs.eq(1).find('img').length).toEqual(0);
+ expect($crumbs.eq(1).attr('data-dir')).toEqual('/somedir');
+
+ expect($crumbs.eq(2).find('a').attr('href')).toEqual('/somedir/with space#2');
+ expect($crumbs.eq(2).find('img').length).toEqual(0);
+ expect($crumbs.eq(2).attr('data-dir')).toEqual('/somedir/with space');
+
+ expect($crumbs.eq(3).find('a').attr('href')).toEqual('/somedir/with space/abc#3');
+ expect($crumbs.eq(3).find('img').length).toEqual(0);
+ expect($crumbs.eq(3).attr('data-dir')).toEqual('/somedir/with space/abc');
+ });
+ });
+ describe('Events', function() {
+ it('Calls onClick handler when clicking on a crumb', function() {
+ var handler = sinon.stub();
+ var bc = new BreadCrumb({
+ onClick: handler
+ });
+ bc.setDirectory('/one/two/three/four');
+ bc.$el.find('.crumb:eq(3)').click();
+ expect(handler.calledOnce).toEqual(true);
+ expect(handler.getCall(0).thisValue).toEqual(bc.$el.find('.crumb').get(3));
+
+ handler.reset();
+ bc.$el.find('.crumb:eq(0) a').click();
+ expect(handler.calledOnce).toEqual(true);
+ expect(handler.getCall(0).thisValue).toEqual(bc.$el.find('.crumb').get(0));
+ });
+ it('Calls onDrop handler when dropping on a crumb', function() {
+ var droppableStub = sinon.stub($.fn, 'droppable');
+ var handler = sinon.stub();
+ var bc = new BreadCrumb({
+ onDrop: handler
+ });
+ bc.setDirectory('/one/two/three/four');
+ expect(droppableStub.calledOnce).toEqual(true);
+
+ expect(droppableStub.getCall(0).args[0].drop).toBeDefined();
+ // simulate drop
+ droppableStub.getCall(0).args[0].drop({dummy: true});
+
+ expect(handler.calledOnce).toEqual(true);
+ expect(handler.getCall(0).args[0]).toEqual({dummy: true});
+
+ droppableStub.restore();
+ });
+ });
+ describe('Resizing', function() {
+ var bc, widthStub, dummyDir,
+ oldUpdateTotalWidth;
+
+ beforeEach(function() {
+ dummyDir = '/short name/longer name/looooooooooooonger/even longer long long long longer long/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/last one';
+
+ oldUpdateTotalWidth = BreadCrumb.prototype._updateTotalWidth;
+ BreadCrumb.prototype._updateTotalWidth = function() {
+ // need to set display:block for correct offsetWidth (no CSS loaded here)
+ $('div.crumb').css({
+ 'display': 'block',
+ 'float': 'left'
+ });
+
+ return oldUpdateTotalWidth.apply(this, arguments);
+ };
+
+ bc = new BreadCrumb();
+ widthStub = sinon.stub($.fn, 'width');
+ // append dummy navigation and controls
+ // as they are currently used for measurements
+ $('#testArea').append(
+ '<div id="navigation" style="width: 80px"></div>',
+ '<div id="controls"></div>'
+ );
+
+ // make sure we know the test screen width
+ $('#testArea').css('width', 1280);
+
+ // use test area as we need it for measurements
+ $('#controls').append(bc.$el);
+ $('#controls').append('<div class="actions"><div>Dummy action with a given width</div></div>');
+ });
+ afterEach(function() {
+ BreadCrumb.prototype._updateTotalWidth = oldUpdateTotalWidth;
+ widthStub.restore();
+ bc = null;
+ });
+ it('Hides breadcrumbs to fit window', function() {
+ var $crumbs;
+
+ widthStub.returns(500);
+ // triggers resize implicitly
+ bc.setDirectory(dummyDir);
+ $crumbs = bc.$el.find('.crumb');
+
+ // first one is always visible
+ expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
+ // second one has ellipsis
+ expect($crumbs.eq(1).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1);
+ // there is only one ellipsis in total
+ expect($crumbs.find('.ellipsis').length).toEqual(1);
+ // subsequent elements are hidden
+ expect($crumbs.eq(2).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(3).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(4).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(5).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
+ });
+ it('Updates ellipsis on window size increase', function() {
+ var $crumbs;
+
+ widthStub.returns(500);
+ // triggers resize implicitly
+ bc.setDirectory(dummyDir);
+ $crumbs = bc.$el.find('.crumb');
+
+ // simulate increase
+ $('#testArea').css('width', 1800);
+ bc.resize(1800);
+
+ // first one is always visible
+ expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
+ // second one has ellipsis
+ expect($crumbs.eq(1).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1);
+ // there is only one ellipsis in total
+ expect($crumbs.find('.ellipsis').length).toEqual(1);
+ // subsequent elements are hidden
+ expect($crumbs.eq(2).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(3).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(4).hasClass('hidden')).toEqual(true);
+ // the rest is visible
+ expect($crumbs.eq(5).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
+ });
+ it('Updates ellipsis on window size decrease', function() {
+ var $crumbs;
+
+ $('#testArea').css('width', 2000);
+ widthStub.returns(2000);
+ // triggers resize implicitly
+ bc.setDirectory(dummyDir);
+ $crumbs = bc.$el.find('.crumb');
+
+ // simulate decrease
+ bc.resize(500);
+ $('#testArea').css('width', 500);
+
+ // first one is always visible
+ expect($crumbs.eq(0).hasClass('hidden')).toEqual(false);
+ // second one has ellipsis
+ expect($crumbs.eq(1).hasClass('hidden')).toEqual(false);
+ expect($crumbs.eq(1).find('.ellipsis').length).toEqual(1);
+ // there is only one ellipsis in total
+ expect($crumbs.find('.ellipsis').length).toEqual(1);
+ // subsequent elements are hidden
+ expect($crumbs.eq(2).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(3).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(4).hasClass('hidden')).toEqual(true);
+ // the rest is visible
+ expect($crumbs.eq(5).hasClass('hidden')).toEqual(true);
+ expect($crumbs.eq(6).hasClass('hidden')).toEqual(false);
+ });
+ });
+});
diff --git a/apps/files/tests/js/fileactionsSpec.js b/apps/files/tests/js/fileactionsSpec.js
index 80c04b5b242..3c22c84b866 100644
--- a/apps/files/tests/js/fileactionsSpec.js
+++ b/apps/files/tests/js/fileactionsSpec.js
@@ -22,6 +22,7 @@
/* global OC, FileActions, FileList */
describe('FileActions tests', function() {
var $filesTable;
+
beforeEach(function() {
// init horrible parameters
var $body = $('body');
@@ -34,17 +35,20 @@ describe('FileActions tests', function() {
$('#dir, #permissions, #filestable').remove();
});
it('calling display() sets file actions', function() {
- // note: download_url is actually the link target, not the actual download URL...
- var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
-
- // no actions before call
- expect($tr.find('.action.action-download').length).toEqual(0);
- expect($tr.find('.action.action-rename').length).toEqual(0);
- expect($tr.find('.action.delete').length).toEqual(0);
+ var fileData = {
+ id: 18,
+ type: 'file',
+ name: 'testName.txt',
+ mimetype: 'plain/text',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
- FileActions.display($tr.find('td.filename'), true);
+ // note: FileActions.display() is called implicitly
+ var $tr = FileList.add(fileData);
- // actions defined after cal
+ // actions defined after call
expect($tr.find('.action.action-download').length).toEqual(1);
expect($tr.find('.action.action-download').attr('data-action')).toEqual('Download');
expect($tr.find('.nametext .action.action-rename').length).toEqual(1);
@@ -52,7 +56,16 @@ describe('FileActions tests', function() {
expect($tr.find('.action.delete').length).toEqual(1);
});
it('calling display() twice correctly replaces file actions', function() {
- var $tr = FileList.addFile('testName.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
+ var fileData = {
+ id: 18,
+ type: 'file',
+ name: 'testName.txt',
+ mimetype: 'plain/text',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
+ var $tr = FileList.add(fileData);
FileActions.display($tr.find('td.filename'), true);
FileActions.display($tr.find('td.filename'), true);
@@ -64,19 +77,36 @@ describe('FileActions tests', function() {
});
it('redirects to download URL when clicking download', function() {
var redirectStub = sinon.stub(OC, 'redirect');
- // note: download_url is actually the link target, not the actual download URL...
- var $tr = FileList.addFile('test download File.txt', 1234, new Date(), false, false, {download_url: 'test/download/url'});
+ var fileData = {
+ id: 18,
+ type: 'file',
+ name: 'testName.txt',
+ mimetype: 'plain/text',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
+ var $tr = FileList.add(fileData);
FileActions.display($tr.find('td.filename'), true);
$tr.find('.action-download').click();
expect(redirectStub.calledOnce).toEqual(true);
- expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=test%20download%20File.txt');
+ expect(redirectStub.getCall(0).args[0]).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt');
redirectStub.restore();
});
it('deletes file when clicking delete', function() {
var deleteStub = sinon.stub(FileList, 'do_delete');
- var $tr = FileList.addFile('test delete File.txt', 1234, new Date());
+ var fileData = {
+ id: 18,
+ type: 'file',
+ name: 'testName.txt',
+ mimetype: 'plain/text',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
+ var $tr = FileList.add(fileData);
FileActions.display($tr.find('td.filename'), true);
$tr.find('.action.delete').click();
diff --git a/apps/files/tests/js/filelistSpec.js b/apps/files/tests/js/filelistSpec.js
index 8f4cb86ab4a..ca85a360cf5 100644
--- a/apps/files/tests/js/filelistSpec.js
+++ b/apps/files/tests/js/filelistSpec.js
@@ -21,6 +21,9 @@
/* global OC, FileList */
describe('FileList tests', function() {
+ var testFiles, alertStub, notificationStub,
+ pushStateStub;
+
beforeEach(function() {
// init horrible parameters
var $body = $('body');
@@ -28,45 +31,784 @@ describe('FileList tests', function() {
$body.append('<input type="hidden" id="permissions" value="31"></input>');
// dummy files table
$body.append('<table id="filestable"></table>');
+
+ // prevents URL changes during tests
+ pushStateStub = sinon.stub(window.history, 'pushState');
+
+ alertStub = sinon.stub(OC.dialogs, 'alert');
+ notificationStub = sinon.stub(OC.Notification, 'show');
+
+ // init parameters and test table elements
+ $('#testArea').append(
+ '<input type="hidden" id="dir" value="/subdir"></input>' +
+ '<input type="hidden" id="permissions" value="31"></input>' +
+ // dummy controls
+ '<div id="controls">' +
+ ' <div class="actions creatable"></div>' +
+ ' <div class="notCreatable"></div>' +
+ '</div>' +
+ // dummy table
+ '<table id="filestable">' +
+ '<thead><tr><th class="hidden">Name</th></tr></thead>' +
+ '<tbody id="fileList"></tbody>' +
+ '</table>' +
+ '<div id="emptycontent">Empty content message</div>'
+ );
+
+ testFiles = [{
+ id: 1,
+ type: 'file',
+ name: 'One.txt',
+ mimetype: 'text/plain',
+ size: 12
+ }, {
+ id: 2,
+ type: 'file',
+ name: 'Two.jpg',
+ mimetype: 'image/jpeg',
+ size: 12049
+ }, {
+ id: 3,
+ type: 'file',
+ name: 'Three.pdf',
+ mimetype: 'application/pdf',
+ size: 58009
+ }, {
+ id: 4,
+ type: 'dir',
+ name: 'somedir',
+ mimetype: 'httpd/unix-directory',
+ size: 250
+ }];
+
+ FileList.initialize();
});
afterEach(function() {
+ testFiles = undefined;
+ FileList.initialized = false;
+ FileList.isEmpty = true;
+ delete FileList._reloadCall;
+
$('#dir, #permissions, #filestable').remove();
+ notificationStub.restore();
+ alertStub.restore();
+ pushStateStub.restore();
+ });
+ describe('Getters', function() {
+ it('Returns the current directory', function() {
+ $('#dir').val('/one/two/three');
+ expect(FileList.getCurrentDirectory()).toEqual('/one/two/three');
+ });
+ it('Returns the directory permissions as int', function() {
+ $('#permissions').val('23');
+ expect(FileList.getDirectoryPermissions()).toEqual(23);
+ });
+ });
+ describe('Adding files', function() {
+ var clock, now;
+ beforeEach(function() {
+ // to prevent date comparison issues
+ clock = sinon.useFakeTimers();
+ now = new Date();
+ });
+ afterEach(function() {
+ clock.restore();
+ });
+ it('generates file element with correct attributes when calling add() with file data', function() {
+ var fileData = {
+ id: 18,
+ type: 'file',
+ name: 'testName.txt',
+ mimetype: 'plain/text',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
+ var $tr = FileList.add(fileData);
+
+ expect($tr).toBeDefined();
+ expect($tr[0].tagName.toLowerCase()).toEqual('tr');
+ expect($tr.attr('data-id')).toEqual('18');
+ expect($tr.attr('data-type')).toEqual('file');
+ expect($tr.attr('data-file')).toEqual('testName.txt');
+ expect($tr.attr('data-size')).toEqual('1234');
+ expect($tr.attr('data-etag')).toEqual('a01234c');
+ expect($tr.attr('data-permissions')).toEqual('31');
+ expect($tr.attr('data-mime')).toEqual('plain/text');
+ expect($tr.attr('data-mtime')).toEqual('123456');
+ expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=testName.txt');
+
+ expect($tr.find('.filesize').text()).toEqual('1 kB');
+ expect(FileList.findFileEl('testName.txt')[0]).toEqual($tr[0]);
+ });
+ it('generates dir element with correct attributes when calling add() with dir data', function() {
+ var fileData = {
+ id: 19,
+ type: 'dir',
+ name: 'testFolder',
+ mimetype: 'httpd/unix-directory',
+ size: '1234',
+ etag: 'a01234c',
+ mtime: '123456'
+ };
+ var $tr = FileList.add(fileData);
+
+ expect($tr).toBeDefined();
+ expect($tr[0].tagName.toLowerCase()).toEqual('tr');
+ expect($tr.attr('data-id')).toEqual('19');
+ expect($tr.attr('data-type')).toEqual('dir');
+ expect($tr.attr('data-file')).toEqual('testFolder');
+ expect($tr.attr('data-size')).toEqual('1234');
+ expect($tr.attr('data-etag')).toEqual('a01234c');
+ expect($tr.attr('data-permissions')).toEqual('31');
+ expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
+ expect($tr.attr('data-mtime')).toEqual('123456');
+
+ expect($tr.find('.filesize').text()).toEqual('1 kB');
+
+ expect(FileList.findFileEl('testFolder')[0]).toEqual($tr[0]);
+ });
+ it('generates file element with default attributes when calling add() with minimal data', function() {
+ var fileData = {
+ type: 'file',
+ name: 'testFile.txt'
+ };
+
+ clock.tick(123456);
+ var $tr = FileList.add(fileData);
+
+ expect($tr).toBeDefined();
+ expect($tr[0].tagName.toLowerCase()).toEqual('tr');
+ expect($tr.attr('data-id')).toEqual(null);
+ expect($tr.attr('data-type')).toEqual('file');
+ expect($tr.attr('data-file')).toEqual('testFile.txt');
+ expect($tr.attr('data-size')).toEqual(null);
+ expect($tr.attr('data-etag')).toEqual(null);
+ expect($tr.attr('data-permissions')).toEqual('31');
+ expect($tr.attr('data-mime')).toEqual(null);
+ expect($tr.attr('data-mtime')).toEqual('123456');
+
+ expect($tr.find('.filesize').text()).toEqual('Pending');
+ });
+ it('generates dir element with default attributes when calling add() with minimal data', function() {
+ var fileData = {
+ type: 'dir',
+ name: 'testFolder'
+ };
+ clock.tick(123456);
+ var $tr = FileList.add(fileData);
+
+ expect($tr).toBeDefined();
+ expect($tr[0].tagName.toLowerCase()).toEqual('tr');
+ expect($tr.attr('data-id')).toEqual(null);
+ expect($tr.attr('data-type')).toEqual('dir');
+ expect($tr.attr('data-file')).toEqual('testFolder');
+ expect($tr.attr('data-size')).toEqual(null);
+ expect($tr.attr('data-etag')).toEqual(null);
+ expect($tr.attr('data-permissions')).toEqual('31');
+ expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
+ expect($tr.attr('data-mtime')).toEqual('123456');
+
+ expect($tr.find('.filesize').text()).toEqual('Pending');
+ });
+ it('generates file element with zero size when size is explicitly zero', function() {
+ var fileData = {
+ type: 'dir',
+ name: 'testFolder',
+ size: '0'
+ };
+ var $tr = FileList.add(fileData);
+ expect($tr.find('.filesize').text()).toEqual('0 B');
+ });
+ it('adds new file to the end of the list before the summary', function() {
+ var fileData = {
+ type: 'file',
+ name: 'P comes after O.txt'
+ };
+ FileList.setFiles(testFiles);
+ $tr = FileList.add(fileData);
+ expect($tr.index()).toEqual(4);
+ expect($tr.next().hasClass('summary')).toEqual(true);
+ });
+ it('adds new file at correct position in insert mode', function() {
+ var fileData = {
+ type: 'file',
+ name: 'P comes after O.txt'
+ };
+ FileList.setFiles(testFiles);
+ $tr = FileList.add(fileData, {insert: true});
+ // after "One.txt"
+ expect($tr.index()).toEqual(1);
+ });
+ it('removes empty content message and shows summary when adding first file', function() {
+ var fileData = {
+ type: 'file',
+ name: 'first file.txt',
+ size: 12
+ };
+ FileList.setFiles([]);
+ expect(FileList.isEmpty).toEqual(true);
+ FileList.add(fileData);
+ $summary = $('#fileList .summary');
+ expect($summary.length).toEqual(1);
+ // yes, ugly...
+ expect($summary.find('.info').text()).toEqual('0 folders and 1 file');
+ expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(true);
+ expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false);
+ expect($summary.find('.filesize').text()).toEqual('12 B');
+ expect($('#filestable thead th').hasClass('hidden')).toEqual(false);
+ expect($('#emptycontent').hasClass('hidden')).toEqual(true);
+ expect(FileList.isEmpty).toEqual(false);
+ });
});
- it('generates file element with correct attributes when calling addFile', function() {
- var lastMod = new Date(10000);
- // note: download_url is actually the link target, not the actual download URL...
- var $tr = FileList.addFile('testName.txt', 1234, lastMod, false, false, {download_url: 'test/download/url'});
-
- expect($tr).toBeDefined();
- expect($tr[0].tagName.toLowerCase()).toEqual('tr');
- expect($tr.find('a:first').attr('href')).toEqual('test/download/url');
- expect($tr.attr('data-type')).toEqual('file');
- expect($tr.attr('data-file')).toEqual('testName.txt');
- expect($tr.attr('data-size')).toEqual('1234');
- expect($tr.attr('data-permissions')).toEqual('31');
- //expect($tr.attr('data-mime')).toEqual('plain/text');
+ describe('Removing files from the list', function() {
+ it('Removes file from list when calling remove() and updates summary', function() {
+ var $removedEl;
+ FileList.setFiles(testFiles);
+ $removedEl = FileList.remove('One.txt');
+ expect($removedEl).toBeDefined();
+ expect($removedEl.attr('data-file')).toEqual('One.txt');
+ expect($('#fileList tr:not(.summary)').length).toEqual(3);
+ expect(FileList.findFileEl('One.txt').length).toEqual(0);
+
+ $summary = $('#fileList .summary');
+ expect($summary.length).toEqual(1);
+ expect($summary.find('.info').text()).toEqual('1 folder and 2 files');
+ expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false);
+ expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false);
+ expect($summary.find('.filesize').text()).toEqual('69 kB');
+ expect(FileList.isEmpty).toEqual(false);
+ });
+ it('Shows empty content when removing last file', function() {
+ FileList.setFiles([testFiles[0]]);
+ FileList.remove('One.txt');
+ expect($('#fileList tr:not(.summary)').length).toEqual(0);
+ expect(FileList.findFileEl('One.txt').length).toEqual(0);
+
+ $summary = $('#fileList .summary');
+ expect($summary.length).toEqual(0);
+ expect($('#filestable thead th').hasClass('hidden')).toEqual(true);
+ expect($('#emptycontent').hasClass('hidden')).toEqual(false);
+ expect(FileList.isEmpty).toEqual(true);
+ });
});
- it('generates dir element with correct attributes when calling addDir', function() {
- var lastMod = new Date(10000);
- var $tr = FileList.addDir('testFolder', 1234, lastMod, false);
-
- expect($tr).toBeDefined();
- expect($tr[0].tagName.toLowerCase()).toEqual('tr');
- expect($tr.attr('data-type')).toEqual('dir');
- expect($tr.attr('data-file')).toEqual('testFolder');
- expect($tr.attr('data-size')).toEqual('1234');
- expect($tr.attr('data-permissions')).toEqual('31');
- //expect($tr.attr('data-mime')).toEqual('httpd/unix-directory');
+ describe('Deleting files', function() {
+ function doDelete() {
+ var request, query;
+ // note: normally called from FileActions
+ FileList.do_delete(['One.txt', 'Two.jpg']);
+
+ expect(fakeServer.requests.length).toEqual(1);
+ request = fakeServer.requests[0];
+ expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/delete.php');
+
+ query = fakeServer.requests[0].requestBody;
+ expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir', files: '["One.txt","Two.jpg"]'});
+ }
+ it('calls delete.php, removes the deleted entries and updates summary', function() {
+ FileList.setFiles(testFiles);
+ doDelete();
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({status: 'success'})
+ );
+
+ expect(FileList.findFileEl('One.txt').length).toEqual(0);
+ expect(FileList.findFileEl('Two.jpg').length).toEqual(0);
+ expect(FileList.findFileEl('Three.pdf').length).toEqual(1);
+ expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(2);
+
+ $summary = $('#fileList .summary');
+ expect($summary.length).toEqual(1);
+ expect($summary.find('.info').text()).toEqual('1 folder and 1 file');
+ expect($summary.find('.dirinfo').hasClass('hidden')).toEqual(false);
+ expect($summary.find('.fileinfo').hasClass('hidden')).toEqual(false);
+ expect($summary.find('.filesize').text()).toEqual('57 kB');
+ expect(FileList.isEmpty).toEqual(false);
+ expect($('#filestable thead th').hasClass('hidden')).toEqual(false);
+ expect($('#emptycontent').hasClass('hidden')).toEqual(true);
+
+ expect(notificationStub.notCalled).toEqual(true);
+ });
+ it('updates summary when deleting last file', function() {
+ FileList.setFiles([testFiles[0], testFiles[1]]);
+ doDelete();
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({status: 'success'})
+ );
+
+ expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(0);
+
+ $summary = $('#fileList .summary');
+ expect($summary.length).toEqual(0);
+ expect(FileList.isEmpty).toEqual(true);
+ expect($('#filestable thead th').hasClass('hidden')).toEqual(true);
+ expect($('#emptycontent').hasClass('hidden')).toEqual(false);
+ });
+ it('bring back deleted item when delete call failed', function() {
+ FileList.setFiles(testFiles);
+ doDelete();
+
+ fakeServer.requests[0].respond(
+ 200,
+ { 'Content-Type': 'application/json' },
+ JSON.stringify({status: 'error', data: {message: 'WOOT'}})
+ );
+
+ // files are still in the list
+ expect(FileList.findFileEl('One.txt').length).toEqual(1);
+ expect(FileList.findFileEl('Two.jpg').length).toEqual(1);
+ expect(FileList.$fileList.find('tr:not(.summary)').length).toEqual(4);
+
+ expect(notificationStub.calledOnce).toEqual(true);
+ });
+ });
+ describe('Renaming files', function() {
+ function doRename() {
+ var $input, request;
+
+ FileList.setFiles(testFiles);
+
+ // trigger rename prompt
+ FileList.rename('One.txt');
+ $input = FileList.$fileList.find('input.filename');
+ $input.val('One_renamed.txt').blur();
+
+ expect(fakeServer.requests.length).toEqual(1);
+ var request = fakeServer.requests[0];
+ expect(request.url.substr(0, request.url.indexOf('?'))).toEqual(OC.webroot + '/index.php/apps/files/ajax/rename.php');
+ expect(OC.parseQueryString(request.url)).toEqual({'dir': '/subdir', newname: 'One_renamed.txt', file: 'One.txt'});
+
+ // element is renamed before the request finishes
+ expect(FileList.findFileEl('One.txt').length).toEqual(0);
+ expect(FileList.findFileEl('One_renamed.txt').length).toEqual(1);
+ // input is gone
+ expect(FileList.$fileList.find('input.filename').length).toEqual(0);
+ }
+ it('Keeps renamed file entry if rename ajax call suceeded', function() {
+ doRename();
+
+ fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+ status: 'success',
+ data: {
+ name: 'One_renamed.txt'
+ }
+ }));
+
+ // element stays renamed
+ expect(FileList.findFileEl('One.txt').length).toEqual(0);
+ expect(FileList.findFileEl('One_renamed.txt').length).toEqual(1);
+
+ expect(alertStub.notCalled).toEqual(true);
+ });
+ it('Reverts file entry if rename ajax call failed', function() {
+ doRename();
+
+ fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+ status: 'error',
+ data: {
+ message: 'Something went wrong'
+ }
+ }));
+
+ // element was reverted
+ expect(FileList.findFileEl('One.txt').length).toEqual(1);
+ expect(FileList.findFileEl('One_renamed.txt').length).toEqual(0);
+
+ expect(alertStub.calledOnce).toEqual(true);
+ });
+ it('Correctly updates file link after rename', function() {
+ var $tr;
+ doRename();
+
+ fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+ status: 'success',
+ data: {
+ name: 'One_renamed.txt'
+ }
+ }));
+
+ $tr = FileList.findFileEl('One_renamed.txt');
+ expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=One_renamed.txt');
+ });
+ // FIXME: fix this in the source code!
+ xit('Correctly updates file link after rename when path has same name', function() {
+ var $tr;
+ // evil case: because of buggy code
+ $('#dir').val('/One.txt/subdir');
+ doRename();
+
+ fakeServer.requests[0].respond(200, {'Content-Type': 'application/json'}, JSON.stringify({
+ status: 'success',
+ data: {
+ name: 'One_renamed.txt'
+ }
+ }));
+
+ $tr = FileList.findFileEl('One_renamed.txt');
+ expect($tr.find('a.name').attr('href')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=One.txt');
+ });
+ });
+ describe('List rendering', function() {
+ it('renders a list of files using add()', function() {
+ var addSpy = sinon.spy(FileList, 'add');
+ FileList.setFiles(testFiles);
+ expect(addSpy.callCount).toEqual(4);
+ expect($('#fileList tr:not(.summary)').length).toEqual(4);
+ addSpy.restore();
+ });
+ it('updates summary using the file sizes', function() {
+ var $summary;
+ FileList.setFiles(testFiles);
+ $summary = $('#fileList .summary');
+ expect($summary.length).toEqual(1);
+ expect($summary.find('.info').text()).toEqual('1 folder and 3 files');
+ expect($summary.find('.filesize').text()).toEqual('69 kB');
+ });
+ it('shows headers, summary and hide empty content message after setting files', function(){
+ FileList.setFiles(testFiles);
+ expect($('#filestable thead th').hasClass('hidden')).toEqual(false);
+ expect($('#emptycontent').hasClass('hidden')).toEqual(true);
+ expect(FileList.$fileList.find('.summary').length).toEqual(1);
+ });
+ it('hides headers, summary and show empty content message after setting empty file list', function(){
+ FileList.setFiles([]);
+ expect($('#filestable thead th').hasClass('hidden')).toEqual(true);
+ expect($('#emptycontent').hasClass('hidden')).toEqual(false);
+ expect(FileList.$fileList.find('.summary').length).toEqual(0);
+ });
+ it('hides headers, empty content message, and summary when list is empty and user has no creation permission', function(){
+ $('#permissions').val(0);
+ FileList.setFiles([]);
+ expect($('#filestable thead th').hasClass('hidden')).toEqual(true);
+ expect($('#emptycontent').hasClass('hidden')).toEqual(true);
+ expect(FileList.$fileList.find('.summary').length).toEqual(0);
+ });
+ it('calling findFileEl() can find existing file element', function() {
+ FileList.setFiles(testFiles);
+ expect(FileList.findFileEl('Two.jpg').length).toEqual(1);
+ });
+ it('calling findFileEl() returns empty when file not found in file', function() {
+ FileList.setFiles(testFiles);
+ expect(FileList.findFileEl('unexist.dat').length).toEqual(0);
+ });
+ it('only add file if in same current directory', function() {
+ $('#dir').val('/current dir');
+ var fileData = {
+ type: 'file',
+ name: 'testFile.txt',
+ directory: '/current dir'
+ };
+ var $tr = FileList.add(fileData);
+ expect(FileList.findFileEl('testFile.txt').length).toEqual(1);
+ });
+ it('triggers "fileActionsReady" event after update', function() {
+ var handler = sinon.stub();
+ FileList.$fileList.on('fileActionsReady', handler);
+ FileList.setFiles(testFiles);
+ expect(handler.calledOnce).toEqual(true);
+ });
+ it('triggers "updated" event after update', function() {
+ var handler = sinon.stub();
+ FileList.$fileList.on('updated', handler);
+ FileList.setFiles(testFiles);
+ expect(handler.calledOnce).toEqual(true);
+ });
+ });
+ describe('file previews', function() {
+ var previewLoadStub;
+
+ function getImageUrl($el) {
+ // might be slightly different cross-browser
+ var url = $el.css('background-image');
+ var r = url.match(/url\(['"]?([^'")]*)['"]?\)/);
+ if (!r) {
+ return url;
+ }
+ return r[1];
+ }
+
+ beforeEach(function() {
+ previewLoadStub = sinon.stub(Files, 'lazyLoadPreview');
+ });
+ afterEach(function() {
+ previewLoadStub.restore();
+ });
+ it('renders default icon for file when none provided and no preview is available', function() {
+ var fileData = {
+ type: 'file',
+ name: 'testFile.txt'
+ };
+ var $tr = FileList.add(fileData);
+ var $td = $tr.find('td.filename');
+ expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
+ expect(previewLoadStub.notCalled).toEqual(true);
+ });
+ it('renders default icon for dir when none provided and no preview is available', function() {
+ var fileData = {
+ type: 'dir',
+ name: 'test dir'
+ };
+ var $tr = FileList.add(fileData);
+ var $td = $tr.find('td.filename');
+ expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/folder.svg');
+ expect(previewLoadStub.notCalled).toEqual(true);
+ });
+ it('renders provided icon for file when provided', function() {
+ var fileData = {
+ type: 'file',
+ name: 'test dir',
+ icon: OC.webroot + '/core/img/filetypes/application-pdf.svg'
+ };
+ var $tr = FileList.add(fileData);
+ var $td = $tr.find('td.filename');
+ expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/application-pdf.svg');
+ expect(previewLoadStub.notCalled).toEqual(true);
+ });
+ it('renders preview when no icon was provided and preview is available', function() {
+ var fileData = {
+ type: 'file',
+ name: 'test dir',
+ isPreviewAvailable: true
+ };
+ var $tr = FileList.add(fileData);
+ var $td = $tr.find('td.filename');
+ expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
+ expect(previewLoadStub.calledOnce).toEqual(true);
+ // third argument is callback
+ previewLoadStub.getCall(0).args[2](OC.webroot + '/somepath.png');
+ expect(getImageUrl($td)).toEqual(OC.webroot + '/somepath.png');
+ });
+ it('renders default file type icon when no icon was provided and no preview is available', function() {
+ var fileData = {
+ type: 'file',
+ name: 'test dir',
+ isPreviewAvailable: false
+ };
+ var $tr = FileList.add(fileData);
+ var $td = $tr.find('td.filename');
+ expect(getImageUrl($td)).toEqual(OC.webroot + '/core/img/filetypes/file.svg');
+ expect(previewLoadStub.notCalled).toEqual(true);
+ });
+ });
+ describe('viewer mode', function() {
+ it('enabling viewer mode hides files table and action buttons', function() {
+ FileList.setViewerMode(true);
+ expect($('#filestable').hasClass('hidden')).toEqual(true);
+ expect($('.actions').hasClass('hidden')).toEqual(true);
+ expect($('.notCreatable').hasClass('hidden')).toEqual(true);
+ });
+ it('disabling viewer mode restores files table and action buttons', function() {
+ FileList.setViewerMode(true);
+ FileList.setViewerMode(false);
+ expect($('#filestable').hasClass('hidden')).toEqual(false);
+ expect($('.actions').hasClass('hidden')).toEqual(false);
+ expect($('.notCreatable').hasClass('hidden')).toEqual(true);
+ });
+ it('disabling viewer mode restores files table and action buttons with correct permissions', function() {
+ $('#permissions').val(0);
+ FileList.setViewerMode(true);
+ FileList.setViewerMode(false);
+ expect($('#filestable').hasClass('hidden')).toEqual(false);
+ expect($('.actions').hasClass('hidden')).toEqual(true);
+ expect($('.notCreatable').hasClass('hidden')).toEqual(false);
+ });
+ });
+ describe('loading file list', function() {
+ beforeEach(function() {
+ var data = {
+ status: 'success',
+ data: {
+ files: testFiles,
+ permissions: 31
+ }
+ };
+ fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2F(subdir|anothersubdir)/, [
+ 200, {
+ "Content-Type": "application/json"
+ },
+ JSON.stringify(data)
+ ]);
+ });
+ it('fetches file list from server and renders it when reload() is called', function() {
+ FileList.reload();
+ expect(fakeServer.requests.length).toEqual(1);
+ var url = fakeServer.requests[0].url;
+ var query = url.substr(url.indexOf('?') + 1);
+ expect(OC.parseQueryString(query)).toEqual({'dir': '/subdir'});
+ fakeServer.respond();
+ expect($('#fileList tr:not(.summary)').length).toEqual(4);
+ expect(FileList.findFileEl('One.txt').length).toEqual(1);
+ });
+ it('switches dir and fetches file list when calling changeDirectory()', function() {
+ FileList.changeDirectory('/anothersubdir');
+ expect(FileList.getCurrentDirectory()).toEqual('/anothersubdir');
+ expect(fakeServer.requests.length).toEqual(1);
+ var url = fakeServer.requests[0].url;
+ var query = url.substr(url.indexOf('?') + 1);
+ expect(OC.parseQueryString(query)).toEqual({'dir': '/anothersubdir'});
+ fakeServer.respond();
+ });
+ it('switches to root dir when current directory does not exist', function() {
+ fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2funexist/, [
+ 404, {
+ "Content-Type": "application/json"
+ },
+ ''
+ ]);
+ FileList.changeDirectory('/unexist');
+ fakeServer.respond();
+ expect(FileList.getCurrentDirectory()).toEqual('/');
+ });
+ it('shows mask before loading file list then hides it at the end', function() {
+ var showMaskStub = sinon.stub(FileList, 'showMask');
+ var hideMaskStub = sinon.stub(FileList, 'hideMask');
+ FileList.changeDirectory('/anothersubdir');
+ expect(showMaskStub.calledOnce).toEqual(true);
+ expect(hideMaskStub.calledOnce).toEqual(false);
+ fakeServer.respond();
+ expect(showMaskStub.calledOnce).toEqual(true);
+ expect(hideMaskStub.calledOnce).toEqual(true);
+ showMaskStub.restore();
+ hideMaskStub.restore();
+ });
+ it('changes URL to target dir', function() {
+ FileList.changeDirectory('/somedir');
+ expect(pushStateStub.calledOnce).toEqual(true);
+ expect(pushStateStub.getCall(0).args[0]).toEqual({dir: '/somedir'});
+ expect(pushStateStub.getCall(0).args[2]).toEqual(OC.webroot + '/index.php/apps/files?dir=/somedir');
+ });
+ it('refreshes breadcrumb after update', function() {
+ var setDirSpy = sinon.spy(FileList.breadcrumb, 'setDirectory');
+ FileList.changeDirectory('/anothersubdir');
+ fakeServer.respond();
+ expect(FileList.breadcrumb.setDirectory.calledOnce).toEqual(true);
+ expect(FileList.breadcrumb.setDirectory.calledWith('/anothersubdir')).toEqual(true);
+ setDirSpy.restore();
+ });
+ });
+ describe('breadcrumb events', function() {
+ beforeEach(function() {
+ var data = {
+ status: 'success',
+ data: {
+ files: testFiles,
+ permissions: 31
+ }
+ };
+ fakeServer.respondWith(/\/index\.php\/apps\/files\/ajax\/list.php\?dir=%2Fsubdir/, [
+ 200, {
+ "Content-Type": "application/json"
+ },
+ JSON.stringify(data)
+ ]);
+ });
+ it('clicking on root breadcrumb changes directory to root', function() {
+ FileList.changeDirectory('/subdir/two/three with space/four/five');
+ fakeServer.respond();
+ var changeDirStub = sinon.stub(FileList, 'changeDirectory');
+ FileList.breadcrumb.$el.find('.crumb:eq(0)').click();
+
+ expect(changeDirStub.calledOnce).toEqual(true);
+ expect(changeDirStub.getCall(0).args[0]).toEqual('/');
+ changeDirStub.restore();
+ });
+ it('clicking on breadcrumb changes directory', function() {
+ FileList.changeDirectory('/subdir/two/three with space/four/five');
+ fakeServer.respond();
+ var changeDirStub = sinon.stub(FileList, 'changeDirectory');
+ FileList.breadcrumb.$el.find('.crumb:eq(3)').click();
+
+ expect(changeDirStub.calledOnce).toEqual(true);
+ expect(changeDirStub.getCall(0).args[0]).toEqual('/subdir/two/three with space');
+ changeDirStub.restore();
+ });
+ it('dropping files on breadcrumb calls move operation', function() {
+ var request, query, testDir = '/subdir/two/three with space/four/five';
+ FileList.changeDirectory(testDir);
+ fakeServer.respond();
+ var $crumb = FileList.breadcrumb.$el.find('.crumb:eq(3)');
+ // no idea what this is but is required by the handler
+ var ui = {
+ helper: {
+ find: sinon.stub()
+ }
+ };
+ // returns a list of tr that were dragged
+ // FIXME: why are their attributes different than the
+ // regular file trs ?
+ ui.helper.find.returns([
+ $('<tr data-filename="One.txt" data-dir="' + testDir + '"></tr>'),
+ $('<tr data-filename="Two.jpg" data-dir="' + testDir + '"></tr>')
+ ]);
+ // simulate drop event
+ FileList._onDropOnBreadCrumb.call($crumb, new $.Event('drop'), ui);
+
+ // will trigger two calls to move.php (first one was previous list.php)
+ expect(fakeServer.requests.length).toEqual(3);
+
+ request = fakeServer.requests[1];
+ expect(request.method).toEqual('POST');
+ expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
+ query = OC.parseQueryString(request.requestBody);
+ expect(query).toEqual({
+ target: '/subdir/two/three with space',
+ dir: testDir,
+ file: 'One.txt'
+ });
+
+ request = fakeServer.requests[2];
+ expect(request.method).toEqual('POST');
+ expect(request.url).toEqual(OC.webroot + '/index.php/apps/files/ajax/move.php');
+ query = OC.parseQueryString(request.requestBody);
+ expect(query).toEqual({
+ target: '/subdir/two/three with space',
+ dir: testDir,
+ file: 'Two.jpg'
+ });
+ });
+ it('dropping files on same dir breadcrumb does nothing', function() {
+ var request, query, testDir = '/subdir/two/three with space/four/five';
+ FileList.changeDirectory(testDir);
+ fakeServer.respond();
+ var $crumb = FileList.breadcrumb.$el.find('.crumb:last');
+ // no idea what this is but is required by the handler
+ var ui = {
+ helper: {
+ find: sinon.stub()
+ }
+ };
+ // returns a list of tr that were dragged
+ // FIXME: why are their attributes different than the
+ // regular file trs ?
+ ui.helper.find.returns([
+ $('<tr data-filename="One.txt" data-dir="' + testDir + '"></tr>'),
+ $('<tr data-filename="Two.jpg" data-dir="' + testDir + '"></tr>')
+ ]);
+ // simulate drop event
+ FileList._onDropOnBreadCrumb.call($crumb, new $.Event('drop'), ui);
+
+ // no extra server request
+ expect(fakeServer.requests.length).toEqual(1);
+ });
});
describe('Download Url', function() {
it('returns correct download URL for single files', function() {
- expect(FileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=some%20file.txt');
- expect(FileList.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fanotherpath%2Fabc&files=some%20file.txt');
+ expect(Files.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=some%20file.txt');
+ expect(Files.getDownloadUrl('some file.txt', '/anotherpath/abc')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fanotherpath%2Fabc&files=some%20file.txt');
$('#dir').val('/');
- expect(FileList.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=some%20file.txt');
+ expect(Files.getDownloadUrl('some file.txt')).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2F&files=some%20file.txt');
});
it('returns correct download URL for multiple files', function() {
- expect(FileList.getDownloadUrl(['a b c.txt', 'd e f.txt'])).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D');
+ expect(Files.getDownloadUrl(['a b c.txt', 'd e f.txt'])).toEqual(OC.webroot + '/index.php/apps/files/ajax/download.php?dir=%2Fsubdir&files=%5B%22a%20b%20c.txt%22%2C%22d%20e%20f.txt%22%5D');
+ });
+ it('returns the correct ajax URL', function() {
+ expect(Files.getAjaxUrl('test', {a:1, b:'x y'})).toEqual(OC.webroot + '/index.php/apps/files/ajax/test.php?a=1&b=x%20y');
});
});
});
diff --git a/apps/files_sharing/ajax/list.php b/apps/files_sharing/ajax/list.php
new file mode 100644
index 00000000000..4b645496253
--- /dev/null
+++ b/apps/files_sharing/ajax/list.php
@@ -0,0 +1,91 @@
+<?php
+/**
+ * ownCloud
+ *
+ * @author Vincent Petry
+ * @copyright 2014 Vincent Petry <pvince81@owncloud.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+// only need filesystem apps
+$RUNTIME_APPTYPES=array('filesystem');
+
+// Init owncloud
+
+if(!\OC_App::isEnabled('files_sharing')){
+ exit;
+}
+
+if(!isset($_GET['t'])){
+ \OC_Response::setStatus(400); //400 Bad Request
+ \OC_Log::write('core-preview', 'No token parameter was passed', \OC_Log::DEBUG);
+ exit;
+}
+
+$token = $_GET['t'];
+
+$password = null;
+if (isset($_POST['password'])) {
+ $password = $_POST['password'];
+}
+
+$relativePath = null;
+if (isset($_GET['dir'])) {
+ $relativePath = $_GET['dir'];
+}
+
+$data = \OCA\Files_Sharing\Helper::setupFromToken($token, $relativePath, $password);
+
+$linkItem = $data['linkItem'];
+// Load the files
+$dir = $data['realPath'];
+
+$dir = \OC\Files\Filesystem::normalizePath($dir);
+if (!\OC\Files\Filesystem::is_dir($dir . '/')) {
+ \OC_Response::setStatus(404);
+ \OCP\JSON::error(array('success' => false));
+ exit();
+}
+
+$data = array();
+$baseUrl = OCP\Util::linkTo('files_sharing', 'index.php') . '?t=' . urlencode($token) . '&dir=';
+
+// make filelist
+$files = \OCA\Files\Helper::getFiles($dir);
+
+$formattedFiles = array();
+foreach ($files as $file) {
+ $entry = \OCA\Files\Helper::formatFileInfo($file);
+ unset($entry['directory']); // for now
+ $entry['permissions'] = \OCP\PERMISSION_READ;
+ $formattedFiles[] = $entry;
+}
+
+$data['directory'] = $relativePath;
+$data['files'] = $formattedFiles;
+$data['dirToken'] = $linkItem['token'];
+
+$permissions = $linkItem['permissions'];
+
+// if globally disabled
+if (OC_Appconfig::getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') {
+ // only allow reading
+ $permissions = \OCP\PERMISSION_READ;
+}
+
+$data['permissions'] = $permissions;
+
+OCP\JSON::success(array('data' => $data));
diff --git a/apps/files_sharing/css/public.css b/apps/files_sharing/css/public.css
index 5246a4b2fec..f0b9b04491f 100644
--- a/apps/files_sharing/css/public.css
+++ b/apps/files_sharing/css/public.css
@@ -35,6 +35,11 @@ body {
background: #fff;
text-align: center;
margin: 45px auto 0;
+ min-height: 150px;
+}
+
+#preview .notCreatable {
+ display: none;
}
#noPreview {
diff --git a/apps/files_sharing/js/public.js b/apps/files_sharing/js/public.js
index 06c168969de..9ce8985f1fd 100644
--- a/apps/files_sharing/js/public.js
+++ b/apps/files_sharing/js/public.js
@@ -8,16 +8,7 @@
*
*/
-/* global OC, FileList, FileActions */
-
-// Override download path to files_sharing/public.php
-function fileDownloadPath(dir, file) {
- var url = $('#downloadURL').val();
- if (url.indexOf('&path=') != -1) {
- url += '/'+file;
- }
- return url;
-}
+/* global OC, FileActions, FileList, Files */
$(document).ready(function() {
@@ -31,31 +22,43 @@ $(document).ready(function() {
action($('#filename').val());
}
}
- FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function(filename) {
- var tr = FileList.findFileEl(filename);
- if (tr.length > 0) {
- window.location = $(tr).find('a.name').attr('href');
- }
- });
+ }
- // override since the format is different
- FileList.getDownloadUrl = function(filename, dir) {
- if ($.isArray(filename)) {
- filename = JSON.stringify(filename);
- }
- var path = dir || FileList.getCurrentDirectory();
- var params = {
- service: 'files',
- t: $('#sharingToken').val(),
- path: path,
- download: null
- };
- if (filename) {
- params.files = filename;
- }
- return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params);
+ // override since the format is different
+ Files.getDownloadUrl = function(filename, dir) {
+ if ($.isArray(filename)) {
+ filename = JSON.stringify(filename);
+ }
+ var path = dir || FileList.getCurrentDirectory();
+ var params = {
+ service: 'files',
+ t: $('#sharingToken').val(),
+ path: path,
+ files: filename,
+ download: null
};
- }
+ return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params);
+ };
+
+ Files.getAjaxUrl = function(action, params) {
+ params = params || {};
+ params.t = $('#sharingToken').val();
+ return OC.filePath('files_sharing', 'ajax', action + '.php') + '?' + OC.buildQueryString(params);
+ };
+
+ FileList.linkTo = function(dir) {
+ var params = {
+ service: 'files',
+ t: $('#sharingToken').val(),
+ dir: dir
+ };
+ return OC.filePath('', '', 'public.php') + '?' + OC.buildQueryString(params);
+ };
+
+ Files.generatePreviewUrl = function(urlSpec) {
+ urlSpec.t = $('#dirToken').val();
+ return OC.generateUrl('/apps/files_sharing/ajax/publicpreview.php?') + $.param(urlSpec);
+ };
var file_upload_start = $('#file_upload_start');
file_upload_start.on('fileuploadadd', function(e, data) {
diff --git a/apps/files_sharing/js/share.js b/apps/files_sharing/js/share.js
index 9f0ed12f935..ea518f3b70e 100644
--- a/apps/files_sharing/js/share.js
+++ b/apps/files_sharing/js/share.js
@@ -1,15 +1,35 @@
+/*
+ * Copyright (c) 2014
+ *
+ * This file is licensed under the Affero General Public License version 3
+ * or later.
+ *
+ * See the COPYING-README file.
+ *
+ */
+
+/* global OC, t, FileList, FileActions */
$(document).ready(function() {
var disableSharing = $('#disableSharing').data('status'),
sharesLoaded = false;
if (typeof OC.Share !== 'undefined' && typeof FileActions !== 'undefined' && !disableSharing) {
+ var oldCreateRow = FileList._createRow;
+ FileList._createRow = function(fileData) {
+ var tr = oldCreateRow.apply(this, arguments);
+ if (fileData.shareOwner) {
+ tr.attr('data-share-owner', fileData.shareOwner);
+ }
+ return tr;
+ };
+
$('#fileList').on('fileActionsReady',function(){
- var allShared = $('#fileList').find('[data-share-owner]').find('[data-Action="Share"]');
+ var allShared = $('#fileList').find('[data-share-owner] [data-Action="Share"]');
allShared.addClass('permanent');
allShared.find('span').text(function(){
- $owner = $(this).closest('tr').attr('data-share-owner');
+ var $owner = $(this).closest('tr').attr('data-share-owner');
return ' ' + t('files_sharing', 'Shared by {owner}', {owner: $owner});
});
diff --git a/apps/files_sharing/lib/helper.php b/apps/files_sharing/lib/helper.php
new file mode 100644
index 00000000000..b602fe3599d
--- /dev/null
+++ b/apps/files_sharing/lib/helper.php
@@ -0,0 +1,114 @@
+<?php
+
+namespace OCA\Files_Sharing;
+
+class Helper {
+
+ /**
+ * Sets up the filesystem and user for public sharing
+ * @param string $token string share token
+ * @param string $relativePath optional path relative to the share
+ * @param string $password optional password
+ */
+ public static function setupFromToken($token, $relativePath = null, $password = null) {
+ \OC_User::setIncognitoMode(true);
+
+ $linkItem = \OCP\Share::getShareByToken($token);
+ if($linkItem === false || ($linkItem['item_type'] !== 'file' && $linkItem['item_type'] !== 'folder')) {
+ \OC_Response::setStatus(404);
+ \OC_Log::write('core-preview', 'Passed token parameter is not valid', \OC_Log::DEBUG);
+ exit;
+ }
+
+ if(!isset($linkItem['uid_owner']) || !isset($linkItem['file_source'])) {
+ \OC_Response::setStatus(500);
+ \OC_Log::write('core-preview', 'Passed token seems to be valid, but it does not contain all necessary information . ("' . $token . '")', \OC_Log::WARN);
+ exit;
+ }
+
+ $type = $linkItem['item_type'];
+ $fileSource = $linkItem['file_source'];
+ $shareOwner = $linkItem['uid_owner'];
+ $rootLinkItem = \OCP\Share::resolveReShare($linkItem);
+ $path = null;
+ if (isset($rootLinkItem['uid_owner'])) {
+ \OCP\JSON::checkUserExists($rootLinkItem['uid_owner']);
+ \OC_Util::tearDownFS();
+ \OC_Util::setupFS($rootLinkItem['uid_owner']);
+ $path = \OC\Files\Filesystem::getPath($linkItem['file_source']);
+ }
+
+ if ($path === null) {
+ \OCP\Util::writeLog('share', 'could not resolve linkItem', \OCP\Util::DEBUG);
+ \OC_Response::setStatus(404);
+ \OCP\JSON::error(array('success' => false));
+ exit();
+ }
+
+ if (!isset($linkItem['item_type'])) {
+ \OCP\Util::writeLog('share', 'No item type set for share id: ' . $linkItem['id'], \OCP\Util::ERROR);
+ \OC_Response::setStatus(404);
+ \OCP\JSON::error(array('success' => false));
+ exit();
+ }
+
+ if (isset($linkItem['share_with'])) {
+ if (!self::authenticate($linkItem, $password)) {
+ \OC_Response::setStatus(403);
+ \OCP\JSON::error(array('success' => false));
+ exit();
+ }
+ }
+
+ $basePath = $path;
+ $rootName = basename($path);
+
+ if ($relativePath !== null && \OC\Files\Filesystem::isReadable($basePath . $relativePath)) {
+ $path .= \OC\Files\Filesystem::normalizePath($relativePath);
+ }
+
+ return array(
+ 'linkItem' => $linkItem,
+ 'basePath' => $basePath,
+ 'realPath' => $path
+ );
+ }
+
+ /**
+ * Authenticate link item with the given password
+ * or with the session if no password was given.
+ * @param array $linkItem link item array
+ * @param string $password optional password
+ *
+ * @return true if authorized, false otherwise
+ */
+ public static function authenticate($linkItem, $password) {
+ if ($password !== null) {
+ if ($linkItem['share_type'] == \OCP\Share::SHARE_TYPE_LINK) {
+ // Check Password
+ $forcePortable = (CRYPT_BLOWFISH != 1);
+ $hasher = new PasswordHash(8, $forcePortable);
+ if (!($hasher->CheckPassword($password.OC_Config::getValue('passwordsalt', ''),
+ $linkItem['share_with']))) {
+ return false;
+ } else {
+ // Save item id in session for future requests
+ \OC::$session->set('public_link_authenticated', $linkItem['id']);
+ }
+ } else {
+ \OCP\Util::writeLog('share', 'Unknown share type '.$linkItem['share_type']
+ .' for share id '.$linkItem['id'], \OCP\Util::ERROR);
+ return false;
+ }
+
+ }
+ else {
+ // not authenticated ?
+ if ( ! \OC::$session->exists('public_link_authenticated')
+ || \OC::$session->get('public_link_authenticated') !== $linkItem['id']) {
+ return false;
+ }
+ }
+ return true;
+ }
+}
diff --git a/apps/files_sharing/public.php b/apps/files_sharing/public.php
index fe61dd4d5a0..ba2494a7b1a 100644
--- a/apps/files_sharing/public.php
+++ b/apps/files_sharing/public.php
@@ -11,31 +11,6 @@ if ($appConfig->getValue('core', 'shareapi_allow_links', 'yes') !== 'yes') {
exit();
}
-function fileCmp($a, $b) {
- if ($a['type'] == 'dir' and $b['type'] != 'dir') {
- return -1;
- } elseif ($a['type'] != 'dir' and $b['type'] == 'dir') {
- return 1;
- } else {
- return strnatcasecmp($a['name'], $b['name']);
- }
-}
-
-function determineIcon($file, $sharingRoot, $sharingToken) {
- // for folders we simply reuse the files logic
- if($file['type'] == 'dir') {
- return \OCA\Files\Helper::determineIcon($file);
- }
-
- $relativePath = substr($file['path'], 6);
- $relativePath = substr($relativePath, strlen($sharingRoot));
- if($file['isPreviewAvailable']) {
- return OCP\publicPreview_icon($relativePath, $sharingToken) . '&c=' . $file['etag'];
- }
- $icon = OCP\mimetype_icon($file['mimetype']);
- return substr($icon, 0, -3) . 'svg';
-}
-
if (isset($_GET['t'])) {
$token = $_GET['t'];
$linkItem = OCP\Share::getShareByToken($token, false);
@@ -153,13 +128,10 @@ if (isset($path)) {
$tmpl->assign('mimetype', \OC\Files\Filesystem::getMimeType($path));
$tmpl->assign('dirToken', $linkItem['token']);
$tmpl->assign('sharingToken', $token);
- $allowPublicUploadEnabled = (bool) ($linkItem['permissions'] & OCP\PERMISSION_CREATE);
- if ($appConfig->getValue('core', 'shareapi_allow_public_upload', 'yes') === 'no') {
- $allowPublicUploadEnabled = false;
- }
- if ($linkItem['item_type'] !== 'folder') {
- $allowPublicUploadEnabled = false;
- }
+ $tmpl->assign('uploadMaxFilesize', $maxUploadFilesize);
+ $tmpl->assign('uploadMaxHumanFilesize', OCP\Util::humanFileSize($maxUploadFilesize));
+ $tmpl->assign('freeSpace', $freeSpace);
+ $tmpl->assign('uploadLimit', $uploadLimit); // PHP upload limit
$urlLinkIdentifiers= (isset($token)?'&t='.$token:'')
.(isset($_GET['dir'])?'&dir='.$_GET['dir']:'')
@@ -170,64 +142,18 @@ if (isset($path)) {
OCP\Util::addStyle('files', 'files');
OCP\Util::addStyle('files', 'upload');
+ OCP\Util::addScript('files', 'breadcrumb');
OCP\Util::addScript('files', 'files');
OCP\Util::addScript('files', 'filelist');
OCP\Util::addscript('files', 'keyboardshortcuts');
$files = array();
$rootLength = strlen($basePath) + 1;
- $totalSize = 0;
- foreach (\OC\Files\Filesystem::getDirectoryContent($path) as $i) {
- $totalSize += $i['size'];
- $i['date'] = OCP\Util::formatDate($i['mtime']);
- if ($i['type'] == 'file') {
- $fileinfo = pathinfo($i['name']);
- $i['basename'] = $fileinfo['filename'];
- if (!empty($fileinfo['extension'])) {
- $i['extension'] = '.' . $fileinfo['extension'];
- } else {
- $i['extension'] = '';
- }
- }
- $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($i['mimetype']);
- $i['directory'] = $getPath;
- $i['permissions'] = OCP\PERMISSION_READ;
- $i['icon'] = determineIcon($i, $basePath, $token);
- $files[] = $i;
- }
- usort($files, "fileCmp");
-
- // Make breadcrumb
- $breadcrumb = array();
- $pathtohere = '';
- foreach (explode('/', $getPath) as $i) {
- if ($i != '') {
- $pathtohere .= '/' . $i;
- $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i);
- }
- }
- $list = new OCP\Template('files', 'part.list', '');
- $list->assign('files', $files);
- $list->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path=');
- $list->assign('downloadURL',
- OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=');
- $list->assign('isPublic', true);
- $list->assign('sharingtoken', $token);
- $list->assign('sharingroot', $basePath);
- $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', '');
- $breadcrumbNav->assign('breadcrumb', $breadcrumb);
- $breadcrumbNav->assign('rootBreadCrumb', $rootName);
- $breadcrumbNav->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path=');
$maxUploadFilesize=OCP\Util::maxUploadFilesize($path);
- $fileHeader = (!isset($files) or count($files) > 0);
- $emptyContent = ($allowPublicUploadEnabled and !$fileHeader);
$freeSpace=OCP\Util::freeSpace($path);
$uploadLimit=OCP\Util::uploadLimit();
$folder = new OCP\Template('files', 'index', '');
- $folder->assign('fileList', $list->fetchPage());
- $folder->assign('breadcrumb', $breadcrumbNav->fetchPage());
$folder->assign('dir', $getPath);
- $folder->assign('isCreatable', $allowPublicUploadEnabled);
$folder->assign('dirToken', $linkItem['token']);
$folder->assign('permissions', OCP\PERMISSION_READ);
$folder->assign('isPublic',true);
@@ -239,15 +165,11 @@ if (isset($path)) {
$folder->assign('uploadLimit', $uploadLimit); // PHP upload limit
$folder->assign('allowZipDownload', intval(OCP\Config::getSystemValue('allowZipDownload', true)));
$folder->assign('usedSpacePercent', 0);
- $folder->assign('fileHeader', $fileHeader);
$folder->assign('disableSharing', true);
$folder->assign('trash', false);
- $folder->assign('emptyContent', $emptyContent);
- $folder->assign('ajaxLoad', false);
$tmpl->assign('folder', $folder->fetchPage());
$maxInputFileSize = OCP\Config::getSystemValue('maxZipInputSize', OCP\Util::computerFileSize('800 MB'));
- $allowZip = OCP\Config::getSystemValue('allowZipDownload', true)
- && ( $maxInputFileSize === 0 || $totalSize <= $maxInputFileSize);
+ $allowZip = OCP\Config::getSystemValue('allowZipDownload', true);
$tmpl->assign('allowZipDownload', intval($allowZip));
$tmpl->assign('downloadURL',
OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path=' . urlencode($getPath));
diff --git a/apps/files_trashbin/ajax/list.php b/apps/files_trashbin/ajax/list.php
index cec18c46525..89a55114524 100644
--- a/apps/files_trashbin/ajax/list.php
+++ b/apps/files_trashbin/ajax/list.php
@@ -4,21 +4,8 @@ OCP\JSON::checkLoggedIn();
// Load the files
$dir = isset( $_GET['dir'] ) ? $_GET['dir'] : '';
-$doBreadcrumb = isset( $_GET['breadcrumb'] ) ? true : false;
$data = array();
-// Make breadcrumb
-if($doBreadcrumb) {
- $breadcrumb = \OCA\Files_Trashbin\Helper::makeBreadcrumb($dir);
-
- $breadcrumbNav = new OCP\Template('files_trashbin', 'part.breadcrumb', '');
- $breadcrumbNav->assign('breadcrumb', $breadcrumb, false);
- $breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php') . '?dir=');
- $breadcrumbNav->assign('home', OCP\Util::linkTo('files', 'index.php'));
-
- $data['breadcrumb'] = $breadcrumbNav->fetchPage();
-}
-
// make filelist
try {
$files = \OCA\Files_Trashbin\Helper::getTrashFiles($dir);
@@ -27,19 +14,11 @@ try {
exit();
}
-$dirlisting = false;
-if ($dir && $dir !== '/') {
- $dirlisting = true;
-}
-
$encodedDir = \OCP\Util::encodePath($dir);
-$list = new OCP\Template('files_trashbin', 'part.list', '');
-$list->assign('files', $files, false);
-$list->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php'). '?dir='.$encodedDir);
-$list->assign('downloadURL', OCP\Util::linkToRoute('download', array('file' => '/')));
-$list->assign('dirlisting', $dirlisting);
-$list->assign('disableDownloadActions', true);
-$data['files'] = $list->fetchPage();
+
+$data['permissions'] = 0;
+$data['directory'] = $dir;
+$data['files'] = \OCA\Files_Trashbin\Helper::formatFileInfos($files);
OCP\JSON::success(array('data' => $data));
diff --git a/apps/files_trashbin/ajax/preview.php b/apps/files_trashbin/ajax/preview.php
index ce64d9ecc9f..32905b2a71c 100644
--- a/apps/files_trashbin/ajax/preview.php
+++ b/apps/files_trashbin/ajax/preview.php
@@ -34,7 +34,7 @@ try{
if ($view->is_dir($file)) {
$mimetype = 'httpd/unix-directory';
} else {
- $pathInfo = pathinfo($file);
+ $pathInfo = pathinfo(ltrim($file, '/'));
$fileName = $pathInfo['basename'];
// if in root dir
if ($pathInfo['dirname'] === '.') {
diff --git a/apps/files_trashbin/ajax/undelete.php b/apps/files_trashbin/ajax/undelete.php
index 9c3ccba7ed8..2b00078669e 100644
--- a/apps/files_trashbin/ajax/undelete.php
+++ b/apps/files_trashbin/ajax/undelete.php
@@ -19,7 +19,7 @@ if (isset($_POST['allfiles']) and $_POST['allfiles'] === 'true') {
foreach (OCA\Files_Trashbin\Helper::getTrashFiles($dir) as $file) {
$fileName = $file['name'];
if (!$dirListing) {
- $fileName .= '.d' . $file['timestamp'];
+ $fileName .= '.d' . $file['mtime'];
}
$list[] = $fileName;
}
diff --git a/apps/files_trashbin/css/trash.css b/apps/files_trashbin/css/trash.css
index 97819f4e80b..7ca3e355fc2 100644
--- a/apps/files_trashbin/css/trash.css
+++ b/apps/files_trashbin/css/trash.css
@@ -1,3 +1,4 @@
-#fileList td a.file, #fileList td a.file span {
+#fileList tr[data-type="file"] td a.name,
+#fileList tr[data-type="file"] td a.name span {
cursor: default;
}
diff --git a/apps/files_trashbin/index.php b/apps/files_trashbin/index.php
index f0c5b0508b8..e63fe1e4188 100644
--- a/apps/files_trashbin/index.php
+++ b/apps/files_trashbin/index.php
@@ -11,6 +11,7 @@ $tmpl = new OCP\Template('files_trashbin', 'index', 'user');
OCP\Util::addStyle('files', 'files');
OCP\Util::addStyle('files_trashbin', 'trash');
+OCP\Util::addScript('files', 'breadcrumb');
OCP\Util::addScript('files', 'filelist');
// filelist overrides
OCP\Util::addScript('files_trashbin', 'filelist');
@@ -34,48 +35,7 @@ if ($isIE8 && isset($_GET['dir'])){
exit();
}
-$ajaxLoad = false;
-
-if (!$isIE8){
- try {
- $files = \OCA\Files_Trashbin\Helper::getTrashFiles($dir);
- } catch (Exception $e) {
- header('Location: ' . OCP\Util::linkTo('files_trashbin', 'index.php'));
- exit();
- }
-}
-else{
- $files = array();
- $ajaxLoad = true;
-}
-
-$dirlisting = false;
-if ($dir && $dir !== '/') {
- $dirlisting = true;
-}
-
-$breadcrumb = \OCA\Files_Trashbin\Helper::makeBreadcrumb($dir);
-
-$breadcrumbNav = new OCP\Template('files_trashbin', 'part.breadcrumb', '');
-$breadcrumbNav->assign('breadcrumb', $breadcrumb);
-$breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php') . '?dir=');
-$breadcrumbNav->assign('home', OCP\Util::linkTo('files', 'index.php'));
-
-$list = new OCP\Template('files_trashbin', 'part.list', '');
-$list->assign('files', $files);
-
-$encodedDir = \OCP\Util::encodePath($dir);
-$list->assign('baseURL', OCP\Util::linkTo('files_trashbin', 'index.php'). '?dir='.$encodedDir);
-$list->assign('downloadURL', OCP\Util::linkTo('files_trashbin', 'download.php') . '?file='.$encodedDir);
-$list->assign('dirlisting', $dirlisting);
-$list->assign('disableDownloadActions', true);
-
-$tmpl->assign('dirlisting', $dirlisting);
-$tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage());
-$tmpl->assign('fileList', $list->fetchPage());
-$tmpl->assign('files', $files);
$tmpl->assign('dir', $dir);
$tmpl->assign('disableSharing', true);
-$tmpl->assign('ajaxLoad', true);
$tmpl->printPage();
diff --git a/apps/files_trashbin/js/disableDefaultActions.js b/apps/files_trashbin/js/disableDefaultActions.js
index afa80cacd6b..50ceaf4696f 100644
--- a/apps/files_trashbin/js/disableDefaultActions.js
+++ b/apps/files_trashbin/js/disableDefaultActions.js
@@ -1,4 +1,3 @@
/* disable download and sharing actions */
var disableDownloadActions = true;
-var disableSharing = true;
var trashBinApp = true;
diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js
index a88459b0a9a..7795daf2775 100644
--- a/apps/files_trashbin/js/filelist.js
+++ b/apps/files_trashbin/js/filelist.js
@@ -1,61 +1,78 @@
-/* globals OC, FileList, t */
-// override reload with own ajax call
-FileList.reload = function(){
- FileList.showMask();
- if (FileList._reloadCall){
- FileList._reloadCall.abort();
- }
- $.ajax({
- url: OC.filePath('files_trashbin','ajax','list.php'),
- data: {
- dir : $('#dir').val(),
- breadcrumb: true
- },
- error: function(result) {
- FileList.reloadCallback(result);
- },
- success: function(result) {
- FileList.reloadCallback(result);
+/* global OC, t, FileList */
+(function() {
+ FileList.appName = t('files_trashbin', 'Deleted files');
+
+ FileList._deletedRegExp = new RegExp(/^(.+)\.d[0-9]+$/);
+
+ /**
+ * Convert a file name in the format filename.d12345 to the real file name.
+ * This will use basename.
+ * The name will not be changed if it has no ".d12345" suffix.
+ * @param name file name
+ * @return converted file name
+ */
+ FileList.getDeletedFileName = function(name) {
+ name = OC.basename(name);
+ var match = FileList._deletedRegExp.exec(name);
+ if (match && match.length > 1) {
+ name = match[1];
}
- });
-};
-
-FileList.appName = t('files_trashbin', 'Deleted files');
-
-FileList._deletedRegExp = new RegExp(/^(.+)\.d[0-9]+$/);
-
-/**
- * Convert a file name in the format filename.d12345 to the real file name.
- * This will use basename.
- * The name will not be changed if it has no ".d12345" suffix.
- * @param name file name
- * @return converted file name
- */
-FileList.getDeletedFileName = function(name) {
- name = OC.basename(name);
- var match = FileList._deletedRegExp.exec(name);
- if (match && match.length > 1) {
- name = match[1];
- }
- return name;
-};
-var oldSetCurrentDir = FileList.setCurrentDir;
-FileList.setCurrentDir = function(targetDir) {
- oldSetCurrentDir.apply(this, arguments);
-
- var baseDir = OC.basename(targetDir);
- if (baseDir !== '') {
- FileList.setPageTitle(FileList.getDeletedFileName(baseDir));
- }
-};
-
-FileList.linkTo = function(dir){
- return OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
-}
-
-FileList.updateEmptyContent = function(){
- var $fileList = $('#fileList');
- var exists = $fileList.find('tr:first').exists();
- $('#emptycontent').toggleClass('hidden', exists);
- $('#filestable th').toggleClass('hidden', !exists);
-}
+ return name;
+ };
+
+ var oldSetCurrentDir = FileList._setCurrentDir;
+ FileList._setCurrentDir = function(targetDir) {
+ oldSetCurrentDir.apply(this, arguments);
+
+ var baseDir = OC.basename(targetDir);
+ if (baseDir !== '') {
+ FileList.setPageTitle(FileList.getDeletedFileName(baseDir));
+ }
+ };
+
+ var oldCreateRow = FileList._createRow;
+ FileList._createRow = function() {
+ // FIXME: MEGAHACK until we find a better solution
+ var tr = oldCreateRow.apply(this, arguments);
+ tr.find('td.filesize').remove();
+ return tr;
+ };
+
+ FileList._onClickBreadCrumb = function(e) {
+ var $el = $(e.target).closest('.crumb'),
+ index = $el.index(),
+ $targetDir = $el.data('dir');
+ // first one is home, let the link makes it default action
+ if (index !== 0) {
+ e.preventDefault();
+ FileList.changeDirectory($targetDir);
+ }
+ };
+
+ var oldAdd = FileList.add;
+ FileList.add = function(fileData, options) {
+ options = options || {};
+ var dir = FileList.getCurrentDirectory();
+ var dirListing = dir !== '' && dir !== '/';
+ // show deleted time as mtime
+ if (fileData.mtime) {
+ fileData.mtime = parseInt(fileData.mtime, 10);
+ }
+ if (!dirListing) {
+ fileData.displayName = fileData.name;
+ fileData.name = fileData.name + '.d' + Math.floor(fileData.mtime / 1000);
+ }
+ return oldAdd.call(this, fileData, options);
+ };
+
+ FileList.linkTo = function(dir){
+ return OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/');
+ };
+
+ FileList.updateEmptyContent = function(){
+ var $fileList = $('#fileList');
+ var exists = $fileList.find('tr:first').exists();
+ $('#emptycontent').toggleClass('hidden', exists);
+ $('#filestable th').toggleClass('hidden', !exists);
+ };
+})();
diff --git a/apps/files_trashbin/js/trash.js b/apps/files_trashbin/js/trash.js
index efe1e89f0bf..5cd49e19aaa 100644
--- a/apps/files_trashbin/js/trash.js
+++ b/apps/files_trashbin/js/trash.js
@@ -8,9 +8,26 @@
*
*/
-/* global OC, t, FileList, FileActions */
-
+/* global OC, t, BreadCrumb, FileActions, FileList, Files */
$(document).ready(function() {
+ var deletedRegExp = new RegExp(/^(.+)\.d[0-9]+$/);
+
+ /**
+ * Convert a file name in the format filename.d12345 to the real file name.
+ * This will use basename.
+ * The name will not be changed if it has no ".d12345" suffix.
+ * @param name file name
+ * @return converted file name
+ */
+ function getDeletedFileName(name) {
+ name = OC.basename(name);
+ var match = deletedRegExp.exec(name);
+ if (match && match.length > 1) {
+ name = match[1];
+ }
+ return name;
+ }
+
function removeCallback(result) {
if (result.status !== 'success') {
OC.dialogs.alert(result.data.message, t('core', 'Error'));
@@ -18,7 +35,7 @@ $(document).ready(function() {
var files = result.data.success;
for (var i = 0; i < files.length; i++) {
- FileList.findFileEl(OC.basename(files[i].filename)).remove();
+ FileList.remove(OC.basename(files[i].filename), {updateSummary: false});
}
FileList.updateFileSummary();
FileList.updateEmptyContent();
@@ -74,7 +91,6 @@ $(document).ready(function() {
}
procesSelection();
});
-
$('.undelete').click('click', function(event) {
event.preventDefault();
var allFiles = $('#select_all').is(':checked');
@@ -89,7 +105,7 @@ $(document).ready(function() {
};
}
else {
- files = getSelectedFiles('name');
+ files = Files.getSelectedFiles('name');
for (var i = 0; i < files.length; i++) {
var deleteAction = FileList.findFileEl(files[i]).children("td.date").children(".action.delete");
deleteAction.removeClass('delete-icon').addClass('progress-icon');
@@ -131,7 +147,7 @@ $(document).ready(function() {
};
}
else {
- files = getSelectedFiles('name');
+ files = Files.getSelectedFiles('name');
params = {
files: JSON.stringify(files),
dir: FileList.getCurrentDirectory()
@@ -158,7 +174,7 @@ $(document).ready(function() {
}
FileList.hideMask();
// simply remove all files
- FileList.update('');
+ FileList.setFiles([]);
enableActions();
}
else {
@@ -191,7 +207,7 @@ $(document).ready(function() {
var filename = $(this).parent().parent().attr('data-file');
var tr = FileList.findFileEl(filename);
var renaming = tr.data('renaming');
- if(!renaming && !FileList.isLoading(filename)){
+ if(!renaming){
if(mime.substr(0, 5) === 'text/'){ //no texteditor for now
return;
}
@@ -203,47 +219,61 @@ $(document).ready(function() {
action(filename);
}
}
-
- // event handlers for breadcrumb items
- $('#controls').delegate('.crumb:not(.home) a', 'click', onClickBreadcrumb);
});
- FileActions.actions.dir = {
- // only keep 'Open' action for navigation
- 'Open': FileActions.actions.dir.Open
+ /**
+ * Override crumb URL maker (hacky!)
+ */
+ FileList.breadcrumb.getCrumbUrl = function(part, index) {
+ if (index === 0) {
+ return OC.linkTo('files', 'index.php');
+ }
+ return OC.linkTo('files_trashbin', 'index.php')+"?dir=" + encodeURIComponent(part.dir);
};
-});
-/**
- * @brief get a list of selected files
- * @param string property (option) the property of the file requested
- * @return array
- *
- * possible values for property: name, mime, size and type
- * if property is set, an array with that property for each file is returnd
- * if it's ommited an array of objects with all properties is returned
- */
-function getSelectedFiles(property){
- var elements=$('td.filename input:checkbox:checked').parent().parent();
- var files=[];
- elements.each(function(i,element){
- var file={
- name:$(element).attr('data-file'),
- timestamp:$(element).attr('data-timestamp'),
- type:$(element).attr('data-type')
+ Files.generatePreviewUrl = function(urlSpec) {
+ return OC.generateUrl('/apps/files_trashbin/ajax/preview.php?') + $.param(urlSpec);
+ };
+
+ Files.getDownloadUrl = function(action, params) {
+ // no downloads
+ return '#';
+ };
+
+ Files.getAjaxUrl = function(action, params) {
+ var q = '';
+ if (params) {
+ q = '?' + OC.buildQueryString(params);
+ }
+ return OC.filePath('files_trashbin', 'ajax', action + '.php') + q;
+ };
+
+
+ /**
+ * Override crumb making to add "Deleted Files" entry
+ * and convert files with ".d" extensions to a more
+ * user friendly name.
+ */
+ var oldMakeCrumbs = BreadCrumb.prototype._makeCrumbs;
+ BreadCrumb.prototype._makeCrumbs = function() {
+ var parts = oldMakeCrumbs.apply(this, arguments);
+ // duplicate first part
+ parts.unshift(parts[0]);
+ parts[1] = {
+ dir: '/',
+ name: t('files_trashbin', 'Deleted Files')
};
- if(property){
- files.push(file[property]);
- }else{
- files.push(file);
+ for (var i = 2; i < parts.length; i++) {
+ parts[i].name = getDeletedFileName(parts[i].name);
}
- });
- return files;
-}
+ return parts;
+ };
-function fileDownloadPath(dir, file) {
- return OC.filePath('files_trashbin', '', 'download.php') + '?file='+encodeURIComponent(file);
-}
+ FileActions.actions.dir = {
+ // only keep 'Open' action for navigation
+ 'Open': FileActions.actions.dir.Open
+ };
+});
function enableActions() {
$(".action").css("display", "inline");
diff --git a/apps/files_trashbin/lib/helper.php b/apps/files_trashbin/lib/helper.php
index 9c24332a964..e6ca73520a6 100644
--- a/apps/files_trashbin/lib/helper.php
+++ b/apps/files_trashbin/lib/helper.php
@@ -27,6 +27,10 @@ class Helper
if ($dirContent === false) {
return $result;
}
+
+ list($storage, $internalPath) = $view->resolvePath($dir);
+ $absoluteDir = $view->getAbsolutePath($dir);
+
if (is_resource($dirContent)) {
while (($entryName = readdir($dirContent)) !== false) {
if (!\OC\Files\Filesystem::isIgnoredDir($entryName)) {
@@ -40,76 +44,41 @@ class Helper
$parts = explode('/', ltrim($dir, '/'));
$timestamp = substr(pathinfo($parts[0], PATHINFO_EXTENSION), 1);
}
- $result[] = array(
- 'id' => $id,
- 'timestamp' => $timestamp,
- 'mime' => \OC_Helper::getFileNameMimeType($id),
+ $i = array(
+ 'name' => $id,
+ 'mtime' => $timestamp,
+ 'mimetype' => \OC_Helper::getFileNameMimeType($id),
'type' => $view->is_dir($dir . '/' . $entryName) ? 'dir' : 'file',
- 'location' => $dir,
+ 'directory' => ($dir === '/') ? '' : $dir,
);
+ $result[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i);
}
}
closedir($dirContent);
}
- $files = array();
- $id = 0;
- list($storage, $internalPath) = $view->resolvePath($dir);
- $absoluteDir = $view->getAbsolutePath($dir);
- foreach ($result as $r) {
- $i = array();
- $i['id'] = $id++;
- $i['name'] = $r['id'];
- $i['date'] = \OCP\Util::formatDate($r['timestamp']);
- $i['timestamp'] = $r['timestamp'];
- $i['etag'] = $r['timestamp']; // add fake etag, it is only needed to identify the preview image
- $i['mimetype'] = $r['mime'];
- $i['type'] = $r['type'];
- if ($i['type'] === 'file') {
- $fileinfo = pathinfo($r['id']);
- $i['basename'] = $fileinfo['filename'];
- $i['extension'] = isset($fileinfo['extension']) ? ('.'.$fileinfo['extension']) : '';
- }
- $i['directory'] = $r['location'];
- if ($i['directory'] === '/') {
- $i['directory'] = '';
- }
- $i['permissions'] = \OCP\PERMISSION_READ;
- if (\OCP\App::isEnabled('files_encryption')) {
- $i['isPreviewAvailable'] = false;
- } else {
- $i['isPreviewAvailable'] = \OC::$server->getPreviewManager()->isMimeSupported($r['mime']);
- }
- $i['icon'] = \OCA\Files\Helper::determineIcon($i);
- $files[] = new FileInfo($absoluteDir . '/' . $i['name'], $storage, $internalPath . '/' . $i['name'], $i);
- }
-
- usort($files, array('\OCA\Files\Helper', 'fileCmp'));
+ usort($result, array('\OCA\Files\Helper', 'fileCmp'));
- return $files;
+ return $result;
}
/**
- * Splits the given path into a breadcrumb structure.
- * @param string $dir path to process
- * @return array where each entry is a hash of the absolute
- * directory path and its name
+ * Format file infos for JSON
+ * @param \OCP\Files\FileInfo[] $fileInfos file infos
*/
- public static function makeBreadcrumb($dir){
- // Make breadcrumb
- $pathtohere = '';
- $breadcrumb = array();
- foreach (explode('/', $dir) as $i) {
- if ($i !== '') {
- if ( preg_match('/^(.+)\.d[0-9]+$/', $i, $match) ) {
- $name = $match[1];
- } else {
- $name = $i;
- }
- $pathtohere .= '/' . $i;
- $breadcrumb[] = array('dir' => $pathtohere, 'name' => $name);
+ public static function formatFileInfos($fileInfos) {
+ $files = array();
+ $id = 0;
+ foreach ($fileInfos as $i) {
+ $entry = \OCA\Files\Helper::formatFileInfo($i);
+ $entry['id'] = $id++;
+ $entry['etag'] = $entry['mtime']; // add fake etag, it is only needed to identify the preview image
+ $entry['permissions'] = \OCP\PERMISSION_READ;
+ if (\OCP\App::isEnabled('files_encryption')) {
+ $entry['isPreviewAvailable'] = false;
}
+ $files[] = $entry;
}
- return $breadcrumb;
+ return $files;
}
}
diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php
index f9264d4352c..615cf8bdd00 100644
--- a/apps/files_trashbin/templates/index.php
+++ b/apps/files_trashbin/templates/index.php
@@ -1,13 +1,11 @@
<div id="controls">
- <?php print_unescaped($_['breadcrumb']); ?>
- <div id="file_action_panel"></div>
+ <div id="file_action_panel"></div>
</div>
<div id='notification'></div>
-<div id="emptycontent" <?php if (!(isset($_['files']) && count($_['files']) === 0 && $_['dirlisting'] === false && !$_['ajaxLoad'])):?>class="hidden"<?php endif; ?>><?php p($l->t('Nothing in here. Your trash bin is empty!'))?></div>
+<div id="emptycontent" class="hidden"><?php p($l->t('Nothing in here. Your trash bin is empty!'))?></div>
-<input type="hidden" name="ajaxLoad" id="ajaxLoad" value="<?php p($_['ajaxLoad']); ?>" />
-<input type="hidden" id="disableSharing" data-status="<?php p($_['disableSharing']); ?>"></input>
+<input type="hidden" id="permissions" value="0"></input>
<input type="hidden" name="dir" value="<?php p($_['dir']) ?>" id="dir">
<table id="filestable">
@@ -40,6 +38,5 @@
</tr>
</thead>
<tbody id="fileList">
- <?php print_unescaped($_['fileList']); ?>
</tbody>
</table>
diff --git a/apps/files_trashbin/templates/part.breadcrumb.php b/apps/files_trashbin/templates/part.breadcrumb.php
deleted file mode 100644
index fdf78c190d0..00000000000
--- a/apps/files_trashbin/templates/part.breadcrumb.php
+++ /dev/null
@@ -1,19 +0,0 @@
-<div class="crumb home">
- <a href="<?php print_unescaped($_['home']); ?>">
- <img src="<?php print_unescaped(OCP\image_path('core', 'places/home.svg'));?>" class="svg" />
- </a>
-</div>
-<div class="crumb svg"
- data-dir='/'>
- <a href="<?php p($_['baseURL']); ?>"><?php p($l->t("Deleted Files")); ?></a>
-</div>
-<?php if(count($_["breadcrumb"])):?>
-<?php endif;?>
-<?php for($i=0; $i<count($_["breadcrumb"]); $i++):
- $crumb = $_["breadcrumb"][$i];
- $dir = \OCP\Util::encodePath($crumb["dir"]); ?>
- <div class="crumb <?php if($i === count($_["breadcrumb"])-1) p('last');?> svg"
- data-dir='<?php p($dir);?>'>
- <a href="<?php p($_['baseURL'].$dir); ?>"><?php p($crumb["name"]); ?></a>
- </div>
-<?php endfor;
diff --git a/apps/files_trashbin/templates/part.list.php b/apps/files_trashbin/templates/part.list.php
deleted file mode 100644
index c32d9fd54da..00000000000
--- a/apps/files_trashbin/templates/part.list.php
+++ /dev/null
@@ -1,79 +0,0 @@
-<?php foreach($_['files'] as $file):
- $relative_deleted_date = OCP\relative_modified_date($file['timestamp']);
- // the older the file, the brighter the shade of grey; days*14
- $relative_date_color = round((time()-$file['date'])/60/60/24*14);
- if($relative_date_color>200) $relative_date_color = 200;
- $name = \OCP\Util::encodePath($file['name']);
- $directory = \OCP\Util::encodePath($file['directory']); ?>
- <tr data-filename="<?php p($file['name']);?>"
- data-type="<?php ($file['type'] === 'dir')?p('dir'):p('file')?>"
- data-mime="<?php p($file['mimetype'])?>"
- data-permissions='<?php p($file['permissions']); ?>'
- <?php if ( $_['dirlisting'] ): ?>
- id="<?php p($file['directory'].'/'.$file['name']);?>"
- data-file="<?php p($name);?>"
- data-timestamp=''
- data-dirlisting=1
- <?php else: ?>
- id="<?php p($file['name'].'.d'.$file['timestamp']);?>"
- data-file="<?php p($file['name'].'.d'.$file['timestamp']);?>"
- data-timestamp='<?php p($file['timestamp']);?>'
- data-dirlisting=0
- <?php endif; ?>>
- <?php if($file['isPreviewAvailable']): ?>
- <td class="filename svg preview-icon"
- <?php else: ?>
- <td class="filename svg"
- <?php endif; ?>
- <?php if($file['type'] === 'dir'): ?>
- style="background-image:url(<?php print_unescaped(OCP\mimetype_icon('dir')); ?>)"
- <?php else: ?>
- <?php if($file['isPreviewAvailable']): ?>
- style="background-image:url(<?php print_unescaped(OCA\Files_Trashbin\Trashbin::preview_icon(!$_['dirlisting'] ? ($file['name'].'.d'.$file['timestamp']) : ($file['directory'].'/'.$file['name']))); ?>)"
- <?php else: ?>
- style="background-image:url(<?php print_unescaped(OCP\mimetype_icon($file['mimetype'])); ?>)"
- <?php endif; ?>
- <?php endif; ?>
- >
- <?php if(!isset($_['readonly']) || !$_['readonly']): ?>
- <input id="select-<?php p($file['id']); ?>" type="checkbox" />
- <label for="select-<?php p($file['id']); ?>"></label>
- <?php endif; ?>
- <?php if($file['type'] === 'dir'): ?>
- <?php if( $_['dirlisting'] ): ?>
- <a class="name dir" href="<?php p($_['baseURL'].'/'.$name); ?>" title="">
- <?php else: ?>
- <a class="name dir" href="<?php p($_['baseURL'].'/'.$name.'.d'.$file['timestamp']); ?>" title="">
- <?php endif; ?>
- <?php else: ?>
- <?php if( $_['dirlisting'] ): ?>
- <a class="name file" href="<?php p($_['downloadURL'].'/'.$name); ?>" title="">
- <?php else: ?>
- <a class="name file" href="<?php p($_['downloadURL'].'/'.$name.'.d'.$file['timestamp']);?>" title="">
- <?php endif; ?>
- <?php endif; ?>
- <span class="nametext">
- <?php if($file['type'] === 'dir'):?>
- <?php print_unescaped(htmlspecialchars($file['name']));?>
- <?php else:?>
- <?php print_unescaped(htmlspecialchars($file['basename']));?><span
- class='extension'><?php p($file['extension']);?></span>
- <?php endif;?>
- </span>
- <?php if($file['type'] === 'dir'):?>
- <span class="uploadtext" currentUploads="0">
- </span>
- <?php endif;?>
- </a>
- </td>
- <td class="date">
- <span class="modified"
- title="<?php p($file['date']); ?>"
- style="color:rgb(<?php p($relative_date_color.','
- .$relative_date_color.','
- .$relative_date_color) ?>)">
- <?php p($relative_deleted_date); ?>
- </span>
- </td>
- </tr>
-<?php endforeach;
diff --git a/core/css/styles.css b/core/css/styles.css
index 8a12057529d..f978eab7cac 100644
--- a/core/css/styles.css
+++ b/core/css/styles.css
@@ -283,6 +283,10 @@ input[type="submit"].enabled {
padding: 7px 10px
}
+#controls .button.hidden {
+ display: none;
+}
+
#content { position:relative; height:100%; width:100%; }
#content .hascontrols {
position: relative;
@@ -922,6 +926,9 @@ div.crumb {
background: url('../img/breadcrumb.svg') no-repeat right center;
height: 44px;
}
+div.crumb.hidden {
+ display: none;
+}
div.crumb a,
div.crumb span {
position: relative;
diff --git a/core/js/js.js b/core/js/js.js
index e907db2837e..9a3b2ee6a5d 100644
--- a/core/js/js.js
+++ b/core/js/js.js
@@ -159,6 +159,7 @@ function escapeHTML(s) {
* @param file The filename
* @param dir The directory the file is in - e.g. $('#dir').val()
* @return string
+* @deprecated use Files.getDownloadURL() instead
*/
function fileDownloadPath(dir, file) {
return OC.filePath('files', 'ajax', 'download.php')+'?files='+encodeURIComponent(file)+'&dir='+encodeURIComponent(dir);
diff --git a/core/js/oc-dialogs.js b/core/js/oc-dialogs.js
index d1bcb4659b8..73ed20b7553 100644
--- a/core/js/oc-dialogs.js
+++ b/core/js/oc-dialogs.js
@@ -514,7 +514,7 @@ var OCdialogs = {
}
return $.getJSON(
- OC.filePath('files', 'ajax', 'rawlist.php'),
+ OC.filePath('files', 'ajax', 'list.php'),
{
dir: dir,
mimetypes: JSON.stringify(mimeType)
@@ -539,7 +539,7 @@ var OCdialogs = {
this.$filelist.empty().addClass('loading');
this.$filePicker.data('path', dir);
$.when(this._getFileList(dir, this.$filePicker.data('mimetype'))).then(function(response) {
- $.each(response.data, function(index, file) {
+ $.each(response.data.files, function(index, file) {
if (file.type === 'dir') {
dirs.push(file);
} else {
@@ -555,9 +555,16 @@ var OCdialogs = {
type: entry.type,
dir: dir,
filename: entry.name,
- date: OC.mtime2date(entry.mtime)
+ date: OC.mtime2date(Math.floor(entry.mtime / 1000))
});
- $li.find('img').attr('src', entry.mimetype_icon);
+ $li.find('img').attr('src', entry.icon);
+ if (entry.isPreviewAvailable) {
+ var urlSpec = {
+ file: dir + '/' + entry.name
+ };
+ var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
+ $li.find('img').attr('src', previewUrl);
+ }
self.$filelist.append($li);
});