I would like to print a PDF in the browser, which was generated by my ASP.NET Core application. I have already tested countless articles and recommendations, but unfortunately there is no universal solution for all browsers.
Solutions like printing from an iframe doesn't work on iPadOS/iOS - for a document with multiple pages it prints only the first page (and the page is scaled incorrectly). The embed is not working anymore.
Print.js looks like that it is not maintained anymore and the owner has no activity on his account in the last year. Based on the issues on project, there are lot of bugs for mobile devices, which were not fixed anymore.
PDF.js from mozilla is also not working with the legacy version on iPadOS/iOS. Testing with the demo page has shown, that the printing often gets stuck. As mentioned in this ticket, the primary target is Firefox - they will not care much about issues on safari).
The only solution I can think of would be to print on desktop devices using an iframe and display the PDF on mobile devices, leaving it to the user to print it themselves. However, on iPadOS in particular, the default setting is "Request Desktop website" and Safari shows as macOS. So it is not possible to determine from the user agent whether it is an iPadOS.
Has anyone a solution for this?
<html>
<head>
<title>Print PDF using Dynamic iFrame</title>
</head>
<body>
<input type="button" id="bt"
onclick="print('../sample.pdf')"
value="Print PDF" />
</body>
<script>
let print = (doc) => {
let objFra = document.createElement('iframe'); // Create an IFrame.
objFra.style.visibility = 'hidden'; // Hide the frame.
objFra.src = doc; // Set source.
document.body.appendChild(objFra); // Add the frame to the web page.
objFra.contentWindow.focus(); // Set focus.
objFra.contentWindow.print(); // Print it.
}
// Using regular js features.
// function print(doc) {
// var objFra = document.createElement('iframe');
// objFra.style.visibility = 'hidden';
// objFra.src = doc;
// document.body.appendChild(objFra);
// objFra.contentWindow.focus();
// objFra.contentWindow.print();
// }
</script>
</html>
Related
I am trying to find a way to count a number of tabs that are currently open in Chrome by javascript.
I have searched and found chrome.tabs.query(). But when I opened my console and tried it I got an undefined message.
Is it not supported anymore by Chrome, or can it only be used in extension development?
As wscourge has implied, chrome.tabs.query() is a Chrome extension API, which is only available to extensions, not web page JavaScript. In fact, it is only available in the background context of an extension (i.e. not content scripts).
To find the number of tabs that are open, you could do something like:
chrome.tabs.query({windowType:'normal'}, function(tabs) {
console.log('Number of open tabs in all normal browser windows:',tabs.length);
});
If you want to run this from a console, you will need to have an extension loaded that has a background page. You will then need to open the console for the background page. From that console, you can execute the above code.
I found the answer to this question here: https://superuser.com/questions/967064/how-to-get-tab-count-in-chrome-desktop-without-app-extension
Go to chrome://inspect/#pages
Run the following line of code in the javascript console:
document.getElementById("pages-list").childElementCount
The tabs count will be printed to the console.
Local and Session storage
In case when we want count only tabs witch our website - first on page load (open tab) event we generate tab hash and we save it in sessionStorage (not shared between tabs) and as key in TabsOpen object in localStorage (which is shared between tabs). Then in event page unload (close tab) we remove current tab hash (saved in sesionStorage) from TabsOpen in localStorage.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>My project</title>
...
<script>
function tabLoadEventHandler() {
let hash = 'tab_' + +new Date();
sessionStorage.setItem('TabHash',hash);
let tabs = JSON.parse(localStorage.getItem('TabsOpen')||'{}');
tabs[hash]=true;
localStorage.setItem('TabsOpen',JSON.stringify(tabs));
}
function tabUnloadEventHandler() {
let hash= sessionStorage.getItem('TabHash');
let tabs = JSON.parse(localStorage.getItem('TabsOpen')||'{}');
delete tabs[hash];
localStorage.setItem('TabsOpen',JSON.stringify(tabs));
}
</script>
...
</head>
<body onunload="tabUnloadEventHandler()" onload="tabLoadEventHandler()">
...
</body>
</html>
Thanks to this in TabsOpen object in localStorage we have information about current open tabs which can be read by
let tabsCount = Object.keys( JSON.parse(localStorage.getItem('TabsOpen')||'{}') ).length
It can only be used in extension development.
You are not able to access that information from document level.
This is not a solution using javascript, but maybe it can help double-check the count against another solution. It is by far the easiest (one-click) solution that works for me:
If you have chrome sync enabled, simply navigate to chrome.google.com/sync
It should give you the count of open tabs, among other counts (e.g. bookmarks, extensions, etc)
window.onerror=function(err,url,line){
if(err=='boom'){
console.log(true);
}
else{
console.log(false);
}};
console.error('boom');
This outputs undefined!
How can I tell in the java-script what text the error contains?
I'm trying to detect google chrome cast extension error
Failed to load resource: net::ERR_ADDRESS_UNREACHABLE chrome-extension://boadgeojelhgndaghljhdicfkmllpafd/cast_sender.js
related: Google chrome cast sender error if chrome cast extension is not installed or using incognito
My reasoning is
//tried to detect chromecast extension id: boadgeojelhgndaghljhdicfkmllpafd
//it looks like it is protected from detection (tried: http://blog.kotowicz.net/2012/02/intro-to-chrome-addons-hacking.html)
//if they are using:
//chrome flash ===flash (needs double click as &autoplay=1 lets the user do only one click but it side-effects with no video preview)
//chrome chromeCast===fastjs (google are being bad players here!)
//chrome ===slowjs (almost unusable website)
//chrome flash chromeCast===flash ffsake! (maybe try one video then see if there are errors and put a cookie, chromecast=true means that we got no errors so we don't need flash!) todo:how to analyse error text?
//if the user is on chrome and does not have flash then they are youtubes 'exception'! they will have very crap loading times
var chrome=0;
if(/Chrome/.test(navigator.userAgent)&&/Google Inc/.test(navigator.vendor)){
chrome=1;
function detectPlugin(substrs){
if(navigator.plugins){
for(var i=0,l=navigator.plugins.length;i<l;i++){
var plugin=navigator.plugins[i]
, haystack=plugin.name+plugin.description
, found=0;
for(var j=0;j<substrs.length;j++){
if(haystack.indexOf(substrs[j])!=-1){found++;}
}
if(found==substrs.length){return true;}
}}
return false;
}
var detectFlash=[/*"Shockwave",*/"Flash"]; //not entirely sure how relevant shockwave is here
if(detectPlugin(detectFlash)){chrome=2;}
}
then I create an iframe with:
'https://www.youtube.com/'+(chrome==2?'v':'embed')+'/'+ytvidcode
where ytvidcode is the id of the youtube video
v is for the depreciated flash embed while embed is for the html5 (broken/wont fix) embed
So the above code will detect chrome then will attempt to detect flash but cannot detect chrome-cast.
If the user has both chrome-cast and flash then (as it cannot detect chrome-cast/chrome-cast errors) it will force flash if present.
If flash is not present then the user will have a crappy youtube embed experience (they might have to use another browser)
Is it possible to detect the errors made by chrome-cast or any other footprint of its presence?
because if it is an installed extension then it should be fully utilized as flash is depreciated
window.onerror=function(e,url,line){console.dir(arguments);}//nope
window.onerror=function(e,url,line){console.dir(this);}//nope
https://github.com/Valve/fingerprintjs2
new Fingerprint2().get(function(result, components){
console.log(result); //a hash, representing your device fingerprint
console.log(components); // an array of FP components
});
components[13] ("regular_plugins") shows no Google cast even though I have installed it today
The only thing I can think of at this point is to time the loading of one of their videos (if they are on chome and it takes too long to load the test video then they must not have chrome cast), using this https://developers.google.com/youtube/iframe_api_reference#Getting_Started and a timer and a cookie after (so the test only happens once)... I will test this then perhaps report back
This lets the videos use embed if non chrome or if they are on chrome with cast extension enabled.
If they are on chrome without cast then it checks for flash and if they support flash then it uses v.
If they have chrome without ether cast or flash then (they will just get the chrome cast errors, it's their fault at that point!)
v is for the depreciated flash embed while embed is for the html5 (broken/wont fix) embed.
Could do with improvements maybe...
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="//www.gstatic.com/cv/js/sender/v1/cast_sender.js"></script>
<script type="text/javascript">
function proceed(how){
document.getElementById('vid').innerHTML='<iframe src="https://www.youtube.com/'+how+'/M_lHI1opADk"></iframe>';
console.log(ischrome,iscast);
}
var ytv=['embed','v','embed','v'];
var ischrome=0;
var iscast=true;//maybe
if(/Chrome/.test(navigator.userAgent)&&/Google Inc/.test(navigator.vendor)){
ischrome=1;
setTimeout(function(){
try{new chrome.cast.SessionRequest('794B7BBF');}
catch(e){console.log(e);
iscast=false;}
finally{
(iscast==true)&&(ischrome=2);
if(ischrome==1){
function hasflash(){if(navigator.plugins){for(var i=0,l=navigator.plugins.length;i<l;i++){if((navigator.plugins[i].name+navigator.plugins[i].description).indexOf("Flash")!=-1){return true;}}}return false;}
if(hasflash()){ischrome=3;}
proceed(ytv[ischrome]);
}
else{
proceed(ytv[ischrome]);
}}},1000);}
else{proceed(ytv[ischrome]);}
</script>
</head>
<body>
<div id="vid"></div>
</body>
</html>
You can test this by installing the cast extension disabling/enabling and refreshing the page.
I've recently created a separate mobile skin for a website. The site serves the mobile version of a page based on the screen size of the device it is being viewed on using the following code.
<script type="text/javascript">
if (screen.width <= 600) {
window.location = "mobile/";
}
</script>
I'd now like to add a "view desktop version" link at the bottom of the page. Naturally, with the above code in the header of each page, it just detects the screen size again and loops back.
Could someone please suggest how I could get around this. I suspect this will be a session or a cookie but I'm very new to java and don't know how to set these up.
thanks in advance for any advice.
This should be handled by the viewport in the metatag of your website. The use of jquery can allow users to opt out of responsive design:
var targetWidth = 980;
$('#view-full').bind('click', function(){
$('meta[name="viewport"]').attr('content', 'width=' + targetWidth);
});
See this link for more clarification.
To detect if link was clicked you can:
Add a specific query parameter (like ?forceDesktop=true) which should be removed if returned to mobile
Use media queries and single skin (see bootstrap)
Maybe look for more elaborate version to detect mobile (link)
Chrome for Android has option to request desktop site (How to request desktop
I've managed to come up with another solution using local storage which is really simple for a beginner like me. It's probably an amateurish way of doing things but it certainly works for my purposes.
So updated the code on the desktop version of the site to:
var GetDesk = 0;
var GetDesk = localStorage.getItem('GetDesk');
//check screen size is less than 600
if (screen.width <= 600) {
//check if there's anything in local storage showing the users requested the desktop
if (GetDesk == 0 ) {
window.location = "/mobile.html";
}
}
then added code to the mobile version of the site to check if the user has previously requested the desktop version:
var GetDesk = localStorage.getItem('GetDesk');
if (GetDesk == 1 ) {
window.location = "/desktop.html";
}
Then at the bottom of the mobile version added the button:
<!-- onclick set the value of GetDesk to 1 and redirect user to desktop site -->
<button onclick="localStorage.setItem('GetDesk','1'); window.location.href = '/desktop.html';">View desktop</button>
As I say, perhaps not the best way but it certainly works and is easy for beginners.
I have am using html2canvas to enable screenshots of divs within my web application. It's working well enough in Chrome (including Android), Safari (including iOS) and FireFox. In IE 11, however the image won't save.
Code looks like this:
function displayModalWithImage(canvas, filename) {
var modalcontainer = $('#snapshot');
var modalcontainer_body = modalcontainer.children().find('.snap_shot_container');
var modalcontainer_save = modalcontainer.children().find('.save_snapshot');
var image = new Image();
var data = canvas.toDataURL("image/png");
image.src = data;
modalcontainer_save.attr('download', filename +".png");
modalcontainer_save.attr('href',
data.replace(/^data[:]image\/png[;]/i, "data:application/octet-stream;"));
$(modalcontainer_body).html('');
$(image).appendTo(modalcontainer_body);
$(modalcontainer_save).on('click', function() {
modalcontainer.modal('hide');
});
modalcontainer.modal();
}
Browser behavior varies:
Chrome: displays modal and then saves the file when "Save" is clicked. (acceptable)
Firefox: displays modal and then displays a separate dialog when "Save" is clicked (acceptable)
Safari: display modal and then loads image in a separate tab when "Save" is clicked (acceptable... maybe)
IE 11: displays modal, but does nothing but hide the dialog when "Save" is clicked (unacceptable)
The data.replace was suggested by another SO answer, but it did not appear to have any effect on the behavior of any of the browsers. Previously the href attribute was simply set to data.
So, anyway, at this point replacing the modal dialog with a simple window.location = data is a viable alternative. But, since Chrome works well and Safari and FF work well enough, i'd like to simply do a feature detection that would window.location for IE but show the modal for the other browsers. But, I don't know what "feature" is missing in IE to check for.
tl;dr
is there simply a change or bug in my javascript that would enable IE to work (save the image encoded as data to a file).
if not, which feature in IE should I detect for that would enable me to customize the behavior for IE
if that's not an option; what's the current best practices for old-fashioned browser detection?
I have tried to load (embed) the .doc file into the html page using object tag. And it doesn't show the word toolbar. My requirement is to allow the user to print the doc from print option in word.
Is there a possible way in javascript to enable the word toolbars??
And I have tried another approach using the ActiveXObject.. but this method opens the document in winword.exe.. is there a way to embed the .doc file through javascript..?
EDIT:
I was looking for other possibilities, but nothing works
Anybody got an idea about the list of params available for the Word ActiveX?
Maybe that could contain the property to enable toolbars on load..
I used the below code to load .doc content to ActiveX Word Document control
var objWord = new ActiveXObject("Word.Application");
objWord.Visible=false;
var Doc=new ActiveXObject("Word.Document");
Doc=objWord.Documents.Add("c:\\test.doc", true);
Is there a way to render the DOC element directly into HTML.. like putting this element in iframe or whatever??
I was assigning the iframe source property directly to the doc file, like this
<iframe id="sam" src="c:\\test.doc">
this loads the doc into browser, but this prompt to open a downloader window.
I'd really appreciate any hint that lead me to some direction.
<HTML>
<HEAD>
<TITLE>MSWORD App through JavaScript</TITLE>
</HEAD>
<BODY>
<script>
var w=new ActiveXObject('Word.Application');
var docText;
var obj;
if (w != null)
{
w.Visible = true; // you can change here visible or not
obj=w.Documents.Open("C:\\A.doc");
docText = obj.Content;
w.Selection.TypeText("Hello");
w.Documents.Save();
document.write(docText);//Print on webpage
/*The Above Code Opens existing Document
set w.Visible=false
*/
/*Below code will create doc file and add data to it and will close*/
w.Documents.Add();
w.Selection.TypeText("Writing This Message ....");
w.Documents.Save("c:\\doc_From_javaScript.doc");
w.Quit();
/*Don't forget
set w.Visible=false */
}
As far as I know there's no way to force this to be opened in a browser. Simply because the server will send the mime type of a word document, from that point on it is up to the client to decide what to do with it and a majority are set to download. There are however some registry tweaks that you can do on a client machine to force the client machine to view word documents inside of internet explorer.