darthapo-comatose 2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (92) hide show
  1. data/CHANGELOG +171 -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 +20 -0
  10. data/generators/comatose_migration/USAGE +15 -0
  11. data/generators/comatose_migration/comatose_migration_generator.rb +59 -0
  12. data/generators/comatose_migration/templates/migration.rb +35 -0
  13. data/generators/comatose_migration/templates/v4_upgrade.rb +15 -0
  14. data/generators/comatose_migration/templates/v6_upgrade.rb +23 -0
  15. data/generators/comatose_migration/templates/v7_upgrade.rb +22 -0
  16. data/init.rb +10 -0
  17. data/install.rb +16 -0
  18. data/lib/acts_as_versioned.rb +543 -0
  19. data/lib/comatose.rb +23 -0
  20. data/lib/comatose/comatose_drop.rb +79 -0
  21. data/lib/comatose/configuration.rb +68 -0
  22. data/lib/comatose/page_wrapper.rb +119 -0
  23. data/lib/comatose/processing_context.rb +69 -0
  24. data/lib/comatose/tasks/admin.rb +60 -0
  25. data/lib/comatose/tasks/data.rb +82 -0
  26. data/lib/comatose/tasks/setup.rb +52 -0
  27. data/lib/comatose/version.rb +4 -0
  28. data/lib/comatose_admin_controller.rb +348 -0
  29. data/lib/comatose_admin_helper.rb +37 -0
  30. data/lib/comatose_controller.rb +141 -0
  31. data/lib/comatose_helper.rb +3 -0
  32. data/lib/comatose_page.rb +141 -0
  33. data/lib/liquid.rb +52 -0
  34. data/lib/liquid/block.rb +96 -0
  35. data/lib/liquid/context.rb +190 -0
  36. data/lib/liquid/document.rb +17 -0
  37. data/lib/liquid/drop.rb +48 -0
  38. data/lib/liquid/errors.rb +7 -0
  39. data/lib/liquid/extensions.rb +53 -0
  40. data/lib/liquid/file_system.rb +62 -0
  41. data/lib/liquid/htmltags.rb +64 -0
  42. data/lib/liquid/standardfilters.rb +111 -0
  43. data/lib/liquid/standardtags.rb +399 -0
  44. data/lib/liquid/strainer.rb +42 -0
  45. data/lib/liquid/tag.rb +25 -0
  46. data/lib/liquid/template.rb +88 -0
  47. data/lib/liquid/variable.rb +39 -0
  48. data/lib/redcloth.rb +1129 -0
  49. data/lib/support/class_options.rb +36 -0
  50. data/lib/support/inline_rendering.rb +48 -0
  51. data/lib/support/route_mapper.rb +50 -0
  52. data/lib/text_filters.rb +138 -0
  53. data/lib/text_filters/markdown.rb +14 -0
  54. data/lib/text_filters/markdown_smartypants.rb +15 -0
  55. data/lib/text_filters/none.rb +8 -0
  56. data/lib/text_filters/rdoc.rb +13 -0
  57. data/lib/text_filters/simple.rb +8 -0
  58. data/lib/text_filters/textile.rb +15 -0
  59. data/rails/init.rb +12 -0
  60. data/resources/layouts/comatose_admin_template.html.erb +28 -0
  61. data/resources/public/images/collapsed.gif +0 -0
  62. data/resources/public/images/expanded.gif +0 -0
  63. data/resources/public/images/no-children.gif +0 -0
  64. data/resources/public/images/page.gif +0 -0
  65. data/resources/public/images/spinner.gif +0 -0
  66. data/resources/public/images/title-hover-bg.gif +0 -0
  67. data/resources/public/javascripts/comatose_admin.js +401 -0
  68. data/resources/public/stylesheets/comatose_admin.css +381 -0
  69. data/tasks/comatose.rake +9 -0
  70. data/test/behaviors.rb +106 -0
  71. data/test/fixtures/comatose_pages.yml +96 -0
  72. data/test/functional/comatose_admin_controller_test.rb +112 -0
  73. data/test/functional/comatose_controller_test.rb +44 -0
  74. data/test/javascripts/test.html +26 -0
  75. data/test/javascripts/test_runner.js +307 -0
  76. data/test/test_helper.rb +43 -0
  77. data/test/unit/class_options_test.rb +52 -0
  78. data/test/unit/comatose_page_test.rb +128 -0
  79. data/test/unit/processing_context_test.rb +108 -0
  80. data/test/unit/text_filters_test.rb +52 -0
  81. data/views/comatose_admin/_form.html.erb +96 -0
  82. data/views/comatose_admin/_page_list_item.html.erb +60 -0
  83. data/views/comatose_admin/delete.html.erb +18 -0
  84. data/views/comatose_admin/edit.html.erb +5 -0
  85. data/views/comatose_admin/index.html.erb +18 -0
  86. data/views/comatose_admin/new.html.erb +5 -0
  87. data/views/comatose_admin/reorder.html.erb +30 -0
  88. data/views/comatose_admin/versions.html.erb +40 -0
  89. data/views/layouts/comatose_admin.html.erb +814 -0
  90. data/views/layouts/comatose_admin_customize.html.erb +28 -0
  91. data/views/layouts/comatose_content.html.erb +17 -0
  92. metadata +157 -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>