This repository has been archived on 2026-07-19. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
espocrm-base/client/src/views/fields/text.js
T
Yuri Kuznetsov 012d98d303 ref
2024-01-15 15:39:39 +02:00

453 lines
12 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/************************************************************************
* This file is part of EspoCRM.
*
* EspoCRM Open Source CRM application.
* Copyright (C) 2014-2024 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
* Website: https://www.espocrm.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* The interactive user interfaces in modified source and object code versions
* of this program must display Appropriate Legal Notices, as required under
* Section 5 of the GNU Affero General Public License version 3.
*
* In accordance with Section 7(b) of the GNU Affero General Public License version 3,
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
/** @module views/fields/text */
import BaseFieldView from 'views/fields/base';
/**
* A text field.
*/
class TextFieldView extends BaseFieldView {
type = 'text'
listTemplate = 'fields/text/list'
detailTemplate = 'fields/text/detail'
editTemplate = 'fields/text/edit'
searchTemplate = 'fields/text/search'
seeMoreText = false
rowsDefault = 50000
rowsMin = 2
seeMoreDisabled = false
cutHeight = 200
noResize = false
changeInterval = 5
shrinkThreshold = 10;
searchTypeList = [
'contains',
'startsWith',
'equals',
'endsWith',
'like',
'notContains',
'notLike',
'isEmpty',
'isNotEmpty',
]
events = {
/** @this TextFieldView */
'click a[data-action="seeMoreText"]': function () {
this.seeMoreText = true;
this.reRender();
},
/** @this TextFieldView */
'click [data-action="mailTo"]': function (e) {
this.mailTo($(e.currentTarget).data('email-address'));
},
}
/** @private */
_lastLength
/** @private */
maxRows
setup() {
super.setup();
this.maxRows = this.params.rows || this.rowsDefault;
this.noResize = this.options.noResize || this.params.noResize || this.noResize;
this.seeMoreDisabled = this.seeMoreDisabled || this.params.seeMoreDisabled;
this.autoHeightDisabled = this.options.autoHeightDisabled || this.params.autoHeightDisabled ||
this.autoHeightDisabled;
if (this.params.cutHeight) {
this.cutHeight = this.params.cutHeight;
}
this.rowsMin = this.options.rowsMin || this.params.rowsMin || this.rowsMin;
if (this.maxRows < this.rowsMin) {
this.rowsMin = this.maxRows;
}
this.on('remove', () => {
$(window).off('resize.see-more-' + this.cid);
});
}
setupSearch() {
this.events['change select.search-type'] = e => {
const type = $(e.currentTarget).val();
this.handleSearchType(type);
};
}
// noinspection JSCheckFunctionSignatures
data() {
const data = super.data();
if (
this.model.get(this.name) !== null &&
this.model.get(this.name) !== '' &&
this.model.has(this.name)
) {
data.isNotEmpty = true;
}
if (this.mode === this.MODE_SEARCH) {
if (typeof this.searchParams.value === 'string') {
this.searchData.value = this.searchParams.value;
}
}
if (this.mode === this.MODE_EDIT) {
data.rows = this.autoHeightDisabled ?
this.maxRows :
this.rowsMin;
}
data.valueIsSet = this.model.has(this.name);
if (this.isReadMode()) {
data.isCut = this.isCut();
if (data.isCut) {
data.cutHeight = this.cutHeight;
}
data.displayRawText = this.params.displayRawText;
}
data.noResize = this.noResize || (!this.autoHeightDisabled && !this.params.rows);
// noinspection JSValidateTypes
return data;
}
handleSearchType(type) {
if (~['isEmpty', 'isNotEmpty'].indexOf(type)) {
this.$el.find('input.main-element').addClass('hidden');
} else {
this.$el.find('input.main-element').removeClass('hidden');
}
}
getValueForDisplay() {
const text = this.model.get(this.name);
return text || '';
}
/**
* @public
* @param {Number} [lastHeight]
*/
controlTextareaHeight(lastHeight) {
const scrollHeight = this.$element.prop('scrollHeight');
const clientHeight = this.$element.prop('clientHeight');
if (typeof lastHeight === 'undefined' && clientHeight === 0) {
setTimeout(this.controlTextareaHeight.bind(this), 10);
return;
}
/** @type {HTMLTextAreaElement} */
const element = this.$element.get(0);
if (!element || element.value === undefined) {
return;
}
const length = element.value.length;
if (this._lastLength === undefined) {
this._lastLength = length;
}
if (length > this._lastLength) {
this._lastLength = length;
}
if (clientHeight === lastHeight) {
// @todo Revise.
return;
}
if (scrollHeight > clientHeight + 1) {
const rows = element.rows;
if (this.maxRows && rows >= this.maxRows) {
return;
}
element.rows ++;
this.controlTextareaHeight(clientHeight);
return;
}
if (this.$element.val().length === 0) {
element.rows = this.rowsMin;
return;
}
const tryShrink = () => {
const rows = element.rows;
if (this.rowsMin && rows - 1 <= this.rowsMin) {
return;
}
element.rows --;
if (element.scrollHeight > element.clientHeight + 1) {
this.controlTextareaHeight();
return;
}
tryShrink();
};
if (length < this._lastLength - this.shrinkThreshold) {
this._lastLength = length;
tryShrink();
}
}
isCut() {
return !this.seeMoreText && !this.seeMoreDisabled;
}
controlSeeMore() {
if (!this.isCut()) {
return;
}
if (this.$text.height() > this.cutHeight) {
this.$seeMoreContainer.removeClass('hidden');
this.$textContainer.addClass('cut');
} else {
this.$seeMoreContainer.addClass('hidden');
this.$textContainer.removeClass('cut');
}
}
afterRender() {
super.afterRender();
if (this.isReadMode()) {
$(window).off('resize.see-more-' + this.cid);
this.$textContainer = this.$el.find('> .complex-text-container');
this.$text = this.$textContainer.find('> .complex-text');
this.$seeMoreContainer = this.$el.find('> .see-more-container');
if (this.isCut()) {
this.controlSeeMore();
if (this.model.get(this.name) && this.$text.height() === 0) {
this.$textContainer.addClass('cut');
setTimeout(this.controlSeeMore.bind(this), 50);
}
this.listenTo(this.recordHelper, 'panel-show', () => this.controlSeeMore());
this.on('panel-show-propagated', () => this.controlSeeMore());
$(window).on('resize.see-more-' + this.cid, () => {
this.controlSeeMore();
});
}
}
if (this.mode === this.MODE_EDIT) {
const text = this.getValueForDisplay();
if (text) {
this.$element.val(text);
}
}
if (this.mode === this.MODE_SEARCH) {
const type = this.$el.find('select.search-type').val();
this.handleSearchType(type);
this.$el.find('select.search-type').on('change', () => {
this.trigger('change');
});
this.$element.on('input', () => {
this.trigger('change');
});
}
if (this.mode === this.MODE_EDIT && !this.autoHeightDisabled) {
if (!this.autoHeightDisabled) {
this.controlTextareaHeight();
this.$element.on('input', () => this.controlTextareaHeight());
}
let lastChangeKeydown = new Date();
const changeKeydownInterval = this.changeInterval * 1000;
this.$element.on('keydown', () => {
if (Date.now() - lastChangeKeydown > changeKeydownInterval) {
this.trigger('change');
lastChangeKeydown = Date.now();
}
});
}
}
fetch() {
const data = {};
let value = this.$element.val() || null;
if (value && value.trim() === '') {
value = '';
}
data[this.name] = value
return data;
}
fetchSearch() {
const type = this.fetchSearchType() || 'startsWith';
if (type === 'isEmpty') {
return {
type: 'or',
value: [
{
type: 'isNull',
field: this.name,
},
{
type: 'equals',
field: this.name,
value: ''
}
],
data: {
type: type,
},
};
}
if (type === 'isNotEmpty') {
return {
type: 'and',
value: [
{
type: 'notEquals',
field: this.name,
value: '',
},
{
type: 'isNotNull',
field: this.name,
value: null,
}
],
data: {
type: type,
},
};
}
const value = this.$element.val().toString().trim();
if (value) {
return {
value: value,
type: type,
};
}
return false;
}
getSearchType() {
return this.getSearchParamsData().type || this.searchParams.typeFront ||
this.searchParams.type;
}
mailTo(emailAddress) {
const attributes = {
status: 'Draft',
to: emailAddress,
};
if (
this.getConfig().get('emailForceUseExternalClient') ||
this.getPreferences().get('emailUseExternalClient') ||
!this.getAcl().checkScope('Email', 'create')
) {
Espo.loader.require('email-helper', EmailHelper => {
const emailHelper = new EmailHelper();
document.location.href = emailHelper
.composeMailToLink(attributes, this.getConfig().get('outboundEmailBccAddress'));
});
return;
}
const viewName = this.getMetadata().get('clientDefs.' + this.scope + '.modalViews.compose') ||
'views/modals/compose-email';
Espo.Ui.notify(' ... ');
this.createView('quickCreate', viewName, {
attributes: attributes,
}, view => {
view.render();
Espo.Ui.notify(false);
});
}
}
export default TextFieldView;