Skip to content

Commit 3a2e7fd

Browse files
refactor(vue3): migrate FooterTemplateEditor to script setup ts
Signed-off-by: Vitor Mattos <1079143+vitormattos@users.noreply.github.com> [skip ci]
1 parent 9edfa37 commit 3a2e7fd

1 file changed

Lines changed: 196 additions & 159 deletions

File tree

src/components/FooterTemplateEditor.vue

Lines changed: 196 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,9 @@
124124
</div>
125125
</template>
126126

127-
<script>
127+
<script setup lang="ts">
128128
import { t } from '@nextcloud/l10n'
129+
import { nextTick, onMounted, ref, computed } from 'vue'
129130
130131
import debounce from 'debounce'
131132
@@ -155,167 +156,203 @@ import {
155156
} from '@mdi/js'
156157
import NcIconSvgWrapper from '@nextcloud/vue/components/NcIconSvgWrapper'
157158
158-
export default {
159+
defineOptions({
159160
name: 'FooterTemplateEditor',
160-
emits: ['template-reset'],
161-
directives: {
162-
Linkify,
163-
},
164-
components: {
165-
CodeEditor,
166-
NcButton,
167-
NcDialog,
168-
NcFormBoxButton,
169-
NcIconSvgWrapper,
170-
NcLoadingIcon,
171-
NcTextField,
172-
PDFElements,
173-
},
174-
setup() {
175-
return {
176-
mdiCheck,
177-
mdiContentCopy,
178-
mdiHelpCircleOutline,
179-
mdiMagnifyMinusOutline,
180-
mdiMagnifyPlusOutline,
181-
mdiUndoVariant,
182-
}
183-
},
184-
data() {
185-
const DEFAULT_PREVIEW_WIDTH = 595
186-
const DEFAULT_PREVIEW_HEIGHT = 100
187-
return {
188-
DEFAULT_PREVIEW_WIDTH,
189-
DEFAULT_PREVIEW_HEIGHT,
190-
footerDescription: t('libresign', 'Configure the content displayed at the footer of the PDF. The text template uses Twig syntax: https://twig.symfony.com/'),
191-
footerTemplate: '',
192-
pdfPreviewFile: null,
193-
loadingPreview: false,
194-
pdfKey: 0,
195-
zoomLevel: loadState('libresign', 'footer_preview_zoom_level', 100),
196-
previewWidth: DEFAULT_PREVIEW_WIDTH,
197-
previewHeight: DEFAULT_PREVIEW_HEIGHT,
198-
containerHeight: null,
199-
showVariablesDialog: false,
200-
templateVariables: loadState('libresign', 'footer_template_variables', {}),
201-
copiedVariable: null,
202-
}
203-
},
204-
computed: {
205-
showResetDimensions() {
206-
return Number(this.previewWidth) !== this.DEFAULT_PREVIEW_WIDTH || Number(this.previewHeight) !== this.DEFAULT_PREVIEW_HEIGHT
207-
},
208-
},
209-
created() {
210-
ensurePdfWorker()
211-
this.debouncedSaveFooterTemplate = debounce(this.saveFooterTemplate, 500)
212-
this.debouncedUpdateScale = debounce(this.updateScale, 300)
213-
this.debouncedSaveDimensions = debounce(this.saveDimensions, 500)
214-
},
215-
mounted() {
216-
axios.get(generateOcsUrl('/apps/libresign/api/v1/admin/footer-template'))
217-
.then(response => {
218-
this.footerTemplate = response.data.ocs.data.template
219-
this.previewHeight = response.data.ocs.data.preview_height
220-
this.previewWidth = response.data.ocs.data.preview_width
221-
this.saveFooterTemplate()
222-
})
223-
},
224-
methods: {
225-
t,
226-
getVariableText(name) {
227-
return `{{ ${name} }}`
228-
},
229-
isCopied(name) {
230-
return this.copiedVariable === this.getVariableText(name)
231-
},
232-
copyToClipboard(text) {
233-
if (this.copiedVariable === text) {
234-
return
235-
}
236-
237-
const value = text
238-
try {
239-
navigator.clipboard.writeText(value)
240-
} catch {
241-
// Fallback for a case when clipboard API is not available or permission denied
242-
// eslint-disable-next-line no-alert
243-
prompt('', value)
244-
}
245-
246-
this.copiedVariable = text
247-
setTimeout(() => {
248-
this.copiedVariable = null
249-
}, 2000)
250-
},
251-
async resetFooterTemplate() {
252-
this.$emit('template-reset')
253-
this.resetDimensions()
254-
axios.post(generateOcsUrl('/apps/libresign/api/v1/admin/footer-template'))
255-
},
256-
resetDimensions() {
257-
this.previewWidth = this.DEFAULT_PREVIEW_WIDTH
258-
this.previewHeight = this.DEFAULT_PREVIEW_HEIGHT
259-
OCP.AppConfig.deleteKey('libresign', 'footer_preview_width')
260-
OCP.AppConfig.deleteKey('libresign', 'footer_preview_height')
261-
},
262-
saveDimensions() {
263-
if (Number(this.previewWidth) === this.DEFAULT_PREVIEW_WIDTH && Number(this.previewHeight) === this.DEFAULT_PREVIEW_HEIGHT) {
264-
OCP.AppConfig.deleteKey('libresign', 'footer_preview_width')
265-
OCP.AppConfig.deleteKey('libresign', 'footer_preview_height')
266-
} else {
267-
OCP.AppConfig.setValue('libresign', 'footer_preview_width', this.previewWidth)
268-
OCP.AppConfig.setValue('libresign', 'footer_preview_height', this.previewHeight)
269-
}
270-
this.saveFooterTemplate()
271-
},
272-
saveFooterTemplate() {
273-
axios.post(
274-
generateOcsUrl('/apps/libresign/api/v1/admin/footer-template'),
275-
{
276-
template: this.footerTemplate,
277-
width: Number(this.previewWidth),
278-
height: Number(this.previewHeight),
279-
},
280-
{ responseType: 'blob' }
281-
).then(response => {
282-
this.setPdfPreview(response.data)
283-
}).catch(error => {
284-
console.error('Error saving footer template:', error)
285-
})
286-
},
287-
setPdfPreview(blob) {
288-
this.loadingPreview = true
289-
290-
if (this.$refs.pdfContainer) {
291-
this.containerHeight = this.$refs.pdfContainer.offsetHeight
292-
}
293-
294-
this.$nextTick(() => {
295-
const timestamp = Date.now()
296-
const pdfFile = new File([blob], `footer-preview-${timestamp}.pdf`, { type: 'application/pdf' })
297-
this.pdfPreviewFile = pdfFile
298-
this.pdfKey++
299-
})
300-
},
301-
onPdfReady() {
302-
this.loadingPreview = false
303-
this.containerHeight = null
304-
},
305-
changeZoomLevel(delta) {
306-
this.zoomLevel = Number(this.zoomLevel) + delta
307-
this.updateScale()
308-
},
309-
onZoomInput() {
310-
this.debouncedUpdateScale()
311-
},
312-
updateScale() {
313-
if (this.$refs.pdfPreview) {
314-
this.$refs.pdfPreview.scale = this.zoomLevel / 100
315-
}
161+
})
162+
163+
const emit = defineEmits<{
164+
(event: 'template-reset'): void
165+
}>()
166+
167+
const vLinkify = Linkify
168+
169+
type TemplateVariableMeta = {
170+
description?: string
171+
type?: string
172+
example?: string
173+
default?: string
174+
}
175+
176+
type PdfPreviewRef = {
177+
scale: number
178+
}
179+
180+
type AppConfigApi = {
181+
deleteKey: (app: string, key: string) => void
182+
setValue: (app: string, key: string, value: string | number) => void
183+
}
184+
185+
const DEFAULT_PREVIEW_WIDTH = 595
186+
const DEFAULT_PREVIEW_HEIGHT = 100
187+
188+
const footerDescription = t('libresign', 'Configure the content displayed at the footer of the PDF. The text template uses Twig syntax: https://twig.symfony.com/')
189+
const footerTemplate = ref('')
190+
const pdfPreviewFile = ref<File | null>(null)
191+
const loadingPreview = ref(false)
192+
const pdfKey = ref(0)
193+
const zoomLevel = ref(loadState('libresign', 'footer_preview_zoom_level', 100))
194+
const previewWidth = ref<number | string>(DEFAULT_PREVIEW_WIDTH)
195+
const previewHeight = ref<number | string>(DEFAULT_PREVIEW_HEIGHT)
196+
const containerHeight = ref<number | null>(null)
197+
const showVariablesDialog = ref(false)
198+
const templateVariables = ref<Record<string, TemplateVariableMeta>>(loadState('libresign', 'footer_template_variables', {}))
199+
const copiedVariable = ref<string | null>(null)
200+
201+
const pdfContainer = ref<HTMLElement | null>(null)
202+
const pdfPreview = ref<PdfPreviewRef | null>(null)
203+
204+
const showResetDimensions = computed(() => Number(previewWidth.value) !== DEFAULT_PREVIEW_WIDTH || Number(previewHeight.value) !== DEFAULT_PREVIEW_HEIGHT)
205+
206+
const appConfig = (globalThis as typeof globalThis & { OCP?: { AppConfig: AppConfigApi } }).OCP?.AppConfig
207+
208+
ensurePdfWorker()
209+
210+
function getVariableText(name: string) {
211+
return `{{ ${name} }}`
212+
}
213+
214+
function isCopied(name: string) {
215+
return copiedVariable.value === getVariableText(name)
216+
}
217+
218+
function copyToClipboard(text: string) {
219+
if (copiedVariable.value === text) {
220+
return
221+
}
222+
223+
try {
224+
navigator.clipboard.writeText(text)
225+
} catch {
226+
prompt('', text)
227+
}
228+
229+
copiedVariable.value = text
230+
setTimeout(() => {
231+
copiedVariable.value = null
232+
}, 2000)
233+
}
234+
235+
async function resetFooterTemplate() {
236+
emit('template-reset')
237+
resetDimensions()
238+
await axios.post(generateOcsUrl('/apps/libresign/api/v1/admin/footer-template'))
239+
}
240+
241+
function resetDimensions() {
242+
previewWidth.value = DEFAULT_PREVIEW_WIDTH
243+
previewHeight.value = DEFAULT_PREVIEW_HEIGHT
244+
appConfig?.deleteKey('libresign', 'footer_preview_width')
245+
appConfig?.deleteKey('libresign', 'footer_preview_height')
246+
}
247+
248+
function saveDimensions() {
249+
if (Number(previewWidth.value) === DEFAULT_PREVIEW_WIDTH && Number(previewHeight.value) === DEFAULT_PREVIEW_HEIGHT) {
250+
appConfig?.deleteKey('libresign', 'footer_preview_width')
251+
appConfig?.deleteKey('libresign', 'footer_preview_height')
252+
} else {
253+
appConfig?.setValue('libresign', 'footer_preview_width', previewWidth.value)
254+
appConfig?.setValue('libresign', 'footer_preview_height', previewHeight.value)
255+
}
256+
saveFooterTemplate()
257+
}
258+
259+
function saveFooterTemplate() {
260+
axios.post(
261+
generateOcsUrl('/apps/libresign/api/v1/admin/footer-template'),
262+
{
263+
template: footerTemplate.value,
264+
width: Number(previewWidth.value),
265+
height: Number(previewHeight.value),
316266
},
317-
},
267+
{ responseType: 'blob' },
268+
).then(response => {
269+
setPdfPreview(response.data)
270+
}).catch(error => {
271+
console.error('Error saving footer template:', error)
272+
})
318273
}
274+
275+
function setPdfPreview(blob: Blob) {
276+
loadingPreview.value = true
277+
278+
if (pdfContainer.value) {
279+
containerHeight.value = pdfContainer.value.offsetHeight
280+
}
281+
282+
nextTick(() => {
283+
const timestamp = Date.now()
284+
pdfPreviewFile.value = new File([blob], `footer-preview-${timestamp}.pdf`, { type: 'application/pdf' })
285+
pdfKey.value += 1
286+
})
287+
}
288+
289+
function onPdfReady() {
290+
loadingPreview.value = false
291+
containerHeight.value = null
292+
}
293+
294+
function changeZoomLevel(delta: number) {
295+
zoomLevel.value = Number(zoomLevel.value) + delta
296+
updateScale()
297+
}
298+
299+
function onZoomInput() {
300+
debouncedUpdateScale()
301+
}
302+
303+
function updateScale() {
304+
if (pdfPreview.value) {
305+
pdfPreview.value.scale = Number(zoomLevel.value) / 100
306+
}
307+
}
308+
309+
const debouncedSaveFooterTemplate = debounce(saveFooterTemplate, 500)
310+
const debouncedUpdateScale = debounce(updateScale, 300)
311+
const debouncedSaveDimensions = debounce(saveDimensions, 500)
312+
313+
onMounted(() => {
314+
axios.get(generateOcsUrl('/apps/libresign/api/v1/admin/footer-template'))
315+
.then(response => {
316+
footerTemplate.value = response.data.ocs.data.template
317+
previewHeight.value = response.data.ocs.data.preview_height
318+
previewWidth.value = response.data.ocs.data.preview_width
319+
saveFooterTemplate()
320+
})
321+
})
322+
323+
defineExpose({
324+
DEFAULT_PREVIEW_WIDTH,
325+
DEFAULT_PREVIEW_HEIGHT,
326+
footerDescription,
327+
footerTemplate,
328+
pdfPreviewFile,
329+
loadingPreview,
330+
pdfKey,
331+
zoomLevel,
332+
previewWidth,
333+
previewHeight,
334+
containerHeight,
335+
showVariablesDialog,
336+
templateVariables,
337+
copiedVariable,
338+
showResetDimensions,
339+
getVariableText,
340+
isCopied,
341+
copyToClipboard,
342+
resetFooterTemplate,
343+
resetDimensions,
344+
saveDimensions,
345+
saveFooterTemplate,
346+
setPdfPreview,
347+
onPdfReady,
348+
changeZoomLevel,
349+
onZoomInput,
350+
updateScale,
351+
debouncedSaveFooterTemplate,
352+
debouncedUpdateScale,
353+
debouncedSaveDimensions,
354+
pdfPreview,
355+
})
319356
</script>
320357

321358
<style lang="scss" scoped>

0 commit comments

Comments
 (0)