marked.use({ breaks: true, extensions: [ { name: 'mention', level: 'inline', start: function(src){ const match = src.match(/@[a-zA-Z0-9_\-]+/); return match != null ? match.index : -1; }, tokenizer: function(src) { const rule = /^@[a-zA-Z0-9_\-]+/; const match = rule.exec(src); if(match){ return { type: 'mention', raw: match[0], text: match[0].trim().slice(1), tokens: [] }; } }, renderer(token) { const u = token.raw; return ` ${u}`; } }, { name: 'group_mention', level: 'inline', start: function(src){ const match = src.match(/![a-zA-Z0-9_\-]+/); return match != null ? match.index : -1; }, tokenizer: function(src) { const rule = /^![a-zA-Z0-9_\-]+/; const match = rule.exec(src); if(match){ return { type: 'group_mention', raw: match[0], text: match[0].trim().slice(1), tokens: [] }; } }, renderer(token) { const g = token.raw; return `${g}`; } }, ] }); const reDisableBeforeUnload = /^\/submit|^\/h\/[a-zA-Z0-9_\-]{3,20}\/submit/; const image_regex_extensions = document.getElementById('IMAGE_FORMATS').value.replaceAll(',', '|') const regex_pattern = String.raw`(^|\s)(https:\/\/[\w\-.#&/=\?@%;+,:]{5,250}(\.|\?format=)(` + image_regex_extensions + String.raw`)((\?|&)[\w\-.#&/=\?@%;+,:]*)?)($|\s)` const compiled_regex = new RegExp(regex_pattern, "g"); const approved_embed_hosts = document.getElementById('approved_embed_hosts').value.replace("{'", "").replace("'}", "").split("', '") function replace_image(match, prefix, url) { if (approved_embed_hosts.some(x => url.startsWith(`https://${x}/`))) return `${prefix}![](${url})` return match } const MODIFIERS = { PAT: 1, TALKING: 2, LARGE: 3, REVERSED: 4, USER: 5, REVERSED_MODIFIER: 6, }; function markdown(t) { let input = t.value; if (!reDisableBeforeUnload.test(location.pathname)) { if (!window.onbeforeunload) { window.onbeforeunload = function (e) { e = e || window.event; if (e) { e.returnValue = 'Any string'; } return 'Any string'; }; } else if (!input) { window.onbeforeunload = null } } input = input.replace(/\|\|(.*?)\|\|/g, '$1') input = input.replace(/(\n|^)>([^ >][^\n]*)/g, '$1\>$2') input = input.replace(/((\s|^)[0-9]+)\. /g, '$1\\. ') const emojis = Array.from(input.matchAll(/:([a-z0-9_\-!#@]{1,36}):(?![^`]*`)/gi)) if(emojis != null){ for(i = 0; i < emojis.length; i++){ const old = emojis[i][0]; if (old.includes('marseyrandom')) continue; if (old.includes('marseyrandom')) continue let emoji = old.replace(/[:]/g,'').toLowerCase(); const modifiers = new Set(); let length = emoji.length if(emoji.includes('!!')) modifiers.add(MODIFIERS.REVERSED_MODIFIER); emoji = emoji.replaceAll('!', ''); if(length !== emoji.length) { modifiers.add(MODIFIERS.REVERSED); length = emoji.length; } emoji = emoji.replaceAll('#', ''); if(length !== emoji.length) { modifiers.add(MODIFIERS.LARGE); } const isTalkingFirst = !(emoji.endsWith('pat') && emoji.slice(0, -3).endsWith('talking')); if(emoji.endsWith('talking') || (emoji.endsWith('pat') && emoji.slice(0, -3).endsWith('talking'))) { modifiers.add(MODIFIERS.TALKING); emoji = emoji.endsWith('pat') ? [emoji.slice(0, -10), emoji.slice(-3)].join('') : emoji.slice(0, -7); } if(emoji.endsWith('pat')) { modifiers.add(MODIFIERS.PAT); emoji = emoji.slice(0, -3); } if(emoji.startsWith('@')) { emoji = emoji.slice(1); modifiers.add(MODIFIERS.USER); } if(emoji === 'marseyunpettable') { modifiers.delete(MODIFIERS.PAT); if(!isTalkingFirst) { modifiers.delete(MODIFIERS.TALKING); } } const mirroredClass = 'mirrored'; const emojiClass = modifiers.has(MODIFIERS.LARGE) ? 'emoji-lg' : 'emoji'; // patted emotes cannot be flipped back easily so they don't support double flipping const spanClass = modifiers.has(MODIFIERS.REVERSED) && (modifiers.has(MODIFIERS.PAT) || !modifiers.has(MODIFIERS.REVERSED_MODIFIER)) ? mirroredClass : ''; const imgClass = modifiers.has(MODIFIERS.REVERSED) && modifiers.has(MODIFIERS.REVERSED_MODIFIER) ? mirroredClass : '' if (modifiers.has(MODIFIERS.PAT) || modifiers.has(MODIFIERS.TALKING)) { const talkingHtml = modifiers.has(MODIFIERS.TALKING) ? `` : ''; const patHtml = modifiers.has(MODIFIERS.PAT) ? `` : ''; const url = modifiers.has(MODIFIERS.USER) ? `/@${emoji}/pic` : `${SITE_FULL_IMAGES}/e/${emoji}.webp`; const modifierHtml = isTalkingFirst ? `${talkingHtml}${patHtml}` : `${patHtml}${talkingHtml}`; input = input.replace(old, `${modifierHtml}`); } else { input = input.replace(old, ``); } } } let options = Array.from(input.matchAll(/\$\$([^\$\n]+)\$\$(?![^`]*`)/gi)) if(options != null){ for(i = 0; i < options.length; i++){ const option = options[i][0]; const option2 = option.replace(/\$\$/g, '').replace(/\n/g, '') input = input.replace(option, `
`); } } options = Array.from(input.matchAll(/&&([^&\n]+)&&(?![^`]*`)/gi)) if(options != null){ for(i = 0; i < options.length; i++){ const option = options[i][0]; const option2 = option.replace(/&&/g, '').replace(/\n/g, '') input = input.replace(option, `
`); } } input = input.replace(compiled_regex, replace_image) input = marked(input) const preview = document.getElementById(t.dataset.preview) preview.innerHTML = input const expandable = preview.querySelectorAll('img[alt]'); for (const element of expandable) { element.onclick = () => {expandImage()}; } } function charLimit(form, text) { const input = document.getElementById(form); text = document.getElementById(text); const length = input.value.length; const maxLength = input.getAttribute("maxlength"); if (length >= maxLength) { text.style.color = "#E53E3E"; } else if (length >= maxLength * .72){ text.style.color = "#FFC107"; } else { text.style.color = "#A0AEC0"; } text.innerText = length + ' / ' + maxLength; } function remove_dialog() { window.onbeforeunload = null; }