olelo 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/.gitmodules +3 -0
- data/Gemfile +3 -0
- data/README.markdown +104 -0
- data/Rakefile +92 -0
- data/bin/olelo +5 -0
- data/config.ru +86 -0
- data/config/aspects.rb +256 -0
- data/config/config.yml.default +154 -0
- data/config/initializers/00-mime_types.rb +29 -0
- data/config/initializers/01-slim.rb +2 -0
- data/config/interwiki.yml +11 -0
- data/doc/AUTHORS +7 -0
- data/doc/LICENSE +22 -0
- data/lib/olelo.rb +39 -0
- data/lib/olelo/application.rb +294 -0
- data/lib/olelo/attributes.rb +285 -0
- data/lib/olelo/config.rb +88 -0
- data/lib/olelo/extensions.rb +252 -0
- data/lib/olelo/helper.rb +290 -0
- data/lib/olelo/hooks.rb +142 -0
- data/lib/olelo/html_safe.rb +29 -0
- data/lib/olelo/initializer.rb +76 -0
- data/lib/olelo/locale.rb +63 -0
- data/lib/olelo/locale.yml +284 -0
- data/lib/olelo/menu.rb +101 -0
- data/lib/olelo/middleware/blacklist.rb +25 -0
- data/lib/olelo/middleware/degrade_mime_type.rb +19 -0
- data/lib/olelo/middleware/flash.rb +97 -0
- data/lib/olelo/middleware/force_encoding.rb +41 -0
- data/lib/olelo/page.rb +266 -0
- data/lib/olelo/patch.rb +311 -0
- data/lib/olelo/plugin.rb +188 -0
- data/lib/olelo/repository.rb +225 -0
- data/lib/olelo/routing.rb +223 -0
- data/lib/olelo/templates.rb +30 -0
- data/lib/olelo/user.rb +132 -0
- data/lib/olelo/util.rb +233 -0
- data/lib/olelo/version.rb +3 -0
- data/lib/olelo/virtualfs.rb +161 -0
- data/lib/rack/olelo_patches.rb +33 -0
- data/lib/rack/relative_redirect.rb +44 -0
- data/lib/rack/static_cache.rb +93 -0
- data/lib/yard/addons.rb +1 -0
- data/lib/yard/addons/hook_handler.rb +25 -0
- data/lib/yard/addons/override_tag.rb +14 -0
- data/lib/yard/addons/route_handler.rb +33 -0
- data/lib/yard/addons/sanitize_anchor.rb +16 -0
- data/olelo.gemspec +31 -0
- data/plugins/aspects/changelog.rb +45 -0
- data/plugins/aspects/documentbrowser.rb +57 -0
- data/plugins/aspects/download.rb +11 -0
- data/plugins/aspects/highlight.rb +8 -0
- data/plugins/aspects/image.rb +41 -0
- data/plugins/aspects/imageinfo.rb +64 -0
- data/plugins/aspects/locale.yml +60 -0
- data/plugins/aspects/main.rb +199 -0
- data/plugins/aspects/pageinfo.rb +37 -0
- data/plugins/aspects/source.rb +6 -0
- data/plugins/aspects/subpages.rb +44 -0
- data/plugins/aspects/text.rb +9 -0
- data/plugins/blog/blog.css +1 -0
- data/plugins/blog/blog.scss +37 -0
- data/plugins/blog/locale.yml +12 -0
- data/plugins/blog/main.rb +85 -0
- data/plugins/editor/locale.yml +18 -0
- data/plugins/editor/markup/main.rb +3 -0
- data/plugins/editor/markup/script.js +10 -0
- data/plugins/editor/markup/script/00-jquery.textselection.js +267 -0
- data/plugins/editor/markup/script/01-olelo.markupeditor.js +116 -0
- data/plugins/editor/markup/script/init.js +10 -0
- data/plugins/editor/preview.rb +52 -0
- data/plugins/editor/recaptcha.rb +56 -0
- data/plugins/filters/creole.rb +37 -0
- data/plugins/filters/disposition.rb +9 -0
- data/plugins/filters/editsection.rb +67 -0
- data/plugins/filters/fix_img_tag.rb +16 -0
- data/plugins/filters/html_wrapper.rb +12 -0
- data/plugins/filters/interwiki.rb +19 -0
- data/plugins/filters/link_classifier.rb +26 -0
- data/plugins/filters/locale.yml +15 -0
- data/plugins/filters/main.rb +202 -0
- data/plugins/filters/markdown_nowiki.rb +15 -0
- data/plugins/filters/numbering.xsl +93 -0
- data/plugins/filters/orgmode.rb +6 -0
- data/plugins/filters/rubypants.rb +6 -0
- data/plugins/filters/s5/main.rb +32 -0
- data/plugins/filters/s5/s5.xsl +118 -0
- data/plugins/filters/tilt.rb +17 -0
- data/plugins/filters/toc.rb +50 -0
- data/plugins/filters/xhtml2latex.xsl +232 -0
- data/plugins/filters/xslt.rb +22 -0
- data/plugins/gallery/gallery.css +1 -0
- data/plugins/gallery/gallery.scss +28 -0
- data/plugins/gallery/main.rb +34 -0
- data/plugins/misc/fancybox/images/blank.gif +0 -0
- data/plugins/misc/fancybox/images/fancy_close.png +0 -0
- data/plugins/misc/fancybox/images/fancy_loading.png +0 -0
- data/plugins/misc/fancybox/images/fancy_nav_left.png +0 -0
- data/plugins/misc/fancybox/images/fancy_nav_right.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_e.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_n.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_ne.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_nw.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_s.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_se.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_sw.png +0 -0
- data/plugins/misc/fancybox/images/fancy_shadow_w.png +0 -0
- data/plugins/misc/fancybox/images/fancy_title_left.png +0 -0
- data/plugins/misc/fancybox/images/fancy_title_main.png +0 -0
- data/plugins/misc/fancybox/images/fancy_title_over.png +0 -0
- data/plugins/misc/fancybox/images/fancy_title_right.png +0 -0
- data/plugins/misc/fancybox/images/fancybox-x.png +0 -0
- data/plugins/misc/fancybox/images/fancybox-y.png +0 -0
- data/plugins/misc/fancybox/images/fancybox.png +0 -0
- data/plugins/misc/fancybox/jquery.fancybox.css +1 -0
- data/plugins/misc/fancybox/jquery.fancybox.scss +323 -0
- data/plugins/misc/fancybox/main.rb +4 -0
- data/plugins/misc/fancybox/script.js +37 -0
- data/plugins/misc/fancybox/script/00-jquery.mousewheel.js +84 -0
- data/plugins/misc/fancybox/script/01-jquery.easing.js +205 -0
- data/plugins/misc/fancybox/script/02-jquery.fancybox.js +1156 -0
- data/plugins/misc/fancybox/script/init.js +18 -0
- data/plugins/misc/system.rb +192 -0
- data/plugins/misc/variables.rb +29 -0
- data/plugins/misc/webdav.rb +45 -0
- data/plugins/repositories/git_grep.rb +69 -0
- data/plugins/repositories/gitrb_repository.rb +204 -0
- data/plugins/repositories/locale.yml +12 -0
- data/plugins/repositories/rugged_repository.rb +454 -0
- data/plugins/security/acl.rb +57 -0
- data/plugins/security/basic_auth.rb +21 -0
- data/plugins/security/locale.yml +21 -0
- data/plugins/security/persistent_login.rb +32 -0
- data/plugins/security/portal.rb +28 -0
- data/plugins/security/private_wiki.rb +24 -0
- data/plugins/security/readonly_wiki.rb +25 -0
- data/plugins/security/stack.rb +20 -0
- data/plugins/security/yamlfile.rb +66 -0
- data/plugins/tags/code.rb +6 -0
- data/plugins/tags/footnotes.rb +35 -0
- data/plugins/tags/gist-embed.css +123 -0
- data/plugins/tags/gist.rb +13 -0
- data/plugins/tags/html.rb +57 -0
- data/plugins/tags/include.rb +20 -0
- data/plugins/tags/main.rb +353 -0
- data/plugins/tags/math.rb +117 -0
- data/plugins/tags/scripting.rb +64 -0
- data/plugins/tags/sort.rb +7 -0
- data/plugins/tags/tabs.rb +20 -0
- data/plugins/treeview/images/collapsed.png +0 -0
- data/plugins/treeview/images/expanded.png +0 -0
- data/plugins/treeview/images/menu.png +0 -0
- data/plugins/treeview/images/tree.png +0 -0
- data/plugins/treeview/images/wait.gif +0 -0
- data/plugins/treeview/main.rb +16 -0
- data/plugins/treeview/script.js +5 -0
- data/plugins/treeview/script/00-jquery.treeview.js +164 -0
- data/plugins/treeview/script/init.js +25 -0
- data/plugins/treeview/treeview.css +1 -0
- data/plugins/treeview/treeview.scss +113 -0
- data/plugins/utils/assets.rb +74 -0
- data/plugins/utils/cache.rb +53 -0
- data/plugins/utils/image_magick.rb +34 -0
- data/plugins/utils/pygments.css +1 -0
- data/plugins/utils/pygments.rb +50 -0
- data/plugins/utils/pygments.scss +83 -0
- data/plugins/utils/semaphore.rb +50 -0
- data/plugins/utils/shell.rb +45 -0
- data/plugins/utils/store.rb +315 -0
- data/plugins/utils/worker.rb +36 -0
- data/plugins/utils/xml.rb +29 -0
- data/static/images/favicon.png +0 -0
- data/static/script.js +267 -0
- data/static/script/00-json2.js +486 -0
- data/static/script/01-jstorage.js +217 -0
- data/static/script/02-jquery.js +9440 -0
- data/static/script/03-jquery.ui.core.js +337 -0
- data/static/script/04-jquery.ui.widget.js +502 -0
- data/static/script/05-jquery.ui.position.js +517 -0
- data/static/script/06-jquery.ui.menu.js +609 -0
- data/static/script/07-jquery.ui.autocomplete.js +601 -0
- data/static/script/08-olelo.i18n.js +37 -0
- data/static/script/09-olelo.unsaved.js +68 -0
- data/static/script/10-olelo.historytable.js +40 -0
- data/static/script/11-olelo.pagination.js +18 -0
- data/static/script/13-olelo.tabwidget.js +57 -0
- data/static/script/14-olelo.timeago.js +70 -0
- data/static/script/15-olelo.underliner.js +31 -0
- data/static/script/16-olelo.ui.combobox.js +32 -0
- data/static/script/init.js +48 -0
- data/static/themes/atlantis/constants.scss +15 -0
- data/static/themes/atlantis/iehacks.scss +38 -0
- data/static/themes/atlantis/images/actions/delete.png +0 -0
- data/static/themes/atlantis/images/actions/edit.png +0 -0
- data/static/themes/atlantis/images/actions/history.png +0 -0
- data/static/themes/atlantis/images/actions/home.png +0 -0
- data/static/themes/atlantis/images/actions/move.png +0 -0
- data/static/themes/atlantis/images/actions/new.png +0 -0
- data/static/themes/atlantis/images/actions/page.png +0 -0
- data/static/themes/atlantis/images/bg/button.png +0 -0
- data/static/themes/atlantis/images/bg/container.png +0 -0
- data/static/themes/atlantis/images/bg/content.png +0 -0
- data/static/themes/atlantis/images/bg/footer.png +0 -0
- data/static/themes/atlantis/images/bg/header.jpg +0 -0
- data/static/themes/atlantis/images/bg/header.orig.jpg +0 -0
- data/static/themes/atlantis/images/bg/header_gray.jpg +0 -0
- data/static/themes/atlantis/images/bug.png +0 -0
- data/static/themes/atlantis/images/filetypes/7z.png +0 -0
- data/static/themes/atlantis/images/filetypes/_archive.png +0 -0
- data/static/themes/atlantis/images/filetypes/_audio.png +0 -0
- data/static/themes/atlantis/images/filetypes/_code.png +0 -0
- data/static/themes/atlantis/images/filetypes/_linux.png +0 -0
- data/static/themes/atlantis/images/filetypes/_picture.png +0 -0
- data/static/themes/atlantis/images/filetypes/_video.png +0 -0
- data/static/themes/atlantis/images/filetypes/bz2.png +0 -0
- data/static/themes/atlantis/images/filetypes/doc.png +0 -0
- data/static/themes/atlantis/images/filetypes/flac.png +0 -0
- data/static/themes/atlantis/images/filetypes/gz.png +0 -0
- data/static/themes/atlantis/images/filetypes/html.png +0 -0
- data/static/themes/atlantis/images/filetypes/java.png +0 -0
- data/static/themes/atlantis/images/filetypes/jpg.png +0 -0
- data/static/themes/atlantis/images/filetypes/midi.png +0 -0
- data/static/themes/atlantis/images/filetypes/mp3.png +0 -0
- data/static/themes/atlantis/images/filetypes/ogg.png +0 -0
- data/static/themes/atlantis/images/filetypes/pdf.png +0 -0
- data/static/themes/atlantis/images/filetypes/php.png +0 -0
- data/static/themes/atlantis/images/filetypes/png.png +0 -0
- data/static/themes/atlantis/images/filetypes/ppt.png +0 -0
- data/static/themes/atlantis/images/filetypes/psd.png +0 -0
- data/static/themes/atlantis/images/filetypes/rar.png +0 -0
- data/static/themes/atlantis/images/filetypes/rb.png +0 -0
- data/static/themes/atlantis/images/filetypes/sh.png +0 -0
- data/static/themes/atlantis/images/filetypes/tar.png +0 -0
- data/static/themes/atlantis/images/filetypes/txt.png +0 -0
- data/static/themes/atlantis/images/filetypes/wma.png +0 -0
- data/static/themes/atlantis/images/filetypes/xls.png +0 -0
- data/static/themes/atlantis/images/filetypes/zip.png +0 -0
- data/static/themes/atlantis/images/folder.png +0 -0
- data/static/themes/atlantis/images/folder_open.png +0 -0
- data/static/themes/atlantis/images/loading.gif +0 -0
- data/static/themes/atlantis/images/loading.xcf +0 -0
- data/static/themes/atlantis/images/not_found.png +0 -0
- data/static/themes/atlantis/images/page.png +0 -0
- data/static/themes/atlantis/images/search.png +0 -0
- data/static/themes/atlantis/layout.scss +115 -0
- data/static/themes/atlantis/menu.scss +99 -0
- data/static/themes/atlantis/print.scss +129 -0
- data/static/themes/atlantis/screen.scss +495 -0
- data/static/themes/atlantis/style.css +3 -0
- data/static/themes/lib/autocomplete.scss +39 -0
- data/static/themes/lib/headlines.scss +10 -0
- data/static/themes/lib/horizontal-list.scss +31 -0
- data/static/themes/lib/patch.scss +88 -0
- data/static/themes/lib/reset.scss +114 -0
- data/static/themes/lib/rounded.scss +46 -0
- data/static/themes/lib/shadow.scss +14 -0
- data/test/config_test.rb +28 -0
- data/test/factory_test.rb +29 -0
- data/test/hash_extensions_test.rb +16 -0
- data/test/helper.rb +38 -0
- data/test/hooks_test.rb +85 -0
- data/test/object_extensions_test.rb +20 -0
- data/test/page_test.rb +168 -0
- data/test/request_test.rb +166 -0
- data/test/string_extensions_test.rb +32 -0
- data/test/templates_test.rb +39 -0
- data/test/util_test.rb +71 -0
- data/views/changes.slim +22 -0
- data/views/compare.slim +8 -0
- data/views/delete.slim +9 -0
- data/views/deleted.slim +2 -0
- data/views/edit.slim +65 -0
- data/views/error.slim +6 -0
- data/views/history.slim +20 -0
- data/views/layout.slim +38 -0
- data/views/login.slim +37 -0
- data/views/move.slim +10 -0
- data/views/not_found.slim +6 -0
- data/views/profile.slim +26 -0
- data/views/show.slim +9 -0
- 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,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 @@
|
|
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
|
+
}
|