jumbo-jekyll-theme-test 1.0.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/LICENSE.txt +21 -0
- data/README.md +26 -0
- data/_config.yml +122 -0
- data/_data/authors.yml +7 -0
- data/_data/footer.yml +55 -0
- data/_data/nav.yml +77 -0
- data/_data/news.yaml +230 -0
- data/_data/settings.yml +148 -0
- data/_data/sidebar-nav.yml +23 -0
- data/_data/sticky-tab-bar.yml +29 -0
- data/_includes/breadcrumb.html +97 -0
- data/_includes/css.html +9 -0
- data/_includes/custom.html +1 -0
- data/_includes/display-blog-posts.html +67 -0
- data/_includes/disqus-comments.html +14 -0
- data/_includes/footer.html +70 -0
- data/_includes/github-edit.html +73 -0
- data/_includes/google-analytics-script.html +9 -0
- data/_includes/gtm-noscript.html +5 -0
- data/_includes/gtm-script.html +7 -0
- data/_includes/head.html +44 -0
- data/_includes/hero-banner.html +21 -0
- data/_includes/image.html +6 -0
- data/_includes/javascript.html +9 -0
- data/_includes/jumbotron.html +87 -0
- data/_includes/linaro-404.html +13 -0
- data/_includes/linaro-svg.html +1 -0
- data/_includes/media.html +11 -0
- data/_includes/members.html +63 -0
- data/_includes/nav.html +132 -0
- data/_includes/newsletter-script.html +30 -0
- data/_includes/owl-carousel-homepage.html +103 -0
- data/_includes/pagination-authors.html +36 -0
- data/_includes/pagination-news.html +36 -0
- data/_includes/pagination.html +36 -0
- data/_includes/post-comments.html +9 -0
- data/_includes/post-sidebar.html +74 -0
- data/_includes/post-tags.html +9 -0
- data/_includes/schema.html +50 -0
- data/_includes/shape-divider.html +12 -0
- data/_includes/shape.html +52 -0
- data/_includes/sidebar.html +55 -0
- data/_includes/sticky-tab-bar.html +63 -0
- data/_includes/universal-nav.html +28 -0
- data/_includes/youtube.html +7 -0
- data/_layouts/container-breadcrumb-left-sidebar.html +10 -0
- data/_layouts/container-breadcrumb-right-sidebar.html +9 -0
- data/_layouts/container-breadcrumb-tabs.html +7 -0
- data/_layouts/container-breadcrumb.html +6 -0
- data/_layouts/container-left-sidebar.html +9 -0
- data/_layouts/container-right-sidebar.html +9 -0
- data/_layouts/container.html +9 -0
- data/_layouts/default.html +31 -0
- data/_layouts/full-width-breadcrumb.html +10 -0
- data/_layouts/full-width.html +9 -0
- data/_layouts/home.html +21 -0
- data/_layouts/post-index.html +19 -0
- data/_layouts/post-no-sidebar.html +0 -0
- data/_layouts/post-old.html +70 -0
- data/_layouts/post.html +240 -0
- data/_sass/_bootstrap-compass.scss +9 -0
- data/_sass/_bootstrap-mincer.scss +19 -0
- data/_sass/_bootstrap-sprockets.scss +9 -0
- data/_sass/_bootstrap.scss +56 -0
- data/_sass/app/blog.scss +58 -0
- data/_sass/app/contact.scss +3 -0
- data/_sass/app/custom.scss +1 -0
- data/_sass/app/home.scss +18 -0
- data/_sass/app/overrides.scss +36 -0
- data/_sass/app/search.scss +1 -0
- data/_sass/blog.scss +9 -0
- data/_sass/bootstrap/_alerts.scss +73 -0
- data/_sass/bootstrap/_badges.scss +68 -0
- data/_sass/bootstrap/_breadcrumbs.scss +28 -0
- data/_sass/bootstrap/_button-groups.scss +244 -0
- data/_sass/bootstrap/_buttons.scss +168 -0
- data/_sass/bootstrap/_carousel.scss +270 -0
- data/_sass/bootstrap/_close.scss +36 -0
- data/_sass/bootstrap/_code.scss +69 -0
- data/_sass/bootstrap/_component-animations.scss +37 -0
- data/_sass/bootstrap/_dropdowns.scss +216 -0
- data/_sass/bootstrap/_forms.scss +617 -0
- data/_sass/bootstrap/_glyphicons.scss +307 -0
- data/_sass/bootstrap/_grid.scss +84 -0
- data/_sass/bootstrap/_input-groups.scss +171 -0
- data/_sass/bootstrap/_jumbotron.scss +54 -0
- data/_sass/bootstrap/_labels.scss +66 -0
- data/_sass/bootstrap/_list-group.scss +130 -0
- data/_sass/bootstrap/_media.scss +66 -0
- data/_sass/bootstrap/_mixins.scss +40 -0
- data/_sass/bootstrap/_modals.scss +150 -0
- data/_sass/bootstrap/_navbar.scss +662 -0
- data/_sass/bootstrap/_navs.scss +242 -0
- data/_sass/bootstrap/_normalize.scss +424 -0
- data/_sass/bootstrap/_pager.scss +54 -0
- data/_sass/bootstrap/_pagination.scss +89 -0
- data/_sass/bootstrap/_panels.scss +271 -0
- data/_sass/bootstrap/_popovers.scss +131 -0
- data/_sass/bootstrap/_print.scss +101 -0
- data/_sass/bootstrap/_progress-bars.scss +87 -0
- data/_sass/bootstrap/_responsive-embed.scss +35 -0
- data/_sass/bootstrap/_responsive-utilities.scss +179 -0
- data/_sass/bootstrap/_scaffolding.scss +161 -0
- data/_sass/bootstrap/_tables.scss +234 -0
- data/_sass/bootstrap/_theme.scss +291 -0
- data/_sass/bootstrap/_thumbnails.scss +38 -0
- data/_sass/bootstrap/_tooltip.scss +101 -0
- data/_sass/bootstrap/_type.scss +298 -0
- data/_sass/bootstrap/_utilities.scss +55 -0
- data/_sass/bootstrap/_variables.scss +922 -0
- data/_sass/bootstrap/_wells.scss +29 -0
- data/_sass/bootstrap/mixins/_alerts.scss +14 -0
- data/_sass/bootstrap/mixins/_background-variant.scss +12 -0
- data/_sass/bootstrap/mixins/_border-radius.scss +18 -0
- data/_sass/bootstrap/mixins/_buttons.scss +65 -0
- data/_sass/bootstrap/mixins/_center-block.scss +7 -0
- data/_sass/bootstrap/mixins/_clearfix.scss +22 -0
- data/_sass/bootstrap/mixins/_forms.scss +88 -0
- data/_sass/bootstrap/mixins/_gradients.scss +58 -0
- data/_sass/bootstrap/mixins/_grid-framework.scss +81 -0
- data/_sass/bootstrap/mixins/_grid.scss +122 -0
- data/_sass/bootstrap/mixins/_hide-text.scss +21 -0
- data/_sass/bootstrap/mixins/_image.scss +33 -0
- data/_sass/bootstrap/mixins/_labels.scss +12 -0
- data/_sass/bootstrap/mixins/_list-group.scss +32 -0
- data/_sass/bootstrap/mixins/_nav-divider.scss +10 -0
- data/_sass/bootstrap/mixins/_nav-vertical-align.scss +9 -0
- data/_sass/bootstrap/mixins/_opacity.scss +8 -0
- data/_sass/bootstrap/mixins/_pagination.scss +24 -0
- data/_sass/bootstrap/mixins/_panels.scss +24 -0
- data/_sass/bootstrap/mixins/_progress-bar.scss +10 -0
- data/_sass/bootstrap/mixins/_reset-filter.scss +8 -0
- data/_sass/bootstrap/mixins/_reset-text.scss +18 -0
- data/_sass/bootstrap/mixins/_resize.scss +6 -0
- data/_sass/bootstrap/mixins/_responsive-visibility.scss +21 -0
- data/_sass/bootstrap/mixins/_size.scss +10 -0
- data/_sass/bootstrap/mixins/_tab-focus.scss +9 -0
- data/_sass/bootstrap/mixins/_table-row.scss +28 -0
- data/_sass/bootstrap/mixins/_text-emphasis.scss +12 -0
- data/_sass/bootstrap/mixins/_text-overflow.scss +8 -0
- data/_sass/bootstrap/mixins/_vendor-prefixes.scss +222 -0
- data/_sass/core.scss +12 -0
- data/_sass/core/404.scss +189 -0
- data/_sass/core/animations.scss +125 -0
- data/_sass/core/blog.scss +441 -0
- data/_sass/core/breadcrumb.scss +97 -0
- data/_sass/core/carousel-styles.scss +3 -0
- data/_sass/core/carousel.scss +318 -0
- data/_sass/core/cookieconsent.scss +42 -0
- data/_sass/core/critical.scss +0 -0
- data/_sass/core/custom.scss +3 -0
- data/_sass/core/fa.scss +2336 -0
- data/_sass/core/flipclock.scss +434 -0
- data/_sass/core/font-awesome.min.scss +4 -0
- data/_sass/core/fonts.scss +3 -0
- data/_sass/core/footer.scss +169 -0
- data/_sass/core/forms.scss +3 -0
- data/_sass/core/homepage.scss +106 -0
- data/_sass/core/jumbotron.scss +51 -0
- data/_sass/core/lightbox.scss +212 -0
- data/_sass/core/nav.scss +971 -0
- data/_sass/core/owl.carousel.min.scss +6 -0
- data/_sass/core/owl.theme.default.min.scss +6 -0
- data/_sass/core/social-media-icons.scss +67 -0
- data/_sass/core/syntax.scss +65 -0
- data/_sass/core/tables.scss +145 -0
- data/_sass/core/theme.scss +630 -0
- data/_sass/core/twitter-feed.scss +414 -0
- data/_sass/core/universal-nav.scss +154 -0
- data/_sass/core/youtube.scss +65 -0
- data/_sass/home.scss +6 -0
- data/assets/css/main-404.scss +18 -0
- data/assets/css/main-blog.scss +19 -0
- data/assets/css/main-contact.scss +23 -0
- data/assets/css/main-home.scss +22 -0
- data/assets/css/main-lightbox.scss +29 -0
- data/assets/css/main-search.scss +13 -0
- data/assets/css/main.scss +12 -0
- data/assets/fonts/fontawesome-webfont.eot +0 -0
- data/assets/fonts/fontawesome-webfont.svg +2671 -0
- data/assets/fonts/fontawesome-webfont.ttf +0 -0
- data/assets/fonts/fontawesome-webfont.woff +0 -0
- data/assets/fonts/fontawesome-webfont.woff2 +0 -0
- data/assets/fonts/fontello.eot +0 -0
- data/assets/fonts/fontello.svg +44 -0
- data/assets/fonts/glyphicons-halflings-regular.ttf +0 -0
- data/assets/fonts/glyphicons-halflings-regular.woff +0 -0
- data/assets/fonts/glyphicons-halflings-regular.woff2 +0 -0
- data/assets/fonts/lato-regular/LICENSE.txt +93 -0
- data/assets/fonts/lato-regular/Lato-regular.eot +0 -0
- data/assets/fonts/lato-regular/Lato-regular.svg +435 -0
- data/assets/fonts/lato-regular/Lato-regular.ttf +0 -0
- data/assets/fonts/lato-regular/Lato-regular.woff +0 -0
- data/assets/fonts/lato-regular/Lato-regular.woff2 +0 -0
- data/assets/images/Linaro-Logo.svg +1 -0
- data/assets/images/Linaro-Logo_light.png +0 -0
- data/assets/images/Linaro-Logo_standard.svg +1 -0
- data/assets/images/Linaro-Sprinkle.png +0 -0
- data/assets/images/avatar-placeholder.png +0 -0
- data/assets/images/background-image.jpg +0 -0
- data/assets/images/banner.jpg +0 -0
- data/assets/images/breadcrumb-image.jpg +0 -0
- data/assets/images/close.png +0 -0
- data/assets/images/favicon.ico +0 -0
- data/assets/images/favicon.png +0 -0
- data/assets/images/loading.gif +0 -0
- data/assets/images/next.png +0 -0
- data/assets/images/owl.video.play.png +0 -0
- data/assets/images/placeholder.png +0 -0
- data/assets/images/prev.png +0 -0
- data/assets/images/social-media-image.png +0 -0
- data/assets/js/app/custom.js +0 -0
- data/assets/js/app/facebook.js +8 -0
- data/assets/js/app/home.js +46 -0
- data/assets/js/app/main.js +143 -0
- data/assets/js/app/scroll-to-anchors.js +10 -0
- data/assets/js/app/sticky-tab-bar.js +72 -0
- data/assets/js/app/tables.js +35 -0
- data/assets/js/package-blog.js +10 -0
- data/assets/js/package-extended.js +14 -0
- data/assets/js/package-home.js +12 -0
- data/assets/js/package-main.js +10 -0
- data/assets/js/package-search.js +8 -0
- data/assets/js/vendor/bootstrap.js +2377 -0
- data/assets/js/vendor/cognito.js +11 -0
- data/assets/js/vendor/cookieconsent.js +1504 -0
- data/assets/js/vendor/jquery.js +10364 -0
- data/assets/js/vendor/jquery.rss.js +333 -0
- data/assets/js/vendor/jquery.validate.js +1601 -0
- data/assets/js/vendor/lazysizes.js +698 -0
- data/assets/js/vendor/lightbox.js +523 -0
- data/assets/js/vendor/loadCSS.js +35 -0
- data/assets/js/vendor/ls.unveilhooks.js +145 -0
- data/assets/js/vendor/mc.js +255 -0
- data/assets/js/vendor/owl.carousel.js +3475 -0
- data/assets/js/vendor/picturefill.js +1471 -0
- data/assets/js/vendor/shuffle.js +2004 -0
- data/robots.txt +9 -0
- metadata +528 -0
|
@@ -0,0 +1,1471 @@
|
|
|
1
|
+
/*! Picturefill - v3.0.2
|
|
2
|
+
* http://scottjehl.github.io/picturefill
|
|
3
|
+
* Copyright (c) 2015 https://github.com/scottjehl/picturefill/blob/master/Authors.txt;
|
|
4
|
+
* License: MIT
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
(function( window, document, undefined ) {
|
|
8
|
+
// Enable strict mode
|
|
9
|
+
"use strict";
|
|
10
|
+
|
|
11
|
+
// HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround)
|
|
12
|
+
document.createElement( "picture" );
|
|
13
|
+
|
|
14
|
+
var warn, eminpx, alwaysCheckWDescriptor, evalId;
|
|
15
|
+
// local object for method references and testing exposure
|
|
16
|
+
var pf = {};
|
|
17
|
+
var isSupportTestReady = false;
|
|
18
|
+
var noop = function() {};
|
|
19
|
+
var image = document.createElement( "img" );
|
|
20
|
+
var getImgAttr = image.getAttribute;
|
|
21
|
+
var setImgAttr = image.setAttribute;
|
|
22
|
+
var removeImgAttr = image.removeAttribute;
|
|
23
|
+
var docElem = document.documentElement;
|
|
24
|
+
var types = {};
|
|
25
|
+
var cfg = {
|
|
26
|
+
//resource selection:
|
|
27
|
+
algorithm: ""
|
|
28
|
+
};
|
|
29
|
+
var srcAttr = "data-pfsrc";
|
|
30
|
+
var srcsetAttr = srcAttr + "set";
|
|
31
|
+
// ua sniffing is done for undetectable img loading features,
|
|
32
|
+
// to do some non crucial perf optimizations
|
|
33
|
+
var ua = navigator.userAgent;
|
|
34
|
+
var supportAbort = (/rident/).test(ua) || ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 > 35 );
|
|
35
|
+
var curSrcProp = "currentSrc";
|
|
36
|
+
var regWDesc = /\s+\+?\d+(e\d+)?w/;
|
|
37
|
+
var regSize = /(\([^)]+\))?\s*(.+)/;
|
|
38
|
+
var setOptions = window.picturefillCFG;
|
|
39
|
+
/**
|
|
40
|
+
* Shortcut property for https://w3c.github.io/webappsec/specs/mixedcontent/#restricts-mixed-content ( for easy overriding in tests )
|
|
41
|
+
*/
|
|
42
|
+
// baseStyle also used by getEmValue (i.e.: width: 1em is important)
|
|
43
|
+
var baseStyle = "position:absolute;left:0;visibility:hidden;display:block;padding:0;border:none;font-size:1em;width:1em;overflow:hidden;clip:rect(0px, 0px, 0px, 0px)";
|
|
44
|
+
var fsCss = "font-size:100%!important;";
|
|
45
|
+
var isVwDirty = true;
|
|
46
|
+
|
|
47
|
+
var cssCache = {};
|
|
48
|
+
var sizeLengthCache = {};
|
|
49
|
+
var DPR = window.devicePixelRatio;
|
|
50
|
+
var units = {
|
|
51
|
+
px: 1,
|
|
52
|
+
"in": 96
|
|
53
|
+
};
|
|
54
|
+
var anchor = document.createElement( "a" );
|
|
55
|
+
/**
|
|
56
|
+
* alreadyRun flag used for setOptions. is it true setOptions will reevaluate
|
|
57
|
+
* @type {boolean}
|
|
58
|
+
*/
|
|
59
|
+
var alreadyRun = false;
|
|
60
|
+
|
|
61
|
+
// Reusable, non-"g" Regexes
|
|
62
|
+
|
|
63
|
+
// (Don't use \s, to avoid matching non-breaking space.)
|
|
64
|
+
var regexLeadingSpaces = /^[ \t\n\r\u000c]+/,
|
|
65
|
+
regexLeadingCommasOrSpaces = /^[, \t\n\r\u000c]+/,
|
|
66
|
+
regexLeadingNotSpaces = /^[^ \t\n\r\u000c]+/,
|
|
67
|
+
regexTrailingCommas = /[,]+$/,
|
|
68
|
+
regexNonNegativeInteger = /^\d+$/,
|
|
69
|
+
|
|
70
|
+
// ( Positive or negative or unsigned integers or decimals, without or without exponents.
|
|
71
|
+
// Must include at least one digit.
|
|
72
|
+
// According to spec tests any decimal point must be followed by a digit.
|
|
73
|
+
// No leading plus sign is allowed.)
|
|
74
|
+
// https://html.spec.whatwg.org/multipage/infrastructure.html#valid-floating-point-number
|
|
75
|
+
regexFloatingPoint = /^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/;
|
|
76
|
+
|
|
77
|
+
var on = function(obj, evt, fn, capture) {
|
|
78
|
+
if ( obj.addEventListener ) {
|
|
79
|
+
obj.addEventListener(evt, fn, capture || false);
|
|
80
|
+
} else if ( obj.attachEvent ) {
|
|
81
|
+
obj.attachEvent( "on" + evt, fn);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* simple memoize function:
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
var memoize = function(fn) {
|
|
90
|
+
var cache = {};
|
|
91
|
+
return function(input) {
|
|
92
|
+
if ( !(input in cache) ) {
|
|
93
|
+
cache[ input ] = fn(input);
|
|
94
|
+
}
|
|
95
|
+
return cache[ input ];
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// UTILITY FUNCTIONS
|
|
100
|
+
|
|
101
|
+
// Manual is faster than RegEx
|
|
102
|
+
// http://jsperf.com/whitespace-character/5
|
|
103
|
+
function isSpace(c) {
|
|
104
|
+
return (c === "\u0020" || // space
|
|
105
|
+
c === "\u0009" || // horizontal tab
|
|
106
|
+
c === "\u000A" || // new line
|
|
107
|
+
c === "\u000C" || // form feed
|
|
108
|
+
c === "\u000D"); // carriage return
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* gets a mediaquery and returns a boolean or gets a css length and returns a number
|
|
113
|
+
* @param css mediaqueries or css length
|
|
114
|
+
* @returns {boolean|number}
|
|
115
|
+
*
|
|
116
|
+
* based on: https://gist.github.com/jonathantneal/db4f77009b155f083738
|
|
117
|
+
*/
|
|
118
|
+
var evalCSS = (function() {
|
|
119
|
+
|
|
120
|
+
var regLength = /^([\d\.]+)(em|vw|px)$/;
|
|
121
|
+
var replace = function() {
|
|
122
|
+
var args = arguments, index = 0, string = args[0];
|
|
123
|
+
while (++index in args) {
|
|
124
|
+
string = string.replace(args[index], args[++index]);
|
|
125
|
+
}
|
|
126
|
+
return string;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
var buildStr = memoize(function(css) {
|
|
130
|
+
|
|
131
|
+
return "return " + replace((css || "").toLowerCase(),
|
|
132
|
+
// interpret `and`
|
|
133
|
+
/\band\b/g, "&&",
|
|
134
|
+
|
|
135
|
+
// interpret `,`
|
|
136
|
+
/,/g, "||",
|
|
137
|
+
|
|
138
|
+
// interpret `min-` as >=
|
|
139
|
+
/min-([a-z-\s]+):/g, "e.$1>=",
|
|
140
|
+
|
|
141
|
+
// interpret `max-` as <=
|
|
142
|
+
/max-([a-z-\s]+):/g, "e.$1<=",
|
|
143
|
+
|
|
144
|
+
//calc value
|
|
145
|
+
/calc([^)]+)/g, "($1)",
|
|
146
|
+
|
|
147
|
+
// interpret css values
|
|
148
|
+
/(\d+[\.]*[\d]*)([a-z]+)/g, "($1 * e.$2)",
|
|
149
|
+
//make eval less evil
|
|
150
|
+
/^(?!(e.[a-z]|[0-9\.&=|><\+\-\*\(\)\/])).*/ig, ""
|
|
151
|
+
) + ";";
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return function(css, length) {
|
|
155
|
+
var parsedLength;
|
|
156
|
+
if (!(css in cssCache)) {
|
|
157
|
+
cssCache[css] = false;
|
|
158
|
+
if (length && (parsedLength = css.match( regLength ))) {
|
|
159
|
+
cssCache[css] = parsedLength[ 1 ] * units[parsedLength[ 2 ]];
|
|
160
|
+
} else {
|
|
161
|
+
/*jshint evil:true */
|
|
162
|
+
try{
|
|
163
|
+
cssCache[css] = new Function("e", buildStr(css))(units);
|
|
164
|
+
} catch(e) {}
|
|
165
|
+
/*jshint evil:false */
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return cssCache[css];
|
|
169
|
+
};
|
|
170
|
+
})();
|
|
171
|
+
|
|
172
|
+
var setResolution = function( candidate, sizesattr ) {
|
|
173
|
+
if ( candidate.w ) { // h = means height: || descriptor.type === 'h' do not handle yet...
|
|
174
|
+
candidate.cWidth = pf.calcListLength( sizesattr || "100vw" );
|
|
175
|
+
candidate.res = candidate.w / candidate.cWidth ;
|
|
176
|
+
} else {
|
|
177
|
+
candidate.res = candidate.d;
|
|
178
|
+
}
|
|
179
|
+
return candidate;
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
*
|
|
184
|
+
* @param opt
|
|
185
|
+
*/
|
|
186
|
+
var picturefill = function( opt ) {
|
|
187
|
+
|
|
188
|
+
if (!isSupportTestReady) {return;}
|
|
189
|
+
|
|
190
|
+
var elements, i, plen;
|
|
191
|
+
|
|
192
|
+
var options = opt || {};
|
|
193
|
+
|
|
194
|
+
if ( options.elements && options.elements.nodeType === 1 ) {
|
|
195
|
+
if ( options.elements.nodeName.toUpperCase() === "IMG" ) {
|
|
196
|
+
options.elements = [ options.elements ];
|
|
197
|
+
} else {
|
|
198
|
+
options.context = options.elements;
|
|
199
|
+
options.elements = null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
elements = options.elements || pf.qsa( (options.context || document), ( options.reevaluate || options.reselect ) ? pf.sel : pf.selShort );
|
|
204
|
+
|
|
205
|
+
if ( (plen = elements.length) ) {
|
|
206
|
+
|
|
207
|
+
pf.setupRun( options );
|
|
208
|
+
alreadyRun = true;
|
|
209
|
+
|
|
210
|
+
// Loop through all elements
|
|
211
|
+
for ( i = 0; i < plen; i++ ) {
|
|
212
|
+
pf.fillImg(elements[ i ], options);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
pf.teardownRun( options );
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* outputs a warning for the developer
|
|
221
|
+
* @param {message}
|
|
222
|
+
* @type {Function}
|
|
223
|
+
*/
|
|
224
|
+
warn = ( window.console && console.warn ) ?
|
|
225
|
+
function( message ) {
|
|
226
|
+
console.warn( message );
|
|
227
|
+
} :
|
|
228
|
+
noop
|
|
229
|
+
;
|
|
230
|
+
|
|
231
|
+
if ( !(curSrcProp in image) ) {
|
|
232
|
+
curSrcProp = "src";
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Add support for standard mime types.
|
|
236
|
+
types[ "image/jpeg" ] = true;
|
|
237
|
+
types[ "image/gif" ] = true;
|
|
238
|
+
types[ "image/png" ] = true;
|
|
239
|
+
|
|
240
|
+
function detectTypeSupport( type, typeUri ) {
|
|
241
|
+
// based on Modernizr's lossless img-webp test
|
|
242
|
+
// note: asynchronous
|
|
243
|
+
var image = new window.Image();
|
|
244
|
+
image.onerror = function() {
|
|
245
|
+
types[ type ] = false;
|
|
246
|
+
picturefill();
|
|
247
|
+
};
|
|
248
|
+
image.onload = function() {
|
|
249
|
+
types[ type ] = image.width === 1;
|
|
250
|
+
picturefill();
|
|
251
|
+
};
|
|
252
|
+
image.src = typeUri;
|
|
253
|
+
return "pending";
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// test svg support
|
|
257
|
+
types[ "image/svg+xml" ] = document.implementation.hasFeature( "http://www.w3.org/TR/SVG11/feature#Image", "1.1" );
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* updates the internal vW property with the current viewport width in px
|
|
261
|
+
*/
|
|
262
|
+
function updateMetrics() {
|
|
263
|
+
|
|
264
|
+
isVwDirty = false;
|
|
265
|
+
DPR = window.devicePixelRatio;
|
|
266
|
+
cssCache = {};
|
|
267
|
+
sizeLengthCache = {};
|
|
268
|
+
|
|
269
|
+
pf.DPR = DPR || 1;
|
|
270
|
+
|
|
271
|
+
units.width = Math.max(window.innerWidth || 0, docElem.clientWidth);
|
|
272
|
+
units.height = Math.max(window.innerHeight || 0, docElem.clientHeight);
|
|
273
|
+
|
|
274
|
+
units.vw = units.width / 100;
|
|
275
|
+
units.vh = units.height / 100;
|
|
276
|
+
|
|
277
|
+
evalId = [ units.height, units.width, DPR ].join("-");
|
|
278
|
+
|
|
279
|
+
units.em = pf.getEmValue();
|
|
280
|
+
units.rem = units.em;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function chooseLowRes( lowerValue, higherValue, dprValue, isCached ) {
|
|
284
|
+
var bonusFactor, tooMuch, bonus, meanDensity;
|
|
285
|
+
|
|
286
|
+
//experimental
|
|
287
|
+
if (cfg.algorithm === "saveData" ){
|
|
288
|
+
if ( lowerValue > 2.7 ) {
|
|
289
|
+
meanDensity = dprValue + 1;
|
|
290
|
+
} else {
|
|
291
|
+
tooMuch = higherValue - dprValue;
|
|
292
|
+
bonusFactor = Math.pow(lowerValue - 0.6, 1.5);
|
|
293
|
+
|
|
294
|
+
bonus = tooMuch * bonusFactor;
|
|
295
|
+
|
|
296
|
+
if (isCached) {
|
|
297
|
+
bonus += 0.1 * bonusFactor;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
meanDensity = lowerValue + bonus;
|
|
301
|
+
}
|
|
302
|
+
} else {
|
|
303
|
+
meanDensity = (dprValue > 1) ?
|
|
304
|
+
Math.sqrt(lowerValue * higherValue) :
|
|
305
|
+
lowerValue;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
return meanDensity > dprValue;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function applyBestCandidate( img ) {
|
|
312
|
+
var srcSetCandidates;
|
|
313
|
+
var matchingSet = pf.getSet( img );
|
|
314
|
+
var evaluated = false;
|
|
315
|
+
if ( matchingSet !== "pending" ) {
|
|
316
|
+
evaluated = evalId;
|
|
317
|
+
if ( matchingSet ) {
|
|
318
|
+
srcSetCandidates = pf.setRes( matchingSet );
|
|
319
|
+
pf.applySetCandidate( srcSetCandidates, img );
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
img[ pf.ns ].evaled = evaluated;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function ascendingSort( a, b ) {
|
|
326
|
+
return a.res - b.res;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function setSrcToCur( img, src, set ) {
|
|
330
|
+
var candidate;
|
|
331
|
+
if ( !set && src ) {
|
|
332
|
+
set = img[ pf.ns ].sets;
|
|
333
|
+
set = set && set[set.length - 1];
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
candidate = getCandidateForSrc(src, set);
|
|
337
|
+
|
|
338
|
+
if ( candidate ) {
|
|
339
|
+
src = pf.makeUrl(src);
|
|
340
|
+
img[ pf.ns ].curSrc = src;
|
|
341
|
+
img[ pf.ns ].curCan = candidate;
|
|
342
|
+
|
|
343
|
+
if ( !candidate.res ) {
|
|
344
|
+
setResolution( candidate, candidate.set.sizes );
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return candidate;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function getCandidateForSrc( src, set ) {
|
|
351
|
+
var i, candidate, candidates;
|
|
352
|
+
if ( src && set ) {
|
|
353
|
+
candidates = pf.parseSet( set );
|
|
354
|
+
src = pf.makeUrl(src);
|
|
355
|
+
for ( i = 0; i < candidates.length; i++ ) {
|
|
356
|
+
if ( src === pf.makeUrl(candidates[ i ].url) ) {
|
|
357
|
+
candidate = candidates[ i ];
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
return candidate;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function getAllSourceElements( picture, candidates ) {
|
|
366
|
+
var i, len, source, srcset;
|
|
367
|
+
|
|
368
|
+
// SPEC mismatch intended for size and perf:
|
|
369
|
+
// actually only source elements preceding the img should be used
|
|
370
|
+
// also note: don't use qsa here, because IE8 sometimes doesn't like source as the key part in a selector
|
|
371
|
+
var sources = picture.getElementsByTagName( "source" );
|
|
372
|
+
|
|
373
|
+
for ( i = 0, len = sources.length; i < len; i++ ) {
|
|
374
|
+
source = sources[ i ];
|
|
375
|
+
source[ pf.ns ] = true;
|
|
376
|
+
srcset = source.getAttribute( "srcset" );
|
|
377
|
+
|
|
378
|
+
// if source does not have a srcset attribute, skip
|
|
379
|
+
if ( srcset ) {
|
|
380
|
+
candidates.push( {
|
|
381
|
+
srcset: srcset,
|
|
382
|
+
media: source.getAttribute( "media" ),
|
|
383
|
+
type: source.getAttribute( "type" ),
|
|
384
|
+
sizes: source.getAttribute( "sizes" )
|
|
385
|
+
} );
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Srcset Parser
|
|
392
|
+
* By Alex Bell | MIT License
|
|
393
|
+
*
|
|
394
|
+
* @returns Array [{url: _, d: _, w: _, h:_, set:_(????)}, ...]
|
|
395
|
+
*
|
|
396
|
+
* Based super duper closely on the reference algorithm at:
|
|
397
|
+
* https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute
|
|
398
|
+
*/
|
|
399
|
+
|
|
400
|
+
// 1. Let input be the value passed to this algorithm.
|
|
401
|
+
// (TO-DO : Explain what "set" argument is here. Maybe choose a more
|
|
402
|
+
// descriptive & more searchable name. Since passing the "set" in really has
|
|
403
|
+
// nothing to do with parsing proper, I would prefer this assignment eventually
|
|
404
|
+
// go in an external fn.)
|
|
405
|
+
function parseSrcset(input, set) {
|
|
406
|
+
|
|
407
|
+
function collectCharacters(regEx) {
|
|
408
|
+
var chars,
|
|
409
|
+
match = regEx.exec(input.substring(pos));
|
|
410
|
+
if (match) {
|
|
411
|
+
chars = match[ 0 ];
|
|
412
|
+
pos += chars.length;
|
|
413
|
+
return chars;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
var inputLength = input.length,
|
|
418
|
+
url,
|
|
419
|
+
descriptors,
|
|
420
|
+
currentDescriptor,
|
|
421
|
+
state,
|
|
422
|
+
c,
|
|
423
|
+
|
|
424
|
+
// 2. Let position be a pointer into input, initially pointing at the start
|
|
425
|
+
// of the string.
|
|
426
|
+
pos = 0,
|
|
427
|
+
|
|
428
|
+
// 3. Let candidates be an initially empty source set.
|
|
429
|
+
candidates = [];
|
|
430
|
+
|
|
431
|
+
/**
|
|
432
|
+
* Adds descriptor properties to a candidate, pushes to the candidates array
|
|
433
|
+
* @return undefined
|
|
434
|
+
*/
|
|
435
|
+
// (Declared outside of the while loop so that it's only created once.
|
|
436
|
+
// (This fn is defined before it is used, in order to pass JSHINT.
|
|
437
|
+
// Unfortunately this breaks the sequencing of the spec comments. :/ )
|
|
438
|
+
function parseDescriptors() {
|
|
439
|
+
|
|
440
|
+
// 9. Descriptor parser: Let error be no.
|
|
441
|
+
var pError = false,
|
|
442
|
+
|
|
443
|
+
// 10. Let width be absent.
|
|
444
|
+
// 11. Let density be absent.
|
|
445
|
+
// 12. Let future-compat-h be absent. (We're implementing it now as h)
|
|
446
|
+
w, d, h, i,
|
|
447
|
+
candidate = {},
|
|
448
|
+
desc, lastChar, value, intVal, floatVal;
|
|
449
|
+
|
|
450
|
+
// 13. For each descriptor in descriptors, run the appropriate set of steps
|
|
451
|
+
// from the following list:
|
|
452
|
+
for (i = 0 ; i < descriptors.length; i++) {
|
|
453
|
+
desc = descriptors[ i ];
|
|
454
|
+
|
|
455
|
+
lastChar = desc[ desc.length - 1 ];
|
|
456
|
+
value = desc.substring(0, desc.length - 1);
|
|
457
|
+
intVal = parseInt(value, 10);
|
|
458
|
+
floatVal = parseFloat(value);
|
|
459
|
+
|
|
460
|
+
// If the descriptor consists of a valid non-negative integer followed by
|
|
461
|
+
// a U+0077 LATIN SMALL LETTER W character
|
|
462
|
+
if (regexNonNegativeInteger.test(value) && (lastChar === "w")) {
|
|
463
|
+
|
|
464
|
+
// If width and density are not both absent, then let error be yes.
|
|
465
|
+
if (w || d) {pError = true;}
|
|
466
|
+
|
|
467
|
+
// Apply the rules for parsing non-negative integers to the descriptor.
|
|
468
|
+
// If the result is zero, let error be yes.
|
|
469
|
+
// Otherwise, let width be the result.
|
|
470
|
+
if (intVal === 0) {pError = true;} else {w = intVal;}
|
|
471
|
+
|
|
472
|
+
// If the descriptor consists of a valid floating-point number followed by
|
|
473
|
+
// a U+0078 LATIN SMALL LETTER X character
|
|
474
|
+
} else if (regexFloatingPoint.test(value) && (lastChar === "x")) {
|
|
475
|
+
|
|
476
|
+
// If width, density and future-compat-h are not all absent, then let error
|
|
477
|
+
// be yes.
|
|
478
|
+
if (w || d || h) {pError = true;}
|
|
479
|
+
|
|
480
|
+
// Apply the rules for parsing floating-point number values to the descriptor.
|
|
481
|
+
// If the result is less than zero, let error be yes. Otherwise, let density
|
|
482
|
+
// be the result.
|
|
483
|
+
if (floatVal < 0) {pError = true;} else {d = floatVal;}
|
|
484
|
+
|
|
485
|
+
// If the descriptor consists of a valid non-negative integer followed by
|
|
486
|
+
// a U+0068 LATIN SMALL LETTER H character
|
|
487
|
+
} else if (regexNonNegativeInteger.test(value) && (lastChar === "h")) {
|
|
488
|
+
|
|
489
|
+
// If height and density are not both absent, then let error be yes.
|
|
490
|
+
if (h || d) {pError = true;}
|
|
491
|
+
|
|
492
|
+
// Apply the rules for parsing non-negative integers to the descriptor.
|
|
493
|
+
// If the result is zero, let error be yes. Otherwise, let future-compat-h
|
|
494
|
+
// be the result.
|
|
495
|
+
if (intVal === 0) {pError = true;} else {h = intVal;}
|
|
496
|
+
|
|
497
|
+
// Anything else, Let error be yes.
|
|
498
|
+
} else {pError = true;}
|
|
499
|
+
} // (close step 13 for loop)
|
|
500
|
+
|
|
501
|
+
// 15. If error is still no, then append a new image source to candidates whose
|
|
502
|
+
// URL is url, associated with a width width if not absent and a pixel
|
|
503
|
+
// density density if not absent. Otherwise, there is a parse error.
|
|
504
|
+
if (!pError) {
|
|
505
|
+
candidate.url = url;
|
|
506
|
+
|
|
507
|
+
if (w) { candidate.w = w;}
|
|
508
|
+
if (d) { candidate.d = d;}
|
|
509
|
+
if (h) { candidate.h = h;}
|
|
510
|
+
if (!h && !d && !w) {candidate.d = 1;}
|
|
511
|
+
if (candidate.d === 1) {set.has1x = true;}
|
|
512
|
+
candidate.set = set;
|
|
513
|
+
|
|
514
|
+
candidates.push(candidate);
|
|
515
|
+
}
|
|
516
|
+
} // (close parseDescriptors fn)
|
|
517
|
+
|
|
518
|
+
/**
|
|
519
|
+
* Tokenizes descriptor properties prior to parsing
|
|
520
|
+
* Returns undefined.
|
|
521
|
+
* (Again, this fn is defined before it is used, in order to pass JSHINT.
|
|
522
|
+
* Unfortunately this breaks the logical sequencing of the spec comments. :/ )
|
|
523
|
+
*/
|
|
524
|
+
function tokenize() {
|
|
525
|
+
|
|
526
|
+
// 8.1. Descriptor tokeniser: Skip whitespace
|
|
527
|
+
collectCharacters(regexLeadingSpaces);
|
|
528
|
+
|
|
529
|
+
// 8.2. Let current descriptor be the empty string.
|
|
530
|
+
currentDescriptor = "";
|
|
531
|
+
|
|
532
|
+
// 8.3. Let state be in descriptor.
|
|
533
|
+
state = "in descriptor";
|
|
534
|
+
|
|
535
|
+
while (true) {
|
|
536
|
+
|
|
537
|
+
// 8.4. Let c be the character at position.
|
|
538
|
+
c = input.charAt(pos);
|
|
539
|
+
|
|
540
|
+
// Do the following depending on the value of state.
|
|
541
|
+
// For the purpose of this step, "EOF" is a special character representing
|
|
542
|
+
// that position is past the end of input.
|
|
543
|
+
|
|
544
|
+
// In descriptor
|
|
545
|
+
if (state === "in descriptor") {
|
|
546
|
+
// Do the following, depending on the value of c:
|
|
547
|
+
|
|
548
|
+
// Space character
|
|
549
|
+
// If current descriptor is not empty, append current descriptor to
|
|
550
|
+
// descriptors and let current descriptor be the empty string.
|
|
551
|
+
// Set state to after descriptor.
|
|
552
|
+
if (isSpace(c)) {
|
|
553
|
+
if (currentDescriptor) {
|
|
554
|
+
descriptors.push(currentDescriptor);
|
|
555
|
+
currentDescriptor = "";
|
|
556
|
+
state = "after descriptor";
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
// U+002C COMMA (,)
|
|
560
|
+
// Advance position to the next character in input. If current descriptor
|
|
561
|
+
// is not empty, append current descriptor to descriptors. Jump to the step
|
|
562
|
+
// labeled descriptor parser.
|
|
563
|
+
} else if (c === ",") {
|
|
564
|
+
pos += 1;
|
|
565
|
+
if (currentDescriptor) {
|
|
566
|
+
descriptors.push(currentDescriptor);
|
|
567
|
+
}
|
|
568
|
+
parseDescriptors();
|
|
569
|
+
return;
|
|
570
|
+
|
|
571
|
+
// U+0028 LEFT PARENTHESIS (()
|
|
572
|
+
// Append c to current descriptor. Set state to in parens.
|
|
573
|
+
} else if (c === "\u0028") {
|
|
574
|
+
currentDescriptor = currentDescriptor + c;
|
|
575
|
+
state = "in parens";
|
|
576
|
+
|
|
577
|
+
// EOF
|
|
578
|
+
// If current descriptor is not empty, append current descriptor to
|
|
579
|
+
// descriptors. Jump to the step labeled descriptor parser.
|
|
580
|
+
} else if (c === "") {
|
|
581
|
+
if (currentDescriptor) {
|
|
582
|
+
descriptors.push(currentDescriptor);
|
|
583
|
+
}
|
|
584
|
+
parseDescriptors();
|
|
585
|
+
return;
|
|
586
|
+
|
|
587
|
+
// Anything else
|
|
588
|
+
// Append c to current descriptor.
|
|
589
|
+
} else {
|
|
590
|
+
currentDescriptor = currentDescriptor + c;
|
|
591
|
+
}
|
|
592
|
+
// (end "in descriptor"
|
|
593
|
+
|
|
594
|
+
// In parens
|
|
595
|
+
} else if (state === "in parens") {
|
|
596
|
+
|
|
597
|
+
// U+0029 RIGHT PARENTHESIS ())
|
|
598
|
+
// Append c to current descriptor. Set state to in descriptor.
|
|
599
|
+
if (c === ")") {
|
|
600
|
+
currentDescriptor = currentDescriptor + c;
|
|
601
|
+
state = "in descriptor";
|
|
602
|
+
|
|
603
|
+
// EOF
|
|
604
|
+
// Append current descriptor to descriptors. Jump to the step labeled
|
|
605
|
+
// descriptor parser.
|
|
606
|
+
} else if (c === "") {
|
|
607
|
+
descriptors.push(currentDescriptor);
|
|
608
|
+
parseDescriptors();
|
|
609
|
+
return;
|
|
610
|
+
|
|
611
|
+
// Anything else
|
|
612
|
+
// Append c to current descriptor.
|
|
613
|
+
} else {
|
|
614
|
+
currentDescriptor = currentDescriptor + c;
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// After descriptor
|
|
618
|
+
} else if (state === "after descriptor") {
|
|
619
|
+
|
|
620
|
+
// Do the following, depending on the value of c:
|
|
621
|
+
// Space character: Stay in this state.
|
|
622
|
+
if (isSpace(c)) {
|
|
623
|
+
|
|
624
|
+
// EOF: Jump to the step labeled descriptor parser.
|
|
625
|
+
} else if (c === "") {
|
|
626
|
+
parseDescriptors();
|
|
627
|
+
return;
|
|
628
|
+
|
|
629
|
+
// Anything else
|
|
630
|
+
// Set state to in descriptor. Set position to the previous character in input.
|
|
631
|
+
} else {
|
|
632
|
+
state = "in descriptor";
|
|
633
|
+
pos -= 1;
|
|
634
|
+
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Advance position to the next character in input.
|
|
639
|
+
pos += 1;
|
|
640
|
+
|
|
641
|
+
// Repeat this step.
|
|
642
|
+
} // (close while true loop)
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// 4. Splitting loop: Collect a sequence of characters that are space
|
|
646
|
+
// characters or U+002C COMMA characters. If any U+002C COMMA characters
|
|
647
|
+
// were collected, that is a parse error.
|
|
648
|
+
while (true) {
|
|
649
|
+
collectCharacters(regexLeadingCommasOrSpaces);
|
|
650
|
+
|
|
651
|
+
// 5. If position is past the end of input, return candidates and abort these steps.
|
|
652
|
+
if (pos >= inputLength) {
|
|
653
|
+
return candidates; // (we're done, this is the sole return path)
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
// 6. Collect a sequence of characters that are not space characters,
|
|
657
|
+
// and let that be url.
|
|
658
|
+
url = collectCharacters(regexLeadingNotSpaces);
|
|
659
|
+
|
|
660
|
+
// 7. Let descriptors be a new empty list.
|
|
661
|
+
descriptors = [];
|
|
662
|
+
|
|
663
|
+
// 8. If url ends with a U+002C COMMA character (,), follow these substeps:
|
|
664
|
+
// (1). Remove all trailing U+002C COMMA characters from url. If this removed
|
|
665
|
+
// more than one character, that is a parse error.
|
|
666
|
+
if (url.slice(-1) === ",") {
|
|
667
|
+
url = url.replace(regexTrailingCommas, "");
|
|
668
|
+
// (Jump ahead to step 9 to skip tokenization and just push the candidate).
|
|
669
|
+
parseDescriptors();
|
|
670
|
+
|
|
671
|
+
// Otherwise, follow these substeps:
|
|
672
|
+
} else {
|
|
673
|
+
tokenize();
|
|
674
|
+
} // (close else of step 8)
|
|
675
|
+
|
|
676
|
+
// 16. Return to the step labeled splitting loop.
|
|
677
|
+
} // (Close of big while loop.)
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
/*
|
|
681
|
+
* Sizes Parser
|
|
682
|
+
*
|
|
683
|
+
* By Alex Bell | MIT License
|
|
684
|
+
*
|
|
685
|
+
* Non-strict but accurate and lightweight JS Parser for the string value <img sizes="here">
|
|
686
|
+
*
|
|
687
|
+
* Reference algorithm at:
|
|
688
|
+
* https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-sizes-attribute
|
|
689
|
+
*
|
|
690
|
+
* Most comments are copied in directly from the spec
|
|
691
|
+
* (except for comments in parens).
|
|
692
|
+
*
|
|
693
|
+
* Grammar is:
|
|
694
|
+
* <source-size-list> = <source-size># [ , <source-size-value> ]? | <source-size-value>
|
|
695
|
+
* <source-size> = <media-condition> <source-size-value>
|
|
696
|
+
* <source-size-value> = <length>
|
|
697
|
+
* http://www.w3.org/html/wg/drafts/html/master/embedded-content.html#attr-img-sizes
|
|
698
|
+
*
|
|
699
|
+
* E.g. "(max-width: 30em) 100vw, (max-width: 50em) 70vw, 100vw"
|
|
700
|
+
* or "(min-width: 30em), calc(30vw - 15px)" or just "30vw"
|
|
701
|
+
*
|
|
702
|
+
* Returns the first valid <css-length> with a media condition that evaluates to true,
|
|
703
|
+
* or "100vw" if all valid media conditions evaluate to false.
|
|
704
|
+
*
|
|
705
|
+
*/
|
|
706
|
+
|
|
707
|
+
function parseSizes(strValue) {
|
|
708
|
+
|
|
709
|
+
// (Percentage CSS lengths are not allowed in this case, to avoid confusion:
|
|
710
|
+
// https://html.spec.whatwg.org/multipage/embedded-content.html#valid-source-size-list
|
|
711
|
+
// CSS allows a single optional plus or minus sign:
|
|
712
|
+
// http://www.w3.org/TR/CSS2/syndata.html#numbers
|
|
713
|
+
// CSS is ASCII case-insensitive:
|
|
714
|
+
// http://www.w3.org/TR/CSS2/syndata.html#characters )
|
|
715
|
+
// Spec allows exponential notation for <number> type:
|
|
716
|
+
// http://dev.w3.org/csswg/css-values/#numbers
|
|
717
|
+
var regexCssLengthWithUnits = /^(?:[+-]?[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?(?:ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmin|vmax|vw)$/i;
|
|
718
|
+
|
|
719
|
+
// (This is a quick and lenient test. Because of optional unlimited-depth internal
|
|
720
|
+
// grouping parens and strict spacing rules, this could get very complicated.)
|
|
721
|
+
var regexCssCalc = /^calc\((?:[0-9a-z \.\+\-\*\/\(\)]+)\)$/i;
|
|
722
|
+
|
|
723
|
+
var i;
|
|
724
|
+
var unparsedSizesList;
|
|
725
|
+
var unparsedSizesListLength;
|
|
726
|
+
var unparsedSize;
|
|
727
|
+
var lastComponentValue;
|
|
728
|
+
var size;
|
|
729
|
+
|
|
730
|
+
// UTILITY FUNCTIONS
|
|
731
|
+
|
|
732
|
+
// (Toy CSS parser. The goals here are:
|
|
733
|
+
// 1) expansive test coverage without the weight of a full CSS parser.
|
|
734
|
+
// 2) Avoiding regex wherever convenient.
|
|
735
|
+
// Quick tests: http://jsfiddle.net/gtntL4gr/3/
|
|
736
|
+
// Returns an array of arrays.)
|
|
737
|
+
function parseComponentValues(str) {
|
|
738
|
+
var chrctr;
|
|
739
|
+
var component = "";
|
|
740
|
+
var componentArray = [];
|
|
741
|
+
var listArray = [];
|
|
742
|
+
var parenDepth = 0;
|
|
743
|
+
var pos = 0;
|
|
744
|
+
var inComment = false;
|
|
745
|
+
|
|
746
|
+
function pushComponent() {
|
|
747
|
+
if (component) {
|
|
748
|
+
componentArray.push(component);
|
|
749
|
+
component = "";
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
function pushComponentArray() {
|
|
754
|
+
if (componentArray[0]) {
|
|
755
|
+
listArray.push(componentArray);
|
|
756
|
+
componentArray = [];
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
// (Loop forwards from the beginning of the string.)
|
|
761
|
+
while (true) {
|
|
762
|
+
chrctr = str.charAt(pos);
|
|
763
|
+
|
|
764
|
+
if (chrctr === "") { // ( End of string reached.)
|
|
765
|
+
pushComponent();
|
|
766
|
+
pushComponentArray();
|
|
767
|
+
return listArray;
|
|
768
|
+
} else if (inComment) {
|
|
769
|
+
if ((chrctr === "*") && (str[pos + 1] === "/")) { // (At end of a comment.)
|
|
770
|
+
inComment = false;
|
|
771
|
+
pos += 2;
|
|
772
|
+
pushComponent();
|
|
773
|
+
continue;
|
|
774
|
+
} else {
|
|
775
|
+
pos += 1; // (Skip all characters inside comments.)
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
} else if (isSpace(chrctr)) {
|
|
779
|
+
// (If previous character in loop was also a space, or if
|
|
780
|
+
// at the beginning of the string, do not add space char to
|
|
781
|
+
// component.)
|
|
782
|
+
if ( (str.charAt(pos - 1) && isSpace( str.charAt(pos - 1) ) ) || !component ) {
|
|
783
|
+
pos += 1;
|
|
784
|
+
continue;
|
|
785
|
+
} else if (parenDepth === 0) {
|
|
786
|
+
pushComponent();
|
|
787
|
+
pos +=1;
|
|
788
|
+
continue;
|
|
789
|
+
} else {
|
|
790
|
+
// (Replace any space character with a plain space for legibility.)
|
|
791
|
+
chrctr = " ";
|
|
792
|
+
}
|
|
793
|
+
} else if (chrctr === "(") {
|
|
794
|
+
parenDepth += 1;
|
|
795
|
+
} else if (chrctr === ")") {
|
|
796
|
+
parenDepth -= 1;
|
|
797
|
+
} else if (chrctr === ",") {
|
|
798
|
+
pushComponent();
|
|
799
|
+
pushComponentArray();
|
|
800
|
+
pos += 1;
|
|
801
|
+
continue;
|
|
802
|
+
} else if ( (chrctr === "/") && (str.charAt(pos + 1) === "*") ) {
|
|
803
|
+
inComment = true;
|
|
804
|
+
pos += 2;
|
|
805
|
+
continue;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
component = component + chrctr;
|
|
809
|
+
pos += 1;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
function isValidNonNegativeSourceSizeValue(s) {
|
|
814
|
+
if (regexCssLengthWithUnits.test(s) && (parseFloat(s) >= 0)) {return true;}
|
|
815
|
+
if (regexCssCalc.test(s)) {return true;}
|
|
816
|
+
// ( http://www.w3.org/TR/CSS2/syndata.html#numbers says:
|
|
817
|
+
// "-0 is equivalent to 0 and is not a negative number." which means that
|
|
818
|
+
// unitless zero and unitless negative zero must be accepted as special cases.)
|
|
819
|
+
if ((s === "0") || (s === "-0") || (s === "+0")) {return true;}
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
// When asked to parse a sizes attribute from an element, parse a
|
|
824
|
+
// comma-separated list of component values from the value of the element's
|
|
825
|
+
// sizes attribute (or the empty string, if the attribute is absent), and let
|
|
826
|
+
// unparsed sizes list be the result.
|
|
827
|
+
// http://dev.w3.org/csswg/css-syntax/#parse-comma-separated-list-of-component-values
|
|
828
|
+
|
|
829
|
+
unparsedSizesList = parseComponentValues(strValue);
|
|
830
|
+
unparsedSizesListLength = unparsedSizesList.length;
|
|
831
|
+
|
|
832
|
+
// For each unparsed size in unparsed sizes list:
|
|
833
|
+
for (i = 0; i < unparsedSizesListLength; i++) {
|
|
834
|
+
unparsedSize = unparsedSizesList[i];
|
|
835
|
+
|
|
836
|
+
// 1. Remove all consecutive <whitespace-token>s from the end of unparsed size.
|
|
837
|
+
// ( parseComponentValues() already omits spaces outside of parens. )
|
|
838
|
+
|
|
839
|
+
// If unparsed size is now empty, that is a parse error; continue to the next
|
|
840
|
+
// iteration of this algorithm.
|
|
841
|
+
// ( parseComponentValues() won't push an empty array. )
|
|
842
|
+
|
|
843
|
+
// 2. If the last component value in unparsed size is a valid non-negative
|
|
844
|
+
// <source-size-value>, let size be its value and remove the component value
|
|
845
|
+
// from unparsed size. Any CSS function other than the calc() function is
|
|
846
|
+
// invalid. Otherwise, there is a parse error; continue to the next iteration
|
|
847
|
+
// of this algorithm.
|
|
848
|
+
// http://dev.w3.org/csswg/css-syntax/#parse-component-value
|
|
849
|
+
lastComponentValue = unparsedSize[unparsedSize.length - 1];
|
|
850
|
+
|
|
851
|
+
if (isValidNonNegativeSourceSizeValue(lastComponentValue)) {
|
|
852
|
+
size = lastComponentValue;
|
|
853
|
+
unparsedSize.pop();
|
|
854
|
+
} else {
|
|
855
|
+
continue;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
// 3. Remove all consecutive <whitespace-token>s from the end of unparsed
|
|
859
|
+
// size. If unparsed size is now empty, return size and exit this algorithm.
|
|
860
|
+
// If this was not the last item in unparsed sizes list, that is a parse error.
|
|
861
|
+
if (unparsedSize.length === 0) {
|
|
862
|
+
return size;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// 4. Parse the remaining component values in unparsed size as a
|
|
866
|
+
// <media-condition>. If it does not parse correctly, or it does parse
|
|
867
|
+
// correctly but the <media-condition> evaluates to false, continue to the
|
|
868
|
+
// next iteration of this algorithm.
|
|
869
|
+
// (Parsing all possible compound media conditions in JS is heavy, complicated,
|
|
870
|
+
// and the payoff is unclear. Is there ever an situation where the
|
|
871
|
+
// media condition parses incorrectly but still somehow evaluates to true?
|
|
872
|
+
// Can we just rely on the browser/polyfill to do it?)
|
|
873
|
+
unparsedSize = unparsedSize.join(" ");
|
|
874
|
+
if (!(pf.matchesMedia( unparsedSize ) ) ) {
|
|
875
|
+
continue;
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
// 5. Return size and exit this algorithm.
|
|
879
|
+
return size;
|
|
880
|
+
}
|
|
881
|
+
|
|
882
|
+
// If the above algorithm exhausts unparsed sizes list without returning a
|
|
883
|
+
// size value, return 100vw.
|
|
884
|
+
return "100vw";
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
// namespace
|
|
888
|
+
pf.ns = ("pf" + new Date().getTime()).substr(0, 9);
|
|
889
|
+
|
|
890
|
+
// srcset support test
|
|
891
|
+
pf.supSrcset = "srcset" in image;
|
|
892
|
+
pf.supSizes = "sizes" in image;
|
|
893
|
+
pf.supPicture = !!window.HTMLPictureElement;
|
|
894
|
+
|
|
895
|
+
// UC browser does claim to support srcset and picture, but not sizes,
|
|
896
|
+
// this extended test reveals the browser does support nothing
|
|
897
|
+
if (pf.supSrcset && pf.supPicture && !pf.supSizes) {
|
|
898
|
+
(function(image2) {
|
|
899
|
+
image.srcset = "data:,a";
|
|
900
|
+
image2.src = "data:,a";
|
|
901
|
+
pf.supSrcset = image.complete === image2.complete;
|
|
902
|
+
pf.supPicture = pf.supSrcset && pf.supPicture;
|
|
903
|
+
})(document.createElement("img"));
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
// Safari9 has basic support for sizes, but does't expose the `sizes` idl attribute
|
|
907
|
+
if (pf.supSrcset && !pf.supSizes) {
|
|
908
|
+
|
|
909
|
+
(function() {
|
|
910
|
+
var width2 = "data:image/gif;base64,R0lGODlhAgABAPAAAP///wAAACH5BAAAAAAALAAAAAACAAEAAAICBAoAOw==";
|
|
911
|
+
var width1 = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
|
|
912
|
+
var img = document.createElement("img");
|
|
913
|
+
var test = function() {
|
|
914
|
+
var width = img.width;
|
|
915
|
+
|
|
916
|
+
if (width === 2) {
|
|
917
|
+
pf.supSizes = true;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
alwaysCheckWDescriptor = pf.supSrcset && !pf.supSizes;
|
|
921
|
+
|
|
922
|
+
isSupportTestReady = true;
|
|
923
|
+
// force async
|
|
924
|
+
setTimeout(picturefill);
|
|
925
|
+
};
|
|
926
|
+
|
|
927
|
+
img.onload = test;
|
|
928
|
+
img.onerror = test;
|
|
929
|
+
img.setAttribute("sizes", "9px");
|
|
930
|
+
|
|
931
|
+
img.srcset = width1 + " 1w," + width2 + " 9w";
|
|
932
|
+
img.src = width1;
|
|
933
|
+
})();
|
|
934
|
+
|
|
935
|
+
} else {
|
|
936
|
+
isSupportTestReady = true;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
// using pf.qsa instead of dom traversing does scale much better,
|
|
940
|
+
// especially on sites mixing responsive and non-responsive images
|
|
941
|
+
pf.selShort = "picture>img,img[srcset]";
|
|
942
|
+
pf.sel = pf.selShort;
|
|
943
|
+
pf.cfg = cfg;
|
|
944
|
+
|
|
945
|
+
/**
|
|
946
|
+
* Shortcut property for `devicePixelRatio` ( for easy overriding in tests )
|
|
947
|
+
*/
|
|
948
|
+
pf.DPR = (DPR || 1 );
|
|
949
|
+
pf.u = units;
|
|
950
|
+
|
|
951
|
+
// container of supported mime types that one might need to qualify before using
|
|
952
|
+
pf.types = types;
|
|
953
|
+
|
|
954
|
+
pf.setSize = noop;
|
|
955
|
+
|
|
956
|
+
/**
|
|
957
|
+
* Gets a string and returns the absolute URL
|
|
958
|
+
* @param src
|
|
959
|
+
* @returns {String} absolute URL
|
|
960
|
+
*/
|
|
961
|
+
|
|
962
|
+
pf.makeUrl = memoize(function(src) {
|
|
963
|
+
anchor.href = src;
|
|
964
|
+
return anchor.href;
|
|
965
|
+
});
|
|
966
|
+
|
|
967
|
+
/**
|
|
968
|
+
* Gets a DOM element or document and a selctor and returns the found matches
|
|
969
|
+
* Can be extended with jQuery/Sizzle for IE7 support
|
|
970
|
+
* @param context
|
|
971
|
+
* @param sel
|
|
972
|
+
* @returns {NodeList|Array}
|
|
973
|
+
*/
|
|
974
|
+
pf.qsa = function(context, sel) {
|
|
975
|
+
return ( "querySelector" in context ) ? context.querySelectorAll(sel) : [];
|
|
976
|
+
};
|
|
977
|
+
|
|
978
|
+
/**
|
|
979
|
+
* Shortcut method for matchMedia ( for easy overriding in tests )
|
|
980
|
+
* wether native or pf.mMQ is used will be decided lazy on first call
|
|
981
|
+
* @returns {boolean}
|
|
982
|
+
*/
|
|
983
|
+
pf.matchesMedia = function() {
|
|
984
|
+
if ( window.matchMedia && (matchMedia( "(min-width: 0.1em)" ) || {}).matches ) {
|
|
985
|
+
pf.matchesMedia = function( media ) {
|
|
986
|
+
return !media || ( matchMedia( media ).matches );
|
|
987
|
+
};
|
|
988
|
+
} else {
|
|
989
|
+
pf.matchesMedia = pf.mMQ;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
return pf.matchesMedia.apply( this, arguments );
|
|
993
|
+
};
|
|
994
|
+
|
|
995
|
+
/**
|
|
996
|
+
* A simplified matchMedia implementation for IE8 and IE9
|
|
997
|
+
* handles only min-width/max-width with px or em values
|
|
998
|
+
* @param media
|
|
999
|
+
* @returns {boolean}
|
|
1000
|
+
*/
|
|
1001
|
+
pf.mMQ = function( media ) {
|
|
1002
|
+
return media ? evalCSS(media) : true;
|
|
1003
|
+
};
|
|
1004
|
+
|
|
1005
|
+
/**
|
|
1006
|
+
* Returns the calculated length in css pixel from the given sourceSizeValue
|
|
1007
|
+
* http://dev.w3.org/csswg/css-values-3/#length-value
|
|
1008
|
+
* intended Spec mismatches:
|
|
1009
|
+
* * Does not check for invalid use of CSS functions
|
|
1010
|
+
* * Does handle a computed length of 0 the same as a negative and therefore invalid value
|
|
1011
|
+
* @param sourceSizeValue
|
|
1012
|
+
* @returns {Number}
|
|
1013
|
+
*/
|
|
1014
|
+
pf.calcLength = function( sourceSizeValue ) {
|
|
1015
|
+
|
|
1016
|
+
var value = evalCSS(sourceSizeValue, true) || false;
|
|
1017
|
+
if (value < 0) {
|
|
1018
|
+
value = false;
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
return value;
|
|
1022
|
+
};
|
|
1023
|
+
|
|
1024
|
+
/**
|
|
1025
|
+
* Takes a type string and checks if its supported
|
|
1026
|
+
*/
|
|
1027
|
+
|
|
1028
|
+
pf.supportsType = function( type ) {
|
|
1029
|
+
return ( type ) ? types[ type ] : true;
|
|
1030
|
+
};
|
|
1031
|
+
|
|
1032
|
+
/**
|
|
1033
|
+
* Parses a sourceSize into mediaCondition (media) and sourceSizeValue (length)
|
|
1034
|
+
* @param sourceSizeStr
|
|
1035
|
+
* @returns {*}
|
|
1036
|
+
*/
|
|
1037
|
+
pf.parseSize = memoize(function( sourceSizeStr ) {
|
|
1038
|
+
var match = ( sourceSizeStr || "" ).match(regSize);
|
|
1039
|
+
return {
|
|
1040
|
+
media: match && match[1],
|
|
1041
|
+
length: match && match[2]
|
|
1042
|
+
};
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
pf.parseSet = function( set ) {
|
|
1046
|
+
if ( !set.cands ) {
|
|
1047
|
+
set.cands = parseSrcset(set.srcset, set);
|
|
1048
|
+
}
|
|
1049
|
+
return set.cands;
|
|
1050
|
+
};
|
|
1051
|
+
|
|
1052
|
+
/**
|
|
1053
|
+
* returns 1em in css px for html/body default size
|
|
1054
|
+
* function taken from respondjs
|
|
1055
|
+
* @returns {*|number}
|
|
1056
|
+
*/
|
|
1057
|
+
pf.getEmValue = function() {
|
|
1058
|
+
var body;
|
|
1059
|
+
if ( !eminpx && (body = document.body) ) {
|
|
1060
|
+
var div = document.createElement( "div" ),
|
|
1061
|
+
originalHTMLCSS = docElem.style.cssText,
|
|
1062
|
+
originalBodyCSS = body.style.cssText;
|
|
1063
|
+
|
|
1064
|
+
div.style.cssText = baseStyle;
|
|
1065
|
+
|
|
1066
|
+
// 1em in a media query is the value of the default font size of the browser
|
|
1067
|
+
// reset docElem and body to ensure the correct value is returned
|
|
1068
|
+
docElem.style.cssText = fsCss;
|
|
1069
|
+
body.style.cssText = fsCss;
|
|
1070
|
+
|
|
1071
|
+
body.appendChild( div );
|
|
1072
|
+
eminpx = div.offsetWidth;
|
|
1073
|
+
body.removeChild( div );
|
|
1074
|
+
|
|
1075
|
+
//also update eminpx before returning
|
|
1076
|
+
eminpx = parseFloat( eminpx, 10 );
|
|
1077
|
+
|
|
1078
|
+
// restore the original values
|
|
1079
|
+
docElem.style.cssText = originalHTMLCSS;
|
|
1080
|
+
body.style.cssText = originalBodyCSS;
|
|
1081
|
+
|
|
1082
|
+
}
|
|
1083
|
+
return eminpx || 16;
|
|
1084
|
+
};
|
|
1085
|
+
|
|
1086
|
+
/**
|
|
1087
|
+
* Takes a string of sizes and returns the width in pixels as a number
|
|
1088
|
+
*/
|
|
1089
|
+
pf.calcListLength = function( sourceSizeListStr ) {
|
|
1090
|
+
// Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33%
|
|
1091
|
+
//
|
|
1092
|
+
// or (min-width:30em) calc(30% - 15px)
|
|
1093
|
+
if ( !(sourceSizeListStr in sizeLengthCache) || cfg.uT ) {
|
|
1094
|
+
var winningLength = pf.calcLength( parseSizes( sourceSizeListStr ) );
|
|
1095
|
+
|
|
1096
|
+
sizeLengthCache[ sourceSizeListStr ] = !winningLength ? units.width : winningLength;
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
return sizeLengthCache[ sourceSizeListStr ];
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* Takes a candidate object with a srcset property in the form of url/
|
|
1104
|
+
* ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or
|
|
1105
|
+
* "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or
|
|
1106
|
+
* "images/pic-small.png"
|
|
1107
|
+
* Get an array of image candidates in the form of
|
|
1108
|
+
* {url: "/foo/bar.png", resolution: 1}
|
|
1109
|
+
* where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value
|
|
1110
|
+
* If sizes is specified, res is calculated
|
|
1111
|
+
*/
|
|
1112
|
+
pf.setRes = function( set ) {
|
|
1113
|
+
var candidates;
|
|
1114
|
+
if ( set ) {
|
|
1115
|
+
|
|
1116
|
+
candidates = pf.parseSet( set );
|
|
1117
|
+
|
|
1118
|
+
for ( var i = 0, len = candidates.length; i < len; i++ ) {
|
|
1119
|
+
setResolution( candidates[ i ], set.sizes );
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return candidates;
|
|
1123
|
+
};
|
|
1124
|
+
|
|
1125
|
+
pf.setRes.res = setResolution;
|
|
1126
|
+
|
|
1127
|
+
pf.applySetCandidate = function( candidates, img ) {
|
|
1128
|
+
if ( !candidates.length ) {return;}
|
|
1129
|
+
var candidate,
|
|
1130
|
+
i,
|
|
1131
|
+
j,
|
|
1132
|
+
length,
|
|
1133
|
+
bestCandidate,
|
|
1134
|
+
curSrc,
|
|
1135
|
+
curCan,
|
|
1136
|
+
candidateSrc,
|
|
1137
|
+
abortCurSrc;
|
|
1138
|
+
|
|
1139
|
+
var imageData = img[ pf.ns ];
|
|
1140
|
+
var dpr = pf.DPR;
|
|
1141
|
+
|
|
1142
|
+
curSrc = imageData.curSrc || img[curSrcProp];
|
|
1143
|
+
|
|
1144
|
+
curCan = imageData.curCan || setSrcToCur(img, curSrc, candidates[0].set);
|
|
1145
|
+
|
|
1146
|
+
// if we have a current source, we might either become lazy or give this source some advantage
|
|
1147
|
+
if ( curCan && curCan.set === candidates[ 0 ].set ) {
|
|
1148
|
+
|
|
1149
|
+
// if browser can abort image request and the image has a higher pixel density than needed
|
|
1150
|
+
// and this image isn't downloaded yet, we skip next part and try to save bandwidth
|
|
1151
|
+
abortCurSrc = (supportAbort && !img.complete && curCan.res - 0.1 > dpr);
|
|
1152
|
+
|
|
1153
|
+
if ( !abortCurSrc ) {
|
|
1154
|
+
curCan.cached = true;
|
|
1155
|
+
|
|
1156
|
+
// if current candidate is "best", "better" or "okay",
|
|
1157
|
+
// set it to bestCandidate
|
|
1158
|
+
if ( curCan.res >= dpr ) {
|
|
1159
|
+
bestCandidate = curCan;
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
if ( !bestCandidate ) {
|
|
1165
|
+
|
|
1166
|
+
candidates.sort( ascendingSort );
|
|
1167
|
+
|
|
1168
|
+
length = candidates.length;
|
|
1169
|
+
bestCandidate = candidates[ length - 1 ];
|
|
1170
|
+
|
|
1171
|
+
for ( i = 0; i < length; i++ ) {
|
|
1172
|
+
candidate = candidates[ i ];
|
|
1173
|
+
if ( candidate.res >= dpr ) {
|
|
1174
|
+
j = i - 1;
|
|
1175
|
+
|
|
1176
|
+
// we have found the perfect candidate,
|
|
1177
|
+
// but let's improve this a little bit with some assumptions ;-)
|
|
1178
|
+
if (candidates[ j ] &&
|
|
1179
|
+
(abortCurSrc || curSrc !== pf.makeUrl( candidate.url )) &&
|
|
1180
|
+
chooseLowRes(candidates[ j ].res, candidate.res, dpr, candidates[ j ].cached)) {
|
|
1181
|
+
|
|
1182
|
+
bestCandidate = candidates[ j ];
|
|
1183
|
+
|
|
1184
|
+
} else {
|
|
1185
|
+
bestCandidate = candidate;
|
|
1186
|
+
}
|
|
1187
|
+
break;
|
|
1188
|
+
}
|
|
1189
|
+
}
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
if ( bestCandidate ) {
|
|
1193
|
+
|
|
1194
|
+
candidateSrc = pf.makeUrl( bestCandidate.url );
|
|
1195
|
+
|
|
1196
|
+
imageData.curSrc = candidateSrc;
|
|
1197
|
+
imageData.curCan = bestCandidate;
|
|
1198
|
+
|
|
1199
|
+
if ( candidateSrc !== curSrc ) {
|
|
1200
|
+
pf.setSrc( img, bestCandidate );
|
|
1201
|
+
}
|
|
1202
|
+
pf.setSize( img );
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
|
|
1206
|
+
pf.setSrc = function( img, bestCandidate ) {
|
|
1207
|
+
var origWidth;
|
|
1208
|
+
img.src = bestCandidate.url;
|
|
1209
|
+
|
|
1210
|
+
// although this is a specific Safari issue, we don't want to take too much different code paths
|
|
1211
|
+
if ( bestCandidate.set.type === "image/svg+xml" ) {
|
|
1212
|
+
origWidth = img.style.width;
|
|
1213
|
+
img.style.width = (img.offsetWidth + 1) + "px";
|
|
1214
|
+
|
|
1215
|
+
// next line only should trigger a repaint
|
|
1216
|
+
// if... is only done to trick dead code removal
|
|
1217
|
+
if ( img.offsetWidth + 1 ) {
|
|
1218
|
+
img.style.width = origWidth;
|
|
1219
|
+
}
|
|
1220
|
+
}
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
pf.getSet = function( img ) {
|
|
1224
|
+
var i, set, supportsType;
|
|
1225
|
+
var match = false;
|
|
1226
|
+
var sets = img [ pf.ns ].sets;
|
|
1227
|
+
|
|
1228
|
+
for ( i = 0; i < sets.length && !match; i++ ) {
|
|
1229
|
+
set = sets[i];
|
|
1230
|
+
|
|
1231
|
+
if ( !set.srcset || !pf.matchesMedia( set.media ) || !(supportsType = pf.supportsType( set.type )) ) {
|
|
1232
|
+
continue;
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
if ( supportsType === "pending" ) {
|
|
1236
|
+
set = supportsType;
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
match = set;
|
|
1240
|
+
break;
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
return match;
|
|
1244
|
+
};
|
|
1245
|
+
|
|
1246
|
+
pf.parseSets = function( element, parent, options ) {
|
|
1247
|
+
var srcsetAttribute, imageSet, isWDescripor, srcsetParsed;
|
|
1248
|
+
|
|
1249
|
+
var hasPicture = parent && parent.nodeName.toUpperCase() === "PICTURE";
|
|
1250
|
+
var imageData = element[ pf.ns ];
|
|
1251
|
+
|
|
1252
|
+
if ( imageData.src === undefined || options.src ) {
|
|
1253
|
+
imageData.src = getImgAttr.call( element, "src" );
|
|
1254
|
+
if ( imageData.src ) {
|
|
1255
|
+
setImgAttr.call( element, srcAttr, imageData.src );
|
|
1256
|
+
} else {
|
|
1257
|
+
removeImgAttr.call( element, srcAttr );
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
if ( imageData.srcset === undefined || options.srcset || !pf.supSrcset || element.srcset ) {
|
|
1262
|
+
srcsetAttribute = getImgAttr.call( element, "srcset" );
|
|
1263
|
+
imageData.srcset = srcsetAttribute;
|
|
1264
|
+
srcsetParsed = true;
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
imageData.sets = [];
|
|
1268
|
+
|
|
1269
|
+
if ( hasPicture ) {
|
|
1270
|
+
imageData.pic = true;
|
|
1271
|
+
getAllSourceElements( parent, imageData.sets );
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
if ( imageData.srcset ) {
|
|
1275
|
+
imageSet = {
|
|
1276
|
+
srcset: imageData.srcset,
|
|
1277
|
+
sizes: getImgAttr.call( element, "sizes" )
|
|
1278
|
+
};
|
|
1279
|
+
|
|
1280
|
+
imageData.sets.push( imageSet );
|
|
1281
|
+
|
|
1282
|
+
isWDescripor = (alwaysCheckWDescriptor || imageData.src) && regWDesc.test(imageData.srcset || "");
|
|
1283
|
+
|
|
1284
|
+
// add normal src as candidate, if source has no w descriptor
|
|
1285
|
+
if ( !isWDescripor && imageData.src && !getCandidateForSrc(imageData.src, imageSet) && !imageSet.has1x ) {
|
|
1286
|
+
imageSet.srcset += ", " + imageData.src;
|
|
1287
|
+
imageSet.cands.push({
|
|
1288
|
+
url: imageData.src,
|
|
1289
|
+
d: 1,
|
|
1290
|
+
set: imageSet
|
|
1291
|
+
});
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
} else if ( imageData.src ) {
|
|
1295
|
+
imageData.sets.push( {
|
|
1296
|
+
srcset: imageData.src,
|
|
1297
|
+
sizes: null
|
|
1298
|
+
} );
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
imageData.curCan = null;
|
|
1302
|
+
imageData.curSrc = undefined;
|
|
1303
|
+
|
|
1304
|
+
// if img has picture or the srcset was removed or has a srcset and does not support srcset at all
|
|
1305
|
+
// or has a w descriptor (and does not support sizes) set support to false to evaluate
|
|
1306
|
+
imageData.supported = !( hasPicture || ( imageSet && !pf.supSrcset ) || (isWDescripor && !pf.supSizes) );
|
|
1307
|
+
|
|
1308
|
+
if ( srcsetParsed && pf.supSrcset && !imageData.supported ) {
|
|
1309
|
+
if ( srcsetAttribute ) {
|
|
1310
|
+
setImgAttr.call( element, srcsetAttr, srcsetAttribute );
|
|
1311
|
+
element.srcset = "";
|
|
1312
|
+
} else {
|
|
1313
|
+
removeImgAttr.call( element, srcsetAttr );
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
|
|
1317
|
+
if (imageData.supported && !imageData.srcset && ((!imageData.src && element.src) || element.src !== pf.makeUrl(imageData.src))) {
|
|
1318
|
+
if (imageData.src === null) {
|
|
1319
|
+
element.removeAttribute("src");
|
|
1320
|
+
} else {
|
|
1321
|
+
element.src = imageData.src;
|
|
1322
|
+
}
|
|
1323
|
+
}
|
|
1324
|
+
|
|
1325
|
+
imageData.parsed = true;
|
|
1326
|
+
};
|
|
1327
|
+
|
|
1328
|
+
pf.fillImg = function(element, options) {
|
|
1329
|
+
var imageData;
|
|
1330
|
+
var extreme = options.reselect || options.reevaluate;
|
|
1331
|
+
|
|
1332
|
+
// expando for caching data on the img
|
|
1333
|
+
if ( !element[ pf.ns ] ) {
|
|
1334
|
+
element[ pf.ns ] = {};
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
imageData = element[ pf.ns ];
|
|
1338
|
+
|
|
1339
|
+
// if the element has already been evaluated, skip it
|
|
1340
|
+
// unless `options.reevaluate` is set to true ( this, for example,
|
|
1341
|
+
// is set to true when running `picturefill` on `resize` ).
|
|
1342
|
+
if ( !extreme && imageData.evaled === evalId ) {
|
|
1343
|
+
return;
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
if ( !imageData.parsed || options.reevaluate ) {
|
|
1347
|
+
pf.parseSets( element, element.parentNode, options );
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
if ( !imageData.supported ) {
|
|
1351
|
+
applyBestCandidate( element );
|
|
1352
|
+
} else {
|
|
1353
|
+
imageData.evaled = evalId;
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
|
|
1357
|
+
pf.setupRun = function() {
|
|
1358
|
+
if ( !alreadyRun || isVwDirty || (DPR !== window.devicePixelRatio) ) {
|
|
1359
|
+
updateMetrics();
|
|
1360
|
+
}
|
|
1361
|
+
};
|
|
1362
|
+
|
|
1363
|
+
// If picture is supported, well, that's awesome.
|
|
1364
|
+
if ( pf.supPicture ) {
|
|
1365
|
+
picturefill = noop;
|
|
1366
|
+
pf.fillImg = noop;
|
|
1367
|
+
} else {
|
|
1368
|
+
|
|
1369
|
+
// Set up picture polyfill by polling the document
|
|
1370
|
+
(function() {
|
|
1371
|
+
var isDomReady;
|
|
1372
|
+
var regReady = window.attachEvent ? /d$|^c/ : /d$|^c|^i/;
|
|
1373
|
+
|
|
1374
|
+
var run = function() {
|
|
1375
|
+
var readyState = document.readyState || "";
|
|
1376
|
+
|
|
1377
|
+
timerId = setTimeout(run, readyState === "loading" ? 200 : 999);
|
|
1378
|
+
if ( document.body ) {
|
|
1379
|
+
pf.fillImgs();
|
|
1380
|
+
isDomReady = isDomReady || regReady.test(readyState);
|
|
1381
|
+
if ( isDomReady ) {
|
|
1382
|
+
clearTimeout( timerId );
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
}
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
var timerId = setTimeout(run, document.body ? 9 : 99);
|
|
1389
|
+
|
|
1390
|
+
// Also attach picturefill on resize and readystatechange
|
|
1391
|
+
// http://modernjavascript.blogspot.com/2013/08/building-better-debounce.html
|
|
1392
|
+
var debounce = function(func, wait) {
|
|
1393
|
+
var timeout, timestamp;
|
|
1394
|
+
var later = function() {
|
|
1395
|
+
var last = (new Date()) - timestamp;
|
|
1396
|
+
|
|
1397
|
+
if (last < wait) {
|
|
1398
|
+
timeout = setTimeout(later, wait - last);
|
|
1399
|
+
} else {
|
|
1400
|
+
timeout = null;
|
|
1401
|
+
func();
|
|
1402
|
+
}
|
|
1403
|
+
};
|
|
1404
|
+
|
|
1405
|
+
return function() {
|
|
1406
|
+
timestamp = new Date();
|
|
1407
|
+
|
|
1408
|
+
if (!timeout) {
|
|
1409
|
+
timeout = setTimeout(later, wait);
|
|
1410
|
+
}
|
|
1411
|
+
};
|
|
1412
|
+
};
|
|
1413
|
+
var lastClientWidth = docElem.clientHeight;
|
|
1414
|
+
var onResize = function() {
|
|
1415
|
+
isVwDirty = Math.max(window.innerWidth || 0, docElem.clientWidth) !== units.width || docElem.clientHeight !== lastClientWidth;
|
|
1416
|
+
lastClientWidth = docElem.clientHeight;
|
|
1417
|
+
if ( isVwDirty ) {
|
|
1418
|
+
pf.fillImgs();
|
|
1419
|
+
}
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
on( window, "resize", debounce(onResize, 99 ) );
|
|
1423
|
+
on( document, "readystatechange", run );
|
|
1424
|
+
})();
|
|
1425
|
+
}
|
|
1426
|
+
|
|
1427
|
+
pf.picturefill = picturefill;
|
|
1428
|
+
//use this internally for easy monkey patching/performance testing
|
|
1429
|
+
pf.fillImgs = picturefill;
|
|
1430
|
+
pf.teardownRun = noop;
|
|
1431
|
+
|
|
1432
|
+
/* expose methods for testing */
|
|
1433
|
+
picturefill._ = pf;
|
|
1434
|
+
|
|
1435
|
+
window.picturefillCFG = {
|
|
1436
|
+
pf: pf,
|
|
1437
|
+
push: function(args) {
|
|
1438
|
+
var name = args.shift();
|
|
1439
|
+
if (typeof pf[name] === "function") {
|
|
1440
|
+
pf[name].apply(pf, args);
|
|
1441
|
+
} else {
|
|
1442
|
+
cfg[name] = args[0];
|
|
1443
|
+
if (alreadyRun) {
|
|
1444
|
+
pf.fillImgs( { reselect: true } );
|
|
1445
|
+
}
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
|
|
1450
|
+
while (setOptions && setOptions.length) {
|
|
1451
|
+
window.picturefillCFG.push(setOptions.shift());
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
/* expose picturefill */
|
|
1455
|
+
window.picturefill = picturefill;
|
|
1456
|
+
|
|
1457
|
+
/* expose picturefill */
|
|
1458
|
+
if ( typeof module === "object" && typeof module.exports === "object" ) {
|
|
1459
|
+
// CommonJS, just export
|
|
1460
|
+
module.exports = picturefill;
|
|
1461
|
+
} else if ( typeof define === "function" && define.amd ) {
|
|
1462
|
+
// AMD support
|
|
1463
|
+
define( "picturefill", function() { return picturefill; } );
|
|
1464
|
+
}
|
|
1465
|
+
|
|
1466
|
+
// IE8 evals this sync, so it must be the last thing we do
|
|
1467
|
+
if ( !pf.supPicture ) {
|
|
1468
|
+
types[ "image/webp" ] = detectTypeSupport("image/webp", "data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==" );
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
} )( window, document );
|