aboutsummaryrefslogtreecommitdiffstats
path: root/apps/files/js
diff options
context:
space:
mode:
Diffstat (limited to 'apps/files/js')
-rw-r--r--apps/files/js/app.js92
-rw-r--r--apps/files/js/file-upload.js80
-rw-r--r--apps/files/js/fileactions.js2
-rw-r--r--apps/files/js/filelist.js122
-rw-r--r--apps/files/js/jquery.iframe-transport.js205
-rw-r--r--apps/files/js/mainfileinfodetailview.js38
6 files changed, 303 insertions, 236 deletions
diff --git a/apps/files/js/app.js b/apps/files/js/app.js
index ff505d417f1..7a3d78f9663 100644
--- a/apps/files/js/app.js
+++ b/apps/files/js/app.js
@@ -11,7 +11,7 @@
*
*/
-/* global dragOptions, folderDropOptions */
+/* global dragOptions, folderDropOptions, OC */
(function() {
if (!OCA.Files) {
@@ -41,10 +41,22 @@
fileList: null,
/**
+ * Backbone model for storing files preferences
+ */
+ _filesConfig: null,
+
+ /**
* Initializes the files app
*/
initialize: function() {
this.navigation = new OCA.Files.Navigation($('#app-navigation'));
+ this.$showHiddenFiles = $('input#showhiddenfilesToggle');
+ var showHidden = $('#showHiddenFiles').val() === "1";
+ this.$showHiddenFiles.prop('checked', showHidden);
+
+ this._filesConfig = new OC.Backbone.Model({
+ showhidden: showHidden
+ });
var urlParams = OC.Util.History.parseUrlQuery();
var fileActions = new OCA.Files.FileActions();
@@ -72,7 +84,12 @@
fileActions: fileActions,
allowLegacyActions: true,
scrollTo: urlParams.scrollto,
- filesClient: OC.Files.getClient()
+ filesClient: OC.Files.getClient(),
+ sorting: {
+ mode: $('#defaultFileSorting').val(),
+ direction: $('#defaultFileSortingDirection').val()
+ },
+ config: this._filesConfig,
}
);
this.files.initialize();
@@ -86,6 +103,8 @@
this._setupEvents();
// trigger URL change event handlers
this._onPopState(urlParams);
+
+ this._debouncedPersistShowHiddenFilesState = _.debounce(this._persistShowHiddenFilesState, 1200);
},
/**
@@ -140,6 +159,14 @@
},
/**
+ *
+ * @returns {Backbone.Model}
+ */
+ getFilesConfig: function() {
+ return this._filesConfig;
+ },
+
+ /**
* Setup events based on URL changes
*/
_setupEvents: function() {
@@ -147,9 +174,34 @@
// detect when app changed their current directory
$('#app-content').delegate('>div', 'changeDirectory', _.bind(this._onDirectoryChanged, this));
+ $('#app-content').delegate('>div', 'afterChangeDirectory', _.bind(this._onAfterDirectoryChanged, this));
$('#app-content').delegate('>div', 'changeViewerMode', _.bind(this._onChangeViewerMode, this));
$('#app-navigation').on('itemChanged', _.bind(this._onNavigationChanged, this));
+ this.$showHiddenFiles.on('change', _.bind(this._onShowHiddenFilesChange, this));
+ },
+
+ /**
+ * Toggle showing hidden files according to the settings checkbox
+ *
+ * @returns {undefined}
+ */
+ _onShowHiddenFilesChange: function() {
+ var show = this.$showHiddenFiles.is(':checked');
+ this._filesConfig.set('showhidden', show);
+ this._debouncedPersistShowHiddenFilesState();
+ },
+
+ /**
+ * Persist show hidden preference on ther server
+ *
+ * @returns {undefined}
+ */
+ _persistShowHiddenFilesState: function() {
+ var show = this._filesConfig.get('showhidden');
+ $.post(OC.generateUrl('/apps/files/api/v1/showhidden'), {
+ show: show
+ });
},
/**
@@ -173,7 +225,16 @@
*/
_onDirectoryChanged: function(e) {
if (e.dir) {
- this._changeUrl(this.navigation.getActiveItem(), e.dir);
+ this._changeUrl(this.navigation.getActiveItem(), e.dir, e.fileId);
+ }
+ },
+
+ /**
+ * Event handler for when an app notified that its directory changed
+ */
+ _onAfterDirectoryChanged: function(e) {
+ if (e.dir && e.fileId) {
+ this._changeUrl(this.navigation.getActiveItem(), e.dir, e.fileId);
}
},
@@ -210,14 +271,35 @@
},
/**
+ * Encode URL params into a string, except for the "dir" attribute
+ * that gets encoded as path where "/" is not encoded
+ *
+ * @param {Object.<string>} params
+ * @return {string} encoded params
+ */
+ _makeUrlParams: function(params) {
+ var dir = params.dir;
+ delete params.dir;
+ return 'dir=' + OC.encodePath(dir) + '&' + OC.buildQueryString(params);
+ },
+
+ /**
* Change the URL to point to the given dir and view
*/
- _changeUrl: function(view, dir) {
+ _changeUrl: function(view, dir, fileId) {
var params = {dir: dir};
if (view !== 'files') {
params.view = view;
+ } else if (fileId) {
+ params.fileid = fileId;
+ }
+ var currentParams = OC.Util.History.parseUrlQuery();
+ if (currentParams.dir === params.dir && currentParams.view === params.view && currentParams.fileid !== params.fileid) {
+ // if only fileid changed or was added, replace instead of push
+ OC.Util.History.replaceState(this._makeUrlParams(params));
+ } else {
+ OC.Util.History.pushState(this._makeUrlParams(params));
}
- OC.Util.History.pushState(params);
}
};
})();
diff --git a/apps/files/js/file-upload.js b/apps/files/js/file-upload.js
index bd80afd072c..3257ded7b89 100644
--- a/apps/files/js/file-upload.js
+++ b/apps/files/js/file-upload.js
@@ -274,6 +274,7 @@ OC.Upload = {
if ( $('#file_upload_start').exists() ) {
var file_upload_param = {
dropZone: $('#content'), // restrict dropZone to content div
+ pasteZone: null,
autoUpload: false,
sequentialUploads: true,
//singleFileUploads is on by default, so the data.files array will always have length 1
@@ -503,7 +504,7 @@ OC.Upload = {
//fetch response from iframe
response = data.result[0].body.innerText;
}
- var result = $.parseJSON(response);
+ var result = JSON.parse(response);
delete data.jqXHR;
@@ -556,7 +557,16 @@ OC.Upload = {
window.file_upload_param = fileupload;
if (supportAjaxUploadWithProgress()) {
-
+ //remaining time
+ var lastUpdate = new Date().getMilliseconds();
+ var lastSize = 0;
+ var bufferSize = 20;
+ var buffer = [];
+ var bufferIndex = 0;
+ var bufferTotal = 0;
+ for(var i = 0; i < bufferSize;i++){
+ buffer[i] = 0;
+ }
// add progress handlers
fileupload.on('fileuploadadd', function(e, data) {
OC.Upload.log('progress handle fileuploadadd', e, data);
@@ -569,7 +579,15 @@ OC.Upload = {
fileupload.on('fileuploadstart', function(e, data) {
OC.Upload.log('progress handle fileuploadstart', e, data);
$('#uploadprogresswrapper .stop').show();
+ $('#uploadprogresswrapper .label').show();
$('#uploadprogressbar').progressbar({value: 0});
+ $('#uploadprogressbar .ui-progressbar-value').
+ html('<em class="label inner"><span class="desktop">'
+ + t('files', 'Uploading...')
+ + '</span><span class="mobile">'
+ + t('files', '...')
+ + '</span></em>');
+ $('#uploadprogressbar').tipsy({gravity:'n', fade:true, live:true});
OC.Upload._showProgressBar();
});
fileupload.on('fileuploadprogress', function(e, data) {
@@ -579,11 +597,67 @@ OC.Upload = {
fileupload.on('fileuploadprogressall', function(e, data) {
OC.Upload.log('progress handle fileuploadprogressall', e, data);
var progress = (data.loaded / data.total) * 100;
+ var thisUpdate = new Date().getMilliseconds();
+ var diffUpdate = (thisUpdate - lastUpdate)/1000; // eg. 2s
+ lastUpdate = thisUpdate;
+ var diffSize = data.loaded - lastSize;
+ lastSize = data.loaded;
+ diffSize = diffSize / diffUpdate; // apply timing factor, eg. 1mb/2s = 0.5mb/s
+ var remainingSeconds = ((data.total - data.loaded) / diffSize);
+ if(remainingSeconds >= 0) {
+ bufferTotal = bufferTotal - (buffer[bufferIndex]) + remainingSeconds;
+ buffer[bufferIndex] = remainingSeconds; //buffer to make it smoother
+ bufferIndex = (bufferIndex + 1) % bufferSize;
+ }
+ var smoothRemainingSeconds = (bufferTotal / bufferSize); //seconds
+ var date = new Date(smoothRemainingSeconds * 1000);
+ var timeStringDesktop = "";
+ var timeStringMobile = "";
+ if(date.getUTCHours() > 0){
+ timeStringDesktop = t('files', '{hours}:{minutes}:{seconds} hour{plural_s} left' , {
+ hours:date.getUTCHours(),
+ minutes: ('0' + date.getUTCMinutes()).slice(-2),
+ seconds: ('0' + date.getUTCSeconds()).slice(-2),
+ plural_s: ( smoothRemainingSeconds === 3600 ? "": "s") // 1 hour = 1*60m*60s = 3600s
+ });
+ timeStringMobile = t('files', '{hours}:{minutes}h' , {
+ hours:date.getUTCHours(),
+ minutes: ('0' + date.getUTCMinutes()).slice(-2),
+ seconds: ('0' + date.getUTCSeconds()).slice(-2)
+ });
+ } else if(date.getUTCMinutes() > 0){
+ timeStringDesktop = t('files', '{minutes}:{seconds} minute{plural_s} left' , {
+ minutes: date.getUTCMinutes(),
+ seconds: ('0' + date.getUTCSeconds()).slice(-2),
+ plural_s: (smoothRemainingSeconds === 60 ? "": "s") // 1 minute = 1*60s = 60s
+ });
+ timeStringMobile = t('files', '{minutes}:{seconds}m' , {
+ minutes: date.getUTCMinutes(),
+ seconds: ('0' + date.getUTCSeconds()).slice(-2)
+ });
+ } else if(date.getUTCSeconds() > 0){
+ timeStringDesktop = t('files', '{seconds} second{plural_s} left' , {
+ seconds: date.getUTCSeconds(),
+ plural_s: (smoothRemainingSeconds === 1 ? "": "s") // 1 second = 1s = 1s
+ });
+ timeStringMobile = t('files', '{seconds}s' , {seconds: date.getUTCSeconds()});
+ } else {
+ timeStringDesktop = t('files', 'Any moment now...');
+ timeStringMobile = t('files', 'Soon...');
+ }
+ $('#uploadprogressbar .label .mobile').text(timeStringMobile);
+ $('#uploadprogressbar .label .desktop').text(timeStringDesktop);
+ $('#uploadprogressbar').attr('original-title',
+ t('files', '{loadedSize} of {totalSize} ({bitrate})' , {
+ loadedSize: humanFileSize(data.loaded),
+ totalSize: humanFileSize(data.total),
+ bitrate: humanFileSize(data.bitrate) + '/s'
+ })
+ );
$('#uploadprogressbar').progressbar('value', progress);
});
fileupload.on('fileuploadstop', function(e, data) {
OC.Upload.log('progress handle fileuploadstop', e, data);
-
OC.Upload._hideProgressBar();
});
fileupload.on('fileuploadfail', function(e, data) {
diff --git a/apps/files/js/fileactions.js b/apps/files/js/fileactions.js
index 69e32d500c4..c3d4fba9ef5 100644
--- a/apps/files/js/fileactions.js
+++ b/apps/files/js/fileactions.js
@@ -619,7 +619,7 @@
this.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
var dir = context.$file.attr('data-path') || context.fileList.getCurrentDirectory();
- context.fileList.changeDirectory(OC.joinPaths(dir, filename));
+ context.fileList.changeDirectory(OC.joinPaths(dir, filename), true, false, parseInt(context.$file.attr('data-id'), 10));
});
this.registerAction({
diff --git a/apps/files/js/filelist.js b/apps/files/js/filelist.js
index 6229d3b2316..ef29a4844bf 100644
--- a/apps/files/js/filelist.js
+++ b/apps/files/js/filelist.js
@@ -145,6 +145,11 @@
_filter: '',
/**
+ * @type Backbone.Model
+ */
+ _filesConfig: undefined,
+
+ /**
* Sort attribute
* @type String
*/
@@ -198,6 +203,18 @@
return;
}
+ if (options.config) {
+ this._filesConfig = options.config;
+ } else if (!_.isUndefined(OCA.Files) && !_.isUndefined(OCA.Files.App)) {
+ this._filesConfig = OCA.Files.App.getFilesConfig();
+ }
+
+ if (!_.isUndefined(this._filesConfig)) {
+ this._filesConfig.on('change:showhidden', function() {
+ self.setFiles(self.files);
+ });
+ }
+
if (options.dragOptions) {
this._dragOptions = options.dragOptions;
}
@@ -239,7 +256,11 @@
this.fileSummary = this._createSummary();
- this.setSort('name', 'asc');
+ if (options.sorting) {
+ this.setSort(options.sorting.mode, options.sorting.direction, false, false);
+ } else {
+ this.setSort('name', 'asc', false, false);
+ }
var breadcrumbOptions = {
onClick: _.bind(this._onClickBreadCrumb, this),
@@ -277,7 +298,8 @@
this.updateSearch();
- this.$fileList.on('click','td.filename>a.name', _.bind(this._onClickFile, this));
+ this.$fileList.on('click','td.filename>a.name, td.filesize, td.date', _.bind(this._onClickFile, this));
+
this.$fileList.on('change', 'td.filename>.selectCheckBox', _.bind(this._onClickFileCheckbox, this));
this.$el.on('urlChanged', _.bind(this._onUrlChanged, this));
this.$el.find('.select-all').click(_.bind(this._onClickSelectAll, this));
@@ -395,6 +417,11 @@
model.toJSON(),
{updateSummary: true, silent: false, animate: true}
);
+
+ // restore selection state
+ var selected = !!self._selectedFiles[$tr.data('id')];
+ self._selectFileEl($tr, selected);
+
$tr.toggleClass('highlighted', highlightState);
});
model.on('busy', function(model, state) {
@@ -695,14 +722,14 @@
sort = $target.attr('data-sort');
if (sort) {
if (this._sort === sort) {
- this.setSort(sort, (this._sortDirection === 'desc')?'asc':'desc', true);
+ this.setSort(sort, (this._sortDirection === 'desc')?'asc':'desc', true, true);
}
else {
if ( sort === 'name' ) { //default sorting of name is opposite to size and mtime
- this.setSort(sort, 'asc', true);
+ this.setSort(sort, 'asc', true, true);
}
else {
- this.setSort(sort, 'desc', true);
+ this.setSort(sort, 'desc', true, true);
}
}
}
@@ -850,6 +877,10 @@
* @return array of DOM elements of the newly added files
*/
_nextPage: function(animate) {
+ // Save full files list while rendering
+ var allFiles = this.files;
+ this.files = this._filterHiddenFiles(this.files);
+
var index = this.$fileList.children().length,
count = this.pageSize(),
hidden,
@@ -896,6 +927,10 @@
}
}, 0);
}
+
+ // Restore full files list after rendering
+ this.files = allFiles;
+
return newTrs;
},
@@ -933,18 +968,25 @@
// clear "Select all" checkbox
this.$el.find('.select-all').prop('checked', false);
+ // Save full files list while rendering
+ var allFiles = this.files;
+ this.files = this._filterHiddenFiles(this.files);
+
this.isEmpty = this.files.length === 0;
this._nextPage();
this.updateEmptyContent();
- this.fileSummary.calculate(filesArray);
+ this.fileSummary.calculate(this.files);
this._selectedFiles = {};
this._selectionSummary.clear();
this.updateSelectionSummary();
$(window).scrollTop(0);
+ // Restore full files list after rendering
+ this.files = allFiles;
+
this.$fileList.trigger(jQuery.Event('updated'));
_.defer(function() {
self.$el.closest('#app-content').trigger(jQuery.Event('apprendered'));
@@ -952,6 +994,21 @@
},
/**
+ * Filter hidden files of the given filesArray (dot-files)
+ *
+ * @param filesArray files to be filtered
+ * @returns {array}
+ */
+ _filterHiddenFiles: function(files) {
+ if (_.isUndefined(this._filesConfig) || this._filesConfig.get('showhidden')) {
+ return files;
+ }
+ return _.filter(files, function(file) {
+ return file.name.indexOf('.') !== 0;
+ });
+ },
+
+ /**
* Returns the icon URL matching the given file info
*
* @param {OC.Files.FileInfo} fileInfo file info
@@ -1318,19 +1375,20 @@
return parseInt(this.$el.find('#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)
- * @param {boolean} force set to true to force changing directory
+ * Changes the current directory and reload the file list.
+ * @param {string} targetDir target directory (non URL encoded)
+ * @param {boolean} [changeUrl=true] if the URL must not be changed (defaults to true)
+ * @param {boolean} [force=false] set to true to force changing directory
+ * @param {string} [fileId] optional file id, if known, to be appended in the URL
*/
- changeDirectory: function(targetDir, changeUrl, force) {
+ changeDirectory: function(targetDir, changeUrl, force, fileId) {
var self = this;
var currentDir = this.getCurrentDirectory();
targetDir = targetDir || '/';
if (!force && currentDir === targetDir) {
return;
}
- this._setCurrentDir(targetDir, changeUrl);
+ this._setCurrentDir(targetDir, changeUrl, fileId);
this.reload().then(function(success){
if (!success) {
self.changeDirectory(currentDir, true);
@@ -1345,8 +1403,9 @@
* 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)
+ * @param {string} [fileId] file id
*/
- _setCurrentDir: function(targetDir, changeUrl) {
+ _setCurrentDir: function(targetDir, changeUrl, fileId) {
targetDir = targetDir.replace(/\\/g, '/');
var previousDir = this.getCurrentDirectory(),
baseDir = OC.basename(targetDir);
@@ -1364,10 +1423,14 @@
this.$el.find('#dir').val(targetDir);
if (changeUrl !== false) {
- this.$el.trigger(jQuery.Event('changeDirectory', {
+ var params = {
dir: targetDir,
previousDir: previousDir
- }));
+ };
+ if (fileId) {
+ params.fileId = fileId;
+ }
+ this.$el.trigger(jQuery.Event('changeDirectory', params));
}
this.breadcrumb.setDirectory(this.getCurrentDirectory());
},
@@ -1377,8 +1440,9 @@
* @param sort sort attribute name
* @param direction sort direction, one of "asc" or "desc"
* @param update true to update the list, false otherwise (default)
+ * @param persist true to save changes in the database (default)
*/
- setSort: function(sort, direction, update) {
+ setSort: function(sort, direction, update, persist) {
var comparator = FileList.Comparators[sort] || FileList.Comparators.name;
this._sort = sort;
this._sortDirection = (direction === 'desc')?'desc':'asc';
@@ -1409,6 +1473,13 @@
this.reload();
}
}
+
+ if (persist) {
+ $.post(OC.generateUrl('/apps/files/api/v1/sorting'), {
+ mode: sort,
+ direction: direction
+ });
+ }
},
/**
@@ -1505,6 +1576,18 @@
result.sort(this._sortComparator);
this.setFiles(result);
+
+ if (this.dirInfo) {
+ var newFileId = this.dirInfo.id;
+ // update fileid in URL
+ var params = {
+ dir: this.getCurrentDirectory()
+ };
+ if (newFileId) {
+ params.fileId = newFileId;
+ }
+ this.$el.trigger(jQuery.Event('afterChangeDirectory', params));
+ }
return true;
},
@@ -2292,12 +2375,14 @@
this.$el.find('#filestable thead th').addClass('hidden');
this.$el.find('#emptycontent').addClass('hidden');
$('#searchresults').addClass('filter-empty');
+ $('#searchresults .emptycontent').addClass('emptycontent-search');
if ( $('#searchresults').length === 0 || $('#searchresults').hasClass('hidden') ) {
this.$el.find('.nofilterresults').removeClass('hidden').
find('p').text(t('files', "No entries in this folder match '{filter}'", {filter:this._filter}, null, {'escape': false}));
}
} else {
$('#searchresults').removeClass('filter-empty');
+ $('#searchresults .emptycontent').removeClass('emptycontent-search');
this.$el.find('#filestable thead th').toggleClass('hidden', this.isEmpty);
if (!this.$el.find('.mask').exists()) {
this.$el.find('#emptycontent').toggleClass('hidden', !this.isEmpty);
@@ -2500,7 +2585,6 @@
}
});
fileUploadStart.on('fileuploadadd', function(e, data) {
- console.log('XXXXXXX');
OC.Upload.log('filelist handle fileuploadadd', e, data);
//finish delete if we are uploading a deleted file
@@ -2543,7 +2627,7 @@
// fetch response from iframe
response = data.result[0].body.innerText;
}
- var result=$.parseJSON(response);
+ var result = JSON.parse(response);
if (typeof result[0] !== 'undefined' && result[0].status === 'success') {
var file = result[0];
@@ -2856,7 +2940,7 @@ $(document).ready(function() {
OCA.Files.FileList.lastAction();
}
});
- $(window).unload(function () {
+ $(window).on('unload', function () {
$(window).trigger('beforeunload');
});
diff --git a/apps/files/js/jquery.iframe-transport.js b/apps/files/js/jquery.iframe-transport.js
deleted file mode 100644
index 5c9df77976b..00000000000
--- a/apps/files/js/jquery.iframe-transport.js
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * jQuery Iframe Transport Plugin 1.7
- * https://github.com/blueimp/jQuery-File-Upload
- *
- * Copyright 2011, Sebastian Tschan
- * https://blueimp.net
- *
- * Licensed under the MIT license:
- * http://www.opensource.org/licenses/MIT
- */
-
-/*jslint unparam: true, nomen: true */
-/*global define, window, document */
-
-(function (factory) {
- 'use strict';
- if (typeof define === 'function' && define.amd) {
- // Register as an anonymous AMD module:
- define(['jquery'], factory);
- } else {
- // Browser globals:
- factory(window.jQuery);
- }
-}(function ($) {
- 'use strict';
-
- // Helper variable to create unique names for the transport iframes:
- var counter = 0;
-
- // The iframe transport accepts three additional options:
- // options.fileInput: a jQuery collection of file input fields
- // options.paramName: the parameter name for the file form data,
- // overrides the name property of the file input field(s),
- // can be a string or an array of strings.
- // options.formData: an array of objects with name and value properties,
- // equivalent to the return data of .serializeArray(), e.g.:
- // [{name: 'a', value: 1}, {name: 'b', value: 2}]
- $.ajaxTransport('iframe', function (options) {
- if (options.async) {
- var form,
- iframe,
- addParamChar;
- return {
- send: function (_, completeCallback) {
- form = $('<form style="display:none;"></form>');
- form.attr('accept-charset', options.formAcceptCharset);
- addParamChar = /\?/.test(options.url) ? '&' : '?';
- // XDomainRequest only supports GET and POST:
- if (options.type === 'DELETE') {
- options.url = options.url + addParamChar + '_method=DELETE';
- options.type = 'POST';
- } else if (options.type === 'PUT') {
- options.url = options.url + addParamChar + '_method=PUT';
- options.type = 'POST';
- } else if (options.type === 'PATCH') {
- options.url = options.url + addParamChar + '_method=PATCH';
- options.type = 'POST';
- }
- // javascript:false as initial iframe src
- // prevents warning popups on HTTPS in IE6.
- // IE versions below IE8 cannot set the name property of
- // elements that have already been added to the DOM,
- // so we set the name along with the iframe HTML markup:
- counter += 1;
- iframe = $(
- '<iframe src="javascript:false;" name="iframe-transport-' +
- counter + '"></iframe>'
- ).bind('load', function () {
- var fileInputClones,
- paramNames = $.isArray(options.paramName) ?
- options.paramName : [options.paramName];
- iframe
- .unbind('load')
- .bind('load', function () {
- var response;
- // Wrap in a try/catch block to catch exceptions thrown
- // when trying to access cross-domain iframe contents:
- try {
- response = iframe.contents();
- // Google Chrome and Firefox do not throw an
- // exception when calling iframe.contents() on
- // cross-domain requests, so we unify the response:
- if (!response.length || !response[0].firstChild) {
- throw new Error();
- }
- } catch (e) {
- response = undefined;
- }
- // The complete callback returns the
- // iframe content document as response object:
- completeCallback(
- 200,
- 'success',
- {'iframe': response}
- );
- // Fix for IE endless progress bar activity bug
- // (happens on form submits to iframe targets):
- $('<iframe src="javascript:false;"></iframe>')
- .appendTo(form);
- window.setTimeout(function () {
- // Removing the form in a setTimeout call
- // allows Chrome's developer tools to display
- // the response result
- form.remove();
- }, 0);
- });
- form
- .prop('target', iframe.prop('name'))
- .prop('action', options.url)
- .prop('method', options.type);
- if (options.formData) {
- $.each(options.formData, function (index, field) {
- $('<input type="hidden"/>')
- .prop('name', field.name)
- .val(field.value)
- .appendTo(form);
- });
- }
- if (options.fileInput && options.fileInput.length &&
- options.type === 'POST') {
- fileInputClones = options.fileInput.clone();
- // Insert a clone for each file input field:
- options.fileInput.after(function (index) {
- return fileInputClones[index];
- });
- if (options.paramName) {
- options.fileInput.each(function (index) {
- $(this).prop(
- 'name',
- paramNames[index] || options.paramName
- );
- });
- }
- // Appending the file input fields to the hidden form
- // removes them from their original location:
- form
- .append(options.fileInput)
- .prop('enctype', 'multipart/form-data')
- // enctype must be set as encoding for IE:
- .prop('encoding', 'multipart/form-data');
- }
- form.submit();
- // Insert the file input fields at their original location
- // by replacing the clones with the originals:
- if (fileInputClones && fileInputClones.length) {
- options.fileInput.each(function (index, input) {
- var clone = $(fileInputClones[index]);
- $(input).prop('name', clone.prop('name'));
- clone.replaceWith(input);
- });
- }
- });
- form.append(iframe).appendTo(document.body);
- },
- abort: function () {
- if (iframe) {
- // javascript:false as iframe src aborts the request
- // and prevents warning popups on HTTPS in IE6.
- // concat is used to avoid the "Script URL" JSLint error:
- iframe
- .unbind('load')
- .prop('src', 'javascript'.concat(':false;'));
- }
- if (form) {
- form.remove();
- }
- }
- };
- }
- });
-
- // The iframe transport returns the iframe content document as response.
- // The following adds converters from iframe to text, json, html, xml
- // and script.
- // Please note that the Content-Type for JSON responses has to be text/plain
- // or text/html, if the browser doesn't include application/json in the
- // Accept header, else IE will show a download dialog.
- // The Content-Type for XML responses on the other hand has to be always
- // application/xml or text/xml, so IE properly parses the XML response.
- // See also
- // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation
- $.ajaxSetup({
- converters: {
- 'iframe text': function (iframe) {
- return iframe && $(iframe[0].body).text();
- },
- 'iframe json': function (iframe) {
- return iframe && $.parseJSON($(iframe[0].body).text());
- },
- 'iframe html': function (iframe) {
- return iframe && $(iframe[0].body).html();
- },
- 'iframe xml': function (iframe) {
- var xmlDoc = iframe && iframe[0];
- return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc :
- $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) ||
- $(xmlDoc.body).html());
- },
- 'iframe script': function (iframe) {
- return iframe && $.globalEval($(iframe[0].body).text());
- }
- }
- });
-
-})); \ No newline at end of file
diff --git a/apps/files/js/mainfileinfodetailview.js b/apps/files/js/mainfileinfodetailview.js
index 1bcb4873c53..c586135b9c7 100644
--- a/apps/files/js/mainfileinfodetailview.js
+++ b/apps/files/js/mainfileinfodetailview.js
@@ -12,7 +12,13 @@
var TEMPLATE =
'<div class="thumbnailContainer"><a href="#" class="thumbnail action-default"><div class="stretcher"/></a></div>' +
'<div class="file-details-container">' +
- '<div class="fileName"><h3 title="{{name}}" class="ellipsis">{{name}}</h3></div>' +
+ '<div class="fileName">' +
+ '<h3 title="{{name}}" class="ellipsis">{{name}}</h3>' +
+ '<a class="permalink" href="{{permalink}}" title="{{permalinkTitle}}">' +
+ '<span class="icon icon-public"></span>' +
+ '<span class="hidden-visually">{{permalinkTitle}}</span>' +
+ '</a>' +
+ '</div>' +
' <div class="file-details ellipsis">' +
' <a href="#" ' +
' class="action action-favorite favorite">' +
@@ -20,6 +26,9 @@
' </a>' +
' {{#if hasSize}}<span class="size" title="{{altSize}}">{{size}}</span>, {{/if}}<span class="date" title="{{altDate}}">{{date}}</span>' +
' </div>' +
+ '</div>' +
+ '<div class="hidden permalink-field">' +
+ '<input type="text" value="{{permalink}}" placeholder="{{permalinkTitle}}" readonly="readonly"/>' +
'</div>';
/**
@@ -50,7 +59,9 @@
events: {
'click a.action-favorite': '_onClickFavorite',
- 'click a.action-default': '_onClickDefaultAction'
+ 'click a.action-default': '_onClickDefaultAction',
+ 'click a.permalink': '_onClickPermalink',
+ 'focus .permalink-field>input': '_onFocusPermalink'
},
template: function(data) {
@@ -72,6 +83,20 @@
}
},
+ _onClickPermalink: function() {
+ var $row = this.$('.permalink-field');
+ $row.toggleClass('hidden');
+ if (!$row.hasClass('hidden')) {
+ $row.find('>input').focus();
+ }
+ // cancel click, user must right-click + copy or middle click
+ return false;
+ },
+
+ _onFocusPermalink: function() {
+ this.$('.permalink-field>input').select();
+ },
+
_onClickFavorite: function(event) {
event.preventDefault();
this._fileActions.triggerAction('Favorite', this.model, this._fileList);
@@ -87,6 +112,11 @@
this.render();
},
+ _makePermalink: function(fileId) {
+ var baseUrl = OC.getProtocol() + '://' + OC.getHost();
+ return baseUrl + OC.generateUrl('/f/{fileId}', {fileId: fileId});
+ },
+
setFileInfo: function(fileInfo) {
if (this.model) {
this.model.off('change', this._onModelChanged, this);
@@ -118,7 +148,9 @@
altDate: OC.Util.formatDate(this.model.get('mtime')),
date: OC.Util.relativeModifiedDate(this.model.get('mtime')),
starAltText: isFavorite ? t('files', 'Favorited') : t('files', 'Favorite'),
- starIcon: OC.imagePath('core', isFavorite ? 'actions/starred' : 'actions/star')
+ starIcon: OC.imagePath('core', isFavorite ? 'actions/starred' : 'actions/star'),
+ permalink: this._makePermalink(this.model.get('id')),
+ permalinkTitle: t('files', 'Local link')
}));
// TODO: we really need OC.Previews