grat 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. data/README.rdoc +3 -3
  2. data/VERSION +1 -1
  3. data/grat.gemspec +21 -3
  4. data/lib/grat.rb +66 -3
  5. data/lib/grat/content.rb +18 -1
  6. data/public/gratfiles/application.js +24 -22
  7. data/public/gratfiles/custom.css +59 -2
  8. data/public/gratfiles/custom2.css +280 -0
  9. data/public/gratfiles/images/ui-bg_diagonals-thick_18_b81900_40x40.png +0 -0
  10. data/public/gratfiles/images/ui-bg_diagonals-thick_20_666666_40x40.png +0 -0
  11. data/public/gratfiles/images/ui-bg_flat_10_000000_40x100.png +0 -0
  12. data/public/gratfiles/images/ui-bg_glass_100_f6f6f6_1x400.png +0 -0
  13. data/public/gratfiles/images/ui-bg_glass_100_fdf5ce_1x400.png +0 -0
  14. data/public/gratfiles/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  15. data/public/gratfiles/images/ui-bg_gloss-wave_35_f6a828_500x100.png +0 -0
  16. data/public/gratfiles/images/ui-bg_highlight-soft_100_eeeeee_1x100.png +0 -0
  17. data/public/gratfiles/images/ui-bg_highlight-soft_75_ffe45c_1x100.png +0 -0
  18. data/public/gratfiles/images/ui-icons_222222_256x240.png +0 -0
  19. data/public/gratfiles/images/ui-icons_228ef1_256x240.png +0 -0
  20. data/public/gratfiles/images/ui-icons_ef8c08_256x240.png +0 -0
  21. data/public/gratfiles/images/ui-icons_ffd27a_256x240.png +0 -0
  22. data/public/gratfiles/images/ui-icons_ffffff_256x240.png +0 -0
  23. data/public/gratfiles/jquery-combined.min.js +289 -2
  24. data/public/gratfiles/jquery-ui.css +406 -0
  25. data/public/gratfiles/reset.css +52 -0
  26. data/views/content_form.haml +48 -48
  27. data/views/import_form.haml +1 -3
  28. data/views/layout.haml +15 -6
  29. data/views/list.haml +19 -18
  30. data/views/page_list.haml +19 -0
  31. metadata +20 -2
@@ -25,13 +25,13 @@ Use it like so:
25
25
  4. rackup (or passenger, if you know how)
26
26
 
27
27
  5. http://localhost:9292/__admin/edit/mypage edits a page that will be available at http://localhost:9292/mypage
28
- 6. http://localhost:9292/__admin/all for a list of all pages
28
+ 6. http://localhost:9292/__admin/ for a list of all pages
29
29
  7. http://localhost:9292/__admin/export to get a json dump of all pages
30
30
  8. http://localhost:9292/__admin/import to import one of those dumps
31
31
 
32
32
  9. Protect from writes by strangers with Rack::If
33
33
  # http://github.com/samsm/Rackif
34
-
34
+
35
35
  use Rack::If, {:method => /(POST)|(PUT)|(DELETE)/, :path => /__admin/}, :any do
36
36
  use Rack::Auth::Basic, "Grat protected" do |username, password|
37
37
  'secret' == password
@@ -40,7 +40,7 @@ Use it like so:
40
40
 
41
41
 
42
42
  == Note on Patches/Pull Requests
43
-
43
+
44
44
  * Fork the project.
45
45
  * Make your feature addition or bug fix.
46
46
  * Add tests for it. This is important so I don't break it in a
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.4.0
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{grat}
8
- s.version = "0.3.1"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Sam Schenkman-Moore"]
12
- s.date = %q{2010-01-12}
12
+ s.date = %q{2010-01-17}
13
13
  s.description = %q{Basic interface for making webpages with Haml and Erb. Supports nested templates.}
14
14
  s.email = %q{samsm@samsm.com}
