/*
* 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.
*/
/**
* Show the values of a repeater in a dialog, and allow the inline modification of its entries
*/
Ext.define('Ametys.plugins.odfpilotage.widget.DoubleMCCSearchGridRepeater', {
singleton: true,
showRepeaterDialog: function()
{
return Ametys.plugins.cms.search.SearchGridRepeaterDialog.showRepeaterDialog.apply(this, arguments);
},
_getEducationalPath: function(parentRecord, dataIndex)
{
let data = parentRecord.get(dataIndex[0] + "_repeater")._educationalPath;
return data ? data[parentRecord.getId()] : null;
},
_openDialog: function (title, parentRecord, contentId, subcolumns, repeaterCfg, dataIndex, metadataPath, contentGridId, callback)
{
let me = this;
let items = [];
let grids = [];
let educationalPath = this._getEducationalPath(parentRecord, dataIndex);
let educationalPathLabel = parentRecord.get(dataIndex[0] + "_repeater")._educationalPathLabel[parentRecord.getId()];
let rootsLabels = "";
let roots = (parentRecord.get(dataIndex[0] + "_repeater")._educationalPathRootLabels || {})[parentRecord.getId()];
if (roots)
{
rootsLabels = "<br/><br/>{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_MCCSESSIONS_EDUCATIONAL_PATH_MULTIPLE_GLOBAL_INTRO}}<ul style='margin-top: 0;'>" + roots.map(x => "<li><strong>" + x + "</strong></li>").join("") + "</ul>{{i18n PLUGINS_ODF_PILOTAGE_RIGHTS_MCCCOURSE_MCCSESSIONS_EDUCATIONAL_PATH_MULTIPLE_GLOBAL_WARN}}";
// Hide the common column
for (let subcolumn of subcolumns)
{
for (let c of subcolumn)
{
if (c.name == "common")
{
c.hidden = true;
}
}
}
}
else
{
// Ensure visibility of common column
for (let subcolumn of subcolumns)
{
for (let c of subcolumn)
{
if (c.name == "common")
{
c.hidden = false;
}
}
}
}
this._cannotEditCommon = {};
for (let i = 0; i < metadataPath.length; i++)
{
this._cannotEditCommon[i] = this._isRecordMetadataNotModifiable(parentRecord, metadataPath[i], "common", null, null);
}
items.push({
xtype: "component",
ui: 'tool-hintmessage',
html: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DIALOG_MCCCOURSE_LABEL}} <strong>" + educationalPathLabel + "</strong>" + rootsLabels
});
this._eliminatedRecordsForEducationPath = [];
for (let i = 0; i < subcolumns.length; i++)
{
let eliminated;
function filter(repeater)
{
let condition = x => x.values.common !== false || x.values.path == educationalPath;
eliminated = repeater.entries.filter(x => !condition(x))
return repeater.entries.filter(condition)
}
let items1 = Ametys.plugins.cms.search.SearchGridRepeaterDialog._createItems(title, parentRecord, contentId, subcolumns[i], repeaterCfg[i], dataIndex[i], metadataPath[i], contentGridId, {add: Ext.bind(this._onAdd, this)}, filter, this);
items1[0]._gridIndex = grids.length;
grids.push(items1[0]);
items.push({
xtype: 'panel',
flex: 1,
layout: 'fit',
title: title[i],
items: items1
});
this._eliminatedRecordsForEducationPath.push(eliminated);
}
items.splice(2, 0, {
xtype: 'container',
layout: 'hbox',
style: {
marginTop: '20px'
},
items: [
{ xtype: 'tbspacer', flex: 1 },
{
xtype: 'button',
text: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_TOOL_MCCCOURSE_COPY_LABEL}}",
handler: Ext.bind(this._copySessions, this, [dataIndex[dataIndex.length - 1], false], 1),
tooltip: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_MCC_SESSIONS_COPY_TOOLTIP}}"
},
{ xtype: 'tbspacer', flex: 1 }
]
});
// If the "common" column is not hidden
// And if we are not in read only mode
if (grids[0].getColumns().filter(x => x.dataIndex == 'common' && !x.hidden).length > 0)
{
items.push({
xtype: 'component',
style: {
marginTop: '5px',
textAlign: 'right'
},
html: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_MCC_SESSIONS_WARN_ORDER}}"
});
}
var isGrid1ReadOnly = parentRecord.data['notEditableData'] === true || parentRecord.data['notEditableDataIndex'] && Ext.Array.contains(parentRecord.data['notEditableDataIndex'], metadataPath[0]);
var isGrid2ReadOnly = parentRecord.data['notEditableData'] === true || parentRecord.data['notEditableDataIndex'] && Ext.Array.contains(parentRecord.data['notEditableDataIndex'], metadataPath[1]);
var dialog = Ametys.plugins.cms.search.SearchGridRepeaterDialog._showDialog(
"{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_DIALOG_MCCCOURSE_LABEL}} " + parentRecord.get('title'),
items,
{type: 'vbox', align: 'stretch'},
function () {
Ametys.plugins.odfpilotage.widget.DoubleMCCSearchGridRepeater._ok(dialog, parentRecord, grids, dataIndex, contentId, callback);
},
callback,
[
{
text :"{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_MCC_SESSIONS_BUTTON_HANDLE}}",
handler: function() {
Ametys.plugins.odf.pilotage.helper.DoubleMCCTemplatesHelper.handleMCCSessionsTemplates(grids, parentRecord.get("mccRegime"), !(isGrid1ReadOnly || repeaterCfg[0].disabled), !(isGrid2ReadOnly || repeaterCfg[1].disabled));
},
tooltip: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_MCC_SESSIONS_HANDLE_TOOLTIP}}",
scope: this
},
{
text :"{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_MCC_SESSIONS_BUTTON_CREATE}}",
handler: function() {
Ametys.plugins.odf.pilotage.helper.DoubleMCCTemplatesHelper.createTemplate(grids);
},
tooltip: "{{i18n plugin.odf-pilotage:PLUGINS_ODF_PILOTAGE_MCC_SESSIONS_CREATE_TOOLTIP}}",
itemId: 'create-user-session',
scope: this
},
{ xtype: 'tbspacer', flex: 1 }
]
);
this._initCreateTemplateButton(dialog, grids);
dialog.setReadOnly = function() {
let copyButton = dialog.items.get(2);
copyButton.disable();
copyButton._definitiveDisabled = true;
for (let i = 1; i < dialog.items.getCount(); i+=2)
{
dialog.items.get(i).items.get(0).getStore().fireEvent('datachanged');
}
dialog.items.get(4).hide();
if (dialog.items.get(3).items.get(0).getStore().getCount() == 0)
{
copyButton.hide();
dialog.items.get(3).hide();
dialog.setHeight(500);
}
}
if (isGrid2ReadOnly || repeaterCfg[1].disabled)
{
dialog.setReadOnly();
}
enableDisableCopyButton();
grids[0].getStore().on('datachanged', enableDisableCopyButton);
return dialog;
function enableDisableCopyButton()
{
let copyButton = dialog.items.get(2);
if (copyButton._definitiveDisabled)
{
return;
}
let nbItemsToCopy = me._copySessions(copyButton.down('button'), dataIndex[dataIndex.length - 1], true);
copyButton.setDisabled(nbItemsToCopy == 0);
}
},
_onAdd: function(repeaterRecord, grid)
{
if (this._cannotEditCommon[grid._gridIndex])
{
repeaterRecord.set('common', false);
}
},
_initCreateTemplateButton: function(dialog, grids)
{
let storeGrid1 = grids[0].getStore();
let storeGrid2 = grids[1].getStore();
let createTemplateButton = dialog.down("#create-user-session");
if (storeGrid1.getCount() == 0 && storeGrid2.getCount() == 0)
{
createTemplateButton.disable();
}
else
{
createTemplateButton.enable();
}
storeGrid1.on("datachanged", function() {
if (storeGrid1.getCount() == 0 && storeGrid2.getCount() == 0)
{
createTemplateButton.disable();
}
else
{
createTemplateButton.enable();
}
})
storeGrid2.on("datachanged", function() {
if (storeGrid1.getCount() == 0 && storeGrid2.getCount() == 0)
{
createTemplateButton.disable();
}
else
{
createTemplateButton.enable();
}
})
},
_copySessions: function(button, config, fake)
{
let sourceStore = button.ownerCt.prev().items.get(0).store;
let targetStore = button.ownerCt.next().items.get(0).store;
let dataThatRequiresAServerConversion = [];
let toReplace = {};
let newRecords = {};
for (let i=0; i < sourceStore.getCount(); i++)
{
let record = sourceStore.getAt(i);
if (record.get(config.authorizeCopy) != true && record.get("__notEditable") !== true)
{
let newRecord = targetStore.getModel().create();
let data = {};
for (let d in record.data)
{
if (d != 'id' && d != config.authorizeCopy)
{
if (!(config.doNotCopy || []).includes(d))
{
if (targetStore.getModel().getField(d) != null)
{
// Direct copy
data[d] = record.data[d];
if (record.data[d + "_repeater"])
{
data[d + "_repeater"] = record.data[d + "_repeater"];
}
}
}
else if (typeof record.data[d] == 'string' && record.data[d])
{
toReplace[newRecord.getId()] = toReplace[newRecord.getId()] || [];
toReplace[newRecord.getId()].push(d);
data[d] = record.data[d];
if (!dataThatRequiresAServerConversion.includes(record.data[d]))
{
// Require a server conversion of the value
dataThatRequiresAServerConversion.push(record.data[d]);
}
}
}
}
newRecords[newRecord.getId()] = {
record: newRecord,
data: data
}
}
}
if (fake)
{
return Object.keys(newRecords).length;
}
debugger
if (dataThatRequiresAServerConversion.length == 0)
{
this._copySessionsStep2(null, {store: targetStore, newRecords: newRecords, toReplace: toReplace});
}
else
{
Ametys.data.ServerComm.callMethod({
role: "org.ametys.plugins.odfpilotage.helper.PilotageHelper",
methodName: "getCompatibleModalityInSession2",
parameters: [dataThatRequiresAServerConversion],
callback: {
handler: this._copySessionsStep2,
scope: this,
arguments: {
store: targetStore,
newRecords: newRecords,
toReplace: toReplace
}
},
errorMessage: true
});
}
},
_copySessionsStep2: function(serverData, args)
{
let store = args.store;
let newRecords = args.newRecords;
let toReplace = args.toReplace;
for (let newRecordId in newRecords)
{
let newRecord = newRecords[newRecordId].record;
let data = newRecords[newRecordId].data;
store.add(newRecord);
newRecord.set(data); // setting data after, to be not commited
if (serverData && toReplace[newRecord.getId()])
{
for (let k of toReplace[newRecord.getId()])
{
newRecord.set(k, serverData[newRecord.get(k)] || null);
}
}
Ametys.plugins.cms.search.SearchGridRepeaterDialog._markAllAsModified(null, newRecord); // to ensure, empty data have the red flag
}
},
_ok: function (dialog, parentRecord, grids, dataIndex, contentId, callback)
{
let repeaterValuesAll = {};
for (let i=0; i < grids.length; i++)
{
// Set educational path on the hidden field 'path'
let educationalPath = this._getEducationalPath(parentRecord, dataIndex);
for (let item of grids[i].getStore().getData().items)
{
if (item.get('common') === undefined)
{
// Untouched old values, will be interpreted by server as "empty values"... therefore, they will not have their default value anymore ODF-3924
item.set('common', true, {silent: true});
}
if (!item.get('path') && item.get('common') === false)
{
item.set('path', educationalPath, {silent: true});
}
}
var entriesValues = Ametys.plugins.cms.search.SearchGridRepeaterDialog._gridToValues(grids[i]);
if (entriesValues == null)
{
Ametys.log.ErrorDialog.display({
title: "{{i18n plugin.cms:UITOOL_CONTENTEDITIONGRID_REPEATER_VALUE_ERROR_TITLE}}",
text: "{{i18n plugin.cms:UITOOL_CONTENTEDITIONGRID_REPEATER_VALUE_ERROR_DESC}}" + "<br/>" + grids[i].ownerCt.getTitle(),
details: "The repeater n°" + i + " has some invalid values",
category: this.self.getName()
});
return;
}
// Replace the initialy filtered data
for (let elimanatedRecord of this._eliminatedRecordsForEducationPath[i])
{
entriesValues.push(elimanatedRecord.values);
}
entriesValues.sort(function(a , b) {
if (a.common !== false && b.common === false)
{
return -1;
}
else if (a.common === false && b.common !== false)
{
return +1;
}
else if (a.common === false /*&& b.common === false*/ && a.path != b.path)
{
return a.path < b.path ? -1 : 1;
}
return entriesValues.indexOf(a) < entriesValues.indexOf(b) ? -1 : 1;
})
var repeaterValues = parentRecord.getData()[dataIndex[i] + "_repeater"];
repeaterValues.entries = [];
for (var index = 0; index < entriesValues.length; index++)
{
let notEditable = entriesValues[index].__notEditable;
delete entriesValues[index].__notEditable;
repeaterValues.entries[index] = {
position: index + 1,
values: entriesValues[index]
};
if (entriesValues[index]['previous-position'] != repeaterValues.entries[index].position)
{
repeaterValues.entries[index]['previous-position'] = entriesValues[index]['previous-position'];
}
delete entriesValues[index]['previous-position'];
if (notEditable)
{
repeaterValues.entries[index].notEditable = true;
}
}
repeaterValuesAll[dataIndex[i]] = repeaterValues;
}
if (callback)
{
callback(repeaterValuesAll);
dialog.doNotCallCallback = true;
}
Ametys.plugins.cms.search.SearchGridRepeaterDialog._closeForced = true;
dialog.close();
},
// Override of SearchGridRepeaterDialog used by the _createItems method
_beforeEdit: function(editor, e, eOpts, contentId, contentGridId)
{
return Ametys.plugins.cms.search.SearchGridRepeaterDialog._beforeEdit.call(this, editor, e, eOpts, contentId, contentGridId);
},
_isRecordMetadataNotModifiable: function(contentRecord, metadataPath, fieldName, repeaterRecord, cell)
{
return Ametys.plugins.cms.search.SearchGridRepeaterDialog._isRecordMetadataNotModifiable(contentRecord, metadataPath, fieldName, repeaterRecord, cell);
},
_beforeEditContentCB: function(content, editingPlugin, record, contentGrid)
{
if (content == null)
{
Ametys.plugins.cms.search.SearchGridRepeaterDialog._beforeEditContentCB(content, editingPlugin, record, contentGrid);
}
else
{
if (content.getAvailableActions().indexOf(this.workflowEditActionId) != -1)
{
Ametys.plugins.cms.search.SearchGridRepeaterDialog._beforeEditContentCB(content, editingPlugin, record, contentGrid);
}
else
{
// Test if edit workflow action id is available for current path
Ametys.data.ServerComm.callMethod({
role: "org.ametys.plugins.odfpilotage.helper.MCCCourseTreeGridHelper",
methodName: "canEditRepeaterWithPath",
parameters: [
content.getId(),
record.get("educationalPaths")[0].path.split(";")
],
callback: {
handler: this._canEditRepeaterWithPathCB,
scope: this,
arguments: {
content: content,
editingPlugin: editingPlugin,
record: record,
contentGrid: contentGrid
}
},
errorMessage: true,
waitMessage: false
});
}
}
},
_canEditRepeaterWithPathCB: function (available, args)
{
// Add edit workflow action id to available actions
let availableActions = args.content.getAvailableActions();
if (available)
{
availableActions.push(args.contentGrid.ownerGrid.workflowEditActionId);
}
args.content._availableActions = availableActions;
Ametys.plugins.cms.search.SearchGridRepeaterDialog._beforeEditContentCB(args.content, args.editingPlugin, args.record, args.contentGrid);
},
_cancelEdit: function(editor, e, eOpts, contentId, contentGridId)
{
return Ametys.plugins.cms.search.SearchGridRepeaterDialog._cancelEdit(editor, e, eOpts, contentId, contentGridId);
},
_edit: function(editor, e, eOpts, contentId, contentGridId)
{
return Ametys.plugins.cms.search.SearchGridRepeaterDialog._edit(editor, e, eOpts, contentId, contentGridId);
},
_validateEdit: function (editor, context)
{
return Ametys.plugins.cms.search.SearchGridRepeaterDialog._validateEdit(editor, context);
}
});