andy_rails_toolbox 0.0.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{LICENSE.txt → MIT-LICENSE} +1 -3
- data/README.md +178 -1
- data/Rakefile +22 -1
- data/app/assets/javascripts/jquery.timeago.js +214 -0
- data/app/assets/javascripts/jquery.timeago.load.coffee +3 -0
- data/app/assets/javascripts/jquery.timeago.zh-TW.js +20 -0
- data/app/helpers/bootstrap_helper.rb +211 -0
- data/app/helpers/font_awesome_helper.rb +94 -0
- data/app/helpers/hash_helper.rb +25 -0
- data/app/helpers/markdown_helper.rb +25 -0
- data/app/helpers/qrcode_helper.rb +21 -0
- data/app/helpers/timeago_helper.rb +7 -0
- data/lib/andy_rails_toolbox/version.rb +1 -1
- data/lib/andy_rails_toolbox.rb +6 -3
- metadata +24 -18
- data/.gitignore +0 -14
- data/Gemfile +0 -4
- data/andy_rails_toolbox.gemspec +0 -23
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f80bf87e2fb9ba3f445312d86e45efe5c892a68
|
4
|
+
data.tar.gz: 116cd8015e92c1cddb2cae0492c5ea1ad22d694e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 55612b107b794647de97be8b31cdd648ab96c360a1d150d390f2f208c021fa765d4e40a7dfa3b8874d167b3a6b96dfb4281fa203da168fc10b55cf842b449cd0
|
7
|
+
data.tar.gz: d3ac2b27b5f8d49df9497957fc0c782c74904c75f6df0ee641d21bf1e49e207a6f2e787072172285984f0c4ca7555ab4c7a37c27f0a65e21b28870ffc5564aa2
|
data/{LICENSE.txt → MIT-LICENSE}
RENAMED
data/README.md
CHANGED
@@ -20,7 +20,184 @@ Or install it yourself as:
|
|
20
20
|
|
21
21
|
## Usage
|
22
22
|
|
23
|
-
|
23
|
+
#### BootstrapHelper
|
24
|
+
|
25
|
+
Bootstrap Homepage: <a href="http://getbootstrap.com/" target="_blank">http://getbootstrap.com/</a>
|
26
|
+
|
27
|
+
|
28
|
+
Add below codes to layout `app/views/layout/application.html.erb`
|
29
|
+
|
30
|
+
``` erb
|
31
|
+
...
|
32
|
+
<%= stylesheet_link_tag '//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap.min.css' %>
|
33
|
+
...
|
34
|
+
<%= javascript_include_tag '//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/js/bootstrap.min.js' %>
|
35
|
+
...
|
36
|
+
```
|
37
|
+
|
38
|
+
Examples
|
39
|
+
|
40
|
+
ICONS
|
41
|
+
|
42
|
+
``` rb
|
43
|
+
bs_icon 'user'
|
44
|
+
# => <span class="glyphicon glyphicon-user"></span>
|
45
|
+
```
|
46
|
+
|
47
|
+
BUTTONS
|
48
|
+
|
49
|
+
``` rb
|
50
|
+
html_button 'button'
|
51
|
+
# => <button name="button" type="button" class="btn btn-default">button</button>
|
52
|
+
html_button 'button', color: 'primary'
|
53
|
+
# => <button name="button" type="button" class="btn btn-primary">button</button>
|
54
|
+
html_button 'button', size: 'sm'
|
55
|
+
# => <button name="button" type="button" class="btn btn-default btn-sm">button</button>
|
56
|
+
html_button 'button', block: true
|
57
|
+
# => <button name="button" type="button" class="btn btn-default btn-block">button</button>
|
58
|
+
html_button 'button', icon: 'user'
|
59
|
+
# => <button name="button" type="button" class="btn btn-default"><i class="fa fa-user"></i> button</button>
|
60
|
+
html_button 'button', active: true
|
61
|
+
# => <button name="button" type="button" class="btn btn-default active">button</button>
|
62
|
+
submit_button 'submit'
|
63
|
+
# => <button type="submit" class="btn btn-default">submit</button>
|
64
|
+
reset_button 'reset'
|
65
|
+
# => <button type="reset" class="btn btn-default">reset</button>
|
66
|
+
link_button 'link', url: root_path
|
67
|
+
# => <a class="btn btn-default" role="button" href="/">link</a>
|
68
|
+
input_button 'input button'
|
69
|
+
# => <input class="btn btn-default" value="input button" type="button" />
|
70
|
+
input_submit 'input button'
|
71
|
+
# => <input type="submit" name="commit" value="input button" class="btn btn-default" />
|
72
|
+
```
|
73
|
+
|
74
|
+
IMAGES
|
75
|
+
|
76
|
+
``` rb
|
77
|
+
image_responsive 'pic.png'
|
78
|
+
# => <img class="img-responsive" src="/images/pic.png" alt="Pic" />
|
79
|
+
image_rounded 'pic.png'
|
80
|
+
# => <img class="img-rounded" src="/images/pic.png" alt="Pic" />
|
81
|
+
image_circle 'pic.png'
|
82
|
+
# => <img class="img-circle" src="/images/pic.png" alt="Pic" />
|
83
|
+
image_thumbnail 'pic.png'
|
84
|
+
# => <img class="img-thumbnail" src="/images/pic.png" alt="Pic" />
|
85
|
+
```
|
86
|
+
|
87
|
+
#### MarkdownHelper
|
88
|
+
|
89
|
+
New a css erb file `app/assets/stylesheets/pygments.css.erb` for pygments color style
|
90
|
+
|
91
|
+
``` erb
|
92
|
+
<%= Pygments.css(style: "igor") %>
|
93
|
+
```
|
94
|
+
|
95
|
+
All styles:
|
96
|
+
|
97
|
+
``` sh
|
98
|
+
$ rails c
|
99
|
+
# => Loading development environment (Rails 4.2.0)
|
100
|
+
irb(main):001:0> require 'pygments.rb'
|
101
|
+
# => true
|
102
|
+
irb(main):002:0> Pygments.styles
|
103
|
+
# => ["manni", "igor", "xcode", "vim", "autumn", "vs", "rrt", "native", "perldoc", "borland", "tango", "emacs", "friendly", "monokai", "paraiso-dark", "colorful", "murphy", "bw", "pastie", "paraiso-light", "trac", "default", "fruity"]
|
104
|
+
```
|
105
|
+
|
106
|
+
Examples
|
107
|
+
|
108
|
+
``` rb
|
109
|
+
markdown '# h1'
|
110
|
+
# => <h1>h1</h1>
|
111
|
+
markdown '## h2'
|
112
|
+
# => <h2>h2</h2>
|
113
|
+
markdown '[an example](http://example.com/)'
|
114
|
+
# => <p><a href="http://example.com/">an example</a></p>
|
115
|
+
markdown @post.content
|
116
|
+
# => transform markdown code to html codes and payments highlighter
|
117
|
+
```
|
118
|
+
|
119
|
+
#### QrcodeHelper Examples
|
120
|
+
|
121
|
+
``` rb
|
122
|
+
qrcode 'Hello world!'
|
123
|
+
```
|
124
|
+
|
125
|
+
<img alt="Hello world!" src="https://chart.googleapis.com/chart?cht=qr&chl=Hello world!&chs=200x200" />
|
126
|
+
|
127
|
+
QRCode options parameters: <a href="https://google-developers.appspot.com/chart/infographics/docs/qr_codes#overview" target="_blank">Here</a>
|
128
|
+
|
129
|
+
``` rb
|
130
|
+
qrcode 'Hello world!', width: '300', output_encoding: 'Shift_JIS', error_correction_level: 'H', margin: '10'
|
131
|
+
```
|
132
|
+
|
133
|
+
#### FontAwesomeHelper
|
134
|
+
|
135
|
+
Font Awesome icons Homepage: <a href="http://fortawesome.github.io/Font-Awesome/" target="_blank">http://fortawesome.github.io/Font-Awesome/</a>
|
136
|
+
|
137
|
+
Add below codes to layout `app/views/layout/application.html.erb`
|
138
|
+
|
139
|
+
``` erb
|
140
|
+
...
|
141
|
+
<%= stylesheet_link_tag '//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css' %>
|
142
|
+
...
|
143
|
+
```
|
144
|
+
|
145
|
+
Examples
|
146
|
+
|
147
|
+
``` rb
|
148
|
+
fa_icon "user"
|
149
|
+
# => <i class="fa fa-user"></i>
|
150
|
+
|
151
|
+
fa_icon "user", text: "Login"
|
152
|
+
# => <i class="fa fa-user"></i> Login
|
153
|
+
|
154
|
+
fa_icon "user", text: "Login", right: true
|
155
|
+
# => Login <i class="fa fa-user"></i>
|
156
|
+
|
157
|
+
fa_icon "user 4x"
|
158
|
+
# => <i class="fa fa-user fa-4x"></i>
|
159
|
+
```
|
160
|
+
|
161
|
+
#### HashHelper Examples
|
162
|
+
|
163
|
+
``` rb
|
164
|
+
options = { a: '1', b: '2', c: '3' }
|
165
|
+
|
166
|
+
get_value :a, options
|
167
|
+
# => '1'
|
168
|
+
get_value :d, options
|
169
|
+
# => nil
|
170
|
+
get_value :d, options, '4'
|
171
|
+
# => '4'
|
172
|
+
|
173
|
+
pop_value :a, options
|
174
|
+
# => '1'
|
175
|
+
# options = { b: '2', c: '3' }
|
176
|
+
pop_value :d, options
|
177
|
+
# => nil
|
178
|
+
pop_value :d, options, '4'
|
179
|
+
# => '4'
|
180
|
+
# options = { a: '1', b: '2', c: '3' }
|
181
|
+
```
|
182
|
+
|
183
|
+
#### TimeagoHelper
|
184
|
+
|
185
|
+
Add below codes to file `app/assets/javascripts/application.js`
|
186
|
+
|
187
|
+
``` js
|
188
|
+
...
|
189
|
+
//= require jquery.timeago
|
190
|
+
//= require jquery.timeago.zh-TW
|
191
|
+
//= require jquery.timeago.load
|
192
|
+
...
|
193
|
+
```
|
194
|
+
|
195
|
+
Use in View
|
196
|
+
|
197
|
+
``` rb
|
198
|
+
timeago '2014-11-21 09:38:27.256503'
|
199
|
+
# => '2個月之前'
|
200
|
+
```
|
24
201
|
|
25
202
|
## Contributing
|
26
203
|
|
data/Rakefile
CHANGED
@@ -1,2 +1,23 @@
|
|
1
|
-
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'AndyRailsToolbox'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
2
23
|
|
@@ -0,0 +1,214 @@
|
|
1
|
+
/**
|
2
|
+
* Timeago is a jQuery plugin that makes it easy to support automatically
|
3
|
+
* updating fuzzy timestamps (e.g. "4 minutes ago" or "about 1 day ago").
|
4
|
+
*
|
5
|
+
* @name timeago
|
6
|
+
* @version 1.4.1
|
7
|
+
* @requires jQuery v1.2.3+
|
8
|
+
* @author Ryan McGeary
|
9
|
+
* @license MIT License - http://www.opensource.org/licenses/mit-license.php
|
10
|
+
*
|
11
|
+
* For usage and examples, visit:
|
12
|
+
* http://timeago.yarp.com/
|
13
|
+
*
|
14
|
+
* Copyright (c) 2008-2013, Ryan McGeary (ryan -[at]- mcgeary [*dot*] org)
|
15
|
+
*/
|
16
|
+
|
17
|
+
(function (factory) {
|
18
|
+
if (typeof define === 'function' && define.amd) {
|
19
|
+
// AMD. Register as an anonymous module.
|
20
|
+
define(['jquery'], factory);
|
21
|
+
} else {
|
22
|
+
// Browser globals
|
23
|
+
factory(jQuery);
|
24
|
+
}
|
25
|
+
}(function ($) {
|
26
|
+
$.timeago = function(timestamp) {
|
27
|
+
if (timestamp instanceof Date) {
|
28
|
+
return inWords(timestamp);
|
29
|
+
} else if (typeof timestamp === "string") {
|
30
|
+
return inWords($.timeago.parse(timestamp));
|
31
|
+
} else if (typeof timestamp === "number") {
|
32
|
+
return inWords(new Date(timestamp));
|
33
|
+
} else {
|
34
|
+
return inWords($.timeago.datetime(timestamp));
|
35
|
+
}
|
36
|
+
};
|
37
|
+
var $t = $.timeago;
|
38
|
+
|
39
|
+
$.extend($.timeago, {
|
40
|
+
settings: {
|
41
|
+
refreshMillis: 60000,
|
42
|
+
allowPast: true,
|
43
|
+
allowFuture: false,
|
44
|
+
localeTitle: false,
|
45
|
+
cutoff: 0,
|
46
|
+
strings: {
|
47
|
+
prefixAgo: null,
|
48
|
+
prefixFromNow: null,
|
49
|
+
suffixAgo: "ago",
|
50
|
+
suffixFromNow: "from now",
|
51
|
+
inPast: 'any moment now',
|
52
|
+
seconds: "less than a minute",
|
53
|
+
minute: "about a minute",
|
54
|
+
minutes: "%d minutes",
|
55
|
+
hour: "about an hour",
|
56
|
+
hours: "about %d hours",
|
57
|
+
day: "a day",
|
58
|
+
days: "%d days",
|
59
|
+
month: "about a month",
|
60
|
+
months: "%d months",
|
61
|
+
year: "about a year",
|
62
|
+
years: "%d years",
|
63
|
+
wordSeparator: " ",
|
64
|
+
numbers: []
|
65
|
+
}
|
66
|
+
},
|
67
|
+
|
68
|
+
inWords: function(distanceMillis) {
|
69
|
+
if(!this.settings.allowPast && ! this.settings.allowFuture) {
|
70
|
+
throw 'timeago allowPast and allowFuture settings can not both be set to false.';
|
71
|
+
}
|
72
|
+
|
73
|
+
var $l = this.settings.strings;
|
74
|
+
var prefix = $l.prefixAgo;
|
75
|
+
var suffix = $l.suffixAgo;
|
76
|
+
if (this.settings.allowFuture) {
|
77
|
+
if (distanceMillis < 0) {
|
78
|
+
prefix = $l.prefixFromNow;
|
79
|
+
suffix = $l.suffixFromNow;
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
if(!this.settings.allowPast && distanceMillis >= 0) {
|
84
|
+
return this.settings.strings.inPast;
|
85
|
+
}
|
86
|
+
|
87
|
+
var seconds = Math.abs(distanceMillis) / 1000;
|
88
|
+
var minutes = seconds / 60;
|
89
|
+
var hours = minutes / 60;
|
90
|
+
var days = hours / 24;
|
91
|
+
var years = days / 365;
|
92
|
+
|
93
|
+
function substitute(stringOrFunction, number) {
|
94
|
+
var string = $.isFunction(stringOrFunction) ? stringOrFunction(number, distanceMillis) : stringOrFunction;
|
95
|
+
var value = ($l.numbers && $l.numbers[number]) || number;
|
96
|
+
return string.replace(/%d/i, value);
|
97
|
+
}
|
98
|
+
|
99
|
+
var words = seconds < 45 && substitute($l.seconds, Math.round(seconds)) ||
|
100
|
+
seconds < 90 && substitute($l.minute, 1) ||
|
101
|
+
minutes < 45 && substitute($l.minutes, Math.round(minutes)) ||
|
102
|
+
minutes < 90 && substitute($l.hour, 1) ||
|
103
|
+
hours < 24 && substitute($l.hours, Math.round(hours)) ||
|
104
|
+
hours < 42 && substitute($l.day, 1) ||
|
105
|
+
days < 30 && substitute($l.days, Math.round(days)) ||
|
106
|
+
days < 45 && substitute($l.month, 1) ||
|
107
|
+
days < 365 && substitute($l.months, Math.round(days / 30)) ||
|
108
|
+
years < 1.5 && substitute($l.year, 1) ||
|
109
|
+
substitute($l.years, Math.round(years));
|
110
|
+
|
111
|
+
var separator = $l.wordSeparator || "";
|
112
|
+
if ($l.wordSeparator === undefined) { separator = " "; }
|
113
|
+
return $.trim([prefix, words, suffix].join(separator));
|
114
|
+
},
|
115
|
+
|
116
|
+
parse: function(iso8601) {
|
117
|
+
var s = $.trim(iso8601);
|
118
|
+
s = s.replace(/\.\d+/,""); // remove milliseconds
|
119
|
+
s = s.replace(/-/,"/").replace(/-/,"/");
|
120
|
+
s = s.replace(/T/," ").replace(/Z/," UTC");
|
121
|
+
s = s.replace(/([\+\-]\d\d)\:?(\d\d)/," $1$2"); // -04:00 -> -0400
|
122
|
+
s = s.replace(/([\+\-]\d\d)$/," $100"); // +09 -> +0900
|
123
|
+
return new Date(s);
|
124
|
+
},
|
125
|
+
datetime: function(elem) {
|
126
|
+
var iso8601 = $t.isTime(elem) ? $(elem).attr("datetime") : $(elem).attr("title");
|
127
|
+
return $t.parse(iso8601);
|
128
|
+
},
|
129
|
+
isTime: function(elem) {
|
130
|
+
// jQuery's `is()` doesn't play well with HTML5 in IE
|
131
|
+
return $(elem).get(0).tagName.toLowerCase() === "time"; // $(elem).is("time");
|
132
|
+
}
|
133
|
+
});
|
134
|
+
|
135
|
+
// functions that can be called via $(el).timeago('action')
|
136
|
+
// init is default when no action is given
|
137
|
+
// functions are called with context of a single element
|
138
|
+
var functions = {
|
139
|
+
init: function(){
|
140
|
+
var refresh_el = $.proxy(refresh, this);
|
141
|
+
refresh_el();
|
142
|
+
var $s = $t.settings;
|
143
|
+
if ($s.refreshMillis > 0) {
|
144
|
+
this._timeagoInterval = setInterval(refresh_el, $s.refreshMillis);
|
145
|
+
}
|
146
|
+
},
|
147
|
+
update: function(time){
|
148
|
+
var parsedTime = $t.parse(time);
|
149
|
+
$(this).data('timeago', { datetime: parsedTime });
|
150
|
+
if($t.settings.localeTitle) $(this).attr("title", parsedTime.toLocaleString());
|
151
|
+
refresh.apply(this);
|
152
|
+
},
|
153
|
+
updateFromDOM: function(){
|
154
|
+
$(this).data('timeago', { datetime: $t.parse( $t.isTime(this) ? $(this).attr("datetime") : $(this).attr("title") ) });
|
155
|
+
refresh.apply(this);
|
156
|
+
},
|
157
|
+
dispose: function () {
|
158
|
+
if (this._timeagoInterval) {
|
159
|
+
window.clearInterval(this._timeagoInterval);
|
160
|
+
this._timeagoInterval = null;
|
161
|
+
}
|
162
|
+
}
|
163
|
+
};
|
164
|
+
|
165
|
+
$.fn.timeago = function(action, options) {
|
166
|
+
var fn = action ? functions[action] : functions.init;
|
167
|
+
if(!fn){
|
168
|
+
throw new Error("Unknown function name '"+ action +"' for timeago");
|
169
|
+
}
|
170
|
+
// each over objects here and call the requested function
|
171
|
+
this.each(function(){
|
172
|
+
fn.call(this, options);
|
173
|
+
});
|
174
|
+
return this;
|
175
|
+
};
|
176
|
+
|
177
|
+
function refresh() {
|
178
|
+
var data = prepareData(this);
|
179
|
+
var $s = $t.settings;
|
180
|
+
|
181
|
+
if (!isNaN(data.datetime)) {
|
182
|
+
if ( $s.cutoff == 0 || Math.abs(distance(data.datetime)) < $s.cutoff) {
|
183
|
+
$(this).text(inWords(data.datetime));
|
184
|
+
}
|
185
|
+
}
|
186
|
+
return this;
|
187
|
+
}
|
188
|
+
|
189
|
+
function prepareData(element) {
|
190
|
+
element = $(element);
|
191
|
+
if (!element.data("timeago")) {
|
192
|
+
element.data("timeago", { datetime: $t.datetime(element) });
|
193
|
+
var text = $.trim(element.text());
|
194
|
+
if ($t.settings.localeTitle) {
|
195
|
+
element.attr("title", element.data('timeago').datetime.toLocaleString());
|
196
|
+
} else if (text.length > 0 && !($t.isTime(element) && element.attr("title"))) {
|
197
|
+
element.attr("title", text);
|
198
|
+
}
|
199
|
+
}
|
200
|
+
return element.data("timeago");
|
201
|
+
}
|
202
|
+
|
203
|
+
function inWords(date) {
|
204
|
+
return $t.inWords(distance(date));
|
205
|
+
}
|
206
|
+
|
207
|
+
function distance(date) {
|
208
|
+
return (new Date().getTime() - date.getTime());
|
209
|
+
}
|
210
|
+
|
211
|
+
// fix for IE6 suckage
|
212
|
+
document.createElement("abbr");
|
213
|
+
document.createElement("time");
|
214
|
+
}));
|
@@ -0,0 +1,20 @@
|
|
1
|
+
// Traditional Chinese, zh-tw
|
2
|
+
jQuery.timeago.settings.strings = {
|
3
|
+
prefixAgo: null,
|
4
|
+
prefixFromNow: "從現在開始",
|
5
|
+
suffixAgo: "之前",
|
6
|
+
suffixFromNow: null,
|
7
|
+
seconds: "不到1分鐘",
|
8
|
+
minute: "大約1分鐘",
|
9
|
+
minutes: "%d分鐘",
|
10
|
+
hour: "大約1小時",
|
11
|
+
hours: "%d小時",
|
12
|
+
day: "大約1天",
|
13
|
+
days: "%d天",
|
14
|
+
month: "大約1個月",
|
15
|
+
months: "%d個月",
|
16
|
+
year: "大約1年",
|
17
|
+
years: "%d年",
|
18
|
+
numbers: [],
|
19
|
+
wordSeparator: ""
|
20
|
+
};
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module BootstrapHelper
|
2
|
+
#############
|
3
|
+
### ICONS ###
|
4
|
+
#############
|
5
|
+
|
6
|
+
# Generates an icon.
|
7
|
+
def bs_icon(icon, options = {})
|
8
|
+
icon = %(glyphicon glyphicon-#{icon})
|
9
|
+
add_css_class icon, options
|
10
|
+
tag = pop_value :tag, options, :span
|
11
|
+
content_tag tag, '', options
|
12
|
+
end
|
13
|
+
|
14
|
+
###############
|
15
|
+
### BUTTONS ###
|
16
|
+
###############
|
17
|
+
|
18
|
+
# Generates a button.
|
19
|
+
def button(label = 'Button', options = {})
|
20
|
+
html_button label, options
|
21
|
+
end
|
22
|
+
|
23
|
+
# Generates a html submit button.
|
24
|
+
def html_button(label = 'Button', options = {})
|
25
|
+
btn :html_button, label, options
|
26
|
+
end
|
27
|
+
|
28
|
+
# Generates a submit button.
|
29
|
+
def submit_button(label = 'Submit', options = {})
|
30
|
+
btn :submit_button, label, options
|
31
|
+
end
|
32
|
+
|
33
|
+
# Generates a reset button.
|
34
|
+
def reset_button(label = 'Reset', options = {})
|
35
|
+
btn :reset_button, label, options
|
36
|
+
end
|
37
|
+
|
38
|
+
# Generates a link submit button.
|
39
|
+
def link_button(label = 'Submit', options = {})
|
40
|
+
btn :link_button, label, options
|
41
|
+
end
|
42
|
+
|
43
|
+
# Generates a input button.
|
44
|
+
def input_button(label = 'Button', options = {})
|
45
|
+
btn :input_button, label, options
|
46
|
+
end
|
47
|
+
|
48
|
+
# Generates a input submit button.
|
49
|
+
def input_submit(label = 'Submit', options = {})
|
50
|
+
btn :input_submit, label, options
|
51
|
+
end
|
52
|
+
|
53
|
+
# Generates a button.
|
54
|
+
def btn(type, label, options = {})
|
55
|
+
add_css_class 'btn', options
|
56
|
+
|
57
|
+
color = pop_value :color, options, 'default'
|
58
|
+
add_css_class(%(btn-#{color}), options) if color
|
59
|
+
|
60
|
+
size = pop_value :size, options
|
61
|
+
add_css_class(%(btn-#{size}), options) if size
|
62
|
+
|
63
|
+
block = pop_value :block, options
|
64
|
+
add_css_class('btn-block', options) if block
|
65
|
+
|
66
|
+
add_active_class options
|
67
|
+
|
68
|
+
icon = pop_value :icon, options
|
69
|
+
unless type.to_s.include? 'input'
|
70
|
+
if icon
|
71
|
+
label = fa_icon(icon) + ' ' + label
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
create_button type, label, options
|
76
|
+
end
|
77
|
+
|
78
|
+
def create_button(type, label, options)
|
79
|
+
url = pop_value :url, options, '#'
|
80
|
+
case type
|
81
|
+
when :html_button
|
82
|
+
options[:type] = :button unless options[:type]
|
83
|
+
button_tag label, options
|
84
|
+
when :submit_button
|
85
|
+
options[:name] = nil
|
86
|
+
options[:type] = :submit
|
87
|
+
button_tag label, options
|
88
|
+
when :reset_button
|
89
|
+
options[:name] = nil
|
90
|
+
options[:type] = :reset
|
91
|
+
button_tag label, options
|
92
|
+
when :link_button
|
93
|
+
options[:role] = :button
|
94
|
+
link_to label, url, options
|
95
|
+
when :input_button
|
96
|
+
options[:value] = label
|
97
|
+
options[:type] = :button
|
98
|
+
tag 'input', options
|
99
|
+
when :input_submit
|
100
|
+
submit_tag label, options
|
101
|
+
else
|
102
|
+
# type code here
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
##############
|
107
|
+
### IMAGES ###
|
108
|
+
##############
|
109
|
+
|
110
|
+
# Generates a responsive-friendly image tag
|
111
|
+
def image_responsive(source, options = {})
|
112
|
+
add_css_class 'img-responsive', options
|
113
|
+
image_tag source, options
|
114
|
+
end
|
115
|
+
|
116
|
+
# Generates an image tag with rounded corners.
|
117
|
+
def image_rounded(source, options = {})
|
118
|
+
add_css_class 'img-rounded', options
|
119
|
+
image_tag source, options
|
120
|
+
end
|
121
|
+
|
122
|
+
# Generates an image tag with circle.
|
123
|
+
def image_circle(source, options = {})
|
124
|
+
add_css_class 'img-circle', options
|
125
|
+
image_tag source, options
|
126
|
+
end
|
127
|
+
|
128
|
+
# Generates an image tag within thumbnail.
|
129
|
+
def image_thumbnail(source, options = {})
|
130
|
+
add_css_class 'img-thumbnail', options
|
131
|
+
image_tag source, options
|
132
|
+
end
|
133
|
+
|
134
|
+
#################
|
135
|
+
### UTILITIES ###
|
136
|
+
#################
|
137
|
+
|
138
|
+
# Appends new class names to the given options.
|
139
|
+
def add_css_class(class_names, options)
|
140
|
+
class_names = class_names.to_s if class_names.is_a? Symbol
|
141
|
+
class_names = class_names.split if class_names.is_a? String
|
142
|
+
if symbolize_keys(options).key? :class
|
143
|
+
options_class_names = options[:class].split
|
144
|
+
class_names.each do |value|
|
145
|
+
options_class_names << %(#{value.strip}) unless options_class_names.include? value
|
146
|
+
end
|
147
|
+
class_names = options_class_names
|
148
|
+
end
|
149
|
+
options[:class] = %(#{class_names * ' '})
|
150
|
+
end
|
151
|
+
|
152
|
+
# Adds the pull class to the given options is applicable.
|
153
|
+
def add_pull_class(options)
|
154
|
+
pull = pop_value :pull, options
|
155
|
+
add_css_class(%(pull-#{pull}), options) if pull
|
156
|
+
end
|
157
|
+
|
158
|
+
# Adds the text align class to the given options if applicable.
|
159
|
+
def add_align_class(options)
|
160
|
+
align = pop_value :align, options
|
161
|
+
add_css_class(%(text-#{align}), options) if align
|
162
|
+
end
|
163
|
+
|
164
|
+
# Adds the text transform class to the given options if applicable.
|
165
|
+
def add_transform_class(options)
|
166
|
+
transform = pop_value :transform, options
|
167
|
+
add_css_class(%(text-#{transform}), options) if transform
|
168
|
+
end
|
169
|
+
|
170
|
+
# Adds the color to the given options if applicable.
|
171
|
+
def add_color_class(options)
|
172
|
+
color = pop_value :color, options
|
173
|
+
add_css_class(%(text-#{color}), options) if color
|
174
|
+
end
|
175
|
+
|
176
|
+
# Adds the bgcolor to the given options if applicable.
|
177
|
+
def add_bgcolor_class(options)
|
178
|
+
bgcolor = pop_value :bgcolor, options
|
179
|
+
add_css_class(%(bg-#{bgcolor}), options) if bgcolor
|
180
|
+
end
|
181
|
+
|
182
|
+
# Adds the active to the given options if applicable.
|
183
|
+
def add_active_class(options)
|
184
|
+
active = pop_value :active, options
|
185
|
+
add_css_class('active', options) if active
|
186
|
+
end
|
187
|
+
|
188
|
+
def normalize_typography_options(options)
|
189
|
+
add_pull_class options
|
190
|
+
add_align_class options
|
191
|
+
add_transform_class options
|
192
|
+
add_color_class options
|
193
|
+
add_bgcolor_class options
|
194
|
+
end
|
195
|
+
|
196
|
+
################
|
197
|
+
### OVERRIDE ###
|
198
|
+
################
|
199
|
+
|
200
|
+
# override rails helper: content_tag
|
201
|
+
def content_tag(name, content_or_options_with_block = nil, options = nil, escape = true, &block)
|
202
|
+
if block_given?
|
203
|
+
options = content_or_options_with_block if content_or_options_with_block.is_a? Hash
|
204
|
+
normalize_typography_options(options) unless options.nil?
|
205
|
+
content_tag_string name, capture(&block), options, escape
|
206
|
+
else
|
207
|
+
normalize_typography_options(options) unless options.nil?
|
208
|
+
content_tag_string name, content_or_options_with_block, options, escape
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module FontAwesomeHelper
|
2
|
+
# Creates an icon tag given an icon name and possible icon
|
3
|
+
# modifiers.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
#
|
7
|
+
# fa_icon "camera-retro"
|
8
|
+
# # => <i class="fa fa-camera-retro"></i>
|
9
|
+
#
|
10
|
+
# fa_icon "camera-retro", text: "Take a photo"
|
11
|
+
# # => <i class="fa fa-camera-retro"></i> Take a photo
|
12
|
+
# fa_icon "chevron-right", text: "Get started", right: true
|
13
|
+
# # => Get started <i class="fa fa-chevron-right"></i>
|
14
|
+
#
|
15
|
+
# fa_icon "camera-retro 2x"
|
16
|
+
# # => <i class="fa fa-camera-retro fa-2x"></i>
|
17
|
+
# fa_icon ["camera-retro", "4x"]
|
18
|
+
# # => <i class="fa fa-camera-retro fa-4x"></i>
|
19
|
+
# fa_icon "spinner spin lg"
|
20
|
+
# # => <i class="fa fa-spinner fa-spin fa-lg">
|
21
|
+
#
|
22
|
+
# fa_icon "quote-left 4x", class: "pull-left"
|
23
|
+
# # => <i class="fa fa-quote-left fa-4x pull-left"></i>
|
24
|
+
#
|
25
|
+
# fa_icon "user", data: { id: 123 }
|
26
|
+
# # => <i class="fa fa-user" data-id="123"></i>
|
27
|
+
#
|
28
|
+
# content_tag(:li, fa_icon("check li", text: "Bulleted list item"))
|
29
|
+
# # => <li><i class="fa fa-check fa-li"></i> Bulleted list item</li>
|
30
|
+
def fa_icon(names = 'flag', options = {})
|
31
|
+
classes = ['fa']
|
32
|
+
classes.concat Private.icon_names(names)
|
33
|
+
classes.concat Array(options.delete(:class))
|
34
|
+
text = options.delete(:text)
|
35
|
+
right_icon = options.delete(:right)
|
36
|
+
icon = content_tag(:i, nil, options.merge(class: classes))
|
37
|
+
Private.icon_join(icon, text, right_icon)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Creates an stack set of icon tags given a base icon name, a main icon
|
41
|
+
# name, and possible icon modifiers.
|
42
|
+
#
|
43
|
+
# Examples
|
44
|
+
#
|
45
|
+
# fa_stacked_icon "twitter", base: "square-o"
|
46
|
+
# # => <span class="fa-stack">
|
47
|
+
# # => <i class="fa fa-square-o fa-stack-2x"></i>
|
48
|
+
# # => <i class="fa fa-twitter fa-stack-1x"></i>
|
49
|
+
# # => </span>
|
50
|
+
#
|
51
|
+
# fa_stacked_icon "terminal inverse", base: "square", class: "pull-right", text: "Hi!"
|
52
|
+
# # => <span class="fa-stack pull-right">
|
53
|
+
# # => <i class="fa fa-square fa-stack-2x"></i>
|
54
|
+
# # => <i class="fa fa-terminal fa-inverse fa-stack-1x"></i>
|
55
|
+
# # => </span> Hi!
|
56
|
+
#
|
57
|
+
# fa_stacked_icon "camera", base: "ban-circle", reverse: true
|
58
|
+
# # => <span class="fa-stack">
|
59
|
+
# # => <i class="fa fa-camera fa-stack-1x"></i>
|
60
|
+
# # => <i class="fa fa-ban-circle fa-stack-2x"></i>
|
61
|
+
# # => </span>
|
62
|
+
def fa_stacked_icon(names = 'flag', options = {})
|
63
|
+
classes = Private.icon_names('stack').concat(Array(options.delete(:class)))
|
64
|
+
base_names = Private.array_value(options.delete(:base) || 'square-o').push('stack-2x')
|
65
|
+
names = Private.array_value(names).push('stack-1x')
|
66
|
+
base = fa_icon(base_names, options.delete(:base_options) || {})
|
67
|
+
icon = fa_icon(names, options.delete(:icon_options) || {})
|
68
|
+
icons = [base, icon]
|
69
|
+
icons.reverse! if options.delete(:reverse)
|
70
|
+
text = options.delete(:text)
|
71
|
+
right_icon = options.delete(:right)
|
72
|
+
stacked_icon = content_tag(:span, safe_join(icons), options.merge(class: classes))
|
73
|
+
Private.icon_join(stacked_icon, text, right_icon)
|
74
|
+
end
|
75
|
+
|
76
|
+
module Private
|
77
|
+
extend ActionView::Helpers::OutputSafetyHelper
|
78
|
+
|
79
|
+
def self.icon_join(icon, text, reverse_order = false)
|
80
|
+
return icon if text.blank?
|
81
|
+
elements = [icon, ERB::Util.html_escape(text)]
|
82
|
+
elements.reverse! if reverse_order
|
83
|
+
safe_join(elements, ' ')
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.icon_names(names = [])
|
87
|
+
array_value(names).map { |n| "fa-#{n}" }
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.array_value(value = [])
|
91
|
+
value.is_a?(Array) ? value : value.to_s.split(/\s+/)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module HashHelper
|
2
|
+
############
|
3
|
+
### Hash ###
|
4
|
+
############
|
5
|
+
|
6
|
+
# Returns a specific value from the given hash (or the default value if not set).
|
7
|
+
def get_value(key, hash, default_value = nil)
|
8
|
+
value = hash.delete key
|
9
|
+
value = default_value if value.nil? and !default_value.nil?
|
10
|
+
value
|
11
|
+
end
|
12
|
+
|
13
|
+
# Removes and returns a specific value from the given hash (or the default value if not set).
|
14
|
+
def pop_value(key, hash, default_value = nil)
|
15
|
+
symbolize_keys hash unless hash.empty?
|
16
|
+
get_value key.to_sym, hash, default_value
|
17
|
+
end
|
18
|
+
|
19
|
+
# all keys of the given hash symbolize.
|
20
|
+
def symbolize_keys(hash)
|
21
|
+
result = {}
|
22
|
+
hash.each { |key, value| result[key.to_sym] = value }
|
23
|
+
hash.replace result
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'redcarpet'
|
2
|
+
|
3
|
+
module MarkdownHelper
|
4
|
+
class HTMLWithPygments < Redcarpet::Render::HTML
|
5
|
+
def block_code(code, language)
|
6
|
+
sha = Digest::SHA1.hexdigest(code)
|
7
|
+
Rails.cache.fetch ["code", language, sha].join('-') do
|
8
|
+
Pygments.highlight(code, lexer: language)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def markdown(text)
|
14
|
+
renderer = HTMLWithPygments.new(hard_wrap: true, filter_html: true)
|
15
|
+
options = {
|
16
|
+
autolink: true,
|
17
|
+
no_intra_emphasis: true,
|
18
|
+
fenced_code_blocks: true,
|
19
|
+
lax_html_blocks: true,
|
20
|
+
strikethrough: true,
|
21
|
+
superscript: true
|
22
|
+
}
|
23
|
+
Redcarpet::Markdown.new(renderer, options).render(text).html_safe
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module QrcodeHelper
|
2
|
+
def qrcode(data='', options = {})
|
3
|
+
# Google API: https://google-developers.appspot.com/chart/infographics/docs/qr_codes
|
4
|
+
width = pop_value :width, options, '200'
|
5
|
+
output_encoding = pop_value :output_encoding, options
|
6
|
+
error_correction_level = pop_value :error_correction_level, options
|
7
|
+
margin = pop_value :margin, options
|
8
|
+
|
9
|
+
qrcode_url = 'https://chart.googleapis.com/chart?cht=qr'
|
10
|
+
qrcode_url += "&chl=#{data}"
|
11
|
+
qrcode_url += "&chs=#{width}x#{width}"
|
12
|
+
qrcode_url += "&choe=#{output_encoding}" unless output_encoding.nil?
|
13
|
+
if error_correction_level.nil? or margin.nil?
|
14
|
+
qrcode_url += "&chld=#{error_correction_level}" unless error_correction_level.nil?
|
15
|
+
qrcode_url += "&chld=|#{margin}" unless margin.nil?
|
16
|
+
else
|
17
|
+
qrcode_url += "&chld=#{error_correction_level}|#{margin}"
|
18
|
+
end
|
19
|
+
image_tag qrcode_url, alt: data
|
20
|
+
end
|
21
|
+
end
|
data/lib/andy_rails_toolbox.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: andy_rails_toolbox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- ChouAndy
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: redcarpet
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
type: :
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: pygments.rb
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
type: :
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
description: Andy Rails Toolbox includes many useful helpers for rails development.
|
42
42
|
email:
|
43
43
|
- chouandy625@gmail.com
|
@@ -45,12 +45,18 @@ executables: []
|
|
45
45
|
extensions: []
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
|
-
-
|
49
|
-
- Gemfile
|
50
|
-
- LICENSE.txt
|
48
|
+
- MIT-LICENSE
|
51
49
|
- README.md
|
52
50
|
- Rakefile
|
53
|
-
-
|
51
|
+
- app/assets/javascripts/jquery.timeago.js
|
52
|
+
- app/assets/javascripts/jquery.timeago.load.coffee
|
53
|
+
- app/assets/javascripts/jquery.timeago.zh-TW.js
|
54
|
+
- app/helpers/bootstrap_helper.rb
|
55
|
+
- app/helpers/font_awesome_helper.rb
|
56
|
+
- app/helpers/hash_helper.rb
|
57
|
+
- app/helpers/markdown_helper.rb
|
58
|
+
- app/helpers/qrcode_helper.rb
|
59
|
+
- app/helpers/timeago_helper.rb
|
54
60
|
- lib/andy_rails_toolbox.rb
|
55
61
|
- lib/andy_rails_toolbox/version.rb
|
56
62
|
homepage: https://github.com/ChouAndy/andy_rails_toolbox
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/andy_rails_toolbox.gemspec
DELETED
@@ -1,23 +0,0 @@
|
|
1
|
-
# coding: utf-8
|
2
|
-
lib = File.expand_path('../lib', __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require 'andy_rails_toolbox/version'
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "andy_rails_toolbox"
|
8
|
-
spec.version = AndyRailsToolbox::VERSION
|
9
|
-
spec.authors = ["ChouAndy"]
|
10
|
-
spec.email = ["chouandy625@gmail.com"]
|
11
|
-
spec.summary = %q{Includes many useful helpers for rails development.}
|
12
|
-
spec.description = %q{Andy Rails Toolbox includes many useful helpers for rails development.}
|
13
|
-
spec.homepage = "https://github.com/ChouAndy/andy_rails_toolbox"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.add_development_dependency "bundler", "~> 1.7"
|
22
|
-
spec.add_development_dependency "rake", "~> 10.0"
|
23
|
-
end
|