WME Closure Sheet Helper

Helps filling those pesky closure sheets

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name:hu             WME Closure Sheet Segéd
// @name:en             WME Closure Sheet Helper
// @description:hu      Lezárási táblázatok kitöltését egyszerűsítő segéd
// @description:en      Helps filling those pesky closure sheets
// @copyright           2016, ragacs
// @name                WME Closure Sheet Helper
// @description         Helps filling those pesky closure sheets
// @version             1.04
// @include             https://www.waze.com/editor*
// @include             https://www.waze.com/*/editor*
// @include             https://beta.waze.com/editor*
// @include             https://beta.waze.com/*/editor*
// @namespace https://greasyfork.org/users/6330
// @grant               none
// ==/UserScript==

var wmecsh_version = "1.04";

/* bootstrap, will call initialiseClosureSheetHelper() */
function bootstrapClosureSheetHelper()
{
  /* begin running the code! */
  setTimeout(initialiseClosureSheetHelper, 999);
}

/* helper function */
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 sortByAB(arr)
{
    //var revsegs=Waze.selectionManager.getReversedSegments();
    var nodes = {};
    var earr = arr.splice(0, arr.length);
    var rnodes = [];
    // collect segments under their node elements
    for(var a=0; a < earr.length; a++)
    {
        if(nodes[earr[a].model.attributes.fromNodeID] === undefined)
            nodes[earr[a].model.attributes.fromNodeID] = [];
        nodes[earr[a].model.attributes.fromNodeID].push(earr[a]);
        
        if(nodes[earr[a].model.attributes.toNodeID] === undefined)
            nodes[earr[a].model.attributes.toNodeID] = [];
        nodes[earr[a].model.attributes.toNodeID].push(earr[a]);
    }

    while(earr.length != arr.length)
    {
        var node = 0;
        // search for nodes with odd connections - these will be start/end points
        for(var n in nodes)
        {
            if(node == 0 && nodes[n].length > 0)
                node = Number(n); // safety starting point if no odd connections found (circle selected)
            if(nodes[n].length % 2 == 1)
            {
                node = Number(n);
                break;
            }
        }
        // walk on the chain to the end
        while(node != 0)
        {
            var seg = nodes[node].pop();
            arr.push(seg);
            rnodes.push(node);
            if(seg.model.attributes.fromNodeID == node)
                node = seg.model.attributes.toNodeID;
            else
                node = seg.model.attributes.fromNodeID;
            nodes[node].splice(nodes[node].indexOf(seg), 1);
            if(nodes[node].length == 0)
            {
                rnodes.push(node);                
                node = 0;
            }
        }
    }
    // rnodes will contain the node list for the segment chains
    return rnodes;
}

