anycoder-cbf34bc5 / index.html
Azerty2197's picture
Upload folder using huggingface_hub
09c24b3 verified
Raw History Blame Contribute Delete
35.8 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>WebSheet - Online Spreadsheet Editor</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/xlsx/0.18.5/xlsx.full.min.js"></script>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
:root {
--primary-color: #217346;
--secondary-color: #107c41;
--header-bg: #217346;
--toolbar-bg: #f3f2f1;
--border-color: #d0d7de;
--cell-hover: #f0f6ff;
--cell-selected: #e3f2fd;
--cell-editing: #ffffff;
--text-primary: #323130;
--text-secondary: #605e5c;
--shadow-sm: 0 1px 3px rgba(0,0,0,0.12);
--shadow-md: 0 4px 6px rgba(0,0,0,0.1);
--shadow-lg: 0 10px 25px rgba(0,0,0,0.1);
}
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
display: flex;
flex-direction: column;
overflow: hidden;
}
.app-container {
flex: 1;
display: flex;
flex-direction: column;
background: white;
max-width: 1400px;
width: 100%;
margin: 0 auto;
box-shadow: 0 0 50px rgba(0,0,0,0.2);
}
header {
background: var(--header-bg);
color: white;
padding: 0.75rem 1.5rem;
display: flex;
justify-content: space-between;
align-items: center;
box-shadow: var(--shadow-md);
z-index: 100;
}
.logo {
display: flex;
align-items: center;
gap: 0.75rem;
font-size: 1.25rem;
font-weight: 600;
}
.logo-icon {
width: 32px;
height: 32px;
background: white;
border-radius: 6px;
display: flex;
align-items: center;
justify-content: center;
color: var(--primary-color);
font-weight: bold;
}
.header-actions {
display: flex;
gap: 1rem;
align-items: center;
}
.header-actions a {
color: white;
text-decoration: none;
font-size: 0.875rem;
opacity: 0.9;
transition: opacity 0.2s;
}
.header-actions a:hover {
opacity: 1;
}
.toolbar {
background: var(--toolbar-bg);
padding: 0.75rem 1.5rem;
display: flex;
gap: 1rem;
align-items: center;
flex-wrap: wrap;
border-bottom: 1px solid var(--border-color);
box-shadow: var(--shadow-sm);
}
.toolbar-group {
display: flex;
gap: 0.5rem;
align-items: center;
padding: 0 0.75rem;
border-right: 1px solid var(--border-color);
}
.toolbar-group:last-child {
border-right: none;
}
.toolbar-btn {
background: white;
border: 1px solid var(--border-color);
padding: 0.5rem 0.75rem;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
color: var(--text-primary);
transition: all 0.2s;
position: relative;
}
.toolbar-btn:hover {
background: #f0f0f0;
transform: translateY(-1px);
box-shadow: var(--shadow-sm);
}
.toolbar-btn:active {
transform: translateY(0);
}
.toolbar-btn.primary {
background: var(--secondary-color);
color: white;
border-color: var(--secondary-color);
}
.toolbar-btn.primary:hover {
background: #0e5d2f;
}
.toolbar-btn.danger {
background: #d83b01;
color: white;
border-color: #d83b01;
}
.toolbar-btn.danger:hover {
background: #c23a00;
}
.toolbar-select {
padding: 0.5rem;
border: 1px solid var(--border-color);
border-radius: 4px;
background: white;
color: var(--text-primary);
font-size: 0.875rem;
cursor: pointer;
}
.toolbar-input {
width: 60px;
padding: 0.5rem;
border: 1px solid var(--border-color);
border-radius: 4px;
font-size: 0.875rem;
}
.formula-bar {
background: white;
border-bottom: 1px solid var(--border-color);
padding: 0.75rem 1.5rem;
display: flex;
align-items: center;
gap: 1rem;
}
.cell-ref {
font-weight: 600;
color: var(--text-primary);
min-width: 60px;
font-size: 0.875rem;
}
.formula-input {
flex: 1;
padding: 0.5rem;
border: 1px solid var(--border-color);
border-radius: 4px;
font-family: 'Consolas', 'Monaco', monospace;
font-size: 0.875rem;
}
.spreadsheet-container {
flex: 1;
overflow: auto;
position: relative;
background: white;
}
.spreadsheet {
display: flex;
min-width: 100%;
position: relative;
}
.column-headers {
position: sticky;
left: 0;
top: 0;
z-index: 20;
background: var(--toolbar-bg);
border-bottom: 2px solid var(--border-color);
display: flex;
}
.corner-cell {
width: 40px;
height: 30px;
background: var(--toolbar-bg);
border-right: 2px solid var(--border-color);
border-bottom: 2px solid var(--border-color);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
color: var(--text-secondary);
}
.column-header {
min-width: 100px;
height: 30px;
background: var(--toolbar-bg);
border-right: 1px solid var(--border-color);
border-bottom: 2px solid var(--border-color);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
font-weight: 600;
color: var(--text-primary);
cursor: pointer;
user-select: none;
position: sticky;
top: 0;
z-index: 10;
}
.column-header:hover {
background: #e8e6e3;
}
.rows-container {
display: flex;
flex-direction: column;
}
.row {
display: flex;
position: relative;
}
.row-header {
width: 40px;
height: 25px;
background: var(--toolbar-bg);
border-right: 2px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
display: flex;
align-items: center;
justify-content: center;
font-size: 0.75rem;
color: var(--text-secondary);
position: sticky;
left: 0;
z-index: 9;
cursor: pointer;
}
.row-header:hover {
background: #e8e6e3;
}
.cell {
min-width: 100px;
height: 25px;
border-right: 1px solid var(--border-color);
border-bottom: 1px solid var(--border-color);
padding: 2px 6px;
font-size: 0.875rem;
color: var(--text-primary);
cursor: cell;
position: relative;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
transition: background-color 0.15s;
}
.cell:hover {
background: var(--cell-hover);
}
.cell.selected {
background: var(--cell-selected);
border: 2px solid #2188ff;
border-radius: 0;
outline: none;
}
.cell.editing {
background: var(--cell-editing);
outline: 2px solid #2188ff;
outline-offset: -2px;
}
.cell-input {
width: 100%;
height: 100%;
border: none;
outline: none;
padding: 2px 6px;
font-size: 0.875rem;
font-family: inherit;
background: transparent;
}
.resize-handle {
position: absolute;
right: -3px;
top: 0;
width: 6px;
height: 100%;
cursor: col-resize;
z-index: 100;
background: transparent;
}
.resize-handle:hover {
background: rgba(33, 136, 255, 0.3);
}
.status-bar {
background: var(--toolbar-bg);
padding: 0.5rem 1.5rem;
border-top: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
font-size: 0.75rem;
color: var(--text-secondary);
}
.status-item {
display: flex;
align-items: center;
gap: 0.5rem;
}
.zoom-controls {
display: flex;
align-items: center;
gap: 0.5rem;
}
.zoom-btn {
background: white;
border: 1px solid var(--border-color);
width: 24px;
height: 24px;
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
font-size: 0.75rem;
color: var(--text-primary);
transition: all 0.2s;
}
.zoom-btn:hover {
background: #f0f0f0;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5);
z-index: 1000;
align-items: center;
justify-content: center;
}
.modal.active {
display: flex;
}
.modal-content {
background: white;
padding: 2rem;
border-radius: 8px;
box-shadow: var(--shadow-lg);
max-width: 400px;
width: 90%;
}
.modal-header {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: 1rem;
color: var(--text-primary);
}
.modal-body {
margin-bottom: 1.5rem;
color: var(--text-secondary);
}
.modal-actions {
display: flex;
gap: 1rem;
justify-content: flex-end;
}
.btn {
padding: 0.5rem 1rem;
border-radius: 4px;
border: none;
cursor: pointer;
font-size: 0.875rem;
transition: all 0.2s;
}
.btn-cancel {
background: #f3f2f1;
color: var(--text-primary);
}
.btn-cancel:hover {
background: #e1dfdd;
}
.btn-confirm {
background: var(--secondary-color);
color: white;
}
.btn-confirm:hover {
background: #0e5d2f;
}
@media (max-width: 768px) {
.toolbar {
padding: 0.5rem;
}
.toolbar-group {
padding: 0 0.5rem;
}
.cell {
min-width: 80px;
font-size: 0.75rem;
}
.column-header {
min-width: 80px;
font-size: 0.7rem;
}
.formula-bar {
padding: 0.5rem;
}
}
</style>
</head>
<body>
<div class="app-container">
<header>
<div class="logo">
<div class="logo-icon">WS</div>
<span>WebSheet</span>
</div>
<div class="header-actions">
<span>Untitled Spreadsheet</span>
<a href="https://huggingface.co/spaces/akhaliq/anycoder" target="_blank">Built with anycoder</a>
</div>
</header>
<div class="toolbar">
<div class="toolbar-group">
<button class="toolbar-btn primary" onclick="downloadXLS()">
<span>📥</span> Download XLS
</button>
<button class="toolbar-btn" onclick="downloadCSV()">
<span>📄</span> CSV
</button>
</div>
<div class="toolbar-group">
<button class="toolbar-btn" onclick="copySelection()">
<span>📋</span> Copy
</button>
<button class="toolbar-btn" onclick="pasteSelection()">
<span>📌</span> Paste
</button>
<button class="toolbar-btn danger" onclick="clearSelection()">
<span>🗑️</span> Clear
</button>
</div>
<div class="toolbar-group">
<button class="toolbar-btn" onclick="addRow()">
<span>➕</span> Row
</button>
<button class="toolbar-btn" onclick="addColumn()">
<span>➕</span> Column
</button>
<button class="toolbar-btn" onclick="deleteRow()">
<span>➖</span> Delete Row
</button>
<button class="toolbar-btn" onclick="deleteColumn()">
<span>➖</span> Delete Column
</button>
</div>
<div class="toolbar-group">
<select class="toolbar-select" onchange="changeFontSize(this.value)">
<option value="14px">Normal</option>
<option value="12px">Small</option>
<option value="16px">Large</option>
</select>
<button class="toolbar-btn" onclick="toggleBold()">
<span>B</span>
</button>
<button class="toolbar-btn" onclick="toggleItalic()">
<span>I</span>
</button>
</div>
</div>
<div class="formula-bar">
<div class="cell-ref" id="cellRef">A1</div>
<input type="text" class="formula-input" id="formulaInput" placeholder="Enter data or formula" onkeyup="updateCellFromFormula()">
</div>
<div class="spreadsheet-container">
<div class="spreadsheet" id="spreadsheet">
<div class="column-headers">
<div class="corner-cell"></div>
</div>
<div class="rows-container" id="rowsContainer">
</div>
</div>
</div>
<div class="status-bar">
<div class="status-item">
<span>Ready</span>
</div>
<div class="zoom-controls">
<button class="zoom-btn" onclick="zoomOut()">−</button>
<span id="zoomLevel">100%</span>
<button class="zoom-btn" onclick="zoomIn()">+</button>
</div>
</div>
</div>
<div class="modal" id="confirmModal">
<div class="modal-content">
<div class="modal-header">Confirm Action</div>
<div class="modal-body" id="modalMessage">Are you sure?</div>
<div class="modal-actions">
<button class="btn btn-cancel" onclick="closeModal()">Cancel</button>
<button class="btn btn-confirm" onclick="confirmAction()">Confirm</button>
</div>
</div>
</div>
<script>
let selectedCell = null;
let editingCell = null;
let currentZoom = 100;
let clipboardData = null;
let spreadsheetData = {};
let numRows = 100;
let numCols = 26;
function initSpreadsheet() {
const spreadsheet = document.getElementById('spreadsheet');
const rowsContainer = document.getElementById('rowsContainer');
// Create column headers
const columnHeaders = spreadsheet.querySelector('.column-headers');
for (let i = 0; i < numCols; i++) {
const header = document.createElement('div');
header.className = 'column-header';
header.textContent = String.fromCharCode(65 + i);
header.onclick = () => selectColumn(i);
columnHeaders.appendChild(header);
}
// Create rows and cells
for (let row = 0; row < numRows; row++) {
const rowDiv = document.createElement('div');
rowDiv.className = 'row';
const rowHeader = document.createElement('div');
rowHeader.className = 'row-header';
rowHeader.textContent = row + 1;
rowHeader.onclick = () => selectRow(row);
rowDiv.appendChild(rowHeader);
for (let col = 0; col < numCols; col++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.id = `cell-${row}-${col}`;
cell.onclick = () => selectCell(row, col);
cell.ondblclick = () => startEditCell(row, col);
cell.onkeydown = (e) => handleCellKeydown(e, row, col);
cell.contentEditable = false;
rowDiv.appendChild(cell);
}
rowsContainer.appendChild(rowDiv);
}
// Add resize handles to column headers
document.querySelectorAll('.column-header').forEach((header, index) => {
const handle = document.createElement('div');
handle.className = 'resize-handle';
handle.onmousedown = (e) => startResize(e, index);
header.appendChild(handle);
});
// Select first cell by default
selectCell(0, 0);
}
function selectCell(row, col) {
// Remove previous selection
document.querySelectorAll('.cell.selected').forEach(cell => {
cell.classList.remove('selected');
});
// Add selection to new cell
const cell = document.getElementById(`cell-${row}-${col}`);
cell.classList.add('selected');
selectedCell = { row, col };
// Update cell reference
updateCellRef(row, col);
// Update formula bar
const cellKey = `${row}-${col}`;
const formulaInput = document.getElementById('formulaInput');
formulaInput.value = spreadsheetData[cellKey] || '';
}
function startEditCell(row, col) {
const cell = document.getElementById(`cell-${row}-${col}`);
cell.classList.add('editing');
cell.contentEditable = true;
cell.focus();
// Select all text
const range = document.createRange();
range.selectNodeContents(cell);
const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
editingCell = { row, col };
}
function finishEditCell() {
if (!editingCell) return;
const cell = document.getElementById(`cell-${editingCell.row}-${editingCell.col}`);
const value = cell.textContent;
// Save data
const cellKey = `${editingCell.row}-${editingCell.col}`;
if (value) {
spreadsheetData[cellKey] = value;
} else {
delete spreadsheetData[cellKey];
}
cell.contentEditable = false;
cell.classList.remove('editing');
editingCell = null;
}
function handleCellKeydown(e, row, col) {
if (e.key === 'Enter') {
e.preventDefault();
if (editingCell) {
finishEditCell();
} else {
startEditCell(row, col);
}
} else if (e.key === 'Tab') {
e.preventDefault();
if (col < numCols - 1) {
selectCell(row, col + 1);
} else if (row < numRows - 1) {
selectCell(row + 1, 0);
}
} else if (e.key === 'ArrowUp' && !editingCell) {
e.preventDefault();
if (row > 0) selectCell(row - 1, col);
} else if (e.key === 'ArrowDown' && !editingCell) {
e.preventDefault();
if (row < numRows - 1) selectCell(row + 1, col);
} else if (e.key === 'ArrowLeft' && !editingCell) {
e.preventDefault();
if (col > 0) selectCell(row, col - 1);
} else if (e.key === 'ArrowRight' && !editingCell) {
e.preventDefault();
if (col < numCols - 1) selectCell(row, col + 1);
} else if (e.key === 'Delete' || e.key === 'Backspace') {
if (!editingCell) {
e.preventDefault();
clearCell(row, col);
}
}
}
function updateCellRef(row, col) {
const colLetter = String.fromCharCode(65 + col);
document.getElementById('cellRef').textContent = `${colLetter}${row + 1}`;
}
function updateCellFromFormula() {
if (!selectedCell) return;
const formulaInput = document.getElementById('formulaInput');
const cell = document.getElementById(`cell-${selectedCell.row}-${selectedCell.col}`);
const cellKey = `${selectedCell.row}-${selectedCell.col}`;
if (formulaInput.value) {
spreadsheetData[cellKey] = formulaInput.value;
cell.textContent = formulaInput.value;
} else {
delete spreadsheetData[cellKey];
cell.textContent = '';
}
}
function downloadXLS() {
const ws_data = [];
// Create header row
const header = [''];
for (let i = 0; i < numCols; i++) {
header.push(String.fromCharCode(65 + i));
}
ws_data.push(header);
// Create data rows
for (let row = 0; row < numRows; row++) {
const rowData = [row + 1];
for (let col = 0; col < numCols; col++) {
const cellKey = `${row}-${col}`;
rowData.push(spreadsheetData[cellKey] || '');
}
ws_data.push(rowData);
}
// Create worksheet
const ws = XLSX.utils.aoa_to_sheet(ws_data);
// Create workbook
const wb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(wb, ws, "Sheet1");
// Generate and download XLS file
XLSX.writeFile(wb, "websheet_export.xls");
}
function downloadCSV() {
let csv = '';
for (let row = 0; row < numRows; row++) {
const rowData = [];
for (let col = 0; col < numCols; col++) {
const cellKey = `${row}-${col}`;
const value = spreadsheetData[cellKey] || '';
rowData.push(`"${value}"`);
}
csv += rowData.join(',') + '\n';
}
const blob = new Blob([csv], { type: 'text/csv' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'websheet_export.csv';
a.click();
window.URL.revokeObjectURL(url);
}
function copySelection() {
if (!selectedCell) return;
const cellKey = `${selectedCell.row}-${selectedCell.col}`;
clipboardData = spreadsheetData[cellKey] || '';
// Also copy to system clipboard
navigator.clipboard.writeText(clipboardData);
}
function pasteSelection() {
if (!selectedCell || !clipboardData) return;
const cell = document.getElementById(`cell-${selectedCell.row}-${selectedCell.col}`);
const cellKey = `${selectedCell.row}-${selectedCell.col}`;
spreadsheetData[cellKey] = clipboardData;
cell.textContent = clipboardData;
document.getElementById('formulaInput').value = clipboardData;
}
function clearSelection() {
if (!selectedCell) return;
clearCell(selectedCell.row, selectedCell.col);
}
function clearCell(row, col) {
const cell = document.getElementById(`cell-${row}-${col}`);
const cellKey = `${row}-${col}`;
delete spreadsheetData[cellKey];
cell.textContent = '';
document.getElementById('formulaInput').value = '';
}
function addRow() {
const rowsContainer = document.getElementById('rowsContainer');
const newRow = document.createElement('div');
newRow.className = 'row';
const rowHeader = document.createElement('div');
rowHeader.className = 'row-header';
rowHeader.textContent = numRows + 1;
rowHeader.onclick = () => selectRow(numRows);
newRow.appendChild(rowHeader);
for (let col = 0; col < numCols; col++) {
const cell = document.createElement('div');
cell.className = 'cell';
cell.id = `cell-${numRows}-${col}`;
cell.onclick = () => selectCell(numRows, col);
cell.ondblclick = () => startEditCell(numRows, col);
cell.onkeydown = (e) => handleCellKeydown(e, numRows, col);
cell.contentEditable = false;
newRow.appendChild(cell);
}
rowsContainer.appendChild(newRow);
numRows++;
}
function addColumn() {
if (numCols >= 26) {
alert('Maximum columns reached');
return;
}
const columnHeaders = document.querySelector('.column-headers');
const header = document.createElement('div');
header.className = 'column-header';
header.textContent = String.fromCharCode(65 + numCols);
header.onclick = () => selectColumn(numCols);
const handle = document.createElement('div');
handle.className = 'resize-handle';
handle.onmousedown = (e) => startResize(e, numCols);
header.appendChild(handle);
columnHeaders.appendChild(header);
// Add cells to each row
document.querySelectorAll('.row').forEach((row, index) => {
const cell = document.createElement('div');
cell.className = 'cell';
cell.id = `cell-${index}-${numCols}`;
cell.onclick = () => selectCell(index, numCols);
cell.ondblclick = () => startEditCell(index, numCols);
cell.onkeydown = (e) => handleCellKeydown(e, index, numCols);
cell.contentEditable = false;
row.appendChild(cell);
});
numCols++;
}
function deleteRow() {
if (!selectedCell) return;
const row = selectedCell.row;
const rows = document.querySelectorAll('.row');
if (rows[row]) {
rows[row].remove();
// Update data
Object.keys(spreadsheetData).forEach(key => {
const [r, c] = key.split('-').map(Number);
if (r === row) {
delete spreadsheetData[key];
} else if (r > row) {
spreadsheetData[`${r-1}-${c}`] = spreadsheetData[key];
delete spreadsheetData[key];
}
});
// Re-select first cell
selectCell(0, 0);
}
}
function deleteColumn() {
if (!selectedCell) return;
const col = selectedCell.col;
// Update data
Object.keys(spreadsheetData).forEach(key => {
const [r, c] = key.split('-').map(Number);
if (c === col) {
delete spreadsheetData[key];
} else if (c > col) {
spreadsheetData[`${r}-${c-1}`] = spreadsheetData[key];
delete spreadsheetData[key];
}
});
// Remove column header
const headers = document.querySelectorAll('.column-header');
if (headers[col]) headers[col].remove();
// Remove cells
document.querySelectorAll('.row').forEach(row => {
const cells = row.querySelectorAll('.cell');
if (cells[col]) cells[col].remove();
});
numCols--;
// Re-select first cell
selectCell(0, 0);
}
function selectColumn(col) {
document.querySelectorAll('.cell').forEach(cell => {
cell.classList.remove('selected');
});
for (let row = 0; row < numRows; row++) {
const cell = document.getElementById(`cell-${row}-${col}`);
if (cell) cell.classList.add('selected');
}
}
function selectRow(row) {
document.querySelectorAll('.cell').forEach(cell => {
cell.classList.remove('selected');
});
const cells = document.querySelectorAll(`#cell-${row}-0`).forEach(cell => {
const cells = cell.parentElement.querySelectorAll('.cell');
cells.forEach(c => c.classList.add('selected'));
});
}
function changeFontSize(size) {
document.querySelectorAll('.cell').forEach(cell => {
cell.style.fontSize = size;
});
}
function toggleBold() {
if (!selectedCell) return;
const cell = document.getElementById(`cell-${selectedCell.row}-${selectedCell.col}`);
cell.style.fontWeight = cell.style.fontWeight === 'bold' ? 'normal' : 'bold';
}
function toggleItalic() {
if (!selectedCell) return;
const cell = document.getElementById(`cell-${selectedCell.row}-${selectedCell.col}`);
cell.style.fontStyle = cell.style.fontStyle === 'italic' ? 'normal' : 'italic';
}
function zoomIn() {
if (currentZoom < 150) {
currentZoom += 10;
updateZoom();
}
}
function zoomOut() {
if (currentZoom > 50) {
currentZoom -= 10;
updateZoom();
}
}
function updateZoom() {
const spreadsheet = document.getElementById('spreadsheet');
spreadsheet.style.transform = `scale(${currentZoom / 100})`;
spreadsheet.style.transformOrigin = 'top left';
document.getElementById('zoomLevel').textContent = `${currentZoom}%`;
}
function startResize(e, colIndex) {
e.preventDefault();
e.stopPropagation();
const startX = e.clientX;
const header = e.target.parentElement;
const startWidth = header.offsetWidth;
function handleMouseMove(e) {
const newWidth = startWidth + (e.clientX - startX);
if (newWidth > 50) {
header.style.width = newWidth + 'px';
// Update all cells in this column
document.querySelectorAll('.row').forEach((row, index) => {
const cell = document.getElementById(`cell-${index}-${colIndex}`);
if (cell) cell.style.width = newWidth + 'px';
});
}
}
function handleMouseUp() {
document.removeEventListener('mousemove', handleMouseMove);
document.removeEventListener('mouseup', handleMouseUp);
}
document.addEventListener('mousemove', handleMouseMove);
document.addEventListener('mouseup', handleMouseUp);
}
function closeModal() {
document.getElementById('confirmModal').classList.remove('active');
}
function confirmAction() {
closeModal();
}
// Initialize on load
document.addEventListener('DOMContentLoaded', () => {
initSpreadsheet();
// Global click handler to finish editing
document.addEventListener('click', (e) => {
if (editingCell && !e.target.classList.contains('cell')) {
finishEditCell();
}
});
// Keyboard shortcuts
document.addEventListener('keydown', (e) => {
if (e.ctrlKey || e.metaKey) {
switch(e.key) {
case 's':
e.preventDefault();
downloadXLS();
break;
case 'c':
e.preventDefault();
copySelection();
break;
case 'v':
e.preventDefault();
pasteSelection();
break;
}
}
});
});
</script>
</body>
</html>