web-mojo 2.1.703 → 2.1.758

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 (62) 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 +38 -10
  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 -3
  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/{ChatView-CzcjZ6QP.js → ChatView-CoCylKpB.js} +6 -6
  12. package/dist/chunks/{ChatView-CzcjZ6QP.js.map → ChatView-CoCylKpB.js.map} +1 -1
  13. package/dist/chunks/{ChatView-B-ALlbsJ.js → ChatView-S4pMSPhI.js} +2 -2
  14. package/dist/chunks/{ChatView-B-ALlbsJ.js.map → ChatView-S4pMSPhI.js.map} +1 -1
  15. package/dist/chunks/{ContextMenu-BLLaTKfb.js → ContextMenu-BKUnE3JT.js} +2 -2
  16. package/dist/chunks/{ContextMenu-BLLaTKfb.js.map → ContextMenu-BKUnE3JT.js.map} +1 -1
  17. package/dist/chunks/{ContextMenu-3XJxQeJC.js → ContextMenu-C5RTltSd.js} +2 -2
  18. package/dist/chunks/{ContextMenu-3XJxQeJC.js.map → ContextMenu-C5RTltSd.js.map} +1 -1
  19. package/dist/chunks/{DataView-aE9jvYh1.js → DataView-D7CYJ31b.js} +2 -2
  20. package/dist/chunks/{DataView-aE9jvYh1.js.map → DataView-D7CYJ31b.js.map} +1 -1
  21. package/dist/chunks/{DataView-NYvpXEiu.js → DataView-idgJVB89.js} +2 -2
  22. package/dist/chunks/{DataView-NYvpXEiu.js.map → DataView-idgJVB89.js.map} +1 -1
  23. package/dist/chunks/{Dialog-BKMpiDdL.js → Dialog-4ra2w2tV.js} +2 -2
  24. package/dist/chunks/{Dialog-BKMpiDdL.js.map → Dialog-4ra2w2tV.js.map} +1 -1
  25. package/dist/chunks/{Dialog-DKYQBU7p.js → Dialog-BPhwGiQx.js} +5 -5
  26. package/dist/chunks/{Dialog-DKYQBU7p.js.map → Dialog-BPhwGiQx.js.map} +1 -1
  27. package/dist/chunks/FormView-C1ljUoea.js +3 -0
  28. package/dist/chunks/FormView-C1ljUoea.js.map +1 -0
  29. package/dist/chunks/{FormView-DV_HKp0B.js → FormView-a7Rl2bmm.js} +379 -2
  30. package/dist/chunks/FormView-a7Rl2bmm.js.map +1 -0
  31. package/dist/chunks/{MetricsMiniChartWidget-k3WKOCxR.js → MetricsMiniChartWidget-hdDNDf7M.js} +3 -3
  32. package/dist/chunks/{MetricsMiniChartWidget-k3WKOCxR.js.map → MetricsMiniChartWidget-hdDNDf7M.js.map} +1 -1
  33. package/dist/chunks/{MetricsMiniChartWidget-lOwyTz8v.js → MetricsMiniChartWidget-m_U_ucCF.js} +2 -2
  34. package/dist/chunks/{MetricsMiniChartWidget-lOwyTz8v.js.map → MetricsMiniChartWidget-m_U_ucCF.js.map} +1 -1
  35. package/dist/chunks/{PDFViewer-89y-uAXH.js → PDFViewer-DwJDeXQH.js} +3 -3
  36. package/dist/chunks/{PDFViewer-89y-uAXH.js.map → PDFViewer-DwJDeXQH.js.map} +1 -1
  37. package/dist/chunks/{PDFViewer-BYcD9j5q.js → PDFViewer-OvkZ_4H3.js} +2 -2
  38. package/dist/chunks/{PDFViewer-BYcD9j5q.js.map → PDFViewer-OvkZ_4H3.js.map} +1 -1
  39. package/dist/chunks/{Page-CqYpkV9V.js → Page-CbWUdARI.js} +2 -2
  40. package/dist/chunks/{Page-CqYpkV9V.js.map → Page-CbWUdARI.js.map} +1 -1
  41. package/dist/chunks/{Page-yJn8PtJJ.js → Page-D7lbK30W.js} +2 -2
  42. package/dist/chunks/{Page-yJn8PtJJ.js.map → Page-D7lbK30W.js.map} +1 -1
  43. package/dist/chunks/{TopNav-CfNvkf5T.js → TopNav-B7o7jhkD.js} +5 -5
  44. package/dist/chunks/{TopNav-CfNvkf5T.js.map → TopNav-B7o7jhkD.js.map} +1 -1
  45. package/dist/chunks/{TopNav-D_J-xBQS.js → TopNav-CKfu-goV.js} +2 -2
  46. package/dist/chunks/{TopNav-D_J-xBQS.js.map → TopNav-CKfu-goV.js.map} +1 -1
  47. package/dist/chunks/{WebApp-BxWFN9k7.js → WebApp-CYCNA3GB.js} +13 -13
  48. package/dist/chunks/{WebApp-BxWFN9k7.js.map → WebApp-CYCNA3GB.js.map} +1 -1
  49. package/dist/chunks/{WebApp-Bjz0wkVk.js → WebApp-Cnkm2125.js} +2 -2
  50. package/dist/chunks/{WebApp-Bjz0wkVk.js.map → WebApp-Cnkm2125.js.map} +1 -1
  51. package/dist/core.css +12 -0
  52. package/dist/css/web-mojo.css +1 -1
  53. package/dist/docit.cjs.js +1 -1
  54. package/dist/docit.es.js +5 -5
  55. package/dist/index.cjs.js +1 -1
  56. package/dist/index.es.js +11 -11
  57. package/dist/lightbox.cjs.js +1 -1
  58. package/dist/lightbox.es.js +4 -4
  59. package/package.json +1 -1
  60. package/dist/chunks/FormView-DVBIrh9Q.js +0 -3
  61. package/dist/chunks/FormView-DVBIrh9Q.js.map +0 -1
  62. package/dist/chunks/FormView-DV_HKp0B.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { M as Mustache, h as MOJOUtils, V as View } from "./WebApp-BxWFN9k7.js";
