MapToExcel.vue
This is where users can create their own map with a set of places by adding markers onto the map.
import
import// Importing Vue components for the NavigationBar and Footer
import NavigationBar from "../reusable-layout/NavigationBar.vue";
import Footer from "../reusable-layout/Footer.vue";
// Importing Axios for making HTTP requests
import axios from "axios";Above, we are importing the NavigationBar and Footer component which is a reusable layout because navigation bars and footers are usually same for each page so instead of writing it for each page, it's better to write it in one Vue page and import it in each page as components
Next, is the "axios" package which is used to make API call to the backend (Laravel). It is important because this is like the key that allows us to communicate with the backend.
export default
export default// Exporting the Vue component
export default {}Inside this is where we define data, methods, computed properties, and lifecycle hooks.
components
components// Register the imported components
components: {
NavigationBar,
Footer,
}The components option is used to register and make Vue external components available for use within this component
data
data// Data properties of the component
data() {
return {
domainBackend: "",
latitude: "",
longitude: "",
allData: [],
map: null,
countId: 1,
};
}The data method is used to initialize and define the data properties for this component. See the source code to know what each variable is used for.
mounted
mounted// Lifecycle hook: Executed when the component is mounted to the DOM
mounted() {
// Scrolls the window to the top when the component is first loaded.
window.scrollTo(0, 0);
// Retrieves and sets the backend domain from the Vuex store.
this.domainBackend = this.$store.state.domainBackend;
// Checks if cookies for 'MTE_allData' and 'MTE_countId' are available. If not, initializes them.
if (
!this.$cookie.isCookieAvailable("MTE_allData") ||
!this.$cookie.isCookieAvailable("MTE_countId")
) {
this.$cookie.setCookie("MTE_allData", JSON.stringify([]));
this.$cookie.setCookie("MTE_countId", 1);
} else {
// If cookies are available, parses and sets the 'allData' and 'countId' from the cookies.
this.allData = JSON.parse(this.$cookie.getCookie("MTE_allData"));
this.countId = parseInt(this.$cookie.getCookie("MTE_countId"));
}
// Initializes the map when the component is mounted.
this.initMap();
// Updates the table with data if 'allData' is not empty.
if (this.allData.length != 0) {
this.updateTable(this.allData);
}
}This is called mounted lifecycle hook. The mounted hook is called after the component has been added to the DOM, making it a good place to perform initial setup and actions.
To explain what this mounted hook does:
It scrolls the window to the top so the user sees the content at the beginning of the page.
It gets the backend domain from what is defined in the Vuex.
It will first check if the cookie of the map data array or currently selected map data is saved or not. If saved, then it will get the cookie of the map data array and currently selected map data and initialize it. If not saved, then it will define an empty map data array and map data and save it as the cookie.
If the map data array is empty, then it will just initialize an empty map to display, update the map entries in the selection section, and name the table with its default name.
If the map data array is not empty, it will just initialize an empty map to display and populates the table with rows.
methods
methods// Methods of the component
methods: {}The methods option is used to define methods that can be called or triggered within a Vue component. These methods are typically used to define the behavior and functionality of the component
openExportMap
openExportMap// Method to display the export map container
openExportMap() {
// Get the HTML element with the id "containerExportMap"
const containerExportMap = document.getElementById("containerExportMap");
// Set the display style property to "block" to make it visible
containerExportMap.style.display = "block";
}To explain what this openExportMap method does:
It shows a pop-up box where the user can choose whether to export the currently selected map data to CSV file or Google Sheets file.
closeExportMap
closeExportMap// Method to hide the export map container
closeExportMap() {
// Get the HTML element with the id "containerExportMap"
const containerExportMap = document.getElementById("containerExportMap");
// Set the display style property to "none" to hide the container
containerExportMap.style.display = "none";
}To explain what this closeExportMap method does:
It will the close the pop-up box.
convertJsonToGoogleSheet
convertJsonToGoogleSheet// Method to convert JSON data to a Google Sheet
convertJsonToGoogleSheet() {
// Create a deep copy of the data to avoid modifying the original
const data = JSON.parse(JSON.stringify(this.allData));
// Remove LATITUDE and LONGITUDE properties from each item in the data
data.forEach((item) => {
delete item.LATITUDE;
delete item.LONGITUDE;
});
// Generate a unique title using a hash function
const title = this.makeHash(32);
// Convert the data to a JSON string
const jsonData = JSON.stringify(data);
// Get the backend domain from the component's state
const domainBackend = this.domainBackend;
// Set properties for the popup window
const popupProperties = "width=500,height=800,scrollbars=yes";
// Initialize a popup window
let windowPopUp;
windowPopUp = window.open("", "Google", popupProperties);
// Authenticate Google account for Google Sheets API
axios
.get(
this.domainBackend + "/api/authenticateGoogleAccountForGoogleSheet"
)
.then((response) => {
if (response.data.SUCCESS == 1) {
// Get the authentication URL and set the popup window's location
const url = response.data.AUTH_URL;
windowPopUp.location.href = url;
// Monitor changes in the popup window's URL
monitorUrlChanges();
}
});
// Function to monitor changes in the popup window's URL
function monitorUrlChanges() {
const interval = setInterval(() => {
if (windowPopUp && !windowPopUp.closed) {
// Check if the URL contains the authorization code
const urlPopUp = windowPopUp.location.href;
if (urlPopUp.includes("?code=")) {
// Extract the code from the URL
const params = new URLSearchParams(urlPopUp.split("?")[1]);
const code = params.get("code");
// Send the JSON data and code for Google Sheets conversion
sendJson(code);
clearInterval(interval);
}
} else {
// Clear the interval if the popup window is closed
clearInterval(interval);
}
}, 1000);
}
// Function to send JSON data and code for Google Sheets conversion
function sendJson(code) {
const request = {
title: title,
jsonData: jsonData,
code: code,
};
// Make a POST request to convert JSON to Google Sheets
axios
.post(domainBackend + "/api/convertJsonToGoogleSheet", request)
.then((response) => {
// Close the popup window and open the generated Google Sheets link in a new tab
windowPopUp.close();
window.open(response.data.LINK, "_blank").focus();
});
}
}To explain what this convertJsonToGoogleSheet method does:
It retrieves an authentication URL which is used to authenticate the user's Google account. It is needed because the converted Google Sheet file will be saved in the user's Google Drive.
The authentication URL will be opened in a pop-up window.
Then, the changes that happens in the URL bar of the pop-up window is monitored because after the user has authenticated their account, Google will send a code which is then used to do the Google Sheets conversion.
After the code has been given by Google, the JSON representation of the currently selected map data, the map title, and the code given by Google is sent to the backend.
After converting the JSON data to Google Sheets, the backend will respond with a link to the Google Sheets file.
The link is automatically opened in a new tab.
convertJsonToCsv
convertJsonToCsv// Method to convert JSON data to a CSV file
convertJsonToCsv() {
// Create a deep copy of the data to avoid modifying the original
const data = JSON.parse(JSON.stringify(this.allData));
// Remove LATITUDE and LONGITUDE properties from each item in the data
data.forEach((item) => {
delete item.LATITUDE;
delete item.LONGITUDE;
});
// Create a request object containing the JSON data
const request = {
jsonData: JSON.stringify(data),
};
// Make a POST request to convert JSON to CSV on the backend
axios
.post(this.domainBackend + "/api/convertJsonToCsv", request)
.then((response) => {
// Check if the conversion was successful
if (response.data.SUCCESS == 1) {
// Create a Blob containing the CSV data
const blob = new Blob([response.data.DATA], { type: "text/csv" });
// Create a download URL for the Blob
const url = window.URL.createObjectURL(blob);
// Create a link element for initiating the download
const a = document.createElement("a");
a.href = url;
// Set the download attribute with a unique filename (using a hash)
a.download = this.makeHash(32) + ".csv";
// Append the link to the document body
document.body.appendChild(a);
// Simulate a click on the link to initiate the download
a.click();
// Revoke the download URL to free up resources
window.URL.revokeObjectURL(url);
// Remove the link element from the document body
document.body.removeChild(a);
}
});
}To explain what this convertJsonToCsv method does:
It sends the JSON representation of the currently selected map data to the backend.
The backend will respond with a CSV representation of the currently selected map data then it converts it to a BLOB object that encapsulates the CSV data.
Then, it programmatically initiates the download of the file.
downloadKml
downloadKml// Method to download data as a KML file
downloadKml() {
// Create a deep copy of the data to avoid modifying the original
const data = JSON.parse(JSON.stringify(this.allData));
// Remove LATITUDE and LONGITUDE properties from each item in the data
data.forEach((item) => {
delete item.LATITUDE;
delete item.LONGITUDE;
});
// Create a request object containing the JSON data
const request = {
jsonData: JSON.stringify(data),
};
// Make a POST request to convert JSON to KML on the backend
axios
.post(this.domainBackend + "/api/convertJsonToKml", request)
.then((response) => {
// Check if the conversion was successful
if (response.data.SUCCESS == 1) {
// Create a Blob containing the KML data
const blob = new Blob([response.data.DATA], { type: "text/kml" });
// Create a download URL for the Blob
const url = window.URL.createObjectURL(blob);
// Create a link element for initiating the download
const a = document.createElement("a");
a.href = url;
// Set the download attribute with a unique filename (using a hash)
a.download = this.makeHash(32) + ".kml";
// Append the link to the document body
document.body.appendChild(a);
// Simulate a click on the link to initiate the download
a.click();
// Revoke the download URL to free up resources
window.URL.revokeObjectURL(url);
// Remove the link element from the document body
document.body.removeChild(a);
}
});
}To explain what this downloadKml method does:
It sends the JSON representation of the map data array to the backend.
The backend will respond with a KML representation of the map data array then it converts it to a BLOB object that encapsulates the KML data.
Then, it programmatically initiates the download of the file.
downloadJson
downloadJson// Method to download data in JSON format
downloadJson() {
// Create a deep copy of the data to avoid modifying the original
const data = JSON.parse(JSON.stringify(this.allData));
// Remove LATITUDE and LONGITUDE properties from each item in the data
data.forEach((item) => {
delete item.LATITUDE;
delete item.LONGITUDE;
});
// Convert the filtered data to a nicely formatted JSON string
const jsonData = JSON.stringify(data, null, 2);
// Create a Blob containing the JSON data
const blob = new Blob([jsonData], { type: "application/json" });
// Create a download URL for the Blob
const url = window.URL.createObjectURL(blob);
// Create a link element for initiating the download
const a = document.createElement("a");
a.href = url;
// Set the download attribute with a unique filename (using a hash)
a.download = this.makeHash(32) + ".json";
// Append the link to the document body
document.body.appendChild(a);
// Simulate a click on the link to initiate the download
a.click();
// Revoke the download URL to free up resources
window.URL.revokeObjectURL(url);
// Remove the link element from the document body
document.body.removeChild(a);
}To explain what this downloadJson method does:
It will get the currently selected map data and convert it to a BLOB object that encapsulates the JSON data.
Then, it programmatically initiates the download of the file.
makeHash
makeHash// Method to generate a random hash of a specified length
makeHash(length) {
// Initialize an empty string to store the generated hash
let result = "";
// Define the characters that can be used in the hash
const characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
// Get the total number of characters available
const charactersLength = characters.length;
// Counter to keep track of the number of characters added to the hash
let counter = 0;
// Loop until the desired length of the hash is reached
while (counter < length) {
// Append a random character from the available set to the hash
result += characters.charAt(
Math.floor(Math.random() * charactersLength)
);
// Increment the counter
counter += 1;
}
// Return the generated hash
return result;
}To explain what this makeHash method does:
It generates a 32-characters hash. The hash is used to define the ID of the published map file so that each published map file can be identified uniquely.
initMap
initMap// Method to initialize the Google Map
initMap() {
// Create a new Google Map instance and assign it to the 'map' property
this.map = new google.maps.Map(document.getElementById("map"), {
center: { lat: 0, lng: 0 }, // Set initial center coordinates
zoom: 2, // Set initial zoom level
markers: [], // Initialize an array to store markers on the map
});
// Add a click event listener to the map to handle marker placement
google.maps.event.addListener(this.map, "click", (event) => {
this.placeMarker(event.latLng); // Call the placeMarker function on map click
});
// Check if geolocation is supported by the browser
if ("geolocation" in navigator) {
// Get the current geolocation of the user
navigator.geolocation.getCurrentPosition((position) => {
// Create a LatLng object using the user's coordinates
var userLatLng = new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude
);
// Create a marker for the user's position
var userMarker = new google.maps.Marker({
position: userLatLng,
map: this.map,
icon: {
url: "https://cdn-icons-png.flaticon.com/512/1673/1673221.png", // Set custom marker icon
scaledSize: new google.maps.Size(52, 52), // Set custom marker size
},
});
// Set the zoom level and center of the map to the user's location
var zoomLevel = 16;
this.map.setZoom(zoomLevel);
this.map.setCenter(userLatLng);
// Add the user's marker to the array of markers on the map
this.map.markers.push(userMarker);
});
}
}To explain what this initMap method does:
It initializes a Google Map on the page.
If the user allows the browser's location permission, then the map will pinpoint their current location on the map.
placeMarker
placeMarker// Method to place a marker on the map at a specified location
placeMarker(location) {
// Check if a marker already exists, and if so, remove it from the map
if (this.marker) {
this.marker.setMap(null);
}
// Create a new marker at the specified location and assign it to the 'marker' property
this.marker = new google.maps.Marker({
position: location, // Set the marker's position to the specified location
map: this.map, // Set the map on which the marker will be placed
});
// Extract latitude and longitude from the marker's position
const lat = location.lat();
const lng = location.lng();
// Update the 'latitude' and 'longitude' properties with the marker's coordinates
this.latitude = lat.toString(); // Convert latitude to string
this.longitude = lng.toString(); // Convert longitude to string
}To explain what this placeMarker method does:
It takes a location, which is the latitude and longitude of a place.
It checks if a previously created marker exists. If it does, it removes it from the map by setting its map property to null.
It creates a new Google Maps marker, positioning it at the specified location.
It stores the latitude and longitude value.
addLabelClassToEdit
addLabelClassToEdit// Method to add a new label class in the edit interface
addLabelClassToEdit() {
// Prompt the user to enter a label for the class
var labelTitle = prompt("LABEL:");
// Check if a label was provided and it is not empty
if (labelTitle !== null && labelTitle.trim() !== "") {
// Get the container element for editing label classes
var labelClassesContainerEdit = document.getElementById(
"labelClassesContainerEdit"
);
// Create a new container div for the labeled class
var labelClassContainer = document.createElement("div");
labelClassContainer.classList.add("form-group");
// Create a label element to display the title
var titleLabel = document.createElement("label");
titleLabel.classList.add("form-label");
titleLabel.innerHTML =
"<div style='padding:5px;display:inline-block'>" +
labelTitle.toUpperCase() +
"</div>";
titleLabel.textContent = labelTitle.toUpperCase();
titleLabel.setAttribute("name", labelTitle.toUpperCase());
// Create a delete button to remove the labeled class
var deleteButton = document.createElement("div");
deleteButton.setAttribute("class", "buttonFormElementDelete");
deleteButton.textContent = "DELETE";
deleteButton.addEventListener("click", () => {
labelClassContainer.remove();
});
// Create an input element for the value of the labeled class
var valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("class", "form-control");
valueInput.setAttribute("id", labelTitle.toUpperCase());
valueInput.setAttribute("value", "");
// Append the label, delete button, and value input to the container div
labelClassContainer.appendChild(titleLabel);
labelClassContainer.appendChild(deleteButton);
labelClassContainer.appendChild(valueInput);
// Append the container div to the container for editing label classes
labelClassesContainerEdit.appendChild(labelClassContainer);
}
}To explain what this addLabelClassToEdit method does:
It prompts the user for a label title, and it stores the user's.
If the label title is not null and is not just whitespace, it proceeds to create and add an HTML element for this label in the pop-up box for editing the row.
It creates a label element for the title.
It creates an input field for the label's value, setting its initial value to an empty string.
It creates a "DELETE" button for removing the label, which triggers the removal of the label when clicked.
saveChanges
saveChanges// Method to save changes made in the edit interface
saveChanges() {
// Get the table element for editing the map
var editMap_table = document.getElementById("editMap_table");
// Get a list of all label elements within the edit map table
var labelList = editMap_table.querySelectorAll("label");
// Create a new item object to store the data
var item = {};
// Assign a unique ID to the item
item["ID"] = this.countId;
this.countId = this.countId + 1;
this.$cookie.setCookie("MTE_countId", this.countId);
// Initialize latitude and longitude variables
var latitude = "";
var longitude = "";
// Iterate through each label in the edit map table
for (let i = 0; i < labelList.length; i++) {
const label = labelList[i];
// Get the label's text, which represents the property name
const labelText = label.getAttribute("name");
// Get the input value corresponding to the property
const inputName = document.getElementById(labelText).value;
// Check if the property is latitude or longitude
if (labelText == "LONGITUDE") {
longitude = inputName;
} else if (labelText == "LATITUDE") {
latitude = inputName;
}
// Add the property and its value to the item object
item[labelText] = inputName;
}
// Add a "WKT" property to the item representing a point with latitude and longitude
item["WKT"] = `POINT (${longitude} ${latitude})`;
// Get the container for editing label classes
var labelClassesContainerEdit = document.getElementById(
"labelClassesContainerEdit"
);
// Get a list of all label elements within the label classes container
labelList = labelClassesContainerEdit.querySelectorAll("label");
// Iterate through each label in the label classes container
for (let i = 0; i < labelList.length; i++) {
const label = labelList[i];
// Get the label's text, which represents the property name
const labelText = label.getAttribute("name");
// Get the input value corresponding to the property
const inputName = document.getElementById(labelText).value;
// Add the property and its value to the item object
item[labelText] = inputName;
}
// Create a proxy for the item object to observe changes
const proxy_item = new Proxy(item, {
get: function (target, prop) {
return target[prop];
},
set: function (target, prop, value) {
target[prop] = value;
return true;
},
});
// Add the proxy_item to the array of all data
this.allData.push(proxy_item);
// Save the updated data and update the table
this.$cookie.setCookie("MTE_allData", JSON.stringify(this.allData));
this.updateTable(this.allData);
}To explain what this saveChanges method does:
It retrieves all the label elements within the map adding section.
It initializes an empty object and assigns a unique ID (incremented by 1) to its "ID" property. It also updates and saves this ID in the cookie.
It iterates through the label elements and extracts the value of associated input elements. Depending on whether the label represents "LONGITUDE" or "LATITUDE," it stores these values in separate variables.
It constructs a "WKT" (Well-Known Text) string using the longitude and latitude values and assigns it to the "WKT" property of the item.
It retrieves all label elements within the user-added-labels section. It then iterates through these elements, extracting input values and adding them as properties to the item.
It creates a Proxy object to watch for changes to the item object properties, allowing for custom behavior when getting or setting properties.
It adds the Proxy object to the map data array.
It saves the updated map data array to the cookie
Finally, it populates the table with the new map data array.
updateTable
updateTable// Method to update the table with new or modified data
updateTable(data) {
// Create a deep copy of the data to avoid modifying the original
const duplicate_data = JSON.parse(JSON.stringify(data));
// Remove the "WKT" property from each item in the duplicated data
duplicate_data.forEach((item) => {
if (item.hasOwnProperty("WKT")) {
delete item.WKT;
}
});
// Create a Proxy for the duplicated data to observe changes
const proxy_data = new Proxy(duplicate_data, {
get: function (target, prop) {
return target[prop];
},
set: function (target, prop, value) {
target[prop] = value;
return true;
},
});
// Get the table head row and table body elements
const tableHeadRow = document.getElementById("table-tr");
const tableBody = document.getElementById("mtsTbody");
// Clear the existing content of the table head and body
tableHeadRow.innerHTML = "";
tableBody.innerHTML = "";
// Check if there is data to display
if (proxy_data.length != 0) {
// Create a set to store all unique property names across items
const allProperties = new Set();
// Iterate through each item to collect all property names
proxy_data.forEach((item) => {
Object.keys(item).forEach((propertyName) => {
allProperties.add(propertyName);
});
});
// Create table header cells for each property name
allProperties.forEach((propertyName) => {
const th = document.createElement("th");
th.textContent = propertyName;
tableHeadRow.appendChild(th);
});
// Create "EDIT" and "OTHER ACTION" header cells
var th = document.createElement("th");
th.textContent = "EDIT";
tableHeadRow.appendChild(th);
th = document.createElement("th");
th.textContent = "OTHER ACTION";
tableHeadRow.appendChild(th);
// Iterate through each item to populate table rows
proxy_data.forEach((item) => {
// Create a new table row for each item
const row = document.createElement("tr");
// Populate cells with data for each property
allProperties.forEach((propertyName) => {
const cell = document.createElement("td");
cell.style.textAlign = "center";
const propertyValue = item[propertyName];
// Display property value if not undefined or null
if (propertyValue !== undefined && propertyValue !== null) {
cell.textContent = propertyValue;
} else {
// Optionally handle undefined or null values
// cell.style.backgroundColor = "#adadad";
}
row.appendChild(cell);
});
// Create "EDIT" cell with an edit button
const editCell = document.createElement("td");
const editButton = document.createElement("button");
editButton.setAttribute("class", "button");
editButton.innerHTML = "<i class='fas fa-edit'></i>";
editButton.addEventListener("click", () => this.editRow(item));
editCell.appendChild(editButton);
row.appendChild(editCell);
// Create "OTHER ACTION" cell with delete, marker, and share buttons
const otherCell = document.createElement("td");
// Delete button
const deleteButton = document.createElement("button");
deleteButton.classList.add("button");
deleteButton.innerHTML = "<i class='fa fa-trash'></i>";
deleteButton.addEventListener("click", () => this.deleteRow(item));
otherCell.appendChild(deleteButton);
// Marker button for Google Maps link
const markerButton = document.createElement("a");
markerButton.href =
"https://www.google.com/maps/search/?api=1&query=" +
item["LATITUDE"] +
"%2C" +
item["LONGITUDE"];
markerButton.target = "_blank";
markerButton.innerHTML =
"<button class='button'><i class='fa fa-map-marker'></i></button>";
otherCell.appendChild(markerButton);
// Share button
const shareButton = document.createElement("button");
shareButton.classList.add("button");
shareButton.innerHTML = "<i class='fa fa-share-nodes'></i>";
shareButton.addEventListener("click", () => this.shareRow(item));
otherCell.appendChild(shareButton);
// Append "OTHER ACTION" cell to the row
row.appendChild(otherCell);
// Append the row to the table body
tableBody.appendChild(row);
});
}
}To explain what this updateTable method does:
It creates a deep copy of the map data using JSON serialization and parsing. This is done to avoid modifying the original data.
It removes the "WKT" property from each object in map data if it exists.
It creates a Proxy object of the map data that allows getting and setting properties while ensuring they are always set successfully.
It selects the table's header row and body elements in the HTML document.
It clears the existing content of the table's header row and body.
If Proxy object is not empty, it proceeds to dynamically generate the table's header based on the properties of the objects in the Proxy object.
It iterates over the properties of the objects to create table header cells and appends them to the header row.
For each object in the Proxy object, it generates a new row in the table body, filling in cells with property values.
It adds buttons to each row in the "EDIT" and "OTHER ACTION" column. Clicking these buttons triggers specific actions, such as editing, deleting, opening the location on Google Maps, or sharing the row.
deleteRow
deleteRow// Method to delete a row of data
deleteRow(item) {
// Iterate through the data to find the item with matching ID
for (let i = 0; i < this.allData.length; i++) {
// Check if the ID of the current item matches the target item's ID
if (this.allData[i].ID === item.ID) {
// Remove the item from the data array
this.allData.splice(i, 1);
// Exit the loop since the item has been found and removed
break;
}
}
// Create a data object to store the modified data
const data = {
DATA: [],
};
// Deep copy each item in the data and add it to the new data object
this.allData.forEach((item) => {
const jsonData = JSON.parse(JSON.stringify(item));
data.DATA.push(jsonData);
});
// Check if there are no more items in the data
if (this.allData.length == 0) {
// If there are no items, clear the table head and body
const tableHeadRow = document.getElementById("table-tr");
const tableBody = document.getElementById("mtsTbody");
tableHeadRow.innerHTML = "";
tableBody.innerHTML = "";
} else {
// If there are remaining items, update the table with the modified data
this.updateTable(data.DATA);
}
// Update the cookie with the modified data
this.$cookie.setCookie("MTE_allData", JSON.stringify(this.allData));
}To explain what this deleteRow method does:
It loops through the currently selected map data array to find the item with an ID that matches the ID of the item that is passed in the method.
Once the matching item is found, it removes it from the currently selected map data array.
It then iterates through the map data array and its nested DATA arrays to find and update the item with the same ID as the ID of the currently selected map data with the modified currently selected map data.
If there are no more items left in the currently selected map data, it sets the map to null and initializes a new map.
If there are still items in the currently selected map data, it add the markers in the map, populates the table, and updates the map entries in the selection section.
The map data array and currently selected map data are saved to the cookie.
If the user is logged in, then the JSON representation of the map data array is sent to the backend so that the backend can write the JSON data to the map file of the user.
shareRow
shareRow// Method to share a specific row of data
shareRow(item) {
// Get the input field for the URL link
const urlLink = document.getElementById("urlLink");
// Construct the Google Maps URL with latitude and longitude from the item
urlLink.value =
"https://www.google.com/maps/search/?api=1&query=" +
item["LATITUDE"] +
"%2C" +
item["LONGITUDE"];
// Get the container for sharing on social media
const containerShareToSocial = document.getElementById(
"containerShareToSocial"
);
// Display the container for sharing on social media
containerShareToSocial.style.display = "block";
}To explain what this shareRow method does:
A pop-up box will be shown where the user can copy the Google Maps link of the map item.
editRow
editRow// Method to edit a specific row of data
editRow(item) {
// Get the edit map pop-up container
const editMapPopUp = document.getElementById("editMapPopUp");
// Display the edit map pop-up
editMapPopUp.style.display = "block";
// Set the title of the pop-up with the row's name
document.getElementById("editMap_TitlePopUp").innerHTML =
"<strong>" + item["NAME"] + "</strong>";
// Get the table and label classes container for the pop-up
const editMap_tablePopUp = document.getElementById("editMap_tablePopUp");
const labelClassesContainerEditPopUp = document.getElementById(
"labelClassesContainerEditPopUp"
);
// Clear the contents of the table and label classes container
editMap_tablePopUp.innerHTML = "";
labelClassesContainerEditPopUp.innerHTML = "";
// Create a deep copy of the item to avoid modifying the original data
const modifiedItem = JSON.parse(JSON.stringify(item));
// Get the list of properties from the modified item
const propertyList = Object.keys(modifiedItem);
// Loop through each property in the item
for (let i = 0; i < propertyList.length; i++) {
const propertyName = propertyList[i];
const propertyValue = modifiedItem[propertyName];
// Create a div element for each property
const divElement = document.createElement("div");
divElement.className = "form-group";
// Create a label element for the property
const labelElement = document.createElement("label");
labelElement.className = "form-label";
labelElement.innerHTML =
"<div style='padding:5px;display:inline-block'>" +
propertyName +
"</div>";
labelElement.setAttribute("name", propertyName);
divElement.appendChild(labelElement);
// Check if the property should be deletable
if (
propertyName == "ID" ||
propertyName == "NAME" ||
propertyName == "LATITUDE" ||
propertyName == "LONGITUDE"
) {
// Do nothing for non-deletable properties
} else {
// Create a delete button for deletable properties
var deleteButton = document.createElement("div");
deleteButton.setAttribute("class", "buttonFormElementDelete");
deleteButton.textContent = "DELETE";
// Add an event listener to delete the div element when the button is clicked
deleteButton.addEventListener("click", () => {
divElement.remove();
});
// Append the delete button to the div element
divElement.appendChild(deleteButton);
}
// Create an input element for the property
const inputElement = document.createElement("input");
inputElement.id = propertyName + "PopUp";
inputElement.type = "text";
inputElement.className = "form-control";
inputElement.value = propertyValue;
// Set readOnly property for certain fields
if (propertyName == "ID" || propertyName == "WKT") {
inputElement.readOnly = true;
} else {
inputElement.readOnly = false;
}
// Append the input element to the div element
divElement.appendChild(inputElement);
// Hide the "ID" field in the pop-up
if (propertyName == "ID") {
divElement.style.display = "none";
}
// Append the div element to the table in the pop-up
editMap_tablePopUp.appendChild(divElement);
}
// Get the "Save Changes" button in the pop-up
const saveChangesPopUp = document.getElementById("saveChangesPopUp");
// Add an event listener to save the changes when the button is clicked
saveChangesPopUp.addEventListener("click", () => {
// Get the table and label list in the pop-up
var editMap_tablePopUp = document.getElementById("editMap_tablePopUp");
var labelList = editMap_tablePopUp.querySelectorAll("label");
// Create an object to store the edited item
var item = {};
// Loop through each label in the pop-up
for (let i = 0; i < labelList.length; i++) {
const label = labelList[i];
const labelText = label.getAttribute("name");
// Get the input value corresponding to the label
const inputName = document.getElementById(labelText + "PopUp").value;
// Add the property and its value to the item object
item[labelText] = inputName;
}
// Get the label list in the label classes container
labelClassesContainerEditPopUp = document.getElementById(
"labelClassesContainerEditPopUp"
);
labelList = labelClassesContainerEditPopUp.querySelectorAll("label");
// Loop through each label in the label classes container
for (let i = 0; i < labelList.length; i++) {
const label = labelList[i];
const labelText = label.getAttribute("name");
// Get the input value corresponding to the label
const inputName = document.getElementById(labelText + "PopUp").value;
// Add the property and its value to the item object
item[labelText] = inputName;
}
// Create a Proxy for the item object
const proxy_item = new Proxy(item, {
get: function (target, prop) {
return target[prop];
},
set: function (target, prop, value) {
target[prop] = value;
return true;
},
});
// Update the original data with the edited item
for (let i = 0; i < this.allData.length; i++) {
if (this.allData[i].ID == proxy_item.ID) {
this.allData[i] = proxy_item;
}
}
// Create an object to store the data for updating the table
const data = {
DATA: [],
};
// Add each item in the updated data to the data object
this.allData.forEach((item) => {
const jsonData = JSON.parse(JSON.stringify(item));
data.DATA.push(jsonData);
});
// Update the table with the new data
this.updateTable(data.DATA);
// Save the updated data to cookies
this.$cookie.setCookie("MTE_allData", JSON.stringify(this.allData));
});
}To explain what this editRow method does:
It toggles the visibility of the pop-up box for editing the row.
It updates the title of the pop-up box to display the name of the map item being edited.
It retrieves the list of property names from map item and iterates through them.
For each property, it creates an input field in the editing interface and populates it with the property's value. It also adds a "DELETE" button for properties other than "ID", "NAME", "LATITUDE", and "LONGITUDE." The "DELETE" button allows removing properties from the item.
When the "Save Changes" button is clicked, it retrieves the updated values of the properties from the input fields.
It uses a Proxy object to allow getting and setting properties in the item.
It updates the corresponding map item in the currently selected map data with the edited map item.
It also updated the map data array with the modified currently selected data.
It add the markers in the map, populates the table, and updates the map entries in the selection section.
The map data array and currently selected map data are saved to the cookie.
If the user is logged in, then the JSON representation of the map data array is sent to the backend so that the backend can write the JSON data to the map file of the user.
addLabelClassToEdit
addLabelClassToEdit// Method to add a new label class in the edit pop-up interface
addLabelClassToEditPopUp() {
// Prompt the user for a label title
var labelTitle = prompt("LABEL:");
// Check if a valid label title is provided
if (labelTitle !== null && labelTitle.trim() !== "") {
// Get the container for label classes in the edit pop-up
var labelClassesContainerEditPopUp = document.getElementById(
"labelClassesContainerEditPopUp"
);
// Create a container div for the label class
var labelClassContainer = document.createElement("div");
labelClassContainer.classList.add("form-group");
// Create a label element for the title
var titleLabel = document.createElement("label");
titleLabel.classList.add("form-label");
titleLabel.innerHTML =
"<div style='padding:5px;display:inline-block'>" +
labelTitle.toUpperCase() +
"</div>";
titleLabel.textContent = labelTitle.toUpperCase();
titleLabel.setAttribute("name", labelTitle.toUpperCase());
// Create a delete button for the label class
var deleteButton = document.createElement("div");
deleteButton.setAttribute("class", "buttonFormElementDelete");
deleteButton.textContent = "DELETE";
// Add an event listener to delete the label class container when the button is clicked
deleteButton.addEventListener("click", () => {
labelClassContainer.remove();
});
// Create an input element for the value
var valueInput = document.createElement("input");
valueInput.setAttribute("type", "text");
valueInput.setAttribute("class", "form-control");
valueInput.setAttribute("id", labelTitle.toUpperCase() + "PopUp");
valueInput.setAttribute("value", "");
// Append the title, delete button, and value input to the label class container
labelClassContainer.appendChild(titleLabel);
labelClassContainer.appendChild(deleteButton);
labelClassContainer.appendChild(valueInput);
// Append the label class container to the label classes container in the edit pop-up
labelClassesContainerEditPopUp.appendChild(labelClassContainer);
}
}To explain what this addLabelClassToEdit method does:
It prompts the user for a label title, and it stores the user's.
If the label title is not null and is not just whitespace, it proceeds to create and add an HTML element for this label in the pop-up box for editing the row.
It creates a label element for the title.
It creates an input field for the label's value, setting its initial value to an empty string.
It creates a "DELETE" button for removing the label, which triggers the removal of the label when clicked.
closeEditMap
closeEditMap// Method to close the edit map pop-up
closeEditMap() {
// Get the edit map pop-up element by its ID
const editMapPopUp = document.getElementById("editMapPopUp");
// Set the display style to "none" to hide the edit map pop-up
editMapPopUp.style.display = "none";
}To explain what this closeEditMap method does:
It will the close the pop-up box for editing the row.
Last updated