effective_bootstrap 0.9.9 → 0.9.14

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.
@@ -0,0 +1,9 @@
1
+ # Prevent non-currency buttons from being pressed
2
+ $(document).on 'click', 'button[data-effective-password]', (event) ->
3
+ $obj = $(event.currentTarget)
4
+ $input = $obj.closest('.input-group')
5
+
6
+ $input.find('input').attr('type', $obj.data('effective-password'))
7
+ $input.find('button[data-effective-password]').toggle()
8
+
9
+ false
@@ -0,0 +1 @@
1
+ //= require ./initialize
@@ -3,6 +3,7 @@
3
3
  @import 'effective_checks/input';
4
4
  @import 'effective_datetime/input';
5
5
  @import 'effective_file/input';
6
+ @import 'effective_has_many/input';
6
7
  @import 'effective_rich_text_area/input';
7
8
  @import 'effective_select/input';
8
9
  @import 'effective_select_or_text/input';
@@ -4,5 +4,5 @@
4
4
  font-size: 0.75rem;
5
5
  margin: 0.25rem 0;
6
6
 
7
- a { padding: 0.25rem 0; }
7
+ a { padding: 0.5rem 0; }
8
8
  }
@@ -0,0 +1,42 @@
1
+ body.dragging,
2
+ body.dragging * {
3
+ cursor: move !important;
4
+ }
5
+
6
+ .form-has-many {
7
+ .has-many-placeholder {
8
+ position: relative;
9
+ height: 2rem;
10
+
11
+ &:before {
12
+ position: absolute;
13
+ content: '';
14
+ background-image: asset-data-url('icons/arrow-right-circle.svg');
15
+ background-repeat: no-repeat;
16
+ height: 2rem;
17
+ width: 2rem;
18
+ }
19
+ }
20
+
21
+ .has-many-fields.dragged {
22
+ position: absolute;
23
+ opacity: 0;
24
+ z-index: 2000;
25
+ .has-many-move { display: none; }
26
+ }
27
+
28
+ .has-many-move svg { margin-top: 6px; }
29
+ .has-many-move { display: none; }
30
+
31
+ .has-many-remove { margin-top: 1.5rem; }
32
+ .has-many-move { margin-top: 1.5rem; }
33
+ }
34
+
35
+ .form-has-many.reordering {
36
+ .has-many-move { display: inline-block; }
37
+ }
38
+
39
+ .form-has-many.tight {
40
+ .has-many-remove { margin-top: 0; }
41
+ .has-many-move { margin-top: 0; }
42
+ }
@@ -1,8 +1,8 @@
1
1
  module EffectiveFormBuilderHelper
2
2
  def effective_form_with(**options, &block)
3
3
  # Compute the default ID
4
- subject = Array(options[:scope] || options[:model]).last
5
- class_name = subject.class.name.parameterize.underscore
4
+ subject = Array(options[:model] || options[:scope]).last
5
+ class_name = (options[:scope] || subject.class.name.parameterize.underscore)
6
6
  unique_id = options.except(:model).hash.abs
7
7
 
8
8
  html_id = if subject.kind_of?(Symbol)
@@ -203,5 +203,19 @@ module Effective
203
203
  Effective::FormLogics::ShowIfAny.new(*args, builder: self).to_html(&block)
204
204
  end
205
205
 
206
+ # Has Many
207
+ def has_many(name, collection = nil, options = {}, &block)
208
+ association = object.class.reflect_on_all_associations.find { |a| a.name == name }
209
+ raise("expected #{object.class.name} to has_many :#{name}") if association.blank?
210
+
211
+ nested_attributes_options = (object.class.nested_attributes_options || {})[name]
212
+ raise("expected #{object.class.name} to accepts_nested_attributes_for :#{name}") if nested_attributes_options.blank?
213
+
214
+ options = collection if collection.kind_of?(Hash)
215
+ options.merge!(collection: collection) if collection && !collection.kind_of?(Hash)
216
+
217
+ Effective::FormInputs::HasMany.new(name, options, builder: self).to_html(&block)
218
+ end
219
+
206
220
  end
