activeadmin-magicfields 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +50 -0
  3. data/Gemfile +42 -0
  4. data/Guardfile +8 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.md +160 -0
  7. data/Rakefile +33 -0
  8. data/activeadmin-magicfields.gemspec +23 -0
  9. data/app/assets/javascripts/activeadmin-magicfields.js.coffee +101 -0
  10. data/app/assets/stylesheets/activeadmin-magicfields.css.scss +53 -0
  11. data/lib/activeadmin-magicfields.rb +18 -0
  12. data/lib/activeadmin-magicfields/engine.rb +12 -0
  13. data/lib/activeadmin-magicfields/form_builder.rb +175 -0
  14. data/lib/activeadmin-magicfields/paperclip.rb +2 -0
  15. data/lib/activeadmin-magicfields/version.rb +3 -0
  16. data/lib/app/admin/part.rb +29 -0
  17. data/lib/app/admin/part_object.rb +26 -0
  18. data/lib/app/models/field/checkbox.rb +12 -0
  19. data/lib/app/models/field/image.rb +35 -0
  20. data/lib/app/models/field/repeater.rb +19 -0
  21. data/lib/app/models/field/text.rb +14 -0
  22. data/lib/app/models/field/textarea.rb +14 -0
  23. data/lib/app/models/field_template.rb +5 -0
  24. data/lib/app/models/part.rb +6 -0
  25. data/lib/app/models/part_object.rb +11 -0
  26. data/lib/app/models/part_object_field.rb +13 -0
  27. data/lib/app/models/repeater_part_object.rb +6 -0
  28. data/lib/app/views/admin/field_inputs/_checkbox.html.erb +1 -0
  29. data/lib/app/views/admin/field_inputs/_image.html.erb +4 -0
  30. data/lib/app/views/admin/field_inputs/_product.html.erb +1 -0
  31. data/lib/app/views/admin/field_inputs/_repeater.html.erb +3 -0
  32. data/lib/app/views/admin/field_inputs/_site_page.html.erb +1 -0
  33. data/lib/app/views/admin/field_inputs/_text.html.erb +1 -0
  34. data/lib/app/views/admin/field_inputs/_textarea.html.erb +8 -0
  35. data/lib/app/views/admin/part_objects/_part_object.html.erb +53 -0
  36. data/lib/app/views/admin/parts/_part.html.erb +11 -0
  37. data/lib/app/views/admin/parts/_part_old.arb +32 -0
  38. data/lib/generators/activeadmin-magicfields/install/install_generator.rb +33 -0
  39. data/lib/generators/activeadmin-magicfields/install/templates/create_field_checkbox.rb +10 -0
  40. data/lib/generators/activeadmin-magicfields/install/templates/create_field_image.rb +10 -0
  41. data/lib/generators/activeadmin-magicfields/install/templates/create_field_repeater.rb +9 -0
  42. data/lib/generators/activeadmin-magicfields/install/templates/create_field_templates.rb +14 -0
  43. data/lib/generators/activeadmin-magicfields/install/templates/create_field_text.rb +10 -0
  44. data/lib/generators/activeadmin-magicfields/install/templates/create_field_textarea.rb +12 -0
  45. data/lib/generators/activeadmin-magicfields/install/templates/create_part_object_fields.rb +10 -0
  46. data/lib/generators/activeadmin-magicfields/install/templates/create_part_objects.rb +13 -0
  47. data/lib/generators/activeadmin-magicfields/install/templates/create_parts.rb +9 -0
  48. data/lib/generators/activeadmin-magicfields/install/templates/create_repeater_part_objects.rb +10 -0
  49. data/spec/rails_helper.rb +154 -0
  50. data/spec/spec_helper.rb +17 -0
  51. data/spec/support/deferred_garbage_collection.rb +19 -0
  52. data/spec/support/detect_rails_version.rb +26 -0
  53. data/spec/support/integration_example_group.rb +31 -0
  54. data/spec/support/jslint.yml +80 -0
  55. data/spec/support/rails_template.rb +104 -0
  56. data/spec/support/rails_template_with_data.rb +59 -0
  57. data/spec/support/templates/cucumber.rb +24 -0
  58. data/spec/support/templates/cucumber_with_reloading.rb +5 -0
  59. data/spec/support/templates/en.yml +8 -0
  60. data/spec/support/templates/policies/active_admin/comment_policy.rb +9 -0
  61. data/spec/support/templates/policies/active_admin/page_policy.rb +18 -0
  62. data/spec/support/templates/policies/application_policy.rb +45 -0
  63. data/spec/support/templates/policies/category_policy.rb +7 -0
  64. data/spec/support/templates/policies/post_policy.rb +15 -0
  65. data/spec/support/templates/policies/store_policy.rb +11 -0
  66. data/spec/support/templates/policies/user_policy.rb +11 -0
  67. data/spec/support/templates/post_decorator.rb +11 -0
  68. data/spec/unit/form_builder_spec.rb +121 -0
  69. data/tasks/test.rake +83 -0
  70. metadata +175 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e2fa74a59fbf379bacb891c95d2fe0ef60b6ba14
