1const CACHE_VERSION = '1.7.44.1'; 2 3const BASE_CACHE_FILES = [ 4 'https://www.milar.es/blog/wp-content/plugins/pwa-for-wp/images/logo.png', 5'https://www.milar.es/blog/wp-content/plugins/pwa-for-wp/images/logo-512x512.png', 6 7]; 8 9const OFFLINE_CACHE_FILES = [ 10 'https://www.milar.es/blog/', 11]; 12 13const NOT_FOUND_CACHE_FILES = [ 14 'https://www.milar.es/blog/', 15]; 16 17const OFFLINE_PAGE = 'https://www.milar.es/blog/'; 18const NOT_FOUND_PAGE = 'https://www.milar.es/blog/'; 19 20const CACHE_VERSIONS = { 21 content: 'content-v' + CACHE_VERSION, 22 notFound: '404-v' + CACHE_VERSION, 23 offline: 'offline-v' + CACHE_VERSION, 24}; 25 26// Define MAX_TTL's in SECONDS for specific file extensions 27const MAX_TTL = { 28 '/': 3600, 29 html: 3600, 30 json: 86400, 31 js: 86400, 32 css: 86400, 33 png: 86400, 34 jpg: 86400, 35}; 36 37const CACHE_STRATEGY = { 38 default: 'cacheFirst', 39 css_js: 'cacheFirst', 40 images: 'cacheFirst', 41 fonts: 'cacheFirst', 42}; 43 44const CACHE_BLACKLIST = [ 45// (str) => { 46// return !str.includes('/wp-admin/') || !str.startsWith('https://www.milar.es/blog//wp-admin/'); 47// }, 48]; 49const neverCacheUrls = [/\/wp-admin/,/\/wp-login/,/preview=true/,/\/cart/,/ajax/,/login/,]; 50 51 52const SUPPORTED_METHODS = [ 53 'GET', 54]; 55// Check if current url is in the neverCacheUrls list 56function pwaForWpcheckNeverCacheList(url) { 57 if ( this.match(url) ) { 58 return false; 59 } 60 return true; 61} 62/** 63 * pwaForWpisBlackListed 64 * @param {string} url 65 * @returns {boolean} 66 */ 67function pwaForWpisBlackListed(url) { 68 return (CACHE_BLACKLIST.length > 0) ? !CACHE_BLACKLIST.filter((rule) => { 69 if(typeof rule === 'function') { 70 return !rule(url); 71 } else { 72 return false; 73 } 74 }).length : false 75} 76 77/** 78 * pwaForWpgetFileExtension 79 * @param {string} url 80 * @returns {string} 81 */ 82function pwaForWpgetFileExtension(url) { 83 84 if (typeof url === 'string') { 85 86 let split_two = url.split('?'); 87 let split_url = split_two[0]; 88 89 let extension = split_url.split('.').reverse()[0].split('?')[0]; 90 return (extension.endsWith('/')) ? '/' : extension; 91 92 }else{ 93 return null; 94 } 95} 96/** 97 * pwaForWpgetTTL 98 * @param {string} url 99 */ 100function pwaForWpgetTTL(url) { 101 if (typeof url === 'string') { 102 let extension = pwaForWpgetFileExtension(url); 103 if (typeof MAX_TTL[extension] === 'number') { 104 return MAX_TTL[extension]; 105 } else { 106 return MAX_TTL["/"]; 107 } 108 } else { 109 return MAX_TTL["/"]; 110 } 111} 112 113/** 114 * pwaForWpinstallServiceWorker 115 * @returns {Promise} 116 */ 117function pwaForWpinstallServiceWorker() { 118 return Promise.all( 119 [ 120 caches.open(CACHE_VERSIONS.content) 121 .then( 122 (cache) => { 123 124 if(BASE_CACHE_FILES.length >0){ 125 126 for (var i = 0; i < BASE_CACHE_FILES.length; i++) { 127 128 pwaForWpprecacheUrl(BASE_CACHE_FILES[i]) 129 130 } 131 132 } 133 134 //return cache.addAll(BASE_CACHE_FILES); 135 } 136 ), 137 caches.open(CACHE_VERSIONS.offline) 138 .then( 139 (cache) => { 140 return cache.addAll(OFFLINE_CACHE_FILES); 141 } 142 ), 143 caches.open(CACHE_VERSIONS.notFound) 144 .then( 145 (cache) => { 146 return cache.addAll(NOT_FOUND_CACHE_FILES); 147 } 148 ) 149 ] 150 ) 151 .then(() => { 152 return self.skipWaiting(); 153 }); 154} 155 156/** 157 * pwaForWpcleanupLegacyCache 158 * @returns {Promise} 159 */ 160function pwaForWpcleanupLegacyCache() { 161
162 let currentCaches = Object.keys(CACHE_VERSIONS) 163 .map( 164 (key) => { 165 return CACHE_VERSIONS[key]; 166 } 167 ); 168 169 return new Promise( 170 (resolve, reject) => { 171 172 caches.keys() 173 .then( 174 (keys) => { 175 return legacyKeys = keys.filter( 176 (key) => { 177 return !~currentCaches.indexOf(key); 178 } 179 ); 180 } 181 ) 182 .then( 183 (legacy) => { 184 if (legacy.length) { 185 Promise.all( 186 legacy.map( 187 (legacyKey) => { 188 return caches.delete(legacyKey) 189 } 190 ) 191 ) 192 .then( 193 () => { 194 resolve() 195 } 196 ) 197 .catch( 198 (err) => { 199 reject(err); 200 } 201 ); 202 } else { 203 resolve(); 204 } 205 } 206 ) 207 .catch( 208 () => { 209 reject(); 210 } 211 ); 212 213 } 214 ); 215} 216 217function pwaForWpprecacheUrl(url) { 218 219 if(!pwaForWpisBlackListed(url)) { 220 caches.open(CACHE_VERSIONS.content) 221 .then((cache) => { 222 cache.match(url) 223 .then((response) => { 224 if(!response) { 225 return fetch(url) 226 } else { 227 // already in cache, nothing to do. 228 return null 229 } 230 }) 231 .then((response) => { 232 if(response) { 233 fetch(url).then(dataWrappedByPromise => dataWrappedByPromise.text()) 234 .then(data => { 235 if(data){ 236 const regex = /<img[^>]+src="(https:\/\/[^">]+)"/g; 237 let m; 238 while ((m = regex.exec(data)) !== null) { 239 if (m.index === regex.lastIndex) { 240 regex.lastIndex++; 241 } 242 m.forEach((match, groupIndex) => { 243 if(groupIndex == 1){ 244 if(new URL(match).origin == location.origin){ 245 fetch(match). 246 then((imagedata) => { 247 //console.log(imagedata); 248 cache.put(match, imagedata.clone()); 249 250 }); 251 } 252 } 253 }); 254 } 255 256 257 } 258 259 260 }); 261 262 return cache.put(url, response.clone()); 263 } else { 264 return null; 265 } 266 }); 267 }) 268 } 269} 270 271var fetchRengeData = function(event){ 272 var pos = Number(/^bytes\=(\d+)\-$/g.exec(event.request.headers.get('range'))[1]); 273 console.log('Range request for', event.request.url, ', starting position:', pos); 274 event.respondWith( 275 caches.open(CACHE_VERSIONS.content) 276 .then(function(cache) { 277 return cache.match(event.request.url); 278 }).then(function(res) { 279 if (!res) { 280 return fetch(event.request) 281 .then(res => { 282 return res.arrayBuffer(); 283 }); 284 } 285 return res.arrayBuffer(); 286 }).then(function(ab) { 287 return new Response( 288 ab.slice(pos), 289 { 290 status: 206, 291 statusText: 'Partial Content', 292 headers: [ 293 // ['Content-Type', 'video/webm'], 294 ['Content-Range', 'bytes ' + pos + '-' + 295 (ab.byteLength - 1) + '/' + ab.byteLength]] 296 }); 297 })); 298} 299 300let cachingStrategy = { 301 notGetMethods: function(event){ 302 // If non-GET request, try the network first, fall back to the offline page 303 if (event.request.method !== 'GET') { 304 event.respondWith( 305 fetch(event.request) 306 .catch(error => { 307 return caches.match(offlinePage); 308 }) 309 ); 310 return false; 311 } 312 }, 313 314 fetchFromCache: function(event){ 315 /* return new Promise( 316 (resolve) => {*/ 317 return caches.open(CACHE_VERSIONS.content) 318 .then( 319 (cache) => { 320 321 return cache.match(event.request) 322 .then( 323 (response) => { 324 325 if (response) { 326 327 let headers = response.headers.entries(); 328 let date = null; 329 330 for (let pair of headers) { 331 if (pair[0] === 'date') { 332 date = new Date(pair[1]); 333 } 334 } 335 336 if (date) { 337 let age = parseInt((new Date().getTime() - date.getTime())/1000); 338 let ttl = pwaForWpgetTTL(event.request.url); 339 340 if (age > ttl) { 341 342 return new Promise( 343 (resolve) => { 344 345 return fetch(event.request.clone()) 346 .then( 347 (updatedResponse) => { 348 if (updatedResponse) { 349 cache.put(event.request, updatedResponse.clone()); 350 resolve(updatedResponse); 351 } else { 352 resolve(response) 353 } 354 } 355 ) 356 .catch( 357 () => { 358 resolve(response); 359 } 360 ); 361 362 } 363 ) 364 .catch( 365 (err) => { 366 return response; 367 } 368 ); 369 } else { 370 return response; 371 } 372 373 } else { 374 return response; 375 } 376 377 } else { 378 return null; 379 } 380 } 381 ) 382 .then( 383 (response) => { 384 if (response) { 385 return response; 386 } else { 387 return fetch(event.request.clone()) 388 .then( 389 (response) => { 390 391 if(response.status < 300) { 392 if (~SUPPORTED_METHODS.indexOf(event.request.method) && !pwaForWpisBlackListed(event.request.url)) { 393 cache.put(event.request, response.clone()); 394 } 395 return response; 396 } else { 397 return caches.open(CACHE_VERSIONS.notFound).then((cache) => { 398 return cache.match(NOT_FOUND_PAGE); 399 }) 400 } 401 } 402 ) 403 .then((response) => { 404 if(response) { 405 return response; 406 } 407 }) 408 .catch( 409 () => { 410 411 return caches.open(CACHE_VERSIONS.offline) 412 .then( 413 (offlineCache) => { 414 return offlineCache.match(OFFLINE_PAGE) 415 } 416 ) 417 418 } 419 ); 420 } 421 } 422 ) 423 .catch( 424 (error) => { 425 console.error(' Error in fetch handler:', error); 426 throw error; 427 } 428 ); 429 } 430 ) 431 /*})*/ 432 433 }, 434 fetchnetwork: function(event){ 435 return caches.open(CACHE_VERSIONS.content) 436 .then( 437 (cache) => { 438 return fetch(event.request.clone()).then(function (response) { 439 440 if(response.status < 300) { 441 if (~SUPPORTED_METHODS.indexOf(event.request.method) && !pwaForWpisBlackListed(event.request.url)) { 442 cache.put(event.request, response.clone()); 443 } 444 return response; 445 }else if(response.status==404){ 446 return cachingStrategy.Notfoundpage(); 447 } else if( cache.match(event.request) ){
448 return cache.match(event.request); 449 }else { 450 return cachingStrategy.Offlinepage(); 451 } 452 }).catch( 453 (err) => { 454 return cache.match(event.request) 455 } 456 ).catch( 457 (err) => { 458 return cachingStrategy.Offlinepage(); 459 } 460 ) 461 } 462 ).catch( 463 (err) => { 464 return cachingStrategy.Offlinepage(); 465 } 466 ) 467 }, 468 addCache: function(event,updatedResponse){ 469 cache.put(event.request, updatedResponse.clone()); 470 resolve(updatedResponse); 471 }, 472 Offlinepage: function(){ 473 return caches.open(CACHE_VERSIONS.offline).then((cache) => { 474 return cache.match(OFFLINE_PAGE); 475 }) 476 }, 477 Notfoundpage: function(){ 478 return caches.open(CACHE_VERSIONS.notFound).then((cache) => { 479 return cache.match(NOT_FOUND_PAGE); 480 }) 481 }, 482 /*Strategies*/ 483 networkOnlyStrategy: function(event){ 484 return caches.open(CACHE_VERSIONS.content) 485 .then( 486 (cache) => { 487 return fetch(event.request.clone()).then(function (response) { 488 if(response.status < 300) { 489 if (~SUPPORTED_METHODS.indexOf(event.request.method) && !pwaForWpisBlackListed(event.request.url)) { 490 cache.put(event.request, response.clone()); 491 } 492 return response; 493 }else if(response.status==404){ 494 return cachingStrategy.Notfoundpage(); 495 } else if(cache.match(event.request)){ 496 return cache.match(event.request) 497 } else { 498 return cachingStrategy.Offlinepage(); 499 } 500 }).catch( 501 (err) => { 502 return cachingStrategy.Offlinepage(); 503 } 504 ) 505 } 506 ).catch( 507 (err) => { 508 return cachingStrategy.Offlinepage() 509 } 510 ); 511 }, 512 cacheFirstStrategy: function(events){ 513 return cachingStrategy.fetchFromCache(events).catch( 514 (err) => { 515 return cachingStrategy.Offlinepage() 516 } 517 ); 518 }, 519 NeworkFirstStrategy: function(events){ 520 return cachingStrategy.fetchnetwork(events).catch( 521 (err) => { 522 return cachingStrategy.fetchFromCache(events) 523 } 524 ).catch( 525 (err) => { 526 return cachingStrategy.Offlinepage() 527 } 528 ); 529 } 530 531 532} 533 534 535self.addEventListener( 536 'install', event => { 537 event.waitUntil( 538 Promise.all([ 539 pwaForWpinstallServiceWorker(), 540 self.skipWaiting(), 541 ]) 542 ); 543 } 544); 545 546// The activate handler takes care of cleaning up old caches. 547self.addEventListener( 548 'activate', event => { 549 event.waitUntil( 550 Promise.all( 551 [ 552 pwaForWpcleanupLegacyCache(), 553 self.clients.claim(),
554 self.skipWaiting(), 555 ] 556 ) 557 .catch( 558 (err) => { 559 self.skipWaiting(); 560 } 561 ) 562 ); 563 } 564); 565self.addEventListener('online', event => { 566 if (navigator.onLine && navigator.standalone === true) { 567 isReachable(event.request.url).then(function(online) { 568 if (online) { 569 //handle online status 570 caches.delete(event.request.url); 571 console.log('online'); 572 } else { 573 console.log('no connectivity'); 574 } 575 }); 576 } else { 577 //handle offline status 578 console.log('offline'); 579 } 580}); 581function isReachable(url) { 582 /** 583 * Note: fetch() still "succeeds" for 404s on subdirectories, 584 * which is ok when only testing for domain reachability. 585 */ 586 return fetch(url, { method: 'HEAD', mode: 'no-cors' }) 587 .then(function(resp) { 588 return resp && (resp.ok || resp.type === 'opaque'); 589 }) 590 .catch(function(err) { 591 console.warn('[conn test failure]:', err); 592 }); 593} 594 595self.addEventListener( 596 'fetch', event => { 597 // Return if the current request url is in the never cache list 598 if ( ! neverCacheUrls.every(pwaForWpcheckNeverCacheList, event.request.url) ) { 599 //console.log( 'PWA ServiceWorker: URL exists in excluded list of cache.' + event.request.url); 600 return; 601 } 602 if(! neverCacheUrls.every(pwaForWpcheckNeverCacheList, event.request.referrer) ){ 603 //console.log( 'PWA ServiceWorker: Ref-URL exists in excluded list of cache.' + event.request.referrer); 604 return; 605 } 606 if(pwaForWpisBlackListed(event.request.url)){ 607 return; 608 } 609 610 // Return if request url protocal isn't http or https 611 if ( ! event.request.url.match(/^(http|https):\/\//i) ) 612 return; 613 if ( event.request.referrer.match(/^(wp-admin):\/\//i) ) 614 return; 615 616 if ( new URL(event.request.url).origin !== location.origin ) 617 return; 618 619 620 if (event.request.headers.get('range')) { 621 fetchRengeData(event); 622 } else { 623 if(event.request.method !== 'GET' ){ 624 event.respondWith( 625 fetch(event.request) 626 .catch(error => { 627 return caches.open(CACHE_VERSIONS.offline).then(function(cache) { 628 return cache.match(OFFLINE_URL); 629 }); 630 }) 631 ); 632 return false; 633 } 634 const destination = event.request.destination; 635 switch (destination) { 636 case 'style': 637 case 'script': 638 cachingStrategyType = CACHE_STRATEGY.css_js; 639 break; 640 case 'document': 641 cachingStrategyType = CACHE_STRATEGY.default 642 break; 643 case 'image': 644 cachingStrategyType = CACHE_STRATEGY.images; 645 break; 646 case 'font': 647 cachingStrategyType = CACHE_STRATEGY.fonts; 648 break; 649 // All `XMLHttpRequest` or `fetch()` calls where 650 // `Request.destination` is the empty string default value 651 default: 652 cachingStrategyType = CACHE_STRATEGY.default 653 } 654 var cache = null; 655 switch(cachingStrategyType){ 656 case "networkFirst": 657 cache = cachingStrategy.NeworkFirstStrategy(event) 658 break; 659 case "networkOnly": 660 cache = cachingStrategy.networkOnlyStrategy(event) 661 break; 662 //break; 663 case "cacheFirst": 664 case "staleWhileRevalidate": 665 default: 666 cache = cachingStrategy.cacheFirstStrategy(event) 667 break; 668 } 669 event.respondWith(cache); 670 671 } 672 673 } 674); 675 676 677self.addEventListener('message', (event) => { 678 679 if( 680 typeof event.data === 'object' && 681 typeof event.data.action === 'string' 682 ) { 683 switch(event.data.action) { 684 case 'cache' : 685 pwaForWpprecacheUrl(event.data.url); 686 break; 687 688 default : 689 console.log('Unknown action: ' + event.data.action); 690 break; 691 } 692 } 693 694}); 695 696 697
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.