staugaard-comatose 2.0.2

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