activeadmin-magicfields 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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++