mirror of
				https://github.com/gristlabs/grist-core.git
				synced 2025-06-13 20:53:59 +00:00 
			
		
		
		
	(core) Improve printing of tables, fix printing of charts, add a browser test.
Summary: - Include column headers on each page for printing tables. - Avoid page-breaks inside rows or cards of a card-list. - Fix printing of charts that did not show up at all before. - Add a browser test, not great, but somewhat functional. Test Plan: New test, plus tested manually. Column headers work on Chrome and Firefox (not Safari). Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2636
This commit is contained in:
		
							parent
							
								
									4d3777578e
								
							
						
					
					
						commit
						5247521cb8
					
				@ -7,6 +7,7 @@ import {fromKoSave} from 'app/client/lib/fromKoSave';
 | 
				
			|||||||
import {loadPlotly, PlotlyType} from 'app/client/lib/imports';
 | 
					import {loadPlotly, PlotlyType} from 'app/client/lib/imports';
 | 
				
			||||||
import * as DataTableModel from 'app/client/models/DataTableModel';
 | 
					import * as DataTableModel from 'app/client/models/DataTableModel';
 | 
				
			||||||
import {ViewFieldRec, ViewSectionRec} from 'app/client/models/DocModel';
 | 
					import {ViewFieldRec, ViewSectionRec} from 'app/client/models/DocModel';
 | 
				
			||||||
 | 
					import {reportError} from 'app/client/models/errors';
 | 
				
			||||||
import {KoSaveableObservable, ObjObservable} from 'app/client/models/modelUtil';
 | 
					import {KoSaveableObservable, ObjObservable} from 'app/client/models/modelUtil';
 | 
				
			||||||
import {SortedRowSet} from 'app/client/models/rowset';
 | 
					import {SortedRowSet} from 'app/client/models/rowset';
 | 
				
			||||||
import {cssRow} from 'app/client/ui/RightPanel';
 | 
					import {cssRow} from 'app/client/ui/RightPanel';
 | 
				
			||||||
