aslakjo-aslakjo-comatose 2.0.5.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 +195 -0
  2. data/INSTALL +20 -0
  3. data/LICENSE +20 -0
  4. data/MANIFEST +91 -0
  5. data/README.markdown +159 -0
  6. data/Rakefile +176 -0
  7. data/SPECS +61 -0
  8. data/about.yml +7 -0
  9. data/bin/comatose +112 -0
  10. data/comatose.gemspec +113 -0
  11. data/generators/comatose_migration/USAGE +15 -0
  12. data/generators/comatose_migration/comatose_migration_generator.rb +74 -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 +18 -0
  19. data/lib/acts_as_versioned.rb +543 -0
  20. data/lib/comatose.rb +33 -0
  21. data/lib/comatose/comatose_drop.rb +79 -0
  22. data/lib/comatose/configuration.rb +69 -0
  23. data/lib/comatose/page_wrapper.rb +119 -0
  24. data/lib/comatose/processing_context.rb +69 -0
  25. data/lib/comatose/tasks/admin.rb +60 -0
  26. data/lib/comatose/tasks/data.rb +82 -0
  27. data/lib/comatose/tasks/setup.rb +52 -0
  28. data/lib/comatose/version.rb +4 -0
  29. data/lib/comatose_admin_controller.rb +395 -0
  30. data/lib/comatose_admin_helper.rb +37 -0
  31. data/lib/comatose_controller.rb +138 -0
  32. data/lib/comatose_helper.rb +3 -0
  33. data/lib/comatose_page.rb +141 -0
  34. data/lib/liquid.rb +52 -0
  35. data/lib/liquid/block.rb +96 -0
  36. data/lib/liquid/context.rb +190 -0
  37. data/lib/liquid/document.rb +17 -0
  38. data/lib/liquid/drop.rb +48 -0
  39. data/lib/liquid/errors.rb +7 -0
  40. data/lib/liquid/extensions.rb +53 -0
  41. data/lib/liquid/file_system.rb +62 -0
  42. data/lib/liquid/htmltags.rb +64 -0
  43. data/lib/liquid/standardfilters.rb +111 -0
  44. data/lib/liquid/standardtags.rb +399 -0
  45. data/lib/liquid/strainer.rb +42 -0
  46. data/lib/liquid/tag.rb +25 -0
  47. data/lib/liquid/template.rb +88 -0
  48. data/lib/liquid/variable.rb +39 -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.rb +140 -0
  54. data/lib/text_filters/markdown.rb +14 -0
  55. data/lib/text_filters/markdown_smartypants.rb +15 -0
  56. data/lib/text_filters/none.rb +8 -0
  57. data/lib/text_filters/rdoc.rb +13 -0
  58. data/lib/text_filters/simple.rb +8 -0
  59. data/lib/text_filters/textile.rb +15 -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 +404 -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 +114 -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 +55 -0
  78. data/test/unit/class_options_test.rb +52 -0
  79. data/test/unit/comatose_page_test.rb +136 -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 +29 -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 +837 -0
  91. data/views/layouts/comatose_admin_customize.html.erb +28 -0
  92. data/views/layouts/comatose_content.html.erb +17 -0
  93. metadata +148 -0
