WME Fix UI

Allows alterations to the WME UI to fix things screwed up or ignored by Waze

As of 22.01.2017. See ბოლო ვერსია.

// ==UserScript==
// @name                WME Fix UI
// @namespace           https://greasyfork.org/en/users/46070
// @description         Allows alterations to the WME UI to fix things screwed up or ignored by Waze
// @include             https://www.waze.com/*editor/*
// @include             https://editor-beta.waze.com/*
// @include             https://beta.waze.com/*
// @exclude             https://www.waze.com/*user/editor/*
// @supportURL          https://www.waze.com/forum/viewtopic.php?f=819&t=191178
// @version             1.7.2
// @grant               none
// ==/UserScript==

// Thanks to (in no particular order)
//    Bellhouse, Twister-UK, Timbones, Dave2084, Rickzabel, Glodenox,
//    JJohnston84, SAR85, Cardyin

(function()
{
// global variables
var wmefu_version = "1.7.2";
var oldVersion;
var prefix = "WMEFU";
var tabAttempts = 0;
var wmeFUAddon;
var debug = false;
var wmeFUinitialising = true;
//Fix for date/time formats in WME released Oct/Nov 2016 - provided by Glodenox
I18n.translations[I18n.currentLocale()].time = {};
I18n.translations[I18n.currentLocale()].time.formats = {};
I18n.translations[I18n.currentLocale()].time.formats.long = "%a %b %d %Y, %H:%M";
I18n.translations[I18n.currentLocale()].date.formats = {};
I18n.translations[I18n.currentLocale()].date.formats.long = "%a %b %d %Y, %H:%M";
I18n.translations[I18n.currentLocale()].date.formats.default = "%a %b %d %Y";
if (I18n.currentLocale() == 'en-GB') {
  I18n.translations['en-GB'].update_requests.panel.reported = 'Reported on: %{date}';
}
// Set the "Chat is here!" message to be hidden
if (localStorage.hiddenMessages) {
	var hm = JSON.parse(localStorage.hiddenMessages);
	if (hm.chat_intro_tip === false) {
		logit("Hiding Chat is Here! message","info");
		hm.chat_intro_tip = true;
		localStorage.setItem('hiddenMessages', JSON.stringify(hm));
	}
}

function init1() {
	console.group(prefix + ": initialising...");
	console.time(prefix + ": initialisation time");
	logit("Starting init1","debug");
	// go round again if map container isn't there yet
	if(!window.Waze.map) {
		logit("waiting for WME...","warning");
		setTimeout(init1, 200);
		return;
	}
	// create tab content and store it
	wmeFUAddon = createAddon();
	// insert the content as a tab
	addMyTab(null,0);
	//pass control to init2
	init2();
}

function init2() {
	logit("Starting init2","debug");
	//go round again if my tab isn't there yet
	if (!getId('sidepanel-FixUI')) {
		logit("Waiting for my tab to appear...","warning");
		setTimeout(init2, 200);
		return;
	}
	// setup event handlers for user actions:
	getId('_cbMoveZoomBar').onclick = moveZoomBar;
	getId('_cbShrinkTopBars').onclick = shrinkTopBars;
	getId('_cbHideUserInfo').onclick = hideUserInfo;
	getId('_cbCompressSegmentTab').onclick = compressSegmentTab;
	getId('_cbRestyleReports').onclick = restyleReports;
	getId('_cbDisableMapBlocker').onclick = disableMapBlocker;
	getId('_cbNarrowSidePanel').onclick = narrowSidePanel;
	getId('_cbHideAveSpeedControls').onclick = hideAveSpeedControls;
	getId('_cbAddZoomIndicator').onclick = addZoomIndicator;
	getId('_cbFixExternalProviders').onclick = fixExternalProviders;

	// set event to recreate my tab when MTE mode is exited
	Waze.app.modeController.model.bind('change:mode', addMyTab);
	// events for Aerial Shifter
	Waze.map.events.register("zoomend", null, shiftAerials);
	Waze.map.events.register("moveend", null, shiftAerials);
	Waze.map.baseLayer.events.register("loadend", null, shiftAerials);
	getId("_inpASX").onchange = shiftAerials;
	getId("_inpASX").onwheel = shiftAerials;
	getId("_inpASY").onchange = shiftAerials;
	getId("_inpASY").onwheel = shiftAerials;
	getId("_inpASO").onchange = shiftAerials;
	getId("_inpASO").onwheel = shiftAerials;
	getId("_resetAS").onclick = function() {
		 _inpASX.value = 0;
		 _inpASY.value = 0;
		 shiftAerials();
		};
	// events for GSV adjustment
	getId("_inpGSVContrast").onchange = adjustGSV;
	getId("_inpGSVBrightness").onchange = adjustGSV;
	getId("_cbGSVInvert").onchange = adjustGSV;
	// set event to deal with ASC controls
	Waze.selectionManager.events.register("selectionchanged", null, hideAveSpeedControls);
	// change menu bar color based on map comments checkbox
	Waze.map.events.register("zoomend", null, warnCommentsOff);
	Waze.map.events.register("moveend", null, warnCommentsOff);

	// restore saved settings
	if (localStorage.WMEFixUI) {
		logit("loading options from local storage");
		options = JSON.parse(localStorage.WMEFixUI);
		oldVersion = options[0];
		getId('_cbMoveZoomBar').checked = options[1];
		getId('_cbShrinkTopBars').checked = options[2];
		getId('_cbHideUserInfo').checked = options[3];
		getId('_cbCompressSegmentTab').checked = options[4];
		getId('_cbRestyleReports').checked = options[5];
		getId('_cbDisableMapBlocker').checked = options[6];
		getId('_cbNarrowSidePanel').checked = options[7];
		getId('_cbHideAveSpeedControls').checked = options[8];
		getId('_cbAddZoomIndicator').checked = options[9];
		if (typeof(options[10]) === "undefined") {
			//define sensible values for AS if none are stored
			logit("setting new AS values","debug");
			options[10] = 0;
			options[11] = 0;
			options[12] = 100;
		}
		getId('_inpASX').value = options[10];
		getId('_inpASY').value = options[11];
		getId('_inpASO').value = options[12];
		getId('_cbFixExternalProviders').checked = options[13];
		if (typeof(options[14]) === "undefined") {
			//define sensible values for GSV if none are stored
			logit("setting new GSV values","debug");
			options[14] = 100;
			options[15] = 100;
			options[16] = false;
		}
		getId('_inpGSVContrast').value = options[14];
		getId('_inpGSVBrightness').value = options[15];
		getId('_cbGSVInvert').checked = options[16];
	} else {
		// default values for first installation
		logit("no options in local storage - setting defaults");
		oldVersion = wmefu_version;
		getId('_cbMoveZoomBar').checked = true;
		getId('_cbShrinkTopBars').checked = true;
		getId('_cbHideUserInfo').checked = true;
		getId('_cbCompressSegmentTab').checked = true;
		getId('_cbRestyleReports').checked = true;
		getId('_cbDisableMapBlocker').checked = false;
		getId('_cbNarrowSidePanel').checked = false;
		getId('_cbHideAveSpeedControls').checked = false;
		getId('_cbAddZoomIndicator').checked = true;
		getId('_inpASX').value = 0;
		getId('_inpASY').value = 0;
		getId('_inpASO').value = 100;
		getId('_cbFixExternalProviders').checked = true;
		getId('_inpGSVContrast').value = 100;
		getId('_inpGSVBrightness').value = 100;
		getId('_cbGSVInvert').checked = false;
	}
	// Adds an extra checkbox so I can test segment panel changes easily
	if (Waze.loginManager.user.userName == 'iainhouse') {
		logit("creating segment detail debug checkbox","info");
		var brand = getId('brand');
		extraCBSection = document.createElement('p');
		extraCBSection.innerHTML = '<input type="checkbox" id="_cbextraCBSection" />';
		brand.appendChild(extraCBSection);
		getId('_cbextraCBSection').onclick = FALSEcompressSegmentTab;
		_cbextraCBSection.checked = _cbCompressSegmentTab.checked;
	}
	// overload the WME exit function to save my settings
	saveOptions = function() {
		if (localStorage) {
			logit("saving options to local storage");
			var options = [];
			// preserve previous options which may get lost after logout
			if (localStorage.WMEFixUI) { options = JSON.parse(localStorage.WMEFixUI); }
			options[0] = wmefu_version;
			options[1] = getId('_cbMoveZoomBar').checked;
			options[2] = getId('_cbShrinkTopBars').checked;
			options[3] = getId('_cbHideUserInfo').checked;
			options[4] = getId('_cbCompressSegmentTab').checked;
			options[5] = getId('_cbRestyleReports').checked;
			options[6] = getId('_cbDisableMapBlocker').checked;
			options[7] = getId('_cbNarrowSidePanel').checked;
			options[8] = getId('_cbHideAveSpeedControls').checked;
			options[9] = getId('_cbAddZoomIndicator').checked;
			options[10] = getId('_inpASX').value;
			options[11] = getId('_inpASY').value;
			options[12] = getId('_inpASO').value;
			options[13] = getId('_cbFixExternalProviders').checked;
			options[14] = getId('_inpGSVContrast').value;
			options[15] = getId('_inpGSVBrightness').value;
			options[16] = getId('_cbGSVInvert').checked;
			localStorage.WMEFixUI = JSON.stringify(options);
		}
	};
	window.addEventListener("beforeunload", saveOptions, false);

	// Alert to new version
	if (oldVersion != wmefu_version) {
		alert("WME Fix UI has been updated to version " + wmefu_version +
		"\n" +
		"\nVersion 1.7" +
		"\n" +
		"\n* Adjust contrast & brightness for Google Street View images" +
		"\n" +
		"\nVersion 1.7.1" +
		"\n" +
		"\n* Kills the 'Chat is here!' pop-up as of the next page reload" +
		"\n" +
		"\nVersion 1.7.2" +
		"\n" +
		"\n* Add validation to prevent an error whilst killing the Chat pop-up" +
		"\n");
		saveOptions();
	}

	// apply the settings
	shiftAerials();
	setTimeout(applyAllSettings, 2000);
	logit("Initialisation complete");
	console.timeEnd(prefix + ": initialisation time");
	console.groupEnd();
}

function createAddon() {
	//create the contents of my side-panel tab
	var addon = document.createElement('section');
	var section = document.createElement('p');
	addon.id = "sidepanel-FixUI";
	section.style.paddingTop = "0px";
	section.id = "fuContent";
	section.innerHTML  = '<b>UI Fixes</b><br>';
	section.innerHTML += '<input type="checkbox" id="_cbMoveZoomBar" /> ' +
			'<span title="Because nobody likes a pointless UI change that breaks your workflow, imposed by idiots who rarely use the editor and don\'t listen to feedback">Move zoom bar to left <sup>*</sup></span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbAddZoomIndicator" /> ' +
			'<span title="Yes - I stole the idea from WME Toolbox. But mine is clearer and takes up no extra room ;)">Add zoom level indicator to zoom bar</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbHideUserInfo" /> ' +
			'<span title="Because we can earn points quicker without a massive chunk of space wasted on telling us how many we earnt up to yesterday">Hide user info in the side panel</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbShrinkTopBars" /> ' +
			'<span title="Because we can\'t afford to waste screen space, particularly on stuff we didn\'t ask for and don\'t want, like the black bar">Shrink bars above the map</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbCompressSegmentTab" /> ' +
			'<span title="Because I\'m sick of having to scroll the side panel because of oversized fonts and wasted space">Compress the contents of the side panel</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbRestyleReports" /> ' +
			'<span title="Another UI element configured for developers with massive screens instead of normal users">Change formatting for report panels (UR/MP)</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbDisableMapBlocker" /> ' +
			'<span title="As if the crappy interface wasn\'t making life hard enough, now they force us to wait for an arbitrary time after every save!">Disable map blocking during/after saving.</span><span title="Use at your own risk. We don\'t know why it\'s there. Maybe there\'s a good reason but Waze can\'t be arsed to tell us what it is." style="font-size: 16px; color: red;">&#9888</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbNarrowSidePanel" /> ' +
			'<span title="If you have a netbook, Waze isn\'t interested in your experience. You need every bit of map space you can get - so have a present from me!">Reduce width of the side panel</span><span title="This will definitely interfere with scripts that rely on a fixed width for their tab contents." style="font-size: 16px; color: red;">&#9888</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbHideAveSpeedControls" /> ' +
			'<span title="If you don\'t have these in your country, YOU\'RE LUCKY! But don\'t forget you\'ve disabled this - they\'ll be coming soon!">Hide average speed camera controls</span><br>';
	section.innerHTML += '<input type="checkbox" id="_cbFixExternalProviders" /> ' +
			'<span title="The External Providers interface is really poor - you can rarely see all the details in the box provided and the other elements are poorly arranged. This fixes all that.">Expand & improve External Provider details for places</span><br>';
	section.innerHTML += '<br>';
	var tbHackStr = '<sup>* If you have WME Toolbox installed, make sure the setting "Move zoom control to left" is ';
	if (document.body.dir != "rtl") {
		tbHackStr += 'OFF';
	} else {
		tbHackStr += 'ON';
	}
	tbHackStr += '.</sup><br>';
	section.innerHTML += tbHackStr;
	section.innerHTML += '<b title="Shift aerial images layer to match GPS tracks and reduce image opacity">Aerial Shifter</b>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;';
	section.innerHTML += '<span class="fa fa-power-off" id="_resetAS" title="Clear X/Y offsets"></span><br>';
	section.innerHTML += '<div style="display:inline-block"><input type="number" id="_inpASX" title="horizontal shift" max=100 min=-100 step=5 style="height:20px; width:47px;text-align:right;"/><b>m</b><span class="fa fa-arrow-right"></span></div>';
	section.innerHTML += '<div id="as2" style="display:inline-block;padding:0 5px;"><input type="number" id="_inpASY" title="vertical shift" max=100 min=-100 step=5 style="height:20px; width:47px;text-align:right;"/><b>m</b><span class="fa fa-arrow-up"></span></div>';
	section.innerHTML += '<div id="as3" style="display:inline-block"><input type="number" id="_inpASO" title="opacity" max=100 min=0 step=10 style="height:20px; width:44px;text-align:right;"/><b>%</b><span class="fa fa-adjust"></span></div>';
	section.innerHTML += '<br>';
	section.innerHTML += '<br>';

	section.innerHTML += '<b title="Adjust contrast & brightness for Google Street View images">GSV image adjust</b><br>';
	section.innerHTML += '<span title="Contrast"><input type="number" id="_inpGSVContrast" max=200 min=0 step=25 style="height:20px; width:47px;text-align:right;"/><b>%</b><span class="fa fa-adjust"></span></span>&nbsp;&nbsp;';
	section.innerHTML += '<span title="Brightness"><input type="number" id="_inpGSVBrightness" max=200 min=0 step=25 style="height:20px; width:47px;text-align:right;"/><b>%</b><span class="fa fa-sun-o"></span></span>&nbsp;&nbsp;&nbsp;';
	section.innerHTML += '<span title="Invert colours"><input type="checkbox" id="_cbGSVInvert"/><span class="fa fa-tint"></span></span>';

	section.innerHTML += '<br>';
	section.innerHTML += '<br>';
	section.innerHTML += '<b><a href="https://www.waze.com/forum/viewtopic.php?f=819&t=191178" title="Forum topic" target="_blank"><u>' +
			'WME Fix UI</u></a></b> &nbsp; v' + wmefu_version;
	addon.appendChild(section);
	addon.className = "tab-pane";
	return addon;
}

function addMyTab(model,modeID) {
	if (modeID === 0) {
		logit("entering default mode, so creating tab");
		tabAttempts = 0;
		tabsLooper();
	} else {
		logit("entering event mode, so not initialising");
		return;
	}
}

function tabsLooper() {
	tabAttempts += 1;
	if (tabAttempts > 20) {
		// tried 20 times to create tab without luck
		logit("unable to create my tab after 20 attempts","error");
		return;
	}
	var userTabs = getId('user-info');
	var navTabs = getElementsByClassName('nav-tabs', userTabs)[0];
	if (typeof navTabs === "undefined") {
		//the basic tabs aren't there yet, so I can't add mine
		logit("waiting for NavTabs","warning");
		setTimeout(tabsLooper, 200);
	} else{
		var tabContent = getElementsByClassName('tab-content', userTabs)[0];
		newtab = document.createElement('li');
		newtab.innerHTML = '<a href="#sidepanel-FixUI" data-toggle="tab" title="Fix UI">FU</a>';
		navTabs.appendChild(newtab);
		tabContent.appendChild(wmeFUAddon);
	}
}

function applyAllSettings() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	console.group(prefix + ": applying all settings");
		moveZoomBar();
		shrinkTopBars();
		hideUserInfo();
		compressSegmentTab();
		restyleReports();
		disableMapBlocker();
		narrowSidePanel();
		hideAveSpeedControls();
		fixExternalProviders();
		addZoomIndicator();
		warnCommentsOff();
		adjustGSV();
	console.groupEnd();
	wmeFUinitialising = false;
}

function moveZoomBar() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var reportPanel = getId('panel-container');

	reportPanel.style.position = "absolute";
	if (_cbMoveZoomBar.checked) {
		addGlobalStyle('.olControlPanZoomBar { left: 10px; width: 30px; right: inherit; }');
		addGlobalStyle('#WMETB_ZoomLevelIndicator { left: 43px !important; right: inherit !important; }');
		if (document.body.dir != "rtl") {
			addGlobalStyle('.panel { left: 40px; }');
		} else {
			addGlobalStyle('.panel { right: inherit; }');
		}
	} else {
		addGlobalStyle('.olControlPanZoomBar { left: inherit; width: 30px; right: 10px; }');
		addGlobalStyle('#WMETB_ZoomLevelIndicator { left: inherit !important; right: 43px !important; }');
		if (document.body.dir != "rtl") {
			addGlobalStyle('.panel { left: inherit; }');
		} else {
			addGlobalStyle('.panel { right: 40px; }');
		}
	}
}

