web-mojo 2.2.101 → 2.3.0
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/CHANGELOG.md +603 -0
- package/README.md +2 -2
- package/dist/admin-models.cjs.js +2 -0
- package/dist/admin-models.cjs.js.map +1 -0
- package/dist/admin-models.es.js +2 -0
- package/dist/admin-models.es.js.map +1 -0
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.css +42 -0
- package/dist/admin.es.js +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.cjs.js.map +1 -1
- package/dist/auth.es.js +1 -1
- package/dist/auth.es.js.map +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.cjs.js.map +1 -1
- package/dist/charts.css +897 -1
- package/dist/charts.es.js +1 -1
- package/dist/charts.es.js.map +1 -1
- package/dist/chat.css +96 -0
- package/dist/chunks/AssistantPanelView-BG34Qbfj.js +2 -0
- package/dist/chunks/AssistantPanelView-BG34Qbfj.js.map +1 -0
- package/dist/chunks/AssistantPanelView-DCEV6VeI.js +2 -0
- package/dist/chunks/AssistantPanelView-DCEV6VeI.js.map +1 -0
- package/dist/chunks/ChatView-B73uox2v.js +2 -0
- package/dist/chunks/ChatView-B73uox2v.js.map +1 -0
- package/dist/chunks/ChatView-W8daOwIo.js +2 -0
- package/dist/chunks/ChatView-W8daOwIo.js.map +1 -0
- package/dist/chunks/Collection-BZlmtcuL.js +2 -0
- package/dist/chunks/Collection-BZlmtcuL.js.map +1 -0
- package/dist/chunks/Collection-Bwoq6muu.js +2 -0
- package/dist/chunks/Collection-Bwoq6muu.js.map +1 -0
- package/dist/chunks/ContextMenu-BPPtuqKk.js +2 -0
- package/dist/chunks/ContextMenu-BPPtuqKk.js.map +1 -0
- package/dist/chunks/ContextMenu-q76hjQb6.js +2 -0
- package/dist/chunks/ContextMenu-q76hjQb6.js.map +1 -0
- package/dist/chunks/DataView-BbrwHMV4.js +2 -0
- package/dist/chunks/{DataView-BFx2glFg.js.map → DataView-BbrwHMV4.js.map} +1 -1
- package/dist/chunks/DataView-k-7wmk5_.js +2 -0
- package/dist/chunks/{DataView-D5C_lDdg.js.map → DataView-k-7wmk5_.js.map} +1 -1
- package/dist/chunks/FormView-DPSuwWMq.js +3 -0
- package/dist/chunks/{FormView-e-PeRx1s.js.map → FormView-DPSuwWMq.js.map} +1 -1
- package/dist/chunks/FormView-Dcy7XOtC.js +3 -0
- package/dist/chunks/{FormView-Cu4iPfvU.js.map → FormView-Dcy7XOtC.js.map} +1 -1
- package/dist/chunks/ListView-DHC-yBIw.js +2 -0
- package/dist/chunks/ListView-DHC-yBIw.js.map +1 -0
- package/dist/chunks/ListView-iGBsD4a7.js +2 -0
- package/dist/chunks/ListView-iGBsD4a7.js.map +1 -0
- package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js +2 -0
- package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js.map +1 -0
- package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js +2 -0
- package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js.map +1 -0
- package/dist/chunks/Modal-DBJU16cc.js +3 -0
- package/dist/chunks/Modal-DBJU16cc.js.map +1 -0
- package/dist/chunks/Modal-DuULCMFZ.js +3 -0
- package/dist/chunks/Modal-DuULCMFZ.js.map +1 -0
- package/dist/chunks/Passkeys-CGRZ8ZMv.js +2 -0
- package/dist/chunks/{Passkeys-DfVHrRPY.js.map → Passkeys-CGRZ8ZMv.js.map} +1 -1
- package/dist/chunks/Passkeys-Dr8-oSm9.js +2 -0
- package/dist/chunks/{Passkeys-Bj-ufmei.js.map → Passkeys-Dr8-oSm9.js.map} +1 -1
- package/dist/chunks/TokenManager-CcQFvaFD.js +2 -0
- package/dist/chunks/TokenManager-CcQFvaFD.js.map +1 -0
- package/dist/chunks/TokenManager-DEWZqbuo.js +2 -0
- package/dist/chunks/TokenManager-DEWZqbuo.js.map +1 -0
- package/dist/chunks/User-DNQhdBtI.js +2 -0
- package/dist/chunks/User-DNQhdBtI.js.map +1 -0
- package/dist/chunks/User-Dg7xpYEI.js +2 -0
- package/dist/chunks/User-Dg7xpYEI.js.map +1 -0
- package/dist/chunks/UserProfileView-B5nczdfw.js +2 -0
- package/dist/chunks/UserProfileView-B5nczdfw.js.map +1 -0
- package/dist/chunks/UserProfileView-Bpz3VZmP.js +2 -0
- package/dist/chunks/UserProfileView-Bpz3VZmP.js.map +1 -0
- package/dist/chunks/View-C5n3sIFi.js +2 -0
- package/dist/chunks/View-C5n3sIFi.js.map +1 -0
- package/dist/chunks/View-Yazho7OL.js +2 -0
- package/dist/chunks/View-Yazho7OL.js.map +1 -0
- package/dist/chunks/WebApp-CeiDNV6L.js +2 -0
- package/dist/chunks/WebApp-CeiDNV6L.js.map +1 -0
- package/dist/chunks/WebApp-irKlhuFX.js +2 -0
- package/dist/chunks/WebApp-irKlhuFX.js.map +1 -0
- package/dist/chunks/admin-B5tf0zOO.js +2 -0
- package/dist/chunks/admin-B5tf0zOO.js.map +1 -0
- package/dist/chunks/admin-CGoTpXfs.js +2 -0
- package/dist/chunks/admin-CGoTpXfs.js.map +1 -0
- package/dist/chunks/exportChart-BTJBYkOz.js +2 -0
- package/dist/chunks/exportChart-BTJBYkOz.js.map +1 -0
- package/dist/chunks/exportChart-kQ-we4Cp.js +2 -0
- package/dist/chunks/exportChart-kQ-we4Cp.js.map +1 -0
- package/dist/chunks/index-BNjCQA7q.js +2 -0
- package/dist/chunks/{index-BY54viKF.js.map → index-BNjCQA7q.js.map} +1 -1
- package/dist/chunks/index-DBsIDOAa.js +2 -0
- package/dist/chunks/{index-Df5lx5TH.js.map → index-DBsIDOAa.js.map} +1 -1
- package/dist/chunks/version-BURwX10Q.js +2 -0
- package/dist/chunks/version-BURwX10Q.js.map +1 -0
- package/dist/chunks/version-CYGIXntv.js +2 -0
- package/dist/chunks/version-CYGIXntv.js.map +1 -0
- package/dist/core.css +306 -0
- package/dist/css/web-mojo.css +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.cjs.js.map +1 -1
- package/dist/docit.es.js +1 -1
- package/dist/docit.es.js.map +1 -1
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1 -1
- package/dist/index.es.js.map +1 -1
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.cjs.js.map +1 -1
- package/dist/lightbox.es.js +1 -1
- package/dist/lightbox.es.js.map +1 -1
- package/dist/map.cjs.js +1 -1
- package/dist/map.cjs.js.map +1 -1
- package/dist/map.es.js +1 -1
- package/dist/map.es.js.map +1 -1
- package/dist/mojo-auth.es.js +94 -65
- package/dist/mojo-auth.umd.js +1 -1
- package/dist/portal.css +86 -0
- package/dist/timeline.cjs.js +1 -1
- package/dist/timeline.cjs.js.map +1 -1
- package/dist/timeline.es.js +1 -1
- package/dist/timeline.es.js.map +1 -1
- package/dist/user-profile.cjs.js +1 -1
- package/dist/user-profile.es.js +1 -1
- package/dist/web-mojo.lite.iife.js +4183 -3916
- package/dist/web-mojo.lite.iife.js.map +1 -1
- package/dist/web-mojo.lite.iife.min.js +289 -311
- package/dist/web-mojo.lite.iife.min.js.map +1 -1
- package/package.json +7 -2
- package/dist/chunks/AssistantPanelView-Bdpmd4z7.js +0 -2
- package/dist/chunks/AssistantPanelView-Bdpmd4z7.js.map +0 -1
- package/dist/chunks/AssistantPanelView-C0bdbEWr.js +0 -2
- package/dist/chunks/AssistantPanelView-C0bdbEWr.js.map +0 -1
- package/dist/chunks/ChatView-B1MZNPGy.js +0 -2
- package/dist/chunks/ChatView-B1MZNPGy.js.map +0 -1
- package/dist/chunks/ChatView-DXl9nVVV.js +0 -2
- package/dist/chunks/ChatView-DXl9nVVV.js.map +0 -1
- package/dist/chunks/Collection-C39Oy2q0.js +0 -2
- package/dist/chunks/Collection-C39Oy2q0.js.map +0 -1
- package/dist/chunks/Collection-CyK0u557.js +0 -2
- package/dist/chunks/Collection-CyK0u557.js.map +0 -1
- package/dist/chunks/ContextMenu-D-C7V6J6.js +0 -2
- package/dist/chunks/ContextMenu-D-C7V6J6.js.map +0 -1
- package/dist/chunks/ContextMenu-hjqR1pGW.js +0 -2
- package/dist/chunks/ContextMenu-hjqR1pGW.js.map +0 -1
- package/dist/chunks/DataView-BFx2glFg.js +0 -2
- package/dist/chunks/DataView-D5C_lDdg.js +0 -2
- package/dist/chunks/Dialog-1umNJi4B.js +0 -3
- package/dist/chunks/Dialog-1umNJi4B.js.map +0 -1
- package/dist/chunks/Dialog-BnxWLMfr.js +0 -3
- package/dist/chunks/Dialog-BnxWLMfr.js.map +0 -1
- package/dist/chunks/FormView-Cu4iPfvU.js +0 -3
- package/dist/chunks/FormView-e-PeRx1s.js +0 -3
- package/dist/chunks/ListView-D_hOtfWZ.js +0 -2
- package/dist/chunks/ListView-D_hOtfWZ.js.map +0 -1
- package/dist/chunks/ListView-Jkke6pU1.js +0 -2
- package/dist/chunks/ListView-Jkke6pU1.js.map +0 -1
- package/dist/chunks/MetricsCountryMapView-UdvJWArx.js +0 -2
- package/dist/chunks/MetricsCountryMapView-UdvJWArx.js.map +0 -1
- package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js +0 -2
- package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js.map +0 -1
- package/dist/chunks/MetricsMiniChartWidget-BaXxR9C6.js +0 -2
- package/dist/chunks/MetricsMiniChartWidget-BaXxR9C6.js.map +0 -1
- package/dist/chunks/MetricsMiniChartWidget-DSKmKY2Z.js +0 -2
- package/dist/chunks/MetricsMiniChartWidget-DSKmKY2Z.js.map +0 -1
- package/dist/chunks/MiniPieChart-B3sM4Bjv.js +0 -2
- package/dist/chunks/MiniPieChart-B3sM4Bjv.js.map +0 -1
- package/dist/chunks/MiniPieChart-DL5Rynvm.js +0 -2
- package/dist/chunks/MiniPieChart-DL5Rynvm.js.map +0 -1
- package/dist/chunks/MiniSeriesChart-C4DPVbU_.js +0 -2
- package/dist/chunks/MiniSeriesChart-C4DPVbU_.js.map +0 -1
- package/dist/chunks/MiniSeriesChart-DdNMLwfh.js +0 -2
- package/dist/chunks/MiniSeriesChart-DdNMLwfh.js.map +0 -1
- package/dist/chunks/Modal-COT4zRh3.js +0 -2
- package/dist/chunks/Modal-COT4zRh3.js.map +0 -1
- package/dist/chunks/Modal-DgMMvDnw.js +0 -2
- package/dist/chunks/Modal-DgMMvDnw.js.map +0 -1
- package/dist/chunks/Passkeys-Bj-ufmei.js +0 -2
- package/dist/chunks/Passkeys-DfVHrRPY.js +0 -2
- package/dist/chunks/TokenManager-DIEaBGJh.js +0 -2
- package/dist/chunks/TokenManager-DIEaBGJh.js.map +0 -1
- package/dist/chunks/TokenManager-DeXkJy0u.js +0 -2
- package/dist/chunks/TokenManager-DeXkJy0u.js.map +0 -1
- package/dist/chunks/UserProfileView-B_jyMUp0.js +0 -2
- package/dist/chunks/UserProfileView-B_jyMUp0.js.map +0 -1
- package/dist/chunks/UserProfileView-DcpvvGQS.js +0 -2
- package/dist/chunks/UserProfileView-DcpvvGQS.js.map +0 -1
- package/dist/chunks/WebApp-BvFnKj-I.js +0 -2
- package/dist/chunks/WebApp-BvFnKj-I.js.map +0 -1
- package/dist/chunks/WebApp-CfDWKmwH.js +0 -2
- package/dist/chunks/WebApp-CfDWKmwH.js.map +0 -1
- package/dist/chunks/WebSocketClient-BQAZr8C4.js +0 -2
- package/dist/chunks/WebSocketClient-BQAZr8C4.js.map +0 -1
- package/dist/chunks/WebSocketClient-YR5d82h8.js +0 -2
- package/dist/chunks/WebSocketClient-YR5d82h8.js.map +0 -1
- package/dist/chunks/admin-BgvcCWQp.js +0 -2
- package/dist/chunks/admin-BgvcCWQp.js.map +0 -1
- package/dist/chunks/admin-DzhyZ_Tn.js +0 -2
- package/dist/chunks/admin-DzhyZ_Tn.js.map +0 -1
- package/dist/chunks/index-BY54viKF.js +0 -2
- package/dist/chunks/index-Df5lx5TH.js +0 -2
- package/dist/chunks/version-8mBBYRDe.js +0 -2
- package/dist/chunks/version-8mBBYRDe.js.map +0 -1
- package/dist/chunks/version-CoLHxZIU.js +0 -2
- package/dist/chunks/version-CoLHxZIU.js.map +0 -1
package/dist/mojo-auth.es.js
CHANGED
|
@@ -17,20 +17,21 @@ var y = k((S, p) => {
|
|
|
17
17
|
passkeyLoginComplete: "/api/auth/passkeys/login/complete",
|
|
18
18
|
oauthBegin: "/api/auth/oauth/{provider}/begin",
|
|
19
19
|
oauthComplete: "/api/auth/oauth/{provider}/complete",
|
|
20
|
-
refreshToken: "/api/refresh_token"
|
|
20
|
+
refreshToken: "/api/refresh_token",
|
|
21
|
+
exchangeAuthCode: "/api/auth/exchange"
|
|
21
22
|
};
|
|
22
|
-
function i(e,
|
|
23
|
-
var
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
}), g.replace(/\/$/, "") +
|
|
23
|
+
function i(e, t) {
|
|
24
|
+
var n = u[e] || w[e] || "";
|
|
25
|
+
return t && Object.keys(t).forEach(function(r) {
|
|
26
|
+
n = n.replace("{" + r + "}", t[r]);
|
|
27
|
+
}), g.replace(/\/$/, "") + n;
|
|
27
28
|
}
|
|
28
|
-
function s(e,
|
|
29
|
-
var
|
|
29
|
+
function s(e, t, n) {
|
|
30
|
+
var r = Object.assign({ "Content-Type": "application/json" }, {});
|
|
30
31
|
return fetch(e, {
|
|
31
32
|
method: "POST",
|
|
32
|
-
headers:
|
|
33
|
-
body: JSON.stringify(
|
|
33
|
+
headers: r,
|
|
34
|
+
body: JSON.stringify(t || {})
|
|
34
35
|
}).then(function(o) {
|
|
35
36
|
return o.json().then(function(a) {
|
|
36
37
|
if (!o.ok) throw a;
|
|
@@ -38,36 +39,36 @@ var y = k((S, p) => {
|
|
|
38
39
|
});
|
|
39
40
|
});
|
|
40
41
|
}
|
|
41
|
-
function m(e,
|
|
42
|
+
function m(e, t) {
|
|
42
43
|
return fetch(e, {
|
|
43
44
|
method: "GET",
|
|
44
45
|
headers: Object.assign({ "Content-Type": "application/json" }, {})
|
|
45
|
-
}).then(function(
|
|
46
|
-
return
|
|
47
|
-
if (!
|
|
48
|
-
return
|
|
46
|
+
}).then(function(n) {
|
|
47
|
+
return n.json().then(function(r) {
|
|
48
|
+
if (!n.ok) throw r;
|
|
49
|
+
return r;
|
|
49
50
|
});
|
|
50
51
|
});
|
|
51
52
|
}
|
|
52
53
|
function h(e) {
|
|
53
|
-
var
|
|
54
|
-
if (!
|
|
55
|
-
return localStorage.setItem(c.access,
|
|
54
|
+
var t = e && e.data ? e.data : e;
|
|
55
|
+
if (!t || !t.access_token) throw new Error("No access_token in response");
|
|
56
|
+
return localStorage.setItem(c.access, t.access_token), t.refresh_token && localStorage.setItem(c.refresh, t.refresh_token), t;
|
|
56
57
|
}
|
|
57
58
|
function v(e) {
|
|
58
59
|
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
|
}
|
|
60
|
-
function
|
|
61
|
-
for (var
|
|
62
|
-
|
|
63
|
-
return
|
|
61
|
+
function f(e) {
|
|
62
|
+
for (var t = e.replace(/-/g, "+").replace(/_/g, "/"), n = atob(t), r = new Uint8Array(n.length), o = 0; o < n.length; o++)
|
|
63
|
+
r[o] = n.charCodeAt(o);
|
|
64
|
+
return r.buffer;
|
|
64
65
|
}
|
|
65
66
|
function l(e) {
|
|
66
|
-
for (var
|
|
67
|
-
|
|
68
|
-
return btoa(
|
|
67
|
+
for (var t = new Uint8Array(e), n = "", r = 0; r < t.byteLength; r++)
|
|
68
|
+
n += String.fromCharCode(t[r]);
|
|
69
|
+
return btoa(n).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
69
70
|
}
|
|
70
|
-
var
|
|
71
|
+
var d = {
|
|
71
72
|
/**
|
|
72
73
|
* Initialize the library. Must be called before any auth method.
|
|
73
74
|
* @param {object} config
|
|
@@ -91,10 +92,10 @@ var y = k((S, p) => {
|
|
|
91
92
|
* NOTE: If MFA is enabled, the response will contain { mfa_required: true, mfa_token, mfa_methods }
|
|
92
93
|
* instead of tokens. Check result.mfa_required before assuming login is complete.
|
|
93
94
|
*/
|
|
94
|
-
login: function(e,
|
|
95
|
-
return s(i("login"), { username: e, password:
|
|
96
|
-
var
|
|
97
|
-
return
|
|
95
|
+
login: function(e, t) {
|
|
96
|
+
return s(i("login"), { username: e, password: t }).then(function(n) {
|
|
97
|
+
var r = n.data || n;
|
|
98
|
+
return r.mfa_required ? r : h(n);
|
|
98
99
|
});
|
|
99
100
|
},
|
|
100
101
|
// -----------------------------------------------------------------------
|
|
@@ -116,11 +117,11 @@ var y = k((S, p) => {
|
|
|
116
117
|
* @param {string} newPassword
|
|
117
118
|
* @returns {Promise<object>}
|
|
118
119
|
*/
|
|
119
|
-
resetWithCode: function(e,
|
|
120
|
+
resetWithCode: function(e, t, n) {
|
|
120
121
|
return s(i("resetWithCode"), {
|
|
121
122
|
email: e,
|
|
122
|
-
code:
|
|
123
|
-
new_password:
|
|
123
|
+
code: t,
|
|
124
|
+
new_password: n
|
|
124
125
|
}).then(h);
|
|
125
126
|
},
|
|
126
127
|
// -----------------------------------------------------------------------
|
|
@@ -141,10 +142,10 @@ var y = k((S, p) => {
|
|
|
141
142
|
* @param {string} newPassword
|
|
142
143
|
* @returns {Promise<object>}
|
|
143
144
|
*/
|
|
144
|
-
resetWithToken: function(e,
|
|
145
|
+
resetWithToken: function(e, t) {
|
|
145
146
|
return s(i("resetWithToken"), {
|
|
146
147
|
token: e,
|
|
147
|
-
new_password:
|
|
148
|
+
new_password: t
|
|
148
149
|
}).then(h);
|
|
149
150
|
},
|
|
150
151
|
// -----------------------------------------------------------------------
|
|
@@ -173,11 +174,11 @@ var y = k((S, p) => {
|
|
|
173
174
|
* @returns {Promise<object|null>} resolves with auth data or null if no token found
|
|
174
175
|
*/
|
|
175
176
|
handleMagicTokenFromURL: function() {
|
|
176
|
-
var e = new URLSearchParams(window.location.search),
|
|
177
|
-
if (!
|
|
177
|
+
var e = new URLSearchParams(window.location.search), t = e.get("token");
|
|
178
|
+
if (!t || t.indexOf("ml:") !== 0) return Promise.resolve(null);
|
|
178
179
|
e.delete("token");
|
|
179
|
-
var
|
|
180
|
-
return window.history.replaceState({}, "",
|
|
180
|
+
var n = e.toString() ? window.location.pathname + "?" + e.toString() : window.location.pathname;
|
|
181
|
+
return window.history.replaceState({}, "", n), d.loginWithMagicToken(t);
|
|
181
182
|
},
|
|
182
183
|
// -----------------------------------------------------------------------
|
|
183
184
|
// Passkey Login (WebAuthn)
|
|
@@ -197,14 +198,14 @@ var y = k((S, p) => {
|
|
|
197
198
|
* @returns {Promise<object>}
|
|
198
199
|
*/
|
|
199
200
|
loginWithPasskeyDiscoverable: function() {
|
|
200
|
-
return
|
|
201
|
-
var
|
|
202
|
-
return
|
|
203
|
-
return Object.assign({}, o, { id:
|
|
204
|
-
})), navigator.credentials.get({ publicKey:
|
|
201
|
+
return d.isPasskeySupported() ? s(i("passkeyLoginBegin"), {}).then(function(e) {
|
|
202
|
+
var t = e.data || e, n = t.challenge_id, r = t.publicKey;
|
|
203
|
+
return r.challenge = f(r.challenge), r.allowCredentials && (r.allowCredentials = r.allowCredentials.map(function(o) {
|
|
204
|
+
return Object.assign({}, o, { id: f(o.id) });
|
|
205
|
+
})), navigator.credentials.get({ publicKey: r }).then(function(o) {
|
|
205
206
|
if (!o) throw new Error("No credential received from authenticator");
|
|
206
207
|
return s(i("passkeyLoginComplete"), {
|
|
207
|
-
challenge_id:
|
|
208
|
+
challenge_id: n,
|
|
208
209
|
credential: {
|
|
209
210
|
id: o.id,
|
|
210
211
|
rawId: l(o.rawId),
|
|
@@ -228,14 +229,14 @@ var y = k((S, p) => {
|
|
|
228
229
|
* @returns {Promise<object>}
|
|
229
230
|
*/
|
|
230
231
|
loginWithPasskey: function(e) {
|
|
231
|
-
return
|
|
232
|
-
var
|
|
233
|
-
return o.challenge =
|
|
234
|
-
return Object.assign({}, a, { id:
|
|
232
|
+
return d.isPasskeySupported() ? s(i("passkeyLoginBegin"), { username: e }).then(function(t) {
|
|
233
|
+
var n = t.data || t, r = n.challenge_id, o = n.publicKey;
|
|
234
|
+
return o.challenge = f(o.challenge), o.allowCredentials && (o.allowCredentials = o.allowCredentials.map(function(a) {
|
|
235
|
+
return Object.assign({}, a, { id: f(a.id) });
|
|
235
236
|
})), navigator.credentials.get({ publicKey: o }).then(function(a) {
|
|
236
237
|
if (!a) throw new Error("No credential received from authenticator");
|
|
237
238
|
return s(i("passkeyLoginComplete"), {
|
|
238
|
-
challenge_id:
|
|
239
|
+
challenge_id: r,
|
|
239
240
|
credential: {
|
|
240
241
|
id: a.id,
|
|
241
242
|
rawId: l(a.rawId),
|
|
@@ -269,17 +270,17 @@ var y = k((S, p) => {
|
|
|
269
270
|
* allowed by the backend (ALLOWED_REDIRECT_URLS or per-group).
|
|
270
271
|
* @returns {Promise<void>}
|
|
271
272
|
*/
|
|
272
|
-
startOAuthLogin: function(e,
|
|
273
|
+
startOAuthLogin: function(e, t) {
|
|
273
274
|
sessionStorage.setItem("oauth_provider", e);
|
|
274
|
-
var
|
|
275
|
-
return m(
|
|
275
|
+
var n = t || window.location.origin + window.location.pathname, r = i("oauthBegin", { provider: e }) + "?redirect_uri=" + encodeURIComponent(n);
|
|
276
|
+
return m(r).then(function(o) {
|
|
276
277
|
var a = o.data || o;
|
|
277
278
|
if (!a.auth_url) throw new Error("No auth_url in OAuth begin response");
|
|
278
279
|
window.location.href = a.auth_url;
|
|
279
280
|
});
|
|
280
281
|
},
|
|
281
282
|
startGoogleLogin: function(e) {
|
|
282
|
-
return
|
|
283
|
+
return d.startOAuthLogin("google", e);
|
|
283
284
|
},
|
|
284
285
|
/**
|
|
285
286
|
* Complete OAuth login for any provider — call this on your OAuth callback page.
|
|
@@ -289,15 +290,43 @@ var y = k((S, p) => {
|
|
|
289
290
|
* @returns {Promise<object>}
|
|
290
291
|
*/
|
|
291
292
|
completeOAuthLogin: function(e) {
|
|
292
|
-
var
|
|
293
|
-
return
|
|
294
|
-
code:
|
|
295
|
-
state:
|
|
293
|
+
var t = new URLSearchParams(window.location.search), n = t.get("code"), r = t.get("state");
|
|
294
|
+
return n ? s(i("oauthComplete", { provider: e }), {
|
|
295
|
+
code: n,
|
|
296
|
+
state: r
|
|
296
297
|
}).then(h) : Promise.reject(new Error("No OAuth code in URL"));
|
|
297
298
|
},
|
|
298
299
|
/** @deprecated use completeOAuthLogin('google') */
|
|
299
300
|
completeGoogleLogin: function() {
|
|
300
|
-
return
|
|
301
|
+
return d.completeOAuthLogin("google");
|
|
302
|
+
},
|
|
303
|
+
// -----------------------------------------------------------------------
|
|
304
|
+
// Cross-Origin Auth Handoff
|
|
305
|
+
// -----------------------------------------------------------------------
|
|
306
|
+
/**
|
|
307
|
+
* Exchange a one-time auth handoff code for access + refresh tokens.
|
|
308
|
+
* The auth domain mints the code via /api/auth/handoff and appends it
|
|
309
|
+
* as ?auth_code= on the redirect to the consuming app. Single-use,
|
|
310
|
+
* 60s TTL — server-enforced.
|
|
311
|
+
* Stores tokens on success.
|
|
312
|
+
* @param {string} code - 32-hex auth handoff code from ?auth_code=
|
|
313
|
+
* @returns {Promise<object>} response data ({ access_token, refresh_token, user })
|
|
314
|
+
*/
|
|
315
|
+
exchangeAuthCode: function(e) {
|
|
316
|
+
return s(i("exchangeAuthCode"), { code: e }).then(h);
|
|
317
|
+
},
|
|
318
|
+
/**
|
|
319
|
+
* Convenience: read ?auth_code= from current URL and exchange it for
|
|
320
|
+
* tokens. Cleans the param from the URL *before* the network call so
|
|
321
|
+
* a slow exchange can't leak the code to third-party scripts.
|
|
322
|
+
* @returns {Promise<object|null>} resolves with auth data or null if no code found
|
|
323
|
+
*/
|
|
324
|
+
handleAuthCodeFromURL: function() {
|
|
325
|
+
var e = new URLSearchParams(window.location.search), t = e.get("auth_code");
|
|
326
|
+
if (!t) return Promise.resolve(null);
|
|
327
|
+
e.delete("auth_code");
|
|
328
|
+
var n = window.location.pathname + (e.toString() ? "?" + e.toString() : "") + (window.location.hash || "");
|
|
329
|
+
return window.history.replaceState({}, "", n), d.exchangeAuthCode(t);
|
|
301
330
|
},
|
|
302
331
|
// -----------------------------------------------------------------------
|
|
303
332
|
// Session helpers
|
|
@@ -346,10 +375,10 @@ var y = k((S, p) => {
|
|
|
346
375
|
var e = localStorage.getItem(c.access);
|
|
347
376
|
if (!e) return null;
|
|
348
377
|
try {
|
|
349
|
-
var
|
|
350
|
-
if (
|
|
351
|
-
var
|
|
352
|
-
return
|
|
378
|
+
var t = e.split(".");
|
|
379
|
+
if (t.length !== 3) return null;
|
|
380
|
+
var n = t[1].replace(/-/g, "+").replace(/_/g, "/"), r = 4 - n.length % 4;
|
|
381
|
+
return r !== 4 && (n += "====".slice(0, r)), JSON.parse(atob(n));
|
|
353
382
|
} catch {
|
|
354
383
|
return null;
|
|
355
384
|
}
|
|
@@ -360,7 +389,7 @@ var y = k((S, p) => {
|
|
|
360
389
|
* @returns {boolean}
|
|
361
390
|
*/
|
|
362
391
|
isTokenExpired: function() {
|
|
363
|
-
var e =
|
|
392
|
+
var e = d.getTokenPayload();
|
|
364
393
|
return !e || !e.exp ? !0 : Math.floor(Date.now() / 1e3) >= e.exp;
|
|
365
394
|
},
|
|
366
395
|
/**
|
|
@@ -383,7 +412,7 @@ var y = k((S, p) => {
|
|
|
383
412
|
*/
|
|
384
413
|
getError: v
|
|
385
414
|
};
|
|
386
|
-
return
|
|
415
|
+
return d;
|
|
387
416
|
});
|
|
388
417
|
});
|
|
389
418
|
export default y();
|
package/dist/mojo-auth.umd.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(d){typeof define=="function"&&define.amd?define(d):d()})((function(){"use strict";(function(d,f){typeof define=="function"&&define.amd?define([],f):typeof module<"u"&&module.exports?module.exports=f():d.MojoAuth=f()})(typeof globalThis<"u"?globalThis:typeof window<"u"?window:void 0,function(){var d="",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",exchangeAuthCode:"/api/auth/exchange"};function i(e,n){var t=f[e]||p[e]||"";return n&&Object.keys(n).forEach(function(r){t=t.replace("{"+r+"}",n[r])}),d.replace(/\/$/,"")+t}function s(e,n,t){var r=Object.assign({"Content-Type":"application/json"},{});return fetch(e,{method:"POST",headers:r,body:JSON.stringify(n||{})}).then(function(o){return o.json().then(function(a){if(!o.ok)throw a;return a})})}function w(e,n){return fetch(e,{method:"GET",headers:Object.assign({"Content-Type":"application/json"},{})}).then(function(t){return t.json().then(function(r){if(!t.ok)throw r;return r})})}function l(e){var n=e&&e.data?e.data:e;if(!n||!n.access_token)throw new Error("No access_token in response");return localStorage.setItem(u.access,n.access_token),n.refresh_token&&localStorage.setItem(u.refresh,n.refresh_token),n}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 n=e.replace(/-/g,"+").replace(/_/g,"/"),t=atob(n),r=new Uint8Array(t.length),o=0;o<t.length;o++)r[o]=t.charCodeAt(o);return r.buffer}function c(e){for(var n=new Uint8Array(e),t="",r=0;r<n.byteLength;r++)t+=String.fromCharCode(n[r]);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");d=e.baseURL,f=Object.assign({},e.endpoints||{})},login:function(e,n){return s(i("login"),{username:e,password:n}).then(function(t){var r=t.data||t;return r.mfa_required?r:l(t)})},forgotPasswordCode:function(e){return s(i("forgotPassword"),{email:e,method:"code"})},resetWithCode:function(e,n,t){return s(i("resetWithCode"),{email:e,code:n,new_password:t}).then(l)},forgotPasswordLink:function(e){return s(i("forgotPassword"),{email:e,method:"link"})},resetWithToken:function(e,n){return s(i("resetWithToken"),{token:e,new_password:n}).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),n=e.get("token");if(!n||n.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(n)},isPasskeySupported:function(){return typeof window<"u"&&typeof window.PublicKeyCredential<"u"&&typeof navigator.credentials<"u"&&typeof navigator.credentials.get=="function"},loginWithPasskeyDiscoverable:function(){return h.isPasskeySupported()?s(i("passkeyLoginBegin"),{}).then(function(e){var n=e.data||e,t=n.challenge_id,r=n.publicKey;return r.challenge=g(r.challenge),r.allowCredentials&&(r.allowCredentials=r.allowCredentials.map(function(o){return Object.assign({},o,{id:g(o.id)})})),navigator.credentials.get({publicKey:r}).then(function(o){if(!o)throw new Error("No credential received from authenticator");return s(i("passkeyLoginComplete"),{challenge_id:t,credential:{id:o.id,rawId:c(o.rawId),type:o.type,response:{clientDataJSON:c(o.response.clientDataJSON),authenticatorData:c(o.response.authenticatorData),signature:c(o.response.signature),userHandle:o.response.userHandle?c(o.response.userHandle):null}}})})}).then(l):Promise.reject(new Error("Passkeys are not supported in this browser"))},loginWithPasskey:function(e){return h.isPasskeySupported()?s(i("passkeyLoginBegin"),{username:e}).then(function(n){var t=n.data||n,r=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:r,credential:{id:a.id,rawId:c(a.rawId),type:a.type,response:{clientDataJSON:c(a.response.clientDataJSON),authenticatorData:c(a.response.authenticatorData),signature:c(a.response.signature),userHandle:a.response.userHandle?c(a.response.userHandle):null}}})})}).then(l):Promise.reject(new Error("Passkeys are not supported in this browser"))},startOAuthLogin:function(e,n){sessionStorage.setItem("oauth_provider",e);var t=n||window.location.origin+window.location.pathname,r=i("oauthBegin",{provider:e})+"?redirect_uri="+encodeURIComponent(t);return w(r).then(function(o){var a=o.data||o;if(!a.auth_url)throw new Error("No auth_url in OAuth begin response");window.location.href=a.auth_url})},startGoogleLogin:function(e){return h.startOAuthLogin("google",e)},completeOAuthLogin:function(e){var n=new URLSearchParams(window.location.search),t=n.get("code"),r=n.get("state");return t?s(i("oauthComplete",{provider:e}),{code:t,state:r}).then(l):Promise.reject(new Error("No OAuth code in URL"))},completeGoogleLogin:function(){return h.completeOAuthLogin("google")},exchangeAuthCode:function(e){return s(i("exchangeAuthCode"),{code:e}).then(l)},handleAuthCodeFromURL:function(){var e=new URLSearchParams(window.location.search),n=e.get("auth_code");if(!n)return Promise.resolve(null);e.delete("auth_code");var t=window.location.pathname+(e.toString()?"?"+e.toString():"")+(window.location.hash||"");return window.history.replaceState({},"",t),h.exchangeAuthCode(n)},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 n=e.split(".");if(n.length!==3)return null;var t=n[1].replace(/-/g,"+").replace(/_/g,"/"),r=4-t.length%4;return r!==4&&(t+="====".slice(0,r)),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/portal.css
CHANGED
|
@@ -84,6 +84,14 @@
|
|
|
84
84
|
--mojo-sidebar-dark-bg: #343a40;
|
|
85
85
|
}
|
|
86
86
|
|
|
87
|
+
/* Under the framework's dark theme, drop the `topnav-dark` / `sidebar-dark`
|
|
88
|
+
surface to a tone that sits *between* the deep page bg (#0a0d11) and the
|
|
89
|
+
card surface (#11161d), so portal chrome reads as a band rather than a
|
|
90
|
+
raised tile. */
|
|
91
|
+
:root[data-bs-theme="dark"] {
|
|
92
|
+
--mojo-sidebar-dark-bg: #0d1117;
|
|
93
|
+
}
|
|
94
|
+
|
|
87
95
|
/*
|
|
88
96
|
Dark / Neutral (common in admin dashboards):
|
|
89
97
|
#1E1E2F (very dark blue-gray)
|
|
@@ -498,6 +506,43 @@ nav.topnav-shadow-dark {
|
|
|
498
506
|
border-right: 1px solid var(--bs-border-color);
|
|
499
507
|
}
|
|
500
508
|
|
|
509
|
+
/* Sidebar treatment classes are theme-agnostic (devs can mix `sidebar-light`
|
|
510
|
+
with `data-bs-theme="dark"`). Override the surface so the rail reads as a
|
|
511
|
+
step lighter than the page background instead of glaring white. */
|
|
512
|
+
[data-bs-theme="dark"] .sidebar-light {
|
|
513
|
+
--mojo-sidebar-light-dark-bg: var(--bs-secondary-bg);
|
|
514
|
+
--mojo-sidebar-light-dark-color: var(--bs-body-color);
|
|
515
|
+
background-color: var(--mojo-sidebar-light-dark-bg);
|
|
516
|
+
color: var(--mojo-sidebar-light-dark-color);
|
|
517
|
+
border-right-color: var(--bs-border-color-translucent);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
[data-bs-theme="dark"] .sidebar-light .sidebar-nav .nav-link {
|
|
521
|
+
color: var(--bs-body-color);
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
[data-bs-theme="dark"] .sidebar-light .sidebar-nav .nav-link:hover {
|
|
525
|
+
color: var(--bs-emphasis-color);
|
|
526
|
+
background-color: rgba(255, 255, 255, 0.06);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
[data-bs-theme="dark"] .sidebar-light .sidebar-nav .nav-link.active {
|
|
530
|
+
color: var(--bs-light);
|
|
531
|
+
background-color: var(--bs-primary);
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
[data-bs-theme="dark"] .sidebar-light .sidebar-header,
|
|
535
|
+
[data-bs-theme="dark"] .sidebar-light .nav-text-muted,
|
|
536
|
+
[data-bs-theme="dark"] .sidebar-light .text-muted {
|
|
537
|
+
color: var(--bs-secondary-color) !important;
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
/* Sanity pass on `sidebar-dark` under the dark global theme — keep the
|
|
541
|
+
existing dark surface but soften hover so it remains distinguishable. */
|
|
542
|
+
[data-bs-theme="dark"] .sidebar-dark .sidebar-nav .nav-link:hover {
|
|
543
|
+
background-color: rgba(255, 255, 255, 0.08);
|
|
544
|
+
}
|
|
545
|
+
|
|
501
546
|
.sidebar-clean {
|
|
502
547
|
background-color: var(--bs-body-bg);
|
|
503
548
|
color: var(--bs-body-color);
|
|
@@ -3166,3 +3211,44 @@ nav.topnav-shadow-dark {
|
|
|
3166
3211
|
.runner-utilization-critical {
|
|
3167
3212
|
background-color: #dc3545;
|
|
3168
3213
|
}
|
|
3214
|
+
|
|
3215
|
+
/* ========================================
|
|
3216
|
+
SideNavView — dark theme overrides
|
|
3217
|
+
|
|
3218
|
+
The base SideNavView styles live inline in the component template
|
|
3219
|
+
(src/core/views/navigation/SideNavView.js). Those values are tuned for
|
|
3220
|
+
the light theme; under data-bs-theme="dark" we re-skin the rail using
|
|
3221
|
+
Bootstrap dark-mode tokens so the values track the rest of the palette.
|
|
3222
|
+
======================================== */
|
|
3223
|
+
[data-bs-theme="dark"] .side-nav-view .snv-nav {
|
|
3224
|
+
background: var(--bs-tertiary-bg);
|
|
3225
|
+
border-right-color: var(--bs-border-color-translucent);
|
|
3226
|
+
}
|
|
3227
|
+
|
|
3228
|
+
[data-bs-theme="dark"] .side-nav-view .snv-nav a {
|
|
3229
|
+
color: var(--bs-body-color);
|
|
3230
|
+
}
|
|
3231
|
+
|
|
3232
|
+
[data-bs-theme="dark"] .side-nav-view .snv-nav a:hover {
|
|
3233
|
+
background: var(--bs-secondary-bg);
|
|
3234
|
+
}
|
|
3235
|
+
|
|
3236
|
+
[data-bs-theme="dark"] .side-nav-view .snv-nav a.active {
|
|
3237
|
+
background: rgba(13, 110, 253, 0.18);
|
|
3238
|
+
color: var(--bs-primary-text-emphasis, #6ea8fe);
|
|
3239
|
+
border-right-color: var(--bs-primary);
|
|
3240
|
+
}
|
|
3241
|
+
|
|
3242
|
+
[data-bs-theme="dark"] .side-nav-view .snv-nav-label {
|
|
3243
|
+
color: var(--bs-secondary-color);
|
|
3244
|
+
}
|
|
3245
|
+
|
|
3246
|
+
[data-bs-theme="dark"] .side-nav-view .snv-select-btn {
|
|
3247
|
+
background: var(--bs-tertiary-bg);
|
|
3248
|
+
border-color: var(--bs-border-color);
|
|
3249
|
+
color: var(--bs-body-color);
|
|
3250
|
+
}
|
|
3251
|
+
|
|
3252
|
+
[data-bs-theme="dark"] .side-nav-view .snv-select-btn:hover {
|
|
3253
|
+
background: var(--bs-secondary-bg);
|
|
3254
|
+
}
|
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-iGBsD4a7.js"),e=require("./chunks/Collection-BZlmtcuL.js"),i=require("./chunks/View-Yazho7OL.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",t.template||(this.template='\n <div class="timeline-marker timeline-marker-{{displayColor}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}}"></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.Collection=e.Collection,exports.Model=e.Model,exports.View=i.View,exports.TimelineView=TimelineView,exports.TimelineViewItem=TimelineViewItem;
|
|
2
2
|
//# sourceMappingURL=timeline.cjs.js.map
|
package/dist/timeline.cjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"timeline.cjs.js","sources":["../src/extensions/timeline/TimelineViewItem.js","../src/extensions/timeline/TimelineView.js"],"sourcesContent":["/**\n * TimelineViewItem - Individual timeline item view\n * \n * Extends ListViewItem to provide timeline-specific rendering.\n * Each item is its own View with its own model, allowing for\n * independent re-rendering when the model changes.\n * \n * Expected model attributes:\n * - date: Date string or Date object\n * - title: Main heading (optional)\n * - description: Body text (optional)\n * - icon: Bootstrap icon class (optional)\n * - color: Bootstrap color variant (optional)\n * - meta: Additional metadata (optional)\n * \n * @example\n * const item = new TimelineViewItem({\n * model: eventModel,\n * dateFormat: 'relative',\n * dotStyle: 'icon'\n * });\n */\n\nimport ListViewItem from '@core/views/list/ListViewItem.js';\nimport dataFormatter from '@core/utils/DataFormatter.js';\n\nclass TimelineViewItem extends ListViewItem {\n constructor(options = {}) {\n super({\n className: 'timeline-item',\n ...options\n });\n\n // Timeline-specific options\n this.dateFormat = options.dateFormat || 'date';\n this.dotStyle = options.dotStyle || 'solid';\n this.showDate = options.showDate !== false;\n this.theme = options.theme || 'primary';\n\n // Default timeline item template\n if (!this.template) {\n 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 `;\n }\n }\n\n async onInit() {\n await super.onInit();\n this.processItemData();\n }\n\n processItemData() {\n // Get color from model or use theme default\n this.displayColor = this.model?.get?.('color') || this.model?.color || this.theme;\n \n // Determine marker type\n const hasIcon = !!(this.model?.get?.('icon') || this.model?.icon) && this.dotStyle === 'icon';\n this.hasIcon = hasIcon;\n this.markerType = hasIcon ? 'icon' : this.dotStyle;\n \n // Format date\n const dateValue = this.model?.get?.('date') || this.model?.date;\n this.formattedDate = this.formatDate(dateValue);\n }\n\n formatDate(date) {\n if (!date) return '';\n \n switch (this.dateFormat) {\n case 'datetime':\n return dataFormatter.pipe(date, 'datetime');\n case 'relative':\n return dataFormatter.pipe(date, 'timeago');\n default:\n return dataFormatter.pipe(date, 'date');\n }\n }\n\n // Override to disable selection behavior in timeline\n async onActionSelect(event, _element) {\n event.stopPropagation();\n \n // Emit click event instead of selection\n this.emit('item:click', {\n item: this,\n model: this.model,\n index: this.index,\n data: this.model?.toJSON ? this.model.toJSON() : this.model\n });\n\n if (this.listView) {\n this.listView.emit('item:click', {\n item: this,\n model: this.model,\n index: this.index,\n data: this.model?.toJSON ? this.model.toJSON() : this.model\n });\n }\n }\n}\n\nexport default TimelineViewItem;\n","/**\n * TimelineView - Timeline component extending ListView\n * \n * Displays chronological events from a Collection with clean, modern styling.\n * Each timeline item is managed as a separate view that updates independently\n * when its model changes.\n * \n * Features:\n * - Collection-based data management\n * - Left-aligned or center-aligned layout\n * - Customizable markers (dots, icons)\n * - Date formatting and grouping\n * - Individual item re-rendering\n * - Responsive Bootstrap 5 styling\n * \n * @example\n * const timeline = new TimelineView({\n * collection: eventCollection,\n * position: 'left',\n * dotStyle: 'icon',\n * dateFormat: 'relative'\n * });\n * \n * @example\n * // Custom item template\n * const timeline = new TimelineView({\n * collection: historyCollection,\n * itemTemplate: `\n * <div class=\"custom-timeline-item\">\n * <strong>{{model.title}}</strong>\n * <p>{{model.description}}</p>\n * </div>\n * `\n * });\n */\n\nimport ListView from '@core/views/list/ListView.js';\nimport TimelineViewItem from './TimelineViewItem.js';\n\nclass TimelineView extends ListView {\n constructor(options = {}) {\n // Override ListView defaults with timeline-specific settings\n super({\n className: 'timeline-view',\n itemClass: options.itemClass || TimelineViewItem,\n selectionMode: 'none', // Timelines typically don't use selection\n emptyMessage: options.emptyMessage || 'No timeline events to display',\n 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 `,\n ...options\n });\n\n // Timeline-specific options\n this.position = options.position || 'left'; // 'left' or 'center'\n this.dateFormat = options.dateFormat || 'date'; // 'date', 'datetime', 'relative'\n this.dotStyle = options.dotStyle || 'solid'; // 'solid', 'hollow', 'icon'\n this.showDate = options.showDate !== false;\n this.theme = options.theme || 'primary';\n this.groupBy = options.groupBy || 'none'; // Future: 'none', 'day', 'month', 'year'\n }\n\n /**\n * Override _createItemView to pass timeline-specific options\n */\n _createItemView(model, index) {\n // Don't create duplicate views\n if (this.itemViews.has(model.id)) return;\n\n const itemView = new this.itemClass({\n model: model,\n index: index,\n listView: this,\n template: this.itemTemplate,\n // Pass timeline-specific options to items\n dateFormat: this.dateFormat,\n dotStyle: this.dotStyle,\n showDate: this.showDate,\n theme: this.theme\n });\n\n // Store the item view\n this.itemViews.set(model.id, itemView);\n\n // Set up item event listeners\n itemView.on('item:click', this._onItemClick.bind(this));\n\n return itemView;\n }\n\n /**\n * Handle item clicks (replaces selection behavior)\n */\n _onItemClick(event) {\n this.emit('item:click', event);\n }\n\n /**\n * Update timeline position\n */\n setPosition(position) {\n if (position !== 'left' && position !== 'center') {\n console.warn('Invalid position. Use \"left\" or \"center\"');\n return this;\n }\n \n this.position = position;\n if (this.isMounted()) {\n this.render();\n }\n return this;\n }\n\n /**\n * Update date format for all items\n */\n setDateFormat(format) {\n this.dateFormat = format;\n \n // Update all items\n this.forEachItem(itemView => {\n itemView.dateFormat = format;\n itemView.processItemData();\n if (itemView.isMounted()) {\n itemView.render();\n }\n });\n \n return this;\n }\n\n /**\n * Update dot style for all items\n */\n setDotStyle(style) {\n this.dotStyle = style;\n \n // Update all items\n this.forEachItem(itemView => {\n itemView.dotStyle = style;\n itemView.processItemData();\n if (itemView.isMounted()) {\n itemView.render();\n }\n });\n \n return this;\n }\n\n /**\n * Toggle date display\n */\n toggleDates(show = null) {\n this.showDate = show !== null ? show : !this.showDate;\n \n // Update all items\n this.forEachItem(itemView => {\n itemView.showDate = this.showDate;\n if (itemView.isMounted()) {\n itemView.render();\n }\n });\n \n return this;\n }\n}\n\nexport default TimelineView;\n"],"names":["TimelineViewItem","ListViewItem","constructor","options","super","className","this","dateFormat","dotStyle","showDate","theme","template","onInit","processItemData","displayColor","model","get","color","hasIcon","icon","markerType","dateValue","date","formattedDate","formatDate","dataFormatter","pipe","onActionSelect","event","_element","stopPropagation","emit","item","index","data","toJSON","listView","TimelineView","ListView","itemClass","selectionMode","emptyMessage","position","groupBy","_createItemView","itemViews","has","id","itemView","itemTemplate","set","on","_onItemClick","bind","setPosition","console","warn","isMounted","render","setDateFormat","format","forEachItem","setDotStyle","style","toggleDates","show"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"timeline.cjs.js","sources":["../src/extensions/timeline/TimelineViewItem.js","../src/extensions/timeline/TimelineView.js"],"sourcesContent":["/**\n * TimelineViewItem - Individual timeline item view\n * \n * Extends ListViewItem to provide timeline-specific rendering.\n * Each item is its own View with its own model, allowing for\n * independent re-rendering when the model changes.\n * \n * Expected model attributes:\n * - date: Date string or Date object\n * - title: Main heading (optional)\n * - description: Body text (optional)\n * - icon: Bootstrap icon class (optional)\n * - color: Bootstrap color variant (optional)\n * - meta: Additional metadata (optional)\n * \n * @example\n * const item = new TimelineViewItem({\n * model: eventModel,\n * dateFormat: 'relative',\n * dotStyle: 'icon'\n * });\n */\n\nimport ListViewItem from '@core/views/list/ListViewItem.js';\nimport dataFormatter from '@core/utils/DataFormatter.js';\n\nclass TimelineViewItem extends ListViewItem {\n constructor(options = {}) {\n super({\n className: 'timeline-item',\n ...options\n });\n\n // Timeline-specific options\n this.dateFormat = options.dateFormat || 'date';\n this.dotStyle = options.dotStyle || 'solid';\n this.showDate = options.showDate !== false;\n this.theme = options.theme || 'primary';\n\n // Default timeline item template — apply only when the caller didn't\n // pass a custom template. Checking `options.template` (not\n // `this.template`) because the parent ListViewItem constructor\n // always sets `this.template` to its own default; without this guard\n // the timeline template never applied and items rendered with\n // ListViewItem's `<span class=\"item-id\">` chrome instead.\n if (!options.template) {\n // The marker's solid background comes from the color-keyed\n // class (`timeline-marker-primary`, `-info`, …). Without it the\n // icon circle is transparent and the timeline's vertical line\n // shows through the center of the icon.\n this.template = `\n <div class=\"timeline-marker timeline-marker-{{displayColor}}\">\n {{#hasIcon}}\n <i class=\"bi {{model.icon}}\"></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 `;\n }\n }\n\n async onInit() {\n await super.onInit();\n this.processItemData();\n }\n\n processItemData() {\n // Get color from model or use theme default\n this.displayColor = this.model?.get?.('color') || this.model?.color || this.theme;\n \n // Determine marker type\n const hasIcon = !!(this.model?.get?.('icon') || this.model?.icon) && this.dotStyle === 'icon';\n this.hasIcon = hasIcon;\n this.markerType = hasIcon ? 'icon' : this.dotStyle;\n \n // Format date\n const dateValue = this.model?.get?.('date') || this.model?.date;\n this.formattedDate = this.formatDate(dateValue);\n }\n\n formatDate(date) {\n if (!date) return '';\n \n switch (this.dateFormat) {\n case 'datetime':\n return dataFormatter.pipe(date, 'datetime');\n case 'relative':\n return dataFormatter.pipe(date, 'timeago');\n default:\n return dataFormatter.pipe(date, 'date');\n }\n }\n\n // Override to disable selection behavior in timeline\n async onActionSelect(event, _element) {\n event.stopPropagation();\n \n // Emit click event instead of selection\n this.emit('item:click', {\n item: this,\n model: this.model,\n index: this.index,\n data: this.model?.toJSON ? this.model.toJSON() : this.model\n });\n\n if (this.listView) {\n this.listView.emit('item:click', {\n item: this,\n model: this.model,\n index: this.index,\n data: this.model?.toJSON ? this.model.toJSON() : this.model\n });\n }\n }\n}\n\nexport default TimelineViewItem;\n","/**\n * TimelineView - Timeline component extending ListView\n * \n * Displays chronological events from a Collection with clean, modern styling.\n * Each timeline item is managed as a separate view that updates independently\n * when its model changes.\n * \n * Features:\n * - Collection-based data management\n * - Left-aligned or center-aligned layout\n * - Customizable markers (dots, icons)\n * - Date formatting and grouping\n * - Individual item re-rendering\n * - Responsive Bootstrap 5 styling\n * \n * @example\n * const timeline = new TimelineView({\n * collection: eventCollection,\n * position: 'left',\n * dotStyle: 'icon',\n * dateFormat: 'relative'\n * });\n * \n * @example\n * // Custom item template\n * const timeline = new TimelineView({\n * collection: historyCollection,\n * itemTemplate: `\n * <div class=\"custom-timeline-item\">\n * <strong>{{model.title}}</strong>\n * <p>{{model.description}}</p>\n * </div>\n * `\n * });\n */\n\nimport ListView from '@core/views/list/ListView.js';\nimport TimelineViewItem from './TimelineViewItem.js';\nimport './timeline.css';\n\nclass TimelineView extends ListView {\n constructor(options = {}) {\n // Override ListView defaults with timeline-specific settings\n super({\n className: 'timeline-view',\n itemClass: options.itemClass || TimelineViewItem,\n selectionMode: 'none', // Timelines typically don't use selection\n emptyMessage: options.emptyMessage || 'No timeline events to display',\n 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 `,\n ...options\n });\n\n // Timeline-specific options\n this.position = options.position || 'left'; // 'left' or 'center'\n this.dateFormat = options.dateFormat || 'date'; // 'date', 'datetime', 'relative'\n this.dotStyle = options.dotStyle || 'solid'; // 'solid', 'hollow', 'icon'\n this.showDate = options.showDate !== false;\n this.theme = options.theme || 'primary';\n this.groupBy = options.groupBy || 'none'; // Future: 'none', 'day', 'month', 'year'\n }\n\n /**\n * Override _createItemView to pass timeline-specific options\n */\n _createItemView(model, index) {\n // Don't create duplicate views\n if (this.itemViews.has(model.id)) return;\n\n const itemView = new this.itemClass({\n model: model,\n index: index,\n listView: this,\n template: this.itemTemplate,\n // Pass timeline-specific options to items\n dateFormat: this.dateFormat,\n dotStyle: this.dotStyle,\n showDate: this.showDate,\n theme: this.theme\n });\n\n // Store the item view\n this.itemViews.set(model.id, itemView);\n\n // Set up item event listeners\n itemView.on('item:click', this._onItemClick.bind(this));\n\n return itemView;\n }\n\n /**\n * Handle item clicks (replaces selection behavior)\n */\n _onItemClick(event) {\n this.emit('item:click', event);\n }\n\n /**\n * Update timeline position\n */\n setPosition(position) {\n if (position !== 'left' && position !== 'center') {\n console.warn('Invalid position. Use \"left\" or \"center\"');\n return this;\n }\n \n this.position = position;\n if (this.isMounted()) {\n this.render();\n }\n return this;\n }\n\n /**\n * Update date format for all items\n */\n setDateFormat(format) {\n this.dateFormat = format;\n \n // Update all items\n this.forEachItem(itemView => {\n itemView.dateFormat = format;\n itemView.processItemData();\n if (itemView.isMounted()) {\n itemView.render();\n }\n });\n \n return this;\n }\n\n /**\n * Update dot style for all items\n */\n setDotStyle(style) {\n this.dotStyle = style;\n \n // Update all items\n this.forEachItem(itemView => {\n itemView.dotStyle = style;\n itemView.processItemData();\n if (itemView.isMounted()) {\n itemView.render();\n }\n });\n \n return this;\n }\n\n /**\n * Toggle date display\n */\n toggleDates(show = null) {\n this.showDate = show !== null ? show : !this.showDate;\n \n // Update all items\n this.forEachItem(itemView => {\n itemView.showDate = this.showDate;\n if (itemView.isMounted()) {\n itemView.render();\n }\n });\n \n return this;\n }\n}\n\nexport default TimelineView;\n"],"names":["TimelineViewItem","ListViewItem","constructor","options","super","className","this","dateFormat","dotStyle","showDate","theme","template","onInit","processItemData","displayColor","model","get","color","hasIcon","icon","markerType","dateValue","date","formattedDate","formatDate","dataFormatter","pipe","onActionSelect","event","_element","stopPropagation","emit","item","index","data","toJSON","listView","TimelineView","ListView","itemClass","selectionMode","emptyMessage","position","groupBy","_createItemView","itemViews","has","id","itemView","itemTemplate","set","on","_onItemClick","bind","setPosition","console","warn","isMounted","render","setDateFormat","format","forEachItem","setDotStyle","style","toggleDates","show"],"mappings":"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"}
|
package/dist/timeline.es.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{L as t,a as e}from"./chunks/ListView-
|
|
1
|
+
import{L as t,a as e}from"./chunks/ListView-DHC-yBIw.js";import{d as i}from"./chunks/Collection-Bwoq6muu.js";import{C as s,M as n}from"./chunks/Collection-Bwoq6muu.js";import{V as o}from"./chunks/View-C5n3sIFi.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",t.template||(this.template='\n <div class="timeline-marker timeline-marker-{{displayColor}}">\n {{#hasIcon}}\n <i class="bi {{model.icon}}"></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{s as Collection,e as ListView,t as ListViewItem,n as Model,TimelineView,TimelineViewItem,o as View};
|
|
2
2
|
//# sourceMappingURL=timeline.es.js.map
|