您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Shows "Bad Angle Infos" of all Junctions in the editing area
// ==UserScript== // @name WME Bad Junction Angle Info // @description Shows "Bad Angle Infos" of all Junctions in the editing area // @match https://beta.waze.com/*editor* // @match https://www.waze.com/*editor* // @exclude https://www.waze.com/*user/*editor/* // @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js // @version 1.9.13 // @grant GM_addElement // @namespace https://wms.kbox.at/ // @copyright 2021 Gerhard; 2018 seb-d59, 2016 Michael Wikberg <[email protected]> // @license CC-BY-NC-SA // @icon data:image/png;base64,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 // ==/UserScript== /** * This script is based on the code from "WME Junction angle Info". * Thanks for the great work to the authors of the original script: */ /** * Copyright 2016 Michael Wikberg <[email protected]> * WME Junction Angle Info extension is licensed under a Creative Commons * Attribution-NonCommercial-ShareAlike 3.0 Unported License. * * Contributions by: * 2014 Paweł Pyrczak "tkr85" <[email protected]> * 2014 "AlanOfTheBerg" <[email protected]> * 2014 "berestovskyy" <?> * 2015 "FZ69617" <?> * 2015 "wlodek76" <?> * 2016 Sergey Kuznetsov "WazeRus" <[email protected]> (Russian translation) * 2016 "MajkiiTelini" <?> Czech translation * 2016 "witoco" <?> (Latin-American Spanish translation) * 2017 "seb-d59" (Check override instruction and French translation) <https://www.waze.com/forum/memberlist.php?mode=viewprofile&u=16863068> * 2019 thank to Sapozhnik for the Ukrainian (український) translation */ /*jshint eqnull:true, nonew:true, nomen:true, curly:true, latedef:true, unused:strict, noarg:true, loopfunc:true */ /*jshint trailing:true, forin:true, noempty:true, maxparams:7, maxerr:100, eqeqeq:true, strict:true, undef:true */ /*jshint bitwise:true, newcap:true, immed:true, onevar:true, browser:true, nonbsp:true, freeze:true */ /*global I18n, $*/ /* global _ */ /* global W */ /* global WazeWrap */ function run_aja() { "use strict"; // var TURN_ANGLE = 45.50; //Turn vs. keep angle - based on map experiments (45.04 specified in Wiki). // var GRAY_ZONE = 1.5; //Gray zone angle intended to prevent from irregularities observed on map. /* * First some variable and enumeration definitions */ var junctionangle_version = "1.9.13"; var name = "Bad Junction Angle Info"; const AJA_UPDATE_NOTES = `<b>FIX:</b><br> - Update for new Beta WME<br>`; var junctionangle_debug = 0; //0: no output, 1: basic info, 2: debug 3: verbose debug, 4: insane debug var aja_last_restart = 0; var aja_roundabout_points = []; var aja_options = {}; var aja_mapLayer; // var scriptenabled = true; var pointSize = 12; var decimals = 2; var AJASettings = {}; var country; var withRouting = true; var aja_vehicle_types = { TRUCK: 1, PUBLIC: 2, TAXI: 4, BUS: 8, HOV2: 16, HOV3: 32, RV: 64, TOWING: 128, MOTORBIKE: 256, PRIVATE: 512, HAZ: 1024 }; const css = [ '.aja-wrapper {position:relative;width:100%;font-size:12px;font-family:"Rubik", "Boing-light", sans-serif;user-select:none;}', '.aja-section-wrapper {display:block;width:100%;padding:4px;}', '.aja-section-wrapper.border {border-bottom:1px solid grey;margin-bottom:5px;}', '.aja-header {font-weight:bold;}', '.aja-option-container {padding:3px;}', '.aja-option-container.no-display {display:none;}', '.aja-option-container.sub {margin-left:20px;}', 'input[type="checkbox"].aja-checkbox {display:inline-block;position:relative;top:3px;vertical-align:top;margin:0;}', 'input[type="color"].aja-color-input {display:inline-block;position:relative;width:20px;padding:0px 1px;border:0px;vertical-align:top;cursor:pointer;}', 'input[type="color"].aja-color-input:focus {outline-width:0;}', 'label.aja-label {display:inline-block;position:relative;max-width:80%;vertical-align:top;font-weight:normal;padding-left:5px;word-wrap:break-word;}', '.group-title.toolbar-top-level-item-title.rsa:hover {cursor:pointer;}' ].join(' '); const TRANSLATIONS = { default: { scriptTitle: 'Bad Junction Angle Info', scriptenabled: 'Script enabled', check: 'Check for TIOs and Restrictions', skiproundabout: 'Skip Roundabouts' } }; /* * Main logic functions */ function junctionangle_init() { // Register event listeners WazeWrap.Events.register('selectionchanged', null, aja_calculate); WazeWrap.Events.register('moveend', null, aja_calculate); WazeWrap.Events.register('afteraction', null, aja_calculate); WazeWrap.Events.register('moveend', null, aja_calculate); window.W.model.segments.on({ "objectschanged": aja_calculate, "objectsremoved": aja_calculate }); window.W.model.nodes.on({ "objectschanged": aja_calculate, "objectsremoved": aja_calculate }); window.W.map.olMap.events.register("zoomend", null, aja_calculate); window.W.map.olMap.events.register("move", null, aja_calculate); const $section = $('<div>'); // HTML for UI tab $section.html([ `<div class='aja-wrapper' id='aja-tab-wrapper'> <div style='margin-bottom:5px;border-bottom:1px solid black;'> <span style='font-weight:bold;'> <a href='https://www.waze.com/forum/viewtopic.php?t=334486' target='_blank' style='text-decoration:none;'>${name}</a> </span> - v${junctionangle_version} </div> <div class="aja-option-container"> <input type=checkbox class='aja-checkbox' id='aja-scriptenabled' /> <label class='aja-label' for='aja-enableScript'><span id='aja-text-enableScript'>${TRANSLATIONS.default.scriptenabled}</span></label> </div> <div class='aja-option-container'> <input type=checkbox class='aja-checkbox' id='aja-check' /> <label class='aja-label' for='aja-CeckTIOs'><span id='aja-text-Check'>${TRANSLATIONS.default.check}</span></label> </div> <div class='aja-option-container'> <input type=checkbox class='aja-checkbox' id='aja-skiproundabout' /> <label class='aja-label' for='aja-SkipRoundabout'><span id='aja-text-SkipRoundabout'>${TRANSLATIONS.default.skiproundabout}</span></label> </div> </div>` ].join(' ')); // Attach HTML for tab to webpage // UpdateObj = require('Waze/Action/UpdateObject'); // Script is initialized and the highlighting layer is created WazeWrap.Interface.Tab('BJAI', $section.html(), initializeSettings, 'BJAI'); WazeWrap.Interface.ShowScriptUpdate(name, junctionangle_version, AJA_UPDATE_NOTES, 'https://greasyfork.org/en/scripts/434562-wme-bad-junction-angle-info', 'https://www.waze.com/forum/viewtopic.php?t=334486'); async function initializeSettings() { await loadSettings(); setEleStatus(); $(`<style type="text/css">${css}</style>`).appendTo('head'); } //Add support for translations. Default (and fallback) is "en". //Note, don't make typos in "acceleratorName", as it has to match the layer name (with whitespace removed) // to actually work. Took me a while to figure that out... I18n.translations[window.I18n.locale].layers.name.alljunction_angles = name; /** * Initialize BJAI OpenLayers vector layer */ if (window.W.map.getLayersBy("uniqueName","alljunction_angles").length === 0) { // Create a vector layer and give it your style map. aja_mapLayer = new window.OpenLayers.Layer.Vector(name, { displayInLayerSwitcher: true, uniqueName: "alljunction_angles", shortcutKey: "S+j", accelerator: "toggle" + name.replace(/\s+/g,''), className: "alljunction-angles", styleMap: new window.OpenLayers.StyleMap(aja_style()) }); window.W.map.addLayer(aja_mapLayer); aja_log("version " + junctionangle_version + " loaded.", 0); aja_log(window.W.map, 3); aja_log(window.W.model, 3); aja_log(window.W.loginManager, 3); aja_log(window.W.selectionManager, 3); aja_log(aja_mapLayer, 3); aja_log(window.OpenLayers, 3); } else { aja_log("Oh, nice.. We already had a layer?", 3); } WazeWrap.Interface.AddLayerCheckbox("display", "Bad Junction Angle Info", true, LayerToggled); $('.aja-checkbox').change(function () { let settingName = $(this)[0].id.substr(4); AJASettings[settingName] = this.checked; saveSettings(); aja_mapLayer.setVisibility(AJASettings.scriptenabled); aja_calculate(); }); aja_apply(); // MTE mode event // reload after changing WME units W.prefs.on('change:isImperial', function(){ aja_apply(); }); aja_calculate(); } function LayerToggled(checked){ aja_mapLayer.setVisibility(checked); AJASettings.scriptenabled = checked; setChecked('aja-scriptenabled', AJASettings.scriptenabled); } function findLayer(partOf_id){ var layer; for (var i=0; i < window.W.map.layers.length; i++){ if (window.W.map.layers[i].id.search(partOf_id) != -1){ layer={id: window.W.map.layers[i].id, name: window.W.map.layers[i].name, number : i}; aja_log("Number: " + i + "; id : " + layer.id + "; name :" + layer.name ,3); return layer; } } } function testLayerZIndex(){ // seb-d59: // Here i search the selection layer and i read the z-index // and put BJAI's layer under this one. var zIndex = 0; aja_mapLayer.setZIndex(500); // now selection layer has no name ... var layer = {} layer = findLayer("OpenLayers_Layer_Vector_RootContainer"); var layerOBJ = window.W.map.layers[layer.number]; //aja_log("id : " + layerOBJ.id + "; name :" + layerOBJ.name + " zIndex: " + layerOBJ.getZIndex() ,3); zIndex = parseInt(layerOBJ.getZIndex()) - 1 ; aja_mapLayer.setZIndex(zIndex); aja_log("aja_mapLayer new zIndex: " + aja_mapLayer.getZIndex() ,3); } function aja_calculate_real() { var aja_start_time = Date.now(); var aja_nodes = []; var restart = false; aja_log("Actually calculating now", 2); aja_roundabout_points = []; aja_log(window.W.map, 3); if (typeof aja_mapLayer === 'undefined') { return; } //clear old info aja_mapLayer.destroyFeatures(); testLayerZIndex(); if (!AJASettings.scriptenabled) return; _.each(W.model.segments.getObjectArray(), s => { if(![5, 10, 16, 18, 19].includes(s.attributes.roadType)){ let segmentsAtt = s.attributes; if (segmentsAtt.fromNodeID != null && aja_nodes.indexOf(segmentsAtt.fromNodeID) === -1) { aja_nodes.push(segmentsAtt.fromNodeID); } if (segmentsAtt.toNodeID != null && aja_nodes.indexOf(segmentsAtt.toNodeID) === -1) { aja_nodes.push(segmentsAtt.toNodeID); } } }); aja_log(aja_nodes, 3); var aja_label_distance; /* * Define a base distance to markers, depending on the zoom level */ switch (window.W.map.olMap.zoom) { case 22: //10: aja_label_distance = 2.8; break; case 21: //9: aja_label_distance = 4; break; case 20: //8: aja_label_distance = 8; break; case 19: //7: aja_label_distance = 15; break; case 18: //6: aja_label_distance = 25; break; case 17: //5: aja_label_distance = 40; break; case 16: //4: aja_label_distance = 80; break; case 15: //3: aja_label_distance = 150; break; case 14: //2: aja_label_distance = 300; break; case 13: //1: aja_label_distance = 400; break; default: aja_log("Unsupported zoom level: " + window.W.map.olMap.zoom + "!", 2); } aja_label_distance *= (1 + (0.2 * parseInt(decimals))); aja_log("zoom: " + window.W.map.olMap.zoom + " -> distance: " + aja_label_distance, 2); //Start looping through selected nodes for (var i = 0; i < aja_nodes.length; i++) { var node = getByID(window.W.model.nodes,aja_nodes[i]); var angles = []; var aja_selected_segments_count = 0; var aja_selected_angles = []; var a; if (node == null || !node.hasOwnProperty('attributes')) { //Oh oh.. should not happen? We want to use a node that does not exist aja_log("Oh oh.. should not happen?",2); aja_log(node, 2); aja_log(aja_nodes[i], 2); aja_log(window.W.model, 3); aja_log(window.W.model.nodes, 3); continue; } //check connected segments var aja_current_node_segments = node.attributes.segIDs; aja_log("Alle aja_current_node_segments",2); aja_log(aja_current_node_segments.length,2); aja_log(node, 2); aja_log(aja_current_node_segments.length,2); //ignore of we have less than 2 segments if (aja_current_node_segments.length <= 2) { aja_log("Found only " + aja_current_node_segments.length + " connected segments at " + aja_nodes[i] + ", not calculating anything...", 2); continue; } aja_log("Mehr als 2 aja_current_node_segments",2); aja_log(aja_current_node_segments.length,2); aja_log("Calculating angles for " + aja_current_node_segments.length + " segments", 2); aja_log(aja_current_node_segments, 3); aja_current_node_segments.forEach(function (nodeSegment, j) { var s = window.W.model.segments.objects[nodeSegment]; if(typeof s === 'undefined') { //Meh. Something went wrong, and we lost track of the segment. This needs a proper fix, but for now // it should be sufficient to just restart the calculation aja_log("Failed to read segment data from model. Restarting calculations.", 1); if(aja_last_restart === 0) { aja_last_restart = new Date().getTime(); setTimeout(function(){aja_calculate();}, 500); } restart = true; } a = aja_getAngle(aja_nodes[i], s); aja_log("Segment " + nodeSegment + " angle is " + a, 2); angles[j] = [a, nodeSegment, s == null ? false : true, s.attributes.roadType]; if (s == null ? false : true) { aja_selected_segments_count++; } }); if(restart) { return; } for( var ii = 0; ii < angles.length; ii++){ if([5, 10, 16, 18, 19].includes(angles[ii][3])){ angles.splice(ii, 1); ii--; } } aja_log(angles, 2); var ha, point; //sort angle data (ascending) angles.sort(function (a, b) { return a[0] - b[0]; }); aja_log(angles, 3); aja_log(aja_selected_segments_count, 3); //get all segment angles for (var iii = 0; iii < angles.length - 1; iii++) { for (var jjj = iii + 1; jjj < angles.length; jjj++) { a = (360 + (angles[(jjj) % angles.length][0] - angles[iii][0])) % 360; if (a > 180) { a = 360 - a; ha = (360 + ((a / 2) + angles[jjj][0])) % 360; } else { ha = (360 + ((a / 2) + angles[iii][0])) % 360; } aja_log(a,3); aja_log("Angle between " + angles[iii][1] + " and " + angles[(jjj) % angles.length][1] + " is " + a + " and position for label should be at " + ha, 1); // if (a < 10.26 || (a > 133 && a < 136 )) { if ((a > 133 && a < 136 )) { point = new window.OpenLayers.Geometry.Point( node.getOLGeometry().x + (aja_label_distance * 1.25 * Math.cos((ha * Math.PI) / 180)), node.getOLGeometry().y + (aja_label_distance * 1.25 * Math.sin((ha * Math.PI) / 180)) ); // Respect Trunrestrictons and TIOs var s1 = getByID(window.W.model.segments,angles[iii][1]) var s2 = getByID(window.W.model.segments,angles[(jjj) % angles.length][1]) var draw_marker = true; if (AJASettings.check) { draw_marker = false; if (aja_is_turn_allowed(s1, node, s2)) { var WazeModelGraphTurnData = window.require("Waze/Model/Graph/TurnData"); var turn = new WazeModelGraphTurnData(); turn = window.W.model.getTurnGraph().getTurnThroughNode(node, s1, s2); var opcode = turn.getTurnData().getInstructionOpcode(); if(!opcode) { if (aja_is_turn_allowed(s2, node, s1)) { turn = window.W.model.getTurnGraph().getTurnThroughNode(node, s2, s1); opcode = turn.getTurnData().getInstructionOpcode(); if(!opcode) { draw_marker = true; } } } } if (s1.attributes.junctionID || s2.attributes.junctionID) { draw_marker = false; } } if (AJASettings.skiproundabout) { if(getByID(window.W.model.segments,angles[iii][1]).attributes.junctionID) { draw_marker = false; } if(getByID(window.W.model.segments,angles[(jjj) % angles.length][1]).attributes.junctionID) { draw_marker = false; } } if (draw_marker) { aja_draw_marker(point, node, aja_label_distance, a, ha); } } } } } aja_last_restart = 0; var aja_end_time = Date.now(); aja_log("Calculation took " + String(aja_end_time - aja_start_time) + " ms", 2); } /* * Drawing functions */ /** * * @param point Estimated point for marker * @param node Node the marker is for * @param aja_label_distance Arbitrary distance to be used in moving markers further away etc * @param a Angle to display * @param ha Angle to marker from node (FIXME: either point or ha is probably unnecessary) * @param withRouting true: show routing guessing markers, false: show "normal" angle markers * @param aja_junction_type If using routing, this needs to be set to the desired type */ function aja_draw_marker(point, node, aja_label_distance, a, ha, withRouting, aja_junction_type) { //Try to estimate of the point is "too close" to another point //(or maybe something else in the future; like turn restriction arrows or something) //FZ69617: Exctract initial label distance from point var aja_tmp_distance = Math.abs(ha) % 180 < 45 || Math.abs(ha) % 180 > 135 ? (point.x - node.getOLGeometry().x) / (Math.cos((ha * Math.PI) / 180)) : (point.y - node.getOLGeometry().y) / (Math.sin((ha * Math.PI) / 180)); aja_log("Starting distance estimation", 3); while(aja_mapLayer.features.some(function(feature){ if(typeof feature.attributes.aja_type !== 'undefined' && feature.attributes.aja_type !== 'roundaboutOverlay') { //Arbitrarily chosen minimum distance.. Should actually use the real bounds of the markers, //but that didn't work out.. Bounds are always 0.. if(aja_label_distance / 1.4 > feature.geometry.distanceTo(point)) { aja_log(aja_label_distance / 1.5 > feature.geometry.distanceTo(point) + " is kinda close..", 3); return true; } } return false; })) { //add 1/4 of the original distance and hope for the best =) aja_tmp_distance += aja_label_distance / 4; aja_log("setting distance to " + aja_tmp_distance, 2); point = new window.OpenLayers.Geometry.Point( node.getOLGeometry().x + (aja_tmp_distance * Math.cos((ha * Math.PI) / 180)), node.getOLGeometry().y + (aja_tmp_distance * Math.sin((ha * Math.PI) / 180)) ); } aja_log("Distance estimation done", 3); var anglePoint = new window.OpenLayers.Feature.Vector( point, { angle: aja_round(180 - a) + "°", aja_type: "generic" } ); aja_log(anglePoint, 3); //Draw a line to the point aja_mapLayer.addFeatures([ new window.OpenLayers.Feature.Vector( new window.OpenLayers.Geometry.LineString([node.getOLGeometry(), point]), {}, {strokeOpacity: 0.9, strokeWidth: 2.2, strokeDashstyle: "solid", strokeColor: "#ff9966"} ) ] ); //push the angle point aja_mapLayer.addFeatures([anglePoint]); } function aja_get_first_point(segment) { return segment.getOLGeometry().components[0]; } function aja_get_last_point(segment) { return segment.getOLGeometry().components[segment.getOLGeometry().components.length - 1]; } function aja_get_second_point(segment) { return segment.getOLGeometry().components[1]; } function aja_get_next_to_last_point(segment) { return segment.getOLGeometry().components[segment.getOLGeometry().components.length - 2]; } //get the absolute angle for a segment end point function aja_getAngle(aja_node, aja_segment) { aja_log("node: " + aja_node, 2); aja_log("segment: " + aja_segment, 2); if (aja_node == null || aja_segment == null) { return null; } var aja_dx, aja_dy; if (aja_segment.attributes.fromNodeID === aja_node) { aja_dx = aja_get_second_point(aja_segment).x - aja_get_first_point(aja_segment).x; aja_dy = aja_get_second_point(aja_segment).y - aja_get_first_point(aja_segment).y; } else { aja_dx = aja_get_next_to_last_point(aja_segment).x - aja_get_last_point(aja_segment).x; aja_dy = aja_get_next_to_last_point(aja_segment).y - aja_get_last_point(aja_segment).y; } aja_log(aja_node + " / " + aja_segment + ": dx:" + aja_dx + ", dy:" + aja_dy, 2); var aja_angle = Math.atan2(aja_dy, aja_dx); return ((aja_angle * 180 / Math.PI)) % 360; } /** * Decimal adjustment of a number. Borrowed (with some modifications) from * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/round * aja_round(55.55); with 1 decimal // 55.6 * aja_round(55.549); with 1 decimal // 55.5 * aja_round(55); with -1 decimals // 60 * aja_round(54.9); with -1 decimals // 50 * * @param {Number} value The number. * @returns {Number} The adjusted value. */ function aja_round(value) { var aja_rounding = -parseInt(decimals); var valueArray; if (typeof aja_rounding === 'undefined' || +aja_rounding === 0) { return Math.round(value); } value = +value; // If the value is not a number or the exp is not an integer... if (isNaN(value) || !(typeof aja_rounding === 'number' && aja_rounding % 1 === 0)) { return NaN; } // Shift valueArray = value.toString().split('e'); value = Math.round(+(valueArray[0] + 'e' + (valueArray[1] ? (+valueArray[1] - aja_rounding) : -aja_rounding))); // Shift back valueArray = value.toString().split('e'); return +(valueArray[0] + 'e' + (valueArray[1] ? (+valueArray[1] + aja_rounding) : aja_rounding)); } /* * WME interface helper functions */ var aja_apply = function applyAJAOptions() { aja_log("Applying stored (or default) settings", 2); if(typeof window.W.map.getLayersBy("uniqueName","alljunction_angles")[0] === 'undefined') { aja_log("WME not ready yet, trying again in 400 ms", 2); setTimeout(function(){aja_apply();}, 400); return; } window.W.map.getLayersBy("uniqueName","alljunction_angles")[0].styleMap = aja_style(); aja_calculate_real(); aja_log(aja_options, 2); }; var aja_reset = function resetAJAOptions() { aja_log("Resetting settings", 2); if(localStorage != null) { localStorage.removeItem("wme_bja_options"); } aja_options = {}; aja_apply(); return false; }; var aja_calculation_timer = { start: function() { aja_log("Starting timer", 2); this.cancel(); var aja_calculation_timer_self = this; this.timeoutID = window.setTimeout(function(){aja_calculation_timer_self.calculate();}, 200); }, calculate: function() { aja_calculate_real(); delete this.timeoutID; }, cancel: function() { if(typeof this.timeoutID === "number") { window.clearTimeout(this.timeoutID); aja_log("Cleared timeout ID : " + this.timeoutID, 2); delete this.timeoutID; } } }; function aja_calculate() { aja_calculation_timer.start(); } function aja_style() { aja_log("Point radius will be: " + (parseInt(pointSize, 10)) + (parseInt(decimals > 0 ? (4 * parseInt(decimals)).toString() : "0")), 2); return new window.OpenLayers.Style({ fillColor: "#ffff00", strokeColor: "#ff9966", strokeWidth: 2, label: "${angle}", fontWeight: "bold", pointRadius: parseInt(pointSize, 10) + (parseInt(decimals) > 0 ? 4 * parseInt(decimals) : 0), fontSize: "10px" }); } function aja_is_turn_allowed(s_from, via_node, s_to) { aja_log("Allow from " + s_from.attributes.id + " to " + s_to.attributes.id + " via " + via_node.attributes.id + "? " + via_node.isTurnAllowedBySegDirections(s_from, s_to) + " | " + s_from.isTurnAllowed(s_to, via_node), 2); //Is there a driving direction restriction? if(!via_node.isTurnAllowedBySegDirections(s_from, s_to)) { aja_log("Driving direction restriction applies", 3); return false; } //Is turn allowed by other means (e.g. turn restrictions)? if(!s_from.isTurnAllowed(s_to, via_node)) { aja_log("Other restriction applies", 3); return false; } if(s_to.attributes.fromNodeID === via_node.attributes.id) { aja_log("FWD direction",3); return aja_is_car_allowed_by_restrictions(s_to.attributes.fwdRestrictions); } else { aja_log("REV direction",3); return aja_is_car_allowed_by_restrictions(s_to.attributes.revRestrictions); } } function aja_is_car_allowed_by_restrictions(restrictions) { aja_log("Checking restrictions for cars", 2); if(typeof restrictions === 'undefined' || restrictions == null || restrictions.length === 0) { aja_log("No car type restrictions to check...", 3); return true; } aja_log(restrictions, 3); return !restrictions.some(function(element) { /*jshint bitwise: false*/ aja_log("Checking restriction " + element, 3); //noinspection JSBitwiseOperatorUsage var ret = element.allDay && //All day restriction element.days === 127 && //Every week day ( element.vehicleTypes === -1 || //All vehicle types element.vehicleTypes & aja_vehicle_types.PRIVATE //or at least private cars ); if (ret) { aja_log("There is an all-day-all-week restriction", 3); var fromDate = Date.parse(element.fromDate); var toDate = Date.parse(element.toDate); aja_log("From: " + fromDate + ", to: " + toDate + ". " + ret, 3); if(isNaN(fromDate && isNaN(toDate))) { aja_log("No start nor end date defined"); return false; } var fRes, tRes; if(!isNaN(fromDate) && new Date() > fromDate) { aja_log("From date is in the past", 3); fRes = 2; } else if(isNaN(fromDate)) { aja_log("From date is invalid/not set", 3); fRes = 1; } else { aja_log("From date is in the future: " + fromDate, 3); fRes = 0; } if(!isNaN(toDate) && new Date() < toDate) { aja_log("To date is in the future", 3); tRes = 2; } else if(isNaN(toDate)) { aja_log("To date is invalid/not set", 3); tRes = 1; } else { aja_log("To date is in the past: " + toDate, 3); tRes = 0; } // Car allowed unless // - toDate is in the future and fromDate is unset or in the past // - fromDate is in the past and toDate is unset in the future // Hope I got this right ;) return (fRes <= 1 && tRes <= 1); } return ret; }); } async function loadSettings() { const localSettings = $.parseJSON(localStorage.getItem('AJA_Settings')); console.log('AJA Settings loaded'); // Attempt connection to WazeWrap setting server to retrieve settings const serverSettings = await WazeWrap.Remote.RetrieveSettings('AJA_Settings'); if (!serverSettings) console.log('AJA: Error communicating with WW settings server'); // Default checkbox settings const defaultsettings = { lastSaveAction: 0, scriptenabled: true, check: false, skiproundabout: false }; AJASettings = $.extend({}, defaultsettings, localSettings); if (serverSettings && serverSettings.lastSaveAction > AJASettings.lastSaveAction) { $.extend(AJASettings, serverSettings); // console.log('AJA: server settings used'); } else { // console.log('AJA: local settings used'); } // If there is no value set in any of the stored settings then use the default Object.keys(defaultsettings).forEach((funcProp) => { if (!AJASettings.hasOwnProperty(funcProp)) { AJASettings[funcProp] = defaultsettings[funcProp]; } }); } async function saveSettings() { const { lastSaveAction, scriptenabled, check, skiproundabout } = AJASettings; const localSettings = { lastSaveAction: Date.now(), scriptenabled, check, skiproundabout }; // Required for the instant update of changes to the keyboard shortcuts on the UI AJASettings = localSettings; if (localStorage) { localStorage.setItem('AJA_Settings', JSON.stringify(localSettings)); } const serverSave = await WazeWrap.Remote.SaveSettings('AJA_Settings', localSettings); if (serverSave === null) { console.warn('AJA: User PIN not set in WazeWrap tab'); } else { if (serverSave === false) { console.error('AJA: Unable to save settings to server'); } } if (serverSave === true) { console.log('AJA: Settings saved'); } } // Set user options function setEleStatus() { setChecked('aja-scriptenabled', AJASettings.scriptenabled); setChecked('aja-skiproundabout', AJASettings.skiproundabout); if ( country == 'Austria' ) { $(`#${'aja-check'}`).prop('disabled', true); } else { setChecked('aja-check', AJASettings.check); } } function setChecked(ele, status) { $(`#${ele}`).prop('checked', status); } /* * Bootstrapping and logging */ function aja_bootstrap(retries) { retries = retries || 0; //If Waze has not been defined in ~15 seconds, it probably won't work anyway. Might need tuning //for really slow devices? if (retries >= 30) { aja_log("Failed to bootstrap 30 times. Giving up.", 0); return; } try { //User logged in and WME ready if ( // !(document.querySelector('.list-unstyled.togglers .group') === null) && aja_is_model_ready() && aja_is_dom_ready() && checkCountry() && window.W.loginManager.isLoggedIn()) { setTimeout(function () { junctionangle_init(); }, 500); } //Some part of the WME was not yet fully loaded. Retry. else { setTimeout(function () { aja_bootstrap(++retries); }, 500); } } catch (err) { aja_log(err, 1); setTimeout(function () { aja_bootstrap(++retries); }, 500); } } function aja_is_model_ready() { if(typeof window.W === 'undefined' || typeof window.W.map === 'undefined') { return false; } else { //return 'undefined' !== typeof window.W.map.events.register && return 'undefined' !== typeof window.W.map.olMap.events.register && 'undefined' !== typeof window.W.selectionManager.events.register && 'undefined' !== typeof window.W.loginManager.events.register; } } function aja_is_dom_ready() { if(null === document.getElementById('user-info')) { return false; } else { return document.getElementById('user-info').getElementsByClassName('nav-tabs').length > 0 && document.getElementById('user-info').getElementsByClassName('tab-content').length > 0; } } /** * Debug logging. * @param aja_log_msg * @param aja_log_level */ function aja_log(aja_log_msg, aja_log_level) { if(typeof aja_log_level === 'undefined') { aja_log_level = 1; } if (aja_log_level <= junctionangle_debug) { if (typeof aja_log_msg === "object") { console.log(aja_log_msg); } else { console.log("WME Bad JAI: " + aja_log_msg); } } } function getByID(obj, id){ if (typeof(obj.getObjectById) == "function"){ return obj.getObjectById(id); }else if (typeof(obj.getObjectById) == "undefined"){ return obj.get(id); } } function checkCountry() { try { country = W.model.getTopCountry().attributes.name; } catch (err) { country = null; // console.log(err); } return country; } aja_bootstrap(); } let run_aja_script = GM_addElement('script', { textContent: "" + run_aja.toString() + " \n" + "run_aja();" });