function hideUserInfo() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var styles = "";
	// WME Panel Swap buttons - move them up if user info is hidden
	var PSButton1 = getId('WMEPS_UIButton');
	var PSButton2 = getId('WMEPS_EditButton');
	if (_cbHideUserInfo.checked) {
		styles += '#sidebar #user-info #user-box { padding: 0px; }';
		styles += '#sidebar #user-details .user-profile { display: none !important; }';
		if (PSButton1) { PSButton1.style.top = '-27px'; }
		if (PSButton2) { PSButton2.style.top = '-27px'; }
		// Keep My Layers toggle - move up if user info is hidden
		styles += '.kml-toggle-container { top: -25px !important; }';
		addStyle(prefix + fname,styles);
	} else {
	if (PSButton1) { PSButton1.style.top = '0px'; }
	if (PSButton2) { PSButton2.style.top = '0px'; }
		removeStyle(prefix + fname);
	}
}

function shrinkTopBars() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var styles = "";
	if (_cbShrinkTopBars.checked) {
		//shrink the blue tool bar
		styles += '.toolbar { height: 31px; }';
		styles += '#app-head { height: 31px; }';
		styles += '#search { padding-top: 1px; }';
		styles += '.toolbar .toolbar-button { padding: 2px 7px; }';
		styles += '.toolbar .toolbar-separator { height: 31px; }';
		styles += '#layer-switcher { height: 51px; }';
		styles += '.toolbar menu.dropdown-menu { top: 31px; }';
		styles += '#layer-switcher .dropdown-menu { top: 31px; }';
		//extra tweaks for Toolbox button & layers menu
		styles += '.WazeControlLayerSwitcherIcon { margin: 5px 2px 0 !important; }';
		styles += '#WazeControlLayerSwitcherIconContainer { height: 51px !important; }';
		styles += '#WazeControlLayerSwitcherIconContainerBeta { height: 51px !important; }';
		if (document.body.dir != "rtl") {
			styles += '.WazeControlLayerSwitcherToolbox { margin-left: -92px !important; }';
		} else {
			styles += '.WazeControlLayerSwitcherToolbox { margin-left: 112px !important; }';
		}
		styles += '#sidebar waze-links { height: 16px; }';
		//shrink the black bar
//		styles += '.topbar { height: 20px; line-height: 20px; }';
//		styles += '.topbar .location-info { font-size: 12px; }';
		styles += 'div#topbar-container { position: relative; }';
		styles += '.topbar { position: absolute; z-index: 1; background: transparent; height: 0; color: white; text-shadow: -1px -1px 0 #000, 1px -1px #000, -1px 1px #000, 1px 1px #000; line-height: 1.1; }';
		styles += '.topbar .location-info { font-size: 15px; font-weight: 900; }';
		styles += '.topbar .area-managers .title, .topbar .area-managers .main-list { font-size: 15px; font-weight: 900; }';
		// following line needed to move MTE menu over the WME Bookmarks pin control
		styles += '#mode-switcher .dropdown-menu { top: 30px; }';
		styles += '.olControlPanZoomBar { top: 32px; }';
		styles += '#panel-container .panel { top: 20px; }';
		addStyle(prefix + fname,styles);
	} else {
		removeStyle(prefix + fname);
	}
	window.dispatchEvent(new Event('resize'));
}

