olelo 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (282) hide show
  1. data/.gitignore +10 -0
  2. data/.gitmodules +3 -0
  3. data/Gemfile +3 -0
  4. data/README.markdown +104 -0
  5. data/Rakefile +92 -0
  6. data/bin/olelo +5 -0
  7. data/config.ru +86 -0
  8. data/config/aspects.rb +256 -0
  9. data/config/config.yml.default +154 -0
  10. data/config/initializers/00-mime_types.rb +29 -0
  11. data/config/initializers/01-slim.rb +2 -0
  12. data/config/interwiki.yml +11 -0
  13. data/doc/AUTHORS +7 -0
  14. data/doc/LICENSE +22 -0
  15. data/lib/olelo.rb +39 -0
  16. data/lib/olelo/application.rb +294 -0
  17. data/lib/olelo/attributes.rb +285 -0
  18. data/lib/olelo/config.rb +88 -0
  19. data/lib/olelo/extensions.rb +252 -0
  20. data/lib/olelo/helper.rb +290 -0
  21. data/lib/olelo/hooks.rb +142 -0
  22. data/lib/olelo/html_safe.rb +29 -0
  23. data/lib/olelo/initializer.rb +76 -0
  24. data/lib/olelo/locale.rb +63 -0
  25. data/lib/olelo/locale.yml +284 -0
  26. data/lib/olelo/menu.rb +101 -0
  27. data/lib/olelo/middleware/blacklist.rb +25 -0
  28. data/lib/olelo/middleware/degrade_mime_type.rb +19 -0
  29. data/lib/olelo/middleware/flash.rb +97 -0
  30. data/lib/olelo/middleware/force_encoding.rb +41 -0
  31. data/lib/olelo/page.rb +266 -0
  32. data/lib/olelo/patch.rb +311 -0
  33. data/lib/olelo/plugin.rb +188 -0
  34. data/lib/olelo/repository.rb +225 -0
  35. data/lib/olelo/routing.rb +223 -0
  36. data/lib/olelo/templates.rb +30 -0
  37. data/lib/olelo/user.rb +132 -0
  38. data/lib/olelo/util.rb +233 -0
  39. data/lib/olelo/version.rb +3 -0
  40. data/lib/olelo/virtualfs.rb +161 -0
  41. data/lib/rack/olelo_patches.rb +33 -0
  42. data/lib/rack/relative_redirect.rb +44 -0
  43. data/lib/rack/static_cache.rb +93 -0
  44. data/lib/yard/addons.rb +1 -0
  45. data/lib/yard/addons/hook_handler.rb +25 -0
  46. data/lib/yard/addons/override_tag.rb +14 -0
  47. data/lib/yard/addons/route_handler.rb +33 -0
  48. data/lib/yard/addons/sanitize_anchor.rb +16 -0
  49. data/olelo.gemspec +31 -0
  50. data/plugins/aspects/changelog.rb +45 -0
  51. data/plugins/aspects/documentbrowser.rb +57 -0
  52. data/plugins/aspects/download.rb +11 -0
  53. data/plugins/aspects/highlight.rb +8 -0
  54. data/plugins/aspects/image.rb +41 -0
  55. data/plugins/aspects/imageinfo.rb +64 -0
  56. data/plugins/aspects/locale.yml +60 -0
  57. data/plugins/aspects/main.rb +199 -0
  58. data/plugins/aspects/pageinfo.rb +37 -0
  59. data/plugins/aspects/source.rb +6 -0
  60. data/plugins/aspects/subpages.rb +44 -0
  61. data/plugins/aspects/text.rb +9 -0
  62. data/plugins/blog/blog.css +1 -0
  63. data/plugins/blog/blog.scss +37 -0
  64. data/plugins/blog/locale.yml +12 -0
  65. data/plugins/blog/main.rb +85 -0
  66. data/plugins/editor/locale.yml +18 -0
  67. data/plugins/editor/markup/main.rb +3 -0
  68. data/plugins/editor/markup/script.js +10 -0
  69. data/plugins/editor/markup/script/00-jquery.textselection.js +267 -0
  70. data/plugins/editor/markup/script/01-olelo.markupeditor.js +116 -0
  71. data/plugins/editor/markup/script/init.js +10 -0
  72. data/plugins/editor/preview.rb +52 -0
  73. data/plugins/editor/recaptcha.rb +56 -0
  74. data/plugins/filters/creole.rb +37 -0
  75. data/plugins/filters/disposition.rb +9 -0
  76. data/plugins/filters/editsection.rb +67 -0
  77. data/plugins/filters/fix_img_tag.rb +16 -0
  78. data/plugins/filters/html_wrapper.rb +12 -0
  79. data/plugins/filters/interwiki.rb +19 -0
  80. data/plugins/filters/link_classifier.rb +26 -0
  81. data/plugins/filters/locale.yml +15 -0
  82. data/plugins/filters/main.rb +202 -0
  83. data/plugins/filters/markdown_nowiki.rb +15 -0
  84. data/plugins/filters/numbering.xsl +93 -0
  85. data/plugins/filters/orgmode.rb +6 -0
  86. data/plugins/filters/rubypants.rb +6 -0
  87. data/plugins/filters/s5/main.rb +32 -0
  88. data/plugins/filters/s5/s5.xsl +118 -0
  89. data/plugins/filters/tilt.rb +17 -0
  90. data/plugins/filters/toc.rb +50 -0
  91. data/plugins/filters/xhtml2latex.xsl +232 -0
  92. data/plugins/filters/xslt.rb +22 -0
  93. data/plugins/gallery/gallery.css +1 -0
  94. data/plugins/gallery/gallery.scss +28 -0
  95. data/plugins/gallery/main.rb +34 -0
  96. data/plugins/misc/fancybox/images/blank.gif +0 -0
  97. data/plugins/misc/fancybox/images/fancy_close.png +0 -0
  98. data/plugins/misc/fancybox/images/fancy_loading.png +0 -0
  99. data/plugins/misc/fancybox/images/fancy_nav_left.png +0 -0
  100. data/plugins/misc/fancybox/images/fancy_nav_right.png +0 -0
  101. data/plugins/misc/fancybox/images/fancy_shadow_e.png +0 -0
  102. data/plugins/misc/fancybox/images/fancy_shadow_n.png +0 -0
  103. data/plugins/misc/fancybox/images/fancy_shadow_ne.png +0 -0
  104. data/plugins/misc/fancybox/images/fancy_shadow_nw.png +0 -0
  105. data/plugins/misc/fancybox/images/fancy_shadow_s.png +0 -0
  106. data/plugins/misc/fancybox/images/fancy_shadow_se.png +0 -0
  107. data/plugins/misc/fancybox/images/fancy_shadow_sw.png +0 -0
  108. data/plugins/misc/fancybox/images/fancy_shadow_w.png +0 -0
  109. data/plugins/misc/fancybox/images/fancy_title_left.png +0 -0
  110. data/plugins/misc/fancybox/images/fancy_title_main.png +0 -0
  111. data/plugins/misc/fancybox/images/fancy_title_over.png +0 -0
  112. data/plugins/misc/fancybox/images/fancy_title_right.png +0 -0
  113. data/plugins/misc/fancybox/images/fancybox-x.png +0 -0
  114. data/plugins/misc/fancybox/images/fancybox-y.png +0 -0
  115. data/plugins/misc/fancybox/images/fancybox.png +0 -0
  116. data/plugins/misc/fancybox/jquery.fancybox.css +1 -0
  117. data/plugins/misc/fancybox/jquery.fancybox.scss +323 -0
  118. data/plugins/misc/fancybox/main.rb +4 -0
  119. data/plugins/misc/fancybox/script.js +37 -0
  120. data/plugins/misc/fancybox/script/00-jquery.mousewheel.js +84 -0
  121. data/plugins/misc/fancybox/script/01-jquery.easing.js +205 -0
  122. data/plugins/misc/fancybox/script/02-jquery.fancybox.js +1156 -0
  123. data/plugins/misc/fancybox/script/init.js +18 -0
  124. data/plugins/misc/system.rb +192 -0
  125. data/plugins/misc/variables.rb +29 -0
  126. data/plugins/misc/webdav.rb +45 -0
  127. data/plugins/repositories/git_grep.rb +69 -0
  128. data/plugins/repositories/gitrb_repository.rb +204 -0
  129. data/plugins/repositories/locale.yml +12 -0
  130. data/plugins/repositories/rugged_repository.rb +454 -0
  131. data/plugins/security/acl.rb +57 -0
  132. data/plugins/security/basic_auth.rb +21 -0
  133. data/plugins/security/locale.yml +21 -0
  134. data/plugins/security/persistent_login.rb +32 -0
  135. data/plugins/security/portal.rb +28 -0
  136. data/plugins/security/private_wiki.rb +24 -0
  137. data/plugins/security/readonly_wiki.rb +25 -0
  138. data/plugins/security/stack.rb +20 -0
  139. data/plugins/security/yamlfile.rb +66 -0
  140. data/plugins/tags/code.rb +6 -0
  141. data/plugins/tags/footnotes.rb +35 -0
  142. data/plugins/tags/gist-embed.css +123 -0
  143. data/plugins/tags/gist.rb +13 -0
  144. data/plugins/tags/html.rb +57 -0
  145. data/plugins/tags/include.rb +20 -0
  146. data/plugins/tags/main.rb +353 -0
  147. data/plugins/tags/math.rb +117 -0
  148. data/plugins/tags/scripting.rb +64 -0
  149. data/plugins/tags/sort.rb +7 -0
  150. data/plugins/tags/tabs.rb +20 -0
  151. data/plugins/treeview/images/collapsed.png +0 -0
  152. data/plugins/treeview/images/expanded.png +0 -0
  153. data/plugins/treeview/images/menu.png +0 -0
  154. data/plugins/treeview/images/tree.png +0 -0
  155. data/plugins/treeview/images/wait.gif +0 -0
  156. data/plugins/treeview/main.rb +16 -0
  157. data/plugins/treeview/script.js +5 -0
  158. data/plugins/treeview/script/00-jquery.treeview.js +164 -0
  159. data/plugins/treeview/script/init.js +25 -0
  160. data/plugins/treeview/treeview.css +1 -0
  161. data/plugins/treeview/treeview.scss +113 -0
  162. data/plugins/utils/assets.rb +74 -0
  163. data/plugins/utils/cache.rb +53 -0
  164. data/plugins/utils/image_magick.rb +34 -0
  165. data/plugins/utils/pygments.css +1 -0
  166. data/plugins/utils/pygments.rb +50 -0
  167. data/plugins/utils/pygments.scss +83 -0
  168. data/plugins/utils/semaphore.rb +50 -0
  169. data/plugins/utils/shell.rb +45 -0
  170. data/plugins/utils/store.rb +315 -0
  171. data/plugins/utils/worker.rb +36 -0
  172. data/plugins/utils/xml.rb +29 -0
  173. data/static/images/favicon.png +0 -0
  174. data/static/script.js +267 -0
  175. data/static/script/00-json2.js +486 -0
  176. data/static/script/01-jstorage.js +217 -0
  177. data/static/script/02-jquery.js +9440 -0
  178. data/static/script/03-jquery.ui.core.js +337 -0
  179. data/static/script/04-jquery.ui.widget.js +502 -0
  180. data/static/script/05-jquery.ui.position.js +517 -0
  181. data/static/script/06-jquery.ui.menu.js +609 -0
  182. data/static/script/07-jquery.ui.autocomplete.js +601 -0
  183. data/static/script/08-olelo.i18n.js +37 -0
  184. data/static/script/09-olelo.unsaved.js +68 -0
  185. data/static/script/10-olelo.historytable.js +40 -0
  186. data/static/script/11-olelo.pagination.js +18 -0
  187. data/static/script/13-olelo.tabwidget.js +57 -0
  188. data/static/script/14-olelo.timeago.js +70 -0
  189. data/static/script/15-olelo.underliner.js +31 -0
  190. data/static/script/16-olelo.ui.combobox.js +32 -0
  191. data/static/script/init.js +48 -0
  192. data/static/themes/atlantis/constants.scss +15 -0
  193. data/static/themes/atlantis/iehacks.scss +38 -0
  194. data/static/themes/atlantis/images/actions/delete.png +0 -0
  195. data/static/themes/atlantis/images/actions/edit.png +0 -0
  196. data/static/themes/atlantis/images/actions/history.png +0 -0
  197. data/static/themes/atlantis/images/actions/home.png +0 -0
  198. data/static/themes/atlantis/images/actions/move.png +0 -0
  199. data/static/themes/atlantis/images/actions/new.png +0 -0
  200. data/static/themes/atlantis/images/actions/page.png +0 -0
  201. data/static/themes/atlantis/images/bg/button.png +0 -0
  202. data/static/themes/atlantis/images/bg/container.png +0 -0
  203. data/static/themes/atlantis/images/bg/content.png +0 -0
  204. data/static/themes/atlantis/images/bg/footer.png +0 -0
  205. data/static/themes/atlantis/images/bg/header.jpg +0 -0
  206. data/static/themes/atlantis/images/bg/header.orig.jpg +0 -0
  207. data/static/themes/atlantis/images/bg/header_gray.jpg +0 -0
  208. data/static/themes/atlantis/images/bug.png +0 -0
  209. data/static/themes/atlantis/images/filetypes/7z.png +0 -0
  210. data/static/themes/atlantis/images/filetypes/_archive.png +0 -0
  211. data/static/themes/atlantis/images/filetypes/_audio.png +0 -0
  212. data/static/themes/atlantis/images/filetypes/_code.png +0 -0
  213. data/static/themes/atlantis/images/filetypes/_linux.png +0 -0
  214. data/static/themes/atlantis/images/filetypes/_picture.png +0 -0
  215. data/static/themes/atlantis/images/filetypes/_video.png +0 -0
  216. data/static/themes/atlantis/images/filetypes/bz2.png +0 -0
  217. data/static/themes/atlantis/images/filetypes/doc.png +0 -0
  218. data/static/themes/atlantis/images/filetypes/flac.png +0 -0
  219. data/static/themes/atlantis/images/filetypes/gz.png +0 -0
  220. data/static/themes/atlantis/images/filetypes/html.png +0 -0
  221. data/static/themes/atlantis/images/filetypes/java.png +0 -0
  222. data/static/themes/atlantis/images/filetypes/jpg.png +0 -0
  223. data/static/themes/atlantis/images/filetypes/midi.png +0 -0
  224. data/static/themes/atlantis/images/filetypes/mp3.png +0 -0
  225. data/static/themes/atlantis/images/filetypes/ogg.png +0 -0
  226. data/static/themes/atlantis/images/filetypes/pdf.png +0 -0
  227. data/static/themes/atlantis/images/filetypes/php.png +0 -0
  228. data/static/themes/atlantis/images/filetypes/png.png +0 -0
  229. data/static/themes/atlantis/images/filetypes/ppt.png +0 -0
  230. data/static/themes/atlantis/images/filetypes/psd.png +0 -0
  231. data/static/themes/atlantis/images/filetypes/rar.png +0 -0
  232. data/static/themes/atlantis/images/filetypes/rb.png +0 -0
  233. data/static/themes/atlantis/images/filetypes/sh.png +0 -0
  234. data/static/themes/atlantis/images/filetypes/tar.png +0 -0
  235. data/static/themes/atlantis/images/filetypes/txt.png +0 -0
  236. data/static/themes/atlantis/images/filetypes/wma.png +0 -0
  237. data/static/themes/atlantis/images/filetypes/xls.png +0 -0
  238. data/static/themes/atlantis/images/filetypes/zip.png +0 -0
  239. data/static/themes/atlantis/images/folder.png +0 -0
  240. data/static/themes/atlantis/images/folder_open.png +0 -0
  241. data/static/themes/atlantis/images/loading.gif +0 -0
  242. data/static/themes/atlantis/images/loading.xcf +0 -0
  243. data/static/themes/atlantis/images/not_found.png +0 -0
  244. data/static/themes/atlantis/images/page.png +0 -0
  245. data/static/themes/atlantis/images/search.png +0 -0
  246. data/static/themes/atlantis/layout.scss +115 -0
  247. data/static/themes/atlantis/menu.scss +99 -0
  248. data/static/themes/atlantis/print.scss +129 -0
  249. data/static/themes/atlantis/screen.scss +495 -0
  250. data/static/themes/atlantis/style.css +3 -0
  251. data/static/themes/lib/autocomplete.scss +39 -0
  252. data/static/themes/lib/headlines.scss +10 -0
  253. data/static/themes/lib/horizontal-list.scss +31 -0
  254. data/static/themes/lib/patch.scss +88 -0
  255. data/static/themes/lib/reset.scss +114 -0
  256. data/static/themes/lib/rounded.scss +46 -0
  257. data/static/themes/lib/shadow.scss +14 -0
  258. data/test/config_test.rb +28 -0
  259. data/test/factory_test.rb +29 -0
  260. data/test/hash_extensions_test.rb +16 -0
  261. data/test/helper.rb +38 -0
  262. data/test/hooks_test.rb +85 -0
  263. data/test/object_extensions_test.rb +20 -0
  264. data/test/page_test.rb +168 -0
  265. data/test/request_test.rb +166 -0
  266. data/test/string_extensions_test.rb +32 -0
  267. data/test/templates_test.rb +39 -0
  268. data/test/util_test.rb +71 -0
  269. data/views/changes.slim +22 -0
  270. data/views/compare.slim +8 -0
  271. data/views/delete.slim +9 -0
  272. data/views/deleted.slim +2 -0
  273. data/views/edit.slim +65 -0
  274. data/views/error.slim +6 -0
  275. data/views/history.slim +20 -0
  276. data/views/layout.slim +38 -0
  277. data/views/login.slim +37 -0
  278. data/views/move.slim +10 -0
  279. data/views/not_found.slim +6 -0
  280. data/views/profile.slim +26 -0
  281. data/views/show.slim +9 -0
  282. metadata +488 -0
