Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Print Items #330

Merged
merged 40 commits into from
Jul 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
d872bb0
Add print view
inukshuk May 31, 2019
5dec7b9
Add print command
inukshuk May 31, 2019
4781212
Update print branch
inukshuk Jun 3, 2019
a3ff66a
Use print callback to close print window
inukshuk Jul 10, 2019
c998ede
Add print view to integration tests
inukshuk Jul 10, 2019
b981a69
Add print helper to WindowManager
inukshuk Jul 11, 2019
4c007eb
Fix print layout.
flachware Jul 12, 2019
c77cacd
Add basic dummy layout for printing with metadata.
flachware Jul 12, 2019
524a2a3
Set white background-color.
flachware Jul 12, 2019
2debf73
Tweak line-height.
flachware Jul 12, 2019
04aa845
Add hairline hack.
flachware Jul 12, 2019
f50de43
Set default page margin.
flachware Jul 12, 2019
59838ae
Add debug outline.
flachware Jul 12, 2019
963972d
Prepare landscape layout.
flachware Jul 12, 2019
5118fce
Force close print window after printing
inukshuk Jul 19, 2019
e11d5b0
Compute printable metadata using ontology data
inukshuk Jul 19, 2019
8777d25
Move HTML serializer to editor module
inukshuk Jul 19, 2019
6a794f7
Send serialzied notes to print view
inukshuk Jul 19, 2019
acf3f05
Skip empty template fields in compact mode
inukshuk Jul 19, 2019
85306c2
Add MetadataField component
inukshuk Jul 19, 2019
99280f2
Init logger before requiring anything else
inukshuk Jul 20, 2019
e1fa810
Auto-format metadata values when printing
inukshuk Jul 20, 2019
5387750
Localize printed metadata headers
inukshuk Jul 20, 2019
5484fb6
Print item metadata
inukshuk Jul 20, 2019
451277c
Print photo notes
inukshuk Jul 20, 2019
ba85588
Add print preferences
inukshuk Jul 21, 2019
d26b517
Add print settings to preferences
inukshuk Jul 21, 2019
451a2c5
Actually print again
inukshuk Jul 21, 2019
2188034
Show print dialog after all photos have loaded
inukshuk Jul 22, 2019
350d52c
Add overflow class, rename .page to .container.
flachware Jul 23, 2019
d85dd70
Conditionally set overflow and metadata classes
inukshuk Jul 23, 2019
2b986db
Remove cover and popup root from print view
inukshuk Jul 23, 2019
6ecc7b5
Add styles for overflow layout. Ensure min size of photos in default …
flachware Jul 23, 2019
7356538
Fix note font-size in overflow layout.
flachware Jul 23, 2019
8377e32
Tweak notes layout and headings.
flachware Jul 23, 2019
1ec6cd9
Stretch empty note paragraphs in print.
flachware Jul 25, 2019
af2dc62
Tweak page margin and spacing.
flachware Jul 25, 2019
5b85116
Fix scaffolding.
flachware Jul 25, 2019
762acec
Style notes.
flachware Jul 25, 2019
19c24ea
Tweak vertical spacing.
flachware Jul 25, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 15 additions & 0 deletions res/menu/app.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ en:
command: 'app:consolidate-photo-library'
condition: 'project'
- type: 'separator'
- &print
label: 'Print'
command: 'app:print'
accelerator: 'CmdOrCtrl+P'
condition: 'project'
- type: 'separator'
- &close
label: 'Close Project'
command: 'app:close-project'
Expand Down Expand Up @@ -131,6 +137,11 @@ en:
label: 'Enter &Full Screen'
role: 'togglefullscreen'
condition: 'window'
- type: 'separator'
- label: 'Close'
accelerator: 'Ctrl+W'
role: 'close'
condition: 'window'
- &dev
label: 'Developer'
id: 'dev'
Expand Down Expand Up @@ -241,6 +252,8 @@ en:
- *import
- *consolidate
- type: 'separator'
- *print
- type: 'separator'
- *close
- label: 'Edit'
submenu:
Expand Down Expand Up @@ -270,6 +283,8 @@ en:
- label: 'Zoom'
accelerator: 'Ctrl+Cmd+Z'
role: 'zoom'
- label: 'Move to Center'
command: 'app:center-window'
condition: 'window'
- type: 'separator'
- *center-window
Expand Down
9 changes: 9 additions & 0 deletions res/strings/renderer.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ en:
light: Light
dark: Dark
system: Follow system preference
print:
mode: Print
modes:
item: One item per page
photo: One photo per page
selection: One selection per page
metadata: Include metadata
notes: Include notes
overflow: Allow content to take up more than one page
locale:
locale: Locale
locales:
Expand Down
9 changes: 9 additions & 0 deletions res/views/print.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'sha256-++gna1tMQ08GGn4M8jnPXPgLA3Il1y2LY+JVA4NpYKk='; style-src 'self'; img-src 'self' data:; form-action 'none'">
</head>
<body id="print" tabindex="-1">
<main id="main"></main>
</body>
</html>
8 changes: 8 additions & 0 deletions src/actions/item.js
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,14 @@ module.exports = {
}
},

