append api to folder name

This commit is contained in:
Mads Rasmussen
2023-05-16 14:05:46 +02:00
parent e20c735fae
commit bd0c552e7d
7 changed files with 0 additions and 0 deletions

View File

@@ -0,0 +1,34 @@
import { UmbControllerHostElement, UmbControllerHostMixin } from './controller-host.mixin';
export class UmbControllerHostInitializerElement
extends UmbControllerHostMixin(HTMLElement)
implements UmbControllerHostElement
{
/**
* A way to initialize controllers.
* @required
*/
create?: (host: UmbControllerHostElement) => void;
constructor() {
super();
this.attachShadow({ mode: 'open' });
const slot = document.createElement('slot');
this.shadowRoot?.appendChild(slot);
}
connectedCallback() {
super.connectedCallback();
if (this.create) {
this.create(this);
}
}
}
customElements.define('umb-controller-host-initializer', UmbControllerHostInitializerElement);
declare global {
interface HTMLElementTagNameMap {
'umb-controller-host-initializer': UmbControllerHostInitializerElement;
}
}

View File

@@ -0,0 +1,44 @@
import { expect, fixture, html } from '@open-wc/testing';
import { customElement } from 'lit/decorators.js';
import { UmbControllerHostInitializerElement } from './controller-host-initializer.element';
import { UmbControllerHostElement, UmbControllerHostMixin } from './controller-host.mixin';
import { UmbContextConsumerController, UmbContextProviderController } from '@umbraco-cms/backoffice/context-api';
@customElement('umb-test-controller-host-initializer-consumer')
export class UmbTestControllerHostInitializerConsumerElement extends UmbControllerHostMixin(HTMLElement) {
public value: string | null = null;
constructor() {
super();
new UmbContextConsumerController<string>(this, 'my-test-context-alias', (value) => {
this.value = value;
});
}
}
describe('UmbControllerHostTestElement', () => {
let element: UmbControllerHostInitializerElement;
let consumer: UmbTestControllerHostInitializerConsumerElement;
const contextValue = 'test-value';
beforeEach(async () => {
element = await fixture(
html` <umb-controller-host-initializer
.create=${(host: UmbControllerHostElement) =>
new UmbContextProviderController(host, 'my-test-context-alias', contextValue)}>
<umb-test-controller-host-initializer-consumer></umb-test-controller-host-initializer-consumer>
</umb-controller-host-initializer>`
);
consumer = element.getElementsByTagName(
'umb-test-controller-host-initializer-consumer'
)[0] as UmbTestControllerHostInitializerConsumerElement;
});
it('element is defined with its own instance', () => {
expect(element).to.be.instanceOf(UmbControllerHostInitializerElement);
});
it('provides the context', () => {
expect(consumer.value).to.equal(contextValue);
});
});

View File

@@ -0,0 +1,120 @@
import { UmbControllerInterface } from './controller.interface';
type HTMLElementConstructor<T = HTMLElement> = new (...args: any[]) => T;
export declare class UmbControllerHostElement extends HTMLElement {
hasController(controller: UmbControllerInterface): boolean;
getControllers(filterMethod: (ctrl: UmbControllerInterface) => boolean): UmbControllerInterface[];
addController(controller: UmbControllerInterface): void;
removeControllerByUnique(unique: UmbControllerInterface['unique']): 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
this.removeControllerByUnique(ctrl.unique);
this.#controllers.push(ctrl);
if (this.#attached) {
ctrl.hostConnected();
}
}
/**
* Remove a controller from this element, by its unique/alias.
* @param {unknown} unique/alias
*/
removeControllerByUnique(unique: UmbControllerInterface['unique']): void {
if (unique) {
this.#controllers.forEach((x) => {
if (x.unique === unique) {
this.removeController(x);
}
});
}
}
/**
* 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<UmbControllerHostElement> & T;
};
declare global {
interface HTMLElement {
connectedCallback(): void;
disconnectedCallback(): void;
}
}

View File

@@ -0,0 +1,27 @@
import { UmbControllerHostElement } from './controller-host.mixin';
import { UmbControllerInterface } from './controller.interface';
export abstract class UmbController implements UmbControllerInterface {
protected host?: UmbControllerHostElement;
private _alias?: string;
public get unique() {
return this._alias;
}
constructor(host: UmbControllerHostElement, 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;
}
}

View File

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

View File

@@ -0,0 +1,44 @@
import { expect } from '@open-wc/testing';
import { customElement } from 'lit/decorators.js';
import { UmbControllerHostElement, UmbControllerHostMixin } from './controller-host.mixin';
import { UmbContextProviderController } from '@umbraco-cms/backoffice/context-api';
class UmbTestContext {
prop = 'value from provider';
}
@customElement('test-my-controller-host')
export class UmbTestControllerHostElement extends UmbControllerHostMixin(HTMLElement) {}
describe('UmbContextProvider', () => {
type NewType = UmbControllerHostElement;
let hostElement: NewType;
const contextInstance = new UmbTestContext();
beforeEach(() => {
hostElement = document.createElement('test-my-controller-host') as UmbControllerHostElement;
});
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', new UmbTestContext());
expect(hostElement.hasController(firstCtrl)).to.be.false;
expect(hostElement.hasController(secondCtrl)).to.be.true;
});
});
});

View File

@@ -0,0 +1,3 @@
export * from './controller-host.mixin';
export * from './controller.class';
export * from './controller.interface';