enlink
Version:
web-portals
1,948 lines • 71.1 kB
JavaScript
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 };