]> source.dussan.org Git - nextcloud-server.git/commitdiff
Files, trashbin, public apps use ajax/JSON for the file list
authorVincent Petry <pvince81@owncloud.com>
Mon, 28 Oct 2013 19:22:06 +0000 (20:22 +0100)
committerVincent Petry <pvince81@owncloud.com>
Wed, 2 Apr 2014 13:33:47 +0000 (15:33 +0200)
Files app:

- removed file list template, now rendering list from JSON response
- FileList.addFile/addDir is now FileList.add() and takes a JS map with all required
  arguments instead of having a long number of function arguments
- added unit tests for many FileList operations
- fixed newfile.php, newfolder.php and rename.php to return the file's
  full JSON on success
- removed obsolete/unused undo code
- removed download_url / loading options, now using
  Files.getDownloadUrl() for that
- server side now uses Helper::getFileInfo() to prepare file JSON response
- previews are now client-side only

Breadcrumbs are now JS only:

- Added BreadCrumb class to handle breadcrumb rendering and events
- Added unit test for BreadCrumb class
- Moved all relevant JS functions to the BreadCrumb class

Public page now uses ajax to load the file list:

- Added Helper class in sharing app to make it easier to authenticate
  and retrieve the file's real path
- Added ajax/list.php to retrieve the file list
- Fixed FileActions and FileList to work with the ajax list

Core:

- Fixed file picker dialog to use the same list format as files app

41 files changed:
apps/files/ajax/list.php
apps/files/ajax/newfile.php
apps/files/ajax/newfolder.php
apps/files/ajax/rawlist.php [deleted file]
apps/files/ajax/upload.php
apps/files/index.php
apps/files/js/breadcrumb.js [new file with mode: 0644]
apps/files/js/file-upload.js
apps/files/js/fileactions.js
apps/files/js/filelist.js
apps/files/js/files.js
apps/files/lib/app.php
apps/files/lib/helper.php
apps/files/templates/index.php
apps/files/templates/part.breadcrumb.php [deleted file]
apps/files/templates/part.list.php [deleted file]
apps/files/tests/ajax_rename.php
apps/files/tests/js/breadcrumbSpec.js [new file with mode: 0644]
apps/files/tests/js/fileactionsSpec.js
apps/files/tests/js/filelistSpec.js
apps/files_sharing/ajax/list.php [new file with mode: 0644]
apps/files_sharing/css/public.css
apps/files_sharing/js/public.js
apps/files_sharing/js/share.js
apps/files_sharing/lib/helper.php [new file with mode: 0644]
apps/files_sharing/public.php
apps/files_trashbin/ajax/list.php
apps/files_trashbin/ajax/preview.php
apps/files_trashbin/ajax/undelete.php
apps/files_trashbin/css/trash.css
apps/files_trashbin/index.php
apps/files_trashbin/js/disableDefaultActions.js
apps/files_trashbin/js/filelist.js
apps/files_trashbin/js/trash.js
apps/files_trashbin/lib/helper.php
apps/files_trashbin/templates/index.php
apps/files_trashbin/templates/part.breadcrumb.php [deleted file]
apps/files_trashbin/templates/part.list.php [deleted file]
core/css/styles.css
core/js/js.js
core/js/oc-dialogs.js

index 3bb35579d5fd177f5e5e86818428347735af823a..0ffae22ec316979730836f4f3dbe644e95b5512e 100644 (file)
@@ -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));
index 1234cf11394342dfb655c97687197a8b7f32f06a..7d6be59beab2b9e29c257fa9a5192b71db7a3000 100644 (file)
@@ -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();
        }
 }
index 032447460f3fb0961c4c0251e6f02aa7b5b6a34c..89c241189d71cf8f0fc3332e4c79925e58a79d4b 100644 (file)
@@ -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 (file)
index f18bbff..0000000
+++ /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));
index 4ed51c527759b49d4626016e44f36e69a3e72083..b21a9dfba2ed256e077233d94272201c9516c2ff 100644 (file)
@@ -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;
                        }
                }
        }
index 4d765b69e4126b67262cfefae868e6f7e753535c..a575e02348ab91f229307ebe61c6e13b5e027ce4 100644 (file)
@@ -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 (file)
index 0000000..21010c7
--- /dev/null
@@ -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;
+})();
+
index 371c83e742cf75172d55e7b3bcba826d5364406c..e5d1eacbd149f2ad52db522e66ed71f0f701086e 100644 (file)
@@ -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();
index 732690f047a4152c95bff8b98830be3baa8acd05..631aebea954d12d0319d242ea8cbeb9c18dd007f 100644 (file)
@@ -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);
                        }
index cda4e823a73b9eb4acfc4610f92a5db8ed40667f..509929d0e5534ed1f69c8fa82fa7826535d50884 100644 (file)
  *
  */
 
