/*
* Copyright 2019 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 tool is the abstract tool editing a file system online.
*
* Creates your own Tool class by inheriting this one and define at least the following methods:
* #reloadFile, #getMessageTargetConfiguration, #getMessageTargetIdForResource, #getMessageTargetIdForCollection.
*/
Ext.define('Ametys.file.AbstractFileEditorTool', {
extend: "Ametys.tool.Tool",
/**
* @private
* @property {String} _fileName The file name
*/
/**
* @private
* @property {String} _fileId The file identifier
*/
/**
* @private
* @property {String} _filePath The file path
*/
/**
* @private
* @property {Ametys.form.field.Code} _editor The editor instance
*/
/**
* @private
* @property _loaded A flag for successful file loading
*/
_loaded: false,
constructor: function()
{
this.callParent(arguments);
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onModified, this);
Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onDeleted, this);
},
createPanel: function()
{
this._mainPanel = new Ext.create('Ext.Container', {
scrollable: false,
layout: 'fit',
cls: 'file-editor-tool',
html: '',
listeners: {
'resize': Ext.bind(this._onResize, this)
}
});
return this._mainPanel;
},
/**
* Editing content in the {@link #_editor} triggers a {@link Ametys.message.Message#MODIFYING} event.
*/
_onChange: function(cms, change)
{
if (this._loaded && !this.isDirty())
{
this.setDirty(true);
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.MODIFYING,
targets: this.getMessageTargetConfiguration()
});
}
},
/**
* Get the message target configuration
* @return {Object} message target configuration
*/
getMessageTargetConfiguration: function()
{
throw new Error("The method #getMessageTargetConfiguration is not implemented in " + this.self.getName());
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_ACTIVE;
},
sendCurrentSelection: function()
{
Ext.create("Ametys.message.Message", {
type: Ametys.message.Message.SELECTION_CHANGED,
targets: this.getMessageTargetConfiguration()
});
},
/**
* @inheritdoc
* @param {Object} params The parameters for the tool
* @param {String} params.id The file id
* @param {String} params.filename The file name
* @param {String} params.path The file path
*/
setParams: function(params)
{
this._fileId = params['id'];
this._fileName = params['filename'];
this._filePath = params['path'];
this.callParent(arguments);
this.refresh();
},
/**
* Get the file path
* @return the file path
*/
getFilePath: function()
{
return this._filePath;
},
/**
* Get the file name
* @return the file name
*/
getFileName: function()
{
return this._fileName;
},
/**
* Loads the file for internal file properties and update the tool info (i.e update the tooltip)
* @param force Force the file load
*/
refresh: function()
{
this.showRefreshing();
if (!this._editor)
{
this._editor = Ext.create("Ametys.form.field.Code", {
mode: this._getMode(),
listeners: {
'change': Ext.bind(this._onChange, this)
}
});
this._mainPanel.add(this._editor);
}
var extension = Ametys.file.AbstractFileExplorerTree.getFileExtension(this._fileName);
// Set title, description, and icons.
this.setTitle(this._fileName);
this.setDescription(this._filePath); // TODO
var iconGlyph = Ametys.file.AbstractFileExplorerTree.getFileIconGlyph(this._fileName);
this.setGlyphIcon(iconGlyph);
this.reloadFile();
// Register the tool on the history tool
var toolId = this.getFactory().getId();
var toolParams = this.getParams();
Ametys.navhistory.HistoryDAO.addEntry({
id: this.getId(),
objectId: this.getId(),
label: this.getTitle(),
description: Ext.String.format("{{i18n PLUGINS_CORE_UI_PARAMETERS_EDITOR_NAVHISTORY_DESC}}", this.getFileName(), this.getFilePath()),
iconGlyph: this.getGlyphIcon(),
iconSmall: this.getSmallIcon(),
iconSmall: this.getSmallIcon(),
iconMedium: this.getMediumIcon(),
iconLarge: this.getLargeIcon(),
type: Ametys.navhistory.HistoryDAO.TOOL_TYPE,
action: Ext.bind(Ametys.tool.ToolsManager.openTool, Ametys.tool.ToolsManager, [toolId, toolParams], false)
});
/*if(!this._loaded || this._params.forceReload)
{
this.reloadFile();
}
else
{
this.showRefreshed();
}*/
},
/**
* Get CodeMirror mode from file name
*/
_getMode: function()
{
var extension = Ametys.file.AbstractFileExplorerTree.getFileExtension(this._fileName).toLowerCase();
switch (extension) {
case 'xml':
return 'xml';
case 'css':
return 'css';
case 'js':
return 'javascript';
default:
return 'htmlmixed';
}
},
/**
* Retrieves the file content from server (asynchronously) and update editor value.
* Have to call #setDirty(false), #setLoaded(true) and #showRefreshed methods after load is complete.
* @template
*/
reloadFile: function()
{
throw new Error("The method #getMessageTargetConfiguration is not implemented in " + this.self.getName());
},
/**
* Indicates the file has been loaded (or not)
* @param {Boolean} loaded true to indicates the file is loaded. false otherwise
*/
setLoaded: function(loaded)
{
this._loaded = loaded;
},
/**
* Set the value of the editor
* @param {String} value The value to set in the code editor
*/
setText: function(value)
{
this._editor.setValue(value);
},
/**
* Returns the content of the codeEditor
* @return {String} The content of the codeEditor
*/
getText: function()
{
return this._editor.getValue();
},
close: function(manual)
{
if (manual && this.isDirty())
{
var me = this;
Ametys.Msg.confirm("{{i18n PLUGINS_CORE_UI_PARAMETERS_EDITOR_UNSAVE_LABEL}}",
"{{i18n PLUGINS_CORE_UI_PARAMETERS_EDITOR_UNSAVE_CONFIRM}}",
function(answer) {
if (answer == 'yes')
{
Ametys.file.AbstractFileEditorTool.superclass.close.call(me, [manual])
}
},
this
);
return;
}
this.callParent(arguments);
},
/**
* @private
* Listener when the panel is resized
* @param {Ext.Component} cmp The component resized
* @param {Number} width The new width
* @param {Number} height The new height
*/
_onResize: function(cmp, width, height)
{
if (this._editor)
{
this._editor.setSize(width, height);
}
},
/**
* Determines if the current file is in path
* @param {String} path the parent path
* @private
*/
_isInPath: function(path)
{
return this._filePath.indexOf(path) == 0;
},
/**
* @protected
* @template
* Get the id of message target for a file resource
* @return {String|Function} the message target type or a function testing the target
*/
getMessageTargetIdForResource: function()
{
throw new Error("The method #getMessageTargetIdForResource is not implemented in " + this.self.getName());
},
/**
* @protected
* @template
* Get the id of message target for a folder resource
* @return {String|Function} the message target type or a function testing the target
*/
getMessageTargetIdForCollection: function()
{
throw new Error("The method #getMessageTargetIdForCollection is not implemented in " + this.self.getName());
},
/**
* Listener when a Ametys.message.Message#MODIFIED message was received.
* Removes the asterisk mark on editor title.
* @param {Ametys.message.Message} message The received message
* @private
*/
_onModified: function(message)
{
var me = this;
var folderTarget = message.getTarget(this.getMessageTargetIdForCollection());
// FIXME oldpath does not exist
/**if (folderTarget != null && folderTarget.getParameters().oldPath && this._isInPath(folderTarget.getParameters().oldPath))
{
this._filePath = folderTarget.getParameters().path + this._filePath.substring(folderTarget.getParameters().oldPath.length);
this.setTitle(this._fileName);
this.setDescription(this._filePath);
return;
}*/
var fileTargets = message.getTargets(this.getMessageTargetIdForResource());
for (var i=0; i < fileTargets.length; i++)
{
if (message.getParameters().major && fileTargets[i].getParameters().path == this._filePath)
{
// The file content has been saved
this.setDirty(false);
}
// FIXME oldpath does not exist
/*
else if (this._filePath == fileTargets[i].getParameters().oldPath)
{
// The file has been renamed
this._fileName = fileTargets[i].getParameters().name;
this._filePath = fileTargets[i].getParameters().path;
var extension = Ametys.file.AbstractFileExplorerTree.getFileExtension(this._fileName);
this.setTitle(this._fileName);
this.setDescription(this._filePath); // TODO
this.setSmallIcon('/plugins/explorer/icon/' + extension + ".png");
this.setMediumIcon('/plugins/explorer/icon-medium/' + extension + ".png");
this.setLargeIcon('/plugins/explorer/icon-medium/' + extension + ".png");
}*/
}
},
/**
* Listener when a Ametys.message.Message#DELETED message was received.
* If the current file is concerned, the tool will be closed.
* @param {Ametys.message.Message} message The received message
* @private
*/
_onDeleted: function(message)
{
var me = this;
var fileTargets = message.getTargets(this.getMessageTargetIdForResource());
for (var i=0; i < fileTargets.length; i++)
{
if (this._filePath == fileTargets[i].getParameters().path)
{
this.close();
// Remove file from navigation history
Ametys.navhistory.HistoryDAO.removeEntry(this.getId());
}
}
}
});