Printer.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. define("dojox/grid/enhanced/plugins/Printer", [
  2. "dojo/_base/declare",
  3. "dojo/_base/html",
  4. "dojo/_base/Deferred",
  5. "dojo/_base/lang",
  6. "dojo/_base/sniff",
  7. "dojo/_base/xhr",
  8. "dojo/_base/array",
  9. "dojo/query",
  10. "dojo/DeferredList",
  11. "../_Plugin",
  12. "../../EnhancedGrid",
  13. "./exporter/TableWriter"
  14. ], function(declare, html, Deferred, lang, has, xhr, array, query, DeferredList, _Plugin, EnhancedGrid, TableWriter){
  15. var Printer = declare("dojox.grid.enhanced.plugins.Printer", _Plugin, {
  16. // summary:
  17. // Provide printGrid function to the grid.
  18. // example:
  19. // | dojo.require("dojox.grid.enhanced.plugins.Printer");
  20. // | dijit.byId("grid1").printGrid("my grid", //A title for the grid,optional
  21. // | ["cssfile1.css","cssfile2.css"],//An array of css files to decorate the printed gird,optional
  22. // | {table:"border='border'"} //tagName:"attrbuteList" pairs, optional,
  23. // | //control the html tags in the generated html
  24. // | );
  25. // __printArgs: {
  26. // title: String
  27. // A title of the printed page can be specified. Optional.
  28. // If given, it's shown in an <h1> tag at the top of the page.
  29. // cssFiles: Array | String
  30. // CSS file paths. Optional.
  31. // Every row and column is given CSS classes, including:
  32. // grid_row_{row-number}, grid_odd_row, grid_even_row, grid_header,
  33. // grid_col_{col-number}, grid_odd_col, grid_even_col
  34. // {row_number} and {col-number} are both integers starting from 1.
  35. // Row classes are for <thead> and <tbody> tags.
  36. // Column classes are for <th> and <td> tags.
  37. // Users can use these classes in the CSS files, but cannot define their own.
  38. // writerArgs: Object (Association Array)
  39. // Arguments for TableWriter.
  40. // fetchArgs: object?
  41. // Any arguments for store.fetch
  42. // }
  43. // name: String
  44. // Plugin name
  45. name: "printer",
  46. constructor: function(grid){
  47. // summary:
  48. // only newed by _Plugin
  49. // inGrid: EnhancedGrid
  50. // The grid to plug in to.
  51. this.grid = grid;
  52. this._mixinGrid(grid);
  53. //For print, we usually need the HTML instead of raw data.
  54. grid.setExportFormatter(function(data, cell, rowIndex, rowItem){
  55. return cell.format(rowIndex, rowItem);
  56. });
  57. },
  58. _mixinGrid: function(){
  59. var g = this.grid;
  60. g.printGrid = lang.hitch(this, this.printGrid);
  61. g.printSelected = lang.hitch(this, this.printSelected);
  62. g.exportToHTML = lang.hitch(this, this.exportToHTML);
  63. g.exportSelectedToHTML = lang.hitch(this, this.exportSelectedToHTML);
  64. g.normalizePrintedGrid = lang.hitch(this, this.normalizeRowHeight);
  65. },
  66. printGrid: function(args){
  67. // summary:
  68. // Print all the data in the grid, using title as a title,
  69. // decorating generated html by cssFiles,
  70. // using tagName:"attrbuteList" pairs(writerArgs) to control html tags
  71. // in the generated html string.
  72. // tags:
  73. // public
  74. // args: __printArgs?
  75. // Arguments for print.
  76. this.exportToHTML(args, lang.hitch(this, this._print));
  77. },
  78. printSelected: function(args){
  79. // summary:
  80. // Print selected data. All other features are the same as printGrid.
  81. // For meaning of arguments see function *printGrid*
  82. // tags:
  83. // public
  84. // args: __printArgs?
  85. // Arguments for print.
  86. this.exportSelectedToHTML(args, lang.hitch(this, this._print));
  87. },
  88. exportToHTML: function(args, onExported){
  89. // summary:
  90. // Export to HTML string, but do NOT print.
  91. // Users can use this to implement print preview.
  92. // For meaning of the 1st-3rd arguments see function *printGrid*.
  93. // tags:
  94. // public
  95. // args: __printArgs?
  96. // Arguments for print.
  97. // onExported: function(string)
  98. // call back function
  99. args = this._formalizeArgs(args);
  100. var _this = this;
  101. this.grid.exportGrid("table", args, function(str){
  102. _this._wrapHTML(args.title, args.cssFiles, args.titleInBody + str).then(onExported);
  103. });
  104. },
  105. exportSelectedToHTML: function(args, onExported){
  106. // summary:
  107. // Export selected rows to HTML string, but do NOT print.
  108. // Users can use this to implement print preview.
  109. // For meaning of arguments see function *printGrid*
  110. // tags:
  111. // public
  112. // args: __printArgs?
  113. // Arguments for print.
  114. args = this._formalizeArgs(args);
  115. var _this = this;
  116. this.grid.exportSelected("table", args.writerArgs, function(str){
  117. _this._wrapHTML(args.title, args.cssFiles, args.titleInBody + str).then(onExported);
  118. });
  119. },
  120. _loadCSSFiles: function(cssFiles){
  121. var dl = array.map(cssFiles, function(cssFile){
  122. cssFile = lang.trim(cssFile);
  123. if(cssFile.substring(cssFile.length - 4).toLowerCase() === '.css'){
  124. return xhr.get({
  125. url: cssFile
  126. });
  127. }else{
  128. var d = new Deferred();
  129. d.callback(cssFile);
  130. return d;
  131. }
  132. });
  133. return DeferredList.prototype.gatherResults(dl);
  134. },
  135. _print: function(/* string */htmlStr){
  136. // summary:
  137. // Do the print job.
  138. // tags:
  139. // private
  140. // htmlStr: String
  141. // The html content string to be printed.
  142. // returns:
  143. // undefined
  144. var win, _this = this,
  145. fillDoc = function(w){
  146. var doc = w.document;
  147. doc.open();
  148. doc.write(htmlStr);
  149. doc.close();
  150. _this.normalizeRowHeight(doc);
  151. };
  152. if(!window.print){
  153. //We don't have a print facility.
  154. return;
  155. }else if(has("chrome") || has("opera")){
  156. //referred from dijit._editor.plugins.Print._print()
  157. //In opera and chrome the iframe.contentWindow.print
  158. //will also print the outside window. So we must create a
  159. //stand-alone new window.
  160. win = window.open("javascript: ''", "",
  161. "status=0,menubar=0,location=0,toolbar=0,width=1,height=1,resizable=0,scrollbars=0");
  162. fillDoc(win);
  163. win.print();
  164. //Opera will stop at this point, showing the popping-out window.
  165. //If the user closes the window, the following codes will not execute.
  166. //If the user returns focus to the main window, the print function
  167. // is executed, but still a no-op.
  168. win.close();
  169. }else{
  170. //Put private things in deeper namespace to avoid poluting grid namespace.
  171. var fn = this._printFrame,
  172. dn = this.grid.domNode;
  173. if(!fn){
  174. var frameId = dn.id + "_print_frame";
  175. if(!(fn = html.byId(frameId))){
  176. //create an iframe to store the grid data.
  177. fn = html.create("iframe");
  178. fn.id = frameId;
  179. fn.frameBorder = 0;
  180. html.style(fn, {
  181. width: "1px",
  182. height: "1px",
  183. position: "absolute",
  184. right: 0,
  185. bottom: 0,
  186. border: "none",
  187. overflow: "hidden"
  188. });
  189. if(!has("ie")){
  190. html.style(fn, "visibility", "hidden");
  191. }
  192. dn.appendChild(fn);
  193. }
  194. //Reuse this iframe
  195. this._printFrame = fn;
  196. }
  197. win = fn.contentWindow;
  198. fillDoc(win);
  199. //IE requires the frame to be focused for print to work, and it's harmless for FF.
  200. win.focus();
  201. win.print();
  202. }
  203. },
  204. _wrapHTML: function(/* string */title, /* Array */cssFiles, /* string */body_content){
  205. // summary:
  206. // Put title, cssFiles, and body_content together into an HTML string.
  207. // tags:
  208. // private
  209. // title: String
  210. // A title for the html page.
  211. // cssFiles: Array
  212. // css file pathes.
  213. // body_content: String
  214. // Content to print, not including <head></head> part and <html> tags
  215. // returns:
  216. // the wrapped HTML string ready for print
  217. return this._loadCSSFiles(cssFiles).then(function(cssStrs){
  218. var i, sb = ['<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">',
  219. '<html ', html._isBodyLtr() ? '' : 'dir="rtl"', '><head><title>', title,
  220. '</title><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></meta>'];
  221. for(i = 0; i < cssStrs.length; ++i){
  222. sb.push('<style type="text/css">', cssStrs[i], '</style>');
  223. }
  224. sb.push('</head>');
  225. if(body_content.search(/^\s*<body/i) < 0){
  226. body_content = '<body>' + body_content + '</body>';
  227. }
  228. sb.push(body_content, '</html>');
  229. return sb.join('');
  230. });
  231. },
  232. normalizeRowHeight: function(doc){
  233. var views = query(".grid_view", doc.body);
  234. var headPerView = array.map(views, function(view){
  235. return query(".grid_header", view)[0];
  236. });
  237. var rowsPerView = array.map(views, function(view){
  238. return query(".grid_row", view);
  239. });
  240. var rowCount = rowsPerView[0].length;
  241. var i, v, h, maxHeight = 0;
  242. for(v = views.length - 1; v >= 0; --v){
  243. h = html.contentBox(headPerView[v]).h;
  244. if(h > maxHeight){
  245. maxHeight = h;
  246. }
  247. }
  248. for(v = views.length - 1; v >= 0; --v){
  249. html.style(headPerView[v], "height", maxHeight + "px");
  250. }
  251. for(i = 0; i < rowCount; ++i){
  252. maxHeight = 0;
  253. for(v = views.length - 1; v >= 0; --v){
  254. h = html.contentBox(rowsPerView[v][i]).h;
  255. if(h > maxHeight){
  256. maxHeight = h;
  257. }
  258. }
  259. for(v = views.length - 1; v >= 0; --v){
  260. html.style(rowsPerView[v][i], "height", maxHeight + "px");
  261. }
  262. }
  263. var left = 0, ltr = html._isBodyLtr();
  264. for(v = 0; v < views.length; ++v){
  265. html.style(views[v], ltr ? "left" : "right", left + "px");
  266. left += html.marginBox(views[v]).w;
  267. }
  268. },
  269. _formalizeArgs: function(args){
  270. args = (args && lang.isObject(args)) ? args : {};
  271. args.title = String(args.title) || "";
  272. if(!lang.isArray(args.cssFiles)){
  273. args.cssFiles = [args.cssFiles];
  274. }
  275. args.titleInBody = args.title ? ['<h1>', args.title, '</h1>'].join('') : '';
  276. return args; //Object
  277. }
  278. });
  279. EnhancedGrid.registerPlugin(Printer/*name:'printer'*/, {
  280. "dependency": ["exporter"]
  281. });
  282. return Printer;
  283. });