I'm trying to learn how to use pdfMake. I'm trying to use open and print to generate or print the information respectively. But, when I click on the button which fires the event, a new tab opens for a second and vanishes.
The page which opens is displayed in history as blob:http://localhost:9999/93c1600e-3c64-42fe-8b44-fe6eeb995b5e
I'm not able to figure out the error. I'm following the official documentation of pdfMake.
Please help.
function print(){
window.event.preventDefault()
// this is just a simulation of the open event, replacing it with print produces the same result
var docDefinition = { content: {text:'This is an sample PDF printed with pdfMake',fontSize:15} };
pdfMake.createPdf(docDefinition).open();
}
<!DOCTYPE HMTL>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<script src='https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.27/pdfmake.min.js'></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.27/vfs_fonts.js"></script>
<script src="js/print.js"></script>
</head>
<body>
<main>
<button onclick="print()">Print Card</button>
</main>
</body>
</html>
Please check that any type of ad blocker in your browser is turned off and try again.
I found solution for printing in same window.
In your .html file put iframe
<iframe id="printPdf" name="printPdf"></iframe>
iframe needs style to hide himself for example (I do not know why, but if I define width and height on iframe, printing will not work):
#printPdf { position: fixed; top: 0px; left: 0px; display: block;
padding: 0px;border: 0px;margin: 0px;
visibility: hidden; opacity: 0;
}
Finally, just call:
if ('safari') {
pdfMake.createPdf(content).open({}, window.frames['printPdf']);
setTimeout(function() {
window.frames['printPdf'].focus();
window.frames['printPdf'].print();
}, 2000)
} else {
pdfMake.createPdf(content).print({}, window.frames['printPdf']);
}
Tested on Chrome v72, Firefox v65, Edge v18, Safari v12
for the open() it's not working even without ad blocker so i converted it to base64 then blob then fileURL
var docDefinition = getRWABELPDF(data);
var createPdf = pdfMake.createPdf(docDefinition);
var base64data = null;
createPdf.getBase64(function(encodedString) {
base64data = encodedString;
console.log(base64data );
var byteCharacters = atob(base64data);
var byteNumbers = new Array(byteCharacters.length);
for (var i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
var byteArray = new Uint8Array(byteNumbers);
var file = new Blob([byteArray], { type: 'application/pdf;base64' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
PDFMake has an open issue for this problem.
PDFMake creates URLs starting with blob: to print/open a generated PDF. The problem is that this pattern of URL is used by many sites to show undesired popups to users. Then EasyList listed this URL pattern and ad blockers started blocking it.
Therefore, as steffanjj suggested, disable your ad blocker and you should be able to print/open the generated PDF. I just wanted to explain in little more detail why this is happening.
This helped me for viewing directly in browser.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PDF Make</title>
<script src='js/pdfmake.min.js'></script>
<script src='js/vfs_fonts.js'></script>
<style>
#viewPdf { position: fixed; top: 0px; left: 0px; display: block; padding: 0px; border: 0px; margin: 0px; width: 100%; height: 100%; }
</style>
</head>
<body>
<iframe id="viewPdf" name="viewPdf"></iframe>
<script>
const docDefinition = {
pageMargins: [ 0, 0, 0, 0 ],
content: 'This is an sample PDF printed with pdfMake'
};
pdfMake.createPdf(docDefinition).open(window.frames['viewPdf']);
</script>
</body>
</html>
Related
I have an iframe that changes src pages when the page would normally switch to another page so that my main JS file can continue running in the background. For the first page, the one defined in the HTML src for the Iframe, I can access the inner document just fine by using iframe.contentDocument.
However, when I change the src, the contentDocument does not change with it, and I cannot access the Iframe's document in the JS at all.
So is there any way to access the new document of an Iframe after changing its source in JS? Or is there an easier alternative for the way I am doing things?
Thanks.
How I've tried:
iframe.src = "pages/home/home.html"
innerDoc = iframe.contentDocument || iframe.contentWindow.document
and the innerDoc does not change from the original page.
I've even tried making an entirely new Iframe that never had the original page as its src
document.body.removeChild(iframe)
let i = document.createElement('iframe')
i.src='pages/home/home.html'
document.body.appendChild(i)
innerDoc = i.contentDocument || i.contentWindow.document
This just makes innerDoc an empty HTML document with an empty head and body.
It appears that the page you are loading inside the iframe is from the same domain as the parent window - so you should not need messaging.
You will, however, need to wait for the "load" event before accessing the page content. This is the same for any webpage, not just one embedded in an iframe. Note that you cannot access the contentWindow for an iframe until it is attached to the DOM:
let i = document.createElement('iframe');
// go ahead and attach it to the dom - you can "hide" it with css
document.body.appendChild(i);
// now that you can access the contentWindow, attach a "load" event
i.contentWindow.addEventListener('load', () => {
// now you should be able to access the content
});
// do this last to avoid race conditions with caching and what not
// this might not be necessary, but it doesn't hurt
i.src='pages/home/home.html'
You can "hide" the iframe off screen if you want with something like this:
iframe {
position: absolute;
top: -9999em;
width: 1px;
height: 1px;
}
the "messaging" way is using Window.postMessage
parent Page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>main Page</title>
<style>
body { font-size: 16px; font-family: Arial, Helvetica, sans-serif; }
iframe { width: 24em; height: 15em; border:3px solid blue; }
#get-iframe-info { width: 24em; border: 1px solid orange; padding: .5em; }
</style>
</head>
<body>
<h4>main page</h4>
<p>parent input :
<input id="in-txt" type="text" placeholder="type something">
<button id="Bt-Send2iFrame">Send2iFrame</button>
</p>
<p> iframe part : <br>
<iframe id="iFrame-01" src="page_iFrame.html" frameborder="0"></iframe>
</p>
<p id="get-iframe-info">iframe return: <br>>
<span></span>
</p>
<script>
const
inTxt = document.querySelector('#in-txt')
, btSend = document.querySelector('#Bt-Send2iFrame')
, iFrame01_ct = document.querySelector('#iFrame-01').contentWindow
, sp_getiFram = document.querySelector('#get-iframe-info span')
;
btSend.onclick =_=>
{
let info = { txt: inTxt.value }
iFrame01_ct.postMessage( JSON.stringify(info), "*")
}
window.onmessage=e=>
{
let info = JSON.parse( e.data )
sp_getiFram.textContent = info.txt
}
</script>
</body>
</html>
iFrame page(s)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
<style>
body { font-family: 'Courier New', Courier, monospace; font-size: 14px;}
p { width: 20em; border: 2px solid aquamarine; padding: .5em; }
</style>
</head>
<body>
<h4>page iFrame</h4>
<input id="inTxt" type="text" placeholder="send text">
<button id="btSend">send to parent</button>
<p id="get-parent-info"> info from Parent: <br>>
<span></span>
</p>
<script>
const sp_infoParent = document.querySelector('#get-parent-info span')
;
btSend.onclick =_=>
{
let info = { txt: inTxt.value }
window.parent.postMessage( JSON.stringify(info), "*")
}
window.onmessage=e=>
{
let info = JSON.parse( e.data )
sp_infoParent.textContent = info.txt
}
</script>
</body>
</html>
I have a few URLs that each show the status of some industrial equipment. I'm trying to create an HTML/Javascript solution that, on load, cycles through each of the websites at a set interval, with two buttons to stop the cycle (to take a closer look at something) and restart the cycle (either from the beginning or where it left off, I'm not picky). I'm REALLY rusty, but I got what I think is a good start. Unfortunately, it doesn't work. Here are the CSS and HTML:
html,
body {
height: 100vh;
width: 100vw;
}
#btStart {
position: absolute;
width: 50px;
height: 40px;
left: 20px;
top: 50px;
}
#btStop {
position: absolute;
width: 50px;
height: 40px;
left: 20px;
top: 120px;
}
#infoFrame {
width: 100%;
height: 100%;
}
.holder {
width: 100%;
height: 100%;
position: relative;
}
<!DOCTYPE HTML>
<html>
<head>
<title>Info Cycle</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="main.css" rel="stylesheet">
</head>
<body>
<div class="holder">
<iframe src="" id="infoFrame" frameborder="0" allowfullscreen>
<script type="text/javascript">
var urlArray = ['url1.com',
'url2.com',
'url3.com',
'url4.com',
'url5.com'];
var count = 0;
var i = document.getElementById('infoFrame');
var u = document.getElementById('url');
var timer = setInterval(cycleTimer, 5000);
function nextUrl() {
url = urlArray[++count];
count = (count >= urlArray.length - 1)? -1 : count;
return url;
}
function cycleTimer() {
u.innerHTML = '';
i.src = nextUrl();
i.onload = function(){
u.innerHTML = i.src;
}
}
</script>
</iframe>
<button type="button" id="btStart" onclick="var timer = setInterval(cycleTimer, 5000);">Start</button>
<button type="button" id="btStop" onclick="clearInterval(timer)";>Stop</button>
</div>
</body>
<footer>
</footer>
</html>
Before I added the buttons it would load, then 5 seconds later it would cycle correctly, and so on. Now it only shows the buttons. Looking at the requests, I believe what's happening in my CSS and structure is trash, and it's loading the appropriate URL, but not displaying. I should add, prior to the buttons I only had the iframe with the script in it as a proof of concept. I div'd it, added the stylesheet, and added the buttons, and now here we are.
This may be a rookie mistake, or something more complicated. I haven't done development in a long time, and I'm just trying to solve a little problem at work. If you could spare a minute, I'd be happy to know how to fix this, and also any feedback on what I could be doing better. I'd love to get back into doing more of this, so I'm interested to learn anything the community can share. I've searched the site and the internet, and I've found a couple of related solutions but nothing for this in particular.
Thanks!
EDIT:
In case it helps, below is the HTML before the buttons and stylesheet, which worked (it rotated between webpages every 7 seconds):
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Info Cycle</title>
</head>
<body>
<iframe id="frame" src=""
style="
position: fixed;
top: 0px;
bottom: 0px;
right: 0px;
width: 100%;
border: none;
margin: 0;
padding: 0;
overflow: hidden;
z-index: 999999;
height: 100%;
"></iframe>
<script type="text/javascript">
var urlArray = ['url1.com',
'url2.com',
'url3.com',
'url4.com',
'url5.com'];
var count = 0;
var i = document.getElementById('frame');
var u = document.getElementById('url');
var timer = setInterval(cycleTimer, 7000);
function nextUrl() {
url = urlArray[++count];
count = (count >= urlArray.length - 1)? -1 : count;
return url;
}
function cycleTimer() {
u.innerHTML = '';
i.src = nextUrl();
i.onload = function(){
u.innerHTML = i.src;
}
}
</script>
</body>
</html>
The iframe style was something I found in an old file I'd written (probably copied and pasted from Stack Overflow to just get a thing to work).
The problem here is having the script inside the iframe. If you move your script out of the iframe and put it under body or head then it will work.
<!DOCTYPE HTML>
<html>
<head>
<title>Info Cycle</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<link href="main.css" rel="stylesheet">
<script type="text/javascript">
var urlArray = ['url1.com',
'url2.com',
'url3.com',
'url4.com',
'url5.com'];
var count = 0;
var timer = setInterval(cycleTimer, 5000);
function nextUrl() {
url = urlArray[++count];
count = (count >= urlArray.length - 1) ? -1 : count;
return url;
}
function cycleTimer() {
var i = document.getElementById('infoFrame');
var u = document.getElementById('url');
u.innerHTML = '';
i.src = nextUrl();
i.onload = function () {
u.innerHTML = i.src;
}
}
</script>
</head>
<body>
<div class="holder">
<iframe src="" id="infoFrame" frameborder="0" allowfullscreen>
</iframe>
<button type="button" id="btStart" onclick="var timer = setInterval(cycleTimer, 5000);">Start</button>
<button type="button" id="btStop" onclick="clearInterval(timer)" ;>Stop</button>
</div>
</body>
<footer>
</footer>
</html>
I am experimenting with a basic VSCode extension webview. I am trying to get a simple button click to display a message whenever it is clicked, but the message is only appearing the first time. My HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Module Manager</title>
<style> h1 {
position: fixed;
top: 50%;
left: 50%;
margin-top: -100px;
margin-left: -200px;}
</style>
</head>
<body style="background-color:rgb(60,99,201);">
<h1 style="color:white;">Welcome to the Lab Ticketing System</h1>
<button onclick="moduleAdd()">Click me</button>
<script>
function moduleAdd(){
const vscode = acquireVsCodeApi();
vscode.postMessage({command: "alert", text: "BUTTON PRESSED!"});
}
</script>
</body>
</html>
Then, the javascript code:
let newCommand = vscode.commands.registerCommand('ticketing.start', function () {
vscode.window.showInformationMessage("Activating ticketing system!")
// create webview
const modulePanel = vscode.window.createWebviewPanel('modManage', "Module Manager",
vscode.ViewColumn.One, {enableScripts: true}, );
// pull in the HTML content for the webview panel from external module
modulePanel.webview.html = htmlStuff.getWelcomeScreen();
// handle recieving messages from the webview
modulePanel.webview.onDidReceiveMessage(message =>
{switch(message.command){case 'alert': vscode.window.showErrorMessage(message.text);
return;}}, undefined, context.subscriptions);
});
context.subscriptions.push(disposable, newCommand);
I'm leaving out some code that manages the extension, since the webview displays correctly I think it's just an issue with how I'm implementing the button.
Only call acquireVsCodeApi() once, outside the functions that need it.
I want to display a polyline underground in cesium.js. But I have no idea about this.
It seems that cesium has not provided official underground function for the reason that cesium cameral can not be placed undergroud,but the underground effect can be gained by an alternative way--translucent terrain.
According How to display underground entity? in Cesium-dev google group,I have achieved a barely satisfactory approach to showing the entity(including gltf models) underground.The displaying effect is as what the GIF file shows.This appoach contains mainly 3 steps.
For gif, see here.
1.change only one line code in cesium source code;get the cesium source code,then find the file named GlobeSurfaceTileProvider.js,change
command.pass = Pass.GLOBE;
to
command.pass = Pass.TRANSLUCENT;
2.generate the cesium release code with gulp tool;use your CLI to execute gulp release. PS: You may need set your node environment and install the dependency node modules and install gulp tool.
3.Implemention code.PS: note the following snippet can run only if you have changed the cesium source code which is illustrated in step one.
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Use correct character set. -->
<meta charset="utf-8">
<!-- Tell IE to use the latest, best version. -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no">
<title>Hello World!</title>
<script src="../Build/Cesium/Cesium.js"></script>
<style>
#import url(../Build/Cesium/Widgets/widgets.css);
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
position: relative;
}
.tools {
position: absolute;
top: 20px;
left: 20px;
width: 100px;
}
</style>
</head>
<body>
<div class="container">
<div id="cesiumContainer">
</div>
<div class="tools">
Opacity: <input id="btnImageryAlpha" type="range" min="0" max="10" value="10" oninput="change()" />
</div>
</div>
<script>
function change() {
var value = document.getElementById("btnImageryAlpha").value;
if (viewer.imageryLayers) {
for (var i = 0; i < viewer.imageryLayers.length; i++) {
viewer.imageryLayers.get(i).alpha = value / 10;
}
}
console.log(value);
}
var terrainProvider = new Cesium.CesiumTerrainProvider({
url: 'https://assets.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestVertexNormals: true
});
var viewer = new Cesium.Viewer('cesiumContainer', {
//skyAtmosphere: false,
//orderIndependentTranslucency: false,
baseLayerPicker: false,
terrainProvider: terrainProvider
});
//viewer.scene.globe.depthTestAgainstTerrain = false;
//change the ugly blue color to black
viewer.scene.globe.baseColor = new Cesium.Color(0, 0, 0, 0);
//default is 1
//viewer.scene.globe.imageryLayers.get(0).alpha = 0.5;
var blueBox = viewer.entities.add({
name: 'Blue box',
position: Cesium.Cartesian3.fromDegrees(-114.0, 40.0, 5),
box: {
dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
material: Cesium.Color.BLUE
}
});
viewer.zoomTo(blueBox);
</script>
</body>
</html>
Yes, this is supported in cesium. It can be hard to see sometimes since the camera cannot go bellow the ellipsoid.
var viewer = new Cesium.Viewer('cesiumContainer');
var purpleArrow = viewer.entities.add({
name : 'Purple straight arrow at height',
polyline : {
positions : Cesium.Cartesian3.fromDegreesArrayHeights([-75, 43, -200000,
-90, 43, -200000]),
width : 10,
followSurface : false,
material : new Cesium.PolylineArrowMaterialProperty(Cesium.Color.PURPLE)
}
});
viewer.zoomTo(viewer.entities);
Live
Here's the entire code for my loop.html file. It first pulls the list of urls from a separate XML file that is in the same directory and then loops through them, given specified time. The time element is the amount it will wait until it cycles to the next page. What I want to do is to use DIV to cycle through the URLs, since iframe is not supported in all the browsers and does not display some of the content when I run the html script. The thing I am not sure about is what to do with the "dashboard.url"--when i want to use a div?
I found this piece of code from a different site--that when you replace the frams['theDisplay'] line with, it sets the div to a webpage--but I want to have something like this, using the dashboard.url
$("#siteloader").html('<object data="http://latimes.com" />');
I am sorry if this is a really long question, and if you get frustrated. I am just trying to learn as I go. Thank you!
Example of list.xml format:
<list>
<url>
<link>http:latimes.com</link>
<time>2</time>
</url>
<url>
<link>http:stackoverflow.com</link>
<time>4</time>
</url>
</list>
Entire HTML code:
<!DOCTYPE HTML>
<!--Created by Megan Chiu - 30 June 2013-->
<html>
<!-- CSS -->
<style type="text/css">
displayArea {
margin: 0;
width: 100%;
}
html, body {
height: 100%
width: 100%;
}
div {
height: 100%;
width: 100%
}
object {
width: 100%;
min-height: 100%;
}
</style>
<head>
<meta charset="UTF-8">
<style type="text/css">
body, html { margin: 0; padding: 0; width: 100%; height: 100%;
overflow: hidden; }
iframe { border: none; }
</style>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"
type="text/javascript"></script>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script type="text/javascript">
var Dash = {
nextIndex: 0,
dashboards: [],
loadXML: function() {
$.ajax( {
type: "GET",
url: "list.xml",
dataType: "xml",
success: Dash.renderXML
});
},
renderXML: function(xml) {
$(xml).find("url").each(function() {
var _link = $(this).find('link').text();
var _time = $(this).find('time').text();
Dash.dashboards.push({url:_link, time:_time});
});
Dash.display();
},
display: function()
{
var dashboard = Dash.dashboards[Dash.nextIndex];
frames['theDisplay'].location.href = dashboard.url;
Dash.nextIndex = (Dash.nextIndex + 1) % Dash.dashboards.length;
setTimeout(Dash.display, dashboard.time * 1000);
}
};
window.onload = Dash.loadXML;
</script>
</head>
<body>
</body>
<iframe id="theDisplay" width="100%" height="100%"></iframe>
</html>
<div id="content1"></div>
<script>
document.getElementById("content1").innerHTML='<object type="text/html" data="header.php" ></object>';
alert('Load_Ok');
</script>
You cannot load content from another website just with pure JavaScript. Period.
http://en.wikipedia.org/wiki/Same_origin_policy
So what you can do? You can make a web request from your server and get Http response from remote server and put them into div element.
<div><%=(new WebClient()).DownloadString("http://www.stackoverflow.com")%></div>
But one of biggest problem is that, since you will download all styles and scripts from remote website then your page probably will not look good. Not even human readable. And if you will keep hitting from same IP to those servers you will may blocked by them.
Good luck.