Interacting with W - WazeDev/WazeDev.github.io GitHub Wiki

Now that we have our tab set up we will start interacting with the Waze object. You can experiment with this by going to the console (F12) and typing W.. This will bring up a list of all the objects available from W. Since we are checking for W.loginManager.user in our bootstrap, lets pull some information from it and use jQuery to display it in our tab.

First, lets take a look at what information is available from W.loginManager.user by running that in the console.

As you can see, most of the information isn't too useful for us in terms of creating a WME script - the important bits are already displayed in the top of the side panel (username, points and edit count). Lets recreate this and add a little more information.

First, we are going to need to change our tab so we have a space to add this information.

var $section = $("<div>");
        $section.html([
            '<div>',
            '<h2>Our First Script!</h2>',
            '<hr>',
            '<div>',
            '<h3>User Info</h3>',
            'Username: <span id="wazedevUsername"></span></br>',
            'Rank: <span id="wazedevRank"></span></br>',
            'Total edits: <span id="wazedevTotalEdits"></span></br>',
            'Total points: <span id="wazedevTotalPoints"></span></br>',
            'Area manager: <span id="wazedevAM"></span></br>',
            'Editable areas: <span id="wazedevEditableAreas"></span>',
            '</div>',
            '</div>'
        ].join(' '));

We are adding spans so we can easily dynamically add the values from W.loginManager.user and we give them all unique IDs. I like to use the script name (or abbreviation) + a recognizable name for what it is. This serves two purposes:

  1. It guarantees the ID we use will be unique (don't want to risk stepping on any other script's toes)
  2. If someone wants to see what script is modifying/adding the information, you can see this in the ID of the element.

So, in order to set these values we need to change our intializeSettings method. This is the method that gets called once the tab has been created in the side panel, by WazeWrap. We'll change our initializeSettings method to the below in order to fill in the information above.

function initializeSettings()
    {
        $('#wazedevUsername').text(W.loginManager.user.userName);
        $('#wazedevRank').text(W.loginManager.user.rank + 1);
        $('#wazedevTotalEdits').text(W.loginManager.user.totalEdits);
        $('#wazedevTotalPoints').text(W.loginManager.user.totalPoints);
        $('#wazedevAM').text(W.loginManager.user.isAreaManager);
        $('#wazedevEditableAreas').text(W.loginManager.user.areas.length);
    }

This is all pretty simple - this is just utilizing jQuery to do a lookup on the span IDs that we set in order to update the text with our user properties. Lets do something a little more complex - we will add an option to enable/disable the script (default it to off) and when enabled we will draw a red line on top of any selected segments and for Places it will draw on the border of the Place.

First, lets modify our tab to add the Enabled option. We will add this before our User Info section, as below. This will give a nice visual break from the enabled option to the rest of the script.

$section.html([
            '<div>',
            '<h2>Our First Script!</h2>',
            '<input type="checkbox" id="wazedevEnabled" class="wazedevSettingsCheckbox"><label for="wazedevEnabled">Enabled</label>',
            '<hr>',
            '<div>',
            '<h3>User Info</h3>',
            'Username: <span id="wazedevUsername"></span></br>',
            'Rank: <span id="wazedevRank"></span></br>',
            'Total edits: <span id="wazedevTotalEdits"></span></br>',
            'Total points: <span id="wazedevTotalPoints"></span></br>',
            'Area manager: <span id="wazedevAM"></span></br>',
            'Editable areas: <span id="wazedevEditableAreas"></span>',
            '</div>',
            '</div>'
        ].join(' '));

With adding this option we are going to want to add a save and load method so we can save this to the browser's localStorage and retrieve it into an object that we can use to check against in the script.

Lets start with the save method:

function saveSettings() {
        if (localStorage) {
            var localsettings = {
                Enabled: settings.Enabled
            };

            localStorage.setItem("wavedev_Settings", JSON.stringify(localsettings));
        }
    }

We create a saveSettings method and which defines a localsettings object which pulls the settings from a settings object defined globally in the script. Once the localsettings object's settings have been set, set the localStorage setting and change the localsettings object to JSON as a parameter to the setItem method. Your settings are now stored in localStorage in the browser. Now we need to handle the user enabling/disabling the Enabled checkebox and save it to our settings.

In order to detect when the user changes the Enabled setting, we will add a handler for the change event for the class we added to the checkbox, which we will do using jQuery. This will automagically pull the settings name from the id that we set (will strip off the first 7 characters since we prefaced it with "wazedev") and set the settings object to the current checkbox status and then save to localStorage. This will allow you to add multiple checkboxes with properly named id's and using the "wazedevSettingsCheckbox" class and have the setting be automatically detected and saved, without having to write code to do it for every checkbox.

$('.wazedevSettingsCheckbox').change(function() {
             var settingName = $(this)[0].id.substr(7);
            settings[settingName] = this.checked;
            saveSettings();
        });

This change handler should be added to the end of the initializeSettings method. Our initializeSettings method should now look like this:

