/* global wLib */
/* global W */
/* global $ */
/* global jQuery */
/* global OL */
// ==UserScript==
// @name WME Show Alt Names
// @description Shows alt names for selected segments
// @version 0.40
// @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?version=52323
// ==/UserScript==
var altLayer, $altDiv, betaEditor, highlightLayer, $altTable,
nameArray = [], alternateObjectsArray = [], selectedSegments = [];
/**
* Returns a random color in rgba() notation.
* @param {Number} opacity The desirected opacity (a value of the color).
* returns {String} The rgba() color.
*/
function randomRgbaColor(opacity) {
opacity = opacity || 0.8;
function random255() {
return Math.floor(Math.random() * 255);
}
return 'rgba(' + random255() + ',' + random255() + ',' + random255() + ',' + opacity + ')';
}
/**
* Resets the renderIntent of all features on altLayer.
* @param {String} intent Optional parameter specifying the intent. The default
* parameter is 'default'.
*/
function resetRenderIntent(intent) {
var i, n;
intent = intent || 'default';
for (i = 0, n = altLayer.features.length; i < n; i++) {
altLayer.features[i].renderIntent = intent;
}
}
/**
* Pans the map to a segment specified by its ID.
* @param {Number} id The ID of the segment.
*/
function panToSegment(id) {
var segment = id && W.model.segments.get(id);
return segment && W.map.moveTo(segment.geometry.getBounds().getCenterLonLat());
}
/**
* Selects a segment specified by its ID.
* @param {Number} id The ID of the segment.
*/
function selectSegment(id) {
var seg = id && W.model.segments.get(id);
return seg && W.selectionManager.select([seg]);
}
/** Event handler for changing the highlight color for a segment.
* @param {Event} event
*/
function changeHighlightColor(event) {
var i, n, $this = $(this);
for (i = 0, n = nameArray.length; i < n; i++) {
if (nameArray[i].name === $this.text()) {
nameArray[i].color = randomRgbaColor();
colorTable();
$this.trigger('mouseenter', { singleSegment: false });
break;
}
}
}
/**
* Lookup function for the display color of a specified road type. Will return
* the color for the experimental layer if it is activated, otherwise it will
* return the color for the old roads layer.
* @param {Number} type The roadType to look up.
* @returns {Object} Object of form {typeString: 'RoadTypeName', typeColor: '#FFFFFF'},
* where RoadTypeName is an abbreviated form of the name of the road type and the type
* color is the hex value of the display color.
*/
function getRoadColor(type) {
var roadTypes = {
1: { name: 'St', color: '#FFFFFF', expColor: '#FFFFDD' },
2: { name: 'PS', color: '#CBA12E', expColor: '#FDFAA7' },
3: { name: 'Fwy', color: '#387FB8', expColor: '#6870C3' },
4: { name: 'Rmp', color: '#8FB838', expColor: '#B3BFB3' },
5: { name: 'Trl', color: '#E6E6E6', expColor: '#B0A790' },
6: { name: 'MH', color: '#C13040', expColor: '#469FBB' },
7: { name: 'mH', color: '#ECE589', expColor: '#69BF88' },
8: { name: 'Dirt', color: '#E6E6E6', expColor: '#867342' },
10: { name: 'Bdwk', color: '#E6E6E6', expColor: '#9A9A9A' },
16: { name: 'Stwy', color: '#E6E6E6', expColor: '#9A9A9A' },
17: { name: 'Pvt', color: '#E6E6E6', expColor: '#BEBA6C' },
18: { name: 'RR', color: '#E6E6E6', expColor: '#B2B6B4' },
19: { name: 'Rwy', color: '#E6E6E6', expColor: '#222222' },
20: { name: 'PLR', color: '#E6E6E6', expColor: '#ABABAB' }
//add ferry
},
roadExpName = betaEditor ? 'Roads' : 'Roads experimental',
roadsExpLayerVisible = W.map.getLayersByName(roadExpName)[0].getVisibility();
if (type && undefined !== typeof roadTypes[type]) {
return {
typeString: roadTypes[type].name,
typeColor: roadsExpLayerVisible ? roadTypes[type].expColor : roadTypes[type].color
};
} else {
return { typeString: 'error', typeColor: roadTypes[1] };
}
}
/**
* Data structure for segment information used to build highlight layer features and
* the alternate names table.
* @class
* @param {Waze.Feature.Vector.Segment} The segment feature on which to base the new instance.
*/
function Alternate(baseFeature) {
var i, n, street, city;
if (!baseFeature) {
return;
}
this.attributes = baseFeature.model.attributes;
this.segmentID = this.attributes.id;
// Make a feature for highlighting on the map.
this.layerFeature = new OL.Feature.Vector(baseFeature.geometry.clone(), this.attributes);
// Store segment name information.
street = W.model.streets.get(this.attributes.primaryStreetID);
city = street && W.model.cities.get(street.cityID);
this.primaryName = street ? street.name || 'No name' : 'error';
this.primaryCity = city ? city.name || 'No city' : 'error';
this.alternates = [];
for (i = 0, n = this.attributes.streetIDs.length; i < n; i++) {
street = W.model.streets.get(this.attributes.streetIDs[i]);
city = street && W.model.cities.get(street.cityID);
this.alternates.push({
name: street ? street.name || 'No name' : 'error',
city: city ? city.name || 'No city' : 'error'
});
}
// Make a table row for displaying segment data.
this.tableRow = this.createTableRow();
// Add name info to attributes of layer feature and add the feature to the layer.
// (For compatibility with highlighting functions--old method)
this.layerFeature.attributes.alt = this.alternates;
this.layerFeature.attributes.primary = { name: this.primaryName, city: this.primaryCity };
}
Alternate.prototype = /** @lends Alternate.prototype */ {
createTableRow: function () {
var i, n, $row, $cell, roadType;
$row = $('<tr/>').attr('id', 'alt' + this.segmentID);
//add road type to row
roadType = getRoadColor(this.layerFeature.attributes.roadType);
$cell = $('<td/>')
.css('border-right', 'none')
.append($('<div/>')
.addClass('altTable-roadType')
.css('background-color', roadType.typeColor)
.text(roadType.typeString))
.append($('<div/>')
.css({ 'text-align': 'center', 'font-size': '0.8em' })
.text(this.layerFeature.attributes.length + ' m')
);
$row.append($cell);
//add id to row
$cell = $('<td/>')
.addClass('altTable-id').css('border-left', 'none')
.append($('<div/>')
.text(this.segmentID));
$row.append($cell);
//add primary name and city to row
$cell = $('<td/>').addClass('altTable-primary')
.append($('<div/>')
.addClass('altTable-primary-name')
.text(this.primaryName))
.append($('<div/>')
.addClass('altTable-primary-city')
.text(this.primaryCity)
);
$row.append($cell);
//add alt names and cities to row
for (i = 0, n = this.alternates.length; i < n; i++) {
$cell = $('<td/>').addClass('altTable-alt')
.append($('<div/>').addClass('altTable-alt-name').text(this.alternates[i].name))
.append($('<div/>').addClass('altTable-alt-city').text(this.alternates[i].city)
);
$row.append($cell);
}
return $row;
}
};
/**
* Colors the table cells based on segment/city name.
*/
function colorTable() {
'use strict';
var i,
n,
$table = $('#altTable');
$table.find('.altTable-primary, .altTable-alt').each(function (index1) {
var $this = $(this),
text = $this.text(),
match = false,
color;
for (i = 0, n = nameArray.length; i < n; i++) {
if (nameArray[i].name === text) {
$this.css('background-color', nameArray[i].color);
match = true;
break;
}
}
if (match === false) {
color = randomRgbaColor();
$this.css('background-color', color);
nameArray.push({ name: text, color: color });
}
match = false;
});
}
/**
* Populates the table with segment information
* @param {Number} maxAlternates The maxiumum number of alternates
* @param {Boolean} sortByNode Whether to sort the table in driving
* order by node ID.
* a segment has (how many "Alt" columns are needed).
*/
function populateTable(maxAlternates, sortByNode) {
'use strict';
var i, n, j, m, $row;
// Empty table contents.
$altTable.find('tbody').empty();
$('.altTable-header-alt').remove();
// Sort if needed.
if (sortByNode) {
sortSegmentsByNode();
}
// Add table rows for each segment.
for (i = 0, n = selectedSegments.length; i < n; i++) {
$row = selectedSegments[i].tableRow.clone();
for (j = selectedSegments[i].alternates.length, m = maxAlternates; j < m; j++) {
$row.append($('<td/>').addClass('altTable-placeholder'));
}
$altTable.append($row);
}
// Add column headings for alt names.
for (i = 1, n = maxAlternates; i <= n; i++) {
$('#altTable-header').append($('<th/>')
.addClass('altTable-header-alt')
.text('Alt ' + i));
}
colorTable();
}
/**
* Callback for hovering over segment name in the table that
* colors all features on the altLayer with the same name/city as the
* one being hovered over.
* @callback
* @param {String} nameToMatch The name/city combination to match.
* @param {String} color The rgba-formatted color value.
*/
function colorFeatures(nameToMatch, color) {
'use strict';
var i,
n,
j,
t,
colorValues,
feature,
names,
nameCityCombined;
//remove opacity from color so it can be controlled by layer style
colorValues = color.match(/\d+/g);
color = 'rgb(' + colorValues[0] + ',' + colorValues[1] + ',' + colorValues[2] + ')';
for (i = 0, n = altLayer.features.length; i < n; i++) {
feature = altLayer.features[i];
//combine primary and alt names in one array
names = feature.attributes.alt.concat(feature.attributes.primary);
//test names for match
for (j = 0, t = names.length; j < t; j++) {
//combine street and city name (as in text of table cell)
nameCityCombined = names[j].name + names[j].city;
if (nameCityCombined === nameToMatch) {
feature.attributes.bgColor = color;
feature.renderIntent = 'highlight';
}
}
}
}
/**
* Callback for hovering over a segment ID in the table. Highlights the corresponding
* altLayer feature black or as specified.
* @callback
* @param {Number} id The segment ID to highlight.
* @param {String} color The rgba-formatted color (optional--default is black).
*/
function colorSegment(id, color) {
'use strict';
var i, n, feature;
color = color || 'rgba(0, 0, 0, 0.8)';
for (i = 0, n = altLayer.features.length; i < n; i++) {
feature = altLayer.features[i];
if (feature.attributes.id == id) {
feature.attributes.bgColor = color;
feature.renderIntent = 'highlight';
break;
}
}
}
/**
* Handles table events for hovering and calls appropriate function
* for highlighting.
* @callback
* @param {Event} event The event object.
*/
function applyHighlighting(event) {
var $this1;
switch (event.type) {
case 'mouseenter':
$this1 = $(this);
if (event.data.singleSegment) {
colorSegment($this1.text());
} else {
colorFeatures($this1.text(), $this1.css('background-color'));
}
$('#altTable tbody td').each(function (index) {
var $this2 = $(this);
if ($this1.text() === $this2.text()) {
$this2.parent().addClass('altTable-selected');
}
});
break;
case 'mouseleave':
resetRenderIntent();
$('#altTable tr').each(function (index) {
$(this).removeClass('altTable-selected');
});
break;
}
altLayer.redraw();
}
/**
* Event handler for selection events. Checks for appropriate condions
* for running script, creates Alternate objects as necessary, displays/hides
* UI elements.
* @callback
*/
function checkSelection() {
var i, n, j, m, alternate, thisItem, maxAlternates = 0, selectedItems;
selectedSegments = [];
$('#altAutoSelect').hide();
if (W.selectionManager.hasSelectedItems() && altLayer.getVisibility()) {
selectedItems = W.selectionManager.selectedItems;
if (selectedItems.length > 1) {
$('#altAutoSelect').show();
}
for (i = 0, n = selectedItems.length; i < n; i++) {
thisItem = selectedItems[i];
if (thisItem.model.type === 'segment') {
for (j = 0, m = alternateObjectsArray.length; j < m; j++) {
if (alternateObjectsArray[j].segmentID === thisItem.model.attributes.id) {
if (alternateObjectsArray[j].layerFeature.attributes.updatedOn !==
thisItem.model.attributes.updatedOn) {
alternateObjectsArray.splice(j, 1);
} else {
alternate = alternateObjectsArray[j];
continue;
}
}
}
if (!alternate) {
alternate = new Alternate(thisItem);
alternateObjectsArray.push(alternate);
}
selectedSegments.push(alternate);
altLayer.addFeatures(alternate.layerFeature);
if (maxAlternates < alternate.alternates.length) {
maxAlternates = alternate.alternates.length;
selectedSegments.maxAlternates = maxAlternates;
}
alternate = null;
}
}
populateTable(maxAlternates, $('#altSortByNode').prop('checked'));
$altDiv.fadeIn();
} else {
$altDiv.fadeOut();
altLayer.removeAllFeatures();
if (alternateObjectsArray.length > 50) {
alternateObjectsArray = [];
}
}
}
/**
* Checks all segments in WME for alt names and adds feature for
* highlighting.
*/
function checkAllSegments() {
'use strict';
var segID, segment;
highlightLayer.removeAllFeatures();
if (altLayer.getVisibility() && $('#altHighlights').prop('checked')) {
for (segID in W.model.segments.objects) {
segment = W.model.segments.objects[segID];
if (W.model.segments.objects.hasOwnProperty(segID) &&
segment.attributes.streetIDs.length > 0) {
highlightLayer.addFeatures(new OL.Feature.Vector(segment.geometry.clone()));
}
}
}
}
/**
* Sorts the selected segments in "driving order" starting with first selected based on Node ID.
*/
function sortSegmentsByNode() {
'use strict';
var reversedSegments = W.selectionManager.getReversedSegments();
// Check each selected segment to see if it is reversed
selectedSegments.forEach(function (item, index, array) {
item.reversed = reversedSegments[item.segmentID];
});
// Sort the segments in place based on the connecting node IDs.
selectedSegments.sort(function (segment1, segment2) {
if (segment1 === selectedSegments[0]) {
if (segment1.attributes.toNodeID === (segment2.reversed ?
segment2.attributes.toNodeID : segment2.attributes.fromNodeID) ||
segment1.attributes.fromNodeID === (segment2.reversed ?
segment2.attributes.fromNodeID : segment2.attributes.toNodeID)) {
return -1;
} else {
return 0;
}
} else if ((segment1.reversed ? segment1.attributes.fromNodeID : segment1.attributes.toNodeID) ===
(segment2.reversed ? segment2.attributes.toNodeID : segment2.attributes.fromNodeID)) {
return -1;
}
return 1;
});
}
/**
* Uses wLib to fetch route from routing server based on selected segments then
* attempts to select the route segments.
*/
function performAutoSelect() {
'use strict';
var i,
options,
route,
segmentsToSelect = [],
selection = W.selectionManager.selectedItems,
n = selection.length;
/**
* Callback for the route selection utility. Gets the segment IDs of
* segments on the route, checks to see if they are loaded in WME and
* pushes them to array for selection later.
* @callback
*/
function routeCallback() {
var segIDs, seg;
segIDs = this.getRouteSegmentIDs()[0];
segIDs.forEach(function (item) {
seg = W.model.segments.get(item);
if (seg) {
segmentsToSelect.push(seg);
}
});
if (this.last) {
W.selectionManager.select(segmentsToSelect);
}
}
/**
* Fetches the route (or sub-route) via wLib.
* @param {OpenLayers.Feature.Vector} start The starting segment of the sub-route.
* @param {OpenLayers.Feature.Vector} end The ending segment of the sub-route.
* @param {Boolean} last Whether the sub-route is the last of the total route.
* @param {Number} The timeout before fetching the route in milliseconds.
*/
function fetchRoute(start, end, last, timeout) {
window.setTimeout(function () {
route = new wLib.Model.RouteSelection(start, end, routeCallback, options);
route.last = last ? true : false;
}, timeout);
}
if (n > 0) {
options = {
fastest: $('#altFastest').prop('checked'),
tolls: $('#altAvoidTolls').prop('checked'),
freeways: $('#altAvoidFreeways').prop('checked'),
dirt: $('#altAvoidDirt').prop('checked'),
longtrails: $('#altAvoidLongDirt').prop('checked'),
uturns: $('#altAllowUturns').prop('checked')
};
for (i = 0; i < n - 1; i++) {
if ('segment' === selection[i].model.type && 'segment' === selection[i + 1].model.type) {
fetchRoute(selection[i], selection[i + 1], i === n - 2 ? true : false, 500 * i);
}
}
}
}
/**
* Saves checkbox states to localStorage.
*/
function saveOptions(event) {
'use strict';
var options = options = {
fastest: $('#altFastest').prop('checked'),
tolls: $('#altAvoidTolls').prop('checked'),
freeways: $('#altAvoidFreeways').prop('checked'),
dirt: $('#altAvoidDirt').prop('checked'),
longtrails: $('#altAvoidLongDirt').prop('checked'),
uturns: $('#altAllowUturns').prop('checked'),
highlights: $('#altHighlights').prop('checked'),
sortByNode: $('#altSortByNode').prop('checked')
};
return window.localStorage.altNamesOptions = JSON.stringify(options);
}
/**
* Loads checkbox states from localStorage.
*/
function loadOptions() {
'use strict';
var options;
if (undefined !== typeof window.localStorage.altNamesOptions) {
options = JSON.parse(window.localStorage.altNamesOptions);
if (undefined !== typeof options.fastest) {
$('#altFastest').prop('checked', options.fastest);
}
if (undefined !== typeof options.tolls) {
$('#altAvoidTolls').prop('checked', options.tolls);
}
if (undefined !== typeof options.freeways) {
$('#altAvoidFreeways').prop('checked', options.freeways);
}
if (undefined !== typeof options.dirt) {
$('#altAvoidDirt').prop('checked', options.dirt);
}
if (undefined !== typeof options.longrails) {
$('#altAvoidDirt').prop('checked', options.longtrails);
}
if (undefined !== typeof options.uturns) {
$('#altAllowUturns').prop('checked', options.uturns);
}
if (undefined !== typeof options.highlights) {
$('#altHighlights').prop('checked', options.highlights);
}
if (undefined !== typeof options.sortByNode) {
$('#altSortByNode').prop('checked', options.sortByNode);
}
}
}
/**
* Shows alert box with version information and changes.
*/
function updateAlert() {
var altVersion = "0.40",
alertOnUpdate = true,
versionChanges = 'WME Show Alt Names has been updated to ' + altVersion + '.\n';
versionChanges += 'Changes:\n';
versionChanges += '[*]New feature: Highlighting for all segments with altnerate names.\n';
versionChanges += '[*]New feature: Table sorting by "driving order."\n';
versionChanges += '[*]New feature: User-selected options are saved across browser sessions.\n';
if (alertOnUpdate && window.localStorage && window.localStorage.altVersion !== altVersion) {
window.localStorage.altVersion = altVersion;
alert(versionChanges);
}
}
/**
* Initializes the script by adding CSS and HTML to page, registering event listeners,
* adding map layers, checking for beta editor, and running main functions to check for
* segments loaded at init and highlighting.
*/
function init() {
var altStyleMap, css, $header, highlightStyle, optionsHTML, $row;
css = '#altTable {width: 100%;}';
css += '.altTable, .altTable th, .altTable td {border: 1px solid white; padding: 3px; border-collapse: collapse; -moz-user-select: -moz-none; -khtml-user-select: none; -webkit-user-select: none;}\n';
css += '.altTable-id {text-align: center; border-left: none;}\n';
css += '.altTable-roadType {border-radius: 10px; color: black; text-shadow: 1px 1px 0 #fff,-1px -1px 0 #fff,1px -1px 0 #fff,-1px 1px 0 #fff,0px 1px 0 #fff,1px 0px 0 #fff,0px -1px 0 #fff,-1px 0px 0 #fff; border: 1px solid white; font-size: 0.8em; text-align: center; padding: 0 3px 0 3px; min-width: 32px;}';
css += 'tr.altTable-selected > .altTable-id {font-weight: bold; background-color: white; color: black;}\n';
css += '#altDiv {display: none; position: absolute; left: 6px; bottom: 60px; height: auto; width: auto; ';
css += 'overflow-y: scroll; overflow-x: hidden; white-space: nowrap; background-color: rgba(0,0,0,0.8); color: white; padding: 5px; ';
css += 'z-index: 1001; border-radius: 5px; max-height: 50%;}\n';
// scroll bar CSS
css += '#altDiv::-webkit-scrollbar {width: 15px; border-radius: 5px;}\n';
css += '#altDiv::-webkit-scrollbar-track {border-radius: 5px; background: none; width: 10px;}\n';
css += '#altDiv::-webkit-scrollbar-thumb {background-color: white; border-radius: 5px; border: 2px solid black;}\n';
css += '#altDiv::-webkit-scrollbar-corner {background: none;}\n';
// buttons css
css += '.altOptions-button {margin: 0 0 3px 3px; height: 2em; font-size: 0.8em;}\n';
// Options Menu CSS
css += '#optionsDiv {display: none; clear: both; border: 1px solid white; padding: 3px; margin: 0 0 3px 0; font-weight: normal;}';
css += '#optionsDiv td {padding-right: 5px;}';
css += '#optionsDiv input {margin-right: 3px;}';
//add css to page
$('<style/>').html(css).appendTo($(document.head));
// Make the options menu.
optionsHTML = '<div id="altOptions"> <button id="altAutoSelect" class="altOptions-button" style="display: none;">Auto Select</button> <label style="float: right; margin: 3px;"><input id="altHighlights" type="checkbox">Highlight Alt Names</label> <button id="altOptionsButton" class="altOptions-button" style="float: right;">Show Options</button> </div> <div id="optionsDiv"> <label style="font-weight: normal;"><input type="checkbox" id="altSortByNode">Sort table by driving order</label> <form> <table> <thead> <tr> <td colspan="2" style="text-align: center; text-decoration: underline; font-weight: bold;">Auto Selection Route Options</td> </tr> </thead> <tbody> <tr> <td> <input type="checkbox" id="altAvoidTolls">Avoid toll roads</td> <td> <input type="checkbox" id="altAvoidFreeways">Avoid freeways</td> </tr> <tr> <td> <input type="checkbox" id="altAvoidLongDirt">Avoid long dirt roads</td> <td> <input type="checkbox" id="altAvoidDirt">Avoid dirt roads</td> </tr> <tr> <td> <input type="checkbox" id="altAllowUturns">Allow U-turns</td> <td> <input type="checkbox" id="altFastest">Fastest route</td> </tr> </tbody> </table> </form> </div>';
// Make the table to hold segment information.
$altTable = $('<table/>').attr('id', 'altTable').addClass('altTable');
$header = $('<thead/>');
$row = $('<tr/>').attr('id', 'altTable-header');
$row.append($('<th/>').attr('colspan', '2').text('Segment ID'));
$row.append($('<th/>').text('Primary'));
$header.append($row);
$altTable.append($header);
$altTable.append('<tbody/>');
// Make the main div to hold script content.
$altDiv = $('<div/>').attr('id', 'altDiv');
$altDiv.append(optionsHTML);
$altDiv.append($altTable);
$altDiv.appendTo($('#WazeMap'));
$('#altAutoSelect').click(performAutoSelect);
$('#altOptionsButton').click(function () {
var $optionsDiv = $('#optionsDiv');
if ($optionsDiv.css('display') === 'none') {
$optionsDiv.show();
$(this).text('Hide Options');
} else {
$optionsDiv.hide();
$(this).text('Show Options');
}
});
$('#altSortByNode').on('change', checkSelection);
$('#altHighlights').on('change', checkAllSegments);
$('#optionsDiv input[type=checkbox], #altOptions input[type=checkbox]').on('change', saveOptions);
$altDiv.on('mouseenter mouseleave', 'td.altTable-primary, td.altTable-alt', { singleSegment: false }, applyHighlighting);
$altDiv.on('dblclick', 'td.altTable-primary, td.altTable-alt', null, changeHighlightColor);
$altDiv.on('mouseenter mouseleave', 'td.altTable-id', { singleSegment: true }, applyHighlighting);
$altDiv.on('click', 'td.altTable-id', null, function () {
panToSegment($(this).text());
});
$altDiv.on('dblclick', 'td.altTable-id', null, function () {
selectSegment($(this).text());
});
// Create the map layers for segment highlighting.
altStyleMap = new OL.StyleMap({
default: new OL.Style({
stroke: false
}),
highlight: new OL.Style({
stroke: true,
strokeWidth: 20,
strokeColor: '${bgColor}',
strokeOpacity: 1,
strokeLinecap: 'round'
})
});
altLayer = new OL.Layer.Vector('WME Show Alt Names', { styleMap: altStyleMap });
altLayer.events.register('visibilitychanged', null, checkSelection);
highlightStyle = new OL.StyleMap({
default: new OL.Style({
strokeWidth: 20,
strokeColor: '#3399FF',
strokeOpacity: 0.6
})
});
highlightLayer = new OL.Layer.Vector('WME Show Alt Names - Highlight All', {
styleMap: highlightStyle,
displayInLayerSwitcher: false
});
W.map.addLayers([highlightLayer, altLayer]);
//check for beta editor due to road layer name differences
if (location.href.match(/-beta/)) {
betaEditor = true;
}
//register WME event listeners
W.loginManager.events.register('afterloginchanged', null, init);
W.selectionManager.events.register('selectionchanged', null, checkSelection);
W.map.events.register('moveend', null, checkAllSegments);
W.map.getLayersByName('Roads')[0].events.register('visibilitychanged', null, checkSelection);
if (betaEditor) {
W.map.getLayersByName('Roads (old)')[0].events.register('visibilitychanged', null, checkSelection);
} else {
W.map.getLayersByName('Roads experimental')[0].events.register('visibilitychanged', null, checkSelection);
}
// Ready to go. Alert user to any updates and check for selected segments.
updateAlert();
loadOptions();
checkAllSegments();
checkSelection();
}
/**
* Checks for key components of the page before initializing the script.
*/
function bootstrap() {
var bGreasemonkeyServiceDefined = false;
try {
if ("object" === typeof Components.interfaces.gmIGreasemonkeyService) {
bGreasemonkeyServiceDefined = true;
}
} catch (err) {
/* Ignore. */
}
if (undefined === typeof unsafeWindow || !bGreasemonkeyServiceDefined) {
unsafeWindow = (function () {
var dummyElem = document.createElement('p');
dummyElem.setAttribute('onclick', 'return window;');
return dummyElem.onclick();
})();
}
/* begin running the code! */
if (undefined !== typeof $ &&
$('#WazeMap').length !== 0 &&
undefined !== typeof W.selectionManager.events.register &&
undefined !== typeof W.loginManager.events.register) {
window.setTimeout(init, 100);
} else {
window.setTimeout(function () {
bootstrap();
}, 1000);
}
}
window.setTimeout(bootstrap, 100);