')
.addClass(itemClassName)
.html(item)
.get(0).outerHTML
)
.join('');
}
if (this.displayAsLabel) {
return list.join(' ');
}
return list.join(', ');
}
/**
* @protected
* @param {string} value
* @return {string}
*/
getItemHtml(value) {
// Do not use the `html` method to avoid XSS.
if (this.translatedOptions !== null) {
for (const item in this.translatedOptions) {
if (this.translatedOptions[item] === value) {
value = item;
break;
}
}
}
value = value.toString();
const text = this.translatedOptions && value in this.translatedOptions ?
this.translatedOptions[value].toString() :
value;
const div = document.createElement('div');
div.className = 'list-group-item';
div.dataset.value = value;
div.style.cursor = 'default';
if (!this.params.keepItems) {
const a = document.createElement('a');
a.role = 'button';
a.tabIndex = 0;
a.classList.add('pull-right');
a.dataset.value = value;
a.dataset.action = 'removeValue';
a.append(
(() => {
const span = document.createElement('span');
span.className = 'fas fa-times'
return span;
})(),
);
div.append(a);
}
div.append(
(() => {
const span = document.createElement('span');
span.className = 'drag-handle';
span.append(
(() => {
const span = document.createElement('span');
span.className = 'fas fa-grip fa-sm';
return span;
})(),
);
return span;
})(),
);
if (this.params.itemsEditable && this.allowCustomOptions) {
div.append(
(() => {
const span = document.createElement('span');
span.className = 'item-button'
span.append(
(() => {
const a = document.createElement('a');
a.role = 'button';
a.tabIndex = 0;
a.dataset.value = value;
a.dataset.action = 'editItem';
a.append(
(() => {
const span = document.createElement('span');
span.className = 'fas fa-pencil-alt fa-sm';
return span;
})(),
);
return a;
})(),
)
return span;
})(),
);
}
div.append(
(() => {
const span = document.createElement('span');
span.classList.add('text');
span.textContent = text;
return span;
})(),
);
return div.outerHTML;
}
/**
* @param {string} value
*/
addValue(value) {
if (this.selected.indexOf(value) === -1) {
const html = this.getItemHtml(value);
this.$list.append(html);
this.selected.push(value);
this.trigger('change');
}
}
/**
* @param {string} value
*/
removeValue(value) {
const valueInternal = CSS.escape(value);
this.$list.children('[data-value="' + valueInternal + '"]').remove();
const index = this.selected.indexOf(value);
this.selected.splice(index, 1);
this.trigger('change');
}
fetch() {
const data = {};
let list = Espo.Utils.clone(this.selected || []);
if (this.params.isSorted && this.translatedOptions) {
list = list.sort((v1, v2) => {
return (this.translatedOptions[v1] || v1)
.localeCompare(this.translatedOptions[v2] || v2);
});
}
data[this.name] = list;
return data;
}
fetchSearch() {
const type = this.$el.find('select.search-type').val() || 'anyOf';
let valueList;
if (~['anyOf', 'noneOf', 'allOf'].indexOf(type)) {
valueList = this.$element.val().split(this.itemDelimiter);
if (valueList.length === 1 && valueList[0] === '') {
valueList = [];
}
if (valueList.length === 0) {
if (type === 'anyOf') {
return {
type: 'any',
data: {
type: type,
valueList: valueList,
},
};
}
if (type === 'noneOf') {
return {
type: 'any',
data: {
type: type,
valueList: valueList,
},
};
}
if (type === 'allOf') {
return {
type: 'any',
data: {
type: type,
valueList: valueList,
},
};
}
}
}
if (type === 'anyOf') {
const data = {
type: 'arrayAnyOf',
value: valueList,
data: {
type: 'anyOf',
valueList: valueList,
},
};
if (!valueList.length) {
data.value = null;
}
return data;
}
if (type === 'noneOf') {
return {
type: 'arrayNoneOf',
value: valueList,
data: {
type: 'noneOf',
valueList: valueList,
},
};
}
if (type === 'allOf') {
const data = {
type: 'arrayAllOf',
value: valueList,
data: {
type: 'allOf',
valueList: valueList,
},
};
if (!valueList.length) {
data.value = null;
}
return data;
}
if (type === 'isEmpty') {
return {
type: 'arrayIsEmpty',
data: {
type: 'isEmpty',
},
};
}
if (type === 'isNotEmpty') {
return {
type: 'arrayIsNotEmpty',
data: {
type: 'isNotEmpty',
},
};
}
return null;
}
validateRequired() {
if (this.isRequired()) {
const value = this.model.get(this.name);
if (!value || value.length === 0) {
const msg = this.translate('fieldIsRequired', 'messages')
.replace('{field}', this.getLabelText());
this.showValidationMessage(msg, '.array-control-container');
return true;
}
}
return false;
}
// noinspection JSUnusedGlobalSymbols
validateMaxCount() {
if (this.params.maxCount) {
const itemList = this.model.get(this.name) || [];
if (itemList.length > this.params.maxCount) {
const msg =
this.translate('fieldExceedsMaxCount', 'messages')
.replace('{field}', this.getLabelText())
.replace('{maxCount}', this.params.maxCount.toString());
this.showValidationMessage(msg, '.array-control-container');
return true;
}
}
return false;
}
getSearchType() {
return this.getSearchParamsData().type || 'anyOf';
}
/**
* @return {{
* translatedOptions: Object.
|null,
* options: string[],
* } | Object.}
*/
getAddItemModalOptions() {
const options = [];
this.params.options.forEach(item => {
if (!~this.selected.indexOf(item)) {
options.push(item);
}
});
return {
options: options,
translatedOptions: this.translatedOptions,
};
}
/**
* @protected
* @return {Promise}
*/
actionAddItem() {
return this.createView('dialog', this.addItemModalView, this.getAddItemModalOptions(), view => {
view.render();
view.once('add', item => {
this.addValue(item);
view.close();
});
view.once('add-mass', items => {
items.forEach(item => this.addValue(item));
view.close();
});
});
}
/**
* @protected
* @param value
*/
async actionEditItem(value) {
const view = new EditItemModalView({
value: value,
required: this.noEmptyString,
maxLength: this.maxItemLength,
onApply: async data => {
const index = this.selected.findIndex(it => it === value);
if (index < 0) {
return;
}
this.selected[index] = data.value;
this.selected = this.selected.filter((it, i) => this.selected.indexOf(it) === i);
await this.reRender();
this.trigger('change');
},
});
await this.assignView('dialog', view);
await view.render();
}
// noinspection JSUnusedGlobalSymbols
/**
* @protected
* @return {boolean}
*/
validateNoInputValue() {
if (!this.element) {
return false;
}
const input = this.element.querySelector('input.select');
if (!(input instanceof HTMLInputElement)) {
return false;
}
if (!input.value) {
return false;
}
const message = this.translate('arrayInputNotEmpty', 'messages');
this.showValidationMessage(message, 'input.select');
return true;
}
}
export default ArrayFieldView;
class EditItemModalView extends ModalView {
// language=Handlebars
templateContent = `
{{{record}}}
`
/**
* @private
* @type {EditForModalRecordView}
*/
recordView
/**
*
* @param {{
* value: string,
* maxLength: number,
* required: boolean,
* onApply: function({value: string}),
* }} options
*/
constructor(options) {
super(options);
this.options = options;
}
setup() {
this.buttonList = [
{
name: 'apply',
label: 'Apply',
style: 'danger',
onClick: () => this.actionApply(),
},
{
name: 'cancel',
label: 'Cancel',
onClick: () => this.actionCancel(),
},
];
this.shortcutKeys = {
'Control+Enter': () => this.actionApply(),
};
this.headerText = this.translate('Edit Item');
this.model = new Model({
value: this.options.value,
});
this.recordView = new EditForModalRecordView({
model: this.model,
detailLayout: [
{
rows: [
[
{
view: new VarcharFieldView({
name: 'value',
labelText: this.translate('Value'),
params: {
required: this.options.required,
maxLength: this.options.maxLength,
},
})
},
false
]
],
},
],
});
this.assignView('record', this.recordView);
}
/**
* @private
*/
actionApply() {
const data = this.recordView.processFetch();
if (!data) {
return;
}
const value = this.model.attributes.value ?? '';
this.options.onApply({value});
this.close();
}
}