instiki 0.9.2 → 0.10.0

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.
Files changed (102) hide show
  1. data/CHANGELOG +165 -0
  2. data/README +68 -172
  3. data/app/controllers/admin_controller.rb +94 -0
  4. data/app/controllers/application.rb +131 -0
  5. data/app/controllers/file_controller.rb +129 -0
  6. data/app/controllers/wiki_controller.rb +354 -0
  7. data/{libraries/view_helper.rb → app/helpers/application_helper.rb} +68 -33
  8. data/app/models/author.rb +3 -3
  9. data/app/models/chunks/category.rb +33 -31
  10. data/app/models/chunks/chunk.rb +86 -20
  11. data/app/models/chunks/engines.rb +54 -38
  12. data/app/models/chunks/include.rb +41 -29
  13. data/app/models/chunks/literal.rb +31 -19
  14. data/app/models/chunks/nowiki.rb +28 -31
  15. data/app/models/chunks/test.rb +18 -18
  16. data/app/models/chunks/uri.rb +182 -97
  17. data/app/models/chunks/wiki.rb +141 -82
  18. data/app/models/file_yard.rb +58 -0
  19. data/app/models/page.rb +112 -86
  20. data/app/models/page_lock.rb +22 -23
  21. data/app/models/page_set.rb +89 -64
  22. data/app/models/revision.rb +123 -90
  23. data/app/models/web.rb +176 -89
  24. data/app/models/wiki_content.rb +207 -105
  25. data/app/models/wiki_service.rb +233 -83
  26. data/app/models/wiki_words.rb +23 -25
  27. data/app/views/{wiki/new_system.rhtml → admin/create_system.rhtml} +83 -78
  28. data/app/views/{wiki/new_web.rhtml → admin/create_web.rhtml} +69 -64
  29. data/app/views/admin/edit_web.rhtml +136 -0
  30. data/app/views/file/file.rhtml +19 -0
  31. data/app/views/file/import.rhtml +23 -0
  32. data/app/views/layouts/default.rhtml +85 -0
  33. data/app/views/markdown_help.rhtml +12 -16
  34. data/app/views/mixed_help.rhtml +7 -0
  35. data/app/views/navigation.rhtml +30 -19
  36. data/app/views/rdoc_help.rhtml +12 -16
  37. data/app/views/textile_help.rhtml +24 -28
  38. data/app/views/wiki/authors.rhtml +11 -13
  39. data/app/views/wiki/edit.rhtml +39 -31
  40. data/app/views/wiki/export.rhtml +12 -14
  41. data/app/views/wiki/feeds.rhtml +14 -10
  42. data/app/views/wiki/list.rhtml +64 -57
  43. data/app/views/wiki/locked.rhtml +23 -14
  44. data/app/views/wiki/login.rhtml +14 -11
  45. data/app/views/wiki/new.rhtml +31 -27
  46. data/app/views/wiki/page.rhtml +115 -81
  47. data/app/views/wiki/print.rhtml +14 -16
  48. data/app/views/wiki/published.rhtml +9 -10
  49. data/app/views/wiki/recently_revised.rhtml +27 -30
  50. data/app/views/wiki/revision.rhtml +103 -81
  51. data/app/views/wiki/rollback.rhtml +14 -9
  52. data/app/views/wiki/rss_feed.rhtml +22 -22
  53. data/app/views/wiki/search.rhtml +38 -15
  54. data/app/views/wiki/tex.rhtml +22 -22
  55. data/app/views/wiki/tex_web.rhtml +34 -34
  56. data/app/views/wiki/web_list.rhtml +18 -13
  57. data/app/views/wiki_words_help.rhtml +9 -8
  58. data/config/environment.rb +82 -0
  59. data/config/environments/development.rb +5 -0
  60. data/config/environments/production.rb +4 -0
  61. data/config/environments/test.rb +17 -0
  62. data/config/routes.rb +18 -0
  63. data/instiki +6 -67
  64. data/instiki.rb +3 -0
  65. data/lib/active_record_stub.rb +31 -0
  66. data/{libraries/diff → lib}/diff.rb +444 -475
  67. data/lib/instiki_errors.rb +15 -0
  68. data/{libraries → lib}/rdocsupport.rb +151 -155
  69. data/lib/redcloth_for_tex.rb +736 -0
  70. data/natives/osx/desktop_launcher/AppDelegate.h +18 -0
  71. data/natives/osx/desktop_launcher/AppDelegate.mm +109 -0
  72. data/natives/osx/desktop_launcher/Credits.html +16 -0
  73. data/natives/osx/desktop_launcher/English.lproj/InfoPlist.strings +0 -0
  74. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/classes.nib +13 -0
  75. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/info.nib +24 -0
  76. data/natives/osx/desktop_launcher/English.lproj/MainMenu.nib/objects.nib +0 -0
  77. data/natives/osx/desktop_launcher/Info.plist +13 -0
  78. data/natives/osx/desktop_launcher/Instiki.xcode/project.pbxproj +592 -0
  79. data/natives/osx/desktop_launcher/Instiki_Prefix.pch +7 -0
  80. data/natives/osx/desktop_launcher/MakeDMG.sh +9 -0
  81. data/natives/osx/desktop_launcher/main.mm +14 -0
  82. data/natives/osx/desktop_launcher/version.plist +16 -0
  83. data/public/404.html +6 -0
  84. data/public/500.html +6 -0
  85. data/public/dispatch.rb +10 -0
  86. data/public/favicon.ico +0 -0
  87. data/public/javascripts/edit_web.js +52 -0
  88. data/public/javascripts/prototype.js +336 -0
  89. data/{app/views/static_style_sheet.rhtml → public/stylesheets/instiki.css} +221 -198
  90. data/script/breakpointer +4 -0
  91. data/script/server +93 -0
  92. metadata +59 -32
  93. data/app/controllers/wiki.rb +0 -389
  94. data/app/models/chunks/match.rb +0 -19
  95. data/app/views/bottom.rhtml +0 -4
  96. data/app/views/top.rhtml +0 -49
  97. data/app/views/wiki/edit_web.rhtml +0 -138
  98. data/libraries/action_controller_servlet.rb +0 -177
  99. data/libraries/erb.rb +0 -490
  100. data/libraries/madeleine_service.rb +0 -68
  101. data/libraries/redcloth_for_tex.rb +0 -869
  102. data/libraries/web_controller_server.rb +0 -81
