WME Closure Sheet Helper

Helps filling those pesky closure sheets

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 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 ======================================================================= */