function FALSEcompressSegmentTab() {
	_cbCompressSegmentTab.checked = _cbextraCBSection.checked;
	compressSegmentTab();
}

function compressSegmentTab() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var styles = "";
	if (_cbCompressSegmentTab.checked) {
		// shrink address
		styles += '#edit-panel .primary-street { font-size: 14px; line-height: 15px; font-weight: 600; color: black; }';
		styles += '#edit-panel .address-edit-view .preview .address-edit-btn:not(.disabled) { background-color: #FFF9C4; }';
		styles += '#edit-panel .segment .address-edit-view, .edit-panel .segment .address-edit-view { margin-bottom: 5px; }';
		//shrink tabs
		styles += '#sidebar .nav-tabs>li {margin-top: 2px; }';
		styles += '#sidebar .nav-tabs li a { padding: 2px; }';
		styles += '#sidebar .nav-tabs { margin: 0 0 5px 0; padding-left: 4px; }';
		//reduce some vertical margins
		styles += '#edit-panel .contents { padding: 0 5px 0 5px; overflow: hidden; }';
		styles += '#edit-panel .form-group { margin-bottom: 2px; line-height: 1; font-size: 11px; }';
		styles += '#edit-panel .selection { margin-bottom: 5px; }';
		styles += '#sidebar .side-panel-section:not(:last-child) { margin-bottom: 2px; }';
		styles += '#sidebar .side-panel-section:not(:last-child)::after { margin-top: 5px; margin-bottom: 2px; }';
		styles += '#edit-panel .control-label { margin-bottom: 1px; }';
		styles += '#sidebar .controls-container { padding-top: 2px; }';
		styles += '#edit-panel .segment .speed-limit label { margin-bottom: 0px; }';
		styles += '#edit-panel .more-actions { padding-top: 2px; }';
		styles += '#edit-panel .segment .speed-limit .direction-label, #edit-panel .segment .speed-limit .unit-label { line-height: 2.1em; }';
		//shrink dropdown controls & buttons
		styles += '#edit-panel button, #edit-panel select, #edit-panel .form-control { font-size: 11px; height: auto; padding: 0px 4px; }';
		styles += '#edit-panel .more-actions button:not(:last-of-type) { margin-bottom: 2px; }';
		styles += '.edit-closure .input-group-addon { padding: 2px 8px; }';
		//fit road property checkboxes on one line for all three (if text length allows)
		styles += '#edit-panel .controls-container { display: inline-block; }';
		styles += '#edit-panel .controls-container label { font-size: 12px; line-height: 18px; padding-left: 22px; }';
		styles += '#edit-panel .select-entire-street { width: 49%; overflow: hidden; }';
		styles += '#edit-panel .edit-house-numbers { width: 49%; overflow: hidden; }';
		styles += '#edit-panel .action-button { color: black; }';
		styles += '#edit-panel .categories .select2-container { margin-bottom: -5px; }';
		//tweaks for Closures tab
		styles += '#edit-panel .segment .segment-details { margin-bottom: 4px; }';
		styles += '.closures-list .closure-item .section { padding: 2px; }';
		styles += '.col-xs-6 { line-height: 14px; }';
		styles += '.closures-list .direction { margin-bottom: 0px; }';
		styles += '.closures-list .closure-item:not(:last-child) { margin-bottom: 4px; }';
		//tweak required for Speedhelper script
		styles += 'div[id^="spd_"] { line-height: 1.43; }';
		//tweaks for Feed tab
		styles += '.feed-item { margin-bottom: 2px; }';
		styles += '.feed-item .inner { padding: 2px; }';
		styles += '.feed-item .delete { zoom: 149%; }';
		styles += '.feed-item .motivation { margin-bottom: 0px; }';
		styles += '.feed-item .content .title { margin-bottom: 0px; }';
		styles += '.feed-item .content .subtext { font-size: 11px; }';
		//tweaks for Drives tab
		styles += '#sidebar .message { margin-bottom: 0px; line-height: 14px; }';
		styles += '#sidebar .result-list .result { padding: 2px 5px; }';
		//tweaks for Restrictions dialogue
		styles += '#schedule-modal .modal-body { padding: 2px 8px; }';
		styles += '#schedule-modal .items { line-height: 0.5; }';
		styles += '#schedule-modal .table { margin-bottom: 10px; }';
		styles += '#schedule-modal .no-restrictions { margin-bottom: 10px; }';
		styles += '#schedule-modal .well { padding: 5px; }';
		styles += '#schedule-modal .edit-restriction .section { margin-bottom: 2px; padding: 0 2px; }';
		styles += '#schedule-modal .nav>li>a { padding: 2px 15px; }';
		styles += '#schedule-modal .btn { height: 22px; padding: 2px 15px; }';
		addStyle(prefix + fname,styles);
	} else {
		removeStyle(prefix + fname);
	}
}

function restyleReports() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var styles = "";
	if (_cbRestyleReports.checked) {
		styles += '#panel-container .panel { font-size: 12px; line-height: 15px; }';
		styles += '#panel-container .problem-edit .header { padding: 5px; line-height: 15px; }';
		styles += '#panel-container .problem-edit .problem-data .title { line-height: 22px; }';
		styles += '#panel-container .problem-edit .section .title { padding: 0 5px; }';
		styles += '#panel-container .problem-edit .section .content { padding: 5px; }';
		styles += '#WMEFP-UR-ALLPM { top: -2px !important; }';
		styles += '#panel-container .problem-edit .conversation.section .comment .comment-content { padding: 0 5px; }';
		styles += '#panel-container .problem-edit .conversation.section .no-comments { padding: 0; }';
		styles += '#panel-container .problem-edit .conversation.section .new-comment-form { padding: 0; }';
		styles += '#panel-container .problem-edit .conversation.section .new-comment-form textarea { resize: vertical; height: 110px; margin-bottom: 0px; padding: 3px 5px; font-size: 12px; }';
		styles += '#panel-container .btn { height: 20px; padding: 0px 10px;}';
		styles += '#panel-container .problem-edit .actions .content { padding: 2px 5px;}';
		styles += '#panel-container .problem-edit .actions .controls-container label { margin-bottom: 0px; line-height: 22px }';
		styles += '#panel-container .problem-edit .actions .navigation { margin-top: 5px;}';
		styles += '#panel-container .problem-edit .actions .controls-container { display: inline-flex; flex-wrap: wrap; margin-left: -3px; }';
		styles += '#panel-container .input-max-length { text-align: right; margin-top: 0; white-space: nowrap; color: #3d3d3d; font-weight: 700; font-size: 11px; }';
		addStyle(prefix + fname,styles);
		if (wmeFUinitialising) {
			setTimeout(draggablePanel, 5000);
		} else {
			draggablePanel();
		}
	} else {
		removeStyle(prefix + fname);
		if (jQuery.ui) {
			$("#panel-container").draggable("destroy");
			getId("panel-container").style = "";
		}
	}
	window.dispatchEvent(new Event('resize'));
}

