web-mojo 2.1.266 → 2.1.278

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 (73) hide show
  1. package/dist/admin.cjs.js +1 -1
  2. package/dist/admin.cjs.js.map +1 -1
  3. package/dist/admin.es.js +14 -13
  4. package/dist/admin.es.js.map +1 -1
  5. package/dist/auth.cjs.js +1 -1
  6. package/dist/auth.cjs.js.map +1 -1
  7. package/dist/auth.es.js +3 -4
  8. package/dist/auth.es.js.map +1 -1
  9. package/dist/charts.cjs.js +1 -1
  10. package/dist/charts.es.js +2 -2
  11. package/dist/chunks/{ContextMenu-zFaO5-N4.js → ContextMenu-B5-M-xk4.js} +2 -2
  12. package/dist/chunks/{ContextMenu-zFaO5-N4.js.map → ContextMenu-B5-M-xk4.js.map} +1 -1
  13. package/dist/chunks/{ContextMenu-4ltJ5APp.js → ContextMenu-BGyC31Bb.js} +2 -2
  14. package/dist/chunks/{ContextMenu-4ltJ5APp.js.map → ContextMenu-BGyC31Bb.js.map} +1 -1
  15. package/dist/chunks/{DataView-iOFKWlbv.js → DataView-D5GAnAwy.js} +2 -2
  16. package/dist/chunks/{DataView-iOFKWlbv.js.map → DataView-D5GAnAwy.js.map} +1 -1
  17. package/dist/chunks/{DataView-Cejy1Cr8.js → DataView-b_MvCVHp.js} +2 -2
  18. package/dist/chunks/{DataView-Cejy1Cr8.js.map → DataView-b_MvCVHp.js.map} +1 -1
  19. package/dist/chunks/{Dialog-BJ18jw7T.js → Dialog-Cb3hStew.js} +2 -2
  20. package/dist/chunks/{Dialog-BJ18jw7T.js.map → Dialog-Cb3hStew.js.map} +1 -1
  21. package/dist/chunks/{Dialog-DTP5nS69.js → Dialog-DL2qXPTj.js} +5 -5
  22. package/dist/chunks/{Dialog-DTP5nS69.js.map → Dialog-DL2qXPTj.js.map} +1 -1
  23. package/dist/chunks/{FilePreviewView-DUa8Q8kR.js → FilePreviewView-BrrJorTn.js} +6 -6
  24. package/dist/chunks/{FilePreviewView-DUa8Q8kR.js.map → FilePreviewView-BrrJorTn.js.map} +1 -1
  25. package/dist/chunks/{FilePreviewView-B_9CFtFI.js → FilePreviewView-DfSMNOwF.js} +2 -2
  26. package/dist/chunks/{FilePreviewView-B_9CFtFI.js.map → FilePreviewView-DfSMNOwF.js.map} +1 -1
  27. package/dist/chunks/{FormView-J-1RnLu0.js → FormView-BCnSXvaY.js} +192 -3
  28. package/dist/chunks/FormView-BCnSXvaY.js.map +1 -0
  29. package/dist/chunks/FormView-FTVjKzXh.js +2 -0
  30. package/dist/chunks/FormView-FTVjKzXh.js.map +1 -0
  31. package/dist/chunks/{MetricsChart-igTZsC5W.js → MetricsChart-B0YqU0CD.js} +4 -4
  32. package/dist/chunks/{MetricsChart-igTZsC5W.js.map → MetricsChart-B0YqU0CD.js.map} +1 -1
  33. package/dist/chunks/{MetricsChart-BCYtvXip.js → MetricsChart-DFNBNWw7.js} +2 -2
  34. package/dist/chunks/{MetricsChart-BCYtvXip.js.map → MetricsChart-DFNBNWw7.js.map} +1 -1
  35. package/dist/chunks/{PDFViewer-BPS5xKz0.js → PDFViewer-B9OppITV.js} +3 -3
  36. package/dist/chunks/{PDFViewer-BPS5xKz0.js.map → PDFViewer-B9OppITV.js.map} +1 -1
  37. package/dist/chunks/{PDFViewer-B0h2W3v3.js → PDFViewer-uSCAzgto.js} +2 -2
  38. package/dist/chunks/{PDFViewer-B0h2W3v3.js.map → PDFViewer-uSCAzgto.js.map} +1 -1
  39. package/dist/chunks/{Page-CL6mad8S.js → Page-BnWHjjZe.js} +2 -2
  40. package/dist/chunks/{Page-CL6mad8S.js.map → Page-BnWHjjZe.js.map} +1 -1
  41. package/dist/chunks/{Page-BfSiGr0L.js → Page-lvFkx9ma.js} +2 -2
  42. package/dist/chunks/{Page-BfSiGr0L.js.map → Page-lvFkx9ma.js.map} +1 -1
  43. package/dist/chunks/{TopNav-LneaWujS.js → TopNav-8K9q8FgL.js} +2 -2
  44. package/dist/chunks/{TopNav-LneaWujS.js.map → TopNav-8K9q8FgL.js.map} +1 -1
  45. package/dist/chunks/{TopNav-Y9xm0v2v.js → TopNav-C86aDfet.js} +2 -2
  46. package/dist/chunks/{TopNav-Y9xm0v2v.js.map → TopNav-C86aDfet.js.map} +1 -1
  47. package/dist/chunks/{User-BgVd3vvo.js → User-DIhA4ryO.js} +2 -2
  48. package/dist/chunks/{User-BgVd3vvo.js.map → User-DIhA4ryO.js.map} +1 -1
  49. package/dist/chunks/{User-CifH24ZI.js → User-DbeMvd6x.js} +2 -2
  50. package/dist/chunks/{User-CifH24ZI.js.map → User-DbeMvd6x.js.map} +1 -1
  51. package/dist/chunks/{WebApp-BTURAtHS.js → WebApp-BIxs8_cJ.js} +2 -2
  52. package/dist/chunks/{WebApp-BTURAtHS.js.map → WebApp-BIxs8_cJ.js.map} +1 -1
  53. package/dist/chunks/{WebApp-Ri8Knc5O.js → WebApp-_cIASgB0.js} +14 -14
  54. package/dist/chunks/{WebApp-Ri8Knc5O.js.map → WebApp-_cIASgB0.js.map} +1 -1
  55. package/dist/chunks/{WebSocketClient-Dvl3AYx1.js → WebSocketClient-B6ribe3B.js} +145 -6
  56. package/dist/chunks/WebSocketClient-B6ribe3B.js.map +1 -0
  57. package/dist/chunks/WebSocketClient-Dbz1XNJA.js +2 -0
  58. package/dist/chunks/WebSocketClient-Dbz1XNJA.js.map +1 -0
  59. package/dist/docit.cjs.js +1 -1
  60. package/dist/docit.es.js +6 -6
  61. package/dist/index.cjs.js +1 -1
  62. package/dist/index.cjs.js.map +1 -1
  63. package/dist/index.es.js +83 -15
  64. package/dist/index.es.js.map +1 -1
  65. package/dist/lightbox.cjs.js +1 -1
  66. package/dist/lightbox.es.js +4 -4
  67. package/package.json +1 -1
  68. package/dist/chunks/FormView-CG2dIaZ6.js +0 -2
  69. package/dist/chunks/FormView-CG2dIaZ6.js.map +0 -1
  70. package/dist/chunks/FormView-J-1RnLu0.js.map +0 -1
  71. package/dist/chunks/WebSocketClient-D6i85jl2.js +0 -2
  72. package/dist/chunks/WebSocketClient-D6i85jl2.js.map +0 -1
  73. package/dist/chunks/WebSocketClient-Dvl3AYx1.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { M as Mustache, h as MOJOUtils, V as View } from "./WebApp-Ri8Knc5O.js";
