cortex-reaver 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +25 -0
- data/README +48 -0
- data/bin/console +11 -0
- data/bin/cortex_reaver +110 -0
- data/bin/import.rb +78 -0
- data/lib/cortex_reaver.rb +114 -0
- data/lib/cortex_reaver/config.rb +21 -0
- data/lib/cortex_reaver/controller/comment.rb +113 -0
- data/lib/cortex_reaver/controller/config.rb +14 -0
- data/lib/cortex_reaver/controller/journal.rb +40 -0
- data/lib/cortex_reaver/controller/main.rb +56 -0
- data/lib/cortex_reaver/controller/page.rb +34 -0
- data/lib/cortex_reaver/controller/photograph.rb +45 -0
- data/lib/cortex_reaver/controller/project.rb +40 -0
- data/lib/cortex_reaver/controller/tag.rb +67 -0
- data/lib/cortex_reaver/controller/user.rb +71 -0
- data/lib/cortex_reaver/helper/activity.rb +9 -0
- data/lib/cortex_reaver/helper/attachments.rb +139 -0
- data/lib/cortex_reaver/helper/auth.rb +45 -0
- data/lib/cortex_reaver/helper/canonical.rb +55 -0
- data/lib/cortex_reaver/helper/crud.rb +317 -0
- data/lib/cortex_reaver/helper/date.rb +29 -0
- data/lib/cortex_reaver/helper/error.rb +14 -0
- data/lib/cortex_reaver/helper/feeds.rb +88 -0
- data/lib/cortex_reaver/helper/form.rb +114 -0
- data/lib/cortex_reaver/helper/navigation.rb +142 -0
- data/lib/cortex_reaver/helper/photographs.rb +25 -0
- data/lib/cortex_reaver/helper/tags.rb +47 -0
- data/lib/cortex_reaver/helper/workflow.rb +27 -0
- data/lib/cortex_reaver/migrations/001_users.rb +24 -0
- data/lib/cortex_reaver/migrations/002_pages.rb +29 -0
- data/lib/cortex_reaver/migrations/003_journals.rb +26 -0
- data/lib/cortex_reaver/migrations/004_photographs.rb +24 -0
- data/lib/cortex_reaver/migrations/005_projects.rb +27 -0
- data/lib/cortex_reaver/migrations/006_tags.rb +64 -0
- data/lib/cortex_reaver/migrations/007_comments.rb +40 -0
- data/lib/cortex_reaver/migrations/008_config.rb +23 -0
- data/lib/cortex_reaver/model/comment.rb +109 -0
- data/lib/cortex_reaver/model/journal.rb +53 -0
- data/lib/cortex_reaver/model/page.rb +87 -0
- data/lib/cortex_reaver/model/photograph.rb +133 -0
- data/lib/cortex_reaver/model/project.rb +49 -0
- data/lib/cortex_reaver/model/tag.rb +72 -0
- data/lib/cortex_reaver/model/user.rb +147 -0
- data/lib/cortex_reaver/public/css/admin.css +45 -0
- data/lib/cortex_reaver/public/css/custom.css +0 -0
- data/lib/cortex_reaver/public/css/form.css +51 -0
- data/lib/cortex_reaver/public/css/main.css +325 -0
- data/lib/cortex_reaver/public/css/photo.css +113 -0
- data/lib/cortex_reaver/public/css/ramaze_error.css +90 -0
- data/lib/cortex_reaver/public/css/text.css +25 -0
- data/lib/cortex_reaver/public/dispatch.fcgi +11 -0
- data/lib/cortex_reaver/public/images/CortexReaver.gif +0 -0
- data/lib/cortex_reaver/public/images/atom-xml-icon.png +0 -0
- data/lib/cortex_reaver/public/images/body.png +0 -0
- data/lib/cortex_reaver/public/images/border_bottom.png +0 -0
- data/lib/cortex_reaver/public/images/border_bottom_left.png +0 -0
- data/lib/cortex_reaver/public/images/border_bottom_right.png +0 -0
- data/lib/cortex_reaver/public/images/border_left.png +0 -0
- data/lib/cortex_reaver/public/images/border_right.png +0 -0
- data/lib/cortex_reaver/public/images/border_top.png +0 -0
- data/lib/cortex_reaver/public/images/border_top_left.png +0 -0
- data/lib/cortex_reaver/public/images/border_top_right.png +0 -0
- data/lib/cortex_reaver/public/images/comment.gif +0 -0
- data/lib/cortex_reaver/public/images/dark_trans.png +0 -0
- data/lib/cortex_reaver/public/images/delete.gif +0 -0
- data/lib/cortex_reaver/public/images/edit.gif +0 -0
- data/lib/cortex_reaver/public/images/header.png +0 -0
- data/lib/cortex_reaver/public/images/header.xcf +0 -0
- data/lib/cortex_reaver/public/images/header_background.png +0 -0
- data/lib/cortex_reaver/public/images/parent.gif +0 -0
- data/lib/cortex_reaver/public/images/rss-xml-icon.png +0 -0
- data/lib/cortex_reaver/public/images/sections.png +0 -0
- data/lib/cortex_reaver/public/images/sections_highlight.png +0 -0
- data/lib/cortex_reaver/public/js/admin.js +36 -0
- data/lib/cortex_reaver/public/js/cookie.js +27 -0
- data/lib/cortex_reaver/public/js/jquery.js +32 -0
- data/lib/cortex_reaver/public/js/photo.js +33 -0
- data/lib/cortex_reaver/snippets/array.rb +7 -0
- data/lib/cortex_reaver/snippets/ramaze/dispatcher/file.rb +37 -0
- data/lib/cortex_reaver/support/attachments.rb +235 -0
- data/lib/cortex_reaver/support/cached_rendering.rb +79 -0
- data/lib/cortex_reaver/support/canonical.rb +107 -0
- data/lib/cortex_reaver/support/comments.rb +69 -0
- data/lib/cortex_reaver/support/pagination.rb +38 -0
- data/lib/cortex_reaver/support/renderer.rb +196 -0
- data/lib/cortex_reaver/support/sequenceable.rb +248 -0
- data/lib/cortex_reaver/support/tags.rb +108 -0
- data/lib/cortex_reaver/support/timestamps.rb +33 -0
- data/lib/cortex_reaver/version.rb +8 -0
- data/lib/cortex_reaver/view/adminbox.rhtml +56 -0
- data/lib/cortex_reaver/view/blank_layout.rhtml +46 -0
- data/lib/cortex_reaver/view/comments/comment.rhtml +34 -0
- data/lib/cortex_reaver/view/comments/form.rhtml +25 -0
- data/lib/cortex_reaver/view/comments/list.rhtml +5 -0
- data/lib/cortex_reaver/view/comments/post_form.rhtml +36 -0
- data/lib/cortex_reaver/view/config/form.rhtml +10 -0
- data/lib/cortex_reaver/view/error.rhtml +72 -0
- data/lib/cortex_reaver/view/journals/form.rhtml +12 -0
- data/lib/cortex_reaver/view/journals/journal.rhtml +39 -0
- data/lib/cortex_reaver/view/journals/list.rhtml +33 -0
- data/lib/cortex_reaver/view/journals/short.rhtml +3 -0
- data/lib/cortex_reaver/view/journals/show.rhtml +5 -0
- data/lib/cortex_reaver/view/pages/form.rhtml +12 -0
- data/lib/cortex_reaver/view/pages/list.rhtml +26 -0
- data/lib/cortex_reaver/view/pages/show.rhtml +12 -0
- data/lib/cortex_reaver/view/photographs/atom_fragment.rhtml +82 -0
- data/lib/cortex_reaver/view/photographs/form.rhtml +19 -0
- data/lib/cortex_reaver/view/photographs/grid.rhtml +36 -0
- data/lib/cortex_reaver/view/photographs/list.rhtml +9 -0
- data/lib/cortex_reaver/view/photographs/short.rhtml +3 -0
- data/lib/cortex_reaver/view/photographs/show.rhtml +114 -0
- data/lib/cortex_reaver/view/photographs/sidebar.rhtml +7 -0
- data/lib/cortex_reaver/view/projects/form.rhtml +13 -0
- data/lib/cortex_reaver/view/projects/list.rhtml +27 -0
- data/lib/cortex_reaver/view/projects/show.rhtml +38 -0
- data/lib/cortex_reaver/view/tags/form.rhtml +9 -0
- data/lib/cortex_reaver/view/tags/list.rhtml +28 -0
- data/lib/cortex_reaver/view/tags/show.rhtml +51 -0
- data/lib/cortex_reaver/view/text_layout.rhtml +78 -0
- data/lib/cortex_reaver/view/users/form.rhtml +16 -0
- data/lib/cortex_reaver/view/users/list.rhtml +38 -0
- data/lib/cortex_reaver/view/users/login.rhtml +13 -0
- data/lib/cortex_reaver/view/users/register.rhtml +13 -0
- data/lib/cortex_reaver/view/users/show.rhtml +37 -0
- data/lib/cortex_reaver/view/users/user.rhtml +35 -0
- data/lib/proto/cortex_reaver.yaml +28 -0
- metadata +285 -0
@@ -0,0 +1,88 @@
|
|
1
|
+
module Ramaze
|
2
|
+
module Helper
|
3
|
+
# Adds an atom method to each controller it's included in, which
|
4
|
+
# lists that controller's recent elements by yielding a block with
|
5
|
+
# each record and a builder object for the feed.
|
6
|
+
#
|
7
|
+
# Requires crud.
|
8
|
+
module Feeds
|
9
|
+
require 'builder'
|
10
|
+
|
11
|
+
Helper::LOOKUP << self
|
12
|
+
|
13
|
+
def self.included(base)
|
14
|
+
base.instance_eval do
|
15
|
+
def self.for_feed(&block)
|
16
|
+
@for_feed_block = block
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.for_feed_block
|
20
|
+
@for_feed_block
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def atom
|
26
|
+
atom_builder
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def atom_builder(params = {:model_class => self.model_class})
|
32
|
+
response['Content-Type'] = 'application/atom+xml'
|
33
|
+
|
34
|
+
x = Builder::XmlMarkup.new(:indent => 2)
|
35
|
+
x.instruct!
|
36
|
+
|
37
|
+
# Get model class to work with
|
38
|
+
model_class = params[:model_class]
|
39
|
+
|
40
|
+
# Get recent items
|
41
|
+
recent = params[:recent] || model_class.recent
|
42
|
+
|
43
|
+
# Find update time
|
44
|
+
updated = recent.first.updated_on.xmlschema
|
45
|
+
|
46
|
+
x.feed(:xmlns => 'http://www.w3.org/2005/Atom') do
|
47
|
+
x.id = model_class.url
|
48
|
+
x.title CortexReaver.config.name + ' - ' + model_class.to_s.demodulize.titleize
|
49
|
+
# x.subtitle
|
50
|
+
x.updated updated
|
51
|
+
x.link :href => model_class.url
|
52
|
+
x.link :href => model_class.atom_url, :rel => 'self'
|
53
|
+
|
54
|
+
recent.all do |model|
|
55
|
+
x.entry do
|
56
|
+
x.id model.url
|
57
|
+
x.title model.title
|
58
|
+
x.published model.created_on.xmlschema
|
59
|
+
x.updated model.updated_on.xmlschema
|
60
|
+
x.link :href => model.url, :rel => 'alternate'
|
61
|
+
|
62
|
+
x.author do
|
63
|
+
x.name model.user.name
|
64
|
+
|
65
|
+
if model.user.http
|
66
|
+
x.uri model.user.http
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Any additional controller-specific info
|
71
|
+
if self.class.for_feed_block
|
72
|
+
self.class.for_feed_block.call(model, x)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def feeds
|
80
|
+
@feeds ||= {}
|
81
|
+
end
|
82
|
+
|
83
|
+
def feed(title, href)
|
84
|
+
feeds[title] = href
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
module Ramaze
|
2
|
+
module Helper
|
3
|
+
# Helps make forms, especially by escaping.
|
4
|
+
module Form
|
5
|
+
|
6
|
+
# Displays errors on a record.
|
7
|
+
def errors_on(model)
|
8
|
+
unless model.errors.empty?
|
9
|
+
s = "<div class=\"form-errors\">\n<h3>Errors</h3>\n<ul>\n"
|
10
|
+
model.errors.each do |attribute, error|
|
11
|
+
s << "<li>#{attribute} #{error}</li>\n"
|
12
|
+
end
|
13
|
+
s << "</ul></div>"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Makes a form for a model. Takes a model, form action, and an array of
|
18
|
+
# fields, which are passed to form_p.
|
19
|
+
def form_for(model, action, fields = [])
|
20
|
+
if model.nil?
|
21
|
+
raise ArgumentError.new("needs a model")
|
22
|
+
elsif action.nil?
|
23
|
+
raise ArgumentError.new("needs an action")
|
24
|
+
end
|
25
|
+
|
26
|
+
f = ''
|
27
|
+
|
28
|
+
unless model.errors.empty?
|
29
|
+
f << "<div class=\"form-errors\">\n"
|
30
|
+
f << "<ul>\n"
|
31
|
+
model.errors.each do |attribute, error|
|
32
|
+
f << "<li>#{attribute} #{error}\n</li>"
|
33
|
+
end
|
34
|
+
f << "</ul>\n"
|
35
|
+
f << "</div>\n"
|
36
|
+
end
|
37
|
+
|
38
|
+
f = "<form action=\"#{action}\" method=\"post\" class=\"edit-form\">"
|
39
|
+
|
40
|
+
fields.each do |field|
|
41
|
+
case field
|
42
|
+
when Array
|
43
|
+
f << form_p(field[0], ({:model => model}.merge!(field[1] || {})))
|
44
|
+
else
|
45
|
+
f << form_p(field, :model => model)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
f << form_submit("Submit #{model.class.to_s.demodulize.titleize}")
|
50
|
+
end
|
51
|
+
|
52
|
+
# Makes a paragraph for accessing an attribute. Escapes the default value.
|
53
|
+
# Parameters:
|
54
|
+
# id => the HTML id/name of the form field.
|
55
|
+
# :type => the type of form field to generate (text, password, checkbox...)
|
56
|
+
# :description => The label for the field (inferred from id by default)
|
57
|
+
# :model => The model to query for fields
|
58
|
+
# :default => The default value for the field (inferred from model and id)
|
59
|
+
def form_p(id, params = {})
|
60
|
+
type = params[:type]
|
61
|
+
description = params[:description] || id.to_s.titleize
|
62
|
+
model = params[:model]
|
63
|
+
default = params[:default]
|
64
|
+
if model and not default
|
65
|
+
default = model.send(id)
|
66
|
+
end
|
67
|
+
|
68
|
+
unless type
|
69
|
+
case default
|
70
|
+
when true
|
71
|
+
type = 'checkbox'
|
72
|
+
when false
|
73
|
+
type = 'checkbox'
|
74
|
+
else
|
75
|
+
type = 'text'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
f = '<p>'
|
80
|
+
unless type == 'checkbox' or type == 'hidden'
|
81
|
+
f << "<label for=\"#{id}\">#{description}</label>"
|
82
|
+
end
|
83
|
+
|
84
|
+
if type == 'textarea'
|
85
|
+
f << '<br />'
|
86
|
+
end
|
87
|
+
|
88
|
+
case type
|
89
|
+
when 'textarea'
|
90
|
+
f << "<textarea name=\"#{id}\" id=\"#{id}\">#{default}</textarea>"
|
91
|
+
when 'checkbox'
|
92
|
+
f << "<input type=\"checkbox\" name=\"#{id}\" id=\"#{id}\" #{default ? 'checked="checked"' : ''} />"
|
93
|
+
else
|
94
|
+
f << "<input name=\"#{id}\" id=\"#{id}\" type=\"#{type}\" value=\"#{attr_h(default)}\" />"
|
95
|
+
end
|
96
|
+
|
97
|
+
if type == 'checkbox'
|
98
|
+
f << "<label class=\"checkbox\" for=\"#{id}\">#{description}</label>"
|
99
|
+
end
|
100
|
+
|
101
|
+
f << "</p>\n"
|
102
|
+
end
|
103
|
+
|
104
|
+
def form_submit(value = "Submit")
|
105
|
+
'<p><input name="submit" type="submit" value="' + attr_h(value) + '" /></p>'
|
106
|
+
end
|
107
|
+
|
108
|
+
# Escapes quotes for HTML attributes.
|
109
|
+
def attr_h(string)
|
110
|
+
h(string).gsub('"', '"')
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,142 @@
|
|
1
|
+
module Ramaze
|
2
|
+
module Helper
|
3
|
+
# Provides navigation rendering shortcuts
|
4
|
+
module Navigation
|
5
|
+
# Returns a div with next/up/previous links for the record.
|
6
|
+
def model_nav(model)
|
7
|
+
n = '<div class="navigation actions">'
|
8
|
+
if model.previous
|
9
|
+
n << ' <a class="previous" href="' + model.previous.url + '">« Previous ' + model.class.to_s.demodulize + '</a>'
|
10
|
+
end
|
11
|
+
n << ' <a class="up" href="' + model.absolute_window_url + '">Back to ' + model.class.to_s.demodulize.pluralize + '</a>'
|
12
|
+
if model.next
|
13
|
+
n << ' <a class="next" href="' + model.next.url + '">Next ' + model.class.to_s.demodulize + ' »</a>'
|
14
|
+
end
|
15
|
+
n << '</div>'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Generate pagination links from a Sequenceable class and index.
|
19
|
+
# The index can be :first or :last for the corresponding pages, an instance
|
20
|
+
# of the class (in which case the page which would contain that instance
|
21
|
+
# is highlighted, or a page number. Limit determines how many numeric links
|
22
|
+
# to include--use :all to include all pages.
|
23
|
+
def page_nav(klass, index = nil, limit = 15)
|
24
|
+
# Translate :first, :last into corresponding windows.
|
25
|
+
case index
|
26
|
+
when :first
|
27
|
+
page = 0
|
28
|
+
when :last
|
29
|
+
page = klass.window_count - 1
|
30
|
+
when klass
|
31
|
+
# Index is actually an instance of the target class
|
32
|
+
page = index.window_absolute_index
|
33
|
+
else
|
34
|
+
# Index is a page number
|
35
|
+
page = index.to_i
|
36
|
+
end
|
37
|
+
|
38
|
+
pages = Array.new
|
39
|
+
links = '<ol class="pagination actions">'
|
40
|
+
window_count = klass.window_count
|
41
|
+
|
42
|
+
# Determine which pages to create links to
|
43
|
+
if limit.kind_of? Integer and window_count > limit
|
44
|
+
# There are more pages than we can display.
|
45
|
+
|
46
|
+
# Default first and last pages are the size of the collection
|
47
|
+
first_page = 1
|
48
|
+
last_page = window_count - 2
|
49
|
+
|
50
|
+
# The desired number of previous or next pages
|
51
|
+
previous_pages = (Float(limit - 3) / 2).floor
|
52
|
+
next_pages = (Float(limit - 3) / 2).floor
|
53
|
+
|
54
|
+
if (offset = first_page - (page - previous_pages)) > 0
|
55
|
+
# Window extends before the start of the pages
|
56
|
+
last_page = first_page + (limit - 2)
|
57
|
+
elsif (offset = (page + next_pages) - last_page) > 0
|
58
|
+
# Window extends beyond the end of the pages
|
59
|
+
first_page = last_page - (limit - 2)
|
60
|
+
else
|
61
|
+
# Window is somewhere in the middle
|
62
|
+
first_page = page - previous_pages
|
63
|
+
last_page = page + next_pages
|
64
|
+
end
|
65
|
+
|
66
|
+
# Generate list of pages
|
67
|
+
pages = [0] + (first_page..last_page).to_a + [window_count - 1]
|
68
|
+
else
|
69
|
+
# The window encompasses the entire set of pages
|
70
|
+
pages = (0 .. window_count - 1).to_a
|
71
|
+
end
|
72
|
+
|
73
|
+
if page > 0
|
74
|
+
# Add "previous page" link.
|
75
|
+
links << "<li><a href=\"#{klass.url}/page/#{page - 1}\">« Previous</a></li>"
|
76
|
+
end
|
77
|
+
|
78
|
+
# Convert pages to links
|
79
|
+
unless pages.empty?
|
80
|
+
pages.inject(pages.first - 1) do |previous, i|
|
81
|
+
if (i - previous) > 1
|
82
|
+
# These pages are not side-by-side.
|
83
|
+
links << '<li>…</li>'
|
84
|
+
end
|
85
|
+
|
86
|
+
if i == page
|
87
|
+
# This is a link to the current page.
|
88
|
+
links << "<li class=\"current\">#{i + 1}</li>"
|
89
|
+
else
|
90
|
+
# This is a link to a different page.
|
91
|
+
links << "<li><a href=\"#{klass.url}/page/#{i}\">#{i + 1}</a></li>"
|
92
|
+
end
|
93
|
+
|
94
|
+
# Remember this as the previous page.
|
95
|
+
i
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
if page < klass.window_count - 1
|
100
|
+
# Add "next page" link.
|
101
|
+
links << "<li><a href=\"#{klass.url}/page/#{page + 1}\">Next »</a></li>"
|
102
|
+
end
|
103
|
+
|
104
|
+
links << '</ol>'
|
105
|
+
end
|
106
|
+
|
107
|
+
# Returns a link to a user.
|
108
|
+
def user_link(x)
|
109
|
+
case x
|
110
|
+
when CortexReaver::User
|
111
|
+
name = x.name || x.login
|
112
|
+
A(name, :href => x.url)
|
113
|
+
when CortexReaver::Comment
|
114
|
+
if x.user
|
115
|
+
# Use attached user
|
116
|
+
user_link x.user
|
117
|
+
else
|
118
|
+
# Use anonymous info
|
119
|
+
name = x.name || x.email || 'Anonymous'
|
120
|
+
if x.email
|
121
|
+
s = "<a href=\"mailto:#{attr_h x.email}\">#{h name}</a>"
|
122
|
+
if x.http
|
123
|
+
s << " (<a href=\"#{attr_h x.http}\" rel=\"nofollow\">#{h x.http}</a>)"
|
124
|
+
end
|
125
|
+
s
|
126
|
+
elsif x.http
|
127
|
+
"<a href=\"#{attr_h x.http}\" rel=\"nofollow\">#{h name}</a>"
|
128
|
+
else
|
129
|
+
h name
|
130
|
+
end
|
131
|
+
end
|
132
|
+
else
|
133
|
+
if x.respond_to? :user
|
134
|
+
user_link x.user
|
135
|
+
else
|
136
|
+
raise ArgumentError.new("don't know how to make a user link to #{x.inspect}")
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Ramaze
|
2
|
+
module Helper
|
3
|
+
# Helps display photographs
|
4
|
+
module Photographs
|
5
|
+
def description_of(photo)
|
6
|
+
begin
|
7
|
+
if exif = photo.exif
|
8
|
+
description = ''
|
9
|
+
description << photo.date.strftime('%m/%d/%Y') + ': '
|
10
|
+
description << exif.make if exif.make
|
11
|
+
description << ' ' + exif.model + ', ' if exif.model
|
12
|
+
description << ' ' + exif.focal_length_in_35mm_film.to_i.to_s + 'mm' if exif.focal_length_in_35mm_film
|
13
|
+
description << ' at ' + exposure_time_to_s(exif.exposure_time) if exif.exposure_time
|
14
|
+
description << ' F' + exif.f_number.to_f.to_s if exif.f_number
|
15
|
+
else
|
16
|
+
nil
|
17
|
+
end
|
18
|
+
rescue
|
19
|
+
# File might not be available, or EXIF might be missing...
|
20
|
+
return description
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Ramaze
|
2
|
+
module Helper
|
3
|
+
module Tags
|
4
|
+
# Adds an AJAX-ified tag editor for a model.
|
5
|
+
def live_tags_field(model, opts={:name => 'tags'})
|
6
|
+
name = opts[:name]
|
7
|
+
title = opts[:title] || name.to_s.titleize
|
8
|
+
|
9
|
+
s = "<p><label for=\"#{name}\">#{title}</label>"
|
10
|
+
s << "<input name=\"#{name}\" id=\"#{name}\" type=\"text\" class=\"autobox\" value=\"#{attr_h(tags_on(model, false))}\" />"
|
11
|
+
s << "</p>"
|
12
|
+
|
13
|
+
s << <<EOF
|
14
|
+
|
15
|
+
<script type="text/javascript">
|
16
|
+
/* <![CDATA[ */
|
17
|
+
|
18
|
+
|
19
|
+
/* ]]> */
|
20
|
+
</script>
|
21
|
+
EOF
|
22
|
+
end
|
23
|
+
|
24
|
+
# Returns an html list of tags on a model that supports #tags.
|
25
|
+
def tags_on(model, html=true)
|
26
|
+
begin
|
27
|
+
if html
|
28
|
+
t = '<ul class="tags">'
|
29
|
+
model.tags.each do |tag|
|
30
|
+
t << "<li><a href=\"#{tag.url}\">#{tag.title}</a></li>"
|
31
|
+
end
|
32
|
+
t << '</ul>'
|
33
|
+
else
|
34
|
+
t = model.tags.map{ |t| t.title }.join(', ')
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
# HACK: This is probably only going to break because a blank model is
|
38
|
+
# missing a primary key or something like that. Since we call this
|
39
|
+
# method SO much (and because that specific error is not subclassed
|
40
|
+
# by Sequel) no custom error handling here.
|
41
|
+
''
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Ramaze
|
2
|
+
module Helper
|
3
|
+
# Provides workflow links on a per-section basis
|
4
|
+
module Workflow
|
5
|
+
def workflows
|
6
|
+
@workflows
|
7
|
+
end
|
8
|
+
|
9
|
+
def workflow(name, href)
|
10
|
+
@workflows ||= []
|
11
|
+
@workflows << [name, href]
|
12
|
+
end
|
13
|
+
|
14
|
+
def workflowbox
|
15
|
+
if @workflows
|
16
|
+
b = '<div class="workflows">'
|
17
|
+
b << ' <ul>'
|
18
|
+
@workflows.each do |name, href|
|
19
|
+
b << " <li><a href=\"#{href}\">#{name}</a></li>"
|
20
|
+
end
|
21
|
+
b << ' </ul>'
|
22
|
+
b << '</div>'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|