Starting your script - WazeDev/WazeDev.github.io GitHub Wiki

When creating user scripts for the Waze Map Editor (WME) you must either create a browser extension or a user script to install through Greasemonkey or Tampermonkey. Tampermonkey is the recommended user script extension due to some recent changes in how Greasemonkey functions.

We will focus on scripts that install through Tampermonkey for this topic: creating browser extensions is similar to scripts but it is not the same and thus a different topic. We will create a simple script in order to demonstrate the basics and start exploring the Waze object.

Tampermonkey scripts must all include a header before the body of the script. Below is the default header that Tampermonkey uses when you create a script through the Tampermonkey editor.

// ==UserScript==
// @name         New Userscript
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        http://*/*
// @grant        none
// ==/UserScript==

This is where you will give your script a name, set the namespace (your greasyfork profile link, typically. This is necessary so the script can update automatically), current version, description, set the author and you declare what pages the script is allowed to run on.

Below is what this looks like in practice.

// ==UserScript==
// @name         WME Wazebar
// @namespace    https://greasyfork.org/users/30701-justins83-waze
// @version      2017.11.24.01
// @description  Displays a bar at the top of the editor that displays inbox, forum & wiki links
// @author       JustinS83
// @include      https://beta.waze.com/*
// @include      https://www.waze.com/forum/*
// @include      https://webnew.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/27023-jscolor/code/JSColor.js
// @connect      status.waze.com
// @grant        GM_xmlhttpRequest
// ==/UserScript==

You can see that it has been allowed to run on multiple waze pages (@include lines) and is forbidden to run on the Waze user profile page (the @exclude) line. It is good practice to @exclude any pages that might be matched by an @include but you do not want the script to run on - otherwise it could cause issues with those pages. It is possible to use regex to create the @include string, and some scripts do this. I prefer the above method because it is easier to read, especially for new scripters.

For our initial script we will use the header below

// ==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/editor*
// @include      https://www.waze.com/*/editor*
// @exclude      https://www.waze.com/user/editor*
// @grant        none
// ==/UserScript==

Our header will let our script run in both production and beta WME, and prevent it from loading on the editor profile page.

Below the header you will have the body of your script. On a new script created in Tampermonkey it will look like below:

(function() {
    'use strict';

    // Your code here...
})();

This is where you write your script. How you write your script is completely up to you and what you wish to accomplish but one thing will always be necessary: a bootstrap. A bootstrap is necessary to make sure the required page/WME elements have loaded before your script starts executing. If the script starts executing before all necessary elements are loaded it is liable to error and stop working.

Bootstrap example:

function bootstrap(tries = 1) {
    if (W && W.map &&
	    W.model && W.loginManager.user &&
	    $ &&
	    W.model.states.top &&
	    window.jscolor &&
	    $('.app.container-fluid.show-sidebar').length > 0) {
	        preinit();
    } else if (tries < 1000)
	    setTimeout(function () {bootstrap(++tries);}, 200);
}

What the above bootstrap does is checks that the Waze object (W), W.map, W.model, W.loginManger.user, etc. have been instantiated (they are not null). If all of these checks pass, meaning everything exists and is set, the preinit() method is called (the preinit method in this case, you can name yours however you want and have it do whatever you want, would then proceed to set up the script and load/create the interface or tab the script uses and load any settings from localStorage). If they are not set, the script pauses for 200ms and tries again. Checking if one of the objects is set isn't the only thing you can do - as seen in the above bootstrap, we check if a control with classes of ".app.container-fluid.show-sidebar" exists. If you are interacting with the WME interface it is a good idea to add checks in like this one to make sure the element you are wanting to read/modify has been created, before attempting to use it. If the control(s) that you are going to interact with do not exist immediately in the interface (maybe a button needs to be clicked before they would show), then you will need to use another method to ensure they exist before attempting to interact with them.

At the end of the script you will call the bootstrap method and that will start your script.

For our script we will use a simplier bootstrap:

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

Our boot strap will ensure that the Waze objects that we will be referencing are available and that jQuery has loaded. Once that is done it will call our init method, which we will start developing in the next section.

Our test script should look like this now:

// ==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*
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

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

    function init()
    {
        
    }

    bootstrap();
})();

This covers the very basics for getting started on a script. In the next section we will look at setting up a tab in the side panel where our script can create controls to toggle settings, using the utility library WazeWrap.