dolphin-client 1.0.9 → 1.1.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/.vscode/dolphin-tags.json +28 -0
- package/dist/dolphin-client.js +143 -4
- package/dist/dolphin-client.min.js +18 -18
- package/dist/index.cjs +143 -4
- package/dist/index.js +143 -4
- package/package.json +1 -1
|
@@ -390,6 +390,34 @@
|
|
|
390
390
|
{
|
|
391
391
|
"name": "data-rt-sort",
|
|
392
392
|
"description": "Sorts the rendered data array (e.g., price.asc or popular)."
|
|
393
|
+
},
|
|
394
|
+
{
|
|
395
|
+
"name": "data-api-toast",
|
|
396
|
+
"description": "Inline success message to show as toast after a successful API request."
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
"name": "data-api-error-toast",
|
|
400
|
+
"description": "Inline error message to show as toast after a failed API request."
|
|
401
|
+
},
|
|
402
|
+
{
|
|
403
|
+
"name": "data-rt-api-success",
|
|
404
|
+
"description": "ID of a hidden element whose text content is shown as a success toast after a successful API request. Example: data-rt-api-success=\"my-success-msg\""
|
|
405
|
+
},
|
|
406
|
+
{
|
|
407
|
+
"name": "data-rt-api-error",
|
|
408
|
+
"description": "ID of a hidden element whose text content is shown as an error toast after a failed API request. Example: data-rt-api-error=\"my-error-msg\""
|
|
409
|
+
},
|
|
410
|
+
{
|
|
411
|
+
"name": "data-rt-api-success-show",
|
|
412
|
+
"description": "ID of an inline alert element to reveal (remove hidden) on API success. Pair with data-rt-alert-duration for auto-hide. Example: data-rt-api-success-show=\"success-alert\""
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
"name": "data-rt-api-error-show",
|
|
416
|
+
"description": "ID of an inline alert element to reveal (remove hidden) on API error. Pair with data-rt-alert-duration for auto-hide. Example: data-rt-api-error-show=\"error-alert\""
|
|
417
|
+
},
|
|
418
|
+
{
|
|
419
|
+
"name": "data-rt-alert-duration",
|
|
420
|
+
"description": "Duration in milliseconds before the inline alert auto-hides. Use with data-rt-api-success-show or data-rt-api-error-show. Example: data-rt-alert-duration=\"3000\""
|
|
393
421
|
}
|
|
394
422
|
],
|
|
395
423
|
"valueSets": [
|
package/dist/dolphin-client.js
CHANGED
|
@@ -41,7 +41,7 @@ var DolphinModule = (() => {
|
|
|
41
41
|
target.patch = (pathOrBody, bodyOrOptions, options) => typeof pathOrBody === "string" ? this.request("PATCH", pathOrBody, bodyOrOptions, options) : this.request("PATCH", joined, pathOrBody, bodyOrOptions);
|
|
42
42
|
target.del = (pathOrOptions, options) => typeof pathOrOptions === "string" ? this.request("DELETE", pathOrOptions, null, options) : this.request("DELETE", joined, null, pathOrOptions);
|
|
43
43
|
target.request = (method, subPath, body, options) => {
|
|
44
|
-
const finalPath = subPath ? `${joined}/${subPath.startsWith("/") ? subPath.slice(1) : subPath}` : joined;
|
|
44
|
+
const finalPath = subPath ? joined ? `${joined}/${subPath.startsWith("/") ? subPath.slice(1) : subPath}` : subPath : joined;
|
|
45
45
|
return this.request(method, finalPath, body, options);
|
|
46
46
|
};
|
|
47
47
|
target.requestDirect = (method, path, body, options) => {
|
|
@@ -225,8 +225,9 @@ var DolphinModule = (() => {
|
|
|
225
225
|
const _isRetry = options._isRetry === true;
|
|
226
226
|
let finalMethod = method.toUpperCase();
|
|
227
227
|
let finalBody = body;
|
|
228
|
+
const hasBody = !["GET", "HEAD"].includes(finalMethod);
|
|
228
229
|
const headers = {
|
|
229
|
-
"Content-Type": "application/json",
|
|
230
|
+
...hasBody ? { "Content-Type": "application/json" } : {},
|
|
230
231
|
...options.headers || {}
|
|
231
232
|
};
|
|
232
233
|
if (["PUT", "PATCH", "DELETE"].includes(finalMethod)) {
|
|
@@ -1376,6 +1377,86 @@ var DolphinModule = (() => {
|
|
|
1376
1377
|
console.error("%cFailed Expression:", "color: #3b82f6; font-style: italic;", expression);
|
|
1377
1378
|
}
|
|
1378
1379
|
};
|
|
1380
|
+
clientProto._showAlert = function(id, duration) {
|
|
1381
|
+
if (typeof document === "undefined") return;
|
|
1382
|
+
const el = document.getElementById(id) || document.querySelector(`[id="${id}"]`);
|
|
1383
|
+
if (!el) return;
|
|
1384
|
+
el.removeAttribute("hidden");
|
|
1385
|
+
el.style.display = "";
|
|
1386
|
+
if (duration && duration > 0) {
|
|
1387
|
+
setTimeout(() => {
|
|
1388
|
+
el.setAttribute("hidden", "");
|
|
1389
|
+
}, duration);
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
clientProto._showToast = function(message, type = "success") {
|
|
1393
|
+
if (typeof document === "undefined") return;
|
|
1394
|
+
const colors = {
|
|
1395
|
+
success: { bg: "rgba(16,185,129,0.15)", border: "#10b981", icon: "\u2705" },
|
|
1396
|
+
error: { bg: "rgba(239,68,68,0.15)", border: "#ef4444", icon: "\u274C" },
|
|
1397
|
+
info: { bg: "rgba(59,130,246,0.15)", border: "#3b82f6", icon: "\u2139\uFE0F" }
|
|
1398
|
+
};
|
|
1399
|
+
const c = colors[type] || colors.success;
|
|
1400
|
+
const toast = document.createElement("div");
|
|
1401
|
+
toast.setAttribute("data-dolphin-toast", "");
|
|
1402
|
+
const existing = document.querySelectorAll("[data-dolphin-toast]");
|
|
1403
|
+
const offset = existing.length * 72;
|
|
1404
|
+
toast.style.cssText = [
|
|
1405
|
+
"position:fixed",
|
|
1406
|
+
`bottom:${24 + offset}px`,
|
|
1407
|
+
"right:24px",
|
|
1408
|
+
"z-index:2147483647",
|
|
1409
|
+
`background:${c.bg}`,
|
|
1410
|
+
`border:1px solid ${c.border}`,
|
|
1411
|
+
"color:#fff",
|
|
1412
|
+
"padding:14px 20px",
|
|
1413
|
+
"border-radius:14px",
|
|
1414
|
+
"font-size:14px",
|
|
1415
|
+
"font-weight:600",
|
|
1416
|
+
"font-family:system-ui,sans-serif",
|
|
1417
|
+
"box-shadow:0 8px 32px rgba(0,0,0,0.4)",
|
|
1418
|
+
"display:flex",
|
|
1419
|
+
"align-items:center",
|
|
1420
|
+
"gap:10px",
|
|
1421
|
+
"max-width:380px",
|
|
1422
|
+
"word-break:break-word",
|
|
1423
|
+
"transform:translateY(80px)",
|
|
1424
|
+
"opacity:0",
|
|
1425
|
+
"transition:transform 0.35s cubic-bezier(0.34,1.56,0.64,1),opacity 0.3s ease",
|
|
1426
|
+
"pointer-events:auto",
|
|
1427
|
+
"backdrop-filter:blur(12px)"
|
|
1428
|
+
].join(";");
|
|
1429
|
+
toast.innerHTML = `<span style="font-size:18px">${c.icon}</span><span>${message}</span>`;
|
|
1430
|
+
document.body.appendChild(toast);
|
|
1431
|
+
const restack = () => {
|
|
1432
|
+
const remaining = document.querySelectorAll("[data-dolphin-toast]");
|
|
1433
|
+
remaining.forEach((el, i) => {
|
|
1434
|
+
el.style.bottom = `${24 + i * 72}px`;
|
|
1435
|
+
});
|
|
1436
|
+
};
|
|
1437
|
+
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
1438
|
+
raf(() => raf(() => {
|
|
1439
|
+
toast.style.transform = "translateY(0)";
|
|
1440
|
+
toast.style.opacity = "1";
|
|
1441
|
+
}));
|
|
1442
|
+
const removeToast = () => {
|
|
1443
|
+
clearTimeout(toast._removeTimer);
|
|
1444
|
+
if (toast.parentNode) {
|
|
1445
|
+
toast.parentNode.removeChild(toast);
|
|
1446
|
+
restack();
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
const hideTimer = setTimeout(() => {
|
|
1450
|
+
toast.style.transform = "translateY(80px)";
|
|
1451
|
+
toast.style.opacity = "0";
|
|
1452
|
+
toast._removeTimer = setTimeout(removeToast, 400);
|
|
1453
|
+
}, 3500);
|
|
1454
|
+
toast._hideTimer = hideTimer;
|
|
1455
|
+
toast.addEventListener("click", () => {
|
|
1456
|
+
clearTimeout(toast._hideTimer);
|
|
1457
|
+
removeToast();
|
|
1458
|
+
}, { once: true });
|
|
1459
|
+
};
|
|
1379
1460
|
clientProto._initDOMBinding = function() {
|
|
1380
1461
|
if (this._domInitialized) return;
|
|
1381
1462
|
this._domInitialized = true;
|
|
@@ -1474,6 +1555,11 @@ var DolphinModule = (() => {
|
|
|
1474
1555
|
resolvedTopic = resolvedTopic.replace(new RegExp(`\\{\\{${escapedK}\\}\\}`, "g"), parentCtx[k] !== void 0 && parentCtx[k] !== null ? parentCtx[k] : "");
|
|
1475
1556
|
}
|
|
1476
1557
|
this.publish(resolvedTopic, data);
|
|
1558
|
+
const rtSuccessId = e.target.getAttribute("data-rt-api-success");
|
|
1559
|
+
if (rtSuccessId) {
|
|
1560
|
+
const rtSuccessEl = document.getElementById(rtSuccessId);
|
|
1561
|
+
if (rtSuccessEl) this._showToast(rtSuccessEl.textContent || rtSuccessEl.innerText || "", "success");
|
|
1562
|
+
}
|
|
1477
1563
|
} else if (apiTarget) {
|
|
1478
1564
|
let resolvedTarget = apiTarget;
|
|
1479
1565
|
for (const k in parentCtx) {
|
|
@@ -1490,16 +1576,40 @@ var DolphinModule = (() => {
|
|
|
1490
1576
|
const result = await this.api.request(method, path, data);
|
|
1491
1577
|
const resultBind = e.target.getAttribute("data-api-result");
|
|
1492
1578
|
if (resultBind) this._updateDOM(resultBind, result);
|
|
1579
|
+
const successToast = e.target.getAttribute("data-api-toast");
|
|
1580
|
+
if (successToast) this._showToast(successToast, "success");
|
|
1581
|
+
const successElId = e.target.getAttribute("data-rt-api-success");
|
|
1582
|
+
if (successElId) {
|
|
1583
|
+
const duration = parseInt(e.target.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1584
|
+
this._showAlert(successElId, duration);
|
|
1585
|
+
const errElId = e.target.getAttribute("data-rt-api-error");
|
|
1586
|
+
if (errElId) {
|
|
1587
|
+
const errEl = document.getElementById(errElId);
|
|
1588
|
+
if (errEl) errEl.setAttribute("hidden", "");
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1493
1591
|
const redirect = e.target.getAttribute("data-api-redirect");
|
|
1494
1592
|
if (redirect) window.location.href = redirect;
|
|
1495
1593
|
if (e.target.hasAttribute("data-api-reload")) window.location.reload();
|
|
1496
1594
|
} catch (err) {
|
|
1497
1595
|
console.error("[Dolphin] API Submit Error:", err);
|
|
1596
|
+
const errorToast = e.target.getAttribute("data-api-error-toast");
|
|
1597
|
+
if (errorToast) this._showToast(errorToast, "error");
|
|
1598
|
+
const errorElId = e.target.getAttribute("data-rt-api-error");
|
|
1599
|
+
if (errorElId) {
|
|
1600
|
+
const duration = parseInt(e.target.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1601
|
+
this._showAlert(errorElId, duration);
|
|
1602
|
+
const sucElId = e.target.getAttribute("data-rt-api-success");
|
|
1603
|
+
if (sucElId) {
|
|
1604
|
+
const sucEl = document.getElementById(sucElId);
|
|
1605
|
+
if (sucEl) sucEl.setAttribute("hidden", "");
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1498
1608
|
}
|
|
1499
1609
|
}
|
|
1500
1610
|
}
|
|
1501
1611
|
});
|
|
1502
|
-
const INTERACTION_EVENTS = ["click", "change", "
|
|
1612
|
+
const INTERACTION_EVENTS = ["click", "change", "input", "keydown", "keyup", "dblclick", "focus", "blur", "mouseenter", "mouseleave"];
|
|
1503
1613
|
INTERACTION_EVENTS.forEach((evtName) => {
|
|
1504
1614
|
this.addDomListener(document, evtName, async (e) => {
|
|
1505
1615
|
if (!e.target || !e.target.closest) return;
|
|
@@ -1530,7 +1640,12 @@ var DolphinModule = (() => {
|
|
|
1530
1640
|
const apiTarget = apiBtn.getAttribute(`data-api-${evtName}`);
|
|
1531
1641
|
const actionData = apiBtn.getAttribute("data-api-payload");
|
|
1532
1642
|
const parentCtx = this.getClosestContext(apiBtn) || {};
|
|
1533
|
-
|
|
1643
|
+
let resolvedApiTarget = apiTarget;
|
|
1644
|
+
for (const k in parentCtx) {
|
|
1645
|
+
const escapedK = escapeRegExp(k);
|
|
1646
|
+
resolvedApiTarget = resolvedApiTarget.replace(new RegExp(`\\{\\{${escapedK}\\}\\}`, "g"), parentCtx[k] !== void 0 && parentCtx[k] !== null ? parentCtx[k] : "");
|
|
1647
|
+
}
|
|
1648
|
+
const parts = resolvedApiTarget.trim().split(" ");
|
|
1534
1649
|
const method = parts.length > 1 ? parts[0].toUpperCase() : "POST";
|
|
1535
1650
|
const path = parts.length > 1 ? parts[1] : parts[0];
|
|
1536
1651
|
let payload = null;
|
|
@@ -1550,11 +1665,35 @@ var DolphinModule = (() => {
|
|
|
1550
1665
|
const result = await this.api.request(method, path, payload);
|
|
1551
1666
|
const resultBind = apiBtn.getAttribute("data-api-result");
|
|
1552
1667
|
if (resultBind) this._updateDOM(resultBind, result);
|
|
1668
|
+
const successToast = apiBtn.getAttribute("data-api-toast");
|
|
1669
|
+
if (successToast) this._showToast(successToast, "success");
|
|
1670
|
+
const successElId = apiBtn.getAttribute("data-rt-api-success");
|
|
1671
|
+
if (successElId) {
|
|
1672
|
+
const duration = parseInt(apiBtn.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1673
|
+
this._showAlert(successElId, duration);
|
|
1674
|
+
const errElId = apiBtn.getAttribute("data-rt-api-error");
|
|
1675
|
+
if (errElId) {
|
|
1676
|
+
const errEl = document.getElementById(errElId);
|
|
1677
|
+
if (errEl) errEl.setAttribute("hidden", "");
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1553
1680
|
const redirect = apiBtn.getAttribute("data-api-redirect");
|
|
1554
1681
|
if (redirect) window.location.href = redirect;
|
|
1555
1682
|
if (apiBtn.hasAttribute("data-api-reload")) window.location.reload();
|
|
1556
1683
|
} catch (err) {
|
|
1557
1684
|
console.error(`[Dolphin] API ${evtName} Error:`, err);
|
|
1685
|
+
const errorToast = apiBtn.getAttribute("data-api-error-toast");
|
|
1686
|
+
if (errorToast) this._showToast(errorToast, "error");
|
|
1687
|
+
const errorElId = apiBtn.getAttribute("data-rt-api-error");
|
|
1688
|
+
if (errorElId) {
|
|
1689
|
+
const duration = parseInt(apiBtn.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1690
|
+
this._showAlert(errorElId, duration);
|
|
1691
|
+
const sucElId = apiBtn.getAttribute("data-rt-api-success");
|
|
1692
|
+
if (sucElId) {
|
|
1693
|
+
const sucEl = document.getElementById(sucElId);
|
|
1694
|
+
if (sucEl) sucEl.setAttribute("hidden", "");
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1558
1697
|
}
|
|
1559
1698
|
}
|
|
1560
1699
|
const storeActionBtn = e.target.closest(`[data-store-${evtName}]`);
|
|
@@ -1,29 +1,29 @@
|
|
|
1
|
-
var DolphinModule=(()=>{var R=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var tt=Object.prototype.hasOwnProperty;var et=(A,t)=>{for(var e in t)R(A,e,{get:t[e],enumerable:!0})},nt=(A,t,e,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let s of Z(t))!tt.call(A,s)&&s!==e&&R(A,s,{get:()=>t[s],enumerable:!(n=Y(t,s))||n.enumerable});return A};var st=A=>nt(R({},"__esModule",{value:!0}),A);var rt={};et(rt,{DolphinClient:()=>C});var x=class{client;constructor(t){return this.client=t,this._createProxy([])}_createProxy(t){let e=t.join("/"),n=i=>this.request("GET",e,null,i);n.get=(i,a)=>typeof i=="string"?this.request("GET",i,null,a):this.request("GET",e,null,i),n.post=(i,a,l)=>typeof i=="string"?this.request("POST",i,a,l):this.request("POST",e,i,a),n.put=(i,a,l)=>typeof i=="string"?this.request("PUT",i,a,l):this.request("PUT",e,i,a),n.patch=(i,a,l)=>typeof i=="string"?this.request("PATCH",i,a,l):this.request("PATCH",e,i,a),n.del=(i,a)=>typeof i=="string"?this.request("DELETE",i,null,a):this.request("DELETE",e,null,i),n.request=(i,a,l,_)=>{let v=a?`${e}/${a.startsWith("/")?a.slice(1):a}`:e;return this.request(i,v,l,_)},n.requestDirect=(i,a,l,_)=>this.requestDirect(i,a,l,_),n._findCSRFToken=()=>this._findCSRFToken(),n._resolveBaseUrl=i=>this._resolveBaseUrl(i),n._normalizeValidationErrors=i=>this._normalizeValidationErrors(i);let s=["get","post","put","patch","del","request","requestDirect","_findCSRFToken","_resolveBaseUrl","_normalizeValidationErrors"];return new Proxy(n,{get:(i,a)=>typeof a=="string"&&!s.includes(a)?this._createProxy([...t,a]):i[a]})}_findCSRFToken(){if(typeof document>"u")return null;let t=["csrf-token","_csrf","xsrf-token","csrf_token"];for(let i of t){let a=document.querySelector(`meta[name="${i}"], meta[content][name$="${i}"]`);if(a){let l=a.getAttribute("content");if(l)return l}}let e=["_csrfToken","_token","_csrf","csrf_token"];for(let i of e){let a=document.querySelector(`input[type="hidden"][name="${i}"]`);if(a&&a.value)return a.value}let n=["csrfToken","XSRF-TOKEN","_csrf","csrf_token"];for(let i of n){let a=document.cookie.match(new RegExp("(^|;\\s*)"+i+"=([^;]*)"));if(a)return decodeURIComponent(a[2])}let s=typeof window<"u"&&window.wpApiSettings?.nonce;return s||null}_resolveBaseUrl(t){if(t.startsWith("http://")||t.startsWith("https://"))return t;let e=this.client.httpUrl;if(typeof document<"u"){let s=document.querySelector("base[href]");if(s){let i=s.getAttribute("href")||"";if(i&&i!=="/"){let a=i.endsWith("/")?i.slice(0,-1):i;e=`${this.client.httpUrl}${a.startsWith("/")?a:"/"+a}`}}else{let i=document.querySelector('meta[name="base-path"]');if(i){let a=i.getAttribute("content")||"";if(a&&a!=="/"){let l=a.endsWith("/")?a.slice(0,-1):a;e=`${this.client.httpUrl}${l.startsWith("/")?l:"/"+l}`}}}}let n=t.startsWith("/")?t:"/"+t;return`${e}${n}`}_normalizeValidationErrors(t){let e={};if(!t||typeof t!="object")return e;let n=t.errors||t.validationErrors||t;if(Array.isArray(n)){for(let s of n)if(s&&typeof s=="object"){let i=s.path||s.param||s.field||s.property,a=s.msg||s.message||s.error;i&&a&&(e[i]=Array.isArray(a)?a[0]:a)}return e}if(typeof n=="object"&&n!==null)for(let s in n){let i=n[s];if(i)if(Array.isArray(i))i.length>0&&(e[s]=String(i[0]));else if(typeof i=="object"){let a=Object.keys(i);if(a.length>0){let l=a[0];e[s]=String(i[l])}}else e[s]=String(i)}return e}async request(t,e,n=null,s={}){if(this.client.offline){let i=this.client.offline.isOnline,a=`${t.toUpperCase()}:${e}`;if(t.toUpperCase()==="GET")if(i)try{let l=await this.requestDirect(t,e,n,s);return await this.client.offline.setCache(a,l),l}catch(l){let _=await this.client.offline.getCache(a);if(_!=null)return _;throw l}else{let l=await this.client.offline.getCache(a);if(l!=null)return l;throw{status:503,data:{error:"Offline, no cache available"}}}else return i?this.requestDirect(t,e,n,s):(await this.client.offline.queueMutation(t,e,n),this.client._dispatch("offline:queued",{method:t,path:e,body:n}),{success:!0,offline:!0,message:"Mutation queued offline"})}return this.requestDirect(t,e,n,s)}async requestDirect(t,e,n=null,s={}){let i=s._isRetry===!0,a=t.toUpperCase(),l=n,_={"Content-Type":"application/json",...s.headers||{}};["PUT","PATCH","DELETE"].includes(a)&&(this.client.options.methodSpoofing||s.methodSpoofing)&&(_["X-HTTP-Method-Override"]=a,l instanceof FormData?l.append("_method",a):l&&typeof l=="object"?l={...l,_method:a}:l||(l={_method:a}),a="POST");let v=this._resolveBaseUrl(e);this.client.options.debug&&console.log("%c\u{1F680} [Dolphin API Request]:","color: #3b82f6; font-weight: bold;",t.toUpperCase(),e,l||"");let k=new AbortController,h=setTimeout(()=>k.abort(),this.client.options.timeout);if(this.client.accessToken&&(_.Authorization=`Bearer ${this.client.accessToken}`),["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let c=this._findCSRFToken();c&&(_["X-CSRF-Token"]=c,_["X-XSRF-TOKEN"]=c,_["X-CSRFToken"]=c,_["X-WP-Nonce"]=c,l&&typeof l=="object"&&!l._csrfToken&&!l._token&&!l._csrf&&(l={...l,_csrfToken:c,_token:c,_csrf:c}))}let d={...s};delete d._isRetry,delete d.methodSpoofing;try{let c=await fetch(v,{method:a,headers:_,signal:k.signal,...l?{body:JSON.stringify(l)}:{},...d});if(clearTimeout(h),c.status===401&&!i&&this.client.options.autoRefreshToken&&await this.client.auth._silentRefresh())return this.request(t,e,n,{...s,_isRetry:!0});let o=(c.headers.get("content-type")||"").includes("application/json")?await c.json():await c.text();if(!c.ok)throw{status:c.status,data:o};if(this.client.options.debug&&console.log("%c\u2705 [Dolphin API Success]:","color: #10b981; font-weight: bold;",t.toUpperCase(),e,o),o&&typeof o=="object"&&o.accessToken&&(this.client.setToken(o.accessToken),o.user&&(this.client.auth.user=o.user)),this.client.options.autoBroadcast&&["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let u=e.startsWith("/")?e.substring(1):e;this.client.publish(u,{method:t.toUpperCase(),payload:n,result:o})}return o}catch(c){if(clearTimeout(h),this.client.options.debug&&console.error("%c\u274C [Dolphin API Error]:","color: #ef4444; font-weight: bold;",t.toUpperCase(),e,c),c&&typeof c=="object"&&c.data){let r=this._normalizeValidationErrors(c.data);if(Object.keys(r).length>0)for(let o in r)this.client.publish(`errors/${o}`,r[o])}throw c.name==="AbortError"?{status:408,data:{error:"Request timed out"}}:c}}};var $=class{client;user;_refreshing;constructor(t){this.client=t,this.user=null,this._refreshing=!1}async login(t,e){let n=await this.client.api.post("/api/auth/login",{email:t,password:e});return n.accessToken&&(this.client.setToken(n.accessToken),this.user=n.user||null),n}async register(t){return this.client.api.post("/api/auth/register",t)}async me(){let t=await this.client.api.get("/api/auth/me");return t.success&&(this.user=t.data),t}async logout(){try{await this.client.api.post("/api/auth/logout")}catch{}this.client.setToken(null),this.user=null}async refresh(){return this._silentRefresh()}async _silentRefresh(){if(this._refreshing)return!1;this._refreshing=!0;try{let t=await this.client.api.post("/api/auth/refresh",null,{_isRetry:!0});return t.accessToken?(this.client.setToken(t.accessToken),!0):!1}catch{return this.client.setToken(null),!1}finally{this._refreshing=!1}}async verify2FA(t,e){let n={code:t,email:e||this.user?.email},s=await this.client.api.post("/api/auth/2fa/verify",n);return s.accessToken&&(this.client.setToken(s.accessToken),s.user&&(this.user=s.user)),s}async enable2FA(){return this.client.api.post("/api/auth/2fa/enable")}async disable2FA(t){return this.client.api.post("/api/auth/2fa/disable",{code:t})}async forgotPassword(t){return this.client.api.post("/api/auth/forgot-password",{email:t})}async resetPassword(t,e){return this.client.api.post("/api/auth/reset-password",{token:t,newPassword:e})}};var P=class{client;data;listeners;subscribed;_unsubscribers;constructor(t){return this.client=t,this.data=new Map,this.listeners=new Set,this.subscribed=new Set,this._unsubscribers=new Map,new Proxy(this,{get:(e,n)=>{if(n in e)return e[n];if(typeof n=="string")return this._getCollection(n)}})}_getCollection(t){if(!this.data.has(t)){let e={_rawItems:[],items:[],loading:!0,error:null,success:!1,_filter:null,_sort:null,where:n=>(e._filter=n,this._applyTransform(e),e),orderBy:(n,s="asc")=>(e._sort={key:n,direction:s},this._applyTransform(e),e),reset:()=>(e._filter=null,e._sort=null,this._applyTransform(e),e)};this.data.set(t,e),this._fetchAndSync(t)}return this.data.get(t)}async _fetchAndSync(t){let e=this.data.get(t);try{let n=await this.client.api.get(`/${t.toLowerCase()}`);if(e._rawItems=Array.isArray(n)?n:n.data||[],e.loading=!1,e.success=!0,e.error=null,this._applyTransform(e),!this.subscribed.has(t)){let s=()=>this.client.unsubscribe(`db:sync/${t.toLowerCase()}`,i),i=a=>{this._handleRemoteUpdate(t,a)};this.client.subscribe(`db:sync/${t.toLowerCase()}`,i),this._unsubscribers.set(t,s),this.subscribed.add(t)}}catch(n){e.loading=!1,e.success=!1,e.error=n.data?.error||n.message||"Fetch failed",this._notify()}}_applyTransform(t){let e=[...t._rawItems];if(t._filter&&(e=e.filter(t._filter)),t._sort){let{key:n,direction:s}=t._sort;e.sort((i,a)=>i[n]===a[n]?0:(i[n]>a[n]?1:-1)*(s==="asc"?1:-1))}t.items=e,this._notify()}_handleRemoteUpdate(t,e){let n=this.data.get(t);if(!n)return;let{type:s,data:i}=e,a=n._rawItems;s==="create"?a=[...a,i]:s==="update"?a=a.map(l=>l.id===i.id||l._id===i._id?{...l,...i}:l):s==="delete"&&(a=a.filter(l=>!(i.id!=null&&l.id===i.id||i._id!=null&&l._id===i._id))),n._rawItems=a,this._applyTransform(n)}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}getSnapshot(t){return this.data.get(t)||{items:[],loading:!1,error:null,success:!1}}_notify(){this.listeners.forEach(t=>t())}destroy(){this._unsubscribers.forEach(t=>{try{t()}catch{}}),this._unsubscribers.clear(),this.subscribed.clear(),this.listeners.clear(),this.data.clear()}};var C=class{host;httpUrl;deviceId;options;socket;storage;accessToken;api;auth;store;handlers;signalHandlers;fileHandlers;_offlineQueue;reconnectAttempts;_reconnectTimer;_attachedListeners;constructor(t="",e="",n={}){!t&&typeof window<"u"&&(t=window.location.host);let s="http:";t.startsWith("https://")?s="https:":t.startsWith("http://")?s="http:":typeof window<"u"&&(s=window.location.protocol),this.host=(t||"localhost").replace(/\/$/,"").replace(/^https?:\/\//,""),this.httpUrl=`${s}//${this.host}`,this.deviceId=e||(typeof crypto<"u"&&typeof crypto.randomUUID=="function"?"web_"+crypto.randomUUID().replace(/-/g,"").slice(0,8):"web_"+Math.random().toString(36).slice(2,10)),this.options={timeout:15e3,chunkSize:65536,maxReconnect:5,autoRefreshToken:!0,debug:!1,methodSpoofing:!1,routerViewport:"main, #viewport, body",routerTransitions:!0,...n},this.socket=null,this.storage=typeof localStorage<"u"?localStorage:{getItem:()=>null,setItem:()=>{},removeItem:()=>{}},this.accessToken=this.storage.getItem("dolphin_token"),this.api=new x(this),this.auth=new $(this),this.store=new P(this),this.handlers=new Map,this.signalHandlers=new Set,this.fileHandlers=new Set,this._offlineQueue=[],this.reconnectAttempts=0,this._reconnectTimer=null,this._attachedListeners=[],typeof window<"u"&&typeof this._initDOMBinding=="function"&&this._initDOMBinding(),typeof this._initOffline=="function"&&this._initOffline(),typeof this._initA11y=="function"&&this._initA11y(),typeof this._initI18n=="function"&&this._initI18n(),typeof this._initDragDrop=="function"&&this._initDragDrop(),typeof this._initCollab=="function"&&this._initCollab()}setToken(t){this.accessToken=t,t?this.storage.setItem("dolphin_token",t):this.storage.removeItem("dolphin_token")}async connect(){return this.socket&&(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)?Promise.resolve():new Promise((t,e)=>{let s=`${this.httpUrl.startsWith("https")?"wss:":"ws:"}//${this.host}/realtime?deviceId=${this.deviceId}`;console.log(`[Dolphin] Connecting to ${s}...`),this.socket=new WebSocket(s),this.socket.onopen=()=>{console.log(`[Dolphin] Connected as "${this.deviceId}" \u{1F42C}`),this.reconnectAttempts=0,this._flushOfflineQueue(),t()},this.socket.onmessage=i=>this._handleMessage(i.data),this.socket.onclose=()=>{console.warn("[Dolphin] Connection closed"),this._maybeReconnect()},this.socket.onerror=i=>{console.error("[Dolphin] WebSocket error:",i),e(i)}})}disconnect(){this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this.socket&&(this.socket.onclose=null,this.socket.close(),this.socket=null),typeof this._collabCleanup=="function"&&this._collabCleanup(),this.cleanupDomListeners()}_handleMessage(t){try{let e=JSON.parse(t);this.options.debug&&console.log("%c\u{1F4E5} [Dolphin WS Incoming]:","color: #eab308; font-weight: bold;",e),e.type&&e.from&&(e.to===this.deviceId||e.to==="all")&&(e.msgId&&e.type!=="ACK"&&this._sendAck(e.from,e.msgId),this.signalHandlers.forEach(n=>n(e))),e.type==="FILE_AVAILABLE"&&this.fileHandlers.forEach(n=>n(e)),e.type==="FILE_CHUNK"&&(this.saveFileProgress(e.fileId,e.chunkIndex),this._dispatch("file:chunk",e),this._dispatch(`file:chunk/${e.fileId}`,e)),e.type==="FILE_UPLOAD_ACK"&&this._dispatch(`file:upload:ack/${e.fileId}`,e),e.type==="PULL_RESPONSE"&&(this._dispatch("pull:response",e.payload,e.topic),this._dispatch(`pull:response/${e.topic}`,e.payload,e.topic)),e.topic&&e.payload!==void 0&&this.handlers.forEach((n,s)=>{this._matchTopic(s,e.topic)&&n.forEach(i=>i(e.payload,e.topic))})}catch{this._dispatch("raw",t)}}_dispatch(t,e,n){let s=this.handlers.get(t);s&&s.forEach(i=>i(e,n||t))}_sendRaw(t){this.options.debug&&console.log("%c\u{1F4E4} [Dolphin WS Outgoing]:","color: #8b5cf6; font-weight: bold;",t);let e=typeof t=="string"?t:JSON.stringify(t);this.socket&&this.socket.readyState===WebSocket.OPEN?this.socket.send(e):this._offlineQueue.length<100&&this._offlineQueue.push(e)}_flushOfflineQueue(){for(;this._offlineQueue.length>0;){let t=this._offlineQueue.shift();this.socket&&this.socket.readyState===WebSocket.OPEN&&this.socket.send(t)}}_sendAck(t,e){this._sendRaw({type:"ACK",from:this.deviceId,to:t,data:{ackId:e},timestamp:Date.now()})}_matchTopic(t,e){if(t===e||t==="#")return!0;let n=t.split("/"),s=e.split("/");if(n.length!==s.length&&!t.includes("#"))return!1;for(let i=0;i<n.length;i++){if(n[i]==="#")return!0;if(n[i]!=="+"&&n[i]!==s[i])return!1}return n.length===s.length}_maybeReconnect(){if(this.reconnectAttempts<this.options.maxReconnect){this.reconnectAttempts++;let t=Math.pow(2,this.reconnectAttempts)*1e3;console.log(`[Dolphin] Reconnecting in ${t/1e3}s (attempt ${this.reconnectAttempts})...`),this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this.connect().catch(()=>{})},t)}else console.error("[Dolphin] Max reconnect attempts reached.")}subscribe(t,e){this.handlers.has(t)||(this.handlers.set(t,new Set),this._sendRaw({type:"sub",topic:t})),this.handlers.get(t).add(e)}unsubscribe(t,e){if(this.handlers.has(t)){let n=this.handlers.get(t);n.delete(e),n.size===0&&(this.handlers.delete(t),this._sendRaw({type:"unsub",topic:t}))}}publish(t,e){this._sendRaw({topic:t,payload:e})}pubPush(t,e){this._sendRaw({type:"pub",topic:t,payload:e})}subPull(t,e=10){this._sendRaw({type:"PULL_REQUEST",topic:t,count:e})}async pubFile(t,e,n="",s){let i;e instanceof Blob?i=await e.arrayBuffer():e instanceof ArrayBuffer?i=e:i=e.buffer||e;let a=new Uint8Array(i),l=this.options.chunkSize,_=Math.ceil(a.length/l);this._sendRaw({type:"FILE_UPLOAD_START",fileId:t,name:n,size:a.length,totalChunks:_,chunkSize:l});for(let v=0;v<_;v++){let k=a.slice(v*l,(v+1)*l),h=this._uint8ToBase64(k);this._sendRaw({type:"FILE_UPLOAD_CHUNK",fileId:t,chunkIndex:v,totalChunks:_,data:h}),s&&s(Math.round((v+1)/_*100)),v%10===0&&await new Promise(d=>setTimeout(d,0))}this._sendRaw({type:"FILE_UPLOAD_DONE",fileId:t})}_uint8ToBase64(t){let e="";for(let n=0;n<t.length;n++)e+=String.fromCharCode(t[n]);return typeof btoa<"u"?btoa(e):Buffer.from(e,"binary").toString("base64")}subFile(t,e=0){this._sendRaw({type:"FILE_REQUEST",fileId:t,startChunk:e})}resumeFile(t){let e=parseInt(this.storage.getItem(`dolphin_file_${t}`)||"-1");this.subFile(t,e+1)}saveFileProgress(t,e){this.storage.setItem(`dolphin_file_${t}`,e.toString())}onSignal(t){this.signalHandlers.add(t)}offSignal(t){this.signalHandlers.delete(t)}onFileAvailable(t){this.fileHandlers.add(t)}offFileAvailable(t){this.fileHandlers.delete(t)}addDomListener(t,e,n){t&&(t.addEventListener(e,n),this._attachedListeners=this._attachedListeners||[],this._attachedListeners.push({target:t,event:e,cb:n}))}cleanupDomListeners(){this._attachedListeners&&(this._attachedListeners.forEach(({target:t,event:e,cb:n})=>{try{t.removeEventListener(e,n)}catch{}}),this._attachedListeners=[])}};function U(A){let t=new Map;function e(h){return h.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function n(h){let d=h.getAttribute("data-rt-template");if(!d)return null;if(typeof document<"u"&&!d.includes("<"))try{let c=document.querySelector(d);if(c)return c.innerHTML}catch{}return d}function s(h,d){if(!h.includes("{#if")&&!h.includes("{#each")){let c=h;for(let r in d){let o=r.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");c=c.replace(new RegExp(`\\{\\{${o}\\}\\}`,"g"),d[r]!==void 0&&d[r]!==null?d[r]:"")}return c}try{let c=p=>p.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t"),r=`let out = "";
|
|
2
|
-
`,o=0,
|
|
3
|
-
`);let
|
|
4
|
-
`}else if(
|
|
5
|
-
`}else if(
|
|
6
|
-
`}else if(
|
|
7
|
-
`;else if(
|
|
8
|
-
`;else if(
|
|
9
|
-
`,
|
|
10
|
-
`),
|
|
11
|
-
`}else if(
|
|
12
|
-
`),
|
|
1
|
+
var DolphinModule=(()=>{var U=Object.defineProperty;var G=Object.getOwnPropertyDescriptor;var Z=Object.getOwnPropertyNames;var tt=Object.prototype.hasOwnProperty;var et=(A,t)=>{for(var e in t)U(A,e,{get:t[e],enumerable:!0})},nt=(A,t,e,s)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of Z(t))!tt.call(A,i)&&i!==e&&U(A,i,{get:()=>t[i],enumerable:!(s=G(t,i))||s.enumerable});return A};var st=A=>nt(U({},"__esModule",{value:!0}),A);var rt={};et(rt,{DolphinClient:()=>C});var N=class{client;constructor(t){return this.client=t,this._createProxy([])}_createProxy(t){let e=t.join("/"),s=r=>this.request("GET",e,null,r);s.get=(r,a)=>typeof r=="string"?this.request("GET",r,null,a):this.request("GET",e,null,r),s.post=(r,a,d)=>typeof r=="string"?this.request("POST",r,a,d):this.request("POST",e,r,a),s.put=(r,a,d)=>typeof r=="string"?this.request("PUT",r,a,d):this.request("PUT",e,r,a),s.patch=(r,a,d)=>typeof r=="string"?this.request("PATCH",r,a,d):this.request("PATCH",e,r,a),s.del=(r,a)=>typeof r=="string"?this.request("DELETE",r,null,a):this.request("DELETE",e,null,r),s.request=(r,a,d,E)=>{let S=a?e?`${e}/${a.startsWith("/")?a.slice(1):a}`:a:e;return this.request(r,S,d,E)},s.requestDirect=(r,a,d,E)=>this.requestDirect(r,a,d,E),s._findCSRFToken=()=>this._findCSRFToken(),s._resolveBaseUrl=r=>this._resolveBaseUrl(r),s._normalizeValidationErrors=r=>this._normalizeValidationErrors(r);let i=["get","post","put","patch","del","request","requestDirect","_findCSRFToken","_resolveBaseUrl","_normalizeValidationErrors"];return new Proxy(s,{get:(r,a)=>typeof a=="string"&&!i.includes(a)?this._createProxy([...t,a]):r[a]})}_findCSRFToken(){if(typeof document>"u")return null;let t=["csrf-token","_csrf","xsrf-token","csrf_token"];for(let r of t){let a=document.querySelector(`meta[name="${r}"], meta[content][name$="${r}"]`);if(a){let d=a.getAttribute("content");if(d)return d}}let e=["_csrfToken","_token","_csrf","csrf_token"];for(let r of e){let a=document.querySelector(`input[type="hidden"][name="${r}"]`);if(a&&a.value)return a.value}let s=["csrfToken","XSRF-TOKEN","_csrf","csrf_token"];for(let r of s){let a=document.cookie.match(new RegExp("(^|;\\s*)"+r+"=([^;]*)"));if(a)return decodeURIComponent(a[2])}let i=typeof window<"u"&&window.wpApiSettings?.nonce;return i||null}_resolveBaseUrl(t){if(t.startsWith("http://")||t.startsWith("https://"))return t;let e=this.client.httpUrl;if(typeof document<"u"){let i=document.querySelector("base[href]");if(i){let r=i.getAttribute("href")||"";if(r&&r!=="/"){let a=r.endsWith("/")?r.slice(0,-1):r;e=`${this.client.httpUrl}${a.startsWith("/")?a:"/"+a}`}}else{let r=document.querySelector('meta[name="base-path"]');if(r){let a=r.getAttribute("content")||"";if(a&&a!=="/"){let d=a.endsWith("/")?a.slice(0,-1):a;e=`${this.client.httpUrl}${d.startsWith("/")?d:"/"+d}`}}}}let s=t.startsWith("/")?t:"/"+t;return`${e}${s}`}_normalizeValidationErrors(t){let e={};if(!t||typeof t!="object")return e;let s=t.errors||t.validationErrors||t;if(Array.isArray(s)){for(let i of s)if(i&&typeof i=="object"){let r=i.path||i.param||i.field||i.property,a=i.msg||i.message||i.error;r&&a&&(e[r]=Array.isArray(a)?a[0]:a)}return e}if(typeof s=="object"&&s!==null)for(let i in s){let r=s[i];if(r)if(Array.isArray(r))r.length>0&&(e[i]=String(r[0]));else if(typeof r=="object"){let a=Object.keys(r);if(a.length>0){let d=a[0];e[i]=String(r[d])}}else e[i]=String(r)}return e}async request(t,e,s=null,i={}){if(this.client.offline){let r=this.client.offline.isOnline,a=`${t.toUpperCase()}:${e}`;if(t.toUpperCase()==="GET")if(r)try{let d=await this.requestDirect(t,e,s,i);return await this.client.offline.setCache(a,d),d}catch(d){let E=await this.client.offline.getCache(a);if(E!=null)return E;throw d}else{let d=await this.client.offline.getCache(a);if(d!=null)return d;throw{status:503,data:{error:"Offline, no cache available"}}}else return r?this.requestDirect(t,e,s,i):(await this.client.offline.queueMutation(t,e,s),this.client._dispatch("offline:queued",{method:t,path:e,body:s}),{success:!0,offline:!0,message:"Mutation queued offline"})}return this.requestDirect(t,e,s,i)}async requestDirect(t,e,s=null,i={}){let r=i._isRetry===!0,a=t.toUpperCase(),d=s,S={...!["GET","HEAD"].includes(a)?{"Content-Type":"application/json"}:{},...i.headers||{}};["PUT","PATCH","DELETE"].includes(a)&&(this.client.options.methodSpoofing||i.methodSpoofing)&&(S["X-HTTP-Method-Override"]=a,d instanceof FormData?d.append("_method",a):d&&typeof d=="object"?d={...d,_method:a}:d||(d={_method:a}),a="POST");let k=this._resolveBaseUrl(e);this.client.options.debug&&console.log("%c\u{1F680} [Dolphin API Request]:","color: #3b82f6; font-weight: bold;",t.toUpperCase(),e,d||"");let f=new AbortController,u=setTimeout(()=>f.abort(),this.client.options.timeout);if(this.client.accessToken&&(S.Authorization=`Bearer ${this.client.accessToken}`),["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let n=this._findCSRFToken();n&&(S["X-CSRF-Token"]=n,S["X-XSRF-TOKEN"]=n,S["X-CSRFToken"]=n,S["X-WP-Nonce"]=n,d&&typeof d=="object"&&!d._csrfToken&&!d._token&&!d._csrf&&(d={...d,_csrfToken:n,_token:n,_csrf:n}))}let l={...i};delete l._isRetry,delete l.methodSpoofing;try{let n=await fetch(k,{method:a,headers:S,signal:f.signal,...d?{body:JSON.stringify(d)}:{},...l});if(clearTimeout(u),n.status===401&&!r&&this.client.options.autoRefreshToken&&await this.client.auth._silentRefresh())return this.request(t,e,s,{...i,_isRetry:!0});let c=(n.headers.get("content-type")||"").includes("application/json")?await n.json():await n.text();if(!n.ok)throw{status:n.status,data:c};if(this.client.options.debug&&console.log("%c\u2705 [Dolphin API Success]:","color: #10b981; font-weight: bold;",t.toUpperCase(),e,c),c&&typeof c=="object"&&c.accessToken&&(this.client.setToken(c.accessToken),c.user&&(this.client.auth.user=c.user)),this.client.options.autoBroadcast&&["POST","PUT","PATCH","DELETE"].includes(t.toUpperCase())){let y=e.startsWith("/")?e.substring(1):e;this.client.publish(y,{method:t.toUpperCase(),payload:s,result:c})}return c}catch(n){if(clearTimeout(u),this.client.options.debug&&console.error("%c\u274C [Dolphin API Error]:","color: #ef4444; font-weight: bold;",t.toUpperCase(),e,n),n&&typeof n=="object"&&n.data){let o=this._normalizeValidationErrors(n.data);if(Object.keys(o).length>0)for(let c in o)this.client.publish(`errors/${c}`,o[c])}throw n.name==="AbortError"?{status:408,data:{error:"Request timed out"}}:n}}};var q=class{client;user;_refreshing;constructor(t){this.client=t,this.user=null,this._refreshing=!1}async login(t,e){let s=await this.client.api.post("/api/auth/login",{email:t,password:e});return s.accessToken&&(this.client.setToken(s.accessToken),this.user=s.user||null),s}async register(t){return this.client.api.post("/api/auth/register",t)}async me(){let t=await this.client.api.get("/api/auth/me");return t.success&&(this.user=t.data),t}async logout(){try{await this.client.api.post("/api/auth/logout")}catch{}this.client.setToken(null),this.user=null}async refresh(){return this._silentRefresh()}async _silentRefresh(){if(this._refreshing)return!1;this._refreshing=!0;try{let t=await this.client.api.post("/api/auth/refresh",null,{_isRetry:!0});return t.accessToken?(this.client.setToken(t.accessToken),!0):!1}catch{return this.client.setToken(null),!1}finally{this._refreshing=!1}}async verify2FA(t,e){let s={code:t,email:e||this.user?.email},i=await this.client.api.post("/api/auth/2fa/verify",s);return i.accessToken&&(this.client.setToken(i.accessToken),i.user&&(this.user=i.user)),i}async enable2FA(){return this.client.api.post("/api/auth/2fa/enable")}async disable2FA(t){return this.client.api.post("/api/auth/2fa/disable",{code:t})}async forgotPassword(t){return this.client.api.post("/api/auth/forgot-password",{email:t})}async resetPassword(t,e){return this.client.api.post("/api/auth/reset-password",{token:t,newPassword:e})}};var O=class{client;data;listeners;subscribed;_unsubscribers;constructor(t){return this.client=t,this.data=new Map,this.listeners=new Set,this.subscribed=new Set,this._unsubscribers=new Map,new Proxy(this,{get:(e,s)=>{if(s in e)return e[s];if(typeof s=="string")return this._getCollection(s)}})}_getCollection(t){if(!this.data.has(t)){let e={_rawItems:[],items:[],loading:!0,error:null,success:!1,_filter:null,_sort:null,where:s=>(e._filter=s,this._applyTransform(e),e),orderBy:(s,i="asc")=>(e._sort={key:s,direction:i},this._applyTransform(e),e),reset:()=>(e._filter=null,e._sort=null,this._applyTransform(e),e)};this.data.set(t,e),this._fetchAndSync(t)}return this.data.get(t)}async _fetchAndSync(t){let e=this.data.get(t);try{let s=await this.client.api.get(`/${t.toLowerCase()}`);if(e._rawItems=Array.isArray(s)?s:s.data||[],e.loading=!1,e.success=!0,e.error=null,this._applyTransform(e),!this.subscribed.has(t)){let i=()=>this.client.unsubscribe(`db:sync/${t.toLowerCase()}`,r),r=a=>{this._handleRemoteUpdate(t,a)};this.client.subscribe(`db:sync/${t.toLowerCase()}`,r),this._unsubscribers.set(t,i),this.subscribed.add(t)}}catch(s){e.loading=!1,e.success=!1,e.error=s.data?.error||s.message||"Fetch failed",this._notify()}}_applyTransform(t){let e=[...t._rawItems];if(t._filter&&(e=e.filter(t._filter)),t._sort){let{key:s,direction:i}=t._sort;e.sort((r,a)=>r[s]===a[s]?0:(r[s]>a[s]?1:-1)*(i==="asc"?1:-1))}t.items=e,this._notify()}_handleRemoteUpdate(t,e){let s=this.data.get(t);if(!s)return;let{type:i,data:r}=e,a=s._rawItems;i==="create"?a=[...a,r]:i==="update"?a=a.map(d=>d.id===r.id||d._id===r._id?{...d,...r}:d):i==="delete"&&(a=a.filter(d=>!(r.id!=null&&d.id===r.id||r._id!=null&&d._id===r._id))),s._rawItems=a,this._applyTransform(s)}subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}getSnapshot(t){return this.data.get(t)||{items:[],loading:!1,error:null,success:!1}}_notify(){this.listeners.forEach(t=>t())}destroy(){this._unsubscribers.forEach(t=>{try{t()}catch{}}),this._unsubscribers.clear(),this.subscribed.clear(),this.listeners.clear(),this.data.clear()}};var C=class{host;httpUrl;deviceId;options;socket;storage;accessToken;api;auth;store;handlers;signalHandlers;fileHandlers;_offlineQueue;reconnectAttempts;_reconnectTimer;_attachedListeners;constructor(t="",e="",s={}){!t&&typeof window<"u"&&(t=window.location.host);let i="http:";t.startsWith("https://")?i="https:":t.startsWith("http://")?i="http:":typeof window<"u"&&(i=window.location.protocol),this.host=(t||"localhost").replace(/\/$/,"").replace(/^https?:\/\//,""),this.httpUrl=`${i}//${this.host}`,this.deviceId=e||(typeof crypto<"u"&&typeof crypto.randomUUID=="function"?"web_"+crypto.randomUUID().replace(/-/g,"").slice(0,8):"web_"+Math.random().toString(36).slice(2,10)),this.options={timeout:15e3,chunkSize:65536,maxReconnect:5,autoRefreshToken:!0,debug:!1,methodSpoofing:!1,routerViewport:"main, #viewport, body",routerTransitions:!0,...s},this.socket=null,this.storage=typeof localStorage<"u"?localStorage:{getItem:()=>null,setItem:()=>{},removeItem:()=>{}},this.accessToken=this.storage.getItem("dolphin_token"),this.api=new N(this),this.auth=new q(this),this.store=new O(this),this.handlers=new Map,this.signalHandlers=new Set,this.fileHandlers=new Set,this._offlineQueue=[],this.reconnectAttempts=0,this._reconnectTimer=null,this._attachedListeners=[],typeof window<"u"&&typeof this._initDOMBinding=="function"&&this._initDOMBinding(),typeof this._initOffline=="function"&&this._initOffline(),typeof this._initA11y=="function"&&this._initA11y(),typeof this._initI18n=="function"&&this._initI18n(),typeof this._initDragDrop=="function"&&this._initDragDrop(),typeof this._initCollab=="function"&&this._initCollab()}setToken(t){this.accessToken=t,t?this.storage.setItem("dolphin_token",t):this.storage.removeItem("dolphin_token")}async connect(){return this.socket&&(this.socket.readyState===WebSocket.OPEN||this.socket.readyState===WebSocket.CONNECTING)?Promise.resolve():new Promise((t,e)=>{let i=`${this.httpUrl.startsWith("https")?"wss:":"ws:"}//${this.host}/realtime?deviceId=${this.deviceId}`;console.log(`[Dolphin] Connecting to ${i}...`),this.socket=new WebSocket(i),this.socket.onopen=()=>{console.log(`[Dolphin] Connected as "${this.deviceId}" \u{1F42C}`),this.reconnectAttempts=0,this._flushOfflineQueue(),t()},this.socket.onmessage=r=>this._handleMessage(r.data),this.socket.onclose=()=>{console.warn("[Dolphin] Connection closed"),this._maybeReconnect()},this.socket.onerror=r=>{console.error("[Dolphin] WebSocket error:",r),e(r)}})}disconnect(){this._reconnectTimer!==null&&(clearTimeout(this._reconnectTimer),this._reconnectTimer=null),this.socket&&(this.socket.onclose=null,this.socket.close(),this.socket=null),typeof this._collabCleanup=="function"&&this._collabCleanup(),this.cleanupDomListeners()}_handleMessage(t){try{let e=JSON.parse(t);this.options.debug&&console.log("%c\u{1F4E5} [Dolphin WS Incoming]:","color: #eab308; font-weight: bold;",e),e.type&&e.from&&(e.to===this.deviceId||e.to==="all")&&(e.msgId&&e.type!=="ACK"&&this._sendAck(e.from,e.msgId),this.signalHandlers.forEach(s=>s(e))),e.type==="FILE_AVAILABLE"&&this.fileHandlers.forEach(s=>s(e)),e.type==="FILE_CHUNK"&&(this.saveFileProgress(e.fileId,e.chunkIndex),this._dispatch("file:chunk",e),this._dispatch(`file:chunk/${e.fileId}`,e)),e.type==="FILE_UPLOAD_ACK"&&this._dispatch(`file:upload:ack/${e.fileId}`,e),e.type==="PULL_RESPONSE"&&(this._dispatch("pull:response",e.payload,e.topic),this._dispatch(`pull:response/${e.topic}`,e.payload,e.topic)),e.topic&&e.payload!==void 0&&this.handlers.forEach((s,i)=>{this._matchTopic(i,e.topic)&&s.forEach(r=>r(e.payload,e.topic))})}catch{this._dispatch("raw",t)}}_dispatch(t,e,s){let i=this.handlers.get(t);i&&i.forEach(r=>r(e,s||t))}_sendRaw(t){this.options.debug&&console.log("%c\u{1F4E4} [Dolphin WS Outgoing]:","color: #8b5cf6; font-weight: bold;",t);let e=typeof t=="string"?t:JSON.stringify(t);this.socket&&this.socket.readyState===WebSocket.OPEN?this.socket.send(e):this._offlineQueue.length<100&&this._offlineQueue.push(e)}_flushOfflineQueue(){for(;this._offlineQueue.length>0;){let t=this._offlineQueue.shift();this.socket&&this.socket.readyState===WebSocket.OPEN&&this.socket.send(t)}}_sendAck(t,e){this._sendRaw({type:"ACK",from:this.deviceId,to:t,data:{ackId:e},timestamp:Date.now()})}_matchTopic(t,e){if(t===e||t==="#")return!0;let s=t.split("/"),i=e.split("/");if(s.length!==i.length&&!t.includes("#"))return!1;for(let r=0;r<s.length;r++){if(s[r]==="#")return!0;if(s[r]!=="+"&&s[r]!==i[r])return!1}return s.length===i.length}_maybeReconnect(){if(this.reconnectAttempts<this.options.maxReconnect){this.reconnectAttempts++;let t=Math.pow(2,this.reconnectAttempts)*1e3;console.log(`[Dolphin] Reconnecting in ${t/1e3}s (attempt ${this.reconnectAttempts})...`),this._reconnectTimer=setTimeout(()=>{this._reconnectTimer=null,this.connect().catch(()=>{})},t)}else console.error("[Dolphin] Max reconnect attempts reached.")}subscribe(t,e){this.handlers.has(t)||(this.handlers.set(t,new Set),this._sendRaw({type:"sub",topic:t})),this.handlers.get(t).add(e)}unsubscribe(t,e){if(this.handlers.has(t)){let s=this.handlers.get(t);s.delete(e),s.size===0&&(this.handlers.delete(t),this._sendRaw({type:"unsub",topic:t}))}}publish(t,e){this._sendRaw({topic:t,payload:e})}pubPush(t,e){this._sendRaw({type:"pub",topic:t,payload:e})}subPull(t,e=10){this._sendRaw({type:"PULL_REQUEST",topic:t,count:e})}async pubFile(t,e,s="",i){let r;e instanceof Blob?r=await e.arrayBuffer():e instanceof ArrayBuffer?r=e:r=e.buffer||e;let a=new Uint8Array(r),d=this.options.chunkSize,E=Math.ceil(a.length/d);this._sendRaw({type:"FILE_UPLOAD_START",fileId:t,name:s,size:a.length,totalChunks:E,chunkSize:d});for(let S=0;S<E;S++){let k=a.slice(S*d,(S+1)*d),f=this._uint8ToBase64(k);this._sendRaw({type:"FILE_UPLOAD_CHUNK",fileId:t,chunkIndex:S,totalChunks:E,data:f}),i&&i(Math.round((S+1)/E*100)),S%10===0&&await new Promise(u=>setTimeout(u,0))}this._sendRaw({type:"FILE_UPLOAD_DONE",fileId:t})}_uint8ToBase64(t){let e="";for(let s=0;s<t.length;s++)e+=String.fromCharCode(t[s]);return typeof btoa<"u"?btoa(e):Buffer.from(e,"binary").toString("base64")}subFile(t,e=0){this._sendRaw({type:"FILE_REQUEST",fileId:t,startChunk:e})}resumeFile(t){let e=parseInt(this.storage.getItem(`dolphin_file_${t}`)||"-1");this.subFile(t,e+1)}saveFileProgress(t,e){this.storage.setItem(`dolphin_file_${t}`,e.toString())}onSignal(t){this.signalHandlers.add(t)}offSignal(t){this.signalHandlers.delete(t)}onFileAvailable(t){this.fileHandlers.add(t)}offFileAvailable(t){this.fileHandlers.delete(t)}addDomListener(t,e,s){t&&(t.addEventListener(e,s),this._attachedListeners=this._attachedListeners||[],this._attachedListeners.push({target:t,event:e,cb:s}))}cleanupDomListeners(){this._attachedListeners&&(this._attachedListeners.forEach(({target:t,event:e,cb:s})=>{try{t.removeEventListener(e,s)}catch{}}),this._attachedListeners=[])}};function B(A){let t=new Map;function e(f){return f.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function s(f){let u=f.getAttribute("data-rt-template");if(!u)return null;if(typeof document<"u"&&!u.includes("<"))try{let l=document.querySelector(u);if(l)return l.innerHTML}catch{}return u}function i(f,u){if(!f.includes("{#if")&&!f.includes("{#each")){let l=f;for(let n in u){let o=n.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");l=l.replace(new RegExp(`\\{\\{${o}\\}\\}`,"g"),u[n]!==void 0&&u[n]!==null?u[n]:"")}return l}try{let l=p=>p.replace(/\\/g,"\\\\").replace(/"/g,'\\"').replace(/\n/g,"\\n").replace(/\r/g,"\\r").replace(/\t/g,"\\t"),n=`let out = "";
|
|
2
|
+
`,o=0,c=/(\{\{([\s\S]*?)\}\}|\{#if\s+([\s\S]*?)\}|\{:else\s+if\s+([\s\S]*?)\}|\{:else\}|\{\/if\}|\{#each\s+([\s\S]*?)\s+as\s+([a-zA-Z_$][a-zA-Z0-9_$]*)(?:\s*,\s*([a-zA-Z_$][a-zA-Z0-9_$]*))?\}|\{\/each\}|\{([^{}]+?)\})/g,y=[],h;for(;(h=c.exec(f))!==null;){let p=f.slice(o,h.index);p&&(n+=`out += "${l(p)}";
|
|
3
|
+
`);let b=h[0];if(b.startsWith("{{")){let T=h[2];n+=`out += (${T} !== undefined && ${T} !== null ? ${T} : "");
|
|
4
|
+
`}else if(b.startsWith("{#if")){let T=h[3];n+=`if (${T}) {
|
|
5
|
+
`}else if(b.startsWith("{:else if")){let T=h[4];n+=`} else if (${T}) {
|
|
6
|
+
`}else if(b.startsWith("{:else}"))n+=`} else {
|
|
7
|
+
`;else if(b.startsWith("{/if}"))n+=`}
|
|
8
|
+
`;else if(b.startsWith("{#each")){let T=h[5],x=h[6],v=h[7];y.push({indexVar:v}),n+=`if (typeof ${T} !== "undefined" && ${T} !== null && Array.isArray(${T})) {
|
|
9
|
+
`,v&&(n+=` let ${v} = 0;
|
|
10
|
+
`),n+=` for (let ${x} of ${T}) {
|
|
11
|
+
`}else if(b.startsWith("{/each}")){let T=y.pop();T&&T.indexVar&&(n+=` ${T.indexVar}++;
|
|
12
|
+
`),n+=` }
|
|
13
13
|
}
|
|
14
|
-
`}else if(
|
|
15
|
-
`)}o=
|
|
16
|
-
`),
|
|
14
|
+
`}else if(b.startsWith("{")){let T=h[8];T&&(n+=`out += (${T} !== undefined && ${T} !== null ? ${T} : "");
|
|
15
|
+
`)}o=c.lastIndex}let m=f.slice(o);m&&(n+=`out += "${l(m)}";
|
|
16
|
+
`),n+=`return out;
|
|
17
17
|
`;let w=`
|
|
18
18
|
with (context) {
|
|
19
19
|
try {
|
|
20
|
-
${
|
|
20
|
+
${n}
|
|
21
21
|
} catch (innerErr) {
|
|
22
22
|
console.warn('[Dolphin Template Eval Warning]:', innerErr);
|
|
23
23
|
return '';
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
|
-
`,S=d;return typeof Proxy<"u"&&d!==null&&typeof d=="object"&&(S=new Proxy(d,{has(p,y){return typeof y!="symbol"},get(p,y){if(y!==Symbol.unscopables){if(y in p)return p[y];if(typeof globalThis<"u"&&y in globalThis)return globalThis[y];if(typeof window<"u"&&y in window)return window[y]}}})),new Function("context",w)(S)}catch(c){console.error("[Dolphin Template Compiler Error]:",c);let r=h;for(let o in d){let u=o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");r=r.replace(new RegExp(`\\{\\{${u}\\}\\}`,"g"),d[o]!==void 0&&d[o]!==null?d[o]:"")}return r}}function i(h){if(typeof document>"u")return h;try{let r=new DOMParser().parseFromString(h,"text/html").body,o=u=>{let b=u.tagName.toLowerCase();if(["script","iframe","object","embed","link","style","meta","applet","svg"].includes(b)){u.parentNode?.removeChild(u);return}let f=u.attributes;for(let m=f.length-1;m>=0;m--){let w=f[m].name.toLowerCase(),S=f[m].value.toLowerCase();(w.startsWith("on")||["src","href","data"].includes(w)&&(S.includes("javascript:")||S.includes("data:text/html")))&&u.removeAttribute(f[m].name)}Array.from(u.children).forEach(o)};return Array.from(r.children).forEach(o),r.innerHTML}catch{return h}}function a(h,d){if(h.nodeType!==d.nodeType){h.parentNode?.replaceChild(d.cloneNode(!0),h);return}if(h.nodeType===Node.TEXT_NODE){h.textContent!==d.textContent&&(h.textContent=d.textContent);return}if(h.nodeType===Node.ELEMENT_NODE){let c=h,r=d;if(c.tagName!==r.tagName){c.parentNode?.replaceChild(r.cloneNode(!0),c);return}let o=c.attributes,u=r.attributes;for(let g=o.length-1;g>=0;g--){let p=o[g].name;r.hasAttribute(p)||c.removeAttribute(p)}for(let g=0;g<u.length;g++){let p=u[g].name,y=u[g].value;c.getAttribute(p)!==y&&c.setAttribute(p,y)}c.tagName==="INPUT"||c.tagName==="TEXTAREA"?(c.value!==r.value&&(c.value=r.value),c.checked!==r.checked&&(c.checked=r.checked)):c.tagName==="SELECT"&&c.value!==r.value&&(c.value=r.value);let b=Array.from(c.childNodes),f=Array.from(r.childNodes),m=b.length,w=f.length,S=Math.max(m,w);for(let g=0;g<S;g++)g>=m?c.appendChild(f[g].cloneNode(!0)):g>=w?c.removeChild(b[g]):a(b[g],f[g])}}function l(h,d){if(typeof document>"u")return;let c=document.createElement(h.tagName);c.innerHTML=d;let r=Array.from(h.childNodes),o=Array.from(c.childNodes),u=r.length,b=o.length,f=Math.max(u,b);for(let m=0;m<f;m++)m>=u?h.appendChild(o[m].cloneNode(!0)):m>=b?h.removeChild(r[m]):a(r[m],o[m])}let _=new Map,v=!1;function k(h,d){_.set(h,d),v||(v=!0,(typeof requestAnimationFrame<"u"?requestAnimationFrame:r=>setTimeout(r,0))(()=>{_.forEach((r,o)=>{o.isConnected!==!1&&l(o,r)}),_.clear(),v=!1}))}A.setStoreState=function(h,d,c){this.uiStores=this.uiStores||new Map,this.uiStores.has(h)||this.uiStores.set(h,{});let r=this.uiStores.get(h);r[d]=c,this.options.debug&&console.log("%c\u{1F4BE} [Dolphin Store Update]:","color: #ec4899; font-weight: bold;",`${h}.${d}`,"=",c),typeof document<"u"&&document.querySelectorAll(`[data-store-read="${h}.${d}"]`).forEach(u=>{u.tagName==="INPUT"||u.tagName==="TEXTAREA"?u.type==="checkbox"?u.checked=!!c:u.value=c??"":u.textContent=c??""}),this.publish(`store/${h}`,r),typeof this._updateDOM=="function"&&this._updateDOM(`store/${h}`,r)},A.getStoreState=function(h,d){this.uiStores=this.uiStores||new Map;let c=this.uiStores.get(h);return c?c[d]:void 0},A._scanStoreBinds=function(){if(typeof document>"u")return;document.querySelectorAll("[data-store-write]").forEach(c=>{let r=c.getAttribute("data-store-write");if(r){let o=r.split(".");if(o.length===2){let u=o[0],b=o[1],f=c.type==="checkbox"?c.checked:c.value;this.uiStores=this.uiStores||new Map,this.uiStores.has(u)||this.uiStores.set(u,{});let m=this.uiStores.get(u);m[b]===void 0&&(m[b]=f)}}}),document.querySelectorAll("[data-store-read]").forEach(c=>{let r=c.getAttribute("data-store-read");if(r){let o=r.split(".");if(o.length===2){let u=o[0],b=o[1],f=this.getStoreState(u,b);f!=null&&(c.tagName==="INPUT"||c.tagName==="TEXTAREA"?c.type==="checkbox"?c.checked=!!f:c.value=f:c.textContent=f)}}})},A.getClosestContext=function(h,d){let c=h;for(;c;){if(c._rtContext){let r=c._rtContext;return d?r[d]:r}c=c.parentElement}return null},A._executeStoreAction=function(h,d){this.uiStores=this.uiStores||new Map;let c=new Proxy({},{has:(r,o)=>!0,get:(r,o)=>{if(typeof o=="string")return new Proxy({},{get:(u,b)=>{if(typeof b=="string")return this.getStoreState(o,b)},set:(u,b,f)=>typeof b=="string"?(this.setStoreState(o,b,f),!0):!1})}});try{new Function("ctx",`with(ctx) { ${h} }`)(c)}catch(r){console.error("%c[Dolphin Store Action Error]:","color: #ef4444; font-weight: bold;",r),d&&console.error("%cFailed Element:","color: #f97316; font-weight: bold;",d),console.error("%cFailed Expression:","color: #3b82f6; font-style: italic;",h)}},A._initDOMBinding=function(){if(this._domInitialized)return;this._domInitialized=!0;let h=["input","change","keyup","paste","blur"],d=new WeakMap;h.forEach(r=>{this.addDomListener(document,r,o=>{if(!o.target||!o.target.getAttribute)return;let u=o.target.getAttribute("data-store-write");if(u){let w=u.split(".");if(w.length===2){let S=w[0],g=w[1],p=o.target.type==="checkbox"?o.target.checked:o.target.value;this.setStoreState(S,g,p)}}let b=o.target.getAttribute("data-rt-validate"),f=o.target.name;if(b&&f&&typeof this.validateField=="function"){let w=o.target.closest("form"),S=w?Object.fromEntries(new FormData(w).entries()):{},g=this.validateField(o.target.value,b,S);g?(o.target.classList.add("invalid"),this.publish(`errors/${f}`,g)):(o.target.classList.remove("invalid"),this.publish(`errors/${f}`,""))}let m=o.target.getAttribute("data-rt-push");if(m){let w=o.target.getAttribute("data-rt-debounce"),S=w?parseInt(w,10):0,g=()=>{let p={name:o.target.name,value:o.target.value};this.pubPush(m,p)};if(S>0){d.has(o.target)&&clearTimeout(d.get(o.target));let p=setTimeout(g,S);d.set(o.target,p)}else g()}})}),this.addDomListener(document,"submit",async r=>{if(!r.target||!r.target.getAttribute)return;let o=r.target.getAttribute("data-rt-submit"),u=r.target.getAttribute("data-api-submit");if(o||u){r.target.querySelectorAll("[name]").forEach(p=>{let y=p.name;y&&(this.publish(`errors/${y}`,""),p.classList.remove("invalid"))});let f=r.target.querySelectorAll("[data-rt-validate]"),m=!0;if(f.length>0&&typeof this.validateField=="function"){let p=Object.fromEntries(new FormData(r.target).entries());f.forEach(y=>{let T=y.getAttribute("data-rt-validate"),D=y.name;if(T&&D){let E=this.validateField(y.value,T,p);E&&(m=!1,y.classList.add("invalid"),this.publish(`errors/${D}`,E))}})}if(!m){r.preventDefault(),r.stopPropagation();return}r.preventDefault();let w=this.getClosestContext(r.target)||{},S=new FormData(r.target),g=Object.fromEntries(S.entries());if(o){let p=o;for(let y in w){let T=e(y);p=p.replace(new RegExp(`\\{\\{${T}\\}\\}`,"g"),w[y]!==void 0&&w[y]!==null?w[y]:"")}this.publish(p,g)}else if(u){let p=u;for(let E in w){let L=e(E);p=p.replace(new RegExp(`\\{\\{${L}\\}\\}`,"g"),w[E]!==void 0&&w[E]!==null?w[E]:"")}let y=p.trim().split(" "),T=y.length>1?y[0].toUpperCase():"POST",D=y.length>1?y[1]:y[0];g._method&&(T=String(g._method).toUpperCase());try{let E=await this.api.request(T,D,g),L=r.target.getAttribute("data-api-result");L&&this._updateDOM(L,E);let M=r.target.getAttribute("data-api-redirect");M&&(window.location.href=M),r.target.hasAttribute("data-api-reload")&&window.location.reload()}catch(E){console.error("[Dolphin] API Submit Error:",E)}}}}),["click","change","submit","input","keydown","keyup","dblclick","focus","blur","mouseenter","mouseleave"].forEach(r=>{this.addDomListener(document,r,async o=>{if(!o.target||!o.target.closest)return;let u=o.target.closest(`[data-rt-${r}]`),b=o.target.closest(`[data-api-${r}]`);if(u){r==="submit"&&o.preventDefault();let m=u.getAttribute(`data-rt-${r}`),w=u.getAttribute("data-rt-payload"),S=this.getClosestContext(u)||{},g={};if(w){let p=w;for(let y in S){let T=e(y);p=p.replace(new RegExp(`\\{\\{${T}\\}\\}`,"g"),S[y]!==void 0&&S[y]!==null?S[y]:"")}try{g=JSON.parse(p)}catch{g={}}}this.publish(m,g)}if(b){r==="submit"&&o.preventDefault();let m=b.getAttribute(`data-api-${r}`),w=b.getAttribute("data-api-payload"),S=this.getClosestContext(b)||{},g=m.trim().split(" "),p=g.length>1?g[0].toUpperCase():"POST",y=g.length>1?g[1]:g[0],T=null;if(w){let D=w;for(let E in S){let L=e(E);D=D.replace(new RegExp(`\\{\\{${L}\\}\\}`,"g"),S[E]!==void 0&&S[E]!==null?S[E]:"")}try{T=JSON.parse(D)}catch{T=null}}try{let D=await this.api.request(p,y,T),E=b.getAttribute("data-api-result");E&&this._updateDOM(E,D);let L=b.getAttribute("data-api-redirect");L&&(window.location.href=L),b.hasAttribute("data-api-reload")&&window.location.reload()}catch(D){console.error(`[Dolphin] API ${r} Error:`,D)}}let f=o.target.closest(`[data-store-${r}]`);if(f){r==="submit"&&o.preventDefault();let m=f.getAttribute(`data-store-${r}`);m&&this._executeStoreAction(m,f)}})}),this.subscribe("#",(r,o)=>{this._updateDOM(o,r)}),this._scanAndFetchAPIBinds(),this._scanStoreBinds(),this._resolveImports(),this._initSPARouter()},A._scanAndFetchAPIBinds=async function(){if(typeof document>"u")return;let h=document.querySelectorAll("[data-api-get]");for(let d of Array.from(h)){let c=d.getAttribute("data-api-get");if(c&&!(typeof d.hasAttribute=="function"&&d.hasAttribute("data-api-initialized"))){typeof d.setAttribute=="function"&&d.setAttribute("data-api-initialized","true");try{let r=await this.api.get(c),o=d.getAttribute("data-api-store");if(o){let b=o.split(".");b.length===2&&this.setStoreState(b[0],b[1],r)}let u=d.getAttribute("data-rt-bind");if(u&&!o)this._updateDOM(u,r);else if(!o){let b=n(d);if(b&&typeof r=="object"&&r!==null){let f=this._applyDeclarativeDirectives(d,r);if(Array.isArray(f)){let m="";for(let w of f)m+=s(b,w);k(d,m)}else k(d,s(b,f))}else if(d.tagName==="INPUT"||d.tagName==="TEXTAREA")d.value=typeof r=="object"?r.value!==void 0?r.value:"":r;else{let f=typeof r=="object"?r.html||r.text||JSON.stringify(r):String(r);d.innerHTML=i(f)}}}catch(r){console.error("[Dolphin] API Get Error:",r)}}}},A._applyDeclarativeDirectives=function(h,d){let c=d;if(typeof d=="object"&&d!==null){let r=o=>{let u=[...o],b=h.getAttribute("data-rt-filter");if(b){let w=b.split("==");if(w.length===2){let S=w[0].trim(),g=w[1].trim(),p,y=g.split(".");y.length===2?p=this.getStoreState(y[0],y[1]):p=d[g]!==void 0?d[g]:this.getStoreState("app",g),p!=null&&p!==""&&(u=u.filter(T=>T[S]===p))}}let f=h.getAttribute("data-rt-search");if(f){let w=f.split("==");if(w.length===2){let S=w[0].trim(),g=w[1].trim(),p,y=g.split(".");if(y.length===2?p=this.getStoreState(y[0],y[1]):p=d[g]!==void 0?d[g]:this.getStoreState("app",g),p!=null&&p!==""){let T=String(p).toLowerCase();u=u.filter(D=>{let E=D[S];return E!=null&&String(E).toLowerCase().includes(T)})}}}let m=h.getAttribute("data-rt-sort");if(m){let w,S=m.split(".");if(S.length===2?w=this.getStoreState(S[0],S[1]):w=d[m]!==void 0?d[m]:this.getStoreState("app",m),w&&w!=="")if(w==="popular")u.sort((g,p)=>{let y=g.rating?.rate||g.rate||0;return(p.rating?.rate||p.rate||0)-y});else{let g="",p="asc";w.endsWith("-low")||w.endsWith("-asc")?(g=w.replace("-low","").replace("-asc",""),p="asc"):(w.endsWith("-high")||w.endsWith("-desc"))&&(g=w.replace("-high","").replace("-desc",""),p="desc"),g&&u.sort((y,T)=>{let D=(J,Q)=>Q.split(".").reduce((q,G)=>q&&q[G],J),E=D(y,g),L=D(T,g);if(E===void 0&&(E=y[g]),L===void 0&&(L=T[g]),typeof E=="string"&&typeof L=="string")return p==="asc"?E.localeCompare(L):L.localeCompare(E);let M=Number(E),I=Number(L);return!isNaN(M)&&!isNaN(I)?p==="asc"?M-I:I-M:0})}}return u};if(Array.isArray(d))c=r(d);else{let o="";for(let u in d)if(Array.isArray(d[u])){o=u;break}if(o){let u=r(d[o]);c={...d,[o]:u}}}}return c},A._updateDOM=function(h,d){if(typeof document>"u")return;document.querySelectorAll(`[data-rt-bind="${h}"]`).forEach(r=>{let o=this._applyDeclarativeDirectives(r,d);if(r.getAttribute("data-rt-type")==="context"&&typeof o=="object"&&o!==null){r._rtContext=o;let b=f=>{if(f.hasAttribute("data-rt-text")){let m=f.getAttribute("data-rt-text");m&&o[m]!==void 0&&o[m]!==null&&(f.textContent=o[m])}if(f.hasAttribute("data-rt-html")){let m=f.getAttribute("data-rt-html");m&&o[m]!==void 0&&o[m]!==null&&(f.innerHTML=i(o[m]))}if(f.hasAttribute("data-rt-attr")){let m=f.getAttribute("data-rt-attr");m&&m.split(",").forEach(w=>{let S=w.split(":");if(S.length===2){let g=S[0].trim(),p=S[1].trim();g&&p&&o[p]!==void 0&&o[p]!==null&&f.setAttribute(g,o[p])}})}if(f.hasAttribute("data-rt-class")){let m=f.getAttribute("data-rt-class");m&&m.split(",").forEach(w=>{let S=w.split(":");if(S.length===2){let g=S[0].trim(),p=S[1].trim(),y=g.split(/\s+/).filter(Boolean);o[p]?y.forEach(T=>f.classList.add(T)):y.forEach(T=>f.classList.remove(T))}})}if(f.hasAttribute("data-rt-if")){let m=f.getAttribute("data-rt-if");m&&(o[m]?f.style.display="":f.style.display="none")}if(f.hasAttribute("data-rt-hide")){let m=f.getAttribute("data-rt-hide");m&&(o[m]?f.style.display="none":f.style.display="")}};b(r),r.querySelectorAll("[data-rt-text], [data-rt-html], [data-rt-attr], [data-rt-class], [data-rt-if], [data-rt-hide]").forEach(b);return}let u=n(r);if(u&&typeof o=="object"&&o!==null){if(Array.isArray(o)){let b="";for(let f of o)b+=s(u,f);k(r,b)}else k(r,s(u,o));return}if(r.tagName==="INPUT"||r.tagName==="TEXTAREA")r.value=typeof o=="object"?o.value!==void 0?o.value:"":o;else if(u)r.innerHTML=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);else{let b=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);r.innerHTML=i(b)}})},A._resolveImports=async function(h){if(typeof document>"u")return;let d=h||document.body||document;if(!d||typeof d.querySelectorAll!="function")return;let c=d.querySelectorAll("[data-import]");if(c.length===0)return;let r=async(u,b)=>{let f=u.getAttribute("data-import");if(!f)return;if(b.has(f)){console.warn(`[Dolphin Component Warning]: Circular import detected for "${f}". Skipping resolving.`),u.innerHTML=`<span style="color:red;font-weight:bold;">Circular import: ${f}</span>`;return}b.add(f);let m=t.get(f);m||(m=fetch(f).then(g=>{if(!g.ok)throw new Error(`HTTP ${g.status}`);return g.text()}),m.catch(()=>t.delete(f)),t.set(f,m));let w="";try{w=await m}catch(g){console.error(`[Dolphin Component Error]: Failed to fetch component "${f}":`,g),w=`<span style="color:red;font-weight:bold;">Failed to import ${f}</span>`}u.innerHTML=i(w),u.removeAttribute("data-import");let S=u.querySelectorAll("[data-import]");if(S.length>0){let g=Array.from(S).map(p=>r(p,new Set(b)));await Promise.all(g)}this._scanStoreBinds(),this._scanAndFetchAPIBinds()},o=Array.from(c).map(u=>r(u,new Set));await Promise.all(o)},A._initSPARouter=function(){if(typeof window>"u"||typeof document>"u"||this._routerInitialized)return;this._routerInitialized=!0;let h=null,d=()=>{let o=(this.options.routerViewport||"main, #viewport, body").split(",").map(u=>u.trim());for(let u of o){let b=document.querySelector(u);if(b)return b}return document.body},c=async(r,o=!0)=>{try{this.options.debug&&console.log(`%c\u{1F6E3}\uFE0F [Dolphin Router]: Navigating to ${r}...`,"color: #3b82f6; font-weight: bold;"),h&&h.abort(),h=new AbortController;let u=h.signal,b=d();this.options.routerTransitions&&b&&(b.classList.add("dolphin-fade-out"),await new Promise(y=>setTimeout(y,150)));let f=await fetch(r,{signal:u});if(!f.ok)throw new Error(`HTTP ${f.status}`);let m=await f.text();h=null;let S=new DOMParser().parseFromString(m,"text/html");S.title&&(document.title=S.title);let g=S.querySelector(this.options.routerViewport||"main, #viewport, body"),p=d();g&&p?(p.innerHTML=g.innerHTML,Array.from(g.attributes).forEach(y=>{p.setAttribute(y.name,y.value)})):p&&(p.innerHTML=S.body.innerHTML),o&&window.history.pushState({dolphinSpa:!0,url:r},"",r),this.options.routerTransitions&&p&&(p.classList.remove("dolphin-fade-out"),p.classList.add("dolphin-fade-in"),setTimeout(()=>p.classList.remove("dolphin-fade-in"),300)),await this._resolveImports(p),this._scanStoreBinds(),this._scanAndFetchAPIBinds()}catch(u){if(u&&u.name==="AbortError")return;console.error("[Dolphin Router Error]: Failed to route page:",u),window.location.href=r}};if(this.addDomListener(document,"click",r=>{let o=r.target.closest("a");if(!o||!o.hasAttribute("data-spa")&&o.getAttribute("data-spa")!=="true")return;let u=o.getAttribute("href");!u||u.startsWith("#")||u.startsWith("javascript:")||u.startsWith("mailto:")||u.startsWith("tel:")||new URL(u,window.location.href).origin!==window.location.origin||(r.preventDefault(),c(u))}),this.addDomListener(window,"popstate",r=>{r.state&&r.state.dolphinSpa?c(r.state.url,!1):r.state===null&&c(window.location.pathname,!1)}),this.options.routerTransitions){let r=document.createElement("style");r.innerHTML=`
|
|
26
|
+
`,_=u;return typeof Proxy<"u"&&u!==null&&typeof u=="object"&&(_=new Proxy(u,{has(p,b){return typeof b!="symbol"},get(p,b){if(b!==Symbol.unscopables){if(b in p)return p[b];if(typeof globalThis<"u"&&b in globalThis)return globalThis[b];if(typeof window<"u"&&b in window)return window[b]}}})),new Function("context",w)(_)}catch(l){console.error("[Dolphin Template Compiler Error]:",l);let n=f;for(let o in u){let c=o.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");n=n.replace(new RegExp(`\\{\\{${c}\\}\\}`,"g"),u[o]!==void 0&&u[o]!==null?u[o]:"")}return n}}function r(f){if(typeof document>"u")return f;try{let n=new DOMParser().parseFromString(f,"text/html").body,o=c=>{let y=c.tagName.toLowerCase();if(["script","iframe","object","embed","link","style","meta","applet","svg"].includes(y)){c.parentNode?.removeChild(c);return}let h=c.attributes;for(let m=h.length-1;m>=0;m--){let w=h[m].name.toLowerCase(),_=h[m].value.toLowerCase();(w.startsWith("on")||["src","href","data"].includes(w)&&(_.includes("javascript:")||_.includes("data:text/html")))&&c.removeAttribute(h[m].name)}Array.from(c.children).forEach(o)};return Array.from(n.children).forEach(o),n.innerHTML}catch{return f}}function a(f,u){if(f.nodeType!==u.nodeType){f.parentNode?.replaceChild(u.cloneNode(!0),f);return}if(f.nodeType===Node.TEXT_NODE){f.textContent!==u.textContent&&(f.textContent=u.textContent);return}if(f.nodeType===Node.ELEMENT_NODE){let l=f,n=u;if(l.tagName!==n.tagName){l.parentNode?.replaceChild(n.cloneNode(!0),l);return}let o=l.attributes,c=n.attributes;for(let g=o.length-1;g>=0;g--){let p=o[g].name;n.hasAttribute(p)||l.removeAttribute(p)}for(let g=0;g<c.length;g++){let p=c[g].name,b=c[g].value;l.getAttribute(p)!==b&&l.setAttribute(p,b)}l.tagName==="INPUT"||l.tagName==="TEXTAREA"?(l.value!==n.value&&(l.value=n.value),l.checked!==n.checked&&(l.checked=n.checked)):l.tagName==="SELECT"&&l.value!==n.value&&(l.value=n.value);let y=Array.from(l.childNodes),h=Array.from(n.childNodes),m=y.length,w=h.length,_=Math.max(m,w);for(let g=0;g<_;g++)g>=m?l.appendChild(h[g].cloneNode(!0)):g>=w?l.removeChild(y[g]):a(y[g],h[g])}}function d(f,u){if(typeof document>"u")return;let l=document.createElement(f.tagName);l.innerHTML=u;let n=Array.from(f.childNodes),o=Array.from(l.childNodes),c=n.length,y=o.length,h=Math.max(c,y);for(let m=0;m<h;m++)m>=c?f.appendChild(o[m].cloneNode(!0)):m>=y?f.removeChild(n[m]):a(n[m],o[m])}let E=new Map,S=!1;function k(f,u){E.set(f,u),S||(S=!0,(typeof requestAnimationFrame<"u"?requestAnimationFrame:n=>setTimeout(n,0))(()=>{E.forEach((n,o)=>{o.isConnected!==!1&&d(o,n)}),E.clear(),S=!1}))}A.setStoreState=function(f,u,l){this.uiStores=this.uiStores||new Map,this.uiStores.has(f)||this.uiStores.set(f,{});let n=this.uiStores.get(f);n[u]=l,this.options.debug&&console.log("%c\u{1F4BE} [Dolphin Store Update]:","color: #ec4899; font-weight: bold;",`${f}.${u}`,"=",l),typeof document<"u"&&document.querySelectorAll(`[data-store-read="${f}.${u}"]`).forEach(c=>{c.tagName==="INPUT"||c.tagName==="TEXTAREA"?c.type==="checkbox"?c.checked=!!l:c.value=l??"":c.textContent=l??""}),this.publish(`store/${f}`,n),typeof this._updateDOM=="function"&&this._updateDOM(`store/${f}`,n)},A.getStoreState=function(f,u){this.uiStores=this.uiStores||new Map;let l=this.uiStores.get(f);return l?l[u]:void 0},A._scanStoreBinds=function(){if(typeof document>"u")return;document.querySelectorAll("[data-store-write]").forEach(l=>{let n=l.getAttribute("data-store-write");if(n){let o=n.split(".");if(o.length===2){let c=o[0],y=o[1],h=l.type==="checkbox"?l.checked:l.value;this.uiStores=this.uiStores||new Map,this.uiStores.has(c)||this.uiStores.set(c,{});let m=this.uiStores.get(c);m[y]===void 0&&(m[y]=h)}}}),document.querySelectorAll("[data-store-read]").forEach(l=>{let n=l.getAttribute("data-store-read");if(n){let o=n.split(".");if(o.length===2){let c=o[0],y=o[1],h=this.getStoreState(c,y);h!=null&&(l.tagName==="INPUT"||l.tagName==="TEXTAREA"?l.type==="checkbox"?l.checked=!!h:l.value=h:l.textContent=h)}}})},A.getClosestContext=function(f,u){let l=f;for(;l;){if(l._rtContext){let n=l._rtContext;return u?n[u]:n}l=l.parentElement}return null},A._executeStoreAction=function(f,u){this.uiStores=this.uiStores||new Map;let l=new Proxy({},{has:(n,o)=>!0,get:(n,o)=>{if(typeof o=="string")return new Proxy({},{get:(c,y)=>{if(typeof y=="string")return this.getStoreState(o,y)},set:(c,y,h)=>typeof y=="string"?(this.setStoreState(o,y,h),!0):!1})}});try{new Function("ctx",`with(ctx) { ${f} }`)(l)}catch(n){console.error("%c[Dolphin Store Action Error]:","color: #ef4444; font-weight: bold;",n),u&&console.error("%cFailed Element:","color: #f97316; font-weight: bold;",u),console.error("%cFailed Expression:","color: #3b82f6; font-style: italic;",f)}},A._showAlert=function(f,u){if(typeof document>"u")return;let l=document.getElementById(f)||document.querySelector(`[id="${f}"]`);l&&(l.removeAttribute("hidden"),l.style.display="",u&&u>0&&setTimeout(()=>{l.setAttribute("hidden","")},u))},A._showToast=function(f,u="success"){if(typeof document>"u")return;let l={success:{bg:"rgba(16,185,129,0.15)",border:"#10b981",icon:"\u2705"},error:{bg:"rgba(239,68,68,0.15)",border:"#ef4444",icon:"\u274C"},info:{bg:"rgba(59,130,246,0.15)",border:"#3b82f6",icon:"\u2139\uFE0F"}},n=l[u]||l.success,o=document.createElement("div");o.setAttribute("data-dolphin-toast","");let y=document.querySelectorAll("[data-dolphin-toast]").length*72;o.style.cssText=["position:fixed",`bottom:${24+y}px`,"right:24px","z-index:2147483647",`background:${n.bg}`,`border:1px solid ${n.border}`,"color:#fff","padding:14px 20px","border-radius:14px","font-size:14px","font-weight:600","font-family:system-ui,sans-serif","box-shadow:0 8px 32px rgba(0,0,0,0.4)","display:flex","align-items:center","gap:10px","max-width:380px","word-break:break-word","transform:translateY(80px)","opacity:0","transition:transform 0.35s cubic-bezier(0.34,1.56,0.64,1),opacity 0.3s ease","pointer-events:auto","backdrop-filter:blur(12px)"].join(";"),o.innerHTML=`<span style="font-size:18px">${n.icon}</span><span>${f}</span>`,document.body.appendChild(o);let h=()=>{document.querySelectorAll("[data-dolphin-toast]").forEach((p,b)=>{p.style.bottom=`${24+b*72}px`})},m=typeof requestAnimationFrame<"u"?requestAnimationFrame:g=>setTimeout(g,0);m(()=>m(()=>{o.style.transform="translateY(0)",o.style.opacity="1"}));let w=()=>{clearTimeout(o._removeTimer),o.parentNode&&(o.parentNode.removeChild(o),h())},_=setTimeout(()=>{o.style.transform="translateY(80px)",o.style.opacity="0",o._removeTimer=setTimeout(w,400)},3500);o._hideTimer=_,o.addEventListener("click",()=>{clearTimeout(o._hideTimer),w()},{once:!0})},A._initDOMBinding=function(){if(this._domInitialized)return;this._domInitialized=!0;let f=["input","change","keyup","paste","blur"],u=new WeakMap;f.forEach(n=>{this.addDomListener(document,n,o=>{if(!o.target||!o.target.getAttribute)return;let c=o.target.getAttribute("data-store-write");if(c){let w=c.split(".");if(w.length===2){let _=w[0],g=w[1],p=o.target.type==="checkbox"?o.target.checked:o.target.value;this.setStoreState(_,g,p)}}let y=o.target.getAttribute("data-rt-validate"),h=o.target.name;if(y&&h&&typeof this.validateField=="function"){let w=o.target.closest("form"),_=w?Object.fromEntries(new FormData(w).entries()):{},g=this.validateField(o.target.value,y,_);g?(o.target.classList.add("invalid"),this.publish(`errors/${h}`,g)):(o.target.classList.remove("invalid"),this.publish(`errors/${h}`,""))}let m=o.target.getAttribute("data-rt-push");if(m){let w=o.target.getAttribute("data-rt-debounce"),_=w?parseInt(w,10):0,g=()=>{let p={name:o.target.name,value:o.target.value};this.pubPush(m,p)};if(_>0){u.has(o.target)&&clearTimeout(u.get(o.target));let p=setTimeout(g,_);u.set(o.target,p)}else g()}})}),this.addDomListener(document,"submit",async n=>{if(!n.target||!n.target.getAttribute)return;let o=n.target.getAttribute("data-rt-submit"),c=n.target.getAttribute("data-api-submit");if(o||c){n.target.querySelectorAll("[name]").forEach(p=>{let b=p.name;b&&(this.publish(`errors/${b}`,""),p.classList.remove("invalid"))});let h=n.target.querySelectorAll("[data-rt-validate]"),m=!0;if(h.length>0&&typeof this.validateField=="function"){let p=Object.fromEntries(new FormData(n.target).entries());h.forEach(b=>{let T=b.getAttribute("data-rt-validate"),x=b.name;if(T&&x){let v=this.validateField(b.value,T,p);v&&(m=!1,b.classList.add("invalid"),this.publish(`errors/${x}`,v))}})}if(!m){n.preventDefault(),n.stopPropagation();return}n.preventDefault();let w=this.getClosestContext(n.target)||{},_=new FormData(n.target),g=Object.fromEntries(_.entries());if(o){let p=o;for(let T in w){let x=e(T);p=p.replace(new RegExp(`\\{\\{${x}\\}\\}`,"g"),w[T]!==void 0&&w[T]!==null?w[T]:"")}this.publish(p,g);let b=n.target.getAttribute("data-rt-api-success");if(b){let T=document.getElementById(b);T&&this._showToast(T.textContent||T.innerText||"","success")}}else if(c){let p=c;for(let v in w){let D=e(v);p=p.replace(new RegExp(`\\{\\{${D}\\}\\}`,"g"),w[v]!==void 0&&w[v]!==null?w[v]:"")}let b=p.trim().split(" "),T=b.length>1?b[0].toUpperCase():"POST",x=b.length>1?b[1]:b[0];g._method&&(T=String(g._method).toUpperCase());try{let v=await this.api.request(T,x,g),D=n.target.getAttribute("data-api-result");D&&this._updateDOM(D,v);let L=n.target.getAttribute("data-api-toast");L&&this._showToast(L,"success");let M=n.target.getAttribute("data-rt-api-success");if(M){let I=parseInt(n.target.getAttribute("data-rt-alert-duration")||"0",10);this._showAlert(M,I);let P=n.target.getAttribute("data-rt-api-error");if(P){let R=document.getElementById(P);R&&R.setAttribute("hidden","")}}let $=n.target.getAttribute("data-api-redirect");$&&(window.location.href=$),n.target.hasAttribute("data-api-reload")&&window.location.reload()}catch(v){console.error("[Dolphin] API Submit Error:",v);let D=n.target.getAttribute("data-api-error-toast");D&&this._showToast(D,"error");let L=n.target.getAttribute("data-rt-api-error");if(L){let M=parseInt(n.target.getAttribute("data-rt-alert-duration")||"0",10);this._showAlert(L,M);let $=n.target.getAttribute("data-rt-api-success");if($){let I=document.getElementById($);I&&I.setAttribute("hidden","")}}}}}}),["click","change","input","keydown","keyup","dblclick","focus","blur","mouseenter","mouseleave"].forEach(n=>{this.addDomListener(document,n,async o=>{if(!o.target||!o.target.closest)return;let c=o.target.closest(`[data-rt-${n}]`),y=o.target.closest(`[data-api-${n}]`);if(c){n==="submit"&&o.preventDefault();let m=c.getAttribute(`data-rt-${n}`),w=c.getAttribute("data-rt-payload"),_=this.getClosestContext(c)||{},g={};if(w){let p=w;for(let b in _){let T=e(b);p=p.replace(new RegExp(`\\{\\{${T}\\}\\}`,"g"),_[b]!==void 0&&_[b]!==null?_[b]:"")}try{g=JSON.parse(p)}catch{g={}}}this.publish(m,g)}if(y){n==="submit"&&o.preventDefault();let m=y.getAttribute(`data-api-${n}`),w=y.getAttribute("data-api-payload"),_=this.getClosestContext(y)||{},g=m;for(let v in _){let D=e(v);g=g.replace(new RegExp(`\\{\\{${D}\\}\\}`,"g"),_[v]!==void 0&&_[v]!==null?_[v]:"")}let p=g.trim().split(" "),b=p.length>1?p[0].toUpperCase():"POST",T=p.length>1?p[1]:p[0],x=null;if(w){let v=w;for(let D in _){let L=e(D);v=v.replace(new RegExp(`\\{\\{${L}\\}\\}`,"g"),_[D]!==void 0&&_[D]!==null?_[D]:"")}try{x=JSON.parse(v)}catch{x=null}}try{let v=await this.api.request(b,T,x),D=y.getAttribute("data-api-result");D&&this._updateDOM(D,v);let L=y.getAttribute("data-api-toast");L&&this._showToast(L,"success");let M=y.getAttribute("data-rt-api-success");if(M){let I=parseInt(y.getAttribute("data-rt-alert-duration")||"0",10);this._showAlert(M,I);let P=y.getAttribute("data-rt-api-error");if(P){let R=document.getElementById(P);R&&R.setAttribute("hidden","")}}let $=y.getAttribute("data-api-redirect");$&&(window.location.href=$),y.hasAttribute("data-api-reload")&&window.location.reload()}catch(v){console.error(`[Dolphin] API ${n} Error:`,v);let D=y.getAttribute("data-api-error-toast");D&&this._showToast(D,"error");let L=y.getAttribute("data-rt-api-error");if(L){let M=parseInt(y.getAttribute("data-rt-alert-duration")||"0",10);this._showAlert(L,M);let $=y.getAttribute("data-rt-api-success");if($){let I=document.getElementById($);I&&I.setAttribute("hidden","")}}}}let h=o.target.closest(`[data-store-${n}]`);if(h){n==="submit"&&o.preventDefault();let m=h.getAttribute(`data-store-${n}`);m&&this._executeStoreAction(m,h)}})}),this.subscribe("#",(n,o)=>{this._updateDOM(o,n)}),this._scanAndFetchAPIBinds(),this._scanStoreBinds(),this._resolveImports(),this._initSPARouter()},A._scanAndFetchAPIBinds=async function(){if(typeof document>"u")return;let f=document.querySelectorAll("[data-api-get]");for(let u of Array.from(f)){let l=u.getAttribute("data-api-get");if(l&&!(typeof u.hasAttribute=="function"&&u.hasAttribute("data-api-initialized"))){typeof u.setAttribute=="function"&&u.setAttribute("data-api-initialized","true");try{let n=await this.api.get(l),o=u.getAttribute("data-api-store");if(o){let y=o.split(".");y.length===2&&this.setStoreState(y[0],y[1],n)}let c=u.getAttribute("data-rt-bind");if(c&&!o)this._updateDOM(c,n);else if(!o){let y=s(u);if(y&&typeof n=="object"&&n!==null){let h=this._applyDeclarativeDirectives(u,n);if(Array.isArray(h)){let m="";for(let w of h)m+=i(y,w);k(u,m)}else k(u,i(y,h))}else if(u.tagName==="INPUT"||u.tagName==="TEXTAREA")u.value=typeof n=="object"?n.value!==void 0?n.value:"":n;else{let h=typeof n=="object"?n.html||n.text||JSON.stringify(n):String(n);u.innerHTML=r(h)}}}catch(n){console.error("[Dolphin] API Get Error:",n)}}}},A._applyDeclarativeDirectives=function(f,u){let l=u;if(typeof u=="object"&&u!==null){let n=o=>{let c=[...o],y=f.getAttribute("data-rt-filter");if(y){let w=y.split("==");if(w.length===2){let _=w[0].trim(),g=w[1].trim(),p,b=g.split(".");b.length===2?p=this.getStoreState(b[0],b[1]):p=u[g]!==void 0?u[g]:this.getStoreState("app",g),p!=null&&p!==""&&(c=c.filter(T=>T[_]===p))}}let h=f.getAttribute("data-rt-search");if(h){let w=h.split("==");if(w.length===2){let _=w[0].trim(),g=w[1].trim(),p,b=g.split(".");if(b.length===2?p=this.getStoreState(b[0],b[1]):p=u[g]!==void 0?u[g]:this.getStoreState("app",g),p!=null&&p!==""){let T=String(p).toLowerCase();c=c.filter(x=>{let v=x[_];return v!=null&&String(v).toLowerCase().includes(T)})}}}let m=f.getAttribute("data-rt-sort");if(m){let w,_=m.split(".");if(_.length===2?w=this.getStoreState(_[0],_[1]):w=u[m]!==void 0?u[m]:this.getStoreState("app",m),w&&w!=="")if(w==="popular")c.sort((g,p)=>{let b=g.rating?.rate||g.rate||0;return(p.rating?.rate||p.rate||0)-b});else{let g="",p="asc";w.endsWith("-low")||w.endsWith("-asc")?(g=w.replace("-low","").replace("-asc",""),p="asc"):(w.endsWith("-high")||w.endsWith("-desc"))&&(g=w.replace("-high","").replace("-desc",""),p="desc"),g&&c.sort((b,T)=>{let x=($,I)=>I.split(".").reduce((P,R)=>P&&P[R],$),v=x(b,g),D=x(T,g);if(v===void 0&&(v=b[g]),D===void 0&&(D=T[g]),typeof v=="string"&&typeof D=="string")return p==="asc"?v.localeCompare(D):D.localeCompare(v);let L=Number(v),M=Number(D);return!isNaN(L)&&!isNaN(M)?p==="asc"?L-M:M-L:0})}}return c};if(Array.isArray(u))l=n(u);else{let o="";for(let c in u)if(Array.isArray(u[c])){o=c;break}if(o){let c=n(u[o]);l={...u,[o]:c}}}}return l},A._updateDOM=function(f,u){if(typeof document>"u")return;document.querySelectorAll(`[data-rt-bind="${f}"]`).forEach(n=>{let o=this._applyDeclarativeDirectives(n,u);if(n.getAttribute("data-rt-type")==="context"&&typeof o=="object"&&o!==null){n._rtContext=o;let y=h=>{if(h.hasAttribute("data-rt-text")){let m=h.getAttribute("data-rt-text");m&&o[m]!==void 0&&o[m]!==null&&(h.textContent=o[m])}if(h.hasAttribute("data-rt-html")){let m=h.getAttribute("data-rt-html");m&&o[m]!==void 0&&o[m]!==null&&(h.innerHTML=r(o[m]))}if(h.hasAttribute("data-rt-attr")){let m=h.getAttribute("data-rt-attr");m&&m.split(",").forEach(w=>{let _=w.split(":");if(_.length===2){let g=_[0].trim(),p=_[1].trim();g&&p&&o[p]!==void 0&&o[p]!==null&&h.setAttribute(g,o[p])}})}if(h.hasAttribute("data-rt-class")){let m=h.getAttribute("data-rt-class");m&&m.split(",").forEach(w=>{let _=w.split(":");if(_.length===2){let g=_[0].trim(),p=_[1].trim(),b=g.split(/\s+/).filter(Boolean);o[p]?b.forEach(T=>h.classList.add(T)):b.forEach(T=>h.classList.remove(T))}})}if(h.hasAttribute("data-rt-if")){let m=h.getAttribute("data-rt-if");m&&(o[m]?h.style.display="":h.style.display="none")}if(h.hasAttribute("data-rt-hide")){let m=h.getAttribute("data-rt-hide");m&&(o[m]?h.style.display="none":h.style.display="")}};y(n),n.querySelectorAll("[data-rt-text], [data-rt-html], [data-rt-attr], [data-rt-class], [data-rt-if], [data-rt-hide]").forEach(y);return}let c=s(n);if(c&&typeof o=="object"&&o!==null){if(Array.isArray(o)){let y="";for(let h of o)y+=i(c,h);k(n,y)}else k(n,i(c,o));return}if(n.tagName==="INPUT"||n.tagName==="TEXTAREA")n.value=typeof o=="object"?o.value!==void 0?o.value:"":o;else if(c)n.innerHTML=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);else{let y=typeof o=="object"?o.html||o.text||JSON.stringify(o):String(o);n.innerHTML=r(y)}})},A._resolveImports=async function(f){if(typeof document>"u")return;let u=f||document.body||document;if(!u||typeof u.querySelectorAll!="function")return;let l=u.querySelectorAll("[data-import]");if(l.length===0)return;let n=async(c,y)=>{let h=c.getAttribute("data-import");if(!h)return;if(y.has(h)){console.warn(`[Dolphin Component Warning]: Circular import detected for "${h}". Skipping resolving.`),c.innerHTML=`<span style="color:red;font-weight:bold;">Circular import: ${h}</span>`;return}y.add(h);let m=t.get(h);m||(m=fetch(h).then(g=>{if(!g.ok)throw new Error(`HTTP ${g.status}`);return g.text()}),m.catch(()=>t.delete(h)),t.set(h,m));let w="";try{w=await m}catch(g){console.error(`[Dolphin Component Error]: Failed to fetch component "${h}":`,g),w=`<span style="color:red;font-weight:bold;">Failed to import ${h}</span>`}c.innerHTML=r(w),c.removeAttribute("data-import");let _=c.querySelectorAll("[data-import]");if(_.length>0){let g=Array.from(_).map(p=>n(p,new Set(y)));await Promise.all(g)}this._scanStoreBinds(),this._scanAndFetchAPIBinds()},o=Array.from(l).map(c=>n(c,new Set));await Promise.all(o)},A._initSPARouter=function(){if(typeof window>"u"||typeof document>"u"||this._routerInitialized)return;this._routerInitialized=!0;let f=null,u=()=>{let o=(this.options.routerViewport||"main, #viewport, body").split(",").map(c=>c.trim());for(let c of o){let y=document.querySelector(c);if(y)return y}return document.body},l=async(n,o=!0)=>{try{this.options.debug&&console.log(`%c\u{1F6E3}\uFE0F [Dolphin Router]: Navigating to ${n}...`,"color: #3b82f6; font-weight: bold;"),f&&f.abort(),f=new AbortController;let c=f.signal,y=u();this.options.routerTransitions&&y&&(y.classList.add("dolphin-fade-out"),await new Promise(b=>setTimeout(b,150)));let h=await fetch(n,{signal:c});if(!h.ok)throw new Error(`HTTP ${h.status}`);let m=await h.text();f=null;let _=new DOMParser().parseFromString(m,"text/html");_.title&&(document.title=_.title);let g=_.querySelector(this.options.routerViewport||"main, #viewport, body"),p=u();g&&p?(p.innerHTML=g.innerHTML,Array.from(g.attributes).forEach(b=>{p.setAttribute(b.name,b.value)})):p&&(p.innerHTML=_.body.innerHTML),o&&window.history.pushState({dolphinSpa:!0,url:n},"",n),this.options.routerTransitions&&p&&(p.classList.remove("dolphin-fade-out"),p.classList.add("dolphin-fade-in"),setTimeout(()=>p.classList.remove("dolphin-fade-in"),300)),await this._resolveImports(p),this._scanStoreBinds(),this._scanAndFetchAPIBinds()}catch(c){if(c&&c.name==="AbortError")return;console.error("[Dolphin Router Error]: Failed to route page:",c),window.location.href=n}};if(this.addDomListener(document,"click",n=>{let o=n.target.closest("a");if(!o||!o.hasAttribute("data-spa")&&o.getAttribute("data-spa")!=="true")return;let c=o.getAttribute("href");!c||c.startsWith("#")||c.startsWith("javascript:")||c.startsWith("mailto:")||c.startsWith("tel:")||new URL(c,window.location.href).origin!==window.location.origin||(n.preventDefault(),l(c))}),this.addDomListener(window,"popstate",n=>{n.state&&n.state.dolphinSpa?l(n.state.url,!1):n.state===null&&l(window.location.pathname,!1)}),this.options.routerTransitions){let n=document.createElement("style");n.innerHTML=`
|
|
27
27
|
.dolphin-fade-out {
|
|
28
28
|
opacity: 0;
|
|
29
29
|
transition: opacity 0.15s ease-in-out;
|
|
@@ -34,4 +34,4 @@ var DolphinModule=(()=>{var R=Object.defineProperty;var Y=Object.getOwnPropertyD
|
|
|
34
34
|
main, #viewport, body {
|
|
35
35
|
transition: opacity 0.15s ease-in-out;
|
|
36
36
|
}
|
|
37
|
-
`,document.head.appendChild(r)}}}var N=class{client;db;isOnline;memoryCache=new Map;memoryMutations=[];constructor(t){this.client=t,this.isOnline=typeof window<"u"&&typeof navigator<"u"?navigator.onLine:!0,this.initDB(),this.setupNetworkListeners()}initDB(){if(!(typeof indexedDB>"u"))try{let t=indexedDB.open("dolphin_offline",1);t.onupgradeneeded=e=>{let n=e.target.result;n.objectStoreNames.contains("cache")||n.createObjectStore("cache"),n.objectStoreNames.contains("mutations")||n.createObjectStore("mutations",{keyPath:"id",autoIncrement:!0})},t.onsuccess=e=>{this.db=e.target.result,this.isOnline&&this.syncMutations()}}catch(t){console.warn("[Dolphin Offline] Failed to initialize IndexedDB:",t)}}setupNetworkListeners(){typeof window>"u"||(this.client.addDomListener(window,"online",()=>{this.isOnline=!0,this.client._dispatch("network:status",{online:!0}),this.syncMutations()}),this.client.addDomListener(window,"offline",()=>{this.isOnline=!1,this.client._dispatch("network:status",{online:!1})}))}async getCache(t){return this.db?new Promise(e=>{try{let i=this.db.transaction("cache","readonly").objectStore("cache").get(t);i.onsuccess=()=>e(i.result?i.result.data:null),i.onerror=()=>e(null)}catch{e(null)}}):this.memoryCache.get(t)}async setCache(t,e){if(!this.db){this.memoryCache.set(t,e);return}return new Promise(n=>{try{let s=this.db.transaction("cache","readwrite");s.objectStore("cache").put({data:e,timestamp:Date.now()},t),s.oncomplete=()=>n(),s.onerror=()=>{console.warn("[Dolphin Offline] setCache write failed for key:",t),n()}}catch{n()}})}async queueMutation(t,e,n){let s={method:t,path:e,payload:n,timestamp:Date.now()};if(!this.db){this.memoryMutations.push(s);return}return new Promise(i=>{try{let a=this.db.transaction("mutations","readwrite");a.objectStore("mutations").add(s),a.oncomplete=()=>i(),a.onerror=()=>{console.warn("[Dolphin Offline] queueMutation write failed:",t,e),this.memoryMutations.push(s),i()}}catch{i()}})}async getMutations(){return this.db?new Promise(t=>{try{let s=this.db.transaction("mutations","readonly").objectStore("mutations").getAll();s.onsuccess=()=>t(s.result||[]),s.onerror=()=>t([])}catch{t([])}}):[...this.memoryMutations]}async removeMutation(t){if(!this.db){this.memoryMutations=this.memoryMutations.filter(e=>e.id!==t);return}return new Promise(e=>{try{let n=this.db.transaction("mutations","readwrite");n.objectStore("mutations").delete(t),n.oncomplete=()=>e(),n.onerror=()=>{console.warn("[Dolphin Offline] removeMutation failed for id:",t),e()}}catch{e()}})}async syncMutations(){let t=await this.getMutations();if(t.length!==0){console.log(`[Dolphin Offline] Syncing ${t.length} queued mutations...`);for(let e of t)try{await this.client.api.requestDirect(e.method,e.path,e.payload),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift()}catch(n){if(console.error(`[Dolphin Offline] Sync failed for mutation ${e.method} ${e.path}:`,n),n&&n.status&&n.status>=400&&n.status<500)console.warn("[Dolphin Offline] Discarding invalid mutation."),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift();else break}}}};function H(A){A._initOffline=function(){this.offline=new N(this)}}function it(A,t,e){let n=t.split(",");for(let s of n){let i=s.trim().split(":"),a=i[0],l=i[1];if(a==="required"){if(!A||A.trim()==="")return"This field is required"}else if(a==="email"){if(A&&A.trim()!==""&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(A))return"Please enter a valid email address"}else if(a==="min"){let _=parseInt(l,10);if(!A||A.length<_)return`Must be at least ${_} characters`}else if(a==="match"&&e&&A!==e[l])return`Must match ${l}`}return null}function F(A){A.validateField=it}function W(A){A.animateElement=function(t,e,n=300){if(typeof t.animate!="function"){t.classList.add(e),setTimeout(()=>t.classList.remove(e),n);return}e==="fade-in"?t.animate([{opacity:0,transform:"translateY(10px)"},{opacity:1,transform:"translateY(0)"}],{duration:n,easing:"ease-out"}):e==="fade-out"&&t.animate([{opacity:1,transform:"translateY(0)"},{opacity:0,transform:"translateY(10px)"}],{duration:n,easing:"ease-in"})},A.staggerListItems=function(t,e,n=50){if(typeof document>"u")return;t.querySelectorAll(e).forEach((i,a)=>{i.style.animationDelay=`${a*n}ms`,i.classList.add("staggered-item")})}}function j(A){A._initA11y=function(){typeof document>"u"||(this.addDomListener(document,"keydown",t=>{if(t.key!=="Tab")return;document.querySelectorAll("[data-rt-a11y-focus-trap]").forEach(n=>{if(n.style.display==="none"||n.hasAttribute("aria-hidden")&&n.getAttribute("aria-hidden")==="true")return;let i=Array.from(n.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]'));if(i.length===0)return;let a=i[0],l=i[i.length-1];t.shiftKey?document.activeElement===a&&(l.focus(),t.preventDefault()):document.activeElement===l&&(a.focus(),t.preventDefault())})}),this.addDomListener(document,"keydown",t=>{if(!["ArrowUp","ArrowDown","Enter"].includes(t.key))return;document.querySelectorAll("[data-rt-keynav]").forEach(n=>{let s=Array.from(n.children);if(s.length===0)return;let i=s.findIndex(a=>a.classList.contains("active")||document.activeElement===a);t.key==="ArrowDown"?(i=(i+1)%s.length,s[i].focus(),s.forEach((a,l)=>{l===i?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="ArrowUp"?(i=(i-1+s.length)%s.length,s[i].focus(),s.forEach((a,l)=>{l===i?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="Enter"&&i!==-1&&(s[i].click(),t.preventDefault())})}))},A.autoAriaModal=function(t,e){e?(t.setAttribute("role","dialog"),t.setAttribute("aria-modal","true"),t.setAttribute("aria-hidden","false"),t.focus()):t.setAttribute("aria-hidden","true")}}function B(A){A._initI18n=function(){if(this.i18n=this.i18n||{locale:"en",dicts:{}},typeof document>"u")return;if(document.querySelectorAll("[data-i18n-dict]").forEach(e=>{let n=e.getAttribute("data-i18n-dict");if(n)try{let s=JSON.parse(e.textContent||"{}");this.i18n.dicts[n]={...this.i18n.dicts[n]||{},...s}}catch(s){console.warn("[Dolphin i18n] Failed to parse dictionary for locale:",n,s)}}),!this.i18n.locale&&typeof navigator<"u"){let e=navigator.language.split("-")[0];this.i18n.dicts[e]&&(this.i18n.locale=e)}this.addDomListener(document,"click",e=>{let n=e.target.closest("[data-i18n-switch]");if(n){let s=n.getAttribute("data-i18n-switch");s&&this.setLocale(s)}}),this.translateDOM()},A.setLocale=function(t){this.i18n=this.i18n||{locale:"en",dicts:{}},this.i18n.locale=t,this.translateDOM(),this.publish("i18n/locale",t)},A.translateDOM=function(){if(typeof document>"u")return;this.i18n=this.i18n||{locale:"en",dicts:{}};let t=this.i18n.locale||"en",e=this.i18n.dicts[t]||{};document.querySelectorAll("[data-i18n-key]").forEach(s=>{let i=s.getAttribute("data-i18n-key");if(!i)return;let a=i.split(".").reduce((_,v)=>_?_[v]:null,e);a==null&&(a=i);let l=s.getAttribute("data-i18n-params");if(l)try{let _=JSON.parse(l),v=k=>k.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");for(let k in _){let h=v(k);a=a.replace(new RegExp(`\\{\\{${h}\\}\\}`,"g"),_[k])}}catch{}s.tagName==="INPUT"||s.tagName==="TEXTAREA"?s.placeholder=a:s.textContent=a})}}function V(A){A._initDragDrop=function(){typeof document>"u"||(this.addDomListener(document,"dragstart",t=>{let e=t.target.closest("[data-drag]");if(!e)return;let n=e.getAttribute("data-drag");n&&(t.dataTransfer.setData("text/plain",n),t.dataTransfer.effectAllowed="move",e.classList.add("dragging"))}),this.addDomListener(document,"dragend",t=>{let e=t.target.closest("[data-drag]");e&&e.classList.remove("dragging")}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-drop]");e&&(t.preventDefault(),e.classList.add("drag-over"))}),this.addDomListener(document,"dragleave",t=>{let e=t.target.closest("[data-drop]");e&&e.classList.remove("drag-over")}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-drop]");if(!e)return;t.preventDefault(),e.classList.remove("drag-over");let n=e.getAttribute("data-drop"),s=t.dataTransfer.getData("text/plain");if(n&&s)try{let i=JSON.parse(s);this.publish(n,i)}catch{this.publish(n,{value:s})}}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;t.preventDefault();let n=e.querySelector(".dragging");if(!n)return;let i=Array.from(e.querySelectorAll("[data-drag]:not(.dragging)")).find(a=>{let l=a.getBoundingClientRect();return t.clientY-l.top-l.height/2<0});i?e.insertBefore(n,i):e.appendChild(n)}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;let n=e.getAttribute("data-sortable");if(!n)return;let i=Array.from(e.querySelectorAll("[data-drag]")).map((a,l)=>{let _=a.getAttribute("data-drag");try{return{index:l,payload:JSON.parse(_||"{}")}}catch{return{index:l,payload:_}}});this.publish(n,i)}))}}function z(A){A._initCollab=function(){if(typeof document>"u")return;let t=new Map,e=new Map,n=5e3;this.addDomListener(document,"mousemove",s=>{document.querySelectorAll("[data-rt-cursor-share]").forEach(a=>{let l=a.getAttribute("data-rt-cursor-share");if(!l)return;let _=a.getBoundingClientRect(),v=(s.clientX-_.left)/_.width,k=(s.clientY-_.top)/_.height,h=Date.now();(!a._lastSent||h-a._lastSent>50)&&(a._lastSent=h,this.pubPush(`collab/${l}/cursor/${this.deviceId}`,{deviceId:this.deviceId,x:v,y:k}))})}),this.addDomListener(document,"input",s=>{let i=s.target.getAttribute("data-rt-typing");if(!i)return;let a=i,l=_=>{this.pubPush(`collab/${a}/typing/${this.deviceId}`,{deviceId:this.deviceId,typing:_})};s.target._isTyping||(s.target._isTyping=!0,l(!0)),s.target._typingTimer&&clearTimeout(s.target._typingTimer),s.target._typingTimer=setTimeout(()=>{s.target._isTyping=!1,s.target._typingTimer=null,l(!1)},2e3)}),this.addDomListener(document,"input",s=>{let i=s.target.getAttribute("data-rt-crdt");if(!i)return;let a=i,l=s.target.value,_=Date.now();this.publish(`collab/${a}/crdt`,{deviceId:this.deviceId,value:l,timestamp:_,cursorPos:s.target.selectionStart})}),this.subscribe("collab/+/cursor/+",(s,i)=>{let a=i.split("/"),l=a[1],_=a[3];if(_===this.deviceId)return;let v=document.querySelector(`[data-rt-cursor-share="${l}"]`);if(!v)return;let k=`${l}::${_}`,h=t.get(k);(!h||!document.contains(h))&&(h=document.createElement("div"),h.className=`rt-cursor rt-cursor-${_}`,h.style.position="absolute",h.style.width="10px",h.style.height="10px",h.style.borderRadius="50%",h.style.backgroundColor="#"+Math.floor(Math.random()*16777215).toString(16).padStart(6,"0"),h.style.pointerEvents="none",v.appendChild(h),t.set(k,h));let d=v.getBoundingClientRect();h.style.left=s.x*d.width+"px",h.style.top=s.y*d.height+"px",e.has(k)&&clearTimeout(e.get(k)),e.set(k,setTimeout(()=>{let c=t.get(k);c&&c.parentNode&&c.parentNode.removeChild(c),t.delete(k),e.delete(k)},n))}),this.subscribe("collab/+/crdt",(s,i)=>{if(s.deviceId===this.deviceId)return;let l=i.split("/")[1];document.querySelectorAll(`[data-rt-crdt="${l}"]`).forEach(v=>{if(!v._lastUpdate||s.timestamp>v._lastUpdate){v._lastUpdate=s.timestamp;let k=v.selectionStart;v.value=s.value,document.activeElement===v&&v.setSelectionRange(k,k)}})}),this._collabCleanup=()=>{e.forEach(s=>clearTimeout(s)),e.clear(),t.forEach(s=>{s&&s.parentNode&&s.parentNode.removeChild(s)}),t.clear()}}}function K(A){A.registerServiceWorker=async function(t="/sw.js"){if(typeof navigator>"u"||!("serviceWorker"in navigator))return console.warn("[Dolphin PWA] Service Workers are not supported in this browser."),null;try{let e=await navigator.serviceWorker.register(t);return console.log("[Dolphin PWA] Service Worker registered successfully with scope:",e.scope),e}catch(e){return console.error("[Dolphin PWA] Service Worker registration failed:",e),null}},A.subscribePushNotifications=async function(t){if(typeof window>"u"||!("serviceWorker"in navigator)||!("PushManager"in window))return console.warn("[Dolphin PWA] Push notifications are not supported in this browser."),null;try{let e=await navigator.serviceWorker.ready,n=await e.pushManager.getSubscription();if(!n){let s="=".repeat((4-t.length%4)%4),i=(t+s).replace(/\-/g,"+").replace(/_/g,"/"),a=window.atob(i),l=new Uint8Array(a.length);for(let _=0;_<a.length;++_)l[_]=a.charCodeAt(_);n=await e.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:l})}return console.log("[Dolphin PWA] Subscribed to push notifications:",n),n}catch(e){return console.error("[Dolphin PWA] Push notification subscription failed:",e),null}}}var O=class{static render(t){if(typeof document>"u")throw new Error("DolphinTestUtils.render requires a DOM document environment to execute.");let e=document.createElement("div");return e.innerHTML=t,document.body.appendChild(e),{container:e,find:n=>e.querySelector(n),fireEvent:(n,s)=>{let i=document.createEvent("Event");i.initEvent(s,!0,!0),n.dispatchEvent(i)}}}static mockWebSocket(){let t=[],e={readyState:1,send:n=>{t.push(n)},close:jest.fn(),onopen:jest.fn(),onmessage:jest.fn(),onclose:jest.fn(),onerror:jest.fn(),sentMessages:t};return global.WebSocket=class{static OPEN=1;readyState=e.readyState;send=e.send;close=e.close;set onopen(n){e.onopen=n}get onopen(){return e.onopen}set onmessage(n){e.onmessage=n}get onmessage(){return e.onmessage}set onclose(n){e.onclose=n}get getonclose(){return e.onclose}constructor(){setTimeout(()=>e.onopen&&e.onopen(),0)}},e}static simulateClick(t){let e={target:t,preventDefault:jest.fn(),stopPropagation:jest.fn()};(global.document._listeners?.click||[]).forEach(s=>s(e))}static simulateChange(t,e){t.value=e;let n={target:t,preventDefault:jest.fn(),stopPropagation:jest.fn()};(global.document._listeners?.change||[]).forEach(i=>i(n))}};function X(A){A.testing=O}U(C.prototype);H(C.prototype);F(C.prototype);W(C.prototype);j(C.prototype);B(C.prototype);V(C.prototype);z(C.prototype);K(C.prototype);X(C.prototype);typeof window<"u"&&(window.DolphinClient=C,document.addEventListener("DOMContentLoaded",()=>{if(!window.dolphin){let A=document.querySelector('script[src*="dolphin-client"]'),t=A?A.getAttribute("data-debug")==="true":!1,e=new C(void 0,void 0,{debug:t});window.dolphin=e,t&&(console.log("%c\u{1F42C} [Dolphin Client] Auto-initialized local reactive engine!","color: #06b6d4; font-weight: bold; font-size: 14px;"),console.log('%c\u{1F449} Tip: You can access the client instance via "window.dolphin" in console.',"color: #94a3b8; font-style: italic;")),document.querySelector('[data-store-write="app.username"]')&&e.setStoreState("app","username","\u0928\u092E\u0938\u094D\u0924\u0947 \u0938\u093E\u0925\u0940!")}}));return st(rt);})();
|
|
37
|
+
`,document.head.appendChild(n)}}}var H=class{client;db;isOnline;memoryCache=new Map;memoryMutations=[];constructor(t){this.client=t,this.isOnline=typeof window<"u"&&typeof navigator<"u"?navigator.onLine:!0,this.initDB(),this.setupNetworkListeners()}initDB(){if(!(typeof indexedDB>"u"))try{let t=indexedDB.open("dolphin_offline",1);t.onupgradeneeded=e=>{let s=e.target.result;s.objectStoreNames.contains("cache")||s.createObjectStore("cache"),s.objectStoreNames.contains("mutations")||s.createObjectStore("mutations",{keyPath:"id",autoIncrement:!0})},t.onsuccess=e=>{this.db=e.target.result,this.isOnline&&this.syncMutations()}}catch(t){console.warn("[Dolphin Offline] Failed to initialize IndexedDB:",t)}}setupNetworkListeners(){typeof window>"u"||(this.client.addDomListener(window,"online",()=>{this.isOnline=!0,this.client._dispatch("network:status",{online:!0}),this.syncMutations()}),this.client.addDomListener(window,"offline",()=>{this.isOnline=!1,this.client._dispatch("network:status",{online:!1})}))}async getCache(t){return this.db?new Promise(e=>{try{let r=this.db.transaction("cache","readonly").objectStore("cache").get(t);r.onsuccess=()=>e(r.result?r.result.data:null),r.onerror=()=>e(null)}catch{e(null)}}):this.memoryCache.get(t)}async setCache(t,e){if(!this.db){this.memoryCache.set(t,e);return}return new Promise(s=>{try{let i=this.db.transaction("cache","readwrite");i.objectStore("cache").put({data:e,timestamp:Date.now()},t),i.oncomplete=()=>s(),i.onerror=()=>{console.warn("[Dolphin Offline] setCache write failed for key:",t),s()}}catch{s()}})}async queueMutation(t,e,s){let i={method:t,path:e,payload:s,timestamp:Date.now()};if(!this.db){this.memoryMutations.push(i);return}return new Promise(r=>{try{let a=this.db.transaction("mutations","readwrite");a.objectStore("mutations").add(i),a.oncomplete=()=>r(),a.onerror=()=>{console.warn("[Dolphin Offline] queueMutation write failed:",t,e),this.memoryMutations.push(i),r()}}catch{r()}})}async getMutations(){return this.db?new Promise(t=>{try{let i=this.db.transaction("mutations","readonly").objectStore("mutations").getAll();i.onsuccess=()=>t(i.result||[]),i.onerror=()=>t([])}catch{t([])}}):[...this.memoryMutations]}async removeMutation(t){if(!this.db){this.memoryMutations=this.memoryMutations.filter(e=>e.id!==t);return}return new Promise(e=>{try{let s=this.db.transaction("mutations","readwrite");s.objectStore("mutations").delete(t),s.oncomplete=()=>e(),s.onerror=()=>{console.warn("[Dolphin Offline] removeMutation failed for id:",t),e()}}catch{e()}})}async syncMutations(){let t=await this.getMutations();if(t.length!==0){console.log(`[Dolphin Offline] Syncing ${t.length} queued mutations...`);for(let e of t)try{await this.client.api.requestDirect(e.method,e.path,e.payload),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift()}catch(s){if(console.error(`[Dolphin Offline] Sync failed for mutation ${e.method} ${e.path}:`,s),s&&s.status&&s.status>=400&&s.status<500)console.warn("[Dolphin Offline] Discarding invalid mutation."),e.id!==void 0?await this.removeMutation(e.id):this.memoryMutations.shift();else break}}}};function W(A){A._initOffline=function(){this.offline=new H(this)}}function it(A,t,e){let s=t.split(",");for(let i of s){let r=i.trim().split(":"),a=r[0],d=r[1];if(a==="required"){if(!A||A.trim()==="")return"This field is required"}else if(a==="email"){if(A&&A.trim()!==""&&!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(A))return"Please enter a valid email address"}else if(a==="min"){let E=parseInt(d,10);if(!A||A.length<E)return`Must be at least ${E} characters`}else if(a==="match"&&e&&A!==e[d])return`Must match ${d}`}return null}function j(A){A.validateField=it}function z(A){A.animateElement=function(t,e,s=300){if(typeof t.animate!="function"){t.classList.add(e),setTimeout(()=>t.classList.remove(e),s);return}e==="fade-in"?t.animate([{opacity:0,transform:"translateY(10px)"},{opacity:1,transform:"translateY(0)"}],{duration:s,easing:"ease-out"}):e==="fade-out"&&t.animate([{opacity:1,transform:"translateY(0)"},{opacity:0,transform:"translateY(10px)"}],{duration:s,easing:"ease-in"})},A.staggerListItems=function(t,e,s=50){if(typeof document>"u")return;t.querySelectorAll(e).forEach((r,a)=>{r.style.animationDelay=`${a*s}ms`,r.classList.add("staggered-item")})}}function V(A){A._initA11y=function(){typeof document>"u"||(this.addDomListener(document,"keydown",t=>{if(t.key!=="Tab")return;document.querySelectorAll("[data-rt-a11y-focus-trap]").forEach(s=>{if(s.style.display==="none"||s.hasAttribute("aria-hidden")&&s.getAttribute("aria-hidden")==="true")return;let r=Array.from(s.querySelectorAll('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]'));if(r.length===0)return;let a=r[0],d=r[r.length-1];t.shiftKey?document.activeElement===a&&(d.focus(),t.preventDefault()):document.activeElement===d&&(a.focus(),t.preventDefault())})}),this.addDomListener(document,"keydown",t=>{if(!["ArrowUp","ArrowDown","Enter"].includes(t.key))return;document.querySelectorAll("[data-rt-keynav]").forEach(s=>{let i=Array.from(s.children);if(i.length===0)return;let r=i.findIndex(a=>a.classList.contains("active")||document.activeElement===a);t.key==="ArrowDown"?(r=(r+1)%i.length,i[r].focus(),i.forEach((a,d)=>{d===r?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="ArrowUp"?(r=(r-1+i.length)%i.length,i[r].focus(),i.forEach((a,d)=>{d===r?a.classList.add("active"):a.classList.remove("active")}),t.preventDefault()):t.key==="Enter"&&r!==-1&&(i[r].click(),t.preventDefault())})}))},A.autoAriaModal=function(t,e){e?(t.setAttribute("role","dialog"),t.setAttribute("aria-modal","true"),t.setAttribute("aria-hidden","false"),t.focus()):t.setAttribute("aria-hidden","true")}}function K(A){A._initI18n=function(){if(this.i18n=this.i18n||{locale:"en",dicts:{}},typeof document>"u")return;if(document.querySelectorAll("[data-i18n-dict]").forEach(e=>{let s=e.getAttribute("data-i18n-dict");if(s)try{let i=JSON.parse(e.textContent||"{}");this.i18n.dicts[s]={...this.i18n.dicts[s]||{},...i}}catch(i){console.warn("[Dolphin i18n] Failed to parse dictionary for locale:",s,i)}}),!this.i18n.locale&&typeof navigator<"u"){let e=navigator.language.split("-")[0];this.i18n.dicts[e]&&(this.i18n.locale=e)}this.addDomListener(document,"click",e=>{let s=e.target.closest("[data-i18n-switch]");if(s){let i=s.getAttribute("data-i18n-switch");i&&this.setLocale(i)}}),this.translateDOM()},A.setLocale=function(t){this.i18n=this.i18n||{locale:"en",dicts:{}},this.i18n.locale=t,this.translateDOM(),this.publish("i18n/locale",t)},A.translateDOM=function(){if(typeof document>"u")return;this.i18n=this.i18n||{locale:"en",dicts:{}};let t=this.i18n.locale||"en",e=this.i18n.dicts[t]||{};document.querySelectorAll("[data-i18n-key]").forEach(i=>{let r=i.getAttribute("data-i18n-key");if(!r)return;let a=r.split(".").reduce((E,S)=>E?E[S]:null,e);a==null&&(a=r);let d=i.getAttribute("data-i18n-params");if(d)try{let E=JSON.parse(d),S=k=>k.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");for(let k in E){let f=S(k);a=a.replace(new RegExp(`\\{\\{${f}\\}\\}`,"g"),E[k])}}catch{}i.tagName==="INPUT"||i.tagName==="TEXTAREA"?i.placeholder=a:i.textContent=a})}}function X(A){A._initDragDrop=function(){typeof document>"u"||(this.addDomListener(document,"dragstart",t=>{let e=t.target.closest("[data-drag]");if(!e)return;let s=e.getAttribute("data-drag");s&&(t.dataTransfer.setData("text/plain",s),t.dataTransfer.effectAllowed="move",e.classList.add("dragging"))}),this.addDomListener(document,"dragend",t=>{let e=t.target.closest("[data-drag]");e&&e.classList.remove("dragging")}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-drop]");e&&(t.preventDefault(),e.classList.add("drag-over"))}),this.addDomListener(document,"dragleave",t=>{let e=t.target.closest("[data-drop]");e&&e.classList.remove("drag-over")}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-drop]");if(!e)return;t.preventDefault(),e.classList.remove("drag-over");let s=e.getAttribute("data-drop"),i=t.dataTransfer.getData("text/plain");if(s&&i)try{let r=JSON.parse(i);this.publish(s,r)}catch{this.publish(s,{value:i})}}),this.addDomListener(document,"dragover",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;t.preventDefault();let s=e.querySelector(".dragging");if(!s)return;let r=Array.from(e.querySelectorAll("[data-drag]:not(.dragging)")).find(a=>{let d=a.getBoundingClientRect();return t.clientY-d.top-d.height/2<0});r?e.insertBefore(s,r):e.appendChild(s)}),this.addDomListener(document,"drop",t=>{let e=t.target.closest("[data-sortable]");if(!e)return;let s=e.getAttribute("data-sortable");if(!s)return;let r=Array.from(e.querySelectorAll("[data-drag]")).map((a,d)=>{let E=a.getAttribute("data-drag");try{return{index:d,payload:JSON.parse(E||"{}")}}catch{return{index:d,payload:E}}});this.publish(s,r)}))}}function J(A){A._initCollab=function(){if(typeof document>"u")return;let t=new Map,e=new Map,s=5e3;this.addDomListener(document,"mousemove",i=>{document.querySelectorAll("[data-rt-cursor-share]").forEach(a=>{let d=a.getAttribute("data-rt-cursor-share");if(!d)return;let E=a.getBoundingClientRect(),S=(i.clientX-E.left)/E.width,k=(i.clientY-E.top)/E.height,f=Date.now();(!a._lastSent||f-a._lastSent>50)&&(a._lastSent=f,this.pubPush(`collab/${d}/cursor/${this.deviceId}`,{deviceId:this.deviceId,x:S,y:k}))})}),this.addDomListener(document,"input",i=>{let r=i.target.getAttribute("data-rt-typing");if(!r)return;let a=r,d=E=>{this.pubPush(`collab/${a}/typing/${this.deviceId}`,{deviceId:this.deviceId,typing:E})};i.target._isTyping||(i.target._isTyping=!0,d(!0)),i.target._typingTimer&&clearTimeout(i.target._typingTimer),i.target._typingTimer=setTimeout(()=>{i.target._isTyping=!1,i.target._typingTimer=null,d(!1)},2e3)}),this.addDomListener(document,"input",i=>{let r=i.target.getAttribute("data-rt-crdt");if(!r)return;let a=r,d=i.target.value,E=Date.now();this.publish(`collab/${a}/crdt`,{deviceId:this.deviceId,value:d,timestamp:E,cursorPos:i.target.selectionStart})}),this.subscribe("collab/+/cursor/+",(i,r)=>{let a=r.split("/"),d=a[1],E=a[3];if(E===this.deviceId)return;let S=document.querySelector(`[data-rt-cursor-share="${d}"]`);if(!S)return;let k=`${d}::${E}`,f=t.get(k);(!f||!document.contains(f))&&(f=document.createElement("div"),f.className=`rt-cursor rt-cursor-${E}`,f.style.position="absolute",f.style.width="10px",f.style.height="10px",f.style.borderRadius="50%",f.style.backgroundColor="#"+Math.floor(Math.random()*16777215).toString(16).padStart(6,"0"),f.style.pointerEvents="none",S.appendChild(f),t.set(k,f));let u=S.getBoundingClientRect();f.style.left=i.x*u.width+"px",f.style.top=i.y*u.height+"px",e.has(k)&&clearTimeout(e.get(k)),e.set(k,setTimeout(()=>{let l=t.get(k);l&&l.parentNode&&l.parentNode.removeChild(l),t.delete(k),e.delete(k)},s))}),this.subscribe("collab/+/crdt",(i,r)=>{if(i.deviceId===this.deviceId)return;let d=r.split("/")[1];document.querySelectorAll(`[data-rt-crdt="${d}"]`).forEach(S=>{if(!S._lastUpdate||i.timestamp>S._lastUpdate){S._lastUpdate=i.timestamp;let k=S.selectionStart;S.value=i.value,document.activeElement===S&&S.setSelectionRange(k,k)}})}),this._collabCleanup=()=>{e.forEach(i=>clearTimeout(i)),e.clear(),t.forEach(i=>{i&&i.parentNode&&i.parentNode.removeChild(i)}),t.clear()}}}function Q(A){A.registerServiceWorker=async function(t="/sw.js"){if(typeof navigator>"u"||!("serviceWorker"in navigator))return console.warn("[Dolphin PWA] Service Workers are not supported in this browser."),null;try{let e=await navigator.serviceWorker.register(t);return console.log("[Dolphin PWA] Service Worker registered successfully with scope:",e.scope),e}catch(e){return console.error("[Dolphin PWA] Service Worker registration failed:",e),null}},A.subscribePushNotifications=async function(t){if(typeof window>"u"||!("serviceWorker"in navigator)||!("PushManager"in window))return console.warn("[Dolphin PWA] Push notifications are not supported in this browser."),null;try{let e=await navigator.serviceWorker.ready,s=await e.pushManager.getSubscription();if(!s){let i="=".repeat((4-t.length%4)%4),r=(t+i).replace(/\-/g,"+").replace(/_/g,"/"),a=window.atob(r),d=new Uint8Array(a.length);for(let E=0;E<a.length;++E)d[E]=a.charCodeAt(E);s=await e.pushManager.subscribe({userVisibleOnly:!0,applicationServerKey:d})}return console.log("[Dolphin PWA] Subscribed to push notifications:",s),s}catch(e){return console.error("[Dolphin PWA] Push notification subscription failed:",e),null}}}var F=class{static render(t){if(typeof document>"u")throw new Error("DolphinTestUtils.render requires a DOM document environment to execute.");let e=document.createElement("div");return e.innerHTML=t,document.body.appendChild(e),{container:e,find:s=>e.querySelector(s),fireEvent:(s,i)=>{let r=document.createEvent("Event");r.initEvent(i,!0,!0),s.dispatchEvent(r)}}}static mockWebSocket(){let t=[],e={readyState:1,send:s=>{t.push(s)},close:jest.fn(),onopen:jest.fn(),onmessage:jest.fn(),onclose:jest.fn(),onerror:jest.fn(),sentMessages:t};return global.WebSocket=class{static OPEN=1;readyState=e.readyState;send=e.send;close=e.close;set onopen(s){e.onopen=s}get onopen(){return e.onopen}set onmessage(s){e.onmessage=s}get onmessage(){return e.onmessage}set onclose(s){e.onclose=s}get getonclose(){return e.onclose}constructor(){setTimeout(()=>e.onopen&&e.onopen(),0)}},e}static simulateClick(t){let e={target:t,preventDefault:jest.fn(),stopPropagation:jest.fn()};(global.document._listeners?.click||[]).forEach(i=>i(e))}static simulateChange(t,e){t.value=e;let s={target:t,preventDefault:jest.fn(),stopPropagation:jest.fn()};(global.document._listeners?.change||[]).forEach(r=>r(s))}};function Y(A){A.testing=F}B(C.prototype);W(C.prototype);j(C.prototype);z(C.prototype);V(C.prototype);K(C.prototype);X(C.prototype);J(C.prototype);Q(C.prototype);Y(C.prototype);typeof window<"u"&&(window.DolphinClient=C,document.addEventListener("DOMContentLoaded",()=>{if(!window.dolphin){let A=document.querySelector('script[src*="dolphin-client"]'),t=A?A.getAttribute("data-debug")==="true":!1,e=new C(void 0,void 0,{debug:t});window.dolphin=e,t&&(console.log("%c\u{1F42C} [Dolphin Client] Auto-initialized local reactive engine!","color: #06b6d4; font-weight: bold; font-size: 14px;"),console.log('%c\u{1F449} Tip: You can access the client instance via "window.dolphin" in console.',"color: #94a3b8; font-style: italic;")),document.querySelector('[data-store-write="app.username"]')&&e.setStoreState("app","username","\u0928\u092E\u0938\u094D\u0924\u0947 \u0938\u093E\u0925\u0940!")}}));return st(rt);})();
|
package/dist/index.cjs
CHANGED
|
@@ -41,7 +41,7 @@ var APIHandler = class {
|
|
|
41
41
|
target.patch = (pathOrBody, bodyOrOptions, options) => typeof pathOrBody === "string" ? this.request("PATCH", pathOrBody, bodyOrOptions, options) : this.request("PATCH", joined, pathOrBody, bodyOrOptions);
|
|
42
42
|
target.del = (pathOrOptions, options) => typeof pathOrOptions === "string" ? this.request("DELETE", pathOrOptions, null, options) : this.request("DELETE", joined, null, pathOrOptions);
|
|
43
43
|
target.request = (method, subPath, body, options) => {
|
|
44
|
-
const finalPath = subPath ? `${joined}/${subPath.startsWith("/") ? subPath.slice(1) : subPath}` : joined;
|
|
44
|
+
const finalPath = subPath ? joined ? `${joined}/${subPath.startsWith("/") ? subPath.slice(1) : subPath}` : subPath : joined;
|
|
45
45
|
return this.request(method, finalPath, body, options);
|
|
46
46
|
};
|
|
47
47
|
target.requestDirect = (method, path, body, options) => {
|
|
@@ -225,8 +225,9 @@ var APIHandler = class {
|
|
|
225
225
|
const _isRetry = options._isRetry === true;
|
|
226
226
|
let finalMethod = method.toUpperCase();
|
|
227
227
|
let finalBody = body;
|
|
228
|
+
const hasBody = !["GET", "HEAD"].includes(finalMethod);
|
|
228
229
|
const headers = {
|
|
229
|
-
"Content-Type": "application/json",
|
|
230
|
+
...hasBody ? { "Content-Type": "application/json" } : {},
|
|
230
231
|
...options.headers || {}
|
|
231
232
|
};
|
|
232
233
|
if (["PUT", "PATCH", "DELETE"].includes(finalMethod)) {
|
|
@@ -1376,6 +1377,86 @@ function attachDOMBinding(clientProto) {
|
|
|
1376
1377
|
console.error("%cFailed Expression:", "color: #3b82f6; font-style: italic;", expression);
|
|
1377
1378
|
}
|
|
1378
1379
|
};
|
|
1380
|
+
clientProto._showAlert = function(id, duration) {
|
|
1381
|
+
if (typeof document === "undefined") return;
|
|
1382
|
+
const el = document.getElementById(id) || document.querySelector(`[id="${id}"]`);
|
|
1383
|
+
if (!el) return;
|
|
1384
|
+
el.removeAttribute("hidden");
|
|
1385
|
+
el.style.display = "";
|
|
1386
|
+
if (duration && duration > 0) {
|
|
1387
|
+
setTimeout(() => {
|
|
1388
|
+
el.setAttribute("hidden", "");
|
|
1389
|
+
}, duration);
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
clientProto._showToast = function(message, type = "success") {
|
|
1393
|
+
if (typeof document === "undefined") return;
|
|
1394
|
+
const colors = {
|
|
1395
|
+
success: { bg: "rgba(16,185,129,0.15)", border: "#10b981", icon: "\u2705" },
|
|
1396
|
+
error: { bg: "rgba(239,68,68,0.15)", border: "#ef4444", icon: "\u274C" },
|
|
1397
|
+
info: { bg: "rgba(59,130,246,0.15)", border: "#3b82f6", icon: "\u2139\uFE0F" }
|
|
1398
|
+
};
|
|
1399
|
+
const c = colors[type] || colors.success;
|
|
1400
|
+
const toast = document.createElement("div");
|
|
1401
|
+
toast.setAttribute("data-dolphin-toast", "");
|
|
1402
|
+
const existing = document.querySelectorAll("[data-dolphin-toast]");
|
|
1403
|
+
const offset = existing.length * 72;
|
|
1404
|
+
toast.style.cssText = [
|
|
1405
|
+
"position:fixed",
|
|
1406
|
+
`bottom:${24 + offset}px`,
|
|
1407
|
+
"right:24px",
|
|
1408
|
+
"z-index:2147483647",
|
|
1409
|
+
`background:${c.bg}`,
|
|
1410
|
+
`border:1px solid ${c.border}`,
|
|
1411
|
+
"color:#fff",
|
|
1412
|
+
"padding:14px 20px",
|
|
1413
|
+
"border-radius:14px",
|
|
1414
|
+
"font-size:14px",
|
|
1415
|
+
"font-weight:600",
|
|
1416
|
+
"font-family:system-ui,sans-serif",
|
|
1417
|
+
"box-shadow:0 8px 32px rgba(0,0,0,0.4)",
|
|
1418
|
+
"display:flex",
|
|
1419
|
+
"align-items:center",
|
|
1420
|
+
"gap:10px",
|
|
1421
|
+
"max-width:380px",
|
|
1422
|
+
"word-break:break-word",
|
|
1423
|
+
"transform:translateY(80px)",
|
|
1424
|
+
"opacity:0",
|
|
1425
|
+
"transition:transform 0.35s cubic-bezier(0.34,1.56,0.64,1),opacity 0.3s ease",
|
|
1426
|
+
"pointer-events:auto",
|
|
1427
|
+
"backdrop-filter:blur(12px)"
|
|
1428
|
+
].join(";");
|
|
1429
|
+
toast.innerHTML = `<span style="font-size:18px">${c.icon}</span><span>${message}</span>`;
|
|
1430
|
+
document.body.appendChild(toast);
|
|
1431
|
+
const restack = () => {
|
|
1432
|
+
const remaining = document.querySelectorAll("[data-dolphin-toast]");
|
|
1433
|
+
remaining.forEach((el, i) => {
|
|
1434
|
+
el.style.bottom = `${24 + i * 72}px`;
|
|
1435
|
+
});
|
|
1436
|
+
};
|
|
1437
|
+
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
1438
|
+
raf(() => raf(() => {
|
|
1439
|
+
toast.style.transform = "translateY(0)";
|
|
1440
|
+
toast.style.opacity = "1";
|
|
1441
|
+
}));
|
|
1442
|
+
const removeToast = () => {
|
|
1443
|
+
clearTimeout(toast._removeTimer);
|
|
1444
|
+
if (toast.parentNode) {
|
|
1445
|
+
toast.parentNode.removeChild(toast);
|
|
1446
|
+
restack();
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
const hideTimer = setTimeout(() => {
|
|
1450
|
+
toast.style.transform = "translateY(80px)";
|
|
1451
|
+
toast.style.opacity = "0";
|
|
1452
|
+
toast._removeTimer = setTimeout(removeToast, 400);
|
|
1453
|
+
}, 3500);
|
|
1454
|
+
toast._hideTimer = hideTimer;
|
|
1455
|
+
toast.addEventListener("click", () => {
|
|
1456
|
+
clearTimeout(toast._hideTimer);
|
|
1457
|
+
removeToast();
|
|
1458
|
+
}, { once: true });
|
|
1459
|
+
};
|
|
1379
1460
|
clientProto._initDOMBinding = function() {
|
|
1380
1461
|
if (this._domInitialized) return;
|
|
1381
1462
|
this._domInitialized = true;
|
|
@@ -1474,6 +1555,11 @@ function attachDOMBinding(clientProto) {
|
|
|
1474
1555
|
resolvedTopic = resolvedTopic.replace(new RegExp(`\\{\\{${escapedK}\\}\\}`, "g"), parentCtx[k] !== void 0 && parentCtx[k] !== null ? parentCtx[k] : "");
|
|
1475
1556
|
}
|
|
1476
1557
|
this.publish(resolvedTopic, data);
|
|
1558
|
+
const rtSuccessId = e.target.getAttribute("data-rt-api-success");
|
|
1559
|
+
if (rtSuccessId) {
|
|
1560
|
+
const rtSuccessEl = document.getElementById(rtSuccessId);
|
|
1561
|
+
if (rtSuccessEl) this._showToast(rtSuccessEl.textContent || rtSuccessEl.innerText || "", "success");
|
|
1562
|
+
}
|
|
1477
1563
|
} else if (apiTarget) {
|
|
1478
1564
|
let resolvedTarget = apiTarget;
|
|
1479
1565
|
for (const k in parentCtx) {
|
|
@@ -1490,16 +1576,40 @@ function attachDOMBinding(clientProto) {
|
|
|
1490
1576
|
const result = await this.api.request(method, path, data);
|
|
1491
1577
|
const resultBind = e.target.getAttribute("data-api-result");
|
|
1492
1578
|
if (resultBind) this._updateDOM(resultBind, result);
|
|
1579
|
+
const successToast = e.target.getAttribute("data-api-toast");
|
|
1580
|
+
if (successToast) this._showToast(successToast, "success");
|
|
1581
|
+
const successElId = e.target.getAttribute("data-rt-api-success");
|
|
1582
|
+
if (successElId) {
|
|
1583
|
+
const duration = parseInt(e.target.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1584
|
+
this._showAlert(successElId, duration);
|
|
1585
|
+
const errElId = e.target.getAttribute("data-rt-api-error");
|
|
1586
|
+
if (errElId) {
|
|
1587
|
+
const errEl = document.getElementById(errElId);
|
|
1588
|
+
if (errEl) errEl.setAttribute("hidden", "");
|
|
1589
|
+
}
|
|
1590
|
+
}
|
|
1493
1591
|
const redirect = e.target.getAttribute("data-api-redirect");
|
|
1494
1592
|
if (redirect) window.location.href = redirect;
|
|
1495
1593
|
if (e.target.hasAttribute("data-api-reload")) window.location.reload();
|
|
1496
1594
|
} catch (err) {
|
|
1497
1595
|
console.error("[Dolphin] API Submit Error:", err);
|
|
1596
|
+
const errorToast = e.target.getAttribute("data-api-error-toast");
|
|
1597
|
+
if (errorToast) this._showToast(errorToast, "error");
|
|
1598
|
+
const errorElId = e.target.getAttribute("data-rt-api-error");
|
|
1599
|
+
if (errorElId) {
|
|
1600
|
+
const duration = parseInt(e.target.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1601
|
+
this._showAlert(errorElId, duration);
|
|
1602
|
+
const sucElId = e.target.getAttribute("data-rt-api-success");
|
|
1603
|
+
if (sucElId) {
|
|
1604
|
+
const sucEl = document.getElementById(sucElId);
|
|
1605
|
+
if (sucEl) sucEl.setAttribute("hidden", "");
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1498
1608
|
}
|
|
1499
1609
|
}
|
|
1500
1610
|
}
|
|
1501
1611
|
});
|
|
1502
|
-
const INTERACTION_EVENTS = ["click", "change", "
|
|
1612
|
+
const INTERACTION_EVENTS = ["click", "change", "input", "keydown", "keyup", "dblclick", "focus", "blur", "mouseenter", "mouseleave"];
|
|
1503
1613
|
INTERACTION_EVENTS.forEach((evtName) => {
|
|
1504
1614
|
this.addDomListener(document, evtName, async (e) => {
|
|
1505
1615
|
if (!e.target || !e.target.closest) return;
|
|
@@ -1530,7 +1640,12 @@ function attachDOMBinding(clientProto) {
|
|
|
1530
1640
|
const apiTarget = apiBtn.getAttribute(`data-api-${evtName}`);
|
|
1531
1641
|
const actionData = apiBtn.getAttribute("data-api-payload");
|
|
1532
1642
|
const parentCtx = this.getClosestContext(apiBtn) || {};
|
|
1533
|
-
|
|
1643
|
+
let resolvedApiTarget = apiTarget;
|
|
1644
|
+
for (const k in parentCtx) {
|
|
1645
|
+
const escapedK = escapeRegExp(k);
|
|
1646
|
+
resolvedApiTarget = resolvedApiTarget.replace(new RegExp(`\\{\\{${escapedK}\\}\\}`, "g"), parentCtx[k] !== void 0 && parentCtx[k] !== null ? parentCtx[k] : "");
|
|
1647
|
+
}
|
|
1648
|
+
const parts = resolvedApiTarget.trim().split(" ");
|
|
1534
1649
|
const method = parts.length > 1 ? parts[0].toUpperCase() : "POST";
|
|
1535
1650
|
const path = parts.length > 1 ? parts[1] : parts[0];
|
|
1536
1651
|
let payload = null;
|
|
@@ -1550,11 +1665,35 @@ function attachDOMBinding(clientProto) {
|
|
|
1550
1665
|
const result = await this.api.request(method, path, payload);
|
|
1551
1666
|
const resultBind = apiBtn.getAttribute("data-api-result");
|
|
1552
1667
|
if (resultBind) this._updateDOM(resultBind, result);
|
|
1668
|
+
const successToast = apiBtn.getAttribute("data-api-toast");
|
|
1669
|
+
if (successToast) this._showToast(successToast, "success");
|
|
1670
|
+
const successElId = apiBtn.getAttribute("data-rt-api-success");
|
|
1671
|
+
if (successElId) {
|
|
1672
|
+
const duration = parseInt(apiBtn.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1673
|
+
this._showAlert(successElId, duration);
|
|
1674
|
+
const errElId = apiBtn.getAttribute("data-rt-api-error");
|
|
1675
|
+
if (errElId) {
|
|
1676
|
+
const errEl = document.getElementById(errElId);
|
|
1677
|
+
if (errEl) errEl.setAttribute("hidden", "");
|
|
1678
|
+
}
|
|
1679
|
+
}
|
|
1553
1680
|
const redirect = apiBtn.getAttribute("data-api-redirect");
|
|
1554
1681
|
if (redirect) window.location.href = redirect;
|
|
1555
1682
|
if (apiBtn.hasAttribute("data-api-reload")) window.location.reload();
|
|
1556
1683
|
} catch (err) {
|
|
1557
1684
|
console.error(`[Dolphin] API ${evtName} Error:`, err);
|
|
1685
|
+
const errorToast = apiBtn.getAttribute("data-api-error-toast");
|
|
1686
|
+
if (errorToast) this._showToast(errorToast, "error");
|
|
1687
|
+
const errorElId = apiBtn.getAttribute("data-rt-api-error");
|
|
1688
|
+
if (errorElId) {
|
|
1689
|
+
const duration = parseInt(apiBtn.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1690
|
+
this._showAlert(errorElId, duration);
|
|
1691
|
+
const sucElId = apiBtn.getAttribute("data-rt-api-success");
|
|
1692
|
+
if (sucElId) {
|
|
1693
|
+
const sucEl = document.getElementById(sucElId);
|
|
1694
|
+
if (sucEl) sucEl.setAttribute("hidden", "");
|
|
1695
|
+
}
|
|
1696
|
+
}
|
|
1558
1697
|
}
|
|
1559
1698
|
}
|
|
1560
1699
|
const storeActionBtn = e.target.closest(`[data-store-${evtName}]`);
|
package/dist/index.js
CHANGED
|
@@ -16,7 +16,7 @@ var APIHandler = class {
|
|
|
16
16
|
target.patch = (pathOrBody, bodyOrOptions, options) => typeof pathOrBody === "string" ? this.request("PATCH", pathOrBody, bodyOrOptions, options) : this.request("PATCH", joined, pathOrBody, bodyOrOptions);
|
|
17
17
|
target.del = (pathOrOptions, options) => typeof pathOrOptions === "string" ? this.request("DELETE", pathOrOptions, null, options) : this.request("DELETE", joined, null, pathOrOptions);
|
|
18
18
|
target.request = (method, subPath, body, options) => {
|
|
19
|
-
const finalPath = subPath ? `${joined}/${subPath.startsWith("/") ? subPath.slice(1) : subPath}` : joined;
|
|
19
|
+
const finalPath = subPath ? joined ? `${joined}/${subPath.startsWith("/") ? subPath.slice(1) : subPath}` : subPath : joined;
|
|
20
20
|
return this.request(method, finalPath, body, options);
|
|
21
21
|
};
|
|
22
22
|
target.requestDirect = (method, path, body, options) => {
|
|
@@ -200,8 +200,9 @@ var APIHandler = class {
|
|
|
200
200
|
const _isRetry = options._isRetry === true;
|
|
201
201
|
let finalMethod = method.toUpperCase();
|
|
202
202
|
let finalBody = body;
|
|
203
|
+
const hasBody = !["GET", "HEAD"].includes(finalMethod);
|
|
203
204
|
const headers = {
|
|
204
|
-
"Content-Type": "application/json",
|
|
205
|
+
...hasBody ? { "Content-Type": "application/json" } : {},
|
|
205
206
|
...options.headers || {}
|
|
206
207
|
};
|
|
207
208
|
if (["PUT", "PATCH", "DELETE"].includes(finalMethod)) {
|
|
@@ -1351,6 +1352,86 @@ function attachDOMBinding(clientProto) {
|
|
|
1351
1352
|
console.error("%cFailed Expression:", "color: #3b82f6; font-style: italic;", expression);
|
|
1352
1353
|
}
|
|
1353
1354
|
};
|
|
1355
|
+
clientProto._showAlert = function(id, duration) {
|
|
1356
|
+
if (typeof document === "undefined") return;
|
|
1357
|
+
const el = document.getElementById(id) || document.querySelector(`[id="${id}"]`);
|
|
1358
|
+
if (!el) return;
|
|
1359
|
+
el.removeAttribute("hidden");
|
|
1360
|
+
el.style.display = "";
|
|
1361
|
+
if (duration && duration > 0) {
|
|
1362
|
+
setTimeout(() => {
|
|
1363
|
+
el.setAttribute("hidden", "");
|
|
1364
|
+
}, duration);
|
|
1365
|
+
}
|
|
1366
|
+
};
|
|
1367
|
+
clientProto._showToast = function(message, type = "success") {
|
|
1368
|
+
if (typeof document === "undefined") return;
|
|
1369
|
+
const colors = {
|
|
1370
|
+
success: { bg: "rgba(16,185,129,0.15)", border: "#10b981", icon: "\u2705" },
|
|
1371
|
+
error: { bg: "rgba(239,68,68,0.15)", border: "#ef4444", icon: "\u274C" },
|
|
1372
|
+
info: { bg: "rgba(59,130,246,0.15)", border: "#3b82f6", icon: "\u2139\uFE0F" }
|
|
1373
|
+
};
|
|
1374
|
+
const c = colors[type] || colors.success;
|
|
1375
|
+
const toast = document.createElement("div");
|
|
1376
|
+
toast.setAttribute("data-dolphin-toast", "");
|
|
1377
|
+
const existing = document.querySelectorAll("[data-dolphin-toast]");
|
|
1378
|
+
const offset = existing.length * 72;
|
|
1379
|
+
toast.style.cssText = [
|
|
1380
|
+
"position:fixed",
|
|
1381
|
+
`bottom:${24 + offset}px`,
|
|
1382
|
+
"right:24px",
|
|
1383
|
+
"z-index:2147483647",
|
|
1384
|
+
`background:${c.bg}`,
|
|
1385
|
+
`border:1px solid ${c.border}`,
|
|
1386
|
+
"color:#fff",
|
|
1387
|
+
"padding:14px 20px",
|
|
1388
|
+
"border-radius:14px",
|
|
1389
|
+
"font-size:14px",
|
|
1390
|
+
"font-weight:600",
|
|
1391
|
+
"font-family:system-ui,sans-serif",
|
|
1392
|
+
"box-shadow:0 8px 32px rgba(0,0,0,0.4)",
|
|
1393
|
+
"display:flex",
|
|
1394
|
+
"align-items:center",
|
|
1395
|
+
"gap:10px",
|
|
1396
|
+
"max-width:380px",
|
|
1397
|
+
"word-break:break-word",
|
|
1398
|
+
"transform:translateY(80px)",
|
|
1399
|
+
"opacity:0",
|
|
1400
|
+
"transition:transform 0.35s cubic-bezier(0.34,1.56,0.64,1),opacity 0.3s ease",
|
|
1401
|
+
"pointer-events:auto",
|
|
1402
|
+
"backdrop-filter:blur(12px)"
|
|
1403
|
+
].join(";");
|
|
1404
|
+
toast.innerHTML = `<span style="font-size:18px">${c.icon}</span><span>${message}</span>`;
|
|
1405
|
+
document.body.appendChild(toast);
|
|
1406
|
+
const restack = () => {
|
|
1407
|
+
const remaining = document.querySelectorAll("[data-dolphin-toast]");
|
|
1408
|
+
remaining.forEach((el, i) => {
|
|
1409
|
+
el.style.bottom = `${24 + i * 72}px`;
|
|
1410
|
+
});
|
|
1411
|
+
};
|
|
1412
|
+
const raf = typeof requestAnimationFrame !== "undefined" ? requestAnimationFrame : (cb) => setTimeout(cb, 0);
|
|
1413
|
+
raf(() => raf(() => {
|
|
1414
|
+
toast.style.transform = "translateY(0)";
|
|
1415
|
+
toast.style.opacity = "1";
|
|
1416
|
+
}));
|
|
1417
|
+
const removeToast = () => {
|
|
1418
|
+
clearTimeout(toast._removeTimer);
|
|
1419
|
+
if (toast.parentNode) {
|
|
1420
|
+
toast.parentNode.removeChild(toast);
|
|
1421
|
+
restack();
|
|
1422
|
+
}
|
|
1423
|
+
};
|
|
1424
|
+
const hideTimer = setTimeout(() => {
|
|
1425
|
+
toast.style.transform = "translateY(80px)";
|
|
1426
|
+
toast.style.opacity = "0";
|
|
1427
|
+
toast._removeTimer = setTimeout(removeToast, 400);
|
|
1428
|
+
}, 3500);
|
|
1429
|
+
toast._hideTimer = hideTimer;
|
|
1430
|
+
toast.addEventListener("click", () => {
|
|
1431
|
+
clearTimeout(toast._hideTimer);
|
|
1432
|
+
removeToast();
|
|
1433
|
+
}, { once: true });
|
|
1434
|
+
};
|
|
1354
1435
|
clientProto._initDOMBinding = function() {
|
|
1355
1436
|
if (this._domInitialized) return;
|
|
1356
1437
|
this._domInitialized = true;
|
|
@@ -1449,6 +1530,11 @@ function attachDOMBinding(clientProto) {
|
|
|
1449
1530
|
resolvedTopic = resolvedTopic.replace(new RegExp(`\\{\\{${escapedK}\\}\\}`, "g"), parentCtx[k] !== void 0 && parentCtx[k] !== null ? parentCtx[k] : "");
|
|
1450
1531
|
}
|
|
1451
1532
|
this.publish(resolvedTopic, data);
|
|
1533
|
+
const rtSuccessId = e.target.getAttribute("data-rt-api-success");
|
|
1534
|
+
if (rtSuccessId) {
|
|
1535
|
+
const rtSuccessEl = document.getElementById(rtSuccessId);
|
|
1536
|
+
if (rtSuccessEl) this._showToast(rtSuccessEl.textContent || rtSuccessEl.innerText || "", "success");
|
|
1537
|
+
}
|
|
1452
1538
|
} else if (apiTarget) {
|
|
1453
1539
|
let resolvedTarget = apiTarget;
|
|
1454
1540
|
for (const k in parentCtx) {
|
|
@@ -1465,16 +1551,40 @@ function attachDOMBinding(clientProto) {
|
|
|
1465
1551
|
const result = await this.api.request(method, path, data);
|
|
1466
1552
|
const resultBind = e.target.getAttribute("data-api-result");
|
|
1467
1553
|
if (resultBind) this._updateDOM(resultBind, result);
|
|
1554
|
+
const successToast = e.target.getAttribute("data-api-toast");
|
|
1555
|
+
if (successToast) this._showToast(successToast, "success");
|
|
1556
|
+
const successElId = e.target.getAttribute("data-rt-api-success");
|
|
1557
|
+
if (successElId) {
|
|
1558
|
+
const duration = parseInt(e.target.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1559
|
+
this._showAlert(successElId, duration);
|
|
1560
|
+
const errElId = e.target.getAttribute("data-rt-api-error");
|
|
1561
|
+
if (errElId) {
|
|
1562
|
+
const errEl = document.getElementById(errElId);
|
|
1563
|
+
if (errEl) errEl.setAttribute("hidden", "");
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1468
1566
|
const redirect = e.target.getAttribute("data-api-redirect");
|
|
1469
1567
|
if (redirect) window.location.href = redirect;
|
|
1470
1568
|
if (e.target.hasAttribute("data-api-reload")) window.location.reload();
|
|
1471
1569
|
} catch (err) {
|
|
1472
1570
|
console.error("[Dolphin] API Submit Error:", err);
|
|
1571
|
+
const errorToast = e.target.getAttribute("data-api-error-toast");
|
|
1572
|
+
if (errorToast) this._showToast(errorToast, "error");
|
|
1573
|
+
const errorElId = e.target.getAttribute("data-rt-api-error");
|
|
1574
|
+
if (errorElId) {
|
|
1575
|
+
const duration = parseInt(e.target.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1576
|
+
this._showAlert(errorElId, duration);
|
|
1577
|
+
const sucElId = e.target.getAttribute("data-rt-api-success");
|
|
1578
|
+
if (sucElId) {
|
|
1579
|
+
const sucEl = document.getElementById(sucElId);
|
|
1580
|
+
if (sucEl) sucEl.setAttribute("hidden", "");
|
|
1581
|
+
}
|
|
1582
|
+
}
|
|
1473
1583
|
}
|
|
1474
1584
|
}
|
|
1475
1585
|
}
|
|
1476
1586
|
});
|
|
1477
|
-
const INTERACTION_EVENTS = ["click", "change", "
|
|
1587
|
+
const INTERACTION_EVENTS = ["click", "change", "input", "keydown", "keyup", "dblclick", "focus", "blur", "mouseenter", "mouseleave"];
|
|
1478
1588
|
INTERACTION_EVENTS.forEach((evtName) => {
|
|
1479
1589
|
this.addDomListener(document, evtName, async (e) => {
|
|
1480
1590
|
if (!e.target || !e.target.closest) return;
|
|
@@ -1505,7 +1615,12 @@ function attachDOMBinding(clientProto) {
|
|
|
1505
1615
|
const apiTarget = apiBtn.getAttribute(`data-api-${evtName}`);
|
|
1506
1616
|
const actionData = apiBtn.getAttribute("data-api-payload");
|
|
1507
1617
|
const parentCtx = this.getClosestContext(apiBtn) || {};
|
|
1508
|
-
|
|
1618
|
+
let resolvedApiTarget = apiTarget;
|
|
1619
|
+
for (const k in parentCtx) {
|
|
1620
|
+
const escapedK = escapeRegExp(k);
|
|
1621
|
+
resolvedApiTarget = resolvedApiTarget.replace(new RegExp(`\\{\\{${escapedK}\\}\\}`, "g"), parentCtx[k] !== void 0 && parentCtx[k] !== null ? parentCtx[k] : "");
|
|
1622
|
+
}
|
|
1623
|
+
const parts = resolvedApiTarget.trim().split(" ");
|
|
1509
1624
|
const method = parts.length > 1 ? parts[0].toUpperCase() : "POST";
|
|
1510
1625
|
const path = parts.length > 1 ? parts[1] : parts[0];
|
|
1511
1626
|
let payload = null;
|
|
@@ -1525,11 +1640,35 @@ function attachDOMBinding(clientProto) {
|
|
|
1525
1640
|
const result = await this.api.request(method, path, payload);
|
|
1526
1641
|
const resultBind = apiBtn.getAttribute("data-api-result");
|
|
1527
1642
|
if (resultBind) this._updateDOM(resultBind, result);
|
|
1643
|
+
const successToast = apiBtn.getAttribute("data-api-toast");
|
|
1644
|
+
if (successToast) this._showToast(successToast, "success");
|
|
1645
|
+
const successElId = apiBtn.getAttribute("data-rt-api-success");
|
|
1646
|
+
if (successElId) {
|
|
1647
|
+
const duration = parseInt(apiBtn.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1648
|
+
this._showAlert(successElId, duration);
|
|
1649
|
+
const errElId = apiBtn.getAttribute("data-rt-api-error");
|
|
1650
|
+
if (errElId) {
|
|
1651
|
+
const errEl = document.getElementById(errElId);
|
|
1652
|
+
if (errEl) errEl.setAttribute("hidden", "");
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1528
1655
|
const redirect = apiBtn.getAttribute("data-api-redirect");
|
|
1529
1656
|
if (redirect) window.location.href = redirect;
|
|
1530
1657
|
if (apiBtn.hasAttribute("data-api-reload")) window.location.reload();
|
|
1531
1658
|
} catch (err) {
|
|
1532
1659
|
console.error(`[Dolphin] API ${evtName} Error:`, err);
|
|
1660
|
+
const errorToast = apiBtn.getAttribute("data-api-error-toast");
|
|
1661
|
+
if (errorToast) this._showToast(errorToast, "error");
|
|
1662
|
+
const errorElId = apiBtn.getAttribute("data-rt-api-error");
|
|
1663
|
+
if (errorElId) {
|
|
1664
|
+
const duration = parseInt(apiBtn.getAttribute("data-rt-alert-duration") || "0", 10);
|
|
1665
|
+
this._showAlert(errorElId, duration);
|
|
1666
|
+
const sucElId = apiBtn.getAttribute("data-rt-api-success");
|
|
1667
|
+
if (sucElId) {
|
|
1668
|
+
const sucEl = document.getElementById(sucElId);
|
|
1669
|
+
if (sucEl) sucEl.setAttribute("hidden", "");
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1533
1672
|
}
|
|
1534
1673
|
}
|
|
1535
1674
|
const storeActionBtn = e.target.closest(`[data-store-${evtName}]`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dolphin-client",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "HTML is back! Hookless, framework-agnostic real-time reactive DOM-binding client for Dolphin Server with WebSockets, WebRTC signaling, and offline REST API fallbacks.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|