Pimki 1.7.092 → 1.8.092

Sign up to get free protection for your applications and to get access to all the features.
Files changed (48) hide show
  1. data/README-PIMKI +182 -178
  2. data/app/controllers/wiki.rb +950 -942
  3. data/app/models/chunks/category.rb +33 -33
  4. data/app/models/chunks/category_test.rb +21 -21
  5. data/app/models/chunks/chunk.rb +20 -20
  6. data/app/models/chunks/engines.rb +48 -48
  7. data/app/models/chunks/include.rb +1 -1
  8. data/app/models/chunks/match.rb +1 -1
  9. data/app/models/chunks/nowiki.rb +1 -1
  10. data/app/models/chunks/nowiki_test.rb +5 -0
  11. data/app/models/chunks/todo.rb +1 -0
  12. data/app/models/chunks/wiki.rb +130 -130
  13. data/app/models/page.rb +124 -124
  14. data/app/models/revision.rb +92 -92
  15. data/app/models/web.rb +314 -316
  16. data/app/models/wiki_content.rb +2 -2
  17. data/app/models/wiki_service.rb +170 -166
  18. data/app/models/wiki_words.rb +28 -28
  19. data/app/views/error.rhtml +37 -37
  20. data/app/views/navigation.rhtml +1 -1
  21. data/app/views/static_style_sheet.rhtml +10 -5
  22. data/app/views/top.rhtml +1 -1
  23. data/app/views/wiki/adv_search.rhtml +61 -61
  24. data/app/views/wiki/bliki.rhtml +7 -6
  25. data/app/views/wiki/bliki_edit.rhtml +26 -37
  26. data/app/views/wiki/bliki_new.rhtml +58 -64
  27. data/app/views/wiki/bliki_revision.rhtml +5 -3
  28. data/app/views/wiki/edit.rhtml +44 -44
  29. data/app/views/wiki/edit_menu.rhtml +26 -19
  30. data/app/views/wiki/edit_web.rhtml +303 -305
  31. data/app/views/wiki/glossary.rhtml +35 -27
  32. data/app/views/wiki/list.rhtml +175 -174
  33. data/app/views/wiki/list.rhtml.bak +175 -0
  34. data/app/views/wiki/mind.rhtml +70 -70
  35. data/app/views/wiki/new.rhtml +34 -32
  36. data/app/views/wiki/published.rhtml +34 -49
  37. data/app/views/wiki/revision.rhtml +88 -87
  38. data/app/views/wiki/rollback.rhtml +36 -35
  39. data/app/views/wiki/todo.rhtml +2 -2
  40. data/app/views/wiki_words_help.rhtml +8 -8
  41. data/libraries/action_controller_servlet.rb +202 -202
  42. data/libraries/madeleine_service.rb +162 -162
  43. data/pimki.rb +181 -181
  44. metadata +11 -12
  45. data/README +0 -172
  46. data/app/models/chunks/acronym.rb +0 -19
  47. data/app/views/wiki/test.rhtml +0 -25
  48. data/libraries/secure_web_controller_server.rb +0 -106
