cortex-reaver 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/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
|