instiki 0.10.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|