We help IT Professionals succeed at work.
Troubleshooting Question

Need help calling a Perl Script from a Google Maps JavaScript

117 Views
Last Modified: 2020-09-21
Currently my Google Maps Javascript has a Mouse Click Event defined:

// Configure the click listener.
map.addListener('click', function(mapsMouseEvent) {
// Create a new InfoWindow.
  infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
  infoWindow.setContent(mapsMouseEvent.latLng.toString());
  infoWindow.open(map);
});

I need to call a Perl Script and pass the latitude and longitude of the Mouse Click to the Perl script from my Google Maps Javascript..

The Perl script will calculate the distance and bearing from the last mouse click to the current mouse click.  

Here is an example of calling the Perl script from a Linux command line:

]# perl BRData.pl -16.7097  -150.9753
-16.7097  -150.9753  Distance: 0.0 nm

# perl BRData.pl -16.1037 -150.2667                                                                
-16.1037  -150.2667  Distance: 55 nm, Bearing: 48

The first call to BRData.pl stores the mouse click latitude and longitude.

The second call to BRData.pl calculates the Distance and Bearing from the first mouse position to the current mouse position.

In Google Maps, I think, but am not sure, the latitude and longitude are "e.latlng.lat" and "e.latlng.lng".  I

 need to call the Perl Script "BRData.pl" and pass "e.latlng.lat" and "e.latlng.lng", and capture the Perl script stdout output line, "  -16.1037  -150.2667  Distance: 55 nm, Bearing: 48".

I then would like to print the stdout output line in the Google Maps "infowindow" popup.  

I have not been able to successfully call the Perl Script  BRData.pl  from my Google Maps Javascript.  

I tried using the "exec" function in nodejs, but that is not working:

// Configure the click listener.
map.addListener('click', function(mapsMouseEvent) {
 
// Create a new InfoWindow.
  infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
 
const { exec } = require("child_process").exec;
exec("perl /var/www/cgi-bin/skipper/BRData.pl mapsMouseEvent.latLng.toString()");
 
//    infoWindow.setContent(mapsMouseEvent.latLng.toString());
    infoWindow.setContent($(stdout));
 
  infoWindow.open(map);
});

My nodejs rpm installation is:

nodejs-child-process-close-0.1.1-2.el6.noarch
nodejs-0.10.48-3.el6.x86_64

I would really appreciate some help on calling my BRData.pl from my Mouse Click Event in my Google Maps javascript.

For a Perl script to call the BRData.pl script, this could be done in a single line:

$text = `perl $dir/BRData.pl  $lat2 $long2`;

Basically I need the Javascript equivalent of that single Perl line calling the Perl script BRData.pl, and capturing the STDOUT generated by the Perl Script..    

Maybe the lat and long for the mouse click is not "e.latlng.lat" and "e.latlng.long" ??  
Maybe my call to  the nodejs function "exec" has a mistake.  
Maybe the output of "exec" is not "STDOUT". is not "$(stdout).  .

It appears from my debugging that my Perl Script BRData.pl is never being call from my Google Maps Javascript.

I would really appreciate some help with this problem.  

Thanks,
Jim West
 





Comment
Watch Question

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
jimtwest3Retired

Author

Commented:
Because the API only returns the distance and not the bearing.  
This is a navigation problem, where we would need both the distance the bearing.

If we want to travel from point A to point B, and know the distance to travel to point B, then when we leave point A, we need the direction to travel to point B.

Calculating the distance and bearing  is a very simple calculation in a Perl script, and it should be simple to call a Perl script from a javascript, but I don't know how, and my knowledge of Google Maps is limited

Calling a Perl script from a Perl script is a simple single Perl script line:

$text = `perl BRData.pl  $lat2 $long2`;

where $lats and $long2 would be the current mouse latitude and longitude,
and the output of the Perl script would be returned in the $text variable.

Hopefully, calling a Perl Script, a Shell script, or a system command, from a Javascript must also be simple, but I don't know Javascript, and my knowledge of Google Maps is limited ....

All help and suggestions appreciated.

Thanks,
Jim
:




leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
and that Perl script can't be translated to JavaScript ?
jimtwest3Retired

Author

Commented:
I don't know Javascript, and I do have a working Perl script.
It should be simpler to call a Perl script from a Java Script than to completely re-write the Perl script into a Javascript.
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
Everyone should win something if you try to convert that perl to JavaScript with some help..
anyway, try this :
    const { execSync } = require("child_process").execSync;

    const lat = mapsMouseEvent.lat.toString(); // you don't really to append toString()...
    const lng = mapsMouseEvent.lng.toString(); // you don't really to append toString()...
    const stdout = execSync("perl /var/www/cgi-bin/skipper/BRData.pl " + lat + " " + lng);

//    infoWindow.setContent(mapsMouseEvent.latLng.toString());
    infoWindow.setContent(stdout);
https://nodejs.org/api/child_process.html#child_process_child_process_execsync_command_options 
jimtwest3Retired

Author

Commented:

Thanks for your suggestion !.

Given your suggestion, this is what I tried:

// Configure the click listener.
map.addListener('click', function(mapsMouseEvent) {
 
    const { execSync } = require("child_process").execSync;
 
    const lat = mapsMouseEvent.lat.toString(); // you don't really to append toString()...
    const lng = mapsMouseEvent.lng.toString(); // you don't really to append toString()...
    const stdout = execSync("perl /var/www/cgi-bin/skipper/BRData.pl " + lat + " " + lng);
 
// Create a new InfoWindow.
  infoWindow = new google.maps.InfyyoWindow({position: mapsMouseEvent.latLng});
 
//    infoWindow.setContent(mapsMouseEvent.latLng.toString());
    infoWindow.setContent(stdout);
 
  infoWindow.open(map);
});

For some reason, my Perl Script BRData.pl is still not being executed, and the new infowindow is not being created.

I verified that BRData.pl  is not being executed by adding an "echo" line to the top of the script:

