// todo: strict type not possible because of octal escape, fix! (function (jsOMS) { /** @namespace jsOMS.Views */ jsOMS.Autoloader.defineNamespace('jsOMS.Utils.Parser.Markdown'); jsOMS.Utils.Parser.Markdown.blockTypes = { '#': ['Header'], '*': ['Rule', 'List'], '+': ['List'], '-': ['SetextHeader', 'Table', 'Rule', 'List'], '0': ['List'], '1': ['List'], '2': ['List'], '3': ['List'], '4': ['List'], '5': ['List'], '6': ['List'], '7': ['List'], '8': ['List'], '9': ['List'], ':': ['Table'], '=': ['SetextHeader'], '>': ['Quote'], '[': ['Reference'], '_': ['Rule'], '`': ['FencedCode'], '|': ['Table'], '~': ['FencedCode'], }; jsOMS.Utils.Parser.Markdown.unmarkedBlockTypes = [ 'Code', ]; jsOMS.Utils.Parser.Markdown.specialCharacters = [ '\\', '`', '*', '_', '{', '}', '[', ']', '(', ')', '>', '#', '+', '-', '.', '!', '|', ]; jsOMS.Utils.Parser.Markdown.strongRegex = { '*': '/^[*]{2}((?:\\\\\*|[^*]|[*][^*]*[*])+?)[*]{2}(?![*])/s', '_': '/^__((?:\\\\_|[^_]|_[^_]*_)+?)__(?!_)/us', }; jsOMS.Utils.Parser.Markdown.emRegex = { '*': '/^[*]((?:\\\\\*|[^*]|[*][*][^*]+?[*][*])+?)[*](?![*])/s', '_': '/^_((?:\\\\_|[^_]|__[^_]*__)+?)_(?!_)\b/us', }; jsOMS.Utils.Parser.Markdown.regexHtmlAttribute = '[a-zA-Z_:][\w:.-]*(?:\s*=\s*(?:[^"\'=<>`\s]+|"[^"]*"|\'[^\']*\'))?'; jsOMS.Utils.Parser.Markdown.voidElements = [ 'area', 'base', 'br', 'col', 'command', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', ]; jsOMS.Utils.Parser.Markdown.textLevelElements = [ 'a', 'br', 'bdo', 'abbr', 'blink', 'nextid', 'acronym', 'basefont', 'b', 'em', 'big', 'cite', 'small', 'spacer', 'listing', 'i', 'rp', 'del', 'code', 'strike', 'marquee', 'q', 'rt', 'ins', 'font', 'strong', 's', 'tt', 'kbd', 'mark', 'u', 'xm', 'sub', 'nobr', 'sup', 'ruby', 'var', 'span', 'wbr', 'time', ]; jsOMS.Utils.Parser.Markdown.inlineTypes = { '"': ['SpecialCharacter'], '!': ['Image'], '&': ['SpecialCharacter'], '*': ['Emphasis'], ':': ['Url'], '<': ['UrlTag', 'EmailTag', 'SpecialCharacter'], '>': ['SpecialCharacter'], '[': ['Link'], '_': ['Emphasis'], '`': ['Code'], '~': ['Strikethrough'], '\\': ['EscapeSequence'], }; jsOMS.Utils.Parser.Markdown.inlineMarkerList = '!"*_&[:<>`~\\'; jsOMS.Utils.Parser.Markdown.continuable = [ 'Code', 'FencedCode', 'List', 'Quote', 'Table' ]; jsOMS.Utils.Parser.Markdown.completable = [ 'Code', 'FencedCode' ]; jsOMS.Utils.Parser.Markdown.safeLinksWhitelist = [ 'http://', 'https://', 'ftp://', 'ftps://', 'mailto:', 'data:image/png;base64,', 'data:image/gif;base64,', 'data:image/jpeg;base64,', 'irc:', 'ircs:', 'git:', 'ssh:', 'news:', 'steam:', ]; jsOMS.Utils.Parser.Markdown.definitionData = {}; jsOMS.Utils.Parser.Markdown.parse = function(text) { jsOMS.Utils.Parser.Markdown.definitionData = {}; text = text.replace("\r\n", "\n").replace("\r", "\n"); text = jsOMS.trim(text, "\n"); const lines = text.split("\n"); const markup = jsOMS.Utils.Parser.Markdown.lines(lines); return jsOMS.trim(markup, "\n"); }; jsOMS.Utils.Parser.Markdown.lines = function(lines) { let currentBlock = null; let blocks = []; outerloop: for (let line in lines) { line = lines[line]; if (jsOMS.rtrim(line) === '') { if (currentBlock !== null) { currentBlock['interrupted'] = true; } continue; } if (line.indexOf("\t") !== -1) { let parts = line.split("\t"); line = parts[0]; parts.shift(); for (let part in parts) { part = parts[part]; const shortage = 4 - line.length() % 4; line += ' '.repeat(shortage); line += part; } } let indent = 0; while (typeof line[indent] !== 'undefined' && line[indent] === ' ') { indent++; } text = indent > 0 ? line.substr(indent) : line; let lineArray = {body: line, indent: indent, text: text}; if (typeof currentblock !== 'undefined' && typeof currentBlock['continuable'] !== 'undefined') { let block = jsOMS.Utils.Parser.Markdown['block' + currentBlock['type'] + 'Continue'](lineArray, currentBlock); if (typeof block !== 'undefined') { currentBlock = block; } else if (jsOMS.Utils.Parser.Markdown.completable.indexOf(currentBlock['type']) !== -1) { currentBlock = jsOMS.Utils.Parser.Markdown['block' + currentBlock['type'] + 'Complete'](lineArray); } } let marker = text[0]; let blockTypes = jsOMS.Utils.Parser.Markdown.unmarkedBlockTypes; if (typeof jsOMS.Utils.Parser.Markdown.blockTypes[marker] !== 'undefined') { for (let blockType in jsOMS.Utils.Parser.Markdown.blockTypes[marker]) { blockType = jsOMS.Utils.Parser.Markdown.blockTypes[marker][blockType]; blockTypes.push(blockType); } } for (let blockType in blockTypes) { blockType = blockTypes[blockType]; let block = jsOMS.Utils.Parser.Markdown['block' + blockType](lineArray, currentBlock); if (typeof block !== 'undefined') { block['type'] = blockType; if (typeof block['identified'] === 'undefined') { blocks.push(currentBlock); block['identified'] = true; } if (jsOMS.Utils.Parser.Markdown.continuable.indexOf(blockType) !== -1) { block['continuable'] = true; } currentBlock = block; continue outerloop; } } if (jsOMS.isset(currentBlock) && typeof currentBlock['type'] === 'undefined' && typeof currentBlock['interrupted'] === 'undefined' ) { currentBlock['element']['text'] += "\n" + text; } else { blocks.push(currentBlock); currentBlock = jsOMS.Utils.Parser.Markdown.paragraph(lineArray); currentBlock['identified'] = true; } } if (currentBlock !== null && typeof currentBlock['continuable'] !== 'undefined' && jsOMS.Utils.Parser.Markdown.completable.indexOf(currentBlock['type']) !== -1) { currentBlock = jsOMS.Utils.Parser.Markdown['block' + currentBlock['type'] + 'Complete'](currentBlock); } blocks.push(currentBlock); blocks.shift(); let markup = ''; for (let block in blocks) { block = blocks[block]; if (typeof block['hidden'] !== 'undefined') { continue; } markup += "\n"; markup += typeof block['markup'] !== 'undefined' ? block['markup'] : jsOMS.Utils.Parser.Markdown.element(block['element']); } markup += "\n"; return markup; }; jsOMS.Utils.Parser.Markdown.blockCode = function(lineArray, block) { if (jsOMS.isset(block) && typeof block['type'] === 'undefined' && typeof block['interrputed'] === 'undefined') { return; } if (lineArray['indent'] < 4) { return; } let text = lineArray['body'].substr(4); return { element: { name: 'pre', handler: 'element', text: { name: 'code', text: text } } }; }; jsOMS.Utils.Parser.Markdown.blockCodeContinue = function(lineArray, block) { if (lineArray['indent'] < 4) { return; } if (typeof block['interrupted'] !== 'undefined') { block['element']['text']['text'] += "\n"; delete block['interrputed']; } block['element']['text']['text'] += "\n"; text = lineArray['body'].substr(4); block['element']['text']['text'] += text; return block; }; jsOMS.Utils.Parser.Markdown.blockCodeComplete = function(block) { text = block['element']['text']['text']; block['element']['text']['text'] = text; return block; }; jsOMS.Utils.Parser.Markdown.blockFencedCode = function(lineArray) { let matches = []; const regex = new RegExp('/^[' + lineArray['text'][0] + ']{3,}[ ]*([\w-]+)?[ ]*$/');; if ((matches = lineArray['text'].match(regex)) === null) { return; } let elementArray = { name: 'code', text: '' } if (typeof matches[1] !== 'undefined') { elementArray['attributes'] = { 'class': 'language-' + matches[1] } } return { char: lineArray['text'][0], element: { name: 'pre', handler: 'element', text: elementArray } } }; jsOMS.Utils.Parser.Markdown.blockFencedCodeContinue = function(lineArray, block) { if (typeof block['complete'] !== 'undefined') { return; } if (typeof block['interrupted'] !== 'undefined') { block['element']['text']['text'] += "\n"; delete block['interrupted']; } const regex = new RegExp('/^' + block['char'] + '{3,}[ ]*$/'); if (lineArray['text'].match(regex) !== null) { block['element']['text']['text'] = block['element']['text']['text'].substr(1); block['complete'] = true; return block; } block['element']['text']['text'] += "\n" + lineArray['body']; return block; }; jsOMS.Utils.Parser.Markdown.blockFencedCodeComplete = function(block) { let text = block['element']['text']['text']; block['element']['text']['text'] = text; return block; }; jsOMS.Utils.Parser.Markdown.blockHeader = function(lineArray) { if (typeof lineArray['text'][1] === 'undefined') { return; } let level = 1; while (typeof lineArray['text'][level] !== 'undefined' && lineArray['text'][level] === '#') { level++; } if (level > 6) { return; } text = jsOMS.trim(lineArray['text'], '# '); return { element: { name: 'h' + Math.min(6, level), text: text, handler: 'line' } }; }; jsOMS.Utils.Parser.Markdown.blockList = function(lineArray) { let list = lineArray['text'][0] <= '-' ? ['ul', '[*+-]'] : ['ol', '[0-9]+[.]']; let matches = null; const regex = new RegExp('/^(' + list[1] + '[ ]+)(.*)/'); if ((matches = lineArray['text'].match(regex)) === null) { return; } block = { indent: lineArray['indent'], pattern: list[1], elment: { name: list[0], handler: 'elements' } }; if (list[0] === 'ol') { let listStart = matches[0].substr(0, matches[0].indexOf('.')); } block['li'] = { name: 'li', handler: 'li', text: [ matches[2] ] }; block['element']['text'].push(block['li']); return block; }; jsOMS.Utils.Parser.Markdown.blockListContinue = function(lineArray, block) { let matches = null; const regex = new RegExp('/^' + block['pattern'] + '(?:[ ]+(.*)|$)/'); if (block['indent'] === lineArray['indent'] && (matches = lineArray['text'].match(regex) !== null)) { if (typeof block['interrupted'] !== 'undefined') { block['li']['text'].push(''); delete block['interrupted']; } delete block['li']; let text = typeof matches[1] !== 'undefined' ? matches[1] : ''; block['li'] = { name: 'li', handler: 'li', text: [ text ] }; block['element']['text'].push(block['li']); return block; } if (lineArray['text'][0] === '[' && jsOMS.Utils.Parser.Markdown.blockReference(lineArray)) { return block; } if (typeof block['interrupted'] === 'undefined') { let text = lineArray['body'].replace(/^[ ]{0,4}/, ''); block['li']['text'].push(text); return block; } if (lineArray['indent'] > 0) { block['li']['text'].push(''); let text = lineArray['body'].replace(/^[ ]{0,4}/, ''); block['li']['text'].push(text); delete block['interrupted']; return block; } }; jsOMS.Utils.Parser.Markdown.blockQuote = function(lineArray) { let matches = null; if ((matches = lineArray['text'].match(/^>[ ]?(.*)/)) === null) { return; } return { element: { name: 'blockquote', handler: 'lines', text: matches[1] } }; }; jsOMS.Utils.Parser.Markdown.blockQuoteContinue = function(lineArray, block) { if (lineArray['text'][0] === '>' && (matches = lineArray['text'].match(/^>[ ]?(.*)/)) !== null) { if (typeof block['interrputed'] !== 'undefined') { block['element']['text'].push(''); delete block['interrupted']; } block['element']['text'].push(matches[1]); return block; } if (typeof block['interrupted'] === 'undefined') { block['element']['text'].push(lineArray['text']); return block; } }; jsOMS.Utils.Parser.Markdown.blockRule = function(lineArray) { const regex = new RegExp('/^([' + lineArray['text'][0] + '])([ ]*\1){2,}[ ]*$/'); if (lineArray['text'].match(regex) === null) { return; } return { element: { name: 'hr' } }; }; jsOMS.Utils.Parser.Markdown.blockSetextHeader = function(lineArray, block) { if(typeof block === 'undefined' || typeof block['type'] !== 'undefined' || typeof block['interrupted'] !== 'undefined') { return; } if (jsOMS.rtrim(lineArray['text'], lineArray['text'][0]) !== '') { return; } block['element']['name'] = lineArray['text'][0] === '=' ? 'h1' : 'h2'; return block; }; jsOMS.Utils.Parser.Markdown.blockReference = function(lineArray) { let matches = null; if ((matches = lineArray['text'].match(/^\[(.+?)\]:[ ]*?(?:[ ]+["\'(](.+)["\')])?[ ]*$/)) === null) { return; } let id = matches[1].toLowerCase(); let data = { url: matches[2], title: typeof matches[3] !== 'undefined' ? matches[3] : null, }; jsOMS.Utils.Parser.Markdown.definitionData['Reference'][id] = data; return {hidden: true}; }; jsOMS.Utils.Parser.Markdown.blockTable = function(lineArray, block) { if (typeof block === 'undefined' || typeof block['type'] !== 'undefined' || typeof block['interrupted'] !== 'undefined') { return } if (block['element']['text'].indexOf('|') !== -1 && jsOMS.rtrim(lineArray['text'], ' -:|') === '') { let alignments = []; let divider = lineArray['text']; divider = jsOMS.trim(divider); divider = jsOMS.trim(divider, '|'); const dividerCells = divider.split('|'); let dividerLength = dividerCells.length; for (let i = 0; i < dividerLength; i++) { let dividerCell = jsOMS.trim(dividerCells[i]); if (dividerCell === '') { continue; } let alignment = null; if (dividerCell[0] === ':') { alignment = 'left'; } if (dividerCell.substr(-1) === ':') { alignment = alignment === 'left' ? 'center' : 'right'; } alignments.push(alignment); } let headerElements = []; let header = block['element']['text']; header = jsOMS.trim(header); header = jsOMS.trim(header, '|'); let headerCells = header.split('|'); const headerLength = headerCells.length; for (let i = 0; i < headerLength; i++) { let headerCell = jsOMS.trim(headerCells[i]); let headerElement = { name: 'th', text: headerCell, handler: 'line' }; if (typeof alignments[i] !== 'undefined') { let alignment = alignments[i]; headerElement['attributes'] = { style: 'text-align: ' + alignment + ';' }; } headerElements.push(headerElement); } block = { alignments: alignments, identified: true, element: { name: 'table', handler: 'elements' } }; block['element']['text'].push({ name: 'thead', handler: 'elements' }); block['element']['text'].push({ name: 'tbody', handler: 'elements', text: [] }); block['element']['text'][0]['text'].push({ name: 'tr', handler: 'elements', text: headerElements }); return block; } }; jsOMS.Utils.Parser.Markdown.blockTableContinue = function(lineArray, block) { if (typeof block['interrupted'] !== 'undefined') { return; } if (lineArray['text'][0] === '|' || lineArray['text'].indexOf('|') !== -1) { let elements = []; let row = lineArray['text']; row = jsOMS.trim(row); row = jsOMS.trim(row, '|'); let matches = row.match(/(?:(\\\\[|])|[^|`]|`[^`]+`|`)+/g); let index = matches[0].length; for (let i = 0; i < index; index++) { let cell = jsOMS.trim(matches[0][index]); let element = { name: 'td', handler: 'line', text: cell }; if (typeof block['alignments'][index] !== 'undefined') { element['attributes'] = { style: 'text-align: ' + block[alignments][index] + ';', } } elements.push(element); } element = { name: 'tr', handler: 'element', text: elements }; block['element']['text'][1]['text'].push(element); return block; } }; jsOMS.Utils.Parser.Markdown.paragraph = function(lineArray) { return { element: { name: 'p', text: lineArray['text'], handler: 'line' } }; }; jsOMS.Utils.Parser.Markdown.line = function(text) { let markup = ''; let excerpt = null; outerloop: while (excerpt = jsOMS.strpbrk(text, jsOMS.Utils.Parser.Markdown.inlineMarkerList)) { let marker = excerpt[0]; let markerPosition = text.indexOf(marker); let excerptArray = {text: excerpt, context: text}; for (let inlineType in jsOMS.Utils.Parser.Markdown.inlineTypes[marker]) { inlineType = jsOMS.Utils.Parser.Markdown.inlineTypes[marker][inlineType]; let inline = jsOMS.Utils.Parser.Markdown['inline' + inlineType](excerptArray); if (typeof inline === 'undefined') { continue; } if (typeof inline['position'] !== 'undefined' && inline['position'] > markerPosition) { continue; } if (typeof inline['position'] === 'undefined') { inline['position'] = markerPosition; } let unmarkedText = text.substr(0, inline['position']); markup += jsOMS.Utils.Parser.Markdown.unmarkedText(unmarkedText); markup += typeof inline['markup'] !== undefined ? inline['markup'] : jsOMS.Utils.Parser.Markup.element(inline['element']); text = text.substr(inline['position'] + inline['extent']); continue outerloop; } let unmarkedText = text.substr(0, markerPosition + 1); markup += jsOMS.Utils.Parser.Markdown.unmarkedText(unmarkedText); text = text.substr(markerPosition + 1); } markup += jsOMS.Utils.Parser.Markdown.unmarkedText(text); return markup; }; jsOMS.Utils.Parser.Markdown.inlineCode = function (excerpt) { let marker = excerpt['text'][0]; let matches = null; const regex = new RegExp('/^(' + marker + '+)[ ]*(.+?)[ ]*(?') === -1 || (matches = excerpt['text'].match(/^<((mailto:)?\S+?@\S+?)>/i)) === null) { return; } let url = matches[1]; if (typeof matches[2] === 'undefined') { url = 'mailto:' + url; } return { extent: matches[0].length, element: { name: 'a', text: matches[1], attributes: { href: url } } }; }; jsOMS.Utils.Parser.Markdown.inlineEmphasis = function (excerpt) { if (typeof excerpt['text'][1] === 'undefined') { return; } let marker = excerpt['text'][0]; let matches = null; const regex1 = new RegExp(jsOMS.Utils.Parser.Markdown.strongRegex[marker]); const regex2 = new RegExp(jsOMS.Utils.Parser.Markdown.emRegex[marker]); let emphasis = ''; if (excerpt['text'][1] === marker && (matches = excerpt['text'].match(regex1)) !== null) { emphasis = 'strong'; } else if ((matches = excerpt['text'].match(regex2)) !== null) { emphasis = 'em'; } else { return; } return { extent: matches[0].length, element: { name: emphasis, handler: 'line', text: matches[1] } }; }; jsOMS.Utils.Parser.Markdown.inlineEscapeSequence = function(excerpt) { if (typeof excerpt['text'][1] === 'undefined' || jsOMS.Utils.Parser.Markdown.specialCharacters.indexOf(excerpt['text'][1]) === -1) { return; } return { markup: excerpt['text'][1], extent: 2 }; }; jsOMS.Utils.Parser.Markdown.inlineImage = function (excerpt) { if (typeof excerpt['text'][1] === 'undefined' || excerpt['text'][1] !== '[') { return; } excerpt['text'] = excerpt['text'].substr(1); let link = jsOMS.Utils.Parser.Markdown.inlineLink(excerpt); if (typeof link === 'undefined') { return; } let inline = { extent: link['extent'] + 1, element: { name: 'img', attributes: { src: link['element']['attributes']['href'], alt: link['element']['text'] } } }; for (let e in link['element']['attributes']) { inline['element']['attributes'][e] = link['element']['attributes'][e]; } delete inline['element']['attributes']['href']; return inline; }; jsOMS.Utils.Parser.Markdown.inlineLink = function(excerpt) { let element = { name: 'a', handler: 'line', text: null, attributes: { href: null, title: null } }; let extent = 0; let remainder = excerpt['text']; let matches = null; //if ((matches = remainder.match(/\[((?:[^][]++|(?R))*+)\]/)) === null) { // return; //} element['text'] = matches[1]; extent += matches[0].length; remainder = remainder.substr(extent); /*if ((matches = remainder.match(/^[(]\s*+((?:[^ ()]++|[(][^ )]+[)])++)(?:[ ]+("[^"]*"|\'[^\']*\'))?\s*[)]/)) !== null) { element['attributes']['href'] = matches[1]; if (typeof matches[2] !== 'undefined') { element['attributes']['title'] = matches[2].substr(1, -1); } extent += matches[0].length; } else { let definition = null; if ((matches = remainder.match(/^\s*\[(.*?)\]/)) !== null) { definition = matches[1].length > 0 ? matches[1] : element['text']; definition = definition.toLowerCase(); extent += matches[0].length; } else { definition = element['text'].toLowerCase(); } if (typeof jsOMS.Utils.Parser.Markdown.definitionData['Reference'][definition] === 'undefined') { return; } let def = jsOMS.Utils.Parser.Markdown.definitionData['Reference'][definition]; element['attributes']['href'] = def['url']; element['attributes']['title'] = def['title']; }*/ return { extent: extent, element: element }; }; jsOMS.Utils.Parser.Markdown.inlineSpecialCharacter = function (excerpt) { if (excerpt['text'][0] === '&' || excerpt['text'].match(/^&#?\w+;/) === null) { return { markup: '&', extent: 1 }; } let specialChr = {'>': 'gt', '<': 'lt', '"': 'quote'}; if (typeof specialChar[excerpt['text'][0]] !== 'undefined') { return { markup: '&' + specialChar[excerpt['text'][0]] + ';', extent: 1 }; } }; jsOMS.Utils.Parser.Markdown.inlineStrikethrough = function (excerpt) { if (typeof excerpt['text'][1] === 'undefined') { return; } let matches = null; //if (excerpt['text'][1] !== '~' || (matches = excerpt['text'].match(/^~~(?=\S)(.+?)(?<=\S)~~/)) === null) { // return; //} return { extent: matches[0].length, element: { name: 'del', text: matches[1], handler: 'line' } }; }; jsOMS.Utils.Parser.Markdown.inlineUrl = function (excerpt) { if (typeof excerpt['text'][2] === 'undefined' || excerpt['text'][2] !== '/') { return; } let matches = null; if ((matches = excerpt['context'].match(/\bhttps?:[\/]{2}[^\s<]+\b\/*/ui)) === null) { return; } // todo: carefull php different?! match position missing return { extent: matches[0].length, position: 0, element: { name: 'a', text: matches[0], attributes: { href: matches[0] } } }; }; jsOMS.Utils.Parser.Markdown.inlineUrlTag = function (excerpt) { let matches = null; if (excerpt['text'].indexOf('>') === -1 || (matches = excerpt['text'].match(/^<(\w+:\/{2}[^ >]+)>/i)) === null) { return; } let url = matches[1]; return { extent: matches[0].length, element: { name: 'a', text: url, attributes: { href: url } } }; }; jsOMS.Utils.Parser.Markdown.unmarkedText = function (text) { return text.replace(/(?:[ ][ ]+|[ ]*\\\\)\n/, "
\n").replace(" \n", "\n"); }; jsOMS.Utils.Parser.Markdown.element = function (element) { element = jsOMS.Utils.Parser.Markdown.sanitizeElement(element); let markup = '<' + element['name']; if (typeof element['attributes'] !== 'undefined') { for (let key in element['attributes']) { if (element['attributes'][key] === null) { continue; } markup += ' ' + key + '="' + jsOMS.Utils.Parser.Markdown.escape(element['attributes'][key]) + '"'; } } if (typeof element['text'] !== 'undefined') { markup += '>'; markup += typeof element['handler'] !== 'undefined' ? jsOMS.Utils.Parser.Markdown[element['handler']](element['text']) : jsOMS.Utils.Parser.Markdown.escape(element['text'], true); markup += ''; } else { markup += ' />'; } return markup; } jsOMS.Utils.Parser.Markdown.elements = function (elements) { let markup = ''; const length = elements.length; for (let i = 0; i < length; i++) { markup += "\n" + jsOMS.Utils.Parser.Markdown.element(elements[i]); } markup += "\n"; return markup; }; jsOMS.Utils.Parser.Markdown.li = function (lines) { let markup = jsOMS.Utils.Parser.Markdown.lines(lines); let trimmedMarkup = jsOMS.trim(markup); if (lines.indexOf('') === -1 && trimmedMarkup.substr(0, 3) === '

