// ==UserScript==
// @name LV WME Helper
// @namespace https://dev.laacz.lv/
// @description Miscelannia
// @include https://www.waze.com/*/editor*
// @include https://www.waze.com/editor*
// @include https://beta.waze.com/*
// @exclude https://www.waze.com/*user/*editor/*
// @require https://gf.qytechs.cn/scripts/24851-wazewrap/code/WazeWrap.js
// @require https://cdnjs.cloudflare.com/ajax/libs/jsts/2.0.6/jsts.min.js
// @license CC-BY-4.0; https://creativecommons.org/licenses/by/4.0/
// @version 2.05
// @white
// @connect waze.dev.laacz.lv
// @grant GM.xmlHttpRequest
// ==/UserScript==
// noinspection DuplicatedCode
/* global W */
/* global WazeWrap */
/* global axios */
(function () {
/**
* @typedef Address
* @property code {number}
* @property name {string}
* @property waze_house_number {string}
* @property waze_name {string}
* @property iela_name {string}
* @property ciems_name {string}
* @property pilseta_name {string}
* @property pagasts_name {string}
* @property novads_name {string}
* @property full_name {string}
* @property parent_code {number}
* @property geom {object}
* @property lat {float}
* @property lng {float}
* @property Point {Point}
*/
/**
* Fetched and mutated address list.
* @type {Address[]}
*/
let addresses = [];
// Reassigned by requure()
let UpdateObject = null;
let Landmark = null;
let AddLandmark = null;
let DeleteSegment = null;
// Regluar expressions for validating stuff
const reStreetNames = /(^.+(aleja|apvedceļš|bulvāris|ceļš|dambis|gatve|iela|krastmala|laukums|līnija|prospekts|šķērslīnija|šoseja) (\d+.+$))/;
const reHN = /^(\d+[a-zA-Z]*)( k-\d+)?$/;
// Game loop's interval
let updateTimeout = undefined;
// Indicates that REST request is in progress
let wmelvLoadingIndicator = true;
function wmelvLoading(value) {
if (value !== undefined) {
wmelvLoadingIndicator = value;
qs('#wmelv-loading-indicator').style.visibility = value ? 'visible' : 'hidden';
}
return wmelvLoadingIndicator;
}
/**
* Stores last clicked point on the map
* @type {Point|null}
*/
let lastClick = null;
/**
* Settings object with getters, setters, and default values.
*/
const settings = {
configuration: {
minHNZoomLevel: 16,
hlIncorrectAddress: true,
hlSmallArea: true,
hlLowerCaseHN: true,
hlNoHN: true,
hlNameHNMismatch: true,
addressFixer: false,
hlDupes: true,
hlIela: true,
autoHN: false,
// autoHNSegmentSelection: true,
}, get: function (key, def) {
return typeof this.configuration[key] !== 'undefined' ? this.configuration[key] : def;
}, set: function (key, value) {
this.configuration[key] = value;
this.save();
}, save() {
if (localStorage) {
localStorage.setItem("_wmelv3_settings", JSON.stringify(this.configuration));
}
}, load() {
let loadedSettings = JSON.parse(localStorage.getItem("_wmelv3_settings"));
this.config = Object.assign(this.configuration, loadedSettings ? loadedSettings : {});
}
};
/**
* querySelectorAll shorthand
* @param selector
* @returns {*[]}
*/
function qsa(selector) {
return Array.from(document.querySelectorAll(selector), e => e);
}
/**
* querySelector shorthand.
* @param selector
* @returns {*}
*/
function qs(selector) {
return document.querySelector(selector);
}
/**
* Shamelessly taken from WME PlaceNames Russian:
* https://gf.qytechs.cn/en/scripts/15310-wme-placenames-russian/code
*/
function fixPlaceArea(place) {
let requiredArea = 516,
oldGeometry = place.geometry.clone(),
newGeometry = place.geometry.clone(),
centerPT = newGeometry.getCentroid(),
oldArea = oldGeometry.getGeodesicArea(W.map.getProjectionObject()),
scale = Math.sqrt(requiredArea / oldArea);
newGeometry.resize(scale, centerPT);
let wazeActionUpdateFeatureGeometry = require("Waze/Action/UpdateFeatureGeometry"),
action = new wazeActionUpdateFeatureGeometry(place, W.model.venues, oldGeometry, newGeometry);
place.attributes.fixArea = false;
W.model.actionManager.add(action);
}
function fixCurrentlySelectedArea(e) {
if (e) e.preventDefault();
if (!W.selectionManager.hasSelectedFeatures()
|| W.selectionManager.getSelectedFeatures()[0].model.type !== "venue"
|| !W.selectionManager.getSelectedFeatures()[0].model.isGeometryEditable()) {
return;
}
fixPlaceArea(W.selectionManager.getSelectedFeatures()[0].model);
wmelvUpdate();
}
/**
* Colorful logger ;)
* @type {{warn(...[*]): void, debug(...[*]): void, crit(...[*]): void, log(*, ...[*]): void, info(...[*]): void}}
*/
const Logger = {
log(style, ...args) {
console.log("%c●%c", style, 'color: #000; background-color: #fff;', ...args)
}, debug(...args) {
Logger.log('background-color: gray; color: #fff; font-weight: bold; padding: .2em .5em;', ...args)
}, info(...args) {
Logger.log('background-color: navy; color: #fff; font-weight: bold; padding: .2em .5em;', ...args)
}, crit(...args) {
Logger.log('background-color: maroon; color: #fff; font-weight: bold; padding: .2em .5em;', ...args)
}, warn(...args) {
Logger.log('background-color: orange; color: #fff; font-weight: bold; padding: .2em .5em;', ...args)
},
}
/**
* Returns closest address to a given point on the map.
* @return Address|null
*/
function getClosestAddress(venue) {
const centroid = venue.geometry.getCentroid();
centroid.transform('EPSG:900913', "EPSG:4326");
return addresses.length ? addresses.reduce((prev, curr) => {
if (!prev) return curr;
return prev.Point.distanceTo(centroid) < curr.Point.distanceTo(centroid) ? prev : curr;
}) : null;
}
/**
* Helper to build a bbox string from the map's extent.
* @returns {string}
*/
function wmelvBBOX() {
const bounds = W.map.getExtent();
bounds.transform("EPSG:900913", "EPSG:4326");
return bounds.toBBOX();
}
/**
* Adds stuff to addresses which cannot be added in the backend.
* @param addresses
* @returns {*}
*/
function wmelvMutateAddresses(addresses) {
if (addresses && addresses.length) {
addresses = addresses.map((ads) => {
ads.Point = new OpenLayers.Geometry.Point(ads.lng, ads.lat);
return ads;
})
}
return addresses;
}
/**
* Creates a new place, given a geometry and attributes, selects it and registers in the actionmanager's history.
* @param geometry
* @param params
* @returns {*}
*/
function wmelvCreateNewPlace(geometry, params) {
let place = new Landmark();
if (!params) params = {};
if (!params.categories || !params.categories.length) params.categories = ["OTHER"];
place.geometry = geometry;
place.attributes.name = params.name ? params.name : '';
place.attributes.lockRank = params.lockRank ? params.lockRank : 2;
params.categories.forEach(cat => {
place.attributes.categories.push(cat);
});
place.attributes.entryExitPoints.push(new NavigationPoint(place.geometry.getCentroid()));
W.model.actionManager.add(new AddLandmark(place));
W.selectionManager.setSelectedModels([place]);
if (params.address && Object.keys(params.address).length) {
W.model.actionManager.add(new UpdateObject(place, params.address));
}
return place;
}
/**
* Game loop as they say.
*/
function wmelvUpdate() {
if (updateTimeout) {
clearTimeout(updateTimeout);
}
if (!wmelvLoading()) {
Object.keys(W.model.venues.objects).forEach((k) => {
// Object.values(W.model.venues.objects).forEach((v) => {
const venue = W.model.venues.objects[k];
const el = qs('#' + venue.geometry.id);
if (!el) {
return
}
if ('attributes' in venue) {
let v = venue.attributes;
// Logger.info(v.attributes.name, 'closest address is', closest.full_name)
let hn = v.houseNumber;
let street = {name: ''};
let city = {name: ''};
if (v.streetID) {
street = W.model.streets.objects[v.streetID];
}
if (street) {
city = W.model.cities.objects[street.cityID].attributes
}
const full_address = `${hn}, ${street.name}, ${city.name}`;
const area = W.model.venues.objects[k].geometry.toString().indexOf('POLYGON') === 0
? W.model.venues.objects[k].geometry.getGeodesicArea(W.map.getProjectionObject())
: false;
W.model.venues.objects[k].attributes.fixLowerCase =
(v.houseNumber && v.houseNumber.toUpperCase() !== v.houseNumber) ||
(v.houseNumber && v.name && v.name.toUpperCase() === v.houseNumber.toUpperCase() && v.name !== v.houseNumber.toUpperCase()) ||
(v.name && v.name.replace(/ k-\d+$/, '').match(/^\d+[a-z]+/) && v.name.replace(/ k-\d+$/, '').toUpperCase() !== v.name.replace(/ k-\d+$/, ''));
W.model.venues.objects[k].attributes.fixNameHNMismatch =
!v.residential &&
(
(v.houseNumber && !v.name) ||
(
v.houseNumber &&
v.name &&
v.name.match(reHN) &&
v.houseNumber.toLowerCase() !== v.name.toLowerCase().replace(' k-', '-'))
);
W.model.venues.objects[k].attributes.fixNoHN =
!v.houseNumber &&
v.streetID && W.model.streets.objects[v.streetID] &&
W.model.streets.objects[v.streetID].name &&
W.model.streets.objects[v.streetID].cityID &&
W.model.cities.objects[W.model.streets.objects[v.streetID].cityID] &&
W.model.cities.objects[W.model.streets.objects[v.streetID].cityID].attributes.name &&
v.categories.indexOf('PARKING_LOT') === -1 &&
v.categories.indexOf('TAXI_STATION') === -1 &&
v.categories.indexOf('PARK') === -1;
W.model.venues.objects[k].attributes.fixIela = v.name.toLowerCase().match(reStreetNames);
W.model.venues.objects[k].attributes.fixArea = !v.residential && area !== false && area < 550 ? area : false;
// wmelvCounts.fixArea += !!W.model.venues.objects[k].attributes.fixArea;
// wmelvCounts.fixLowerCase += !!W.model.venues.objects[k].attributes.fixLowerCase;
// wmelvCounts.fixIela += !!W.model.venues.objects[k].attributes.fixIela;
const closest = getClosestAddress(venue);
if (closest) {
W.model.venues.objects[k].attributes.fixAddress =
closest.waze_name !== full_address &&
v.categories.indexOf('PARKING_LOT') === -1 &&
v.categories.indexOf('TAXI_STATION') === -1 &&
v.categories.indexOf('PARK') === -1;
W.model.venues.objects[k].attributes.ads = closest;
}
// if (full_address !== closest.waze_name) {
// Logger.warn(`[${full_address}] is not at [${closest.waze_name}]`)
// el.setAttribute('stroke', '#ff0000');
// el.setAttribute("stroke-width", "4");
// el.setAttribute("stroke-dash-array", "none");
// }
} else {
// Logger.warn(v.attributes.name, 'has no closest address')
}
});
wmelvDraw();
}
updateTimeout = setTimeout(wmelvUpdate, 345);
}
/**
* Updates visualizations.
*/
function wmelvDraw() {
Object.values(W.model.venues.objects).forEach((v) => {
let el = qs('#' + v.geometry.id), hled = false;
if (el) {
if (!el.getAttribute('ogAttributes')) {
el.setAttribute('ogAttributes', {
'stroke': el.getAttribute('stroke'),
"stroke-width": el.getAttribute("stroke-width"),
"stroke-dash-array": el.getAttribute("stroke-dash-array"),
});
}
if (!hled && settings.get('hlIncorrectAddress') && v.attributes.fixAddress) {
el.setAttribute('stroke', '#ff00ff');
el.setAttribute("stroke-width", "4");
el.setAttribute("stroke-dash-array", "none");
hled = true;
}
if (!hled && ((settings.get('hlLowerCaseHN') && v.attributes.fixLowerCase) || (settings.get('hlNoHN') && v.attributes.fixNoHN) || (settings.get('hlIela') && v.attributes.fixIela))) {
el.setAttribute('stroke', '#ff0000');
el.setAttribute("stroke-width", "4");
el.setAttribute("stroke-dash-array", "none");
hled = true;
}
if (!hled && settings.get('hlSmallArea') && el && v.attributes.fixArea) {
el.setAttribute('stroke', '#0000ff');
el.setAttribute("stroke-width", "4");
el.setAttribute("stroke-dash-array", "none");
hled = true;
}
if (!hled && settings.get('hlNameHNMismatch') && el && v.attributes.fixNameHNMismatch) {
el.setAttribute('stroke', '#ffff00');
el.setAttribute("stroke-width", "4");
el.setAttribute("stroke-dash-array", "none");
hled = true;
}
if (!hled && settings.get('hlDupes') && el && v.attributes.fixDupes) {
el.setAttribute('stroke', '#00ffff');
el.setAttribute("stroke-width", "4");
el.setAttribute("stroke-dash-array", "none");
hled = true;
}
// const shouldRevert = !hled && el.getAttribute('ogAttributes').all((k, v) => el.getAttribute(k) === v);
// if (!hled) {
// Logger.info('Reverting HL');
// const attrs = el.getAttribute('ogAttributes');
// el.setAttribute('stroke', attrs['stroke']);
// el.setAttribute("stroke-width", attrs["stroke-width"]);
// el.setAttribute("stroke-dash-array", attrs["stroke-dash-array"]);
// }
}
});
}
/**
* Fetches VZD addresses from an API. Restricts to viewport plus a tiny buffer.
*/
function wmelvLoadAddresses() {
if (!settings.get('autoHN') || W.map.getZoom() < 16) {
if (W.map.getLayersByName("pointLayer").length) {
W.map.removeLayer(W.map.getLayersByName("pointLayer")[0]);
}
return;
}
const request = {
bounds: wmelvBBOX(),
}
wmelvLoading(true);
GM.xmlHttpRequest({
method: 'POST', url: '//waze.dev.laacz.lv/api/2/addresses', data: JSON.stringify(request), headers: {
'Content-Type': 'application/json'
}, onload: function (response) {
addresses = JSON.parse(response.responseText);
addresses = wmelvMutateAddresses(addresses)
if (W.map.getLayersByName("pointLayer").length) {
W.map.removeLayer(W.map.getLayersByName("pointLayer")[0]);
}
const pointLayer = new OpenLayers.Layer.Vector("pointLayer");
const proj = new OpenLayers.Projection("EPSG:4326");
const features = [];
for (const addr of addresses) {
const point = new OpenLayers.Geometry.Point(addr.lng, addr.lat).transform(proj, W.map.getProjectionObject());
const ft = new OpenLayers.Feature.Vector(point, null, null);
ft.style = {
label: addr.name,
pointRadius: 15,
fillColor: addr.color,
fillOpacity: 0.8,
strokeColor: "#cc6633",
strokeWidth: 2,
strokeOpacity: 0.8,
fontColor: "black",
labelOutlineColor: "white",
labelOutlineWidth: 3,
};
features.push(ft);
}
pointLayer.addFeatures(features);
W.map.addLayer(pointLayer);
wmelvLoading(false);
wmelvUpdate();
},
onerror: () => {
wmelvLoading(false);
},
onabort: () => {
wmelvLoading(false);
},
ontimeout: () => {
wmelvLoading(false);
},
});
}
/**
* Triggered when selection changes (user selects or deselects a WME feature)
* @param e {Event}
*/
function wmeSelectionChanged(e) {
if (e &&
W.selectionManager.hasSelectedFeatures() &&
W.selectionManager.getSelectedFeatures().length === 1 &&
W.selectionManager.getSelectedFeatures()[0].model.type === "venue") {
const venue = W.selectionManager.getSelectedFeatures()[0].model.attributes;
let warnings = []
let html = `<div class="action-buttons"><div class="alert addresses"></div>`;
if (venue.fixAddress) warnings.push('Ēkas adrese, iespējams, nav korekta (tuvākā ir ' + venue.ads.waze_name + '; <a href="#" id="fixCurrentlySelectedVenueAddress">salabot</a>)');
if (venue.fixLowerCase) warnings.push('Ēkas numurs satur mazo burtu (<a href="" id="fixThisLowerCase">salabot</a>)');
if (venue.fixNameHNMismatch) warnings.push('Ēkas numurs nesakrīt ar numuru nosaukumā<br/>' + '(<a href="#" id="fixNameHNMismatchToAddress">pareiza adrese</a>, <a href="" id="fixNameHNMismatchToName">pareizs nosaukums</a>)');
if (venue.fixIela) warnings.push('Vietas nosaukums satur "' + venue.name.match(reStreetNames)[0] + '" (<a href="#" id="fixIelaInName">salabot</a>)');
if (venue.fixNoHN) warnings.push('Adrese ir, bet ēkas numura nav');
if (venue.fixArea) warnings.push('Laukuma platība ' + Math.floor(venue.fixArea) + 'm² ir mazāka par 550m² (<a href="#" id="fixThisArea">salabot</a>)');
html += warnings.map(warning => `<div class="alert alert-danger">${warning}</div>`).join('');
html += '</div>';
/**
* Update landmark edit tab.
*/
if (!qs('#wmelv-landmark-edit')) {
let div = document.createElement('div');
div.id = 'wmelv-landmark-edit';
qs('#venue-edit-general').insertBefore(div, qs('#venue-edit-general').firstChild);
}
qs('#wmelv-landmark-edit').innerHTML = html;
if (qs('#fixCurrentlySelectedVenueAddress')) {
qs('#fixCurrentlySelectedVenueAddress').addEventListener('click', (e) => {
e.preventDefault();
let venue = W.selectionManager.getSelectedFeatures()[0];
let venue_id = venue.model.attributes.id;
const closest = getClosestAddress(venue);
// wmllvSetAddress(venue, closest);
const street = Object.values(W.model.streets.objects).find((street) => street.name === closest.iela_name);
const changes = {
name: closest.name.replace(' k-', '-'),
houseNumber: closest.iela_name ? closest.waze_house_number : null,
streetID: street ? street.id : null,
};
if (changes) W.model.actionManager.add(new UpdateObject(venue.model, changes));
W.selectionManager.unselectAll();
W.selectionManager.setSelectedModels([W.model.venues.objects[venue_id]]);
})
}
if (qs('#fixNameHNMismatchToAddress')) {
qs('#fixNameHNMismatchToAddress').addEventListener('click', (e) => {
e.preventDefault();
let venue = W.selectionManager.getSelectedFeatures()[0],
changes = {
name: venue.model.attributes.houseNumber.replace('-', ' k-'),
};
if (changes) W.model.actionManager.add(new UpdateObject(venue.model, changes));
})
}
if (qs('#fixNameHNMismatchToName')) {
qs('#fixNameHNMismatchToName').addEventListener('click', (e) => {
e.preventDefault();
let venue = W.selectionManager.getSelectedFeatures()[0],
changes = {
houseNumber: venue.model.attributes.name.replace(' k-', '-'),
};
if (changes) W.model.actionManager.add(new UpdateObject(venue.model, changes));
})
}
if (qs('#fixThisArea')) {
qs('#fixThisArea').addEventListener('click', fixCurrentlySelectedArea);
}
if (qs('#fixIelaInName')) {
qs('#fixIelaInName').addEventListener('click', (e) => {
e.preventDefault();
let venue = W.selectionManager.getSelectedFeatures()[0],
name = venue.model.attributes.name,
changes = {
name: name.replace(reStreetNames, '$3'),
};
if (changes) W.model.actionManager.add(new UpdateObject(venue.model, changes));
});
}
if (qs('#fixThisLowerCase')) {
qs('#fixThisLowerCase').addEventListener('click', (e) => {
e.preventDefault();
let changes = {};
if (venue.attributes.houseNumber && venue.attributes.houseNumber.toUpperCase() !== venue.attributes.houseNumber) {
changes.houseNumber = venue.attributes.houseNumber.toUpperCase();
}
if (venue.attributes.name && venue.attributes.name.match(/^\d+[a-z][^a-z]*/)) {
changes.name = venue.attributes.name.toUpperCase().replace(' K-', ' k-');
if (venue.attributes.houseNumber) changes.houseNumber = venue.attributes.houseNumber.toUpperCase();
}
if (changes) W.model.actionManager.add(new UpdateObject(venue, changes));
wmelvUpdate();
});
}
}
}
/**
* Creates WME tab and registers all corresponding event listeners on inputs.
*/
function wmelvRegisterTab() {
let style = document.getElementById('wmelv-style');
if (!style) {
style = document.createElement('style');
style.id = 'wmelv-style';
document.head.appendChild(style);
}
style.innerText = `
#wmelv-loading-indicator {
text-align: center;
display: inline-block;
}
#wmelv-loading-indicator path,
#wmelv-loading-indicator rect {
fill: #FF6700;
}
#sidepanel-wmelv hr {
height: 1px;
width: 100%;
border-top: 1px solid #ccc;
}
#sidepanel-wmelv label {
white-space: normal;
}
.waze-btn:disabled {
cursor: no-drop;
}
#applyAllAddresses {
text-align: center;
}
.count {
background-color: #009900;
color: #fff;
font-size: 90%;
border-radius: 25%;
padding-left: .5rem;
margin-left: 1rem;
padding-right: .5rem;
}
#wmelv-landmark-edit .alert {
margin-bottom: .25rem;
text-transform: none;
font-size: 12px;
}
#wmelv-landmark-edit .alert-danger {
border: 1px solid #ed503b;
}
.alert .waze-btn.waze-btn-blue {
box-shadow: none;
}
#zoom-level-warning {
color: red;
font-weight: bold;
}
.wme-lv-details {
font-weight: bold;
color: green;
}
#wmelv-convert-to-area {
margin-top: .25rem;
}
#wmelv-venues-list ul {
margin: 1rem;
padding: 0;
}
#wmelv-venues-list ul li {
list-style-type: none;
margin: 0;
padding: 0;
}
#wmelv-venues-list [data-type]:before {
content: "";
display: inline-block;
position: relative;
top: 1px;
background-image: url(//editor-assets.waze.com/production/img/buttons756c103910d73f4d45328e08f6016871.png);
width: 11px;
height: 11px;
margin-right: 5px;
}
#wmelv-venues-list [data-type="point"]:before {
background-position: -49px -58px;
}
#wmelv-venues-list [data-type="area"]:before {
background-position: -25px -58px;
}
#wmelv-venues-list li a {
text-decoration: none;
}
.wmelv-lock-rank {
box-shadow: 0 4px 4px 0 #def7ff;
color: #fff;
background: #32a852;
height: 23px;
line-height: 23px;
margin-right: 1px;
text-align: center;
font-weight: normal;
font-size: 13px;
padding-left: 8px;
padding-right: 8px;
border-radius: 13px;
}
[data-lock-rank="0"] .wmelv-lock-rank,
[data-lock-rank="1"] .wmelv-lock-rank {
background: #ff7f00;
}
`;
settings.load();
const html = `
<div class="form-group">
<span id="zoom-level-warning" style="display: none;">Zoom par mazu. Funkcionalitāte atslēgta.</span>
</div>
<div class="form-group">
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="hlSmallArea"
id="hlSmallArea"
${settings.get('hlSmallArea') ? 'checked' : ''}
><label for="hlSmallArea"> Vietas, kuras mazākas par 550m² (zils)</label>
</div>
</div>
<div class="form-group">
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="hlIncorrectAddress"
id="hlIncorrectAddress"
${settings.get('hlIncorrectAddress') ? 'checked' : ''}
><label for="hlIncorrectAddress"> Vietas, kurām adrešu reģistra adrese atšķiras no Waze (lillā)</label>
</div>
</div>
<div class="form-group">
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="hlNoHN"
id="hlNoHN"
${settings.get('hlNoHN') ? 'checked' : ''}
><label for="hlNoHN"> Adresē ir iela, pilsēta, bet nav ēkas numura (sarkans)</label>
</div>
</div>
<div class="form-group">
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="hlIela"
id="hlIela"
${settings.get('hlIela') ? 'checked' : ''}
><label for="hlIela"> Vietas nosaukumā ir vārds "iela" (sarkans)</label>
</div>
</div>
<div class="form-group">
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="hlLowerCaseHN"
id="hlLowerCaseHN"
${settings.get('hlLowerCaseHN') ? 'checked' : ''}
><label for="hlLowerCaseHN"> Ēkas numurā ir mazie burti (sarkans)</label>
</div>
</div>
<div class="form-group">
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="hlNameHNMismatch"
id="hlNameHNMismatch"
${settings.get('hlNameHNMismatch') ? 'checked' : ''}
><label for="hlNameHNMismatch"> Ēkas numurs adresē un numurs nosaukumā nesakrīt (dzeltens)</label>
</div>
</div>
<div class="form-group" data-hide>
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="hlDupes"
id="hlDupes"
${settings.get('hlDupes') ? 'checked' : ''}
><label for="hlDupes"> Identiski objekti, viens uz otra (gaiši zils)</label>
</div>
</div>
<!--
<div class="form-group" data-api-required>
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="addressFixer"
id="addressFixer"
${settings.get('addressFixer') ? 'checked' : ''}
><label for="addressFixer"> Adrešu labotājs</label>
</div>
</div>
-->
<div class="form-group" data-api-required>
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="autoHN"
id="autoHN"
${settings.get('autoHN') ? 'checked' : ''}
><label for="autoHN"> Ielādēt adreses automātiski</label>
</div>
</div>
<!--
<div class="form-group" data-api-required>
<div class="controls-container">
<input type="checkbox"
class="settings-input"
name="autoHNSegmentSelection"
id="autoHNSegmentSelection"
${settings.get('autoHNSegmentSelection') ? 'checked' : ''}
><label for="autoHNSegmentSelection"> Iezīmējot segmentu, rādīt tikai tās ielas HN</label>
</div>
</div>
-->
<!--
<div id="wmelv-place-info" data-api-required>
<hr>
<p id="wmlelv-place-info">Noklikšķini kartē un tadā.</p>
<div class="action-buttons">
<button class="waze-btn waze-btn-smaller" type="submit" id="wmelvCreatePlace" data-action="create-place" data-ratio="1:1">Izveidot 1:1</button>
<button class="waze-btn waze-btn-smaller" type="submit" id="wmelvCreatePlace2" data-action="create-place" data-ratio="2:1">Izveidot 2:1</button>
</div>
</div>
-->
<hr>
<p>
Tu esi ${W.loginManager.user.userName} (level ${W.loginManager.user.rank + 1}), es esmu skripts.
</p>
<hr>
<div class="form-group" data-api-required>
<label class="control-label">Funkcionalitāte sāk darboties, ja zoom ir vismaz:</label>
<div class="controls">
<div class="form-control waze-radio-container" style="display: block;">
<input type="radio" name="minHNZoomLevel" value="3" id="minHNZoomLevel-3" ${parseInt(settings.get('minHNZoomLevel')) === 3 ? 'checked' : ''}>
<label for="minHNZoomLevel-3">3 (drosmīgajiem)</label>
<input type="radio" name="minHNZoomLevel" value="4" id="minHNZoomLevel-4" ${parseInt(settings.get('minHNZoomLevel')) === 4 ? 'checked' : ''}>
<label for="minHNZoomLevel-4">4</label>
<input type="radio" name="minHNZoomLevel" value="5" id="minHNZoomLevel-5" ${parseInt(settings.get('minHNZoomLevel')) === 5 ? 'checked' : ''}>
<label for="minHNZoomLevel-5">5</label>
<input type="radio" name="minHNZoomLevel" value="6" id="minHNZoomLevel-6" ${parseInt(settings.get('minHNZoomLevel')) === 6 ? 'checked' : ''}>
<label for="minHNZoomLevel-6">6</label>
</div>
</div>
</div>
<!--
<div class="form-group">
<label class="control-label" for="segmentToHouseWidth">Ēkas platums, veidojot to no segmenta</label>
<div class="controls">
<input class="form-control settings-input" name="segmentToHouseWidth" type="number" id="segmentToHouseWidth" value="${settings.get('segmentToHouseWidth')}">
</div>
</div>
-->
<hr>
<dl>
<dt>2.05</dt>
<dd>Minimālais <em>area</em> izmērs palielināts uz 550m²</dd>
<dt>2.04</dt>
<dd>Adreses maiņas rezultātā tā nomainās arī saskarnē.</dd>
<dt>2.03</dt>
<dd>Iespēja koriģēt kļūda (laukumu, adreses, utt) ar vienu pogas klikšķi.</dd>
<dd>Paplašinājums vairs nesalauž Google StreetView.</dd>
<dd>Vēl kārtīgi jātestē, jo daudz kas nestrādā.</dd>
<dd>Ielādes indikācija blakus cilnes nosaukumam.</dd>
<dt>2.02</dt>
<dd>Salasāmāki māju numuri un nosaukumi.</dd>
<dt>2.01</dt>
<dd>Labota kļūda ar ķekškastīti pie VZD adrešu neatbilstību krāsošanas</dd>
<dt>2.00</dt>
<dd>Pirmā publiskā versija</dd>
</dl>
<hr>
`;
//<div class="loader loader--style3" id="wmelv-loading-indicator" title="2"><svg version="1.1" id="loader-1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="40px" height="40px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"><path fill="#000" d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z"><animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="0.6s" repeatCount="indefinite"/></path></svg></div>
new WazeWrap.Interface.Tab('WME LV', html, () => {
Array.from(document.querySelectorAll("#user-tabs > ul > li")).map((el) => {
const a = el.querySelector('a')
if (a && a.innerText === 'WME LV') {
a.innerHTML = `
WME LV
<svg id="wmelv-loading-indicator" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="10px" height="10px" viewBox="0 0 50 50" style="enable-background:new 0 0 50 50;" xml:space="preserve"><path fill="#000" d="M43.935,25.145c0-10.318-8.364-18.683-18.683-18.683c-10.318,0-18.683,8.365-18.683,18.683h4.068c0-8.071,6.543-14.615,14.615-14.615c8.072,0,14.615,6.543,14.615,14.615H43.935z"><animateTransform attributeType="xml" attributeName="transform" type="rotate" from="0 25 25" to="360 25 25" dur="0.6s" repeatCount="indefinite"/></path></svg>
`
}
})
// Attach settings change handler to corresponding inputs
qsa('.settings-input').forEach(element => {
element.addEventListener('change', event => {
settings.set(event.target.name, event.target.type === 'checkbox' ? event.target.checked : event.target.value);
wmelvUpdate();
wmelvLoadAddresses();
})
});
qsa('[name="minHNZoomLevel"]').forEach(element => {
element.addEventListener('change', event => {
settings.set('minHNZoomLevel', parseInt(event.target.value));
});
});
// qsa('[data-action="create-place"]').forEach(el => {
// el.addEventListener('click', (e) => {
// log.info(e.target)
// const vertex = 22.57;
//
// let place = new Landmark()
// let poly = new OpenLayers.Geometry.LinearRing([
// new OpenLayers.Geometry.Point(lastClick.lon - vertex, lastClick.lat - (e.target.dataset.ratio === '2:1' ? vertex / 2 : vertex)),
// new OpenLayers.Geometry.Point(lastClick.lon - vertex, lastClick.lat + (e.target.dataset.ratio === '2:1' ? vertex / 2 : vertex)),
// new OpenLayers.Geometry.Point(lastClick.lon + vertex, lastClick.lat + (e.target.dataset.ratio === '2:1' ? vertex / 2 : vertex)),
// new OpenLayers.Geometry.Point(lastClick.lon + vertex, lastClick.lat - (e.target.dataset.ratio === '2:1' ? vertex / 2 : vertex)),
// new OpenLayers.Geometry.Point(lastClick.lon - vertex, lastClick.lat - (e.target.dataset.ratio === '2:1' ? vertex / 2 : vertex)),
// ]);
// poly.rotate(10, poly.getCentroid());
//
// place = wmelvCreateNewPlace(new OpenLayers.Geometry.Polygon([poly]), {});
//
// const closest = getClosestAddress(lastClick)
// if (closest) {
// setVenueAddress(place.attributes.id, 0);
// fixPlaceArea(place);
// }
// });
// });
});
//
// update();
}
/**
* Registers global handlers which apply to W and W.map.
*/
function wmelvRegisterGlobalHandlers() {
W.map.events.register('zoomend', this, () => {
// updateVenuesFilterList();
// updateAddressSuggestions();
});
W.map.events.register('moveend', this, () => {
wmelvLoadAddresses();
});
W.selectionManager.events.register('selectionchanged', this, wmeSelectionChanged);
/**
* Registers click handler to the main map. That's me - being a smartass.
*/
// W.map.events.register('mousedown', (e) => {
// console.log(e.target);
// if (e && e.xy) {
// lastClick = W.map.getLonLatFromViewPortPx(e.xy).clone();
// const point = (new OpenLayers.Geometry.Point(lastClick.lon, lastClick.lat)).transform('EPSG:900913', 'EPSG:4326');
// const closest = getClosestAddress(point);
// console.log(closest);
// qs('#wmlelv-place-info').innerHTML = closest
// ? `Tuvākā vieta: <strong>${closest.waze_name}<strong>`
// : 'Noklikšķini adreses tuvumā kartē un tadā.';
// }
// }, true)
}
/**
* Initializes application.
*/
function init() {
Logger.info('WMELV initializing...');
UpdateObject = require("Waze/Action/UpdateObject");
Landmark = require("Waze/Feature/Vector/Landmark");
AddLandmark = require("Waze/Action/AddLandmark");
DeleteSegment = require("Waze/Action/DeleteSegment");
wmelvRegisterGlobalHandlers();
wmelvRegisterTab();
wmelvLoadAddresses();
wmelvUpdate();
Logger.info('WMELV initialized.');
}
/**
* Starts waiting for W to load. Max 1000 times (100 seconds)
* @param tries {number}
*/
function bootstrap(tries = 1) {
if (W &&
W.map &&
W.model &&
W.loginManager.user &&
typeof W.selectionManager !== 'undefined' &&
typeof WazeWrap !== "undefined" &&
WazeWrap.Ready
) {
init();
} else if (tries < 1000) {
setTimeout(() => {
bootstrap(tries + 1);
}, 200);
}
}
Logger.info('WMELV waiting...');
bootstrap();
}());
/* end ======================================================================= */