bootstrap_form_extensions 1.0.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 (97) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +34 -0
  4. data/app/assets/javascripts/bootstrap_form_extensions/arrayed_field.js +70 -0
  5. data/app/assets/javascripts/bootstrap_form_extensions/bootstrap-timepicker.min.js +5 -0
  6. data/app/assets/javascripts/bootstrap_form_extensions/index.js +2 -0
  7. data/app/assets/javascripts/bootstrap_form_extensions/jquery.html5data.min.js +7 -0
  8. data/app/assets/javascripts/bootstrap_form_extensions/scheduler.js +226 -0
  9. data/app/assets/javascripts/bootstrap_form_extensions/select_or_new.js +76 -0
  10. data/app/assets/javascripts/bootstrap_form_extensions/time_picker.js +61 -0
  11. data/app/assets/javascripts/bootstrap_form_extensions/timespan.js +60 -0
  12. data/app/assets/stylesheets/bootstrap_form_extensions/bootstrap-timepicker.min.css +10 -0
  13. data/app/assets/stylesheets/bootstrap_form_extensions/common.css +11 -0
  14. data/app/assets/stylesheets/bootstrap_form_extensions/index.css +4 -0
  15. data/app/assets/stylesheets/bootstrap_form_extensions/scheduler.css +31 -0
  16. data/app/assets/stylesheets/bootstrap_form_extensions/submit_bar.css +4 -0
  17. data/app/views/bootstrap_form_extensions/_submit_bar.html.erb +36 -0
  18. data/lib/bootstrap_form_extensions.rb +22 -0
  19. data/lib/bootstrap_form_extensions/arrayed_field.rb +107 -0
  20. data/lib/bootstrap_form_extensions/date_time_pickers.rb +71 -0
  21. data/lib/bootstrap_form_extensions/helpers.rb +18 -0
  22. data/lib/bootstrap_form_extensions/scheduler.rb +72 -0
  23. data/lib/bootstrap_form_extensions/select_or_new.rb +36 -0
  24. data/lib/bootstrap_form_extensions/submit_bar.rb +65 -0
  25. data/lib/bootstrap_form_extensions/timespan.rb +55 -0
  26. data/lib/bootstrap_form_extensions/version.rb +3 -0
  27. data/lib/tasks/rails_bootstrap_form_extensions_tasks.rake +4 -0
  28. data/test/arrayed_field_test.rb +63 -0
  29. data/test/bootstrap_form_extensions_test.rb +7 -0
  30. data/test/date_time_pickers_test.rb +50 -0
  31. data/test/dummy/README.rdoc +28 -0
  32. data/test/dummy/Rakefile +6 -0
  33. data/test/dummy/app/assets/javascripts/application.js +13 -0
  34. data/test/dummy/app/assets/stylesheets/application.css +15 -0
  35. data/test/dummy/app/controllers/application_controller.rb +5 -0
  36. data/test/dummy/app/helpers/application_helper.rb +2 -0
  37. data/test/dummy/app/models/category.rb +7 -0
  38. data/test/dummy/app/models/thing.rb +46 -0
  39. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  40. data/test/dummy/bin/bundle +3 -0
  41. data/test/dummy/bin/rails +4 -0
  42. data/test/dummy/bin/rake +4 -0
  43. data/test/dummy/bin/setup +29 -0
  44. data/test/dummy/config.ru +4 -0
  45. data/test/dummy/config/application.rb +26 -0
  46. data/test/dummy/config/boot.rb +5 -0
  47. data/test/dummy/config/database.yml +25 -0
  48. data/test/dummy/config/environment.rb +5 -0
  49. data/test/dummy/config/environments/development.rb +41 -0
  50. data/test/dummy/config/environments/production.rb +79 -0
  51. data/test/dummy/config/environments/test.rb +42 -0
  52. data/test/dummy/config/initializers/assets.rb +11 -0
  53. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  54. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  55. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  56. data/test/dummy/config/initializers/inflections.rb +16 -0
  57. data/test/dummy/config/initializers/mime_types.rb +4 -0
  58. data/test/dummy/config/initializers/session_store.rb +3 -0
  59. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  60. data/test/dummy/config/locales/en.yml +23 -0
  61. data/test/dummy/config/routes.rb +3 -0
  62. data/test/dummy/config/secrets.yml +22 -0
  63. data/test/dummy/db/migrate/20150918185031_create_things.rb +9 -0
  64. data/test/dummy/db/migrate/20150924203053_add_timespan.rb +7 -0
  65. data/test/dummy/db/migrate/20150929213249_add_arrayed_field.rb +7 -0
  66. data/test/dummy/db/migrate/20151006171627_add_another_arrayed_field.rb +7 -0
  67. data/test/dummy/db/migrate/20151006181943_add_json_field.rb +7 -0
  68. data/test/dummy/db/migrate/20151007213131_add_scheduler_field.rb +7 -0
  69. data/test/dummy/db/migrate/20151030194330_add_date_time.rb +7 -0
  70. data/test/dummy/db/migrate/20151106165522_add_category.rb +10 -0
  71. data/test/dummy/db/schema.rb +31 -0
  72. data/test/dummy/db/test.sqlite3 +0 -0
  73. data/test/dummy/log/development.log +0 -0
  74. data/test/dummy/log/test.log +1997 -0
  75. data/test/dummy/public/404.html +67 -0
  76. data/test/dummy/public/422.html +67 -0
  77. data/test/dummy/public/500.html +66 -0
  78. data/test/dummy/public/favicon.ico +0 -0
  79. data/test/dummy/test/fixtures/things.yml +8 -0
  80. data/test/javascripts/arrayed_field_spec.js +101 -0
  81. data/test/javascripts/helpers/function_bind_polyfill_for_phantomjs.js +32 -0
  82. data/test/javascripts/helpers/jasmine-jquery.js +838 -0
  83. data/test/javascripts/scheduler_spec.js +354 -0
  84. data/test/javascripts/select_or_new_spec.js +113 -0
  85. data/test/javascripts/support/jasmine.yml +127 -0
  86. data/test/javascripts/support/jasmine_helper.rb +19 -0
  87. data/test/javascripts/time_picker_spec.js +42 -0
  88. data/test/javascripts/timespan_spec.js +81 -0
  89. data/test/javascripts/vendor/bootstrap.min.js +7 -0
  90. data/test/javascripts/vendor/jquery-2.1.4.min.js +4 -0
  91. data/test/scheduler_serializer_test.rb +200 -0
  92. data/test/scheduler_test.rb +15 -0
  93. data/test/select_or_new_test.rb +37 -0
  94. data/test/submit_bar_test.rb +112 -0
  95. data/test/test_helper.rb +37 -0
  96. data/test/timespan_test.rb +47 -0
  97. metadata +291 -0
