viewlogic 1.2.4 → 1.2.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -187,33 +187,23 @@ export default {
|
|
|
187
187
|
|
|
188
188
|
**src/layouts/default.html** (optional)
|
|
189
189
|
```html
|
|
190
|
-
|
|
191
|
-
<
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
</
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
<div class="container">
|
|
208
|
-
{{ content }}
|
|
209
|
-
</div>
|
|
210
|
-
</main>
|
|
211
|
-
|
|
212
|
-
<footer>
|
|
213
|
-
<p>© 2024 My ViewLogic App</p>
|
|
214
|
-
</footer>
|
|
215
|
-
</body>
|
|
216
|
-
</html>
|
|
190
|
+
<header class="navbar">
|
|
191
|
+
<h1>My App</h1>
|
|
192
|
+
<nav>
|
|
193
|
+
<a href="#/home">Home</a>
|
|
194
|
+
<a href="#/about">About</a>
|
|
195
|
+
</nav>
|
|
196
|
+
</header>
|
|
197
|
+
|
|
198
|
+
<main class="main-content">
|
|
199
|
+
<div class="container">
|
|
200
|
+
{{ content }}
|
|
201
|
+
</div>
|
|
202
|
+
</main>
|
|
203
|
+
|
|
204
|
+
<footer>
|
|
205
|
+
<p>© 2024 My ViewLogic App</p>
|
|
206
|
+
</footer>
|
|
217
207
|
```
|
|
218
208
|
|
|
219
209
|
### Query Parameter Example
|
|
@@ -357,7 +347,8 @@ if (this.$state.has('user')) {
|
|
|
357
347
|
// Watch for changes (reactive)
|
|
358
348
|
this.$state.watch('user', (newValue, oldValue) => {
|
|
359
349
|
console.log('User changed:', newValue);
|
|
360
|
-
|
|
350
|
+
// Update component data to trigger reactivity
|
|
351
|
+
this.currentUser = newValue;
|
|
361
352
|
});
|
|
362
353
|
|
|
363
354
|
// Bulk updates
|
|
@@ -389,8 +380,7 @@ this.setToken('jwt-token-here');
|
|
|
389
380
|
|
|
390
381
|
// Login with options
|
|
391
382
|
this.setToken('jwt-token', {
|
|
392
|
-
storage: 'localStorage'
|
|
393
|
-
skipValidation: false // Skip JWT validation
|
|
383
|
+
storage: 'localStorage' // 'localStorage', 'sessionStorage', 'cookie'
|
|
394
384
|
});
|
|
395
385
|
|
|
396
386
|
// Get current token
|
|
@@ -685,8 +675,9 @@ const router = new ViewLogicRouter({
|
|
|
685
675
|
maxCacheSize: 100, // Maximum number of cached items
|
|
686
676
|
|
|
687
677
|
// API settings
|
|
688
|
-
apiBaseURL: '/
|
|
689
|
-
|
|
678
|
+
apiBaseURL: 'https://api.example.com/v1', // Base URL for API requests
|
|
679
|
+
requestTimeout: 30000, // Form submission timeout in milliseconds (30 seconds)
|
|
680
|
+
uploadTimeout: 300000, // File upload timeout in milliseconds (5 minutes)
|
|
690
681
|
|
|
691
682
|
// Development settings
|
|
692
683
|
environment: 'development', // 'development' or 'production'
|
package/dist/viewlogic-router.js
CHANGED
|
@@ -355,8 +355,7 @@ var AuthManager = class {
|
|
|
355
355
|
checkAuthFunction: options.checkAuthFunction || null,
|
|
356
356
|
redirectAfterLogin: options.redirectAfterLogin || "home",
|
|
357
357
|
authCookieName: options.authCookieName || "authToken",
|
|
358
|
-
authStorage: options.authStorage || "localStorage"
|
|
359
|
-
authSkipValidation: options.authSkipValidation || false
|
|
358
|
+
authStorage: options.authStorage || "localStorage"
|
|
360
359
|
};
|
|
361
360
|
this.router = router;
|
|
362
361
|
this.eventListeners = /* @__PURE__ */ new Map();
|
|
@@ -510,11 +509,10 @@ var AuthManager = class {
|
|
|
510
509
|
}
|
|
511
510
|
const {
|
|
512
511
|
storage = this.config.authStorage,
|
|
513
|
-
cookieOptions = this.config.authCookieOptions
|
|
514
|
-
skipValidation = this.config.authSkipValidation
|
|
512
|
+
cookieOptions = this.config.authCookieOptions
|
|
515
513
|
} = options;
|
|
516
514
|
try {
|
|
517
|
-
if (!
|
|
515
|
+
if (!this.isTokenValid(token)) {
|
|
518
516
|
this.log("warn", "\u274C Token is expired or invalid");
|
|
519
517
|
return false;
|
|
520
518
|
}
|
|
@@ -541,7 +539,7 @@ var AuthManager = class {
|
|
|
541
539
|
});
|
|
542
540
|
return true;
|
|
543
541
|
} catch (error) {
|
|
544
|
-
this.log("Failed to set token:", error);
|
|
542
|
+
this.log("error", "Failed to set token:", error);
|
|
545
543
|
return false;
|
|
546
544
|
}
|
|
547
545
|
}
|
|
@@ -592,14 +590,14 @@ var AuthManager = class {
|
|
|
592
590
|
break;
|
|
593
591
|
}
|
|
594
592
|
this.emitAuthEvent("token_removed", { storage });
|
|
595
|
-
this.log(`Token removed from: ${storage}`);
|
|
593
|
+
this.log("debug", `Token removed from: ${storage}`);
|
|
596
594
|
}
|
|
597
595
|
/**
|
|
598
596
|
* 로그인 성공 처리
|
|
599
597
|
*/
|
|
600
598
|
loginSuccess(targetRoute = null) {
|
|
601
599
|
const redirectRoute = targetRoute || this.config.redirectAfterLogin;
|
|
602
|
-
this.log(`\u{1F389} Login success, redirecting to: ${redirectRoute}`);
|
|
600
|
+
this.log("info", `\u{1F389} Login success, redirecting to: ${redirectRoute}`);
|
|
603
601
|
this.emitAuthEvent("login_success", { targetRoute: redirectRoute });
|
|
604
602
|
if (this.router && typeof this.router.navigateTo === "function") {
|
|
605
603
|
this.router.navigateTo(redirectRoute);
|
|
@@ -610,7 +608,7 @@ var AuthManager = class {
|
|
|
610
608
|
* 로그아웃 처리
|
|
611
609
|
*/
|
|
612
610
|
logout() {
|
|
613
|
-
this.log("\u{1F44B} Logging out user");
|
|
611
|
+
this.log("info", "\u{1F44B} Logging out user");
|
|
614
612
|
this.removeAccessToken();
|
|
615
613
|
this.emitAuthEvent("logout", {});
|
|
616
614
|
if (this.router && typeof this.router.navigateTo === "function") {
|
|
@@ -635,11 +633,11 @@ var AuthManager = class {
|
|
|
635
633
|
try {
|
|
636
634
|
listener(data);
|
|
637
635
|
} catch (error) {
|
|
638
|
-
this.log("Event listener error:", error);
|
|
636
|
+
this.log("error", "Event listener error:", error);
|
|
639
637
|
}
|
|
640
638
|
});
|
|
641
639
|
}
|
|
642
|
-
this.log(`\u{1F514} Auth event emitted: ${eventType}`, data);
|
|
640
|
+
this.log("debug", `\u{1F514} Auth event emitted: ${eventType}`, data);
|
|
643
641
|
}
|
|
644
642
|
/**
|
|
645
643
|
* 이벤트 리스너 등록
|
|
@@ -812,7 +810,7 @@ var CacheManager = class {
|
|
|
812
810
|
patterns.forEach((pattern) => {
|
|
813
811
|
totalInvalidated += this.deleteByPattern(pattern);
|
|
814
812
|
});
|
|
815
|
-
this.log(`\u{1F504} Deleted component cache for route: ${routeName} (${totalInvalidated} entries)`);
|
|
813
|
+
this.log("debug", `\u{1F504} Deleted component cache for route: ${routeName} (${totalInvalidated} entries)`);
|
|
816
814
|
return totalInvalidated;
|
|
817
815
|
}
|
|
818
816
|
/**
|
|
@@ -824,7 +822,7 @@ var CacheManager = class {
|
|
|
824
822
|
componentPatterns.forEach((pattern) => {
|
|
825
823
|
totalCleared += this.deleteByPattern(pattern);
|
|
826
824
|
});
|
|
827
|
-
this.log(`\u{1F9FD} Deleted all component caches (${totalCleared} entries)`);
|
|
825
|
+
this.log("debug", `\u{1F9FD} Deleted all component caches (${totalCleared} entries)`);
|
|
828
826
|
return totalCleared;
|
|
829
827
|
}
|
|
830
828
|
/**
|
|
@@ -835,7 +833,7 @@ var CacheManager = class {
|
|
|
835
833
|
this.cache.clear();
|
|
836
834
|
this.cacheTimestamps.clear();
|
|
837
835
|
this.lruOrder = [];
|
|
838
|
-
this.log(`\u{1F525} Cleared all cache (${size} entries)`);
|
|
836
|
+
this.log("debug", `\u{1F525} Cleared all cache (${size} entries)`);
|
|
839
837
|
return size;
|
|
840
838
|
}
|
|
841
839
|
/**
|
|
@@ -860,7 +858,7 @@ var CacheManager = class {
|
|
|
860
858
|
}
|
|
861
859
|
});
|
|
862
860
|
if (expiredKeys.length > 0) {
|
|
863
|
-
this.log(`\u23F1\uFE0F Cleaned ${expiredKeys.length} expired cache entries`);
|
|
861
|
+
this.log("debug", `\u23F1\uFE0F Cleaned ${expiredKeys.length} expired cache entries`);
|
|
864
862
|
}
|
|
865
863
|
return expiredKeys.length;
|
|
866
864
|
}
|
|
@@ -952,7 +950,7 @@ var CacheManager = class {
|
|
|
952
950
|
this.cleanupInterval = setInterval(() => {
|
|
953
951
|
this.cleanExpired();
|
|
954
952
|
}, interval);
|
|
955
|
-
this.log(`\u{1F916} Auto cleanup started (interval: ${interval}ms)`);
|
|
953
|
+
this.log("debug", `\u{1F916} Auto cleanup started (interval: ${interval}ms)`);
|
|
956
954
|
}
|
|
957
955
|
/**
|
|
958
956
|
* 자동 정리 중지
|
|
@@ -1174,11 +1172,8 @@ var QueryManager = class {
|
|
|
1174
1172
|
var FormHandler = class {
|
|
1175
1173
|
constructor(router, options = {}) {
|
|
1176
1174
|
this.router = router;
|
|
1177
|
-
this.
|
|
1178
|
-
|
|
1179
|
-
requestTimeout: options.requestTimeout || 3e4,
|
|
1180
|
-
...options
|
|
1181
|
-
};
|
|
1175
|
+
this.requestTimeout = options.requestTimeout || 3e4;
|
|
1176
|
+
this.uploadTimeout = options.uploadTimeout || 3e5;
|
|
1182
1177
|
this.log("debug", "FormHandler initialized");
|
|
1183
1178
|
}
|
|
1184
1179
|
/**
|
|
@@ -1205,11 +1200,13 @@ var FormHandler = class {
|
|
|
1205
1200
|
startFormSubmission(form) {
|
|
1206
1201
|
form._isSubmitting = true;
|
|
1207
1202
|
form._abortController = new AbortController();
|
|
1203
|
+
const hasFile = Array.from(form.elements).some((el) => el.type === "file" && el.files.length > 0);
|
|
1204
|
+
const timeout = hasFile ? this.uploadTimeout : this.requestTimeout;
|
|
1208
1205
|
form._timeoutId = setTimeout(() => {
|
|
1209
1206
|
if (form._isSubmitting) {
|
|
1210
1207
|
this.abortFormSubmission(form);
|
|
1211
1208
|
}
|
|
1212
|
-
},
|
|
1209
|
+
}, timeout);
|
|
1213
1210
|
}
|
|
1214
1211
|
/**
|
|
1215
1212
|
* 폼 제출 완료
|
|
@@ -1413,12 +1410,7 @@ var FormHandler = class {
|
|
|
1413
1410
|
var ApiHandler = class {
|
|
1414
1411
|
constructor(router, options = {}) {
|
|
1415
1412
|
this.router = router;
|
|
1416
|
-
this.
|
|
1417
|
-
debug: options.debug || false,
|
|
1418
|
-
timeout: options.timeout || 1e4,
|
|
1419
|
-
retries: options.retries || 1,
|
|
1420
|
-
...options
|
|
1421
|
-
};
|
|
1413
|
+
this.apiBaseURL = options.apiBaseURL || "";
|
|
1422
1414
|
this.log("debug", "ApiHandler initialized");
|
|
1423
1415
|
}
|
|
1424
1416
|
/**
|
|
@@ -1435,6 +1427,9 @@ var ApiHandler = class {
|
|
|
1435
1427
|
async fetchData(dataURL, component = null, options = {}) {
|
|
1436
1428
|
try {
|
|
1437
1429
|
let processedURL = this.processURLParameters(dataURL, component);
|
|
1430
|
+
if (this.apiBaseURL && !this.isAbsoluteURL(processedURL)) {
|
|
1431
|
+
processedURL = this.combineURLs(this.apiBaseURL, processedURL);
|
|
1432
|
+
}
|
|
1438
1433
|
const queryString = this.router.queryManager?.buildQueryString(this.router.queryManager?.getQueryParams()) || "";
|
|
1439
1434
|
const fullURL = queryString ? `${processedURL}?${queryString}` : processedURL;
|
|
1440
1435
|
this.log("debug", `Fetching data from: ${fullURL}`);
|
|
@@ -1525,15 +1520,15 @@ var ApiHandler = class {
|
|
|
1525
1520
|
const paramName = match.slice(1, -1);
|
|
1526
1521
|
try {
|
|
1527
1522
|
let paramValue = null;
|
|
1528
|
-
if (component
|
|
1529
|
-
paramValue = component
|
|
1523
|
+
if (component.$options?.computed?.[paramName]) {
|
|
1524
|
+
paramValue = component[paramName];
|
|
1530
1525
|
}
|
|
1531
1526
|
if (paramValue === null || paramValue === void 0) {
|
|
1532
1527
|
paramValue = component[paramName];
|
|
1533
1528
|
}
|
|
1534
1529
|
if (paramValue === null || paramValue === void 0) {
|
|
1535
|
-
if (component
|
|
1536
|
-
paramValue = component
|
|
1530
|
+
if (component.getParam) {
|
|
1531
|
+
paramValue = component.getParam(paramName);
|
|
1537
1532
|
}
|
|
1538
1533
|
}
|
|
1539
1534
|
if (paramValue === null || paramValue === void 0) {
|
|
@@ -1587,6 +1582,20 @@ var ApiHandler = class {
|
|
|
1587
1582
|
fetchMultipleData: (dataConfig) => this.fetchMultipleData(dataConfig, component)
|
|
1588
1583
|
};
|
|
1589
1584
|
}
|
|
1585
|
+
/**
|
|
1586
|
+
* 절대 URL인지 확인
|
|
1587
|
+
*/
|
|
1588
|
+
isAbsoluteURL(url) {
|
|
1589
|
+
return /^https?:\/\//.test(url) || url.startsWith("//");
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* 두 URL을 조합
|
|
1593
|
+
*/
|
|
1594
|
+
combineURLs(baseURL, relativeURL) {
|
|
1595
|
+
const cleanBase = baseURL.replace(/\/$/, "");
|
|
1596
|
+
const cleanRelative = relativeURL.startsWith("/") ? relativeURL : `/${relativeURL}`;
|
|
1597
|
+
return `${cleanBase}${cleanRelative}`;
|
|
1598
|
+
}
|
|
1590
1599
|
/**
|
|
1591
1600
|
* 정리 (메모리 누수 방지)
|
|
1592
1601
|
*/
|
|
@@ -1602,7 +1611,6 @@ var ComponentLoader = class {
|
|
|
1602
1611
|
this.config = {
|
|
1603
1612
|
componentsPath: options.componentsPath || "/components",
|
|
1604
1613
|
// srcPath 기준 상대 경로
|
|
1605
|
-
debug: options.debug || false,
|
|
1606
1614
|
environment: options.environment || "development",
|
|
1607
1615
|
...options
|
|
1608
1616
|
};
|
|
@@ -1873,8 +1881,7 @@ var RouteLoader = class {
|
|
|
1873
1881
|
// 프로덕션 라우트 경로
|
|
1874
1882
|
environment: options.environment || "development",
|
|
1875
1883
|
useLayout: options.useLayout !== false,
|
|
1876
|
-
defaultLayout: options.defaultLayout || "default"
|
|
1877
|
-
debug: options.debug || false
|
|
1884
|
+
defaultLayout: options.defaultLayout || "default"
|
|
1878
1885
|
};
|
|
1879
1886
|
this.router = router;
|
|
1880
1887
|
this.formHandler = new FormHandler(router, this.config);
|
|
@@ -2189,9 +2196,7 @@ ${template}`;
|
|
|
2189
2196
|
var ErrorHandler = class {
|
|
2190
2197
|
constructor(router, options = {}) {
|
|
2191
2198
|
this.config = {
|
|
2192
|
-
|
|
2193
|
-
debug: options.debug || false,
|
|
2194
|
-
logLevel: options.logLevel || (options.debug ? "debug" : "info"),
|
|
2199
|
+
logLevel: options.logLevel || "info",
|
|
2195
2200
|
environment: options.environment || "development"
|
|
2196
2201
|
};
|
|
2197
2202
|
this.router = router;
|
|
@@ -2221,9 +2226,7 @@ var ErrorHandler = class {
|
|
|
2221
2226
|
errorMessage = "\uD398\uC774\uC9C0\uC5D0 \uC811\uADFC\uD560 \uAD8C\uD55C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
|
|
2222
2227
|
}
|
|
2223
2228
|
this.debug("ErrorHandler", `\uC5D0\uB7EC \uCF54\uB4DC \uACB0\uC815: ${errorCode} (\uB77C\uC6B0\uD2B8: ${routeName})`);
|
|
2224
|
-
|
|
2225
|
-
this.reportError(routeName, error, errorCode);
|
|
2226
|
-
}
|
|
2229
|
+
this.reportError(routeName, error, errorCode);
|
|
2227
2230
|
try {
|
|
2228
2231
|
if (errorCode === 404) {
|
|
2229
2232
|
await this.load404Page();
|
|
@@ -2394,7 +2397,7 @@ var ErrorHandler = class {
|
|
|
2394
2397
|
if (typeof level !== "string" || !this.logLevels.hasOwnProperty(level)) {
|
|
2395
2398
|
args = [component, ...args];
|
|
2396
2399
|
component = level;
|
|
2397
|
-
level =
|
|
2400
|
+
level = "info";
|
|
2398
2401
|
}
|
|
2399
2402
|
const currentLevelValue = this.logLevels[this.config.logLevel] || this.logLevels.info;
|
|
2400
2403
|
const messageLevelValue = this.logLevels[level] || this.logLevels.info;
|
|
@@ -2635,6 +2638,9 @@ var ViewLogicRouter = class {
|
|
|
2635
2638
|
i18nPath: "/i18n",
|
|
2636
2639
|
// 다국어 파일 경로
|
|
2637
2640
|
logLevel: "info",
|
|
2641
|
+
apiBaseURL: "",
|
|
2642
|
+
requestTimeout: 3e4,
|
|
2643
|
+
uploadTimeout: 3e5,
|
|
2638
2644
|
authEnabled: false,
|
|
2639
2645
|
loginRoute: "login",
|
|
2640
2646
|
protectedRoutes: [],
|
|
@@ -2643,8 +2649,7 @@ var ViewLogicRouter = class {
|
|
|
2643
2649
|
checkAuthFunction: null,
|
|
2644
2650
|
redirectAfterLogin: "home",
|
|
2645
2651
|
authCookieName: "authToken",
|
|
2646
|
-
authStorage: "localStorage"
|
|
2647
|
-
authSkipValidation: false
|
|
2652
|
+
authStorage: "localStorage"
|
|
2648
2653
|
};
|
|
2649
2654
|
const config = { ...defaults, ...options };
|
|
2650
2655
|
config.srcPath = this.resolvePath(config.srcPath, config.basePath);
|
|
@@ -2653,49 +2658,42 @@ var ViewLogicRouter = class {
|
|
|
2653
2658
|
return config;
|
|
2654
2659
|
}
|
|
2655
2660
|
/**
|
|
2656
|
-
*
|
|
2661
|
+
* 두 경로를 안전하게 조합 및 정규화 (기본 유틸리티)
|
|
2662
|
+
* @param {string} basePath - 기본 경로
|
|
2663
|
+
* @param {string} relativePath - 상대 경로
|
|
2664
|
+
* @returns {string} 조합된 경로 (예: '/examples' + '/about' → '/examples/about')
|
|
2665
|
+
*/
|
|
2666
|
+
combinePaths(basePath, relativePath) {
|
|
2667
|
+
if (!basePath || basePath === "/") {
|
|
2668
|
+
return relativePath.replace(/\/+/g, "/");
|
|
2669
|
+
}
|
|
2670
|
+
const cleanBase = basePath.endsWith("/") ? basePath.slice(0, -1) : basePath;
|
|
2671
|
+
const cleanRelative = relativePath.startsWith("/") ? relativePath : `/${relativePath}`;
|
|
2672
|
+
const combined = `${cleanBase}${cleanRelative}`;
|
|
2673
|
+
return combined.replace(/\/+/g, "/");
|
|
2674
|
+
}
|
|
2675
|
+
/**
|
|
2676
|
+
* 상대 경로를 완전한 절대 URL로 변환 (파일 시스템 전용)
|
|
2677
|
+
* @param {string} path - 변환할 경로
|
|
2678
|
+
* @param {string} basePath - 기본 경로 (옵션)
|
|
2679
|
+
* @returns {string} 완전한 절대 URL (예: 'http://localhost:3000/examples/about')
|
|
2657
2680
|
*/
|
|
2658
2681
|
resolvePath(path, basePath = null) {
|
|
2682
|
+
if (basePath === null) {
|
|
2683
|
+
basePath = this.config?.basePath || "/";
|
|
2684
|
+
}
|
|
2659
2685
|
const currentOrigin = window.location.origin;
|
|
2660
2686
|
if (path.startsWith("http")) {
|
|
2661
2687
|
return path;
|
|
2662
2688
|
}
|
|
2663
2689
|
if (path.startsWith("/")) {
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
const cleanPath = path.startsWith("/") ? path : `/${path}`;
|
|
2667
|
-
const fullPath = `${cleanBasePath}${cleanPath}`;
|
|
2668
|
-
const fullUrl2 = `${currentOrigin}${fullPath}`;
|
|
2669
|
-
return fullUrl2.replace(/([^:])\/{2,}/g, "$1/");
|
|
2670
|
-
}
|
|
2671
|
-
return `${currentOrigin}${path}`;
|
|
2690
|
+
const combinedPath = this.combinePaths(basePath, path);
|
|
2691
|
+
return `${currentOrigin}${combinedPath}`;
|
|
2672
2692
|
}
|
|
2673
2693
|
const currentPathname = window.location.pathname;
|
|
2674
2694
|
const currentBase = currentPathname.endsWith("/") ? currentPathname : currentPathname.substring(0, currentPathname.lastIndexOf("/") + 1);
|
|
2675
|
-
const resolvedPath = this.
|
|
2676
|
-
|
|
2677
|
-
return fullUrl.replace(/([^:])\/{2,}/g, "$1/");
|
|
2678
|
-
}
|
|
2679
|
-
/**
|
|
2680
|
-
* URL 경로 정규화 (이중 슬래시 제거 및 ../, ./ 처리)
|
|
2681
|
-
*/
|
|
2682
|
-
normalizePath(path) {
|
|
2683
|
-
path = path.replace(/\/+/g, "/");
|
|
2684
|
-
const parts = path.split("/").filter((part) => part !== "" && part !== ".");
|
|
2685
|
-
const stack = [];
|
|
2686
|
-
for (const part of parts) {
|
|
2687
|
-
if (part === "..") {
|
|
2688
|
-
if (stack.length > 0 && stack[stack.length - 1] !== "..") {
|
|
2689
|
-
stack.pop();
|
|
2690
|
-
} else if (!path.startsWith("/")) {
|
|
2691
|
-
stack.push(part);
|
|
2692
|
-
}
|
|
2693
|
-
} else {
|
|
2694
|
-
stack.push(part);
|
|
2695
|
-
}
|
|
2696
|
-
}
|
|
2697
|
-
const normalized = "/" + stack.join("/");
|
|
2698
|
-
return normalized === "/" ? "/" : normalized;
|
|
2695
|
+
const resolvedPath = this.combinePaths(currentBase, path);
|
|
2696
|
+
return `${currentOrigin}${resolvedPath}`;
|
|
2699
2697
|
}
|
|
2700
2698
|
/**
|
|
2701
2699
|
* 로깅 래퍼 메서드
|
|
@@ -2936,31 +2934,17 @@ var ViewLogicRouter = class {
|
|
|
2936
2934
|
updateURL(route, params = null) {
|
|
2937
2935
|
const queryParams = params || this.queryManager?.getQueryParams() || {};
|
|
2938
2936
|
const queryString = this.queryManager?.buildQueryString(queryParams) || "";
|
|
2939
|
-
|
|
2940
|
-
let base = route2 === "home" ? "/" : `/${route2}`;
|
|
2941
|
-
if (!isHash && this.config.basePath && this.config.basePath !== "/") {
|
|
2942
|
-
base = `${this.config.basePath}${base}`;
|
|
2943
|
-
}
|
|
2944
|
-
const url = queryString2 ? `${base}?${queryString2}` : base;
|
|
2945
|
-
return isHash ? `#${url}` : url;
|
|
2946
|
-
};
|
|
2937
|
+
let base = route === "home" ? "/" : `/${route}`;
|
|
2947
2938
|
if (this.config.mode === "hash") {
|
|
2948
|
-
const
|
|
2939
|
+
const url = queryString ? `${base}?${queryString}` : base;
|
|
2940
|
+
const newHash = `#${url}`;
|
|
2949
2941
|
if (window.location.hash !== newHash) {
|
|
2950
2942
|
window.location.hash = newHash;
|
|
2951
2943
|
}
|
|
2952
2944
|
} else {
|
|
2953
|
-
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
expectedPath = `${this.config.basePath}${expectedPath}`;
|
|
2957
|
-
}
|
|
2958
|
-
const isSameRoute = window.location.pathname === expectedPath;
|
|
2959
|
-
if (isSameRoute) {
|
|
2960
|
-
window.history.replaceState({}, "", newPath);
|
|
2961
|
-
} else {
|
|
2962
|
-
window.history.pushState({}, "", newPath);
|
|
2963
|
-
}
|
|
2945
|
+
base = this.combinePaths(this.config.basePath, base);
|
|
2946
|
+
const url = queryString ? `${base}?${queryString}` : base;
|
|
2947
|
+
window.history.pushState({}, "", url);
|
|
2964
2948
|
this.handleRouteChange();
|
|
2965
2949
|
}
|
|
2966
2950
|
}
|