Saturday, 24 January 2026

TreeView

 <?php

error_reporting(E_ALL);

ini_set('display_errors', 0);

header('Content-Type: application/json');


$mysqli = new mysqli("localhost", "xxx", "xxx", "xxxx");

if ($mysqli->connect_error) {

    echo json_encode(["error" => "DB connection failed: " . $mysqli->connect_error]);

    exit;

}


$type   = $_GET['type']   ?? '';

$value  = $_GET['value']  ?? '';   // month or other

$symbol = $_GET['symbol'] ?? '';

$symbolsParam = $_GET['symbols'] ?? '';


$result = [];


if ($type === "symbols") {


    $symbolsParam = $_GET['symbols'] ?? '';

    $sql = "SELECT DISTINCT symbol, concat(symbol,' | ','Shares') company_name, 'TECH' sector 

            FROM stock 

            WHERE symbol IN ($symbolsParam) 

            ORDER BY symbol";

    $res = $mysqli->query($sql);

    while ($row = $res->fetch_assoc()) {

        $result[] = [

            "label"    => $row['symbol'] . " (" . $row['company_name'] . ", " . $row['sector'] . ")",

            "value"    => $row['symbol'],

            "nextType" => "symbol"

        ];

    }

}

/*

elseif ($type === "symbol") {

    // Under each symbol, show 3 fixed nodes

    $result = [

        ["label" => "Database",      "value" => $symbol, "nextType" => "database",      "symbol" => $symbol],

        ["label" => "Allapps",       "value" => $symbol, "nextType" => "allapps",       "symbol" => $symbol],

        ["label" => "Microservices", "value" => $symbol, "nextType" => "microservices", "symbol" => $symbol]

    ];

}

*/

elseif ($type === "symbol") {

    $result = [

        ["label" => "Database",      "value" => $symbol, "nextType" => "database",      "symbol" => $symbol, "cssClass" => "database-label"],

        ["label" => "Allapps",       "value" => $symbol, "nextType" => "allapps",       "symbol" => $symbol, "cssClass" => "allapps-label"],

        ["label" => "Microservices", "value" => $symbol, "nextType" => "microservices", "symbol" => $symbol, "cssClass" => "microservices-label"]

    ];

}



elseif ($type === "database") {

    $stmt = $mysqli->prepare("SELECT * FROM myinv WHERE sym=?");

    $stmt->bind_param("s", $symbol);

    $stmt->execute();

    $res = $stmt->get_result();

    while ($row = $res->fetch_assoc()) {

        $result[] = $row;

    }

    $stmt->close();

}

elseif ($type === "allapps") {

    $stmt = $mysqli->prepare("SELECT * FROM corona WHERE symbol=?");

    $stmt->bind_param("s", $symbol);

    $stmt->execute();

    $res = $stmt->get_result();

    while ($row = $res->fetch_assoc()) {

        $result[] = $row;

    }

    $stmt->close();

}

elseif ($type === "microservices") {

    $stmt = $mysqli->prepare("SELECT * FROM stock WHERE symbol=?");

    $stmt->bind_param("s", $symbol);

    $stmt->execute();

    $res = $stmt->get_result();

    while ($row = $res->fetch_assoc()) {

        $result[] = $row;

    }

    $stmt->close();

}


echo json_encode($result ?? []);




#################JS ###########################



<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>Stock TreeView</title>

