Looping Over Custom Protocol with Chrome - javascript

I'm currently looping over a custom protocol to pass information into an Electron app from the browser. This works great on every browser except Chrome. The below code runs the protocol in an iframe that then loads the data into Electron.
Code
<iframe id="dataDiv" style="width:100%;align:center;overflow-y:hidden;" frameborder="0" scrolling="no" />
url = "custom-protocol://some-data?"
for (i = 0; i < 5; i++) {
$("#dataDiv").attr("src", url + i);
}
The above code is pseudo code of how I'm trying to achieve this.
Expectation
My expectation is that it will loop 5 times, and pass the data into the Electron app. Like mentioned, this seems to only work with IE and Firefox.
Actual Results
While debugging Chrome, I find that it is only executing the first page. From the looks of it, for whatever reason, Chrome is only executing the first protocol load in the loop.
Other Attempts
I've also tried to do a timeout in the loop. Thinking that maybe it's
just triggering the protocol too fast, and Chrome doesn't like that.
That failed as well.
I've even tried just looping over javascript that creates a new tab,
instead of an iframe.. and it gives me the same result.
Does anyone know of a security setting in Chrome that would prevent custom protocols to be loaded into Chrome multiple times simultaneously?

The answer was quite simple, don't use the protocol to POST data. Instead I ended up creating a web server within electron, and passed the data off via the URL.
var http=require('http');
var url=require('url');
var server=http.createServer(function(req,res){
var pathname=url.parse(req.url).pathname;
switch(pathname){
case '/data':
var query=url.parse(req.url).query;
someFunction(query);
res.end('200 ok');
break;
}
}).listen(8080);
This way I can use AJAX to launch and hand off data to Electron, instead of iframes.
Then you just pass the data in like:
http://localhost:8080/data?{insertyourdatahere}

Related

when running testCafe some language constructs ruin the postMessage from an iFrame

So I encountered the maybe strangest thing in the last years. It took me hours to make it reproducible but still, I can not explain it at all.
I have an application that loads variable stuff in an iFrame. Then host and iFrame communicate via postMessage. The application is in use for years and there were never such problems in production or development as the one we encountered when we wanted to write e2e-tests in Testcafe. In the tests, the communication between host and client fails under certain circumstances: The iFrame sends a message with some data but the data attribute of the postMessage is undefined at the host's end. WTF.
Under what circumstances? It seems that, when certain language constructs are used in the JavaScript of the page inside the iFrame, the message gets distorted. Again: only when using Testcafe. Regardless of with Chrome, Chromium, or Firefox.
Ho to Reproduce:
Have a test.html:
<!DOCTYPE HTML>
<html>
<body>
<h1 id='output'>test</h1>
<iframe srcdoc='<!DOCTYPE html><html><body>inner<script>setTimeout(() => {window.parent.postMessage({type: `communication worked`}, `*`);}, 1500);const x = new class { y = new class {} } </script></body></html>' sandbox="allow-forms allow-scripts allow-same-origin"></iframe>
<script>
window.addEventListener('message', (event) => {
console.log({event});
document.getElementById('output').innerText = event.data.type;
});
</script>
</body>
</html>
Serve it with your favorite server. I use node with a server.js int his example, ng in the real-life application.
const connect = require('connect');
const serveStatic = require('serve-static');
var app = connect();
app.use(serveStatic(__dirname))
app.listen('8000', () => console.log('Server running on 8000...'));
And then, run the testcafe-test:
npx testcafe firefox e2e/src/test.ts
fixture`Foo`
.page`http://localhost:8080/test.html`;
test('Bar', async t => {
await t.wait(120000);
});
As you can find in the browser console the host is receiving the message from the client, but its data is empty.
Now, remove those characters y = new class {} from the srcdoc. Do the test again. Communication works, seriously WTF.
Maybe using new class inside of new class might be a strange style. If it would even be bogus somehow, how come there is no error at all? And how can it distort the postMessage without even being connected to it in any way? How does this problem only occur with Testcafe, not when you run the code by yourself or even with Protractor? I am maximum clueless.
Some Details:
In the real life the iFrame's content can contain also a more complex app, written in angular, with which the same thing happens. I am not able to say if it's the very same language construct in this case which "breaks the postMessage-system of the whole page" or a different one.
It doesn't change if the content of the src doc is not hardcoded (naturally it's not in the real-life application)
I use testcafe 1.18.2, Firefox 91.5.0, Chromium 90.0, Google Chrome, Debian 10
I am very thankful for the slightest hint!

Replacing XML DataIsland Files in asp.net

