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,60 @@
1
+ <%# Params:
2
+ # - page (Page Node)
3
+ # - level (integer indicating current tree depth)
4
+ # Called From:
5
+ # - index
6
+ # Description:
7
+ # This partial is used recursively. Render it with the root node, and it will recurse
8
+ # down all of the child nodes to build a list with proper indentation to indicate
9
+ # tree depth.
10
+ %>
11
+
12
+ <%
13
+ # Create the page-level links...
14
+ links = []
15
+ links << link_to(pluralize(page.versions.length, 'revision', 'revisions'), :action=>'versions', :id=>page) if !page.nil? and !page.versions.nil? and page.versions.length > 0
16
+ links << link_to('add child page', {:action=>'new', :parent=>page}, :title=>"Add a child to '#{page.title}'", :class=>'add-page')
17
+ links << link_to_function('reorder children', "ComatoseList.toggle_reorder('page_list_#{page.id}',this,#{page.id})", :title=>"Reorder children of '#{page.title}'", :class=>'reorder-children', :href=>url_for(:action=>'reorder', :id=>page)) if !page.children.empty? and page.children.length > 1
18
+ links << link_to('delete', {:action=>'delete', :id=>page}, :confirm=>'This will delete this page, and any children. Are you sure?', :title=>"Delete page '#{page.title}' and all it's children", :class=>'delete-page', :method=>'post', :onmouseover=>"ComatoseList.item_hover('page_#{page.id}', 'over', true)", :onmouseout=>"ComatoseList.item_hover('page_#{page.id}', 'out', true)") unless @root_pages.include? page
19
+ # Level check, one, two, three...
20
+ collapse_children = (level >= Comatose.config.default_tree_level)
21
+ %>
22
+
23
+ <li id="page_<%= page.id %>">
24
+ <table cellpadding="0" cellspacing="0">
25
+ <tr>
26
+ <td rowspan="2" valign="center">
27
+ <% if !page.children.empty? %>
28
+ <%= image_tag( ((collapse_children) ? 'comatose/collapsed.gif' : 'comatose/expanded.gif'), :title=>'Expand/Collapse', :onclick=>"ComatoseList.toggle_tree_nodes(this,#{page.id});", :class=>'tree-controller', :size=>'12x12', :id=>"page_controller_#{page.id}" ) %>
29
+ <% else %>
30
+ <%= image_tag 'comatose/no-children.gif', :size=>'12x12', :class=>'tree-controller' %>
31
+ <% end %>
32
+ </td>
33
+ <td rowspan="2" valign="center">
34
+ <%= image_tag 'comatose/page.gif', :size=>'25x31', :align=>"absmiddle" %>
35
+ <span class="handle">DRAG</span>
36
+ </td>
37
+ <td>
38
+ <%= link_to page.title, {:action=>'edit', :id=>page}, :title=>"Path:#{page.full_path}", :class=>'page' %>
39
+ </td>
40
+ </tr>
41
+ <tr>
42
+ <td class="commands">
43
+ Updated <span title="Created on <%= page.created_on %>"><%= time_ago_in_words page.updated_on, true %> ago</span><%= " by #{page.author}" unless page.author.nil? or page.author.empty? %>,
44
+ <%= links.join(', ') %>.
45
+ </td>
46
+ </tr>
47
+ </table>
48
+
49
+ <ul id="page_list_<%= page.id %>" old="lvl-<%= page.id %>" class="page-list <%= 'collapsed' if collapse_children %>" >
50
+ <% for child in page.children %>
51
+ <%= render :partial=>'page_list_item', :locals=>{ :page=>child, :level=>level+1 } %>
52
+ <% end %>
53
+ </ul>
54
+
55
+ <%= sortable_element( "page_list_#{page.id}",
56
+ :complete => visual_effect(:highlight, "page_list_#{page.id}"),
57
+ :handle=>'handle',
58
+ :update=>'flash-content',
59
+ :url => { :action => "reorder", :id=>page } ) if !page.children.empty? and page.children.length > 1 %>
60
+ </li>
@@ -0,0 +1,18 @@
1
+ <h1>
2
+ Page Delete Confirmation
3
+ </h1>
4
+
5
+ <blockquote>
6
+ <p>Are you sure you want to delete the page titled "<b><%= @page.title %></b>"?</p>
7
+ <% unless @page.children.empty? %>
8
+ <p>It has <b><%= @page.children.length %></b> child pages that will also be deleted...</p>
9
+ <% end %>
10
+ </blockquote>
11
+
12
+ <%= start_form_tag %>
13
+ <div id="button-group">
14
+ <%= submit_tag "Yes, Delete The Page" %>
15
+ or
16
+ <%= link_to "Cancel", :action=>'index' %>
17
+ </div>
18
+ <%= end_form_tag %>
@@ -0,0 +1,5 @@
1
+ <h1>
2
+ Edit Page
3
+ </h1>
4
+
5
+ <%= render :partial=>'form', :locals=>{:mode=>:edit} %>
@@ -0,0 +1,29 @@
1
+ <div class="action">
2
+ <%= link_to 'Clear Page Cache', :controller=>controller.controller_name, :action=>'expire_page_cache' %>
3
+ <% if Comatose.config.allow_import_export %>
4
+ <%= link_to 'Import', '#', :id => 'import_link2', :onclick => "$('import_form').setStyle({display: 'inline'}); return false;" %>
5
+ <%= link_to 'Export', :controller=>controller.controller_name, :action=>'export' %>
6
+ <div id="import_form" style="display: none;">
7
+ <% form_tag(url_for(:action => 'import'), :multipart => true) do %>
8
+ <%= file_field_tag 'import_file' %>
9
+ <%= submit_tag 'Upload and Import' %>
10
+ <a href="#" onclick="$('import_form').hide(); return false;">Cancel</a>
11
+ <% end %>
12
+ </div>
13
+ <% end %>
14
+ </div>
15
+
16
+ <h1>
17
+ Page List
18
+ <%= image_tag 'comatose/spinner.gif', :id=>'spinner', :align=>'absmiddle', :style=>'display:none;' %>
19
+ </h1>
20
+
21
+ <ul class="page-list root">
22
+ <% @root_pages.each do |page| %>
23
+ <%= render :partial=>'page_list_item', :locals=>{ :page=>page, :level=>1 } %>
24
+ <% end %>
25
+ </ul>
26
+
27
+ <div id="status"></div>
28
+
29
+ <%= javascript_tag "ComatoseList.init()" %>
@@ -0,0 +1,5 @@
1
+ <h1>
2
+ New Page
3
+ </h1>
4
+
5
+ <%= render :partial=>'form', :locals=>{:mode=>:new} %>
@@ -0,0 +1,30 @@
1
+ <h1>Reorder Pages</h1>
2
+
3
+ <h3>"<%= @page.title %>" child pages:</h3>
4
+
5
+ <ul class="page-list">
6
+ <% @page.children.each do |page| %>
7
+ <li>
8
+ <table cellpadding="0" cellspacing="0">
9
+ <tr>
10
+ <td rowspan="2" valign="center">
11
+ <%= image_tag 'comatose/page.gif', :size=>'25x31', :align=>"absmiddle" %>
12
+ </td>
13
+ <td>
14
+ <a class="page"><%= page.title %></a>
15
+ </td>
16
+ </tr>
17
+ <tr>
18
+ <td class="commands">
19
+ <%= link_to "Move Up", :action=>'reorder', :cmd=>'up', :page=>page.id %>,
20
+ <%= link_to "Move Down", :action=>'reorder', :cmd=>'down', :page=>page.id %>
21
+ </td>
22
+ </tr>
23
+ </table>
24
+ </li>
25
+ <% end %>
26
+ </ul>
27
+
28
+ <div id="button-group">
29
+ <%= link_to "Finished", :action=>'index' %>
30
+ </div>
@@ -0,0 +1,40 @@
1
+ <h1>Page Revisions</h1>
2
+ <form>
3
+ <div class="revisions older-content">
4
+ <div class="header">
5
+ <div class="header-actions">
6
+ <% form_tag :action => 'versions', :id => @page, :html => { :method => :get } do %>
7
+ View Version: <%= select_tag "version", options_from_collection_for_select(@page.versions, 'version', 'version', @version_num), {'onchange'=>'this.form.submit();'} %>
8
+ <%= submit_tag 'Go', {'id'=>'go-btn'} %>
9
+ <% end %>
10
+ </div>
11
+ Version <%= @version_num %>
12
+ </div>
13
+ <div class="meta">
14
+ <label class="title"><span>Title:</span><%= @version.title %></label>
15
+ <label><span>Slug:</span> <%= @version.slug %></label>
16
+ <label><span>Keywords:</span> <%= @version.keywords %></label>
17
+ </div>
18
+ <%= @version.body.split("\n").join('<br/>') unless @version.body.nil? %>
19
+ <div id="button-group" class="footer">
20
+ <% form_tag :action=>'set_version', :id => @page, :version => @version_num do %>
21
+ <%= submit_tag "Set As Current Version" %>
22
+ or
23
+ <%= link_to "Cancel", :action=>'index' %>
24
+ <% end %>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="revisions current-content">
29
+ <div class="header">
30
+ Current Version
31
+ </div>
32
+ <div class="meta">
33
+ <label class="title"><span>Title:</span><%= @page.title %></label>
34
+ <label><span>Slug:</span> <%= @page.slug %></label>
35
+ <label><span>Keywords:</span> <%= @page.keywords %></label>
36
+ </div>
37
+ <%= @page.body.split("\n").join('<br/>') unless @page.body.nil? %>
38
+ </div>
39
+
40
+ <div style="clear:both">&nbsp;</div>
@@ -0,0 +1,837 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
2
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
3
+ <html class="noscript" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=<%= Comatose.config.content_type %>"/>
6
+ <title>Comatose Admin</title>
7
+ <style>
8
+ BODY {
9
+ background: #DDD;
10
+ margin: 0px 100px;
11
+ padding: 0px;
12
+ font-family: "Lucida Grande", Tahoma, Verdana, Arial, Sans-Serif;
13
+ font-size: 12px;
14
+ min-width: 450px;
15
+ }
16
+ /* General Layout and Header Area */
17
+ #page-container {
18
+ margin: 0px;
19
+ padding: 0px;
20
+ }
21
+ #header {
22
+ background: #0053C2;
23
+ padding: 5px;
24
+ border-bottom: 4px solid #00398B;
25
+ }
26
+ #header A {
27
+ text-decoration: none;
28
+ color: white;
29
+ }
30
+ #header A:hover {
31
+ color: white;
32
+ }
33
+ #header h1 {
34
+ margin: 0px;
35
+ padding: 0px;
36
+ padding-left: 10px;
37
+ }
38
+ #header h5 {
39
+ margin: 0px;
40
+ padding: 0px;
41
+ padding-left: 15px;
42
+ color: silver;
43
+ }
44
+ #header #flash {
45
+ float: right;
46
+ color: #4BA8FF;
47
+ font-weight: bold;
48
+ margin-right: 5px;
49
+ }
50
+ /* Content Area */
51
+ #content {
52
+ padding: 15px;
53
+ background: white;
54
+ border-left: 1px solid silver;
55
+ border-right: 1px solid silver;
56
+ }
57
+ #content h1 {
58
+ margin: 0px;
59
+ padding: 0px;
60
+ font-size: 135%;
61
+ color: gray;
62
+ }
63
+ #content .action {
64
+ float: right;
65
+ color: gray;
66
+ }
67
+ #content .action A {
68
+ font-weight: bold;
69
+ text-decoration: none;
70
+ color: navy;
71
+ border-bottom: 1px solid blue;
72
+ margin-left: 15px;
73
+ }
74
+ #content .action A:hover {
75
+ color: red;
76
+ border-bottom: 1px solid red;
77
+ }
78
+ #content .page-header {
79
+ color: gray;
80
+ }
81
+ #import_form {
82
+ position: fixed;
83
+ right: 75px;
84
+ border: 3px solid gray !important;
85
+ -webkit-border-radius: 10px;
86
+ -moz-border-radius: 10px;
87
+ background: #FFF;
88
+ padding: 15px;
89
+ }
90
+ #import_form FORM {
91
+ display: inline;
92
+ margin: 0px;
93
+ padding: 0px;
94
+ }
95
+ #import_form A {
96
+ color: maroon !important;
97
+ border-bottom: 1px solid gray !important;
98
+ }
99
+ #import_form A:hover {
100
+ color: red !important;
101
+ border-bottom: 1px solid red !important;
102
+ }
103
+
104
+ /* Page Listing */
105
+ #content .tree-controller {
106
+ border: 0px;
107
+ cursor: pointer;
108
+ }
109
+ #content .page-list.root {
110
+ clear: both;
111
+ list-style: none;
112
+ margin: 0px;
113
+ padding: 0px;
114
+ margin-top: 10px;
115
+ }
116
+ #content .page-list.collapsed {
117
+ display: none;
118
+ }
119
+ #content .page-list {
120
+ background: white;
121
+ clear: both;
122
+ list-style: none;
123
+ border-left: 0px dotted silver;
124
+ margin: 0px;
125
+ padding: 0px;
126
+ padding-left: 15px;
127
+ margin-top: 2px;
128
+ }
129
+ #content .page-list LI {
130
+ clear: both;
131
+ padding: 0px;
132
+ margin: 5px 0px;
133
+ padding-top: 2px;
134
+ padding-right: 0px;
135
+ padding-left: 2px;
136
+ }
137
+ #content .page-list .commands {
138
+ font-size: 90%;
139
+ padding-left: 5px;
140
+ color: silver;
141
+ }
142
+ #content .page-list .commands A {
143
+ color: gray;
144
+ }
145
+ #content .page-list .commands A.add-page:hover {
146
+ color: blue;
147
+ }
148
+ #content .page-list .commands A.reorder-children:hover {
149
+ color: black;
150
+ }
151
+ #content .page-list .commands A.delete-page:hover {
152
+ color: white;
153
+ }
154
+ #content .page-list .commands A.reordering {
155
+ background: navy;
156
+ color: white;
157
+ }
158
+ #content .page-list .commands A.reordering:hover {
159
+ color: white;
160
+ }
161
+ #content .page-list A.page {
162
+ text-decoration: none;
163
+ color: black;
164
+ margin-left: 3px;
165
+ font-size: 150%;
166
+ display: block;
167
+ }
168
+ #content .page-list A.page:hover {
169
+ /*color: blue;*/
170
+ background: white url(../images/comatose/title-hover-bg.gif) top left repeat-y;
171
+ }
172
+ #content .handle, #content .do-reorder UL LI .handle {
173
+ display: none;
174
+ }
175
+
176
+ #content .page-list .hover {
177
+ background: #F1F0DB;
178
+ }
179
+ #content .page-list .hover-delete {
180
+ background: red;
181
+ color: #FF8E90;
182
+ }
183
+ #content .page-list .hover-delete A,
184
+ #content .page-list .hover-delete .commands A {
185
+ color: #FF8E90;
186
+ }
187
+ #content .page-list .hover-delete A.page {
188
+ color: white;
189
+ border-bottom: 0px;
190
+ }
191
+ #content .page-list .hover-delete UL LI A.page {
192
+ color: red;
193
+ border-bottom: 0px;
194
+ }
195
+
196
+ #content .do-reorder LI .handle {
197
+ display: inline;
198
+ background: gray;
199
+ color: white;
200
+ padding: 1px 3px;
201
+ cursor: move;
202
+ }
203
+
204
+ #content .page-list .do-reorder .commands A {
205
+ display: none;
206
+ }
207
+
208
+ /* Page Form */
209
+ #content .page-form {
210
+ margin-top: 10px;
211
+ }
212
+ #content .page-form LABEL {
213
+ font-weight: bold;
214
+ color: #555;
215
+ }
216
+ #content .page-form .meta-info LABEL {
217
+ color: #999 !important;
218
+ }
219
+ #content .page-form .label {
220
+ padding-top: 5px;
221
+ width: 75px;
222
+ text-align: right;
223
+ padding-right: 10px;
224
+ }
225
+ #content .page-form .label.body {
226
+ vertical-align: top;
227
+ padding-top: 10px;
228
+ }
229
+ #content .page-form .field {
230
+ padding-top: 5px;
231
+ }
232
+ #content .page-form .field-help {
233
+ color: gray;
234
+ }
235
+ #content .page-form #page_title {
236
+ font-size: 125%;
237
+ font-weight: bold;
238
+ }
239
+ #content .page-form #page_slug {
240
+ color: gray;
241
+ }
242
+ #content .page-form #page_body {
243
+ font-family: monospace;
244
+ font-size: 110%;
245
+ }
246
+ #content #button-group {
247
+ padding: 10px;
248
+ text-align: right;
249
+ background-color: #EAEAEA;
250
+ margin-top: 10px;
251
+ }
252
+ #content #button-group .last-update {
253
+ float: left;
254
+ color: gray;
255
+ padding-top: 4px;
256
+ font-weight: bold;
257
+ }
258
+ #content #button-group .last-update LABEL {
259
+ font-weight: normal;
260
+ }
261
+ #content #button-group .last-update A {
262
+ color: gray;
263
+ }
264
+ #content #button-group A {
265
+ color: maroon;
266
+ }
267
+ #content #button-group A:hover {
268
+ color: red;
269
+ }
270
+ #content #preview-area {
271
+ margin-top: 10px;
272
+ }
273
+ #content #preview-area FIELDSET {
274
+ border: 1px solid silver;
275
+ }
276
+ #content #preview-area LEGEND {
277
+ font-size: 125%;
278
+ }
279
+ #content #preview-area .preview-body {
280
+ padding: 10px;
281
+ }
282
+ #content #preview-area .preview-note {
283
+ background: #FFFFD9;
284
+ padding: 15px;
285
+ }
286
+ #content #preview-area .commands {
287
+ text-align: right;
288
+ color: gray;
289
+ }
290
+ #content #preview-area .commands A{
291
+ color: gray;
292
+ }
293
+ #content #preview-area .commands A:hover{
294
+ color: black;
295
+ }
296
+ #content .revisions {
297
+ padding: 10px;
298
+ width: 49%;
299
+ }
300
+ #content .current-content {
301
+ }
302
+ #content .older-content {
303
+ background: #E9E9E9;
304
+ float: right;
305
+ }
306
+
307
+ #content .revisions label {
308
+ display: block;
309
+ color: #000;
310
+ }
311
+ #content .revisions label span {
312
+ color: #999;
313
+ font-weight: normal !important;
314
+ }
315
+ #content .revisions .title {
316
+ font-weight: bold;
317
+ margin-top: 5px;
318
+ }
319
+ #content .revisions .header {
320
+ font-size: 110%;
321
+ vertical-align: middle;
322
+ font-weight: bold;
323
+ }
324
+ #content .revisions .header-actions {
325
+ float: right;
326
+ font-size: 90%;
327
+ font-weight: normal;
328
+ color: #999;
329
+ }
330
+ #content .revisions .meta {
331
+ margin-bottom: 15px;
332
+ }
333
+ #content .revisions .footer {
334
+ margin-top: 25px !important;
335
+ text-align: center !important;
336
+ }
337
+ #content #go-btn {
338
+ display: none;
339
+ }
340
+ /* Errors */
341
+ #errorExplanation {
342
+ border: 1px solid red;
343
+ background: #FFEAEB;
344
+ padding: 10px;
345
+ margin-top: 10px;
346
+ }
347
+ #errorExplanation h2 {
348
+ margin: 0px;
349
+ padding: 0px;
350
+ color: maroon;
351
+ }
352
+ #errorExplanation p {
353
+ margin: 0px;
354
+ padding: 0px;
355
+ padding-top: 5px;
356
+ padding-left: 15px;
357
+ }
358
+ #errorExplanation ul {
359
+ margin: 0px;
360
+ padding: 0px;
361
+ padding-left: 35px;
362
+ }
363
+ #errorExplanation li {
364
+ margin: 0px;
365
+ padding: 0px;
366
+ padding-top: 5px;
367
+ }
368
+ /* Footer Area*/
369
+ #footer {
370
+ border-top: 4px solid #AAA;
371
+ text-align: center;
372
+ font-size: 90%;
373
+ color: #AAA;
374
+ padding-top: 5px;
375
+ padding-bottom: 5px;
376
+ }
377
+ #footer A {
378
+ color: #AAA;
379
+ text-decoration: none;
380
+ font-weight: bold;
381
+ }
382
+ #footer A:hover {
383
+ color: #333;
384
+ text-decoration: underline;
385
+ }
386
+
387
+ /* Modifiers */
388
+
389
+ /* When JavaScript is Turned Off... We need to adjust some things... */
390
+ .noscript #more-options,
391
+ .noscript #preview-area,
392
+ .noscript #preview-btn,
393
+ .noscript .tree-controller {
394
+ display: none;
395
+ }
396
+ .noscript .page-list.collapsed {
397
+ display: block !important;
398
+ }
399
+ .noscript .delete-page:hover {
400
+ color: red !important;
401
+ }
402
+ .noscript #content .page-form #page_title,
403
+ .noscript #content .page-form #page_slug,
404
+ .noscript #content .page-form #page_parent,
405
+ .noscript #content .page-form #page_keywords,
406
+ .noscript #content .page-form #page_body {
407
+ width: 100% !important;
408
+ }
409
+ .noscript #content .revisions #go-btn {
410
+ display: inline;
411
+ }
412
+
413
+ </style>
414
+ <%= javascript_include_tag :defaults %>
415
+ <script>
416
+ // CSS Browser Selector v0.2.3b (M@: added noscript support)
417
+ // Documentation: http://rafael.adm.br/css_browser_selector
418
+ // License: http://creativecommons.org/licenses/by/2.5/
419
+ // Author: Rafael Lima (http://rafael.adm.br)
420
+ // Contributors: http://rafael.adm.br/css_browser_selector#contributors
421
+ var css_browser_selector = function() {
422
+ var
423
+ ua = navigator.userAgent.toLowerCase(),
424
+ is = function(t){ return ua.indexOf(t) != -1; },
425
+ h = document.getElementsByTagName('html')[0],
426
+ b = (!(/opera|webtv/i.test(ua)) && /msie (\d)/.test(ua)) ? ((is('mac') ? 'ieMac ' : '') + 'ie ie' + RegExp.$1)
427
+ : is('gecko/') ? 'gecko' : is('opera') ? 'opera' : is('konqueror') ? 'konqueror' : is('applewebkit/') ? 'webkit safari' : is('mozilla/') ? 'gecko' : '',
428
+ os = (is('x11') || is('linux')) ? ' linux' : is('mac') ? ' mac' : is('win') ? ' win' : '';
429
+ var c = b+os+' js';
430
+ h.className = h.className.replace('noscript', '') + h.className?' '+c:c;
431
+ }();
432
+
433
+ // List View Functions
434
+ var ComatoseList = {
435
+ save_node_state: true,
436
+ state_store: 'cookie', // Only 'cookie' for now
437
+ state_key: 'ComatoseTreeState',
438
+
439
+ init: function() {
440
+ var items = ComatoseList._read_state();
441
+ items.each(function(node){
442
+ ComatoseList.expand_node(node.replace('page_controller_', ''))
443
+ });
444
+ },
445
+
446
+ toggle_tree_nodes : function(img, id) {
447
+ if(/expanded/.test(img.src)) {
448
+ $('page_list_'+ id).addClassName('collapsed');
449
+ img.src = img.src.replace(/expanded/, 'collapsed')
450
+ if(ComatoseList.save_node_state) {
451
+ var items = ComatoseList._read_state();
452
+ items = items.select(function(id){ return id != img.id; })
453
+ ComatoseList._write_state(items);
454
+ }
455
+ } else {
456
+ $('page_list_'+ id).removeClassName('collapsed');
457
+ img.src = img.src.replace(/collapsed/, 'expanded')
458
+ if(ComatoseList.save_node_state) {
459
+ var items = ComatoseList._read_state();
460
+ items.push(img.id);
461
+ ComatoseList._write_state(items);
462
+ }
463
+ }
464
+ },
465
+
466
+ expand_node: function(id) {
467
+ $('page_list_'+ id).removeClassName('collapsed');
468
+ $('page_controller_'+ id).src = $('page_controller_'+ id).src.replace(/collapsed/, 'expanded')
469
+ },
470
+
471
+ collapse_node: function(id) {
472
+ $('page_list_'+ id).addClassName('collapsed');
473
+ $('page_controller_'+ id).src = $('page_controller_'+ id).src.replace(/expanded/, 'collapsed')
474
+ },
475
+
476
+ item_hover : function(node, state, is_delete) {
477
+ if( state == 'over') {
478
+ $(node).addClassName( (is_delete) ? 'hover-delete' : 'hover' );
479
+ } else {
480
+ $(node).removeClassName( (is_delete) ? 'hover-delete' : 'hover' );
481
+ }
482
+ },
483
+
484
+ toggle_reorder: function(node, anc, id) {
485
+ if( $(node).hasClassName('do-reorder') ) {
486
+ $(node).removeClassName( 'do-reorder' );
487
+ $(anc).removeClassName('reordering');
488
+ $(anc).innerHTML = "reorder children";
489
+ } else {
490
+ $(node).addClassName( 'do-reorder' );
491
+ $(anc).addClassName('reordering');
492
+ $(anc).innerHTML = "finished reordering";
493
+ // Make sure the children are visible...
494
+ ComatoseList.expand_node(id);
495
+ }
496
+ },
497
+
498
+ _write_state: function(items) {
499
+ var cookie = {}; var options = {}; var expiration = new Date();
500
+ cookie[ ComatoseList.state_key ] = items.join(',');
501
+ expiration.setDate(expiration.getDate()+30)
502
+ options['expires'] = expiration;
503
+ Cookie.write( cookie, options );
504
+ },
505
+
506
+ _read_state: function() {
507
+ var state = Cookie.read( ComatoseList.state_key );
508
+ return (state != "" && state != null) ? state.split(',') : [];
509
+ }
510
+ }
511
+
512
+ // Edit Form Functions
513
+ var ComatoseEditForm = {
514
+
515
+ default_data: {},
516
+ last_preview: {},
517
+ last_title_slug: '',
518
+ mode : null,
519
+ liquid_horiz: true,
520
+ width_offset: 325,
521
+
522
+ // Initialize the page...
523
+ init : function(mode) {
524
+ this.mode = mode;
525
+ this.default_data = Form.serialize(document.forms[0]);
526
+ if(mode == 'new') {
527
+ this.last_title_slug = $('page_title').value.toSlug();
528
+ Event.observe('page_title', 'blur', ComatoseEditForm.title_updated_aggressive);
529
+ } else {
530
+ Event.observe('page_title', 'blur', ComatoseEditForm.title_updated);
531
+ }
532
+ $('page_title').focus();
533
+ Hide.these(
534
+ 'preview-area',
535
+ 'slug_row',
536
+ 'parent_row',
537
+ 'keywords_row',
538
+ 'filter_row',
539
+ 'created_row'
540
+ );
541
+ $('page_title').select();
542
+ // Create the horizontal liquidity of the fields
543
+ if(this.liquid_horiz) {
544
+ xOffset = this.width_offset;
545
+ new Layout.LiquidHoriz((xOffset + 50), 'page_title');
546
+ new Layout.LiquidHoriz(xOffset, 'page_slug','page_keywords','page_parent','page_body');
547
+ }
548
+ },
549
+ // For use when updating an existing page...
550
+ title_updated : function() {
551
+ slug = $('page_slug');
552
+ if(slug.value == "") {
553
+ title = $('page_title');
554
+ slug.value = title.value.toSlug();
555
+ }
556
+ },
557
+ // For use when creating a new page...
558
+ title_updated_aggressive : function() {
559
+ slug = $('page_slug');
560
+ title = $('page_title');
561
+ if(slug.value == "" || slug.value == this.last_title ) {
562
+ slug.value = title.value.toSlug();
563
+ }
564
+ this.last_title = slug.value;
565
+ },
566
+ // Todo: Make the meta fields remember their visibility?
567
+ toggle_extra_fields : function(anchor) {
568
+ if(anchor.innerHTML == "More...") {
569
+ Show.these(
570
+ 'slug_row',
571
+ 'keywords_row',
572
+ 'parent_row',
573
+ 'filter_row',
574
+ 'created_row'
575
+ );
576
+ anchor.innerHTML = 'Less...';
577
+ } else {
578
+ Hide.these(
579
+ 'slug_row',
580
+ 'keywords_row',
581
+ 'parent_row',
582
+ 'filter_row',
583
+ 'created_row'
584
+ );
585
+ anchor.innerHTML = 'More...';
586
+ }
587
+ },
588
+ // Uses server to create preview of content...
589
+ preview_content : function(preview_url) {
590
+ $('preview-area').show();
591
+ var params = Form.serialize(document.forms[0]);
592
+ if( params != this.last_preview ) {
593
+ $('preview-panel').innerHTML = "<span style='color:blue;'>Loading Preview...</span>";
594
+ new Ajax.Updater(
595
+ 'preview-panel',
596
+ preview_url,
597
+ { parameters: params }
598
+ );
599
+ }
600
+ this.last_preview = params;
601
+ },
602
+ cancel : function(url) {
603
+ var current_data = Form.serialize(document.forms[0]);
604
+ var data_changed = (this.default_data != current_data)
605
+ if(data_changed) {
606
+ if( confirm('Changes detected. You will lose all the updates you have made if you proceed...') ) {
607
+ location.href = url;
608
+ }
609
+ } else {
610
+ location.href = url;
611
+ }
612
+
613
+ }
614
+ }
615
+
616
+ var Hide = {
617
+ these : function() {
618
+ for (var i = 0; i < arguments.length; i++) {
619
+ try {
620
+ $(arguments[i]).hide();
621
+ } catch (e) {}
622
+ }
623
+ }
624
+ }
625
+
626
+ var Show = {
627
+ these : function() {
628
+ for (var i = 0; i < arguments.length; i++) {
629
+ try {
630
+ $(arguments[i]).show();
631
+ } catch (e) {}
632
+ }
633
+ }
634
+ }
635
+
636
+ // Layout namespace
637
+ var Layout = {};
638
+
639
+ // This class allows dom objects to stretch with the browser
640
+ // (for when a good, cross-browser, CSS approach can't be found)
641
+ Layout.LiquidBase = Class.create();
642
+ // Base class for all Liquid* layouts...
643
+ Object.extend(Layout.LiquidBase.prototype, {
644
+ enabled: true,
645
+ elems: [],
646
+ offset: null,
647
+ // Constructor is (offset, **array_of_elements)
648
+ initialize: function() {
649
+ args = $A(arguments)
650
+ this.offset = args.shift();
651
+ this.elems = args.select( function(elem){ return ($(elem) != null) } );
652
+ if( this.elems.length > 0 ) {
653
+ this.on_resize(); // Initial size
654
+ Event.observe(window, 'resize', this.on_resize.bind(this) );
655
+ Event.observe(window, 'load', this.on_resize.bind(this) );
656
+ }
657
+ },
658
+ resize_in: function(timeout) {
659
+ setTimeout( this.on_resize.bind(this), timeout );
660
+ },
661
+ on_resize: function() {
662
+ // Need to override!
663
+ alert('Override on_resize, please!');
664
+ }
665
+ });
666
+
667
+
668
+ // Liquid vertical layout
669
+ Layout.LiquidVert = Class.create();
670
+ Object.extend(Layout.LiquidVert.prototype, Object.extend(Layout.LiquidBase.prototype, {
671
+ on_resize: function() {
672
+ if( this.offset != null && this.enabled ) {
673
+ var new_height = ((window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight) - this.offset) +"px";
674
+ this.elems.each(function(e){ $(e).style.height = new_height; })
675
+ }
676
+ }
677
+ }) );
678
+
679
+
680
+ // Liquid horizontal layout
681
+ Layout.LiquidHoriz = Class.create();
682
+ Object.extend(Layout.LiquidHoriz.prototype, Object.extend(Layout.LiquidBase.prototype, {
683
+ on_resize: function() {
684
+ if( this.offset != null && this.enabled ) {
685
+ var new_width = ((window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth) - this.offset) +"px";
686
+ this.elems.each( function(e){ $(e).style.width = new_width; })
687
+ }
688
+ }
689
+ }) );
690
+
691
+ // String Extensions... Yes, these are from Radiant! ;-)
692
+ Object.extend(String.prototype, {
693
+ upcase: function() {
694
+ return this.toUpperCase();
695
+ },
696
+ downcase: function() {
697
+ return this.toLowerCase();
698
+ },
699
+ strip: function() {
700
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
701
+ },
702
+ toInteger: function() {
703
+ return parseInt(this);
704
+ },
705
+ toSlug: function() {
706
+ // M@: Modified from Radiant's version, removes multple --'s next to each other
707
+ // This is the same RegExp as the one on the page model...
708
+ return this.strip().downcase().replace(/[^-a-z0-9~\s\.:;+=_]/g, '').replace(/[\s\.:;=_+]+/g, '-').replace(/[\-]{2,}/g, '-');
709
+ }
710
+ });
711
+
712
+ // Run a spinner when an AJAX request in running...
713
+ var ComatoseAJAXSpinner = {
714
+ busy : function () {
715
+ if($('spinner') && Ajax.activeRequestCount > 0) {
716
+ Effect.Appear('spinner',{duration:0.5,queue:'end'});
717
+ }
718
+ },
719
+
720
+ notBusy: function() {
721
+ if($('spinner') && Ajax.activeRequestCount == 0) {
722
+ Effect.Fade('spinner',{duration:0.5,queue:'end'});
723
+ }
724
+ }
725
+ }
726
+ // Register it with Prototype...
727
+ Ajax.Responders.register({
728
+ onCreate: ComatoseAJAXSpinner.busy,
729
+ onComplete: ComatoseAJAXSpinner.notBusy
730
+ });
731
+
732
+
733
+ if(!window.Cookie)
734
+ (function (){
735
+ // From Mephisto!
736
+ window.Cookie = {
737
+ version: '0.7',
738
+ cookies: {},
739
+ _each: function(iterator) {
740
+ $H(this.cookies).each(iterator);
741
+ },
742
+
743
+ getAll: function() {
744
+ this.cookies = {};
745
+ $A(document.cookie.split('; ')).each(function(cookie) {
746
+ var seperator = cookie.indexOf('=');
747
+ this.cookies[cookie.substring(0, seperator)] =
748
+ unescape(cookie.substring(seperator + 1, cookie.length));
749
+ }.bind(this));
750
+ return this.cookies;
751
+ },
752
+
753
+ read: function() {
754
+ var cookies = $A(arguments), results = [];
755
+ this.getAll();
756
+ cookies.each(function(name) {
757
+ if (this.cookies[name]) results.push(this.cookies[name]);
758
+ else results.push(null);
759
+ }.bind(this));
760
+ return results.length > 1 ? results : results[0];
761
+ },
762
+
763
+ write: function(cookies, options) {
764
+ if (cookies.constructor == Object && cookies.name) cookies = [cookies];
765
+ if (cookies.constructor == Array) {
766
+ $A(cookies).each(function(cookie) {
767
+ this._write(cookie.name, cookie.value, cookie.expires,
768
+ cookie.path, cookie.domain);
769
+ }.bind(this));
770
+ } else {
771
+ options = options || {expires: false, path: '', domain: ''};
772
+ for (name in cookies){
773
+ this._write(name, cookies[name],
774
+ options.expires, options.path, options.domain);
775
+ }
776
+ }
777
+ },
778
+
779
+ _write: function(name, value, expires, path, domain) {
780
+ if (name.indexOf('=') != -1) return;
781
+ var cookieString = name + '=' + escape(value);
782
+ if (expires) cookieString += '; expires=' + expires.toGMTString();
783
+ if (path) cookieString += '; path=' + path;
784
+ if (domain) cookieString += '; domain=' + domain;
785
+ document.cookie = cookieString;
786
+ },
787
+
788
+ erase: function(cookies) {
789
+ var cookiesToErase = {};
790
+ $A(arguments).each(function(cookie) {
791
+ cookiesToErase[cookie] = '';
792
+ });
793
+
794
+ this.write(cookiesToErase, {expires: (new Date((new Date()).getTime() - 1e11))});
795
+ this.getAll();
796
+ },
797
+
798
+ eraseAll: function() {
799
+ this.erase.apply(this, $H(this.getAll()).keys());
800
+ }
801
+ };
802
+
803
+ Object.extend(Cookie, {
804
+ get: Cookie.read,
805
+ set: Cookie.write,
806
+
807
+ add: Cookie.read,
808
+ remove: Cookie.erase,
809
+ removeAll: Cookie.eraseAll,
810
+
811
+ wipe: Cookie.erase,
812
+ wipeAll: Cookie.eraseAll,
813
+ destroy: Cookie.erase,
814
+ destroyAll: Cookie.eraseAll
815
+ });
816
+ })();
817
+
818
+ </script>
819
+ </head>
820
+ <body>
821
+ <div id="page-container">
822
+ <div id="header">
823
+ <h1><%= link_to Comatose.config.admin_title, :controller=>controller.controller_name, :action=>'index' %></h1>
824
+ <div id="flash">
825
+ <span id="flash-content"><%= flash[:notice] %></span>
826
+ </div>
827
+ <h5><%= Comatose.config.admin_sub_title %></h5>
828
+ </div>
829
+ <div id="content">
830
+ <%= yield %>
831
+ </div>
832
+ <div id="footer">
833
+ Powered by <a href="http://comatose.rubyforge.org" target="_new_window">Comatose <%= Comatose::VERSION_STRING %></a>, created by <a href="http://www.mattmccray.com" target="_new_window">M@ McCray</a>.
834
+ </div>
835
+ </div>
836
+ </body>
837
+ </html>