From 09c2b57468efe99181703f6f5cbf882ad10863f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Sat, 17 Feb 2024 11:23:13 +0100 Subject: [PATCH 1/4] feat(reference): Add opt-in for interactive mode and render widgets lazy once in view MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/components/NcRichText/NcReferenceList.vue | 13 ++--- .../NcRichText/NcReferenceWidget.vue | 55 ++++++++++++++++--- src/functions/reference/index.js | 3 +- src/functions/reference/widgets.js | 13 ++++- 4 files changed, 68 insertions(+), 16 deletions(-) diff --git a/src/components/NcRichText/NcReferenceList.vue b/src/components/NcRichText/NcReferenceList.vue index f01abc7c7f..4dab736ee1 100644 --- a/src/components/NcRichText/NcReferenceList.vue +++ b/src/components/NcRichText/NcReferenceList.vue @@ -1,7 +1,7 @@ @@ -38,6 +38,10 @@ export default { type: Boolean, default: false, }, + interactiveOptIn: { + type: Boolean, + default: false, + }, }, data() { return { @@ -64,12 +68,7 @@ export default { return this.values[0] ?? null }, displayedReferences() { - return this.values.slice(0, this.limit).map(reference => { - return { - ...reference, - interactive: this.interactive, - } - }) + return this.values.slice(0, this.limit) }, fallbackReference() { return { diff --git a/src/components/NcRichText/NcReferenceWidget.vue b/src/components/NcRichText/NcReferenceWidget.vue index 3ab0237030..67696e9052 100644 --- a/src/components/NcRichText/NcReferenceWidget.vue +++ b/src/components/NcRichText/NcReferenceWidget.vue @@ -1,8 +1,6 @@ diff --git a/src/components/NcRichText/index.js b/src/components/NcRichText/index.js index 4d9580c093..56b11ea8c9 100644 --- a/src/components/NcRichText/index.js +++ b/src/components/NcRichText/index.js @@ -22,7 +22,7 @@ import NcRichText from './NcRichText.vue' -import { registerWidget, renderWidget, isWidgetRegistered } from './../../functions/reference/widgets.js' +import { registerWidget, renderWidget, isWidgetRegistered } from './../../functions/reference/widgets.ts' import NcReferenceList from './NcReferenceList.vue' import NcReferenceWidget from './NcReferenceWidget.vue' import NcReferencePicker from './NcReferencePicker/NcReferencePicker.vue' diff --git a/src/functions/reference/index.js b/src/functions/reference/index.js index 50d9a8e098..24077ae1e5 100644 --- a/src/functions/reference/index.js +++ b/src/functions/reference/index.js @@ -1,4 +1,4 @@ -import { registerWidget, renderWidget, isWidgetRegistered, hasInteractiveView } from './widgets.js' +import { registerWidget, renderWidget, isWidgetRegistered, hasInteractiveView } from './widgets.ts' import { getLinkWithPicker } from './referencePickerModal.js' import { getProvider, diff --git a/src/functions/reference/widgets.js b/src/functions/reference/widgets.js deleted file mode 100644 index 3fdca1322d..0000000000 --- a/src/functions/reference/widgets.js +++ /dev/null @@ -1,65 +0,0 @@ -if (!window._vue_richtext_widgets) { - window._vue_richtext_widgets = {} -} - -const isWidgetRegistered = (id) => { - return !!window._vue_richtext_widgets[id] -} - -const hasInteractiveView = (id) => { - return !!window._vue_richtext_widgets[id]?.hasInteractiveView -} - -const registerWidget = (id, callback, onDestroy = (el) => {}, props) => { - const propsWithDefaults = { - hasInteractiveView: false, - ...props, - } - - if (window._vue_richtext_widgets[id]) { - console.error('Widget for id ' + id + ' already registered') - return - } - - window._vue_richtext_widgets[id] = { - id, - callback, - onDestroy, - ...propsWithDefaults, - } -} - -const renderWidget = (el, { richObjectType, richObject, accessible, interactive }) => { - if (richObjectType === 'open-graph') { - return - } - - if (!window._vue_richtext_widgets[richObjectType]) { - console.error('Widget for rich object type ' + richObjectType + ' not registered') - return - } - - window._vue_richtext_widgets[richObjectType].callback(el, { richObjectType, richObject, accessible, interactive }) -} - -const destroyWidget = (richObjectType, el) => { - if (richObjectType === 'open-graph') { - return - } - - if (!window._vue_richtext_widgets[richObjectType]) { - return - } - - window._vue_richtext_widgets[richObjectType].onDestroy(el) -} - -window._registerWidget = registerWidget - -export { - registerWidget, - renderWidget, - destroyWidget, - isWidgetRegistered, - hasInteractiveView, -} diff --git a/src/functions/reference/widgets.ts b/src/functions/reference/widgets.ts new file mode 100644 index 0000000000..318cba5381 --- /dev/null +++ b/src/functions/reference/widgets.ts @@ -0,0 +1,96 @@ +interface WidgetRenderProperties { + richObjectType: string; + richObject: object; + accessible: boolean; + interactive: boolean; +} + +type widgetRenderCallback = (el: HTMLElement, properties: WidgetRenderProperties) => void; +type widgetDestroyCallback = (el: HTMLElement) => void; + +interface WidgetProps { + id: string; + hasInteractiveView: boolean; + callback: widgetRenderCallback; + onDestroy: widgetDestroyCallback; +} + +interface WidgetPropsOptional { + hasInteractiveView?: boolean; +} + +declare global { + interface Window { + _vue_richtext_widgets: Record; + _registerWidget: (id: string, callback: widgetRenderCallback, onDestroy: widgetDestroyCallback, props: WidgetPropsOptional) => void; + } +} + +if (!window._vue_richtext_widgets) { + window._vue_richtext_widgets = {} +} + +const isWidgetRegistered = (id: string) => { + return !!window._vue_richtext_widgets[id] +} + +const hasInteractiveView = (id: string) => { + return !!window._vue_richtext_widgets[id]?.hasInteractiveView +} + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +const registerWidget = (id: string, callback: widgetRenderCallback, onDestroy = (el: HTMLElement) => {}, props: WidgetPropsOptional) => { + const propsWithDefaults = { + hasInteractiveView: true, + ...props, + } + + if (window._vue_richtext_widgets[id]) { + console.error('Widget for id ' + id + ' already registered') + return + } + + window._vue_richtext_widgets[id] = { + id, + callback, + onDestroy, + ...propsWithDefaults, + } +} + +const renderWidget = (el: HTMLElement, { richObjectType, richObject, accessible, interactive }) => { + if (richObjectType === 'open-graph') { + return + } + + if (!window._vue_richtext_widgets[richObjectType]) { + console.error('Widget for rich object type ' + richObjectType + ' not registered') + return + } + + window._vue_richtext_widgets[richObjectType].callback(el, { richObjectType, richObject, accessible, interactive }) +} + +const destroyWidget = (richObjectType: string, el: HTMLElement) => { + if (richObjectType === 'open-graph') { + return + } + + if (!window._vue_richtext_widgets[richObjectType]) { + return + } + + window._vue_richtext_widgets[richObjectType].onDestroy(el) +} + +window._registerWidget = (id: string, callback: widgetRenderCallback, onDestroy: widgetDestroyCallback, props: WidgetPropsOptional) => { + registerWidget(id, callback, onDestroy, props) +} + +export { + registerWidget, + renderWidget, + destroyWidget, + isWidgetRegistered, + hasInteractiveView, +} diff --git a/src/functions/registerReference/index.js b/src/functions/registerReference/index.js index 2d6f64f850..ec3ad70905 100644 --- a/src/functions/registerReference/index.js +++ b/src/functions/registerReference/index.js @@ -3,7 +3,7 @@ export { renderWidget, destroyWidget, isWidgetRegistered, -} from './../reference/widgets.js' +} from './../reference/widgets.ts' export { NcCustomPickerRenderResult, registerCustomPickerElement, From f72035078469e18c44f57c09bd8803b63efa3b54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julius=20H=C3=A4rtl?= Date: Fri, 1 Mar 2024 11:17:14 +0100 Subject: [PATCH 4/4] feat: Implement full width support for widgets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julius Härtl --- src/components/NcRichText/NcReferenceList.vue | 4 ++++ src/components/NcRichText/NcReferenceWidget.vue | 16 ++++++++++++++-- src/functions/reference/widgets.ts | 7 +++++++ 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/components/NcRichText/NcReferenceList.vue b/src/components/NcRichText/NcReferenceList.vue index a5fcc82bc5..0b45ca6540 100644 --- a/src/components/NcRichText/NcReferenceList.vue +++ b/src/components/NcRichText/NcReferenceList.vue @@ -127,6 +127,10 @@ export default { }