;#!/usr/bin/perl -w
#
$ret = `echo "test 111213 $ARGV[0]  $ARGV[1]" >> /tmp/test.txt`;
 
Earlier, I used yum to install nodejs, and the following nodejs rpm are installed:

nodejs-child-process-close-0.1.1-2.el6.noarch
nodejs-0.10.48-3.el6.x86_64

Your thoughts are appreciated.

Thanks,
Jim

jimtwest3Retired

Author

Commented:
Hi,

You can execute this html script by pointing your browser to:

https://kjm.positiondatabase.com/Track/ComposeJ3.html

Thanks,
Jim



jimtwest3Retired

Author

Commented:
Hi,

If you would like to see what the infowindow looks like go to:

https://kjm.positiondatabase.com/Track/ComposeJ.html

As you move your cursor around the map, you will see the latitude and longitude of your cursor above the upper left side of the map.

If you click on any position on the map, the infowindow will popup and you will see the latitude and longitude of the location that you clicked on.

The purpose of the BRData.pl Perl script is to calculate the distance and bearing between two click positions.
Should be easy ... ouch ..

Thanks,
Jim

jimtwest3Retired

Author

Commented:
The ComposeJ.html script is the script without any changes to call BRData.pl.

jimtwest3Retired

Author

Commented:
ComposeJ.html    ComposeJ3.html    BRData.pl

Attached are the ComposeJ.html script,  the ComposeJ3.html script, and the Perl BRData.pl script.

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
You can display the command ran by adding a console.log so you can check if everything look fine :
(hope you start nodejs from a command line...)

// Configure the click listener.
map.addListener('click', function(mapsMouseEvent) {

    const { execSync } = require("child_process").execSync;

    const lat = mapsMouseEvent.lat.toString(); // you don't really to append toString()...
    const lng = mapsMouseEvent.lng.toString(); // you don't really to append toString()...
    const cmd = "perl /var/www/cgi-bin/skipper/BRData.pl " + lat + " " + lng;
    console.log(cmd);
    const stdout = execSync(cmd);

// Create a new InfoWindow.
    infoWindow = new google.maps.InfyyoWindow({position: mapsMouseEvent.latLng});

//    infoWindow.setContent(mapsMouseEvent.latLng.toString());
    infoWindow.setContent(stdout);

    infoWindow.open(map);
});

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
We need distance2.pl  and bearing2.pl

my $DistanceNM = `perl $dir/distance2.pl $lat1  $long1  $lat2  $long2`;
#
$DistanceNM = $DistanceNM + 0.50;
$DistanceNM = int($DistanceNM);
#
my $r_brng = `perl $dir/bearings2.pl $lat1  $long1  $lat2  $long2`;
#
my $MyBrng = int($r_brng);
#
$DistanceMiles = int($DistanceNM*1.15078 + 0.5);
$DistanceMiles = int($DistanceNM*1.15078 + 0.5);
#
$text = "$lat2  $long2  Distance: $DistanceNM nm, Bearing: $MyBrng";
#


jimtwest3Retired

Author

Commented:
distance2.pl      bearings2.pl

Attached are distance2.pl and bearing2.pl

Thanks,
Jim

jimtwest3Retired

Author

Commented:
Hi,
This is the first time that I have used nodejs.
I searched yum for nodejs child and did a yum install:

#  yum install nodejs-child-process-close.noarch

This installed:
:
nodejs-child-process-close-0.1.1-2.el6.noarch
nodejs-0.10.48-3.el6.x86_64

I just started to install "npm",

# yum install npm.noarch

This install wants to install 87 packages, and upgrade 9 packages.

That is a huge installation.

This makes me wonder if nodejs is installed correctly.

My server is being used to host a web server used by several people.
I do not want to damage my web server.
Do I need to install npm ??
Is having npm  install 87 packages and upgrade 9 packages safe ???
Does this indicate that nodejs is not completely installed ?

Thanks,
Jim

jimtwest3Retired

Author

Commented:
Hi,

Is there another way to execute a system level command from javascript without using node.js ??

I looked at "AJAX", and thought  that it was unnecessarily complex for this simple requirement.

I am retired from IT.  I spent the first 20 years of my career in scientific programming,  primarily with Fortran at Oak Ridge National Lab, and Los Alamos National Laboratory.  .
I then spent years working with C, Bournce Shell, Perl while working at IBM for 11 years..  

I  I can't imagine a serious scripting language without the ability to run a system level command.  That should be a very basic level requirement for any major scripting language.  

I then spent 16 ysers  involved with System support, and large commercial software server installations supporting millions of mail clients.  

I don't understand why executing a simple system level command from a scripting language has to be so complicated.

Your thoughts appreciated.    

Thanks,
Jim
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
distance :
const PI = Math.atan2(1,1) * 4;

function distance(lat1, lon1, lat2, lon2, unit) {
    if ((lat1 == lat2) && (lon1 == lon2)) {
        return 0;
    }
    else {
        theta = lon1 - lon2;
        dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
        dist  = Math.acos(dist);
        dist = rad2deg(dist);
        dist = dist * 60 * 1.1515;
        if (unit === "K") {
            dist = dist * 1.609344;
        } elsif (unit === "N") {
            dist = dist * 0.8684;
        }
        return (dist);
    }
}

function acos(rad) {
    return Math.atan2(Math.sqrt(1 - Math.pow(rad,2), rad);
}

function deg2rad(deg) {
    return (deg * PI / 180);
}

function rad2deg(rad) {
    return (rad * 180 / PI);
}

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
bearing (without PI constant /!\) :

function bearing(lat1, lon1, lat2, lon2) {
    const d_lon = lon2 - lon1;
    const y = Math.sin(d_lon) * Math.cos(lat2);
    const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon);
    const rad = Math.atan2(y, x);
    let deg = rad * (180 / PI);
    return deg < 0 ? deg += 360 : deg;
}

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
const PI = Math.atan2(1,1) * 4;
var stacks = [];