') { markup = trimmedMarkup; markup = markup.substr(3); let position = markup.indexOf('

'); let temp = markup.substr(0, position - 1) + markup.substr(position + 4); markup = temp; } return markup; }; jsOMS.Utils.Parser.Markdown.sanitizeElement = function (element) { const safeUrlNameToAtt = { a: 'href', img: 'src' }; if (typeof safeUrlNameToAtt[element['name']] !== 'undefined') { element = jsOMS.Utils.Parser.Markdown.filterUnsafeUrlInAttribute(element, safeUrlNameToAtt[element['name']]); } if (typeof element['attributes'] !== 'undefined' && element['attributes'] !== null && element['attributes'] !== '') { for (let att in element['attributs']) { //if (att.match(/^[a-zA-Z0-9][a-zA-Z0-9-_]*+$/) === null) { // delete element['attributes'][att] //} else if (jsOMS.Utils.Parser.Markdown.striAtStart(att, 'on')) { // delete element['attributes'][att]; //} } } return element; }; jsOMS.Utils.Parser.Markdown.filterUnsafeUrlInAttribute = function (element, attribute) { const length = jsOMS.Utils.Parser.Markdown.safeLinksWhitelist.length; for (let i = 0; i < length; i++) { if (jsOMS.Utils.Parser.Markdown.striAtStart(element['attributes'][attribute], jsOMS.Utils.Parser.Markdown.safeLinksWhitelist[i])) { return element; } } element['attributes'][attribute] = element['attributes'][attribute].replace(':', '%3A'); return element; }; jsOMS.Utils.Parser.Markdown.escape = function (text, allowQuotes) { allowQuotes = typeof allowQuotes !== 'undefined'; return jsOMS.htmlspecialchars(text, allowQuotes); }; jsOMS.Utils.Parser.Markdown.striAtStart = function (string, needle) { const lenght = needle.length; if(length > string.length) { return false; } return string.substr(0, length).toLowerCase() === needle.toLowerCase(); }; }(window.jsOMS = window.jsOMS || {}));