- 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
449 lines
15 KiB
JavaScript
449 lines
15 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 PropertySymbol = __importStar(require("../../PropertySymbol.cjs"));
|
|
const HTMLElement_js_1 = __importDefault(require("../html-element/HTMLElement.cjs"));
|
|
const Event_js_1 = __importDefault(require("../../event/Event.cjs"));
|
|
const DOMTokenList_js_1 = __importDefault(require("../../dom/DOMTokenList.cjs"));
|
|
const DOMExceptionNameEnum_js_1 = __importDefault(require("../../exception/DOMExceptionNameEnum.cjs"));
|
|
const ResourceFetch_js_1 = __importDefault(require("../../fetch/ResourceFetch.cjs"));
|
|
const WindowBrowserContext_js_1 = __importDefault(require("../../window/WindowBrowserContext.cjs"));
|
|
const Fetch_js_1 = __importDefault(require("../../fetch/Fetch.cjs"));
|
|
const BrowserErrorCaptureEnum_js_1 = __importDefault(require("../../browser/enums/BrowserErrorCaptureEnum.cjs"));
|
|
const ModuleFactory_js_1 = __importDefault(require("../../module/ModuleFactory.cjs"));
|
|
const PreloadUtility_js_1 = __importDefault(require("../../fetch/preload/PreloadUtility.cjs"));
|
|
const PreloadEntry_js_1 = __importDefault(require("../../fetch/preload/PreloadEntry.cjs"));
|
|
const ElementEventAttributeUtility_js_1 = __importDefault(require("../element/ElementEventAttributeUtility.cjs"));
|
|
/**
|
|
* HTML Link Element.
|
|
*
|
|
* Reference:
|
|
* https://developer.mozilla.org/en-US/docs/Web/API/HTMLLinkElement.
|
|
*/
|
|
class HTMLLinkElement extends HTMLElement_js_1.default {
|
|
// Internal properties
|
|
[PropertySymbol.sheet] = null;
|
|
[PropertySymbol.evaluateCSS] = true;
|
|
[PropertySymbol.relList] = null;
|
|
#loadedStyleSheetURL = null;
|
|
// Events
|
|
/* eslint-disable jsdoc/require-jsdoc */
|
|
get onerror() {
|
|
return ElementEventAttributeUtility_js_1.default.getEventListener(this, 'onerror');
|
|
}
|
|
set onerror(value) {
|
|
this[PropertySymbol.propertyEventListeners].set('onerror', value);
|
|
}
|
|
get onload() {
|
|
return ElementEventAttributeUtility_js_1.default.getEventListener(this, 'onload');
|
|
}
|
|
set onload(value) {
|
|
this[PropertySymbol.propertyEventListeners].set('onload', value);
|
|
}
|
|
/* eslint-enable jsdoc/require-jsdoc */
|
|
/**
|
|
* Returns sheet.
|
|
*/
|
|
get sheet() {
|
|
return this[PropertySymbol.sheet];
|
|
}
|
|
/**
|
|
* Returns rel list.
|
|
*
|
|
* @returns Rel list.
|
|
*/
|
|
get relList() {
|
|
if (!this[PropertySymbol.relList]) {
|
|
this[PropertySymbol.relList] = new DOMTokenList_js_1.default(PropertySymbol.illegalConstructor, this, 'rel', ['stylesheet', 'modulepreload', 'preload']);
|
|
}
|
|
return this[PropertySymbol.relList];
|
|
}
|
|
/**
|
|
* Sets rel list.
|
|
*
|
|
* @param value Value.
|
|
*/
|
|
set relList(value) {
|
|
this.setAttribute('rel', value);
|
|
}
|
|
/**
|
|
* Returns as.
|
|
*
|
|
* @returns As.
|
|
*/
|
|
get as() {
|
|
return this.getAttribute('as') || '';
|
|
}
|
|
/**
|
|
* Sets as.
|
|
*
|
|
* @param as As.
|
|
*/
|
|
set as(as) {
|
|
this.setAttribute('as', as);
|
|
}
|
|
/**
|
|
* Returns crossOrigin.
|
|
*
|
|
* @returns CrossOrigin.
|
|
*/
|
|
get crossOrigin() {
|
|
return this.getAttribute('crossorigin') || '';
|
|
}
|
|
/**
|
|
* Sets crossOrigin.
|
|
*
|
|
* @param crossOrigin CrossOrigin.
|
|
*/
|
|
set crossOrigin(crossOrigin) {
|
|
this.setAttribute('crossorigin', crossOrigin);
|
|
}
|
|
/**
|
|
* Returns href.
|
|
*
|
|
* @returns Href.
|
|
*/
|
|
get href() {
|
|
if (!this.hasAttribute('href')) {
|
|
return '';
|
|
}
|
|
try {
|
|
return new URL(this.getAttribute('href'), this[PropertySymbol.ownerDocument].location.href)
|
|
.href;
|
|
}
|
|
catch (e) {
|
|
return this.getAttribute('href');
|
|
}
|
|
}
|
|
/**
|
|
* Sets href.
|
|
*
|
|
* @param href Href.
|
|
*/
|
|
set href(href) {
|
|
this.setAttribute('href', href);
|
|
}
|
|
/**
|
|
* Returns hreflang.
|
|
*
|
|
* @returns Hreflang.
|
|
*/
|
|
get hreflang() {
|
|
return this.getAttribute('hreflang') || '';
|
|
}
|
|
/**
|
|
* Sets hreflang.
|
|
*
|
|
* @param hreflang Hreflang.
|
|
*/
|
|
set hreflang(hreflang) {
|
|
this.setAttribute('hreflang', hreflang);
|
|
}
|
|
/**
|
|
* Returns media.
|
|
*
|
|
* @returns Media.
|
|
*/
|
|
get media() {
|
|
return this.getAttribute('media') || '';
|
|
}
|
|
/**
|
|
* Sets media.
|
|
*
|
|
* @param media Media.
|
|
*/
|
|
set media(media) {
|
|
this.setAttribute('media', media);
|
|
}
|
|
/**
|
|
* Returns referrerPolicy.
|
|
*
|
|
* @returns ReferrerPolicy.
|
|
*/
|
|
get referrerPolicy() {
|
|
return this.getAttribute('referrerPolicy') || '';
|
|
}
|
|
/**
|
|
* Sets referrerPolicy.
|
|
*
|
|
* @param referrerPolicy ReferrerPolicy.
|
|
*/
|
|
set referrerPolicy(referrerPolicy) {
|
|
this.setAttribute('referrerPolicy', referrerPolicy);
|
|
}
|
|
/**
|
|
* Returns rel.
|
|
*
|
|
* @returns Rel.
|
|
*/
|
|
get rel() {
|
|
return this.getAttribute('rel') || '';
|
|
}
|
|
/**
|
|
* Sets rel.
|
|
*
|
|
* @param rel Rel.
|
|
*/
|
|
set rel(rel) {
|
|
this.setAttribute('rel', rel);
|
|
}
|
|
/**
|
|
* Returns type.
|
|
*
|
|
* @returns Type.
|
|
*/
|
|
get type() {
|
|
return this.getAttribute('type') || '';
|
|
}
|
|
/**
|
|
* Sets type.
|
|
*
|
|
* @param type Type.
|
|
*/
|
|
set type(type) {
|
|
this.setAttribute('type', type);
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
[PropertySymbol.connectedToDocument]() {
|
|
super[PropertySymbol.connectedToDocument]();
|
|
const rel = this.getAttribute('rel');
|
|
const href = this.getAttribute('href');
|
|
if (rel && href) {
|
|
switch (rel) {
|
|
case 'stylesheet':
|
|
this.#loadStyleSheet(href);
|
|
break;
|
|
case 'modulepreload':
|
|
this.#preloadModule(href);
|
|
break;
|
|
case 'preload':
|
|
this.#preloadResource(href);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* @override
|
|
*/
|
|
[PropertySymbol.onSetAttribute](attribute, replacedAttribute) {
|
|
super[PropertySymbol.onSetAttribute](attribute, replacedAttribute);
|
|
if (attribute[PropertySymbol.name] === 'rel' || attribute[PropertySymbol.name] === 'href') {
|
|
const rel = this.getAttribute('rel');
|
|
const href = this.getAttribute('href');
|
|
if (rel && href) {
|
|
switch (rel) {
|
|
case 'stylesheet':
|
|
this.#loadStyleSheet(href);
|
|
break;
|
|
case 'modulepreload':
|
|
this.#preloadModule(href);
|
|
break;
|
|
case 'preload':
|
|
this.#preloadResource(href);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Preloads a module.
|
|
*
|
|
* @param url URL.
|
|
*/
|
|
async #preloadModule(url) {
|
|
const absoluteURL = new URL(url, this[PropertySymbol.ownerDocument].location.href);
|
|
const window = this[PropertySymbol.window];
|
|
const browserFrame = new WindowBrowserContext_js_1.default(window).getBrowserFrame();
|
|
const browserSettings = new WindowBrowserContext_js_1.default(window).getSettings();
|
|
if (!browserSettings ||
|
|
!this[PropertySymbol.isConnected] ||
|
|
browserSettings.disableJavaScriptFileLoading ||
|
|
browserSettings.disableJavaScriptEvaluation) {
|
|
return;
|
|
}
|
|
if (browserSettings.disableErrorCapturing ||
|
|
browserSettings.errorCapture !== BrowserErrorCaptureEnum_js_1.default.tryAndCatch) {
|
|
const module = await ModuleFactory_js_1.default.getModule(window, absoluteURL, url);
|
|
await module.preload();
|
|
}
|
|
else {
|
|
try {
|
|
const module = await ModuleFactory_js_1.default.getModule(window, absoluteURL, url);
|
|
await module.preload();
|
|
}
|
|
catch (error) {
|
|
browserFrame.page?.console.error(error);
|
|
window[PropertySymbol.dispatchError](error);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
/**
|
|
* Preloads a resource.
|
|
*
|
|
* @param url URL.
|
|
*/
|
|
async #preloadResource(url) {
|
|
const window = this[PropertySymbol.window];
|
|
const browserFrame = new WindowBrowserContext_js_1.default(window).getBrowserFrame();
|
|
const as = this.as;
|
|
// Only "script", "style" and "fetch" are supported for now.
|
|
if (!browserFrame ||
|
|
!this[PropertySymbol.isConnected] ||
|
|
(as !== 'script' && as !== 'style' && as !== 'fetch')) {
|
|
return;
|
|
}
|
|
const browserSettings = browserFrame.page?.context?.browser?.settings;
|
|
if (as === 'script' &&
|
|
(browserSettings.disableJavaScriptFileLoading || browserSettings.disableJavaScriptEvaluation)) {
|
|
return;
|
|
}
|
|
if (as === 'style' && browserSettings.disableCSSFileLoading) {
|
|
return;
|
|
}
|
|
const absoluteURL = new URL(url, window.location.href).href;
|
|
const preloadKey = PreloadUtility_js_1.default.getKey({
|
|
url: absoluteURL,
|
|
destination: as,
|
|
mode: 'cors',
|
|
credentialsMode: this.crossOrigin === 'use-credentials' ? 'include' : 'same-origin'
|
|
});
|
|
if (window.document[PropertySymbol.preloads].has(preloadKey)) {
|
|
return;
|
|
}
|
|
const preloadEntry = new PreloadEntry_js_1.default();
|
|
window.document[PropertySymbol.preloads].set(preloadKey, preloadEntry);
|
|
const fetch = new Fetch_js_1.default({
|
|
browserFrame,
|
|
window,
|
|
url: absoluteURL,
|
|
disableSameOriginPolicy: as === 'script' || as === 'style',
|
|
disablePreload: true,
|
|
init: {
|
|
credentials: this.crossOrigin === 'use-credentials' ? 'include' : 'same-origin'
|
|
}
|
|
});
|
|
try {
|
|
const response = await fetch.send();
|
|
if (!response[PropertySymbol.buffer]) {
|
|
await response.buffer();
|
|
}
|
|
preloadEntry.responseAvailable(null, response);
|
|
}
|
|
catch (error) {
|
|
preloadEntry.responseAvailable(error, null);
|
|
window.document[PropertySymbol.preloads].delete(preloadKey);
|
|
browserFrame.page?.console?.error(`Failed to preload resource "${absoluteURL}": ${error.message}`);
|
|
}
|
|
}
|
|
/**
|
|
* Returns a URL relative to the given Location object.
|
|
*
|
|
* @param url URL.
|
|
* @param rel Rel.
|
|
*/
|
|
async #loadStyleSheet(url) {
|
|
const window = this[PropertySymbol.window];
|
|
const browserFrame = new WindowBrowserContext_js_1.default(window).getBrowserFrame();
|
|
if (!browserFrame) {
|
|
return;
|
|
}
|
|
const browserSettings = browserFrame.page?.context?.browser?.settings;
|
|
if (!this[PropertySymbol.evaluateCSS] || !this[PropertySymbol.isConnected]) {
|
|
return;
|
|
}
|
|
let absoluteURL;
|
|
try {
|
|
absoluteURL = new URL(url, window.location.href).href;
|
|
}
|
|
catch (error) {
|
|
return;
|
|
}
|
|
if (this.#loadedStyleSheetURL === absoluteURL) {
|
|
return;
|
|
}
|
|
if (browserSettings && browserSettings.disableCSSFileLoading) {
|
|
if (browserSettings.handleDisabledFileLoadingAsSuccess) {
|
|
this.dispatchEvent(new Event_js_1.default('load'));
|
|
}
|
|
else {
|
|
const error = new window.DOMException(`Failed to load external stylesheet "${absoluteURL}". CSS file loading is disabled.`, DOMExceptionNameEnum_js_1.default.notSupportedError);
|
|
browserFrame.page?.console.error(error);
|
|
this.dispatchEvent(new Event_js_1.default('error'));
|
|
}
|
|
return;
|
|
}
|
|
const resourceFetch = new ResourceFetch_js_1.default(window);
|
|
const readyStateManager = window[PropertySymbol.readyStateManager];
|
|
this.#loadedStyleSheetURL = absoluteURL;
|
|
readyStateManager.startTask();
|
|
let code = null;
|
|
let error = null;
|
|
try {
|
|
code = await resourceFetch.fetch(absoluteURL, 'style', {
|
|
credentials: this.crossOrigin === 'use-credentials' ? 'include' : 'same-origin'
|
|
});
|
|
}
|
|
catch (e) {
|
|
error = e;
|
|
}
|
|
readyStateManager.endTask();
|
|
if (error) {
|
|
browserFrame.page?.console.error(error);
|
|
this.dispatchEvent(new Event_js_1.default('error'));
|
|
}
|
|
else {
|
|
const styleSheet = new this[PropertySymbol.ownerDocument][PropertySymbol.window].CSSStyleSheet();
|
|
styleSheet.replaceSync(code);
|
|
this[PropertySymbol.sheet] = styleSheet;
|
|
// Computed style cache is affected by all mutations.
|
|
const document = this[PropertySymbol.ownerDocument];
|
|
if (document) {
|
|
for (const item of document[PropertySymbol.affectsComputedStyleCache]) {
|
|
item.result = null;
|
|
}
|
|
document[PropertySymbol.affectsComputedStyleCache] = [];
|
|
}
|
|
this.dispatchEvent(new Event_js_1.default('load'));
|
|
}
|
|
}
|
|
}
|
|
exports.default = HTMLLinkElement;
|
|
//# sourceMappingURL=HTMLLinkElement.cjs.map
|