Discussion for the unofficial, community-developed addons, extensions and scripts built for the Waze Map Editor.

The official index of these tools is the Community Plugins, Extensions and Tools wiki page.
Post by CBenson
Olestas wrote:So maybe the script should not FORCE u-turns on us? As I said, they are not there by default when creating a segment.
This makes sense to me. I don't think the routing has been fixed yet.
ohad-ron wrote:U-Turns - No routing changes were made specifically related to the editor change. What we've done with this editor release is just disable the option to not have a U-turn at the end of a dead-end.
[restricted link]

Maybe we should let them enable the turns when they fix the routing.
CBenson
EmeritusChamps
EmeritusChamps
Posts: 10330
Has thanked: 608 times
Been thanked: 1642 times
Send a message
Regional Coordinator: Mid-Atlantic, US
Verizon, Nexus 6, Android 6.0.1, Waze 4.7.0.902

Post by CBenson
BellHouse wrote:This error message is from WME Toolbox, into which some of the JNF code was incorporated.
I'll note I get the error and haven't downloaded the Toolbox.
CBenson
EmeritusChamps
EmeritusChamps
Posts: 10330
Has thanked: 608 times
Been thanked: 1642 times
Send a message
Regional Coordinator: Mid-Atlantic, US
Verizon, Nexus 6, Android 6.0.1, Waze 4.7.0.902

Post by Contrerasf5
You coud put it on GreasyFork or Github too, userscripts is apparentrly diying :(
Contrerasf5
Area Manager
Area Manager
Posts: 49
Has thanked: 6 times
Been thanked: 11 times
Send a message

Post by Contrerasf5
james890526 wrote:
bgodette wrote:Version 0.0.9.0
This is now a Chrome Webstore Extension
Chrome Webstore

Checks WME's API to make sure used objects and functions exist and are the correct type. This works as long as function argument order doesn't change. Next step is to regex match on function contents to confirm arg order.

Makes cameras visible at zoom 0.
Updates keyboard pan amount by 1/4th the map view height.
Saves and persists turn arrow visibility and clickability between reloads/permalinks.
Saves and persists Full-screen mode.

Hooks into replaces 'q' (Disable All Turns) and does these actions on the selected node:
  • Enables U-Turn and locks all turns at dead-end nodes. Changed Behavior
  • Fixes any self and reverse connectivity issues
  • Converts single node roundabouts (lollipops) and loops into a three segment loop. Any existing house numbers will be associated with the middle segment and MUST BE EDITED after save to update their stop point.
  • If two or more segments are connected to the same two segments, it will split one of them. Same rules as SameNode.js bookmarklet.
  • Terminates dead-ends
  • Makes dead-ends two-way (only if both ends of the segment are visible)
  • Sets the Type of a roundabouts using lowest of two highest rule and sets country/state if needed
  • For UK sets Type of roundabouts using highest type excluding Freeway rule.
  • Removes revcon (turns into wrong-direction of one-way), and selfcon (U-Turns at non-dead ends). Once the app has real support for U-Turns selfconf will be left alone
  • Locks all turns at selected node.
bgodette, will you be providing a Firefox script extension anytime soon?
Yes please, I'm using Tampermonkey for Opera because this JNF is not compatible, it would be great if you could port it to Greasy Fork
Contrerasf5
Area Manager
Area Manager
Posts: 49
Has thanked: 6 times
Been thanked: 11 times
Send a message

Post by Contrerasf5
doctorkb wrote:Here's a version of 0.0.9.3 that seems to work on FF in GreaseMonkey for me.

I did some basic testing -- there's no error thrown to the user, it fixes RevConns and u-turns.

N.b. this is only modified from the original to have the bootstrapping code that works with FF. It will cause problems with the editing standards in Canada and the UK (i.e. it enables dead-end u-turns).

Can someone do some further testing and report back if there are any issues?

Code: Select all

// ==UserScript==
// @name                WME Junction Node Fixer
// @description         Creates a new editor hotkey to lock turns, fix reverse connectivity, and restore original restricted turns.
// @include             https://*.waze.com/editor/*
// @include             https://*.waze.com/*/editor/*
// @version             0.0.9.3
// @grant             none
// ==/UserScript==

if ('undefined' == typeof __RTLM_PAGE_SCOPE_RUN__) {
  (function page_scope_runner() {
    // If we're _not_ already running in the page, grab the full source
    // of this script.
    var my_src = "(" + page_scope_runner.caller.toString() + ")();";

    // Create a script node holding this script, plus a marker that lets us
    // know we are running in the page scope (not the Greasemonkey sandbox).
    // Note that we are intentionally *not* scope-wrapping here.
    var script = document.createElement('script');
    script.setAttribute("type", "text/javascript");
    script.textContent = "var __RTLM_PAGE_SCOPE_RUN__ = true;\n" + my_src;

    // Insert the script node into the page, so it will run, and immediately
    // remove it to clean up.  Use setTimeout to force execution "outside" of
    // the user script scope completely.
    setTimeout(function() {
      document.body.appendChild(script);
      document.body.removeChild(script);
    }, 1000);
  })();

  // Stop running, because we know Greasemonkey actually runs us in
  // an anonymous wrapper.
  return;
}

WME_JNF_Version = "v0.0.9.3";

function WME_JNF_Bootstrap()
{
  var bGreasemonkeyServiceDefined = false;

  try {
    bGreasemonkeyServiceDefined = (typeof Components.interfaces.gmIGreasemonkeyService === "object");
  }
  catch (err) { /* Ignore */ }

  if (typeof unsafeWindow === "undefined" || ! bGreasemonkeyServiceDefined) {
    unsafeWindow    = ( function () {
      var dummyElem = document.createElement('p');
      dummyElem.setAttribute('onclick', 'return window;');
      return dummyElem.onclick();
    }) ();
  }

  /* begin running the code! */
  setTimeout(WME_JNF_Init, 500);
}

var matched = false;
var WME_Version = undefined;

// Feature detect + local reference
var storage, fail, uid;
var options = {};

var WCENC = null;
var WCSAVE = null;
var WCCHAT = null;
var WCLU = null;
var WCUR = null;
var WCMP = null;

var UpdateObject, SplitSegments, UpdateSegmentAddress, DisconnectSegment, AddSegment, UpdateSegmentGeometry, ConnectSegment, AddNode, ModifyAllConnections, ModifyConnection, FeatureVectorSegment;

function WME_JNF_PatchAndReload() {
  var patch;
}

function WME_JNF_SaveEnd(b) {
  console.log("WME-JNF: Save %s", b.success ? "succeeded" : "failed");
  if (b.success) {
    WCSAVE.controller.reload();
  }
}


function WME_JNF_smn(s1, s2)
{
  var pmap = [0, 10, 11, 15, 14, 1, 13, 12, 8, 0, 3, 0, 0, 0, 0, 0, 2, 7, 5, 4, 6, 9];
  var mod = null;
  if (s1.isGeometryEditable() && !s2.isGeometryEditable()) {
    console.log("only s1 can be modified");
    mod = s1;
  } else if (!s1.isGeometryEditable() && s2.isGeometryEditable()) {
    console.log("only s2 can be modified");
    mod = s2;
  } else if (s1.isGeometryEditable() && s2.isGeometryEditable()) {
    /* pick one */
    if (pmap[s1.attributes.roadType] < pmap[s2.attributes.roadType]) {
      console.log("s1 lower type");
      mod = s1;
    } else if (pmap[s1.attributes.roadType] > pmap[s2.attributes.roadType]) {
      console.log("s2 lower type");
      mod = s2;
    } else {
      if (s1.attributes.length > s2.attributes.length) {
        console.log("s1 longer");
        mod = s1;
      } else if (s1.attributes.length < s2.attributes.length) {
        console.log("s2 longer");
        mod = s2;
      } else {
        if (s1.attributes.createdOn > s2.attributes.createdOn) {
          console.log("s1 newer");
          mod = s1;
        } else if (s1.attributes.createdOn < s2.attributes.createdOn) {
          console.log("s2 newer");
          mod = s2;
        } else {
          if (s1.getID() > s2.getID()) {
            console.log("s1 higher id");
            mod = s1;
          } else {
            console.log("s2 higher id");
            mod = s2;
          }
        }
      }
    }
  } else {
    console.log("cannot modify either.");
  }
  if (mod) {
    var point;
    if (mod.geometry.components.length > 2) {
      console.log("Splitting: " + mod.getID() + " on geo point " + (Math.ceil(mod.geometry.components.length / 2) - 1) + " of " + mod.geometry.components.length);
      point = mod.geometry.components[Math.ceil(mod.geometry.components.length / 2) - 1];
    } else {
      point = mod.getCenter();
      console.log("Splitting:", mod.getID(), "at center.");
    }
    W.model.actionManager.add(new SplitSegments(mod, {splitAtPoint: point}));
  }
}

function WME_JNF_CleanRBT(jct) {
  var roadTypes = { "street": 1,      "primary": 2,   "freeway": 3,   "ramp": 4,
                    "trail": 5,       "major": 6,     "minor": 7,     "dirt": 8,
                    "boardwalk": 10,  "stairway": 16, "private": 17,  "railroad": 18,
                    "runway": 19,     "parking": 20,  "service": 21};
  var typenames = { 1: "street",      2: "primary",   3: "freeway",   4: "ramp",
                    5: "trail",       6: "major",     7: "minor",     8: "dirt",
                    10: "boardwalk",  16: "stairway", 17: "private",  18: "railroad",
                    19: "runway",     20: "parking",  21: "service"};
  var prec = [4, 6, 7, 2, 1, 21, 17, 20, 8];
  if (jct.valid == true) {
    var types = {};
    var roadtype = false;
    var cities = {};
    var i = 0;
    var cityid = 0;
    var street = null;
    var city = null;
    var state = null;
    var country = null;
    var update = true;
    var street_updated = false;
    var type_updated = false;
    var nodes = {};
    
    jct.segIDs.forEach(function(segid) {
      var seg = W.model.segments.get(segid);
      for (var i = 0; i < seg.geometry.components.length; i++)
        if (!onScreen(seg))
          update = false;
    });

    if (update == false)
      return;
    
    jct.segIDs.forEach(function(segid) {
      var seg = W.model.segments.get(segid);
      if (seg.attributes.primaryStreetID) {
        street = W.model.streets.get(seg.attributes.primaryStreetID);
        city = W.model.cities.get(street.cityID);
        if (city) {
          if (!cities[street.cityID])
            cities[street.cityID] = 0;
          if (!city.isEmpty)
            cities[street.cityID] += 100;
        }
      }
      nodes[seg.attributes.toNodeID] = W.model.nodes.get(seg.attributes.toNodeID);
      nodes[seg.attributes.fromNodeID] = W.model.nodes.get(seg.attributes.fromNodeID);
    });
    Object.forEach(nodes, function(k, node) {
      node.attributes.segIDs.forEach(function(csegid) {
        var cseg = W.model.segments.get(csegid);
        if (!cseg.attributes.junctionID) {
          if (cseg.attributes.roadType != roadTypes["freeway"]) {
            if (!types[cseg.attributes.roadType])
              types[cseg.attributes.roadType] = 0;
            if (cseg.attributes.fwdDirection)
              types[cseg.attributes.roadType] += 1;
            if (cseg.attributes.revDirection)
              types[cseg.attributes.roadType] += 1;
            if (cseg.attributes.primaryStreetID) {
              street = W.model.streets.get(cseg.attributes.primaryStreetID);
              city = W.model.cities.get(street.cityID);
              if (city) {
                if (!cities[street.cityID])
                  cities[street.cityID] = 0;
                if (city.isEmpty) {
                  cities[street.cityID] += 1; 
                } else {
                  cities[street.cityID] += 2;
                }
              }
            }
          } 
        }
      });
    });
    i = 0;
    Object.forEach(cities, function(k, v) {
      if (i < v) {
        i = v;
        cityid = k;
      }
    });
    street = W.model.streets.getByAttributes({isEmpty: true, cityID: cityid}).first();
    city = W.model.cities.get(cityid);
    if (city)
      country = W.model.countries.get(city.countryID);
    state = null;
    if (city && city.stateID)
      state = W.model.states.get(city.stateID);
    var j;
    for (i = 0; i < prec.length && !roadtype; i++) {
      if (city.countryID == 234 && prec[i] == 4)
        continue;
      if (prec[i] in types) {
        if (types[prec[i]] > 3 || (types[prec[i]] && city.countryID == 234)) {
          roadtype = prec[i];
        } else {
          for (j = i+1; j < prec.length && !roadtype; j++) {
            if (types[prec[j]] > 1) {
              roadtype = prec[j];
            }
          }
        }
        if (!roadtype)
          roadtype = prec[i];
      }
    }
    jct.segIDs.forEach(function(segid) {
      var seg = W.model.segments.get(segid);
      if (seg.attributes.roadType != roadtype) {
        W.model.actionManager.add(new UpdateObject(seg, {roadType: roadtype}));
        if (!type_updated) {
          console.log("JNF_RBT: road type: " + roadtype + " " + typenames[roadtype]);
          type_updated = true;
        }
      }
      if (!seg.attributes.primaryStreetID || (street && seg.attributes.primaryStreetID != street.id)) {
        W.model.actionManager.add(new UpdateSegmentAddress(seg, {countryID: city.countryID, stateID: city.stateID, cityName: city.name, emptyStreet: true}));
        if (!street_updated) {
          if (state.name != "Other")
            console.log("JNF_RBT: " + city.name + ", " + state.name + ", " + country.name);
          else
            console.log("JNF_RBT: " + city.name + ", " + country.name);
          street = W.model.streets.getByAttributes({isEmpty: true, cityID: cityid}).first();
          console.log("JNF_RBT: street: %o ", street);
          street_updated = true;
        }
      }
    });
    Object.forEach(nodes, function(k, node) {
      WME_JNF_FixNode(node, false);
    });
  }
}

function WME_JNF_DAT(a) {
  if (!a.enabled)
    return;
  WME_JNF_FixNode(a.selectedFeature, true);
}

function onScreen(obj) {
  if (obj.geometry) {
    return(W.map.getExtent().intersectsBounds(obj.geometry.getBounds()));
  }
  return(false);
}

WME_JNF_FixNode = function(node, doJunctions) {
  if (!node)
    return;
  if (!node.type)
    return;
  if (node.type != "node")
    return;
  if (node.areConnectionsEditable() && onScreen(node)) {
    connections = {};
    junctions = {};
    
    for (var i = 0; i < node.attributes.segIDs.length; i++) {
      var seg = W.model.segments.get(node.attributes.segIDs[i]);
      if (seg) {
        if (seg.attributes.toNodeID == seg.attributes.fromNodeID) {
          if (seg.attributes.junctionID) {
            console.log("single node rb");
          } else {
            console.log("single node loop");
          }
          var seg1geo = seg.geometry.clone();
          var seg2geo = seg.geometry.clone();
          var seg3geo = seg.geometry.clone();
          var mod3 = seg.geometry.components.length % 3;
          for (var i = 0; i < seg.geometry.components.length / 3 - 1; i++) {
            seg1geo.components.pop();
            seg1geo.components.pop();
            seg2geo.components.pop();
            seg2geo.components.shift();
            seg3geo.components.shift();
            seg3geo.components.shift();
          }
          if (mod3 == 2) {
            seg1geo.components.pop();
            seg3geo.components.shift();
          }
          if (mod3 == 0) {
            seg1geo.components.pop();
            seg1geo.components.pop();
            seg3geo.components.shift();
            seg3geo.components.shift();
          }
					seg1geo.calculateBounds();
					seg2geo.calculateBounds();
					seg3geo.calculateBounds();
          var newseg1, newseg3, ns1ls, ns3ls;
          if (node.attributes.connections) {
            newseg1 = new FeatureVectorSegment(seg1geo);
            newseg3 = new FeatureVectorSegment(seg3geo);
          } else {
            newseg1 = new FeatureVectorSegment({geometry: seg1geo});
            newseg3 = new FeatureVectorSegment({geometry: seg3geo});
          }
          newseg1.copyAttributes(seg);
          newseg3.copyAttributes(seg);
          newseg1.attributes.junctionID = null;
          newseg3.attributes.junctionID = null;
          newseg1.attributes.fromNodeID = null;
          newseg3.attributes.fromNodeID = null;
          newseg1.attributes.toNodeID = null;
          newseg3.attributes.toNodeID = null;
          if (!node.attributes.connections) {
            //newseg1.geometry = seg1geo;
            //newseg3.geometry = seg3geo;
						if (seg.setID) {
							newseg1.setID(null);
							newseg3.setID(null);
						} else {
							newseg1.geometry = seg1geo;
							newseg3.geometry = seg3geo;
						}
          }
          var joinsegs = [];
          joinsegs.push(newseg1);
          joinsegs.push(seg);
          W.model.actionManager.add(new DisconnectSegment(seg, node));
          W.model.actionManager.add(new DisconnectSegment(seg, node));
          W.model.actionManager.add(new UpdateSegmentGeometry(seg, seg.geometry, seg2geo));

          W.model.actionManager.add(new AddSegment(newseg1));
          W.model.actionManager.add(new AddSegment(newseg3));

          W.model.actionManager.add(new ConnectSegment(node, newseg1));
          W.model.actionManager.add(new ConnectSegment(node, newseg3));

          W.model.actionManager.add(new AddNode(seg1geo.components.last(), joinsegs));
          joinsegs = []
          joinsegs.push(seg);
          joinsegs.push(newseg3);
          W.model.actionManager.add(new AddNode(seg3geo.components.first(), joinsegs));
          W.model.actionManager.add(new UpdateObject(newseg1, {fwdTurnsLocked: true, revTurnsLocked: true}));
          W.model.actionManager.add(new UpdateObject(seg, {fwdTurnsLocked: true, revTurnsLocked: true}));
          W.model.actionManager.add(new UpdateObject(newseg3, {fwdTurnsLocked: true, revTurnsLocked: true}));
          W.model.actionManager.add(new ModifyAllConnections(newseg1.getToNode(), true));
          W.model.actionManager.add(new ModifyAllConnections(newseg1.getFromNode(), true));
          W.model.actionManager.add(new ModifyAllConnections(seg.getToNode(), true));
          W.model.actionManager.add(new ModifyAllConnections(seg.getFromNode(), true));
          W.model.actionManager.add(new ModifyAllConnections(newseg3.getToNode(), true));
          W.model.actionManager.add(new ModifyAllConnections(newseg3.getFromNode(), true));
        }
        if (!seg.isDeleted()) {
          // store any roundabouts we see
          if (seg.attributes.junctionID) {
            junctions[seg.attributes.junctionID] = W.model.junctions.get(seg.attributes.junctionID);
          }

          // terminate unterminated dead-ends
          var segments = [];
          segments.push(seg);
          if (seg.attributes.toNodeID == null) {
            W.model.actionManager.add(new AddNode(seg.geometry.components.last(), segments));
          }
          if (seg.attributes.fromNodeID == null) {
            W.model.actionManager.add(new AddNode(seg.geometry.components.first(), segments));
          }

          var toNode = seg.getToNode();
          var fromNode = seg.getFromNode();
          if (toNode && fromNode && !toNode.isDeleted() && !fromNode.isDeleted()) {
            if (onScreen(toNode) && onScreen(fromNode)) {
              if ((seg.attributes.fwdDirection == false || seg.attributes.revDirection == false) && (toNode.attributes.segIDs.length < 2 || fromNode.attributes.segIDs.length < 2))
              {
                console.log("JNF: updating dead-end segment " + seg.getID() + " to two-way");
                W.model.actionManager.add(new UpdateObject(seg, {fwdDirection: true, revDirection: true}));
              }
              if (toNode.attributes.connections) {
                // old editor
                if (toNode.attributes.segIDs.length < 2 && !toNode.isTurnAllowed(seg, seg)) {
                  console.log("Enabling dead-end u-turn at", toNode.getID(), "on", seg.getID());
                  W.model.actionManager.add(new ModifyConnection(seg.getID(), toNode, seg.getID(), true));
                  if (!seg.attributes.fwdTurnsLocked) {
                     W.model.actionManager.add(new UpdateObject(seg, {fwdTurnsLocked: true}));
                  }
                }
                if (fromNode.attributes.segIDs.length < 2 && !fromNode.isTurnAllowed(seg, seg)) {
                  console.log("Enabling dead-end u-turn at", toNode.getID(), "on", seg.getID());
                  W.model.actionManager.add(new ModifyConnection(seg.getID(), fromNode, seg.getID(), true));
                  if (!seg.attributes.revTurnsLocked) {
                     W.model.actionManager.add(new UpdateObject(seg, {revTurnsLocked: true}));
                  }
                }
              } else {
                // beta editor
                if (toNode.attributes.segIDs.length < 2 && !seg.isTurnAllowed(seg, toNode)) {
                  console.log("Enabling dead-end u-turn at", toNode.getID(), "on", seg.getID());
                  W.model.actionManager.add(new ModifyConnection(seg.getID(), toNode, seg.getID(), true));
                }
                if (fromNode.attributes.segIDs.length < 2 && !seg.isTurnAllowed(seg, fromNode)) {
                  console.log("Enabling dead-end u-turn at", toNode.getID(), "on", seg.getID());
                  W.model.actionManager.add(new ModifyConnection(seg.getID(), fromNode, seg.getID(), true));
                }
              }
            }
            if (node.attributes.segIDs.length > 1) {
              // disable u-turns
              var turnAllowed;
              if (node.attributes.connections) {
                // old editor
                turnAllowed = node.isTurnAllowed(seg, seg);
              } else {
                // beta editor
                turnAllowed = seg.isTurnAllowed(seg, node);
              }
              if (turnAllowed) {
                console.log("Disabling U-Turn at", node.getID(), "on", seg.getID());
                W.model.actionManager.add(new ModifyConnection(seg.getID(), node, seg.getID(), false));
              }
            }
          }
        }
      }
    }
    
    if (node.attributes.segIDs.length > 1) {
      var seg1, seg2;
      for (var i = 0; i < node.attributes.segIDs.length - 1; i++) {
        seg1 = W.model.segments.get(node.attributes.segIDs[i]);
        for (var j = i + 1; j < node.attributes.segIDs.length; j++) {
          seg2 = W.model.segments.get(node.attributes.segIDs[j]);
          if (seg1.isDeleted() == false && seg2.isDeleted() == false) {
            var fwd_t;
            var rev_t;
            var fwd_a;
            var rev_a;
            if (node.attributes.connections) {
              fwd_t = node.isTurnAllowed(seg1, seg2);
              rev_t = node.isTurnAllowed(seg2, seg1);
            } else {
              fwd_t = seg1.isTurnAllowed(seg2, node);
              rev_t = seg2.isTurnAllowed(seg1, node);
            }
            fwd_a = node.isTurnAllowedBySegDirections(seg1, seg2);
            rev_a = node.isTurnAllowedBySegDirections(seg2, seg1);
            if (fwd_t && !fwd_a) {
              console.log("Disabling RevCon at", node.getID(), "into", seg2.getID());
              W.model.actionManager.add(new ModifyConnection(seg1.getID(), node, seg2.getID(), false));
            }
            if (rev_t && !rev_a) {
              console.log("Disabling RevCon at", node.getID(), "into", seg1.getID());
              W.model.actionManager.add(new ModifyConnection(seg2.getID(), node, seg1.getID(), false));
            }
            if ((seg1.attributes.fromNodeID == seg2.attributes.fromNodeID && seg1.attributes.toNodeID == seg2.attributes.toNodeID) ||
                (seg1.attributes.fromNodeID == seg2.attributes.toNodeID && seg1.attributes.toNodeID == seg2.attributes.fromNodeID)) {
              console.log("sid:", seg1.getID(), "and sid:", seg2.getID(), "connected to same nodes:", seg1.attributes.fromNodeID, seg1.attributes.toNodeID);
              WME_JNF_smn(seg1, seg2);
            }
          }
        }
        if (!seg1.isDeleted() && !seg1.areTurnsLocked(node)) {
          var attr = seg1.getTurnsLockAttribute(node);
          var dict = {}
          dict[attr] = true;
          console.log("Locking Turns at", node.getID(), "on", seg1.getID());
          W.model.actionManager.add(new UpdateObject(seg1, dict));
        }
      }
      if (!seg2.isDeleted() && !seg2.areTurnsLocked(node)) {
        var attr = seg2.getTurnsLockAttribute(node);
        var dict = {}
        dict[attr] = true;
        console.log("Locking Turns at", node.getID(), "on", seg2.getID());
        W.model.actionManager.add(new UpdateObject(seg2, dict));
      }
    }

    if (doJunctions) {
      // clean up roundabouts
      Object.forEach(junctions, function(i, j) {
        WME_JNF_CleanRBT(j);
      });
    }
    
    // refresh turn arrows
    WCENC.toggleShowAllArrows();
    WCENC.toggleShowAllArrows();
  }
}

function WME_JNF_CheckAPI() {
  if (typeof(Waze) != "object") {
    matched = "Waze";
    return false;
  }
  if (typeof(W.model) != "object") {
    matched = "W.model";
    return false;
  }
  if (typeof(W.map) != "object") {
    matched = "W.map";
    return false;
  }
  if (typeof(W.map.controls) != "object") {
    matched = "W.map.controls";
    return false;
  }
  if (typeof(W.map.controls[0]) != "object") {
    matched = "W.map.controls[0]";
    return false;
  }
  if (typeof(W.map.controls[0].displayClass) != "string") {
    matched = "W.map.controls[0].displayClass";
    return false;
  }
  Object.forEach(W.map.controls, function(k, v) {
    if (v.displayClass == "WazeControlEditNodeConnections") {
      WCENC = v;
    }
    if (v.displayClass == "WazeControlSave") {
      WCSAVE = v;
    }
    if (v.displayClass == "WazeControlChat") {
      WCCHAT = v;
    }
    if (v.displayClass == "WazeControlMapProblems") {
      WCMP = v;
    }
    if (v.displayClass == "WazeControlUpdateRequests") {
      WCUR = v;
    }
    if (v.displayClass == "WazeControlLiveUsers") {
      WCLU = v;
    }
  });
  if (typeof(WCENC) != "object") {
    matched = "WCENC";
    return false;
  }
  if (typeof(WCSAVE) != "object") {
    matched = "WCSAVE";
    return false;
  }
  if (typeof(WCCHAT) != "object") {
    matched = "WCCHAT";
    return false;
  }
  if (typeof(WCMP) != "object") {
    matched = "WCMP";
    return false;
  }
  if (typeof(WCUR) != "object") {
    matched = "WCUR";
    return false;
  }
  if (typeof(WCLU) != "object") {
    matched = "WCLU";
    return false;
  }
  if (typeof(Waze.Config) != "object") {
    matched = "Waze.Config";
    return false;
  }
  if (typeof(Waze.Config.cameras) != "object") {
    matched = "Waze.Config.cameras";
    return false;
  }
  if (typeof(Waze.Config.cameras.minDisplayZoom) != "number") {
    matched = "Waze.Config.cameras.minDisplayZoom";
    return false;
  }
  if (typeof(W.model.cameras) != "object") {
    matched = "W.model.cameras";
    return false;
  }
  if (typeof(W.model.cameras.minZoom) != "number") {
    matched = "W.model.cameras.minZoom";
    return false;
  }
  if (typeof(W.map.toggleFullscreen) != "function") {
    matched = "W.map.toggleFullscreen";
    return false;
  }
  if (typeof(WCENC.showAllArrows) != "boolean") {
    matched = "WCENC.showAllArrows";
    return false;
  }
  if (typeof(WCENC.showArrows) != "boolean") {
    matched = "WCENC.showArrows";
    return false;
  }
  if (typeof(WCENC.toggleShowAllArrows) != "function") {
    matched = "WCENC.toggleShowAllArrows";
    return false;
  }
  if (typeof(WCSAVE.controller) != "object") {
    matched = "WCSAVE.controller";
    return false;
  }
  if (typeof(WCSAVE.controller.events) != "object") {
    matched = "WCSAVE.controller.events";
    return false;
  }
  if (typeof(WCSAVE.controller.events.register) != "function") {
    matched = "WCSAVE.controller.events.register";
    return false;
  }
  if (typeof(W.map.DefaultPanInPixel) != "number") {
    matched = "W.map.DefaultPanInPixel";
    return false;
  }
  if (typeof(Waze.accelerators) != "object") {
    if (typeof(Waze.Accelerators) != "object") {
      matched = "Waze.accelerators";
      return false;
    } else {
      Waze.accelerators = Waze.Accelerators;
    }
  }
  if (typeof(Waze.accelerators.events) != "object") {
    matched = "Waze.accelerators.events";
    return false;
  }
  if (typeof(Waze.accelerators.events.listeners) != "object") {
    matched = "Waze.accelerators.events.listeners";
    return false;
  }
  if (typeof(Waze.accelerators.events.listeners.disallowAllConnections) != "object") {
    matched = "Waze.accelerators.events.listeners.disallowAllConnections";
    return false;
  }
  if (typeof(Waze.accelerators.events.listeners.disallowAllConnections[0]) != "object") {
    matched = "Waze.accelerators.events.listeners.disallowAllConnections[0]";
    return false;
  }
  if (typeof(Waze.accelerators.events.listeners.disallowAllConnections[0].func) != "function") {
    matched = "Waze.accelerators.events.listeners.disallowAllConnections[0].func";
    return false;
  }
  if (typeof(Waze.accelerators.events.listeners.allowAllConnections) != "object") {
    matched = "Waze.accelerators.events.listeners.allowAllConnections";
    return false;
  }
  if (typeof(Waze.accelerators.events.listeners.allowAllConnections[0]) != "object") {
    matched = "Waze.accelerators.events.listeners.allowAllConnections[0]";
    return false;
  }
  if (typeof(Waze.accelerators.events.listeners.allowAllConnections[0].func) != "function") {
    matched = "Waze.accelerators.events.listeners.allowAllConnections[0].func";
    return false;
  }
  if (typeof(W.map.getExtent) != "function") {
    matched = "W.map.getExtent";
    return false;
  }
  var tstvar = W.map.getExtent();
  if (typeof(tstvar) != "object") {
    matched = "W.map.getExtent()";
    return false;
  }
  if (typeof(tstvar.toGeometry) != "function") {
    matched = "W.map.getExtent().toGeometry";
    return false;
  }
  var tstvar = tstvar.toGeometry();
  if (typeof(tstvar) != "object") {
    matched = "W.map.getExtent().toGeometry() == object";
    return false;
  }
  if (typeof(tstvar.containsPoint) != "function") {
    matched = "W.map.getExtent().toGeometry().containsPoint";
    return false;
  }
  if (typeof(W.model.segments) != "object") {
    matched = "W.model.segments";
    return false;
  }
  if (typeof(W.model.segments.get) != "function") {
    matched = "W.model.segments.get";
    return false;
  }
  if (typeof(W.model.nodes) != "object") {
    matched = "W.model.nodes";
    return false;
  }
  if (typeof(W.model.nodes.get) != "function") {
    matched = "W.model.nodes.get";
    return false;
  }
  if (typeof(W.model.junctions) != "object") {
    matched = "W.model.junctions";
    return false;
  }
  if (typeof(W.model.junctions.get) != "function") {
    matched = "W.model.junctions.get";
    return false;
  }
  if (typeof(W.model.streets) != "object") {
    matched = "W.model.streets";
    return false;
  }
  if (typeof(W.model.streets.get) != "function") {
    matched = "W.model.streets.get";
    return false;
  }
  if (typeof(W.model.streets.getByAttributes) != "function") {
    matched = "W.model.streets.getByAttributes";
    return false;
  }
  if (typeof(W.model.cities) != "object") {
    matched = "W.model.cities";
    return false;
  }
  if (typeof(W.model.cities.get) != "function") {
    matched = "W.model.cities.get";
    return false;
  }
  if (typeof(W.model.countries) != "object") {
    matched = "W.model.countries";
    return false;
  }
  if (typeof(W.model.countries.get) != "function") {
    matched = "W.model.countries.get";
    return false;
  }
  if (typeof(W.model.actionManager) != "object") {
    matched = "W.model.actionManager";
    return false;
  }
  if (typeof(W.model.actionManager.add) != "function") {
    matched = "W.model.actionManager.add";
    return false;
  }
  if (typeof(UpdateObject) != "function") {
    matched = "UpdateObject";
    return false;
  }
  if (typeof(UpdateSegmentAddress) != "function") {
    matched = "UpdateSegmentAddress";
    return false;
  }
  if (typeof(DisconnectSegment) != "function") {
    matched = "DisconnectSegment";
    return false;
  }
  if (typeof(UpdateSegmentGeometry) != "function") {
    matched = "UpdateSegmentGeometry";
    return false;
  }
  if (typeof(AddSegment) != "function") {
    matched = "AddSegment";
    return false;
  }
  if (typeof(AddNode) != "function") {
    matched = "AddNode";
    return false;
  }
  if (typeof(ConnectSegment) != "function") {
    matched = "ConnectSegment";
    return false;
  }
  if (typeof(ModifyAllConnections) != "function") {
    matched = "ModifyAllConnections";
    return false;
  }
  if (typeof(FeatureVectorSegment) != "function") {
    matched = "FeatureVectorSegment";
    return false;
  }
  if (typeof(W.model.nodes.objects) != "object") {
    matched = "W.model.nodes.objects";
    return false;
  }
  tstvar = Object.keys(W.model.nodes.objects);
  if (typeof(tstvar) != "object") {
    matched = "W.model.nodes.objects keys";
    return false;
  }
  return true;
}

function WME_JNF_RestoreSettings() {
  // restore saved setting
  if (storage) {
    console.log("WME-JNF: loading options");
    options = JSON.parse(storage.getItem('WME_JNF'));
    if (options == null) {
      console.log("no options");
      return;
    }
    if (WCENC) {
      WCENC.showAllArrows = options['showallarrows'];
      WCENC.showArrows = options['showarrows'];
      WCENC.toggleShowAllArrows();
      WCENC.toggleShowAllArrows();
    } else {
      console.log("no WCENC");
    }
    if (WCSAVE) {
      WCSAVE.controller.events.register("saveend", this, WME_JNF_SaveEnd);
      WME_JNF_PatchAndReload();
    } else {
      console.log("no WCSAVE");
    }
    if (options['fullscreen']) {
      if (options['fullscreen'] == "fullscreen" && document.body.className != "fullscreen") {
        console.log("going fullscreen");
        W.map.toggleFullscreen();
      }
    }
  }
//  W.model.events.unregister("mergeend", this, WME_JNF_RestoreSettings);
}

function WME_JNF_OnUnload() {
    if (storage) {
      console.log("WME-JNF: saving options");
      options = {};

      //    options['hotkey'] = getId('_cbJNF_Hotkey');
      Object.forEach(W.map.controls, function(k, v) {
        if (v.displayClass == "WazeControlEditNodeConnections") {
          options['showallarrows'] = v.showAllArrows;
          options['showarrows'] = v.showArrows;
        }
      });
      options['fullscreen'] = document.body.className;
      storage.setItem('WME_JNF', JSON.stringify(options));
    }
}

function WME_JNF_Hook() {
  console.log("WME-JNF: Hook");
  // make cameras visible at zoom 0 and load at zoom 1
  Waze.Config.cameras.minDisplayZoom = 0;
  W.model.cameras.minZoom = 0;
  
  // update pan amount so keyboard panning is useful
  W.map.DefaultPanInPixel = W.map.size.h / 4;

  $(window).on("beforeunload", WME_JNF_OnUnload);

  // hook 'q'
  Waze.accelerators.events.listeners.disallowAllConnections[0].func = function() {
    WME_JNF_DAT(this);
  }

  // hook 'w'
  Waze.accelerators.events.listeners.allowAllConnections[0].func = function() {
    if (typeof(allowAllConnections) == 'function') {
      allowAllConnections();
    } else {
      this.setAllConnections(true);
    }
    
    // refresh turn arrows
    WCENC.toggleShowAllArrows();
    WCENC.toggleShowAllArrows();
  }
//  W.model.events.unregister("mergeend", this, WME_JNF_Hook);
}

var init_tries = 0;

function WME_JNF_Init() {
  console.log("WME-JNF: " + WME_JNF_Version + " starting");
  
  try {
    uid = new Date;
    (storage = window.localStorage).setItem(uid, uid);
    fail = storage.getItem(uid) != uid;
    storage.removeItem(uid);
    fail && (storage = false);
  } catch(e) {}
  
  console.log("WME-JNF: Checking API");
	if (typeof(require) !== "undefined") {
		UpdateObject = require("Waze/Action/UpdateObject");
		SplitSegments = require("Waze/Action/SplitSegments");
		UpdateSegmentAddress = require("Waze/Action/UpdateSegmentAddress");
		DisconnectSegment = require("Waze/Action/DisconnectSegment");
		AddSegment = require("Waze/Action/AddSegment");
		UpdateSegmentGeometry = require("Waze/Action/UpdateSegmentGeometry");
		ConnectSegment = require("Waze/Action/ConnectSegment");
		AddNode = require("Waze/Action/AddNode");
		ModifyAllConnections = require("Waze/Action/ModifyAllConnections");
		ModifyConnection = require("Waze/Action/ModifyConnection");
		FeatureVectorSegment = require("Waze/Feature/Vector/Segment");
	} else {
		UpdateObject = W.Action.UpdateObject;
		SplitSegments = W.Action.SplitSegments;
		UpdateSegmentAddress = W.Action.UpdateSegmentAddress;
		DisconnectSegment = W.Action.DisconnectSegment;
		AddSegment = W.Action.AddSegment;
		UpdateSegmentGeometry = W.Action.UpdateSegmentGeometry;
		ConnectSegment = W.Action.ConnectSegment;
		AddNode = W.Action.AddNode;
		ModifyAllConnections = W.Action.ModifyAllConnections;
		ModifyConnection = W.Action.ModifyConnection;
		FeatureVectorSegment = W.Feature.Vector.Segment;
	}
  if (WME_JNF_CheckAPI()) {
    WME_JNF_RestoreSettings();
    WME_JNF_Hook();
  } else {
    console.log("WME-JNF: failed API check, exiting. " + matched);
    alert("WME Junction Node Fixer has failed to load due to API check: " + matched);
    WME_JNF_FixNode = undefined;
    return;
  }
}

$(document).ready(WME_JNF_Bootstrap);
thanks!!!
it's working fine with Opera on TamerMonkey
Contrerasf5
Area Manager
Area Manager
Posts: 49
Has thanked: 6 times
Been thanked: 11 times
Send a message

Post by CrackedLCD
sketch wrote:TB is in progress. A few days probably. Needs to be tested but most of us are out for the holidays.
Whatever you do, whenever you do it, it's greatly appreciated. We can wait. :D

Happy holidays, sketch and here's hoping your 2015 is great!
CrackedLCD
Area Manager
Area Manager
Posts: 434
Has thanked: 98 times
Been thanked: 63 times
Send a message

Post by Crawdad_Junior
@bgodette: Thank you very much for this contribution to our efforts. Your efforts on behalf of all of us are appreciated.
Crawdad_Junior
Area Manager
Area Manager
Posts: 2
Send a message

Post by crazycaveman
This looks like a Shift+Z problem, not JNF. Hit Shift+Z to show all disabled turns in the view (if you're zoomed in enough) and hit it again to disable it and have turns work as normal.
crazycaveman
US Waze Champs
US Waze Champs
Posts: 857
Has thanked: 226 times
Been thanked: 441 times
Send a message

Post by CTGreybeard
I've got a node here that JNF says has seven reverse connections but doesn't want to fix it. I've cleared several in the area but this one won't go away.

I'm new to this script so it may be the loose nut at the keyboard ... :o
CTGreybeard
Posts: 445
Has thanked: 54 times
Been thanked: 52 times
Send a message

Post by CTGreybeard
I'm running 0.0.7.6 under Chrome 27.0.1453.110 and a strange thing has just started happening. When I highlight a segment the turns are all "grayed out" and can't be changed. I can click on a node and change All Allowed or All Disallowed but I can't change individual arrows or u-turns. If I disable the extension and reload the page then I can change the arrows individually.

The same version running under Firefox doesn't show the same problem.

I know it was fine earlier today under Chrome. Maybe I'm just going nuts. :?:
CTGreybeard
Posts: 445
Has thanked: 54 times
Been thanked: 52 times
Send a message