underpost 2.8.878 → 2.8.882
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/.env.development +35 -3
- package/.env.production +40 -3
- package/.env.test +35 -3
- package/.github/workflows/release.cd.yml +3 -3
- package/README.md +20 -2
- package/bin/deploy.js +40 -0
- package/cli.md +3 -1
- package/conf.js +29 -3
- package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
- package/manifests/deployment/dd-test-development/deployment.yaml +6 -6
- package/package.json +1 -2
- package/src/api/document/document.controller.js +66 -0
- package/src/api/document/document.model.js +51 -0
- package/src/api/document/document.router.js +24 -0
- package/src/api/document/document.service.js +133 -0
- package/src/cli/deploy.js +1 -1
- package/src/cli/index.js +2 -0
- package/src/cli/repository.js +2 -0
- package/src/cli/run.js +27 -1
- package/src/client/Default.index.js +46 -1
- package/src/client/components/core/Account.js +8 -1
- package/src/client/components/core/AgGrid.js +18 -9
- package/src/client/components/core/Auth.js +258 -89
- package/src/client/components/core/BtnIcon.js +13 -3
- package/src/client/components/core/Content.js +2 -1
- package/src/client/components/core/CssCore.js +40 -27
- package/src/client/components/core/Docs.js +189 -88
- package/src/client/components/core/Input.js +34 -19
- package/src/client/components/core/LoadingAnimation.js +5 -10
- package/src/client/components/core/Modal.js +280 -123
- package/src/client/components/core/ObjectLayerEngine.js +470 -104
- package/src/client/components/core/ObjectLayerEngineModal.js +1 -0
- package/src/client/components/core/Panel.js +9 -2
- package/src/client/components/core/PanelForm.js +234 -76
- package/src/client/components/core/Router.js +15 -15
- package/src/client/components/core/ToolTip.js +83 -19
- package/src/client/components/core/Translate.js +1 -1
- package/src/client/components/core/VanillaJs.js +7 -3
- package/src/client/components/core/windowGetDimensions.js +202 -0
- package/src/client/components/default/MenuDefault.js +105 -41
- package/src/client/components/default/RoutesDefault.js +2 -0
- package/src/client/services/default/default.management.js +1 -0
- package/src/client/services/document/document.service.js +97 -0
- package/src/client/services/file/file.service.js +2 -0
- package/src/client/ssr/Render.js +1 -1
- package/src/client/ssr/head/DefaultScripts.js +2 -0
- package/src/client/ssr/head/Seo.js +1 -0
- package/src/index.js +1 -1
- package/src/mailer/EmailRender.js +1 -1
- package/src/server/auth.js +68 -17
- package/src/server/client-build.js +2 -3
- package/src/server/client-formatted.js +40 -12
- package/src/server/conf.js +5 -1
- package/src/server/crypto.js +195 -76
- package/src/server/object-layer.js +196 -0
- package/src/server/peer.js +47 -5
- package/src/server/process.js +85 -1
- package/src/server/runtime.js +23 -23
- package/src/server/ssr.js +52 -10
- package/src/server/valkey.js +89 -1
- package/test/crypto.test.js +117 -0
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility class for authentication state management and session lifecycle control.
|
|
3
|
+
* This class is designed to be used as a singleton instance (exported as 'Auth').
|
|
4
|
+
* @module src/client/components/core/Auth.js
|
|
5
|
+
* @namespace AuthClient
|
|
6
|
+
*/
|
|
7
|
+
|
|
1
8
|
import { UserMock, UserService } from '../../services/user/user.service.js';
|
|
2
9
|
import { Account } from './Account.js';
|
|
3
10
|
import { loggerFactory } from './Logger.js';
|
|
@@ -9,95 +16,202 @@ import { s } from './VanillaJs.js';
|
|
|
9
16
|
|
|
10
17
|
const logger = loggerFactory(import.meta, { trace: true });
|
|
11
18
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Manages user authentication state, tokens, and session lifecycle.
|
|
21
|
+
* @memberof AuthClient
|
|
22
|
+
*/
|
|
23
|
+
class Auth {
|
|
24
|
+
/**
|
|
25
|
+
* The current user access token (JWT).
|
|
26
|
+
* @type {string}
|
|
27
|
+
* @private
|
|
28
|
+
*/
|
|
29
|
+
#token = '';
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* The token for anonymous guest sessions.
|
|
33
|
+
* @type {string}
|
|
34
|
+
* @private
|
|
35
|
+
*/
|
|
36
|
+
#guestToken = '';
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Timeout ID for the token refresh schedule.
|
|
40
|
+
* @type {number | undefined}
|
|
41
|
+
* @private
|
|
42
|
+
*/
|
|
43
|
+
#refreshTimeout;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates an instance of Auth.
|
|
47
|
+
*/
|
|
48
|
+
constructor() {
|
|
49
|
+
// Private fields are initialized above.
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// --- Token Management ---
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Sets the user's access token.
|
|
56
|
+
* @memberof AuthClient.Auth
|
|
57
|
+
* @param {string} [value=''] - The JWT token value.
|
|
58
|
+
* @returns {string} The set token value.
|
|
59
|
+
*/
|
|
60
|
+
setToken(value = '') {
|
|
61
|
+
return (this.#token = value);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Clears the user's access token.
|
|
66
|
+
* @memberof AuthClient.Auth
|
|
67
|
+
* @returns {string} An empty string.
|
|
68
|
+
*/
|
|
69
|
+
deleteToken() {
|
|
70
|
+
return (this.#token = '');
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Gets the user's access token.
|
|
75
|
+
* @memberof AuthClient.Auth
|
|
76
|
+
* @returns {string} The JWT token.
|
|
77
|
+
*/
|
|
78
|
+
getToken() {
|
|
79
|
+
return this.#token;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Sets the anonymous guest token.
|
|
84
|
+
* @memberof AuthClient.Auth
|
|
85
|
+
* @param {string} [value=''] - The guest token value.
|
|
86
|
+
* @returns {string} The set guest token value.
|
|
87
|
+
*/
|
|
88
|
+
setGuestToken(value = '') {
|
|
89
|
+
return (this.#guestToken = value);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Clears the anonymous guest token.
|
|
94
|
+
* @memberof AuthClient.Auth
|
|
95
|
+
* @returns {string} An empty string.
|
|
96
|
+
*/
|
|
97
|
+
deleteGuestToken() {
|
|
98
|
+
return (this.#guestToken = '');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Gets the anonymous guest token.
|
|
103
|
+
* @memberof AuthClient.Auth
|
|
104
|
+
* @returns {string} The guest token.
|
|
105
|
+
*/
|
|
106
|
+
getGuestToken() {
|
|
107
|
+
return this.#guestToken;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Generates the JWT header string (e.g., "Bearer [token]") using the active token (user or guest).
|
|
112
|
+
* @memberof AuthClient.Auth
|
|
113
|
+
* @returns {string} The Bearer token string or an empty string.
|
|
114
|
+
*/
|
|
115
|
+
getJWT() {
|
|
116
|
+
if (this.getToken()) return `Bearer ${this.getToken()}`;
|
|
117
|
+
if (this.getGuestToken()) return `Bearer ${this.getGuestToken()}`;
|
|
42
118
|
return '';
|
|
43
|
-
}
|
|
44
|
-
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Decodes the payload section of a JWT token.
|
|
123
|
+
* @static
|
|
124
|
+
* @memberof AuthClient.Auth
|
|
125
|
+
* @param {string} token - The JWT string.
|
|
126
|
+
* @returns {object | null} The decoded JWT payload object, or null on failure.
|
|
127
|
+
*/
|
|
128
|
+
static decodeJwt(token) {
|
|
45
129
|
try {
|
|
130
|
+
// Uses atob for base64 decoding of the middle part of the JWT
|
|
46
131
|
return JSON.parse(atob(token.split('.')[1]));
|
|
47
132
|
} catch (e) {
|
|
133
|
+
logger.error('Failed to decode JWT:', e);
|
|
48
134
|
return null;
|
|
49
135
|
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// --- Session Management ---
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Schedules the access token to be refreshed shortly before it expires.
|
|
142
|
+
* Clears any existing refresh timeout before setting a new one.
|
|
143
|
+
* @memberof AuthClient.Auth
|
|
144
|
+
* @returns {void}
|
|
145
|
+
*/
|
|
146
|
+
scheduleTokenRefresh() {
|
|
147
|
+
if (this.#refreshTimeout) {
|
|
148
|
+
clearTimeout(this.#refreshTimeout);
|
|
149
|
+
this.#refreshTimeout = undefined;
|
|
54
150
|
}
|
|
55
151
|
|
|
56
|
-
const currentToken =
|
|
152
|
+
const currentToken = this.getToken();
|
|
57
153
|
if (!currentToken) return;
|
|
58
154
|
|
|
59
155
|
const payload = Auth.decodeJwt(currentToken);
|
|
60
|
-
if (!payload || !payload.refreshExpiresAt) return;
|
|
156
|
+
if (!payload || !payload.refreshExpiresAt) return; // Requires refreshExpiresAt in milliseconds
|
|
61
157
|
|
|
62
158
|
const expiresIn = payload.refreshExpiresAt - Date.now();
|
|
63
|
-
const refreshBuffer = 2 * 60 * 1000; // 2 minutes
|
|
159
|
+
const refreshBuffer = 2 * 60 * 1000; // 2 minutes buffer before expiry
|
|
64
160
|
const refreshIn = expiresIn - refreshBuffer;
|
|
65
161
|
|
|
66
|
-
logger.info(`Token refresh in ${refreshIn / (1000 * 60)} minutes`);
|
|
162
|
+
logger.info(`Token refresh scheduled in ${refreshIn / (1000 * 60)} minutes`);
|
|
67
163
|
|
|
68
|
-
if (refreshIn <= 0)
|
|
164
|
+
if (refreshIn <= 0) {
|
|
165
|
+
logger.warn('Token already expired or too close to expiry, skipping refresh schedule.');
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
69
168
|
|
|
70
|
-
this
|
|
71
|
-
const { data, status } = await UserService.get({ id: 'auth' });
|
|
72
|
-
if (status === 'success') {
|
|
73
|
-
logger.info('
|
|
74
|
-
|
|
169
|
+
this.#refreshTimeout = setTimeout(async () => {
|
|
170
|
+
const { data, status } = await UserService.get({ id: 'auth' }); // API call to get a fresh token
|
|
171
|
+
if (status === 'success' && data?.token) {
|
|
172
|
+
logger.info('Successfully refreshed access token.');
|
|
173
|
+
this.setToken(data.token);
|
|
75
174
|
localStorage.setItem('jwt', data.token);
|
|
76
|
-
|
|
77
|
-
} else
|
|
175
|
+
this.scheduleTokenRefresh(); // Schedule the next refresh
|
|
176
|
+
} else {
|
|
177
|
+
logger.warn('Token refresh failed, attempting session out.');
|
|
178
|
+
this.sessionOut();
|
|
179
|
+
}
|
|
78
180
|
}, refreshIn);
|
|
79
|
-
}
|
|
80
|
-
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Establishes a user session (logged-in) or falls back to a guest session.
|
|
185
|
+
* It attempts to use the provided token or a token from localStorage ('jwt').
|
|
186
|
+
* @memberof AuthClient.Auth
|
|
187
|
+
* @param {object} [userServicePayload] - Payload from a successful login/signup call to UserService.
|
|
188
|
+
* @returns {Promise<{user: object}>} A promise resolving to the current user object.
|
|
189
|
+
*/
|
|
190
|
+
async sessionIn(userServicePayload) {
|
|
81
191
|
try {
|
|
82
|
-
|
|
192
|
+
let token = userServicePayload?.data?.token || localStorage.getItem('jwt');
|
|
193
|
+
|
|
83
194
|
if (token) {
|
|
84
|
-
|
|
195
|
+
this.setToken(token);
|
|
85
196
|
|
|
86
197
|
const result = userServicePayload
|
|
87
198
|
? userServicePayload // From login/signup
|
|
88
|
-
: await UserService.get({ id: 'auth' });
|
|
199
|
+
: await UserService.get({ id: 'auth' }); // Verify token with backend
|
|
89
200
|
|
|
90
201
|
const { status, data, message } = result;
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
202
|
+
|
|
203
|
+
if (status === 'success' && data.token) {
|
|
204
|
+
// A valid user token was found/refreshed
|
|
205
|
+
this.setToken(data.token);
|
|
206
|
+
localStorage.setItem('jwt', data.token);
|
|
207
|
+
this.renderSessionUI();
|
|
95
208
|
await LogIn.Trigger({ user: data.user });
|
|
96
209
|
await Account.updateForm(data.user);
|
|
97
|
-
|
|
210
|
+
this.scheduleTokenRefresh();
|
|
98
211
|
return { user: data.user };
|
|
99
|
-
}
|
|
100
|
-
|
|
212
|
+
} else if (message && message.match('expired')) {
|
|
213
|
+
logger.warn('User session token expired.');
|
|
214
|
+
// Redirect to login modal and push notification
|
|
101
215
|
setTimeout(() => {
|
|
102
216
|
s(`.main-btn-log-in`).click();
|
|
103
217
|
NotificationManager.Push({
|
|
@@ -105,69 +219,124 @@ const Auth = {
|
|
|
105
219
|
status: 'warning',
|
|
106
220
|
});
|
|
107
221
|
});
|
|
222
|
+
}
|
|
108
223
|
}
|
|
109
|
-
|
|
110
|
-
|
|
224
|
+
|
|
225
|
+
// Cleanup failed user session attempt
|
|
226
|
+
this.deleteToken();
|
|
111
227
|
localStorage.removeItem('jwt');
|
|
112
228
|
|
|
113
|
-
// Anon guest session
|
|
229
|
+
// Anon guest session attempt
|
|
114
230
|
let guestToken = localStorage.getItem('jwt.g');
|
|
115
231
|
if (guestToken) {
|
|
116
|
-
|
|
117
|
-
let { data, status, message } = await UserService.get({ id: 'auth' });
|
|
118
|
-
if (status === 'success') {
|
|
232
|
+
this.setGuestToken(guestToken);
|
|
233
|
+
let { data, status, message } = await UserService.get({ id: 'auth' }); // Verify guest token
|
|
234
|
+
if (status === 'success' && data.token) {
|
|
235
|
+
// Guest token is valid and refreshed
|
|
236
|
+
this.setGuestToken(data.token);
|
|
237
|
+
localStorage.setItem('jwt.g', data.token);
|
|
119
238
|
await LogIn.Trigger(data);
|
|
120
239
|
await Account.updateForm(data.user);
|
|
121
240
|
return data;
|
|
122
|
-
} else
|
|
241
|
+
} else {
|
|
242
|
+
logger.error(`Guest token validation failed: ${message}`);
|
|
243
|
+
// Fall through to full sessionOut to re-create guest session
|
|
244
|
+
}
|
|
123
245
|
}
|
|
124
|
-
|
|
246
|
+
|
|
247
|
+
// If all attempts fail, create a new guest session (which calls sessionIn recursively)
|
|
248
|
+
return await this.sessionOut();
|
|
125
249
|
} catch (error) {
|
|
126
|
-
logger.error(error);
|
|
250
|
+
logger.error('Error during sessionIn process:', error);
|
|
251
|
+
// Fallback to a mock user object
|
|
127
252
|
return { user: UserMock.default };
|
|
128
253
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Ends the current user session (logout) and initiates a new anonymous guest session.
|
|
258
|
+
* @memberof AuthClient.Auth
|
|
259
|
+
* @returns {Promise<object>} A promise resolving to the newly created guest session data.
|
|
260
|
+
*/
|
|
261
|
+
async sessionOut() {
|
|
262
|
+
// 1. End User Session
|
|
263
|
+
try {
|
|
132
264
|
const result = await UserService.delete({ id: 'logout' });
|
|
133
265
|
localStorage.removeItem('jwt');
|
|
134
|
-
|
|
135
|
-
if (this
|
|
136
|
-
clearTimeout(this
|
|
266
|
+
this.deleteToken();
|
|
267
|
+
if (this.#refreshTimeout) {
|
|
268
|
+
clearTimeout(this.#refreshTimeout);
|
|
269
|
+
this.#refreshTimeout = undefined;
|
|
137
270
|
}
|
|
138
|
-
|
|
271
|
+
this.renderGuestUi();
|
|
272
|
+
// Reset user data in the LogIn state/model
|
|
139
273
|
LogIn.Scope.user.main.model.user = {};
|
|
140
274
|
await LogOut.Trigger(result);
|
|
275
|
+
} catch (error) {
|
|
276
|
+
logger.error('Error during user logout:', error);
|
|
141
277
|
}
|
|
142
|
-
|
|
278
|
+
|
|
279
|
+
// 2. Start Guest Session
|
|
280
|
+
try {
|
|
143
281
|
localStorage.removeItem('jwt.g');
|
|
144
|
-
|
|
145
|
-
const result = await UserService.post({ id: 'guest' });
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
282
|
+
this.deleteGuestToken();
|
|
283
|
+
const result = await UserService.post({ id: 'guest' }); // Request a new guest token
|
|
284
|
+
|
|
285
|
+
if (result.status === 'success' && result.data.token) {
|
|
286
|
+
localStorage.setItem('jwt.g', result.data.token);
|
|
287
|
+
this.setGuestToken(result.data.token);
|
|
288
|
+
// Recursively call sessionIn to complete the guest login process (UI update, etc.)
|
|
289
|
+
return await this.sessionIn();
|
|
290
|
+
} else {
|
|
291
|
+
logger.error('Failed to get a new guest token.');
|
|
292
|
+
return { user: UserMock.default };
|
|
293
|
+
}
|
|
294
|
+
} catch (error) {
|
|
295
|
+
logger.error('Error during guest session creation:', error);
|
|
296
|
+
return { user: UserMock.default };
|
|
149
297
|
}
|
|
150
|
-
}
|
|
151
|
-
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// --- UI Rendering ---
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Renders the UI for a logged-in user (hides Log In/Sign Up, shows Log Out/Account).
|
|
304
|
+
* Also closes any active login/signup modals.
|
|
305
|
+
* @memberof AuthClient.Auth
|
|
306
|
+
* @returns {void}
|
|
307
|
+
*/
|
|
308
|
+
renderSessionUI() {
|
|
152
309
|
s(`.main-btn-log-in`).style.display = 'none';
|
|
153
310
|
s(`.main-btn-sign-up`).style.display = 'none';
|
|
154
311
|
s(`.main-btn-log-out`).style.display = null;
|
|
155
312
|
s(`.main-btn-account`).style.display = null;
|
|
156
313
|
setTimeout(() => {
|
|
314
|
+
// Close any open login/signup modals
|
|
157
315
|
if (s(`.modal-log-in`)) s(`.btn-close-modal-log-in`).click();
|
|
158
316
|
if (s(`.modal-sign-up`)) s(`.btn-close-modal-sign-up`).click();
|
|
159
317
|
});
|
|
160
|
-
}
|
|
161
|
-
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Renders the UI for a guest user (shows Log In/Sign Up, hides Log Out/Account).
|
|
322
|
+
* Also closes any active logout/account modals.
|
|
323
|
+
* @memberof AuthClient.Auth
|
|
324
|
+
* @returns {void}
|
|
325
|
+
*/
|
|
326
|
+
renderGuestUi() {
|
|
162
327
|
s(`.main-btn-log-in`).style.display = null;
|
|
163
328
|
s(`.main-btn-sign-up`).style.display = null;
|
|
164
329
|
s(`.main-btn-log-out`).style.display = 'none';
|
|
165
330
|
s(`.main-btn-account`).style.display = 'none';
|
|
166
331
|
setTimeout(() => {
|
|
332
|
+
// Close any open logout/account modals
|
|
167
333
|
if (s(`.modal-log-out`)) s(`.btn-close-modal-log-out`).click();
|
|
168
334
|
if (s(`.modal-account`)) s(`.btn-close-modal-account`).click();
|
|
169
335
|
});
|
|
170
|
-
}
|
|
171
|
-
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// Export a singleton instance of the Auth class to maintain the original utility object access pattern.
|
|
340
|
+
const AuthSingleton = new Auth();
|
|
172
341
|
|
|
173
|
-
export { Auth };
|
|
342
|
+
export { AuthSingleton as Auth };
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getId, s4 } from './CommonJs.js';
|
|
2
2
|
import { renderCssAttr } from './Css.js';
|
|
3
3
|
import { ToolTip } from './ToolTip.js';
|
|
4
|
-
import { getAllChildNodes, s } from './VanillaJs.js';
|
|
4
|
+
import { getAllChildNodes, htmlStrSanitize, s } from './VanillaJs.js';
|
|
5
5
|
|
|
6
6
|
const BtnIcon = {
|
|
7
7
|
Tokens: {},
|
|
@@ -15,9 +15,12 @@ const BtnIcon = {
|
|
|
15
15
|
labelStyle: '',
|
|
16
16
|
tabHref: '',
|
|
17
17
|
tooltipHtml: '',
|
|
18
|
+
useVisibilityHover: false,
|
|
19
|
+
useMenuBtn: false,
|
|
18
20
|
},
|
|
19
21
|
) {
|
|
20
22
|
const tokenId = getId(this.Tokens, 'btn-token-');
|
|
23
|
+
if (options.useMenuBtn) options.class += ' main-menu-btn-selector';
|
|
21
24
|
this.Tokens[tokenId] = { ...options };
|
|
22
25
|
setTimeout(() => {
|
|
23
26
|
if (s(`.a-${tokenId}`)) s(`.a-${tokenId}`).onclick = (e) => e.preventDefault();
|
|
@@ -32,7 +35,7 @@ const BtnIcon = {
|
|
|
32
35
|
: ''}`;
|
|
33
36
|
let render = html`<button
|
|
34
37
|
${options?.class ? `class="${options.class} ${tokenId}"` : ''}
|
|
35
|
-
${options?.type ? `type="${options.type}"` :
|
|
38
|
+
${options?.type ? `type="${options.type}"` : `type="button"`}
|
|
36
39
|
${options?.style ? `style="${options.style}"` : ''}
|
|
37
40
|
${options?.attrs ? `${options.attrs}` : ''}
|
|
38
41
|
>
|
|
@@ -49,11 +52,18 @@ const BtnIcon = {
|
|
|
49
52
|
>`
|
|
50
53
|
: label}
|
|
51
54
|
</div>
|
|
55
|
+
<label class="hide">${htmlStrSanitize(options.label) ? htmlStrSanitize(options.label) : tokenId}</label>
|
|
52
56
|
</button>`;
|
|
53
57
|
if (options.tooltipHtml)
|
|
54
58
|
setTimeout(() => {
|
|
55
59
|
if (s(`.${tokenId}`))
|
|
56
|
-
ToolTip.Render({
|
|
60
|
+
ToolTip.Render({
|
|
61
|
+
container: `.${tokenId}`,
|
|
62
|
+
id: tokenId,
|
|
63
|
+
htmlRender: options.tooltipHtml,
|
|
64
|
+
useVisibilityHover: !!options.useVisibilityHover,
|
|
65
|
+
useMenuBtn: !!options.useMenuBtn,
|
|
66
|
+
});
|
|
57
67
|
});
|
|
58
68
|
return render;
|
|
59
69
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { marked } from 'marked';
|
|
2
2
|
import { FileService } from '../../services/file/file.service.js';
|
|
3
3
|
import { append, getBlobFromUint8ArrayFile, getRawContentFile, htmls, s } from './VanillaJs.js';
|
|
4
|
-
import {
|
|
4
|
+
import { s4 } from './CommonJs.js';
|
|
5
5
|
import { Translate } from './Translate.js';
|
|
6
6
|
import { Modal, renderViewTitle } from './Modal.js';
|
|
7
7
|
import { DocumentService } from '../../services/document/document.service.js';
|
|
@@ -139,6 +139,7 @@ const Content = {
|
|
|
139
139
|
case 'png': {
|
|
140
140
|
const url = Content.urlFactory(options);
|
|
141
141
|
const imgRender = html`<img
|
|
142
|
+
alt="${file.name ? file.name : `file ${s4()}`}"
|
|
142
143
|
class="in ${options.class}"
|
|
143
144
|
${styleFactory(options.style, `${renderChessPattern(50)}`)}
|
|
144
145
|
src="${url}"
|
|
@@ -130,19 +130,20 @@ const CssCommonCore = async () => {
|
|
|
130
130
|
opacity: 0;
|
|
131
131
|
}
|
|
132
132
|
}
|
|
133
|
-
.title-
|
|
133
|
+
.title-main-modal {
|
|
134
134
|
top: 8px;
|
|
135
|
-
font-size: 21px
|
|
136
|
-
position: absolute
|
|
135
|
+
font-size: 21px;
|
|
136
|
+
position: absolute;
|
|
137
137
|
}
|
|
138
|
-
.title-
|
|
139
|
-
font-size: 21px
|
|
138
|
+
.title-main-modal .view-title-icon {
|
|
139
|
+
font-size: 21px;
|
|
140
140
|
}
|
|
141
141
|
.down-arrow-submenu {
|
|
142
|
-
top:
|
|
143
|
-
text-align: right;
|
|
144
|
-
padding-right: 42px;
|
|
142
|
+
top: 0px;
|
|
145
143
|
color: #5f5f5f;
|
|
144
|
+
left: 115px;
|
|
145
|
+
transform-origin: center;
|
|
146
|
+
width: 0px;
|
|
146
147
|
}
|
|
147
148
|
.main-body-btn {
|
|
148
149
|
width: 50px;
|
|
@@ -153,6 +154,9 @@ const CssCommonCore = async () => {
|
|
|
153
154
|
.main-body-btn:hover {
|
|
154
155
|
font-size: 21px;
|
|
155
156
|
}
|
|
157
|
+
.main-menu-btn-selector {
|
|
158
|
+
overflow: hidden;
|
|
159
|
+
}
|
|
156
160
|
</style>
|
|
157
161
|
<style>
|
|
158
162
|
.lds-dual-ring,
|
|
@@ -215,6 +219,20 @@ const CssCommonCore = async () => {
|
|
|
215
219
|
.bar-default-modal {
|
|
216
220
|
overflow: hidden;
|
|
217
221
|
}
|
|
222
|
+
.panel-placeholder-bottom {
|
|
223
|
+
height: 100px;
|
|
224
|
+
color: gray;
|
|
225
|
+
}
|
|
226
|
+
.menu-label-text {
|
|
227
|
+
transition: 0.3s;
|
|
228
|
+
position: relative;
|
|
229
|
+
}
|
|
230
|
+
.menu-btn-icon {
|
|
231
|
+
font-size: 20px;
|
|
232
|
+
width: 40px;
|
|
233
|
+
overflow: hidden;
|
|
234
|
+
text-align: center;
|
|
235
|
+
}
|
|
218
236
|
</style>
|
|
219
237
|
${boxShadow({ selector: '.account-profile-image' })}
|
|
220
238
|
<div class="ag-grid-style"></div>`;
|
|
@@ -325,11 +343,12 @@ const CssCoreDark = {
|
|
|
325
343
|
}
|
|
326
344
|
.main-btn-menu {
|
|
327
345
|
text-align: left;
|
|
346
|
+
transition: none; /* sortable necessary */
|
|
328
347
|
padding: 15px;
|
|
329
|
-
transition: none;
|
|
330
348
|
margin: 0;
|
|
331
349
|
border: 0;
|
|
332
350
|
height: 52px;
|
|
351
|
+
background: #121212;
|
|
333
352
|
}
|
|
334
353
|
.main-btn-menu-active {
|
|
335
354
|
background: #212020;
|
|
@@ -431,10 +450,6 @@ const CssCoreDark = {
|
|
|
431
450
|
margin: 15px 5px 5px;
|
|
432
451
|
text-align: left;
|
|
433
452
|
}
|
|
434
|
-
.menu-btn-icon {
|
|
435
|
-
font-size: 20px;
|
|
436
|
-
margin: 12px;
|
|
437
|
-
}
|
|
438
453
|
.view-title-icon {
|
|
439
454
|
font-size: 35px;
|
|
440
455
|
margin: 20px;
|
|
@@ -531,6 +546,10 @@ const CssCoreDark = {
|
|
|
531
546
|
padding: 5px;
|
|
532
547
|
margin: 5px;
|
|
533
548
|
}
|
|
549
|
+
.submenu-btn {
|
|
550
|
+
background: rgba(255, 255, 255, 0.1);
|
|
551
|
+
border-radius: 0;
|
|
552
|
+
}
|
|
534
553
|
</style>
|
|
535
554
|
${scrollBarDarkRender()} ${borderChar(1, 'black', ['.main-body-btn-container'])}
|
|
536
555
|
`,
|
|
@@ -579,12 +598,7 @@ const CssCoreLight = {
|
|
|
579
598
|
.hover-active {
|
|
580
599
|
background: #bbbbbb;
|
|
581
600
|
}
|
|
582
|
-
|
|
583
|
-
cursor: default;
|
|
584
|
-
font-size: 20px;
|
|
585
|
-
padding: 5px;
|
|
586
|
-
margin: 5px;
|
|
587
|
-
}
|
|
601
|
+
|
|
588
602
|
.box-shadow {
|
|
589
603
|
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
|
590
604
|
}
|
|
@@ -645,11 +659,12 @@ const CssCoreLight = {
|
|
|
645
659
|
}
|
|
646
660
|
.main-btn-menu {
|
|
647
661
|
text-align: left;
|
|
662
|
+
transition: none; /* sortable necessary */
|
|
648
663
|
padding: 15px;
|
|
649
|
-
transition: none;
|
|
650
664
|
margin: 0;
|
|
651
665
|
border: 0;
|
|
652
666
|
height: 52px;
|
|
667
|
+
background: #fff;
|
|
653
668
|
}
|
|
654
669
|
.main-btn-menu-active {
|
|
655
670
|
background: #d8d8d8;
|
|
@@ -727,9 +742,7 @@ const CssCoreLight = {
|
|
|
727
742
|
color: #333;
|
|
728
743
|
background: 0 0;
|
|
729
744
|
}
|
|
730
|
-
|
|
731
|
-
color: #000;
|
|
732
|
-
}
|
|
745
|
+
|
|
733
746
|
input {
|
|
734
747
|
cursor: pointer;
|
|
735
748
|
color: #272727;
|
|
@@ -748,10 +761,6 @@ const CssCoreLight = {
|
|
|
748
761
|
margin: 15px 5px 5px;
|
|
749
762
|
text-align: left;
|
|
750
763
|
}
|
|
751
|
-
.menu-btn-icon {
|
|
752
|
-
font-size: 20px;
|
|
753
|
-
margin: 12px;
|
|
754
|
-
}
|
|
755
764
|
.view-title-icon {
|
|
756
765
|
font-size: 35px;
|
|
757
766
|
margin: 20px;
|
|
@@ -861,6 +870,10 @@ const CssCoreLight = {
|
|
|
861
870
|
padding: 5px;
|
|
862
871
|
margin: 5px;
|
|
863
872
|
}
|
|
873
|
+
.submenu-btn {
|
|
874
|
+
background: rgba(0, 0, 0, 0.1);
|
|
875
|
+
border-radius: 0;
|
|
876
|
+
}
|
|
864
877
|
</style>
|
|
865
878
|
${scrollBarLightRender()} ${borderChar(1, 'white', ['.main-body-btn-container'])}
|
|
866
879
|
`,
|