Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/CoreHome/vue/src/createAngularJsAdapter.ts')
-rw-r--r--plugins/CoreHome/vue/src/createAngularJsAdapter.ts180
1 files changed, 180 insertions, 0 deletions
diff --git a/plugins/CoreHome/vue/src/createAngularJsAdapter.ts b/plugins/CoreHome/vue/src/createAngularJsAdapter.ts
new file mode 100644
index 0000000000..9d7ba86cea
--- /dev/null
+++ b/plugins/CoreHome/vue/src/createAngularJsAdapter.ts
@@ -0,0 +1,180 @@
+/*!
+ * Matomo - free/libre analytics platform
+ *
+ * @link https://matomo.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ */
+
+import {
+ createApp,
+ defineComponent,
+ ref,
+ ComponentPublicInstance,
+} from 'vue';
+
+interface SingleScopeVarInfo {
+ vue: string;
+ default?: any; // eslint-disable-line
+ angularJsBind?: string;
+}
+
+type ScopeMapping = { [scopeVarName: string]: SingleScopeVarInfo };
+
+type AdapterFunction<InjectTypes, R = void> = (
+ scope: ng.IScope,
+ element: ng.IAugmentedJQuery,
+ attrs: ng.IAttributes,
+ ...injected: InjectTypes,
+) => R;
+
+type PostCreateFunction<InjectTypes, R = void> = (
+ vm: ComponentPublicInstance,
+ scope: ng.IScope,
+ element: ng.IAugmentedJQuery,
+ attrs: ng.IAttributes,
+ ...injected: InjectTypes,
+) => R;
+
+type EventMapping<InjectTypes> = { [vueEventName: string]: AdapterFunction<InjectTypes> };
+
+type ComponentType = ReturnType<typeof defineComponent>;
+
+export default function createAngularJsAdapter<InjectTypes = []>(options: {
+ component: ComponentType,
+ scope?: ScopeMapping,
+ directiveName: string,
+ events?: EventMapping<InjectTypes>,
+ $inject?: string[],
+ transclude?: boolean,
+ mountPointFactory?: AdapterFunction<InjectTypes, HTMLElement>,
+ postCreate?: PostCreateFunction<InjectTypes>,
+ noScope?: boolean,
+}): ng.IDirectiveFactory {
+ const {
+ component,
+ scope = {},
+ events = {},
+ $inject,
+ directiveName,
+ transclude,
+ mountPointFactory,
+ postCreate,
+ noScope,
+ } = options;
+
+ const angularJsScope = {};
+ Object.entries(scope).forEach(([scopeVarName, info]) => {
+ if (info.angularJsBind) {
+ angularJsScope[scopeVarName] = info.angularJsBind;
+ }
+ });
+
+ function angularJsAdapter(...injectedServices: InjectTypes) {
+ const adapter: ng.IDirective = {
+ restrict: 'A',
+ scope: noScope ? undefined : angularJsScope,
+ compile: function angularJsAdapterCompile() {
+ return {
+ post: function angularJsAdapterLink(
+ ngScope: ng.IScope,
+ ngElement: ng.IAugmentedJQuery,
+ ngAttrs: ng.IAttributes,
+ ) {
+ const clone = ngElement.find('[ng-transclude]');
+
+ let rootVueTemplate = '<root-component';
+ Object.entries(scope).forEach(([, info]) => {
+ rootVueTemplate += ` :${info.vue}="${info.vue}"`;
+ });
+ Object.entries(events).forEach((info) => {
+ const [eventName] = info;
+ rootVueTemplate += ` @${eventName}="onEventHandler('${eventName}')"`;
+ });
+ rootVueTemplate += '>';
+ if (transclude) {
+ rootVueTemplate += '<div ref="transcludeTarget"/>';
+ }
+ rootVueTemplate += '</root-component>';
+ const app = createApp({
+ template: rootVueTemplate,
+ data() {
+ const initialData = {};
+ Object.entries(scope).forEach(([scopeVarName, info]) => {
+ let value = ngScope[scopeVarName];
+ if (typeof value === 'undefined' && typeof info.default !== 'undefined') {
+ value = info.default instanceof Function
+ ? info.default(ngScope, ngElement, ngAttrs, ...injectedServices)
+ : info.default;
+ }
+ initialData[info.vue] = value;
+ });
+ return initialData;
+ },
+ setup() {
+ if (transclude) {
+ const transcludeTarget = ref(null);
+ return {
+ transcludeTarget,
+ };
+ }
+
+ return undefined;
+ },
+ methods: {
+ onEventHandler(name: string) {
+ if (events[name]) {
+ events[name](ngScope, ngElement, ngAttrs, ...injectedServices);
+ }
+ },
+ },
+ });
+ app.config.globalProperties.$sanitize = window.vueSanitize;
+ app.component('root-component', component);
+
+ const mountPoint = mountPointFactory
+ ? mountPointFactory(ngScope, ngElement, ngAttrs, ...injectedServices)
+ : ngElement[0];
+ const vm = app.mount(mountPoint);
+
+ Object.entries(scope).forEach(([scopeVarName, info]) => {
+ if (!info.angularJsBind) {
+ return;
+ }
+
+ ngScope.$watch(scopeVarName, (newValue: any) => { // eslint-disable-line
+ if (typeof info.default !== 'undefined' && typeof newValue === 'undefined') {
+ vm[scopeVarName] = info.default instanceof Function
+ ? info.default(ngScope, ngElement, ngAttrs, ...injectedServices)
+ : info.default;
+ } else {
+ vm[scopeVarName] = newValue;
+ }
+ });
+ });
+
+ if (transclude) {
+ $(vm.transcludeTarget).append(clone);
+ }
+
+ if (postCreate) {
+ postCreate(vm, ngScope, ngElement, ngAttrs, ...injectedServices);
+ }
+ },
+ };
+ },
+ };
+
+ if (transclude) {
+ adapter.transclude = true;
+ adapter.template = '<div ng-transclude/>';
+ }
+
+ return adapter;
+ }
+
+ angularJsAdapter.$inject = $inject || [];
+
+ angular.module('piwikApp').directive(directiveName, angularJsAdapter);
+
+ return angularJsAdapter;
+}