WME PL Jump

Opens a PL in an existing WME window/tab.

As of 2016-01-16. See the latest version.

// ==UserScript==
// @name            WME PL Jump
// @description     Opens a PL in an existing WME window/tab.
// @version         0.0.1
// @author          SAR85
// @copyright       SAR85
// @license         CC BY-NC-ND
// @grant           none
// @include         https://www.waze.com/editor/*
// @include         https://www.waze.com/*/editor/*
// @include         https://editor-beta.waze.com/*
// @namespace       https://greasyfork.org/users/9321
// @require			https://greasyfork.org/scripts/9794-wlib/code/wLib.js?
// ==/UserScript==

(function () {
    'use strict';
    var dataMerged = false,
        decodedLink = {
            lon: null,
            lat: null,
            segments: null,
            nodes: null,
            venues: null,
            updateRequest: null,
            zoom: null
        };
    
    /**
     * Checks for necessary page elements or objects before initalization 
     * script.
     * @param tries {Number} The number of tries bootstrapping has been 
     * attempted.
     */
    function bootstrap(tries) {
        tries = tries || 1;
        if ('undefined' !== typeof wLib &&
            'undefined' !== typeof $ &&
            $('#edit-buttons').length > 0) {
            init();
        } else if (tries < 20) {
            window.setTimeout(function () {
                bootstrap(tries + 1);
            }, 1000);
        }
    }
    
    /**
     * Initializes global variables and sets up HTML and event listeners.
     */
    function init() {
        var inputContent = '<input type="text" id="pljumpinput"></input><button id="pljumpbutton">Jump</button>',
            tabContent = '<p>Insert content here</p>',
            tab;

        if ($('#pljumpinput').length === 0) {
            // Create the PL input box and jump button
            $('<div/>').
                css({
                    'float': 'right',
                    'margin': '15px'
                }).
                append(inputContent).
                insertAfter($('#edit-buttons'));
            $('#pljumpbutton').click(function () {
                decodeLink($('#pljumpinput').val());
                moveToPL(true);
            });
            
            // Create the tab for possible future use (history!)
            tab = new wLib.Interface.Tab('PLJump', tabContent, function () { });

            W.model.events.register('mergestart', null, function () {
                dataMerged = false;
            });
            W.model.events.register('mergeend', null, function () {
                dataMerged = true;
            });
        }
    }

    /**
     * Extracts location and object data from a WME permalink. Puts the values 
     * in decodedLink.
     * @param {String} link A string containing the link to decode.
     */
    function decodeLink(link) {
        var lat, lon, nodes, segments, updateRequest, venues, zoom;

        lat = link.match(/lat=(-?\d+\.\d+)/);
        lon = link.match(/lon=(-?\d+\.\d+)/);
        nodes = link.match(/nodes=((\d+,?)+)+/);
        segments = link.match(/segments=((\d+,?)+)+/);
        updateRequest = link.match(/mapUpdateRequest=(\d+)/);
        venues = link.match(/venues=((\d+\.?)+)+/);
        zoom = link.match(/zoom=(\d+)/);

        decodedLink.lat = lat && lat.length === 2 ? parseFloat(lat[1]) : null;
        decodedLink.lon = lon && lon.length === 2 ? parseFloat(lon[1]) : null;
        decodedLink.segments = segments ? segments[1].split(',') : null;
        decodedLink.venues = venues ? venues[1].split(',') : null;
        decodedLink.nodes = nodes ? nodes[1].split(',') : null;
        decodedLink.updateRequest = updateRequest &&
            updateRequest.length === 2 ? updateRequest[1] : null;
        decodedLink.zoom = zoom ? zoom[1] : null;

        console.debug(decodedLink);
    }

    /**
     * Pans the map to the lat & lon location specified in the PL.
     * @param {Boolean} select Whether or not to also select objects in the PL.
     */
    function moveToPL(select) {
        var lonLat,
            zoom = decodedLink.zoom || W.map.getZoom();

        if (decodedLink.lon && decodedLink.lat) {
            lonLat = new OL.LonLat(decodedLink.lon, decodedLink.lat);
            lonLat.transform(
                W.map.displayProjection, W.map.getProjectionObject());
            if (select) {
                W.model.events.register('mergestart', null, selectFromPL);
            }
            W.map.moveTo(lonLat, zoom);
        }
    }
    
    /**
     * Selects objects exracted from the PL.
     */
    function selectFromPL() {
        var itemsToSelect = [],
            updateRequestObject;

        W.model.events.unregister('mergestart', null, selectFromPL);
        if (!dataMerged) {
            W.model.events.register('mergeend', null, selectFromPL);
            return;
        } else {
            W.model.events.unregister('mergend', null, selectFromPL);
        }

        if (decodedLink.updateRequest) {
            updateRequestObject = W.model.problems.get(
                decodedLink.updateRequest) || W.model.mapUpdateRequests.get(
                    decodedLink.updateRequest);
            if ('undefined' !== typeof updateRequestObject) {
                W.commands.execute('problems:show', updateRequestObject);
                return;
            }
        }
        if (decodedLink.segments) {
            _.each(decodedLink.segments, function (segment) {
                var segmentObject = W.model.segments.get(parseInt(segment));
                if (segmentObject) {
                    itemsToSelect.push(segmentObject);
                }
            });
        } else if (decodedLink.nodes) {
            _.each(decodedLink.nodes, function (node) {
                var nodeObject = W.model.nodes.get(parseInt(node));
                if (nodeObject) {
                    itemsToSelect.push(nodeObject);
                }
            });
        } else if (decodedLink.venues) {
            _.each(decodedLink.venues, function (venue) {
                var venueObject = W.model.venues.get(venue);
                if (venueObject) {
                    itemsToSelect.push(venueObject);
                }
            });
        }

        if (itemsToSelect.length > 0) {
            W.selectionManager.select(itemsToSelect);
        }
    }

    bootstrap();
} ());