From fd9d270478964cc8d27c2eda686b66d9a31fcc35 Mon Sep 17 00:00:00 2001 From: Vitaly Puzrin Date: Thu, 9 Oct 2014 16:04:42 +0400 Subject: [PATCH] Added links autoconversion --- lib/typographer.js | 102 ++++++++++++++++++++++- package.json | 3 +- test/fixtures/remarkable/typographer.txt | 13 +++ 3 files changed, 114 insertions(+), 4 deletions(-) diff --git a/lib/typographer.js b/lib/typographer.js index a81ee1f..669f1ab 100644 --- a/lib/typographer.js +++ b/lib/typographer.js @@ -12,14 +12,110 @@ // - fractionals 1/2, 1/4, 3/4 -> ½, ¼, ¾ // - miltiplication 2 x 4 -> 2 × 4 -var assign = require('./common/utils').assign; -var defaults = require('./defaults_typographer'); -var Ruler = require('./ruler'); + +var Autolinker = require('autolinker'); + + +var assign = require('./common/utils').assign; +var escapeHtml = require('./helpers').escapeHtml; +var defaults = require('./defaults_typographer'); +var Ruler = require('./ruler'); + + +var links = []; +var autolinker = new Autolinker({ + stripPrefix: false, + replaceFn: function (autolinker, match) { + // Only collect matched strings but don't change anything. + var url; + if (match.getType() === 'url') { + url = match.getUrl(); + if (/^(http|https|ftp|git)/.test(url)) { + links.push(url); + } + } + return false; + } +}); var rules = []; +rules.push(function linkify(t, state) { + var i, token, text, nodes, ln, pos, level, + tokens = state.tokens; + + if (!t.options.linkify) { return; } + + for (i = tokens.length - 1; i >= 0; i--) { + token = tokens[i]; + + // Skip content of links + if (token.type === 'link_close') { + i--; + while (tokens[i].type !== 'link_open' && tokens[i].level !== token.level) { + i--; + } + i--; + continue; + } + + if (token.type === 'text' && + (token.content.indexOf('://') || + token.content.indexOf('www'))) { + text = token.content; + links = []; + autolinker.link(text); + + if (!links.length) { continue; } + + // Now split string to nodes + nodes = []; + level = token.level; + + for (ln = 0; ln < links.length; ln++) { + pos = text.indexOf(links[ln]); + if (pos) { + level = level; + nodes.push({ + type: 'text', + content: text.slice(0, pos), + level: level + }); + } + nodes.push({ + type: 'link_open', + href: links[ln], + title: '', + level: level++ + }); + nodes.push({ + type: 'text', + content: escapeHtml(links[ln]), + level: level + }); + nodes.push({ + type: 'link_close', + level: --level + }); + text = text.slice(pos + links[ln].length); + } + if (text.length) { + nodes.push({ + type: 'text', + content: text, + level: level + }); + } + + // replace cuttent node + state.tokens = tokens = [].concat(tokens.slice(0, i), nodes, tokens.slice(i + 1)); + } + } +}); + + rules.push(function single(t, state) { var i, token, text, tokens = state.tokens, diff --git a/package.json b/package.json index 995bca3..3bbf4c1 100644 --- a/package.json +++ b/package.json @@ -17,7 +17,8 @@ ], "main": "index.js", "dependencies": { - "argparse": "~ 0.1.15" + "argparse": "~ 0.1.15", + "autolinker": "~ 0.12.3" }, "devDependencies": { "ansi": "^0.3.0", diff --git a/test/fixtures/remarkable/typographer.txt b/test/fixtures/remarkable/typographer.txt index 1afa319..5b44b24 100644 --- a/test/fixtures/remarkable/typographer.txt +++ b/test/fixtures/remarkable/typographer.txt @@ -62,6 +62,19 @@ em-dashes . +linkify +. +url http://www.youtube.com/watch?v=5Jt5GEr4AYg. +. +

url http://www.youtube.com/watch?v=5Jt5GEr4AYg.

+. +. +don't touch text in links +. +

don't touch text in links https://example.com

+. + + TODO: