From 1139870e5c42d0bd22afe5761447dbf5fa004b7e Mon Sep 17 00:00:00 2001 From: Dave Alverson Date: Wed, 10 Jun 2026 10:42:33 -0400 Subject: [PATCH] lots of changes for SDK; use turf for geom calcs/ops --- 99.build.sh | 2 +- meta/meta-begin.js | 8 +- meta/wme-externs.js | 34 ++ src/basic.js | 137 ++++- src/data.js | 23 +- src/helpers.js | 17 +- src/login.js | 175 +++--- src/other.js | 427 +++++++++------ src/release.js | 12 +- src/report.js | 84 +-- src/validate.js | 1270 +++++++++++++++++++++---------------------- 11 files changed, 1203 insertions(+), 986 deletions(-) diff --git a/99.build.sh b/99.build.sh index 7e65c65..224f041 100644 --- a/99.build.sh +++ b/99.build.sh @@ -31,7 +31,7 @@ echo cat "${SRC_DIR}/meta/i18n-end.js" >> "${LOC_FILE}" ${COMPILER} \ - --language_in ECMASCRIPT_2017 \ + --language_in ECMASCRIPT_2020 \ --js "${SRC_DIR}/src/release.js" \ --js "${LOC_FILE}" \ --js "${SRC_DIR}/src/helpers.js" \ diff --git a/meta/meta-begin.js b/meta/meta-begin.js index 8451e92..17c40a7 100644 --- a/meta/meta-begin.js +++ b/meta/meta-begin.js @@ -1,15 +1,16 @@ // ==UserScript== // @name WME Validator -// @version 2025.02.26 +// @version 2026.06.09 // @description This script validates a map area in Waze Map Editor, highlights issues and generates a very detailed report with wiki references and solutions // @match https://beta.waze.com/*editor* // @match https://www.waze.com/*editor* // @exclude https://www.waze.com/*user/*editor/* // @exclude https://www.waze.com/discuss/* // @grant none +// @require https://cdn.jsdelivr.net/npm/@turf/turf@7/turf.min.js // @icon https://raw.githubusercontent.com/WMEValidator/release/master/img/WV-icon96.png // @namespace a -// @homepage https://www.waze.com/forum/viewtopic.php?f=819&t=76488 +// @homepage https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877 // @author Andriy Berestovskyy // @copyright 2013-2018 Andriy Berestovskyy // @license GPLv3 @@ -19,6 +20,7 @@ // @contributor Glodenox // @contributor DaveAcincy // ==/UserScript== +/* global turf */ /* * WME Validator uses Open Source GPLv3 license, i.e. you may copy, * distribute and modify the software as long as you track changes/dates @@ -30,7 +32,7 @@ * https://github.com/WMEValidator/ * * For questions please use official forum: - * https://www.waze.com/forum/viewtopic.php?f=819&t=76488 + * https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877 * * Report bugs on GitHub Issues Tracker: * https://github.com/WMEValidator/validator/issues diff --git a/meta/wme-externs.js b/meta/wme-externs.js index 7c45211..d2a66c7 100644 --- a/meta/wme-externs.js +++ b/meta/wme-externs.js @@ -521,6 +521,9 @@ window.viewHelpers = { formatRank: function (r) { } }; window.require = {}; +window.SDK_INITIALIZED = {}; +var getWmeSdk = function(e) { }; +var turf = {}; /////////////////////////////////////////////////////////////////////////// // Other externs @@ -537,3 +540,34 @@ Error.prepareStackTrace = function (a, b) { }; var WME_Validator_I18n = {}; window.WME_Validator_I18n = {}; + +var wmeSDKref = { + DataModel: { + Cities: { + getById: function () { }, + }, + Countries: { + getById: function () { }, + }, + States: { + getById: function () { }, + }, + Streets: { + getById: function () { }, + }, + }, + Editing: { + getSelection: function () { }, + }, + Events: { + on: function () { }, + once: function () { }, + }, + Sidebar: { + registerScriptTab: function () { }, + }, + State: { + getUserInfo: function () { }, + isLoggedIn: function () { }, + }, +} diff --git a/src/basic.js b/src/basic.js index 43c47b3..d60715b 100644 --- a/src/basic.js +++ b/src/basic.js @@ -80,7 +80,7 @@ function escRE(e) { * @param {boolean=} newLine */ function getMsg(mType, msg, newLine) { - return "WME Validator v" + WV_VERSION + return "Validator" + (mType ? " " + mType : "") + (msg ? ":" + (newLine ? "\n" : " ") @@ -94,6 +94,17 @@ function getMsg(mType, msg, newLine) { function log(msg) { window.console.log(getMsg("", msg)); } +function tlog(message, data = '') { + //if (!debug) return; + + const t = new Date; + const h = t.getHours(); + const m = t.getMinutes(); + const s = t.getSeconds(); + const ms = `${t.getMilliseconds()}`.padStart(3, '0'); + + console.log(`${h}:${m}:${s}.${ms} VAL: ${message}`, data); +} /** * Show error message @@ -300,8 +311,12 @@ function ForceHLAllObjects() { * This is used to wait for DOM to populate before filling in problem details in left panel. */ function delayForceHLAllObjects(e) { - const ldf = nW.app.layout.model.attributes.loadingFeatures; - if (ldf) { + const ldf = W.app.attributes.loadingFeatures; + const ae = document.getElementsByClassName("address-edit"); + const selection = wmeSDK.Editing.getSelection(); + let needLeftP = false; + if (ae.length == 0 && selection && selection.ids.length > 0 && ((selection.objectType == "segment") || (selection.objectType == "venue"))) { needLeftP = true; } + if (ldf || needLeftP) { setTimeout(function () { delayForceHLAllObjects(e); }, 50); } else { ForceHLAllObjects(); } @@ -476,23 +491,23 @@ function checkFilter(severity, objectCopy, seenObjects) { && _UI.pMain.pFilter.oExcludeNotes.CHECKED) return false; - if (objectCopy.$userID !== _RT.$topUser.$userID + if (objectCopy.$userName !== _RT.$topUser.$userName && !_UI.pMain.pSearch.oIncludeYourEdits.NODISPLAY && _UI.pMain.pSearch.oIncludeYourEdits.CHECKED) return false; if (!_UI.pMain.pSearch.oIncludeUpdatedBy.NODISPLAY && _UI.pMain.pSearch.oIncludeUpdatedBy.VALUE) { - var cache = _RT.$includeUpdatedByCache; - var hash = objectCopy.$userID; + let cache = _RT.$includeUpdatedByCache; + let hash = objectCopy.$userID; if (hash in cache) { if (!cache[hash]) return false; } else { - var forUser = _UI.pMain.pSearch.oIncludeUpdatedBy.VALUE; - var curUser = _REP.$users[objectCopy.$userID]; + let forUser = _UI.pMain.pSearch.oIncludeUpdatedBy.VALUE; + let curUser = _REP.$users[objectCopy.$userName]; try { cache[hash] = false; // check if the user tries to match another user @@ -536,23 +551,23 @@ function checkFilter(severity, objectCopy, seenObjects) { if (!objectCopy.$cityID) return false; - var cache = _RT.$includeCityNameCache; - var hash = objectCopy.$cityID; + let cache = _RT.$includeCityNameCache; + let hash = objectCopy.$cityID; if (hash in cache) { if (!cache[hash]) return false; } else { - var forCity = _UI.pMain.pSearch.oIncludeCityName.VALUE; - var curCity = _REP.$cities[objectCopy.$cityID]; + let forCity = _UI.pMain.pSearch.oIncludeCityName.VALUE; + let curCity = _REP.$cities[objectCopy.$cityID]; try { cache[hash] = false; if (!_WV.checkAccessFor(forCity, function (e) { // escape user input e = escRE(e); - var r = new RegExp("^" + e + "$", "i"); + let r = new RegExp("^" + e + "$", "i"); return r.test(curCity); }) ) @@ -714,6 +729,14 @@ function onMoveEnd(e) { else delayForceHLAllObjects(e); } +function onZoomEnd(e) { + //showTimes('onZoomEnd'); + delayForceHLAllObjects(e); +} +function onSelChanged(e) { + //showTimes('onSelChanged'); + delayForceHLAllObjects(e); +} /** * Load Start Handler @@ -728,11 +751,65 @@ function onLoadStart() { function onChangeLayer(e) { sync(F_ONCHANGELAYER, e); } +function onObjectsChanged(e) { + //const ln = e.objectIds.length; + //const tx = ln == 0 ? '' : ', id: ' + e.objectIds[0]; + //tlog(e.dataModelName + ' objects changed, count: ' + ln + tx); + if (e.dataModelName == 'segments') { + _RT.$isMapChanged = true; + sync(F_ONSEGMENTSCHANGED, e.objectIds); + } + else if (e.dataModelName == 'venues') { + _RT.$isMapChanged = true; + sync(F_ONVENUESCHANGED, e.objectIds); + } + else if (e.dataModelName == 'nodes') { + _RT.$isMapChanged = true; + sync(F_ONNODESCHANGED, e.objectIds); + } +} +function onObjectsRemoved(e) { + //const ln = e.objectIds.length; + //const tx = ln == 0 ? '' : ', id: ' + e.objectIds[0]; + //tlog(e.dataModelName + ' objects removed, count: ' + ln + tx); + if (e.dataModelName == 'segments') { + _RT.$isMapChanged = true; + if (1 === e.objectIds.length) { + if (RTStateIs(ST_STOP) || RTStateIs(ST_PAUSE)) { + sync(F_ONSEGMENTSCHANGED, e.objectIds); + } + } + } + else if (e.dataModelName == 'venues') { + _RT.$isMapChanged = true; + if (1 === e.objectIds.length) { + if (RTStateIs(ST_STOP) || RTStateIs(ST_PAUSE)) { + sync(F_ONVENUESCHANGED, e.objectIds); + } + } + } + else if (e.dataModelName == 'nodes') { + _RT.$isMapChanged = true; + if (1 === e.objectIds.length) { + if (RTStateIs(ST_STOP) || RTStateIs(ST_PAUSE)) { + sync(F_ONNODESCHANGED, e.objectIds); + } + } + } +} +function onObjectsAdded(e) { + //const ln = e.objectIds.length; + //const tx = ln == 0 ? '' : ', id: ' + e.objectIds[0]; + //tlog(e.dataModelName + ' objects added, count: ' + ln + tx); + if (e.dataModelName == 'segments' || e.dataModelName == 'venues') { + _RT.$isMapChanged = true; + } +} /** * Segments Changed Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onSegmentsChanged(e) { _RT.$isMapChanged = true; sync(F_ONSEGMENTSCHANGED, e); @@ -741,7 +818,7 @@ function onSegmentsChanged(e) { /** * Segments Removed Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onSegmentsRemoved(e) { _RT.$isMapChanged = true; if (1 === e.length) @@ -752,7 +829,7 @@ function onSegmentsRemoved(e) { /** * Segments Added Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onSegmentsAdded(e) { _RT.$isMapChanged = true; } @@ -760,7 +837,7 @@ function onSegmentsAdded(e) { /** * Nodes Changed Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onNodesChanged(e) { _RT.$isMapChanged = true; sync(F_ONNODESCHANGED, e); @@ -769,7 +846,7 @@ function onNodesChanged(e) { /** * Nodes Removed Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onNodesRemoved(e) { _RT.$isMapChanged = true; if (1 === e.length) @@ -781,25 +858,29 @@ function onNodesRemoved(e) { * Recover from switching isImperial pref */ /** @suppress {strictMissingProperties} */ -function onChangeIsImperial() { - clearReport(); - _RT.$HLedObjects = {}; - _RT.$HLlayer.destroyFeatures(); - _RT.$isMapChanged = true; - async(F_LOGIN); +function onChangeUserSettings() { + const s = wmeSDK.Settings.getUserSettings(); + if (_RT.$isImperial != s.isImperial) { + tlog('isImperial changed to: ' + s.isImperial); + clearReport(); + _RT.$HLedObjects = {}; + wmeSDK.Map.removeAllFeaturesFromLayer( { layerName: GL_LAYERNAME } ); + _RT.$isMapChanged = true; + async(F_LOGIN); + } } /** * Venues Added Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onVenuesAdded(e) { _RT.$isMapChanged = true; } /** * Venues Changed Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onVenuesChanged(e) { _RT.$isMapChanged = true; sync(F_ONVENUESCHANGED, e); @@ -807,10 +888,10 @@ function onVenuesChanged(e) { /** * Venues Removed Handler */ -/** @suppress {strictMissingProperties} */ +/** @suppress {strictMissingProperties} function onVenuesRemoved(e) { _RT.$isMapChanged = true; if (1 === e.length) if (RTStateIs(ST_STOP) || RTStateIs(ST_PAUSE)) sync(F_ONVENUESCHANGED, e); -} +} */ diff --git a/src/data.js b/src/data.js index 78cdd4c..e3e7626 100644 --- a/src/data.js +++ b/src/data.js @@ -112,7 +112,7 @@ var GL_LAYERNAME = "WME Validator"; /** @const */ //var GL_LAYERBIT = 13; /** @const */ -var GL_LAYERUNAME = "WMEValidator"; +//var GL_LAYERUNAME = "WMEValidator"; /** @const */ var GL_LAYERACCEL = "toggleWMEValidator"; /** @const */ @@ -304,7 +304,7 @@ var RS_MAX = 6; /** @const */ var LIMIT_PERCHECK = 300; /** @const */ -var LIMIT_TOLERANCE = 6; // ~5m +var LIMIT_TOLERANCE = 5; // ~5m /** @const */ var LIMIT_DEBUG = 20; @@ -465,6 +465,7 @@ var AS_NAME = "WME_Validator"; */ /** @const */ var SZ_PANEL_HEIGHT = 190; +let u_meters = { units: 'meters' }; // for turf distance calculations /** * Scan constants @@ -520,7 +521,7 @@ var CO_MAX = 3; * Watch Dogs */ /** @const */ -var WD_SHORT = 5; +var WD_SHORT = 120; /** @const */ var WD_LONG = 1e4; @@ -528,18 +529,18 @@ var WD_LONG = 1e4; * Shortcuts */ /** new W @const */ -var nW = null; +//var nW = null; /** Waze.map @const */ -var WM = null; +//var WM = null; /** Waze.loginManager @const */ -var WLM = null; +//var WLM = null; /** Waze.selectionManager @const */ -var WSM = null; +//var WSM = null; /** Waze.model @const */ -var WMo = null; +//var WMo = null; /** Waze.controller @const */ -var WC = null; +//var WC = null; /** unsafeWindow @const */ -var UW = null; +//var UW = null; /** requite @const */ -var R = null; +//var R = null; diff --git a/src/helpers.js b/src/helpers.js index cba39de..ad5cfdf 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -91,14 +91,15 @@ function isEmpty(obj) { * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach#An_object_copy_function */ function deepCopy(obj) { + let cpy; switch (classCode(obj)) { case CC_ARRAY: - var cpy = []; + cpy = []; for (var i = 0, len = obj.length; i < len; i++) cpy[i] = deepCopy(obj[i]); return cpy; case CC_OBJECT: - var cpy = {}; + cpy = {}; for (var attr in obj) if (obj.hasOwnProperty(attr)) cpy[attr] = deepCopy(obj[attr]); @@ -140,17 +141,19 @@ function deepCompare(obj1, obj2) { } function getDirection(seg) { - return (seg.attributes.fwdDirection ? 1 : 0) + (seg.attributes.revDirection ? 2 : 0); + // only one of these 3 booleans is true for any segment + return (seg.isAtoB ? 1 : 0) + (seg.isBtoA ? 2 : 0) + (seg.isTwoWay ? 3 : 0); }; function getLocalizedValue(val, country) { - var ipu = OpenLayers.INCHES_PER_UNIT; - var mph = false; + //var ipu = OpenLayers.INCHES_PER_UNIT; + const IPU_MILE = 63360; + const IPU_KM = 39370; + let mph = false; if ((country == "United Kingdom") || (country == "Jersey") || (country == "Guernsey") || (country == "United States")) mph = true; - return mph ? - Math.round(val * ipu["km"] / ipu["mi"]) : val; + return mph ? Math.round(val * IPU_KM / IPU_MILE) : val; } diff --git a/src/login.js b/src/login.js index 5756a87..f101382 100644 --- a/src/login.js +++ b/src/login.js @@ -22,8 +22,7 @@ * Login new user */ async function F_LOGIN() { - log("login " + WLM.user.attributes.userName); - + log("login " + wmeSDK.State.getUserInfo().userName); /////////////////////////////////////////////////////////////////////// // Support Functions /** @@ -148,17 +147,16 @@ async function F_LOGIN() { $cachedTopCCode: "", // top (logged in) user $topUser: { - $userID: WLM.user.attributes.id, - $userName: WLM.user.attributes.userName, - $userLevel: WLM.user.attributes.rank + 1, + $userName: wmeSDK.State.getUserInfo().userName, + $userLevel: wmeSDK.State.getUserInfo().rank + 1, }, // top (current) map center $topCenter: null, // watch dog $WDmoveID: -1, $WDloadID: -1, - // current layers visibility - $layersVisibility: "", + // current layers that were toggled off + layerToggle: [], // current state $state: ST_STOP, // current direction @@ -176,7 +174,7 @@ async function F_LOGIN() { // map of segment IDs to revalidate $revalidate: {}, // current user - $curUserName: WLM.user.attributes.userName, + $curUserName: wmeSDK.State.getUserInfo().userName, // error flag $error: false, // no editable segment was found - show a message @@ -193,8 +191,9 @@ async function F_LOGIN() { // "da", "lt", "zh"], $untranslatedLngs: ["IT"], }; - _RT.$topUser.$isCM = WLM.user.attributes.editableCountryIDs ? 0 !== WLM.user.attributes.editableCountryIDs.length : false; - _RT.$topUser.$countryIDs = WLM.user.attributes.editableCountryIDs ? WLM.user.attributes.editableCountryIDs : []; + _RT.$topUser.$isCM = wmeSDK.State.getUserInfo().isCountryManager; + _RT.$topUser.$countryIDs = wmeSDK.State.getManagedCountries(); + _RT.$isImperial = wmeSDK.Settings.getUserSettings().isImperial; /////////////////////////////////////////////////////////////////////// // WV Checks @@ -256,10 +255,10 @@ async function F_LOGIN() { ["#00A8FF", , true, "House numbers"], ["#F7B020", , true, "Segment with time restrictions"] ]; - for (var i = CK_TBFIRST; i <= CK_TBLAST; i++) { - var cc = TBchecks[i - CK_TBFIRST]; - var cp = cc[4] || defTBProblem; - var cpl = cc[5]; + for (let i = CK_TBFIRST; i <= CK_TBLAST; i++) { + let cc = TBchecks[i - CK_TBFIRST]; + let cp = cc[4] || defTBProblem; + let cpl = cc[5]; if (!classCodeDefined(cpl)) cpl = defTBProblemLink; @@ -295,12 +294,12 @@ async function F_LOGIN() { ["#FFFF01", , true, "Filter by city (alt. city)"], ["#00FF00", , true, "Filter by editor"] ]; - for (var i = CK_WMECHFIRST; i <= CK_WMECHLAST; i++) { - var cc = WMECHchecks[i - CK_WMECHFIRST]; + for (let i = CK_WMECHFIRST; i <= CK_WMECHLAST; i++) { + let cc = WMECHchecks[i - CK_WMECHFIRST]; /** @const */ - var cp = defWMECHProblem; + let cp = defWMECHProblem; /** @const */ - var cpl = defWMECHProblemLink; + let cpl = defWMECHProblemLink; defTranslation[i + '.enabled'] = true; defTranslation[i + '.color'] = cc[0]; @@ -316,8 +315,8 @@ async function F_LOGIN() { "Ramp", "Primary Street", "Street", "Parking Lot Road", "Railroad", "Private Road"]; // Generate custom checks descriptions in EN - for (var i = CK_TYPEFIRST; i <= CK_TYPELAST; i++) { - var streetName = streetNames[i - CK_TYPEFIRST]; + for (let i = CK_TYPEFIRST; i <= CK_TYPELAST; i++) { + let streetName = streetNames[i - CK_TYPEFIRST]; defTranslation[i + '.severity'] = "W"; defTranslation[i + '.title'] = "Must be a " + streetName; defTranslation[i + '.problem'] = "This segment must be a " + streetName; @@ -325,7 +324,7 @@ async function F_LOGIN() { + streetName + " or change the road name"; } // Generate custom checks descriptions in EN - for (var i = CK_CUSTOMFIRST; i <= CK_CUSTOMLAST; i++) { + for (let i = CK_CUSTOMFIRST; i <= CK_CUSTOMLAST; i++) { defTranslation[i + '.title'] = "Custom check"; defTranslation[i + '.severity'] = "W"; defTranslation[i + '.problem'] = "The segment matched custom conditions"; @@ -356,9 +355,9 @@ async function F_LOGIN() { 157: 2, 158: 2 }; - for (var i = CK_LOCKFIRST; i <= CK_LOCKLAST; i++) { - var lockName = streetNames[i - CK_LOCKFIRST]; - var lockLevel = lockLevels[i]; + for (let i = CK_LOCKFIRST; i <= CK_LOCKLAST; i++) { + let lockName = streetNames[i - CK_LOCKFIRST]; + let lockLevel = lockLevels[i]; defTranslation[i + '.title'] = "No lock on " + lockName; defTranslation[i + '.problem'] = "The " + lockName + " segment should be locked at least to Lvl ${n}"; defTranslation[i + '.solution'] = "Lock the segment"; @@ -377,9 +376,9 @@ async function F_LOGIN() { }; /** @const */ var streetDefRegExp = "!/.?/"; - for (var i = CK_STREETTNFIRST; i <= CK_STREETTNLAST; i++) { - var streetName = streetNames[i - CK_STREETTNFIRST]; - var streetRegExp = streetRegExps[CK_STREETTNFIRST] || streetDefRegExp; + for (let i = CK_STREETTNFIRST; i <= CK_STREETTNLAST; i++) { + let streetName = streetNames[i - CK_STREETTNFIRST]; + let streetRegExp = streetRegExps[CK_STREETTNFIRST] || streetDefRegExp; if (i < 165 || i > 167) defTranslation[i + '.severity'] = "W"; defTranslation[i + '.title'] = "Incorrect " + streetName + " name"; @@ -397,13 +396,13 @@ async function F_LOGIN() { // init internal translations var listOfIntPacks = ''; - for (var translationsKey in _translations) { - var translation = _translations[translationsKey]; + for (let translationsKey in _translations) { + let translation = _translations[translationsKey]; mirrorChecks(translation); _I18n.addTranslation(translation); // update listOfIntPacks - var country = translation[".country"]; + let country = translation[".country"]; if (!country) continue; if (classCodeIs(country, CC_ARRAY)) country = country[0]; @@ -429,17 +428,17 @@ async function F_LOGIN() { // add external translations var listOfPacks = ''; - for (var gObject in window) { + for (let gObject in window) { if (!window.hasOwnProperty(gObject)) continue; if (-1 !== gObject.indexOf("WME_Validator")) { - var translation = window[gObject]; + let translation = window[gObject]; log("found localization pack: " + gObject.replace('WME_Validator_', '')); mirrorChecks(translation); _I18n.addTranslation(translation); // update listOfPacks if (".country" in translation) { - var country = translation[".country"]; + let country = translation[".country"]; if (classCodeIs(country, CC_ARRAY)) country = country[0]; listOfPacks += '' + country; @@ -469,7 +468,7 @@ async function F_LOGIN() { + 'how to create a localization pack'; // Generate $checks - for (var i = 1; i < MAX_CHECKS; i++) { + for (let i = 1; i < MAX_CHECKS; i++) { var check = { ENABLED: {}, PROBLEMLINK: {}, @@ -538,8 +537,8 @@ async function F_LOGIN() { var defEnabled = false; var arrCodes = []; - for (var ccode in _I18n.$translations) { - var translation = _I18n.$translations[ccode]; + for (let ccode in _I18n.$translations) { + let translation = _I18n.$translations[ccode]; if (label in translation) { var e = translation[label]; check.ENABLED[ccode] = e; @@ -556,7 +555,7 @@ async function F_LOGIN() { } if (labelPL in translation) { - var l = translation[labelPL] + let l = translation[labelPL] .replace('W:', PFX_WIKI) .replace('P:', PFX_PEDIA) .replace('F:', PFX_FORUM) @@ -572,7 +571,7 @@ async function F_LOGIN() { check.PROBLEMLINKTEXT[ccode] = trS('report.link.other'); } if (labelSL in translation) { - var l = translation[labelSL] + let l = translation[labelSL] .replace('W:', PFX_WIKI) .replace('P:', PFX_PEDIA) .replace('F:', PFX_FORUM) @@ -1117,8 +1116,8 @@ async function F_LOGIN() { // check for AudioContext - if (!classCodeDefined(UW.AudioContext) - && !classCodeDefined(UW.webkitAudioContext)) { + if (!classCodeDefined(window.AudioContext) + && !classCodeDefined(window.webkitAudioContext)) { _UI.pSettings.pScanner.oSounds.CHECKED = false; _UI.pSettings.pScanner.oSounds.NA = true; } @@ -1143,10 +1142,7 @@ async function F_LOGIN() { // destroy UI _UI = {}; // uninstall login/logout handler - WLM.events.un({ - "afterloginchanged": onLogin, - "login": onLogin - }); + eventOff( "wme-logged-in", onLogin ); return; } } @@ -1165,7 +1161,7 @@ async function F_LOGIN() { _THUI.loadValues(_UI, storageObj); // create a styleMap with a custom default symbolizer - var styleMap = new OpenLayers.StyleMap({ +/* var styleMap = new OpenLayers.StyleMap({ strokeWidth: HL_WIDTH, }); @@ -1211,15 +1207,48 @@ async function F_LOGIN() { WM.addLayer(_RT.$HLlayer); _RT.$HLlayer.setVisibility(_UI.pSettings.pScanner.oHLReported.CHECKED); WM.raiseLayer(_RT.$HLlayer, 99); + */ + const styleRules = [{ + style: { + strokeWidth:HL_WIDTH, + //opacity: HL_OPACITY, + // + }, + }, + { + predicate: (properties)=>{ + return properties.type == RS_NOTE; + }, + style: { + strokeColor:GL_NOTECOLOR, graphicZIndex:10 + } + }, + { + predicate: (properties)=>{ + return properties.type == RS_WARNING; + }, + style: { + strokeColor:GL_WARNINGCOLOR, graphicZIndex:20 + } + }, + { + predicate: (properties)=>{ + return properties.type == RS_ERROR; + }, + style: { + strokeColor:GL_ERRORCOLOR, graphicZIndex:30 + } + } + ]; + wmeSDK.Map.addLayer( { layerName: GL_LAYERNAME, styleRules } ); + wmeSDK.Map.setLayerOpacity( { layerName: GL_LAYERNAME, opacity: HL_OPACITY }) - var tabLabel; - var tabPane; // create userscript tab - var res = W.userscripts.registerSidebarTab("validator"); - tabLabel = res.tabLabel; - tabPane = res.tabPane; + let res = await wmeSDK.Sidebar.registerScriptTab(); + + let tabLabel = res.tabLabel; + let tabPane = res.tabPane; tabLabel.innerText = " Validator"; - await W.userscripts.waitForElementConnected(tabPane); $(tabLabel.parentElement).prepend( $('', { class: 'fa fa-check-square-o' }) ); @@ -1232,36 +1261,22 @@ async function F_LOGIN() { async(ForceHLAllObjects, null, 700); // register event handlers - WMo.events.on({ - "mergeend": onMergeEnd, - }); - WM.events.on({ - "moveend": onMoveEnd, - "zoomend": delayForceHLAllObjects, - "changelayer": onChangeLayer, - }); - WSM.addEventListener('selectionchanged', delayForceHLAllObjects); - WC.events.on({ - "loadstart": onLoadStart, - }); + wmeSDK.Events.on({ eventName: "wme-map-data-loaded", eventHandler:onMergeEnd }); + wmeSDK.Events.on({ eventName: "wme-map-move-end", eventHandler:onMoveEnd }); + wmeSDK.Events.on({ eventName: "wme-map-zoom-changed", eventHandler:onZoomEnd }); + wmeSDK.Events.on({ eventName: "wme-map-layer-changed", eventHandler:onChangeLayer }); + wmeSDK.Events.on({eventName:"wme-selection-changed", eventHandler:onSelChanged}); + //wmeSDK.Events.on({ eventName: "wme-selection-changed", eventHandler: delayForceHLAllObjects }); // monitor segments, venues and nodes changes - WMo.segments.on({ - "objectsadded": onSegmentsAdded, - "objectschanged": onSegmentsChanged, - "objectsremoved": onSegmentsRemoved, - }); - WMo.venues.on({ - "objectsadded": onVenuesAdded, - "objectschanged": onVenuesChanged, - "objectsremoved": onVenuesRemoved, - }); - WMo.nodes.on({ - "objectschanged": onNodesChanged, - "objectsremoved": onNodesRemoved, - }); + wmeSDK.Events.trackDataModelEvents({ dataModelName: "segments" }); + wmeSDK.Events.trackDataModelEvents({ dataModelName: "venues" }); + wmeSDK.Events.trackDataModelEvents({ dataModelName: "nodes" }); + wmeSDK.Events.on({ eventName: "wme-data-model-objects-added", eventHandler: onObjectsAdded }); + wmeSDK.Events.on({ eventName: "wme-data-model-objects-changed", eventHandler: onObjectsChanged }); + wmeSDK.Events.on({ eventName: "wme-data-model-objects-removed", eventHandler: onObjectsRemoved }); + // event to recreate tab after changing WME units - W.prefs.on({ - "change:isImperial": onChangeIsImperial, - }); + wmeSDK.Events.on({ eventName: "wme-user-settings-changed", eventHandler: onChangeUserSettings }); + } diff --git a/src/other.js b/src/other.js index 4f5d7c2..e5f309d 100644 --- a/src/other.js +++ b/src/other.js @@ -23,15 +23,18 @@ */ function F_ONSEGMENTSCHANGED(e) { // add nearby segments to _RT.$revalidate - var changedNodes = []; - for (var i = 0; i < e.length; i++) { - var nodeIDs = [e[i].attributes.fromNodeID, e[i].attributes.toNodeID]; - for (var j = 0; j < nodeIDs.length; j++) { - var nodeID = nodeIDs[j]; - if (!nodeID) continue; - var node = WMo.nodes.getObjectById(nodeID); - if (node) - changedNodes.push(node); + let changedNodes = []; + for (let i = 0; i < e.length; i++) { + const sg = wmeSDK.DataModel.Segments.getById({segmentId: e[i]} ); + if (sg) { + var nodeIDs = [sg.fromNodeId, sg.toNodeId]; + for (let j = 0; j < nodeIDs.length; j++) { + let nodeID = nodeIDs[j]; + if (!nodeID) continue; + let node = wmeSDK.DataModel.Nodes.getById({nodeId: nodeID} ); + if (node) + changedNodes.push(node); + } } } if (changedNodes.length) @@ -43,12 +46,18 @@ function F_ONSEGMENTSCHANGED(e) { */ function F_ONNODESCHANGED(e) { // add nearby segments to _RT.$revalidate - var reHL = false; - for (var i = 0; i < e.length; i++) { - var ids = e[i].attributes.segIDs; - for (var j = 0; j < ids.length; j++) - _RT.$revalidate[ids[j]] = true, - reHL = true; + let reHL = false; + for (let i = 0; i < e.length; i++) { + let nd = e[i]; + if (typeof nd === 'number') { nd = wmeSDK.DataModel.Nodes.getById({nodeId: nd} ); } + //console.log('VAL NODES CHANGED ' + i, nd); + if (nd) { + let ids = nd.hasOwnProperty('connectedSegmentIds') ? nd.connectedSegmentIds :nd.attributes.segIDs; + + for (let j = 0; j < ids.length; j++) + _RT.$revalidate[ids[j]] = true, + reHL = true; + } } // revalidate all the objects if (reHL) @@ -62,7 +71,7 @@ function F_ONVENUESCHANGED(e) { // add nearby venues to _RT.$revalidate var reHL = false; for (var i = e.length - 1; i >= 0; i--) { - var id = e[i].attributes.id; + var id = e[i]; _RT.$revalidate[id] = true; reHL = true; } @@ -76,10 +85,10 @@ function F_ONVENUESCHANGED(e) { /** @suppress {strictMissingProperties} */ function F_ONCHANGELAYER(e) { // Trigger of layer change was not by a layer (ie WMETB Config Dialog) - if (!e.hasOwnProperty('layer')) { + if (!e.hasOwnProperty('layerName')) { return; } - if (-1 !== e.layer.id.indexOf(GL_TBPREFIX)) { +/* if (-1 !== e.layer.id.indexOf(GL_TBPREFIX)) { if (!e.layer.visibility) { for (var segmentID in WMo.segments.objects) { if (!WMo.segments.objects.hasOwnProperty(segmentID)) continue; @@ -88,10 +97,9 @@ function F_ONCHANGELAYER(e) { } ForceHLAllObjects(); } - else - if (GL_LAYERUNAME === e.layer.uniqueName - && e.layer.visibility !== _UI.pSettings.pScanner.oHLReported.CHECKED - ) { + else */ + if (GL_LAYERNAME === e.layerName + && wmeSDK.Map.isLayerVisibile({ layerName: GL_LAYERNAME }) !== _UI.pSettings.pScanner.oHLReported.CHECKED) { // switch Validator on/off _RT.$switchValidator = true; async(F_UPDATEUI); @@ -103,18 +111,18 @@ function F_ONCHANGELAYER(e) { */ /** @suppress {strictMissingProperties} */ function F_ONMOVEEND() { - var c = WM.getCenter(); + const c = wmeSDK.Map.getMapCenter(); if (-1 === _RT.$WDmoveID && -1 === _RT.$WDloadID - && c.equals(_RT.$nextCenter) + && ptEqual(c,_RT.$nextCenter) ) _RT.$WDmoveID = window.setTimeout(onMergeEnd, WD_SHORT); else { // autopause on user move if (RTStateIs(ST_RUN) && !_RT.$firstStep - && !c.equals(_RT.$nextCenter) - && !c.equals(_RT.$startCenter) + && !ptEqual(c,_RT.$nextCenter) + && !ptEqual(c,_RT.$startCenter) ) { _RT.$curMessage = { TEXT: trS("msg.autopaused.text"), @@ -132,13 +140,13 @@ function F_ONMOVEEND() { */ /** @suppress {strictMissingProperties} */ function F_ONLOADSTART() { - var c = WM.getCenter(); + const c = wmeSDK.Map.getMapCenter(); // kill move WD window.clearTimeout(_RT.$WDmoveID); if (-1 === _RT.$WDloadID - && c.equals(_RT.$nextCenter) + && ptEqual(c,_RT.$nextCenter) ) _RT.$WDloadID = window.setTimeout(onMergeEnd, WD_LONG); @@ -146,6 +154,18 @@ function F_ONLOADSTART() { } +/** + * Pass in a layer switcher DOM selector. If its currently checked/enabled, disable it and add to layerToggle list + */ +function disableLayer( sel ) +{ + const l = document.querySelector(sel); + if (l && l.checked) { + l.click(); + _RT.layerToggle.push(sel); + } +} + /** * Switch all layers but roads off */ @@ -154,20 +174,15 @@ function F_LAYERSOFF() { // TODO: // Waze.Config.segments.zoomToRoadType[SCAN_ZOOM] = -1; - _RT.$HLlayer.destroyFeatures(); - // if(_RT.$layersVisibility || _UI.pSettings.pScanner.oShowLayers.CHECKED) - if (_RT.$layersVisibility || GL_SHOWLAYERS) + wmeSDK.Map.removeAllFeaturesFromLayer( { layerName: GL_LAYERNAME } ); + if (GL_SHOWLAYERS) return; - WM.layers.forEach(function (el) { - if (el.displayInLayerSwitcher && GL_LAYERUNAME !== el.uniqueName) { - if (el.getVisibility()) - _RT.$layersVisibility += "T"; - else - _RT.$layersVisibility += "F"; + _RT.layerToggle = []; + disableLayer('#layer-switcher-group_display'); + disableLayer('#layer-switcher-group_permanent_hazards'); + disableLayer("#layer-switcher-group_issues_tracker"); + disableLayer("#layer-switcher-group_places"); - el.setVisibility(false); - } - }); } /** @@ -175,19 +190,15 @@ function F_LAYERSOFF() { */ /** @suppress {strictMissingProperties} */ function F_LAYERSON() { - // if(!_RT.$layersVisibility || _UI.pSettings.pScanner.oShowLayers.CHECKED) - if (!_RT.$layersVisibility || GL_SHOWLAYERS) + if (_RT.layerToggle.length == 0 || GL_SHOWLAYERS) return; - var j = 0; - WM.layers.forEach(function (el) { - if (el.displayInLayerSwitcher && GL_LAYERUNAME !== el.uniqueName) { - if (_RT.$layersVisibility.length > j) { - el.setVisibility("T" === _RT.$layersVisibility.charAt(j)); - j++; - } - } - }); - _RT.$layersVisibility = ""; + + for (let l = 0; l<_RT.layerToggle.length; l++) { + const ll = document.querySelector(_RT.layerToggle[l]); + ll.click(); + } + _RT.layerToggle = []; + } /** @@ -214,8 +225,7 @@ function F_STOP() { beep(100, "square"); // restore current view if (_RT.$startCenter) { - WM.panTo(_RT.$startCenter); - WM.zoomTo(_RT.$startZoom); + wmeSDK.Map.setMapCenter({ lonLat: _RT.$startCenter, zoomLevel: _RT.$startZoom} ); } if (!_REP.$maxSeverity) _RT.$curMessage = { @@ -230,39 +240,65 @@ function F_STOP() { async(F_LAYERSON); } +/** + * Compares two points, passed in as lonLat object + */ +function ptEqual(a,b) +{ + const aa = turf.point( [a.lon, a.lat] ); + const bb = turf.point( [b.lon, b.lat] ); + const eq = turf.booleanEqual(aa,bb); + return eq; +} + /** * Merge End Handler */ /** @suppress {strictMissingProperties} */ function F_ONMERGEEND() { + const ldf = W.app.attributes.loadingFeatures; + if (ldf ) { + setTimeout(F_ONMERGEEND, 50); + return; + } /** @const */ - var c = WM.getCenter(); + const c = wmeSDK.Map.getMapCenter(); // skip all but next center runs - if (RTStateIs(ST_RUN) && _RT.$nextCenter && !c.equals(_RT.$nextCenter)) + if (RTStateIs(ST_RUN) && _RT.$nextCenter && !ptEqual(c,_RT.$nextCenter)) { return; - /** @const */ - var e = nW.map.getOLExtent(); - /** @const */ - var ew = e.getWidth(); - /** @const */ - var eh = e.getHeight(); + } + //tlog("ONMERGEEND called..."); + + const [left, bottom, right, top] = wmeSDK.Map.getMapExtent(); + const p1 = turf.point( [left,top]); + const p2 = turf.point( [right,top]); + const p3 = turf.point( [left,bottom]); + const ew = turf.distance(p1,p2,u_meters); + const eh = turf.distance(p1,p3,u_meters); + /** @const */ var ew2 = ew / 2; /** @const */ var eh2 = eh / 2; var s = _RT.$startExtent; - if (!s) s = new UW.OpenLayers.Bounds(); + if (!s) { + s = { left, bottom, right, top}; + //showExtent(s, 'ONMERGE set s: '); + } + const s1 = turf.point( [s.left,s.top]); + const s2 = turf.point( [s.right,s.top]); + const s3 = turf.point( [s.left,s.bottom]); + /** @const */ var cx = c.lon; /** @const */ var cy = c.lat; /** @const */ var dir = Math.round(_RT.$direction / Math.abs(_RT.$direction)); - /** @const */ - var sw = s.getWidth(); - /** @const */ - var sh = s.getHeight(); + + const sw = turf.distance(s1,s2,u_meters); + const sh = turf.distance(s1,s3,u_meters); // calculate real step X and Y /** @const */ @@ -278,8 +314,7 @@ function F_ONMERGEEND() { if (_RT.$nextCenter) { setRTState(ST_RUN); // restore current view and continue - WM.zoomTo(SCAN_ZOOM); - WM.panTo(_RT.$nextCenter); + wmeSDK.Map.setMapCenter({ lonLat: _RT.$nextCenter, zoomLevel: SCAN_ZOOM} ); clearWD(); return; } @@ -298,17 +333,20 @@ function F_ONMERGEEND() { if (_RT.$firstStep) { // make first step _RT.$firstStep = false; - var newX = s.left + ew2; - var newY = s.top - eh2; - // save current view for pause - _RT.$nextCenter = new UW.OpenLayers.LonLat(newX, newY); - WM.zoomTo(SCAN_ZOOM); - WM.panTo(_RT.$nextCenter); + _RT.$curStep = 1; + _RT.$stepCount = kxMax * kyMax; + const startPt = turf.point([s.left,s.top]); + let newPtA = turf.destination(startPt,ew2,90, u_meters); + let newPt = turf.destination(newPtA,eh2,0, u_meters); + _RT.$nextCenter = { lon:newPt.geometry.coordinates[0], lat: newPt.geometry.coordinates[1] }; + showPt(_RT.$nextCenter, 'ONMERGE FIRSTSTEP nxCen: '); + wmeSDK.Map.setMapCenter({ lonLat: _RT.$nextCenter, zoomLevel: SCAN_ZOOM} ); clearWD(); return; } // do the job! + //tlog("ONMERGEEND DO VALIDATE ..."); sync(F_VALIDATE, false); /////////////////////////////////////////////////////////////////////// @@ -319,7 +357,7 @@ function F_ONMERGEEND() { var deltaY = Number.MAX_VALUE; var kx = 0; var ky = 0; - for (var i = 0; ; i++) { +/* for (var i = 0; ; i++) { var x = s.left + ew2 + i * stepX; var y = s.top - eh2 - i * stepY; if (x > s.right && y < s.bottom) break; @@ -329,14 +367,15 @@ function F_ONMERGEEND() { cd = Math.abs(y - cy); if (cd < deltaY) deltaY = cd, ky = i; - } + } */ updateTimer(ST_RUN); - var curStep = ky * kxMax + (0 < dir ? kx : kxMax - kx); - if (4 < curStep) { - if (0 === curStep % 5) { + _RT.$curStep++; + //var curStep = ky * kxMax + (0 < dir ? kx : kxMax - kx); + if (4 < _RT.$curStep) { + //if (0 === curStep % 5) { //var maxStep = (kyMax*(kxMax - 1)); var maxStep = kyMax * kxMax; - var minETA = (maxStep / curStep - 1) * _RT.$timer.$secInRun / 60; + var minETA = (maxStep / _RT.$curStep - 1) * _RT.$timer.$secInRun / 60; var strMsg = (1 > minETA) ? trS("msg.scanning.text.soon") : trSO("msg.scanning.text", { "n": Math.round(minETA) }) @@ -345,32 +384,41 @@ function F_ONMERGEEND() { TEXT: strMsg, TITLE: trS("msg.scanning.tip"), }; - } + //} } // 2. Make an X step kx = kx + dir; // 3. Check if new X is within start extent - var newX = s.left + ew2 + kx * stepX; + let newX; // = s.left + ew2 + kx * stepX; + const startPt = turf.point([cx,cy]); + let newPt = turf.destination(startPt,stepX,90, u_meters); + newX = newPt.geometry.coordinates[0]; if (newX < s.left || newX > s.right // or if center is closer to the start border that the edge - || Math.abs(newX - s.left) < Math.abs(newX - ew2 - s.left) - || Math.abs(newX - s.right) < Math.abs(newX + ew2 - s.right) + // || Math.abs(newX - s.left) < Math.abs(newX - ew2 - s.left) // ####### + // || Math.abs(newX - s.right) < Math.abs(newX + ew2 - s.right) ) { // step back newX = s.left + ew2 + (kx - dir) * stepX; + const startPt = turf.point([s.left,cy]); + let newPtA = turf.destination(startPt,ew2,90, u_meters); + newPt = turf.destination(newPtA,stepY,180, u_meters); + newX = newPt.geometry.coordinates[0]; + //showPt(newPt, 'ONMERGE move down nxCen: '); // change direction - _RT.$direction = -_RT.$direction; + //_RT.$direction = -_RT.$direction; // make an Y step ky++; } // 4. Check if new Y is within start extent - var newY = s.top - eh2 - ky * stepY; + //var newY = s.top - eh2 - ky * stepY; + let newY = newPt.geometry.coordinates[1]; if (newY < s.bottom // or if center is closer to the start border that the edge - || Math.abs(newY - s.bottom) < Math.abs(newY - eh2 - s.bottom) + // ### || Math.abs(newY - s.bottom) < Math.abs(newY - eh2 - s.bottom) ) { // finished! // check if any editable objects was found @@ -381,12 +429,38 @@ function F_ONMERGEEND() { return; } - _RT.$nextCenter = new UW.OpenLayers.LonLat(newX, newY); + _RT.$nextCenter = { lon: newX, lat: newY }; + showPt(_RT.$nextCenter, 'ONMERGE PAN step ' + _RT.$curStep +' nxCen: '); // pan map - WM.zoomTo(SCAN_ZOOM); - WM.panTo(_RT.$nextCenter); + wmeSDK.Map.setMapCenter({ lonLat: _RT.$nextCenter, zoomLevel: SCAN_ZOOM} ); clearWD(); } +function showcoord( f ) +{ + return f.toString().substring(0,7) + ' '; +} +function showPt( p, tx ) +{ + let e; + if (p.geometry) { + const cc = p.geometry.coordinates; + e = showcoord(cc[0]); + e += showcoord(cc[1]); + } + else { + e = showcoord(p.lon); + e += showcoord(p.lat); + } + console.info('VAL ' + tx + e) +} +function showExtent( ex, tx ) +{ + let e = showcoord(ex.left); + e += showcoord(ex.bottom); + e += showcoord(ex.right); + e += showcoord(ex.top); + console.info('VAL ' + tx + e); +} /** * Run Handler @@ -411,25 +485,26 @@ function F_ONRUN() { _RT.$firstStep = true; // save current view - var e = nW.map.getOLExtent(); - _RT.$startExtent = e; - _RT.$startCenter = WM.getCenter(); - _RT.$startZoom = WM.getZoom(); + let [left, bottom, right, top] = wmeSDK.Map.getMapExtent(); + _RT.$startExtent = {left, bottom, right, top}; + showExtent(_RT.$startExtent, 'ONRUN start: '); + _RT.$startCenter = wmeSDK.Map.getMapCenter(); + _RT.$startZoom = wmeSDK.Map.getZoomLevel(); _RT.$nextCenter = null; _RT.$moveEndCenter = null; // clearReport(); - _RT.$nextCenter = new UW.OpenLayers.LonLat(e.left, e.top); - WM.panTo(_RT.$nextCenter); - WM.zoomTo(SCAN_ZOOM); + _RT.$nextCenter = { lon:left, lat: top }; + showPt(_RT.$nextCenter, 'ONRUN start nxCen: '); + wmeSDK.Map.setMapCenter({ lonLat: _RT.$nextCenter, zoomLevel: SCAN_ZOOM} ); } /** * Login Handler */ function F_ONLOGIN() { - if (WLM.user) { + if (wmeSDK.State.isLoggedIn()) { if (!_WV.$loggedIn) { // set the flag and do login _WV.$loggedIn = true; @@ -455,43 +530,55 @@ function F_ONLOGIN() { */ function F_INIT() { // init shortcuts - UW = window; - nW = UW.W; - WLM = nW.loginManager; - WSM = nW.selectionManager; - WM = nW.map; - WMo = nW.model; - WC = nW.controller; - if (!nW || !WLM || !WLM.user || !WSM || !WM || !WMo || !WC || !$("#user-tabs")) { + //UW = window; + //nW = UW.W; + //WLM = nW.loginManager; +// WSM = nW.selectionManager; + //WM = nW.map; + //WMo = nW.model; + //WC = nW.controller; +/* if (!nW || !WLM || !WLM.user || !WSM || !WM || !WMo || !WC || !$("#user-tabs")) { log("waiting for WME...") async(F_INIT, null, 1e3); return; - } + } */ // Now we surely have WM as map, but stuff moved to W.map.olMap for us // So we redefine WM here to use olMap instead, now we have map loaded. - WM = nW.map.olMap; + //WM = nW.map.olMap; // detect new WME version - if (classCodeDefined(UW.require)) { - R = UW.require; - WME_BETA = /beta/.test(location.href); - } + WME_BETA = /beta/.test(location.href); setupPolicy(); // Google Analytics - var _gaq = UW["_gaq"]; + /*var _gaq = UW["_gaq"]; if (_gaq) { _gaq.push(["WME_Validator._setAccount", "UA-46853768-3"]); _gaq.push(["WME_Validator._setDomainName", "waze.com"]); _gaq.push(["WME_Validator._trackPageview"]); - } + } */ + + // check for .address-edit added to the edit-panel + const panelObserver = new MutationObserver((mutations) => { + mutations.forEach(function(mutation) { + for (let i = 0; i < mutation.addedNodes.length; i++) { + const addedNode = mutation.addedNodes[i]; + + // Only fire up if it's a node + if (addedNode.nodeType === Node.ELEMENT_NODE) { + if (addedNode.querySelector('.address-edit')) { + //log('address-edit added to DOM'); + addPanelDetails(); + } + } + } + }); + }); + panelObserver.observe(document.getElementById('edit-panel'), { childList: true , subtree: true }); _WV.$loggedIn = false; // install login/logout handler - WLM.events.on({ - "loginStatus": onLogin, - "login": onLogin - }); + wmeSDK.Events.on({ eventName: "wme-logged-in", eventHandler:onLogin }); // do login or wait for user async(F_ONLOGIN); @@ -570,16 +657,16 @@ function F_INIT() { if (objID) { this.$cityID = objID; - var oc = WMo.cities.getObjectById(objID); + var oc = wmeSDK.DataModel.Cities.getById( {cityId: objID} ); if (oc) { - this.$city = oc.attributes.isEmpty ? "" : oc.attributes.name; - var o = WMo.states.getObjectById(oc.attributes.stateID); + this.$city = oc.isEmpty ? "" : oc.name; + var o = wmeSDK.DataModel.States.getById( {stateId: oc.stateId} ); if (o) - this.$state = o.attributes.name; - this.$countryID = oc.attributes.countryID; - o = WMo.countries.getObjectById(oc.attributes.countryID); + this.$state = o.name; + this.$countryID = oc.countryId; + o = wmeSDK.DataModel.Countries.getById( {countryId: oc.countryId} ); if (o) - this.$country = o.attributes.name; + this.$country = o.name; } this.$hash = this.$cityID + this.$countryID; @@ -683,19 +770,19 @@ function F_INIT() { this.$streetID = 0; /** @type {string} */ this.$street = ""; - - if (objID) { + if (objID?.isEmpty) { + } + else if (objID?.street) { + this.$streetID = objID.street.id; + } else if (objID) { this.$streetID = objID; - var o = WMo.streets.getObjectById(objID); + } + + if (this.$streetID) { + let o = wmeSDK.DataModel.Streets.getById({streetId: this.$streetID}) ;//WMo.streets.getObjectById(objID); if (o) { - if (o.hasOwnProperty('isEmpty')) { - this.$street = o.isEmpty ? '' : o.name; - _WV.SimpleCITY.call(this, o.cityID) - } - else { - this.$street = o.attributes.isEmpty ? '' : o.attributes.name; - _WV.SimpleCITY.call(this, o.attributes.cityID); - } + this.$street = o.isEmpty ? '' : o.name; + _WV.SimpleCITY.call(this, o.cityId) } else { this.$street = GL_NOID; @@ -738,7 +825,7 @@ function F_UPDATEUI(e) { */ function destroyHLs() { _RT.$HLedObjects = {}; - _RT.$HLlayer.destroyFeatures(); + wmeSDK.Map.removeAllFeaturesFromLayer( { layerName: GL_LAYERNAME } ); } /** * Updates report buttons @@ -779,7 +866,7 @@ function F_UPDATEUI(e) { } // update start button - if (15 < WM.getZoom()) { + if (15 < wmeSDK.Map.getZoomLevel()) { btns.bScan.CLASS = "btn btn-default"; btns.bScan.DISABLED = true; btns.bScan.TITLE = trS("button.scan.tip.NA"); @@ -818,8 +905,8 @@ function F_UPDATEUI(e) { * Returns simple representation of top city and country */ function getTopCity() { - var i = WMo.segments.topCityID; - if (i) return new _WV.SimpleCITY(i); + let i = wmeSDK.DataModel.Cities.getTopCity(); + if (i) return new _WV.SimpleCITY(i.id); return new _WV.SimpleCITY(0); } @@ -973,8 +1060,7 @@ function F_UPDATEUI(e) { setRTState(ST_CONTINUE); // restore start view and continue if (_RT.$startCenter) { - WM.zoomTo(_RT.$startZoom); - WM.panTo(_RT.$startCenter); + wmeSDK.Map.setMapCenter({ lonLat: _RT.$startCenter, zoomLevel: _RT.$startZoom} ); } clearWD(); break; @@ -1019,12 +1105,12 @@ function F_UPDATEUI(e) { !_UI.pSettings.pScanner.oHLReported.CHECKED; if (_UI.pSettings.pScanner.oHLReported.CHECKED) { ForceHLAllObjects(); - _RT.$HLlayer.setVisibility(true); + wmeSDK.Map.setLayerVisibility( { layerName: GL_LAYERNAME, visibility: true }); } else { ForceHLAllObjects(); destroyHLs(); - _RT.$HLlayer.setVisibility(false); + wmeSDK.Map.setLayerVisibility( { layerName: GL_LAYERNAME, visibility: false }); } _RT.$switchValidator = false; } @@ -1114,7 +1200,7 @@ function F_UPDATEUI(e) { if (RTStateIs(ST_STOP) && !_REP.$maxSeverity) { // always display a zoom out message if (!_UI.pMain.NODISPLAY) { - if (15 < WM.getZoom()) + if (15 < wmeSDK.Map.getZoomLevel()) _RT.$curMessage = { TEXT: _UI.pSettings.pScanner.oHLReported.CHECKED ? trS("msg.pan.text") @@ -1166,35 +1252,28 @@ function F_LOGOUT() { _UI = {}; // unregister event handlers - WMo.events.un({ - "mergeend": onMergeEnd, - }); - WM.events.un({ - "moveend": onMoveEnd, - "zoomend": HLAllObjects, - "changelayer": onChangeLayer, - }); - WSM.removeEventListener('selectionchanged', delayForceHLAllObjects); - WC.events.un({ - "loadstart": onLoadStart, - }); + eventOff("wme-map-move-end",onMoveEnd); + eventOff("wme-map-zoom-changed",onZoomEnd); + eventOff("wme-map-layer-changed",onChangeLayer); + eventOff("wme-selection-changed", onSelChanged); + eventOff("wme-data-model-objects-added", onObjectsAdded ); + eventOff("wme-data-model-objects-changed", onObjectsChanged ); + eventOff("wme-data-model-objects-removed", onObjectsRemoved ); - // monitor segments, venues and nodes changes - WMo.segments.events.un({ - "objectsadded": onSegmentsAdded, - "objectschanged": onSegmentsChanged, - "objectsremoved": onSegmentsRemoved, - }); - WMo.venues.events.un({ - "objectsadded": onVenuesAdded, - "objectschanged": onVenuesChanged, - "objectsremoved": onVenuesRemoved, - }); - WMo.nodes.events.un({ - "objectschanged": onNodesChanged, - "objectsremoved": onNodesRemoved, - }); +} +function eventOff( eventName, eventHandler ) { + try { + wmeSDK.Events.off({ eventName, eventHandler }); + } catch(e) { + console.info('VAL Events.off failed ' + eventName); + } } // call the init function when the library is initialized -async(F_INIT, null, 0); +window.SDK_INITIALIZED.then(() => { + wmeSDK = getWmeSdk({ scriptId, scriptName }); + wmeSDK.Events.once({ eventName: 'wme-ready' }).then(async () => { + F_INIT(); + }); +}); + diff --git a/src/release.js b/src/release.js index 05d4428..a5c4db5 100644 --- a/src/release.js +++ b/src/release.js @@ -68,10 +68,10 @@ v2023.2.13: * #55 "No city on named segment" Please report any issues/suggestions on the forum: -https://www.waze.com/forum/viewtopic.php?t=76488 +https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877 See the full Change Log: -https://www.waze.com/forum/viewtopic.php?f=819&t=76488&p=787161#p787161` +https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877` ; /** @const */ var WV_LICENSE_VERSION = "1"; @@ -88,7 +88,7 @@ WME Validator source code is available on GitHub: https://github.com/WMEValidator/ For questions please use official forum: -https://www.waze.com/forum/viewtopic.php?f=819&t=76488 +https://www.waze.com/discuss/t/script-wme-validator-v2025-02-26-places-beta/44877 Report bugs on GitHub Issues Tracker: https://github.com/WMEValidator/validator/issues @@ -119,6 +119,12 @@ var LIMIT_TOTAL = 2e4; /** @const */ var MAX_CHECKS = 310; +// IDs for SDK use +const scriptName = 'Validator'; +const scriptId = 'validator'; +let wmeSDK; + + /************************************************************************* * URLs *************************************************************************/ diff --git a/src/report.js b/src/report.js index ba01ca4..99ebdc3 100644 --- a/src/report.js +++ b/src/report.js @@ -152,17 +152,16 @@ function F_SHOWREPORT(reportFormat) { zoom = _RT.$startZoom; } else { - center = WM.getCenter(); - zoom = WM.getZoom(); + center = wmeSDK.Map.getMapCenter(); + zoom = wmeSDK.Map.getZoomLevel(); } - var c = center.clone() - .transform(nW.Config.map.projection.local, nW.Config.map.projection.remote); + //var c = center.clone().transform(nW.Config.map.projection.local, nW.Config.map.projection.remote); return window.location.origin + window.location.pathname + '?zoomLevel=' + zoom - + '&lat=' + Math.round(c.lat * 1e5) / 1e5 - + '&lon=' + Math.round(c.lon * 1e5) / 1e5 - + '&env=' + nW.app.getAppRegionCode() + + '&lat=' + Math.round(center.lat * 1e5) / 1e5 + + '&lon=' + Math.round(center.lon * 1e5) / 1e5 + + '&env=' + wmeSDK.Settings.getRegionCode() ; } @@ -475,7 +474,7 @@ function F_SHOWREPORT(reportFormat) { ; var newCountries = []; - for (var k in _I18n.$country2code) { + for (let k in _I18n.$country2code) { if (ccode === _I18n.$country2code[k] && ucountry !== k) newCountries.push(_I18n.capitalize(k)); @@ -507,8 +506,8 @@ function F_SHOWREPORT(reportFormat) { if (ccode in _I18n.$code2dir) pack[".dir"] = _I18n.$code2dir[ccode]; - var newLngs = []; - for (var k in _I18n.$lng2code) { + let newLngs = []; + for (let k in _I18n.$lng2code) { if (ccode === _I18n.$lng2code[k] && k !== lng) newLngs.push(k); @@ -522,7 +521,7 @@ function F_SHOWREPORT(reportFormat) { // compare and add UI strings if (lng) { - for (var label in _I18n.$defSet) { + for (let label in _I18n.$defSet) { // skip meta labels and checks if (/^\./.test(label) || /^[0-9]/.test(label)) @@ -534,17 +533,17 @@ function F_SHOWREPORT(reportFormat) { } // compare and add checks - var allLabels = _RT.$otherLabels.concat(_RT.$textLabels); - var arrDepCodes = _I18n.getDependantCodes(ccode); - for (var i = 1; i < MAX_CHECKS; i++) { + let allLabels = _RT.$otherLabels.concat(_RT.$textLabels); + let arrDepCodes = _I18n.getDependantCodes(ccode); + for (let i = 1; i < MAX_CHECKS; i++) { // skip mirror checks if ((CK_MIRRORFIRST + 100) <= i && (CK_MIRRORLAST + 100) >= i) continue; // check is enabled? - var label = i + '.enabled'; + let label = i + '.enabled'; - var checkEnabled = false; + let checkEnabled = false; if (_I18n.$defSet[label] || oldPack[label]) checkEnabled = true; if (!checkEnabled) { @@ -562,12 +561,12 @@ function F_SHOWREPORT(reportFormat) { continue; } - for (var j = 0; j < allLabels.length; j++) { - var labelSfx = allLabels[j]; + for (let j = 0; j < allLabels.length; j++) { + let labelSfx = allLabels[j]; label = i + '.' + labelSfx; - var defData = _I18n.$defSet[label]; - var oldData = oldPack[label]; + let defData = _I18n.$defSet[label]; + let oldData = oldPack[label]; if (classCodeDefined(defData) || classCodeDefined(oldData)) { if (-1 !== _RT.$textLabels.indexOf(labelSfx)) { @@ -582,11 +581,11 @@ function F_SHOWREPORT(reportFormat) { continue; defData = deepCopy(defData || {}); oldData = deepCopy(oldData); - for (var k = CO_MIN; k <= CO_MAX; k++) { + for (let k = CO_MIN; k <= CO_MAX; k++) { delete defData[k]; delete oldData[k]; } - for (var k in defData) { + for (let k in defData) { if (!defData.hasOwnProperty(k)) continue; if (/\.title$/.test(k)) delete defData[k]; @@ -608,23 +607,23 @@ function F_SHOWREPORT(reportFormat) { // returns list of checks function getListOfChecks(countryID, country) { - var ucountry = country.toUpperCase(); - var ccode = ""; + let ucountry = country.toUpperCase(); + let ccode = ""; if (countryID) ccode = _I18n.getCountryCode(ucountry); - var ret = trS("report.list.see") + ' ' + Bb + let ret = trS("report.list.see") + ' ' + Bb + trS("report.list.checks") + Eb + Br + Br; - var fallbacks = ''; + let fallbacks = ''; if (ccode) - for (var i in _I18n.$country2code) { + for (let i in _I18n.$country2code) { if (!_I18n.$country2code.hasOwnProperty(i)) continue; if (i === ucountry) continue; - var acode = _I18n.$country2code[i]; + let acode = _I18n.$country2code[i]; if (ccode && acode !== ccode) continue; @@ -632,11 +631,11 @@ function F_SHOWREPORT(reportFormat) { + ' \u2192 ' + country + Br; } - for (var i in _I18n.$code2code) { + for (let i in _I18n.$code2code) { if (!_I18n.$code2code.hasOwnProperty(i)) continue; - var countryFrom = _I18n.getCapitalizedCountry(i); - var countryTo = _I18n.getCapitalizedCountry(_I18n.$code2code[i]); + let countryFrom = _I18n.getCapitalizedCountry(i); + let countryTo = _I18n.getCapitalizedCountry(_I18n.$code2code[i]); if (ccode && i !== ccode && _I18n.$code2code[i] !== ccode) continue; if (country && countryFrom !== country && countryTo !== country) @@ -751,7 +750,7 @@ function F_SHOWREPORT(reportFormat) { } // opens new browser window function openWindow(data) { - var nw = UW.open("", "_blank"); + let nw = window.open("", "_blank"); nw.document.write(data); // UW.open("data:text/html;charset=UTF-8," + encodeURIComponent(data), // "_blank"); @@ -794,7 +793,7 @@ function F_SHOWREPORT(reportFormat) { FR = ''; encFR += encodeURIComponent(FRfooter); FRfooter = ''; - UW.open(encFR, "_blank"); + window.open(encFR, "_blank"); } } // filter helpers @@ -875,7 +874,7 @@ function F_SHOWREPORT(reportFormat) { // _REP->$cityIDs->streetIDs->$objectIDs->$reportIDs // traverse report and call a handler function traverseReport(handler) { - var mapCenter = WM.getCenter(); + let mapCenter = wmeSDK.Map.getMapCenter(); // get sorted cities function getSortedCities() { @@ -1153,8 +1152,8 @@ function F_SHOWREPORT(reportFormat) { FR += '&lon='; FR += obj.$objectCopy.$center.lon; FR += '&env='; - FR += nW.app.getAppRegionCode(); - FR += '&' + obj.$objectCopy.$model.name + '='; + FR += wmeSDK.Settings.getRegionCode(); + FR += "&" + obj.$objectCopy.$objtype + "s="; FR += obj.$objectCopy.$objectID; } // report item handler @@ -1223,7 +1222,7 @@ function F_SHOWREPORT(reportFormat) { getPermalink(obj); FR += Ca if (isBeta) FR += 'B:'; - if (obj.$objectCopy.$model === WMo.segments) { + if (obj.$objectCopy.$objtype === 'segment') { FR += obj.$objectCopy.$objectID; } else { // Use the name of a venue, when set. @@ -1345,6 +1344,7 @@ function F_SHOWREPORT(reportFormat) { // prepare report setFormat(RF_HTML); var t = trS("report.title"); + let country; switch (reportFormat) { case RF_UPDATEMAXSEVERITY: updateMaxSeverity(); @@ -1363,7 +1363,7 @@ function F_SHOWREPORT(reportFormat) { true))) break; // prompt for country - var country = _RT.$topCity && _RT.$topCity.$country ? + country = _RT.$topCity && _RT.$topCity.$country ? _RT.$topCity.$country : window.prompt( getMsg(wType, @@ -1430,8 +1430,8 @@ function F_SHOWREPORT(reportFormat) { ); break; case RF_LIST: - var countryID = 0; - var country = ""; + let countryID = 0; + country = ""; t = trS("report.list.title") + ' '; // try top city if (_RT.$topCity && _RT.$topCity.$country) { @@ -1454,7 +1454,7 @@ function F_SHOWREPORT(reportFormat) { break; case RF_HTML: // open new window - newWin = UW.open("", "_blank"); + newWin = window.open("", "_blank"); FR += getHTMLHeader(t); FR += getHeader(t); // save header to insert save button @@ -1475,7 +1475,7 @@ function F_SHOWREPORT(reportFormat) { break; case RF_BB: // open new window - newWin = UW.open("", "_blank"); + newWin = window.open("", "_blank"); var tf = t + " " + trS("report.share"); FR += getHTMLHeader(tf); diff --git a/src/validate.js b/src/validate.js index cb8718d..8e5f573 100644 --- a/src/validate.js +++ b/src/validate.js @@ -21,6 +21,7 @@ /** * Validate current view */ +var skippedObject; /** @suppress {strictMissingProperties} */ function F_VALIDATE(disabledHL) { if (!_RT.$isMapChanged) @@ -34,7 +35,7 @@ function F_VALIDATE(disabledHL) { beep(10); var options; - var skippedObject = false; + skippedObject = false; if (disabledHL) { updateObjectProperties([], true); @@ -62,7 +63,7 @@ function F_VALIDATE(disabledHL) { // 0. Prepare objects // update map info - _RT.$topCenter = WM.getCenter(); + _RT.$topCenter = wmeSDK.Map.getMapCenter(); // 1. Dispatch per view WHC event if (_UI.pSettings.pScanner.oReportExt.CHECKED @@ -117,21 +118,21 @@ function F_VALIDATE(disabledHL) { * Get user name * @returns {string} * @param {number} objID - */ + * / function getUserName(objID) { var u = WMo.users.getObjectById(objID); return u ? u.attributes.userName : objID.toString(); - } + } */ /** * Get user level * @returns {number} * @param {number} objID - */ + * / function getUserLevel(objID) { var u = WMo.users.getObjectById(objID); return u ? u.attributes.rank + 1 : 0; - } + } */ /** * Simple node object constructor @@ -191,13 +192,17 @@ function F_VALIDATE(disabledHL) { /** @type {number} */ this.$inConnectionsLen = 0; - var n = WMo.nodes.getObjectById(objID); + var n = W.model.nodes.getObjectById(objID); this.$rawNode = n; + this.rNode = null; + if (objID) { + this.rNode = wmeSDK.DataModel.Nodes.getById({nodeId: objID} ); + } if (n) { this.$isPartial = n.attributes.partial; this.$isEditable = true; // TODO: n.areConnectionsEditable(); // convert restrictions into an array - var co = n.attributes.restrictions; + /* var co = n.attributes.restrictions; for (var k in co) { if (!co[k]) continue; @@ -212,19 +217,20 @@ function F_VALIDATE(disabledHL) { } } - } + } */ this.$restrictionsLen = this._rawRestrictions.length; // convert segIDs into an array - for (var i = 0; i < n.attributes.segIDs.length; i++) { - var si = n.attributes.segIDs[i]; + for (let i = 0; i < this.rNode?.connectedSegmentIds.length; i++) { + let si = this.rNode.connectedSegmentIds[i]; // TODO: workaround for hangs at new segment save / 20150105 - if (+segID === +si || !WMo.segments.getObjectById(si)) + if (+segID === +si || !wmeSDK.DataModel.Segments.getById({segmentId: si})) { continue; + } this._rawOtherSegments.push(si); } this.$otherSegmentsLen = this._rawOtherSegments.length; // convert connections into in/out arrays - co = n.attributes.connections; + /* co = n.attributes.connections; for (var k in co) { if (!co[k]) continue; @@ -242,7 +248,7 @@ function F_VALIDATE(disabledHL) { // in connection if (+segID === con1) this._rawInConnections.push(con0); - } + } */ } this.$outConnectionsLen = this._rawOutConnections.length; this.$inConnectionsLen = this._rawInConnections.length; @@ -281,11 +287,9 @@ function F_VALIDATE(disabledHL) { SimpleNODE.prototype.getCenter = function () { if (this._center) return this._center; - if (!this.$rawNode) return null; + if (!this.rNode) return null; - var bounds = this.$rawNode.getOLGeometry().getBounds(); - this._center = new OpenLayers.LonLat(bounds.left, bounds.bottom) - .transform(nW.Config.map.projection.local, nW.Config.map.projection.remote); + this._center = { lon: this.rNode.geometry.coordinates[0], lat: this.rNode.geometry.coordinates[1] }; // round the lon/lat this._center.lon = Math.round(this._center.lon * 1e5) / 1e5; this._center.lat = Math.round(this._center.lat * 1e5) / 1e5; @@ -311,7 +315,7 @@ function F_VALIDATE(disabledHL) { SimpleNODE.prototype.getOutConnections = function () { return this._outConnections ? this._outConnections : this._outConnections = this._rawOutConnections.map( - function (e) { return new SimpleOBJECT(e, WMo.segments) }); + function (e) { return new SimpleOBJECT(e, 'segment') }); } /** * Get inward connection @@ -320,7 +324,7 @@ function F_VALIDATE(disabledHL) { SimpleNODE.prototype.getInConnections = function () { return this._inConnections ? this._inConnections : this._inConnections = this._rawInConnections.map( - function (e) { return new SimpleOBJECT(e, WMo.segments) }); + function (e) { return new SimpleOBJECT(e, 'segment') }); } /** * Get another segment @@ -329,72 +333,9 @@ function F_VALIDATE(disabledHL) { SimpleNODE.prototype.getOtherSegments = function () { return this._otherSegments ? this._otherSegments : this._otherSegments = this._rawOtherSegments.map( - function (e) { return new SimpleOBJECT(e, WMo.segments) }); + function (e) { return new SimpleOBJECT(e, 'segment') }); } - /** - * Simple roadclosure object constructor - * @constructor - * @struct - * @param {Waze.ROADCLOSURE} obj - */ - function SimpleROADCLOSURE(obj) { - /** @type {string} */ - this.$id = obj.id; - /** @type {number} */ - this.$segID = obj.segID; - /** @type {boolean} */ - this.$active = obj.active; - /** @type {string} */ - this.$updatedOn = ""; - /** @type {string} */ - this.$updatedBy = ""; - /** @type {number} */ - this.$updatedByID = 0; - /** @type {number} */ - this.$updatedByLevel = 0; - /** @type {string} */ - this.$createdOn = ""; - /** @type {string} */ - this.$createdBy = ""; - /** @type {number} */ - this.$createdByID = 0; - /** @type {number} */ - this.$createdByLevel = 0; - - this.$startDate = Date.parse(obj.startDate); - this.$endDate = Date.parse(obj.endDate); - /** @type {string} */ - this.$location = obj.location; - /** @type {string} */ - this.$reason = obj.reason; - - if (obj.updatedOn) - this.$updatedOn = formatDate('' + obj.updatedOn); - if (0 < obj.updatedBy) { - this.$updatedByID = obj.updatedBy; - this.$updatedBy = getUserName(obj.updatedBy); - this.$updatedByLevel = getUserLevel(obj.updatedBy); - } - if (obj.createdOn) - this.$createdOn = formatDate('' + obj.createdOn); - if (obj.createdBy) { - this.$createdByID = obj.createdBy; - this.$createdBy = getUserName(obj.createdBy); - this.$createdByLevel = getUserLevel(obj.createdBy); - } - - /* - * To avoid any issues with time zones, report expired - * restrictions 1-2 days after. - */ - var past = new Date(); - past.setDate(past.getDate() - 2); /* 2..days().ago() */ - /** @type {boolean} */ - this.$isInThePast = this.$endDate < past; - } - - /** * Simple restriction object constructor * @constructor @@ -403,39 +344,49 @@ function F_VALIDATE(disabledHL) { * @param {number} segID */ function SimpleRESTRICTION(obj, segID) { - var timeFrame = obj.getTimeFrame(); // cached node /** *type {SimpleOBJECT} */ this._to = null; this.$to = null; /** @type {number} */ this.$toID = segID; - /** @type {boolean} */ - this.$allDay = timeFrame.isAllDay() || false; - /** @type {number} */ - this.$days = timeFrame.getWeekdays(); /** @type {string} */ - this.$description = (obj.getDescription() || ""); + this.$description = ""; /** @type {boolean} */ this.$isEnabled = true; //obj.enabled || false; + /** @type {boolean} */ + this.$allDay = false; + /** @type {number} */ + this.$days = 0; /** @type {string} */ - this.$fromDate = (timeFrame.getStartDate() || ""); + this.$fromDate = ""; /** @type {string} */ - this.$fromTime = (timeFrame.getFromTime() || ""); + this.$fromTime = ""; /** @type {string} */ - this.$toDate = (timeFrame.getEndDate() || ""); + this.$toDate = ""; /** @type {string} */ - this.$toTime = (timeFrame.getToTime() || ""); - - /* - * To avoid any issues with time zones, report expired - * restrictions 1-2 days after. - */ - var past = new Date(); - past.setDate(past.getDate() - 2); /* 2..days().ago() */ + this.$toTime = ""; /** @type {boolean} */ - this.$isInThePast = new Date(this.$toDate + " " + - this.$toTime) < past; + this.$isInThePast = false; + if (typeof obj.getTimeFrame === 'function') { + this.$description = (obj.getDescription() || ""); + var timeFrame = obj.getTimeFrame(); + this.$allDay = timeFrame.isAllDay() || false; + this.$days = timeFrame.getWeekdays(); + this.$fromDate = (timeFrame.getStartDate() || ""); + this.$fromTime = (timeFrame.getFromTime() || ""); + this.$toDate = (timeFrame.getEndDate() || ""); + this.$toTime = (timeFrame.getToTime() || ""); + + /* + * To avoid any issues with time zones, report expired + * restrictions 1-2 days after. + */ + var past = new Date(); + past.setDate(past.getDate() - 2); /* 2..days().ago() */ + this.$isInThePast = new Date(this.$toDate + " " + + this.$toTime) < past; + } Object.defineProperties(this, { _to: { enumerable: false }, @@ -458,20 +409,22 @@ function F_VALIDATE(disabledHL) { */ SimpleRESTRICTION.prototype.getTo = function () { return this._to ? this._to : - this._to = new SimpleOBJECT('' + this.$toID, WMo.segments); + this._to = new SimpleOBJECT('' + this.$toID, 'segment'); }; /** * Simple representation of a segment constructor * @constructor * @struct - * @param {string} objID + * @param {Segment|Venue} rawobj */ - function SimpleOBJECT(objID, model) { - this.$model = model; - var raw = this.$model.getObjectById(objID); + function SimpleOBJECT(rawobj, obtype) { + if (typeof rawobj === 'number') { rawobj = wmeSDK.DataModel.Segments.getById({segmentId: rawobj} );} + //this.$model = model; + this.$objtype = obtype; + var raw = rawobj; // cached object - this.$rawObject = raw; + this.$rawObject = rawobj; // cached node /** *type {SimpleNODE} */ this._nodeA = null; @@ -497,7 +450,7 @@ function F_VALIDATE(disabledHL) { /** @type {string} */ this.$brand = ""; /** @type {string} */ - this.$objectID = objID; + this.$objectID = rawobj.id; /** *type {_WV.SimpleADDRESS} */ this.$address = null; /** @type {boolean} */ @@ -549,17 +502,17 @@ function F_VALIDATE(disabledHL) { /** @type {string} */ this.$updatedBy = ""; /** @type {number} */ - this.$updatedByID = 0; + //this.$updatedByID = 0; /** @type {number} */ - this.$updatedByLevel = 0; + //this.$updatedByLevel = 0; /** @type {string} */ this.$createdOn = ""; /** @type {string} */ this.$createdBy = ""; /** @type {number} */ - this.$createdByID = 0; + //this.$createdByID = 0; /** @type {number} */ - this.$createdByLevel = 0; + //this.$createdByLevel = 0; /** @type {Array} */ this.$alts = []; /** @type {number} */ @@ -580,83 +533,93 @@ function F_VALIDATE(disabledHL) { if (classCodeIs(raw, CC_UNDEFINED) || classCodeIs(raw, CC_NULL)) return; - var attrs = raw.attributes; + var attrs = raw; // Set segment only properties - if (this.$model === WMo.segments) { - this.$nodeAID = attrs.fromNodeID; - this.$nodeBID = attrs.toNodeID; + if (this.$objtype === 'segment') { + this.$nodeAID = raw.fromNodeId; + this.$nodeBID = raw.toNodeId; this.$isRoutable = this.isRoutable(); - this.$isTurnALocked = attrs.revTurnsLocked; - this.$isTurnBLocked = attrs.fwdTurnsLocked; - this.$isRoundabout = classCodeDefined(attrs.junctionID) - && null !== attrs.junctionID; - this.$hasHNs = attrs.hasHNs; - this.$hasRestrictions = raw.hasRestrictions(); - this.$restrictions = attrs.restrictions; - this.$type = attrs.roadType; - this.$typeRank = this.getTypeRank(attrs.roadType); + const baseobj = W.model.segments.getObjectById(raw.id); + this.$isEditable = wmeSDK.DataModel.Segments.hasPermissions( { segmentId: this.$objectID }); + this.$baseobj = baseobj; + this.$isTurnALocked = raw.areRevTurnsVerified; + this.$isTurnBLocked = raw.areFwdTurnsVerified; + this.$isRoundabout = null !== raw.junctionId; + this.$hasHNs = raw.hasHouseNumbers; + this.$hasRestrictions = raw.hasRestrictions; + this.$restrictions = raw.restrictions; + this.$type = raw.roadType; + this.$typeRank = this.getTypeRank(raw.roadType); + this.$rank = raw.rank + 1; this.$direction = getDirection(raw); - this.$elevation = attrs.level; - if ("length" in attrs) - this.$length = attrs.length; - else - this.$length = Math.round(raw.getOLGeometry().getGeodesicLength(WM.projection)); + this.$elevation = raw.elevationLevel; + if (raw.hasOwnProperty("length")) + this.$length = raw.length; + if (this.$length < 7) + this.$length = turf.length(raw.geometry, u_meters); // TODO: this.$isToll = raw.isTollRoad(); - this.$alts = attrs.streetIDs.map(function (objID) { + this.$alts = raw.alternateStreetIds.map(function (objID) { return new _WV.SimpleADDRESS(objID); }); - this.$restrictionsLen = attrs.restrictions.length; - this.$address = new _WV.SimpleADDRESS(attrs.primaryStreetID); + this.$restrictionsLen = raw.restrictions.length; + this.$address = new _WV.SimpleADDRESS(raw.primaryStreetId); // set speedlimits - this.$fwdMaxSpeed = getLocalizedValue(+attrs.fwdMaxSpeed, this.$address.$country); - this.$fwdMaxSpeedUnverified = attrs.fwdMaxSpeedUnverified; - this.$revMaxSpeed = getLocalizedValue(+attrs.revMaxSpeed, this.$address.$country); - this.$revMaxSpeedUnverified = attrs.revMaxSpeedUnverified; - this.$hasClosures = attrs.hasClosures; - if (raw.getFlagAttributes) { - this.$flags = raw.getFlagAttributes(); - } + this.$fwdMaxSpeed = getLocalizedValue(+raw.fwdSpeedLimit, this.$address.$country); + this.$fwdMaxSpeedUnverified = !raw.isFwdSpeedLimitVerified; + this.$revMaxSpeed = getLocalizedValue(+raw.revSpeedLimit, this.$address.$country); + this.$revMaxSpeedUnverified = !raw.isRevSpeedLimitVerified; + this.$hasClosures = raw.hasClosures; + this.$flags = raw.flagAttributes; + } else { + attrs = raw; // Set venue only properties this.$name = attrs.name; this.$brand = attrs.brand; if (this.$brand === null) { this.$brand = ""; } + this.$rank = raw.lockRank + 1; this.$isApproved = attrs.approved; - this.$mainCategory = raw.getMainCategory(); + this.$mainCategory = raw.categories[0]; this.$categories = attrs.categories; - this.$categoryAttributes = attrs.categoryAttributes; + this.$isParkingLot = (this.$mainCategory == 'PARKING_LOT'); + if (this.$isParkingLot) { + const parkingType = wmeSDK.DataModel.Venues.ParkingLot.getParkingLotType( { venueId: this.$objectID }); // "PRIVATE" | "PUBLIC" | "RESTRICTED" | null + const costType = wmeSDK.DataModel.Venues.ParkingLot.getCostType( { venueId: this.$objectID }); // "FREE" | "LOW" | "MODERATE" | "EXPENSIVE" | "UNKNOWN" + const lotType = wmeSDK.DataModel.Venues.ParkingLot.getLotTypes( { venueId: this.$objectID }); // "MULTI_LEVEL" | "STREET_LEVEL" | "STREET_LEVEL_COVERED" | "UNDERGROUND" + const paymentType = wmeSDK.DataModel.Venues.ParkingLot.getPaymentMethods( { venueId: this.$objectID }); // "CASH"| "CHECKS"| "CREDIT" | "DEBIT_CARD"| "DIGITAL_WALLET"| "ELECTRONIC_PASS"| "MEMBERSHIP"| "PARKING_APP"| "PERMIT"| "PREPAID"| "SMS_CALL" + this.$parkAttr = { parkingType, costType, lotType, paymentType }; + } + this.$categoryAttributes = ''; + this.$isGasStation = false; + this.$categories.forEach((c, i) => {if (c == 'GAS_STATION') this.$isGasStation = true; }); this.$openingHours = attrs.openingHours; this.$services = attrs.services; this.$externalProviders = attrs.externalProviderIDs; - this.$entryExitPoints = attrs.entryExitPoints; + this.$entryExitPoints = attrs.navigationPoints; this.$alts = attrs.aliases; - this.$address = new _WV.SimpleADDRESS(attrs.streetID); - this.$geometry = raw.getOLGeometry(); + const adr = wmeSDK.DataModel.Venues.getAddress( { venueId: this.$objectID }); + this.$address = new _WV.SimpleADDRESS(adr); + this.$geometry = raw.geometry; this.$phone = attrs.phone; this.$url = attrs.url; - this.$isPoint = raw.isPoint(); + this.$isPoint = raw.geometry.type == 'Point'; + this.$isEditable = wmeSDK.DataModel.Venues.hasPermissions( { venueId: this.$objectID }); + this.$rank = attrs.lockRank + 1; } - this.$isEditable = raw.arePropertiesEditable(); - - this.$lock = attrs.lockRank + 1; - this.$rank = attrs.rank + 1; - - if (attrs.updatedOn) - this.$updatedOn = formatDate(attrs.updatedOn); - if (0 < attrs.updatedBy) { - this.$updatedByID = attrs.updatedBy; - this.$updatedBy = getUserName(attrs.updatedBy); - this.$updatedByLevel = getUserLevel(attrs.updatedBy); + this.$lock = raw.lockRank + 1; + let mod = raw.modificationData; + if (mod.updatedOn) + this.$updatedOn = formatDate(mod.updatedOn); + if (mod.updatedBy) { + this.$updatedByName = mod.updatedBy; } - if (attrs.createdOn) - this.$createdOn = formatDate(attrs.createdOn); - if (attrs.createdBy) { - this.$createdByID = attrs.createdBy; - this.$createdBy = getUserName(attrs.createdBy); - this.$createdByLevel = getUserLevel(attrs.createdBy); + if (mod.createdOn) + this.$createdOn = formatDate(mod.createdOn); + if (mod.createdBy) { + this.$createdByName = mod.createdBy; } // mark some properties as readonly @@ -685,13 +648,9 @@ function F_VALIDATE(disabledHL) { $length: { writable: false }, $mainCategory: { writable: false }, $updatedOn: { writable: false }, - $updatedBy: { writable: false }, - $updatedByID: { writable: false }, - $updatedByLevel: { writable: false }, + $updatedByName: { writable: false }, $createdOn: { writable: false }, - $createdBy: { writable: false }, - $createdByID: { writable: false }, - $createdByLevel: { writable: false }, + $createdByName: { writable: false }, $restrictionsLen: { writable: false }, }); } @@ -762,12 +721,21 @@ function F_VALIDATE(disabledHL) { }; /** * Get center - * @returns {OpenLayers.LonLat} + * @returns {LonLat} */ SimpleOBJECT.prototype.getCenter = function () { if (this._center) return this._center; - this._center = this.$rawObject.getOLGeometry().getBounds().getCenterLonLat().clone() - .transform(nW.Config.map.projection.local, nW.Config.map.projection.remote); + this._center = {}; + const g = this.$rawObject.geometry; + if (g.type == 'Point') { + this._center.lon = g.coordinates[0]; + this._center.lat = g.coordinates[1]; + } else { + const c = turf.centroid(g); + this._center.lon = c.geometry.coordinates[0]; + this._center.lat = c.geometry.coordinates[1]; + } + // round the lon/lat this._center.lon = Math.round(this._center.lon * 1e5) / 1e5; this._center.lat = Math.round(this._center.lat * 1e5) / 1e5; @@ -780,8 +748,8 @@ function F_VALIDATE(disabledHL) { SimpleOBJECT.prototype.getRestrictions = function () { var t; return this._restrictions ? this._restrictions : - this._restrictions = this.$model == WMo.venues ? [] : - (t = this, this.$rawObject.attributes.restrictions.map( + this._restrictions = this.$objtype == 'venue' ? [] : + (t = this, this.$rawObject.restrictions.map( function (e) { return new SimpleRESTRICTION(e, t.$objectID) }) @@ -814,16 +782,15 @@ function F_VALIDATE(disabledHL) { /** @struct */ return { $objectID: ss.$objectID, - $model: ss.$model, + $objtype: ss.$objtype, $name: ss.$name, $countryID: +ss.$address.$countryID, $cityID: +ss.$address.$cityID, $streetID: +ss.$address.$streetID, $reportIDs: {}, - $updated: ss.$updatedOn ? ss.$rawObject.attributes.updatedOn - : (ss.$createdOn ? ss.$rawObject.attributes.createdOn : 0), - $userID: ss.$updatedByID ? +ss.$updatedByID - : (ss.$createdByID ? +ss.$createdByID : 0), + $updated: ss.$updatedOn ? ss.$rawObject.modificationData.updatedOn + : (ss.$createdOn ? ss.$rawObject.modificationData.createdOn : 0), + $userName: ss.$updatedByName ? ss.$updatedByName : (ss.$createdByName ? ss.$createdByName : '') , $isEditable: ss.$isEditable && (ss.$nodeA.$isEditable || ss.$nodeA.$isPartial) && (ss.$nodeB.$isEditable || ss.$nodeB.$isPartial) @@ -876,14 +843,14 @@ function F_VALIDATE(disabledHL) { var objectCopy = rep.$objectIDs[this.$objectID]; // add an user - var uid = objectCopy.$userID; + var uid = objectCopy.$userName; if (!(uid in _repU)) { var n = ""; - if (uid === this.$createdByID) - n = this.$createdBy; + if (uid === this.$createdByName) + n = this.$createdByName; else if (uid === this.$updatedByID) - n = this.$updatedBy; + n = this.$updatedByName; _repU[uid] = n; } @@ -1178,18 +1145,15 @@ function F_VALIDATE(disabledHL) { if (RTStateIs(ST_RUN) || RTStateIs(ST_CONTINUE)) return; - var features = []; - for (var i in _RT.$HLedObjects) { + wmeSDK.Map.removeAllFeaturesFromLayer( { layerName: GL_LAYERNAME } ); + for (let i in _RT.$HLedObjects) { if (!_RT.$HLedObjects.hasOwnProperty(i)) continue; - var obj = _RT.$HLedObjects[i]; + let obj = _RT.$HLedObjects[i]; if (obj.$severity) - features.push(new OpenLayers.Feature.Vector( - obj.$geometry.clone(), { 0: obj.$severity } - )); + wmeSDK.Map.addFeatureToLayer( { feature: { type: 'Feature', id: i, geometry: obj.$geometry, properties: { type: obj.$severity }, }, + layerName: GL_LAYERNAME } ); } - _RT.$HLlayer.destroyFeatures(); - _RT.$HLlayer.addFeatures(features); } /** @@ -1199,7 +1163,7 @@ function F_VALIDATE(disabledHL) { if (RTStateIs(ST_RUN) || RTStateIs(ST_CONTINUE)) return; - var objectID = rawObject.getID(); + var objectID = rawObject.id; var seenObj = _RT.$seen[objectID]; var severity = seenObj[I_SEVERITY]; var objectCopy = seenObj[I_OBJECTCOPY]; @@ -1218,7 +1182,7 @@ function F_VALIDATE(disabledHL) { /** @struct */ var obj = { $severity: filteredSeverity, - $geometry: rawObject.getOLGeometry(), + $geometry: rawObject.geometry, }; _RT.$HLedObjects[objectID] = obj; } @@ -1316,278 +1280,17 @@ function F_VALIDATE(disabledHL) { } // for all streets } // for all cities } - /** - * Update object properties - */ - function updateObjectProperties(selectedObjects, disabledHL) { - if (RTStateIs(ST_RUN) || RTStateIs(ST_CONTINUE)) - return; - - // remove WV properties - var prop = document.getElementById("i" + ID_PROPERTY) - var propDis = document.getElementById("i" + ID_PROPERTY_DISABLED) - - var defID = ID_PROPERTY; - var defHTML = ''; - if (disabledHL) { - defID = ID_PROPERTY_DISABLED; - defHTML = '
' - + ' ' - + trS("props.disabled") - + '
' - ; - // remove prop - if (prop) { - prop.parentNode.removeChild(prop); - } - prop = propDis; - } - else { - // remove propDis - if (propDis) { - propDis.parentNode.removeChild(propDis); - } - } - - if (prop) - prop.innerHTML = createSafeHtml(defHTML); - else { - var objectProperties = document.getElementsByClassName("address-edit")[0]; - if (!objectProperties) - objectProperties = document.getElementsByClassName("venue-edit-general")[0]; - - if (objectProperties) { - var d = document.createElement("div"); - d.innerHTML = createSafeHtml(defHTML); - d.id = "i" + defID; - d.style.cssText = "text-transform: none; padding: 5px;" - prop = objectProperties.appendChild(d) - } // if objectProperties - } // if prop - - if (disabledHL) - return; - - // check if there are any object selected - if (!selectedObjects.length) - return; - - // find selected issues - var selectedIssues = []; - for (var i = 0; i < selectedObjects.length; i++) { - var objectID = selectedObjects[i]; - if (objectID in _RT.$seen) { - var objectCopy = _RT.$seen[objectID][I_OBJECTCOPY]; - if (!objectCopy) continue; - // object is selected and highlighted - for (var cid in objectCopy.$reportIDs) { - if (objectCopy.$reportIDs.hasOwnProperty(cid)) { - var check = _RT.$checks[cid]; - if (check.REPORTONLY) - continue; - - selectedIssues.push([check, objectCopy, cid]); - } - } - } - } // for all selected objects - - var newProp = 'WME Validator ' + trS("props.reports") + ':' - ; - if (_REP.$isLimitPerCheck) { - newProp += '
' - + '' - + ' ' - + trS("props.limit.title") - + '' - + '
' - + '' - + '
' - + trS("props.limit.problem") - + '.
' - + '' - + '
' - + '

