- Delete old Vite+Svelte frontend - Initialize new SvelteKit project with TypeScript - Configure Tailwind CSS v4 + DaisyUI - Implement JWT authentication with auto-refresh - Create login page with form validation (Zod) - Add protected route guards - Update Docker configuration for single-stage build - Add E2E tests with Playwright (6/11 passing) - Fix Svelte 5 reactivity with $state() runes Known issues: - 5 E2E tests failing (timing/async issues) - Token refresh implementation needs debugging - Validation error display timing
409 lines
13 KiB
JavaScript
409 lines
13 KiB
JavaScript
"use strict";
|
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
}
|
|
Object.defineProperty(o, k2, desc);
|
|
}) : (function(o, m, k, k2) {
|
|
if (k2 === undefined) k2 = k;
|
|
o[k2] = m[k];
|
|
}));
|
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
}) : function(o, v) {
|
|
o["default"] = v;
|
|
});
|
|
var __importStar = (this && this.__importStar) || (function () {
|
|
var ownKeys = function(o) {
|
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
var ar = [];
|
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
return ar;
|
|
};
|
|
return ownKeys(o);
|
|
};
|
|
return function (mod) {
|
|
if (mod && mod.__esModule) return mod;
|
|
var result = {};
|
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
__setModuleDefault(result, mod);
|
|
return result;
|
|
};
|
|
})();
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const Event_js_1 = __importDefault(require("../../event/Event.cjs"));
|
|
const PropertySymbol = __importStar(require("../../PropertySymbol.cjs"));
|
|
const HTMLElement_js_1 = __importDefault(require("../html-element/HTMLElement.cjs"));
|
|
const CrossOriginBrowserWindow_js_1 = __importDefault(require("../../window/CrossOriginBrowserWindow.cjs"));
|
|
const DOMTokenList_js_1 = __importDefault(require("../../dom/DOMTokenList.cjs"));
|
|
const BrowserFrameFactory_js_1 = __importDefault(require("../../browser/utilities/BrowserFrameFactory.cjs"));
|
|
const BrowserFrameURL_js_1 = __importDefault(require("../../browser/utilities/BrowserFrameURL.cjs"));
|
|
const DOMExceptionNameEnum_js_1 = __importDefault(require("../../exception/DOMExceptionNameEnum.cjs"));
|
|
const WindowBrowserContext_js_1 = __importDefault(require("../../window/WindowBrowserContext.cjs"));
|
|
const ElementEventAttributeUtility_js_1 = __importDefault(require("../element/ElementEventAttributeUtility.cjs"));
|
|
const SANDBOX_FLAGS = [
|
|
'allow-downloads',
|
|
'allow-forms',
|
|
'allow-modals',
|
|
'allow-orientation-lock',
|
|
'allow-pointer-lock',
|
|
'allow-popups',
|
|
'allow-popups-to-escape-sandbox',
|
|
'allow-presentation',
|
|
'allow-same-origin',
|
|
'allow-scripts',
|
|
'allow-top-navigation',
|
|
'allow-top-navigation-by-user-activation',
|
|
'allow-top-navigation-to-custom-protocols'
|
|
];
|
|
/**
|
|
* HTML Iframe Element.
|
|
*
|
|
* Reference:
|
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLIFrameElement.
|
|
*/
|
|
class HTMLIFrameElement extends HTMLElement_js_1.default {
|
|
// Internal properties
|
|
[PropertySymbol.sandbox] = null;
|
|
// Private properties
|
|
#contentWindowContainer = {
|
|
window: null
|
|
};
|
|
#iframe;
|
|
#loadedSrcdoc = null;
|
|
// Events
|
|
/* eslint-disable jsdoc/require-jsdoc */
|
|
get onload() {
|
|
return ElementEventAttributeUtility_js_1.default.getEventListener(this, 'onload');
|
|
}
|
|
set onload(value) {
|
|
this[PropertySymbol.propertyEventListeners].set('onload', value);
|
|
}
|
|
get onerror() {
|
|
return ElementEventAttributeUtility_js_1.default.getEventListener(this, 'onerror');
|
|
}
|
|
set onerror(value) {
|
|
this[PropertySymbol.propertyEventListeners].set('onerror', value);
|
|
}
|
|
/* eslint-enable jsdoc/require-jsdoc */
|
|
/**
|
|
* Returns source.
|
|
*
|
|
* @returns Source.
|
|
*/
|
|
get src() {
|
|
if (!this.hasAttribute('src')) {
|
|
return '';
|
|
}
|
|
try {
|
|
return new URL(this.getAttribute('src'), this[PropertySymbol.ownerDocument].location.href)
|
|
.href;
|
|
}
|
|
catch (e) {
|
|
return this.getAttribute('src');
|
|
}
|
|
}
|
|
/**
|
|
* Sets source.
|
|
*
|
|
* @param src Source.
|
|
*/
|
|
set src(src) {
|
|
this.setAttribute('src', src);
|
|
}
|
|
/**
|
|
* Returns allow.
|
|
*
|
|
* @returns Allow.
|
|
*/
|
|
get allow() {
|
|
return this.getAttribute('allow') || '';
|
|
}
|
|
/**
|
|
* Sets allow.
|
|
*
|
|
* @param allow Allow.
|
|
*/
|
|
set allow(allow) {
|
|
this.setAttribute('allow', allow);
|
|
}
|
|
/**
|
|
* Returns height.
|
|
*
|
|
* @returns Height.
|
|
*/
|
|
get height() {
|
|
return this.getAttribute('height') || '';
|
|
}
|
|
/**
|
|
* Sets height.
|
|
*
|
|
* @param height Height.
|
|
*/
|
|
set height(height) {
|
|
this.setAttribute('height', height);
|
|
}
|
|
/**
|
|
* Returns width.
|
|
*
|
|
* @returns Width.
|
|
*/
|
|
get width() {
|
|
return this.getAttribute('width') || '';
|
|
}
|
|
/**
|
|
* Sets width.
|
|
*
|
|
* @param width Width.
|
|
*/
|
|
set width(width) {
|
|
this.setAttribute('width', width);
|
|
}
|
|
/**
|
|
* Returns name.
|
|
*
|
|
* @returns Name.
|
|
*/
|
|
get name() {
|
|
return this.getAttribute('name') || '';
|
|
}
|
|
/**
|
|
* Sets name.
|
|
*
|
|
* @param name Name.
|
|
*/
|
|
set name(name) {
|
|
this.setAttribute('name', name);
|
|
}
|
|
/**
|
|
* Returns sandbox.
|
|
*
|
|
* @returns Sandbox.
|
|
*/
|
|
get sandbox() {
|
|
if (!this[PropertySymbol.sandbox]) {
|
|
this[PropertySymbol.sandbox] = new DOMTokenList_js_1.default(PropertySymbol.illegalConstructor, this, 'sandbox');
|
|
}
|
|
return this[PropertySymbol.sandbox];
|
|
}
|
|
/**
|
|
* Sets sandbox.
|
|
*/
|
|
set sandbox(sandbox) {
|
|
this.setAttribute('sandbox', sandbox);
|
|
}
|
|
/**
|
|
* Returns srcdoc.
|
|
*
|
|
* @returns Srcdoc.
|
|
*/
|
|
get srcdoc() {
|
|
return this.getAttribute('srcdoc') || '';
|
|
}
|
|
/**
|
|
* Sets srcdoc.
|
|
*
|
|
* @param srcdoc Srcdoc.
|
|
*/
|
|
set srcdoc(srcdoc) {
|
|
this.setAttribute('srcdoc', srcdoc);
|
|
}
|
|
/**
|
|
* Returns referrer policy.
|
|
*/
|
|
get referrerPolicy() {
|
|
return this.getAttribute('referrerpolicy') || '';
|
|
}
|
|
/**
|
|
* Sets referrer policy.
|
|
*
|
|
* @param referrerPolicy Referrer policy.
|
|
*/
|
|
set referrerPolicy(referrerPolicy) {
|
|
this.setAttribute('referrerpolicy', referrerPolicy);
|
|
}
|
|
/**
|
|
* Returns content document.
|
|
*
|
|
* @returns Content document.
|
|
*/
|
|
get contentDocument() {
|
|
return this.#contentWindowContainer.window?.document ?? null;
|
|
}
|
|
/**
|
|
* Returns content window.
|
|
*
|
|
* @returns Content window.
|
|
*/
|
|
get contentWindow() {
|
|
return this.#contentWindowContainer.window;
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
get tabIndex() {
|
|
const tabIndex = this.getAttribute('tabindex');
|
|
if (tabIndex !== null) {
|
|
const parsed = Number(tabIndex);
|
|
return isNaN(parsed) ? 0 : parsed;
|
|
}
|
|
return 0;
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
set tabIndex(tabIndex) {
|
|
super.tabIndex = tabIndex;
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
[PropertySymbol.connectedToDocument]() {
|
|
super[PropertySymbol.connectedToDocument]();
|
|
this.#loadPage();
|
|
}
|
|
/**
|
|
* Called when disconnected from document.
|
|
* @param e
|
|
*/
|
|
[PropertySymbol.disconnectedFromDocument]() {
|
|
super[PropertySymbol.disconnectedFromDocument]();
|
|
this.#unloadPage();
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
[PropertySymbol.cloneNode](deep = false) {
|
|
return super[PropertySymbol.cloneNode](deep);
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
[PropertySymbol.onSetAttribute](attribute, replacedAttribute) {
|
|
super[PropertySymbol.onSetAttribute](attribute, replacedAttribute);
|
|
if (attribute[PropertySymbol.name] === 'srcdoc') {
|
|
this.#loadPage();
|
|
}
|
|
if (attribute[PropertySymbol.name] === 'src' &&
|
|
attribute[PropertySymbol.value] &&
|
|
!this.hasAttribute('srcdoc') &&
|
|
attribute[PropertySymbol.value] !== replacedAttribute?.[PropertySymbol.value]) {
|
|
this.#loadPage();
|
|
}
|
|
if (attribute[PropertySymbol.name] === 'sandbox') {
|
|
this.#validateSandboxFlags();
|
|
}
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
[PropertySymbol.onRemoveAttribute](removedAttribute) {
|
|
super[PropertySymbol.onRemoveAttribute](removedAttribute);
|
|
if (removedAttribute[PropertySymbol.name] === 'srcdoc' ||
|
|
removedAttribute[PropertySymbol.name] === 'src') {
|
|
this.#loadPage();
|
|
}
|
|
}
|
|
/**
|
|
*
|
|
* @param tokens
|
|
* @param vconsole
|
|
*/
|
|
#validateSandboxFlags() {
|
|
const window = this[PropertySymbol.window];
|
|
const invalidFlags = [];
|
|
for (const token of this.sandbox) {
|
|
if (!SANDBOX_FLAGS.includes(token)) {
|
|
invalidFlags.push(token);
|
|
}
|
|
}
|
|
if (invalidFlags.length === 1) {
|
|
window.console.error(`Error while parsing the 'sandbox' attribute: '${invalidFlags[0]}' is an invalid sandbox flag.`);
|
|
}
|
|
else if (invalidFlags.length > 1) {
|
|
window.console.error(`Error while parsing the 'sandbox' attribute: '${invalidFlags.join(`', '`)}' are invalid sandbox flags.`);
|
|
}
|
|
}
|
|
/**
|
|
* Loads an iframe page.
|
|
*/
|
|
#loadPage() {
|
|
if (!this[PropertySymbol.isConnected]) {
|
|
this.#unloadPage();
|
|
return;
|
|
}
|
|
const srcdoc = this.getAttribute('srcdoc');
|
|
const window = this[PropertySymbol.window];
|
|
const browserFrame = new WindowBrowserContext_js_1.default(window).getBrowserFrame();
|
|
if (!browserFrame) {
|
|
return;
|
|
}
|
|
if (srcdoc !== null) {
|
|
if (this.#loadedSrcdoc === srcdoc) {
|
|
return;
|
|
}
|
|
this.#unloadPage();
|
|
this.#iframe = BrowserFrameFactory_js_1.default.createChildFrame(browserFrame);
|
|
this.#iframe.url = 'about:srcdoc';
|
|
this.#contentWindowContainer.window = this.#iframe.window;
|
|
this.#iframe.window[PropertySymbol.top] = browserFrame.window.top;
|
|
this.#iframe.window[PropertySymbol.parent] = browserFrame.window;
|
|
this.#iframe.window.document.open();
|
|
this.#iframe.window.document.write(srcdoc);
|
|
this.#loadedSrcdoc = srcdoc;
|
|
this[PropertySymbol.window].requestAnimationFrame(() => this.dispatchEvent(new Event_js_1.default('load')));
|
|
return;
|
|
}
|
|
if (this.#loadedSrcdoc !== null) {
|
|
this.#unloadPage();
|
|
}
|
|
const originURL = browserFrame.window.location;
|
|
const targetURL = BrowserFrameURL_js_1.default.getRelativeURL(browserFrame, this.src);
|
|
if (this.#iframe && this.#iframe.window.location.href === targetURL.href) {
|
|
return;
|
|
}
|
|
if (browserFrame.page.context.browser.settings.disableIframePageLoading) {
|
|
const error = new window.DOMException(`Failed to load iframe page "${targetURL.href}". Iframe page loading is disabled.`, DOMExceptionNameEnum_js_1.default.notSupportedError);
|
|
browserFrame.page?.console.error(error);
|
|
this.dispatchEvent(new Event_js_1.default('error'));
|
|
return;
|
|
}
|
|
// Iframes has a special rule for CORS and doesn't allow access between frames when the origin is different.
|
|
const isSameOrigin = originURL.origin === targetURL.origin || targetURL.origin === 'null';
|
|
const parentWindow = isSameOrigin ? window : new CrossOriginBrowserWindow_js_1.default(window);
|
|
this.#iframe = this.#iframe ?? BrowserFrameFactory_js_1.default.createChildFrame(browserFrame);
|
|
this.#iframe.window[PropertySymbol.top] = parentWindow;
|
|
this.#iframe.window[PropertySymbol.parent] = parentWindow;
|
|
this.#iframe
|
|
.goto(targetURL.href, {
|
|
referrer: originURL.origin,
|
|
referrerPolicy: this.referrerPolicy
|
|
})
|
|
.then(() => this.dispatchEvent(new Event_js_1.default('load')))
|
|
.catch((error) => {
|
|
browserFrame.page?.console.error(error);
|
|
this.dispatchEvent(new Event_js_1.default('error'));
|
|
});
|
|
this.#contentWindowContainer.window = isSameOrigin
|
|
? this.#iframe.window
|
|
: new CrossOriginBrowserWindow_js_1.default(this.#iframe.window, window);
|
|
}
|
|
/**
|
|
* Unloads an iframe page.
|
|
*/
|
|
#unloadPage() {
|
|
if (this.#iframe) {
|
|
BrowserFrameFactory_js_1.default.destroyFrame(this.#iframe);
|
|
this.#iframe = null;
|
|
}
|
|
this.#contentWindowContainer.window = null;
|
|
this.#loadedSrcdoc = null;
|
|
}
|
|
}
|
|
exports.default = HTMLIFrameElement;
|
|
//# sourceMappingURL=HTMLIFrameElement.cjs.map
|