4
+ data.tar.gz: e4fed1594cfac9aecf652c9514542dabdaf20470
5
+ SHA512:
6
+ metadata.gz: d6d6f9f3836941469d5863eddba3f55460e8ac5415383e24592a906d912cb540115f2b8fa313b1ae2489fac41868941c14fcb7fdc704adb18b3e3403f414b129
7
+ data.tar.gz: 5ba2fdf9cdd43681fd5796c0284017a7a906519c784c0c74506f706554099c89a993cdf50a27877c0b7adc8b99ef56851667844b429385df30cf3c5f98d49cea
data/.gitignore ADDED
@@ -0,0 +1,50 @@
1
+ *.gem
2
+ ## Mac
3
+ .DS_Store
4
+
5
+ ## Windows
6
+ .Thumbs.db
7
+
8
+ ## TextMate
9
+ *.tm_project
10
+ *.tmproj
11
+ tmtags
12
+
13
+ ## Emacs
14
+ *~
15
+ \#*
16
+ .\#*
17
+
18
+ ## Vim
19
+ *.swp
20
+ # IDEA / RUBYMINE
21
+ .idea
22
+
23
+ ## RVM
24
+ .rvmrc
25
+ .ruby-version
26
+ .ruby-gemset
27
+
28
+ ## Project (general)
29
+ tags
30
+ coverage
31
+ rdoc
32
+ doc
33
+ .yardoc
34
+ pkg
35
+
36
+ ## Project (specific)
37
+ bin/
38
+ .bundle
39
+ spec/rails
40
+ *.sqlite3-journal
41
+ Gemfile.lock
42
+ Gemfile-*.lock
43
+ capybara*
44
+ viewcumber
45
+ test-rails*
46
+ public
47
+ .rspec
48
+ .rails-version
49
+ .rbenv-version
50
+ .localeapp/*
data/Gemfile ADDED
@@ -0,0 +1,42 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'activeadmin', github: 'activeadmin'
6
+ gem 'inherited_resources'
7
+ gem 'paperclip'
8
+ # gem 'activeadmin-wysihtml5', github: 'silvaire/activeadmin-wysihtml5'
9
+
10
+ group :development do
11
+ # Debugging
12
+ gem 'better_errors' # Web UI to debug exceptions. Go to /__better_errors to access the latest one
13
+ gem 'binding_of_caller' # Retrieve the binding of a method's caller in MRI Ruby >= 1.9.2
14
+
15
+ # Performance
16
+ gem 'rack-mini-profiler' # Inline app profiler. See ?pp=help for options.
17
+ gem 'flamegraph' # Flamegraph visualiztion: ?pp=flamegraph
18
+
19
+ # Documentation
20
+ gem 'yard' # Documentation generator
21
+ gem 'redcarpet' # Markdown implementation (for yard)
22
+ end
23
+
24
+ group :test do
25
+ gem 'capybara'
26
+ gem 'simplecov', require: false # Test coverage generator. Go to /coverage/ after running tests
27
+ gem 'coveralls', require: false # Test coverage website. Go to https://coveralls.io
28
+ gem 'cucumber-rails', require: false
29
+ gem 'database_cleaner'
30
+ gem 'guard-rspec'
31
+ gem 'jasmine'
32
+ gem 'jslint_on_rails'
33
+ gem 'launchy'
34
+ gem 'rails-i18n' # Provides default i18n for many languages
35
+ gem 'rspec'
36
+ gem 'rspec-mocks'
37
+ gem 'rspec-rails'
38
+ gem 'i18n-spec'
39
+ gem 'shoulda-matchers'
40
+ gem 'sqlite3'
41
+ gem 'poltergeist'
42
+ end
data/Guardfile ADDED
@@ -0,0 +1,8 @@
1
+ # More info at https://github.com/guard/guard#readme
2
+
3
+ guard 'rspec', all_on_start: false, cmd: "bundle exec rspec" do
4
+ watch(%r{^spec/.+_spec\.rb$})
5
+ watch(%r{^lib/active_admin-magicfields/(.+)\.rb$}) { |m| "spec/unit/#{m[1]}_spec.rb" }
6
+ watch('spec/spec_helper.rb') { "spec/" }
7
+ watch('spec/rails_helper.rb') { "spec/" }
8
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Sergeev Peter
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,160 @@
1
+ # Activeadmin Magicfields
2
+
3
+ Activeadmin Magicfields gem is made to bring simple sections and custom field support into your ActiveAdmin. It aims to bring some of Wordpress' [Advanced Custom Fields](http://www.advancedcustomfields.com/) plugin features to Active Admin. Its development was greatly inspired by Petr Sergeev's and Sindre Moen's `activeadmin_polymorphic` [gem](https://github.com/hyperoslo/activeadmin_polymorphic).
4
+
5
+ This gem includes a lot of hacks and tricks, and has been developed mainly as an experiment. Use carefully and at your own risk.
6
+
7
+ Installing the gem enables the user to create section templates (called parts) straight from the admin panel, defining which field types should be included in a part.
8
+
9
+ ![create a part](http://i.imgur.com/XJbuHXx.png)
10
+
11
+ Then, users can add parts to Active Admin models with the click of a button, and simply fill in their content.
12
+
13
+ ![fill the content](http://i.imgur.com/mQ0vSGb.png)
14
+
15
+ # Features
16
+
17
+ * Part creation from custom fields (default field types are: text, textarea, image, checkbox and repeater. See down to add your own field types)
18
+ * Add parts and content to Active Admin model
19
+ * Form Validation
20
+ * Sortable behaviour
21
+ * File uploads
22
+
23
+ # Installation
24
+
25
+ Add this to your Gemfile:
26
+
27
+ ``` ruby
28
+ gem "activeadmin-magicfields"
29
+ ```
30
+
31
+ and run `bundle install`, then `rails g activeadmin-magicfields:install`, and finally `rake db:migrate`.
32
+
33
+ Include assets in js and css manifests
34
+
35
+ ```
36
+ # assets/javascripts/active_admin.js.coffee
37
+ # ...
38
+ #= require activeadmin-magicfields
39
+ # ...
40
+
41
+ // assets/stylesheets/active_admin.scss
42
+ // ...
43
+ @import "activeadmin-magicfields";
44
+ // ...
45
+ ```
46
+
47
+ # Usage
48
+
49
+ To use the gem, you need to enable parts on one of your models
50
+
51
+ ```
52
+ # db/migrate
53
+ class CreateYourModelsParts < ActiveRecord::Migration
54
+ def change
55
+ create_table :your_models_parts do |t|
56
+ t.integer :your_model_id
57
+ t.integer :part_id
58
+ end
59
+ end
60
+ end
61
+ ```
62
+
63
+ ```
64
+ # models/your_model.rb
65
+ class YourModel < ActiveRecord::Base
66
+ # ...
67
+
68
+ has_many :part_objects, dependent: :destroy, inverse_of: :base_model, foreign_key: "base_model_id"
69
+ has_and_belongs_to_many :parts
70
+ accepts_nested_attributes_for :part_objects, allow_destroy: true
71
+
72
+ # ...
73
+ end
74
+ ```
75
+
76
+
77
+ The gem extends activeadmin's form builder, so to enable it you need to override the form builder using `builder` option:
78
+
79
+ ```
80
+ #admin/your_model.rb
81
+ ActiveAdmin.register YourModel do
82
+ # ...
83
+
84
+ form builder: ActiveadminMagicfields::FormBuilder, html: { :enctype => "multipart/form-data" } do |f|
85
+ f.inputs do
86
+ # ...
87
+ f.sections_has_many :parts, collection: Part.includes(:field_templates).all, part_objects: resource.part_objects, sortable: :position
88
+ end
89
+ f.actions
90
+ end
91
+
92
+ # ...
93
+ end
94
+ ```
95
+
96
+ There are few parameters available, currently none of which can be changed:
97
+ * the first is the name of the parts association
98
+ * the second parameter refers to the available parts (previously created in the admin panel)
99
+ * `part_objects` loads the pre-existing parts associated with the edited object
100
+ * `sortable` - enables drag'n'drop for parts
101
+
102
+ # Adding a custom field type
103
+
104
+ To add a custom field type, just create a table called 'field_[your_field_type]s', a model in models/field/your_field_type.rb, and a form partial. This will enable you to use your_field_type as a part's custom field.
105
+
106
+ ```
107
+ # db/migrate
108
+ class CreateFieldYourFieldType < ActiveRecord::Migration
109
+ def change
110
+ create_table :field_your_field_types do |t|
111
+ t.string :title #required for all field types
112
+ t.integer :field_template_id #required for all field types
113
+
114
+ t.[some_database_type] :your_field_type
115
+
116
+ t.timestamps
117
+ end
118
+ end
119
+ end
120
+ ```
121
+
122
+ ```
123
+ # models/field/your_field_type.rb
124
+ module Field
125
+ class YourFieldType < ActiveRecord::Base
126
+ self.table_name = "field_your_field_types"
127
+
128
+ has_one :part_object_field, as: :fieldable
129
+ belongs_to :field_template
130
+
131
+ delegate :title, to: :field_template, allow_nil: true
132
+ delegate :is_required, to: :field_template, allow_nil: true
133
+
134
+ validates :your_field_type, presence: { if: :is_required }
135
+
136
+ end
137
+ end
138
+ ```
139
+
140
+ ```
141
+ <%# views/admin/field_inputs/_your_field_type.html.erb %>
142
+ <%= builder.input field_template.field_type, label: field_template.title, required: field_template.is_required, input_html: {name: form_prefix + builder.object_name.sub('part[', '[') + "[#{field_template.field_type}]" } %>
143
+ ```
144
+
145
+ # Testing
146
+
147
+ As this gem was created the quick'n'dirty way as a fast experiment, tests are not up-to-date at all.
148
+
149
+ # In plan
150
+
151
+ * Fix strong parameters (currently, the gem accepts any parameters submission)
152
+ * Namespace everything to avoid conflicts
153
+ * Make proper tests
154
+ * Make more thing customizable (eg. the names 'parts' and 'part_objects' could be defined by user)
155
+ * Improve the form UI, currently pretty raw.
156
+ * Repeater fields could allow a selection of parts (or define their own).
157
+
158
+ # License
159
+
160
+ [MIT](LICENSE.txt)
data/Rakefile ADDED
@@ -0,0 +1,33 @@
1
+ require 'bundler'
2
+ require 'rake'
3
+ Bundler.setup
4
+ Bundler::GemHelper.install_tasks
5
+
6
+ def cmd(command)
7
+ puts command
8
+ fail unless system command
9
+ end
10
+
11
+ require File.expand_path('../spec/support/detect_rails_version', __FILE__)
12
+
13
+ # Import all our rake tasks
14
+ FileList['tasks/**/*.rake'].each { |task| import task }
15
+
16
+ task default: :test
17
+
18
+ begin
19
+ require 'jasmine'
20
+ load 'jasmine/tasks/jasmine.rake'
21
+ rescue LoadError
22
+ task :jasmine do
23
+ abort 'Jasmine is not available. In order to run jasmine, you must: (sudo) gem install jasmine'
24
+ end
25
+ end
26
+
27
+ task :console do
28
+ require 'irb'
29
+ require 'irb/completion'
30
+
31
+ ARGV.clear
32
+ IRB.start
33
+ end
@@ -0,0 +1,23 @@
1
+ $:.push File.expand_path("../lib", __FILE__)
2
+
3
+ # Maintain your gem's version:
4
+ require "activeadmin-magicfields/version"
5
+
6
+ # Describe your gem and declare its dependencies:
7
+ Gem::Specification.new do |s|
8
+ s.license = "MIT"
9
+ s.name = "activeadmin-magicfields"
10
+ s.version = ActiveadminMagicfields::VERSION
11
+ s.authors = ["Silvain Toromanoff"]
12
+ s.email = ["silvain@agencyleroy.com"]
13
+ s.description = 'This gem extends formtastic\'s form builder to support custom sections and fields in your forms'
14
+ s.summary = 'Custom fields and sections for active admin.'
15
+ s.homepage = ""
16
+
17
+ s.files = `git ls-files`.split("\n").sort
18
+ s.test_files = `git ls-files -- {spec,features}/*`.split("\n")
19
+
20
+ s.add_dependency "activeadmin"
21
+ s.add_dependency "inherited_resources"
22
+ s.add_dependency "paperclip"
23
+ end
@@ -0,0 +1,101 @@
1
+ $ ->
2
+ init_sections_sortable()
3
+ activateAJAXwysiwyg()
4
+ activateAJAXsortable()
5
+
6
+ $(document).on 'click', 'a.button.section_has_many_remove', (e)->
7
+ e.preventDefault()
8
+ parent = $(@).closest '.section_has_many_container'
9
+ to_remove = $(@).closest 'fieldset'
10
+ recompute_positions parent
11
+
12
+ parent.trigger 'section_has_many_remove:before', [to_remove, parent]
13
+ to_remove.remove()
14
+ parent.trigger 'section_has_many_remove:after', [to_remove, parent]
15
+
16
+ $(document).on 'click', 'a.button.section_has_many_add', (e)->
17
+ e.preventDefault()
18
+ parent = $(@).closest '.section_has_many_container'
19
+ parent.trigger before_add = $.Event('section_has_many_add:before'), [parent]
20
+
21
+ unless before_add.isDefaultPrevented()
22
+ index = parent.data('section_has_many_index') || parent.children('fieldset').length - 1
23
+ parent.data has_many_index: ++index
24
+
25
+ regex = new RegExp $(@).data('placeholder'), 'g'
26
+ html = $(@).data('html').replace regex, index
27
+
28
+ fieldset = $(html).insertBefore(@)
29
+ recompute_positions parent
30
+ parent.trigger 'section_has_many_add:after', [fieldset, parent]
31
+
32
+ $('.json_container').on 'change', '.section_type_select', (event) ->
33
+ fieldset = $(this).closest 'fieldset'
34
+
35
+ selectedOption = $(this).find 'option:selected'
36
+ formPath = selectedOption.data 'path'
37
+
38
+ label = $(this).prev 'label'
39
+ label.remove()
40
+
41
+ # hiddenField = $('<input type="hidden" />')
42
+ # hiddenField.attr 'name', $(this).attr('name')
43
+ # hiddenField.val $(this).val()
44
+
45
+ $(this).parents('ol').first().remove()#replaceWith hiddenField
46
+
47
+ newListItem = $ '<li>'
48
+
49
+ formName = $(this).attr('name').split("[parts]")[0]
50
+
51
+ extractAndInsertSectionForm formPath, fieldset, formName
52
+
53
+ activateAJAXwysiwyg = ->
54
+ $(document).ajaxSuccess( ->
55
+ $('.wysihtml5:not(.initialized)').each( ->
56
+ editor = new wysihtml5.Editor($(this).find('textarea').attr('id'), # id of textarea element
57
+ {
58
+ toolbar: $(this).find('.toolbar').attr('id'), # id of toolbar element
59
+ parserRules: wysihtml5ParserRules # defined in parser rules set
60
+ })
61
+ $(@).addClass('initialized')
62
+ )
63
+ )
64
+
65
+ activateAJAXsortable = ->
66
+ $(document).ajaxSuccess( ->
67
+ init_sections_sortable()
68
+ )
69
+
70
+
71
+ window.extractAndInsertSectionForm= (url, target, formName)->
72
+ target = $ target
73
+
74
+ $.get url + "?form_name=#{formName}", (data) ->
75
+ target.prepend data
76
+ return false
77
+
78
+
79
+ init_sections_sortable = ->
80
+ elems = $('.json_container[data-sortable]:not(.ui-sortable)')
81
+ if elems.length
82
+ elems.sortable
83
+ axis: 'y'
84
+ items: '> fieldset',
85
+ handle: '> ol > .handle',
86
+ stop: recompute_positions
87
+ elems.each recompute_positions
88
+
89
+ recompute_positions = (parent)->
90
+ parent = if parent instanceof jQuery then parent else $(@)
91
+ input_name = parent.data 'sortable'
92
+ position = parseInt(parent.data('sortable-start') || 0, 10)
93
+
94
+ parent.children('fieldset').each ->
95
+ # We ignore nested inputs, so when defining your has_many, be sure to keep
96
+ # your sortable input at the root of the has_many block.
97
+ destroy_input = $(@).find "> .input > :input[name$='[_destroy]']"
98
+ sortable_input = $(@).find "> .input > :input[name$='[#{input_name}]']"
99
+
100
+ if sortable_input.length
101
+ sortable_input.val if destroy_input.is ':checked' then '' else position++