cardboard_cms 0.1.8 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +4 -5
  3. data/README.md +14 -14
  4. data/app/assets/javascripts/cardboard/admin.js +3 -24
  5. data/app/assets/javascripts/cardboard/datepicker.js +1 -5
  6. data/app/assets/javascripts/cardboard/rich_text.js +1 -1
  7. data/app/assets/javascripts/cardboard/search_filter.js +1 -1
  8. data/app/assets/stylesheets/cardboard/_bootstrap-select.css.scss +1 -1
  9. data/app/assets/stylesheets/cardboard/_framework.css.scss +1 -1
  10. data/app/assets/stylesheets/cardboard/_main_topbar.css.scss +1 -1
  11. data/app/controllers/cardboard/pages_controller.rb +25 -1
  12. data/app/controllers/pages_controller.rb +12 -11
  13. data/app/helpers/cardboard/resource_helper.rb +1 -1
  14. data/app/models/cardboard/field/boolean.rb +1 -1
  15. data/app/models/cardboard/field.rb +21 -9
  16. data/app/models/cardboard/page.rb +19 -30
  17. data/app/models/cardboard/page_part.rb +13 -46
  18. data/app/models/cardboard/setting.rb +3 -0
  19. data/app/models/cardboard/template.rb +15 -0
  20. data/app/views/cardboard/fields/_base_input.html.slim +1 -1
  21. data/app/views/cardboard/fields/_boolean.html.slim +2 -2
  22. data/app/views/cardboard/fields/_date.html.slim +1 -1
  23. data/app/views/cardboard/fields/_external_link.html.slim +2 -2
  24. data/app/views/cardboard/fields/_file.html.slim +4 -4
  25. data/app/views/cardboard/fields/_image.html.slim +2 -2
  26. data/app/views/cardboard/fields/_resource_link.html.slim +2 -2
  27. data/app/views/cardboard/fields/_rich_text.html.slim +1 -1
  28. data/app/views/cardboard/fields/_string.html.slim +1 -1
  29. data/app/views/cardboard/pages/_error.html.slim +1 -1
  30. data/app/views/cardboard/pages/_part_fields.html.slim +19 -0
  31. data/app/views/cardboard/pages/_sidebar.html.slim +8 -4
  32. data/app/views/cardboard/pages/_url_field.html.slim +6 -8
  33. data/app/views/cardboard/pages/edit.html.slim +24 -15
  34. data/app/views/cardboard/pages/new.html.slim +7 -0
  35. data/app/views/cardboard/pages/show.html.slim +3 -3
  36. data/app/views/cardboard/resources/_advanced_search.html.slim +1 -1
  37. data/app/views/cardboard/resources/_search_helper.html.slim +3 -3
  38. data/app/views/cardboard/resources/_simple_search.html.slim +1 -1
  39. data/app/views/cardboard/settings/index.html.slim +12 -3
  40. data/app/views/cardboard/super_user/index.html.slim +1 -1
  41. data/app/views/layouts/cardboard/_main_sidebar.html.slim +1 -1
  42. data/app/views/layouts/cardboard/_main_topbar.html.slim +1 -1
  43. data/app/views/layouts/cardboard/application.html.slim +1 -1
  44. data/cardboard.gemspec +1 -1
  45. data/config/routes.rb +2 -0
  46. data/db/migrate/1_create_cardboard.rb +63 -0
  47. data/lib/cardboard/engine.rb +1 -11
  48. data/lib/cardboard/helpers/seed.rb +31 -30
  49. data/lib/cardboard/version.rb +1 -1
  50. data/lib/cardboard_cms.rb +6 -2
  51. data/lib/generators/cardboard/install/install_generator.rb +5 -13
  52. data/lib/tasks/cardboard_tasks.rake +5 -3
  53. data/test/dummy/app/views/{pages → templates}/about-us.html.slim +0 -0
  54. data/test/dummy/app/views/templates/home.html.slim +5 -0
  55. data/test/dummy/config/cardboard.yml +1 -1
  56. data/test/dummy/db/schema.rb +7 -39
  57. data/test/dummy/db/seeds.rb +1 -1
  58. data/test/factories.rb +40 -1
  59. data/test/integration/page_editing_test.rb +2 -1
  60. data/test/integration/seeding_test.rb +16 -31
  61. data/test/models/field_test.rb +42 -28
  62. data/test/models/page_test.rb +1 -1
  63. data/test/models/template_test.rb +11 -0
  64. data/test/test_helper.rb +5 -1
  65. metadata +13 -29
  66. data/app/views/cardboard/pages/_subpart_fields.html.slim +0 -20
  67. data/lib/generators/cardboard/install/templates/migrations/1_create_cardboard_fields.rb +0 -21
  68. data/lib/generators/cardboard/install/templates/migrations/2_create_cardboard_page_parts.rb +0 -17
  69. data/lib/generators/cardboard/install/templates/migrations/3_create_cardboard_pages.rb +0 -18
  70. data/lib/generators/cardboard/install/templates/migrations/4_create_cardboard_settings.rb +0 -14
  71. data/test/dummy/app/views/pages/home.html.slim +0 -3
  72. data/test/dummy/db/migrate/20130426021522_create_news_posts.rb +0 -10
  73. data/test/dummy/db/migrate/20130501195423_create_icescreams.rb +0 -10
  74. data/test/dummy/db/migrate/20130502165540_create_beans.rb +0 -12
  75. data/test/dummy/db/migrate/20130522151358_create_cardboard_fields.rb +0 -21
  76. data/test/dummy/db/migrate/20130522151359_create_cardboard_page_parts.rb +0 -17
  77. data/test/dummy/db/migrate/20130522151400_create_cardboard_pages.rb +0 -18
  78. data/test/dummy/db/migrate/20130522151401_create_cardboard_settings.rb +0 -14
  79. data/test/dummy/db/migrate/20130607132558_create_admins.rb +0 -9
  80. data/vendor/assets/javascripts/cardboard/jquery.pjax.js +0 -840
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe8f9938ba535b8fed9271fb66606e70e78e4a5b
4
- data.tar.gz: 4eef9fe937568db71e1cd7af25b5f62f89add959
3
+ metadata.gz: 75333a699fb1dccadb5e0e997b8c7a500ba5b9dd
4
+ data.tar.gz: 055466fb6267926f0b78c134a82598d7aa5b6364
5
5
  SHA512:
