/*
* Copyright 2024 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.
*/
/**
* Field to query and select one right.
* To facilitate the selection of a right. It's possible to restrict the list of
* right by selecting a profile
*/
Ext.define('Ametys.form.field.RightByProfile', {
extend: 'Ametys.form.AbstractFieldsWrapper',
statics:
{
/**
* @readonly
* @protected
* @property {String} ALL_PROFILES value of the profile combobox to ignore filtering by profile
*/
ALL_PROFILES: "#ALL#",
/**
* @readonly
* @property {String} READER_PROFILE id of the reader profile
*/
READER_PROFILE: "READER"
},
/**
* @cfg {boolean} [showProfilesIncludingRight=false] true to display a line
* of text below the selectors to list all the profile including the selected
* right
*/
/**
* @private
* @property {Ext.data.Store} _profileStore The store of the profile combobox
*/
initComponent: function()
{
var rightCfg = {
xtype: 'edition.right',
itemId: 'select-right',
cls: 'ametys',
includeReader: true,
allowBlank: this.allowBlank,
flex: 2
}
var selectors = [
{
xtype: 'combobox',
itemId: 'select-profile',
editable: false,
queryMode: "local", // remote is useless on non editable field
value: Ametys.form.field.RightByProfile.ALL_PROFILES,
forceSelection: true,
cls: 'ametys',
flex: 1,
maxWidth: 120,
valueField: "id",
displayField: "label",
store: this._createProfileStore(),
listeners: {
change: this._onProfileChange,
scope: this
},
listConfig: {
getInnerTpl: function(displayField) {
return '{[Ext.String.escapeHtml(values.' + displayField + ')]}';
}
}
},
rightCfg
];
this.items = [{
xtype: 'container',
layout: {
type: 'hbox',
align: 'stretch'
},
items : selectors
}, {
padding: "2 0 0 0",
html: "",
visible: false,
}];
this.layout = {
type: 'vbox',
align: 'stretch'
};
this._includedTpl = new Ext.XTemplate(
'{{i18n PLUGINS_CORE_UI_WIDGET_RIGHT_BY_PROFILE_CONTAINING_PROFILE}}',
'<tpl for="." between=", "><strong>{.}</strong></tpl>'
);
this.callParent(arguments);
},
getValue: function()
{
return this.items.get(0).getComponent('select-right').getValue();
},
setValue: function(value)
{
return this.items.get(0).getComponent('select-right').setValue(value);
},
/**
* @private
* @return {Ext.data.Store} A newly created store for the profile
*/
_createProfileStore: function()
{
this._profileStore = Ext.create('Ext.data.Store', {
autoDestroy: true,
autoLoad: true,
proxy: {
type: 'ametys',
plugin: 'core',
url: 'rights/profiles.json',
extraParams: {
limit: null, // No pagination
context: this._getContext()
},
reader: {
type: 'json',
rootProperty: 'profiles'
}
},
fields: [
{name: 'id'},
{name: 'label', type: 'string'},
{name: 'rights'}
],
sorters: [
{sorterFn: function(p1, p2) {
if (p1.get("id") == Ametys.form.field.RightByProfile.ALL_PROFILES) { return -1; }
else if (p2.get("id") == Ametys.form.field.RightByProfile.ALL_PROFILES) { return 1; }
else { return 0; }
}},
{property: 'label', direction: 'ASC'}
],
listeners: {
'load': {
scope: this,
fn: function(store) {
// Add a select all option
store.add({id: Ametys.form.field.RightByProfile.ALL_PROFILES, label: "{{i18n PLUGINS_CORE_UI_WIDGET_RIGHT_BY_PROFILE_ALL_PROFILE}}", rights: []});
// wait for the profile store to be initialized before
// adding the listener on right field as it requires
// to have the profile store initialized
if (this.showProfilesIncludingRight)
{
var rightField = this.items.get(0).getComponent('select-right');
rightField.on("change", this._onRightChange, this);
this._onRightChange(rightField, rightField.getValue());
}
}
}
}
});
return this._profileStore;
},
/**
* @protected
* Returns an additional context to provide to the profile store proxy.
* @return {String} a context or ""
*/
_getContext: function() {
return "";
},
/**
* @private
* Filter the right field based on the selected profile
*/
_onProfileChange: function(profileField, newValue, oldValue)
{
var rightField = this.items.get(0).getComponent('select-right');
if (newValue == Ametys.form.field.RightByProfile.ALL_PROFILES || newValue == null)
{
rightField._store.removeFilter('profile');
}
else
{
var rights;
// special case for the reader profile that should
// include the fake reader right
if (newValue == Ametys.form.field.RightByProfile.READER_PROFILE)
{
rights = [Ametys.form.widget.Right.READER_RIGHT];
}
else
{
var profile = this._profileStore.getById(newValue);
rights = profile.get("rights");
}
if (rights.length == 1)
{
rightField.setValue(rights[0]);
}
rightField._store.addFilter([{
id: "profile",
filterFn: function(item) {
return Ext.Array.contains(rights, item.get("id"));
}
}]);
}
},
/**
* @private
* Display a line of text showing all the profile containing the selected
* right
*/
_onRightChange: function(rightField, newValue, oldValue)
{
var infoBloc = this.items.get(1);
if (newValue)
{
var profiles = [];
// Special case for the reader right as the reader profile
// does not include the fake reader right
if (newValue == Ametys.form.widget.Right.READER_RIGHT)
{
var readerProfile = this._profileStore.getById(Ametys.form.field.RightByProfile.READER_PROFILE);
profiles.push(readerProfile.get('label'));
}
else
{
this._profileStore.each(function(item) {
if (Ext.Array.contains(item.get('rights'), newValue))
{
profiles.push(item.get('label'));
}
});
}
if (profiles.length == 0)
{
infoBloc.setHtml("{{i18n PLUGINS_CORE_UI_WIDGET_RIGHT_BY_PROFILE_NO_CONTAINING_PROFILE}}");
}
else
{
infoBloc.setHtml(this._includedTpl.apply(profiles.map(p => Ext.String.htmlEncode(p))));
}
infoBloc.setVisible(true);
}
else
{
infoBloc.setVisible(false);
}
}
});