ultimate-jekyll-manager 0.0.118 → 0.0.120

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.
Files changed (51) hide show
  1. package/CLAUDE.md +409 -23
  2. package/README.md +171 -2
  3. package/TODO.md +10 -2
  4. package/_backup/form-manager.backup.js +1020 -0
  5. package/dist/assets/js/core/auth.js +5 -4
  6. package/dist/assets/js/core/cookieconsent.js +24 -17
  7. package/dist/assets/js/core/exit-popup.js +15 -12
  8. package/dist/assets/js/core/social-sharing.js +8 -4
  9. package/dist/assets/js/libs/auth/pages.js +78 -149
  10. package/dist/assets/js/libs/dev.js +192 -129
  11. package/dist/assets/js/libs/form-manager.js +643 -775
  12. package/dist/assets/js/pages/account/index.js +3 -2
  13. package/dist/assets/js/pages/account/sections/api-keys.js +37 -52
  14. package/dist/assets/js/pages/account/sections/connections.js +37 -46
  15. package/dist/assets/js/pages/account/sections/delete.js +57 -78
  16. package/dist/assets/js/pages/account/sections/profile.js +37 -56
  17. package/dist/assets/js/pages/account/sections/security.js +102 -125
  18. package/dist/assets/js/pages/admin/notifications/new/index.js +73 -151
  19. package/dist/assets/js/pages/blog/index.js +33 -53
  20. package/dist/assets/js/pages/contact/index.js +112 -173
  21. package/dist/assets/js/pages/download/index.js +39 -86
  22. package/dist/assets/js/pages/oauth2/index.js +17 -17
  23. package/dist/assets/js/pages/payment/checkout/index.js +23 -36
  24. package/dist/assets/js/pages/pricing/index.js +5 -2
  25. package/dist/assets/js/pages/test/libraries/form-manager/index.js +194 -0
  26. package/dist/assets/themes/classy/css/components/_cards.scss +2 -2
  27. package/dist/defaults/_.env +6 -0
  28. package/dist/defaults/_.gitignore +7 -1
  29. package/dist/defaults/dist/_includes/core/body.html +5 -13
  30. package/dist/defaults/dist/_includes/core/foot.html +1 -0
  31. package/dist/defaults/dist/_includes/themes/classy/frontend/sections/nav.html +51 -36
  32. package/dist/defaults/dist/_layouts/blueprint/admin/notifications/new.html +13 -2
  33. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/about.html +84 -42
  34. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/account/index.html +26 -21
  35. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signin.html +2 -2
  36. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/auth/signup.html +2 -2
  37. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/index.html +72 -58
  38. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/blog/post.html +46 -29
  39. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/contact.html +46 -53
  40. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/download.html +111 -73
  41. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/index.html +111 -56
  42. package/dist/defaults/dist/_layouts/themes/classy/frontend/pages/pricing.html +127 -81
  43. package/dist/defaults/dist/pages/test/libraries/form-manager.html +181 -0
  44. package/dist/defaults/dist/pages/test/libraries/lazy-loading.html +1 -1
  45. package/dist/gulp/tasks/defaults.js +210 -1
  46. package/dist/gulp/tasks/serve.js +18 -0
  47. package/dist/lib/logger.js +1 -1
  48. package/firebase-debug.log +770 -0
  49. package/package.json +6 -6
  50. package/.playwright-mcp/page-2025-10-22T19-11-27-666Z.png +0 -0
  51. package/.playwright-mcp/page-2025-10-22T19-11-57-357Z.png +0 -0
@@ -1,4 +1,8 @@
1
- // Security section module
1
+ /**
2
+ * Security Section JavaScript
3
+ */
4
+
5
+ // Libraries
2
6
  import authorizedFetch from '__main_assets__/js/libs/authorized-fetch.js';
3
7
  import { FormManager } from '__main_assets__/js/libs/form-manager.js';
4
8
  import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js';
@@ -6,7 +10,11 @@ import { getPrerenderedIcon } from '__main_assets__/js/libs/prerendered-icons.js
6
10
  let webManager = null;
7
11
  let firebaseAuth = null;
8
12
  let signinMethodForms = new Map(); // Store FormManager instances for signin methods