6
- metadata.gz: 680fb7e71e94677f7930ab992999e43484db299760dbc490a754a60290cb095c0b5f5fc206ecb8c3daf65f5bf7507458d52b02b51016a3a82da3ac2ca7db942e
7
- data.tar.gz: 15a04806e88a768d83a769af68f8bacdfc8b13757517538013452c333b6b091eb7197ece71e97d97c83659e673825715819eaf7c93789e6c829947992fbc6b5d
6
+ metadata.gz: 1e4f0901db574ea6abdfc3a8c3390690741a06e0c4d4aedb3d2c29594267f3e3c031b2942b649d9103bd8ce62f3d91e09fb48040047680bc6345329214ad7bc1
7
+ data.tar.gz: 6fe7a9005e459619530949535a6bdaf23c021299e4c97b654e83192e5529198db8ba2ad61f93468019702562a730619c4cafb920ec5a141ad47bf708890b5855
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cardboard_cms (0.1.8)
4
+ cardboard_cms (0.2.1)
5
5
  bootstrap-datepicker-rails
6
6
  bootstrap-sass (~> 2.2)
7
7
  bootstrap-wysihtml5-rails
@@ -18,7 +18,6 @@ PATH
18
18
  kaminari
19
19
  kaminari-bootstrap (~> 0.1.3)
20
20
  rack-cache
21
- rack-pjax
22
21
  rails (~> 4.0.0)
23
22
  ranked-model (>= 0.2.1)
24
23
  ransack (>= 1.0.0)
@@ -27,6 +26,7 @@ PATH
27
26
  simple_form (>= 3.0.0)
28
27
  slim (>= 1.3.8)
29
28
  stringex
29
+ turbolinks
30
30
 
31
31
  GEM
32
32
  remote: http://rubygems.org/
@@ -207,9 +207,6 @@ GEM
207
207
  rack (1.5.2)
208
208
  rack-cache (1.2)
209
209
  rack (>= 0.4)
210
- rack-pjax (0.7.0)
211
- nokogiri (~> 1.5)
212
- rack (~> 1.3)
213
210
  rack-test (0.6.2)
214
211
  rack (>= 1.0)
215
212
  rails (4.0.0)
@@ -285,6 +282,8 @@ GEM
285
282
  treetop (1.4.14)
286
283
  polyglot
287
284
  polyglot (>= 0.3.1)
285
+ turbolinks (2.2.1)
286
+ coffee-rails
288
287
  turn (0.9.6)
289
288
  ansi
290
289
  tzinfo (0.3.37)
