Detect print events from iFrame - javascript

I am trying to build a print solution which programmatically prints PDF documents using URLs and fire an event after printing.
I am using the "matchMedia" event listener below to test with Chrome (v54). For IE and Firefox, I plan to listen to the "onbeforeprint" and "onafterprint" of the same iframe contentWindow object.
Here is how I invoke the print. The dojo function is just an xhr wrapper.
dojoRequest(url, {
handleAs: 'blob'
}).then(function (blob) {
var src = URL.createObjectURL(blob);
printFrame = document.createElement('iframe');
printFrame.id = 'print-frame';
// printFrame.style.display = 'none';
printFrame.src = src;
document.body.appendChild(printFrame);
var mediaQueryList = printFrame.contentWindow.matchMedia('print');
mediaQueryList.addListener(function (mql) {
console.log('print event', mql);
debugger;
});
setTimeout(function () {
printFrame.contentWindow.print();
}, 0);
});
This works well except that the "print event" event never fires. I would expect it to fire once when showing the "print preview" window and again after clicking the "print" button.
I tried registering the same event listener against the main "window" object. It fires when initiating a print manually (from the File menu), but not when initiating the print programmatically using the method described above.

To get events, you must wrap your code inside of onload of iframe, like this:
printFrame.onload = function () {
var mediaQueryList = printFrame.contentWindow.matchMedia('print');
mediaQueryList.addListener(function (mql) {
console.log('print event', mql);
});
setTimeout(function () {
printFrame.contentWindow.print();
}, 0);
};
However, I still think that this approach is really complex and not stable enough for enterprise application.
UPDATE:
Jsfiddle link showing it works on Chrome 54: https://jsfiddle.net/anhhnt/nj851e52/

Related

javascript iframe set timer and check if loaded

I need to trigger a url validation check onclick of the url before loading the page. If the url is not valid or cannot be reached I need to display an alert.
When I use i.onload it keeps waiting for it to load. If it never loads it also never produces an error to be caught by i.onerror. If the link loads properly everything works well.
html:
<a id={UrlToTest} onClick={this.testUrl}>{UrlToTest}</a>
javascript:
testURL(e) {
var targetURL = e.target.id;
var i = document.createElement('iframe');
i.style.display = 'none';
i.src = targetURL;
document.body.appendChild(i);
i.onload = function() {
//setTimeout(function(){
i.parentNode.removeChild(i);
return window.open(targetURL, '_blank');
//}, 5000);
};
i.onerror = function(){
alert('The link didn"t load');
};
}
If I insert console.log's it remains waiting for onload to trigger. If I allow the link to open without testing in a hidden iframe it will display 'unable to connect' immediately, or 404 error, etc. This error is never received when checked within the iframe.
Welcome to Stack Overflow :)
I believe your issue is that you set your onload and onerror after you set the src.
Think of it this way - your browser is trying to load (or error) the iframe as soon as possible, once the src is set, the browser starts his work, if an error (or success) is thrown before the onload was set, there's nothing to catch it.
TLDR - I think that switching the order (setting onload and onerror first) should resolve your problem.
Edit --
So I misunderstood the question, yes there are situations where nothing comes back from the iframe, specifically I could reproduce that with this code on the console here in stack overflow:
var targetURL = 'localhost:1'
var i = document.createElement('iframe');
i.onload = function() {
alert('The link did load');
};
i.onerror = function(){
alert('The link did NOT load');
};
i.src = targetURL;
document.body.appendChild(i);
the above code will not fire any event.
I'm not aware of why this is exactly happening, but maybe you should use a setTimeout timer to timeout the whole operation
let timer = setTimeout(() => {
alert('Error opening page');
}, 5000);
var targetURL = 'localhost:1'
var i = document.createElement('iframe');
i.onload = function() {
alert('The link did load');
clearTimeout(timer);
};
i.onerror = function(){
alert('The link did NOT load');
clearTimeout(timer);
};
i.src = targetURL;
document.body.appendChild(i);
I dug a bit deeper, turns out there's a bug for Chrome on this matter
https://bugs.chromium.org/p/chromium/issues/detail?id=365457
Unfortunately it seems that 'this is the spec', from the bug report:
I have discussed this with Adam Barth, and we have confirmed that the
behaviour described here is the behaviour described in the Living HTML
specification.
As follows: The specification requires that all HTML elements support
on onerror event. However, it does NOT require that all elements
supporting network fetches raise fire a simple event called onerror.
That is, elements must support allowing applications to set error
handlers, but there is no (generic) requirement that the event be
raised, in either HTML or the Fetch specification.

Adding Tab on Window Load for Firefox Extension

I want to add a tab whenever a new Firefox window is loaded for my bootstrap extension. I use this code listing:
var WindowListener = {
setupBrowserUI: function(window) {
window.gBrowser.selectedTab=window.gBrowser.addTab("http://google.com");
},
tearDownBrowserUI: function(window) {
},
// nsIWindowMediatorListener functions
onOpenWindow: function(xulWindow) {
var domWindow = xulWindow.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
// Wait for it to finish loading
domWindow.addEventListener("load", function listener() {
domWindow.removeEventListener("load", listener, false);
// If this is a browser window then setup its UI
if (domWindow.document.documentElement.getAttribute("windowtype")=="navigator:browser") domWindow.gBrowser.selectedTab=domWindow.gBrowser.addTab("http://google.com");
}, false);
},
onCloseWindow: function(xulWindow) {
},
onWindowTitleChange: function(xulWindow, newTitle) {
}
};
let wm = Components.classes["#mozilla.org/appshell/window-mediator;1"].
getService(Components.interfaces.nsIWindowMediator);
// Wait for any new browser windows to open
wm.addListener(WindowListener);
You can try it in Scratchpad.
onOpenWindow method have the code to open tab in new window but it executes before the window is loaded completely so adding tab in this state does not seem to work although MDN code says "Wait for it to finish loading".
Setting a timeout by setTimeout function does the job but it looks ugly.
domWindow.setTimeout(function(){domWindow.gBrowser.selectedTab=domWindow.gBrowser.addTab("http://google.com");},1000);
Is it possible to add tab for new Firefox windows after window completely is loaded without setTimeouts?
I'd go with a setTimeout(..., 0) hack. That ought to be the most reliable option and is used throughout the Firefox code itself :p
if (domWindow.gBrowser) {
setTimeout(function() {
domWindow.gBrowser.selectedTab =
domWindow.gBrowser.addTab("http://google.com");
}, 0);
}
It's really weird. I can't explain it. But from the line:
if (domWindow.document.documentElement.getAttribute("windowtype")=="navigator:browser") domWindow.gBrowser.selectedTab=domWindow.gBrowser.addTab("http://google.com");
remove the domWindow.gBrowser.selectedTab = so change it to:
if (domWindow.document.documentElement.getAttribute("windowtype")=="navigator:browser") {
domWindow.gBrowser.addTab("http://google.com");
}
this succesfully loads the url BUT it doesnt select the tab SO I tried and absolutely new idea why this stuff FAILED:
if (domWindow.document.documentElement.getAttribute("windowtype")=="navigator:browser") {
var tab = domWindow.gBrowser.addTab("http://google.com");
}
as soon as i put that var tab = in front it fails. If it didn't fail i was planning to put on next line: domWindow.gBrowser.selectedTab = tab
THEN this also fails:
loadOneTab has inBackground parameter, if set it to false it will focus the tab:
if (domWindow.document.documentElement.getAttribute("windowtype")=="navigator:browser") {
domWindow.gBrowser.loadOneTab("http://google.com", {inBackground:false});
}
Absolutely no idea but this fails to load url but it focuses the tab. If you set inBackground to true it loads the url and of course it wont focus the tab. Absolutely weird...
Posted so others can maybe find out where the problem is, maybe we need to report something on bugzilla.

onload event listener called many times when loading just one page in Firefox extension