1
+ import { M as Mustache, h as MOJOUtils, V as View } from "./WebApp-CYCNA3GB.js";
2
2
  class FormBuilder {
3
3
  constructor(config = {}) {
4
4
  this.fields = config.fields || [];
@@ -604,6 +604,10 @@ class FormBuilder {
604
604
  case "collection":
605
605
  fieldHTML = this.renderCollectionField(field);
606
606
  break;
607
+ case "collectionmultiselect":
608
+ case "collection-multiselect":
609
+ fieldHTML = this.renderCollectionMultiSelectField(field);
610
+ break;
607
611
  case "datepicker":
608
612
  fieldHTML = this.renderDatePickerField(field);
609
613
  break;
@@ -1671,6 +1675,59 @@ class FormBuilder {
1671
1675
  </div>
1672
1676
  `;
1673
1677
  }
1678
+ /**
1679
+ * Render collection multiselect field
1680
+ * @param {Object} field - Field configuration
1681
+ * @returns {string} Field HTML
1682
+ */
1683
+ renderCollectionMultiSelectField(field) {
1684
+ const {
1685
+ name,
1686
+ label,
1687
+ value = [],
1688
+ required = false,
1689
+ disabled = false,
1690
+ Collection: _Collection,
1691
+ collectionParams = {},
1692
+ labelField = "name",
1693
+ valueField = "id",
1694
+ excludeIds = [],
1695
+ size = 8,
1696
+ maxHeight = null,
1697
+ showSelectAll = true,
1698
+ requiresActiveGroup = false,
1699
+ help = field.helpText || field.help || ""
1700
+ } = field;
1701
+ this.getFieldId(name);
1702
+ const error = this.errors[name];
1703
+ const fieldValue = this.getFieldValue(name) ?? value;
1704
+ return `
1705
+ <div class="mojo-form-control">
1706
+ ${label ? `<label class="${this.options.labelClass}">${this.escapeHtml(label)}${required ? '<span class="text-danger">*</span>' : ""}</label>` : ""}
1707
+ <div class="collection-multiselect-placeholder"
1708
+ data-field-name="${name}"
1709
+ data-field-type="collectionmultiselect"
1710
+ data-field-config='${JSON.stringify({
1711
+ name,
1712
+ value: fieldValue,
1713
+ labelField,
1714
+ valueField,
1715
+ excludeIds,
1716
+ size,
1717
+ maxHeight,
1718
+ showSelectAll,
1719
+ disabled,
1720
+ required,
1721
+ requiresActiveGroup
1722
+ })}'>
1723
+ <input type="hidden" name="${name}" value="${this.escapeHtml(JSON.stringify(fieldValue))}">
1724
+ <small class="form-text text-muted">This will be enhanced with CollectionMultiSelect component</small>
1725
+ </div>
1726
+ ${help ? `<div class="${this.options.helpClass}">${this.escapeHtml(help)}</div>` : ""}
1727
+ ${error ? `<div class="${this.options.errorClass}">${this.escapeHtml(error)}</div>` : ""}
1728
+ </div>
1729
+ `;
1730
+ }
1674
1731
  /**
1675
1732
  * Render enhanced date picker field
1676
1733
  * @param {Object} field - Field configuration
@@ -3213,6 +3270,286 @@ class CollectionSelectView extends View {
3213
3270
  return MOJOUtils.getNestedValue(item, fieldPath);
3214
3271
  }
3215
3272
  }
3273
+ class CollectionMultiSelectView extends View {
3274
+ constructor(options = {}) {
3275
+ super({
3276
+ tagName: "div",
3277
+ className: "collection-multiselect-view",
3278
+ template: `
3279
+ <div class="mojo-form-control">
3280
+ {{#label}}
3281
+ <label class="form-label">
3282
+ {{label}}{{#required}}<span class="text-danger">*</span>{{/required}}
3283
+ </label>
3284
+ {{/label}}
3285
+
3286
+ {{#loading}}
3287
+ <div class="text-center py-3">
3288
+ <div class="spinner-border spinner-border-sm" role="status">
3289
+ <span class="visually-hidden">Loading...</span>
3290
+ </div>
3291
+ </div>
3292
+ {{/loading}}
3293
+
3294
+ {{^loading}}
3295
+ {{#items.length}}
3296
+ <div class="collection-multiselect-list border rounded p-3" style="max-height: {{maxHeight}}px; overflow-y: auto; background: #fff;">
3297
+ {{#items}}
3298
+ <div class="d-flex align-items-center mb-2 py-1 px-2 rounded {{^disabled}}hover-bg{{/disabled}}"
3299
+ style="cursor: {{^disabled}}pointer{{/disabled}}{{#disabled}}not-allowed{{/disabled}}; user-select: none; transition: background-color 0.15s;"
3300
+ data-action="{{^disabled}}toggle-item{{/disabled}}"
3301
+ data-value="{{value}}"
3302
+ data-index="{{index}}"
3303
+ {{#disabled}}data-disabled="true"{{/disabled}}>
3304
+ <i class="bi {{#isSelected}}bi-check-square-fill text-primary{{/isSelected}}{{^isSelected}}bi-square{{/isSelected}} me-2"
3305
+ style="font-size: 1.25rem;"></i>
3306
+ <span {{#disabled}}class="text-muted"{{/disabled}}>{{label}}</span>
3307
+ </div>
3308
+ {{/items}}
3309
+ </div>
3310
+
3311
+ {{#showSelectAll}}
3312
+ <div class="mt-2">
3313
+ <button type="button" class="btn btn-sm btn-outline-secondary me-2" data-action="select-all">
3314
+ Select All
3315
+ </button>
3316
+ <button type="button" class="btn btn-sm btn-outline-secondary" data-action="deselect-all">
3317
+ Deselect All
3318
+ </button>
3319
+ </div>
3320
+ {{/showSelectAll}}
3321
+ {{/items.length}}
3322
+
3323
+ {{^items.length}}
3324
+ <div class="text-muted text-center py-3 border rounded">
3325
+ No items available
3326
+ </div>
3327
+ {{/^items.length}}
3328
+ {{/loading}}
3329
+
3330
+ {{#help}}
3331
+ <div class="form-text">{{help}}</div>
3332
+ {{/help}}
3333
+ {{#error}}
3334
+ <div class="invalid-feedback d-block">{{error}}</div>
3335
+ {{/error}}
3336
+ </div>
3337
+ `,
3338
+ ...options
3339
+ });
3340
+ this.name = options.name || "collection_multiselect";
3341
+ this.label = options.label || "";
3342
+ this.help = options.help || "";
3343
+ this.error = options.error || "";
3344
+ this.required = options.required || false;
3345
+ this.disabled = options.disabled || false;
3346
+ this.collection = options.collection;
3347
+ this.collectionParams = options.collectionParams || {};
3348
+ this.labelField = options.labelField || "name";
3349
+ this.valueField = options.valueField || "id";
3350
+ this.excludeIds = options.excludeIds || [];
3351
+ this.requiresActiveGroup = options.requiresActiveGroup || false;
3352
+ this.size = options.size || 8;
3353
+ this.maxHeight = options.maxHeight || this.size * 42;
3354
+ this.showSelectAll = options.showSelectAll !== false;
3355
+ this.selectedValues = Array.isArray(options.value) ? options.value : [];
3356
+ this.loading = false;
3357
+ this.items = [];
3358
+ this.lastClickedIndex = -1;
3359
+ this.fieldId = options.fieldId || `field_${this.name}`;
3360
+ }
3361
+ onInit() {
3362
+ if (this.collection) {
3363
+ this.setupCollection();
3364
+ }
3365
+ }
3366
+ setupCollection() {
3367
+ if (!this.collection) {
3368
+ console.warn("CollectionMultiSelect: No collection provided");
3369
+ return;
3370
+ }
3371
+ if (this.collectionParams && Object.keys(this.collectionParams).length > 0) {
3372
+ this.collection.params = { ...this.collection.params, ...this.collectionParams };
3373
+ }
3374
+ if (this.requiresActiveGroup) {
3375
+ const app = this.getApp();
3376
+ if (app && app.activeGroup && app.activeGroup.id) {
3377
+ this.collection.params.group = app.activeGroup.id;
3378
+ }
3379
+ }
3380
+ this.collection.on("fetch:start", () => {
3381
+ this.loading = true;
3382
+ this.render(false);
3383
+ });
3384
+ this.collection.on("fetch:end", () => {
3385
+ this.loading = false;
3386
+ this.updateItems();
3387
+ this.render(false);
3388
+ });
3389
+ if (!this.collection.isEmpty()) {
3390
+ this.updateItems();
3391
+ }
3392
+ }
3393
+ onAfterMount() {
3394
+ if (this.collection && this.collection.isEmpty()) {
3395
+ this.collection.fetch();
3396
+ }
3397
+ }
3398
+ /**
3399
+ * Update items array from collection
3400
+ */
3401
+ updateItems() {
3402
+ const filteredModels = this.collection.models.filter((model) => {
3403
+ const modelId = this.getFieldValue(model, this.valueField);
3404
+ return !this.excludeIds.some((id) => id == modelId);
3405
+ });
3406
+ this.items = filteredModels.map((model, index) => {
3407
+ const labelValue = this.getFieldValue(model, this.labelField);
3408
+ const fieldValue = this.getFieldValue(model, this.valueField);
3409
+ return {
3410
+ label: labelValue,
3411
+ value: fieldValue,
3412
+ index,
3413
+ isSelected: this.selectedValues.some((v) => v == fieldValue),
3414
+ disabled: this.disabled
3415
+ };
3416
+ });
3417
+ }
3418
+ /**
3419
+ * Get field value from model or object, supporting dot notation
3420
+ */
3421
+ getFieldValue(item, fieldPath) {
3422
+ if (!item || !fieldPath) return void 0;
3423
+ if (typeof item.get === "function") {
3424
+ const value = item.get(fieldPath);
3425
+ if (value === void 0 && fieldPath.includes(".")) {
3426
+ return MOJOUtils.getNestedValue(item, fieldPath);
3427
+ }
3428
+ return value;
3429
+ }
3430
+ return MOJOUtils.getNestedValue(item, fieldPath);
3431
+ }
3432
+ /**
3433
+ * Handle item toggle with shift-click range selection support
3434
+ */
3435
+ handleActionToggleItem(event, element) {
3436
+ const value = element.getAttribute("data-value");
3437
+ const clickedIndex = parseInt(element.getAttribute("data-index"), 10);
3438
+ const numValue = Number(value);
3439
+ const typedValue = !isNaN(numValue) && String(numValue) === value ? numValue : value;
3440
+ if (event.shiftKey && this.lastClickedIndex !== -1 && this.lastClickedIndex !== clickedIndex) {
3441
+ const isCurrentlySelected = this.selectedValues.some((v) => v == typedValue);
3442
+ const shouldSelect = !isCurrentlySelected;
3443
+ const start = Math.min(this.lastClickedIndex, clickedIndex);
3444
+ const end = Math.max(this.lastClickedIndex, clickedIndex);
3445
+ for (let i = start; i <= end; i++) {
3446
+ const item = this.items[i];
3447
+ if (item && !item.disabled) {
3448
+ const itemNumValue = Number(item.value);
3449
+ const itemTypedValue = !isNaN(itemNumValue) && String(itemNumValue) === String(item.value) ? itemNumValue : item.value;
3450
+ if (shouldSelect) {
3451
+ if (!this.selectedValues.some((v) => v == itemTypedValue)) {
3452
+ this.selectedValues.push(itemTypedValue);
3453
+ }
3454
+ item.isSelected = true;
3455
+ } else {
3456
+ this.selectedValues = this.selectedValues.filter((v) => v != itemTypedValue);
3457
+ item.isSelected = false;
3458
+ }
3459
+ }
3460
+ }
3461
+ } else {
3462
+ const isCurrentlySelected = this.selectedValues.some((v) => v == typedValue);
3463
+ if (isCurrentlySelected) {
3464
+ this.selectedValues = this.selectedValues.filter((v) => v != typedValue);
3465
+ } else {
3466
+ this.selectedValues.push(typedValue);
3467
+ }
3468
+ const item = this.items.find((i) => i.value == value);
3469
+ if (item) {
3470
+ item.isSelected = !isCurrentlySelected;
3471
+ }
3472
+ }
3473
+ this.lastClickedIndex = clickedIndex;
3474
+ this.render(false);
3475
+ this.emit("change", {
3476
+ value: this.selectedValues,
3477
+ name: this.name
3478
+ });
3479
+ }
3480
+ /**
3481
+ * Select all items
3482
+ */
3483
+ async handleActionSelectAll(event, element) {
3484
+ event.preventDefault();
3485
+ this.selectedValues = this.items.filter((item) => !item.disabled).map((item) => item.value);
3486
+ this.items.forEach((item) => {
3487
+ if (!item.disabled) {
3488
+ item.isSelected = true;
3489
+ }
3490
+ });
3491
+ this.render(false);
3492
+ this.emit("change", {
3493
+ value: this.selectedValues,
3494
+ name: this.name
3495
+ });
3496
+ }
3497
+ /**
3498
+ * Deselect all items
3499
+ */
3500
+ async handleActionDeselectAll(event, element) {
3501
+ event.preventDefault();
3502
+ this.selectedValues = [];
3503
+ this.items.forEach((item) => {
3504
+ item.isSelected = false;
3505
+ });
3506
+ this.render(false);
3507
+ this.emit("change", {
3508
+ value: this.selectedValues,
3509
+ name: this.name
3510
+ });
3511
+ }
3512
+ /**
3513
+ * Get the current selected values
3514
+ */
3515
+ getValue() {
3516
+ return this.selectedValues;
3517
+ }
3518
+ /**
3519
+ * Set the selected values
3520
+ */
3521
+ setValue(values) {
3522
+ this.selectedValues = Array.isArray(values) ? values : [];
3523
+ this.updateItems();
3524
+ this.render();
3525
+ }
3526
+ /**
3527
+ * Set the excluded IDs
3528
+ */
3529
+ setExcludeIds(ids) {
3530
+ this.excludeIds = Array.isArray(ids) ? ids : [];
3531
+ this.updateItems();
3532
+ this.render();
3533
+ }
3534
+ /**
3535
+ * Refresh the collection
3536
+ */
3537
+ async refresh() {
3538
+ await this.collection.fetch();
3539
+ }
3540
+ /**
3541
+ * Get form value for form submission
3542
+ */
3543
+ getFormValue() {
3544
+ return this.selectedValues;
3545
+ }
3546
+ /**
3547
+ * Set form value from form data
3548
+ */
3549
+ setFormValue(value) {
3550
+ this.setValue(value);
3551
+ }
3552
+ }
3216
3553
  class DatePicker extends View {
3217
3554
  constructor(options = {}) {
3218
3555
  const {
@@ -4478,6 +4815,7 @@ class FormView extends View {
4478
4815
  this.initializeCustomComponents();
4479
4816
  this.initializeTagInputs();
4480
4817
  this.initializeCollectionSelects();
4818
+ this.initializeCollectionMultiSelects();
4481
4819
  this.initializeDatePickers();
4482
4820
  this.initializeDateRangePickers();
4483
4821
  this.initializePasswordFields();
@@ -4506,6 +4844,7 @@ class FormView extends View {
4506
4844
  initializeCustomComponents() {
4507
4845
  this.initializeTagInputs();
4508
4846
  this.initializeCollectionSelects();
4847
+ this.initializeCollectionMultiSelects();
4509
4848
  this.initializeDatePickers();
4510
4849
  this.initializeDateRangePickers();
4511
4850
  const componentContainers = this.element.querySelectorAll("[data-component]");
@@ -4622,6 +4961,44 @@ class FormView extends View {
4622
4961
  }
4623
4962
  });
4624
4963
  }
4964
+ /**
4965
+ * Initialize CollectionMultiSelect components
4966
+ */
4967
+ initializeCollectionMultiSelects() {
4968
+ const collectionMultiSelectPlaceholders = this.element.querySelectorAll('[data-field-type="collectionmultiselect"]');
4969
+ collectionMultiSelectPlaceholders.forEach((placeholder) => {
4970
+ try {
4971
+ const fieldName = placeholder.getAttribute("data-field-name");
4972
+ const configData = placeholder.getAttribute("data-field-config");
4973
+ const config = JSON.parse(configData);
4974
+ const fieldConfig = this.getFormFieldConfig(fieldName);
4975
+ if (!fieldConfig || !fieldConfig.Collection) {
4976
+ return;
4977
+ }
4978
+ const collection = new fieldConfig.Collection();
4979
+ if (fieldConfig.collectionParams) {
4980
+ collection.params = { ...collection.params, ...fieldConfig.collectionParams };
4981
+ }
4982
+ const collectionMultiSelect = new CollectionMultiSelectView({
4983
+ ...config,
4984
+ collection,
4985
+ containerId: null
4986
+ // We'll mount directly
4987
+ });
4988
+ let value = MOJOUtils.getContextData(this.data, fieldName);
4989
+ if (value) {
4990
+ collectionMultiSelect.setFormValue(value);
4991
+ }
4992
+ collectionMultiSelect.render(true, placeholder);
4993
+ this.customComponents.set(fieldName, collectionMultiSelect);
4994
+ collectionMultiSelect.on("change", (data) => {
4995
+ this.handleFieldChange(fieldName, data.value);
4996
+ });
4997
+ } catch (error) {
4998
+ console.error("CollectionMultiSelect initialization failed:", error);
4999
+ }
5000
+ });
5001
+ }
4625
5002
  /**
4626
5003
  * Initialize DatePicker components
4627
5004
  */
@@ -6219,4 +6596,4 @@ export {
6219
6596
  applyFileDropMixin as a,
6220
6597
  FormView$1 as b
6221
6598
  };
6222
- //# sourceMappingURL=FormView-DV_HKp0B.js.map
6599
+ //# sourceMappingURL=FormView-a7Rl2bmm.js.map