// Configure the click listener.
map.addListener('click', function(mapsMouseEvent) {
    stacks.push(mapsMouseEvent.latLng);
    if(stacks>=2) {
        // Create a new InfoWindow.
        infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
        // infoWindow.setContent(mapsMouseEvent.latLng.toString());
        const pos1 = stacks[stacks.length-2];
        const pos2 = stacks[stacks.length-1];
        const stdout = distance(pos1.lat, pos2.lng, pos2.lat, pos2.lng, "N") + "<br>" + bearing(pos1.lat, pos2.lng, pos2.lat, pos2.lng);
        infoWindow.setContent(stdout);
        infoWindow.open(map);
    }
});

function distance(lat1, lon1, lat2, lon2, unit) {
    if ((lat1 == lat2) && (lon1 == lon2)) {
        return 0;
    }
    else {
        theta = lon1 - lon2;
        dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
        dist  = Math.acos(dist);
        dist = rad2deg(dist);
        dist = dist * 60 * 1.1515;
        if (unit === "K") {
            dist = dist * 1.609344;
        } elsif (unit === "N") {
            dist = dist * 0.8684;
        }
        return (dist);
    }
}

function acos(rad) {
    return Math.atan2(Math.sqrt(1 - Math.pow(rad,2), rad);
}

function deg2rad(deg) {
    return (deg * PI / 180);
}

function rad2deg(rad) {
    return (rad * 180 / PI);
}

function bearing(lat1, lon1, lat2, lon2) {
    const d_lon = lon2 - lon1;
    const y = Math.sin(d_lon) * Math.cos(lat2);
    const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon);
    const rad = Math.atan2(y, x);
    let deg = rad * (180 / PI);
    return deg < 0 ? deg += 360 : deg;
}
jimtwest3Retired

Author

Commented:
I found the following suggestion:
function exec(cmd, handler = function(error, stdout, stderr){console.log(stdout);if(error !== null){console.log(stderr)}})
{    const childfork = require('child_process');    return childfork.exec(cmd, handler);
}
This function can be easily used like:
exec('echo test');
//output:
//test
 exec('echo test', function(err, stdout){console.log(stdout+stdout+stdout)});
//output:
//testtesttest
   
This looks like a self contained "exec" function.
Is there a way to use this approach ??
Where does the output from the Perl Script go ??

This suggestion was found at::

https://stackoverflow.com/questions/1880198/how-to-execute-shell-command-in-javascript#20638212

Your thoughts appreciated.

Thanks,
Jim



jimtwest3Retired

Author

Commented:
My question is how can a Perl script be run from a JavaScript.
That is a very basic technical question.
It should be simple.
I have many Perl scripts, and Perl is in my cases my preferred language.
I want  to run a Perl Scripts from a Javascript.
I have no doubt that Javascripts can be run from Javasctipts, but that is not my question.

Jim

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
test page : https://jsfiddle.net/5k6a1ovw/2/ 

code with corrections :

  const PI = Math.atan2(1,1) * 4;
  var stacks = [];


  // Configure the click listener.
  map.addListener('click', function(mapsMouseEvent) {
      stacks.push(mapsMouseEvent.latLng);
      if(stacks.length>=2) {
          // Create a new InfoWindow.
          infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
          // infoWindow.setContent(mapsMouseEvent.latLng.toString());
          const pos1 = stacks[stacks.length-2];
          const pos2 = stacks[stacks.length-1];
          const stdout = distance(pos1.lat(), pos2.lng(), pos2.lat(), pos2.lng(), "N") + "<br>" + bearing(pos1.lat(), pos2.lng(), pos2.lat(), pos2.lng());
          infoWindow.setContent(stdout);
          infoWindow.open(map);
      }
  });


  function distance(lat1, lon1, lat2, lon2, unit) {
      if ((lat1 == lat2) && (lon1 == lon2)) {
          return 0;
      }
      else {
          theta = lon1 - lon2;
          dist = Math.sin(deg2rad(lat1)) * Math.sin(deg2rad(lat2)) + Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2)) * Math.cos(deg2rad(theta));
          dist  = Math.acos(dist);
          dist = rad2deg(dist);
          dist = dist * 60 * 1.1515;
          if (unit === "K") {
              dist = dist * 1.609344;
          } else if (unit === "N") {
              dist = dist * 0.8684;
          }
          return (dist);
      }
  }


  function acos(rad) {
      return Math.atan2(Math.sqrt(1 - Math.pow(rad,2), rad));
  }


  function deg2rad(deg) {
      return (deg * PI / 180);
  }


  function rad2deg(rad) {
      return (rad * 180 / PI);
  }


  function bearing(lat1, lon1, lat2, lon2) {
      const d_lon = lon2 - lon1;
      const y = Math.sin(d_lon) * Math.cos(lat2);
      const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon);
      const rad = Math.atan2(y, x);
      let deg = rad * (180 / PI);
      return deg < 0 ? deg += 360 : deg;
  }


jimtwest3Retired

Author

Commented:
Your Bearing in your test case, and on my installation are always returns  "0"  or "180".
Your Bearing function has a problem.

Jim

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
here a correction :

  function bearing(lat1, lon1, lat2, lon2) {
      lat1 = lat1 * PI / 180;
      lon1 = lon1 * PI / 180;
      lat2 = lat2 * PI / 180;
      lon2 = lon1 * PI / 180;


      const d_lon = lon2 - lon1;
      const y = Math.sin(d_lon) * Math.cos(lat2);
      const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(d_lon);
      const rad = Math.atan2(y, x);
      let deg = rad * (180 / PI);
      return deg < 0 ? deg += 360 : deg;
  }
jimtwest3Retired

Author

Commented:
Please print out the latitude and longitude with the distance and bearing.
Then you need to compare your results with the BRData.pl script.
Let's compare your results with the BRDdata.pl script.
That is the best way to verify the results.
jimtwest3Retired

Author

Commented:
Please print out the latitude and longitude with the distance and bearing.
Then you need to compare your results with the BRData.pl script.
Let's compare your results with the BRDdata.pl script.
That is the best way to verify the results.
jimtwest3Retired

