gumby 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +73 -0
- data/Rakefile +1 -0
- data/gumby.gemspec +20 -0
- data/lib/gumby.rb +8 -0
- data/lib/gumby/version.rb +5 -0
- data/vendor/assets/fonts/icons/entypo.eot +0 -0
- data/vendor/assets/fonts/icons/entypo.ttf +0 -0
- data/vendor/assets/fonts/icons/entypo.woff +0 -0
- data/vendor/assets/javascripts/gumby.js +150 -0
- data/vendor/assets/javascripts/gumby.min.js +1 -0
- data/vendor/assets/javascripts/ui/gumby.checkbox.js +84 -0
- data/vendor/assets/javascripts/ui/gumby.fittext.js +107 -0
- data/vendor/assets/javascripts/ui/gumby.fixed.js +206 -0
- data/vendor/assets/javascripts/ui/gumby.navbar.js +115 -0
- data/vendor/assets/javascripts/ui/gumby.radiobtn.js +74 -0
- data/vendor/assets/javascripts/ui/gumby.retina.js +74 -0
- data/vendor/assets/javascripts/ui/gumby.skiplink.js +145 -0
- data/vendor/assets/javascripts/ui/gumby.tabs.js +71 -0
- data/vendor/assets/javascripts/ui/gumby.toggleswitch.js +203 -0
- data/vendor/assets/javascripts/ui/jquery.validation.js +138 -0
- data/vendor/assets/stylesheets/gumby.css +1876 -0
- metadata +101 -0
@@ -0,0 +1,206 @@
|
|
1
|
+
/**
|
2
|
+
* Gumby Fixed
|
3
|
+
*/
|
4
|
+
!function() {
|
5
|
+
|
6
|
+
'use strict';
|
7
|
+
|
8
|
+
function Fixed($el) {
|
9
|
+
this.$el = $el;
|
10
|
+
|
11
|
+
this.fixedPoint = '';
|
12
|
+
this.pinPoint = false;
|
13
|
+
this.offset = 0;
|
14
|
+
this.pinOffset = 0;
|
15
|
+
this.top = 0;
|
16
|
+
this.constrainEl = true;
|
17
|
+
this.state = false;
|
18
|
+
this.measurements = {
|
19
|
+
left: 0,
|
20
|
+
width: 0
|
21
|
+
};
|
22
|
+
|
23
|
+
// set up module based on attributes
|
24
|
+
this.setup();
|
25
|
+
|
26
|
+
var scope = this;
|
27
|
+
|
28
|
+
// monitor scroll and update fixed elements accordingly
|
29
|
+
$(window).on('scroll load', function() {
|
30
|
+
scope.monitorScroll();
|
31
|
+
});
|
32
|
+
|
33
|
+
// reinitialize event listener
|
34
|
+
this.$el.on('gumby.initialize', function() {
|
35
|
+
scope.setup();
|
36
|
+
});
|
37
|
+
}
|
38
|
+
|
39
|
+
// set up module based on attributes
|
40
|
+
Fixed.prototype.setup = function() {
|
41
|
+
var scope = this;
|
42
|
+
|
43
|
+
this.fixedPoint = this.parseAttrValue(Gumby.selectAttr.apply(this.$el, ['fixed']));
|
44
|
+
|
45
|
+
// pin point is optional
|
46
|
+
this.pinPoint = Gumby.selectAttr.apply(this.$el, ['pin']) || false;
|
47
|
+
|
48
|
+
// offset from fixed point
|
49
|
+
this.offset = Number(Gumby.selectAttr.apply(this.$el, ['offset'])) || 0;
|
50
|
+
|
51
|
+
// offset from pin point
|
52
|
+
this.pinOffset = Number(Gumby.selectAttr.apply(this.$el, ['pinoffset'])) || 0;
|
53
|
+
|
54
|
+
// top position when fixed
|
55
|
+
this.top = Number(Gumby.selectAttr.apply(this.$el, ['top'])) || 0;
|
56
|
+
|
57
|
+
// constrain can be turned off
|
58
|
+
this.constrainEl = Gumby.selectAttr.apply(this.$el, ['constrain']) || true;
|
59
|
+
if(this.constrainEl === 'false') {
|
60
|
+
this.constrainEl = false;
|
61
|
+
}
|
62
|
+
|
63
|
+
// reference to the parent, row/column
|
64
|
+
this.$parent = this.$el.parents('.columns, .column, .row');
|
65
|
+
this.$parent = this.$parent.length ? this.$parent.first() : false;
|
66
|
+
this.parentRow = this.$parent ? !!this.$parent.hasClass('row') : false;
|
67
|
+
|
68
|
+
// if optional pin point set then parse now
|
69
|
+
if(this.pinPoint) {
|
70
|
+
this.pinPoint = this.parseAttrValue(this.pinPoint);
|
71
|
+
}
|
72
|
+
|
73
|
+
// if we have a parent constrain dimenions
|
74
|
+
if(this.$parent && this.constrainEl) {
|
75
|
+
// measure up
|
76
|
+
this.measure();
|
77
|
+
// and on resize reset measurement
|
78
|
+
$(window).resize(function() {
|
79
|
+
if(scope.state) {
|
80
|
+
scope.measure();
|
81
|
+
scope.constrain();
|
82
|
+
}
|
83
|
+
});
|
84
|
+
}
|
85
|
+
};
|
86
|
+
|
87
|
+
// monitor scroll and trigger changes based on position
|
88
|
+
Fixed.prototype.monitorScroll = function() {
|
89
|
+
var scrollAmount = $(window).scrollTop(),
|
90
|
+
// recalculate selector attributes as position may have changed
|
91
|
+
fixedPoint = this.fixedPoint instanceof jQuery ? this.fixedPoint.offset().top : this.fixedPoint,
|
92
|
+
pinPoint = false;
|
93
|
+
|
94
|
+
// if a pin point is set recalculate
|
95
|
+
if(this.pinPoint) {
|
96
|
+
pinPoint = this.pinPoint instanceof jQuery ? this.pinPoint.offset().top : this.pinPoint;
|
97
|
+
}
|
98
|
+
|
99
|
+
// apply offsets
|
100
|
+
if(this.offset) { fixedPoint -= this.offset; }
|
101
|
+
if(this.pinOffset) { pinPoint -= this.pinOffset; }
|
102
|
+
|
103
|
+
// fix it
|
104
|
+
if((scrollAmount >= fixedPoint) && this.state !== 'fixed') {
|
105
|
+
if(!pinPoint || scrollAmount < pinPoint) {
|
106
|
+
this.fix();
|
107
|
+
}
|
108
|
+
// unfix it
|
109
|
+
} else if(scrollAmount < fixedPoint && this.state === 'fixed') {
|
110
|
+
this.unfix();
|
111
|
+
|
112
|
+
// pin it
|
113
|
+
} else if(pinPoint && scrollAmount >= pinPoint && this.state !== 'pinned') {
|
114
|
+
this.pin();
|
115
|
+
}
|
116
|
+
};
|
117
|
+
|
118
|
+
// fix the element and update state
|
119
|
+
Fixed.prototype.fix = function() {
|
120
|
+
this.state = 'fixed';
|
121
|
+
this.$el.css({
|
122
|
+
'top' : 0 + this.top
|
123
|
+
}).addClass('fixed').removeClass('unfixed pinned').trigger('gumby.onFixed');
|
124
|
+
|
125
|
+
// if we have a parent constrain dimenions
|
126
|
+
if(this.$parent) {
|
127
|
+
this.constrain();
|
128
|
+
}
|
129
|
+
};
|
130
|
+
|
131
|
+
// unfix the element and update state
|
132
|
+
Fixed.prototype.unfix = function() {
|
133
|
+
this.state = 'unfixed';
|
134
|
+
this.$el.addClass('unfixed').removeClass('fixed pinned').trigger('gumby.onUnfixed');
|
135
|
+
};
|
136
|
+
|
137
|
+
// pin the element in position
|
138
|
+
Fixed.prototype.pin = function() {
|
139
|
+
this.state = 'pinned';
|
140
|
+
this.$el.css({
|
141
|
+
'top' : this.$el.offset().top
|
142
|
+
}).addClass('pinned fixed').removeClass('unfixed').trigger('gumby.onPinned');
|
143
|
+
};
|
144
|
+
|
145
|
+
// constrain elements dimensions to match width/height
|
146
|
+
Fixed.prototype.constrain = function() {
|
147
|
+
this.$el.css({
|
148
|
+
left: this.measurements.left,
|
149
|
+
width: this.measurements.width
|
150
|
+
});
|
151
|
+
};
|
152
|
+
|
153
|
+
// measure up the parent for constraining
|
154
|
+
Fixed.prototype.measure = function() {
|
155
|
+
var offsets = this.$parent.offset(), parentPadding;
|
156
|
+
|
157
|
+
this.measurements.left = offsets.left;
|
158
|
+
this.measurements.width = this.$parent.width();
|
159
|
+
|
160
|
+
// if element has a parent row then need to consider padding
|
161
|
+
if(this.parentRow) {
|
162
|
+
parentPadding = Number(this.$parent.css('paddingLeft').replace(/px/, ''));
|
163
|
+
if(parentPadding) {
|
164
|
+
this.measurements.left += parentPadding;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
};
|
168
|
+
|
169
|
+
// parse attribute values, could be px, top, selector
|
170
|
+
Fixed.prototype.parseAttrValue = function(attr) {
|
171
|
+
// px value fixed point
|
172
|
+
if($.isNumeric(attr)) {
|
173
|
+
return Number(attr);
|
174
|
+
// 'top' string fixed point
|
175
|
+
} else if(attr === 'top') {
|
176
|
+
return this.$el.offset().top;
|
177
|
+
// selector specified
|
178
|
+
} else {
|
179
|
+
var $el = $(attr);
|
180
|
+
return $el;
|
181
|
+
}
|
182
|
+
};
|
183
|
+
|
184
|
+
// add initialisation
|
185
|
+
Gumby.addInitalisation('fixed', function() {
|
186
|
+
$('[data-fixed],[gumby-fixed],[fixed]').each(function() {
|
187
|
+
var $this = $(this);
|
188
|
+
// this element has already been initialized
|
189
|
+
if($this.data('isFixed')) {
|
190
|
+
return true;
|
191
|
+
}
|
192
|
+
// mark element as initialized
|
193
|
+
$this.data('isFixed', true);
|
194
|
+
new Fixed($this);
|
195
|
+
});
|
196
|
+
});
|
197
|
+
|
198
|
+
// register UI module
|
199
|
+
Gumby.UIModule({
|
200
|
+
module: 'fixed',
|
201
|
+
events: ['onFixed', 'onUnfixed'],
|
202
|
+
init: function() {
|
203
|
+
Gumby.initialize('fixed');
|
204
|
+
}
|
205
|
+
});
|
206
|
+
}();
|
@@ -0,0 +1,115 @@
|
|
1
|
+
/**
|
2
|
+
* Gumby Navbar
|
3
|
+
*/
|
4
|
+
!function() {
|
5
|
+
|
6
|
+
'use strict';
|
7
|
+
|
8
|
+
var $html = Gumby.$dom.find('html');
|
9
|
+
|
10
|
+
// define and init module on touch enabled devices only
|
11
|
+
// when we are at tablet size or smaller
|
12
|
+
if(!Modernizr.touch || $(window).width() > Gumby.breakpoint) {
|
13
|
+
|
14
|
+
// add Gumby no touch class
|
15
|
+
$html.addClass('gumby-no-touch');
|
16
|
+
return;
|
17
|
+
}
|
18
|
+
|
19
|
+
// add Gumby touch class
|
20
|
+
$html.addClass('gumby-touch');
|
21
|
+
|
22
|
+
function Navbar($el) {
|
23
|
+
this.$el = $el;
|
24
|
+
this.$dropDowns = this.$el.find('li:has(.dropdown)');
|
25
|
+
var scope = this;
|
26
|
+
|
27
|
+
// when navbar items
|
28
|
+
this.$dropDowns
|
29
|
+
// are tapped hide/show dropdowns
|
30
|
+
.on('tap', this.toggleDropdown)
|
31
|
+
// are swiped right open link
|
32
|
+
.on('swiperight', this.openLink);
|
33
|
+
|
34
|
+
// if there's a link set
|
35
|
+
if(this.$dropDowns.children('a').attr('href') !== '#') {
|
36
|
+
// append an icon
|
37
|
+
this.$dropDowns.children('a').append('<i class="icon-popup"></i>').children('i')
|
38
|
+
// and bind to click event to open link
|
39
|
+
.on('tap', this.openLink);
|
40
|
+
}
|
41
|
+
|
42
|
+
// on mousemove and touchstart toggle modernizr classes and disable/enable this module
|
43
|
+
// workaround for Pixel and other multi input devices
|
44
|
+
$(window).on('mousemove touchstart', function(e) {
|
45
|
+
e.stopImmediatePropagation();
|
46
|
+
if(e.type === 'mousemove') {
|
47
|
+
scope.$dropDowns.on('mouseover mouseout', scope.toggleDropdown);
|
48
|
+
}
|
49
|
+
});
|
50
|
+
}
|
51
|
+
|
52
|
+
Navbar.prototype.toggleDropdown = function(e) {
|
53
|
+
// prevent click from triggering here too
|
54
|
+
e.stopImmediatePropagation();
|
55
|
+
e.preventDefault();
|
56
|
+
|
57
|
+
var $this = $(this);
|
58
|
+
|
59
|
+
if($this.hasClass('active')) {
|
60
|
+
$this.removeClass('active');
|
61
|
+
} else {
|
62
|
+
$this.addClass('active');
|
63
|
+
}
|
64
|
+
};
|
65
|
+
|
66
|
+
// handle opening list item link
|
67
|
+
Navbar.prototype.openLink = function(e) {
|
68
|
+
e.stopImmediatePropagation();
|
69
|
+
e.preventDefault();
|
70
|
+
|
71
|
+
var $this = $(this),
|
72
|
+
$el, href;
|
73
|
+
|
74
|
+
// tapped icon
|
75
|
+
if($this.is('i')) {
|
76
|
+
$el = $this.parent('a');
|
77
|
+
// swiped li
|
78
|
+
} else if($this.is('li')) {
|
79
|
+
$el = $this.children('a');
|
80
|
+
}
|
81
|
+
|
82
|
+
href = $el.attr('href');
|
83
|
+
|
84
|
+
// open in new window
|
85
|
+
if($el.attr('target') == 'blank') {
|
86
|
+
window.open(href);
|
87
|
+
// regular relocation
|
88
|
+
} else {
|
89
|
+
window.location = href;
|
90
|
+
}
|
91
|
+
};
|
92
|
+
|
93
|
+
// add initialisation
|
94
|
+
Gumby.addInitalisation('navbars', function() {
|
95
|
+
$('.navbar').each(function() {
|
96
|
+
var $this = $(this);
|
97
|
+
// this element has already been initialized
|
98
|
+
if($this.data('isNavbar')) {
|
99
|
+
return true;
|
100
|
+
}
|
101
|
+
// mark element as initialized
|
102
|
+
$this.data('isNavbar', true);
|
103
|
+
new Navbar($this);
|
104
|
+
});
|
105
|
+
});
|
106
|
+
|
107
|
+
// register UI module
|
108
|
+
Gumby.UIModule({
|
109
|
+
module: 'navbar',
|
110
|
+
events: [],
|
111
|
+
init: function() {
|
112
|
+
Gumby.initialize('navbars');
|
113
|
+
}
|
114
|
+
});
|
115
|
+
}();
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/**
|
2
|
+
* Gumby RadioBtn
|
3
|
+
*/
|
4
|
+
!function() {
|
5
|
+
|
6
|
+
'use strict';
|
7
|
+
|
8
|
+
function RadioBtn($el) {
|
9
|
+
|
10
|
+
this.$el = $el;
|
11
|
+
var scope = this;
|
12
|
+
|
13
|
+
// listen for click event and custom gumby check event
|
14
|
+
this.$el.on(Gumby.click, function(e) {
|
15
|
+
// prevent propagation
|
16
|
+
e.stopImmediatePropagation();
|
17
|
+
|
18
|
+
// prevent radio button checking, we'll do that manually
|
19
|
+
e.preventDefault();
|
20
|
+
|
21
|
+
// check radio button
|
22
|
+
scope.update();
|
23
|
+
}).on('gumby.check', function() {
|
24
|
+
scope.update();
|
25
|
+
});
|
26
|
+
|
27
|
+
// update any .checked checkboxes on load
|
28
|
+
if(scope.$el.hasClass('checked')) {
|
29
|
+
scope.update();
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
// check radio button, uncheck all others in name group
|
34
|
+
RadioBtn.prototype.update = function() {
|
35
|
+
var // this specific radio button
|
36
|
+
$input = this.$el.find('input[type=radio]'),
|
37
|
+
$span = this.$el.find('span'),
|
38
|
+
// the group of radio buttons
|
39
|
+
group = 'input[name="'+$input.attr('name')+'"]';
|
40
|
+
|
41
|
+
// uncheck radio buttons in same group - uncheck input, remove checked class, remove <i>
|
42
|
+
$('.radio').has(group).removeClass('checked')
|
43
|
+
.find('input').prop('checked', false).end()
|
44
|
+
.find('i').remove();
|
45
|
+
|
46
|
+
// check this radio button - check input, add checked class, append <i>
|
47
|
+
$input.prop('checked', true);
|
48
|
+
$span.append('<i class="icon-dot" />');
|
49
|
+
this.$el.addClass('checked').trigger('gumby.onChange');
|
50
|
+
};
|
51
|
+
|
52
|
+
// add initialisation
|
53
|
+
Gumby.addInitalisation('radiobtns', function() {
|
54
|
+
$('.radio').each(function() {
|
55
|
+
var $this = $(this);
|
56
|
+
// this element has already been initialized
|
57
|
+
if($this.data('isRadioBtn')) {
|
58
|
+
return true;
|
59
|
+
}
|
60
|
+
// mark element as initialized
|
61
|
+
$this.data('isRadioBtn', true);
|
62
|
+
new RadioBtn($this);
|
63
|
+
});
|
64
|
+
});
|
65
|
+
|
66
|
+
// register UI module
|
67
|
+
Gumby.UIModule({
|
68
|
+
module: 'radiobtn',
|
69
|
+
events: ['onChange', 'check'],
|
70
|
+
init: function() {
|
71
|
+
Gumby.initialize('radiobtns');
|
72
|
+
}
|
73
|
+
});
|
74
|
+
}();
|
@@ -0,0 +1,74 @@
|
|
1
|
+
/**
|
2
|
+
* Gumby Retina
|
3
|
+
*/
|
4
|
+
!function() {
|
5
|
+
|
6
|
+
'use strict';
|
7
|
+
|
8
|
+
function Retina($el) {
|
9
|
+
this.$el = $el;
|
10
|
+
this.imageSrc = this.$el.attr('src');
|
11
|
+
this.retinaSrc = this.fetchRetinaImage();
|
12
|
+
this.$retinaImg = $(new Image());
|
13
|
+
|
14
|
+
var scope = this
|
15
|
+
|
16
|
+
// image src not valid
|
17
|
+
if(!this.retinaSrc) {
|
18
|
+
return false;
|
19
|
+
}
|
20
|
+
|
21
|
+
// load retina image
|
22
|
+
this.$retinaImg.attr('src', this.retinaSrc).load(function() {
|
23
|
+
scope.retinaImageLoaded();
|
24
|
+
});
|
25
|
+
}
|
26
|
+
|
27
|
+
// fetch retina src by appending '@2x' to image string before extension
|
28
|
+
Retina.prototype.fetchRetinaImage = function() {
|
29
|
+
var imgSrc = this.imageSrc,
|
30
|
+
index = this.imageSrc.search(/(\.|\/)(gif|jpe?g|png)$/i);
|
31
|
+
|
32
|
+
// image src is not valid
|
33
|
+
if(index < 0) {
|
34
|
+
return false;
|
35
|
+
}
|
36
|
+
|
37
|
+
// return retina src
|
38
|
+
return imgSrc.substr(0, index) + '@2x' + imgSrc.substr(index, imgSrc.length);
|
39
|
+
};
|
40
|
+
|
41
|
+
// once retina image loaded swap original src
|
42
|
+
Retina.prototype.retinaImageLoaded = function() {
|
43
|
+
this.$el.attr('src', this.$retinaImg.attr('src')).trigger('gumby.onRetina');
|
44
|
+
};
|
45
|
+
|
46
|
+
// add initialisation
|
47
|
+
Gumby.addInitalisation('retina', function() {
|
48
|
+
|
49
|
+
// this module is for retina devices only
|
50
|
+
if(!window.devicePixelRatio || window.devicePixelRatio <= 1) {
|
51
|
+
return;
|
52
|
+
}
|
53
|
+
|
54
|
+
$('img[data-retina],img[gumby-retina],img[retina]').each(function() {
|
55
|
+
var $this = $(this);
|
56
|
+
// this element has already been initialized
|
57
|
+
if($this.data('isRetina')) {
|
58
|
+
return true;
|
59
|
+
}
|
60
|
+
// mark element as initialized
|
61
|
+
$this.data('isRetina', true);
|
62
|
+
new Retina($this);
|
63
|
+
});
|
64
|
+
});
|
65
|
+
|
66
|
+
// register UI module
|
67
|
+
Gumby.UIModule({
|
68
|
+
module: 'retina',
|
69
|
+
events: ['onRetina'],
|
70
|
+
init: function() {
|
71
|
+
Gumby.initialize('retina');
|
72
|
+
}
|
73
|
+
});
|
74
|
+
}();
|