slices 1.0.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +8 -0
  3. data/README.md +85 -17
  4. data/app/assets/images/slices/i18n.png +0 -0
  5. data/app/assets/images/slices/icon_collapse.png +0 -0
  6. data/app/assets/javascripts/slices/app/helpers/apply_defaults.js +9 -0
  7. data/app/assets/javascripts/slices/app/helpers/composer.js +2 -0
  8. data/app/assets/javascripts/slices/app/helpers/i18n.js +7 -0
  9. data/app/assets/javascripts/slices/app/helpers/markdown_cheat_sheet.js +50 -0
  10. data/app/assets/javascripts/slices/app/helpers/radio_field.js +21 -0
  11. data/app/assets/javascripts/slices/app/helpers/sitemap.js +82 -1
  12. data/app/assets/javascripts/slices/app/helpers/uploader.js +1 -1
  13. data/app/assets/javascripts/slices/app/helpers/url_field.js +17 -0
  14. data/app/assets/javascripts/slices/app/slices.js +14 -11
  15. data/app/assets/javascripts/slices/app/views/composer_view.js +16 -0
  16. data/app/assets/javascripts/slices/app/views/radio_field_view.js +67 -0
  17. data/app/assets/javascripts/slices/app/views/token_field_view.js +81 -24
  18. data/app/assets/javascripts/slices/app/views/url_field_view.js +44 -0
  19. data/app/assets/javascripts/slices/slices.js +1 -0
  20. data/app/assets/javascripts/slices/vendor/jquery.js +4 -2
  21. data/app/assets/stylesheets/slices/admin.css.erb +156 -31
  22. data/app/controllers/admin/admin_controller.rb +16 -1
  23. data/app/controllers/admin/assets_controller.rb +1 -1
  24. data/app/controllers/admin/entries_controller.rb +1 -1
  25. data/app/controllers/admin/pages_controller.rb +4 -13
  26. data/app/controllers/admin/site_maps_controller.rb +1 -2
  27. data/app/controllers/slices_controller.rb +12 -1
  28. data/app/helpers/admin/admin_helper.rb +8 -0
  29. data/app/helpers/admin/site_maps_helper.rb +41 -6
  30. data/app/helpers/navigation_helper.rb +8 -3
  31. data/app/helpers/pages_helper.rb +2 -2
  32. data/app/helpers/snippets_helper.rb +26 -0
  33. data/app/models/admin.rb +2 -3
  34. data/app/models/asset.rb +9 -20
  35. data/app/models/attachment.rb +10 -1
  36. data/app/models/page.rb +45 -34
  37. data/app/models/site_map.rb +1 -2
  38. data/app/models/slice.rb +46 -1
  39. data/app/models/snippet.rb +13 -4
  40. data/app/presenters/page_presenter.rb +8 -13
  41. data/app/views/admin/auth/sessions/_form.html.erb +3 -0
  42. data/app/views/admin/pages/_fields.html.erb +1 -0
  43. data/app/views/admin/pages/_slices.html.erb +8 -4
  44. data/app/views/admin/pages/new.html.erb +5 -1
  45. data/app/views/admin/pages/show.html.erb +30 -14
  46. data/app/views/admin/site_maps/_page_actions.html.erb +2 -0
  47. data/app/views/admin/site_maps/_page_li.html.erb +18 -7
  48. data/app/views/admin/site_maps/_set_page_li.html.erb +5 -5
  49. data/app/views/layouts/admin.html.erb +0 -17
  50. data/config/routes.rb +13 -16
  51. data/lib/generators/slice/templates/presenter.rb +11 -12
  52. data/lib/generators/slice/templates/set.html.erb +2 -2
  53. data/lib/generators/slices/install_generator.rb +13 -3
  54. data/lib/generators/slices/templates/slices.rb +3 -4
  55. data/lib/mongo_search.rb +1 -1
  56. data/lib/slices.rb +2 -9
  57. data/lib/slices/asset/maker.rb +2 -3
  58. data/lib/slices/available_slices.rb +8 -1
  59. data/lib/slices/config.rb +49 -8
  60. data/lib/slices/engine.rb +0 -4
  61. data/lib/slices/has_attachments.rb +25 -37
  62. data/lib/slices/has_slices.rb +15 -8
  63. data/lib/slices/localized_fields.rb +9 -0
  64. data/lib/slices/page_as_json.rb +7 -1
  65. data/lib/slices/renderer.rb +2 -2
  66. data/lib/slices/tree.rb +12 -3
  67. data/lib/slices/version.rb +1 -1
  68. data/lib/tasks/db.rake +6 -10
  69. data/lib/tasks/seeds.rake +1 -1
  70. data/public/slices/templates/page_main.hbs +1 -1
  71. data/public/slices/templates/page_meta.hbs +2 -2
  72. metadata +56 -84
  73. data/app/views/admin/shared/_custom_links.html.erb +0 -1
  74. data/app/views/admin/shared/_custom_navigation.html.erb +0 -1
  75. data/app/views/layouts/slices/application.html.erb +0 -14
  76. data/lib/ext/file_store_cache.rb +0 -18
  77. data/lib/generators/slices/templates/mongoid.yml +0 -12
  78. data/lib/generators/templates/slices.rb +0 -209
  79. data/lib/rack_utf8_fix.rb +0 -10
  80. data/lib/set_link_renderer.rb +0 -31
  81. data/lib/slices/i18n.rb +0 -6
  82. data/lib/slices/i18n/backend.rb +0 -32
  83. data/lib/slices/will_paginate_mongoid.rb +0 -45
  84. data/lib/standard_tree.rb +0 -193
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0b50a602b55d804ce6e82fd30ff4caeeae4e218f
4
- data.tar.gz: 4a4788c7dcbe27ae76972168c36bcf74672b23d0
3
+ metadata.gz: 7351b77e31a685b3a9b8caf5f1591815408bd4e2
4
+ data.tar.gz: e1373f1063e41190ea32c92c4367de45b687e3a8
5
5
  SHA512:
6
- metadata.gz: bcc62dbc628c164bb9e5939f1d7852014c91579b31fa590d013d3c80d149aa95ddc7e2f6ce0622932fbaee05d8645e13980c7fd899499d6b396b1850c3812f28
7
- data.tar.gz: f48be52b0e4b7732ae5d809985aaf4994dd06f3b9e1de30cc737148e40dc6e0cb83fc19ee2232e8183b20260df002067b46252faef44374eb1f122615f4b84e5
6
+ metadata.gz: 86ef317f478a14a86267f71ef732ab81014241c83765dd13be39758eadc4398b2f65cb35a70b4f72dd8289c9b93cfbd6683e55c7c70a84bfa9e5e202a2157124
7
+ data.tar.gz: 3bf5b78441a9a342980297657fbfaab284216c2450345e7b0999efda1b245394fcf8de3a3c1d1bef60014476bf25f60f92a0dacbc9b5181493205dc318abfa18
data/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ # 2.0.0 / 2016-01-15
2
+
3
+ * Rails I18n support
4
+ * Refactor snippets to not piggy back on I18n
5
+ * Upgrade to mongoid v3.1
6
+ * Ensure (soft-)destroying an asset removes it from all pages/slices [#39](https://github.com/withassociates/slices/pull/39)
7
+ * Drop support for ruby 1.9
8
+
1
9
  # 1.0.5 / 2014-08-21
2
10
 
3
11
  * Add confirmation when deleting set entries
data/README.md CHANGED
@@ -2,35 +2,103 @@
2
2
 
3
3
  In-house CMS of [With Associates](http://withassociates.com/).
4
4
 
5
- ## Starting a new Slices project
5
+ [![Travis CI](https://api.travis-ci.org/withassociates/slices.png)](https://travis-ci.org/withassociates/slices)
6
+ [![Code Climate](https://codeclimate.com/github/withassociates/slices.png)](https://codeclimate.com/github/withassociates/slices)
7
+ [![Gemnasium](https://gemnasium.com/withassociates/slices.png)](https://gemnasium.com/withassociates/slices)
6
8
 
7
- Slices requires Ruby, MongoDB and ImageMagick. If you don't have them installed, follow this [guide](https://github.com/withassociates/slices/wiki/Installation.md) before beginning.
9
+ ## Getting Started
8
10
 
9
- Now we're ready to create the Slices project:
11
+ ### Prerequisites
10
12
 
11
- $ cd ~/Projects
12
- $ rails _3.2.16_ new mywebsite -O
13
- $ cd ~/Projects/mywebsite
13
+ Slices requires [Ruby](https://ruby-lang.org), [MongoDB](http://mongodb.org),
14
+ and [ImageMagick](http://imagemagick.org).
14
15
 
15
- Add 'slices' to the Gemfile of your new project:
16
+ We suggest installing Ruby using [ruby-install](https://github.com/postmodern/ruby-install):
16
17
 
17
- gem 'slices'
18
+ ```sh
19
+ $ ruby-install --latest ruby
20
+ ```
18
21
 
19
- Run `rails generate slices:install` in the terminal and follow the instructions.
22
+ Install MongoDB and ImageMagick with [Homebrew](http://brew.sh):
20
23
 
21
- If you intend to deploy your Slices app to Heroku, run `rails generate slices:install --heroku` to make life easier.
24
+ ```sh
25
+ $ brew install mongodb ImageMagick # this can take a while
26
+ ```
22
27
 
23
- You're ready to go! Run `rails server` and visit http://localhost:3000/admin to begin using Slices.
28
+ ### Generating a Slices Project
24
29
 
25
- The next step is to create some [slices](https://github.com/withassociates/slices/wiki/Creating-Slices) - there are more guides in the [Wiki](https://github.com/withassociates/slices/wiki).
30
+ We'll need to create a Rails project:
26
31
 
27
- ## Code Status
32
+ ```sh
33
+ $ gem install rails -v 3.2.22
34
+ $ rails _3.2.22_ new mywebsite -JOT
35
+ $ cd mywebsite
36
+ ```
28
37
 
29
- [![Travis CI ](https://api.travis-ci.org/withassociates/slices.png) ](https://travis-ci.org/withassociates/slices)
30
- [![Code Climate](https://codeclimate.com/github/withassociates/slices.png) ](https://codeclimate.com/github/withassociates/slices)
31
- [![Gemnasium ](https://gemnasium.com/withassociates/slices.png) ](https://gemnasium.com/withassociates/slices)
38
+ Add Slices to the project’s Gemfile:
39
+
40
+ ```ruby
41
+ gem 'slices', '~> 2.0.0'
42
+ ```
43
+
44
+ Run bundler:
45
+
46
+ ```sh
47
+ $ bundle install
48
+ ```
49
+
50
+ Run the generator and follow the instructions to configure Slices for the first time:
51
+
52
+ ```sh
53
+ $ rails generate slices:install
54
+ ```
55
+
56
+ At the end of this process we should have a new Slices project with a git
57
+ repository created, gems installed, database seeded and ready to run:
58
+
59
+ ```sh
60
+ $ rails server
61
+ ```
62
+
63
+ Visit `http://localhost:3000/admin` to begin using Slices.
64
+
65
+ ### Generating Slices
66
+
67
+ The quickest way to create a Slice is to use the generator. In this example
68
+ we're going to create a Slice called `title_body` with title and body fields.
69
+
70
+ ```shell
71
+ $ rails generate slice title_body title:string body:text
72
+ ```
73
+
74
+ The syntax is `field_name:field_type`.
75
+
76
+ This command will create a new folder called `title_body` within `apps/slices`,
77
+ containing the required Ruby file, the Handlebars templates for the Admin view,
78
+ and the HTML for the front-end.
79
+
80
+ #### Slice Field Types
81
+
82
+ ```
83
+ Field Type | Best for | HTML Control
84
+ -------------+------------------------+--------------------
85
+ string | Single lines of text | Text input
86
+ text | Multiple lines of text | Textarea
87
+ boolean | Settings | Checkbox input
88
+ date | Dates | Date input
89
+ datetime | Times | Datetime input
90
+ attachments | Files and images | Attachment composer
91
+ page | Links to other pages | Internal link field
92
+ ```
93
+
94
+ An example of a complicated Slice:
95
+
96
+ ```shell
97
+ $ rails generate slice carousel title:string gallery:attachments link:page
98
+ ```
32
99
 
33
100
  ## License
34
101
 
35
- Slices is released under the [MIT license](http://www.opensource.org/licenses/MIT). Copyright (c) 2014 With Associates.
102
+ Slices is released under the [MIT license](http://www.opensource.org/licenses/MIT).
36
103
 
104
+ Copyright (c) 2016 With Associates.
Binary file
@@ -0,0 +1,9 @@
1
+ // Applys default values to the context.
2
+ //
3
+ // Example:
4
+ //
5
+ // {{applyDefaults title="Hello world" text="Lorem ipsum dolor sit amet"}}
6
+ //
7
+ Handlebars.registerHelper('applyDefaults', function(options) {
8
+ _.defaults(this, options.hash);
9
+ });
@@ -17,6 +17,8 @@ Handlebars.registerHelper('composer', function(options) {
17
17
  var view = new slices.ComposerView({
18
18
  id : slices.fieldId(this, options.hash.field),
19
19
  value : this[options.hash.field],
20
+ min : options.hash.min,
21
+ max : options.hash.max,
20
22
  fields : options.fn,
21
23
  addLabel : options.hash.addLabel,
22
24
  autoAttach : true
@@ -0,0 +1,7 @@
1
+ Handlebars.registerHelper('ifI18nEnabled', function(options) {
2
+ if (slices.i18n) {
3
+ return options.fn(this);
4
+ } else {
5
+ return options.inverse(this);
6
+ }
7
+ });
@@ -0,0 +1,50 @@
1
+ // Adds a Markdown cheat sheet.
2
+ //
3
+ // Example:
4
+ //
5
+ // {{markdownCheatSheet}}
6
+ //
7
+ Handlebars.registerHelper('markdownCheatSheet', function() {
8
+ return new Handlebars.SafeString(
9
+ '<div class="markdown-cheat-sheet">' +
10
+ '<h4>Markdown Cheat Sheet</h4>' +
11
+ '<div class="columns">' +
12
+ '<div class="column">' +
13
+ '<code># This is an &lt;h1&gt;</code>' +
14
+ '<code>## This is an &lt;h2&gt;</code>' +
15
+ '<code>###### This is an &lt;h6&gt;</code>' +
16
+ '<code>*This text will be italic*</code>' +
17
+ '<code>**This text will be bold**</code>' +
18
+ '<code>*You **can** combine them*</code>' +
19
+ '<code>[A Link](http://example.com/)</code>' +
20
+ '<code>![An Image](http://example.com/example.jpg)</code>' +
21
+ '</div>' +
22
+ '<div class="column">' +
23
+ '<code>' +
24
+ '* An\n' +
25
+ '* Unordered\n' +
26
+ '* List' +
27
+ '</code>' +
28
+ '<code>' +
29
+ '1. An\n' +
30
+ '2. Ordered\n' +
31
+ '3. List\n' +
32
+ ' * With\n' +
33
+ ' * Sub\n' +
34
+ ' * List' +
35
+ '</code>' +
36
+ '<code>' +
37
+ 'The following is a blockquote:\n\n' +
38
+ '> Sed posuere consectetur est at lobortis. Aenean lacinia\n' +
39
+ '> bibendum nulla sed consectetur. Maecenas sed diam eget\n' +
40
+ '> risus varius blandit sit amet non magna.' +
41
+ '</code>' +
42
+ '</div>' +
43
+ '</div>' +
44
+ '</div>'
45
+ );
46
+ });
47
+
48
+ $(document).on('click', '.markdown-cheat-sheet h4', function() {
49
+ $(this).parent().toggleClass('display');
50
+ });
@@ -0,0 +1,21 @@
1
+ // Creates a radio field.
2
+ //
3
+ // Example:
4
+ //
5
+ // {{#radioField field="example"}}
6
+ // <input type="radio" value="one">
7
+ // <input type="radio" value="two">
8
+ // <input type="radio" value="three">
9
+ // {{/radioField}}
10
+ //
11
+ Handlebars.registerHelper('radioField', function(options) {
12
+ var view = new slices.RadioFieldView({
13
+ id : slices.fieldId(this, options.hash.field),
14
+ name : options.hash.field,
15
+ value : this[options.hash.field],
16
+ inner : options.fn,
17
+ autoAttach : true
18
+ });
19
+
20
+ return new Handlebars.SafeString(view.placeholder());
21
+ });
@@ -80,7 +80,7 @@ $(function () {
80
80
  contentType: 'application/json',
81
81
  dataType: 'json',
82
82
  success: function (data, statusText, xhr) {
83
- // TODO:
83
+ location.reload();
84
84
  },
85
85
  error: function (xhr, textStatus, errorThrown) {
86
86
  // TODO:
@@ -146,5 +146,86 @@ $(function () {
146
146
  return false;
147
147
  });
148
148
 
149
+ function loadLocalStorage() {
150
+ var ids = JSON.parse(localStorage.getItem('sitemap.hidden'));
151
+
152
+ $('.toggle-children').filter(function() {
153
+ var id = $(this).attr('href').substring(1);
154
+ return $.inArray(id, ids) >= 0;
155
+ }).each(function() {
156
+ toggleChildren(this, false, true);
157
+ });
158
+ }
159
+
160
+ function updateLocalStorage() {
161
+ var ids = $('.page-children.hidden').map(function() {
162
+ return $(this).attr('id');
163
+ }).toArray();
164
+
165
+ localStorage['sitemap.hidden'] = JSON.stringify(ids);
166
+ }
167
+
168
+ function toggleChildren(target, value, instant) {
169
+ var toggle = $(target),
170
+ selector = toggle.attr('href'),
171
+ element = $(selector);
172
+
173
+ if (value) {
174
+ if (instant) {
175
+ element.show();
176
+ } else {
177
+ element.slideDown('fast');
178
+ }
179
+
180
+ element.removeClass('hidden');
181
+ toggle.removeClass('active');
182
+ } else {
183
+ if (instant) {
184
+ element.hide();
185
+ } else {
186
+ element.slideUp('fast');
187
+ }
188
+
189
+ element.addClass('hidden');
190
+ toggle.addClass('active');
191
+ }
192
+
193
+ updateLocalStorage();
194
+ }
195
+
196
+ function showChildren() {
197
+ toggleChildren(this, true);
198
+ }
199
+
200
+ function hideChildren() {
201
+ toggleChildren(this, false);
202
+ }
203
+
204
+ $('.hide-all-children').click(function() {
205
+ $('.toggle-children').each(hideChildren);
206
+ });
207
+
208
+ $('.show-all-children').click(function() {
209
+ $('.page-children:hidden .page-children').show();
210
+ $('.toggle-children').each(showChildren);
211
+ });
212
+
213
+ $('.toggle-children').click(function(event) {
214
+ event.preventDefault();
215
+
216
+ var toggle = $(this),
217
+ selector = toggle.attr('href'),
218
+ element = $(selector);
219
+
220
+ element.slideToggle('fast').toggleClass('hidden');
221
+ toggle.toggleClass('active');
222
+ updateLocalStorage();
223
+ });
224
+
225
+ if ($('.page-children .page-children').size() == 0) {
226
+ $('.toggle-actions').hide();
227
+ }
228
+
229
+ loadLocalStorage();
149
230
  });
150
231
 
@@ -43,7 +43,7 @@ $.extend(slices.Uploader.prototype, Backbone.Events, {
43
43
  type : 'file',
44
44
  multiple : 'multiple',
45
45
  style : 'position: absolute; visibility: hidden'
46
- });
46
+ }).appendTo('body');
47
47
  },
48
48
 
49
49
  observeEvents: function() {
@@ -0,0 +1,17 @@
1
+ // Creates a URL field.
2
+ //
3
+ // Example:
4
+ //
5
+ // {{urlField field="example"}}
6
+ //
7
+ Handlebars.registerHelper('urlField', function(options) {
8
+ var view = new slices.UrlFieldView({
9
+ id : slices.fieldId(this, options.hash.field),
10
+ name : options.hash.field,
11
+ value : this[options.hash.field],
12
+ autoAttach : true
13
+ });
14
+
15
+ return new Handlebars.SafeString(view.placeholder());
16
+ });
17
+
@@ -51,17 +51,18 @@ var slices = {
51
51
 
52
52
  slices.availableContainers = settings.availableContainers;
53
53
  slices.availableSlices = settings.availableSlices;
54
+ slices.i18n = settings.i18n;
54
55
 
55
56
 
56
57
  addSliceOptions(slices.availableSlices);
57
58
 
58
- templates = [
59
+ templates = _.flatten([
59
60
  'slice',
60
61
  settings.mainTemplate,
61
62
  settings.metaTemplate,
62
- settings.mainExtraTemplate,
63
- settings.metaExtraTemplate
64
- ];
63
+ settings.mainExtraTemplates,
64
+ settings.metaExtraTemplates
65
+ ]);
65
66
 
66
67
  loadSliceTemplates(pageId);
67
68
  loadTemplates(templates, pageId, loadPageModel);
@@ -298,10 +299,12 @@ var slices = {
298
299
  $('#page-meta').slideDown('fast');
299
300
  $(this).html('<a href="#">hide advanced options</a>');
300
301
  $(this).addClass('open');
302
+ $(document).trigger('slices:didShowAdvancedOptions');
301
303
  }, function() {
302
304
  $('#page-meta').slideUp('fast');
303
305
  $(this).html('<a href="#">advanced options&hellip;</a>');
304
306
  $(this).removeClass('open');
307
+ $(document).trigger('slices:didHideAdvancedOptions');
305
308
  });
306
309
 
307
310
  if (slices.model.Page.seemsNew()) $('#show-meta').trigger('click');
@@ -312,16 +315,16 @@ var slices = {
312
315
 
313
316
  function initMeta() {
314
317
  $('#page-main').html(renderMetaFields(settings.mainTemplate));
315
-
316
318
  $('#page-meta').html(renderMetaFields(settings.metaTemplate));
319
+ $('#page-extra-main').empty();
317
320
 
318
- if (settings.metaExtraTemplate) {
319
- $('#page-meta').append(renderMetaFields(settings.metaExtraTemplate));
320
- }
321
+ $.each(settings.metaExtraTemplates, function(i, template) {
322
+ $('#page-meta').append(renderMetaFields(template));
323
+ });
321
324
 
322
- if (settings.mainExtraTemplate) {
323
- $('#page-extra-main').html(renderMetaFields(settings.mainExtraTemplate));
324
- }
325
+ $.each(settings.mainExtraTemplates, function(i, template) {
326
+ $('#page-extra-main').append(renderMetaFields(template));
327
+ });
325
328
 
326
329
  $('#page-meta-fields').applyDataValues().initDataPlugins();
327
330
 
@@ -86,12 +86,28 @@ slices.ComposerView = Backbone.View.extend({
86
86
  },
87
87
 
88
88
  update: function() {
89
+ this.ensureMinAndMax();
90
+
89
91
  var value = this.collection.toJSON();
90
92
  this.$el.data('computed-value', value);
91
93
  this.$el[this.collection.isEmpty() ? 'removeClass' : 'addClass']('not-empty');
92
94
  if (this.broadcastChanges) this.$el.trigger('change');
93
95
  },
94
96
 
97
+ ensureMinAndMax: function() {
98
+ var actions = this.$('.composer-actions');
99
+
100
+ if (this.collection.length < this.options.min) {
101
+ this.collection.add({});
102
+ }
103
+
104
+ if (this.collection.length >= this.options.max) {
105
+ actions.hide();
106
+ } else {
107
+ actions.show();
108
+ }
109
+ },
110
+
95
111
  addItem: function(item, collection, options) {
96
112
  var view = new slices.ComposerItemView({
97
113
  fields: this.options.fields,