slices 1.0.5 → 2.0.0

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 (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,