@@ -1,31 +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
- def self.pattern() Regexp.new('<nowiki>(.*?)</nowiki>') end
19
-
20
- attr_reader :plain_text
21
-
22
- def initialize(match_data)
23
- super(match_data)
24
- @plain_text = match_data[1]
25
- end
26
-
27
- # The nowiki content is not unmasked. This means the chunk will be reverted
28
- # using the plain text.
29
- def unmask(content) nil end
30
- def revert(content) content.sub!( Regexp.new(mask(content)), plain_text ) end
31
- 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
@@ -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
@@ -1,97 +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
- class URIChunk < Chunk::Abstract
19
- include URI::REGEXP::PATTERN
20
-
21
- GENERIC = '(?:aero|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org)'
22
- COUNTRY = '(?:au|at|be|ca|ch|de|dk|fr|hk|in|ir|it|jp|nl|no|pt|ru|se|sw|tv|tw|uk|us)'
23
-
24
- # These are needed otherwise HOST will match almost anything
25
- TLDS = "\\.(?:#{GENERIC}|#{COUNTRY})"
26
-
27
- # Redefine USERINFO so that it must have non-zero length
28
- USERINFO = "(?:[#{UNRESERVED};:&=+$,]|#{ESCAPED})+"
29
-
30
- # Pattern of legal URI endings to stop interference with some Textile
31
- # markup. (Images: !URI!) and other punctuation eg, (http://wiki.com/)
32
- URI_ENDING = '[)!]'
33
-
34
- # The basic URI expression as a string
35
- URI_PATTERN =
36
- "(?:(#{SCHEME})://)?" + # Optional scheme:// (\1|\8)
37
- "(?:(#{USERINFO})@)?" + # Optional userinfo@ (\2|\9)
38
- "(#{HOSTNAME}#{TLDS})" + # Mandatory host eg, HOST.com.au (\3|\10)
39
- "(?::(#{PORT}))?" + # Optional :port (\4|\11)
40
- "(#{ABS_PATH})?" + # Optional absolute path (\5|\12)
41
- "(?:\\?(#{QUERY}))?" + # Optional ?query (\6|\13)
42
- "(?:\\#(#{FRAGMENT}))?" # Optional #fragment (\7|\14)
43
-
44
- def self.pattern()
45
- # This pattern first tries to match the URI_PATTERN that ends with
46
- # punctuation that is a valid URI character (eg, ')', '!'). If
47
- # such a match occurs, there should be no backtracking (hence the ?> ).
48
- # If the string cannot match a URI ending with URI_ENDING, then a second
49
- # attempt is tried.
50
- Regexp.new("(?>#{URI_PATTERN}(?=#{URI_ENDING}))|#{URI_PATTERN}", Regexp::EXTENDED, 'N')
51
- end
52
-
53
- attr_reader :uri, :scheme, :user, :host, :port, :path, :query, :fragment, :link_text
54
-
55
- def initialize(match_data)
56
- super(match_data)
57
- # Since the URI_PATTERN is tried twice, there are two sets of
58
- # groups, one from \1 to \7 and the second from \8 to \14.
59
- # The fields are set by which ever group matches.
60
- @scheme = match_data[1] || match_data[8]
61
- @user = match_data[2] || match_data[9]
62
- @host = match_data[3] || match_data[10]
63
- @port = match_data[4] || match_data[11]
64
- @path = match_data[5] || match_data[12]
65
- @query = match_data[6] || match_data[13]
66
- @fragment = match_data[7] || match_data[14]
67
-
68
- # If there is no scheme, add an appropriate one, otherwise
69
- # set the URI to the matched text.
70
- @text_scheme = scheme
71
- @uri = (scheme ? match_data[0] : nil )
72
- @scheme = scheme || ( user ? 'mailto' : 'http' )
73
- @delimiter = ( scheme == 'mailto' ? ':' : '://' )
74
- @uri ||= scheme + @delimiter + match_data[0]
75
-
76
- # Build up the link text. Schemes are omitted unless explicitly given.
77
- @link_text = ''
78
- @link_text << "#{@scheme}#{@delimiter}" if @text_scheme
79
- @link_text << "#{@user}@" if @user
80
- @link_text << "#{@host}" if @host
81
- @link_text << ":#{@port}" if @port
82
- @link_text << "#{@path}" if @path
83
- @link_text << "?#{@query}" if @query
84
- end
85
-
86
- # If the text should be escaped then don't keep this chunk.
87
- # Otherwise only keep this chunk if it was substituted back into the
88
- # content.
89
- def unmask(content)
90
- return nil if escaped_text
91
- return self if content.sub!( Regexp.new(mask(content)), "<a href=\"#{uri}\">#{link_text}</a>" )
92
- end
93
-
94
- # If there is no hostname in the URI, do not render it
95
- # It's probably only contains the scheme, eg 'something:'
96
- def escaped_text() ( host.nil? ? @uri : nil ) end
97
- 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
@@ -1,82 +1,141 @@
1
- require 'wiki_words'
2
- require 'chunks/chunk'
3
- require 'cgi'
4
-
5
- # Contains all the methods for finding and replacing wiki related
6
- # links.
7
- module WikiChunk
8
- include Chunk
9
-
10
- # A wiki link is the top-level class for anything that refers to
11
- # another wiki page.
12
- class WikiLink < Chunk::Abstract
13
- # By default, no escaped text
14
- def escaped_text() nil end
15
-
16
- # Delimit the link text with markers to replace later unless
17
- # the word is escaped. In that case, just return the link text
18
- def mask(content) escaped_text || pre_mask + link_text + post_mask end
19
-
20
- def regexp() Regexp.new(pre_mask + '(.*)?' + post_mask) end
21
-
22
- def revert(content) content.sub!(regexp, text) end
23
-
24
- # Do not keep this chunk if it is escaped.
25
- # Otherwise, pass the link procedure a page_name and link_text and
26
- # get back a string of HTML to replace the mask with.
27
- def unmask(content)
28
- return nil if escaped_text
29
- return self if content.sub!(regexp) { |match| content.page_link(page_name, $1) }
30
- end
31
- end
32
-
33
- # This chunk matches a WikiWord. WikiWords can be escaped
34
- # by prepending a '\'. When this is the case, the +escaped_text+
35
- # method will return the WikiWord instead of the usual +nil+.
36
- # The +page_name+ method returns the matched WikiWord.
37
- class Word < WikiLink
38
- def self.pattern
39
- Regexp.new('(\\\\)?(' + WikiWords::WIKI_WORD_PATTERN + ')\b', 0, "utf-8")
40
- end
41
-
42
- attr_reader :page_name
43
-
44
- def initialize(match_data)
45
- super(match_data)
46
- @escape = match_data[1]
47
- @page_name = match_data[2]
48
- end
49
-
50
- def escaped_text() (@escape.nil? ? nil : page_name) end
51
- def link_text() WikiWords.separate(page_name) end
52
- end
53
-
54
- # This chunk handles [[bracketted wiki words]] and
55
- # [[AliasedWords|aliased wiki words]]. The first part of an
56
- # aliased wiki word must be a WikiWord. If the WikiWord
57
- # is aliased, the +link_text+ field will contain the
58
- # alias, otherwise +link_text+ will contain the entire
59
- # contents within the double brackets.
60
- #
61
- # NOTE: This chunk must be tested before WikiWord since
62
- # a WikiWords can be a substring of a WikiLink.
63
- class Link < WikiLink
64
- def self.pattern() /\[\[([^\]]+)\]\]/ end
65
- ALIASED_LINK_PATTERN= Regexp.new('^(.*)?\|(.*)$', 0, "utf-8")
66
-
67
- attr_reader :page_name, :link_text
68
-
69
- def initialize(match_data)
70
- super(match_data)
71
-
72
- # If the like is aliased, set the page name to the first bit
73
- # and the link text to the second, otherwise set both to the
74
- # contents of the double brackets.
75
- if match_data[1] =~ ALIASED_LINK_PATTERN
76
- @page_name, @link_text = $1, $2
77
- else
78
- @page_name, @link_text = match_data[1], match_data[1]
79
- end
80
- end
81
- end
82
- end
1
+ require 'wiki_words'
2
+ require 'chunks/chunk'
3
+ require 'chunks/wiki'
4
+ require 'cgi'
5
+
6
+ # Contains all the methods for finding and replacing wiki related links.
7
+ module WikiChunk
8
+ include Chunk
9
+
10
+ # A wiki reference is the top-level class for anything that refers to
11
+ # another wiki page.
12
+ class WikiReference < Chunk::Abstract
13
+
14
+ # Name of the referenced page
15
+ attr_reader :page_name
16
+
17
+ # the referenced page
18
+ def refpage
19
+ @content.web.pages[@page_name]
20
+ end
21
+
22
+ end
23
+
24
+ # A wiki link is the top-level class for links that refers to
25
+ # another wiki page.
26
+ class WikiLink < WikiReference
27
+
28
+ attr_reader :link_text, :link_type
29
+
30
+ def initialize(match_data, content)
31
+ super
32
+ @link_type = :show
33
+ end
34
+
35
+ def self.apply_to(content)
36
+ content.gsub!( self.pattern ) do |matched_text|
37
+ chunk = self.new($~, content)
38
+ if chunk.textile_url?
39
+ # do not substitute
40
+ matched_text
41
+ else
42
+ content.add_chunk(chunk)
43
+ chunk.mask
44
+ end
45
+ end
46
+ end
47
+
48
+ # the referenced page
49
+ def refpage
50
+ @content.web.pages[@page_name]
51
+ end
52
+
53
+ def textile_url?
54
+ not @textile_link_suffix.nil?
55
+ end
56
+
57
+ end
58
+
59
+ # This chunk matches a WikiWord. WikiWords can be escaped
60
+ # by prepending a '\'. When this is the case, the +escaped_text+
61
+ # method will return the WikiWord instead of the usual +nil+.
62
+ # The +page_name+ method returns the matched WikiWord.
63
+ class Word < WikiLink
64
+
65
+ attr_reader :escaped_text
66
+
67
+ unless defined? WIKI_WORD
68
+ WIKI_WORD = Regexp.new('(":)?(\\\\)?(' + WikiWords::WIKI_WORD_PATTERN + ')\b', 0, "utf-8")
69
+ end
70
+
71
+ def self.pattern
72
+ WIKI_WORD
73
+ end
74
+
75
+ def initialize(match_data, content)
76
+ super
77
+ @textile_link_suffix, @escape, @page_name = match_data[1..3]
78
+ if @escape
79
+ @unmask_mode = :escape
80
+ @escaped_text = @page_name
81
+ else
82
+ @escaped_text = nil
83
+ end
84
+ @link_text = WikiWords.separate(@page_name)
85
+ @unmask_text = (@escaped_text || @content.page_link(@page_name, @link_text, @link_type))
86
+ end
87
+
88
+ end
89
+
90
+ # This chunk handles [[bracketted wiki words]] and
91
+ # [[AliasedWords|aliased wiki words]]. The first part of an
92
+ # aliased wiki word must be a WikiWord. If the WikiWord
93
+ # is aliased, the +link_text+ field will contain the
94
+ # alias, otherwise +link_text+ will contain the entire
95
+ # contents within the double brackets.
96
+ #
97
+ # NOTE: This chunk must be tested before WikiWord since
98
+ # a WikiWords can be a substring of a WikiLink.
99
+ class Link < WikiLink
100
+
101
+ unless defined? WIKI_LINK
102
+ WIKI_LINK = /(":)?\[\[([^\]]+)\]\]/
103
+ LINK_TYPE_SEPARATION = Regexp.new('^(.+):((file)|(pic))$', 0, 'utf-8')
104
+ ALIAS_SEPARATION = Regexp.new('^(.+)\|(.+)$', 0, 'utf-8')
105
+ end
106
+
107
+ def self.pattern() WIKI_LINK end
108
+
109
+ def initialize(match_data, content)
110
+ super
111
+ @textile_link_suffix, @page_name = match_data[1..2]
112
+ @link_text = @page_name
113
+ separate_link_type
114
+ separate_alias
115
+ @unmask_text = @content.page_link(@page_name, @link_text, @link_type)
116
+ end
117
+
118
+ private
119
+
120
+ # if link wihin the brackets has a form of [[filename:file]] or [[filename:pic]],
121
+ # this means a link to a picture or a file
122
+ def separate_link_type
123
+ link_type_match = LINK_TYPE_SEPARATION.match(@page_name)
124
+ if link_type_match
125
+ @link_text = @page_name = link_type_match[1]
126
+ @link_type = link_type_match[2..3].compact[0].to_sym
127
+ end
128
+ end
129
+
130
+ # link text may be different from page name. this will look like [[actual page|link text]]
131
+ def separate_alias
132
+ alias_match = ALIAS_SEPARATION.match(@page_name)
133
+ if alias_match
134
+ @page_name, @link_text = alias_match[1..2]
135
+ end
136
+ # note that [[filename|link text:file]] is also supported
137
+ end
138
+
139
+ end
140
+
141
+ end