gumby-rails 1.1
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +30 -0
- data/Rakefile +1 -0
- data/gumby-rails.gemspec +22 -0
- data/lib/gumby-rails.rb +8 -0
- data/lib/gumby-rails/version.rb +5 -0
- data/vendor/assets/javascripts/gumby.js +361 -0
- data/vendor/assets/stylesheets/gumby-hybrid.css +4 -0
- data/vendor/assets/stylesheets/gumby/12col.css +441 -0
- data/vendor/assets/stylesheets/gumby/16col.css +459 -0
- data/vendor/assets/stylesheets/gumby/hybrid.css +543 -0
- data/vendor/assets/stylesheets/gumby/style.css +9 -0
- data/vendor/assets/stylesheets/gumby/text.css +50 -0
- data/vendor/assets/stylesheets/gumby/ui.css +1613 -0
- data/vendor/assets/stylesheets/gumby12.css +4 -0
- data/vendor/assets/stylesheets/gumby16.css +4 -0
- metadata +96 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Fábio Luiz Nery de Miranda
|
|
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,30 @@
|
|
|
1
|
+
# Gumby::Rails
|
|
2
|
+
|
|
3
|
+
A rails gem for http://gumbyframework.com/ assets.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
gem 'gumby-rails'
|
|
10
|
+
|
|
11
|
+
And then execute:
|
|
12
|
+
|
|
13
|
+
$ bundle
|
|
14
|
+
|
|
15
|
+
Or install it yourself as:
|
|
16
|
+
|
|
17
|
+
$ gem install gumby-rails
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## Contributing
|
|
25
|
+
|
|
26
|
+
1. Fork it
|
|
27
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
28
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
|
29
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
30
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require "bundler/gem_tasks"
|
data/gumby-rails.gemspec
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'gumby-rails/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |gem|
|
|
7
|
+
gem.name = "gumby-rails"
|
|
8
|
+
gem.version = Gumby::Rails::VERSION
|
|
9
|
+
gem.authors = ["Fábio Luiz Nery de Miranda"]
|
|
10
|
+
gem.email = ["fabio@miranti.net.br"]
|
|
11
|
+
gem.description = %q{A rails gem for http://gumbyframework.com assets}
|
|
12
|
+
gem.summary = %q{}
|
|
13
|
+
gem.homepage = "https://github.com/fabiolnm/gumby-rails"
|
|
14
|
+
|
|
15
|
+
gem.files = `git ls-files`.split($/)
|
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
|
18
|
+
gem.require_paths = ["lib"]
|
|
19
|
+
|
|
20
|
+
gem.add_development_dependency "jquery-rails"
|
|
21
|
+
gem.add_development_dependency "modernizr-rails"
|
|
22
|
+
end
|
data/lib/gumby-rails.rb
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/* Gumby JS */
|
|
2
|
+
|
|
3
|
+
(function ($) {
|
|
4
|
+
|
|
5
|
+
var Gumby = function () {
|
|
6
|
+
|
|
7
|
+
// Gumby data object for storing simpleUI classes and handlers
|
|
8
|
+
var gumbyData = {},
|
|
9
|
+
|
|
10
|
+
setGumbyData = function (key, value) {
|
|
11
|
+
return gumbyData[key] = value;
|
|
12
|
+
},
|
|
13
|
+
|
|
14
|
+
getGumbyData = function (key) {
|
|
15
|
+
return gumbyData[key] || false;
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Simple UI Elements
|
|
20
|
+
* ------------------
|
|
21
|
+
* UI elements that bind to an event, toggle
|
|
22
|
+
* a class with possibility to run simple logic
|
|
23
|
+
* on completion and test for specific conditions
|
|
24
|
+
*/
|
|
25
|
+
simpleUI = {
|
|
26
|
+
|
|
27
|
+
// simple UI elements holder object
|
|
28
|
+
ui: [
|
|
29
|
+
|
|
30
|
+
// checkbox - check/uncheck (including hidden input) on click
|
|
31
|
+
{
|
|
32
|
+
selector: '.checkbox',
|
|
33
|
+
onEvent: 'click',
|
|
34
|
+
className: 'checked',
|
|
35
|
+
target: false,
|
|
36
|
+
condition: false,
|
|
37
|
+
// check/uncheck hidden checkbox input
|
|
38
|
+
complete: function ($e) {
|
|
39
|
+
var checked = $e.hasClass('checked');
|
|
40
|
+
$e.children('input').attr('checked', checked).change();
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
// radio - check/uncheck (including hidden input) on click
|
|
45
|
+
// also uncheck all others with same name
|
|
46
|
+
{
|
|
47
|
+
selector: '.radio',
|
|
48
|
+
onEvent: 'click',
|
|
49
|
+
className: 'checked',
|
|
50
|
+
target: false,
|
|
51
|
+
condition: false,
|
|
52
|
+
// check hidden radio input and uncheck others
|
|
53
|
+
complete: function ($e) {
|
|
54
|
+
var $input = $e.children('input'),
|
|
55
|
+
// radio buttons with matching names in the same group
|
|
56
|
+
$otherInputs = $('input[name="' + $input.attr('name') + '"]');
|
|
57
|
+
|
|
58
|
+
// uncheck other radio buttons that are currently checked
|
|
59
|
+
// loop round so we can trigger change on required elements
|
|
60
|
+
$otherInputs.each(function() {
|
|
61
|
+
var $this = $(this);
|
|
62
|
+
|
|
63
|
+
// uncheck select radio buttons in group
|
|
64
|
+
$this.attr('checked', false).parent().removeClass('checked');
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// check this one and trigger change on it
|
|
68
|
+
$input.attr('checked', true).change().parent().addClass('checked')
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// validation - add/remove error class dependent on value being present
|
|
73
|
+
// conditional method used to check for value
|
|
74
|
+
{
|
|
75
|
+
selector: 'form[data-form="validate"] .field',
|
|
76
|
+
onEvent: 'blur',
|
|
77
|
+
className: 'error',
|
|
78
|
+
target: false,
|
|
79
|
+
// check input is required and if so add/remove error class based on present value
|
|
80
|
+
condition: function ($e) {
|
|
81
|
+
var $child = $e.find('input, textarea').first(),
|
|
82
|
+
val = $child.val(),
|
|
83
|
+
req = $child.attr('data-form');
|
|
84
|
+
|
|
85
|
+
if(!req || req !== 'required') {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// email/regular validation
|
|
90
|
+
if (($child.attr('type') === 'email' && !val.match(/^[\w.%&=+$#!-']+@[\w.-]+\.[a-zA-Z]{2,4}$/)) || !val.length) {
|
|
91
|
+
$e.addClass('error');
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
$e.removeClass('error');
|
|
96
|
+
},
|
|
97
|
+
complete: false
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
// toggles - toggle active class on itself and selector in data-for
|
|
101
|
+
// on click
|
|
102
|
+
{
|
|
103
|
+
selector: '.toggle:not([data-on]), .toggle[data-on="click"]',
|
|
104
|
+
onEvent: 'click',
|
|
105
|
+
className: 'active',
|
|
106
|
+
target: function($e) {
|
|
107
|
+
return $e.add($($e.attr('data-for')));
|
|
108
|
+
},
|
|
109
|
+
condition: false,
|
|
110
|
+
complete: false
|
|
111
|
+
},
|
|
112
|
+
|
|
113
|
+
// on mouseover (will always add class) and mouseout (will always remove class)
|
|
114
|
+
{
|
|
115
|
+
selector: '.toggle[data-on="hover"]',
|
|
116
|
+
onEvent: 'mouseover mouseout',
|
|
117
|
+
className: 'active',
|
|
118
|
+
target: function($e) {
|
|
119
|
+
return $e.add($($e.attr('data-for')));
|
|
120
|
+
},
|
|
121
|
+
condition: false,
|
|
122
|
+
complete: false
|
|
123
|
+
}
|
|
124
|
+
],
|
|
125
|
+
|
|
126
|
+
// initialize simple UI
|
|
127
|
+
init: function () {
|
|
128
|
+
|
|
129
|
+
var x, ui, $e, callBack, conditionalCallBack, activeClass, targetName;
|
|
130
|
+
|
|
131
|
+
// loop round gumby UI elements applying active/inactive class logic
|
|
132
|
+
for(x = 0; x < simpleUI.ui.length; x++) {
|
|
133
|
+
|
|
134
|
+
ui = simpleUI.ui[x];
|
|
135
|
+
$e = $(ui.selector);
|
|
136
|
+
// complete call back
|
|
137
|
+
callBack = ui.complete && typeof ui.complete === 'function' ? ui.complete : false;
|
|
138
|
+
// conditional callback
|
|
139
|
+
conditionalCallBack = ui.condition && typeof ui.condition === 'function' ? ui.condition : false;
|
|
140
|
+
targetName = ui.target && typeof ui.target === 'function' ? ui.target : false;
|
|
141
|
+
activeClass = ui.className || false;
|
|
142
|
+
|
|
143
|
+
// store UI data
|
|
144
|
+
// replace spaces with dashes for GumbyData object reference
|
|
145
|
+
setGumbyData(ui.selector.replace(' ', '-'), {
|
|
146
|
+
'GumbyCallback' : callBack,
|
|
147
|
+
'GumbyConditionalCallBack' : conditionalCallBack,
|
|
148
|
+
'GumbyActiveClass' : activeClass,
|
|
149
|
+
'GumbyTarget' : targetName
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// bind it all!
|
|
153
|
+
$(document).on(ui.onEvent, ui.selector, function (e) {
|
|
154
|
+
e.preventDefault();
|
|
155
|
+
|
|
156
|
+
var $this = $(this),
|
|
157
|
+
$target = $(this),
|
|
158
|
+
gumbyData = getGumbyData(e.handleObj.selector.replace(' ', '-')),
|
|
159
|
+
condition = true;
|
|
160
|
+
|
|
161
|
+
// if there is a conditional function test it here
|
|
162
|
+
// leaving if it returns false
|
|
163
|
+
if(gumbyData.GumbyConditionalCallBack) {
|
|
164
|
+
return condition = gumbyData.GumbyConditionalCallBack($this);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// no conditional or it passed so toggle class
|
|
168
|
+
if (gumbyData.GumbyActiveClass) {
|
|
169
|
+
// check for sepcified target
|
|
170
|
+
if(gumbyData.GumbyTarget) {
|
|
171
|
+
$target = gumbyData.GumbyTarget($this);
|
|
172
|
+
}
|
|
173
|
+
$target.toggleClass(gumbyData.GumbyActiveClass);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// if complete call back present call it here
|
|
177
|
+
if (gumbyData.GumbyCallback) {
|
|
178
|
+
gumbyData.GumbyCallback($this);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
},
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Complex UI Elements
|
|
187
|
+
* ------------------
|
|
188
|
+
* UI elements that require logic passed the
|
|
189
|
+
* capabilities of simple add/remove class.
|
|
190
|
+
*/
|
|
191
|
+
complexUI = {
|
|
192
|
+
|
|
193
|
+
// init separate complexUI elements
|
|
194
|
+
init: function () {
|
|
195
|
+
complexUI.pickers();
|
|
196
|
+
complexUI.skipLinks();
|
|
197
|
+
complexUI.tabs();
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// pickers - open picker on click and update <select> and picker label when option chosen
|
|
201
|
+
pickers: function() {
|
|
202
|
+
|
|
203
|
+
// open picker on click
|
|
204
|
+
$(document).on('click', '.picker', function (e) {
|
|
205
|
+
e.preventDefault();
|
|
206
|
+
|
|
207
|
+
var $this = $(this),
|
|
208
|
+
openTimer = null;
|
|
209
|
+
|
|
210
|
+
// custom .picker style are removed on handheld devices using :after to insert hidden content and inform JS
|
|
211
|
+
if (window.getComputedStyle && window.getComputedStyle($this.get(0), ':after').getPropertyValue('content') === 'handheld') {
|
|
212
|
+
return false;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// mouseout for > 500ms will close picker
|
|
216
|
+
$this.hover(function () {
|
|
217
|
+
clearTimeout(openTimer);
|
|
218
|
+
}, function () {
|
|
219
|
+
var $this = $(this);
|
|
220
|
+
openTimer = setTimeout(function () {
|
|
221
|
+
$this.removeClass('open');
|
|
222
|
+
}, 500);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
$this.toggleClass('open');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// clicking children elements should update hidden <select> and .picker active label
|
|
229
|
+
$(document).on('click', '.picker > ul > li', function (e) {
|
|
230
|
+
e.preventDefault();
|
|
231
|
+
|
|
232
|
+
var $this = $(this),
|
|
233
|
+
$parent = $this.parents('.picker'),
|
|
234
|
+
val = $this.children('a').html();
|
|
235
|
+
|
|
236
|
+
// update label
|
|
237
|
+
$parent.children('.toggle').html(val + '<span class="caret"></span>');
|
|
238
|
+
|
|
239
|
+
// update hidden select and trigger change event
|
|
240
|
+
$parent.find('option').attr('selected', false).eq($this.index() + 1)
|
|
241
|
+
.attr('selected', true).parent('select').change();
|
|
242
|
+
});
|
|
243
|
+
},
|
|
244
|
+
|
|
245
|
+
// skiplinks - slide to data-type content area on click of skiplink and on window load if hash present
|
|
246
|
+
skipLinks: function () {
|
|
247
|
+
var skip = function () {
|
|
248
|
+
|
|
249
|
+
var skipTypeParts,
|
|
250
|
+
skipType,
|
|
251
|
+
$skipTos = $('[data-type]'),
|
|
252
|
+
$skipTo = false,
|
|
253
|
+
onWin = false,
|
|
254
|
+
$this = $(this);
|
|
255
|
+
|
|
256
|
+
if ($this.get(0) === window && !window.location.hash) {
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// initial load skip
|
|
261
|
+
if ($this.get(0) === window && window.location.hash) {
|
|
262
|
+
skipType = window.location.hash.replace('#', '');
|
|
263
|
+
onWin = true;
|
|
264
|
+
} else {
|
|
265
|
+
skipTypeParts = $this.attr('href').split('#');
|
|
266
|
+
skipType = skipTypeParts[skipTypeParts.length - 1];
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// loop round potential data-type matches
|
|
270
|
+
$skipTos.each(function () {
|
|
271
|
+
// data-type can be multiple space separated values
|
|
272
|
+
var typeParts = $(this).attr('data-type').split(' '), x;
|
|
273
|
+
|
|
274
|
+
// find first match and break the each
|
|
275
|
+
for (x in typeParts) {
|
|
276
|
+
if (typeParts[x] === skipType) {
|
|
277
|
+
$skipTo = $(this);
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
if (!$skipTo.length) {
|
|
284
|
+
return false;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// scroll to skiplink
|
|
288
|
+
$('body,html').animate({
|
|
289
|
+
'scrollTop' : $skipTo.offset().top
|
|
290
|
+
}, 350);
|
|
291
|
+
|
|
292
|
+
// update hash if not an initial hash load
|
|
293
|
+
if (onWin) {
|
|
294
|
+
window.location.hash = skipType;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
// bind to skip links and window load
|
|
300
|
+
$(document).on('click', '.skiplink a, .skipnav ul li a, .skip', skip);
|
|
301
|
+
$(window).load(skip);
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
// tabs - activate tab and tab content on click as well as on window load if hash present
|
|
305
|
+
tabs: function () {
|
|
306
|
+
|
|
307
|
+
var activateTab = function ($tab) {
|
|
308
|
+
var // this links tabs set
|
|
309
|
+
$tabs = $tab.parents('.tabs'),
|
|
310
|
+
// currently active tab
|
|
311
|
+
activeTab = {
|
|
312
|
+
'tab' : $tabs.find('ul').children('li.active'),
|
|
313
|
+
'content' : $tabs.find('div[data-tab].active')
|
|
314
|
+
},
|
|
315
|
+
// newly clicked tab
|
|
316
|
+
newTab = {
|
|
317
|
+
'tab' : $tab.parent('li'),
|
|
318
|
+
'content' : $tabs.find('[data-tab=' + $tab.attr('href').replace('#', '') + ']')
|
|
319
|
+
},
|
|
320
|
+
x, y;
|
|
321
|
+
|
|
322
|
+
// remove active class from tab and content
|
|
323
|
+
for (x in activeTab) {
|
|
324
|
+
activeTab[x].removeClass('active');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// add active class to tab and content
|
|
328
|
+
for (y in newTab) {
|
|
329
|
+
newTab[y].addClass('active');
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// hook up tab links
|
|
334
|
+
$(document).on('click', '.tabs > ul > li > a', function(e) {
|
|
335
|
+
activateTab($(this));
|
|
336
|
+
});
|
|
337
|
+
|
|
338
|
+
// hook up initial load active tab
|
|
339
|
+
if (window.location.hash) {
|
|
340
|
+
var $activeTab = $('a[href="' + window.location.hash + '"]');
|
|
341
|
+
if ($activeTab.length && $activeTab.parents('.tabs').length) {
|
|
342
|
+
activateTab($activeTab);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
// initialize Gumby
|
|
349
|
+
init = function () {
|
|
350
|
+
simpleUI.init();
|
|
351
|
+
complexUI.init();
|
|
352
|
+
};
|
|
353
|
+
|
|
354
|
+
// return public methods
|
|
355
|
+
return {
|
|
356
|
+
i: init
|
|
357
|
+
}
|
|
358
|
+
}().i();
|
|
359
|
+
|
|
360
|
+
})(window.jQuery);
|
|
361
|
+
|