Difference between oncached and onupdateready - html

What is the exact difference between oncached and onupdateready methods in AppCache API? It seems like both get fired when the manifest items are downloaded completely. If that's the case, which event get fired first?

The oncached event gets fired when the cache is downloaded for the first time.
The onupdateready event gets fired when the previously cached resources have been updated, typically when an update to the manifest file is detected. This does not automatically update the cache, it just downloads the new resources. The swapCache method should be called to switch the old cache with the newly downloaded one.
From this link (emphasis mine):
window.applicationCache.oncached - This eventhandler is called, after the downloading eventhandler is called, when all the resources in the manifest file have been downloaded. No more eventhandlers are called after this eventhandler.
window.applicationCache.onupdateready - This eventhandler is called, after the downloading eventhandler is called, when there has been an updated to an existing Application Cache and all the resources in the manifest file have been downloaded. No more eventhandlers are called after this eventhandler.
Event listeners for each of these events can be added as explained here.
appCache.addEventListener('cached', function(e) {
// Cache event code
}, false);
appCache.addEventListener('updateready', function (e) {
appCache.swapCache();
window.location.reload();
}, false);

Related

Chrome (open) Shadow DOM Events Not Reaching Host

I'm running Chrome 56.0.x (corporate mandate), along with Polymer 2. My sample component isn't doing anything fancy; just raising a CustomEvent after making a simple AJAX call. I'm setting "bubbles":true and "composed":true, and I can validate that the event is dispatched and that my host is listening for the event properly.
sample-component.html
raiseDataRetrievedEvent() {
this.dispatchEvent(
new CustomEvent('sample-component-data-retrieved', {
bubbles: true,
composed: true,
detail: { data: "loading complete" }
}));
}
However, the events never make it out of the Shadow DOM to my host page listeners.
index.html
// Listen to Custom event from Sample Component
document.querySelector('sample-component').addEventListener('sample-component-data-retrieved', function (e) {
alert(e.detail);
console.log(e.detail);
});
Interestingly enough, when I have a user initiated event (e.g. click) trigger this CustomEvent, it happily makes its way through the Shadow DOM to my listener. It's just the events that are programmatically created that are getting stuck.
UPDATE 1
This issue only seems to manifest itself when I'm serving my site locally (e.g. http://localhost, http://127.0.0.1, http://COMPUTERNAME). When I publish the site to another host, all the events seem to propagate as expected. Feels to me more like a Chrome issue at this point...
UPDATE 2
I put my code out on github here: https://github.com/davidfilkins/polymer-test.
I did some more testing and the results keep getting weirder... when I'm developing / testing in Chrome, I almost always have Dev Tools open. I noticed strangely enough that when my tools are open, that the event isn't captured by the host page (index.html)... but this seems to only happen locally. When I close tools and load the page locally, the events bubble properly... But this is only for the dispatched events that aren’t tied to an explicit user action; those all seem to work regardless of the tools being open or not.
When I access the simple Azure app that I created - http://samplepolymertwo.azurewebsites.net/index.html - all events are bubbled / captured regardless of whether the tools are open.
No clue if this is fixed in more current versions of Chrome or not.
The culprit was all timing...
In Chrome, with Dev Tools open, running on localhost, the event was dispatched from the component before the event listener was wired up on the host page.
Event Timing
I suppose the ideal scenario would be for the web component to wait until the event listener on the host had been wired up before broadcasting the event.

activeTab permission issue for Chrome extension