@@ -0,0 +1,61 @@
1
+ +function ($) {
2
+ 'use strict';
3
+
4
+
5
+ // TIME PICKER CLASS DEFINITION
6
+ // ============================
7
+
8
+ var TimePicker = function (element, options) {
9
+ var defaults = {
10
+ minuteStep: 1,
11
+ showSeconds: true,
12
+ secondStep: 1,
13
+ showMeridian: false,
14
+ defaultTime: false
15
+ }
16
+ $(element).timepicker($.extend(defaults, options))
17
+ }
18
+
19
+ TimePicker.VERSION = '1.0.0'
20
+
21
+
22
+ // TIME PICKER PLUGIN DEFINITION
23
+ // =============================
24
+
25
+ function Plugin(options) {
26
+ return $(this).each(function () {
27
+ var $this = $(this)
28
+ var data = $this.data('bsfe.timepicker')
29
+
30
+ if (!data) $this.data('bsfe.timepicker', (data = new TimePicker(this, options)))
31
+ })
32
+ }
33
+
34
+ var old = $.fn.timePicker
35
+
36
+ $.fn.timePicker = Plugin
37
+ $.fn.timePicker.Constructor = TimePicker
38
+
39
+
40
+ // TIME PICKER NO CONFLICT
41
+ // =======================
42
+
43
+ $.fn.timePicker.noConflict = function () {
44
+ $.fn.timePicker = old
45
+ return this
46
+ }
47
+
48
+
49
+ // TIME PICKER DATA-API
50
+ // ====================
51
+
52
+ $(window).on('load page:load page:restore', function () {
53
+ $('[data-provide="timepicker"]').each(function () {
54
+ var $picker = $(this)
55
+ var options = $picker.html5data('time')
56
+
57
+ Plugin.call($picker, options)
58
+ })
59
+ })
60
+
61
+ }(jQuery);
@@ -0,0 +1,60 @@
1
+ +function ($) {
2
+ 'use strict';
3
+
4
+ // TIMESPAN CLASS DEFINITION
5
+ // =========================
6
+
7
+ var Timespan = function (element) {
8
+ this.$container = $(element)
9
+ this.$container.on('change.bsfe.timespan.data-api', '.timespan-quantity, .timespan-unit', this.updateSeconds.bind(this))
10
+ }
11
+
12
+ Timespan.VERSION = '1.0.0'
13
+
14
+ Timespan.prototype.updateSeconds = function (e) {
15
+ var hidden = this.$container.find('.timespan-seconds')
16
+ var quantity = this.$container.find('.timespan-quantity')
17
+ var unit = this.$container.find('.timespan-unit')
18
+ var seconds = +quantity.val() * +unit.val()
19
+
20
+ hidden.val(seconds)
21
+ }
22
+
23
+
24
+ // TIMESPAN PLUGIN DEFINITION
25
+ // ==========================
26
+
27
+ function Plugin() {
28
+ return $(this).each(function () {
29
+ var $this = $(this)
30
+ var data = $this.data('bsfe.timespan')
31
+
32
+ if (!data) $this.data('bsfe.timespan', (data = new Timespan(this)))
33
+ })
34
+ }
35
+
36
+ var old = $.fn.timespan
37
+
38
+ $.fn.timespan = Plugin
39
+ $.fn.timespan.Constructor = Timespan
40
+
41
+
42
+ // TIMESPAN NO CONFLICT
43
+ // ====================
44
+
45
+ $.fn.timespan.noConflict = function () {
46
+ $.fn.timespan = old
47
+ return this
48
+ }
49
+
50
+
51
+ // TIMESPAN DATA-API
52
+ // =================
53
+
54
+ $(window).on('load page:load page:restore', function () {
55
+ $('[data-timespan]').each(function () {
56
+ Plugin.call(this)
57
+ })
58
+ })
59
+
60
+ }(jQuery);
@@ -0,0 +1,10 @@
1
+ /*!
2
+ * Timepicker Component for Twitter Bootstrap
3
+ *
4
+ * Copyright 2013 Joris de Wit
5
+ *
6
+ * Contributors https://github.com/jdewit/bootstrap-timepicker/graphs/contributors
7
+ *
8
+ * For the full copyright and license information, please view the LICENSE
9
+ * file that was distributed with this source code.
10
+ */.bootstrap-timepicker{position:relative}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu{left:auto;right:0}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:before{left:auto;right:12px}.bootstrap-timepicker.pull-right .bootstrap-timepicker-widget.dropdown-menu:after{left:auto;right:13px}.bootstrap-timepicker .input-group-addon{cursor:pointer}.bootstrap-timepicker .input-group-addon i{display:inline-block;width:16px;height:16px}.bootstrap-timepicker-widget.dropdown-menu{padding:4px}.bootstrap-timepicker-widget.dropdown-menu.open{display:inline-block}.bootstrap-timepicker-widget.dropdown-menu:before{border-bottom:7px solid rgba(0,0,0,0.2);border-left:7px solid transparent;border-right:7px solid transparent;content:"";display:inline-block;position:absolute}.bootstrap-timepicker-widget.dropdown-menu:after{border-bottom:6px solid #fff;border-left:6px solid transparent;border-right:6px solid transparent;content:"";display:inline-block;position:absolute}.bootstrap-timepicker-widget.timepicker-orient-left:before{left:6px}.bootstrap-timepicker-widget.timepicker-orient-left:after{left:7px}.bootstrap-timepicker-widget.timepicker-orient-right:before{right:6px}.bootstrap-timepicker-widget.timepicker-orient-right:after{right:7px}.bootstrap-timepicker-widget.timepicker-orient-top:before{top:-7px}.bootstrap-timepicker-widget.timepicker-orient-top:after{top:-6px}.bootstrap-timepicker-widget.timepicker-orient-bottom:before{bottom:-7px;border-bottom:0;border-top:7px solid #999}.bootstrap-timepicker-widget.timepicker-orient-bottom:after{bottom:-6px;border-bottom:0;border-top:6px solid #fff}.bootstrap-timepicker-widget a.btn,.bootstrap-timepicker-widget input{border-radius:4px}.bootstrap-timepicker-widget table{width:100%;margin:0}.bootstrap-timepicker-widget table td{text-align:center;height:30px;margin:0;padding:2px}.bootstrap-timepicker-widget table td:not(.separator){min-width:30px}.bootstrap-timepicker-widget table td span{width:100%}.bootstrap-timepicker-widget table td a{border:1px transparent solid;width:100%;display:inline-block;margin:0;padding:8px 0;outline:0;color:#333}.bootstrap-timepicker-widget table td a:hover{text-decoration:none;background-color:#eee;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;border-color:#ddd}.bootstrap-timepicker-widget table td a i{margin-top:2px;font-size:18px}.bootstrap-timepicker-widget table td input{width:25px;margin:0;text-align:center}.bootstrap-timepicker-widget .modal-content{padding:4px}@media(min-width:767px){.bootstrap-timepicker-widget.modal{width:200px;margin-left:-100px}}@media(max-width:767px){.bootstrap-timepicker{width:100%}.bootstrap-timepicker .dropdown-menu{width:100%}}
@@ -0,0 +1,11 @@
1
+ // Vertical space
2
+ .voffset { margin-top: 2px; }
3
+ .voffset1 { margin-top: 5px; }
4
+ .voffset2 { margin-top: 10px; }
5
+ .voffset3 { margin-top: 15px; }
6
+ .voffset4 { margin-top: 30px; }
7
+ .voffset5 { margin-top: 40px; }
8
+ .voffset6 { margin-top: 60px; }
9
+ .voffset7 { margin-top: 80px; }
10
+ .voffset8 { margin-top: 100px; }
11
+ .voffset9 { margin-top: 150px; }
@@ -0,0 +1,4 @@
1
+ /*
2
+ *= require bootstrap-datepicker3
3
+ *= require_tree .
4
+ */
@@ -0,0 +1,31 @@
1
+ .scheduler-badge {
2
+ }
3
+ .scheduler-badge td {
4
+ cursor: pointer;
5
+ width: 13px;
6
+ line-height: 0.5em;
7
+ border: 1px solid grey;
8
+ }
9
+ .scheduler-badge td.on {
10
+ background-color: #dff0d8;
11
+ }
12
+ .scheduler-editor a {
13
+ color: #777777;
14
+ }
15
+ .scheduler-editor th {
16
+ width: 38px;
17
+ text-align: center;
18
+ }
19
+ .scheduler-editor th a {
20
+ font-weight: normal;
21
+ }
22
+ .scheduler-editor td.clickable {
23
+ border: 1px solid lightgrey;
24
+ cursor: pointer;
25
+ }
26
+ .scheduler-editor td.clickable.on {
27
+ background-color: #dff0d8;
28
+ }
29
+ #scheduler-container a {
30
+ cursor: pointer;
31
+ }
@@ -0,0 +1,4 @@
1
+ .submitbar-next-action-menu > li > button.btn-link {
2
+ width: 100%;
3
+ text-align: left;
4
+ }
@@ -0,0 +1,36 @@
1
+ <div class="form-group">
2
+ <div class='pull-left submitbar-left'>
3
+ <% if show_submit_button %>
4
+ <div class="btn-group dropup submitbar-submit-group">
5
+ <button type="submit" class="btn btn-primary submitbar-save"><%= submit_button_text %></button>
6
+ <% if show_submit_menu %>
7
+ <button type="button" class="btn btn-primary dropdown-toggle submitbar-next-action-toggle" data-toggle="dropdown">
8
+ <span class="caret"></span>
9
+ <span class="sr-only">Toggle Dropdown</span>
10
+ </button>
11
+ <ul class="dropdown-menu submitbar-next-action-menu" role="menu">
12
+ <% if show_submit_and_dup_button %>
13
+ <li><button type="submit" name="next_action" class="btn-link submitbar-duplicate" value="duplicate"><%= submit_button_text %> and duplicate</button></li>
14
+ <% end %>
15
+ <% if show_submit_and_new_button %>
16
+ <li><button type="submit" name="next_action" class="btn-link submitbar-new" value="new"><%= submit_button_text %> and new</button></li>
17
+ <% end %>
18
+ </ul>
19
+ <% end %>
20
+ </div>
21
+ <% end %>
22
+ <% extra_buttons.each do |text:, url:, options:| %>
23
+ <%= link_to text, url, options %>
24
+ <% end %>
25
+ <% if show_cancel_button %>
26
+ <%= link_to cancel_button_text, cancel_button_url, class: "btn btn-default submitbar-cancel", rel: "nofollow" %>
27
+ <% end %>
28
+ </div>
29
+ <% if right_buttons.any? %>
30
+ <div class='pull-right submitbar-right'>
31
+ <% right_buttons.each do |text:, url:, options:| %>
32
+ <%= link_to text, url, options %>
33
+ <% end %>
34
+ </div>
35
+ <% end %>
36
+ </div>
@@ -0,0 +1,22 @@
1
+ require 'bootstrap_form/form_builder'
2
+ require 'bootstrap_form_extensions/submit_bar'
3
+ require 'bootstrap_form_extensions/timespan'
4
+ require 'bootstrap_form_extensions/arrayed_field'
5
+ require 'bootstrap_form_extensions/scheduler'
6
+ require 'bootstrap_form_extensions/date_time_pickers'
7
+ require 'bootstrap-datepicker-rails'
8
+ require 'bootstrap_form_extensions/select_or_new'
9
+
10
+ module BootstrapFormExtensions
11
+ module Rails
12
+ class Engine < ::Rails::Engine
13
+ end
14
+ end
15
+ end
16
+
17
+ BootstrapForm::FormBuilder.send :include, BootstrapFormExtensions::SubmitBar,
18
+ BootstrapFormExtensions::Timespan,
19
+ BootstrapFormExtensions::ArrayedField,
20
+ BootstrapFormExtensions::Scheduler,
21
+ BootstrapFormExtensions::DateTimePickers,
22
+ BootstrapFormExtensions::SelectOrNew
@@ -0,0 +1,107 @@
1
+ require 'bootstrap_form_extensions/helpers'
2
+
3
+ module BootstrapFormExtensions
4
+
5
+ module ArrayedField
6
+
7
+ include BootstrapFormExtensions::Helpers
8
+
9
+ ARRAYED_HELPERS = %w[ url_field text_field ]
10
+ ARRAYED_HELPERS.each do |method_name|
11
+ define_method "arrayed_#{method_name}" do |field, **options|
12
+ arrayed_field method_name, field, options
13
+ end
14
+ end
15
+
16
+ def arrayed_json_field method, fields, **options
17
+ fields = parse_fields_for_arrayed_json fields
18
+ col_class = options.fetch :col_class, 'col-sm-2'
19
+
20
+ blueprint = fields.map do |field|
21
+ case field[:type]
22
+ when :select
23
+ @template.select_tag nil, @template.options_for_select(field[:options]), class: 'form-control', data: { name: "#{object_name}[#{method}][][#{field[:name]}]" }
24
+ else
25
+ @template.text_field_tag nil, nil, class: 'form-control', placeholder: field[:name], data: { name: "#{object_name}[#{method}][][#{field[:name]}]" }
26
+ end
27
+ end
28
+ blueprint = arrayed_field_row_builder blueprint, col_class: col_class
29
+ blueprint = arrayed_field_blueprint_builder blueprint
30
+
31
+ form_group_builder_for_arrayed_field method, blueprint, options do |values|
32
+ inputs = fields.map do |field|
33
+ case field[:type]
34
+ when :select
35
+ @template.select_tag nil, @template.options_for_select(field[:options], values[field[:name].to_s]), class: 'form-control'
36
+ else
37
+ @template.text_field_tag "#{object_name}[#{method}][][#{field[:name]}]", values[field[:name].to_s], class: 'form-control', placeholder: field[:name]
38
+ end
39
+ end
40
+ arrayed_field_row_builder inputs, col_class: col_class
41
+ end
42
+ end
43
+
44
+ private
45
+
46
+ def arrayed_field field_type, field, **options
47
+ field_tag = "#{field_type}_tag".to_sym
48
+
49
+ blueprint = @template.send field_tag, nil, nil, class: 'form-control', data: { name: "#{object_name}[#{field}][]" }
50
+ blueprint = arrayed_field_row_builder blueprint
51
+ blueprint = arrayed_field_blueprint_builder blueprint
52
+
53
+ form_group_builder_for_arrayed_field field, blueprint, options do |value|
54
+ input = @template.send field_tag, "#{object_name}[#{field}][]", value, class: 'form-control'
55
+ arrayed_field_row_builder input
56
+ end
57
+ end
58
+
59
+ def parse_fields_for_arrayed_json fields
60
+ fields.map do |field|
61
+ if field.is_a? Hash
62
+ name = field.keys.first
63
+ values = field.values.first
64
+ type = values.fetch :type, :text
65
+ select_options = values.fetch :options, []
66
+ { name: name, type: type, options: select_options }
67
+ else
68
+ { name: field, type: :text }
69
+ end
70
+ end
71
+ end
72
+
73
+ def arrayed_field_row_builder args, col_class: 'col-sm-11'
74
+ args = [ args ].flatten
75
+
76
+ inputs = args.inject(''.html_safe) do |content, input|
77
+ content << content_tag(:div, input, class: col_class)
78
+ end
79
+
80
+ remove_button = @template.link_to glyphicon_tag('trash'), 'javascript:void(0);', class: 'btn btn-default remove-arrayed-field-row'
81
+ remove_button = content_tag :div, remove_button, class: 'col-sm-1'
82
+
83
+ content_tag :div, inputs + remove_button, class: 'row voffset1'
84
+ end
85
+
86
+ def arrayed_field_blueprint_builder row
87
+ content_tag :div, row, class: 'blueprint-for-arrayed-field', style: 'display:none;'
88
+ end
89
+
90
+ def form_group_builder_for_arrayed_field method, blueprint, options, &row_builder_block
91
+ add_button = @template.link_to glyphicon_tag('plus'), 'javascript:void(0);', class: 'btn btn-default add-arrayed-field-row'
92
+ add_button = content_tag :div, add_button, class: 'col-sm-12'
93
+ add_button = content_tag :div, add_button, class: 'row voffset1'
94
+
95
+ rows = object.send(method) rescue []
96
+ rows = [] unless rows.is_a? Array
97
+ rows = rows.inject(''.html_safe) { |content, value| content << row_builder_block.call(value) }
98
+ rows = content_tag :div, rows, class: 'arrayed-field-rows'
99
+
100
+ form_group_builder method, options do
101
+ content_tag :div, blueprint + rows + add_button, data: { arrayed_field: true }
102
+ end
103
+ end
104
+
105
+ end
106
+
107
+ end
@@ -0,0 +1,71 @@
1
+ module BootstrapFormExtensions
2
+
3
+ module DateTimePickers
4
+
5
+ include BootstrapFormExtensions::Helpers
6
+
7
+ def date_time_picker attribute, **options
8
+ name = attribute.to_s.sub /_at$/, ''
9
+ date_method = options.delete(:date_method) { "#{name}_date".to_sym }
10
+ time_method = options.delete(:time_method) { "#{name}_time".to_sym }
11
+
12
+ date_options = options.delete(:date_options) { {} }
13
+ time_options = options.delete(:time_options) { {} }
14
+ date_options[:class] = [ 'form-control', date_options[:class] ].compact.uniq.join(' ')
15
+ time_options[:class] = [ 'form-control', time_options[:class] ].compact.uniq.join(' ')
16
+
17
+ # TODO: Replace for these commented out lines, once this pull request is merged: https://github.com/bootstrap-ruby/rails-bootstrap-forms/pull/238
18
+ # options[:wrapper] ||= {}
19
+ # options[:wrapper].merge! inline: true
20
+ options[:control_col] = 'col-sm-10 form-inline'
21
+
22
+ date_picker_html = content_tag :div, date_picker_builder(date_method, date_options), class: 'form-group'
23
+ time_picker_html = content_tag :div, time_picker_builder(time_method, time_options), class: 'form-group'
24
+ form_group_builder(attribute, options) { date_picker_html + '&nbsp;&nbsp;'.html_safe + time_picker_html }
25
+ end
26
+
27
+ def date_picker method, **options
28
+ form_group_builder(method, options) { date_picker_builder method, options }
29
+ end
30
+
31
+ def time_picker method, **options
32
+ form_group_builder(method, options) { time_picker_builder method, options }
33
+ end
34
+
35
+ private
36
+
37
+ def date_picker_builder method, **options
38
+ widget_options = {
39
+ provide: 'datepicker',
40
+ date_today_highlight: true,
41
+ date_format: 'yyyy-mm-dd',
42
+ date_today_btn: 'linked',
43
+ date_autoclose: true,
44
+ date_disable_touch_keyboard: true,
45
+ date_enable_on_readonly: false,
46
+ date_show_on_focus: false
47
+ }
48
+ widget = options.delete(:widget) { {} }
49
+ widget.each { |option, value| widget_options["date_#{option.to_s.underscore}".to_sym] = value }
50
+
51
+ text = self.text_field_without_bootstrap method, { size: 10 }.merge(options)
52
+ icon = content_tag :span, glyphicon_tag('calendar'), class: 'input-group-addon'
53
+ content_tag :div, text + icon, class: 'input-group date', data: widget_options
54
+ end
55
+
56
+ def time_picker_builder method, **options
57
+ widget_options = { provide: 'timepicker' }
58
+ widget = options.delete(:widget) { {} }
59
+ widget.each { |option, value| widget_options["time_#{option.to_s.underscore}".to_sym] = value }
60
+
61
+ options.reverse_merge! size: 8, data: {}
62
+ options[:data].merge! widget_options
63
+
64
+ text = self.text_field_without_bootstrap method, options
65
+ icon = content_tag :span, glyphicon_tag('time'), class: 'input-group-addon'
66
+ content_tag :div, text + icon, class: 'input-group bootstrap-timepicker'
67
+ end
68
+
69
+ end
70
+
71
+ end
@@ -0,0 +1,18 @@
1
+ module BootstrapFormExtensions
2
+
3
+ module Helpers
4
+
5
+ def glyphicon_tag *icons
6
+ options = icons.extract_options!
7
+ options[:class] = options.fetch :class, ''
8
+ options[:class] << " glyphicon " << icons.flatten.map{ |icon| "glyphicon-#{icon}"}.join(' ')
9
+ content_tag :i, nil, options
10
+ end
11
+
12
+ def true? value
13
+ value.to_s.match(/(true|t|yes|y|1)$/i).present?
14
+ end
15
+
16
+ end
17
+
18
+ end