print(payload, meta) {
return {
type: ITEM.PRINT,
payload,
meta: { cmd: 'project', ...meta }
}
},

bulk: {
update(payload, meta) {
return {
Expand Down
14 changes: 8 additions & 6 deletions src/bootstrap.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,19 @@ try {
require('module').globalPaths.push(__dirname)

const opts = require('./args').parse()
const { Window } = require('./window')
const { ready } = require('./dom')
const { ipcRenderer: ipc } = require('electron')

const win = new Window(opts)
const { basename } = require('path')
const { fatal, info } = require('./common/log')({
dest: opts.log,
level: opts.level,
name: win.type
name: basename(location.pathname, '.html')
})

const { ipcRenderer: ipc } = require('electron')
const { ready } = require('./dom')
const { Window } = require('./window')

const win = new Window(opts)

info({
dpx: window.devicePixelRatio,
opts
Expand Down
32 changes: 32 additions & 0 deletions src/browser/tropy.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const {
} = require('electron')

const { fatal, info, warn, logger, crashReport } = require('../common/log')
const { delay, once } = require('../common/util')
const { existsSync: exists } = require('fs')
const { into, compose, remove, take } = require('transducers.js')

Expand Down Expand Up @@ -644,6 +645,10 @@ class Tropy extends EventEmitter {
this.showOpenDialog(null)
})

this.on('app:print', () => {
this.dispatch(act.item.print(), this.wm.current())
})

this.on('app:zoom-in', () => {
this.state.zoom = this.wm.zoom(this.state.zoom + 0.25)
})
Expand Down Expand Up @@ -688,6 +693,33 @@ class Tropy extends EventEmitter {
this.emit(cmd, BrowserWindow.fromWebContents(event.sender), ...args)
})

ipc.on('print', async (_, opts) => {
try {
if (!opts.items.length) return

var win = await this.wm.open('print', this.hash)

await Promise.race([
once(win, 'react:ready'),
delay(2000)
])

info(`will print ${opts.items.length} item(s)`)
win.send('print', opts)

await Promise.race([
once(win, 'print:ready'),
delay(60000)
])

let result = await WindowManager.print(win)
info(`printing ${result ? 'confirmed' : 'aborted'}`)

} finally {
if (win != null) win.destroy()
}
})

ipc.on('error', (event, error) => {
this.handleUncaughtException(
error,
Expand Down
10 changes: 10 additions & 0 deletions src/browser/wm.js
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,10 @@ class WindowManager extends EventEmitter {
minimizable: false,
resizable: false
},
print: {
width: 600,
height: 300
},
project: {
width: 1280,
height: 720,
Expand Down Expand Up @@ -466,6 +470,12 @@ class WindowManager extends EventEmitter {
.getUserDefault('AppleActionOnDoubleClick', 'string')
.toLowerCase()
}

static print(win, opts = {}) {
return new Promise((resolve) => {
win.webContents.print(opts, resolve)
})
}
}


Expand Down
19 changes: 18 additions & 1 deletion src/commands/item.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict'

const { debug, warn } = require('../common/log')
const { clipboard } = require('electron')
const { clipboard, ipcRenderer: ipc } = require('electron')
const assert = require('assert')
const { DuplicateError } = require('../common/error')
const { all, call, put, select, cps } = require('redux-saga/effects')
Expand All @@ -23,6 +23,7 @@ const {
getGroupedItems,
getItemTemplate,
getPhotoTemplate,
getPrintableItems,
getTemplateValues
} = require('../selectors')

Expand Down Expand Up @@ -470,6 +471,21 @@ class Preview extends Command {
}
}

class Print extends Command {
static get ACTION() { return ITEM.PRINT }

*exec() {
let [prefs, items] = yield select(state => ([
state.settings.print,
getPrintableItems(state)
]))

if (items.length) {
ipc.send('print', { ...prefs, items })
}
}
}

class AddTag extends Command {
static get ACTION() { return ITEM.TAG.CREATE }

Expand Down Expand Up @@ -535,6 +551,7 @@ module.exports = {
Restore,
TemplateChange,
Preview,
Print,
AddTag,
RemoveTag,
ToggleTags,
Expand Down
6 changes: 5 additions & 1 deletion src/common/iiif.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use strict'

const { URL } = require('url')
const { rotate } = require('./math')
const { rotate, isHorizontal } = require('./math')


class Rotation {
Expand Down Expand Up @@ -44,6 +44,10 @@ class Rotation {
return `${this.mirror ? symbol : ''}${this.angle}`
}

get isHorizontal() {
return isHorizontal(this.angle)
}

get orientation() {
switch (this.angle) {
case 0:
Expand Down
24 changes: 24 additions & 0 deletions src/components/editor/serialize.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use strict'

const { DOMSerializer } = require('prosemirror-model')
const { schema } = require('./schema')
const { warn } = require('../../common/log')

const DOM = DOMSerializer.fromSchema(schema)

module.exports = {
toHTML(doc) {
try {
let node = schema.nodeFromJSON(doc)
let frag = DOM.serializeFragment(node)

return Array
.from(frag.children, el => el.outerHTML)
.join('')

} catch (e) {
warn({ stack: e.stack }, 'failed to convert doc to HTML')
return ''
}
}
}
8 changes: 6 additions & 2 deletions src/components/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ const IntlProvider = connect(state => {

// eslint-disable-next-line react/prefer-stateless-function
class Main extends React.Component {
componentDidMount() {
this.props.window.send('react:ready')
}

render() {
return (
<WindowContext.Provider value={this.props.window}>
<Provider store={this.props.store}>
<IntlProvider>
<div className="main-container">
<React.Fragment>
{this.props.children}
<Flash/>
</div>
</React.Fragment>
</IntlProvider>
</Provider>
</WindowContext.Provider>
Expand Down
6 changes: 4 additions & 2 deletions src/components/photo/info.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ class PhotoInfo extends PureComponent {
}

handleFileClick = () => {
this.props.onOpenInFolder(this.props.photo.path)
if (this.props.onOpenInFolder) {
this.props.onOpenInFolder(this.props.photo.path)
}
}

render() {
Expand All @@ -45,7 +47,7 @@ class PhotoInfo extends PureComponent {

static propTypes = {
photo: object.isRequired,
onOpenInFolder: func.isRequired
onOpenInFolder: func
}
}

Expand Down
39 changes: 38 additions & 1 deletion src/components/prefs/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ class AppPrefs extends React.PureComponent {
}
}

handlePrintSettingsChange = (print) => {
this.props.onSettingsUpdate({ print })
}

render() {
return (
<div className="scroll-container">
Expand Down Expand Up @@ -187,6 +191,37 @@ class AppPrefs extends React.PureComponent {
options={this.props.layouts}
onChange={this.props.onSettingsUpdate}/>
<hr/>
<FormSelect
id="prefs.app.print.mode"
name="mode"
isDisabled
isRequired
isSelectionHidden
value={this.props.settings.print.mode}
options={this.props.printModes}
onChange={this.handlePrintSettingsChange}/>
<FormElement isCompact>
<Toggle
id="prefs.app.print.metadata"
name="metadata"
value={this.props.settings.print.metadata}
onChange={this.handlePrintSettingsChange}/>
<Toggle
id="prefs.app.print.notes"
name="notes"
value={this.props.settings.print.notes}
onChange={this.handlePrintSettingsChange}/>
<Toggle
id="prefs.app.print.overflow"
isDisabled={!(
this.props.settings.print.metadata ||
this.props.settings.print.notes
)}
name="overflow"
value={this.props.settings.print.overflow}
onChange={this.handlePrintSettingsChange}/>
</FormElement>
<hr/>
<FormToggle
id="prefs.app.debug"
name="debug"
Expand Down Expand Up @@ -217,6 +252,7 @@ class AppPrefs extends React.PureComponent {
themes: arrayOf(string).isRequired,
dupOptions: arrayOf(string).isRequired,
zoomModes: arrayOf(string).isRequired,
printModes: arrayOf(string).isRequired,
onSettingsUpdate: func.isRequired
}

Expand All @@ -225,7 +261,8 @@ class AppPrefs extends React.PureComponent {
layouts: [ITEM.LAYOUT.STACKED, ITEM.LAYOUT.SIDE_BY_SIDE],
locales: ['de', 'en', 'fr', 'ja'],
dupOptions: ['skip', 'import', 'prompt'],
zoomModes: [ESPER.MODE.FIT, ESPER.MODE.FILL]
zoomModes: [ESPER.MODE.FIT, ESPER.MODE.FILL],
printModes: ['item', 'photo', 'selection']
}
}

Expand Down