viewlogic 1.2.0 → 1.2.1
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/dist/viewlogic-router.js
CHANGED
|
@@ -1488,6 +1488,7 @@ var FormHandler = class {
|
|
|
1488
1488
|
this.router = router;
|
|
1489
1489
|
this.config = {
|
|
1490
1490
|
debug: options.debug || false,
|
|
1491
|
+
requestTimeout: options.requestTimeout || 3e4,
|
|
1491
1492
|
...options
|
|
1492
1493
|
};
|
|
1493
1494
|
this.log("debug", "FormHandler initialized");
|
|
@@ -1500,6 +1501,48 @@ var FormHandler = class {
|
|
|
1500
1501
|
this.router.errorHandler.log(level, "FormHandler", ...args);
|
|
1501
1502
|
}
|
|
1502
1503
|
}
|
|
1504
|
+
/**
|
|
1505
|
+
* 중복 요청 체크
|
|
1506
|
+
*/
|
|
1507
|
+
isDuplicateRequest(form) {
|
|
1508
|
+
if (form._isSubmitting) {
|
|
1509
|
+
this.log("debug", "Duplicate request blocked");
|
|
1510
|
+
return true;
|
|
1511
|
+
}
|
|
1512
|
+
return false;
|
|
1513
|
+
}
|
|
1514
|
+
/**
|
|
1515
|
+
* 폼 제출 시작
|
|
1516
|
+
*/
|
|
1517
|
+
startFormSubmission(form) {
|
|
1518
|
+
form._isSubmitting = true;
|
|
1519
|
+
form._abortController = new AbortController();
|
|
1520
|
+
form._timeoutId = setTimeout(() => {
|
|
1521
|
+
if (form._isSubmitting) {
|
|
1522
|
+
this.abortFormSubmission(form);
|
|
1523
|
+
}
|
|
1524
|
+
}, this.config.requestTimeout);
|
|
1525
|
+
}
|
|
1526
|
+
/**
|
|
1527
|
+
* 폼 제출 완료
|
|
1528
|
+
*/
|
|
1529
|
+
finishFormSubmission(form) {
|
|
1530
|
+
form._isSubmitting = false;
|
|
1531
|
+
if (form._timeoutId) {
|
|
1532
|
+
clearTimeout(form._timeoutId);
|
|
1533
|
+
delete form._timeoutId;
|
|
1534
|
+
}
|
|
1535
|
+
delete form._abortController;
|
|
1536
|
+
}
|
|
1537
|
+
/**
|
|
1538
|
+
* 폼 제출 중단
|
|
1539
|
+
*/
|
|
1540
|
+
abortFormSubmission(form) {
|
|
1541
|
+
if (form._abortController) {
|
|
1542
|
+
form._abortController.abort();
|
|
1543
|
+
}
|
|
1544
|
+
this.finishFormSubmission(form);
|
|
1545
|
+
}
|
|
1503
1546
|
/**
|
|
1504
1547
|
* 자동 폼 바인딩
|
|
1505
1548
|
*/
|
|
@@ -1525,28 +1568,40 @@ var FormHandler = class {
|
|
|
1525
1568
|
const errorHandler = form.getAttribute("data-error-handler");
|
|
1526
1569
|
const loadingHandler = form.getAttribute("data-loading-handler");
|
|
1527
1570
|
const redirectTo = form.getAttribute("data-redirect");
|
|
1571
|
+
action = this.processActionParams(action, component);
|
|
1572
|
+
if (!this.validateForm(form, component)) {
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
if (this.isDuplicateRequest(form)) {
|
|
1576
|
+
return;
|
|
1577
|
+
}
|
|
1578
|
+
this.startFormSubmission(form);
|
|
1579
|
+
const formData = new FormData(form);
|
|
1580
|
+
const data = Object.fromEntries(formData.entries());
|
|
1528
1581
|
try {
|
|
1529
1582
|
if (loadingHandler && component[loadingHandler]) {
|
|
1530
1583
|
component[loadingHandler](true, form);
|
|
1531
1584
|
}
|
|
1532
|
-
action = this.processActionParams(action, component);
|
|
1533
|
-
if (!this.validateForm(form, component)) {
|
|
1534
|
-
return;
|
|
1535
|
-
}
|
|
1536
|
-
const formData = new FormData(form);
|
|
1537
|
-
const data = Object.fromEntries(formData.entries());
|
|
1538
1585
|
this.log("debug", `Form submitting to: ${action}`, data);
|
|
1539
|
-
const response = await this.submitFormData(action, method, data, form, component);
|
|
1586
|
+
const response = await this.submitFormData(action, method, data, form, component, form._abortController.signal);
|
|
1540
1587
|
if (successHandler && component[successHandler]) {
|
|
1541
1588
|
component[successHandler](response, form);
|
|
1542
1589
|
}
|
|
1590
|
+
this.finishFormSubmission(form);
|
|
1543
1591
|
if (redirectTo) {
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1592
|
+
requestAnimationFrame(() => {
|
|
1593
|
+
setTimeout(() => {
|
|
1594
|
+
component.navigateTo(redirectTo);
|
|
1595
|
+
}, 1e3);
|
|
1596
|
+
});
|
|
1547
1597
|
}
|
|
1548
1598
|
} catch (error) {
|
|
1549
|
-
|
|
1599
|
+
if (error.name === "AbortError") {
|
|
1600
|
+
this.log("debug", "Form submission aborted");
|
|
1601
|
+
return;
|
|
1602
|
+
}
|
|
1603
|
+
this.log("warn", "Form submission error:", error);
|
|
1604
|
+
this.finishFormSubmission(form);
|
|
1550
1605
|
if (errorHandler && component[errorHandler]) {
|
|
1551
1606
|
component[errorHandler](error, form);
|
|
1552
1607
|
} else {
|
|
@@ -1567,11 +1622,13 @@ var FormHandler = class {
|
|
|
1567
1622
|
/**
|
|
1568
1623
|
* 폼 데이터 서브밋 (ApiHandler 활용)
|
|
1569
1624
|
*/
|
|
1570
|
-
async submitFormData(action, method, data, form, component) {
|
|
1625
|
+
async submitFormData(action, method, data, form, component, signal = null) {
|
|
1571
1626
|
const hasFile = Array.from(form.elements).some((el) => el.type === "file" && el.files.length > 0);
|
|
1572
1627
|
const options = {
|
|
1573
1628
|
method: method.toUpperCase(),
|
|
1574
|
-
headers: {}
|
|
1629
|
+
headers: {},
|
|
1630
|
+
signal
|
|
1631
|
+
// AbortController 신호 추가
|
|
1575
1632
|
};
|
|
1576
1633
|
if (hasFile) {
|
|
1577
1634
|
options.data = new FormData(form);
|
|
@@ -1624,20 +1681,44 @@ var FormHandler = class {
|
|
|
1624
1681
|
this.log("warn", `Validation function '${validationFunction}' not found`);
|
|
1625
1682
|
return true;
|
|
1626
1683
|
}
|
|
1684
|
+
/**
|
|
1685
|
+
* 모든 폼 요청 취소
|
|
1686
|
+
*/
|
|
1687
|
+
cancelAllRequests() {
|
|
1688
|
+
const forms = document.querySelectorAll("form");
|
|
1689
|
+
forms.forEach((form) => {
|
|
1690
|
+
if (form._isSubmitting) {
|
|
1691
|
+
this.abortFormSubmission(form);
|
|
1692
|
+
}
|
|
1693
|
+
});
|
|
1694
|
+
}
|
|
1627
1695
|
/**
|
|
1628
1696
|
* 정리 (메모리 누수 방지)
|
|
1629
1697
|
*/
|
|
1630
1698
|
destroy() {
|
|
1699
|
+
this.cancelAllRequests();
|
|
1631
1700
|
const forms = document.querySelectorAll("form.auto-form, form[action]");
|
|
1632
1701
|
forms.forEach((form) => {
|
|
1633
1702
|
if (form._boundSubmitHandler) {
|
|
1634
1703
|
form.removeEventListener("submit", form._boundSubmitHandler);
|
|
1635
1704
|
delete form._boundSubmitHandler;
|
|
1636
1705
|
}
|
|
1706
|
+
this.cleanupFormState(form);
|
|
1637
1707
|
});
|
|
1638
1708
|
this.log("debug", "FormHandler destroyed");
|
|
1639
1709
|
this.router = null;
|
|
1640
1710
|
}
|
|
1711
|
+
/**
|
|
1712
|
+
* 폼 상태 정리
|
|
1713
|
+
*/
|
|
1714
|
+
cleanupFormState(form) {
|
|
1715
|
+
delete form._isSubmitting;
|
|
1716
|
+
delete form._abortController;
|
|
1717
|
+
if (form._timeoutId) {
|
|
1718
|
+
clearTimeout(form._timeoutId);
|
|
1719
|
+
delete form._timeoutId;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1641
1722
|
};
|
|
1642
1723
|
|
|
1643
1724
|
// src/core/ApiHandler.js
|