Pimki 1.7.092 → 1.8.092
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.
- 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
data/README-PIMKI
CHANGED
|
@@ -1,178 +1,182 @@
|
|
|
1
|
-
What is Pimki?
|
|
2
|
-
================
|
|
3
|
-
|
|
4
|
-
Pimki is a Personal Information Manager based on Instiki's Wiki technology.
|
|
5
|
-
|
|
6
|
-
It has some added features over Instiki, while keeping (most of) the simplicity
|
|
7
|
-
of Instiki. Add added complication is installing GraphViz on the path. GraphViz
|
|
8
|
-
is available from: http://www.research.att.com/sw/tools/graphviz.
|
|
9
|
-
|
|
10
|
-
Instiki Features:
|
|
11
|
-
* Regular expression search: Find deep stuff really fast
|
|
12
|
-
* Revisions: Follow the changes on every page from birth. Rollback to an earlier rev
|
|
13
|
-
* Export to HTML or markup in a zip: Take the entire wiki with you home or for reference
|
|
14
|
-
* RSS feeds to track recently revised pages
|
|
15
|
-
* Multiple webs: Create separate wikis with their own namespace
|
|
16
|
-
* Password-protected webs: Keep it private
|
|
17
|
-
* Authors: Each revision is associated with an author, so you can see who changed what
|
|
18
|
-
* Reference tracker: Which other pages are pointing to the current?
|
|
19
|
-
* Speed: Using Madelein for persistence (all pages are in memory)
|
|
20
|
-
* Three markup choices: Textile (default / RedCloth), Markdown (BlueCloth), and RDoc
|
|
21
|
-
* Embedded webserver: Through WEBrick
|
|
22
|
-
* Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters
|
|
23
|
-
* Color diffs: Track changes through revisions
|
|
24
|
-
|
|
25
|
-
Pimki added features:
|
|
26
|
-
* Mind Map: a graph of wiki connections (made with GraphViz). All graphs can be
|
|
27
|
-
laid-out with the 4 GraphViz engines. Graph contents can be arranged as:
|
|
28
|
-
* Page -> linked pages
|
|
29
|
-
* Authors -> pages
|
|
30
|
-
* Categories -> pages
|
|
31
|
-
* Bliki: a blog integrated with the wiki. Blog entries are simply wiki-pages in
|
|
32
|
-
a special space. Can link from an entry to wiki pages via PageName or [[page name]]
|
|
33
|
-
and from pages to Bliki entries via [bliki[page name]].
|
|
34
|
-
* c2 Wiki links, via [c2[PageName]]. If you run multiple webs within Pimki, you
|
|
35
|
-
can now link between them using [web_address[PageName]].
|
|
36
|
-
* Todo Items & List:
|
|
37
|
-
* 'todo:' items are highlighted on each page.
|
|
38
|
-
* Added a capacity to pull and list todo items from all pages.
|
|
39
|
-
* On main list, items are highlighted according to date (if there is one).
|
|
40
|
-
* Added capacity to (persistently :) delete/rename pages through the 'All Pages'
|
|
41
|
-
list.
|
|
42
|
-
* Lots of web customization and administration options through the edit_web template.
|
|
43
|
-
* Added left-side menu. Content options are:
|
|
44
|
-
* Only pages that reference other pages (default)
|
|
45
|
-
* Only pages that belong to a specific category
|
|
46
|
-
* All pages: by name
|
|
47
|
-
* All pages: recently revised
|
|
48
|
-
* All pages: recently visited
|
|
49
|
-
* All pages: most often visited
|
|
50
|
-
* User definable wiki-text
|
|
51
|
-
* Added Glossary function: shows all acronyms defined in the web
|
|
52
|
-
* Expanded Search:
|
|
53
|
-
* Search also tries to match the page names (not just contents).
|
|
54
|
-
* Now showing part of sentance around match in search-results page
|
|
55
|
-
* Advanced Search
|
|
56
|
-
* Case sensitivity
|
|
57
|
-
* Search as regex, phrase or words
|
|
58
|
-
* Search pages and bliki entries
|
|
59
|
-
* Search in page names / contents
|
|
60
|
-
* Limit search to selected categories
|
|
61
|
-
* Limit search to selected authors
|
|
62
|
-
* Removed unnecessary (for me) stuff from the nav-bar: RSS, authors, export.
|
|
63
|
-
Moved to bottom of Home Page.
|
|
64
|
-
* Minor stylesheet tweaks.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
Command-line options:
|
|
68
|
-
Run "ruby pimki.rb --help"
|
|
69
|
-
|
|
70
|
-
History:
|
|
71
|
-
|
|
72
|
-
1.
|
|
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
|
-
- Added
|
|
121
|
-
(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
- Fixed problem
|
|
141
|
-
|
|
142
|
-
- Fixed
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
0.
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
1
|
+
What is Pimki?
|
|
2
|
+
================
|
|
3
|
+
|
|
4
|
+
Pimki is a Personal Information Manager based on Instiki's Wiki technology.
|
|
5
|
+
|
|
6
|
+
It has some added features over Instiki, while keeping (most of) the simplicity
|
|
7
|
+
of Instiki. Add added complication is installing GraphViz on the path. GraphViz
|
|
8
|
+
is available from: http://www.research.att.com/sw/tools/graphviz.
|
|
9
|
+
|
|
10
|
+
Instiki Features:
|
|
11
|
+
* Regular expression search: Find deep stuff really fast
|
|
12
|
+
* Revisions: Follow the changes on every page from birth. Rollback to an earlier rev
|
|
13
|
+
* Export to HTML or markup in a zip: Take the entire wiki with you home or for reference
|
|
14
|
+
* RSS feeds to track recently revised pages
|
|
15
|
+
* Multiple webs: Create separate wikis with their own namespace
|
|
16
|
+
* Password-protected webs: Keep it private
|
|
17
|
+
* Authors: Each revision is associated with an author, so you can see who changed what
|
|
18
|
+
* Reference tracker: Which other pages are pointing to the current?
|
|
19
|
+
* Speed: Using Madelein for persistence (all pages are in memory)
|
|
20
|
+
* Three markup choices: Textile (default / RedCloth), Markdown (BlueCloth), and RDoc
|
|
21
|
+
* Embedded webserver: Through WEBrick
|
|
22
|
+
* Internationalization: Wiki words in any latin, greek, cyrillian, or armenian characters
|
|
23
|
+
* Color diffs: Track changes through revisions
|
|
24
|
+
|
|
25
|
+
Pimki added features:
|
|
26
|
+
* Mind Map: a graph of wiki connections (made with GraphViz). All graphs can be
|
|
27
|
+
laid-out with the 4 GraphViz engines. Graph contents can be arranged as:
|
|
28
|
+
* Page -> linked pages
|
|
29
|
+
* Authors -> pages
|
|
30
|
+
* Categories -> pages
|
|
31
|
+
* Bliki: a blog integrated with the wiki. Blog entries are simply wiki-pages in
|
|
32
|
+
a special space. Can link from an entry to wiki pages via PageName or [[page name]]
|
|
33
|
+
and from pages to Bliki entries via [bliki[page name]].
|
|
34
|
+
* c2 Wiki links, via [c2[PageName]]. If you run multiple webs within Pimki, you
|
|
35
|
+
can now link between them using [web_address[PageName]].
|
|
36
|
+
* Todo Items & List:
|
|
37
|
+
* 'todo:' items are highlighted on each page.
|
|
38
|
+
* Added a capacity to pull and list todo items from all pages.
|
|
39
|
+
* On main list, items are highlighted according to date (if there is one).
|
|
40
|
+
* Added capacity to (persistently :) delete/rename pages through the 'All Pages'
|
|
41
|
+
list.
|
|
42
|
+
* Lots of web customization and administration options through the edit_web template.
|
|
43
|
+
* Added left-side menu. Content options are:
|
|
44
|
+
* Only pages that reference other pages (default)
|
|
45
|
+
* Only pages that belong to a specific category
|
|
46
|
+
* All pages: by name
|
|
47
|
+
* All pages: recently revised
|
|
48
|
+
* All pages: recently visited
|
|
49
|
+
* All pages: most often visited
|
|
50
|
+
* User definable wiki-text
|
|
51
|
+
* Added Glossary function: shows all acronyms defined in the web
|
|
52
|
+
* Expanded Search:
|
|
53
|
+
* Search also tries to match the page names (not just contents).
|
|
54
|
+
* Now showing part of sentance around match in search-results page
|
|
55
|
+
* Advanced Search
|
|
56
|
+
* Case sensitivity
|
|
57
|
+
* Search as regex, phrase or words
|
|
58
|
+
* Search pages and bliki entries
|
|
59
|
+
* Search in page names / contents
|
|
60
|
+
* Limit search to selected categories
|
|
61
|
+
* Limit search to selected authors
|
|
62
|
+
* Removed unnecessary (for me) stuff from the nav-bar: RSS, authors, export.
|
|
63
|
+
Moved to bottom of Home Page.
|
|
64
|
+
* Minor stylesheet tweaks.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
Command-line options:
|
|
68
|
+
Run "ruby pimki.rb --help"
|
|
69
|
+
|
|
70
|
+
History:
|
|
71
|
+
|
|
72
|
+
1.8.092 Bug Fixes & New features
|
|
73
|
+
- Many small & not-so-small bug fixes
|
|
74
|
+
- Still based on Instiki 0.9.2 for storage compatibility
|
|
75
|
+
|
|
76
|
+
1.7.092 Bug Fixes & New features
|
|
77
|
+
- Better control on multiple webs, including web administration and links between webs via [web_address[PageName]]
|
|
78
|
+
- Added Glossary function: shows all acronyms defined in the web
|
|
79
|
+
- Better export in anticipation of Pimki2
|
|
80
|
+
- Moved things back to the nav-bar
|
|
81
|
+
- Even more and better things at the web setup (edit_web) template
|
|
82
|
+
- Lots of bug fixes
|
|
83
|
+
|
|
84
|
+
1.6.092 Mainly bug fixes with some minor enhancements
|
|
85
|
+
- Squashed horrible restart bug
|
|
86
|
+
- Several bug fixes
|
|
87
|
+
- Upgraded to RedCloth 3.0.3, which seems stable enough
|
|
88
|
+
- RSS includes Bliki
|
|
89
|
+
- Added capacity to stop server through the edit_web template
|
|
90
|
+
- Added an error reporting template
|
|
91
|
+
- Can now display just the Mind Map image for printing
|
|
92
|
+
- Minor improvements to the publish interface, e.g. displaying menu
|
|
93
|
+
|
|
94
|
+
1.5.092 Bug fixes & new features release
|
|
95
|
+
- Several bug fixes
|
|
96
|
+
- RedCloth is now defaulting to 2.0.11. Controllable thru commandline.
|
|
97
|
+
- Advanced Search
|
|
98
|
+
- c2 wiki links via [c2[PageName]]
|
|
99
|
+
- FavIcon (working in Firefox)
|
|
100
|
+
- Madeleine Snapshot Controls (thru edit_web)
|
|
101
|
+
|
|
102
|
+
1.4.092 New features release
|
|
103
|
+
- Added a major/minor edit override for the default 'continous edit' when
|
|
104
|
+
revising a page.
|
|
105
|
+
- MarkDown can now be through RedCloth 3.0.0 (experimental) or BlueCloth.
|
|
106
|
+
- Integrated Instiki release 0.9.2 features and bug fixes.
|
|
107
|
+
- Todo@Context
|
|
108
|
+
- Edit page on double click (based on Mark Reid's patch to Instiki)
|
|
109
|
+
- Possibility to require edit password for each edit
|
|
110
|
+
- Persist user changes to free-wiki menu content
|
|
111
|
+
- Numerous bug fixes.
|
|
112
|
+
|
|
113
|
+
1.3.092 New features and bug fixes release
|
|
114
|
+
- Updated to RedCloth v3.0.0.
|
|
115
|
+
- Fixed problem with incorrect handling of some complex link formats and
|
|
116
|
+
<pre> tags. (Justin)
|
|
117
|
+
- Expanded search to look also in Bliki entries.
|
|
118
|
+
- Can now show diff between Bliki entry versions.
|
|
119
|
+
- Editing left-side menu is now password protected.
|
|
120
|
+
- Added capacity in Mind Map to filter displayed pages by category and/or
|
|
121
|
+
filter leaf nodes (i.e. pages that do not have links to other pages). This
|
|
122
|
+
cuts down on the anount of visual information to give a bit more topical
|
|
123
|
+
view of the web.
|
|
124
|
+
- Added custom symbols/elements: <:cbx> and <:cbxc> to display a checkbox
|
|
125
|
+
(and a checked checkbox).
|
|
126
|
+
- Added customization options through "Edit Web":
|
|
127
|
+
- Added capacity to set the prefered size of the Mind Map image.
|
|
128
|
+
- Customizable mapping of symbols/elements (in progress).
|
|
129
|
+
- Added capacity for custom link formats (in progress).
|
|
130
|
+
|
|
131
|
+
1.2.092 Bug-fix and minor enhancements release
|
|
132
|
+
- Fixed problem with free-content of menu. (Mark S)
|
|
133
|
+
- Fixed problem in persisting menu-type changes.
|
|
134
|
+
- Fixed broken images in Mind Map under Firefox 1.0
|
|
135
|
+
|
|
136
|
+
1.1.092 Bug-fix and minor enhancements release
|
|
137
|
+
- Changed storage path to be relative to CWD to avoid storing under gem
|
|
138
|
+
version directory. When running/installing service should normally
|
|
139
|
+
provide the --storage command-line parameter. (Chad)
|
|
140
|
+
- Fixed a problem with the bliki_new form that prevented saving the entry
|
|
141
|
+
due to debug code in the JS validation code of the entry name. (PragDave)
|
|
142
|
+
- Fixed problem with export and storage path relating to app-dir instead
|
|
143
|
+
of storage dir in Instiki core. (Prag Dave)
|
|
144
|
+
- Fixed problem of missing files in in tgz packaging (rake needs
|
|
145
|
+
PackagingTask defined _before_ GemPackageTask). (Ruben)
|
|
146
|
+
- Fixed require 'YAML' to correct 'yaml' in Instiki core. (Chad)
|
|
147
|
+
- Added capability to link from pages to Bliki entries. To use link via:
|
|
148
|
+
[bliki[entry name]]
|
|
149
|
+
- ToDo list picks up items from bliki entries and links to the entry (Ruben)
|
|
150
|
+
- Menu can be set as all pages belonging to a specific category. If you set
|
|
151
|
+
some page to a category e.g. 'menu', only those pages will appear on the
|
|
152
|
+
left-side menu.
|
|
153
|
+
|
|
154
|
+
1.0.092 Updated Initial Release
|
|
155
|
+
- Finalized Numbering scheme.
|
|
156
|
+
- Made available as a gem.
|
|
157
|
+
|
|
158
|
+
0.9.2-7 Initial Public Release
|
|
159
|
+
I have been working on Pimki for my own use for quite some time. It is
|
|
160
|
+
fairly mature and stable. The version number reflects the base Instiki
|
|
161
|
+
version (0.9.2; or actually the latest CVS that's markes so) and the
|
|
162
|
+
running number of my feature-addition releases.
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
Download latest from:
|
|
166
|
+
http://rubyforge.org/project/showfiles.php?group_id=447
|
|
167
|
+
|
|
168
|
+
Or go the Gem way and install through:
|
|
169
|
+
gem install pimki
|
|
170
|
+
|
|
171
|
+
Visit the official Pimki home page at:
|
|
172
|
+
http://pimki.rubyforge.org/
|
|
173
|
+
|
|
174
|
+
Visit the official Instiki wiki:
|
|
175
|
+
http://www.instiki.org/
|
|
176
|
+
|
|
177
|
+
License is the same as Ruby's.
|
|
178
|
+
|
|
179
|
+
--
|
|
180
|
+
Assaph Mehr
|
|
181
|
+
assaph@gmail.com
|
|
182
|
+
|
data/app/controllers/wiki.rb
CHANGED
|
@@ -1,943 +1,951 @@
|
|
|
1
|
-
require "cgi"
|
|
2
|
-
require "redcloth_for_tex"
|
|
3
|
-
|
|
4
|
-
RenderedTodo = Struct.new( :text, :context, :due_date )
|
|
5
|
-
|
|
6
|
-
class WikiController < ActionControllerServlet
|
|
7
|
-
EXPORT_DIRECTORY = WikiService.storage_path
|
|
8
|
-
|
|
9
|
-
def index
|
|
10
|
-
if web_address
|
|
11
|
-
check_external_req_and_redirect web
|
|
12
|
-
elsif !wiki.setup?
|
|
13
|
-
redirect_path "/new_system/"
|
|
14
|
-
elsif wiki.webs.length == 1
|
|
15
|
-
check_external_req_and_redirect wiki.webs.values.first
|
|
16
|
-
else
|
|
17
|
-
wiki.default_web ?
|
|
18
|
-
check_external_req_and_redirect(wiki.webs[wiki.default_web]) :
|
|
19
|
-
redirect_path("/web_list/")
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
def check_external_req_and_redirect web
|
|
24
|
-
if web.default_to_published and @req.addr[2] != @req.peeraddr[2]
|
|
25
|
-
redirect_action("published/", web.address)
|
|
26
|
-
else
|
|
27
|
-
redirect_show("HomePage", web.address)
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# Administrating the Instiki setup --------------------------------------------
|
|
32
|
-
|
|
33
|
-
def new_system
|
|
34
|
-
wiki.setup? ? redirect_path("/") : render
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def new_web
|
|
38
|
-
redirect_path("/") if wiki.system["password"].nil?
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def create_system
|
|
42
|
-
wiki.setup(@params["password"], @params["web_name"], @params["web_address"]) unless wiki.setup?
|
|
43
|
-
redirect_path "/"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
def create_web
|
|
47
|
-
redirect_path("/") unless wiki.authenticate(@params["system_password"])
|
|
48
|
-
wiki.create_web(@params["name"], @params["address"])
|
|
49
|
-
redirect_show("HomePage", @params["address"])
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
# Outside a single web --------------------------------------------------------
|
|
54
|
-
|
|
55
|
-
def web_list
|
|
56
|
-
@system, @webs = wiki.system, wiki.webs.values
|
|
57
|
-
render "wiki/web_list"
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
def login
|
|
61
|
-
render "wiki/login"
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def authenticate
|
|
65
|
-
password_check(@params["password"]) ? redirect_show("HomePage") : redirect_action("login")
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
def static_style_sheet() render "static_style_sheet" end
|
|
69
|
-
|
|
70
|
-
def stop
|
|
71
|
-
redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
|
|
72
|
-
|
|
73
|
-
begin
|
|
74
|
-
secs = @params['seconds'].to_i
|
|
75
|
-
raise if secs.zero?
|
|
76
|
-
@logger.warn "Pimki server will stop in #{secs} seconds!"
|
|
77
|
-
WikiService.request_stop
|
|
78
|
-
render_text "Pimki server will stop in #{secs} seconds!"
|
|
79
|
-
Thread.new { sleep secs; Kernel.exit! }
|
|
80
|
-
rescue
|
|
81
|
-
redirect_show("HomePage")
|
|
82
|
-
end
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
# Within a single web ---------------------------------------------------------
|
|
86
|
-
|
|
87
|
-
def parse_category
|
|
88
|
-
@categories = web.categories
|
|
89
|
-
@category = @params["category"]
|
|
90
|
-
@pages_in_category = web.select { |page| page.in_category?(@category) }
|
|
91
|
-
@pages_without_category = web.select { |page| page.categories.length == 0 }
|
|
92
|
-
if @category == 'none'
|
|
93
|
-
@pages_in_category = @pages_without_category
|
|
94
|
-
end
|
|
95
|
-
@set_name = ( @categories.include?(@category) ? "category '#{@category}'" : "the web" )
|
|
96
|
-
@category_links = @categories.map do |c|
|
|
97
|
-
(@category == c ? "<span class=\"selected\">[#{c}]</span>" : "<a href=\"?category=#{c}\">#{c}</a>")
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
def search
|
|
102
|
-
set_menu_pages
|
|
103
|
-
@query = @params["query"]
|
|
104
|
-
search_content = [nil, 'both', 'contents'].include? @params['fields']
|
|
105
|
-
search_names = [nil, 'both', 'names'].include? @params['fields']
|
|
106
|
-
|
|
107
|
-
case @params['expression']
|
|
108
|
-
when 'regex', nil
|
|
109
|
-
rex = Regexp.new @query, (Regexp::IGNORECASE unless @params['case'])
|
|
110
|
-
@results = if [nil, 'all', 'pages', nil].include? @params['where']
|
|
111
|
-
web.select do |page|
|
|
112
|
-
(search_names and rex.match(page.name)) or (search_content and rex.match(page.content))
|
|
113
|
-
end
|
|
114
|
-
else
|
|
115
|
-
[]
|
|
116
|
-
end
|
|
117
|
-
@bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
|
|
118
|
-
web.bliki.values.select do |entry|
|
|
119
|
-
(search_names and rex.match(entry.name)) or (search_content and rex.match(entry.content))
|
|
120
|
-
end
|
|
121
|
-
else
|
|
122
|
-
[]
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
when 'all'
|
|
126
|
-
words = @query.split(/\s/).reject { |w| w.empty? }
|
|
127
|
-
@results = if [nil, 'all', 'pages'].include? @params['where']
|
|
128
|
-
web.select do |page|
|
|
129
|
-
words.all? do |word|
|
|
130
|
-
(search_names and page.name.index(word)) or (search_content and page.content.index(word))
|
|
131
|
-
end
|
|
132
|
-
end
|
|
133
|
-
else
|
|
134
|
-
[]
|
|
135
|
-
end
|
|
136
|
-
@bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
|
|
137
|
-
web.bliki.values.select do |entry|
|
|
138
|
-
words.all? do |word|
|
|
139
|
-
(search_names and entry.name.index(word)) or (search_content and entry.content.index(word))
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
|
-
else
|
|
143
|
-
[]
|
|
144
|
-
end
|
|
145
|
-
|
|
146
|
-
when 'exact'
|
|
147
|
-
@results = if [nil, 'all', 'pages'].include? @params['where']
|
|
148
|
-
web.select do |page|
|
|
149
|
-
(search_names and page.name.index(@query)) or (search_content and page.content.index(@query))
|
|
150
|
-
end
|
|
151
|
-
else
|
|
152
|
-
[]
|
|
153
|
-
end
|
|
154
|
-
@bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
|
|
155
|
-
web.bliki.values.select do |entry|
|
|
156
|
-
(search_names and entry.name.index(@query)) or (search_content and entry.content.index(@query))
|
|
157
|
-
end
|
|
158
|
-
else
|
|
159
|
-
[]
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
if !@params['category'].nil? and @params['category'] != 'noselect'
|
|
164
|
-
@selected_categories = parse_multi_select 'category'
|
|
165
|
-
@results.reject! { |page| (page.categories & @selected_categories).empty? }
|
|
166
|
-
@bliki_results.reject! { |page| (page.categories & @selected_categories).empty? }
|
|
167
|
-
end
|
|
168
|
-
|
|
169
|
-
if !@params['author'].nil? and @params['author'] != 'noselect'
|
|
170
|
-
@selected_authors = parse_multi_select 'author'
|
|
171
|
-
@results.reject! { |page| (page.authors & @selected_authors).empty? }
|
|
172
|
-
@bliki_results.reject! { |page| (page.authors & @selected_authors).empty? }
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
redirect_show(@results.first.name) if @results.length == 1 && @bliki_results.length == 0
|
|
176
|
-
redirect_path("/#{web_address}/bliki_revision/#{@bliki_results.first.name}?rev=#{@bliki_results.first.revisions.size-1}") if @results.length == 0 && @bliki_results.length == 1
|
|
177
|
-
render_action "search"
|
|
178
|
-
end
|
|
179
|
-
|
|
180
|
-
def glossary
|
|
181
|
-
set_menu_pages
|
|
182
|
-
|
|
183
|
-
rex = %r{([A-Z\d]+)\(([\w\s]+)\)}
|
|
184
|
-
scan_results = web.select.map { |page| [page.link, page.content.scan(rex)] }
|
|
185
|
-
scan_results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
|
|
186
|
-
results = Hash.new { Array.new }
|
|
187
|
-
scan_results.each { |page, acronyms| acronyms.each { |ac| results[ac] += [page] } }
|
|
188
|
-
@results = results.map{ |(ac, df), pg|[[ac,df], pg.uniq] }.sort_by{ |(ac, df), pg| ac }
|
|
189
|
-
|
|
190
|
-
acronyms = @results.map { |(ac, df), pg| ac }
|
|
191
|
-
rex = %r{(#{acronyms.join('|')})[^\(]}
|
|
192
|
-
results = web.select.map { |page| [page.link, page.content.scan(rex)] }
|
|
193
|
-
results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
|
|
194
|
-
@undefined_on = Hash.new { Array.new }
|
|
195
|
-
results.each { |page, acronyms| acronyms.each { |ac| @undefined_on[ac[0]] += [page] } }
|
|
196
|
-
@undefined_on = @undefined_on.inject({}) { |hsh, (k, v)| hsh[k] = v.uniq; hsh }
|
|
197
|
-
end
|
|
198
|
-
|
|
199
|
-
def authors
|
|
200
|
-
set_menu_pages
|
|
201
|
-
@authors = web.select.authors
|
|
202
|
-
end
|
|
203
|
-
|
|
204
|
-
def recently_revised
|
|
205
|
-
parse_category
|
|
206
|
-
set_menu_pages
|
|
207
|
-
@pages_by_revision = @pages_in_category.by_revision
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def rss_with_content
|
|
211
|
-
@pages_by_revision = @rss_bliki_only ? [] : web.select.by_revision.first(15)
|
|
212
|
-
@bliki_entries = web.bliki_entries_by_date
|
|
213
|
-
@uri = @req.request_uri
|
|
214
|
-
host = @req.meta_vars["HTTP_X_FORWARDED_HOST"] || "#{@uri.host}:#{@uri.port.to_s}"
|
|
215
|
-
@web_url = "#{@uri.scheme}://#{host}/#{@web.address}"
|
|
216
|
-
@res["Content-Type"] = "text/xml"
|
|
217
|
-
render "wiki/rss_feed"
|
|
218
|
-
end
|
|
219
|
-
|
|
220
|
-
def rss_with_headlines
|
|
221
|
-
@hide_description = true
|
|
222
|
-
rss_with_content
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
def rss_bliki_only
|
|
226
|
-
@rss_bliki_only = true
|
|
227
|
-
rss_with_content
|
|
228
|
-
end
|
|
229
|
-
|
|
230
|
-
def rss_todo_items
|
|
231
|
-
todo
|
|
232
|
-
@display_todo = true
|
|
233
|
-
rss_with_content
|
|
234
|
-
end
|
|
235
|
-
|
|
236
|
-
def feeds
|
|
237
|
-
set_menu_pages
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
def list
|
|
241
|
-
parse_category
|
|
242
|
-
set_menu_pages
|
|
243
|
-
@pages_by_name = @pages_in_category.by_name
|
|
244
|
-
@page_names_that_are_wanted = @pages_in_category.wanted_pages
|
|
245
|
-
@pages_that_are_orphaned = @pages_in_category.orphaned_pages
|
|
246
|
-
|
|
247
|
-
if @req.query['Action']
|
|
248
|
-
# redirect_action 'list/' if web.check_pass_on_edit and not password_check(@params['password'])
|
|
249
|
-
|
|
250
|
-
case @req.query['Action']
|
|
251
|
-
when 'Delete' # Handle page deletion
|
|
252
|
-
wiki.delete_page(web_address, @req.query['del_sel_page_name'])
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
@params["
|
|
319
|
-
@params["
|
|
320
|
-
@params["
|
|
321
|
-
@params[
|
|
322
|
-
@params["
|
|
323
|
-
@params["
|
|
324
|
-
@params['
|
|
325
|
-
@params[
|
|
326
|
-
@params[
|
|
327
|
-
@params['
|
|
328
|
-
@params['
|
|
329
|
-
@params['
|
|
330
|
-
@params['
|
|
331
|
-
@
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
when '
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
when '
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
when '
|
|
351
|
-
WikiService.
|
|
352
|
-
|
|
353
|
-
when '
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
when '
|
|
357
|
-
wiki.
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
@
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
# sort the
|
|
418
|
-
todos.
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
when '
|
|
454
|
-
when '
|
|
455
|
-
when '
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
end
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
when '
|
|
505
|
-
@pngFile, @mapFile = web.
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
@
|
|
516
|
-
@
|
|
517
|
-
@
|
|
518
|
-
@
|
|
519
|
-
|
|
520
|
-
@
|
|
521
|
-
@
|
|
522
|
-
|
|
523
|
-
@
|
|
524
|
-
@
|
|
525
|
-
|
|
526
|
-
@
|
|
527
|
-
@
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
@
|
|
547
|
-
@
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
#
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
redirect_bliki
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
if
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
@
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
end
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
elsif
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
end
|
|
786
|
-
|
|
787
|
-
def
|
|
788
|
-
redirect_path "/#{web}/#{
|
|
789
|
-
end
|
|
790
|
-
|
|
791
|
-
def
|
|
792
|
-
"
|
|
793
|
-
end
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
def
|
|
806
|
-
|
|
807
|
-
end
|
|
808
|
-
|
|
809
|
-
def
|
|
810
|
-
|
|
811
|
-
end
|
|
812
|
-
|
|
813
|
-
def
|
|
814
|
-
|
|
815
|
-
end
|
|
816
|
-
|
|
817
|
-
def
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
end
|
|
831
|
-
|
|
832
|
-
def
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
end
|
|
915
|
-
|
|
916
|
-
def
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
else
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
1
|
+
require "cgi"
|
|
2
|
+
require "redcloth_for_tex"
|
|
3
|
+
|
|
4
|
+
RenderedTodo = Struct.new( :text, :context, :due_date )
|
|
5
|
+
|
|
6
|
+
class WikiController < ActionControllerServlet
|
|
7
|
+
EXPORT_DIRECTORY = WikiService.storage_path
|
|
8
|
+
|
|
9
|
+
def index
|
|
10
|
+
if web_address
|
|
11
|
+
check_external_req_and_redirect web
|
|
12
|
+
elsif !wiki.setup?
|
|
13
|
+
redirect_path "/new_system/"
|
|
14
|
+
elsif wiki.webs.length == 1
|
|
15
|
+
check_external_req_and_redirect wiki.webs.values.first
|
|
16
|
+
else
|
|
17
|
+
wiki.default_web ?
|
|
18
|
+
check_external_req_and_redirect(wiki.webs[wiki.default_web]) :
|
|
19
|
+
redirect_path("/web_list/")
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def check_external_req_and_redirect web
|
|
24
|
+
if web.default_to_published and @req.addr[2] != @req.peeraddr[2]
|
|
25
|
+
redirect_action("published/", web.address)
|
|
26
|
+
else
|
|
27
|
+
redirect_show("HomePage", web.address)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Administrating the Instiki setup --------------------------------------------
|
|
32
|
+
|
|
33
|
+
def new_system
|
|
34
|
+
wiki.setup? ? redirect_path("/") : render
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def new_web
|
|
38
|
+
redirect_path("/") if wiki.system["password"].nil?
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def create_system
|
|
42
|
+
wiki.setup(@params["password"], @params["web_name"], @params["web_address"]) unless wiki.setup?
|
|
43
|
+
redirect_path "/"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def create_web
|
|
47
|
+
redirect_path("/") unless wiki.authenticate(@params["system_password"])
|
|
48
|
+
wiki.create_web(@params["name"], @params["address"])
|
|
49
|
+
redirect_show("HomePage", @params["address"])
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Outside a single web --------------------------------------------------------
|
|
54
|
+
|
|
55
|
+
def web_list
|
|
56
|
+
@system, @webs = wiki.system, wiki.webs.values
|
|
57
|
+
render "wiki/web_list"
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def login
|
|
61
|
+
render "wiki/login"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def authenticate
|
|
65
|
+
password_check(@params["password"]) ? redirect_show("HomePage") : redirect_action("login")
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def static_style_sheet() render "static_style_sheet" end
|
|
69
|
+
|
|
70
|
+
def stop
|
|
71
|
+
redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
|
|
72
|
+
|
|
73
|
+
begin
|
|
74
|
+
secs = @params['seconds'].to_i
|
|
75
|
+
raise if secs.zero?
|
|
76
|
+
@logger.warn "Pimki server will stop in #{secs} seconds!"
|
|
77
|
+
WikiService.request_stop
|
|
78
|
+
render_text "Pimki server will stop in #{secs} seconds!"
|
|
79
|
+
Thread.new { sleep secs; Kernel.exit! }
|
|
80
|
+
rescue
|
|
81
|
+
redirect_show("HomePage")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
# Within a single web ---------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
def parse_category
|
|
88
|
+
@categories = web.categories
|
|
89
|
+
@category = @params["category"]
|
|
90
|
+
@pages_in_category = web.select { |page| page.in_category?(@category) }
|
|
91
|
+
@pages_without_category = web.select { |page| page.categories.length == 0 }
|
|
92
|
+
if @category == 'none'
|
|
93
|
+
@pages_in_category = @pages_without_category
|
|
94
|
+
end
|
|
95
|
+
@set_name = ( @categories.include?(@category) ? "category '#{@category}'" : "the web" )
|
|
96
|
+
@category_links = @categories.map do |c|
|
|
97
|
+
(@category == c ? "<span class=\"selected\">[#{c}]</span>" : "<a href=\"?category=#{c}\">#{c}</a>")
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def search
|
|
102
|
+
set_menu_pages
|
|
103
|
+
@query = @params["query"]
|
|
104
|
+
search_content = [nil, 'both', 'contents'].include? @params['fields']
|
|
105
|
+
search_names = [nil, 'both', 'names'].include? @params['fields']
|
|
106
|
+
|
|
107
|
+
case @params['expression']
|
|
108
|
+
when 'regex', nil
|
|
109
|
+
rex = Regexp.new @query, (Regexp::IGNORECASE unless @params['case'])
|
|
110
|
+
@results = if [nil, 'all', 'pages', nil].include? @params['where']
|
|
111
|
+
web.select do |page|
|
|
112
|
+
(search_names and rex.match(page.name)) or (search_content and rex.match(page.content))
|
|
113
|
+
end
|
|
114
|
+
else
|
|
115
|
+
[]
|
|
116
|
+
end
|
|
117
|
+
@bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
|
|
118
|
+
web.bliki.values.select do |entry|
|
|
119
|
+
(search_names and rex.match(entry.name)) or (search_content and rex.match(entry.content))
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
[]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
when 'all'
|
|
126
|
+
words = @query.split(/\s/).reject { |w| w.empty? }
|
|
127
|
+
@results = if [nil, 'all', 'pages'].include? @params['where']
|
|
128
|
+
web.select do |page|
|
|
129
|
+
words.all? do |word|
|
|
130
|
+
(search_names and page.name.index(word)) or (search_content and page.content.index(word))
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
else
|
|
134
|
+
[]
|
|
135
|
+
end
|
|
136
|
+
@bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
|
|
137
|
+
web.bliki.values.select do |entry|
|
|
138
|
+
words.all? do |word|
|
|
139
|
+
(search_names and entry.name.index(word)) or (search_content and entry.content.index(word))
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
else
|
|
143
|
+
[]
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
when 'exact'
|
|
147
|
+
@results = if [nil, 'all', 'pages'].include? @params['where']
|
|
148
|
+
web.select do |page|
|
|
149
|
+
(search_names and page.name.index(@query)) or (search_content and page.content.index(@query))
|
|
150
|
+
end
|
|
151
|
+
else
|
|
152
|
+
[]
|
|
153
|
+
end
|
|
154
|
+
@bliki_results = if [nil, 'all', 'bliki'].include? @params['where']
|
|
155
|
+
web.bliki.values.select do |entry|
|
|
156
|
+
(search_names and entry.name.index(@query)) or (search_content and entry.content.index(@query))
|
|
157
|
+
end
|
|
158
|
+
else
|
|
159
|
+
[]
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
if !@params['category'].nil? and @params['category'] != 'noselect'
|
|
164
|
+
@selected_categories = parse_multi_select 'category'
|
|
165
|
+
@results.reject! { |page| (page.categories & @selected_categories).empty? }
|
|
166
|
+
@bliki_results.reject! { |page| (page.categories & @selected_categories).empty? }
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
if !@params['author'].nil? and @params['author'] != 'noselect'
|
|
170
|
+
@selected_authors = parse_multi_select 'author'
|
|
171
|
+
@results.reject! { |page| (page.authors & @selected_authors).empty? }
|
|
172
|
+
@bliki_results.reject! { |page| (page.authors & @selected_authors).empty? }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
redirect_show(@results.first.name) if @results.length == 1 && @bliki_results.length == 0
|
|
176
|
+
redirect_path("/#{web_address}/bliki_revision/#{@bliki_results.first.name}?rev=#{@bliki_results.first.revisions.size-1}") if @results.length == 0 && @bliki_results.length == 1
|
|
177
|
+
render_action "search"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def glossary
|
|
181
|
+
set_menu_pages
|
|
182
|
+
|
|
183
|
+
rex = %r{([A-Z\d]+)\(([\w\s]+)\)}
|
|
184
|
+
scan_results = web.select.map { |page| [page.link, page.content.scan(rex)] }
|
|
185
|
+
scan_results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
|
|
186
|
+
results = Hash.new { Array.new }
|
|
187
|
+
scan_results.each { |page, acronyms| acronyms.each { |ac| results[ac] += [page] } }
|
|
188
|
+
@results = results.map{ |(ac, df), pg|[[ac,df], pg.uniq] }.sort_by{ |(ac, df), pg| ac }
|
|
189
|
+
|
|
190
|
+
acronyms = @results.map { |(ac, df), pg| ac }
|
|
191
|
+
rex = %r{(#{acronyms.join('|')})[^\(]}
|
|
192
|
+
results = web.select.map { |page| [page.link, page.content.scan(rex)] }
|
|
193
|
+
results += web.bliki.values.map { |entry| [link_to_bliki(entry), entry.content.scan(rex)] }
|
|
194
|
+
@undefined_on = Hash.new { Array.new }
|
|
195
|
+
results.each { |page, acronyms| acronyms.each { |ac| @undefined_on[ac[0]] += [page] } }
|
|
196
|
+
@undefined_on = @undefined_on.inject({}) { |hsh, (k, v)| hsh[k] = v.uniq; hsh }
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def authors
|
|
200
|
+
set_menu_pages
|
|
201
|
+
@authors = web.select.authors
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def recently_revised
|
|
205
|
+
parse_category
|
|
206
|
+
set_menu_pages
|
|
207
|
+
@pages_by_revision = @pages_in_category.by_revision
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def rss_with_content
|
|
211
|
+
@pages_by_revision = @rss_bliki_only ? [] : web.select.by_revision.first(15)
|
|
212
|
+
@bliki_entries = web.bliki_entries_by_date
|
|
213
|
+
@uri = @req.request_uri
|
|
214
|
+
host = @req.meta_vars["HTTP_X_FORWARDED_HOST"] || "#{@uri.host}:#{@uri.port.to_s}"
|
|
215
|
+
@web_url = "#{@uri.scheme}://#{host}/#{@web.address}"
|
|
216
|
+
@res["Content-Type"] = "text/xml"
|
|
217
|
+
render "wiki/rss_feed"
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def rss_with_headlines
|
|
221
|
+
@hide_description = true
|
|
222
|
+
rss_with_content
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
def rss_bliki_only
|
|
226
|
+
@rss_bliki_only = true
|
|
227
|
+
rss_with_content
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def rss_todo_items
|
|
231
|
+
todo
|
|
232
|
+
@display_todo = true
|
|
233
|
+
rss_with_content
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
def feeds
|
|
237
|
+
set_menu_pages
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def list
|
|
241
|
+
parse_category
|
|
242
|
+
set_menu_pages
|
|
243
|
+
@pages_by_name = @pages_in_category.by_name
|
|
244
|
+
@page_names_that_are_wanted = @pages_in_category.wanted_pages
|
|
245
|
+
@pages_that_are_orphaned = @pages_in_category.orphaned_pages
|
|
246
|
+
|
|
247
|
+
if @req.query['Action']
|
|
248
|
+
# redirect_action 'list/' if web.check_pass_on_edit and not password_check(@params['password'])
|
|
249
|
+
|
|
250
|
+
case @req.query['Action']
|
|
251
|
+
when 'Delete' # Handle page deletion
|
|
252
|
+
wiki.delete_page(web_address, @req.query['del_sel_page_name'])
|
|
253
|
+
clear_render_cache true
|
|
254
|
+
redirect_action "list/"
|
|
255
|
+
|
|
256
|
+
when 'Create' # Handle page creation
|
|
257
|
+
redirect_show @req.query['newpage']
|
|
258
|
+
|
|
259
|
+
when 'Rename' # Handle page rename
|
|
260
|
+
wiki.rename_page(web_address, @req.query['ren_sel_page_name'], @req.query['ren_newpage'])
|
|
261
|
+
clear_render_cache true
|
|
262
|
+
redirect_action "list/"
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
def export
|
|
269
|
+
set_menu_pages
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
def export_html
|
|
273
|
+
file_name = "#{web.address}-html-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
|
|
274
|
+
file_path = File.join EXPORT_DIRECTORY, file_name
|
|
275
|
+
|
|
276
|
+
export_pages_to_zip_file(file_path) unless FileTest.exists?(file_path)
|
|
277
|
+
send_export(file_name, file_path)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def export_markup
|
|
281
|
+
file_name = "#{web.address}-markup-#{web.revised_on.strftime("%Y-%m-%d-%H-%M")}.zip"
|
|
282
|
+
file_path = File.join EXPORT_DIRECTORY, file_name
|
|
283
|
+
|
|
284
|
+
export_markup_to_zip_file(file_path) unless FileTest.exists?(file_path)
|
|
285
|
+
send_export(file_name, file_path)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
def export_pdf
|
|
289
|
+
file_name = "#{web.address}-tex-#{web.revised_on.strftime('%Y-%m-%d-%H-%M')}"
|
|
290
|
+
file_path = File.join EXPORT_DIRECTORY, file_name
|
|
291
|
+
|
|
292
|
+
export_web_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
|
|
293
|
+
convert_tex_to_pdf(file_path + ".tex")
|
|
294
|
+
send_export(file_name + ".pdf", file_path + ".pdf")
|
|
295
|
+
end
|
|
296
|
+
|
|
297
|
+
def export_tex
|
|
298
|
+
file_name = "#{web.address}-tex-#{web.revised_on.strftime('%Y-%m-%d-%H-%M')}.tex"
|
|
299
|
+
file_path = File.join EXPORT_DIRECTORY, file_name
|
|
300
|
+
|
|
301
|
+
export_web_to_tex(file_path) unless FileTest.exists?(file_path)
|
|
302
|
+
send_export(file_name, file_path)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def edit_web #{{{
|
|
306
|
+
parse_category
|
|
307
|
+
set_mm_options
|
|
308
|
+
@snapshot_interval = WikiService.snapshot_interval_hours
|
|
309
|
+
end #}}}
|
|
310
|
+
|
|
311
|
+
def update_web
|
|
312
|
+
redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
|
|
313
|
+
|
|
314
|
+
parse_category
|
|
315
|
+
set_mm_options
|
|
316
|
+
|
|
317
|
+
wiki.update_web(
|
|
318
|
+
web.address, @params["address"], @params["name"],
|
|
319
|
+
@params["markup"].intern,
|
|
320
|
+
@params["color"], @params["additional_style"],
|
|
321
|
+
@params["safe_mode"] ? true : false,
|
|
322
|
+
@params["password"].empty? ? nil : @params["password"],
|
|
323
|
+
@params["published"] ? true : false,
|
|
324
|
+
@params['default_to_published'] ? true : false,
|
|
325
|
+
@params["brackets_only"] ? true : false,
|
|
326
|
+
@params["count_pages"] ? true : false,
|
|
327
|
+
@params['mind_map_size'],
|
|
328
|
+
@params['symbols_map'],
|
|
329
|
+
@params['links_map'],
|
|
330
|
+
@params['snapshots_interval'],
|
|
331
|
+
@params['enable_dclick_edit'] ? true : false,
|
|
332
|
+
@params['enable_menu'] ? true : false,
|
|
333
|
+
@params['check_pass_on_edit'] == 'each_edit',
|
|
334
|
+
@prog, @graph_type, @missing, @show_authors, @show_leaves, @selected_categories
|
|
335
|
+
)
|
|
336
|
+
|
|
337
|
+
redirect_show("HomePage", @params["address"])
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def administrate
|
|
341
|
+
@logger.info "Taking administrative action: #{@params['action']}"
|
|
342
|
+
redirect_show 'HomePage' unless wiki.authenticate(@params['system_password'])
|
|
343
|
+
case @params['action']
|
|
344
|
+
when 'Delete Orphan Pages'
|
|
345
|
+
wiki.remove_orphaned_pages(web_address)
|
|
346
|
+
|
|
347
|
+
when 'Clear Render Cache'
|
|
348
|
+
clear_render_cache true
|
|
349
|
+
|
|
350
|
+
when 'Force Data Snapshot'
|
|
351
|
+
WikiService.take_snapshot
|
|
352
|
+
|
|
353
|
+
when 'Clean Storage'
|
|
354
|
+
WikiService.clean_old_snapshots
|
|
355
|
+
|
|
356
|
+
when 'Make This Web Default'
|
|
357
|
+
wiki.default_web = web_address
|
|
358
|
+
|
|
359
|
+
when 'Remove This Web'
|
|
360
|
+
wiki.webs.delete web_address
|
|
361
|
+
redirect_path '/'
|
|
362
|
+
|
|
363
|
+
end
|
|
364
|
+
@message = 'Operation succeeded'
|
|
365
|
+
redirect_action 'edit_web/'
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
FAR_FUTURE = Date.new(4000,1,1).freeze
|
|
369
|
+
TODO_RE = %r{<todo-tag context='(.*?)' due_date='(.*?)'><span class="todo"><strong>TODO(?:[^:]*)?:</strong> (.*?)</span></todo-tag>}
|
|
370
|
+
|
|
371
|
+
def todo #{{{
|
|
372
|
+
parse_category
|
|
373
|
+
set_menu_pages
|
|
374
|
+
|
|
375
|
+
@context = @params['context']
|
|
376
|
+
@sort_order = @params['sort_order']
|
|
377
|
+
|
|
378
|
+
# the clear_render_cache hack to make sure we don't have old-style rendered
|
|
379
|
+
# todos is no longer needed - can go thru the edit web to explicitely clear the cache.
|
|
380
|
+
@todo_items = analyse_rendered_todo_items @pages_in_category.by_name
|
|
381
|
+
@bliki_todo_items = analyse_rendered_todo_items web.bliki.values
|
|
382
|
+
|
|
383
|
+
@context_links = @todo_items.clone.update(@bliki_todo_items).map { |page, items|
|
|
384
|
+
# 'items' contain the full 'todo' info
|
|
385
|
+
items.map { |item| item.context }
|
|
386
|
+
}.flatten.compact.uniq.reject { |c| c.nil? || c.empty? }.map { |context|
|
|
387
|
+
@context == context ?
|
|
388
|
+
"[<span class='selected'>#{context}</span>]" :
|
|
389
|
+
"<a href='?context=#{context}#{"&sort_order=#{@sort_order}" if @sort_order}'>#{context}</a>"
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
@todo_items = sort_and_filter_todo_items @todo_items, @sort_order, @context
|
|
393
|
+
@bliki_todo_items = sort_and_filter_todo_items @bliki_todo_items, @sort_order, @context
|
|
394
|
+
|
|
395
|
+
end #}}}
|
|
396
|
+
|
|
397
|
+
def analyse_rendered_todo_items pages
|
|
398
|
+
items = Hash.new { Array.new }
|
|
399
|
+
pages.each do |page|
|
|
400
|
+
if page.has_todos?
|
|
401
|
+
# Page has todo items. Get the rendered version (marked-up and with links):
|
|
402
|
+
# I specifically don't use the todo chunkss because I want the fully marked-up
|
|
403
|
+
# text of the item.
|
|
404
|
+
content = page.revisions.last.display_content
|
|
405
|
+
items[page] = content.scan(TODO_RE).map { |match|
|
|
406
|
+
RenderedTodo.new match[2], (match[0].empty? ? [] : match[0].split(',') ), (Date.parse(match[1]) rescue FAR_FUTURE)
|
|
407
|
+
}
|
|
408
|
+
end
|
|
409
|
+
end
|
|
410
|
+
items
|
|
411
|
+
end
|
|
412
|
+
|
|
413
|
+
def sort_and_filter_todo_items items, sort_order, context
|
|
414
|
+
case sort_order
|
|
415
|
+
when 'due_date'
|
|
416
|
+
result = items.map { |page, todos|
|
|
417
|
+
# sort the to items themselves
|
|
418
|
+
[page, todos.sort_by { |i| i.due_date } ]
|
|
419
|
+
}.sort_by { |page, todos|
|
|
420
|
+
# sort the pages by the one with the most urgent todo
|
|
421
|
+
todos.map{ |i| i.due_date }.min
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
else # default = sort by page name
|
|
425
|
+
result = items.sort_by { |page, items| page.name }
|
|
426
|
+
|
|
427
|
+
end
|
|
428
|
+
|
|
429
|
+
if context
|
|
430
|
+
# filter the items to those that are in context
|
|
431
|
+
result = result.map { |page, items|
|
|
432
|
+
[ page, items.select { |item| item.context.include? context } ]
|
|
433
|
+
}.select { |page, items| not items.empty? }
|
|
434
|
+
end
|
|
435
|
+
result
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def get_todo_display_style due_date
|
|
439
|
+
# default is the muted 'darkred', to prevent to many bright red
|
|
440
|
+
# items on one page: (See also chunks/todo.rb)
|
|
441
|
+
(due_date <=> Date.today) > -1 ? "todoFuture" : "todo"
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
def clear_render_cache dont_redirect=false
|
|
445
|
+
web.refresh_revisions
|
|
446
|
+
redirect_path "/#{web_address}/edit_web/" unless dont_redirect
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def set_menu_pages published = false #{{{
|
|
450
|
+
parse_category
|
|
451
|
+
@all_pages = web.select { true }
|
|
452
|
+
@menu_pages = case web.menu_type
|
|
453
|
+
when 'all' then @all_pages.by_name
|
|
454
|
+
when 'recent' then @all_pages.by_last_visited
|
|
455
|
+
when 'viewed' then @all_pages.by_most_viewed
|
|
456
|
+
when 'revised' then @all_pages.by_revision
|
|
457
|
+
when 'category' then web.select { |page| page.in_category?(web.menu_category) }
|
|
458
|
+
when 'user'
|
|
459
|
+
@menu_content = if Page === web.menu_content
|
|
460
|
+
web.menu_content.revisions.last.display_content
|
|
461
|
+
else
|
|
462
|
+
web.menu_content
|
|
463
|
+
end
|
|
464
|
+
@menu_content = @menu_content.gsub('/show/', '/published/').gsub( %r{<a href="../published/.*?">\?</a>}, '') if published
|
|
465
|
+
nil
|
|
466
|
+
when 'linkers'
|
|
467
|
+
web.select { |page|
|
|
468
|
+
page.wiki_words.size > 0
|
|
469
|
+
}.sort_by { |page| page.name }
|
|
470
|
+
end
|
|
471
|
+
if web.menu_limit && @menu_pages
|
|
472
|
+
@menu_pages = @menu_pages[0..web.menu_limit]
|
|
473
|
+
end
|
|
474
|
+
end #}}}
|
|
475
|
+
|
|
476
|
+
def bliki #{{{
|
|
477
|
+
set_menu_pages
|
|
478
|
+
@entries = web.bliki_entries_by_date
|
|
479
|
+
unless @req.query['authorname'].nil? || @req.query['authorname'] == 'noselect'
|
|
480
|
+
@entries = @entries.select { |page|
|
|
481
|
+
page.authors.include?(@req.query['authorname'])
|
|
482
|
+
}
|
|
483
|
+
end
|
|
484
|
+
unless @req.query['regexp'].nil?
|
|
485
|
+
@entries = @entries.select { |page|
|
|
486
|
+
page.content =~ /#{@req.query['regexp']}/i
|
|
487
|
+
}
|
|
488
|
+
end
|
|
489
|
+
@color = web.color
|
|
490
|
+
@authors = web.authors
|
|
491
|
+
end #}}}
|
|
492
|
+
|
|
493
|
+
def mind #{{{
|
|
494
|
+
parse_category
|
|
495
|
+
set_menu_pages
|
|
496
|
+
set_mm_options
|
|
497
|
+
|
|
498
|
+
@pngFile = @mapFile = nil
|
|
499
|
+
case @graph_type
|
|
500
|
+
when 'normal'
|
|
501
|
+
@pngFile, @mapFile = web.create_mind_map(@prog, @missing,
|
|
502
|
+
@show_authors, @show_leaves, @selected_categories, @mm_size)
|
|
503
|
+
|
|
504
|
+
when 'author'
|
|
505
|
+
@pngFile, @mapFile = web.create_author_graph(@prog, @selected_categories, @mm_size)
|
|
506
|
+
|
|
507
|
+
when 'category'
|
|
508
|
+
@pngFile, @mapFile = web.create_category_graph(@prog,
|
|
509
|
+
@show_authors, @selected_categories, @mm_size)
|
|
510
|
+
end
|
|
511
|
+
end #}}}
|
|
512
|
+
|
|
513
|
+
def set_mm_options #{{{
|
|
514
|
+
if @req.query.empty?
|
|
515
|
+
@prog = web.mm_prog
|
|
516
|
+
@graph_type = web.mm_graph_type
|
|
517
|
+
@missing = @pages_in_category.wanted_pages if web.mm_show_missing
|
|
518
|
+
@show_authors = web.mm_show_authors
|
|
519
|
+
@show_leaves = web.mm_show_leaves
|
|
520
|
+
@selected_categories = web.mm_selected_categories
|
|
521
|
+
@mm_size = web.mind_map_size
|
|
522
|
+
else
|
|
523
|
+
@prog = @req.query['draw_type'] || 'neato'
|
|
524
|
+
@graph_type = @req.query['graph_type'] || 'normal'
|
|
525
|
+
@missing = @pages_in_category.wanted_pages if @req.query['missing']
|
|
526
|
+
@show_authors = @req.query['show_authors'] == 'on'
|
|
527
|
+
@show_leaves = @req.query.empty? || @req.query['show_leaves'] == 'on'
|
|
528
|
+
|
|
529
|
+
@selected_categories = parse_multi_select 'selected_categs'
|
|
530
|
+
@selected_categories = [] if @selected_categories.include? 'all'
|
|
531
|
+
@mm_size = @params['mind_map_size'] || web.mind_map_size
|
|
532
|
+
end
|
|
533
|
+
end #}}}
|
|
534
|
+
|
|
535
|
+
def parse_multi_select field #{{{
|
|
536
|
+
if @req.body
|
|
537
|
+
@req.body.split('&').map { |pair|
|
|
538
|
+
pair.split('=') }.select { |k,v|
|
|
539
|
+
k == field }.map { |k,v| v }
|
|
540
|
+
else
|
|
541
|
+
[]
|
|
542
|
+
end
|
|
543
|
+
end #}}}
|
|
544
|
+
|
|
545
|
+
def edit_menu #{{{
|
|
546
|
+
@menu_type = web.menu_type
|
|
547
|
+
@menu_content = web.menu_content
|
|
548
|
+
@list_limit = web.menu_limit
|
|
549
|
+
@list_limit += 1 if @list_limit >= -1
|
|
550
|
+
@author = default_author
|
|
551
|
+
end #}}}
|
|
552
|
+
|
|
553
|
+
def save_menu #{{{
|
|
554
|
+
redirect_show("HomePage") unless wiki.authenticate(@params["system_password"])
|
|
555
|
+
|
|
556
|
+
unless @req.query['action'] == 'Cancel Update'
|
|
557
|
+
type = @req.query['type']
|
|
558
|
+
content = @req.query['content']
|
|
559
|
+
sel_category = @req.query['sel_category']
|
|
560
|
+
author = @req.query['author']
|
|
561
|
+
|
|
562
|
+
limit = @req.query['limit'].to_i rescue nil
|
|
563
|
+
limit = 20 unless limit
|
|
564
|
+
limit -= 1 if limit >= 0
|
|
565
|
+
|
|
566
|
+
# need to go through the WikiService to persist the command:
|
|
567
|
+
wiki.save_menu_pref(web_address, type, limit, content, sel_category, Author.new(author, remote_ip))
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
redirect_action 'edit_web/' # go back to web options page
|
|
571
|
+
end #}}}
|
|
572
|
+
|
|
573
|
+
def get_map_img
|
|
574
|
+
file_name = "map.png"
|
|
575
|
+
file_path = File.join WikiService.storage_path, file_name
|
|
576
|
+
send_export(file_name, file_path, "image/png")
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
def adv_search
|
|
580
|
+
parse_category
|
|
581
|
+
set_menu_pages
|
|
582
|
+
end
|
|
583
|
+
|
|
584
|
+
# Within a single page --------------------------------------------------------
|
|
585
|
+
|
|
586
|
+
def show
|
|
587
|
+
set_menu_pages
|
|
588
|
+
if @page = wiki.read_page(web_address, page_name)
|
|
589
|
+
unless page_name == 'HomePage'
|
|
590
|
+
# HomePage should not be in the menu as there's a link at the top.
|
|
591
|
+
@page.last_visited = Time.now
|
|
592
|
+
@page.viewed += 1
|
|
593
|
+
end
|
|
594
|
+
begin
|
|
595
|
+
render_action "page"
|
|
596
|
+
rescue => e
|
|
597
|
+
$stderr << e.backtrace.join("\n")
|
|
598
|
+
redirect_action "edit/#{CGI.escape(page_name)}?msg=#{CGI.escape(e.message)}"
|
|
599
|
+
end
|
|
600
|
+
else
|
|
601
|
+
if page_name
|
|
602
|
+
redirect_action "new/#{CGI.escape(page_name)}"
|
|
603
|
+
else
|
|
604
|
+
redirect_show "HomePage"
|
|
605
|
+
end
|
|
606
|
+
end
|
|
607
|
+
end
|
|
608
|
+
|
|
609
|
+
def published
|
|
610
|
+
set_menu_pages true
|
|
611
|
+
if web.published then @page = wiki.read_page(web_address, page_name || "HomePage") else redirect_show("HomePage") end
|
|
612
|
+
end
|
|
613
|
+
|
|
614
|
+
def print
|
|
615
|
+
@page = wiki.read_page(web_address, page_name)
|
|
616
|
+
end
|
|
617
|
+
|
|
618
|
+
def tex
|
|
619
|
+
@page = wiki.read_page(web_address, page_name)
|
|
620
|
+
@tex_content = RedClothForTex.new(@page.content).to_tex
|
|
621
|
+
end
|
|
622
|
+
|
|
623
|
+
def pdf
|
|
624
|
+
page = wiki.read_page(web_address, page_name)
|
|
625
|
+
safe_page_name = page.name.gsub(/\W/, "")
|
|
626
|
+
file_name = "#{safe_page_name}-#{web.address}-#{page.created_at.strftime("%Y-%m-%d-%H-%M")}"
|
|
627
|
+
file_path = File.join EXPORT_DIRECTORY, file_name
|
|
628
|
+
|
|
629
|
+
export_page_to_tex(file_path + ".tex") unless FileTest.exists?(file_path + ".tex")
|
|
630
|
+
convert_tex_to_pdf(file_path + ".tex")
|
|
631
|
+
send_export(file_name + ".pdf", file_path + ".pdf")
|
|
632
|
+
end
|
|
633
|
+
|
|
634
|
+
def new
|
|
635
|
+
# redirect_show("HomePage") if web.check_pass_on_edit and not password_check(@params['password'])
|
|
636
|
+
@page_name, @author = page_name, default_author
|
|
637
|
+
end
|
|
638
|
+
|
|
639
|
+
def edit
|
|
640
|
+
@page = wiki.read_page(web_address, page_name)
|
|
641
|
+
|
|
642
|
+
if !@page.locked?(Time.now) || @params["break_lock"]
|
|
643
|
+
@page.lock(Time.now, default_author)
|
|
644
|
+
@author = default_author
|
|
645
|
+
render
|
|
646
|
+
else
|
|
647
|
+
render "wiki/locked"
|
|
648
|
+
end
|
|
649
|
+
end
|
|
650
|
+
|
|
651
|
+
def cancel_edit
|
|
652
|
+
@page = wiki.read_page(web_address, page_name)
|
|
653
|
+
@page.unlock
|
|
654
|
+
redirect_show
|
|
655
|
+
end
|
|
656
|
+
|
|
657
|
+
def save
|
|
658
|
+
# if web.check_pass_on_edit and not password_check(@params['password'])
|
|
659
|
+
# wiki.read_page(web_address, page_name).unlock if web.pages[page_name]
|
|
660
|
+
# redirect_show("HomePage")
|
|
661
|
+
# end
|
|
662
|
+
|
|
663
|
+
if web.pages[page_name]
|
|
664
|
+
page = wiki.revise_page(
|
|
665
|
+
web_address, page_name, @params["content"], Time.now,
|
|
666
|
+
Author.new(@params["author"], remote_ip), @params['edit_type']
|
|
667
|
+
)
|
|
668
|
+
|
|
669
|
+
page.unlock
|
|
670
|
+
else
|
|
671
|
+
page = wiki.write_page(
|
|
672
|
+
web_address, page_name, @params["content"], Time.now,
|
|
673
|
+
Author.new(@params["author"], remote_ip)
|
|
674
|
+
)
|
|
675
|
+
end
|
|
676
|
+
|
|
677
|
+
write_cookie("author", @params["author"], true)
|
|
678
|
+
redirect_show(page_name)
|
|
679
|
+
end
|
|
680
|
+
|
|
681
|
+
def revision
|
|
682
|
+
redirect_show 'HomePage' if page_name.nil?
|
|
683
|
+
set_menu_pages
|
|
684
|
+
@page = wiki.read_page(web_address, page_name)
|
|
685
|
+
@revision = @page.revisions[@params["rev"].to_i]
|
|
686
|
+
end
|
|
687
|
+
|
|
688
|
+
def rollback
|
|
689
|
+
# redirect_show("HomePage") if web.check_pass_on_edit and not password_check(@params['password'])
|
|
690
|
+
|
|
691
|
+
@page = wiki.read_page(web_address, page_name)
|
|
692
|
+
@revision = @page.revisions[@params["rev"].to_i]
|
|
693
|
+
end
|
|
694
|
+
|
|
695
|
+
# Bliki ----------------------------------------------------------------------
|
|
696
|
+
|
|
697
|
+
def bliki_delete
|
|
698
|
+
# redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
|
|
699
|
+
|
|
700
|
+
wiki.delete_bliki_entry(web_address, page_name)
|
|
701
|
+
clear_render_cache true
|
|
702
|
+
redirect_bliki
|
|
703
|
+
end
|
|
704
|
+
|
|
705
|
+
def bliki_edit
|
|
706
|
+
# redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
|
|
707
|
+
|
|
708
|
+
@page = wiki.read_bliki_entry(web_address, page_name)
|
|
709
|
+
|
|
710
|
+
if !@page.locked?(Time.now) || @params["break_lock"]
|
|
711
|
+
@page.lock(Time.now, default_author)
|
|
712
|
+
@author = default_author
|
|
713
|
+
render
|
|
714
|
+
else
|
|
715
|
+
@bliki_entry = true
|
|
716
|
+
render "wiki/locked"
|
|
717
|
+
end
|
|
718
|
+
end
|
|
719
|
+
|
|
720
|
+
def cancel_bliki_edit
|
|
721
|
+
@page = wiki.read_bliki_entry(web_address, page_name)
|
|
722
|
+
@page.unlock if @page
|
|
723
|
+
redirect_bliki
|
|
724
|
+
end
|
|
725
|
+
|
|
726
|
+
def bliki_new
|
|
727
|
+
@entry_name = @params['entry_name']
|
|
728
|
+
@author = default_author
|
|
729
|
+
end
|
|
730
|
+
|
|
731
|
+
def bliki_save
|
|
732
|
+
# redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
|
|
733
|
+
|
|
734
|
+
pname = page_name || @params["pagename"]
|
|
735
|
+
if web.bliki[pname]
|
|
736
|
+
page = wiki.revise_bliki_entry(web_address, pname, @params["content"], Time.now, @params["author"])
|
|
737
|
+
page.unlock
|
|
738
|
+
else
|
|
739
|
+
page = wiki.write_bliki_entry(web_address, pname, @params["content"], Time.now, @params["author"])
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
write_cookie("author", @params["author"])
|
|
743
|
+
redirect_bliki
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
def bliki_revision
|
|
747
|
+
parse_category
|
|
748
|
+
set_menu_pages
|
|
749
|
+
@page = wiki.read_bliki_entry(web_address, page_name || @params['pagename'])
|
|
750
|
+
if @page.nil?
|
|
751
|
+
render_text "Unable to find bliki entry #{page_name || @params['pagename']}"
|
|
752
|
+
return
|
|
753
|
+
end
|
|
754
|
+
@revision = @page.revisions[@params["rev"].to_i] || @page.revisions.last
|
|
755
|
+
end
|
|
756
|
+
|
|
757
|
+
def rollback_bliki
|
|
758
|
+
# redirect_bliki if web.check_pass_on_edit and not password_check(@params['password'])
|
|
759
|
+
|
|
760
|
+
@page = wiki.read_bliki_entry(web_address, page_name)
|
|
761
|
+
wiki.rollback_bliki_entry(web_address, page_name, @params["rev"].to_i, Time.now)
|
|
762
|
+
redirect_bliki
|
|
763
|
+
end
|
|
764
|
+
|
|
765
|
+
# ----------------------------------------------------------------------------
|
|
766
|
+
|
|
767
|
+
protected
|
|
768
|
+
def before_action
|
|
769
|
+
if in_a_web? && !authorized?(web_address) && !%w( login authenticate published ).include?(action_name)
|
|
770
|
+
redirect_action("login")
|
|
771
|
+
return false
|
|
772
|
+
elsif in_a_web?
|
|
773
|
+
@web, @page_name, @action_name = web, page_name, action_name
|
|
774
|
+
end
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
def action_name
|
|
778
|
+
if in_a_web?
|
|
779
|
+
request_path[1]
|
|
780
|
+
elsif action_methods.include?(request_path[0])
|
|
781
|
+
request_path[0]
|
|
782
|
+
else
|
|
783
|
+
"index"
|
|
784
|
+
end
|
|
785
|
+
end
|
|
786
|
+
|
|
787
|
+
def redirect_show(page = @page.name, web = web_address)
|
|
788
|
+
redirect_path "/#{web}/show/#{CGI.escape(page)}"
|
|
789
|
+
end
|
|
790
|
+
|
|
791
|
+
def redirect_bliki
|
|
792
|
+
redirect_path "/#{web_address}/bliki/"
|
|
793
|
+
end
|
|
794
|
+
|
|
795
|
+
def redirect_action(action, web = web_address)
|
|
796
|
+
redirect_path "/#{web}/#{action}"
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
def link_to_bliki(entry, web = web_address) #{{{
|
|
800
|
+
"<a class='existingWikiWord' href='/#{web}/bliki_revision/#{entry.name}?rev=#{entry.revisions.size-1}'>#{entry.name}</a>"
|
|
801
|
+
end #}}}
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
private
|
|
805
|
+
def wiki
|
|
806
|
+
WikiService.instance
|
|
807
|
+
end
|
|
808
|
+
|
|
809
|
+
def web
|
|
810
|
+
wiki.webs[web_address]
|
|
811
|
+
end
|
|
812
|
+
|
|
813
|
+
def in_a_web?
|
|
814
|
+
request_path.length > 1
|
|
815
|
+
end
|
|
816
|
+
|
|
817
|
+
def web_address
|
|
818
|
+
request_path[0]
|
|
819
|
+
end
|
|
820
|
+
|
|
821
|
+
def page_name
|
|
822
|
+
CGI.unescape(request_path[2]) if request_path[2]
|
|
823
|
+
end
|
|
824
|
+
|
|
825
|
+
def authorized?(web_address)
|
|
826
|
+
web.nil? ||
|
|
827
|
+
web.password.nil? ||
|
|
828
|
+
(read_cookie(web_address) && read_cookie(web_address) == web.password) ||
|
|
829
|
+
password_check(@params["password"])
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
def default_author
|
|
833
|
+
read_cookie("author") || "AnonymousCoward"
|
|
834
|
+
end
|
|
835
|
+
|
|
836
|
+
def password_check(password)
|
|
837
|
+
web && @params["password"] == web.password && write_cookie(web_address, @params["password"])
|
|
838
|
+
end
|
|
839
|
+
|
|
840
|
+
def export_pages_to_zip_file(zip_file_path)
|
|
841
|
+
Zip::ZipOutputStream.open(zip_file_path) do |zos|
|
|
842
|
+
web.select.by_name.each do |@page|
|
|
843
|
+
zos.put_next_entry(@page.name + ".html")
|
|
844
|
+
zos.puts(template_engine("print").result(binding))
|
|
845
|
+
end
|
|
846
|
+
|
|
847
|
+
zos.put_next_entry "pages-metadata.txt"
|
|
848
|
+
web.select.by_name.each do |page|
|
|
849
|
+
zos.puts "#{page.name}: by #{page.author}, created on #{page.pretty_created_at}"
|
|
850
|
+
end
|
|
851
|
+
|
|
852
|
+
web.select_bliki.by_name.each do |@page|
|
|
853
|
+
zos.put_next_entry("bliki/#{@page.name}.html")
|
|
854
|
+
zos.puts(template_engine("print").result(binding))
|
|
855
|
+
end
|
|
856
|
+
|
|
857
|
+
zos.put_next_entry "bliki/bliki-metadata.txt"
|
|
858
|
+
web.select_bliki.by_name.each do |page|
|
|
859
|
+
zos.puts "#{page.name}: by #{page.author}, created on #{page.revisions.first.pretty_created_at}"
|
|
860
|
+
end
|
|
861
|
+
|
|
862
|
+
zos.put_next_entry("index.html")
|
|
863
|
+
zos.puts('<html><head><META HTTP-EQUIV="Refresh" CONTENT="0;URL=HomePage.html"></head></html>')
|
|
864
|
+
end
|
|
865
|
+
end
|
|
866
|
+
|
|
867
|
+
def export_markup_to_zip_file(zip_file_path)
|
|
868
|
+
Zip::ZipOutputStream.open(zip_file_path) do |zos|
|
|
869
|
+
web.select.by_name.each do |page|
|
|
870
|
+
zos.put_next_entry(page.name + ".#{web.markup}")
|
|
871
|
+
zos.puts(page.content)
|
|
872
|
+
end
|
|
873
|
+
|
|
874
|
+
zos.put_next_entry "pages-metadata.txt"
|
|
875
|
+
web.select.by_name.each do |page|
|
|
876
|
+
zos.puts "#{page.name}: by #{page.author}, created on #{page.pretty_created_at}"
|
|
877
|
+
end
|
|
878
|
+
|
|
879
|
+
web.select_bliki.by_name.each do |page|
|
|
880
|
+
zos.put_next_entry("bliki/#{page.name}.#{web.markup}")
|
|
881
|
+
zos.puts(page.content)
|
|
882
|
+
end
|
|
883
|
+
|
|
884
|
+
zos.put_next_entry "bliki/bliki-metadata.txt"
|
|
885
|
+
web.select_bliki.by_name.each do |page|
|
|
886
|
+
zos.puts "#{page.name}: by #{page.author}, created on #{page.revisions.first.pretty_created_at}"
|
|
887
|
+
end
|
|
888
|
+
end
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
def export_web_to_tex(file_path)
|
|
892
|
+
@web_name = web.name
|
|
893
|
+
@tex_content = table_of_contents(web.pages["HomePage"].content.dup, render_tex_web)
|
|
894
|
+
File.open(file_path, "w") { |f| f.write(template_engine("tex_web").result(binding)) }
|
|
895
|
+
end
|
|
896
|
+
|
|
897
|
+
def render_tex_web
|
|
898
|
+
pages = web.select.by_name.inject({}) do |tex_web, page|
|
|
899
|
+
tex_web[page.name] = RedClothForTex.new(page.content).to_tex
|
|
900
|
+
tex_web
|
|
901
|
+
end
|
|
902
|
+
|
|
903
|
+
bliki_entries = web.select_bliki.by_name.inject({}) do |tex_web, page|
|
|
904
|
+
tex_web["bliki/#{page.name}"] = RedClothForTex.new(page.content).to_tex
|
|
905
|
+
tex_web
|
|
906
|
+
end
|
|
907
|
+
|
|
908
|
+
pages.update bliki_entries
|
|
909
|
+
end
|
|
910
|
+
|
|
911
|
+
def export_page_to_tex(file_path)
|
|
912
|
+
tex
|
|
913
|
+
File.open(file_path, "w") { |f| f.write(template_engine("tex").result(binding)) }
|
|
914
|
+
end
|
|
915
|
+
|
|
916
|
+
def convert_tex_to_pdf(tex_path)
|
|
917
|
+
`cd #{File.dirname(tex_path)}; pdflatex --interaction=scrollmode '#{File.basename(tex_path)}'`
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
def truncate(text, length = 30, truncate_string = "...")
|
|
921
|
+
if text.length > length then text[0..(length - 3)] + truncate_string else text end
|
|
922
|
+
end
|
|
923
|
+
|
|
924
|
+
def render_markup_help
|
|
925
|
+
if web
|
|
926
|
+
markup = web.markup
|
|
927
|
+
markup = 'markdown' if markup.to_s =~ /markdown/
|
|
928
|
+
sub_template("#{markup}_help")
|
|
929
|
+
else
|
|
930
|
+
''
|
|
931
|
+
end
|
|
932
|
+
end
|
|
933
|
+
|
|
934
|
+
def send_export(file_name, file_path, content_type = "application/zip")
|
|
935
|
+
@res["Content-Type"] = content_type
|
|
936
|
+
@res["Content-Disposition"] = "attachment; filename=#{file_name}"
|
|
937
|
+
@res["Content-Length"] = File.size(file_path)
|
|
938
|
+
File.open(file_path, "rb") { |f| @res.body = f.read }
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
def template_engine(template_name)
|
|
942
|
+
ERB.new(IO.readlines(action_template_path(template_name)).join)
|
|
943
|
+
end
|
|
944
|
+
|
|
945
|
+
def remote_ip
|
|
946
|
+
$stderr << "#{@req.meta_vars['HTTP_X_FORWARDED_FOR']} || #{@req.meta_vars['REMOTE_ADDR']}"
|
|
947
|
+
@req.meta_vars["HTTP_X_FORWARDED_FOR"] || @req.meta_vars["REMOTE_ADDR"]
|
|
948
|
+
end
|
|
949
|
+
end
|
|
950
|
+
|
|
943
951
|
# jEdit :folding=indent:collapseFolds=2:
|