instiki 0.10.0 → 0.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +174 -165
- data/README +68 -68
- data/app/controllers/admin_controller.rb +94 -94
- data/app/controllers/application.rb +135 -131
- data/app/controllers/file_controller.rb +129 -129
- data/app/controllers/wiki_controller.rb +354 -354
- data/app/helpers/application_helper.rb +68 -68
- data/app/models/author.rb +3 -3
- data/app/models/chunks/category.rb +33 -33
- data/app/models/chunks/chunk.rb +86 -86
- data/app/models/chunks/engines.rb +61 -54
- data/app/models/chunks/include.rb +41 -41
- data/app/models/chunks/literal.rb +31 -31
- data/app/models/chunks/nowiki.rb +28 -28
- data/app/models/chunks/test.rb +18 -18
- data/app/models/chunks/uri.rb +182 -182
- data/app/models/chunks/wiki.rb +141 -141
- data/app/models/file_yard.rb +58 -58
- data/app/models/page.rb +112 -112
- data/app/models/page_lock.rb +22 -22
- data/app/models/page_set.rb +89 -89
- data/app/models/revision.rb +123 -123
- data/app/models/web.rb +182 -176
- data/app/models/wiki_content.rb +207 -207
- data/app/models/wiki_service.rb +233 -233
- data/app/models/wiki_words.rb +23 -23
- data/app/views/admin/create_system.rhtml +83 -83
- data/app/views/admin/create_web.rhtml +69 -69
- data/app/views/admin/edit_web.rhtml +137 -136
- data/app/views/file/file.rhtml +18 -18
- data/app/views/file/import.rhtml +22 -22
- data/app/views/layouts/default.rhtml +86 -85
- data/app/views/markdown_help.rhtml +12 -12
- data/app/views/mixed_help.rhtml +6 -6
- data/app/views/navigation.rhtml +30 -30
- data/app/views/rdoc_help.rhtml +12 -12
- data/app/views/textile_help.rhtml +24 -24
- data/app/views/wiki/authors.rhtml +11 -11
- data/app/views/wiki/edit.rhtml +39 -39
- data/app/views/wiki/export.rhtml +12 -12
- data/app/views/wiki/feeds.rhtml +14 -14
- data/app/views/wiki/list.rhtml +64 -64
- data/app/views/wiki/locked.rhtml +23 -23
- data/app/views/wiki/login.rhtml +14 -14
- data/app/views/wiki/new.rhtml +31 -31
- data/app/views/wiki/page.rhtml +115 -115
- data/app/views/wiki/print.rhtml +14 -14
- data/app/views/wiki/published.rhtml +9 -9
- data/app/views/wiki/recently_revised.rhtml +26 -26
- data/app/views/wiki/revision.rhtml +103 -103
- data/app/views/wiki/rollback.rhtml +36 -36
- data/app/views/wiki/rss_feed.rhtml +22 -22
- data/app/views/wiki/search.rhtml +38 -38
- data/app/views/wiki/tex.rhtml +22 -22
- data/app/views/wiki/tex_web.rhtml +34 -34
- data/app/views/wiki/web_list.rhtml +18 -18
- data/app/views/wiki_words_help.rhtml +9 -9
- data/config/environment.rb +82 -82
- data/config/environments/development.rb +5 -5
- data/config/environments/production.rb +4 -4
- data/config/environments/test.rb +17 -17
- data/config/routes.rb +18 -18
- data/lib/active_record_stub.rb +31 -31
- data/lib/bluecloth_tweaked.rb +1127 -0
- data/lib/diff.rb +444 -444
- data/lib/instiki_errors.rb +14 -14
- data/lib/rdocsupport.rb +151 -151
- data/lib/redcloth_for_tex.rb +736 -736
- data/natives/osx/desktop_launcher/AppDelegate.h +18 -18
- data/natives/osx/desktop_launcher/AppDelegate.mm +109 -109
- data/natives/osx/desktop_launcher/Credits.html +15 -15
- data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/classes.nib +12 -12
- data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/info.nib +24 -24
- data/natives/osx/desktop_launcher/Info.plist +12 -12
- data/natives/osx/desktop_launcher/Instiki.xcode/project.pbxproj +592 -592
- data/natives/osx/desktop_launcher/Instiki_Prefix.pch +7 -7
- data/natives/osx/desktop_launcher/MakeDMG.sh +9 -9
- data/natives/osx/desktop_launcher/main.mm +14 -14
- data/natives/osx/desktop_launcher/version.plist +16 -16
- data/public/404.html +5 -5
- data/public/500.html +5 -5
- data/public/dispatch.rb +9 -9
- data/public/javascripts/edit_web.js +52 -52
- data/public/javascripts/prototype.js +336 -336
- data/public/stylesheets/instiki.css +222 -222
- data/script/breakpointer +4 -4
- data/script/server +93 -93
- metadata +4 -3
@@ -1,41 +1,41 @@
|
|
1
|
-
require 'chunks/wiki'
|
2
|
-
|
3
|
-
# Includes the contents of another page for rendering.
|
4
|
-
# The include command looks like this: "[[!include PageName]]".
|
5
|
-
# It is a WikiReference since it refers to another page (PageName)
|
6
|
-
# and the wiki content using this command must be notified
|
7
|
-
# of changes to that page.
|
8
|
-
# If the included page could not be found, a warning is displayed.
|
9
|
-
|
10
|
-
class Include < WikiChunk::WikiReference
|
11
|
-
|
12
|
-
INCLUDE_PATTERN = /\[\[!include(.*)\]\]\s*/i
|
13
|
-
def self.pattern() INCLUDE_PATTERN end
|
14
|
-
|
15
|
-
|
16
|
-
def initialize(match_data, content)
|
17
|
-
super
|
18
|
-
@page_name = match_data[1].strip
|
19
|
-
@unmask_text = get_unmask_text_avoiding_recursion_loops
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def get_unmask_text_avoiding_recursion_loops
|
25
|
-
if refpage then
|
26
|
-
if refpage.wiki_includes.include?(@content.page_name)
|
27
|
-
# this will break the recursion
|
28
|
-
@content.delete_chunk(self)
|
29
|
-
refpage.clear_display_cache
|
30
|
-
return "<em>Recursive include detected; #{@page_name} --> #{@content.page_name} " +
|
31
|
-
"--> #{@page_name}</em>\n"
|
32
|
-
else
|
33
|
-
@content.merge_chunks(refpage.display_content)
|
34
|
-
return refpage.display_content.pre_rendered
|
35
|
-
end
|
36
|
-
else
|
37
|
-
return "<em>Could not include #{@page_name}</em>\n"
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
1
|
+
require 'chunks/wiki'
|
2
|
+
|
3
|
+
# Includes the contents of another page for rendering.
|
4
|
+
# The include command looks like this: "[[!include PageName]]".
|
5
|
+
# It is a WikiReference since it refers to another page (PageName)
|
6
|
+
# and the wiki content using this command must be notified
|
7
|
+
# of changes to that page.
|
8
|
+
# If the included page could not be found, a warning is displayed.
|
9
|
+
|
10
|
+
class Include < WikiChunk::WikiReference
|
11
|
+
|
12
|
+
INCLUDE_PATTERN = /\[\[!include(.*)\]\]\s*/i
|
13
|
+
def self.pattern() INCLUDE_PATTERN end
|
14
|
+
|
15
|
+
|
16
|
+
def initialize(match_data, content)
|
17
|
+
super
|
18
|
+
@page_name = match_data[1].strip
|
19
|
+
@unmask_text = get_unmask_text_avoiding_recursion_loops
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def get_unmask_text_avoiding_recursion_loops
|
25
|
+
if refpage then
|
26
|
+
if refpage.wiki_includes.include?(@content.page_name)
|
27
|
+
# this will break the recursion
|
28
|
+
@content.delete_chunk(self)
|
29
|
+
refpage.clear_display_cache
|
30
|
+
return "<em>Recursive include detected; #{@page_name} --> #{@content.page_name} " +
|
31
|
+
"--> #{@page_name}</em>\n"
|
32
|
+
else
|
33
|
+
@content.merge_chunks(refpage.display_content)
|
34
|
+
return refpage.display_content.pre_rendered
|
35
|
+
end
|
36
|
+
else
|
37
|
+
return "<em>Could not include #{@page_name}</em>\n"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
@@ -1,31 +1,31 @@
|
|
1
|
-
require 'chunks/chunk'
|
2
|
-
|
3
|
-
# These are basic chunks that have a pattern and can be protected.
|
4
|
-
# They are used by rendering process to prevent wiki rendering
|
5
|
-
# occuring within literal areas such as <code> and <pre> blocks
|
6
|
-
# and within HTML tags.
|
7
|
-
module Literal
|
8
|
-
|
9
|
-
class AbstractLiteral < Chunk::Abstract
|
10
|
-
|
11
|
-
def initialize(match_data, content)
|
12
|
-
super
|
13
|
-
@unmask_text = @text
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
# A literal chunk that protects 'code' and 'pre' tags from wiki rendering.
|
19
|
-
class Pre < AbstractLiteral
|
20
|
-
PRE_BLOCKS = "a|pre|code"
|
21
|
-
PRE_PATTERN = Regexp.new('<('+PRE_BLOCKS+')\b[^>]*?>.*?</\1>', Regexp::MULTILINE)
|
22
|
-
def self.pattern() PRE_PATTERN end
|
23
|
-
end
|
24
|
-
|
25
|
-
# A literal chunk that protects HTML tags from wiki rendering.
|
26
|
-
class Tags < AbstractLiteral
|
27
|
-
TAGS = "a|img|em|strong|div|span|table|td|th|ul|ol|li|dl|dt|dd"
|
28
|
-
TAGS_PATTERN = Regexp.new('<(?:'+TAGS+')[^>]*?>', Regexp::MULTILINE)
|
29
|
-
def self.pattern() TAGS_PATTERN end
|
30
|
-
end
|
31
|
-
end
|
1
|
+
require 'chunks/chunk'
|
2
|
+
|
3
|
+
# These are basic chunks that have a pattern and can be protected.
|
4
|
+
# They are used by rendering process to prevent wiki rendering
|
5
|
+
# occuring within literal areas such as <code> and <pre> blocks
|
6
|
+
# and within HTML tags.
|
7
|
+
module Literal
|
8
|
+
|
9
|
+
class AbstractLiteral < Chunk::Abstract
|
10
|
+
|
11
|
+
def initialize(match_data, content)
|
12
|
+
super
|
13
|
+
@unmask_text = @text
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
# A literal chunk that protects 'code' and 'pre' tags from wiki rendering.
|
19
|
+
class Pre < AbstractLiteral
|
20
|
+
PRE_BLOCKS = "a|pre|code"
|
21
|
+
PRE_PATTERN = Regexp.new('<('+PRE_BLOCKS+')\b[^>]*?>.*?</\1>', Regexp::MULTILINE)
|
22
|
+
def self.pattern() PRE_PATTERN end
|
23
|
+
end
|
24
|
+
|
25
|
+
# A literal chunk that protects HTML tags from wiki rendering.
|
26
|
+
class Tags < AbstractLiteral
|
27
|
+
TAGS = "a|img|em|strong|div|span|table|td|th|ul|ol|li|dl|dt|dd"
|
28
|
+
TAGS_PATTERN = Regexp.new('<(?:'+TAGS+')[^>]*?>', Regexp::MULTILINE)
|
29
|
+
def self.pattern() TAGS_PATTERN end
|
30
|
+
end
|
31
|
+
end
|
data/app/models/chunks/nowiki.rb
CHANGED
@@ -1,28 +1,28 @@
|
|
1
|
-
require 'chunks/chunk'
|
2
|
-
|
3
|
-
# This chunks allows certain parts of a wiki page to be hidden from the
|
4
|
-
# rest of the rendering pipeline. It should be run at the beginning
|
5
|
-
# of the pipeline in `wiki_content.rb`.
|
6
|
-
#
|
7
|
-
# An example use of this chunk is to markup double brackets or
|
8
|
-
# auto URI links:
|
9
|
-
# <nowiki>Here are [[double brackets]] and a URI: www.uri.org</nowiki>
|
10
|
-
#
|
11
|
-
# The contents of the chunks will not be processed by any other chunk
|
12
|
-
# so the `www.uri.org` and the double brackets will appear verbatim.
|
13
|
-
#
|
14
|
-
# Author: Mark Reid <mark at threewordslong dot com>
|
15
|
-
# Created: 8th June 2004
|
16
|
-
class NoWiki < Chunk::Abstract
|
17
|
-
|
18
|
-
NOWIKI_PATTERN = Regexp.new('<nowiki>(.*?)</nowiki>')
|
19
|
-
def self.pattern() NOWIKI_PATTERN end
|
20
|
-
|
21
|
-
attr_reader :plain_text
|
22
|
-
|
23
|
-
def initialize(match_data, content)
|
24
|
-
super
|
25
|
-
@plain_text = @unmask_text = match_data[1]
|
26
|
-
end
|
27
|
-
|
28
|
-
end
|
1
|
+
require 'chunks/chunk'
|
2
|
+
|
3
|
+
# This chunks allows certain parts of a wiki page to be hidden from the
|
4
|
+
# rest of the rendering pipeline. It should be run at the beginning
|
5
|
+
# of the pipeline in `wiki_content.rb`.
|
6
|
+
#
|
7
|
+
# An example use of this chunk is to markup double brackets or
|
8
|
+
# auto URI links:
|
9
|
+
# <nowiki>Here are [[double brackets]] and a URI: www.uri.org</nowiki>
|
10
|
+
#
|
11
|
+
# The contents of the chunks will not be processed by any other chunk
|
12
|
+
# so the `www.uri.org` and the double brackets will appear verbatim.
|
13
|
+
#
|
14
|
+
# Author: Mark Reid <mark at threewordslong dot com>
|
15
|
+
# Created: 8th June 2004
|
16
|
+
class NoWiki < Chunk::Abstract
|
17
|
+
|
18
|
+
NOWIKI_PATTERN = Regexp.new('<nowiki>(.*?)</nowiki>')
|
19
|
+
def self.pattern() NOWIKI_PATTERN end
|
20
|
+
|
21
|
+
attr_reader :plain_text
|
22
|
+
|
23
|
+
def initialize(match_data, content)
|
24
|
+
super
|
25
|
+
@plain_text = @unmask_text = match_data[1]
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
data/app/models/chunks/test.rb
CHANGED
@@ -1,18 +1,18 @@
|
|
1
|
-
require 'test/unit'
|
2
|
-
|
3
|
-
class ChunkTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
# Asserts a number of tests for the given type and text.
|
6
|
-
def match(type, test_text, expected)
|
7
|
-
pattern = type.pattern
|
8
|
-
assert_match(pattern, test_text)
|
9
|
-
pattern =~ test_text # Previous assertion guarantees match
|
10
|
-
chunk = type.new($~)
|
11
|
-
|
12
|
-
# Test if requested parts are correct.
|
13
|
-
for method_sym, value in expected do
|
14
|
-
assert_respond_to(chunk, method_sym)
|
15
|
-
assert_equal(value, chunk.method(method_sym).call, "Checking value of '#{method_sym}'")
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
1
|
+
require 'test/unit'
|
2
|
+
|
3
|
+
class ChunkTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
# Asserts a number of tests for the given type and text.
|
6
|
+
def match(type, test_text, expected)
|
7
|
+
pattern = type.pattern
|
8
|
+
assert_match(pattern, test_text)
|
9
|
+
pattern =~ test_text # Previous assertion guarantees match
|
10
|
+
chunk = type.new($~)
|
11
|
+
|
12
|
+
# Test if requested parts are correct.
|
13
|
+
for method_sym, value in expected do
|
14
|
+
assert_respond_to(chunk, method_sym)
|
15
|
+
assert_equal(value, chunk.method(method_sym).call, "Checking value of '#{method_sym}'")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/app/models/chunks/uri.rb
CHANGED
@@ -1,182 +1,182 @@
|
|
1
|
-
require 'chunks/chunk'
|
2
|
-
|
3
|
-
# This wiki chunk matches arbitrary URIs, using patterns from the Ruby URI modules.
|
4
|
-
# It parses out a variety of fields that could be used by renderers to format
|
5
|
-
# the links in various ways (shortening domain names, hiding email addresses)
|
6
|
-
# It matches email addresses and host.com.au domains without schemes (http://)
|
7
|
-
# but adds these on as required.
|
8
|
-
#
|
9
|
-
# The heuristic used to match a URI is designed to err on the side of caution.
|
10
|
-
# That is, it is more likely to not autolink a URI than it is to accidently
|
11
|
-
# autolink something that is not a URI. The reason behind this is it is easier
|
12
|
-
# to force a URI link by prefixing 'http://' to it than it is to escape and
|
13
|
-
# incorrectly marked up non-URI.
|
14
|
-
#
|
15
|
-
# I'm using a part of the [ISO 3166-1 Standard][iso3166] for country name suffixes.
|
16
|
-
# The generic names are from www.bnoack.com/data/countrycode2.html)
|
17
|
-
# [iso3166]: http://geotags.com/iso3166/
|
18
|
-
|
19
|
-
class URIChunk < Chunk::Abstract
|
20
|
-
include URI::REGEXP::PATTERN
|
21
|
-
|
22
|
-
# this condition is to get rid of pesky warnings in tests
|
23
|
-
unless defined? URIChunk::INTERNET_URI_REGEXP
|
24
|
-
|
25
|
-
GENERIC = 'aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org'
|
26
|
-
|
27
|
-
COUNTRY = 'ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|' +
|
28
|
-
'bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cf|cd|cg|ch|ci|ck|cl|' +
|
29
|
-
'cm|cn|co|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|fi|' +
|
30
|
-
'fj|fk|fm|fo|fr|fx|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|' +
|
31
|
-
'hk|hm|hn|hr|ht|hu|id|ie|il|in|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|' +
|
32
|
-
'kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|' +
|
33
|
-
'mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nt|' +
|
34
|
-
'nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|' +
|
35
|
-
'sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|' +
|
36
|
-
'tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|' +
|
37
|
-
'ws|ye|yt|yu|za|zm|zr|zw'
|
38
|
-
# These are needed otherwise HOST will match almost anything
|
39
|
-
TLDS = "(?:#{GENERIC}|#{COUNTRY})"
|
40
|
-
|
41
|
-
# Redefine USERINFO so that it must have non-zero length
|
42
|
-
USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})+"
|
43
|
-
|
44
|
-
# unreserved_no_ending = alphanum | mark, but URI_ENDING [)!] excluded
|
45
|
-
UNRESERVED_NO_ENDING = "-_.~*'(#{ALNUM}"
|
46
|
-
|
47
|
-
# this ensures that query or fragment do not end with URI_ENDING
|
48
|
-
# and enable us to use a much simpler self.pattern Regexp
|
49
|
-
|
50
|
-
# uric_no_ending = reserved | unreserved_no_ending | escaped
|
51
|
-
URIC_NO_ENDING = "(?:[#{UNRESERVED_NO_ENDING}#{RESERVED}]|#{ESCAPED})"
|
52
|
-
# query = *uric
|
53
|
-
QUERY = "#{URIC_NO_ENDING}*"
|
54
|
-
# fragment = *uric
|
55
|
-
FRAGMENT = "#{URIC_NO_ENDING}*"
|
56
|
-
|
57
|
-
# DOMLABEL is defined in the ruby uri library, TLDS is defined above
|
58
|
-
INTERNET_HOSTNAME = "(?:#{DOMLABEL}\\.)+#{TLDS}"
|
59
|
-
|
60
|
-
# Correct a typo bug in ruby 1.8.x lib/uri/common.rb
|
61
|
-
PORT = '\\d*'
|
62
|
-
|
63
|
-
INTERNET_URI =
|
64
|
-
"(?:(#{SCHEME}):/{0,2})?" + # Optional scheme: (\1)
|
65
|
-
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
|
66
|
-
"(#{INTERNET_HOSTNAME})" + # Mandatory hostname (\3)
|
67
|
-
"(?::(#{PORT}))?" + # Optional :port (\4)
|
68
|
-
"(#{ABS_PATH})?" + # Optional absolute path (\5)
|
69
|
-
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
|
70
|
-
"(?:\\#(#{FRAGMENT}))?" + # Optional #fragment (\7)
|
71
|
-
'(?=\.?(?:\s|\)|\z))' # ends only with optional dot + space or ")"
|
72
|
-
# or end of the string
|
73
|
-
|
74
|
-
SUSPICIOUS_PRECEDING_CHARACTER = '(!|\"\:|\"|\\\')?' # any of !, ":, ", '
|
75
|
-
|
76
|
-
INTERNET_URI_REGEXP =
|
77
|
-
Regexp.new(SUSPICIOUS_PRECEDING_CHARACTER + INTERNET_URI, Regexp::EXTENDED, 'N')
|
78
|
-
|
79
|
-
end
|
80
|
-
|
81
|
-
def URIChunk.pattern
|
82
|
-
INTERNET_URI_REGEXP
|
83
|
-
end
|
84
|
-
|
85
|
-
attr_reader :user, :host, :port, :path, :query, :fragment, :link_text
|
86
|
-
|
87
|
-
def self.apply_to(content)
|
88
|
-
content.gsub!( self.pattern ) do |matched_text|
|
89
|
-
chunk = self.new($~, content)
|
90
|
-
if chunk.avoid_autolinking?
|
91
|
-
# do not substitute nor register the chunk
|
92
|
-
matched_text
|
93
|
-
else
|
94
|
-
content.add_chunk(chunk)
|
95
|
-
chunk.mask
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
def initialize(match_data, content)
|
101
|
-
super
|
102
|
-
@link_text = match_data[0]
|
103
|
-
@suspicious_preceding_character = match_data[1]
|
104
|
-
@original_scheme, @user, @host, @port, @path, @query, @fragment = match_data[2..-1]
|
105
|
-
treat_trailing_character
|
106
|
-
@unmask_text = "<a href=\"#{uri}\">#{link_text}</a>"
|
107
|
-
end
|
108
|
-
|
109
|
-
def avoid_autolinking?
|
110
|
-
not @suspicious_preceding_character.nil?
|
111
|
-
end
|
112
|
-
|
113
|
-
def treat_trailing_character
|
114
|
-
# If the last character matched by URI pattern is in ! or ), this may be part of the markup,
|
115
|
-
# not a URL. We should handle it as such. It is possible to do it by a regexp, but
|
116
|
-
# much easier to do programmatically
|
117
|
-
last_char = @link_text[-1..-1]
|
118
|
-
if last_char == ')' or last_char == '!'
|
119
|
-
@trailing_punctuation = last_char
|
120
|
-
@link_text.chop!
|
121
|
-
[@original_scheme, @user, @host, @port, @path, @query, @fragment].compact.last.chop!
|
122
|
-
else
|
123
|
-
@trailing_punctuation = nil
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
def scheme
|
128
|
-
@original_scheme or (@user ? 'mailto' : 'http')
|
129
|
-
end
|
130
|
-
|
131
|
-
def scheme_delimiter
|
132
|
-
scheme == 'mailto' ? ':' : '://'
|
133
|
-
end
|
134
|
-
|
135
|
-
def user_delimiter
|
136
|
-
'@' unless @user.nil?
|
137
|
-
end
|
138
|
-
|
139
|
-
def port_delimiter
|
140
|
-
':' unless @port.nil?
|
141
|
-
end
|
142
|
-
|
143
|
-
def query_delimiter
|
144
|
-
'?' unless @query.nil?
|
145
|
-
end
|
146
|
-
|
147
|
-
def uri
|
148
|
-
[scheme, scheme_delimiter, user, user_delimiter, host, port_delimiter, port, path,
|
149
|
-
query_delimiter, query].compact.join
|
150
|
-
end
|
151
|
-
|
152
|
-
end
|
153
|
-
|
154
|
-
# uri with mandatory scheme but less restrictive hostname, like
|
155
|
-
# http://localhost:2500/blah.html
|
156
|
-
class LocalURIChunk < URIChunk
|
157
|
-
|
158
|
-
unless defined? LocalURIChunk::LOCAL_URI_REGEXP
|
159
|
-
# hostname can be just a simple word like 'localhost'
|
160
|
-
ANY_HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
|
161
|
-
|
162
|
-
# The basic URI expression as a string
|
163
|
-
# Scheme and hostname are mandatory
|
164
|
-
LOCAL_URI =
|
165
|
-
"(?:(#{SCHEME})://)+" + # Mandatory scheme:// (\1)
|
166
|
-
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
|
167
|
-
"(#{ANY_HOSTNAME})" + # Mandatory hostname (\3)
|
168
|
-
"(?::(#{PORT}))?" + # Optional :port (\4)
|
169
|
-
"(#{ABS_PATH})?" + # Optional absolute path (\5)
|
170
|
-
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
|
171
|
-
"(?:\\#(#{FRAGMENT}))?" + # Optional #fragment (\7)
|
172
|
-
'(?=\.?(?:\s|\)|\z))' # ends only with optional dot + space or ")"
|
173
|
-
# or end of the string
|
174
|
-
|
175
|
-
LOCAL_URI_REGEXP = Regexp.new(SUSPICIOUS_PRECEDING_CHARACTER + LOCAL_URI, Regexp::EXTENDED, 'N')
|
176
|
-
end
|
177
|
-
|
178
|
-
def LocalURIChunk.pattern
|
179
|
-
LOCAL_URI_REGEXP
|
180
|
-
end
|
181
|
-
|
182
|
-
end
|
1
|
+
require 'chunks/chunk'
|
2
|
+
|
3
|
+
# This wiki chunk matches arbitrary URIs, using patterns from the Ruby URI modules.
|
4
|
+
# It parses out a variety of fields that could be used by renderers to format
|
5
|
+
# the links in various ways (shortening domain names, hiding email addresses)
|
6
|
+
# It matches email addresses and host.com.au domains without schemes (http://)
|
7
|
+
# but adds these on as required.
|
8
|
+
#
|
9
|
+
# The heuristic used to match a URI is designed to err on the side of caution.
|
10
|
+
# That is, it is more likely to not autolink a URI than it is to accidently
|
11
|
+
# autolink something that is not a URI. The reason behind this is it is easier
|
12
|
+
# to force a URI link by prefixing 'http://' to it than it is to escape and
|
13
|
+
# incorrectly marked up non-URI.
|
14
|
+
#
|
15
|
+
# I'm using a part of the [ISO 3166-1 Standard][iso3166] for country name suffixes.
|
16
|
+
# The generic names are from www.bnoack.com/data/countrycode2.html)
|
17
|
+
# [iso3166]: http://geotags.com/iso3166/
|
18
|
+
|
19
|
+
class URIChunk < Chunk::Abstract
|
20
|
+
include URI::REGEXP::PATTERN
|
21
|
+
|
22
|
+
# this condition is to get rid of pesky warnings in tests
|
23
|
+
unless defined? URIChunk::INTERNET_URI_REGEXP
|
24
|
+
|
25
|
+
GENERIC = 'aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org'
|
26
|
+
|
27
|
+
COUNTRY = 'ad|ae|af|ag|ai|al|am|an|ao|aq|ar|as|at|au|aw|az|ba|bb|bd|be|' +
|
28
|
+
'bf|bg|bh|bi|bj|bm|bn|bo|br|bs|bt|bv|bw|by|bz|ca|cc|cf|cd|cg|ch|ci|ck|cl|' +
|
29
|
+
'cm|cn|co|cr|cs|cu|cv|cx|cy|cz|de|dj|dk|dm|do|dz|ec|ee|eg|eh|er|es|et|fi|' +
|
30
|
+
'fj|fk|fm|fo|fr|fx|ga|gb|gd|ge|gf|gh|gi|gl|gm|gn|gp|gq|gr|gs|gt|gu|gw|gy|' +
|
31
|
+
'hk|hm|hn|hr|ht|hu|id|ie|il|in|io|iq|ir|is|it|jm|jo|jp|ke|kg|kh|ki|km|kn|' +
|
32
|
+
'kp|kr|kw|ky|kz|la|lb|lc|li|lk|lr|ls|lt|lu|lv|ly|ma|mc|md|mg|mh|mk|ml|mm|' +
|
33
|
+
'mn|mo|mp|mq|mr|ms|mt|mu|mv|mw|mx|my|mz|na|nc|ne|nf|ng|ni|nl|no|np|nr|nt|' +
|
34
|
+
'nu|nz|om|pa|pe|pf|pg|ph|pk|pl|pm|pn|pr|pt|pw|py|qa|re|ro|ru|rw|sa|sb|sc|' +
|
35
|
+
'sd|se|sg|sh|si|sj|sk|sl|sm|sn|so|sr|st|su|sv|sy|sz|tc|td|tf|tg|th|tj|tk|' +
|
36
|
+
'tm|tn|to|tp|tr|tt|tv|tw|tz|ua|ug|uk|um|us|uy|uz|va|vc|ve|vg|vi|vn|vu|wf|' +
|
37
|
+
'ws|ye|yt|yu|za|zm|zr|zw'
|
38
|
+
# These are needed otherwise HOST will match almost anything
|
39
|
+
TLDS = "(?:#{GENERIC}|#{COUNTRY})"
|
40
|
+
|
41
|
+
# Redefine USERINFO so that it must have non-zero length
|
42
|
+
USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})+"
|
43
|
+
|
44
|
+
# unreserved_no_ending = alphanum | mark, but URI_ENDING [)!] excluded
|
45
|
+
UNRESERVED_NO_ENDING = "-_.~*'(#{ALNUM}"
|
46
|
+
|
47
|
+
# this ensures that query or fragment do not end with URI_ENDING
|
48
|
+
# and enable us to use a much simpler self.pattern Regexp
|
49
|
+
|
50
|
+
# uric_no_ending = reserved | unreserved_no_ending | escaped
|
51
|
+
URIC_NO_ENDING = "(?:[#{UNRESERVED_NO_ENDING}#{RESERVED}]|#{ESCAPED})"
|
52
|
+
# query = *uric
|
53
|
+
QUERY = "#{URIC_NO_ENDING}*"
|
54
|
+
# fragment = *uric
|
55
|
+
FRAGMENT = "#{URIC_NO_ENDING}*"
|
56
|
+
|
57
|
+
# DOMLABEL is defined in the ruby uri library, TLDS is defined above
|
58
|
+
INTERNET_HOSTNAME = "(?:#{DOMLABEL}\\.)+#{TLDS}"
|
59
|
+
|
60
|
+
# Correct a typo bug in ruby 1.8.x lib/uri/common.rb
|
61
|
+
PORT = '\\d*'
|
62
|
+
|
63
|
+
INTERNET_URI =
|
64
|
+
"(?:(#{SCHEME}):/{0,2})?" + # Optional scheme: (\1)
|
65
|
+
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
|
66
|
+
"(#{INTERNET_HOSTNAME})" + # Mandatory hostname (\3)
|
67
|
+
"(?::(#{PORT}))?" + # Optional :port (\4)
|
68
|
+
"(#{ABS_PATH})?" + # Optional absolute path (\5)
|
69
|
+
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
|
70
|
+
"(?:\\#(#{FRAGMENT}))?" + # Optional #fragment (\7)
|
71
|
+
'(?=\.?(?:\s|\)|\z))' # ends only with optional dot + space or ")"
|
72
|
+
# or end of the string
|
73
|
+
|
74
|
+
SUSPICIOUS_PRECEDING_CHARACTER = '(!|\"\:|\"|\\\')?' # any of !, ":, ", '
|
75
|
+
|
76
|
+
INTERNET_URI_REGEXP =
|
77
|
+
Regexp.new(SUSPICIOUS_PRECEDING_CHARACTER + INTERNET_URI, Regexp::EXTENDED, 'N')
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
def URIChunk.pattern
|
82
|
+
INTERNET_URI_REGEXP
|
83
|
+
end
|
84
|
+
|
85
|
+
attr_reader :user, :host, :port, :path, :query, :fragment, :link_text
|
86
|
+
|
87
|
+
def self.apply_to(content)
|
88
|
+
content.gsub!( self.pattern ) do |matched_text|
|
89
|
+
chunk = self.new($~, content)
|
90
|
+
if chunk.avoid_autolinking?
|
91
|
+
# do not substitute nor register the chunk
|
92
|
+
matched_text
|
93
|
+
else
|
94
|
+
content.add_chunk(chunk)
|
95
|
+
chunk.mask
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def initialize(match_data, content)
|
101
|
+
super
|
102
|
+
@link_text = match_data[0]
|
103
|
+
@suspicious_preceding_character = match_data[1]
|
104
|
+
@original_scheme, @user, @host, @port, @path, @query, @fragment = match_data[2..-1]
|
105
|
+
treat_trailing_character
|
106
|
+
@unmask_text = "<a href=\"#{uri}\">#{link_text}</a>"
|
107
|
+
end
|
108
|
+
|
109
|
+
def avoid_autolinking?
|
110
|
+
not @suspicious_preceding_character.nil?
|
111
|
+
end
|
112
|
+
|
113
|
+
def treat_trailing_character
|
114
|
+
# If the last character matched by URI pattern is in ! or ), this may be part of the markup,
|
115
|
+
# not a URL. We should handle it as such. It is possible to do it by a regexp, but
|
116
|
+
# much easier to do programmatically
|
117
|
+
last_char = @link_text[-1..-1]
|
118
|
+
if last_char == ')' or last_char == '!'
|
119
|
+
@trailing_punctuation = last_char
|
120
|
+
@link_text.chop!
|
121
|
+
[@original_scheme, @user, @host, @port, @path, @query, @fragment].compact.last.chop!
|
122
|
+
else
|
123
|
+
@trailing_punctuation = nil
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def scheme
|
128
|
+
@original_scheme or (@user ? 'mailto' : 'http')
|
129
|
+
end
|
130
|
+
|
131
|
+
def scheme_delimiter
|
132
|
+
scheme == 'mailto' ? ':' : '://'
|
133
|
+
end
|
134
|
+
|
135
|
+
def user_delimiter
|
136
|
+
'@' unless @user.nil?
|
137
|
+
end
|
138
|
+
|
139
|
+
def port_delimiter
|
140
|
+
':' unless @port.nil?
|
141
|
+
end
|
142
|
+
|
143
|
+
def query_delimiter
|
144
|
+
'?' unless @query.nil?
|
145
|
+
end
|
146
|
+
|
147
|
+
def uri
|
148
|
+
[scheme, scheme_delimiter, user, user_delimiter, host, port_delimiter, port, path,
|
149
|
+
query_delimiter, query].compact.join
|
150
|
+
end
|
151
|
+
|
152
|
+
end
|
153
|
+
|
154
|
+
# uri with mandatory scheme but less restrictive hostname, like
|
155
|
+
# http://localhost:2500/blah.html
|
156
|
+
class LocalURIChunk < URIChunk
|
157
|
+
|
158
|
+
unless defined? LocalURIChunk::LOCAL_URI_REGEXP
|
159
|
+
# hostname can be just a simple word like 'localhost'
|
160
|
+
ANY_HOSTNAME = "(?:#{DOMLABEL}\\.)*#{TOPLABEL}\\.?"
|
161
|
+
|
162
|
+
# The basic URI expression as a string
|
163
|
+
# Scheme and hostname are mandatory
|
164
|
+
LOCAL_URI =
|
165
|
+
"(?:(#{SCHEME})://)+" + # Mandatory scheme:// (\1)
|
166
|
+
"(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2)
|
167
|
+
"(#{ANY_HOSTNAME})" + # Mandatory hostname (\3)
|
168
|
+
"(?::(#{PORT}))?" + # Optional :port (\4)
|
169
|
+
"(#{ABS_PATH})?" + # Optional absolute path (\5)
|
170
|
+
"(?:\\?(#{QUERY}))?" + # Optional ?query (\6)
|
171
|
+
"(?:\\#(#{FRAGMENT}))?" + # Optional #fragment (\7)
|
172
|
+
'(?=\.?(?:\s|\)|\z))' # ends only with optional dot + space or ")"
|
173
|
+
# or end of the string
|
174
|
+
|
175
|
+
LOCAL_URI_REGEXP = Regexp.new(SUSPICIOUS_PRECEDING_CHARACTER + LOCAL_URI, Regexp::EXTENDED, 'N')
|
176
|
+
end
|
177
|
+
|
178
|
+
def LocalURIChunk.pattern
|
179
|
+
LOCAL_URI_REGEXP
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|