207
221
  end
@@ -50,18 +50,29 @@ module Effective
50
50
  end
51
51
 
52
52
  def build_label
53
- return BLANK if options[:label] == false
53
+ return BLANK if options[:label] == false && !actions?
54
54
  return BLANK if name.kind_of?(NilClass)
55
55
 
56
- text = (options[:label].delete(:text) || (object.class.human_attribute_name(name) if object) || BLANK).html_safe
56
+ text = begin
57
+ if options[:label] == false
58
+ nil
59
+ elsif options[:label].key?(:text)
60
+ options[:label].delete(:text)
61
+ elsif object.present?
62
+ object.class.human_attribute_name(name)
63
+ end || BLANK
64
+ end.html_safe
65
+
66
+ actions = if !disabled? && actions?
67
+ content_tag(:div, class: 'effective-checks-actions text-muted') do
68
+ link_to('Select All', '#', 'data-effective-checks-all': true) + ' - ' + link_to('Select None', '#', 'data-effective-checks-none': true)
69
+ end
70
+ end
57
71
 
58
72
  content_tag(:label, options[:label]) do
59
- text + content_tag(:div, class: 'effective-checks-actions text-muted') do
60
- unless disabled? || !actions?
61
- link_to('Select All', '#', 'data-effective-checks-all': true) + ' - ' + link_to('Select None', '#', 'data-effective-checks-none': true)
62
- end
63
- end
73
+ [text, actions].compact.join.html_safe
64
74
  end
75
+
65
76
  end
66
77
 
67
78
  def build_item(builder)
@@ -91,7 +102,7 @@ module Effective
91
102
 
92
103
  def actions? # default true
93
104
  return @actions unless @actions.nil?
94
- @actions = (options.delete(:actions) != false)
105
+ @actions = (options[:input].delete(:actions) != false)
95
106
  end
96
107
 
97
108
  end
