WME Check Road Name

This script make a Check for Roads naming (Only for french editors)

目前為 2014-08-03 提交的版本,檢視 最新版本

// ==UserScript==
// @name WME Check Road Name
// @description This script make a Check for Roads naming (Only for french editors)
// @namespace https://greasyfork.org/users/4062
// @match     https://world.waze.com/editor/*
// @match     https://*.waze.com/editor/*
// @match     https://*.waze.com/*/editor/*
// @match     https://world.waze.com/map-editor/*
// @match     https://world.waze.com/beta_editor/*
// @match     https://www.waze.com/map-editor/*
// @grant     GM_xmlhttpRequest
// @include   https://editor-beta.waze.com/*
// @include   https://*.waze.com/editor/editor/*
// @include   https://*.waze.com/*/editor/*
// @version   1.5.3
// ==/UserScript==

// Based on Street to River ( http://userscripts.org/scripts/show/122049 )
// Thanks to aeytom - Street to River ( http://userscripts.org/scripts/show/122049 )

// Adapted by buchet37  

if ('undefined' == typeof WME_CRN_onload) {        // le script n'est a pas encore chargé
  unsafeWindow.WME_CRN_onload = "In Progress";
  unsafeWindow.WME_CRN_1_wordGenericState = "In Progress";
  unsafeWindow.WME_CRN_1_roadGenericState = "In Progress";
  unsafeWindow.WME_CRN_1_IncorrectCitiesState = "In Progress";
  unsafeWindow.WME_CRN_1_citiesDoublonsState = "In Progress";
  GM_xmlhttpRequest({
    method:  'GET',
    url: 'https://www.dropbox.com/s/nfrrfe04vdl2kvw/CorrectMots.txt?dl=1',
     headers: {"User-Agent": "Mozilla/5.0",   // If not specified, navigator.userAgent will be used.
              "Accept": "text/plain"  },     // If not specified, browser defaults will be used.
    synchronous: false,
    onload: function (wordDetails) {
      unsafeWindow.WME_CRN_1_wordGenericTxt   = wordDetails.responseText;
      unsafeWindow.WME_CRN_1_wordGenericState = "Ready";
    }
  }); 

  GM_xmlhttpRequest({
    method:  'GET',
    url: 'https://www.dropbox.com/s/g1y7rrvthgxrx0p/CorrectRue.txt?dl=1',
     headers: {"User-Agent": "Mozilla/5.0",   // If not specified, navigator.userAgent will be used.
              "Accept": "text/plain"  },     // If not specified, browser defaults will be used.
    synchronous: false,
    onload: function (roadDetails) { 
      unsafeWindow.WME_CRN_1_roadGenericTxt   = roadDetails.responseText;
      unsafeWindow.WME_CRN_1_roadGenericState = "Ready";    
    }
  }); 
 
 GM_xmlhttpRequest({
    method:  'GET',
    url: 'https://www.dropbox.com/s/e1pojw81quth43u/citiesIncorrectes.txt?dl=1',
     headers: {"User-Agent": "Mozilla/5.0",   // If not specified, navigator.userAgent will be used.
              "Accept": "text/plain"  },     // If not specified, browser defaults will be used.
    synchronous: false,
    onload: function (responseIncorrectCities) { 
      unsafeWindow.WME_CRN_1_IncorrectCitiesTxt   = responseIncorrectCities.responseText;
      unsafeWindow.WME_CRN_1_IncorrectCitiesState = "Ready";  
    }
  }); 

 GM_xmlhttpRequest({
    method:  'GET',
    url: 'https://www.dropbox.com/s/dklv3al61o1sx86/citiesDoublons.txt?dl=1',
     headers: {"User-Agent": "Mozilla/5.0",  // If not specified, navigator.userAgent will be used.
              "Accept": "text/plain"},       // If not specified, browser defaults will be used. 
    synchronous: false,
    onload: function (responseDoublons) { 
      unsafeWindow.WME_CRN_1_citiesDoublonsTxt   = responseDoublons.responseText;
      unsafeWindow.WME_CRN_1_citiesDoublonsState = "Ready";
    }
  }); 
}

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);
        }, 0);
  })();

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

