olelo 0.9.0

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.
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,76 @@
1
+ module Olelo
2
+ class<< self
3
+ attr_accessor :logger
4
+ end
5
+
6
+ class Initializer
7
+ include Util
8
+
9
+ def self.initialize(logger)
10
+ @instance ||= Initializer.new(logger)
11
+ end
12
+
13
+ def initialize(logger)
14
+ Olelo.logger = logger
15
+ init_locale
16
+ init_templates
17
+ init_plugins
18
+ init_routes
19
+ init_scripts
20
+ end
21
+
22
+ private
23
+
24
+ def init_locale
25
+ Locale.locale = Config['locale']
26
+ Locale.load(File.join(File.dirname(__FILE__), 'locale.yml'))
27
+ end
28
+
29
+ def init_templates
30
+ Templates.enable_caching if Config['production']
31
+ Templates.loader = Class.new do
32
+ def context
33
+ Plugin.caller.first.try(:name)
34
+ end
35
+
36
+ def load(name)
37
+ VirtualFS::Union.new(Plugin.caller.first.try(:virtual_fs),
38
+ VirtualFS::Native.new(Config['views_path'])).read(name)
39
+ end
40
+ end.new
41
+ end
42
+
43
+ def init_plugins
44
+ # Load locales for loaded plugins
45
+ Plugin.after(:load) { Locale.load(File.join(File.dirname(file), 'locale.yml')) }
46
+
47
+ # Configure plugin system
48
+ Plugin.disabled = Config['disabled_plugins'].to_a
49
+ Plugin.dir = Config['plugins_path']
50
+
51
+ Plugin.load_all
52
+ Plugin.start
53
+ end
54
+
55
+ def init_routes
56
+ Application.reserved_paths = Application.router.map do |method, router|
57
+ router.head.map {|name, pattern, keys, function| pattern }
58
+ end.flatten
59
+ Application.router.each do |method, router|
60
+ Olelo.logger.debug method
61
+ router.each do |name, pattern, keys, function|
62
+ Olelo.logger.debug "#{name} -> #{pattern.inspect}"
63
+ end
64
+ end if Olelo.logger.debug?
65
+ end
66
+
67
+ def init_scripts
68
+ Dir[File.join(Config['initializers_path'], '*.rb')].sort_by do |f|
69
+ File.basename(f)
70
+ end.each do |f|
71
+ Olelo.logger.debug "Running script initializer #{f}"
72
+ instance_eval(File.read(f), f)
73
+ end
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,63 @@
1
+ module Olelo
2
+ # Simple localization implementation
3
+ module Locale
4
+ @locale = nil
5
+ @translations = Hash.with_indifferent_access
6
+ @loaded = []
7
+
8
+ class << self
9
+ attr_accessor :locale
10
+
11
+ # Load locale from file
12
+ #
13
+ # A locale is a yamlfile which maps
14
+ # keys to strings.
15
+ #
16
+ # @param [String] file name
17
+ # @return [void]
18
+ #
19
+ def load(file)
20
+ if !@loaded.include?(file) && File.file?(file)
21
+ locale = YAML.load_file(file)
22
+ @translations.update(locale[$1] || {}) if @locale =~ /^(\w+)(_|-)/
23
+ @translations.update(locale[@locale] || {})
24
+ @translations.each_value(&:freeze)
25
+ @loaded << file
26
+ end
27
+ end
28
+
29
+ # Return translated string for key
30
+ #
31
+ # A translated string can contain variables which are substituted in this method.
32
+ # You have to pass an arguments hash.
33
+ #
34
+ # @option args [Integer] :count if count is not 1, the key #{key}_plural is looked up instead
35
+ # @option args [String] :fallback Fallback string if key is not found in the locale
36
+ # @param [Symbol, String] key which identifies string in locale
37
+ # @param [Hash] args Arguments hash for string interpolation
38
+ # @return [String] translated string
39
+ #
40
+ def translate(key, args = {})
41
+ if !key.to_s.ends_with?('_plural') && args[:count] && args[:count] != 1
42
+ translate("#{key}_plural", args)
43
+ elsif @translations[key]
44
+ args.inject(@translations[key]) {|s,(k,v)| s.gsub("#\{#{k}\}", v.to_s) }
45
+ else
46
+ args[:fallback] || "##{key}"
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ class Symbol
54
+ # Lookup translated string identified by this symbol
55
+ #
56
+ # @param [Hash] args Arguments hash for string interpolation
57
+ # @return [String] translated string
58
+ # @see Olelo::Locale#translate
59
+ #
60
+ def t(args = {})
61
+ Olelo::Locale.translate(self, args)
62
+ end
63
+ end
@@ -0,0 +1,284 @@
1
+ en:
2
+ access_denied: 'Access denied'
3
+ actions: 'Actions'
4
+ already_exists: '#{page} exists already'
5
+ attribute_mime: 'Mime-Type'
6
+ attribute_no_title: 'Disable title'
7
+ attribute_title: 'Title'
8
+ attributes: 'Attributes'
9
+ attributes_edited: 'Attributes of #{page} edited'
10
+ auth_unsupported: 'Authentication service does not support #{name}'
11
+ author: 'Author'
12
+ binary_file: 'Binary file'
13
+ by: 'by'
14
+ cancel: 'Cancel'
15
+ change_password: 'Change password'
16
+ changes: 'Changes'
17
+ changes_of: 'Changes of #{page}'
18
+ changes_saved: 'Changes saved'
19
+ comment: 'Comment'
20
+ compare: 'Compare #{name}'
21
+ confirm_password: 'Confirm password'
22
+ head: 'Head'
23
+ create_page: 'Create #{page}'
24
+ create_redirect: 'Create redirect'
25
+ date: 'Date'
26
+ delete: 'Delete'
27
+ deleted: 'Deleted'
28
+ delete_page: 'Delete #{page}'
29
+ description: 'Description'
30
+ destination: 'Destination'
31
+ edit: 'Edit'
32
+ edit_page: 'Editing #{page}'
33
+ edit_page_section: 'Editing #{page} (Section)'
34
+ email: 'E-Mail'
35
+ empty_password: 'Empty password'
36
+ error_binary: '#{page} is a binary #{type} and cannot be edited like a text file.'
37
+ error_occurred: 'Oh snap! An error occurred.'
38
+ file: 'File'
39
+ groups: 'Groups'
40
+ history: 'History'
41
+ history_of: 'History of #{page}'
42
+ invalid_email: 'E-Mail is invalid'
43
+ invalid_name: 'Name is invalid'
44
+ invalid_path: 'Invalid path'
45
+ last_modified: 'Last modified'
46
+ login: 'Login'
47
+ logout: 'Logout'
48
+ menu_actions_edit_new: 'New Page'
49
+ move: 'Move'
50
+ move_page: 'Move #{page}'
51
+ name: 'Name'
52
+ newer: 'Newer'
53
+ new_page: 'New Page'
54
+ no_changes: 'No changes'
55
+ not_found: '#{id} not found'
56
+ old_password: 'Old password'
57
+ page: 'Page'
58
+ page_edited: '#{page} edited'
59
+ page_not_found: 'Sorry, the page you were looking for was not found.'
60
+ page_uploaded: 'Page #{page} uploaded'
61
+ password: 'Password'
62
+ passwords_do_not_match: 'Passwords do not match'
63
+ parents: 'Parents'
64
+ path: 'Path'
65
+ profile_title: 'Profile of #{user}'
66
+ really_delete: 'Really delete?'
67
+ reserved_path: 'Path is reserved'
68
+ reset: 'Reset'
69
+ root: 'Root'
70
+ page_deleted: '#{page} deleted.'
71
+ page_moved: '#{page} moved to #{destination}.'
72
+ save: 'Save'
73
+ save_and_close: 'Save & Close'
74
+ search: 'Search'
75
+ settings: 'Settings'
76
+ signup: 'Sign up'
77
+ summary: 'Summary'
78
+ text: 'Text'
79
+ title: 'Title'
80
+ tree: 'Tree'
81
+ type_select: 'Select value'
82
+ type_stringlist: 'Comma-separated strings'
83
+ upload_file: 'Upload file'
84
+ upload: 'Upload'
85
+ user: 'User'
86
+ user_already_exists: 'User #{name} already exists'
87
+ version: 'Version'
88
+ version_conflict: 'Version conflict detected'
89
+ wrong_user_or_pw: 'Wrong username or password'
90
+ wrong_password: 'Wrong password'
91
+ de:
92
+ access_denied: 'Zugriff verweigert'
93
+ actions: 'Aktionen'
94
+ already_exists: '#{page} existiert bereits'
95
+ attribute_mime: 'Mime-Typ'
96
+ attribute_no_title: 'Titel deaktivieren'
97
+ attribute_title: 'Titel'
98
+ attributes: 'Attribute'
99
+ attributes_edited: 'Attribute von #{page} bearbeitet'
100
+ auth_unsupported: 'Authentifikationsservice unterstützt #{name} nicht'
101
+ author: 'Autor'
102
+ binary_file: 'Binärdatei'
103
+ by: 'von'
104
+ cancel: 'Abbrechen'
105
+ change_password: 'Passwort ändern'
106
+ changes: 'Änderungen'
107
+ changes_of: 'Änderungen von #{page}'
108
+ changes_saved: 'Änderungen gespeichert'
109
+ comment: 'Kommentar'
110
+ compare: 'Vergleiche #{name}'
111
+ confirm_password: 'Bestätige Passwort'
112
+ head: 'Kopf'
113
+ create_page: 'Neue #{page}'
114
+ create_redirect: 'Weiterleitung'
115
+ date: 'Datum'
116
+ delete: 'Löschen'
117
+ deleted: 'Gelöscht'
118
+ delete_page: 'Lösche #{page}'
119
+ description: 'Beschreibung'
120
+ destination: 'Ziel'
121
+ edit: 'Bearbeiten'
122
+ edit_page: 'Bearbeite #{page}'
123
+ edit_page_section: 'Bearbeite #{page} (Bereich)'
124
+ email: 'E-Mail'
125
+ empty_password: 'Leeres Passwort'
126
+ error_binary: '#{page} ist eine Datei mit dem Typ #{type} und kann nicht wie eine Textdatei bearbeitet werden.'
127
+ error_occurred: 'Hoppla! Es ist ein Fehler aufgetreten.'
128
+ file: 'Datei'
129
+ groups: 'Gruppen'
130
+ history: 'Historie'
131
+ history_of: 'Historie von #{page}'
132
+ invalid_email: 'E-Mail ist ungültig'
133
+ invalid_name: 'Name ist ungültig'
134
+ invalid_path: 'Ungültiger Pfad'
135
+ last_modified: 'Letzte Änderung'
136
+ login: 'Anmelden'
137
+ logout: 'Abmelden'
138
+ menu_actions_edit: 'Bearbeiten'
139
+ menu_actions_edit_delete: 'Löschen'
140
+ menu_actions_edit_move: 'Verschieben'
141
+ menu_actions_edit_new: 'Neue Seite'
142
+ menu_actions_history: 'Historie'
143
+ menu_actions_history_newer: 'Neuer'
144
+ menu_actions_history_older: 'Älter'
145
+ menu_actions_view: 'Ansicht'
146
+ move: 'Verschieben'
147
+ move_page: 'Verschiebe #{page}'
148
+ name: 'Name'
149
+ new_page: 'Neue Seite'
150
+ no_changes: 'Keine Änderungen'
151
+ not_found: '#{id} nicht gefunden'
152
+ old_password: 'Altes Passwort'
153
+ page: 'Seite'
154
+ page_edited: '#{page} edited'
155
+ page_not_found: 'Die Seite wurde leider nicht gefunden.'
156
+ page_uploaded: 'Seite #{page} hochgeladen'
157
+ password: 'Passwort'
158
+ passwords_do_not_match: 'Passwörter stimmen nicht überein'
159
+ parents: 'Eltern'
160
+ path: 'Pfad'
161
+ profile_title: 'Profil von #{user}'
162
+ really_delete: 'Wirklich löschen?'
163
+ reserved_path: 'Pfad ist reserviert'
164
+ reset: 'Zurücksetzen'
165
+ root: 'Root'
166
+ page_deleted: '#{page} gelöscht.'
167
+ page_moved: '#{page} verschoben nach #{destination}.'
168
+ save: 'Speichern'
169
+ save_and_close: 'Speichern & Schließen'
170
+ search: 'Suche'
171
+ settings: 'Einstellungen'
172
+ signup: 'Konto anlegen'
173
+ summary: 'Zusammenfassung'
174
+ text: 'Text'
175
+ title: 'Titel'
176
+ type_select: 'Wert auswählen'
177
+ type_stringlist: 'Durch Komma getrennte Strings'
178
+ tree: 'Baum'
179
+ upload_file: 'Datei hochladen'
180
+ upload: 'Hochladen'
181
+ user: 'Benutzer'
182
+ user_already_exists: 'Benutzer #{name} existiert bereits'
183
+ version: 'Version'
184
+ version_conflict: 'Versionskonflikt aufgetreten'
185
+ wrong_user_or_pw: 'Falscher Benutzername oder falsches Passwort'
186
+ wrong_password: 'Falsches Passwort'
187
+ cs_CZ:
188
+ access_denied: 'Přístup odepřen'
189
+ actions: 'Akce'
190
+ already_exists: 'Stránka #{page} již existuje'
191
+ attribute_mime: 'Mime-Type'
192
+ attribute_no_title: 'Skrýt titulek'
193
+ attribute_title: 'Titulek'
194
+ attributes: 'Atributy'
195
+ attributes_edited: 'Atributy stránky #{page} editovány'
196
+ auth_unsupported: 'Autentizační služba nepodporuje #{name}'
197
+ author: 'Autor'
198
+ binary_file: 'Binární soubor'
199
+ by: 'od'
200
+ cancel: 'Zrušit'
201
+ change_password: 'Změnit heslo'
202
+ changes: 'Změny'
203
+ changes_of: 'Změny stránky #{page}'
204
+ changes_saved: 'Změny uloženy'
205
+ comment: 'Komentář'
206
+ compare: 'Porovnat #{name}'
207
+ confirm_password: 'Potvrdit heslo'
208
+ head: 'Nejnovější'
209
+ create_page: 'Vytvořit stránku #{page}'
210
+ create_redirect: 'Vytvořit přesměrování'
211
+ date: 'Datum'
212
+ delete: 'Smazat'
213
+ deleted: 'Smazáno'
214
+ delete_page: 'Smazat stránku #{page}'
215
+ description: 'Popis'
216
+ destination: 'Cíl'
217
+ edit: 'Editovat'
218
+ edit_page: 'Editace stránky #{page}'
219
+ edit_page_section: 'Editovat #{page} (Sekci)'
220
+ email: 'e-mail'
221
+ empty_password: 'Prázdné heslo'
222
+ error_binary: 'Stránka #{page} je binární typ #{type} a nemůže být editována jako textový soubor.'
223
+ error_occurred: 'Ouvej! Vyskytla se chyba.'
224
+ file: 'Soubor'
225
+ groups: 'Skupiny'
226
+ history: 'Historie'
227
+ history_of: 'Historie stránky #{page}'
228
+ invalid_email: 'e-mail je neplatný'
229
+ invalid_name: 'Jméno je neplatné'
230
+ invalid_path: 'Neplatná cesta'
231
+ last_modified: 'Poslední modifikace'
232
+ login: 'Přihlášení'
233
+ logout: 'Odhlášení'
234
+ menu_actions_edit: 'Editovat'
235
+ menu_actions_edit_delete: 'Smazat'
236
+ menu_actions_edit_move: 'Přesunout'
237
+ menu_actions_edit_new: 'Nová stránka'
238
+ menu_actions_history: 'Historie'
239
+ menu_actions_history_newer: 'Novější'
240
+ menu_actions_history_older: 'Starší'
241
+ menu_actions_history_head: 'Aktuální'
242
+ menu_actions_view: 'Zobrazit'
243
+ move: 'Přesunout'
244
+ move_page: 'Přesunout stránku #{page}'
245
+ name: 'Jméno'
246
+ newer: 'Novější'
247
+ new_page: 'Nová stránka'
248
+ no_changes: 'Žádné změny'
249
+ not_found: '#{id}: nenalezeno'
250
+ old_password: 'Staré heslo'
251
+ page: 'Stránka'
252
+ page_edited: 'Stránka #{page} editována'
253
+ page_not_found: 'Pardon, stránka, kterou hledáte, nebyla nalezena.'
254
+ page_uploaded: 'Stránka #{page} nahrána'
255
+ password: 'Heslo'
256
+ passwords_do_not_match: 'Hesla se neshodují'
257
+ parents: 'Rodiče'
258
+ path: 'Cesta'
259
+ profile_title: 'Profil uživatele #{user}'
260
+ really_delete: 'Opravdu smazat?'
261
+ reserved_path: 'Cesta je rezervována'
262
+ reset: 'Reset'
263
+ root: 'Hlavní strana'
264
+ page_deleted: 'Stránka #{page} smazána.'
265
+ page_moved: 'Stránka #{page} přesunuta do #{destination}.'
266
+ save: 'Uložit'
267
+ save_and_close: 'Uložit a zavřít'
268
+ search: 'Hledat'
269
+ settings: 'Nastavení'
270
+ signup: 'Registrovat se'
271
+ summary: 'Souhrn'
272
+ text: 'Text'
273
+ title: 'Titulek'
274
+ tree: 'Strom'
275
+ type_select: 'Vybrat hodnotu'
276
+ type_stringlist: 'Řetězce oddělené čárkou'
277
+ upload_file: 'Nahrát soubor'
278
+ upload: 'Nahrát'
279
+ user: 'Uživatel'
280
+ user_already_exists: 'Uživatel #{name} již existuje'
281
+ version: 'Verze'
282
+ version_conflict: 'Detekován konflikt verzí'
283
+ wrong_user_or_pw: 'Chybné jméno uživatele nebo heslo'
284
+ wrong_password: 'Chybné heslo'
data/lib/olelo/menu.rb ADDED
@@ -0,0 +1,101 @@
1
+ module Olelo
2
+ class Menu
3
+ include Util
4
+ include Enumerable
5
+ attr_reader :name
6
+
7
+ def initialize(name)
8
+ @name = name.to_sym
9
+ @items = []
10
+ @items_map = {}
11
+ end
12
+
13
+ def each(&block)
14
+ @items.each(&block)
15
+ end
16
+
17
+ def [](name)
18
+ path = path.to_s
19
+ i = path.index('/')
20
+ if i
21
+ item = @items_map[path[0...i]]
22
+ item[path[i+1..-1]] if item
23
+ else
24
+ @items_map[name.to_sym]
25
+ end
26
+ end
27
+
28
+ def item(name, options = {})
29
+ self << MenuItem.new(name, options)
30
+ end
31
+
32
+ def <<(item)
33
+ raise TypeError, "Only items allowed" unless MenuItem === item
34
+ raise "Item #{item.name} exists already in #{path.join('/')}" if @items_map.include?(item.name)
35
+ item.parent = self
36
+ @items << item
37
+ @items_map[item.name] = item
38
+ end
39
+
40
+ def empty?
41
+ @items.empty?
42
+ end
43
+
44
+ def clear
45
+ @items.clear
46
+ @items_map.clear
47
+ end
48
+
49
+ def remove(name)
50
+ path = name.to_s
51
+ i = path.index('/')
52
+ if i
53
+ item = @items_map[path[0...i]]
54
+ item.remove(path[i+1..-1]) if item
55
+ else
56
+ item = @items_map.delete(name.to_sym)
57
+ @items.delete(item) if item
58
+ end
59
+ end
60
+
61
+ def build_menu
62
+ empty? ? '' : %{<ul id="menu-#{html_id}">#{map {|item| item.build_menu }.join}</ul>}
63
+ end
64
+
65
+ def to_html
66
+ build_menu.html_safe
67
+ end
68
+
69
+ def html_id
70
+ escape_html path.join('-')
71
+ end
72
+
73
+ def path
74
+ [name]
75
+ end
76
+ end
77
+
78
+ class MenuItem < Menu
79
+ attr_reader :options
80
+ attr_accessor :parent
81
+
82
+ def initialize(name, options = {})
83
+ super(name)
84
+ @parent = nil
85
+ @options = options
86
+ end
87
+
88
+ def path
89
+ parent ? parent.path << super : super
90
+ end
91
+
92
+ def build_menu
93
+ attrs = options.dup
94
+ label = attrs.delete(:label) || Locale.translate("menu_#{path.join('_')}", :fallback => titlecase(name))
95
+ klass = [*attrs.delete(:class)].flatten.compact
96
+ klass = klass.empty? ? '' : %{class="#{klass.join(' ')}" }
97
+ attrs = attrs.map {|k,v| %{#{k}="#{escape_html v}"} }.join(' ')
98
+ %{<li #{klass}id="item-#{html_id}"><a #{attrs}>#{escape_html label}</a>#{super}</li>}
99
+ end
100
+ end
101
+ end