/*
* Copyright 2010 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 displays the properties of a repository node in a table and its referrers.
* @private
*/
Ext.define('Ametys.repository.tool.NodePropertiesTool',
{
extend: 'Ametys.repository.tool.RepositoryTool',
statics: {
/**
* Open the node properties tool.
* @param {String} path The path of the node to open.
* @param {String} workspaceName The workspace of the node to open.
*/
open: function(path, workspaceName)
{
var toolParams = {
id: path + '$' + workspaceName,
path: path,
workspaceName: workspaceName
}
Ametys.tool.ToolsManager.openTool('uitool-repository-nodeproperties', toolParams);
}
},
/**
* @private
* @property {Boolean} _openedAtStartup Was the tool opened during the UI startup
*/
constructor: function(config)
{
this.callParent(arguments);
// Bus messages listeners
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFYING, this._onMessageModifying, this);
Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onMessageDeleted, this);
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onSaveOrRevertChanges, this);
Ametys.message.MessageBus.on(Ametys.message.Message.REVERTED, this._onSaveOrRevertChanges, this);
},
createPanel: function()
{
this.referrersPanel = this._getReferrersPanel();
this.propertiesPanel = Ext.create('Ametys.repository.tool.NodePropertiesTool.TablePropertiesPanel', {
title: "{{i18n PLUGINS_REPOSITORYAPP_NODEPROPERTIES_PANEL_TITLE}}",
saveProperty: Ext.bind (this._saveProperty, this),
deleteProperty: Ext.bind(this._deleteProperty, this),
downloadBinaryProperty: Ext.bind(this._downloadBinary, this),
onClickReferenceProperty: Ext.bind(this._openReference, this)
});
return Ext.create('Ext.panel.Panel', {
split: true,
scrollable: true,
// JCR node path
dockedItems: {
dock: 'top',
ui: 'tool-hintmessage',
xtype: 'component',
html: ''
},
layout: {
type: 'vbox',
align: 'stretch'
},
items: [
this.propertiesPanel,
this.referrersPanel
],
listeners: {
'render': function() {
new Ametys.relation.dd.AmetysDropZone(this.getContentPanel().getEl(), {setAmetysDropZoneInfos: Ext.bind(this.getDropInfo, this)});
},
scope: this
}
});
},
getDropInfo: function(target, item)
{
item.target = {
relationTypes: [Ametys.relation.Relation.MOVE, Ametys.relation.Relation.REFERENCE, Ametys.relation.Relation.COPY],
targets: [{
id: Ametys.message.MessageTarget.REPOSITORY_NODE,
parameters: {
'paths': [this.getParams().path],
'workspaceName': this.getParams().workspaceName,
}
}]
};
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_ACTIVE;
},
getType: function()
{
return Ametys.tool.Tool.TYPE_REPOSITORY;
},
sendCurrentSelection: function()
{
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.SELECTION_CHANGED,
targets: {
id: Ametys.message.MessageTarget.REPOSITORY_NODE,
parameters: {
'paths': [this.getParams().path],
'workspaceName': this.getParams().workspaceName,
'errorMessage': this._openedAtStartup ? false : undefined
}
}
});
},
setParams: function(params)
{
this._openedAtStartup = !Ametys.tool.ToolsManager.isInitialized();
var selectionHasChanged = params.path != this.getParams().path || params.workspaceName != this.getParams().workspaceName;
this.callParent(arguments);
if (selectionHasChanged)
{
this.refresh();
}
},
refresh: function(manual)
{
this.showRefreshing();
var nodePath = this.getParams().path;
var workspaceName = this.getParams().workspaceName;
Ametys.data.ServerComm.send({
workspace: Ametys.WORKSPACE_NAME,
url: 'repository/node',
parameters: {
workspace: workspaceName,
path: nodePath.substring(1)
},
priority: Ametys.data.ServerComm.PRIORITY_MAJOR,
callback: {
handler: this._refreshCb,
scope: this
}
});
},
/**
* Callback: update all the UI (toolbar and panels) to reflect the selected repository node.
* @param {HTMLElement} response The XML document.
* @param {Array} args The callback arguments.
* @private
*/
_refreshCb: function(response, args)
{
if (Ametys.data.ServerComm.isBadResponse(response))
{
Ametys.notify({
title: "{{i18n PLUGINS_REPOSITORYAPP_NODEPROPERTIES_ERROR_NOTFOUND_TITLE}}",
description: "{{i18n PLUGINS_REPOSITORYAPP_NODEPROPERTIES_ERROR_NOTFOUND_DESCRIPTION}}",
type: "warn"
});
this.close();
return;
}
this._openedAtStartup = false;
var name = Ext.dom.Query.selectValue('repository > node > @name', response, '');
if (name == '')
{
name = '/';
}
var pathWithGroups = Ext.dom.Query.selectValue('repository > node > @pathWithGroups', response, '');
this.setTitle(name + ' (' + this.getParams().workspaceName + ')');
// Update path
this.getContentPanel().down("*[dock='top']").update(pathWithGroups);
// Update properties
var properties = Ext.dom.Query.select('> repository > node > property', response);
this.propertiesPanel.updatePropertiesFromXml(properties);
// Update referrers
var referrers = Ext.dom.Query.select('> repository > node > referer', response);
this._updateReferrers(referrers);
this.showRefreshed();
},
/**
* @private
* Get the referrers panel.
* @return {Ext.panel.Panel} the referrers panel.
*/
_getReferrersPanel: function()
{
return Ext.create('Ext.grid.Panel', {
title: "{{i18n PLUGINS_REPOSITORYAPP_REFERRERS_PANEL_TITLE}}",
collapsible: true,
titleCollapse: true,
animCollapse: true,
header: {
titlePosition: 1
},
cls: 'referrers-panel',
ui: 'light',
border: false,
hidden: false,
forceLayout: true,
scrollable: false,
disableSelection: true,
store: {
autoDestroy: true,
id: 'ReferrerStore',
fields: [
{name: 'path'},
{name: 'property'}
]
},
// TODO Action
columns: [{
text: "{{i18n PLUGINS_REPOSITORYAPP_REFERRERS_PANEL_PATH_COLUMN_HEADER}}",
xtype: 'templatecolumn',
flex: 0.4,
dataIndex: 'path',
tpl: '<a href="#" onclick="Ametys.repository.tool.NodePropertiesTool.open(\'{path}\', \'{workspace}\')">{path}</a>'
}, {
text: "{{i18n PLUGINS_REPOSITORYAPP_REFERRERS_PANEL_PROPERTY_COLUMN_HEADER}}",
flex: 0.6,
dataIndex: 'property'
}]
});
},
/**
* @private
* This listener is invoked when a node has on-going changes
* @param {Ametys.message.Message} message The bus message.
*/
_onMessageModifying: function(message)
{
var target = message.getTarget(Ametys.message.MessageTarget.REPOSITORY_NODE);
if (target != null && target.getParameters().workspaceName == this.getParams().workspaceName && target.getParameters().path == this.getParams().path)
{
if (message.getParameters().major)
{
this.showOutOfDate();
}
}
},
/**
* @private
* This listener is invoked when a node has been deleted
* @param {Ametys.message.Message} message The bus message.
*/
_onMessageDeleted: function(message)
{
var target = message.getTarget(Ametys.message.MessageTarget.REPOSITORY_NODE);
if (target != null && target.getParameters().workspaceName == this.getParams().workspaceName && target.getParameters().path == this.getParams().path)
{
// Close the tool
this.close();
}
},
/**
* @private
* This listener is invoked when the repository session has been saved or rolled back
* @param {Ametys.message.Message} message The bus message.
*/
_onSaveOrRevertChanges: function(message)
{
var target = message.getTarget(Ametys.message.MessageTarget.REPOSITORY_SESSION);
if (target != null && target.getParameters().workspaceName == this.getParams().workspaceName)
{
this.showOutOfDate();
}
},
/**
* @private
* Update the referrers panel to reflect the currently selected node.
* @param {HTMLElement[]} referrers The referrer XML elements.
*/
_updateReferrers: function(referrers)
{
if (referrers == null || referrers.length == 0)
{
this.referrersPanel.hide();
}
else
{
var myData = [];
for (var i=0; i < referrers.length; i++)
{
var referrer = referrers[i];
var path = referrer.getAttribute('path');
var property = referrer.getAttribute('name');
myData.push({
path: path,
property: property,
workspace: this.getParams().workspaceName
});
}
this.referrersPanel.getStore().loadData(myData);
this.referrersPanel.setTitle("{{i18n PLUGINS_REPOSITORYAPP_REFERRERS_PANEL_TITLE}} (" + referrers.length + " {{i18n PLUGINS_REPOSITORYAPP_REFERRERS_ELEMENT}})");
this.referrersPanel.show();
}
},
/**
* Search and open a node by identifier.
* @param {String} identifier The node identifier.
* @private
*/
_openReference: function (identifier)
{
// Get the node path from its identifier.
Ametys.data.ServerComm.callMethod({
role: 'org.ametys.workspaces.repository.jcr.RepositoryDao',
methodName: 'getNodeByIdentifier',
parameters: [identifier, this.getParams().workspaceName],
callback: {
handler: this._getNodeByIdentifierCb,
scope: this
}
});
},
/**
* Callback fired when the node path is known.
* @param {Object} nodeInfo The node information, if found.
* @param {Array} args The callback arguments.
* @private
*/
_getNodeByIdentifierCb: function(nodeInfo, args)
{
var nodePath = nodeInfo.path;
var workspaceName = this.getParams().workspaceName;
Ametys.repository.tool.NodePropertiesTool.open(nodePath, workspaceName);
},
/**
* Read a binary from a binary property (using servercomm)
* @param {String} name The binary property name.
* @private
*/
_downloadBinary: function(name)
{
// FIXME : binary received in XML response from servercomm, bug if not XML binary (eg picture)
var path = this.getParams().path;
var args = {
'workspace': this.getParams().workspaceName,
'path': path,
'property': name
};
Ametys.openWindow(Ametys.getPluginDirectPrefix('repositoryapp') + '/repository/read-binary', args);
},
/**
* Save the new property value.
* @param {Ext.form.Panel} form The form panel to submit the value
* @param {String} type The property type
* @param {String} id The field id
* @param {String} name The property name.
* @param {String} value The property new value as string
* @param {Boolean} multiple true if the metadata is multiple
* @param {Function} [successCb] The callback function to call in case of success
* @param {Function} [failureCb] The callback function to call in case of failure
* @private
*/
_saveProperty: function(form, type, id, name, value, multiple, successCb, failureCb)
{
form.getForm().submit({
url: Ametys.getPluginDirectPrefix('repositoryapp') + '/repository/set-property',
params: {
path: this.getParams().path,
workspace: this.getParams().workspaceName,
name: name,
value: value,
type: type
},
success: Ext.bind(this._savePropertySuccess, this, [successCb], true),
failure: Ext.bind(this._savePropertyFail, this, [failureCb], true)
});
},
/**
* Callback function invoked when a property has been successfully saved.
* @param {Ext.form.Basic} form The form that requested the action.
* @param {Ext.form.action.Action} action The Action class.
* @param {Function} [callback] The callback function
* @private
*/
_savePropertySuccess: function (form, action, callback)
{
if (Ext.isFunction(callback))
{
callback();
}
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.MODIFYING,
parameters: {
major: false
},
targets: {
id: Ametys.message.MessageTarget.REPOSITORY_NODE,
parameters: {
paths: [this.getParams().path],
workspaceName: this.getParams().workspaceName
}
}
});
},
/**
* Callback function invoked when a property failed to be saved.
* @param {Ext.form.Basic} form The form that requested the action.
* @param {Ext.form.action.Action} action The Action class.
* @param {Function} [callback] The callback function
* @private
*/
_savePropertyFail: function(form, action, callback)
{
if (Ext.isFunction(callback))
{
callback();
}
Ametys.log.ErrorDialog.display({
title: "{{i18n PLUGINS_REPOSITORYAPP_SAVE_PROPERTY_ERROR_TITLE}}",
text: "{{i18n PLUGINS_REPOSITORYAPP_SAVE_PROPERTY_ERROR}}",
details: action.result ? action.result.message : ''
});
},
/**
* Delete a property.
* @param {String} name The property's name.
* @param {Function} [successCb] The callback function to call in case of success
* @param {Function} [failureCb] The callback function to call in case of failure
* @private
*/
_deleteProperty: function(name, successCb, failureCb)
{
Ametys.Msg.confirm(
"{{i18n PLUGINS_REPOSITORYAPP_DELETE_PROPERTY_CONFIRM_TITLE}}",
"{{i18n PLUGINS_REPOSITORYAPP_DELETE_PROPERTY_CONFIRM_TEXT}} '" + name + "' ?",
function (btn) {
if (btn == 'yes')
{
this._doDelete(name, successCb);
}
},
this
);
},
/**
* Delete a property (after user confirmation).
* @param {String} name The property name.
* @param {Function} [successCb] The callback function to call in case of success
* @private
*/
_doDelete: function(name, successCb)
{
Ametys.workspace.repository.actions.RemoveProperty.act(this.getParams().path, this.getParams().workspaceName, name, successCb);
}
});