/*
* 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.
*/
/**
* This UI helper provides a dialog to select one or more orgunits on a orgunits tree.
* See {@link #open} method.
*/
Ext.define('Ametys.odf.helper.ChooseOrgUnit', {
singleton: true,
/**
* @private
* @property {Boolean} _multiple True to allow multiple selection. Default to false.
*/
/**
* @private
* @property {String[]} _valuesToCheck If multiple, the values to initially check.
*/
/**
* @private
* @property {String} [_contentType="org.ametys.plugins.odf.Content.orgunit"] The content type for orgunit to create when creation is enabled
*/
/**
* Configure and open the dialog box
* @param {Object} config The configuration options :
* @param {String} [config.values] The selected orgunits (ids).
* @param {Boolean} [config.allowCreation=false] `true` to allow the creation of new orgunits from the dialog box.
* @param {Function} config.callback The callback function invoked when orgunit is selected. The callback function will received the following parameters:
* @param {Function} config.callback.ids ids of selected orgunits.
* @param {Boolean} [config.multiple]=false `true` to allow selecting multiple orgunits.
* @param {String[]} config.values If mutliple is true, the values to check
*/
open: function (config)
{
config = config || {};
this._cbFn = config.callback;
this._multiple = config.multiple || false;
this._valuesToCheck = config.values;
this._rootOrgUnitId = config.rootOrgUnitId;
// configuration options for creation
this._allowCreation = config.allowCreation || false;
this._contentType = config.contentType || 'org.ametys.plugins.odf.Content.orgunit';
this._workflowName = config.workflowName || 'orgunit';
this._initWorkflowActionId = config.initWorkflowActionId || 1;
this._editWorkflowActionId = config.editWorkflowActionId || '2';
this._createDialogBox();
this._tree.getStore().getProxy().setExtraParam('tree', "odf-orgunit-tree-config");
this._box.show();
if (this._rootOrgUnitId)
{
this._setRootNode(this._rootOrgUnitId);
}
else
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.odf.orgunit.RootOrgUnitProvider",
methodName: "getRootId",
callback: {
handler: this._setRootNode,
scope: this
},
waitMessage: false
});
}
},
/**
* Creates the dialog box
* @private
*/
_createDialogBox: function ()
{
var me = this;
this._tree = Ext.create('Ametys.plugins.contentstree.ContentsTreePanel', {
checkMode: this._multiple,
treeId: "odf-orgunit-tree-config",
border: true,
flex: 1,
selModel: {
mode: 'SINGLE'
},
listeners : {
'selectionchange': Ext.bind(this._onSelectOrgUnit, this)
}
});
this._box = Ext.create('Ametys.window.DialogBox', {
title: "{{i18n PLUGINS_ODF_WIDGET_ORGUNITWIDGET_SELECTTITLE}}",
iconCls: 'odficon-orgunit',
icon: null,
width: 395,
height: 400,
scrollable: false,
layout: {
type: 'vbox',
align : 'stretch',
pack : 'start'
},
items: [{
xtype: 'component',
cls: 'a-text',
html: "{{i18n PLUGINS_ODF_WIDGET_ORGUNITWIDGET_SELECTDESCRIPTION}}"
},
this._tree,
{
xtype: 'component',
cls: 'a-text link',
html: "{{i18n PLUGINS_ODF_HELPER_CHOOSEORGUNIT_NO_ORGUNIT_SELECTED}}",
hidden: !this._allowCreation
}
],
closeAction: 'destroy',
buttons : [{
itemId: 'ok-btn',
disabled: !this._multiple,
text : "{{i18n PLUGINS_ODF_HELPER_CHOOSEORGUNIT_OKBUTTON}}",
handler : Ext.bind(this._validate, this)
}, {
text : "{{i18n PLUGINS_ODF_HELPER_CHOOSEORGUNIT_CANCELBUTTON}}",
handler: Ext.bind(function() {this._box.close();}, this)
}
]
});
},
/**
* @private
* Sets the root node
* @param {String} rootOrgUnitId The id of the root orgunit to set
*/
_setRootNode: function(rootOrgUnitId)
{
this._tree.setContentRootNode(rootOrgUnitId, {metadataPath: 'childOrgUnits'}, Ext.bind(this._setRootNodeCb, this));
},
/**
* @private
* The callback function of #_setRootNode
*/
_setRootNodeCb: function()
{
this._tree.getSelectionModel().deselectAll();
this._tree.getRootNode().expand();
if (this._multiple && this._valuesToCheck.length)
{
this._tree.store.getRoot().on('expand', function() {
Ametys.data.ServerComm.callMethod({
role: "org.ametys.odf.orgunit.OrgUnitDAO",
methodName: "getOrgUnitsInfos",
parameters: [this._valuesToCheck, this._rootOrgUnitId],
callback: {
handler: this._expandAndCheckNodes,
scope: this
},
waitMessage: false
});
}, this, { single: true });
}
},
/**
* @private
* Expands and select the nodes retrieved from the server.
* @param {Object} response The response
*/
_expandAndCheckNodes: function(response)
{
Ext.Array.forEach(response.orgUnits, function(orgUnit) {
this._tree.selectPath(orgUnit.path, 'name', '/', this._checkNode, this);
}, this);
this._tree.getSelectionModel().deselectAll();
},
/**
* @private
* Check the given node
* @param {Boolean} success true if the node expansion was successful.
* @param {Ext.data.Model} record If successful, the target record.
*/
_checkNode: function(success, record)
{
if (success)
{
record.set('checked', true);
}
},
/**
* This method updates the dialog box depending on the current selection for non-mutliple selection
* @param {Ext.selection.Model} sm The selection model
* @param {Ext.data.Model[]} nodes The selected records
* @private
*/
_onSelectOrgUnit: function(sm, nodes)
{
if (!this._multiple)
{
var isValidSelection = this._isSelectionValid(nodes);
this._box.down("button[itemId='ok-btn']").setDisabled(!isValidSelection);
}
if (this._allowCreation)
{
this._updateLinkCreation();
}
},
/**
* This method retrieves the current selection, and set the tag creation link accordingly.
* @private
*/
_updateLinkCreation: function ()
{
var selection = this._tree.getSelectionModel().getSelection();
var createLink = this._box.child("component[cls~=link]");
var node = selection[0];
if (node != null)
{
this._checkUserRight(node);
}
else
{
// No node is selected
this._box._clickEventRegistered = false;
createLink.update("{{i18n PLUGINS_ODF_HELPER_CHOOSEORGUNIT_NO_ORGUNIT_SELECTED}}");
}
},
/**
* @private
* Check if user has right to create a new orgunit
* @param node The selected node
*/
_checkUserRight: function (node)
{
var me = this,
createLink = me._box.child("component[cls~=link]");
// FIXME this should also check if user can edit the parent orgunit
var contentType = Ametys.cms.content.ContentTypeDAO.getContentType(this._contentType);
if (contentType == null || contentType.isMixin() || contentType.isAbstract() || !contentType.hasRight())
{
// No right to create orgunit
me._box._clickEventRegistered = false;
createLink.update("{{i18n PLUGINS_ODF_HELPER_CHOOSEORGUNIT_CREATE_ORGUNIT_NORIGHT}}");
}
else
{
createLink.update("<a class='action'>{{i18n PLUGINS_ODF_HELPER_CHOOSEORGUNIT_CREATE_ORGUNIT_LINK}}</a>");
// add a click event listener on the <a class='action'> dom node to call the #_createOrgUnit method.
if (!me._box._clickEventRegistered)
{
createLink.mon(createLink.getEl(), 'click', Ext.bind(me._createOrgUnit, me, [[contentType]]), me, {delegate: 'a.action'});
me._box._clickEventRegistered = true;
}
}
},
/**
* @private
* Create a new orgunit
* @param {Object[]} contentTypes The content type
*/
_createOrgUnit: function (contentTypes)
{
var selection = this._tree.getSelectionModel().getSelection();
if (selection && selection.length > 0)
{
var parentNode = selection[0];
Ametys.cms.uihelper.CreateContent.open({
contentTypes: contentTypes,
contentLanguage: parentNode.get('lang') || 'fr',
initWorkflowActionId: this._initWorkflowActionId,
workflowName: this._workflowName
}, Ext.bind(this._createOrgUnitCb, this, [parentNode], true), this);
}
},
/**
* Callback invoked after creating the orgunit. Set the parent metadata
* @param {String} ouId The id of created orgunit
* @param {Ext.data.NodeInterface} parentNode The parent node
*/
_createOrgUnitCb: function(ouId, parentNode)
{
var me = this,
contentIdsToEdit = {};
contentIdsToEdit[parentNode.get('contentId')] = null;
Ametys.data.ServerComm.callMethod({
role: "org.ametys.core.ui.RelationsManager",
id: "org.ametys.cms.relations.setcontentattribute",
methodName: "setContentAttribute",
parameters: [
[ouId],
contentIdsToEdit,
[],
parentNode.get('metadataPath'),
[this._editWorkflowActionId]
],
callback: {
handler: function(response, args) {
if (response == null)
{
Ametys.log.ErrorDialog.display({
title: "{{i18n plugin.contents-tree:PLUGINS_CONTENTSTREE_ADDELEMENT_CREATEDNOTASSOCIATED_TITLE}}",
text: "{{i18n plugin.contents-tree:PLUGINS_CONTENTSTREE_ADDELEMENT_CREATEDNOTASSOCIATED_TEXT}}"
});
}
else if (response['success'] == true)
{
// Set leaf to false, to allow children to be added during the load.
parentNode.set('leaf', false);
me._tree.getStore().load({node: parentNode});
}
},
arguments: null
},
waitMessage: true
});
},
/**
* Check if selection is valid according to the configuration parameters
* @param {Ext.data.Model[]} nodes The selected nodes.
* @return {boolean} true if the selection is valid
* @private
*/
_isSelectionValid : function(nodes)
{
if (nodes.length == 0)
{
return false;
}
return true;
},
/**
* Retrieve the current tree value, and call the callback function from the initial configuration sent to #open
* @private
*/
_validate: function ()
{
if (this._multiple)
{
var selected = this._tree.getChecked();
}
else
{
var selected = this._tree.getSelectionModel().getSelection(); // always an array of length 1
}
this._box.close();
if (this._cbFn)
{
var contentIds = Ext.Array.map(selected, function(item) {
return item.get('contentId');
}, this);
this._cbFn(contentIds);
}
}
});