// ==UserScript==
// @name WME WazeMY
// @namespace https://greasyfork.org/en/scripts/404584-wazemy
// @version 2022.08.12.01
// @description WME script for WazeMY editing moderation
// @author junyianl
// @match https://beta.waze.com/*
// @match https://www.waze.com/forum/*
// @match https://www.waze.com/editor*
// @match https://www.waze.com/*/editor*
// @match https://www.waze.com/user/editor*
// @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @require https://greasyfork.org/scripts/449165-wme-wazemy-trafcamlist/code/wme-wazemy-trafcamlist.js
// @grant GM_xmlhttpRequest
// @license MIT
// ==/UserScript==
// @connect fgies.com
// @connect jalanow.com
/* global W */
/* global WazeWrap */
/* global $ */
/* global OL */
/* global OpenLayers */
/**
* All mentions of script names and links in this script is my way of giving
* credit to where it's due.
* Without those scripts, I would have no place to start.
* Big thanks to the original script authors.
*
* Huge thanks to the following contributors for cam locations around Malaysia.
* :: epailxi | dckj | firman_bakti | rickylo103 ::
*/
const updateMessage = `
► Added AKLEH and LDP cams.
`;
var staticUpdateID;
(function() {
'use strict';
var settings = {};
function bootstrap(tries = 1) {
if (W && W.map && W.model && W.loginManager.user &&
$ && WazeWrap.Ready) {
init();
} else if (tries < 1000) {
setTimeout(function () {bootstrap(++tries);}, 200);
} else {
WazeWrap.Alerts.error(GM_info.script.name, "Bootstrap timeout.")
}
}
async function init() {
let $section = $('<div>');
$section.html([
'<div>',
'Version: <span id="wazemyVersion"></span><br>',
'<span id="wazemyUsername"></span> (<span id="wazemyRank"></span>)',
'</div><br>',
'<div id="wazemySettings">',
'<b>Settings</b><br>',
'<input type="checkbox" id="wazemySettings_tooltip">',
'<label for="wazemySettings_tooltip">Map tooltip</label><br>',
'<input type="checkbox" id="wazemySettings_trafcam">',
'<label for="wazemySettings_trafcam">Traffic cameras</label><br>',
'</div><br>',
'<div>',
'<b>Shortcuts</b><br>',
'Ctrl+Alt+C: Copy lat/lon of mouse position to clipboard.<br>',
'</div>'
].join(' '));
// Initialize features of WME WazeMY
wazemyTooltip_init();
wazemyTrafcam_init();
new WazeWrap.Interface.Tab('WazeMY', $section.html(), initializeSettings);
WazeWrap.Interface.ShowScriptUpdate("WME WazeMY", GM_info.script.version,
updateMessage, "https://greasyfork.org/en/scripts/404584-wazemy", null);
// Initialize keyboard shortcuts
new WazeWrap.Interface.Shortcut('WazeMY_latloncopy',
'Copies lat/lon of mouse position', 'wazemy', 'WazeMY', 'CA+c',
wazemyCopyLatLon, null).add();
}
/* ******* */
/* Tooltip */
/* ******* */
function wazemyTooltip_init() {
let $tooltip = $('<div/>');
$tooltip.attr('id', 'wazemyTooltip');
$tooltip.css({
'height':'auto',
'width':'auto',
'background':'rgba(0,0,0,0.5)',
'color':'white',
'borderRadius':'5px',
'padding':'5px',
'position':'absolute',
'top':'0px',
'left':'0px',
'visibility':'hidden',
'zIndex':'10000'
})
$tooltip.appendTo('body');
}
function wazemyTooltip_initSettings() {
setChecked('wazemySettings_tooltip', settings.tooltip);
if (settings.tooltip) {
WazeWrap.Events.register('mousemove', null, wazemyTooltip_show);
}
$('#wazemySettings_tooltip').change(function () {
var settingName = $(this)[0].id.substr(15); // strip off the "wazemySettings_" prefix
settings[settingName] = this.checked;
saveSettings();
if (this.checked) {
WazeWrap.Events.register('mousemove', null, wazemyTooltip_show);
}
else {
$('#wazemyTooltip').css('visibility', 'hidden');
WazeWrap.Events.unregister('mousemove', null, wazemyTooltip_show);
}
});
}
function wazemyTooltip_show(e) { // from URO+
var result = '';
var showTooltip = false;
let landmark = W.map.venueLayer.getFeatureBy('renderIntent', 'highlight');
let segment = W.map.segmentLayer.getFeatureBy('renderIntent', 'highlight');
if (landmark != null) {
result = '<b>' + landmark.model.attributes.name + '</b><br>';
let address = landmark.model.getAddress();
try {
result += address.attributes.houseNumber ? (address.attributes.houseNumber + ', ') : ''
result += (address.attributes.street.name ? address.attributes.street.name : 'No street') + '<br>';
result += address.attributes.city.attributes.name + ', ';
result += address.attributes.state.name + '<br>';
}
catch {
result += 'No address<br>';
}
result += '<b>Lock:</b> ' + (landmark.model.getLockRank() + 1);
showTooltip = true;
} else if (segment != null) {
let segmentId = segment.model.attributes.id;
// let primaryStreetId = WazeWrap.Model.getPrimaryStreetId(segmentId);
let address = segment.model.getAddress();
result = '<b>';
result += address.attributes.street.name ? address.attributes.street.name : 'No street';
result += '</b><br>';
result += address.attributes.city.attributes.name + ', ' + address.attributes.state.name;
result += '<br>';
result += '<b>ID:</b> ' + segmentId + '<br>';
result += '<b>Lock:</b> ' + (segment.model.getLockRank() + 1);
showTooltip = true;
}
if (showTooltip == true) {
let tw = $('#wazemyTooltip').width();
let th = $('#wazemyTooltip').height();
var tooltipX = e.clientX + window.scrollX + 15;
var tooltipY = e.clientY + window.scrollY + 15;
// Handle cases where tooltip is too near the edge.
if ((tooltipX + tw) > W.map.$map.innerWidth()) {
tooltipX -= tw + 20; // 20 = scroll bar size
if (tooltipX < 0) tooltipX = 0;
}
if ((tooltipY + th) > W.map.$map.innerHeight()) {
tooltipY -= th + 20;
if (tooltipY < 0) tooltipY = 0;
}
$('#wazemyTooltip').html(result);
$('#wazemyTooltip').css({
'top':tooltipY + 'px',
'left':tooltipX + 'px',
'visibility':'visible'
});
} else {
$('#wazemyTooltip').css('visibility', 'hidden');
}
}
/* *************** */
/* Traffic cameras */
/* *************** */
// Adapted from WME DOT Cameras
var wazemyTrafcamLayer;
function wazemyTrafcam_init() {
if (!OpenLayers.Icon) {
wazemyTrafcam_installIconClass();
}
wazemyTrafcamLayer = new OpenLayers.Layer.Markers("wazemyTrafcamLayer");
W.map.addLayer(wazemyTrafcamLayer);
wazemyTrafcam_show();
wazemyTrafcamLayer.setVisibility(false);
}
function wazemyTrafcam_initSettings() {
setChecked('wazemySettings_trafcam', settings.trafcam);
if (settings.trafcam) {
wazemyTrafcamLayer.setVisibility(true);
// WazeWrap.Events.register('moveend', null, wazemyTrafcam_show);
}
$('#wazemySettings_trafcam').change(function () {
var settingName = $(this)[0].id.substr(15); // strip off the "wazemySettings_" prefix
settings[settingName] = this.checked;
saveSettings();
if (this.checked) {
wazemyTrafcamLayer.setVisibility(true);
// WazeWrap.Events.register('moveend', null, wazemyTrafcam_show);
} else {
// WazeWrap.Events.unregister('moveend', null, wazemyTrafcam_show);
wazemyTrafcamLayer.setVisibility(false);
}
});
}
function wazemyTrafcam_show(e) {
trafficCamsData.forEach(e => {
wazemyTrafcam_drawCam({
desc:e.desc,
src:e.url,
width:20,
height:20,
lat:e.lat,
lon:e.lon
});
});
}
function wazemyTrafcam_drawCam(spec) {
const camIcon = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAAGXcA1uAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAA2ZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMC1jMDYxIDY0LjE0MDk0OSwgMjAxMC8xMi8wNy0xMDo1NzowMSAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOk9yaWdpbmFsRG9jdW1lbnRJRD0ieG1wLmRpZDpBRDNGNTkwRTYzQThFMzExQTc4MDhDNjAwODdEMzdEQSIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDo2OUI0RUEyN0IwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDo2OUI0RUEyNkIwRjcxMUUzOERFM0E1OTJCRUY3NTFBOCIgeG1wOkNyZWF0b3JUb29sPSJBZG9iZSBQaG90b3Nob3AgQ1M1LjEgV2luZG93cyI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjZGOEJBMzExNkZCMEUzMTFCOEY5QTU3QUQxM0M2MjI5IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkFEM0Y1OTBFNjNBOEUzMTFBNzgwOEM2MDA4N0QzN0RBIi8+IDwvcmRmOkRlc2NyaXB0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';
let size = new OpenLayers.Size(20,20);
let icon = new OpenLayers.Icon(camIcon, size);
let epsg4326 = new OpenLayers.Projection("EPSG:4326"); // WGS 1984 projection. Malaysia uses EPSG:900913
let projectTo = W.map.getProjectionObject();
let lonLat = new OpenLayers.LonLat(spec.lon, spec.lat).transform(epsg4326, projectTo);
var newMarker = new OpenLayers.Marker(lonLat, icon);
newMarker.title = spec.desc;
newMarker.url = spec.src;
newMarker.width = spec.width;
newMarker.height = spec.height;
newMarker.location = lonLat;
newMarker.events.register('click', newMarker, wazemyTrafcam_popupCam);
wazemyTrafcamLayer.addMarker(newMarker);
}
function wazemyTrafcam_popupCam(e) {
console.log("wazemyTrafcam_popupCam");
clearInterval(staticUpdateID);
$("#gmPopupContainerCam").remove();
$("#gmPopupContainerCam").hide();
var popupHTML = ([`
<div id="gmPopupContainerCam" style="margin: 1;text-align: center;padding: 5px;z-index: 1100; position: absolute; color: white; background: rgba(0,0,0,0.5)">
<table border=0>
<tr>
<td><div id="mycamdivheader" style="min-height: 20px;white-space: pre-wrap;white-space: -moz-pre-wrap; white-space: -pre-wrap;white-space: -o-pre-wrap;word-wrap: break-word;width:380px">${this.title}</div></td>
<td align="right"><a href="#close" id="gmCloseCamDlgBtn" title="Close" style="color:red">X</a></td>
</tr>
<tr><td colspan=2><img style="width:400px" id="staticimage"></td></tr>
</table></div>
`]);
$("body").append(popupHTML);
GM_xmlhttpRequest({
method: 'GET',
responseType: 'blob',
headers: {
"authority":"p4.fgies.com",
"referer":'https://www.jalanow.com/',
'accept':'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8'
},
url: this.url,
onload: function (response) {
document.getElementById('staticimage').src = URL.createObjectURL(response.response);
}
});
// Handle cases where popup is too near the edge.
let tw = $('#gmPopupContainerCam').width();
let th = $('#gmPopupContainerCam').height() + 200;
var tooltipX = e.clientX + window.scrollX + 15;
var tooltipY = e.clientY + window.scrollY + 15;
if ((tooltipX + tw) > W.map.$map.innerWidth()) {
tooltipX -= tw + 20; // 20 = scroll bar size
if (tooltipX < 0) tooltipX = 0;
}
if ((tooltipY + th) > W.map.$map.innerHeight()) {
tooltipY -= th + 20;
if (tooltipY < 0) tooltipY = 0;
}
$("#gmPopupContainerCam").css({ left: tooltipX });
$("#gmPopupContainerCam").css({ top: tooltipY });
//Add listener for popup's "Close" button
$("#gmCloseCamDlgBtn").click(function () {
clearInterval(staticUpdateID);
$("#gmPopupContainerCam").remove();
$("#gmPopupContainerCam").hide();
});
wazemyTrafcam_dragElement(document.getElementById("gmPopupContainerCam"));
}
function wazemyTrafcam_installIconClass() {
OpenLayers.Icon = OpenLayers.Class({
url: null,
size: null,
offset: null,
calculateOffset: null,
imageDiv: null,
px: null,
initialize: function (a, b, c, d) {
this.url = a;
this.size = b || {
w: 20,
h: 20
};
this.offset = c || {
x: -(this.size.w / 2),
y: -(this.size.h / 2)
};
this.calculateOffset = d;
a = OpenLayers.Util.createUniqueID("OL_Icon_");
let div = this.imageDiv = OpenLayers.Util.createAlphaImageDiv(a);
$(div.firstChild).removeClass('olAlphaImg'); // LEAVE THIS LINE TO PREVENT WME-HARDHATS SCRIPT FROM TURNING ALL ICONS INTO HARDHAT WAZERS --MAPOMATIC
},
destroy: function () {
this.erase();
OpenLayers.Event.stopObservingElement(this.imageDiv.firstChild);
this.imageDiv.innerHTML = "";
this.imageDiv = null;
},
clone: function () {
return new OpenLayers.Icon(this.url, this.size, this.offset, this.calculateOffset);
},
setSize: function (a) {
null !== a && (this.size = a);
this.draw();
},
setUrl: function (a) {
null !== a && (this.url = a);
this.draw();
},
draw: function (a) {
OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, this.size, this.url, "absolute");
this.moveTo(a);
return this.imageDiv;
},
erase: function () {
null !== this.imageDiv && null !== this.imageDiv.parentNode && OpenLayers.Element.remove(this.imageDiv);
},
setOpacity: function (a) {
OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, null, null, null, null, null, null, a);
},
moveTo: function (a) {
null !== a && (this.px = a);
null !== this.imageDiv && (null === this.px ? this.display(!1) : (
this.calculateOffset && (this.offset = this.calculateOffset(this.size)),
OpenLayers.Util.modifyAlphaImageDiv(this.imageDiv, null, {
x: this.px.x + this.offset.x,
y: this.px.y + this.offset.y
})
));
},
display: function (a) {
this.imageDiv.style.display = a ? "" : "none";
},
isDrawn: function () {
return this.imageDiv && this.imageDiv.parentNode && 11 != this.imageDiv.parentNode.nodeType;
},
CLASS_NAME: "OpenLayers.Icon"
});
}
// Make the DIV element draggable:
function wazemyTrafcam_dragElement(elmnt) {
var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
if (document.getElementById("mycamdivheader")) {
// if present, the header is where you move the DIV from:
document.getElementById("mycamdivheader").onmousedown = dragMouseDown;
} else {
// otherwise, move the DIV from anywhere inside the DIV:
elmnt.onmousedown = dragMouseDown;
}
function dragMouseDown(e) {
e = e || window.event;
e.preventDefault();
// get the mouse cursor position at startup:
pos3 = e.clientX;
pos4 = e.clientY;
document.onmouseup = closeDragElement;
// call a function whenever the cursor moves:
document.onmousemove = elementDrag;
}
function elementDrag(e) {
e = e || window.event;
e.preventDefault();
// calculate the new cursor position:
pos1 = pos3 - e.clientX;
pos2 = pos4 - e.clientY;
pos3 = e.clientX;
pos4 = e.clientY;
// set the element's new position:
elmnt.style.top = (elmnt.offsetTop - pos2) + "px";
elmnt.style.left = (elmnt.offsetLeft - pos1) + "px";
}
function closeDragElement() {
// stop moving when mouse button is released:
document.onmouseup = null;
document.onmousemove = null;
}
}
/* ************ */
/* Copy lat/lon */
/* ************ */
function wazemyCopyLatLon(){
copyToClipboard($('.mouse-position').text());
}
function initializeSettings() {
loadSettings();
$('#wazemyVersion').text(GM_info.script.version);
$('#wazemyUsername').text(WazeWrap.User.Username());
$('#wazemyRank').text(WazeWrap.User.Rank());
wazemyTooltip_initSettings();
wazemyTrafcam_initSettings();
}
function saveSettings() {
if (localStorage) {
var localsettings = {
tooltip: settings.tooltip,
trafcam: settings.trafcam
};
localStorage.setItem('WME_wazemySettings', JSON.stringify(localsettings));
}
}
function loadSettings() {
var loadedSettings = $.parseJSON(localStorage.getItem("WME_wazemySettings"));
var defaultSettings = {
tooltip: false,
};
settings = loadedSettings ? loadedSettings : defaultSettings;
for (var prop in defaultSettings) {
if (!settings.hasOwnProperty(prop)) {
settings[prop] = defaultSettings[prop];
}
}
}
function setChecked(checkboxId, checked) {
$('#' + checkboxId).prop('checked', checked);
}
// utility functions
var copyToClipboard = function(str) { // from PIE
var $temp = $('<input>');
$('body').append($temp);
$temp.val(str).select();
document.execCommand('copy');
$temp.remove();
};
bootstrap();
})();