// ==UserScript==
// @name WME Find Deleted Objects
// @namespace https://greasyfork.org/users/32336-joyriding
// @version 2019.01.18.02
// @description Attempts to show the history of a venue that has been deleted in an area.
// @author Joyriding
// @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*
// @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKT2lDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVNnVFPpFj333vRCS4iAlEtvUhUIIFJCi4AUkSYqIQkQSoghodkVUcERRUUEG8igiAOOjoCMFVEsDIoK2AfkIaKOg6OIisr74Xuja9a89+bN/rXXPues852zzwfACAyWSDNRNYAMqUIeEeCDx8TG4eQuQIEKJHAAEAizZCFz/SMBAPh+PDwrIsAHvgABeNMLCADATZvAMByH/w/qQplcAYCEAcB0kThLCIAUAEB6jkKmAEBGAYCdmCZTAKAEAGDLY2LjAFAtAGAnf+bTAICd+Jl7AQBblCEVAaCRACATZYhEAGg7AKzPVopFAFgwABRmS8Q5ANgtADBJV2ZIALC3AMDOEAuyAAgMADBRiIUpAAR7AGDIIyN4AISZABRG8lc88SuuEOcqAAB4mbI8uSQ5RYFbCC1xB1dXLh4ozkkXKxQ2YQJhmkAuwnmZGTKBNA/g88wAAKCRFRHgg/P9eM4Ors7ONo62Dl8t6r8G/yJiYuP+5c+rcEAAAOF0ftH+LC+zGoA7BoBt/qIl7gRoXgugdfeLZrIPQLUAoOnaV/Nw+H48PEWhkLnZ2eXk5NhKxEJbYcpXff5nwl/AV/1s+X48/Pf14L7iJIEyXYFHBPjgwsz0TKUcz5IJhGLc5o9H/LcL//wd0yLESWK5WCoU41EScY5EmozzMqUiiUKSKcUl0v9k4t8s+wM+3zUAsGo+AXuRLahdYwP2SycQWHTA4vcAAPK7b8HUKAgDgGiD4c93/+8//UegJQCAZkmScQAAXkQkLlTKsz/HCAAARKCBKrBBG/TBGCzABhzBBdzBC/xgNoRCJMTCQhBCCmSAHHJgKayCQiiGzbAdKmAv1EAdNMBRaIaTcA4uwlW4Dj1wD/phCJ7BKLyBCQRByAgTYSHaiAFiilgjjggXmYX4IcFIBBKLJCDJiBRRIkuRNUgxUopUIFVIHfI9cgI5h1xGupE7yAAygvyGvEcxlIGyUT3UDLVDuag3GoRGogvQZHQxmo8WoJvQcrQaPYw2oefQq2gP2o8+Q8cwwOgYBzPEbDAuxsNCsTgsCZNjy7EirAyrxhqwVqwDu4n1Y8+xdwQSgUXACTYEd0IgYR5BSFhMWE7YSKggHCQ0EdoJNwkDhFHCJyKTqEu0JroR+cQYYjIxh1hILCPWEo8TLxB7iEPENyQSiUMyJ7mQAkmxpFTSEtJG0m5SI+ksqZs0SBojk8naZGuyBzmULCAryIXkneTD5DPkG+Qh8lsKnWJAcaT4U+IoUspqShnlEOU05QZlmDJBVaOaUt2ooVQRNY9aQq2htlKvUYeoEzR1mjnNgxZJS6WtopXTGmgXaPdpr+h0uhHdlR5Ol9BX0svpR+iX6AP0dwwNhhWDx4hnKBmbGAcYZxl3GK+YTKYZ04sZx1QwNzHrmOeZD5lvVVgqtip8FZHKCpVKlSaVGyovVKmqpqreqgtV81XLVI+pXlN9rkZVM1PjqQnUlqtVqp1Q61MbU2epO6iHqmeob1Q/pH5Z/YkGWcNMw09DpFGgsV/jvMYgC2MZs3gsIWsNq4Z1gTXEJrHN2Xx2KruY/R27iz2qqaE5QzNKM1ezUvOUZj8H45hx+Jx0TgnnKKeX836K3hTvKeIpG6Y0TLkxZVxrqpaXllirSKtRq0frvTau7aedpr1Fu1n7gQ5Bx0onXCdHZ4/OBZ3nU9lT3acKpxZNPTr1ri6qa6UbobtEd79up+6Ynr5egJ5Mb6feeb3n+hx9L/1U/W36p/VHDFgGswwkBtsMzhg8xTVxbzwdL8fb8VFDXcNAQ6VhlWGX4YSRudE8o9VGjUYPjGnGXOMk423GbcajJgYmISZLTepN7ppSTbmmKaY7TDtMx83MzaLN1pk1mz0x1zLnm+eb15vft2BaeFostqi2uGVJsuRaplnutrxuhVo5WaVYVVpds0atna0l1rutu6cRp7lOk06rntZnw7Dxtsm2qbcZsOXYBtuutm22fWFnYhdnt8Wuw+6TvZN9un2N/T0HDYfZDqsdWh1+c7RyFDpWOt6azpzuP33F9JbpL2dYzxDP2DPjthPLKcRpnVOb00dnF2e5c4PziIuJS4LLLpc+Lpsbxt3IveRKdPVxXeF60vWdm7Obwu2o26/uNu5p7ofcn8w0nymeWTNz0MPIQ+BR5dE/C5+VMGvfrH5PQ0+BZ7XnIy9jL5FXrdewt6V3qvdh7xc+9j5yn+M+4zw33jLeWV/MN8C3yLfLT8Nvnl+F30N/I/9k/3r/0QCngCUBZwOJgUGBWwL7+Hp8Ib+OPzrbZfay2e1BjKC5QRVBj4KtguXBrSFoyOyQrSH355jOkc5pDoVQfujW0Adh5mGLw34MJ4WHhVeGP45wiFga0TGXNXfR3ENz30T6RJZE3ptnMU85ry1KNSo+qi5qPNo3ujS6P8YuZlnM1VidWElsSxw5LiquNm5svt/87fOH4p3iC+N7F5gvyF1weaHOwvSFpxapLhIsOpZATIhOOJTwQRAqqBaMJfITdyWOCnnCHcJnIi/RNtGI2ENcKh5O8kgqTXqS7JG8NXkkxTOlLOW5hCepkLxMDUzdmzqeFpp2IG0yPTq9MYOSkZBxQqohTZO2Z+pn5mZ2y6xlhbL+xW6Lty8elQfJa7OQrAVZLQq2QqboVFoo1yoHsmdlV2a/zYnKOZarnivN7cyzytuQN5zvn//tEsIS4ZK2pYZLVy0dWOa9rGo5sjxxedsK4xUFK4ZWBqw8uIq2Km3VT6vtV5eufr0mek1rgV7ByoLBtQFr6wtVCuWFfevc1+1dT1gvWd+1YfqGnRs+FYmKrhTbF5cVf9go3HjlG4dvyr+Z3JS0qavEuWTPZtJm6ebeLZ5bDpaql+aXDm4N2dq0Dd9WtO319kXbL5fNKNu7g7ZDuaO/PLi8ZafJzs07P1SkVPRU+lQ27tLdtWHX+G7R7ht7vPY07NXbW7z3/T7JvttVAVVN1WbVZftJ+7P3P66Jqun4lvttXa1ObXHtxwPSA/0HIw6217nU1R3SPVRSj9Yr60cOxx++/p3vdy0NNg1VjZzG4iNwRHnk6fcJ3/ceDTradox7rOEH0x92HWcdL2pCmvKaRptTmvtbYlu6T8w+0dbq3nr8R9sfD5w0PFl5SvNUyWna6YLTk2fyz4ydlZ19fi753GDborZ752PO32oPb++6EHTh0kX/i+c7vDvOXPK4dPKy2+UTV7hXmq86X23qdOo8/pPTT8e7nLuarrlca7nuer21e2b36RueN87d9L158Rb/1tWeOT3dvfN6b/fF9/XfFt1+cif9zsu72Xcn7q28T7xf9EDtQdlD3YfVP1v+3Njv3H9qwHeg89HcR/cGhYPP/pH1jw9DBY+Zj8uGDYbrnjg+OTniP3L96fynQ89kzyaeF/6i/suuFxYvfvjV69fO0ZjRoZfyl5O/bXyl/erA6xmv28bCxh6+yXgzMV70VvvtwXfcdx3vo98PT+R8IH8o/2j5sfVT0Kf7kxmTk/8EA5jz/GMzLdsAAAAgY0hSTQAAeiUAAICDAAD5/wAAgOkAAHUwAADqYAAAOpgAABdvkl/FRgAABY1JREFUeNqcl22MlNUVx3/nPjM7u+yKi4AsC2UNMSAfmmCwxsbERGliW0Pw5YOGGBJCYjTFREJrJGpLSH2JrbYGq7UJbT+obY0vIGg0UQyaIBFiSjCGLAhlYXdnUXFZ2J2deZ57Tj/cZ2aeHWZ3aW9yMvflOed/zzn/e+4dMTMARITJWv/WPYWZve/fImqrIXcdJN2Im+18/J26aAA4aE52jiz56Z4Fv76lPJmdKhaATAV8ctvB3OzP3lwvGm/BrCv9EGoGFHB1BZGiufyW73581/aeB69L/i/gC2s294iv7BAfL0cIAKYgKZApE+YhrIX5f2u+/faO1546+T8Bl+7acD2wG9zculYjqGOadgZ0VdubL3x+ScAX1mzuiUrnDogxFxRzOUTrUWsch1Br0745d8a3XnZ91fMssGvMaW707A5RPxfziE8QHyM+ATPEJ7h4fMIY82CG65lPy8tbcT3zAwfM4+LxK3Nj53ac3HYw1xiOCR6XV913P+hLE/ajWutWZl3J+fUPcPnyLgodEePnPSOHisz85H3aN62B9hkwOkb86HPY8VNZnAcKu/7y56ahLq++t+B8238w7cqwIXikyvDym7j8N+tpmTFNbkdLJI88gx3vy5DNFTUqXVXY+Ur5olA737YSX+lCE9AE4nFIKuAhbp9N59bpQa00TvLwk9ix4+DLkJSDLV/pcr5tJQ3MCK5XSqtRj3iPxDFiFnhSLnH2FxvJF8KnSUXp2/YR5x57CS1PPKpne0fh6AnEe7DAfvEe1Af7mZZN+goxAqAZ+AQ8qDk6r+2uV7Htn9J9YBf5Pz0BhYmcaV/cGfQBSdNpIjg1TGRFU2Ax60Z9yIvGYAJxBfFG68w6wKwzR8m/+AR0tAfDY+PIjFYA8m0u5YXW8lutDuKi7uah9skcUR+OjwmSeFBDvDI+Ug9px+Z1NVAujFJ876va2ti3cdCv2lFflySe0xQYHw+jIR/4GHyMJMHA8KHBukJLFDwdr1D8tI95d1xbJ/SJ76nZUGuQeLg5sDGIgaghmi6JgHna9++9iMHS2kLXz5bhonqpLbz2aqpvKbnS8moKRIPNQ222T1TTHMUIhphHll7NrA13TFeXOTdQpvOLT2pnXzRJRdNfv28Sj+0DLEl3aKAVZMki3Pbfw2UdU59fNaJfbQGt1D20pC5V+82AT93z+G5R+sMOQXCI5EK4Ac6P8u0f3m4KXHzuXTqOHUI81PSVMPaA0W8Lhnc3BU4v7qdRAyQQovdrWL8JBobQtQ9yxcvPc/q3b2Far7mn/7qP+f98MXwvGTJ5X7tARPXp6PW9yaSXhP1rg+PZ4/sx+1HtclCFSgxJDN4wgbM3raL1d5sY+eMbzN/1N4iikB7nUkZlHxV2gF9efYPc/YJOdR+L3bB6HknpY4xrai+LxAdRCRUNDy0zILIAikHUEjwEkCj0hSPk2m6W/TuHwnU8BTAg5c4fdrcsnvchyFLUh2kzSDSc8SgfAEVCMp1LVa3usFlv5cSZlYXhwwPVgzXpQ6AKXBg+PNR/ZOBWvD8Qdp9aixzk8wHIhcMfSmO6sardJPl88MiRWwvDh4eqNhsJOek9t3Dsq6FlA6dWUixuxFxfyHm6ARHw6bgKqAqJ9lEc2rhssP8n3aX+4lRHsDHU1Zg5IKrKwpkLcn1SuFt6Fj0PLn+xFZdY36mHFvkL/zg90p+SoCbVHeu0OU4BXWYDDnC+fcnP3eLuvwfw6ptaEzs5sM6N9O5OQTQDWO3bpZCr0XOXGaNzlt4mXfNeAcmDS+ybb9a6oS/fqVX8OqBmxjQCY2bZZ6c0CXUOaMlIwX6w4na75sb9tnD5nUChYT2X0XVZclWxzGzSfxLSyPQm8xeV7MyvNZmf8K7OTWNEmhi61Dalzn8HAB4VQHAYFYLdAAAAAElFTkSuQmCC
// @require https://greasyfork.org/scripts/24851-wazewrap/code/WazeWrap.js
// @require https://greasyfork.org/scripts/38421-wme-utils-navigationpoint/code/WME%20Utils%20-%20NavigationPoint.js
// @contributionURL https://github.com/WazeDev/Thank-The-Authors
// @license GPLv3
// @grant none
// ==/UserScript==
/* global W */
/* global OL */
/* global I18n */
/* global $ */
/* global WazeWrap */
/* global NavigationPoint */
/* global require */
/* global uuidGenerator */
/* global Backbone */
(function() {
'use strict';
var settings = {};
var _wmeFdoFeatureLayer;
var _wmeFdoMarkerLayer;
var requestStatus = [];
var seenVenueIds = [];
var subcategoryToParentCategories = [];
var rateLimitLastCall = Date.now();
var rateLimitLastModified = Date.now();
var rateLimitBaseDelay = 50;
var rateLimitAddedDelay = 0;
var rateLimitDelayStepUp = 25;
var rateLimitDelayStepDown = 5;
var flags = {
venue: { }
};
var externalProviderDetails = { };
function bootstrap(tries) {
tries = tries || 1;
if (W && W.map &&
W.model && W.loginManager.user &&
$ ) {
init();
} else if (tries < 1000)
setTimeout(function () {bootstrap(tries++);}, 200);
}
function init()
{
_wmeFdoFeatureLayer = new OL.Layer.Vector("_wmeFdoFeatureLayer",{uniqueName: "__wmeFdoFeatureLayer"});
W.map.addLayer(_wmeFdoFeatureLayer);
_wmeFdoFeatureLayer.setVisibility(true);
_wmeFdoMarkerLayer = new OL.Layer.Markers("_wmeFdoMarkerLayer",{uniqueName: "__wmeFdoMarkerLayer"});
W.map.addLayer(_wmeFdoMarkerLayer);
_wmeFdoMarkerLayer.setVisibility(true);
var curr_ver = GM_info.script.version;
let styleElements = getWmeStyles();
var $style = $("<style>");
$style.html([
'<style>',
'#wmeFdoStatusDate { margin-top:10px;margin-bottom:10px; }',
'.spinner-disable { opacity: 0; }',
'.wmeFdoFormInputLabel { display:inline-block;margin-right:10px;}',
'.wmeFdoFormInput { display:inline-block; width:150px;}',
'.wmeFdoButtonArea {margin-top:10px;margin-bottom:10px; }',
'.wmeFdoGoogleBtn { margin-top:10px;margin-bottom:10px; }',
'.wmeFdoRecreate a { color: #b5b5b5; cursor: pointer; text-decoration:none;}',
'.wmeFdoRecreate a:hover { text-decoration:underline; }',
'.wmeFdoResultDetail { position: relative; }',
'.wmeFdoDetailControls {position: absolute;right: 17px;top: 10px;}',
'.wmeFdoFlag a { text-decoration: none; }',
'.wmeFdoFlag { cursor:pointer; opacity:0.2; margin-right:5px;}',
'.wmeFdoFlag:hover { color:red; opacity:.75}',
'.wmeFdoFlag.flagged { color: red; opacity:1}',
'.historySummaryItem { margin-left:10px; color:#a7a7a7; }',
'.historySummaryItem a, .historySummaryItem a:visited { color:#a7a7a7; }',
'.wmeFdo-place-delete { filter: saturate(17) hue-rotate(65deg); }',
'.wmeFdo-place-delete:hover { filter: brightness(110%) saturate(17) hue-rotate(65deg) !important; }',
'.wmeFdo-place-delete:after {',
'border-top: 3px solid #ffffff;',
'width: 69%;',
'height: 49%;',
'position: absolute;',
'bottom: 6px;',
'left: 8px;',
'content: "";',
'transform: rotate(-45deg);',
'}',
'#wmeFdoSubTabs, .wmeFdoFlag { display: none!important; }',
'.wmeFdoResultTypeVenue { opacity:0.5; margin-left:-3px;margin-right:5px;position:relative;top:3px;' + styleElements.resultTypeVenueStyle.css + '}',
'.wmeFdoResultTypeCamera { opacity:0.5; margin-left:-3px;margin-right:5px;position:relative;top:3px;' + styleElements.resultTypeCameraStyle.css + '}',
'.wmeFdoResultTypeArea { opacity:0.5; margin-left:-3px;margin-right:5px;position:relative;top:10px;' + styleElements.resultTypeAreaStyle.css + '}',
'</style>'
].join(' '));
var $section = $('<div id="wmeFdoPanel">');
$section.html(
'<div id="wmeFdoHead">',
'</div>'
);
var $navTabs = $('<ul id="wmeFdoSubTabs" class="nav nav-tabs"><li class="active"><a data-toggle="tab" href="#wmeFdoTabFind">Find</a></li>' +
'<li><a data-toggle="tab" href="#wmeFdoTabFlagged" id="wmeFdoTabFlagEvent">Flagged</a></li>' +
'<li><a data-toggle="tab" href="#wmeFdoTabSettings"><span class="fa fa-gear"></span></a></li></ul>');
var $tabContent = $('<div class="tab-content" style="padding:5px;">');
var $fdoTabFind = $('<div id="wmeFdoTabFind" class="tab-pane active">');
$fdoTabFind.append([
'<h4 style="margin-top:0px;">Find Deleted Objects</h4>',
'<h6 style="margin-top:0px;">' + curr_ver + '</h6>'
].join(' '));
createSettingsCheckbox($fdoTabFind, 'wmeFdoNearbyEditors','Nearby Editors');
$fdoTabFind.append([
'<div class="controls-container" style="padding-top: 2px;"><div class="wmeFdoFormInputLabel">Editor Name</div><input type="text" id="wmeFdoEditorName" class="form-control wmeFdoFormInput"><label for="wmeFdoEditorName"></label></div><br>',
].join(' '));
createSettingsCheckbox($fdoTabFind, 'wmeFdoIncludeSelf','Include Deletes By This Editor');
createSettingsCheckbox($fdoTabFind, 'wmeFdoLimitToScreen','Limit to Screen');
$fdoTabFind.append([
'<div class="controls-container" style="padding-top: 2px;"><div class="wmeFdoFormInputLabel">Find Prior To</div><input type="text" id="wmeFdoFindDate" class="form-control wmeFdoFormInput"><label for="wmeFdoFindDate"></label></div><br>',
].join(' '));
var $fdoTabFlagged = $('<div id="wmeFdoTabFlagged" class="tab-pane">');
$fdoTabFlagged.html('<h4>Flagged Objects<h4>');
let $fdoTabFlaggedResults = $('<div id="wmeFdoFlaggedResults>');
$fdoTabFlagged.append($fdoTabFlaggedResults);
var $fdoTabSettings = $('<div id="wmeFdoTabSettings" class="tab-pane">');
$fdoTabSettings.append([
'<h4>Settings</h4>',
'<div id="wmeFdoSettings">',
'<div class="controls-container" style="padding-top: 2px;">Rate Limit Delay: <input type="text" id="wmeFdoRateLimitDelay" ><label for="wmeFdoRateLimitDelay"></label></div>',
'</div>'
].join(' '));
$('#wmeFdoTabSettings').append('div').append('Reset Settings');
$tabContent.append($fdoTabFind,$fdoTabFlagged,$fdoTabSettings);
$section.append($navTabs, $tabContent);
$section.append($style);
new WazeWrap.Interface.Tab('FiDO', $section.html(), initializeSettings);
prepareTab();
WazeWrap.Interface.AddLayerCheckbox("display", "Deleted Objects", settings.Enabled, onLayerCheckboxChanged);
onLayerCheckboxChanged(settings.Enabled);
let buttons = document.createElement('div');
buttons.className = 'wmeFdoButtonArea';
$('#wmeFdoTabFind').append(buttons);
var findButton = document.createElement('button');
findButton.id = 'wmeFdoFindButton';
findButton.textContent = 'Start Scan';
findButton.className = 'btn btn-success center-block';
buttons.append(findButton);
var cancelButton = document.createElement('button');
cancelButton.id = 'wmeFdoCancelButton';
cancelButton.textContent = 'Cancel Scan';
cancelButton.className = 'btn btn-warning center-block hidden';
buttons.append(cancelButton);
findButton.addEventListener('click', function() {
findButton.className = 'btn btn-success center-block hidden';
cancelButton.className = 'btn btn-danger center-block ';
_wmeFdoFeatureLayer.removeAllFeatures();
_wmeFdoMarkerLayer.clearMarkers();
seenVenueIds = [];
requestStatus = {};
resetRateLimit();
document.getElementById('wmeFdoTransactionList').innerHTML = '';
let tab = document.getElementById('wmeFdoTab');
tab.innerHTML = 'FiDO <span class="spinner-enable"><i class="icon-spinner icon-spin fa fa-spinner fa-spin"></i></span>';
$('#wmeFdoTabFind').data("status","running");
settings.Enabled = true;
onLayerCheckboxChanged(settings.Enabled); // TODO: Fix this so the Layer menu checkbox gets updated
findObjects();
});
cancelButton.addEventListener('click', function() {
cancelButton.textContent = 'Cancelling...';
cancelButton.className = 'btn btn-warning center-block disabled';
$('#wmeFdoTabFind').data("status","cancelled");
let tab = document.getElementById('wmeFdoTab');
tab.innerHTML = 'FiDO <span class="spinner-disable"><i class="icon-spinner icon-spin fa fa-spinner fa-spin"></i></span>';
cancelScan(0);
});
$("#wmeFdoEditorName").keyup(function(event) {
if (event.keyCode === 13) {
$("#wmeFdoFindButton").click();
}
});
$("#wmeFdoFindDate").keyup(function(event) {
if (event.keyCode === 13) {
$("#wmeFdoFindButton").click();
}
});
$('#wmeFdoNearbyEditors').change(function() {
var settingName = $(this)[0].id.substr(6);
settings[settingName] = this.checked;
saveSettings();
if(this.checked)
{
$("#wmeFdoEditorName").prop('disabled', true);
$("#wmeFdoIncludeSelf").prop('disabled', true);
$("#wmeFdoLimitToScreen").prop('disabled', true);
}
else
{
$("#wmeFdoEditorName").prop('disabled', false);
$("#wmeFdoIncludeSelf").prop('disabled', false);
$("#wmeFdoLimitToScreen").prop('disabled', false);
}
});
let flaggedTab = document.getElementById('wmeFdoTabFlagEvent');
flaggedTab.addEventListener('click', function() {
let flagList = '';
for (var id in flags.venue) {
flagList = flagList + id + '<br>';
console.log(id);
}
let results = document.getElementById('wmeFdoTabFlagged');
results.append(flagList);
});
var $usersDiv = $( '<div id="fdoUsersPanel"></div>');
var dateSpan = document.createElement('div');
dateSpan.id = 'wmeFdoStatusDate';
$('#wmeFdoTabFind').append(dateSpan);
let inputDate = document.getElementById('wmeFdoFindDate');
inputDate.value = formatCurrentDate();
$('#wmeFdoTabFind').append(buildResultsPanel());
console.log('FiDO: done');
}
function initializeSettings()
{
loadSettings();
setChecked('wmeFdoIncludeSelf', settings.IncludeSelf);
setChecked('wmeFdoLimitToScreen', settings.LimitToScreen);
setChecked('wmeFdoNearbyEditors', settings.NearbyEditors);
// if(settings.Enabled)
// W.selectionManager.events.register("selectionchanged", null, drawSelection);
$('.wmeFdoSettingsCheckbox').change(function() {
var settingName = $(this)[0].id.substr(6);
settings[settingName] = this.checked;
saveSettings();
if(this.checked)
{
// W.selectionManager.events.register("selectionchanged", null, drawSelection);
// processVenues(W.model.venues.getObjectArray());
}
else
{
// W.selectionManager.events.unregister("selectionchanged", null, drawSelection);
// wmeFdoSelectedLayer.removeAllFeatures();
// processVenues(W.model.venues.getObjectArray());
}
});
if(settings.NearbyEditors)
{
$("#wmeFdoEditorName").prop('disabled', true);
$("#wmeFdoIncludeSelf").prop('disabled', true);
$("#wmeFdoLimitToScreen").prop('disabled', true);
}
else
{
$("#wmeFdoEditorName").prop('disabled', false);
$("#wmeFdoIncludeSelf").prop('disabled', false);
$("#wmeFdoLimitToScreen").prop('disabled', false);
}
$('.wmeFdoSettingsText').on('input propertychange paste', function() {
var settingName = $(this)[0].id.substr(6);
settings[settingName] = parseInt($(this).val());
saveSettings();
//W.selectionManager.events.unregister("selectionchanged", null, drawSelection);
//processVenues(W.model.venues.getObjectArray());
});
}
function getWmeStyles() {
// Get the sprite icons from the native WME CSS so that we can use our own document structure
let styleElements = {
resultTypeVenueStyle: { cssParts: {}, css: "" },
resultTypeCameraStyle: { cssParts: {}, css: "" },
resultTypeAreaStyle: { cssParts: {}, css: "" }
};
let $tempDiv = null;
let tempQuerySelector = null;
let tempComputedStyle = null;
let tempCurrentStyle = null;
//.form-search .search-result-region .search-result .icon {
//background-image: url(//editor-assets.waze.com/production/img/toolbare2f6b31….png);
$tempDiv = $('<div class="form-search">').append($('<div class="search-result-region">').append($('<div class="search-result">').append($('<div class="icon">'))));
$('body').append($tempDiv);
tempQuerySelector = document.querySelector('.form-search .search-result-region .search-result .icon');
tempComputedStyle = window.getComputedStyle(tempQuerySelector);
tempCurrentStyle = styleElements.resultTypeVenueStyle.cssParts;
tempCurrentStyle.backgroundImage = tempComputedStyle.getPropertyValue('background-image');
tempCurrentStyle.backgroundPosition = tempComputedStyle.getPropertyValue('background-position');
tempCurrentStyle.backgroundSize = tempComputedStyle.getPropertyValue('background-size');
tempCurrentStyle.width = tempComputedStyle.getPropertyValue('width');
tempCurrentStyle.height = tempComputedStyle.getPropertyValue('height');
styleElements.resultTypeVenueStyle.css = `background-image:${tempCurrentStyle.backgroundImage};background-size:${tempCurrentStyle.backgroundSize};background-position:${tempCurrentStyle.backgroundPosition};width:${tempCurrentStyle.width};height:${tempCurrentStyle.height};`;
$tempDiv.remove();
//#edit-buttons .camera .item-icon::after {
//background-image: url(//editor-assets.waze.com/production/img/toolbare2f6b31….png);
tempQuerySelector = document.querySelector('#edit-buttons .camera .item-icon');
tempComputedStyle = window.getComputedStyle(tempQuerySelector,'::after');
tempCurrentStyle = styleElements.resultTypeCameraStyle.cssParts;
tempCurrentStyle.backgroundImage = tempComputedStyle.getPropertyValue('background-image');
tempCurrentStyle.backgroundPosition = tempComputedStyle.getPropertyValue('background-position');
tempCurrentStyle.backgroundSize = tempComputedStyle.getPropertyValue('background-size');
tempCurrentStyle.width = tempComputedStyle.getPropertyValue('width');
tempCurrentStyle.height = tempComputedStyle.getPropertyValue('height');
styleElements.resultTypeCameraStyle.css = `background-image:${tempCurrentStyle.backgroundImage};background-size:${tempCurrentStyle.backgroundSize};background-position:${tempCurrentStyle.backgroundPosition};width:${tempCurrentStyle.width};height:${tempCurrentStyle.height};`;
//$tempDiv.remove();
//#edit-buttons .toolbar-group .toolbar-group-item .drawing-controls .drawing-control.polygon:after {
//background-image: url(//editor-assets.waze.com/production/img/toolbare2f6b31….png);
tempQuerySelector = document.querySelector('#edit-buttons .toolbar-group .toolbar-group-item .drawing-controls .drawing-control.polygon');
tempComputedStyle = window.getComputedStyle(tempQuerySelector,'::after');
tempCurrentStyle = styleElements.resultTypeAreaStyle.cssParts;
tempCurrentStyle.backgroundImage = tempComputedStyle.getPropertyValue('background-image');
tempCurrentStyle.backgroundPosition = tempComputedStyle.getPropertyValue('background-position');
tempCurrentStyle.backgroundSize = tempComputedStyle.getPropertyValue('background-size');
tempCurrentStyle.width = tempComputedStyle.getPropertyValue('width');
tempCurrentStyle.height = tempComputedStyle.getPropertyValue('height');
styleElements.resultTypeAreaStyle.css = `background-image:${tempCurrentStyle.backgroundImage};background-size:${tempCurrentStyle.backgroundSize};background-position:${tempCurrentStyle.backgroundPosition};width:${tempCurrentStyle.width};height:${tempCurrentStyle.height};`;
return styleElements;
}
function buildResultsPanel() {
return $('<div id="fdoResultsPanel">')
.append($('<div class="elementHistoryContainer">')
.append($('<div class="historyContent">')
.append($('<div class="transactions">')
.append($('<ul id="wmeFdoTransactionList">'))
)
)
);
}
function onLayerCheckboxChanged(checked) {
settings.Enabled = checked;
if (settings.Enabled) {
_wmeFdoFeatureLayer.setVisibility(true);
_wmeFdoMarkerLayer.setVisibility(true);
} else {
_wmeFdoFeatureLayer.setVisibility(false);
_wmeFdoMarkerLayer.setVisibility(false);
}
saveSettings();
}
function cancelScan(tries) {
//TODO: Move rest of cancel code into here
tries = tries || 1;
//console.log('incomplete: ' + incompleteRequestCount());
if (incompleteRequestCount() > 0 && tries < 10) {
console.log('Cancel requested, waiting for ' + incompleteRequestCount() + ' requests to complete');
setTimeout(function () {cancelScan(tries++);}, 500);
} else {
// TODO: Change button to Start Scan
let findButton = document.getElementById('wmeFdoFindButton');
let cancelButton = document.getElementById('wmeFdoCancelButton');
findButton.className = 'btn btn-success center-block';
cancelButton.className = 'btn btn-warning center-block hidden';
cancelButton.textContent = 'Cancel Scan';
$('#wmeFdoStatusDate')[0].innerText = 'Scan Cancelled';
console.log('Cancelled');
}
}
function incompleteRequestCount() {
let incompleteCount = 0;
let failedCount = 0;
Object.keys(requestStatus).forEach(function (url) {
if (requestStatus[url].status != 'successful') {
if (Date.now() - requestStatus[url].lastAttempt < 10000) {
incompleteCount++;
} else {
failedCount++;
}
}
});
return incompleteCount;
}
function defaultRequestStatus() {
return {
status: 'initial',
attempts: 0,
lastAttempt: null
};
}
function requestParams(url) {
return {
url: url,
iteration: 0,
nextTransactionDate: null,
delay: calculateDelay(url)
}
}
function calculateDelay(url) {
let hash = Math.abs(hashCode(url)).toString();
let delay = parseInt(hash.substring(hash.length - 2));
if (delay == 0) {
delay = 30;
}
return delay;
}
function hashCode(s) {
let h;
for(let i = 0; i < s.length; i++) {
h = Math.imul(31, h) + s.charCodeAt(i) | 0;
}
return h;
}
async function beginFind(lookFor, transactionLookup) {
// var findCenterPoint = new OL.Geometry.Point(lookFor.locationCenter.coordinates[0], lookFor.locationCenter.coordinates[1]).transform(W.map.displayProjection, W.map.projection);
if ( $('#wmeFdoTabFind').data("status") == "running"
&& transactionLookup.iteration < transactionLookup.maxIterations
)
{
transactionLookup.iteration++;
let requestParamsTransactions = requestParams(getApiUrlTransactions(transactionLookup.userId, transactionLookup.nextTransactionDate));
requestStatus[requestParamsTransactions.url] = defaultRequestStatus();
var data = await getApiRequest(requestParamsTransactions);
while (typeof(data.error) != 'undefined' && data.error && requestParamsTransactions.attempts < 100)
{
data = await getApiRequest(requestParamsTransactions);
}
if (data.error) {
let delay = 100 * requestParamsTransactions.delay;
console.log(`Last chance attempt, delay: ${delay}`);
await wait(delay);
data = await getApiRequest(requestParamsTransactions);
}
if (data.error) {
console.log('Request failed.');
}
transactionLookup.nextTransactionDate = data.nextTransactionDate
let nextDate = 'Complete';
if (data.nextTransactionDate != null)
{
nextDate = uuidToDate(data.nextTransactionDate);
//$('#wmeFdoStatusDate')[0].innerText = 'Scanning thru ' + nextDate + '...';
$('#wmeFdoStatusDate')[0].innerText = 'Scanning...';
}
var transactionCount = 0;
data.transactions.forEach(function(transaction) {
transaction.operations.forEach(async function(operation) {
if (operation.objectType == lookFor.objectType || operation.objectType == 'Camera')
{
transactionCount++;
var operationCenterPoint = new OL.Geometry.Point(operation.objectCentroid.coordinates[0], operation.objectCentroid.coordinates[1]).transform(W.map.displayProjection, W.map.projection);
//var distance = operationCenterPoint.distanceTo(findCenterPoint);
//if (distance < 1000)
if (!lookFor.limitToScreen || lookFor.searchArea.containsPoint(operationCenterPoint))
{
if (operation.objectType == 'Camera') {
console.log('camera: ' + operation.objectID);
} else {
getDeletedItemsVenue(operation, transactionLookup, lookFor, operationCenterPoint);
}
}
}
});
});
if (transactionLookup.nextTransactionDate != null) {
beginFind(lookFor, transactionLookup);
} else {
endScan("End of Editor History", false);
}
} else {
if (transactionLookup.iteration >= transactionLookup.maxIterations)
{
endScan("Transaction Limit Exceeded", false);
}
}
}
async function getDeletedItemsVenue(operation, transactionLookup, lookFor, operationCenterPoint) {
//console.log('element history for ' + data.nextTransactionDate);
let requestParamsElementHistory = requestParams(getApiUrlElementHistory('venue', operation.objectID, null));
requestStatus[requestParamsElementHistory.url] = defaultRequestStatus();
var venueHistory = await getApiRequest(requestParamsElementHistory);
while (typeof(venueHistory.error) != 'undefined' && venueHistory.error && requestParamsElementHistory.attempts < 100)
{
venueHistory = await getApiRequest(requestParamsElementHistory);
}
venueHistory.transactions.objects.forEach(function(venueTransaction) {
venueTransaction.objects.forEach(function(venueAction) {
if (venueAction.actionType == 'DELETE') {
// console.log(venueAction);
if (venueAction.objectType == 'venue' && venueAction.oldValue != null)
{
let selfDelete = false;
if (transactionLookup.userId == venueTransaction.userID) {
selfDelete = true;
}
if (lookFor.includeSelf || !selfDelete) {
// Skip if searching for editor who deleted it
if (!seenVenueIds.includes(venueAction.objectID))
{
seenVenueIds.push(venueAction.objectID);
// console.log('Deleted Venue Name: ' + venueAction.oldValue.name);
// console.log('Deleted Venue ID: ' + venueAction.objectID);
// console.log('User ID: ' + venueTransaction.userID);
// console.log(venueHistory);
var record = document.createElement('div');
record.id=venueTransaction.transactionID;
let username = null;
venueHistory.users.objects.forEach( function(user) {
if (user.id == venueTransaction.userID) {
let userRank = user.rank + 1;
username = user.userName + '(' + userRank + ')';
}
});
record.innerText = username + ": " + venueAction.oldValue.name + " - " + venueAction.objectID;
// $('#wmeFdoTransactionList').append(record);
var details = document.createElement('li');
details.id = 'entry-' + venueAction.objectID;
details.className = 'element-history-item tx-has-content tx-has-related closed';
//details.innerText= username + ": " + venueAction.oldValue.name + " - " + venueAction.objectID;
var txHeader = document.createElement('div');
txHeader.className = 'tx-header';
let detailsDisplayedOnce = false;
txHeader.onclick = function () {
if (!detailsDisplayedOnce && details.classList.contains('closed')) {
detailsDisplayedOnce = true;
displayExternalProviders(venueAction.objectID, venueItem.externalProviderIDs);
}
toggleDetailsDropDown(details.id, operationCenterPoint);
};
var txTypeDiv = document.createElement('div');
txTypeDiv.className = 'flex-noshrink';
txHeader.append(txTypeDiv);
var txTypeIcon = document.createElement('div');
txTypeIcon.className = 'flex-noshrink wmeFdoResultTypeVenue';
txTypeDiv.append(txTypeIcon);
var txSummary = document.createElement('div');
txSummary.className = 'tx-summary';
txHeader.append(txSummary);
var txCollapse = document.createElement('div');
txCollapse.className = 'flex-noshrink tx-toggle-closed';
txHeader.append(txCollapse);
var txAuthorDate = document.createElement('div');
txAuthorDate.className = 'tx-author-date';
var txPreview = document.createElement('div');
txPreview.className = 'tx-preview';
var txName = document.createElement('h4');
//txName.className = 'type';
txAuthorDate.append(txName);
txSummary.append(txAuthorDate);
txSummary.append(txPreview);
var txContent = document.createElement('div');
txContent.className = 'tx-content wmeFdoResultDetail';
var txContentClass = document.createElement('div');
txContentClass.className = 'main-object-region tx-changes';
txContent.append(txContentClass);
var txContentInfo = document.createElement('div');
txContentInfo.className = 'related-objects-region tx-changes';
var txContentData = document.createElement('div');
var controls = document.createElement('div');
controls.className = 'wmeFdoDetailControls';
txContent.append(controls);
txContentInfo.append(txContentData);
txContent.append(txContentInfo);
details.append(txHeader);
details.append(txContent);
var venueItem = venueAction.oldValue;
if (typeof(venueItem.geometry) == 'undefined') {
// History does not contain any details for this place, other than it was deleted.
// TODO: create empty record to at least show that there was something here at one point.
console.log(`No history found for venue id ${venueAction.objectID}`);
} else {
if (venueItem.geometry.type == 'Polygon') {
var txTypeArea = document.createElement('div');
txTypeArea.className = 'flex-noshrink wmeFdoResultTypeArea';
txTypeDiv.append(txTypeArea);
}
let streetName = formatFullStreetName(venueHistory, venueItem.streetID);
let address = streetName;
if (typeof(venueItem.houseNumber) != 'undefined') {
address = venueItem.houseNumber + ' ' + address;
}
var venueName = venueItem.name;
if (typeof venueName == 'undefined' || venueName == " " || venueName == "")
{
if (typeof(venueItem.categories) != 'undefined' && venueItem.categories[0] == 'RESIDENCE_HOME') {
let resiStreet = formatStreetName(venueHistory, venueItem.streetID);
if (typeof(venueItem.houseNumber) != 'undefined') {
resiStreet = venueItem.houseNumber + ' ' + resiStreet;
}
venueName = resiStreet;
} else if (typeof(venueItem.categories) != 'undefined') {
venueName = 'unnamed ' + I18n.t("venues.categories." + venueItem.categories[0]);
} else {
venueName = 'unnamed';
//console.log('No category: ' + venueAction.objectID);
}
}
txName.innerText = venueName;
txPreview.innerHTML = streetName + '<br>Deleted by ' + username + " " + timeConverter(venueTransaction.date);
var info = document.createElement('div');
info.id = 'details-' + venueAction.objectID;
let flagControl = document.createElement('div');
flagControl.className = 'focus-buttons';
let flag = document.createElement('a');
flag.className = 'wmeFdoFlag';
if (flags['venue'][venueAction.objectID]) { flag.className = 'wmeFdoFlag flagged'; }
flag.innerHTML = '<span class="fa fa-flag"></span>';
flag.onclick = function () {
toggleFlag(flag, 'venue', venueAction.objectID);
};
flagControl.append(flag);
controls.append(flagControl);
var focusButtons = document.createElement('div');
focusButtons.className = 'focus-buttons';
var focus = document.createElement('a');
focus.className = 'focus';
focus.onclick = function () {
var lonLat = new OL.LonLat(operationCenterPoint.x, operationCenterPoint.y);
W.map.moveTo(lonLat, 6);
highlightPin(pin);
};
focusButtons.append(focus);
controls.append(focusButtons);
let lockRank = venueItem.lockRank +1;
txContentData.append(info);
let searchText = venueItem.name + " " + streetName;
var searchButton = document.createElement('button');
searchButton.textContent = 'Google';
searchButton.className = 'wmeFdoGoogleBtn btn btn-default center-block';
searchButton.addEventListener('click', function() {
window.open('https://www.google.com/search?q=' + encodeURIComponent(searchText),'_blank');
});
let recreateDiv = document.createElement('div');
recreateDiv.className = 'wmeFdoRecreate';
let recreateButton = document.createElement('a');
recreateButton.textContent = 'Recreate Place';
recreateButton.className = 'focus';
recreateButton.addEventListener('click', function() {
recreatePlace(venueItem, venueHistory, operationCenterPoint);
});
recreateDiv.append(recreateButton);
txContentData.append(searchButton);
txContentData.append(recreateDiv);
let panelHTML = '<ul>';
//panelHTML += '<ul>';
let venueIdReference = 'details-venue-id-' + venueAction.objectID;
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">Venue ID</div>';
panelHTML += '<div class="ca-description ca-preview" id="' + venueIdReference + '">';
panelHTML += '</div></li>';
if (address != null && address != "" && address != " ") {
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">Address</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += address;
panelHTML += '</div></li>';
}
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">Categories</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += formatCategories(venueItem.categories);
panelHTML += '</div></li>';
if (typeof(venueItem.description) != 'undefined') {
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">Description</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += venueItem.description;
panelHTML += '</div></li>';
}
if (typeof(venueItem.url) != 'undefined') {
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">Website</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += venueItem.url;
panelHTML += '</div></li>';
}
if (typeof(venueItem.phone) != 'undefined') {
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">Phone</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += venueItem.phone;
panelHTML += '</div></li>';
}
if (typeof(venueItem.lockRank) != 'undefined') {
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">Lock Rank</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += lockRank;
panelHTML += '</div></li>';
}
if (typeof(venueItem.externalProviderIDs) != 'undefined') {
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">External Provider IDs</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += '<div id="wmeFdoExternalProviders-' + venueAction.objectID + '"></div>';
panelHTML += '</div></li>';
}
panelHTML+= '<li class="tx-changed-attribute"><div class="ca-name">History</div>';
panelHTML += '<div class="ca-description ca-preview">';
panelHTML += formatVenueHistory(venueHistory);
panelHTML += '</div></li>';
panelHTML += '</ul>';
info.innerHTML = panelHTML;
//info.innerHTML += 'Changed from';
//info.innerHTML += '<span class="ca-value ca-value-old">';
//info.innerHTML += 'Walmart';
//info.innerHTML += '</span>';
//info.innerHTML += '<span>';
//info.innerHTML += 'to';
//info.innerHTML += '</span>';
//info.innerHTML += '<span class="ca-value ca-value-new">';
//info.innerHTML += 'Walmart Supercenter';
//info.innerHTML += '</span>';
$('#wmeFdoTransactionList').append(details);
let venueIdDiv = document.getElementById(venueIdReference);
let venueIdDisplay = document.createElement('span');
if (W.loginManager.user.userName == "Joyriding") {
venueIdDisplay.innerHTML = `<a href="https://${window.location.host}${W.Config.api_base}/ElementHistory?objectType=venue&objectID=${venueAction.objectID}" target="_blank">${venueAction.objectID}</a> `;
} else {
venueIdDisplay.innerHTML = venueAction.objectID;
}
venueIdDiv.append(venueIdDisplay);
let pin = displayPin(operation, venueAction.oldValue);
let areaPreview = null;
details.onmouseenter = function () {
highlightPin(pin);
areaPreview = showDeletedArea(operation, venueAction.oldValue);
};
details.onmouseleave = function () {
returnPin(pin);
//removeDeletedArea();
_wmeFdoFeatureLayer.removeFeatures([areaPreview]);
};
}
}
}
}
}
});
});
}
function toggleFlag (control, objectType, objectID) {
if (flags[objectType][objectID]) {
delete flags[objectType][objectID];
control.className = 'wmeFdoFlag';
} else {
flags[objectType][objectID] = true;
control.className = 'wmeFdoFlag flagged';
}
}
function displayDetails() {
}
async function recreatePlace(origVenue, venueHistory, operationCenterPoint) {
var lonLat = new OL.LonLat(operationCenterPoint.x, operationCenterPoint.y);
if(!W.map.getExtent().containsLonLat(operationCenterPoint.toLonLat())) {
// Move to pin so that the City can be populated correctly
W.map.moveTo(lonLat, 6);
await wait(1000); //TODO: Check to see that cities have loaded before continuing rather than guessing a time delay
}
let wazeActionUpdateFeatureGeometry = require("Waze/Action/UpdateFeatureGeometry");
let wazefeatureVectorLandmark = require("Waze/Feature/Vector/Landmark");
let wazeActionAddLandmark = require("Waze/Action/AddLandmark");
//console.log(origVenue);
let landmark = new wazefeatureVectorLandmark();
if (origVenue.geometry.type == 'Polygon') {
let points = [];
origVenue.geometry.coordinates[0].forEach( function(coord) {
let point = new OL.Geometry.Point(coord[0],coord[1]);
point.transform(W.map.displayProjection,W.map.projection);
points.push(point);
});
points.push(points[0]);
let linearRing = new OL.Geometry.LinearRing(points);
let polygon = new OL.Geometry.Polygon(linearRing);
landmark.geometry = polygon;
} else {
let point = new OL.Geometry.Point(origVenue.geometry.coordinates[0],origVenue.geometry.coordinates[1]);
point.transform(W.map.displayProjection,W.map.projection);
landmark.geometry = point;
}
if (typeof(origVenue.name) != 'undefined') { landmark.attributes.name = origVenue.name; }
if (typeof(origVenue.aliases) != 'undefined') { landmark.attributes.aliases = origVenue.aliases; }
if (typeof(origVenue.categories) != 'undefined') { landmark.attributes.categories = origVenue.categories; }
if (typeof(origVenue.description) != 'undefined') { landmark.attributes.description = origVenue.description; }
if (typeof(origVenue.lockRank) != 'undefined') { landmark.attributes.lockRank = origVenue.lockRank; }
if (typeof(origVenue.openingHours) != 'undefined') { landmark.attributes.openingHours = origVenue.openingHours; }
if (typeof(origVenue.phone) != 'undefined') { landmark.attributes.phone = origVenue.phone; }
if (typeof(origVenue.rank) != 'undefined') { landmark.attributes.rank = origVenue.rank; }
if (typeof(origVenue.residential) != 'undefined') { landmark.attributes.residential = origVenue.residential; }
if (typeof(origVenue.services) != 'undefined') { landmark.attributes.services = origVenue.services; }
if (typeof(origVenue.url) != 'undefined') { landmark.attributes.url = origVenue.url; }
if (origVenue.categories.indexOf('GAS_STATION') > -1 || origVenue.categories.indexOf('PARKING_LOT') > -1) {
if (typeof(origVenue.brand) != 'undefined') { landmark.attributes.brand = origVenue.brand; }
}
if (origVenue.categories.indexOf('PARKING_LOT') > -1)
{
if (typeof(origVenue.categoryAttributes) != 'undefined') { landmark.attributes.categoryAttributes = origVenue.categoryAttributes; }
}
if (typeof(origVenue.entryExitPoints) != 'undefined') { //TODO: and if # entry points > 0
// Only use first point for now until multiple are supported.
//origVenue.entryExitPoints.forEach(function(origEntryExitPoint) // Uncomment once supported
{
let origEntryExitPoint = origVenue.entryExitPoints[0]; // Remove once supported
let point = new OL.Geometry.Point(origEntryExitPoint.point.coordinates[0],origEntryExitPoint.point.coordinates[1]);
point.transform(W.map.displayProjection, W.map.projection);
let entryExitPoint = new NavigationPoint(point);
// Uncomment below once supported
//entryExitPoint._name = origEntryExitPoint.name;
//entryExitPoint._entry = origEntryExitPoint.entry;
//entryExitPoint._exit = origEntryExitPoint.exit;
//entryExitPoint._isPrimary = origEntryExitPoint.primary;
landmark.attributes.entryExitPoints.push(entryExitPoint);
}
//);
}
//debugger;
W.model.actionManager.add(new wazeActionAddLandmark(landmark));
if (typeof(origVenue.streetID) != 'undefined') {
//TODO: Make this a separate function and use for all address building, cache after built by streetID
var addressParts = {
streetName: "",
emptyStreet: false,
cityName: "",
emptyCity: false,
streetID: origVenue.streetID,
stateID: null,
countryID: null,
addressFormShown: false,
editable: true,
fullAddress: "",
ttsLocales: [W.Config.tts.default_locale],
altStreets: new Backbone.Collection,
newAltStreets: new Backbone.Collection
};
venueHistory.streets.objects.forEach(function(street) {
if (street.id == origVenue.streetID) {
if (street.name == "")
addressParts.emptyStreet = true;
addressParts.streetName = street.name;
venueHistory.cities.objects.forEach(function(city) {
if (street.cityID == city.id) {
if (city.name == "")
addressParts.emptyCity = true;
addressParts.cityName = city.name;
addressParts.stateID = city.stateID;
venueHistory.states.objects.forEach(function(state) {
if (city.stateID == state.id) {
addressParts.countryID = state.countryID;
}
});
}
});
}
});
let wazeActionUpdateFeatureAddress = require('Waze/Action/UpdateFeatureAddress');
W.model.actionManager.add(new wazeActionUpdateFeatureAddress(landmark, addressParts,{streetIDField: 'streetID'}));
}
if (typeof(origVenue.houseNumber) != 'undefined') {
let wazeActionUpdateObject = require('Waze/Action/UpdateObject');
W.model.actionManager.add(new wazeActionUpdateObject(landmark,{houseNumber: origVenue.houseNumber}));
}
//console.log(landmark);
let foundFeature = null;
W.selectionManager._layers.forEach(function(layer) {
if (layer.featureType == 'venue') {
layer.features.forEach(function(feature) {
if (landmark.geometry.id == feature.geometry.id)
{
foundFeature = feature;
}
});
}
});
if (foundFeature != null) {
W.selectionManager.selectFeature(foundFeature);
W.selectionManager._triggerSelectionChanged()
}
var epm = Backbone.Model.extend({
defaults: {
uuid: null,
name: null,
url: null,
location: null
},
initialize: function() {
if (null === this.get("uuid")) return this.set({
uuid: this.id
})
},
getDetails: function(e) {
this.set({uuid: e});
return this.set({
name: externalProviderDetails[e].name,
location: externalProviderDetails[e].geometry.location,
url: externalProviderDetails[e].url
});
},
_getDetailsFromUuid: function(e) {
return this.set({
name: this.get("uuid"),
location: "",
url: ""
})
},
toJSON: function() {
return this.get("uuid")
}
});
if (typeof(origVenue.externalProviderIDs) != 'undefined') {
let ids = [];
origVenue.externalProviderIDs.forEach(function(externalProviderID) {
let newID = new epm();
newID.getDetails(externalProviderID);
newID.collection = new Backbone.Collection();
// newID.collection.model.push(newID);
ids.push(newID);
// - Find an existing venue with an external provider.
// - If found:
// -- Copy that object to new venue
// -- Update object with data from deleted venue
//debugger;
// landmark.attributes.externalProviderIDs.push(newID);
}); //10521
let wazeActionUpdateObject = require('Waze/Action/UpdateObject');
//debugger;
if (window.location.host.includes('beta')) { //TODO: Make work in Prod, or wait for Beta to be promoted
W.model.actionManager.add(new wazeActionUpdateObject(landmark,{externalProviderIDs: ids}));
}
}
//console.log(landmark);
}
function displayExternalProviders(venueID, externalProviderIDs) {
if (typeof(externalProviderIDs) != 'undefined') {
externalProviderIDs.forEach(function(externalProviderID) {
if (typeof(externalProviderDetails[externalProviderID]) == 'undefined') {
let sessionid = '';
if (typeof(uuidGenerator) != 'undefined') {
sessionid = uuidGenerator.v1();
}
let url = `https://${window.location.host}/${W.Config.places_api.url.details}?placeid=${externalProviderID}&key=${W.apiKeys.googleMapsApiKey}&sessiontoken=${sessionid}`;
$.getJSON(url,function(data) {
//TODO: check for invalid result
let closed = data.result.permanently_closed;
let extProv = document.getElementById('wmeFdoExternalProviders-' + venueID);
let div = document.createElement('div');
div.innerHTML = '<a href="' + data.result.url + '" target="_blank">' + externalProviderID + '</a>';
if (closed) {
div.innerHTML = div.innerHTML + ' <span style="color:red;">closed</span>';
}
extProv.append(div);
externalProviderDetails[externalProviderID] = data.result;
// console.log(data);
});
} else {
let data = {};
data.result = externalProviderDetails[externalProviderID];
let closed = data.result.permanently_closed;
let extProv = document.getElementById('wmeFdoExternalProviders-' + venueID);
let div = document.createElement('div');
div.innerHTML = '<a href="' + data.result.url + '" target="_blank">' + externalProviderID + '</a>';
if (closed) {
div.innerHTML = div.innerHTML + ' <span style="color:red;">closed</span>';
}
extProv.append(div);
}
});
}
}
function toggleDetailsDropDown(elementId, operationCenterPoint) {
let details = document.getElementById(elementId);
let openDropDown = false;
if (details.classList.contains('closed')) {
openDropDown = true;
}
closeAllDetailsDropDown();
if (openDropDown) {
details.className = 'element-history-item tx-has-content';
settings.Enabled = true;
onLayerCheckboxChanged(settings.Enabled); // TODO: Fix this so the Layer menu checkbox gets updated
if(!W.map.getExtent().containsLonLat(operationCenterPoint.toLonLat())) {
W.map.moveTo(operationCenterPoint.toLonLat(), 6);
}
}
}
function openDetailsDropDown(elementId, operationCenterPoint) {
let details = document.getElementById(elementId);
details.className = 'element-history-item tx-has-content';
// var lonLat = new OL.LonLat(operationCenterPoint.x, operationCenterPoint.y);
//W.map.moveTo(operationCenterPoint.toLonLat(), 6);
}
function closeDetailsDropDown(elementId) {
let details = document.getElementById(elementId);
details.className = 'element-history-item tx-has-content tx-has-related closed';
}
function closeAllDetailsDropDown() {
let ul = document.getElementById('wmeFdoTransactionList');
let items = ul.getElementsByTagName('li');
for (var i = 0; i < items.length; ++i) {
let elementId = items[i].id;
if (elementId.startsWith('entry-')) {
closeDetailsDropDown(elementId);
}
}
}
function displayPin(transactionOperation, deletedVenue) {
let deletedPlacePt=new OL.Geometry.Point(transactionOperation.objectCentroid.coordinates[0], transactionOperation.objectCentroid.coordinates[1]);
deletedPlacePt.transform(W.map.displayProjection, W.map.projection);
let point = new OL.Geometry.Point(deletedPlacePt.x, deletedPlacePt.y);
let style = {strokeColor: 'black',
strokeWidth: '5',
strokeDashstyle: 'solid',
pointRadius: '5',
fillOpacity: '1'};
let feature = new OL.Feature.Vector(point, {id:transactionOperation.objectID}, style);
var di = require("Waze/DivIcon");
var iconA = new di("place-update add_venue low map-marker wmeFdo-place-delete");
var lonlatA = new OL.LonLat(deletedPlacePt.toLonLat().lon, deletedPlacePt.toLonLat().lat);
// let markerLayer = W.map.getLayerByUniqueName('__wmeFdoMarkerLayer');
let marker = new OL.Marker(lonlatA, iconA);
marker.id = 1;
marker.events.register('click', marker, function(evt) {
W.selectionManager.unselectAll();
selectTab();
let elementId = 'entry-' + transactionOperation.objectID;
closeAllDetailsDropDown();
openDetailsDropDown(elementId, deletedPlacePt);
document.getElementById(elementId).scrollIntoView();
});
_wmeFdoFeatureLayer.addFeatures([feature]);
_wmeFdoMarkerLayer.addMarker(marker);
return feature;
}
function showDeletedArea(transactionOperation, deletedVenue) {
let polygon = null;
if (deletedVenue.geometry.type == 'Polygon') {
let points = [];
deletedVenue.geometry.coordinates[0].forEach( function(coord) {
let point = new OL.Geometry.Point(coord[0],coord[1]);
point.transform(W.map.displayProjection,W.map.projection);
points.push(point);
});
points.push(points[0]);
let linearRing = new OL.Geometry.LinearRing(points);
polygon = new OL.Geometry.Polygon(linearRing);
}
let style = {strokeColor: 'orange',
strokeWidth: '4',
strokeDashstyle: 'solid',
fillOpacity: '0.2'};
let feature = new OL.Feature.Vector(polygon, {id:transactionOperation.objectID}, style);
_wmeFdoFeatureLayer.addFeatures([feature]);
return feature;
}
function getParentCategory(category) {
// Build subcategory > parent category mapping once
if (subcategoryToParentCategories.length == 0) {
let index = 0;
Object.keys(W.Config.venues.subcategories).forEach(function(parent) {
let parentName = Object.getOwnPropertyNames(W.Config.venues.subcategories)[index];
subcategoryToParentCategories[parentName] = parentName;
W.Config.venues.subcategories[parentName].forEach(function(subcategory) {
subcategoryToParentCategories[subcategory] = parentName;
});
index++;
});
}
return subcategoryToParentCategories[category];
}
function getCategoryIconClass(category) {
let parentCategory = getParentCategory(category);
// TODO: Lowercase and replace '_' with '-' instead?
switch(parentCategory) {
case 'TRANSPORTATION':
return 'transportation';
break;
case 'PROFESSIONAL_AND_PUBLIC':
return 'professional-and-public';
break;
case 'SHOPPING_AND_SERVICES':
return 'shopping-and-services';
break;
case 'FOOD_AND_DRINK':
return 'food-and-drink';
break;
case 'CULTURE_AND_ENTERTAINEMENT':
return 'culture-and-entertainement';
break;
case 'LODGING':
return 'lodging';
break;
case 'OUTDOORS':
return 'outdoors';
break;
case 'NATURAL_FEATURES':
return 'natural-features';
break;
case 'PARKING_LOT':
return 'parking-lot';
default:
return 'OTHER';
}
// WME CSS Example:
// #edit-buttons .transportation .item-icon::after {
// background-image: url(//editor-assets.waze.com/production/img/toolbare2f6b31….png);
// background-position: -13px -70px;
// width: 12px;
// height: 12px;
// }
}
function formatStreetName(venueHistory, streetId) {
// TODO: replace with address cache lookup/build function
let streetName = null;
venueHistory.streets.objects.forEach(function(street) {
if (street.id == streetId) {
streetName = street.name;
}
});
if (streetName == null) {
streetName = "";
}
return streetName;
}
function formatFullStreetName(venueHistory, streetId) {
// TODO: replace with address cache lookup/build function
let streetName = null;
venueHistory.streets.objects.forEach(function(street) {
if (street.id == streetId) {
streetName = street.name;
venueHistory.cities.objects.forEach(function(city) {
if (street.cityID == city.id) {
if (streetName != '') {
streetName = streetName + ", ";
}
streetName = streetName + city.name;
venueHistory.states.objects.forEach(function(state) {
if (city.stateID == state.id) {
if (city.name != '') {
streetName = streetName + ", ";
}
streetName = streetName + state.name;
}
});
}
});
}
});
if (streetName == null) {
streetName = "";
}
return streetName;
}
function formatCategories(categories) {
let output = ''
categories.forEach(function(category) {
output = output + ", " + I18n.t("venues.categories." + category);
});
output = output.substring(2);
return output;
}
function formatExternalProviders(externalProviderIDs) {
let output = "<ul>";
if (typeof externalProviderIDs != 'undefined') {
externalProviderIDs.forEach(function(externalProviderID) {
output = output + "<li>" + externalProviderID + "</ul>";
});
}
output = output + "</ul>";
return output;
}
function formatVenueHistory(venueHistory) {
let output = "<ul>";
venueHistory.transactions.objects.forEach(function(venueTransaction) {
let username = null;
venueHistory.users.objects.forEach( function(user) {
if (user.id == venueTransaction.userID) {
let userRank = user.rank + 1;
let name = user.userName + '(' + userRank + ')';
username = `<a target="_blank" href="https://${window.location.host}/user/editor/${user.userName}">${name}</a>`;
}
});
let detailCount = 0;
let requestType = venueTransaction.actionType;
if (venueTransaction.objects[0].objectType == 'venueUpdateRequest') {
requestType = requestType + " (PUR)";
}
output = output + "<li><div>" + timeConverter(venueTransaction.date) + " " + requestType + " " + username + "</div>";
output = output + '<ul class="historySummaryItem">';
if (typeof(venueTransaction.objects[0].newValue) != 'undefined' && typeof(venueTransaction.objects[0].newValue.name) != 'undefined')
{
detailCount++;
output = output + '<li>Name: ' + venueTransaction.objects[0].newValue.name + '</li>';
if (venueTransaction.objects[0].actionType == 'UPDATE') {
output = output + '<li>Was: ' + venueTransaction.objects[0].oldValue.name + '</li>';
}
}
if (typeof(venueTransaction.objects[0].oldValue) != 'undefined' && venueTransaction.objects[0].oldValue.type == 'IMAGE') {
output = output + `<li><a target="_blank" href="https://venue-image.waze.com/${venueTransaction.objects[0].oldValue.id}">Rejected Photo</a></li>`;
}
output = output + '</ul>';
if (detailCount > 0) {
output = output + '</li style="margin-bottom:4px">';
} else {
output = output + "</li>";
}
// console.log(venueTransaction);
});
output = output + "</ul>";
return output;
}
function endScan(reasonText, setEndedFlag) {
if (setEndedFlag) {
var findButton = document.getElementById('wmeFdoFindButton');
findButton.className = 'btn btn-success center-block';
var cancelButton = document.getElementById('wmeFdoCancelButton');
cancelButton.className = 'btn btn-warning center-block hidden';
$('#wmeFdoTabFind').data("status","ended");
let tab = document.getElementById('wmeFdoTab');
tab.innerHTML = 'FiDO <span class="spinner-disable"><i class="icon-spinner icon-spin fa fa-spinner fa-spin"></i></span>';
}
$('#wmeFdoStatusDate')[0].innerText = reasonText;
}
async function findObjects() {
//var centerCoords = W.map.getCenter().clone().transform(W.map.projection, W.map.displayProjection);
if (settings.NearbyEditors) {
let editorListScreen = getNearbyEditors();
let featuresList = await getScreenFeatures();
// console.log(featuresList);
// debugger;
//console.log(featuresList[0].venues);
let editorListFeatures = getNearbyEditorsFromFeatures(featuresList);
let editorListTemp = [];
editorListScreen.forEach(function(userID) {
editorListTemp[userID] = true;
});
editorListFeatures.forEach(function(userID) {
editorListTemp[userID] = true;
});
let editorList = [];
Object.keys(editorListTemp).forEach(function(userID) {
editorList.push(userID);
});
let searchAreaGeometry = getSearchArea();
editorList.forEach(function (userID) {
//console.log('userID: ' + userID);
var lookFor = {
objectType:'Venue',
actionType:'DELETE',
searchArea: searchAreaGeometry,
limitToScreen: true,
includeSelf: true
}
Date.prototype.addDays = function(days) {
var date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
}
let startDate = null;
let startDateInput = document.getElementById('wmeFdoFindDate');
if (Date.parse(startDateInput.value) != null) {
let dateInput = new Date(startDateInput.value).addDays(1);
startDate = dateToUuid(dateInput);
}
var transactionLookup = {
username:null,
userId:userID,
nextTransactionDate:startDate,
iteration:0,
maxIterations:100000
};
beginFind(lookFor, transactionLookup);
});
} else {
var searchAreaGeometry = getSearchArea();
var lookFor = {
objectType:'Venue',
actionType:'DELETE',
searchArea: searchAreaGeometry,
limitToScreen: settings.LimitToScreen,
includeSelf: settings.IncludeSelf
}
Date.prototype.addDays = function(days) {
var date = new Date(this.valueOf());
date.setDate(date.getDate() + days);
return date;
}
let startDate = null;
let startDateInput = document.getElementById('wmeFdoFindDate');
if (Date.parse(startDateInput.value) != null) {
let dateInput = new Date(startDateInput.value).addDays(1);
startDate = dateToUuid(dateInput);
}
var transactionLookup = {
username:$('#wmeFdoEditorName')[0].value,
userId:null,
nextTransactionDate:startDate,
iteration:0,
maxIterations:100000
};
if (transactionLookup.username == null || transactionLookup.username == "") {
endScan('Please enter an editor name!', true);
} else {
let requestParamsUserProfile = requestParams(getApiUrlUserProfile(transactionLookup.username));
requestStatus[requestParamsUserProfile.url] = defaultRequestStatus();
var userProfile = await getApiRequest(requestParamsUserProfile);
if (typeof(userProfile.userID) == 'undefined') {
endScan('Editor name not found!', true);
} else {
transactionLookup.userId = userProfile.userID;
beginFind(lookFor, transactionLookup);
}
}
}
}
function getSearchArea() {
var theVenue = null;
var count = 0;
for (var v in W.model.venues.objects) {
if (W.model.venues.objects.hasOwnProperty(v) === false) {
continue;
}
var venue = W.model.venues.objects[v];
if (venue.isPoint() === true) {
continue;
}
if ($.isNumeric(venue.attributes.id) && parseInt(venue.attributes.id) <= 0) {
theVenue = venue;
count++;
}
}
if (count === 0) {
console.log("using screen");
return W.map.getExtent().toGeometry();
}
if (theVenue.geometry.components.length !== 1) {
alert("Can't parse the geometry");
return;
} else {
console.log("using unsaved place area");
return theVenue.geometry.clone();
}
}
function getNearbyEditors() {
$('#wmeFdoStatusDate')[0].innerText = 'Finding Nearby Editors...';
let earliestDate = parseInt(new Date('2016-12-31').getTime());
let editorList = [];
let editorListReturn = [];
Object.keys(W.model.venues.objects).forEach(function (venueId) {
let venue = W.model.venues.objects[venueId].attributes;
if (typeof(venue.createdOn) != 'undefined' && venue.createdOn > earliestDate) {
editorList[venue.createdBy] = venue.createdOn;
}
if (typeof(venue.updatedOn) != 'undefined' && venue.updatedOn > earliestDate) {
editorList[venue.updatedBy] = venue.updatedBy;
}
//console.log(W.model.venues.objects[venueId].attributes.createdBy)
});
Object.keys(W.model.segments.objects).forEach(function (segmentId) {
let segment = W.model.segments.objects[segmentId].attributes;
if (typeof(segment.createdOn) != 'undefined' && segment.createdOn > earliestDate) {
editorList[segment.createdBy] = segment.createdOn;
}
if (typeof(segment.updatedOn) != 'undefined' && segment.updatedOn > earliestDate) {
editorList[segment.updatedBy] = segment.updatedBy;
}
//console.log(W.model.venues.objects[venueId].attributes.createdBy)
});
Object.keys(editorList).forEach(function (editorId) {
if (editorId != 'undefined') {
editorListReturn.push(editorId);
}
});
return editorListReturn;
}
function getNearbyEditorsFromFeatures(featuresList) {
$('#wmeFdoStatusDate')[0].innerText = 'Finding Nearby Editors...';
let earliestDate = parseInt(new Date('2016-12-31').getTime());
let editorList = [];
let editorListReturn = [];
featuresList.forEach(function (features) {
if (typeof(features.venues) != 'undefined') {
features.venues.objects.forEach(function (venue) {
if (typeof(venue.createdOn) != 'undefined' && venue.createdOn > earliestDate) {
editorList[venue.createdBy] = venue.createdOn;
}
if (typeof(venue.updatedOn) != 'undefined' && venue.updatedOn > earliestDate) {
editorList[venue.updatedBy] = venue.updatedBy;
}
});
}
if (typeof(features.segments) != 'undefined') {
features.segments.objects.forEach(function (segment) {
if (typeof(segment.createdOn) != 'undefined' && segment.createdOn > earliestDate) {
editorList[segment.createdBy] = segment.createdOn;
}
if (typeof(segment.updatedOn) != 'undefined' && segment.updatedOn > earliestDate) {
editorList[segment.updatedBy] = segment.updatedBy;
}
});
}
});
Object.keys(editorList).forEach(function (editorId) {
if (editorId != 'undefined') {
editorListReturn.push(editorId);
}
});
return editorListReturn;
}
async function getScreenFeatures() {
return new Promise( async resolve => {
let urlList = [];
let featuresList = [];
let maxDegrees = 0.125;
let minDegrees = 0.0625;
let extent = W.map.getExtent().transform(W.map.projection,W.map.displayProjection);
//NW: LT - left top
//NE: RT - right top
//SW: LB - left bottom
//SE: RB - right bottom
let geoLT = new OL.Geometry.Point(extent.left,extent.top);
let geoRB = new OL.Geometry.Point(extent.right,extent.bottom);
let geoLTSplit = new OL.Geometry.Point(geoLT.x,geoLT.y);
let geoRBSplit = new OL.Geometry.Point(geoRB.x,geoRB.y);
let geoTempY = new OL.Geometry.Point(geoLT.x,geoLT.y);
let xSplit = geoLT.x;
let ySplit = geoLT.y;
//console.log(extent);
//console.log(geoLT);
//console.log(geoRB);
while (ySplit >= geoRB.y) {
geoTempY.y = geoTempY.y - maxDegrees;
ySplit = geoTempY.y;
let degreesFromGeoRBY = geoRB.y - ySplit;
//debugger;
if (ySplit > geoRB.y)
geoRBSplit.y = ySplit
else if (degreesFromGeoRBY <= minDegrees)
geoRBSplit.y = ySplit - (minDegrees - degreesFromGeoRBY);
else
geoRBSplit.y = geoRB.y;
while (xSplit <= geoRB.x) {
geoTempY.x = geoTempY.x + maxDegrees;
xSplit = geoTempY.x;
let degreesFromGeoRBX = geoRB.x - xSplit;
if (xSplit > geoRB.x)
geoRBSplit.x = xSplit
else if (degreesFromGeoRBX <= minDegrees)
geoRBSplit.x = xSplit - (minDegrees - degreesFromGeoRBX);
else
geoRBSplit.x = geoRB.x;
// let bboxGeoLT = geoLTSplit.clone();
// let bboxGeoEB = geoEBSplit.clone();
let bbox = `${geoLTSplit.x},${geoLTSplit.y},${geoRBSplit.x},${geoRBSplit.y}`;
let url = getApiUrlFeatures(bbox);
urlList.push(url);
//console.log(url);
let params = requestParams(url);
requestStatus[url] = defaultRequestStatus();
let features = null;
features = await getApiRequest(params);
featuresList.push(features);
geoLTSplit.x = xSplit;
}
geoLTSplit.y = ySplit;
geoLTSplit.x = geoLT.x;
xSplit = geoLT.x;
geoTempY.x = xSplit;
}
resolve(featuresList);
});
}
async function getApiRequest(requestParams) {
let currentTime = Date.now();
//console.log(requestParams.delay);
requestStatus[requestParams.url].lastAttempt = currentTime;
requestStatus[requestParams.url].status = 'waiting';
// delay semi-randomized by using the last two digits of the hashcode of the url
let delayTimeMs = requestParams.delay + requestParams.iteration;
let rateLimitAttempt = 0;
while (currentTime - rateLimitLastCall < getCurrentRateLimit() && rateLimitAttempt < 200) {
// Attempt to rate limit requests by holding current request until configured amount of time has elapsed since last request.
rateLimitAttempt++;
let difference = currentTime - rateLimitLastCall;
if (delayTimeMs > 400) {
console.log("delay > 400 " + requestParams);
}
await wait(delayTimeMs);
currentTime = Date.now();
}
//if (rateLimitAttempt == 100) {
// console.log("max attempts hit");
//} else if (rateLimitAttempt == 0) {
// let diff = currentTime - rateLimitLastCall;
// console.log("did not rate limit (" + diff + ") " + requestParams.url);
//}
rateLimitLastCall = Date.now();
requestStatus[requestParams.url].attempts++;
requestStatus[requestParams.url].lastAttempt = Date.now();
requestStatus[requestParams.url].status = 'requested';
return new Promise( resolve => {
$.ajax({
type: 'GET',
url: requestParams.url,
success: function(data) {
adjustRateLimitDown();
requestStatus[requestParams.url].status = 'successful';
resolve(data);
},
statusCode: {
429: function() {
adjustRateLimitUp();
requestStatus[requestParams.url].status = 'error: rate limit';
console.log('Rate Limited: attempt ' + requestParams.attempts + " new delay: " + rateLimitAddedDelay);
resolve({"error": true,reason:"rate limit"});
},
500: function() {
resolve({"error":true,reason:"error"});
}
}
});
});
}
function resetRateLimit() {
rateLimitAddedDelay = 0;
console.log(`Rate Limit reset: ${getCurrentRateLimit()}ms`);
}
function getCurrentRateLimit() {
return rateLimitBaseDelay + rateLimitAddedDelay;
}
function adjustRateLimitDown() {
let currentTime = Date.now();
if (rateLimitAddedDelay > 0 && currentTime - rateLimitLastModified < 5000) {
rateLimitAddedDelay -= rateLimitDelayStepDown;
rateLimitLastModified = currentTime;
console.log(`New Rate Limit (lowered): ${getCurrentRateLimit()}ms`);
}
}
function adjustRateLimitUp() {
let currentTime = Date.now();
rateLimitAddedDelay += rateLimitDelayStepUp;
rateLimitLastModified = currentTime;
console.log(`New Rate Limit (raised): ${getCurrentRateLimit()}ms`);
}
function getApiUrlUserProfile(username) {
return `https://${window.location.host}${W.Config.api_base}/UserProfile/Profile?username=${username}`;
}
function getApiUrlTransactions(userId, nextTransactionDate) {
let url = `https://${window.location.host}${W.Config.api_base}/UserProfile/Transactions?userID=${userId}`;
if (nextTransactionDate != null) {
url = url + '&till=' + nextTransactionDate;
}
return url;
}
function getApiUrlElementHistory(objectType, objectId, nextTransactionDate) {
let url = `https://${window.location.host}${W.Config.api_base}/ElementHistory?objectType=${objectType}&objectID=${objectId}`;
if (nextTransactionDate != null) {
url = url + '&till=' + nextTransactionDate;
}
return url;
}
function getApiUrlFeatures(bbox) {
//let bbox = '-77.636232%2C43.152936%2C-77.6232%2C43.160287';
let url = `https://${window.location.host}${W.Config.api_base}/Features?language=en-US&bbox=${bbox}&roadTypes=2%2C3%2C4%2C6%2C7%2C8%2C9%2C10%2C11%2C12%2C13%2C14%2C15%2C16%2C17%2C18%2C19%2C20%2C21%2C22&venueLevel=4&venueFilter=3%2C3%2C3`;
return url;
}
async function highlightPin(pin) {
if (pin.onScreen()) {
let layer = W.map.getLayerByUniqueName('__wmeFdoFeatureLayer');
let enableAnimation = false;
if (enableAnimation) {
pin.data.mouseout = false;
pin.style.strokeColor = 'red';
for (var i=100;i>=1;i--) {
await wait(10);
pin.style.strokeWidth = i;
layer.redraw();
if (pin.data.mouseout == true) {
i = 1;
returnPin(pin);
}
}
pin.style.strokeWidth = 4;
pin.style.pointRadius = 5;
pin.style.strokeColor = 'orange';
layer.redraw();
if (pin.data.mouseout == true) {
returnPin(pin);
}
} else {
pin.style.strokeWidth = 4;
pin.style.pointRadius = 5;
pin.style.strokeColor = 'orange';
layer.redraw();
}
}
}
function returnPin(pin) {
let style = {strokeColor: 'black',
strokeWidth: '4',
strokeDashstyle: 'solid',
pointRadius: '4',
fillOpacity: '1'};
if (pin.onScreen()) {
let layer = W.map.getLayerByUniqueName('__wmeFdoFeatureLayer');
pin.data.mouseout = true;
//pin.style.strokeColor = 'black';
//pin.style.strokeWidth = 5;
pin.style = style;
layer.redraw();
}
}
function createSettingsCheckbox($div, settingID, textDescription) {
let $checkbox = $('<input>', {type:'checkbox', id:settingID, class:'wmeFdoSettingsCheckbox'});
$div.append(
$('<div>', {class:'controls-container'}).css({paddingTop:'2px'}).append(
$checkbox,
$('<label>', {for:settingID}).text(textDescription).css({whiteSpace:'pre-line'})
)
);
return $checkbox;
}
function setChecked(checkboxId, checked) {
$('#' + checkboxId).prop('checked', checked);
}
function saveSettings() {
if (localStorage) {
var localsettings = {
Enabled: settings.Enabled,
IncludeSelf: settings.IncludeSelf,
LimitToScreen: settings.LimitToScreen,
NearbyEditors: settings.NearbyEditors
};
localStorage.setItem("wmeFdo_Settings", JSON.stringify(localsettings));
}
}
function loadSettings() {
var loadedSettings = $.parseJSON(localStorage.getItem("wmeFdo_Settings"));
var defaultSettings = {
Enabled: true,
IncludeSelf: true,
LimitToScreen: true,
NearbyEditors: true
};
settings = loadedSettings ? loadedSettings : defaultSettings;
for (var prop in defaultSettings) {
if (!settings.hasOwnProperty(prop))
settings[prop] = defaultSettings[prop];
}
}
function prepareTab() {
let tabs = document.getElementById('user-tabs');
let items = tabs.getElementsByTagName('li');
for (var i = 0; i < items.length; ++i) {
let a = items[i].getElementsByTagName('a')[0]
if (a.href.includes('sidepanel-fido')) {
a.id = "wmeFdoTab";
a.innerHTML = 'FiDO <span class="spinner-disable"><i class="icon-spinner icon-spin fa fa-spinner fa-spin"></i></span>';
}
}
}
function selectTab() {
let tabs = document.getElementById('user-tabs');
let items = tabs.getElementsByTagName('li');
for (var i = 0; i < items.length; ++i) {
let a = items[i].getElementsByTagName('a')[0]
if (a.href.includes('sidepanel-fido')) {
items[i].getElementsByTagName('a')[0].click();
}
}
}
function dateToUuid(inputDate) {
let timestamp = parseInt(new Date(inputDate).getTime());
// uuid = "a02102cd-19df-11e9-bd87-1201fde9baf6"
// timestamp = 1547678386643;
let a = timestamp * 10000;
let b = a + 122192928000000000;
let c = b.toString(16);
//if (c.length % 2) {
// c = '0' + c;
//}
let d = c.substring(7) + '-' + c.substring(3,7) + '-1' + c.substring(0,3) + '-bd87-1201fde9baf6';
return d;
}
function get_time_int(uuid_str) {
var uuid_arr = uuid_str.split( '-' ),
time_str = [
uuid_arr[ 2 ].substring( 1 ),
uuid_arr[ 1 ],
uuid_arr[ 0 ]
].join( '' );
return parseInt( time_str, 16 );
};
function uuidToDate(uuid_str) {
var int_time = get_time_int( uuid_str ) - 122192928000000000,
int_millisec = Math.floor( int_time / 10000 );
//return new Date( int_millisec );
return timeConverter(int_millisec);
};
function formatCurrentDate() {
var today = new Date();
var dd = today.getDate();
var mm = today.getMonth() + 1; //January is 0!
var yyyy = today.getFullYear();
if (dd < 10) {
dd = '0' + dd;
}
if (mm < 10) {
mm = '0' + mm;
}
return yyyy + '-' + mm + '-' + dd;
}
function timeConverter(UNIX_timestamp){
var a = new Date(UNIX_timestamp);
var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
var year = a.getFullYear();
var month = months[a.getMonth()];
var date = a.getDate();
if (date.toString().length == 1) {
date = "0" + date;
}
var hour = a.getHours();
if (hour.toString().length == 1) {
hour = "0" + hour;
}
var min = a.getMinutes();
if (min.toString().length == 1) {
min = "0" + min;
}
var sec = a.getSeconds();
if (sec.toString().length == 1) {
sec = "0" + sec;
}
//Dec 08, 2018
var time = month + ' ' + date + ', ' + year + ' ' + hour + ':' + min;
return time;
}
async function wait(ms) {
return new Promise(resolve => {
setTimeout(resolve, ms);
});
}
bootstrap();
})();