/*
* 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 class provides a widget to select one or more entry of a reference table content type.<br>
* This embeds a drop down list with querying on title of contents and type-ahead support.<br>
* Advanced search and content creation are disabled.<br>
*
* This widget is registered for fields of type Ametys.form.WidgetManager#TYPE_CONTENT.<br>
*/
Ext.define('Ametys.cms.form.widget.SelectReferenceTableContent', {
extend: 'Ametys.cms.form.widget.SelectContent',
allowSearch: false,
allowCreation: false,
openOnClick: false,
modelId: null,
/**
* @cfg {String} [contentType] The content type to allow search on. If not null, the search will be restricted the search to this content type (and its sub-types).
*/
contentType: null,
/**
* @cfg {Boolean} [allowHierarchicalTreeOpening=true] Set to `false` to not display the button for selecting the content in its potential hierarchy.
*/
allowHierarchicalTreeOpening: true,
/**
* @cfg {Object} openTreeButtonConfig The configuration object for the button to open hierarchical tree
*/
/**
* @cfg {String} [openTreeButtonText=""] The text of the button for opening the hierarchical tree.
* Note that if you supply a value for {@link #openTreeButtonConfig}, the openTreeButtonConfig.text
* value will be used instead if available.
*/
openTreeButtonText: '',
/**
* @cfg {String} [openTreeButtonIconCls="ametysicon-squares36"] One or more space separated CSS classes to be applied to the icon of button for opening the hierarchical tree. Only used if {@link #openTreeButtonIcon} is null.
* Note that if you supply a value for {@link #openTreeButtonConfig}, the openTreeButtonCfg.iconCls
* value will be used instead if available.
*/
openTreeButtonIconCls: 'ametysicon-squares36',
/**
* @cfg {String} [openTreeButtonIcon] The button icon path for the button for opening the hierarchical tree.
* Note that if you supply a value for {@link #openTreeButtonConfig}, the openTreeButtonCfg.icon
* value will be used instead if available.
*/
openTreeButtonIcon: null,
/**
* @cfg {String} openTreeButtonTooltip The button icon tooltip for the button for opening the hierarchical tree.
*/
openTreeButtonTooltip: "{{i18n WIDGET_SELECT_REFERENCETABLE_CONTENT_OPENTREEBUTTON_TOOLTIP}}",
/**
* @cfg {String} buttonAutopostingEnabledIconCls The separated CSS classes to apply to button for autoposting enabled
*/
buttonAutopostingEnabledIconCls: 'ametysicon-text decorator-ametysicon-check34 referencetable-autoposting referencetable-autoposting-enabled',
/**
* @cfg {String} buttonAutopostingDisabledIconCls The separated CSS classes to apply to button for autoposting disabled
*/
buttonAutopostingDisabledIconCls: 'ametysicon-text decorator-ametysicon-delete30 referencetable-autoposting referencetable-autoposting-disabled',
/**
* @cfg {String} [searchModelIdForContentsWithSameReferencing="search-ui.referencing-contents-with-same-values"] The id of search model for search on contents referencing widget's same values
*/
searchModelIdForContentsWithSameReferencing: 'search-ui.referencing-contents-with-same-values',
/**
* @cfg {Boolean} [allowSearchOnContentsWithSameReferencing=false] Set to `true` to display a button to search on contents referencing widget's same values
*/
allowSearchOnContentsWithSameReferencing: false,
/**
* @cfg {String} searchOnContentsWithSameReferencingButtonIcon The icon path for the button to open search tool on same referencing contents. Only used if {#cfg-allowSearchOnContentsWithSameReferencing} is true
*/
searchOnContentsWithSameReferencingButtonIcon: null,
/**
* @cfg {String} searchOnContentsWithSameReferencingButtonIconCls The separated CSS classes to apply to button for open search tool on same referencing contents. Only used if {#cfg-allowSearchOnContentsWithSameReferencing} is true
*/
searchOnContentsWithSameReferencingButtonIconCls: 'ametysicon-object-binoculars',
/**
* @cfg {String} searchOnContentsWithSameReferencingButtonTooltip The tooltip use for button to open search tool on same referencing contents. Only used if {#cfg-allowSearchOnContentsWithSameReferencing} is true
*/
searchOnContentsWithSameReferencingButtonTooltip: "{{i18n WIDGET_REFERENCE_TABLE_SEARCH_REFERENCING_CONTENTS_BUTTON_TOOLTIP}}",
/**
* @cfg {Boolean} [allowToggleAutoposting=false] Set to `true` to allow autoposting during search.
*/
allowToggleAutoposting: false,
/**
* @cfg {Boolean} [activateTopItemAlert=false] Set to 'true' to activate the alert when a item of first level (with children) is selected
*/
activateTopItemAlert: false,
/**
* @cfg {Boolean} [topItemAlertTitle] The title of alert when a item of first level (with children) is selected. If empty, the default alert title will be used. Only used if {#cfg-activateTopItemAlert} is true.
*/
/**
* @cfg {Boolean} [topItemAlertText] The text of alert when a item of first level (with children) is selected. If empty, the default alert text will be used. Only used if {#cfg-activateTopItemAlert} is true.
*/
/**
* @property {String} _activeAutoposting Set to 'true' to activate the autoposting.
* Only used if the create {@link #cfg-allowToggleAutoposting} has need set to true.
* @protected
*/
constructor: function (config)
{
config.allowToggleAutoposting = config.allowToggleAutoposting === true || config.allowToggleAutoposting == 'true';
config.activateTopItemAlert = config.activateTopItemAlert === true || config.activateTopItemAlert == 'true';
if (config.contentInfo && config.contentInfo.contentId)
{
config.allowSearchOnContentsWithSameReferencing = config.allowSearchOnContentsWithSameReferencing === true || config.allowSearchOnContentsWithSameReferencing == 'true';
}
else
{
// Search on contents with same referenced values necessary needs a current content
config.allowSearchOnContentsWithSameReferencing = false;
}
config.allowHierarchicalTreeOpening = config.allowHierarchicalTreeOpening !== false && config.allowHierarchicalTreeOpening !== "false";
config.limitToContextLanguage = false;
this.callParent(arguments);
},
initComponent: function()
{
if (this.modelId == null) // otherwise keep the modelId from config
{
this.modelId = "reference-table-search-ui." + this.contentType;
}
this.callParent(arguments);
},
getItems: function()
{
var items = this.callParent(arguments);
if (!this.readOnly
&& this.allowHierarchicalTreeOpening
&& this.contentType != null
&& Ametys.cms.content.ContentTypeDAO.getContentType(this.contentType).getParentMetadataName() != "")
{
var openTreeButtonConfig = this.openTreeButtonConfig || {};
Ext.applyIf(openTreeButtonConfig, {
itemId: "openTreeButton",
text: this.openTreeButtonText,
iconCls: this.openTreeButtonIcon ? null : this.openTreeButtonIconCls,
icon: this.openTreeButtonIcon,
tooltip: this.openTreeButtonTooltip,
handler: this._chooseContentInTree,
scope: this
});
this.openTreeButton = Ext.create('Ext.button.Button', openTreeButtonConfig);
items.push(this.openTreeButton);
}
if (this.allowToggleAutoposting)
{
this._activeAutoposting = true;
items.push(Ext.create('Ext.button.Button', {
itemId: 'toggle-autoposting',
text: '',
iconCls: this._activeAutoposting ? this.buttonAutopostingEnabledIconCls : this.buttonAutopostingDisabledIconCls,
tooltip: this._activeAutoposting ? "{{i18n WIDGET_REFERENCE_TABLE_AUTOPOSTING_ENABLED}}" : "{{i18n WIDGET_REFERENCE_TABLE_AUTOPOSTING_DISABLED}}",
enableToggle: true,
pressed: this._activeAutoposting,
toggleHandler: function (btn, state) {
this._activeAutoposting = state;
if (this._activeAutoposting)
{
btn.setIconCls(this.buttonAutopostingEnabledIconCls);
btn.setTooltip("{{i18n WIDGET_REFERENCE_TABLE_AUTOPOSTING_ENABLED}}")
}
else
{
btn.setIconCls(this.buttonAutopostingDisabledIconCls);
btn.setTooltip("{{i18n WIDGET_REFERENCE_TABLE_AUTOPOSTING_DISABLED}}");
}
},
scope: this
}));
}
if (this.allowSearchOnContentsWithSameReferencing)
{
items.push(Ext.create('Ext.button.Button', {
itemId: 'search-same-referencing-contents',
text: '',
iconCls: this.searchOnContentsWithSameReferencingButtonIcon ? null : this.searchOnContentsWithSameReferencingButtonIconCls,
tooltip: this.searchOnContentsWithSameReferencingButtonTooltip,
handler: this.searchOnContentsWithSameReferencing,
disabled: true,
scope: this
}));
this.combobox.on("change", this._onValueChange, this);
}
return items;
},
setValue: function(value)
{
if (Ext.isObject(value) && value.value)
{
if (this.allowToggleAutoposting)
{
this.items.get('toggle-autoposting').toggle(value.autoposting || false);
}
value = value.value;
}
this.callParent([value]);
},
getValue: function ()
{
var value = this.callParent(arguments);
if (this.allowToggleAutoposting == true)
{
if (!Ext.isEmpty(value))
{
return {
value: value,
autoposting: this._activeAutoposting
};
}
}
return value;
},
getSubmitValue: function ()
{
return this.multiple || (this.allowToggleAutoposting == true || this.allowToggleAutoposting == 'true') ? Ext.encode(this.getValue()) : this.getValue();
},
/**
* @private
* Listener when the value change, to enable/disable the button to see referencing contents.
* @param {Ext.form.field.Tag} combobox The combobox
* @param {String|String[]} newValue The new value
* @param {String|String[]} oldValue The old value
*/
_onValueChange: function(combobox, newValue, oldValue)
{
var searchReferencingBtn = this.down('#search-same-referencing-contents');
if (searchReferencingBtn)
{
searchReferencingBtn.setDisabled(Ext.isEmpty(newValue));
}
},
/**
* @private
* Open the dialog box to display the hierarchy of reference tables.
*/
_chooseContentInTree: function()
{
var ids = this._getIds();
Ametys.cms.uihelper.ChooseHierarchicalContent.open({
allowToggleAutoposting: this.allowToggleAutoposting,
activeAutoposting: this._activeAutoposting,
activateTopItemAlert: this.activateTopItemAlert,
topItemAlertTitle: this.topItemAlertTitle,
topItemAlertText: this.topItemAlertText,
leafContentType: this.contentType,
multiple: this.multiple,
values: ids,
callback: Ext.bind(this._chooseContentInTreeCb, this)
});
},
/**
* @private
* Callback function after some contents have been selected in the helper.
* Select the contents in the combobox.
* @param {String[]} contents The ids of the selected contents in the tree
* @param {Boolean} autoposting 'true' if the autoposting button is activated
*/
_chooseContentInTreeCb: function(contents, autoposting)
{
contents = Ext.Array.from(contents);
this.setValue({
value : (this.multiple ? contents : (contents.length > 0 ? contents[0] : null)),
autoposting: autoposting
});
},
/**
* @private
* Get the ids of the values selected
*/
_getIds: function()
{
var values = this.getValue();
var ids = [];
if (values)
{
values = Ext.Array.from(values);
Ext.Array.each(values, function(v) {
if (Ext.isObject(v) && v.value)
{
ids.push(v.value);
}
else
{
ids.push(v);
}
})
}
return ids;
},
/**
* Open a search tool with the referencing contents.
*/
searchOnContentsWithSameReferencing: function ()
{
if (this.contentInfo && this.contentInfo.contentId)
{
var fieldName = this.getName();
var fieldNamePrefix = this.form.fieldNamePrefix;
fieldName = Ext.String.startsWith (fieldName, fieldNamePrefix) ? fieldName.substring(fieldNamePrefix.length) : fieldName;
var referenceFieldPath = [];
var pathSegments = fieldName.split('.');
for (var i=0; i < pathSegments.length; i++)
{
// Remove repeater entry from path
if (!/^[0-9]+$/.test(pathSegments[i]))
{
referenceFieldPath.push(pathSegments[i]);
}
}
var referenceField = referenceFieldPath.join('.');
var value = this.getValue();
if (Ext.isObject(value) && value.value)
{
value = value.value;
}
value = Ext.Array.from(value);
if (value.length > 0)
{
// Defer the call to let the focus happen before opening the tool.
Ext.defer(Ametys.tool.ToolsManager.openTool, 1, Ametys.tool.ToolsManager, ['uitool-search-referencing-contents-with-same-values', {
contentId: this.contentInfo.contentId,
referenceField: referenceField,
referenceValues: value,
modelId: this.searchModelIdForContentsWithSameReferencing,
id: referenceField + ';' + value.sort().join('-'),
startSearchAtOpening: true
}]);
}
}
else
{
this.getLogger().warn({message: "Missing contentInfo/contentId property : search on contents with same referenced values is not available ouside a content"});
}
},
onAdded: function(container, pos, instanced)
{
if (this.allowEdition === null || this.allowEdition === undefined)
{
// Forcing false, otherwise the super will put it to true when in a grid (that we don't want for reference tables)
this.allowEdition = false;
}
this.callParent(arguments);
}
});