comatose 2.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.
Files changed (93) hide show
  1. data/CHANGELOG +176 -0
  2. data/INSTALL +19 -0
  3. data/LICENSE +20 -0
  4. data/MANIFEST +91 -0
  5. data/README.rdoc +148 -0
  6. data/Rakefile +122 -0
  7. data/SPECS +61 -0
  8. data/about.yml +7 -0
  9. data/bin/comatose +109 -0
  10. data/comatose.gemspec +113 -0
  11. data/generators/comatose_migration/USAGE +15 -0
  12. data/generators/comatose_migration/comatose_migration_generator.rb +59 -0
  13. data/generators/comatose_migration/templates/migration.rb +35 -0
  14. data/generators/comatose_migration/templates/v4_upgrade.rb +15 -0
  15. data/generators/comatose_migration/templates/v6_upgrade.rb +23 -0
  16. data/generators/comatose_migration/templates/v7_upgrade.rb +22 -0
  17. data/init.rb +2 -0
  18. data/install.rb +16 -0
  19. data/lib/acts_as_versioned.rb +543 -0
  20. data/lib/comatose/comatose_drop.rb +79 -0
  21. data/lib/comatose/configuration.rb +68 -0
  22. data/lib/comatose/page_wrapper.rb +119 -0
  23. data/lib/comatose/processing_context.rb +69 -0
  24. data/lib/comatose/tasks/admin.rb +60 -0
  25. data/lib/comatose/tasks/data.rb +82 -0
  26. data/lib/comatose/tasks/setup.rb +52 -0
  27. data/lib/comatose/version.rb +4 -0
  28. data/lib/comatose.rb +33 -0
  29. data/lib/comatose_admin_controller.rb +349 -0
  30. data/lib/comatose_admin_helper.rb +37 -0
  31. data/lib/comatose_controller.rb +141 -0
  32. data/lib/comatose_helper.rb +3 -0
  33. data/lib/comatose_page.rb +141 -0
  34. data/lib/liquid/block.rb +96 -0
  35. data/lib/liquid/context.rb +190 -0
  36. data/lib/liquid/document.rb +17 -0
  37. data/lib/liquid/drop.rb +48 -0
  38. data/lib/liquid/errors.rb +7 -0
  39. data/lib/liquid/extensions.rb +53 -0
  40. data/lib/liquid/file_system.rb +62 -0
  41. data/lib/liquid/htmltags.rb +64 -0
  42. data/lib/liquid/standardfilters.rb +111 -0
  43. data/lib/liquid/standardtags.rb +399 -0
  44. data/lib/liquid/strainer.rb +42 -0
  45. data/lib/liquid/tag.rb +25 -0
  46. data/lib/liquid/template.rb +88 -0
  47. data/lib/liquid/variable.rb +39 -0
  48. data/lib/liquid.rb +52 -0
  49. data/lib/redcloth.rb +1129 -0
  50. data/lib/support/class_options.rb +36 -0
  51. data/lib/support/inline_rendering.rb +48 -0
  52. data/lib/support/route_mapper.rb +50 -0
  53. data/lib/text_filters/markdown.rb +14 -0
  54. data/lib/text_filters/markdown_smartypants.rb +15 -0
  55. data/lib/text_filters/none.rb +8 -0
  56. data/lib/text_filters/rdoc.rb +13 -0
  57. data/lib/text_filters/simple.rb +8 -0
  58. data/lib/text_filters/textile.rb +15 -0
  59. data/lib/text_filters.rb +138 -0
  60. data/rails/init.rb +3 -0
  61. data/resources/layouts/comatose_admin_template.html.erb +28 -0
  62. data/resources/public/images/collapsed.gif +0 -0
  63. data/resources/public/images/expanded.gif +0 -0
  64. data/resources/public/images/no-children.gif +0 -0
  65. data/resources/public/images/page.gif +0 -0
  66. data/resources/public/images/spinner.gif +0 -0
  67. data/resources/public/images/title-hover-bg.gif +0 -0
  68. data/resources/public/javascripts/comatose_admin.js +401 -0
  69. data/resources/public/stylesheets/comatose_admin.css +381 -0
  70. data/tasks/comatose.rake +9 -0
  71. data/test/behaviors.rb +106 -0
  72. data/test/fixtures/comatose_pages.yml +96 -0
  73. data/test/functional/comatose_admin_controller_test.rb +112 -0
  74. data/test/functional/comatose_controller_test.rb +44 -0
  75. data/test/javascripts/test.html +26 -0
  76. data/test/javascripts/test_runner.js +307 -0
  77. data/test/test_helper.rb +43 -0
  78. data/test/unit/class_options_test.rb +52 -0
  79. data/test/unit/comatose_page_test.rb +128 -0
  80. data/test/unit/processing_context_test.rb +108 -0
  81. data/test/unit/text_filters_test.rb +52 -0
  82. data/views/comatose_admin/_form.html.erb +96 -0
  83. data/views/comatose_admin/_page_list_item.html.erb +60 -0
  84. data/views/comatose_admin/delete.html.erb +18 -0
  85. data/views/comatose_admin/edit.html.erb +5 -0
  86. data/views/comatose_admin/index.html.erb +18 -0
  87. data/views/comatose_admin/new.html.erb +5 -0
  88. data/views/comatose_admin/reorder.html.erb +30 -0
  89. data/views/comatose_admin/versions.html.erb +40 -0
  90. data/views/layouts/comatose_admin.html.erb +814 -0
  91. data/views/layouts/comatose_admin_customize.html.erb +28 -0
  92. data/views/layouts/comatose_content.html.erb +17 -0
  93. metadata +156 -0