@ -131,6 +132,10 @@ export class ChartView extends Disposable {
 | 
				
			|||||||
    this.autoDispose(this.sortedRows.getKoArray().subscribe(this._update));
 | 
					    this.autoDispose(this.sortedRows.getKoArray().subscribe(this._update));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public prepareToPrint(onOff: boolean) {
 | 
				
			||||||
 | 
					    Plotly.relayout(this._chartDom, {}).catch(reportError);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  protected onTableLoaded() {
 | 
					  protected onTableLoaded() {
 | 
				
			||||||
    (BaseView.prototype as any).onTableLoaded.call(this);
 | 
					    (BaseView.prototype as any).onTableLoaded.call(this);
 | 
				
			||||||
    this._update();
 | 
					    this._update();
 | 
				
			||||||
 | 
				
			|||||||
@ -270,3 +270,15 @@
 | 
				
			|||||||
  margin-right: -6px;   /* allow labels to overflow into the padding */
 | 
					  margin-right: -6px;   /* allow labels to overflow into the padding */
 | 
				
			||||||
  margin-bottom: 4px;
 | 
					  margin-bottom: 4px;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@media print {
 | 
				
			||||||
 | 
					  .detail_theme_record_compact {
 | 
				
			||||||
 | 
					    background-color: var(--grist-color-medium-grey) !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .detail_theme_record_compact > .g_record_detail_inner {
 | 
				
			||||||
 | 
					    background-color: white !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .detail_theme_field_blocks {
 | 
				
			||||||
 | 
					    background-color: var(--grist-color-medium-grey) !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -99,6 +99,33 @@
 | 
				
			|||||||
  .gridview_data_header {
 | 
					  .gridview_data_header {
 | 
				
			||||||
    background-color: var(--grist-color-light-grey) !important;
 | 
					    background-color: var(--grist-color-light-grey) !important;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  .print-widget .gridview_header_backdrop_left, .print-widget .gridview_data_corner_overlay {
 | 
				
			||||||
 | 
					    display: none;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .print-widget .gridview_data_scroll {
 | 
				
			||||||
 | 
					    display: table;
 | 
				
			||||||
 | 
					    border-collapse: collapse;
 | 
				
			||||||
 | 
					    position: relative !important;
 | 
				
			||||||
 | 
					    height: max-content !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .print-widget .gridview_stick-top {
 | 
				
			||||||
 | 
					    /* The next two styles *together* tell Chrome to repeat this header on each page */
 | 
				
			||||||
 | 
					    display: table-header-group;
 | 
				
			||||||
 | 
					    break-inside: avoid;
 | 
				
			||||||
 | 
					    position: static;
 | 
				
			||||||
 | 
					    border-top: 1px solid var(--grist-color-dark-grey);
 | 
				
			||||||
 | 
					    border-left: 1px solid var(--grist-color-dark-grey);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .print-widget .gridview_data_header {
 | 
				
			||||||
 | 
					    padding-left: 4rem !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .print-widget .gridview_data_pane .print-all-rows {
 | 
				
			||||||
 | 
					    display: table-row-group;
 | 
				
			||||||
 | 
					    border-left: 1px solid var(--grist-color-dark-grey);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  .print-widget .gridview_data_pane .print-row {
 | 
				
			||||||
 | 
					    display: table-row;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* ========= Overlay styles ========== */
 | 
					/* ========= Overlay styles ========== */
 | 
				
			||||||
 | 
				
			|||||||
@ -15,6 +15,9 @@
 | 
				
			|||||||
  .print-widget {
 | 
					  .print-widget {
 | 
				
			||||||
    margin: 0px !important;
 | 
					    margin: 0px !important;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  .print-row {
 | 
				
			||||||
 | 
					    break-inside: avoid;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .print-widget .viewsection_title {
 | 
					  .print-widget .viewsection_title {
 | 
				
			||||||
    display: none !important;
 | 
					    display: none !important;
 | 
				
			||||||
@ -35,13 +38,6 @@
 | 
				
			|||||||
    position: relative !important;
 | 
					    position: relative !important;
 | 
				
			||||||
    height: max-content !important;
 | 
					    height: max-content !important;
 | 
				
			||||||
    overflow: visible !important;
 | 
					    overflow: visible !important;
 | 
				
			||||||
    border-top: 1px solid var(--grist-color-dark-grey);
 | 
					 | 
				
			||||||
    border-left: 1px solid var(--grist-color-dark-grey);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  .print-widget .gridview_data_scroll {
 | 
					 | 
				
			||||||
    position: relative !important;
 | 
					 | 
				
			||||||
    height: max-content !important;
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .print-widget .scrolly_outer {
 | 
					  .print-widget .scrolly_outer {
 | 
				
			||||||
@ -51,6 +47,21 @@
 | 
				
			|||||||
  .print-widget .custom_view {
 | 
					  .print-widget .custom_view {
 | 
				
			||||||
    height: calc(100vh - 24px);
 | 
					    height: calc(100vh - 24px);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  .ui-resizable-handle {
 | 
				
			||||||
 | 
					    display: none !important;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The chart div needs to be measured before its relayout() call, and "@media print" is not in
 | 
				
			||||||
 | 
					 * effect for that measurement, so we temporarily resize the chart for all @media, to a plausible
 | 
				
			||||||
 | 
					 * size for printing.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					.print-widget .chart_container {
 | 
				
			||||||
 | 
					  width: 6.5in !important;
 | 
				
			||||||
 | 
					  height: 6.5in !important;
 | 
				
			||||||
 | 
					  overflow: visible !important;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@media not print {
 | 
					@media not print {
 | 
				
			||||||
 | 
				
			|||||||
@ -67,15 +67,19 @@ export async function printViewSection(layout: any, viewSection: ViewSectionRec)
 | 
				
			|||||||
  const sub2 = dom.onElem(window, 'afterprint', () => {
 | 
					  const sub2 = dom.onElem(window, 'afterprint', () => {
 | 
				
			||||||
    sub1.dispose();
 | 
					    sub1.dispose();
 | 
				
			||||||
    sub2.dispose();
 | 
					    sub2.dispose();
 | 
				
			||||||
    // To debug printing, set window.debugPringint=1 in the console, then print a section, dismiss
 | 
					    // To debug printing, set window.debugPrinting=1 in the console, then print a section, dismiss
 | 
				
			||||||
    // the print dialog, switch to "@media print" emulation, and you can explore the styles. You'd
 | 
					    // the print dialog, switch to "@media print" emulation, and you can explore the styles. You'd
 | 
				
			||||||
    // need to reload the page to do it again.
 | 
					    // need to call window.finishPrinting() or reload the page to do it again.
 | 
				
			||||||
    if (!(window as any).debugPrinting) {
 | 
					    if ((window as any).debugPrinting) {
 | 
				
			||||||
 | 
					      (window as any).finishPrinting = () => prepareToPrint(false);
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
      prepareToPrint(false);
 | 
					      prepareToPrint(false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  window.print();
 | 
					  // Running print on a timeout makes it possible to test printing using selenium, and doesn't
 | 
				
			||||||
 | 
					  // seem to affect normal printing.
 | 
				
			||||||
 | 
					  setTimeout(() => window.print(), 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -97,7 +101,7 @@ export function renderAllRows(
 | 
				
			|||||||
      rowModel._index(index);
 | 
					      rowModel._index(index);
 | 
				
			||||||
      rowModel.assign(rowId);
 | 
					      rowModel.assign(rowId);
 | 
				
			||||||
      const elem = renderRow(rowModel);
 | 
					      const elem = renderRow(rowModel);
 | 
				
			||||||
      html.push(elem.outerHTML);
 | 
					      html.push(`<div class="print-row">${elem.outerHTML}</div>`);
 | 
				
			||||||
      dom.domDispose(elem);
 | 
					      dom.domDispose(elem);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user