url-multiple field
This commit is contained in:
@@ -40,7 +40,7 @@ class ArrayType
|
||||
{
|
||||
private const DEFAULT_MAX_ITEM_LENGTH = 100;
|
||||
|
||||
public function __construct(private Metadata $metadata, private Defs $defs)
|
||||
public function __construct(protected Metadata $metadata, private Defs $defs)
|
||||
{}
|
||||
|
||||
public function checkRequired(Entity $entity, string $field): bool
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://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 General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
namespace Espo\Classes\FieldValidators;
|
||||
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
class UrlMultipleType extends ArrayType
|
||||
{
|
||||
private const MAX_ITEM_LENGTH = 255;
|
||||
|
||||
public function checkNoEmptyString(Entity $entity, string $field, ?bool $validationValue): bool
|
||||
{
|
||||
return parent::checkNoEmptyString($entity, $field, true);
|
||||
}
|
||||
|
||||
public function checkMaxItemLength(Entity $entity, string $field, ?int $validationValue): bool
|
||||
{
|
||||
return parent::checkMaxItemLength($entity, $field, self::MAX_ITEM_LENGTH);
|
||||
}
|
||||
|
||||
public function checkPattern(Entity $entity, string $field, ?string $validationValue): bool
|
||||
{
|
||||
/** @var string $pattern */
|
||||
$pattern = $this->metadata->get(['app', 'regExpPatterns', 'uriOptionalProtocol', 'pattern']);
|
||||
|
||||
return parent::checkPattern($entity, $field, $pattern);
|
||||
}
|
||||
}
|
||||
@@ -30,20 +30,22 @@
|
||||
namespace Espo\Repositories;
|
||||
|
||||
use Espo\Core\ORM\Entity as CoreEntity;
|
||||
use Espo\Entities\ArrayValue as ArrayValueEntity;
|
||||
use Espo\ORM\Entity;
|
||||
|
||||
use Espo\Core\Repositories\Database;
|
||||
|
||||
use RuntimeException;
|
||||
use LogicException;
|
||||
|
||||
/**
|
||||
* @extends Database<\Espo\Entities\ArrayValue>
|
||||
* @extends Database<ArrayValueEntity>
|
||||
*/
|
||||
class ArrayValue extends Database
|
||||
{
|
||||
protected $hooksDisabled = true;
|
||||
|
||||
private const ITEM_MAX_LENGTH = 100;
|
||||
|
||||
public function storeEntityAttribute(CoreEntity $entity, string $attribute, bool $populateMode = false): void
|
||||
{
|
||||
if ($entity->getAttributeType($attribute) !== Entity::JSON_ARRAY) {
|
||||
@@ -73,7 +75,6 @@ class ArrayValue extends Database
|
||||
}
|
||||
|
||||
$valueList = array_unique($valueList);
|
||||
|
||||
$toSkipValueList = [];
|
||||
|
||||
$isTransaction = false;
|
||||
@@ -104,6 +105,12 @@ class ArrayValue extends Database
|
||||
}
|
||||
}
|
||||
|
||||
$itemMaxLength = $this->entityManager
|
||||
->getDefs()
|
||||
->getEntity(ArrayValueEntity::ENTITY_TYPE)
|
||||
->getField('value')
|
||||
->getParam('maxLength') ?? self::ITEM_MAX_LENGTH;
|
||||
|
||||
foreach ($valueList as $value) {
|
||||
if (in_array($value, $toSkipValueList)) {
|
||||
continue;
|
||||
@@ -113,6 +120,10 @@ class ArrayValue extends Database
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen($value) > $itemMaxLength) {
|
||||
$value = substr($value, 0, $itemMaxLength);
|
||||
}
|
||||
|
||||
$arrayValue = $this->getNew();
|
||||
|
||||
$arrayValue->set([
|
||||
|
||||
@@ -136,6 +136,7 @@
|
||||
"phone": "Phone",
|
||||
"text": "Text",
|
||||
"url": "Url",
|
||||
"urlMultiple": "Url Multiple",
|
||||
"varchar": "Varchar",
|
||||
"file": "File",
|
||||
"image": "Image",
|
||||
|
||||
@@ -144,6 +144,7 @@
|
||||
"array": "A list of values, similar to Multi-Enum field.",
|
||||
"address": "An address with street, city, state, postal code and country.",
|
||||
"url": "For storing links.",
|
||||
"urlMultiple": "Multiple links.",
|
||||
"wysiwyg": "A text with HTML support.",
|
||||
"file": "For file uploading.",
|
||||
"image": "For image uploading.",
|
||||
|
||||
@@ -308,6 +308,7 @@
|
||||
"fieldNotMatchingPattern$latinLettersDigitsWhitespace": "{field} can contain only latin letters, digits and whitespace",
|
||||
"fieldNotMatchingPattern$latinLettersWhitespace": "{field} can contain only latin letters and whitespace",
|
||||
"fieldNotMatchingPattern$digits": "{field} can contain only digits",
|
||||
"fieldNotMatchingPattern$uriOptionalProtocol": "{field} must be a valid URL",
|
||||
"fieldInvalid": "{field} is invalid",
|
||||
"fieldIsRequired": "{field} is required",
|
||||
"fieldPhoneInvalidCharacters": "Only digits, latin letters and characters `-+_@:#().` are allowed",
|
||||
|
||||
@@ -247,6 +247,10 @@
|
||||
"checklist": {
|
||||
"view": "views/admin/dynamic-logic/conditions/field-types/multi-enum",
|
||||
"typeList": ["isEmpty", "isNotEmpty", "has", "notHas"]
|
||||
},
|
||||
"urlMultiple": {
|
||||
"view": "views/admin/dynamic-logic/conditions/field-types/multi-enum",
|
||||
"typeList": ["isEmpty", "isNotEmpty"]
|
||||
}
|
||||
},
|
||||
"conditionTypes": {
|
||||
@@ -317,4 +321,4 @@
|
||||
"valueType": "varchar"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"params": [
|
||||
{
|
||||
"name": "required",
|
||||
"type": "bool",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"name": "maxCount",
|
||||
"type": "int",
|
||||
"min": 1,
|
||||
"tooltip": true
|
||||
},
|
||||
{
|
||||
"name": "strip",
|
||||
"type": "bool",
|
||||
"default": false,
|
||||
"tooltip": "urlStrip"
|
||||
},
|
||||
{
|
||||
"name": "audited",
|
||||
"type": "bool"
|
||||
},
|
||||
{
|
||||
"name": "readOnly",
|
||||
"type": "bool"
|
||||
}
|
||||
],
|
||||
"validationList": [
|
||||
"required",
|
||||
"maxCount"
|
||||
],
|
||||
"mandatoryValidationList": [
|
||||
"array",
|
||||
"arrayOfString",
|
||||
"valid",
|
||||
"maxItemLength",
|
||||
"pattern",
|
||||
"noEmptyString"
|
||||
],
|
||||
"filter": true,
|
||||
"notCreatable": false,
|
||||
"notSortable": true,
|
||||
"fieldDefs": {
|
||||
"type": "jsonArray",
|
||||
"storeArrayValues": true
|
||||
},
|
||||
"personalData": true,
|
||||
"massUpdateActionList": [
|
||||
"update",
|
||||
"add",
|
||||
"remove"
|
||||
]
|
||||
}
|
||||
@@ -386,7 +386,7 @@ function (Dep, RegExpPattern, /** module:ui/multi-select*/MultiSelect) {
|
||||
this.trigger('change');
|
||||
},
|
||||
distance: 5,
|
||||
cancel: 'input,textarea,button,select,option,a',
|
||||
cancel: 'input,textarea,button,select,option,a[role="button"]',
|
||||
cursor: 'grabbing',
|
||||
});
|
||||
}
|
||||
@@ -604,9 +604,10 @@ function (Dep, RegExpPattern, /** module:ui/multi-select*/MultiSelect) {
|
||||
)
|
||||
.append(
|
||||
$('<span>')
|
||||
.addClass('text')
|
||||
.text(text)
|
||||
.append(' ')
|
||||
)
|
||||
.append('')
|
||||
.get(0)
|
||||
.outerHTML;
|
||||
},
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2023 Yurii Kuznietsov, Taras Machyshyn, Oleksii Avramenko
|
||||
* Website: https://www.espocrm.com
|
||||
*
|
||||
* EspoCRM is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* EspoCRM 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with EspoCRM. If not, see http://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 General Public License version 3.
|
||||
*
|
||||
* In accordance with Section 7(b) of the GNU General Public License version 3,
|
||||
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
|
||||
************************************************************************/
|
||||
|
||||
define('views/fields/url-multiple', ['views/fields/array'], function (Dep) {
|
||||
|
||||
/**
|
||||
* An Url-Multiple field.
|
||||
*
|
||||
* @class
|
||||
* @name Class
|
||||
* @extends module:views/fields/array.Class
|
||||
* @memberOf module:views/fields/url-multiple
|
||||
*/
|
||||
return Dep.extend(/** @lends module:views/fields/url-multiple.Class# */{
|
||||
|
||||
type: 'urlMultiple',
|
||||
|
||||
maxItemLength: 255,
|
||||
displayAsList: true,
|
||||
defaultProtocol: 'https:',
|
||||
|
||||
setup: function () {
|
||||
Dep.prototype.setup.call(this);
|
||||
|
||||
this.noEmptyString = true;
|
||||
this.params.pattern = '$uriOptionalProtocol';
|
||||
},
|
||||
|
||||
addValueFromUi: function (value) {
|
||||
value = value.trim();
|
||||
|
||||
if (this.params.strip) {
|
||||
value = this.strip(value);
|
||||
}
|
||||
|
||||
if (value === decodeURI(value)) {
|
||||
value = encodeURI(value);
|
||||
}
|
||||
|
||||
Dep.prototype.addValueFromUi.call(this, value);
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @return {string}
|
||||
*/
|
||||
strip: function (value) {
|
||||
if (value.indexOf('//') !== -1) {
|
||||
value = value.substring(value.indexOf('//') + 2);
|
||||
}
|
||||
|
||||
value = value.replace(/\/+$/, '');
|
||||
|
||||
return value;
|
||||
},
|
||||
|
||||
prepareUrl: function (url) {
|
||||
if (url.indexOf('//') === -1) {
|
||||
url = this.defaultProtocol + '//' + url;
|
||||
}
|
||||
|
||||
return url;
|
||||
},
|
||||
|
||||
getValueForDisplay: function () {
|
||||
/** @type {JQuery[]} */
|
||||
let $list = this.selected.map(value => {
|
||||
return $('<a>')
|
||||
.attr('href', this.prepareUrl(value))
|
||||
.attr('target', '_blank')
|
||||
.text(decodeURI(value));
|
||||
});
|
||||
|
||||
return $list
|
||||
.map($item =>
|
||||
$('<div>')
|
||||
.addClass('multi-enum-item-container')
|
||||
.append($item)
|
||||
.get(0).outerHTML
|
||||
)
|
||||
.join('');
|
||||
},
|
||||
|
||||
getItemHtml: function (value) {
|
||||
let html = Dep.prototype.getItemHtml.call(this, value);
|
||||
|
||||
let $item = $(html);
|
||||
|
||||
$item.find('span.text').html(
|
||||
$('<a>')
|
||||
.attr('href', this.prepareUrl(value))
|
||||
.css('user-drag', 'none')
|
||||
.attr('target', '_blank')
|
||||
.text(decodeURI(value))
|
||||
);
|
||||
|
||||
return $item.get(0).outerHTML;
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1132,8 +1132,6 @@ input.global-search-input {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.link-container {
|
||||
> .list-group-item {
|
||||
.link-item-column {
|
||||
@@ -1151,18 +1149,18 @@ input.global-search-input {
|
||||
}
|
||||
}
|
||||
|
||||
.filter .field .link-container .list-group-item a {
|
||||
.filter .field .link-container .list-group-item a[role="button"] {
|
||||
margin-top: 1px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.field .link-container .list-group-item a {
|
||||
.field .link-container .list-group-item a[role="button"] {
|
||||
margin-top: 1px;
|
||||
margin-left: 2px;
|
||||
}
|
||||
|
||||
.field .link-container > .list-group-item.link-with-role > a,
|
||||
.field .link-container > .list-group-item.link-with-role > div > a {
|
||||
.field .link-container > .list-group-item.link-with-role > a[role="button"],
|
||||
.field .link-container > .list-group-item.link-with-role > div > a[role="button"] {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user