From 1304b511e9533dee4cf1125e625568c8a74719a1 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sat, 17 Aug 2013 13:07:18 +0200 Subject: [PATCH 01/12] Ajax calls for "files" and "files_trashbin" apps Frontend: - The files app list now uses ajax calls to refresh the list. - Added support the browser back button (history API). - Added mask + spinner while loading file list Backend: - Added utility function in core JS for parsing query strings. - Moved file list + breadcrumb template data code to helper functions - Fixed some file paths in trashbin app to be similar to the files app --- apps/files/ajax/list.php | 36 +++-- apps/files/css/files.css | 22 +++ apps/files/index.php | 42 +----- apps/files/js/fileactions.js | 5 +- apps/files/js/filelist.js | 137 ++++++++++++++++-- apps/files/js/files.js | 48 +++--- apps/files/lib/helper.php | 65 +++++++++ apps/files/templates/index.php | 10 +- apps/files/templates/part.list.php | 4 +- apps/files_sharing/js/share.js | 2 +- apps/files_sharing/public.php | 2 +- apps/files_trashbin/ajax/list.php | 51 +++++++ apps/files_trashbin/index.php | 93 ++---------- apps/files_trashbin/js/filelist.js | 29 ++++ apps/files_trashbin/js/trash.js | 14 +- apps/files_trashbin/lib/helper.php | 97 +++++++++++++ apps/files_trashbin/templates/index.php | 3 + .../templates/part.breadcrumb.php | 4 +- apps/files_trashbin/templates/part.list.php | 3 +- core/js/js.js | 32 ++++ 20 files changed, 518 insertions(+), 181 deletions(-) create mode 100644 apps/files_trashbin/ajax/list.php create mode 100644 apps/files_trashbin/js/filelist.js create mode 100644 apps/files_trashbin/lib/helper.php diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index 14ed43cbb3a..035ffc0e393 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -10,36 +10,34 @@ OCP\JSON::checkLoggedIn(); // Load the files $dir = isset( $_GET['dir'] ) ? $_GET['dir'] : ''; + +if (!\OC\Files\Filesystem::is_dir($dir . '/')) { + header("HTTP/1.0 404 Not Found"); + exit(); +} + $doBreadcrumb = isset($_GET['breadcrumb']); $data = array(); +$baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; // Make breadcrumb if($doBreadcrumb) { - $breadcrumb = array(); - $pathtohere = "/"; - foreach( explode( "/", $dir ) as $i ) { - if( $i != "" ) { - $pathtohere .= "$i/"; - $breadcrumb[] = array( "dir" => $pathtohere, "name" => $i ); - } - } + $breadcrumb = \OCA\files\lib\Helper::makeBreadcrumb($dir); - $breadcrumbNav = new OCP\Template( "files", "part.breadcrumb", "" ); - $breadcrumbNav->assign( "breadcrumb", $breadcrumb, false ); + $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); + $breadcrumbNav->assign('breadcrumb', $breadcrumb, false); + $breadcrumbNav->assign('baseURL', $baseUrl); $data['breadcrumb'] = $breadcrumbNav->fetchPage(); } // make filelist -$files = array(); -foreach( \OC\Files\Filesystem::getDirectoryContent( $dir ) as $i ) { - $i["date"] = OCP\Util::formatDate($i["mtime"] ); - $i['icon'] = \OCA\files\lib\Helper::determineIcon($i); - $files[] = $i; -} +$files = \OCA\files\lib\Helper::getFiles($dir); -$list = new OCP\Template( "files", "part.list", "" ); -$list->assign( "files", $files, false ); -$data = array('files' => $list->fetchPage()); +$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' => '/'))); +$data['files'] = $list->fetchPage(); OCP\JSON::success(array('data' => $data)); diff --git a/apps/files/css/files.css b/apps/files/css/files.css index 8053649bd55..f506a379477 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -336,3 +336,25 @@ table.dragshadow td.size { text-align: center; margin-left: -200px; } +.mask { + z-index: 50; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: white; + background-repeat: no-repeat no-repeat; + background-position: 50%; + opacity: 0.7; + filter: alpha(opacity=70); + transition: opacity 100ms; + -moz-transition: opacity 100ms; + -o-transition: opacity 100ms; + -ms-transition: opacity 100ms; + -webkit-transition: opacity 100ms; +} +.mask.transparent{ + opacity: 0; +} + diff --git a/apps/files/index.php b/apps/files/index.php index 4443bf5fde0..ec824f895b6 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -41,62 +41,25 @@ if (!\OC\Files\Filesystem::is_dir($dir . '/')) { 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']); - } -} - $files = array(); $user = OC_User::getUser(); if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache - $content = array(); $needUpgrade = true; $freeSpace = 0; } else { - $content = \OC\Files\Filesystem::getDirectoryContent($dir); + $files = \OCA\files\lib\Helper::getFiles($dir); $freeSpace = \OC\Files\Filesystem::free_space($dir); $needUpgrade = false; } -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'] = \OCP\Preview::isMimeSupported($i['mimetype']); - $i['icon'] = \OCA\files\lib\Helper::determineIcon($i); - $files[] = $i; -} - -usort($files, "fileCmp"); // Make breadcrumb -$breadcrumb = array(); -$pathtohere = ''; -foreach (explode('/', $dir) as $i) { - if ($i != '') { - $pathtohere .= '/' . $i; - $breadcrumb[] = array('dir' => $pathtohere, 'name' => $i); - } -} +$breadcrumb = \OCA\files\lib\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('disableSharing', false); $list->assign('isPublic', false); $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); $breadcrumbNav->assign('breadcrumb', $breadcrumb); @@ -154,5 +117,6 @@ if ($needUpgrade) { $tmpl->assign('isPublic', false); $tmpl->assign('publicUploadEnabled', $publicUploadEnabled); $tmpl->assign("encryptedFiles", \OCP\Util::encryptedFiles()); + $tmpl->assign('disableSharing', false); $tmpl->printPage(); } diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index 097fe521aa6..330fe86f6b3 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -196,13 +196,12 @@ FileActions.register('all', 'Rename', OC.PERMISSION_UPDATE, function () { FileList.rename(filename); }); - FileActions.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename) { - var dir = $('#dir').val(); + var dir = $('#dir').val() || '/'; if (dir !== '/') { dir = dir + '/'; } - window.location = OC.linkTo('files', 'index.php') + '?dir=' + encodeURIComponent(dir + filename); + FileList.changeDirectory(dir + filename); }); FileActions.setDefault('dir', 'Open'); diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 29be5e0d362..c205ae32aa9 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -1,7 +1,25 @@ var FileList={ 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'))); + }); + }, update:function(fileListHtml) { - $('#fileList').empty().html(fileListHtml); + var $fileList = $('#fileList'); + $fileList.empty().html(fileListHtml); + $('#emptycontent').toggleClass('hidden', $fileList.find('tr').length > 0); + $fileList.find('tr').each(function () { + FileActions.display($(this).children('td.filename')); + }); + $fileList.trigger(jQuery.Event("fileActionsReady")); + FileList.postProcessList(); + // "Files" might not be loaded in extending apps + if (window.Files){ + Files.setupDragAndDrop(); + } + $fileList.trigger(jQuery.Event("updated")); }, createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions){ var td, simpleSize, basename, extension; @@ -134,20 +152,83 @@ var FileList={ FileActions.display(tr.find('td.filename')); return tr; }, - refresh:function(data) { - var result = jQuery.parseJSON(data.responseText); + /** + * @brief Changes the current directory and reload the file list. + * @param targetDir target directory (non URL encoded) + * @param changeUrl false if the URL must not be changed (defaults to true) + */ + changeDirectory: function(targetDir, changeUrl){ + var $dir = $('#dir'), + url, + currentDir = $dir.val() || '/'; + targetDir = targetDir || '/'; + if (currentDir === targetDir){ + return; + } + FileList.setCurrentDir(targetDir, changeUrl); + FileList.reload(); + }, + setCurrentDir: function(targetDir, changeUrl){ + $('#dir').val(targetDir); + // Note: IE8 handling ignored for now + if (window.history.pushState && changeUrl !== false){ + url = OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(targetDir).replace(/%2F/g, '/'), + window.history.pushState({dir: targetDir}, '', url); + } + }, + /** + * @brief Reloads the file list using ajax call + */ + reload: function(){ + FileList.showMask(); + if (FileList._reloadCall){ + FileList._reloadCall.abort(); + } + FileList._reloadCall = $.ajax({ + url: OC.filePath('files','ajax','list.php'), + data: { + dir : $('#dir').val(), + breadcrumb: true + }, + error: function(result){ + FileList.reloadCallback(result); + }, + success: function(result) { + FileList.reloadCallback(result); + } + }); + }, + reloadCallback: function(result){ + var $controls = $('#controls'); + + delete FileList._reloadCall; + FileList.hideMask(); + + if (!result || result.status === 'error') { + OC.Notification.show(result.data.message); + return; + } + + if (result.status === 404){ + // go back home + FileList.changeDirectory('/'); + return; + } + if(typeof(result.data.breadcrumb) != 'undefined'){ - updateBreadcrumb(result.data.breadcrumb); + $controls.find('.crumb').remove(); + $controls.prepend(result.data.breadcrumb); + // TODO: might need refactor breadcrumb code into a new file + //resizeBreadcrumbs(true); } FileList.update(result.data.files); - resetFileActionPanel(); }, remove:function(name){ $('tr').filterAttr('data-file',name).find('td.filename').draggable('destroy'); $('tr').filterAttr('data-file',name).remove(); FileList.updateFileSummary(); if($('tr[data-file]').length==0){ - $('#emptycontent').show(); + $('#emptycontent').removeClass('hidden'); } }, insertElement:function(name,type,element){ @@ -177,7 +258,7 @@ var FileList={ }else{ $('#fileList').append(element); } - $('#emptycontent').hide(); + $('#emptycontent').addClass('hidden'); FileList.updateFileSummary(); }, loadingDone:function(name, id){ @@ -508,6 +589,30 @@ var FileList={ $connector.show(); } } + }, + showMask: function(){ + // in case one was shown before + var $mask = $('#content .mask'); + if ($mask.length){ + return; + } + + $mask = $('
'); + + $mask.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); + $('#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); + }, + hideMask: function(){ + var $mask = $('#content .mask').remove(); + if (FileList._maskTimeout){ + window.clearTimeout(FileList._maskTimeout); + } } }; @@ -629,8 +734,8 @@ $(document).ready(function(){ } // update folder size - var size = parseInt(data.context.data('size')); - size += parseInt(file.size) ; + var size = parseInt(data.context.data('size')); + size += parseInt(file.size); data.context.attr('data-size', size); data.context.find('td.filesize').text(humanFileSize(size)); @@ -710,5 +815,19 @@ $(document).ready(function(){ $(window).trigger('beforeunload'); }); + window.onpopstate = function(e){ + var targetDir; + if (e.state && e.state.dir){ + targetDir = e.state.dir; + } + else{ + // read from URL + targetDir = (OC.parseQueryString(location.search) || {dir: '/'}).dir || '/'; + } + if (targetDir){ + FileList.changeDirectory(targetDir, false); + } + } + FileList.createFileSummary(); }); diff --git a/apps/files/js/files.js b/apps/files/js/files.js index d729077ea72..ce72c7bcb5a 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -94,29 +94,34 @@ Files={ OC.Notification.show(t('files_encryption', 'Encryption was disabled but your files are still encrypted. Please go to your personal settings to decrypt your files.')); return; } + }, + + setupDragAndDrop: function(){ + var $fileList = $('#fileList'); + + //drag/drop of files + $fileList.find('tr td.filename').each(function(i,e){ + if ($(e).parent().data('permissions') & OC.PERMISSION_DELETE) { + $(e).draggable(dragOptions); + } + }); + + $fileList.find('tr[data-type="dir"] td.filename').each(function(i,e){ + if ($(e).parent().data('permissions') & OC.PERMISSION_CREATE){ + $(e).droppable(folderDropOptions); + } + }); } }; $(document).ready(function() { Files.displayEncryptionWarning(); Files.bindKeyboardShortcuts(document, jQuery); - $('#fileList tr').each(function(){ - //little hack to set unescape filenames in attribute - $(this).attr('data-file',decodeURIComponent($(this).attr('data-file'))); - }); + + FileList.postProcessList(); + Files.setupDragAndDrop(); $('#file_action_panel').attr('activeAction', false); - //drag/drop of files - $('#fileList tr td.filename').each(function(i,e){ - if ($(e).parent().data('permissions') & OC.PERMISSION_DELETE) { - $(e).draggable(dragOptions); - } - }); - $('#fileList tr[data-type="dir"] td.filename').each(function(i,e){ - if ($(e).parent().data('permissions') & OC.PERMISSION_CREATE){ - $(e).droppable(folderDropOptions); - } - }); $('div.crumb:not(.last)').droppable(crumbDropOptions); $('ul#apps>li:first-child').data('dir',''); if($('div.crumb').length){ @@ -335,6 +340,9 @@ $(document).ready(function() { resizeBreadcrumbs(true); + // event handlers for breadcrumb items + $('#controls').delegate('.crumb a', 'click', onClickBreadcrumb); + // display storage warnings setTimeout ( "Files.displayStorageWarnings()", 100 ); OC.Notification.setDefault(Files.displayStorageWarnings); @@ -415,10 +423,6 @@ function boolOperationFinished(data, callback) { } } -function updateBreadcrumb(breadcrumbHtml) { - $('p.nav').empty().html(breadcrumbHtml); -} - var createDragShadow = function(event){ //select dragged file var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked'); @@ -681,3 +685,9 @@ function checkTrashStatus() { } }); } + +function onClickBreadcrumb(e){ + var $el = $(e.target).closest('.crumb'); + e.preventDefault(); + FileList.changeDirectory(decodeURIComponent($el.data('dir'))); +} diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index 9170c6e3fc0..282f0678a9a 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -45,5 +45,70 @@ class Helper return \OC_Helper::mimetypeIcon($file['mimetype']); } + /** + * Comparator function to sort files alphabetically and have + * the directories appear first + * @param array $a file + * @param array $b file + * @return -1 if $a must come before $b, 1 otherwise + */ + public static 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']); + } + } + /** + * 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 + */ + public static function getFiles($dir) { + $content = \OC\Files\Filesystem::getDirectoryContent($dir); + $files = 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'] = \OCP\Preview::isMimeSupported($i['mimetype']); + $i['icon'] = \OCA\files\lib\Helper::determineIcon($i); + $files[] = $i; + } + + usort($files, array('\OCA\files\lib\Helper', 'fileCmp')); + + 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 + */ + 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; + } } diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 29cb457cd5a..85e21380c6d 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -2,7 +2,7 @@
-
+
t('New'));?>
    @@ -55,9 +55,9 @@
