radiant 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of radiant might be problematic. Click here for more details.

Files changed (205) hide show
  1. data/CHANGELOG +1 -0
  2. data/CONTRIBUTORS +12 -0
  3. data/LICENSE +9 -0
  4. data/README +91 -0
  5. data/Rakefile +10 -0
  6. data/app/behaviors/archive_behavior.rb +42 -0
  7. data/app/behaviors/archive_day_index_behavior.rb +30 -0
  8. data/app/behaviors/archive_month_index_behavior.rb +30 -0
  9. data/app/behaviors/archive_year_index_behavior.rb +30 -0
  10. data/app/behaviors/env_behavior.rb +18 -0
  11. data/app/behaviors/page_missing_behavior.rb +31 -0
  12. data/app/controllers/admin/export_controller.rb +8 -0
  13. data/app/controllers/admin/layout_controller.rb +23 -0
  14. data/app/controllers/admin/model_controller.rb +119 -0
  15. data/app/controllers/admin/page_controller.rb +119 -0
  16. data/app/controllers/admin/snippet_controller.rb +6 -0
  17. data/app/controllers/admin/user_controller.rb +45 -0
  18. data/app/controllers/admin/welcome_controller.rb +39 -0
  19. data/app/controllers/application.rb +32 -0
  20. data/app/controllers/site_controller.rb +54 -0
  21. data/app/filters/markdown_filter.rb +9 -0
  22. data/app/filters/textile_filter.rb +9 -0
  23. data/app/helpers/admin/export_helper.rb +2 -0
  24. data/app/helpers/admin/layout_helper.rb +2 -0
  25. data/app/helpers/admin/page_helper.rb +10 -0
  26. data/app/helpers/admin/snippet_helper.rb +2 -0
  27. data/app/helpers/admin/user_helper.rb +2 -0
  28. data/app/helpers/admin/welcome_helper.rb +2 -0
  29. data/app/helpers/application_helper.rb +141 -0
  30. data/app/helpers/site_helper.rb +2 -0
  31. data/app/models/archive_finder.rb +66 -0
  32. data/app/models/behavior.rb +194 -0
  33. data/app/models/layout.rb +13 -0
  34. data/app/models/page.rb +91 -0
  35. data/app/models/page_context.rb +526 -0
  36. data/app/models/page_part.rb +13 -0
  37. data/app/models/radiant/config.rb +53 -0
  38. data/app/models/radiant/exporter.rb +11 -0
  39. data/app/models/response_cache.rb +112 -0
  40. data/app/models/snippet.rb +16 -0
  41. data/app/models/status.rb +31 -0
  42. data/app/models/text_filter.rb +11 -0
  43. data/app/models/user.rb +70 -0
  44. data/app/models/user_action_observer.rb +13 -0
  45. data/app/views/admin/layout/index.rhtml +38 -0
  46. data/app/views/admin/layout/new.rhtml +37 -0
  47. data/app/views/admin/layout/remove.rhtml +17 -0
  48. data/app/views/admin/page/_node.rhtml +51 -0
  49. data/app/views/admin/page/_part.rhtml +17 -0
  50. data/app/views/admin/page/children.rhtml +4 -0
  51. data/app/views/admin/page/index.rhtml +172 -0
  52. data/app/views/admin/page/new.rhtml +164 -0
  53. data/app/views/admin/page/remove.rhtml +14 -0
  54. data/app/views/admin/snippet/index.rhtml +36 -0
  55. data/app/views/admin/snippet/new.rhtml +28 -0
  56. data/app/views/admin/snippet/remove.rhtml +16 -0
  57. data/app/views/admin/user/index.rhtml +43 -0
  58. data/app/views/admin/user/new.rhtml +48 -0
  59. data/app/views/admin/user/preferences.rhtml +29 -0
  60. data/app/views/admin/user/remove.rhtml +16 -0
  61. data/app/views/admin/welcome/login.rhtml +51 -0
  62. data/app/views/layouts/application.rhtml +75 -0
  63. data/app/views/site/not_found.rhtml +3 -0
  64. data/bin/radiant +305 -0
  65. data/config/boot.rb +80 -0
  66. data/config/database.mysql.yml +20 -0
  67. data/config/database.postgresql.yml +20 -0
  68. data/config/database.sqlite.yml +20 -0
  69. data/config/environment.rb +76 -0
  70. data/config/environments/development.rb +20 -0
  71. data/config/environments/production.rb +22 -0
  72. data/config/environments/test.rb +20 -0
  73. data/config/locomotive.yml +6 -0
  74. data/config/routes.rb +64 -0
  75. data/db/development_structure.sql +80 -0
  76. data/db/migrate/001_create_radiant_tables.rb +73 -0
  77. data/db/migrate/002_insert_initial_data.rb +45 -0
  78. data/db/migrate/003_rename_behavior_column.rb +9 -0
  79. data/db/migrate/004_rename_filter_column.rb +11 -0
  80. data/db/migrate/005_add_virtual_column_to_page.rb +9 -0
  81. data/db/migrate/006_integer_columns_to_boolean.rb +11 -0
  82. data/db/migrate/007_remove_virtual_column_from_page.rb +9 -0
  83. data/db/migrate/008_add_virtual_column_to_page_again.rb +9 -0
  84. data/db/migrate/009_add_content_type_field_to_layout.rb +9 -0
  85. data/db/schema.rb +74 -0
  86. data/db/templates/empty.yml +2 -0
  87. data/db/templates/simple-blog.yml +197 -0
  88. data/db/templates/styled-blog.yml +472 -0
  89. data/lib/advanced_delegation.rb +21 -0
  90. data/lib/archive_index_behavior_tags_and_methods.rb +48 -0
  91. data/lib/generators/behavior/USAGE +16 -0
  92. data/lib/generators/behavior/behavior_generator.rb +22 -0
  93. data/lib/generators/behavior/templates/model.rb.template +9 -0
  94. data/lib/generators/behavior/templates/unit_test.rb.template +16 -0
  95. data/lib/generators/filter/USAGE +16 -0
  96. data/lib/generators/filter/filter_generator.rb +22 -0
  97. data/lib/generators/filter/templates/model.rb.template +8 -0
  98. data/lib/generators/filter/templates/unit_test.rb.template +7 -0
  99. data/lib/inheritable_class_attributes.rb +65 -0
  100. data/lib/login_system.rb +80 -0
  101. data/lib/plugins/index_quoting_fix/init.rb +32 -0
  102. data/lib/plugins/string_io/init.rb +2 -0
  103. data/lib/radiant.rb +5 -0
  104. data/lib/registerable.rb +70 -0
  105. data/lib/tasks/release.rake +84 -0
  106. data/public/404.html +8 -0
  107. data/public/500.html +8 -0
  108. data/public/dispatch.cgi +10 -0
  109. data/public/dispatch.fcgi +24 -0
  110. data/public/dispatch.rb +10 -0
  111. data/public/favicon.ico +0 -0
  112. data/public/images/add-child.png +0 -0
  113. data/public/images/brown-bottom-line.gif +0 -0
  114. data/public/images/clear-page-cache.png +0 -0
  115. data/public/images/collapse.png +0 -0
  116. data/public/images/expand.png +0 -0
  117. data/public/images/minus.png +0 -0
  118. data/public/images/new-homepage.png +0 -0
  119. data/public/images/new-layout.png +0 -0
  120. data/public/images/new-snippet.png +0 -0
  121. data/public/images/new-user.png +0 -0
  122. data/public/images/page.png +0 -0
  123. data/public/images/plus.png +0 -0
  124. data/public/images/remove-disabled.png +0 -0
  125. data/public/images/remove.png +0 -0
  126. data/public/images/snippet.png +0 -0
  127. data/public/images/spinner.gif +0 -0
  128. data/public/images/view-site.gif +0 -0
  129. data/public/images/virtual-page.png +0 -0
  130. data/public/javascripts/application.js +2 -0
  131. data/public/javascripts/controls.js +815 -0
  132. data/public/javascripts/dragdrop.js +913 -0
  133. data/public/javascripts/effects.js +958 -0
  134. data/public/javascripts/pngfix.js +78 -0
  135. data/public/javascripts/prototype.js +2006 -0
  136. data/public/javascripts/ruledtable.js +28 -0
  137. data/public/javascripts/string.js +23 -0
  138. data/public/javascripts/tabcontrol.js +140 -0
  139. data/public/robots.txt +1 -0
  140. data/public/stylesheets/admin.css +464 -0
  141. data/script/about +3 -0
  142. data/script/breakpointer +3 -0
  143. data/script/console +3 -0
  144. data/script/destroy +3 -0
  145. data/script/generate +3 -0
  146. data/script/performance/benchmarker +3 -0
  147. data/script/performance/profiler +3 -0
  148. data/script/plugin +3 -0
  149. data/script/process/reaper +3 -0
  150. data/script/process/spawner +3 -0
  151. data/script/process/spinner +3 -0
  152. data/script/runner +3 -0
  153. data/script/server +3 -0
  154. data/script/setup_database +297 -0
  155. data/test/fixtures/layouts.yml +26 -0
  156. data/test/fixtures/page_parts.yml +99 -0
  157. data/test/fixtures/pages.yml +359 -0
  158. data/test/fixtures/pages.yml.rej +28 -0
  159. data/test/fixtures/snippets.yml +18 -0
  160. data/test/fixtures/users.yml +30 -0
  161. data/test/functional/admin/export_controller_test.rb +22 -0
  162. data/test/functional/admin/layout_controller_test.rb +40 -0
  163. data/test/functional/admin/model_controller_test.rb +152 -0
  164. data/test/functional/admin/page_controller_test.rb +179 -0
  165. data/test/functional/admin/snippet_controller_test.rb +11 -0
  166. data/test/functional/admin/user_controller_test.rb +71 -0
  167. data/test/functional/admin/welcome_controller_test.rb +48 -0
  168. data/test/functional/application_controller_test.rb +44 -0
  169. data/test/functional/login_system_test.rb +155 -0
  170. data/test/functional/site_controller_test.rb +172 -0
  171. data/test/helpers/archive_index_test_helper.rb +35 -0
  172. data/test/helpers/behavior_render_test_helper.rb +34 -0
  173. data/test/helpers/behavior_test_helper.rb +47 -0
  174. data/test/helpers/caching_test_helper.rb +41 -0
  175. data/test/helpers/layout_test_helper.rb +35 -0
  176. data/test/helpers/page_part_test_helper.rb +49 -0
  177. data/test/helpers/page_test_helper.rb +36 -0
  178. data/test/helpers/snippet_test_helper.rb +32 -0
  179. data/test/helpers/user_test_helper.rb +34 -0
  180. data/test/helpers/validation_test_helper.rb +42 -0
  181. data/test/test_helper.rb +54 -0
  182. data/test/unit/behavior_test.rb +196 -0
  183. data/test/unit/behaviors/archive_behavior_test.rb +33 -0
  184. data/test/unit/behaviors/archive_day_index_behavior_test.rb +21 -0
  185. data/test/unit/behaviors/archive_month_index_behavior_test.rb +21 -0
  186. data/test/unit/behaviors/archive_year_index_behavior_test.rb +21 -0
  187. data/test/unit/behaviors/page_missing_behavior_test.rb +27 -0
  188. data/test/unit/filters/markdown_filter_test.rb +14 -0
  189. data/test/unit/filters/textile_filter_test.rb +14 -0
  190. data/test/unit/inheritable_class_attributes_test.rb +47 -0
  191. data/test/unit/layout_test.rb +29 -0
  192. data/test/unit/page_context_test.rb +375 -0
  193. data/test/unit/page_context_test.rb.rej +26 -0
  194. data/test/unit/page_part_test.rb +44 -0
  195. data/test/unit/page_test.rb +224 -0
  196. data/test/unit/radiant/config_test.rb +46 -0
  197. data/test/unit/radiant/exporter_test.rb +26 -0
  198. data/test/unit/registerable_test.rb +68 -0
  199. data/test/unit/response_cache_test.rb +133 -0
  200. data/test/unit/snippet_test.rb +47 -0
  201. data/test/unit/status_test.rb +43 -0
  202. data/test/unit/text_filter_test.rb +14 -0
  203. data/test/unit/user_action_observer_test.rb +40 -0
  204. data/test/unit/user_test.rb +138 -0
  205. metadata +355 -0
