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.
- checksums.yaml +4 -4
- data/Gemfile.lock +4 -5
- data/README.md +14 -14
- data/app/assets/javascripts/cardboard/admin.js +3 -24
- data/app/assets/javascripts/cardboard/datepicker.js +1 -5
- data/app/assets/javascripts/cardboard/rich_text.js +1 -1
- data/app/assets/javascripts/cardboard/search_filter.js +1 -1
- data/app/assets/stylesheets/cardboard/_bootstrap-select.css.scss +1 -1
- data/app/assets/stylesheets/cardboard/_framework.css.scss +1 -1
- data/app/assets/stylesheets/cardboard/_main_topbar.css.scss +1 -1
- data/app/controllers/cardboard/pages_controller.rb +25 -1
- data/app/controllers/pages_controller.rb +12 -11
- data/app/helpers/cardboard/resource_helper.rb +1 -1
- data/app/models/cardboard/field/boolean.rb +1 -1
- data/app/models/cardboard/field.rb +21 -9
- data/app/models/cardboard/page.rb +19 -30
- data/app/models/cardboard/page_part.rb +13 -46
- data/app/models/cardboard/setting.rb +3 -0
- data/app/models/cardboard/template.rb +15 -0
- data/app/views/cardboard/fields/_base_input.html.slim +1 -1
- data/app/views/cardboard/fields/_boolean.html.slim +2 -2
- data/app/views/cardboard/fields/_date.html.slim +1 -1
- data/app/views/cardboard/fields/_external_link.html.slim +2 -2
- data/app/views/cardboard/fields/_file.html.slim +4 -4
- data/app/views/cardboard/fields/_image.html.slim +2 -2
- data/app/views/cardboard/fields/_resource_link.html.slim +2 -2
- data/app/views/cardboard/fields/_rich_text.html.slim +1 -1
- data/app/views/cardboard/fields/_string.html.slim +1 -1
- data/app/views/cardboard/pages/_error.html.slim +1 -1
- data/app/views/cardboard/pages/_part_fields.html.slim +19 -0
- data/app/views/cardboard/pages/_sidebar.html.slim +8 -4
- data/app/views/cardboard/pages/_url_field.html.slim +6 -8
- data/app/views/cardboard/pages/edit.html.slim +24 -15
- data/app/views/cardboard/pages/new.html.slim +7 -0
- data/app/views/cardboard/pages/show.html.slim +3 -3
- data/app/views/cardboard/resources/_advanced_search.html.slim +1 -1
- data/app/views/cardboard/resources/_search_helper.html.slim +3 -3
- data/app/views/cardboard/resources/_simple_search.html.slim +1 -1
- data/app/views/cardboard/settings/index.html.slim +12 -3
- data/app/views/cardboard/super_user/index.html.slim +1 -1
- data/app/views/layouts/cardboard/_main_sidebar.html.slim +1 -1
- data/app/views/layouts/cardboard/_main_topbar.html.slim +1 -1
- data/app/views/layouts/cardboard/application.html.slim +1 -1
- data/cardboard.gemspec +1 -1
- data/config/routes.rb +2 -0
- data/db/migrate/1_create_cardboard.rb +63 -0
- data/lib/cardboard/engine.rb +1 -11
- data/lib/cardboard/helpers/seed.rb +31 -30
- data/lib/cardboard/version.rb +1 -1
- data/lib/cardboard_cms.rb +6 -2
- data/lib/generators/cardboard/install/install_generator.rb +5 -13
- data/lib/tasks/cardboard_tasks.rake +5 -3
- data/test/dummy/app/views/{pages → templates}/about-us.html.slim +0 -0
- data/test/dummy/app/views/templates/home.html.slim +5 -0
- data/test/dummy/config/cardboard.yml +1 -1
- data/test/dummy/db/schema.rb +7 -39
- data/test/dummy/db/seeds.rb +1 -1
- data/test/factories.rb +40 -1
- data/test/integration/page_editing_test.rb +2 -1
- data/test/integration/seeding_test.rb +16 -31
- data/test/models/field_test.rb +42 -28
- data/test/models/page_test.rb +1 -1
- data/test/models/template_test.rb +11 -0
- data/test/test_helper.rb +5 -1
- metadata +13 -29
- data/app/views/cardboard/pages/_subpart_fields.html.slim +0 -20
- data/lib/generators/cardboard/install/templates/migrations/1_create_cardboard_fields.rb +0 -21
- data/lib/generators/cardboard/install/templates/migrations/2_create_cardboard_page_parts.rb +0 -17
- data/lib/generators/cardboard/install/templates/migrations/3_create_cardboard_pages.rb +0 -18
- data/lib/generators/cardboard/install/templates/migrations/4_create_cardboard_settings.rb +0 -14
- data/test/dummy/app/views/pages/home.html.slim +0 -3
- data/test/dummy/db/migrate/20130426021522_create_news_posts.rb +0 -10
- data/test/dummy/db/migrate/20130501195423_create_icescreams.rb +0 -10
- data/test/dummy/db/migrate/20130502165540_create_beans.rb +0 -12
- data/test/dummy/db/migrate/20130522151358_create_cardboard_fields.rb +0 -21
- data/test/dummy/db/migrate/20130522151359_create_cardboard_page_parts.rb +0 -17
- data/test/dummy/db/migrate/20130522151400_create_cardboard_pages.rb +0 -18
- data/test/dummy/db/migrate/20130522151401_create_cardboard_settings.rb +0 -14
- data/test/dummy/db/migrate/20130607132558_create_admins.rb +0 -9
- 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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 75333a699fb1dccadb5e0e997b8c7a500ba5b9dd
|
|
4
|
+
data.tar.gz: 055466fb6267926f0b78c134a82598d7aa5b6364
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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/
|
|
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
|
|
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("
|
|
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
|
|
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
|
|
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,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
|
-
|
|
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
|
-
|
|
10
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
|
@@ -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
|
|
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
|
|
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
|
-
|
|
24
|
+
new_without_castnew(*attributes, &block)
|
|
28
25
|
end
|
|
29
|
-
alias_method_chain :new, :
|
|
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?
|
|
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
|
-
|
|
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
|
-
|
|
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")}
|
|
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
|
-
|
|
94
|
-
return nil unless parent_part
|
|
102
|
+
parts = self.parts.where(identifier: f.first)
|
|
95
103
|
|
|
96
|
-
|
|
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
|
-
|
|
106
|
+
parts
|
|
100
107
|
else
|
|
108
|
+
part = parts.first
|
|
101
109
|
return nil unless part
|
|
102
|
-
f.size == 1 ? part
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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 :
|
|
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
|
|
31
|
-
|
|
20
|
+
def repeatable?
|
|
21
|
+
template_hash[:repeatable]
|
|
32
22
|
end
|
|
33
23
|
|
|
34
|
-
def
|
|
35
|
-
|
|
24
|
+
def template_hash
|
|
25
|
+
@template ||= self.page.template.fields[self.identifier.to_sym]
|
|
36
26
|
end
|
|
37
27
|
|
|
38
|
-
def
|
|
39
|
-
|
|
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
|
-
|
|
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
|
|
@@ -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:
|
|
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 +=
|
|
4
|
-
= f.input :value, inline_label: label.html_safe, as:
|
|
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
|