The app I am working on, currently uses XML dataisland files to retrieve the dropdown data. Below is the code that defines the file.
<xml id="DefaultDataIslands" src="../XMLData/DataIslands-<%=((User.Identity).Database)%>.xml">
</xml>
Below is an example code that uses these XML dataislands.
var oDataIsland = document.getElementById("DefaultDataIslands");
var oXmlNodes = oDataIsland.XMLDocument.selectNodes("XMLDataIslands/DataIsland[#ID='DIMRGroup']/Option");
This oDataIsland line is used about 4k times total in the application. The application itself is intranet, so, I can even ask the users to download the xml files directly. Whole point is to keep the changes required to minimum, while removing all traces of XML tags. I want to make sure that application works on Chrome once this thing is completed.
I checked the link from mozilla regarding the dataislands here. https://developer.mozilla.org/en/docs/Using_XML_Data_Islands_in_Mozilla
Below is the code based on that mozilla link.
var doc = document.getElementById(strDataSource).contentDocument;
var mainNode = doc.getElementsByTagName("DataIsland");
var oXmlNodes;
var strOptions = "";
//finds the selected node based on the id, and gets the options for that id
for (i = 0; i < mainNode.length; i++) {
if (mainNode[i].getAttributeNode("ID").nodeValue == strDataMember) {
oXmlNodes = mainNode[i].getElementsByTagName("Option");
}
}
This code reads the data properly, works perfectly in IE (10 with standards mode, no quirks), was easy enough change to do in the full solution.
Only problem is, document.getElementById(strDataSource).contentDocument; line fails in Chrome. This is the same line as what was mentioned in Mozilla's documentation. But somehow contentDocument property is undefined on chrome.
So, I need some other suggestion on how to get this fixed. I tried other methods, using HTTPRequest (too many request per page), using JSON (requires changing existing methods completely), using backend to process XML instead of doing it client side (requires architectural changes). Till now, all these ideas failed.
Is there any other method that I can use? Or should I fix the contentDocument issue?
To allow contentDocument in Chrome, you will have to use --allow-file-access-from-files. Following are the steps for doing so:
Get the url of your Chrome Installation path to your chrome
installation e.g
C:\Users-your-user-name\AppData\Local\Google\Chrome\Application>
Launch the Google Chrome browser from the command line window with
the additional argument ‘–allow-file-access-from-files’. E.g ‘path
to your chrome installation\chrome.exe
--allow-file-access-from-files’
Temporary method you can use each time you are testing
Copy the existing chrome launcher
Do as above and save it with a new name e.g chrome - testing
Alternatively, you can simply create a new launcher with the above and use it to start chrome.
Source

Force (or ask nicely) to refresh the browser

