PDA

View Full Version : Print Element



nerdydude81
21 Aug 2008, 7:29 AM
This is my first post. For my site I needed to print specific elements without using popup windows. I solved this by creating an iframe and inserting the html, then printing the hidden iframe. Here's my code, please make suggestions.



/**
* @version 0.4
* @author nerdydude81
*/
Ext.override(Ext.Element, {
/**
* @cfg {string} printCSS The file path of a CSS file for printout.
*/
printCSS: null
/**
* @cfg {Boolean} printStyle Copy the style attribute of this element to the print iframe.
*/
, printStyle: false
/**
* @property {string} printTitle Page Title for printout.
*/
, printTitle: document.title
/**
* Prints this element.
*
* @param config {object} (optional)
*/
, print: function(config) {
Ext.apply(this, config);

var el = Ext.get(this.id).dom;
var c = document.getElementById('printcontainer');
var iFrame = document.getElementById('printframe');

var strTemplate = '<HTML><HEAD>{0}<TITLE>{1}</TITLE></HEAD><BODY onload="{2}"><DIV {3}>{4}</DIV></BODY></HTML>';
var strLinkTpl = '<link rel="stylesheet" type="text/css" href="{0}"/>'
var strAttr = '';
var strFormat;
var strHTML;

//Get rid of the old crap so we don't copy it
//to our iframe
if (iFrame != null) c.removeChild(iFrame);
if (c != null) el.removeChild(c);

//Copy attributes from this element.
for (var i = 0; i < el.attributes.length; i++) {
if (Ext.isEmpty(el.attributes[i].value) || el.attributes[i].value.toLowerCase() != 'null') {
strFormat = Ext.isEmpty(el.attributes[i].value)? '{0}="true" ': '{0}="{1}" ';
if (this.printStyle? this.printStyle: el.attributes[i].name.toLowerCase() != 'style')
strAttr += String.format(strFormat, el.attributes[i].name, el.attributes[i].value);
}
}

var strLink ='';
if(this.printCSS){
if(!Ext.isArray(this.printCSS))
this.printCSS = [this.printCSS];

for(var i=0; i<this.printCSS.length; i++) {
strLink += String.format(strLinkTpl, this.printCSS[i]);
}
}

//Build our HTML document for the iframe
strHTML = String.format(
strTemplate
, strLink
, this.printTitle
, Ext.isIE? 'document.execCommand(\'print\');': 'window.print();'
, strAttr
, el.innerHTML
);

//I coun't get FF to print a hidden iframe,
//so I encapsulated it in a hidden div.
c = document.createElement('div');
c.setAttribute('style','width:0px;height:0px;' + (Ext.isSafari? 'display:none;': 'visibility:hidden;'));
c.setAttribute('id', 'printcontainer');
el.appendChild(c);

//IE doesn't like style attributes anymore?
if (Ext.isIE)
c.style.display = 'none';

iFrame = document.createElement('iframe');
iFrame.setAttribute('id', 'printframe');
iFrame.setAttribute('name', 'printframe');
c.appendChild(iFrame);

//Write our new document to the iframe
iFrame.contentWindow.document.open();
iFrame.contentWindow.document.write(strHTML);
iFrame.contentWindow.document.close();
}
});

Ext.override(Ext.Component, {
printEl: function(config) {
this.el.print(Ext.isEmpty(config)? this.initialConfig: config);
}
, printBody: function(config) {
this.body.print(Ext.isEmpty(config)? this.initialConfig: config);
}
});

kekoav
22 Aug 2008, 3:21 PM
Thanks for that great piece of code it worked flawlessly, without any goofy setup either!

It does exactly what it needs to do, I was going to do something similar, but glad I found you beat me to it!

NO issues yet.

vasan_sr@yahoo.com
2 Sep 2008, 6:18 AM
Iam new to Ext JS. I saw your code but uanable to execute it

Can you please explain me with an Example.

Thanks
VasanS

galdaka
2 Sep 2008, 7:09 AM
Live example or screenshot please!!


Greetngs,

nerdydude81
2 Sep 2008, 9:44 AM
I'll see if I can get an example setup. It's usage it fairly simple

