This repository has been archived by the owner on Nov 26, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
pickyfill.js
183 lines (156 loc) · 7.01 KB
/
pickyfill.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
/*! Pickyfill - Offline caching for picturefill responsive image polyfill. Author: Rich Trott | Copyright: Regents of University of California, 2012 | License: MIT */
(function( w ) {
"use strict";
var localStorage = w.localStorage,
applicationCache = w.applicationCache,
image,
dataUri,
pf_index_string,
pf_index,
canvasTest = document.createElement('canvas');
// Don't run any of this stuff if application cache, localStorage or canvas are not available.
if ( (! applicationCache) || (! localStorage) || (!(canvasTest.getContext && canvasTest.getContext('2d'))) ) {
return;
}
pf_index_string = localStorage.getItem('pf_index') || '{}';
pf_index = JSON.parse(pf_index_string);
// We'll use this to clear the pickyfill cache when appcache updates.
var clearCache = function () {
localStorage.removeItem('pf_index');
for (var prop in pf_index) {
if (pf_index.hasOwnProperty(prop)) {
localStorage.removeItem(prop);
}
}
};
// Unfortunately, reloading is the most reliable way to get stuff into the
// pickyfill cache. If you wait for the user to reload, they may be offline
// at that time. If we just had an updateready event, chances are very good
// that they are still online. Another possibility is to just try to reload
// the images that are currently shown, but there's no guarantee that those
// images are in the new page or that the current page isn't missing important
// images that will display in the new page and need to be cached.
var refreshCache = function () {
clearCache();
w.location.reload();
};
// If appcache is new, refresh the pickyfill cache to get new items.
// If appcache is obsolete, clear the pickyfill cache.
// Appcache == IE10 or later == no need to worry about attachEvent (IE8 and earlier)
// Anything that has appcache is going to have addEventListener.
applicationCache.addEventListener('updateready', refreshCache, false);
applicationCache.addEventListener('cached', refreshCache, false);
applicationCache.addEventListener('obsolete', clearCache, false);
// If the event has already fired and we missed it, clear/refresh the pickyfill cache.
if (applicationCache.status === applicationCache.UPDATEREADY) {
refreshCache();
}
if (applicationCache.status === applicationCache.OBSOLETE) {
clearCache();
}
var srcFromCacheRan = false;
var srcFromCache = function ( ps ) {
var sources, src, newSrc;
// Loop the pictures
for( var i = 0, il = ps.length; i < il; i++ ){
if( ps[ i ].getAttribute( "data-picture" ) !== null ){
sources = ps[ i ].getElementsByTagName( "div" );
// See which ones are cached in localStorage. Use the cached value.
for( var j = 0, jl = sources.length; j < jl; j++ ){
if ((src = sources[j].getAttribute( "data-src" )) !== null ) {
if ( pf_index.hasOwnProperty('pf_s_' + src)) {
newSrc = localStorage.getItem('pf_s_' + src);
if (newSrc !== null) {
sources[j].setAttribute('data-src', localStorage.getItem('pf_s_' + src));
}
}
}
}
}
}
};
var cacheImage = function () {
var canvas,
ctx,
imageSrc,
mimeType;
imageSrc = this.getAttribute("src");
if ((pf_index.hasOwnProperty('pf_s_' + imageSrc)) ||
(imageSrc.substr(0,5) === "data:") ||
(imageSrc === null) || (imageSrc.length === 0)) {
return;
}
canvas = w.document.createElement("canvas");
canvas.width = this.width;
canvas.height = this.height;
ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0);
// Lossy JPGs will be huge as PNGs, so let JPGs be JPGs.
mimeType = /\.jpe?g$/i.exec(imageSrc) ? 'image/jpeg' : 'image/png';
try {
dataUri = canvas.toDataURL( mimeType );
} catch (e) {
// TODO: Improve error handling here. For now, if canvas.toDataURL()
// throws an exception, don't cache the image and move on.
return;
}
// Do not cache if the resulting cache item will take more than 192Kb.
// Do not cache if dataUri is corrupt and useless. (Hi, Android 2.3!)
if ((dataUri.length > 196608) || (dataUri.length < 7)) {
return;
}
pf_index["pf_s_"+imageSrc] = 1;
try {
localStorage.setItem("pf_s_"+imageSrc, dataUri);
localStorage.setItem("pf_index", JSON.stringify(pf_index));
} catch (e) {
// Caching failed. Remove item from index object so next cached item
// doesn't wrongly indicate this item was successfully cached.
delete pf_index["pf_s_"+imageSrc];
}
// WAT?!?! UserAgent sniffing?! Yes, lame, but Firefox will cache truncated
// images if you're resize happens at the wrong moment and there's not a
// an efficient way that I'm aware of to detect that this has happened.
//
// So we only cache images in Firefox on load, not on resize. I have not seen
// it happen on document load...yet.
//
// If you think you have a better way to handle this, see details at
// http://stackoverflow.com/q/11928878/436641 and submit an answer or
// comment there.
if (navigator.userAgent.indexOf("Firefox") !== -1) {
this.removeEventListener('load', cacheImage, false);
}
};
// Exit here if uncached. If updateready fires later, it will reload,
// and status will not be uncached on the that load.
if (applicationCache.status === applicationCache.UNCACHED) {
return;
}
w.picturefillOrig = w.picturefill;
w.picturefill = function () {
var ps = w.document.getElementsByTagName( "div" ),
i,
il;
if (! srcFromCacheRan ) {
srcFromCacheRan = true;
srcFromCache( ps );
}
w.picturefillOrig();
// Loop the pictures
for( i = 0, il = ps.length; i < il; i++ ) {
if( ps[ i ].getAttribute( "data-picture" ) !== null ){
image = ps[ i ].getElementsByTagName( "img" )[0];
if (image) {
if (image.getAttribute("src") !== null) {
image.addEventListener('load', cacheImage, false);
//TODO: What to do (if anything) if we missed the load event. image.complete
// cannot be used for this, at least not on Firefox 14.0.1 on the Mac. It is
// set to "true" even after window is resized and src attribute is changed to an
// image that is not yet loaded.
}
}
}
}
};
}( this ));