/*
* Copyright 2018 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.
*/
/**
* Search sort field widget
* This widget is registered for fields of type Ametys.form.WidgetManager#TYPE_STRING
*/
Ext.define('Ametys.web.form.widget.SearchSort', {
extend: 'Ametys.web.form.widget.SearchField',
/**
* @cfg {String} [dependingFieldName] The relative path to a widget whose value will be the restriction of the store of the SearchSort field.
*/
/**
* @private
* @property {String} iconSortPlugin The plugin having the sort icons
*/
iconSortPlugin: 'cms',
/**
* @private
* @property {String} iconSortASC The page in the resources dir of the #iconSortPlugin plugin for the ASC sort image
*/
iconSortASC: 'img/widgets/ascending.png',
/**
* @private
* @property {String} iconSortDESC The page in the resources dir of the #iconSortPlugin plugin for the DESC sort image
*/
iconSortDESC: 'img/widgets/descending.png',
getServerId: function()
{
return "edition.search-sort";
},
/**
* @protected
* The model name for the store
* @return {String} model name for the store
*/
getStoreModel: function()
{
return 'Ametys.web.form.widget.SearchSort.Model';
},
constructor: function(config)
{
this.iconSorts = {
'ASC': Ametys.getPluginResourcesPrefix(this.iconSortPlugin) + '/' + this.iconSortASC,
'DESC': Ametys.getPluginResourcesPrefix(this.iconSortPlugin) + '/' + this.iconSortDESC
};
config.labelTpl = this._getLabelTpl();
config.labelHTML = true;
this.callParent(arguments);
},
initComponent: function()
{
this.cls = 'x-form-selectmetadatasort-widget';
if (this.dependingFieldName && this.form && Ext.isFunction(this.form.onRelativeFieldsChange))
{
this.form.onRelativeFieldsChange(this.dependingFieldName, this, this._onDependingFieldChange);
}
this.callParent(arguments);
},
/**
* @private
* Listener called when the value of the depending field changed.
* @param {Ext.form.field.Base} dependingField The field that its value will restrain the store of the sort field. Must be multiple.
* @param {String[]} newValue The new value of the depending field
* @param {String[]} oldValue the old value of the depending field
*/
_onDependingFieldChange: function(dependingField, newValue, oldValue)
{
// Clean current selection
if (newValue.length > 0)
{
var filteredValue = this.value
.map(this._decode)
.filter(function(sort) {
return Ext.Array.contains(newValue, sort.name);
});
this.setValue(filteredValue);
}
// Add a filter on the store if proposed sorts are not empty
var filters = this.getStore().getFilters();
filters.removeAll();
if (newValue.length > 0)
{
filters.add(function(sort) {
// only keep entries that are selected in the depending field
return Ext.Array.contains(newValue, sort.getId());
});
}
// else no filter as we want to allow all sorts from proposed sorts
},
initEvents: function()
{
this.callParent(arguments);
// Click listener on the combobox to deals with clickable entries.
this.mon(this.itemList, 'click', this._onComboboxItemListClick, this);
},
/**
* @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'),
clickValid = itemEl ? evt.getTarget('.clickable') : false,
record, name, sort;
if (clickValid)
{
record = this.getRecordByListItemNode(itemEl);
if (record)
{
record.invertIfPossible();
}
}
},
/**
* @private
* Gets the label template
* @return {String[]} the label template
*/
_getLabelTpl: function()
{
var labelTpl = [];
labelTpl.push('<tpl if="values.sort == \'ASC\'"><img class="clickable" width="16" height="16" src="' + this.iconSorts.ASC + '"/></tpl>');
labelTpl.push('<tpl if="values.sort == \'DESC\'"><img class="clickable" width="16" height="16" src="' + this.iconSorts.DESC + '{smallIcon}"/></tpl>');
labelTpl.push('<span>{[values.text]}</span>');
return labelTpl;
},
/**
* @private
* Decodes the given object
* @param {String/Object} valueObj The encoded (as string) object, or the object itself
* @return {Object} The decoded object
*/
_decode: function(valueObj)
{
if (Ext.isString(valueObj))
{
var decoded = Ext.decode(valueObj, true/*safe*/);
if (decoded == null)
{
decoded = {
name: valueObj,
sort: null
};
}
return decoded;
}
else
{
return valueObj
}
},
_isInStore: function(valueAsStr)
{
var decoded = this._decode(valueAsStr);
return this.getStore().indexOfId(decoded.name) > -1;
},
setValue: function(value)
{
var valueObjs = Ext.Array.from(value),
store = this.getStore(),
sortByNames = {};
Ext.Array.map(valueObjs, this._decode, this)
.forEach(function(valueObj) { sortByNames[valueObj.name] = valueObj.sort; });
this.callParent([Object.keys(sortByNames)]);
this.value = value;
Ext.Object.each(sortByNames, function(name, sort) {
var record = store.getById(name);
if (record && sort)
{
record.set('sort', sort);
}
});
},
getValue: function()
{
var value = Ext.Array.from(this.callParent(arguments)),
store = this.getStore();
function toObj(record)
{
return {
name: record.getId(),
sort: record.get('sort')
};
}
var valueObjs = value
.map(this._decode)
.map(function(valueObj) { return valueObj.name; })
.map(function(id) { return store.getById(id); })
.filter(function(record) { return record != null; })
.map(toObj)
.map(function(valueObj) { return Ext.encode(valueObj); });
return this.multiple ? valueObjs : (valueObjs.length > 0 ? valueObjs[0] : null);
}
});
/**
* @private
* The model used in the {@link Ametys.web.form.widget.SearchSort} store
*/
Ext.define('Ametys.web.form.widget.SearchSort.Model', {
extend: 'Ametys.web.form.widget.SearchFacet.Model',
fields: [
'availableOrders',
{
name: 'sort', convert: function(v, record) {
var availableOrders = record.get('availableOrders');
if (availableOrders.length == 1)
{
return availableOrders[0];
}
else
{
return v || 'ASC';
}
},
depends: ['availableOrders']
}
],
/**
* Inverts the sort direction, if possible (i.e. if both direction are present in availableOrders)
*/
invertIfPossible: function()
{
var availableOrders = this.get('availableOrders');
if (availableOrders.length == 1)
{
// Cannot invert, do nothing
}
else
{
var sort = this.get('sort');
this.set('sort', sort == 'DESC' ? 'ASC' : 'DESC');
}
}
});