7b71ac65839f0f1c3eb3659ca1a48ebca980fab5
[tine20] / tine20 / Tinebase / js / ux / Printer / renderers / Base.js
1 /**
2  * @class Ext.ux.Printer.BaseRenderer
3  * @extends Object
4  * @author Ed Spencer
5  * Abstract base renderer class. Don't use this directly, use a subclass instead
6  */
7 Ext.ux.Printer.BaseRenderer = Ext.extend(Object, {
8   /**
9    * @cfg {String} printStrategy window or iframe
10    */
11   printStrategy: 'iframe',
12
13   /**
14    * @cfg {Boll} useHtml2Canvas
15    */
16   useHtml2Canvas: true,
17   
18   debug: false,
19   
20   constructor: function(config) {
21     Ext.apply(this, config);
22     
23     if (this.debug) {
24         this.printStrategy = 'window';
25     }
26     Ext.ux.Printer.BaseRenderer.superclass.constructor.call(this, config);
27   },
28
29   /**
30    * template method to intercept when document is ready
31    *
32    * @param {Document} document
33    * @pram {Ext.Component} component
34    */
35   onBeforePrint: Ext.emptyFn,
36
37   /**
38    * Prints the component
39    * @param {Ext.Component} component The component to print
40    */
41   print: function(component) {
42     return this[this.printStrategy + 'Print'](component);
43   },
44   
45   /**
46    * Prints the component using the new window strategy
47    * @param {Ext.Component} component The component to print
48    */
49   windowPrint: function(component) {
50     var name = component && component.getXType
51              ? String.format("print_{0}_{1}", String(component.getXType()).replace(/(\.|-)/g, '_'), component.id.replace(/(\.|-)/g, '_'))
52              : "print";
53
54     var win = window.open('', name);
55     
56     win.document.write(this.generateHTML(component));
57     win.document.close();
58
59     // gecko looses its document after document.close(). but fortunally waits with printing till css is loaded itself
60     return this.doPrint(win);
61     
62     this.doPrintOnStylesheetLoad.defer(10, this, [win, component]);
63   },
64   
65   /**
66    * Prints the component using the hidden iframe strategy
67    * @param {Ext.Component} component The component to print
68    */
69   iframePrint: function(component) {
70     var id = Ext.id(),
71     doc = document,
72     frame = doc.createElement('iframe');
73         
74     Ext.fly(frame).set({
75       id: id,
76       name: id,
77       style: {
78         position: 'absolute',
79         width: '210mm',
80         height: '297mm',
81         top: '-10000px',
82         left: '-10000px'
83       }
84     });
85     
86     doc.body.appendChild(frame);
87
88     Ext.fly(frame).set({
89       src : Ext.SSL_SECURE_URL
90     });
91
92     var doc = frame.contentWindow.document || frame.contentDocument || WINDOW.frames[id].document;
93         
94     doc.open();
95     doc.write(this.generateHTML(component));
96     doc.close();
97
98     this.doPrintOnStylesheetLoad.defer(10, this, [frame.contentWindow, component]);
99   },
100   
101   /**
102    * check if style is loaded and do print afterwards
103    * 
104    * @param {window} win
105    */
106   doPrintOnStylesheetLoad: function(win, component) {
107     var el = win.document.getElementById('csscheck'),
108         comp = el.currentStyle || getComputedStyle(el, null);
109     if (comp.display !== "none") {
110       return this.doPrintOnStylesheetLoad.defer(10, this, [win, component]);
111     }
112
113     this.onBeforePrint(win.document, component);
114
115     this.doPrint(win);
116   },
117
118   doPrint: function(win) {
119     if (this.useHtml2Canvas) {
120       var me = this;
121       html2canvas(win.document.body, {
122         grabMouse: false,
123         onrendered: function (canvas) {
124           var screenshot = canvas.toDataURL();
125           me.useHtml2Canvas = false;
126           win.document.body.innerHTML = '<img style="display: block; width: 100%" />';
127           win.document.body.firstChild.onload = me.doPrint.createDelegate(me, [win]);
128           win.document.body.firstChild.src = screenshot;
129         }
130       });
131     } else {
132       win.print();
133       if (!this.debug) {
134         win.close();
135       }
136     }
137   },
138   /**
139    * Generates the HTML Markup which wraps whatever this.generateBody produces
140    * @param {Ext.Component} component The component to generate HTML for
141    * @return {String} An HTML fragment to be placed inside the print window
142    */
143   generateHTML: function(component) {
144     return new Ext.XTemplate(
145       '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">',
146       '<html>',
147         '<head>',
148           '<meta content="text/html; charset=UTF-8" http-equiv="Content-Type" />',
149           this.getAdditionalHeaders(),
150           '<link href="' + this.stylesheetPath + '?' + new Date().getTime() + '" rel="stylesheet" type="text/css" media="screen,print" />',
151           '<title>' + this.getTitle(component) + '</title>',
152         '</head>',
153         '<body>',
154           '<div id="csscheck"></div>',
155           this.generateBody(component),
156         '</body>',
157       '</html>'
158     ).apply(this.prepareData(component));
159   },
160   
161   /**
162    * Returns the HTML that will be placed into the <head> element of th print window.
163    * @param {Ext.Component} component The component to render
164    * @return {String} The HTML fragment to place inside the print window's <head> element
165    */
166   getAdditionalHeaders: function(component) {
167     return '';
168   },
169   /**
170    * Returns the HTML that will be placed into the print window. This should produce HTML to go inside the
171    * <body> element only, as <head> is generated in the print function
172    * @param {Ext.Component} component The component to render
173    * @return {String} The HTML fragment to place inside the print window's <body> element
174    */
175   generateBody: Ext.emptyFn,
176   
177   /**
178    * Prepares data suitable for use in an XTemplate from the component 
179    * @param {Ext.Component} component The component to acquire data from
180    * @return {Array} An empty array (override this to prepare your own data)
181    */
182   prepareData: function(component) {
183     return component;
184   },
185   
186   /**
187    * Returns the title to give to the print window
188    * @param {Ext.Component} component The component to be printed
189    * @return {String} The window title
190    */
191   getTitle: function(component) {
192     return typeof component.getTitle == 'function' ? component.getTitle() : (component.title || "Printing");
193   },
194   
195   /**
196    * @property stylesheetPath
197    * @type String
198    * The path at which the print stylesheet can be found (defaults to 'stylesheets/print.css')
199    */
200   stylesheetPath: 'stylesheets/print.css'
201 });