UNPKG

enlink

Version:

web-portals

1,948 lines 71.1 kB
class ModuleProptey {
    constructor(id, model, application) {
        this.param = {};
        this.events = {
            transformStart: () => undefined,
            transformEnd: () => undefined,
            start: () => undefined,
            load: () => undefined,
            loadError: () => undefined,
            preload: () => undefined,
            destroy: () => undefined
        };
        this.createTime = Date.now();
        this.transient = false;
        this.shadowView = null;
        this.shadowViewType = null;
        this.status = {
            init: false,
            preload: false,
            prefetch: false,
            prerender: false
        };
        this.config = {
            title: '',
            rel: 'module',
            level: 0,
            source: {},
            prerender: [],
            apply: ['smart-setTimeout', 'link-in-new-window', ['tap-highlight', 'tap-highlight data-appeared']],
            free: true,
            background: 'auto'
        };
        this.resources = {
            script: [],
            image: [],
            worker: [],
            video: [],
            audio: [],
            font: [],
            style: []
        };
        this.elements = {
            container: document.body
        };
        this.id = id;
        this.param = {};
        this.application = application;
        const { config, resources, events } = this.setDefaultConfig(model);
        Object.assign(this.config, config);
        Object.assign(this.resources, resources);
        Object.assign(this.events, events);
    }
    setDefaultConfig(manifest) {
        var _a, _b, _c;
        if (((_a = manifest.config) === null || _a === void 0 ? void 0 : _a.rel) === 'frameworks') ;
        if ((_b = manifest.config) === null || _b === void 0 ? void 0 : _b.portal) {
            if (!manifest.config.free) {
                console.error('Module.config[free & portal] conflit!');
            }
        }
        if (isNaN((_c = manifest.config) === null || _c === void 0 ? void 0 : _c.level)) {
            manifest.config.level = 0;
        }
        if (manifest.config.level > 10000) {
            console.error('Module.confi.level <= 9999!');
        }
        return manifest;
    }
}