I wrote a program to capture browser side implicit indicators using Javascript and PHP. The program is working very well as a standalone on a single index page. I tried adding it as an extension in Firefox so that users can access it remotely and to capture all URL visited. As I added it, I discovered that it fires whenever a single file (such as html, jpg, css, js) has loaded thereby given me multiple loads. Please How can I make the associated files fire at the same time like a single file? Below is the code section:
var linkTargetFinder = function () {
var prefManager = Components.classes["#mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
return {
selectedTab: null,
init: function () {
gBrowser.addEventListener("load", function (e) {
linkTargetFinder.run(e);
}, false);
},
run: function (e) {
var doc = e.originalTarget;
doc.defaultView.addEventListener("unload", function (e) {
alert('Unloading tab');
linkTargetFinder.setCloseEvent();
}, false);
},
}
}();
window.addEventListener("load", linkTargetFinder.init, false);

XMLHttpRequest from Firefox Extension

I'm using XMLHttpRequest to exchange data between server and Firefox extension I'm developing. Unfortunately, those requests seem somehow connected with the currently open page - if I try to issue request while the current tab is closing, it will fail with an error. How can I make my requests originate from the extension itself, independently of what's going on in tabs?
EDIT: Here is the code that reproduces this problem. It's run as the main extension body (I based my design on the "Hello world" tutorial from http://kb.mozillazine.org/Getting_started_with_extension_development, so no Add-on SDK). This means that it's executed in the same place as the code from "overlay.js" in above tutorial.
function createXMLHttpRequest() {
return Components.classes["#mozilla.org/xmlextras/xmlhttprequest;1"]
.createInstance(Components.interfaces.nsIXMLHttpRequest);
}
function issueRequest() {
var req = createXMLHttpRequest();
req.open("GET", "http://google.com", true);
req.addEventListener("load", function(event) {
alert("SUCCES");
});
req.addEventListener("error", function(event) {
alert("ERROR");
});
req.send();
};
window.addEventListener("DOMContentLoaded", function(event) {
issueRequest();
var doc = event.originalTarget;
var win = doc.defaultView;
win.addEventListener("unload", function(event) {
issueRequest();
});
});
This results in "SUCCESS" after opening of new tab, and "ERROR" after closing it. I would prefer to have two SUCCESSES.
If that script is running in a browser window overlay then you attached your DOMContentLoaded handler to the wrong node - you will only get notified when the browser window itself loads. Consequently, your unload handler waits for the browser window to the closed, you probably intended to wait for a tab to be closed. The correct code would look like this:
// Wait for the browser window to load before doing anything
window.addEventListener("load", function() {
// Attach a listener to the tabbrowser to get notified about new pages
window.gBrowser.addEventListener("DOMContentLoaded", function(event) {
issueRequest();
var doc = event.originalTarget;
var win = doc.defaultView;
win.addEventListener("unload", function(event) {
issueRequest();
});
}, false);
}, false)

Detect page load completed event in Firefox

I'm writing a Firefox add-on that do something after the webpage is completely loaded.My current code is
var target = this;
const STATE_STOP = Components.interfaces.nsIWebProgressListener.STATE_STOP;
const STATE_IS_WINDOW = Components.interfaces.nsIWebProgressListener.STATE_IS_WINDOW;
const STATE_IS_DOCUMENT = Components.interfaces.nsIWebProgressListener.STATE_IS_DOCUMENT;
const locationChangeListener = {
onStatusChange: function(){},
onProgressChange: function(){},
onLocationChange: function(aWebProgress, aRequest, aLocation){},
onStateChange: function(aWebProgress, aRequest, aFlag, aStatus){
if((aFlag & STATE_STOP) && (aFlag & STATE_IS_WINDOW)){
//Do something in here
}
},
onSecurityChange: function(){}
};
gBrowser.addProgressListener(locationChangeListener);
It works fine. But sometimes, for example webpage with AJAX call, this event fired several times for one web page.
Is there any way to detect if the webpage is completely loaded or not?
If you are only interested in detecting when the page has completely loaded and not the intermediary steps it is easier to listen for load events, with something like (code from https://developer.mozilla.org/en/Code_snippets/Tabbed_browser):
function examplePageLoad(event) {
if (event.originalTarget instanceof HTMLDocument) {
var win = event.originalTarget.defaultView;
if (win.frameElement) {
// Frame within a tab was loaded. win should be the top window of
// the frameset. If you don't want do anything when frames/iframes
// are loaded in this web page, uncomment the following line:
// return;
// Find the root document:
win = win.top;
}
}
}
// do not try to add a callback until the browser window has
// been initialised. We add a callback to the tabbed browser
// when the browser's window gets loaded.
window.addEventListener("load", function () {
// Add a callback to be run every time a document loads.
// note that this includes frames/iframes within the document
gBrowser.addEventListener("load", examplePageLoad, true);
}, false);
...
// When no longer needed
gBrowser.removeEventListener("load", examplePageLoad, true);
...
gBrowser is a global var in the main firefox window (if your code is running from an overlay of browser.xul you should see it). If not (running in a sidebar for example), you can get a reference to the main window:
var mainWindow = window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIWebNavigation)
.QueryInterface(Components.interfaces.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindow);
mainWindow.gBrowser.addEventListener (...)

Categories

Resources