mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-12 18:43:26 +00:00
web ui cost module:
- double click cost cell to enable editing cost values. - fix tables' height / scrollbar behaviour
This commit is contained in:
@@ -3,6 +3,8 @@
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
border: 1px solid #444;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.ribbon-bar .action-button {
|
||||
|
||||
@@ -11,45 +11,55 @@
|
||||
--scrollbar-track-color: #f1f1f1;
|
||||
--scrollbar-thumb-color: #888;
|
||||
--scrollbar-thumb-hover-color: #555;
|
||||
--padding-small: 5px;
|
||||
--padding-medium: 10px;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.form-header {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-bottom: 10px;
|
||||
background-color: var(--background-color);
|
||||
padding: 10px;
|
||||
font-size: var(--fontSize);
|
||||
background-color: #323936;
|
||||
padding: var(--padding-medium);
|
||||
font-size: large;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-radius: 6px 6px 0 0;
|
||||
}
|
||||
|
||||
span {
|
||||
.floating-form span {
|
||||
padding: var(--padding-small);
|
||||
margin-left: var(--margin-small);
|
||||
}
|
||||
|
||||
.floating-form {
|
||||
width: 50vw;
|
||||
height: 50vh;
|
||||
max-height: 80vh;
|
||||
position: absolute;
|
||||
background-color: var(--background-color);
|
||||
border: 1px solid black;
|
||||
z-index: 9999;
|
||||
cursor: move;
|
||||
padding: 20px;
|
||||
user-select: none;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
resize: both;
|
||||
}
|
||||
|
||||
.floating-form table tr {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
|
||||
.form-container {
|
||||
padding: var(--padding-medium);
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.action-button {
|
||||
background-color: var(--button-background);
|
||||
border: none;
|
||||
@@ -128,32 +138,37 @@ body {
|
||||
overflow-x: auto;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.floating-form .table-container {
|
||||
height: 50%;
|
||||
max-height: 50%;
|
||||
max-height: 70%;
|
||||
}
|
||||
|
||||
#cost-items {
|
||||
max-height: calc(100vh - var(--margin-small));
|
||||
}
|
||||
|
||||
/* if id starts with cost-values-form */
|
||||
[id^="cost-values-form"] table {
|
||||
/* fixed */
|
||||
max-height: 50%;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
|
||||
[id^="selected-products"] .form-container {
|
||||
height: 50vh;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-collapse: collapse;
|
||||
user-select: none;
|
||||
font-size: var(--fontSize);
|
||||
-webkit-font-smoothing: antialiased; /* Improve font rendering */
|
||||
-moz-osx-font-smoothing: grayscale; /* Improve font rendering */
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
border: 1px solid #ddd;
|
||||
}
|
||||
|
||||
thead {
|
||||
@@ -161,7 +176,6 @@ thead {
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background-color: #727272;
|
||||
font-size: large;
|
||||
}
|
||||
|
||||
tbody {
|
||||
@@ -172,13 +186,9 @@ tbody {
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-left: 1px solid #ddd;
|
||||
border-right: 1px solid #ddd;
|
||||
text-align: center;
|
||||
border-bottom: 0;
|
||||
border-top: 0;
|
||||
}
|
||||
|
||||
th {
|
||||
@@ -189,7 +199,6 @@ td {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
/* first td of a row, must be flex */
|
||||
td:first-child {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -223,7 +232,7 @@ select {
|
||||
margin-left: 0.5em;
|
||||
margin-right: 0.5em;
|
||||
font-size: var(--fontSize);
|
||||
min-width: 50px; /* Minimum width to prevent it from becoming too small */
|
||||
min-width: 50px;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
@@ -258,7 +267,6 @@ input:focus {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Responsive Styles */
|
||||
@media (max-width: 768px) {
|
||||
table {
|
||||
font-size: 12px;
|
||||
@@ -295,3 +303,9 @@ input:focus {
|
||||
form table {
|
||||
max-height: 50%;
|
||||
}
|
||||
|
||||
|
||||
.subtotal-row {
|
||||
background-color: var(--button-hover-background);
|
||||
font-weight: bold;
|
||||
}
|
||||
@@ -51,7 +51,7 @@
|
||||
--border-color: #222;
|
||||
}
|
||||
|
||||
*:not(td, tr, td, .gmain) {
|
||||
*:not(td, tr, td, th, button, .gmain) {
|
||||
border-radius: var(--border-radius) !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,21 +11,7 @@ $(document).ready(function () {
|
||||
setTheme(theme);
|
||||
|
||||
connectSocket();
|
||||
CostUI.addSettingsMenu();
|
||||
CostUI.addRibbonButton({
|
||||
text: "Hide Schedules",
|
||||
icon: "fa-regular fa-eye-slash",
|
||||
callback: (button) => {
|
||||
CostUI.toggleSchedulesContainer(button);
|
||||
},
|
||||
});
|
||||
CostUI.addRibbonButton({
|
||||
text: "Settings",
|
||||
icon: "fas fa-cog",
|
||||
callback: (button) => {
|
||||
CostUI.toggleSettingsMenu(button);
|
||||
},
|
||||
});
|
||||
CostUI.createRibbon();
|
||||
});
|
||||
|
||||
function connectSocket() {
|
||||
@@ -54,9 +40,15 @@ function handleSelectedProducts(data) {
|
||||
const formId = "selected-products-" + costItemId;
|
||||
const form = CostUI.Form({
|
||||
id: formId,
|
||||
name: "Selected Products",
|
||||
icon: "fa-solid fa-cart-shopping",
|
||||
name: "Edit Product Assignments for: " + CostUI.getCostItemName(costItemId),
|
||||
icon: "fa-solid fa-box",
|
||||
});
|
||||
const numberOfProducts = CostUI.Text(
|
||||
"Selection basket : " + products.length + " products",
|
||||
"fa-solid fa-cart-shopping",
|
||||
"large"
|
||||
);
|
||||
form.appendChild(numberOfProducts);
|
||||
CostUI.highlightElement(costItemId);
|
||||
const selectedProductsTable = CostUI.createProductTable({
|
||||
form,
|
||||
@@ -68,11 +60,12 @@ function handleSelectedProducts(data) {
|
||||
getSelectedProducts: getSelectedProducts,
|
||||
},
|
||||
});
|
||||
|
||||
if (assigned_products.length > 0) {
|
||||
const assignedProductsText = CostUI.Text(
|
||||
"Assigned Products",
|
||||
"fa-solid fa-box",
|
||||
"x-large"
|
||||
"fa-solid fa-solid fa-paperclip",
|
||||
"large"
|
||||
);
|
||||
form.appendChild(assignedProductsText);
|
||||
const assignmentsTable = CostUI.createAssignmentsTable({
|
||||
@@ -339,7 +332,6 @@ function handleCostSchedulesData(data) {
|
||||
"Predefined Type: " + costSchedule.PredefinedType,
|
||||
"fa-solid fa-paperclip"
|
||||
);
|
||||
// simplyfying the date
|
||||
const updatedDate = new Date(costSchedule.UpdateDate).toLocaleDateString();
|
||||
const updatedOn = CostUI.Text(
|
||||
"Updated On: " + updatedDate,
|
||||
@@ -363,7 +355,6 @@ function handleCostSchedulesData(data) {
|
||||
}
|
||||
|
||||
function handleCostItemsData(data) {
|
||||
console.log(data);
|
||||
const cards = document.querySelectorAll("[id^='schedule-']");
|
||||
cards.forEach((card) => {
|
||||
if (card.id === "schedule-" + data.data["cost_items"]["cost_schedule_id"]) {
|
||||
|
||||
@@ -182,7 +182,6 @@ export class CostUI {
|
||||
getSelectedProducts.hasListener = true;
|
||||
}
|
||||
|
||||
// Function to get column names from the table header
|
||||
function getColumnNames(tableId) {
|
||||
const table = document.getElementById(tableId);
|
||||
const headerRow = table.querySelector("thead tr");
|
||||
@@ -191,7 +190,6 @@ export class CostUI {
|
||||
);
|
||||
}
|
||||
|
||||
// Add double-click event listener
|
||||
document
|
||||
.getElementById("cost-items")
|
||||
.addEventListener("dblclick", function (event) {
|
||||
@@ -202,36 +200,12 @@ export class CostUI {
|
||||
targetCell
|
||||
);
|
||||
const costItemId = parseInt(targetRow.getAttribute("id"));
|
||||
const cellContent = targetCell.textContent;
|
||||
const columnName = getColumnNames("cost-items")[columnIndex];
|
||||
|
||||
// Get column names from the table header
|
||||
const columnNames = getColumnNames("cost-items");
|
||||
const cellName = columnNames[columnIndex];
|
||||
|
||||
console.log("Column Name: ", cellName);
|
||||
console.log("Content: ", cellContent);
|
||||
|
||||
// Implement different behaviors based on the column index
|
||||
switch (columnIndex) {
|
||||
case 0:
|
||||
// Behavior for the first column
|
||||
callbacks.firstColumnDoubleClick
|
||||
? callbacks.firstColumnDoubleClick(costItemId)
|
||||
: null;
|
||||
break;
|
||||
case 1:
|
||||
// Behavior for the second column
|
||||
callbacks.secondColumnDoubleClick
|
||||
? callbacks.secondColumnDoubleClick(costItemId)
|
||||
: null;
|
||||
break;
|
||||
// Add more cases as needed for other columns
|
||||
default:
|
||||
// Default behavior
|
||||
callbacks.defaultDoubleClick
|
||||
? callbacks.defaultDoubleClick(costItemId)
|
||||
: null;
|
||||
break;
|
||||
if (columnName === "Cost") {
|
||||
callbacks.enableEditingCostValues
|
||||
? callbacks.enableEditingCostValues(costItemId)
|
||||
: null;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -345,21 +319,24 @@ export class CostUI {
|
||||
form.appendChild(typeSelect);
|
||||
|
||||
const submitButton = document.createElement("button");
|
||||
submitButton.type = "submit";
|
||||
submitButton.textContent = "Add";
|
||||
submitButton.classList.add("action-button");
|
||||
form.appendChild(submitButton);
|
||||
|
||||
form.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(form);
|
||||
const data = {};
|
||||
formData.forEach((value, key) => {
|
||||
data[key] = value;
|
||||
document
|
||||
.getElementById("add-cost-schedule-form")
|
||||
.addEventListener("submit", function (event) {
|
||||
event.preventDefault();
|
||||
const formData = new FormData(
|
||||
document.getElementById("add-cost-schedule-form")
|
||||
);
|
||||
const data = {};
|
||||
formData.forEach((value, key) => {
|
||||
data[key] = value;
|
||||
});
|
||||
addCostSchedule(data.name, data["Predefined Type"]);
|
||||
document.getElementById("add-cost-schedule-form").remove();
|
||||
});
|
||||
addCostSchedule(data.name, data["Predefined Type"]);
|
||||
form.remove();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1012,19 +989,20 @@ export class CostUI {
|
||||
}
|
||||
|
||||
static Form({ id, name, icon = "fa-solid fa-file", shouldHide = false }) {
|
||||
let form;
|
||||
if (document.getElementById(id)) {
|
||||
form = document.getElementById(id);
|
||||
} else {
|
||||
form = document.createElement("form");
|
||||
form.id = id;
|
||||
form.classList.add("floating-form");
|
||||
form.style.position = "absolute";
|
||||
form.style.top = "50%";
|
||||
form.style.left = "50%";
|
||||
form.style.transform = "translate(-50%, -50%)";
|
||||
const formContainer = document
|
||||
.getElementById(id)
|
||||
.querySelector(".form-container");
|
||||
formContainer.innerHTML = "";
|
||||
return formContainer;
|
||||
}
|
||||
|
||||
const form = document.createElement("form");
|
||||
form.id = id;
|
||||
form.classList.add("floating-form");
|
||||
form.style.position = "absolute";
|
||||
form.style.top = "50%";
|
||||
form.style.left = "50%";
|
||||
form.style.transform = "translate(-50%, -50%)";
|
||||
const header = CostUI.createHeader(name, icon);
|
||||
let closeButton;
|
||||
if (shouldHide) {
|
||||
@@ -1035,8 +1013,12 @@ export class CostUI {
|
||||
form.appendChild(header);
|
||||
form.appendChild(closeButton);
|
||||
CostUI.makeFormDraggable(form);
|
||||
|
||||
const formContainer = document.createElement("div");
|
||||
formContainer.classList.add("form-container");
|
||||
form.appendChild(formContainer);
|
||||
document.body.appendChild(form);
|
||||
return form;
|
||||
return formContainer;
|
||||
}
|
||||
static makeFormDraggable(form) {
|
||||
let pos1 = 0,
|
||||
@@ -1154,7 +1136,6 @@ export class CostUI {
|
||||
Object.entries(qto).forEach(([key, value]) => {
|
||||
if (key !== "id") {
|
||||
const cell = document.createElement("td");
|
||||
// check if value is a number
|
||||
cell.textContent = parseFloat(value).toFixed(2);
|
||||
row.appendChild(cell);
|
||||
}
|
||||
@@ -1254,7 +1235,7 @@ export class CostUI {
|
||||
});
|
||||
}
|
||||
|
||||
subtotalRow.style.fontWeight = "bold";
|
||||
subtotalRow.classList.add("subtotal-row");
|
||||
|
||||
return subtotalRow;
|
||||
}
|
||||
@@ -1489,9 +1470,6 @@ export class CostUI {
|
||||
}
|
||||
|
||||
static addSettingsMenu() {
|
||||
if (document.getElementById("settings-menu")) {
|
||||
return document.getElementById("settings-menu");
|
||||
}
|
||||
const settingsMenu = CostUI.Form({
|
||||
id: "settings-menu",
|
||||
name: "Settings",
|
||||
@@ -1503,14 +1481,7 @@ export class CostUI {
|
||||
const tableFontSize = CostUI.createFontSizePicker();
|
||||
settingsMenu.appendChild(picker);
|
||||
settingsMenu.appendChild(tableFontSize);
|
||||
|
||||
settingsMenu.style.display = "none";
|
||||
const settingsButton = document.getElementById("settings-button");
|
||||
settingsButton.addEventListener("click", function () {
|
||||
settingsMenu.style.display = "block";
|
||||
});
|
||||
|
||||
// Apply saved settings on page load
|
||||
document.getElementById("settings-menu").style.display = "none";
|
||||
CostUI.applySavedSettings();
|
||||
}
|
||||
|
||||
@@ -1570,7 +1541,6 @@ export class CostUI {
|
||||
}
|
||||
|
||||
static applySavedSettings() {
|
||||
console.log("Applying saved settings");
|
||||
const savedFontSize = localStorage.getItem("tableFontSize");
|
||||
if (savedFontSize) {
|
||||
CostUI.applyFontSizeToAllTables(savedFontSize);
|
||||
@@ -1599,7 +1569,7 @@ export class CostUI {
|
||||
|
||||
const button = document.createElement("button");
|
||||
button.classList.add("action-button", ...icon.split(" "));
|
||||
button.dataset.tooltip = text; // Use dataset to set the tooltip attribute
|
||||
button.dataset.tooltip = text;
|
||||
|
||||
button.addEventListener("click", () => callback(button));
|
||||
|
||||
@@ -1641,20 +1611,30 @@ export class CostUI {
|
||||
return document.getElementById("settings-menu");
|
||||
}
|
||||
|
||||
static toggleSettingsMenu(button) {
|
||||
static toggleSettingsMenu() {
|
||||
const settingsMenu = CostUI.getSettingsMenu();
|
||||
const isHidden = settingsMenu.style.display === "none";
|
||||
|
||||
if (isHidden) {
|
||||
if (settingsMenu.style.display === "none") {
|
||||
settingsMenu.style.display = "block";
|
||||
button.classList.remove("fa-gear");
|
||||
button.classList.add("fa-times");
|
||||
button.dataset.tooltip = "Close Settings";
|
||||
} else {
|
||||
settingsMenu.style.display = "none";
|
||||
button.classList.remove("fa-times");
|
||||
button.classList.add("fa-gear");
|
||||
button.dataset.tooltip = "Open Settings";
|
||||
}
|
||||
}
|
||||
|
||||
static createRibbon() {
|
||||
CostUI.addSettingsMenu();
|
||||
CostUI.addRibbonButton({
|
||||
text: "Hide Schedules",
|
||||
icon: "fa-regular fa-eye-slash",
|
||||
callback: (button) => {
|
||||
CostUI.toggleSchedulesContainer(button);
|
||||
},
|
||||
});
|
||||
CostUI.addRibbonButton({
|
||||
text: "Settings",
|
||||
icon: "fas fa-cog",
|
||||
callback: () => {
|
||||
CostUI.toggleSettingsMenu();
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,9 +75,6 @@
|
||||
<button id="toggle-theme" onclick="toggleTheme()">
|
||||
<i class="fas fa-moon"></i>
|
||||
</button>
|
||||
<button id="settings-button">
|
||||
<i class="fa-solid fa-gear"></i>
|
||||
</button>
|
||||
<div id="connected-list-div">
|
||||
<button id="show-connected-button" onclick="toggleClientList()">
|
||||
Connected Blenders:
|
||||
|
||||
Reference in New Issue
Block a user