9
- let signoutAllForm = null; // FormManager instance for sign out all sessions
13
+ let signoutAllFormManager = null; // FormManager instance for sign out all sessions
14
+
15
+ // Check query string for popup parameter
16
+ const url = new URL(window.location.href);
17
+ const useAuthPopup = url.searchParams.get('authPopup') === 'true' || window !== window.top;
10
18
 
11
19
  // Initialize security section
12
20
  export function init(wm) {
@@ -17,7 +25,9 @@ export function init(wm) {
17
25
 
18
26
  // Load security data
19
27
  export function loadData(account) {
20
- if (!account) return;
28
+ if (!account) {
29
+ return;
30
+ }
21
31
 
22
32
  console.log('[DEBUG] security.js - loadData() called with account:', account);
23
33
 
@@ -106,7 +116,7 @@ async function updateSigninMethods() {
106
116
  $googleEmail: !!$googleEmail,
107
117
  $googleForm: !!$googleForm,
108
118
  $connectButton: !!$connectButton,
109
- $disconnectButton: !!$disconnectButton
119
+ $disconnectButton: !!$disconnectButton,
110
120
  });
111
121
 
112
122
  if ($googleEmail && $connectButton && $disconnectButton) {
@@ -161,7 +171,9 @@ function update2FAStatus(twoFactorData) {
161
171
  // Update active sessions
162
172
  async function updateActiveSessions(account) {
163
173
  const $sessionsList = document.getElementById('active-sessions-list');
164
- if (!$sessionsList) return;
174
+ if (!$sessionsList) {
175
+ return;
176
+ }
165
177
 
166
178
  const sessions = [];
167
179
 
@@ -179,7 +191,7 @@ async function updateActiveSessions(account) {
179
191
  region: account.activity.geolocation?.region,
180
192
  country: account.activity.geolocation?.country,
181
193
  timestamp: account.activity.created?.timestamp,
182
- timestampUNIX: account.activity.created?.timestampUNIX
194
+ timestampUNIX: account.activity.created?.timestampUNIX,
183
195
  };
184
196
  sessions.push(currentSession);
185
197
  }
@@ -195,9 +207,7 @@ async function updateActiveSessions(account) {
195
207
  tries: 2,
196
208
  body: {
197
209
  command: 'user:get-active-sessions',
198
- payload: {
199
- // id: 'app',
200
- },
210
+ payload: {},
201
211
  },
202
212
  });
203
213
 
@@ -240,7 +250,6 @@ async function updateActiveSessions(account) {
240
250
  sessions.push(sessionObj);
241
251
  });
242
252
  }
243
-
244
253
  } catch (error) {
245
254
  console.error('Failed to get active sessions:', error);
246
255
  }
@@ -259,7 +268,7 @@ async function updateActiveSessions(account) {
259
268
  region: account.lastActivity.geolocation?.region,
260
269
  country: account.lastActivity.geolocation?.country,
261
270
  timestamp: account.lastActivity.timestamp,
262
- timestampUNIX: account.lastActivity.timestampUNIX
271
+ timestampUNIX: account.lastActivity.timestampUNIX,
263
272
  };
264
273
 
265
274
  // Only add if it's different from current session (different IP or timestamp)