class ModuleState extends ModuleProptey {
    constructor(id, model, application) {
        super(id, model, application);
    }
    get sameOrigin() {
        if (!this.uri)
            return true;
        const link = document.createElement('a');
        link.href = this.uri;
        const isSameOrigin = link.host === location.host;
        return isSameOrigin;
    }
    get level() {
        var _a;
        const level = this.config.level || (((_a = this.application.activeModule) === null || _a === void 0 ? void 0 : _a.config.level) || 1) + 1;
        const baseLevel = this.config.free ? 20000 : 10000;
        return baseLevel + level;
    }
    get rel() {
        if (this.id === 'system')
            return 'system';
        if (this.id === 'frameworks')
            return 'frameworks';
        return this.config.rel || 'module';
    }
    get uri() {
        var _a, _b;
        return ((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.src) || '';
    }
    get viewType() {
        var _a;
        if (this.rel !== 'module')
            return 'shadow';
        if (!((_a = this.config) === null || _a === void 0 ? void 0 : _a.portal) || !this.uri)
            return 'iframe';
        if (!this.shadowViewType) {
            const type = ('HTMLPortalElement' in window) && this.sameOrigin ? 'portal' : 'iframe';
            this.shadowViewType = type;
        }
        return this.shadowViewType;
    }
}

class ModuleMount extends ModuleState {
    constructor(id, model, application) {
        super(id, model, application);
    }
    timeTick() {
        if (Date.now() - this.createTime > (this.config.timeout || 3600000)) {
            if (this.shadowView)
                this.destroy();
        }
    }
    show() {
        if (this.viewType !== 'iframe')
            return;
        const sandbox = this.shadowView;
        const contentWindow = sandbox === null || sandbox === void 0 ? void 0 : sandbox.contentWindow;
        if (contentWindow) {
            contentWindow.window.postMessage('module-visible', '*');
            if (this.sameOrigin) {
                contentWindow.window['moduleVisibilityState'] = 'visible';
            }
        }
    }
    hide() {
        var _a;
        if (this.viewType !== 'iframe')
            return;
        const sandbox = this.shadowView;
        const contentWindow = (_a = sandbox === null || sandbox === void 0 ? void 0 : sandbox.contentWindow) === null || _a === void 0 ? void 0 : _a.window;
        if (contentWindow) {
            contentWindow.postMessage('module-hidden', '*');
            if (this.sameOrigin) {
                contentWindow['moduleVisibilityState'] = 'visible';
            }
        }
    }
    destroy() {
        return new Promise((resolve, reject) => {
            var _a, _b, _c;
            if (this.rel !== 'module')
                return reject();
            if (((_a = this.application.transform) === null || _a === void 0 ? void 0 : _a.id) === this.id)
                return reject();
            if (this.viewType === 'iframe')
                this.unload().catch(reject);
            (_b = this.elements.container.parentElement) === null || _b === void 0 ? void 0 : _b.removeChild(this.elements.container);
            this.status.prefetch = this.status.preload = this.status.prerender = false;
            this.shadowView = null;
            this.status.init = false;
            (_c = this.events) === null || _c === void 0 ? void 0 : _c.destroy.bind(this)();
            resolve();
        });
    }
    fate() {
        return new Promise((resolve, reject) => {
            var _a;
            if (this.rel !== 'module')
                return reject();
            if (this.config.background === false)
                return resolve();
            if (this.viewType !== 'iframe')
                return resolve();
            if (this.sameOrigin === false)
                return resolve();
            const sandbox = this.shadowView;
            if (!sandbox)
                return;
            try {
                const contentDocumentElement = (_a = sandbox.contentDocument) === null || _a === void 0 ? void 0 : _a.documentElement;
                if (document.getElementsByTagName('video')[0])
                    return resolve();
                if (document.getElementsByTagName('source')[0])
                    return resolve();
                if (document.getElementsByTagName('object')[0])
                    return resolve();
                if (document.getElementsByTagName('audio')[0])
                    return resolve();
                if (document.getElementsByTagName('embed')[0])
                    return resolve();
                if (document.getElementsByTagName('applet')[0])
                    return resolve();
                if (document.getElementsByTagName('iframe')[0])
                    return resolve();
                if (contentDocumentElement) {
                    const counter = {
                        times: 0
                    };
                    this.mutationObserver = new MutationObserver(() => {
                        counter.times++;
                        if (counter.times > 1000) {
                            resolve();
                            this.mutationObserver.disconnect();
                        }
                    });
                    this.mutationObserver.observe(contentDocumentElement, {
                        subtree: true,
                        attributes: true,
                        childList: true,
                        characterData: true,
                        attributeOldValue: true,
                        characterDataOldValue: true
                    });
                    setTimeout(() => {
                        if (counter.times > 10)
                            resolve();
                    }, 3000);
                }
                else {
                    reject();
                }
            }
            catch (error) {
                reject();
            }
        });
    }
    unfate() {
        var _a;
        (_a = this.mutationObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
    }
    unload() {
        return new Promise((resolve, reject) => {
            var _a, _b;
            this.unfate();
            const sandbox = this.shadowView;
            if (!sandbox)
                return resolve();
            sandbox.style.display = 'none';
            sandbox.src = 'about:blank';
            try {
                const contentWindow = (_a = sandbox.contentWindow) === null || _a === void 0 ? void 0 : _a.window;
                const contentDocument = sandbox.contentDocument;
                contentWindow === null || contentWindow === void 0 ? void 0 : contentWindow.location.reload();
                contentDocument === null || contentDocument === void 0 ? void 0 : contentDocument.open();
                contentDocument === null || contentDocument === void 0 ? void 0 : contentDocument.write('');
                contentDocument === null || contentDocument === void 0 ? void 0 : contentDocument.close();
            }
            catch (error) {
                reject();
            }
            (_b = sandbox.parentElement) === null || _b === void 0 ? void 0 : _b.removeChild(sandbox);
            resolve();
        });
    }
}

class ModulePrefetch extends ModuleMount {
    constructor(id, model, application) {
        super(id, model, application);
    }
    prefetch() {
        return new Promise((resolve, reject) => {
            Promise.all([
                this.prefetchStatic(this.resources.script, 'script'),
                this.prefetchStatic(this.resources.image, 'image'),
                this.prefetchStatic(this.resources.worker, 'worker'),
                this.prefetchStatic(this.resources.video, 'video'),
                this.prefetchStatic(this.resources.audio, 'audio'),
                this.prefetchStatic(this.resources.font, 'font'),
                this.prefetchStatic(this.resources.style, 'style')
            ]).then(() => {
                this.status.prefetch = true;
                resolve(true);
            }).catch(reject);
        });
    }
    prefetchStatic(list = [], as = 'script') {
        return new Promise((resolve, reject) => {
            Promise.all([].concat(list).map(url => this.beforehandLink(url, 'preload', as))).then(resolve).catch(reject);
        });
    }
    beforehandLink(url, rel = 'preload', as = 'worker | video | audio | font | script | style | image | document') {
        if (!url)
            return Promise.reject();
        return new Promise((resolve, reject) => {
            var _a;
            const link = document.createElement('link');
            link.rel = rel;
            link.href = url;
            link.as = as;
            link.onload = resolve;
            link.onerror = reject;
            if (!((_a = link.relList) === null || _a === void 0 ? void 0 : _a.supports(rel))) {
                reject();
            }
            document.getElementsByTagName('head')[0].appendChild(link);
        });
    }
}

var windowOpen = (moduleWindow, application) => {
    const realOpen = moduleWindow.open;
    moduleWindow.addEventListener('click', (event) => {
        const path = event['path'] || [];
        const anchor = (() => {
            for (const el of path) {
                if (el.tagName === 'A')
                    return el;
            }
        })();
        if ((anchor === null || anchor === void 0 ? void 0 : anchor.target) === '_bank') {
            const href = anchor.href;
            const title = anchor.title || '';
            const preset = anchor.getAttribute('preset');
            if (href) {
                application.pushWindow(href, title, preset).catch(() => {
                    realOpen(href);
                });
                event.stopPropagation();
                event.preventDefault();
            }
        }
    });
    moduleWindow.open = (url, target, features) => {
        if (typeof url !== 'string' || target || features) {
            return realOpen(url, target, features);
        }
        if (typeof url === 'string') {
            application.pushWindow(url, '').catch(() => {
                realOpen(url);
            });
        }
        return null;
    };
};

const getTimerHandler = (handler, moduleWindow) => {
    return (..._args) => {
        if (moduleWindow['moduleVisibilityState'] === 'visible') {
            if (typeof handler === 'function') {
                handler(..._args);
            }
            else if (typeof handler === 'string') {
                const evalHander = new moduleWindow['Function'](`return ${handler}`);
                evalHander(..._args);
            }
        }
    };
};
const smartSetTimeout = (moduleWindow) => {
    const realSetTimeout = moduleWindow.setTimeout;
    moduleWindow.setInterval = (handler, timeout, ...args) => {
        const fn = getTimerHandler(handler, moduleWindow);
        const intervalId = realSetTimeout(fn, timeout, ...args);
        return intervalId;
    };
};
const smartSetInterval = (moduleWindow) => {
    const realSetInterval = moduleWindow.setInterval;
    moduleWindow.setInterval = (handler, timeout, ...args) => {
        const fn = getTimerHandler(handler, moduleWindow);
        const intervalId = realSetInterval(fn, timeout, ...args);
        return intervalId;
    };
};

var tapHighlight = (moduleWindow, capture) => {
    const touchActive = {
        element: null,
        oldStyle: ''
    };
    const addHighlight = (event) => {
        const captureList = capture ? typeof capture === 'string' ? capture.split(' ') : capture : null;
        const path = event['path'] || event.composedPath() || [];
        path.splice(-3);
        const anchor = (() => {
            var _a, _b, _c;
            for (const el of path) {
                if (!((_a = el.children) === null || _a === void 0 ? void 0 : _a.length))
                    continue;
                if (el.tagName === 'A')
                    return el;
                if (captureList) {
                    for (const attr of captureList) {
                        if (el === null || el === void 0 ? void 0 : el.getAttribute(attr))
                            return el;
                    }
                }
            }
            return (((_c = (_b = path[0]) === null || _b === void 0 ? void 0 : _b.children) === null || _c === void 0 ? void 0 : _c.length) ? path[0] : path[1]) || event.target;
        })();
        if (!anchor)
            return;
        touchActive.element = anchor;
        touchActive.oldStyle = anchor.style.filter;
        setTimeout(() => {
            if (touchActive.element === anchor)
                anchor.style.filter = touchActive.oldStyle + ' brightness(.8)';
            const continueCheck = () => {
                setTimeout(() => {
                    if (touchActive.element !== anchor) {
                        anchor.style.filter = touchActive.oldStyle;
                    }
                    else {
                        continueCheck();
                    }
                }, 600);
            };
            continueCheck();
        }, 60);
    };
    const cancelHighlight = () => {
        var _a, _b;
        if ((_b = (_a = touchActive.element) === null || _a === void 0 ? void 0 : _a.style) === null || _b === void 0 ? void 0 : _b.filter) {
            touchActive.element.style.filter = touchActive.oldStyle;
        }
        touchActive.element = null;
        touchActive.oldStyle = '';
    };
    const delayCancelHighlight = () => {
        setTimeout(() => {
            cancelHighlight();
        }, 600);
    };
    moduleWindow.document.addEventListener('touchstart', addHighlight);
    moduleWindow.addEventListener('touchstart', addHighlight);
    moduleWindow.addEventListener('touchmove', cancelHighlight);
    moduleWindow.addEventListener('touchcancel', cancelHighlight);
    moduleWindow.addEventListener('touchend', delayCancelHighlight);
};

var inject = (moduleWindow, config, application) => {
    const apply = config.apply || [];
    if (Array.isArray(apply)) {
        for (const item of apply) {
            switch (item) {
                case 'link-in-new-window':
                    windowOpen(moduleWindow, application);
                    break;
                case 'smart-setTimeout':
                    smartSetTimeout(moduleWindow);
                    break;
                case 'smart-setInterval':
                    smartSetInterval(moduleWindow);
                    break;
                case 'tap-highlight':
                    tapHighlight(moduleWindow);
                    break;
                default:
                    if (Array.isArray(item)) {
                        switch (item[0]) {
                            case 'tap-highlight':
                                tapHighlight(moduleWindow, item[1]);
                                break;
                        }
                    }
                    break;
            }
        }
    }
    if (typeof config.inject === 'function') {
        config.inject(moduleWindow, config, application);
    }
};

class ModuleView extends ModulePrefetch {
    constructor(id, model, application) {
        super(id, model, application);
    }
    rigesterElement(name, element) {
        this.elements[name] = element;
        if (name === 'container' && element) {
            this.status.init = true;
        }
    }
    createSandbox(uri, config) {
        const sandbox = document.createElement('iframe');
        if (config !== undefined)
            sandbox.setAttribute('sandbox', config);
        if (uri)
            sandbox.src = uri;
        return sandbox;
    }
    writeSandbox(sandbox, container) {
        var _a, _b;
        sandbox.src = 'about:blank';
        sandbox.setAttribute('seamless', 'seamless');
        container.appendChild(sandbox);
        const contentDocument = sandbox.contentDocument;
        const contentWindow = sandbox.contentWindow;
        if (contentWindow && contentDocument) {
            contentDocument.open();
            contentDocument.write(((_b = (_a = this.config) === null || _a === void 0 ? void 0 : _a.source) === null || _b === void 0 ? void 0 : _b.html) || '<head><meta charset="utf-8"></head>');
            contentDocument.close();
            inject(contentWindow === null || contentWindow === void 0 ? void 0 : contentWindow.window, this.config, this.application);
        }
    }
    createShadowbox(render) {
        const shadowbox = document.createElement('div');
        const shadowboxInner = document.createElement('div');
        shadowbox === null || shadowbox === void 0 ? void 0 : shadowbox.attachShadow({ mode: 'open' });
        const shadowRoot = shadowbox.shadowRoot ? shadowbox.shadowRoot : shadowbox;
        shadowRoot.appendChild(shadowboxInner);
        render(shadowboxInner);
        this.elements.container.appendChild(shadowbox);
        return shadowbox;
    }
    createPortals(uri) {
        const portal = document.createElement('portal');
        portal.src = uri;
        return portal;
    }
    createShadowView() {
        if (this.shadowView)
            return this.shadowView;
        if (this.config.render) {
            return this.shadowView = this.createShadowbox(this.config.render);
        }
        if (this.rel !== 'module')
            return;
        return this.shadowView = this.viewType === 'portal' ? this.createPortals(this.uri) : this.createSandbox(this.uri, this.config.sandbox);
    }
    loadShadowView() {
        const container = this.elements.container;
        const shadowView = this.shadowView;
        if (!shadowView)
            return;
        switch (this.viewType) {
            case 'portal':
                container.appendChild(shadowView);
                break;
            case 'iframe':
            default:
                if (this.uri) {
                    container.appendChild(shadowView);
                    const contentWindow = shadowView.contentWindow;
                    if (contentWindow && this.sameOrigin) {
                        inject(contentWindow === null || contentWindow === void 0 ? void 0 : contentWindow.window, this.config, this.application);
                        contentWindow === null || contentWindow === void 0 ? void 0 : contentWindow.window.postMessage('container-ready', '*');
                    }
                }
                else {
                    this.writeSandbox(shadowView, container);
                }
                break;
        }
    }
    create(prepare = true) {
        this.unfate();
        this.timeTick();
        if (this.status.prerender) {
            return Promise.resolve('prerender');
        }
        return new Promise((resolve, reject) => {
            this.createTime = Date.now();
            const shadowView = this.createShadowView();
            if (!shadowView) {
                return resolve('null');
            }
            if (this.viewType === 'shadow') {
                return resolve('shadow');
            }
            shadowView.style.cssText = `
        position: absolute;
        z-index: 0;
        width: 100%;
        height: 100%;
        border: 0;
        transform: translate3d(0, 0, 0);
      `;
            shadowView.onload = (e) => {
                var _a;
                this.status.prerender = true;
                (_a = this.events) === null || _a === void 0 ? void 0 : _a.load.bind(this)();
                resolve(e);
            };
            shadowView.onerror = (e) => {
                var _a;
                (_a = this.events) === null || _a === void 0 ? void 0 : _a.loadError.bind(this)();
                reject(e);
            };
            this.loadShadowView();
            if (prepare === false || this.config.animation === false) {
                return resolve('instant');
            }
            setTimeout(() => {
                resolve('timeout');
            }, this.status.preload ? 800 : 200);
        });
    }
    preload() {
        return new Promise((resolve, reject) => {
            const uri = this.uri;
            const head = document.head;
            const sandbox = this.createSandbox('', '');
            sandbox.style.display = 'none';
            sandbox.onload = (e) => {
                var _a;
                this.status.preload = true;
                head.removeChild(sandbox);
                (_a = this.events) === null || _a === void 0 ? void 0 : _a.preload.bind(this)();
                resolve(e);
            };
            sandbox.onerror = (e) => {
                head.removeChild(sandbox);
                reject(e);
            };
            if (uri) {
                sandbox.src = this.uri;
                head.appendChild(sandbox);
            }
            else {
                this.writeSandbox(sandbox, head);
            }
        });
    }
    prerender() {
        if (this.status.preload || this.status.prerender) {
            return Promise.resolve();
        }
        return new Promise((resolve, reject) => {
            this.preload().then(resolve).catch(reject);
            this.beforehandLink(this.uri, 'prerender', 'document');
        });
    }
}

class Module extends ModuleView {
    constructor(id, model, application) {
        super(id, model, application);
        this.events.start.bind(this)();
    }
}

/*! *****************************************************************************
Copyright (c) Microsoft Corporation.

Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */

function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
}

var ease = {
    'in': 'ease-in',
    'out': 'ease-out',
    'in-out': 'ease-in-out',
    'snap': 'cubic-bezier(0, 1, .5, 1)',
    'linear': 'cubic-bezier(0.250, 0.250, 0.750, 0.750)',
    'ease-in-quad': 'cubic-bezier(0.550, 0.085, 0.680, 0.530)',
    'ease-in-cubic': 'cubic-bezier(0.550, 0.055, 0.675, 0.190)',
    'ease-in-quart': 'cubic-bezier(0.895, 0.030, 0.685, 0.220)',
    'ease-in-quint': 'cubic-bezier(0.755, 0.050, 0.855, 0.060)',
    'ease-in-sine': 'cubic-bezier(0.470, 0.000, 0.745, 0.715)',
    'ease-in-expo': 'cubic-bezier(0.950, 0.050, 0.795, 0.035)',
    'ease-in-circ': 'cubic-bezier(0.600, 0.040, 0.980, 0.335)',
    'ease-in-back': 'cubic-bezier(0.600, -0.280, 0.735, 0.045)',
    'ease-out-quad': 'cubic-bezier(0.250, 0.460, 0.450, 0.940)',
    'ease-out-cubic': 'cubic-bezier(0.215, 0.610, 0.355, 1.000)',
    'ease-out-quart': 'cubic-bezier(0.165, 0.840, 0.440, 1.000)',
    'ease-out-quint': 'cubic-bezier(0.230, 1.000, 0.320, 1.000)',
    'ease-out-sine': 'cubic-bezier(0.390, 0.575, 0.565, 1.000)',
    'ease-out-expo': 'cubic-bezier(0.190, 1.000, 0.220, 1.000)',
    'ease-out-circ': 'cubic-bezier(0.075, 0.820, 0.165, 1.000)',
    'ease-out-back': 'cubic-bezier(0.175, 0.885, 0.320, 1.275)',
    'ease-in-out-quad': 'cubic-bezier(0.455, 0.030, 0.515, 0.955)',
    'ease-in-out-cubic': 'cubic-bezier(0.645, 0.045, 0.355, 1.000)',
    'ease-in-out-quart': 'cubic-bezier(0.770, 0.000, 0.175, 1.000)',
    'ease-in-out-quint': 'cubic-bezier(0.860, 0.000, 0.070, 1.000)',
    'ease-in-out-sine': 'cubic-bezier(0.445, 0.050, 0.550, 0.950)',
    'ease-in-out-expo': 'cubic-bezier(1.000, 0.000, 0.000, 1.000)',
    'ease-in-out-circ': 'cubic-bezier(0.785, 0.135, 0.150, 0.860)',
    'ease-in-out-back': 'cubic-bezier(0.680, -0.550, 0.265, 1.550)'
};

class EventProvider {
    constructor() {
        this._events = {};
    }
    on(type, fn) {
        const types = type.split(' ');
        types.forEach((typ) => {
            if (!this._events[typ]) {
                this._events[typ] = [fn];
            }
            else {
                this._events[typ].push(fn);
            }
        });
        return this;
    }
    one(type, fn) {
        const once = (...args) => {
            fn.apply(null, args);
            this.off(type, once);
        };
        const types = type.split(' ');
        types.forEach((typ) => {
            if (!this._events[typ]) {
                this._events[typ] = [once];
            }
            else {
                this._events[typ].push(once);
            }
        });
        return this;
    }
    off(type, fn) {
        const types = type.split(' ');
        types.forEach((typ) => {
            if (!this._events[typ])
                return;
            const index = this._events[typ].indexOf(fn);
            if (index > -1) {
                this._events[typ].splice(index, 1);
            }
        });
        return this;
    }
    trigger(type, ...args) {
        if (!this._events[type])
            return;
        this._events[type].forEach(fn => {
            try {
                fn.apply(null, args);
            }
            catch (e) {
                this.off(type, fn);
                this.trigger('error', `Error by event[${type}]`);
            }
        });
        return this;
    }
}

const rAF = requestAnimationFrame;
const gCS = getComputedStyle;
/* Animate */
class Animate extends EventProvider {
    constructor(el) {
        super();
        this._props = {};
        this._transforms = {};
        this._transforming = false;
        this._proper = [];
        this._caller = [];
        this._transitionProps = [];
        this.translate = this.to;
        this.translate3d = this.to;
        this.translateX = this.x;
        this.translateY = this.y;
        this.translateZ = this.z;
        if (!el)
            return;
        this.el = el;
        this.el.style.setProperty('transition-duration', '0ms');
    }
    transform(transform) {
        this.transition('transform');
        const propName = (transform.match(/\w+\b/) || [])[0];
        if (propName)
            this._transforms[propName] = transform;
        return this;
    }
    skew(x, y) {
        return this.transform('skew(' + x + 'deg, ' + (y || 0) + 'deg)');
    }
    skewX(n) {
        return this.transform('skewX(' + n + 'deg)');
    }
    skewY(n) {
        return this.transform('skewY(' + n + 'deg)');
    }
    to(x = 0, y = 0, z = 0) {
        // 3d set
        this.transform('translate3d(' + (x ? x + 'px' : 0) + ',' + (y ? y + 'px' : 0) + ',' + (z ? z + 'px' : 0) + ')');
        return this;
    }
    x(n) {
        return this.transform('translateX(' + n + 'px)');
    }
    y(n) {
        return this.transform('translateY(' + n + 'px)');
    }
    z(z) {
        return this.transform('translateZ(' + z + 'px)');
    }
    scale(x, y) {
        return this.transform('scale(' +
            x + ', ' +
            (y || x) +
            ')');
    }
    opacity(o) {
        this.transition('opacity');
        return this.style('opacity', o);
    }
    scaleX(n) {
        return this.transform('scaleX(' + n + ')');
    }
    matrix(m11, m12, m21, m22, m31, m32) {
        return this.transform('matrix(' + [m11, m12, m21, m22, m31, m32].join(',') + ')');
    }
    scaleY(n) {
        return this.transform('scaleY(' + n + ')');
    }
    rotate(n) {
        return this.transform('rotate(' + n + 'deg)');
    }
    rotateX(n) {
        return this.transform('rotateX(' + n + 'deg)');
    }
    rotateY(n) {
        return this.transform('rotateY(' + n + 'deg)');
    }
    rotateZ(n) {
        return this.transform('rotateZ(' + n + 'deg)');
    }
    rotate3d(x, y, z, d) {
        return this.transform('rotate3d(' + x + ', ' + y + ',' + z + ',' + d + 'deg)');
    }
    perspective(z) {
        const box = this.el.parentElement;
        if (box) {
            box.style.setProperty('transform-style', 'preserve-3d');
            box.style.setProperty('perspective', z + 'px');
        }
        return this;
    }
    backface(visibility = true) {
        return this.style('backface-visibility', visibility ? 'visible' : 'hidden');
    }
    ease(s) {
        s = ease[s] || s || 'ease';
        return this.style('transition-timing-function', s);
    }
    animate(name, props) {
        for (const i in props) {
            if (props.hasOwnProperty(i)) {
                this.style('animation-' + i, props[i]);
            }
        }
        return this.style('animation-name', name);
    }
    duration(n) {
        n = 'string' === typeof n ?
            parseFloat(n) * 1000 :
            n;
        return this.style('transition-duration', n + 'ms');
    }
    getDuration() {
        return !!parseFloat(gCS(this.el).transitionDuration);
    }
    delay(n) {
        n = 'string' === typeof n ?
            parseFloat(n) * 1000 :
            n;
        return this.style('transition-delay', n + 'ms');
    }
    origin(x, y) {
        let n = 'center';
        if (typeof x === 'object') {
            y = x[1] || 0;
            x = x[0] || 0;
        }
        if (!isNaN(x) && !isNaN(y)) {
            n = x + 'px' + ' ' + y + 'px';
        }
        else if (y) {
            n = x + ' ' + y;
        }
        return this.style('transform-origin', n);
    }
    width(val) {
        this.transition('width');
        return this.style('width', val === undefined ? '' : val + 'px');
    }
    height(val) {
        this.transition('height');
        return this.style('height', val === undefined ? '' : val + 'px');
    }
    add(prop, val) {
        return this.on('start', () => {
            const curr = parseInt(this.current(prop), 10);
            this.style(prop, curr + val + 'px');
        });
    }
    subc(prop, val) {
        return this.on('start', () => {
            const curr = parseInt(this.current(prop), 10);
            this.style(prop, curr - val + 'px');
        });
    }
    current(prop) {
        return gCS(this.el).getPropertyValue(prop);
    }
    transition(prop) {
        if (this._transitionProps.indexOf(prop) === -1)
            this._transitionProps.push(prop);
        return this;
    }
    filter(val) {
        this.style('filter', val);
        this.transition('filter');
        return this;
    }
    style(prop, val) {
        this._props[prop] = val === undefined ? '' : val;
        return this;
    }
    _transitionend(fn) {
        if (!this.getDuration())
            return setTimeout(fn, 0);
        const onec = (e) => {
            if (e.target !== this.el)
                return false;
            fn(e);
            this.el.removeEventListener('transitionend', onec, false);
        };
        this.el.addEventListener('transitionend', onec, false);
    }
    _applyTransform() {
        const transform = [];
        if (!this._transforms['translate3d'] && !this._transforms['translateZ']) {
            this._transforms['translateZ'] = 'translateZ(0)';
        }
        for (const i in this._transforms) {
            transform.push(this._transforms[i]);
        }
        if (transform.length) {
            this.style('transform', transform.join(' '));
        }
        return this;
    }
    applyProperties() {
        const prop = this._proper.shift();
        this._transforming = true;
        for (const name in prop) {
            this.el.style.setProperty(name, prop[name]);
        }
        this._transitionend(() => {
            this.clear();
            this.next();
        });
        return this;
    }
    next() {
        if (this._caller.length) {
            const fn = this._caller.shift();
            fn && fn();
        }
        if (this._caller.length === 0) {
            this.init();
        }
        else {
            rAF(() => { this.applyProperties(); });
        }
    }
    clear() {
        this._transforms = {};
    }
    init() {
        if (this.getDuration()) {
            this.el.style.setProperty('transition-duration', '0ms');
        }
        this.clear();
        this._transforming = false;
        return this;
    }
    then(fn) {
        this._applyTransform();
        this.style('transition-property', this._transitionProps.join(', '));
        this._proper.push(this._props);
        this._props = {};
        this._caller.push(() => fn && fn.call(this));
        return this;
    }
    end(fn) {
        this.then(fn);
        if (this._transforming)
            return this;
        rAF(() => { this.applyProperties(); });
        return this;
    }
}

var flip = (e) => {
    e.in.duration(0).ease('ease-out-expo').perspective(1000).to(0, 0, 0).opacity(0).rotate3d(0, 1, 0, 90 * e.direction).scale(.92).end(() => {
        e.out.duration(400).ease('ease-out-expo').perspective(1000).rotate3d(0, 1, 0, -90 * e.direction).scale(.92).end(() => {
            e.out.duration(0).opacity(0).end();
            e.in.duration(0).to(0, 0, 0).opacity(1).rotate3d(0, 1, 0, 90 * e.direction).scale(1).end(() => {
                e.in.duration(400).rotate3d(0, 1, 0, 0).end(() => {
                    e.callback(false);
                });
            });
        });
    });
};

var fade = (type) => {
    return (e) => {
        let inO, outO, inV, outV;
        switch (type) {
            case 0:
                inO = 1;
                outO = 0;
                inV = e.in;
                outV = e.out;
                break;
            case 1:
            default:
                inO = 0;
                outO = 1;
                inV = outV = e.in;
        }
        inV.duration(0).ease('ease-out-expo').to(0, 0, 0).opacity(inO).end(function () {
            outV.duration(300).opacity(outO).end(function () {
                e.callback(false);
            });
        });
    };
};

var zoom = (type) => {
    return (e) => {
        e.in.origin(type === 0 ? e.attach : e.origin).ease('ease-out-expo').duration(0).to(0, 0, 0).scale(type === 0 ? 2.5 : 0).end(() => {
            e.out.origin(type === 1 ? e.attach : e.origin).ease('ease-in-expo').duration(0).to(0, 0, 0).opacity(1).scale(1).end(() => {
                e.in.duration(767).to(0, 0, 0).scale(1).end();
                e.out.duration(400).opacity(type === 0 ? 0 : 1).scale(type === 0 ? 0 : 2.5).end(() => {
                    e.callback(false);
                });
            });
        });
    };
};

var slide = (type) => {
    return (e) => {
        let inX = 0;
        let outX = 0;
        let inY = 0;
        let outY = 0;
        switch (type) {
            case 0:
                outY = e.height;
                inY = -outY;
                inX = outX = 0;
                break;
            case 1:
                inX = e.width;
                outX = -inX;
                inY = outY = 0;
                break;
            case 2:
                inY = e.height;
                outY = -inY;
                inX = outX = 0;
                break;
            case 3:
                outX = e.width;
                inX = -outX;
                inY = outY = 0;
                break;
        }
        if (e.reverse) {
            e.in.duration(0).filter('brightness(0.5)').to(inX * .1, inY * .1, 0).end(() => {
                e.out.duration(767).ease('ease-out-expo').to(outX, outY, 0).end();
                e.in.duration(767).filter('brightness(1)').to(0, 0, 0).end(() => {
                    e.callback(false);
                });
            });
        }
        else {
            e.in.duration(0).to(inX, inY, 0).end(() => {
                e.in.duration(767).ease('ease-out-expo').to(0, 0, 0).end(() => {
                    e.callback(false);
                });
                e.out.duration(767).filter('brightness(0.5)').to(outX * .5, outY * .5, 0).end();
            });
        }
    };
};

var effectTypes = {
    flip,
    fade,
    zoom,
    slide
};

class TransformProptey {
    constructor(app) {
        this.id = '';
        this.od = '';
        this.ids = [];
        this.param = '';
        this.history = 0;
        this.animation = false;
        this.switchover = false;
        this.relativeViewport = document.createElement('relative-windows');
        this.absoluteViewport = document.createElement('absolute-windows');
        this.fixedViewport = document.createElement('fixed-windows');
        this.target = this.relativeViewport;
        this.app = app;
        this.setupViewport();
    }
    setupViewport() {
        var _a, _b;
        this.relativeViewport.id = 'relative-viewport';
        (_a = this.relativeViewport) === null || _a === void 0 ? void 0 : _a.attachShadow({ mode: 'open' });
        this.absoluteViewport.id = 'absolute-viewport';
        (_b = this.absoluteViewport) === null || _b === void 0 ? void 0 : _b.attachShadow({ mode: 'open' });
        this.resetViewport();
        this.fixedViewport.id = 'fixed-viewport';
        this.fixedViewport.style.position = 'fixed';
        this.fixedViewport.style.zIndex = '3';
        this.fixedViewport.style.width = '100%';
        this.fixedViewport.style.height = '0';
        this.fixedViewport.style.contain = 'strict';
        this.fixedViewport.style.overflow = 'visible';
        document.body.appendChild(this.relativeViewport);
        document.body.appendChild(this.absoluteViewport);
        document.body.appendChild(this.fixedViewport);
    }
    resetViewport() {
        this.relativeViewport.style.cssText = '';
        this.relativeViewport.style.position = 'absolute';
        this.relativeViewport.style.zIndex = '1';
        this.relativeViewport.style.width = this.relativeViewport.style.height = '100%';
        this.relativeViewport.style.overflow = 'hidden';
        this.relativeViewport.style.contain = 'strict';
        this.absoluteViewport.style.cssText = '';
        this.absoluteViewport.style.position = 'absolute';
        this.absoluteViewport.style.zIndex = '2';
        this.absoluteViewport.style.width = this.absoluteViewport.style.height = '100%';
        this.absoluteViewport.style.overflow = 'visible';
        this.absoluteViewport.style.contain = 'strict';
    }
}

class TransformAnimation extends TransformProptey {
    constructor(app) {
        super(app);
    }
    getAnimationGroup() {
        if (!this.modulu || this.modulu.rel !== 'module')
            return false;
        let animationFunction;
        let animationNames = this[this.history === -1 ? 'modulu' : 'module'].config.animation;
        if (animationNames === true || animationNames === 'inherit') {
            animationNames = this.options.defaultAnimation;
        }
        if (typeof animationNames === 'string') {
            animationFunction = this.getAnimationByName(animationNames);
        }
        else if (typeof (animationNames === null || animationNames === void 0 ? void 0 : animationNames[0]) !== 'function') {
            return animationNames;
        }
        if (typeof (animationFunction === null || animationFunction === void 0 ? void 0 : animationFunction[0]) !== 'function') {
            return false;
        }
        return animationFunction;
    }
    getAnimationOneSide(backset) {
        const animationGroup = this.animation;
        if (backset >= 0) {
            switch (typeof animationGroup) {
                case 'function':
                    return animationGroup;
                case 'object':
                    return animationGroup[animationGroup.length === 2 ? backset : 0];
                default:
                    return;
            }
        }
        return;
    }
    getAnimationByName(type) {
        switch (type) {
            case 'flip':
                return [effectTypes.flip, effectTypes.flip];
            case 'fade':
                return [effectTypes.fade(1), effectTypes.fade(0)];
            case 'zoom':
                return [effectTypes.zoom(1), effectTypes.zoom(0)];
            case 'slide':
            case 'slideLeft':
            case 'slideleft':
            case 'slide-left':
                return [effectTypes.slide(1), effectTypes.slide(3)];
            case 'slideRight':
            case 'slideright':
            case 'slide-right':
                return [effectTypes.slide(3), effectTypes.slide(1)];
            case 'slideUp':
            case 'slideup':
            case 'slide-up':
                return [effectTypes.slide(0), effectTypes.slide(2)];
            case 'slideDown':
            case 'slidedown':
            case 'slide-down':
                return [effectTypes.slide(2), effectTypes.slide(0)];
            default:
                return;
        }
    }
}

class TransformHistory extends TransformAnimation {
    constructor(app) {
        super(app);
        this.backoutCount = 0;
        this.bindHistoryState();
    }
    bindHistoryState() {
        addEventListener('popstate', this.popstate.bind(this));
    }
    popstate(event) {
        this.back(event);
    }
    pushState(id = '', title = '', search = location.search, param = '') {
        id = encodeURIComponent(id);
        history.pushState({
            id,
            title,
            time: Date.now(),
            search,
            historyIndex: history.length
        }, title, location.pathname + search + '#' + id + '/' + param);
    }
    replaceState(id = '', title = '', search = location.search, param = '') {
        id = encodeURIComponent(id);
        history.replaceState({
            id,
            title,
            time: Date.now(),
            search,
            historyIndex: history.length
        }, title, location.pathname + search + '#' + id + '/' + param);
    }
    back(event) {
        return __awaiter(this, void 0, void 0, function* () {
            const options = this.options;
            const route = event.state || this.app.route;
            const id = decodeURIComponent(route.id) || options.index || 'frameworks';
            const search = route.search;
            const module = yield this.app.get(id);
            if (!module)
                return;
            /**
             * 如果设置了单向锁,且回退时模块层级为 0 时
             * 阻止返回,并发送事件
             */
            if (this.checkSingleLock()) {
                this.backoutCount++;
                this.pushState(id, module.config.title, search);
                this.app.trigger('exit', {
                    backoutCount: this.backoutCount
                });
                return;
            }
            else {
                this.backoutCount = 0;
            }
            if (options.singleFlow && module.config.level !== 0 && module.config.level >= this.module.config.level) {
                return history.back();
            }
            this.app.transform.to(id, search, -1);
            this.app.trigger('back', {
                id,
                module
            });
        });
    }
    checkSingleLock() {
        return this.options.singleLock && this.module.config.level === 0 ? true : false;
    }
}

class TransformSwitch extends TransformHistory {
    constructor(app) {
        super(app);
        this.windowSet = [];
        this.promiseQueue = [];
        this.promiseParamQueue = [];
    }
    checkSingleLock() {
        return this.options.singleLock && this.module.config.level === 0 ? true : false;
    }
    createContainer(module) {
        if (module.status.init)
            return;
        const container = document.createElement('module-container');
        container.setAttribute('name', this.id);
        container.setAttribute('type', ['frameworks', 'system'].indexOf(this.id) !== -1 ? this.id : 'module');
        module.rigesterElement('container', container);
        this.resetContainer(module, this.switchover || !this.animation);
        this.getViewport(module).appendChild(container);
    }
    resetContainer(module, situ = false) {
        const config = module.config;
        const container = module.elements.container;
        const systemLevel = ['frameworks', 'system'].includes(module.rel);
        const isDarkModel = this.app.properties.darkTheme;
        container.style.cssText = '';
        if (!systemLevel) {
            container.style.cssText = `
        position: absolute;
        z-index: ${(Number(module.level) || 0) + 1};
        width: 100%;
        height: 100%;
        background: ${config.color || (isDarkModel ? '#000' : '#fff')};
        transform: ${situ ? 'translate3d(0, 0, 0)' : 'translate3d(200%, 200%, 0)'};
        contain: strict;
      `;
        }
    }
    getViewport(module = this.module) {
        return module.rel === 'system' ? this.fixedViewport : module.config.free === false ? (this.relativeViewport.shadowRoot || this.relativeViewport) : (this.absoluteViewport.shadowRoot || this.absoluteViewport);
    }
    checkSwitchover(modulu = this.modulu, module = this.module) {
        return (modulu === null || modulu === void 0 ? void 0 : modulu.rel) === 'module' && module.config.free !== modulu.config.free ? true : false;
    }
    to(...args) {
        return __awaiter(this, void 0, void 0, function* () {
            return this.pushPromise(this.next() || this.promise(...args), args);
        });
    }
    prev() {
        return this.promiseQueue[0];
    }
    next() {
        const prev = this.prev();
        if (prev) {
            return new Promise((resolve, reject) => {
                prev.then(() => {
                    if (this.promiseParamQueue[0]) {
                        this.promise(...this.promiseParamQueue[0]).then(resolve).catch(reject);
                    }
                });
            });
        }
        return;
    }
    pushPromise(promise, param) {
        this.promiseParamQueue.push(param);
        this.promiseQueue.push(promise);
        return promise;
    }
    shiftPromise() {
        this.promiseParamQueue.shift();
        this.promiseQueue.shift();
    }
    limit(id) {
        var _a, _b;
        const limit = Math.max(((_a = this === null || this === void 0 ? void 0 : this.options) === null || _a === void 0 ? void 0 : _a.limit) || 3, 2);
        const index = this.windowSet.indexOf(id);
        if (this.module.rel !== 'module' || this.module.config.background === true)
            return;
        if (index !== -1)
            this.windowSet.splice(index, 1);
        this.windowSet.push(id);
        if (this.windowSet.length > limit) {
            (_b = this.app.modules[this.windowSet.splice(0, 1)[0]]) === null || _b === void 0 ? void 0 : _b.destroy();
        }
    }
    destroy(module) {
        if (module.transient && this.history === -1) {
            this.app.del(module).then(() => {
                const index = this.windowSet.indexOf(module.id);
                this.windowSet.splice(index, 1);
            });
        }
        else {
            module.fate().then(() => {
                module.destroy().then(() => {
                    const index = this.windowSet.indexOf(module.id);
                    this.windowSet.splice(index, 1);
                });
            });
        }
    }
    beforehandDependencies(dependencies = []) {
        const allPromise = [];
        for (const dep of dependencies) {
            allPromise.push(new Promise((resolve, reject) => {
                this.app.get(dep).then((module) => {
                    module.prerender().then(resolve).catch(resolve);
                }).catch(reject);
            }));
        }
        return new Promise((resolve, reject) => {
            Promise.all(allPromise).then(resolve).catch(reject);
        });
    }
    checkPushState() {
        return this.history !== -1 && this.module.viewType !== 'portal';
    }
    promise(id, param = location.search, history = 1, touches) {
        return new Promise((resolve, reject) => {
            const od = this.od;
            const ids = od ? [id, od] : [id];
            const module = this.app.modules[id];
            const modulu = this.app.modules[od];
            const moduli = od ? [module, modulu] : [module];
            if (!module) {
                return this.app.get(id).then(() => {
                    this.promise(id, param, history).then(() => {
                        this.shiftPromise();
                        resolve();
                    }).catch(() => {
                        reject();
                    });
                });
            }
            this.id = id;
            this.ids = ids;
            this.param = param;
            this.module = module;
            this.modulu = modulu;
            this.moduli = moduli;
            this.history = history;
            this.touches = touches;
            this.animation = this.getAnimationGroup();
            this.switchover = this.checkSwitchover();
            this.target = this.getViewport();
            this.createContainer(module);
            this.start().then(() => {
                this.hintWillTrans(this.viewport);
                if (this.checkPushState() === true) {
                    this.pushState(id, module.config.title, param);
                }
                module.create(!!this.animation).then(() => {
                    var _a;
                    document.title = module.config.title;
                    this.transform().then((stillness) => {
                        this.od = id;
                        this.end(stillness);
                        this.shiftPromise();
                        this.limit(this.id);
                        resolve();
                    });
                    this.beforehandDependencies((_a = module.config) === null || _a === void 0 ? void 0 : _a.prerender).then(() => {
                        this.app.trigger('prerenderComplete');
                    });
                });
            });
        });
    }
    pos() {
        let x = 0;
        let y = 0;
        let attach = 'center';
        let origin = 'center';
        const width = this.relativeViewport.offsetWidth;
        const height = this.relativeViewport.offsetHeight;
        const event = this.touches ? this.touches['srcEvent'] : {};
        if (event.changedTouches) {
            x = event.changedTouches[0].pageX;
            y = event.changedTouches[0].pageY;
        }
        else {
            x = event.x;
            y = event.y;
        }
        if (x && y) {
            origin = [x, y];
            if (x < width / 4) {
                x = 0;
            }
            else if (x > width * 3 / 4) {
                x = width;
            }
            if (y < height / 4) {
                y = 0;
            }
            else if (y > height * 3 / 4) {
                y = height;
            }
            attach = [x, y];
        }
        return {
            x, y, width, height, attach, origin
        };
    }
    get backsetState() {
        return (this.moduli.length === 1 || this.module.level === this.modulu.level) ? -1 : (this.module.level > this.modulu.level ? 0 : 1);
    }
    get viewport() {
        var _a, _b;
        return this.switchover ? [
            this.module.config.free === false ? this.relativeViewport : this.absoluteViewport,
            ((_a = this.modulu) === null || _a === void 0 ? void 0 : _a.config.free) === false ? this.relativeViewport : this.absoluteViewport
        ] : [
            this.module.elements.container,
            (_b = this.modulu) === null || _b === void 0 ? void 0 : _b.elements.container
        ];
    }
    modulation(callback) {
        const viewport = this.viewport;
        const backset = this.backsetState;
        const reverse = backset === 0 ? false : true;
        const pos = this.pos();
        const animateEvent = {
            x: pos.x,
            y: pos.y,
            in: new Animate(viewport[0]),
            out: new Animate(viewport[1]),
            view: viewport,
            width: pos.width,
            height: pos.height,
            viewport: [this.relativeViewport, this.absoluteViewport],
            modules: this.moduli,
            reverse: reverse,
            direction: reverse ? -1 : 1,
            backset: backset,
            origin: origin,
            attach: pos.attach,
            touches: this.touches,
            callback: callback
        };
        return animateEvent;
    }
    transform() {
        return new Promise((resolve) => {
            if (!this.animation) {
                this.switchViewport();
                resolve(true);
                return;
            }
            const backset = this.backsetState;
            const animation = this.getAnimationOneSide(backset);
            const end = (stillness) => resolve(stillness);
            if (!animation)
                return end(true);
            const prosise = animation(this.modulation(end));
            if (prosise instanceof Promise)
                prosise.then(end);
        });
    }
    hintWillTrans(viewport) {
        viewport[0].style.willChange = 'transform, opacity';
        if (viewport[1]) {
            viewport[1].style.willChange = 'transform, opacity';
        }
    }
    removeTransHint(viewport) {
        viewport[0].style.willChange = 'auto';
        if (viewport[1]) {
            viewport[1].style.willChange = 'auto';
        }
    }
    start() {
        return new Promise((resolve, reject) => {
            this.app.trigger('transformStart', this.moduli);
            const transformStart = this.module.events.transformStart;
            if (typeof transformStart === 'function') {
                if (transformStart.call(this.module) === false)
                    return reject();
            }
            if (!this.animation || this.switchover) {
                this.module.elements.container.style.transform = 'translate3d(0, 0, 0)';
            }
            resolve();
        });
    }
    end(stillness = false) {
        const transformEnd = this.module.events.transformEnd;
        this.removeTransHint(this.viewport);
        if (this.switchover) {
            this.switchViewport();
        }
        if (this.modulu) {
            if (!this.animation || !stillness) {
                if (this.modulu.rel === 'module') {
                    this.modulu.elements.container.style.transform = 'translate3d(200%, 200%, 0)';
                }
                this.resetContainer(this.module, true);
            }
            this.modulu.elements.container.style.transitionDuration = '0ms';
            if (this.modulu.config.background === true) {
                this.modulu.hide();
            }
            else {
                this.destroy(this.modulu);
            }
        }
        this.module.show();
        if (typeof transformEnd === 'function') {
            transformEnd.call(this.module);
        }
        this.app.trigger('transformEnd', this.moduli);
    }
    switchViewport() {
        var _a, _b;
        this.resetViewport();
        if (((_b = (_a = this.module) === null || _a === void 0 ? void 0 : _a.config) === null || _b === void 0 ? void 0 : _b.free) === false) {
            this.absoluteViewport.style.transform = 'translate3d(200%, 200%, 0)';
            this.relativeViewport.style.transform = 'translate3d(0, 0, 0)';
        }
        else {
            this.relativeViewport.style.transform = 'translate3d(200%, 200%, 0)';
            this.absoluteViewport.style.transform = 'translate3d(0, 0, 0)';
        }
    }
}

class Transform extends TransformSwitch {
    constructor(app) {
        super(app);
    }
    setup(options) {
        this.options = options;
    }
}

class ApplicationProptey extends EventProvider {
    constructor() {
        super();
        this.modules = {};
        this.historyNodeLocation = history.length;
        this.routerRegExp = /([^#\/]+)(.+)?/;
        this.options = {
            modules: {}
        };
    }
    setting(options) {
        this.options = options;
    }
}

const BASE_CSS = `
* { box-sizing: border-box; margin: 0; padding: 0; text-size-adjust: 100%; tap-highlight-color: rgba(0, 0, 0, 0)  } \n
html, body { position: absolute; width: 100%; height: 100%; background: #fff; overflow: hidden; overscroll-behavior: none } \n
module-mask, module-view { position: absolute; width: 100%; height: 100%; overflow: hidden } \n
module-container[type=module] { display: block; top: 0; right: 0; bottom: 0; left: 0; width: 100%; height: 100% } \n
iframe { width: 100%; height: 100%; border: 0 } \n
`;

class ApplicationBase extends ApplicationProptey {
    constructor() {
        var _a, _b;
        super();
        this.properties = {
            darkTheme: (_b = (_a = window.matchMedia) === null || _a === void 0 ? void 0 : _a.call(window, '(prefers-color-scheme: dark)')) === null || _b === void 0 ? void 0 : _b.matches
        };
        this.console = {
            echo: (type, pre, mid, suf) => {
                console[type]('%c ' +
                    (pre[0] ? pre[0] + ' ' : '') +
                    '%c ' + (mid[0] ? mid[0] + ' ' : '') +
                    '%c ' + (suf[0] ? suf[0] + ' ' : ''), 'color: #ffffff; background:' + pre[1], 'color: #ffffff; background:' + mid[1], 'color: #ffffff; background:' + (suf[0] ? suf[1] : mid[1]));
            },
            log: (message, title, description) => {
                this.console.echo('log', [title, '#999'], [message, '#333'], [description, '#666']);
            },
            info: (message, title, description) => {
                this.console.echo('info', [title, '#0cf'], [message, '#06c'], [description, '#0c0']);
            },
            warn: (message, title, description) => {
                this.console.echo('warn', [title, '#f60'], [message, '#f30'], [description, '#f90']);
            },
            error: (message, title, description) => {
                this.console.echo('warn', [title, '#f06'], [message, '#903'], [description, '#993']);
            }
        };
        this.setBaseCSS();
    }
    get route() {
        const router = this.routerRegExp.exec(location.hash) || [];
        const id = router[1];
        const param = router[2];
        const search = location.search;
        return {
            id: id ? decodeURIComponent(id) : '',
            param: param ? decodeURIComponent(param) : '',
            search
        };
    }
    setBaseCSS() {
        const style = document.createElement('style');
        style.innerHTML = BASE_CSS;
        document.getElementsByTagName('head')[0].appendChild(style);
    }
    resolveURL(url) {
        const link = document.createElement('a');
        link.href = url;
        const path = link.origin + link.pathname;
        return {
            path,
            origin: link.origin,
            host: link.host,
            search: link.search
        };
    }
    promiseModule(promise) {
        return new Promise((resolve, reject) => __awaiter(this, void 0, void 0, function* () {
            try {
                resolve(yield promise());
            }
            catch (error) {
                reject(error);
            }
        }));
    }
    moduleSrcVerify(url) {
        const allowHosts = this.config.allowHosts;
        if (!Array.isArray(allowHosts)) {
            this.console.warn('Module.config.allowHosts is not defined', 'Security risks exist: ', '');
            return true;
        }
        const link = document.createElement('a');
        link.href = decodeURIComponent(url);
        const linkHost = link.host;
        for (const host of allowHosts) {
            if (linkHost === host)
                return true;
        }
        return false;
    }
    getModuleByURL(url) {
        const modules = this.modules;
        const resolve = this.resolveURL(url);
        const path = resolve.path;
        for (const id in modules) {
            const module = modules[id];
            const capture = module.config.capture;
            if (typeof capture === 'string') {
                if (capture === path)
                    return module;
            }
            else if (typeof capture === 'function') {
                if (capture(resolve, url))
                    return module;
            }
            if (module.uri === path)
                return module;
        }
        return;
    }
    setExists() {
        return new Promise((resolve, reject) => {
            try {
                sessionStorage.setItem('__EXISTS', String(history.length));
                resolve();
            }
            catch (e) {
                reject();
            }
        });
    }
    get exists() {
        try {
            return parseInt(sessionStorage.getItem('__EXISTS') || '-1', 10) === history.length;
        }
        catch (e) {
            return false;
        }
    }
}

var provider = (app) => {
    window.addEventListener('message', (event) => {
        const { data } = event;
        const { action } = data;
        switch (action) {
            case 'to':
                app.transform.to(data.module, data.query, data.history);
                break;
            case 'back':
                history.back();
                break;
            case 'forward':
                history.forward();
                break;
        }
    });
    return;
};

class Application extends ApplicationBase {
    constructor() {
        super();
        this.transform = new Transform(this);
        provider(this);
    }
    get activeModule() {
        const id = this.transform.id;
        const module = this.modules[id];
        return module;
    }
    add(id, manifest) {
        return this.modules[id] = new Module(id, manifest, this);
    }
    del(module) {
        return new Promise((resolve, reject) => {
            delete this.modules[module.id];
            if (module.status.init) {
                module.destroy().then(resolve).catch(reject);
            }
            else {
                resolve();
            }
        });
    }
    get(id) {
        return new Promise((resolve, reject) => {
            if (!id)
                return reject();
            if (typeof this.modules[id] === 'object')
                return resolve(this.modules[id]);
            const modulePromise = this.options.modules[id];
            switch (typeof modulePromise) {
                case 'function':
                    this.promiseModule(modulePromise).then((manifest) => {
                        resolve(this.add(id, manifest));
                    }).catch(reject);
                    break;
                case 'object':
                    resolve(this.add(id, modulePromise));
                    break;
                default:
                    const url = id;
                    if (!this.moduleSrcVerify(url)) {
                        reject();
                        break;
                    }
                    const module = this.createModuleByURL(url);
                    if (module) {
                        resolve(module);
                    }
                    else {
                        reject();
                    }
                    break;
            }
        });
    }
    createModuleByURL(url, config) {
        var _a, _b;
        const newModuleId = decodeURIComponent(url);
        const modules = this.modules;
        if (modules[newModuleId])
            return modules[newModuleId];
        const sameModule = this.getModuleByURL(url);
        if (sameModule)
            return sameModule;
        return this.add(newModuleId, {
            config: Object.assign({
                title: '',
                rel: 'module',
                level: ((_b = (_a = this.activeModule) === null || _a === void 0 ? void 0 : _a.config.level) !== null && _b !== void 0 ? _b : 0) + 1,
                free: true,
                source: {
                    src: url
                },
                background: 'auto',
                timeout: 0,
                animation: 'inherit',
                transient: true
            }, config)
        });
    }
    pushWindow(url, title = '', preset = 'slide') {
        const resolve = this.resolveURL(url);
        const search = resolve.search;
        if (!this.moduleSrcVerify(url)) {
            return Promise.reject('Illegal');
        }
        return new Promise((resolve, reject) => {
            const module = this.createModuleByURL(url, {
                title,
                animation: preset
            });
            if (module) {
                this.transform.to(module.id, module.config.source.html ? search : '').then(resolve).catch(reject);
            }
        });
    }
    mountSystem() {
        if (this.options.modules['system']) {
            this.get('system').then(() => {
                this.transform.to('system', undefined, -1).then(() => {
                    this.trigger('systemDidMount');
                });
            });
        }
    }
    mountFramework() {
        this.get('frameworks').then((module) => {
            const route = this.route;
            const index = module.config.index || '';
            const id = route.id || index;
            const config = module.config;
            this.config = config;
            this.transform.setup({
                singleFlow: config.singleFlow,
                index,
                defaultIndex: id,
                notFound: config.notFind,
                limit: Math.max(config.limit || 7, 2),
                exists: this.exists,
                defaultAnimation: config.animation
            });
            this.transform.to('frameworks', undefined, -1).then(() => {
                this.trigger('frameworksDidMount');
            });
            if (id !== index) {
                this.transform.pushState(index);
                if (id)
                    this.transform.to(id);
                return;
            }
            if (id)
                this.transform.to(id);
        }).catch(() => {
            this.console.error('Module frameworks must be included!', 'Serious!', '');
        });
    }
    start() {
        this.setExists();
        this.mountFramework();
        this.mountSystem();
    }
}

const application = new Application();

export { Application, application };