Pimki 1.0.092
Sign up to get free protection for your applications and to get access to all the features.
- data/README +158 -0
- data/README-PIMKI +87 -0
- data/app/controllers/wiki.rb +563 -0
- data/app/models/author.rb +4 -0
- data/app/models/chunks/category.rb +31 -0
- data/app/models/chunks/category_test.rb +21 -0
- data/app/models/chunks/chunk.rb +20 -0
- data/app/models/chunks/engines.rb +34 -0
- data/app/models/chunks/include.rb +29 -0
- data/app/models/chunks/literal.rb +19 -0
- data/app/models/chunks/match.rb +19 -0
- data/app/models/chunks/nowiki.rb +31 -0
- data/app/models/chunks/nowiki_test.rb +14 -0
- data/app/models/chunks/test.rb +18 -0
- data/app/models/chunks/todo.rb +22 -0
- data/app/models/chunks/uri.rb +97 -0
- data/app/models/chunks/uri_test.rb +92 -0
- data/app/models/chunks/wiki.rb +82 -0
- data/app/models/chunks/wiki_test.rb +36 -0
- data/app/models/page.rb +91 -0
- data/app/models/page_lock.rb +24 -0
- data/app/models/page_set.rb +73 -0
- data/app/models/page_test.rb +76 -0
- data/app/models/revision.rb +91 -0
- data/app/models/revision_test.rb +252 -0
- data/app/models/web.rb +277 -0
- data/app/models/web_test.rb +53 -0
- data/app/models/wiki_content.rb +113 -0
- data/app/models/wiki_service.rb +137 -0
- data/app/models/wiki_service_test.rb +15 -0
- data/app/models/wiki_words.rb +26 -0
- data/app/models/wiki_words_test.rb +12 -0
- data/app/views/bottom.rhtml +4 -0
- data/app/views/markdown_help.rhtml +16 -0
- data/app/views/menu.rhtml +20 -0
- data/app/views/navigation.rhtml +26 -0
- data/app/views/rdoc_help.rhtml +16 -0
- data/app/views/static_style_sheet.rhtml +231 -0
- data/app/views/style.rhtml +179 -0
- data/app/views/textile_help.rhtml +28 -0
- data/app/views/top.rhtml +52 -0
- data/app/views/wiki/authors.rhtml +15 -0
- data/app/views/wiki/bliki.rhtml +101 -0
- data/app/views/wiki/bliki_edit.rhtml +33 -0
- data/app/views/wiki/bliki_new.rhtml +61 -0
- data/app/views/wiki/bliki_revision.rhtml +51 -0
- data/app/views/wiki/edit.rhtml +34 -0
- data/app/views/wiki/edit_menu.rhtml +27 -0
- data/app/views/wiki/edit_web.rhtml +139 -0
- data/app/views/wiki/export.rhtml +14 -0
- data/app/views/wiki/feeds.rhtml +10 -0
- data/app/views/wiki/list.rhtml +164 -0
- data/app/views/wiki/locked.rhtml +14 -0
- data/app/views/wiki/login.rhtml +11 -0
- data/app/views/wiki/mind.rhtml +39 -0
- data/app/views/wiki/new.rhtml +27 -0
- data/app/views/wiki/new_system.rhtml +78 -0
- data/app/views/wiki/new_web.rhtml +64 -0
- data/app/views/wiki/page.rhtml +84 -0
- data/app/views/wiki/print.rhtml +16 -0
- data/app/views/wiki/published.rhtml +10 -0
- data/app/views/wiki/recently_revised.rhtml +31 -0
- data/app/views/wiki/revision.rhtml +87 -0
- data/app/views/wiki/rss_feed.rhtml +22 -0
- data/app/views/wiki/search.rhtml +26 -0
- data/app/views/wiki/tex.rhtml +23 -0
- data/app/views/wiki/tex_web.rhtml +35 -0
- data/app/views/wiki/todo.rhtml +39 -0
- data/app/views/wiki/web_list.rhtml +13 -0
- data/app/views/wiki_words_help.rhtml +8 -0
- data/libraries/action_controller_servlet.rb +177 -0
- data/libraries/bluecloth.rb +1127 -0
- data/libraries/diff/diff.rb +475 -0
- data/libraries/diff/diff_test.rb +80 -0
- data/libraries/erb.rb +490 -0
- data/libraries/madeleine/automatic.rb +357 -0
- data/libraries/madeleine/clock.rb +94 -0
- data/libraries/madeleine_service.rb +69 -0
- data/libraries/rdocsupport.rb +156 -0
- data/libraries/redcloth_for_tex.rb +869 -0
- data/libraries/redcloth_for_tex_test.rb +41 -0
- data/libraries/view_helper.rb +33 -0
- data/libraries/web_controller_server.rb +95 -0
- data/pimki.rb +97 -0
- metadata +169 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
<%
|
2
|
+
@title = @page.plain_name
|
3
|
+
@hide_navigation = true
|
4
|
+
@style_additions = ".newWikiWord { background-color: white; font-style: italic; }"
|
5
|
+
@inline_style = true
|
6
|
+
%><%= sub_template "top" %>
|
7
|
+
|
8
|
+
<%= @page.display_content_for_export %>
|
9
|
+
|
10
|
+
<div class="byline">
|
11
|
+
<%= @page.revisions? ? "Revised" : "Created" %> on <%= @page.pretty_created_at %>
|
12
|
+
by
|
13
|
+
<%= @page.author_link({ :mode => :export }) %>
|
14
|
+
</div>
|
15
|
+
|
16
|
+
<%= sub_template "bottom" %>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<%
|
2
|
+
@title = @page.plain_name
|
3
|
+
@hide_navigation = true
|
4
|
+
@style_additions = ".newWikiWord { background-color: white; font-style: italic; }"
|
5
|
+
@inline_style = true
|
6
|
+
%><%= sub_template "top" %>
|
7
|
+
|
8
|
+
<%= @page.display_published %>
|
9
|
+
|
10
|
+
<%= sub_template "bottom" %>
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<% @title = "Recently Revised" %>
|
2
|
+
<%= sub_template "top" %>
|
3
|
+
|
4
|
+
<% unless @categories.empty? %>
|
5
|
+
<div id="categories">
|
6
|
+
<strong>Categories</strong>:
|
7
|
+
[<a href=".">Any</a>]
|
8
|
+
<%= @category_links.join(', ') %>
|
9
|
+
</div>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
<% revision_date = Date.new(2100) %>
|
13
|
+
<ul>
|
14
|
+
<% for page in @pages_by_revision %>
|
15
|
+
<% if page.revised_on < revision_date %>
|
16
|
+
</ul><b><%= page.pretty_revised_on %></b><ul>
|
17
|
+
<% end %>
|
18
|
+
|
19
|
+
<li>
|
20
|
+
<a href="../show/<%= page.name %>"><%= page.plain_name %></a>
|
21
|
+
<div class="byline" style="margin-bottom: 0px">
|
22
|
+
by <%= page.author_link %>
|
23
|
+
at <%= page.created_at.strftime "%H:%M" %>
|
24
|
+
<%= "from #{page.author.ip}" if page.author.respond_to?(:ip) %>
|
25
|
+
</div>
|
26
|
+
</li>
|
27
|
+
|
28
|
+
<% revision_date = page.revised_on %>
|
29
|
+
<% end %>
|
30
|
+
|
31
|
+
<%= sub_template "bottom" %>
|
@@ -0,0 +1,87 @@
|
|
1
|
+
<% @title = "#{@page.plain_name} (Rev ##{@revision.number})" %><%= sub_template "top" %>
|
2
|
+
|
3
|
+
<div id="revision">
|
4
|
+
<%= @revision.display_content %>
|
5
|
+
</div>
|
6
|
+
|
7
|
+
<div id="changes" style="display: none">
|
8
|
+
<p style="background: #eee; padding: 3px; border: 1px solid silver">
|
9
|
+
<small>
|
10
|
+
Showing changes from revision #<%= @revision.number - 1 %> to #<%= @revision.number %>:
|
11
|
+
<ins class="diffins">Added</ins> | <del class="diffdel">Removed</del>
|
12
|
+
</small>
|
13
|
+
</p>
|
14
|
+
|
15
|
+
<%= @revision.display_diff %>
|
16
|
+
</div>
|
17
|
+
|
18
|
+
|
19
|
+
<div class="byline">
|
20
|
+
<%= "Revision from #{@revision.pretty_created_at} by" %>
|
21
|
+
<%= @page.web.make_link(@revision.author) %>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<div class="navigation">
|
25
|
+
|
26
|
+
<% if @revision.next_revision %>
|
27
|
+
<% if @revision.next_revision.number < (@page.revisions.length - 1) %>
|
28
|
+
<a href="../revision/<%= @page.name %>?rev=<%= @revision.next_revision.number %>" class="navlink">
|
29
|
+
<% else %>
|
30
|
+
<a href="../show/<%= @page.name %>" class="navlink">
|
31
|
+
<% end %>
|
32
|
+
Forward in time</a>
|
33
|
+
(<%= @revision.page.revisions.length - @revision.next_revision.number %> more)
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<% if @revision.next_revision && @revision.previous_revision %>
|
37
|
+
|
|
38
|
+
<% end %>
|
39
|
+
|
40
|
+
<% if @revision.previous_revision %>
|
41
|
+
<a href="../revision/<%= @page.name %>?rev=<%= @revision.previous_revision.number %>" class="navlink">Back in time</a>
|
42
|
+
(<%= @revision.previous_revision.number + 1 %> more)
|
43
|
+
<% end %>
|
44
|
+
|
45
|
+
| <a href="../show/<%= @page.name %>" class="navlink">See current</a>
|
46
|
+
|
47
|
+
<% if @revision.previous_revision %>
|
48
|
+
<span id="show_changes">
|
49
|
+
| <a href="#" onClick="toggleChanges(); return false;">See changes</a>
|
50
|
+
</span>
|
51
|
+
<span id="hide_changes" style="display: none">
|
52
|
+
| <a href="#" onClick="toggleChanges(); return false;">Hide changes</a>
|
53
|
+
</span>
|
54
|
+
<% end %>
|
55
|
+
|
56
|
+
| <a href="#" class="navlink" onClick="confirmRollback(); return false;">Rollback</a>
|
57
|
+
|
58
|
+
<% if @page.references.length > 0 %>
|
59
|
+
<small>
|
60
|
+
| Linked from: <%= @page.references.collect { |ref| "<a href='#{ref.name}'>#{ref.name}</a>" }.join(", ") %>
|
61
|
+
</small>
|
62
|
+
<% end %>
|
63
|
+
</div>
|
64
|
+
|
65
|
+
<script language="Javascript">
|
66
|
+
function toggleChanges() {
|
67
|
+
if (document.getElementById("changes").style.display == "none") {
|
68
|
+
document.getElementById("changes").style.display = "block";
|
69
|
+
document.getElementById("revision").style.display = "none";
|
70
|
+
document.getElementById("show_changes").style.display = "none";
|
71
|
+
document.getElementById("hide_changes").style.display = "inline";
|
72
|
+
} else {
|
73
|
+
document.getElementById("changes").style.display = "none";
|
74
|
+
document.getElementById("revision").style.display = "block";
|
75
|
+
document.getElementById("show_changes").style.display = "inline";
|
76
|
+
document.getElementById("hide_changes").style.display = "none";
|
77
|
+
}
|
78
|
+
}
|
79
|
+
|
80
|
+
function confirmRollback() {
|
81
|
+
if (confirm('Are you sure you want reset the page to this revision?')) {
|
82
|
+
location.href = '../rollback/<%= @page.name %>?rev=<%= @revision.number %>';
|
83
|
+
}
|
84
|
+
}
|
85
|
+
</script>
|
86
|
+
|
87
|
+
<%= sub_template "bottom" %>
|
@@ -0,0 +1,22 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
|
3
|
+
<channel>
|
4
|
+
<title><%= @web.name %></title>
|
5
|
+
<link><%= "#{@web_url}/show/HomePage" %></link>
|
6
|
+
<description>An Instiki wiki</description>
|
7
|
+
<language>en-us</language>
|
8
|
+
<ttl>40</ttl>
|
9
|
+
<% for page in @pages_by_revision %>
|
10
|
+
<item>
|
11
|
+
<title><%= page.plain_name %></title>
|
12
|
+
<% unless @hide_description %>
|
13
|
+
<description><%= CGI.escapeHTML(page.display_content) %></description>
|
14
|
+
<% end %>
|
15
|
+
<pubDate><%= page.created_at.strftime "%a, %e %b %Y %H:%M:%S %Z" %></pubDate>
|
16
|
+
<guid><%= "#{@web_url}/show/#{page.name}" %></guid>
|
17
|
+
<link><%= "#{@web_url}/show/#{page.name}" %></link>
|
18
|
+
<dc:creator><%= WikiWords.separate(page.author) %></dc:creator>
|
19
|
+
</item>
|
20
|
+
<% end %>
|
21
|
+
</channel>
|
22
|
+
</rss>
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<% @title = @results.length > 0 ? "#{@results.length} pages contains \"#{@params["query"]}\"" : "No pages contains \"#{@query}\"" %><%= sub_template "top" %>
|
2
|
+
|
3
|
+
<% if @results.length > 0 %>
|
4
|
+
<ul>
|
5
|
+
<% for page in @results %>
|
6
|
+
<li><a href="../show/<%= page.name %>"><%= page.plain_name %></a><br />
|
7
|
+
<%
|
8
|
+
idxs = page.content.scan(/.{0,30}#{@params["query"]}.{0,30}/im)
|
9
|
+
idxs.each do |i|
|
10
|
+
begin %>
|
11
|
+
...<%= i.to_s %>...<br /><%
|
12
|
+
rescue Exception => e
|
13
|
+
%><%= e.message %><%
|
14
|
+
end
|
15
|
+
end
|
16
|
+
%>
|
17
|
+
</li>
|
18
|
+
<% end %>
|
19
|
+
</ul>
|
20
|
+
<% else %>
|
21
|
+
<p>Perhaps you should try expanding your query. Remember that Instiki searches for entire phrases, so if you search for "all that jazz" it will not match pages that contain these words in separation—only as a sentence fragment.</p>
|
22
|
+
|
23
|
+
<p>If you're a high-tech computer wizard, you might even want try constructing a regular expression. That's actually what Instiki uses, so go right ahead and flex your "[a-z]*Leet?RegExpSkill(s|z)"</p>
|
24
|
+
<% end %>
|
25
|
+
|
26
|
+
<%= sub_template "bottom" %>
|
@@ -0,0 +1,23 @@
|
|
1
|
+
\documentclass[12pt,titlepage]{article}
|
2
|
+
|
3
|
+
\usepackage[danish]{babel} %danske tekster
|
4
|
+
\usepackage[OT1]{fontenc} %rigtige danske bogstaver...
|
5
|
+
\usepackage{a4}
|
6
|
+
\usepackage{graphicx}
|
7
|
+
\usepackage{ucs}
|
8
|
+
\usepackage[utf8]{inputenc}
|
9
|
+
\input epsf
|
10
|
+
|
11
|
+
%-------------------------------------------------------------------
|
12
|
+
|
13
|
+
\begin{document}
|
14
|
+
|
15
|
+
\sloppy
|
16
|
+
|
17
|
+
%-------------------------------------------------------------------
|
18
|
+
|
19
|
+
\section*{<%= @page.name %>}
|
20
|
+
|
21
|
+
<%= @tex_content %>
|
22
|
+
|
23
|
+
\end{document}
|
@@ -0,0 +1,35 @@
|
|
1
|
+
\documentclass[12pt,titlepage]{article}
|
2
|
+
|
3
|
+
\usepackage{fancyhdr}
|
4
|
+
\pagestyle{fancy}
|
5
|
+
|
6
|
+
\fancyhead[LE,RO]{}
|
7
|
+
\fancyhead[LO,RE]{\nouppercase{\bfseries \leftmark}}
|
8
|
+
\fancyfoot[C]{\thepage}
|
9
|
+
|
10
|
+
\usepackage[danish]{babel} %danske tekster
|
11
|
+
\usepackage{a4}
|
12
|
+
\usepackage{graphicx}
|
13
|
+
\usepackage{ucs}
|
14
|
+
\usepackage[utf8]{inputenc}
|
15
|
+
\input epsf
|
16
|
+
|
17
|
+
|
18
|
+
%-------------------------------------------------------------------
|
19
|
+
|
20
|
+
\title{<%= @web_name %>}
|
21
|
+
|
22
|
+
\begin{document}
|
23
|
+
|
24
|
+
\maketitle
|
25
|
+
|
26
|
+
\tableofcontents
|
27
|
+
\pagebreak
|
28
|
+
|
29
|
+
\sloppy
|
30
|
+
|
31
|
+
%-------------------------------------------------------------------
|
32
|
+
|
33
|
+
<%= @tex_content %>
|
34
|
+
|
35
|
+
\end{document}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
<% @title = "ToDo" %>
|
2
|
+
<%= sub_template "top" %>
|
3
|
+
|
4
|
+
<% num_items = @todo_items.inject(0) { |n, (p,i)| n += i.size } %>
|
5
|
+
<h3>There <%= num_items == 1 ? 'is' : 'are' %> <%= num_items.zero? ? "no" : @todo_items.size %> ToDo item<%= num_items != 1 ? 's' : '' %>.
|
6
|
+
</h3>
|
7
|
+
|
8
|
+
<ul>
|
9
|
+
<% today = Date.today
|
10
|
+
@todo_items.each do |page, items| %>
|
11
|
+
<li><%= page.link %>
|
12
|
+
<ul>
|
13
|
+
<% items.each do |item|
|
14
|
+
# default is the muted 'darkred', to prevent to many bright red
|
15
|
+
# items on one page: (See also chunks/todo.rb)
|
16
|
+
tclass = "todoFuture"
|
17
|
+
# next check is the item is dated:
|
18
|
+
d = ParseDate.parsedate(item[0]) rescue nil
|
19
|
+
if not d.nil? and not d.all? { |x| x.nil? }
|
20
|
+
# there's a date in the todo. display it accordingly
|
21
|
+
d[0] ||= today.year # make sure there's a 'year' component
|
22
|
+
d = Date.new(*d[0..2]) rescue nil
|
23
|
+
tclass = 'todo' if (not d.nil?) and ((today <=> d) > -1)
|
24
|
+
end %>
|
25
|
+
<li class="<%= tclass %>"><%= item %></li>
|
26
|
+
<% end %>
|
27
|
+
</ul>
|
28
|
+
</li>
|
29
|
+
<% end %>
|
30
|
+
</ul>
|
31
|
+
|
32
|
+
<% if num_items == 0 %>
|
33
|
+
<p>To make ToDo items appear here insert a 'todo' item in any page. Simply write at the start of any line 'todo' followed by a colon (':'), followed by a space and some text. For example:
|
34
|
+
<pre>todo: some text</pre></p>
|
35
|
+
<p> This text will be rendered in red on the page itself, and will also appear here in a list of todo items from all the pages.</p>
|
36
|
+
<p>This module also uses <a href='http://www.ruby-docs.org/stdlib/'>ParseDate</a>, which is a fairly smart module. If you write a date anywhere in the todo item's text, it will be picked up. If that date is today or in the past, the item will be colored bright red!<p>
|
37
|
+
<% end %>
|
38
|
+
|
39
|
+
<%= sub_template "bottom" %>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<% @title = "Wiki webs" %><%= sub_template "top" %>
|
2
|
+
|
3
|
+
<ul>
|
4
|
+
<% for web in @webs %>
|
5
|
+
<li>
|
6
|
+
<a href="/<%= web.address %>/show/HomePage"><%= web.name %></a>
|
7
|
+
(<%= web.pages.length %> pages by <%= web.authors.length %> authors)
|
8
|
+
<% if web.published then %>(<a href="/<%= web.address %>/published/HomePage">published</a>)<% end %>
|
9
|
+
</li>
|
10
|
+
<% end %>
|
11
|
+
</ul>
|
12
|
+
|
13
|
+
<%= sub_template "bottom" %>
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<h3>Wiki words</h3>
|
2
|
+
<p style="border-top: 1px dotted #ccc; margin-top: 0px">
|
3
|
+
Two or more uppercase words stuck together (camel case) or any phrase surrounded by doubble brackets is a wiki word. A camel-case wiki word can be escaped by putting \ in front of it.
|
4
|
+
</p>
|
5
|
+
<p>
|
6
|
+
Wiki words: <i>HomePage, ThreeWordsTogether, [[C++]], [[Let's play again!]]</i><br/>
|
7
|
+
Not wiki words: <i>IBM, School</i>
|
8
|
+
</p>
|
@@ -0,0 +1,177 @@
|
|
1
|
+
require 'erb'
|
2
|
+
require 'cgi'
|
3
|
+
require 'webrick'
|
4
|
+
include WEBrick
|
5
|
+
|
6
|
+
require 'view_helper'
|
7
|
+
|
8
|
+
class ActionControllerServlet < HTTPServlet::AbstractServlet
|
9
|
+
@@template_root = "./views"
|
10
|
+
def self.template_root() @@template_root end
|
11
|
+
def self.template_root=(template_root) @@template_root = template_root end
|
12
|
+
|
13
|
+
include ViewHelper
|
14
|
+
|
15
|
+
def do_POST(req, res) do_GET(req, res) end
|
16
|
+
|
17
|
+
def do_GET(req, res)
|
18
|
+
@req, @res = req, res
|
19
|
+
|
20
|
+
@res['Content-Type'] = "text/html; charset=utf-8"
|
21
|
+
@res['Pragma'] = "no-cache"
|
22
|
+
@res['Cache-Control'] = "no-cache"
|
23
|
+
|
24
|
+
@params = @req.query
|
25
|
+
@assigns = {}
|
26
|
+
@performed_render = @performed_redirect = false
|
27
|
+
|
28
|
+
@logger.info "Performing #{action_name}"
|
29
|
+
@logger.info " Parameters: #{@params.inspect}"
|
30
|
+
@logger.info " Cookies: #{@req.cookies.collect { |c| "#{c.name} => #{c.value}" }.join(", ") }"
|
31
|
+
|
32
|
+
perform_action
|
33
|
+
@res
|
34
|
+
end
|
35
|
+
|
36
|
+
protected
|
37
|
+
def template_root() self.class.template_root end
|
38
|
+
|
39
|
+
# Issues a HTTP 302 (location) redirect to the specified <tt>path</tt>. Query string
|
40
|
+
# parameters can be specified in the <tt>params</tt> hash and are automatically URL escaped.
|
41
|
+
# An <tt>anchor</tt> can also be specified (as a string).
|
42
|
+
def redirect_path(path, params = nil, anchor = nil)
|
43
|
+
path << build_query_string(params) unless params.nil?
|
44
|
+
path << "\##{anchor}" unless anchor.nil?
|
45
|
+
@res.set_redirect WEBrick::HTTPStatus::MovedPermanently, path
|
46
|
+
@performed_redirect = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# Redirects the browser to another action within the current controller, so redirect_path "pages"
|
50
|
+
# within a controller called WikiController would take the user to "http://www.example.com/wiki/pages"
|
51
|
+
def redirect_action(action, params = nil, anchor = nil)
|
52
|
+
redirect_path "/#{controller_name}/#{action}", params, anchor
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Compiles the template response and adds it to the response. If no template_name has been
|
57
|
+
# supplied, the action parameter parsed to the controller is used. So invoking
|
58
|
+
# render on a object initialized with myController.new("show_person") will compile the template
|
59
|
+
# located at "../views/show_person.rhtml". Notice that the ".rhtml" extension is postfixed
|
60
|
+
# to the template_name regardless of one was passed or that the action parameter was used.
|
61
|
+
def render(template_name = "#{controller_name}/#{action_name}")
|
62
|
+
@performed_render = true
|
63
|
+
@logger.info "Rendering: #{template_name}"
|
64
|
+
add_instance_variables_to_assigns
|
65
|
+
@res.body = template_result "#{template_root}/#{template_name}.rhtml"
|
66
|
+
end
|
67
|
+
|
68
|
+
def render_text(text)
|
69
|
+
@performed_render = true
|
70
|
+
@logger.info "Rendering in text"
|
71
|
+
@res.body = text
|
72
|
+
end
|
73
|
+
|
74
|
+
# Wrapper around render that presumes the current controller is used as a base for the action,
|
75
|
+
# so render_action("page") in WikiController will be equal to render("wiki/page")
|
76
|
+
def render_action(action_name)
|
77
|
+
render "#{controller_name}/#{action_name}"
|
78
|
+
end
|
79
|
+
|
80
|
+
def sub_template(template_name)
|
81
|
+
template_result "#{template_root}/#{template_name}.rhtml"
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns the value of the cookie matching +name+ (or nil if none is found).
|
85
|
+
def read_cookie(key)
|
86
|
+
cookies = @req.cookies.select { |cookie| cookie.name == key }
|
87
|
+
cookies.empty? ? nil : cookies.first.value
|
88
|
+
end
|
89
|
+
|
90
|
+
def write_cookie(key, value, permanent = false)
|
91
|
+
@logger.info "Writing cookie: #{key} => #{value}"
|
92
|
+
|
93
|
+
cookie = WEBrick::Cookie.new(key, value)
|
94
|
+
cookie.path = "/"
|
95
|
+
cookie.expires = Time.local(2030) if permanent
|
96
|
+
@res.cookies << cookie
|
97
|
+
end
|
98
|
+
|
99
|
+
|
100
|
+
# Returns the last part of the uri path ("page" in "/wiki/page") by default, but
|
101
|
+
# can be overwritten to implement mod_rewrite-like behaviour, such as "page" in "/wiki/page/home"
|
102
|
+
def action_name
|
103
|
+
@req.path.to_s.split(/\//).last
|
104
|
+
end
|
105
|
+
|
106
|
+
# Returns an array with each of the parts in the request as an element. So /something/cool/dude
|
107
|
+
# returns ["something", "cool", "dude"]
|
108
|
+
def request_path
|
109
|
+
request_path_parts = @req.path.to_s.split(/\//)
|
110
|
+
request_path_parts.length > 1 ? request_path_parts[1..-1] : []
|
111
|
+
end
|
112
|
+
|
113
|
+
# Can be overwritten by a controller class to implement shared behaviour for all the actions in
|
114
|
+
# the class, such as security measures
|
115
|
+
def before_action() end
|
116
|
+
|
117
|
+
|
118
|
+
private
|
119
|
+
# Wraps around all action calls to ensure the session is properly updated and closed.
|
120
|
+
# Figures out whether an action, such as "list", is implemented as show_list or do_list.
|
121
|
+
# The show_* type has precedence and automatically calls render after execution.
|
122
|
+
def perform_action
|
123
|
+
if before_action == false then return end
|
124
|
+
|
125
|
+
if action_methods.include?(action_name)
|
126
|
+
send(action_name)
|
127
|
+
render unless @performed_render || @performed_redirect || !@res.body.empty?
|
128
|
+
elsif template_exists_for_action
|
129
|
+
render
|
130
|
+
else
|
131
|
+
raise "No action responded to #{action_name}", caller
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
def add_instance_variables_to_assigns
|
136
|
+
instance_variables.each { |var|
|
137
|
+
next if protected_instance_variables.include?(var)
|
138
|
+
@assigns[var[1..-1]] = instance_variable_get(var)
|
139
|
+
}
|
140
|
+
end
|
141
|
+
|
142
|
+
def protected_instance_variables
|
143
|
+
[ "@assigns", "@performed_redirect", "@performed_render" ]
|
144
|
+
end
|
145
|
+
|
146
|
+
def action_methods
|
147
|
+
methods - Object.instance_methods
|
148
|
+
end
|
149
|
+
|
150
|
+
# Returns true if a template exists in the controller directory for the specified <tt>action_name</tt>,
|
151
|
+
# which would mean true if called for WikiController#changes and "/views/wiki/changes.rhtml" existed.
|
152
|
+
def template_exists_for_action
|
153
|
+
File.exist? action_template_path
|
154
|
+
end
|
155
|
+
|
156
|
+
def action_template_path(action = action_name)
|
157
|
+
"#{template_root}/#{controller_name}/#{action}.rhtml"
|
158
|
+
end
|
159
|
+
|
160
|
+
def template_result(template_path)
|
161
|
+
@assigns.each { |key, value| instance_variable_set "@#{key}", value }
|
162
|
+
ERB.new(IO.readlines(template_path).join).result(binding)
|
163
|
+
end
|
164
|
+
|
165
|
+
# Converts the class name from something like "OneModule::TwoModule::NeatController"
|
166
|
+
# to "neat".
|
167
|
+
def controller_name
|
168
|
+
self.class.to_s.split("::").last.sub(/Controller/, "").downcase
|
169
|
+
end
|
170
|
+
|
171
|
+
# Returns a query string with escaped keys and values from the passed hash.
|
172
|
+
def build_query_string(hash)
|
173
|
+
elements = []
|
174
|
+
hash.each { |key, value| elements << "#{CGI.escape(key)}=#{CGI.escape(value.to_s)}" }
|
175
|
+
"?" + elements.join("&")
|
176
|
+
end
|
177
|
+
end
|