' + trS("props.limit.solution") + '.

' - + '

' - ; - } // limit per check - - // exceptions note - if (skippedObject) { - newProp += '
' - + '' - + ' ' - + trS("props.skipped.title") - + '' - + '
' - + '' - + '
' - + trS("props.skipped.problem") - + '.
' - + '

' - ; - } - - - if (!selectedIssues.length) { - // update properties - if (prop && (_REP.$isLimitPerCheck || skippedObject)) - prop.innerHTML = createSafeHtml(newProp); - return; - } - - // sort the issues - selectedIssues.sort(function (a, b) { return cmpCheckIDs(a[2], b[2]) }); - - // only unique issues - var selectedCounters = {}; - selectedIssues = selectedIssues.filter(function (e, i, arr) { - var checkID = e[2]; - // skip first element - if (i && arr[i - 1][2] === checkID) { - selectedCounters[checkID]++; - return false; - } - selectedCounters[checkID] = 1; - return true; - }); - // create a list of issues - selectedIssues.forEach(function (e) { - var check = e[0]; - var objectCopy = e[1]; - var checkID = e[2]; - var checkCounter = selectedCounters[checkID]; - var sevClass = 0; - var sevIcon = ""; - var sevBG = ""; - var strCountry = _REP.$countries[objectCopy.$countryID]; - var ccode = ""; - - if (strCountry) - ccode = _I18n.getCountryCode(strCountry.toUpperCase()); - else { - // try top country - ccode = _RT.$cachedTopCCode; - } - options = trO(check.OPTIONS, ccode); - - switch (check.SEVERITY) { - case RS_NOTE: - sevClass = CL_NOTE; - sevIcon = "info-circle"; - sevBG = GL_NOTEBGCOLOR; - break; - case RS_WARNING: - sevClass = CL_WARNING; - sevIcon = "exclamation-triangle"; - sevBG = GL_WARNINGBGCOLOR; - break; - case RS_ERROR: - sevClass = CL_ERROR; - sevIcon = "times-circle"; - sevBG = GL_ERRORBGCOLOR; - break; - case RS_CUSTOM1: - sevClass = CL_CUSTOM1; - sevIcon = "user"; - sevBG = GL_CUSTOM1BGCOLOR; - break; - case RS_CUSTOM2: - sevClass = CL_CUSTOM2; - sevIcon = "user"; - sevBG = GL_CUSTOM2BGCOLOR; - break; - } - var shortTitle = exSOS(check.TITLE, options, "titleEN") - .replace("WME Color Highlights", "WMECH") - .replace("WME Toolbox", "WMETB"); - newProp += '
' - + '' - + ' ' - + shortTitle - + (1 < checkCounter ? ' (' + checkCounter + ')' : '') - + '' - + '
' - + '' - + '
' - + '#' + checkID + ' ' - + exSOS(check.PROBLEM, options, "problemEN") - ; - var pl = trO(check.PROBLEMLINK, ccode); - if (pl) { - newProp += ': ' - + trO(check.PROBLEMLINKTEXT, ccode) - + '' - ; - } - else - newProp += '.'; - - newProp += '
'; - - // show howto - if (objectCopy.$isEditable) { - newProp += '' - + '
' - ; - if (check.SOLUTION) { - newProp += '

