web-mojo 2.2.57 → 2.2.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.cjs.js.map +1 -1
- package/dist/admin.es.js +1 -10105
- package/dist/admin.es.js.map +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.es.js +1 -588
- package/dist/auth.es.js.map +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +1 -571
- package/dist/charts.es.js.map +1 -1
- package/dist/chunks/ChatView-D4A9rIX3.js +2 -0
- package/dist/chunks/ChatView-D4A9rIX3.js.map +1 -0
- package/dist/chunks/ChatView-nxaq8aIo.js +2 -0
- package/dist/chunks/ChatView-nxaq8aIo.js.map +1 -0
- package/dist/chunks/Collection-1sPoIFvQ.js +2 -0
- package/dist/chunks/{Collection-DaiL0uGl.js.map → Collection-1sPoIFvQ.js.map} +1 -1
- package/dist/chunks/{Collection-CxbNKOas.js → Collection-DSBRXpwK.js} +2 -2
- package/dist/chunks/{Collection-CxbNKOas.js.map → Collection-DSBRXpwK.js.map} +1 -1
- package/dist/chunks/{ContextMenu-ClwHEbbD.js → ContextMenu-BWy7WqF4.js} +2 -2
- package/dist/chunks/{ContextMenu-ClwHEbbD.js.map → ContextMenu-BWy7WqF4.js.map} +1 -1
- package/dist/chunks/ContextMenu-BvniQz-N.js +3 -0
- package/dist/chunks/{ContextMenu-sgvgSACY.js.map → ContextMenu-BvniQz-N.js.map} +1 -1
- package/dist/chunks/DataView--nUWtq6r.js +2 -0
- package/dist/chunks/{DataView-Dzo0jbs2.js.map → DataView--nUWtq6r.js.map} +1 -1
- package/dist/chunks/{DataView-1xh3GFeC.js → DataView-CK3Z0TJH.js} +2 -2
- package/dist/chunks/{DataView-1xh3GFeC.js.map → DataView-CK3Z0TJH.js.map} +1 -1
- package/dist/chunks/Dialog-BcgSR01Z.js +2 -0
- package/dist/chunks/{Dialog-DOGDalUq.js.map → Dialog-BcgSR01Z.js.map} +1 -1
- package/dist/chunks/{Dialog-CQlTDhZS.js → Dialog-DwCTFV6O.js} +2 -2
- package/dist/chunks/{Dialog-CQlTDhZS.js.map → Dialog-DwCTFV6O.js.map} +1 -1
- package/dist/chunks/FormPlugins-DvQ-G5J5.js +2 -0
- package/dist/chunks/{FormPlugins-DY6e88YT.js.map → FormPlugins-DvQ-G5J5.js.map} +1 -1
- package/dist/chunks/{FormView-DaKA4Sys.js → FormView-CRmEReTC.js} +3 -3
- package/dist/chunks/{FormView-DaKA4Sys.js.map → FormView-CRmEReTC.js.map} +1 -1
- package/dist/chunks/FormView-OLA7t-yv.js +3 -0
- package/dist/chunks/{FormView-Dz3mYasQ.js.map → FormView-OLA7t-yv.js.map} +1 -1
- package/dist/chunks/ListView-6JQ6tRXs.js +2 -0
- package/dist/chunks/{ListView-X5w5jf51.js.map → ListView-6JQ6tRXs.js.map} +1 -1
- package/dist/chunks/{ListView-CDzKIpd8.js → ListView-DVStKiMi.js} +2 -2
- package/dist/chunks/{ListView-CDzKIpd8.js.map → ListView-DVStKiMi.js.map} +1 -1
- package/dist/chunks/{MetricsCountryMapView-Dx2cw7ya.js → MetricsCountryMapView-CnAEbUw_.js} +2 -2
- package/dist/chunks/{MetricsCountryMapView-Dx2cw7ya.js.map → MetricsCountryMapView-CnAEbUw_.js.map} +1 -1
- package/dist/chunks/MetricsCountryMapView-J067qrrt.js +2 -0
- package/dist/chunks/{MetricsCountryMapView-B2xz6zUw.js.map → MetricsCountryMapView-J067qrrt.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-CBuso0OE.js → MetricsMiniChartWidget-BeD1slGs.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-CBuso0OE.js.map → MetricsMiniChartWidget-BeD1slGs.js.map} +1 -1
- package/dist/chunks/MetricsMiniChartWidget-x2gFjHOU.js +2 -0
- package/dist/chunks/{MetricsMiniChartWidget-DvKd7Qrk.js.map → MetricsMiniChartWidget-x2gFjHOU.js.map} +1 -1
- package/dist/chunks/PDFViewer-CsyKn-gh.js +2 -0
- package/dist/chunks/{PDFViewer-EJ9cOfPF.js.map → PDFViewer-CsyKn-gh.js.map} +1 -1
- package/dist/chunks/{PDFViewer-ofMGdSaj.js → PDFViewer-DSa4BZCm.js} +2 -2
- package/dist/chunks/{PDFViewer-ofMGdSaj.js.map → PDFViewer-DSa4BZCm.js.map} +1 -1
- package/dist/chunks/Rest-DHbszkuP.js +2 -0
- package/dist/chunks/Rest-DHbszkuP.js.map +1 -0
- package/dist/chunks/Rest-Ds9e8tN8.js +2 -0
- package/dist/chunks/Rest-Ds9e8tN8.js.map +1 -0
- package/dist/chunks/TokenManager-D6SjKgPZ.js +2 -0
- package/dist/chunks/{TokenManager-DoN9e6q6.js.map → TokenManager-D6SjKgPZ.js.map} +1 -1
- package/dist/chunks/{TokenManager-Gqvj7SDX.js → TokenManager-REbha1Le.js} +2 -2
- package/dist/chunks/{TokenManager-Gqvj7SDX.js.map → TokenManager-REbha1Le.js.map} +1 -1
- package/dist/chunks/WebApp-CULZpO_0.js +2 -0
- package/dist/chunks/{WebApp-6qvqmOts.js.map → WebApp-CULZpO_0.js.map} +1 -1
- package/dist/chunks/{WebApp-_dgpwtFw.js → WebApp-DovLtA60.js} +2 -2
- package/dist/chunks/{WebApp-_dgpwtFw.js.map → WebApp-DovLtA60.js.map} +1 -1
- package/dist/chunks/WebSocketClient-B-wc3mez.js +2 -0
- package/dist/chunks/{WebSocketClient-DG2olXpH.js.map → WebSocketClient-B-wc3mez.js.map} +1 -1
- package/dist/chunks/{WebSocketClient-MFkFlSue.js → WebSocketClient-BdZ9QYll.js} +2 -2
- package/dist/chunks/{WebSocketClient-MFkFlSue.js.map → WebSocketClient-BdZ9QYll.js.map} +1 -1
- package/dist/chunks/version-C3dnl1bg.js +2 -0
- package/dist/chunks/version-C3dnl1bg.js.map +1 -0
- package/dist/chunks/{version-BVADfTA5.js → version-ioN546cp.js} +2 -2
- package/dist/chunks/{version-BVADfTA5.js.map → version-ioN546cp.js.map} +1 -1
- package/dist/css/web-mojo.css +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +1 -957
- package/dist/docit.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +1 -3252
- package/dist/index.es.js.map +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +1 -3737
- package/dist/lightbox.es.js.map +1 -1
- package/dist/loader.umd.js +2 -2
- package/dist/map.cjs.js +1 -1
- package/dist/map.es.js +1 -1032
- package/dist/map.es.js.map +1 -1
- package/dist/mojo-auth.es.js +338 -0
- package/dist/mojo-auth.umd.js +1 -0
- package/dist/timeline.cjs.js +1 -1
- package/dist/timeline.es.js +1 -224
- package/dist/timeline.es.js.map +1 -1
- package/dist/web-mojo.lite.iife.js +14 -3
- package/dist/web-mojo.lite.iife.js.map +1 -1
- package/dist/web-mojo.lite.iife.min.js +6 -6
- package/dist/web-mojo.lite.iife.min.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunks/ChatView-9k6xBWXk.js +0 -7632
- package/dist/chunks/ChatView-9k6xBWXk.js.map +0 -1
- package/dist/chunks/ChatView-CdtuCDYm.js +0 -2
- package/dist/chunks/ChatView-CdtuCDYm.js.map +0 -1
- package/dist/chunks/Collection-DaiL0uGl.js +0 -1014
- package/dist/chunks/ContextMenu-sgvgSACY.js +0 -1535
- package/dist/chunks/DataView-Dzo0jbs2.js +0 -862
- package/dist/chunks/Dialog-DOGDalUq.js +0 -1579
- package/dist/chunks/FormPlugins-DY6e88YT.js +0 -124
- package/dist/chunks/FormView-Dz3mYasQ.js +0 -8636
- package/dist/chunks/ListView-X5w5jf51.js +0 -495
- package/dist/chunks/MetricsCountryMapView-B2xz6zUw.js +0 -1054
- package/dist/chunks/MetricsMiniChartWidget-DvKd7Qrk.js +0 -3283
- package/dist/chunks/PDFViewer-EJ9cOfPF.js +0 -946
- package/dist/chunks/Rest-CgSjfMaU.js +0 -2
- package/dist/chunks/Rest-CgSjfMaU.js.map +0 -1
- package/dist/chunks/Rest-W-sPfGh9.js +0 -4375
- package/dist/chunks/Rest-W-sPfGh9.js.map +0 -1
- package/dist/chunks/TokenManager-DoN9e6q6.js +0 -1423
- package/dist/chunks/WebApp-6qvqmOts.js +0 -1386
- package/dist/chunks/WebSocketClient-DG2olXpH.js +0 -209
- package/dist/chunks/version-OyPGnx30.js +0 -38
- package/dist/chunks/version-OyPGnx30.js.map +0 -1
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
var v = (f, s) => () => (s || f((s = { exports: {} }).exports, s), s.exports);
|
|
2
|
+
var y = v((S, d) => {
|
|
3
|
+
(function(f, s) {
|
|
4
|
+
typeof define == "function" && define.amd ? define([], s) : typeof d < "u" && d.exports ? d.exports = s() : f.MojoAuth = s();
|
|
5
|
+
})(typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : void 0, function() {
|
|
6
|
+
var f = "", s = {}, c = {
|
|
7
|
+
access: "access_token",
|
|
8
|
+
refresh: "refresh_token"
|
|
9
|
+
}, w = {
|
|
10
|
+
login: "/api/login",
|
|
11
|
+
forgotPassword: "/api/auth/forgot",
|
|
12
|
+
resetWithCode: "/api/auth/password/reset/code",
|
|
13
|
+
resetWithToken: "/api/auth/password/reset/token",
|
|
14
|
+
magicSend: "/api/auth/magic/send",
|
|
15
|
+
magicLogin: "/api/auth/magic/login",
|
|
16
|
+
passkeyLoginBegin: "/api/auth/passkeys/login/begin",
|
|
17
|
+
passkeyLoginComplete: "/api/auth/passkeys/login/complete",
|
|
18
|
+
oauthBegin: "/api/auth/oauth/{provider}/begin",
|
|
19
|
+
oauthComplete: "/api/auth/oauth/{provider}/complete",
|
|
20
|
+
refreshToken: "/api/refresh_token"
|
|
21
|
+
};
|
|
22
|
+
function i(e, r) {
|
|
23
|
+
var t = s[e] || w[e] || "";
|
|
24
|
+
return r && Object.keys(r).forEach(function(n) {
|
|
25
|
+
t = t.replace("{" + n + "}", r[n]);
|
|
26
|
+
}), f.replace(/\/$/, "") + t;
|
|
27
|
+
}
|
|
28
|
+
function u(e, r, t) {
|
|
29
|
+
var n = Object.assign({ "Content-Type": "application/json" }, {});
|
|
30
|
+
return fetch(e, {
|
|
31
|
+
method: "POST",
|
|
32
|
+
headers: n,
|
|
33
|
+
body: JSON.stringify(r || {})
|
|
34
|
+
}).then(function(o) {
|
|
35
|
+
return o.json().then(function(a) {
|
|
36
|
+
if (!o.ok) throw a;
|
|
37
|
+
return a;
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
function m(e, r) {
|
|
42
|
+
return fetch(e, {
|
|
43
|
+
method: "GET",
|
|
44
|
+
headers: Object.assign({ "Content-Type": "application/json" }, {})
|
|
45
|
+
}).then(function(t) {
|
|
46
|
+
return t.json().then(function(n) {
|
|
47
|
+
if (!t.ok) throw n;
|
|
48
|
+
return n;
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
function l(e) {
|
|
53
|
+
var r = e && e.data ? e.data : e;
|
|
54
|
+
if (!r || !r.access_token) throw new Error("No access_token in response");
|
|
55
|
+
return localStorage.setItem(c.access, r.access_token), r.refresh_token && localStorage.setItem(c.refresh, r.refresh_token), r;
|
|
56
|
+
}
|
|
57
|
+
function k(e) {
|
|
58
|
+
return e ? typeof e == "string" ? e : e.message || e.error || Array.isArray(e.errors) && e.errors[0] && e.errors[0].message || "An error occurred" : "An error occurred";
|
|
59
|
+
}
|
|
60
|
+
function p(e) {
|
|
61
|
+
for (var r = e.replace(/-/g, "+").replace(/_/g, "/"), t = atob(r), n = new Uint8Array(t.length), o = 0; o < t.length; o++)
|
|
62
|
+
n[o] = t.charCodeAt(o);
|
|
63
|
+
return n.buffer;
|
|
64
|
+
}
|
|
65
|
+
function h(e) {
|
|
66
|
+
for (var r = new Uint8Array(e), t = "", n = 0; n < r.byteLength; n++)
|
|
67
|
+
t += String.fromCharCode(r[n]);
|
|
68
|
+
return btoa(t).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
69
|
+
}
|
|
70
|
+
var g = {
|
|
71
|
+
/**
|
|
72
|
+
* Initialize the library. Must be called before any auth method.
|
|
73
|
+
* @param {object} config
|
|
74
|
+
* @param {string} config.baseURL - API base URL e.g. 'https://api.example.com'
|
|
75
|
+
* @param {object} [config.endpoints] - Override any default endpoint paths
|
|
76
|
+
*/
|
|
77
|
+
init: function(e) {
|
|
78
|
+
if (!e || !e.baseURL) throw new Error("MojoAuth.init: baseURL is required");
|
|
79
|
+
f = e.baseURL, s = Object.assign({}, e.endpoints || {});
|
|
80
|
+
},
|
|
81
|
+
// -----------------------------------------------------------------------
|
|
82
|
+
// JWT Login
|
|
83
|
+
// -----------------------------------------------------------------------
|
|
84
|
+
/**
|
|
85
|
+
* Login with username/email and password.
|
|
86
|
+
* Stores access_token and refresh_token in localStorage on success.
|
|
87
|
+
* @param {string} username
|
|
88
|
+
* @param {string} password
|
|
89
|
+
* @returns {Promise<object>} response data ({ access_token, refresh_token, user })
|
|
90
|
+
*
|
|
91
|
+
* NOTE: If MFA is enabled, the response will contain { mfa_required: true, mfa_token, mfa_methods }
|
|
92
|
+
* instead of tokens. Check result.mfa_required before assuming login is complete.
|
|
93
|
+
*/
|
|
94
|
+
login: function(e, r) {
|
|
95
|
+
return u(i("login"), { username: e, password: r }).then(function(t) {
|
|
96
|
+
var n = t.data || t;
|
|
97
|
+
return n.mfa_required ? n : l(t);
|
|
98
|
+
});
|
|
99
|
+
},
|
|
100
|
+
// -----------------------------------------------------------------------
|
|
101
|
+
// Password Reset — Code method
|
|
102
|
+
// -----------------------------------------------------------------------
|
|
103
|
+
/**
|
|
104
|
+
* Request a 6-digit reset code sent to the user's email.
|
|
105
|
+
* @param {string} email
|
|
106
|
+
* @returns {Promise<object>}
|
|
107
|
+
*/
|
|
108
|
+
forgotPasswordCode: function(e) {
|
|
109
|
+
return u(i("forgotPassword"), { email: e, method: "code" });
|
|
110
|
+
},
|
|
111
|
+
/**
|
|
112
|
+
* Complete password reset using the emailed code.
|
|
113
|
+
* Stores tokens on success (logs user in automatically).
|
|
114
|
+
* @param {string} email
|
|
115
|
+
* @param {string} code - 6-digit code from email
|
|
116
|
+
* @param {string} newPassword
|
|
117
|
+
* @returns {Promise<object>}
|
|
118
|
+
*/
|
|
119
|
+
resetWithCode: function(e, r, t) {
|
|
120
|
+
return u(i("resetWithCode"), {
|
|
121
|
+
email: e,
|
|
122
|
+
code: r,
|
|
123
|
+
new_password: t
|
|
124
|
+
}).then(l);
|
|
125
|
+
},
|
|
126
|
+
// -----------------------------------------------------------------------
|
|
127
|
+
// Password Reset — Link / Token method
|
|
128
|
+
// -----------------------------------------------------------------------
|
|
129
|
+
/**
|
|
130
|
+
* Request a password reset link (pr: token) sent to the user's email.
|
|
131
|
+
* @param {string} email
|
|
132
|
+
* @returns {Promise<object>}
|
|
133
|
+
*/
|
|
134
|
+
forgotPasswordLink: function(e) {
|
|
135
|
+
return u(i("forgotPassword"), { email: e, method: "link" });
|
|
136
|
+
},
|
|
137
|
+
/**
|
|
138
|
+
* Complete password reset using the token from the reset link email.
|
|
139
|
+
* Stores tokens on success.
|
|
140
|
+
* @param {string} token - pr: prefixed token from URL
|
|
141
|
+
* @param {string} newPassword
|
|
142
|
+
* @returns {Promise<object>}
|
|
143
|
+
*/
|
|
144
|
+
resetWithToken: function(e, r) {
|
|
145
|
+
return u(i("resetWithToken"), {
|
|
146
|
+
token: e,
|
|
147
|
+
new_password: r
|
|
148
|
+
}).then(l);
|
|
149
|
+
},
|
|
150
|
+
// -----------------------------------------------------------------------
|
|
151
|
+
// Magic Login (passwordless email link)
|
|
152
|
+
// -----------------------------------------------------------------------
|
|
153
|
+
/**
|
|
154
|
+
* Send a magic login link (ml: token) to the user's email.
|
|
155
|
+
* @param {string} email
|
|
156
|
+
* @returns {Promise<object>}
|
|
157
|
+
*/
|
|
158
|
+
sendMagicLink: function(e) {
|
|
159
|
+
return u(i("magicSend"), { email: e });
|
|
160
|
+
},
|
|
161
|
+
/**
|
|
162
|
+
* Complete login using the ml: token from the magic link URL.
|
|
163
|
+
* Stores tokens on success.
|
|
164
|
+
* @param {string} token - ml: prefixed token from URL ?token=ml:...
|
|
165
|
+
* @returns {Promise<object>}
|
|
166
|
+
*/
|
|
167
|
+
loginWithMagicToken: function(e) {
|
|
168
|
+
return u(i("magicLogin"), { token: e }).then(l);
|
|
169
|
+
},
|
|
170
|
+
/**
|
|
171
|
+
* Convenience: read ?token= from current URL and login if it's a magic link token.
|
|
172
|
+
* Cleans the token from the URL after reading it.
|
|
173
|
+
* @returns {Promise<object|null>} resolves with auth data or null if no token found
|
|
174
|
+
*/
|
|
175
|
+
handleMagicTokenFromURL: function() {
|
|
176
|
+
var e = new URLSearchParams(window.location.search), r = e.get("token");
|
|
177
|
+
if (!r || r.indexOf("ml:") !== 0) return Promise.resolve(null);
|
|
178
|
+
e.delete("token");
|
|
179
|
+
var t = e.toString() ? window.location.pathname + "?" + e.toString() : window.location.pathname;
|
|
180
|
+
return window.history.replaceState({}, "", t), g.loginWithMagicToken(r);
|
|
181
|
+
},
|
|
182
|
+
// -----------------------------------------------------------------------
|
|
183
|
+
// Passkey Login (WebAuthn)
|
|
184
|
+
// -----------------------------------------------------------------------
|
|
185
|
+
/**
|
|
186
|
+
* Check if WebAuthn passkeys are supported in this browser.
|
|
187
|
+
* @returns {boolean}
|
|
188
|
+
*/
|
|
189
|
+
isPasskeySupported: function() {
|
|
190
|
+
return typeof window < "u" && typeof window.PublicKeyCredential < "u" && typeof navigator.credentials < "u" && typeof navigator.credentials.get == "function";
|
|
191
|
+
},
|
|
192
|
+
/**
|
|
193
|
+
* Login with a passkey (WebAuthn).
|
|
194
|
+
* Handles the full begin → browser prompt → complete flow.
|
|
195
|
+
* Stores tokens on success.
|
|
196
|
+
* @param {string} username - username or email
|
|
197
|
+
* @returns {Promise<object>}
|
|
198
|
+
*/
|
|
199
|
+
loginWithPasskey: function(e) {
|
|
200
|
+
return g.isPasskeySupported() ? u(i("passkeyLoginBegin"), { username: e }).then(function(r) {
|
|
201
|
+
var t = r.data || r, n = t.challenge_id, o = t.publicKey;
|
|
202
|
+
return o.challenge = p(o.challenge), o.allowCredentials && (o.allowCredentials = o.allowCredentials.map(function(a) {
|
|
203
|
+
return Object.assign({}, a, { id: p(a.id) });
|
|
204
|
+
})), navigator.credentials.get({ publicKey: o }).then(function(a) {
|
|
205
|
+
if (!a) throw new Error("No credential received from authenticator");
|
|
206
|
+
return u(i("passkeyLoginComplete"), {
|
|
207
|
+
challenge_id: n,
|
|
208
|
+
credential: {
|
|
209
|
+
id: a.id,
|
|
210
|
+
rawId: h(a.rawId),
|
|
211
|
+
type: a.type,
|
|
212
|
+
response: {
|
|
213
|
+
clientDataJSON: h(a.response.clientDataJSON),
|
|
214
|
+
authenticatorData: h(a.response.authenticatorData),
|
|
215
|
+
signature: h(a.response.signature),
|
|
216
|
+
userHandle: a.response.userHandle ? h(a.response.userHandle) : null
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
}).then(l) : Promise.reject(new Error("Passkeys are not supported in this browser"));
|
|
222
|
+
},
|
|
223
|
+
// -----------------------------------------------------------------------
|
|
224
|
+
// Google OAuth
|
|
225
|
+
// -----------------------------------------------------------------------
|
|
226
|
+
/**
|
|
227
|
+
* Start Google OAuth login.
|
|
228
|
+
* Fetches the authorization URL from the backend and redirects the browser.
|
|
229
|
+
* @returns {Promise<void>}
|
|
230
|
+
*/
|
|
231
|
+
startGoogleLogin: function() {
|
|
232
|
+
return m(i("oauthBegin", { provider: "google" })).then(function(e) {
|
|
233
|
+
var r = e.data || e;
|
|
234
|
+
if (!r.auth_url) throw new Error("No auth_url in OAuth begin response");
|
|
235
|
+
window.location.href = r.auth_url;
|
|
236
|
+
});
|
|
237
|
+
},
|
|
238
|
+
/**
|
|
239
|
+
* Complete Google OAuth login — call this on your OAuth callback page.
|
|
240
|
+
* Reads ?code and ?state from the current URL automatically.
|
|
241
|
+
* Stores tokens on success.
|
|
242
|
+
* @returns {Promise<object>}
|
|
243
|
+
*/
|
|
244
|
+
completeGoogleLogin: function() {
|
|
245
|
+
var e = new URLSearchParams(window.location.search), r = e.get("code"), t = e.get("state");
|
|
246
|
+
return r ? u(i("oauthComplete", { provider: "google" }), {
|
|
247
|
+
code: r,
|
|
248
|
+
state: t
|
|
249
|
+
}).then(l) : Promise.reject(new Error("No OAuth code in URL"));
|
|
250
|
+
},
|
|
251
|
+
// -----------------------------------------------------------------------
|
|
252
|
+
// Session helpers
|
|
253
|
+
// -----------------------------------------------------------------------
|
|
254
|
+
/**
|
|
255
|
+
* Log out — clears tokens from localStorage.
|
|
256
|
+
*/
|
|
257
|
+
logout: function() {
|
|
258
|
+
localStorage.removeItem(c.access), localStorage.removeItem(c.refresh);
|
|
259
|
+
},
|
|
260
|
+
/**
|
|
261
|
+
* Check if the user has a stored access token.
|
|
262
|
+
* Does not validate expiry — use getTokenPayload() for that.
|
|
263
|
+
* @returns {boolean}
|
|
264
|
+
*/
|
|
265
|
+
isAuthenticated: function() {
|
|
266
|
+
return !!localStorage.getItem(c.access);
|
|
267
|
+
},
|
|
268
|
+
/**
|
|
269
|
+
* Get the raw access token string.
|
|
270
|
+
* @returns {string|null}
|
|
271
|
+
*/
|
|
272
|
+
getToken: function() {
|
|
273
|
+
return localStorage.getItem(c.access);
|
|
274
|
+
},
|
|
275
|
+
/**
|
|
276
|
+
* Get the raw refresh token string.
|
|
277
|
+
* @returns {string|null}
|
|
278
|
+
*/
|
|
279
|
+
getRefreshToken: function() {
|
|
280
|
+
return localStorage.getItem(c.refresh);
|
|
281
|
+
},
|
|
282
|
+
/**
|
|
283
|
+
* Get the Authorization header value for use in API requests.
|
|
284
|
+
* @returns {string|null} e.g. "Bearer eyJhbGci..."
|
|
285
|
+
*/
|
|
286
|
+
getAuthHeader: function() {
|
|
287
|
+
var e = localStorage.getItem(c.access);
|
|
288
|
+
return e ? "Bearer " + e : null;
|
|
289
|
+
},
|
|
290
|
+
/**
|
|
291
|
+
* Decode the JWT access token payload (client-side only, no signature verification).
|
|
292
|
+
* @returns {object|null}
|
|
293
|
+
*/
|
|
294
|
+
getTokenPayload: function() {
|
|
295
|
+
var e = localStorage.getItem(c.access);
|
|
296
|
+
if (!e) return null;
|
|
297
|
+
try {
|
|
298
|
+
var r = e.split(".");
|
|
299
|
+
if (r.length !== 3) return null;
|
|
300
|
+
var t = r[1].replace(/-/g, "+").replace(/_/g, "/"), n = 4 - t.length % 4;
|
|
301
|
+
return n !== 4 && (t += "====".slice(0, n)), JSON.parse(atob(t));
|
|
302
|
+
} catch {
|
|
303
|
+
return null;
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
/**
|
|
307
|
+
* Check if the stored access token is expired (based on JWT exp claim).
|
|
308
|
+
* Returns true if expired or if token is missing/undecodable.
|
|
309
|
+
* @returns {boolean}
|
|
310
|
+
*/
|
|
311
|
+
isTokenExpired: function() {
|
|
312
|
+
var e = g.getTokenPayload();
|
|
313
|
+
return !e || !e.exp ? !0 : Math.floor(Date.now() / 1e3) >= e.exp;
|
|
314
|
+
},
|
|
315
|
+
/**
|
|
316
|
+
* Refresh the access token using the stored refresh token.
|
|
317
|
+
* Stores the new tokens on success.
|
|
318
|
+
* @returns {Promise<object>}
|
|
319
|
+
*/
|
|
320
|
+
refreshToken: function() {
|
|
321
|
+
var e = localStorage.getItem(c.refresh);
|
|
322
|
+
return e ? u(i("refreshToken"), { refresh_token: e }).then(l) : Promise.reject(new Error("No refresh token stored"));
|
|
323
|
+
},
|
|
324
|
+
// -----------------------------------------------------------------------
|
|
325
|
+
// Error helper
|
|
326
|
+
// -----------------------------------------------------------------------
|
|
327
|
+
/**
|
|
328
|
+
* Extract a human-readable error message from a caught error.
|
|
329
|
+
* Works with the MOJO backend error shapes.
|
|
330
|
+
* @param {any} err - the caught error (object, string, etc.)
|
|
331
|
+
* @returns {string}
|
|
332
|
+
*/
|
|
333
|
+
getError: k
|
|
334
|
+
};
|
|
335
|
+
return g;
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
export default y();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
(function(c){typeof define=="function"&&define.amd?define(c):c()})((function(){"use strict";(function(c,f){typeof define=="function"&&define.amd?define([],f):typeof module<"u"&&module.exports?module.exports=f():c.MojoAuth=f()})(typeof globalThis<"u"?globalThis:typeof window<"u"?window:void 0,function(){var c="",f={},u={access:"access_token",refresh:"refresh_token"},p={login:"/api/login",forgotPassword:"/api/auth/forgot",resetWithCode:"/api/auth/password/reset/code",resetWithToken:"/api/auth/password/reset/token",magicSend:"/api/auth/magic/send",magicLogin:"/api/auth/magic/login",passkeyLoginBegin:"/api/auth/passkeys/login/begin",passkeyLoginComplete:"/api/auth/passkeys/login/complete",oauthBegin:"/api/auth/oauth/{provider}/begin",oauthComplete:"/api/auth/oauth/{provider}/complete",refreshToken:"/api/refresh_token"};function i(e,r){var t=f[e]||p[e]||"";return r&&Object.keys(r).forEach(function(n){t=t.replace("{"+n+"}",r[n])}),c.replace(/\/$/,"")+t}function s(e,r,t){var n=Object.assign({"Content-Type":"application/json"},{});return fetch(e,{method:"POST",headers:n,body:JSON.stringify(r||{})}).then(function(o){return o.json().then(function(a){if(!o.ok)throw a;return a})})}function w(e,r){return fetch(e,{method:"GET",headers:Object.assign({"Content-Type":"application/json"},{})}).then(function(t){return t.json().then(function(n){if(!t.ok)throw n;return n})})}function l(e){var r=e&&e.data?e.data:e;if(!r||!r.access_token)throw new Error("No access_token in response");return localStorage.setItem(u.access,r.access_token),r.refresh_token&&localStorage.setItem(u.refresh,r.refresh_token),r}function m(e){return e?typeof e=="string"?e:e.message||e.error||Array.isArray(e.errors)&&e.errors[0]&&e.errors[0].message||"An error occurred":"An error occurred"}function g(e){for(var r=e.replace(/-/g,"+").replace(/_/g,"/"),t=atob(r),n=new Uint8Array(t.length),o=0;o<t.length;o++)n[o]=t.charCodeAt(o);return n.buffer}function d(e){for(var r=new Uint8Array(e),t="",n=0;n<r.byteLength;n++)t+=String.fromCharCode(r[n]);return btoa(t).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}var h={init:function(e){if(!e||!e.baseURL)throw new Error("MojoAuth.init: baseURL is required");c=e.baseURL,f=Object.assign({},e.endpoints||{})},login:function(e,r){return s(i("login"),{username:e,password:r}).then(function(t){var n=t.data||t;return n.mfa_required?n:l(t)})},forgotPasswordCode:function(e){return s(i("forgotPassword"),{email:e,method:"code"})},resetWithCode:function(e,r,t){return s(i("resetWithCode"),{email:e,code:r,new_password:t}).then(l)},forgotPasswordLink:function(e){return s(i("forgotPassword"),{email:e,method:"link"})},resetWithToken:function(e,r){return s(i("resetWithToken"),{token:e,new_password:r}).then(l)},sendMagicLink:function(e){return s(i("magicSend"),{email:e})},loginWithMagicToken:function(e){return s(i("magicLogin"),{token:e}).then(l)},handleMagicTokenFromURL:function(){var e=new URLSearchParams(window.location.search),r=e.get("token");if(!r||r.indexOf("ml:")!==0)return Promise.resolve(null);e.delete("token");var t=e.toString()?window.location.pathname+"?"+e.toString():window.location.pathname;return window.history.replaceState({},"",t),h.loginWithMagicToken(r)},isPasskeySupported:function(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator.credentials<"u"&&typeof navigator.credentials.get=="function"},loginWithPasskey:function(e){return h.isPasskeySupported()?s(i("passkeyLoginBegin"),{username:e}).then(function(r){var t=r.data||r,n=t.challenge_id,o=t.publicKey;return o.challenge=g(o.challenge),o.allowCredentials&&(o.allowCredentials=o.allowCredentials.map(function(a){return Object.assign({},a,{id:g(a.id)})})),navigator.credentials.get({publicKey:o}).then(function(a){if(!a)throw new Error("No credential received from authenticator");return s(i("passkeyLoginComplete"),{challenge_id:n,credential:{id:a.id,rawId:d(a.rawId),type:a.type,response:{clientDataJSON:d(a.response.clientDataJSON),authenticatorData:d(a.response.authenticatorData),signature:d(a.response.signature),userHandle:a.response.userHandle?d(a.response.userHandle):null}}})})}).then(l):Promise.reject(new Error("Passkeys are not supported in this browser"))},startGoogleLogin:function(){return w(i("oauthBegin",{provider:"google"})).then(function(e){var r=e.data||e;if(!r.auth_url)throw new Error("No auth_url in OAuth begin response");window.location.href=r.auth_url})},completeGoogleLogin:function(){var e=new URLSearchParams(window.location.search),r=e.get("code"),t=e.get("state");return r?s(i("oauthComplete",{provider:"google"}),{code:r,state:t}).then(l):Promise.reject(new Error("No OAuth code in URL"))},logout:function(){localStorage.removeItem(u.access),localStorage.removeItem(u.refresh)},isAuthenticated:function(){return!!localStorage.getItem(u.access)},getToken:function(){return localStorage.getItem(u.access)},getRefreshToken:function(){return localStorage.getItem(u.refresh)},getAuthHeader:function(){var e=localStorage.getItem(u.access);return e?"Bearer "+e:null},getTokenPayload:function(){var e=localStorage.getItem(u.access);if(!e)return null;try{var r=e.split(".");if(r.length!==3)return null;var t=r[1].replace(/-/g,"+").replace(/_/g,"/"),n=4-t.length%4;return n!==4&&(t+="====".slice(0,n)),JSON.parse(atob(t))}catch{return null}},isTokenExpired:function(){var e=h.getTokenPayload();return!e||!e.exp?!0:Math.floor(Date.now()/1e3)>=e.exp},refreshToken:function(){var e=localStorage.getItem(u.refresh);return e?s(i("refreshToken"),{refresh_token:e}).then(l):Promise.reject(new Error("No refresh token stored"))},getError:m};return h})}));
|
package/dist/timeline.cjs.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/ListView-
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./chunks/ListView-DVStKiMi.js"),e=require("./chunks/Rest-Ds9e8tN8.js"),i=require("./chunks/Collection-DSBRXpwK.js");class TimelineViewItem extends t.ListViewItem{constructor(t={}){super({className:"timeline-item",...t}),this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.template||(this.template='\n <div class="timeline-marker timeline-marker-{{markerType}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}} text-{{displayColor}}"></i>\n {{/hasIcon}}\n {{^hasIcon}}\n <div class="timeline-dot bg-{{displayColor}}"></div>\n {{/hasIcon}}\n </div>\n \n <div class="timeline-content">\n {{#showDate}}\n <div class="timeline-date text-muted small">\n {{formattedDate}}\n </div>\n {{/showDate}}\n \n <div class="timeline-card">\n {{#model.title}}\n <h6 class="timeline-title mb-1">{{model.title}}</h6>\n {{/model.title}}\n \n {{#model.description}}\n <p class="timeline-description mb-0">{{model.description}}</p>\n {{/model.description}}\n \n {{#model.meta}}\n <div class="timeline-meta mt-2 text-muted small">\n {{model.meta}}\n </div>\n {{/model.meta}}\n </div>\n </div>\n ')}async onInit(){await super.onInit(),this.processItemData()}processItemData(){this.displayColor=this.model?.get?.("color")||this.model?.color||this.theme;const t=!(!this.model?.get?.("icon")&&!this.model?.icon)&&"icon"===this.dotStyle;this.hasIcon=t,this.markerType=t?"icon":this.dotStyle;const e=this.model?.get?.("date")||this.model?.date;this.formattedDate=this.formatDate(e)}formatDate(t){if(!t)return"";switch(this.dateFormat){case"datetime":return e.dataFormatter.pipe(t,"datetime");case"relative":return e.dataFormatter.pipe(t,"timeago");default:return e.dataFormatter.pipe(t,"date")}}async onActionSelect(t,e){t.stopPropagation(),this.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model})}}class TimelineView extends t.ListView{constructor(t={}){super({className:"timeline-view",itemClass:t.itemClass||TimelineViewItem,selectionMode:"none",emptyMessage:t.emptyMessage||"No timeline events to display",template:'\n <div class="timeline-container timeline-{{position}}">\n {{#loading}}\n <div class="timeline-loading text-center py-4">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <span class="ms-2 text-muted">Loading timeline...</span>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="timeline-empty text-center text-muted py-4">\n <i class="bi bi-clock-history fs-1 d-block mb-2"></i>\n <p>{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <div class="timeline" data-container="items"></div>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ',...t}),this.position=t.position||"left",this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.groupBy=t.groupBy||"none"}_createItemView(t,e){if(this.itemViews.has(t.id))return;const i=new this.itemClass({model:t,index:e,listView:this,template:this.itemTemplate,dateFormat:this.dateFormat,dotStyle:this.dotStyle,showDate:this.showDate,theme:this.theme});return this.itemViews.set(t.id,i),i.on("item:click",this._onItemClick.bind(this)),i}_onItemClick(t){this.emit("item:click",t)}setPosition(t){return"left"!==t&&"center"!==t?(console.warn('Invalid position. Use "left" or "center"'),this):(this.position=t,this.isMounted()&&this.render(),this)}setDateFormat(t){return this.dateFormat=t,this.forEachItem(e=>{e.dateFormat=t,e.processItemData(),e.isMounted()&&e.render()}),this}setDotStyle(t){return this.dotStyle=t,this.forEachItem(e=>{e.dotStyle=t,e.processItemData(),e.isMounted()&&e.render()}),this}toggleDates(t=null){return this.showDate=null!==t?t:!this.showDate,this.forEachItem(t=>{t.showDate=this.showDate,t.isMounted()&&t.render()}),this}}exports.ListView=t.ListView,exports.ListViewItem=t.ListViewItem,exports.View=e.View,exports.Collection=i.Collection,exports.Model=i.Model,exports.TimelineView=TimelineView,exports.TimelineViewItem=TimelineViewItem;
|
|
2
2
|
//# sourceMappingURL=timeline.cjs.js.map
|
package/dist/timeline.es.js
CHANGED
|
@@ -1,225 +1,2 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { d as dataFormatter } from "./chunks/Rest-W-sPfGh9.js";
|
|
3
|
-
import { V } from "./chunks/Rest-W-sPfGh9.js";
|
|
4
|
-
import { C, M } from "./chunks/Collection-DaiL0uGl.js";
|
|
5
|
-
class TimelineViewItem extends ListViewItem {
|
|
6
|
-
constructor(options = {}) {
|
|
7
|
-
super({
|
|
8
|
-
className: "timeline-item",
|
|
9
|
-
...options
|
|
10
|
-
});
|
|
11
|
-
this.dateFormat = options.dateFormat || "date";
|
|
12
|
-
this.dotStyle = options.dotStyle || "solid";
|
|
13
|
-
this.showDate = options.showDate !== false;
|
|
14
|
-
this.theme = options.theme || "primary";
|
|
15
|
-
if (!this.template) {
|
|
16
|
-
this.template = `
|
|
17
|
-
<div class="timeline-marker timeline-marker-{{markerType}}">
|
|
18
|
-
{{#hasIcon}}
|
|
19
|
-
<i class="bi {{model.icon}} text-{{displayColor}}"></i>
|
|
20
|
-
{{/hasIcon}}
|
|
21
|
-
{{^hasIcon}}
|
|
22
|
-
<div class="timeline-dot bg-{{displayColor}}"></div>
|
|
23
|
-
{{/hasIcon}}
|
|
24
|
-
</div>
|
|
25
|
-
|
|
26
|
-
<div class="timeline-content">
|
|
27
|
-
{{#showDate}}
|
|
28
|
-
<div class="timeline-date text-muted small">
|
|
29
|
-
{{formattedDate}}
|
|
30
|
-
</div>
|
|
31
|
-
{{/showDate}}
|
|
32
|
-
|
|
33
|
-
<div class="timeline-card">
|
|
34
|
-
{{#model.title}}
|
|
35
|
-
<h6 class="timeline-title mb-1">{{model.title}}</h6>
|
|
36
|
-
{{/model.title}}
|
|
37
|
-
|
|
38
|
-
{{#model.description}}
|
|
39
|
-
<p class="timeline-description mb-0">{{model.description}}</p>
|
|
40
|
-
{{/model.description}}
|
|
41
|
-
|
|
42
|
-
{{#model.meta}}
|
|
43
|
-
<div class="timeline-meta mt-2 text-muted small">
|
|
44
|
-
{{model.meta}}
|
|
45
|
-
</div>
|
|
46
|
-
{{/model.meta}}
|
|
47
|
-
</div>
|
|
48
|
-
</div>
|
|
49
|
-
`;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
async onInit() {
|
|
53
|
-
await super.onInit();
|
|
54
|
-
this.processItemData();
|
|
55
|
-
}
|
|
56
|
-
processItemData() {
|
|
57
|
-
this.displayColor = this.model?.get?.("color") || this.model?.color || this.theme;
|
|
58
|
-
const hasIcon = !!(this.model?.get?.("icon") || this.model?.icon) && this.dotStyle === "icon";
|
|
59
|
-
this.hasIcon = hasIcon;
|
|
60
|
-
this.markerType = hasIcon ? "icon" : this.dotStyle;
|
|
61
|
-
const dateValue = this.model?.get?.("date") || this.model?.date;
|
|
62
|
-
this.formattedDate = this.formatDate(dateValue);
|
|
63
|
-
}
|
|
64
|
-
formatDate(date) {
|
|
65
|
-
if (!date) return "";
|
|
66
|
-
switch (this.dateFormat) {
|
|
67
|
-
case "datetime":
|
|
68
|
-
return dataFormatter.pipe(date, "datetime");
|
|
69
|
-
case "relative":
|
|
70
|
-
return dataFormatter.pipe(date, "timeago");
|
|
71
|
-
default:
|
|
72
|
-
return dataFormatter.pipe(date, "date");
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
// Override to disable selection behavior in timeline
|
|
76
|
-
async onActionSelect(event, _element) {
|
|
77
|
-
event.stopPropagation();
|
|
78
|
-
this.emit("item:click", {
|
|
79
|
-
item: this,
|
|
80
|
-
model: this.model,
|
|
81
|
-
index: this.index,
|
|
82
|
-
data: this.model?.toJSON ? this.model.toJSON() : this.model
|
|
83
|
-
});
|
|
84
|
-
if (this.listView) {
|
|
85
|
-
this.listView.emit("item:click", {
|
|
86
|
-
item: this,
|
|
87
|
-
model: this.model,
|
|
88
|
-
index: this.index,
|
|
89
|
-
data: this.model?.toJSON ? this.model.toJSON() : this.model
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
class TimelineView extends ListView {
|
|
95
|
-
constructor(options = {}) {
|
|
96
|
-
super({
|
|
97
|
-
className: "timeline-view",
|
|
98
|
-
itemClass: options.itemClass || TimelineViewItem,
|
|
99
|
-
selectionMode: "none",
|
|
100
|
-
// Timelines typically don't use selection
|
|
101
|
-
emptyMessage: options.emptyMessage || "No timeline events to display",
|
|
102
|
-
template: `
|
|
103
|
-
<div class="timeline-container timeline-{{position}}">
|
|
104
|
-
{{#loading}}
|
|
105
|
-
<div class="timeline-loading text-center py-4">
|
|
106
|
-
<div class="spinner-border spinner-border-sm" role="status">
|
|
107
|
-
<span class="visually-hidden">Loading...</span>
|
|
108
|
-
</div>
|
|
109
|
-
<span class="ms-2 text-muted">Loading timeline...</span>
|
|
110
|
-
</div>
|
|
111
|
-
{{/loading}}
|
|
112
|
-
{{^loading}}
|
|
113
|
-
{{#isEmpty}}
|
|
114
|
-
<div class="timeline-empty text-center text-muted py-4">
|
|
115
|
-
<i class="bi bi-clock-history fs-1 d-block mb-2"></i>
|
|
116
|
-
<p>{{emptyMessage}}</p>
|
|
117
|
-
</div>
|
|
118
|
-
{{/isEmpty}}
|
|
119
|
-
{{^isEmpty}}
|
|
120
|
-
<div class="timeline" data-container="items"></div>
|
|
121
|
-
{{/isEmpty}}
|
|
122
|
-
{{/loading}}
|
|
123
|
-
</div>
|
|
124
|
-
`,
|
|
125
|
-
...options
|
|
126
|
-
});
|
|
127
|
-
this.position = options.position || "left";
|
|
128
|
-
this.dateFormat = options.dateFormat || "date";
|
|
129
|
-
this.dotStyle = options.dotStyle || "solid";
|
|
130
|
-
this.showDate = options.showDate !== false;
|
|
131
|
-
this.theme = options.theme || "primary";
|
|
132
|
-
this.groupBy = options.groupBy || "none";
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Override _createItemView to pass timeline-specific options
|
|
136
|
-
*/
|
|
137
|
-
_createItemView(model, index) {
|
|
138
|
-
if (this.itemViews.has(model.id)) return;
|
|
139
|
-
const itemView = new this.itemClass({
|
|
140
|
-
model,
|
|
141
|
-
index,
|
|
142
|
-
listView: this,
|
|
143
|
-
template: this.itemTemplate,
|
|
144
|
-
// Pass timeline-specific options to items
|
|
145
|
-
dateFormat: this.dateFormat,
|
|
146
|
-
dotStyle: this.dotStyle,
|
|
147
|
-
showDate: this.showDate,
|
|
148
|
-
theme: this.theme
|
|
149
|
-
});
|
|
150
|
-
this.itemViews.set(model.id, itemView);
|
|
151
|
-
itemView.on("item:click", this._onItemClick.bind(this));
|
|
152
|
-
return itemView;
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* Handle item clicks (replaces selection behavior)
|
|
156
|
-
*/
|
|
157
|
-
_onItemClick(event) {
|
|
158
|
-
this.emit("item:click", event);
|
|
159
|
-
}
|
|
160
|
-
/**
|
|
161
|
-
* Update timeline position
|
|
162
|
-
*/
|
|
163
|
-
setPosition(position) {
|
|
164
|
-
if (position !== "left" && position !== "center") {
|
|
165
|
-
console.warn('Invalid position. Use "left" or "center"');
|
|
166
|
-
return this;
|
|
167
|
-
}
|
|
168
|
-
this.position = position;
|
|
169
|
-
if (this.isMounted()) {
|
|
170
|
-
this.render();
|
|
171
|
-
}
|
|
172
|
-
return this;
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Update date format for all items
|
|
176
|
-
*/
|
|
177
|
-
setDateFormat(format) {
|
|
178
|
-
this.dateFormat = format;
|
|
179
|
-
this.forEachItem((itemView) => {
|
|
180
|
-
itemView.dateFormat = format;
|
|
181
|
-
itemView.processItemData();
|
|
182
|
-
if (itemView.isMounted()) {
|
|
183
|
-
itemView.render();
|
|
184
|
-
}
|
|
185
|
-
});
|
|
186
|
-
return this;
|
|
187
|
-
}
|
|
188
|
-
/**
|
|
189
|
-
* Update dot style for all items
|
|
190
|
-
*/
|
|
191
|
-
setDotStyle(style) {
|
|
192
|
-
this.dotStyle = style;
|
|
193
|
-
this.forEachItem((itemView) => {
|
|
194
|
-
itemView.dotStyle = style;
|
|
195
|
-
itemView.processItemData();
|
|
196
|
-
if (itemView.isMounted()) {
|
|
197
|
-
itemView.render();
|
|
198
|
-
}
|
|
199
|
-
});
|
|
200
|
-
return this;
|
|
201
|
-
}
|
|
202
|
-
/**
|
|
203
|
-
* Toggle date display
|
|
204
|
-
*/
|
|
205
|
-
toggleDates(show = null) {
|
|
206
|
-
this.showDate = show !== null ? show : !this.showDate;
|
|
207
|
-
this.forEachItem((itemView) => {
|
|
208
|
-
itemView.showDate = this.showDate;
|
|
209
|
-
if (itemView.isMounted()) {
|
|
210
|
-
itemView.render();
|
|
211
|
-
}
|
|
212
|
-
});
|
|
213
|
-
return this;
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
export {
|
|
217
|
-
C as Collection,
|
|
218
|
-
ListView,
|
|
219
|
-
ListViewItem,
|
|
220
|
-
M as Model,
|
|
221
|
-
TimelineView,
|
|
222
|
-
TimelineViewItem,
|
|
223
|
-
V as View
|
|
224
|
-
};
|
|
1
|
+
import{a as t,L as e}from"./chunks/ListView-6JQ6tRXs.js";import{d as i}from"./chunks/Rest-DHbszkuP.js";import{V as s}from"./chunks/Rest-DHbszkuP.js";import{C as n,M as o}from"./chunks/Collection-1sPoIFvQ.js";class TimelineViewItem extends t{constructor(t={}){super({className:"timeline-item",...t}),this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.template||(this.template='\n <div class="timeline-marker timeline-marker-{{markerType}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}} text-{{displayColor}}"></i>\n {{/hasIcon}}\n {{^hasIcon}}\n <div class="timeline-dot bg-{{displayColor}}"></div>\n {{/hasIcon}}\n </div>\n \n <div class="timeline-content">\n {{#showDate}}\n <div class="timeline-date text-muted small">\n {{formattedDate}}\n </div>\n {{/showDate}}\n \n <div class="timeline-card">\n {{#model.title}}\n <h6 class="timeline-title mb-1">{{model.title}}</h6>\n {{/model.title}}\n \n {{#model.description}}\n <p class="timeline-description mb-0">{{model.description}}</p>\n {{/model.description}}\n \n {{#model.meta}}\n <div class="timeline-meta mt-2 text-muted small">\n {{model.meta}}\n </div>\n {{/model.meta}}\n </div>\n </div>\n ')}async onInit(){await super.onInit(),this.processItemData()}processItemData(){this.displayColor=this.model?.get?.("color")||this.model?.color||this.theme;const t=!(!this.model?.get?.("icon")&&!this.model?.icon)&&"icon"===this.dotStyle;this.hasIcon=t,this.markerType=t?"icon":this.dotStyle;const e=this.model?.get?.("date")||this.model?.date;this.formattedDate=this.formatDate(e)}formatDate(t){if(!t)return"";switch(this.dateFormat){case"datetime":return i.pipe(t,"datetime");case"relative":return i.pipe(t,"timeago");default:return i.pipe(t,"date")}}async onActionSelect(t,e){t.stopPropagation(),this.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model}),this.listView&&this.listView.emit("item:click",{item:this,model:this.model,index:this.index,data:this.model?.toJSON?this.model.toJSON():this.model})}}class TimelineView extends e{constructor(t={}){super({className:"timeline-view",itemClass:t.itemClass||TimelineViewItem,selectionMode:"none",emptyMessage:t.emptyMessage||"No timeline events to display",template:'\n <div class="timeline-container timeline-{{position}}">\n {{#loading}}\n <div class="timeline-loading text-center py-4">\n <div class="spinner-border spinner-border-sm" role="status">\n <span class="visually-hidden">Loading...</span>\n </div>\n <span class="ms-2 text-muted">Loading timeline...</span>\n </div>\n {{/loading}}\n {{^loading}}\n {{#isEmpty}}\n <div class="timeline-empty text-center text-muted py-4">\n <i class="bi bi-clock-history fs-1 d-block mb-2"></i>\n <p>{{emptyMessage}}</p>\n </div>\n {{/isEmpty}}\n {{^isEmpty}}\n <div class="timeline" data-container="items"></div>\n {{/isEmpty}}\n {{/loading}}\n </div>\n ',...t}),this.position=t.position||"left",this.dateFormat=t.dateFormat||"date",this.dotStyle=t.dotStyle||"solid",this.showDate=!1!==t.showDate,this.theme=t.theme||"primary",this.groupBy=t.groupBy||"none"}_createItemView(t,e){if(this.itemViews.has(t.id))return;const i=new this.itemClass({model:t,index:e,listView:this,template:this.itemTemplate,dateFormat:this.dateFormat,dotStyle:this.dotStyle,showDate:this.showDate,theme:this.theme});return this.itemViews.set(t.id,i),i.on("item:click",this._onItemClick.bind(this)),i}_onItemClick(t){this.emit("item:click",t)}setPosition(t){return"left"!==t&&"center"!==t?(console.warn('Invalid position. Use "left" or "center"'),this):(this.position=t,this.isMounted()&&this.render(),this)}setDateFormat(t){return this.dateFormat=t,this.forEachItem(e=>{e.dateFormat=t,e.processItemData(),e.isMounted()&&e.render()}),this}setDotStyle(t){return this.dotStyle=t,this.forEachItem(e=>{e.dotStyle=t,e.processItemData(),e.isMounted()&&e.render()}),this}toggleDates(t=null){return this.showDate=null!==t?t:!this.showDate,this.forEachItem(t=>{t.showDate=this.showDate,t.isMounted()&&t.render()}),this}}export{n as Collection,e as ListView,t as ListViewItem,o as Model,TimelineView,TimelineViewItem,s as View};
|
|
225
2
|
//# sourceMappingURL=timeline.es.js.map
|