/*
* Copyright 2014 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.
*/
/**
* Singleton class for actions on skin's resources
* @private
*/
Ext.define('Ametys.plugins.skineditor.resources.SkinResourcesActions', {
singleton: true,
/**
* Saves the changes of the current file without leaving the editing.
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
save: function (controller)
{
this._startSave(controller, false);
},
/**
* Saves the changes of the current file and leave the editing.
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
saveAndQuit: function (controller)
{
this._startSave(controller, true);
},
/**
* Saves the content of the current editor tool
* Sends a {@link Ametys.message.Message#MODIFIED} event on success.
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
* @param {Boolean} quit true close tool edition.
*/
_startSave: function (controller, quit)
{
var target = controller.getMatchingTargets()[0];
var fileName = target.getParameters().name;
var path = target.getParameters().path;
var skinName = target.getParameters().skinName;
var tool = Ametys.tool.ToolsManager.getFocusedTool();
var content = tool.getText();
Ametys.data.ServerComm.callMethod({
role: "org.ametys.plugins.skineditor.resources.SkinResourceDAO",
methodName: "save",
parameters: [skinName, path, content],
callback: {
scope: this,
handler: this._saveCb,
arguments:
{
tool: tool,
skinName: skinName,
name: fileName,
path: path,
quit: quit
}
},
waitMessage: {
target: tool.getContentPanel(),
msg: "{{i18n plugin.cms:CONTENT_EDITION_SAVING}}"
},
errorMessage: {
msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_ERROR}}",
category: "Ametys.plugins.cms.params.editor.EditorTool"
}
});
},
/**
* Callback function called after saving
* @param {Object[]} response The server response.
* @param {Boolean} response.success true if the operation succeeded, false otherwise.
* @param {String} [response.error] The error message in case of failure
* @param {Object[]} args The callback arguments.
* @private
*/
_saveCb: function (response, args)
{
if (!response.success && response.error == 'unknown-file')
{
Ametys.Msg.show({
title: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_LABEL}}",
msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_UNKNOWN_FILE}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
if (response.isI18n)
{
Ametys.Msg.show({
title: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_LABEL}}",
msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_EDITOR_SAVE_NEED_WAIT}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.INFO
});
}
args.tool.setDirty(false);
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
parameters: { major: true },
targets: {
id: Ametys.message.MessageTarget.SKIN_RESOURCE,
parameters: {
'name': args.name,
'path': args.path,
'skinName': args.skinName
}
}
});
if (args.quit)
{
args.tool.close();
}
},
/**
* Cancel current changes.
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
unsave: function (controller)
{
Ametys.Msg.confirm("{{i18n PLUGINS_SKINEDITOR_EDITOR_UNSAVE_LABEL}}",
"{{i18n PLUGINS_SKINEDITOR_EDITOR_UNSAVE_CONFIRM}}",
Ext.bind(this._unsaveConfirm, this),
this
);
},
/**
* Callback function invoked after the 'unsave' confirm box is closed
* @param {String} answer Id of the button that was clicked
* @private
*/
_unsaveConfirm: function (answer)
{
if (answer == 'yes')
{
var editorTool = Ametys.tool.ToolsManager.getFocusedTool();
editorTool.close();
}
},
// ------------------------ FOLDERS -------------------------------//
/**
* Create sa new folder.
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
addFolder: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.plugins.skineditor.resources.SkinResourceDAO",
methodName: "addFolder",
parameters: [targets[0].getParameters().skinName, targets[0].getParameters().path, "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_ADD_FOLDER_NEW}}", true],
callback: {
scope: this,
handler: this._addFolderCb
},
errorMessage:{
msg: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_ADD_FOLDER_ERROR}}",
category: this.self.getName()
}
});
}
},
/**
* Callback invoked when adding a folder
* @param {Object[]} response The JSON response from the server
* @param {String} response.path the path of the folder
* @param {String} response.parentPath the path of the parent
* @param {String} response.name the name of the folder
* @param {String} response.skinName the skin's name
*/
_addFolderCb: function (response)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.CREATED,
parameters: {parentPath: response.parentPath},
targets:
{
id: Ametys.message.MessageTarget.SKIN_COLLECTION,
parameters: {
path: response.path,
name: response.name,
skinName: response.skinName
}
}
});
},
// -----------------------------------------------------------
/**
* Deletes a folder.
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
removeFolder: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
Ametys.Msg.confirm("{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FOLDER_TITLE}}",
"{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FOLDER_CONFIRM}}",
function (btn)
{
this._doRemove(btn, targets[0]);
},
this);
}
},
/**
* Do remove the current file or folder.
* @param {String} answer The id of the button pressed.
* @param {Ametys.message.MessageTarget} target The target of the folder or file to delete
* @private
*/
_doRemove: function (answer, target)
{
if (answer == 'yes')
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.plugins.skineditor.resources.SkinResourceDAO",
methodName: "deleteFile",
parameters: [target.getParameters().skinName, target.getParameters().path],
callback: {
scope: this,
handler: this._doRemoveCb,
arguments: {
target: target
}
},
errorMessage: {
msg: target.getId() == Ametys.message.MessageTarget.SKIN_COLLECTION ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FOLDER_ERROR}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FILE_ERROR}}",
category: this.self.getName()
},
});
}
},
/**
* @private
* Callback function after deletion.
* @param {Object[]} result the server's response
* @param {Object} params The callback arguments
*/
_doRemoveCb: function (result, params)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.DELETED,
targets: params.target
});
},
// -----------------------------------------------------------
/**
* Renames a folder
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
renameFolder: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
var oldName = targets[0].getParameters().name;
Ametys.Msg.prompt(
"{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_TITLE}}",
"{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_MSG}}",
function (btn, text)
{
if (btn == 'ok' && text != oldName)
{
this.rename (targets[0].getParameters().skinName, targets[0].getParameters().path, text, 'collection');
}
},
this,
false,
oldName
);
}
},
/**
* Refresh the currently selected folder inside the SkinEditor tool
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
refreshFolder: function (controller)
{
var targets = controller.getMatchingTargets();
var skinEditorTool = Ametys.tool.ToolsManager.getFocusedTool();
if (targets.length > 0 && skinEditorTool != null)
{
skinEditorTool.refreshNode(targets[0].getParameters().path);
}
},
// ----------------------------- FILES -------------------------------//
/**
* Open or download a file.
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
openFile: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
this.doOpenFile(targets[0].getParameters().name, targets[0].getParameters().path, targets[0].getParameters().skinName);
}
},
/**
* Open the editor corresponding to the file, or starts the download if no editor matches
* @param {String} filename The name of the file
* @param {String} path The path of the file
* @param {String} skinName the name of the skin
*/
doOpenFile: function (filename, path, skinName)
{
if (this.isFileEditableOnline(filename))
{
var params = {};
params.id = path.replace(/\//g, "-");
params.filename = filename;
params.path = path;
params.skinName = skinName;
var fileTool = Ametys.tool.ToolsManager.getTool("uitool-skin-file-editor$" + params.id);
if (fileTool)
{
fileTool.focus();
}
else
{
Ametys.tool.ToolsManager.openTool("uitool-skin-file-editor", params);
}
}
else
{
// Download uneditable file
var args = "path=" + path + "&skinName=" + skinName;
var url = Ametys.getPluginDirectPrefix('skineditor') + '/file/download?' + args;
window.open(url);
}
},
/**
* Determines if a file can be edited online by its name
* @param {String} name The file name
*/
isFileEditableOnline: function (name)
{
var extension = Ametys.file.AbstractFileExplorerTree.getFileExtension(name).toLowerCase();
return extension == 'js' || extension == 'html' || extension == 'xhtml' || extension == 'css' || extension == 'xml' || extension == 'xsl' || extension == 'xslt' || extension == 'txt' || extension == 'dtd';
},
/**
* Function called to add or update a file
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
addFile: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
Ametys.plugins.skineditor.resources.UploadFile.open(targets[0].getParameters().skinName, targets[0].getParameters().path, Ext.bind(this._addFileCb, this, [targets[0].getParameters().skinName], true));
}
},
/**
* Callback function called after #addFile action is processed
* @param {String} name The name of uploaded file
* @param {String} path The path of uploaded file
* @param {String} parentPath The parent path of uploaded file
* @param {String} skinName The skin name
* @private
*/
_addFileCb: function (name, path, parentPath, skinName)
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.CREATED,
parameters: {parentPath: parentPath},
targets: {
id: Ametys.message.MessageTarget.SKIN_RESOURCE,
parameters:
{
path: path,
name: name,
skinName: skinName
}
}
});
},
/**
* Deletes a file
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
removeFile: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
Ametys.Msg.confirm("{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FILE_TITLE}}",
"{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_DELETE_FILE_CONFIRM}}",
function (btn)
{
this._doRemove(btn, targets[0], targets[0].getParameters().skinName);
},
this);
}
},
/**
* Renames a file
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
renameFile: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
var name = targets[0].getParameters().name;
Ametys.Msg.prompt(
"{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_PROMPT_TITLE}}",
"{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_PROMPT_MSG}}",
function (btn, text)
{
if (btn == 'ok' && text != name)
{
this.rename (targets[0].getParameters().skinName, targets[0].getParameters().path, text, 'resource');
}
},
this,
false,
name
);
}
},
/**
* Renames a file or a folder
* @param {String} skinName The skin's name
* @param {String} path The path of file/folder to rename
* @param {String} name The new name
* @param {String} type The type of resource : 'resource' or 'collection'
* @param {Function} [callback] Callback function. The function receives the following parameters:
* @param {Boolean} callback.success true if the renaming was successful
* @param {String} callback.path The path of the renamed file
* @param {String} callback.name The name of the renamed file
*/
rename: function (skinName, path, name, type, callback)
{
name = Ext.String.trim(name);
if (name == '' || !/^[^\\/:*?"<>|]*$/.test(name))
{
// Invalid name
var alertMsg = type == 'resource' ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FILE_INVALID_CHARACTERS}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_INVALID_CHARACTERS}}";
Ametys.Msg.alert(
"{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_FILE}}",
alertMsg
);
if (Ext.isFunction(callback))
{
callback(false, path, name);
}
return false;
}
var errorMsg = type == 'resource' ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FILE_ERROR}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_ERROR}}";
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.plugins.skineditor.resources.SkinResourceDAO',
methodName: 'renameSource',
parameters: [skinName, path, name],
callback: {
scope: this,
handler: this._renameCb,
arguments: {
name: name,
type: type,
path: path,
callback: callback,
messageTargetType: type == 'resource' ? Ametys.message.MessageTarget.SKIN_RESOURCE : Ametys.message.MessageTarget.SKIN_COLLECTION
}
},
errorMessage: {
msg: errorMsg,
category: Ext.getClassName(this) + '.rename'
},
waitMessage: true
});
},
/**
* @private
* Callback invoked after renaming a file or folder
* @param {Object} result The server result
* @param {Object} args the callback arguments
*/
_renameCb: function (result, args)
{
if (result.error == 'already-exist')
{
var errorMsg = args.type == 'resource' ? "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FILE_ALREADY_EXISTS}}" : "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_ALREADY_EXISTS}}";
Ametys.Msg.show({
title: "{{i18n plugin.core-ui:PLUGINS_CORE_UI_PARAMETERS_FILE_RENAME_FOLDER_FILE}}",
msg: errorMsg,
buttons: Ext.Msg.OK,
icon: Ext.Msg.ERROR
});
if (Ext.isFunction(args.callback))
{
args.callback(false, args.path, args.name);
}
return false;
}
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFIED,
targets: {
id: args.messageTargetType,
parameters: {
path: result.path,
name: result.name,
skinName: result.skinName
}
}
});
if (Ext.isFunction(args.callback))
{
args.callback(true, result.path, result.name);
}
},
/**
* Download the currently selected file
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
downloadFile: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length > 0)
{
var args = {
"path": targets[0].getParameters().path,
"skinName": targets[0].getParameters().skinName
}
Ametys.openWindow(Ametys.getPluginDirectPrefix('skineditor') + '/file/download', args);
}
},
// ----------------------------- CLIPBOARD -------------------------------//
/**
* Copy the currently selected file or folder. This allows the {#paste} function to be called
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
copy: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length == 0)
{
return;
}
var data = Ext.apply (targets[0].getParameters(), {mode: 'copy', messageTargetType: targets[0].getId()});
Ametys.clipboard.Clipboard.setData (targets[0].getId(), data);
},
/**
* Cut the currently selected file or folder. This allow the {#paste} function to be called
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
cut: function (controller)
{
var targets = controller.getMatchingTargets();
if (targets.length == 0)
{
return;
}
var data = Ext.apply (targets[0].getParameters(), {mode: 'cut', messageTargetType: targets[0].getId()});
Ametys.clipboard.Clipboard.setData (targets[0].getId(), data);
},
/**
* Paste a file or a folder previously saved in clipboard
* @param {Ametys.ribbon.element.ui.ButtonController} controller The controller calling the function
*/
paste: function (controller)
{
if (Ametys.clipboard.Clipboard.getType() != Ametys.message.MessageTarget.SKIN_RESOURCE && Ametys.clipboard.Clipboard.getType() != Ametys.message.MessageTarget.SKIN_COLLECTION)
{
return;
}
var targets = controller.getMatchingTargets();
if (targets.length == 0)
{
return;
}
var clipboardData = Ametys.clipboard.Clipboard.getData();
if (Ext.isEmpty(clipboardData))
{
return;
}
var skinName = clipboardData[0].skinName;
if (clipboardData[0].mode == 'cut')
{
// First check that file is not currently in edition
var id = clipboardData[0].path.replace(/\//g, "-");
var tool = Ametys.tool.ToolsManager.getTool("uitool-skin-file-editor$" + id);
if (tool != null)
{
Ametys.Msg.alert("{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE}}", "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_OPEN}}");
return;
}
this.move(clipboardData[0].skinName, clipboardData[0].path, targets[0].getParameters().path, clipboardData[0].messageTargetType);
}
else
{
this.doCopy(clipboardData[0].skinName, clipboardData[0].path, targets[0].getParameters().path, clipboardData[0].messageTargetType);
}
Ametys.clipboard.Clipboard.setData (targets[0].getId(), null);
},
/**
* Move the selected file or folder to the target path
* @param {String} skinName The name of the skin
* @param {String} srcPath The path of the file or folder to move
* @param {String} targetPath The path where the file or folder will be moved
* @param {String} messageTargetType The message target type concerned by the move.
*/
move: function (skinName, srcPath, targetPath, messageTargetType)
{
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.plugins.skineditor.resources.SkinResourceDAO',
methodName: 'moveSource',
parameters: [skinName, srcPath, targetPath],
callback: {
scope: this,
handler: this._moveCb,
arguments:
{
skinName: skinName,
oldPath: srcPath,
messageTargetType: messageTargetType
}
},
errorMessage: {
msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_ERROR}}",
category: this.self.getName()
},
waitMessage: true
});
},
/**
* Callback for the {#_move} function
* @param {Object[]} response The data from the move action
* @param {Object[]} args The arguments sent to the callback function
* @private
*/
_moveCb: function (response, args)
{
if (!response.success && response.msg == 'already-exists')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE}}",
msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_ALREADY_EXISTS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
else if (!response.success && response.msg == 'no-exists')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE}}",
msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_NO_EXISTS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MOVED,
parameters: {oldPath: args.oldPath},
targets: {
id: args.messageTargetType,
parameters: {
name: response.name,
path: response.path,
skinName: response.skinName
}
}
});
},
/**
* @private
* Copy the selected file or folder to the target path
* @param {String} skinName The name of the skin
* @param {String} path The path of file/folder to copy
* @param {String} targetPath The path where the file or folder will be copied
* @param {String} messageTargetType The message target type concerned by the copy.
*/
doCopy: function (skinName, path, targetPath, messageTargetType)
{
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.plugins.skineditor.resources.SkinResourceDAO',
methodName: 'copySource',
parameters: [skinName, path, targetPath],
callback:
{
scope: this,
handler: this._copyCb,
arguments:{
skinName: skinName,
parentPath: targetPath,
messageTargetType: messageTargetType
}
},
errorMessage: {
msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_MOVE_ERROR}}",
category: this.self.getName()
},
waitMessage: true
});
},
/**
* Callback invoked after copying source
* @param {Object[]} response The data from the copy action
* @param {Object[]} args The arguments sent to the callback function
* @private
*/
_copyCb: function (response, args)
{
if (!response.success && response.error == 'already-exists')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY}}",
msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY_ALREADY_EXISTS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
else if (!response.success && response.error == 'no-exists')
{
Ametys.Msg.show({
title: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY}}",
msg: "{{i18n PLUGINS_SKINEDITOR_SOURCE_HANDLE_COPY_NO_EXISTS}}",
buttons: Ext.Msg.OK,
icon: Ext.MessageBox.ERROR
});
return;
}
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.CREATED,
parameters: {parentPath: args.parentPath},
targets:
{
id: args.messageTargetType,
parameters: {
name: response.name,
path: response.path,
skin: response.skinName
}
}
});
}
});