Google Maps API Marker Clusterer show a dot instead of the numbers of markers inside the cluster using nextjs

I’m trying to do make a map with some POI and everything works fine except when I want to add a Marker Clusterer. In fact, I can see the cluster and interact with it, but instead of showing the number of makers inside the clusterer, it just shows a dot… Image of my current webapp.

I think the problems is here because I’m using JS instead of TS. So I tried to modify the code in the tutorial of google maps (https://developers.google.com/codelabs/maps-platform/maps-platform-101-react-js#0) but I may have made a mistake…

Also, here’s my code:

import {
  APIProvider,
  Map,
  AdvancedMarker,
  Pin,
  useMap,
} from "@vis.gl/react-google-maps";
import { MarkerClusterer, ClusterIconStyle } from "@googlemaps/markerclusterer";

export default function MapInterface({ setTableView }) {
  //------------- POLYGONS DATA -------------
  const encode = require("geojson-polyline").encode;
  const regSimpData = regSimp.features;
  const encodedRegSimp = regSimpData.map((reg) => encode(reg.geometry));

  const tableButtonClickHandler = () => {
    setTableView(true);
  };

  //------------- DATA -------------

  const initialData = [
    { key: "operaHouse", location: { lat: -33.8567844, lng: 151.213108 } },
    { key: "tarongaZoo", location: { lat: -33.8472767, lng: 151.2188164 } },
    { key: "manlyBeach", location: { lat: -33.8209738, lng: 151.2563253 } },
    { key: "hyderPark", location: { lat: -33.8690081, lng: 151.2052393 } },
    { key: "theRocks", location: { lat: -33.8587568, lng: 151.2058246 } },
    { key: "circularQuay", location: { lat: -33.858761, lng: 151.2055688 } },
    { key: "harbourBridge", location: { lat: -33.852228, lng: 151.2038374 } },
    { key: "kingsCross", location: { lat: -33.8737375, lng: 151.222569 } },
    { key: "botanicGardens", location: { lat: -33.864167, lng: 151.216387 } },
    { key: "museumOfSydney", location: { lat: -33.8636005, lng: 151.2092542 } },
    { key: "maritimeMuseum", location: { lat: -33.869395, lng: 151.198648 } },
    {
      key: "kingStreetWharf",
      location: { lat: -33.8665445, lng: 151.1989808 },
    },
    { key: "aquarium", location: { lat: -33.869627, lng: 151.202146 } },
    { key: "darlingHarbour", location: { lat: -33.87488, lng: 151.1987113 } },
    { key: "barangaroo", location: { lat: -33.8605523, lng: 151.1972205 } },
  ];

  //------------- MARKERS -------------
  const BordeauxMarkers = ({ pois }) => {
    const map = useMap();
    const [markers, setMarkers] = useState({});
    const clusterer = useRef(null);

    // Initialize MarkerClusterer, if the map has changed
    useEffect(() => {
      if (!map) return;
      if (!clusterer.current) {
        clusterer.current = new MarkerClusterer({
          map: map,
        });
      }
    }, [map]);

    // Update markers, if the markers array has changed
    useEffect(() => {
      if (!clusterer.current) return;
      clusterer.current.clearMarkers();
      clusterer.current.addMarkers(Object.values(markers));
    }, [markers]);

    const setMarkerRef = (marker, key) => {
      if (marker && markers[key]) return;
      if (!marker && !markers[key]) return;

      setMarkers((prev) => {
        if (marker) {
          return { ...prev, [key]: marker };
        } else {
          const newMarkers = { ...prev };
          delete newMarkers[key];
          return newMarkers;
        }
      });
    };

    console.log(markers);

    return (
      <>
        {pois.map((poi) => (
          <AdvancedMarker
            key={poi.key}
            position={poi.location}
            ref={(marker) => setMarkerRef(marker, poi.key)}
          >
            <Pin
              background={"#FBBC04"}
              glyphColor={"#000"}
              borderColor={"#000"}
            />
          </AdvancedMarker>
        ))}
      </>
    );
  };

  //------------- CLUSTERS -------------

  return (
    <>
      <Flex position={"relative"} bgColor={"transparent"}>
        <Flex h="850px" w="vw" position={"absolute"} top={0} left={0}>
          <APIProvider
            apiKey={"APIKEY"}
            onLoad={() => console.log("Maps API has loaded.")}
          >
            <Map
              defaultZoom={6}
              defaultCenter={{ lat: 46.757285, lng: 2.2329292 }}
              mapId="MAP ID"
              onCameraChanged={(ev) =>
                console.log(
                  "camera changed:",
                  ev.detail.center,
                  "zoom:",
                  ev.detail.zoom
                )
              }
            >
              <BordeauxMarkers pois={initialData} />
              <Polygon encodedPaths={encodedRegSimp[0].coordinates} />
              <Polygon encodedPaths={encodedRegSimp[1].coordinates} />
              <Polygon encodedPaths={encodedRegSimp[2].coordinates} />
              <Polygon encodedPaths={encodedRegSimp[3].coordinates} />
              <Polygon encodedPaths={encodedRegSimp[4].coordinates} />
              <Polygon encodedPaths={encodedRegSimp[5].coordinates} />
              <Polygon encodedPaths={encodedRegSimp[6].coordinates[0]} />
              <Polygon encodedPaths={encodedRegSimp[7].coordinates[0]} />
              <Polygon encodedPaths={encodedRegSimp[8].coordinates[0]} />
              <Polygon encodedPaths={encodedRegSimp[9].coordinates[0]} />
              <Polygon encodedPaths={encodedRegSimp[10].coordinates} />
              <Polygon encodedPaths={encodedRegSimp[11].coordinates[0]} />
              <Polygon encodedPaths={encodedRegSimp[12].coordinates} />
            </Map>
          </APIProvider>
        </Flex>
        <Flex w="80%"></Flex>
        <Flex justifyContent={"end"} w="full" marginX="2%" marginY="2%">
          <Group attached={true}>
            <Button variant={"solid"} onClick={tableButtonClickHandler}>
              Table
            </Button>
            <Button variant={"solid"} disabled>
              Map
            </Button>
          </Group>
        </Flex>
      </Flex>
    </>
  );
}

I don’t really don’t know what’s wrong because my code seems the same as the one in the tutorial, except it’s in JS. I tried to modify the render but it didn’t change anything and I have watch other tutorials but that didn’t help me. Also, I didn’t really get how the ref tag works in the AdvancedMarker component…

Thanks in advance!

How to remove text from all pages of a specific website? [closed]

I’m looking for a way to remove a portion of text that appears on all page of a website.

The text i would like to remove is within a structure like this :

<div class="feedback">
    <div class="i_element">Here it is : lorem ipsum sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam ...
    </div>
</div>

I would like to remove the “Here it is :” part and leave the rest of the text everytime i load a page on this website.

I thought maybe it can be done by targetting the .i_element nested inside the .feedback div and erasing the first twelve characters of the text within the i_element div

I looked for solution and it seems that this can be achieved using tools like tampermonkey or Greasemonkey but i don’t know javascript.
I only know html and css.

I’m using Firefox.

Is this a good solution ?
Can anyone help with this ?
Thanks

Why does my resetChallenge() function not completely reset the progress and badges in my JS web app?

I’m building a small web-based challenge tracker using JavaScript and localStorage. Everything works fine, except for the resetChallenge() functionality.

When I reach 100% progress on a task, I call resetChallenge() to clear the UI and start fresh. However, while the progress bar and challenge info reset visually, the badges from the previous challenge still appear on refresh or after reset.

Here’s my resetChallenge() function:

function resetChallenge() {
    challengeTitle.textContent = "Challenge not set";
    challengeDescription.textContent = "Set your challenge above";
    progressFill.style.width = '0%';
    progressText.textContent = '0%';
    badgeContainer.innerHTML = '';
    challengeCompleted = false;
    updateProgress(0);
    localStorage.removeItem('spendSmartState');
}

The issue is that when I refresh the page, the badges come back. It seems like they’re being reloaded from localStorage inside my loadBadges() function. I suspect it’s because I’m not resetting badgesEarned, which is a global variable used to track how many badges a user has unlocked.

My init() function looks like this:

function init() {
    const savedState = JSON.parse(localStorage.getItem('spendSmartState'));
    if (savedState) {
        challengeCompleted = savedState.challengeCompleted;
        updateProgress(savedState.progress || 0);
        loadBadges(savedState.badgesEarned || 0);
    }
}

I want to:

  1. Ensure resetChallenge() properly clears everything so the user starts fresh.
  2. Optionally, provide a “hard reset” on refresh if needed, without reloading old state from localStorage.

Is resetting badgesEarned = 0 inside resetChallenge() the correct approach? Should I clear localStorage differently to avoid reloading outdated badge data?

Any advice on best practices for managing localStorage state resets and UI sync would be greatly appreciated!

Is possible to upload chunked files one by one – multiple selection in – pure JS?

I am trying to use pure JS for select multiple files on form, take one by one , chunk it and process it by PHP on server side. BUT with follow code I am not able process files one by one and also final size of files bigger than 2MB is incorrect.
My code https://pastebin.com/nmkYB3LL

I do not want to use third party products.
I really must use chunked files due used hardware.

Can somebody help me?

I tried it in many ways but without success.

New tab not focused on window.open & I don’t know why

I have an element that I’d like to be treated as if it were a link. This includes opening the target in a new tab if the user middle-clicks it (by default middle-clicking allows you to scroll the page by moving your mouse, assuming the page is larger than your window).

I can get the target to open in a new tab, but when it does the existing tab keeps the focus (unlike when you middle-click a link) & I cannot figure out why. The JS I’m using is as follows:

var list = document.getElementsByClassName('test');                 
for (let item of list) {
    item.addEventListener("mousedown", function(event) {                        
        if (event.which === 2) {                            
            event.preventDefault();                         
        }
    });                 
    item.addEventListener("auxclick", function(event) {                     
        if (event.button === 1) {                           
            event.preventDefault();
            window.open(item.getAttribute('data-href'), '_blank').focus();
        }                   
    });                 
}

… and the sample HTML that shows the behavior (in my app I’m working with table rows, but the end result is the same) is:

<span class='test' data-href='https://www.google.com'>TEST</span>

… I thought adding .focus() onto the end of the window.open() call would do what I wanted it to, but apparently not …

Same behavior seen in latest builds of Chrome, Edge, and FireFox.

To be clear, the following results with the desired behavior, but on a ‘normal’ click:

    item.addEventListener("click", function(event) {                        
        window.open(item.getAttribute('data-href'), '_blank').focus();
    }); 

Data from within JSON Array not showing when Fetching in Alpine.js

I am trying to fetch data from a (local) JSON file. I have no trouble accessing the first level of data within the JSON file (e.g. id, title, ingredients as a whole). However, the issue arises when I try to access/read/fetch the single ingredients.

By my understanding, x-for="ingredient in data.recipies.ingredients" should give me one instance of <p>TEST</p> for each ingredient per recipe. However, the output is empty. I am getting no console errors.

HTML/Alpine Markup:

<div x-data="data()">
  <template x-for="recipe in data.recipies">
    <div>
      <h3 x-text="recipe.title"></h3>
      <template x-for="ingredient in data.recipes.ingredients">
        <p>TEST</p>
      </template>
    </div>
  </template>
</div>

The JS file:

const data = () => {
    return {
        data: {
            recipies: [],
        },
        init() {
            fetch('src/recipies.json')
                .then((res) => {
                    return res.json();
                })
                .then((data) => {
                    this.data.recipies = Object.values(data)
                });
        },
    };
};

The JSON file:

{
    "aglioolio": {
        "id": 1,
        "title": "Aglio Olio + Chili",
        "ingredients": ["Spaghetti", "Olive oil", "Garlic", "Chili"]
    },
    "tortellinisoup": {
        "id": 2,
        "title": "Tortellini Soup",
        "ingredients": ["Tortellini", "Veggie Broth", "Chieves"]
    }
}

Why the check Number(undefined) === NaN fails? [duplicate]

Can anyone explain this:

{25 Apr 20:15}~ ➭ node                   
Welcome to Node.js v20.18.2.
Type ".help" for more information.
> +undefined
NaN
> NaN
NaN
> +undefined === NaN
false
> Number(undefined) == NaN
false

Even though Number(undefined) is NaN (not a number). But when i compare it with NaN it fails. Both using == and === operators.

How to create a function to determine the current school grade based on graduation year and month [closed]

I’m trying to create a function in TypeScript like the one below:

getSchoolGradeLabel(gradYear: number, gradMonth: number): string

This function takes the graduation year (gradYear) and graduation month (gradMonth) as arguments and returns a string indicating the current school grade, such as:

  • Junior High School Year 1
  • Junior High School Year 2
  • Junior High School Year 3
  • Senior High School Year 1
  • Senior High School Year 2
  • Senior High School Year 3
  • If the student has already graduated → “Graduated in XXXX”

The timing of the school year change depends on the graduation month:

Graduation Month Grade Transition Timing
March April 1st of the following year
June July 1st of the same year
September October 1st of the same year
December January 1st of the following year

For example, as today is April 25, 2025, the result of calling:

getSchoolGradeLabel(2029, 3)

should be: “Junior High School Year 2”.

How can I enforce code integrity for a locally installed (unpacked) Chrome extension so it refuses to run if tampered with?

Background

I’m developing a Chrome extension distributed locally in “unpacked” mode, outside of the Chrome Web Store. I need a way to guarantee that if any part of the extension’s code (JS, HTML, CSS, manifest, etc.) is modified, the extension immediately stops working—similar to the signature-based protection that Chrome Store extensions enjoy.

What I’ve Tried

  • There is an existing discussion from 12 years ago on Stack Overflow:
    How to check the authenticity of a Chrome extension?
    The primary recommendation was to obfuscate the code. Obfuscation only slows down reverse-engineering; it does not prevent actual code modification.

  • Obfuscation adds friction but does not enforce integrity.

Question

In 2025, is there any reliable technique or standard that allows embedding a cryptographic signature or verified hash within an unpacked extension so that, at startup or runtime, the extension can:

  • Detect if any internal file has been altered (beyond a simple hard-coded checksum).

  • Halt its own execution if the integrity check fails.

Examples of approaches I’m curious about:

  • A form of code signing that can be performed locally and verified by the extension’s own scripts.

  • Remote attestation: fetching an externally signed manifest and validating it offline.

  • Leveraging Service Workers, WebAssembly, or Native Messaging for more secure tamper-detection.

  • Any open-source libraries or commercial solutions specifically designed for tamper detection in unpacked Chrome extensions.

Additional Details

  • Using Manifest V3.

  • Must work when installed manually via .zip or by loading a folder in chrome://extensions.

  • Upon detecting tampering, the extension should disable itself or display an “Invalid code” warning.

What modern approaches or technologies do you recommend to achieve robust code integrity and tamper-detection for an unpacked Chrome extension?

Why Is pLimit() Not A Function?

I have a class that controls a list of ips. Every single item in that list is an instance of another class, that controls data around a specific ip. One of the methods of each ip, is the ability to search itself on a website.

With Promise.All, I reach the common parallel request flooding issue; decided to use p-limit to solve this. However, instead of creating a concurrency limit on my parallels calls of Promise, pLimit() simply causes an error, because it isn’t being recognized as a function.

import NeoIp from './NeoIp.js';
import { v4 as uuidv4 } from 'uuid';
import pLimit from 'p-limit'; //Attempted this, and the two at the bottom.
//import * as pLimitModule from 'p-limit';
//const pLimit = pLimitModule.default || pLimitModule;

class NeoIpList {
// [...] Abbreviated

    async arinSearchAll() {
        // Arin has a daily api limit of 100,000
        // Maximum of 10 calls per second.
        const alreadySearched = new Set(); // More appropriate than Map here

        // --------------------------
        //#region pLimit, Concurrency
        // --------------------------

        try {
            const alreadySearched = new Set(); // More appropriate than Map here
            const limit = pLimit(5); // Limit to 5 concurrent requests

            const tasks = this.list
                .map((singleIp) => {
                    if (!alreadySearched.has(singleIp)) {
                        alreadySearched.add(singleIp);
                        return limit(() => singleIp.arinSearchSingle());
                    }
                    return null;
                })
                .filter(Boolean); // Remove nulls from already-searched IPs

            const results = await Promise.all(tasks);
            return results;
// [...] No longer relevant.
TypeError: pLimit is not a function

Aside from checking the different, commented-out approaches above, I’ve also gone ahead and verified that p-limit is, in fact, downloaded with npm show p-limit, and the result is as follows:

npm show p-limit

[email protected] | MIT | deps: 1 | versions: 19
Run multiple promise-returning & async functions with limited concurrency
https://github.com/sindresorhus/p-limit#readme

keywords: promise, limit, limited, concurrency, throttle, throat, rate, batch, ratelimit, task, queue, async, await, promises, bluebird

dist
.tarball: https://registry.npmjs.org/p-limit/-/p-limit-6.2.0.tgz
.shasum: c254d22ba6aeef441a3564c5e6c2f2da59268a0f
.integrity: sha512-kuUqqHNUqoIWp/c467RI4X6mmyuojY5jGutNU0wVTmEOOfcuwLqyMVoAi9MKi2Ak+5i9+nhmrK4ufZE8069kHA==
.unpackedSize: 10.3 kB

dependencies:
yocto-queue: ^1.1.1

maintainers:
- sindresorhus <[email protected]>

dist-tags:
latest: 6.2.0

published 4 months ago by sindresorhus <[email protected]>

Could use a few more ideas on troubleshooting this.

Alignment for seachbar in the header

enter image description here

Above you can see my issue. Im having trubble making it so that the search bar stays within the header. What do I do? enter code here

enter code here 
/* Header Search Styles */
.search-container-header {
    background-color: var(--light-green) !important;
    max-width: 30vw; 
    margin-top: 1rem;
    border: 2px solid rgba(255, 255, 255, 0);
    border-radius: 28px;
    height: 6vh;
    padding: 0.5rem; 
    box-sizing: border-box;
     margin: 0; 
  }
.search-wrapper-header{
  display: flex; /*not doing anything :(((*/
}

.input-search-header {
  font-size: 1rem;
  width: calc(100% - 2.8rem);
  background-color: var(--light-green) !important;
  border: 2px solid transparent;  
  border-radius: 5px;
  outline: none; 
  height: 2rem; 
  color: var(--dark-green);
  }
 /* When the search bar is visible */
.search-wrapper-header.active .search-container-header {
display: block; /* Make it visible when active */
}
   /* code from other doc */
   header {
     background-color: var(--red);
     height: 5rem;
     position: relative; /* Allow absolute positioning of inner elements */
     z-index: 10;
    }

    nav a {
    color: var(--off-white);
    text-decoration: none;
    }

    .nav-space {
      display: flex;
      justify-content: space-between;
      }

     nav ul {
      display: flex;
      list-style: none;
      justify-content: flex-end;
      }

       /*html added for searsh bar in js:*/

       enter code here 
       <div class="search-container-header">
         <input class="input-search-header" type="search" id="search-header" data-    search="header">
       </div>
       <div class="search-show-header" data-show-container></div>
       <template data-content-template>
         <div class="title-content-header">
            <p class="search-result-header" data-title></p>
         </div>
       </template>

Interception xhr requests after pressing the load more button with puppeteer

Initially two json files arrive on the site – the rest arrive after clicking the ‘load more’ button. I’m trying to intercept all requests. The example shows how I am waiting for the button to appear and click it accordingly. But so far I’m capturing only two requests – although there should be three, because I’ve already pressed the button once.

How can I wait for the rest of the xhr to intercept after pressing the ‘load more’ button?

const grab = async(url) => { 
  const browser = await puppeteer.launch({ headless: false});
  const page = await browser.newPage();

  await page.setRequestInterception(true);
  page.on("request", async (request) => {
    const current = await request.url();
    if (current.includes('betty-variants')) {
     console.log(request.url())
    }
  //This clicking not working here, the page does not see this selector
  // await page.waitForSelector('.well-sm.well p.text-primary.pull-left span', { timeout: 5000})
  // await page.click('.well-sm.well p.text-primary.pull-left span')


// Allow the request to be sent
    await request.continue();
  });

  await page.goto(url, { waitUntil: 'networkidle2' });

  await page.waitForSelector('.well-sm.well p.text-primary.pull-left span');      
  await page.click('.well-sm.well p.text-primary.pull-left span')

  await browser.close(); 
};

I tried getting the data after clicking on the button, but I only get the standard two json responses from the site.

Why my input validation function and mask for it are not working?

I have a problem. There is a parent component Form/index.vue , which contains an input for a phone number, it is linked to v-model. But for some reason, validating the mask using a function in the parent component Input does not work, only in mozilla

form component input

<MainPageFormNumberInput
  :error="inputErrorsVar.numberError"
  v-model="form_data.number"
    @update:error="updateNumberError"
   />` 
connects to the field 
`const form_data = reactive({
  fio: "",
  class: "",
  number: "",
  email: "",
  direction: "",
});

MainPageFormNumberInput :

<template>
  <CustomInput
    :text="'Number'"
    :error="error"
    v-model="model"
    @input="formatPhone"
    @focus="getPrefix"
    @blur="removePrefix"
    @update:error="$emit('update:error', $event)"
  />
</template>

<script setup>
const props = defineProps({
  error: {
    type: Boolean,
  },
});
const emits = defineEmits(["update:error"]);
const model = defineModel();
const phoneNumber = ref("");
const formatPhone = (event) => {
  let numbers = event.target.value.replace(/D/g, "");

  if (numbers.length > 0 && numbers[0] !== "7") {
    numbers = "7" + numbers.substring(1);
  }
  numbers = numbers.substring(0, 11);
  phoneNumber.value = numbers.length > 0 ? "+" + numbers : "";
  let formatted = "+7";
  if (numbers.length > 1) {
    formatted += " (" + numbers.substring(1, 4);
  }
  if (numbers.length > 4) {
    formatted += ") " + numbers.substring(4, 7);
  }
  if (numbers.length > 7) {
    formatted += " " + numbers.substring(7, 9);
  }
  if (numbers.length > 9) {
    formatted += "-" + numbers.substring(9, 11);
  }
  model.value = formatted;
};

const getPrefix = (e) => {
  if (e.target.value.length === 0) {
    model.value = "+7";
  }
};
const removePrefix = (e) => {
  if (e.target.value === "+7") {
    model.value = "";
  }
};
</script>

Custom input :

<template>
  <div class="input-field" :class="{ 'has-error': showError }">
    <input
      required=""
      :placeholder="placeholder"
      autocomplete="off"
      :type="type"
      name="text"
      :id="text"
      v-model="model"
      @blur="blurHandler"
      @focus="focusHandler"
      @input="inputHandler"
    />
    <label :for="text">
      {{ text }}
    </label>
  </div>
</template>

<script setup>
const emits = defineEmits(["blur", "focus", "input", "update:error"]);
const props = defineProps({
  text: String,
  placeholder: {
    type: String,
    required: false,
  },
  type: {
    type: String,
    required: false,
    default: "text",
  },
  error: {
    type: Boolean,
    default: false,
  },
});

const model = defineModel();
const isDirty = ref(false);

const showError = computed(() => {
  return props.error && model.value.length > 0;
});
function blurHandler(event) {
  isDirty.value = true;
  emits("blur", event);
}

function focusHandler(event) {
  emits("focus", event);
}

function inputHandler(event) {
  emits("input", event);
}
watch(model, (newVal) => {
  if (newVal.length === 0 && props.error) {
    emits("update:error", false);
  }
});

I searched a lot of information on this, read the documentation, asked the gpt chat and tried to use a bunch of props and emits instead of defineModel, but it didn’t give any results

Remove trailing decimals without rounding up [duplicate]

For example, I have a number 123.429. How can I remove the trailing decimals without rounding up to two decimal places. Hence, I need the number to be up to one decimal point i.e. 123.4

-0.5 to -0.58 to -0.5(output)
-0.9 to -0.99 to -0.9(output)

-1.00 to -1.09 to -1.0(output)
-1.10 to -1.19 to -1.1 (output)
-1.9 to -1.99 to -1.9(output)

How to achieve this in JavaScript?

When the Like/Dislike button is pressed, the counter increases on the first click and decreases on the second

there is a working example of a comment rating. Everything works (when you press like, it’s plus 1, when you press dislike, it’s minus 1) All that needs to be done is to return everything to its original state when the button is pressed again. .

<?
// Checking the id of the evaluated comment received via javascript
if (isset($_POST["comm_id"]) and is_numeric($_POST["comm_id"]))
    $obj = $_POST["comm_id"];
else $obj = '';

// Checking the "rate" sent via JS with a value of 1
if (isset($_POST["rate"]) and ($_POST["rate"] == 0 or $_POST["rate"] == 1))
    $rate = $_POST["rate"];
else $rate = '';

if ($rate != '' and $obj > 0) {
    $rating_plus = 0;
    $rating_minus = 0;

    if ($rating_plus == 0 and $rating_minus == 0) {
        if ($rate == 0) $rating_minus = $rating_minus + 1;
        else $rating_plus = $rating_plus + 1;
    }
    
    else {
        if ($rate == 0) {
            $rating_minus = $rating_minus + 1;
            $rating_plus = $rating_plus - 1;
        } else {
            $rating_minus = $rating_minus - 1;
            $rating_plus = $rating_plus + 1;
        }
        
    }

    //Calculating the rating of a comment

    $sum = $rating_plus - $rating_minus;        
   
    if ($sum < 0) $color_sum = '#865656';
    else {
        $color_sum = '#688656';
        if ($sum == 0) $color_sum = '#888';
    }
    
    $rating_sum = '<b style="color: '.$color_sum.'">'.$sum.'</b>';
    
   // Forming a response
    $output = ['rating_sum' => $rating_sum];
    exit(json_encode($output));
}



//Calculating the rating of a comment
$sum = $Row["plus"] - $Row["minus"];
if ($sum < 0) $comm_rate = '<b style="color: #865656">'.$sum.'</b>';
    else {
        $comm_rate = '<b style="color: #688656">'.$sum.'</b>';
        if ($sum == 0) $comm_rate = '<b style="color: #888">'.$sum.'</b>';
    }
// --/-- //  

$Row["id"] = 4;        
        
$com_rating = '
<div class="rating_com">
    <div class="comm_plus">Like</div>
    <div class="comm_rate" id="rating_comm'.$Row["id"].'">
        '.$comm_rate.'
    </div>
    <div class="comm_minus">Dislike</div>
</div>';


echo '
    <div class="comments" id="m'.$Row["id"].'">
        <div class="com_block">         
            <div class="name">$Name</div>
            <div class="companel">
                '.$com_rating.'
            </div>
            <p>$Row["text"]</p>
    </div>';

?>


<script>
    
document.querySelectorAll('.comm_plus,.comm_minus,.comm_rate').forEach(arm =>{
    arm.addEventListener('click', e => {
        var id_comm = e.target.closest(".comments").getAttribute('id').substr(1); // we get the id of the rated comment and trim the first letter.
        // Check if "comm_plus" was pressed, then the value "1" will be sent to $_POST['rate']
        if (arm.classList.contains("comm_plus")) var num = 1;
        if (arm.classList.contains("comm_minus")) var num = 0;
    
        var xmlhttp = getXmlHttp(); 
        xmlhttp.open('POST', '/news/material', true); 
        xmlhttp.responseType = 'json';
        xmlhttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
        xmlhttp.send(`rate=${num}&comm_id=` + encodeURIComponent(id_comm)); 
        xmlhttp.onreadystatechange = function() { 
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) { 
                const response = xmlhttp.response;               
                var com_rate = document.getElementById(`rating_comm`+id_comm);
                com_rate.classList.add('_active');
    
                setTimeout(() => { 
                    com_rate.classList.remove('_active');
                    com_rate.innerHTML = `${response.rating_sum}`; 
                }, 500);
            }
        };
            
    });
});

// The function creates an XMLHTTP object to send data to a POST request (without using an html form) 
function getXmlHttp() {
    var xmlhttp;
    try {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
        try {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } catch (E) {
            xmlhttp = false;
        }
    }
    if (!xmlhttp && typeof XMLHttpRequest!='undefined') xmlhttp = new XMLHttpRequest();
    return xmlhttp;
}

</script>



<style>
.comments {width: 60%; margin: 4em 2em; border: 2px solid grey; border-radius: 10px; padding: 1em}
.com_block .name {display: inline-block; margin: 0 0 7px;}
.com_block .companel {float: right; color: #6A6E68;}
.comment_edit {padding: 6px}
.comment_edit #button {margin-top: 4px}
.rating_com {margin: 0 5px 0 9px}
.rating_com div {display: inline-block}
.comm_minus, .comm_plus {cursor: pointer}
</style>