function clickedClosureSheetHelper(event)
{
    var segs = Waze.selectionManager.selectedItems;
    event = event || window.event;
    var ctrlalt = (event.ctrlKey || event.metaKey);
    var zoom = Waze.map.getZoom();
    
    if(segs.length == 0)
    {
        alert("Select some segments first!");
        return;
    }
    
    if(zoom < 4)
    {
        alert("Too low zoom level!");
        return;
    }
    
    var endobj = {};
    var cityname = "";
    for(var s=0; s < segs.length; s++)
    {
        if(segs[s].model.type === "segment")
        {
            var pristrid = segs[s].model.attributes.primaryStreetID;  // segment's street ID
            var streetname = Waze.model.streets.get(pristrid).name; // street name
            if(streetname === null)
                streetname = "No street";
            if(cityname.length == 0)
                cityname = Waze.model.cities.get(Waze.model.streets.get(pristrid).cityID).name;
            var segid = segs[s].model.attributes.id;               // segment ID
            if(endobj[streetname] === undefined)
                endobj[streetname] = [];
            endobj[streetname].push(segs[s]);
        }
    }
    
    if(cityname.length == 0)
        cityname = "No city";
    var tmplatlon=Waze.map.getCenter();
    tmplatlon.transform(Waze.map.getProjectionObject(), Waze.map.displayProjection); // This will be the center of the map in normal projection EPSG:900913
    // Creating sheet rows
    // date	time	date	time	streetname	segmentids	permalink nodeids
    // permalink = https://www.waze.com/editor/?lon=19.154683728784565&lat=47.46686402709748&zoom=6&segments=102441276
    // 2015-05-08	17:30:00	2015-05-11	00:01:00	Adverse street	199532916,199532917	https://www.waze.com/editor/?env=row&lon=21.61066&lat=47.54755&layers=1476&zoom=6&segments=199532916,199532917 18442418,18442419,21655326
    
    var alls = "";
    for(var k in endobj)
    {
        var line1 = "d\tt\td\tt\t"; 
        var ends = "";
        if (!ctrlalt)
            line1 += cityname + "\t";
        line1 += k + "\t'";
        var plink = "https://www.waze.com/editor/?lon=" + tmplatlon.lon + "&lat=" + tmplatlon.lat + "&zoom=" + zoom + "&segments=";
        var idss = "";
        var nodess = "";
        var lastid = 0;
        var rnodes = sortByAB(endobj[k]);
        for(var si=0; si < endobj[k].length; si++)
        {
            if(endobj[k][si].model.attributes.fromNodeID != lastid && endobj[k][si].model.attributes.toNodeID != lastid)
            {
                if(k == "No street" && lastid != 0)
                {
                    ends += line1 + idss + "\t" + plink + idss + "\t'" + nodess + "\n";
                    idss = "";
                    nodess = "";
                }
                if(nodess.length > 0) nodess += ",";
                nodess += rnodes.shift();
            }
            if(idss.length > 0) idss += ",";
            idss += endobj[k][si].model.attributes.id;
            
            lastid = rnodes.shift();
            if(lastid !== undefined && lastid != 0)
            {
                if(nodess.length > 0) nodess += ",";
                nodess += lastid;
            }
        }
        ends += line1 + idss + "\t" + plink + idss + "\t'" + nodess + "\n";
// There is a problem in Google Chrome and Opera to limit the text in window.prompt to 2000 characters (or less with accented characters)
// These lines below tries to "fix" it but it has some drawbacks. Chrome sticks focus to prompted tabs. So you should paste every block to another app (eg. Notepad)
// which is a pain in the ass. So it is now removed and replaced with a warning.
//        if(alls.length + ends.length > 1900)
//        {
//            window.prompt("CSH v" + wmecsh_version + ". Copy to clipboard: Ctrl+C, Enter", alls);
//            alls = "";
//        }
        alls += ends;
    }
    var msgtitle = "CSH v" + wmecsh_version + ". Copy to clipboard: Ctrl+C, Enter";
    if(alls.length > 1900) msgtitle += "\nWARNING: Chrome browsers truncate string - select fewer segments!";
    window.prompt(msgtitle, alls);
}

/* =========================================================================== */

