gumbie 0.1.0
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/gumbie.gemspec +25 -0
- data/lib/gumbie/version.rb +3 -0
- data/lib/gumbie.rb +7 -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/libs/gumby.init.js +47 -0
- data/vendor/assets/javascripts/libs/gumby.js +258 -0
- data/vendor/assets/javascripts/libs/gumby.min.js +1 -0
- data/vendor/assets/javascripts/libs/jquery-1.10.1.min.js +6 -0
- data/vendor/assets/javascripts/libs/jquery-1.10.1.min.map +1 -0
- data/vendor/assets/javascripts/libs/jquery-2.0.2.min.js +6 -0
- data/vendor/assets/javascripts/libs/jquery-2.0.2.min.map +1 -0
- data/vendor/assets/javascripts/libs/jquery.mobile.custom.min.js +3 -0
- data/vendor/assets/javascripts/libs/modernizr-2.6.2.min.js +4 -0
- data/vendor/assets/javascripts/libs/ui/gumby.checkbox.js +101 -0
- data/vendor/assets/javascripts/libs/ui/gumby.fixed.js +240 -0
- data/vendor/assets/javascripts/libs/ui/gumby.navbar.js +115 -0
- data/vendor/assets/javascripts/libs/ui/gumby.radiobtn.js +90 -0
- data/vendor/assets/javascripts/libs/ui/gumby.retina.js +81 -0
- data/vendor/assets/javascripts/libs/ui/gumby.skiplink.js +157 -0
- data/vendor/assets/javascripts/libs/ui/gumby.tabs.js +80 -0
- data/vendor/assets/javascripts/libs/ui/gumby.toggleswitch.js +264 -0
- data/vendor/assets/javascripts/libs/ui/jquery.validation.js +142 -0
- data/vendor/assets/javascripts/main.js +23 -0
- data/vendor/assets/javascripts/plugins.js +4 -0
- data/vendor/assets/stylesheets/gumby.css +1683 -0
- data/vendor/assets/stylesheets/style.css +4 -0
- metadata +134 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gumby Fixed
|
|
3
|
+
*/
|
|
4
|
+
!function($) {
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function Fixed($el) {
|
|
9
|
+
|
|
10
|
+
Gumby.debug('Initializing Fixed Position', $el);
|
|
11
|
+
|
|
12
|
+
this.$el = $el;
|
|
13
|
+
|
|
14
|
+
this.$window = $(window);
|
|
15
|
+
this.fixedPoint = '';
|
|
16
|
+
this.pinPoint = false;
|
|
17
|
+
this.fixedPointjQ = false;
|
|
18
|
+
this.pinPointjQ = false;
|
|
19
|
+
this.offset = 0;
|
|
20
|
+
this.pinOffset = 0;
|
|
21
|
+
this.top = 0;
|
|
22
|
+
this.constrainEl = true;
|
|
23
|
+
this.state = false;
|
|
24
|
+
this.measurements = {
|
|
25
|
+
left: 0,
|
|
26
|
+
width: 0
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
// set up module based on attributes
|
|
30
|
+
this.setup();
|
|
31
|
+
|
|
32
|
+
var scope = this;
|
|
33
|
+
|
|
34
|
+
// monitor scroll and update fixed elements accordingly
|
|
35
|
+
this.$window.on('scroll load', function() {
|
|
36
|
+
scope.monitorScroll();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// reinitialize event listener
|
|
40
|
+
this.$el.on('gumby.initialize', function() {
|
|
41
|
+
Gumby.debug('Re-initializing Fixed Position', $el);
|
|
42
|
+
scope.setup();
|
|
43
|
+
scope.monitorScroll();
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// set up module based on attributes
|
|
48
|
+
Fixed.prototype.setup = function() {
|
|
49
|
+
var scope = this;
|
|
50
|
+
|
|
51
|
+
this.fixedPoint = this.parseAttrValue(Gumby.selectAttr.apply(this.$el, ['fixed']));
|
|
52
|
+
|
|
53
|
+
// pin point is optional
|
|
54
|
+
this.pinPoint = Gumby.selectAttr.apply(this.$el, ['pin']) || false;
|
|
55
|
+
|
|
56
|
+
// offset from fixed point
|
|
57
|
+
this.offset = Number(Gumby.selectAttr.apply(this.$el, ['offset'])) || 0;
|
|
58
|
+
|
|
59
|
+
// offset from pin point
|
|
60
|
+
this.pinOffset = Number(Gumby.selectAttr.apply(this.$el, ['pinoffset'])) || 0;
|
|
61
|
+
|
|
62
|
+
// top position when fixed
|
|
63
|
+
this.top = Number(Gumby.selectAttr.apply(this.$el, ['top'])) || 0;
|
|
64
|
+
|
|
65
|
+
// constrain can be turned off
|
|
66
|
+
this.constrainEl = Gumby.selectAttr.apply(this.$el, ['constrain']) || true;
|
|
67
|
+
if(this.constrainEl === 'false') {
|
|
68
|
+
this.constrainEl = false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// reference to the parent, row/column
|
|
72
|
+
this.$parent = this.$el.parents('.columns, .column, .row');
|
|
73
|
+
this.$parent = this.$parent.length ? this.$parent.first() : false;
|
|
74
|
+
this.parentRow = this.$parent ? !!this.$parent.hasClass('row') : false;
|
|
75
|
+
|
|
76
|
+
// if optional pin point set then parse now
|
|
77
|
+
if(this.pinPoint) {
|
|
78
|
+
this.pinPoint = this.parseAttrValue(this.pinPoint);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.fixedPointjQ = this.fixedPoint instanceof jQuery;
|
|
82
|
+
this.pinPointjQ = this.pinPoint instanceof jQuery;
|
|
83
|
+
|
|
84
|
+
// if we have a parent constrain dimenions
|
|
85
|
+
if(this.$parent && this.constrainEl) {
|
|
86
|
+
// measure up
|
|
87
|
+
this.measure();
|
|
88
|
+
// and on resize reset measurement
|
|
89
|
+
this.$window.resize(function() {
|
|
90
|
+
if(scope.state) {
|
|
91
|
+
scope.measure();
|
|
92
|
+
scope.constrain();
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// monitor scroll and trigger changes based on position
|
|
99
|
+
Fixed.prototype.monitorScroll = function() {
|
|
100
|
+
var scrollAmount = this.$window.scrollTop(),
|
|
101
|
+
// recalculate selector attributes as position may have changed
|
|
102
|
+
fixedPoint = this.fixedPointjQ ? this.fixedPoint.offset().top : this.fixedPoint,
|
|
103
|
+
pinPoint = false,
|
|
104
|
+
timer;
|
|
105
|
+
|
|
106
|
+
// if a pin point is set recalculate
|
|
107
|
+
if(this.pinPoint) {
|
|
108
|
+
pinPoint = this.pinPointjQ ? this.pinPoint.offset().top : this.pinPoint;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// apply offsets
|
|
112
|
+
if(this.offset) { fixedPoint -= this.offset; }
|
|
113
|
+
if(this.pinOffset) { pinPoint -= this.pinOffset; }
|
|
114
|
+
|
|
115
|
+
// fix it
|
|
116
|
+
if((scrollAmount >= fixedPoint) && this.state !== 'fixed') {
|
|
117
|
+
if(!pinPoint || scrollAmount < pinPoint) {
|
|
118
|
+
this.fix();
|
|
119
|
+
}
|
|
120
|
+
// unfix it
|
|
121
|
+
} else if(scrollAmount < fixedPoint && this.state === 'fixed') {
|
|
122
|
+
this.unfix();
|
|
123
|
+
|
|
124
|
+
// pin it
|
|
125
|
+
} else if(pinPoint && scrollAmount >= pinPoint && this.state !== 'pinned') {
|
|
126
|
+
this.pin();
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
// fix the element and update state
|
|
131
|
+
Fixed.prototype.fix = function() {
|
|
132
|
+
Gumby.debug('Element has been fixed', this.$el);
|
|
133
|
+
Gumby.debug('Triggering onFixed event', this.$el);
|
|
134
|
+
|
|
135
|
+
this.state = 'fixed';
|
|
136
|
+
this.$el.css({
|
|
137
|
+
'top' : this.top
|
|
138
|
+
}).addClass('fixed').removeClass('unfixed pinned').trigger('gumby.onFixed');
|
|
139
|
+
|
|
140
|
+
// if we have a parent constrain dimenions
|
|
141
|
+
if(this.$parent) {
|
|
142
|
+
this.constrain();
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// unfix the element and update state
|
|
147
|
+
Fixed.prototype.unfix = function() {
|
|
148
|
+
Gumby.debug('Element has been unfixed', this.$el);
|
|
149
|
+
Gumby.debug('Triggering onUnfixed event', this.$el);
|
|
150
|
+
|
|
151
|
+
this.state = 'unfixed';
|
|
152
|
+
this.$el.addClass('unfixed').removeClass('fixed pinned').trigger('gumby.onUnfixed');
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// pin the element in position
|
|
156
|
+
Fixed.prototype.pin = function() {
|
|
157
|
+
Gumby.debug('Element has been pinned', this.$el);
|
|
158
|
+
Gumby.debug('Triggering onPinned event', this.$el);
|
|
159
|
+
this.state = 'pinned';
|
|
160
|
+
this.$el.css({
|
|
161
|
+
'top' : this.$el.offset().top
|
|
162
|
+
}).addClass('pinned fixed').removeClass('unfixed').trigger('gumby.onPinned');
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
// constrain elements dimensions to match width/height
|
|
166
|
+
Fixed.prototype.constrain = function() {
|
|
167
|
+
Gumby.debug("Constraining element", this.$el);
|
|
168
|
+
this.$el.css({
|
|
169
|
+
left: this.measurements.left,
|
|
170
|
+
width: this.measurements.width
|
|
171
|
+
});
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
// measure up the parent for constraining
|
|
175
|
+
Fixed.prototype.measure = function() {
|
|
176
|
+
var parentPadding;
|
|
177
|
+
|
|
178
|
+
this.measurements.left = this.$parent.offset().left;
|
|
179
|
+
this.measurements.width = this.$parent.width();
|
|
180
|
+
|
|
181
|
+
// if element has a parent row then need to consider padding
|
|
182
|
+
if(this.parentRow) {
|
|
183
|
+
parentPadding = Number(this.$parent.css('paddingLeft').replace(/px/, ''));
|
|
184
|
+
if(parentPadding) {
|
|
185
|
+
this.measurements.left += parentPadding;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// parse attribute values, could be px, top, selector
|
|
191
|
+
Fixed.prototype.parseAttrValue = function(attr) {
|
|
192
|
+
// px value fixed point
|
|
193
|
+
if($.isNumeric(attr)) {
|
|
194
|
+
return Number(attr);
|
|
195
|
+
// 'top' string fixed point
|
|
196
|
+
} else if(attr === 'top') {
|
|
197
|
+
return this.$el.offset().top;
|
|
198
|
+
// selector specified
|
|
199
|
+
} else {
|
|
200
|
+
var $el = $(attr);
|
|
201
|
+
if(!$el.length) {
|
|
202
|
+
Gumby.error('Cannot find Fixed target: '+attr);
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
return $el;
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// add initialisation
|
|
210
|
+
Gumby.addInitalisation('fixed', function(all) {
|
|
211
|
+
$('[data-fixed],[gumby-fixed],[fixed]').each(function() {
|
|
212
|
+
var $this = $(this);
|
|
213
|
+
|
|
214
|
+
// this element has already been initialized
|
|
215
|
+
// and we're only initializing new modules
|
|
216
|
+
if($this.data('isFixed') && !all) {
|
|
217
|
+
return true;
|
|
218
|
+
|
|
219
|
+
// this element has already been initialized
|
|
220
|
+
// and we need to reinitialize it
|
|
221
|
+
} else if($this.data('isFixed') && all) {
|
|
222
|
+
$this.trigger('gumby.initialize');
|
|
223
|
+
return true;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// mark element as initialized
|
|
227
|
+
$this.data('isFixed', true);
|
|
228
|
+
new Fixed($this);
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// register UI module
|
|
233
|
+
Gumby.UIModule({
|
|
234
|
+
module: 'fixed',
|
|
235
|
+
events: ['initialize', 'onFixed', 'onUnfixed'],
|
|
236
|
+
init: function() {
|
|
237
|
+
Gumby.initialize('fixed');
|
|
238
|
+
}
|
|
239
|
+
});
|
|
240
|
+
}(jQuery);
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gumby Navbar
|
|
3
|
+
*/
|
|
4
|
+
!function($) {
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
// define and init module on touch enabled devices only
|
|
9
|
+
if(!Gumby.gumbyTouch) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function Navbar($el) {
|
|
14
|
+
|
|
15
|
+
Gumby.debug('Initializing Navbar', $el);
|
|
16
|
+
|
|
17
|
+
this.$el = $el;
|
|
18
|
+
this.$dropDowns = this.$el.find('li:has(.dropdown)');
|
|
19
|
+
var scope = this;
|
|
20
|
+
|
|
21
|
+
var persist = this.$el.attr('gumby-persist');
|
|
22
|
+
if(typeof persist === 'undefined' && persist !== 'false') {
|
|
23
|
+
this.$el.find('li:not(:has(.dropdown)) a').on(Gumby.click, function() {
|
|
24
|
+
scope.$el.find('ul').removeClass('active');
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// when navbar items
|
|
29
|
+
this.$dropDowns
|
|
30
|
+
// are tapped hide/show dropdowns
|
|
31
|
+
.on(Gumby.click, this.toggleDropdown)
|
|
32
|
+
// are swiped right open link
|
|
33
|
+
.on('swiperight', this.openLink);
|
|
34
|
+
|
|
35
|
+
// if there's a link set
|
|
36
|
+
if(this.$dropDowns.children('a').attr('href') !== '#') {
|
|
37
|
+
// append an icon
|
|
38
|
+
this.$dropDowns.children('a').append('<i class="icon-popup"></i>').children('i')
|
|
39
|
+
// and bind to click event to open link
|
|
40
|
+
.on(Gumby.click, this.openLink);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// override with childlinks
|
|
44
|
+
this.$el.find('li:not(:has(.dropdown)) a[href]').on(Gumby.click, this.openLink);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Navbar.prototype.toggleDropdown = function(e) {
|
|
48
|
+
e.preventDefault();
|
|
49
|
+
|
|
50
|
+
if($(this).parents('.dropdown')) {
|
|
51
|
+
e.stopImmediatePropagation();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if($(e.target).is('i')) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
var $this = $(this);
|
|
59
|
+
|
|
60
|
+
if($this.hasClass('active')) {
|
|
61
|
+
$this.removeClass('active');
|
|
62
|
+
} else {
|
|
63
|
+
$this.addClass('active');
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// handle opening list item link
|
|
68
|
+
Navbar.prototype.openLink = function(e) {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
|
|
71
|
+
var $this = $(this),
|
|
72
|
+
$el = $this, 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('navbar', 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('navbar');
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}(jQuery);
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gumby RadioBtn
|
|
3
|
+
*/
|
|
4
|
+
!function($) {
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function RadioBtn($el) {
|
|
9
|
+
|
|
10
|
+
Gumby.debug('Initializing Radio Button', $el);
|
|
11
|
+
|
|
12
|
+
this.$el = $el;
|
|
13
|
+
this.$input = this.$el.find('input[type=radio]');
|
|
14
|
+
|
|
15
|
+
var scope = this;
|
|
16
|
+
|
|
17
|
+
// listen for click event and custom gumby check event
|
|
18
|
+
this.$el.on(Gumby.click, function(e) {
|
|
19
|
+
// prevent radio button checking, we'll do that manually
|
|
20
|
+
e.preventDefault();
|
|
21
|
+
|
|
22
|
+
// do nothing if radio is disabled
|
|
23
|
+
if (scope.$input.is('[disabled]')) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// check radio button
|
|
28
|
+
scope.update();
|
|
29
|
+
}).on('gumby.check', function() {
|
|
30
|
+
Gumby.debug('Check event triggered', scope.$el);
|
|
31
|
+
scope.update();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// update any prechecked on load
|
|
35
|
+
if(this.$input.prop('checked') || this.$el.hasClass('checked')) {
|
|
36
|
+
scope.update(true);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// check radio button, uncheck all others in name group
|
|
41
|
+
RadioBtn.prototype.update = function() {
|
|
42
|
+
|
|
43
|
+
// already checked so no need to update
|
|
44
|
+
if(this.$el.hasClass('checked') && this.$input.prop('checked') && this.$el.find('i.icon-dot').length) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
Gumby.debug('Updating Radio Button group', this.$el);
|
|
49
|
+
|
|
50
|
+
var $span = this.$el.find('span'),
|
|
51
|
+
// the group of radio buttons
|
|
52
|
+
group = 'input[name="'+this.$input.attr('name')+'"]';
|
|
53
|
+
|
|
54
|
+
// uncheck radio buttons in same group - uncheck input, remove checked class, remove <i>
|
|
55
|
+
$('.radio').has(group).removeClass('checked')
|
|
56
|
+
.find('input').prop('checked', false).end()
|
|
57
|
+
.find('i').remove();
|
|
58
|
+
|
|
59
|
+
// check this radio button - check input, add checked class, append <i>
|
|
60
|
+
this.$input.prop('checked', true);
|
|
61
|
+
$span.append('<i class="icon-dot" />');
|
|
62
|
+
|
|
63
|
+
Gumby.debug('Triggering onCheck event', this.$el);
|
|
64
|
+
|
|
65
|
+
this.$el.addClass('checked').trigger('gumby.onCheck');
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// add initialisation
|
|
69
|
+
Gumby.addInitalisation('radiobtn', function() {
|
|
70
|
+
$('.radio').each(function() {
|
|
71
|
+
var $this = $(this);
|
|
72
|
+
// this element has already been initialized
|
|
73
|
+
if($this.data('isRadioBtn')) {
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
// mark element as initialized
|
|
77
|
+
$this.data('isRadioBtn', true);
|
|
78
|
+
new RadioBtn($this);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// register UI module
|
|
83
|
+
Gumby.UIModule({
|
|
84
|
+
module: 'radiobtn',
|
|
85
|
+
events: ['onCheck', 'check'],
|
|
86
|
+
init: function() {
|
|
87
|
+
Gumby.initialize('radiobtn');
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}(jQuery);
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gumby Retina
|
|
3
|
+
*/
|
|
4
|
+
!function($) {
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function Retina($el) {
|
|
9
|
+
|
|
10
|
+
Gumby.debug('Initializing Retina', $el);
|
|
11
|
+
|
|
12
|
+
this.$el = $el;
|
|
13
|
+
this.imageSrc = this.$el.attr('src');
|
|
14
|
+
this.retinaSrc = this.fetchRetinaImage();
|
|
15
|
+
this.$retinaImg = $(new Image());
|
|
16
|
+
|
|
17
|
+
var scope = this;
|
|
18
|
+
|
|
19
|
+
// image src not valid
|
|
20
|
+
if(!this.retinaSrc) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// load retina image
|
|
25
|
+
this.$retinaImg.attr('src', this.retinaSrc).load(function() {
|
|
26
|
+
scope.retinaImageLoaded();
|
|
27
|
+
}).error(function() {
|
|
28
|
+
Gumby.error('Couln\'t load retina image: '+scope.retinaSrc);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// fetch retina src by appending '@2x' to image string before extension
|
|
33
|
+
Retina.prototype.fetchRetinaImage = function() {
|
|
34
|
+
var imgSrc = this.imageSrc,
|
|
35
|
+
index = this.imageSrc.search(/(\.|\/)(gif|jpe?g|png)$/i);
|
|
36
|
+
|
|
37
|
+
// image src is not valid
|
|
38
|
+
if(index < 0) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// return retina src
|
|
43
|
+
return imgSrc.substr(0, index) + '@2x' + imgSrc.substr(index, imgSrc.length);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// once retina image loaded swap original src
|
|
47
|
+
Retina.prototype.retinaImageLoaded = function() {
|
|
48
|
+
Gumby.debug('Swapping image for retina version', this.$el);
|
|
49
|
+
Gumby.debug('Triggering onRetina event', this.$el);
|
|
50
|
+
this.$el.attr('src', this.$retinaImg.attr('src')).trigger('gumby.onRetina');
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// add initialisation
|
|
54
|
+
Gumby.addInitalisation('retina', function() {
|
|
55
|
+
|
|
56
|
+
// this module is for retina devices only
|
|
57
|
+
if(!window.devicePixelRatio || window.devicePixelRatio <= 1) {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
$('img[data-retina],img[gumby-retina],img[retina]').each(function() {
|
|
62
|
+
var $this = $(this);
|
|
63
|
+
// this element has already been initialized
|
|
64
|
+
if($this.data('isRetina')) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
// mark element as initialized
|
|
68
|
+
$this.data('isRetina', true);
|
|
69
|
+
new Retina($this);
|
|
70
|
+
});
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
// register UI module
|
|
74
|
+
Gumby.UIModule({
|
|
75
|
+
module: 'retina',
|
|
76
|
+
events: ['onRetina'],
|
|
77
|
+
init: function() {
|
|
78
|
+
Gumby.initialize('retina');
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}(jQuery);
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Gumby SkipLink
|
|
3
|
+
*/
|
|
4
|
+
!function($) {
|
|
5
|
+
|
|
6
|
+
'use strict';
|
|
7
|
+
|
|
8
|
+
function SkipLink($el) {
|
|
9
|
+
|
|
10
|
+
Gumby.debug('Initializing Skiplink', $el);
|
|
11
|
+
|
|
12
|
+
this.$el = $el;
|
|
13
|
+
this.targetPos = 0;
|
|
14
|
+
this.duration = 0;
|
|
15
|
+
this.offset = false;
|
|
16
|
+
this.easing = '';
|
|
17
|
+
this.update = false;
|
|
18
|
+
|
|
19
|
+
// set up module based on attributes
|
|
20
|
+
this.setup();
|
|
21
|
+
|
|
22
|
+
var scope = this;
|
|
23
|
+
|
|
24
|
+
// skip to target element on click or trigger of gumby.skipTo event
|
|
25
|
+
this.$el.on(Gumby.click+' gumby.skip', function(e) {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
|
|
28
|
+
if(e.namespace === 'skip') {
|
|
29
|
+
Gumby.debug('Skip event triggered', scope.$el);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// calculate target on each click if update var set to true
|
|
33
|
+
if(scope.update) {
|
|
34
|
+
scope.calculateTarget(scope.skipTo);
|
|
35
|
+
|
|
36
|
+
// skip straight to target
|
|
37
|
+
} else {
|
|
38
|
+
scope.skipTo();
|
|
39
|
+
}
|
|
40
|
+
}).on('gumby.initialize', function() {
|
|
41
|
+
Gumby.debug('Re-initializing Skiplink', scope.$el);
|
|
42
|
+
scope.setup();
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// set up module based on attributes
|
|
47
|
+
SkipLink.prototype.setup = function() {
|
|
48
|
+
this.duration = Number(Gumby.selectAttr.apply(this.$el, ['duration'])) || 200;
|
|
49
|
+
this.offset = Gumby.selectAttr.apply(this.$el, ['offset']) || false;
|
|
50
|
+
this.easing = Gumby.selectAttr.apply(this.$el, ['easing']) || 'swing';
|
|
51
|
+
this.update = Gumby.selectAttr.apply(this.$el, ['update']) ? true : false;
|
|
52
|
+
|
|
53
|
+
this.calculateTarget();
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
// calculate target px point to skip to
|
|
57
|
+
SkipLink.prototype.calculateTarget = function(cb) {
|
|
58
|
+
|
|
59
|
+
var scope = this,
|
|
60
|
+
target = Gumby.selectAttr.apply(this.$el, ['goto']),
|
|
61
|
+
$target;
|
|
62
|
+
|
|
63
|
+
// 'top' specified so target is 0px
|
|
64
|
+
if(target == 'top') {
|
|
65
|
+
this.targetPos = 0;
|
|
66
|
+
|
|
67
|
+
// px point specified
|
|
68
|
+
} else if($.isNumeric(target)) {
|
|
69
|
+
this.targetPos = Number(target);
|
|
70
|
+
} else {
|
|
71
|
+
|
|
72
|
+
// check for element with target as selector
|
|
73
|
+
$target = $(target);
|
|
74
|
+
|
|
75
|
+
// target does not exist, we need a target
|
|
76
|
+
if(!$target.length) {
|
|
77
|
+
Gumby.error('Cannot find skiplink target: '+target);
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
this.targetPos = $target.offset().top;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if(cb) {
|
|
85
|
+
cb.apply(this);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
// animate body, html scrollTop value to target px point
|
|
90
|
+
SkipLink.prototype.skipTo = function() {
|
|
91
|
+
|
|
92
|
+
Gumby.debug('Skipping to target', this.$el);
|
|
93
|
+
|
|
94
|
+
var scope = this;
|
|
95
|
+
|
|
96
|
+
// slide to position of target
|
|
97
|
+
$('html,body').animate({
|
|
98
|
+
'scrollTop' : this.calculateOffset()
|
|
99
|
+
}, this.duration, this.easing).promise().done(function() {
|
|
100
|
+
|
|
101
|
+
Gumby.debug('Triggering onComplete event', scope.$el);
|
|
102
|
+
scope.$el.trigger('gumby.onComplete');
|
|
103
|
+
});
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
// calculate offset with current target point
|
|
107
|
+
SkipLink.prototype.calculateOffset = function() {
|
|
108
|
+
// no offset so return target here
|
|
109
|
+
if(!this.offset) {
|
|
110
|
+
return this.targetPos;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// negative / positive
|
|
114
|
+
var op = this.offset.substr(0, 1),
|
|
115
|
+
off = Number(this.offset.substr(1, this.offset.length));
|
|
116
|
+
|
|
117
|
+
// subtract offset from target position
|
|
118
|
+
if(op === '-') {
|
|
119
|
+
return this.targetPos - off;
|
|
120
|
+
// add offset to target position
|
|
121
|
+
} else if(op === '+') {
|
|
122
|
+
return this.targetPos + off;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// add initialisation
|
|
127
|
+
Gumby.addInitalisation('skiplink', function(all) {
|
|
128
|
+
$('.skiplink > a, .skip').each(function() {
|
|
129
|
+
var $this = $(this);
|
|
130
|
+
|
|
131
|
+
// this element has already been initialized
|
|
132
|
+
// and we're only initializing new modules
|
|
133
|
+
if($this.data('isSkipLink') && !all) {
|
|
134
|
+
return true;
|
|
135
|
+
|
|
136
|
+
// this element has already been initialized
|
|
137
|
+
// and we need to reinitialize it
|
|
138
|
+
} else if($this.data('isSkipLink') && all) {
|
|
139
|
+
$this.trigger('gumby.initialize');
|
|
140
|
+
return true;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// mark element as initialized
|
|
144
|
+
$this.data('isSkipLink', true);
|
|
145
|
+
new SkipLink($this);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// register UI module
|
|
150
|
+
Gumby.UIModule({
|
|
151
|
+
module: 'skiplink',
|
|
152
|
+
events: ['initialize', 'onComplete', 'skip'],
|
|
153
|
+
init: function() {
|
|
154
|
+
Gumby.initialize('skiplink');
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}(jQuery);
|