diff --git a/Gemfile b/Gemfile index 55c1de693..c97f80bde 100644 --- a/Gemfile +++ b/Gemfile @@ -35,6 +35,7 @@ gem 'devise-two-factor' gem 'doorkeeper' gem 'rabl' gem 'rqrcode' +gem 'twitter-text' gem 'oj' gem 'hiredis' gem 'redis', '~>3.2' diff --git a/Gemfile.lock b/Gemfile.lock index f50edaf95..19d61103d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -422,6 +422,8 @@ GEM thread_safe (0.3.5) tilt (2.0.5) tins (1.12.0) + twitter-text (1.14.5) + unf (~> 0.1.0) tzinfo (1.2.2) thread_safe (~> 0.1) uglifier (3.0.1) @@ -514,6 +516,7 @@ DEPENDENCIES simple_form simplecov statsd-instrument + twitter-text uglifier (>= 1.3.0) webmock will_paginate diff --git a/app/lib/formatter.rb b/app/lib/formatter.rb index 044407a6c..073ab0784 100644 --- a/app/lib/formatter.rb +++ b/app/lib/formatter.rb @@ -9,6 +9,8 @@ class Formatter include ActionView::Helpers::TextHelper include ActionView::Helpers::SanitizeHelper + AUTOLINK_RE = /https?:\/\/([\S]+\.[!#$&-;=?-[\]_a-z~]|%[\w\d]{2}]+[\w])/i + def format(status) return reformat(status.content) unless status.local? @@ -44,9 +46,9 @@ class Formatter end def link_urls(html) - html.gsub(URI.regexp(%w(http https))) do |match| - link_html(match) - end + Twitter::Autolink.auto_link_urls(html, url_target: '_blank', + link_attribute_block: lambda { |_, a| a[:rel] << ' noopener' }, + link_text_block: lambda { |_, text| link_html(text) }) end def link_mentions(html, mentions) @@ -70,7 +72,7 @@ class Formatter suffix = url[prefix.length + 30..-1] cutoff = url[prefix.length..-1].length > 30 - "#{prefix}#{text}#{suffix}" + "#{prefix}#{text}#{suffix}" end def hashtag_html(match) diff --git a/spec/lib/formatter_spec.rb b/spec/lib/formatter_spec.rb index 0db1634e9..4b003b8e5 100644 --- a/spec/lib/formatter_spec.rb +++ b/spec/lib/formatter_spec.rb @@ -17,8 +17,38 @@ RSpec.describe Formatter do end it 'contains a link' do - expect(subject).to match('google.com') + expect(subject).to match('google.com') end + +=begin + it 'matches a stand-alone medium URL' do + expect(subject.match('https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4')[0]).to eq 'https://hackernoon.com/the-power-to-build-communities-a-response-to-mark-zuckerberg-3f2cac9148a4' + end + + it 'matches a stand-alone google URL' do + expect(subject.match('http://google.com')[0]).to eq 'http://google.com' + end + + it 'matches a URL without trailing period' do + expect(subject.match('http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona. ')[0]).to eq 'http://www.mcmansionhell.com/post/156408871451/50-states-of-mcmansion-hell-scottsdale-arizona' + end + + it 'matches a URL without closing paranthesis' do + expect(subject.match('(http://google.com/)')[0]).to eq 'http://google.com' + end + + it 'matches a URL without exclamation point' do + expect(subject.match('http://www.google.com! ')[0]).to eq 'http://www.google.com' + end + + it 'matches a URL with a query string' do + expect(subject.match('https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink')[0]).to eq 'https://www.ruby-toolbox.com/search?utf8=%E2%9C%93&q=autolink' + end + + it 'matches a URL with parenthesis in it' do + expect(subject.match('https://en.wikipedia.org/wiki/Diaspora_(software)')[0]).to eq 'https://en.wikipedia.org/wiki/Diaspora_(software)' + end +=end end describe '#reformat' do