profoundjs
Version:
Profound.js Framework and Server
327 lines (302 loc) • 14.9 kB
JavaScript
if (!window.plogic) window.plogic = {};
plogic.grid = {
// Used by option_buttons widget
// gridId = option_buttons["user defined data"]
// selectionFieldName = option_buttons["user defined data 2"] (optional - default value is "sopt")
doOption: (opt, gridId, selectionFieldName) => {
selectionFieldName = selectionFieldName || "option";
// Is there more than 1 grid?
arrGridId = gridId.split(",");
// Is there more than 1 selection fieldName?
arrSelectionFieldName = selectionFieldName.split(",");
if (arrGridId.length !== arrSelectionFieldName.length) {
alert(`The Option Buttons Widget "user defined data" & "user defined data 2" properties must have the same number of elements.`);
return;
}
for (let i = 0; i < arrGridId.length; i += 1) {
const gridObj = getObj(arrGridId[i]);
if (gridObj !== null) {
const count = gridObj.grid.getRecordCount();
for (let j = 1; j <= count; j += 1) {
if (gridObj.grid.getDataValue(j, plogic.string.up("schecked")) === "1") {
gridObj.grid.setDataValue(j, plogic.string.up(arrSelectionFieldName[i]), opt);
}
}
}
}
plogic.button.pressKey("Enter");
},
// Grid - Handle keyboard Mode changed
handleKeyboardModeChanged: (panel) => {
const isKeyboard = plogic.keyboardMode.getMode();
const iconKeyboardModeOn = "list_alt";
const iconKeyboardModeOff = "check_box";
panel = panel || document;
for (const gridWidget of panel.querySelectorAll('div[puiwdgt="grid"]')) {
// If there is an icon in the 1st colum of the grid, change it to match the keyboard mode state.
if (gridWidget.pui.properties["column headings"] && gridWidget.pui.properties["column headings"].split(",")[0].startsWith("<icon class=")) {
const arrColumnHeadings = gridWidget.pui.properties["column headings"].split(",");
arrColumnHeadings[0] = `<icon class="plogic--header pui-material-icons">${isKeyboard ? iconKeyboardModeOn : iconKeyboardModeOff}</icon>`;
gridWidget.grid.setProperty("column headings", arrColumnHeadings.toString());
}
const optionButtons = plogic.optionButtons.getforGrid(gridWidget);
if (!optionButtons) continue;
for (let row = 1; row <= gridWidget.grid.getRecordCount(); row += 1) {
if (gridWidget.pui.properties["display subfile"] !== "false") {
gridWidget.grid.setDataValue(row, plogic.string.up("keybrdmode"), isKeyboard);
}
}
}
},
// Check if the grid has active filters.
isFiltered: (gridObj) => {
if (get("filterAllId") === "") {
// Set the filterAll field with the retrieved filterAll value.
pui.set(`${gridObj.id}_filterAll`, gridObj.grid.getFilter("*all"));
}
let isFiltered = gridObj.grid.getFilter("*all") !== null && gridObj.grid.getFilter("*all") !== "";
if (!isFiltered) {
// Loop on all columns
for (let i = 0; i < gridObj.pui.properties["number of columns"]; i += 1) {
isFiltered = gridObj.grid.getFilter(i) !== null && gridObj.grid.getFilter(i) !== "";
if (isFiltered) break;
}
}
return isFiltered;
},
// Do onfilterchange action
onFilterChanged: (gridObj) => {
if (!gridObj) {
return;
}
// Check if the grid has active filters.
const gridIsFiltered = plogic.grid.isFiltered(gridObj);
const filterAllObj = getObj(`${gridObj.id}_filterAll`);
if (filterAllObj) {
// Add or remove the Remove Filters button depending on if grid has filtered rows or not.
plogic.button.toggleRemoveFiltersButton(gridIsFiltered, gridObj, filterAllObj);
}
},
// Position message subfile based on "messages" output field
positionMessageSubfile: (config) => {
// Is there an error messages grid ?
const msgGridItem = config.metaData.items.filter((item) => item["css class 2"] === "plogic--grid--messages")[0];
if (msgGridItem) {
const myGridParent = getObj(msgGridItem.layout); // The grid container
const myGrid = getObj(msgGridItem.id).grid; // The grid object
if (myGridParent && myGrid) {
// Update grid width based on its container width
const newWidth = `${myGridParent.clientWidth - parseInt(msgGridItem.left, 10) - 20}px`;
myGrid.setProperty("column widths", `${newWidth}`);
myGrid.setProperty("width", `${newWidth}px`);
myGrid.render();
}
}
},
// Remove all filters
removeFilter: (gridObj, filterAllObj, removeFilterButton) => {
pui.set(filterAllObj.id, ""); // Clear the filterAll field
if (gridObj && gridObj.grid) {
gridObj.grid.removeAllFilters();
}
},
// Resize a grid based on its parent width
resizeGrid: (gridObj) => {
const myGridParent = gridObj.parentElement; // The grid container
const myGrid = gridObj.grid;
// Update grid width based on its container width
const newWidth = `${myGridParent.clientWidth - parseInt(gridObj.style.left, 10) - 20}px`;
myGrid.setProperty("column widths", `${newWidth}`);
myGrid.setProperty("width", `${newWidth}px`);
myGrid.render();
},
// Row click -> is there a checkbox to select ?
rowClick: (row, rowNumber, event) => {
const gridWidget = event.srcElement.closest('div[puiwdgt="grid"]');
// Don't do anything on blank rows
if (row > gridWidget.grid.getRecordCount()) return;
let checkBox = getObj(`schecked.${row}`);
const simpleSelector = getObj(`${gridWidget.id.toLowerCase()}_selector.${row}`);
if (simpleSelector) {
simpleSelector.focus();
}
else {
const comboBox = checkBox && checkBox.previousElementSibling;
// Don't do anything if the selectors (combo box AND checkbox) are protected
if (
checkBox &&
(checkBox.classList.contains("PR") || checkBox.pui.properties["read only"] === "true") &&
comboBox &&
(comboBox.classList.contains("PR") || comboBox.pui.properties["read only"] === "true")
) {
return;
}
// Don't do anything if the selectors (combo box AND checkbox) are hidden
if (
checkBox &&
(checkBox.classList.contains("hidden") || checkBox.pui.properties.visibility === "hidden") &&
comboBox &&
(comboBox.classList.contains("hidden") || comboBox.pui.properties.visibility === "hidden")
) {
return;
}
// Don't do anything if the selector is protected
if (getObj(`schecked.${row}`) && getObj(`schecked.${row}`).pui.properties["read only"] === "true") return;
// Don't set the option if keyboard mode and row is selected
if (plogic.keyboardMode.getMode() && event && event.detail === 1) return;
// Do not select when not keyboard mode, single click and checkbox does not exist
if (!plogic.keyboardMode.getMode() && event && event.detail === 1 && !checkBox) return;
}
let makeSelected = event && event.detail === 2;
if (!makeSelected) {
const data = gridWidget.grid.getAllDataValues();
// We use rowNumber because of possible filtered or sorted rows.
makeSelected = !(data[rowNumber - 1][plogic.string.up("schecked")] == "1" ? true : false);
}
if (!simpleSelector) {
if (makeSelected) plogic.grid.setOption(gridWidget, row);
else plogic.grid.setOption(gridWidget, row, "");
}
// Double-click
if (event && event.detail === 2) plogic.button.pressKey("Enter");
},
// Sometimes, grids have column headings built with variables. Those headings have been temporary tagged by the conversion theme as @[item_fieldName].
// This function will build "column headings" property based on those individuals fields.
setColumnHeadings: (format) => {
const arrGrids = format.metaData.items.filter((item) => item["field type"] === "grid" && !item["subfile message key"]);
for (const gridWidget of arrGrids) {
if (gridWidget["column headings"]) {
const arrHeadings = gridWidget["column headings"].split(",");
let arrTempFieldNames = [];
for (let j = 0; j < arrHeadings.length; j += 1) {
// If the heading corresponds to an individual field, let's replace the dummy value with the field value.
if (arrHeadings[j].includes("@[") && arrHeadings[j].includes("]")) {
const heading = arrHeadings[j];
const posStart = heading.indexOf("@[") + 2;
const posEnd = heading.indexOf("]");
if (posStart >= posEnd) return;
const tempFieldName = arrHeadings[j].substring(posStart, posEnd);
// If there is more than one variable inside the brackets, the separator has to be ";;".
if (tempFieldName.includes(";;")) {
arrTempFieldNames = tempFieldName.split(";;");
}
else {
arrTempFieldNames = [];
arrTempFieldNames.push(tempFieldName);
}
let tempHeading;
arrHeadings[j] = "";
for (let k = 0; k < arrTempFieldNames.length; k += 1) {
let currentItem = format.metaData.items.find((item) => item.value && item.value.fieldName && item.value.fieldName === arrTempFieldNames[k]);
if (!currentItem) {
currentItem = format.metaData.items.find((item) => item.id.endsWith(arrTempFieldNames[k]));
}
if (currentItem) {
tempHeading = plogic.fields.getItemValue(currentItem, format);
}
// If the field has a conditioned visibility
if (
currentItem &&
currentItem.visibility &&
currentItem.visibility.fieldName &&
currentItem.visibility.dataType === "expression" &&
currentItem.visibility.formatting === "Indicator"
) {
const indicatorValue = format.data[`*IN${currentItem.visibility.fieldName.trim("N")}`];
// If not visible, search for the opposite field
if (
(indicatorValue === "0" && currentItem.visibility.indFormat === "visible / hidden") ||
(indicatorValue === "1" && currentItem.visibility.indFormat === "hidden / visible")
) {
// Opposite item = if the current item has a visibility conditioned by an indicator, we search the item with the same row/column and with opposite visibility.
const oppositeItem = plogic.fields.getOppositeItem(currentItem, format.metaData.items);
if (oppositeItem) {
tempHeading = plogic.fields.getItemValue(oppositeItem, format);
}
}
}
if (k > 0) tempHeading = ` ${tempHeading}`; // Add a space between labels
// Does currentItem have a "display attribute" property?
// If yes, let's add the corresponding CSS class.
if (currentItem && currentItem["display attribute field"] && currentItem["display attribute field"].fieldName) {
const tempCSS = plogic.string.getClassFromHexcode(format.data[plogic.string.up(currentItem["display attribute field"].fieldName)]);
tempHeading = `<div class="${tempCSS}">${tempHeading}</div>`;
}
arrHeadings[j] += tempHeading;
// If last pass
if (k === arrTempFieldNames.length - 1) {
arrHeadings[j] = heading.replace(`@[${tempFieldName}]`, arrHeadings[j]);
// If there is another variable like @[xxx]
if (arrHeadings[j].includes("@[")) j -= 1;
}
}
}
}
gridWidget["column headings"] = arrHeadings.toString();
}
}
},
// Grid filter Textbox
setFilter: (gridId, filterObj) => {
if (getObj(gridId) && getObj(gridId).grid) {
getObj(gridId).grid.setFilter("*all", filterObj.value);
}
},
setOption: (gridWidget, row, value) => {
const optionButtons = plogic.optionButtons.getforGrid(gridWidget);
if (!optionButtons) return;
let selecting = false;
if (value == null) {
value = optionButtons.pui.optionButtons.getDefaultOption();
// Not passing the 'value' parm means we are selecting records and the value takes the default value retruned by getDefaultOption().
// But this default value can only be 1, 2 or 5. If these 3 options are not authorized/available, it will return blank.
// Therefore, we need an indicator saying that we are "selecting" records.
selecting = true;
}
// selectionFieldName = option_buttons["user defined data 2"] (optional - default value is "sopt")
let selectionFieldName = optionButtons.pui.properties["user defined data 2"] || "option";
// Is there more than 1 selection fieldName?
arrSelectionFieldName = selectionFieldName.split(",");
for (let i = 0; i < arrSelectionFieldName.length; i += 1) {
// Do not change the selector value on blank rows
if (row <= gridWidget.grid.getRecordCount()) {
gridWidget.grid.setDataValue(row, plogic.string.up(arrSelectionFieldName[i]), value);
gridWidget.grid.setDataValue(row, plogic.string.up("schecked"), value.length > 0 || selecting ? "1" : "0");
}
}
},
setSelection: (gridWidget, row, value) => {
const schecked = plogic.string.up("schecked");
// Do not change the selector value on blank rows
if (row <= gridWidget.grid.getRecordCount()) {
// Only change the value if selecting/deselecting the row
if (
gridWidget.grid.getDataValue(row, schecked) !== undefined &&
(
(gridWidget.grid.getDataValue(row, schecked) === "1" && value === "0") ||
(gridWidget.grid.getDataValue(row, schecked) === "0" && [undefined, "1"].includes(value))
)
) {
gridWidget.grid.setDataValue(row, schecked, value);
}
}
},
// Update grid column headings css class
updateHeadingsClass: (gridObj) => {
// Grid column headings cells
const arrGridHeaders = Array.prototype.slice.call(gridObj.querySelectorAll(".cell.header-cell"));
// Grid 1st row cells
const arrGridRow1Cells = Array.prototype.slice.call(gridObj.querySelectorAll(".cell.odd")).slice(0, arrGridHeaders.length);
for (let i = 0; i < arrGridRow1Cells.length; i += 1) {
// List elements of the grid cell
const arrCellChildren = Array.prototype.slice.call(arrGridRow1Cells[i].children);
if (arrCellChildren) {
// Check if the cell content has the "plogic--monospace" css class. If yes, add that class to the header.
const arrElems = arrCellChildren.find((elem) => elem.className.includes("plogic--monospace"));
if (arrElems) {
arrGridHeaders[i].className += " plogic--monospace";
}
}
}
}
};