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.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in gumby-rails.gemspec
4
+ gemspec
@@ -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.
@@ -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
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -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
@@ -0,0 +1,8 @@
1
+ require "gumby-rails/version"
2
+
3
+ module Gumby
4
+ module Rails
5
+ class Engine < ::Rails::Engine
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,5 @@
1
+ module Gumby
2
+ module Rails
3
+ VERSION = "1.1"
4
+ end
5
+ end
@@ -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
+