gumby-rails 1.1

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