@@ -0,0 +1,349 @@
1
+ # The controller for serving cms content...
2
+ class ComatoseAdminController < ActionController::Base
3
+ unloadable
4
+
5
+ define_option :original_template_root, nil
6
+ define_option :plugin_layout_path, File.join( '..', '..', '..', 'vendor', 'plugins', 'comatose', 'views', 'layouts' )
7
+
8
+ before_filter :handle_authorization
9
+ before_filter :set_content_type
10
+ layout 'comatose_admin'
11
+
12
+ # Shows the page tree
13
+ def index
14
+ @root_pages = [fetch_root_page].flatten
15
+ end
16
+
17
+ # Edit a specfic page (posts back)
18
+ def edit
19
+ # Clear the page cache for this page... ?
20
+ @page = ComatosePage.find params[:id]
21
+ @root_pages = [fetch_root_page].flatten
22
+ if request.post?
23
+ @page.update_attributes(params[:page])
24
+ @page.updated_on = Time.now
25
+ @page.author = fetch_author_name
26
+ if @page.save
27
+ expire_cms_page @page
28
+ expire_cms_fragment @page
29
+ flash[:notice] = "Saved changes to '#{@page.title}'"
30
+ redirect_to :controller=>self.controller_name, :action=>'index'
31
+ end
32
+ end
33
+ end
34
+
35
+ # Create a new page (posts back)
36
+ def new
37
+ @root_pages = [fetch_root_page].flatten
38
+ if request.post?
39
+ @page = ComatosePage.new params[:page]
40
+ @page.author = fetch_author_name
41
+ if @page.save
42
+ flash[:notice] = "Created page '#{@page.title}'"
43
+ redirect_to :controller=>self.controller_name, :action=>'index'
44
+ end
45
+ else
46
+ @page = ComatosePage.new :title=>'New Page', :parent_id=>(params[:parent] || nil)
47
+ end
48
+ end
49
+
50
+ # Saves position of child pages
51
+ def reorder
52
+ # If it's AJAX, do our thing and move on...
53
+ if request.xhr?
54
+ params["page_list_#{params[:id]}"].each_with_index { |id,idx| ComatosePage.update(id, :position => idx) }
55
+ expire_cms_page ComatosePage.find(params[:id])
56
+ render :text=>'Updated sort order', :layout=>false
57
+ else
58
+ @page = ComatosePage.find params[:id]
59
+ if params.has_key? :cmd
60
+ @target = ComatosePage.find params[:page]
61
+ case params[:cmd]
62
+ when 'up' then @target.move_higher
63
+ when 'down' then @target.move_lower
64
+ end
65
+ redirect_to :action=>'reorder', :id=>@page
66
+ end
67
+ end
68
+ end
69
+
70
+ # Allows comparing between two versions of a page's content
71
+ def versions
72
+ @page = ComatosePage.find params[:id]
73
+ @version_num = (params[:version] || @page.versions.length).to_i
74
+ @version = @page.find_version(@version_num)
75
+ end
76
+
77
+ # Reverts a page to a specific version...
78
+ def set_version
79
+ if request.post?
80
+ @page = ComatosePage.find params[:id]
81
+ @version_num = params[:version]
82
+ @page.revert_to!(@version_num)
83
+ end
84
+ redirect_to :controller=>self.controller_name, :action=>'index'
85
+ end
86
+
87
+ # Deletes the specified page
88
+ def delete
89
+ @page = ComatosePage.find params[:id]
90
+ if request.post?
91
+ expire_cms_pages_from_bottom @page
92
+ expire_cms_fragments_from_bottom @page
93
+ @page.destroy
94
+ flash[:notice] = "Deleted page '#{@page.title}'"
95
+ redirect_to :controller=>self.controller_name, :action=>'index'
96
+ end
97
+ end
98
+
99
+ # Returns a preview of the page content...
100
+ def preview
101
+ begin
102
+ page = ComatosePage.new(params[:page])
103
+ page.author = fetch_author_name
104
+ if params.has_key? :version
105
+ content = page.to_html( {'params'=>params.stringify_keys, 'version'=>params[:version]} )
106
+ else
107
+ content = page.to_html( {'params'=>params.stringify_keys} )
108
+ end
109
+ rescue SyntaxError
110
+ content = "<p>There was an error generating the preview.</p><p><pre>#{$!.to_s.gsub(/\</, '&lt;')}</pre></p>"
111
+ rescue
112
+ content = "<p>There was an error generating the preview.</p><p><pre>#{$!.to_s.gsub(/\</, '&lt;')}</pre></p>"
113
+ end
114
+ render :text=>content, :layout => false
115
+ end
116
+
117
+ # Expires the entire page cache
118
+ def expire_page_cache
119
+ expire_cms_pages_from_bottom( fetch_root_page )
120
+ expire_cms_fragments_from_bottom( fetch_root_page )
121
+ flash[:notice] = "Page cache has been flushed"
122
+ redirect_to :controller=>self.controller_name, :action=>'index'
123
+ end
124
+
125
+ # Walks the page tree and generates HTML files in your /public
126
+ # folder... It will skip pages that have a 'nocache' keyword
127
+ # TODO: Make page cache generation work when in :plugin mode
128
+ def generate_page_cache
129
+ if runtime_mode == :plugin
130
+ @errors = ["Page cache cannot be generated in plugin mode"]
131
+ else
132
+ @errors = generate_all_pages_html(params)
133
+ end
134
+ if @errors.length == 0
135
+ flash[:notice] = "Pages Cached Successfully"
136
+ else
137
+ flash[:notice] = "Pages Cache Error(s): #{@errors.join(', ')}"
138
+ flash[:cache_errors] = @errors
139
+ end
140
+ redirect_to :controller=>self.controller_name, :action=>'index'
141
+ end
142
+
143
+
144
+ protected
145
+
146
+ def handle_authorization
147
+ if Comatose.config.admin_authorization.is_a? Proc
148
+ instance_eval &Comatose.config.admin_authorization
149
+ elsif Comatose.config.admin_authorization.is_a? Symbol
150
+ send(Comatose.config.admin_authorization)
151
+ elsif defined? authorize
152
+ authorize
153
+ else
154
+ true
155
+ end
156
+ end
157
+
158
+ def fetch_author_name
159
+ if Comatose.config.admin_get_author.is_a? Proc
160
+ instance_eval &Comatose.config.admin_get_author
161
+ elsif Comatose.config.admin_get_author.is_a? Symbol
162
+ send(Comatose.config.admin_get_author)
163
+ elsif defined? get_author
164
+ get_author
165
+ end
166
+ end
167
+
168
+ # Can be overridden -- return your root comtase page
169
+ def fetch_root_page
170
+ if Comatose.config.admin_get_root_page.is_a? Proc
171
+ instance_eval &Comatose.config.admin_get_root_page
172
+ elsif Comatose.config.admin_get_root_page.is_a? Symbol
173
+ send(Comatose.config.admin_get_root_page)
174
+ elsif defined? get_root_page
175
+ get_root_page
176
+ end
177
+ end
178
+
179
+ # Sets the HTTP content-type header based on what's configured
180
+ # in Comatose.config.content_type
181
+ def set_content_type
182
+ response.headers["Content-Type"] = "text/html; charset=#{Comatose.config.content_type}" unless Comatose.config.content_type.nil?
183
+ end
184
+
185
+ # Calls generate_page_html for each mount point..
186
+ def generate_all_pages_html(params={})
187
+ @errors = []
188
+ @been_cached = []
189
+ Comatose.mount_points.each do |root_info|
190
+ ComatosePage.active_mount_info = root_info
191
+ generate_page_html(ComatosePage.find_by_path( root_info[:index] ), root_info, params)
192
+ end
193
+ @errors
194
+ end
195
+
196
+ # Accepts a Comatose Page and a root_info object to generate
197
+ # the page as a static HTML page -- using the layout that was
198
+ # defined on the mount point
199
+ def generate_page_html(page, root_info, params={})
200
+ @been_cached ||= []
201
+ unless page.has_keyword? :nocache or @been_cached.include? page.id
202
+ uri = page.uri
203
+ uri = "#{uri}/index".split('/').flatten.join('/') if page.full_path == root_info[:index]
204
+ @page = Comatose::PageWrapper.new(page)
205
+ begin
206
+ page_layout = get_page_layout(root_info)
207
+ #puts "mode = #{runtime_mode}, layout = #{page_layout}, template_root = #{template_root}, original_template_root = #{original_template_root}"
208
+ html = render_to_string( :text=>page.to_html({'params'=>params.stringify_keys}), :layout=>page_layout )
209
+ cache_page( html, uri )
210
+ rescue
211
+ logger.error "Comatose CMS Page Cache Exception: #{$!}"
212
+ @errors << "(#{page}/#{page.slug}) - #{$!}"
213
+ end
214
+ @been_cached << page.id
215
+ # recurse...
216
+ page.children.each do |child|
217
+ generate_page_html(child, root_info)
218
+ end
219
+ end
220
+ end
221
+
222
+ # Calls the class methods of the same name...
223
+ def expire_cms_page(page)
224
+ self.class.expire_cms_page(page)
225
+ end
226
+ def expire_cms_pages_from_bottom(page)
227
+ self.class.expire_cms_pages_from_bottom(page)
228
+ end
229
+
230
+
231
+ # expire the page from the fragment cache
232
+ def expire_cms_fragment(page)
233
+ key = page.full_path.gsub(/\//, '+')
234
+ expire_fragment(key)
235
+ end
236
+
237
+ # expire pages starting at a specific node
238
+ def expire_cms_fragments_from_bottom(page)
239
+ pages = page.is_a?(Array) ? page : [page]
240
+ pages.each do |page|
241
+ page.children.each {|c| expire_cms_fragments_from_bottom( c ) } if !page.children.empty?
242
+ expire_cms_fragment( page )
243
+ end
244
+ end
245
+
246
+ # Class Methods...
247
+ class << self
248
+
249
+ # Walks all the way down, and back up the tree -- the allows the expire_cms_page
250
+ # to delete empty directories better
251
+ def expire_cms_pages_from_bottom(page)
252
+ pages = page.is_a?(Array) ? page : [page]
253
+ pages.each do |page|
254
+ page.children.each {|c| expire_cms_pages_from_bottom( c ) } if !page.children.empty?
255
+ expire_cms_page( page )
256
+ end
257
+ end
258
+
259
+ # Expire the page from all the mount points...
260
+ def expire_cms_page(page)
261
+ Comatose.mount_points.each do |path_info|
262
+ ComatosePage.active_mount_info = path_info
263
+ expire_page(page.uri)
264
+ # If the page is the index page for the root, expire it too
265
+ if path_info[:root] == page.uri
266
+ expire_page("#{path_info[:root]}/index")
267
+ end
268
+ begin # I'm not sure this matters too much -- but it keeps things clean
269
+ dir_path = File.join(RAILS_ROOT, 'public', page.uri[1..-1])
270
+ Dir.delete( dir_path ) if FileTest.directory?( dir_path ) and !page.parent.nil?
271
+ rescue
272
+ # It probably isn't empty -- just as well we leave it be
273
+ #STDERR.puts " - Couldn't delete dir #{dir_path} -> #{$!}"
274
+ end
275
+ end
276
+ end
277
+
278
+ # Returns a path to plugin layout, if it's unspecified, otherwise
279
+ # a path to an application layout...
280
+ def get_page_layout(params)
281
+ if params[:layout] == 'comatose_content'
282
+ File.join(plugin_layout_path, params[:layout])
283
+ else
284
+ params[:layout]
285
+ end
286
+ end
287
+
288
+ def configure_template_root
289
+ if self.runtime_mode == :unknown
290
+ if FileTest.exist? File.join(RAILS_ROOT, 'public', 'javascripts', 'comatose_admin.js')
291
+ self.runtime_mode = :application
292
+ else
293
+ self.runtime_mode = :plugin
294
+ end
295
+ end
296
+ end
297
+
298
+ def runtime_mode
299
+ @@runtime_mode ||= :unknown
300
+ end
301
+
302
+ def runtime_mode=(mode)
303
+ admin_view_path = File.expand_path(File.join( File.dirname(__FILE__), '..', 'views'))
304
+ if self.respond_to?(:template_root)
305
+ case mode
306
+ when :plugin
307
+ self.original_template_root = self.template_root
308
+ self.template_root = admin_view_path
309
+ when :application
310
+ self.template_root = self.original_template_root if self.original_template_root
311
+ end
312
+ else
313
+ ActionController::Base.append_view_path(admin_view_path) unless ActionController::Base.view_paths.include?(admin_view_path)
314
+ end
315
+ @@runtime_mode = mode
316
+ end
317
+
318
+ end
319
+
320
+ # Check to see if we are in 'embedded' mode, or are being 'customized'
321
+ # embedded = runtime_mode of :plugin
322
+ # customized = runtime_mode of :application
323
+ configure_template_root
324
+
325
+ #
326
+ # Include any modules...
327
+ Comatose.config.admin_includes.each do |mod|
328
+ if mod.is_a? String
329
+ include mod.constantize
330
+ elsif mod.is_a? Symbol
331
+ include mod.to_s.classify.constantize
332
+ else
333
+ include mod
334
+ end
335
+ end
336
+
337
+ # Include any helpers...
338
+ Comatose.config.admin_helpers.each do |mod|
339
+ if mod.is_a? String
340
+ helper mod.constantize
341
+ elsif mod.is_a? Symbol
342
+ helper mod.to_s.classify.constantize
343
+ else
344
+ helper mod
345
+ end
346
+ end
347
+
348
+
349
+ end
@@ -0,0 +1,37 @@
1
+ module ComatoseAdminHelper
2
+
3
+ # Checks the hidden_meta_fields class variable for a specified field name...
4
+ def show_field?(key)
5
+ !Comatose.config.hidden_meta_fields.include? key
6
+ end
7
+
8
+ # Used in the Page Form to build an indented drop-down list of pages
9
+ def tree_select_box(nodes, selected= nil, hide= nil, label="Parent", add_initial=false)
10
+ level = 0
11
+ select_box = add_initial ? "<option value=0>No #{label}</option>\n" : ""
12
+ selected = nodes[0].id if selected.nil? and not add_initial
13
+ nodes.each {|node| select_box += add_select_tree_node(node, selected, level, hide) }
14
+ select_box += ''
15
+ end
16
+ # Called by tree_select_box
17
+ def add_select_tree_node(node, selected, level, hide)
18
+ padding = "&nbsp;" * level * 4
19
+ padding += '&raquo; ' unless level==0
20
+ hide_values = Array.new
21
+ hide_values << hide if hide
22
+ if node.id == selected
23
+ select_box = %Q|<option value="#{node.id}" selected="true">#{padding}#{node.title}</option>\n|
24
+ else
25
+ if hide_values.include?(node.id)
26
+ select_box = ''
27
+ else
28
+ select_box = %Q|<option value="#{node.id}">#{padding}#{node.title}</option>\n|
29
+ end
30
+ end
31
+ node.children.each do |child|
32
+ select_box += add_select_tree_node(child, selected, level + 1, hide) unless hide_values.include?(node.id)
33
+ end
34
+ select_box
35
+ end
36
+
37
+ end
@@ -0,0 +1,141 @@
1
+ # The controller for serving cms content...
2
+ class ComatoseController < ActionController::Base
3
+
4
+ before_filter :handle_authorization, :set_content_type
5
+ after_filter :cache_cms_page
6
+
7
+ # Render a specific page
8
+ def show
9
+ page_name, page_ext = get_page_path
10
+ page = ComatosePage.find_by_path( page_name )
11
+ status = nil
12
+ if page.nil?
13
+ page = ComatosePage.find_by_path( '404' )
14
+ status = 404
15
+ end
16
+ # if it's still nil, well, send a 404 status
17
+ if page.nil?
18
+ render :nothing=>true, :status=>status
19
+ #raise ActiveRecord::RecordNotFound.new("Comatose page not found ")
20
+ else
21
+ # Make the page access 'safe'
22
+ @page = Comatose::PageWrapper.new(page)
23
+ # For accurate uri creation, tell the page class which is the active mount point...
24
+ ComatosePage.active_mount_info = get_active_mount_point(params[:index])
25
+ render :text=>page.to_html({'params'=>params.stringify_keys}), :layout=>get_page_layout, :status=>status
26
+ end
27
+ end
28
+
29
+ protected
30
+
31
+ def handle_authorization
32
+ if Comatose.config.authorization.is_a? Proc
33
+ instance_eval &Comatose.config.authorization
34
+ elsif Comatose.config.authorization.is_a? Symbol
35
+ send(Comatose.config.authorization)
36
+ elsif defined? authorize
37
+ authorize
38
+ else
39
+ true
40
+ end
41
+ end
42
+
43
+ def allow_page_cache?
44
+ # You should have access to the @page being rendered
45
+ true
46
+ end
47
+
48
+ # For use in the #show method... determines the current mount point
49
+ def get_active_mount_point( index )
50
+ Comatose.mount_points.each do |path_info|
51
+ if path_info[:index] == index
52
+ return path_info
53
+ end
54
+ end
55
+ {:root=>"", :index=>index}
56
+ end
57
+
58
+ # For use in the #show method... determines the current page path
59
+ def get_page_path
60
+
61
+ #in rails 2.0, params[:page] comes back as just an Array, so to_s doesn't do join('/')
62
+ if params[:page].is_a? Array
63
+ page_name = params[:page].join("/")
64
+ #in rails 1.x, params[:page] comes back as ActionController::Routing::PathSegment::Result
65
+ elsif params[:page].is_a? ActionController::Routing::PathSegment::Result
66
+ page_name = params[:page].to_s
67
+ else
68
+ logger.debug "get_page_path - params[:page] is an unrecognized type, may cause problems: #{params[:page].class}"
69
+ page_name = params[:page].to_s
70
+ end
71
+
72
+ page_ext = page_name.split('.')[1] unless page_name.empty?
73
+ # TODO: Automatic support for page RSS feeds... ????
74
+ if page_name.nil? or page_name.empty?
75
+ page_name = params[:index]
76
+ params[:cache_path] = "#{request.request_uri}/index"
77
+ elsif !params[:index].empty?
78
+ page_name = "#{params[:index]}/#{page_name}"
79
+ end
80
+ return page_name, page_ext
81
+ end
82
+
83
+ # Returns a path to plugin layout, if it's unspecified, otherwise
84
+ # a path to an application layout...
85
+ def get_page_layout
86
+ if params[:layout] == 'comatose_content'
87
+ File.join(plugin_layout_path, params[:layout])
88
+ else
89
+ params[:layout]
90
+ end
91
+ end
92
+
93
+ # An after_filter implementing page caching if it's enabled, globally,
94
+ # and is allowed by #allow_page_cache?
95
+ def cache_cms_page
96
+ unless Comatose.config.disable_caching or response.headers['Status'] == '404 Not Found'
97
+ return unless params[:use_cache].to_s == 'true' and allow_page_cache?
98
+ path = params[:cache_path] || request.request_uri
99
+ begin
100
+ # TODO: Don't cache pages rendering '404' content...
101
+ self.class.cache_page( response.body, path )
102
+ rescue
103
+ logger.error "Comatose CMS Page Cache Exception: #{$!}"
104
+ end
105
+ end
106
+ end
107
+
108
+ # An after_filter that sets the HTTP header for Content-Type to
109
+ # what's defined in Comatose.config.content_type. Defaults to utf-8.
110
+ def set_content_type
111
+ response.headers["Content-Type"] = "text/html; charset=#{Comatose.config.content_type}" unless Comatose.config.content_type.nil? or response.headers['Status'] == '404 Not Found'
112
+ end
113
+
114
+ # Path to layouts within the plugin... Assumes the plugin directory name is 'comatose'
115
+ define_option :plugin_layout_path, File.join( '..', '..', '..', 'vendor', 'plugins', 'comatose', 'views', 'layouts' )
116
+
117
+ # Include any, well, includes...
118
+ Comatose.config.includes.each do |mod|
119
+ mod_klass = if mod.is_a? String
120
+ mod.constantize
121
+ elsif mod.is_a? Symbol
122
+ mod.to_s.classify.constantize
123
+ else
124
+ mod
125
+ end
126
+ include mod_klass
127
+ end
128
+
129
+ # Include any helpers...
130
+ Comatose.config.helpers.each do |mod|
131
+ mod_klass = if mod.is_a? String
132
+ mod.constantize
133
+ elsif mod.is_a? Symbol
134
+ mod.to_s.classify.constantize
135
+ else
136
+ mod
137
+ end
138
+ helper mod_klass
139
+ end
140
+ end
141
+
@@ -0,0 +1,3 @@
1
+ module ComatoseHelper
2
+
3
+ end
@@ -0,0 +1,141 @@
1
+ # ComatosePage attributes
2
+ # - parent_id
3
+ # - title
4
+ # - full_path
5
+ # - slug
6
+ # - keywords
7
+ # - body
8
+ # - author
9
+ # - filter_type
10
+ # - position
11
+ # - version
12
+ # - updated_on
13
+ # - created_on
14
+ class ComatosePage < ActiveRecord::Base
15
+
16
+ set_table_name 'comatose_pages'
17
+
18
+ # Only versions the content... Not all of the meta data or position
19
+ acts_as_versioned :table_name=>'comatose_page_versions', :if_changed => [:title, :slug, :keywords, :body]
20
+
21
+ define_option :active_mount_info, {:root=>'', :index=>''}
22
+
23
+ acts_as_tree :order => "position, title"
24
+ acts_as_list :scope => :parent_id
25
+
26
+ #before_create :create_full_path
27
+ before_save :cache_full_path, :create_full_path
28
+ after_save :update_children_full_path
29
+
30
+ # Using before_validation so we can default the slug from the title
31
+ before_validation do |record|
32
+ # Create slug from title
33
+ if record.slug.blank? and !record.title.blank?
34
+ record.slug = record.title.downcase.lstrip.rstrip.gsub( /[^-a-z0-9~\s\.:;+=_]/, '').gsub(/[\s\.:;=_+]+/, '-').gsub(/[\-]{2,}/, '-').to_s
35
+ end
36
+ end
37
+
38
+ # Manually set these, because record_timestamps = false
39
+ before_create do |record|
40
+ record.created_on = record.updated_on = Time.now
41
+ end
42
+
43
+ validates_presence_of :title, :on => :save, :message => "must be present"
44
+ validates_uniqueness_of :slug, :on => :save, :scope=>'parent_id', :message => "is already in use"
45
+ validates_presence_of :parent_id, :on=>:create, :message=>"must be present"
46
+
47
+ # Tests ERB/Liquid content...
48
+ validates_each :body, :allow_nil=>true, :allow_blank=>true do |record, attr, value|
49
+ begin
50
+ body_html = record.to_html
51
+ rescue SyntaxError
52
+ record.errors.add :body, "syntax error: #{$!.to_s.gsub('<', '&lt;')}"
53
+ rescue
54
+ record.errors.add :body, "content error: #{$!.to_s.gsub('<', '&lt;')}"
55
+ end
56
+ end
57
+
58
+ # Returns a pages URI dynamically, based on the active mount point
59
+ def uri
60
+ if full_path == ''
61
+ active_mount_info[:root]
62
+ else
63
+ page_path = (full_path || '').split('/')
64
+ idx_path = active_mount_info[:index].split('/')
65
+ uri_root = active_mount_info[:root].split('/')
66
+ uri_path = ( uri_root + (page_path - idx_path) ).flatten.delete_if {|i| i == "" }
67
+ ['',uri_path].join('/')
68
+ end
69
+ end
70
+
71
+ # Check if a page has a selected keyword... NOT case sensitive.
72
+ # So the keyword McCray is the same as mccray
73
+ def has_keyword?(keyword)
74
+ @key_list ||= (self.keywords || '').downcase.split(',').map {|k| k.strip }
75
+ @key_list.include? keyword.to_s.downcase
76
+ rescue
77
+ false
78
+ end
79
+
80
+ # Returns the page's content, transformed and filtered...
81
+ def to_html(options={})
82
+ #version = options.delete(:version)
83
+ text = self.body
84
+ binding = Comatose::ProcessingContext.new(self, options)
85
+ filter_type = self.filter_type || '[No Filter]'
86
+ TextFilters.transform(text, binding, filter_type, Comatose.config.default_processor)
87
+ end
88
+
89
+ # Static helpers...
90
+
91
+ # Returns a Page with a matching path.
92
+ def self.find_by_path( path )
93
+ path = path.split('.')[0] unless path.empty? # Will ignore file extension...
94
+ path = path[1..-1] if path.starts_with? "/"
95
+ find( :first, :conditions=>[ 'full_path = ?', path ] )
96
+ end
97
+
98
+ # Overrides...
99
+
100
+ # I don't want the AR magic timestamping support for this class...
101
+ def record_timestamps
102
+ false
103
+ end
104
+ def self.record_timestamps
105
+ false
106
+ end
107
+
108
+ protected
109
+
110
+ # Creates a URI path based on the Page tree
111
+ def create_full_path
112
+ if parent_node = self.parent
113
+ # Build URI Path
114
+ path = "#{parent_node.full_path}/#{self.slug}"
115
+ # strip leading space, if there is one...
116
+ path = path[1..-1] if path.starts_with? "/"
117
+ self.full_path = path || ""
118
+ else
119
+ # I'm the root -- My path is blank
120
+ self.full_path = ""
121
+ end
122
+ end
123
+ def create_full_path!
124
+ create_full_path
125
+ save
126
+ end
127
+
128
+ # Caches old path (before save) for comparison later
129
+ def cache_full_path
130
+ @old_full_path = self.full_path
131
+ end
132
+
133
+ # Updates all this content's child URI paths
134
+ def update_children_full_path(should_save=true)
135
+ # OPTIMIZE: Only update all the children if the :slug/:fullpath is different
136
+ for child in self.children
137
+ child.create_full_path! unless child.frozen?
138
+ child.update_children_full_path(should_save)
139
+ end
140
+ end
141
+ end