' + exSOS(check.SOLUTION, options, "solutionEN"); - - var sl = trO(check.SOLUTIONLINK, ccode); - if (sl) { - newProp += ': ' - + trO(check.SOLUTIONLINKTEXT, ccode) - + '' - ; - } - else - newProp += '.'; - - newProp += '

'; - } - } - else { - newProp += '' - + '
' - + '

' + trS("props.noneditable") + '.

'; - ; - } - - // show params - var cityID = objectCopy.$cityID; - var cityParam = _REP.$cityIDs[cityID].$params[checkID]; - if (cityParam) - newProp += '

' + cityParam + '

'; - var streetID = objectCopy.$streetID; - var streetParam = _REP.$cityIDs[cityID] - .$streetIDs[streetID].$params[checkID]; - - if (streetParam) - newProp += '

' + streetParam + '

'; - - newProp += '

' - ; - }); // forEach - - // update properties - if (prop) - prop.innerHTML = createSafeHtml(newProp); - } // updateObjectProperties /** * Match regular expression */ - function matchRegExp(checkID, objectID, expandedString, options) { - var optRegExp = options[CO_REGEXP]; + function matchRegExp(checkID, objectID, expandedString, loptions) { + var optRegExp = loptions[CO_REGEXP]; if (!optRegExp) return false; - var optString = options[CO_STRING]; - var optBool = options[CO_BOOL]; + var optString = loptions[CO_STRING]; + var optBool = loptions[CO_BOOL]; // debug - if (options[CO_NUMBER] + if (loptions[CO_NUMBER] && 0 < _REP.$debugCounter) { var checkTitle = ''; if (_RT.$checks[checkID] && _RT.$checks[checkID].TITLE) @@ -1629,10 +1332,10 @@ function F_VALIDATE(disabledHL) { * ignoring ignoreSegment */ function checkPublicConnection(seg, ignoreSegment) { - var foundPublicConnection = false; + let foundPublicConnection = false; if (!seg.$nodeA.$isPartial && seg.$nodeA.$otherSegmentsLen > 0) { - for (var i = 0; i < seg.$nodeA.$otherSegmentsLen; i++) { - var otherSegment = seg.$nodeA.$otherSegments[i]; + for (let i = 0; i < seg.$nodeA.$otherSegmentsLen; i++) { + let otherSegment = seg.$nodeA.$otherSegments[i]; if (ignoreSegment && otherSegment === ignoreSegment) continue; // Remember; ramps are public too, just not endpoint routable. @@ -1643,8 +1346,8 @@ function F_VALIDATE(disabledHL) { } } if (!seg.$nodeB.$isPartial && seg.$nodeB.$otherSegmentsLen > 0) { - for (var i = 0; i < seg.$nodeB.$otherSegmentsLen; i++) { - var otherSegment = seg.$nodeB.$otherSegments[i]; + for (let i = 0; i < seg.$nodeB.$otherSegmentsLen; i++) { + let otherSegment = seg.$nodeB.$otherSegments[i]; if (ignoreSegment && otherSegment === ignoreSegment) continue; if (otherSegment.$isRoutable || RT_RAMP === otherSegment.$type) { @@ -1666,20 +1369,34 @@ function F_VALIDATE(disabledHL) { && _RT.oReportWMECH.CHECKED; var reportToolbox = _UI.pSettings.pScanner.oReportExt.CHECKED && _RT.oReportToolbox.CHECKED; - var currentZoom = WM.getZoom(); + var currentZoom = wmeSDK.Map.getZoomLevel(); var slowChecks = _UI.pSettings.pScanner.oSlowChecks.CHECKED && 15 < currentZoom; var oExcludeNotes = _UI.pMain.pFilter.oExcludeNotes.CHECKED; + let sel; + try { + sel = wmeSDK.Editing.getSelection(); //?.objectType === 'segment' + } catch(e) { + sel = null; + console.warn('VAL getSel trap', e); + } + if (!sel) { + sel = { ids: [] } + } var selectedObjects = []; + let selectedPlaces = []; + if (sel?.objectType == 'segment') { selectedObjects = sel.ids; } + if (sel?.objectType == 'venue') { selectedPlaces = sel.ids; } _RT.$HLedObjects = {}; - for (var segmentKey in WMo.segments.objects) { - var rawSegment = WMo.segments.objects[segmentKey]; - var segmentID = rawSegment.getID(); + const segs = wmeSDK.DataModel.Segments.getAll(); + for (let r in segs ) { //segmentKey in WMo.segments.objects) { + let rawSegment = segs[r]; + let segmentID = rawSegment.id; // SPECIAL CASE - skip all checks for locked segments (exceptions) // 2014-05-01 - if (_RT.$topUser.$userLevel <= rawSegment.attributes.lockRank +/* if (_RT.$topUser.$userLevel <= rawSegment.attributes.lockRank && rawSegment.attributes.updatedOn && 1398902400000 < rawSegment.attributes.updatedOn) { if (rawSegment.selected) { @@ -1690,14 +1407,16 @@ function F_VALIDATE(disabledHL) { } if (!DEF_DEBUG) continue; - } + } */ // skip unrendered features - if (rawSegment.layer + /* if (rawSegment.layer && rawSegment.id in rawSegment.layer.unrenderedFeatures) - continue; + continue; */ - if ("Delete" === rawSegment.state) continue; + if (rawSegment.fromNodeId == null && rawSegment.toNodeId == null) { //("Delete" === rawSegment.state) { + continue; + } var seen = null; // check if the segment was already seen @@ -1705,10 +1424,11 @@ function F_VALIDATE(disabledHL) { seen = _RT.$seen[segmentID]; // always re-check selected segments - if (rawSegment.selected) { - // add selected segment to the array - selectedObjects.push(segmentID); - + let isSel = false; + for (let i=0; i 180) angle = 360 - angle; if (2 > angle @@ -1886,14 +1606,14 @@ function F_VALIDATE(disabledHL) { if (nodeB.$otherSegmentsLen && isLimitOk(119)) { - var rawNode = nodeB.$rawNode; - var baseAngle = rawNode.getAngleToSegment(rawSegment); - for (var i = 0; i < nodeB.$otherSegmentsLen; i++) { - var otherSegment = nodeB.$otherSegments[i]; + let rawNode = nodeB.$rawNode; + let baseAngle = rawNode.getAngleToSegment(segment.$baseobj); + for (let i = 0; i < nodeB.$otherSegmentsLen; i++) { + let otherSegment = nodeB.$otherSegments[i]; if (!otherSegment.$rawObject) continue; - var curAngle = rawNode.getAngleToSegment(otherSegment.$rawObject); - var angle = Math.abs(baseAngle - curAngle); + let curAngle = rawNode.getAngleToSegment(otherSegment.$baseobj); + let angle = Math.abs(baseAngle - curAngle); if (angle > 180) angle = 360 - angle; if (2 > angle @@ -1920,7 +1640,7 @@ function F_VALIDATE(disabledHL) { } // SPECIAL CASE - skip all checks for construction zones - if (streetLen + if (streetLen && isDrivable && address.isOkFor(101)) { options = getCheckOptions(101, countryCode); if (options[CO_REGEXP].test(street)) { @@ -1939,11 +1659,11 @@ function F_VALIDATE(disabledHL) { if (reportToolbox && address.isOkFor(CK_TBFIRST)) { - var col = rawSegment[GL_TBCOLOR]; + let col = rawSegment[GL_TBCOLOR]; if (col) { col = col.toUpperCase(); - for (var i = CK_TBFIRST; i <= CK_TBLAST; i++) { - var check = _RT.$checks[i]; + for (let i = CK_TBFIRST; i <= CK_TBLAST; i++) { + let check = _RT.$checks[i]; if (check.COLOR === col) { segment.report(i); break; @@ -1953,10 +1673,10 @@ function F_VALIDATE(disabledHL) { } if (reportWMECH && address.isOkFor(CK_WMECHFIRST)) { - var col = rawSegment[GL_WMECHCOLOR]; + let col = rawSegment[GL_WMECHCOLOR]; if (col) { - for (var i = CK_WMECHFIRST; i <= CK_WMECHLAST; i++) { - var check = _RT.$checks[i]; + for (let i = CK_WMECHFIRST; i <= CK_WMECHLAST; i++) { + let check = _RT.$checks[i]; if (check && check.COLOR === col) { segment.report(i); break; @@ -1967,7 +1687,7 @@ function F_VALIDATE(disabledHL) { if (alts.length && address.isOkFor(34)) { - for (var i = 0; i < alts.length; i++) { + for (let i = 0; i < alts.length; i++) { if (!alts[i].$street) { segment.report(34); break; @@ -1979,8 +1699,8 @@ function F_VALIDATE(disabledHL) { && segment.$restrictionsLen && isLimitOk(38) && address.isOkFor(38)) { - var restrictions = segment.$restrictions; - for (var i = 0; i < restrictions.length; i++) { + let restrictions = segment.$restrictions; + for (let i = 0; i < restrictions.length; i++) { if (restrictions[i].$isInThePast) { segment.report(38); break; @@ -1992,11 +1712,11 @@ function F_VALIDATE(disabledHL) { && (nodeA.$restrictionsLen || nodeB.$restrictionsLen) && isLimitOk(39) && address.isOkFor(39)) { - var restrictions = nodeA.$restrictions.concat(nodeB.$restrictions); - for (var i = 0; i < restrictions.length; i++) { - var restriction = restrictions[i]; + let restrictions = nodeA.$restrictions.concat(nodeB.$restrictions); + for (let i = 0; i < restrictions.length; i++) { + let restriction = restrictions[i]; if (restriction.$isInThePast) { - var param = ''; + let param = ''; if (restriction.$to.$address && restriction.$to.$address.$street) param = 'turn to ' + restriction.$to.$address.$street; @@ -2016,6 +1736,7 @@ function F_VALIDATE(disabledHL) { if (RT_RAILROAD === roadType && 100 > segmentLen + && streetLen > 0 && !isPartial && !nodeA.$otherSegmentsLen && !nodeB.$otherSegmentsLen @@ -2078,7 +1799,7 @@ function F_VALIDATE(disabledHL) { "speedLimitBA": reverseSpeed, "checkSpeedLimit": isDrivable && (reverseSpeedUnverified || forwardSpeedUnverified), }; - for (var i = CK_MATCHFIRST; i <= CK_MATCHLAST; i++) { + for (let i = CK_MATCHFIRST; i <= CK_MATCHLAST; i++) { if (!isLimitOk(i) || !address.isOkFor(i)) continue; @@ -2137,8 +1858,8 @@ function F_VALIDATE(disabledHL) { && !hasClosures && isLimitOk(36) && address.isOkFor(36)) { - var otherSegment = nodeA.$otherSegments[0]; - var otherNode, nextNode; + let otherSegment = nodeA.$otherSegments[0]; + let otherNode, nextNode; if (otherSegment.$nodeAID === nodeAID) { otherNode = otherSegment.$nodeA; nextNode = otherSegment.$nodeB; @@ -2179,9 +1900,9 @@ function F_VALIDATE(disabledHL) { && deepCompare(otherSegment.$alts, alts) ) { // check deep for loop - var loopFound = false; - for (var i = 0; i < nextNode.$otherSegmentsLen; i++) { - var thirdSegment = nextNode.$otherSegments[i]; + let loopFound = false; + for (let i = 0; i < nextNode.$otherSegmentsLen; i++) { + let thirdSegment = nextNode.$otherSegments[i]; if (thirdSegment.$nodeAID === nodeBID || thirdSegment.$nodeBID === nodeBID ) { @@ -2207,8 +1928,8 @@ function F_VALIDATE(disabledHL) { && !hasClosures && isLimitOk(37) && address.isOkFor(37)) { - var otherSegment = nodeB.$otherSegments[0]; - var otherNode, nextNode; + let otherSegment = nodeB.$otherSegments[0]; + let otherNode, nextNode; if (otherSegment.$nodeAID === nodeBID) { otherNode = otherSegment.$nodeA; nextNode = otherSegment.$nodeB; @@ -2250,9 +1971,9 @@ function F_VALIDATE(disabledHL) { && deepCompare(otherSegment.$alts, alts) ) { // check deep for loop - var loopFound = false; - for (var i = 0; i < nextNode.$otherSegmentsLen; i++) { - var thirdSegment = nextNode.$otherSegments[i]; + let loopFound = false; + for (let i = 0; i < nextNode.$otherSegmentsLen; i++) { + let thirdSegment = nextNode.$otherSegments[i]; if (thirdSegment.$nodeAID === nodeAID || thirdSegment.$nodeBID === nodeAID ) { @@ -2273,7 +1994,7 @@ function F_VALIDATE(disabledHL) { if (cityLen) { // GROUP cutyLen // RegExp city name checks - for (var i = CK_CITYNAMEFIRST; i <= CK_CITYNAMELAST; i++) { + for (let i = CK_CITYNAMEFIRST; i <= CK_CITYNAMELAST; i++) { if (!address.isOkFor(i) || !isLimitOk(i)) continue; @@ -2286,25 +2007,25 @@ function F_VALIDATE(disabledHL) { // GROUP cityLen if (isLimitOk(24) && address.isOkFor(24)) { - var param = trS("city.1"); - var r = 3 > cityLen ? true : false; + let param = trS("city.1"); + let r = 3 > cityLen ? true : false; - var cityCounter = _repCC[cityID]; + let cityCounter = _repCC[cityID]; // check new city if (1 === cityCounter || ((cityID in _REP.$incompleteIDs) && !_REP.$incompleteIDs[cityID].$counterReported)) { - for (var i = 0, len = _REP.$unsortedCityIDs.length; i < len; i++) { - var cid = _REP.$unsortedCityIDs[i]; + for (let i = 0, len = _REP.$unsortedCityIDs.length; i < len; i++) { + let cid = _REP.$unsortedCityIDs[i]; if (cid === cityID) continue; - var c = _repC[cid]; - var cLen = c.length; + let c = _repC[cid]; + let cLen = c.length; if (1 > cLen) continue; - var cityObj = getCityCmpObj(cityID, city, c); - var cObj = getCityCmpObj(cid, c, city); + let cityObj = getCityCmpObj(cityID, city, c); + let cObj = getCityCmpObj(cid, c, city); setCmpObjLimits(cityObj, cObj); setCmpObjLimits(cObj, cityObj); @@ -2319,7 +2040,7 @@ function F_VALIDATE(disabledHL) { // check if city was reported before if (cityID in _REP.$incompleteIDs) { // shortcut - var incompleteCity = _REP.$incompleteIDs[cityID]; + let incompleteCity = _REP.$incompleteIDs[cityID]; // increase the counter incompleteCity.$counterReported++; @@ -2347,7 +2068,7 @@ function F_VALIDATE(disabledHL) { // GROUP cityLen if (RT_RAILROAD === roadType - && isLimitOk(24) + && isLimitOk(27) && address.isOkFor(27)) segment.report(27); @@ -2368,14 +2089,14 @@ function F_VALIDATE(disabledHL) { // exclude revCons && (DIR_TWO === direction || DIR_BA === direction) && isLimitOk(120)) { - var rawNode = nodeA.$rawNode; - var baseAngle = rawNode.getAngleToSegment(rawSegment); - for (var i = 0; i < nodeA.$outConnectionsLen; i++) { - var otherSegment = nodeA.$outConnections[i]; + let rawNode = nodeA.$rawNode; + let baseAngle = rawNode.getAngleToSegment(rawSegment); + for (let i = 0; i < nodeA.$outConnectionsLen; i++) { + let otherSegment = nodeA.$outConnections[i]; if (!otherSegment.$rawObject) continue; - var curAngle = rawNode.getAngleToSegment(otherSegment.$rawObject); - var angle = Math.abs(baseAngle - curAngle); + let curAngle = rawNode.getAngleToSegment(otherSegment.$rawObject); + let angle = Math.abs(baseAngle - curAngle); if (angle > 180) angle = 360 - angle; if (30 > angle @@ -2402,14 +2123,14 @@ function F_VALIDATE(disabledHL) { // exclude revCons && (DIR_TWO === direction || DIR_AB === direction) && isLimitOk(121)) { - var rawNode = nodeB.$rawNode; - var baseAngle = rawNode.getAngleToSegment(rawSegment); - for (var i = 0; i < nodeB.$outConnectionsLen; i++) { - var otherSegment = nodeB.$outConnections[i]; + let rawNode = nodeB.$rawNode; + let baseAngle = rawNode.getAngleToSegment(rawSegment); + for (let i = 0; i < nodeB.$outConnectionsLen; i++) { + let otherSegment = nodeB.$outConnections[i]; if (!otherSegment.$rawObject) continue; - var curAngle = rawNode.getAngleToSegment(otherSegment.$rawObject); - var angle = Math.abs(baseAngle - curAngle); + let curAngle = rawNode.getAngleToSegment(otherSegment.$rawObject); + let angle = Math.abs(baseAngle - curAngle); if (angle > 180) angle = 360 - angle; if (30 > angle @@ -2449,8 +2170,8 @@ function F_VALIDATE(disabledHL) { && DIR_TWO === direction && nodeA.$otherSegmentsLen && isLimitOk(46)) { - for (var i = 0; i < nodeA.$otherSegmentsLen; i++) { - var otherSegment = nodeA.$otherSegments[i]; + for (let i = 0; i < nodeA.$otherSegmentsLen; i++) { + let otherSegment = nodeA.$otherSegments[i]; if (!otherSegment.$rawObject) continue; // if(one of other segments at node A is drivable @@ -2480,8 +2201,8 @@ function F_VALIDATE(disabledHL) { && DIR_TWO === direction && nodeB.$otherSegmentsLen && isLimitOk(47)) { - for (var i = 0; i < nodeB.$otherSegmentsLen; i++) { - var otherSegment = nodeB.$otherSegments[i]; + for (let i = 0; i < nodeB.$otherSegmentsLen; i++) { + let otherSegment = nodeB.$otherSegments[i]; if (!otherSegment.$rawObject) continue; // if(one of other segments at node B is drivable // AND in connection is possible (two way or dir to node B)) @@ -2518,8 +2239,8 @@ function F_VALIDATE(disabledHL) { && DIR_TWO === direction && nodeA.$otherSegmentsLen && isLimitOk(102)) { - for (var i = 0; i < nodeA.$otherSegmentsLen; i++) { - var otherSegment = nodeA.$otherSegments[i]; + for (let i = 0; i < nodeA.$otherSegmentsLen; i++) { + let otherSegment = nodeA.$otherSegments[i]; if (!otherSegment.$rawObject) continue; // if(one of other segments at node A is drivable // AND no private @@ -2549,8 +2270,8 @@ function F_VALIDATE(disabledHL) { && DIR_TWO === direction && nodeB.$otherSegmentsLen && isLimitOk(103)) { - for (var i = 0; i < nodeB.$otherSegmentsLen; i++) { - var otherSegment = nodeB.$otherSegments[i]; + for (let i = 0; i < nodeB.$otherSegmentsLen; i++) { + let otherSegment = nodeB.$otherSegments[i]; if (!otherSegment.$rawObject) continue; // if(one of other segments at node B is drivable // AND ni private @@ -2585,14 +2306,14 @@ function F_VALIDATE(disabledHL) { && address.isOkFor(202)) { // Check other segments to be a drivable public segment // Second param is a segment to ignore as a valid public connection - var foundPublicConnection = checkPublicConnection(segment, null); + let foundPublicConnection = checkPublicConnection(segment, null); if (!foundPublicConnection) { // We might have a isolated segment. Could be a Restricted Gate // See https://wazeopedia.waze.com/wiki/USA/Private_Installations#Specialty_Gate:_Restricted_Gate if (nodeA.$otherSegmentsLen == 1 && nodeB.$otherSegmentsLen == 1) { // both sides are connected to just one private segment - var nodeASegment = nodeA.$otherSegments[0]; - var nodeBSegment = nodeB.$otherSegments[0]; + let nodeASegment = nodeA.$otherSegments[0]; + let nodeBSegment = nodeB.$otherSegments[0]; if (checkPublicConnection(nodeASegment, segment) && checkPublicConnection(nodeBSegment, segment)) { // the private segments are connected to a routable segment beside the isolated one! @@ -2653,9 +2374,9 @@ function F_VALIDATE(disabledHL) { // GROUP isDrivable // on named segment, make sure theres a city on primary or alt if (!cityLen && streetLen && RT_RAMP !== roadType && RT_FREEWAY !== roadType && (isLimitOk(54) || isLimitOk(55))) { - var noCity = true; + let noCity = true; if (alts.length) { - for (var i = 0; i < alts.length; i++) { + for (let i = 0; i < alts.length; i++) { if (alts[i].$city) { noCity = false; break; @@ -2733,31 +2454,32 @@ function F_VALIDATE(disabledHL) { && 5 < segmentLen // only for dead-ends && !nodeA.$otherSegmentsLen - && nodeA.$rawNode.getOLGeometry().getBounds() + && nodeA.getCenter() && isLimitOk(107) && address.isOkFor(107)) { // check if any other segment is close to the node A - var IDs = nodeA.$rawNode.attributes.segIDs; - const bd = nodeA.$rawNode.getOLGeometry().getBounds(); - var pt = new OpenLayers.Geometry.Point(bd.left, bd.bottom); - for (var segKey in WMo.segments.objects) { - var seg = WMo.segments.objects[segKey]; - if (segmentID === seg.getID()) continue; - if (!seg.getOLGeometry()) continue; + let IDs = nodeA.rNode.connectedSegmentIds; + const c = nodeA.getCenter(); + const nPt = turf.point( [c.lon, c.lat ] ); + const segs = wmeSDK.DataModel.Segments.getAll(); + for (let r in segs ) { //segmentKey in WMo.segments.objects) { + let seg = segs[r]; + if (segmentID === seg.id) { continue; } + if (!seg.geometry) continue; // different elevations - if (elevation !== seg.attributes.level) continue; + if (elevation !== seg.elevationLevel) continue; // only for non-deleted segments - if ("Delete" === seg.state) continue; + if (seg.fromNodeId == null && seg.toNodeId == null) continue; //("Delete" === seg.state) continue; // only for drivable segments if (RR_TRAIL - >= SimpleOBJECT.prototype.getTypeRank(seg.attributes.roadType)) + >= SimpleOBJECT.prototype.getTypeRank(seg.roadType)) continue; // check if node A is not connected to the segment // only for dead-ends! - if (LIMIT_TOLERANCE > seg.getOLGeometry().distanceTo(pt, null)) { + if (LIMIT_TOLERANCE > turf.pointToLineDistance(nPt, seg.geometry, u_meters)) { // other segment is not editable - if (!seg.arePropertiesEditable()) + if (_RT.$topUser.$userLevel <= seg.lockRank) //(!seg.arePropertiesEditable()) { segment.$forceNonEditable = true; segment.report(107); break; @@ -2788,8 +2510,8 @@ function F_VALIDATE(disabledHL) { && !isRoundabout && isLimitOk(78) && address.isOkFor(78)) { - for (var i = 0; i < nodeA.$otherSegmentsLen; i++) { - var otherSegment = nodeA.$otherSegments[i]; + for (let i = 0; i < nodeA.$otherSegmentsLen; i++) { + let otherSegment = nodeA.$otherSegments[i]; if (!otherSegment.$rawObject) continue; // same endpoints if (RR_TRAIL < otherSegment.$typeRank @@ -2914,29 +2636,30 @@ function F_VALIDATE(disabledHL) { && 5 < segmentLen // only for dead-ends && !nodeB.$otherSegmentsLen - && nodeB.$rawNode.getOLGeometry().getBounds() + && nodeB.getCenter() && isLimitOk(108) && address.isOkFor(108)) { // check if any other segment is close to the node B - var IDs = nodeB.$rawNode.attributes.segIDs; - const bd = nodeB.$rawNode.getOLGeometry().getBounds(); - var pt = new OpenLayers.Geometry.Point(bd.left, bd.bottom); - for (var segKey in WMo.segments.objects) { - var seg = WMo.segments.objects[segKey]; - if (segmentID === seg.getID()) continue; - if (!seg.getOLGeometry()) continue; + let IDs = nodeB.rNode.connectedSegmentIds; + const c = nodeB.getCenter(); + const nPt = turf.point( [c.lon, c.lat ] ); + const segs = wmeSDK.DataModel.Segments.getAll(); + for (let r in segs ) { //segmentKey in WMo.segments.objects) { + let seg = segs[r]; + if (segmentID === seg.id) continue; + if (!seg.geometry) continue; // different elevations - if (elevation !== seg.attributes.level) continue; + if (elevation !== seg.elevationLevel) continue; // only for non-deleted segments - if ("Delete" === seg.state) continue; + if (seg.fromNodeId == null && seg.toNodeId == null) continue; //if ("Delete" === seg.state) continue; // only for drivable segments if (RR_TRAIL - >= SimpleOBJECT.prototype.getTypeRank(seg.attributes.roadType)) + >= SimpleOBJECT.prototype.getTypeRank(seg.roadType)) continue; - if (LIMIT_TOLERANCE > seg.getOLGeometry().distanceTo(pt, null)) { + if (LIMIT_TOLERANCE > turf.pointToLineDistance(nPt, seg.geometry, u_meters)) { // other segment is not editable - if (!seg.arePropertiesEditable()) + if (_RT.$topUser.$userLevel <= seg.lockRank) // (!seg.arePropertiesEditable()) segment.$forceNonEditable = true; segment.report(108); break; @@ -3085,8 +2808,8 @@ function F_VALIDATE(disabledHL) { && (nodeB.$otherSegmentsLen || 300 < segmentLen) && isLimitOk(114) && address.isOkFor(114)) { - for (var i = 0; i < nodeA.$otherSegmentsLen; i++) { - var otherSegment = nodeA.$otherSegments[i]; + for (let i = 0; i < nodeA.$otherSegmentsLen; i++) { + let otherSegment = nodeA.$otherSegments[i]; if (!otherSegment.$rawObject) continue; // if one of other segments at node A is drivable @@ -3104,8 +2827,8 @@ function F_VALIDATE(disabledHL) { && (nodeA.$otherSegmentsLen || 300 < segmentLen) && isLimitOk(115) && address.isOkFor(115)) { - for (var i = 0; i < nodeB.$otherSegmentsLen; i++) { - var otherSegment = nodeB.$otherSegments[i]; + for (let i = 0; i < nodeB.$otherSegmentsLen; i++) { + let otherSegment = nodeB.$otherSegments[i]; if (!otherSegment.$rawObject) continue; // if one of other segments at node B is drivable @@ -3124,20 +2847,20 @@ function F_VALIDATE(disabledHL) { // GROUP streetLen // Street type-name checks: {check:type} /** @const */ - var checkIDType = { + let checkIDType = { 160: RT_FREEWAY, 161: RT_MAJOR, 162: RT_MINOR, 163: RT_RAMP, 164: RT_PRIMARY, 165: RT_STREET, 166: RT_PARKING, 167: RT_RAILROAD, 169: 0 }; // mirror checks /** @const */ - var checkIDID = { 160: 70, 161: 71, 162: 72 }; - for (var i in checkIDType) { + let checkIDID = { 160: 70, 161: 71, 162: 72 }; + for (let i in checkIDType) { i = +i; if (!isLimitOk(i) || !address.isOkFor(i)) continue; - var rType = checkIDType[i]; + let rType = checkIDType[i]; options = getCheckOptions(i, countryCode); @@ -3146,7 +2869,7 @@ function F_VALIDATE(disabledHL) { segment.report(i); } else { - var mi = checkIDID[i]; + let mi = checkIDID[i]; if (mi && address.isOkFor(mi) && !matchRegExp(i, segmentID, street, options)) @@ -3156,7 +2879,7 @@ function F_VALIDATE(disabledHL) { // GROUP streetLen // RegExp street name checks - for (var i = CK_STREETNAMEFIRST; i <= CK_STREETNAMELAST; i++) { + for (let i = CK_STREETNAMEFIRST; i <= CK_STREETNAMELAST; i++) { if (!isLimitOk(i) || !address.isOkFor(i)) continue; @@ -3256,23 +2979,23 @@ function F_VALIDATE(disabledHL) { ) { // GROUP isRoundabout.loops // check if roundabout connected to another roundabout - var okA = false; - var okB = false; - var anode, bnode; + let okA = false; + let okB = false; + let anode, bnode; if (DIR_AB === direction) anode = nodeA, bnode = nodeB; else anode = nodeB, bnode = nodeA; - for (var i = 0; i < bnode.$outConnectionsLen; i++) { - var otherSegment = bnode.$outConnections[i]; + for (let i = 0; i < bnode.$outConnectionsLen; i++) { + let otherSegment = bnode.$outConnections[i]; if (otherSegment.$isRoundabout) { okB = true; break; } } if (okB) - for (var i = 0; i < anode.$inConnectionsLen; i++) { - var otherSegment = anode.$inConnections[i]; + for (let i = 0; i < anode.$inConnectionsLen; i++) { + let otherSegment = anode.$inConnections[i]; if (otherSegment.$isRoundabout) { okA = true; break; @@ -3294,28 +3017,32 @@ function F_VALIDATE(disabledHL) { // If places checking enabled... if (_UI.pMain.pFilter.oEnablePlaces.CHECKED) { - for (var venueKey in WMo.venues.objects) { - // check the venues - var rawVenue = WMo.venues.objects[venueKey]; - var venueID = rawVenue.getID(); + const vlist = wmeSDK.DataModel.Venues.getAll(); + for (let i=0; i 0 && (selection.objectType == "segment" || selection.objectType == "venue")) { + //log('addPanelDetails calling updObjProp'); + updateObjectProperties(selection.ids, false); + } +} + +/** + * Update object properties + - Note: this pulled out of F_VALIDATE scope so it can be called from mutation observer. + */ +function updateObjectProperties(selectedObjects, disabledHL) { + if (RTStateIs(ST_RUN) || RTStateIs(ST_CONTINUE)) + return; + + // remove WV properties + var prop = document.getElementById("i" + ID_PROPERTY) + var propDis = document.getElementById("i" + ID_PROPERTY_DISABLED) + var xoptions; + + var defID = ID_PROPERTY; + var defHTML = ''; + if (disabledHL) { + defID = ID_PROPERTY_DISABLED; + defHTML = '
' + + ' ' + + trS("props.disabled") + + '
' + ; + // remove prop + if (prop) { + prop.parentNode.removeChild(prop); + } + prop = propDis; + } + else { + // remove propDis + if (propDis) { + propDis.parentNode.removeChild(propDis); + } + } + + if (prop) + prop.innerHTML = createSafeHtml(defHTML); + else { + var objectProperties = document.getElementsByClassName("address-edit")[0]; + if (!objectProperties) + objectProperties = document.getElementsByClassName("venue-edit-general")[0]; + + if (objectProperties) { + var d = document.createElement("div"); + d.innerHTML = createSafeHtml(defHTML); + d.id = "i" + defID; + d.style.cssText = "text-transform: none; padding: 5px;" + prop = objectProperties.appendChild(d) + } // if objectProperties + } // if prop + + if (disabledHL) + return; + + // check if there are any object selected + if (!selectedObjects.length) + return; + + // find selected issues + var selectedIssues = []; + for (var i = 0; i < selectedObjects.length; i++) { + var objectID = selectedObjects[i]; + if (objectID in _RT.$seen) { + var objectCopy = _RT.$seen[objectID][I_OBJECTCOPY]; + if (!objectCopy) continue; + // object is selected and highlighted + for (var cid in objectCopy.$reportIDs) { + if (objectCopy.$reportIDs.hasOwnProperty(cid)) { + var check = _RT.$checks[cid]; + if (check.REPORTONLY) + continue; + + selectedIssues.push([check, objectCopy, cid]); + } + } + } + } // for all selected objects + + var newProp = 'WME Validator ' + trS("props.reports") + ':' + ; + if (_REP.$isLimitPerCheck) { + newProp += '
' + + '' + + ' ' + + trS("props.limit.title") + + '' + + '
' + + '' + + '
' + + trS("props.limit.problem") + + '.
' + + '' + + '
' + + '