function initialiseClosureSheetHelper()
{
  // global variables
  var betaMode = location.hostname.match(/beta.waze.com/);

  // add new box to left of the map
  var addon = document.createElement('div');
  addon.id = "closuresheethelper-addon";
  addon.className = "toolbar-button";
  addon.title = "Click to Closures Sheet, Ctrl+Click to Event Sheet";
  addon.innerHTML  = '<span>To Closures Sheet</span>';
  addon.style.backgroundRepeat = "no-repeat";
  addon.style.backgroundPosition = "center center";
  addon.style.backgroundImage = "url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACYAAAAmCAYAAACoPemuAAAACXBIWXMAAA7DAAAOwwHHb6hkAAAE"
                              + "rUlEQVRYw+2XW2xURRjH/9/MOWdZbGtv1FIumxguwQpdQYqobKBiYuKjL0JC48YnE160T/pk4gM+"
                              + "4IMaog9qQ8OTGnxSowlWWgtNgdo22JIUIhKCcimX9LZ7zsx8PvRsPT09e6PGxKRfstmzszNzfvNd"
                              + "/jMDLNuyLduy/b+Ngj86e4bIGCMYEGDYINh+H44YR+HxIWP/YwBo/5nAYKL5/8EAE8hYllBNq2ql"
                              + "lKKibcOae1YQylPaUUonzo+Ov09EdQCqI6AYABEgGRAFVqx5DsgDMDP3zQSQ8acxzFAA+OnmjYc1"
                              + "y9vaGEgpHgdwYR7MGAOtdeLsyNgpT+m1/2XY+n4d3b+rZUsy66m7jm1NAMA8GDPk+dHLxwpBObb1"
                              + "ly1lX7BNG1OtjdnoKb2+HBjHtq47tn0tk822KG0eGb505ctVNZVtlStXPFgABoIkYFOBifq7Otp3"
                              + "h9sPHe36vhwo25L321pbdqZTycudPUMNZ4bGvpqcmU0BcCanZt0DrU9MAsEcYYABJw/U6Sio9qNd"
                              + "P3pKvVSylyzrVltry9Z0Knk5l0F+YeQKKve8IHnDSQ5Likx8hdPZ1dG+dxHUB13drlIvlhG6a/ta"
                              + "tz2ZTiWv51GGjF8oWBhKAJmsW/sPlJxa11j/6pFDL38bkhSr+9xIt+up50uFitn2+N6dW3ekU8nJ"
                              + "0F91s667w3+eDjonmGOkjXECKzwZARXvPjfS63pqR+lQ1kUfyg3N1fTTwPCAUrrSD1g2GEErKpCO"
                              + "bY3v2d785hcLJ6rqPjfS73pqSxnhGzre0f7U8cUFs/2HM4MnAVQFVMGNBiMYy5L3ldLVYMR7B3/7"
                              + "+PCnXw9MZzJJAlWdGhjer5SuKnlLIVKC6N47J757BYD35527mwD8obVZ53rqNQBrQkNUcCcJ5phJ"
                              + "NK56+/cbNz90lVrrKnVwJpM9+LCiycxWxvX2Xb1x87k5AWcnX19LysnqyopPgnGbd50UwiSaGrrj"
                              + "sVjfv6nqxrBTCMq25MSahrrXNyZW90shVL5NPKaNaTw7PPYREVUBiGWy3ialdV2wn5RiKu44F0Hk"
                              + "LpAbZpUTa2a+pw3ftqRIZFxvdzgNbMuacGx5+rHamhMb1q/+hRlTQlA2nUoaFDkd4POfB2vPjlz6"
                              + "Zmomkwq2V6yM9z6zbfMBKcSNdCrJ+cZ39gwRgEfPDI/1T07Pbg6EbvqFXS1JAFdyDDmgSB2LSGEX"
                              + "QDbcqrUeE0R3CkEFzA07IL7CGQFwyx8fOYcomMBzY2S4fc/25vf8KipogRfzwsLAtA+c1wp6TBBJ"
                              + "AsUjToCylMT3Q0l5HMAPDUZEArS4DxsupzAp4j1FJxBFJ+XFBWK4LDCxGIzNksCYOfJcTwATUel0"
                              + "ixeni3mtIJhhFigxn4r6PTT1ksDAEFF9iMgQlXUL43LXUkwuZDQYPCqR7GFNFJYLYXy3B0+1/lWs"
                              + "JC/k7pUqpGNqSWBE0GEhjMdiV/37Yqku8wA8CBXVTHjB5erYTGN9zTHcwRv+1iQa62s+E3Obd1GP"
                              + "pVNJ7uwZMg211UcAvAvABnD/2ZYtbxUDo2LKzcwxfwHazysFQJW4T+bUXwKI+RFSALLhTXvZlmp/"
                              + "A6Qq+7ZpKd6qAAAAAElFTkSuQmCC)";

  var buttonsBar = getId('edit-buttons');
  var firstButton = getElementsByClassName('toolbar-button', buttonsBar)[0];
  buttonsBar.style.cssText = 'width:' + (3*firstButton.offsetWidth + buttonsBar.offsetWidth) + 'px !important';
  //buttonsBar.style.cssText = 'width:auto !important';    
  addon.style.backgroundSize = window.getComputedStyle(firstButton, ':after').width.split(" ")[0]; //"25px"
  addon.style.width = window.getComputedStyle(firstButton).width;
  addon.style.height = window.getComputedStyle(firstButton).height;
  firstButton.parentNode.insertBefore(addon, firstButton);    
 
  getId('closuresheethelper-addon').onclick = clickedClosureSheetHelper;    
}

/* engage! =================================================================== */
bootstrapClosureSheetHelper();

/* end ======================================================================= */