/*
* Copyright 2023 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 tool is an abstract class allowing to search some items based on AbstractSearchTool, it allows facets.
*/
Ext.define('Ametys.plugins.cms.search.AbstractFacetedSearchTool', {
extend: "Ametys.plugins.cms.search.AbstractSearchTool",
getBottomPanelItems: function()
{
var items = this.callParent(arguments); // array with one item: result grid. We will add the facet panel (on first index of the items array)
this.facetPanel = this._createFacetPanel();
items.splice(0, 0, this.facetPanel); // insert facetPanel at the 0-index position, removing 0 items
return items;
},
/**
* @protected
* Create the tree panel for the facets
* @return {Ext.tree.Panel} The created tree panel
*/
_createFacetPanel: function ()
{
this._createFacetModel();
var facetStore = Ext.create('Ext.data.TreeStore', {
model: this._facetModelName,
autoLoad: false,
autoDestroy: true,
// root: {
// expanded: false
// },
proxy: {
type: 'memory',
reader: {
type: 'json'
}
},
// filters: [
// function(node) {
// return node.get('type') != 'facet' || node.get('count') > 0;
// }
// ],
sorters: [{
sorterFn: function(n1, n2) {
if (n1.get('type') == 'facet' && n1.get('type') == 'facet')
{
let v1 = Ext.data.SortTypes.asNonAccentedUCString(n1.get('label') || n1.get('value'));
let v2 = Ext.data.SortTypes.asNonAccentedUCString(n2.get('label') || n2.get('value'));
return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
}
return 0;
}
}]
});
var facetPanel = Ext.create('Ext.tree.Panel', {
title: "{{i18n PLUGINS_CMS_UITOOL_SEARCH_FACET_PANEL}}",
region: 'west',
width: 200,
collapsible: true,
border: false,
split: true,
maxWidth: 500,
rootVisible: false,
itemId: 'facet-tree',
cls: 'search-tool-facet-tree',
layout: 'fit',
viewConfig: {
markDirty: false
},
store: facetStore,
listeners: {
'checkchange': this._onCheckFacet,
scope: this
}
});
// All the following block is juste to remove border on the place holder without any bug
// We do create an interceptor
facetPanel.__getPlaceholder = facetPanel.getPlaceholder;
facetPanel.getPlaceholder = function() {
var result = facetPanel.__getPlaceholder();
// Modify the initial result
result.on('render', function(ph) { ph.setBorder(false); }, null, { single: true });
// Reset the interceptor after first use
facetPanel.getPlaceholder = facetPanel.__getPlaceholder;
return result;
}
// Disable row selection.
facetPanel.getSelectionModel().on('beforeselect', function () {return false;});
return facetPanel;
},
/**
* Creates the model for the facet store.
* @private
*/
_createFacetModel: function()
{
fields = [
{name: 'text', mapping: 'label', type: 'string'},
{name: 'label', type: 'string'},
{name: 'name'},
{name: 'value'},
{name: 'count', type: 'int'},
{name: 'type'}
];
if (!this._facetModelName)
{
this._facetModelName = this.getId() + '-SearchFacet';
if (!Ext.data.schema.Schema.get('default').hasEntity(this._facetModelName))
{
Ext.define(this._facetModelName, {
extend: 'Ext.data.TreeModel',
schema: 'default',
fields: fields,
listeners: {
beforeappend: {fn: function(parentNode, node, eOpts)
{
var type = node.get('type');
if (type == 'criterion')
{
node.set('leaf', false);
node.set('cls', 'criterion');
}
else if (type == 'facet')
{
var value = node.get('value');
var label = node.get('label') || value;
var count = node.get('count');
node.set('text', label + ' (' + count + ')');
node.set('leaf', true);
node.set('checked', false);
node.set('cls', 'facet');
if (count === 0)
{
return false;
}
}
}, scope: this}
}
});
}
else
{
//Ext.data.schema.Schema.get('default').getEntity(this._facetModelName).replaceFields(fields, true);
//FIXME remove else statement if line above useless
}
}
},
/**
* @private
* Listener when node's checked property changes
* Relaunch the search
* @param {Ext.data.NodeInterface} node The node who's checked property was changed
* @param {Boolean} checked The node's new checked state
*/
_onCheckFacet: function(node, checked)
{
if (node.get('type') == 'facet')
{
this._launchSearch({faceting: true});
}
},
/**
* @inheritdoc
* @param {Object/Ext.button.Button} [params] Additional parameters, or the button which was clicked if this function was bound to a button
* @param {Boolean} [params.faceting] true if the search was launch from facet tree.
* @param {Function} [callback] Callback function to execute after search
* @param {Object} [scope] The scope for callback function
*/
_launchSearch: function(params, callback, scope)
{
params = params || {};
this._faceting = Ext.isBoolean(params.faceting) ? params.faceting : false;
if (!this._faceting)
{
this.facetPanel.getStore().clearFilter(true);
}
this.callParent([callback, scope]);
},
/**
* Updates the facet tree panel
* @param {Object} facets The facets
* @private
*/
_updateFacetPanel: function(facets)
{
Ext.suspendLayouts();
try
{
var store = this.facetPanel.getStore();
store.clearFilter(true);
var root = this.facetPanel.getRootNode();
Ext.Array.forEach(root.childNodes, function(criterionNode) {
var name = criterionNode.get('name');
var facetToFind = Ext.Array.findBy(facets, function(facet) {return facet.name == name;}) || {};
var facetValues = facetToFind.children || [];
this._updateFacetValues(criterionNode, facetValues);
}, this);
// Hide facet with count = 0
store.filterBy(function(record) {
return record.get('type') != 'facet' || record.get('count') > 0;
});
}
finally
{
Ext.resumeLayouts(true);
}
},
/**
* @private
* Updates facet
* @param {Ext.data.NodeInterface} criterionNode The node holding the facet criterion
* @param {Object} facetValues The values
*/
_updateFacetValues: function(criterionNode, facetValues)
{
Ext.Array.forEach(criterionNode.childNodes, function(facetNode) {
var value = facetNode.get('value');
var label = facetNode.get('label') || value;
var facet = Ext.Array.findBy(facetValues, function(facetValue){return facetValue.value == value;}) || {};
facetNode.set({
'count': facet.count,
'text': label + ' (' + facet.count + ')'
});
}, this);
},
/**
* Get the facet values.
* Call this method to provide the facet params to the search
* @return {Object} The facet values
*/
getFacetValues: function ()
{
var facetValues = {};
if (this.facetPanel)
{
var checkedFacets = this.facetPanel.getChecked();
for (var i = 0; i < checkedFacets.length; i++)
{
var criterionName = checkedFacets[i].parentNode.get('name');
var value = checkedFacets[i].get('value');
if (facetValues[criterionName] == null)
{
facetValues[criterionName] = [];
}
facetValues[criterionName].push(value);
}
}
return facetValues;
},
});