- -
t('Nothing in here. Upload something!'))?>
- +
0):?>class="hidden">t('Nothing in here. Upload something!'))?>
+ + @@ -82,7 +82,7 @@
t( 'Modified' )); ?> - + t('Unshare'))?> diff --git a/apps/files/templates/part.list.php b/apps/files/templates/part.list.php index 9e1750faddf..1e4d4d11c98 100644 --- a/apps/files/templates/part.list.php +++ b/apps/files/templates/part.list.php @@ -1,4 +1,6 @@ - + assign('mimetype', \OC\Files\Filesystem::getMimeType($path)); $tmpl->assign('fileTarget', basename($linkItem['file_target'])); $tmpl->assign('dirToken', $linkItem['token']); + $tmpl->assign('disableSharing', true); $allowPublicUploadEnabled = (bool) ($linkItem['permissions'] & OCP\PERMISSION_CREATE); if (\OCP\App::isEnabled('files_encryption')) { $allowPublicUploadEnabled = false; @@ -206,7 +207,6 @@ if (isset($path)) { } $list = new OCP\Template('files', 'part.list', ''); $list->assign('files', $files); - $list->assign('disableSharing', true); $list->assign('baseURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&path='); $list->assign('downloadURL', OCP\Util::linkToPublic('files') . $urlLinkIdentifiers . '&download&path='); diff --git a/apps/files_trashbin/ajax/list.php b/apps/files_trashbin/ajax/list.php new file mode 100644 index 00000000000..e72e67b01d7 --- /dev/null +++ b/apps/files_trashbin/ajax/list.php @@ -0,0 +1,51 @@ +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 +$files = \OCA\files_trashbin\lib\Helper::getTrashFiles($dir); + +if ($files === null){ + header("HTTP/1.0 404 Not Found"); + 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(); + +OCP\JSON::success(array('data' => $data)); + diff --git a/apps/files_trashbin/index.php b/apps/files_trashbin/index.php index b7d0ef012f4..c28a88d541a 100644 --- a/apps/files_trashbin/index.php +++ b/apps/files_trashbin/index.php @@ -10,92 +10,27 @@ OCP\Util::addScript('files_trashbin', 'disableDefaultActions'); OCP\Util::addScript('files', 'fileactions'); $tmpl = new OCP\Template('files_trashbin', 'index', 'user'); -$user = \OCP\User::getUser(); -$view = new OC_Filesystemview('/'.$user.'/files_trashbin/files'); - OCP\Util::addStyle('files', 'files'); OCP\Util::addScript('files', 'filelist'); +// filelist overrides +OCP\Util::addScript('files_trashbin', 'filelist'); $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : ''; -$result = array(); -if ($dir) { - $dirlisting = true; - $dirContent = $view->opendir($dir); - $i = 0; - if(is_resource($dirContent)) { - while(($entryName = readdir($dirContent)) !== false) { - if (!\OC\Files\Filesystem::isIgnoredDir($entryName)) { - $pos = strpos($dir.'/', '/', 1); - $tmp = substr($dir, 0, $pos); - $pos = strrpos($tmp, '.d'); - $timestamp = substr($tmp, $pos+2); - $result[] = array( - 'id' => $entryName, - 'timestamp' => $timestamp, - 'mime' => $view->getMimeType($dir.'/'.$entryName), - 'type' => $view->is_dir($dir.'/'.$entryName) ? 'dir' : 'file', - 'location' => $dir, - ); - } - } - closedir($dirContent); - } -} else { - $dirlisting = false; - $query = \OC_DB::prepare('SELECT `id`,`location`,`timestamp`,`type`,`mime` FROM `*PREFIX*files_trash` WHERE `user` = ?'); - $result = $query->execute(array($user))->fetchAll(); +$files = \OCA\files_trashbin\lib\Helper::getTrashFiles($dir); + +// Redirect if directory does not exist +if ($files === null){ + header('Location: ' . OCP\Util::linkTo('files_trashbin', 'index.php')); + exit(); } -$files = array(); -foreach ($result as $r) { - $i = array(); - $i['name'] = $r['id']; - $i['date'] = OCP\Util::formatDate($r['timestamp']); - $i['timestamp'] = $r['timestamp']; - $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; - $i['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($r['mime']); - $i['icon'] = \OCA\files\lib\Helper::determineIcon($i); - $files[] = $i; +$dirlisting = false; +if ($dir && $dir !== '/') { + $dirlisting = true; } -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']); - } -} - -usort($files, "fileCmp"); - -// 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); - } -} +$breadcrumb = \OCA\files_trashbin\lib\Helper::makeBreadcrumb($dir); $breadcrumbNav = new OCP\Template('files_trashbin', 'part.breadcrumb', ''); $breadcrumbNav->assign('breadcrumb', $breadcrumb); @@ -108,7 +43,6 @@ $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('disableSharing', true); $list->assign('dirlisting', $dirlisting); $list->assign('disableDownloadActions', true); @@ -116,6 +50,7 @@ $tmpl->assign('dirlisting', $dirlisting); $tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage()); $tmpl->assign('fileList', $list->fetchPage()); $tmpl->assign('files', $files); -$tmpl->assign('dir', \OC\Files\Filesystem::normalizePath($view->getAbsolutePath())); +$tmpl->assign('dir', $dir); +$tmpl->assign('disableSharing', true); $tmpl->printPage(); diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js new file mode 100644 index 00000000000..ff3a846d860 --- /dev/null +++ b/apps/files_trashbin/js/filelist.js @@ -0,0 +1,29 @@ +// 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); + } + }); +} + +FileList.setCurrentDir = function(targetDir, changeUrl){ + $('#dir').val(targetDir); + // Note: IE8 handling ignored for now + if (window.history.pushState && changeUrl !== false){ + url = OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(targetDir).replace(/%2F/g, '/'), + window.history.pushState({dir: targetDir}, '', url); + } +} diff --git a/apps/files_trashbin/js/trash.js b/apps/files_trashbin/js/trash.js index 40c0bdb3829..d73eadb6011 100644 --- a/apps/files_trashbin/js/trash.js +++ b/apps/files_trashbin/js/trash.js @@ -171,9 +171,15 @@ $(document).ready(function() { action(filename); } } + + // event handlers for breadcrumb items + $('#controls').delegate('.crumb:not(.home) a', 'click', onClickBreadcrumb); }); - FileActions.actions.dir = {}; + FileActions.actions.dir = { + // only keep 'Open' action for navigation + 'Open': FileActions.actions.dir.Open + }; }); function processSelection(){ @@ -246,3 +252,9 @@ function disableActions() { $(".action").css("display", "none"); $(":input:checkbox").css("display", "none"); } +function onClickBreadcrumb(e){ + var $el = $(e.target).closest('.crumb'); + e.preventDefault(); + FileList.changeDirectory(decodeURIComponent($el.data('dir'))); +} + diff --git a/apps/files_trashbin/lib/helper.php b/apps/files_trashbin/lib/helper.php new file mode 100644 index 00000000000..098fc0b54b7 --- /dev/null +++ b/apps/files_trashbin/lib/helper.php @@ -0,0 +1,97 @@ +opendir($dir); + if ($dirContent === false){ + return null; + } + if(is_resource($dirContent)){ + while(($entryName = readdir($dirContent)) !== false) { + if (!\OC\Files\Filesystem::isIgnoredDir($entryName)) { + $pos = strpos($dir.'/', '/', 1); + $tmp = substr($dir, 0, $pos); + $pos = strrpos($tmp, '.d'); + $timestamp = substr($tmp, $pos+2); + $result[] = array( + 'id' => $entryName, + 'timestamp' => $timestamp, + 'mime' => $view->getMimeType($dir.'/'.$entryName), + 'type' => $view->is_dir($dir.'/'.$entryName) ? 'dir' : 'file', + 'location' => $dir, + ); + } + } + closedir($dirContent); + } + } else { + $query = \OC_DB::prepare('SELECT `id`,`location`,`timestamp`,`type`,`mime` FROM `*PREFIX*files_trash` WHERE `user` = ?'); + $result = $query->execute(array($user))->fetchAll(); + } + + $files = array(); + foreach ($result as $r) { + $i = array(); + $i['name'] = $r['id']; + $i['date'] = \OCP\Util::formatDate($r['timestamp']); + $i['timestamp'] = $r['timestamp']; + $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; + $i['isPreviewAvailable'] = \OCP\Preview::isMimeSupported($r['mime']); + $i['icon'] = \OCA\files\lib\Helper::determineIcon($i); + $files[] = $i; + } + + usort($files, array('\OCA\files\lib\Helper', 'fileCmp')); + + 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 + */ + 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); + } + } + return $breadcrumb; + } +} diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index 88c32b1f3eb..daae7753aeb 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -9,6 +9,9 @@
t('Nothing in here. Your trash bin is empty!'))?>
+ + + diff --git a/apps/files_trashbin/templates/part.breadcrumb.php b/apps/files_trashbin/templates/part.breadcrumb.php index 8ecab58e5c8..4acc298adbe 100644 --- a/apps/files_trashbin/templates/part.breadcrumb.php +++ b/apps/files_trashbin/templates/part.breadcrumb.php @@ -1,11 +1,11 @@ -
+
'> + data-dir='/'> t("Deleted Files")); ?>
diff --git a/apps/files_trashbin/templates/part.list.php b/apps/files_trashbin/templates/part.list.php index f7cc6b01bbb..78709d986ae 100644 --- a/apps/files_trashbin/templates/part.list.php +++ b/apps/files_trashbin/templates/part.list.php @@ -1,4 +1,3 @@ - ' id="" - data-file="" + data-file="" data-timestamp='' data-dirlisting=1 diff --git a/core/js/js.js b/core/js/js.js index 1999ff73d23..c09f80369f9 100644 --- a/core/js/js.js +++ b/core/js/js.js @@ -321,6 +321,38 @@ var OC={ var date = new Date(1000*mtime); return date.getDate()+'.'+(date.getMonth()+1)+'.'+date.getFullYear()+', '+date.getHours()+':'+date.getMinutes(); }, + /** + * Parses a URL query string into a JS map + * @param queryString query string in the format param1=1234¶m2=abcde¶m3=xyz + * @return map containing key/values matching the URL parameters + */ + parseQueryString:function(queryString){ + var parts, + components, + result = {}, + key, + value; + if (!queryString){ + return null; + } + if (queryString[0] === '?'){ + queryString = queryString.substr(1); + } + parts = queryString.split('&'); + for (var i = 0; i < parts.length; i++){ + components = parts[i].split('='); + if (!components.length){ + continue; + } + key = decodeURIComponent(components[0]); + if (!key){ + continue; + } + value = components[1]; + result[key] = value && decodeURIComponent(value); + } + return result; + }, /** * Opens a popup with the setting for an app. * @param appid String. The ID of the app e.g. 'calendar', 'contacts' or 'files'. From e6f21927d60ee1061652f8c34247afa94933c326 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 27 Aug 2013 10:29:28 +0200 Subject: [PATCH 02/12] fixing no-repeat for IE8 --- apps/files/js/filelist.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index c205ae32aa9..278b2c4cbcb 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -600,6 +600,7 @@ var FileList={ $mask = $('
'); $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 From ef955bae566be054276ec5b2dd96fdf1c23bd1c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 27 Aug 2013 11:18:59 +0200 Subject: [PATCH 03/12] calling replaceSVG() to display breadcrumb images correctly on IE8 --- apps/files/js/filelist.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 278b2c4cbcb..21f713b4a80 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -220,7 +220,13 @@ var FileList={ $controls.prepend(result.data.breadcrumb); // TODO: might need refactor breadcrumb code into a new file //resizeBreadcrumbs(true); + + // in case svg is not supported by the browser we need to execute the fallback mechanism + if(!SVGSupport()) { + replaceSVG(); + } } + FileList.update(result.data.files); }, remove:function(name){ From 4e751cbb473b416f693473ae69e7c55e013e854b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Tue, 27 Aug 2013 13:13:00 +0200 Subject: [PATCH 04/12] fixing breadcrumbs on ajax loading of files --- apps/files/js/filelist.js | 6 +- apps/files/js/files.js | 133 ++++++++++++++++++--------------- apps/files/templates/index.php | 4 +- 3 files changed, 78 insertions(+), 65 deletions(-) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 21f713b4a80..b3955b3d22e 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -218,8 +218,10 @@ var FileList={ if(typeof(result.data.breadcrumb) != 'undefined'){ $controls.find('.crumb').remove(); $controls.prepend(result.data.breadcrumb); - // TODO: might need refactor breadcrumb code into a new file - //resizeBreadcrumbs(true); + + 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()) { diff --git a/apps/files/js/files.js b/apps/files/js/files.js index ce72c7bcb5a..1ea2f5fbcc2 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -111,6 +111,72 @@ Files={ $(e).droppable(folderDropOptions); } }); + }, + + lastWidth: 0, + + initBreadCrumbs: function () { + Files.lastWidth = 0; + Files.breadcrumbs = []; + + // initialize with some extra space + Files.breadcrumbsWidth = 64; + if ( document.getElementById("navigation") ) { + Files.breadcrumbsWidth += $('#navigation').get(0).offsetWidth; + } + 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; + }); + }, + + resizeBreadcrumbs: function (width, firstRun) { + if (width != Files.lastWidth) { + if ((width < Files.lastWidth || firstRun) && width < Files.breadcrumbsWidth) { + if (Files.hiddenBreadcrumbs == 0) { + Files.breadcrumbsWidth -= $(Files.breadcrumbs[1]).get(0).offsetWidth; + $(Files.breadcrumbs[1]).find('a').hide(); + $(Files.breadcrumbs[1]).append('...'); + Files.breadcrumbsWidth += $(Files.breadcrumbs[1]).get(0).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; + } } }; $(document).ready(function() { @@ -273,72 +339,15 @@ $(document).ready(function() { //do a background scan if needed scanFiles(); - var lastWidth = 0; - var breadcrumbs = []; - var breadcrumbsWidth = 0; - if ( document.getElementById("navigation") ) { - breadcrumbsWidth = $('#navigation').get(0).offsetWidth; - } - var hiddenBreadcrumbs = 0; - - $.each($('.crumb'), function(index, breadcrumb) { - breadcrumbs[index] = breadcrumb; - breadcrumbsWidth += $(breadcrumb).get(0).offsetWidth; - }); - - - $.each($('#controls .actions>div'), function(index, action) { - breadcrumbsWidth += $(action).get(0).offsetWidth; - }); - - function resizeBreadcrumbs(firstRun) { - var width = $(this).width(); - if (width != lastWidth) { - if ((width < lastWidth || firstRun) && width < breadcrumbsWidth) { - if (hiddenBreadcrumbs == 0) { - breadcrumbsWidth -= $(breadcrumbs[1]).get(0).offsetWidth; - $(breadcrumbs[1]).find('a').hide(); - $(breadcrumbs[1]).append('...'); - breadcrumbsWidth += $(breadcrumbs[1]).get(0).offsetWidth; - hiddenBreadcrumbs = 2; - } - var i = hiddenBreadcrumbs; - while (width < breadcrumbsWidth && i > 1 && i < breadcrumbs.length - 1) { - breadcrumbsWidth -= $(breadcrumbs[i]).get(0).offsetWidth; - $(breadcrumbs[i]).hide(); - hiddenBreadcrumbs = i; - i++ - } - } else if (width > lastWidth && hiddenBreadcrumbs > 0) { - var i = hiddenBreadcrumbs; - while (width > breadcrumbsWidth && i > 0) { - if (hiddenBreadcrumbs == 1) { - breadcrumbsWidth -= $(breadcrumbs[1]).get(0).offsetWidth; - $(breadcrumbs[1]).find('span').remove(); - $(breadcrumbs[1]).find('a').show(); - breadcrumbsWidth += $(breadcrumbs[1]).get(0).offsetWidth; - } else { - $(breadcrumbs[i]).show(); - breadcrumbsWidth += $(breadcrumbs[i]).get(0).offsetWidth; - if (breadcrumbsWidth > width) { - breadcrumbsWidth -= $(breadcrumbs[i]).get(0).offsetWidth; - $(breadcrumbs[i]).hide(); - break; - } - } - i--; - hiddenBreadcrumbs = i; - } - } - lastWidth = width; - } - } + Files.initBreadCrumbs(); $(window).resize(function() { - resizeBreadcrumbs(false); + var width = $(this).width(); + Files.resizeBreadcrumbs(width, false); }); - resizeBreadcrumbs(true); + var width = $(this).width(); + Files.resizeBreadcrumbs(width, true); // event handlers for breadcrumb items $('#controls').delegate('.crumb a', 'click', onClickBreadcrumb); diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 85e21380c6d..9ca115f7711 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -38,7 +38,9 @@
- > +
From 4ab5e58e0224d7668e2a6fc4f25bc53dc7d97a03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thomas=20M=C3=BCller?= Date: Thu, 29 Aug 2013 01:17:04 +0200 Subject: [PATCH 05/12] update file summary on ajax file list load --- apps/files/js/filelist.js | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index b3955b3d22e..638864d9eca 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -19,6 +19,7 @@ var FileList={ if (window.Files){ Files.setupDragAndDrop(); } + FileList.updateFileSummary(); $fileList.trigger(jQuery.Event("updated")); }, createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions){ From 4549cf519e838a2dd2828453c4157231bccd3287 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 29 Aug 2013 20:59:45 +0200 Subject: [PATCH 06/12] Added missing "files" JS to files_trashbin module The recent refactoring for the breadcrumb resizing relies on the "Files" object which is in the "files" Javascript file. This fix includes it here as well. --- apps/files_trashbin/index.php | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/files_trashbin/index.php b/apps/files_trashbin/index.php index c28a88d541a..c9468b60bd4 100644 --- a/apps/files_trashbin/index.php +++ b/apps/files_trashbin/index.php @@ -14,6 +14,7 @@ OCP\Util::addStyle('files', 'files'); OCP\Util::addScript('files', 'filelist'); // filelist overrides OCP\Util::addScript('files_trashbin', 'filelist'); +OCP\Util::addscript('files', 'files'); $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : ''; From 364e7991a42c92affb9085082ff79f6b653de6dd Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 29 Aug 2013 23:45:02 +0200 Subject: [PATCH 07/12] Fixed ajax support to also update the current dir permissions --- apps/files/ajax/list.php | 4 ++++ apps/files/index.php | 14 +------------- apps/files/js/filelist.js | 16 ++++++++++++++-- apps/files/lib/helper.php | 22 ++++++++++++++++++++++ apps/files/templates/index.php | 10 ++++------ 5 files changed, 45 insertions(+), 21 deletions(-) diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index 035ffc0e393..f1b713b5534 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -20,6 +20,8 @@ $doBreadcrumb = isset($_GET['breadcrumb']); $data = array(); $baseUrl = OCP\Util::linkTo('files', 'index.php') . '?dir='; +$permissions = \OCA\files\lib\Helper::getDirPermissions($dir); + // Make breadcrumb if($doBreadcrumb) { $breadcrumb = \OCA\files\lib\Helper::makeBreadcrumb($dir); @@ -38,6 +40,8 @@ $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['permissions'] = $permissions; OCP\JSON::success(array('data' => $data)); diff --git a/apps/files/index.php b/apps/files/index.php index ec824f895b6..4b930f89024 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -65,19 +65,7 @@ $breadcrumbNav = new OCP\Template('files', 'part.breadcrumb', ''); $breadcrumbNav->assign('breadcrumb', $breadcrumb); $breadcrumbNav->assign('baseURL', OCP\Util::linkTo('files', 'index.php') . '?dir='); -$permissions = OCP\PERMISSION_READ; -if (\OC\Files\Filesystem::isCreatable($dir . '/')) { - $permissions |= OCP\PERMISSION_CREATE; -} -if (\OC\Files\Filesystem::isUpdatable($dir . '/')) { - $permissions |= OCP\PERMISSION_UPDATE; -} -if (\OC\Files\Filesystem::isDeletable($dir . '/')) { - $permissions |= OCP\PERMISSION_DELETE; -} -if (\OC\Files\Filesystem::isSharable($dir . '/')) { - $permissions |= OCP\PERMISSION_SHARE; -} +$permissions = \OCA\files\lib\Helper::getDirPermissions($dir); if ($needUpgrade) { OCP\Util::addscript('files', 'upgrade'); diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 638864d9eca..07605a7d891 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -7,9 +7,11 @@ var FileList={ }); }, update:function(fileListHtml) { - var $fileList = $('#fileList'); + var $fileList = $('#fileList'), + permissions = $('#permissions').val(), + isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; $fileList.empty().html(fileListHtml); - $('#emptycontent').toggleClass('hidden', $fileList.find('tr').length > 0); + $('#emptycontent').toggleClass('hidden', !isCreatable || $fileList.find('tr').length > 0); $fileList.find('tr').each(function () { FileActions.display($(this).children('td.filename')); }); @@ -216,6 +218,10 @@ var FileList={ return; } + if (result.data.permissions){ + FileList.setDirectoryPermissions(result.data.permissions); + } + if(typeof(result.data.breadcrumb) != 'undefined'){ $controls.find('.crumb').remove(); $controls.prepend(result.data.breadcrumb); @@ -232,6 +238,12 @@ var FileList={ FileList.update(result.data.files); }, + setDirectoryPermissions: function(permissions){ + var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; + $('#permissions').val(permissions); + $('.creatable').toggleClass('hidden', !isCreatable); + $('.notCreatable').toggleClass('hidden', isCreatable); + }, remove:function(name){ $('tr').filterAttr('data-file',name).find('td.filename').draggable('destroy'); $('tr').filterAttr('data-file',name).remove(); diff --git a/apps/files/lib/helper.php b/apps/files/lib/helper.php index 282f0678a9a..3c13b8ea6e2 100644 --- a/apps/files/lib/helper.php +++ b/apps/files/lib/helper.php @@ -111,4 +111,26 @@ class Helper } return $breadcrumb; } + + /** + * Returns the numeric permissions for the given directory. + * @param string $dir directory without trailing slash + * @return numeric permissions + */ + public static function getDirPermissions($dir){ + $permissions = \OCP\PERMISSION_READ; + if (\OC\Files\Filesystem::isCreatable($dir . '/')) { + $permissions |= \OCP\PERMISSION_CREATE; + } + if (\OC\Files\Filesystem::isUpdatable($dir . '/')) { + $permissions |= \OCP\PERMISSION_UPDATE; + } + if (\OC\Files\Filesystem::isDeletable($dir . '/')) { + $permissions |= \OCP\PERMISSION_DELETE; + } + if (\OC\Files\Filesystem::isSharable($dir . '/')) { + $permissions |= \OCP\PERMISSION_SHARE; + } + return $permissions; + } } diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 9ca115f7711..0105f4370e5 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -1,8 +1,7 @@
- -
+
t('New'));?>
    @@ -50,10 +49,9 @@
