-
Notifications
You must be signed in to change notification settings - Fork 0
/
content.js
118 lines (98 loc) · 5.31 KB
/
content.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
// DOM element containing the tabs
const tabsContainer = document.getElementById("primary-tabs");
let directionsButton = document.getElementsByClassName("place-body")[0];
// Path definition for the Maps icon (from Fontawesome)
const mapIcon = "M565.6 36.2C572.1 40.7 576 48.1 576 56V392c0 10-6.2 18.9-15.5 22.4l-168 64c-5.2 2-10.9 2.1-16.1 .3L192.5 417.5l-160 61c-7.4 2.8-15.7 1.8-22.2-2.7S0 463.9 0 456V120c0-10 6.1-18.9 15.5-22.4l168-64c5.2-2 10.9-2.1 16.1-.3L383.5 94.5l160-61c7.4-2.8 15.7-1.8 22.2 2.7zM48 136.5V421.2l120-45.7V90.8L48 136.5zM360 422.7V137.3l-144-48V374.7l144 48zm48-1.5l120-45.7V90.8L408 136.5V421.2z";
const iconViewBox = "0 0 576 512";
// Variables for user chosen maps provider and the current query
const mapsName = "Maps";
const query = new URLSearchParams(window.location.search).get("q");
let mapsURL;
// This is needed to check if the page has loaded the SVG icons the second time, as for some reason they load the tabs, delete their icons and the one we added, then load them again. We might as well just wait for the second batch of icons to be added and then add the Maps tab.
let pathCounter = 0;
// The observer will:
// - Watch for changes in the DOM and add the Maps tab when the fifth path element (seems to be a good number to tell us when it"s loading icons the second time) is added to the DOM;
// - When a minimap is loaded, it will add a button to open the user"s preferred maps provider;
const observer = new MutationObserver((mutationsList) => {
for (let mutation of mutationsList) {
if (mutation.type === "childList" && mutation.addedNodes.length > 0) {
for (let node of mutation.addedNodes) {
if (node.nodeName.toLowerCase() === "path" || node.nodeName.toLowerCase() === "canvas") {
pathCounter++;
if (pathCounter === 5) {
addMapsTab();
}
if (node.classList.contains("maplibregl-canvas")) {
addButtonToMiniMap(node);
}
}
}
}
}
});
// If tabs exist, start the observer
if (tabsContainer) {
observer.observe(document, { attributes: false, childList: true, subtree: true });
}
// Getting the base URL from user settings
chrome.storage.sync.get(["mapsProvider"], function(result) {
if (result.mapsProvider) {
if (result.mapsProvider.includes("%s")) {
mapsURL = result.mapsProvider.replace("%s", query);
} else {
mapsURL = result.mapsProvider + query;
}
} else {
mapsURL = "https://google.com/maps?q=" + query;
}
});
// if tabs exist, add the maps tab
function addMapsTab() {
const newsTab = tabsContainer.childNodes[4];
const mapsTab = newsTab.cloneNode(true); // Clone the button with its children (that's why we need the true argument)
// Modify the duplicated tab
mapsTab.childNodes[0].href = mapsURL;
mapsTab.childNodes[0].childNodes[2].innerText = mapsName;
swapSvg(mapsTab);
tabsContainer.insertBefore(mapsTab, newsTab);
if (directionsButton) {
addButtonToPlaceSnippet();
}
}
// If a "Place" snippet is shown, add a new button that allows user to open it in their preferred maps provider before the directions button
function addButtonToPlaceSnippet() {
directionsButton = directionsButton.childNodes[0].childNodes[2]; // We need the children to get the directions button we want to clone because it itself doesn't have a unique identifier
const mapsButton = directionsButton.cloneNode(true); // Clone the button with its children (that's why we need the true argument)
// Modify the duplicated button
mapsButton.childNodes[2].innerText = mapsName;
swapSvg(mapsButton);
// Add the event listener to the new button as for some reason setting the href attribute doesn't work
mapsButton.addEventListener("click", function() {
window.location.href = mapsURL;
});
// Insert the new button before the directionsButton
directionsButton.parentNode.insertBefore(mapsButton, directionsButton);
}
// If a minimap is shown, add a new button within that map that allows user to open it in their preferred maps provider instead while persisting the normal behavior of extending the map container if clicked within the UI map element
function addButtonToMiniMap(mapContainer) {
const mapWrapperLinkEl = document.createElement("a");
mapWrapperLinkEl.href = mapsURL;
mapWrapperLinkEl.classList.add("map-link", "custom-button"); // Add a class for the CSS
const mapsIcon = document.createElementNS("http://www.w3.org/2000/svg", "svg");
mapsIcon.width = "24";
mapsIcon.height = "24";
mapsIcon.setAttribute("viewBox", iconViewBox);
mapsIcon.classList.add("icon", "map-icon"); // Add a class for the CSS
const mapsPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
mapsPath.setAttribute("fill-rule", "evenodd");
mapsPath.setAttribute("clip-rule", "evenodd");
mapsPath.setAttribute("d", mapIcon);
mapsIcon.appendChild(mapsPath);
mapWrapperLinkEl.prepend(mapsIcon);
mapContainer.parentNode.append(mapWrapperLinkEl);
}
function swapSvg(element) {
const svgElement = element.childNodes[0].childNodes[0];
svgElement.setAttribute("viewBox", iconViewBox);
svgElement.childNodes[0].setAttribute("d", mapIcon);
}