diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..fc334da
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,11 @@
+{
+ "files.exclude": {
+ "**/.git": true,
+ "**/.svn": true,
+ "**/.hg": true,
+ "**/CVS": true,
+ "**/.DS_Store": true,
+ "**/Thumbs.db": true
+ },
+ "hide-files.files": []
+}
diff --git a/assets/favicon.ico b/assets/favicon.ico
new file mode 100644
index 0000000..d6600e8
Binary files /dev/null and b/assets/favicon.ico differ
diff --git a/css/style.css b/css/style.css
new file mode 100644
index 0000000..3e90970
--- /dev/null
+++ b/css/style.css
@@ -0,0 +1,282 @@
+@import url("https://fonts.googleapis.com/css2?family=Caveat:wght@400;700&family=Lobster&family=Pacifico&family=Roboto:ital,wght@1,100;1,400;1,700&display=swap");
+
+/* Default styling */
+* {
+ padding: 0;
+ margin: 0;
+ /* font-size: 62.5%; */
+ box-sizing: border-box;
+}
+
+/* utility class */
+.fix-height {
+ height: 3rem;
+}
+option[value="Arial"]{
+ font-family: 'Arial';
+}
+option[value="Caveat"]{
+ font-family: 'Caveat';
+
+}
+option[value="Impact"]{
+ font-family: 'Impact';
+}
+option[value="Lobster"]{
+ font-family: 'Lobster';
+}
+option[value="monospace"]{
+ font-family: 'monospace';
+}
+option[value="Pacifico"]{
+ font-family: 'Pacifico';
+}
+option[value="Roboto"]{
+ font-family: 'Roboto';
+}
+option[value="Courier New"]{
+ font-family: 'Courier New';
+}
+option[value="Segoe"]{
+ font-family: 'Segoe';
+}
+option[value="Times New Roman"]{
+ font-family: 'Times New Roman';
+}
+option[value="serif"]{
+ font-family: 'serif';
+}
+option[value="Tahoma"]{
+ font-family: 'Tahoma';
+}
+option[value="sans-serif"]{
+ font-family: 'sans-serif';
+}
+option[value="Trebuchet"]{
+ font-family: 'Trebuchet';
+}
+option[value="Geneva"]{
+ font-family: 'Geneva';
+}
+
+/* Menu-Bar style */
+.page-actions-cont {
+ background-color: #218c74;
+ display: flex;
+ align-items: flex-end;
+}
+.page-action {
+ width: 3.5rem;
+ height: 2rem;
+ text-align: center;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ color: #f1f2f6;
+}
+
+/* Tool-Bar style */
+.cellprops-action-cont {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ background-color: #ecf0f1;
+ padding-left: 1rem;
+}
+.cellprops-action-cont > * {
+ display: inline-block;
+ margin-right: 1rem;
+}
+.cellprops-action-cont > *:hover {
+ cursor: pointer;
+}
+.cellprops-action-cont > div > *:hover {
+ cursor: pointer;
+}
+.font-family-prop,
+.font-size-prop {
+ padding: 0.2rem;
+ border: none;
+ border-radius: 3px;
+ outline: none;
+}
+.color-prop {
+ position: relative;
+}
+.color-prop > input {
+ opacity: 0;
+ position: absolute;
+ top: 0;
+ left: 0;
+ height: 100%;
+ width: 100%;
+}
+.selected-page-action{
+ background-color: #ecf0f1;
+ color: #218c74;
+}
+
+/* Fotmula-Bar style */
+.formula-action-cont {
+ background-color: #ecf0f1;
+ display: flex;
+ padding-left: 1rem;
+ align-items: center;
+ height: 2rem;
+}
+.formula-action-cont > input {
+ border: none;
+ outline: none;
+ height: 70%;
+}
+.formula-action-cont > * {
+ display: inline-block;
+ margin-right: 0.7rem;
+}
+.formula-icon {
+ width: 1.2rem;
+}
+.address-bar {
+ width: 5rem;
+ text-align: center;
+}
+.formula-bar {
+ width: calc(100vw - 5rem - 2.1rem);
+ padding-left: 0.5rem;
+}
+
+/* Grid and Cells style */
+.grid-cont {
+ height: calc(100vh - 3rem * 3 - 2rem);
+ position: relative;
+ overflow: auto;
+ background-color: #ecf0f1;
+}
+.top-left-dummy {
+ height: 2rem;
+ width: 2rem;
+ background-color: #747d8c;
+ position: fixed;
+ z-index: 5;
+}
+
+.address-col-cont {
+ width: 2rem;
+ position: sticky;
+ top: 2rem;
+ left: 0rem;
+ background-color: #dbdddf;
+ z-index: 2;
+}
+.address-row-cont {
+ display: flex;
+ position: sticky;
+ top: 0rem;
+ left: 2rem;
+ background-color: #dbdddf;
+ z-index: 2;
+ border-top: none;
+}
+.cells-cont {
+ position: absolute;
+ top: 0rem;
+ left: 2rem;
+}
+.address-col {
+ height: 2rem;
+ min-width: 2rem;
+ max-width: 6rem;
+ border: 1px solid #dfe4ea;
+ text-align: center;
+}
+.address-row {
+ height: 2rem;
+ width: 10rem;
+ border: 1px solid #dfe4ea;
+ border-top: none;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+.cell {
+ height: 2rem;
+ width: 10rem;
+ border: 1px solid #dfe4ea;
+ outline: none;
+ overflow: hidden;
+ padding: 6px;
+ vertical-align: middle;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.cell:hover {
+ overflow: visible;
+}
+.row-cont {
+ display: flex;
+}
+
+/* Sheet-No style */
+.sheet-action-cont {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ padding-left: 1.5rem;
+ padding-right: 0.5rem;
+ background-color: #ecf0f1;
+}
+.sheet-action-cont > * {
+ display: inline-block;
+}
+.sheet-add-icon {
+ width: 4.1vw;
+}
+.sheet-add-icon:hover {
+ cursor: pointer;
+}
+
+.sheets-folder-cont {
+ display: flex;
+ align-items: center;
+ height: 70%;
+ width: calc(100vw - 4.1vw);
+ overflow: auto;
+}
+.sheet-folder {
+ height: 80%;
+ width: 5rem;
+ font-weight: bold;
+}
+.sheet-folder:hover{
+ cursor: pointer;
+}
+.sheet-content{
+ height: 100%;
+ width: 100%;
+ text-align: center;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ text-decoration: underline;
+ text-decoration-thickness: 3px;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ padding: .3rem;
+}
+
+footer{
+ position: sticky;
+ z-index: 2;
+}
+@media screen and (max-width: 768px) {
+ .cellprops-action-cont{
+ padding: .3rem;
+ height: 4rem;
+ }
+}
+@media screen and (max-width: 425px) {
+ .cellprops-action-cont{
+ padding: .3rem;
+ height: 6rem;
+ }
+}
\ No newline at end of file
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..4a5b5bf
--- /dev/null
+++ b/index.html
@@ -0,0 +1,111 @@
+
+
+
+
+
+
+
+
+
+
+ Excel-Sheet
+
+
+
+
+
+
+
Home
+
File
+
Insert
+
Layout
+
Help
+
+
+
+
content_copy
+
content_cut
+
content_paste
+
+
+
format_bold
+
format_italic
+
format_underline
+
format_align_left
+
format_align_center
+
format_align_right
+
+ format_color_text
+
+
+
+ format_color_fill
+
+
+
cloud_download
+
cloud_upload
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/js/grid.js b/js/grid.js
new file mode 100644
index 0000000..89e512b
--- /dev/null
+++ b/js/grid.js
@@ -0,0 +1,970 @@
+const rows = 150; // No of rows
+const cols = 30; // No of columns
+
+// previous Clicked cell
+let previousClickedCell = "";
+
+// Cell border Color when click
+const cellBorderColor = "#218c74";
+const lightGray = "#dfe4ea";
+
+// Collection of whole excel-sheet database
+let collectedSheetDB = [];
+// Collection of whole sheet-cell database
+let sheetDB = [];
+
+// Copy arrays
+let copyData = [];
+
+// Range Storage
+let rangeStorage = [];
+
+// Collection of whole excel-sheet
+let collecteddGraphComponent = [];
+// Collection of whole excel-sheet
+let graphComponentMatrix = [];
+
+// Rows and Columns numbering element selection
+const addressColCont = document.querySelector(".address-col-cont");
+const addressRowCont = document.querySelector(".address-row-cont");
+const cellsCont = document.querySelector(".cells-cont");
+const addressBar = document.querySelector(".address-bar");
+
+// Rows numbering
+for (let i = 0; i < rows; i++) {
+ const addressCol = document.createElement("div");
+ addressCol.innerText = i + 1;
+ addressCol.setAttribute("class", "address-col");
+ addressColCont.appendChild(addressCol);
+}
+
+// Column numbering
+for (let i = 0; i < cols; i++) {
+ const addressRow = document.createElement("div");
+ if (i < 26) {
+ addressRow.innerText = String.fromCharCode(65 + i);
+ } else {
+ addressRow.innerText = "A" + String.fromCharCode(65 + i - 26);
+ }
+ addressRow.setAttribute("class", "address-row");
+ addressRowCont.appendChild(addressRow);
+}
+
+// Create cells
+for (let i = 0; i < rows; i++) {
+ const rowCont = document.createElement("div");
+ rowCont.setAttribute("class", "row-cont");
+ for (let j = 0; j < cols; j++) {
+ const cell = document.createElement("div");
+ cell.setAttribute("class", "cell");
+ cell.setAttribute("contenteditable", "true");
+ cell.setAttribute("spellcheck", "false");
+ cell.setAttribute("rid", i);
+ cell.setAttribute("cid", j);
+ rowCont.appendChild(cell);
+ addClickListenerForCells(cell, i + 1, j + 1);
+ addBlurEventListenerOnCell(cell);
+ }
+ cellsCont.appendChild(rowCont);
+}
+
+// Add Listener to cells and update address bar
+function addClickListenerForCells(cell, i, j) {
+ cell.addEventListener("click", (e) => {
+ if (j <= 26) {
+ addressBar.value = String.fromCharCode(64 + j) + i;
+ } else {
+ addressBar.value = "A" + String.fromCharCode(64 + j - 26) + i;
+ }
+ addListenerToAttachCellProperties(cell);
+ handleSelectedCells(cell);
+ });
+}
+
+// Default cell data
+function returnDefauldata() {
+ return {
+ bold: false,
+ italic: false,
+ underline: false,
+ alignment: "left",
+ fontFamily: "Arial",
+ fontSize: "14",
+ fontColor: "#000000",
+ BGcolor: "#ecf0f1",
+ value: "",
+ formula: "",
+ children: [],
+ };
+}
+
+//create DB and graph for new sheet
+function createSheetDB_And_createGraphComponentMatrix() {
+ const sheetDB1 = [];
+ const graphComponentMatrix1 = [];
+ for (let i = 0; i < rows; i++) {
+ const sheetRow = [];
+ const graphRow = [];
+ for (let j = 0; j < cols; j++) {
+ sheetRow.push(returnDefauldata());
+ graphRow.push([]);
+ }
+ sheetDB1.push(sheetRow);
+ graphComponentMatrix1.push(graphRow);
+ }
+ collectedSheetDB.push(sheetDB1);
+ collecteddGraphComponent.push(graphComponentMatrix1);
+}
+
+// Add blur Event listener
+let shouldCheck = true;
+function addBlurEventListenerOnCell(cell) {
+ cell.addEventListener("blur", (e) => {
+ const address = addressBar.value;
+ const [activedCell, cellprop] = getCellandCellProp(address);
+ const enterData = activedCell.innerText;
+ if (enterData[0] === "=" && shouldCheck) {
+ const inputFormula = enterData.slice(1);
+ cellAsFormulaBar(inputFormula);
+ } else {
+ cellprop.value = enterData;
+ removeChildFromParent(cellprop.formula);
+ cellprop.formula = "";
+ updateChildrenCells(address);
+ }
+ });
+}
+
+async function cellAsFormulaBar(inputFormula) {
+ if (inputFormula) {
+ const address = addressBar.value;
+ const [cell, cellProp] = getCellandCellProp(address);
+ if (inputFormula !== cellProp.formula) {
+ removeChildFromParent(cellProp.formula);
+ }
+ const exactFormula = GetExactFormula(inputFormula);
+ addChildtoGraphComponent(inputFormula, address);
+ const cycleStart = isGraphCyclic(graphComponentMatrix);
+ if (cycleStart) {
+ let isOk = confirm(
+ "There is Cyclic in cells formulas. Do you want to trace your cyclic cell path"
+ );
+ while (isOk) {
+ shouldCheck = false;
+ await isGraphCyclicTracePath(graphComponentMatrix, cycleStart);
+ isOk = confirm("Do you want to trace your cyclic again");
+ cell.innerText = "";
+ }
+ shouldCheck = true;
+ removeChildFromGraphComponent(inputFormula);
+ return;
+ }
+ const evaluatedValue = evaluatedFormula(inputFormula);
+ setCellUIAndCellProp(evaluatedValue, exactFormula, address);
+ addChildToParent(exactFormula);
+ updateChildrenCells(address);
+ }
+}
+
+// Selection of tool-bar element
+const bold = document.querySelector(".bold");
+const italic = document.querySelector(".italic");
+const underline = document.querySelector(".underline");
+const fontSize = document.querySelector(".font-size-prop");
+const fontFamily = document.querySelector(".font-family-prop");
+const fontColor = document.querySelector(".font-color-prop");
+const BGcolor = document.querySelector(".BGcolor-prop");
+const alignment = document.querySelectorAll(".alignment");
+const leftAlignment = alignment[0];
+const centerAlignment = alignment[1];
+const rightAlignment = alignment[2];
+
+// Color
+const activeColorProp = "#d1d8e0";
+const inactiveColorProp = "#ecf0f1";
+
+// Event-Listener to the all tools
+{
+ bold.addEventListener("click", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ // Change in database
+ cellprop.bold = !cellprop.bold;
+ //Channge in Cell
+ cell.style.fontWeight = cellprop.bold ? "bold" : "normal";
+ // Change in tool-bar
+ bold.style.backgroundColor = cellprop.bold
+ ? activeColorProp
+ : inactiveColorProp;
+ });
+
+ italic.addEventListener("click", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ cellprop.italic = !cellprop.italic;
+ cell.style.fontStyle = cellprop.italic ? "italic" : "normal";
+ italic.style.backgroundColor = cellprop.italic
+ ? activeColorProp
+ : inactiveColorProp;
+ });
+
+ underline.addEventListener("click", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ cellprop.underline = !cellprop.underline;
+ cell.style.textDecoration = cellprop.underline ? "underline" : "none";
+ underline.style.backgroundColor = cellprop.underline
+ ? activeColorProp
+ : inactiveColorProp;
+ });
+
+ fontSize.addEventListener("change", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ cellprop.fontSize = fontSize.value;
+ cell.style.fontSize = cellprop.fontSize + "px";
+ fontSize.value = cellprop.fontSize;
+ });
+
+ fontFamily.addEventListener("change", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ cellprop.fontFamily = fontFamily.value;
+ cell.style.fontFamily = cellprop.fontFamily;
+ fontFamily.value = cellprop.fontFamily;
+ });
+
+ fontColor.addEventListener("change", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ cellprop.fontColor = fontColor.value;
+ cell.style.color = cellprop.fontColor;
+ fontColor.value = cellprop.fontColor;
+ });
+ BGcolor.addEventListener("change", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ cellprop.BGcolor = BGcolor.value;
+ cell.style.backgroundColor = cellprop.BGcolor;
+ BGcolor.value = cellprop.BGcolor;
+ });
+
+ alignment.forEach((alignEle) => {
+ alignEle.addEventListener("click", (e) => {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+
+ const alignValue = e.target.classList[0];
+ cellprop.alignment = alignValue;
+ cell.style.textAlign = cellprop.alignment;
+
+ alignmentWork(cellprop.alignment);
+ });
+ });
+}
+
+// Restore Style of the clicked cell
+
+function addListenerToAttachCellProperties(cell) {
+ if (rangeStorage.length === 2) {
+ SelectCellborder(1, lightGray);
+ }
+ const address = addressBar.value;
+ const [rid, cid] = decodeRIDCIDfromAddress(address);
+ cell.style.border = `3px solid ${cellBorderColor}`;
+ const [prid, pcid] = decodeRIDCIDfromAddress(previousClickedCell);
+ if (previousClickedCell && (rid !== prid || cid !== pcid)) {
+ const Prevcell = document.querySelector(
+ `.cell[rid="${prid}"][cid="${pcid}"]`
+ );
+ Prevcell.style.border = `1px solid #dfe4ea`;
+ }
+ previousClickedCell = addressBar.value;
+ const cellprop = sheetDB[rid][cid];
+ cell.style.fontWeight = cellprop.bold ? "bold" : "normal";
+ cell.style.fontStyle = cellprop.italic ? "italic" : "normal";
+ cell.style.textDecoration = cellprop.underline ? "underline" : "none";
+ cell.style.fontSize = cellprop.fontSize + "px";
+ cell.style.fontFamily = cellprop.fontFamily;
+ cell.style.color = cellprop.fontColor;
+ cell.style.backgroundColor = cellprop.BGcolor;
+ cell.style.textAlign = cellprop.alignment;
+
+ bold.style.backgroundColor = cellprop.bold
+ ? activeColorProp
+ : inactiveColorProp;
+ italic.style.backgroundColor = cellprop.italic
+ ? activeColorProp
+ : inactiveColorProp;
+ underline.style.backgroundColor = cellprop.underline
+ ? activeColorProp
+ : inactiveColorProp;
+ fontSize.value = cellprop.fontSize;
+ fontFamily.value = cellprop.fontFamily;
+ fontColor.value = cellprop.fontColor;
+ BGcolor.value = cellprop.BGcolor;
+
+ alignmentWork(cellprop.alignment);
+
+ const formulaBar = document.querySelector(".formula-bar");
+ formulaBar.value = cellprop.formula;
+ cell.innerText = cellprop.value;
+}
+// Switch UI to the selected alignment icon
+function alignmentWork(cellAlignment) {
+ switch (cellAlignment) {
+ case "left":
+ leftAlignment.style.backgroundColor = activeColorProp;
+ centerAlignment.style.backgroundColor = inactiveColorProp;
+ rightAlignment.style.backgroundColor = inactiveColorProp;
+ break;
+ case "center":
+ leftAlignment.style.backgroundColor = inactiveColorProp;
+ centerAlignment.style.backgroundColor = activeColorProp;
+ rightAlignment.style.backgroundColor = inactiveColorProp;
+ break;
+ case "right":
+ leftAlignment.style.backgroundColor = inactiveColorProp;
+ centerAlignment.style.backgroundColor = inactiveColorProp;
+ rightAlignment.style.backgroundColor = activeColorProp;
+ break;
+ }
+}
+
+// Get cell and cell properties
+function getCellandCellProp(address) {
+ const [rid, cid] = decodeRIDCIDfromAddress(address);
+ const cell = document.querySelector(`.cell[rid="${rid}"][cid="${cid}"]`);
+ const cellprop = sheetDB[rid][cid];
+ return [cell, cellprop];
+}
+
+// Decode Rows and Columns
+function decodeRIDCIDfromAddress(address) {
+ let rid;
+ let cid;
+ if (
+ Number(address.charCodeAt(1)) >= 65 &&
+ Number(address.charCodeAt(1)) <= 90
+ ) {
+ rid = Number(address.slice(2)) - 1;
+ cid = Number(address.charCodeAt(1)) - 65 + 26;
+ } else {
+ rid = Number(address.slice(1)) - 1;
+ cid = Number(address.charCodeAt(0)) - 65;
+ }
+ return [rid, cid];
+}
+
+const formulaBar = document.querySelector(".formula-bar");
+formulaBar.addEventListener("keydown", async (e) => {
+ const inputFormula = formulaBar.value;
+ if (e.key === "Enter" && inputFormula) {
+ const address = addressBar.value;
+ const [, cellProp] = getCellandCellProp(address);
+ if (inputFormula !== cellProp.formula) {
+ removeChildFromParent(cellProp.formula);
+ }
+ const exactFormula = GetExactFormula(inputFormula);
+ addChildtoGraphComponent(exactFormula, address);
+ const cycleStart = isGraphCyclic(graphComponentMatrix);
+ if (cycleStart) {
+ let isOk = confirm(
+ "There is Cyclic in cells formulas. Do you want to trace your cyclic cell path"
+ );
+ while (isOk) {
+ await isGraphCyclicTracePath(graphComponentMatrix, cycleStart);
+ isOk = confirm("Do you want to trace your cyclic again");
+ }
+ removeChildFromGraphComponent(exactFormula);
+ return;
+ }
+ const evaluatedValue = evaluatedFormula(exactFormula);
+ setCellUIAndCellProp(evaluatedValue, exactFormula, address);
+ addChildToParent(exactFormula);
+ updateChildrenCells(address);
+ }
+});
+
+formulaBar.addEventListener("blur", async (e) => {
+ const inputFormula = formulaBar.value
+ if (inputFormula) {
+ const address = addressBar.value
+ const [, cellProp] = getCellandCellProp(address)
+ if (inputFormula !== cellProp.formula) {
+ removeChildFromParent(cellProp.formula)
+ }
+ const exactFormula = GetExactFormula(inputFormula);
+ addChildtoGraphComponent(exactFormula, address)
+ const cycleStart = isGraphCyclic(graphComponentMatrix)
+ if (cycleStart) {
+ let isOk = confirm("There is Cyclic in cells formulas. Do you want to trace your cyclic cell path")
+ while (isOk) {
+ await isGraphCyclicTracePath(graphComponentMatrix, cycleStart)
+ isOk = confirm("Do you want to trace your cyclic again")
+ }
+ removeChildFromGraphComponent(exactFormula)
+ return;
+ }
+ const evaluatedValue = evaluatedFormula(exactFormula)
+ setCellUIAndCellProp(evaluatedValue, exactFormula, address)
+ addChildToParent(exactFormula)
+ updateChildrenCells(address)
+ }
+})
+
+//Remove child cell from parent DB
+
+function removeChildFromParent(formula) {
+ const childAddress = addressBar.value;
+ const arr = getArrayOfFormula(formula);
+ for (let i = 0; i < arr.length; i++) {
+ const charect = Number(arr[i].charCodeAt(0));
+ if (charect >= 65 && charect <= 90) {
+ const [, cellprop] = getCellandCellProp(arr[i]);
+ const idx = cellprop.children.indexOf(childAddress);
+ cellprop.childAddress.splice(idx, 1);
+ }
+ }
+}
+
+//Update child cell DB and UI
+function updateChildrenCells(parentAddress) {
+ const [, parentCellProp] = getCellandCellProp(parentAddress);
+ const children = parentCellProp.children;
+ for (let child of children) {
+ const [, childCellProp] = getCellandCellProp(child);
+ const childformula = childCellProp.formula;
+ const evaluatedValue = evaluatedFormula(childformula);
+ setCellUIAndCellProp(evaluatedValue, childformula, child);
+ updateChildrenCells(child);
+ }
+}
+
+// Add child cell to parent DB
+function addChildToParent(formula) {
+ const childAddress = addressBar.value;
+ const arr = getArrayOfFormula(formula);
+ for (let i = 0; i < arr.length; i++) {
+ const charect = Number(arr[i].charCodeAt(0));
+ if (charect >= 65 && charect <= 90) {
+ const [, cellprop] = getCellandCellProp(arr[i]);
+ cellprop.children.push(childAddress);
+ }
+ }
+}
+
+// Evaluation of formula
+function evaluatedFormula(formula) {
+ const arr = getArrayOfFormula(formula);
+ formula = "";
+ for (let i = 0; i < arr.length; i++) {
+ const charect = Number(arr[i].charCodeAt(0));
+ if (charect >= 65 && charect <= 90) {
+ const [, cellprop] = getCellandCellProp(arr[i]);
+ const enterData = cellprop.value;
+ formula += enterData;
+ } else {
+ formula += arr[i];
+ }
+ }
+ return eval(formula);
+}
+
+// Change in cell DB and UI
+function setCellUIAndCellProp(evaluatedValue, formula, address) {
+ const [activedCell, cellprop] = getCellandCellProp(address);
+ activedCell.innerText = evaluatedValue;
+ cellprop.value = evaluatedValue;
+ cellprop.formula = formula;
+}
+
+// Get array of the formula
+function getArrayOfFormula(formula) {
+ let str = "";
+ const arr = [];
+ for (let i = 0; i < formula.length; i++) {
+ if (formula[i] == " ") {
+ continue;
+ } else if (
+ formula[i] == "(" ||
+ formula[i] == ")" ||
+ formula[i] == "{" ||
+ formula[i] == "}" ||
+ formula[i] == "[" ||
+ formula[i] == "]"
+ ) {
+ arr.push(formula[i]);
+ } else if (
+ formula[i] == "+" ||
+ formula[i] == "-" ||
+ formula[i] == "*" ||
+ formula[i] == "/"
+ ) {
+ arr.push(str.toUpperCase());
+ arr.push(formula[i]);
+ str = "";
+ } else {
+ str += formula[i];
+ }
+ }
+ arr.push(str.toUpperCase());
+ return arr;
+}
+
+// To get exact formula
+function GetExactFormula(formula) {
+ const arr = getArrayOfFormula(formula);
+ formula = "";
+ for (let i = 0; i < arr.length; i++) {
+ formula += arr[i];
+ }
+ return formula;
+}
+
+// Add child in graphDB
+function addChildtoGraphComponent(exactFormula, childAddress) {
+ const [crid, ccid] = decodeRIDCIDfromAddress(childAddress);
+ const arr = getArrayOfFormula(exactFormula);
+ for (let i = 0; i < arr.length; i++) {
+ const charect = Number(arr[i].charCodeAt(0));
+ if (charect >= 65 && charect <= 90) {
+ const [prid, pcid] = decodeRIDCIDfromAddress(arr[i]);
+ graphComponentMatrix[prid][pcid].push([crid, ccid]);
+ }
+ }
+}
+
+// To find where is graph found;
+function isGraphCyclic(graphComponentMatrix) {
+ const visited = [];
+ const dfsVisited = [];
+ for (let i = 0; i < rows; i++) {
+ const visitedRow = [];
+ const dfsVisitedRow = [];
+ for (let j = 0; j < cols; j++) {
+ visitedRow.push(false);
+ dfsVisitedRow.push(false);
+ }
+ visited.push(visitedRow);
+ dfsVisited.push(dfsVisitedRow);
+ }
+ for (let i = 0; i < rows; i++) {
+ for (let j = 0; j < cols; j++) {
+ if (!visited[i][j]) {
+ const isTrue = dfsCycleDetection(
+ graphComponentMatrix,
+ i,
+ j,
+ visited,
+ dfsVisited
+ );
+ if (isTrue) {
+ return [i, j];
+ }
+ }
+ }
+ }
+ return null;
+}
+
+// To detect cycle
+function dfsCycleDetection(
+ graphComponentMatrix,
+ srcr,
+ srcc,
+ visited,
+ dfsVisited
+) {
+ visited[srcr][srcc] = true;
+ dfsVisited[srcr][srcc] = true;
+
+ for (let i = 0; i < graphComponentMatrix[srcr][srcc].length; i++) {
+ const [crid, ccid] = graphComponentMatrix[srcr][srcc][i];
+ if (!visited[crid][ccid]) {
+ const isTrue = dfsCycleDetection(
+ graphComponentMatrix,
+ crid,
+ ccid,
+ visited,
+ dfsVisited
+ );
+ if (isTrue) {
+ return true;
+ }
+ } else if (dfsVisited[crid][ccid]) {
+ return true;
+ }
+ }
+ dfsVisited[srcr][srcc] = false;
+ return false;
+}
+
+// To remove child in graphDB after cycle detection
+function removeChildFromGraphComponent(exactFormula) {
+ const arr = getArrayOfFormula(exactFormula);
+ for (let i = 0; i < arr.length; i++) {
+ let charect = Number(arr[i].charCodeAt(0));
+ if (charect >= 65 && charect <= 90) {
+ const [prid, pcid] = decodeRIDCIDfromAddress(arr[i]);
+ graphComponentMatrix[prid][pcid].pop();
+ }
+ }
+}
+
+// To provide delay function
+function colorPromise() {
+ return new Promise((resolve, reject) => {
+ setTimeout(() => {
+ resolve();
+ }, 1000);
+ });
+}
+
+// Trace Path
+async function isGraphCyclicTracePath(graphComponentMatrix, cycleStart) {
+ const [srcr, srcc] = cycleStart;
+ const visited = [];
+ const dfsVisited = [];
+ for (let i = 0; i < rows; i++) {
+ const visitedRow = [];
+ const dfsVisitedRow = [];
+ for (let j = 0; j < cols; j++) {
+ visitedRow.push(false);
+ dfsVisitedRow.push(false);
+ }
+ visited.push(visitedRow);
+ dfsVisited.push(dfsVisitedRow);
+ }
+ const isTrue = await dfsCycleDetectionTracePath(
+ graphComponentMatrix,
+ srcr,
+ srcc,
+ visited,
+ dfsVisited
+ );
+ if (isTrue) {
+ return Promise.resolve(true);
+ }
+ return Promise.resolve(false);
+}
+// To detect cycle and color them
+async function dfsCycleDetectionTracePath(
+ graphComponentMatrix,
+ srcr,
+ srcc,
+ visited,
+ dfsVisited
+) {
+ visited[srcr][srcc] = true;
+ dfsVisited[srcr][srcc] = true;
+ const cell = document.querySelector(`.cell[rid="${srcr}"][cid="${srcc}"]`);
+ cell.style.backgroundColor = "lightblue";
+ await colorPromise();
+ for (let i = 0; i < graphComponentMatrix[srcr][srcc].length; i++) {
+ const [crid, ccid] = graphComponentMatrix[srcr][srcc][i];
+ if (!visited[crid][ccid]) {
+ const isTrue = await dfsCycleDetectionTracePath(
+ graphComponentMatrix,
+ crid,
+ ccid,
+ visited,
+ dfsVisited
+ );
+ if (isTrue) {
+ cell.style.backgroundColor = "transparent";
+ await colorPromise();
+ return Promise.resolve(true);
+ }
+ } else if (visited[crid][ccid] && dfsVisited[crid][ccid]) {
+ const CyclicCell = document.querySelector(
+ `.cell[rid="${crid}"][cid="${ccid}"]`
+ );
+ CyclicCell.style.backgroundColor = "lightsalmon";
+ await colorPromise();
+ CyclicCell.style.backgroundColor = "transparent";
+ await colorPromise();
+ cell.style.backgroundColor = "transparent";
+ await colorPromise();
+ return Promise.resolve(true);
+ }
+ }
+ dfsVisited[srcr][srcc] = false;
+ return Promise.resolve(false);
+}
+
+const addSheetBtn = document.querySelector(".sheet-add-icon");
+const sheetFolderCont = document.querySelector(".sheets-folder-cont");
+const activeSheetColor = "#ced6e0";
+
+
+
+// click listener to add sheet btn
+addSheetBtn.addEventListener("click", (e) => {
+ const sheet = document.createElement("div");
+ sheet.setAttribute("class", "sheet-folder");
+ const allSheetFolder = document.querySelectorAll(".sheet-folder");
+ sheet.setAttribute("id", allSheetFolder.length);
+ sheet.innerHTML = `
+ Sheet-${allSheetFolder.length + 1}
+ `;
+ sheetFolderCont.appendChild(sheet);
+ createSheetDB_And_createGraphComponentMatrix();
+ handleSheetActiveness(sheet);
+ handlesheetRemoval(sheet);
+ sheet.click();
+ sheet.scrollIntoView();
+});
+
+function handleSheetActiveness(sheet) {
+ sheet.addEventListener("click", (e) => {
+ const sheetIndex = Number(sheet.getAttribute("id"));
+ handleSheetDB(sheetIndex);
+ handleSheetUi(sheet);
+
+ });
+}
+
+function handleSheetDB(sheetIndex) {
+ sheetDB = collectedSheetDB[sheetIndex];
+ graphComponentMatrix = collecteddGraphComponent[sheetIndex];
+}
+
+function handleSheetProp() {
+ for (let i = 0; i < rows; i++) {
+ for (let j = 0; j < cols; j++) {
+ const cell = document.querySelector(`.cell[rid="${i}"][cid="${j}"]`);
+ cell.click();
+ }
+ }
+ const firstCell = document.querySelector(".cell");
+ firstCell.click();
+ firstCell.style.border = `3px solid ${cellBorderColor}`;
+}
+
+function handleSheetUi(sheet) {
+ const allSheetFolder = document.querySelectorAll(".sheet-folder");
+ for (let i = 0; i < allSheetFolder.length; i++) {
+ allSheetFolder[i].style.backgroundColor = "transparent";
+ }
+ sheet.style.backgroundColor = activeSheetColor;
+ handleSheetProp();
+}
+
+function handlesheetRemoval(sheet) {
+ sheet.addEventListener("mousedown", (e) => {
+ if (e.button !== 2) {
+ return;
+ }
+ const allSheetFolder = document.querySelectorAll(".sheet-folder");
+ if (allSheetFolder.length === 1) {
+ alert("You need to have atleast one sheet");
+ return;
+ }
+ const isOk = confirm("Do you want to delete permanently");
+ if (!isOk) {
+ return;
+ }
+
+ const sheetIndex = Number(sheet.getAttribute("id"));
+ collectedSheetDB.splice(sheetIndex, 1);
+ collecteddGraphComponent.splice(sheetIndex, 1);
+ handleSheetUiRemoval(sheet);
+ sheetDB = collectedSheetDB[0];
+ graphComponentMatrix = collecteddGraphComponent[0];
+ handleSheetProp();
+ });
+}
+
+function handleSheetUiRemoval(sheet) {
+ sheet.remove();
+ const allSheetFolder = document.querySelectorAll(".sheet-folder");
+ for (let i = 0; i < allSheetFolder.length; i++) {
+ allSheetFolder[i].setAttribute("id", i);
+ const sheetContent = allSheetFolder[i].querySelector(".sheet-content");
+ sheetContent.innerText = `Sheet-${i + 1}`;
+ allSheetFolder[i].style.backgroundColor = "transparent";
+ }
+ allSheetFolder[0].style.backgroundColor = activeSheetColor;
+}
+
+const copybtn = document.querySelector(".copy");
+const pastebtn = document.querySelector(".paste");
+const cutbtn = document.querySelector(".cut");
+
+let shiftKey;
+document.addEventListener("keydown", (e) => {
+ shiftKey = e.shiftKey;
+});
+document.addEventListener("keyup", (e) => {
+ shiftKey = e.shiftKey;
+});
+
+
+// Range selection
+function handleSelectedCells(cell) {
+ if (!shiftKey) {
+ return;
+ }
+ if (rangeStorage.length >= 2) {
+ SelectCellborder(1, lightGray);
+ rangeStorage = [];
+ }
+ const rid = Number(cell.getAttribute("rid"));
+ const cid = Number(cell.getAttribute("cid"));
+ rangeStorage.push([rid, cid]);
+ if (rangeStorage.length == 2) {
+ SelectCellborder(3, cellBorderColor);
+ }
+}
+// border color of while selecton and unselection
+function SelectCellborder(size, color) {
+ for (let i = rangeStorage[0][0]; i <= rangeStorage[1][0]; i++) {
+ for (let j = rangeStorage[0][1]; j <= rangeStorage[1][1]; j++) {
+ const rangeCell = document.querySelector(`.cell[rid="${i}"][cid="${j}"]`);
+ if (i === rangeStorage[0][0] && j === rangeStorage[0][1]) {
+ rangeCell.style.borderLeft = `${size}px solid ${color}`;
+ rangeCell.style.borderTop = `${size}px solid ${color}`;
+ } else if (i === rangeStorage[0][0]) {
+ rangeCell.style.borderTop = `${size}px solid ${color}`;
+ }
+ if (i === rangeStorage[1][0] && j === rangeStorage[0][1]) {
+ rangeCell.style.borderLeft = `${size}px solid ${color}`;
+ rangeCell.style.borderBottom = `${size}px solid ${color}`;
+ } else if (j === rangeStorage[0][1]) {
+ rangeCell.style.borderLeft = `${size}px solid ${color}`;
+ }
+ if (i === rangeStorage[0][0] && j === rangeStorage[1][1]) {
+ rangeCell.style.borderRight = `${size}px solid ${color}`;
+ rangeCell.style.borderTop = `${size}px solid ${color}`;
+ } else if (j === rangeStorage[1][1]) {
+ rangeCell.style.borderRight = `${size}px solid ${color}`;
+ }
+ if (i === rangeStorage[1][0] && j === rangeStorage[1][1]) {
+ rangeCell.style.borderRight = `${size}px solid ${color}`;
+ rangeCell.style.borderBottom = `${size}px solid ${color}`;
+ if (size === 3) {
+ rangeCell.style.borderTop = `1px solid ${lightGray}`;
+ rangeCell.style.borderLeft = `1px solid ${lightGray}`;
+ }
+ } else if (i === rangeStorage[1][0]) {
+ rangeCell.style.borderBottom = `${size}px solid ${color}`;
+ }
+ }
+ }
+}
+
+let singleCellprop = {};
+copybtn.addEventListener("click", (e) => {
+ copyData = [];
+ if (rangeStorage.length < 2) {
+ const address = addressBar.value;
+ const [, cellprop] = getCellandCellProp(address);
+ singleCellprop = cellprop;
+ return;
+ }
+
+ for (let i = rangeStorage[0][0]; i <= rangeStorage[1][0]; i++) {
+ const row = [];
+ for (let j = rangeStorage[0][1]; j <= rangeStorage[1][1]; j++) {
+ row.push(sheetDB[i][j]);
+ }
+ copyData.push(row);
+ }
+ console.log(copyData)
+ if (rangeStorage.length === 2) SelectCellborder(1, lightGray);
+});
+
+pastebtn.addEventListener("click", (e) => {
+ const address = addressBar.value;
+ const [rid, cid] = decodeRIDCIDfromAddress(address);
+ console.log("ok");
+ if (rangeStorage.length < 2) {
+ sheetDB[rid][cid] = singleCellprop;
+ console.log(sheetDB[rid][cid]);
+ const rangeCell = document.querySelector(
+ `.cell[rid="${rid}"][cid="${cid}"]`
+ );
+ rangeCell.click();
+ return;
+ }
+ if (copyData.length === 0) {
+ return;
+ }
+ for (
+ let i = rid, k = 0;
+ i <= rid + Math.abs(rangeStorage[1][0] - rangeStorage[0][0]);
+ k++, i++
+ ) {
+ for (
+ let j = cid, l = 0;
+ j <= cid + Math.abs(rangeStorage[1][1] - rangeStorage[0][1]);
+ j++, l++
+ ) {
+ const rangeCell = document.querySelector(`.cell[rid="${i}"][cid="${j}"]`);
+ if (rangeCell) {
+ sheetDB[i][j] = copyData[k][l];
+ rangeCell.click();
+ }
+ }
+ }
+});
+
+cutbtn.addEventListener("click", (e) => {
+ if (rangeStorage.length < 2) {
+ const address = addressBar.value;
+ const [cell, cellprop] = getCellandCellProp(address);
+ singleCellprop = cellprop;
+ cell.innerText = "";
+ return;
+ }
+ copyData = [];
+ for (let i = rangeStorage[0][0]; i <= rangeStorage[1][0]; i++) {
+ const row = [];
+ for (let j = rangeStorage[0][1]; j <= rangeStorage[1][1]; j++) {
+ const rangeCell = document.querySelector(`.cell[rid="${i}"][cid="${j}"]`);
+ row.push(sheetDB[i][j]);
+ sheetDB[i][j] = returnDefauldata();
+ rangeCell.click();
+ }
+ copyData.push(row);
+ }
+ if (rangeStorage.length === 2) SelectCellborder(1, lightGray);
+});
+
+const downloadbtn = document.querySelector(".download");
+const uploadbtn = document.querySelector(".upload");
+
+downloadbtn.addEventListener("click", (e) => {
+ const data = JSON.stringify([sheetDB, graphComponentMatrix]);
+ const file = new Blob([data], { type: "application/json" });
+ const a = document.createElement("a");
+ a.href = URL.createObjectURL(file);
+ a.download = "sheetDATA.json";
+ a.click();
+});
+uploadbtn.addEventListener("click", (e) => {
+ const input = document.createElement("input");
+ input.setAttribute("type", "file");
+ input.click();
+ input.addEventListener("change", (e) => {
+ const fr = new FileReader();
+ const files = input.files;
+ const fileObj = files[0];
+ fr.readAsText(fileObj);
+ fr.addEventListener("load", (e) => {
+ const readSheetData = JSON.parse(fr.result);
+ addSheetBtn.click();
+ sheetDB = readSheetData[0];
+ graphComponentMatrix = readSheetData[0];
+ collectedSheetDB[collectedSheetDB.length - 1] = sheetDB;
+ collecteddGraphComponent[collecteddGraphComponent.length - 1] =
+ graphComponentMatrix;
+ handleSheetProp();
+ });
+ });
+});
+{
+ const addSheetBtn = document.querySelector(".sheet-add-icon");
+ addSheetBtn.click();
+}
\ No newline at end of file