@@ -1,33 +1,33 @@
1
- require 'chunks/chunk'
2
-
3
- # The category chunk looks for "category: news" on a line by
4
- # itself and parses the terms after the ':' as categories.
5
- # Other classes can search for Category chunks within
6
- # rendered content to find out what categories this page
7
- # should be in.
8
- #
9
- # Category lines can be hidden using ':category: news', for example
10
- class Category < Chunk::Abstract
11
- def self.pattern() return /^(:)?category\s*:(.*)$/i end
12
-
13
- attr_reader :hidden, :list
14
-
15
- def initialize(match_data, revision)
16
- super(match_data, revision)
17
- @hidden = match_data[1]
18
- @list = match_data[2].split(',').map { |c| c.strip }
19
- end
20
-
21
- # Mark this chunk's start and end points but allow the terms
22
- # after the ':' to be marked up.
23
- def mask(content) pre_mask + list.join(', ') + post_mask end
24
-
25
- # If the chunk is hidden, erase the mask and return this chunk
26
- # otherwise, surround it with a 'div' block.
27
- def unmask(content)
28
- #replacement = ( hidden ? '' : '<div class="property">category:\1</div>' )
29
- self if content.sub!( Regexp.new( pre_mask+'(.*)?'+post_mask ) ) {
30
- "<div class='property'>category:#{$1.split(',').map { |c| c.strip!; "<a href='../list/?category=#{c}'>#{c}</a> " }}</div>"
31
- }
32
- end
33
- end
1
+ require 'chunks/chunk'
2
+
3
+ # The category chunk looks for "category: news" on a line by
4
+ # itself and parses the terms after the ':' as categories.
5
+ # Other classes can search for Category chunks within
6
+ # rendered content to find out what categories this page
7
+ # should be in.
8
+ #
9
+ # Category lines can be hidden using ':category: news', for example
10
+ class Category < Chunk::Abstract
11
+ def self.pattern() return /^(:)?category\s*:(.*)$/i end
12
+
13
+ attr_reader :hidden, :list
14
+
15
+ def initialize(match_data, revision)
16
+ super(match_data, revision)
17
+ @hidden = match_data[1]
18
+ @list = match_data[2].split(',').map { |c| c.strip }
19
+ end
20
+
21
+ # Mark this chunk's start and end points but allow the terms
22
+ # after the ':' to be marked up.
23
+ def mask(content) pre_mask + list.join(', ') + post_mask end
24
+
25
+ # If the chunk is hidden, erase the mask and return this chunk
26
+ # otherwise, surround it with a 'div' block.
27
+ def unmask(content)
28
+ #replacement = ( hidden ? '' : '<div class="property">category:\1</div>' )
29
+ self if content.sub!( Regexp.new( pre_mask+'(.*)?'+post_mask ) ) {
30
+ "<div class='property'>category:#{$1.split(',').map { |c| c.strip!; "<a href='../list/?category=#{c}'>#{c}</a> " }}</div>"
31
+ }
32
+ end
33
+ end
@@ -1,21 +1,21 @@
1
- require 'chunks/category'
2
- require 'chunks/match'
3
- require 'test/unit'
4
-
5
- class CategoryTest < Test::Unit::TestCase
6
- include ChunkMatch
7
-
8
- def test_single_category
9
- match(Category, 'category: test', :list => ['test'], :hidden => nil)
10
- match(Category, 'category : chunk test ', :list => ['chunk test'], :hidden => nil)
11
- match(Category, ':category: test', :list => ['test'], :hidden => ':')
12
- end
13
-
14
- def test_multiple_categories
15
- match(Category, 'category: test, multiple', :list => ['test', 'multiple'], :hidden => nil)
16
- match(Category, 'category : chunk test , multi category,regression test case ',
17
- :list => ['chunk test','multi category','regression test case'], :hidden => nil
18
- )
19
- end
20
-
21
- end
1
+ require 'chunks/category'
2
+ require 'chunks/match'
3
+ require 'test/unit'
4
+
5
+ class CategoryTest < Test::Unit::TestCase
6
+ include ChunkMatch
7
+
8
+ def test_single_category
9
+ match(Category, 'category: test', :list => ['test'], :hidden => nil)
10
+ match(Category, 'category : chunk test ', :list => ['chunk test'], :hidden => nil)
11
+ match(Category, ':category: test', :list => ['test'], :hidden => ':')
12
+ end
13
+
14
+ def test_multiple_categories
15
+ match(Category, 'category: test, multiple', :list => ['test', 'multiple'], :hidden => nil)
16
+ match(Category, 'category : chunk test , multi category,regression test case ',
17
+ :list => ['chunk test','multi category','regression test case'], :hidden => nil
18
+ )
19
+ end
20
+
21
+ end
@@ -1,20 +1,20 @@
1
- require 'digest/md5'
2
- require 'uri/common'
3
-
4
- # A chunk is a pattern of text that can be protected
5
- # and interrogated by a renderer. Each Chunk class has a
6
- # +pattern+ that states what sort of text it matches.
7
- # Chunks are initalized by passing in the result of a
8
- # match by its pattern.
9
- module Chunk
10
- class Abstract
11
- attr_reader :text, :revision
12
-
13
- def initialize(match_data, revision) @text = match_data[0]; @revision = revision end
14
- def pre_mask() "chunk#{self.object_id}start " end
15
- def post_mask() " chunk#{self.object_id}end" end
16
- def mask(content) "chunk#{self.object_id}chunk" end
17
- def revert(content) content.sub!( Regexp.new(mask(content)), text ) end
18
- def unmask(content) self if revert(content) end
19
- end
20
- end
1
+ require 'digest/md5'
2
+ require 'uri/common'
3
+
4
+ # A chunk is a pattern of text that can be protected
5
+ # and interrogated by a renderer. Each Chunk class has a
6
+ # +pattern+ that states what sort of text it matches.
7
+ # Chunks are initalized by passing in the result of a
8
+ # match by its pattern.
9
+ module Chunk
10
+ class Abstract
11
+ attr_reader :text, :revision
12
+
13
+ def initialize(match_data, revision) @text = match_data[0]; @revision = revision end
14
+ def pre_mask() "chunk#{self.object_id}start " end
15
+ def post_mask() " chunk#{self.object_id}end" end
16
+ def mask(content) "chunk#{self.object_id}chunk" end
17
+ def revert(content) content.sub!( Regexp.new(mask(content)), text ) end
18
+ def unmask(content) self if revert(content) end
19
+ end
20
+ end
@@ -1,48 +1,48 @@
1
- require 'rdocsupport'
2
- require 'chunks/chunk'
3
-
4
- # The markup engines are Chunks that call the one of RedCloth, BlueCloth
5
- # or RDoc to convert text. This markup occurs when the chunk is required
6
- # to mask itself.
7
- module Engines
8
-
9
- class MarkupEngine < Chunk::Abstract
10
- def self.pattern() /^(.*)$/m end
11
- def unmask(content) self end
12
- end
13
-
14
- class Textile < MarkupEngine
15
- def mask(content)
16
- rc = RedCloth.new(text,content.options[:engine_opts])
17
- rc.rules = [:textile] if RedCloth::VERSION >= '3.0.0'
18
- rc.to_html
19
- end
20
- end
21
-
22
- class RedMarkdown < MarkupEngine
23
- def mask(content)
24
- rc = RedCloth.new(text,content.options[:engine_opts])
25
- rc.rules = [:markdown]
26
- rc.to_html
27
- end
28
- end
29
-
30
- class BlueMarkdown < MarkupEngine
31
- def mask(content)
32
- BlueCloth.new(text,content.options[:engine_opts]).to_html
33
- end
34
- end
35
-
36
- class RDoc < MarkupEngine
37
- def mask(content)
38
- RDocSupport::RDocFormatter.new(text).to_html
39
- end
40
- end
41
-
42
- MAP = { :textile => Textile,
43
- :red_markdown => RedMarkdown,
44
- :blue_markdown => BlueMarkdown,
45
- :markdown => BlueMarkdown,
46
- :rdoc => RDoc }
47
- end
48
-
1
+ require 'rdocsupport'
2
+ require 'chunks/chunk'
3
+
4
+ # The markup engines are Chunks that call the one of RedCloth, BlueCloth
5
+ # or RDoc to convert text. This markup occurs when the chunk is required
6
+ # to mask itself.
7
+ module Engines
8
+
9
+ class MarkupEngine < Chunk::Abstract
10
+ def self.pattern() /^(.*)$/m end
11
+ def unmask(content) self end
12
+ end
13
+
14
+ class Textile < MarkupEngine
15
+ def mask(content)
16
+ rc = RedCloth.new(text,content.options[:engine_opts])
17
+ rc.rules = [:textile] if RedCloth::VERSION >= '3.0.0'
18
+ rc.to_html
19
+ end
20
+ end
21
+
22
+ class RedMarkdown < MarkupEngine
23
+ def mask(content)
24
+ rc = RedCloth.new(text,content.options[:engine_opts])
25
+ rc.rules = [:markdown]
26
+ rc.to_html
27
+ end
28
+ end
29
+
30
+ class BlueMarkdown < MarkupEngine
31
+ def mask(content)
32
+ BlueCloth.new(text,content.options[:engine_opts]).to_html
33
+ end
34
+ end
35
+
36
+ class RDoc < MarkupEngine
37
+ def mask(content)
38
+ RDocSupport::RDocFormatter.new(text).to_html
39
+ end
40
+ end
41
+
42
+ MAP = { :textile => Textile,
43
+ :red_markdown => RedMarkdown,
44
+ :blue_markdown => BlueMarkdown,
45
+ :markdown => BlueMarkdown,
46
+ :rdoc => RDoc }
47
+ end
48
+
@@ -7,7 +7,7 @@ require 'chunks/wiki'
7
7
  # of changes to that page.
