webshims-rails 1.12.7 → 1.13.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 +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 );
|