1
+ import { M as Mustache, h as MOJOUtils, V as View } from "./WebApp-_cIASgB0.js";
2
2
  class FormBuilder {
3
3
  constructor(config = {}) {
4
4
  this.fields = config.fields || [];
@@ -58,6 +58,48 @@ class FormBuilder {
58
58
  {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}
59
59
  </div>
60
60
  `,
61
+ password: `
62
+ <div class="mojo-form-control">
63
+ {{#label}}
64
+ <label for="{{fieldId}}" class="{{labelClass}}">
65
+ {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}
66
+ </label>
67
+ {{/label}}
68
+ <div class="input-group">
69
+ <input type="password" id="{{fieldId}}" name="{{name}}"
70
+ class="{{inputClass}}{{#error}} is-invalid{{/error}}"
71
+ value="{{fieldValue}}" {{#placeholder}}placeholder="{{placeholder}}"{{/placeholder}}
72
+ {{#required}}required{{/required}} {{#disabled}}disabled{{/disabled}}
73
+ {{#readonly}}readonly{{/readonly}} data-change-action="validate-field"
74
+ data-field-type="password" {{{attrs}}}>
75
+ {{#showToggle}}
76
+ <button type="button" class="btn btn-outline-secondary"
77
+ data-action="toggle-password"
78
+ data-target="{{fieldId}}"
79
+ aria-label="Show password" aria-pressed="false">
80
+ <i class="bi bi-eye"></i>
81
+ </button>
82
+ {{/showToggle}}
83
+ </div>
84
+ {{#strengthMeter}}
85
+ <div class="mt-2">
86
+ <div class="progress" style="height: 4px;">
87
+ <div class="progress-bar bg-secondary" role="progressbar"
88
+ style="width: 0%;" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100"
89
+ id="{{fieldId}}_strength_bar"></div>
90
+ </div>
91
+ <small class="{{helpClass}}" id="{{fieldId}}_strength_text">Strength</small>
92
+ </div>
93
+ {{/strengthMeter}}
94
+ {{#capsLockWarning}}
95
+ <div class="{{helpClass}} text-warning d-none" id="{{fieldId}}_caps_warning">
96
+ Caps Lock is on
97
+ </div>
98
+ {{/capsLockWarning}}
99
+ {{#help}}<div class="{{helpClass}}">{{help}}</div>{{/help}}
100
+ {{#error}}<div class="{{errorClass}}">{{error}}</div>{{/error}}
101
+ </div>
102
+ `,
61
103
  textarea: `
62
104
  <div class="mojo-form-control">
63
105
  {{#label}}
@@ -589,7 +631,21 @@ class FormBuilder {
589
631
  * @returns {string} Field HTML
590
632
  */
591
633
  renderPasswordField(field) {
592
- return this.renderInputField(field, "password");
634
+ const passwordUsage = field.passwordUsage || "current";
635
+ const inferredAutocomplete = passwordUsage === "new" || passwordUsage === "new-password" ? "new-password" : "current-password";
636
+ const attributes = {
637
+ ...field.attributes || {},
638
+ autocomplete: field.attributes && field.attributes.autocomplete || inferredAutocomplete
639
+ };
640
+ return this.renderInputField(
641
+ {
642
+ ...field,
643
+ showToggle: field.showToggle !== false,
644
+ // default to showing the toggle unless explicitly disabled
645
+ attributes
646
+ },
647
+ "password"
648
+ );
593
649
  }
594
650
  /**
595
651
  * Render number input field
@@ -751,6 +807,24 @@ class FormBuilder {
751
807
  readonly,
752
808
  attrs
753
809
  };
810
+ if (type === "password" && (field.showToggle || field.strengthMeter || field.capsLockWarning)) {
811
+ const enhancedContext = {
812
+ ...context,
813
+ showToggle: !!field.showToggle,
814
+ strengthMeter: !!field.strengthMeter,
815
+ capsLockWarning: !!field.capsLockWarning
816
+ };
817
+ return Mustache.render(this.templates.password, enhancedContext);
818
+ }
819
+ if (type === "password") {
820
+ const enhancedContext = {
821
+ ...context,
822
+ showToggle: field.showToggle !== false,
823
+ strengthMeter: !!field.strengthMeter,
824
+ capsLockWarning: !!field.capsLockWarning
825
+ };
826
+ return Mustache.render(this.templates.password, enhancedContext);
827
+ }
754
828
  return Mustache.render(this.templates.input, context);
755
829
  }
756
830
  /**
@@ -4090,6 +4164,7 @@ class FormView extends View {
4090
4164
  await super.onAfterRender();
4091
4165
  this.initializeImageFields();
4092
4166
  this.initializeCustomComponents();
4167
+ this.initializePasswordFields();
4093
4168
  }
4094
4169
  /**
4095
4170
  * Initialize image fields with FileDropMixin
@@ -5210,6 +5285,120 @@ class FormView extends View {
5210
5285
  });
5211
5286
  await super.onBeforeDestroy();
5212
5287
  }
5288
+ /**
5289
+ * Initialize password fields: strength meter, caps lock warning, and hold-to-reveal
5290
+ */
5291
+ initializePasswordFields() {
5292
+ if (!this.element) return;
5293
+ const inputs = this.element.querySelectorAll('input[data-field-type="password"], input[type="password"]');
5294
+ inputs.forEach((input) => {
5295
+ this.updatePasswordStrengthUI(input);
5296
+ const onInput = (e) => {
5297
+ this.updatePasswordStrengthUI(e.target);
5298
+ };
5299
+ input.addEventListener("input", onInput);
5300
+ const capsHandler = (e) => {
5301
+ if (typeof e.getModifierState === "function") {
5302
+ const caps = e.getModifierState("CapsLock");
5303
+ this.updateCapsLockWarning(input, !!caps);
5304
+ }
5305
+ };
5306
+ input.addEventListener("keydown", capsHandler);
5307
+ input.addEventListener("keyup", capsHandler);
5308
+ this.updateCapsLockWarning(input, false);
5309
+ });
5310
+ }
5311
+ /**
5312
+ * Toggle password visibility on click (persistent toggle)
5313
+ * Ignored if currently in press-and-hold mode.
5314
+ */
5315
+ async onActionTogglePassword(event, element) {
5316
+ event.preventDefault();
5317
+ const targetId = element.getAttribute("data-target");
5318
+ let input = null;
5319
+ if (targetId) {
5320
+ input = this.element.querySelector("#" + targetId);
5321
+ }
5322
+ if (!input) {
5323
+ const group = element.closest(".input-group");
5324
+ if (group) {
5325
+ input = group.querySelector('input[type="password"], input[data-field-type="password"], input[type="text"]');
5326
+ }
5327
+ }
5328
+ if (!input) return;
5329
+ const isHidden = input.type === "password";
5330
+ input.type = isHidden ? "text" : "password";
5331
+ element.setAttribute("aria-pressed", isHidden ? "true" : "false");
5332
+ element.setAttribute("aria-label", isHidden ? "Hide password" : "Show password");
5333
+ const icon = element.querySelector("i");
5334
+ if (icon) {
5335
+ icon.classList.toggle("bi-eye", !isHidden);
5336
+ icon.classList.toggle("bi-eye-slash", isHidden);
5337
+ }
5338
+ input.focus();
5339
+ try {
5340
+ const len = input.value?.length ?? 0;
5341
+ input.setSelectionRange(len, len);
5342
+ } catch (_e) {
5343
+ }
5344
+ }
5345
+ /**
5346
+ * Compute a simple password strength score and associated UI metadata
5347
+ */
5348
+ computePasswordStrength(password = "") {
5349
+ const len = password.length;
5350
+ let score = 0;
5351
+ if (len >= 6) score++;
5352
+ if (len >= 8) score++;
5353
+ if (len >= 12) score++;
5354
+ const hasLower = /[a-z]/.test(password);
5355
+ const hasUpper = /[A-Z]/.test(password);
5356
+ const hasDigit = /\d/.test(password);
5357
+ const hasSymbol = /[^A-Za-z0-9]/.test(password);
5358
+ const variety = [hasLower, hasUpper, hasDigit, hasSymbol].filter(Boolean).length;
5359
+ if (variety >= 2) score++;
5360
+ if (variety >= 3) score++;
5361
+ score = Math.max(0, Math.min(4, score));
5362
+ const map = [
5363
+ { percent: 0, label: "Too short", barClass: "bg-secondary" },
5364
+ { percent: 25, label: "Weak", barClass: "bg-danger" },
5365
+ { percent: 50, label: "Fair", barClass: "bg-warning" },
5366
+ { percent: 75, label: "Good", barClass: "bg-info" },
5367
+ { percent: 100, label: "Strong", barClass: "bg-success" }
5368
+ ];
5369
+ return map[score];
5370
+ }
5371
+ /**
5372
+ * Update strength meter UI if present for a given password input
5373
+ */
5374
+ updatePasswordStrengthUI(input) {
5375
+ if (!input || !input.id) return;
5376
+ const bar = this.element.querySelector(`#${input.id}_strength_bar`);
5377
+ const text = this.element.querySelector(`#${input.id}_strength_text`);
5378
+ if (!bar && !text) return;
5379
+ const { percent, label, barClass } = this.computePasswordStrength(input.value || "");
5380
+ if (bar) {
5381
+ bar.className = `progress-bar ${barClass}`;
5382
+ bar.style.width = `${percent}%`;
5383
+ bar.setAttribute("aria-valuenow", String(percent));
5384
+ }
5385
+ if (text) {
5386
+ text.textContent = label;
5387
+ }
5388
+ }
5389
+ /**
5390
+ * Show/Hide a caps lock warning element if present for the given input
5391
+ */
5392
+ updateCapsLockWarning(input, capsOn) {
5393
+ if (!input || !input.id) return;
5394
+ const warn = this.element.querySelector(`#${input.id}_caps_warning`);
5395
+ if (!warn) return;
5396
+ if (capsOn) {
5397
+ warn.classList.remove("d-none");
5398
+ } else {
5399
+ warn.classList.add("d-none");
5400
+ }
5401
+ }
5213
5402
  }
5214
5403
  const FormView$1 = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
5215
5404
  __proto__: null,
@@ -5221,4 +5410,4 @@ export {
5221
5410
  applyFileDropMixin as a,
5222
5411
  FormView$1 as b
5223
5412
  };
5224
- //# sourceMappingURL=FormView-J-1RnLu0.js.map
5413
+ //# sourceMappingURL=FormView-BCnSXvaY.js.map