1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
require 'xhtmldiff'
# Temporary class containing all rendering stuff from a Revision
# I want to shift all rendering loguc to the controller eventually
class PageRenderer
def self.setup_url_generator(url_generator)
@@url_generator = url_generator
end
def self.teardown_url_generator
@@url_generator = nil
end
attr_reader :revision
def initialize(revision = nil)
self.revision = revision
end
def revision=(r)
@revision = r
@display_content = @display_published = @wiki_words_cache = @wiki_includes_cache =
@wiki_references_cache = nil
end
def display_content(update_references = false)
@display_content ||= render(:update_references => update_references)
end
def display_content_for_export
render :mode => :export
end
def display_published
@display_published ||= render(:mode => :publish)
end
def display_diff(styles = {})
previous_revision = @revision.page.previous_revision(@revision)
if previous_revision
previous_content = "<div xmlns:se='http://svg-edit.googlecode.com' xmlns:xlink='http://www.w3.org/1999/xlink'>" + WikiContent.new(previous_revision, @@url_generator).render!.to_s + "</div>"
current_content = "<div xmlns:se='http://svg-edit.googlecode.com' xmlns:xlink='http://www.w3.org/1999/xlink'>" + display_content.to_s + "</div>"
diff_doc = REXML::Document.new
div = REXML::Element.new('div', nil, {:respect_whitespace =>:all})
div.attributes['class'] = 'xhtmldiff_wrapper'
diff_doc << div
hd = XHTMLDiff.new(div, styles)
parsed_previous_revision = REXML::HashableElementDelegator.new(
REXML::XPath.first(REXML::Document.new(previous_content), '/div'))
parsed_display_content = REXML::HashableElementDelegator.new(
REXML::XPath.first(REXML::Document.new(current_content), '/div'))
Diff::LCS.traverse_balanced(parsed_previous_revision, parsed_display_content, hd)
diffs = ''
diff_doc.write(diffs, -1, true, true)
diffs.gsub(/\A<div class='xhtmldiff_wrapper'>(.*)<\/div>\Z/m, '1円').html_safe
else
display_content
end
end
attr :s5_theme
def s5_theme=(s)
@s5_theme = s
end
# Renders an S5 slideshow
def display_s5
@display_s5 ||= render(:mode => :s5,
:engine_opts => {:author => @author, :title => @plain_name},
:renderer => self)
end
# Returns an array of all the WikiIncludes present in the content of this revision.
def wiki_includes
unless @wiki_includes_cache
chunks = display_content.find_chunks(Include)
@wiki_includes_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq
end
@wiki_includes_cache
end
# Returns an array of all the WikiReferences present in the content of this revision.
def wiki_references
unless @wiki_references_cache
chunks = display_content.find_chunks(WikiChunk::WikiReference)
@wiki_references_cache = chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq
end
@wiki_references_cache
end
# Returns an array of all the WikiWords present in the content of this revision.
def wiki_words
@wiki_words_cache ||= find_wiki_words(display_content)
end
def find_wiki_words(rendering_result)
the_wiki_words = wiki_links(rendering_result)
# Exclude backslash-escaped wiki words, such as \WikiWord, as well as links to files
# and pictures, such as [[foo.txt:file]] or [[foo.jpg:pic]]
the_wiki_words.delete_if { |link| link.escaped? or [:pic, :file, :cdf, :audio, :video, :delete].include?(link.link_type) }
# convert to the list of unique page names
the_wiki_words.map { |link| ( link.page_name ) }.uniq
end
# Returns an array of all the WikiWords present in the content of this revision.
def wiki_files
@wiki_files_cache ||= find_wiki_files(display_content)
end
def find_wiki_files(rendering_result)
the_wiki_files = wiki_links(rendering_result)
the_wiki_files.delete_if { |link| ![:pic, :file, :cdf, :audio, :video].include?(link.link_type) }
the_wiki_files.map { |link| ( link.page_name ) }.uniq
end
def wiki_links(rendering_result)
rendering_result.find_chunks(WikiChunk::WikiLink)
end
# Returns an array of all the WikiWords present in the content of this revision.
# that already exists as a page in the web.
def existing_pages
wiki_words.select { |wiki_word| @revision.page.web.page(wiki_word) }
end
# Returns an array of all the WikiWords present in the content of this revision
# that *doesn't* already exists as a page in the web.
def unexisting_pages
wiki_words - existing_pages
end
private
def render(options = {})
rendering_result = WikiContent.new(@revision, @@url_generator, options).render!
update_references(rendering_result) if options[:update_references]
rendering_result
end
def update_references(rendering_result)
WikiReference.delete_all ['page_id = ?', @revision.page_id]
references = @revision.page.wiki_references
wiki_words = find_wiki_words(rendering_result)
# TODO it may be desirable to save links to files and pictures as WikiReference objects
# present version doesn't do it
wiki_words.each do |referenced_name|
# Links to self are always considered linked
if referenced_name == @revision.page.name
link_type = WikiReference::LINKED_PAGE
else
link_type = WikiReference.link_type(@revision.page.web, referenced_name)
end
references.build :referenced_name => referenced_name, :link_type => link_type
end
wiki_files = find_wiki_files(rendering_result)
wiki_files.each do |referenced_name|
references.build :referenced_name => referenced_name, :link_type => WikiReference::FILE
end
include_chunks = rendering_result.find_chunks(Include)
includes = include_chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq
includes.each do |included_page_name|
references.build :referenced_name => included_page_name,
:link_type => WikiReference::INCLUDED_PAGE
end
redirect_chunks = rendering_result.find_chunks(Redirect)
redirects = redirect_chunks.map { |c| ( c.escaped? ? nil : c.page_name ) }.compact.uniq
redirects.each do |redirected_page_name|
references.build :referenced_name => redirected_page_name,
:link_type => WikiReference::REDIRECTED_PAGE
end
# ugly hack: store these in a thread-local variable, so that the cache-sweeper has access to it.
Thread.current[:page_redirects] ?
Thread.current[:page_redirects].update({ @revision.page => redirects}) :
Thread.current[:page_redirects] = { @revision.page => redirects}
categories = rendering_result.find_chunks(Category).map { |cat| cat.list }.flatten
categories.each do |category|
references.build :referenced_name => category, :link_type => WikiReference::CATEGORY
end
end
end