/*
* Copyright 2021 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 class provides a widget to create a grid for matrixes
*/
Ext.define('Ametys.plugins.forms.widget.MatrixGrid', {
extend : 'Ametys.form.AbstractField',
xtype: 'matrix-grid',
height: 250,
/**
* @private
* @property {Ext.grid.Panel} _grid The grid containing the input choices.
*/
constructor: function(config)
{
this.callParent(arguments);
},
initComponent: function()
{
this._optGrid = this._createOptGrid();
this._colGrid = this._createColGrid();
this.items = [{xtype: 'container', height: 260, layout: { type: 'hbox', align: 'stretch' }, items: [this._optGrid, this._colGrid]}];
this.layout = 'fit';
this.cls = this.emptyCls;
this.callParent(arguments);
},
getValue: function ()
{
var values = {};
//Options
var options = {};
this._optGrid.getStore().getData().each (function (record) {
options[record.get('value')] = record.get('label');
});
values.options = options;
//Columns
var columns = {};
this._colGrid.getStore().getData().each (function (record) {
columns[record.get('value')] = record.get('label');
});
values.columns = columns;
return Ext.JSON.encode(values);
},
setValue: function(value)
{
this.callParent(arguments);
if (value != null)
{
var row = Ext.JSON.decode(value);
var options = row.options;
this._loadOptGridStore(options);
var columns = row.columns;
this._loadColGridStore(columns);
}
},
/**
* Fill the opt-grid with some values.
* @param {Object} options The options to add in the opt-grid.
* @private
*/
_loadOptGridStore: function(options)
{
var store = this._optGrid.getStore();
for (var key in options)
{
store.add({
label: options[key],
value: key
});
}
},
/**
* Fill the col-grid with some values.
* @param {Object} columns The columns to add in the col-grid.
* @private
*/
_loadColGridStore: function(columns)
{
var store = this._colGrid.getStore();
for (var key in columns)
{
store.add({
label: columns[key],
value: key
});
}
},
/**
* Creates the bottom-left grid (options grid) of this dialog box.
* @return {Ext.grid.Panel} The grid
* @private
*/
_createOptGrid: function()
{
var columns = [
{
xtype: 'widgetcolumn',
stateId: 'opt-grid-column-label',
header: "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_COL_LABEL}}",
menuDisabled: true,
sortable: false,
dataIndex: 'label',
widget: {
xtype: 'textfield',
listeners: {
'change': Ext.bind(this._onWidgetChange, this, ['label'], 0),
'focus': Ext.bind(this._onFocus, this)
}
}
}
];
var grid = Ext.create('Ext.grid.Panel', {
flex: 0.5,
border: true,
scrollable: true,
store: {
fields: ['label', 'value'],
trackRemoved: false
},
columns: columns,
columnLines: true,
forceFit: true,
selModel: 'cellmodel',
bbar: [
{
xtype: 'button',
itemId: 'addButton',
flex: 1,
text: "{{i18n PLUGINS_FORMS_QUESTIONS_DIALOG_CHOICE_BOX_GRID_ACTION_ADD_OPTION_LABEL}}",
tooltip: "{{i18n PLUGINS_FORMS_QUESTIONS_DIALOG_CHOICE_BOX_GRID_ACTION_ADD_OPTION_DESCRIPTION}}",
handler: Ext.bind(this._addOpt, this)
},
'-',
{
xtype: 'button',
itemId: 'removeButton',
flex: 1,
text: "{{i18n PLUGINS_FORMS_QUESTIONS_DIALOG_CHOICE_BOX_GRID_ACTION_DEL_OPTION_LABEL}}",
tooltip: "{{i18n PLUGINS_FORMS_QUESTIONS_DIALOG_CHOICE_BOX_GRID_ACTION_DEL_OPTION_DESCRIPTION}}",
handler: Ext.bind(this._removeOpt, this),
disabled: true
}
],
listeners: {
'selectionchange': Ext.bind(this._onOptSelectionChange, this),
'edit': function(editor, context) {
context.record.commit();
}
}
});
return grid;
},
/**
* Creates the bottom-right grid (columns grid) of this dialog box.
* @return {Ext.grid.Panel} The grid
* @private
*/
_createColGrid: function()
{
var grid = Ext.create('Ext.grid.Panel', {
flex: 0.5,
border: true,
scrollable: true,
store: {
fields: ['label', 'value'],
trackRemoved: false
},
columns: [
{
xtype: 'widgetcolumn',
stateId: 'col-grid-column-label',
header: "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_COL_COLUMN_LABEL}}",
menuDisabled: true,
sortable: false,
dataIndex: 'label',
widget: {
xtype: 'textfield',
listeners: {
'change': Ext.bind(this._onWidgetColumnChange, this, ['label'], 0),
'focus': Ext.bind(this._onFocusColumn, this)
}
}
}
],
columnLines: true,
forceFit: true,
selModel: 'cellmodel',
bbar: [
{
xtype: 'button',
itemId: 'addButton',
flex: 1,
text: "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_COLUMN_LABEL}}",
tooltip: "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_COLUMN_DESCRIPTION}}",
handler: Ext.bind(this._addCol, this)
},
'-',
{
xtype: 'button',
itemId: 'removeButton',
flex: 1,
text: "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_DEL_LABEL}}",
tooltip: "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_DEL_DESCRIPTION}}",
handler: Ext.bind(this._removeCol, this),
disabled: true
}
],
listeners: {
'selectionchange': Ext.bind(this._onColSelectionChange, this),
'edit': function(editor, context) {
context.record.commit();
}
}
});
return grid;
},
/**
* @private
* Listener when a widget option value has changed, in order to update the optGrid store.
* @param {String} fieldName The name of the field to update in the record
* @param {Ext.form.field.Field} widget The widget
* @param {Object} newValue The new value
*/
_onWidgetChange: function(fieldName, widget, newValue)
{
if (widget.getWidgetRecord)
{
var rec = widget.getWidgetRecord();
if (rec != null)
{
var currentPos = this._optGrid.getStore().indexOf(rec);
rec.set(fieldName, newValue);
rec.commit();
}
}
},
/**
* Select the option row
* @param {Object} widget this grid
*/
_onFocus: function(widget)
{
var record = widget.getWidgetRecord();
var recordRow = this._optGrid.getStore().indexOf(record);
this._optGrid.getSelectionModel().select(recordRow);
this._onOptSelectionChange();
},
/**
* @private
* Listener when a widget column value has changed, in order to update the col grid store.
* @param {String} fieldName The name of the field to update in the record
* @param {Ext.form.field.Field} widget The widget
* @param {Object} newValue The new value
*/
_onWidgetColumnChange: function(fieldName, widget, newValue)
{
if (widget.getWidgetRecord)
{
var rec = widget.getWidgetRecord();
if (rec != null)
{
var currentPos = this._colGrid.getStore().indexOf(rec);
rec.set(fieldName, newValue);
rec.commit();
}
}
},
/**
* Select the column row
* @param {Object} widget this grid
*/
_onFocusColumn: function(widget)
{
var record = widget.getWidgetRecord();
var recordRow = this._colGrid.getStore().indexOf(record);
this._colGrid.getSelectionModel().select(recordRow);
this._onColSelectionChange();
},
/**
* Listener when the selection in the opt-grid has changed.
* @private
*/
_onOptSelectionChange: function()
{
var sm = this._optGrid.getSelectionModel();
this._optGrid.down('#removeButton').setDisabled(!sm.hasSelection());
},
/**
* Listener when the selection in the col-grid has changed.
* @private
*/
_onColSelectionChange: function()
{
var sm = this._colGrid.getSelectionModel();
this._colGrid.down('#removeButton').setDisabled(!sm.hasSelection());
},
/**
* Adds a new choice to the opt-grid, and starts the edition of its name.
* @private
*/
_addOpt: function()
{
var store = this._optGrid.getStore(),
sm = this._optGrid.getSelectionModel(),
pos;
if (sm.hasSelection())
{
pos = {row: sm.getPosition().rowIdx + 1, column: 0};
}
else
{
pos = {row: store.getCount(), column: 0};
}
store.insert(pos.row, {
label: this._getUniqueLabel(this._optGrid, "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_DEFAULTLABEL}}"),
value: this._getUniqueValue("opt", "opt_value", pos.row)
});
var widgetCols = Ext.ComponentQuery.query('textfield',this._optGrid.getView());
widgetCols[widgetCols.length - 1].focus(true)
},
/**
* Adds a new choice to the col-grid, and starts the edition of its name.
* @private
*/
_addCol: function()
{
var store = this._colGrid.getStore(),
sm = this._colGrid.getSelectionModel(),
pos;
if (sm.hasSelection())
{
pos = {row: sm.getPosition().rowIdx + 1, column: 0};
}
else
{
pos = {row: store.getCount(), column: 0};
}
store.insert(pos.row, {
label: this._getUniqueLabel(this._colGrid, "{{i18n PLUGINS_FORMS_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_COLUMN_DEFAULT_LABEL}}"),
value: this._getUniqueValue("col", "col_value", pos.row)
});
var widgetCols = Ext.ComponentQuery.query('textfield',this._colGrid.getView());
widgetCols[widgetCols.length - 1].focus(true)
},
/**
* Removes the selected record of the col-grid.
* @private
*/
_removeCol: function()
{
var store = this._colGrid.getStore(),
sm = this._colGrid.getSelectionModel();
if (sm.hasSelection())
{
store.remove(sm.getSelection());
}
},
/**
* Removes the selected record of the opt-grid.
* @private
*/
_removeOpt: function()
{
var store = this._optGrid.getStore(),
sm = this._optGrid.getSelectionModel();
if (sm.hasSelection())
{
store.remove(sm.getSelection());
}
},
/**
* @private
* Get a unique label for this option
* @param {Object} grid the grid
* @param {String} newLabel the new label
* @return {String} a unique label
*/
_getUniqueLabel: function(grid, newLabel)
{
var uniqueLabel = newLabel;
var i = 1;
var values = this._getGridLabels(grid);
while (values.indexOf(uniqueLabel) != -1)
{
uniqueLabel = newLabel + " " + i;
i++;
}
return uniqueLabel;
},
/**
* @private
* Get all the labels in the grid minus the row to ignore
* @param {Object} grid the grid
* @return {String[]} an array of all labels
*/
_getGridLabels : function(grid)
{
var gridLabels = [];
var values = grid.getStore().getData().items;
for (var index in values)
{
gridLabels.push(values[index].get('label'));
}
return gridLabels;
},
/**
* @private
* Get a unique value for this option
* @param {String} value the default value
* @param {Number} row position of the current cell
* @return {String} a unique value
*/
_getUniqueValue: function(grid, newValue, row)
{
var uniqueValue = newValue;
var i = 1;
var values = this._getGridValues(grid, row);
while (values.indexOf(uniqueValue) != -1)
{
uniqueValue = newValue + "_" + i;
i++;
}
return uniqueValue;
},
/**
* Get all the values in the grid minus the row to ignore
* @param {Number} rowToIgnore row of current value
* @return {String[]} an array of all the values to compare
*/
_getGridValues : function(gridName, rowToIgnore)
{
var gridValues = [];
var grid = gridName == "opt" ? this._optGrid : this._colGrid;
var values = grid.getStore().getData().items;
for (var index in values)
{
if(index != rowToIgnore)
{
gridValues.push(values[index].get('value'));
}
}
return gridValues;
}
});