From 5247521cb8ff324215b4ba7edbd8484d93a098c1 Mon Sep 17 00:00:00 2001 From: Dmitry S Date: Mon, 12 Oct 2020 16:00:56 -0400 Subject: [PATCH] (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 --- app/client/components/ChartView.ts | 5 +++++ app/client/components/DetailView.css | 12 ++++++++++++ app/client/components/GridView.css | 27 +++++++++++++++++++++++++++ app/client/components/Printing.css | 25 ++++++++++++++++++------- app/client/components/Printing.ts | 14 +++++++++----- 5 files changed, 71 insertions(+), 12 deletions(-) diff --git a/app/client/components/ChartView.ts b/app/client/components/ChartView.ts index 66056407..f67341f3 100644 --- a/app/client/components/ChartView.ts +++ b/app/client/components/ChartView.ts @@ -7,6 +7,7 @@ import {fromKoSave} from 'app/client/lib/fromKoSave'; import {loadPlotly, PlotlyType} from 'app/client/lib/imports'; import * as DataTableModel from 'app/client/models/DataTableModel'; import {ViewFieldRec, ViewSectionRec} from 'app/client/models/DocModel'; +import {reportError} from 'app/client/models/errors'; import {KoSaveableObservable, ObjObservable} from 'app/client/models/modelUtil'; import {SortedRowSet} from 'app/client/models/rowset'; import {cssRow} from 'app/client/ui/RightPanel'; @@ -131,6 +132,10 @@ export class ChartView extends Disposable { this.autoDispose(this.sortedRows.getKoArray().subscribe(this._update)); } + public prepareToPrint(onOff: boolean) { + Plotly.relayout(this._chartDom, {}).catch(reportError); + } + protected onTableLoaded() { (BaseView.prototype as any).onTableLoaded.call(this); this._update(); diff --git a/app/client/components/DetailView.css b/app/client/components/DetailView.css index efe90e49..7f31dbfb 100644 --- a/app/client/components/DetailView.css +++ b/app/client/components/DetailView.css @@ -270,3 +270,15 @@ margin-right: -6px; /* allow labels to overflow into the padding */ 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; + } +} diff --git a/app/client/components/GridView.css b/app/client/components/GridView.css index dca03ff6..3b0d4b7b 100644 --- a/app/client/components/GridView.css +++ b/app/client/components/GridView.css @@ -99,6 +99,33 @@ .gridview_data_header { 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 ========== */ diff --git a/app/client/components/Printing.css b/app/client/components/Printing.css index a036d240..06c7e3a2 100644 --- a/app/client/components/Printing.css +++ b/app/client/components/Printing.css @@ -15,6 +15,9 @@ .print-widget { margin: 0px !important; } + .print-row { + break-inside: avoid; + } .print-widget .viewsection_title { display: none !important; @@ -35,13 +38,6 @@ position: relative !important; height: max-content !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 { @@ -51,6 +47,21 @@ .print-widget .custom_view { 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 { diff --git a/app/client/components/Printing.ts b/app/client/components/Printing.ts index ba9abe0b..5d6e90fa 100644 --- a/app/client/components/Printing.ts +++ b/app/client/components/Printing.ts @@ -67,15 +67,19 @@ export async function printViewSection(layout: any, viewSection: ViewSectionRec) const sub2 = dom.onElem(window, 'afterprint', () => { sub1.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 - // need to reload the page to do it again. - if (!(window as any).debugPrinting) { + // need to call window.finishPrinting() or reload the page to do it again. + if ((window as any).debugPrinting) { + (window as any).finishPrinting = () => prepareToPrint(false); + } else { 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.assign(rowId); const elem = renderRow(rowModel); - html.push(elem.outerHTML); + html.push(``); dom.domDispose(elem); } });