Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,7 @@ The full handler shape (see the `IHandler` interface):
| `group` | `string` | no | Group used to combine handlers when opening a folder |
| `preload` | `(node: File) => Promise<void>` | no | Preload data for neighbouring files |
| `theme` | `'dark' \| 'light' \| 'default'` | no | Viewer modal theme |
| `canCompare` | `boolean` | no | Comparing two versions is worth offering, see `canCompare(node)` |
| `supportsEndToEndEncryption` | `boolean` | no | Whether the handler supports end-to-end encrypted files |

Gotchas:
Expand Down Expand Up @@ -453,7 +454,7 @@ instead, and the viewer works with `@nextcloud/files` nodes rather than the
| `OCA.Viewer.mimetypesCompare.includes(node.mime)` | `canView(node)` |
| `OCA.Viewer.availableHandlers` | `getHandlers()`, or `canView(node)` to test one file |
| `OCA.Viewer.registerHandler({ component })` | `registerHandler({ tagName })`, see above |
| `canCompare: true` on a handler | nothing, any handler can be compared |
| `canCompare: true` on a handler | the same, and `canCompare(node)` to decide whether to offer it |
| `\OCP\Util::addScript` for the registration | `\OCP\Util::addInitScript` |
| A listener for `OCA\Viewer\Event\LoadViewer` | a listener for `BeforeTemplateRenderedEvent`, see the [tutorial](#4-load-it-on-every-page) |
| Dispatching `OCA\Viewer\Event\LoadViewer` | nothing, the viewer is on every page already |
Expand Down
26 changes: 25 additions & 1 deletion __tests__/canView.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
*/
import { Folder, Permission } from '@nextcloud/files'
import { describe, expect, it } from 'vitest'
import { canView, registerHandler } from '../lib/index.ts'
import { canCompare, canView, registerHandler } from '../lib/index.ts'
import { makeFile, makeHandler } from './factories.ts'

describe('canView', () => {
Expand Down Expand Up @@ -44,3 +44,27 @@ describe('canView', () => {
expect(canView([image, video])).toBe(false)
})
})

describe('canCompare', () => {
it('is true for a file whose handler says comparing it is worth it', () => {
registerHandler(makeHandler({ id: 'images', canCompare: true, enabled: (nodes) => nodes.every((node) => node.mime === 'image/jpeg') }))
registerHandler(makeHandler({ id: 'videos', enabled: (nodes) => nodes.every((node) => node.mime === 'video/mp4') }))

expect(canCompare(makeFile({ mime: 'image/jpeg' }))).toBe(true)
expect(canCompare(makeFile({ mime: 'video/mp4' }))).toBe(false)
})

// The handler the viewer would show it with, not any that takes it
it('asks the first handler to take the file', () => {
registerHandler(makeHandler({ id: 'first', enabled: () => true }))
registerHandler(makeHandler({ id: 'second', canCompare: true, enabled: () => true }))

expect(canCompare(makeFile())).toBe(false)
})

it('is false for a file that cannot be viewed', () => {
registerHandler(makeHandler({ id: 'everything', canCompare: true, enabled: () => true }))

expect(canCompare(makeFile({ permissions: Permission.NONE }))).toBe(false)
})
})
1 change: 1 addition & 0 deletions __tests__/entry.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ describe('importing @nextcloud/viewer', () => {

expect(Object.keys(entry).sort()).toEqual([
'Viewer',
'canCompare',
'canView',
'getHandlers',
'getViewer',
Expand Down
3 changes: 3 additions & 0 deletions __tests__/models.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ describe('handler groups', () => {
expect(handlerById('videos').group).toBe('media')
expect(handlerById('audios').group).toBe('media')
expect(handlerById('images').group).toBe('media')
// Two versions of a picture side by side show what changed
expect(handlerById('images').canCompare).toBe(true)
expect(handlerById('videos').canCompare).toBeUndefined()
})
})

Expand Down
26 changes: 26 additions & 0 deletions lib/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,14 @@ export interface IHandler {
*/
canEdit?: boolean

/**
* Whether comparing two versions of a file side by side is worth offering
* for this handler's files. It is a hint for callers deciding whether to
* offer it at all (see `canCompare()`): `getViewer().compare()` shows any
* pair either way.
*/
canCompare?: boolean

/**
* Whether this handler works with end-to-end encrypted files.
*
Expand Down Expand Up @@ -103,6 +111,24 @@ export function canView(nodes: INode | INode[]): boolean {
return countEnabledHandlers(Array.isArray(nodes) ? nodes : [nodes], 1)
}

/**
* Whether comparing two versions of a file is worth offering.
*
* For a caller deciding whether to show a "Compare" action, like the
* versions tab of the Files sidebar: the file has to be viewable, and the
* handler the viewer would open it with has to say so with `canCompare`.
*
* @param node - The file to compare versions of
*/
export function canCompare(node: INode): boolean {
if (!canView(node)) {
return false
}
// The one the viewer would show it with: the first to take it
const handler = [...getHandlers().values()].find((candidate) => isHandlerEnabled(candidate, [node as IFile]))
return handler?.canCompare === true
}

/**
* Whether a handler accepts the given files.
*
Expand Down
2 changes: 1 addition & 1 deletion lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ registerImplementation({
// It is an empty shell until the viewer is mounted.
getViewer()

export { canView, getHandlers, registerHandler } from './handlers.ts'
export { canCompare, canView, getHandlers, registerHandler } from './handlers.ts'
export type { IHandler } from './handlers.ts'
export { getViewer, Viewer } from './viewer.ts'
export type { ViewerAPI, ViewerEmits, ViewerOptions, ViewerProps } from './viewer.ts'
Expand Down
2 changes: 2 additions & 0 deletions lib/models/images.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ export function registerImageHandler() {
group: 'media',
supportsEndToEndEncryption: true,
canEdit: true,
// Side by side is how two versions of a picture show what changed
canCompare: true,

enabled: (nodes) => {
if (nodes.length === 0) {
Expand Down
Loading