I have the following html code:
<!DOCTYPE html>
<html>
<body>
<p>don't print this to pdf</p>
<div id="pdf">
<p><font size="3" color="red">print this to pdf</font></p>
</div>
</body>
</html>
All I want to do is to print to pdf whatever is found in the div with an id of "pdf". This must be done using JavaScript. The "pdf" document should then be automatically downloaded with a filename of "foobar.pdf"
I've been using jspdf to do this, but the only function it has is "text" which accepts only string values. I want to submit HTML to jspdf, not text.
jsPDF is able to use plugins. In order to enable it to print HTML, you have to include certain plugins and therefore have to do the following:
Go to https://github.com/MrRio/jsPDF and download the latest Version.
Include the following Scripts in your project:
jspdf.js
jspdf.plugin.from_html.js
jspdf.plugin.split_text_to_size.js
jspdf.plugin.standard_fonts_metrics.js
If you want to ignore certain elements, you have to mark them with an ID, which you can then ignore in a special element handler of jsPDF. Therefore your HTML should look like this:
<!DOCTYPE html>
<html>
<body>
<p id="ignorePDF">don't print this to pdf</p>
<div>
<p><font size="3" color="red">print this to pdf</font></p>
</div>
</body>
</html>
Then you use the following JavaScript code to open the created PDF in a PopUp:
var doc = new jsPDF();
var elementHandler = {
'#ignorePDF': function (element, renderer) {
return true;
}
};
var source = window.document.getElementsByTagName("body")[0];
doc.fromHTML(
source,
15,
15,
{
'width': 180,'elementHandlers': elementHandler
});
doc.output("dataurlnewwindow");
For me this created a nice and tidy PDF that only included the line 'print this to pdf'.
Please note that the special element handlers only deal with IDs in the current version, which is also stated in a GitHub Issue. It states:
Because the matching is done against every element in the node tree, my desire was to make it as fast as possible. In that case, it meant "Only element IDs are matched" The element IDs are still done in jQuery style "#id", but it does not mean that all jQuery selectors are supported.
Therefore replacing '#ignorePDF' with class selectors like '.ignorePDF' did not work for me. Instead you will have to add the same handler for each and every element, which you want to ignore like:
var elementHandler = {
'#ignoreElement': function (element, renderer) {
return true;
},
'#anotherIdToBeIgnored': function (element, renderer) {
return true;
}
};
From the examples it is also stated that it is possible to select tags like 'a' or 'li'. That might be a little bit to unrestrictive for the most usecases though:
We support special element handlers. Register them with jQuery-style
ID selector for either ID or node name. ("#iAmID", "div", "span" etc.)
There is no support for any other type of selectors (class, of
compound) at this time.
One very important thing to add is that you lose all your style information (CSS). Luckily jsPDF is able to nicely format h1, h2, h3 etc., which was enough for my purposes. Additionally it will only print text within text nodes, which means that it will not print the values of textareas and the like. Example:
<body>
<ul>
<!-- This is printed as the element contains a textnode -->
<li>Print me!</li>
</ul>
<div>
<!-- This is not printed because jsPDF doesn't deal with the value attribute -->
<input type="textarea" value="Please print me, too!">
</div>
</body>
This is the simple solution. This works for me. You can use the javascript print concept and simple save this as pdf.
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript">
$("#btnPrint").live("click", function () {
var divContents = $("#dvContainer").html();
var printWindow = window.open('', '', 'height=400,width=800');
printWindow.document.write('<html><head><title>DIV Contents</title>');
printWindow.document.write('</head><body >');
printWindow.document.write(divContents);
printWindow.document.write('</body></html>');
printWindow.document.close();
printWindow.print();
});
</script>
</head>
<body>
<form id="form1">
<div id="dvContainer">
This content needs to be printed.
</div>
<input type="button" value="Print Div Contents" id="btnPrint" />
</form>
</body>
</html>
No depenencies, pure JS
To add CSS or images - do not use relative URLs, use full URLs http://...domain.../path.css or so. It creates separate HTML document and it has no context of main thing.
you can also embed images as base64
This served me for years now:
export default function printDiv({divId, title}) {
let mywindow = window.open('', 'PRINT', 'height=650,width=900,top=100,left=150');
mywindow.document.write(`<html><head><title>${title}</title>`);
mywindow.document.write('</head><body >');
mywindow.document.write(document.getElementById(divId).innerHTML);
mywindow.document.write('</body></html>');
mywindow.document.close(); // necessary for IE >= 10
mywindow.focus(); // necessary for IE >= 10*/
mywindow.print();
mywindow.close();
return true;
}
Of course this will open print dialog and user will have to know she/he can select print to pdf option, to get pdf. There may be printer pre-selected and if user confirms may get this document actually printed. To avoid such situation and to provide PDF without any extras, you need to make PDF file. Probably on the server side. You could have tiny html page with invoice only and convert it to PDF file with headless chrome. It's super easy with puppeteer. No need to install/config chrome, just install npm package puppeteer (managed by chrome team) and run it. Keep in mind this will actually launch real chrome just w/o GUI, so you need to have some RAM & CPU for this. Most servers will be fine with low enough traffic. Here is code sample but this must run on the BACKEND. Nodejs. Also it's slow call, it's resources intensive call. You should run it NOT on api call but e.g. after invoice was created - create pdf for it and store, if pdf was not generated yet, just show message to try again in couple minutes.
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://your-domain.com/path-to-invoice', {
waitUntil: 'networkidle2',
});
await page.pdf({ path: 'invoice-file-path.pdf', format: 'a4' });
await browser.close();
})();
Learn more here: https://pptr.dev/
if you need to downloadable pdf of a specific page just add button like this
<h4 onclick="window.print();"> Print </h4>
use window.print() to print your all page not just a div
You can use autoPrint() and set output to 'dataurlnewwindow' like this:
function printPDF() {
var printDoc = new jsPDF();
printDoc.fromHTML($('#pdf').get(0), 10, 10, {'width': 180});
printDoc.autoPrint();
printDoc.output("dataurlnewwindow"); // this opens a new popup, after this the PDF opens the print window view but there are browser inconsistencies with how this is handled
}
As mentioned, you should use jsPDF and html2canvas. I've also found a function inside issues of jsPDF which splits automatically your pdf into multiple pages (sources)
function makePDF() {
var quotes = document.getElementById('container-fluid');
html2canvas(quotes, {
onrendered: function(canvas) {
//! MAKE YOUR PDF
var pdf = new jsPDF('p', 'pt', 'letter');
for (var i = 0; i <= quotes.clientHeight/980; i++) {
//! This is all just html2canvas stuff
var srcImg = canvas;
var sX = 0;
var sY = 980*i; // start 980 pixels down for every new page
var sWidth = 900;
var sHeight = 980;
var dX = 0;
var dY = 0;
var dWidth = 900;
var dHeight = 980;
window.onePageCanvas = document.createElement("canvas");
onePageCanvas.setAttribute('width', 900);
onePageCanvas.setAttribute('height', 980);
var ctx = onePageCanvas.getContext('2d');
// details on this usage of this function:
// https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Using_images#Slicing
ctx.drawImage(srcImg,sX,sY,sWidth,sHeight,dX,dY,dWidth,dHeight);
// document.body.appendChild(canvas);
var canvasDataURL = onePageCanvas.toDataURL("image/png", 1.0);
var width = onePageCanvas.width;
var height = onePageCanvas.clientHeight;
//! If we're on anything other than the first page,
// add another page
if (i > 0) {
pdf.addPage(612, 791); //8.5" x 11" in pts (in*72)
}
//! now we declare that we're working on that page
pdf.setPage(i+1);
//! now we add content to that page!
pdf.addImage(canvasDataURL, 'PNG', 20, 40, (width*.62), (height*.62));
}
//! after the for loop is finished running, we save the pdf.
pdf.save('test.pdf');
}
});
}
i use jspdf and html2canvas for css rendering and i export content of specific div as this is my code
$(document).ready(function () {
let btn=$('#c-oreder-preview');
btn.text('download');
btn.on('click',()=> {
$('#c-invoice').modal('show');
setTimeout(function () {
html2canvas(document.querySelector("#c-print")).then(canvas => {
//$("#previewBeforeDownload").html(canvas);
var imgData = canvas.toDataURL("image/jpeg",1);
var pdf = new jsPDF("p", "mm", "a4");
var pageWidth = pdf.internal.pageSize.getWidth();
var pageHeight = pdf.internal.pageSize.getHeight();
var imageWidth = canvas.width;
var imageHeight = canvas.height;
var ratio = imageWidth/imageHeight >= pageWidth/pageHeight ? pageWidth/imageWidth : pageHeight/imageHeight;
//pdf = new jsPDF(this.state.orientation, undefined, format);
pdf.addImage(imgData, 'JPEG', 0, 0, imageWidth * ratio, imageHeight * ratio);
pdf.save("invoice.pdf");
//$("#previewBeforeDownload").hide();
$('#c-invoice').modal('hide');
});
},500);
});
});
One way is to use window.print() function. Which does not require any library
Pros
1.No external library require.
2.We can print only selected parts of body also.
3.No css conflicts and js issues.
4.Core html/js functionality
---Simply add below code
CSS to
#media print {
body * {
visibility: hidden; // part to hide at the time of print
-webkit-print-color-adjust: exact !important; // not necessary use
if colors not visible
}
#printBtn {
visibility: hidden !important; // To hide
}
#page-wrapper * {
visibility: visible; // Print only required part
text-align: left;
-webkit-print-color-adjust: exact !important;
}
}
JS code - Call bewlow function on btn click
$scope.printWindow = function () {
window.print()
}
Note: Use !important in every css object
Example -
.legend {
background: #9DD2E2 !important;
}
Use pdfMake.js and this Gist.
(I found the Gist here along with a link to the package html-to-pdfmake, which I end up not using for now.)
After npm install pdfmake and saving the Gist in htmlToPdf.js I use it like this:
const pdfMakeX = require('pdfmake/build/pdfmake.js');
const pdfFontsX = require('pdfmake-unicode/dist/pdfmake-unicode.js');
pdfMakeX.vfs = pdfFontsX.pdfMake.vfs;
import * as pdfMake from 'pdfmake/build/pdfmake';
import htmlToPdf from './htmlToPdf.js';
var docDef = htmlToPdf(`<b>Sample</b>`);
pdfMake.createPdf({content:docDef}).download('sample.pdf');
Remarks:
My use case is to create the relevant html from a markdown document (with markdown-it) and subsequently generating the pdf, and uploading its binary content (which I can get with pdfMake's getBuffer() function), all from the browser. The generated pdf turns out to be nicer for this kind of html than with other solutions I have tried.
I am dissatisfied with the results I got from jsPDF.fromHTML() suggested in the accepted answer, as that solution gets easily confused by special characters in my HTML that apparently are interpreted as a sort of markup and totally mess up the resulting PDF.
Using canvas based solutions (like the deprecated jsPDF.from_html() function, not to be confused with the one from the accepted answer) is not an option for me since I want the text in the generated PDF to be pasteable, whereas canvas based solutions generate bitmap based PDFs.
Direct markdown to pdf converters like md-to-pdf are server side only and would not work for me.
Using the printing functionality of the browser would not work for me as I do not want to display the generated PDF but upload its binary content.
I was able to get jsPDF to print dynamically created tables from a div.
$(document).ready(function() {
$("#pdfDiv").click(function() {
var pdf = new jsPDF('p','pt','letter');
var specialElementHandlers = {
'#rentalListCan': function (element, renderer) {
return true;
}
};
pdf.addHTML($('#rentalListCan').first(), function() {
pdf.save("caravan.pdf");
});
});
});
Works great with Chrome and Firefox... formatting is all blown up in IE.
I also included these:
<script src="js/jspdf.js"></script>
<script src="js/jspdf.plugin.from_html.js"></script>
<script src="js/jspdf.plugin.addhtml.js"></script>
<script src="//mrrio.github.io/jsPDF/dist/jspdf.debug.js"></script>
<script src="http://html2canvas.hertzen.com/build/html2canvas.js"></script>
<script type="text/javascript" src="./libs/FileSaver.js/FileSaver.js"></script>
<script type="text/javascript" src="./libs/Blob.js/Blob.js"></script>
<script type="text/javascript" src="./libs/deflate.js"></script>
<script type="text/javascript" src="./libs/adler32cs.js/adler32cs.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.addimage.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.sillysvgrenderer.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.split_text_to_size.js"></script>
<script type="text/javascript" src="js/jspdf.plugin.standard_fonts_metrics.js"></script>
If you want to export a table, you can take a look at this export sample provided by the Shield UI Grid widget.
It is done by extending the configuration like this:
...
exportOptions: {
proxy: "/filesaver/save",
pdf: {
fileName: "shieldui-export",
author: "John Smith",
dataSource: {
data: gridData
},
readDataSource: true,
header: {
cells: [
{ field: "id", title: "ID", width: 50 },
{ field: "name", title: "Person Name", width: 100 },
{ field: "company", title: "Company Name", width: 100 },
{ field: "email", title: "Email Address" }
]
}
}
}
...
This example works great.
<button onclick="genPDF()">Generate PDF</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js"></script>
<script>
function genPDF() {
var doc = new jsPDF();
doc.text(20, 20, 'Hello world!');
doc.text(20, 30, 'This is client-side Javascript, pumping out a PDF.');
doc.addPage();
doc.text(20, 20, 'Do you like that?');
doc.save('Test.pdf');
}
</script>
Dissatisfied with the rendering of html2canvas and lack of modern CSS3/JS and print specific CSS support of pdfMake's outdated version of WebKit...
Here's a theoretical solution, it's headless and can render pages faithfully, supports page breaks, margins, different page sizes and can be automated. You can even render WebGl to PDF.
Chrome has a devtools protocol... which has a printtoPDF function
Excerpt: https://gitlab.com/-/snippets/new
Official 20k-SLOC spec: https://github.com/ChromeDevTools/devtools-protocol/blob/master/json/browser_protocol.json
You can use node and https://github.com/GoogleChrome/chrome-launcher to run chrome headless... wait for it to render.
Profit
printToPDF command you'd run on chrome_devtools protocol:
printToPDF({
printBackground: false,
pageWidth: 8.5,
pageHeight: 11,
transferMode: "ReturnAsStream" // or ReturnAsBase64
})
2022 Answer:
To generate PDF from HTML Element and prompt to save file:
import { jsPDF } from "jsPDF"
function generatePDF() {
const doc = new jsPDF({ unit: 'pt' }) // create jsPDF object
const pdfElement = document.getElementById('pdf') // HTML element to be converted to PDF
doc.html(pdfElement, {
callback: (pdf) => {
pdf.save('MyPdfFile.pdf')
},
margin: 32, // optional: page margin
// optional: other HTMLOptions
})
}
<button onclick="generatePDF()">Save PDF</button>
...
To preview PDF without printing:
doc.html(pdfElement, {
callback: (pdf) => {
const myPdfData = pdf.output('datauristring')
}
})
<embed type="application/pdf" src={myPdfData} />
...
For more HTMLOptions:
https://github.com/parallax/jsPDF/blob/master/types/index.d.ts
To capture div as PDF you can use https://grabz.it solution. It's got a JavaScript API which is easy and flexible and will allow you to capture the contents of a single HTML element such as a div or a span
In order to implement it you will need to first get an app key and secret and download the (free) SDK.
And now an example.
Let's say you have the HTML:
<div id="features">
<h4>Acme Camera</h4>
<label>Price</label>$399<br />
<label>Rating</label>4.5 out of 5
</div>
<p>Cras ut velit sed purus porttitor aliquam. Nulla tristique magna ac libero tempor, ac vestibulum felisvulput ate. Nam ut velit eget
risus porttitor tristique at ac diam. Sed nisi risus, rutrum a metus suscipit, euismod tristique nulla. Etiam venenatis rutrum risus at
blandit. In hac habitasse platea dictumst. Suspendisse potenti. Phasellus eget vehicula felis.</p>
To capture what is under the features id you will need to:
//add the sdk
<script type="text/javascript" src="grabzit.min.js"></script>
<script type="text/javascript">
//login with your key and secret.
GrabzIt("KEY", "SECRET").ConvertURL("http://www.example.com/my-page.html",
{"target": "#features", "format": "pdf"}).Create();
</script>
Please note the target: #feature. #feature is you CSS selector, like in the previous example. Now, when the page is loaded an image screenshot will now be created in the same location as the script tag, which will contain all of the contents of the features div and nothing else.
The are other configuration and customization you can do to the div-screenshot mechanism, please check them out here
The following method works fine for my case.
Hide additional parts for a page like the following example
#media print{
body{
-webkit-print-color-adjust: exact; // if you want to enable graphics
color-adjust: exact !important; // if you want to enable graphics
print-color-adjust: exact !important; // if you want to enable graphics
* {
visibility: hidden;
margin:0;
padding:0
}
.print_area, .print_area *{
visibility: visible;
}
.print_area{
margin: 0;
align: center;
}
.pageBreak {
page-break-before : always; // If you want to skip next page
page-break-inside: avoid; // If you want to skip next page
}
}
#page {
size: A4; margin:0mm; // set page layout
background-color: #fff;
}
}
Use the javascript print function to print execution.
<button onclick="window.print()">Print</button>
any one try this
(function () {
var
form = $('.form'),
cache_width = form.width(),
a4 = [595.28, 841.89]; // for a4 size paper width and height
$('#create_pdf').on('click', function () {
$('body').scrollTop(0);
createPDF();
});
//create pdf
function createPDF() {
getCanvas().then(function (canvas) {
var
img = canvas.toDataURL("image/png"),
doc = new jsPDF({
unit: 'px',
format: 'a4'
});
doc.addImage(img, 'JPEG', 20, 20);
doc.save('Bhavdip-html-to-pdf.pdf');
form.width(cache_width);
});
}
// create canvas object
function getCanvas() {
form.width((a4[0] * 1.33333) - 80).css('max-width', 'none');
return html2canvas(form, {
imageTimeout: 2000,
removeContainer: true
});
}
}());
I have a base website system which is using ajax load content without refreshing pages. I have a game page that load many html5 game links via ajax json and when I click on any games it will load the game source files which display as pop up. I am wonder while I'm playing then if I click the close button for stopping the game and then I remove the element of the source files game. Will it free up the memory? As I have noticed, it seems to getting slow the broswer. Anyone has experienced with that, please share with me.
Note: I need some suggestions in order to remove the elements and free up the memory.
eg:
<div id="pop-up">
<a id="close" href="#">Close Button</a>
<div id="inner-pop-up">
<script src="game sources" type="text/javascript"></script>
<script src="game sources" type="text/javascript"></script>
<script src="game sources" type="text/javascript"></script>
<div id="game">
<canvas></canvas>
</div>
</div>
</div>
$('#pop-up').modal('view', {
speed: 750,
close: '.close-favourite',
easing: 'easeOutBounce',
animation: 'top',
position: 'center',
overlayClose: true
});
$('#close').on('click', function() {
$('#inner-pop-up').children().remove();
});
The only real way to free up any resources used by script functions is to add a JavaScript file that basically calls delete window.myFunction for every possible object and function (functions are objects really) your specified script files may define. To me, for obvious reasons, this is a really bad idea.
Note that these objects would be script (window) objects so you cannot use .remove() to remove those.
I would also note that your should use $('#inner-pop-up').empty(); rather than your $('#inner-pop-up').children().remove(); since that would remove the text of the element if any, as well and specifically removes the data and event handlers from those elements prior to removal from the DOM.
You might have some very specific functions and objects from your scripts that you might want to remove here but only the contents of your scripts would tell that. If you create global window objects that gets really messy fast.
Note it is REALLY hard to determine what a script file creates and then remove it.
To prove a point open up your favorite browser console and execute $("script").remove(). stuff in that script still runs.
Eg: This is my game file which contained the object like that
FootballChallenge.Game = function (game) {
FootballChallenge._scoreText = null;
FootballChallenge._score = 0;
FootballChallenge.kickBoard;
this._preventClick = true;
FootballChallenge.kaboomGroup;
FootballChallenge.ball;
FootballChallenge.shoe;
FootballChallenge.self;
};
FootballChallenge.Game.prototype = {
create: function () {
FootballChallenge.self = this.game;
this.game.physics.startSystem(Phaser.Physics.ARCADE);
this.game.physics.arcade.checkCollision.up = false;
this.bg = this.game.add.image(this.game.world.centerX, this.game.world.centerY, 'field');
this.bg.anchor.setTo(0.5);
FootballChallenge.kickBoard = this.game.add.sprite(10, 20, 'kickBoard');
FootballChallenge._scoreText = this.game.add.bitmapText(0, FootballChallenge.kickBoard.height/2 + 20, 'white-font', ''+FootballChallenge._score+'', 32);
FootballChallenge._scoreText.align = 'center';
FootballChallenge._scoreText.x = (FootballChallenge.kickBoard.width-FootballChallenge._scoreText.width + 20)/2;
FootballChallenge.ball = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY - 100, 'ball');
this.game.physics.arcade.enable(FootballChallenge.ball);
FootballChallenge.ball.anchor.setTo(0.5);
FootballChallenge.ball.scale.setTo(0.5);
FootballChallenge.ball.body.collideWorldBounds = true;
FootballChallenge.ball.body.gravity.y = 0;
FootballChallenge.ball.body.bounce.setTo(1);
FootballChallenge.shoe = this.game.add.sprite(this.game.world.centerX, this.game.world.centerY, 'shoe');
this.game.physics.arcade.enable(FootballChallenge.shoe);
FootballChallenge.shoe.anchor.setTo(0.5);
FootballChallenge.shoe.scale.setTo(0.5);
FootballChallenge.shoe.body.setSize(130,50,0,20);
FootballChallenge.shoe.body.collideWorldBounds = true;
FootballChallenge.kaboomGroup = this.game.add.group();
FootballChallenge.kaboomGroup.createMultiple(10, 'kaboom');
FootballChallenge.kaboomGroup.forEach(this.explosion, this);
this.play();
},
explosion: function(kick) {
kick.anchor.x = 0.7;
kick.anchor.y = 0.5;
kick.animations.add('kaboom');
},
play: function() {
this.bitmask = this.game.make.bitmapData(this.game.width, this.game.height);
this.bitmask.fill(50,50,50);
this.mask = this.game.add.sprite(0, 0, this.bitmask);
this.mask.tint = 0x000000;
this.mask.alpha = 0.6;
this.game.paused = true;
var pausedText = this.game.add.bitmapText(this.game.world.centerX, this.game.world.centerY - 200, 'white-font', 'click anywhere to begin!', 32);
pausedText.align = 'center';
pausedText.tint = 0xff0e25;
pausedText.anchor.setTo(0.5);
this.game.input.onDown.add(function(){
pausedText.destroy();
this.game.paused = false;
this.mask.alpha = 0;
FootballChallenge.ball.body.gravity.y = 1500;
this.game.canvas.style.cursor = "none";
}, this);
},
countScore: function(ball, shoe) {
ball.body.velocity.y = -1000;
ball.body.gravity.x = FootballChallenge.self.rnd.integerInRange(-80, 80);
FootballChallenge._scoreText.setText(FootballChallenge._score +=1);
FootballChallenge._scoreText.x = (FootballChallenge.kickBoard.width-FootballChallenge._scoreText.width + 20)/2;
var boom = FootballChallenge.kaboomGroup.getFirstExists(false);
boom.reset(shoe.x, shoe.y);
boom.play('kaboom', 40, false, true);
},
lose: function() {
this.game.state.start('EndGame');
},
update: function() {
if(FootballChallenge.ball.y >= this.game.height - 100) {
FootballChallenge.ball.body.gravity = false;
this.game.time.events.add(Phaser.Timer.SECOND * 0.2, this.lose, this);
}
this.game.physics.arcade.collide(FootballChallenge.ball, FootballChallenge.shoe, this.countScore);
this.game.physics.arcade.moveToPointer(FootballChallenge.shoe, 30, this.game.input.activePointer, 50);
}
};
I'm programming a firefox addon and using a panel to display info on a video, everything works fine althought I can't make the panel transparent. I define the panel styling in the html file as follow:
<html>
<head>
<meta charset="utf-8" />
<style type="text/css" media="all">
html
{
opacity:0.1;
border-style:none;
resize:none;
}
textarea
{
background-color:transparent;
resize: none;
border-style:none;
}
</style>
</head>
<body>
<textarea id="text" readonly=true rows="3" cols="60"></textarea>
</panel>
</body>
</html>
Except the panel is not transparent only the text area is. I tried with:
opacity:1 for textarea
It doesn't work either way. What am I doing wrong? Is this even possible?
From what I understand :
html
{
opacity:0.1;
border-style:none;
resize:none;
}
only applies to the panel content not to the panel itself. I found a post on this subject but it is outdated since the sdk/panel.js mentionned in the post is not the same anymore.
Anyway I tried downloading the panel.js and replacing the current one, but it doesn't seem to affect the panel I display at all. The panel is still white and the border-radius option does not work either. (I should say that I replaced all the "./" with "sdk/" as mentionned in that post).
Ok here is a pure addon sdk solution:
let myPanel = Panel({
width: 180,
height: 180,
contentURL: 'data:text/html,<textarea style="width:120px; height:80px;">this is my textarea</textarea>'
})
let { getActiveView }=require("sdk/view/core");
getActiveView(myPanel).setAttribute("noautohide", true);
getActiveView(myPanel).setAttribute("level", 'top');
getActiveView(myPanel).setAttribute("style", 'background-color:rgba(0, 0, 0, 0.2);');
You can't style the panel provided in the SDK, only the content but you can definitely follow the procedure you mention and provide your modified panel.
I had to solve this same problem today (transparent panel in SDK). The trick is getting at the anonymous content:
function makePanelTransparent() {
// Get the panel element in the XUL DOM and make its background transparent.
const { getActiveView } = require('sdk/view/core');
const el = getActiveView(panel);
el.style.background = 'rgba(0,0,0,0)';
// Go up the XUL DOM till you hit the Document (nodeType 9).
let parentNode = el;
while (parentNode !== null && parentNode.nodeType !== 9) {
parentNode = parentNode.parentNode;
}
if (!parentNode) {
console.error('unable to find the document parent; giving up');
return;
}
// Now that we've found it, call the document a document.
const xulDocument = parentNode;
// Use the document pointer to access and style 'anonymous' content.
const xulContainer = xulDocument.getAnonymousElementByAttribute(el, 'class', 'panel-arrowcontent')
xulContainer.style.background = 'rgba(0,0,0,0)';
xulContainer.style.boxShadow = 'none';
}
This works for me. Hope it helps some other person in the next 1-5 years ;-)
I found out that you could create a panel with transparency this way:
var win = Services.wm.getMostRecentWindow('navigator:browser');
var panel = win.document.createElement('panel');
var screen = Services.appShell.hiddenDOMWindow.screen;
var props = {
noautohide: true,
noautofocus: false,
level: 'top',
style: 'padding:15px; margin:0; width:' + screen.width + 'px; height:' + screen.height + 'px; background-color:rgba(180,180,180,.5);'
}
for (var p in props) {
panel.setAttribute(p, props[p]);
}
win.document.querySelector('#mainPopupSet').appendChild(panel);
panel.addEventListener('dblclick', function () {
panel.parentNode.removeChild(panel)
}, false);
panel.openPopup(null, 'overlap', screen.availLeft, screen.availTop);
To embed an iframe remember to set the path to your ".html" as:
"resource://"id of your addon"-at-jetpack/data/custom_panel.html".
Here is my code :
var win = Services.wm.getMostRecentWindow('navigator:browser');
var panel = win.document.createElement('panel');
var screen = Services.appShell.hiddenDOMWindow.screen;
var props = {
noautohide: true,
noautofocus: false,
backdrag: true,
level: 'top',
style: 'padding:10px; margin:0; width:530px; height:90px; background-color:rgba(180,180,180,.5);'
}
for (var p in props) {
panel.setAttribute(p, props[p]);
}
var iframe = win.document.createElement('iframe');
iframe.setAttribute('src','resource://"id of your addon"-at-jetpack/data/custom_panel.html');
panel.appendChild(iframe);
win.document.querySelector('#mainPopupSet').appendChild(panel);
panel.addEventListener('dblclick', function () {
panel.parentNode.removeChild(panel)
}, false);
panel.openPopup(null, 'overlap', screen.availLeft+screen.width/2-256, screen.availTop+760);
Thanks Noitidart for the help.
Good day. I am developing a Web Application and there's a part where I print the form on button click. To achieve this, I overrode the definition of my Form Panel so that I can call form.print() anywhere in my code when I need to. Here is how I overrode my form:
Ext.define('my_app_name.override.form.Panel', {
override: 'Ext.form.Panel',
print: function(pnl) {
if (!pnl) {
pnl = this;
}
// instantiate hidden iframe
var iFrameId = "printerFrame";
var printFrame = Ext.get(iFrameId);
if (printFrame === null) {
printFrame = Ext.getBody().appendChild({
id: iFrameId,
tag: 'iframe',
cls: 'x-hidden',
style: {
display: "none"
}
});
}
var cw = printFrame.dom.contentWindow;
// instantiate application stylesheets in the hidden iframe
var stylesheets = "";
for (var i = 0; i < document.styleSheets.length; i++) {
stylesheets += Ext.String.format('<link rel="stylesheet" href="{0}" />', document.styleSheets[i].href);
}
// various style overrides
stylesheets += ''.concat(
"<style>",
".x-panel-body {overflow: visible !important;}",
// experimental - page break after embedded panels
// .x-panel {page-break-after: always; margin-top: 10px}",
"</style>"
);
// get the contents of the panel and remove hardcoded overflow properties
var markup = pnl.getEl().dom.innerHTML;
while (markup.indexOf('overflow: auto;') >= 0) {
markup = markup.replace('overflow: auto;', '');
}
var str = Ext.String.format('<html><head>{0}</head><body>{1}</body></html>',stylesheets,markup);
// output to the iframe
cw.document.open();
cw.document.write(str);
cw.document.close();
// remove style attrib that has hardcoded height property
cw.document.getElementsByTagName('DIV')[0].removeAttribute('style');
// print the iframe
cw.print();
// destroy the iframe
Ext.fly(iFrameId).destroy();
}
});
Then on a click of a button in my Web App, I do something like:
var form = Ext.getCmp('formIDHere');
form.print();
However, this code is rather inconsistent at times. There are times that I can print the form no problem and there are times that it gives the "Print Preview Error" message. I can't replicate the issue consistently and the logs aren't showing anything so I'm in the dark.
What I've noticed however, is that when I save my project (I'm using Sencha Architect), preview it (or refresh the current window where I'm previewing my Web App), stay with the web app all throughout the process (meaning I don't shift tabs or windows), hit the print button, the print preview appears and I don't have problems with it.
So far I haven't tested in other Web Browsers. Any ideas anyone? I'll be really thankful for anyone who can point out what I'm doing wrong. Thanks in advance.
Sorry I forgot to update this. Thanks to whoever upvoted my question.
The concept is simple. Since ExtJS4 is asynchronous, I placed my code in "blocks" and then I delayed my calls to those functions to ensure that they finish constructing what they need to construct before moving on to the next part.
print: function(pnl) {
if (!pnl) {
pnl = this;
}
// instantiate hidden iframe
var iFrameId = "printerFrame";
var printFrame = Ext.get(iFrameId);
if (printFrame === null) {
printFrame = Ext.getBody().appendChild({
id: iFrameId,
tag: 'iframe',
cls: 'x-hidden',
style: {
display: "none"
}
});
}
var cw = printFrame.dom.contentWindow;
var stylesheets = "";
var markup;
// instantiate application stylesheets in the hidden iframe
var printTask = new Ext.util.DelayedTask(function(){
// print the iframe
cw.print();
// destroy the iframe
Ext.fly(iFrameId).destroy();
});
var strTask = new Ext.util.DelayedTask(function(){
var str = Ext.String.format('<html><head>{0}</head><body>{1}</body></html>',stylesheets,markup);
// output to the iframe
cw.document.open();
cw.document.write(str);
cw.document.close();
// remove style attrib that has hardcoded height property
// cw.document.getElementsByTagName('DIV')[0].removeAttribute('style');
printTask.delay(500);
});
var markUpTask = new Ext.util.DelayedTask(function(){
// get the contents of the panel and remove hardcoded overflow properties
markup = pnl.getEl().dom.innerHTML;
while (markup.indexOf('overflow: auto;') >= 0) {
markup = markup.replace('overflow: auto;', '');
}
while (markup.indexOf('background: rgb(255, 192, 203) !important;') >= 0) {
markup = markup.replace('background: rgb(255, 192, 203) !important;', 'background: pink !important;');
}
strTask.delay(500);
});
var styleSheetConcatTask = new Ext.util.DelayedTask(function(){
// various style overrides
stylesheets += ''.concat(
"<style>",
".x-panel-body {overflow: visible !important;}",
// experimental - page break after embedded panels
// .x-panel {page-break-after: always; margin-top: 10px}",
"</style>"
);
markUpTask.delay(500);
});
var styleSheetCreateTask = new Ext.util.DelayedTask(function(){
for (var i = 0; i < document.styleSheets.length; i++) {
stylesheets += Ext.String.format('<link rel="stylesheet" href="{0}" />', document.styleSheets[i].href);
}
styleSheetConcatTask.delay(500);
});
styleSheetCreateTask.delay(500);
}