@@ -0,0 +1,52 @@
1
+ require 'rake'
2
+ require 'rake/tasklib'
3
+
4
+ namespace :comatose do
5
+ #
6
+ # Setup Task...
7
+ #
8
+ namespace :setup do
9
+
10
+ desc "If the installation didn't add the images correctly, use this task"
11
+ task :copy_images do
12
+ plugin_dir = File.join(File.dirname(__FILE__), '..')
13
+ unless FileTest.exist? File.join(RAILS_ROOT, 'public', 'images', 'comatose')
14
+ FileUtils.mkdir( File.join(RAILS_ROOT, 'public', 'images', 'comatose') )
15
+ end
16
+ FileUtils.cp(
17
+ Dir[File.join(plugin_dir, 'resources', 'public', 'images', '*.gif')],
18
+ File.join(RAILS_ROOT, 'public', 'images', 'comatose'),
19
+ :verbose => true
20
+ )
21
+ puts "Finished."
22
+ end
23
+
24
+ # For use when upgrading...
25
+
26
+ def move(args)
27
+ if ENV['USE_SVN'] == 'true'
28
+ `svn move #{args}`
29
+ else
30
+ `mv #{args}`
31
+ end
32
+ end
33
+
34
+ def delete(args)
35
+ if ENV['USE_SVN'] == 'true'
36
+ `svn delete #{args}`
37
+ else
38
+ `rm -rf #{args}`
39
+ end
40
+ end
41
+
42
+ # TODO: Test the setup:restructure_customization task...
43
+ desc "[EXPERIMENTAL] Restructures customized admin folder to version 0.6 from older version -- Only run this if you have customized the admin. USE_SVN=true if you want to update subversion"
44
+ task :restructure_customization do
45
+ ENV['USE_SVN'] ||= 'false'
46
+ move 'public/javscripts/comatose.js public/javscripts/comatose_admin.js'
47
+ move 'public/stylesheets/comatose.css public/stylesheets/comatose_admin.css'
48
+ move 'app/views/comatose app/views/comatose_admin'
49
+ delete 'app/views/layouts/comatose_content.html.erb'
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,4 @@
1
+ module Comatose
2
+ VERSION = "2.0.5"
3
+ VERSION_STRING = "#{VERSION} (beta)"
4
+ end
@@ -0,0 +1,395 @@
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
+ def export
144
+ if Comatose.config.allow_import_export
145
+ send_data(page_to_hash(ComatosePage.root).to_yaml, :disposition => 'attachment', :type => 'text/yaml', :filename => "comatose-pages.yml")
146
+ else
147
+ flash[:notice] = "Export is not allowed"
148
+ redirect_to :controller=>self.controller_name, :action=>'index'
149
+ end
150
+ end
151
+
152
+ def import
153
+ if Comatose.config.allow_import_export
154
+ data = YAML::load(params[:import_file])
155
+ hash_to_page_tree(data, ComatosePage.root)
156
+ flash[:notice] = "Pages Imported Successfully"
157
+ else
158
+ flash[:notice] = "Import isn't allowed"
159
+ end
160
+ redirect_to :controller=>self.controller_name, :action=>'index'
161
+ end
162
+
163
+ protected
164
+
165
+ def handle_authorization
166
+ if Comatose.config.admin_authorization.is_a? Proc
167
+ instance_eval &Comatose.config.admin_authorization
168
+ elsif Comatose.config.admin_authorization.is_a? Symbol
169
+ send(Comatose.config.admin_authorization)
170
+ elsif defined? authorize
171
+ authorize
172
+ else
173
+ true
174
+ end
175
+ end
176
+
177
+ def fetch_author_name
178
+ if Comatose.config.admin_get_author.is_a? Proc
179
+ instance_eval &Comatose.config.admin_get_author
180
+ elsif Comatose.config.admin_get_author.is_a? Symbol
181
+ send(Comatose.config.admin_get_author)
182
+ elsif defined? get_author
183
+ get_author
184
+ end
185
+ end
186
+
187
+ # Can be overridden -- return your root comtase page
188
+ def fetch_root_page
189
+ if Comatose.config.admin_get_root_page.is_a? Proc
190
+ instance_eval &Comatose.config.admin_get_root_page
191
+ elsif Comatose.config.admin_get_root_page.is_a? Symbol
192
+ send(Comatose.config.admin_get_root_page)
193
+ elsif defined? get_root_page
194
+ get_root_page
195
+ end
196
+ end
197
+
198
+ # Sets the HTTP content-type header based on what's configured
199
+ # in Comatose.config.content_type
200
+ def set_content_type
201
+ response.headers["Content-Type"] = "text/html; charset=#{Comatose.config.content_type}" unless Comatose.config.content_type.nil?
202
+ end
203
+
204
+ # Calls generate_page_html for each mount point..
205
+ def generate_all_pages_html(params={})
206
+ @errors = []
207
+ @been_cached = []
208
+ Comatose.mount_points.each do |root_info|
209
+ ComatosePage.active_mount_info = root_info
210
+ generate_page_html(ComatosePage.find_by_path( root_info[:index] ), root_info, params)
211
+ end
212
+ @errors
213
+ end
214
+
215
+ # Accepts a Comatose Page and a root_info object to generate
216
+ # the page as a static HTML page -- using the layout that was
217
+ # defined on the mount point
218
+ def generate_page_html(page, root_info, params={})
219
+ @been_cached ||= []
220
+ unless page.has_keyword? :nocache or @been_cached.include? page.id
221
+ uri = page.uri
222
+ uri = "#{uri}/index".split('/').flatten.join('/') if page.full_path == root_info[:index]
223
+ @page = Comatose::PageWrapper.new(page)
224
+ begin
225
+ page_layout = get_page_layout(root_info)
226
+ #puts "mode = #{runtime_mode}, layout = #{page_layout}, template_root = #{template_root}, original_template_root = #{original_template_root}"
227
+ html = render_to_string( :text=>page.to_html({'params'=>params.stringify_keys}), :layout=>page_layout )
228
+ cache_page( html, uri )
229
+ rescue
230
+ logger.error "Comatose CMS Page Cache Exception: #{$!}"
231
+ @errors << "(#{page}/#{page.slug}) - #{$!}"
232
+ end
233
+ @been_cached << page.id
234
+ # recurse...
235
+ page.children.each do |child|
236
+ generate_page_html(child, root_info)
237
+ end
238
+ end
239
+ end
240
+
241
+ # Calls the class methods of the same name...
242
+ def expire_cms_page(page)
243
+ self.class.expire_cms_page(page)
244
+ end
245
+ def expire_cms_pages_from_bottom(page)
246
+ self.class.expire_cms_pages_from_bottom(page)
247
+ end
248
+
249
+
250
+ # expire the page from the fragment cache
251
+ def expire_cms_fragment(page)
252
+ key = page.full_path.gsub(/\//, '+')
253
+ expire_fragment(key)
254
+ end
255
+
256
+ # expire pages starting at a specific node
257
+ def expire_cms_fragments_from_bottom(page)
258
+ pages = page.is_a?(Array) ? page : [page]
259
+ pages.each do |page|
260
+ page.children.each {|c| expire_cms_fragments_from_bottom( c ) } if !page.children.empty?
261
+ expire_cms_fragment( page )
262
+ end
263
+ end
264
+
265
+ # Class Methods...
266
+ class << self
267
+
268
+ # Walks all the way down, and back up the tree -- the allows the expire_cms_page
269
+ # to delete empty directories better
270
+ def expire_cms_pages_from_bottom(page)
271
+ pages = page.is_a?(Array) ? page : [page]
272
+ pages.each do |page|
273
+ page.children.each {|c| expire_cms_pages_from_bottom( c ) } if !page.children.empty?
274
+ expire_cms_page( page )
275
+ end
276
+ end
277
+
278
+ # Expire the page from all the mount points...
279
+ def expire_cms_page(page)
280
+ Comatose.mount_points.each do |path_info|
281
+ ComatosePage.active_mount_info = path_info
282
+ expire_page(page.uri)
283
+ # If the page is the index page for the root, expire it too
284
+ if path_info[:root] == page.uri
285
+ expire_page("#{path_info[:root]}/index")
286
+ end
287
+ begin # I'm not sure this matters too much -- but it keeps things clean
288
+ dir_path = File.join(RAILS_ROOT, 'public', page.uri[1..-1])
289
+ Dir.delete( dir_path ) if FileTest.directory?( dir_path ) and !page.parent.nil?
290
+ rescue
291
+ # It probably isn't empty -- just as well we leave it be
292
+ #STDERR.puts " - Couldn't delete dir #{dir_path} -> #{$!}"
293
+ end
294
+ end
295
+ end
296
+
297
+ # Returns a path to plugin layout, if it's unspecified, otherwise
298
+ # a path to an application layout...
299
+ def get_page_layout(params)
300
+ if params[:layout] == 'comatose_content'
301
+ File.join(plugin_layout_path, params[:layout])
302
+ else
303
+ params[:layout]
304
+ end
305
+ end
306
+
307
+ def configure_template_root
308
+ if self.runtime_mode == :unknown
309
+ if FileTest.exist? File.join(RAILS_ROOT, 'public', 'javascripts', 'comatose_admin.js')
310
+ self.runtime_mode = :application
311
+ else
312
+ self.runtime_mode = :plugin
313
+ end
314
+ end
315
+ end
316
+
317
+ def runtime_mode
318
+ @@runtime_mode ||= :unknown
319
+ end
320
+
321
+ def runtime_mode=(mode)
322
+ admin_view_path = File.expand_path(File.join( File.dirname(__FILE__), '..', 'views'))
323
+ if self.respond_to?(:template_root)
324
+ case mode
325
+ when :plugin
326
+ self.original_template_root = self.template_root
327
+ self.template_root = admin_view_path
328
+ when :application
329
+ self.template_root = self.original_template_root if self.original_template_root
330
+ end
331
+ else
332
+ ActionController::Base.append_view_path(admin_view_path) unless ActionController::Base.view_paths.include?(admin_view_path)
333
+ end
334
+ @@runtime_mode = mode
335
+ end
336
+
337
+ end
338
+
339
+ # Check to see if we are in 'embedded' mode, or are being 'customized'
340
+ # embedded = runtime_mode of :plugin
341
+ # customized = runtime_mode of :application
342
+ configure_template_root
343
+
344
+ #
345
+ # Include any modules...
346
+ Comatose.config.admin_includes.each do |mod|
347
+ if mod.is_a? String
348
+ include mod.constantize
349
+ elsif mod.is_a? Symbol
350
+ include mod.to_s.classify.constantize
351
+ else
352
+ include mod
353
+ end
354
+ end
355
+
356
+ # Include any helpers...
357
+ Comatose.config.admin_helpers.each do |mod|
358
+ if mod.is_a? String
359
+ helper mod.constantize
360
+ elsif mod.is_a? Symbol
361
+ helper mod.to_s.classify.constantize
362
+ else
363
+ helper mod
364
+ end
365
+ end
366
+
367
+ private
368
+
369
+ def page_to_hash(page)
370
+ data = page.attributes.clone
371
+ # Pull out the specific, or unnecessary fields
372
+ %w(id parent_id updated_on author position version created_on full_path).each {|key| data.delete(key)}
373
+ if !page.children.empty?
374
+ data['children'] = []
375
+ page.children.each do |child|
376
+ data['children'] << page_to_hash(child)
377
+ end
378
+ end
379
+ data
380
+ end
381
+
382
+ def hash_to_page_tree(hsh, page)
383
+ child_ary = hsh.delete 'children'
384
+ page.update_attributes(hsh)
385
+ page.save
386
+ child_ary.each do |child_hsh|
387
+ if child_pg = page.children.find_by_slug( child_hsh['slug'] )
388
+ hash_to_page_tree( child_hsh, child_pg )
389
+ else
390
+ hash_to_page_tree( child_hsh, page.children.create )
391
+ end
392
+ end if child_ary
393
+ end
394
+
395
+ end