@ -8,7 +8,6 @@
*
* /
/* global trashBinApp */
( function ( ) {
/ * *
@ -109,33 +108,37 @@
permissions : permissions ,
icon : icon ,
actionHandler : action ,
displayName : displayName
displayName : displayName || name
} ) ;
} ,
/ * *
* Register action
*
* @ param { Object } action action object
* @ param { String } action . name identifier of the action
* @ param { String } action . displayName display name of the action , defaults
* to the name given in action . name
* @ param { String } action . mime mime type
* @ param { int } action . permissions permissions
* @ param { ( Function | String ) } action . icon icon path to the icon or function
* that returns it
* @ param { OCA . Files . FileActions ~ actionHandler } action . actionHandler action handler function
* @ param { OCA . Files . FileAction } action object
* /
registerAction : function ( action ) {
var mime = action . mime ;
var name = action . name ;
var actionSpec = {
action : action . actionHandler ,
name : name ,
displayName : action . displayName ,
mime : mime ,
icon : action . icon ,
permissions : action . permissions
} ;
if ( _ . isUndefined ( action . displayName ) ) {
actionSpec . displayName = t ( 'files' , name ) ;
}
if ( _ . isFunction ( action . render ) ) {
actionSpec . render = action . render ;
} else {
actionSpec . render = _ . bind ( this . _defaultRenderAction , this ) ;
}
if ( ! this . actions [ mime ] ) {
this . actions [ mime ] = { } ;
}
this . actions [ mime ] [ name ] = {
action : action . actionHandler ,
permissions : action . permissions ,
displayName : action . displayName || t ( 'files' , name )
} ;
this . actions [ mime ] [ name ] = actionSpec ;
this . icons [ name ] = action . icon ;
this . _notifyUpdateListeners ( 'registerAction' , { action : action } ) ;
} ,
@ -212,6 +215,127 @@
var actions = this . get ( mime , type , permissions ) ;
return actions [ name ] ;
} ,
/ * *
* 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 ) {
var name = actionSpec . name ;
if ( name === 'Download' || ! isDefault ) {
var $actionLink = this . _makeActionLink ( actionSpec , context ) ;
context . $file . find ( 'a.name>span.fileactions' ) . append ( $actionLink ) ;
return $actionLink ;
}
} ,
/ * *
* Renders the action link element
*
* @ param { OCA . Files . FileAction } actionSpec action object
* @ param { OCA . Files . FileActionContext } context action context
* /
_makeActionLink : function ( actionSpec , context ) {
var img = actionSpec . icon ;
if ( img && img . call ) {
img = img ( context . $file . attr ( 'data-file' ) ) ;
}
var html = '<a href="#">' ;
if ( img ) {
html += '<img class="svg" alt="" src="' + img + '" />' ;
}
if ( actionSpec . displayName ) {
html += '<span> ' + actionSpec . displayName + '</span></a>' ;
}
return $ ( html ) ;
} ,
/ * *
* Custom renderer for the "Rename" action .
* Displays the rename action as an icon behind the file name .
*
* @ param { OCA . Files . FileAction } actionSpec file action to render
* @ param { boolean } isDefault true if the action is a default action ,
* false otherwise
* @ param { OCAFiles . FileActionContext } context rendering context
* /
_renderRenameAction : function ( actionSpec , isDefault , context ) {
var $actionEl = this . _makeActionLink ( actionSpec , context ) ;
var $container = context . $file . find ( 'a.name span.nametext' ) ;
$container . find ( '.action-rename' ) . remove ( ) ;
$container . append ( $actionEl ) ;
return $actionEl ;
} ,
/ * *
* Custom renderer for the "Delete" action .
* Displays the "Delete" action as a trash icon at the end of
* the table row .
*
* @ param { OCA . Files . FileAction } actionSpec file action to render
* @ param { boolean } isDefault true if the action is a default action ,
* false otherwise
* @ param { OCAFiles . FileActionContext } context rendering context
* /
_renderDeleteAction : function ( actionSpec , isDefault , 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' ) ;
}
var $actionLink = $ ( '<a href="#" original-title="' +
escapeHTML ( deleteTitle ) +
'" class="action delete icon-delete" />'
) ;
var $container = context . $file . find ( 'td:last' ) ;
$container . find ( '.delete' ) . remove ( ) ;
$container . append ( $actionLink ) ;
return $actionLink ;
} ,
/ * *
* 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
* @ param { OCAFiles . FileActionContext } context rendering context
* /
_renderAction : function ( actionSpec , isDefault , context ) {
var $actionEl = actionSpec . render ( actionSpec , isDefault , context ) ;
if ( ! $actionEl || ! $actionEl . length ) {
return ;
}
$actionEl . addClass ( 'action action-' + actionSpec . name . toLowerCase ( ) ) ;
$actionEl . attr ( 'data-action' , actionSpec . name ) ;
$actionEl . on (
'click' , {
a : null
} ,
function ( event ) {
var $file = $ ( event . target ) . closest ( 'tr' ) ;
var currentFile = $file . find ( 'td.filename' ) ;
var fileName = $file . attr ( 'data-file' ) ;
event . stopPropagation ( ) ;
event . preventDefault ( ) ;
context . fileActions . currentFile = currentFile ;
// also set on global object for legacy apps
window . FileActions . currentFile = currentFile ;
actionSpec . action (
fileName ,
_ . extend ( context , {
dir : $file . attr ( 'data-path' ) || context . fileList . getCurrentDirectory ( )
} )
) ;
}
) ;
return $actionEl ;
} ,
/ * *
* Display file actions for the given element
* @ param parent "td" element of the file for which to display actions
@ -226,107 +350,51 @@
return ;
}
this . currentFile = parent ;
var $tr = parent . closest ( 'tr' ) ;
var self = this ;
var actions = this . getActions ( this . getCurrentMimeType ( ) , this . getCurrentType ( ) , this . getCurrentPermissions ( ) ) ;
var file = this . getCurrentFile ( ) ;
var $tr = parent . closest ( 'tr' ) ;
var actions = this . getActions (
this . getCurrentMimeType ( ) ,
this . getCurrentType ( ) ,
this . getCurrentPermissions ( )
) ;
var nameLinks ;
if ( $tr . data ( 'renaming' ) ) {
return ;
}
// recreate fileactions
// recreate fileactions container
nameLinks = parent . children ( 'a.name' ) ;
nameLinks . find ( '.fileactions, .nametext .action' ) . remove ( ) ;
nameLinks . append ( '<span class="fileactions" />' ) ;
var defaultAction = this . getDefault ( this . getCurrentMimeType ( ) , this . getCurrentType ( ) , this . getCurrentPermissions ( ) ) ;
var actionHandler = function ( event ) {
event . stopPropagation ( ) ;
event . preventDefault ( ) ;
var defaultAction = this . getDefault (
this . getCurrentMimeType ( ) ,
this . getCurrentType ( ) ,
this . getCurrentPermissions ( )
) ;
self . currentFile = event . data . elem ;
// also set on global object for legacy apps
window . FileActions . currentFile = self . currentFile ;
var file = self . getCurrentFile ( ) ;
var $tr = $ ( this ) . closest ( 'tr' ) ;
event . data . actionFunc ( file , {
$file : $tr ,
fileList : fileList ,
fileActions : self ,
dir : $tr . attr ( 'data-path' ) || fileList . getCurrentDirectory ( )
} ) ;
} ;
var addAction = function ( name , action , displayName ) {
if ( ( name === 'Download' || action !== defaultAction ) && name !== 'Delete' ) {
var img = self . icons [ name ] ,
actionText = displayName ,
actionContainer = 'a.name>span.fileactions' ;
if ( name === 'Rename' ) {
// rename has only an icon which appears behind
// the file name
actionText = '' ;
actionContainer = 'a.name span.nametext' ;
}
if ( img . call ) {
img = img ( file ) ;
}
var html = '<a href="#" class="action action-' + name . toLowerCase ( ) + '" data-action="' + name + '">' ;
if ( img ) {
html += '<img class ="svg" alt="" src="' + img + '" />' ;
}
html += '<span> ' + actionText + '</span></a>' ;
var element = $ ( html ) ;
element . data ( 'action' , name ) ;
element . on ( 'click' , { a : null , elem : parent , actionFunc : actions [ name ] . action } , actionHandler ) ;
parent . find ( actionContainer ) . append ( element ) ;
}
} ;
$ . each ( actions , function ( name , action ) {
$ . each ( actions , function ( name , actionSpec ) {
if ( name !== 'Share' ) {
displayName = action . displayName ;
ah = action . action ;
addAction ( name , ah , displayName ) ;
self . _renderAction (
actionSpec ,
actionSpec . action === defaultAction , {
$file : $tr ,
fileActions : this ,
fileList : fileList
}
) ;
}
} ) ;
if ( actions . Share ) {
displayName = t ( 'files' , 'Share' ) ;
addAction ( 'Share' , actions . Share , displayName ) ;
}
// remove the existing delete action
parent . parent ( ) . children ( ) . last ( ) . find ( '.action.delete' ) . remove ( ) ;
if ( actions [ 'Delete' ] ) {
var img = self . icons [ 'Delete' ] ;
var html ;
var mountType = $tr . 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' ) ;
} else if ( fileList . id === 'trashbin' ) {
deleteTitle = t ( 'files' , 'Delete permanently' ) ;
}
if ( img . call ) {
img = img ( file ) ;
}
html = '<a href="#" original-title="' + escapeHTML ( deleteTitle ) + '" class="action delete icon-delete" />' ;
var element = $ ( html ) ;
element . data ( 'action' , actions [ 'Delete' ] ) ;
element . on ( 'click' , { a : null , elem : parent , actionFunc : actions [ 'Delete' ] . action } , actionHandler ) ;
parent . parent ( ) . children ( ) . last ( ) . append ( element ) ;
// added here to make sure it's always the last action
var shareActionSpec = actions . Share ;
if ( shareActionSpec ) {
this . _renderAction (
shareActionSpec ,
shareActionSpec . action === defaultAction , {
$file : $tr ,
fileActions : this ,
fileList : fileList
}
) ;
}
if ( triggerEvent ) {
@ -350,18 +418,34 @@
* Register the actions that are used by default for the files app .
* /
registerDefaultActions : function ( ) {
this . register ( 'all' , 'Delete' , OC . PERMISSION _DELETE , function ( ) {
return OC . imagePath ( 'core' , 'actions/delete' ) ;
} , function ( filename , context ) {
context . fileList . do _delete ( filename , context . dir ) ;
$ ( '.tipsy' ) . remove ( ) ;
this . registerAction ( {
name : 'Delete' ,
displayName : '' ,
mime : 'all' ,
permissions : OC . PERMISSION _DELETE ,
icon : function ( ) {
return OC . imagePath ( 'core' , 'actions/delete' ) ;
} ,
render : _ . bind ( this . _renderDeleteAction , this ) ,
actionHandler : function ( fileName , context ) {
context . fileList . do _delete ( fileName , context . dir ) ;
$ ( '.tipsy' ) . remove ( ) ;
}
} ) ;
// t('files', 'Rename')
this . register ( 'all' , 'Rename' , OC . PERMISSION _UPDATE , function ( ) {
return OC . imagePath ( 'core' , 'actions/rename' ) ;
} , function ( filename , context ) {
context . fileList . rename ( filename ) ;
this . registerAction ( {
name : 'Rename' ,
displayName : '' ,
mime : 'all' ,
permissions : OC . PERMISSION _UPDATE ,
icon : function ( ) {
return OC . imagePath ( 'core' , 'actions/rename' ) ;
} ,
render : _ . bind ( this . _renderRenameAction , this ) ,
actionHandler : function ( filename , context ) {
context . fileList . rename ( filename ) ;
}
} ) ;
this . register ( 'dir' , 'Open' , OC . PERMISSION _READ , '' , function ( filename , context ) {
@ -388,6 +472,47 @@
OCA . Files . FileActions = FileActions ;
/ * *
* File action attributes .
*
* @ todo make this a real class in the future
* @ typedef { Object } OCA . Files . FileAction
*
* @ property { String } name identifier of the action
* @ property { String } displayName display name of the action , defaults
* to the name given in name property
* @ property { String } mime mime type
* @ property { int } permissions permissions
* @ property { ( Function | String ) } icon icon path to the icon or function
* that returns it
* @ 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
* /
/ * *
* Action handler function for file actions
*