data/README.md CHANGED
@@ -28,7 +28,7 @@ Add the gem to the `Gemfile`
28
28
  gem "cardboard_cms", github: "smashingboxes/cardboard"
29
29
  ```
30
30
 
31
- And run `bundle install`.
31
+ And run `bundle install`.
32
32
 
33
33
  Run the generator to install cardboard and it's migrations:
34
34
  ```sh
@@ -45,7 +45,7 @@ rake cardboard:seed
45
45
 
46
46
  ## Usage
47
47
  ### Get a page
48
- Add a file in your `app/views/pages` with filename matching the identifier of the page. Inside this file you can access the page with:
48
+ Add a file in your `app/views/templates` with filename matching the identifier of the page. Inside this file you can access the page with:
49
49
  ```ruby
50
50
  current_page
51
51
  ```
@@ -57,7 +57,7 @@ current_page.get('slideshow')
57
57
  ### Fetch a repeatable page part
58
58
  Repeatable parts returns an active record collection. This means that regular Rails methods such as `where`, `limit`, `first`, `each`, etc can be used on page parts
59
59
  ```slim
60
- - current_page.get('slideshow').each do |slide|
60
+ - current_page.get('slideshow').each do |slide|
61
61
  p= image_tag slide.attr('image1').thumb('600x300').url, alt: slide.attr('description') if slide.attr('image1')
62
62
  ```
63
63
  ### Fetch a single field
@@ -127,7 +127,7 @@ Key | Type | Default | Definition
127
127
  ---|--- | ---|---