<style>

  body { font-family: Arial, sans-serif; background: #f9f9f9; padding: 20px; }

  h2 { text-align: center; }

  #inputArea { text-align: center; margin-bottom: 20px; }

  textarea { width: 400px; padding: 8px; }

  button { padding: 8px 12px; margin-left: 10px; cursor: pointer; }

  ul.tree, ul.tree ul { list-style-type: none; margin: 0; padding: 0; }

  ul.tree li { margin: 4px 0; cursor: pointer; }

  .caret::before { content: "+ "; color: #007BFF; font-weight: bold; margin-right: 4px; }

  .caret-down::before { content: "- "; }

  .nested { display: none; margin-left: 20px; }

  .active { display: block; }

  .node-label { padding: 4px 8px; border-radius: 4px; }

  .node-label:hover { background: #e6f0ff; }

  table { border-collapse: collapse; width: 100%; margin-top: 10px; }

  th, td { border: 1px solid #ccc; padding: 6px; text-align: left; }

  th { background: #f4f4f4; }

  input.search-box { margin-bottom: 8px; padding: 6px; width: 10%; }

</style>

</head>

<body>


<h2>Stock TreeView</h2>


<!-- Separate container for symbol input -->

<div id="symbolInputContainer">

  <h3>Enter Symbols</h3>

  <textarea id="symbolsInput" rows="3" placeholder="Enter symbols (space or line separated)"></textarea><br>

  <button onclick="buildTree()">Build Tree</button>

</div>


<!-- Separate container for tree results -->

<div id="treeContainer"></div>




<script>

function buildTree() {

  const input = document.getElementById("symbolsInput").value;

  const symbols = input.split(/\s+/).filter(s => s.trim() !== "");

  const formatted = symbols.map(s => `'${s.toUpperCase()}'`).join(",");


  const container = document.getElementById("treeContainer");

  container.innerHTML = "";


  fetch(`backend.php?type=symbols&symbols=${encodeURIComponent(formatted)}`)

    .then(res => res.json())

    .then(data => {

      if (!Array.isArray(data)) {

        container.innerHTML = `<p style="color:red;">Error: ${data.error || "Invalid response"}</p>`;

        return;

      }


      const ul = document.createElement("ul");

      ul.className = "tree";


      data.forEach(item => {

        const li = document.createElement("li");

        const span = document.createElement("span");

        span.className = "caret node-label";

        span.textContent = item.label;

        span.onclick = () => toggleNode(span, item.nextType, item.value);

        li.appendChild(span);


        const nested = document.createElement("ul");

        nested.className = "nested";

        li.appendChild(nested);


        ul.appendChild(li);

      });


      container.appendChild(ul);

    })

    .catch(err => {

      container.innerHTML = `<p style="color:red;">Fetch error: ${err}</p>`;

    });

}


function toggleNode(element, type, value, symbol="") {

  element.classList.toggle("caret-down");

  const nested = element.nextElementSibling;


  if (!nested.classList.contains("active")) {

    const url = `backend.php?type=${type}&value=${value}&symbol=${symbol || value}`;


    fetch(url)

      .then(res => res.json())

      .then(data => {

        nested.innerHTML = "";

        if (!Array.isArray(data)) {

          nested.innerHTML = `<li style="color:red;">Error: ${data.error || "Invalid response"}</li>`;

          nested.classList.add("active");

          return;

        }

        if (type === "database" || type === "allapps" || type === "microservices") {

const li = document.createElement("li");

  const wrapper = document.createElement("div");


  // Search box + table creation (same as before)

  // ...

  li.appendChild(wrapper);


  // Append inside the child UL of Database/Allapps/Microservices

  nested.appendChild(li);



          if (data.length > 0) {

            const wrapper = document.createElement("div");


            // Search box

            const searchBox = document.createElement("input");

            searchBox.type = "text";

            searchBox.placeholder = "Search...";

            searchBox.className = "search-box";


            // Table

            const table = document.createElement("table");

if (type === "database") {

  table.classList.add("database-table");

}

if (type === "allapps") {

  table.classList.add("allapps-table");

}

if (type === "microservices") {

  table.classList.add("microservices-table");

}

            const headerRow = document.createElement("tr");

            Object.keys(data[0]).forEach(key => {

              const th = document.createElement("th");

              th.textContent = key;

              headerRow.appendChild(th);

            });

            table.appendChild(headerRow);


            data.forEach(row => {

              const tr = document.createElement("tr");

              Object.values(row).forEach(val => {

                const td = document.createElement("td");

                td.textContent = val;

                tr.appendChild(td);

              });

              table.appendChild(tr);

            });


            // Filter logic

            searchBox.addEventListener("keyup", function() {

              const filter = this.value.toLowerCase();

              const rows = table.getElementsByTagName("tr");

              for (let i = 1; i < rows.length; i++) { // skip header

                let rowText = rows[i].textContent.toLowerCase();

                rows[i].style.display = rowText.includes(filter) ? "" : "none";

              }

            });


            wrapper.appendChild(searchBox);

            wrapper.appendChild(table);


            const li = document.createElement("li");

            li.appendChild(wrapper);

            nested.appendChild(li);

          } else {

            nested.innerHTML = "<li>No records found</li>";

          }

        } else {

  data.forEach(item => {

    const li = document.createElement("li");

    const span = document.createElement("span");

    span.className = "caret node-label " + (item.cssClass || "");

    span.textContent = item.label;

    span.onclick = () => toggleNode(span, item.nextType, item.value, item.symbol || symbol);

    li.appendChild(span);


    // Each child node gets its own nested UL

    const childUl = document.createElement("ul");

    childUl.className = "nested";

    li.appendChild(childUl);


    nested.appendChild(li);

  });

}


        nested.classList.add("active");

      })

      .catch(err => {

        nested.innerHTML = `<li style="color:red;">Fetch error: ${err}</li>`;

        nested.classList.add("active");

      });

  } else {

    nested.classList.toggle("active");

  }

}

</script>


<style>

/* General page styling */

body {

  font-family: "Segoe UI", Roboto, Arial, sans-serif;

  background: linear-gradient(135deg, #f0f4f8, #d9e2ec);

  margin: 0;

  padding: 20px;

  color: #333;

}


h2 {

  text-align: center;

  font-size: 28px;

  color: #2a4365;

  margin-bottom: 20px;

}


/* Input area */

#inputArea {

  text-align: center;

  margin-bottom: 30px;

}


textarea {

  width: 400px;

  padding: 10px;

  border: 2px solid #cbd5e0;

  border-radius: 6px;

  font-size: 14px;

  resize: none;

  transition: border-color 0.3s;

}


textarea:focus {

  border-color: #3182ce;

  outline: none;

}


button {

  padding: 10px 18px;

  margin-left: 10px;

  cursor: pointer;

  background: #3182ce;

  color: #fff;

  border: none;

  border-radius: 6px;

  font-size: 14px;

  transition: background 0.3s;

}


button:hover {

  background: #2b6cb0;

}


/* Tree styling */

ul.tree, ul.tree ul {

  list-style-type: none;

  margin: 0;

  padding: 0;

}


ul.tree li {

  margin: 6px 0;

  cursor: pointer;

  position: relative;

}


.caret::before {

  font-family: "Font Awesome 5 Free";

  content: "\f0da"; /* fa-caret-right */

  font-weight: 900;

  margin-right: 6px;

}


.caret::before {

  content: "\25B6"; /* ? right-pointing triangle */

  color: #3182ce;

  font-weight: bold;

  margin-right: 6px;

  transition: transform 0.3s;

}


.caret-down::before {

  content: "\25BC"; /* ? down-pointing triangle */

}

.node-label:hover {

  background: #e2e8f0;

  transform: translateX(3px);

}


.nested {

  display: none;

  margin-left: 20px;

}


.active {

  display: block;

}


/* Shared table styling */

table {

  border-collapse: collapse;

  width: 95%;

  margin: 15px auto;

  box-shadow: 0 2px 6px rgba(0,0,0,0.1);

  border-radius: 6px;

  overflow: hidden;

}


th, td {

  border: 1px solid #e2e8f0;

  padding: 10px;

  text-align: left;

  font-size: 14px;

}


tr:nth-child(even) {

  background: #f7fafc;

}


tr:hover {

  background: #ebf8ff;

}


/* Search box styling */

input.search-box {

  margin: 10px auto;

  display: block;

  padding: 8px 12px;

  width: 50%;

  border: 2px solid #cbd5e0;

  border-radius: 6px;

  font-size: 14px;

  transition: border-color 0.3s;

}


input.search-box:focus {

  border-color: #3182ce;

  outline: none;

}


/* Section-specific themes */

.database-table th {

  background: #2b6cb0; /* Deep blue */

  color: #fff;

}


.allapps-table th {

  background: #38a169; /* Green */

  color: #fff;

}


.microservices-table th {

  background: #d69e2e; /* Amber/Orange */

  color: #fff;

}


/* Section-specific label icons */

.database-label::before {

  content: "??? "; /* database cylinder/file cabinet */

}


.allapps-label::before {

  content: "?? "; /* app icon (mobile) */

}


.microservices-label::before {

  content: "?? "; /* gear for microservices */

}


.database-label::before {

  content: "\25A3 "; /* ? square with fill */

  color: #2b6cb0;

}


.allapps-label::before {

  content: "\25A0 "; /* ¦ solid square */

  color: #38a169;

}


.microservices-label::before {

  content: "\25CF "; /* ? solid circle */

  color: #d69e2e;

}


/* Extra indentation for tables under child nodes */

.nested li div {

  margin-left: 30px;   /* pushes the wrapper (search + table) to the right */

}


.database-table {

  margin-left: 30px;

}


.allapps-table {

  margin-left: 30px;

}


.microservices-table {

  margin-left: 30px;

}


/* Indent the child headings under each symbol */

.database-label,

.allapps-label,

.microservices-label {

  margin-left: 25px;   /* push the caret + label right */

  display: inline-block;

}


ul.tree ul li .node-label {

  margin-left: 25px;

}


#symbolInputContainer {

  max-width: 500px;

  margin: 0 auto 30px auto;

  padding: 20px;

  background: #ffffff;

  border: 2px solid #cbd5e0;

  border-radius: 8px;

  box-shadow: 0 4px 10px rgba(0,0,0,0.05);

  text-align: center;

}


#symbolInputContainer h3 {

  margin-bottom: 15px;

  color: #2a4365;

  font-size: 20px;

}


/* Smaller search box */

input.search-box {

  margin: 8px auto;

  display: block;

  padding: 5px 8px;       /* reduced padding */

  width: 35%;             /* narrower width */

  border: 2px solid #cbd5e0;

  border-radius: 6px;

  font-size: 13px;        /* slightly smaller font */

  transition: border-color 0.3s;

}


input.search-box:focus {

  border-color: #3182ce;

  outline: none;

}


/* Larger font for symbols */

ul.tree > li > .node-label {

  font-size: 18px;        /* bigger font for main symbols */

  font-weight: 600;

  color: #2a4365;

}


/* Larger font for Database / Allapps / Microservices headings */

.database-label,

.allapps-label,

.microservices-label {

  font-size: 16px;        /* bigger font for child headings */

  font-weight: 500;

  color: #1a202c;

  margin-left: 25px;      /* indentation to push them right */

  display: inline-block;

}


#pageFooter {

  text-align: center;

  margin-top: 40px;

  padding: 15px;

  font-size: 14px;

  font-weight: 500;

  color: #2a4365;

  background: #edf2f7;

  border-top: 2px solid #cbd5e0;

  border-radius: 0 0 8px 8px;

}


</style>


<!-- Footer -->

<footer id="pageFooter">

  Developed by Dilip

</footer>

</body>


</body>

</html>

No comments:

Post a Comment