Author

Commented:
Hi,
A friend suggested using AJAX to interface between Javascript and Perl, and that appears to be a good solution.
I also found another approach that is simple, where I convert my Perl script to a Perl CGI web server, and pass it the position paramters in the http URL.  Both of these approaches are good solutions for me.  I am disappointed that Javascript does not have an easy way to run system commands from inside a Javascript..  In my Solution Request, I really wanted to learn how to interface a perl script with a javascript.  I have many perl scripts.  Both javascript and perl have their advantages for different applications in different applications.   Thanks, Jim

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
I tried using the "exec" function in nodejs, but that is not working: 
I don't why you're running Google Maps and the onclick event on the server side.
Or maybe,
You don't know nodejs run on the server side and you decide to use a nodejs function in a browser.
If that would be possible someone would be able to run a perl script at your issue.

So to be clear, you CAN'T run the exec or execSync function on the client side (browser).

A friend suggested using AJAX to interface between Javascript and Perl 
So, ok, friend suggestion are the best.
Ajax allow you to call server code from the browser without posting/reloading the current page.
That seems to be good.
I really wanted to learn how to interface a perl script with a javascript.
I think you know why you can't find an easy solution now

IMHO, the bearing function is so short, if you decided to take time to compare your Perl script and the JavaScript version, I'm pretty sure you should be able to know why they don't return the same value but this is not your friend or your suggestion...

jimtwest3Retired

Author

Commented:
I have verified the bearing results from my Perl script from a couple of independent sources, so I have confidence in the results..Your function is returning bearings that are different.

My goal was to find a solution where I can call perl scripts from javascript.
This is a general problem, and is not specific to this specific script.

You spent your time re-writing a perl script to a javascript.
That is fine, but my problem was to find a way to call a perl script from a java script.
If you know a workable solution to that question, feel free to demonstrate it.

I strongly agree that a perl script can be re-written into a javascript, and
I agree that one javascript can be embedded inside another javascript, and successfully used, but that was not my question.
If javascript is such a great scripting language, why can't it interface with system level commands.

Thanks
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
My goal was to find a solution where I can call perl scripts from javascript.

So the title should be : Need help calling a Perl Script from JavaScript

Usualy this is done using by putting the perl script in the webserver (usualy Apache httpd) cgi-bin folder
You call the script using :
http://your-web-server/cgi-bin/yourscript.pl

you need your apache httpd.conf to be propely configured to allow this dangerous folder be accessed from a browser...