-/* 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,98 +259,122 @@ 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)
@@ -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();
 });
+
index 1137364db4a8c2b91a3839d9989eb7ab8cffed68..4c2d87d808ca1811bd9255890365d1e139263889 100644 (file)
@@ -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);
 }
 
index fea88faa92a872cb17b8757b8d2e952004f246f7..adfca669577babcb6c3afba4067a250835453d67 100644 (file)
@@ -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 {
index c41e2d155813fd1b3f6333b36566c14c47c55042..b765fdaf3e3ac234653b688bb2a6a516412a49ec 100644 (file)
@@ -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;
        }
 }
index 34acd9c4f51260745a43324c6293380501c560b1..95edd625cb31491552427f55b79b02d3e9680b02 100644 (file)
@@ -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>
                        </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! -->
 
 <!-- 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 (file)
index 69b4cbc..0000000
+++ /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 (file)
index 8a7a1e3..0000000
+++ /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;
index e53c0fb3dd180e1b8602e0b7f2041b5a142f8120..cb62d22a7e2bab5cdce938653552f404d93f99d1 100644 (file)
@@ -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 (file)
index 0000000..1bfe530
--- /dev/null
@@ -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);
+               });
+       });
+});
index 80c04b5b242d5dc05dd90ebe660d771dee1b293b..3c22c84b866d979397eaaac831a402dbd72149be 100644 (file)
@@ -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();
index 8f4cb86ab4ae14158b737a6e4a761866a4fb6eda..ca85a360cf508a0e684b17e123b76fa7da7039de 100644 (file)
@@ -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 (file)
index 0000000..4b64549
--- /dev/null
@@ -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));
index 5246a4b2fec1dd6dde2ec8153c3c27966d8c60a8..f0b9b04491fdbb0591f923a64aa79712506313a8 100644 (file)
@@ -35,6 +35,11 @@ body {
        background: #fff;
        text-align: center;
        margin: 45px auto 0;
+       min-height: 150px;
+}
+
+#preview .notCreatable {
+       display: none;
 }
 
 #noPreview {
index 06c168969deac4620ba42600ad18e8e645c0c0e0..9ce8985f1fd28e381e9a45ae515c0648a714d302 100644 (file)
@@ -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) {
index 9f0ed12f935cce15439de22c0dcd5544537c396f..ea518f3b70e61e724d0a9ecace198b72f98eecdd 100644 (file)
@@ -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 (file)
index 0000000..b602fe3
--- /dev/null
@@ -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;
+       }
+}
index fe61dd4d5a048d0a128597744c9ceaf31ae5a9c9..ba2494a7b1a18c6832eb9691b23b4bfa9976841e 100644 (file)
@@ -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));
index cec18c46525dd63dd61daccf2dc7695e05bb2ea2..89a5511452449ccb416cbac15ca2952c723c19a7 100644 (file)
@@ -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));
 
index ce64d9ecc9f962bbc4532f6d53729b517e0be00c..32905b2a71ce41d54df8bf72d456ef80cf8d1e58 100644 (file)
@@ -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'] === '.') {
index 9c3ccba7ed8812021aa26520025ffdc7844d4f32..2b00078669ee42074ae9d63e8b1fac1bd43eaeb3 100644 (file)
@@ -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;
        }
index 97819f4e80b5b15fcd4e31077821075aa907af7c..7ca3e355fc211bf02aabb20bb036710279d52a6e 100644 (file)
@@ -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;
 }
index f0c5b0508b8440285ccca7e89ed0e1fedf98e882..e63fe1e4188e46e2052818e53b3873d5b6b8d1a0 100644 (file)
@@ -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();
index afa80cacd6b04756f9abf296ca0908061561bd6f..50ceaf4696fe1aa041dfea3c29d02b8e513dc6da 100644 (file)
@@ -1,4 +1,3 @@
 /* disable download and sharing actions */
 var disableDownloadActions = true;
-var disableSharing = true;
 var trashBinApp = true;
index a88459b0a9aaa016b4980d731a5cffeba9eb4bd0..7795daf2775bbc609c82c7dfcac868d565cccc48 100644 (file)
@@ -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);
+       };
+})();
index efe1e89f0bf3fc2c67a1d5e2f643d860995996bd..5cd49e19aaacab86488be40b35ccfe60e1bf2ba5 100644 (file)
@@ -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");
index 9c24332a964dd2227ab1dfd9c5d6d640229a8481..e6ca73520a6fe5bb747d7ff06e3c4ea5152e7afe 100644 (file)
@@ -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;
        }
 }
index f9264d4352cca017004e6a3021f304bd5feb5dde..615cf8bdd009f0fbff43113cff296de50e6f948f 100644 (file)
@@ -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 (file)
index fdf78c1..0000000
+++ /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 (file)
index c32d9fd..0000000
+++ /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;
index 8a12057529d934504571788c35cfa57be6ed6c66..f978eab7cac8ff26555a3a8ab38ffc7e81ea3f25 100644 (file)
@@ -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;
index e907db2837e6b82f7c2808ab9cb247ee873b5eba..9a3b2ee6a5d663ecfdb285853016c9aa7a6d587e 100644 (file)
@@ -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);
index d1bcb4659b89c80671aa65578d40e51b66789458..73ed20b75538bf19485a73c42f660554debff505 100644 (file)
@@ -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);
                        });