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
13 changes: 12 additions & 1 deletion src/components/ViewerComponent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<template>
<EditorReloader
v-if="!useSourceView"
ref="editor"
:context="{ id: fileid, type: 'file' }"
:relativePath="filename"
:active="active || isEmbedded"
Expand All @@ -27,7 +28,7 @@

<script setup lang="ts">
import { getSharingToken } from '@nextcloud/sharing/public'
import { computed, onMounted, provide, ref, useAttrs } from 'vue'
import { computed, onMounted, provide, ref, useAttrs, useTemplateRef } from 'vue'
import EditorReloader from './EditorReloader.vue'
import SourceView from './SourceView.vue'

Expand Down Expand Up @@ -74,6 +75,16 @@ function toggleEdit() {
hasToggledInteractiveEmbedding.value = true
}

const editor = useTemplateRef('editor')

/**
* Write edits not saved yet, if any
*/
async function saveWhenDirty() {
await editor.value?.saveWhenDirty?.()
}

defineExpose({ saveWhenDirty })
</script>

<style lang="scss" scoped>
Expand Down
22 changes: 21 additions & 1 deletion src/tests/components/TextViewerWrapper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import type { IFile } from '@nextcloud/files'

import { mount } from '@vue/test-utils'
import { describe, expect, it, vi } from 'vitest'
import { defineComponent } from 'vue'
import { defineComponent, defineCustomElement, nextTick } from 'vue'

const saveWhenDirty = vi.hoisted(() => vi.fn(async () => {}))

// The editor itself is not what is tested here, only what it is handed
vi.mock('../../components/ViewerComponent.vue', () => ({
default: defineComponent({
name: 'ViewerComponent',
props: ['filename', 'fileid', 'forceSource', 'mime', 'source', 'e2EeIsEncrypted', 'active', 'onLoadedHandler'],
methods: { saveWhenDirty },
template: '<div />',
}),
}))
Expand Down Expand Up @@ -71,6 +74,23 @@ describe('the text viewer wrapper', () => {
expect(editor.props('source')).toBe(version.encodedSource)
})

// A download from the viewer would otherwise get the last saved version
it('saves edits not written yet before the viewer downloads the file', async () => {
window.customElements.define('text-viewer-test', defineCustomElement(TextViewerWrapper, { shadowRoot: false }))
const element = document.createElement('text-viewer-test') as HTMLElement & { file: IFile }
element.file = makeFile()
document.body.append(element)
await nextTick()

const pending: Promise<unknown>[] = []
element.dispatchEvent(new CustomEvent('before-download', { detail: { file: element.file, waitUntil: (promise: Promise<unknown>) => pending.push(promise) } }))
await Promise.all(pending)

expect(saveWhenDirty).toHaveBeenCalledOnce()
expect(pending).toHaveLength(1)
element.remove()
})

it('stops the viewer from swiping, so text can be selected', () => {
const wrapper = mount(TextViewerWrapper, { props: { file: makeFile() } })

Expand Down
11 changes: 10 additions & 1 deletion src/views/TextViewerWrapper.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@

<script setup lang="ts">
import type { IFile } from '@nextcloud/files'
import type { ViewerBeforeDownloadDetail } from '@nextcloud/viewer'

import { computed, onMounted } from 'vue'
import { computed, onMounted, useHost, useTemplateRef } from 'vue'
import ViewerComponent from '../components/ViewerComponent.vue'
import ViewerVersionComparison from '../components/ViewerVersionComparison.vue'
import { openMimetypesMarkdown } from '../helpers/mime.js'
Expand Down Expand Up @@ -59,6 +60,13 @@ function showChange() {

// Swiping to select text would otherwise step to the next file
onMounted(() => emit('update:canSwipe', false))

// A download from the viewer gets the edits not saved yet too
const viewerComponent = useTemplateRef<InstanceType<typeof ViewerComponent>>('viewerComponent')
useHost()?.addEventListener('before-download', (event) => {
const { detail } = event as CustomEvent<ViewerBeforeDownloadDetail>
detail.waitUntil(viewerComponent.value?.saveWhenDirty() ?? Promise.resolve())
})
</script>

<template>
Expand All @@ -71,6 +79,7 @@ onMounted(() => emit('update:canSwipe', false))
@select="showChange" />
<ViewerComponent
v-else
ref="viewerComponent"
:filename="file.path"
:fileid="file.fileid"
:forceSource
Expand Down
Loading