/*
* Copyright 2013 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 contents.<br>
* This embeds a drop down list with querying on title of contents and type-ahead support.<br>
* Advanced search through a dialog box could be enable. See #cfg-allowSearch.<br>
* Allow content creation using #cfg-allowCreation.<br>
*
* This widget is the default widget registered for fields of type Ametys.form.WidgetManager#TYPE_CONTENT.<br>
*/
Ext.define('Ametys.cms.form.widget.SelectContent', {
extend: 'Ametys.form.AbstractQueryableComboBox',
/**
* @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 {Number} [initWorkflowActionId=1] The id of the initialize workflow action to create the content. Only used if the create content button is displayed.
*/
initWorkflowActionId: 1,
/**
* @cfg {Number} [initAndEditWorkflowActionId=11] The id of the initialize workflow action to create the content followed by an edition. Only used if the create content button is displayed.
*/
initAndEditWorkflowActionId: 11,
/**
* @cfg {Number} [editWorkflowActionId=2] The id of the workflow action to edit the content. Only used if the create content button is displayed.
*/
editWorkflowActionId: 2,
/**
* @cfg {String} [workflowName=content] The id of the workflow initialization function. Only used if the create content button is displayed.
*/
workflowName: 'content',
/**
* @cfg {Boolean} [limitToContextLanguage=true] True to limit the search to the context language. Default value to true.
*/
limitToContextLanguage: true,
/**
* @property {Ametys.cms.content.ContentType/Ametys.cms.content.ContentType[]} _contentTypes Array of content type displayed in the drop down list of the create content dialog box.
* Only used if the create content button is displayed.
* @protected
*/
/**
* @property {Boolean} _noValueOptionId The id of the 'No value' options.
* @private
* @readonly
*/
_noValueOptionId: '__ametys_none',
/**
* @cfg {String} [boxTitle] The title of the dialog box.
*/
boxTitle: "{{i18n PLUGINS_CMS_HELPER_SELECTCONTENTBYSEARCH_TITLE}}",
/**
* @cfg {String} [boxIcon=null] The path of the icon of the dialog box.
*/
boxIcon: null,
/**
* @cfg {String} [boxMinHeight=300] The minimum height of the dialog box.
*/
boxMinHeight: 300,
/**
* @cfg {String} [boxMaxHeight=300] The maximum height of the dialog box.
*/
boxMaxHeight: 600,
/**
* @cfg {String} [boxIconCls] The icon cls
*/
boxIconCls: 'ametysicon-document209 decorator-ametysicon-magnifier12',
/**
* @cfg {String} [boxForceMode] The force mode for the dialog box.
* @see Ametys.cms.uihelper.SelectContentBySearch.open
*/
boxForceMode: 'disabled',
/**
* @cfg {String} [helpMsg1] The message displayed at the top of the first card of search dialog box
*/
helpMsg1: "{{i18n PLUGINS_CMS_HELPER_SELECTCONTENTBYSEARCH_SEARCH_HINT}}",
/**
* @cfg {String} [helpMsg2] The message displayed at the top of the second card of search dialog box
*/
helpMsg2: "{{i18n PLUGINS_CMS_HELPER_SELECTCONTENTBYSEARCH_RESULT_HINT_MULTIPLE}}",
/**
* @cfg {String} [searchButtonText=""] The text of the search button.
* Note that if you supply a value for {@link #searchButtonConfig}, the searchButtonCfg.text
* value will be used instead if available.
*/
searchButtonText: '',
/**
* @cfg {String} [searchButtonIconCls="ametysicon-magnifier12"] One or more space separated CSS classes to be applied to the icon of search button. Only used if {@link #searchButtonIcon} is null.
* Note that if you supply a value for {@link #searchButtonConfig}, the searchButtonCfg.iconCls
* value will be used instead if available.
*/
searchButtonIconCls: 'ametysicon-magnifier12',
/**
* @cfg {String} [searchButtonIcon] The button icon path for the search button.
* Note that if you supply a value for {@link #searchButtonConfig}, the searchButtonCfg.icon
* value will be used instead if available.
*/
searchButtonIcon: null,
/**
* @cfg {String} searchButtonTooltip The button icon tooltip for the search button.
* Note that if you supply a value for {@link #searchButtonConfig}, the searchButtonCfg.tooltip
* value will be used instead if available.
*/
searchButtonTooltip: "{{i18n WIDGET_SELECTCONTENT_SEARCHBUTTON_TOOLTIP}}",
/**
* @cfg {Object} searchButtonConfig The configuration object for the button to search contents
*/
/**
* @cfg {String} [createButtonText=""] The text of the create content button.
* Note that if you supply a value for {@link #createButtonConfig}, the createButtonCfg.text
* value will be used instead if available.
*/
createButtonText: '',
/**
* @cfg {String} [createButtonIconCls="ametysicon-add64"] One or more space separated CSS classes to be applied to the icon of create button. Only used if {@link #createButtonIcon} is null.
* Note that if you supply a value for {@link #createButtonConfig}, the createButtonConfig.iconCls
* value will be used instead if available.
*/
createButtonIconCls: 'ametysicon-add64',
/**
* @cfg {String} [createButtonIcon] The button icon path for the create content button.
* Note that if you supply a value for {@link #createButtonConfig}, the createButtonCfg.icon
* value will be used instead if available.
*/
createButtonIcon: null,
/**
* @cfg {String} createButtonTooltip The button icon tooltip for the create button.
* Note that if you supply a value for {@link #createButtonConfig}, the createButtonCfg.tooltip
* value will be used instead if available.
*/
createButtonTooltip: "{{i18n WIDGET_SELECTCONTENT_CREATEBUTTON_TOOLTIP}}",
/**
* @cfg {String} [creationBoxTitle] The title of dialog box of content creation
* Note that if you supply a value for {@link #createButtonConfig}, the createButtonCfg.title
* value will be used instead if available.
*/
createBoxTitle: null,
/**
* @cfg {Object} createButtonConfig The configuration object for the button to create a content
*/
/**
* @cfg {String} [editButtonText=""] The text of the edit content button.
* Note that if you supply a value for {@link #editButtonConfig}, the editButtonCfg.text
* value will be used instead if available.
*/
editButtonText: '',
/**
* @cfg {String} [editButtonIconCls="ametysicon-add64"] One or more space separated CSS classes to be applied to the icon of create button. Only used if {@link #createButtonIcon} is null.
* Note that if you supply a value for {@link #editButtonConfig}, the editButtonConfig.iconCls
* value will be used instead if available.
*/
editButtonIconCls: 'ametysicon-art-pencil',
/**
* @cfg {String} [editButtonIcon] The button icon path for the create content button.
* Note that if you supply a value for {@link #editButtonConfig}, the editButtonCfg.icon
* value will be used instead if available.
*/
editButtonIcon: null,
/**
* @cfg {String} editButtonTooltip The button icon tooltip for the create button.
* Note that if you supply a value for {@link #editButtonConfig}, the editButtonConfig.tooltip
* value will be used instead if available.
*/
editButtonTooltip: "{{i18n WIDGET_SELECTCONTENT_EDITBUTTON_TOOLTIP}}",
/**
* @cfg {String} [editBoxTitle] The title of dialog box of content creation
* Note that if you supply a value for {@link #editButtonConfig}, the editButtonConfig.title
* value will be used instead if available.
*/
editBoxTitle: null,
/**
* @cfg {Object} editButtonConfig The configuration object for the button to create a content
*/
/**
* @cfg {String} [loadingText] The message displayed when loading the store.
*/
loadingText: "{{i18n WIDGET_SELECTCONTENT_LOADINGTEXT}}",
/**
* @cfg {String} [emptyText] The default text to place into an empty field.
*/
noResultText: "{{i18n WIDGET_SELECTCONTENT_EMPTYTEXT}}",
/**
* @cfg {String} [activateNoneValue=false] Set to `true` to activate the "none" value in the field.
*/
activateNoneValue: false,
/**
* @cfg {String} [noneValueText] The label of the optional "none" value to add in the field. Defaults to "WIDGET_SELECTCONTENT_NONEVALUETEXT"
*/
noneValueDefaultText: "{{i18n WIDGET_SELECTCONTENT_NONEVALUETEXT}}",
/**
* @cfg {Boolean} [displayTypeIcon=true] Set to `true` to display the content type icon in the selection boxes.
*/
displayTypeIcon: true,
/**
* @cfg {Number} [minChars=3] The minimum number of characters the user must type before autocomplete activates.
*/
minChars: 3,
/**
* @cfg {Boolean} [allowSearch=true] Set to `false` to disable advanced search.
*/
allowSearch: true,
/**
* @cfg {Boolean} [allowCreation=false] Set to `true` allow content creation. Note that if {@link #creatingContent} is set to 'true', creation will be always disallowed.
*/
allowCreation: false,
/**
* @cfg {Boolean} [allowEdition] Set to `true` to display a button to edit the currently selected linked contents. Set to `false` to hide this button. Set to empty/null (default value) to display the button only when the widget is used in grids.
*/
allowEdition: null,
/**
* @cfg {String} [editionView] The attributes view of the content type to use for edition
*/
editionView: null,
/**
* cfg {Boolean} [checkCreationRights=true] Set to `false` to not check rights on content types for content creation
*/
checkCreationRights: true,
/**
* @cfg {Boolean} [creatingContent=false] Set to `true` if a content is already being creating.
*/
creatingContent: false,
/**
* @cfg {Boolean} [openOnClick=true] Set to `false` to disable the opening of selected contents
*/
openOnClick: true,
/**
* @cfg {Boolean} [excludeSubContents=true] Set to `false` to search on subcontents
*/
excludeSubContents: true,
/**
* @cfg {Boolean} [includePrivate=false] Set to `true` allow creation of private content types.
*/
includePrivate: false,
/**
* @cfg {String} [modelId=search-ui.select-content] The id of model to use for search
*/
modelId: 'search-ui.select-content',
/**
* @cfg {String} solrRequest The solr request to select some contents only
*/
/**
/**
* @cfg {String} [growMax=300] If not set to `false`, the max height in pixels of the box select
*/
growMax: 300,
/**
* @cfg {String} [boxSize=default] If set to `large`, the select box width is the window width with a 0.8 ratio, otherwise `default` mode is for a width of 600 pixels
*/
boxSize: 'default',
/**
* @property {Ext.button.Button} searchButton The search contents button, if any.
* @protected
*/
/**
* @property {Ext.button.Button} createButton The create content button, if any.
* @protected
*/
/**
* @cfg {Boolean} [triggerOnClick=false] Set to `true` to activate the trigger when clicking in empty space in the field.
*/
triggerOnClick: false,
valueField: 'id',
displayField: 'title',
maxResult: 50,
nbResults: 0,
totalResults: 0,
listConfig: {
// Override the render template of boundlist to add a result bar when the search limit is reached
renderTpl: [
'<div id="{id}-results" class="{baseCls}-result-bbar">',
"<span>{{i18n WIDGET_SELECTCONTENT_RESULT_BAR_HINT_1}}</span> <span>{{i18n WIDGET_SELECTCONTENT_RESULT_BAR_HINT_2}}</span>",
'</div>',
'<div id="{id}-results2" class="{baseCls}-result-bbar">',
"<span>{{i18n WIDGET_SELECTCONTENT_RESULT_BAR_HINT2_1}}</span><span>{{i18n WIDGET_SELECTCONTENT_RESULT_BAR_HINT2_2}}</span>",
'</div>',
'<div id="{id}-listWrap" data-ref="listWrap"',
' class="{baseCls}-list-ct ', Ext.dom.Element.unselectableCls, '">',
'<ul id="{id}-listEl" data-ref="listEl" class="', Ext.baseCSSPrefix, 'list-plain"',
'<tpl foreach="ariaAttributes"> {$}="{.}"</tpl>',
'>',
'</ul>',
'</div>',
'{%',
'var pagingToolbar=values.$comp.pagingToolbar;',
'if (pagingToolbar) {',
'Ext.DomHelper.generateMarkup(pagingToolbar.getRenderTree(), out);',
'}',
'%}',
{
disableFormats: true
}
]
},
statics: {
/**
* Open the content tool on the given content.
* @param {String} contentId The ID of the content to open.
*/
openContent: function(contentId)
{
// Defer the call to let the focus happen before opening the tool.
Ext.defer(Ametys.tool.ToolsManager.openTool, 1, Ametys.tool.ToolsManager, ['uitool-content', {id: contentId}]);
}
},
constructor: function (config)
{
if (config.minChars)
{
config.minChars = Ext.isString(config.minChars) ? parseInt(config.minChars) : config.minChars;
}
if (config.maxResult)
{
config.maxResult = Ext.isString(config.maxResult) ? parseInt(config.maxResult) : config.maxResult;
}
config.limitToContextLanguage = config.limitToContextLanguage !== false && config.limitToContextLanguage != 'false';
this.callParent(arguments);
// Must be called after the parent as it will this.contentInfo set by the parent constructor
this.updateAdditionalWidgetsConf(config);
},
initComponent: function()
{
this.cls = 'x-form-selectcontent-widget';
this.callParent(arguments);
},
onFocusEnter: function(e)
{
this.callParent(arguments);
if (this.triggerDialogBoxOpened)
{
Ext.Function.defer(e.fromComponent.focus, 1, e.fromComponent);
}
},
/**
* @private
* Event when the combobox itemlist is clicked to open the content if required
* @param {Event} evt The click event
* @param {Ext.Element} el The item list
* @param {Object} o Options. Emtpy.
*/
_onComboboxItemListClick: function(evt, el, o)
{
// Handle clickable entry, in order to open the corresponding content.
var itemEl = evt.getTarget('.x-tagfield-item'),
spanEl = itemEl ? evt.getTarget('span.clickable') : false,
record;
if (spanEl)
{
record = this.combobox.getRecordByListItemNode(itemEl);
if (record)
{
Ametys.cms.form.widget.SelectContent.openContent(record.getId());
}
}
},
initEvents: function()
{
this.callParent(arguments);
// Click listener on the combobox to deals with clickable entries.
this.combobox.mon(this.combobox.itemList, 'click', this._onComboboxItemListClick, this);
this.combobox.addListener('change', this._onComboBoxChange, this);
},
getItems: function()
{
var items = this.callParent(arguments);
if (!this.readOnly)
{
var subitems = [];
// Button that opens the search dialog box.
if (this.allowSearch == true || this.allowSearch == 'true')
{
var searchButtonConfig = this.searchButtonConfig || {};
Ext.applyIf(searchButtonConfig, {
text: this.searchButtonText,
iconCls: this.searchButtonIcon ? null : this.searchButtonIconCls,
icon: this.searchButtonIcon,
tooltip: this.searchButtonTooltip,
handler: this.selectContentsBySearch,
scope: this
});
this.searchButton = Ext.create('Ext.button.Button', searchButtonConfig);
subitems.push(this.searchButton);
}
// Button that opens the create content dialog box.
if (this.contentType && (this.allowCreation == true || this.allowCreation == 'true') && !this.creatingContent)
{
// Get the content type and its sub-content types allowed to be created by the user
var checkRights = this.checkCreationRights !== false;
var contentTypesCollection = Ametys.cms.content.ContentTypeDAO.getContentType(this.contentType).getDescendantsOrSelf().createFiltered(function (contentType) {
return (contentType.hasRight() || !checkRights)
&& (!contentType.isPrivate() || !(this.includePrivate == true || this.includePrivate == 'true'))
&& !contentType.isMixin()
&& !contentType.isAbstract();
});
if (contentTypesCollection.count() > 0)
{
var createButtonConfig = this.createButtonConfig || {};
Ext.applyIf(createButtonConfig, {
text: this.createButtonText,
iconCls: this.createButtonIcon ? null : this.createButtonIconCls,
icon: this.createButtonIcon,
tooltip: this.createButtonTooltip,
handler: this.openCreateContentBox,
scope: this,
hidden: false
});
this.createButton = Ext.create('Ext.button.Button', createButtonConfig);
subitems.push(this.createButton);
this._contentTypes = contentTypesCollection.items;
}
}
// Button that allow to edit the contents in a dialogbox
if (this.contentType)
{
// At this time automatic edition mode cannot be determine. Let's insert the button as hidden and it will be display in #onAdded
var editButtonConfig = this.editButtonConfig || {};
Ext.applyIf(editButtonConfig, {
text: this.editButtonText,
iconCls: this.editButtonIcon ? null : this.editButtonIconCls,
icon: this.editButtonIcon,
tooltip: this.editButtonTooltip,
handler: this._startEdit,
scope: this,
disabled :true,
hidden: true
});
this.editionButton = Ext.create('Ext.button.Button', editButtonConfig);
subitems.push(this.editionButton)
}
if (subitems.length > 0)
{
items.push({
xtype: 'container',
itemId: 'toolbar',
items: subitems
});
}
}
return items;
},
onResize: function(w, h)
{
this.callParent(arguments);
var toolbar = this.getComponent("toolbar");
if (toolbar)
{
var nbVisibleItems = toolbar.items.filter("hidden", false).length;
var nbItemsSize = (nbVisibleItems * 24 + 2);
if (nbVisibleItems > 1)
{
var labelHeight = 0;
if (this.labelAlign == "top" && this.labelEl)
{
labelHeight = this.labelEl.getHeight();
}
if (this.bodyEl.getWidth() < 300)
{
toolbar.setWidth(27);
if (h < nbItemsSize)
{
this.setHeight(labelHeight + nbItemsSize);
}
}
else if (h >= nbItemsSize + labelHeight)
{
toolbar.setWidth(27);
}
else
{
toolbar.setWidth("auto");
}
}
}
},
onAdded: function(container, pos, instanced)
{
this.callParent(arguments);
if (this.editionButton)
{
if (this.allowEdition === true || this.allowEdition === "true")
{
this.allowEdition = true;
}
else if (this.allowEdition === false || this.allowEdition === "false")
{
this.allowEdition = false;
}
else
{
// Automatic mode
this.allowEdition = container instanceof Ext.grid.CellEditor;
}
if (this.allowEdition)
{
this.editionButton.show();
}
}
},
getLabelTpl: function ()
{
var labelTpl = [];
if (this.displayTypeIcon != false && this.displayTypeIcon != 'false')
{
labelTpl.push('<tpl if="values.iconGlyph != \'\'"><span class="x-tagfield-glyph {iconGlyph} {iconDecorator}"></span></tpl>');
labelTpl.push('<tpl if="values.iconGlyph == \'\'"><img width="16" height="16" src="' + Ametys.CONTEXT_PATH + '{smallIcon}"/></tpl>');
}
if (this.openOnClick == true || this.openOnClick == 'true')
{
labelTpl.push('<tpl if="values.clickable == true"><span class="clickable">{[values.title]}</span></tpl>');
labelTpl.push('<tpl if="values.clickable != true">{[values.title]}</tpl>');
}
else
{
labelTpl.push('{[values.title]}');
}
return labelTpl;
},
/**
* Open the dialog box to search contents.
*/
selectContentsBySearch: function()
{
this.triggerDialogBoxOpened = true;
Ametys.cms.uihelper.SelectContentBySearch.open({
icon: this.boxIcon,
iconCls: this.boxIconCls,
title: this.boxTitle,
boxSize: this.boxSize,
minHeight: this.boxMinHeight,
maxHeight: this.boxMaxHeight,
helpmessage1: this.helpMsg1,
helpmessage2: this.helpMsg2,
callback: Ext.bind(this._selectContentsCb, this),
multiple: this.multiple,
modelId: this.modelId,
contentType: this.contentType,
searchModelParameters: this._getSearchModelParameters(),
forceMode: this.boxForceMode,
forceValues: this._getAdditionalLoadValues()
});
},
/**
* Get the search model parameters
* @private
*/
_getSearchModelParameters: function()
{
let solrRequest = this.solrRequest;
if (solrRequest && this.contentInfo && this.contentInfo.contentId)
{
solrRequest = solrRequest.replace(/\$\{content.id\}/g, this.contentInfo.contentId);
}
return {
solrRequest: solrRequest,
restrictedContentType: this.contentType
};
},
/**
* This function is called after selecting contents in the search dialog box.
* Sets the value of the field.
* @param {String|String[]} contentIds The identifiers of selected content
* @private
*/
_selectContentsCb: function(contentIds)
{
if (contentIds != null)
{
this.combobox.setValue(this.multiple ? Ext.Array.merge(this.combobox.getValue(), contentIds)
: contentIds);
this._onComboBoxChange();
}
this.triggerDialogBoxOpened = false;
this.focus();
},
/**
* Open the dialog box to create a content.
*/
openCreateContentBox: function()
{
var me = this;
var openParams = Ext.apply({
title: this.createBoxTitle,
parentContentType: this.contentType,
contentTypes: this._contentTypes,
contentLanguage: this._getLanguage(),
initWorkflowActionId: this.initWorkflowActionId,
initAndEditWorkflowActionId: this.initAndEditWorkflowActionId,
editWorkflowActionId: this.editWorkflowActionId,
workflowName: this.workflowName,
closeCbFn: function() { me.triggerDialogBoxOpened = false; me.focus(); }
}, this._getAdditionalCreationParameters())
this.triggerDialogBoxOpened = true;
Ametys.cms.uihelper.CreateContent.open(openParams, this._openCreateContentBoxCb, this);
},
/**
* @protected
* Get additional parameters for creation
* @return {Object} Non empty
*/
_getAdditionalCreationParameters: function()
{
return {};
},
updateAdditionalWidgetsConf: function(config)
{
this.contentInfo = config.contentInfo;
// If a context is provided with a content id but without a lang
// set the lang of the content as the lang for the context
if (this.contentInfo && this.contentInfo.contentId != null && this.contentInfo.lang == null)
{
Ametys.cms.content.ContentDAO.getContent(this.contentInfo.contentId, c => {
this.contentInfo.lang = c.getLang();
})
}
// Delete lastQuery to force load of store next time the combo is expanded
delete this.combobox.lastQuery;
},
/**
* @private
* Retrieve the context language, i.e. either the content language if a content is being edited,
* or the current CMS language.
* @return {String} The language.
*/
_getLanguage: function()
{
var lang = null;
if (this.contentInfo != null && this.contentInfo.lang)
{
lang = this.contentInfo.lang;
}
else
{
lang = Ametys.cms.language.LanguageDAO.getCurrentLanguage();
}
return lang;
},
/**
* This function is called after a content has been created with the create content button.
* Add the content to the select field and open the new content in the content tool (in view mode).
* @param {String} contentId The identifier of created content
* @private
*/
_openCreateContentBoxCb: function(contentId)
{
this.combobox.getStore().on('load', function() {
// Wait for store to load, otherwise, the openCreateContent will blur the widget
// in a grid, bluring the widget leads to the widget removal and saves its value but the value is not updated yet
this.triggerDialogBoxOpened = false;
this.focus();
Ext.defer(this._openCreatedContent, 1, this, [contentId]);
}, this, { single: true } );
var oldValue = this.combobox.getValue();
//if not old value, or empty array, or the combobox is not multiselect, we set the value instead of adding it.
if (!oldValue || (Ext.isArray(oldValue) && oldValue.length == 0) || !this.combobox.multiSelect)
{
this.combobox.setValue(contentId);
this._onComboBoxChange();
}
else
{
this.combobox.addValue(contentId);
this._onComboBoxChange();
}
},
/**
* @protected
* After creation will open the content
* @param {String} contentId The id to open
*/
_openCreatedContent: function(contentId)
{
if (Ametys.tool.ToolsManager.getFactory('uitool-content'))
{
Ametys.tool.ToolsManager.openTool('uitool-content', {id: contentId, mode: 'view'});
}
},
getStore: function()
{
return Ext.create('Ext.data.Store', {
model: this._getModel(),
proxy: {
type: 'ametys',
plugin: 'cms',
url: 'select-content-search/list.json',
reader: {
type: 'json',
rootProperty: 'contents'
}
},
pageSize: this.maxResult,
remoteSort: true,
sortOnLoad: true,
sorters: [{property: 'title', direction:'ASC'}],
listeners: {
beforeload: {fn: this._onStoreBeforeLoad, scope: this},
load: {fn: this._onLoad, scope: this}
}
});
},
/**
* @private
* Get model for the store
*/
_getModel: function()
{
// Default implementation
return 'Ametys.cms.form.widget.SelectContent.ContentEntry';
},
/**
* @private
* Update the result bar if there is more results
* @param {Ext.data.Store} store The store.
*/
_onLoad: function(store)
{
// Update result bar
let resultEl = Ext.get(this.combobox.id + '-picker-results');
let resultEl2 = Ext.get(this.combobox.id + '-picker-results2');
if (resultEl)
{
if (store.totalCount > this.maxResult)
{
if (this.editable || (this.allowSearch == true || this.allowSearch == 'true'))
{
// Search limit is reached
resultEl.addCls("show");
}
else
{
// Search limit is reached
resultEl2.addCls("show");
}
}
else
{
// All results are visible
resultEl.removeCls("show");
resultEl2.removeCls("show");
}
}
// If the field is not multiple and the noneValue is activated, we add the "none" value at the beginning of the combobox
if (!this.multiple && (this.activateNoneValue == true || this.activateNoneValue == 'true'))
{
var noneValue = {};
// Set the title given
noneValue[this.displayField] = this.noneValueText || this.noneValueDefaultText;
// Set other attributes
noneValue[this.valueField] = this._noValueOptionId;
noneValue["clickable"] = false;
noneValue["iconGlyph"] = "ametysicon-sign-raw-forbidden";
// Add the new none value to the combobox store
store.insert(0, noneValue);
}
},
/**
* @private
* Set the request parameters before loading the store.
* @param {Ext.data.Store} store The store.
* @param {Ext.data.operation.Operation} operation The Ext.data.operation.Operation object that will be passed to the Proxy to load the Store.
*/
_onStoreBeforeLoad: function(store, operation)
{
operation.setParams( operation.getParams() || {} );
operation.setParams( Ext.apply(operation.getParams(), {
model: this.modelId
}));
var lang = this._getLanguage();
var values = {};
// Title criterion
var query = operation.getParams().query;
if (query)
{
// TODO Provide standard IDs
values['reference-title-like'] = '*' + query + '*';
}
values = Ext.apply(values, this._getAdditionalLoadValues());
operation.setParams( Ext.apply(operation.getParams(), {
'id': Ext.isEmpty(operation.getParams().id) ? null : operation.getParams().id.split(','),
'excludeSubContents': this.excludeSubContents,
'contextualParameters': {
'language': lang,
...this._getSearchModelParameters()
},
values: values
}));
},
/**
* @protected
* Get additional values used to load the combobox with values for search
* @return {Object} Non empty
*/
_getAdditionalLoadValues: function()
{
let values = {};
// Language criterion
// Only use the context language if there is a context
if (this.limitToContextLanguage && this.contentInfo)
{
// TODO Provide standard IDs
values['reference-contentLanguage-eq'] = this._getLanguage();
}
return values;
},
/**
* @private
* Listener of the edit button
*/
_startEdit: function()
{
if (!this.triggerDialogBoxOpened)
{
this.triggerDialogBoxOpened = true;
Ametys.cms.form.widget.SelectContent.EditContentsDialogBox.openDialog(this.getValue(), this.contentType, Ext.bind(this._afterEdit, this), {
title: this.getFieldLabel(),
view: this.editionView
});
}
},
/**
* @private
* Callback at the end of the edition process
* @param {Object/Object[]} contents The contents (ids and titles) select in the dialog box. Can be null if edition was canceled
*/
_afterEdit: function(contents)
{
var me = this;
this.triggerDialogBoxOpened = false;
if (contents)
{
// Some content might be missing due to right restriction.
// Do not assume that all values of the widget are present.
// Update title in the store of the underlying combobox
Ext.Array.each(Ext.Array.from(contents), function(content) {
var record = me.combobox.getStore().getById(content.id);
if (record)
{
record.set("title", content.title);
}
});
}
this.focus();
},
/**
* @private
* Listener when the unerlying combobox value change in order to enable the edit button
*/
_onComboBoxChange: function()
{
if (this.editionButton)
{
var finalValue = this.getValue();
this.editionButton.setDisabled(!finalValue || this.multiple && finalValue.length == 0)
}
},
setReadOnly: function(readOnly)
{
this.callParent(arguments);
if (this.searchButton)
{
this.searchButton.setVisible(!readOnly);
}
if (this.createButton)
{
this.createButton.setVisible(!readOnly);
}
},
setValue: function()
{
let a = this.callParent(arguments);
this._onComboBoxChange();
return a;
}
});