Skip to content
Snippets Groups Projects
dbp-lit-element.js 5.26 KiB
Newer Older
Reiter, Christoph's avatar
Reiter, Christoph committed
import {AdapterLitElement} from './src/adapter-lit-element';
export default class DBPLitElement extends AdapterLitElement {
    constructor() {
        super();
        this.htmlOverrides = '';
        this._localTemplateSlotsImported = false;
        this._globalSlotsContainer = null;
        this._globalTemplateSlotsImported = false;
        this._renderDone = false;
    }

    static get properties() {
        return {
            ...super.properties,
Reiter, Christoph's avatar
Reiter, Christoph committed
            htmlOverrides: {type: String, attribute: 'html-overrides'},
    disconnectedCallback() {
        super.disconnectedCallback();

        if (this._globalSlotsContainer !== null) {
            this._globalSlotsContainer.remove();
Reiter, Christoph's avatar
Reiter, Christoph committed
        return this.shadowRoot === null
            ? this.querySelector(selector)
            : this.shadowRoot.querySelector(selector);
    _a(selector) {
        return this.shadowRoot === null
            ? this.querySelectorAll(selector)
            : this.shadowRoot.querySelectorAll(selector);
    }

    firstUpdated() {
        super.firstUpdated();
        this._renderDone = true;
        this._importTemplateSlots();
    }
    update(changedProperties) {
        changedProperties.forEach((oldValue, propName) => {
            switch (propName) {
Reiter, Christoph's avatar
Reiter, Christoph committed
                case 'html-overrides':
                    this._importTemplateSlots();
                    break;
            }
        });

        super.update(changedProperties);
     * Transforms all global override templates or named template slots in the light DOM to named div slots
     * Global overrides will replace all existing slotted elements with the same slot name.
Reiter, Christoph's avatar
Reiter, Christoph committed
    _importTemplateSlots() {
        this._importLocalTemplateSlots();
        this._importGlobalTemplateSlots();
    }
Reiter, Christoph's avatar
Reiter, Christoph committed
        if (this._localTemplateSlotsImported) {
        // Now extract slots from templates contained in the light dom
        let lightTemplateSlots = this.querySelectorAll(':scope > template[slot]:not([slot=""]');
Reiter, Christoph's avatar
Reiter, Christoph committed
        for (let templateElem of lightTemplateSlots) {
            // create a slot div container to put in the cloned template content
            const divElem = document.createElement('div');
            divElem.slot = templateElem.getAttribute('slot');
            divElem.appendChild(templateElem.content.cloneNode(true));
            templateElem.remove();
            // put the slot div container with the cloned template in the light DOM
            this.appendChild(divElem);
        }

        this._localTemplateSlotsImported = true;
    }

    _importGlobalTemplateSlots() {
Reiter, Christoph's avatar
Reiter, Christoph committed
        if (this.htmlOverrides === '' || this._globalTemplateSlotsImported) {
        // First add global override templates as light dom slots
        let globalOverrideTemplateElem = document.querySelector('template#' + this.htmlOverrides);
        if (globalOverrideTemplateElem !== null) {
            // we need to clone the element so we can access the content
            const overrideTemplateElemClone = globalOverrideTemplateElem.content.cloneNode(true);
Reiter, Christoph's avatar
Reiter, Christoph committed
            const templateOverrideElem = overrideTemplateElemClone.querySelector(
                'template#' + this.tagName.toLowerCase()
            );
            if (templateOverrideElem !== null) {
                const templateOverrideElemClone = templateOverrideElem.content.cloneNode(true);

                // Find all slots which are direct children (somehow :scope doesn't work here so check parentNode)
                let globalTemplateSlots = [];
Reiter, Christoph's avatar
Reiter, Christoph committed
                for (let e of templateOverrideElemClone.querySelectorAll('[slot]:not([slot=""]')) {
                    if (e.parentNode === templateOverrideElemClone) {
                        globalTemplateSlots.push(e);

                // Global overrides will replace local ones.
                // Either normal slotted elements or the ones we create from templates.
Reiter, Christoph's avatar
Reiter, Christoph committed
                for (let slotElem of globalTemplateSlots) {
                    for (let elm of this.querySelectorAll('[slot="' + slotElem.slot + '"]')) {
                        elm.remove();
                    }
                }

                // Create a dummy node and add it to the the same shadow root the templates are from
                // By adding it into the template we have the nice side effect that it is not visible
Reiter, Christoph's avatar
Reiter, Christoph committed
                let container = document.createElement('div');
                globalOverrideTemplateElem.append(container);
                this._globalSlotsContainer = container;
Reiter, Christoph's avatar
Reiter, Christoph committed
                for (let slotElem of globalTemplateSlots) {
                    container.appendChild(slotElem);
                }

                // Now move the slots into the light dom of the target.
                // The parent node in the other shadow root has to stay around for this to work
                while (container.childNodes.length) {
                    this.appendChild(container.removeChild(container.childNodes[0]));
                }

        this._globalTemplateSlotsImported = true;