From 42678cc3d447f4b2a70fab7d458352fe99ebb1fb Mon Sep 17 00:00:00 2001 From: Mateusz Baginski Date: Tue, 1 Oct 2024 13:48:19 +0200 Subject: [PATCH] Align integration to work with self-service for premium features. --- demos/tsconfig.json | 3 +- package.json | 2 +- src/ckeditor.vue | 6 +- src/plugins/VueIntegrationUsageDataPlugin.ts | 21 ++++ .../appendAllIntegrationPluginsToConfig.ts | 33 ++++++ tests/ckeditor.test.ts | 111 +++++++++++++++++- tests/tsconfig.json | 5 +- tsconfig.json | 3 + vite-env.d.ts | 6 + vite.config.ts | 4 + yarn.lock | 8 +- 11 files changed, 189 insertions(+), 13 deletions(-) create mode 100644 src/plugins/VueIntegrationUsageDataPlugin.ts create mode 100644 src/plugins/appendAllIntegrationPluginsToConfig.ts create mode 100644 vite-env.d.ts diff --git a/demos/tsconfig.json b/demos/tsconfig.json index 898220b..3e76e1a 100644 --- a/demos/tsconfig.json +++ b/demos/tsconfig.json @@ -2,7 +2,8 @@ "extends": "../tsconfig.json", "compilerOptions": { "types": [ - "../src/plugin.ts" + "../src/plugin.ts", + "../vite-env.d.ts" ] }, "include": [ diff --git a/package.json b/package.json index 3cb0a12..34a926e 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ }, "dependencies": { "lodash-es": "^4.17.21", - "@ckeditor/ckeditor5-integrations-common": "^2.1.0" + "@ckeditor/ckeditor5-integrations-common": "^2.2.0" }, "peerDependencies": { "ckeditor5": ">=42.0.0 || ^0.0.0-nightly", diff --git a/src/ckeditor.vue b/src/ckeditor.vue index b60ae35..2ce4332 100644 --- a/src/ckeditor.vue +++ b/src/ckeditor.vue @@ -21,6 +21,8 @@ import { import type { Editor, EditorConfig, EventInfo } from 'ckeditor5'; import type { Props, ExtractEditorType } from './types.js'; +import { appendAllIntegrationPluginsToConfig } from './plugins/appendAllIntegrationPluginsToConfig.js'; + type EditorType = ExtractEditorType; defineOptions( { @@ -149,7 +151,9 @@ checkVersion(); onMounted( () => { // Clone the config first so it never gets mutated (across multiple editor instances). // https://github.com/ckeditor/ckeditor5-vue/issues/101 - const editorConfig: EditorConfig = Object.assign( {}, props.config ); + const editorConfig: EditorConfig = appendAllIntegrationPluginsToConfig( + Object.assign( {}, props.config ) + ); if ( model.value ) { editorConfig.initialData = model.value; diff --git a/src/plugins/VueIntegrationUsageDataPlugin.ts b/src/plugins/VueIntegrationUsageDataPlugin.ts new file mode 100644 index 0000000..6ffc02c --- /dev/null +++ b/src/plugins/VueIntegrationUsageDataPlugin.ts @@ -0,0 +1,21 @@ +/** + * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +import { version } from 'vue'; + +import { createIntegrationUsageDataPlugin } from '@ckeditor/ckeditor5-integrations-common'; + +/** + * This part of the code is not executed in open-source implementations using a GPL key. + * It only runs when a specific license key is provided. If you are uncertain whether + * this applies to your installation, please contact our support team. + */ +export const VueIntegrationUsageDataPlugin = createIntegrationUsageDataPlugin( + 'vue', + { + version: __VUE_INTEGRATION_VERSION__, + frameworkVersion: version + } +); diff --git a/src/plugins/appendAllIntegrationPluginsToConfig.ts b/src/plugins/appendAllIntegrationPluginsToConfig.ts new file mode 100644 index 0000000..3903212 --- /dev/null +++ b/src/plugins/appendAllIntegrationPluginsToConfig.ts @@ -0,0 +1,33 @@ +/** + * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +import { appendExtraPluginsToEditorConfig, isCKEditorFreeLicense } from '@ckeditor/ckeditor5-integrations-common'; +import type { EditorConfig } from 'ckeditor5'; + +import { VueIntegrationUsageDataPlugin } from './VueIntegrationUsageDataPlugin.js'; + +/** + * Appends all integration plugins to the editor configuration. + * + * @param editorConfig The editor configuration. + * @returns The editor configuration with all integration plugins appended. + */ +export function appendAllIntegrationPluginsToConfig( editorConfig: EditorConfig ): EditorConfig { + /** + * Do not modify the editor configuration if the editor is using a free license. + */ + if ( isCKEditorFreeLicense( editorConfig.licenseKey ) ) { + return editorConfig; + } + + return appendExtraPluginsToEditorConfig( editorConfig, [ + /** + * This part of the code is not executed in open-source implementations using a GPL key. + * It only runs when a specific license key is provided. If you are uncertain whether + * this applies to your installation, please contact our support team. + */ + VueIntegrationUsageDataPlugin + ] ); +} diff --git a/tests/ckeditor.test.ts b/tests/ckeditor.test.ts index 8dd748f..64d56c7 100644 --- a/tests/ckeditor.test.ts +++ b/tests/ckeditor.test.ts @@ -7,6 +7,7 @@ import { nextTick } from 'vue'; import { describe, beforeEach, afterEach, it, expect, vi } from 'vitest'; import { mount } from '@vue/test-utils'; import { Ckeditor } from '../src/plugin.js'; +import { VueIntegrationUsageDataPlugin } from '../src/plugins/VueIntegrationUsageDataPlugin.js'; import { MockEditor, ModelDocument, @@ -157,7 +158,9 @@ describe( 'CKEditor component', () => { await nextTick(); expect( editor ).toHaveBeenCalledOnce(); - expect( editor ).toHaveBeenCalledWith( expect.any( HTMLElement ), { initialData: 'foo' } ); + expect( editor ).toHaveBeenCalledWith( expect.any( HTMLElement ), { + initialData: 'foo' + } ); component.unmount(); } ); @@ -241,7 +244,10 @@ describe( 'CKEditor component', () => { await nextTick(); - expect( component.vm.instance!.config ).to.deep.equal( { foo: 'bar' } ); + expect( component.vm.instance!.config ).to.deep.equal( { + foo: 'bar' + } ); + component.unmount(); } ); @@ -274,12 +280,107 @@ describe( 'CKEditor component', () => { await nextTick(); expect( stub ).toHaveBeenCalledTimes( 3 ); - expect( stub ).toHaveBeenNthCalledWith( 1, expect.any( HTMLElement ), { foo: 'bar', initialData: 'foo' } ); - expect( stub ).toHaveBeenNthCalledWith( 2, expect.any( HTMLElement ), { foo: 'bar', initialData: 'bar' } ); - expect( stub ).toHaveBeenNthCalledWith( 3, expect.any( HTMLElement ), { foo: 'bar', initialData: 'baz' } ); + expect( stub ).toHaveBeenNthCalledWith( 1, expect.any( HTMLElement ), { + foo: 'bar', + initialData: 'foo' + } ); + + expect( stub ).toHaveBeenNthCalledWith( 2, expect.any( HTMLElement ), { + foo: 'bar', + initialData: 'bar' + } ); + + expect( stub ).toHaveBeenNthCalledWith( 3, expect.any( HTMLElement ), { + foo: 'bar', + initialData: 'baz' + } ); component.unmount(); } ); + + describe( 'license v2', () => { + it( 'should add usage data extra plugin if it\'s commercial', async () => { + window.CKEDITOR_VERSION = '43.0.0'; + + const component = mountComponent( { + config: { + foo: 'bar', + licenseKey: '' + } + } ); + + await nextTick(); + + expect( component.vm.instance!.config ).to.deep.equal( { + foo: 'bar', + licenseKey: '', + extraPlugins: [ VueIntegrationUsageDataPlugin ] + } ); + + component.unmount(); + } ); + + it( 'should not add usage data extra plugin if it\'s free', async () => { + window.CKEDITOR_VERSION = '43.0.0'; + + const component = mountComponent( { + config: { + foo: 'bar' + } + } ); + + await nextTick(); + + expect( component.vm.instance!.config ).to.deep.equal( { + foo: 'bar' + } ); + + component.unmount(); + } ); + } ); + + describe( 'license v3', () => { + it( 'should add usage data extra plugin if it\'s commercial license', async () => { + window.CKEDITOR_VERSION = '44.0.0'; + + const component = mountComponent( { + config: { + foo: 'bar', + licenseKey: '' + } + } ); + + await nextTick(); + + expect( component.vm.instance!.config ).to.deep.equal( { + foo: 'bar', + licenseKey: '', + extraPlugins: [ VueIntegrationUsageDataPlugin ] + } ); + + component.unmount(); + } ); + + it( 'should not add usage data extra plugin if it\'s free license v3', async () => { + window.CKEDITOR_VERSION = '44.0.0'; + + const component = mountComponent( { + config: { + foo: 'bar', + licenseKey: 'GPL' + } + } ); + + await nextTick(); + + expect( component.vm.instance!.config ).to.deep.equal( { + foo: 'bar', + licenseKey: 'GPL' + } ); + + component.unmount(); + } ); + } ); } ); describe( '#disableTwoWayDataBinding', () => { diff --git a/tests/tsconfig.json b/tests/tsconfig.json index 7121038..5431365 100644 --- a/tests/tsconfig.json +++ b/tests/tsconfig.json @@ -2,7 +2,10 @@ "extends": "../tsconfig.json", "compilerOptions": { "emitDeclarationOnly": false, - "noImplicitAny": false + "noImplicitAny": false, + "types": [ + "../vite-env.d.ts" + ] }, "include": [ "./", diff --git a/tsconfig.json b/tsconfig.json index 7cdd61e..7760295 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,9 @@ "DOM", "DOM.Iterable" ], + "types": [ + "./vite-env.d.ts" + ], "skipLibCheck": true, /* Bundler mode */ diff --git a/vite-env.d.ts b/vite-env.d.ts new file mode 100644 index 0000000..499a23a --- /dev/null +++ b/vite-env.d.ts @@ -0,0 +1,6 @@ +/** + * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md. + */ + +declare const __VUE_INTEGRATION_VERSION__: string; diff --git a/vite.config.ts b/vite.config.ts index fc69236..61f4013 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -75,5 +75,9 @@ export default defineConfig( { name: 'chrome', screenshotFailures: false } + }, + + define: { + __VUE_INTEGRATION_VERSION__: JSON.stringify( pkg.version ) } } ); diff --git a/yarn.lock b/yarn.lock index 6f6808b..e5aec7e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1193,10 +1193,10 @@ "@ckeditor/ckeditor5-utils" "43.2.0" ckeditor5 "43.2.0" -"@ckeditor/ckeditor5-integrations-common@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-integrations-common/-/ckeditor5-integrations-common-2.1.0.tgz#5e1423ff764c421d8181a35f73677610038f1fb8" - integrity sha512-vn6qMb36sl6eSCc27dvThk6xISif59MxnxZmRBC440TyP7S9ZcS0ai4yHd5QyaH70ZIe0lhS7DWdLaiKtBggVQ== +"@ckeditor/ckeditor5-integrations-common@^2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@ckeditor/ckeditor5-integrations-common/-/ckeditor5-integrations-common-2.2.0.tgz#3eb75e21eddc880c87a675125ec3fcfe0c258847" + integrity sha512-qH68tqgyMibuejo+VAJ+iSH3ZmZweqBEzaawv9hZb4zzSMkBityWBjSc2hKXMtmJgCNsbSK84cyHpa5J/MNyLg== "@ckeditor/ckeditor5-language@43.2.0": version "43.2.0"