function draggablePanel() {
	if (jQuery.ui) {
		$("#panel-container").draggable({ handle: ".header" });
	}
}

function disableMapBlocker() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	if (_cbDisableMapBlocker.checked) {
		addStyle(prefix + fname,'#popup-overlay { width: 0%; height: 0%; }');
	} else {
		removeStyle(prefix + fname);
	}
}

function narrowSidePanel() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var styles = "";
	if (_cbNarrowSidePanel.checked) {
		styles += '.row-fluid #sidebar { width: 250px; }';
		styles += '.col-fixed-330 { width: 250px; }';
		styles += '#sidebar waze-links { overflow: hidden; }';
		styles += '#sidebar waze-links li+li::before { padding: 0; }';
		styles += '#sidebar waze-links li { font-size: 10px; }';
		styles += '#edit-panel .add-alt-street-form th.city { min-width: inherit; }';
		styles += '#edit-panel .external-providers-view .select2-container { width: 100%; }';
		if (document.body.dir != "rtl") {
			styles += '.show-sidebar .row-fluid .fluid-fixed { margin-left: 250px; }';
			styles += '.col-offset-330 { padding-left: 250px; }';
		} else {
			styles += '.show-sidebar .row-fluid .fluid-fixed { margin-right: 250px; }';
			styles += '.col-offset-330 { padding-right: 250px; }';
		}
		styles += '.edit-closure .form { padding: 2px; }';
		styles += '.edit-closure .date-input-group { width: 56%; }';
		styles += '#editor-container #map.street-view-mode #street-view-container { width: 35%; }';
		styles += '#editor-container #map.street-view-mode #WazeMap { width: 65%; margin-right: 65%; }';
		addStyle(prefix + fname, styles);
	} else {
		removeStyle(prefix + fname);
	}
	window.dispatchEvent(new Event('resize'));
}

