Merge pull request #405 from umbraco/feature/identify-controller-via-unique

This commit is contained in:
Niels Lyngsø
2023-01-12 10:40:54 +01:00
committed by GitHub
13 changed files with 108 additions and 24 deletions

View File

@@ -6,6 +6,10 @@ import { UmbControllerHostInterface } from 'src/core/controller/controller-host.
export class UmbContextConsumerController extends UmbContextConsumer<UmbControllerHostInterface> implements UmbControllerInterface {
public get unique() {
return this._contextAlias;
}
constructor(host:UmbControllerHostInterface, contextAlias: string, callback: UmbContextCallback) {
super(host, contextAlias, callback);
host.addController(this);

View File

@@ -23,7 +23,7 @@ export class UmbContextConsumer<HostType extends EventTarget = EventTarget> {
* @param {UmbContextCallback} _callback
* @memberof UmbContextConsumer
*/
constructor(protected host: HostType, private _contextAlias: string, private _callback: UmbContextCallback) {}
constructor(protected host: HostType, protected _contextAlias: string, private _callback: UmbContextCallback) {}
private _onResponse = (instance: unknown) => {

View File

@@ -5,6 +5,10 @@ import { UmbControllerHostInterface } from 'src/core/controller/controller-host.
export class UmbContextProviderController extends UmbContextProvider<UmbControllerHostInterface> implements UmbControllerInterface {
public get unique() {
return this._contextAlias;
}
constructor(host:UmbControllerHostInterface, contextAlias: string, instance: unknown) {
super(host, contextAlias, instance);

View File

@@ -9,8 +9,8 @@ export class UmbContextProvider<HostType extends EventTarget = EventTarget > {
protected host: HostType;
private _contextAlias: string;
private _instance: unknown;
protected _contextAlias: string;
#instance: unknown;
/**
* Creates an instance of UmbContextProvider.
@@ -22,7 +22,7 @@ export class UmbContextProvider<HostType extends EventTarget = EventTarget > {
constructor(host: HostType, contextAlias: string, instance: unknown) {
this.host = host;
this._contextAlias = contextAlias;
this._instance = instance;
this.#instance = instance;
}
/**
@@ -51,6 +51,6 @@ export class UmbContextProvider<HostType extends EventTarget = EventTarget > {
if (event.contextAlias !== this._contextAlias) return;
event.stopPropagation();
event.callback(this._instance);
event.callback(this.#instance);
};
}

View File

@@ -45,6 +45,16 @@ export const UmbControllerHostMixin = <T extends HTMLElementConstructor>(superCl
* @param {UmbControllerInterface} ctrl
*/
addController(ctrl: UmbControllerInterface): void {
// Check if there is one already with same unique
if(ctrl.unique) {
this.#controllers.forEach(x => {
if(x.unique === ctrl.unique) {
this.removeController(x);
}
});
}
this.#controllers.push(ctrl);
if(this.#attached) {
ctrl.hostConnected();

View File

@@ -4,8 +4,15 @@ import { UmbControllerInterface } from './controller.interface';
export abstract class UmbController implements UmbControllerInterface {
protected host?: UmbControllerHostInterface;
constructor(host: UmbControllerHostInterface) {
private _alias?: string;
public get unique() {
return this._alias;
}
constructor(host: UmbControllerHostInterface, alias?: string) {
this.host = host;
this._alias = alias;
this.host.addController(this);
}

View File

@@ -1,4 +1,5 @@
export interface UmbControllerInterface {
get unique(): string | undefined;
hostConnected(): void;
hostDisconnected(): void;
destroy(): void;

View File

@@ -0,0 +1,50 @@
import { expect } from '@open-wc/testing';
import { customElement } from 'lit/decorators.js';
import { UmbContextProviderController } from '../context-api/provide/context-provider.controller';
import { UmbControllerHostInterface, UmbControllerHostMixin } from './controller-host.mixin';
class MyClass {
prop = 'value from provider';
}
@customElement('test-my-controller-host')
class MyHostElement extends UmbControllerHostMixin(HTMLElement) {
}
describe('UmbContextProvider', () => {
type NewType = UmbControllerHostInterface;
let hostElement: NewType;
const contextInstance = new MyClass();
beforeEach(() => {
hostElement = document.createElement('test-my-controller-host') as UmbControllerHostInterface;
});
describe('Destroyed controllers is gone from host', () => {
it('has a host property', () => {
const ctrl = new UmbContextProviderController(hostElement, 'my-test-context', contextInstance);
expect(hostElement.hasController(ctrl)).to.be.true;
ctrl.destroy();
expect(hostElement.hasController(ctrl)).to.be.false;
});
});
describe('Unique controllers replace each other', () => {
it('has a host property', () => {
const firstCtrl = new UmbContextProviderController(hostElement, 'my-test-context', contextInstance);
const secondCtrl = new UmbContextProviderController(hostElement, 'my-test-context', contextInstance);
expect(hostElement.hasController(firstCtrl)).to.be.false;
expect(hostElement.hasController(secondCtrl)).to.be.true;
});
});
});

View File

@@ -12,7 +12,7 @@ interface ResolvedContexts {
}
export declare class UmbElementMixinInterface extends UmbControllerHostInterface {
observe<T>(source: Observable<T>, callback: (_value: T) => void): UmbObserverController<T>;
observe<T>(source: Observable<T>, callback: (_value: T) => void, unique?: string): UmbObserverController<T>;
provideContext(alias: string, instance: unknown): UmbContextProviderController;
consumeContext(alias: string, callback: UmbContextCallback): UmbContextConsumerController;
consumeAllContexts(contextAliases: string[], callback: (_instances: ResolvedContexts) => void): void;
@@ -28,8 +28,8 @@ export const UmbElementMixin = <T extends HTMLElementConstructor>(superClass: T)
* @return {UmbObserverController} Reference to a Observer Controller instance
* @memberof UmbElementMixin
*/
observe<T>(source: Observable<T>, callback: (_value: T) => void): UmbObserverController<T> {
return new UmbObserverController<T>(this, source, callback);
observe<T>(source: Observable<T>, callback: (_value: T) => void, unique?: string): UmbObserverController<T> {
return new UmbObserverController<T>(this, source, callback, unique);
}
/**

View File

@@ -1,6 +1,6 @@
import { LitElement } from 'lit';
import { UmbElementMixin } from './element.mixin';
export abstract class UmbLitElement extends UmbElementMixin(LitElement) {
export class UmbLitElement extends UmbElementMixin(LitElement) {
}

View File

@@ -6,9 +6,23 @@ import { UmbControllerHostInterface } from 'src/core/controller/controller-host.
export class UmbObserverController<T> extends UmbObserver<T> implements UmbControllerInterface {
constructor(host:UmbControllerHostInterface, source: Observable<T>, callback: (_value: T) => void) {
_alias?: string;
public get unique() {
return this._alias;
}
constructor(host:UmbControllerHostInterface, source: Observable<T>, callback: (_value: T) => void, alias?: string) {
super(source, callback);
// TODO: What should happen if source or some? identifier is already present?
this._alias = alias;
// Lets check if controller is already here:
/*
if (this._subscriptions.has(source)) {
const subscription = this._subscriptions.get(source);
subscription?.unsubscribe();
}
*/
host.addController(this);
}
@@ -16,4 +30,5 @@ export class UmbObserverController<T> extends UmbObserver<T> implements UmbContr
return;
}
}

View File

@@ -3,16 +3,8 @@ import { Observable, Subscription } from 'rxjs';
export class UmbObserver<T> {
#subscription!: Subscription;
constructor(source: Observable<T>, callback: (_value: T) => void) {
// TODO: can be transferred to something using alias?
/*
if (this._subscriptions.has(source)) {
const subscription = this._subscriptions.get(source);
subscription?.unsubscribe();
}
*/
constructor(source: Observable<T>, callback: (_value: T) => void) {
this.#subscription = source.subscribe((value) => callback(value));
}
@@ -27,4 +19,4 @@ export class UmbObserver<T> {
this.#subscription.unsubscribe();
}
};
};

View File

@@ -7,12 +7,13 @@ import { UmbNotificationOptions, UmbNotificationService } from 'src/core/notific
import { UmbNotificationDefaultData } from 'src/core/notification/layouts/default';
export class UmbResourceController extends UmbController {
#promise: Promise<any>;
#notificationService?: UmbNotificationService;
constructor(host: UmbControllerHostInterface, promise: Promise<any>) {
super(host);
constructor(host: UmbControllerHostInterface, promise: Promise<any>, alias?: string) {
super(host, alias);
this.#promise = promise;