cardboard_cms 0.1.8 → 0.2.1

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