markdown support

This commit is contained in:
yuri
2017-12-14 15:06:08 +02:00
parent 6ae345a9e1
commit 0836dec4a6
5 changed files with 87 additions and 69 deletions

View File

@@ -260,7 +260,7 @@
"massRemoveResultSingle": "{count} record has been removed",
"noRecordsRemoved": "No records were removed",
"clickToRefresh": "Click to refresh",
"streamPostInfo": "Type <strong>@username</strong> to mention users in the post.\n\nAvailable markdown syntax:\n`<code>code</code>`\n**<strong>strong text</strong>**\n*<em>emphasized text</em>*\n~<del>deleted text</del>~\n> blockquote\n[link text](url)",
"streamPostInfo": "Type <strong>@username</strong> to mention users in the post.\n\nAvailable markdown syntax:\n`<code>code</code>`\n```<code>multiline code</code>```\n**<strong>strong text</strong>**\n*<em>emphasized text</em>*\n~~<del>deleted text</del>~~\n> blockquote\n[link text](url)",
"writeYourCommentHere": "Write your comment here",
"writeMessageToUser": "Write a message to {user}",
"writeMessageToSelf": "Write a message on your stream",

6
client/lib/marked.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -70,6 +70,7 @@
<li>gridstack.js by Pavel Reznikov</li>
<li>vis.js by Almende B.V.</li>
<li>Ace</li>
<li>Marked by Christopher Jeffrey</li>
</ul>
</section>
</div>
@@ -81,7 +82,7 @@
<li>Doctrine (DBAL)</li>
<li>Slim</li>
<li>Cron Expression Parser by Michael Dowling</li>
<li>Zendframework (Validator, Mail, Ldap)</li>
<li>Zendframework (Mail, Ldap)</li>
<li>Monolog</li>
<li>Identicon by Don Park</li>
<li>php-semver by Lars Vierbergen</li>

View File

@@ -26,32 +26,34 @@
* these Appropriate Legal Notices must retain the display of the "EspoCRM" word.
************************************************************************/
Espo.define('view-helper', [], function () {
Espo.define('view-helper', ['lib!client/lib/marked.min.js'], function () {
var ViewHelper = function (options) {
this.urlRegex = /(^|[^\(])(\b(https?|ftp|file):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/ig;
this._registerHandlebarsHelpers();
this.mdSearch = [
/\["?(.*?)"?\]\((.*?)\)/g,
/\&\#x60;\&\#x60;\&\#x60;\n?([\s\S]*?)\&\#x60;\&\#x60;\&\#x60;/g,
/\&\#x60;([\s\S]*?)\&\#x60;/g,
/(\*\*)(.*?)\1/g,
/(\*)(.*?)\1/g,
/\~\~(.*?)\~\~/g
];
this.mdReplace = [
'<a href="$2">$1</a>',
function (s, string) {
return '<pre><code>' + string.replace(/\*/g, '&#42;').replace(/\~/g, '&#126;') + '</code></pre>';
this.mdBeforeList = [
{
regex: /\["?(.*?)"?\]\((.*?)\)/g,
value: '<a href="$2">$1</a>'
},
function (s, string) {
return '<code>' + string.replace(/\*/g, '&#42;').replace(/\~/g, '&#126;') + '</code>';
{
regex: /\&\#x60;\&\#x60;\&\#x60;\n?([\s\S]*?)\&\#x60;\&\#x60;\&\#x60;/g,
value: function (s, string) {
return '<pre><code>' + string.replace(/\*/g, '&#42;').replace(/\~/g, '&#126;') + '</code></pre>';
}
},
'<strong>$2</strong>',
'<em>$2</em>',
'<del>$1</del>'
{
regex: /\&\#x60;([\s\S]*?)\&\#x60;/g,
value: function (s, string) {
return '<code>' + string.replace(/\*/g, '&#42;').replace(/\~/g, '&#126;') + '</code>';
}
}
];
marked.setOptions({
breaks: true
});
}
_.extend(ViewHelper.prototype, {
@@ -78,47 +80,6 @@ Espo.define('view-helper', [], function () {
return text;
},
tranformTextMarkdown: function (text) {
var newline = text.indexOf('\r\n') != -1 ? '\r\n' : text.indexOf('\n') != -1 ? '\n' : '';
if (newline != '') {
var d = [];
var r = [];
var p = text.split(newline);
p.push('');
var isBlockLevel = false;
p.forEach(function (item, i) {
if (item.length >= 5 && item.indexOf('&gt; ') === 0) {
if (!isBlockLevel) {
d = [];
isBlockLevel = true;
}
d.push(item.replace(/&gt; /gm, ''));
} else {
if (isBlockLevel) {
r.push('<blockquote>' + d.join(newline) + '</blockquote>' + item)
} else {
r.push(item);
}
isBlockLevel = false;
}
}, this);
if (r.slice(-1)[0] == '') {
r.pop();
}
var t = r.join(newline);
return t;
}
return text;
},
_registerHandlebarsHelpers: function () {
var self = this;
@@ -219,21 +180,19 @@ Espo.define('view-helper', [], function () {
Handlebars.registerHelper('complexText', function (text) {
text = text || ''
text = text.replace(self.urlRegex, '$1[$2]($2)');
text = text.replace(this.urlRegex, '$1[$2]($2)');
text = Handlebars.Utils.escapeExpression(text);
text = Handlebars.Utils.escapeExpression(text).replace(/&gt;+/g, '>');
self.mdSearch.forEach(function (re, i) {
text = text.replace(re, self.mdReplace[i]);
this.mdBeforeList.forEach(function (item) {
text = text.replace(item.regex, item.value);
});
text = self.tranformTextMarkdown(text);
text = text.replace(/(\r\n|\n|\r)/gm, '<br>');
text = marked(text);
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));
Handlebars.registerHelper('translateOption', function (name, options) {
var scope = options.hash.scope || null;

View File

@@ -1175,6 +1175,58 @@ table.table td.cell .complex-text {
white-space: normal;
}
.complex-text {
h1:first-child,
h2:first-child,
h3:first-child,
h4:first-child,
h5:first-child,
h6:first-child,
p:first-child,
ul:first-child,
ol:first-child,
blockquote:first-child {
margin-top: 0 !important;
}
h1 {
font-weight: bold;
margin-top: @line-height-computed;
margin-bottom: (@line-height-computed / 2);
}
h2, h3 {
font-weight: bold;
margin-top: (@line-height-computed / 2);
margin-bottom: (@line-height-computed / 2);
}
h4, h5, h6 {
font-weight: normal;
margin-top: (@line-height-computed / 2);
margin-bottom: (@line-height-computed / 2);
}
h1 {
font-size: floor(@font-size-base * 1.1);
}
h2, h3, h4, h5, h6 {
font-size: floor(@font-size-base);
}
p,
ul,
ol,
pre,
blockquote {
margin-top: @line-height-computed / 2;
}
ul > li {
list-style-type: disc;
}
ul, ol {
padding-left: 30px;
}
}
#popup-notifications-container {
overflow-y: auto;
overflow-x: hidden;