// ==UserScript==
// @name WME RTC Manager
// @description Utility to manage RTC
// @namespace [email protected]
// @grant none
// @grant GM_info
// @version 0.0.2
// @include /^https:\/\/(www|beta)\.waze\.com\/(?!user\/)(.{2,6}\/)?editor.*$/
// @exclude https://www.waze.com/user/*editor/*
// @exclude https://www.waze.com/*/user/*editor/*
// @author GyllieGyllie
// @license MIT/BSD/X11
// @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// ==/UserScript==
/* Changelog
*/
/* global W */
/* global I18n */
/* global $ */
const ScriptName = GM_info.script.name;
const ScriptVersion = GM_info.script.version;
let ChangeLog = "RTC Manager has been updated to " + ScriptVersion + "<br />";
ChangeLog = ChangeLog + "<br /><b>New: </b>";
ChangeLog = ChangeLog + "<br />" + "- (0.0.1) Ability to select all linked segments with a matching closure";
ChangeLog = ChangeLog + "<br /><b>Updated: </b>";
ChangeLog = ChangeLog + "<br />" + "- (0.0.2) Fix not all segments being selected in some scenarios";
let wmeSDK;
const options = loadOptions();
// Now validate the options are ok
validateOptions(options);
function log(message) {
if (typeof message === 'string') {
console.log('RTC Manager: ' + message);
} else {
console.log('RTC Manager: ', message);
}
}
// the sdk init function will be available after the WME is initialized
function WMERTCManager_bootstrap() {
if (!document.getElementById('edit-panel') || !wmeSDK.DataModel.Countries.getTopCountry() || !WazeWrap.Ready) {
setTimeout(WMERTCManager_bootstrap, 250);
return;
}
if (wmeSDK.State.isReady) {
WMERTCManager_init();
} else {
wmeSDK.Events.once({ eventName: "wme-ready" }).then(WMERTCManager_init);
}
}
function WMERTCManager_init() {
log("Start");
// check for changes in the edit-panel
const speedLimitsObserver = new MutationObserver((mutations) => {
mutations.forEach(function(mutation) {
// Mutation is a NodeList and doesn't support forEach like an array
for (let i = 0; i < mutation.addedNodes.length; i++) {
const addedNode = mutation.addedNodes[i];
// Only fire up if it's a node
if (addedNode.nodeType === Node.ELEMENT_NODE) {
if (addedNode.querySelector('div.closures')) {
makeListButtons();
}
}
}
makeDetailsButtons();
});
});
speedLimitsObserver.observe(document.getElementById('edit-panel'), { childList: true, subtree: true });
// Catch permalinks
//makeSigns();
constructSettings();
displayChangelog();
log("Done");
}
// Check if unsafeWindow is availabe, if so use that
('unsafeWindow' in window ? window.unsafeWindow : window).SDK_INITIALIZED.then(() => {
// initialize the sdk with your script id and script name
wmeSDK = getWmeSdk({scriptId: "wme-rtc-manager", scriptName: "RTC Manager"});
WMERTCManager_bootstrap();
});
function displayChangelog() {
if (!WazeWrap.Interface) {
setTimeout(displayChangelog, 1000);
return;
}
// Alert the user version updates
if (options.lastAnnouncedVersion === ScriptVersion) {
log('Version: ' + ScriptVersion);
} else {
WazeWrap.Interface.ShowScriptUpdate(ScriptName, ScriptVersion, ChangeLog + "<br /><br />", "https://github.com/wazers/rtc-manager");
const updateName = "#wmertcmanager" + ScriptVersion.replaceAll(".", "");
$(updateName + " .WWSUFooter a").text("Github")
options.lastAnnouncedVersion = ScriptVersion;
saveOptions(options);
}
}
function makeListButtons() {
const container = $('div.closures-list');
/*const selectAllButton = $('<wz-button size="sm" style="width: 100%; margin-top: 10px;">Select all</wz-button>');
selectAllButton.on('click', selectAll);
container.append(selectAllButton);*/
/*const saveButton = $('<wz-button size="sm" style="width: 100%; margin-top: 10px;">Delete all</wz-button>');
saveButton.on('click', deleteAll);
container.append(saveButton);*/
}
function makeDetailsButtons() {
const container = $('div.closure');
if (!container) {
return;
}
const footer = $('div.closure div.action-buttons');
if ($("#rtcm-detail-all").length > 0) {
return;
}
const selectAllButton = $('<wz-button id="rtcm-detail-all" size="sm"">Select all</wz-button>');
selectAllButton.on('click', selectAll);
footer.append(selectAllButton);
}
function selectAll() {
const ids = [];
const footerIds = $('div[class^="closureFooterFragmentContainer"] > div > li');
footerIds.each((el) => ids.push($(footerIds[el]).text()));
if (ids.length === 0) return;
const nearbyClosures = wmeSDK.DataModel.RoadClosures.getAll();
let closure = nearbyClosures.find(closure => ids.indexOf(closure.id) >= 0);
const segmentIds = [];
const scanned = new Set();
if (closure) {
const segment = wmeSDK.DataModel.Segments.getById({ segmentId: closure.segmentId });
// Segment not found
if (!segment) {
return;
}
appendSegments(scanned, segmentIds, segment, closure);
}
wmeSDK.Editing.setSelection({
selection: {
ids: segmentIds,
objectType: 'segment'
}
});
}
function deleteAll() {
const selection = wmeSDK.Editing.getSelection();
if ("segment" !== selection.objectType) {
return;
}
const nearbyClosures = wmeSDK.DataModel.RoadClosures.getAll();
console.log(selection);
for (let segmentId of selection.ids) {
console.log(segmentId);
const segment = wmeSDK.DataModel.Segments.getById({ segmentId: segmentId });
console.log(segment);
if (!segment.hasClosures) {
continue;
}
}
}
function appendSegments(scanned, segmentIds, segment, originalClosure) {
// This was already scanned
if (scanned.has(segment.id)) {
return;
}
scanned.add(segment.id);
const closures = wmeSDK.DataModel.RoadClosures.getAll().filter(rc => rc.segmentId === segment.id);
// See if any closure matches
for (let closure of closures) {
if (originalClosure.description === closure.description
&& originalClosure.startDate === closure.startDate
&& originalClosure.endDate === closure.endDate
&& originalClosure.trafficEventId === closure.trafficEventId) {
segmentIds.push(segment.id);
break;
}
}
let linkedSegments = wmeSDK.DataModel.Segments.getConnectedSegments({ segmentId: segment.id });
for (let ls of linkedSegments) {
appendSegments(scanned, segmentIds, ls, originalClosure);
}
linkedSegments = wmeSDK.DataModel.Segments.getConnectedSegments({ segmentId: segment.id, reverseDirection: true });
for (let ls of linkedSegments) {
appendSegments(scanned, segmentIds, ls, originalClosure);
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////
////
//// Option Logic
////
////////////////////////////////////////////////////////////////////////////////////////////////////////////
function constructSettings() {
// -- Set up the tab for the script
wmeSDK.Sidebar.registerScriptTab().then(({ tabLabel, tabPane }) => {
tabLabel.innerText = 'RTC Manager';
tabLabel.title = 'RTC Manager Settings';
tabPane.innerHTML = '<div id="rtc-manager-settings"></div>';
const scriptContentPane = $('#rtc-manager-settings');
scriptContentPane.append(`<h2 style="margin-top: 0;">RTC Manager</h2>`);
scriptContentPane.append(`<span>Current Version: <b>${ScriptVersion}</b></span>`);
//addTextNumberSettings(scriptContentPane, '', 'Icon Scale in %', 'iconScale');
//addBooleanSettingsCallback(scriptContentPane, '', 'Enable Clear Sign', 'clearSign', toggleBoolean);
});
}
function getDefaultOptions() {
return {
lastAnnouncedVersion: '',
}
}
function loadOptions() {
let text = localStorage.getItem("RTC-Manager-Options");
let options;
if (text) {
options = JSON.parse(text);
} else {
options = getDefaultOptions();
}
return options;
}
function validateOptions(options) {
const defaultOptions = getDefaultOptions();
// Add missing options
for (let key in defaultOptions) {
if (!(key in options)) {
options[key] = defaultOptions[key]
}
}
}
function saveOptions(options) {
const optionsJson = JSON.stringify(options);
localStorage.setItem("RTC-Manager-Options", optionsJson);
}
function changeText(event) {
options[event.target.id] = event.target.value;
saveOptions(options);
}
function addTextNumberSettings(container, title, label, name, step = 1) {
const currentValue = options[name];
const textInput = $('<wz-text-input type="number" min="0" max="999" step="' + step + '" id="' + name + '" value="' + currentValue + '"></wz-text-input>');
const optionHtml = $('<div style="margin-top: 10px;"><span Title="' + title + '">' + label + '</span></div>').append(textInput);
container.append(optionHtml);
textInput.on('change', changeText);
}
function addBooleanSettingsCallback(container, title, label, name, clickHandler) {
const currentValue = options[name];
const checkbox = $('<wz-checkbox id="' + name + '" Title="' + title + '" name="types" disabled="false" checked="' + currentValue + '">' + label + '</wz-checkbox>');
const optionHtml = $('<div class="urcom-option"></div>').append(checkbox);
container.append(optionHtml);
checkbox.on('click', clickHandler);
}
function toggleBoolean(event) {
options[event.target.id] = event.target.checked;
saveOptions(options);
}