15
15
  s.extra_rdoc_files = [
@@ -38,6 +38,7 @@ Gem::Specification.new do |s|
38
38
  "lib/grat/system.rb",
39
39
  "public/gratfiles/application.js",
40
40
  "public/gratfiles/custom.css",
41
+ "public/gratfiles/custom2.css",
41
42
  "public/gratfiles/einars-js-beautify/HTML-Beautify.js",
42
43
  "public/gratfiles/einars-js-beautify/beautify-cl.js",
43
44
  "public/gratfiles/einars-js-beautify/beautify-tests.js",
@@ -52,7 +53,22 @@ Gem::Specification.new do |s|
52
53
  "public/gratfiles/einars-js-beautify/unmaintained/opera-userscript/make_opera_userscript.sh",
53
54
  "public/gratfiles/einars-js-beautify/unmaintained/opera-userscript/opera_userscript.js",
54
55
  "public/gratfiles/favicon.ico",
56
+ "public/gratfiles/images/ui-bg_diagonals-thick_18_b81900_40x40.png",
57
+ "public/gratfiles/images/ui-bg_diagonals-thick_20_666666_40x40.png",
58
+ "public/gratfiles/images/ui-bg_flat_10_000000_40x100.png",
59
+ "public/gratfiles/images/ui-bg_glass_100_f6f6f6_1x400.png",
60
+ "public/gratfiles/images/ui-bg_glass_100_fdf5ce_1x400.png",
61
+ "public/gratfiles/images/ui-bg_glass_65_ffffff_1x400.png",
62
+ "public/gratfiles/images/ui-bg_gloss-wave_35_f6a828_500x100.png",
63
+ "public/gratfiles/images/ui-bg_highlight-soft_100_eeeeee_1x100.png",
64
+ "public/gratfiles/images/ui-bg_highlight-soft_75_ffe45c_1x100.png",
65
+ "public/gratfiles/images/ui-icons_222222_256x240.png",
66
+ "public/gratfiles/images/ui-icons_228ef1_256x240.png",
67
+ "public/gratfiles/images/ui-icons_ef8c08_256x240.png",
68
+ "public/gratfiles/images/ui-icons_ffd27a_256x240.png",
69
+ "public/gratfiles/images/ui-icons_ffffff_256x240.png",
55
70
  "public/gratfiles/jquery-combined.min.js",
71
+ "public/gratfiles/jquery-ui.css",
56
72
  "public/gratfiles/js-beautifier.min.js",
57
73
  "public/gratfiles/oocss.min.css",
58
74
  "public/gratfiles/oocss/content.css",
@@ -66,6 +82,7 @@ Gem::Specification.new do |s|
66
82
  "public/gratfiles/oocss/talk_skins.css",
67
83
  "public/gratfiles/oocss/template.css",
68
84
  "public/gratfiles/oocss/template_debug.css",
85
+ "public/gratfiles/reset.css",
69
86
  "views/content_form.haml",
70
87
  "views/css/_content.sass",
71
88
  "views/css/_custom.sass",
@@ -81,7 +98,8 @@ Gem::Specification.new do |s|
81
98
  "views/import_form.haml",
82
99
  "views/layout.haml",
83
100
  "views/list.haml",
84
- "views/missing.haml"
101
+ "views/missing.haml",
102
+ "views/page_list.haml"
85
103
  ]
