/*
* Copyright 2015 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.
*/
/**
* <p>This tool displays a tree of sites
* @private
*/
Ext.define('Ametys.plugins.web.site.SitesTool', {
extend: 'Ametys.tool.Tool',
/**
* @private
* @property {Ametys.web.site.SitesTree} _tree The sites tree panel
*/
/**
* @private
* @property {String} _autoSelectId The site to select on next refresh
*/
constructor: function(config)
{
this.callParent(arguments);
Ametys.message.MessageBus.on(Ametys.message.Message.MODIFIED, this._onModified, this);
Ametys.message.MessageBus.on(Ametys.message.Message.CREATED, this._onCreated, this);
Ametys.message.MessageBus.on(Ametys.message.Message.DELETED, this._onDeleted, this);
},
getMBSelectionInteraction: function()
{
return Ametys.tool.Tool.MB_TYPE_ACTIVE;
},
createPanel: function ()
{
this._tree = this._createSitesTreePanel();
this._tree.getSelectionModel().select(0);
return this._tree;
},
sendCurrentSelection: function()
{
this._onSelectSite();
},
setParams: function (params)
{
this.callParent(arguments);
this._autoSelectId = params ? params.id : null;
this.refresh();
},
/**
* Refreshes the tool
*/
refresh: function ()
{
this.showRefreshing();
Ametys.data.ServerComm.callMethod({
role: "org.ametys.web.repository.site.SiteDAO",
methodName: "getRootId",
parameters: [],
callback: {
scope: this,
handler: this._getRootCb
},
errorMessage: {
category: this.self.getName(),
msg: "{{i18n PLUGINS_WEB_ADMINISTRATOR_SITES_HANDLE_GETROOT_ERROR}}"
}
});
},
/**
* @private
* Callback function invoked after retrieving the id of sites root node
* @param {String} rootId The id of sites root node
*/
_getRootCb: function (rootId)
{
var newRoot = Ext.clone(this._tree.getRootNode());
newRoot.setId(rootId);
this._tree.setRootNode(newRoot);
this._tree.getStore().load({node: this._tree.getRootNode(), callback: this.showRefreshed, scope: this});
},
/**
* @private
* After store load
*/
_onLoad: function()
{
if (this._autoSelectId)
{
var record = this._tree.getStore().findNode('id', this._autoSelectId);
if (record)
{
this._tree.getSelectionModel().select([record]);
}
this._autoSelectId = null;
}
},
/**
* Get the tree of the tool
* @return {Ext.tree.Panel} The main tree component of the tool
*/
getTree: function()
{
return this._tree;
},
/**
* @private
* Draw the tree panel for the sites
*/
_createSitesTreePanel: function()
{
return Ext.create('Ametys.web.site.SitesTree', {
showColumns: true,
cls: 'uitool-sites',
url: 'administrator/sites.json',
plugin: 'web',
stateId: this.$className,
stateful: true,
// handle drag & drop
viewConfig: {
plugins: {
ptype: 'ametystreeviewdragdrop',
containerScroll: true,
appendOnly: true,
sortOnDrop: true,
expandDelay: 500,
allowContainerDrops: true,
setAmetysDragInfos: Ext.bind(this.getDragInfo, this),
setAmetysDropZoneInfos: Ext.bind(this.getDropInfo, this)
}
},
listeners: {
'selectionchange': this.sendCurrentSelection,
'load': this._onLoad,
scope: this
}
});
},
/**
* @private
* This event is thrown by the getDragData to add the 'source' of the drag.
* @param {Object} item The default drag data that will be transmitted. You have to add a 'source' item in it:
* @param {Ametys.relation.RelationPoint} item.source The source (in the relation way) of the drag operation.
*/
getDragInfo: function (item)
{
var targets = [];
for (var i = 0; i < item.records.length; i++)
{
var node = item.records[i];
targets.push({
id: node.isRoot() ? Ametys.message.MessageTarget.ROOT_SITES : Ametys.message.MessageTarget.SITE,
parameters: {
id: node.getId(),
name: node.get('name'),
title: node.get('title')
}
});
}
if (targets.length > 0)
{
item.source = {
relationTypes: [Ametys.relation.Relation.MOVE, Ametys.relation.Relation.REFERENCE],
targets: targets
};
}
},
/**
* @private
* This event is thrown before the beforeDrop event and create the target of the drop operation relation.
* @param {Ext.data.Model[]} targetRecords The target records of the drop operation.
* @param {Object} item The default drag data that will be transmitted. You have to add a 'target' item in it:
* @param {Object} item.target The target (in the relation way) of the drop operation. A Ametys.relation.RelationPoint config.
*/
getDropInfo: function(targetRecords, item)
{
var targets = [];
for (var i = 0; i < targetRecords.length; i++)
{
var node = targetRecords[i];
targets.push({
id: node.isRoot() ? Ametys.message.MessageTarget.ROOT_SITES : Ametys.message.MessageTarget.SITE,
parameters: {
id: node.getId(),
name: node.get('name'),
title: node.get('title')
}
});
}
if (targets.length > 0)
{
item.target = {
relationTypes: [Ametys.relation.Relation.MOVE],
targets: targets
};
}
},
/**
* @private
* Send selection message
*/
_onSelectSite: function()
{
var targets = [];
var selection = this._tree.getSelectionModel().getSelection();
Ext.Array.forEach(selection, function(node) {
target = Ext.create('Ametys.message.MessageTarget', {
id: node.isRoot() ? Ametys.message.MessageTarget.ROOT_SITES : Ametys.message.MessageTarget.SITE,
parameters: {
id: node.getId(),
name: node.get('name'),
title: node.get('title')
}
});
targets.push(target);
});
Ext.create('Ametys.message.Message', {
type: Ametys.message.Message.SELECTION_CHANGED,
targets: targets
});
},
/**
* @private
* Listener on edition (site or population)
* @param {Ametys.message.Message} message The edition message
*/
_onModified: function(message)
{
// Site edition
var targets = message.getTargets(Ametys.message.MessageTarget.SITE);
if (targets.length > 0)
{
var store = this._tree.getStore();
var me = this;
Ext.Array.forEach(targets, function(target) {
var node = me._tree.getStore().getNodeById(target.getParameters().id);
if (node != null && !me.isRefreshing())
{
// FIXME only refresh the edited node
me._tree.getStore().load({node: node.parentNode});
}
});
}
// Population edition
targets = message.getTargets(Ametys.message.MessageTarget.USER_POPULATION);
if (targets.length > 0)
{
var store = this._tree.getStore();
var modifiedPopulationIds = Ext.Array.map(targets, function(target) {
return target.getParameters().id;
});
var me = this;
// Retrieve the sites to update (sites which have one of the modified population as context)
var sitesToUpdate = Ext.Array.filter(store.getRange(), function(site) {
var sitePopulations = site.get('populations');
if (sitePopulations != null)
{
var sitePopulationsIds = Ext.Array.map(sitePopulations, function(population) {
return population.id;
});
return containsAny(sitePopulationsIds, modifiedPopulationIds);
}
return false;
});
if (sitesToUpdate.length > 0 && !me.isRefreshing())
{
// need refresh
me.showOutOfDate()
}
function containsAny(arr1, arr2)
{
var result = false;
// Tests if one of the item in arr2 is in arr1
Ext.Array.each(arr2, function(item) {
if (Ext.Array.contains(arr1, item))
{
result = true;
return true;
}
});
return result;
}
}
},
/**
* @private
* Listener on site creation
* @param {Ametys.message.Message} message The creation message
*/
_onCreated: function (message)
{
var target = message.getTarget(Ametys.message.MessageTarget.SITE);
if (target != null)
{
var store = this._tree.getStore();
var node = store.getNodeById(target.getParameters().parentId);
if (node == null)
{
node = this._tree.getRootNode();
}
else
{
node.set('expanded', true)
node.commit();
}
store.load({node: node});
}
},
/**
* @private
* Listener on site deletion
* @param {Ametys.message.Message} message The deletion message
*/
_onDeleted: function (message)
{
var targets = message.getTargets(Ametys.message.MessageTarget.SITE);
if (targets.length > 0)
{
var store = this._tree.getStore();
var me = this;
Ext.Array.forEach(targets, function(target) {
var node = store.getNodeById(target.getParameters().id);
if (node != null)
{
var parentNode = node.parentNode;
me._tree.getSelectionModel().select([parentNode]);
node.remove();
}
});
}
}
});
Ext.define("Ametys.message.SiteMessageTarget",
{
override: "Ametys.message.MessageTarget",
statics:
{
/**
* @member Ametys.message.MessageTarget
* @readonly
* @property {String} SITE The target type is a site.
*/
SITE: "site",
/**
* @member Ametys.message.MessageTarget
* @readonly
* @property {String} ROOT_SITES The target type is the root of sites.
*/
ROOT_SITES: "root-sites"
}
}
);