I am developing a Chrome App with webviews. Pages intended for the webviews may also run in a regular browser. If inside a webview, pages send messages to the main App, but apparently they need to get a message from the App first, in order to know where to send their messages.
No problem - the main App sends a message as soon as it sees a 'loadstop' event which tells the pages where to send messages to. If a page is not in a webview then it never gets the message.
The problem is, I need to know when a page should stop waiting for the message and assume it is NOT in a webview.
When does 'loadstop' occur, relative to events in the page such as jQuery's .ready or .load? Is there a way to trap or trigger an event guaranteed to occur after 'loadstop' MIGHT be seen in the main App and a message sent and received by the webview's JavaScript.
When does 'loadstop' occur, relative to events in the page such as jQuery's .ready or .load?
According to the documentation for the loadstop event:
Fired when all frame-level loads in a guest page (including all its subframes) have completed. This includes navigation within the current document as well as subframe document-level loads, but does not include asynchronous resource loads.
This would suggest it's more akin to jQuery's .ready(), which executes after the DOM tree is loaded, but before waiting for asset (.css, .js) downloads.
Keep an eye on that documentation page; it's already much improved since two weeks ago.
Is there a way to trap or trigger an event guaranteed to occur after 'loadstop' MIGHT be seen in the main App and a message sent and received by the webview's JavaScript?
Your manifest.json declares your my-app-main.js background script (and your webview permission) which launches your my-webview-wrapper.html which includes your <webview> tag and also inlines some javascript (or sources a my-webview-wrapper.js file) that assigns event listeners to your webview via an onload function as such:
onload = function() {
webview = document.getElementById("the-id-attribute-of-my-webview");
webview.addEventListener("<EVENT>", function() {
// the cool stuff you want to do
}
}
<EVENT> can be any of the webview DOM events listed in the documentation I linked (including loadstop). Your main app shouldn't really care that any of this is happening. (It's async! It's javascript! It's magic!)
If you're still confused, just poke around Google's webview sample on GitHub.
Related
I want to make a webpage in not responding state manually. The purpose is to embed webpage inside a webview component in an electron application. so that the renderer process can know the embedded process is not responding, I wish to use the unresponsive event for the webcontents object. Can anyone help?
The Electron API Demos application has a demo section called Handling Window Crashes and Hangs making use of the Electron methods process.crash() and process.hang(), which have been specifically designed for this kind of test purposes.
You may try using process.hang() somewhere in the relevant renderer process code to simulate an unresponsive webpage...
To make a webpage unresponsive you need an infinite rendering proccess. For example putting infinite images in a webpage:
while (true){
var elem=document.getElementById("test");
var img='<img src="test">'
var data=elem.innerHTML;
elem.innerHTML=data + img;
}
<div id="test"></div>
Please note that technically the Not responding is not a state nor an event of webpage. It is a message from browser. Infinite rendering loops ends in Webpage unresponsive normally. However non-rendering script such as while(true){} also ends in errors but perhaps with different messages from browser.
I'm having some trouble with some inAppBrowser behavior in my cordova app. Here's the code:
var codePass = fooCode;
var executeScriptFunc = function(event) {
ref.executeScript({
code: codePass
}, function (value) {});
ref.removeEventListener('loadstop', executeScriptFunc);
};
var ref = cordova.InAppBrowser.open(fooObject.link, "_blank", "location=yes,enableViewportScale=yes");
ref.addEventListener('loadstop', executeScriptFunc)
The strange thing here is that the code works perfectly every time when emulated. It opens the browser and executes the script no problem. But when I try it on my actual iPhone device, it doesn't always work. The script executes maybe every other time. But it's never even that consistent.
Both the emulator and iPhone are using iOS 9.3.4. Any ideas?
If the site inside the inAppBrowser happens to be served via HTTPS, the callback for executeScript() will not work if the site employs a Content-Security-Policy HTTP response header that does not contain the gap: or gap-iab: schemes for the default-src directive. These are needed because execution of the callback function on iOS relies on an iframe that gets added to the page.
You can check whether this is the root cause for the problem by opening Safari’s Web Inspector for the inAppBrowser—it has a separate Web Inspector instance, independent of the parent application that opened it—and look out for a corresponding error message in the console. Note that you should open the console before executeScript() is run, or otherwise you might not get the error message.
Make sure also that you don't have other event handlers firing at the same time during your polling.
I had multiple pollers all firing every second and that's when I ran into the issue.
After changing the polling time so they all fired at different times, the issue went away.
This question already has answers here:
Fire Greasemonkey script on AJAX request
(2 answers)
Closed 7 years ago.
I have the following situation:
A website gets data from another html-file("news.html") which gets called every 10s or so
I want to manipulate the data from the news.html
I thought I could set up a greasemonkey script which manipulates the news.html and thus also the main website.
However this assumption was wrong: When I open the news.html in my browser, the news are manipulated (in terms of data - just to clarify this), but when I visit the main website the news don't get manipulated.
I think that greasemonkey does not work when the website is not opened "directly" in the browser, but with ajax/jQuery/....
Is there any known workaround for this?
Thanks in advance!
You can't change files that are on a server with greasemonkey unless the API for some reason leaves that exposed. Whatever you are changing is just local to you.
For simple pages, it's safest to wrap your greasemonkey scripts in at least an unload handler: According to the "Authoring" page at http://greasemonkey.mozdev.org/authoring.html,
User scripts are executed after the DOM is fully loaded, but before
onload occurs. This means that your scripts can begin immediately and
don't need to wait for onload. However, replacing large parts of the
DOM (e.g. using innerHTML or outerHTML) at this early stage of
rendering is known to cause Firefox some trouble. In this case, you'll
have more success if you call your code in response to the load event
instead:
window.addEventListener("load", function(e) {
document.innerHTML = "Hello, world!";
}, false);
However, if the "main site" is constructing itself via a secondary ajax call to news.html, that won't be enough, because the data you want to manipulate won't be in the DOM yet when your script runs on the main site. You'll need to delay your script's execution until after the main site has finished doing its thing, so that when you try to do your thing there'll be the thing there for you to do your thing to. So to speak.
Have your script observe the DOM and wait to run until after news.html has been injected into the main site, or be lazy and start it after a sufficiently-long setTimeout.
(A clarification based on discussion in comments: Greasemonkey will only act on the site that was actually loaded in the browser; it will not act directly on every XHR request that site makes, even if that url was #included in the script. So if site "foo.com" ajax-injects content from "bar.com/news.html", and the browser loaded "foo.com", greasemonkey will not directly modify the "bar.com/news.html" request foo.com made; it can only work with the DOM that foo.com constructs based on what it got from news.html.)
I am using chrome.downloads.onChanged.addListener to find out when a download completes.
The callback does not fire sometimes, and there is no apparent reason for it.
The code looks like this
chrome.downloads.onChanged.addListener(function (downloadDelta) {...});
and it is in background.js and file is mentioned in background section of manifest. I added console.log(downloadDelta); at the very begining of callback, but it is not fired.
The API is mentioned here
EDIT: Test extension
Most probably this has to do with peculiarities of Event pages - something not working properly when your page gets unloaded.
This is easy to test - remove "persistent": "false" from the manifest.
That said, your test extension does not violate any Event page recommendations and chrome.downloads API does not list any incompatibilities. Therefore, 2 scenarios are possible:
It's quite possible that you are misinterpreting results due to the page being unloaded. For instance, if the page gets unloaded between the callback executing and you opening the devtools for it - the console and all local state will be wiped.
To test for that, make sure to write your diagnostics to persistent storage - chrome.storage API is one option for this.
If you are 100% sure the above is not the case, there may be a bug related to event pages and chrome.downloads. In that case, it should be reported.
I have pages loading json into hidden iframes from javascript.
The Firefox browser seems to never acknowledge fully receiving the iframe content, and reports 'Transferring data from ...' on the status line, and shows the twirly 'busy' icon on the tab, indefinitely.
I am using jQuery to bind the 'load' handlers, and would prefer a solution that does not involve over-riding jQuery functionality.
btw, the load handler does fire, the json received is complete, and the iframe itself gets .remove()d in the cleanup code. The browser still waits for something to signal completeness.
Ben Nadel posted a blogpost on just this topic.
It seems that Firefox acknowledges that an iframe document was completely received only after the onload handler returns. If the iframe is deleted from the DOM within the handler, Firefox never detects completion. The solution Mr Nadel suggested, and which I used, is to use the javascript timer to call a deletion function to run after a brief delay. This allows the handler to return while the iframe persists, but does not let the iframe linger around.