You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
CheezeNotes/static/modules/md.js

624 lines
22 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

import { saveSelection, loadSelection } from "./caret.js";
function setEditable() {
let editModeButton = document.getElementById('editModeButton');
let cheezenotes = document.getElementById('cheezenotes');
if (editModeButton.classList.contains('buttonoff')) {
cheezenotes.contentEditable = false;
} else {
cheezenotes.contentEditable = true;
}
}
function load(textarea, div) {
div.innerHTML = '';
let lines = textarea.value.split('\n');
for (let i = 0; i < lines.length; i++) {
let line = lines[i];
line.replace('<', '&lt;');
let elem = formatLine(line);
div.append(elem);
}
redrawTables(div, 0);
}
function appendData(div, data) {
const selection = window.getSelection();
selection.deleteFromDocument();
let ret = saveSelection();
let line = ret[0];
let position = ret[1];
if (line == null) {
return;
}
let lineBegin = line.innerText.substring(0, position);
let lineEnd = line.innerText.substring(position, line.innerText.length);
let lines = data.split('\n');
let newline;
if (lines.length == 1) {
newline = formatLine(lineBegin + lines[0] + lineEnd);
line.parentNode.replaceChild(newline, line);
position = position + lines[0].length;
} else {
newline = formatLine(lineBegin + lines[0]);
line.parentNode.replaceChild(newline, line);
let prevline = newline;
for (let i = 1; i < lines.length - 1; i++) {
newline = formatLine(lines[i]);
prevline.after(newline);
prevline = newline;
}
newline = formatLine(lines[lines.length - 1] + lineEnd);
prevline.after(newline);
position = lines[lines.length - 1].length;
}
loadSelection([newline, position, newline, position]);
redrawTables(div, dpwidth(div));
}
var _dpwidth = null;
function dpwidth(div) {
if (_dpwidth != null) {
return _dpwidth;
}
let dp = document.createElement('span');
dp.classList.add('tokenfictif');
div.append(dp);
dp.innerText = ':';
_dpwidth = dp.getBoundingClientRect().width;
div.removeChild(dp);
return _dpwidth;
}
function save(textarea, div) {
let lines = div.children;
let text = '';
for (let i = 0; i < lines.length; i++) {
if (lines[i].innerText != '\n') {
text += lines[i].innerText.replace(emsp(), '\t');
}
if (i < lines.length - 1) {
text += '\n';
}
}
textarea.value = text;
return text;
}
function emsp() {
return '';
}
function onlinkin(e) {
let link = e.currentTarget;
if (document.getElementById('cheezenotes') !== document.activeElement) {
document.getElementById('cheezenotes').contentEditable = false;
}
}
function onlink(e) {
let cheezenotes = document.getElementById('cheezenotes');
if (cheezenotes.contentEditable == 'false') {
e.preventDefault();
setEditable();
let link = e.currentTarget;
if (link.host !== document.location.host) {
open(link.href);
} else {
fetch(link.href + '?data=&fromDomain=' + window.domain + '&fromPage=' + window.page).then((response) => {
let ta = document.getElementById('ta');
response.text().then((data) => {
let content = document.getElementById('content');
let left = content.scrollLeft;
let top = content.scrollTop;
window.history.replaceState({ top: top, left: left }, "");
window.history.pushState({}, "", link.href);
document.title = 'CheezeNotes - ' + link.getAttribute('data-href');
ta.value = data;
let url = link.getAttribute('data-href').split('/');
let page = url[0];
let domain = window.domain;
if (url.length == 3) {
domain = url[1];
page = url[2];
}
window.domain = domain;
window.page = page;
load(document.getElementById('ta'), cheezenotes);
content.scrollTop = 0;
content.scrollLeft = 0;
});
}).catch((error) => { alert(error); });
}
return false;
} else {
return true;
}
}
function onlinkout(e) {
let cheezenotes = document.getElementById('cheezenotes');
if (cheezenotes.contentEditable == 'false') {
setEditable();
}
}
function oncheckbox(e) {
let cb = e.currentTarget;
let line = cb.parentNode;
let text = line.innerText;
if (cb.checked) {
text = text.replace(/^(\s*)(\[\])/, "$1[v]");
} else {
text = text.replace(/^(\s*)(\[[vVxX]\])/, "$1[]");
}
let newline = formatLine(text);
line.parentNode.replaceChild(newline, line);
}
function formatLine(line) {
let token = null;
let elem = document.createElement('div');
elem.classList.add('cheezenotes_line');
if (line == '' || line == '\n') {
elem.classList.add('body');
elem.innerHTML = '<br>';
return elem;
}
line = line.replace(/\t/, emsp());
line = line.replace('&', '&amp;');
line = line.replace('<', '&lt;');
let ret = removeMono(line);
line = ret[0];
let listMono = ret[1];
ret = removeLink(line);
line = ret[0];
let listLink = ret[1];
if (line.match(/^\s*_{3,}\s*$/)) {
token = /^(\s*_{3,}\s*)$/
elem.classList.add('line');
} else if (line.match(/^\s*######(\s|$)/i)) {
token = /^(\s*######(\s|$))/i;
elem.classList.add('h6');
elem.classList.add('h');
} else if (line.match(/^\s*#####(\s|$)/i)) {
token = /^(\s*#####(\s|$))/i;
elem.classList.add('h5');
elem.classList.add('h');
} else if (line.match(/^\s*####(\s|$)/i)) {
token = /^(\s*####(\s|$))/i;
elem.classList.add('h4');
elem.classList.add('h');
} else if (line.match(/^\s*###(\s|$)/i)) {
token = /^(\s*###(\s|$))/i;
elem.classList.add('h3');
elem.classList.add('h');
} else if (line.match(/^\s*##(\s|$)/)) {
token = /^(\s*##(\s|$))/i;
elem.classList.add('h2');
elem.classList.add('h');
} else if (line.match(/^\s*#(\s|$)/i)) {
token = /^(\s*#(\s|$))/i;
elem.classList.add('h1');
elem.classList.add('h');
} else if (line.match(/^\s*>\s*>\s*>(\s|$)/i)) {
token = /^(\s*>\s*>\s*>(\s|$))/i;
elem.classList.add('bq3');
elem.classList.add('bq');
} else if (line.match(/^\s*>\s*>(\s|$)/i)) {
token = /^(\s*>\s*>(\s|$))/i;
elem.classList.add('bq2');
elem.classList.add('bq');
} else if (line.match(/^\s*>(\s|$)/i)) {
token = /^(\s*>(\s|$))/i;
elem.classList.add('bq1');
elem.classList.add('bq');
} else if (line.match(/^\s*\[[xXvV]?\]\s+/i)) {
//token = /^(\s*\[[xXvV]?\]\s+)/i;
let checked = '';
if (line.match(/^\s*\[[xXvV]\]\s+/i)) {
checked = ' checked="checked"';
}
line = line.replace(/^(\s*\[[xXvV]?\]\s+)/i, '<input class="checkbox" type="checkbox"' + checked + '><span class="token">$1</span></input>')
elem.classList.add('checkbox');
} else {
elem.classList.add('body');
}
if (elem.classList.contains('bq') || elem.classList.contains('body')) {
if (line.match(/^\s*((>\s*){0,3}\s)?([\*\-+]\s*){3}(\s|$)/i)) {
token = /^(\s*(>\s*){0,3}([\*\-+]\s*){3}(\s|$))/i;
elem.classList.add('ul3');
elem.classList.remove('body');
} else if (line.match(/^\s*((>\s*){0,3}\s)?([\*\-+]\s*){2}(\s|$)/i)) {
token = /^(\s*(>\s*){0,3}([\*\-+]\s*){2}(\s|$))/i;
elem.classList.add('ul2');
elem.classList.remove('body');
} else if (line.match(/^\s*((>\s*){0,3}\s)?[\*\-+](\s|$)/i)) {
token = /^(\s*(>\s*){0,3}[\*\-+](\s*|$))/;
elem.classList.add('ul1');
elem.classList.remove('body');
} else if (line.match(/^\s*((>\s*){0,3}\s)?([0-9]+\.){3}(\s|$)/i)) {
token = /^(\s*(>\s*){0,3}(\s*|$))/;
elem.classList.add('ol3');
elem.classList.remove('body');
} else if (line.match(/^\s*((>\s*){0,3}\s)?([0-9]+\.){2}(\s|$)/i)) {
token = /^(\s*(>\s*){0,3}(\s*|$))/;
elem.classList.add('ol2');
elem.classList.remove('body');
} else if (line.match(/^\s*((>\s*){0,3}\s)?[0-9]+\.(\s|$)/i)) {
token = /^(\s*(>\s*){0,3}(\s*|$))/;
elem.classList.add('ol1');
elem.classList.remove('body');
}
}
if (token != null) {
line = line.replace(token, '<span class="token">$1</span>');
}
line = addBold(line);
line = addItalic(line);
line = addStrike(line);
line = addTableLine(line);
line = addLink(line, listLink);
line = addMono(line, listMono);
elem.innerHTML = line;
let checkboxes = elem.getElementsByClassName('checkbox');
for (let i = 0; i < checkboxes.length; i++) {
let checkbox = checkboxes[i];
checkbox.addEventListener('mouseover', onlinkin);
checkbox.addEventListener('change', oncheckbox);
checkbox.addEventListener('mouseout', onlinkout);
}
if (elem.getElementsByClassName('tablerow').length > 0) {
if (elem.childNodes[0].childNodes.length > 0) {
let child = elem.childNodes[0].childNodes[0];
while (child != null) {
if (child.nodeType == 3) {
let newchild = document.createElement('span');
newchild.innerText = child.nodeValue;
child.parentNode.replaceChild(newchild, child);
child = newchild;
}
child = child.nextSibling;
}
}
elem.classList.remove('body');
elem.classList.add('tablerow');
}
let links = elem.getElementsByClassName('link');
for (let i = 0; i < links.length; i++) {
let link = links[i];
link.addEventListener('mouseover', onlinkin);
link.addEventListener('click', onlink);
link.addEventListener('mouseout', onlinkout);
}
return elem;
}
function addTableLine(line) {
if (line.match(/^\s*\|:{0,1}(\s*.*?:{0,1}\|:{0,1})*/)) {
let cpt = 0;
let re = /:{0,1}\|:{0,1}/g;
let match;
let matches = [];
let lengthes = []
while ((match = re.exec(line)) != null) {
matches[cpt] = match;
if (cpt > 1000) {
continue;
}
cpt++;
}
matches = matches.reverse();
for (let i = 0; i < matches.length; i++) {
let match = matches[i];
if (i == matches.length - 1) {
// premier |
let leftdp = ' data-dp="false"';
if (match[0].length == 2) {
leftdp = ' data-dp="true"';
}
let line1 = line.substring(0, match.index);
let line2 = '<span class="token">' + match[0] + '</span><span class="lefttablespacer"' + leftdp + '></span>'
let line3 = line.substring(match.index + match[0].length, line.length);
line = line1 + line2 + line3;
} else if (i == 0 && match.index == line.length - 1) {
// dernier |
let rightdp = ' data-dp="false"';
if (match[0].charAt(0) == ':') {
rightdp = ' data-dp="true"';
}
let line1 = line.substring(0, match.index);
let line2 = '<span class="righttablespacer"' + rightdp + '></span><span class="token">' + match[0] + '</span>'
let line3 = line.substring(match.index + match[0].length, line.length);
line = line1 + line2 + line3;
} else {
let rightdp = ' data-dp="false"';
let leftdp = ' data-dp="false"';
if (match[0].length == 3) {
rightdp = ' data-dp="true"';
leftdp = ' data-dp="true"';
} else if (match[0].length == 2) {
if (match[0].charAt(0) == ':') {
rightdp = ' data-dp="true"';
} else {
leftdp = ' data-dp="true"';
}
}
let line1 = line.substring(0, match.index);
let line2 = '<span class="righttablespacer"' + rightdp + '></span><span class="token">' + match[0] + '</span><span class="lefttablespacer"' + leftdp + '></span>';
let line3 = line.substring(match.index + match[0].length, line.length);
line = line1 + line2 + line3;
}
}
line = '<span class="tablerow">' + line + '</span>';
}
return line;
}
function redrawTables(cheezenotes, dpwidth = 0) {
if (cheezenotes.childNodes.length == 0) {
return;
}
let child = cheezenotes.childNodes[0];
let firsttableline = null;
while (child != null) {
if (firsttableline == null) {
if (child.classList.contains('tablerow')) {
firsttableline = child;
}
} else {
if (!child.classList.contains('tablerow')) {
formatTable(firsttableline, dpwidth);
firsttableline = null;
}
}
child = child.nextSibling;
}
if (firsttableline != null) {
formatTable(firsttableline, dpwidth);
}
}
function formatTable(line, dpwidth = 0) {
if (!line.classList.contains('tablerow')) {
return;
}
let firstline = line;
let lastline = line;
while (firstline.previousSibling !== null && firstline.previousSibling.classList.contains('tablerow')) {
firstline = firstline.previousSibling;
firstline.classList.remove('firsttablerow');
firstline.classList.remove('lasttablerow');
}
while (lastline.nextSibling !== null && lastline.nextSibling.classList.contains('tablerow')) {
lastline = lastline.nextSibling;
lastline.classList.remove('firsttablerow');
lastline.classList.remove('lasttablerow');
}
firstline.classList.add('firsttablerow');
lastline.classList.add('lasttablerow');
resizeTableCols(firstline, lastline, dpwidth)
}
function resizeTableCols(firstline, lastline, dpwidth) {
let colsmaxwidth = [];
let colsjustif = [];
let currentline = firstline;
while (currentline !== null && currentline.classList.contains('tablerow')) {
let tablerow = currentline.getElementsByClassName('tablerow')[0];
let childNodes = tablerow.childNodes;
let currentwidth = 0;
let col = 0;
let currentleft;
for (let i = 0; i < childNodes.length; i++) {
let child = childNodes[i];
if (child.classList != null && child.classList.contains('lefttablespacer')) {
currentleft = child;
} else if (child.classList != null && child.classList.contains('righttablespacer')) {
let leftdp = currentleft.getAttribute('data-dp');
let rightdp = child.getAttribute('data-dp');
if (colsjustif[col] == null) {
if (leftdp == 'true' && rightdp == 'true') {
colsjustif[col] = 'c';
} else if (leftdp == 'true' && rightdp == 'false') {
colsjustif[col] = 'l';
} else if (leftdp == 'false' && rightdp == 'true') {
colsjustif[col] = 'r';
}
}
if (colsmaxwidth[col] == null || colsmaxwidth[col] < currentwidth) {
colsmaxwidth[col] = currentwidth;
}
child.dataWidth = currentwidth;
currentleft.dataWidth = currentwidth;
currentleft = null;
currentwidth = 0;
col += 1;
} else if (currentleft != null) {
let width = child.getBoundingClientRect().width;
currentwidth += width;
}
}
currentline = currentline.nextSibling;
}
for (let i = 0; i < colsmaxwidth.length; i++) {
if (colsjustif[i] == null) {
colsjustif[i] = 'l';
}
}
currentline = firstline;
while (currentline !== null && currentline.classList.contains('tablerow')) {
let tablerow = currentline.getElementsByClassName('tablerow')[0];
let childNodes = tablerow.childNodes;
let col = 0;
let currentleft;
for (let i = 0; i < childNodes.length; i++) {
let child = childNodes[i];
if (child.classList != null && child.classList.contains('lefttablespacer')) {
currentleft = child;
} else if (child.classList != null && child.classList.contains('righttablespacer')) {
let lplus = dpwidth;
let rplus = dpwidth;
let justif = 'l';
let leftdp = currentleft.getAttribute('data-dp');
let rightdp = child.getAttribute('data-dp');
if (leftdp == 'true' && rightdp == 'true') {
justif = 'c';
lplus = 0;
rplus = 0;
} else if (leftdp == 'true' && rightdp == 'false') {
justif = 'l';
lplus = 0;
} else if (leftdp == 'false' && rightdp == 'true') {
justif = 'r';
rplus = 0;
} else {
justif = colsjustif[col];
}
colsjustif[col] = justif;
let leftwidth = 10 + lplus;
let rightwidth = Math.round(colsmaxwidth[col] - child.dataWidth + 10 + rplus);
if (justif == 'c') {
leftwidth = Math.round((colsmaxwidth[col] - child.dataWidth) / 2 + 10 + lplus);
rightwidth = Math.round((colsmaxwidth[col] - child.dataWidth) / 2 + 10 + rplus);
} else if (justif == 'r') {
leftwidth = Math.round(colsmaxwidth[col] - child.dataWidth + 10 + lplus);
rightwidth = 10 + rplus;
}
currentleft.style.width = '' + leftwidth + 'px';
child.style.width = '' + rightwidth + 'px';
currentleft = null;
col += 1;
}
}
currentline = currentline.nextSibling;
}
}
function removeMono(line) {
let listMono = line.match(/`(`|.*?)`/g);
if (listMono == null) {
return [line, null];
}
line = line.replace(/`(`|.*?)`/g, "``");
return [line, listMono.reverse()];
}
function addMono(line, listMono) {
if (listMono == null) {
return line;
}
let cpt = 0;
let match;
let matches = [];
let re = /``/g;
while ((match = re.exec(line)) != null) {
matches[cpt] = match.index;
if (cpt > 1000) {
continue;
}
cpt++;
}
matches = matches.reverse();
for (let i = 0; i < matches.length; i++) {
let mono = listMono[i];
mono = mono.substring(1, mono.length - 1);
line = line.substring(0, matches[i]) + '<span class="token">`</span><span class="mono">' + mono + '</span><span class="token">`</span>' + line.substring(matches[i] + 2, line.length);
}
return line;
}
function removeLink(line) {
let listLink = line.match(/(\[([^\]]*?)\]\(([^\)]*?)\))/g);
if (listLink == null) {
return [line, null];
}
line = line.replace(/(\[([^\]]*?)\]\(([^\)]*?)\))/g, "[]()");
return [line, listLink.reverse()];
}
function addLink(line, listLink) {
if (listLink == null) {
return line;
}
let cpt = 0;
let match;
let matches = [];
let re = /\[\]\(\)/g;
while ((match = re.exec(line)) != null) {
matches[cpt] = match.index;
if (cpt > 1000) {
continue;
}
cpt++;
}
matches = matches.reverse();
for (let i = 0; i < matches.length; i++) {
line = line.substring(0, matches[i]) + formatLink(listLink[i]) + line.substring(matches[i] + 4, line.length);
}
return line;
}
function formatLink(link) {
let matches = link.match(/\[(.*)\]\((.*)\)/);
let libelle = matches[1];
let url = matches[2];
if (url == '' && libelle == '') {
return link;
}
let href = url;
if (href == '') {
href = libelle;
}
if (href.match(/^[^\:\/]+\/.*$/)) {
href = '/' + href;
}
let datahref = href;
href = formatUrl(href);
if (libelle == '') {
return '<span class="token">[](</span><a class="link" data-href="' + datahref + '" href="' + href + '">' + url + '</a><span class="token">)</span>';
} else {
if (libelle.startsWith('!')) {
return '<span class="token">[' + libelle + '</span><img style="vertical-align: top; max-height: 1rem;" class="image" src="' + href + '" title="' + libelle.substring(1) + '" /><span class="token">](' + url + ')</span>';
} else {
return '<span class="token">[</span><a class="link" data-href="' + datahref + '" href="' + href + '">' + libelle + '</a><span class="token">](' + url + ')</span>';
}
}
}
function formatUrl(url) {
if (url.match(/\w+:\/\//)) {
return url;
}
return window.baseUrl + url.replace(' ', '_');
}
function addBold(line) {
line = line.replace(/\*\*([^\s].*?)\*\*/ig, '<b><span class="token">**</span>$1<span class="token">**</span></b>');
line = line.replace(/__([^\s].*?)__/ig, '<b><span class="token">__</span>$1<span class="token">__</span></b>');
return line;
}
function addItalic(line) {
line = line.replace(/(^|[^\*])\*([^\*\s].*?[^\*\s]|[^\*\s])\*([^\*]|$)/ig, '$1<i><span class="token">*</span>$2<span class="token">*</span></i>$3');
line = line.replace(/(^|[\s^*])_([^_\s].*?[^_\s]|[^_\s])_([^_]|$)/ig, '$1<i><span class="token">_</span>$2<span class="token">_</span></i>$3');
return line;
}
function addStrike(line) {
line = line.replace(/~~([^\s].*?)~~/ig, '<s><span class="token">~~</span>$1<span class="token">~~</span></s>');
return line;
}
export { load, save, formatLine, formatTable, redrawTables, dpwidth, appendData };