@@ -0,0 +1,64 @@
1
+ description 'Image information aspect'
2
+ dependencies 'utils/image_magick'
3
+
4
+ Aspect.create(:imageinfo, :priority => 1, :layout => true, :cacheable => true, :accepts => %r{^image/}) do
5
+ def call(context, page)
6
+ @page = page
7
+ identify = ImageMagick.identify('-format', '%m %h %w', '-').run(page.content).split(' ')
8
+ @type = identify[0]
9
+ @geometry = "#{identify[1]}x#{identify[2]}"
10
+ begin
11
+ @exif = Shell.exif('-m', '/dev/stdin').run(page.content)
12
+ @exif.force_encoding(Encoding.default_external)
13
+ @exif = @exif.split("\n").map {|line| line.split("\t") }
14
+ @exif = nil if !@exif[0] || !@exif[0][1]
15
+ rescue => ex
16
+ Olelo.logger.warn "Exif data could not be read: #{ex.message}"
17
+ @exif = nil
18
+ end
19
+ render :info
20
+ end
21
+ end
22
+
23
+ __END__
24
+ @@ info.slim
25
+ p
26
+ a href=build_path(@page, :aspect => 'image')
27
+ img src=build_path(@page, :aspect => 'image', :geometry => '640x480>') alt=@page.title
28
+ h3= :information.t
29
+ table
30
+ tbody
31
+ tr
32
+ td= :name.t
33
+ td= @page.name
34
+ tr
35
+ td= :title.t
36
+ td= @page.title
37
+ tr
38
+ td= :description.t
39
+ td= @page.attributes['description']
40
+ tr
41
+ td= :type.t
42
+ td= @type
43
+ tr
44
+ td= :geometry.t
45
+ td= @geometry
46
+ - if @page.version
47
+ tr
48
+ td= :last_modified.t
49
+ td= date @page.version.date
50
+ tr
51
+ td= :version.t
52
+ td.version= @page.version
53
+ - if @exif
54
+ h3= :exif.t
55
+ table
56
+ thead
57
+ tr
58
+ th= :entry.t
59
+ th= :value.t
60
+ tbody
61
+ - @exif.each do |key, value|
62
+ tr
63
+ td= key
64
+ td= value
@@ -0,0 +1,60 @@
1
+ en:
2
+ attribute_aspect: 'Default Aspect'
3
+ download: 'Download'
4
+ aspect_documentbrowser: 'Document Browser'
5
+ aspect_download: 'Raw Download'
6
+ aspect_pageinfo: 'Page Information'
7
+ aspect_highlight: 'Highlighted Source'
8
+ aspect_imageinfo: 'Image Information'
9
+ aspect_image: 'Raw Image'
10
+ aspect_source: 'Page Source'
11
+ aspect_subpages: 'Subpages'
12
+ aspect_text: 'Text Download'
13
+ aspect_gallery: 'Image Gallery'
14
+ aspect_not_available: 'Aspect #{aspect} is not available for page #{page} with type #{type}.'
15
+ entry: 'Entry'
16
+ exif: 'EXIF Information'
17
+ geometry: 'Geometry'
18
+ information: 'Information'
19
+ type: 'Type'
20
+ value: 'Value'
21
+ de:
22
+ attribute_aspect: 'Standard-Ansicht'
23
+ download: 'Herunterladen'
24
+ aspect_documentbrowser: 'Dokumentenbrowser'
25
+ aspect_download: 'Herunterladen'
26
+ aspect_pageinfo: 'Seiten-Information'
27
+ aspect_highlight: 'Quellcode mit Syntaxhighlighting'
28
+ aspect_imageinfo: 'Bild-Information'
29
+ aspect_image: 'Bild'
30
+ aspect_source: 'Quellcode'
31
+ aspect_subpages: 'Unterseiten'
32
+ aspect_text: 'Quellcode herunterladen'
33
+ aspect_gallery: 'Bildergalerie'
34
+ aspect_not_available: 'Aspekt #{aspect} für die Seite #{page} mit dem Typ #{type} ist nicht verfügbar.'
35
+ entry: 'Eintrag'
36
+ exif: 'EXIF-Information'
37
+ geometry: 'Geometrie'
38
+ information: 'Information'
39
+ type: 'Typ'
40
+ value: 'Wert'
41
+ cs_CZ:
42
+ attribute_aspect: 'Přednastavený vzhled'
43
+ download: 'Stáhnout'
44
+ aspect_documentbrowser: 'Document Browser'
45
+ aspect_download: 'Stažení (neupraveno)'
46
+ aspect_pageinfo: 'Informace o stránce'
47
+ aspect_highlight: 'Zvýrazněný zdroj'
48
+ aspect_imageinfo: 'Informace o obrázku'
49
+ aspect_image: 'Stažení obrázku'
50
+ aspect_source: 'Zdroj stránky'
51
+ aspect_subpages: 'Podstránky'
52
+ aspect_text: 'Stažení textu'
53
+ aspect_gallery: 'Galerie'
54
+ aspect_not_available: 'Vzhled #{aspect} není k dispozici pro stránku #{page} s typem #{type}.'
55
+ entry: 'Položka'
56
+ exif: 'Informace EXIF'
57
+ geometry: 'Geometrie'
58
+ information: 'Informace'
59
+ type: 'Typ'
60
+ value: 'Hodnota'
@@ -0,0 +1,199 @@
1
+ description 'Aspect subsystem'
2
+ dependencies 'utils/cache'
3
+
4
+ Page.attributes do
5
+ enum :aspect do
6
+ Aspect.aspects.keys.inject({}) do |hash, name|
7
+ hash[name] = Locale.translate("aspect_#{name}", :fallback => titlecase(name))
8
+ hash
9
+ end
10
+ end
11
+ end
12
+
13
+ # Aspect context
14
+ # A aspect context holds the request parameters and other
15
+ # variables used by the aspects.
16
+ # It is possible for a aspect to run sub-aspects. For this
17
+ # purpose you create a subcontext which inherits the variables.
18
+ class Context
19
+ include Hooks
20
+ has_hooks :initialized
21
+
22
+ attr_reader :page, :private, :params, :request, :header
23
+
24
+ def initialize(options = {})
25
+ @page = options[:page]
26
+ @private = options[:private] || Hash.with_indifferent_access
27
+ @params = Hash.with_indifferent_access.merge(options[:params] || {})
28
+ @request = options[:request]
29
+ @header = options[:header] || Hash.with_indifferent_access
30
+ invoke_hook(:initialized)
31
+ end
32
+
33
+ def [](key)
34
+ private[key]
35
+ end
36
+
37
+ def []=(key, value)
38
+ private[key] = value
39
+ end
40
+
41
+ def subcontext(options = {})
42
+ Context.new(:page => options[:page] || page,
43
+ :private => private.merge(options[:private] || {}),
44
+ :params => params.merge(options[:params] || {}),
45
+ :request => request,
46
+ :header => header)
47
+ end
48
+ end
49
+
50
+ # An Aspect renders pages
51
+ # Aspects get a page as input and create text.
52
+ class Aspect
53
+ include PageHelper
54
+ include Templates
55
+
56
+ @aspects = {}
57
+
58
+ class NotAvailable < NameError
59
+ def initialize(name, page)
60
+ super(:aspect_not_available.t(:aspect => name, :page => page.path,
61
+ :type => "#{page.mime.comment} (#{page.mime})"))
62
+ end
63
+ end
64
+
65
+ # Constructor for aspect
66
+ # Options:
67
+ # * layout: Aspect output should be wrapped in HTML layout (Not used for download/image aspects for example)
68
+ # * priority: Aspect priority. The aspect with the lowest priority will be used for a page.
69
+ # * cacheable: Aspect is cacheable
70
+ def initialize(name, options)
71
+ @name = name.to_s
72
+ @layout = !!options[:layout]
73
+ @hidden = !!options[:hidden]
74
+ @cacheable = !!options[:cacheable]
75
+ @priority = (options[:priority] || 99).to_i
76
+ @accepts = String === options[:accepts] ? /^(?:#{options[:accepts]})$/ : options[:accepts]
77
+ @mime = options[:mime]
78
+ @plugin = options[:plugin] || Plugin.for(self.class)
79
+ @description = options[:description] || @plugin.description
80
+ end
81
+
82
+ attr_reader :name, :priority, :mime, :accepts, :description, :plugin
83
+ attr_reader? :layout, :hidden, :cacheable
84
+
85
+ # Aspects hash
86
+ def self.aspects
87
+ @aspects
88
+ end
89
+
90
+ # Create aspect class. This is sugar to create and
91
+ # register an aspect class in one step.
92
+ def self.create(name, options = {}, &block)
93
+ options[:plugin] ||= Plugin.for(block)
94
+ klass = Class.new(self)
95
+ klass.class_eval(&block)
96
+ register klass.new(name, options)
97
+ end
98
+
99
+ # Register aspect instance
100
+ def self.register(aspect)
101
+ (@aspects[aspect.name] ||= []) << aspect
102
+ end
103
+
104
+ # Find all accepting aspects for a page
105
+ def self.find_all(page)
106
+ @aspects.values.map do |aspects|
107
+ aspects.sort_by(&:priority).find {|a| a.accepts?(page) }
108
+ end.compact
109
+ end
110
+
111
+ # Find appropiate aspect for page. An optional
112
+ # name can be given to claim a specific aspect.
113
+ # If no aspect is found a exception is raised.
114
+ def self.find!(page, options = {})
115
+ options[:name] ||= page.attributes['aspect']
116
+ aspects = options[:name] ? @aspects[options[:name].to_s] : @aspects.values.flatten
117
+ aspect = aspects.to_a.sort_by(&:priority).find {|a| a.accepts?(page) && (!options[:layout] || a.layout?) }
118
+ raise NotAvailable.new(options[:name], page) if !aspect
119
+ aspect.dup
120
+ end
121
+
122
+ # Find appropiate aspect for page. An optional
123
+ # name can be given to claim a specific aspect.
124
+ # If no aspect is found nil is returned.
125
+ def self.find(page, options = {})
126
+ find!(page, options) rescue nil
127
+ end
128
+
129
+ # Acceptor should return true if page would be accepted by this aspect.
130
+ # Reimplement this method.
131
+ def accepts?(page)
132
+ !@accepts || page.mime.to_s =~ @accepts
133
+ end
134
+
135
+ # Render page content.
136
+ # Reimplement this method.
137
+ def call(context, page)
138
+ raise NotImplementedError
139
+ end
140
+ end
141
+
142
+ # Plug-in the aspect subsystem
143
+ module ::Olelo::PageHelper
144
+ def render_page(page)
145
+ Cache.cache("include-#{page.path}-#{page.version.cache_id}", :update => request.no_cache?, :defer => true) do |context|
146
+ begin
147
+ context = Context.new(:page => page, :params => {:included => true})
148
+ Aspect.find!(page, :layout => true).call(context, page)
149
+ rescue Aspect::NotAvailable => ex
150
+ %{<span class="error">#{escape_html ex.message}</span>}
151
+ end
152
+ end
153
+ end
154
+ end
155
+
156
+ # Plug-in the aspect subsystem
157
+ class ::Olelo::Application
158
+ def show_page
159
+ params[:aspect] ||= 'subpages' if params[:path].to_s.ends_with? '/'
160
+ @selected_aspect, layout, header, content =
161
+ Cache.cache("aspect-#{page.path}-#{page.version.cache_id}-#{build_query(params)}",
162
+ :update => request.no_cache?, :defer => true) do |cache|
163
+ aspect = Aspect.find!(page, :name => params[:aspect])
164
+ cache.disable! if !aspect.cacheable?
165
+ context = Context.new(:page => page, :params => params, :request => request)
166
+ result = aspect.call(context, page)
167
+ context.header['Content-Type'] ||= aspect.mime.to_s if aspect.mime
168
+ context.header['Content-Type'] ||= page.mime.to_s if !aspect.layout?
169
+ [aspect.name, aspect.layout?, context.header.to_hash, result]
170
+ end
171
+ self.response.header.merge!(header)
172
+
173
+ @menu_versions = true
174
+ halt(layout ? render(:show, :locals => {:content => content}) : content)
175
+ rescue Aspect::NotAvailable => ex
176
+ cache_control :no_cache => true
177
+ redirect build_path(page.path) if params[:path].to_s.ends_with? '/'
178
+ raise if params[:aspect]
179
+ flash.error ex.message
180
+ redirect build_path(page, :action => :edit)
181
+ end
182
+
183
+ hook :menu do |menu|
184
+ if menu.name == :actions && view_menu = menu[:view]
185
+ Cache.cache("aspect-menu-#{page.path}-#{page.version.cache_id}-#{@selected_aspect}",
186
+ :update => request.no_cache?, :defer => true) do
187
+ aspects = Aspect.find_all(page).select {|a| !a.hidden? || a.name == @selected_aspect || a.name == page.attributes['aspect'] }.map do |a|
188
+ [Locale.translate("aspect_#{a.name}", :fallback => titlecase(a.name)), a]
189
+ end.sort_by(&:first)
190
+ aspects.select {|label, a| a.layout? }.map do |label, a|
191
+ MenuItem.new(a.name, :label => label, :href => build_path(page, :aspect => a.name), :class => a.name == @selected_aspect ? 'selected' : nil)
192
+ end +
193
+ aspects.reject {|label, a| a.layout? }.map do |label, a|
194
+ MenuItem.new(a.name, :label => label, :href => build_path(page, :aspect => a.name), :class => 'download')
195
+ end
196
+ end.each {|item| view_menu << item }
197
+ end
198
+ end
199
+ end
@@ -0,0 +1,37 @@
1
+ description 'Page information aspect'
2
+
3
+ Aspect.create(:pageinfo, :priority => 4, :layout => true, :cacheable => true) do
4
+ def call(context, page)
5
+ @page = page
6
+ render :info
7
+ end
8
+ end
9
+
10
+ __END__
11
+ @@ info.slim
12
+ table
13
+ tbody
14
+ tr
15
+ td= :name.t
16
+ td= @page.name
17
+ tr
18
+ td= :title.t
19
+ td= @page.title
20
+ tr
21
+ td= :description.t
22
+ td= @page.attributes['description']
23
+ - if @page.version
24
+ tr
25
+ td= :last_modified.t
26
+ td= date @page.version.date
27
+ tr
28
+ td= :version.t
29
+ td.version = @page.version
30
+ tr
31
+ td= :type.t
32
+ td= @page.mime.comment.blank? ? @page.mime : "#{@page.mime.comment} (#{@page.mime})"
33
+ - if !@page.content.empty?
34
+ tr
35
+ td= :download.t
36
+ td
37
+ a href=build_path(@page, :aspect => 'download') = :download.t
@@ -0,0 +1,6 @@
1
+ description 'Source aspect'
2
+
3
+ Aspect.create(:source, :priority => 3, :layout => true, :cacheable => true) do
4
+ def accepts?(page); page.mime.text?; end
5
+ def call(context, page); "<pre>#{escape_html page.content}</pre>"; end
6
+ end
@@ -0,0 +1,44 @@
1
+ description 'Subpages aspect'
2
+
3
+ Aspect.create(:subpages, :priority => 2, :layout => true, :cacheable => true) do
4
+ def accepts?(page); !page.children.empty?; end
5
+ def call(context, page)
6
+ @page_nr = [context.params[:page].to_i, 1].max
7
+ per_page = 20
8
+ @page = page
9
+ @page_count = @page.children.size / per_page + 1
10
+ @children = @page.children[((@page_nr - 1) * per_page) ... (@page_nr * per_page)].to_a
11
+ render :subpages
12
+ end
13
+ end
14
+
15
+ __END__
16
+ @@ subpages.slim
17
+ = pagination(@page, @page_count, @page_nr, :aspect => 'subpages')
18
+ table#subpages-table
19
+ thead
20
+ tr
21
+ th= :name.t
22
+ th= :description.t
23
+ th= :last_modified.t
24
+ th= :author.t
25
+ th= :comment.t
26
+ th= :actions.t
27
+ tbody
28
+ - @children.each do |child|
29
+ - classes = child.children.empty? ? 'page' : 'folder'
30
+ - if !child.extension.empty?
31
+ - classes << " file-type-#{child.extension}"
32
+ tr
33
+ td.link
34
+ a href=build_path(child) class=classes = child.name
35
+ td= truncate(child.attributes['description'], 30)
36
+ td= date(child.version.date)
37
+ td= truncate(child.version.author.name, 30)
38
+ td= truncate(child.version.comment, 30)
39
+ td.actions
40
+ a.action-edit href=build_path(child, :action => :edit) title=:edit.t = :edit.t
41
+ a.action-history href=build_path(child, :action => :history) title=:history.t = :history.t
42
+ a.action-move href=build_path(child, :action => :move) title=:move.t = :move.t
43
+ a.action-delete href=build_path(child, :action => :delete) title=:delete.t = :delete.t
44
+ = pagination(@page, @page_count, @page_nr, :aspect => 'subpages')
@@ -0,0 +1,9 @@
1
+ description 'Text aspect'
2
+
3
+ Aspect.create(:text, :mime => 'text/plain; charset=utf-8') do
4
+ def accepts?(page); page.mime.text?; end
5
+ def call(context, page)
6
+ context.header['Content-Length'] = page.content.bytesize.to_s
7
+ page.content
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ .blog>.article{clear:both;width:100%}.blog>.article>h2{margin:0}.blog>.article>.author,.blog>.article>.date{float:left;font-size:90%;color:#555555;margin:0.2em 0.4em 1em 0}.blog>.article>.content{clear:both;width:100%}.blog>.article>.full{clear:both;float:right}.blog-menu{border-collapse:separate;border-spacing:0;vertical-align:middle;margin:0;padding:0;border:0;outline:0;box-shadow:0px 0px 0px transparent;-webkit-box-shadow:0px 0px 0px transparent}.blog-menu tr{background:transparent}.blog-menu tr td{vertical-align:top}
@@ -0,0 +1,37 @@
1
+ @import "lib/reset.scss";
2
+ @import "lib/shadow.scss";
3
+ @import "lib/horizontal-list.scss";
4
+
5
+ .blog > .article {
6
+ clear: both;
7
+ width: 100%;
8
+ > h2 {
9
+ margin: 0;
10
+ }
11
+ > .author, > .date {
12
+ float: left;
13
+ font-size: 90%;
14
+ color: #555555;
15
+ margin: 0.2em 0.4em 1em 0;
16
+ }
17
+ > .content {
18
+ clear: both;
19
+ width: 100%;
20
+ }
21
+ > .full {
22
+ clear: both;
23
+ float: right;
24
+ }
25
+ }
26
+
27
+ .blog-menu {
28
+ @include reset-table;
29
+ @include reset-box-model;
30
+ @include no-box-shadow;
31
+ tr {
32
+ background: transparent;
33
+ td {
34
+ vertical-align: top;
35
+ }
36
+ }
37
+ }