You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

print_format.js 22 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
  1. // Copyright (c) 2012 Web Notes Technologies Pvt Ltd (http://erpnext.com)
  2. //
  3. // MIT License (MIT)
  4. //
  5. // Permission is hereby granted, free of charge, to any person obtaining a
  6. // copy of this software and associated documentation files (the "Software"),
  7. // to deal in the Software without restriction, including without limitation
  8. // the rights to use, copy, modify, merge, publish, distribute, sublicense,
  9. // and/or sell copies of the Software, and to permit persons to whom the
  10. // Software is furnished to do so, subject to the following conditions:
  11. //
  12. // The above copyright notice and this permission notice shall be included in
  13. // all copies or substantial portions of the Software.
  14. //
  15. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  16. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  17. // PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  18. // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
  19. // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
  20. // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  21. //
  22. // default print style
  23. _p.def_print_style_body = "html, body, div, span, td { font-family: Arial, Helvetica; font-size: 12px; }" + "\npre { margin:0; padding:0;}"
  24. _p.def_print_style_other = "\n.simpletable, .noborder { border-collapse: collapse; margin-bottom: 10px;}"
  25. +"\n.simpletable td {border: 1pt solid #000; vertical-align: top; padding: 2px; }"
  26. +"\n.noborder td { vertical-align: top; }"
  27. _p.go = function(html) {
  28. var d = document.createElement('div')
  29. d.innerHTML = html
  30. $(d).printElement();
  31. }
  32. _p.preview = function(html) {
  33. var w = window.open('');
  34. if(!w) return;
  35. w.document.write(html)
  36. w.document.close();
  37. }
  38. // _p can be referenced as this inside $.extend
  39. $.extend(_p, {
  40. show_dialog: function() {
  41. if(!_p.dialog) {
  42. _p.make_dialog();
  43. }
  44. _p.dialog.show();
  45. },
  46. make_dialog: function() {
  47. // Prepare Dialog Box Layout
  48. var d = new Dialog(
  49. 360, // w
  50. 140, // h
  51. 'Print Formats', // title
  52. [ // content
  53. ['HTML', 'Select'],
  54. ['Check', 'No Letterhead'],
  55. ['HTML', 'Buttons']
  56. ]);
  57. //d.widgets['No Letterhead'].checked = 1;
  58. // Print Button
  59. $btn(d.widgets.Buttons, 'Print', function() {
  60. _p.build(
  61. sel_val(cur_frm.print_sel), // fmtname
  62. _p.go, // onload
  63. d.widgets['No Letterhead'].checked // no_letterhead
  64. );
  65. },
  66. {
  67. cssFloat: 'right',
  68. marginBottom: '16px',
  69. marginLeft: '7px'
  70. }, 'green');
  71. // Print Preview
  72. $btn(d.widgets.Buttons, 'Preview', function() {
  73. _p.build(
  74. sel_val(cur_frm.print_sel), // fmtname
  75. _p.preview, // onload
  76. d.widgets['No Letterhead'].checked // no_letterhead
  77. );
  78. },
  79. {
  80. cssFloat: 'right',
  81. marginBottom: '16px'
  82. }, '');
  83. // Delete previous print format select list and Reload print format list from current form
  84. d.onshow = function() {
  85. var c = _p.dialog.widgets['Select'];
  86. if(c.cur_sel && c.cur_sel.parentNode == c) {
  87. c.removeChild(c.cur_sel);
  88. }
  89. c.appendChild(cur_frm.print_sel);
  90. c.cur_sel = cur_frm.print_sel;
  91. }
  92. _p.dialog = d;
  93. },
  94. // Define formats dict
  95. formats: {},
  96. /* args dict can contain:
  97. + fmtname --> print format name
  98. + onload
  99. + no_letterhead
  100. + only_body
  101. */
  102. build: function(fmtname, onload, no_letterhead, only_body) {
  103. args = {
  104. fmtname: fmtname,
  105. onload: onload,
  106. no_letterhead: no_letterhead,
  107. only_body: only_body
  108. };
  109. if(!cur_frm) {
  110. alert('No Document Selected');
  111. return;
  112. }
  113. // Get current doc (record)
  114. var doc = locals[cur_frm.doctype][cur_frm.docname];
  115. if(args.fmtname == 'Standard') {
  116. /*
  117. Render standard print layout
  118. The function passed as args onload is then called using these parameters
  119. */
  120. args.onload(_p.render({
  121. body: _p.print_std(args.no_letterhead),
  122. style: _p.print_style,
  123. doc: doc,
  124. title: doc.name,
  125. no_letterhead: args.no_letterhead,
  126. only_body: args.only_body
  127. }));
  128. } else {
  129. if (!_p.formats[args.fmtname]) {
  130. /*
  131. If print formats are not loaded, then load them and call the args onload function on callback.
  132. I think, this case happens when preview is invoked directly
  133. */
  134. var build_args = args;
  135. $c(
  136. command = 'webnotes.widgets.form.print_format.get',
  137. args = { 'name': build_args.fmtname },
  138. fn = function(r, rt) {
  139. _p.formats[build_args.fmtname] = r.message;
  140. build_args.onload(_p.render({
  141. body: _p.formats[build_args.fmtname],
  142. style: '',
  143. doc: doc,
  144. title: doc.name,
  145. no_letterhead: build_args.no_letterhead,
  146. only_body: build_args.only_body
  147. }));
  148. }
  149. );
  150. } else {
  151. // If print format is already loaded, go ahead with args onload function call
  152. args.onload(_p.render({
  153. body: _p.formats[args.fmtname],
  154. style: '',
  155. doc: doc,
  156. title: doc.name,
  157. no_letterhead: args.no_letterhead,
  158. only_body: args.only_body
  159. }));
  160. }
  161. }
  162. },
  163. /*
  164. args dict can contain:
  165. + body
  166. + style
  167. + doc
  168. + title
  169. + no_letterhead
  170. + only_body
  171. */
  172. render: function(args) {
  173. var container = document.createElement('div');
  174. var stat = '';
  175. // if draft/archived, show draft/archived banner
  176. stat += _p.show_draft(args);
  177. stat += _p.show_archived(args);
  178. stat += _p.show_cancelled(args);
  179. // Append args.body's content as a child of container
  180. container.innerHTML = args.body;
  181. // Show letterhead?
  182. _p.show_letterhead(container, args);
  183. _p.run_embedded_js(container, args.doc);
  184. var style = _p.consolidate_css(container, args);
  185. _p.render_header_on_break(container, args);
  186. return _p.render_final(style, stat, container, args);
  187. },
  188. head_banner_format: function() {
  189. return "\
  190. <div style = '\
  191. text-align: center; \
  192. padding: 8px; \
  193. background-color: #CCC;'> \
  194. <div style = '\
  195. font-size: 20px; \
  196. font-weight: bold;'>\
  197. {{HEAD}}\
  198. </div>\
  199. {{DESCRIPTION}}\
  200. </div>"
  201. },
  202. /*
  203. Check if doc's status is not submitted (docstatus == 0)
  204. and submission is pending
  205. Display draft in header if true
  206. */
  207. show_draft: function(args) {
  208. var is_doctype_submittable = 0;
  209. var plist = locals['DocPerm'];
  210. for(var perm in plist) {
  211. var p = plist[perm];
  212. if((p.parent==args.doc.doctype) && (p.submit==1)){
  213. is_doctype_submittable = 1;
  214. break;
  215. }
  216. }
  217. if(args.doc && cint(args.doc.docstatus)==0 && is_doctype_submittable) {
  218. draft = _p.head_banner_format();
  219. draft = draft.replace("{{HEAD}}", "DRAFT");
  220. draft = draft.replace("{{DESCRIPTION}}", "This box will go away after the document is submitted.");
  221. return draft;
  222. } else {
  223. return "";
  224. }
  225. },
  226. /*
  227. Check if doc is archived
  228. Display archived in header if true
  229. */
  230. show_archived: function(args) {
  231. if(args.doc && args.doc.__archived) {
  232. archived = _p.head_banner_format();
  233. archived = archived.replace("{{HEAD}}", "ARCHIVED");
  234. archived = archived.replace("{{DESCRIPTION}}", "You must restore this document to make it editable.");
  235. return archived;
  236. } else {
  237. return "";
  238. }
  239. },
  240. /*
  241. Check if doc is cancelled
  242. Display cancelled in header if true
  243. */
  244. show_cancelled: function(args) {
  245. if(args.doc && args.doc.docstatus==2) {
  246. cancelled = _p.head_banner_format();
  247. cancelled = cancelled.replace("{{HEAD}}", "CANCELLED");
  248. cancelled = cancelled.replace("{{DESCRIPTION}}", "You must amend this document to make it editable.");
  249. return cancelled;
  250. } else {
  251. return "";
  252. }
  253. },
  254. consolidate_css: function(container, args) {
  255. // Extract <style> content from container
  256. var body_style = '';
  257. var style_list = container.getElementsByTagName('style');
  258. while(style_list && style_list.length>0) {
  259. for(i in style_list) {
  260. if(style_list[i] && style_list[i].innerHTML) {
  261. body_style += style_list[i].innerHTML;
  262. var parent = style_list[i].parentNode;
  263. if(parent) {
  264. parent.removeChild(style_list[i]);
  265. } else {
  266. container.removeChild(style_list[i]);
  267. }
  268. }
  269. }
  270. style_list = container.getElementsByTagName('style');
  271. }
  272. // Concatenate all styles
  273. //style_concat = _p.def_print_style_other + args.style + body_style;
  274. style_concat = (args.only_body ? '' : _p.def_print_style_body)
  275. + _p.def_print_style_other + args.style + body_style;
  276. return style_concat;
  277. },
  278. // This is used to calculate and substitude values in the HTML
  279. run_embedded_js: function(container, doc) {
  280. var jslist = container.getElementsByTagName('script');
  281. while(jslist && jslist.length > 0) {
  282. for(i in jslist) {
  283. if(jslist[i] && jslist[i].innerHTML) {
  284. var code = jslist[i].innerHTML;
  285. var parent = jslist[i].parentNode;
  286. var span = $a(parent, 'span');
  287. parent.replaceChild(span, jslist[i]);
  288. var val = code ? eval(code) : '';
  289. if(!val || typeof(val)=='object') { val = ''; }
  290. span.innerHTML = val;
  291. }
  292. }
  293. jslist = container.getElementsByTagName('script');
  294. }
  295. },
  296. // Attach letterhead at top of container
  297. show_letterhead: function(container, args) {
  298. if(!(args.no_letterhead || args.only_body)) {
  299. container.innerHTML = '<div>' + _p.get_letter_head() + '</div>'
  300. + container.innerHTML;
  301. }
  302. },
  303. render_header_on_break: function(container, args) {
  304. var page_set = container.getElementsByClassName('page-settings');
  305. if(page_set.length) {
  306. for(var i = 0; i < page_set.length; i++) {
  307. var tmp = '';
  308. // if draft/archived, show draft/archived banner
  309. tmp += _p.show_draft(args);
  310. tmp += _p.show_archived(args);
  311. _p.show_letterhead(page_set[i], args);
  312. page_set[i].innerHTML = tmp + page_set[i].innerHTML;
  313. }
  314. }
  315. },
  316. // called by _p.render for final render of print
  317. render_final: function(style, stat, container, args) {
  318. var header = '<div class="page-settings">\n';
  319. var footer = '\n</div>';
  320. if(!args.only_body) {
  321. header = '<!DOCTYPE html>\n\
  322. <html>\
  323. <head>\
  324. <title>' + args.title + '</title>\
  325. <style>' + style + '</style>\
  326. </head>\
  327. <body>\n' + header;
  328. footer = footer + '\n</body>\n\
  329. </html>';
  330. }
  331. var finished = header
  332. + stat
  333. + container.innerHTML.replace(/<div/g, '\n<div').replace(/<td/g, '\n<td')
  334. + footer;
  335. return finished;
  336. },
  337. // fetches letter head from current doc or control panel
  338. get_letter_head: function() {
  339. var cp = wn.control_panel;
  340. var lh = '';
  341. if(cur_frm.doc.letter_head) {
  342. lh = cstr(wn.boot.letter_heads[cur_frm.doc.letter_head]);
  343. } else if (cp.letter_head) {
  344. lh = cp.letter_head;
  345. }
  346. return lh;
  347. },
  348. // common print style setting
  349. print_style: "\
  350. .datalabelcell { \
  351. padding: 2px 0px; \
  352. width: 38%; \
  353. vertical-align: top; \
  354. } \
  355. .datainputcell { \
  356. padding: 2px 0px; \
  357. width: 62%; \
  358. text-align: left; \
  359. }\
  360. .sectionHeading { \
  361. font-size: 16px; \
  362. font-weight: bold; \
  363. margin: 8px 0px; \
  364. } \
  365. .columnHeading { \
  366. font-size: 14px; \
  367. font-weight: bold; \
  368. margin: 8px 0px; \
  369. }",
  370. print_std: function(no_letterhead) {
  371. // Get doctype, docname, layout for a doctype
  372. var docname = cur_frm.docname;
  373. var doctype = cur_frm.doctype;
  374. var data = getchildren('DocField', doctype, 'fields', 'DocType');
  375. var layout = _p.add_layout(doctype);
  376. this.pf_list = [layout];
  377. var me = this;
  378. me.layout = layout;
  379. $.extend(this, {
  380. build_head: function(doctype, docname) {
  381. // Heading
  382. var h1_style = {
  383. fontSize: '22px',
  384. marginBottom: '8px'
  385. }
  386. var h1 = $a(me.layout.cur_row.header, 'h1', '', h1_style);
  387. h1.innerHTML = cur_frm.pformat[docname] ? cur_frm.pformat[docname] :
  388. get_doctype_label(doctype);
  389. var h2_style = {
  390. fontSize: '16px',
  391. color: '#888',
  392. marginBottom: '8px',
  393. paddingBottom: '8px',
  394. borderBottom: (me.layout.with_border ? '0px' :
  395. '1px solid #000')
  396. }
  397. var h2 = $a(me.layout.cur_row.header, 'div', '', h2_style);
  398. h2.innerHTML = docname;
  399. },
  400. build_data: function(data, doctype, docname) {
  401. // Start with a row and a cell in that row
  402. if(data[0] && data[0].fieldtype != "Section Break") {
  403. me.layout.addrow();
  404. if(data[0].fieldtype != "Column Break") {
  405. me.layout.addcell();
  406. }
  407. }
  408. $.extend(this, {
  409. generate_custom_html: function(field, doctype, docname) {
  410. var container = $a(me.layout.cur_cell, 'div');
  411. container.innerHTML = cur_frm.pformat[field.fieldname](locals[doctype][docname]);
  412. },
  413. render_normal: function(field, data, i) {
  414. switch(field.fieldtype) {
  415. case 'Section Break':
  416. me.layout.addrow();
  417. // Add column if no column break after this field
  418. if(data[i+1] && data[i+1].fieldtype !=
  419. 'Column Break') {
  420. me.layout.addcell();
  421. }
  422. break;
  423. case 'Column Break':
  424. me.layout.addcell(field.width, field.label);
  425. break;
  426. case 'Table':
  427. var table = print_table(
  428. doctype, // dt
  429. docname, // dn
  430. field.fieldname,
  431. field.options, // tabletype
  432. null, // cols
  433. null, // head_labels
  434. null, // widths
  435. null); // condition
  436. me.layout = _p.print_std_add_table(table, me.layout, me.pf_list, doctype, no_letterhead);
  437. break;
  438. case 'HTML':
  439. var div = $a(me.layout.cur_cell, 'div');
  440. div.innerHTML = field.options;
  441. break;
  442. case 'Code':
  443. var div = $a(me.layout.cur_cell, 'div');
  444. var val = _f.get_value(doctype, docname,
  445. field.fieldname);
  446. div.innerHTML = '<div>' + field.label +
  447. ': </div><pre style="font-family: Courier, Fixed;">' + (val ? val : '') +
  448. '</pre>';
  449. break;
  450. case 'Text Editor':
  451. var div = $a(me.layout.cur_cell, 'div');
  452. var val = _f.get_value(doctype, docname,
  453. field.fieldname);
  454. div.innerHTML = val ? val : '';
  455. break;
  456. default:
  457. // Add Cell Data
  458. _p.print_std_add_field(doctype, docname, field, me.layout);
  459. break;
  460. }
  461. }
  462. });
  463. // Then build each field
  464. for(var i = 0; i < data.length; i++) {
  465. var fieldname = data[i].fieldname ? data[i].fieldname :
  466. data[i].label;
  467. var field = fieldname ?
  468. get_field(doctype, fieldname, docname) : data[i];
  469. if(!field.print_hide) {
  470. if(cur_frm.pformat[field.fieldname]) {
  471. // If there is a custom method to generate the HTML, then use it
  472. this.generate_custom_html(field, doctype, docname);
  473. } else {
  474. // Do the normal rendering
  475. this.render_normal(field, data, i);
  476. }
  477. }
  478. }
  479. me.layout.close_borders();
  480. },
  481. build_html: function() {
  482. var html = '';
  483. for(var i = 0; i < me.pf_list.length; i++) {
  484. if(me.pf_list[i].wrapper) {
  485. html += me.pf_list[i].wrapper.innerHTML;
  486. } else if(me.pf_list[i].innerHTML) {
  487. html += me.pf_list[i].innerHTML;
  488. } else {
  489. html += me.pf_list[i];
  490. }
  491. }
  492. this.pf_list = [];
  493. return html;
  494. }
  495. });
  496. this.build_head(doctype, docname);
  497. this.build_data(data, doctype, docname);
  498. var html = this.build_html();
  499. return html;
  500. },
  501. add_layout: function(doctype) {
  502. var layout = new Layout();
  503. layout.addrow();
  504. if(locals['DocType'][doctype].print_outline == 'Yes') {
  505. layout.with_border = 1
  506. }
  507. return layout;
  508. },
  509. print_std_add_table: function(t, layout, pf_list, dt, no_letterhead) {
  510. if(t.appendChild) {
  511. // If only one table is passed
  512. layout.cur_cell.appendChild(t);
  513. } else {
  514. page_break = '\n\
  515. <div style = "page-break-after: always;" \
  516. class = "page_break"></div><div class="page-settings"></div>';
  517. // If a list of tables is passed
  518. for(var i = 0; i < t.length-1; i++) {
  519. // add to current page
  520. layout.cur_cell.appendChild(t[i]);
  521. layout.close_borders();
  522. pf_list.push(page_break);
  523. // Create new page
  524. layout = _p.add_layout(dt, no_letterhead);
  525. pf_list.push(layout);
  526. layout.addrow();
  527. layout.addcell();
  528. var div = $a(layout.cur_cell, 'div');
  529. div.innerHTML = 'Continued from previous page...';
  530. div.style.padding = '4px';
  531. }
  532. // Append last table
  533. layout.cur_cell.appendChild(t[t.length-1]);
  534. }
  535. return layout;
  536. },
  537. print_std_add_field: function(dt, dn, f, layout) {
  538. var val = _f.get_value(dt, dn, f.fieldname);
  539. if(f.fieldtype!='Button') {
  540. if(val || in_list(['Float', 'Int', 'Currency'], f.fieldtype)) {
  541. // If value or a numeric type then proceed
  542. // Add field table
  543. row = _p.field_tab(layout.cur_cell);
  544. // Add label
  545. row.cells[0].innerHTML = f.label ? f.label : f.fieldname;
  546. $s(row.cells[1], val, f.fieldtype);
  547. // left align currency in normal display
  548. if(f.fieldtype == 'Currency') {
  549. $y(row.cells[1], { textAlign: 'left' });
  550. }
  551. }
  552. }
  553. },
  554. field_tab: function(layout_cell) {
  555. var tab = $a(layout_cell, 'table', '', {width:'100%'});
  556. var row = tab.insertRow(0);
  557. _p.row = row; // Don't know this line's purpose
  558. row.insertCell(0);
  559. row.insertCell(1);
  560. row.cells[0].className = 'datalabelcell';
  561. row.cells[1].className = 'datainputcell';
  562. return row;
  563. }
  564. });
  565. print_table = function(dt, dn, fieldname, tabletype, cols, head_labels, widths, condition, cssClass, modifier, hide_empty) {
  566. var me = this;
  567. $.extend(this, {
  568. flist: (function() {
  569. var f_list = [];
  570. var fl = wn.meta.docfield_list[tabletype];
  571. if(fl) {
  572. for(var i=0; i<fl.length; i++) {
  573. f_list.push(copy_dict(fl[i]));
  574. }
  575. }
  576. return f_list;
  577. })(),
  578. data: function() {
  579. var children = getchildren(
  580. tabletype, // child_dt
  581. dn, // parent
  582. fieldname, // parentfield
  583. dt // parenttype
  584. );
  585. var data = []
  586. for(var i=0; i<children.length; i++) {
  587. data.push(copy_dict(children[i]));
  588. }
  589. return data;
  590. }(),
  591. cell_style: {
  592. border: '1px solid #000',
  593. padding: '2px',
  594. verticalAlign: 'top'
  595. },
  596. head_cell_style: {
  597. border: '1px solid #000',
  598. padding: '2px',
  599. verticalAlign: 'top',
  600. backgroundColor: '#ddd',
  601. fontWeight: 'bold'
  602. },
  603. table_style: {
  604. width: '100%',
  605. borderCollapse: 'collapse',
  606. marginBottom: '10px'
  607. },
  608. remove_empty_cols: function(flist) {
  609. var non_empty_cols = []
  610. for(var i=0; i<me.data.length; i++) {
  611. for(var c=0; c<flist.length; c++) {
  612. if(flist[c].print_hide || !inList(['', null], me.data[i][flist[c].fieldname])) {
  613. if(!inList(non_empty_cols, flist[c])) {
  614. non_empty_cols.push(flist[c]);
  615. }
  616. }
  617. }
  618. }
  619. for(var c=0; c<flist.length; c++) {
  620. if(!inList(non_empty_cols, flist[c])) {
  621. flist.splice(c, 1);
  622. c = c - 1;
  623. }
  624. }
  625. },
  626. /*
  627. This function prepares a list of columns to be displayed and calls make_print_table to create a table with these columns
  628. */
  629. prepare_col_heads: function(flist) {
  630. var new_flist = [];
  631. if(!cols || (cols && cols.length && hide_empty)) {
  632. me.remove_empty_cols(flist);
  633. }
  634. // Make a list of column headings
  635. if(cols && cols.length) {
  636. // If cols to be displayed are passed in print_table
  637. if(cols[0] == 'SR') { new_flist.push('SR') }
  638. for(var i = 0; i < cols.length; i++) {
  639. for(var j = 0; j < flist.length; j++) {
  640. if(flist[j].fieldname == cols[i]) {
  641. new_flist.push(flist[j]);
  642. break;
  643. }
  644. }
  645. }
  646. } else {
  647. // Default action: remove hidden cols
  648. new_flist.push('SR');
  649. for(var i = 0; i < flist.length; i++) {
  650. if(!flist[i].print_hide) {
  651. new_flist.push(flist[i]);
  652. }
  653. }
  654. }
  655. // Changing me.flist so that it could be used to hide data
  656. me.flist = new_flist;
  657. },
  658. // This function makes a new table with its heading rows
  659. make_print_table: function(flist) {
  660. // Make a table
  661. var wrapper = document.createElement('div');
  662. var table = $a(wrapper, 'table', '', me.table_style);
  663. table.wrapper = wrapper;
  664. // Make Head Row
  665. table.insertRow(0);
  666. var col_start = 0;
  667. // If 'SR' exists in flist, then create its heading column cell
  668. if(flist[0]=='SR') {
  669. var cell = table.rows[0].insertCell(0);
  670. cell.innerHTML = head_labels?head_labels[0]:'<b>SR</b>';
  671. $y(cell, { width: '30px' });
  672. $y(cell, me.head_cell_style);
  673. col_start++;
  674. }
  675. for(var c = col_start; c < flist.length; c++) {
  676. var cell = table.rows[0].insertCell(c);
  677. $y(cell, me.head_cell_style);
  678. cell.innerHTML = head_labels?head_labels[c]:flist[c].label;
  679. if(flist[c].width) { $y(cell, {width: flist[c].width}); }
  680. if(widths) { $y(cell, {width: widths[c]}); }
  681. if(in_list(['Currency', 'Float'], flist[c].fieldtype)) {
  682. $y(cell, { textAlign: 'right' });
  683. }
  684. }
  685. return table;
  686. },
  687. // Populate table with data
  688. populate_table: function(table, data) {
  689. for(var r = 0; r < data.length; r++) {
  690. if((!condition) || (condition(data[r]))) {
  691. // Check for page break
  692. if(data[r].page_break) {
  693. table = me.make_print_table(me.flist);
  694. me.table_list.push(table.wrapper);
  695. }
  696. var row = table.insertRow(table.rows.length);
  697. // Add serial number if required
  698. if(me.flist[0] == 'SR') {
  699. var cell = row.insertCell(0);
  700. cell.innerHTML = r + 1;
  701. $y(cell, me.cell_style);
  702. }
  703. for(var c=me.flist.indexOf('SR')+1; c<me.flist.length; c++){
  704. var cell = row.insertCell(c);
  705. $y(cell, me.cell_style);
  706. if(modifier && me.flist[c].fieldname in modifier) {
  707. data[r][me.flist[c].fieldname] = modifier[me.flist[c].fieldname](data[r]);
  708. }
  709. $s(cell, data[r][me.flist[c].fieldname],
  710. me.flist[c].fieldtype);
  711. if(in_list(['Currency', 'Float'], me.flist[c].fieldtype)) {
  712. cell.style.textAlign = 'right';
  713. }
  714. }
  715. }
  716. }
  717. }
  718. });
  719. // If no data, do not create table
  720. if(!this.data.length) { return document.createElement('div'); }
  721. this.prepare_col_heads(this.flist);
  722. var table = me.make_print_table(this.flist);
  723. this.table_list = [table.wrapper];
  724. this.populate_table(table, this.data);
  725. // If multiple tables exists, send whole list, else send only one table
  726. return (me.table_list.length > 1) ? me.table_list : me.table_list[0];
  727. }