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,13 @@
1
+ class PagePart < ActiveRecord::Base
2
+
3
+ # Associations
4
+ belongs_to :page
5
+
6
+ # Validations
7
+ validates_presence_of :name, :message => 'required'
8
+ validates_length_of :name, :maximum => 100, :message => '%d-character limit'
9
+ validates_length_of :filter_id, :maximum => 25, :allow_nil => true, :message => '%d-character limit'
10
+ validates_numericality_of :id, :page_id, :allow_nil => true, :only_integer => true, :message => 'must be a number'
11
+
12
+ registered_attr :filter, TextFilter
13
+ end
@@ -0,0 +1,53 @@
1
+ module Radiant
2
+ #
3
+ # The Radiant::Config object emulates a hash with simple bracket methods
4
+ # which allow you to get and set values in the configuration table:
5
+ #
6
+ # Radiant::Config['setting.name'] = 'value'
7
+ # Radiant::Config['setting.name'] #=> "value"
8
+ #
9
+ # Currently, there is not a way to edit configuration through the admin
10
+ # system so it must be done manually. The console script is probably the
11
+ # easiest way to this:
12
+ #
13
+ # % script/console production
14
+ # Loading production environment.
15
+ # >> Radiant::Config['setting.name'] = 'value'
16
+ # => "value"
17
+ # >>
18
+ #
19
+ # Radiant currently uses the following settings:
20
+ #
21
+ # admin.title :: the title of the admin system
22
+ # admin.subtitle :: the subtitle of the admin system
23
+ # default.parts :: a comma separated list of default page parts
24
+ # dev.host :: the hostname where draft pages are viewable
25
+ #
26
+ class Config < ActiveRecord::Base
27
+ set_table_name "config"
28
+
29
+ class << self
30
+ def [](key)
31
+ pair = find_by_key(key)
32
+ pair.value unless pair.nil?
33
+ end
34
+
35
+ def []=(key, value)
36
+ pair = find_by_key(key)
37
+ unless pair
38
+ pair = new
39
+ pair.key, pair.value = key, value
40
+ pair.save
41
+ else
42
+ pair.value = value
43
+ pair.save
44
+ end
45
+ value
46
+ end
47
+
48
+ def to_hash
49
+ Hash[ *find_all.map { |pair| [pair.key, pair.value] }.flatten ]
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,11 @@
1
+ module Radiant
2
+ class Exporter
3
+ def self.export
4
+ hash = {}
5
+ [Radiant::Config, User, Page, PagePart, Snippet, Layout].each do |klass|
6
+ hash[klass.name.pluralize] = klass.find(:all).inject({}) { |h, record| h[record.id.to_i] = record.attributes; h }
7
+ end
8
+ hash.to_yaml
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,112 @@
1
+ class ResponseCache
2
+ include ActionController::Benchmarking::ClassMethods
3
+ include ActionController::Caching::Pages::ClassMethods
4
+
5
+ @@defaults = {
6
+ :directory => ActionController::Base.page_cache_directory,
7
+ :expire_time => 5.minutes,
8
+ :default_extension => '.yml',
9
+ :perform_caching => true,
10
+ :logger => ActionController::Base.logger
11
+ }
12
+ cattr_accessor :defaults
13
+
14
+ attr_accessor :directory, :expire_time, :default_extension, :perform_caching, :logger
15
+ alias :page_cache_directory :directory
16
+ alias :page_cache_extension :default_extension
17
+ private :expire_page, :cache_page, :caches_page, :benchmark, :silence, :page_cache_directory,
18
+ :page_cache_extension
19
+
20
+ # Creates a ResponseCache object with the specified options.
21
+ #
22
+ # Options are as follows:
23
+ # :directory :: the path to the temporary cache directory
24
+ # :expire_time :: the number of seconds a cached response is considered valid (defaults to 5 min)
25
+ # :default_extension :: the extension cached files should use (defaults to '.html')
26
+ # :peform_caching :: boolean value that turns caching on or off (defaults to true)
27
+ # :logger :: the application logging object (defaults to ActionController::Base.logger)
28
+ #
29
+ def initialize(options = {})
30
+ options = options.symbolize_keys.reverse_merge(defaults)
31
+ self.directory = options[:directory]
32
+ self.expire_time = options[:expire_time]
33
+ self.default_extension = options[:default_extension]
34
+ self.perform_caching = options[:perform_caching]
35
+ self.logger = options[:logger]
36
+ end
37
+
38
+ # Caches a response object for path to disk.
39
+ def cache_response(path, response)
40
+ path = clean(path)
41
+ write_response(path, response)
42
+ response
43
+ end
44
+
45
+ # If peform_caching is set to true, updates a response object so that it mirrors the
46
+ # cached version.
47
+ def update_response(path, response)
48
+ if perform_caching
49
+ path = clean(path)
50
+ read_response(path, response)
51
+ end
52
+ response
53
+ end
54
+
55
+ # Returns true if a response is cached at the specified path.
56
+ def response_cached?(path)
57
+ path = clean(path)
58
+ name = page_cache_path(path)
59
+ File.exists?(name) and not File.directory?(name) and not (File.stat(name).mtime < (Time.now - @expire_time))
60
+ end
61
+
62
+ # Expires the cached response for the specified path.
63
+ def expire_response(path)
64
+ path = clean(path)
65
+ expire_page(path)
66
+ end
67
+
68
+ # Expires the entire cache.
69
+ def clear
70
+ Dir["#{directory}/*"].each do |f|
71
+ FileUtils.rm_rf f
72
+ end
73
+ end
74
+
75
+ # Returns the singleton instance for an application.
76
+ def self.instance
77
+ @@instance ||= new
78
+ end
79
+
80
+ private
81
+
82
+ # Ensures that path begins with a slash and remove extra slashes.
83
+ def clean(path)
84
+ path = path.gsub(%{/+}, '/')
85
+ %r{^/?(.*?)/?$}.match(path)
86
+ "/#{$1}"
87
+ end
88
+
89
+ # Reads a cached string from disk.
90
+ def read_page(path)
91
+ File.open(page_cache_path(path), "rb") { |f| f.read } if response_cached?(path)
92
+ end
93
+
94
+ # Reads a cached response from disk and updates a response object.
95
+ def read_response(path, response)
96
+ if content = read_page(path)
97
+ updates = YAML::load(content)
98
+ response.headers.merge!(updates['headers'] || {})
99
+ response.body = updates['body']
100
+ end
101
+ response
102
+ end
103
+
104
+ # Writes a response to disk.
105
+ def write_response(path, response)
106
+ content = {
107
+ 'headers' => response.headers,
108
+ 'body' => response.body
109
+ }.to_yaml
110
+ cache_page(content, path)
111
+ end
112
+ end
@@ -0,0 +1,16 @@
1
+ class Snippet < ActiveRecord::Base
2
+
3
+ # Associations
4
+ belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by'
5
+ belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by'
6
+
7
+ # Validations
8
+ validates_presence_of :name, :message => 'required'
9
+ validates_length_of :name, :maximum => 100, :message => '%d-character limit'
10
+ validates_length_of :filter_id, :maximum => 25, :allow_nil => true, :message => '%d-character limit'
11
+ validates_format_of :name, :with => %r{^\S*$}, :message => 'cannot contain spaces or tabs'
12
+ validates_uniqueness_of :name, :message => 'name already in use'
13
+
14
+ registered_attr :filter, TextFilter
15
+
16
+ end
@@ -0,0 +1,31 @@
1
+ class Status
2
+ attr_accessor :id, :name
3
+
4
+ def initialize(options = {})
5
+ options = options.symbolize_keys
6
+ @id, @name = options[:id], options[:name]
7
+ end
8
+
9
+ def symbol
10
+ @name.to_s.downcase.intern
11
+ end
12
+
13
+ def self.[](value)
14
+ @@statuses.select { |status| status.symbol == value.to_s.downcase.intern }.first
15
+ end
16
+
17
+ def self.find(id)
18
+ @@statuses.select { |status| status.id.to_s == id.to_s }.first
19
+ end
20
+
21
+ def self.find_all
22
+ @@statuses.dup
23
+ end
24
+
25
+ @@statuses = [
26
+ Status.new(:id => 1, :name => 'Draft' ),
27
+ Status.new(:id => 50, :name => 'Reviewed' ),
28
+ Status.new(:id => 100, :name => 'Published'),
29
+ Status.new(:id => 101, :name => 'Hidden' )
30
+ ]
31
+ end
@@ -0,0 +1,11 @@
1
+ require 'registerable'
2
+
3
+ module TextFilter
4
+ include Registerable
5
+
6
+ class Base
7
+ def filter(text)
8
+ text
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,70 @@
1
+ require 'digest/sha1'
2
+
3
+ class User < ActiveRecord::Base
4
+
5
+ # Associations
6
+ belongs_to :created_by, :class_name => 'User', :foreign_key => 'created_by'
7
+ belongs_to :updated_by, :class_name => 'User', :foreign_key => 'updated_by'
8
+
9
+ # Validations
10
+ validates_uniqueness_of :login, :message => 'login already in use'
11
+
12
+ validates_confirmation_of :password, :message => 'must match confirmation', :if => :confirm_password?
13
+
14
+ validates_presence_of :name, :login, :message => 'required'
15
+ validates_presence_of :password, :password_confirmation, :message => 'required', :if => :new_record?
16
+
17
+ validates_format_of :email, :message => 'invalid e-mail address', :allow_nil => true, :with => /^$|^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
18
+
19
+ validates_length_of :name, :maximum => 100, :allow_nil => true, :message => '%d-character limit'
20
+ validates_length_of :login, :within => 3..40, :allow_nil => true, :too_long => '%d-character limit', :too_short => '%d-character minimum'
21
+ validates_length_of :password, :within => 5..40, :allow_nil => true, :too_long => '%d-character limit', :too_short => '%d-character minimum', :if => :validate_length_of_password?
22
+ validates_length_of :email, :maximum => 255, :allow_nil => true, :message => '%d-character limit'
23
+
24
+ validates_numericality_of :id, :only_integer => true, :allow_nil => true, :message => 'must be a number'
25
+
26
+ cattr_accessor :salt
27
+ @@salt = 'sweet harmonious biscuits' # historic value
28
+
29
+ attr_writer :confirm_password
30
+
31
+ def self.sha1(phrase)
32
+ Digest::SHA1.hexdigest("--#{@@salt}--#{phrase}--")
33
+ end
34
+
35
+ def self.authenticate(login, password)
36
+ find_by_login_and_password(login, sha1(password))
37
+ end
38
+
39
+ def after_initialize
40
+ @confirm_password = true
41
+ end
42
+
43
+ def confirm_password?
44
+ @confirm_password
45
+ end
46
+
47
+ private
48
+
49
+ def validate_length_of_password?
50
+ new_record? or not password.to_s.empty?
51
+ end
52
+
53
+ before_create :encrypt_password
54
+ def encrypt_password
55
+ self.password = self.class.sha1(password)
56
+ end
57
+
58
+ before_update :encrypt_password_unless_empty_or_unchanged
59
+ def encrypt_password_unless_empty_or_unchanged
60
+ user = self.class.find(self.id)
61
+ case password
62
+ when ''
63
+ self.password = user.password
64
+ when user.password
65
+ else
66
+ encrypt_password
67
+ end
68
+ end
69
+
70
+ end
@@ -0,0 +1,13 @@
1
+ class UserActionObserver < ActiveRecord::Observer
2
+ observe User, Page, Layout, Snippet
3
+
4
+ cattr_accessor :current_user
5
+
6
+ def before_create(model)
7
+ model.created_by = @@current_user
8
+ end
9
+
10
+ def before_update(model)
11
+ model.updated_by = @@current_user
12
+ end
13
+ end
@@ -0,0 +1,38 @@
1
+ <h1>Layouts</h1>
2
+
3
+ <p>Use layouts to apply a visual look to a Web page. Layouts can contain special tags to include
4
+ page content and other elements such as the header or footer. Click on a layout name below to
5
+ edit it or click <code>Remove</code> to delete it.</p>
6
+
7
+ <table id="layouts" class="index" cellpadding="0" cellspacing="0" border="0">
8
+ <thead>
9
+ <tr>
10
+ <th class="layout">Layout</th>
11
+ <th class="modify">Modify</th>
12
+ </tr>
13
+ </thead>
14
+ <tbody>
15
+ <% unless @layouts.empty? -%>
16
+ <% for layout in @layouts -%>
17
+ <tr class="node level-1">
18
+ <td class="layout">
19
+ <%= image_tag 'page', :alt => 'layout-icon', :title => '', :align => 'center' %>
20
+ <%= link_to layout.name, layout_edit_url(:id => layout) %>
21
+ </td>
22
+ <td class="remove"><%= link_to image_tag('remove', :alt => 'Remove Layout'), layout_remove_url(:id => layout) %></td>
23
+ </tr>
24
+ <% end -%>
25
+ <% else -%>
26
+ <tr>
27
+ <td colspan="2" class="note">No Layouts</td>
28
+ </tr>
29
+ <% end -%>
30
+ </tbody>
31
+ </table>
32
+ <script type="text/javascript">
33
+ // <![CDATA[
34
+ new RuledTable('layouts');
35
+ // ]]>
36
+ </script>
37
+
38
+ <p><%= link_to image_tag('new-layout', :alt => 'New Layout'), layout_new_url %></p>
@@ -0,0 +1,37 @@
1
+ <% if @layout.new_record? -%>
2
+ <h1>New Layout</h1>
3
+ <% else -%>
4
+ <h1>Edit Layout</h1>
5
+ <% end -%>
6
+
7
+ <form method="post">
8
+ <div class="form-area">
9
+ <p class="title">
10
+ <label for="layout_name">Name</label>
11
+ <%= text_field "layout", "name", :class => 'textbox', :maxlength => 100 %>
12
+ </p>
13
+ <div id="extended-metadata" class="row"<%= meta_visible(:meta) %>>
14
+ <table class="fieldset" cellpadding="0" cellspacing="0" border="0">
15
+ <tr>
16
+ <td><label for="layout_content_type">Content-Type</label></td>
17
+ <td class="field"><%= text_field "layout", "content_type", :class => 'textbox', :maxlength => 40 %></td>
18
+ </tr>
19
+ </table>
20
+ </div>
21
+ <p>
22
+ <small>
23
+ <a id="more-extended-metadata" href="<%= toggle_javascript_for('extended-metadata') %>"<%= meta_visible(:meta_more) %>>More</a>
24
+ <a id="less-extended-metadata" href="<%= toggle_javascript_for('extended-metadata') %>"<%= meta_visible(:meta_less) %>>Less</a>
25
+ </small>
26
+ </p>
27
+ <p class="content">
28
+ <label for="layout_content">Body</label>
29
+ <%= text_area "layout", "content", :class => "textarea", :style => "width: 100%" %></p>
30
+ <%= updated_stamp @layout %>
31
+ </div>
32
+ <p class="buttons">
33
+ <%= save_model_button(@layout) %> <%= save_model_and_continue_editing_button(@layout) %> or <%= link_to "Cancel", layout_index_url %>
34
+ </p>
35
+ </form>
36
+
37
+ <%= focus 'layout_name' %>
@@ -0,0 +1,17 @@
1
+ <h1>Remove Layout</h1>
2
+ <p>Are you sure you want to <strong class="warning">permanently remove</strong> the following layout?</p>
3
+
4
+ <table id="site-map" class="index" cellpadding="0" cellspacing="0" border="0">
5
+ <tbody>
6
+ <tr class="node level-1" onmouseover="Element.addClassName(this, 'highlight');" onmouseout="Element.removeClassName(this, 'highlight');">
7
+ <td class="layout">
8
+ <%= image_tag 'page', :alt => 'layout-icon', :title => '', :align => 'center' %>
9
+ <%= @layout.name %>
10
+ </td>
11
+ </tr>
12
+ </tbody>
13
+ </table>
14
+
15
+ <form method="post">
16
+ <p class="buttons"><%= submit_tag "Delete Layout", :class => 'button' %> or <%= link_to 'Cancel', layout_index_url %></p>
17
+ </form>
@@ -0,0 +1,51 @@
1
+ <%
2
+ count = page.children.count
3
+ children = count > 0
4
+ expand = expand - 1
5
+ expanded = expand > 0
6
+ padding_left = (level * 22) + 4
7
+
8
+ children_class = children ? (expanded ? ' children-visible' : ' children-hidden') : ' no-children'
9
+ virtual_class = page.virtual? ? " virtual": ""
10
+
11
+ expander = children ? image_tag((expanded ? "collapse" : "expand"), :class => "expander", :alt => 'toggle children', :title => '', :align => 'center') : ""
12
+
13
+ icon_name = page.virtual? ? "virtual-page" : "page"
14
+ icon = image_tag(icon_name, :class => "icon", :alt => 'page-icon', :title => '', :align => 'center')
15
+
16
+ title = %{<span class="title">#{ page.title }</span>}
17
+
18
+ behavior_id = page.behavior_id.to_s.strip
19
+ behavior = behavior_id.empty? ? '' : %{<small class="info">(#{ behavior_id })</small>}
20
+
21
+ spinner = image_tag("spinner.gif", :class => 'busy', :id => "busy-#{page.id}", :alt => "", :title => "", :align => "center", :style => 'display: none;')
22
+ -%>
23
+ <tr id="page-<%= page.id %>" class="node level-<%= level %><%= children_class %><%= virtual_class %>">
24
+ <td class="page" style="padding-left: <%= padding_left %>px">
25
+ <span class="w1">
26
+ <% if simple -%>
27
+ <%= icon %>
28
+ <%= title %>
29
+ <% else -%>
30
+ <%= expander %><a href="<%= page_edit_url(:id => page) %>"><%= icon %> <%= title %></a>
31
+ <%= behavior %>
32
+ <%= spinner %>
33
+ <% end -%>
34
+ </span>
35
+ </td>
36
+ <% unless simple -%>
37
+ <td class="status <%= page.status.name.downcase %>-status"><%= page.status.name %></td>
38
+ <td class="add-child"><%= link_to image_tag('add-child', :alt => 'add child'), page_new_url(:parent_id => page) %></td>
39
+ <td class="remove"><%= link_to image_tag('remove', :alt => 'remove page'), page_remove_url(:id => page) %></td>
40
+ <% end -%>
41
+ </tr>
42
+ <% level = level + 1 -%>
43
+ <%
44
+ if expanded
45
+ page.children.each do |child|
46
+ -%>
47
+ <%= render_node child, :level => level, :expand => expand, :simple => simple -%>
48
+ <%
49
+ end
50
+ end
51
+ -%>