forked from cory/tildefriends
		
	Consolidate markdown linkification, and add support for authors, blobs, and messages.
This commit is contained in:
		@@ -1,5 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
	"type": "tildefriends-app",
 | 
			
		||||
	"emoji": "🐌",
 | 
			
		||||
	"previous": "&Xs1X5TzLCk6KVr+5IDc80JAHYxJyoD10cXKBUYpFqWQ=.sha256"
 | 
			
		||||
	"previous": "&0WzpczDOhxawXBY8fAPMQWwOuF8bVRO+cMJJTxBpYOQ=.sha256"
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,90 +1,94 @@
 | 
			
		||||
function textNode(text) {
 | 
			
		||||
  const node = new commonmark.Node("text", undefined);
 | 
			
		||||
  node.literal = text;
 | 
			
		||||
  return node;
 | 
			
		||||
	const node = new commonmark.Node('text', undefined);
 | 
			
		||||
	node.literal = text;
 | 
			
		||||
	return node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function linkNode(text, link) {
 | 
			
		||||
  const linkNode = new commonmark.Node("link", undefined);
 | 
			
		||||
  linkNode.destination = `#q=${encodeURIComponent(link)}`;
 | 
			
		||||
  linkNode.appendChild(textNode(text));
 | 
			
		||||
  return linkNode;
 | 
			
		||||
	const linkNode = new commonmark.Node('link', undefined);
 | 
			
		||||
	if (link.startsWith('#')) {
 | 
			
		||||
		linkNode.destination = `#q=${encodeURIComponent(link)}`;
 | 
			
		||||
	} else {
 | 
			
		||||
		linkNode.destination = link;
 | 
			
		||||
	}
 | 
			
		||||
	linkNode.appendChild(textNode(text));
 | 
			
		||||
	return linkNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function splitMatches(text, regexp) {
 | 
			
		||||
  // Regexp must be sticky.
 | 
			
		||||
  regexp = new RegExp(regexp, "gm");
 | 
			
		||||
	// Regexp must be sticky.
 | 
			
		||||
	regexp = new RegExp(regexp, 'gm');
 | 
			
		||||
 | 
			
		||||
  let i = 0;
 | 
			
		||||
  const result = [];
 | 
			
		||||
	let i = 0;
 | 
			
		||||
	const result = [];
 | 
			
		||||
 | 
			
		||||
  let match = regexp.exec(text);
 | 
			
		||||
  while (match) {
 | 
			
		||||
    const matchText = match[0];
 | 
			
		||||
	let match = regexp.exec(text);
 | 
			
		||||
	while (match) {
 | 
			
		||||
		const matchText = match[0];
 | 
			
		||||
 | 
			
		||||
    if (match.index > i) {
 | 
			
		||||
      result.push([text.substring(i, match.index), false]);
 | 
			
		||||
    }
 | 
			
		||||
		if (match.index > i) {
 | 
			
		||||
			result.push([text.substring(i, match.index), false]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
    result.push([matchText, true]);
 | 
			
		||||
    i = match.index + matchText.length;
 | 
			
		||||
		result.push([matchText, true]);
 | 
			
		||||
		i = match.index + matchText.length;
 | 
			
		||||
 | 
			
		||||
    match = regexp.exec(text);
 | 
			
		||||
  }
 | 
			
		||||
		match = regexp.exec(text);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  if (i < text.length) {
 | 
			
		||||
    result.push([text.substring(i, text.length), false]);
 | 
			
		||||
  }
 | 
			
		||||
	if (i < text.length) {
 | 
			
		||||
		result.push([text.substring(i, text.length), false]);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
	return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const regex = new RegExp("(?<!\\w)#[\\w-]+");
 | 
			
		||||
const regex = new RegExp('(?:https?://[^ ]+[^ .,])|(?:(?<!\\w)#[\\w-]+)|(?:@[A-Za-z0-9+/]+=.ed25519)|(?:[%&][A-Za-z0-9+/]+=.sha256)');
 | 
			
		||||
 | 
			
		||||
function split(textNodes) {
 | 
			
		||||
  const text = textNodes.map(n => n.literal).join("");
 | 
			
		||||
  const parts = splitMatches(text, regex);
 | 
			
		||||
	const text = textNodes.map((n) => n.literal).join('');
 | 
			
		||||
	const parts = splitMatches(text, regex);
 | 
			
		||||
 | 
			
		||||
  return parts.map(part => {
 | 
			
		||||
    if (part[1]) {
 | 
			
		||||
      return linkNode(part[0], part[0]);
 | 
			
		||||
    } else {
 | 
			
		||||
      return textNode(part[0]);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
	return parts.map((part) => {
 | 
			
		||||
		if (part[1]) {
 | 
			
		||||
			return linkNode(part[0], part[0]);
 | 
			
		||||
		} else {
 | 
			
		||||
			return textNode(part[0]);
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function transform(parsed) {
 | 
			
		||||
  const walker = parsed.walker();
 | 
			
		||||
  let event;
 | 
			
		||||
	const walker = parsed.walker();
 | 
			
		||||
	let event;
 | 
			
		||||
 | 
			
		||||
  let nodes = [];
 | 
			
		||||
  while ((event = walker.next())) {
 | 
			
		||||
    const node = event.node;
 | 
			
		||||
    if (event.entering && node.type === "text") {
 | 
			
		||||
      nodes.push(node);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (nodes.length > 0) {
 | 
			
		||||
        split(nodes)
 | 
			
		||||
          .reverse()
 | 
			
		||||
          .forEach(newNode => {
 | 
			
		||||
            nodes[0].insertAfter(newNode);
 | 
			
		||||
          });
 | 
			
		||||
	let nodes = [];
 | 
			
		||||
	while ((event = walker.next())) {
 | 
			
		||||
		const node = event.node;
 | 
			
		||||
		if (event.entering && node.type === 'text') {
 | 
			
		||||
			nodes.push(node);
 | 
			
		||||
		} else {
 | 
			
		||||
			if (nodes.length > 0) {
 | 
			
		||||
				split(nodes)
 | 
			
		||||
					.reverse()
 | 
			
		||||
					.forEach((newNode) => {
 | 
			
		||||
						nodes[0].insertAfter(newNode);
 | 
			
		||||
					});
 | 
			
		||||
 | 
			
		||||
        nodes.forEach(n => n.unlink());
 | 
			
		||||
        nodes = [];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
				nodes.forEach((n) => n.unlink());
 | 
			
		||||
				nodes = [];
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  if (nodes.length > 0) {
 | 
			
		||||
    split(nodes)
 | 
			
		||||
      .reverse()
 | 
			
		||||
      .forEach(newNode => {
 | 
			
		||||
        nodes[0].insertAfter(newNode);
 | 
			
		||||
      });
 | 
			
		||||
    nodes.forEach(n => n.unlink());
 | 
			
		||||
  }
 | 
			
		||||
	if (nodes.length > 0) {
 | 
			
		||||
		split(nodes)
 | 
			
		||||
			.reverse()
 | 
			
		||||
			.forEach((newNode) => {
 | 
			
		||||
				nodes[0].insertAfter(newNode);
 | 
			
		||||
			});
 | 
			
		||||
		nodes.forEach((n) => n.unlink());
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
  return parsed;
 | 
			
		||||
	return parsed;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,91 +0,0 @@
 | 
			
		||||
function textNode(text) {
 | 
			
		||||
  const node = new commonmark.Node("text", undefined);
 | 
			
		||||
  node.literal = text;
 | 
			
		||||
  return node;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function linkNode(text, url) {
 | 
			
		||||
  const urlNode = new commonmark.Node("link", undefined);
 | 
			
		||||
  urlNode.destination = url;
 | 
			
		||||
  urlNode.appendChild(textNode(text));
 | 
			
		||||
 | 
			
		||||
  return urlNode;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function splitMatches(text, regexp) {
 | 
			
		||||
  // Regexp must be sticky.
 | 
			
		||||
  regexp = new RegExp(regexp, "gm");
 | 
			
		||||
 | 
			
		||||
  let i = 0;
 | 
			
		||||
  const result = [];
 | 
			
		||||
 | 
			
		||||
  let match = regexp.exec(text);
 | 
			
		||||
  while (match) {
 | 
			
		||||
    const matchText = match[0];
 | 
			
		||||
 | 
			
		||||
    if (match.index > i) {
 | 
			
		||||
      result.push([text.substring(i, match.index), false]);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    result.push([matchText, true]);
 | 
			
		||||
    i = match.index + matchText.length;
 | 
			
		||||
 | 
			
		||||
    match = regexp.exec(text);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (i < text.length) {
 | 
			
		||||
    result.push([text.substring(i, text.length), false]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const urlRegexp = new RegExp("https?://[^ ]+[^ .,]");
 | 
			
		||||
 | 
			
		||||
function splitURLs(textNodes) {
 | 
			
		||||
  const text = textNodes.map(n => n.literal).join("");
 | 
			
		||||
  const parts = splitMatches(text, urlRegexp);
 | 
			
		||||
 | 
			
		||||
  return parts.map(part => {
 | 
			
		||||
    if (part[1]) {
 | 
			
		||||
      return linkNode(part[0], part[0]);
 | 
			
		||||
    } else {
 | 
			
		||||
      return textNode(part[0]);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function transform(parsed) {
 | 
			
		||||
  const walker = parsed.walker();
 | 
			
		||||
  let event;
 | 
			
		||||
 | 
			
		||||
  let nodes = [];
 | 
			
		||||
  while ((event = walker.next())) {
 | 
			
		||||
    const node = event.node;
 | 
			
		||||
    if (event.entering && node.type === "text") {
 | 
			
		||||
      nodes.push(node);
 | 
			
		||||
    } else {
 | 
			
		||||
      if (nodes.length > 0) {
 | 
			
		||||
        splitURLs(nodes)
 | 
			
		||||
          .reverse()
 | 
			
		||||
          .forEach(newNode => {
 | 
			
		||||
            nodes[0].insertAfter(newNode);
 | 
			
		||||
          });
 | 
			
		||||
 | 
			
		||||
        nodes.forEach(n => n.unlink());
 | 
			
		||||
        nodes = [];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (nodes.length > 0) {
 | 
			
		||||
    splitURLs(nodes)
 | 
			
		||||
      .reverse()
 | 
			
		||||
      .forEach(newNode => {
 | 
			
		||||
        nodes[0].insertAfter(newNode);
 | 
			
		||||
      });
 | 
			
		||||
    nodes.forEach(n => n.unlink());
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return parsed;
 | 
			
		||||
}
 | 
			
		||||
@@ -17,7 +17,6 @@
 | 
			
		||||
		</script>
 | 
			
		||||
		<script src="filesaver.min.js"></script>
 | 
			
		||||
		<script src="commonmark.min.js"></script>
 | 
			
		||||
		<script src="commonmark-linkify.js" type="module"></script>
 | 
			
		||||
		<script src="commonmark-hashtag.js" type="module"></script>
 | 
			
		||||
		<script src="script.js" type="module"></script>
 | 
			
		||||
	</body>
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import * as linkify from './commonmark-linkify.js';
 | 
			
		||||
import * as hashtagify from './commonmark-hashtag.js';
 | 
			
		||||
 | 
			
		||||
function image(node, entering) {
 | 
			
		||||
@@ -67,7 +66,6 @@ export function markdown(md) {
 | 
			
		||||
	writer.image = image;
 | 
			
		||||
	let parsed = reader.parse(md || '');
 | 
			
		||||
	parsed = hashtagify.transform(parsed);
 | 
			
		||||
	parsed = linkify.transform(parsed);
 | 
			
		||||
	let walker = parsed.walker();
 | 
			
		||||
	let event, node;
 | 
			
		||||
	while ((event = walker.next())) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user