/*
* 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 pages.<br>
* This embeds a drop down list with querying on title of pages and type-ahead support.<br>
* A dialog box also allow to select pages in sitemap tree.<br>
* See {@link Ametys.web.helper.ChoosePage}<br>
*
* This widget is registered for fields of type Ametys.form.WidgetManager#TYPE_STRING
*/
Ext.define('Ametys.web.form.widget.SelectPage', {
extend: 'Ametys.form.AbstractQueryableComboBox',
statics: {
/**
* @property {String} [SITE_CONTEXT_CURRENT="current"] Context of site for using current site only.
*/
SITE_CONTEXT_CURRENT: "current",
/**
* @property {String} [SITE_CONTEXT_ALL="all"] Context of site for choosing site in a combo box of available sites.
*/
SITE_CONTEXT_ALL: "all",
/**
* @property {String} [SITEMAP_CONTEXT_ALL="all"] Context of sitemap for choosing language in a combo box of available languages.
*/
SITEMAP_CONTEXT_ALL: "all",
/**
* @property {String} [SITEMAP_CONTEXT_CURRENT="current"] Context of sitemap for using current sitemap only.
*/
SITEMAP_CONTEXT_CURRENT: "current",
/**
* Open the page tool on the given page.
* @param {String} pageId The ID of the page to open.
*/
openPage: function(pageId)
{
// Defer the call to let the focus happen before opening the tool.
Ext.defer(Ametys.tool.ToolsManager.openTool, 1, Ametys.tool.ToolsManager, ['uitool-page', {id: pageId}]);
}
},
/**
* @cfg {String} [sitesField] The relative path to a sites widget.
* If not empty, the select page widget will be disabled if several sites are selected
*/
/**
* @private
* @property {String[]} _sitesFieldName The property related to {@link #cfg-sitesField}
*/
/**
* @cfg {String} [enableWithFieldName] The relative path to a widget whose value will enable or disable
* this widget. See {@link #cfg-enableOnFieldValues} for the values checked.
*/
/**
* @private
* @property {String[]} _enableWithFieldName The property related to {@link #cfg-enableWithFieldName}
*/
/**
* @cfg {String} [enableOnFieldValues] The value or list of values of the {@link #cfg-enableWithFieldName}
* to enable this widget.
*/
/**
* @private
* @property {String[]} _enableOnFieldValues The property related to {@link #cfg-enableOnFieldValues}
*/
/**
* @cfg {Boolean} [multiple=false] True to allow multi-selection and display checkboxes (defaults to false).
*/
multiple: false,
/**
* @cfg {String} [boxTitle] The title of the dialog box.
*/
/**
* @cfg {String} [boxIcon] The title of the dialog box.
*/
/**
* @cfg {String} [helpMsg] The message displayed at the top of dialog box
*/
/**
* @cfg {Object} buttonConfig The configuration that will be transmitted to the button. The handler cannot be changed, moreover be aware of the behavior of #cfg-buttonText, #cfg-buttonIcon and #cfg-IconCls.
*/
/**
* @cfg {String} [buttonText=""] The text of the select page button.
* Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.text
* value will be used instead if available.
*/
buttonText: '',
/**
* @cfg {String} buttonIcon The button icon path for the select button.
* Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.icon
* value will be used instead if available.
*/
buttonIcon: null,
/**
* @cfg {String} buttonIconCls The CSS class to apply to the select button
* Note that if you supply a value for {@link #buttonConfig}, the buttonConfig.icon
* value will be used instead if available.
*/
buttonIconCls: 'ametysicon-website38',
/**
* @cfg {String} buttonTooltip The button icon tooltip for the select button.
*/
buttonTooltip: "{{i18n PLUGINS_WEB_WIDGET_SITEMAPWIDGET_SELECTPAGE}}",
/**
* @cfg {Number} [minChars=3] The minimum number of characters the user must type before autocomplete activates.
*/
minChars: 3,
/**
* @cfg {Boolean} [openOnClick=true] Set to `false` to disable the opening of selected pages
*/
openOnClick: true,
/**
* @cfg {String} [growMax=300] If not set to `false`, the max height in pixels of the box select
*/
growMax: 300,
/**
* @property {Ext.button.Button} selectButton The select pages 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,
/**
* @cfg {Boolean} [hideTrigger=true] Set to `false` to show trigger
*/
/*hideTrigger: true,*/
valueField: 'id',
displayField: 'title',
maxResult: 50,
/**
* @cfg {String} [siteContext=Ametys.web.form.widget.SelectPage.SITE_CONTEXT_CURRENT] The site context.
* Valid contexts are:
* <ul>
* <li>Ametys.web.form.widget.SelectPage.SITE_CONTEXT_CURRENT for current site only</li>
* <li>Ametys.web.form.widget.SelectPage.SITE_CONTEXT_ALL for all sites</li>
* </ul>
*/
/**
* @cfg {String} [sitemapContext=Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL] The sitemap context.
* Valid contexts are:
* <ul>
* <li>Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_CURRENT for current sitemap only</li>
* <li>Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL for all languages</li>
* <li>a language code such as 'fr', 'en', .. for using a specifying language.</li>
* </ul>
*/
/**
* @cfg {String} choosePageDialogTitle Title of the dialog box to choose page(s). See {@link Ametys.web.helper.ChoosePage#open}.
*/
/**
* @cfg {String} choosePageDialogIcon The full icon path for the dialog box to choose page(s). See {@link Ametys.web.helper.ChoosePage#open}.
*/
/**
* @cfg {String} choosePageDialogHint The help message to display on top of dialog box to choose page(s). See {@link Ametys.web.helper.ChoosePage#open}.
*/
/**
* @protected
* @property {Boolean} _listenToClick True to have a listener when a page is clicked
*/
_listenToClick: true,
initComponent: function()
{
this.cls = 'x-form-selectpage-widget';
// remember the desired allowBlank policy
this._configuredAllowBlank = this.allowBlank;
this._sitesFieldName = this.sitesField || null;
if (this._sitesFieldName && this.form && Ext.isFunction(this.form.onRelativeFieldsChange))
{
this.form.onRelativeFieldsChange(this._sitesFieldName, this, this._sitesFieldChange);
}
this._enableWithFieldName = this.enableWithFieldName || null;
this._enableOnFieldValues = this.enableOnFieldValues || null;
if (this._enableOnFieldValues != null && !Ext.isArray(this._enableOnFieldValues))
{
this._enableOnFieldValues = this._enableOnFieldValues.split(",");
}
if (this._enableWithFieldName && this.form && Ext.isFunction(this.form.onRelativeFieldsChange))
{
this.form.onRelativeFieldsChange(this._enableWithFieldName, this, this._enableWithFieldChange);
}
this.callParent(arguments);
},
/**
* @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.web.form.widget.SelectPage.openPage(record.getId());
}
}
},
initEvents: function()
{
this.callParent(arguments);
if (this._listenToClick)
{
// Click listener on the combobox to deals with clickable entries.
this.combobox.mon(this.combobox.itemList, 'click', this._onComboboxItemListClick, this);
}
},
getItems: function()
{
var items = this.callParent(arguments);
// Button that opens the search dialog box.
if (!this.readOnly)
{
var buttonConfig = this.buttonConfig || {};
Ext.applyIf(buttonConfig, {
text: this.buttonText,
icon: this.buttonIcon,
iconCls: this.buttonIcon ? null : this.buttonIconCls,
tooltip: this.buttonTooltip,
handler: this.choosePage,
scope: this
});
this.selectButton = Ext.create('Ext.button.Button', buttonConfig);
items.push(this.selectButton);
}
return items;
},
getLabelTpl: function ()
{
var labelTpl = [];
if (this.openOnClick == true || this.openOnClick == 'true')
{
labelTpl.push('<span class="clickable">{[values.title]}</span>');
}
else
{
labelTpl.push('{[values.title]}');
}
return labelTpl;
},
/**
* @private
* Listener called when the value of the site field changes
*/
_sitesFieldChange: function()
{
var sitesField = this.form.getRelativeField(this._sitesFieldName, this),
siteContext = sitesField ? sitesField.getSiteContext() : null,
sites = sitesField ? sitesField.getSiteValues() : null;
this.siteFieldChanged(siteContext, sites);
},
/**
* if no sitesField was given, call manually this method to update site context and sites
* @param {String} siteContext site context
* @param {String[]} sites list of sites
*/
siteFieldChanged: function(siteContext, sites)
{
var enabled = siteContext == Ametys.web.form.widget.SelectSite.SITE_CONTEXT_CURRENT
|| (sites != null && sites.length == 1);
if (!enabled)
{
this.disable();
this.allowBlank = true;
this.combobox.allowBlank = true;
this.setValue(null);
this.combobox.lastQuery = null;
this.clearInvalid();
}
else
{
var newSiteName = siteContext == Ametys.web.form.widget.SelectSite.SITE_CONTEXT_CURRENT ? Ametys.getAppParameters().siteName : sites[0];
if (this.siteName != newSiteName && this.siteName /* the last part is mandatory to not reset the current value when the field is initialized */)
{
this.setValue(null);
this.combobox.lastQuery = null;
}
this.siteName = newSiteName;
if (this.isDisabled())
{
this.enable();
this.allowBlank = this._configuredAllowBlank;
this.combobox.allowBlank = this._configuredAllowBlank;
}
}
},
/**
* Listener called when the value of the FO search mode changes
*/
_enableWithFieldChange: function()
{
var fieldValue = this.form.getRelativeField(this._enableWithFieldName, this).getValue();
if (this._enableOnFieldValues != null && !Ext.Array.contains(this._enableOnFieldValues, fieldValue))
{
this.disable();
this.allowBlank = true;
this.combobox.allowBlank = true;
this.setValue(null);
this.combobox.lastQuery = null;
this.clearInvalid();
}
else
{
this.enable();
this.allowBlank = this._configuredAllowBlank;
this.combobox.allowBlank = this._configuredAllowBlank;
this.reset();
}
},
/**
* Open the dialog box to select pages in sitemap
*/
choosePage: function()
{
var values = this.getValue();
values = values ? (Ext.isArray(values) ? Ext.Array.clone(values) : [values]) : [];
var siteContext = (this.siteContext == Ametys.web.form.widget.SelectPage.SITE_CONTEXT_ALL) ? Ametys.web.helper.ContextToolbar.SITE_CONTEXT_ALL : Ametys.web.helper.ContextToolbar.SITE_CONTEXT_CURRENT;
var defaultSitemapName;
var sitemapContext;
if (this.sitemapContext == Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_CURRENT)
{
sitemapContext = this._getCurrentSitemapName();
defaultSitemapName = this._getCurrentSitemapName();
}
else if (this.sitemapContext == Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL)
{
sitemapContext = Ametys.web.helper.ContextToolbar.SITEMAP_CONTEXT_ALL;
defaultSitemapName = this._getCurrentSitemapName();
}
else
{
sitemapContext = this.sitemapContext;
defaultSitemapName = this.sitemapContext;
}
var config = {
title: this.choosePageDialogTitle,
iconCls: this.choosePageDialogIconCls,
helpMessage: this.choosePageDialogHint,
values: values,
multiple: this.multiple,
siteContext: siteContext,
sitemapContext: sitemapContext,
defaultSitemapName: defaultSitemapName,
defaultSiteName: this.siteName,
showSelectDecorators: this.showSelectDecorators,
callback: Ext.bind(this._choosePageCb, this)
};
this.triggerDialogBoxOpened = true;
Ametys.web.helper.ChoosePage.open(config);
},
/**
* This function is called after selecting pages
* Sets the value of the field.
* @param {String|String[]} pageIds The identifiers of selected pages
* @private
*/
_choosePageCb: function(pageIds)
{
this.triggerDialogBoxOpened = false;
if (pageIds !== undefined)
{
pageIds = Ext.Array.from(pageIds);
this.setValue(pageIds);
}
},
/**
* Get the current language
* @return the current language
*/
_getCurrentSitemapName: function ()
{
// First search in current selection
var pageTarget = Ametys.message.MessageBus.getCurrentSelectionMessage().getTarget(Ametys.message.MessageTarget.PAGE);
if (pageTarget != null)
{
return pageTarget.getParameters().lang;
}
return Ametys.cms.language.LanguageDAO.getCurrentLanguage();
},
getStore: function()
{
return Ext.create('Ext.data.Store', {
model: 'Ametys.web.form.widget.SelectPage.PageEntry',
proxy: {
type: 'ametys',
plugin: 'web',
url: 'search-pages',
reader: {
type: 'json',
rootProperty: 'pages'
}
},
pageSize: this.maxResult,
remoteSort: true,
sortOnLoad: true,
sorters: [{property: 'title', direction:'ASC'}],
listeners: {
beforeload: {fn: this._onStoreBeforeLoad, scope: this}
}
});
},
/**
* 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)
{
var lang = null;
if (this.sitemapContext == Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_CURRENT)
{
lang = this._getCurrentSitemapName();
}
else if (this.sitemapContext != Ametys.web.form.widget.SelectPage.SITEMAP_CONTEXT_ALL)
{
lang = this.sitemapContext;
}
else
{
lang = this._getCurrentSitemapName();
}
var siteName = this.siteName || (this.siteContext == Ametys.web.helper.ContextToolbar.SITE_CONTEXT_CURRENT ? Ametys.getAppParameters().siteName : null);
var query = operation.getParams().query;
if (query)
{
query = '*' + query + '*';
}
operation.setParams( operation.getParams() || {} );
operation.setParams( Ext.apply(operation.getParams(), {
'ids': Ext.isEmpty(operation.getParams().id) ? null : operation.getParams().id.split(','),
siteName: siteName,
lang: lang,
query: query
}));
}
});