您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Serves to reverse the nodes A and B of a segment, in order to better manage restrictions on multiples segments.
当前为
// ==UserScript== // @name WME Reverse Nodes // @name:fr WME Reverse Nodes // @description Serves to reverse the nodes A and B of a segment, in order to better manage restrictions on multiples segments. // @description:fr Sert à inverser les nodes A et B d'un segment, dans le but de mieux gérer les restrictions sur segments multiples. // @include https://www.waze.com/editor/* // @include https://www.waze.com/*/editor/* // @include https://beta.waze.com/editor/* // @include https://beta.waze.com/*/editor/* // @exclude https://www.waze.com/user/* // @exclude https://www.waze.com/*/user/* // @namespace WME_Reverse_Nodes // @version 0.9 // @grant none // ==/UserScript== function WRNAB_Injected(){ var WRNAB_version = "0.9"; var debug = false; var WRNAB_API = {}; WRNAB_API.require = {}; /* bootstrap */ function WRNAB_bootstrap(){ if (typeof(unsafeWindow) === "undefined"){ unsafeWindow = ( function () { var dummyElem = document.createElement('p'); dummyElem.setAttribute('onclick', 'return window;'); return dummyElem.onclick(); }) (); } /* begin running the code! */ log("Start"); setTimeout(initialize, 1000); } //========== Helper ==============================// function getElementsByClassName(classname, node) { if(!node) node = document.getElementsByTagName("body")[0]; var a = []; var re = new RegExp('\\b' + classname + '\\b'); var els = node.getElementsByTagName("*"); for (var i=0,j=els.length; i<j; i++) if (re.test(els[i].className)) a.push(els[i]); return a; } function getId(node) { return document.getElementById(node); } function log(msg, obj) { if (obj==null) console.log("WME Reverse Nodes AB v" + WRNAB_version + " - " + msg); else if(debug) console.debug("WME Reverse Nodes AB v" + WRNAB_version + " - " + msg + " " ,obj); } //========== /Helper ==============================// function initialize() { initializeWazeObjects(); } function waitForObject(object) { var obj=null; if (object.r==true) { if (debug) log ("eval: " + (object.s!=null?object.s:'dummy') + "="+ ((typeof(window.require)=="function")?"require":"WRNAB_API.require") +"(\"" + object.o + "\")"); eval ((object.s!=null?object.s:'dummy') + '=' + ((typeof(window.require)=="function")?'require':'WRNAB_API.require') +'("' + object.o + '")'); eval ("obj=" + (object.s!=null?object.s:'dummy')); if (debug) log("obj", obj); }else{ if (debug) log ("eval: " + "typeof(unsafeWindow." + object.o.replace(/\//g, '.') + ")"); obj=eval("typeof(unsafeWindow." + object.o.replace(/\//g, '.') + ")"); } if(obj === "undefined") { log(object.o + ' KO'); window.setTimeout(waitForObject.caller, 500); return false; } if (debug) log(object.s + ' OK'); if (object.s!=null && object.r==false) eval (object.s + "=" + object.o.replace(/\//g, '.')); return true; } function initializeWazeObjects() { var objectToCheck = [ {o: "Waze", s: "waze", r: false}, {o: "Waze.vent", s: "wazeVent", r: false}, {o: "Waze.controller", s: "wazeController", r: false}, {o: "Waze.model", s: "wazeModel", r: false}, {o: "Waze.map", s: "wazeMap", r: false}, {o: "Waze.loginManager", s: "WazeLoginManager", r: false}, {o: "Waze.selectionManager", s: "WazeSelectionManager", r: false}, {o: "Waze/Action/UpdateObject", s: "WazeActionUpdateObject", r: true}, {o: "Waze/Action/UpdateSegmentGeometry", s: "WazeUpdateSegmentGeometry", r: true}, {o: "Waze/Action/ConnectSegment", s: "WazeActionConnectSegment", r: true}, {o: "Waze/Action/ModifyConnection", s: "WazeActionModifyConnection", r: true}, //{o: "Waze/Action/ModifyAllConnections", s: "WazeActionModifyAllConnections", r: true}, {o: "Waze.loginManager.user", s: "me", r: false}, {o: "me.rank", s: "ul", r: false}, {o: "me.isAreaManager", s: "uam", r: false}, {o: "localStorage", s: null, r: false} ]; for (var i=0; i<objectToCheck.length; i++) { if (!waitForObject(objectToCheck[i])) return; } initializeWazeUI(); } function initializeWazeUI() { var userInfo = getId('user-info'); if (userInfo==null) { window.setTimeout(initializeWazeUI, 500); return; } var navTabs=userInfo.getElementsByTagName('ul'); if (navTabs.length==0) { window.setTimeout(initializeWazeUI, 500); return; } if (typeof(navTabs[0])==='undefined') { window.setTimeout(initializeWazeUI, 500); return; } var tabContents=userInfo.getElementsByTagName('div'); if (tabContents.length==0) { window.setTimeout(initializeWazeUI, 500); return; } if (typeof(tabContents[0])==='undefined') { window.setTimeout(initializeWazeUI, 500); return; } WRNAB_Init(); } function WRNAB_newSelectionAvailable() { log('WazeSelectionManager',WazeSelectionManager); if (WazeSelectionManager.selectedItems.length!=1) return; var selectedObject = WazeSelectionManager.selectedItems[0].model; if (selectedObject.type!="segment") return; log('uam', uam); if (!uam) return; var attributes = selectedObject.attributes; log('attributes', attributes); if (attributes.fwdRestrictions !== undefined && attributes.fwdRestrictions.length > 0){ var fwdRestrictions = attributes.fwdRestrictions; } if (attributes.revRestrictions !== undefined && attributes.revRestrictions.length > 0){ var revRestrictions = attributes.revRestrictions; } var editPanel=getId('edit-panel'); if (editPanel.firstElementChild.style.display=='none') window.setTimeout(WRNAB_newSelectionAvailable, 100); // ok: 1 selected item and pannel is shown if (selectedObject.type=="segment") { item=getId("segment-edit-general"); var WRNAB_Controle=document.createElement('Div'); WRNAB_Controle.id="WRNAB-Controle"; WRNAB_Controle.innerHTML='<input type="button" id="_btnInvertAB" value="Reverse Nodes A/B">'; item.appendChild(WRNAB_Controle); getId("_btnInvertAB").onclick=invertNodeAB; log("wazeModel.actionManager",wazeModel.actionManager); } } function WRNAB_Init() { WazeSelectionManager.events.register("selectionchanged", null, WRNAB_newSelectionAvailable); log('init done.'); } function onScreen(obj) { if (obj.geometry) { return(wazeMap.getExtent().intersectsBounds(obj.geometry.getBounds())); } return false; } function isSegmentEditable(seg) { var rep = true; if (seg==null) return false; //if (Waze.loginManager.user.isCountryManager() ) rep = true; if (!uam) rep = false; var ndA = wazeModel.nodes.get(seg.attributes.fromNodeID); var ndB = wazeModel.nodes.get(seg.attributes.toNodeID); if ((seg.attributes.permissions == 0) || (seg.attributes.hasClosures)) rep = false; if ((ndA.attributes.permissions == 0) || (seg.attributes.hasClosures)) rep = false; if ((ndB.attributes.permissions == 0) || (seg.attributes.hasClosures)) rep = false; return rep; } function invertNodeAB() { if (WazeSelectionManager.selectedItems.length!=1) return; var seg = wazeModel.segments.get(WazeSelectionManager.selectedItems[0].model.attributes.id); if (seg.type!="segment") return; var attr = seg.attributes; log("seg",seg); log("attr",attr); var sid = attr.id; // si non nomme, on touche pas: if (attr.primaryStreetID==null) { log("Unnamed segment. Do not put my name on it!"); return; } // si locke: on edite pas /*if ((attr.lockRank==null && attr.rank>usrRank) || (attr.lockRank!=null && attr.lockRank>usrRank)) { log("locked: " + attr.rank + " " + attr.lockRank); continue; } */ //var ndA = wazeModel.nodes.objects[attr.fromNodeID]; //var ndB = wazeModel.nodes.objects[attr.toNodeID]; var ndA = wazeModel.nodes.get(attr.fromNodeID); var ndB = wazeModel.nodes.get(attr.toNodeID); log("ndA", ndA); log("ndB", ndB); // verification de pbs sur nodes (unterminated roads par ex) if (!ndA || !ndB) { log("Bad nodes: A=" + ndA + " B=" + ndB); return; } // On verifie que le segment est affiche a l'ecran if (onScreen(ndA) && onScreen(ndB)) { log("IN Screen!"); } else { log("OUT of Screen"); return; } // On verifie que le segment est éditable if (!isSegmentEditable(seg)) { log("Not editable!"); return; } // On mémorise les directions autorisées vers le segment var sconA=[]; var sconB=[]; // pour les segments connecté à la node A for (var s=0; s<ndA.attributes.segIDs.length; s++) { var scon=ndA.attributes.segIDs[s]; if (wazeModel.segments.objects[scon].attributes.fromConnections.hasOwnProperty(attr.id)) sconA.push(scon); if (wazeModel.segments.objects[scon].attributes.toConnections.hasOwnProperty(attr.id)) sconA.push(scon); } // pour les segments connecté à la node B for (var s=0; s<ndB.attributes.segIDs.length; s++) { var scon=ndB.attributes.segIDs[s]; if (wazeModel.segments.objects[scon].attributes.fromConnections.hasOwnProperty(attr.id)) sconB.push(scon); if (wazeModel.segments.objects[scon].attributes.toConnections.hasOwnProperty(attr.id)) sconB.push(scon); } log("sconA",sconA); log("sconB",sconB); // Mémorisation des paramètre du segment pour les reporter après changement de sens var newAttr={}; var fromConnections = attr.toConnections; var toConnections = attr.fromConnections; //var fromConnections = attr.toConnections.clone(); //var toConnections = attr.fromConnections.clone(); newAttr.fwdDirection = attr.revDirection; newAttr.revDirection = attr.fwdDirection; newAttr.fwdTurnsLocked = attr.revTurnsLocked; newAttr.revTurnsLocked = attr.fwdTurnsLocked; newAttr.fwdMaxSpeed = attr.revMaxSpeed; newAttr.revMaxSpeed = attr.fwdMaxSpeed; newAttr.fwdMaxSpeedUnverified = attr.revMaxSpeedUnverified; newAttr.revMaxSpeedUnverified = attr.fwdMaxSpeedUnverified; newAttr.fwdRestrictions = attr.revRestrictions.clone(); newAttr.revRestrictions = attr.fwdRestrictions.clone(); log("seg",seg); log("attr",attr); log("newAttr", newAttr); log("fromConnections", fromConnections); log("toConnections", toConnections); //on inverse la géométrie du segment var geo = seg.geometry.clone(); geo.components.reverse(); // controle de position var nbPoints = geo.components.length-1; if (!geo.components[0].equals(ndB.attributes.geometry)){ if (debug) log("point 0 et dif de node A"); var delta = {x:0, y:0}; delta.x =ndB.attributes.geometry.x - geo.components[0].x; delta.y = ndB.attributes.geometry.y - geo.components[0].y; geo.components[0].move(delta.x, delta.y); } if (!geo.components[nbPoints].equals(ndA.attributes.geometry)){ if (debug) log("point "+nbPoints+ " est dif de node B"); var delta = {x:0, y:0}; delta.x = ndA.attributes.geometry.x - geo.components[nbPoints].x; delta.y = ndA.attributes.geometry.y - geo.components[nbPoints].y; geo.components[nbPoints].move(delta.x, delta.y); } // maj de la géo du seg wazeModel.actionManager.add(new WazeUpdateSegmentGeometry (seg,seg.geometry,geo)); // On reconecte le segment wazeModel.actionManager.add(new WazeActionConnectSegment(ndB, seg)); wazeModel.actionManager.add(new WazeActionConnectSegment(ndA, seg)); //on replace les paramètre inversé wazeModel.actionManager.add(new WazeActionUpdateObject(seg, newAttr)); //on replace les autorisations sortantes for (var sid in fromConnections) { if (debug) log("attr.id: " + attr.id + " --> NodeA --> sid: " + sid); wazeModel.actionManager.add(new WazeActionModifyConnection(attr.id, ndB, sid, true)); } for (var sid in toConnections) { if (debug) log("attr.id: " + attr.id + " --> NodeB --> sid: " + sid); wazeModel.actionManager.add(new WazeActionModifyConnection(attr.id, ndA, sid, true)); } //on replace les autorisations entrantes log("ndB", ndB); for (var s=0; s<sconB.length; s++) { if (debug) log("sconB["+s+"] :" + sconB[s] + " nodeA: " + ndB.attributes.id + " attr.id: " + attr.id); wazeModel.actionManager.add(new WazeActionModifyConnection(sconB[s], ndB, attr.id, false)); wazeModel.actionManager.add(new WazeActionModifyConnection(sconB[s], ndB, attr.id, true)); } log("ndA", ndA); for (var s=0; s<sconA.length; s++) { if (debug) log("sconA["+s+"] :" + sconA[s] + " nodeB: " + ndA.attributes.id + " attr.id: " + attr.id); wazeModel.actionManager.add(new WazeActionModifyConnection(sconA[s], ndA, attr.id, false)); wazeModel.actionManager.add(new WazeActionModifyConnection(sconA[s], ndA, attr.id, true)); } log('Invert node for segment '+attr.id+': Ok'); } if (typeof(window.require) == "function"){ log("bootstrap classique"); WRNAB_bootstrap(); }else{ /////////////////////////////////////////////// /// Big thanks to dummyd2 for this Patch // /////////////////////////////////////////////// log("load patch dummyd2"); // setup one global var and put all in var WRNABAPI = {}; // detect URL of WME source code WRNABAPI.scripts = document.getElementsByTagName('script'); WRNABAPI.url=null; for (i=0;i<WRNABAPI.scripts.length;i++) { if (WRNABAPI.scripts[i].src.indexOf('/assets-editor/js/app')!=-1) { WRNABAPI.url=WRNABAPI.scripts[i].src; break; } } if (WRNABAPI.url==null) { throw new Error("WME Hack: can't detect WME main JS"); } // setup a fake require and require.define WRNABAPI.require=function (e) { return WRNABAPI.require.define.modules[e]; }; WRNABAPI.require.define=function (m) { if (WRNABAPI.require.define.hasOwnProperty('modules')==false) WRNABAPI.require.define.modules={}; for (var p in m) { WRNABAPI.require.define.modules[p]=m[p]; } }; // save the original webpackJsonp function WRNABAPI.tmp = window.webpackJsonp; // taken from WME code: this function is a wrapper that setup the API and may call recursively other functions WRNABAPI.t = function (n) { if (WRNABAPI.s[n]) return WRNABAPI.s[n].exports; var r = WRNABAPI.s[n] = { exports: {}, id: n, loaded: !1 }; return WRNABAPI.e[n].call(r.exports, r, r.exports, WRNABAPI.t), r.loaded = !0, r.exports; }; // e is a copy of all WME funcs because function t need to access to this list WRNABAPI.e=[]; // the patch window.webpackJsonp = function(a, i) { // our API but we will use it only to build the require stuffs var api={}; // taken from WME code. a is [1], so... for (var o, d, u = 0, l = []; u < a.length; u++) d = a[u], WRNABAPI.r[d] && l.push.apply(l, WRNABAPI.r[d]), WRNABAPI.r[d] = 0; var unknownCount=0; var classname, funcStr; // copy i in e and keep a link from classname to index in e for (o in i) { WRNABAPI.e[o] = i[o]; funcStr = i[o].toString(); classname = funcStr.match(/CLASS_NAME:\"([^\"]*)\"/); if (classname) { // keep the link. api[classname[1].replace(/\./g,'/').replace(/^W\//, 'Waze/')]={index: o, func: WRNABAPI.e[o]}; } else { api['Waze/Unknown/' + unknownCount]={index: o, func: WRNABAPI.e[o]}; unknownCount++; } } // taken from WME code: it calls the original webpackJsonp and do something else, but I don't really know what. // removed the call to the original webpackJsonp: still works... //for (tmp && tmp(a, i); l.length;) l.shift().call(null, t); for (; l.length;) l.shift().call(null, WRNABAPI.t); WRNABAPI.s[0] = 0; // run the first func of WME. This first func will call recusrsively all funcs needed to setup the API. // After this call, s will contain all instanciables classes. //var ret = WRNABAPI.t(0); // now, build the requires thanks to the link we've built in var api. var module={}; var apiFuncName; unknownCount=0; for (o in i) { funcStr = i[o].toString(); classname = funcStr.match(/CLASS_NAME:\"([^\"]*)\"/); if (classname) { module={}; apiFuncName = classname[1].replace(/\./g,'/').replace(/^W\//, 'Waze/'); module[apiFuncName]=WRNABAPI.t(api[apiFuncName].index); WRNABAPI.require.define(module); } else { var matches = funcStr.match(/SEGMENT:"segment",/); if (matches) { module={}; apiFuncName='Waze/Model/ObjectType'; module[apiFuncName]=WRNABAPI.t(api['Waze/Unknown/' + unknownCount].index); WRNABAPI.require.define(module); } unknownCount++; } } // restore the original func window.webpackJsonp=WRNABAPI.tmp; // set the require public if needed // if so: others scripts must wait for the window.require to be available before using it. //window.require=WRNABAPI.require; WRNAB_API.require=WRNABAPI.require; // all available functions are in WRNABAPI.require.define.modules // console.debug this variable to read it: //console.debug('WRNABAPI Modules: ', WRNABAPI.require.define.modules); // run your script here: setTimeout(WRNAB_bootstrap, 1000); // again taken from WME code. Not sure about what it does. //if (i[0]) return ret; }; // some kind of global vars and init WRNABAPI.s = {}; WRNABAPI.r = { 0: 0 }; // hacking finished // load again WME through our patched func WRNABAPI.WMEHACK_Injected_script = document.createElement("script"); WRNABAPI.WMEHACK_Injected_script.setAttribute("type", "application/javascript"); WRNABAPI.WMEHACK_Injected_script.src = WRNABAPI.url; document.body.appendChild(WRNABAPI.WMEHACK_Injected_script); } }var WRNAB_Injected_script = document.createElement("script"); WRNAB_Injected_script.textContent = '' + WRNAB_Injected.toString() + ' \n' + 'WRNAB_Injected();'; WRNAB_Injected_script.setAttribute("type", "application/javascript"); document.body.appendChild(WRNAB_Injected_script);