8
8
  # If the included page could not be found, a warning is displayed.
9
9
  class Include < WikiChunk::WikiLink
10
- def self.pattern() /^\[\[!include(.*)\]\]\s*$/i end
10
+ def self.pattern() /^\s*\[\[!include([^\]]*)\]\]\s*$/i end
11
11
 
12
12
  attr_reader :page_name
13
13
 
@@ -8,7 +8,7 @@ module ChunkMatch
8
8
  pattern = type.pattern
9
9
  assert_match(pattern, test_text)
10
10
  pattern =~ test_text # Previous assertion guarantees match
11
- chunk = type.new($~)
11
+ chunk = type.new($~, nil)
12
12
 
13
13
  # Test if requested parts are correct.
14
14
  for method_sym, value in expected do
@@ -15,7 +15,7 @@ require 'chunks/chunk'
15
15
  # Created: 8th June 2004
16
16
  class NoWiki < Chunk::Abstract
17
17
 
18
- def self.pattern() Regexp.new('<nowiki>(.*?)</nowiki>') end
18
+ def self.pattern() Regexp.new('<nowiki>(.*?)</nowiki>', Regexp::MULTILINE) end
19
19
 
20
20
  attr_reader :plain_text
21
21
 
@@ -9,6 +9,11 @@ class NoWikiTest < Test::Unit::TestCase
9
9
  match(NoWiki, 'This sentence contains <nowiki>[[raw text]]</nowiki>. Do not touch!',
10
10
  :plain_text => '[[raw text]]'
11
11
  )
