diff --git a/app/assets/javascripts/app/helpers/text_formatter.js b/app/assets/javascripts/app/helpers/text_formatter.js index 7a3c626a0..2e0c7b7ca 100644 --- a/app/assets/javascripts/app/helpers/text_formatter.js +++ b/app/assets/javascripts/app/helpers/text_formatter.js @@ -15,7 +15,7 @@ url = // rebuild the url (!addr.scheme ? '' : addr.scheme + - ( (addr.scheme.toLowerCase()=="mailto") ? ':' : '://')) + + ( (addr.scheme.toLowerCase()=="mailto" || addr.scheme.toLowerCase()=="xmpp") ? ':' : '://')) + (!addr.user ? '' : addr.user + (!addr.pass ? '' : ':'+addr.pass) + '@') + punycode.toASCII(addr.host) + diff --git a/lib/assets/javascripts/markdown-it-diaspora-linkify.js b/lib/assets/javascripts/markdown-it-diaspora-linkify.js index 319497b08..4ffa8f727 100644 --- a/lib/assets/javascripts/markdown-it-diaspora-linkify.js +++ b/lib/assets/javascripts/markdown-it-diaspora-linkify.js @@ -2,69 +2,11 @@ // remove it as soon as markdown-it fixes its autolinking feature /*! markdown-it-diaspora-linkify 0.1.0 https://github.com/diaspora/markdown-it-diaspora-linkify @license MIT */!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.markdownitDiasporaLinkify=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o\s]/i.test(str); @@ -78,7 +20,7 @@ module.exports = function linkify_plugin(md) { function linkify(state) { var i, j, l, tokens, token, text, nodes, ln, pos, level, htmlLinkLevel, - blockTokens = state.tokens, links, href; + blockTokens = state.tokens, links, href, url; if (!state.md.options.linkify) { return; } @@ -113,62 +55,60 @@ module.exports = function linkify_plugin(md) { } if (htmlLinkLevel > 0) { continue; } - if (token.type === 'text' && LINK_SCAN_RE.test(token.content)) { + if (token.type !== 'text') { continue; } - text = token.content; - links = text.match(urlRegex()); + links = token.content.match(urlRegex); + if (links === null || !links.length) { continue; } - if (links === null || !links.length) { continue; } + text = token.content; - // Now split string to nodes - nodes = []; - level = token.level; + // Now split string to nodes + nodes = []; + level = token.level; - for (ln = 0; ln < links.length; ln++) { + for (ln = 0; ln < links.length; ln++) { + url = links[ln].trim(); + href = url; - if (!state.md.inline.validateLink(links[ln])) { continue; } + if (/^www/i.test(href)) { href = 'http://' + href; } + pos = text.indexOf(url); - pos = text.indexOf(links[ln]); - - href = links[ln]; - - if (pos) { - level = level; - nodes.push({ - type: 'text', - content: text.slice(0, pos), - level: level - }); - } - nodes.push({ - type: 'link_open', - href: href, - target: '', - title: '', - level: level++ - }); + if (pos) { + level = level; nodes.push({ type: 'text', - content: 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, + content: text.slice(0, pos), level: level }); } - - // replace current node - blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes); + nodes.push({ + type: 'link_open', + href: href, + target: '', + title: '', + level: level++ + }); + nodes.push({ + type: 'text', + content: url, + level: level + }); + nodes.push({ + type: 'link_close', + level: --level + }); + text = text.slice(pos + url.length); } + if (text.length) { + nodes.push({ + type: 'text', + content: text, + level: level + }); + } + + // replace current node + blockTokens[j].children = tokens = arrayReplaceAt(tokens, i, nodes); } } } @@ -176,5 +116,5 @@ module.exports = function linkify_plugin(md) { md.core.ruler.at('linkify', linkify); }; -},{"url-regex":1}]},{},[4])(4) +},{}]},{},[1])(1) }); diff --git a/spec/javascripts/app/helpers/text_formatter_spec.js b/spec/javascripts/app/helpers/text_formatter_spec.js index ccbd7d1c3..c9f5750be 100644 --- a/spec/javascripts/app/helpers/text_formatter_spec.js +++ b/spec/javascripts/app/helpers/text_formatter_spec.js @@ -88,7 +88,9 @@ describe("app.helpers.textFormatter", function(){ "http://japan.co.jp", "www.mygreat-example-website.de", "www.jenseitsderfenster.de", // from issue #3468 - "www.google.com" + "www.google.com", + "xmpp:podmin@pod.tld", + "mailto:podmin@pod.tld" ]; var formattedText = this.formatter(links.join(" ")); @@ -195,6 +197,12 @@ describe("app.helpers.textFormatter", function(){ }); context("misc breakage and/or other issues with weird urls", function(){ + it("doesn't crash Firefox", function() { + var content = "antifaschistisch-feministische ://" + var parsed = this.formatter(content); + expect(parsed).toContain(content); + }); + it("doesn't crash Chromium - RUN ME WITH CHROMIUM! (issue #3553)", function() { var text_part = 'Revert "rails admin is conflicting with client side validations: see https://github.com/sferik/rails_admin/issues/985"'; @@ -226,6 +234,34 @@ describe("app.helpers.textFormatter", function(){ expect(parsed).toContain(this.correctHref); }); }); + + it("doesn't fail for misc urls", function() { + var contents = [ + 'https://foo.com!', + 'ftp://example.org:8080' + ]; + var results = [ + '

https://foo.com!

', + '

ftp://example.org:8080

' + ]; + for (var i = 0; i < contents.length; i++) { + expect(this.formatter(contents[i])).toContain(results[i]); + } + }); + }); + }); + + context("real world examples", function(){ + it("renders them as expected", function(){ + var contents = [ + 'oh, cool, nginx 1.7.9 supports json autoindexes: http://nginx.org/en/docs/http/ngx_http_autoindex_module.html#autoindex_format' + ]; + var results = [ + '

oh, cool, nginx 1.7.9 supports json autoindexes: http://nginx.org/en/docs/http/ngx_http_autoindex_module.html#autoindex_format

' + ]; + for (var i = 0; i < contents.length; i++) { + expect(this.formatter(contents[i])).toContain(results[i]); + } }); }); })