86
104
  s.homepage = %q{http://github.com/samsm/grat}
87
105
  s.rdoc_options = ["--charset=UTF-8"]
@@ -19,8 +19,8 @@ class Grat::Application < Sinatra::Base
19
19
  file_data
20
20
  end
21
21
 
22
- get '/__admin/all' do
23
- @pages = model.all
22
+ get '/__admin/' do
23
+ pages
24
24
  @templates = templates
25
25
  haml :list
26
26
  end
@@ -39,7 +39,7 @@ class Grat::Application < Sinatra::Base
39
39
  post '/__admin/import' do
40
40
  json_text = file_import_text || params[:import][:text]
41
41
  @import_results = import(json_text, params[:import][:strategy])
42
- redirect '/__admin/all'
42
+ redirect '/__admin/'
43
43
  end
44
44
 
45
45
  # Rather inefficient at present.
@@ -77,6 +77,7 @@ class Grat::Application < Sinatra::Base
77
77
  end
78
78
 
79
79
  get '/__admin/edit/*' do
80
+ @page_heading_text = "Editing: <a href='#{url}'>#{url}</a>"
80
81
  haml :content_form
81
82
  end
82
83
 
@@ -185,6 +186,68 @@ class Grat::Application < Sinatra::Base
185
186
  def form_nest(name)
186
187
  "content[#{name}]"
187
188
  end
189
+
190
+ # The next few methods build the tree for the file list
191
+ # This can likely be greatly simpified and more efficient.
192
+ def peel(pages, start)
193
+ pages.each do |page|
194
+ if under?(start,page)
195
+ if immediate_child?(start,page)
196
+ start.children << page
197
+ else
198
+ # Skip if already done
199
+ unless start.children.detect {|ec| ec.url == next_dir(start,page) }
200
+ ec = Grat::EmptyContent.new(next_dir(start,page))
201
+ peel(pages,ec)
202
+ unless start.children.detect {|c| c.url == ec.url }
203
+ start.children << ec
204
+ end
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
210
+
211
+ def under?(start,other)
212
+ other.url.index(start.url) == 0 && other.url != start.url
213
+ end
214
+
215
+ def next_dir(start,other)
216
+ other.url.match(/#{start.url}?[^\/]+\//)[0]
217
+ end
218
+
219
+ def immediate_child?(start,other)
220
+ !url_difference(start,other).index('/')
221
+ end
222
+
223
+ def url_difference(start,other)
224
+ other.url.sub(/#{start.url}/, '')
225
+ end
226
+
227
+ def recursive_url_list(page)
228
+ puts page.url
229
+ page.children.each { |c| recursive_url_list(c) }
230
+ end
231
+
232
+ # only works if there's a url '/'
233
+ def nested_root
234
+ sorted_pages = pages.sort_by {|p| p.url }
235
+ first = sorted_pages.first
236
+ peel(sorted_pages, first)
237
+ first
238
+ end
239
+
240
+ def pages
241
+ @pages ||= model.all
242
+ end
243
+
244
+ def nested_root_list
245
+ to_list([nested_root])
246
+ end
247
+
248
+ def page_heading_text
249
+ @page_heading_text or 'Unnamed page.'
250
+ end
188
251
  end
189
252
 
190
253
  end
@@ -118,4 +118,21 @@ class Grat::Content
118
118
  def suggested_fields
119
119
  @suggested_fields or []
120
120
  end
121
- end
121
+
122
+ def children
123
+ @children ||= []
124
+ end
125
+
126
+ end
127
+
128
+ class Grat::EmptyContent
129
+ attr_accessor :url
130
+ def initialize(url)
131
+ self.url = url
132
+ end
133
+
134
+ def children
135
+ @children ||= []
136
+ end
137
+
138
+ end
@@ -1,6 +1,6 @@
1
1
  // once page is loaded ...
2
2
  $(document).ready(function(){
3
-
3
+
4
4
  // Collapse fields
5
5
  $('.collapsable').each(function() {
6
6
  parent_div = $(this);
@@ -19,7 +19,7 @@ $(document).ready(function(){
19
19
  parent_div.addClass('activeCollapse');
20
20
  }
21
21
  })
22
-
22
+
23
23
  // Add fields for selected template.
24
24
  $('.template select').change(function() {
25
25
  // if template has url
@@ -37,26 +37,26 @@ $(document).ready(function(){
37
37
  })
38
38
  }
39
39
  })
40
-
40
+
41
41
  // New field button + features
42
42
  $('a[href=#new_field]').click(function(){
43
-
43
+
44
44
  $('#new_fields').prepend("<div class='new_field'><p class='myEditableText sameaslabel'>Write the title here</p><input name='content[new_field]' value='' /></div>");
45
-
45
+
46
46
  // upon click make label editable and other junk associated with customizing the new field
47
47
  $('.myEditableText').click(function(){
48
48
  editable = $(this);
49
-
49
+
50
50
  editable.attr('contentEditable',true);
51
51
  editable.addClass('editing'); // style for editing
52
52
  editable.focus(); // put cursor in element
53
-
53
+
54
54
  // this should only clear if default text is in there
55
55
  if (!editable[0].className.match(/edited/)) {
56
56
  editable.text(''); // clear text
57
57
  editable.addClass('edited')
58
58
  }
59
-
59
+
60
60
  // On focus of input, change name= to correspond to p sibling
61
61
  editable.parent().children().filter('input').focus(function() {
62
62
  input = $(this);
@@ -64,19 +64,19 @@ $(document).ready(function(){
64
64
  // need to sanitize key
65
65
  sanitized_key = key.replace(/[^a-zA-Z]/g,'_').toLowerCase().replace(/[^a-z]/,'').toLowerCase()
66
66
  new_name = 'content[' + sanitized_key + ']';
67
-
67
+
68
68
  input.attr('name',new_name);
69
69
  })
70
-
70
+
71
71
  // Move to input field on enter
72
72
  editable.keypress(function(event){
73
-
73
+
74
74
  // move to field input is cancelled if enter is pressed
75
75
  if (event.which == 13) {
76
-
76
+
77
77
  // Remove editing class -- should add edited class maybe
78
78
  editable.removeClass('editing');
79
-
79
+
80
80
  // forward to text input
81
81
  $(editable).parent().children().filter('input').focus();
82
82
  return false
@@ -84,28 +84,30 @@ $(document).ready(function(){
84
84
  return event.which
85
85
  }
86
86
  });
87
-
87
+
88
88
  editable.change(function() {
89
89
  console.log('blur');
90
90
  editable.removeClass('editing');
91
91
  })
92
-
92
+
93
93
  });
94
-
94
+
95
95
  // bind an event listener that will be called when
96
96
  // user saves changed content
97
97
  $('.editableText').change(function(){
98
98
  var newValue = $(this).html();
99
99
  });
100
-
101
-
102
-
100
+
101
+
102
+
103
103
  return false;
104
104
  })
105
-
105
+
106
106
  // Beautify default data textarea
107
107
  $('#default_content_vars').each(function() {
108
108
  this.innerHTML = js_beautify(this.innerHTML, {'indent_size':2});
109
- })
110
-
109
+ });
110
+
111
+ $('.tabs').tabs();
112
+
111
113
  });
@@ -1,4 +1,4 @@
1
- /* @override
1
+ /* @override
2
2
  http://localhost:9393/custom.css
3
3
  http://grat.local/css/custom.css
4
4
  http://localhost:9393/gratfiles/custom.css
@@ -80,4 +80,61 @@ a.collapse {
80
80
  }
81
81
  .expander, .collapser {
82
82
  margin-left: 1em;
83
- }
83
+ }
84
+
85
+ .pages {
86
+ background-color: #573515;
87
+ color: whitesmoke;
88
+ border-bottom: solid black;
89
+ -webkit-box-shadow: 0 1px 10px rgba(0,0,0,.1);
90
+ -moz-box-shadow: 0 1px 10px rgba(0,0,0,.1);
91
+ box-shadow: 0 1px 10px rgba(0,0,0,.1);
92
+ font-weight: normal;
93
+ font-style: normal;
94
+ font-family: "Lucida Grande", Lucida, Verdana, sans-serif;
95
+ padding: 1em;
96
+ }
97
+
98
+ .pages a.emptycontent {
99
+ color: #b6ff48;
100
+ }
101
+ .pages .missing_message {
102
+ font-size: .75em;
103
+ visibility: hidden;
104
+ }
105
+
106
+ .pages a {
107
+ color: white;
108
+ }
109
+
110
+ .pages li {
111
+ margin: 0;
112
+ margin-bottom: 0.5em;
113
+ padding-left: 1em;
114
+ border-top: solid 1px rgba(250,250,250,.3);
115
+ }
116
+ .pages ol {
117
+ padding: 0;
118
+ padding-top: 0.25em;
119
+ padding-bottom: 0;
120
+ padding-left: 0;
121
+ }
122
+
123
+ .tags, .template, .created {
124
+ margin-left: 2em;
125
+ float: right;
126
+ }
127
+
128
+
129
+ /*.pages ol:before {
130
+ content: "collapse";
131
+ }*/
132
+
133
+
134
+
135
+ /*.pages li:nth-child(odd) {
136
+ background-color: #86B486;
137
+ }
138
+ .pages li:nth-child(even) {
139
+ background-color: red;
140
+ }*/
@@ -0,0 +1,280 @@
1
+ /* @override http://localhost:9393/gratfiles/custom2.css */
2
+
3
+ /*
4
+ rgba(114,123,127,1) // medium grey
5
+ rgba(204,234,234,1) // very light blue
6
+ rgba(122,117,86,1) // medium brown
7
+ rgba(46,33,37,1) // dark brown
8
+ rgba(68,202,204,1) // bright blue
9
+
10
+
11
+ rgba(255,255,255,1) // white
12
+ rgba(0,0,0,1) // black
13
+ */
14
+ body {
15
+ font: normal 62.5% helvetica, arial, sans-serif;
16
+ background-color: rgba(204,234,234,1);
17
+ color: rgba(0,0,0,.8);
18
+ }
19
+
20
+ .container {
21
+ /*margin-left: 10em;*/
22
+ }
23
+
24
+ .mod:after {
25
+ content: ".";
26
+ display: block;
27
+ height: 0;
28
+ clear: both;
29
+ visibility: hidden;
30
+ }
31
+
32
+
33
+ .masthead {
34
+ background-color: rgba(46,33,37,1);
35
+ padding: 1em;
36
+ height: 4em;
37
+ }
38
+
39
+ .masthead h1, .masthead h2 {
40
+ text-shadow: 1px 1px 1px rgba(68,202,204,.4);
41
+ color: rgba(204,234,234,1);
42
+ }
43
+
44
+ .masthead h1 {
45
+ font-size: 4em;
46
+ float: left;
47
+ }
48
+ .masthead h2 {
49
+ margin-top: 1em;
50
+ font-size: 2em;
51
+ float: right;
52
+ }
53
+ .masthead h2 a, .masthead h1 a {
54
+ color: inherit;
55
+ }
56
+ .masthead h1 a {
57
+ text-decoration: none;
58
+ }
59
+
60
+ .panel {
61
+ margin: 0 auto;
62
+ width: 30em;
63
+ background-color: rgba(255,255,255,1);
64
+ padding: 1em;
65
+ padding-top: 2em;
66
+ float: left;
67
+
68
+ border-right: 2px solid rgba(114,123,127,1);
69
+ margin-bottom: 2em;
70
+ -webkit-box-shadow: 0 1px 5px rgba(114,123,127,.5);
71
+ -moz-box-shadow: 0 1px 5px rgba(114,123,127,.5);
72
+ box-shadow: 0 1px 5px rgba(114,123,127,.5);
73
+
74
+ margin-right: 2.2em;
75
+
76
+ /* Make column go to bottom of screen */
77
+ margin-bottom: -1000px;
78
+ padding-bottom: 1000px;
79
+ }
80
+ .panel h2 {
81
+ font-size: 2em;
82
+ color: rgba(46,33,37,1);
83
+ text-shadow: 2px 2px 2px rgba(114,123,127,.4);
84
+ }
85
+
86
+ .pages {
87
+ float: left;
88
+ }
89
+ .pages li {
90
+ margin-left: 1em;
91
+ margin-top: 1em;
92
+ }
93
+
94
+ /* form stuffs */
95
+ .container {
96
+ margin-top: 1em;
97
+ margin-left: 17em;
98
+ width: 40em;
99
+ font-size: 2em;
100
+ }
101
+
102
+ input, textarea, label, .sameaslabel {
103
+ display: block;
104
+ width: 99%;
105
+ }
106
+
107
+ .sameaslabel, label {
108
+ margin-top: .5em;
109
+ }
110
+
111
+ textarea {
112
+ font-family: "Courier New", Courier, mono;
113
+ font-weight: bold;
114
+ height: 13em;
115
+ }
116
+ .sameaslabel {
117
+ padding-left: 0; // no padding like p has
118
+ }
119
+
120
+ .submit input {
121
+ width: auto;
122
+ }
123
+
124
+
125
+ p.editing {
126
+ min-height: 1em;
127
+ background-color: yellow;
128
+ }
129
+
130
+ input[type=file] {
131
+ padding-top: .5em;
132
+ font-size: 1.5em;
133
+ }
134
+
135
+ input[type=radio] {
136
+ width: 1em;
137
+ float: left;
138
+ margin-top: .25em;
139
+ }
140
+
141
+ input {
142
+ width: 33%;
143
+ }
144
+ input[type=submit] {
145
+ width: auto;
146
+ display: inline;
147
+ }
148
+
149
+ a.collapse {
150
+ font-size: .5em;
151
+ font-weight: normal;
152
+ }
153
+
154
+ .activeCollapse textarea {
155
+ display: none;
156
+ }
157
+
158
+ .activeCollapse .collapser {
159
+ display:none;
160
+ }
161
+
162
+ a.button {
163
+ color: rgba(68,202,204,1);
164
+ padding: .5em;
165
+ -moz-border-radius: 1em;
166
+ -webkit-border-radius: 1em;
167
+ border-radius: 1em;
168
+
169
+ background-color: rgba(46,33,37,1);
170
+ text-decoration: none;
171
+
172
+ -webkit-box-shadow: 0 1px 5px rgba(122,117,86,.5);
173
+ -moz-box-shadow: 0 1px 5px rgba(122,117,86,.5);
174
+ box-shadow: 0 1px 5px rgba(122,117,86,.5);
175
+ }
176
+ #new_fields p {
177
+ margin-top: 1em;
178
+ }
179
+ .expander {
180
+ display: none;
181
+ float: left;
182
+ }
183
+ .collapser {
184
+ float: right;
185
+ margin-top: -1.5em;
186
+ margin-right: 1em;
187
+ }
188
+ .activeCollapse .expander {
189
+ display: inline;
190
+ }
191
+ .expander, .collapser {
192
+ font-size: .65em;
193
+ font-weight: normal;
194
+ color: rgba(68,202,204,1);
195
+ text-decoration: none;
196
+ }
197
+
198
+ /* JQuery UI Tabs tweaks */
199
+ .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
200
+ .ui-tabs .ui-tabs-hide { display: none !important; }
201
+
202
+ .tabs ul.mod {
203
+ height: 1.8em;
204
+ }
205
+ .tabs li {
206
+ float: right;
207
+ background-color: rgba(46,33,37,1);
208
+ border: solid 2px rgba(46,33,37,1);
209
+ margin-right: .5em;
210
+ padding: 1em;
211
+ padding-bottom: .5em;
212
+
213
+ border-bottom: 0;
214
+ -moz-border-radius-topleft: 1.5em;
215
+ -webkit-border-top-left-radius: 1.5em;
216
+
217
+ -moz-border-radius-topright: .5em;
218
+ -webkit-border-top-right-radius: .5em;
219
+ /*border-radius: .5em;*/
220
+
221
+ font-size: .65em;
222
+
223
+
224
+ /*-webkit-box-shadow: 0 1px 5px rgba(114,123,127,.5);
225
+ -moz-box-shadow: 0 1px 5px rgba(114,123,127,.5);
226
+ box-shadow: 0 1px 5px rgba(114,123,127,.5);*/
227
+ /*letter-spacing: 0em;*/
228
+ }
229
+ .tabs li.ui-tabs-selected {
230
+ background-color: rgba(122,117,86,1);
231
+ border-bottom: solid 3px rgba(122,117,86,1);
232
+ }
233
+ .tabs li a {
234
+ color: rgba(68,202,204,1);
235
+ text-decoration: none;
236
+ }
237
+ #basics, #data, #history {
238
+ border-top: solid 2px;
239
+ border-left: dotted 1px rgba(46,33,37,.5);
240
+ border-right: dotted 1px rgba(46,33,37,.5);
241
+ background-color: rgba(122,117,86,1);
242
+ padding: 1em;
243
+ }
244
+
245
+ /* Radio buttons on import */
246
+ .import_replace_or_add input {
247
+ float: left;
248
+ margin-top: .5em;
249
+ display: inline;
250
+ }
251
+ .import_replace_or_add label {
252
+ margin-left: .5em;
253
+ display: inline;
254
+ }
255
+ .import_replace_or_add div {
256
+ margin-top: .5em;
257
+ }
258
+
259
+ .bulk-options li {
260
+ margin-bottom: 2em;
261
+ }
262
+ .new_page {
263
+ margin-bottom: .5em;
264
+ }
265
+
266
+
267
+
268
+
269
+
270
+
271
+
272
+
273
+
274
+
275
+
276
+
277
+
278
+
279
+
280
+