If javascript is such a great scripting language, why can't it interface with system level commands. 
javascript is originaly designed to run at the client side (inside a browser) and you don't want to allow people calling dangerous server side script from a browser
with nodejs, javascript run on the server side, it's possible but in your example (a click in browser CAN'T fire a server side process without using Ajax or refreshing the page(and you probably don't want to reload the map every click so Ajax would be the way to go)

So your solution seems to be the use of the cgi-bin folder + ajax

jimtwest3Retired

Author

Commented:
Hi,

I have made progress debugging my problem, but I need help on several Google Map questions
.
My Perl CGI script was not being called by my addListener function, because I needed to install a javascript node-fetch module. After installing that module, I can now call my Perl CGI script, and pass the latitude and longitude variable to it.

Here is a small javascript test script, Script5.js, that I can run with "node Script5.js"
This script works fine running standalone:
 
const fs = require('fs');
const fetch = require('node-fetch');
 
src=fetch("https://kjm.positiondatabase.com/cgi-bin/Distance?lat2=-16.1037&long2=-150.2667");

fs.readFile('/tmp/DataOUT.txt', (err, data) => {
    if (err) throw err;
 
    console.log(data.toString());
})

I have tried applying this logic to my Google Map script, but I'm having problems.

My latest attempt, that is not working, is:

// Configure the click listener.
map.addListener('click', function(mapsMouseEvent) {
 
  const fetch = require('node-fetch');
 
  src=fetch('https://kjm.positiondatabase.com/cgi-bin/Distance?lat2="latclicked.toString()"&long2="longclicked.toString()"');
 
  const fs = require('fs');
  fs.readFile('/tmp/DataOUT.txt', (err, data) => {
    if (err) throw err;
  })
 
// Create a new InfoWindow.
  infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
  infoWindow.setContent(data.toString());
  infoWindow.open(map);
 
});
 
I think the latitude and longitude for the mouse click may be "latclicked" and "longclicked", but I'm not sure if
I am accessing these variables correctly ... also I do now know the format of the data being stored in these variables.

The latitude and longitude Google Map variables may be event.latLng.lat and event.latLng.lng, but I'm not sure.

What is the structure of these variables ??  I  have never used the "toString()" function to pass variables  
When is this function needed, and Why is it needed ??. .

Please tell me know the correct latitude and longitude variables  for a mouse location during a mouse click, and the format of those variables.
.
Please let me know if I need to add any logic to access those variables, and please tell me the format of the variables.

Please let me know how I should pass the Google  latitude and longitude to my Perl CGI script.
.
Do I need to add ".toString()" to the variables ??   Do I need to enclose the variables in double quotes to pass them ??

My Perl CGI script creates a single text line containing, the latitude and longitude of the mouse click, and the distance and bearing from the last mouse click:  

Here is an example
:
-16.1037  -150.2667  Distance: 55 nm, Bearing: 48 degrees

When I pass this text  to "infowindow SetContent, do I need to add ".toString()" to this variable.
The "data" variable is already a text string.  
.  
Please let me know if my text string will fit in an info window?
Do I need to set the width of the infowindow ??  If I do, how ?
Do I need to reduce the length of my text string ??

Your thoughts on these questions are appreciated..

Thanks,
Jim

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
This script works fine running standalone
When you run it from a shell or command line right ?
Please confirm the context

I have tried applying this logic to my Google Map script, but I'm having problems.
So opening a web browser, please confirm

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
try this and let me know when you get on the screen :
map.addListener('click', function(mapsMouseEvent) {
  var lat = mapsMouseEvent.latLng.lat();
  var lng = mapsMouseEvent.latLng.lng();
  alert("mouse clicked, coords are lat :" + lat + "\nlng :" + lng);
  try {
     const fetch = require('node-fetch');
    
     src=fetch(' https://kjm.positiondatabase.com/cgi-bin/Distance?lat2="latclicked.toString()"&long2="longclicked.toString()"');
    
     const fs = require('fs');
     fs.readFile('/tmp/DataOUT.txt', (err, data) => {
       if (err) throw err;
     })
    
   // Create a new InfoWindow.
     infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
     infoWindow.setContent(data.toString());
     infoWindow.open(map);
  } catch(e) {
   alert(e);  
  }
 
});
 
jimtwest3Retired

Author

Commented:
Hi,

Your alert is working, but we are seeing "ReferenceError:  require is not defined".
Take a look at:

https://kjm.positiondatabase.com/Track/ComposeM10.html

Since your alert is printing out "lat" and "lng", correctly I tried passing "lat" and "lng" in the call to the Perl Script,
instead of "latclicked" and "lngclicked", but we are still getting the ReferenceError:

https://kjm.positiondatabase.com/Track/ComposeM15.html

Since "node Script5.js"  works fine, I tried copying that into the script, but that did not help.As

As a test, I even tried copying the exact fetch line from Script5.js into ComposeM16.html, but that did not help.
Still seeing the ReferenceError: Require not defined.

It is almost as if the "const fs = require('fs')" is not being recognized.
I ran a test where I removed the require('fs') line, and that made no differece.
Still seeiing the ReferenceError: require not defined.

Those are the only 2 "require" statements in the ComposeM...  script, and that is the only occurrence of "fs"  in the entire script, so the ReferenceError is a puzzle.

Bring up the script in your browser's web console, and see if you see the problem.

Thanks,
Jim

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
Your alert is working, but we are seeing "ReferenceError:  require is not defined".
This is not a "but" but a "and"
Your alert is working AND we are seeing "ReferenceError:  require is not defined".

I don't need to go to your link because I know exactly what was going on.
You just need to understand something I already mentioned in a previous answer.

1 - NodeJS run on a server
2 - Google Maps run in a web browser.
3 - the "require" is NodeJS JavaScript code, Same for readFile, fetch. All this command is for NodeJS and not for JavaScript running in a browser.

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
the only path you've is to use cgi-bin, put your script inside this folder, configure Apache to allow execution of perl script
once its done, try to run your script from your browser

http://your-web-server/cgi-bin/yourscript.pl
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
It seems you reported this question instead answering my last answer...

There's no way to call DIRECTLY a Perl script which run on a server from a web browser.

You can (need to) :
1 - put your script in the cgi-bin folder of your server
2 - configure you web server, probably Apache HTTPD, to be allowed to run your perl scripts when someone request it from a web browser
3 - Type : http://your-web-server/cgi-bin/yourscript.pl  in your web browser to test you Perl script
4 - Once you are able to test succesfuly your Perl script you can use Ajax to call it instead typing it address in web browser address bar

JavaScript CAN'T CALL DIRECTLY a Perl script from a web browser

Let me know if something is not clear.

jimtwest3Retired

Author

Commented:
Hi,
I have made some progress.
I gave up on trying to figure out how to a Perl CGI POST and return the results of my distance calculation back to the javascript.   I looked at AJAX, but it looked really complicated, or at least I did not find the instructions on how to use it very clear, and I could not find any good examples of returning a Perl variable to a javascript.  AJAX may be a great tool, but the insturctions on how to use it need more work. I understand the security reasons that reading files on a server are so difficult in javascript.  I thought about storing the text string in local storage where the browser is running, but so many different devices make that approach confusing.  Location storage for a PC, an Android, an IPhone, a Linux server, all would be very different, so local storage would be easier but has it's own set of problems.
 I decided to have my Distance Perl CGI script store the result text string in my MySQL database.  
  I then loaded the nodejs mysql module, and created a small script to retrieve my text string from my MySQL database.   Executing the small script with "node" worked great.   Sure hope it will work empbedded in the javascript

Please take a look at:

.https://kjm.positiondatabase.com/Track/ComposeM19.html

After your lat and long alert prints out, I get a message that my "Require is not defined".  
The only require left in the the javascript is require('node-fetch'), and that is working fine in the javascript.
After that message, the javascript does not execute the infowindow lines in my addListener.

Here is the current status of my addListener:

map.addListener('click', function(mapsMouseEvent) {
 
  var lat = mapsMouseEvent.latLng.lat();
  var lng = mapsMouseEvent.latLng.lng();
  alert("mouse clicked, coords are lat :" + lat + "\nlng :" + lng);
  try {
 
const fetch = require('node-fetch');
src=fetch('https://kjm.positiondatabase.com/cgi-bin/Distance?lat2="lat.toString()"&long2="lng.toString()"');
 
var mysql      = require('mysql');
var connection = mysql.createConnection({
  host     : 'localhost',
  user     : 'xxxx',
  password : 'xxxx',
  database : 'xxxx'
});
connection.connect();
connection.query('SELECT text FROM distance', function(err, rows, fields)
{
  if (err) throw err;
  console.log(rows[0]);
});
connection.end();
 
   // Create a new InfoWindow.
     infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
     infoWindow.setContent(mapsMouseEvent.latLng.toString());
     infoWindow.setContent(rows[0].toString());
     infoWindow.open(map);
  } catch(e) {
   alert(e);
  }
 
});
 
}

I need to understand and correct the "ReferenceError: Require is not defined", and then maybe we can find out if the text string will appear in the infowindow.   Since you understand Browser Web Console debuggers really well, I would appreciate your taking a look and seeing if the text string is being retrieved correctly from the database.  The line should look like:  "text:    '-16.1037 -150.2667 Distance: 55 nm  Bearing: 48 degrees'  )"   I would like to remove "text:  ': and remove ";  )" from the line, but have not found a good string replacement method.

