Merge branch 'hotfix/5.5.6'

This commit is contained in:
yuri
2019-01-17 15:56:58 +02:00
26 changed files with 385 additions and 67 deletions
+7
View File
@@ -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();
+140 -2
View File
@@ -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'];
+4
View File
@@ -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';
+23 -20
View File
@@ -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);
+2 -2
View File
@@ -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);
}
+22
View File
@@ -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()) {
+14 -2
View File
@@ -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;
}
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -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>
+2 -3
View File
@@ -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>
+2
View File
@@ -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));
+41
View File
@@ -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);
}
},
});
});
+39
View File
@@ -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));
}
},
+7 -1
View File
@@ -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 () {
+4
View File
@@ -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 () {
+36 -3
View File
@@ -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);
});
},
});
});
-23
View File
@@ -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();
}
}
}
}
}
});
});
+19 -4
View File
@@ -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;
}