diff options
author | Vincent Petry <pvince81@owncloud.com> | 2013-10-28 20:22:06 +0100 |
---|---|---|
committer | Vincent Petry <pvince81@owncloud.com> | 2014-04-02 15:33:47 +0200 |
commit | 0be9de5df558232e12e2f582af5d08e1f488ba90 (patch) | |
tree | de37dea2e23dd28f631948295979980ec774027f /apps/files/js | |
parent | 268206cec55921d2d0309469ebd5d9533e4f79ee (diff) | |
download | nextcloud-server-0be9de5df558232e12e2f582af5d08e1f488ba90.tar.gz nextcloud-server-0be9de5df558232e12e2f582af5d08e1f488ba90.zip |
Files, trashbin, public apps use ajax/JSON for the file list
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
Diffstat (limited to 'apps/files/js')
-rw-r--r-- | apps/files/js/breadcrumb.js | 242 | ||||
-rw-r--r-- | apps/files/js/file-upload.js | 61 | ||||
-rw-r--r-- | apps/files/js/fileactions.js | 4 | ||||
-rw-r--r-- | apps/files/js/filelist.js | 740 | ||||
-rw-r--r-- | apps/files/js/files.js | 216 |
5 files changed, 709 insertions, 554 deletions
diff --git a/apps/files/js/breadcrumb.js b/apps/files/js/breadcrumb.js new file mode 100644 index 00000000000..21010c7dc11 --- /dev/null +++ b/apps/files/js/breadcrumb.js @@ -0,0 +1,242 @@ +/** +* ownCloud +* +* @author Vincent Petry +* @copyright 2014 Vincent Petry <pvince81@owncloud.com> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE +* License as published by the Free Software Foundation; either +* version 3 of the License, or any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU AFFERO GENERAL PUBLIC LICENSE for more details. +* +* You should have received a copy of the GNU Affero General Public +* License along with this library. If not, see <http://www.gnu.org/licenses/>. +* +*/ + +/* global OC */ +/* global SVGSupport, replaceSVG */ +(function() { + /** + * Creates an breadcrumb element in the given container + */ + var BreadCrumb = function(options){ + this.$el = $('<div class="breadcrumb"></div>'); + options = options || {}; + if (options.onClick) { + this.onClick = options.onClick; + } + if (options.onDrop) { + this.onDrop = options.onDrop; + } + if (options.getCrumbUrl) { + this.getCrumbUrl = options.getCrumbUrl; + } + }; + BreadCrumb.prototype = { + $el: null, + dir: null, + + lastWidth: 0, + hiddenBreadcrumbs: 0, + totalWidth: 0, + breadcrumbs: [], + onClick: null, + onDrop: null, + + /** + * Sets the directory to be displayed as breadcrumb. + * This will re-render the breadcrumb. + * @param dir path to be displayed as breadcrumb + */ + setDirectory: function(dir) { + dir = dir || '/'; + if (dir !== this.dir) { + this.dir = dir; + this.render(); + } + }, + + /** + * Returns the full URL to the given directory + * @param part crumb data as map + * @param index crumb index + * @return full URL + */ + getCrumbUrl: function(part, index) { + return '#'; + }, + + /** + * Renders the breadcrumb elements + */ + render: function() { + var parts = this._makeCrumbs(this.dir || '/'); + var $crumb; + this.$el.empty(); + this.breadcrumbs = []; + + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; + var $image; + var $link = $('<a></a>').attr('href', this.getCrumbUrl(part, i)); + $link.text(part.name); + $crumb = $('<div class="crumb"></div>'); + $crumb.append($link); + $crumb.attr('data-dir', part.dir); + + if (part.img) { + $image = $('<img class="svg"></img>'); + $image.attr('src', part.img); + $link.append($image); + } + this.breadcrumbs.push($crumb); + this.$el.append($crumb); + if (this.onClick) { + $crumb.on('click', this.onClick); + } + } + $crumb.addClass('last'); + + // in case svg is not supported by the browser we need to execute the fallback mechanism + if (!SVGSupport()) { + replaceSVG(); + } + + // setup drag and drop + if (this.onDrop) { + this.$el.find('.crumb:not(.last)').droppable({ + drop: this.onDrop, + tolerance: 'pointer' + }); + } + + this._updateTotalWidth(); + this.resize($(window).width(), true); + }, + + /** + * Makes a breadcrumb structure based on the given path + * @param dir path to split into a breadcrumb structure + * @return array of map {dir: path, name: displayName} + */ + _makeCrumbs: function(dir) { + var crumbs = []; + var pathToHere = ''; + // trim leading and trailing slashes + dir = dir.replace(/^\/+|\/+$/g, ''); + var parts = dir.split('/'); + if (dir === '') { + parts = []; + } + // root part + crumbs.push({ + dir: '/', + name: '', + img: OC.imagePath('core', 'places/home.svg') + }); + for (var i = 0; i < parts.length; i++) { + var part = parts[i]; + pathToHere = pathToHere + '/' + part; + crumbs.push({ + dir: pathToHere, + name: part + }); + } + return crumbs; + }, + + _updateTotalWidth: function () { + var self = this; + + this.lastWidth = 0; + + // initialize with some extra space + this.totalWidth = 64; + // FIXME: this class should not know about global elements + if ( $('#navigation').length ) { + this.totalWidth += $('#navigation').get(0).offsetWidth; + } + this.hiddenBreadcrumbs = 0; + + for (var i = 0; i < this.breadcrumbs.length; i++ ) { + this.totalWidth += $(this.breadcrumbs[i]).get(0).offsetWidth; + } + + $.each($('#controls .actions>div'), function(index, action) { + self.totalWidth += $(action).get(0).offsetWidth; + }); + + }, + + /** + * Show/hide breadcrumbs to fit the given width + */ + resize: function (width, firstRun) { + var i, $crumb; + + if (width === this.lastWidth) { + return; + } + + // window was shrinked since last time or first run ? + if ((width < this.lastWidth || firstRun) && width < this.totalWidth) { + if (this.hiddenBreadcrumbs === 0 && this.breadcrumbs.length > 1) { + // start by hiding the first breadcrumb after home, + // that one will have extra three dots displayed + $crumb = this.breadcrumbs[1]; + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.find('a').addClass('hidden'); + $crumb.append('<span class="ellipsis">...</span>'); + this.totalWidth += $crumb.get(0).offsetWidth; + this.hiddenBreadcrumbs = 2; + } + i = this.hiddenBreadcrumbs; + // hide subsequent breadcrumbs if the space is still not enough + while (width < this.totalWidth && i > 1 && i < this.breadcrumbs.length - 1) { + $crumb = this.breadcrumbs[i]; + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.addClass('hidden'); + this.hiddenBreadcrumbs = i; + i++; + } + // window is bigger than last time + } else if (width > this.lastWidth && this.hiddenBreadcrumbs > 0) { + i = this.hiddenBreadcrumbs; + while (width > this.totalWidth && i > 0) { + if (this.hiddenBreadcrumbs === 1) { + // special handling for last one as it has the three dots + $crumb = this.breadcrumbs[1]; + if ($crumb) { + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.find('.ellipsis').remove(); + $crumb.find('a').removeClass('hidden'); + this.totalWidth += $crumb.get(0).offsetWidth; + } + } else { + $crumb = this.breadcrumbs[i]; + $crumb.removeClass('hidden'); + this.totalWidth += $crumb.get(0).offsetWidth; + if (this.totalWidth > width) { + this.totalWidth -= $crumb.get(0).offsetWidth; + $crumb.addClass('hidden'); + break; + } + } + i--; + this.hiddenBreadcrumbs = i; + } + } + + this.lastWidth = width; + } + }; + + window.BreadCrumb = BreadCrumb; +})(); + diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js index 371c83e742c..e5d1eacbd14 100644 --- a/apps/files/js/file-upload.js +++ b/apps/files/js/file-upload.js @@ -180,7 +180,7 @@ OC.Upload = { }, init: function() { - if ( $('#file_upload_start').exists() && $('#file_upload_start').is(':visible')) { + if ( $('#file_upload_start').exists() ) { var file_upload_param = { dropZone: $('#content'), // restrict dropZone to content div @@ -483,28 +483,6 @@ OC.Upload = { $('#file_upload_start').attr('multiple', 'multiple'); } - //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder - var crumb=$('div.crumb').first(); - while($('div.controls').height() > 40 && crumb.next('div.crumb').length > 0) { - crumb.children('a').text('...'); - crumb = crumb.next('div.crumb'); - } - //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent - var crumb = $('div.crumb').first(); - var next = crumb.next('div.crumb'); - while($('div.controls').height()>40 && next.next('div.crumb').length > 0) { - crumb.remove(); - crumb = next; - next = crumb.next('div.crumb'); - } - //still not enough, start shorting down the current folder name - var crumb=$('div.crumb>a').last(); - while($('div.controls').height() > 40 && crumb.text().length > 6) { - var text=crumb.text(); - text = text.substr(0,text.length-6)+'...'; - crumb.text(text); - } - $(document).click(function(ev) { // do not close when clicking in the dropdown if ($(ev.target).closest('#new').length){ @@ -617,21 +595,7 @@ OC.Upload = { {dir:$('#dir').val(), filename:name}, function(result) { if (result.status === 'success') { - var date = new Date(); - // TODO: ideally addFile should be able to receive - // all attributes and set them automatically, - // and also auto-load the preview - var tr = FileList.addFile(name, 0, date, false, hidden); - tr.attr('data-size', result.data.size); - tr.attr('data-mime', result.data.mime); - tr.attr('data-id', result.data.id); - tr.attr('data-etag', result.data.etag); - tr.find('.filesize').text(humanFileSize(result.data.size)); - var path = getPathForPreview(name); - Files.lazyLoadPreview(path, result.data.mime, function(previewpath) { - tr.find('td.filename').attr('style','background-image:url('+previewpath+')'); - }, null, null, result.data.etag); - FileActions.display(tr.find('td.filename'), true); + FileList.add(result.data, {hidden: hidden, insert: true}); } else { OC.dialogs.alert(result.data.message, t('core', 'Could not create file')); } @@ -644,10 +608,7 @@ OC.Upload = { {dir:$('#dir').val(), foldername:name}, function(result) { if (result.status === 'success') { - var date=new Date(); - FileList.addDir(name, 0, date, hidden); - var tr = FileList.findFileEl(name); - tr.attr('data-id', result.data.id); + FileList.add(result.data, {hidden: hidden, insert: true}); } else { OC.dialogs.alert(result.data.message, t('core', 'Could not create folder')); } @@ -682,20 +643,10 @@ OC.Upload = { } }); eventSource.listen('success',function(data) { - var mime = data.mime; - var size = data.size; - var id = data.id; + var file = data; $('#uploadprogressbar').fadeOut(); - var date = new Date(); - FileList.addFile(localName, size, date, false, hidden); - var tr = FileList.findFileEl(localName); - tr.data('mime', mime).data('id', id); - tr.attr('data-id', id); - var path = $('#dir').val()+'/'+localName; - Files.lazyLoadPreview(path, mime, function(previewpath) { - tr.find('td.filename').attr('style', 'background-image:url('+previewpath+')'); - }, null, null, data.etag); - FileActions.display(tr.find('td.filename'), true); + + FileList.add(file, {hidden: hidden, insert: true}); }); eventSource.listen('error',function(error) { $('#uploadprogressbar').fadeOut(); diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js index 732690f047a..631aebea954 100644 --- a/apps/files/js/fileactions.js +++ b/apps/files/js/fileactions.js @@ -8,7 +8,7 @@ * */ -/* global OC, FileList */ +/* global OC, FileList, Files */ /* global trashBinApp */ var FileActions = { actions: {}, @@ -214,7 +214,7 @@ $(document).ready(function () { FileActions.register(downloadScope, 'Download', OC.PERMISSION_READ, function () { return OC.imagePath('core', 'actions/download'); }, function (filename) { - var url = FileList.getDownloadUrl(filename); + var url = Files.getDownloadUrl(filename); if (url) { OC.redirect(url); } diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js index cda4e823a73..509929d0e55 100644 --- a/apps/files/js/filelist.js +++ b/apps/files/js/filelist.js @@ -8,17 +8,104 @@ * */ -/* global OC, t, n, FileList, FileActions, Files */ -/* global procesSelection, dragOptions, SVGSupport, replaceSVG */ -window.FileList={ +/* global OC, t, n, FileList, FileActions, Files, BreadCrumb */ +/* global procesSelection, dragOptions, SVGSupport */ +window.FileList = { appName: t('files', 'Files'), + isEmpty: true, useUndo:true, - postProcessList: function() { - $('#fileList tr').each(function() { - //little hack to set unescape filenames in attribute - $(this).attr('data-file',decodeURIComponent($(this).attr('data-file'))); + $el: $('#filestable'), + $fileList: $('#fileList'), + breadcrumb: null, + initialized: false, + + /** + * Initialize the file list and its components + */ + initialize: function() { + var self = this; + if (this.initialized) { + return; + } + + // TODO: FileList should not know about global elements + this.$el = $('#filestable'); + this.$fileList = $('#fileList'); + + this.breadcrumb = new BreadCrumb({ + onClick: this._onClickBreadCrumb, + onDrop: this._onDropOnBreadCrumb, + getCrumbUrl: function(part, index) { + return self.linkTo(part.dir); + } + }); + + $('#controls').prepend(this.breadcrumb.$el); + + $(window).resize(function() { + // TODO: debounce this ? + var width = $(this).width(); + FileList.breadcrumb.resize(width, false); + }); + }, + + /** + * Event handler when clicking on a bread crumb + */ + _onClickBreadCrumb: function(e) { + var $el = $(e.target).closest('.crumb'), + $targetDir = $el.data('dir'); + + if ($targetDir !== undefined) { + e.preventDefault(); + FileList.changeDirectory($targetDir); + } + }, + + /** + * Event handler when dropping on a breadcrumb + */ + _onDropOnBreadCrumb: function( event, ui ) { + var target=$(this).data('dir'); + var dir = FileList.getCurrentDirectory(); + while(dir.substr(0,1) === '/') {//remove extra leading /'s + dir=dir.substr(1); + } + dir = '/' + dir; + if (dir.substr(-1,1) !== '/') { + dir = dir + '/'; + } + if (target === dir || target+'/' === dir) { + return; + } + var files = ui.helper.find('tr'); + $(files).each(function(i,row) { + var dir = $(row).data('dir'); + var file = $(row).data('filename'); + //slapdash selector, tracking down our original element that the clone budded off of. + var origin = $('tr[data-id=' + $(row).data('origin') + ']'); + var td = origin.children('td.filename'); + var oldBackgroundImage = td.css('background-image'); + td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); + $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) { + if (result) { + if (result.status === 'success') { + FileList.remove(file); + procesSelection(); + $('#notification').hide(); + } else { + $('#notification').hide(); + $('#notification').text(result.data.message); + $('#notification').fadeIn(); + } + } else { + OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); + } + td.css('background-image', oldBackgroundImage); + }); }); }, + /** * Sets a new page title */ @@ -36,64 +123,133 @@ window.FileList={ }, /** * Returns the tr element for a given file name + * @param fileName file name */ findFileEl: function(fileName){ // use filterAttr to avoid escaping issues - return $('#fileList tr').filterAttr('data-file', fileName); + return this.$fileList.find('tr').filterAttr('data-file', fileName); }, - update:function(fileListHtml) { - var $fileList = $('#fileList'); - $fileList.empty().html(fileListHtml); - FileList.updateEmptyContent(); - $fileList.find('tr').each(function () { - FileActions.display($(this).children('td.filename')); - }); - $fileList.trigger(jQuery.Event("fileActionsReady")); - FileList.postProcessList(); + /** + * Sets the files to be displayed in the list. + * This operation will rerender the list and update the summary. + * @param filesArray array of file data (map) + */ + setFiles:function(filesArray) { + // detach to make adding multiple rows faster + this.$fileList.detach(); + + this.$fileList.empty(); + + this.isEmpty = filesArray.length === 0; + for (var i = 0; i < filesArray.length; i++) { + this.add(filesArray[i], {updateSummary: false}); + } + + this.$el.find('thead').after(this.$fileList); + + this.updateEmptyContent(); + this.$fileList.trigger(jQuery.Event("fileActionsReady")); // "Files" might not be loaded in extending apps if (window.Files) { Files.setupDragAndDrop(); } - FileList.updateFileSummary(); + this.updateFileSummary(); procesSelection(); - $(window).scrollTop(0); - $fileList.trigger(jQuery.Event("updated")); + + this.$fileList.trigger(jQuery.Event("updated")); + }, + /** + * If SVG is not supported, replaces the given images's extension + * from ".svg" to ".png". + * If SVG is supported, return the image path as is. + * @param icon image path + * @return fixed image path + */ + _replaceSVG: function(icon) { + if (!SVGSupport()) { + var i = icon.lastIndexOf('.svg'); + if (i >= 0) { + icon = icon.substr(0, i) + '.png' + icon.substr(i+4); + } + } + return icon; }, - createRow:function(type, name, iconurl, linktarget, size, lastModified, permissions) { - var td, simpleSize, basename, extension; + /** + * Creates a new table row element using the given file data. + * @param fileData map of file attributes + * @param options map of attribute "loading" whether the entry is currently loading + * @return new tr element (not appended to the table) + */ + _createRow: function(fileData, options) { + var td, simpleSize, basename, extension, sizeColor, + icon = FileList._replaceSVG(fileData.icon), + name = fileData.name, + type = fileData.type || 'file', + mtime = parseInt(fileData.mtime, 10) || new Date().getTime(), + mime = fileData.mimetype, + linkUrl; + options = options || {}; + + if (type === 'dir') { + mime = mime || 'httpd/unix-directory'; + } //containing tr var tr = $('<tr></tr>').attr({ + "data-id" : fileData.id, "data-type": type, - "data-size": size, + "data-size": fileData.size, "data-file": name, - "data-permissions": permissions + "data-mime": mime, + "data-mtime": mtime, + "data-etag": fileData.etag, + "data-permissions": fileData.permissions || this.getDirectoryPermissions() }); + + if (type === 'dir') { + // use default folder icon + icon = icon || OC.imagePath('core', 'filetypes/folder'); + } + else { + icon = icon || OC.imagePath('core', 'filetypes/file'); + } + // filename td td = $('<td></td>').attr({ - "class": "filename svg", - "style": 'background-image:url('+iconurl+'); background-size: 32px;' + "class": "filename", + "style": 'background-image:url(' + icon + '); background-size: 32px;' }); - var rand = Math.random().toString(16).slice(2); - td.append('<input id="select-'+rand+'" type="checkbox" /><label for="select-'+rand+'"></label>'); + + // linkUrl + if (type === 'dir') { + linkUrl = FileList.linkTo(FileList.getCurrentDirectory() + '/' + name); + } + else { + linkUrl = Files.getDownloadUrl(name, FileList.getCurrentDirectory()); + } + td.append('<input id="select-' + fileData.id + '" type="checkbox" /><label for="select-' + fileData.id + '"></label>'); var link_elem = $('<a></a>').attr({ "class": "name", - "href": linktarget + "href": linkUrl }); - //split extension from filename for non dirs + + // from here work on the display name + name = fileData.displayName || name; + + // split extension from filename for non dirs if (type !== 'dir' && name.indexOf('.') !== -1) { - basename=name.substr(0,name.lastIndexOf('.')); - extension=name.substr(name.lastIndexOf('.')); + basename = name.substr(0, name.lastIndexOf('.')); + extension = name.substr(name.lastIndexOf('.')); } else { - basename=name; - extension=false; + basename = name; + extension = false; } var name_span=$('<span></span>').addClass('nametext').text(basename); link_elem.append(name_span); if (extension) { name_span.append($('<span></span>').addClass('extension').text(extension)); } - //dirs can show the number of uploaded files + // dirs can show the number of uploaded files if (type === 'dir') { link_elem.append($('<span></span>').attr({ 'class': 'uploadtext', @@ -103,99 +259,123 @@ window.FileList={ td.append(link_elem); tr.append(td); - //size column - if (size !== t('files', 'Pending')) { - simpleSize = humanFileSize(size); + // size column + if (typeof(fileData.size) !== 'undefined' && fileData.size >= 0) { + simpleSize = humanFileSize(parseInt(fileData.size, 10)); + sizeColor = Math.round(160-Math.pow((fileData.size/(1024*1024)),2)); } else { - simpleSize=t('files', 'Pending'); + simpleSize = t('files', 'Pending'); } - var sizeColor = Math.round(160-Math.pow((size/(1024*1024)),2)); - var lastModifiedTime = Math.round(lastModified.getTime() / 1000); + var lastModifiedTime = Math.round(mtime / 1000); td = $('<td></td>').attr({ "class": "filesize", - "style": 'color:rgb('+sizeColor+','+sizeColor+','+sizeColor+')' + "style": 'color:rgb(' + sizeColor + ',' + sizeColor + ',' + sizeColor + ')' }).text(simpleSize); tr.append(td); // date column - var modifiedColor = Math.round((Math.round((new Date()).getTime() / 1000)-lastModifiedTime)/60/60/24*5); + var modifiedColor = Math.round((Math.round((new Date()).getTime() / 1000) - mtime)/60/60/24*5); td = $('<td></td>').attr({ "class": "date" }); td.append($('<span></span>').attr({ "class": "modified", - "title": formatDate(lastModified), + "title": formatDate(mtime), "style": 'color:rgb('+modifiedColor+','+modifiedColor+','+modifiedColor+')' - }).text( relative_modified_date(lastModified.getTime() / 1000) )); + }).text( relative_modified_date(mtime / 1000) )); + tr.find('.filesize').text(simpleSize); tr.append(td); return tr; }, - addFile:function(name, size, lastModified, loading, hidden, param) { - var imgurl; + /** + * Adds an entry to the files table using the data from the given file data + * @param fileData map of file attributes + * @param options map of attributes: + * - "insert" true to insert in a sorted manner, false to append (default) + * - "updateSummary" true to update the summary after adding (default), false otherwise + * @return new tr element (not appended to the table) + */ + add: function(fileData, options) { + options = options || {}; + var type = fileData.type || 'file', + mime = fileData.mimetype, + permissions = parseInt(fileData.permissions, 10) || 0; - if (!param) { - param = {}; + if (type === 'dir') { + mime = mime || 'httpd/unix-directory'; } + var tr = this._createRow( + fileData, + options + ); + var filenameTd = tr.find('td.filename'); - var download_url = null; - if (!param.download_url) { - download_url = OC.generateUrl( - 'apps/files/download{file}', - { file: $('#dir').val()+'/'+name }); - } else { - download_url = param.download_url; + // sorted insert is expensive, so needs to be explicitly + // requested + if (options.insert) { + this.insertElement(fileData.name, type, tr); } + else { + this.$fileList.append(tr); + } + FileList.isEmpty = false; - if (loading) { - imgurl = OC.imagePath('core', 'loading.gif'); - } else { - imgurl = OC.imagePath('core', 'filetypes/file'); - } - var tr = this.createRow( - 'file', - name, - imgurl, - download_url, - size, - lastModified, - $('#permissions').val() - ); + // TODO: move dragging to FileActions ? + // enable drag only for deletable files + if (permissions & OC.PERMISSION_DELETE) { + filenameTd.draggable(dragOptions); + } + // allow dropping on folders + if (fileData.type === 'dir') { + filenameTd.droppable(folderDropOptions); + } - FileList.insertElement(name, 'file', tr); - if (loading) { - tr.data('loading', true); - } else { - tr.find('td.filename').draggable(dragOptions); + if (options.hidden) { + tr.addClass('hidden'); } - if (hidden) { - tr.hide(); + + // display actions + FileActions.display(filenameTd, false); + + if (fileData.isPreviewAvailable) { + // lazy load / newly inserted td ? + if (!fileData.icon) { + Files.lazyLoadPreview(getPathForPreview(fileData.name), mime, function(url) { + filenameTd.css('background-image', 'url(' + url + ')'); + }, null, null, fileData.etag); + } + else { + // set the preview URL directly + var urlSpec = { + file: FileList.getCurrentDirectory() + '/' + fileData.name, + c: fileData.etag + }; + var previewUrl = Files.generatePreviewUrl(urlSpec); + previewUrl = previewUrl.replace('(', '%28').replace(')', '%29'); + filenameTd.css('background-image', 'url(' + previewUrl + ')'); + } } - return tr; - }, - addDir:function(name, size, lastModified, hidden) { - - var tr = this.createRow( - 'dir', - name, - OC.imagePath('core', 'filetypes/folder'), - OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent($('#dir').val()+'/'+name).replace(/%2F/g, '/'), - size, - lastModified, - $('#permissions').val() - ); - FileList.insertElement(name, 'dir', tr); - var td = tr.find('td.filename'); - td.draggable(dragOptions); - td.droppable(folderDropOptions); - if (hidden) { - tr.hide(); + // defaults to true if not defined + if (typeof(options.updateSummary) === 'undefined' || !!options.updateSummary) { + this.updateFileSummary(); + this.updateEmptyContent(); } - FileActions.display(tr.find('td.filename'), true); return tr; }, + /** + * Returns the current directory + * @return current directory + */ getCurrentDirectory: function(){ return $('#dir').val() || '/'; }, /** + * Returns the directory permissions + * @return permission value as integer + */ + getDirectoryPermissions: function() { + return parseInt($('#permissions').val(), 10); + }, + /** * @brief Changes the current directory and reload the file list. * @param targetDir target directory (non URL encoded) * @param changeUrl false if the URL must not be changed (defaults to true) @@ -209,7 +389,7 @@ window.FileList={ if (!force && currentDir === targetDir) { return; } - FileList.setCurrentDir(targetDir, changeUrl); + FileList._setCurrentDir(targetDir, changeUrl); $('#fileList').trigger( jQuery.Event('changeDirectory', { dir: targetDir, @@ -221,7 +401,13 @@ window.FileList={ linkTo: function(dir) { return OC.linkTo('files', 'index.php')+"?dir="+ encodeURIComponent(dir).replace(/%2F/g, '/'); }, - setCurrentDir: function(targetDir, changeUrl) { + + /** + * Sets the current directory name and updates the breadcrumb. + * @param targetDir directory to display + * @param changeUrl true to also update the URL, false otherwise (default) + */ + _setCurrentDir: function(targetDir, changeUrl) { var url, baseDir = OC.basename(targetDir); @@ -243,6 +429,7 @@ window.FileList={ window.location.hash = '?dir='+ encodeURIComponent(targetDir).replace(/%2F/g, '/'); } } + this.breadcrumb.setDirectory(this.getCurrentDirectory()); }, /** * @brief Reloads the file list using ajax call @@ -253,10 +440,9 @@ window.FileList={ FileList._reloadCall.abort(); } FileList._reloadCall = $.ajax({ - url: OC.filePath('files','ajax','list.php'), + url: Files.getAjaxUrl('list'), data: { - dir : $('#dir').val(), - breadcrumb: true + dir : $('#dir').val() }, error: function(result) { FileList.reloadCallback(result); @@ -269,8 +455,8 @@ window.FileList={ reloadCallback: function(result) { var $controls = $('#controls'); - delete FileList._reloadCall; - FileList.hideMask(); + delete this._reloadCall; + this.hideMask(); if (!result || result.status === 'error') { OC.Notification.show(result.data.message); @@ -279,7 +465,11 @@ window.FileList={ if (result.status === 404) { // go back home - FileList.changeDirectory('/'); + this.changeDirectory('/'); + return; + } + // aborted ? + if (result.status === 0){ return; } @@ -288,24 +478,10 @@ window.FileList={ Files.updateStorageStatistics(true); if (result.data.permissions) { - FileList.setDirectoryPermissions(result.data.permissions); - } - - if (typeof(result.data.breadcrumb) !== 'undefined') { - $controls.find('.crumb').remove(); - $controls.prepend(result.data.breadcrumb); - - var width = $(window).width(); - Files.initBreadCrumbs(); - Files.resizeBreadcrumbs(width, true); - - // in case svg is not supported by the browser we need to execute the fallback mechanism - if (!SVGSupport()) { - replaceSVG(); - } + this.setDirectoryPermissions(result.data.permissions); } - FileList.update(result.data.files); + this.setFiles(result.data.files); }, setDirectoryPermissions: function(permissions) { var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; @@ -322,10 +498,14 @@ window.FileList={ $('.actions,#file_action_panel').toggleClass('hidden', !show); if (show){ // make sure to display according to permissions - var permissions = $('#permissions').val(); + var permissions = this.getDirectoryPermissions(); var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; $('.creatable').toggleClass('hidden', !isCreatable); $('.notCreatable').toggleClass('hidden', isCreatable); + // remove old style breadcrumbs (some apps might create them) + $('#controls .crumb').remove(); + // refresh breadcrumbs in case it was replaced by an app + this.breadcrumb.render(); } else{ $('.creatable, .notCreatable').addClass('hidden'); @@ -341,22 +521,32 @@ window.FileList={ this.showActions(!show); $('#filestable').toggleClass('hidden', show); }, - remove:function(name){ + /** + * Removes a file entry from the list + * @param name name of the file to remove + * @param options optional options as map: + * "updateSummary": true to update the summary (default), false otherwise + */ + remove:function(name, options){ + options = options || {}; var fileEl = FileList.findFileEl(name); if (fileEl.data('permissions') & OC.PERMISSION_DELETE) { // file is only draggable when delete permissions are set fileEl.find('td.filename').draggable('destroy'); } fileEl.remove(); - FileList.updateFileSummary(); - if ( ! $('tr[data-file]').exists() ) { - $('#emptycontent').removeClass('hidden'); - $('#filescontent th').addClass('hidden'); + // TODO: improve performance on batch update + FileList.isEmpty = !this.$fileList.find('tr:not(.summary)').length; + if (typeof(options.updateSummary) === 'undefined' || !!options.updateSummary) { + FileList.updateEmptyContent(); + FileList.updateFileSummary(); } + return fileEl; }, insertElement:function(name, type, element) { - //find the correct spot to insert the file or folder - var pos, fileElements=$('tr[data-file][data-type="'+type+'"]:visible'); + // find the correct spot to insert the file or folder + var pos, + fileElements = this.$fileList.find('tr[data-file][data-type="'+type+'"]:not(.hidden)'); if (name.localeCompare($(fileElements[0]).attr('data-file')) < 0) { pos = -1; } else if (name.localeCompare($(fileElements[fileElements.length-1]).attr('data-file')) > 0) { @@ -376,35 +566,18 @@ window.FileList={ } else { $(fileElements[pos]).after(element); } - } else if (type === 'dir' && $('tr[data-file]').exists()) { - $('tr[data-file]').first().before(element); - } else if (type === 'file' && $('tr[data-file]').exists()) { - $('tr[data-file]').last().before(element); + } else if (type === 'dir' && !FileList.isEmpty) { + this.$fileList.find('tr[data-file]:first').before(element); + } else if (type === 'file' && !FileList.isEmpty) { + this.$fileList.find('tr[data-file]:last').before(element); } else { - $('#fileList').append(element); + this.$fileList.append(element); } - $('#emptycontent').addClass('hidden'); - $('#filestable th').removeClass('hidden'); + FileList.isEmpty = false; + FileList.updateEmptyContent(); FileList.updateFileSummary(); }, - loadingDone:function(name, id) { - var mime, tr = FileList.findFileEl(name); - tr.data('loading', false); - mime = tr.data('mime'); - tr.attr('data-mime', mime); - if (id) { - tr.attr('data-id', id); - } - var path = getPathForPreview(name); - Files.lazyLoadPreview(path, mime, function(previewpath) { - tr.find('td.filename').attr('style','background-image:url('+previewpath+')'); - }, null, null, tr.attr('data-etag')); - tr.find('td.filename').draggable(dragOptions); - }, - isLoading:function(file) { - return FileList.findFileEl(file).data('loading'); - }, - rename:function(oldname) { + rename: function(oldname) { var tr, td, input, form; tr = FileList.findFileEl(oldname); tr.data('renaming',true); @@ -438,6 +611,7 @@ window.FileList={ event.preventDefault(); try { var newname = input.val(); + var directory = FileList.getCurrentDirectory(); if (newname !== oldname) { checkInput(); // save background image, because it's replaced by a spinner while async request @@ -480,12 +654,12 @@ window.FileList={ tr.attr('data-mime', fileInfo.mime); tr.attr('data-etag', fileInfo.etag); if (fileInfo.isPreviewAvailable) { - Files.lazyLoadPreview(fileInfo.directory + '/' + fileInfo.name, result.data.mime, function(previewpath) { + Files.lazyLoadPreview(directory + '/' + fileInfo.name, result.data.mime, function(previewpath) { tr.find('td.filename').attr('style','background-image:url('+previewpath+')'); }, null, null, result.data.etag); } else { - tr.find('td.filename').removeClass('preview').attr('style','background-image:url('+fileInfo.icon+')'); + tr.find('td.filename').removeClass('preview').attr('style','background-image:url('+FileList._replaceSVG(fileInfo.icon)+')'); } } // reinsert row @@ -554,58 +728,12 @@ window.FileList={ inList:function(file) { return FileList.findFileEl(file).length; }, - replace:function(oldName, newName, isNewFile) { - // Finish any existing actions - var oldFileEl = FileList.findFileEl(oldName); - var newFileEl = FileList.findFileEl(newName); - oldFileEl.hide(); - newFileEl.hide(); - var tr = oldFileEl.clone(); - tr.attr('data-replace', 'true'); - tr.attr('data-file', newName); - var td = tr.children('td.filename'); - td.children('a.name .span').text(newName); - var path = td.children('a.name').attr('href'); - td.children('a.name').attr('href', path.replace(encodeURIComponent(oldName), encodeURIComponent(newName))); - var basename = newName; - if (newName.indexOf('.') > 0) { - basename = newName.substr(0, newName.lastIndexOf('.')); - } - td.children('a.name').empty(); - var span = $('<span class="nametext"></span>'); - span.text(basename); - td.children('a.name').append(span); - if (newName.indexOf('.') > 0) { - span.append($('<span class="extension">'+newName.substr(newName.lastIndexOf('.'))+'</span>')); - } - FileList.insertElement(newName, tr.data('type'), tr); - tr.show(); - FileList.replaceCanceled = false; - FileList.replaceOldName = oldName; - FileList.replaceNewName = newName; - FileList.replaceIsNewFile = isNewFile; - FileList.lastAction = function() { - FileList.finishReplace(); - }; - if (!isNewFile) { - OC.Notification.showHtml(t('files', 'replaced {new_name} with {old_name}', {new_name: newName}, {old_name: oldName})+'<span class="undo">'+t('files', 'undo')+'</span>'); - } - }, - finishReplace:function() { - if (!FileList.replaceCanceled && FileList.replaceOldName && FileList.replaceNewName) { - $.ajax({url: OC.filePath('files', 'ajax', 'rename.php'), async: false, data: { dir: $('#dir').val(), newname: FileList.replaceNewName, file: FileList.replaceOldName }, success: function(result) { - if (result && result.status === 'success') { - $('tr[data-replace="true"').removeAttr('data-replace'); - } else { - OC.dialogs.alert(result.data.message, 'Error moving file'); - } - FileList.replaceCanceled = true; - FileList.replaceOldName = null; - FileList.replaceNewName = null; - FileList.lastAction = null; - }}); - } - }, + /** + * Delete the given files from the given dir + * @param files file names list (without path) + * @param dir directory in which to delete the files, defaults to the current + * directory + */ do_delete:function(files, dir) { var params; if (files && files.substr) { @@ -622,7 +750,7 @@ window.FileList={ FileList.lastAction(); } - var params = { + params = { dir: dir || FileList.getCurrentDirectory() }; if (files) { @@ -643,10 +771,9 @@ window.FileList={ } else { $.each(files,function(index,file) { - var files = FileList.findFileEl(file); - files.remove(); - files.find('input[type="checkbox"]').removeAttr('checked'); - files.removeClass('selected'); + var fileEl = FileList.remove(file, {updateSummary: false}); + fileEl.find('input[type="checkbox"]').prop('checked', false); + fileEl.removeClass('selected'); }); } procesSelection(); @@ -680,7 +807,7 @@ window.FileList={ }); }, createFileSummary: function() { - if( $('#fileList tr').exists() ) { + if ( !FileList.isEmpty ) { var summary = this._calculateFileSummary(); // Get translations @@ -702,7 +829,7 @@ window.FileList={ } var $summary = $('<tr class="summary" data-file="undefined"><td><span class="info">'+info+'</span></td>'+fileSize+'<td></td></tr>'); - $('#fileList').append($summary); + this.$fileList.append($summary); var $dirInfo = $summary.find('.dirinfo'); var $fileInfo = $summary.find('.fileinfo'); @@ -710,12 +837,12 @@ window.FileList={ // Show only what's necessary, e.g.: no files: don't show "0 files" if (summary.totalDirs === 0) { - $dirInfo.hide(); - $connector.hide(); + $dirInfo.addClass('hidden'); + $connector.addClass('hidden'); } if (summary.totalFiles === 0) { - $fileInfo.hide(); - $connector.hide(); + $fileInfo.addClass('hidden'); + $connector.addClass('hidden'); } } }, @@ -740,10 +867,13 @@ window.FileList={ return result; }, updateFileSummary: function() { - var $summary = $('.summary'); + var $summary = this.$el.find('.summary'); + + // always make it the last element + this.$fileList.append($summary.detach()); // Check if we should remove the summary to show "Upload something" - if ($('#fileList tr').length === 1 && $summary.length === 1) { + if (this.isEmpty && $summary.length === 1) { $summary.remove(); } // If there's no summary create one (createFileSummary checks if there's data) @@ -751,7 +881,7 @@ window.FileList={ FileList.createFileSummary(); } // There's a summary and data -> Update the summary - else if ($('#fileList tr').length > 1 && $summary.length === 1) { + else if (!this.isEmpty && $summary.length === 1) { var fileSummary = this._calculateFileSummary(); var $dirInfo = $('.summary .dirinfo'); var $fileInfo = $('.summary .fileinfo'); @@ -764,19 +894,19 @@ window.FileList={ // Show only what's necessary (may be hidden) if (fileSummary.totalDirs === 0) { - $dirInfo.hide(); - $connector.hide(); + $dirInfo.addClass('hidden'); + $connector.addClass('hidden'); } else { - $dirInfo.show(); + $dirInfo.removeClass('hidden'); } if (fileSummary.totalFiles === 0) { - $fileInfo.hide(); - $connector.hide(); + $fileInfo.addClass('hidden'); + $connector.addClass('hidden'); } else { - $fileInfo.show(); + $fileInfo.removeClass('hidden'); } if (fileSummary.totalDirs > 0 && fileSummary.totalFiles > 0) { - $connector.show(); + $connector.removeClass('hidden'); } } }, @@ -784,10 +914,14 @@ window.FileList={ var $fileList = $('#fileList'); var permissions = $('#permissions').val(); var isCreatable = (permissions & OC.PERMISSION_CREATE) !== 0; - var exists = $fileList.find('tr:first').exists(); - $('#emptycontent').toggleClass('hidden', !isCreatable || exists); - $('#filestable th').toggleClass('hidden', !exists); + $('#emptycontent').toggleClass('hidden', !isCreatable || !FileList.isEmpty); + $('#filestable thead th').toggleClass('hidden', FileList.isEmpty); }, + /** + * Shows the loading mask. + * + * @see #hideMask + */ showMask: function() { // in case one was shown before var $mask = $('#content .mask'); @@ -795,23 +929,23 @@ window.FileList={ return; } + this.$el.addClass('hidden'); + $mask = $('<div class="mask transparent"></div>'); $mask.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); $mask.css('background-repeat', 'no-repeat'); $('#content').append($mask); - // block UI, but only make visible in case loading takes longer - FileList._maskTimeout = window.setTimeout(function() { - // reset opacity - $mask.removeClass('transparent'); - }, 250); + $mask.removeClass('transparent'); }, + /** + * Hide the loading mask. + * @see #showMask + */ hideMask: function() { - var $mask = $('#content .mask').remove(); - if (FileList._maskTimeout) { - window.clearTimeout(FileList._maskTimeout); - } + $('#content .mask').remove(); + this.$el.removeClass('hidden'); }, scrollTo:function(file) { //scroll to and highlight preselected file @@ -850,29 +984,11 @@ window.FileList={ */ isAllSelected: function() { return $('#select_all').prop('checked'); - }, - - /** - * Returns the download URL of the given file - * @param filename file name of the file - * @param dir optional directory in which the file name is, defaults to the current directory - */ - getDownloadUrl: function(filename, dir) { - var files = filename; - if ($.isArray(filename)) { - files = JSON.stringify(filename); - } - var params = { - dir: dir || FileList.getCurrentDirectory(), - files: files - }; - return OC.filePath('files', 'ajax', 'download.php') + '?' + OC.buildQueryString(params); } }; $(document).ready(function() { - var baseDir, - isPublic = !!$('#isPublic').val(); + FileList.initialize(); // handle upload events var file_upload_start = $('#file_upload_start'); @@ -907,8 +1023,13 @@ $(document).ready(function() { {name: 'requesttoken', value: oc_requesttoken} ]; }; + } else { + // cancel uploads to current dir if no permission + var isCreatable = (FileList.getDirectoryPermissions() & OC.PERMISSION_CREATE) !== 0; + if (!isCreatable) { + return false; + } } - }); file_upload_start.on('fileuploadadd', function(e, data) { OC.Upload.log('filelist handle fileuploadadd', e, data); @@ -993,31 +1114,11 @@ $(document).ready(function() { if (data.files[0].size>=0) { size=data.files[0].size; } - var date=new Date(); - var param = {}; - if ($('#publicUploadRequestToken').exists()) { - param.download_url = document.location.href + '&download&path=/' + $('#dir').val() + '/' + file.name; - } //should the file exist in the list remove it FileList.remove(file.name); // create new file context - data.context = FileList.addFile(file.name, file.size, date, false, false, param); - - // update file data - data.context.attr('data-mime',file.mime).attr('data-id',file.id).attr('data-etag', file.etag); - - var permissions = data.context.data('permissions'); - if (permissions !== file.permissions) { - data.context.attr('data-permissions', file.permissions); - data.context.data('permissions', file.permissions); - } - FileActions.display(data.context.find('td.filename'), true); - - var path = getPathForPreview(file.name); - Files.lazyLoadPreview(path, file.mime, function(previewpath) { - data.context.find('td.filename').attr('style','background-image:url('+previewpath+')'); - }, null, null, file.etag); + data.context = FileList.add(file, {insert: true}); } } }); @@ -1049,31 +1150,6 @@ $(document).ready(function() { }); $('#notification').hide(); - $('#notification').on('click', '.undo', function() { - if (FileList.deleteFiles) { - $.each(FileList.deleteFiles,function(index,file) { - FileList.findFileEl(file).show(); - }); - FileList.deleteCanceled=true; - FileList.deleteFiles=null; - } else if (FileList.replaceOldName && FileList.replaceNewName) { - if (FileList.replaceIsNewFile) { - // Delete the new uploaded file - FileList.deleteCanceled = false; - FileList.deleteFiles = [FileList.replaceOldName]; - } else { - FileList.findFileEl(FileList.replaceOldName).show(); - } - $('tr[data-replace="true"').remove(); - FileList.findFileEl(FileList.replaceNewName).show(); - FileList.replaceCanceled = true; - FileList.replaceOldName = null; - FileList.replaceNewName = null; - FileList.replaceIsNewFile = null; - } - FileList.lastAction = null; - OC.Notification.hide(); - }); $('#notification:first-child').on('click', '.replace', function() { OC.Notification.hide(function() { FileList.replace($('#notification > span').attr('data-oldName'), $('#notification > span').attr('data-newName'), $('#notification > span').attr('data-isNewFile')); @@ -1081,7 +1157,7 @@ $(document).ready(function() { }); $('#notification:first-child').on('click', '.suggest', function() { var file = $('#notification > span').attr('data-oldName'); - FileList.findFileEl(file).show(); + FileList.findFileEl(file).removeClass('hidden'); OC.Notification.hide(); }); $('#notification:first-child').on('click', '.cancel', function() { @@ -1130,34 +1206,32 @@ $(document).ready(function() { } // disable ajax/history API for public app (TODO: until it gets ported) - if (!isPublic) { - // fallback to hashchange when no history support - if (!window.history.pushState) { - $(window).on('hashchange', function() { - FileList.changeDirectory(parseCurrentDirFromUrl(), false); - }); + // fallback to hashchange when no history support + if (!window.history.pushState) { + $(window).on('hashchange', function() { + FileList.changeDirectory(parseCurrentDirFromUrl(), false); + }); + } + window.onpopstate = function(e) { + var targetDir; + if (e.state && e.state.dir) { + targetDir = e.state.dir; } - window.onpopstate = function(e) { - var targetDir; - if (e.state && e.state.dir) { - targetDir = e.state.dir; - } - else{ - // read from URL - targetDir = parseCurrentDirFromUrl(); - } - if (targetDir) { - FileList.changeDirectory(targetDir, false); - } - }; - - if (parseInt($('#ajaxLoad').val(), 10) === 1) { - // need to initially switch the dir to the one from the hash (IE8) - FileList.changeDirectory(parseCurrentDirFromUrl(), false, true); + else{ + // read from URL + targetDir = parseCurrentDirFromUrl(); + } + if (targetDir) { + FileList.changeDirectory(targetDir, false); } + }; - FileList.setCurrentDir(parseCurrentDirFromUrl(), false); - } + var dir = parseCurrentDirFromUrl(); + // trigger ajax load, deferred to let sub-apps do their overrides first + setTimeout(function() { + FileList.changeDirectory(dir, false, true); + }, 0); FileList.createFileSummary(); }); + diff --git a/apps/files/js/files.js b/apps/files/js/files.js index 1137364db4a..4c2d87d808c 100644 --- a/apps/files/js/files.js +++ b/apps/files/js/files.js @@ -161,80 +161,33 @@ var Files = { }); }, - lastWidth: 0, - - initBreadCrumbs: function () { - var $controls = $('#controls'); - - Files.lastWidth = 0; - Files.breadcrumbs = []; - - // initialize with some extra space - Files.breadcrumbsWidth = 64; - if ( document.getElementById("navigation") ) { - Files.breadcrumbsWidth += $('#navigation').get(0).offsetWidth; + /** + * Returns the download URL of the given file(s) + * @param filename string or array of file names to download + * @param dir optional directory in which the file name is, defaults to the current directory + */ + getDownloadUrl: function(filename, dir) { + if ($.isArray(filename)) { + filename = JSON.stringify(filename); } - Files.hiddenBreadcrumbs = 0; - - $.each($('.crumb'), function(index, breadcrumb) { - Files.breadcrumbs[index] = breadcrumb; - Files.breadcrumbsWidth += $(breadcrumb).get(0).offsetWidth; - }); - - $.each($('#controls .actions>div'), function(index, action) { - Files.breadcrumbsWidth += $(action).get(0).offsetWidth; - }); - - // event handlers for breadcrumb items - $controls.find('.crumb a').on('click', onClickBreadcrumb); - - // setup drag and drop - $controls.find('.crumb:not(.last)').droppable(crumbDropOptions); + var params = { + dir: dir || FileList.getCurrentDirectory(), + files: filename + }; + return this.getAjaxUrl('download', params); }, - resizeBreadcrumbs: function (width, firstRun) { - if (width !== Files.lastWidth) { - if ((width < Files.lastWidth || firstRun) && width < Files.breadcrumbsWidth) { - if (Files.hiddenBreadcrumbs === 0) { - bc = $(Files.breadcrumbs[1]).get(0); - if (typeof bc != 'undefined') { - Files.breadcrumbsWidth -= bc.offsetWidth; - $(Files.breadcrumbs[1]).find('a').hide(); - $(Files.breadcrumbs[1]).append('<span>...</span>'); - Files.breadcrumbsWidth += bc.offsetWidth; - Files.hiddenBreadcrumbs = 2; - } - } - var i = Files.hiddenBreadcrumbs; - while (width < Files.breadcrumbsWidth && i > 1 && i < Files.breadcrumbs.length - 1) { - Files.breadcrumbsWidth -= $(Files.breadcrumbs[i]).get(0).offsetWidth; - $(Files.breadcrumbs[i]).hide(); - Files.hiddenBreadcrumbs = i; - i++; - } - } else if (width > Files.lastWidth && Files.hiddenBreadcrumbs > 0) { - var i = Files.hiddenBreadcrumbs; - while (width > Files.breadcrumbsWidth && i > 0) { - if (Files.hiddenBreadcrumbs === 1) { - Files.breadcrumbsWidth -= $(Files.breadcrumbs[1]).get(0).offsetWidth; - $(Files.breadcrumbs[1]).find('span').remove(); - $(Files.breadcrumbs[1]).find('a').show(); - Files.breadcrumbsWidth += $(Files.breadcrumbs[1]).get(0).offsetWidth; - } else { - $(Files.breadcrumbs[i]).show(); - Files.breadcrumbsWidth += $(Files.breadcrumbs[i]).get(0).offsetWidth; - if (Files.breadcrumbsWidth > width) { - Files.breadcrumbsWidth -= $(Files.breadcrumbs[i]).get(0).offsetWidth; - $(Files.breadcrumbs[i]).hide(); - break; - } - } - i--; - Files.hiddenBreadcrumbs = i; - } - } - Files.lastWidth = width; + /** + * Returns the ajax URL for a given action + * @param action action string + * @param params optional params map + */ + getAjaxUrl: function(action, params) { + var q = ''; + if (params) { + q = '?' + OC.buildQueryString(params); } + return OC.filePath('files', 'ajax', action + '.php') + q; } }; $(document).ready(function() { @@ -245,14 +198,10 @@ $(document).ready(function() { Files.displayEncryptionWarning(); Files.bindKeyboardShortcuts(document, jQuery); - FileList.postProcessList(); Files.setupDragAndDrop(); $('#file_action_panel').attr('activeAction', false); - // allow dropping on the "files" app icon - $('ul#apps li:first-child').data('dir','').droppable(crumbDropOptions); - // Triggers invisible file input $('#upload a').on('click', function() { $(this).parent().children('#file_upload_start').trigger('click'); @@ -311,7 +260,7 @@ $(document).ready(function() { var filename=$(this).parent().parent().attr('data-file'); var tr = FileList.findFileEl(filename); var renaming=tr.data('renaming'); - if (!renaming && !FileList.isLoading(filename)) { + if (!renaming) { FileActions.currentFile = $(this).parent(); var mime=FileActions.getCurrentMimeType(); var type=FileActions.getCurrentType(); @@ -377,15 +326,15 @@ $(document).ready(function() { dir = OC.dirname(dir) || '/'; } else { - files = getSelectedFilesTrash('name'); + files = Files.getSelectedFiles('name'); } OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.')); - OC.redirect(FileList.getDownloadUrl(files, dir)); + OC.redirect(Files.getDownloadUrl(files, dir)); return false; }); $('.delete-selected').click(function(event) { - var files=getSelectedFilesTrash('name'); + var files = Files.getSelectedFiles('name'); event.preventDefault(); if (FileList.isAllSelected()) { files = null; @@ -403,16 +352,6 @@ $(document).ready(function() { //do a background scan if needed scanFiles(); - Files.initBreadCrumbs(); - - $(window).resize(function() { - var width = $(this).width(); - Files.resizeBreadcrumbs(width, false); - }); - - var width = $(this).width(); - Files.resizeBreadcrumbs(width, true); - // display storage warnings setTimeout(Files.displayStorageWarnings, 100); OC.Notification.setDefault(Files.displayStorageWarnings); @@ -503,7 +442,7 @@ var createDragShadow = function(event) { $(event.target).parents('tr').find('td input:first').prop('checked',true); } - var selectedFiles = getSelectedFilesTrash(); + var selectedFiles = Files.getSelectedFiles(); if (!isDragSelected && selectedFiles.length === 1) { //revert the selection @@ -619,52 +558,8 @@ var folderDropOptions={ tolerance: 'pointer' }; -var crumbDropOptions={ - drop: function( event, ui ) { - var target=$(this).data('dir'); - var dir = $('#dir').val(); - while(dir.substr(0,1) === '/') {//remove extra leading /'s - dir=dir.substr(1); - } - dir = '/' + dir; - if (dir.substr(-1,1) !== '/') { - dir = dir + '/'; - } - if (target === dir || target+'/' === dir) { - return; - } - var files = ui.helper.find('tr'); - $(files).each(function(i,row) { - var dir = $(row).data('dir'); - var file = $(row).data('filename'); - //slapdash selector, tracking down our original element that the clone budded off of. - var origin = $('tr[data-id=' + $(row).data('origin') + ']'); - var td = origin.children('td.filename'); - var oldBackgroundImage = td.css('background-image'); - td.css('background-image', 'url('+ OC.imagePath('core', 'loading.gif') + ')'); - $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) { - if (result) { - if (result.status === 'success') { - FileList.remove(file); - procesSelection(); - $('#notification').hide(); - } else { - $('#notification').hide(); - $('#notification').text(result.data.message); - $('#notification').fadeIn(); - } - } else { - OC.dialogs.alert(t('files', 'Error moving file'), t('files', 'Error')); - } - td.css('background-image', oldBackgroundImage); - }); - }); - }, - tolerance: 'pointer' -}; - function procesSelection() { - var selected = getSelectedFilesTrash(); + var selected = Files.getSelectedFiles(); var selectedFiles = selected.filter(function(el) { return el.type==='file'; }); @@ -714,7 +609,7 @@ function procesSelection() { * if property is set, an array with that property for each file is returnd * if it's ommited an array of objects with all properties is returned */ -function getSelectedFilesTrash(property) { +Files.getSelectedFiles = function(property) { var elements=$('td.filename input:checkbox:checked').parent().parent(); var files=[]; elements.each(function(i,element) { @@ -755,25 +650,30 @@ function getPathForPreview(name) { return path; } +/** + * Generates a preview URL based on the URL space. + * @param urlSpec map with {x: width, y: height, file: file path} + * @return preview URL + */ +Files.generatePreviewUrl = function(urlSpec) { + urlSpec = urlSpec || {}; + if (!urlSpec.x) { + urlSpec.x = $('#filestable').data('preview-x'); + } + if (!urlSpec.y) { + urlSpec.y = $('#filestable').data('preview-y'); + } + urlSpec.forceIcon = 0; + return OC.generateUrl('/core/preview.png?') + $.param(urlSpec); +} + Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { // get mime icon url Files.getMimeIcon(mime, function(iconURL) { - var urlSpec = {}; var previewURL; + urlSpec = {}; ready(iconURL); // set mimeicon URL - // now try getting a preview thumbnail URL - if ( ! width ) { - width = $('#filestable').data('preview-x'); - } - if ( ! height ) { - height = $('#filestable').data('preview-y'); - } - // note: the order of arguments must match the one - // from the server's template so that the browser - // knows it's the same file for caching - urlSpec.x = width; - urlSpec.y = height; urlSpec.file = Files.fixPath(path); if (etag){ @@ -784,15 +684,9 @@ Files.lazyLoadPreview = function(path, mime, ready, width, height, etag) { console.warn('Files.lazyLoadPreview(): missing etag argument'); } - if ( $('#isPublic').length ) { - urlSpec.t = $('#dirToken').val(); - previewURL = OC.generateUrl('/publicpreview.png?') + $.param(urlSpec); - } else { - previewURL = OC.generateUrl('/core/preview.png?') + $.param(urlSpec); - } + previewURL = Files.generatePreviewUrl(urlSpec); previewURL = previewURL.replace('(', '%28'); previewURL = previewURL.replace(')', '%29'); - previewURL += '&forceIcon=0'; // preload image to prevent delay // this will make the browser cache the image @@ -841,14 +735,8 @@ function checkTrashStatus() { }); } -function onClickBreadcrumb(e) { - var $el = $(e.target).closest('.crumb'), - $targetDir = $el.data('dir'), - isPublic = !!$('#isPublic').val(); - - if ($targetDir !== undefined && !isPublic) { - e.preventDefault(); - FileList.changeDirectory(decodeURIComponent($targetDir)); - } +// override core's fileDownloadPath (legacy) +function fileDownloadPath(dir, file) { + return Files.getDownloadUrl(file, dir); } |