function hideAveSpeedControls() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	removeStyle(prefix + fname);
	if (_cbHideAveSpeedControls.checked) {
		var ASCBox;
		if (getId('fwdSpeedCameraCheckbox')) {
			ASCBox = getId('fwdSpeedCameraCheckbox');
		}
		if (getId('revSpeedCameraCheckbox')) {
			ASCBox = getId('revSpeedCameraCheckbox');
		}
		if (ASCBox) {
			var formGroup = ASCBox.parentNode.parentNode.parentNode;
			var formGroupParent = formGroup.parentNode;
			var targetGroup = Array.prototype.indexOf.call(formGroupParent.children, formGroup) + 1;
			addStyle(prefix + fname, '#segment-edit-general > .side-panel-section.attributes-form > .form-group:nth-of-type(' + targetGroup + ') { display: none; }');
		}
	}
}

function addZoomIndicator() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var slider = getElementsByClassName('slider', getId('WazeMap'))[1];
	if (_cbAddZoomIndicator.checked) {
		addStyle(prefix + fname, '.slider { font-size: 15px; font-weight: 900; line-height: 1; height: 18px; margin-top: 23px; padding-top: 2px; text-align: center; }');
		Waze.map.events.register("zoomend", null, ZLI);
		ZLI();
	} else {
		removeStyle(prefix + fname);
		Waze.map.events.unregister("zoomend", null, ZLI);
		slider.innerText = "";
		slider.title = "";
	}
}