@@ -0,0 +1,207 @@
1
+ module Effective
2
+ module FormInputs
3
+ class HasMany < Effective::FormInput
4
+ BLANK = ''.html_safe
5
+
6
+ def to_html(&block)
7
+ object.send(name).build() if build? && collection.blank?
8
+
9
+ errors = (@builder.error(name) if errors?) || BLANK
10
+
11
+ errors + content_tag(:div, options[:input]) do
12
+ has_many_fields_for(block) + has_many_links_for(block)
13
+ end
14
+ end
15
+
16
+ def input_html_options
17
+ { class: 'form-has-many mb-4' }
18
+ end
19
+
20
+ def input_js_options
21
+ { sortable: true }
22
+ end
23
+
24
+ def collection
25
+ Array(options[:input][:collection] || object.send(name))
26
+ end
27
+
28
+ # cards: false
29
+ def display
30
+ @display ||= (options[:input].delete(:cards) ? :cards : :rows)
31
+ end
32
+
33
+ # build: true
34
+ def build?
35
+ return @build unless @build.nil?
36
+
37
+ @build ||= begin
38
+ build = options[:input].delete(:build)
39
+ build.nil? ? true : build
40
+ end
41
+ end
42
+
43
+ # add: true
44
+ def add?
45
+ return @add unless @add.nil?
46
+
47
+ @add ||= begin
48
+ add = options[:input].delete(:add)
49
+ add.nil? ? true : add
50
+ end
51
+ end
52
+
53
+ # errors: true
54
+ def errors?
55
+ return @errors unless @errors.nil?
56
+
57
+ @errors ||= begin
58
+ errors = options[:input].delete(:errors)
59
+ errors.nil? ? true : errors
60
+ end
61
+ end
62
+
63
+ # remove: true
64
+ def remove?
65
+ return @remove unless @remove.nil?
66
+
67
+ @remove ||= begin
68
+ remove = options[:input].delete(:remove)
69
+
70
+ if remove != nil
71
+ remove
72
+ else
73
+ opts = (object.class.nested_attributes_options[name] || {})
74
+ opts[:update_only] != true && opts[:allow_destroy] != false
75
+ end
76
+ end
77
+ end
78
+
79
+ # reorder: true
80
+ def reorder?
81
+ return @reorder unless @reorder.nil?
82
+
83
+ @reorder ||= begin
84
+ reorder = options[:input].delete(:reorder)
85
+
86
+ if reorder != nil
87
+ reorder
88
+ else
89
+ build_resource().class.columns_hash['position']&.type == :integer
90
+ end
91
+ end
92
+ end
93
+
94
+ private
95
+
96
+ def has_many_fields_for(block)
97
+ collection.map { |resource| render_resource(resource, block) }.join.html_safe
98
+ end
99
+
100
+ def has_many_links_for(block)
101
+ return BLANK unless add? || reorder?
102
+
103
+ content_tag(:div, class: 'has-many-links text-center mt-2') do
104
+ [*(link_to_add(block) if add?), *(link_to_reorder(block) if reorder?)].join(' ').html_safe
105
+ end
106
+ end
107
+
108
+ def render_resource(resource, block)
109
+ remove = BLANK
110
+
111
+ content = @builder.fields_for(name, resource) do |form|
112
+ fields = block.call(form)
113
+
114
+ remove += form.super_hidden_field(:_destroy) if remove? && resource.persisted?
115
+ remove += form.super_hidden_field(:position) if reorder? && !fields.include?('][position]')
116
+
117
+ fields
118
+ end
119
+
120
+ remove += link_to_remove(resource) if remove?
121
+
122
+ content_tag(:div, render_fields(content, remove), class: 'has-many-fields')
123
+ end
124
+
125
+ def render_fields(content, remove)
126
+ case display
127
+ when :rows
128
+ content_tag(:div, class: 'form-row') do
129
+ (reorder? ? content_tag(:div, has_many_move, class: 'col-auto') : BLANK) +
130
+ content_tag(:div, content, class: 'col mr-auto') +
131
+ content_tag(:div, remove, class: 'col-auto')
132
+ end
133
+ when :cards
134
+ raise('unsupported')
135
+ else
136
+ content + remove
137
+ end
138
+ end
139
+
140
+ def render_template(block)
141
+ resource = build_resource()
142
+ index = collection.length
143
+
144
+ html = render_resource(resource, block)
145
+
146
+ unless html.include?("#{name}_attributes][#{index}]")
147
+ raise('unexpected index. unable to render resource template.')
148
+ end
149
+
150
+ html.gsub!("#{name}_attributes][#{index}]", "#{name}_attributes][HASMANYINDEX]")
151
+ html.gsub!("#{name}_attributes_#{index}_", "#{name}_attributes_HASMANYINDEX_")
152
+
153
+ html.html_safe
154
+ end
155
+
156
+ def link_to_add(block)
157
+ content_tag(
158
+ :button,
159
+ icon('plus-circle') + 'Add Another',
160
+ class: 'has-many-add btn btn-secondary',
161
+ title: 'Add Another',
162
+ data: {
163
+ 'effective-form-has-many-add': true,
164
+ 'effective-form-has-many-template': render_template(block)
165
+ }
166
+ )
167
+ end
168
+
169
+ def link_to_reorder(block)
170
+ content_tag(
171
+ :button,
172
+ icon('list') + 'Reorder',
173
+ class: 'has-many-reorder btn btn-secondary',
174
+ title: 'Reorder',
175
+ data: {
176
+ 'effective-form-has-many-reorder': true,
177
+ }
178
+ )
179
+ end
180
+
181
+ def link_to_remove(resource)
182
+ content_tag(
183
+ :button,
184
+ icon('trash-2') + 'Remove',
185
+ class: 'has-many-remove btn btn-danger',
186
+ title: 'Remove',
187
+ data: {
188
+ 'confirm': "Remove #{resource}?",
189
+ 'effective-form-has-many-remove': true,
190
+ }
191
+ )
192
+ end
193
+
194
+ def has_many_move
195
+ @has_many_move ||= content_tag(:span, icon('move'), class: 'has-many-move')
196
+ end
197
+
198
+ def build_resource
199
+ # Using .new() here seems like it should work but it doesn't. It changes the index
200
+ @build_resource ||= object.send(name).build().tap do |resource|
201
+ object.send(name).delete(resource)
202
+ end
203
+ end
204
+
205
+ end
206
+ end
207
+ end
@@ -3,11 +3,25 @@ module Effective
3
3
  class PasswordField < Effective::FormInput
