Class: Vivlio::PDF::Session

Inherits:
Object
  • Object
show all
Defined in:
lib/vivlio/pdf/session.rb

Overview

One document open in the viewer, inside one browser tab.

Wraps the CDP page so callers talk about rendering and printing rather than about JavaScript evaluation, and so Ferrum's exceptions stop here. A Session is single-use: open it, read from it, print it, close it.

Constant Summary collapse

READY_STATE =
<<~JS
  window.coreViewer ? window.coreViewer.readyState : 'loading'
JS
READ_TOC =

Reading the TOC has a side effect we depend on: the entries must be in the DOM while printing for Chromium to emit named destinations for them. Same approach as vivliostyle-cli.

<<~JS
  const done = arguments[0];
  function listener(payload) {
    if (payload.a !== 'toc') return;
    window.coreViewer.removeListener('done', listener);
    window.coreViewer.showTOC(false);
    done(window.coreViewer.getTOC());
  }
  window.coreViewer.addListener('done', listener);
  window.coreViewer.showTOC(true);
JS
POLL_INTERVAL =
0.2

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(page, timeout:) ⇒ Session

Returns a new instance of Session.



52
53
54
55
56
# File 'lib/vivlio/pdf/session.rb', line 52

def initialize(page, timeout:)
  @page = page
  @timeout = timeout
  @warnings = []
end

Instance Attribute Details

#warningsObject (readonly)

Non-fatal problems met while rendering, in the order they happened. Printer hands these to the caller as Result#warnings; nothing here writes to stderr on the caller's behalf.



50
51
52
# File 'lib/vivlio/pdf/session.rb', line 50

def warnings
  @warnings
end

Class Method Details

.open(page, url, timeout:) ⇒ Object

Closes the tab if the document never renders, so a Printer reusing one browser does not accumulate tabs across failed conversions.



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/vivlio/pdf/session.rb', line 34

def self.open(page, url, timeout:)
  session = new(page, timeout: timeout)
  session.visit(url)
  session
rescue StandardError
  begin
    session&.close
  rescue StandardError
    nil # whatever went wrong first is the failure worth reporting
  end
  raise
end

Instance Method Details

#closeObject



87
88
89
# File 'lib/vivlio/pdf/session.rb', line 87

def close
  PDF.translate_browser_errors { @page.close }
end

#to_pdf(generate_outline: false) ⇒ Object

Renders the paginated document to PDF bytes.



76
77
78
79
80
81
82
83
84
85
# File 'lib/vivlio/pdf/session.rb', line 76

def to_pdf(generate_outline: false)
  parameters = {
    preferCSSPageSize: true,
    printBackground: true,
    transferMode: 'ReturnAsBase64'
  }
  parameters[:generateDocumentOutline] = true if generate_outline
  printed = PDF.translate_browser_errors { @page.command('Page.printToPDF', **parameters) }
  printed['data'].unpack1('m')
end

#tocObject

The publication's table of contents as a TocItem forest.

A document that cannot report one still prints; the failure is recorded in warnings rather than aborting the conversion over an outline.



68
69
70
71
72
73
# File 'lib/vivlio/pdf/session.rb', line 68

def toc
  @toc ||= TocItem.build(read_toc)
rescue Error => e
  @warnings << "could not read the table of contents (#{e.message}); outline skipped"
  @toc = []
end

#visit(url) ⇒ Object



58
59
60
61
62
# File 'lib/vivlio/pdf/session.rb', line 58

def visit(url)
  PDF.translate_browser_errors { @page.go_to(url) }
  wait_until_ready
  self
end