So I run a site that uses a lot of javascript and ajax. I understand how to make users refresh their browser when the browser loads. But what happens if I need them to refresh their browser after they have loaded the site?
I want to change the ajax that is served to the client to speed up things up, but this is going to cause errors for the users who have not yet refreshed their browser.
The only solution I can come up with is that when a new version of the JavaScript file is required, the site uses a popup that asks the users to force refresh their browsers. (This won't really fix the current version, but would prevent future issues.)
I hate to use a popup for something that I could do automatically. Is there a better way to force updates for the client?
window.location.href = "http://example.com"
replaces the current page with the one pointed to by http://example.com.
You sound like you are having trouble with your JavaScript getting an updated version of the data it loads through Ajax methods, is that correct? For instance, if two Ajax calls try to load 'data.txt', then the second call merely uses the cached version.
You also may be having trouble with loading new versions your script itself.
The way around both of these problems is to add a randomly-generated query string to your script source and your Ajax source.
For example, make one script that loads your main script, like this:
/* loader1.js */
document.write('<script src="mainjavascript.js?.rand=', Math.random(), '"></script>');
And in your HTML, just do
<script src="loader1.js"></script>
The same method works for JavaScript Ajax requests as well. Assuming that "client" is a new XMLHttpRequest() object, and has been properly set up with a readystatechange function and so on, then the you simply append the same query string, like this:
request = client.open('GET', 'data.txt?.rand=' + Math.random(), true);
request.send();
You may be using a library to do your Ajax requests, and so it's even easier then. Just specify the data URL as 'data.txt?.rand=' + Math.random() instead of merely 'data.txt'

Embed PDF in page and print - IE9 issues

I have some code which dynamically loads a PDF document into a web page by setting a container's innerHTML to the returned string of this function:
function getPdfString(url) {
return '<object data="' + url + '" type="application/pdf" classid="clsid:ca8a9780-280d-11cf-a24d-444553540000" style="width:100%;height:600px"></object>';
}
In IE with the Adobe Reader plugin installed (as determined by the code that detects the Adobe ActiveX at PDFObject), my code inserts this HTML into a hidden container, puts a reference to the object element into el, and then runs this code (Repeater is a custom class):
log("** start repeater **");
var r = _repeater = new Repeater(function() {
try {
var delta = timeInterval();
log("iteration - " + delta + "ms");
el.gotoFirstPage(); //throws exceptions until the PDF is loaded
log("** assuming success, stop **");
r.stop();
r = undefined;
setTimeout(function() {
el.print(); //should succeed, can't tell because it doesn't throw or return anything
}, 100);
} catch(e) { }
}, 0, 100);
This is very convoluted, but necessary because there's no way to tell when the PDF is loaded, nor whether or not el.print() succeeded. It took me a long time to figure out, but it seems to work well in IE7 and IE8. IE9 has been hit and miss, usually working on my local machine (which runs IIS7.5), but sometimes not. IE9 has never worked when the site is running on my test server, which runs IIS6 out of necessity. I don't know if the version of IIS that I am running is causing my issue, but judging from the Fiddler logs, I doubt it.
I have been poring over Fiddler, making small tweaks here and there to see if anything makes a difference. So far, nothing has. The only difference that I can see is the Server header.
I found that the classid attribute is needed by IE7 and IE8; otherwise, they will make multiple requests for the PDF, and often fail to load it. It also significantly improves IE9's caching behavior.
The PDF is slightly different each time it is acquired. I'm not currently saving it to a temporary file or anything, though I could if it is absolutely necessary (so I could re-send the same PDF in a subsequent request).
The response is being gzip encoded, but I have the same problem whether it is enabled or not.
I have noticed that when the problem occurs, terminating AcroRd32.exe sometimes fixes the issue temporarily.
Side note: Firefox and Opera use the same HTML in an in-page popup which embeds the PDF. This works perfectly fine. (The Adobe Reader NPAPI plugin doesn't have a print() method on it that I have been able to find, sadly, so the popup instructs users to click the embedded view's Print button)
Nothing is stopping me from trying other methods of embedding such as an iframe, but I had some weird issues with it when I first tried it (can't remember what they were now, after all this mess).
I think that's everything I know about the problem right now...
This seems to be a problem specifically with Adobe Reader and the IE plugin. I've found a few forum threads that indicate this is a common, reproducible error (http://forums.adobe.com/thread/758489).
The solution seems to be using an iFrame over an <object>/<embed> tag.

Accessing and modifying tabs opened using window.open in Google Chrome

I used to be able to do this to create an exported HTML page containing some data. But the code is not working with the latest version of Google Chrome (It works all right with Chrome 5.0.307.11 beta and all other major browsers).
function createExport(text) {
var target = window.open();
target.title = 'Memonaut - Exported View';
target.document.open();
target.document.write(text);
target.document.close();
}
Chrome now complains that the domains don't match and disallows the JavaScript calls as unsafe. How can I access and modify the document of a newly opened browser-tab in such a scenario?
I also got this problem when using a local page using the file:// protocol (in Chromium 5.0.342.9 (Developer Build 43360) under Linux). The exact error message is:
Unsafe JavaScript attempt to access
frame with URL about:blank from frame
with URL
file:///home/foo/bar/index.htm.
Domains, protocols and ports must
match.
Apparently the protocols don't match, but the good news is: when this page on a web server, Chromium also opens a new window as "about:blank", but it doesn't complain any longer. It also works when using a local web server accessed via http://localhost.
EDIT: there is bug filed upstream about this. According to this comment, it is fixed and it will be rolled into trunk shortly.
UPDATE: this bug is now fixed, the following test case works properly:
var target = window.open();
target.title = 'Memonaut - Exported View';
target.document.open();
target.document.write("test");
target.document.close();
Here is the explanation I think
http://groups.google.com/group/chromium-dev/browse_thread/thread/9844b1823037d297?pli=1
Are you accessing any data from other domain? Not sure, but that might be causing this problem.
One alternative would be a data: protocol URL.
https://developer.mozilla.org/en/data_URIs
http://msdn.microsoft.com/en-us/library/cc848897%28VS.85%29.aspx
var durl = "data:text/html," + encodeURIComponent(text);
var target = window.open(durl);
Supported in all modern browsers except IE7 and below.
you can also try closing self tab/window by using this code,
originally I've made this small greasemonkey script sometime ago in order to close
bad popups and ad windows, it worked fair (not too brilliant though)...
//window.addEventListener("load", function () {
window.addEventListener("onbeforeunload", function () {
try {
// clear inner html content to prevent malicious JS overrides.
document.getElementsByTagName("html")[0].innerHTML = "";
window.open("javascript:window.close();", "_self", "");
window.open("javascript:window.close();", "_self", "");
}
catch (e) {}
}(), false);

Categories

Resources