I'm running the following code in a background.js script for my Chrome extension:
chrome.browserAction.onClicked.addListener(captureCurrentTab());
function handleCapture(stream) {
console.log('content captured');
console.log("backround.js stream: ", stream);
alert(stream);
// localStream = stream; // used by RTCPeerConnection addStream();
// initialize(); // start signalling and peer connection process
}
function captureCurrentTab() {
console.log('reqeusted current tab');
chrome.tabs.query({active : true}, function(tab) {
console.log('got current tab');
chrome.tabCapture.capture({
audio : true,
video : false
}, handleCapture);
});
}
However, this gives me the following error:
Unchecked runtime.lastError while running tabCapture.capture: Extension has not been invoked for the current page (see activeTab permission). Chrome pages cannot be captured.
However, I specifically am granting activeTab permission in manifest.json:
"permissions": [
"tabs",
"tabCapture",
"activeTab",
]
Thanks for your help!
When the activeTab permission is declared, you only get access to the current tab when a user performs certain actions that imply they want you to have access.
The following user gestures enable activeTab:
Executing a browser action
Executing a page action
Executing a context menu item
Executing a keyboard shortcut from the commands API
Accepting a suggestion from the omnibox API
The error is telling you that capture the current tab because the user hasn't performed one of the actions listed above.
It looks like you might already understand this and just have an error in your code. When registering captureCurrentTab as the click listener for the browser action, you are actually executing it immediately instead of passing the function by reference. Change your first line to this:
// Remove the () after captureCurrentTab
chrome.browserAction.onClicked.addListener(captureCurrentTab);
Chrome pages cannot be captured. means that you are trying to capture a chrome://, chrome-extension://, or similar Chrome specific page which is not allowed. Make sure the current page is http:// or https://.

How to ensure that all application cache resources are downloaded?

I've been experiencing what initially appeared to be an intermittent issue where my application wouldn't work offline.
A few details regarding my application:
The entry point into my application is a Login page
All of the pages in my application, w/ the exception of the Login page, display dynamic data. And to ensure the pages that display dynamic data aren't cached, I chose to only have the Login page include the manifest attribute in it's html element.
The total size of the assets listed in my manifest file is roughly 1MB.
The steps I take to reproduce the issue (assume I do not have the applicationCache resources cached on my browser/device):
Navigate to the Login Page (applicationCache resources will begin downloading)
Immediately Login to the application
Go offline and request an offline resource
Notice the browser failed to serve the resource from applicationCache
While I do not have any concrete proof, what I ultimately discovered is navigating away from the Login page, while the browser is in the process of retrieving applicationCache assets, interrupts the download of appCache assets and leads to offline resources not being served up when offline. Is this expected browser behavior? If I wait a sufficient amount of time and give the browser a chance to download assets, offline functionality works.
In order to insure offline functionality, do I need to prevent the user from navigating away from the Login page until the applicationCache cache event is fired?
Is this expected browser behavior?
It is indeed intended behaviour. See http://diveintohtml5.info/offline.html#debugging
if even a single resource listed in your cache manifest file fails to download properly, the entire process of caching your offline web application will fail. Your browser will fire the error event, but there is no indication of what the actual problem was.
One solution I could think of would be to check on beforeunload if the the window.applicationCache.status is either checking or downloading.
Or you might be able to set a flag in the users localStorage, indicating that the last attempt was not successfull, using the error event (see below) and try to refetch the files until everything was loaded successfully.
If you've got lots of stuff to cache, you can show a progress bar and some text asking the user to be patient while the page is loading. For the progress bar you can use event.loaded and event.total in the progress event of your cache handling function.
var appCache = window.applicationCache;
// Fired after the first cache of the manifest.
appCache.addEventListener('cached', handleCacheEvent, false);
// Checking for an update. Always the first event fired in the sequence.
appCache.addEventListener('checking', handleCacheEvent, false);
// An update was found. The browser is fetching resources.
appCache.addEventListener('downloading', handleCacheEvent, false);
// The manifest returns 404 or 410, the download failed,
// or the manifest changed while the download was in progress.
appCache.addEventListener('error', handleCacheError, false);
// Fired after the first download of the manifest.
appCache.addEventListener('noupdate', handleCacheEvent, false);
// Fired if the manifest file returns a 404 or 410.
// This results in the application cache being deleted.
appCache.addEventListener('obsolete', handleCacheEvent, false);
// Fired for each resource listed in the manifest as it is being fetched.
appCache.addEventListener('progress', handleCacheEvent, false);
// Fired when the manifest resources have been newly redownloaded.
appCache.addEventListener('updateready', handleCacheEvent, false);
function handleCacheEvent(e){
if(e.type && (e.type=='progress' || e.type=='ProgressEvent')){
console.log('percent:', Math.round(e.loaded/e.total*100)+'%', 'total:', e.total, 'loaded:',e.loaded);
}
}

Access-Control-Allow-Origin error in a chrome extension

