/*
* Copyright 2025 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 helper provides renderer for grid column.
*/
Ext.define("Ametys.grid.GridColumnHelper", {
singleton: true,
/**
* Renderer for String that escape the characters using HTML entities, unless record contains a field 'config-doNotEscapeHtml' equals to <code>true</code>
* @param {String|String[]} value The data value
* @param {Object} metaData A collection of data about the current cell
* @param {Ext.data.Model} record The record
* @return {String} The escaped value to render.
*/
renderWithHtmlEscaping: function(value, metadata, record)
{
if (!value || record.get('config-doNotEscapeHtml') === true)
{
return value;
}
if (Ext.isArray(value))
{
return Ext.Array.map(value, v => Ext.String.escapeHtml(v)).join(", ");
}
else
{
return Ext.String.escapeHtml(value);
}
},
/**
* Renderer for a value to be preceded by a icon associated to the record.<br>
* Icon is search on 'iconGlyph' or 'iconCls' or 'icon' record's properties.<br>
* Text value is HTML escaped, unless record contains a field 'config-doNotEscapeHtml' equals to <code>true</code>.
* @param {String} value the value to display
* @param {Object} metadata A collection of metadata about the current cell
* @param {Ext.data.Model} record The record for the current row
* @return {String} The value preceded by the icon if exists
*/
renderTextWithIcon: function(value, metadata, record)
{
var text = record.get('config-doNotEscapeHtml') !== true ? Ext.String.escapeHtml(value) : value;
if (record.get('iconGlyph') != null)
{
return '<span class="a-grid-glyph ' + record.get('iconGlyph') + (record.get('iconDecorator') != null ? ' ' + record.get('iconDecorator') : '') + '"></span>' + text;
}
else if (record.get('iconCls') != null)
{
return '<span class="a-grid-glyph ' + record.get('iconCls') + '"></span>' + text;
}
else if (record.get('icon'))
{
return '<img src="' + Ametys.CONTEXT_PATH + record.get('icon') + '" class="a-grid-icon a-grid-icon-title"/>' + text;
}
else
{
return text; // No icon found
}
},
/**
* Function to render a boolean value as 'yes' or 'no' text
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
*/
renderBoolean: function (value, metaData, record)
{
var isTrue = Ext.isBoolean(value) ? value : value == 'true';
if (isTrue)
{
return "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_YES}}";
}
else
{
return "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_NO}}";
}
},
/**
* Function to render a boolean value with icon
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
*/
renderBooleanIcon: function (value, metaData, record)
{
if (value != null)
{
var isTrue = Ext.isBoolean(value) ? value : value == 'true';
if (isTrue)
{
// if it's not a metadata cell render
if (Ext.Object.isEmpty(metaData))
{
return '<span class="a-grid-glyph ametysicon-check34" title="' + "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_YES}}" + '"></span>';
}
return '<span class="a-grid-glyph a-grid-centered-glyph ametysicon-check34" title="' + "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_YES}}" + '"></span>';
}
else
{
// if it's not a metadata cell render
if (Ext.Object.isEmpty(metaData))
{
return '<span class="a-grid-glyph ametysicon-sign-raw-cross" title="' + "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_NO}}" + '"></span>';
}
return '<span class="a-grid-glyph a-grid-centered-glyph ametysicon-sign-raw-small-cross" title="' + "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_NO}}" + '"></span>';
}
}
else // boolean value is not set
{
// if it's not a metadata cell render
if (Ext.Object.isEmpty(metaData))
{
return '<span class="a-grid-glyph ametysicon-sign-question" title="' + "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_NOT_DEFINED}}" + '"></span>';
}
return "";
}
},
/**
* Function to render a TRUE boolean value with icon. If false or empty the cell will be empty.
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
*/
renderBooleanTrueIcon: function (value, metaData, record)
{
var isTrue = Ext.isBoolean(value) ? value : value == 'true';
if (isTrue)
{
// if it's not a metadata cell render
if (Ext.Object.isEmpty(metaData))
{
return '<span class="a-grid-glyph ametysicon-check34" title="' + "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_YES}}" + '"></span>';
}
return '<span class="a-grid-glyph a-grid-centered-glyph ametysicon-check34" title="' + "{{i18n plugin.core-ui:PLUGINS_CORE_UI_GRID_COLUMN_BOOLEAN_YES}}" + '"></span>';
}
return "";
},
/**
* Convert a user object to a user light-object. The light version is the same handled by the user widget, so editing such user will not change the object
* @param {Object/Object[]} value The value as a object with the value for each language
* @param {Ext.data.Model} record The record
* @param {String} dataIndex The model data index
* @return {Object/Object[]} The property value or code.
*/
convertUser: function (value, record, dataIndex)
{
let values = Ext.Array.from(value);
if (values && values.length > 0)
{
let lightValues = [];
for (let v of values)
{
let lightValue = {
fullname: v.fullname,
sortablename: v.sortablename,
login: v.login,
populationId: v.populationId,
populationLabel: v.populationLabel,
};
lightValues.push(lightValue);
}
return Ext.isArray(value) ? lightValues : lightValues[0];
}
return value;
},
/**
* Function to render the user
* Either by considering {@code value} as the diplay name of the user and
* retrieving other user information from the record.
* Or by relying only on {@code value} if its an object (or array of object)
* @param {Object} value The data value.
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @param {Number} rowIndex The index of the current row
* @param {Number} colIndex The index of the current column
* @param {Ext.data.Store} store The store
* @param {Ext.view.View} view The current view
* @param {String} dataIndex concatenated with '_user' will get the user additional informations.
*/
renderUser: function(value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
let v = value;
if (!Ext.isArray(v) && !Ext.isObject(v) && !Ext.isEmpty(record.get('login')))
{
v = {
login: record.get('login'),
populationId: record.get("populationId"),
sortablename: v,
populationLabel: record.get("populationLabel")
}
}
if (Ext.isEmpty(v) || Ext.Object.isEmpty(v))
{
return '';
}
dataIndex = dataIndex || rowIndex; // When used by grouping feature, data index is the 4th arguments
var values = Ext.Array.from(v);
var html = '';
for (var i=0; i < values.length; i++)
{
var userValue = values[i];
var login = userValue.login;
var populationId = userValue.populationId;
if (!Ext.isEmpty(html))
{
html += '<br/>';
}
let knownUsername = userValue.sortablename || userValue.fullname;
if (!knownUsername)
{
html += "<span class='a-grid-user-unknown'>"
}
html += `<img src="${Ametys.helper.Users.getUserImage(login, populationId, 16)}" class="a-grid-icon a-grid-icon-user"/>`;
html += Ametys.helper.Users.renderUser(login, userValue.populationLabel || populationId, knownUsername);
if (!knownUsername)
{
html += "</span>"
}
}
return html;
},
/**
* Function to render a date
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @param {Number} rowIndex The index of the current row
* @param {Number} colIndex The index of the current column
* @param {Ext.data.Store} store The store
* @param {Ext.view.View} view The current view
* @param {String} dataIndex concatenated with 'Display' will be the name of the dataIndex to display
*/
renderDate: function (value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
if (!value)
{
return '-';
}
var date = Ext.isDate(value) ? value : Ext.Date.parse(value, Ext.Date.patterns.ISO8601DateTime);
return Ext.Date.format(date, Ext.Date.patterns.LongDate);
},
/**
* Function to render a datetime
* @param {Object} value The data value
* @param {Object} metaData A collection of metadata about the current cell
* @param {Ext.data.Model} record The record
* @param {Number} rowIndex The index of the current row
* @param {Number} colIndex The index of the current column
* @param {Ext.data.Store} store The store
* @param {Ext.view.View} view The current view
* @param {String} dataIndex concatenated with 'Display' will be the name of the dataIndex to display
*/
renderDateTime: function (value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
if (!value)
{
return '-';
}
var date = Ext.isDate(value) ? value : Ext.Date.parse(value, Ext.Date.patterns.ISO8601DateTime);
return Ext.Date.format(date, Ext.Date.patterns.FriendlyDateTime);
}
});