@@ -0,0 +1,119 @@
1
+ class Admin::PageController < ApplicationController
2
+ model :page
3
+
4
+ attr_accessor :cache
5
+
6
+ def initialize
7
+ super
8
+ @cache = ResponseCache.instance
9
+ end
10
+
11
+ def index
12
+ @homepage = Page.find_by_parent_id(nil)
13
+ end
14
+
15
+ def new
16
+ @page = Page.new
17
+ @page.slug = params[:slug]
18
+ @page.breadcrumb = params[:breadcrumb]
19
+ @page.parent = Page.find_by_id(params[:parent_id])
20
+ if request.get?
21
+ default_parts.each do |name|
22
+ @page.parts << PagePart.new(:name => name)
23
+ end
24
+ end
25
+ handle_new_or_edit_post
26
+ end
27
+
28
+ def edit
29
+ @page = Page.find_by_id(params[:id])
30
+ render :action => :new if handle_new_or_edit_post
31
+ end
32
+
33
+ def remove
34
+ @page = Page.find_by_id(params[:id])
35
+ if request.post?
36
+ announce_pages_removed(@page.children.count + 1)
37
+ @page.destroy
38
+ redirect_to page_index_url
39
+ end
40
+ end
41
+
42
+ def clear_cache
43
+ if request.post?
44
+ @cache.clear
45
+ announce_cache_cleared
46
+ redirect_to page_index_url
47
+ else
48
+ render :text => 'Do not access this URL directly.'
49
+ end
50
+ end
51
+
52
+ def add_part
53
+ part = PagePart.new(params[:part])
54
+ render(:partial => 'part', :object => part, :layout => false)
55
+ end
56
+
57
+ def children
58
+ @parent = Page.find(params[:id])
59
+ @level = params[:level].to_i
60
+ response.headers['Content-Type'] = 'text/html;charset=utf-8'
61
+ render(:layout => false)
62
+ end
63
+
64
+ private
65
+ def announce_page_saved
66
+ flash[:notice] = "Your page has been saved below."
67
+ end
68
+
69
+ def announce_validation_errors
70
+ flash[:error] = "Validation errors occurred while processing this form. Please take a moment to review the form and correct any input errors before continuing."
71
+ end
72
+
73
+ def announce_pages_removed(count)
74
+ flash[:notice] = if count > 1
75
+ "The pages were successfully removed from the site."
76
+ else
77
+ "The page was successfully removed from the site."
78
+ end
79
+ end
80
+
81
+ def announce_cache_cleared
82
+ flash[:notice] = "The page cache was successfully cleared."
83
+ end
84
+
85
+ def handle_new_or_edit_post
86
+ if request.post?
87
+ @page.attributes = params[:page]
88
+
89
+ original_names = @page.parts.map { |part| part.name }
90
+ new_names = (params[:part] || {}).values.map { |part| part[:name] }
91
+ names_to_remove = (original_names - new_names)
92
+
93
+ parts_to_update = []
94
+ (params[:part] || {}).values.each do |v|
95
+ if part = @page.parts.find_by_name(v[:name])
96
+ part.attributes = part.attributes.merge(v)
97
+ parts_to_update << part
98
+ else
99
+ @page.parts.build(v)
100
+ end
101
+ end
102
+ if @page.save
103
+ names_to_remove.each { |name| @page.parts.find_by_name(name).destroy }
104
+ parts_to_update.each { |part| part.save }
105
+ @cache.expire_response(@page.url)
106
+ announce_page_saved
107
+ if params[:continue]
108
+ redirect_to page_edit_url(:id => @page.id)
109
+ else
110
+ redirect_to page_index_url
111
+ end
112
+ return false
113
+ else
114
+ announce_validation_errors
115
+ end
116
+ end
117
+ true
118
+ end
119
+ end
@@ -0,0 +1,6 @@
1
+ require_dependency 'admin/model_controller'
2
+ require_dependency 'response_cache'
3
+
4
+ class Admin::SnippetController < Admin::AbstractModelController
5
+ model :snippet
6
+ end
@@ -0,0 +1,45 @@
1
+ require_dependency 'admin/model_controller'
2
+
3
+ class Admin::UserController < Admin::AbstractModelController
4
+ model :user
5
+
6
+ only_allow_access_to :index, :new, :edit, :remove, :when => :admin,
7
+ :denied_url => {:controller => 'page', :action => :index},
8
+ :denied_message => 'You must have administrative privileges to perform this action.'
9
+
10
+ def preferences
11
+ @user = User.find(session[:user].id)
12
+ if valid_params?
13
+ handle_new_or_edit_post(
14
+ :redirect_to => page_index_url,
15
+ :saved_message => 'Your preferences have been saved.'
16
+ )
17
+ else
18
+ announce_bad_data
19
+ end
20
+ end
21
+
22
+ def remove
23
+ if session[:user].id.to_s == params[:id].to_s
24
+ announce_cannot_delete_self
25
+ redirect_to user_index_url
26
+ else
27
+ super
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def announce_cannot_delete_self
34
+ flash[:error] = 'You cannot delete yourself.'
35
+ end
36
+
37
+ def announce_bad_data
38
+ flash[:error] = 'Bad form data.'
39
+ end
40
+
41
+ def valid_params?
42
+ hash = (params[:user] || {}).symbolize_keys
43
+ (hash.keys - [:password, :password_confirmation, :email]).size == 0
44
+ end
45
+ end
@@ -0,0 +1,39 @@
1
+ class Admin::WelcomeController < ApplicationController
2
+ no_login_required
3
+
4
+ model :user
5
+
6
+ def index
7
+ redirect_to page_index_url
8
+ end
9
+
10
+ def login
11
+ if request.post?
12
+ login = params[:user][:login]
13
+ password = params[:user][:password]
14
+ session[:user] = User.authenticate(login, password)
15
+ if session[:user]
16
+ redirect_to welcome_url
17
+ else
18
+ announce_invalid_user
19
+ end
20
+ end
21
+ end
22
+
23
+ def logout
24
+ session[:user] = nil
25
+ announce_logged_out
26
+ redirect_to login_url
27
+ end
28
+
29
+ private
30
+
31
+ def announce_logged_out
32
+ flash[:notice] = 'You are now logged out.'
33
+ end
34
+
35
+ def announce_invalid_user
36
+ flash[:error] = 'Invalid username or password.'
37
+ end
38
+
39
+ end
@@ -0,0 +1,32 @@
1
+ require_dependency 'login_system'
2
+
3
+ ActionView::Base.field_error_proc = Proc.new do |html, instance|
4
+ %{<div class="error-with-field">#{html} <small class="error">&bull; #{[instance.error_message].flatten.first}</small></div>}
5
+ end
6
+
7
+ class ApplicationController < ActionController::Base
8
+ include LoginSystem
9
+
10
+ model :user
11
+ observer :user_action_observer
12
+
13
+ before_filter :set_current_user
14
+
15
+ attr_accessor :config
16
+
17
+ def initialize
18
+ super
19
+ @config = Radiant::Config
20
+ end
21
+
22
+ def default_parts
23
+ (@config['default.parts'] || 'body, extended').strip.split(/\s*,\s*/)
24
+ end
25
+
26
+ private
27
+
28
+ def set_current_user
29
+ UserActionObserver.current_user = session[:user]
30
+ end
31
+
32
+ end
@@ -0,0 +1,54 @@
1
+ require_dependency 'response_cache'
2
+
3
+ class SiteController < ApplicationController
4
+ session :off
5
+
6
+ no_login_required
7
+
8
+ attr_accessor :config, :cache
9
+
10
+ def initialize
11
+ @config = Radiant::Config
12
+ @cache = ResponseCache.instance
13
+ end
14
+
15
+ def show_page
16
+ @response.headers.delete('Cache-Control')
17
+ url = params[:url].to_s
18
+ if live? and (@cache.response_cached?(url))
19
+ @cache.update_response(url, response)
20
+ @performed_render = true
21
+ else
22
+ show_uncached_page(url)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def find_page(url)
29
+ found = Page.find_by_url(url, live?)
30
+ found if found and (found.published? or dev?)
31
+ end
32
+
33
+ def show_uncached_page(url)
34
+ @page = find_page(url)
35
+ unless @page.nil?
36
+ @page.process(request, response)
37
+ @cache.cache_response(url, response) if live? and @page.cache?
38
+ @performed_render = true
39
+ else
40
+ render :template => 'site/not_found', :status => 404
41
+ end
42
+ rescue Page::MissingRootPageError
43
+ redirect_to(:controller => 'admin/welcome')
44
+ end
45
+
46
+ def dev?
47
+ (@request.host == @config['dev.host']) or (@request.host =~ /^dev/)
48
+ end
49
+
50
+ def live?
51
+ not dev?
52
+ end
53
+
54
+ end
@@ -0,0 +1,9 @@
1
+ require 'bluecloth'
2
+
3
+ class MarkdownFilter < TextFilter::Base
4
+ register 'Markdown'
5
+
6
+ def filter(text)
7
+ BlueCloth.new(text).to_html
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ require 'redcloth'
2
+
3
+ class TextileFilter < TextFilter::Base
4
+ register 'Textile'
5
+
6
+ def filter(text)
7
+ RedCloth.new(text).to_html
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ module ExportHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module Admin::LayoutHelper
2
+ end
@@ -0,0 +1,10 @@
1
+ module Admin::PageHelper
2
+ def render_node(page, locals = {})
3
+ locals.reverse_merge!( :level => 0, :expand => 3, :simple => false ).merge!( :page => page )
4
+ render :partial => 'node', :locals => locals
5
+ end
6
+
7
+ def meta_errors?
8
+ !!(@page.errors[:slug] or @page.errors[:breadcrumb])
9
+ end
10
+ end
@@ -0,0 +1,2 @@
1
+ module Admin::SnippetHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module Admin::UserHelper
2
+ end
@@ -0,0 +1,2 @@
1
+ module Admin::WelcomeHelper
2
+ end
@@ -0,0 +1,141 @@
1
+ require 'radiant/config'
2
+
3
+ module ApplicationHelper
4
+ def config
5
+ Radiant::Config
6
+ end
7
+
8
+ def default_page_title
9
+ title + ' - ' + subtitle
10
+ end
11
+
12
+ def title
13
+ config['admin.title'] || 'Radiant CMS'
14
+ end
15
+
16
+ def subtitle
17
+ config['admin.subtitle'] || 'Publishing for Small Teams'
18
+ end
19
+
20
+ def logged_in?
21
+ session[:user] ? true : false
22
+ end
23
+
24
+ def save_model_button(model)
25
+ label = if model.new_record?
26
+ "Create #{model.class.name}"
27
+ else
28
+ 'Save Changes'
29
+ end
30
+ submit_tag label, :class => 'button'
31
+ end
32
+
33
+ def save_model_and_continue_editing_button(model)
34
+ submit_tag 'Save and Continue Editing', :name => 'continue', :class => 'button'
35
+ end
36
+
37
+ # Redefine pluralize() so that it doesn't put the count at the beginning of
38
+ # the string.
39
+ def pluralize(count, singular, plural = nil)
40
+ if count == 1
41
+ singular
42
+ elsif plural
43
+ plural
44
+ elsif Object.const_defined?("Inflector")
45
+ Inflector.pluralize(singular)
46
+ else
47
+ singular + "s"
48
+ end
49
+ end
50
+
51
+ def links_for_navigation
52
+ tabs = []
53
+ tabs << nav_link_to('Pages', page_index_url)
54
+ tabs << nav_link_to('Snippets', snippet_index_url)
55
+ tabs << nav_link_to('Layouts', layout_index_url) if developer?
56
+ tabs.join(separator)
57
+ end
58
+
59
+ def separator
60
+ %{ <span class="separator"> | </span> }
61
+ end
62
+
63
+ def current_url?(options)
64
+ url = case
65
+ when Hash
66
+ url_for options
67
+ else
68
+ options.to_s
69
+ end
70
+ request.request_uri =~ Regexp.new('^' + Regexp.quote(clean(url)))
71
+ end
72
+
73
+ def clean(url)
74
+ uri = URI.parse(url)
75
+ uri.path.gsub(%r{/+}, '/').gsub(%r{/$}, '')
76
+ end
77
+
78
+ def nav_link_to(name, options)
79
+ logger.debug 'options are: ' + options.to_s
80
+ if current_url?(options)
81
+ %{<strong>#{ link_to name, options }</strong>}
82
+ else
83
+ link_to name, options
84
+ end
85
+ end
86
+
87
+ def admin?
88
+ user = session[:user]
89
+ user and user.admin?
90
+ end
91
+
92
+ def developer?
93
+ user = session[:user]
94
+ user and (user.developer? or user.admin?)
95
+ end
96
+
97
+ def focus(field_name)
98
+ %{
99
+ <script type="text/javascript">
100
+ // <![CDATA[
101
+ Field.activate('#{field_name}');
102
+ // ]]>
103
+ </script>
104
+ }
105
+ end
106
+
107
+ def updated_stamp(model)
108
+ unless model.new_record?
109
+ updated_by = (model.updated_by || model.created_by)
110
+ login = updated_by ? updated_by.login : nil
111
+ time = (model.updated_at || model.created_at)
112
+ if login or time
113
+ html = %{<p style="clear: left"><small>Last updated }
114
+ html << %{by #{login} } if login
115
+ html << %{at #{ time.strftime("%I:%M <small>%p</small> on %B %d, %Y") }} if time
116
+ html << %{</small></p>}
117
+ html
118
+ end
119
+ else
120
+ %{<p class="clear">&nbsp;</p>}
121
+ end
122
+ end
123
+
124
+ def meta_visible(symbol)
125
+ v = case symbol
126
+ when :meta_more
127
+ not meta_errors?
128
+ when :meta, :meta_less
129
+ meta_errors?
130
+ end
131
+ ' style="display: none"' unless v
132
+ end
133
+
134
+ def meta_errors?
135
+ false
136
+ end
137
+
138
+ def toggle_javascript_for(id)
139
+ "javascript:Element.toggle('#{id}', 'more-#{id}', 'less-#{id}')"
140
+ end
141
+ end