Thanks,
Jim

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
I need to understand and correct the "ReferenceError: Require is not defined"

As I previously said : required is unknown in a web browser JavaScript interpreter
jimtwest3Retired

Author

Commented:

I agree.  You are correct.

Instead of attempting to pass the distance and bearing back from my Perl Script to the javascript,

If possible, I would like to just pass the lat and long to my Perl CGI URL and then work on attempting to have the Perl CGI script embed  a call to alert and display the distance and bearing in a javascript  in an alert window.

If that is not possible, then I can just monitor the output files of my Perl CGI script.

The first step is to call my Perl CGI  URL and pass the latitude and longitude ... with the using the require('node-fetch').  
It must be possilbe to call a website and pass parameters in Javascript.

The Google Maps Javascript currently calls a Google URL and passes my Key with the following line:

 src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCEjevcQPtLsBV4XG9PLnqAbpmAp01k20I&callback=initMap">

I tried including the following lines::

var lat = mapsMouseEvent.latLng.lat();
var lng = mapsMouseEvent.latLng.lng();
alert("mouse clicked, coords are lat :" + lat + "\nlng :" + lng);
 
src="https://kjm.positiondatabase.com/cgi-bin/Distance?lat2=lat.toString()&long2=lng.toString()">

But .. This is not working
When I add the above src line, my Javascript does not run at all.

Do you see a problem with this approach ??
With this approach, I will not even attempt to return anything back to the Google Map Javascript.

If you know a way for this work, please suggest how to call my perl cgi and pass the parameters.
Since the call to googleapis.com works, I don't understand why my call to positiondatabase.com i not working.

Both calls are inside of  <script> and <\script>.

Your thoughts are appreciated.

Thanks,
Jim
.
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
If possible, I would like to just pass the lat and long to my Perl CGI URL
If that is not possible, then I can just monitor the output files of my Perl CGI script.

To do that, you need to configure your web server, probably(?) Apache HTTPD, to allow it to run Perl script
You can find plenty of web site explaning in detail how to do that, a random one :
https://editrocket.com/articles/perl_apache_windows.html
You probably don't need to instead Perl as you probably already have it installed...
jimtwest3Retired

Author

Commented:
Hi,
I should have listed more lines:
The lines around the call to the Googleapis is:

  </script>
  <script async defer
    src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCEjevcQPtLsBV4XG9PLnqAbpmAp01k20I&callback=initMap">
  </script>

I tried that same set of lines
The following lines are in my script and cause no problems:

  var lat = "mapsMouseEvent.latLng.lat().toString";
  var lng = "mapsMouseEvent.latLng.lng().toString";
  alert("mouse clicked, coords are lat :" + lat + "\nlng :" + lng);
 
I tried:

src="https://kjm.positiondatabase.com/cgi-bin/Distance";

src="https://kjm.positiondatabase.com/cgi-bin/Distance?lat2=lat&long2=lng">

<script async defer
.   src="https://kjm.positiondatabase.com/cgi-bin/Distance?lat2=lat&long2=lng">

<script>
<script async defer
   src="https://kjm.positiondatabase.com/cgi-bin/Distance?lat2=lat&long2=lng">
<\script>

None of these tries worked.

Jim



 
 


jimtwest3Retired

Author

Commented:
The following line was a typo in my note to you:

src="https://kjm.positiondatabase.com/cgi-bin/Distance?lat2=lat&long2=lng">

I tried:

src="https://kjm.positiondatabase.com/cgi-bin/Distance?lat2=lat&long2=lng";

( the line ends with a semicolon when not inside a couple of "script" lines.

Jim


leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
just type it in your address bar, this is the simplest test you can do
maybe try a simple Perl script saying "Hello world"
once it work, let's fight with your Distance.pl script
jimtwest3Retired

Author

Commented:
# 5. Send code to the JavaScript on the web page.
print "Content-type: text/javascript\n\n";
 
print $JScode;

Hi,
The entire Google Maps Javascript is encloded between <script> at the top to <\secript> at the bottom.
That is followed by a short <script> section where https Googleapis is called to pass my Google Maps license key.

I now have my Perl CGI Distance script being called inside Javascript.
The Perl CGI script is being called in a fetch https call with the latitude and longitude parameters.
I don't see a way to way to return the text string back to fetch from my perl cgi script.

The Distance script is calculating the distance and bearing between 2 (clicked) latitude and longitude positions really well, , and writing the result in a single line text file.  

I can not find a way to return the text string back to the javascript from my perl cgi script.

The text line looks like

:-16.1037  -150.2667  Distance: 4843 nm, Bearing: 242 degrees

I can not find a common storage area that could be accessed by both the javascript and the Perl script..

There is a new method called "localStorage" and "SessionStorage", but I'm not sure if that is available in both Perl and javascript.

I thought about using a cookie to share the text string between the Perl CGI and javascript, but writing the line in a cookie requires both scripts to be run in the browser.  Javascript can't do server file I/O so the javascript can't read the file.  The Perl Distance script can't access storage on the client where the browser is running.  Javascript can't talk to a MySQL script, so sharing the data in a database won't work.

I have a simple perl script and a simple nodejs script that can easily read the single line file..
The Perl script watches the file and when the file changes, launches an embedded javascrip alert function.
That works but not very well.  The alert popup appears in a different tab from the Google Maps tab, so that is awkward.

I really need to run the alert inside the Google Maps javascript.

Is it posible to embed a nodejs script inside a javascript to read the single line file and pass it to the javascript ??

I think html can be embedded inside javascript, and I think a nodejs scirpt can be run inside html ... could that work ??

The entire Google Maps script is a couple of hundred lines between <script> and <\script>.

Can you think of a way to somehow read the single line file, and pass the content to Google Map script inside the addListener Mouse Click Event ??, or at least pass the Distance and the Bearing a 2 variables from the Perl Distance script to the javascript.

Your thoughts appreciated.

Thanks,
Jim

jimtwest3Retired

Author

Commented:
Hi,
Please suggest how the Google Maps javascript can see the results of the Perl CGI distance and bearing calculation, so the data can be viewed using alert in the same display window as the javascript.  The result line is stored in a single line file on the server.

Thanks,
Jim

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
1 - allow Perl script from cgi-bin folder to be executed

Please let me know when it's done
jimtwest3Retired

Author

Commented:
The Distance script is a Perl CGI script.
It can be called with a Browser and run interactively, or it can be called with the parameters passed to it.
The web address for the script is :   https://kjm.positiondatabase.com/cgi-bin/Distance.pl
Here is my current addListener function where it is called:

// Configure the click listener.
map.addListener('click', function(mapsMouseEvent) {
 
  var lat = mapsMouseEvent.latLng.lat();
  var lng = mapsMouseEvent.latLng.lng();
  var text = "https://kjm.positiondatabase.com/cgi-bin/Distance.pl?lat2=" + String(lat) + "&long2=" + String(lng) + ")";
  fetch(text);
 
// Create a new InfoWindow.
  infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
  infoWindow.setContent(mapsMouseEvent.latLng.toString());
  infoWindow.open(map);
});
 
}

