-
Notifications
You must be signed in to change notification settings - Fork 6
/
gumby.images.js
executable file
·202 lines (165 loc) · 5.11 KB
/
gumby.images.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
* Gumby Images
*/
!function() {
'use strict';
function Images($el) {
Gumby.debug('Initializing Responsive Images module', $el);
this.$el = $el;
this.type = '';
this.supports = '';
this.media = '';
this.def = '';
this.current = '';
// set up module based on attributes
this.setup();
var scope = this;
$(window).on('load gumby.trigger '+(!this.media || 'resize'), function(e) {
scope.fire();
});
this.$el.on('gumby.initialize', function() {
Gumby.debug('Re-initializing Responsive Images module', scope.$el);
scope.setup();
scope.fire();
});
scope.fire();
}
// set up module based on attributes
Images.prototype.setup = function() {
// is this an <img> or background-image?
this.type = this.$el.is('img') ? 'img' : 'bg';
// supports attribute in format test:image
this.supports = Gumby.selectAttr.apply(this.$el, ['supports']) || false;
// media attribute in format mediaQuery:image
this.media = Gumby.selectAttr.apply(this.$el, ['media']) || false;
// default image to load
this.def = Gumby.selectAttr.apply(this.$el, ['default']) || false;
// parse support/media objects
if(this.supports) { this.supports = this.parseAttr(this.supports); }
if(this.media) { this.media = this.parseAttr(this.media); }
// check functions
this.checks = {
supports : function(val) {
return Modernizr[val];
},
media: function(val) {
return window.matchMedia(val).matches;
}
};
};
// fire required checks and load resulting image
Images.prototype.fire = function() {
// feature supported or media query matched
var success = false;
// if support attribute supplied and Modernizr is present
if(this.supports && Modernizr) {
success = this.handleTests('supports', this.supports);
}
// if media attribute supplied and matchMedia is supported
// and success is still false, meaning no supporting feature was found
if(this.media && window.matchMedia && !success) {
success = this.handleTests('media', this.media);
}
// no feature supported or media query matched so load default if supplied
if(!success && this.def) {
success = this.def;
}
// no image to load
if(!success) {
return false;
}
// preload image and insert or set background-image property if not already set
if(this.current !== success) {
this.current = success;
this.insertImage(this.type, success);
}
};
// handle media object checking each prop for matching media query
Images.prototype.handleTests = function(type, array) {
var scope = this,
supported = false;
$(array).each(function(key, val) {
// media query matched
// supplied in order of preference so halt each loop
if(scope.check(type, val.test)) {
supported = val.img;
return false;
}
});
return supported;
};
// return the result of test function
Images.prototype.check = function(type, val) {
return this.checks[type](val);
};
// preload image and insert or set background-image property
Images.prototype.insertImage = function(type, img) {
var scope = this,
image = $(new Image());
image.load(function() {
type === 'img' ? scope.$el.attr('src', img) : scope.$el.css('background-image', 'url('+img+')');
// trigger custom loaded event
Gumby.debug('Triggering onChange event', img, scope.$el);
scope.$el.trigger('gumby.onChange', [img]);
}).attr('src', img);
};
// parse attribute strings, media/support
Images.prototype.parseAttr = function(support) {
var scope = this,
supp = support.split(','),
res = [], splt = [];
// multiple can be supplied so loop round and create object
$(supp).each(function(key, val) {
splt = val.split('|');
if(splt.length !== 2) {
return true;
}
// object containing Modernizr test or media query and image url
res.push({
'test' : scope.shorthand(splt[0]),
'img' : splt[1]
});
});
return res;
};
// replace < and > with min/max width media queries
Images.prototype.shorthand = function(str) {
// replace < and >
if(str.indexOf('>') > -1 || str.indexOf('<') > -1) {
str = str.replace('>', 'min-width: ').replace('<', 'max-width: ');
}
// check if media query (prevent wrapping feature detection tests) AND if media query, wrapped in ()
if(str.indexOf('width') > -1
&& str.charAt(0) !== '(' && str.charAt(str.length - 1) !== ')') {
str = '('+str+')';
}
return str;
};
// add initialisation
Gumby.addInitalisation('images', function(all) {
$('[gumby-supports],[data-supports],[supports],[gumby-media],[data-media],[media]').each(function() {
var $this = $(this);
// this element has already been initialized
// and we're only initializing new modules
if($this.data('isImage') && !all) {
return true;
// this element has already been initialized
// and we need to reinitialize it
} else if($this.data('isImage') && all) {
$this.trigger('gumby.initialize');
return true;
}
// mark element as initialized
$this.data('isImage', true);
new Images($this);
});
});
// register UI module
Gumby.UIModule({
module: 'images',
events: ['onChange', 'trigger'],
init: function() {
Gumby.initialize('images');
}
});
}();