Skip to content
Snippets Groups Projects
Commit 3f498c58 authored by elijah's avatar elijah
Browse files

Merge branch 'feature/autolink' into 'master'

add autolink() helper

See merge request !2
parents 66a8b7dc 6ad3ea36
Branches master
No related tags found
1 merge request!2add autolink() helper
# encoding: utf-8
#
# adapted from https://github.com/tenderlove/rails_autolink, with minor
# modifications to support current rails and markdown.
#
# MIT license
#
# TODO:
#
# * consider using https://github.com/sporkmonger/addressable to clean up URLs
# (for example, URLs with ../.. that can be nefarious)
#
module NestHelpers
module AutolinkHelper
def autolink(str, html_options={}, options={}, &block)
auto_link_urls(str, html_options, options, &block)
end
private
AUTO_LINK_RE = %r{
(?: ((?:ed2k|ftp|http|https|irc|mailto|news|gopher|nntp|telnet|webcal|xmpp|callto|feed|svn|urn|aim|rsync|tag|ssh|sftp|rtsp|afs|file):)// | www\.\w )
[^\s<\u00A0"]+
}ix
# regexps for determining context, used high-volume
AUTO_LINK_CRE = [/<[^>]+$/, /^[^>]*>/, /<a\b.*?>/i, /<\/a>/i]
AUTO_EMAIL_LOCAL_RE = /[\w.!#\$%&'*\/=?^`{|}~+-]/
AUTO_EMAIL_RE = /(?<!#{AUTO_EMAIL_LOCAL_RE})[\w.!#\$%+-]\.?#{AUTO_EMAIL_LOCAL_RE}*@[\w-]+(?:\.[\w-]+)+/
BRACKETS = { ']' => '[', ')' => '(', '}' => '{' }
WORD_PATTERN = RUBY_VERSION < '1.9' ? '\w' : '\p{Word}'
BLOCKDOWN_LINK_RE = /[^\]]\]\(.+\)/ # matches "https:example.org](example)"
# Turns all urls into clickable links. If a block is given, each url
# is yielded and the result is used as the link text.
def auto_link_urls(text, html_options = {}, options = {})
link_attributes = html_options.stringify_keys
text.gsub(AUTO_LINK_RE) do
scheme, href = $1, $&
punctuation = []
trailing_gt = ""
if auto_linked?($`, $') || blockdown?($`,href)
# do not change string; URL is already linked
href
else
# don't include trailing punctuation character as part of the URL
while href.sub!(/[^#{WORD_PATTERN}\/\-=;]$/, '')
punctuation.push $&
if opening = BRACKETS[punctuation.last] and href.scan(opening).size > href.scan(punctuation.last).size
href << punctuation.pop
break
end
end
# don't include trailing &gt; entities as part of the URL
trailing_gt = $& if href.sub!(/&gt;$/, '')
link_text = block_given? ? yield(href) : href.sub(/^#{scheme}\/\//,'')
href = 'http://' + href unless scheme
unless options[:sanitize] == false
link_text = sanitize(link_text)
href = sanitize(href)
end
content_tag(:a, link_text, link_attributes.merge('href' => href), !!options[:sanitize]) + punctuation.reverse.join('') + trailing_gt.html_safe
end
end
end
# Turns all email addresses into clickable links.
def auto_link_email_addresses(text)
text.gsub(AUTO_EMAIL_RE) do
text = $&
if auto_linked?($`, $')
text
else
#display_text = (block_given?) ? yield(text) : text
#display_text = text
text.gsub!('@', '&#064').gsub!('.', '&#046;')
%(<a href="mailto:#{text}">#{text}</a>)
end
end
end
# Detects already linked context or position in the middle of a tag
def auto_linked?(left, right)
(left =~ AUTO_LINK_CRE[0] and right =~ AUTO_LINK_CRE[1]) or
(left.rindex(AUTO_LINK_CRE[2]) and $' !~ AUTO_LINK_CRE[3])
end
def blockdown?(before, href)
(before.last == "[" && href =~ BLOCKDOWN_LINK_RE) ||
(before.last == "<" && href.last == ">")
end
end
end
\ No newline at end of file
......@@ -16,7 +16,8 @@ module NestHelpers
# html in it, so there be dragons here.
#
# for this reason, we first pass the raw input text through rails sanitize()
# before it is passed to the markdown processor.
# before it is passed to the markdown processor. This has the unfortunate
# consequence of removing some valid markdown, such as "<https://example.org>"
#
# @param str [String] The string of markdown to convert.
# @param inline [Boolean] inline If true, don't include any block HTML elements (default: false).
......
#
# Adapted from rails_autolink gem
#
require 'minitest/autorun'
require 'action_view'
require_relative '../app/helpers/nest_helpers/autolink_helper'
class TestAutolink < ActionView::TestCase
include ActionView::Helpers
include ActionView::Helpers::SanitizeHelper
include NestHelpers::AutolinkHelper
def test_ignore_markdown_links
expected = "hello [https://example.org](example) goodbye"
actual = autolink(expected)
assert_equal expected, actual
expected = "hello [https://example.org](https://example.org) goodbye"
actual = autolink(expected)
assert_equal expected, actual
end
def test_ignore_markdown_caret_links
expected = "hello <https://example.org> goodbye"
actual = autolink(expected)
assert_equal expected, actual
end
def test_autolink_remove_scheme
assert_equal(
%q[Open the file at <a href="http://localhost/file">localhost/file</a>.],
autolink(
%q[Open the file at http://localhost/file.]
)
)
end
def test_autolink_within_tags
html = %Q(<img src="http://www.rubyonrails.org/images/rails.png">)
assert_equal html, autolink(html)
end
def test_autolink_with_brackets
link1_raw = 'http://en.wikipedia.org/wiki/Sprite_(computer_graphics)'
link1_result = generate_result(link1_raw)
assert_equal link1_result, autolink(link1_raw)
assert_equal "(link: #{link1_result})", autolink("(link: #{link1_raw})")
link2_raw = 'http://en.wikipedia.org/wiki/Sprite_[computer_graphics]'
link2_result = generate_result(link2_raw)
assert_equal link2_result, autolink(link2_raw)
assert_equal "[link: #{link2_result}]", autolink("[link: #{link2_raw}]")
link3_raw = 'http://en.wikipedia.org/wiki/Sprite_{computer_graphics}'
link3_result = generate_result(link3_raw)
assert_equal link3_result, autolink(link3_raw)
assert_equal "{link: #{link3_result}}", autolink("{link: #{link3_raw}}")
link4_raw = 'http://en.wikipedia.org/wiki/Sprite_{computer_graphics}'
link4_result = generate_result(link4_raw)
assert_equal link4_result, autolink(link4_raw)
assert_equal "&lt;link: #{link4_result}&gt;", autolink("&lt;link: #{link4_raw}&gt;")
end
def test_autolink_parsing
urls = %w(
http://www.rubyonrails.com
http://www.rubyonrails.com:80
http://www.rubyonrails.com/~minam
https://www.rubyonrails.com/~minam
http://www.rubyonrails.com/~minam/url%20with%20spaces
http://www.rubyonrails.com/foo.cgi?something=here
http://www.rubyonrails.com/foo.cgi?something=here&and=here
http://www.rubyonrails.com/contact;new
http://www.rubyonrails.com/contact;new%20with%20spaces
http://www.rubyonrails.com/contact;new?with=query&string=params
http://www.rubyonrails.com/~minam/contact;new?with=query&string=params
http://en.wikipedia.org/wiki/Wikipedia:Today%27s_featured_picture_%28animation%29/January_20%2C_2007
http://www.mail-archive.com/rails@lists.rubyonrails.org/
http://www.amazon.com/Testing-Equal-Sign-In-Path/ref=pd_bbs_sr_1?ie=UTF8&s=books&qid=1198861734&sr=8-1
http://en.wikipedia.org/wiki/Texas_hold'em
https://www.google.com/doku.php?id=gps:resource:scs:start
http://connect.oraclecorp.com/search?search[q]=green+france&search[type]=Group
http://of.openfoundry.org/projects/492/download#4th.Release.3
http://maps.google.co.uk/maps?f=q&q=the+london+eye&ie=UTF8&ll=51.503373,-0.11939&spn=0.007052,0.012767&z=16&iwloc=A
http://около.кола/колокола
https://123domain.com https://123.com https://123.domain.com https://www.123.domain.com
)
urls.each do |url|
assert_equal generate_result(url), autolink(url)
end
end
def test_auto_link_with_options_hash
assert_dom_equal(
'Welcome to my new blog at <a href="http://www.myblog.com/" class="menu" target="_blank">www.myblog.com/</a>.',
autolink(
"Welcome to my new blog at http://www.myblog.com/.",
{class: "menu", target: "_blank" }
)
)
end
def test_auto_link_with_multiple_trailing_punctuations
url = "http://youtube.com"
url_result = generate_result(url)
assert_equal url_result, autolink(url)
assert_equal "(link: #{url_result}).", autolink("(link: #{url}).")
end
def test_auto_link_with_yield
url = "http://api.rubyonrails.com/Foo.html"
assert_equal(
%(<p><a href="#{url}">xxxx</a></p>),
autolink("<p>#{url}</p>") { |_url| "xxxx" }
)
end
def test_auto_link_with_block_with_html
pic = "http://example.com/pic.png"
url = "http://example.com/album?a&b=c"
expected = %(My pic: <a href="#{pic}"><img src="#{pic}" width="160px"></a> -- full album here #{generate_result(url,nil,false)})
actual = autolink("My pic: #{pic} -- full album here #{url}") {|link|
if link =~ /\.(jpg|gif|png|bmp|tif)$/i
raw %(<img src="#{link}" width="160px">)
else
link
end
}
assert_equal expected, actual
end
def test_auto_link_already_linked
linked1 = generate_result('Ruby On Rails', 'http://www.rubyonrails.com')
linked2 = %('<a href="http://www.example.com">www.example.com</a>')
linked3 = %('<a href="http://www.example.com" rel="nofollow">www.example.com</a>')
linked4 = %('<a href="http://www.example.com"><b>www.example.com</b></a>')
linked5 = %('<a href="#close">close</a> <a href="http://www.example.com"><b>www.example.com</b></a>')
assert_equal linked1, autolink(linked1)
assert_equal linked2, autolink(linked2)
assert_equal linked3, autolink(linked3)
assert_equal linked4, autolink(linked4)
assert_equal linked5, autolink(linked5)
end
def test_auto_link_with_malicious_attr
url1 = "http://api.rubyonrails.com/Foo.html"
malicious = "\"onmousemove=\"prompt()"
combination = "#{url1}#{malicious}"
assert_equal %(<p><a href="#{url1}">#{url1[7..-1]}</a>#{malicious}</p>), autolink("<p>#{combination}</p>")
end
def test_auto_link_at_eol
url1 = "http://api.rubyonrails.com/Foo.html"
url2 = "http://www.ruby-doc.org/core/Bar.html"
assert_equal %(<p><a href="#{url1}">#{url1[7..-1]}</a><br><a href="#{url2}">#{url2[7..-1]}</a><br></p>), autolink("<p>#{url1}<br>#{url2}<br></p>")
end
def test_autolink_with_trailing_equals_on_link
url = "http://www.rubyonrails.com/foo.cgi?trailing_equals="
assert_equal generate_result(url), autolink(url)
end
def test_autolink_with_trailing_amp_on_link
url = "http://www.rubyonrails.com/foo.cgi?trailing_ampersand=value&"
assert_equal generate_result(url.sub('&','')) + '&amp;', autolink(url)
end
def test_autolink_with_trailing_colon_on_link
url = "http://www.rubyonrails.com/foo.cgi?trailing_colon=value:"
expected_url = "http://www.rubyonrails.com/foo.cgi?trailing_colon=value"
assert_equal "#{generate_result(expected_url)}:", autolink(url)
end
def test_autolink_with_trailing_hyphen_on_link
url = "http://www.rubyonrails.com/foo.cgi?trailing_hyphen=value-"
assert_equal generate_result(url), autolink(url)
end
def test_autolink_with_trailing_forward_slash_on_link
url = "http://www.rubyonrails.com/foo.cgi?trailing_forward_slash=value/"
assert_equal generate_result(url), autolink(url)
end
def test_autolink_with_trailing_number_on_link
url = "http://www.rubyonrails.com/foo.cgi?trailing_number=value3"
assert_equal generate_result(url), autolink(url)
end
private
def generate_result(link_text, href = nil, remove_scheme = true)
text = sanitize(link_text)
href = sanitize(href) || text
text = text.sub(/https?:\/\//,'') if remove_scheme
%{<a href="#{href}">#{text}</a>}.gsub("&#39;", "'") # ActionView does not escape '
end
end
2.5.0
\ No newline at end of file
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 0) do
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment