b8b56383b460baeded0eb044c5c50998564f4b9d
jcasper
Sun Jan 25 22:35:48 2026 -0800
Initial pass at making data types optional for the new faceted
composite UI. refs #36320
diff --git src/hg/js/facetedComposite.js src/hg/js/facetedComposite.js
index e14690b3867..2a2f31e613b 100644
--- src/hg/js/facetedComposite.js
+++ src/hg/js/facetedComposite.js
@@ -71,30 +71,35 @@
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: `hgsid=${hgsid}&db=${db}&${uriForUpdate}`,
}).then(() => {
// 'disable' any CSS named elements here to them keep out of cart
const dtLength = submitBtnEvent.
target.form.querySelector("select[name$='_length']");
if (dtLength) {
dtLength.disabled = true;
}
submitBtnEvent.target.form.submit(); // release submit event
});
}
function initDataTypeSelector() {
+ // Skip if no dataTypes defined or empty object
+ if (!embeddedData.dataTypes || Object.keys(embeddedData.dataTypes).length === 0) {
+ return;
+ }
+
const selector = document.getElementById("dataTypeSelector");
selector.appendChild(Object.assign(document.createElement("label"), {
innerHTML: "Data type",
}));
Object.keys(embeddedData.dataTypes).forEach(name => {
const label = document.createElement("label");
label.innerHTML = `
${name}`;
selector.appendChild(label);
});
const selectedDataTypes = new Set( // get dataTypes selected initially
Object.entries(embeddedData.dataTypes).filter(([_, val]) => val === 1)
.map(([key]) => key)
);
// initialize data type checkboxes (using class instead of 'name')
@@ -224,31 +229,32 @@
const filtersDiv = document.getElementById("filters");
colNames.forEach((key) => {
// skip attributes if they should be excluded from checkbox sets
if (excludeCheckboxes.includes(key)) {
return;
}
const sortedPossibleVals = Array.from(possibleValues[key].entries());
sortedPossibleVals.sort((a, b) => // neg: less-than
a[1] !== b[1] ? b[1] - a[1] : a[0].localeCompare(b[0]));
// Use 'maxCheckboxes' most frequent items (if they appear > 1 time)
let topToShow = sortedPossibleVals
.filter(([val, count]) =>
- val.trim().toUpperCase() !== "NA" && count > 1)
+ val.trim().toUpperCase() !== "NA") // why only > 1?
+ //val.trim().toUpperCase() !== "NA" && count > 1)
.slice(0, maxCheckboxes);
// Any "other/Other/OTHER" entry will be put at the end
let otherKey = null, otherValue = null;
topToShow = topToShow.filter(([val, value]) => {
if (val.toLowerCase() === "other") {
otherKey = val;
otherValue = value;
return false;
}
return true;
});
if (otherValue !== null) {
topToShow.push([otherKey, otherValue]);
}
@@ -305,45 +311,60 @@
clearBtn.textContent = "Clear";
clearBtn.type = "button"; // prevent form submit if inside a form
clearBtn.addEventListener("click", () => {
cboxes.forEach(cb => cb.checked = false); // Uncheck all
// Recalculate the (now cleared) search term and update table
table.column(colIdx + 1).search("", true, false).draw();
});
// Prepend the "clear" button
attrDiv.insertBefore(clearBtn, attrDiv.children[1] || null);
});
return table; // to chain calls
} // end initFilters
function initSubmit(table) { // logic for the submit event
const { mdid, primaryKey } = embeddedData; // mdid: metadata identifier
+ const hasDataTypes = embeddedData.dataTypes &&
+ Object.keys(embeddedData.dataTypes).length > 0;
+
document.getElementById("Submit").addEventListener("click", (submitBtnEvent) => {
submitBtnEvent.preventDefault(); // hold the submit button event
const selectedRows = table.rows({selected: true}).data().toArray();
+ const uriForUpdate = new URLSearchParams({ "cartDump.metaDataId": mdid, "noDisplay": 1 });
+ selectedRows.forEach(obj => // 'de' for data element
+ uriForUpdate.append(`${mdid}.de`, obj[primaryKey]));
+
+ if (hasDataTypes) {
+ // Collect checked data types
const selectedDataTypes = [];
document.querySelectorAll("input.cbgroup").forEach(cb => {
if (cb.checked) {
selectedDataTypes.push(cb.value);
}
});
- const uriForUpdate = new URLSearchParams({ "cartDump.metaDataId": mdid, "noDisplay": 1 });
- selectedRows.forEach(obj => // 'de' for data element
- uriForUpdate.append(`${mdid}.de`, obj[primaryKey]));
+ // Require at least one data type when the selector exists
+ if (selectedDataTypes.length === 0) {
+ alert("Please select at least one data type.");
+ return; // abort submission
+ }
selectedDataTypes.forEach(dat => // 'dt' for data type
uriForUpdate.append(`${mdid}.dt`, dat));
+ } else {
+ // No data types configured for this track: send empty-string sentinel
+ uriForUpdate.append(`${mdid}.dt`, "");
+ }
updateVisibilities(uriForUpdate, submitBtnEvent);
});
} // end initSubmit
function initAll(dataForTable) {
initDataTypeSelector();
const table = initTable(dataForTable);
initFilters(table, dataForTable);
initSubmit(table);
}
function loadDataAndInit() { // load data and call init functions
const { mdid, primaryKey, metadataUrl, colorSettingsUrl } = embeddedData;
const CACHE_KEY = mdid;