2014-01-30 09:41:04 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014
|
|
|
|
*
|
|
|
|
* This file is licensed under the Affero General Public License version 3
|
|
|
|
* or later.
|
|
|
|
*
|
|
|
|
* See the COPYING-README file.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2014-05-08 20:06:30 +00:00
|
|
|
(function() {
|
|
|
|
|
2015-07-16 13:28:45 +00:00
|
|
|
var TEMPLATE_FILE_ACTION_TRIGGER =
|
2016-02-25 15:43:03 +00:00
|
|
|
'<a class="action action-{{nameLowerCase}}" href="#" data-action="{{name}}">' +
|
2016-02-17 10:04:29 +00:00
|
|
|
'{{#if icon}}' +
|
|
|
|
'<img class="svg" alt="{{altText}}" src="{{icon}}" />' +
|
|
|
|
'{{else}}' +
|
|
|
|
'{{#if iconClass}}<span class="icon {{iconClass}}" />{{/if}}' +
|
|
|
|
'{{#unless hasDisplayName}}<span class="hidden-visually">{{altText}}</span>{{/unless}}' +
|
|
|
|
'{{/if}}' +
|
2015-07-16 13:28:45 +00:00
|
|
|
'{{#if displayName}}<span> {{displayName}}</span>{{/if}}' +
|
|
|
|
'</a>';
|
|
|
|
|
2014-05-20 14:01:34 +00:00
|
|
|
/**
|
|
|
|
* Construct a new FileActions instance
|
2014-06-23 21:56:10 +00:00
|
|
|
* @constructs FileActions
|
|
|
|
* @memberof OCA.Files
|
2014-05-20 14:01:34 +00:00
|
|
|
*/
|
|
|
|
var FileActions = function() {
|
|
|
|
this.initialize();
|
2014-06-23 21:56:10 +00:00
|
|
|
};
|
2015-07-16 13:28:45 +00:00
|
|
|
FileActions.TYPE_DROPDOWN = 0;
|
|
|
|
FileActions.TYPE_INLINE = 1;
|
2014-05-20 14:01:34 +00:00
|
|
|
FileActions.prototype = {
|
2014-06-23 21:56:10 +00:00
|
|
|
/** @lends FileActions.prototype */
|
2014-05-08 20:06:30 +00:00
|
|
|
actions: {},
|
|
|
|
defaults: {},
|
|
|
|
icons: {},
|
2015-08-12 15:30:20 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* @deprecated
|
|
|
|
*/
|
2014-05-08 20:06:30 +00:00
|
|
|
currentFile: null,
|
2014-06-27 11:36:18 +00:00
|
|
|
|
2014-07-09 10:26:33 +00:00
|
|
|
/**
|
|
|
|
* Dummy jquery element, for events
|
|
|
|
*/
|
|
|
|
$el: null,
|
|
|
|
|
2014-06-27 11:36:18 +00:00
|
|
|
/**
|
|
|
|
* List of handlers to be notified whenever a register() or
|
|
|
|
* setDefault() was called.
|
2014-06-23 21:56:10 +00:00
|
|
|
*
|
|
|
|
* @member {Function[]}
|
2014-06-27 11:36:18 +00:00
|
|
|
*/
|
2014-07-09 10:26:33 +00:00
|
|
|
_updateListeners: {},
|
2014-06-27 11:36:18 +00:00
|
|
|
|
2015-07-16 13:28:45 +00:00
|
|
|
_fileActionTriggerTemplate: null,
|
|
|
|
|
2014-06-23 21:56:10 +00:00
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
2014-05-20 14:01:34 +00:00
|
|
|
initialize: function() {
|
|
|
|
this.clear();
|
2014-07-09 10:26:33 +00:00
|
|
|
// abusing jquery for events until we get a real event lib
|
|
|
|
this.$el = $('<div class="dummy-fileactions hidden"></div>');
|
|
|
|
$('body').append(this.$el);
|
2015-07-16 13:28:45 +00:00
|
|
|
|
|
|
|
this._showMenuClosure = _.bind(this._showMenu, this);
|
2014-05-20 14:01:34 +00:00
|
|
|
},
|
2014-06-27 11:36:18 +00:00
|
|
|
|
|
|
|
/**
|
2014-07-09 10:26:33 +00:00
|
|
|
* Adds an event handler
|
2014-06-27 11:36:18 +00:00
|
|
|
*
|
2014-07-09 10:26:33 +00:00
|
|
|
* @param {String} eventName event name
|
2014-06-23 21:56:10 +00:00
|
|
|
* @param {Function} callback
|
2014-06-27 11:36:18 +00:00
|
|
|
*/
|
2014-07-09 10:26:33 +00:00
|
|
|
on: function(eventName, callback) {
|
|
|
|
this.$el.on(eventName, callback);
|
2014-06-27 11:36:18 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2014-07-09 10:26:33 +00:00
|
|
|
* Removes an event handler
|
2014-06-27 11:36:18 +00:00
|
|
|
*
|
2014-07-09 10:26:33 +00:00
|
|
|
* @param {String} eventName event name
|
2014-06-27 11:36:18 +00:00
|
|
|
* @param Function callback
|
|
|
|
*/
|
2014-07-09 10:26:33 +00:00
|
|
|
off: function(eventName, callback) {
|
|
|
|
this.$el.off(eventName, callback);
|
2014-06-27 11:36:18 +00:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
2014-07-09 10:26:33 +00:00
|
|
|
* Notifies the event handlers
|
|
|
|
*
|
|
|
|
* @param {String} eventName event name
|
|
|
|
* @param {Object} data data
|
2014-06-27 11:36:18 +00:00
|
|
|
*/
|
2014-07-09 10:26:33 +00:00
|
|
|
_notifyUpdateListeners: function(eventName, data) {
|
|
|
|
this.$el.trigger(new $.Event(eventName, data));
|
2014-06-27 11:36:18 +00:00
|
|
|
},
|
|
|
|
|
2014-05-20 14:01:34 +00:00
|
|
|
/**
|
|
|
|
* Merges the actions from the given fileActions into
|
|
|
|
* this instance.
|
|
|
|
*
|
2014-06-23 21:56:10 +00:00
|
|
|
* @param {OCA.Files.FileActions} fileActions instance of OCA.Files.FileActions
|
2014-05-20 14:01:34 +00:00
|
|
|
*/
|
|
|
|
merge: function(fileActions) {
|
|
|
|
var self = this;
|
|
|
|
// merge first level to avoid unintended overwriting
|
|
|
|
_.each(fileActions.actions, function(sourceMimeData, mime) {
|
|
|
|
var targetMimeData = self.actions[mime];
|
|
|
|
if (!targetMimeData) {
|
|
|
|
targetMimeData = {};
|
|
|
|
}
|
|
|
|
self.actions[mime] = _.extend(targetMimeData, sourceMimeData);
|
|
|
|
});
|
|
|
|
|
|
|
|
this.defaults = _.extend(this.defaults, fileActions.defaults);
|
|
|
|
this.icons = _.extend(this.icons, fileActions.icons);
|
|
|
|
},
|
2014-07-09 10:26:33 +00:00
|
|
|
/**
|
|
|
|
* @deprecated use #registerAction() instead
|
|
|
|
*/
|
|
|
|
register: function(mime, name, permissions, icon, action, displayName) {
|
|
|
|
return this.registerAction({
|
|
|
|
name: name,
|
|
|
|
mime: mime,
|
|
|
|
permissions: permissions,
|
|
|
|
icon: icon,
|
|
|
|
actionHandler: action,
|
2014-11-24 15:26:50 +00:00
|
|
|
displayName: displayName || name
|
2014-07-09 10:26:33 +00:00
|
|
|
});
|
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
2014-07-09 10:26:33 +00:00
|
|
|
/**
|
|
|
|
* Register action
|
|
|
|
*
|
2014-11-24 15:26:50 +00:00
|
|
|
* @param {OCA.Files.FileAction} action object
|
2014-07-09 10:26:33 +00:00
|
|
|
*/
|
|
|
|
registerAction: function (action) {
|
|
|
|
var mime = action.mime;
|
|
|
|
var name = action.name;
|
2014-11-24 15:26:50 +00:00
|
|
|
var actionSpec = {
|
|
|
|
action: action.actionHandler,
|
|
|
|
name: name,
|
|
|
|
displayName: action.displayName,
|
|
|
|
mime: mime,
|
2015-09-28 09:19:49 +00:00
|
|
|
order: action.order || 0,
|
2014-11-24 15:26:50 +00:00
|
|
|
icon: action.icon,
|
2016-02-17 10:04:29 +00:00
|
|
|
iconClass: action.iconClass,
|
2015-07-16 13:28:45 +00:00
|
|
|
permissions: action.permissions,
|
2015-10-03 13:47:20 +00:00
|
|
|
type: action.type || FileActions.TYPE_DROPDOWN,
|
|
|
|
altText: action.altText || ''
|
2014-11-24 15:26:50 +00:00
|
|
|
};
|
|
|
|
if (_.isUndefined(action.displayName)) {
|
|
|
|
actionSpec.displayName = t('files', name);
|
|
|
|
}
|
|
|
|
if (_.isFunction(action.render)) {
|
|
|
|
actionSpec.render = action.render;
|
|
|
|
}
|
2014-05-08 20:06:30 +00:00
|
|
|
if (!this.actions[mime]) {
|
|
|
|
this.actions[mime] = {};
|
2011-06-04 18:16:44 +00:00
|
|
|
}
|
2014-11-24 15:26:50 +00:00
|
|
|
this.actions[mime][name] = actionSpec;
|
2014-07-09 10:26:33 +00:00
|
|
|
this.icons[name] = action.icon;
|
|
|
|
this._notifyUpdateListeners('registerAction', {action: action});
|
2014-05-08 20:06:30 +00:00
|
|
|
},
|
2014-06-23 21:56:10 +00:00
|
|
|
/**
|
|
|
|
* Clears all registered file actions.
|
|
|
|
*/
|
2014-05-08 20:06:30 +00:00
|
|
|
clear: function() {
|
|
|
|
this.actions = {};
|
|
|
|
this.defaults = {};
|
|
|
|
this.icons = {};
|
|
|
|
this.currentFile = null;
|
2014-06-27 11:36:18 +00:00
|
|
|
this._updateListeners = [];
|
2014-05-08 20:06:30 +00:00
|
|
|
},
|
2014-06-23 21:56:10 +00:00
|
|
|
/**
|
|
|
|
* Sets the default action for a given mime type.
|
|
|
|
*
|
|
|
|
* @param {String} mime mime type
|
|
|
|
* @param {String} name action name
|
|
|
|
*/
|
2014-05-08 20:06:30 +00:00
|
|
|
setDefault: function (mime, name) {
|
|
|
|
this.defaults[mime] = name;
|
2014-07-09 10:26:33 +00:00
|
|
|
this._notifyUpdateListeners('setDefault', {defaultAction: {mime: mime, name: name}});
|
2014-05-08 20:06:30 +00:00
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns a map of file actions handlers matching the given conditions
|
|
|
|
*
|
|
|
|
* @param {string} mime mime type
|
|
|
|
* @param {string} type "dir" or "file"
|
|
|
|
* @param {int} permissions permissions
|
|
|
|
*
|
|
|
|
* @return {Object.<string,OCA.Files.FileActions~actionHandler>} map of action name to action spec
|
|
|
|
*/
|
2014-05-08 20:06:30 +00:00
|
|
|
get: function (mime, type, permissions) {
|
|
|
|
var actions = this.getActions(mime, type, permissions);
|
|
|
|
var filteredActions = {};
|
|
|
|
$.each(actions, function (name, action) {
|
|
|
|
filteredActions[name] = action.action;
|
|
|
|
});
|
|
|
|
return filteredActions;
|
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns an array of file actions matching the given conditions
|
|
|
|
*
|
|
|
|
* @param {string} mime mime type
|
|
|
|
* @param {string} type "dir" or "file"
|
|
|
|
* @param {int} permissions permissions
|
|
|
|
*
|
|
|
|
* @return {Array.<OCA.Files.FileAction>} array of action specs
|
|
|
|
*/
|
2014-05-08 20:06:30 +00:00
|
|
|
getActions: function (mime, type, permissions) {
|
|
|
|
var actions = {};
|
|
|
|
if (this.actions.all) {
|
|
|
|
actions = $.extend(actions, this.actions.all);
|
2012-07-25 20:33:08 +00:00
|
|
|
}
|
2014-05-08 20:06:30 +00:00
|
|
|
if (type) {//type is 'dir' or 'file'
|
|
|
|
if (this.actions[type]) {
|
|
|
|
actions = $.extend(actions, this.actions[type]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (mime) {
|
|
|
|
var mimePart = mime.substr(0, mime.indexOf('/'));
|
|
|
|
if (this.actions[mimePart]) {
|
|
|
|
actions = $.extend(actions, this.actions[mimePart]);
|
|
|
|
}
|
|
|
|
if (this.actions[mime]) {
|
|
|
|
actions = $.extend(actions, this.actions[mime]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var filteredActions = {};
|
|
|
|
$.each(actions, function (name, action) {
|
2017-11-02 13:55:58 +00:00
|
|
|
if ((action.permissions === OC.PERMISSION_NONE) || (action.permissions & permissions)) {
|
2014-05-08 20:06:30 +00:00
|
|
|
filteredActions[name] = action;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
return filteredActions;
|
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the default file action handler for the given conditions
|
|
|
|
*
|
|
|
|
* @param {string} mime mime type
|
|
|
|
* @param {string} type "dir" or "file"
|
|
|
|
* @param {int} permissions permissions
|
|
|
|
*
|
|
|
|
* @return {OCA.Files.FileActions~actionHandler} action handler
|
|
|
|
*
|
|
|
|
* @deprecated use getDefaultFileAction instead
|
|
|
|
*/
|
2014-05-08 20:06:30 +00:00
|
|
|
getDefault: function (mime, type, permissions) {
|
2015-07-16 13:28:45 +00:00
|
|
|
var defaultActionSpec = this.getDefaultFileAction(mime, type, permissions);
|
|
|
|
if (defaultActionSpec) {
|
|
|
|
return defaultActionSpec.action;
|
|
|
|
}
|
|
|
|
return undefined;
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the default file action handler for the given conditions
|
|
|
|
*
|
|
|
|
* @param {string} mime mime type
|
|
|
|
* @param {string} type "dir" or "file"
|
|
|
|
* @param {int} permissions permissions
|
|
|
|
*
|
|
|
|
* @return {OCA.Files.FileActions~actionHandler} action handler
|
|
|
|
* @since 8.2
|
|
|
|
*/
|
|
|
|
getDefaultFileAction: function(mime, type, permissions) {
|
2014-05-08 20:06:30 +00:00
|
|
|
var mimePart;
|
|
|
|
if (mime) {
|
|
|
|
mimePart = mime.substr(0, mime.indexOf('/'));
|
|
|
|
}
|
|
|
|
var name = false;
|
|
|
|
if (mime && this.defaults[mime]) {
|
|
|
|
name = this.defaults[mime];
|
|
|
|
} else if (mime && this.defaults[mimePart]) {
|
|
|
|
name = this.defaults[mimePart];
|
|
|
|
} else if (type && this.defaults[type]) {
|
|
|
|
name = this.defaults[type];
|
|
|
|
} else {
|
|
|
|
name = this.defaults.all;
|
|
|
|
}
|
2015-07-16 13:28:45 +00:00
|
|
|
var actions = this.getActions(mime, type, permissions);
|
2014-05-08 20:06:30 +00:00
|
|
|
return actions[name];
|
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
/**
|
|
|
|
* Default function to render actions
|
|
|
|
*
|
|
|
|
* @param {OCA.Files.FileAction} actionSpec file action spec
|
|
|
|
* @param {boolean} isDefault true if the action is a default one,
|
|
|
|
* false otherwise
|
|
|
|
* @param {OCA.Files.FileActionContext} context action context
|
|
|
|
*/
|
|
|
|
_defaultRenderAction: function(actionSpec, isDefault, context) {
|
2015-07-16 13:28:45 +00:00
|
|
|
if (!isDefault) {
|
|
|
|
var params = {
|
|
|
|
name: actionSpec.name,
|
|
|
|
nameLowerCase: actionSpec.name.toLowerCase(),
|
|
|
|
displayName: actionSpec.displayName,
|
|
|
|
icon: actionSpec.icon,
|
2016-02-17 10:04:29 +00:00
|
|
|
iconClass: actionSpec.iconClass,
|
2015-07-16 13:28:45 +00:00
|
|
|
altText: actionSpec.altText,
|
2016-02-17 10:04:29 +00:00
|
|
|
hasDisplayName: !!actionSpec.displayName
|
2015-07-16 13:28:45 +00:00
|
|
|
};
|
|
|
|
if (_.isFunction(actionSpec.icon)) {
|
2016-02-17 10:04:29 +00:00
|
|
|
params.icon = actionSpec.icon(context.$file.attr('data-file'), context);
|
|
|
|
}
|
|
|
|
if (_.isFunction(actionSpec.iconClass)) {
|
|
|
|
params.iconClass = actionSpec.iconClass(context.$file.attr('data-file'), context);
|
2015-07-16 13:28:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
var $actionLink = this._makeActionLink(params, context);
|
2014-11-24 15:26:50 +00:00
|
|
|
context.$file.find('a.name>span.fileactions').append($actionLink);
|
2015-08-10 13:57:21 +00:00
|
|
|
$actionLink.addClass('permanent');
|
2014-11-24 15:26:50 +00:00
|
|
|
return $actionLink;
|
|
|
|
}
|
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
/**
|
|
|
|
* Renders the action link element
|
|
|
|
*
|
2015-07-16 13:28:45 +00:00
|
|
|
* @param {Object} params action params
|
2014-11-24 15:26:50 +00:00
|
|
|
*/
|
2015-07-16 13:28:45 +00:00
|
|
|
_makeActionLink: function(params) {
|
|
|
|
if (!this._fileActionTriggerTemplate) {
|
|
|
|
this._fileActionTriggerTemplate = Handlebars.compile(TEMPLATE_FILE_ACTION_TRIGGER);
|
2014-11-24 15:26:50 +00:00
|
|
|
}
|
|
|
|
|
2015-07-16 13:28:45 +00:00
|
|
|
return $(this._fileActionTriggerTemplate(params));
|
2014-11-24 15:26:50 +00:00
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
/**
|
2015-07-16 13:28:45 +00:00
|
|
|
* Displays the file actions dropdown menu
|
2014-11-24 15:26:50 +00:00
|
|
|
*
|
2015-07-16 13:28:45 +00:00
|
|
|
* @param {string} fileName file name
|
|
|
|
* @param {OCA.Files.FileActionContext} context rendering context
|
2014-11-24 15:26:50 +00:00
|
|
|
*/
|
2015-07-16 13:28:45 +00:00
|
|
|
_showMenu: function(fileName, context) {
|
2015-08-11 09:35:46 +00:00
|
|
|
var menu;
|
|
|
|
var $trigger = context.$file.closest('tr').find('.fileactions .action-menu');
|
|
|
|
$trigger.addClass('open');
|
|
|
|
|
|
|
|
menu = new OCA.Files.FileActionsMenu();
|
2015-08-12 15:30:20 +00:00
|
|
|
|
|
|
|
context.$file.find('td.filename').append(menu.$el);
|
|
|
|
|
2015-08-11 09:35:46 +00:00
|
|
|
menu.$el.on('afterHide', function() {
|
|
|
|
context.$file.removeClass('mouseOver');
|
|
|
|
$trigger.removeClass('open');
|
|
|
|
menu.remove();
|
|
|
|
});
|
|
|
|
|
|
|
|
context.$file.addClass('mouseOver');
|
|
|
|
menu.show(context);
|
2014-11-24 15:26:50 +00:00
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
/**
|
2015-07-16 13:28:45 +00:00
|
|
|
* Renders the menu trigger on the given file list row
|
2016-10-17 16:52:25 +00:00
|
|
|
*
|
2015-07-16 13:28:45 +00:00
|
|
|
* @param {Object} $tr file list row element
|
|
|
|
* @param {OCA.Files.FileActionContext} context rendering context
|
2014-11-24 15:26:50 +00:00
|
|
|
*/
|
2015-07-16 13:28:45 +00:00
|
|
|
_renderMenuTrigger: function($tr, context) {
|
|
|
|
// remove previous
|
|
|
|
$tr.find('.action-menu').remove();
|
2015-08-04 16:25:35 +00:00
|
|
|
|
|
|
|
var $el = this._renderInlineAction({
|
2015-07-16 13:28:45 +00:00
|
|
|
name: 'menu',
|
|
|
|
displayName: '',
|
2016-02-17 10:04:29 +00:00
|
|
|
iconClass: 'icon-more',
|
2015-07-16 13:28:45 +00:00
|
|
|
altText: t('files', 'Actions'),
|
|
|
|
action: this._showMenuClosure
|
2015-08-04 16:25:35 +00:00
|
|
|
}, false, context);
|
|
|
|
|
|
|
|
$el.addClass('permanent');
|
2014-11-24 15:26:50 +00:00
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
/**
|
|
|
|
* Renders the action element by calling actionSpec.render() and
|
|
|
|
* registers the click event to process the action.
|
|
|
|
*
|
|
|
|
* @param {OCA.Files.FileAction} actionSpec file action to render
|
|
|
|
* @param {boolean} isDefault true if the action is a default action,
|
|
|
|
* false otherwise
|
2015-07-16 13:28:45 +00:00
|
|
|
* @param {OCA.Files.FileActionContext} context rendering context
|
2014-11-24 15:26:50 +00:00
|
|
|
*/
|
2015-07-16 13:28:45 +00:00
|
|
|
_renderInlineAction: function(actionSpec, isDefault, context) {
|
|
|
|
var renderFunc = actionSpec.render || _.bind(this._defaultRenderAction, this);
|
|
|
|
var $actionEl = renderFunc(actionSpec, isDefault, context);
|
2014-11-24 15:26:50 +00:00
|
|
|
if (!$actionEl || !$actionEl.length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
$actionEl.on(
|
|
|
|
'click', {
|
|
|
|
a: null
|
|
|
|
},
|
|
|
|
function(event) {
|
2015-08-11 09:35:46 +00:00
|
|
|
event.stopPropagation();
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
if ($actionEl.hasClass('open')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
var $file = $(event.target).closest('tr');
|
2015-07-16 13:28:45 +00:00
|
|
|
if ($file.hasClass('busy')) {
|
|
|
|
return;
|
|
|
|
}
|
2014-11-24 15:26:50 +00:00
|
|
|
var currentFile = $file.find('td.filename');
|
|
|
|
var fileName = $file.attr('data-file');
|
|
|
|
|
|
|
|
context.fileActions.currentFile = currentFile;
|
|
|
|
// also set on global object for legacy apps
|
|
|
|
window.FileActions.currentFile = currentFile;
|
|
|
|
|
2015-08-12 15:30:20 +00:00
|
|
|
var callContext = _.extend({}, context);
|
|
|
|
|
|
|
|
if (!context.dir && context.fileList) {
|
|
|
|
callContext.dir = $file.attr('data-path') || context.fileList.getCurrentDirectory();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!context.fileInfoModel && context.fileList) {
|
|
|
|
callContext.fileInfoModel = context.fileList.getModelForFile(fileName);
|
|
|
|
if (!callContext.fileInfoModel) {
|
|
|
|
console.warn('No file info model found for file "' + fileName + '"');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
actionSpec.action(
|
|
|
|
fileName,
|
2015-08-12 15:30:20 +00:00
|
|
|
callContext
|
2014-11-24 15:26:50 +00:00
|
|
|
);
|
|
|
|
}
|
|
|
|
);
|
2015-08-07 12:00:44 +00:00
|
|
|
$actionEl.tooltip({placement:'top'});
|
2014-11-24 15:26:50 +00:00
|
|
|
return $actionEl;
|
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
|
2015-08-12 15:30:20 +00:00
|
|
|
/**
|
|
|
|
* Trigger the given action on the given file.
|
|
|
|
*
|
|
|
|
* @param {string} actionName action name
|
|
|
|
* @param {OCA.Files.FileInfoModel} fileInfoModel file info model
|
|
|
|
* @param {OCA.Files.FileList} [fileList] file list, for compatibility with older action handlers [DEPRECATED]
|
|
|
|
*
|
|
|
|
* @return {boolean} true if the action handler was called, false otherwise
|
|
|
|
*
|
|
|
|
* @since 8.2
|
|
|
|
*/
|
|
|
|
triggerAction: function(actionName, fileInfoModel, fileList) {
|
|
|
|
var actionFunc;
|
|
|
|
var actions = this.get(
|
|
|
|
fileInfoModel.get('mimetype'),
|
|
|
|
fileInfoModel.isDirectory() ? 'dir' : 'file',
|
|
|
|
fileInfoModel.get('permissions')
|
|
|
|
);
|
|
|
|
|
|
|
|
if (actionName) {
|
|
|
|
actionFunc = actions[actionName];
|
|
|
|
} else {
|
|
|
|
actionFunc = this.getDefault(
|
|
|
|
fileInfoModel.get('mimetype'),
|
|
|
|
fileInfoModel.isDirectory() ? 'dir' : 'file',
|
|
|
|
fileInfoModel.get('permissions')
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!actionFunc) {
|
|
|
|
actionFunc = actions['Download'];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!actionFunc) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
var context = {
|
|
|
|
fileActions: this,
|
|
|
|
fileInfoModel: fileInfoModel,
|
|
|
|
dir: fileInfoModel.get('path')
|
|
|
|
};
|
|
|
|
|
|
|
|
var fileName = fileInfoModel.get('name');
|
|
|
|
this.currentFile = fileName;
|
|
|
|
// also set on global object for legacy apps
|
|
|
|
window.FileActions.currentFile = fileName;
|
|
|
|
|
|
|
|
if (fileList) {
|
|
|
|
// compatibility with action handlers that expect these
|
|
|
|
context.fileList = fileList;
|
|
|
|
context.$file = fileList.findFileEl(fileName);
|
|
|
|
}
|
|
|
|
|
|
|
|
actionFunc(fileName, context);
|
|
|
|
},
|
|
|
|
|
2014-05-08 20:06:30 +00:00
|
|
|
/**
|
|
|
|
* Display file actions for the given element
|
|
|
|
* @param parent "td" element of the file for which to display actions
|
|
|
|
* @param triggerEvent if true, triggers the fileActionsReady on the file
|
|
|
|
* list afterwards (false by default)
|
2014-05-19 11:18:44 +00:00
|
|
|
* @param fileList OCA.Files.FileList instance on which the action is
|
|
|
|
* done, defaults to OCA.Files.App.fileList
|
2014-05-08 20:06:30 +00:00
|
|
|
*/
|
2014-05-19 11:18:44 +00:00
|
|
|
display: function (parent, triggerEvent, fileList) {
|
|
|
|
if (!fileList) {
|
|
|
|
console.warn('FileActions.display() MUST be called with a OCA.Files.FileList instance');
|
2014-06-27 11:36:18 +00:00
|
|
|
return;
|
2014-05-19 11:18:44 +00:00
|
|
|
}
|
2014-05-08 20:06:30 +00:00
|
|
|
this.currentFile = parent;
|
|
|
|
var self = this;
|
2014-11-24 15:26:50 +00:00
|
|
|
var $tr = parent.closest('tr');
|
|
|
|
var actions = this.getActions(
|
|
|
|
this.getCurrentMimeType(),
|
|
|
|
this.getCurrentType(),
|
|
|
|
this.getCurrentPermissions()
|
|
|
|
);
|
2014-05-08 20:06:30 +00:00
|
|
|
var nameLinks;
|
2014-07-01 19:32:04 +00:00
|
|
|
if ($tr.data('renaming')) {
|
2014-05-08 20:06:30 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
// recreate fileactions container
|
2014-05-08 20:06:30 +00:00
|
|
|
nameLinks = parent.children('a.name');
|
|
|
|
nameLinks.find('.fileactions, .nametext .action').remove();
|
|
|
|
nameLinks.append('<span class="fileactions" />');
|
2015-08-05 10:48:42 +00:00
|
|
|
var defaultAction = this.getDefaultFileAction(
|
2014-11-24 15:26:50 +00:00
|
|
|
this.getCurrentMimeType(),
|
|
|
|
this.getCurrentType(),
|
|
|
|
this.getCurrentPermissions()
|
|
|
|
);
|
2013-01-14 19:30:39 +00:00
|
|
|
|
2015-07-16 13:28:45 +00:00
|
|
|
var context = {
|
|
|
|
$file: $tr,
|
|
|
|
fileActions: this,
|
|
|
|
fileList: fileList
|
|
|
|
};
|
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
$.each(actions, function (name, actionSpec) {
|
2015-07-16 13:28:45 +00:00
|
|
|
if (actionSpec.type === FileActions.TYPE_INLINE) {
|
|
|
|
self._renderInlineAction(
|
2014-11-24 15:26:50 +00:00
|
|
|
actionSpec,
|
2015-08-05 10:48:42 +00:00
|
|
|
defaultAction && actionSpec.name === defaultAction.name,
|
2015-07-16 13:28:45 +00:00
|
|
|
context
|
2014-11-24 15:26:50 +00:00
|
|
|
);
|
2014-05-08 20:06:30 +00:00
|
|
|
}
|
|
|
|
});
|
2015-07-16 13:28:45 +00:00
|
|
|
|
|
|
|
this._renderMenuTrigger($tr, context);
|
2013-01-14 19:30:39 +00:00
|
|
|
|
2014-05-08 20:06:30 +00:00
|
|
|
if (triggerEvent){
|
2014-07-01 19:32:04 +00:00
|
|
|
fileList.$fileList.trigger(jQuery.Event("fileActionsReady", {fileList: fileList, $files: $tr}));
|
2014-05-08 20:06:30 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
getCurrentFile: function () {
|
|
|
|
return this.currentFile.parent().attr('data-file');
|
|
|
|
},
|
|
|
|
getCurrentMimeType: function () {
|
|
|
|
return this.currentFile.parent().attr('data-mime');
|
|
|
|
},
|
|
|
|
getCurrentType: function () {
|
|
|
|
return this.currentFile.parent().attr('data-type');
|
|
|
|
},
|
|
|
|
getCurrentPermissions: function () {
|
|
|
|
return this.currentFile.parent().data('permissions');
|
|
|
|
},
|
2013-02-11 15:09:04 +00:00
|
|
|
|
2014-05-08 20:06:30 +00:00
|
|
|
/**
|
|
|
|
* Register the actions that are used by default for the files app.
|
|
|
|
*/
|
2014-05-19 13:20:44 +00:00
|
|
|
registerDefaultActions: function() {
|
2014-11-24 15:26:50 +00:00
|
|
|
this.registerAction({
|
2015-07-16 13:28:45 +00:00
|
|
|
name: 'Download',
|
|
|
|
displayName: t('files', 'Download'),
|
2015-09-28 09:19:49 +00:00
|
|
|
order: -20,
|
2014-11-24 15:26:50 +00:00
|
|
|
mime: 'all',
|
2015-04-23 12:33:19 +00:00
|
|
|
permissions: OC.PERMISSION_READ,
|
2016-02-17 10:04:29 +00:00
|
|
|
iconClass: 'icon-download',
|
2015-07-16 13:28:45 +00:00
|
|
|
actionHandler: function (filename, context) {
|
|
|
|
var dir = context.dir || context.fileList.getCurrentDirectory();
|
2015-07-13 15:38:13 +00:00
|
|
|
var isDir = context.$file.attr('data-type') === 'dir';
|
|
|
|
var url = context.fileList.getDownloadUrl(filename, dir, isDir);
|
2015-07-16 13:28:45 +00:00
|
|
|
|
|
|
|
var downloadFileaction = $(context.$file).find('.fileactions .action-download');
|
|
|
|
|
|
|
|
// don't allow a second click on the download action
|
|
|
|
if(downloadFileaction.hasClass('disabled')) {
|
2015-04-23 12:33:19 +00:00
|
|
|
return;
|
|
|
|
}
|
2015-07-16 13:28:45 +00:00
|
|
|
|
|
|
|
if (url) {
|
|
|
|
var disableLoadingState = function() {
|
|
|
|
context.fileList.showFileBusyState(filename, false);
|
|
|
|
};
|
|
|
|
|
2015-10-30 13:37:19 +00:00
|
|
|
context.fileList.showFileBusyState(filename, true);
|
2015-07-16 13:28:45 +00:00
|
|
|
OCA.Files.Files.handleDownload(url, disableLoadingState);
|
|
|
|
}
|
2014-11-24 15:26:50 +00:00
|
|
|
}
|
2014-05-08 20:06:30 +00:00
|
|
|
});
|
2014-03-17 19:15:10 +00:00
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
this.registerAction({
|
|
|
|
name: 'Rename',
|
2015-09-22 12:52:52 +00:00
|
|
|
displayName: t('files', 'Rename'),
|
2014-11-24 15:26:50 +00:00
|
|
|
mime: 'all',
|
2015-09-28 09:19:49 +00:00
|
|
|
order: -30,
|
2014-11-24 15:26:50 +00:00
|
|
|
permissions: OC.PERMISSION_UPDATE,
|
2016-02-17 10:04:29 +00:00
|
|
|
iconClass: 'icon-rename',
|
2014-11-24 15:26:50 +00:00
|
|
|
actionHandler: function (filename, context) {
|
|
|
|
context.fileList.rename(filename);
|
|
|
|
}
|
2014-05-08 20:06:30 +00:00
|
|
|
});
|
2013-01-14 19:30:39 +00:00
|
|
|
|
2016-10-14 14:23:11 +00:00
|
|
|
this.registerAction({
|
2017-08-28 08:56:21 +00:00
|
|
|
name: 'MoveCopy',
|
|
|
|
displayName: t('files', 'Move or copy'),
|
2016-10-14 14:23:11 +00:00
|
|
|
mime: 'all',
|
|
|
|
order: -25,
|
|
|
|
permissions: OC.PERMISSION_UPDATE,
|
2016-10-17 16:52:25 +00:00
|
|
|
iconClass: 'icon-external',
|
2016-10-14 14:23:11 +00:00
|
|
|
actionHandler: function (filename, context) {
|
2017-08-27 15:39:22 +00:00
|
|
|
OC.dialogs.filepicker(t('files', 'Target folder'), function(targetPath, type) {
|
|
|
|
if (type === OC.dialogs.FILEPICKER_TYPE_COPY) {
|
|
|
|
context.fileList.copy(filename, targetPath);
|
|
|
|
}
|
|
|
|
if (type === OC.dialogs.FILEPICKER_TYPE_MOVE) {
|
|
|
|
context.fileList.move(filename, targetPath);
|
|
|
|
}
|
|
|
|
}, false, "httpd/unix-directory", true, OC.dialogs.FILEPICKER_TYPE_COPY_MOVE);
|
2017-08-27 13:28:26 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2014-05-19 13:20:44 +00:00
|
|
|
this.register('dir', 'Open', OC.PERMISSION_READ, '', function (filename, context) {
|
2014-07-04 10:53:03 +00:00
|
|
|
var dir = context.$file.attr('data-path') || context.fileList.getCurrentDirectory();
|
2016-05-04 09:17:53 +00:00
|
|
|
context.fileList.changeDirectory(OC.joinPaths(dir, filename), true, false, parseInt(context.$file.attr('data-id'), 10));
|
2014-05-08 20:06:30 +00:00
|
|
|
});
|
|
|
|
|
2015-07-16 13:28:45 +00:00
|
|
|
this.registerAction({
|
|
|
|
name: 'Delete',
|
2015-12-11 14:14:30 +00:00
|
|
|
displayName: function(context) {
|
|
|
|
var mountType = context.$file.attr('data-mounttype');
|
|
|
|
var deleteTitle = t('files', 'Delete');
|
|
|
|
if (mountType === 'external-root') {
|
|
|
|
deleteTitle = t('files', 'Disconnect storage');
|
|
|
|
} else if (mountType === 'shared-root') {
|
|
|
|
deleteTitle = t('files', 'Unshare');
|
|
|
|
}
|
|
|
|
return deleteTitle;
|
|
|
|
},
|
2015-07-16 13:28:45 +00:00
|
|
|
mime: 'all',
|
2015-09-28 09:19:49 +00:00
|
|
|
order: 1000,
|
2015-07-16 13:28:45 +00:00
|
|
|
// permission is READ because we show a hint instead if there is no permission
|
2015-08-18 09:35:40 +00:00
|
|
|
permissions: OC.PERMISSION_DELETE,
|
2016-02-17 10:04:29 +00:00
|
|
|
iconClass: 'icon-delete',
|
2015-07-16 13:28:45 +00:00
|
|
|
actionHandler: function(fileName, context) {
|
|
|
|
// if there is no permission to delete do nothing
|
|
|
|
if((context.$file.data('permissions') & OC.PERMISSION_DELETE) === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
context.fileList.do_delete(fileName, context.dir);
|
|
|
|
$('.tipsy').remove();
|
2015-06-26 08:26:01 +00:00
|
|
|
}
|
2015-07-16 13:28:45 +00:00
|
|
|
});
|
2015-06-26 08:26:01 +00:00
|
|
|
|
2015-07-16 13:28:45 +00:00
|
|
|
this.setDefault('dir', 'Open');
|
2013-10-17 09:59:13 +00:00
|
|
|
}
|
2014-05-08 20:06:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
OCA.Files.FileActions = FileActions;
|
|
|
|
|
2015-07-22 08:35:15 +00:00
|
|
|
/**
|
|
|
|
* Replaces the download icon with a loading spinner and vice versa
|
|
|
|
* - also adds the class disabled to the passed in element
|
|
|
|
*
|
2016-03-04 09:48:08 +00:00
|
|
|
* @param {jQuery} $downloadButtonElement download fileaction
|
2015-07-22 08:35:15 +00:00
|
|
|
* @param {boolean} showIt whether to show the spinner(true) or to hide it(false)
|
|
|
|
*/
|
2016-03-04 09:48:08 +00:00
|
|
|
OCA.Files.FileActions.updateFileActionSpinner = function($downloadButtonElement, showIt) {
|
|
|
|
var $icon = $downloadButtonElement.find('.icon');
|
|
|
|
if (showIt) {
|
2016-05-24 23:11:07 +00:00
|
|
|
var $loadingIcon = $('<span class="icon icon-loading-small"></span>');
|
2016-03-04 09:48:08 +00:00
|
|
|
$icon.after($loadingIcon);
|
|
|
|
$icon.addClass('hidden');
|
2015-07-22 08:35:15 +00:00
|
|
|
} else {
|
2016-05-24 23:11:07 +00:00
|
|
|
$downloadButtonElement.find('.icon-loading-small').remove();
|
2016-03-04 09:48:08 +00:00
|
|
|
$downloadButtonElement.find('.icon').removeClass('hidden');
|
2015-07-22 08:35:15 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-11-24 15:26:50 +00:00
|
|
|
/**
|
|
|
|
* File action attributes.
|
|
|
|
*
|
|
|
|
* @todo make this a real class in the future
|
|
|
|
* @typedef {Object} OCA.Files.FileAction
|
|
|
|
*
|
|
|
|
* @property {String} name identifier of the action
|
2015-12-11 14:14:30 +00:00
|
|
|
* @property {(String|OCA.Files.FileActions~displayNameFunction)} displayName
|
|
|
|
* display name string for the action, or function that returns the display name.
|
|
|
|
* Defaults to the name given in name property
|
2014-11-24 15:26:50 +00:00
|
|
|
* @property {String} mime mime type
|
|
|
|
* @property {int} permissions permissions
|
2016-02-17 10:04:29 +00:00
|
|
|
* @property {(Function|String)} icon icon path to the icon or function that returns it (deprecated, use iconClass instead)
|
2017-09-26 23:50:24 +00:00
|
|
|
* @property {(String|OCA.Files.FileActions~iconClassFunction)} iconClass class name of the icon (recommended for theming)
|
2014-11-24 15:26:50 +00:00
|
|
|
* @property {OCA.Files.FileActions~renderActionFunction} [render] optional rendering function
|
|
|
|
* @property {OCA.Files.FileActions~actionHandler} actionHandler action handler function
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* File action context attributes.
|
|
|
|
*
|
|
|
|
* @typedef {Object} OCA.Files.FileActionContext
|
|
|
|
*
|
|
|
|
* @property {Object} $file jQuery file row element
|
|
|
|
* @property {OCA.Files.FileActions} fileActions file actions object
|
|
|
|
* @property {OCA.Files.FileList} fileList file list object
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Render function for actions.
|
|
|
|
* The function must render a link element somewhere in the DOM
|
|
|
|
* and return it. The function should NOT register the event handler
|
|
|
|
* as this will be done after the link was returned.
|
|
|
|
*
|
|
|
|
* @callback OCA.Files.FileActions~renderActionFunction
|
|
|
|
* @param {OCA.Files.FileAction} actionSpec action definition
|
|
|
|
* @param {Object} $row row container
|
|
|
|
* @param {boolean} isDefault true if the action is the default one,
|
|
|
|
* false otherwise
|
|
|
|
* @return {Object} jQuery link object
|
|
|
|
*/
|
|
|
|
|
2015-12-11 14:14:30 +00:00
|
|
|
/**
|
|
|
|
* Display name function for actions.
|
|
|
|
* The function returns the display name of the action using
|
|
|
|
* the given context information..
|
|
|
|
*
|
|
|
|
* @callback OCA.Files.FileActions~displayNameFunction
|
|
|
|
* @param {OCA.Files.FileActionContext} context action context
|
|
|
|
* @return {String} display name
|
|
|
|
*/
|
|
|
|
|
2017-09-26 23:50:24 +00:00
|
|
|
/**
|
|
|
|
* Icon class function for actions.
|
|
|
|
* The function returns the icon class of the action using
|
|
|
|
* the given context information.
|
|
|
|
*
|
|
|
|
* @callback OCA.Files.FileActions~iconClassFunction
|
|
|
|
* @param {String} fileName name of the file on which the action must be performed
|
|
|
|
* @param {OCA.Files.FileActionContext} context action context
|
|
|
|
* @return {String} icon class
|
|
|
|
*/
|
|
|
|
|
2014-06-23 21:56:10 +00:00
|
|
|
/**
|
|
|
|
* Action handler function for file actions
|
|
|
|
*
|
|
|
|
* @callback OCA.Files.FileActions~actionHandler
|
2015-08-12 15:30:20 +00:00
|
|
|
* @param {String} fileName name of the file on which the action must be performed
|
2014-06-23 21:56:10 +00:00
|
|
|
* @param context context
|
|
|
|
* @param {String} context.dir directory of the file
|
2015-08-12 15:30:20 +00:00
|
|
|
* @param {OCA.Files.FileInfoModel} fileInfoModel file info model
|
|
|
|
* @param {Object} [context.$file] jQuery element of the file [DEPRECATED]
|
|
|
|
* @param {OCA.Files.FileList} [context.fileList] the FileList instance on which the action occurred [DEPRECATED]
|
2014-06-23 21:56:10 +00:00
|
|
|
* @param {OCA.Files.FileActions} context.fileActions the FileActions instance on which the action occurred
|
|
|
|
*/
|
|
|
|
|
2014-05-20 14:01:34 +00:00
|
|
|
// global file actions to be used by all lists
|
|
|
|
OCA.Files.fileActions = new OCA.Files.FileActions();
|
|
|
|
OCA.Files.legacyFileActions = new OCA.Files.FileActions();
|
|
|
|
|
|
|
|
// for backward compatibility
|
2016-10-17 16:52:25 +00:00
|
|
|
//
|
2014-05-20 14:01:34 +00:00
|
|
|
// legacy apps are expecting a stateful global FileActions object to register
|
|
|
|
// their actions on. Since legacy apps are very likely to break with other
|
|
|
|
// FileList views than the main one ("All files"), actions registered
|
|
|
|
// through window.FileActions will be limited to the main file list.
|
2014-06-23 21:56:10 +00:00
|
|
|
// @deprecated use OCA.Files.FileActions instead
|
2014-05-20 14:01:34 +00:00
|
|
|
window.FileActions = OCA.Files.legacyFileActions;
|
|
|
|
window.FileActions.register = function (mime, name, permissions, icon, action, displayName) {
|
2014-05-21 10:54:34 +00:00
|
|
|
console.warn('FileActions.register() is deprecated, please use OCA.Files.fileActions.register() instead', arguments);
|
|
|
|
OCA.Files.FileActions.prototype.register.call(
|
|
|
|
window.FileActions, mime, name, permissions, icon, action, displayName
|
|
|
|
);
|
2014-05-20 14:01:34 +00:00
|
|
|
};
|
2014-06-27 11:36:18 +00:00
|
|
|
window.FileActions.display = function (parent, triggerEvent, fileList) {
|
|
|
|
fileList = fileList || OCA.Files.App.fileList;
|
|
|
|
console.warn('FileActions.display() is deprecated, please use OCA.Files.fileActions.register() which automatically redisplays actions', mime, name);
|
|
|
|
OCA.Files.FileActions.prototype.display.call(window.FileActions, parent, triggerEvent, fileList);
|
2014-05-20 14:01:34 +00:00
|
|
|
};
|
|
|
|
})();
|