/*
* Copyright 2017 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 edit a string in multiple locales.<br>
*
* This widget is the default widget registered for fields of type Ametys.form.WidgetManager#TYPE_MULTILINGUAL_STRING.<br>
* It does NOT handle multiple values.<br>
*
*/
Ext.define('Ametys.form.widget.MultilingualString', {
extend : 'Ametys.form.AbstractFieldsWrapper',
alias: "widget.multilingualstring",
/**
* @cfg {String} buttonIconCls The CSS class for the button icon
*/
buttonIconCls: 'ametysicon-translation',
/**
* @cfg {String} buttonTooltipText The button tooltip text
*/
buttonTooltipText : "{{i18n PLUGINS_CORE_UI_WIDGET_MULTILINGUAL_EDIT_LANG_BUTTON_TOOLTIP}}",
/**
* @cfg {String} defaultLanguage The default language
*/
defaultLanguage: Ametys.LANGUAGE_CODE,
initComponent: function()
{
var me = this;
let maxHeight = Ametys.form.WidgetManager.getWidgetMaxHeight(this.getInitialConfig());
// Textfield field.
this.textfield = Ext.create('Ext.form.field.Text', {
flex: 1,
enableKeyEvents: true,
readOnly: this.getInitialConfig('readOnly'),
maxHeight: maxHeight,
listeners: {
keyup: Ext.bind(this._updateValueOnKeyUp, this),
change: Ext.bind(this._updateValueOnKeyUp, this)
}
});
// Edit button
this.editButton = Ext.create('Ext.button.Button', {
iconCls: this.buttonIconCls,
tooltip: this.buttonTooltipText,
maxHeight: maxHeight,
handler : this._editLanguages,
scope : this
});
this.items = [ this.textfield, this.editButton ];
this.callParent(arguments);
},
constructor: function (config)
{
this.callParent(arguments);
if (!this.allowBlank)
{
this.on('change', this._updateWarning, this);
}
},
/**
* @private
* Function to edit all available languages
*/
_editLanguages: function ()
{
this.loadAvailableLanguages(this._openDialog, this);
},
/**
* Open the dialog for editing the given languages
* @param {Object[]} languages Array of the available languages
*/
_openDialog: function(languages)
{
this.triggerDialogBoxOpened = true;
Ametys.helper.EditMultilingualString.open({
title: this.getFieldLabel(),
ownerField: this,
values: this.getValue(),
allowBlank: this.getInitialConfig('allowBlank'),
languages: languages,
itemConfig: this._getItemsConfig(),
readOnly: this.getInitialConfig('readOnly'),
callback: Ext.bind(this._editLanguagesCb, this)
});
},
/**
* Load available languages for edition
* @param {Function} callback The callback function to call after loading. Excepted parameters are :
* @param {Object[]} callback.languages Array of the available languages. Excepted properties for each language are: 'name' for the language code and 'label' for the label
* @param {Object} scope The
*/
loadAvailableLanguages: function(callback, scope)
{
callback.call(scope || this, []);
},
/**
* @private
* Get the configuration options to transmit to dialog box items
* @return {Object} the the configuration options for each language items
*/
_getItemsConfig: function()
{
return {
regex: this.getInitialConfig('regex'),
regexText: this.getInitialConfig('regexText'),
minLength: this.getInitialConfig('minLength'),
maxLength: this.getInitialConfig('maxLength'),
}
},
/**
* @private
* Callback function invoked after editing languages' values
* @param values The values for each language
*/
_editLanguagesCb: function (values)
{
if (values != null && !this.getInitialConfig('readOnly'))
{
this.setValue(values);
}
this.triggerDialogBoxOpened = false;
this.focus();
},
isEqual: function (value1, value2)
{
if (value1 != null && value2 != null)
{
return Ext.Object.equals(value1, value2);
}
else if (value1 == null && value2 == null)
{
return true;
}
else
{
return false;
}
},
getSubmitValue: function ()
{
var value = this.getValue();
return value ? Ext.encode(this.getValue()) : null;
},
/**
* @private
* Update warning message
* A warning is active if the field is mandatory but does not contain value for default language
*/
_updateWarning: function()
{
if (!this.allowBlank)
{
var value = this.getValue();
if (value && Ext.isObject(value) && !Ext.Object.isEmpty(value) && Ext.isEmpty(value[this.defaultLanguage]))
{
this.markWarning("{{i18n PLUGINS_CORE_UI_WIDGET_MULTILINGUAL_MANDATORY_DEFAULT_LANG_EMPTY_WARN}}");
}
else
{
this.clearWarning();
}
}
},
getErrors: function (value)
{
var me = this,
errors = [];
Ext.Object.eachValue(value, function (v) {
errors = Ext.Array.merge(me._getErrors(v), errors);
});
if (!me.allowBlank && (!value || Ext.Object.isEmpty(value)))
{
errors.push(me.blankText);
}
return errors;
},
/**
* @private
* Get errors for each single language value
* @param {String} value The value to validate
* @return {String[]} error messages
*/
_getErrors: function (value)
{
var me = this,
errors = [],
validator = me.validator,
regex = me.regex,
trimmed, isBlank;
if (Ext.isFunction(validator))
{
var msg = validator.call(me, value);
if (msg !== true) {
errors.push(msg);
}
}
trimmed = me.allowOnlyWhitespace ? value : Ext.String.trim(value);
isBlank = trimmed.length == 0 || (value === me.emptyText && me.valueContainsPlaceholder);
if (!isBlank && value.length < me.minLength) {
errors.push(Ext.String.format(me.minLengthText, me.minLength));
}
if (value.length > me.maxLength) {
errors.push(Ext.String.format(me.maxLengthText, me.maxLength));
}
if (regex && !regex.test(value)) {
errors.push(me.regexText || me.invalidText);
}
return errors;
},
getValue: function ()
{
var value = this.callParent(arguments);
if ((!value || !Ext.isObject(value)) && this.textfield.getValue())
{
value = {};
value[this.defaultLanguage] = this.textfield.getValue();
}
return value;
},
/**
* Sets a data value into the field and updates the display field
* @param {Object} value The value to set. Keys are locales.
*/
setValue: function (value)
{
if (value && !Ext.isObject(value))
{
value = Ext.JSON.decode(value);
}
this.callParent([value]);
this._updateDefaultValue(value);
},
/**
* @private
* Listener when the value of the main textfield has changed.
* Update the global value of the field
*/
_updateValueOnKeyUp: function()
{
var value = Ext.clone(this.value) || {};
var mainValue = this.textfield.getValue();
if (!Ext.isEmpty(mainValue))
{
value[this.defaultLanguage] = mainValue;
}
else if (value[this.defaultLanguage])
{
delete value[this.defaultLanguage]; // remove value for main language
}
this.setValue(value);
},
/**
* @private
* Update the displayed default value
* @param {Object} value The field's value
*/
_updateDefaultValue: function(value)
{
if (value && Ext.isObject(value) && !Ext.Object.isEmpty(value) && value[this.defaultLanguage])
{
this.textfield.setValue(value[this.defaultLanguage]);
}
else
{
this.textfield.setValue();
}
}
});