Merge branch 'hotfix/5.5.6'
This commit is contained in:
@@ -106,6 +106,13 @@ class User extends \Espo\Core\Controllers\Record
|
||||
return $this->getService('User')->passwordChangeRequest($userName, $emailAddress, $url);
|
||||
}
|
||||
|
||||
public function postActionGenerateNewApiKey($params, $data, $request)
|
||||
{
|
||||
if (empty($data->id)) throw new BadRequest();
|
||||
if (!$this->getUser()->isAdmin()) throw new Forbidden();
|
||||
return $this->getRecordService()->generateNewApiKeyForEntity($data->id)->getValueMap();
|
||||
}
|
||||
|
||||
public function actionCreateLink($params, $data, $request)
|
||||
{
|
||||
if (!$this->getUser()->isAdmin()) throw new Forbidden();
|
||||
|
||||
@@ -843,7 +843,7 @@ class Base
|
||||
return $this->userTimeZone;
|
||||
}
|
||||
|
||||
public function convertDateTimeWhere($item)
|
||||
public function transformDateTimeWhereItem($item)
|
||||
{
|
||||
$format = 'Y-m-d H:i:s';
|
||||
|
||||
@@ -997,6 +997,7 @@ class Base
|
||||
$dt->setTimezone(new \DateTimeZone('UTC'));
|
||||
$where['value'] = $dt->format($format);
|
||||
break;
|
||||
|
||||
case 'between':
|
||||
$where['type'] = 'between';
|
||||
if (is_array($value)) {
|
||||
@@ -1012,11 +1013,143 @@ class Base
|
||||
$where['value'] = [$from, $to];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'currentMonth':
|
||||
case 'lastMonth':
|
||||
case 'nextMonth':
|
||||
$where['type'] = 'between';
|
||||
$dtFrom = new \DateTime('now', new \DateTimeZone($timeZone));
|
||||
$dtFrom = $dt->modify('first day of this month')->setTime(0, 0, 0);
|
||||
|
||||
if ($type == 'lastMonth') {
|
||||
$dtFrom->modify('-1 month');
|
||||
} else if ($type == 'nextMonth') {
|
||||
$dtFrom->modify('+1 month');
|
||||
}
|
||||
|
||||
$dtTo = clone $dtFrom;
|
||||
$dtTo->modify('+1 month');
|
||||
|
||||
$dtFrom->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dtTo->setTimezone(new \DateTimeZone('UTC'));
|
||||
|
||||
$where['value'] = [$dtFrom->format($format), $dtTo->format($format)];
|
||||
break;
|
||||
|
||||
case 'currentQuarter':
|
||||
case 'lastQuarter':
|
||||
$where['type'] = 'between';
|
||||
$dt = new \DateTime('now', new \DateTimeZone($timeZone));
|
||||
$quarter = ceil($dt->format('m') / 3);
|
||||
|
||||
$dtFrom = clone $dt;
|
||||
$dtFrom->modify('first day of January this year')->setTime(0, 0, 0);
|
||||
|
||||
if ($type === 'lastQuarter') {
|
||||
$quarter--;
|
||||
if ($quarter == 0) {
|
||||
$quarter = 4;
|
||||
$dtFrom->modify('-1 year');
|
||||
}
|
||||
}
|
||||
|
||||
$dtFrom->add(new \DateInterval('P'.(($quarter - 1) * 3).'M'));
|
||||
$dtTo = clone $dtFrom;
|
||||
$dtTo->add(new \DateInterval('P3M'));
|
||||
$dtFrom->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dtTo->setTimezone(new \DateTimeZone('UTC'));
|
||||
$where['value'] = [
|
||||
$dtFrom->format($format),
|
||||
$dtTo->format($format)
|
||||
];
|
||||
break;
|
||||
|
||||
case 'currentYear':
|
||||
case 'lastYear':
|
||||
$where['type'] = 'between';
|
||||
$dtFrom = new \DateTime('now', new \DateTimeZone($timeZone));
|
||||
$dtFrom->modify('first day of January this year')->setTime(0, 0, 0);
|
||||
if ($type == 'lastYear') {
|
||||
$dtFrom->modify('-1 year');
|
||||
}
|
||||
$dtTo = clone $dtFrom;
|
||||
$dtTo = $dtTo->modify('+1 year');
|
||||
$dtFrom->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dtTo->setTimezone(new \DateTimeZone('UTC'));
|
||||
$where['value'] = [
|
||||
$dtFrom->format($format),
|
||||
$dtTo->format($format)
|
||||
];
|
||||
break;
|
||||
|
||||
case 'currentFiscalYear':
|
||||
case 'lastFiscalYear':
|
||||
$where['type'] = 'between';
|
||||
$dtToday = new \DateTime('now', new \DateTimeZone($timeZone));
|
||||
$dt = clone $dtToday;
|
||||
$fiscalYearShift = $this->getConfig()->get('fiscalYearShift', 0);
|
||||
$dt->modify('first day of January this year')->modify('+' . $fiscalYearShift . ' months')->setTime(0, 0, 0);
|
||||
if (intval($dtToday->format('m')) < $fiscalYearShift + 1) {
|
||||
$dt->modify('-1 year');
|
||||
}
|
||||
if ($type === 'lastFiscalYear') {
|
||||
$dt->modify('-1 year');
|
||||
}
|
||||
$dtFrom = clone $dt;
|
||||
$dtTo = clone $dt;
|
||||
$dtTo = $dtTo->modify('+1 year');
|
||||
$dtFrom->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dtTo->setTimezone(new \DateTimeZone('UTC'));
|
||||
$where['value'] = [
|
||||
$dtFrom->format($format),
|
||||
$dtTo->format($format)
|
||||
];
|
||||
break;
|
||||
|
||||
case 'currentFiscalQuarter':
|
||||
case 'lastFiscalQuarter':
|
||||
$where['type'] = 'between';
|
||||
$dtToday = new \DateTime('now', new \DateTimeZone($timeZone));
|
||||
$dt = clone $dtToday;
|
||||
$fiscalYearShift = $this->getConfig()->get('fiscalYearShift', 0);
|
||||
$dt->modify('first day of January this year')->modify('+' . $fiscalYearShift . ' months')->setTime(0, 0, 0);
|
||||
$month = intval($dtToday->format('m'));
|
||||
$quarterShift = floor(($month - $fiscalYearShift - 1) / 3);
|
||||
if ($quarterShift) {
|
||||
if ($quarterShift >= 0) {
|
||||
$dt->add(new \DateInterval('P'.($quarterShift * 3).'M'));
|
||||
} else {
|
||||
$quarterShift *= -1;
|
||||
$dt->sub(new \DateInterval('P'.($quarterShift * 3).'M'));
|
||||
}
|
||||
}
|
||||
if ($type === 'lastFiscalQuarter') {
|
||||
$dt->modify('-3 months');
|
||||
}
|
||||
$dtFrom = clone $dt;
|
||||
$dtTo = clone $dt;
|
||||
$dtTo = $dtTo->modify('+3 months');
|
||||
$dtFrom->setTimezone(new \DateTimeZone('UTC'));
|
||||
$dtTo->setTimezone(new \DateTimeZone('UTC'));
|
||||
$where['value'] = [
|
||||
$dtFrom->format($format),
|
||||
$dtTo->format($format)
|
||||
];
|
||||
break;
|
||||
|
||||
default:
|
||||
$where['type'] = $type;
|
||||
}
|
||||
$result = $this->getWherePart($where);
|
||||
|
||||
$where['originalType'] = $type;
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
public function convertDateTimeWhere($item)
|
||||
{
|
||||
$where = $this->transformDateTimeWhereItem($item);
|
||||
$result = $this->getWherePart($where);
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -1056,6 +1189,11 @@ class Base
|
||||
}
|
||||
$value = $item['value'];
|
||||
|
||||
$timeZone = null;
|
||||
if (isset($item['timeZone'])) {
|
||||
$timeZone = $item['timeZone'];
|
||||
}
|
||||
|
||||
if (!empty($item['type'])) {
|
||||
$type = $item['type'];
|
||||
|
||||
|
||||
@@ -37,6 +37,10 @@ class DateTime
|
||||
|
||||
protected $timezone;
|
||||
|
||||
public static $systemDateTimeFormat = 'Y-m-d H:i:s';
|
||||
|
||||
public static $systemDateFormat = 'Y-m-d';
|
||||
|
||||
protected $internalDateTimeFormat = 'Y-m-d H:i:s';
|
||||
|
||||
protected $internalDateFormat = 'Y-m-d';
|
||||
|
||||
@@ -208,30 +208,33 @@ class ScheduledJob
|
||||
*/
|
||||
public function isCronConfigured()
|
||||
{
|
||||
$startDate = new \DateTime('-' . $this->checkingCronPeriod, new \DateTimeZone("UTC"));
|
||||
$endDate = new \DateTime('+' . $this->checkingCronPeriod, new \DateTimeZone("UTC"));
|
||||
$r1From = new \DateTime('-' . $this->checkingCronPeriod);
|
||||
$r1To = new \DateTime('+' . $this->checkingCronPeriod);
|
||||
|
||||
$query = "
|
||||
SELECT job.id FROM scheduled_job
|
||||
LEFT JOIN job ON job.scheduled_job_id = scheduled_job.id AND job.deleted = 0
|
||||
WHERE
|
||||
scheduled_job.job = 'Dummy'
|
||||
AND scheduled_job.deleted = 0
|
||||
AND job.execute_time BETWEEN '". $startDate->format('Y-m-d H:i:s') ."' AND '". $endDate->format('Y-m-d H:i:s') ."'
|
||||
AND job.status IN ('Success', 'Failed', 'Pending')
|
||||
ORDER BY job.execute_time DESC
|
||||
";
|
||||
$r2From = new \DateTime('- 1 hour');
|
||||
$r2To = new \DateTime();
|
||||
|
||||
$pdo = $this->getEntityManager()->getPDO();
|
||||
$sth = $pdo->prepare($query);
|
||||
$sth->execute();
|
||||
$format = \Espo\Core\Utils\DateTime::$systemDateTimeFormat;
|
||||
|
||||
$row = $sth->fetch(\PDO::FETCH_ASSOC);
|
||||
$selectParams = [
|
||||
'select' => ['id'],
|
||||
'leftJoins' => ['scheduledJob'],
|
||||
'whereClause' => [
|
||||
'OR' => [
|
||||
[
|
||||
['executedAt>=' => $r2From->format($format)] ,
|
||||
['executedAt<=' => $r2To->format($format)],
|
||||
],
|
||||
[
|
||||
['executeTime>=' => $r1From->format($format)],
|
||||
['executeTime<='=> $r1To->format($format)],
|
||||
'scheduledJob.job' => 'Dummy'
|
||||
]
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
if (!empty($row['id'])) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return !!$this->getEntityManager()->getRepository('Job')->findOne($selectParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,10 @@ use \Espo\ORM\Entity;
|
||||
|
||||
class Task extends \Espo\Services\Record
|
||||
{
|
||||
protected $selectAttributesDependancyMap = [
|
||||
'dateEnd' => ['status']
|
||||
];
|
||||
|
||||
public function loadAdditionalFields(Entity $entity)
|
||||
{
|
||||
parent::loadAdditionalFields($entity);
|
||||
|
||||
@@ -296,7 +296,7 @@ abstract class Base
|
||||
throw new \Exception("Not allowed function '".$function."'.");
|
||||
}
|
||||
|
||||
if (strpos($function, 'YEAR_') === 0) {
|
||||
if (strpos($function, 'YEAR_') === 0 && $function !== 'YEAR_NUMBER') {
|
||||
$fiscalShift = substr($function, 5);
|
||||
if (is_numeric($fiscalShift)) {
|
||||
$fiscalShift = intval($fiscalShift);
|
||||
@@ -309,7 +309,7 @@ abstract class Base
|
||||
}
|
||||
}
|
||||
|
||||
if (strpos($function, 'QUARTER_') === 0) {
|
||||
if (strpos($function, 'QUARTER_') === 0 && $function !== 'QUARTER_NUMBER') {
|
||||
$fiscalShift = substr($function, 8);
|
||||
if (is_numeric($fiscalShift)) {
|
||||
$fiscalShift = intval($fiscalShift);
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"placeholderTexts": {
|
||||
"today": "Today's date",
|
||||
"now": "Current date & time",
|
||||
"currentYear": "Current Year",
|
||||
"optOutUrl": "URL for an unsubsbribe link",
|
||||
"optOutLink": "an unsubscribe link"
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@
|
||||
"outboundEmailBccAddress": "BCC address for external clients",
|
||||
"cleanupDeletedRecords": "Clean up deleted records",
|
||||
"addressCountryList": "Address Country Autocomplete List",
|
||||
"addressCityList": "Address City Autocomplete List",
|
||||
"fiscalYearShift": "Fiscal Year Start",
|
||||
"jobRunInParallel": "Jobs Run in Parallel",
|
||||
"jobMaxPortion": "Jobs Max Portion",
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
[{"name": "language"}, {"name": "timeZone"}],
|
||||
[{"name": "dateFormat"}, {"name": "weekStart"}],
|
||||
[{"name": "timeFormat"}, {"name": "thousandSeparator"}],
|
||||
[{"name": "addressFormat"}, {"name": "decimalMark"}],
|
||||
[{"name": "addressPreview"}, {"name": "addressCountryList"}],
|
||||
[{"name": "fiscalYearShift"}, false]
|
||||
[{"name": "fiscalYearShift"}, {"name": "decimalMark"}],
|
||||
[{"name": "addressFormat"}, {"name": "addressPreview"}],
|
||||
[{"name": "addressCountryList"}, {"name": "addressCityList"}]
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -43,6 +43,6 @@
|
||||
"filterList": [
|
||||
"actual"
|
||||
],
|
||||
"placeholderList": ["today", "now", "optOutUrl", "optOutLink"],
|
||||
"placeholderList": ["today", "now", "currentYear", "optOutUrl", "optOutLink"],
|
||||
"iconClass": "fas fa-envelope-square"
|
||||
}
|
||||
|
||||
@@ -505,6 +505,9 @@
|
||||
"addressCountryList": {
|
||||
"type": "multiEnum"
|
||||
},
|
||||
"addressCityList": {
|
||||
"type": "multiEnum"
|
||||
},
|
||||
"jobRunInParallel": {
|
||||
"type": "bool",
|
||||
"tooltip": true
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
},
|
||||
"city":{
|
||||
"type":"varchar",
|
||||
"trim": true
|
||||
"trim": true,
|
||||
"view": "views/fields/address-city",
|
||||
"customizationOptionsDisabled": true
|
||||
},
|
||||
"state":{
|
||||
"type":"varchar",
|
||||
|
||||
@@ -276,6 +276,11 @@ class EmailTemplate extends Record
|
||||
$replaceData['today'] = $this->getDateTime()->getTodayString();
|
||||
$replaceData['now'] = $this->getDateTime()->getNowString();
|
||||
|
||||
$timeZone = $this->getConfig()->get('timeZone');
|
||||
$now = new \DateTime('now', new \DateTimezone($timeZone));
|
||||
|
||||
$replaceData['currentYear'] = $now->format('Y');
|
||||
|
||||
foreach ($replaceData as $key => $value) {
|
||||
$text = str_replace('{' . $key . '}', $value, $text);
|
||||
}
|
||||
|
||||
@@ -82,6 +82,11 @@ class Note extends Record
|
||||
protected function beforeCreateEntity(Entity $entity, $data)
|
||||
{
|
||||
parent::beforeCreateEntity($entity, $data);
|
||||
|
||||
if ($entity->get('type') === 'Post') {
|
||||
$this->handlePostText($entity);
|
||||
}
|
||||
|
||||
$targetType = $entity->get('targetType');
|
||||
|
||||
$entity->clear('isGlobal');
|
||||
@@ -119,6 +124,10 @@ class Note extends Record
|
||||
{
|
||||
parent::beforeUpdateEntity($entity, $data);
|
||||
|
||||
if ($entity->get('type') === 'Post') {
|
||||
$this->handlePostText($entity);
|
||||
}
|
||||
|
||||
$entity->clear('targetType');
|
||||
$entity->clear('usersIds');
|
||||
$entity->clear('teamsIds');
|
||||
@@ -126,6 +135,19 @@ class Note extends Record
|
||||
$entity->clear('isGlobal');
|
||||
}
|
||||
|
||||
protected function handlePostText(Entity $entity)
|
||||
{
|
||||
$post = $entity->get('post');
|
||||
if (empty($post)) return;
|
||||
|
||||
$siteUrl = $this->getConfig()->getSiteUrl();
|
||||
|
||||
$regexp = '/' . preg_quote($siteUrl, '/') . '(\/portal|\/portal\/[a-zA-Z0-9]*)?\/#([A-Z][a-zA-Z0-9]*)\/view\/([a-zA-Z0-9]*)/';
|
||||
$post = preg_replace($regexp, '[\2/\3](#\2/view/\3)', $post);
|
||||
|
||||
$entity->set('post', $post);
|
||||
}
|
||||
|
||||
public function checkAssignment(Entity $entity)
|
||||
{
|
||||
if ($entity->isNew()) {
|
||||
|
||||
@@ -117,6 +117,8 @@ class Record extends \Espo\Core\Services\Base
|
||||
|
||||
protected $forceSelectAllAttributes = false;
|
||||
|
||||
protected $selectAttributesDependancyMap = [];
|
||||
|
||||
const MAX_SELECT_TEXT_ATTRIBUTE_LENGTH = 5000;
|
||||
|
||||
const FOLLOWERS_LIMIT = 4;
|
||||
@@ -2073,7 +2075,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
break;
|
||||
}
|
||||
$value = $entity->get($attribute);
|
||||
return \Espo\Core\Utils\Json::encode($value);
|
||||
return \Espo\Core\Utils\Json::encode($value, \JSON_UNESCAPED_UNICODE);
|
||||
break;
|
||||
case 'jsonArray':
|
||||
if (!empty($defs[$attribute]['isLinkMultipleIdList'])) {
|
||||
@@ -2081,7 +2083,7 @@ class Record extends \Espo\Core\Services\Base
|
||||
}
|
||||
$value = $entity->get($attribute);
|
||||
if (is_array($value)) {
|
||||
return \Espo\Core\Utils\Json::encode($value);
|
||||
return \Espo\Core\Utils\Json::encode($value, \JSON_UNESCAPED_UNICODE);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
@@ -2479,6 +2481,16 @@ class Record extends \Espo\Core\Services\Base
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->selectAttributesDependancyMap as $attribute => $dependantAttributeList) {
|
||||
if (in_array($attribute, $attributeList)) {
|
||||
foreach ($dependantAttributeList as $dependantAttribute) {
|
||||
if (!in_array($dependantAttribute, $attributeList)) {
|
||||
$attributeList[] = $dependantAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $attributeList;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div>
|
||||
{{#each emailAddressData}}
|
||||
<div class="input-group email-address-block">
|
||||
<input type="email" class="form-control email-address" value="{{emailAddress}}" autocomplete="espo-{{../name}}">
|
||||
<input type="email" class="form-control email-address" value="{{emailAddress}}" autocomplete="espo-{{../name}}" maxlength={{../itemMaxLength}}>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default btn-icon email-property{{#if primary}} active{{/if}} hidden" type="button" tabindex="-1" data-action="switchEmailProperty" data-property-type="primary" data-toggle="tooltip" data-placement="top" title="{{translate 'Primary' scope='EmailAddress'}}">
|
||||
<span class="fas fa-star fa-sm{{#unless primary}} text-muted{{/unless}}"></span>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<span class="input-group-btn">
|
||||
<select data-property-type="type" class="form-control">{{options ../params.typeList type scope=../scope field=../name}}</select>
|
||||
</span>
|
||||
<input type="input" class="form-control phone-number no-margin-shifting" value="{{phoneNumber}}" autocomplete="espo-{{../name}}">
|
||||
<input type="input" class="form-control phone-number no-margin-shifting" value="{{phoneNumber}}" autocomplete="espo-{{../name}}" maxlength={{../itemMaxLength}}>
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-default btn-icon phone-property{{#if primary}} active{{/if}} hidden" type="button" tabindex="-1" data-action="switchPhoneProperty" data-property-type="primary" data-toggle="tooltip" data-placement="top" title="{{translate 'Primary' scope='PhoneNumber'}}">
|
||||
<span class="fa fa-star fa-sm{{#unless primary}} text-muted{{/unless}}"></span>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<div class="row">
|
||||
<div class="{{#if isHeaderAdditionalSpace}}col-sm-8{{else}}col-sm-7{{/if}}{{#if isXsSingleRow}} col-xs-6{{/if}}">
|
||||
<div class="{{#if isHeaderAdditionalSpace}}col-sm-8{{else}}col-sm-7{{/if}}{{#if isXsSingleRow}} col-xs-6{{/if}} page-header-column-1">
|
||||
<h3>{{{header}}}</h3>
|
||||
</div>
|
||||
<div class="{{#if isHeaderAdditionalSpace}}col-sm-4{{else}}col-sm-5{{/if}}{{#if isXsSingleRow}} col-xs-6{{/if}}">
|
||||
<div class="{{#if isHeaderAdditionalSpace}}col-sm-4{{else}}col-sm-5{{/if}}{{#if isXsSingleRow}} col-xs-6{{/if}} page-header-column-2">
|
||||
<div class="header-buttons btn-group pull-right">
|
||||
{{#each items.buttons}}
|
||||
<a {{#if link}}href="{{link}}"{{else}}href="javascript:"{{/if}} class="btn btn-{{#if style}}{{style}}{{else}}default{{/if}} action{{#if hidden}} hidden{{/if}}" data-name="{{name}}" data-action="{{action}}"{{#each data}} data-{{@key}}="{{./this}}"{{/each}}{{#if title}} title="{{title}}"{{/if}}>
|
||||
@@ -47,4 +47,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -217,6 +217,8 @@ Espo.define('view-helper', [], function () {
|
||||
|
||||
text = marked(text);
|
||||
|
||||
text = text.replace(/<a href="mailto:(.*)"/gm, '<a href="javascript:" data-email-address="$1" data-action="mailTo"');
|
||||
|
||||
text = text.replace('[#see-more-text]', ' <a href="javascript:" data-action="seeMoreText">' + self.language.translate('See more')) + '</a>';
|
||||
return new Handlebars.SafeString(text);
|
||||
}.bind(this));
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/************************************************************************
|
||||
* This file is part of EspoCRM.
|
||||
*
|
||||
* EspoCRM - Open Source CRM application.
|
||||
* Copyright (C) 2014-2018 Yuri Kuznetsov, Taras Machyshyn, Oleksiy Avramenko
|
||||
* Website: http://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.
|
||||
************************************************************************/
|
||||
|
||||
Espo.define('views/fields/address-city', 'views/fields/varchar', function (Dep) {
|
||||
|
||||
return Dep.extend({
|
||||
|
||||
setupOptions: function () {
|
||||
var cityList = this.getConfig().get('addressCityList') || [];
|
||||
if (cityList.length) {
|
||||
this.params.options = Espo.Utils.clone(cityList);
|
||||
}
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
@@ -338,6 +338,45 @@ Espo.define('views/fields/address', 'views/fields/base', function (Dep) {
|
||||
this.$street.on('input', function (e) {
|
||||
this.controlStreetTextareaHeight();
|
||||
}.bind(this));
|
||||
|
||||
var cityList = this.getConfig().get('addressCityList') || [];
|
||||
if (cityList.length) {
|
||||
this.$city.autocomplete({
|
||||
minChars: 0,
|
||||
lookup: cityList,
|
||||
maxHeight: 200,
|
||||
formatResult: function (suggestion) {
|
||||
return suggestion.value;
|
||||
},
|
||||
lookupFilter: function (suggestion, query, queryLowerCase) {
|
||||
if (suggestion.value.toLowerCase().indexOf(queryLowerCase) === 0) {
|
||||
if (suggestion.value.length === queryLowerCase.length) return false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
onSelect: function () {
|
||||
this.trigger('change');
|
||||
}.bind(this)
|
||||
});
|
||||
this.$city.on('focus', function () {
|
||||
if (this.$city.val()) return;
|
||||
this.$city.autocomplete('onValueChange');
|
||||
}.bind(this));
|
||||
this.once('render', function () {
|
||||
this.$city.autocomplete('dispose');
|
||||
}, this);
|
||||
this.once('remove', function () {
|
||||
this.$city.autocomplete('dispose');
|
||||
}, this);
|
||||
|
||||
this.$city.attr('autocomplete', 'espo-city');
|
||||
}
|
||||
|
||||
this.controlStreetTextareaHeight();
|
||||
this.$street.on('input', function (e) {
|
||||
this.controlStreetTextareaHeight();
|
||||
}.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -136,6 +136,8 @@ Espo.define('views/fields/email', 'views/fields/varchar', function (Dep) {
|
||||
data.valueIsSet = this.model.has(this.name);
|
||||
}
|
||||
|
||||
data.itemMaxLength = this.itemMaxLength;
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
@@ -385,8 +387,10 @@ Espo.define('views/fields/email', 'views/fields/varchar', function (Dep) {
|
||||
return;
|
||||
}
|
||||
|
||||
var viewName = this.getMetadata().get('clientDefs.' + this.scope + '.modalViews.compose') || 'views/modals/compose-email';
|
||||
|
||||
this.notify('Loading...');
|
||||
this.createView('quickCreate', 'views/modals/compose-email', {
|
||||
this.createView('quickCreate', viewName, {
|
||||
attributes: attributes,
|
||||
}, function (view) {
|
||||
view.render();
|
||||
@@ -405,6 +409,8 @@ Espo.define('views/fields/email', 'views/fields/varchar', function (Dep) {
|
||||
this.erasedPlaceholder = 'ERASED:';
|
||||
|
||||
this.emailAddressOptedOutByDefault = this.getConfig().get('emailAddressIsOptedOutByDefault');
|
||||
|
||||
this.itemMaxLength = this.getMetadata().get(['entityDefs', 'EmailAddress', 'fields', 'name', 'maxLength']) || 255;
|
||||
},
|
||||
|
||||
fetchEmailAddressData: function () {
|
||||
|
||||
@@ -128,6 +128,8 @@ Espo.define('views/fields/phone', 'views/fields/varchar', function (Dep) {
|
||||
data.valueIsSet = this.model.has(this.name);
|
||||
}
|
||||
|
||||
data.itemMaxLength = this.itemMaxLength;
|
||||
|
||||
return data;
|
||||
},
|
||||
|
||||
@@ -270,6 +272,8 @@ Espo.define('views/fields/phone', 'views/fields/varchar', function (Dep) {
|
||||
}
|
||||
|
||||
this.erasedPlaceholder = 'ERASED:';
|
||||
|
||||
this.itemMaxLength = this.getMetadata().get(['entityDefs', 'PhoneNumber', 'fields', 'name', 'maxLength']);
|
||||
},
|
||||
|
||||
fetchPhoneNumberData: function () {
|
||||
|
||||
@@ -56,7 +56,10 @@ Espo.define('views/fields/text', 'views/fields/base', function (Dep) {
|
||||
'click a[data-action="seeMoreText"]': function (e) {
|
||||
this.seeMoreText = true;
|
||||
this.reRender();
|
||||
}
|
||||
},
|
||||
'click [data-action="mailTo"]': function (e) {
|
||||
this.mailTo($(e.currentTarget).data('email-address'));
|
||||
},
|
||||
},
|
||||
|
||||
setup: function () {
|
||||
@@ -287,8 +290,38 @@ Espo.define('views/fields/text', 'views/fields/base', function (Dep) {
|
||||
|
||||
getSearchType: function () {
|
||||
return this.getSearchParamsData().type || this.searchParams.typeFront || this.searchParams.type;
|
||||
}
|
||||
},
|
||||
|
||||
mailTo: function (emailAddress) {
|
||||
var attributes = {
|
||||
status: 'Draft',
|
||||
to: emailAddress
|
||||
};
|
||||
|
||||
if (
|
||||
this.getConfig().get('emailForceUseExternalClient') ||
|
||||
this.getPreferences().get('emailUseExternalClient') ||
|
||||
!this.getAcl().checkScope('Email', 'create')
|
||||
) {
|
||||
require('email-helper', function (EmailHelper) {
|
||||
var emailHelper = new EmailHelper();
|
||||
var link = emailHelper.composeMailToLink(attributes, this.getConfig().get('outboundEmailBccAddress'));
|
||||
document.location.href = link;
|
||||
}.bind(this));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var viewName = this.getMetadata().get('clientDefs.' + this.scope + '.modalViews.compose') || 'views/modals/compose-email';
|
||||
|
||||
this.notify('Loading...');
|
||||
this.createView('quickCreate', viewName, {
|
||||
attributes: attributes,
|
||||
}, function (view) {
|
||||
view.render();
|
||||
view.notify(false);
|
||||
});
|
||||
},
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -230,32 +230,9 @@ Espo.define('views/note/fields/post', ['views/fields/text', 'lib!Textcomplete'],
|
||||
xhr.errorIsHandled = true;
|
||||
});
|
||||
}
|
||||
} else if (text.indexOf(siteUrl) === 0) {
|
||||
if (/\#[A-Z][a-zA-Z0-9]*\/view\/[a-zA-Z0-9]*$/.test(text)) {
|
||||
var match = /\#([A-Z][a-zA-Z0-9]*)\/view\/([a-zA-Z0-9]*)$/.exec(text)
|
||||
if (match.length === 3) {
|
||||
var entityType = match[1];
|
||||
var id = match[2];
|
||||
|
||||
event.preventDefault();
|
||||
|
||||
var cursorStartPosition = this.$element.prop('selectionStart');
|
||||
var cursorEndPosition = this.$element.prop('selectionEnd');
|
||||
var text = this.$element.val();
|
||||
var textBefore = text.substring(0, cursorStartPosition);
|
||||
var textAfter = text.substring(cursorEndPosition, text.length);
|
||||
|
||||
var textToPaste = '['+entityType+'/'+id+'](#'+entityType+'/view/'+id+')';
|
||||
|
||||
this.$element.val(textBefore + textToPaste + textAfter);
|
||||
|
||||
this.controlTextareaHeight();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -108,6 +108,10 @@
|
||||
.clearfix();
|
||||
}
|
||||
|
||||
hr {
|
||||
border-top: 1px solid @panel-default-border;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
font-size: @font-size-base;
|
||||
border-left-width: 3px;
|
||||
@@ -207,10 +211,14 @@ label {
|
||||
}
|
||||
|
||||
.page-header {
|
||||
margin: 10px 0;
|
||||
border-bottom: 0;
|
||||
padding-bottom: 2px;
|
||||
min-height: 33px;
|
||||
margin: 10px 0;
|
||||
border-bottom: 0;
|
||||
padding-bottom: 2px;
|
||||
min-height: 33px;
|
||||
|
||||
.page-header-column-1 {
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.page-header > .row {
|
||||
@@ -921,6 +929,13 @@ table.table > tbody td > .list-row-buttons button {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
table.table > tbody > tr > td,
|
||||
table.table > tbody > tr > th,
|
||||
table.table > thead > tr > th {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list-row-buttons span.caret {
|
||||
border-top-color: @gray-light;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user