/**
* Prints an element on the page. Copies all attributes except
* style, unless specified.
* @param {node} el Element to print out
* @param {string} style CSS Style file for printing
* @param {number} pageWidth Page width in inches
* @param {number} pageHeight Page height in inches
* @param {boolean} elStyle Copy the Elements style attribute
*/


@param {node} el Element to print outThis is the parent container that you want printed. Everything within this node will be printed. Populate this parameter using the actual DOM node.

Like:


var myElement = document.getElementByID('MyDiv');

SS.printElement(myElement, ....

@param {string} style CSS Style file for printingBecause this function copies the node to a hidden iframe, your CSS file won't be applied. To solve this I'm adding a link tag to the html in the iframe. This can also be useful if you have a different style sheet for printing. Populate this parameter with the path for your css file or make it a null string (' ' or "").

Like


var myElement = document.getElementByID('MyDiv');
var cssPath = '/css/gridprint.css';

SS.printElement(myElement, cssPath, ....


@param {number} pageWidth Page width in inches
@param {number} pageHeight Page height in inches
The page size is self explainitory

Like


var myElement = document.getElementByID('MyDiv');
var cssPath = '/css/gridprint.css';
var pageWidth = 8.5;
var pageHeight = 11;

SS.printElement(myElement, cssPath, pageWidth, pageHeight, ....

@param {boolean} elStyle Copy the Elements style attributeBecause this function copies all the attributes on the Element node, I chose to exclude the style attribute; however if it's needed set this parameter to true.

Like


var myElement = document.getElementByID('MyDiv');
var cssPath = '/css/gridprint.css';
var pageWidth = 8.5;
var pageHeight = 11;

SS.printElement(myElement, cssPath, pageWidth, pageHeight, true);
For Extjs you could do something like


var myPanel = new Ext.Panel({some stuff here});

SS.printElement(myPanel.getEl().dom, '/css/gridprint.css', 8.5, 11, true);
Hope this helps out.

TopKatz
3 Sep 2008, 6:35 AM
Is there another part to configuring this for use? Im getting a "SS is not defined" error with it.

nerdydude81
3 Sep 2008, 7:56 AM
You can take the SS off, change it, declare it or add it's namespace to Ext via Ext.namespace("SS"). Some people here are using the Ext.ux namespace, I'll update the code to make it easier. SS is just the initials for my company.

TopKatz
3 Sep 2008, 8:32 AM
I actualy had tried that with more success, but I was still getting errors. I figured out the problem. You have what looks like a type-O in the code.


for (var I = 0; I < el.attributes.length; I++) {
if (elStyle? elStyle: el.attributes[i].name.toLowerCase() != 'style') {
strAttr += String.format('{0}="{1}" ', el.attributes[i].name, el.attributes[i].value);
}
}


should be:


for (var i = 0; i < el.attributes.length; i++) {
if (elStyle? elStyle: el.attributes[i].name.toLowerCase() != 'style') {
strAttr += String.format('{0}="{1}" ', el.attributes[i].name, el.attributes[i].value);
}
}


the upper case "I" should be "i"

BTW: this only seams to work once per page load. Any reason in particular for that?

Tasm
3 Sep 2008, 8:37 AM
Hi sorry for my english, i dont test this extension yet, but i think will be cool to override Ext.Element for add method print:


Ext.override(Ext.Element, {
print: function(style, pageWidth, pageHeight, elStyle) {
var el = this.dom;
...
}
});

And use so:


var myEl = Ext.Element({...})
myEl.print(style, pageWidth, pageHeight, elStyle);

devnull
3 Sep 2008, 9:38 AM
Pretty cool stuff :)
I would highly recommend using a config object rather than params though since everything else in Ext uses this pattern wherever possible.


SS.printElement({
element: myElement, //having this accept an Ext.element reference or a string id might be nice too
pageWidth: 200,
pageHeight: 400,
//etc
})

nerdydude81
3 Sep 2008, 12:33 PM
I decided to go with an override, I've solved the issue TopKatz found with printing more than once.

Tasm,
Thanks for the idea, I'm still debating if Ext.Element is the right class to override. Maybe Ext.Component, or Ext.Container?

Devnull,
I added the config to the Ext.Component.

TopKatz -

Tasm
4 Sep 2008, 2:04 AM
I'm still debating if Ext.Element is the right class to override. Maybe Ext.Component, or Ext.Container
I think Ext.Element will be better desing becouse Ext.Element not extends from Ext.Component but each Ext.Component contains Ext.Element and we can use

someCmp.el.print({...})or

someCmp.body.print({..})But it may be useful to add delegated methods to Ext.Component like this:

Ext.override(Ext.Component, {
printEl: function(config) {
this.el.print(config)
},

printBody: function(config) {
this.body.print(config)
}
});

TopKatz
4 Sep 2008, 5:01 AM
This is working very well.

I do have a question: This appears to only handle Ext components now, where the last code could take either an Ext cmp, or a dom el. Is there a way to get this to take a regular element. Or would overriding El handle both?

TopKatz
4 Sep 2008, 5:27 AM
I handed it a config string but it seams to be ignoring it:



Ext.getCmp('tabSched').print({
printCss:'/css/hcaStyle.css',
printWidth:11,
printHeight:8.5
});


this should use my css, and print it landscape. However its not applying the css, and its still portrait. Im I doing something wrong?

Do I need to take out the default config in the code? I figured my config would override the default?

nerdydude81
4 Sep 2008, 5:31 AM
I think Ext.Element will be better desing becouse Ext.Element not extends from Ext.Component but each Ext.Component contains Ext.Element

Good point Tasm. I added the delegates to the Ext.Component; however it would be nice to still be able to set the config for the print function in the component's initial config. Can you think of anyway to accomplish this without modifying the constructor?

TopKatz, I changed it back to Ext.Element you should be able to use Ext.get('someID').printEL to print any element on the page.

nerdydude81
4 Sep 2008, 5:38 AM
I think Ext.Element will be better desing becouse Ext.Element not extends from Ext.Component but each Ext.Component contains Ext.Element
Good point Tasm. I added the delegates to the Ext.Component; however it would be nice to still be able to set the config for the print function in the component's initial config. Can you think of anyway to accomplish this without modifying the constructor?



I just figured it out. I forgot about the initialConfig property.

nerdydude81
4 Sep 2008, 6:31 AM
I handed it a config string but it seams to be ignoring it:



Ext.getCmp('tabSched').print({
printCss:'/css/hcaStyle.css',
printWidth:11,
printHeight:8.5
});
this should use my css, and print it landscape. However its not applying the css, and its still portrait. Im I doing something wrong?

Do I need to take out the default config in the code? I figured my config would override the default?

printCSS: '/css/hcaStyle.css',
You can set the size to landscape but the user must configure their printer for landscape as well. I don't know if there is a way to force a page size for the printer.

jt
11 Sep 2008, 7:47 AM
I thought I would give the Print Element a try and it seems to be working flawlessly.

Thanks to everyone that made this component what it is. :D


The only question I have is with the CSS file.
Does anyone have an example of how to print a Terms & Conditions page with the text wrapping in the iFrame?
Currently when I print it using this extension the text doesn't wrap and gets cutoff on the printout.

Thanks for any and all help.

Justin.

nerdydude81
11 Sep 2008, 8:29 AM
I thought I would give the Print Element a try and it seems to be working flawlessly.

Thanks to everyone that made this component what it is. :D


The only question I have is with the CSS file.
Does anyone have an example of how to print a Terms & Conditions page with the text wrapping in the iFrame?
Currently when I print it using this extension the text doesn't wrap and gets cutoff on the printout.

Thanks for any and all help.

Justin.


If the text display's correctly in the element or component your trying to print then it should display correctly in the iframe. Is all your style code within a CSS file or did you set some in the component's or element's style property? Have you checked the printCSS property, does it have the correct path? I'd be glade to help anyway I can.

Jack

jt
11 Sep 2008, 8:38 AM
Jack,

Here is some context. I have an Ext Window that has a panel with the Terms & Conditions text.

When I resize the window the text also resizes, wraps and has a scroll bar.

If I include the config property printCSS it pulls in my css file (eg. printCSS='css/print.css').
I have also been able to include other CSS files from my print.css file via @import statements.

However when I print the Terms & Conditions text it doesn't seem to wrap and the text gets chopped off.
(When I say print, I mean print to PDF so I can save paper and ink ;)).

There are no other styles applied to any of the components that I am trying to print.

Justin.

nerdydude81
11 Sep 2008, 9:14 AM
Justin,
I think the problem you're having is related to the style for the window or panel, which is normally defined in the ext-all.css or it's related file. Try naming the panel and setting its width in your print.css file. If this works, let me know so I can work on a more permanent solution.

Thanks,
Jack

jt
12 Sep 2008, 11:43 AM
Jack,

I found the problem.

In Firefox it prints properly, but IE was causing the issue.

The problem with IE is that it always gives you all of the attributes for an element even if they are unset (null or blank values). Plus it seems to have a problem with values that are boolean as it doesn't convert them properly when we readd the attribute to the div.

If you add the attribute


noWrap='false'

for some reason IE interprets it as


noWrap='True'

which is what was causing the problem.

Firefox only returns you the attributes that you have actually set. :D

So in order for me to get it to work I have changed the following:


for (var i = 0; i < el.attributes.length; i++) {
if (this.printStyle? this.printStyle: el.attributes[i].name.toLowerCase() != 'style') {
strAttr += String.format('{0}="{1}" ', el.attributes[i].name, el.attributes[i].value);
}
}

to


for (var i = 0; i < el.attributes.length; i++) {
if (this.printStyle? this.printStyle: el.attributes[i].name.toLowerCase() != 'style') {
var name = el.attributes[i].name;
var value = el.attributes[i].value;
if (value == null || value == 'null' || value == '') {
// IE returns unset attributes that have empty or null values??
continue;
}
if (value == 'true' || value == 'false') {
// IE is unable to handle setting attributes that have a boolean value??
continue;
}
strAttr += String.format('{0}="{1}" ', name, value);
}
}


I also noticed, and this might just be me, that the printWidth and printHeight variables didn't seem to do anything. I even managed to remove them from the code and everything still printed properly.


I welcome any help to make it cleaner, as I just needed to get it working.

Thanks for all your help.

Justin.

nerdydude81
7 Oct 2008, 6:50 AM
Sorry for the long delay in my response, things have been a little crazy here at work.

The noWrap was initially intended to be a flag, it's presents indicated true and absents was false. IE maybe being lazy and not parsing it's value, assuming it to be true because it's present. Have you tried using it's CSS replacement whitespace (http://www.w3schools.com/CSS/pr_text_white-space.asp)?


I've removed the width & height from the code. They aren't really needed, I didn't know the browser would re-render the page for printout based on the print media.

I also excluded attributes with 'null' values, and attempted to account for flags such as noWrap setting them to true.

Michael85
8 Oct 2008, 11:53 AM
I'm *very* new to extjs and I'm running into trouble trying to get this to work properly.

I'm getting an error in firebug on this line:

if (iFrame != null) c.removeChild(iFrame);

The error is:

Node was not found" code: "8

To put this context a bit more, I have an extjs window open with an iframe appended to it with the following line: frameWin.body.appendChild(ifrm); When making the call to our print function, i use the following line: frameWin.body.print();

It should be noted that I have custom css in the head portion of the html in my iframe. Not sure if that would have any effect. Any ideas? I'll try to elaborate on as much as I can, but I tend to be pretty bad at explaining things. Apologies ahead of time.

nerdydude81
8 Oct 2008, 12:17 PM
Can you comment out line 39? Does this solve your problem?




//if (iFrame != null) c.removeChild(iFrame);

Michael85
8 Oct 2008, 1:17 PM
Actually, I commented out the following lines:

if (iFrame != null) c.removeChild(iFrame);
if (c != null) el.removeChild(c);

And:

//I coun't get FF to print a hidden iframe,
//so I encapsulated it in a hidden div.
c = document.createElement('div');
c.setAttribute('style','width:0px;height:0px;visibility:hidden;');
c.setAttribute('id', 'printcontainer');
el.appendChild(c);

//IE doesn't like style attributes anymore?
if (Ext.isIE)
c.style.display = 'none';


Now it seems to be working again, but it's completely ignoring the css that i'm trying to apply to it. So, to recap, css is applied to the original iFrame. That css is lost in translation and is not being replaced by the printCSS file that I'm assigning.

Is this why you were trying to remove the original iframe? Because it would overwrite the css?

nerdydude81
8 Oct 2008, 1:22 PM
The lines



if (iFrame != null) c.removeChild(iFrame);
if (c != null) el.removeChild(c);


are to remove a previously printed element. The code creates it's own hidden iframe, how are you attempting to print? What other iframe are you talking about?

Thanks,
Jack

vtswingkid
18 Nov 2008, 7:34 PM
Great work on this extension!

Here are some changes to allow multiple style sheets to be loaded...



var strTemplate ='<HTML><HEAD>{0}<TITLE>{1}</TITLE></HEAD><BODY onload="{2}"><DIV {3}>{4}</DIV></BODY></HTML>';
var strLinkTpl ='<link rel="stylesheet" type="text/css" href="{0}"/>';


//Build our HTML document for the iframe
var strLink ='';
if(this.printCSS){
if(!Ext.isArray(this.printCSS))this.printCSS=[this.printCSS];
for(var i=0;i<this.printCSS.length;i++){
strLink += String.format(strLinkTpl,this.printCSS[i]);
}
}
strHTML = String.format(strTemplate, strLink,this.printTitle, Ext.isIE ?'document.execCommand(\'print\');':'window.print();', strAttr, el.innerHTML);



just set this.printCSS to an array of style sheet links.

nerdydude81
19 Nov 2008, 6:54 AM
Nice addition, I'll test it in my latest code and update the first post.

Thanks

nerdydude81
19 Nov 2008, 7:13 AM
I tested it on IE7, Chrome, Safari, & FF3. First post is updated

Thanks,
Jack

Michael85
24 Nov 2008, 2:42 PM
If anyone finds the original code a bit intimidating in its complexity, I found this to work just as well for my purposes:



var ifrm = document.createElement("IFRAME");
ifrm.id = 'printframe'; //set print frame id
ifrm.src = htmlContent; //straight html, or the url that generates the html content
ifrm.style.width = "100%";
ifrm.style.height = "100%";

if (Ext.isIE){
//IE requires focus on the frame
document.frames(ifrm.id).focus();
document.frames(ifrm.id).print();
}else{
//Firefox is smart enough to do it on its own
ifrm.contentWindow.window.print();
}

Prior to this, I appended the iframe to a window with this:



frameWin.show(); //render window first
frameWin.body.appendChild(ifrm); //add iframe second

EDIT: Oh yeah, as for the css problem, since i'm working within the asp.net framework, i just made a css file and linked it in the head portion of the html.



<link type=""text/css"" href=""PathHere/print.css"" rel=""stylesheet"" media=""all"" />

nerdydude81
24 Nov 2008, 3:07 PM
Michael85,

Your code renders the printout to the user, I wanted to be able print any element without the use of popup windows and/or re-rendering the content to the user. I also wanted to print the element by calling a function on the ExtJs component.

ie:


MyExtJsPanel.printEl();


Though it could probably be commented and/or formated better, the complexity of my code allows printing via a hidden iframe, applying custom StyleSheets, Setting a Page Title, and stripping the style attribute.

This would be "Overkill" if you're just opening a popup window and printing, or if you're rendering the content in an iframe already. In that case I would use something similar to what you contributed.

Thanks,
Jack

k_lib
18 Feb 2009, 6:10 AM
Hi I created a print icon in a Ext.toolbar calling the handler printMe and then i'm trying to call printEl as a function but it doesn't seem to be working. I'm new to Ext so let me know if i'm way off.


var printMe = function(){
Ext.namespace("SS");
var myElement= document.getElementById("contentDiv");
SS.printEl(myElement);
}i get the firebug error of SS.printEl is not a function but i have all the of the code at the bottom of my js.

help :((

nerdydude81
18 Feb 2009, 9:18 AM
Hi I created a print icon in a Ext.toolbar calling the handler printMe and then i'm trying to call printEl as a function but it doesn't seem to be working. I'm new to Ext so let me know if i'm way off.


var printMe = function(){
Ext.namespace("SS");
var myElement= document.getElementById("contentDiv");
SS.printEl(myElement);
}i get the firebug error of SS.printEl is not a function but i have all the of the code at the bottom of my js.

help :((



var printMe = function() {
var el = Ext.get("contentDiv");
el.print({
printCSS: 'a css file path'
});
}

k_lib
18 Feb 2009, 10:08 AM
Thank you! that did the trick.

Now that the printing works I only get a little bit of the content. It prints out 3 pages , I assume that is all the hidden content. I have been looking everywhere for a way to turn off the overflow constraints but i can't seem to find it. If it helps these are my settings for that div



var dataPanel = new Ext.Panel({
id:'contentDiv',
region:'center',
layout:'fit',
width:400,
...
and the over all height is being set at



var mainpanel = new Ext.Panel({
layout:'border',
applyTo:divTag,
width:800,
height:700,
items:[tb, centerPanel, footerPanel]
});
any clues??? I am guessing i would change those when printing, maybe?

Thanks!

zombeerose
18 Feb 2009, 10:47 AM
Will this plugin work with grids? It worked fine for a panel but when I tried to print a grid, I got the following error in FF3:


[Exception... "Node was not found" code: "8" nsresult: "0x80530008 (NS_ERROR_DOM_NOT_FOUND_ERR)" location: "http://.../Ext.ux.Element.Print.js Line: 40"]

The error went away when I commented out
if (c != null) el.removeChild(c); but I don't want to modify your source.

DigitalSkyline
20 Feb 2009, 1:07 PM
My first thought on this ux was that it's cool, but would probably not work for grids.

There is another extension for printing grids... you might try that ;)

johnleroux
14 Mar 2009, 1:34 AM
The changed source below will print grids.

Call with:

grid.printEl({printCSS: '../../resources/css/ext-all.css', printStyle: true, isGrid: true, printTitle: 'Test'});Changed source


/**
* @version 0.4
* @author nerdydude81
*/Ext.override(Ext.Element, {
/**
* @cfg {string} printCSS The file path of a CSS file for printout.
*/
printCSS: null,
/**
* @cfg {Boolean} printStyle Copy the style attribute of this element to the print iframe.
*/
printStyle: false,
/**
* @property {string} printTitle Page Title for printout.
*/
printTitle: document.title,
/**
* Prints this element.
*
* @param config {object} (optional)
*/
print: function(config) {
Ext.apply(this, config);

var el = Ext.get(this.id).dom;
if (this.isGrid)
el = el.parentNode;

var c = document.getElementById('printcontainer');
var iFrame = document.getElementById('printframe');

var strTemplate = '<HTML><HEAD>{0}<TITLE>{1}</TITLE></HEAD><BODY onload="{2}"><DIV {3}>{4}</DIV></BODY></HTML>';
var strLinkTpl = '<link rel="stylesheet" type="text/css" href="{0}"/>'
var strAttr = '';
var strFormat;
var strHTML;

if (c) {
if (iFrame)
c.removeChild(iFrame);
el.removeChild(c);
}

for (var i = 0; i < el.attributes.length; i++) {
if (Ext.isEmpty(el.attributes[i].value) || el.attributes[i].value.toLowerCase() != 'null') {
strFormat = Ext.isEmpty(el.attributes[i].value)? '{0}="true" ': '{0}="{1}" ';
if (this.printStyle? this.printStyle: el.attributes[i].name.toLowerCase() != 'style')
strAttr += String.format(strFormat, el.attributes[i].name, el.attributes[i].value);
}
}

var strLink ='';
if(this.printCSS){
if(!Ext.isArray(this.printCSS))
this.printCSS = [this.printCSS];

for(var i=0; i<this.printCSS.length; i++) {
strLink += String.format(strLinkTpl, this.printCSS[i]);
}
}

strHTML = String.format(
strTemplate,
strLink,
this.printTitle,
'',
strAttr,
el.innerHTML
);

c = document.createElement('div');
c.setAttribute('style','width:0px;height:0px;' + (Ext.isSafari? 'display:none;': 'visibility:hidden;'));
c.setAttribute('id', 'printcontainer');
el.appendChild(c);
if (Ext.isIE)
c.style.display = 'none';

iFrame = document.createElement('iframe');
iFrame.setAttribute('id', 'printframe');
iFrame.setAttribute('name', 'printframe');
c.appendChild(iFrame);

iFrame.contentWindow.document.open();
iFrame.contentWindow.document.write(strHTML);
iFrame.contentWindow.document.close();

if (this.isGrid) {
var iframeBody = Ext.get(iFrame.contentWindow.document.body);
var cc = Ext.get(iframeBody.first().dom.parentNode);
cc.child('div.x-panel-body').setStyle('height', '');
cc.child('div.x-grid3').setStyle('height', '');
cc.child('div.x-grid3-scroller').setStyle('height', '');
}
if (Ext.isIE)
iFrame.contentWindow.document.execCommand('print');
else
iFrame.contentWindow.print();
}
});

g13013
18 Apr 2009, 1:58 AM
i added 3 new options that are usefull when we need to customize printing for every element:
css: pure css text, i added it beacause in case whe create a css rules dynamically for example with Ext.util.CSS.createStyleSheet(), whe can't add it like a external stylesheet, so we can get css text and put it int this param.
addHeader:html that we can add as header before element to print
addFooter:html that we can add as footer after element to print


Ext.override(Ext.Element, {
/**
* @cfg {string} css A string containing a css style text.
*/
css: ''
/**
* @cfg {string} printCSS The file path of a CSS file for printout.
*/
,printCSS: null
/**
* @cfg {string} addHeader Additional HTML text to add a the top.
*/
, addHeader: ''
/**
* @cfg {string} addFooter Additional HTML text to add a the bottom.
*/
, addFooter: ''
/**
* @cfg {Boolean} printStyle Copy the style attribute of this element to the print iframe.
*/
, printStyle: true
/**
* @property {string} printTitle Page Title for printout.
*/
, printTitle: document.title
/**
* Prints this element.
*
* @param config {object} (optional)
*/
, print: function(config) {
Ext.apply(this, config);

var el = Ext.get(this.id).dom;
var c = document.getElementById('printcontainer');
var iFrame = document.getElementById('printframe');

var strTemplate = '<HTML><HEAD>{0}<TITLE>{1}</TITLE><style type="text/css">'+this.css+'</style></HEAD><BODY onload="{2}"><DIV>'+this.addHeader+'</DIV><DIV width="100%" {3}>{4}</DIV><DIV>'+this.addFooter+'</DIV></BODY></HTML>';
var strLinkTpl = '<link rel="stylesheet" type="text/css" href="{0}"/>'
var strAttr = '';
var strFormat;
var strHTML;

//Get rid of the old crap so we don't copy it
//to our iframe
if (iFrame != null) c.removeChild(iFrame);
if (c != null) el.removeChild(c);

//Copy attributes from this element.
for (var i = 0; i < el.attributes.length; i++) {
if (Ext.isEmpty(el.attributes[i].value) || el.attributes[i].value.toLowerCase() != 'null') {
strFormat = Ext.isEmpty(el.attributes[i].value)? '{0}="true" ': '{0}="{1}" ';
if (this.printStyle? this.printStyle: el.attributes[i].name.toLowerCase() != 'style')
strAttr += String.format(strFormat, el.attributes[i].name, el.attributes[i].value);
}
}

var strLink ='';
if(this.printCSS){
if(!Ext.isArray(this.printCSS))
this.printCSS = [this.printCSS];

for(var i=0; i<this.printCSS.length; i++) {
strLink += String.format(strLinkTpl, this.printCSS[i]);
}
}

//Build our HTML document for the iframe
strHTML = String.format(
strTemplate
, strLink
, this.printTitle
, Ext.isIE? 'document.execCommand(\'print\');': 'window.print();'
, strAttr
, el.innerHTML
);
//I coun't get FF to print a hidden iframe,
//so I encapsulated it in a hidden div.
c = document.createElement('div');
c.setAttribute('style','width:0px;height:0px;' + (Ext.isSafari? 'display:none;': 'visibility:hidden;'));
c.setAttribute('id', 'printcontainer');
el.appendChild(c);

//IE doesn't like style attributes anymore?
if (Ext.isIE)
c.style.display = 'none';

iFrame = document.createElement('iframe');
iFrame.setAttribute('id', 'printframe');
iFrame.setAttribute('name', 'printframe');
c.appendChild(iFrame);

//Write our new document to the iframe
iFrame.contentWindow.document.open();
iFrame.contentWindow.document.write(strHTML);
iFrame.contentWindow.document.close();
}
});

Ext.override(Ext.Component, {
printEl: function(config) {
this.el.print(Ext.isEmpty(config)? this.initialConfig: config);
}
, printBody: function(config) {
this.body.print(Ext.isEmpty(config)? this.initialConfig: config);
}
});

g13013
18 Apr 2009, 2:00 AM
just a question, is this pluging is able to print hidden areas of the element, because a can't print element that have scroll anabled

nerdydude81
20 Apr 2009, 6:00 AM
The browser will only print the visible nodes, I would suggest adjusting the overflow property on the node before print. You should be able to override it using the printcss file, or your css property. Sorry I checkout for so long, I've been overwhelmed at work with a new solr setup.

Jack

g13013
21 Apr 2009, 6:09 AM
thank you, i will try to do with css and inform you.

cnesbit
15 May 2009, 5:49 AM
I had found some other "Printer Friendly"-ifier code for extjs, but it involved lots of code spread over lots of files (too complicated). This, however, is a much more cut and dry tool! It is a great!

But... I've got an extjs "email client" which displays the email's body in a read only textarea. how would I go about tailoring this tool to print the contents of that textarea? It seems to ignore "iFrame.contentWindow.document.open(); " even though I added the following code to make this work with extjs form fields:


strHTML = String.format(
strTemplate
, strLink
, this.printTitle
, Ext.isIE? 'document.execCommand(\'print\');': 'window.print();'
, strAttr
, (el.innerHTML?el.innerHTML:(el.value?el.value:""))
);Also, there are several versions of this awesome tool posted throughout this thread. Could you repost the most up to date version of this tool back to the first post please, so we can all benefit from everyone's input?

Thanks so much!
cnesbit

jineshkunnath
7 Jul 2009, 5:28 AM
hello sir
please help me . i didn't get the styles what i pass through the style sheet
This is my sample pgm. i am try to pass the styles to my print page. but i failed. i tried lot about that.
couldn't get any solution
this is my code
please help me
var p = new Ext.Panel({
title: 'My Panel',
id:'p',
renderTo: document.body,
width:400,
html: "<div class='colorcls'>test Print is working. </div>"
});

Ext.get('p').print({
printCss:'/printcss/print.css',
printWidth:11,
printHeight:8.5
});

fanzhongkai
26 Jul 2009, 11:34 PM
If the target element contains <embed> which is a ".swf" picture, How can I print this component.

moegal
2 Apr 2010, 3:38 PM
Hi,

This is very nice but I am having a problem.

When I click print, the element that I am printing gets re-sized and adds scrollbars. to the right and bottom and in Firefox only. IE is kinda fine

Also, the fields are printing out as blank boxes in Firefox. Grids print fine except for the resizing.

Any ideas?

Marty

bhaidaya
17 Mar 2011, 4:13 AM
This thread feels dead but here goes.. might still be useful info for someone:

if you are getting the error
Node was not found" code: "8

swap out the following lines


if (c !== null) el.removeChild(c);

with


if (c !== null) document.body.removeChild(c);


and



el.appendChild(c);

with


document.body.appendChild(c);


This error arises when you have multiple elements that try and use the print function ( on second print). Previously it would append the iframe to the element trying to be printed and when a new element was asked to be printed it would look at itself to find the iframe not finding it.

The changed way included above simply appends it to the bottom of the pages markup making it easier to clean up upon second attempt.

creepi
18 Apr 2011, 10:16 PM
This thread seems to be dead but i give it a try at least.
I could really use the functionallity of this orverride for printing a Form which is in a Window.
The problem is that in all Browsers expect the Mozilla Firefox the values of the FormFields are given to the iframe.
It seems to be the problem that Ext JS saves the values of an input Tag in el.dom.value and sth. like IE in the values option of the input field.
Is there a way to get the Form Field Values printet out of the firefox ?

Would be nice to get an reply.

extjs-dev
19 May 2011, 10:16 AM
This thread seems to be dead but i give it a try at least.
I could really use the functionallity of this orverride for printing a Form which is in a Window.
The problem is that in all Browsers expect the Mozilla Firefox the values of the FormFields are given to the iframe.
It seems to be the problem that Ext JS saves the values of an input Tag in el.dom.value and sth. like IE in the values option of the input field.
Is there a way to get the Form Field Values printet out of the firefox ?

Would be nice to get an reply.

I am having the same problem. Did you get this working? If so, could you share the solution?