migrate @umbraco-cms/controller to libs
This commit is contained in:
@@ -0,0 +1,112 @@
|
||||
import type { HTMLElementConstructor } from '../../src/core/models';
|
||||
import { UmbControllerInterface } from './controller.interface';
|
||||
|
||||
export declare class UmbControllerHostInterface extends HTMLElement {
|
||||
//#controllers:UmbController[];
|
||||
//#attached:boolean;
|
||||
hasController(controller: UmbControllerInterface): boolean;
|
||||
getControllers(filterMethod: (ctrl: UmbControllerInterface) => boolean): UmbControllerInterface[];
|
||||
addController(controller: UmbControllerInterface): void;
|
||||
removeController(controller: UmbControllerInterface): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* This mixin enables the component to host controllers.
|
||||
* This is done by calling the `consumeContext` method.
|
||||
*
|
||||
* @param {Object} superClass - superclass to be extended.
|
||||
* @mixin
|
||||
*/
|
||||
export const UmbControllerHostMixin = <T extends HTMLElementConstructor>(superClass: T) => {
|
||||
class UmbContextConsumerClass extends superClass {
|
||||
#controllers: UmbControllerInterface[] = [];
|
||||
|
||||
#attached = false;
|
||||
|
||||
/**
|
||||
* Tests if a controller is assigned to this element.
|
||||
* @param {UmbControllerInterface} ctrl
|
||||
*/
|
||||
hasController(ctrl: UmbControllerInterface): boolean {
|
||||
return this.#controllers.indexOf(ctrl) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve controllers matching a filter of this element.
|
||||
* @param {method} filterMethod
|
||||
*/
|
||||
getControllers(filterMethod: (ctrl: UmbControllerInterface) => boolean): UmbControllerInterface[] {
|
||||
return this.#controllers.filter(filterMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append a controller to this element.
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a controller from this element.
|
||||
* Notice this will also destroy the controller.
|
||||
* @param {UmbControllerInterface} ctrl
|
||||
*/
|
||||
removeController(ctrl: UmbControllerInterface): void {
|
||||
const index = this.#controllers.indexOf(ctrl);
|
||||
if (index !== -1) {
|
||||
this.#controllers.splice(index, 1);
|
||||
if (this.#attached) {
|
||||
ctrl.hostDisconnected();
|
||||
}
|
||||
ctrl.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a controller from this element by its alias.
|
||||
* Notice this will also destroy the controller.
|
||||
* @param {string} unique
|
||||
*/
|
||||
removeControllerByAlias(unique: string): void {
|
||||
this.#controllers.forEach((x) => {
|
||||
if (x.unique === unique) {
|
||||
this.removeController(x);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
connectedCallback() {
|
||||
super.connectedCallback?.();
|
||||
this.#attached = true;
|
||||
this.#controllers.forEach((ctrl: UmbControllerInterface) => ctrl.hostConnected());
|
||||
}
|
||||
|
||||
disconnectedCallback() {
|
||||
super.disconnectedCallback?.();
|
||||
this.#attached = false;
|
||||
this.#controllers.forEach((ctrl: UmbControllerInterface) => ctrl.hostDisconnected());
|
||||
}
|
||||
}
|
||||
|
||||
return UmbContextConsumerClass as unknown as HTMLElementConstructor<UmbControllerHostInterface> & T;
|
||||
};
|
||||
|
||||
declare global {
|
||||
interface HTMLElement {
|
||||
connectedCallback(): void;
|
||||
disconnectedCallback(): void;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { UmbControllerHostInterface } from './controller-host.mixin';
|
||||
import { UmbControllerInterface } from './controller.interface';
|
||||
|
||||
export abstract class UmbController implements UmbControllerInterface {
|
||||
protected 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);
|
||||
}
|
||||
|
||||
abstract hostConnected(): void;
|
||||
abstract hostDisconnected(): void;
|
||||
|
||||
public destroy() {
|
||||
if (this.host) {
|
||||
this.host.removeController(this);
|
||||
}
|
||||
delete this.host;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
export interface UmbControllerInterface {
|
||||
get unique(): string | undefined;
|
||||
hostConnected(): void;
|
||||
hostDisconnected(): void;
|
||||
destroy(): void;
|
||||
}
|
||||
44
src/Umbraco.Web.UI.Client/libs/controller/controller.test.ts
Normal file
44
src/Umbraco.Web.UI.Client/libs/controller/controller.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { expect } from '@open-wc/testing';
|
||||
import { customElement } from 'lit/decorators.js';
|
||||
import { UmbControllerHostInterface, UmbControllerHostMixin } from './controller-host.mixin';
|
||||
import { UmbContextProviderController } from '@umbraco-cms/context-api';
|
||||
|
||||
class MyClass {
|
||||
prop = 'value from provider';
|
||||
}
|
||||
|
||||
@customElement('test-my-controller-host')
|
||||
export 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;
|
||||
});
|
||||
});
|
||||
});
|
||||
3
src/Umbraco.Web.UI.Client/libs/controller/index.ts
Normal file
3
src/Umbraco.Web.UI.Client/libs/controller/index.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
export * from './controller-host.mixin';
|
||||
export * from './controller.class';
|
||||
export * from './controller.interface';
|
||||
Reference in New Issue
Block a user