function ZLI() {
	var slider = getElementsByClassName('slider', getId('WazeMap'))[1];
	slider.innerText = Waze.map.zoom;
	slider.title = "Zoom level indicator by WMEFU";
	switch (Waze.map.zoom) {
		case 0:
		case 1:
			slider.style.background = '#ef9a9a';
			slider.title += "\nCannot permalink any segments at this zoom level";
			break;
		case 2:
		case 3:
			slider.style.background = '#ffe082';
			slider.title += "\nCan only permalink primary or higher at this zoom level";
			break;
		default:
			slider.style.background = '#ffffff';
			slider.title += "\nCan permalink any segments at this zoom level";
			break;
	}
}

function shiftAerials() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	// calculate meters/pixel for current map view
	var ipu = OpenLayers.INCHES_PER_UNIT;
	var metersPerPixel = Waze.map.getResolution() * ipu.m / ipu[Waze.map.getUnits()];
	// Apply the shift and opacity
	Waze.map.baseLayer.div.style.left = Math.round(getId("_inpASX").value / metersPerPixel) + 'px';
	Waze.map.baseLayer.div.style.top = Math.round(- getId("_inpASY").value / metersPerPixel) + 'px';
	Waze.map.baseLayer.div.style.opacity = getId("_inpASO").value/100;
}

