UNPKG

@ckeditor/ckeditor5-vue

Version:

Official Vue.js 3+ component for CKEditor 5 – the best browser-based rich text editor.

1 lines 18.5 kB
{"version":3,"file":"ckeditor.umd.cjs","sources":["../src/plugins/VueIntegrationUsageDataPlugin.ts","../src/plugins/appendAllIntegrationPluginsToConfig.ts","../src/ckeditor.vue","../src/composables/useAsync.ts","../src/useCKEditorCloud.ts","../src/plugin.ts"],"sourcesContent":["/**\n * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\nimport { version } from 'vue';\n\nimport { createIntegrationUsageDataPlugin } from '@ckeditor/ckeditor5-integrations-common';\n\n/**\n * This part of the code is not executed in open-source implementations using a GPL key.\n * It only runs when a specific license key is provided. If you are uncertain whether\n * this applies to your installation, please contact our support team.\n */\nexport const VueIntegrationUsageDataPlugin = createIntegrationUsageDataPlugin(\n\t'vue',\n\t{\n\t\tversion: __VUE_INTEGRATION_VERSION__,\n\t\tframeworkVersion: version\n\t}\n);\n","/**\n * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\nimport { appendExtraPluginsToEditorConfig, isCKEditorFreeLicense } from '@ckeditor/ckeditor5-integrations-common';\nimport type { EditorConfig } from 'ckeditor5';\n\nimport { VueIntegrationUsageDataPlugin } from './VueIntegrationUsageDataPlugin.js';\n\n/**\n * Appends all integration plugins to the editor configuration.\n *\n * @param editorConfig The editor configuration.\n * @returns The editor configuration with all integration plugins appended.\n */\nexport function appendAllIntegrationPluginsToConfig( editorConfig: EditorConfig ): EditorConfig {\n\t/**\n\t * Do not modify the editor configuration if the editor is using a free license.\n\t */\n\tif ( isCKEditorFreeLicense( editorConfig.licenseKey ) ) {\n\t\treturn editorConfig;\n\t}\n\n\treturn appendExtraPluginsToEditorConfig( editorConfig, [\n\t\t/**\n\t\t * This part of the code is not executed in open-source implementations using a GPL key.\n\t\t * It only runs when a specific license key is provided. If you are uncertain whether\n\t\t * this applies to your installation, please contact our support team.\n\t\t */\n\t\tVueIntegrationUsageDataPlugin\n\t] );\n}\n","<template>\n <component\n :is=\"tagName\"\n ref=\"element\"\n />\n</template>\n\n<script\n\tsetup\n\tlang=\"ts\"\n\tgeneric=\"TEditor extends { create( ...args: any[] ): Promise<Editor> }\"\n>\nimport { debounce } from 'lodash-es';\nimport {\n\tref,\n\twatch,\n\tmarkRaw,\n\tonMounted,\n\tonBeforeUnmount\n} from 'vue';\nimport type { Editor, EditorConfig, EventInfo } from 'ckeditor5';\nimport type { Props, ExtractEditorType } from './types.js';\n\nimport { appendAllIntegrationPluginsToConfig } from './plugins/appendAllIntegrationPluginsToConfig.js';\n\ntype EditorType = ExtractEditorType<TEditor>;\n\ndefineOptions( {\n\tname: 'CKEditor'\n} );\n\nconst model = defineModel( 'modelValue', { type: String, default: '' } );\n\nconst props = withDefaults( defineProps<Props<TEditor>>(), {\n\tconfig: () => ( {} ),\n\ttagName: 'div',\n\tdisabled: false,\n\tdisableTwoWayDataBinding: false\n} );\n\nconst emit = defineEmits<{\n\tready: [ editor: EditorType ],\n\tdestroy: [],\n\tblur: [ event: EventInfo, editor: EditorType ],\n\tfocus: [ event: EventInfo, editor: EditorType ],\n\tinput: [ data: string, event: EventInfo, editor: EditorType ],\n\t'update:modelValue': [ data: string, event: EventInfo, editor: EditorType ],\n}>();\n\nconst VUE_INTEGRATION_READ_ONLY_LOCK_ID = 'Lock from Vue integration (@ckeditor/ckeditor5-vue)';\nconst INPUT_EVENT_DEBOUNCE_WAIT = 300;\n\nconst element = ref<HTMLElement>();\nconst instance = ref<EditorType>();\nconst lastEditorData = ref<string>();\n\ndefineExpose( {\n\tinstance,\n\tlastEditorData\n} );\n\nwatch( model, newModel => {\n\t// Synchronize changes of #modelValue. There are two sources of changes:\n\t//\n\t// External modelValue change ──────╮\n\t// ╰─────> ┏━━━━━━━━━━━┓\n\t// ┃ Component ┃\n\t// ╭─────> ┗━━━━━━━━━━━┛\n\t// Internal data change ──────╯\n\t// (typing, commands, collaboration)\n\t//\n\t// Case 1: If the change was external (via props), the editor data must be synced with\n\t// the component using instance#setData() and it is OK to destroy the selection.\n\t//\n\t// Case 2: If the change is the result of internal data change, the #modelValue is the\n\t// same as this.lastEditorData, which has been cached on #change:data. If we called\n\t// instance#setData() at this point, that would demolish the selection.\n\t//\n\t// To limit the number of instance#setData() which is time-consuming when there is a\n\t// lot of data we make sure:\n\t// * the new modelValue is at least different than the old modelValue (Case 1.)\n\t// * the new modelValue is different than the last internal instance state (Case 2.)\n\t//\n\t// See: https://github.com/ckeditor/ckeditor5-vue/issues/42.\n\tif ( instance.value && newModel !== lastEditorData.value ) {\n\t\tinstance.value.data.set( newModel );\n\t}\n} );\n\nwatch( () => props.disabled, readOnlyMode => {\n\tif ( readOnlyMode ) {\n\t\tinstance.value!.enableReadOnlyMode( VUE_INTEGRATION_READ_ONLY_LOCK_ID );\n\t} else {\n\t\tinstance.value!.disableReadOnlyMode( VUE_INTEGRATION_READ_ONLY_LOCK_ID );\n\t}\n} );\n\nfunction checkVersion(): void {\n\tconst version = window.CKEDITOR_VERSION;\n\n\tif ( !version ) {\n\t\treturn console.warn( 'Cannot find the \"CKEDITOR_VERSION\" in the \"window\" scope.' );\n\t}\n\n\tconst [ major ] = version.split( '.' ).map( Number );\n\n\tif ( major >= 42 || version.startsWith( '0.0.0' ) ) {\n\t\treturn;\n\t}\n\n\tconsole.warn( 'The <CKEditor> component requires using CKEditor 5 in version 42+ or nightly build.' );\n}\n\nfunction setUpEditorEvents( editor: EditorType ) {\n\t// Use the leading edge so the first event in the series is emitted immediately.\n\t// Failing to do so leads to race conditions, for instance, when the component modelValue\n\t// is set twice in a time span shorter than the debounce time.\n\t// See https://github.com/ckeditor/ckeditor5-vue/issues/149.\n\tconst emitDebouncedInputEvent = debounce( ( evt: EventInfo ) => {\n\t\tif ( props.disableTwoWayDataBinding ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Cache the last editor data. This kind of data is a result of typing,\n\t\t// editor command execution, collaborative changes to the document, etc.\n\t\t// This data is compared when the component modelValue changes in a 2-way binding.\n\t\tconst data = lastEditorData.value = editor.data.get();\n\n\t\t// The compatibility with the v-model and general Vue.js concept of input–like components.\n\t\temit( 'update:modelValue', data, evt, editor );\n\t\temit( 'input', data, evt, editor );\n\t}, INPUT_EVENT_DEBOUNCE_WAIT, { leading: true } );\n\n\t// Debounce emitting the #input event. When data is huge, instance#getData()\n\t// takes a lot of time to execute on every single key press and ruins the UX.\n\t//\n\t// See: https://github.com/ckeditor/ckeditor5-vue/issues/42\n\teditor.model.document.on( 'change:data', emitDebouncedInputEvent );\n\n\teditor.editing.view.document.on( 'focus', ( evt: EventInfo ) => {\n\t\temit( 'focus', evt, editor );\n\t} );\n\n\teditor.editing.view.document.on( 'blur', ( evt: EventInfo ) => {\n\t\temit( 'blur', evt, editor );\n\t} );\n}\n\ncheckVersion();\n\nonMounted( () => {\n\t// Clone the config first so it never gets mutated (across multiple editor instances).\n\t// https://github.com/ckeditor/ckeditor5-vue/issues/101\n\tconst editorConfig: EditorConfig = appendAllIntegrationPluginsToConfig(\n\t\tObject.assign( {}, props.config )\n\t);\n\n\tif ( model.value ) {\n\t\teditorConfig.initialData = model.value;\n\t}\n\n\t( props.editor.create( element.value, editorConfig ) as unknown as Promise<EditorType> )\n\t\t.then( editor => {\n\t\t\t// Save the reference to the instance for further use.\n\t\t\tinstance.value = markRaw( editor );\n\n\t\t\tsetUpEditorEvents( editor );\n\n\t\t\t// Synchronize the editor content. The #modelValue may change while the editor is being created, so the editor content has\n\t\t\t// to be synchronized with these potential changes as soon as it is ready.\n\t\t\tif ( model.value !== editorConfig.initialData ) {\n\t\t\t\teditor.data.set( model.value );\n\t\t\t}\n\n\t\t\t// Set initial disabled state.\n\t\t\tif ( props.disabled ) {\n\t\t\t\teditor.enableReadOnlyMode( VUE_INTEGRATION_READ_ONLY_LOCK_ID );\n\t\t\t}\n\n\t\t\t// Let the world know the editor is ready.\n\t\t\temit( 'ready', editor );\n\t\t} )\n\t\t.catch( error => {\n\t\t\tconsole.error( error );\n\t\t} );\n} );\n\nonBeforeUnmount( () => {\n\tif ( instance.value ) {\n\t\tinstance.value.destroy();\n\t\tinstance.value = undefined;\n\t}\n\n\t// Note: By the time the editor is destroyed (promise resolved, editor#destroy fired)\n\t// the Vue component will not be able to emit any longer. So emitting #destroy a bit earlier.\n\temit( 'destroy' );\n} );\n</script>\n","/**\n * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\nimport {\n\tcomputed, ref,\n\tshallowReadonly, watchEffect,\n\ttype ComputedRef, type Ref\n} from 'vue';\n\nimport { uid } from '@ckeditor/ckeditor5-integrations-common';\n\n/**\n * A composable that executes an async function and provides the result.\n *\n * @param asyncFunc The async function to execute.\n * @returns The result of the async function.\n * @example\n *\n * ```ts\n * const { loading, data, error } = useAsync( async () => {\n * \tconst response = await fetch( 'https://api.example.com/data' );\n * \treturn response.json();\n * } );\n * ```\n */\nexport const useAsync = <R>(\n\tasyncFunc: () => Promise<R>\n): AsyncComposableResult<R> => {\n\t// The UUID of the last query to prevent race conditions between multiple queries.\n\tconst lastQueryUUID = ref<string | null>( null );\n\n\t// The error thrown by the async function.\n\tconst error = ref<Error | null>( null );\n\n\t// The data returned by the async function.\n\tconst data: Ref<R | null> = ref( null );\n\n\t// Whether the async function is currently loading.\n\tconst loading = computed( () => lastQueryUUID.value !== null );\n\n\t// Execute the async function and update the result. This will be re-executed\n\t// whenever refs used inside the `asyncFunc` change.\n\twatchEffect( async () => {\n\t\tconst currentQueryUID = uid();\n\n\t\tlastQueryUUID.value = currentQueryUID;\n\t\tdata.value = null;\n\t\terror.value = null;\n\n\t\t// This function is called before updating `data`, `error` or `loading`\n\t\t// because the `watchEffect` could be re-triggered with the new data\n\t\t// while waiting for the previous `asyncFunc` to resolve.\n\t\tconst shouldDiscardQuery = () => lastQueryUUID.value !== currentQueryUID;\n\n\t\ttry {\n\t\t\tconst result = await asyncFunc();\n\n\t\t\tif ( !shouldDiscardQuery() ) {\n\t\t\t\tdata.value = result;\n\t\t\t}\n\t\t} catch ( err: any ) {\n\t\t\tif ( !shouldDiscardQuery() ) {\n\t\t\t\terror.value = err;\n\t\t\t}\n\t\t} finally {\n\t\t\tif ( !shouldDiscardQuery() ) {\n\t\t\t\tlastQueryUUID.value = null;\n\t\t\t}\n\t\t}\n\t} );\n\n\treturn {\n\t\tloading: shallowReadonly( loading ),\n\t\tdata: shallowReadonly( data ),\n\t\terror: shallowReadonly( error )\n\t};\n};\n\n/**\n * The result of the `useAsync` composable.\n */\nexport type AsyncComposableResult<R> = {\n\n\t/**\n\t * Whether the async function is currently loading.\n\t */\n\tloading: ComputedRef<boolean>;\n\n\t/**\n\t * \tThe data returned by the async function.\n\t */\n\tdata: Ref<R | null>;\n\n\t/**\n\t * The error thrown by the async function.\n\t */\n\terror: Ref<Error | null>;\n};\n","/**\n * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\nimport { toValue, type MaybeRefOrGetter } from 'vue';\nimport { useAsync, type AsyncComposableResult } from './composables/useAsync.js';\n\nimport {\n\tloadCKEditorCloud,\n\ttype CKEditorCloudConfig,\n\ttype CKEditorCloudResult\n} from '@ckeditor/ckeditor5-integrations-common';\n\n/**\n * A composable function that loads CKEditor Cloud services.\n *\n * @param config The configuration of the CKEditor Cloud services.\n * @returns The result of the loaded CKEditor Cloud services.\n * @template Config The type of the CKEditor Cloud configuration.\n * @example\n * ```ts\n * const { data } = useCKEditorCloud( {\n * \tversion: '43.0.0',\n * \tlanguages: [ 'en', 'de' ],\n * \tpremium: true\n * } );\n *\n * if ( data.value ) {\n * \tconst { CKEditor, CKEditorPremiumFeatures } = data.value;\n * \tconst { Paragraph } = CKEditor;\n *\n * \t// ..\n * }\n */\nexport default function useCKEditorCloud<Config extends CKEditorCloudConfig>(\n\tconfig: MaybeRefOrGetter<Config>\n): AsyncComposableResult<CKEditorCloudResult<Config>> {\n\treturn useAsync(\n\t\t(): Promise<CKEditorCloudResult<Config>> => loadCKEditorCloud(\n\t\t\ttoValue( config )\n\t\t)\n\t);\n}\n","/**\n * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.\n * For licensing, see LICENSE.md.\n */\n\n/* eslint-env browser */\nimport * as Vue from 'vue';\nimport Ckeditor from './ckeditor.vue';\n\n/* istanbul ignore if -- @preserve */\nif ( !Vue.version || !Vue.version.startsWith( '3.' ) ) {\n\tthrow new Error(\n\t\t'The CKEditor plugin works only with Vue 3+. ' +\n\t\t'For more information, please refer to ' +\n\t\t'https://ckeditor.com/docs/ckeditor5/latest/builds/guides/integration/frameworks/vuejs-v3.html'\n\t);\n}\n\nconst CkeditorPlugin = {\n\t/**\n\t * Installs the plugin, registering the `<ckeditor>` component.\n\t *\n\t * @param app The application instance.\n\t */\n\tinstall( app: Vue.App ): void {\n\t\tapp.component( 'Ckeditor', Ckeditor );\n\t}\n};\n\n/**\n * The component is exported as `Ckeditor` and not `CKEditor`, because of how Vue handles components with\n * capitalized names. The component with more than one consecutive capital letter will also be be available\n * in kebab-case, where each capital letter is separated by `-`. This way, the `CKEditor` component will\n * be available as `c-k-editor`, which doesn't look good.\n */\nexport {\n\tCkeditorPlugin,\n\tCkeditor\n};\n\n/**\n * CDN related exports.\n */\n\nexport { default as useCKEditorCloud } from './useCKEditorCloud.js';\n\nexport {\n\tloadCKEditorCloud,\n\ttype CKEditorCloudResult,\n\ttype CKEditorCloudConfig,\n\ttype CdnPluginsPacks\n} from '@ckeditor/ckeditor5-integrations-common';\n\ndeclare module 'vue' {\n\tinterface GlobalComponents {\n\t\tCkeditor: typeof Ckeditor;\n\t\tckeditor: typeof Ckeditor;\n\t}\n}\n"],"names":["createIntegrationUsageDataPlugin","version","isCKEditorFreeLicense","appendExtraPluginsToEditorConfig","_useModel","ref","watch","debounce","onMounted","markRaw","onBeforeUnmount","computed","watchEffect","uid","shallowReadonly","loadCKEditorCloud","toValue","Vue","Ckeditor"],"mappings":"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"}