webshims-rails 1.12.7 → 1.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/webshims-rails/version.rb +2 -2
- data/vendor/assets/javascripts/webshims/polyfiller.js +12 -1
- data/vendor/assets/javascripts/webshims/shims/combos/1.js +4 -1
- data/vendor/assets/javascripts/webshims/shims/combos/10.js +7 -4
- data/vendor/assets/javascripts/webshims/shims/combos/11.js +7 -4
- data/vendor/assets/javascripts/webshims/shims/combos/14.js +23 -10
- data/vendor/assets/javascripts/webshims/shims/combos/15.js +7 -2
- data/vendor/assets/javascripts/webshims/shims/combos/16.js +7 -2
- data/vendor/assets/javascripts/webshims/shims/combos/17.js +28 -13
- data/vendor/assets/javascripts/webshims/shims/combos/18.js +28 -13
- data/vendor/assets/javascripts/webshims/shims/combos/19.js +5 -4
- data/vendor/assets/javascripts/webshims/shims/combos/2.js +4 -1
- data/vendor/assets/javascripts/webshims/shims/combos/20.js +5 -4
- data/vendor/assets/javascripts/webshims/shims/combos/21.js +5 -4
- data/vendor/assets/javascripts/webshims/shims/combos/25.js +5 -4
- data/vendor/assets/javascripts/webshims/shims/combos/28.js +24 -10
- data/vendor/assets/javascripts/webshims/shims/combos/29.js +20 -9
- data/vendor/assets/javascripts/webshims/shims/combos/3.js +7 -2
- data/vendor/assets/javascripts/webshims/shims/combos/30.js +7 -2
- data/vendor/assets/javascripts/webshims/shims/combos/31.js +4 -1
- data/vendor/assets/javascripts/webshims/shims/combos/32.js +21 -9
- data/vendor/assets/javascripts/webshims/shims/combos/33.js +21 -9
- data/vendor/assets/javascripts/webshims/shims/combos/4.js +3 -1
- data/vendor/assets/javascripts/webshims/shims/combos/5.js +28 -13
- data/vendor/assets/javascripts/webshims/shims/combos/6.js +28 -13
- data/vendor/assets/javascripts/webshims/shims/combos/7.js +7 -2
- data/vendor/assets/javascripts/webshims/shims/combos/8.js +7 -2
- data/vendor/assets/javascripts/webshims/shims/combos/9.js +7 -4
- data/vendor/assets/javascripts/webshims/shims/form-core.js +4 -1
- data/vendor/assets/javascripts/webshims/shims/form-message.js +3 -1
- data/vendor/assets/javascripts/webshims/shims/form-number-date-api.js +20 -9
- data/vendor/assets/javascripts/webshims/shims/form-number-date-ui.js +7 -4
- data/vendor/assets/javascripts/webshims/shims/form-shim-extend2.js +7 -1
- data/vendor/assets/javascripts/webshims/shims/form-validation.js +4 -4
- data/vendor/assets/javascripts/webshims/shims/form-validators.js +6 -3
- data/vendor/assets/javascripts/webshims/shims/forms-picker.js +16 -13
- data/vendor/assets/javascripts/webshims/shims/mediaelement-jaris.js +5 -4
- data/vendor/assets/javascripts/webshims/shims/picture.js +570 -0
- data/vendor/assets/javascripts/webshims/shims/promise.js +684 -0
- data/vendor/assets/javascripts/webshims/shims/styles/color-picker.png +0 -0
- data/vendor/assets/javascripts/webshims/shims/styles/forms-ext.css +90 -38
- data/vendor/assets/javascripts/webshims/shims/styles/shim-ext.css +1039 -0
- data/vendor/assets/javascripts/webshims/shims/styles/widget.eot +0 -0
- data/vendor/assets/javascripts/webshims/shims/styles/widget.svg +12 -0
- data/vendor/assets/javascripts/webshims/shims/styles/widget.ttf +0 -0
- data/vendor/assets/javascripts/webshims/shims/styles/widget.woff +0 -0
- metadata +10 -10
- data/vendor/assets/javascripts/webshims/shims/styles/forms.png +0 -0
- data/vendor/assets/javascripts/webshims/shims/styles/scss/_api-forms-ext.scss +0 -219
- data/vendor/assets/javascripts/webshims/shims/styles/scss/_api-shim.scss +0 -115
- data/vendor/assets/javascripts/webshims/shims/styles/scss/_extends.scss +0 -31
- data/vendor/assets/javascripts/webshims/shims/styles/scss/forms-ext.scss +0 -479
- data/vendor/assets/javascripts/webshims/shims/styles/scss/forms-picker.scss +0 -488
- data/vendor/assets/javascripts/webshims/shims/styles/scss/shim-ext.scss +0 -2
- data/vendor/assets/javascripts/webshims/shims/styles/scss/shim.scss +0 -633
@@ -1136,6 +1136,12 @@ webshims.register('form-shim-extend2', function($, webshims, window, document, u
|
|
1136
1136
|
//pro forma
|
1137
1137
|
,color: 1
|
1138
1138
|
},
|
1139
|
+
inputElements = {
|
1140
|
+
input: 1,
|
1141
|
+
INPUT: 1,
|
1142
|
+
textarea: 1,
|
1143
|
+
TEXTAREA: 1
|
1144
|
+
},
|
1139
1145
|
timer,
|
1140
1146
|
lastVal,
|
1141
1147
|
input,
|
@@ -1181,7 +1187,7 @@ webshims.register('form-shim-extend2', function($, webshims, window, document, u
|
|
1181
1187
|
|
1182
1188
|
$(doc)
|
1183
1189
|
.on('focusin wswidgetfocusin', function(e){
|
1184
|
-
if( e.target && !e.target.readOnly && !e.target.disabled &&
|
1190
|
+
if( e.target && !e.target.readOnly && !e.target.disabled && inputElements[e.target.nodeName] && !noInputTypes[e.target.type] && !(webshims.data(e.target, 'implemented') || {}).inputwidgets){
|
1185
1191
|
observe($(e.target));
|
1186
1192
|
}
|
1187
1193
|
})
|
@@ -114,7 +114,7 @@ webshims.register('form-validation', function($, webshims, window, document, und
|
|
114
114
|
return;
|
115
115
|
}
|
116
116
|
if(webshims.refreshCustomValidityRules && webshims.refreshCustomValidityRules(elem) == 'async'){
|
117
|
-
$(elem).one('updatevalidation', switchValidityClass);
|
117
|
+
$(elem).one('updatevalidation.webshims', switchValidityClass);
|
118
118
|
return;
|
119
119
|
}
|
120
120
|
|
@@ -158,12 +158,12 @@ webshims.register('form-validation', function($, webshims, window, document, und
|
|
158
158
|
//jQuery 1.6.1 IE9 bug (doubble trigger bug)
|
159
159
|
setTimeout(function(){
|
160
160
|
$(elem).trigger(trigger);
|
161
|
-
}
|
161
|
+
});
|
162
162
|
}
|
163
163
|
if(generaltrigger){
|
164
164
|
setTimeout(function(){
|
165
165
|
$(elem).trigger(generaltrigger);
|
166
|
-
}
|
166
|
+
});
|
167
167
|
}
|
168
168
|
|
169
169
|
$.removeData(elem, 'webshimsswitchvalidityclass');
|
@@ -178,7 +178,7 @@ webshims.register('form-validation', function($, webshims, window, document, und
|
|
178
178
|
}
|
179
179
|
switchClass();
|
180
180
|
} else {
|
181
|
-
$.data(elem, 'webshimsswitchvalidityclass', setTimeout(switchClass
|
181
|
+
$.data(elem, 'webshimsswitchvalidityclass', setTimeout(switchClass));
|
182
182
|
}
|
183
183
|
}
|
184
184
|
};
|
@@ -147,7 +147,7 @@ var iValClasses = '.'+ options.iVal.errorClass +', .'+options.iVal.successClass;
|
|
147
147
|
/*
|
148
148
|
* adds support for HTML5 constraint validation
|
149
149
|
* - partial pattern: <input data-partial-pattern="RegExp" />
|
150
|
-
* - creditcard-validation: <input data-
|
150
|
+
* - creditcard-validation: <input data-luhn="" />
|
151
151
|
* - several dependent-validation patterns (examples):
|
152
152
|
* - <input type="email" id="mail" /> <input data-dependent-validation='mail' />
|
153
153
|
* - <input type="date" id="start" data-dependent-validation='{"from": "end", "prop": "max"}' /> <input type="date" id="end" data-dependent-validation='{"from": "start", "prop": "min"}' />
|
@@ -196,8 +196,11 @@ var iValClasses = '.'+ options.iVal.errorClass +', .'+options.iVal.successClass;
|
|
196
196
|
}, 'Please check one of these checkboxes.');
|
197
197
|
|
198
198
|
// based on https://sites.google.com/site/abapexamples/javascript/luhn-validation
|
199
|
-
addCustomValidityRule('
|
200
|
-
if(!value || (!data || !('creditcard' in data))){return;}
|
199
|
+
addCustomValidityRule('luhn', function(elem, value, data){
|
200
|
+
if(!value || (!data || (!('creditcard' in data) && !('luhn' in data)))){return;}
|
201
|
+
if(('creditcard' in data)){
|
202
|
+
webshims.error('data-creditcard was renamed to data-luhn!!!');
|
203
|
+
}
|
201
204
|
value = value.replace(/\-/g, "");
|
202
205
|
//if it's not numeric return true >- for invalid
|
203
206
|
if(value != value * 1){return true;}
|
@@ -595,15 +595,21 @@ webshims.register('forms-picker', function($, webshims, window, document, undefi
|
|
595
595
|
if(o.stepfactor){
|
596
596
|
factor *= o.stepfactor;
|
597
597
|
}
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
}
|
604
|
-
|
605
|
-
|
606
|
-
|
598
|
+
|
599
|
+
if(factor > 0 && !isNaN(that.minAsNumber) && (isNaN(that.valueAsNumber) || that.valueAsNumber < that.minAsNumber) && that.elemHelper.prop('valueAsNumber') <= that.minAsNumber){
|
600
|
+
ret = that.asValue(that.minAsNumber);
|
601
|
+
} else if(factor < 0 && !isNaN(that.maxAsNumber) && (isNaN(that.valueAsNumber) || that.valueAsNumber > that.minAsNumber) && that.elemHelper.prop('valueAsNumber') <= that.maxAsNumber){
|
602
|
+
ret = that.asValue(that.maxAsNumber);
|
603
|
+
}
|
604
|
+
|
605
|
+
if(ret === false){
|
606
|
+
try {
|
607
|
+
that.elemHelper[name](factor);
|
608
|
+
ret = that.elemHelper.prop('value');
|
609
|
+
} catch (er) {
|
610
|
+
if (!o.value && that.maxAsNumber >= that.minAsNumber) {
|
611
|
+
ret = o.defValue;
|
612
|
+
}
|
607
613
|
}
|
608
614
|
}
|
609
615
|
if (ret !== false && o.value != ret) {
|
@@ -645,10 +651,7 @@ webshims.register('forms-picker', function($, webshims, window, document, undefi
|
|
645
651
|
}
|
646
652
|
};
|
647
653
|
|
648
|
-
spinElement.
|
649
|
-
'autocomplete': 'off',
|
650
|
-
role: 'spinbutton'
|
651
|
-
}).on(spinEvents);
|
654
|
+
spinElement.on(spinEvents);
|
652
655
|
}
|
653
656
|
$(this.buttonWrapper)
|
654
657
|
.on('mousepressstart mousepressend', '.step-up, .step-down', mousePress)
|
@@ -1229,14 +1229,15 @@ webshims.register('mediaelement-jaris', function($, webshims, window, document,
|
|
1229
1229
|
|
1230
1230
|
|
1231
1231
|
if(hasNative && hasFlash && !options.preferFlash){
|
1232
|
-
var
|
1233
|
-
|
1232
|
+
var switchErrors = {
|
1233
|
+
3: 1,
|
1234
|
+
4: 1
|
1234
1235
|
};
|
1235
1236
|
var switchOptions = function(e){
|
1236
1237
|
var media, error, parent;
|
1237
1238
|
if(!options.preferFlash &&
|
1238
1239
|
($(e.target).is('audio, video') || ((parent = e.target.parentNode) && $('source', parent).last()[0] == e.target)) &&
|
1239
|
-
(media = $(e.target).closest('audio, video')) && (error = media.prop('error')) &&
|
1240
|
+
(media = $(e.target).closest('audio, video')) && (error = media.prop('error')) && switchErrors[error.code]
|
1240
1241
|
){
|
1241
1242
|
|
1242
1243
|
if(!options.preferFlash){
|
@@ -1257,7 +1258,7 @@ webshims.register('mediaelement-jaris', function($, webshims, window, document,
|
|
1257
1258
|
document.addEventListener('error', switchOptions, true);
|
1258
1259
|
$('audio, video').each(function(){
|
1259
1260
|
var error = $.prop(this, 'error');
|
1260
|
-
if(error &&
|
1261
|
+
if(error && switchErrors[error]){
|
1261
1262
|
switchOptions({target: this});
|
1262
1263
|
return false;
|
1263
1264
|
}
|
@@ -0,0 +1,570 @@
|
|
1
|
+
(function(){
|
2
|
+
"use strict";
|
3
|
+
try {
|
4
|
+
new Image();
|
5
|
+
} catch(e){
|
6
|
+
window.Image = function(){
|
7
|
+
return document.createElement('img');
|
8
|
+
};
|
9
|
+
}
|
10
|
+
setTimeout(function(){
|
11
|
+
var sel = 'picture, img[srcset]';
|
12
|
+
webshims.addReady(function(context, insertedElement){
|
13
|
+
if(context == document || !window.picturefill){return;}
|
14
|
+
if(context.querySelector(sel) || insertedElement.filter(sel).length){
|
15
|
+
window.picturefill();
|
16
|
+
}
|
17
|
+
});
|
18
|
+
});
|
19
|
+
})();
|
20
|
+
|
21
|
+
/*! Picturefill - v2.0.0-beta - 2014-05-02
|
22
|
+
* http://scottjehl.github.io/picturefill
|
23
|
+
* Copyright (c) 2014 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT */
|
24
|
+
/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas, David Knight. Dual MIT/BSD license */
|
25
|
+
|
26
|
+
window.matchMedia || (window.matchMedia = function() {
|
27
|
+
"use strict";
|
28
|
+
|
29
|
+
// For browsers that support matchMedium api such as IE 9 and webkit
|
30
|
+
var styleMedia = (window.styleMedia || window.media);
|
31
|
+
|
32
|
+
// For those that don't support matchMedium
|
33
|
+
if (!styleMedia) {
|
34
|
+
var style = document.createElement('style'),
|
35
|
+
script = document.getElementsByTagName('script')[0],
|
36
|
+
info = null;
|
37
|
+
|
38
|
+
style.type = 'text/css';
|
39
|
+
style.id = 'matchmediajs-test';
|
40
|
+
|
41
|
+
script.parentNode.insertBefore(style, script);
|
42
|
+
|
43
|
+
// 'style.currentStyle' is used by IE <= 8 and 'window.getComputedStyle' for all other browsers
|
44
|
+
info = ('getComputedStyle' in window) && window.getComputedStyle(style, null) || style.currentStyle;
|
45
|
+
|
46
|
+
styleMedia = {
|
47
|
+
matchMedium: function(media) {
|
48
|
+
var text = '@media ' + media + '{ #matchmediajs-test { width: 1px; } }';
|
49
|
+
|
50
|
+
// 'style.styleSheet' is used by IE <= 8 and 'style.textContent' for all other browsers
|
51
|
+
if (style.styleSheet) {
|
52
|
+
style.styleSheet.cssText = text;
|
53
|
+
} else {
|
54
|
+
style.textContent = text;
|
55
|
+
}
|
56
|
+
|
57
|
+
// Test if media query is true or false
|
58
|
+
return info.width === '1px';
|
59
|
+
}
|
60
|
+
};
|
61
|
+
}
|
62
|
+
|
63
|
+
return function(media) {
|
64
|
+
return {
|
65
|
+
matches: styleMedia.matchMedium(media || 'all'),
|
66
|
+
media: media || 'all'
|
67
|
+
};
|
68
|
+
};
|
69
|
+
}());
|
70
|
+
/*! Picturefill - Responsive Images that work today.
|
71
|
+
* Author: Scott Jehl, Filament Group, 2012 ( new proposal implemented by Shawn Jansepar )
|
72
|
+
* License: MIT/GPLv2
|
73
|
+
* Spec: http://picture.responsiveimages.org/
|
74
|
+
*/
|
75
|
+
(function( w, doc ) {
|
76
|
+
// Enable strict mode
|
77
|
+
"use strict";
|
78
|
+
|
79
|
+
// If picture is supported, well, that's awesome. Let's get outta here...
|
80
|
+
if( w.HTMLPictureElement ){
|
81
|
+
return;
|
82
|
+
}
|
83
|
+
|
84
|
+
// HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround)
|
85
|
+
doc.createElement( "picture" );
|
86
|
+
|
87
|
+
// local object for method references and testing exposure
|
88
|
+
var pf = {};
|
89
|
+
|
90
|
+
// namespace
|
91
|
+
pf.ns = "picturefill";
|
92
|
+
|
93
|
+
// srcset support test
|
94
|
+
pf.srcsetSupported = new w.Image().srcset !== undefined;
|
95
|
+
|
96
|
+
// just a string trim workaround
|
97
|
+
pf.trim = function( str ){
|
98
|
+
return str.trim ? str.trim() : str.replace( /^\s+|\s+$/g, "" );
|
99
|
+
};
|
100
|
+
|
101
|
+
// just a string endsWith workaround
|
102
|
+
pf.endsWith = function( str, suffix ){
|
103
|
+
return str.endsWith ? str.endsWith( suffix ) : str.indexOf( suffix, str.length - suffix.length ) !== -1;
|
104
|
+
};
|
105
|
+
|
106
|
+
/**
|
107
|
+
* Shortcut method for matchMedia ( for easy overriding in tests )
|
108
|
+
*/
|
109
|
+
pf.matchesMedia = function( media ) {
|
110
|
+
return w.matchMedia && w.matchMedia( media ).matches;
|
111
|
+
};
|
112
|
+
|
113
|
+
/**
|
114
|
+
* Shortcut method for `devicePixelRatio` ( for easy overriding in tests )
|
115
|
+
*/
|
116
|
+
pf.getDpr = function() {
|
117
|
+
return ( w.devicePixelRatio || 1 );
|
118
|
+
};
|
119
|
+
|
120
|
+
/**
|
121
|
+
* Get width in css pixel value from a "length" value
|
122
|
+
* http://dev.w3.org/csswg/css-values-3/#length-value
|
123
|
+
*/
|
124
|
+
pf.getWidthFromLength = function( length ) {
|
125
|
+
// If no length was specified, or it is 0, default to `100vw` (per the spec).
|
126
|
+
length = length && parseFloat( length ) > 0 ? length : "100vw";
|
127
|
+
|
128
|
+
/**
|
129
|
+
* If length is specified in `vw` units, use `%` instead since the div we’re measuring
|
130
|
+
* is injected at the top of the document.
|
131
|
+
*
|
132
|
+
* TODO: maybe we should put this behind a feature test for `vw`?
|
133
|
+
*/
|
134
|
+
length = length.replace( "vw", "%" );
|
135
|
+
|
136
|
+
// Create a cached element for getting length value widths
|
137
|
+
if( !pf.lengthEl ){
|
138
|
+
pf.lengthEl = doc.createElement( "div" );
|
139
|
+
doc.documentElement.insertBefore( pf.lengthEl, doc.documentElement.firstChild );
|
140
|
+
}
|
141
|
+
|
142
|
+
// Positioning styles help prevent padding/margin/width on `html` from throwing calculations off.
|
143
|
+
pf.lengthEl.style.cssText = "position: absolute; left: 0; width: " + length + ";";
|
144
|
+
// Using offsetWidth to get width from CSS
|
145
|
+
return pf.lengthEl.offsetWidth;
|
146
|
+
};
|
147
|
+
|
148
|
+
// container of supported mime types that one might need to qualify before using
|
149
|
+
pf.types = {};
|
150
|
+
|
151
|
+
// test svg support
|
152
|
+
pf.types[ "image/svg+xml" ] = doc.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1');
|
153
|
+
|
154
|
+
// test webp support, only when the markup calls for it
|
155
|
+
pf.types[ "image/webp" ] = function(){
|
156
|
+
// based on Modernizr's lossless img-webp test
|
157
|
+
// note: asynchronous
|
158
|
+
var img = new w.Image(),
|
159
|
+
type = "image/webp";
|
160
|
+
|
161
|
+
img.onerror = function(){
|
162
|
+
pf.types[ type ] = false;
|
163
|
+
picturefill();
|
164
|
+
};
|
165
|
+
img.onload = function(){
|
166
|
+
pf.types[ type ] = img.width === 1;
|
167
|
+
picturefill();
|
168
|
+
};
|
169
|
+
img.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
|
170
|
+
};
|
171
|
+
|
172
|
+
/**
|
173
|
+
* Takes a source element and checks if its type attribute is present and if so, supported
|
174
|
+
* Note: for type tests that require a async logic,
|
175
|
+
* you can define them as a function that'll run only if that type needs to be tested. Just make the test function call picturefill again when it is complete.
|
176
|
+
* see the async webp test above for example
|
177
|
+
*/
|
178
|
+
pf.verifyTypeSupport = function( source ){
|
179
|
+
var type = source.getAttribute( "type" );
|
180
|
+
// if type attribute exists, return test result, otherwise return true
|
181
|
+
if( type === null || type === "" ){
|
182
|
+
return true;
|
183
|
+
}
|
184
|
+
else {
|
185
|
+
// if the type test is a function, run it and return "pending" status. The function will rerun picturefill on pending elements once finished.
|
186
|
+
if( typeof( pf.types[ type ] ) === "function" ){
|
187
|
+
pf.types[ type ]();
|
188
|
+
return "pending";
|
189
|
+
}
|
190
|
+
else {
|
191
|
+
return pf.types[ type ];
|
192
|
+
}
|
193
|
+
}
|
194
|
+
};
|
195
|
+
|
196
|
+
/**
|
197
|
+
* Parses an individual `size` and returns the length, and optional media query
|
198
|
+
*/
|
199
|
+
pf.parseSize = function( sourceSizeStr ) {
|
200
|
+
var match = /(\([^)]+\))?\s*(.+)/g.exec( sourceSizeStr );
|
201
|
+
return {
|
202
|
+
media: match && match[1],
|
203
|
+
length: match && match[2]
|
204
|
+
};
|
205
|
+
};
|
206
|
+
|
207
|
+
/**
|
208
|
+
* Takes a string of sizes and returns the width in pixels as a number
|
209
|
+
*/
|
210
|
+
pf.findWidthFromSourceSize = function( sourceSizeListStr ) {
|
211
|
+
// Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33%
|
212
|
+
// or (min-width:30em) calc(30% - 15px)
|
213
|
+
var sourceSizeList = pf.trim( sourceSizeListStr ).split( /\s*,\s*/ ),
|
214
|
+
winningLength;
|
215
|
+
|
216
|
+
for ( var i=0, len=sourceSizeList.length; i < len; i++ ) {
|
217
|
+
// Match <media-condition>? length, ie ( min-width: 50em ) 100%
|
218
|
+
var sourceSize = sourceSizeList[ i ],
|
219
|
+
// Split "( min-width: 50em ) 100%" into separate strings
|
220
|
+
parsedSize = pf.parseSize( sourceSize ),
|
221
|
+
length = parsedSize.length,
|
222
|
+
media = parsedSize.media;
|
223
|
+
|
224
|
+
if ( !length ) {
|
225
|
+
continue;
|
226
|
+
}
|
227
|
+
if ( !media || pf.matchesMedia( media ) ) {
|
228
|
+
// if there is no media query or it matches, choose this as our winning length
|
229
|
+
// and end algorithm
|
230
|
+
winningLength = length;
|
231
|
+
break;
|
232
|
+
}
|
233
|
+
}
|
234
|
+
|
235
|
+
// pass the length to a method that can properly determine length
|
236
|
+
// in pixels based on these formats: http://dev.w3.org/csswg/css-values-3/#length-value
|
237
|
+
return pf.getWidthFromLength( winningLength );
|
238
|
+
};
|
239
|
+
|
240
|
+
/**
|
241
|
+
* Takes a srcset in the form of url/
|
242
|
+
* ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or
|
243
|
+
* "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or
|
244
|
+
* "images/pic-small.png"
|
245
|
+
* Get an array of image candidates in the form of
|
246
|
+
* {url: "/foo/bar.png", resolution: 1}
|
247
|
+
* where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value
|
248
|
+
* If sizes is specified, resolution is calculated
|
249
|
+
*/
|
250
|
+
pf.getCandidatesFromSourceSet = function( srcset, sizes ) {
|
251
|
+
var candidates = pf.trim( srcset ).split( /,\s+/ ),
|
252
|
+
widthInCssPixels = sizes ? pf.findWidthFromSourceSize( sizes ) : "100%",
|
253
|
+
formattedCandidates = [];
|
254
|
+
|
255
|
+
for ( var i = 0, len = candidates.length; i < len; i++ ) {
|
256
|
+
var candidate = candidates[ i ],
|
257
|
+
candidateArr = candidate.split( /\s+/ ),
|
258
|
+
sizeDescriptor = candidateArr[ 1 ],
|
259
|
+
resolution;
|
260
|
+
if ( sizeDescriptor && ( sizeDescriptor.slice( -1 ) === "w" || sizeDescriptor.slice( -1 ) === "x" ) ) {
|
261
|
+
sizeDescriptor = sizeDescriptor.slice( 0, -1 );
|
262
|
+
}
|
263
|
+
if ( sizes ) {
|
264
|
+
// get the dpr by taking the length / width in css pixels
|
265
|
+
resolution = parseFloat( ( parseInt( sizeDescriptor, 10 ) / widthInCssPixels ) );
|
266
|
+
} else {
|
267
|
+
// get the dpr by grabbing the value of Nx
|
268
|
+
resolution = sizeDescriptor ? parseFloat( sizeDescriptor, 10 ) : 1;
|
269
|
+
}
|
270
|
+
|
271
|
+
var formattedCandidate = {
|
272
|
+
url: candidateArr[ 0 ],
|
273
|
+
resolution: resolution
|
274
|
+
};
|
275
|
+
formattedCandidates.push( formattedCandidate );
|
276
|
+
}
|
277
|
+
return formattedCandidates;
|
278
|
+
};
|
279
|
+
|
280
|
+
/*
|
281
|
+
* if it's an img element and it has a srcset property,
|
282
|
+
* we need to remove the attribute so we can manipulate src
|
283
|
+
* (the property's existence infers native srcset support, and a srcset-supporting browser will prioritize srcset's value over our winning picture candidate)
|
284
|
+
* this moves srcset's value to memory for later use and removes the attr
|
285
|
+
*/
|
286
|
+
pf.dodgeSrcset = function( img ){
|
287
|
+
if( img.srcset ){
|
288
|
+
img[ pf.ns ].srcset = img.srcset;
|
289
|
+
img.removeAttribute( "srcset" );
|
290
|
+
}
|
291
|
+
};
|
292
|
+
|
293
|
+
/*
|
294
|
+
* Accept a source or img element and process its srcset and sizes attrs
|
295
|
+
*/
|
296
|
+
pf.processSourceSet = function( el ) {
|
297
|
+
var srcset = el.getAttribute( "srcset" ),
|
298
|
+
sizes = el.getAttribute( "sizes" ),
|
299
|
+
candidates = [];
|
300
|
+
|
301
|
+
// if it's an img element, use the cached srcset property (defined or not)
|
302
|
+
if( el.nodeName.toUpperCase() === "IMG" && el[ pf.ns ] && el[ pf.ns ].srcset ){
|
303
|
+
srcset = el[ pf.ns ].srcset;
|
304
|
+
}
|
305
|
+
|
306
|
+
if( srcset ) {
|
307
|
+
candidates = pf.getCandidatesFromSourceSet( srcset, sizes );
|
308
|
+
}
|
309
|
+
return candidates;
|
310
|
+
};
|
311
|
+
|
312
|
+
pf.applyBestCandidate = function( candidates, picImg ) {
|
313
|
+
var candidate,
|
314
|
+
length,
|
315
|
+
bestCandidate;
|
316
|
+
|
317
|
+
candidates.sort( pf.ascendingSort );
|
318
|
+
|
319
|
+
length = candidates.length;
|
320
|
+
bestCandidate = candidates[ length - 1 ];
|
321
|
+
|
322
|
+
for ( var l=0; l < length; l++ ) {
|
323
|
+
candidate = candidates[ l ];
|
324
|
+
if ( candidate.resolution >= pf.getDpr() ) {
|
325
|
+
bestCandidate = candidate;
|
326
|
+
break;
|
327
|
+
}
|
328
|
+
}
|
329
|
+
|
330
|
+
if ( !pf.endsWith( picImg.src, bestCandidate.url ) ) {
|
331
|
+
picImg.src = bestCandidate.url;
|
332
|
+
// currentSrc attribute and property to match
|
333
|
+
// http://picture.responsiveimages.org/#the-img-element
|
334
|
+
picImg.currentSrc = picImg.src;
|
335
|
+
}
|
336
|
+
};
|
337
|
+
|
338
|
+
pf.ascendingSort = function( a, b ) {
|
339
|
+
return a.resolution - b.resolution;
|
340
|
+
};
|
341
|
+
|
342
|
+
/*
|
343
|
+
* In IE9, <source> elements get removed if they aren"t children of
|
344
|
+
* video elements. Thus, we conditionally wrap source elements
|
345
|
+
* using <!--[if IE 9]><video style="display: none;"><![endif]-->
|
346
|
+
* and must account for that here by moving those source elements
|
347
|
+
* back into the picture element.
|
348
|
+
*/
|
349
|
+
pf.removeVideoShim = function( picture ){
|
350
|
+
var videos = picture.getElementsByTagName( "video" );
|
351
|
+
if ( videos.length ) {
|
352
|
+
var video = videos[ 0 ],
|
353
|
+
vsources = video.getElementsByTagName( "source" );
|
354
|
+
while ( vsources.length ) {
|
355
|
+
picture.insertBefore( vsources[ 0 ], video );
|
356
|
+
}
|
357
|
+
// Remove the video element once we're finished removing its children
|
358
|
+
video.parentNode.removeChild( video );
|
359
|
+
}
|
360
|
+
};
|
361
|
+
|
362
|
+
/*
|
363
|
+
* Find all picture elements and,
|
364
|
+
* in browsers that don't natively support srcset, find all img elements
|
365
|
+
* with srcset attrs that don't have picture parents
|
366
|
+
*/
|
367
|
+
pf.getAllElements = function() {
|
368
|
+
var pictures = doc.getElementsByTagName( "picture" ),
|
369
|
+
elems = [],
|
370
|
+
imgs = doc.getElementsByTagName( "img" );
|
371
|
+
|
372
|
+
for ( var h = 0, len = pictures.length + imgs.length; h < len; h++ ) {
|
373
|
+
if ( h < pictures.length ){
|
374
|
+
elems[ h ] = pictures[ h ];
|
375
|
+
}
|
376
|
+
else {
|
377
|
+
var currImg = imgs[ h - pictures.length ];
|
378
|
+
|
379
|
+
if ( currImg.parentNode.nodeName.toUpperCase() !== "PICTURE" &&
|
380
|
+
( ( pf.srcsetSupported && currImg.getAttribute( "sizes" ) ) ||
|
381
|
+
currImg.getAttribute( "srcset" ) !== null ) ) {
|
382
|
+
elems.push( currImg );
|
383
|
+
}
|
384
|
+
}
|
385
|
+
}
|
386
|
+
return elems;
|
387
|
+
};
|
388
|
+
|
389
|
+
pf.getMatch = function( picture ) {
|
390
|
+
var sources = picture.childNodes,
|
391
|
+
match;
|
392
|
+
|
393
|
+
// Go through each child, and if they have media queries, evaluate them
|
394
|
+
for ( var j=0, slen = sources.length; j < slen; j++ ) {
|
395
|
+
var source = sources[ j ];
|
396
|
+
|
397
|
+
// ignore non-element nodes
|
398
|
+
if( source.nodeType !== 1 ){
|
399
|
+
continue;
|
400
|
+
}
|
401
|
+
|
402
|
+
// Hitting an `img` element stops the search for `sources`.
|
403
|
+
// If no previous `source` matches, the `img` itself is evaluated later.
|
404
|
+
if( source.nodeName.toUpperCase() === "IMG" ) {
|
405
|
+
return match;
|
406
|
+
}
|
407
|
+
|
408
|
+
// ignore non-`source` nodes
|
409
|
+
if( source.nodeName.toUpperCase() !== "SOURCE" ){
|
410
|
+
continue;
|
411
|
+
}
|
412
|
+
|
413
|
+
var media = source.getAttribute( "media" );
|
414
|
+
|
415
|
+
// if source does not have a srcset attribute, skip
|
416
|
+
if ( !source.getAttribute( "srcset" ) ) {
|
417
|
+
continue;
|
418
|
+
}
|
419
|
+
|
420
|
+
// if there"s no media specified, OR w.matchMedia is supported
|
421
|
+
if( ( !media || pf.matchesMedia( media ) ) ){
|
422
|
+
var typeSupported = pf.verifyTypeSupport( source );
|
423
|
+
|
424
|
+
if( typeSupported === true ){
|
425
|
+
match = source;
|
426
|
+
break;
|
427
|
+
} else if( typeSupported === "pending" ){
|
428
|
+
return false;
|
429
|
+
}
|
430
|
+
}
|
431
|
+
}
|
432
|
+
|
433
|
+
return match;
|
434
|
+
};
|
435
|
+
|
436
|
+
function picturefill( options ) {
|
437
|
+
var elements,
|
438
|
+
element,
|
439
|
+
elemType,
|
440
|
+
firstMatch,
|
441
|
+
candidates,
|
442
|
+
picImg;
|
443
|
+
|
444
|
+
options = options || {};
|
445
|
+
elements = options.elements || pf.getAllElements();
|
446
|
+
|
447
|
+
// Loop through all elements
|
448
|
+
for ( var i=0, plen = elements.length; i < plen; i++ ) {
|
449
|
+
element = elements[ i ];
|
450
|
+
elemType = element.nodeName.toUpperCase();
|
451
|
+
firstMatch = undefined;
|
452
|
+
candidates = undefined;
|
453
|
+
picImg = undefined;
|
454
|
+
|
455
|
+
// expando for caching data on the img
|
456
|
+
if( !element[ pf.ns ] ){
|
457
|
+
element[ pf.ns ] = {};
|
458
|
+
}
|
459
|
+
|
460
|
+
// if the element has already been evaluated, skip it
|
461
|
+
// unless `options.force` is set to true ( this, for example,
|
462
|
+
// is set to true when running `picturefill` on `resize` ).
|
463
|
+
if ( !options.reevaluate && element[ pf.ns ].evaluated ) {
|
464
|
+
continue;
|
465
|
+
}
|
466
|
+
|
467
|
+
// if element is a picture element
|
468
|
+
if( elemType === "PICTURE" ){
|
469
|
+
|
470
|
+
// IE9 video workaround
|
471
|
+
pf.removeVideoShim( element );
|
472
|
+
|
473
|
+
// return the first match which might undefined
|
474
|
+
// returns false if there is a pending source
|
475
|
+
// TODO the return type here is brutal, cleanup
|
476
|
+
firstMatch = pf.getMatch( element );
|
477
|
+
|
478
|
+
// if any sources are pending in this picture due to async type test(s)
|
479
|
+
// remove the evaluated attr and skip for now ( the pending test will
|
480
|
+
// rerun picturefill on this element when complete)
|
481
|
+
if( firstMatch === false ) {
|
482
|
+
continue;
|
483
|
+
}
|
484
|
+
|
485
|
+
// Find any existing img element in the picture element
|
486
|
+
picImg = element.getElementsByTagName( "img" )[ 0 ];
|
487
|
+
} else {
|
488
|
+
// if it's an img element
|
489
|
+
firstMatch = undefined;
|
490
|
+
picImg = element;
|
491
|
+
}
|
492
|
+
|
493
|
+
if( picImg ) {
|
494
|
+
|
495
|
+
// expando for caching data on the img
|
496
|
+
if( !picImg[ pf.ns ] ){
|
497
|
+
picImg[ pf.ns ] = {};
|
498
|
+
}
|
499
|
+
|
500
|
+
// Cache and remove `srcset` if present and we’re going to be doing `sizes`/`picture` polyfilling to it.
|
501
|
+
if( picImg.srcset && ( elemType === "PICTURE" || picImg.getAttribute( "sizes" ) ) ){
|
502
|
+
pf.dodgeSrcset( picImg );
|
503
|
+
}
|
504
|
+
|
505
|
+
if ( firstMatch ) {
|
506
|
+
candidates = pf.processSourceSet( firstMatch );
|
507
|
+
pf.applyBestCandidate( candidates, picImg );
|
508
|
+
} else {
|
509
|
+
// No sources matched, so we’re down to processing the inner `img` as a source.
|
510
|
+
candidates = pf.processSourceSet( picImg );
|
511
|
+
|
512
|
+
if( picImg.srcset === undefined || picImg.getAttribute( "sizes" ) ) {
|
513
|
+
// Either `srcset` is completely unsupported, or we need to polyfill `sizes` functionality.
|
514
|
+
pf.applyBestCandidate( candidates, picImg );
|
515
|
+
} // Else, resolution-only `srcset` is supported natively.
|
516
|
+
}
|
517
|
+
|
518
|
+
// set evaluated to true to avoid unnecessary reparsing
|
519
|
+
element[ pf.ns ].evaluated = true;
|
520
|
+
}
|
521
|
+
}
|
522
|
+
}
|
523
|
+
|
524
|
+
/**
|
525
|
+
* Sets up picture polyfill by polling the document and running
|
526
|
+
* the polyfill every 250ms until the document is ready.
|
527
|
+
* Also attaches picturefill on resize
|
528
|
+
*/
|
529
|
+
function runPicturefill() {
|
530
|
+
picturefill();
|
531
|
+
var intervalId = setInterval( function(){
|
532
|
+
// When the document has finished loading, stop checking for new images
|
533
|
+
// https://github.com/ded/domready/blob/master/ready.js#L15
|
534
|
+
w.picturefill();
|
535
|
+
if ( /^loaded|^i|^c/.test( doc.readyState ) ) {
|
536
|
+
clearInterval( intervalId );
|
537
|
+
return;
|
538
|
+
}
|
539
|
+
}, 250 );
|
540
|
+
if( w.addEventListener ){
|
541
|
+
var resizeThrottle;
|
542
|
+
w.addEventListener( "resize", function() {
|
543
|
+
w.clearTimeout( resizeThrottle );
|
544
|
+
resizeThrottle = w.setTimeout( function(){
|
545
|
+
picturefill({ reevaluate: true });
|
546
|
+
}, 60 );
|
547
|
+
}, false );
|
548
|
+
}
|
549
|
+
}
|
550
|
+
|
551
|
+
runPicturefill();
|
552
|
+
|
553
|
+
/* expose methods for testing */
|
554
|
+
picturefill._ = pf;
|
555
|
+
|
556
|
+
/* expose picturefill */
|
557
|
+
if ( typeof module === "object" && typeof module.exports === "object" ){
|
558
|
+
// CommonJS, just export
|
559
|
+
module.exports = picturefill;
|
560
|
+
}
|
561
|
+
else if( typeof define === "object" && define.amd ){
|
562
|
+
// AMD support
|
563
|
+
define( function(){ return picturefill; } );
|
564
|
+
}
|
565
|
+
else if( typeof w === "object" ){
|
566
|
+
// If no AMD and we are in the browser, attach to window
|
567
|
+
w.picturefill = picturefill;
|
568
|
+
}
|
569
|
+
|
570
|
+
} )( this, this.document );
|