4
4
 
5
5
  def input_html_options
6
- { class: 'form-control', id: tag_id }
6
+ { class: 'form-control effective_password', id: tag_id }
7
7
  end
8
8
 
9
9
  def input_group_options
10
- { input_group: { class: 'input-group' }, prepend: content_tag(:span, icon('lock'), class: 'input-group-text') }
10
+ { input_group: { class: 'input-group' }, append: eyes }
11
+ end
12
+
13
+ def eyes
14
+ content_tag(:button, icon('eye'),
15
+ class: 'btn input-group-text',
16
+ title: 'Show password',
17
+ 'data-effective-password': 'text'
18
+ ) +
19
+ content_tag(:button, icon('eye-off'),
20
+ class: 'btn input-group-text',
21
+ title: 'Hide password',
22
+ style: 'display: none;',
23
+ 'data-effective-password': 'password'
24
+ )
11
25
  end
12
26
 
13
27
  def feedback_options
@@ -1,3 +1,3 @@
1
1
  module EffectiveBootstrap
2
- VERSION = '0.9.9'.freeze
2
+ VERSION = '0.9.14'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: effective_bootstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.9
4
+ version: 0.9.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Code and Effect
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-20 00:00:00.000000000 Z
11
+ date: 2021-02-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: haml
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
97
111
  description: Everything you need to get set up with bootstrap 4.
98
112
  email:
99
113
  - info@codeandeffect.com
@@ -419,10 +433,15 @@ files:
419
433
  - app/assets/javascripts/effective_editor/quill.js
420
434
  - app/assets/javascripts/effective_file/initialize.js.coffee
421
435
  - app/assets/javascripts/effective_file/input.js
436
+ - app/assets/javascripts/effective_has_many/initialize.js.coffee
437
+ - app/assets/javascripts/effective_has_many/input.js
438
+ - app/assets/javascripts/effective_has_many/jquery.sortable.js
422
439
  - app/assets/javascripts/effective_integer/initialize.js.coffee
423
440
  - app/assets/javascripts/effective_integer/input.js
424
441
  - app/assets/javascripts/effective_number_text/initialize.js.coffee
425
442
  - app/assets/javascripts/effective_number_text/input.js
443
+ - app/assets/javascripts/effective_password/initialize.js.coffee
444
+ - app/assets/javascripts/effective_password/input.js
426
445
  - app/assets/javascripts/effective_percent/initialize.js.coffee
427
446
  - app/assets/javascripts/effective_percent/input.js
428
447
  - app/assets/javascripts/effective_phone/initialize.js.coffee
@@ -584,6 +603,7 @@ files:
584
603
  - app/assets/stylesheets/effective_editor/overrides.scss
585
604
  - app/assets/stylesheets/effective_editor/quill.scss
586
605
  - app/assets/stylesheets/effective_file/input.scss
606
+ - app/assets/stylesheets/effective_has_many/input.scss
587
607
  - app/assets/stylesheets/effective_radio/input.scss
588
608
  - app/assets/stylesheets/effective_rich_text_area/input.scss
589
609
  - app/assets/stylesheets/effective_select/bootstrap-theme.css
@@ -613,6 +633,7 @@ files:
613
633
  - app/models/effective/form_inputs/file_field.rb
614
634
  - app/models/effective/form_inputs/float_field.rb
615
635
  - app/models/effective/form_inputs/form_group.rb
636
+ - app/models/effective/form_inputs/has_many.rb
616
637
  - app/models/effective/form_inputs/hidden_field.rb
617
638
  - app/models/effective/form_inputs/integer_field.rb
618
639
  - app/models/effective/form_inputs/number_field.rb