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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +34 -0
- data/app/assets/javascripts/bootstrap_form_extensions/arrayed_field.js +70 -0
- data/app/assets/javascripts/bootstrap_form_extensions/bootstrap-timepicker.min.js +5 -0
- data/app/assets/javascripts/bootstrap_form_extensions/index.js +2 -0
- data/app/assets/javascripts/bootstrap_form_extensions/jquery.html5data.min.js +7 -0
- data/app/assets/javascripts/bootstrap_form_extensions/scheduler.js +226 -0
- data/app/assets/javascripts/bootstrap_form_extensions/select_or_new.js +76 -0
- data/app/assets/javascripts/bootstrap_form_extensions/time_picker.js +61 -0
- data/app/assets/javascripts/bootstrap_form_extensions/timespan.js +60 -0
- data/app/assets/stylesheets/bootstrap_form_extensions/bootstrap-timepicker.min.css +10 -0
- data/app/assets/stylesheets/bootstrap_form_extensions/common.css +11 -0
- data/app/assets/stylesheets/bootstrap_form_extensions/index.css +4 -0
- data/app/assets/stylesheets/bootstrap_form_extensions/scheduler.css +31 -0
- data/app/assets/stylesheets/bootstrap_form_extensions/submit_bar.css +4 -0
- data/app/views/bootstrap_form_extensions/_submit_bar.html.erb +36 -0
- data/lib/bootstrap_form_extensions.rb +22 -0
- data/lib/bootstrap_form_extensions/arrayed_field.rb +107 -0
- data/lib/bootstrap_form_extensions/date_time_pickers.rb +71 -0
- data/lib/bootstrap_form_extensions/helpers.rb +18 -0
- data/lib/bootstrap_form_extensions/scheduler.rb +72 -0
- data/lib/bootstrap_form_extensions/select_or_new.rb +36 -0
- data/lib/bootstrap_form_extensions/submit_bar.rb +65 -0
- data/lib/bootstrap_form_extensions/timespan.rb +55 -0
- data/lib/bootstrap_form_extensions/version.rb +3 -0
- data/lib/tasks/rails_bootstrap_form_extensions_tasks.rake +4 -0
- data/test/arrayed_field_test.rb +63 -0
- data/test/bootstrap_form_extensions_test.rb +7 -0
- data/test/date_time_pickers_test.rb +50 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/category.rb +7 -0
- data/test/dummy/app/models/thing.rb +46 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +26 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/db/migrate/20150918185031_create_things.rb +9 -0
- data/test/dummy/db/migrate/20150924203053_add_timespan.rb +7 -0
- data/test/dummy/db/migrate/20150929213249_add_arrayed_field.rb +7 -0
- data/test/dummy/db/migrate/20151006171627_add_another_arrayed_field.rb +7 -0
- data/test/dummy/db/migrate/20151006181943_add_json_field.rb +7 -0
- data/test/dummy/db/migrate/20151007213131_add_scheduler_field.rb +7 -0
- data/test/dummy/db/migrate/20151030194330_add_date_time.rb +7 -0
- data/test/dummy/db/migrate/20151106165522_add_category.rb +10 -0
- data/test/dummy/db/schema.rb +31 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +0 -0
- data/test/dummy/log/test.log +1997 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/test/fixtures/things.yml +8 -0
- data/test/javascripts/arrayed_field_spec.js +101 -0
- data/test/javascripts/helpers/function_bind_polyfill_for_phantomjs.js +32 -0
- data/test/javascripts/helpers/jasmine-jquery.js +838 -0
- data/test/javascripts/scheduler_spec.js +354 -0
- data/test/javascripts/select_or_new_spec.js +113 -0
- data/test/javascripts/support/jasmine.yml +127 -0
- data/test/javascripts/support/jasmine_helper.rb +19 -0
- data/test/javascripts/time_picker_spec.js +42 -0
- data/test/javascripts/timespan_spec.js +81 -0
- data/test/javascripts/vendor/bootstrap.min.js +7 -0
- data/test/javascripts/vendor/jquery-2.1.4.min.js +4 -0
- data/test/scheduler_serializer_test.rb +200 -0
- data/test/scheduler_test.rb +15 -0
- data/test/select_or_new_test.rb +37 -0
- data/test/submit_bar_test.rb +112 -0
- data/test/test_helper.rb +37 -0
- data/test/timespan_test.rb +47 -0
- 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,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,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 + ' '.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
|