/*
* Copyright 2015 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.
*/
/**
* Helper for creating or editing a MATRIX question.
*/
Ext.define('Ametys.plugins.survey.question.MatrixDialog', {
singleton: true,
/**
* @private
* @property {String} _mode Can be 'new or 'edit'.
*/
/**
* @private
* @property {Ametys.window.DialogBox} _box The dialog box for creating/editing a page.
*/
/**
* @private
* @property {Ext.form.Panel} _formPanel The form panel of the dialog box.
*/
/**
* @private
* @property {Ext.grid.Panel} _grid The grid containing the input choices.
*/
/**
* @private
* @property {Boolean} _initialized True if the dialog box is initialized.
*/
/**
* @private
* @property {Boolean} _modifiable True if the choices can be removed.
*/
/**
* Open the dialog to create or edit a question
* @param {Object} config The configuration object
* @param {Ametys.message.MessageTarget} config.target If 'new' mode, the parent target. If 'edit' mode, the target to edit.
* @param {String} [config.mode=new] The mode: 'new' for creation or 'edit' for edition
*/
open: function (config)
{
this._mode = config.mode || 'new';
this._modifiable = true;
this._delayedInitialize();
this._initForm (config.target);
},
/**
* @private
* Creates the dialog box
*/
_delayedInitialize: function ()
{
if (!this._initialized)
{
this._formPanel = this._createFormPanel();
this._optGrid = this._createOptGrid();
this._colGrid = this._createColGrid();
this._box = Ext.create('Ametys.window.DialogBox', {
title: "{{i18n PLUGINS_SURVEY_DIALOG_MATRIX}}",
iconCls: "ametysicon-matrix",
width: 550,
scrollable: false,
items: [
this._formPanel,
{xtype: 'container', height: 260, layout: { type: 'hbox', align: 'stretch' }, items: [this._optGrid, this._colGrid]}
],
closeAction: 'hide',
defaultFocus: 'label',
selectDefaultFocus: true,
referenceHolder: true,
defaultButton: 'validate',
buttons: [{
reference: 'validate',
text: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_OK}}",
handler: Ext.bind(this._validate, this)
}, {
text: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_CANCEL}}",
handler: Ext.bind(this._cancel, this)
}]
});
this._initialized = true;
}
},
/**
* @private
* Handler for the 'ok' button of the dialog box
*/
_validate: function ()
{
var form = this._formPanel.getForm();
if (!form.isValid())
{
return;
}
var values = form.getValues();
values.type = values.multiple ? 'MULTIPLE_MATRIX' : 'SINGLE_MATRIX';
// Options
var options = {};
this._optGrid.getStore().getData().each (function (record) {
options[record.get('label')] = record.get('value');
});
values.options = Ext.JSON.encode(options);
//Columns
var columns = {};
this._colGrid.getStore().getData().each (function (record) {
columns[record.get('label')] = record.get('value');
});
values.columns = Ext.JSON.encode(columns);
if (this._mode == 'new')
{
var params = [values];
Ametys.cms.survey.QuestionDAO.createQuestion(params, this._validateCb, {scope: this} );
}
else
{
var params = [values];
Ametys.cms.survey.QuestionDAO.editQuestion(params, this._validateCb, {scope: this} );
}
},
/**
* Callback function called after creation or edition process
* @param {Object} response The server response
* @private
*/
_validateCb: function (response)
{
if (!response['error'])
{
this._box.close();
}
},
/**
* @private
* Callback for the "cancel" button of the dialog. Close the dialog.
*/
_cancel: function ()
{
this._box.close();
},
/**
* @private
* Initializes the form with some optional values.
* @param {Ametys.message.MessageTarget} target If 'new' mode, the parent target. If 'edit' mode, the target to edit.
*/
_initForm: function (target)
{
var form = this._formPanel.getForm();
form.reset();
this._optGrid.getStore().removeAll();
this._colGrid.getStore().removeAll();
if (this._mode === "new")
{
form.findField('id').setValue('');
form.findField('pageId').setValue(target.getParameters().id);
form.findField('label').setValue("{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_LABEL_DEFAULT}}");
form.findField('title').setValue('');
form.findField('title').clearInvalid();
form.findField('mandatory').setValue(false);
form.findField('multiple').setValue(false);
form.findField('picture-alternative').setValue();
form.findField('picture').setValue();
this._optGrid.down('#addButton').setDisabled(false);
this._colGrid.down('#addButton').setDisabled(false);
this._box.show();
}
else
{
form.findField('id').setValue(target.getParameters().id);
form.findField('pageId').setValue('');
Ametys.cms.survey.QuestionDAO.getQuestion([target.getParameters().id], this._setValues, {scope: this});
}
},
/**
* Fill the form with some values.
* @param {Object} data The question.
* @private
*/
_setValues: function(data)
{
var form = this._formPanel.getForm();
this._modifiable = data.validated == "false";
form.findField('label').setValue(data.label);
form.findField('title').setValue(data.title);
form.findField('mandatory').setValue(data.mandatory == 'true');
form.findField('multiple').setValue(data.type == 'MULTIPLE_MATRIX');
form.findField('picture-alternative').setValue(data.pictureAlternative);
if (!Ext.Object.isEmpty(data.picture))
{
data.picture.id = 'untouched';
form.findField('picture').setValue(data.picture);
}
else
{
form.findField('picture').setValue();
}
this._loadOptGridStore(data.options);
this._loadColGridStore(data.columns);
this._optGrid.down('#addButton').setDisabled(!this._modifiable);
this._colGrid.down('#addButton').setDisabled(!this._modifiable);
this._box.show();
},
/**
* 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 form panel of this dialog box.
* @return {Ext.form.Panel} The form panel
* @private
*/
_createFormPanel: function()
{
var formPanel = Ext.create('Ext.form.Panel', {
defaultType: 'textfield',
defaults: {
cls: 'ametys',
labelSeparator: '',
labelAlign: 'right',
labelWidth: 110,
width: '100%',
msgTarget: 'side'
},
border: false,
scrollable: true,
items: [
{
xtype: 'hidden',
name: 'id'
},
{
xtype: 'hidden',
name: 'pageId'
},
{
itemId: 'label',
name: 'label',
fieldLabel: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_LABEL}}",
ametysDescription: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_LABEL_DESC}}",
allowBlank: false,
maxLength: 20
},
{
name: 'title',
fieldLabel: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_TITLE}}",
ametysDescription: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_TITLE_DESC}}",
allowBlank: false
},
{
xtype: 'edition.file',
name: 'picture',
allowSources: [Ametys.form.widget.File.External.SOURCE, Ametys.cms.widget.File.Resource.SOURCE],
filter: Ametys.form.widget.File.IMAGE_FILTER,
fieldLabel: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_PICTURE_LABEL}}",
ametysDescription: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_PICTURE_DESC}}"
},
{
xtype: 'textfield',
name: 'picture-alternative',
fieldLabel: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_PICTURE_ALT_LABEL}}",
ametysDescription: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_PICTURE_ALT_DESC}}"
},
{
xtype: 'checkbox',
name: 'mandatory',
fieldLabel: ' ',
boxLabel: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_MANDATORY}}",
ametysDescription: "{{i18n PLUGINS_SURVEY_DIALOG_QUESTION_MANDATORY_DESC}}",
inputValue: 'true',
checked: false
},
{
xtype: 'checkbox',
name: 'multiple',
fieldLabel: ' ',
boxLabel: "{{i18n PLUGINS_SURVEY_DIALOG_MATRIX_MULTIPLE_CHOICE}}",
ametysDescription: "{{i18n PLUGINS_SURVEY_DIALOG_MATRIX_MULTIPLE_CHOICE_DESC}}",
inputValue: 'true',
checked: false
}
]
});
return formPanel;
},
/**
* Creates the bottom-left grid (options grid) of this dialog box.
* @return {Ext.grid.Panel} The grid
* @private
*/
_createOptGrid: function()
{
var grid = Ext.create('Ext.grid.Panel', {
flex: 0.5,
border: true,
scrollable: true,
store: {
fields: ['label', 'value'],
trackRemoved: false
},
stateful: true,
stateId: this.self.getName() + "$grid",
columns: [
{stateId: 'opt-grid-column-label', header: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_COL_LABEL}}", sortable: false, dataIndex: 'label',
editor: {
xtype: 'textfield',
allowBlank: false,
selectOnFocus: true
}
}
],
columnLines: true,
forceFit: true,
selModel: 'cellmodel',
plugins: {
ptype: 'cellediting',
clicksToEdit: 2
},
bbar: [
{
xtype: 'button',
itemId: 'addButton',
width: 150,
text: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_LABEL}}",
tooltip: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_DESCRIPTION}}",
handler: Ext.bind(this._addOpt, this)
},
'-',
{
xtype: 'button',
itemId: 'removeButton',
width: 70,
text: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_DEL_LABEL}}",
tooltip: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_DEL_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
},
stateful: true,
stateId: this.self.getName() + "$grid",
columns: [
{stateId: 'col-grid-column-label', header: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_COL_COLUMN_LABEL}}", sortable: false, dataIndex: 'label',
editor: {
xtype: 'textfield',
allowBlank: false,
selectOnFocus: true
}
}
],
columnLines: true,
forceFit: true,
selModel: 'cellmodel',
plugins: {
ptype: 'cellediting',
clicksToEdit: 2
},
bbar: [
{
xtype: 'button',
itemId: 'addButton',
width: 150,
text: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_COLUMN_LABEL}}",
tooltip: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_COLUMN_DESCRIPTION}}",
handler: Ext.bind(this._addCol, this)
},
'-',
{
xtype: 'button',
itemId: 'removeButton',
width: 70,
text: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_DEL_LABEL}}",
tooltip: "{{i18n PLUGINS_SURVEY_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;
},
/**
* Listener when the selection in the opt-grid has changed.
* @private
*/
_onOptSelectionChange: function()
{
var sm = this._optGrid.getSelectionModel();
var setEnable = sm.hasSelection() && this._modifiable;
this._optGrid.down('#removeButton').setDisabled(!setEnable);
},
/**
* Listener when the selection in the col-grid has changed.
* @private
*/
_onColSelectionChange: function()
{
var sm = this._colGrid.getSelectionModel();
var setEnable = sm.hasSelection() && this._modifiable;
this._colGrid.down('#removeButton').setDisabled(!setEnable);
},
/**
* 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: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_DEFAULTLABEL}}",
value: ''
});
this._optGrid.editingPlugin.startEditByPosition(pos);
},
/**
* 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());
}
},
/**
* 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: "{{i18n PLUGINS_SURVEY_QUESTION_VALUE_SELECT_BOX_GRID_ACTION_ADD_COLUMN_DEFAULT_LABEL}}",
value: ''
});
this._colGrid.editingPlugin.startEditByPosition(pos);
},
/**
* 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());
}
}
});