I have a chrome extension which monitors the browser in a special way, sending some data to a web-server. In the current configuration this is the localhost. So the content script contains a code like this:
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function(data)...
xhr.open('GET', url, true);
xhr.send();
where url parameter is 'http://localhost/ctrl?params' (or http://127.0.0.1/ctrl?params - it doesn't matter).
Manifest-file contains all necessary permissions for cross-site requests.
The extension works fine on most sites, but on one site I get the error:
XMLHttpRequest cannot load http://localhost/ctrl?params. Origin http://www.thissite.com is not allowed by Access-Control-Allow-Origin.
I've tried several permissions which are proposed here (*://*/*, http://*/*, and <all_urls>), but no one helped to solve the problem.
So, the question is what can be wrong with this specific site (apparently there may be another sites with similar misbehaviour, and I'd like to know the nature of this), and how to fix the error?
(tl;dr: see two possible workarounds at the end of the answer)
This is the series of events that happens, which leads to the behavior that you see:
http://www.wix.com/ begins to load
It has a <script> tag that asynchronously loads the Facebook Connect script:
(function() {
var e = document.createElement('script');
e.type = 'text/javascript';
e.src = document.location.protocol +
'//connect.facebook.net/en_US/all.js';
e.async = true;
document.getElementById('fb-root').appendChild(e);
}());
Once the HTML (but not resources, including the Facebook Connect script) of the wix.com page loads, the DOMContentLoaded event fires. Since your content script uses "run_at" : "document_end", it gets injected and run at this time.
Your content script runs the following code (as best as I can tell, it wants to do the bulk of its work after the load event fires):
window.onload = function() {
// code that eventually does the cross-origin XMLHttpRequest
};
The Facebook Connect script loads, and it has its own load event handler, which it adds with this snippet:
(function() {
var oldonload=window.onload;
window.onload=function(){
// Run new onload code
if(oldonload) {
if(typeof oldonload=='string') {
eval(oldonload);
} else {
oldonload();
}
}
};
})();
(this is the first key part) Since your script set the onload property, oldonload is your script's load handler.
Eventually, all resources are loaded, and the load event handler fires.
Facebook Connect's load handler is run, which run its own code, and then invokes oldonload. (this is the second key part) Since the page is invoking your load handler, it's not running it in your script's isolated world, but in the page's "main world". Only the script's isolated world has cross-origin XMLHttpRequest access, so the request fails.
To see a simplified test case of this, see this page (which mimics http://www.wix.com), which loads this script (which mimics Facebook Connect). I've also put up simplified versions of the content script and extension manifest.
The fact that your load handler ends up running in the "main world" is most likely a manifestation of Chrome bug 87520 (the bug has security implications, so you might not be able to see it).
There are two ways to work around this:
Instead of using "run_at" : "document_end" and a load event handler, you can use the default running time (document_idle, after the document loads) and just have your code run inline.
Instead of adding your load event handler by setting the window.onload property, use window.addEventListener('load', func). That way your event handler will not be visible to the Facebook Connect, so it'll get run in the content script's isolated world.
The access control origin issue you're seeing is likely manifest in the headers for the response (out of your control), rather than the request (under your control).
Access-Control-Allow-Origin is a policy for CORS, set in the header. Using PHP, for example, you use a set of headers like the following to enable CORS:
header('Access-Control-Allow-Origin: http://blah.com');
header('Access-Control-Allow-Credentials: true' );
header('Access-Control-Allow-Headers: Content-Type, Content-Disposition, attachment');
If sounds like that if the server is setting a specific origin in this header, then your Chrome extension is following the directive to allow cross-domain (POST?) requests from only that domain.

window.applicationCache

Using HTML5 manifest file and cache is working fine.
I use window.applicationCache.update() to download the updated version. works fine.
How can I check to see if the manifest file has been updated so an update is available but not start downloading. Reason for this I want the user to allow the update or not as they may be in a bad network connection area.
Try this:
// Check if a new cache is available on page load.
window.addEventListener('load', function(e) {
window.applicationCache.addEventListener('ondownloading', function(e) {
window.applicationCache.abort();
}, false);
}, false);
Just abort the download when you catch the ondownloading event.
You can see all the available events here
There is not an event like that.
Browser checks the update of the manifest file and download the new added files automatically. You can check current state of the cache using its status property. It may have six different values. You can see the available status properties here. Then you can use applicationCache.swapCache() for swapping according to Your/User need.