' + trS("props.limit.solution") + '.

' + + '

' + ; + } // limit per check + + // exceptions note + if (skippedObject) { + newProp += '
' + + '' + + ' ' + + trS("props.skipped.title") + + '' + + '
' + + '' + + '
' + + trS("props.skipped.problem") + + '.
' + + '

' + ; + } + + + if (!selectedIssues.length) { + // update properties + if (prop && (_REP.$isLimitPerCheck || skippedObject)) + prop.innerHTML = createSafeHtml(newProp); + return; + } + + // sort the issues + selectedIssues.sort(function (a, b) { return cmpCheckIDs(a[2], b[2]) }); + + // only unique issues + var selectedCounters = {}; + selectedIssues = selectedIssues.filter(function (e, i, arr) { + var checkID = e[2]; + // skip first element + if (i && arr[i - 1][2] === checkID) { + selectedCounters[checkID]++; + return false; + } + selectedCounters[checkID] = 1; + return true; + }); + // create a list of issues + selectedIssues.forEach(function (e) { + var check = e[0]; + var objectCopy = e[1]; + var checkID = e[2]; + var checkCounter = selectedCounters[checkID]; + var sevClass = 0; + var sevIcon = ""; + var sevBG = ""; + var strCountry = _REP.$countries[objectCopy.$countryID]; + var ccode = ""; + + if (strCountry) + ccode = _I18n.getCountryCode(strCountry.toUpperCase()); + else { + // try top country + ccode = _RT.$cachedTopCCode; + } + xoptions = trO(check.OPTIONS, ccode); + + switch (check.SEVERITY) { + case RS_NOTE: + sevClass = CL_NOTE; + sevIcon = "info-circle"; + sevBG = GL_NOTEBGCOLOR; + break; + case RS_WARNING: + sevClass = CL_WARNING; + sevIcon = "exclamation-triangle"; + sevBG = GL_WARNINGBGCOLOR; + break; + case RS_ERROR: + sevClass = CL_ERROR; + sevIcon = "times-circle"; + sevBG = GL_ERRORBGCOLOR; + break; + case RS_CUSTOM1: + sevClass = CL_CUSTOM1; + sevIcon = "user"; + sevBG = GL_CUSTOM1BGCOLOR; + break; + case RS_CUSTOM2: + sevClass = CL_CUSTOM2; + sevIcon = "user"; + sevBG = GL_CUSTOM2BGCOLOR; + break; + } + var shortTitle = exSOS(check.TITLE, xoptions, "titleEN") + .replace("WME Color Highlights", "WMECH") + .replace("WME Toolbox", "WMETB"); + newProp += '
' + + '' + + ' ' + + shortTitle + + (1 < checkCounter ? ' (' + checkCounter + ')' : '') + + '' + + '
' + + '' + + '
' + + '#' + checkID + ' ' + + exSOS(check.PROBLEM, xoptions, "problemEN") + ; + var pl = trO(check.PROBLEMLINK, ccode); + if (pl) { + newProp += ': ' + + trO(check.PROBLEMLINKTEXT, ccode) + + '' + ; + } + else + newProp += '.'; + + newProp += '
'; + + // show howto + if (objectCopy.$isEditable) { + newProp += '' + + '
' + ; + if (check.SOLUTION) { + newProp += '

' + exSOS(check.SOLUTION, xoptions, "solutionEN"); + + var sl = trO(check.SOLUTIONLINK, ccode); + if (sl) { + newProp += ': ' + + trO(check.SOLUTIONLINKTEXT, ccode) + + '' + ; + } + else + newProp += '.'; + + newProp += '

'; + } + } + else { + newProp += '' + + '
' + + '

' + trS("props.noneditable") + '.

'; + ; + } + + // show params + var cityID = objectCopy.$cityID; + var cityParam = _REP.$cityIDs[cityID].$params[checkID]; + if (cityParam) + newProp += '

' + cityParam + '

'; + var streetID = objectCopy.$streetID; + var streetParam = _REP.$cityIDs[cityID] + .$streetIDs[streetID].$params[checkID]; + + if (streetParam) + newProp += '

' + streetParam + '

'; + + newProp += '

' + ; + }); // forEach + + // update properties + if (prop) + prop.innerHTML = createSafeHtml(newProp); +} // updateObjectProperties