web-mojo 2.1.979 → 2.1.995

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 (50) 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 -16
  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 +2 -2
  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-C1702ZPZ.js → ChatView-Bk3XGtNh.js} +69 -8
  12. package/dist/chunks/ChatView-Bk3XGtNh.js.map +1 -0
  13. package/dist/chunks/{ChatView-CVZScWPz.js → ChatView-Bz_YZdHd.js} +2 -2
  14. package/dist/chunks/ChatView-Bz_YZdHd.js.map +1 -0
  15. package/dist/chunks/{Dialog-Be1EkdvX.js → Dialog-BiVgKzSK.js} +3 -3
  16. package/dist/chunks/{Dialog-Be1EkdvX.js.map → Dialog-BiVgKzSK.js.map} +1 -1
  17. package/dist/chunks/{Dialog-YnhCC4C2.js → Dialog-DmIPK_Bi.js} +2 -2
  18. package/dist/chunks/{Dialog-YnhCC4C2.js.map → Dialog-DmIPK_Bi.js.map} +1 -1
  19. package/dist/chunks/{FormView-CQbR3S82.js → FormView-BClEkzmE.js} +134 -14
  20. package/dist/chunks/FormView-BClEkzmE.js.map +1 -0
  21. package/dist/chunks/FormView-nulck4nL.js +3 -0
  22. package/dist/chunks/FormView-nulck4nL.js.map +1 -0
  23. package/dist/chunks/{MetricsMiniChartWidget-CHsOuS2O.js → MetricsMiniChartWidget-CCroU6BZ.js} +2 -2
  24. package/dist/chunks/{MetricsMiniChartWidget-CHsOuS2O.js.map → MetricsMiniChartWidget-CCroU6BZ.js.map} +1 -1
  25. package/dist/chunks/{MetricsMiniChartWidget-DMGjpLSU.js → MetricsMiniChartWidget-Esvv-lFp.js} +2 -2
  26. package/dist/chunks/{MetricsMiniChartWidget-DMGjpLSU.js.map → MetricsMiniChartWidget-Esvv-lFp.js.map} +1 -1
  27. package/dist/chunks/{PDFViewer-BlWEqtY5.js → PDFViewer-D4uo3oiA.js} +2 -2
  28. package/dist/chunks/{PDFViewer-BlWEqtY5.js.map → PDFViewer-D4uo3oiA.js.map} +1 -1
  29. package/dist/chunks/{PDFViewer-BN200UnI.js → PDFViewer-NeL91Gon.js} +2 -2
  30. package/dist/chunks/{PDFViewer-BN200UnI.js.map → PDFViewer-NeL91Gon.js.map} +1 -1
  31. package/dist/chunks/{TopNav-DF8w5mgO.js → TopNav-23B5R-dl.js} +2 -2
  32. package/dist/chunks/{TopNav-DF8w5mgO.js.map → TopNav-23B5R-dl.js.map} +1 -1
  33. package/dist/chunks/{TopNav-ueVUoXcv.js → TopNav-CYTDmhAF.js} +2 -2
  34. package/dist/chunks/{TopNav-ueVUoXcv.js.map → TopNav-CYTDmhAF.js.map} +1 -1
  35. package/dist/chunks/{WebApp-m17riaNV.js → WebApp-CQKxglmg.js} +2 -2
  36. package/dist/chunks/{WebApp-m17riaNV.js.map → WebApp-CQKxglmg.js.map} +1 -1
  37. package/dist/chunks/{WebApp-gsWqZg8e.js → WebApp-CWuDQOYo.js} +13 -13
  38. package/dist/chunks/{WebApp-gsWqZg8e.js.map → WebApp-CWuDQOYo.js.map} +1 -1
  39. package/dist/docit.cjs.js +1 -1
  40. package/dist/docit.es.js +3 -3
  41. package/dist/index.cjs.js +1 -1
  42. package/dist/index.es.js +7 -7
  43. package/dist/lightbox.cjs.js +1 -1
  44. package/dist/lightbox.es.js +3 -3
  45. package/package.json +1 -1
  46. package/dist/chunks/ChatView-C1702ZPZ.js.map +0 -1
  47. package/dist/chunks/ChatView-CVZScWPz.js.map +0 -1
  48. package/dist/chunks/FormView-CQbR3S82.js.map +0 -1
  49. package/dist/chunks/FormView-DHz1ydYg.js +0 -3
  50. package/dist/chunks/FormView-DHz1ydYg.js.map +0 -1
@@ -625,6 +625,9 @@ class FormBuilder {
625
625
  case "autocomplete":
626
626
  fieldHTML = this.renderComboField(field);
627
627
  break;
628
+ case "tabset":
629
+ fieldHTML = this.renderTabsetField(field);
630
+ break;
628
631
  default:
629
632
  console.warn(`Unknown field type: ${type}`);
630
633
  fieldHTML = this.renderTextField(field);
@@ -2018,6 +2021,70 @@ class FormBuilder {
2018
2021
  </div>
2019
2022
  `;
2020
2023
  }
2024
+ /**
2025
+ * Render a tabset field consisting of Bootstrap nav tabs and tab panes.
2026
+ * Each pane's fields are rendered using existing field rendering,
2027
+ * wrapped in a row so column layouts work as expected.
2028
+ * @param {Object} field - Tabset configuration
2029
+ * @param {Array} field.tabs - Array of tabs: [{ label, fields }]
2030
+ * @param {string} [field.name] - Optional name used to generate stable IDs
2031
+ * @param {string} [field.navClass] - CSS classes for the tabs nav
2032
+ * @param {string} [field.contentClass] - CSS classes for the tab content container
2033
+ * @returns {string} HTML
2034
+ */
2035
+ renderTabsetField(field) {
2036
+ const {
2037
+ tabs = [],
2038
+ name = `tabset-${Date.now()}`,
2039
+ navClass = "nav nav-tabs mb-3",
2040
+ contentClass = "tab-content"
2041
+ } = field;
2042
+ const safe = String(name).toLowerCase().replace(/[^a-z0-9]/g, "-");
2043
+ const nav = tabs.map((t, i) => {
2044
+ const id = `${safe}-pane-${i}`;
2045
+ const isActive = i === 0;
2046
+ return `
2047
+ <li class="nav-item" role="presentation">
2048
+ <button class="nav-link ${isActive ? "active" : ""}"
2049
+ id="${id}-tab"
2050
+ data-bs-toggle="tab"
2051
+ data-bs-target="#${id}"
2052
+ type="button"
2053
+ role="tab"
2054
+ aria-controls="${id}"
2055
+ aria-selected="${isActive}">
2056
+ ${this.escapeHtml(t.label || `Tab ${i + 1}`)}
2057
+ </button>
2058
+ </li>
2059
+ `;
2060
+ }).join("");
2061
+ const panes = tabs.map((t, i) => {
2062
+ const id = `${safe}-pane-${i}`;
2063
+ const isActive = i === 0;
2064
+ const fieldsHTML = (t.fields || []).map((f) => this.buildFieldHTML(f)).join("");
2065
+ return `
2066
+ <div class="tab-pane fade ${isActive ? "show active" : ""}"
2067
+ id="${id}"
2068
+ role="tabpanel"
2069
+ aria-labelledby="${id}-tab"
2070
+ data-tab-index="${i}">
2071
+ <div class="row">
2072
+ ${fieldsHTML}
2073
+ </div>
2074
+ </div>
2075
+ `;
2076
+ }).join("");
2077
+ return `
2078
+ <div class="mojo-form-tabset">
2079
+ <ul class="${navClass}" role="tablist">
2080
+ ${nav}
2081
+ </ul>
2082
+ <div class="${contentClass}">
2083
+ ${panes}
2084
+ </div>
2085
+ </div>
2086
+ `;
2087
+ }
2021
2088
  /**
2022
2089
  * Generate select options automatically from numeric range or patterns
2023
2090
  * Supports multiple generation modes:
@@ -3383,6 +3450,8 @@ class SearchView extends View {
3383
3450
  }
3384
3451
  class ListItemsView extends View {
3385
3452
  constructor(options = {}) {
3453
+ const hasCustomTemplate = !!options.customItemTemplate;
3454
+ const itemContentTemplate = hasCustomTemplate ? `{{{customContent}}}` : `<span {{#disabled}}class="text-muted"{{/disabled}}>{{label}}</span>`;
3386
3455
  super({
3387
3456
  tagName: "div",
3388
3457
  className: "collection-multiselect-items",
@@ -3425,7 +3494,7 @@ class ListItemsView extends View {
3425
3494
  data-index="{{index}}">
3426
3495
  <i class="bi {{#selected}}bi-check-square-fill text-primary{{/selected}}{{^selected}}bi-square{{/selected}} me-2"
3427
3496
  style="font-size: 1.1rem;"></i>
3428
- <span {{#disabled}}class="text-muted"{{/disabled}}>{{label}}</span>
3497
+ ${itemContentTemplate}
3429
3498
  </div>
3430
3499
  {{/items}}
3431
3500
  </div>
@@ -3450,6 +3519,7 @@ class ListItemsView extends View {
3450
3519
  this.unselectedCount = options.unselectedCount || 0;
3451
3520
  this.allSelected = options.allSelected || false;
3452
3521
  this.noneSelected = options.noneSelected || true;
3522
+ this.customItemTemplate = options.customItemTemplate || null;
3453
3523
  this.lastClickedIndex = -1;
3454
3524
  }
3455
3525
  handleActionToggle(event, element) {
@@ -3507,6 +3577,7 @@ class CollectionMultiSelectView extends View {
3507
3577
  this.valueField = options.valueField || "id";
3508
3578
  this.excludeIds = options.excludeIds || [];
3509
3579
  this.ignoreIds = options.ignoreIds || [];
3580
+ this.itemTemplate = options.itemTemplate || null;
3510
3581
  this.collectionParams = options.collectionParams || {};
3511
3582
  this.defaultParamsOption = options.defaultParams || null;
3512
3583
  this.baseParams = {};
@@ -3598,7 +3669,8 @@ class CollectionMultiSelectView extends View {
3598
3669
  totalCount,
3599
3670
  unselectedCount,
3600
3671
  allSelected: selectedCount === totalCount && totalCount > 0,
3601
- noneSelected: selectedCount === 0
3672
+ noneSelected: selectedCount === 0,
3673
+ customItemTemplate: this.itemTemplate
3602
3674
  });
3603
3675
  this.listView.on("toggle", (data) => {
3604
3676
  this.handleToggle(data);
@@ -3637,13 +3709,38 @@ class CollectionMultiSelectView extends View {
3637
3709
  if (this.ignoreIds.some((ignoreId) => ignoreId == id)) return false;
3638
3710
  return true;
3639
3711
  });
3640
- this.items = models.map((model, index) => ({
3641
- label: this.getFieldValue(model, this.labelField),
3642
- value: this.getFieldValue(model, this.valueField),
3643
- index,
3644
- selected: this.selectedValues.some((v) => v == this.getFieldValue(model, this.valueField)),
3645
- disabled: this.disabled
3646
- }));
3712
+ this.items = models.map((model, index) => {
3713
+ const modelData = model.toJSON ? model.toJSON() : model;
3714
+ const value = this.getFieldValue(model, this.valueField);
3715
+ const item = {
3716
+ label: this.getFieldValue(model, this.labelField),
3717
+ value,
3718
+ index,
3719
+ selected: this.selectedValues.some((v) => v == value),
3720
+ disabled: this.disabled,
3721
+ model: modelData
3722
+ // All model data nested under 'model' context
3723
+ };
3724
+ if (this.itemTemplate) {
3725
+ item.customContent = this.renderItemTemplate(item);
3726
+ }
3727
+ return item;
3728
+ });
3729
+ }
3730
+ // Render custom item template
3731
+ renderItemTemplate(itemData) {
3732
+ if (!this.itemTemplate) return "";
3733
+ try {
3734
+ const Mustache2 = window.Mustache || this.constructor.Mustache;
3735
+ if (!Mustache2) {
3736
+ console.warn("Mustache not available for item template rendering");
3737
+ return itemData.label;
3738
+ }
3739
+ return Mustache2.render(this.itemTemplate, itemData);
3740
+ } catch (error) {
3741
+ console.error("Error rendering item template:", error);
3742
+ return itemData.label;
3743
+ }
3647
3744
  }
3648
3745
  // Get field value (supports dot notation)
3649
3746
  getFieldValue(item, field) {
@@ -5795,6 +5892,8 @@ class FormView extends View {
5795
5892
  collection,
5796
5893
  defaultParams: fieldConfig.defaultParams || null,
5797
5894
  // Can be dict or callback
5895
+ itemTemplate: fieldConfig.itemTemplate || null,
5896
+ // Custom item template
5798
5897
  containerId: null
5799
5898
  // We'll mount directly
5800
5899
  });
@@ -6875,16 +6974,37 @@ class FormView extends View {
6875
6974
  return isValid;
6876
6975
  }
6877
6976
  /**
6878
- * Focus first error field
6977
+ * Focus first error
6978
+ * If the invalid field is inside a hidden tab pane, activate that tab first.
6879
6979
  */
6880
6980
  focusFirstError() {
6881
6981
  const form = this.getFormElement();
6882
6982
  if (!form) return;
6883
6983
  const firstInvalid = form.querySelector(":invalid");
6884
- if (firstInvalid) {
6885
- firstInvalid.focus();
6886
- firstInvalid.scrollIntoView({ behavior: "smooth", block: "center" });
6984
+ if (!firstInvalid) return;
6985
+ const tabPane = firstInvalid.closest(".tab-pane");
6986
+ if (tabPane && !tabPane.classList.contains("active")) {
6987
+ const tabId = tabPane.id;
6988
+ const trigger = form.querySelector(`[role="tab"][aria-controls="${tabId}"], [data-bs-target="#${tabId}"]`);
6989
+ if (trigger) {
6990
+ const bsTab = window.bootstrap?.Tab?.getOrCreateInstance ? window.bootstrap.Tab.getOrCreateInstance(trigger) : null;
6991
+ if (bsTab && typeof bsTab.show === "function") {
6992
+ bsTab.show();
6993
+ } else {
6994
+ const navLinks = form.querySelectorAll('[role="tab"].nav-link');
6995
+ navLinks.forEach((link) => {
6996
+ const isActive = link === trigger;
6997
+ link.classList.toggle("active", isActive);
6998
+ link.setAttribute("aria-selected", isActive ? "true" : "false");
6999
+ });
7000
+ const panes = form.querySelectorAll(".tab-pane");
7001
+ panes.forEach((p) => p.classList.remove("show", "active"));
7002
+ tabPane.classList.add("show", "active");
7003
+ }
7004
+ }
6887
7005
  }
7006
+ firstInvalid.focus();
7007
+ firstInvalid.scrollIntoView({ behavior: "smooth", block: "center" });
6888
7008
  }
6889
7009
  /**
6890
7010
  * Clear all errors
@@ -7470,4 +7590,4 @@ export {
7470
7590
  applyFileDropMixin as a,
7471
7591
  FormView$1 as b
7472
7592
  };
7473
- //# sourceMappingURL=FormView-CQbR3S82.js.map
7593
+ //# sourceMappingURL=FormView-BClEkzmE.js.map