Pimki 1.7.092 → 1.8.092
Sign up to get free protection for your applications and to get access to all the features.
- data/README-PIMKI +182 -178
- data/app/controllers/wiki.rb +950 -942
- data/app/models/chunks/category.rb +33 -33
- data/app/models/chunks/category_test.rb +21 -21
- data/app/models/chunks/chunk.rb +20 -20
- data/app/models/chunks/engines.rb +48 -48
- data/app/models/chunks/include.rb +1 -1
- data/app/models/chunks/match.rb +1 -1
- data/app/models/chunks/nowiki.rb +1 -1
- data/app/models/chunks/nowiki_test.rb +5 -0
- data/app/models/chunks/todo.rb +1 -0
- data/app/models/chunks/wiki.rb +130 -130
- data/app/models/page.rb +124 -124
- data/app/models/revision.rb +92 -92
- data/app/models/web.rb +314 -316
- data/app/models/wiki_content.rb +2 -2
- data/app/models/wiki_service.rb +170 -166
- data/app/models/wiki_words.rb +28 -28
- data/app/views/error.rhtml +37 -37
- data/app/views/navigation.rhtml +1 -1
- data/app/views/static_style_sheet.rhtml +10 -5
- data/app/views/top.rhtml +1 -1
- data/app/views/wiki/adv_search.rhtml +61 -61
- data/app/views/wiki/bliki.rhtml +7 -6
- data/app/views/wiki/bliki_edit.rhtml +26 -37
- data/app/views/wiki/bliki_new.rhtml +58 -64
- data/app/views/wiki/bliki_revision.rhtml +5 -3
- data/app/views/wiki/edit.rhtml +44 -44
- data/app/views/wiki/edit_menu.rhtml +26 -19
- data/app/views/wiki/edit_web.rhtml +303 -305
- data/app/views/wiki/glossary.rhtml +35 -27
- data/app/views/wiki/list.rhtml +175 -174
- data/app/views/wiki/list.rhtml.bak +175 -0
- data/app/views/wiki/mind.rhtml +70 -70
- data/app/views/wiki/new.rhtml +34 -32
- data/app/views/wiki/published.rhtml +34 -49
- data/app/views/wiki/revision.rhtml +88 -87
- data/app/views/wiki/rollback.rhtml +36 -35
- data/app/views/wiki/todo.rhtml +2 -2
- data/app/views/wiki_words_help.rhtml +8 -8
- data/libraries/action_controller_servlet.rb +202 -202
- data/libraries/madeleine_service.rb +162 -162
- data/pimki.rb +181 -181
- metadata +11 -12
- data/README +0 -172
- data/app/models/chunks/acronym.rb +0 -19
- data/app/views/wiki/test.rhtml +0 -25
- 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
|
data/app/models/chunks/chunk.rb
CHANGED
@@ -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(
|
10
|
+
def self.pattern() /^\s*\[\[!include([^\]]*)\]\]\s*$/i end
|
11
11
|
|
12
12
|
attr_reader :page_name
|
13
13
|
|
data/app/models/chunks/match.rb
CHANGED
@@ -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
|
data/app/models/chunks/nowiki.rb
CHANGED
@@ -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
|
data/app/models/chunks/todo.rb
CHANGED
@@ -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)
|
data/app/models/chunks/wiki.rb
CHANGED
@@ -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}
|
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
|