bootstrap_form_extensions 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|