/*
* 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.
*/
/**
* Tool to edit MCC in course
* @private
*/
Ext.define('Ametys.plugins.odf.pilotage.tool.MCCCourseTool', {
extend: 'Ametys.plugins.odf.pilotage.tool.ContentViewTreeGridTool',
statics: {
/**
* @private
* Fill a cache object with the table ref data
*/
_getTableRefData: function(tableRefId, cache) {
Ametys.data.ServerComm.send({
plugin: 'cms',
url: 'search/list.json',
parameters: {
model: tableRefId
},
priority: Ametys.data.ServerComm.PRIORITY_MAJOR,
errorMessage: true,
callback: {
handler: function(response) {
if (Ametys.data.ServerComm.isBadResponse(response))
{
return;
}
let result = Ext.JSON.decode(Ext.dom.Query.selectValue("", response));
for (let c of result.contents)
{
cache[c.id] = {
title: Ametys.plugins.cms.search.SearchGridHelper.getDefaultLocalizedValue(c.title),
shortLabel: c.properties.shortLabel
};
}
},
scope: this,
},
responseType: 'text'
});
},
/**
* @private
* @property {Object} _natureCache The internal reftable cache
*/
_natureCache: {},
/**
* @private
* @property {Object} _regimeCache The internal reftable cache
*/
_regimeCache: {},
/**
* @private
* @property {Object} _modalite2Cache The internal reftable cache
*/
_modaliteCache: {},
/**
* @private
* @property {Ext.XTemplate} _repeaterTpl The template used for rendering repeater entries
*/
_repeaterTpl: Ext.create('Ext.XTemplate', [
'<span data-qtip="{tip}"><tpl for="entries">',
'<tpl if="position > 1">',
", ",
'</tpl>',
'<span class="a-grid-repeater-entry">{label}</span>',
'</tpl></span>'
]),
renderTrueWhenNull: function(value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
let v = value;
if ((v === undefined || v == null)
&& (record.get('contenttypesIds') || []).includes('org.ametys.plugins.odf.Content.course'))
{
v = true;
}
return Ametys.grid.GridColumnHelper.renderBooleanIcon(v, metaData, record, rowIndex, colIndex, store, view, dataIndex)
},
renderTrueWhenNullInRepeater: function(value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
let v = value;
if (v === undefined || v == null)
{
v = true;
}
return Ametys.grid.GridColumnHelper.renderBooleanIcon(v, metaData, record, rowIndex, colIndex, store, view, dataIndex)
},
renderMCCRegime: function(value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
return this._readShortLabelOrTitle(record.data, "mccRegime", Ametys.plugins.odf.pilotage.tool.MCCCourseTool._regimeCache, "");
},
/**
* @private
* Get the short label if available in cache, title otherwise
*/
_readShortLabelOrTitle(values, dataindex, cache, otherwise)
{
if (values[dataindex])
{
let cacheEntry = cache[values[dataindex]];
if (cacheEntry)
{
return cacheEntry.shortLabel || cacheEntry.title;
}
else
{
return values[dataindex + "_content"][values[dataindex]].title;
}
}
else
{
return otherwise;
}
},
renderRepeater: function(value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
let me = this;
let repeater = record.get(dataIndex + "_repeater") || record.get(dataIndex);
let rawValues = repeater ? repeater.entries : null;
let knownEducationalPath = record.getPath("contentId", ";").substring(1);
let matchingEducationalPaths = record.get("educationalPaths");
if (matchingEducationalPaths.length == 1)
{
let currentEducationalPath = matchingEducationalPaths[0].path;
let currentEducationalPathLabel = matchingEducationalPaths[0].label;
// VERY IMPORTANT remmeber the educational path selected to allow the widget edit the record later
let repData = record.get(dataIndex + "_repeater");
repData._educationalPath = repData._educationalPath || {};
repData._educationalPath[record.getId()] = currentEducationalPath;
repData._educationalPathLabel = repData._educationalPathLabel || {};
repData._educationalPathLabel[record.getId()] = currentEducationalPathLabel;
if (Ext.isEmpty(value) || !Ext.isObject(repeater) || !Ext.isArray(rawValues) || rawValues.length == 0)
{
return '';
}
let rawByPathValues = rawValues.filter(a => a.values.common !== false || a.values.path == currentEducationalPath);
return display(rawByPathValues);
}
else
{
// Truncate the educational path to the meaningful part
let nbItemsToRemove = (knownEducationalPath.match(/;/g) || []).length + 1;
rawValues = Ext.Array.from(rawValues);
let rawByPathValues = rawValues.filter(a => a.values.common !== false);
let onlyGlobalValue = rawByPathValues.length == rawValues.length;
if (!onlyGlobalValue)
{
cellIsNotEditable();
// Not clickable when not editable (whereas by default repeaters are)
record.data.notClickableRepeater = record.data.notClickableRepeater || [];
record.data.notClickableRepeater.push(dataIndex);
}
else
{
// VERY IMPORTANT remmeber the educational path selected to allow the widget edit the record later
let repData = record.get(dataIndex + "_repeater");
repData._educationalPathLabel = repData._educationalPathLabel || {};
repData._educationalPathLabel[record.getId()] = record.getPath("title", " > ").substring(3);
let rootsLabels = [];
for (let matchingEducationalPath of matchingEducationalPaths)
{
let labelParts = matchingEducationalPath.label.split(" > ");
let meaningFullLabelParts = labelParts.slice(0, labelParts.length - nbItemsToRemove);
let meaningFullHtmlParts = [];
for (let i=0; i < meaningFullLabelParts.length; i++)
{
meaningFullHtmlParts.push(meaningFullLabelParts[i]);
}
let label = meaningFullHtmlParts.join(" > ");
rootsLabels.push(label);
repData._educationalPathRootLabels = repData._educationalPathRootLabels || {};
repData._educationalPathRootLabels[record.getId()] = rootsLabels;
}
}
if (!onlyGlobalValue)
{
let qTip = "{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_MCCSESSIONS_EDUCATIONAL_PATH_MULTIPLE_MIXED_TOOLTIP_INTRO}}";
qTip += "<ul style=\'margin: 0 5px 0 5px; padding: 0 0 0 20px;\'>";
for (let matchingEducationalPath of matchingEducationalPaths)
{
let labelParts = matchingEducationalPath.label.split(" > ");
let idParts = matchingEducationalPath.path.split(";");
let meaningFullLabelParts = labelParts.slice(0, labelParts.length - nbItemsToRemove);
let meaningFullHtmlParts = [];
for (let i=0; i < meaningFullLabelParts.length; i++)
{
let meaningFullLabelPart = meaningFullLabelParts[i];
let id = idParts[i];
meaningFullHtmlParts.push("<a href='javascript:void(0)' onclick="Ametys.tool.ToolsManager.openTool('uitool-content', {id: '" + id + "'})">" + meaningFullLabelPart.replaceAll("\"", """) + "</a>");
}
let label = meaningFullHtmlParts.join(" > ");
qTip += "<li style='margin: 5px 0 5px 0'>" + label + "</li>";
}
qTip += "</ul>";
metaData.tdAttr = "data-anchor='right' data-qtip=\"" + qTip + "\""
}
/*if (Ext.isEmpty(value) || !Ext.isObject(repeater) || rawValues.length == 0)
{
return '';
}*/
return onlyGlobalValue ? display(rawByPathValues) : "{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_MCCSESSIONS_EDUCATIONAL_PATH_MULTIPLE_MIXED_VALUE}}";
}
function cellIsNotEditable()
{
metaData.tdCls = metaData.tdCls.split(" ")
.filter(x => !!x) // remove empty
.map(x => x == "editable" ? "cell-noteditable" : x) // replace editable by noteditable
.filter((x, index, array) => array.indexOf(x) === index) // distinct values
.join(" ");
record.data.notEditableDataIndex = record.data.notEditableDataIndex || [];
record.data.notEditableDataIndex.push(dataIndex);
}
function display(rawValues)
{
let labels = [];
// cannot rely on rawValues[x].position since they were filtered
let x = 1;
let entries = [];
for (let i in rawValues)
{
let rawValue = rawValues[i];
let label = "";
label += me._readShortLabelOrTitle(rawValue.values, "nature", Ametys.plugins.odf.pilotage.tool.MCCCourseTool._natureCache, "");
label += " (";
label += me._readShortLabelOrTitle(rawValue.values, "modalite", Ametys.plugins.odf.pilotage.tool.MCCCourseTool._modaliteCache, "");
if (rawValue.values["coefficient"])
{
label += ", Coef. " + rawValue.values["coefficient"];
}
label += ")";
labels.push(label);
entries.push({
label: label,
position: x
});
x++;
}
let html = me._repeaterTpl.applyTemplate({
entries: entries,
tip: labels.join(",<br/>")
});
return html;
}
},
renderRepeaterByEducationalPath: function(value, metaData, record, rowIndex, colIndex, store, view, dataIndex)
{
metaData.tdCls += ' ftype-educationalPath';
// Not clickable when not editable (whereas by default repeaters are)
record.data.notClickableRepeater = record.data.notClickableRepeater || [];
record.data.notClickableRepeater.push(dataIndex);
let repeater = record.get(dataIndex + "_repeater") || record.get(dataIndex);
let rawValues = repeater ? repeater.entries : null;
let knownEducationalPath = record.getPath("contentId", ";").substring(1);
let matchingEducationalPaths = record.get("educationalPaths");
if (matchingEducationalPaths.length == 1)
{
let currentEducationalPath = matchingEducationalPaths[0].path;
// VERY IMPORTANT remember the educational path selected to allo the widget edit the record later
let repData = record.get(dataIndex + "_repeater");
repData._educationalPath = repData._educationalPath || {};
repData._educationalPath[record.getId()] = currentEducationalPath;
if (Ext.isEmpty(value) || !Ext.isObject(repeater) || !Ext.isArray(rawValues) || rawValues.length == 0)
{
return '';
}
let rawByPathValues = rawValues.filter(a => a.values[(metaData.column.editor || metaData.column.field).pathField] == currentEducationalPath);
if (rawByPathValues.length > 1)
{
return 'ERROR'; // Not handled properly since a global validation is done to avoid this case
}
else
{
if (rawByPathValues.length == 0)
{
return '';
}
else
{
return rawByPathValues[0].values[(metaData.column.editor || metaData.column.field).valueField];
}
}
}
else
{
// Truncate the educational path to the meaningful part
let nbItemsToRemove = (knownEducationalPath.match(/;/g) || []).length + 1;
// Cell is not editable
metaData.tdCls = metaData.tdCls.replace(/ editable(?= )/g, '') + ' cell-noteditable';
record.data.notEditableDataIndex = record.data.notEditableDataIndex || [];
record.data.notEditableDataIndex.push(dataIndex);
if (Ext.isEmpty(value) || !Ext.isObject(repeater) || !Ext.isArray(rawValues) || rawValues.length == 0)
{
return '';
}
let qTip = "{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_REPEATER_EDUCATIONAL_PATH_MULTIPLE_TOOLTIP_INTRO}}";
qTip += "<ul style=\'margin: 0 5px 0 5px; padding: 0 0 0 20px;\'>";
for (let matchingEducationalPath of matchingEducationalPaths)
{
let labelParts = matchingEducationalPath.label.split(" > ");
let idParts = matchingEducationalPath.path.split(";");
let meaningFullLabelParts = labelParts.slice(0, labelParts.length - nbItemsToRemove);
let meaningFullHtmlParts = [];
for (let i=0; i < meaningFullLabelParts.length; i++)
{
let meaningFullLabelPart = meaningFullLabelParts[i];
let id = idParts[i];
meaningFullHtmlParts.push("<a href='javascript:void(0)' onclick="Ametys.tool.ToolsManager.openTool('uitool-content', {id: '" + id + "'})">" + meaningFullLabelPart.replaceAll("\"", """) + "</a>");
}
let label = meaningFullHtmlParts.join(" > ");
label += "<span style='white-space:nowrap;'> > … > </span>" + record.get('title');
let rawByPathValues = rawValues ? rawValues.filter(a => a.values[(metaData.column.editor || metaData.column.field).pathField] == matchingEducationalPath.path) : [];
if (rawByPathValues.length == 1)
{
label += " ({{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_REPEATER_EDUCATIONAL_PATH_MULTIPLE_TOOLTIP_VALUE}} " + rawByPathValues[0].values[(metaData.column.editor || metaData.column.field).valueField] + ")";
}
else
{
label += " ({{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_REPEATER_EDUCATIONAL_PATH_MULTIPLE_TOOLTIP_NOVALUE}})";
}
qTip += "<li style='margin: 5px 0 5px 0'>" + label + "</li>";
}
qTip += "</ul>";
metaData.tdAttr = "data-anchor='left' data-qtip=\"" + qTip + "\""
return "{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_REPEATER_EDUCATIONAL_PATH_MULTIPLE_VALUE}}" ;
}
}
},
_createTree: function()
{
return Ext.create('Ametys.plugins.odf.pilotage.tool.MCCCourseTreeGridPanel', this._getTreeConfig());
},
_getColumnsCb: function(columnsData, args)
{
let columnsDataModified = columnsData.map(c => {
if (c.type == "repeater" && (c.path == "mccSession1" || c.path == "mccSession2"))
{
c.widget = "edition.mcccourserepeater";
c['widget-params'] = {
dataIndexes: ["mccSession1", "mccSession2"],
authorizeCopy: "reportSession2",
doNotCopy: ["modalite", "modalite_content", "modalite_content_initial"]
};
c.columns.filter(c => c.name == "notes").map(sc => { sc.widget = "edition.notesRepeaterAsForm"; sc["widget-params"] = {mode: "table"}; });
}
else if (c.type == "repeater" && c.columns.length == 2 && c.columns.filter(cc => cc.type == 'educational-path').length == 1)
{
let pathColumn = c.columns.filter(col => col.type == 'educational-path')[0];
let valueColumn = c.columns.filter(col => col != pathColumn)[0];
c.widget = "edition.repeaterValueByEducationalPath";
c['widget-params'] = c['widget-params'] || {};
c['widget-params']['pathField'] = pathColumn.name;
c['widget-params']['valueField'] = valueColumn.name;
c['widget-params']['innerWidget'] = Ext.applyIf({
xtype: Ametys.form.WidgetManager.getWidgetXType(valueColumn.widget, valueColumn.type, !!valueColumn.enumeration, valueColumn.multiple),
enumeration: valueColumn['enumeration'],
multiple: valueColumn['multiple'],
}, valueColumn['widget-params']);
}
return c;
});
this.callParent([columnsDataModified, args]);
},
_getTreeConfig: function()
{
var treeCfg = this.callParent(arguments);
var activeIndicators = treeCfg.activeIndicators || [];
activeIndicators.push("odf-pilotage-indicator-excluded-mcc-status");
return Ext.apply(treeCfg, {
forceReadonlyField: "mccSession2",
activeIndicators: activeIndicators
});
}
});
// Fetch all renderer values
(function () {
Ametys.plugins.odf.pilotage.tool.MCCCourseTool._getTableRefData('reference-table-search-ui.odf-enumeration.MccSessionNature', Ametys.plugins.odf.pilotage.tool.MCCCourseTool._natureCache);
Ametys.plugins.odf.pilotage.tool.MCCCourseTool._getTableRefData('reference-table-search-ui.odf-enumeration.MccRegime', Ametys.plugins.odf.pilotage.tool.MCCCourseTool._regimeCache);
Ametys.plugins.odf.pilotage.tool.MCCCourseTool._getTableRefData('reference-table-search-ui.odf-enumeration.MccModaliteSession1', Ametys.plugins.odf.pilotage.tool.MCCCourseTool._modaliteCache);
Ametys.plugins.odf.pilotage.tool.MCCCourseTool._getTableRefData('reference-table-search-ui.odf-enumeration.MccModaliteSession2', Ametys.plugins.odf.pilotage.tool.MCCCourseTool._modaliteCache);
})();