In your browser, bring up a Google Map script:

https://kjm.positiondatabase.com/Track/ComposeM.html

In another browser tab, bring up the Perl CGI script that monitirs :/tmp/DataOUT.txt :

https://kjm.positiondatabase.com/cgi-bin/watch.pl

When you click on a position on the Google Map, the Distance and Bearing is calculated from the last position clicked on the Map to the current position on the map, where you clicked. The Distance and Bearing are written in a short single line to /tmp/DataOUT.txt.  When you bring up watch.pl script monitors that file.  If the line in /tmp/DataOUT.txt, then watch.pl sends the line to alert.  The alert will appear in your watch.pl  browser tab.  The script goes to sleep, so it does not always work.
When it stiops working, just restart it in your browser.  The contents of the watch.pl script are:

#!/usr/bin/perl -w
#use strict; # enforce variable declarations and quoting
use CGI qw(:standard);
 
print header, start_html("Navigation Tool"), h1("Navigation Tool");
#
$newtext = `cat /tmp/DataOUT.txt`;
chomp($newtext);
#
while (1) {
#
 while (1) {
   sleep 1;
   $text = `cat /tmp/DataOUT.txt`;
   chomp($text);
   if ($text !~ $newtext ) {
       last;
   }
 }
#
 print p("$text");
 my $js = "alert(\"$text\");";
 print qq(<script type="text/javascript">$js</script>);
# print p("<script type=\"text/javascript\">$js</script>");
 $newtext = $text;
}
#
print end_html;
exit;

Hope you can figure out a way for the Perl CGI script to send the text string written to /tmp/DataOUT.txt to the addListener function.   From the description of the "fetch" function in javascript, the Perl CGI script should be able to pass a JSON file back to the fetch call by doing a fetch "GET" call.  The JSON file would have:

{"lat":"12.2132","long":"-68.8888","Bearing":"274","DistanceMiles":549,"DistaneeNM":"477"}

The Nav.pl script is:

#!/usr/bin/perl
use JSON;
use CGI qw(:standard);
#
print header('application/json');
#
open(INP,"/tmp/DataOUT.txt");
$line=<INP>;
($lat,$long,$Name1,$DistanceNM,$unit1,$Name2,$myBrng,$unit2) = split(" ",$line);
close(INP);
#
$DistanceMiles = int($DistanceNM*1.15078 + 0.5);
$DistanceMiles = $DistanceMiles + 0.50;
$DistanceMiles = int($DistanceMiles);
#
use JSON;
my %rec_hash = ('lat' => $lat, 'long' => $long, 'DistaneeNM' => $DistanceNM, 'DistanceMiles' => $DistanceMiles, 'Bearing' => $myBrng);
my $json = encode_json \%rec_hash;
print "$json\n";

One possibility would be to have another "fetch" call to call "Nav.pl", and have Nav.pl return the JSON information with DistanceNM, DistanceMiles, and Bearing.  The DistanceNM, DistanceMiles, and Bearing data could then be put into an alert message in the addListener function.  I am still reading how JSON data in a Perl CGI script can be returned to the javascript "fetch" function.  I don't understand the process yet, but the capability may exist.  

Thanks,
Jim
 
jimtwest3Retired

Author

Commented:
Hi,

Another possiblity is to use a new feature, "localStorage" or "SessionStorage".  This is storage in the Browser, and can be called and used by scripts, not limited to browser connection. Both javascript running on the browser, and Perl CGI running on the server would have access to the browser storage, so that might be a way to share data between javascript and Perl CGI.

Jim
jimtwest3Retired

Author

Commented:
This looks interesting ...   https://www.youtube.com/watch?v=ycmci-hiPfQ
The video shows how to use the Fetch API to send JSON data.
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
here the code :
    map.addListener('click', function(mapsMouseEvent) {

        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
            if(xhr.readyState == 4) {
                if(xhr.status == 200) {
                    var txt = xhr.response.match(/<p>.*<\/p><p>.*<\/p><p>(.*)<\/p>/)[1];
                    // Create a new InfoWindow.
                    infoWindow = new google.maps.InfoWindow({position: mapsMouseEvent.latLng});
                    infoWindow.setContent(txt);
                    infoWindow.open(map);
                }
                else {
                    alert("error : " + xhr.status + "\n" + xhr.statusText);
                }
            }
        }

        var data = "lat2=" + mapsMouseEvent.latLng.lat() + "&long2=" + mapsMouseEvent.latLng.lng();
//        var data = "lat2=12&long2=-68";
        xhr.open("POST", "/cgi-bin/Distance.pl", true);
        xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhr.send(data);

    });

leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
depending what text you want to display, you can also use (line 7) :
xhr.response.match(/<p>(.*)<\/p>/)[1]
instead :
xhr.response.match(/<p>.*<\/p><p>.*<\/p><p>(.*)<\/p>/)[1]
jimtwest3Retired

Author

