/** * useFileEditor — resolves which registered editor can handle a given MIME type. * * Other modules register editors at the `documents_file_editor` integration * point by including an entry in their `integrations.ts`: * * ```ts * documents_file_editor: [{ * id: 'my_editor', * meta: { mimeTypes: ['text/plain'] }, * component: () => import('./components/MyEditor.vue'), * }] * ``` * * Editor components receive the props: * `entity: EntityObject`, `mime: string`, * `readFile: (entityId: string) => Promise`, * `writeFile: (entityId: string, content: string) => Promise` */ import { useIntegrationStore } from '@KTXC' import type { EntityObject } from '@DocumentsManager/models/entity' const INTEGRATION_POINT = 'documents_file_editor' function mimeMatchesPattern(mime: string, pattern: string): boolean { if (pattern.endsWith('/*')) { return mime.startsWith(pattern.slice(0, -1)) } return mime === pattern } function editorMatchesMime( mime: string, mimeTypes?: string[], mimePatterns?: string[], ): boolean { if (mimeTypes?.includes(mime)) return true if (mimePatterns) { for (const pattern of mimePatterns) { if (mimeMatchesPattern(mime, pattern)) return true } } return false } export function useFileEditor() { const integrationStore = useIntegrationStore() /** * Returns the highest-priority registered editor that can handle `mime`, * or `null` if none is found. */ function findEditor(mime: string) { const editors = integrationStore.getItems(INTEGRATION_POINT) for (const editor of editors) { if ( editorMatchesMime( mime, editor.meta?.mimeTypes as string[] | undefined, editor.meta?.mimePatterns as string[] | undefined, ) ) { return editor } } return null } /** * Convenience: returns true if any registered editor can handle this entity. */ function canEdit(entity: EntityObject): boolean { const mime = entity.properties.mime if (!mime) return false return findEditor(mime) !== null } return { findEditor, canEdit } } export type UseFileEditorReturn = ReturnType