- -
- - +
+
+
From 3cf0820d3507349fa2d518c24579d8605db7cd2e Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sun, 1 Sep 2013 14:24:01 +0200 Subject: [PATCH 08/12] Changed breadcrumb event handling to not use delegate Using delegate might break apps that embed themselves in the files container. When an app embeds itself and the user clicks a breadcrumb, it will simply reload the whole browser page. --- apps/files/js/files.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 1ea2f5fbcc2..7aef8ea1d11 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -131,10 +131,12 @@ Files={ 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 .crumb a').on('click', onClickBreadcrumb); }, resizeBreadcrumbs: function (width, firstRun) { @@ -349,9 +351,6 @@ $(document).ready(function() { var width = $(this).width(); Files.resizeBreadcrumbs(width, true); - // event handlers for breadcrumb items - $('#controls').delegate('.crumb a', 'click', onClickBreadcrumb); - // display storage warnings setTimeout ( "Files.displayStorageWarnings()", 100 ); OC.Notification.setDefault(Files.displayStorageWarnings); From 611075bf206555cf011b5fb70e117c93040e9027 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Sun, 1 Sep 2013 14:36:33 +0200 Subject: [PATCH 09/12] Fixed JS error in trashbin app --- apps/files/js/files.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 7aef8ea1d11..c2418cfa751 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -182,6 +182,10 @@ Files={ } }; $(document).ready(function() { + // FIXME: workaround for trashbin app + if (window.trashBinApp){ + return; + } Files.displayEncryptionWarning(); Files.bindKeyboardShortcuts(document, jQuery); From 4d38441e72f3825006ea034b18390bc22a3d9e97 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Wed, 4 Sep 2013 20:50:59 +0200 Subject: [PATCH 10/12] Fixed loading mask/spinner to stay fixed on scroll --- apps/files/css/files.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/files/css/files.css b/apps/files/css/files.css index f506a379477..41d9808c56b 100644 --- a/apps/files/css/files.css +++ b/apps/files/css/files.css @@ -338,7 +338,7 @@ table.dragshadow td.size { } .mask { z-index: 50; - position: absolute; + position: fixed; top: 0; left: 0; right: 0; From 30a2f2f35282a4414269a7650513348b99fb7965 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Thu, 29 Aug 2013 21:56:14 +0200 Subject: [PATCH 11/12] Use hash part of URL for IE8 in files app Before this fix, the URL wasn't updated in IE8 when navigating into folders. This fix makes use of the hash part of URLs to make this work in IE8, since IE8 doesn't support the history API nor changing the URL without redirecting. From now, both the regular query URL "?dir=somedir" and "#?dir=somedir" will work in both IE8 and non-IE8 browsers. In IE8, query based URLs are automatically converted to hash URLs upon page load. The conversion is done on the server side by redirecting the user to the updated URL. When loading a page directly using a hash URL in the form "#?dir=somedir" in IE8, the server doesn't get the hash, so it will not return any results in that case and rely on ajax to load the first page. --- apps/files/index.php | 30 +++++++++++++++- apps/files/js/filelist.js | 58 ++++++++++++++++++++++++++---- apps/files/templates/index.php | 3 +- apps/files_trashbin/js/filelist.js | 9 ++--- 4 files changed, 84 insertions(+), 16 deletions(-) diff --git a/apps/files/index.php b/apps/files/index.php index 4b930f89024..d46d8e32eef 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -41,13 +41,40 @@ if (!\OC\Files\Filesystem::is_dir($dir . '/')) { exit(); } +$isIE8 = false; +preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches); +if (count($matches) > 0 && $matches[1] <= 8){ + $isIE8 = true; +} + +// if IE8 and "?dir=path" was specified, reformat the URL to use a hash like "#?dir=path" +if ($isIE8 && isset($_GET['dir'])){ + if ($dir === ''){ + $dir = '/'; + } + header('Location: ' . OCP\Util::linkTo('files', 'index.php') . '#?dir=' . \OCP\Util::encodePath($dir)); + exit(); +} + +$ajaxLoad = false; $files = array(); $user = OC_User::getUser(); if (\OC\Files\Cache\Upgrade::needUpgrade($user)) { //dont load anything if we need to upgrade the cache $needUpgrade = true; $freeSpace = 0; } else { - $files = \OCA\files\lib\Helper::getFiles($dir); + 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\lib\Helper::getFiles($dir); + } $freeSpace = \OC\Files\Filesystem::free_space($dir); $needUpgrade = false; } @@ -106,5 +133,6 @@ if ($needUpgrade) { $tmpl->assign('publicUploadEnabled', $publicUploadEnabled); $tmpl->assign("encryptedFiles", \OCP\Util::encryptedFiles()); $tmpl->assign('disableSharing', false); + $tmpl->assign('ajaxLoad', $ajaxLoad); $tmpl->printPage(); } diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index 07605a7d891..b50d46c98d3 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -160,23 +160,31 @@ var FileList={ * @param targetDir target directory (non URL encoded) * @param changeUrl false if the URL must not be changed (defaults to true) */ - changeDirectory: function(targetDir, changeUrl){ + changeDirectory: function(targetDir, changeUrl, force){ var $dir = $('#dir'), url, currentDir = $dir.val() || '/'; targetDir = targetDir || '/'; - if (currentDir === targetDir){ + if (!force && currentDir === targetDir){ return; } FileList.setCurrentDir(targetDir, changeUrl); FileList.reload(); }, + linkTo: function(dir){ + return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); + }, setCurrentDir: function(targetDir, changeUrl){ $('#dir').val(targetDir); - // Note: IE8 handling ignored for now - if (window.history.pushState && changeUrl !== false){ - url = OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(targetDir).replace(/%2F/g, '/'), - window.history.pushState({dir: targetDir}, '', url); + if (changeUrl !== false){ + if (window.history.pushState && changeUrl !== false){ + url = FileList.linkTo(targetDir); + window.history.pushState({dir: targetDir}, '', url); + } + // use URL hash for IE8 + else{ + window.location.hash = '?dir='+ encodeURIComponent(targetDir).replace(/%2F/g, '/'); + } } }, /** @@ -837,6 +845,37 @@ $(document).ready(function(){ $(window).trigger('beforeunload'); }); + function parseHashQuery(){ + var hash = window.location.hash, + pos = hash.indexOf('?'), + query; + if (pos >= 0){ + return hash.substr(pos + 1); + } + return ''; + } + + function parseCurrentDirFromUrl(){ + var query = parseHashQuery(), + params, + dir = '/'; + // try and parse from URL hash first + if (query){ + params = OC.parseQueryString(query); + } + // else read from query attributes + if (!params){ + params = OC.parseQueryString(location.search); + } + return (params && params.dir) || '/'; + } + + // 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){ @@ -844,12 +883,17 @@ $(document).ready(function(){ } else{ // read from URL - targetDir = (OC.parseQueryString(location.search) || {dir: '/'}).dir || '/'; + 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); + } + FileList.createFileSummary(); }); diff --git a/apps/files/templates/index.php b/apps/files/templates/index.php index 0105f4370e5..09e351d4ea8 100644 --- a/apps/files/templates/index.php +++ b/apps/files/templates/index.php @@ -55,7 +55,7 @@
-
0):?>class="hidden">t('Nothing in here. Upload something!'))?>
+
0 or !$_['ajaxLoad']):?>class="hidden">t('Nothing in here. Upload something!'))?>
@@ -120,6 +120,7 @@
+ diff --git a/apps/files_trashbin/js/filelist.js b/apps/files_trashbin/js/filelist.js index ff3a846d860..cd5a67ddfe0 100644 --- a/apps/files_trashbin/js/filelist.js +++ b/apps/files_trashbin/js/filelist.js @@ -19,11 +19,6 @@ FileList.reload = function(){ }); } -FileList.setCurrentDir = function(targetDir, changeUrl){ - $('#dir').val(targetDir); - // Note: IE8 handling ignored for now - if (window.history.pushState && changeUrl !== false){ - url = OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(targetDir).replace(/%2F/g, '/'), - window.history.pushState({dir: targetDir}, '', url); - } +FileList.linkTo = function(dir){ + return OC.linkTo('files_trashbin', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); } From ec2f20f72013f5ed6adcf5724006bd5ada462727 Mon Sep 17 00:00:00 2001 From: Vincent Petry Date: Fri, 13 Sep 2013 21:00:15 +0200 Subject: [PATCH 12/12] Fixed files_trashbin to also use hash URL part for IE8 --- apps/files_trashbin/index.php | 26 ++++++++++++++++++++++++- apps/files_trashbin/templates/index.php | 3 ++- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/apps/files_trashbin/index.php b/apps/files_trashbin/index.php index c9468b60bd4..9f17448a757 100644 --- a/apps/files_trashbin/index.php +++ b/apps/files_trashbin/index.php @@ -18,7 +18,30 @@ OCP\Util::addscript('files', 'files'); $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : ''; -$files = \OCA\files_trashbin\lib\Helper::getTrashFiles($dir); +$isIE8 = false; +preg_match('/MSIE (.*?);/', $_SERVER['HTTP_USER_AGENT'], $matches); +if (count($matches) > 0 && $matches[1] <= 8){ + $isIE8 = true; +} + +// if IE8 and "?dir=path" was specified, reformat the URL to use a hash like "#?dir=path" +if ($isIE8 && isset($_GET['dir'])){ + if ($dir === ''){ + $dir = '/'; + } + header('Location: ' . OCP\Util::linkTo('files_trashbin', 'index.php') . '#?dir=' . \OCP\Util::encodePath($dir)); + exit(); +} + +$ajaxLoad = false; + +if (!$isIE8){ + $files = \OCA\files_trashbin\lib\Helper::getTrashFiles($dir); +} +else{ + $files = array(); + $ajaxLoad = true; +} // Redirect if directory does not exist if ($files === null){ @@ -53,5 +76,6 @@ $tmpl->assign('fileList', $list->fetchPage()); $tmpl->assign('files', $files); $tmpl->assign('dir', $dir); $tmpl->assign('disableSharing', true); +$tmpl->assign('ajaxLoad', true); $tmpl->printPage(); diff --git a/apps/files_trashbin/templates/index.php b/apps/files_trashbin/templates/index.php index daae7753aeb..82ba0608834 100644 --- a/apps/files_trashbin/templates/index.php +++ b/apps/files_trashbin/templates/index.php @@ -5,10 +5,11 @@
- +
t('Nothing in here. Your trash bin is empty!'))?>
+