/*
* Copyright 2013 Anyware Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* This class is a singleton to handle actions on files
*/
Ext.define('Ametys.explorer.resources.actions.File', {
singleton: true,
// ------------------------------------------------ //
// ADD //
// ------------------------------------------------ //
/**
* Upload a new file
* @param {String} parentID The id of parent folder
* @param {Function} callback The callback function called when the file was uploaded. Has the following parameters:
* {String} callback.id The id of the new resource
* @param {String} callback.parentID The id of parent folder
* @param {Boolean} callback.reload true if a reload is needed.
* @param {Object} scope the callback scope
*/
add: function (parentID, callback, scope)
{
Ametys.explorer.resources.helper.ResourceUpload.open(parentID, null, Ext.bind(this._addCb, this, [callback, scope], true));
},
/**
* @private
* Callback function called after #add is processed
* @param {Object[]} files The files
* @param {String} files.id The id of the new resource
* @param {String} files.name The name of the new resource
* @param {Boolean} files.reload true if a reload is needed.
* @param {String} parentID The id of parent folder
* @param {Boolean} unzip True if the file was unziped on the server
* @param {Function} callback The callback function
* @param {String} callback.id The id of the new resource
* @param {String} callback.parentID The id of parent folder
* @param {String} callback.reload true if a reload is needed.
* @param {Object} scope the callback scope
*/
_addCb: function(files, parentID, reload, unzip, callback, scope)
{
var callback = callback || Ext.emptyFn,
scope = scope || this;
for (let file of files)
{
this._addCbNotifyAndSendMessage(file.id, file.name, parentID, reload);
}
// callback
callback.apply(scope, [files, parentID, reload, unzip]);
},
/**
* @private
* Callback function called after #add is processed
* @param {String} id The id of the new resource
* @param {String} name The name of the new resource
* @param {String} parentID The id of parent folder
* @param {Boolean} reload true if a reload is needed.
* @param {Boolean} unzip True if the file was unziped on the server
*/
_addCbNotifyAndSendMessage: function(id, name, parentID, reload)
{
if (reload || !id)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: Ametys.message.MessageTarget.EXPLORER_COLLECTION,
parameters: { ids: [parentID] }
},
parameters: {
major: true // request refresh
}
});
}
else
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.CREATED,
targets: {
id: Ametys.message.MessageTarget.RESOURCE,
parameters: { ids: [id]}
}
});
}
Ametys.notify({
type: 'info',
title: "{{i18n PLUGINS_EXPLORER_FILE_NOTIFY_ADD_LABEL}}",
description: Ext.String.format("{{i18n PLUGINS_EXPLORER_FILE_NOTIFY_ADD_DESC}}", name),
iconGlyph: 'ametysicon-arrow88',
action: Ext.bind(Ametys.explorer.resources.actions.File.download, this, [id], false)
});
},
// ------------------------------------------------ //
// RENAME //
// ------------------------------------------------ //
/**
* Rename a file
* @param {String} id The file id to rename
* @param {String} oldName The old name
* @param {String} newName The new name
* @param {Function} callback The callback function
* @param {String} callback.id The id of the renamed file
* @param {String} callback.name The new file name
* @param {Boolean} callback.success True if the renaming succeeded
* @param {Object} scope the callback scope
*/
rename: function (id, oldName, newName, callback, scope)
{
var name = Ext.String.trim(newName),
callback = Ext.isFunction(callback) ? callback : Ext.emptyFn,
scope = scope|| this;
if (name == '' || !/^[^\\/:*?"<>|]*$/.test(name))
{
Ametys.Msg.alert(
"{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME}}",
"{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME_INVALID_CHARACTERS}}"
);
callback.apply(scope, [id, name, false]);
return;
}
if (this._getFileExtension (oldName) != this._getFileExtension(name))
{
Ametys.Msg.confirm(
"{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME}}",
"{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME_EXTENSION}}",
function(answer)
{
if (answer == 'yes')
{
this._doRename(id, name, callback, scope);
}
else
{
callback.apply(scope, [id, name, false]);
}
},
this
);
}
else
{
this._doRename(id, name, callback, scope);
}
return true;
},
/**
* Rename a file
* @param {String} id The file id to rename
* @param {String} name The new name
* @param {Function} callback The callback function
* @param {String} callback.id The id of the renamed file
* @param {String} callback.name The new file name
* @param {Boolean} callback.success True if the renaming succeeded
* @param {Object} scope the callback scope
* @private
*/
_doRename: function (id, name, callback, scope)
{
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO',
methodName: 'renameResource',
parameters: [id, name],
callback: {
handler: this._renameCb,
scope: this,
arguments: [callback, scope]
},
waitMessage: true,
errorMessage: true
});
},
/**
* @private
* Callback of #_doRename
* @param {Object[]} response the server response
* @param {Object[]} args the callback args
*/
_renameCb: function(response, args)
{
var msg = response['message'] || null,
id = response['id'],
name = response['name'];
var callback = args[0] || Ext.emptyFn,
scope = args[1] || this;
if (msg == 'locked')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME_LOCKED}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
callback.apply(scope, [id, name, false]);
}
else if (msg == 'already-exist')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_RENAME_ALREADY_EXISTS}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
callback.apply(scope, [id, name, false]);
}
else
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: Ametys.message.MessageTarget.RESOURCE,
parameters: { ids: [id]}
}
});
callback.apply(scope, [id, name, true]);
}
},
/**
* Get the extension of a file
* @param {String} fileName The file name
* @private
*/
_getFileExtension: function(fileName)
{
var ext = '';
var dotPos = fileName.lastIndexOf('.');
if (dotPos > -1)
{
ext = fileName.substring(dotPos + 1).toLowerCase();
}
return ext;
},
// ------------------------------------------------ //
// DELETE //
// ------------------------------------------------ //
/**
* Delete a file
* @param {String} parentID The folder parent id
* @param {String[]} ids The file id's to delete
* @param {Function} callback The callback function
* @param {String} callback.parentID The folder parent id
* @param {String[]} callback.ids The id's of the deleted resources
* @param {Boolean} callback.success True if the renaming succeeded
* @param {Object} scope the callback scope
*/
remove: function(parentID, ids, callback, scope)
{
Ametys.Msg.confirm("{{i18n PLUGINS_EXPLORER_FILE_HANDLE_DELETE}}",
"{{i18n PLUGINS_EXPLORER_FILE_HANDLE_DELETE_CONFIRM}}",
function(btn) {
this._doRemove(btn, parentID, ids, callback, scope)
},
this
);
},
/**
* Internal callback for the #remove function
* @param {String} answer The id of the button pressed. See {@link Ext.window.MessageBox#method-show}
* @param {String} parentID The folder parent id
* @param {String[]} ids The file id's to delete
* @param {Function} callback The callback function
* @param {String} callback.parentID The folder parent id
* @param {String[]} callback.ids id's of the removed resources
* @param {Boolean} callback.success
* @param {Object} scope the callback scope
* @private
*/
_doRemove: function(answer, parentID, ids, callback, scope)
{
var callback = Ext.isFunction(callback) ? callback : Ext.emptyFn,
scope = scope|| this;
if (answer == 'yes')
{
var me = this;
// Sending the deleting message to store target info
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.DELETING,
targets: {
id: Ametys.message.MessageTarget.RESOURCE,
parameters: {ids: ids}
},
callback: function(deletingMsg) {
// Effectively removing the folder
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO',
methodName: 'deleteObject',
parameters: [ids],
callback: {
handler: me._removeCb,
scope: me,
arguments: [callback, scope, deletingMsg.getTargets(), parentID, ids]
},
waitMessage: true,
errorMessage: true
});
}
});
}
else
{
// callback
callback.apply(scope, [parentID, ids, false]);
}
},
/**
* @private
* Callback of #_doRemove
* @param {Object[]} response the server response
* @param {Object[]} args the callback args
*/
_removeCb: function(response, args)
{
var msg = response['message'] || null;
var callback = args[0] || Ext.emptyFn,
scope = args[1] || this,
targets = args[2],
parentID = args[3],
ids = args[4];
if (msg == 'locked')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_DELETE}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_DELETE_LOCKED}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
// callback
callback.apply(scope, [parentID, ids, false]);
}
else
{
// Sending the deleted message with stored targets
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.DELETED,
// FIXME this should be determined based on the response
parameters: {trashed: true},
targets: targets
});
// callback
callback.apply(scope, [parentID, ids, true]);
}
},
// ------------------------------------------------ //
// DOWNLOAD //
// ------------------------------------------------ //
/**
* Download a file
* @param {String} id The id of the file to download
*/
download: function(id)
{
var args = {
'id': id,
'download': "true"
}
Ametys.openWindow(Ametys.getPluginDirectPrefix('explorer') + '/resource', args);
},
// ------------------------------------------------ //
// EXPORT //
// ------------------------------------------------ //
/**
* Export to ZIP archive
* @param {String} folder The folder id.
* @param {String[]} files The file ids to export
*/
exportZIP: function(folder, files)
{
var args = "id=" + folder;
for (var i = 0; i < files.length; i++)
{
args += "&file=" + encodeURIComponent(files[i]);
}
window.open(Ametys.getPluginDirectPrefix('explorer') + '/files/archive.zip?' + args)
},
/**
* Export to RDF format
* _Currently unused : see EXPLORER-108_
* @param {String} id The file id to export
*/
exportRDF: function(id)
{
var args = { 'id': encodeURIComponent(id)};
Ametys.openWindow(Ametys.getPluginDirectPrefix('explorer') + '/resource/rdf', args)
},
// ------------------------------------------------ //
// HISTORY //
// ------------------------------------------------ //
/**
* Show the history of a file
* @param {String} id The id of the resource
* @param {String} parentId The id of the parent resource. Only used as an argument for the callback. Can be null.
* @param {Boolean} allowRestore True to enable the restore action
* @param {Function} callback The callback function called when an old version has been restored. Has the following parameters
* @param {String} callback.id The id of restored resource
* @param {String} callback.parentId The id of the parent resource
* @param {Object} scope the callback scope
*/
showHistory: function (id, parentId, allowRestore, callback, scope)
{
Ametys.explorer.resources.helper.History.open(id, parentId, allowRestore, Ext.bind(this._showHistoryCb, this, [callback, scope], true), this);
},
/**
* @private
* Callback called when an old version is restored.
* @param {String} id The id of restored resource
* @param {String} parentId The id of the parent resource
* @param {Function} callback The callback function
* @param {String} callback.id The id of restored resource
* @param {String} callback.parentId The id of the parent resource
* @param {Object} scope the callback scope
*/
_showHistoryCb: function(id, parentId, callback, scope)
{
var callback = Ext.isFunction(callback) ? callback : Ext.emptyFn,
scope = scope|| this;
// Sending modified message
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: Ametys.message.MessageTarget.RESOURCE,
parameters: { ids: [id]}
},
parameters: {
major: true
}
});
// callback
callback.apply(scope, [id, parentId]);
},
// ------------------------------------------------ //
// DUBLIN CORE //
// ------------------------------------------------ //
/**
* Edit the dublin core metadata. Open a pop up.
* @param {String} id The id of the resource
* @param {Function} callback The callback function called when an old version has been restored. Has the following parameters
* @param {String} callback.id The id of the edited resource
* @param {Object} scope the callback scope
*/
editDublinCore: function (id, callback, scope)
{
Ametys.explorer.resources.helper.DublinCore.open(id, Ext.bind(this._editDublinCoreCb, this, [callback, scope], true));
},
/**
* @private
* Callback function called after #editDublinCore action is processed
* @param {String} id The id of modified file
* @param {Function} callback The callback function
* @param {String} callback.id The id of restored resource
* @param {String} callback.parentId The id of the parent resource
* @param {Object} scope the callback scope
*/
_editDublinCoreCb: function (id, callback, scope)
{
var callback = Ext.isFunction(callback) ? callback : Ext.emptyFn,
scope = scope|| this;
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: Ametys.message.MessageTarget.RESOURCE,
parameters: { ids: [id]}
}
});
// callback
callback.apply(scope, [id]);
},
// ------------------------------------------------ //
// SEARCH //
// ------------------------------------------------ //
/**
* Perform a search on files
* @param {String} id The folder id
* @param {Function} callback The callback function
* @param {Object} callback.values set of key/value pairs representing the values of the fields of the form. See {@link Ext.form.Basic#getValues}
*/
search: function(id, callback)
{
Ametys.explorer.resources.helper.SearchResources.open (id, callback);
},
// ------------------------------------------------ //
// COPY / CUT / PASTE //
// ------------------------------------------------ //
/**
* Cut the selected files
* @param {String} base The folder id to cut from
* @param {String[]} files The files id to move
*/
cut: function(base, files)
{
/**
* @private
* @property {String[]} _pasteFiles The id's of the current files to move or copy.
*/
this._pasteFiles = files;
/**
* @private
* @property {String} _pasteMode The mode of the paste operation: 'cut' or 'copy'
*/
this._pasteMode = 'cut';
/**
* @private
* @property {String} _pasteBase The id of the parent folder.
*/
this._pasteBase = base;
},
/**
* Paste files into target folder
* @param {String} target The folder id to move into
* @param {Function} callback The callback function. See {@link #move method} for the callback args.
*/
paste: function(target, callback)
{
if (!this._pasteFiles)
{
return;
}
if (this._pasteMode == 'cut')
{
this.move(target, this._pasteFiles, callback)
}
else if (this._pasteMode == 'copy')
{
this.doCopy(target, this._pasteFiles, callback)
}
},
/**
* Copy files to a target folder
* @param {String} base The folder id to copy into
* @param {String[]} files The files id to copy
*/
copy: function(base, files)
{
this._pasteFiles = files;
this._pasteMode = 'copy';
this._pasteBase = base;
},
/**
* Move files to a target folder
* @param {String} target The folder id to move into
* @param {String[]} files The file id's to move
* @param {Function} callback The callback function
* @param {String} callback.target The folder id to move into
* @param {String[]} callback.ids File ids moved effectively
*/
move: function(target, files, callback)
{
var params = {
id: files,
target: target
};
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO',
methodName: 'moveObject',
parameters: [files, target],
callback: {
handler: this._moveCb,
scope: this,
arguments: {
callback: callback,
target: target
}
},
errorMessage: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_PASTE_ERROR}}"
});
},
/**
* @private
* Callback function invoked after moving objects
* @param {Object} response The server result
* @param {String} response.message In case of error
* @param {String[]} response.moved-objects The ids of effective moved objects
* @param {String[]} response.unmoved-objects The ids of unmoved objects
* @param {Object[]} args Additionnal arguments
* @param {Function} [args.callback] A callback at the end
* @param {String[]} args.callback.movedObjects The identifiers of the moved objects
* @param {String} args.callback.target The target in #move
* @param {String} [args.target] The target in #move
*/
_moveCb: function (response, args)
{
if (response.message && response.message == 'locked')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_PASTE}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_PASTE_LOCKED}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
return;
}
if (response.message && response.message == 'already-exist')
{
var unmovedObjects = response["unmoved-objects"];
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_PASTE}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_UNPASTE}}" + unmovedObjects.join(", ") + "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_UNPASTE_2}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.WARN
});
}
var noRightOjects = response["noright-objects"] || [];
if (noRightOjects.length > 0)
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_PASTE}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_CUT_NORIGHT}}" + noRightOjects.join(", "),
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
}
var movedObjects = response["moved-objects"] || [];
if (movedObjects.length > 0)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MOVED,
targets: {
id: Ametys.message.MessageTarget.RESOURCE,
parameters: {ids: movedObjects}
}
});
}
if (Ext.isFunction(args.callback))
{
args.callback(args.target, movedObjects);
}
},
/**
* Copy files to a target folder
* @param {String} target The folder id to copy into
* @param {String[]} files The file id's to copy
* @param {Function} callback The callback function
* @param {String} callback.target The folder id to copy into
* @param {String[]} callback.ids File ids copied effectively
*/
doCopy: function(target, files, callback)
{
var params = {
id: files,
target: target
};
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.plugins.explorer.resources.actions.ExplorerResourcesDAO',
methodName: 'copyResource',
parameters: [files, target],
callback: {
handler: this._copyCb,
scope: this,
arguments: {
callback: callback,
target: target
}
},
errorMessage: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_COPY_PASTE_ERROR}}"
});
},
/**
* @private
* Callback function invoked after copying objects
* @param {Object} response The server result
* @param {String} response.message In case of error
* @param {String[]} response.copied-resources The ids of effective copied resources
* @param {String[]} response.uncopied-resources The ids of uncopied resources
* @param {Object[]} args Additionnal arguments
* @param {Function} [args.callback] A callback at the end
* @param {String[]} args.callback.copiedResources The identifiers of the copied objects
* @param {String} args.callback.target The target in #move
* @param {String} [args.target] The target in #move
*/
_copyCb: function (response, args)
{
if (response.message && response.message == 'locked')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_COPY_PASTE}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_COPY_PASTE_LOCKED}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
return;
}
if (response.message && response.message == 'already-exist')
{
var uncopiedResources = response["uncopied-resources"];
Ametys.Msg.show({
title: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_COPY_PASTE}}",
msg: "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_COPY_UNPASTE}}" + uncopiedResources.join(", ") + "{{i18n PLUGINS_EXPLORER_FILE_HANDLE_COPY_UNPASTE_2}}",
buttons: Ext.Msg.OK,
icon: Ext.Msg.WARN
});
}
var copiedResources = response["copied-resources"] || [];
if (copiedResources.length > 0)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.CREATED,
targets: {
id: Ametys.message.MessageTarget.RESOURCE,
parameters: {ids: copiedResources}
}
});
}
if (Ext.isFunction(args.callback))
{
args.callback(args.target, copiedResources);
}
},
//------------------------------------------------------//
// SLIDE SHOW //
//------------------------------------------------------//
/**
* Show the slideshow for a set of files.
* @param {String[]} files the file ids.
*/
slideshow: function(files)
{
var divEl = Ext.get('div-slideshow');
if (divEl == null)
{
var div = document.createElement('div');
div.id = 'div-slideshow';
div.style.display = 'none';
document.body.appendChild(div);
divEl = Ext.get('div-slideshow');
}
else
{
divEl.dom.innerHTML = '';
}
var me = this;
Ametys.explorer.ExplorerNodeDAO.getExplorerNodes(files, function(resources) {
// Sort images by alphabetical order
var sortedResources = Ext.Array.sort(resources, function (r1, r2){
var v1 = r1.getProperties().name;
var v2 = r2.getProperties().name;
return Ext.String.enhancedCompare(v1, v2);
});
var rl = sortedResources.length;
for (var i = 0; i < rl; i++)
{
var props = sortedResources[i].getProperties(),
id = props.id,
name = props.name || '';
var link = document.createElement('a');
link.id = 'div-slideshow-' + i;
link.className = 'pirobox' + (rl == 1 ? '' : '_gall');
link.rel = rl == 1 ? 'single' : 'gallery';
link.href = Ametys.getPluginDirectPrefix('explorer') + "/resource?id=" + id;
link.setAttribute('title', name);
divEl.dom.appendChild(link);
}
$('.piro_html').remove();
$('.piro_overlay').remove();
$().piroBox_ext({bg_alpha : 0.5});
$('#div-slideshow-0').click();
});
}
});