128
128
  [fields](#fields) | hash | nil | list of fields that make this part's form
129
129
  position | integer | auto-increment | position of the part on the admin page
130
- repeatable | boolean | false | can the client add multiple of these parts (example a slide in a slideshow)
130
+ repeatable | boolean | false | can the client add multiple of these parts (example a slide in a slideshow)
131
131
 
132
132
 
133
133
  ####fields
@@ -155,10 +155,10 @@ rails g cardboard:resource model_name
155
155
  Then customize the `controllers/cardboard/model_name_controller.rb` and associated views to your heart's desire.
156
156
 
157
157
 
158
- The default cardboard resource scaffold help you quickly get started by making the most of the following gems.
158
+ The default cardboard resource scaffold help you quickly get started by making the most of the following gems.
159
159
 
160
- Gem | Description
161
- --- | ---
160
+ Gem | Description
161
+ --- | ---
162
162
  [InheritedResources](https://github.com/josevalim/inherited_resources) | Inherited Resources speeds up development by making your controllers inherit all restful actions so you just have to focus on what is important.
163
163
  [Simple Form](https://github.com/plataformatec/simple_form) | Forms made easy! It's tied to a simple DSL, with no opinion on markup.
164
164
  [Kaminari](https://github.com/amatsuda/kaminari) | A Scope & Engine based, clean, powerful, customizable and sophisticated paginator
@@ -179,7 +179,7 @@ You can also choose to remove a resource from the menu
179
179
  ```ruby
180
180
  default_order "name DESC" # default: 'updated_at desc'
181
181
  ```
182
- You can pass any `ransack` sort order, which includes associations. Example:
182
+ You can pass any `ransack` sort order, which includes associations. Example:
183
183
  ```ruby
184
184
  default_order "user_name" # belongs to a user
185
185
  ```
@@ -210,13 +210,13 @@ We use kaminari, so all you need to do is add to your index view:
210
210
 
211
211
 
212
212
  #### Column sorting helper
213
- Cardboard's controllers inherit from a `@q` variable which gives access to the ransack gem.
213
+ Cardboard's controllers inherit from a `@q` variable which gives access to the ransack gem.
214
214
  ```
215
- = sort_link @q, :name, "Product Name"
215
+ = sort_link @q, :name, "Product Name"
216
216
  ```
217
217
 
218
218
  #### Custom resource helpers
219
- To add custom helpers for your resource simply create a helper with the same name.
219
+ To add custom helpers for your resource simply create a helper with the same name.
220
220
  Example:
221
221
  ```ruby
222
222
  module Cardboard
@@ -232,7 +232,7 @@ The css/js for the resources is the same as the cardboard admin interface. If yo
232
232
  Note: Make sure to remove `*= require_tree .` from your application.css, you don't want your cardboard css and js to leak into your main app!
233
233
 
234
234
  ## Create Settings
235
- You can create new settings that will be editable from the admin panel.
235
+ You can create new settings that will be editable from the admin panel.
236
236
 
237
237
  In your `config/cardboard.yml`
238
238
 
@@ -269,7 +269,7 @@ PagesController.class_eval do
269
269
  @example = "cool"
270
270
  end
271
271
  end
272
- ```
272
+ ```
273
273
  ### Page Path
274
274
  In your controllers you may want to redirect to a specific page. You can do so with the following:
275
275
  ```ruby
@@ -315,7 +315,7 @@ Use the page identifier defined in the cardboard.yml file (or see yoda)
315
315
  = link_to_page "page_identifier", class: "btn" do |page|
316
316
  "hello #{page.title}"
317
317
  end
318
-
318
+
319
319
  # or, to simply use the page title
320
320
 
321
321
  = link_to_page "page_identifier", class: "btn"
@@ -5,7 +5,7 @@
5
5
  //= require jquery_ujs
6
6
  //= require jquery.ui.sortable
7
7
  //= require cardboard/jquery.livesearch
8
- //= require cardboard/jquery.pjax
8
+ //= require turbolinks
9
9
  //= require bootstrap-button
10
10
  //= require bootstrap-dropdown
11
11
  //= require bootstrap-modal
@@ -21,42 +21,21 @@
21
21
  //= require cardboard/content_sidebar
22
22
  //= require cardboard/search_filter
23
23
  //= require select2
24
-
25
24
  // require cardboard/jquery.wysihtml5imgresizer
26
25
 
27
26
 
28
- $(document).pjax('a:not([data-remote]):not([data-behavior]):not([data-skip-pjax]):not([href="#"]):not([href=""]):not([data-method])', '[data-pjax-container]');
29
-
30
- $(document).on('submit', 'form[data-pjax]', function(event) {
31
- $.pjax.submit(event, '[data-pjax-container]');
32
- });
33
-
34
27
  $(document).on('click', '.nav-tabs a', function(e){
35
28
  e.preventDefault();
36
29
  $(this).tab('show');
37
30
  });
38
31
 
39
- $(document).on("pjax:success ready cocoon:after-insert", function(e){
32
+ $(document).on("page:load ready cocoon:after-insert", function(e){
40
33
 
41
34
  $('select:not([data-search-select])').selectpicker();
42
35
  $('select[data-search-select]').select2({allowClear: true, width: "resolve"});
43
36
 
44
37
  $('.nav-tabs a:first').tab('show');
45
- });
46
-
47
- $(function(){
48
- $('.page_link .link_wrap a').click(function(){
49
- $('.nav_resource_link.active').removeClass('active');
50
- $('#nav_dashboard_link').addClass('active');
51
- });
52
-
53
- $('.nav_resource_link').click(function(){
54
- $('.nav_resource_link.active, #nav_dashboard_link').removeClass('active');
55
- $(this).addClass('active');
56
- $("#content_sidebar").removeClass('toggle');
57
- $('#content').removeClass('toggle');
58
- });
59
38
 
60
39
  window.setTimeout(function() { $(".alert:not(.alert-error)").alert('close'); }, 2000);
61
- })
40
+ });
62
41
 
@@ -10,10 +10,6 @@ var create_datepickers = function(){
10
10
  }
11
11
 
12
12
 
13
- $(document).on("ready pjax:end", function () {
13
+ $(document).on("ready page:load cocoon:after-insert", function () {
14
14
  create_datepickers();
15
-
16
- $(document).on('cocoon:after-insert', function(e, insertedItem) {
17
- create_datepickers();
18
- });
19
15
  });
@@ -55,7 +55,7 @@ var rich_text_editor_defaults = {
55
55
  useLineBreaks: false
56
56
  }
57
57
 
58
- $(document).on("ready pjax:end", function(e){
58
+ $(document).on("ready page:load", function(e){
59
59
  if($(".wysihtml5").length) {
60
60
  $('.wysihtml5').wysihtml5(rich_text_editor_defaults);
61
61
  $('iframe.wysihtml5-sandbox').wysihtml5_size_matters();
@@ -1,7 +1,7 @@
1
1
  $(function(){
2
2
  var ransack_options;
3
3
 
4
- $(document).on("pjax:end ready", function(e){
4
+ $(document).on("page:load ready", function(e){
5
5
  ransack_options = $("select#ransack_options").html();
6
6
  $("select#advanced_field").trigger("change");
7
7
  })
@@ -2,7 +2,7 @@
2
2
  .bootstrap-select.btn-group[class*="span"] {
3
3
  float: none;
4
4
  display: inline-block;
5
- margin-bottom: 10px;
5
+ // margin-bottom: 10px;
6
6
  margin-left: 0;
7
7
  }
8
8
  .form-search .bootstrap-select.btn-group,
@@ -97,7 +97,7 @@ textarea {
97
97
 
98
98
  .right{
99
99
  float: right;
100
- margin-right: 1.5em;
100
+ margin-left: 1.5em;
101
101
  }
102
102
  .nav li img{
103
103
  margin-right: 6px;
@@ -17,7 +17,7 @@ $main_topbar_zindex: 100;
17
17
  @include border-radius(0px);
18
18
  border: none;
19
19
  padding: 0px 10px;
20
- height: $main_topbar_height;
20
+ min-width: 760px;
21
21
  a{color: $main_topbar_color;}
22
22
  text-shadow: $main_topbar_color_text_shadow;
23
23
 
@@ -1,13 +1,31 @@
1
1
  require_dependency "cardboard/application_controller"
2
+ require_dependency Cardboard::Engine.root.join('lib/cardboard/helpers/seed.rb').to_s
2
3
 
3
4
  module Cardboard
4
5
  class PagesController < ApplicationController
5
6
  before_filter :check_ability
6
7
 
8
+ def new
9
+ @page = Cardboard::Page.new
10
+ end
11
+
7
12
  def edit
8
13
  @page = Cardboard::Page.find(params[:id])
9
14
  end
10
15
 
16
+ def create
17
+ @page = Cardboard::Page.new(params.require(:page).permit(:title, :template_id))
18
+ @page.identifier = @page.title.to_url.underscore if @page.identifier.blank?
19
+ if @page.save
20
+ Cardboard::Seed.populate_parts(@page.template.fields, @page)
21
+ @page.reload
22
+ redirect_to edit_page_path(@page)
23
+ else
24
+ @page.errors.add(:title, "is reserved or is already used") if @page.errors[:identifier].present?
25
+ render :new
26
+ end
27
+ end
28
+
11
29
  def update
12
30
  @page = Cardboard::Page.find(params[:id])
13
31
 
@@ -20,10 +38,16 @@ module Cardboard
20
38
  end
21
39
 
22
40
  def sort
23
- Page.find(params[:id]).update_attribute(:position_position, params[:index])
41
+ Cardboard::Page.find(params[:id]).update_attribute(:position_position, params[:index])
24
42
  render nothing: true
25
43
  end
26
44
 
45
+ def destroy
46
+ @page = Cardboard::Page.find(params[:id])
47
+ @page.destroy
48
+ redirect_to pages_path
49
+ end
50
+
27
51
  private
28
52
  def check_ability
29
53
  unless cardboard_user_can_manage?(:pages)
@@ -1,15 +1,17 @@
1
1
  class PagesController < ApplicationController
2
2
  def show
3
-
4
- raise ActionController::RoutingError.new("Page Not Found") if current_page.nil?
5
-
6
- if current_page.using_slug_backup?
7
- redirect_to current_page.url, status: :moved_permanently
3
+ if current_page.nil?
4
+ flash[:error] = "No root page! Make sure to add a page first"
5
+ redirect_to cardboard.dashboard_path
8
6
  else
9
- # call controller hook
10
- self.send(current_page.identifier) if self.respond_to? current_page.identifier
7
+ if current_page.using_slug_backup?
8
+ redirect_to current_page.url, status: :moved_permanently
9
+ else
10
+ # call controller hook
11
+ self.send(current_page.identifier) if self.respond_to? current_page.identifier
11
12
 
12
- render "cardboard/pages/show", layout: @layout || "layouts/application"
13
+ render "cardboard/pages/show", layout: @layout || "layouts/application"
14
+ end
13
15
  end
14
16
  end
15
17
 
@@ -21,9 +23,8 @@ private
21
23
  # helper_method :edit_link
22
24
 
23
25
  def current_page
24
- @page ||= Cardboard::Page.find_by_url(params[:id]) ||
25
- Cardboard::Page.root ||
26
- raise(ActionController::RoutingError.new("No root page, make sure to run `rake cardboard:seed`"))
26
+ @page ||= Cardboard::Page.find_by_url(params[:id]) || Cardboard::Page.root
27
+ # || raise(ActionController::RoutingError.new("No root page, make sure to run `rake cardboard:seed`"))
27
28
  end
28
29
 
29
30
  end
@@ -63,7 +63,7 @@ module Cardboard
63
63
  end
64
64
  end
65
65
 
66
- render "cardboard/resources/search_helper", klass: klass.to_s.demodulize.underscore, options: options, main_element: main_element #,elements: elements
66
+ render "cardboard/resources/search_helper", klass: klass.to_s, options: options, main_element: main_element #,elements: elements
67
67
  end
68
68
 
69
69
 
@@ -17,7 +17,7 @@ module Cardboard
17
17
  private
18
18
 
19
19
  def is_boolean
20
- errors.add(:value, "is not a valid boolean") if self.value_uid.nil?
20
+ errors.add(:value, "is not a valid boolean") if value_uid.present? && value.nil?
21
21
  end
22
22
 
23
23
  def to_boolean(val)
@@ -6,27 +6,33 @@ module Cardboard
6
6
  belongs_to :object_with_field, :polymorphic => true, :inverse_of => :fields
7
7
 
8
8
  #gem
9
- include RankedModel
10
- ranks :position, :with_same => [:object_with_field_id, :object_with_field_type], :class_name => 'Cardboard::Field'
11
9
 
12
10
  #validations
13
- validates :identifier, :type, presence:true
11
+ validates :identifier, :type, :object_with_field, presence:true
14
12
  validates :identifier, uniqueness: {:case_sensitive => false, :scope => [:object_with_field_id, :object_with_field_type]},
15
13
  :format => { :with => /\A[a-z\_0-9]+\z/,
16
- :message => "Only downcase letters, numbers and underscores are allowed" }
14
+ :message => "Only lowercase letters, numbers and underscores are allowed" }
17
15
 
18
- default_scope {rank(:position)}
19
16
 
20
17
  class << self
21
18
  # Allow "type" to be passed in nested forms
22
- def new_with_cast(*attributes, &block)
19
+ def new_with_castnew(*attributes, &block)
23
20
  if (h = attributes.first).is_a?(Hash) && !h.nil? && (type = h.delete(:type) || h.delete('type')) && type.present? && (klass = type.constantize) != self
24
21
  raise "Field type #{type} does not inherit from Cardboard::Field" unless klass <= self
25
22
  return klass.new(*attributes, &block)
26
23
  end
27
- new_without_cast(*attributes, &block)
24
+ new_without_castnew(*attributes, &block)
28
25
  end
29
- alias_method_chain :new, :cast
26
+ alias_method_chain :new, :castnew
27
+
28
+ # def build_with_castbuild(*attributes, &block)
29
+ # if (h = attributes.first).is_a?(Hash) && !h.nil? && (type = h.delete(:type) || h.delete('type')) && type.present? && (klass = type.constantize) != self
30
+ # raise "Field type #{type} does not inherit from Cardboard::Field" unless klass <= self
31
+ # return klass.build(*attributes, &block)
32
+ # end
33
+ # new_without_castbuild(*attributes, &block)
34
+ # end
35
+ # alias_method_chain :build, :castbuild
30
36
  end
31
37
 
32
38
  # overwritten setter
@@ -53,6 +59,12 @@ module Cardboard
53
59
  end
54
60
  end
55
61
 
62
+ def required?
63
+ required = self.object_with_field.template[self.identifier.to_sym][:required]
64
+ required = true if required.nil?
65
+ required
66
+ end
67
+
56
68
  private
57
69
 
58
70
  def is_required
@@ -60,7 +72,7 @@ module Cardboard
60
72
  end
61
73
 
62
74
  def required_field?
63
- self.required? && !self.seeding
75
+ !self.seeding && required?
64
76
  end
65
77
 
66
78
  end
@@ -1,10 +1,15 @@
1
1
  module Cardboard
2
2
  class Page < ActiveRecord::Base
3
+
3
4
  has_many :parts, class_name: "Cardboard::PagePart", :dependent => :destroy, :validate => true
5
+
6
+ belongs_to :template, class_name: "Cardboard::Template"
4
7
 
5
8
  attr_accessor :parent_url, :is_root
6
9
 
7
10
  accepts_nested_attributes_for :parts, allow_destroy: true, :reject_if => :all_blank
11
+ # TODO: allow destroy and allow all blank only if repeatable
12
+
8
13
  serialize :meta_seo, Hash
9
14
  serialize :slugs_backup, Array
10
15
 
@@ -18,16 +23,16 @@ module Cardboard
18
23
  ranks :position, :with_same => :path
19
24
 
20
25
  #validations
21
- validates :title, :path, presence:true
26
+ # validates_associated :parts
27
+ validates :title, :path, :template, presence:true
22
28
  validates :slug, uniqueness: { :case_sensitive => false, :scope => :path }, presence: true
23
29
  validates :identifier, uniqueness: {:case_sensitive => false}, :format => { :with => /\A[a-z\_0-9]+\z/,
24
- :message => "Only downcase letters, numbers and underscores are allowed" }
30
+ :message => "Only downcase letters, numbers and underscores are allowed" }, presence: true
25
31
  #validate all seo keys are valid meta keys + title
26
32
 
27
- # validates_associated :parts, on: :update #breaks seed, should work
28
-
29
33
  #scopes
30
- scope :preordered, -> {order("path ASC, position ASC, slug ASC")} #order("CASE slug WHEN '/' THEN 'slug, position' ELSE 'path, position, slug' END")
34
+ scope :preordered, -> {order("path ASC, position ASC, slug ASC")}
35
+
31
36
 
32
37
  #class variables
33
38
  after_commit do
@@ -80,6 +85,10 @@ module Cardboard
80
85
 
81
86
  #instance methods
82
87
 
88
+ def template_hash
89
+ @template_hash ||= self.template.fields
90
+ end
91
+
83
92
  # @page.get("slideshow.image1")
84
93
  # @page.get("slideshow").first.image1
85
94
  # @page.get("slideshow").each...
@@ -90,38 +99,18 @@ module Cardboard
90
99
  # slideshow.get("slide1")
91
100
  def get(field)
92
101
  f = field.split(".")
93
- parent_part = self.parts.where(identifier: f.first).first
94
- return nil unless parent_part
102
+ parts = self.parts.where(identifier: f.first)
95
103
 
96
- part = parent_part.try(:subparts)
97
- if parent_part.repeatable?
104
+ if template_hash[f.first.to_sym][:repeatable]
98
105
  raise "Part is repeatable, expected each loop" unless f.size == 1
99
- part || []
106
+ parts
100
107
  else
108
+ part = parts.first
101
109
  return nil unless part
102
- f.size == 1 ? part.first : part.first.attr(f.last)
110
+ f.size == 1 ? part : part.attr(f.last)
103
111
  end
104
112
  end
105
113
 
106
- # def page_hash
107
- # return {} if self.parts.blank?
108
- # self.parts.rank(:part_position).inject(ActiveSupport::OrderedHash.new) do |part_hash, part|
109
- # part_hash[part.identifier] = if part.repeatable?
110
- # part.subparts.rank(:subpart_position).inject([]) do |sub_array, subpart|
111
- # sub_array << subpart.fields.rank(:position).inject(ActiveSupport::OrderedHash.new) do |fields_hash, field|
112
- # fields_hash[field.identifier] = subpart.attr(field.identifier)
113
- # fields_hash
114
- # end
115
- # end
116
- # else
117
- # get(part.identifier).fields.rank(:position).inject(ActiveSupport::OrderedHash.new) do |fields_hash, field|
118
- # fields_hash[field.identifier] = part.attr(field.identifier)
119
- # fields_hash
120
- # end
121
- # end
122
- # part_hash
123
- # end
124
- # end
125
114
 
126
115
  # SEO
127
116
  # children inherit their parent's SEO settings (these can be overwritten)
@@ -1,54 +1,32 @@
1
1
  module Cardboard
2
2
  class PagePart < ActiveRecord::Base
3
3
  has_many :fields, :as => :object_with_field, class_name: "Cardboard::Field", :dependent => :destroy, :inverse_of => :object_with_field
4
- has_many :subparts, class_name: "Cardboard::PagePart", :dependent => :destroy, :foreign_key => "parent_part_id", :inverse_of => :parent
5
4
 
6
- belongs_to :parent, class_name: "Cardboard::PagePart", :foreign_key => "parent_part_id", :inverse_of => :subparts
7
5
  belongs_to :page
8
6
 
9
- accepts_nested_attributes_for :subparts, :allow_destroy => true #, :reject_if => :all_blank
10
7
  accepts_nested_attributes_for :fields #, :allow_destroy => true (maybe for super admin?)
11
8
 
12
- validates :identifier, uniqueness: {:case_sensitive => false, :scope => :page_id},
13
- :format => {:with => /\A[a-z\_0-9]+\z/, :message => "Only downcase letters, numbers and underscores are allowed"},
14
- :unless => :subpart?
15
- validates_associated :fields
16
- # validates :subparts, presence:true, unless: -> {new_record? || subpart?}
17
- validate :at_least_one_subpart
18
-
19
- # Scopes
20
- scope :is_subparts, ->{ where("parent_part_id IS NOT NULL")}
21
- scope :is_parent, ->{where("parent_part_id IS NULL")}
9
+ validates :identifier, :format => {:with => /\A[a-z\_0-9]+\z/, :message => "Only downcase letters, numbers and underscores are allowed"} # uniqueness: {:case_sensitive => false, :scope => :page_id},
10
+ validates :page, :identifier, presence: true
11
+ # validates_associated :fields
12
+
22
13
 
23
14
  #gem
24
15
  include RankedModel
25
- ranks :subpart_position, :with_same => :parent_part_id, :column => :position, :scope => :is_subparts
26
- ranks :part_position, :with_same => :page_id, :column => :position, :scope => :is_parent
16
+ ranks :part_position, :with_same => :page_id, :column => :position
27
17
  default_scope {order("position ASC")}
28
18
 
29
19
 
30
- def subpart?
31
- !self.parent_part_id.nil?
20
+ def repeatable?
21
+ template_hash[:repeatable]
32
22
  end
33
23
 
34
- def repeatable?
35
- @parent_repeatable ||= self.parent ? self.parent[:repeatable] : super
24
+ def template_hash
25
+ @template ||= self.page.template.fields[self.identifier.to_sym]
36
26
  end
37
27
 
38
- def new_subpart
39
- return nil if !repeatable? || subpart?
40
- master = self.subparts.first
41
- master_hash = master.attributes.select do |key, value|
42
- ["parent_part_id"].include? key
43
- end
44
- subpart = Cardboard::PagePart.new(master_hash)
45
- for field in master.fields
46
- field_hash = field.attributes.select do |key, value|
47
- ["identifier", "label", "type", "required", "hint", "placeholder"].include? key
48
- end
49
- subpart.fields << Cardboard::Field.new(field_hash)
50
- end
51
- return subpart
28
+ def template
29
+ template_hash[:fields]
52
30
  end
53
31
 
54
32
  def attr(field)
@@ -63,17 +41,6 @@ module Cardboard
63
41
  end
64
42
  end
65
43
 
66
- private
67
-
68
- def at_least_one_subpart
69
- return true if subpart? || new_record?
70
- # require a minimum of one task
71
- undestroyed_part_count = 0
72
-
73
- subparts.each { |t| undestroyed_part_count += 1 unless t.marked_for_destruction? }
74
- if undestroyed_part_count < 1
75
- errors.add(:base, 'There must be at least one')
76
- end
77
- end
44
+
78
45
  end
79
- end
46
+ end
@@ -6,6 +6,9 @@ module Cardboard
6
6
  has_many :fields, :as => :object_with_field
7
7
  accepts_nested_attributes_for :fields, :allow_destroy => true
8
8
 
9
+ serialize :template, Hash
10
+
11
+
9
12
  # thread save caching of the settings
10
13
  @lock = ::Mutex.new
11
14
  after_commit do
@@ -0,0 +1,15 @@
1
+ module Cardboard
2
+ class Template < ActiveRecord::Base
3
+
4
+ serialize :fields, Hash
5
+
6
+ has_many :pages
7
+
8
+ validates :identifier, uniqueness: {:case_sensitive => false}, :format => { :with => /\A[a-z\_0-9]+\z/,
9
+ :message => "Only downcase letters, numbers and underscores are allowed" }
10
+
11
+ def name
12
+ self[:name] || self.identifier
13
+ end
14
+ end
15
+ end
@@ -1 +1 @@
1
- = f.input :value, label: f.object.label || f.object.identifier.titleize, as: f.object.type, hint: f.object.hint, placeholder: f.object.placeholder, required: f.object.required
1
+ = f.input :value, label: field[:label] || identifier.titleize, as: field[:type], hint: field[:hint], placeholder: field[:placeholder], required: field[:required] != false
@@ -1,4 +1,4 @@
1
1
  - label = ""
2
2
  / - label += '<abbr title="required">*</abbr> ' if f.object.required
3
- - label += f.object.label || f.object.identifier.titleize
4
- = f.input :value, inline_label: label.html_safe, as: f.object.type, hint: f.object.hint, placeholder: f.object.placeholder, required: f.object.required, label: false
3
+ - label += field[:label] || identifier.titleize
4
+ = f.input :value, inline_label: label.html_safe, as: field[:type], hint: field[:hint], placeholder: field[:placeholder], required: field[:required] != false, label: false