function fixExternalProviders () {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var styles = "";
	if (_cbFixExternalProviders.checked) {
		//enlarge external provider boxes
		styles += '#edit-panel .external-providers-view .select2-container { width: 90%; margin-bottom: 2px; }';
		styles += '.select2-container .select2-choice { height: inherit; line-height: 16px; }';
		styles += '.select2-container .select2-choice>.select2-chosen { white-space: normal; }';
		styles += '.placeId { padding-bottom: 5px; }';
		addStyle(prefix + fname,styles);
	} else {
		removeStyle(prefix + fname);
	}
}

function warnCommentsOff() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	if (Waze.map.getLayerByUniqueName('mapComments').visibility === false) {
		removeStyle(prefix + fname);
		addStyle(prefix + fname, '.toolbar { background-color: #FFC107; }');
	} else {
		removeStyle(prefix + fname);
	}
}

function adjustGSV() {
	var fname = arguments.callee.toString().match(/function ([^\(]+)/)[1];
	logit("function " + fname + " called", "debug");
	var styles = "";
	styles += '.gm-style { filter: contrast(' + getId('_inpGSVContrast').value + '%) ';
	styles += 'brightness(' + getId('_inpGSVBrightness').value + '%) ';
	if (getId('_cbGSVInvert').checked) {
		styles += 'invert(1); }';
	} else {
		styles += 'invert(0); }';
	}
	removeStyle(prefix + fname);
	addStyle(prefix + fname, styles);
}

//Helper functions

function addGlobalStyle(css) {
	var head, style;
	head = document.getElementsByTagName('head')[0];
	if (!head) {
		return;
	}
	style = document.createElement('style');
	style.type = 'text/css';
	style.innerHTML = css;
	head.appendChild(style);
}

function addStyle(ID, css) {
	var head, style;
	head = document.getElementsByTagName('head')[0];
	if (!head) {
		return;
	}
	style = document.createElement('style');
	style.type = 'text/css';
	style.innerHTML = css;
	style.id = ID;
	head.appendChild(style);
}

function removeStyle(ID) {
	var style = document.getElementById(ID);
	if (style) { style.parentNode.removeChild(style); }
}

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 logit(msg, typ) {
	if (!typ) {
		console.log(prefix + ": " + msg);
	} else {
		switch(typ) {
			case "error":
				console.error(prefix + ": " + msg);
				break;
			case "warning":
				console.warn(prefix + ": " + msg);
				break;
			case "info":
				console.info(prefix + ": " + msg);
				break;
			case "debug":
				if (debug) {
					console.debug(prefix + ": " + msg);
				}
				break;
			default:
				console.log(prefix + " unknown message type: " + msg);
				break;
		}
	}
}

// Start it running
setTimeout(init1, 200);
})();