bootstrap_ui_helper 0.3.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 36f403069f00bd4734ef52b6121d05b875b458a4
4
+ data.tar.gz: 7f0099b18df7f8af7e246bd4484473a41c9c68ed
5
+ SHA512:
6
+ metadata.gz: 9e4588ec543f3ff3832ef45fa1f021ac0f363d393bd55cda257d3ca96d974179f296f302395d2f4dcaeacd9dae0047efb4c85052b8863f3dd5f1ca2ced62685a
7
+ data.tar.gz: fbc507cd20ba350cabf8d1301677533f199efaa4d846fa3cba1951af60e0af2e42c592338e84ea0b2f86d8e237ff78c703887c85833680cb797b26b392e3327b
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+
16
+ .idea
17
+ vender
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in bootstrap_ui_helper.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Sen Zhang
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,48 @@
1
+ # Bootstrap UI Helper
2
+
3
+ Bootstrap style UI helpers engine
4
+
5
+ [![Code Climate](https://codeclimate.com/github/Sen-Zhang/bootstrap_ui_helper/badges/gpa.svg)](https://codeclimate.com/github/Sen-Zhang/bootstrap_ui_helper)
6
+
7
+
8
+ ## Requirement
9
+ * Rails 3.0+
10
+ * Bootstrap v3.0+ (http://getbootstrap.com/)
11
+ * Font Awesome v4.4.0 (https://fortawesome.github.io/Font-Awesome/)
12
+ * jQuery 1.7+ (http://jquery.com/download/)
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'bootstrap_ui_helper'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install bootstrap_ui_helper
29
+
30
+ In `application.js`, add the following line:
31
+
32
+ //= require bootstrap_ui_helper
33
+
34
+ In `application.css`, add the following line:
35
+
36
+ *= require bootstrap_ui_helper
37
+
38
+ ## Usage
39
+
40
+ Please proceed to http://sen-zhang.github.io/#/articles/bootstrap_ui_helper for more details and examples on how to use the helpers.
41
+
42
+ ## Contributing
43
+
44
+ 1. Fork it ( https://github.com/[my-github-username]/bootstrap_ui_helper/fork )
45
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
46
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
47
+ 4. Push to the branch (`git push origin my-new-feature`)
48
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require 'bundler/gem_tasks'
@@ -0,0 +1,113 @@
1
+ (function ($) {
2
+ "use strict";
3
+
4
+ /*
5
+ * create a jquery DOM element based on tag name and options
6
+ *
7
+ */
8
+ var createElement = function (tag, options) {
9
+ var $el = $(document.createElement(tag));
10
+
11
+ return options === undefined ? $el : $el.attr(options);
12
+ };
13
+
14
+ /*
15
+ * Nav
16
+ * Wrap each child nav with +li+ tag and put class +active+ to indicated
17
+ * active element
18
+ *
19
+ */
20
+ $.fn.nav = function () {
21
+ var $this = $(this),
22
+ activeChildLocator = $this.data("active-el-locator"),
23
+ children = $this.children();
24
+
25
+ if (activeChildLocator % 1 === 0) {
26
+ $(children[activeChildLocator]).attr("active", true);
27
+ } else {
28
+ $this.children(activeChildLocator).attr("active", true);
29
+ }
30
+
31
+ $this.children().remove();
32
+
33
+ children.each(function () {
34
+ var $child = $(this),
35
+ wrapper = createElement("li", {role: "presentation"});
36
+
37
+ if ($child.attr("active") === "true") {
38
+ $child.removeAttr("active");
39
+ wrapper.addClass("active");
40
+ }
41
+
42
+ $this.append(wrapper.append($child));
43
+ });
44
+ };
45
+
46
+ /*
47
+ * Panel Row
48
+ * Wrap each child panel with indicated column-class
49
+ *
50
+ */
51
+ $.fn.panelRow = function () {
52
+ var $this = $(this),
53
+ columnClass = $this.data("column-class"),
54
+ children = $this.children();
55
+
56
+ $this.children().remove();
57
+
58
+ children.each(function () {
59
+ var $child = $(this),
60
+ wrapper = createElement("div");
61
+
62
+ $this.append(wrapper.addClass(columnClass).append($child));
63
+ });
64
+ };
65
+
66
+ /*
67
+ * Button Group
68
+ * make sure children button group has the same size of their parents"
69
+ *
70
+ */
71
+ $.fn.buttonGroup = function () {
72
+ var $this = $(this);
73
+
74
+ $this.children(".btn-group").addClass($this.data("size"));
75
+ };
76
+
77
+ /*
78
+ * Navbar Collapse
79
+ *
80
+ */
81
+ $.fn.navBar = function () {
82
+ var $this = $(this),
83
+ $burgerBtn = $this.find(".navbar-toggle"),
84
+ $collapse = $this.find(".navbar-collapse");
85
+
86
+ if ($burgerBtn.length > 0 && $collapse.length > 0) {
87
+ var collapseId = $collapse.attr("id");
88
+
89
+ if ($collapse.attr("id") === undefined) {
90
+ collapseId = Math.random().toString(36).substring(7);
91
+ $collapse.attr("id", collapseId);
92
+ }
93
+
94
+ $burgerBtn.attr("data-target", "#" + collapseId);
95
+ }
96
+ };
97
+
98
+ $(function () {
99
+
100
+ /* Initialize Nav */
101
+ $("[data-bui='nav']").nav();
102
+
103
+ /* Enable Navbar Collapse */
104
+ $("[data-bui='navbar']").navBar();
105
+
106
+ /* Initialize Panel Row */
107
+ $("[data-bui='panel_row']").panelRow();
108
+
109
+ /* Resize Button Group */
110
+ $("[data-bui='btn_group']").buttonGroup();
111
+
112
+ });
113
+ })(jQuery);
@@ -0,0 +1,12 @@
1
+ label.required:after {
2
+ content: ' *';
3
+ color: red;
4
+ }
5
+
6
+ .form-horizontal input[type='file'] {
7
+ padding-top: 7px;
8
+ }
9
+
10
+ .input-group-addon {
11
+ min-width: 40px;
12
+ }
@@ -0,0 +1,50 @@
1
+ module AlertBoxHelper
2
+ include ActionView::Helpers
3
+
4
+ def alert_box(content_or_options=nil, options={}, &block)
5
+ if content_or_options.is_a?(Hash)
6
+ options = content_or_options
7
+ else
8
+ content = content_or_options
9
+ end
10
+
11
+ dismissible = options.delete(:dismiss).present?
12
+ klass = options.delete(:class)
13
+ type = alert_type(options.delete(:type))
14
+
15
+ prepend_class(options, 'alert', type, klass)
16
+ options[:role] = 'alert'
17
+
18
+ render_alert_box(options, dismissible, content, &block)
19
+ end
20
+
21
+ def alert_type(type)
22
+ case type.try(:to_sym)
23
+ when :info
24
+ 'alert-info'
25
+ when :success
26
+ 'alert-success'
27
+ when :warning
28
+ 'alert-warning'
29
+ when :danger
30
+ 'alert-danger'
31
+ else
32
+ 'alert-info'
33
+ end
34
+ end
35
+
36
+ def dismiss_button
37
+ "<button type='button' class='close' data-dismiss='alert'" \
38
+ "aria-label='Close'><span aria-hidden='true'>&times;</span></button>"
39
+ end
40
+
41
+ def render_alert_box(options, dismissible, content, &block)
42
+ content_tag :div, options do
43
+ if dismissible
44
+ (dismiss_button + (content.presence || capture(&block))).html_safe
45
+ else
46
+ content.presence || capture(&block)
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,12 @@
1
+ module BadgeHelper
2
+ include FormatHelper
3
+
4
+ def badge(content=nil, options={})
5
+ return if content.blank?
6
+
7
+ tag = options.delete(:tag).try(:to_sym).presence || :span
8
+ prepend_class(options, 'badge')
9
+
10
+ content_tag tag, content, options
11
+ end
12
+ end
@@ -0,0 +1,191 @@
1
+ module BootstrapFormHelper
2
+ include ActionView::Helpers
3
+ include PanelHelper
4
+
5
+ mattr_accessor :layout
6
+ FIELD_HELPERS = [:email_field, :password_field, :text_field, :text_area,
7
+ :search_field, :telephone_field, :url_field, :number_field,
8
+ :file_field, :date_field, :time_field, :month_field,
9
+ :week_field, :datetime_field]
10
+
11
+ def form_for(record, options = {}, &block)
12
+ html_options = options[:html] ||= {}
13
+
14
+ prepend_class(html_options, get_form_layout(options.delete(:layout)))
15
+ options[:html] = html_options
16
+
17
+ super
18
+ end
19
+
20
+ # TODO: color_field, datetime_local_field, range_field
21
+
22
+ FIELD_HELPERS.each do |helper|
23
+ define_method helper do |object_name, method, options={}|
24
+ label_class, field_wrapper = ['col-sm-3 control-label', true] if layout == :horizontal
25
+
26
+ prepend_class(options, 'form-control') unless __callee__ == :file_field
27
+
28
+ required = 'required' if options.delete(:required)
29
+ label_sr_only = 'sr-only' if options[:label].is_a?(FalseClass)
30
+ label_class = squeeze_n_strip("#{label_class} #{required} #{label_sr_only}")
31
+ help_text = (options[:help] ? "<span class='help-block text-left'>#{options[:help]}</span>" : '').html_safe
32
+ prefix_content = options.delete(:prefix)
33
+ suffix_content = options.delete(:suffix)
34
+
35
+ label_proc = proc { label(object_name, method, options[:label], class: label_class) }
36
+
37
+ input_proc = proc do
38
+ input_content = if prefix_content.present? || suffix_content.present?
39
+ prefix_addon = build_input_addon(prefix_content)
40
+ suffix_addon = build_input_addon(suffix_content)
41
+ content_tag :div, class: 'input-group' do
42
+ prefix_addon + super(object_name, method, options) + suffix_addon
43
+ end
44
+ else
45
+ super(object_name, method, options)
46
+ end
47
+
48
+ input_content + help_text
49
+ end
50
+
51
+ render_field(field_wrapper, label_proc, input_proc)
52
+ end
53
+
54
+ def fields_for(record_name, record_object = nil, options = {}, &block)
55
+ fieldset = HashWithIndifferentAccess.new(options.delete(:fieldset))
56
+
57
+ if fieldset.present?
58
+ type = get_panel_type(fieldset[:type])
59
+ title = fieldset[:title]
60
+ end
61
+
62
+ content_tag :fieldset, class: "panel #{type}" do
63
+ ((title.present? ? (content_tag :div, title, class: 'panel-heading') : '') +
64
+ (content_tag :div, class: 'panel-body' do
65
+ super
66
+ end)).html_safe
67
+ end
68
+ end
69
+
70
+ alias_method :fieldset, :panel
71
+
72
+ def build_input_addon(content)
73
+ return ('').html_safe if content.blank?
74
+
75
+ if content.is_a?(String)
76
+ "<span class='input-group-addon'>#{content}</span>".html_safe
77
+ elsif content.is_a?(Hash) && content.key?(:icon)
78
+ "<span class='input-group-addon'>#{icon(content[:icon])}</span>".html_safe
79
+ else
80
+ ('').html_safe
81
+ end
82
+ end
83
+
84
+ def render_field(inline_style, label_proc, input_proc)
85
+ content_tag :div, class: 'form-group' do
86
+ if inline_style
87
+ (label_proc.call + (content_tag :div, class: 'col-sm-9', &input_proc)).html_safe
88
+ else
89
+ (label_proc.call + input_proc.call).html_safe
90
+ end
91
+ end
92
+ end
93
+ end
94
+
95
+ class ActionView::Helpers::FormBuilder
96
+ include BootstrapFormHelper
97
+ include ButtonHelper
98
+
99
+ attr_accessor :output_buffer
100
+
101
+ def check_box(method, options = {}, checked_value = '1', unchecked_value = '0')
102
+ layout_inline = options.delete(:layout).try(:to_sym) == :inline
103
+
104
+ check_box = proc do
105
+ proc = proc do
106
+ @template.check_box(@object_name, method, objectify_options(options), checked_value, unchecked_value) +
107
+ options[:label]
108
+ end
109
+
110
+ if layout_inline
111
+ content_tag :label, class: 'checkbox-inline', &proc
112
+ else
113
+ content_tag :div, class: 'checkbox' do
114
+ content_tag :label, &proc
115
+ end
116
+ end
117
+ end
118
+
119
+ if horizontal_layout?
120
+ content_tag :div, class: 'form-group' do
121
+ content_tag :div, class: 'col-sm-offset-3 col-sm-9', &check_box
122
+ end
123
+ else
124
+ check_box.call
125
+ end
126
+ end
127
+
128
+ def radio_button(method, tag_value, options = {})
129
+ layout_inline = options.delete(:layout).try(:to_sym) == :inline
130
+
131
+ radio_button = proc do
132
+ proc = proc do
133
+ @template.radio_button(@object_name, method, tag_value, objectify_options(options)) + options[:label]
134
+ end
135
+
136
+ if layout_inline
137
+ content_tag :label, class: 'radio-inline', &proc
138
+ else
139
+ content_tag :div, class: 'radio' do
140
+ content_tag :label, &proc
141
+ end
142
+ end
143
+ end
144
+
145
+ if horizontal_layout?
146
+ content_tag :div, class: 'form-group' do
147
+ content_tag :div, class: 'col-sm-offset-3 col-sm-9', &radio_button
148
+ end
149
+ else
150
+ radio_button.call
151
+ end
152
+ end
153
+
154
+ def submit(value=nil, options={})
155
+ value, options = nil, value if value.is_a?(Hash)
156
+ value ||= submit_default_value
157
+
158
+ prepend_class(options, 'btn', get_btn_type(options.delete(:type)))
159
+
160
+ submit_prc = proc { @template.submit_tag(value, options) }
161
+
162
+ return submit_prc.call unless horizontal_layout?
163
+
164
+ content_tag :div, class: 'form-group' do
165
+ content_tag :div, class: 'col-sm-offset-3 col-sm-9', &submit_prc
166
+ end
167
+ end
168
+
169
+ private
170
+
171
+ def horizontal_layout?
172
+ BootstrapFormHelper.layout == :horizontal
173
+ end
174
+ end
175
+
176
+ private
177
+
178
+ def get_form_layout(form_layout)
179
+ case form_layout.try(:to_sym)
180
+ when :horizontal
181
+ layout = :horizontal
182
+ 'form form-horizontal'
183
+ when :inline
184
+ layout = :inline
185
+ 'form form-inline'
186
+ else
187
+ layout = :basic
188
+ 'form'
189
+ end
190
+ end
191
+ end