Skip to content

Commit

Permalink
Merge pull request #330 from tropy/feature/print
Browse files Browse the repository at this point in the history
Feature: Print Items
  • Loading branch information
inukshuk committed Jul 25, 2019
2 parents 816373e + 19c24ea commit 90de31f
Show file tree
Hide file tree
Showing 39 changed files with 991 additions and 43 deletions.
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

0 comments on commit 90de31f

Please sign in to comment.