12
+ match(NoWiki, 'This sentence contains <nowiki>
13
+ MultiLine [[raw text]]
14
+ </nowiki>. Do not touch!',
15
+ :plain_text => "\n MultiLine [[raw text]]\n "
16
+ )
12
17
  end
13
18
 
14
19
  end
@@ -12,6 +12,7 @@ class Todo < Chunk::Abstract
12
12
  super(match_data, revision)
13
13
  @context = match_data[1]
14
14
  @context = @context.nil? || @context.empty? ? [] : @context.delete('@').split(',')
15
+ @context += revision.page.categories
15
16
  @text = match_data[2]
16
17
  begin
17
18
  d = ParseDate.parsedate(@text)
@@ -1,130 +1,130 @@
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 + ')(</a>)?', 0, "utf-8")
40
- end # (chunk\d+chunk)?
41
-
42
- attr_reader :page_name
43
-
44
- def initialize(match_data, revision)
45
- super(match_data, revision)
46
- @escaped = match_data[1] || match_data[3]
47
- @text.delete! '\\' if @escaped
48
- @page_name = @link_text = match_data[2]
49
- end
50
-
51
- def mask(content) pre_mask + post_mask; end
52
- def regexp() Regexp.new(pre_mask + post_mask) end
53
- def escaped_text() (@escaped.nil? ? nil : page_name) end
54
- def link_text() WikiWords.separate(page_name) end
55
- end
56
-
57
- # This chunk handles [[bracketted wiki words]] and
58
- # [[AliasedWords|aliased wiki words]]. The first part of an
59
- # aliased wiki word must be a WikiWord. If the WikiWord
60
- # is aliased, the +link_text+ field will contain the
61
- # alias, otherwise +link_text+ will contain the entire
62
- # contents within the double brackets.
63
- #
64
- # NOTE: This chunk must be tested before WikiWord since
65
- # a WikiWords can be a substring of a WikiLink.
66
- class Link < WikiLink
67
- def self.pattern() /\[\[([^\]]+)\]\]/ end
68
- ALIASED_LINK_PATTERN= Regexp.new('^(.*)?\|(.*)$', 0, "utf-8")
69
-
70
- attr_reader :page_name, :link_text
71
-
72
- def initialize(match_data, revision)
73
- super(match_data, revision)
74
-
75
- # If the like is aliased, set the page name to the first bit
76
- # and the link text to the second, otherwise set both to the
77
- # contents of the double brackets.
78
- if match_data[1] =~ ALIASED_LINK_PATTERN
79
- @page_name, @link_text = $1, $2
80
- else
81
- @page_name, @link_text = match_data[1], match_data[1]
82
- end
83
-
84
- @link_text = WikiWords.separate(@link_text) if @link_text.match /^#{WikiWords::WIKI_WORD_PATTERN}$/
85
- end
86
- end
87
-
88
- # This chunk handles [bliki[entry name]].
89
- # This format has been extended for some other pre-configured redirection.
90
- # Probably a bad name now, as we're using this for any link outside the current
91
- # web, but if I change the class name it'll break existing storages.
92
- class BlikiLink < WikiLink
93
- def self.pattern() /\[(\w+)\[([\w\d\s]+)\]\]/ end
94
-
95
- attr_reader :page_name, :link_text, :entry
96
-
97
- def initialize(match_data, revision)
98
- super(match_data, revision)
99
- @target, @page_name, @link_text = match_data[1], match_data[2], match_data[2]
100
- end
101
-
102
- def mask(content) pre_mask + post_mask end
103
-
104
- def unmask(content)
105
- return self if content.sub!(regexp) { |match|
106
- case @target
107
- when 'bliki'
108
- web = revision.page.web
109
- entry = web.bliki[page_name]
110
- if entry.nil?
111
- #"<span style='background:lightgrey;font-style:italic'>Unknown Bliki entry: '#{page_name}'</span>"
112
- "<a class='newWikiWord' href='/#{web.address}/bliki_new/?entry_name=#{CGI::escape page_name}'>Bliki::#{page_name}</a>"
113
- else
114
- "<a class='existingWikiWord' href='/#{web.address}/bliki_revision/#{entry.name}?rev=#{entry.revisions.size-1}'>Bliki::#{entry.name}</a>"
115
- end
116
-
117
- when 'c2'
118
- "<a href='http://c2.com/cgi/wiki?#{@page_name}'>C2::#{@page_name}</a>"
119
-
120
- else
121
- if web = WikiService.instance.webs[@target]
122
- "<a href='/#{web.address}@/show/#@page_name'>#{web.name}::#@page_name</a>"
123
- else
124
- "<i>#@text</i>"
125
- end
126
- end
127
- }
128
- end
129
- end
130
- end
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 + ')(</a>)?', 0, "utf-8")
40
+ end # (chunk\d+chunk)?
41
+
42
+ attr_reader :page_name
43
+
44
+ def initialize(match_data, revision)
45
+ super(match_data, revision)
46
+ @escaped = match_data[1] || match_data[3]
47
+ @text.delete! '\\' if @escaped
48
+ @page_name = @link_text = match_data[2]
49
+ end
50
+
51
+ def mask(content) pre_mask + post_mask; end
52
+ def regexp() Regexp.new(pre_mask + post_mask) end
53
+ def escaped_text() (@escaped.nil? ? nil : page_name) end
54
+ def link_text() WikiWords.separate(page_name) end
55
+ end
56
+
57
+ # This chunk handles [[bracketted wiki words]] and
58
+ # [[AliasedWords|aliased wiki words]]. The first part of an
59
+ # aliased wiki word must be a WikiWord. If the WikiWord
60
+ # is aliased, the +link_text+ field will contain the
61
+ # alias, otherwise +link_text+ will contain the entire
62
+ # contents within the double brackets.
63
+ #
64
+ # NOTE: This chunk must be tested before WikiWord since
65
+ # a WikiWords can be a substring of a WikiLink.
66
+ class Link < WikiLink
67
+ def self.pattern() /\[\[([^\]]+)\]\]/ end
68
+ ALIASED_LINK_PATTERN= Regexp.new('^(.*)?\|(.*)$', 0, "utf-8")
69
+
70
+ attr_reader :page_name, :link_text
71
+
72
+ def initialize(match_data, revision)
73
+ super(match_data, revision)
74
+
75
+ # If the like is aliased, set the page name to the first bit
76
+ # and the link text to the second, otherwise set both to the
77
+ # contents of the double brackets.
78
+ if match_data[1] =~ ALIASED_LINK_PATTERN
79
+ @page_name, @link_text = $1, $2
80
+ else
81
+ @page_name, @link_text = match_data[1], match_data[1]
82
+ end
83
+
84
+ @link_text = WikiWords.separate(@link_text) if @link_text.match /^#{WikiWords::WIKI_WORD_PATTERN}$/
85
+ end
86
+ end
87
+
88
+ # This chunk handles [bliki[entry name]].
89
+ # This format has been extended for some other pre-configured redirection.
90
+ # Probably a bad name now, as we're using this for any link outside the current
91
+ # web, but if I change the class name it'll break existing storages.
92
+ class BlikiLink < WikiLink
93
+ def self.pattern() /\[(\w+)\[([\w\d\s]+)\]\]/ end
94
+
95
+ attr_reader :page_name, :link_text, :entry
96
+
97
+ def initialize(match_data, revision)
98
+ super(match_data, revision)
99
+ @target, @page_name, @link_text = match_data[1], match_data[2], match_data[2]
100
+ end
101
+
102
+ def mask(content) pre_mask + post_mask end
103
+
104
+ def unmask(content)
105
+ return self if content.sub!(regexp) { |match|
106
+ case @target
107
+ when 'bliki'
108
+ web = revision.page.web
109
+ entry = web.bliki[page_name]
110
+ if entry.nil?
111
+ #"<span style='background:lightgrey;font-style:italic'>Unknown Bliki entry: '#{page_name}'</span>"
112
+ "<a class='newWikiWord' href='/#{web.address}/bliki_new/?entry_name=#{CGI::escape page_name}'>Bliki::#{page_name}</a>"
113
+ else
114
+ "<a class='existingWikiWord' href='/#{web.address}/bliki_revision/#{entry.name}?rev=#{entry.revisions.size-1}'>Bliki::#{entry.name}</a>"
115
+ end
116
+
117
+ when 'c2'
118
+ "<a href='http://c2.com/cgi/wiki?#{@page_name}'>C2::#{@page_name}</a>"
119
+
120
+ else
121
+ if web = WikiService.instance.webs[@target]
122
+ "<a href='/#{web.address}/show/#@page_name'>#{web.name}::#@page_name</a>"
123
+ else
124
+ "<i>#@text</i>"
125
+ end
126
+ end
127
+ }
128
+ end
129
+ end
130
+ end