function initializeSettings()
    {
        $('#wazedevUsername').text(W.loginManager.user.userName);
        $('#wazedevRank').text(W.loginManager.user.rank + 1);
        $('#wazedevTotalEdits').text(W.loginManager.user.totalEdits);
        $('#wazedevTotalPoints').text(W.loginManager.user.totalPoints);
        $('#wazedevAM').text(W.loginManager.user.isAreaManager);
        $('#wazedevEditableAreas').text(W.loginManager.user.areas.length);

        $('.wazedevSettingsCheckbox').change(function() {
             var settingName = $(this)[0].id.substr(7);
            settings[settingName] = this.checked;
            saveSettings();
        });
    }

Now that we have saving set up, lets get loading working. For this we will create a loadSettings method which will retrieve our script's settings from localStorage. To do this we will use jQuery's parseJSON method to parse our localStorage settings into an object that we can interact with. We will then set up an object with default settings, in case a storage object doesn't exist or we have added options to the script that do not exist locally. We will start with the script disabled, so the user doesn't experience strange behavior after installing/updating (usually a good practice, depending on what your script is doing). Once that is set up, the function will loop the settings object property and add any missing settings to our settings object that we will define globally in our script.

function loadSettings() {
        var loadedSettings = $.parseJSON(localStorage.getItem("wavedev_Settings"));
        var defaultSettings = {
            Enabled: false,
        };
        settings = loadedSettings ? loadedSettings : defaultSettings;
        for (var prop in defaultSettings) {
            if (!settings.hasOwnProperty(prop))
                settings[prop] = defaultSettings[prop];
        }

    }

This method should be called once our script's tab is added to the side bar, before set add any event handlers. To do this, we will call loadSettings at the start of the initializeSettings method and then set the Enabled checkbox based on the loaded settings. In order to set the checkbox state, we will create a helper method called setChecked which will make it easy to check/uncheck any checkboxes we use on the settings tab.

    function setChecked(checkboxId, checked) {
        $('#' + checkboxId).prop('checked', checked);
    }

We should also now declare our settings object at the top of our script

    var settings = {};

Our script should now look like this:

// ==UserScript==
// @name         WazeDev First Script
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Learning to script!
// @author       You
// @include      https://beta.waze.com/*
// @include      https://www.waze.com/forum/*
// @include      https://www.waze.com/editor*
// @include      https://www.waze.com/*/editor*
// @exclude      https://www.waze.com/user/editor*
// @require      https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    var settings = {};

    function bootstrap(tries = 1) {
        if (W && W.map &&
            W.model && W.loginManager.user &&
            $ && WazeWrap.Ready) {
            init();
        } else if (tries < 1000)
            setTimeout(function () {bootstrap(++tries);}, 200);
    }

    function init()
    {
        var $section = $("<div>");
        $section.html([
            '<div>',
            '<h2>Our First Script!</h2>',
            '<input type="checkbox" id="wazedevEnabled" class="wazedevSettingsCheckbox"><label for="wazedevEnabled">Enabled</label>',
            '<hr>',
            '<div>',
            '<h3>User Info</h3>',
            'Username: <span id="wazedevUsername"></span></br>',
            'Rank: <span id="wazedevRank"></span></br>',
            'Total edits: <span id="wazedevTotalEdits"></span></br>',
            'Total points: <span id="wazedevTotalPoints"></span></br>',
            'Area manager: <span id="wazedevAM"></span></br>',
            'Editable areas: <span id="wazedevEditableAreas"></span>',
            '</div>',
            '</div>'
        ].join(' '));

        new WazeWrap.Interface.Tab('WazeDev', $section.html(), initializeSettings);
    }

    function initializeSettings()
    {
        loadSettings();
        setChecked('wazedevEnabled', settings.Enabled);

        $('#wazedevUsername').text(W.loginManager.user.userName);
        $('#wazedevRank').text(W.loginManager.user.rank + 1);
        $('#wazedevTotalEdits').text(W.loginManager.user.totalEdits);
        $('#wazedevTotalPoints').text(W.loginManager.user.totalPoints);
        $('#wazedevAM').text(W.loginManager.user.isAreaManager);
        $('#wazedevEditableAreas').text(W.loginManager.user.areas.length);

        $('.wazedevSettingsCheckbox').change(function() {
             var settingName = $(this)[0].id.substr(7);
            settings[settingName] = this.checked;
            saveSettings();
        });
    }

    function setChecked(checkboxId, checked) {
        $('#' + checkboxId).prop('checked', checked);
    }

    function saveSettings() {
        if (localStorage) {
            var localsettings = {
                Enabled: settings.Enabled
            };

            localStorage.setItem("wavedev_Settings", JSON.stringify(localsettings));
        }
    }

    function loadSettings() {
        var loadedSettings = $.parseJSON(localStorage.getItem("wavedev_Settings"));
        var defaultSettings = {
            Enabled: false,
        };
        settings = loadedSettings ? loadedSettings : defaultSettings;
        for (var prop in defaultSettings) {
            if (!settings.hasOwnProperty(prop))
                settings[prop] = defaultSettings[prop];
        }

    }

    bootstrap();
})();

Our script is now saving & loading the Enabled setting! Hooray! In the next section we will add drawing of the lines when segments & Places are selected.

⚠️ **GitHub.com Fallback** ⚠️