Commented:
When I click on a position, the popup window is showing the last latitude and longitude and not the current latitude and longitude, where I clicked:

For example, here is 2   latitude and longitude points:

11.9202  -61.4068  11.7912  -69.2291

I am clicking at   11.7712 -69.2291, but 11.9202  -61.4068  is being displayed in the popup window.

The text string stored in /tmp/DataOUT.txt contains:

11.7912  -69.2291  Distance: 459 nm, Bearing: 269 degrees

The line in /tmp/DataOUT.txt  file contains, the current latitude and longitude posittion, and the distance and bearing from the last position to the current position.    

My problem is having the Distance and Bearing variables communicated to the addListener function from Distance.pl, so they could be shown in the popup window.  The popup window from addListener needs to show the current lattitude and longitude, along with the distance and bearing, "11.7912  -69.2291  Distance: 459 nm, Bearing: 269 degrees"

The Distance and Bearing variables are  DistanceNM and myBrng in Distance.pl.

 $text = "$lat2  $long2  Distance: $DistanceNM nm, Bearing: $MyBrng degrees";

The problem is having the $DistanceNM and MyBrng communicated from Distance.pl to the Google Map javascript, so they can be displayed in the Google Map javascript.

Before the popup window was showing:  mapsMouseEvent.latLng,
which contains:   mapsMouseEvent.latLng.lat()   and    mapsMouseEvent.latLng.lng()

As far as I know, Distance.pl can not create an alert that will display in the Google Map display window.
If Distance.pl could display an alert int the Google Map display window, that would work since Distance.pl has the
latitude and longitudes, and has the Distance and Bearing data.  

Since Distance.pl can not display an alert in the Google Map display window, my problem has been having the DistanceNM and MyBrng variables in Google Map display window with the current latitude and longitude.

Does the addListener function in the Google Maps javascript now have the DistanceNM and MyBrng variables calculated in Distance.pl ?.

Thanks,
Jim
 



Jim


jimtwest3Retired

Author

Commented:
I am wondering if it would be simpler to use either XMLHtttpRequest or $.ajax() to read the small server text file /tmp/DataOUT.txt.  The file is only a single line.  

While javascript can not read server files, it appears that XMLHttpRequest or $.ajax() can read a server text file.  The server text file /tmp/DataOUT..txt is a short simple single line text file, that contains exactly what  we need in the alert popup window in the Google Map display.:  

11.7051  -69.4049  Distance: 460 nm, Bearing: 272 degrees

If XMLHttpRequest or $.ajax could read /tmp/DataOUT.txt in the addLIstener function, then we could call alert with the contents, to display in an alert popup window.  That would solve this problem, and may be simpler than attempting to return data from Distance.pl back to the addListener function.

Jim

jimtwest3Retired

Author

Commented:
WOW ... OK, I have changed your "line 7", and now I see all the data that you are displaying.
That is amazing.  This is much more data displayed that I thought possible.
I need to understand the variable names of the data in Distance.pl that you have available in the addListener function.
Are the variable names in Distance.pl the same in addListener ??

This is definitely a good solution !!
This question/problem is definitely solved ...

Thanks,
Jim
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
I am wondering if it would be simpler to use either XMLHtttpRequest or $.ajax() to read the small server text file

It's a bad idea because two persons can use your script at the same times
You need to send back the previous lat/lng in a cookie on the browser or a user session for example
leakim971Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
I need to understand the variable names of the data in Distance.pl that you have available in the addListener function.

If the Distance.pl can return just JSON data instead a page, we can easily parse the response to get all the values.
Also instead reading in a file, we should send the previous lat and lng to the Distance.pl script

Are the variable names in Distance.pl the same in addListener ??

line 19, lat2 and long2 :
var data = "lat2=" + mapsMouseEvent.latLng.lat() + "&long2=" + mapsMouseEvent.latLng.lng();
The listener know nothing with variables name, it's just a code running for a click
We use mapsMouseEvent (event) to get the position lng and lat using a method
jimtwest3Retired

Author

Commented:
Hi,
The solution you have is better than what I had expected.
It would be easy to create a JSON format of the data with the variables in Distance.pl, but it is not necessary.
After making the change to line 7 as you suggested, the (response) output became clear.

In looking at your addListener, the call to the Distance.pl script is in the bottom half of the function, and if line7 is filtering the output, then the output is being processed in the first half of the addListener function.  Is addListener being called twice ??

The "data" variable is the parameter input, for the param data in Distance.pl.

The response appears to be the output of the Distance.pl script.
How is the output of Distance.pl being captured to become the response ?

I think what you have looks great.  I don't see a need for any tweaks, unless you do.

I think you should declare victory, and have a drink of your favorite beverage..

I'm glad you understand how to use XMLHtttpRequest.  
I did not find any discussions on XMLHttpRequest that would have been easy to replicate ..
 or maybe I was just dense in reading them.
.
The documentation that I read encouraged me to use "fetch" instead of XMLHttpRequest,
but your implementation of XMLHttpRequest looks great and works great.  

This was not a simple problem.  I really appreciate your help.
Without your help, I would probably still be working on this at Christmas.
Hopefully someone will be able to use this solution to help with their navigation..

Thanks,
Jim
 
Multitechnician
CERTIFIED EXPERT
Distinguished Expert 2019
Commented:
This one is on us!
(Get your first solution completely free - no credit card required)
UNLOCK SOLUTION
jimtwest3Retired

Author

Commented:
Hi,
I just tested your latest addListener script, and it works great.  
I marked you solution as fully accepted.  
This is good solution, very logical, very clean, and gives a clean output.
I experimented with "fetch" over the weekend, but your script and output are much better than what I developed.
Your knowledge, and help are very much appreciated.
In my opinion, this was a difficult technical problem, and your solution is really good..
Thanks
Jim West

Unlock the solution to this question.
Join our community and discover your potential

Experts Exchange is the only place where you can interact directly with leading experts in the technology field. Become a member today and access the collective knowledge of thousands of technology experts.

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.