From 43496e2fa004444222dc62717221964a0c704aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jarda=20Kot=C4=9B=C5=A1ovec?= Date: Tue, 14 Nov 2023 16:35:07 +0100 Subject: [PATCH] pkp/pkp-lib#9494 (#9496) - Add API for component registry from plugins - Expose vue module globally --- js/classes/VueRegistry.js | 39 ++++++++ js/load.js | 201 +++++++++++++++++++++----------------- 2 files changed, 151 insertions(+), 89 deletions(-) diff --git a/js/classes/VueRegistry.js b/js/classes/VueRegistry.js index 8fd7217c9c7..4e3ba8c84f5 100644 --- a/js/classes/VueRegistry.js +++ b/js/classes/VueRegistry.js @@ -16,6 +16,11 @@ export default { */ _instances: {}, + /** + * Registry of all global components + */ + _globalComponents: {}, + /** * Initialize a Vue controller * @@ -62,4 +67,38 @@ export default { } }); }, + + /** + * Keeps track of all globally registered vue components + * + * This is important especially for plugins with custom vue components + * All global components gets automatically registered for each vue instance thats created + * It has same signature as vueInstance.component() + * @param string componentName + * @param object component + */ + registerComponent(componentName, component) { + this._globalComponents[componentName] = component; + }, + + /** + * Allow possibility to allow retrive component object + * + * Should be needed very rarely. This is important for some plugins which currently extends existing component, like FieldPubIdUrn + * @param string Able to retrieve component object + */ + getComponent(componentName) { + return this._globalComponents[componentName]; + }, + + /** + * Provides all globaly registered components + * + * Main reason is to be able get all components to be registered in lib/pkp/load.js + * for every vue instance which is created + * @returns object Object of all components, where key is component name and value component object + */ + getAllComponents() { + return this._globalComponents; + }, }; diff --git a/js/load.js b/js/load.js index 00a15d3e723..779cacd7a59 100644 --- a/js/load.js +++ b/js/load.js @@ -10,8 +10,9 @@ // Vue lib and custom mixins import {createApp} from 'vue'; -import {createPinia} from 'pinia' +import * as vue from 'vue'; +import {createPinia} from 'pinia'; import GlobalMixins from '@/mixins/global.js'; import VueAnnouncer from '@vue-a11y/announcer'; import FloatingVue from 'floating-vue'; @@ -99,18 +100,116 @@ import ListPanel from '@/components/ListPanel/ListPanel.vue'; import VueRegistry from './classes/VueRegistry.js'; import i18nPlugin from '@/piniaPlugins/i18n.plugin.js'; +// Register global components +VueRegistry.registerComponent('Badge', Badge); +VueRegistry.registerComponent('PkpBadge', Badge); +VueRegistry.registerComponent('Dropdown', Dropdown); +VueRegistry.registerComponent('PkpDropdown', Dropdown); +VueRegistry.registerComponent('Icon', Icon); +VueRegistry.registerComponent('PkpIcon', Icon); +VueRegistry.registerComponent('Notification', Notification); +VueRegistry.registerComponent('PkpNotification', Notification); +VueRegistry.registerComponent('Panel', Panel); +VueRegistry.registerComponent('PkpPanel', Panel); +VueRegistry.registerComponent('PanelSection', PanelSection); +VueRegistry.registerComponent('PkpPanelSection', PanelSection); +VueRegistry.registerComponent('PkpButton', PkpButton); +VueRegistry.registerComponent('PkpHeader', PkpHeader); +VueRegistry.registerComponent('Spinner', Spinner); +VueRegistry.registerComponent('PkpSpinner', Spinner); +VueRegistry.registerComponent('Step', Step); +VueRegistry.registerComponent('PkpStep', Step); +VueRegistry.registerComponent('Steps', Steps); +VueRegistry.registerComponent('PkpSteps', Steps); +VueRegistry.registerComponent('Tab', Tab); +VueRegistry.registerComponent('PkpTab', Tab); +VueRegistry.registerComponent('Tabs', Tabs); +VueRegistry.registerComponent('PkpTabs', Tabs); + +// Register other components +VueRegistry.registerComponent('PkpActionPanel', ActionPanel); +VueRegistry.registerComponent('PkpButtonRow', ButtonRow); +VueRegistry.registerComponent('PkpDoughnutChart', DoughnutChart); +VueRegistry.registerComponent('PkpLineChart', LineChart); +VueRegistry.registerComponent('PkpComposer', Composer); +VueRegistry.registerComponent('PkpDateRange', DateRange); +VueRegistry.registerComponent('PkpFile', File); +VueRegistry.registerComponent('PkpFileAttacher', FileAttacher); +VueRegistry.registerComponent('PkpFileUploader', FileUploader); +VueRegistry.registerComponent('PkpFileUploadProgress', FileUploadProgress); +VueRegistry.registerComponent('PkpFilter', PkpFilter); +VueRegistry.registerComponent('PkpFilterAutosuggest', FilterAutosuggest); +VueRegistry.registerComponent('PkpFilterSlider', FilterSlider); +VueRegistry.registerComponent( + 'PkpFilterSliderMultirange', + FilterSliderMultirange, +); +VueRegistry.registerComponent('PkpList', List); +VueRegistry.registerComponent('PkpListItem', ListItem); +VueRegistry.registerComponent('PkpModal', Modal); +VueRegistry.registerComponent('PkpMultilingualProgress', MultilingualProgress); +VueRegistry.registerComponent('PkpOrderer', Orderer); +VueRegistry.registerComponent('PkpPagination', Pagination); +VueRegistry.registerComponent('PkpProgressBar', ProgressBar); +VueRegistry.registerComponent('PkpSearch', Search); +VueRegistry.registerComponent('PkpTable', Table); +VueRegistry.registerComponent('PkpTableCell', TableCell); +VueRegistry.registerComponent('PkpTooltip', Tooltip); + +// Register Form components +VueRegistry.registerComponent('PkpForm', Form); +VueRegistry.registerComponent('PkpFieldArchivingPn', FieldArchivingPn); +VueRegistry.registerComponent( + 'PkpFieldAutosuggestPreset', + FieldAutosuggestPreset, +); +VueRegistry.registerComponent('PkpFieldBase', FieldBase); +VueRegistry.registerComponent('PkpFieldBaseAutosuggest', FieldBaseAutosuggest); +VueRegistry.registerComponent('PkpFieldColor', FieldColor); +VueRegistry.registerComponent('PkpFieldControlledVocab', FieldControlledVocab); +VueRegistry.registerComponent('PkpFieldHtml', FieldHtml); +VueRegistry.registerComponent('PkpFieldMetadataSetting', FieldMetadataSetting); +VueRegistry.registerComponent('PkpFieldOptions', FieldOptions); +VueRegistry.registerComponent('PkpFieldPreparedContent', FieldPreparedContent); +VueRegistry.registerComponent('PkpFieldPubId', FieldPubId); +VueRegistry.registerComponent('PkpFieldRadioInput', FieldRadioInput); +VueRegistry.registerComponent('PkpFieldRichText', FieldRichText); +VueRegistry.registerComponent('PkpFieldRichTextarea', FieldRichTextarea); +VueRegistry.registerComponent('PkpFieldSelect', FieldSelect); +VueRegistry.registerComponent('PkpFieldSelectIssue', FieldSelectIssue); +VueRegistry.registerComponent('PkpFieldSelectIssues', FieldSelectIssues); +VueRegistry.registerComponent( + 'PkpFieldSelectSubmissions', + FieldSelectSubmissions, +); +VueRegistry.registerComponent('PkpFieldSelectUsers', FieldSelectUsers); +VueRegistry.registerComponent( + 'PkpFieldShowEnsuringLink', + FieldShowEnsuringLink, +); +VueRegistry.registerComponent('PkpFieldText', FieldText); +VueRegistry.registerComponent('PkpFieldTextarea', FieldTextarea); +VueRegistry.registerComponent('PkpFieldUpload', FieldUpload); +VueRegistry.registerComponent('PkpFieldUploadImage', FieldUploadImage); + +// Required by the URN plugin, to be migrated at some point to pkp prefix +VueRegistry.registerComponent('field-text', FieldText); +VueRegistry.registerComponent('field-pub-id', FieldPubId); + +// Register ListPanel +VueRegistry.registerComponent('PkpListPanel', ListPanel); + function pkpCreateVueApp(createAppArgs) { // Initialize Vue const vueApp = createApp(createAppArgs); const pinia = createPinia(i18nPlugin); - pinia.use(i18nPlugin) + pinia.use(i18nPlugin); vueApp.use(pinia); // https://github.com/vuejs/pinia/discussions/1197 // to be able globally share stores vueApp.config.globalProperties.$store = {}; - // For compatibility with vue2 to preserve spaces between html tags vueApp.config.compilerOptions.whitespace = 'preserve'; vueApp.use(VueScrollTo); @@ -130,98 +229,22 @@ function pkpCreateVueApp(createAppArgs) { vueApp.mixin(GlobalMixins); - // Register global components - vueApp.component('Badge', Badge); - vueApp.component('PkpBadge', Badge); - vueApp.component('Dropdown', Dropdown); - vueApp.component('PkpDropdown', Dropdown); - vueApp.component('Icon', Icon); - vueApp.component('PkpIcon', Icon); - vueApp.component('Notification', Notification); - vueApp.component('PkpNotification', Notification); - vueApp.component('Panel', Panel); - vueApp.component('PkpPanel', Panel); - vueApp.component('PanelSection', PanelSection); - vueApp.component('PkpPanelSection', PanelSection); - vueApp.component('PkpButton', PkpButton); - vueApp.component('PkpHeader', PkpHeader); - vueApp.component('Spinner', Spinner); - vueApp.component('PkpSpinner', Spinner); - vueApp.component('Step', Step); - vueApp.component('PkpStep', Step); - vueApp.component('Steps', Steps); - vueApp.component('PkpSteps', Steps); - vueApp.component('Tab', Tab); - vueApp.component('PkpTab', Tab); - vueApp.component('Tabs', Tabs); - vueApp.component('PkpTabs', Tabs); - - // Register other components - vueApp.component('PkpActionPanel', ActionPanel); - vueApp.component('PkpButtonRow', ButtonRow); - vueApp.component('PkpDoughnutChart', DoughnutChart); - vueApp.component('PkpLineChart', LineChart); - vueApp.component('PkpComposer', Composer); - vueApp.component('PkpDateRange', DateRange); - vueApp.component('PkpFile', File); - vueApp.component('PkpFileAttacher', FileAttacher); - vueApp.component('PkpFileUploader', FileUploader); - vueApp.component('PkpFileUploadProgress', FileUploadProgress); - vueApp.component('PkpFilter', PkpFilter); - vueApp.component('PkpFilterAutosuggest', FilterAutosuggest); - vueApp.component('PkpFilterSlider', FilterSlider); - vueApp.component('PkpFilterSliderMultirange', FilterSliderMultirange); - vueApp.component('PkpList', List); - vueApp.component('PkpListItem', ListItem); - vueApp.component('PkpModal', Modal); - vueApp.component('PkpMultilingualProgress', MultilingualProgress); - vueApp.component('PkpOrderer', Orderer); - vueApp.component('PkpPagination', Pagination); - vueApp.component('PkpProgressBar', ProgressBar); - vueApp.component('PkpSearch', Search); - vueApp.component('PkpTable', Table); - vueApp.component('PkpTableCell', TableCell); - vueApp.component('PkpTooltip', Tooltip); - - // Register Form components - vueApp.component('PkpForm', Form); - vueApp.component('PkpFieldArchivingPn', FieldArchivingPn); - vueApp.component('PkpFieldAutosuggestPreset', FieldAutosuggestPreset); - vueApp.component('PkpFieldBase', FieldBase); - vueApp.component('PkpFieldBaseAutosuggest', FieldBaseAutosuggest); - vueApp.component('PkpFieldColor', FieldColor); - vueApp.component('PkpFieldControlledVocab', FieldControlledVocab); - vueApp.component('PkpFieldHtml', FieldHtml); - vueApp.component('PkpFieldMetadataSetting', FieldMetadataSetting); - vueApp.component('PkpFieldOptions', FieldOptions); - vueApp.component('PkpFieldPreparedContent', FieldPreparedContent); - vueApp.component('PkpFieldPubId', FieldPubId); - vueApp.component('PkpFieldRadioInput', FieldRadioInput); - vueApp.component('PkpFieldRichText', FieldRichText); - vueApp.component('PkpFieldRichTextarea', FieldRichTextarea); - vueApp.component('PkpFieldSelect', FieldSelect); - vueApp.component('PkpFieldSelectIssue', FieldSelectIssue); - vueApp.component('PkpFieldSelectIssues', FieldSelectIssues); - vueApp.component('PkpFieldSelectSubmissions', FieldSelectSubmissions); - vueApp.component('PkpFieldSelectUsers', FieldSelectUsers); - vueApp.component('PkpFieldShowEnsuringLink', FieldShowEnsuringLink); - vueApp.component('PkpFieldText', FieldText); - vueApp.component('PkpFieldTextarea', FieldTextarea); - vueApp.component('PkpFieldUpload', FieldUpload); - vueApp.component('PkpFieldUploadImage', FieldUploadImage); - - // Required by the URN plugin, to be migrated at some point to pkp prefix - vueApp.component('field-text', FieldText); - vueApp.component('field-pub-id', FieldPubId); - - // Register ListPanel - vueApp.component('PkpListPanel', ListPanel); + // register all global components + const allGlobalComponents = VueRegistry.getAllComponents(); + Object.keys(allGlobalComponents).forEach((componentName) => { + vueApp.component(componentName, allGlobalComponents[componentName]); + }); return vueApp; } export default { Vue: pkpCreateVueApp({}), + // making vue functions available via pkp.modules.vue for plugins + // especially useful when using composition api + modules: { + vue, + }, pkpCreateVueApp, createApp, registry: VueRegistry,