/*
* Copyright 2017 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 hierarchical contents on a tree.
* See {@link #open} method.
*
* Ametys.cms.uihelper.ChooseHierarchicalContent.open({
* leafContentType: 'my.hierarchical.reference.table.content.type',
* multiple: false,
* values: ["foo"],
* callback: function(contents) {console.log(contents);},
* scope: this
* });
*/
Ext.define('Ametys.cms.uihelper.ChooseHierarchicalContent', {
singleton: true,
/**
* @readonly
* @property {String} TOP_ITEM_ALERT_DEFAULT_TITLE The default title of alert when a item of first level (with children) is selected
*/
TOP_ITEM_ALERT_DEFAULT_TITLE: "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_TOP_ITEM_ALERT_TITLE}}",
/**
* @readonly
* @property {String} TOP_ITEM_ALERT_DEFAULT_TEXT The default text of alert when a item of first level (with children) is selected
*/
TOP_ITEM_ALERT_DEFAULT_TEXT: "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_TOP_ITEM_ALERT_TEXT}}",
/**
* Configure and open the helper dialog box to select a reference table entry in its hierarchy.
* @param {Object} config The configuration :
* @param {String} config.leafContentType The id of the content type for the leaves of the tree. Mandatory
* @param {String} [config.title] The title of the dialog box
* @param {String} [config.iconCls=ametysicon-list6] The CSS class for icon of the dialog box
* @param {String} [config.helpMessage] The help message to display on top of dialog box
* @param {String} [config.activateTopItemAlert=false] 'true' to activate the alert when a item of first level (with children) is selected
* @param {String} [config.topItemAlertTitle] The title of alert when a item of first level (with children) is selected
* @param {String} [config.topItemAlertText] The text of alert when a item of first level (with children) is selected
* @param {String} [config.multiple=false] 'true' to allow to select multiple contents
* @param {String} [config.values] The list of the ids of th econtents to initially check
* @param {String} [config.allowToggleAutoposting] Allow the autoposting
* @param {String} [config.activeAutoposting] Activate the autoposting button
* @param {String} config.callback The callback function to call after the 'OK' button was clicked. The callback function will receive the following parameters:
* @param {String} config.callback.contents The ids of the selected contents in the tree
* @param {Boolean} config.callback.autoposting 'true' if the autoposting button is activated
* @param {String} config.scope The scope of the callback function
*/
open: function(config)
{
config = config || {};
config.activateTopItemAlert = config.activateTopItemAlert === true || config.activateTopItemAlert === "true";
config.topItemAlertTitle = config.topItemAlertTitle || Ametys.cms.uihelper.ChooseHierarchicalContent.TOP_ITEM_ALERT_DEFAULT_TITLE;
config.topItemAlertText = config.topItemAlertText || Ametys.cms.uihelper.ChooseHierarchicalContent.TOP_ITEM_ALERT_DEFAULT_TEXT;
config.multiple = config.multiple === true || config.multiple === "true";
config.viewName = config.viewName || 'main';
Ametys.data.ServerComm.callMethod({
role: "org.ametys.cms.content.referencetable.HierarchicalReferenceTablesHelper",
methodName: "isHierarchicalSimpleTree",
parameters: [config.leafContentType],
callback: {
handler: this._isHierarchicalSimpleTreeCb,
scope: this,
arguments: config
},
waitMessage: false
});
},
/**
* @private
* Callback invoked after retrieving the type of tree
* @param {Boolean} isSimpleTree true if the tree is composed by simple contents only
* @param {Object} config The dialog box configuration
*/
_isHierarchicalSimpleTreeCb: function (isSimpleTree, config)
{
var box = this._createBox(config, isSimpleTree);
box.show();
var tree = box.down('#tree'),
rootNode = tree.getRootNode();
tree.getStore().load({
node : rootNode,
callback : function()
{
tree.expandNode(rootNode);
},
scope : this
});
},
/**
* @private
* Create the tree displayed in the dialog box
* @param {Object} config The configuration
*/
_createTree: function(config)
{
return Ext.create('Ametys.plugins.cms.content.tree.HierarchicalReferenceTablesTree', {
itemId: 'tree',
rootVisible: false,
rootCfg: {
expanded: false,
text: "",
contenttypesIds: [config.leafContentType]
},
bodyStyle: {
borderTopWidth: 0
},
region: 'center',
split: true,
scrollable: true,
referenceTableId: config.leafContentType,
checkSelection: true,
checkMode: config.multiple,
values: config.values,
allowToggleAutoposting: config.allowToggleAutoposting,
activeAutoposting: config.activeAutoposting
});
},
/**
* @private
* Create the dialog box in order to select an item
* @param {Object} config The configuration
* @param {Boolean} simpleTree true if the tree is composed by simple contents only
*/
_createBox: function(config, simpleTree)
{
var tree = this._createTree(config);
var multiple = config.multiple,
callback = config.callback;
var items = [tree];
if (!simpleTree)
{
var iframe = Ext.create("Ext.ux.IFrame", {itemId: 'iframe'});
items.push({
split: true,
region: 'east',
xtype: 'container',
layout: 'card',
itemId: 'card',
activeItem: 1,
border: false,
flex: 2,
items: [
iframe,
{
xtype: 'component',
padding: '5',
html: config.helpMessage || ("{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_NO_SELECTION}}")
}
]
});
}
var box = Ext.create('Ametys.window.DialogBox', {
title: config.title || (multiple ? "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_DEFAULT_TITLE_MULTIPLE}}" : "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_DEFAULT_TITLE}}"),
iconCls: config.iconCls || 'ametysicon-list6',
width: simpleTree ? 400 : 800,
items: {
xtype: 'container',
layout: {
type: 'vbox',
align : 'stretch',
pack : 'start'
},
border: false,
items: [{
xtype: 'component',
padding: '5',
html: config.helpMessage || (multiple ? "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_HINT_MULTIPLE}}" : "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_HINT}}")
},
{
xtype: 'panel',
layout: 'border',
split: true,
height: 500,
flex: 1,
border: true,
items: items
}
]
},
closeAction: 'destroy',
referenceHolder: true,
defaultButton: 'validate',
buttons : [{
reference: 'validate',
itemId: 'ok-btn',
text: "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_OKBUTTON}}"
}, {
itemId: 'cancel-btn',
text: "{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_CANCELBUTTON}}",
handler: function(button) {
button.up('[xtype=dialog]').close();
}
}]
});
box.down("button[itemId='ok-btn']").setHandler (Ext.bind(this._validate, this, [box, config]));
if (!simpleTree)
{
tree.on('selectionChange', this._onSelectionChanged, this, {args: [box, config]});
}
return box;
},
/**
* This listener is called on the click event on an node is processed.
* @param {Ametys.window.DialogBox} box The current dialog box
* @param {Object} config The initial configuration object
* @param {Ext.selection.Model} sm The selection model
* @param {Ext.data.Model[]} records The selected records
* @private
*/
_onSelectionChanged: function (box, config, sm, records)
{
var cardPanel = box.down('#card');
if (records.length > 0)
{
if (!records[0].get('isSimple'))
{
this._updateContentDetails(box, config, records[0].get('contentId'));
cardPanel.setActiveItem(0);
}
else
{
// simple content selection
cardPanel.setActiveItem(1);
}
}
else
{
// empty selection
cardPanel.setActiveItem(1);
cardPanel.layout.getActiveItem().update(("{{i18n PLUGINS_CMS_HELPER_CHOOSEHIERARCHICALCONTENT_NO_SELECTION}}"))
}
},
/**
* Retrieve the current tree values, and call the callback function from the initial configuration sent to #open
* @param {Ametys.window.DialogBox} box The current dialog box
* @param {Object} config the initial config
* @private
*/
_validate: function (box, config)
{
if (Ext.isFunction(config.callback))
{
var tree = box.down("#tree");
var selectedNodes = config.multiple ? tree.getChecked() : tree.getSelectionModel().getSelection();
var autoposting = tree.isActiveAutoposting();
var hasAtLeastOneTopItem = false;
contentIds = [];
Ext.Array.each (selectedNodes, function (node) {
contentIds.push(node.get('contentId'));
if (config.activateTopItemAlert)
{
// Is it possible to be more specific on first level nodes?
if (node.getDepth() == 1
&& (node.hasChildNodes() || !node.isLeaf())
&& node.findChildBy(function(child) {
return child.get('checked') == true;
}, this, true) == null)
{
hasAtLeastOneTopItem = true;
}
}
}, this);
if (config.activateTopItemAlert && hasAtLeastOneTopItem)
{
// Display alert
Ametys.Msg.confirm(
config.topItemAlertTitle,
config.topItemAlertText,
function (buttonId)
{
if (buttonId == 'no')
{
config.callback.call(this, config.multiple ? contentIds : (contentIds.length > 0 ? contentIds[0] : null), autoposting);
box.close();
}
},
this
);
}
else
{
config.callback.call(this, config.multiple ? contentIds : (contentIds.length > 0 ? contentIds[0] : null), autoposting);
box.close();
}
}
},
/**
* Update the details panel for the given content
* @param {Ametys.window.DialogBox} box The current dialog box
* @param {Object} config The initial configuration object
* @param {String} contentId The id of content
* @private
*/
_updateContentDetails: function (box, config, contentId)
{
var additionParams = "&viewName=" + config.viewName;
// FIXME CMS-2316
var appParameters = Ametys.getAppParameters();
Ext.Object.each(appParameters, function(key, value) {
additionParams += '&' + key + '=' + encodeURIComponent(value);
});
var detailsUri = Ametys.CONTEXT_PATH + "/_content.html?contentId=" + contentId + additionParams;
var iframe = box.down('#iframe');
iframe.load(detailsUri)
}
});