/* * Markdown is a named function that will parse markdown syntax * @param {String} msg - The message html */ import { Meteor } from 'meteor/meteor'; import { Random } from 'meteor/random'; import s from 'underscore.string'; import { settings } from '../../../../settings'; const addAsToken = function(message, html) { const token = `=!=${ Random.id() }=!=`; message.tokens.push({ token, text: html, }); return token; }; const URL = global.URL || require('url').URL || require('url').Url; const validateUrl = (url) => { try { new URL(url); return true; } catch (e) { return false; } }; const parseNotEscaped = function(msg, message) { if (message && message.tokens == null) { message.tokens = []; } const schemes = (settings.get('Markdown_SupportSchemesForLink') || '').split(',').join('|'); if (settings.get('Markdown_Headers')) { // Support # Text for h1 msg = msg.replace(/^# (([\S\w\d-_\/\*\.,\\][ \u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]?)+)/gm, '

$1

'); // Support # Text for h2 msg = msg.replace(/^## (([\S\w\d-_\/\*\.,\\][ \u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]?)+)/gm, '

$1

'); // Support # Text for h3 msg = msg.replace(/^### (([\S\w\d-_\/\*\.,\\][ \u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]?)+)/gm, '

$1

'); // Support # Text for h4 msg = msg.replace(/^#### (([\S\w\d-_\/\*\.,\\][ \u00a0\u1680\u180e\u2000-\u200a\u2028\u2029\u202f\u205f\u3000\ufeff]?)+)/gm, '

$1

'); } // Support *text* to make bold msg = msg.replace(/(|>|[ >_~`])\*{1,2}([^\*\r\n]+)\*{1,2}([<_~`]|\B|\b|$)/gm, '$1*$2*$3'); // Support _text_ to make italics msg = msg.replace(/(^|>|[ >*~`])\_{1,2}([^\_\r\n]+)\_{1,2}([<*~`]|\B|\b|$)/gm, '$1_$2_$3'); // Support ~text~ to strike through text msg = msg.replace(/(^|>|[ >_*`])\~{1,2}([^~\r\n]+)\~{1,2}([<_*`]|\B|\b|$)/gm, '$1~$2~$3'); // Support for block quote // >>> // Text // <<< msg = msg.replace(/(?:>){3}\n+([\s\S]*?)\n+(?:<){3}/g, '
>>>$1<<<
'); // Support >Text for quote msg = msg.replace(/^>(.*)$/gm, '
>$1
'); // Remove white-space around blockquote (prevent
). Because blockquote is block element. msg = msg.replace(/\s*
/gm, '
'); msg = msg.replace(/<\/blockquote>\s*/gm, '
'); // Remove new-line between blockquotes. msg = msg.replace(/<\/blockquote>\n
{ if (!validateUrl(url)) { return match; } const target = url.indexOf(Meteor.absoluteUrl()) === 0 ? '' : '_blank'; return addAsToken(message, `
`); }); // Support [Text](http://link) msg = msg.replace(new RegExp(`\\[([^\\]]+)\\]\\(((?:${ schemes }):\\/\\/[^\\)]+)\\)`, 'gm'), (match, title, url) => { if (!validateUrl(url)) { return match; } const target = url.indexOf(Meteor.absoluteUrl()) === 0 ? '' : '_blank'; title = title.replace(/&/g, '&'); let escapedUrl = s.escapeHTML(url); escapedUrl = escapedUrl.replace(/&/g, '&'); return addAsToken(message, `${ s.escapeHTML(title) }`); }); // Support msg = msg.replace(new RegExp(`(?:<|<)((?:${ schemes }):\\/\\/[^\\|]+)\\|(.+?)(?=>|>)(?:>|>)`, 'gm'), (match, url, title) => { if (!validateUrl(url)) { return match; } const target = url.indexOf(Meteor.absoluteUrl()) === 0 ? '' : '_blank'; return addAsToken(message, `${ s.escapeHTML(title) }`); }); return msg; }; export const markdown = function(message) { message.html = parseNotEscaped(message.html, message); return message; };