@@ -319,21 +328,16 @@ function initializeSigninMethodForms() {
319
328
  console.log('[DEBUG] security.js - Initializing password FormManager');
320
329
 
321
330
  const formManager = new FormManager($passwordForm, {
322
- allowMultipleSubmissions: false,
323
- autoDisable: true,
324
- showSpinner: true,
325
- submitButtonSuccessText: 'Email Sent'
331
+ allowResubmit: false,
332
+ submittingText: 'Sending...',
333
+ submittedText: 'Email Sent!',
326
334
  });
327
335
 
328
336
  signinMethodForms.set('password', formManager);
329
337
 
330
- formManager.addEventListener('submit', async () => {
331
- try {
332
- await handleChangePassword();
333
- } catch (error) {
334
- formManager.showError(error);
335
- formManager.setFormState('ready');
336
- }
338
+ formManager.on('submit', async () => {
339
+ await handleChangePassword();
340
+ formManager.showSuccess('Password reset email sent!');
337
341
  });
338
342
  }
339
343
 
@@ -345,44 +349,24 @@ function initializeSigninMethodForms() {
345
349
  console.log('[DEBUG] security.js - Google form exists:', !!$googleForm);
346
350
 
347
351
  const formManager = new FormManager($googleForm, {
348
- autoDisable: true,
349
- showSpinner: true
352
+ submittingText: 'Connecting...',
350
353
  });
351
354
 
352
355
  signinMethodForms.set('google', formManager);
353
356
  console.log('[DEBUG] security.js - Google FormManager initialized and stored');
354
357
 
355
- formManager.addEventListener('submit', async (event) => {
356
- event.preventDefault();
357
- const { submitButton } = event.detail;
358
-
358
+ formManager.on('submit', async ({ $submitButton }) => {
359
359
  // Determine action from the clicked button's data-action attribute
360
- const action = submitButton?.getAttribute('data-action');
361
-
362
- try {
363
- if (action === 'disconnect') {
364
- await disconnectGoogleProvider();
365
- } else if (action === 'connect') {
366
- await connectGoogleProvider();
367
- }
360
+ const action = $submitButton?.getAttribute('data-action');
368
361
 
369
- // Set form state back to ready first
370
- formManager.setFormState('ready');
371
-
372
- // Then update display (this will set the button text correctly again)
373
- updateSigninMethods();
374
- } catch (error) {
375
- // Reset form state
376
- formManager.setFormState('ready');
377
-
378
- // If user cancelled, also update the display to ensure button state is correct
379
- if (error.message === 'Disconnection cancelled') {
380
- updateSigninMethods();
381
- } else {
382
- // Show error for other failures
383
- formManager.showError(error);
384
- }
362
+ if (action === 'disconnect') {
363
+ await disconnectGoogleProvider();
364
+ } else if (action === 'connect') {
365
+ await connectGoogleProvider();
385
366
  }
367
+
368
+ // Update display after success
369
+ updateSigninMethods();
386
370
  });
387
371
  }
388
372
 
@@ -397,41 +381,31 @@ function initializeSigninMethodForms() {
397
381
  function initializeSignoutAllForm() {
398
382
  const $form = document.getElementById('signout-all-sessions-form');
399
383
 
400
- if ($form && !signoutAllForm) {
401
- signoutAllForm = new FormManager($form, {
402
- autoDisable: true,
403
- showSpinner: true
384
+ if ($form && !signoutAllFormManager) {
385
+ signoutAllFormManager = new FormManager($form, {
386
+ submittingText: 'Signing out...',
404
387
  });
405
388
 
406
- signoutAllForm.addEventListener('submit', async (event) => {
407
- event.preventDefault();
389
+ signoutAllFormManager.on('submit', async () => {
390
+ // 1ms wait to allow form state to update and show processing
391
+ await new Promise(resolve => setTimeout(resolve, 1));
408
392
 
409
- try {
410
- // Confirm sign out
411
- if (!confirm('Are you sure you want to sign out of all sessions? This will log you out everywhere, including this device.')) {
412
- throw new Error('Sign out cancelled');
413
- }
393
+ // Confirm sign out
394
+ if (!confirm('Are you sure you want to sign out of all sessions? This will log you out everywhere, including this device.')) {
395
+ throw new Error('Sign out cancelled.');
396
+ }
414
397
 
415
- // Sign out of all sessions
416
- await webManager.auth().signOut();
398
+ // Sign out of all sessions
399
+ await webManager.auth().signOut();
417
400
 
418
- // Show success message
419
- webManager.utilities().showNotification('Successfully signed out of all sessions.', 'success');
401
+ // Show success message
402
+ signoutAllFormManager.showSuccess('Successfully signed out of all sessions.');
420
403
 
421
- // Note: The page will likely redirect due to auth state change
422
- // so we might not need to reset form state
423
- } catch (error) {
424
- if (error.message !== 'Sign out cancelled') {
425
- signoutAllForm.showError(error);
426
- }
427
- signoutAllForm.setFormState('ready');
428
- }
404
+ // Note: The page will likely redirect due to auth state change
429
405
  });
430
406
  }
431
407
  }
432
408
 
433
-
434
-
435
409
  // Connect Google provider
436
410
  async function connectGoogleProvider() {
437
411
  // Dynamic import of Firebase auth methods
@@ -439,35 +413,38 @@ async function connectGoogleProvider() {
439
413
 
440
414
  const provider = new GoogleAuthProvider();
441
415
 
442
- try {
443
- // Try popup first for better UX
444
- const result = await linkWithPopup(firebaseAuth.currentUser, provider);
445
- webManager.utilities().showNotification('Google account connected successfully', 'success');
416
+ // Use popup if query parameter is set, otherwise use redirect
417
+ if (useAuthPopup) {
418
+ try {
419
+ const result = await linkWithPopup(firebaseAuth.currentUser, provider);
420
+ webManager.utilities().showNotification('Google account connected successfully', 'success');
446
421
 
447
- // Force refresh of the current user to get updated provider data
448
- await firebaseAuth.currentUser.reload();
422
+ // Force refresh of the current user to get updated provider data
423
+ await firebaseAuth.currentUser.reload();
449
424
 
450
- return result;
451
- } catch (error) {
452
- // Check if we should fallback to redirect
453
- if (error.code === 'auth/popup-blocked'
454
- || error.code === 'auth/popup-closed-by-user'
455
- || error.code === 'auth/cancelled-popup-request') {
425
+ return result;
426
+ } catch (error) {
427
+ // Check if we should fallback to redirect
428
+ if (error.code === 'auth/popup-blocked'
429
+ || error.code === 'auth/popup-closed-by-user'
430
+ || error.code === 'auth/cancelled-popup-request') {
456
431
 
457
- console.log('Popup failed, falling back to redirect:', error.code);
432
+ console.log('Popup failed, falling back to redirect:', error.code);
458
433
 
459
- // Fallback to redirect
460
- try {
434
+ // Fallback to redirect
461
435
  await linkWithRedirect(firebaseAuth.currentUser, provider);
462
436
  // This will redirect the page, so no immediate result
463
- } catch (redirectError) {
464
- throw redirectError;
437
+ } else if (error.code === 'auth/credential-already-in-use') {
438
+ throw new Error('This Google account is already linked to another user');
439
+ } else {
440
+ throw error;
465
441
  }
466
- } else if (error.code === 'auth/credential-already-in-use') {
467
- throw new Error('This Google account is already linked to another user');
468
- } else {
469
- throw error;
470
442
  }
443
+ } else {
444
+ // Use redirect by default
445
+ console.log('Using redirect for Google account linking');
446
+ await linkWithRedirect(firebaseAuth.currentUser, provider);
447
+ // This will redirect the page, so no immediate result
471
448
  }
472
449
  }
473
450
 
@@ -478,7 +455,7 @@ async function disconnectGoogleProvider() {
478
455
 
479
456
  // Confirm disconnection
480
457
  if (!confirm('Are you sure you want to disconnect your Google account?')) {
481
- throw new Error('Disconnection cancelled');
458
+ throw new Error('Disconnection cancelled.');
482
459
  }
483
460
 
484
461
  // Dynamic import of Firebase auth methods
@@ -505,22 +482,16 @@ async function disconnectGoogleProvider() {
505
482
 
506
483
  // Handle change password
507
484
  async function handleChangePassword() {
508
- try {
509
- const user = webManager.auth().getUser();
510
- if (!user || !user.email) {
511
- throw new Error('Please log in to reset your password.');
512
- }
485
+ const user = webManager.auth().getUser();
486
+ if (!user || !user.email) {
487
+ throw new Error('Please log in to reset your password.');
488
+ }
513
489
 
514
- // Import Firebase auth method
515
- const { sendPasswordResetEmail } = await import('@firebase/auth');
490
+ // Import Firebase auth method
491
+ const { sendPasswordResetEmail } = await import('@firebase/auth');
516
492
 
517
- // Send password reset email
518
- await sendPasswordResetEmail(firebaseAuth, user.email);
519
- webManager.utilities().showNotification('Password reset email sent. Please check your inbox.', 'info');
520
- } catch (error) {
521
- console.error('Failed to send password reset:', error);
522
- throw new Error(error.message || 'Failed to send password reset email. Please try again.');
523
- }
493
+ // Send password reset email
494
+ await sendPasswordResetEmail(firebaseAuth, user.email);
524
495
  }
525
496
 
526
497
  // Handle 2FA button click
@@ -537,10 +508,11 @@ async function handle2FAClick(event) {
537
508
  }
538
509
  }
539
510
 
540
-
541
511
  // Get device from user agent string
542
512
  function getDeviceFromUserAgent(userAgent) {
543
- if (!userAgent) return 'Unknown Device';
513
+ if (!userAgent) {
514
+ return 'Unknown Device';
515
+ }
544
516
 
545
517
  const ua = userAgent.toLowerCase();
546
518
 
@@ -565,7 +537,9 @@ function getDeviceFromUserAgent(userAgent) {
565
537
 
566
538
  // Get browser from user agent string
567
539
  function getBrowserFromUserAgent(userAgent) {
568
- if (!userAgent) return 'Unknown Browser';
540
+ if (!userAgent) {
541
+ return 'Unknown Browser';
542
+ }
569
543
 
570
544
  const ua = userAgent.toLowerCase();
571
545
 
@@ -582,7 +556,9 @@ function getBrowserFromUserAgent(userAgent) {
582
556
 
583
557
  // Get platform name from platform string
584
558
  function getPlatformName(platform) {
585
- if (!platform) return 'Unknown Device';
559
+ if (!platform) {
560
+ return 'Unknown Device';
561
+ }
586
562
 
587
563
  const platformLower = platform.toLowerCase();
588
564
 
@@ -649,7 +625,6 @@ function formatSessionLocation(session) {
649
625
  return parts.length > 0 ? parts.join(', ') : null;
650
626
  }
651
627
 
652
-
653
628
  // Generate fake sessions for development mode
654
629
  function generateFakeSessions() {
655
630
  const now = Date.now();
@@ -662,42 +637,44 @@ function generateFakeSessions() {
662
637
  platform: 'Windows',
663
638
  ip: '98.137.246.8',
664
639
  timestamp: new Date(now - (3 * oneHour)).toISOString(),
665
- timestampUNIX: Math.floor((now - (3 * oneHour)) / 1000)
640
+ timestampUNIX: Math.floor((now - (3 * oneHour)) / 1000),
666
641
  },
667
642
  'session_def456': {
668
643
  _current: false,
669
644
  platform: 'Darwin', // macOS
670
645
  ip: '192.168.1.42',
671
646
  timestamp: new Date(now - (8 * oneHour)).toISOString(),
672
- timestampUNIX: Math.floor((now - (8 * oneHour)) / 1000)
647
+ timestampUNIX: Math.floor((now - (8 * oneHour)) / 1000),
673
648
  },
674
649
  'session_ghi789': {
675
650
  _current: false,
676
651
  platform: 'Linux',
677
652
  ip: '45.62.189.3',
678
653
  timestamp: new Date(now - (oneDay)).toISOString(),
679
- timestampUNIX: Math.floor((now - (oneDay)) / 1000)
654
+ timestampUNIX: Math.floor((now - (oneDay)) / 1000),
680
655
  },
681
656
  'session_jkl012': {
682
657
  _current: false,
683
658
  platform: 'Win32',
684
659
  ip: '203.0.113.45',
685
660
  timestamp: new Date(now - (2 * oneDay)).toISOString(),
686
- timestampUNIX: Math.floor((now - (2 * oneDay)) / 1000)
661
+ timestampUNIX: Math.floor((now - (2 * oneDay)) / 1000),
687
662
  },
688
663
  'session_mno345': {
689
664
  _current: false,
690
665
  platform: 'Mac',
691
666
  ip: '172.217.16.195',
692
667
  timestamp: new Date(now - (5 * oneDay)).toISOString(),
693
- timestampUNIX: Math.floor((now - (5 * oneDay)) / 1000)
694
- }
668
+ timestampUNIX: Math.floor((now - (5 * oneDay)) / 1000),
669
+ },
695
670
  };
696
671
  }
697
672
 
698
673
  // Format date helper
699
674
  function formatDate(timestamp) {
700
- if (!timestamp) return 'Unknown';
675
+ if (!timestamp) {
676
+ return 'Unknown';
677
+ }
701
678
 
702
679
  const date = new Date(timestamp);
703
680
  const now = new Date();