CoolFace
Apppublic

KEXEL/git

sourceHugging Faceupdated 1mo agoView on Hugging Face
0likes
excel-file-reader-editor.html595 linesDownload Raw Back to root
1<!DOCTYPE html>2<html lang="pt-br">3 4<head>5  <meta charset="UTF-8">6  <meta name="viewport" content="width=device-width, initial-scale=1.0">7  <title>XLSX File Reader & Editor</title>8  <!-- Bootstrap 5 CSS -->9  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css" rel="stylesheet">10  <!-- Bootstrap Icons -->11  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1/font/bootstrap-icons.css">12  <!-- XLSX Library -->13  <script src="https://cdn.jsdelivr.net/npm/xlsx@0.18.5/dist/xlsx.full.min.js"></script>14  <!-- FileSaver.js -->15  <script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>16  <style>17    .dropzone {18      border: 2px dashed #0d6efd;19      transition: all 0.3s ease;20      cursor: pointer;21    }22 23    .dropzone.active {24      border-color: #198754;25      background-color: rgba(25, 135, 84, 0.05);26    }27 28    .table-container {29      /*max-height: 70vh;*/30      overflow-y: auto;31    }32 33    .editable-cell {34      min-width: 120px;35      border: 1px solid #dee2e6;36      padding: 0.5rem;37    }38 39    .editable-cell:focus {40      outline: 2px solid #0d6efd;41      background-color: rgba(13, 110, 253, 0.1);42    }43 44    .sheet-tab {45      cursor: pointer;46      padding: 0.5rem 1rem;47      border-radius: 0.375rem;48      margin-right: 0.5rem;49      background-color: #f8f9fa;50      transition: all 0.2s ease;51    }52 53    .sheet-tab:hover {54      background-color: #e9ecef;55    }56 57    .sheet-tab.active {58      background-color: #0d6efd;59      color: white;60    }61 62    .file-info {63      background-color: #f8f9fa;64      border-radius: 0.375rem;65      padding: 1rem;66    }67 68    .how-to-use-card {69      height: 100%;70    }71  </style>72</head>73 74<body class="bg-light">75  <div class="container py-5">76  <div class="text-center mb-5">77    <h1 class="display-5 fw-bold text-dark mb-3">Excel File Reader & Editor</h1>78    <p class="lead text-muted">Upload, view, edit and export Excel files directly in your browser</p>79  </div>80 81  <div class="shadow-sm mb-5">82    <div class="">83      <div class="row">84        85        <!-- File Upload Section -->86        <div class="col-md">87          <div id="dropzone" class="dropzone rounded-0 p-3 text-center mb-4">88            <div class="d-flex flex-column align-items-center justify-content-center">89              <i class="bi bi-file-earmark-excel text-primary fs-1 mb-3"></i>90              <p class="text-muted mb-2">Drag & drop your Excel file here</p>91              <p class="text-muted small mb-3">or</p>92              <!--<label for="fileInput" class="btn btn-primary">93                <i class="bi bi-upload me-2"></i> Browse Files94              </label>-->95              <input type="file" id="fileInput" class="d-none" accept=".xlsx, .xls, .csv" />96            </div>97          </div>98 99          100        </div>101        <div class="col-md-3">102            <h5 class="fw-bold mb-3">File Information</h5>103            <div class="file-info">104              <div class="d-flex align-items-center mb-2">105                <i class="bi bi-file-earmark text-muted me-2"></i>106                <span id="fileName" class="text-dark">No file selected</span>107              </div>108              <div class="d-flex align-items-center mb-2">109                <i class="bi bi-collection text-muted me-2"></i>110                <span id="sheetCount" class="text-dark">0 sheets</span>111              </div>112              <div class="d-flex align-items-center">113                <i class="bi bi-table text-muted me-2"></i>114                <span id="rowCount" class="text-dark">0 rows</span>115              </div>116            </div>117          </div>118        119 120        <!-- Sheet Navigation -->121        <div class="col-ms">122          <div id="sheetTabs" class="d-flex overflow-auto py-2 mb-3">123            <!-- Sheets will be added here dynamically -->124          </div>125 126          <!-- Table Container -->127          <div id="tableContainer" class="table-container border rounded-0 overflow-hidden">128            <div class="text-center py-5 text-muted" id="emptyState">129              <i class="bi bi-file-earmark-excel display-4 opacity-25 mb-3"></i>130              <p class="h5">Upload an Excel file to get started</p>131            </div>132            <table id="dataTable" class="table table-bordered m-0 d-none overflow-auto">133              <!-- Table content will be generated dynamically -->134            </table>135          </div>136 137          <!-- Action Buttons -->138          <div class="d-flex flex-wrap gap-2 mt-4">139            <button id="exportBtn" class="btn btn-success" disabled>140              <i class="bi bi-download me-2"></i> Export Excel141            </button>142            <button id="addRowBtn" class="btn btn-primary" disabled>143              <i class="bi bi-plus me-2"></i> Add Row144            </button>145            <button id="addColBtn" class="btn btn-primary" disabled>146              <i class="bi bi-plus me-2"></i> Add Column147            </button>148            <button id="resetBtn" class="btn btn-secondary">149              <i class="bi bi-arrow-counterclockwise me-2"></i> Reset150            </button>151          </div>152        </div>153      </div>154    </div>155  </div>156 157  <!-- Instructions -->158  <div class="card shadow-sm">159    <div class="card-body p-4">160      <h2 class="h4 fw-bold mb-4">How to use</h2>161      <div class="row g-4">162        <div class="col-md-4">163          <div class="card bg-primary bg-opacity-10 how-to-use-card">164            <div class="card-body">165              <div class="d-flex align-items-center mb-3">166                <div class="bg-primary bg-opacity-25 p-2 rounded-circle me-3">167                  <i class="bi bi-upload text-primary"></i>168                </div>169                <h3 class="h6 fw-bold mb-0 text-primary">Upload</h3>170              </div>171              <p class="card-text text-muted">Drag & drop or click to upload your Excel file (.xlsx, .xls, .csv)</p>172            </div>173          </div>174        </div>175        <div class="col-md-4">176          <div class="card bg-success bg-opacity-10 how-to-use-card">177            <div class="card-body">178              <div class="d-flex align-items-center mb-3">179                <div class="bg-success bg-opacity-25 p-2 rounded-circle me-3">180                  <i class="bi bi-pencil text-success"></i>181                </div>182                <h3 class="h6 fw-bold mb-0 text-success">Edit</h3>183              </div>184              <p class="card-text text-muted">Click on any cell to edit its content. Add/remove rows and columns as needed.</p>185            </div>186          </div>187        </div>188        <div class="col-md-4">189          <div class="card bg-info bg-opacity-10 how-to-use-card">190            <div class="card-body">191              <div class="d-flex align-items-center mb-3">192                <div class="bg-info bg-opacity-25 p-2 rounded-circle me-3">193                  <i class="bi bi-download text-info"></i>194                </div>195                <h3 class="h6 fw-bold mb-0 text-info">Export</h3>196              </div>197              <p class="card-text text-muted">Download your edited file back to Excel format when you're done.</p>198            </div>199          </div>200        </div>201      </div>202    </div>203  </div>204</div>205 206  <!-- Bootstrap 5 JS Bundle with Popper -->207  <script src="https://cdn.jsdelivr.net/npm/bootstrap@5/dist/js/bootstrap.bundle.min.js"></script>208 209  <script>210    document.addEventListener("DOMContentLoaded", function () {211  // DOM Elements212  const fileInput = document.getElementById("fileInput");213  const dropzone = document.getElementById("dropzone");214  const fileName = document.getElementById("fileName");215  const sheetCount = document.getElementById("sheetCount");216  const rowCount = document.getElementById("rowCount");217  const tableContainer = document.getElementById("tableContainer");218  const dataTable = document.getElementById("dataTable");219  const emptyState = document.getElementById("emptyState");220  const sheetTabs = document.getElementById("sheetTabs");221  const exportBtn = document.getElementById("exportBtn");222  const addRowBtn = document.getElementById("addRowBtn");223  const addColBtn = document.getElementById("addColBtn");224  const resetBtn = document.getElementById("resetBtn");225 226  // Global variables227  let workbook = null;228  let currentSheetName = "";229  let sheetData = [];230  let headers = [];231 232  // Event Listeners233  fileInput.addEventListener("change", handleFileSelect);234  dropzone.addEventListener("click", () => fileInput.click());235  dropzone.addEventListener("dragover", handleDragOver);236  dropzone.addEventListener("dragleave", handleDragLeave);237  dropzone.addEventListener("drop", handleDrop);238  exportBtn.addEventListener("click", exportToExcel);239  addRowBtn.addEventListener("click", addNewRow);240  addColBtn.addEventListener("click", addNewColumn);241  resetBtn.addEventListener("click", resetApp);242 243  // Functions244  function handleFileSelect(e) {245    const file = e.target.files[0];246    if (!file) return;247 248    processExcelFile(file);249  }250 251  function handleDragOver(e) {252    e.preventDefault();253    e.stopPropagation();254    dropzone.classList.add("active");255  }256 257  function handleDragLeave(e) {258    e.preventDefault();259    e.stopPropagation();260    dropzone.classList.remove("active");261  }262 263  function handleDrop(e) {264    e.preventDefault();265    e.stopPropagation();266    dropzone.classList.remove("active");267 268    const file = e.dataTransfer.files[0];269    if (!file) return;270 271    processExcelFile(file);272  }273 274  function processExcelFile(file) {275    fileName.textContent = file.name;276 277    const reader = new FileReader();278    reader.onload = function (e) {279      const data = new Uint8Array(e.target.result);280      workbook = XLSX.read(data, { type: "array" });281 282      updateSheetInfo();283      renderSheetTabs();284      loadFirstSheet();285      enableButtons();286    };287    reader.readAsArrayBuffer(file);288  }289 290  function updateSheetInfo() {291    if (!workbook) return;292 293    sheetCount.textContent = `${workbook.SheetNames.length} sheet${294      workbook.SheetNames.length !== 1 ? "s" : ""295    }`;296  }297 298  function renderSheetTabs() {299    if (!workbook) return;300 301    sheetTabs.innerHTML = "";302    workbook.SheetNames.forEach((sheetName) => {303      const tab = document.createElement("div");304      tab.className = "sheet-tab";305      tab.textContent = sheetName;306      tab.addEventListener("click", () => switchSheet(sheetName));307 308      if (sheetName === workbook.SheetNames[0]) {309        tab.classList.add("active");310      }311 312      sheetTabs.appendChild(tab);313    });314  }315 316  function switchSheet(sheetName) {317    if (!workbook || currentSheetName === sheetName) return;318 319    // Update active tab320    document.querySelectorAll(".sheet-tab").forEach((tab) => {321      tab.classList.remove("active");322      if (tab.textContent === sheetName) {323        tab.classList.add("active");324      }325    });326 327    currentSheetName = sheetName;328    loadSheetData();329    renderTable();330  }331 332  function loadFirstSheet() {333    if (!workbook || workbook.SheetNames.length === 0) return;334 335    currentSheetName = workbook.SheetNames[0];336    loadSheetData();337    renderTable();338  }339 340  function loadSheetData() {341    if (!workbook || !currentSheetName) return;342 343    const worksheet = workbook.Sheets[currentSheetName];344    sheetData = XLSX.utils.sheet_to_json(worksheet, { header: 1, defval: "" });345 346    if (sheetData.length > 0) {347      headers = sheetData[0];348      rowCount.textContent = `${sheetData.length - 1} row${349        sheetData.length - 1 !== 1 ? "s" : ""350      }`;351    } else {352      headers = [];353      rowCount.textContent = "0 rows";354    }355  }356 357  function renderTable() {358    if (!sheetData || sheetData.length === 0) {359      emptyState.classList.remove("d-none");360      dataTable.classList.add("d-none");361      return;362    }363 364    emptyState.classList.add("d-none");365    dataTable.classList.remove("d-none");366 367    // Clear existing table368    dataTable.innerHTML = "";369 370    // Create header row371    const thead = document.createElement("thead");372    const headerRow = document.createElement("tr");373    headerRow.className = "table-light";374 375    // Add empty cell for corner376    const cornerCell = document.createElement("th");377    cornerCell.className = "text-center";378    cornerCell.style.padding = "0px 45px";379    headerRow.appendChild(cornerCell);380 381    // Add column headers382    headers.forEach((header, colIndex) => {383      const th = document.createElement("th");384      th.className = "text-nowrap";385      th.textContent = header || `Column ${colIndex + 1}`;386 387      // Add delete column button388      const deleteBtn = document.createElement("button");389      deleteBtn.className = "btn btn-sm btn-link text-danger ms-2 p-0";390      deleteBtn.innerHTML = '<i class="bi bi-x"></i>';391      deleteBtn.addEventListener("click", () => deleteColumn(colIndex));392 393      th.appendChild(deleteBtn);394      headerRow.appendChild(th);395    });396 397    // Add new column header398    const newColHeader = document.createElement("th");399    newColHeader.className = "text-center";400    newColHeader.style.width = "50px";401 402    const addColBtn = document.createElement("button");403    addColBtn.className = "btn btn-sm btn-link text-primary p-0";404    addColBtn.innerHTML = '<i class="bi bi-plus"></i>';405    addColBtn.addEventListener("click", addNewColumn);406 407    newColHeader.appendChild(addColBtn);408    headerRow.appendChild(newColHeader);409 410    thead.appendChild(headerRow);411    dataTable.appendChild(thead);412 413    // Create table body414    const tbody = document.createElement("tbody");415 416    // Add data rows417    for (let rowIndex = 1; rowIndex < sheetData.length; rowIndex++) {418      const row = document.createElement("tr");419 420      // Add row number cell421      const rowNumCell = document.createElement("td");422      rowNumCell.className = "text-center text-muted";423      rowNumCell.textContent = rowIndex;424 425      // Add delete row button426      const deleteRowBtn = document.createElement("button");427      deleteRowBtn.className = "btn btn-sm btn-link text-danger ms-2 p-0";428      deleteRowBtn.innerHTML = '<i class="bi bi-x"></i>';429      deleteRowBtn.addEventListener("click", () => deleteRow(rowIndex));430 431      rowNumCell.appendChild(deleteRowBtn);432      row.appendChild(rowNumCell);433 434      // Add data cells435      for (let colIndex = 0; colIndex < headers.length; colIndex++) {436        const cell = document.createElement("td");437        cell.className = "editable-cell";438        cell.contentEditable = true;439 440        // Set cell value (handle cases where row might be shorter than headers)441        const cellValue =442          sheetData[rowIndex][colIndex] !== undefined443            ? sheetData[rowIndex][colIndex]444            : "";445        cell.textContent = cellValue;446 447        // Add event listener to save changes448        cell.addEventListener("blur", () => {449          if (!sheetData[rowIndex]) {450            sheetData[rowIndex] = new Array(headers.length).fill("");451          }452          sheetData[rowIndex][colIndex] = cell.textContent;453        });454 455        row.appendChild(cell);456      }457 458      // Add empty cell for new column459      const newColCell = document.createElement("td");460      newColCell.className = "text-center";461      row.appendChild(newColCell);462 463      tbody.appendChild(row);464    }465 466    // Add new row button467    const newRow = document.createElement("tr");468    const newRowCell = document.createElement("td");469    newRowCell.colSpan = headers.length + 2;470    newRowCell.className = "text-center py-3";471 472    const addRowBtn = document.createElement("button");473    addRowBtn.className = "btn btn-sm btn-primary";474    addRowBtn.innerHTML = '<i class="bi bi-plus me-2"></i>Add Row';475    addRowBtn.addEventListener("click", addNewRow);476 477    newRowCell.appendChild(addRowBtn);478    newRow.appendChild(newRowCell);479    tbody.appendChild(newRow);480 481    dataTable.appendChild(tbody);482  }483 484  function addNewRow() {485    if (!sheetData) return;486 487    const newRow = new Array(headers.length).fill("");488    sheetData.push(newRow);489    rowCount.textContent = `${sheetData.length - 1} row${490      sheetData.length - 1 !== 1 ? "s" : ""491    }`;492    renderTable();493  }494 495  function addNewColumn() {496    if (!headers) return;497 498    const newHeader = `Column ${headers.length + 1}`;499    headers.push(newHeader);500 501    // Add empty value for the new column in each row502    for (let i = 0; i < sheetData.length; i++) {503      sheetData[i].push("");504    }505 506    renderTable();507  }508 509  function deleteRow(rowIndex) {510    if (!sheetData || rowIndex < 1 || rowIndex >= sheetData.length) return;511 512    sheetData.splice(rowIndex, 1);513    rowCount.textContent = `${sheetData.length - 1} row${514      sheetData.length - 1 !== 1 ? "s" : ""515    }`;516    renderTable();517  }518 519  function deleteColumn(colIndex) {520    if (!headers || colIndex < 0 || colIndex >= headers.length) return;521 522    headers.splice(colIndex, 1);523 524    // Remove the column from each row525    for (let i = 0; i < sheetData.length; i++) {526      if (sheetData[i].length > colIndex) {527        sheetData[i].splice(colIndex, 1);528      }529    }530 531    renderTable();532  }533 534  function exportToExcel() {535    if (!workbook || !currentSheetName) return;536 537    // Update the current sheet with edited data538    const worksheet = XLSX.utils.aoa_to_sheet(sheetData);539    workbook.Sheets[currentSheetName] = worksheet;540 541    // Generate Excel file542    const excelBuffer = XLSX.write(workbook, {543      bookType: "xlsx",544      type: "array"545    });546    const blob = new Blob([excelBuffer], {547      type: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"548    });549 550    // Suggest a filename551    let exportName = "edited_" + (fileName.textContent || "spreadsheet");552    if (!exportName.endsWith(".xlsx")) {553      exportName += ".xlsx";554    }555 556    // Save the file557    saveAs(blob, exportName);558  }559 560  function resetApp() {561    // Reset UI562    fileName.textContent = "No file selected";563    sheetCount.textContent = "0 sheets";564    rowCount.textContent = "0 rows";565 566    emptyState.classList.remove("d-none");567    dataTable.classList.add("d-none");568    sheetTabs.innerHTML = "";569 570    // Reset data571    workbook = null;572    currentSheetName = "";573    sheetData = [];574    headers = [];575 576    // Disable buttons577    exportBtn.disabled = true;578    addRowBtn.disabled = true;579    addColBtn.disabled = true;580 581    // Reset file input582    fileInput.value = "";583  }584 585  function enableButtons() {586    exportBtn.disabled = false;587    addRowBtn.disabled = false;588    addColBtn.disabled = false;589  }590});591 592  </script>593</body>594 595</html>