function CheckRoadName() {
  var WME_CRN_badStreet = [];
  var WME_CRN_goodStreet = [];  

  var WME_CRN_wordGeneric = [];           // déclaration Hors "loadFiles" pour compatibilité Chrome
  var WME_CRN_roadGeneric = [];   
  var WME_CRN_citiesDoublons = [];
  var WME_CRN_IncorrectCities = []
//alert (  WME_CRN_onload ); 
  loadFiles ();
  function loadFiles () {                  // Passage en variable locales
    if (WME_CRN_onload != "Ready" ) {
      var i = 0;                                  // compteur 
      if (WME_CRN_1_wordGenericState == "Ready")    { WME_CRN_wordGeneric     = traiteGeneric (WME_CRN_1_wordGenericTxt); i++; }
      if (WME_CRN_1_roadGenericState == "Ready")    { WME_CRN_roadGeneric     = traiteGeneric (WME_CRN_1_roadGenericTxt); i++; }
      if (WME_CRN_1_citiesDoublonsState == "Ready") { WME_CRN_citiesDoublons  = WME_CRN_1_citiesDoublonsTxt.split(/\n|\r|\r\n/); i++; }
      if (WME_CRN_1_IncorrectCitiesState == "Ready"){ WME_CRN_IncorrectCities = WME_CRN_1_IncorrectCitiesTxt.split(/\n|\r|\r\n/); i++; }
      
      if ( i == 4) {                     // tout est chargé
        WME_CRN_onload = "Ready" ;      // Flag = OK et purge variables globales
        delete WME_CRN_1_wordGenericState;delete WME_CRN_1_roadGenericState;delete WME_CRN_1_citiesDoublonsState;delete WME_CRN_1_IncorrectCitiesState;
        delete WME_CRN_1_wordGenericTxt;  delete WME_CRN_1_roadGenericTxt;  delete WME_CRN_1_citiesDoublonsTxt;  delete WME_CRN_1_IncorrectCitiesTxt;

        insertButton();                          // les fichiers sont chargés = > on met en place les boutons
      }
      else {
        setTimeout (function () {loadFiles();}, 1000);
      }
    }
  }  
  
  function traiteGeneric(texte) {
    var generic = texte.replace (/\t\t/g,"\t");                                // supprime les doubles tabulation
    var genericSplit = generic.split(/\n|\r|\r\n/);                            // split
    var inter1 = [];
    for(var i = 0; i < genericSplit.length; i++) {
      genericSplit[i] = genericSplit[i].replace (/^[ ]*\t/g,"\/\/");
      if (!(/^[ ]*\/\//.test(genericSplit[i])) && genericSplit[i] !="") {
        var inter2 = genericSplit[i].split(/\t/);
        inter2[0]=inter2[0].replace (/[ ]*$/g,"");
        inter2[1]="("+inter2[1].replace (/[ ]*$/g,"")+")";
        var inter3 = inter2[0].split("/");
      if (!inter3[2]) {inter3[2]="";}
        inter1.push({toVerify: inter3[1],flags: inter3[2],  corrected : inter2[1]});
      }
    } 
    return inter1;
  }
    
  String.prototype.capitalize = function() { return this.charAt(0).toUpperCase() + this.slice(1); };
  
  function insertButton() {

    if(document.getElementById('WME_CRN_All') == null) {
      var chk1 = $('<Label style="font-weight:normal"><input type="checkbox"; style="vertical-align: middle;margin: 0px;" id="WME_CRN_enable" title="Enable or Disable WME CRN">On-Off   </input></Label>');   
      var cnt1 = $ ('<section id="WME_CRN_link" style="padding-top:2px;;display: inline;"/>'); cnt1.append(chk1);cnt1.append(" ");  
//      cnt1.append('<div style="font-size:12px;display: inline;"> <u><i><a >Check Road Name V1.5.2</a></i></u>');
      
			cnt1.append('<div style="font-size:12px;display: inline;"> <u><i><a href="https://greasyfork.org/scripts/3776-wme-check-road-name" target="_blank">Check Road Name V1.5.3</a></i></u>');

      var btn2 = $('<button class="btn btn-default" style="padding:0px 10px; height:22px" id="WME_CRN_chk" title="Click this button to Check Road Names">Check Road Name</button>'); btn2.click(rename_Road);
      var chk2 = $('<Label style="font-weight:normal"><input type="checkbox"; style="vertical-align: middle;margin: 0px;" id="WME_CRN_CheckRoadName" title="Click for automatic check of road name (and landmark if layer On)"> Auto Check</input></Label>');
      var btn3 = $('<button class="btn btn-default" style="padding:0px 10px; height:22px" id="WME_CRN_raz" title="Click this button to Clear stored roads">RAZ</button>'); btn3.click(RAZ);
      var cnt2 = $ ('<section id="WME_CRN_rename" style="padding-top:2px"/>');
      cnt2.append(btn2); cnt2.append(" "); cnt2.append(chk2); cnt2.append(" "); cnt2.append(btn3);
//cnt2.append('<hr style="margin-bottom:5px ; margin-top:5px" width="100%">');    // ligne séparatrice pour les autres modules      
      
      var WME_CRN_Menu = $ ('<div id="WME_CRN_All" style="margin-top: 2px;padding-bottom:20px;padding-top:4px;padding-left:5px;width:290px; border-width:3px; border-style:double;border-color: rgb(147, 196, 211); border-radius:10px"/>');  
      WME_CRN_Menu.append(cnt1);
      WME_CRN_Menu.append(cnt2);

//Boite de dialogue City Change
      var myDialogBox = $ ('<div id="WME_CRN_ChangeCity" style="display :none; padding:10px; z-index: 1500;position: absolute;top :80px; left : 80px;background-color:#FFFFFF; border-width:3px; border-style:double;border-color: rgb(147, 196, 211); border-radius:10px"/>');  
      var txt0 =  $('<div id= "WME_CRN_ChangeCityTitle" style="text-align:center;padding:0px 0px"><b>Incorrect City Name Detected</b>');
      myDialogBox.append(txt0);
      var cnt11 = $('<section style="text-align: center; padding-top:2px; font-weight: bold" id="WME_CRN_OldCity"/>');
      var txt1 =  $('<div id= "WME_CRN_CityIDtoChange" style="display:inline;padding:0px 0px">City ID/');
      var txt2 =  $('<div id= "WME_CRN_nametoChange" style="display:inline;padding:0px 0px">City Name/>');
      cnt11.append("ID: ");cnt11.append(txt1);  cnt11.append("    ");cnt11.append(txt2);
      myDialogBox.append(cnt11);
      myDialogBox.append('<hr style="margin-bottom:5px ; margin-top:5px" width="100%">');
      myDialogBox.append('<label style="font-weight:normal">Correct it or select in the list</label> : <input class="form-control" style="padding:0px; margin-bottom: 10px;height:22px" type="text" value="My Default City Name" id="WME_CRN_newCityName" />');
      var dplist4 = $('<select class="form-control" style="display: block;  margin-bottom: 10px ;padding:0px; height:22px" id="WME_CRN_cityList"> <option value="0">Strict</option><option value="1">Large</option></select>');
      myDialogBox.append(dplist4);
      
      var cnt10 = $('<section style="padding-top:2px"/>');
      var btn8 =  $('<button class="btn btn-default" style="padding:0px 10px ;margin-right: 5px ; height:22px" title="Click this button to clear City Name on selected Roads">Cancel </button>');
      var btn9 =  $('<button class="btn btn-default" style="padding:0px 10px; height:22px" title="Click this button to clear City Name on selected Roads">Validate Change</button>');  
      btn8.click(cancel_Change_city_Name); btn9.click(valid_Change_city_Name);
      cnt10.append(btn8);  cnt10.append(btn9);
      myDialogBox.append(cnt10);
      
// Boite d'alerte
      var myAlertBox = $ ('<div id="WME_CRN_AlertBox" class="form-control search-query" style="opacity : 0.8;display :none;  height: auto;min-height: 30px; position: absolute;top :16px; margin-left: 350px; margin-right: auto; "/>');  
      var myAlertTxt = $('<div id= "WME_CRN_AlertTxt" style=" opacity : 1 ;display:inline;padding:0px 0px">City ID/');
      myAlertBox.append(myAlertTxt);
      
// ******* Mise en place des buttons      
      var WME_CRN_MenuFlag = false,myAlertBoxFlag = false,myDialogBoxFlag = false;
      function put_WME_CRN_Menu() {        // wait for 'sidebar'
        if (document.getElementById('sidebar')!=null) { $("#sidebar").append(WME_CRN_Menu);WME_CRN_MenuFlag = true;}
          else {setTimeout (function () {put_WME_CRN_Menu();}, 500);}
      }
      put_WME_CRN_Menu();
      
      function put_myAlertBox() {
        if (document.getElementById('map-search')!=null) { $("#map-search").append(myAlertBox);myAlertBoxFlag = true;}
          else {setTimeout (function () {put_myAlertBox();}, 500);}
      }
      put_myAlertBox();
      
      function put_myDialogBox() {
        if (document.getElementById('map')!=null) { $("#map").append(myDialogBox); myDialogBoxFlag = true;}
          else {setTimeout (function () {put_myDialogBox();}, 500);}
      }
      put_myDialogBox();
      
      function start_init_WME_CRN() {         // si tous les boutons sont chargés on démarre le script
        if (WME_CRN_MenuFlag && myAlertBoxFlag && myDialogBoxFlag) {init_WME_CRN();}
          else {setTimeout(start_init_WME_CRN(), 500);}
      }
      start_init_WME_CRN();
    }
    console_log("Check Road Name initialized");
  }

  function RAZ (ev) {
    WME_CRN_badStreet = [];
    WME_CRN_goodStreet = [];
    document.getElementById('WME_CRN_raz').disabled = true; // on desactive le bouton RAZ puisque les tableaux sont vides
    return;
  } 

  function cancel_Change_city_Name(ev) {
    WME_CRN_badStreet.push (document.getElementById ('WME_CRN_nametoChange').innerHTML);              // stocke l'annulation si on est en détction automatique
    document.getElementById('WME_CRN_raz').disabled = false;
    document.getElementById ('WME_CRN_ChangeCity').style.display = "none";
    manage_CheckRoadName();
  }

  function valid_Change_city_Name(ev) {
    if (findPending().length==0) {                                              // wait for loading
      var CityIDtoChange = document.getElementById ('WME_CRN_CityIDtoChange').innerHTML;
      var CityToChange = Waze.model.cities.objects[CityIDtoChange];
      var  oldCityName = document.getElementById ('WME_CRN_nametoChange').innerHTML;
      var CityID = document.getElementById ('WME_CRN_cityList').value; 
      var newCityName = document.getElementById ('WME_CRN_newCityName').value;
      if ((newCityName == oldCityName) && (CityID !="00")) {        //  Traitement par le menu déroulant    
        newCityName = Waze.model.cities.objects[CityID].name;
      }

      var newCityID = SearchCityID(CityToChange.countryID, CityToChange.stateID, newCityName);
      if (newCityID!= null && CityIDtoChange!="" && newCityName != oldCityName){
        for (var roadID in Waze.model.segments.objects) {
          var sel = Waze.model.segments.objects[roadID];
          if (sel!= null && sel.type == "segment" &&  sel.state != "Delete" && sel.attributes.primaryStreetID!= null  && sel.isAllowed(sel.PERMISSIONS.EDIT_GEOMETRY) ) {
            var street = Waze.model.streets.objects[sel.attributes.primaryStreetID];
            if (street && street.cityID == CityIDtoChange && limitForSaveNotReach() ) {      
              var newPrimaryID = SearchPrimaryID (street.id, newCityName, street.name);
              if (newPrimaryID!= null) {
                Waze.model.actionManager.add (new Waze.Action.UpdateSegmentDetails(sel, {primaryStreetID: newPrimaryID}));
              }
            }
            if (sel.attributes.streetIDs) {                              // traitement des alternate names
              var altName = sel.attributes.streetIDs;  
              var AltNameAdd =[];
              var modif = false ;
              for (var i = 0; i < altName.length ;i++) {
                var street = Waze.model.streets.objects[altName[i]];
                if (street && street.cityID == CityIDtoChange) {      
                  var newPrimaryID = SearchPrimaryID (street.id, newCityName, street.name); 
                  if (newPrimaryID!= null) {
                    modif =true
                    altName.splice (i,1);               // on retire l'ancien
                    i = 0;                              // et on positionne l'index pour un rebalayage du tableau
                    if (notInArray(newPrimaryID,altName) && notInArray(newPrimaryID,AltNameAdd)) {
                      AltNameAdd.push(newPrimaryID);    //et on ajoute l'autre s'il n'existe pas
                    }
                  }
                }
              }
              if (modif) {Waze.model.actionManager.add (new Waze.Action.UpdateSegmentDetails(sel, {streetIDs: altName.concat (AltNameAdd)}));}
            }
          }
        }
        
        for (var ldmkID in Waze.model.venues.objects) {
          var ldmk = Waze.model.venues.objects[ldmkID];
          if (ldmk!= null && ldmk.state != "Delete" && ldmk.attributes.streetID!= null && ldmk.isAllowed(ldmk.PERMISSIONS.EDIT_GEOMETRY)) {
            var street = ldmk.model.streets.get(ldmk.attributes.streetID);
            if (street && street.cityID == CityIDtoChange && limitForSaveNotReach() ) {      
              var newPrimaryID = SearchPrimaryID (street.id, newCityName, street.name);
              if (newPrimaryID!= null) {
                Waze.model.actionManager.add (new Waze.Action.UpdateObject(ldmk,{streetID: newPrimaryID}));
              }
            }
          }
        } 
      }
      document.getElementById ('WME_CRN_ChangeCity').style.display = "none";
      manage_CheckRoadName();
    }
    if (!limitForSaveNotReach()){myAlert ("<FONT color='red'><b>Please save and retry</b></FONT>");}
  }

  function rename_Road(ev) {
//console_log (Math.random());
    var name, oldName, newName;
    var modif = false;
    var listSegIDs = [];
    var cityIds= [];
    var listLmrkIDs = [];
    var road, ldmk, street, city ;
    var roadID,ldmkID,cityID,goodstreet;
//myAlert ("je vais y aller");
    
    if (findPending().length==0  && Waze.map.zoom > 1 && limitForSaveNotReach() && document.getElementById ('WME_CRN_ChangeCity').style.display != "block" )  {  // wait for loading 
      var date = new Date();
      var myWazeSegments = []; myWazeSegments = Waze.model.segments.objects;
      var myWazeStreets = [];  myWazeStreets = Waze.model.streets.objects;
      var myWazeCities = [];   myWazeCities = Waze.model.cities.objects;
      for (roadID in myWazeSegments) {
        road =  myWazeSegments[roadID];
        if (road!= null &&road.state != "Delete" &&  roadOnScreen(road) && road.attributes.primaryStreetID!= null && road.isAllowed(road.PERMISSIONS.EDIT_GEOMETRY)) { // la rue existe et "on a les droits" ;) 
          street = myWazeStreets[road.attributes.primaryStreetID];
          if (street && street.cityID != null) {
            city = myWazeCities[street.cityID];
            if (city && city.name!=null && city.countryID =="73") {
              if (city.name!="" ) {
                cityIds.push (street.cityID);                        // alimente la base de villes
              }
              if (notInArray(road.attributes.primaryStreetID,WME_CRN_badStreet) && notInArray(road.attributes.primaryStreetID,WME_CRN_goodStreet)) {              //  Le segment remplit toutes les conditions pour analyse ultérieure
                listSegIDs.push (roadID);                            // alimente la bsase des rues a tester
              }
            }              
          }
        } 
      }
      modif = checkRoadName (listSegIDs);                            // vérfication de noms en prodécure externe
      
      if (checkLayerState ("landmarks")) {
        var myWazeVenues = [];    myWazeVenues = Waze.model.venues.objects;
        for (ldmkID in myWazeVenues) {
          ldmk =  myWazeVenues[ldmkID];
          if (ldmk!= null && ldmk.state != "Delete" && ldmk.onScreen() && (ldmk.attributes.streetID!= null) && ldmk.isAllowed(ldmk.PERMISSIONS.EDIT_GEOMETRY)) {
            street = myWazeStreets[ldmk.attributes.streetID];  
            if (street && street.cityID != null) {
              city = myWazeCities[street.cityID];
              if (city && city.name!=null && city.countryID =="73" && city.name!="" ) {
                cityIds.push (street.cityID);                                        // alimente la base de villes
              }
              oldName = ldmk.attributes.name;  
              if (oldName && oldName!="" && notInArray(oldName,WME_CRN_badStreet) && notInArray(oldName,WME_CRN_goodStreet)) {              //  Le segment remplit toutes les conditions pour analyse ultérieure
                listLmrkIDs.push (ldmkID);                                          // alimente la bsase des rues a tester
              }
            }
          }
        }
        modif = checkLandmarkName (listLmrkIDs);
      }
      
      cityIds = delete_multi_Ids (cityIds);
      
      for (var i = 0, len_i = cityIds.length ; i<len_i ;i++) {
        cityID = cityIds[i];
        city = myWazeCities[cityID];
        if (document.getElementById ('WME_CRN_ChangeCity').style.display != "block" && notInArray(city.name, WME_CRN_badStreet) &&  testCityName (city.name) ) {                    // verification du nom de ville
          init_WME_CRN_ChangeCity(cityID,"red");
          document.getElementById ('WME_CRN_ChangeCity').style.display = "block";
        }
      }
      if (!limitForSaveNotReach()){myAlert ("<FONT color='red'><b>Please save and retry</b></FONT>");}
//myAlert ("Fin   : " + new Date());
    }

    manage_CheckRoadName();
  }
    
  function init_WME_CRN_ChangeCity(cityID,color) {
    document.getElementById ('WME_CRN_OldCity').style.color = color;
    document.getElementById ('WME_CRN_CityIDtoChange').innerHTML  = cityID;
    var cityName = "";
    if (cityID!="") { cityName = Waze.model.cities.objects[cityID].name;}
    document.getElementById ('WME_CRN_nametoChange').innerHTML = encodeHTML(cityName);
    document.getElementById ('WME_CRN_newCityName').value = cityName;  
    document.getElementById ('WME_CRN_cityList').innerHTML = feedCityList();
    document.getElementById ('WME_CRN_ChangeCity').style.display = "block";
    document.getElementById ('WME_CRN_ChangeCityTitle').innerHTML = "<b>Incorrect City Name Detected</b>";
  }
  
  function roadOnScreen (road) {
    if (road !=null && road.state != "Delete" ) {
      var node1 = Waze.model.nodes.objects[road.attributes.fromNodeID];
      var node2 = Waze.model.nodes.objects[road.attributes.toNodeID];
      return ((node1!= null && node1.onScreen()) || (node2!= null &&  node2.onScreen())); // une extrémité est sur l'ecran
    }
    else {
      return false;}
  }

  function testCityName (Name) {
    
    if (isInArray (Name,WME_CRN_IncorrectCities)) {return true; }      // test with confirmed incorrect city
    if (Name.length==1 && Name !="Y") {return true;}  // ville d'une seule lettre et diff de "Y" (Somme)
    if (/^[a-z]/.test(Name))          {return true;}  // commence par une minuscule
    if (/[A-Z][A-Z]/.test(Name))      {return true;}  // à 2 majuscules consécutives
    if (/(')[a-z]/.test(Name))        {return true;}  // minuscule après apostrophe
    if (/[.,#@"]/.test(Name))         {return true;}  // présence de point ou de virgule ou autres
    if (/([-][ ]|[ ][-])/.test(Name)) {return true;}  // Espace avant ou après tiret
    if (/[ ][ ]/.test(Name))          {return true;}  // double espace
    if (/[ -]$/.test(Name))           {return true;}  // espace ou tiret à la fin
    if (/[o][e]/.test(Name))          {return true;}  // e dans l'o

// Parenthèses
    if ((/[(]/.test(Name))!= (/[)]/.test(Name)))                {return true;}  // Parenthèse ouvrante sans parenthèse fermante (et vice versa)
    if ((/[(]/.test(Name))&& !(/[ ][(][ÉA-Z0-9]/.test(Name)))   {return true;}  // Parenthèse ouvrante sans espace avant ou sans majuscule ou chiffre après
    if ((/[)]/.test(Name))&& !(/[éa-z0-9)][)]/.test(Name)))     {return true;}  // Parenthèse fermante sans minuscule, chiffre ou ")" avant
    if ((/.*[ ].*[ ].*[ ].*/.test(Name))&& !(/[(]/.test(Name))) {return true;}  // 3 espaces ou plus dans le nom et pas de parentèses  // Voire réduire à 2 
    
// Chiffres  
    if (/.*[0-9].*[0-9].*[0-9].*/.test(Name))                    {return true;}  // 3 Chiffres ou plus dans le nom
    if ((/[0-9]/.test(Name))&& !(/[(][0-9][0-9][)]/.test(Name))) {return true;}  // S'il y a un chiffre, il est double et encadré par des parenthèses

    if (/(^Rue |^Avenue )/.test(Name)) {return true;}
    if ((/[ ](sur|sous|en|le|de|du|aux)[ ]/.test(Name)) && !(/[(]/.test(Name)))  {return true;}  // "sur" précédé et suivi d'un espace et ce n'est pas un lieudit
    if (/(Saint[e]*[ ])/.test(Name))   {return true;}  // Saint suivi d'un espace
  
    var doublons = WME_CRN_citiesDoublons;
    var lenDoublons = doublons.length;
    var testDoublons;
    for (var i = 0; i < lenDoublons ;i++) {
      testDoublons = (doublons[i] == Name); 
      if (testDoublons && !(/[(][0-9][0-9][)]/.test(Name))) {return true;}  // Ville en doublon sans département et parenthèses    
    }
    
    var nameToTest = Name.replace (/[ ]*[(][0-9][0-9][)]*/,"");      //supprime le numéro en fin de nom
    if (/[(]/.test(nameToTest)) { 
      nameToTest = nameToTest.replace (/^(.)*[(]/,"");              //supprime ce qu'il y a avant la parenthèses ouvrante (cas des lieux-dits)
    }
    if (/[(][0-9][0-9][)]/.test(Name)){                              // ville supposée en doublon car avec (XX)
      for (var j = 0; j <lenDoublons;j++) {
        if (nameToTest == doublons[j]) {return false;}              // Ville en doublon sans parenthèses    
      }
      return true;
    }
    return false;
  }

  function feedCityList() {
    var cityIds= [];
    for (var cityID in Waze.model.cities.objects) {
      cityIds.push(cityID);
    }
    return doCityList (cityIds);
  }

  function doCityList (CityIds) {
    CityIds = delete_multi_Ids (CityIds);
    var city = sortCityIDs (CityIds);
    var dplist=  '<select><option value="00">-----------------------------------------</option>';    //build street menu
    for (var i = 0; i <city.length;i++) {
      dplist = dplist +'<option value='+ city[i].ID +'>'+city[i].name+'</option>';
    }
    dplist = dplist + '</select>';
    return dplist;
  }

  function sortCityIDs (CityIds) {
    var city = [];
    var nameArray = [];
    var newName = [];
    for (var i = 0,len_i = CityIds.length; i <len_i;i++) {
      var CityId = CityIds[i];
      nameArray[i] = Waze.model.cities.objects[CityId].name;
      newName[i] = Waze.model.cities.objects[CityId].name;
    }
    newName.sort();
    for (var i = 0; i < newName.length;i++) {
      for (var j = 0; j < nameArray.length;j++) {
        if (newName[i] == nameArray[j]) {
          city[i]={name: nameArray[j], ID:CityIds[j]};
        }
      }
    }
    return city ;
  }

  function checkLandmarkName (listLmrkIDs) {
    var modif = false;
    var street,city,ldmark;
    var oldName, newName, cityName, ldmarkID    ;
    if (Waze.model.venues.objects.length ==0 ) { myAlert ("No landmark in memory");}
    for (var i = 0; i < listLmrkIDs.length; i++) {
      ldmark =  Waze.model.venues.objects[listLmrkIDs[i]];
      if (ldmark!=null && ldmark.onScreen()) {
         oldName = ldmark.attributes.name;
        if (oldName !=null && oldName !="" && !isInArray(oldName,WME_CRN_badStreet)) {
          newName = rename2 (oldName);
          newName = newName.replace (/ *: */g," - ");          // remplacement des ":"par "-" pour les landmark
          if (newName !=oldName && limitForSaveNotReach() ) {      
            Waze.selectionManager.select([ldmark]);
            street = Waze.model.streets.objects [ldmark.attributes.streetID];
            city = Waze.model.cities.objects [street.cityID];
            if (typeof(city) === 'undefined' || city == null) {cityName ="";}
              else {cityName= city.name;}
            newName = prompt (" Landmark to rename \n\nCity :"+cityName+"\nOld name is : "+oldName+"\n\nConfirm the new name or change it",newName);
            if (newName == null) {
              WME_CRN_badStreet.push (ldmark.attributes.name);
              document.getElementById('WME_CRN_raz').disabled = false;
            }
            else if (newName != oldName) {        
              Waze.model.actionManager.add (new Waze.Action.UpdateObject(ldmark,{name: newName}));
              modif = true;
            }
            Waze.selectionManager.select([]);
          }
        }
      }
    } 
    return modif;
  }

  function checkRoadName (listSegIDs) {    
    var modif = false;
    while (listSegIDs.length > 0) {
      var sel = Waze.model.segments.objects[listSegIDs[0]];
      if (notInArray(sel.attributes.primaryStreetID,WME_CRN_goodStreet)) {
        var idemRoadIDs = [];
        for (var i = 0,len_i =listSegIDs.length ; i < len_i; i++) {                                    //Search for identical PrimaryStreetID (same name road)
          var sel1 = Waze.model.segments.objects[listSegIDs[i]];    
          if (sel1.attributes.primaryStreetID == sel.attributes.primaryStreetID) {
            idemRoadIDs.push (listSegIDs[i]);
          }
        }
      
        var street = Waze.model.streets.objects [sel.attributes.primaryStreetID];
        var name = street.name;
        if (name !=null) {
          var newName = rename2 (name);
          if (newName !=name && limitForSaveNotReach()) {
            select (idemRoadIDs);
            var city = Waze.model.cities.objects[street.cityID];
            var newName = prompt (idemRoadIDs.length+" segment(s) to rename : \n"+idemRoadIDs+"\n\nCity :"+city.name+"\nOld name is : "+name+"\n\nConfirm the new name or change it",newName);
            if (newName == null) {
              WME_CRN_badStreet.push (sel.attributes.primaryStreetID);
              document.getElementById('WME_CRN_raz').disabled = false;
              }
            else if (newName != name) {
              var newPrimaryID = SearchPrimaryID (sel.attributes.primaryStreetID, city.name, newName);
              if (newPrimaryID!=null) {
                var action = [];
                for (var k = 0; k < Waze.selectionManager.selectedItems.length; k++) {
                  action.push (new Waze.Action.UpdateSegmentDetails(Waze.selectionManager.selectedItems[k], {primaryStreetID: newPrimaryID}));
                }
                Waze.model.actionManager.add (new Waze.Action.MultiAction(action));  
                modif = true;
              }
            }
          }
        } 
        else {
          WME_CRN_goodStreet.push(sel.attributes.primaryStreetID);
          WME_CRN_goodStreet = delete_multi_Ids (WME_CRN_goodStreet);
        }
        listSegIDs = soustraitArray(listSegIDs,idemRoadIDs);
      }
    } 
    return modif ;
  }
  
  function soustraitArray (array1,array2) {
    var newArray = []; 
    for (var i = 0, len =  array1.length; i<len;i++) {
      if (notInArray (array1[i] , array2)) {
        newArray.push (array1[i]);
      }
    }
    return newArray;
  }
  
  function traiteNumero (name) {
    name = name.replace (/(➘|➚| vers |[ ]*:|>)/gi,"> ");                          // supprime flèche montante et descendante  
    name = name.replace (/(^[ ]*vers )/gi,"> ");                                  // standardise ">" 
    name = name.replace (/([a-z])[-]([0-9]+)/gi,"$1.$2");                          // remplace - par . dans les numéros
    name = name.replace (/[.][0]*/gi,".");                                        // supprime des  0 inutiles  
    name = name.replace (/([ -])[R]?([A|D|E|N|M])[ 0]*([1-9][0-9]+)/gi,"$1$2$3");  //supprime les "R"," "&"0" inutiles dans le nom
    name = name.replace      (/^[R]?([A|D|E|N|M])[ 0]*([1-9][0-9]+)/gi,"$1$2");    //supprime les "R" & "0" inutiles au début  
  
    name = name.replace (/([A|D|E|N|M])([1-9][0-9a-zA-Z.]*)/gi, function (a,x,y) {return (x.toUpperCase()+y); });                    
                                                                                  // minuscules - majuscules
    if (!(/^[D]/.test(name))) {name = name.replace (/(.*)[- ,]+(D[1-9][0-9a-zA-Z.]*)[- ]*$/,"$2 - $1");}      // permutation des départementales à la fin
    
    name = name.replace (/([A|D|E|N|M][1-9][0-9a-zA-Z.]*)[;, -]+/g,"$1 - ")        // mets en place les tirets
    name = name.replace (/^[>][ ]*([A|D|E|N|M][1-9][0-9a-zA-Z.]*)[, -]+/,"$1> ")  // permute les directions
    
    if (/[E][0-9]/.test(name)) {name = triExx(name);}        // tri des routes européennes
    
    // name = triExx(name);                                                
    if (/[>]/.test(name)) {                                              // si indication de sortie
      name = name.replace (/[ -]+[E][0-9]+[ -]*/gi," - ");}              // pas de route européenne
    name = name.replace (/[> ]*Sortie[n° O]*([1-9][0-9a-zA-Z.]*)/gi,
        function (a,x) {return ("Sortie "+x.toLowerCase()+"> "); });
    name = name.replace (/[ ]*[>][ ]*[>]*[ ]*/g,": ")                    // traite les directions
    name = name.replace (/[ ]*[,\/]+[ ]*/g," / ")                        // traite les séparateurs
    name = name.replace (/[ ]*[:][ ]*[:][ ]*/gi,": ");  // supprime les doubles "Deux points"
    name = name.replace (/[ ]*[:][ ]*[/][ ]*/gi," / ");  // traite ": /" en " / "
    name = name.replace (/[-][ ]*[/]/gi,"/");            // supprime les - 
    name = name.replace (/[ ]*[-][ ]*[-][ ]*/gi," - ");  // supprime les doubles tirets
    name = name.replace (/[ ]+/gi," ");                  // supprime les doubles espaces
    name = name.replace (/^[- ,:]*/gi,"");              // nettoyage début
    name = name.replace (/[- ,:]*$/gi,"");              // nettoyage fin
    return name;
  }

  function triExx(name) {                              // Tri les routes européennes
    var part_name = name.split(" ");
    var europe = [];
    for (var i=0;i<part_name.length;i++) {
      if (/^[E][0-9]/.test(part_name[i])) {
        var chaine = part_name[i];
        while (chaine.length <6) {                    // complète les chaines pour le tri
            chaine = chaine.substring(0,1)+"0"+chaine.substring(1,chaine.length);}
        europe.push (chaine);                          // extrait le tableau des routes européennes
      }
    }
    europe.sort();                                    // tri le tableau des chaine européennes
    for (var j=0;j<part_name.length;j++) {
      if (/^[E][0-9]/.test(part_name[j])) {
        part_name[j] = europe.shift().replace (/^[E][0]*/,"E");}  // remet les routes européennes et supprime les zéros inutiles
    }
    return part_name.join(" ");
  }
  
  function rename2(name) {
    var new_name = name;
    new_name = new_name.replace (/[´’]/g,"'");      // Standardise l'apostrophe  (Code ASCII 146 - 180)
    new_name = traiteNumero (new_name);
    new_name = new_name.replace (/'/g,"' ");        // ajout " "  après "'" pour les passages en majuscules
    var part_name = new_name.split(" ");
    for (var i=0;i<part_name.length;i++) {
      part_name[i] = part_name[i].capitalize()+" ";
      part_name[i] = part_name[i].replace (/(-*)(Qui |Sur |Sous |Aux? |Par |Du |Des? |La |Les? |En |Et |À )/gi, function (a,x,y) {return (x+y.toLowerCase()); });
      part_name[i] = correcteurMots(part_name[i]);
    }
    new_name = part_name.join(" ");
    
    new_name = new_name.replace (/ *: *\- */g,  ": ");
    new_name = new_name.replace (/:[ ]*:/g,  ": ");
    new_name = new_name.replace (/^ */,  "");            // supprime " " en tête
    new_name = new_name.replace (/ +/g," ");            // Supprime les doubles espaces    
    new_name = new_name.replace (/[ |-|,|\/]*$/g,  "");  // Traite la fin de chaine
    new_name = new_name.replace (/' */g,"'");            // supprime " "  après "'"
    new_name = new_name.capitalize();
    new_name = new_name.replace (/(\- |\/ |: )([a-z])/g, function (a,x,y) {return (x+y.toUpperCase()); }); // force les majuscules après : ,- et /
    new_name = new_name.replace (/(\- \-)/gi,  "-");
    new_name = new_name.replace (/(\- x)/gi,  "-");
    new_name = correcteurRue (new_name);
    new_name = new_name.replace (/c'H/g,  "c'h");        //exception bretonne "c'h"
    new_name = new_name.replace (/(['][A-Z])$/, function (a,x) {return (x.toLowerCase()); }); // force les minuscules après ' en fin de texte
    
    new_name = new_name.capitalize();
    
    return new_name;
  }

  function correcteurMots (name) {
    var list = WME_CRN_wordGeneric;
    for (var i = 0, len_i = list.length; i < len_i; i++) {
      name = corrigeName (name,list[i]);
    }
    return name;
  }
  
  function correcteurRue (name) {
    var list = WME_CRN_roadGeneric;
    for (var i = 0, len_i = list.length; i < len_i; i++) {
      name = corrigeName (name,list[i]);
    }
    return name;
  }

  function corrigeName (name,Correction) {
    var regexp = new RegExp(Correction.toVerify, Correction.flags);
    return name.replace (regexp, eval(Correction.corrected));
  }
  
  function SearchCityID (country_ID, state_ID, cityName) {
    var emptyct = (cityName==="");
    var fattr = {countryID: country_ID, stateID: state_ID, isEmpty: emptyct, name : cityName };
    var city = Waze.model.cities.getByAttributes(fattr);
    if (city.length === 0) {
      myAlert ("Create new city: "+cityName);
      var f = new Waze.Action.CreateObject(Waze.Model.ObjectType.CITY, {
        countryID: country_ID,stateID: state_ID,isEmpty: emptyct,name: cityName});
      Waze.model.actionManager.add(f);
      return f.newObject.getID();
    }
    if (city.length === 1) {return city[0].getID();}
    if (city.length > 1) {
      myAlert ("Problems with cityID : "+city.length+" cities with same name. Please save and redo");
      return null;
    }
    return null;
  }

  function SearchPrimaryID (oldStreetID, newCityName, newStreetName) {
    var oldStreet = Waze.model.streets.objects[oldStreetID];
    var oldCity    = Waze.model.cities.objects[oldStreet.cityID];
    var newCityID = SearchCityID (oldCity.countryID, oldCity.stateID, newCityName);
    if (newCityID == null) { return null; }
    
    if (newStreetName == null) {newStreetName ="";}
    var emptyst = (newStreetName =="");
    var fattr = {cityID: newCityID, isEmpty: emptyst};
    if (emptyst == false) { fattr.name = newStreetName;}
    var st = Waze.model.streets.getByAttributes(fattr);
    if (st.length === 0) {
      myAlert ("Create new street: "+newCityName+"  "+newStreetName);
      var a = new Waze.Action.CreateObject(Waze.Model.ObjectType.STREET, {
        name: newStreetName,isEmpty: emptyst,cityID: newCityID});
      Waze.model.actionManager.add(a);
      var newPrimaryStreetID = a.newObject.getID();
    }
    if (st.length === 1) {var newPrimaryStreetID = st[0].getID();}
    if (st.length > 1) {
      myAlert ("Problems with StreetID : "+st.length+" streets with same name. Please save and redo");
      return null;
    }
    return newPrimaryStreetID;
  }

  function checkLayerState (layerName) {
    var index = findLayerIndex (layerName);
    if (index != null) {
      return Waze.map.controls[33].map.layers[index].visibility;
    }
    return false;
  }

  function activateLayer (layerName, flag) {
    if (flag == true || flag == false) {
      var index = findLayerIndex (layerName);
      if (index != null) {
        var layerID = Waze.map.controls[0].map.layers[index].id;
        Waze.map.controls[33].map.getLayer(layerID).setVisibility(flag);          //affiche le Layer "landmark"  "Waze.Layer.FeatureLayer_60"    
      }
    }
  }

  function findLayerIndex (layerName) {
    var index;
    switch (layerName.toUpperCase()) {
      case "AERIALS":          index = 1 ; break;
      case "CITIES":          index = 2 ; break;
      case "ROADS":            index = 3 ; break;
      case "GPS POINTS":      index = 4 ; break;
      case "AREA MANAGERS":    index = 6 ; break;
      case "LANDMARKS":        index = 7 ; break;
      case "SPEED CAMERAS":    index = 10; break;
      case "MAP PROBLEMS":    index = 12; break;
      case "UPDATE REQUESTS":  index = 14; break;
      case "EDITABLE AREAS":  index = 16; break;
      case "LIVE USERS":      index = 25; break;
    }
    return index;
  }

  function select (Select_IDs)  {
    Select_IDs = delete_multi_Ids (Select_IDs)  ;                  // suppression des doublons
    var foundSegs = [];  
    for (var i = 0; i<Select_IDs.length;i++) {  
      foundSegs.push(Waze.model.segments.objects[Select_IDs[i]]);  // créer la selection
    }
    Waze.selectionManager.select(foundSegs); 
  }

  function delete_multi_Ids (myArray) {
    var myNewArray = [];
    if (myArray.length > 0) {
      myNewArray[0]= myArray [0];
      var len =  myArray.length;
      for (var i = 0; i < len; i++) {
        if (notInArray (myArray [i],myNewArray)) {myNewArray.push(myArray [i]);}
      }
    }
    return myNewArray;
  }

  function isInArray (item,array) {return array.indexOf(item) !== -1;}
  function notInArray (item,array) {return array.indexOf(item) === -1;}
  function findPending() {return Waze.map.controls[5].pending ;}

  function manage_WME_CRN(ev) {  
    localStorage.WME_CRN_enable = document.getElementById ('WME_CRN_enable').checked == 1;  
    if(document.getElementById('WME_CRN_enable').checked == 1) {
      document.getElementById ('WME_CRN_All').style.height = "auto";
      document.getElementById ('WME_CRN_rename').style.display = "block";
    }
    else {
      document.getElementById ('WME_CRN_All').style.height = "40px";
      document.getElementById ('WME_CRN_rename').style.display = "none";
      document.getElementById ('WME_CRN_CheckRoadName').checked = 0;
    }
    manage_CheckRoadName() ;
    WME_CRN_goodStreet.length = 0;                                              // vide le tableau des rues correctes
    return;
  }

  function manage_CheckRoadName() {
    var checkRoad = (document.getElementById ('WME_CRN_CheckRoadName').checked == 1) ;
    localStorage.WME_CRN_CheckRoadName = checkRoad;
    if (checkRoad) {
      setTimeout (function(){rename_Road();},4001);                                      // on le relance si une case est cochée
    }
    return;
  }

   function afficheObjet (objet) {
     for (var e in objet) {alert("objet["+e+"] ="+ objet[e]+" !");}
   }

  function console_log(msg) {
    if (console.log) {
      console.log(msg);}
  }

  function encodeHTML (var1) {
    var var2 = var1;
    var2 = var2.replace (/[&]/gi,"&amp;");
    var2 = var2.replace (/["]/gi,"&quot;");
    var2 = var2.replace (/[<]/gi,"&lsaquo;");
    var2 = var2.replace (/[>]/gi,"&rsaquo;");
    return var2 ;
  }

  function init_WME_CRN() {
    localStorage.removeItem('WME_CRN_CheckLdmkName');                        // Remove old item in LocalStorage
    localStorage.removeItem('WME_Merge_Unknown_Roads_CheckLdmkName');
    localStorage.removeItem('WME_Merge_Unknown_Roads_CheckRoadName');
    localStorage.removeItem('WME_Merge_Unknown_Roads_enable');
    localStorage.removeItem('WME_CRN_CheckCityName');

    if (localStorage.WME_CRN_enable == "true") {                              // restaure old Values (if exist)
      document.getElementById ('WME_CRN_enable').checked = 1 ; }
    if (localStorage.WME_CRN_CheckRoadName == "true") {
      document.getElementById ('WME_CRN_CheckRoadName').checked = 1 ; }
    document.getElementById("WME_CRN_enable").onclick = manage_WME_CRN;
    document.getElementById("WME_CRN_CheckRoadName").onclick = manage_CheckRoadName;  
    manage_WME_CRN ();
    
		if ('undefined' == typeof Waze.Action.UpdateSegmentDetails ) {	// compatibility with new editor
			Waze.Action.UpdateSegmentDetails = Waze.Action.UpdateObject ;    
		}
		
		myAlert("WME_CRN initialized");
  }
  
  function myAlert (message) {
    var myMessage = document.getElementById ('WME_CRN_AlertTxt').innerHTML;
    var line = myMessage.split("<br>");
    if (line.length==1 && line[0]==""){ line[0]= message;}
      else { line.push (message);}
    document.getElementById ('WME_CRN_AlertTxt').innerHTML = line.join ("<br>");
    document.getElementById ('WME_CRN_AlertBox').style.display = "block";
    setTimeout(function() {endAlert();}, 3750 + 500*Math.random());
  } 

  function endAlert() {
    var myMessage = document.getElementById ('WME_CRN_AlertTxt').innerHTML;
    var line = myMessage.split("<br>");
    line.shift();
    document.getElementById ('WME_CRN_AlertTxt').innerHTML = line.join ("<br>");
    if (line.length ==0){
      document.getElementById ('WME_CRN_AlertBox').style.display = "none";
    }
  } 

  function limitForSaveNotReach() {
    if (Waze.model.actionManager.index > 98) {return false;}    // limit action not saved
    else {return true;}
  }

}

CheckRoadName();