parent
6492022ead
commit
436f889192
@ -1,8 +1,273 @@
|
||||
/**
|
||||
* Represents a table object.
|
||||
*/
|
||||
class Table {
|
||||
constructor(table_element) {
|
||||
this.table_element = table_element
|
||||
this.data = []
|
||||
/**
|
||||
* Initializes a new instance of the Table class.
|
||||
* @param {HTMLElement} tableElement - The HTML table element.
|
||||
* @param {HTMLElement} rcMenu - The right-click menu element.
|
||||
*/
|
||||
constructor(tableElement, rcMenu) {
|
||||
this.tableElement = tableElement
|
||||
this.tableBody = tableElement.querySelector("tbody")
|
||||
this.tableHead = tableElement.querySelector("thead")
|
||||
this.rcMenu = rcMenu
|
||||
|
||||
// Initialize right-click menu options
|
||||
this.rcAddRow = rcMenu.querySelector("#rcAddRow")
|
||||
this.rcDelRow = rcMenu.querySelector("#rcDelRow")
|
||||
this.rcAddCol = rcMenu.querySelector("#rcAddCol")
|
||||
this.rcDelCol = rcMenu.querySelector("#rcDelCol")
|
||||
|
||||
this.selectedCell = null
|
||||
|
||||
this.addEventListeners(this.rcMenu, this.tableElement)
|
||||
}
|
||||
|
||||
addEventListeners() {
|
||||
// Hide context menu when mouse button is clicked anywhere on the window
|
||||
window.addEventListener('mousedown', (e) => {
|
||||
this.rcMenu.style.display = "none"
|
||||
})
|
||||
|
||||
// Show context menu when right-clicking on the data table
|
||||
this.tableElement.addEventListener('contextmenu', (e) => {
|
||||
const pos = {
|
||||
x: e.clientX,
|
||||
y: e.clientY
|
||||
}
|
||||
|
||||
this.handleContextMenu(this.rcMenu, this.tableElement, pos)
|
||||
|
||||
this.selectedCell = e.target
|
||||
|
||||
// Prevent default context menu from appearing
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
})
|
||||
|
||||
// Add click event listeners to toggle display of settings submenus
|
||||
let labels = [...document.getElementsByClassName("submenuLabel")]
|
||||
labels.forEach(label => {
|
||||
label.addEventListener('click', e => {
|
||||
let submenuDiv = e.target.nextElementSibling
|
||||
|
||||
// Toggle display of submenu
|
||||
if (getComputedStyle(submenuDiv).display == "block")
|
||||
submenuDiv.style.display = "none"
|
||||
else
|
||||
submenuDiv.style.display = "block"
|
||||
})
|
||||
})
|
||||
|
||||
this.rcAddRow.addEventListener("mousedown", (e) => { this.addRow() })
|
||||
this.rcDelRow.addEventListener("mousedown", (e) => { this.delRow() })
|
||||
this.rcAddCol.addEventListener("mousedown", (e) => { this.addCol() })
|
||||
this.rcDelCol.addEventListener("mousedown", (e) => { this.delCol() })
|
||||
}
|
||||
|
||||
handleContextMenu(rcMenu, tableElement, pos) {
|
||||
rcMenu.style.display = "block"
|
||||
|
||||
// Position the context menu relative to the mouse pointer
|
||||
if (pos.x + rcMenu.clientWidth <= tableElement.clientWidth)
|
||||
rcMenu.style.left = pos.x + "px"
|
||||
else
|
||||
rcMenu.style.left = pos.x - rcMenu.clientWidth + "px"
|
||||
|
||||
if (pos.y + rcMenu.clientHeight <= window.innerHeight + document.documentElement.scrollTop)
|
||||
rcMenu.style.top = pos.y + "px"
|
||||
else
|
||||
rcMenu.style.top = pos.y - rcMenu.clientHeight + "px"
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the position of the cell in the table.
|
||||
* @param {HTMLElement} cell - The HTML cell element.
|
||||
* @returns {Object} An object containing the column and row indexes.
|
||||
*/
|
||||
getCellPos(cell) {
|
||||
// Name contains the column and row indexes.
|
||||
let name = cell.name
|
||||
|
||||
let match = name.match(/\d+/g)
|
||||
let col = +match[0]
|
||||
let row = +match[1]
|
||||
row = isNaN(row) ? -1 : row
|
||||
|
||||
return {
|
||||
col: col,
|
||||
row: row
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new row to the table below the selected cell.
|
||||
*/
|
||||
addRow() {
|
||||
// Clone the last row to create a new row.
|
||||
let lastRow = this.tableBody.lastElementChild
|
||||
let newRow = lastRow.cloneNode(true)
|
||||
|
||||
// Get all input cells in the new row.
|
||||
let cells = Array.from(newRow.children).map(cell => cell.querySelector("input"))
|
||||
// Determine the row index of the last row.
|
||||
let lastRowIndex = this.getCellPos(cells[0]).row
|
||||
|
||||
// Update IDs and names of input cells in the new row.
|
||||
cells.forEach(cell => {
|
||||
let pos = this.getCellPos(cell)
|
||||
cell.id = `chart_table_${pos.col}_values_${pos.row + 1}`
|
||||
cell.name = `chart[table][${pos.col}][values][${pos.row + 1}]`
|
||||
})
|
||||
|
||||
// Shift existing row data down to make room for a new row.
|
||||
let pos = this.getCellPos(this.selectedCell)
|
||||
//pos.row = pos.row === -1 ? 0 : pos.row
|
||||
pos.row++
|
||||
for (let i = lastRowIndex; i > pos.row; i--) {
|
||||
for (let j = 0; j < cells.length; j++) {
|
||||
let currentCell = this.tableBody.querySelector(`#chart_table_${j}_values_${i}`)
|
||||
let previousCell = this.tableBody.querySelector(`#chart_table_${j}_values_${i - 1}`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
}
|
||||
|
||||
this.tableBody.appendChild(newRow)
|
||||
|
||||
// Clear input cells in the new row.
|
||||
for (let j = 0; j < cells.length; j++) {
|
||||
let currentCell = this.tableBody.querySelector(`#chart_table_${j}_values_${pos.row}`)
|
||||
currentCell.value = ""
|
||||
console.log(currentCell)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deletes the row containing the selected cell.
|
||||
*/
|
||||
delRow() {
|
||||
// Get the number of rows and columns in the table.
|
||||
let rowCount = this.tableBody.children.length
|
||||
let colCount = this.tableBody.lastElementChild.children.length
|
||||
|
||||
// Get the position of the selected cell.
|
||||
let pos = this.getCellPos(this.selectedCell)
|
||||
|
||||
// Don't delete heading row.
|
||||
if (pos.row === -1)
|
||||
return
|
||||
|
||||
// Shift row data
|
||||
for (let i = pos.row; i < rowCount - 1; i++) {
|
||||
for (let j = 0; j < colCount; j++) {
|
||||
let currentCell = this.tableBody.querySelector(`#chart_table_${j}_values_${i}`)
|
||||
let previousCell = this.tableBody.querySelector(`#chart_table_${j}_values_${i + 1}`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the last row from the table.
|
||||
this.tableBody.removeChild(this.tableBody.lastElementChild)
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new column to the table.
|
||||
*/
|
||||
addCol() {
|
||||
// Get the rows and column count of the table.
|
||||
let rows = Array.from(this.tableBody.children)
|
||||
let rowCount = rows.length
|
||||
let colCount = this.tableBody.lastElementChild.children.length
|
||||
// Clone the last cell in the heading row to create a new header cell for the new column.
|
||||
let newHeadCell = this.tableHead.lastElementChild.lastElementChild.cloneNode(true)
|
||||
let newHeadCellInput = newHeadCell.querySelector("input[type='text']")
|
||||
newHeadCellInput.id = `chart_table_${colCount}_col_name`
|
||||
newHeadCellInput.name = `chart[table][${colCount}][col_name]`
|
||||
let newHeadCellColor = newHeadCell.querySelector("input[type='color']")
|
||||
newHeadCellColor.id = `chart_table_${colCount}_color`
|
||||
newHeadCellColor.name = `chart[table][${colCount}][color]`
|
||||
this.tableHead.lastElementChild.appendChild(newHeadCell)
|
||||
|
||||
// Clone the last cell in each row to create a new cell for the new column in each row.
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
let newCell = rows[i].lastElementChild.cloneNode(true)
|
||||
let newCellInput = newCell.querySelector("input")
|
||||
newCellInput.id = `chart_table_${colCount}_values_${i}`
|
||||
newCellInput.name = `chart[table][${colCount}][values][${i}]`
|
||||
|
||||
rows[i].appendChild(newCell)
|
||||
}
|
||||
|
||||
// Shift existing column data to the right to make room for a new column.
|
||||
let pos = this.getCellPos(this.selectedCell)
|
||||
pos.col++
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
for (let j = colCount; j > pos.col; j--) {
|
||||
let currentCell = this.tableBody.querySelector(`#chart_table_${j}_values_${i}`)
|
||||
let previousCell = this.tableBody.querySelector(`#chart_table_${j - 1}_values_${i}`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
}
|
||||
|
||||
// Shift existing column headings to the right to make room for a new column heading.
|
||||
for (let j = colCount; j > pos.col; j--) {
|
||||
let currentCell = this.tableHead.querySelector(`#chart_table_${j}_col_name`)
|
||||
let previousCell = this.tableHead.querySelector(`#chart_table_${j - 1}_col_name`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
|
||||
// Shift existing column colors to the right to make room for a new column color.
|
||||
for (let j = colCount; j > pos.col; j--) {
|
||||
let currentCell = this.tableHead.querySelector(`#chart_table_${j}_color`)
|
||||
let previousCell = this.tableHead.querySelector(`#chart_table_${j - 1}_color`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
|
||||
// Clear input cells in the new column.
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
let currentCell = this.tableBody.querySelector(`#chart_table_${pos.col}_values_${i}`)
|
||||
currentCell.value = ""
|
||||
}
|
||||
|
||||
// Clear the input and color of the new column heading.
|
||||
let headCell = this.tableHead.lastElementChild.children[pos.col]
|
||||
headCell.querySelector("input[type='text']").value = ""
|
||||
headCell.querySelector("input[type='color']").value = "#FFFFFF"
|
||||
}
|
||||
|
||||
delCol() {
|
||||
let rows = Array.from(this.tableBody.children)
|
||||
let rowCount = rows.length
|
||||
let colCount = this.tableBody.lastElementChild.children.length
|
||||
|
||||
let pos = this.getCellPos(this.selectedCell)
|
||||
for (let i = 0; i < rowCount; i++) {
|
||||
for (let j = pos.col; j < colCount - 1; j++) {
|
||||
let currentCell = this.tableBody.querySelector(`#chart_table_${j}_values_${i}`)
|
||||
let previousCell = this.tableBody.querySelector(`#chart_table_${j + 1}_values_${i}`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = pos.col; i < colCount - 1; i++) {
|
||||
let currentCell = this.tableHead.querySelector(`#chart_table_${i}_col_name`)
|
||||
let previousCell = this.tableHead.querySelector(`#chart_table_${i + 1}_col_name`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
|
||||
for (let i = pos.col; i < colCount - 1; i++) {
|
||||
let currentCell = this.tableHead.querySelector(`#chart_table_${i}_color`)
|
||||
let previousCell = this.tableHead.querySelector(`#chart_table_${i + 1}_color`)
|
||||
currentCell.value = previousCell.value
|
||||
}
|
||||
|
||||
rows.forEach(row => {
|
||||
row.removeChild(row.lastElementChild)
|
||||
})
|
||||
|
||||
this.tableHead.lastElementChild.removeChild(this.tableHead.lastElementChild.lastElementChild)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,14 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Form\Type;
|
||||
|
||||
use Symfony\Component\Form\AbstractType;
|
||||
use Symfony\Component\Form\Extension\Core\Type\ButtonType as BaseType;
|
||||
|
||||
class CellType extends AbstractType
|
||||
{
|
||||
public function getParent()
|
||||
{
|
||||
return BaseType::class;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue