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.
- package/dist/admin.cjs.js +1 -1
- package/dist/admin.cjs.js.map +1 -1
- package/dist/admin.es.js +14 -16
- package/dist/admin.es.js.map +1 -1
- package/dist/auth.cjs.js +1 -1
- package/dist/auth.cjs.js.map +1 -1
- package/dist/auth.es.js +2 -2
- package/dist/auth.es.js.map +1 -1
- package/dist/charts.cjs.js +1 -1
- package/dist/charts.es.js +2 -2
- package/dist/chunks/{ChatView-C1702ZPZ.js → ChatView-Bk3XGtNh.js} +69 -8
- package/dist/chunks/ChatView-Bk3XGtNh.js.map +1 -0
- package/dist/chunks/{ChatView-CVZScWPz.js → ChatView-Bz_YZdHd.js} +2 -2
- package/dist/chunks/ChatView-Bz_YZdHd.js.map +1 -0
- package/dist/chunks/{Dialog-Be1EkdvX.js → Dialog-BiVgKzSK.js} +3 -3
- package/dist/chunks/{Dialog-Be1EkdvX.js.map → Dialog-BiVgKzSK.js.map} +1 -1
- package/dist/chunks/{Dialog-YnhCC4C2.js → Dialog-DmIPK_Bi.js} +2 -2
- package/dist/chunks/{Dialog-YnhCC4C2.js.map → Dialog-DmIPK_Bi.js.map} +1 -1
- package/dist/chunks/{FormView-CQbR3S82.js → FormView-BClEkzmE.js} +134 -14
- package/dist/chunks/FormView-BClEkzmE.js.map +1 -0
- package/dist/chunks/FormView-nulck4nL.js +3 -0
- package/dist/chunks/FormView-nulck4nL.js.map +1 -0
- package/dist/chunks/{MetricsMiniChartWidget-CHsOuS2O.js → MetricsMiniChartWidget-CCroU6BZ.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-CHsOuS2O.js.map → MetricsMiniChartWidget-CCroU6BZ.js.map} +1 -1
- package/dist/chunks/{MetricsMiniChartWidget-DMGjpLSU.js → MetricsMiniChartWidget-Esvv-lFp.js} +2 -2
- package/dist/chunks/{MetricsMiniChartWidget-DMGjpLSU.js.map → MetricsMiniChartWidget-Esvv-lFp.js.map} +1 -1
- package/dist/chunks/{PDFViewer-BlWEqtY5.js → PDFViewer-D4uo3oiA.js} +2 -2
- package/dist/chunks/{PDFViewer-BlWEqtY5.js.map → PDFViewer-D4uo3oiA.js.map} +1 -1
- package/dist/chunks/{PDFViewer-BN200UnI.js → PDFViewer-NeL91Gon.js} +2 -2
- package/dist/chunks/{PDFViewer-BN200UnI.js.map → PDFViewer-NeL91Gon.js.map} +1 -1
- package/dist/chunks/{TopNav-DF8w5mgO.js → TopNav-23B5R-dl.js} +2 -2
- package/dist/chunks/{TopNav-DF8w5mgO.js.map → TopNav-23B5R-dl.js.map} +1 -1
- package/dist/chunks/{TopNav-ueVUoXcv.js → TopNav-CYTDmhAF.js} +2 -2
- package/dist/chunks/{TopNav-ueVUoXcv.js.map → TopNav-CYTDmhAF.js.map} +1 -1
- package/dist/chunks/{WebApp-m17riaNV.js → WebApp-CQKxglmg.js} +2 -2
- package/dist/chunks/{WebApp-m17riaNV.js.map → WebApp-CQKxglmg.js.map} +1 -1
- package/dist/chunks/{WebApp-gsWqZg8e.js → WebApp-CWuDQOYo.js} +13 -13
- package/dist/chunks/{WebApp-gsWqZg8e.js.map → WebApp-CWuDQOYo.js.map} +1 -1
- package/dist/docit.cjs.js +1 -1
- package/dist/docit.es.js +3 -3
- package/dist/index.cjs.js +1 -1
- package/dist/index.es.js +7 -7
- package/dist/lightbox.cjs.js +1 -1
- package/dist/lightbox.es.js +3 -3
- package/package.json +1 -1
- package/dist/chunks/ChatView-C1702ZPZ.js.map +0 -1
- package/dist/chunks/ChatView-CVZScWPz.js.map +0 -1
- package/dist/chunks/FormView-CQbR3S82.js.map +0 -1
- package/dist/chunks/FormView-DHz1ydYg.js +0 -3
- 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
|
-
|
|
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
|
-
|
|
3642
|
-
value
|
|
3643
|
-
|
|
3644
|
-
|
|
3645
|
-
|
|
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
|
|
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
|
-
|
|
6886
|
-
|
|
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-
|
|
7593
|
+
//# sourceMappingURL=FormView-BClEkzmE.js.map
|