From 36efbca08c84a9e1fd2ecaf5fc62c4e5ea8126e5 Mon Sep 17 00:00:00 2001
From: rapotek <17698165+rapotek@users.noreply.github.com>
Date: Fri, 10 Jul 2020 15:37:14 +0200
Subject: [PATCH 01/17] Interactive Map: validation ready
---
config/map.default.php | 6 +
lib/languages/en.php | 3 +
.../chunks/interactiveMap/interactiveMap.css | 289 ++++
.../chunks/interactiveMap/interactiveMap.js | 1365 +++++++++++++++++
.../chunks/interactiveMap/markers/ocMarker.js | 79 +
.../markers/simple/cacheMarker.js | 31 +
.../markers/simple/highlightedMarker.js | 32 +
.../markers/simple/logMarker.js | 31 +
public/views/myNbhInteractive/common.css | 166 ++
public/views/myNbhInteractive/config.js | 50 +
public/views/myNbhInteractive/config_draw.js | 307 ++++
.../myNbhInteractive/myNeighbourhood-full.css | 13 +
.../myNbhInteractive/myNeighbourhood-min.css | 13 +
.../views/myNbhInteractive/myNeighbourhood.js | 83 +
.../MyNbhInteractiveController.php | 744 +++++++++
.../AbstractMarkerModelBase.php | 42 +
.../InteractiveMap/CacheMarkerModel.php | 129 ++
.../InteractiveMap/InteractiveMapModel.php | 259 ++++
.../InteractiveMap/LogMarkerModel.php | 71 +
src/Models/GeoCache/GeoCache.php | 35 +
src/Models/GeoCache/GeoCacheCommons.php | 24 +
src/Models/GeoCache/GeoCacheLogCommons.php | 24 +
src/Models/Neighbourhood/Neighbourhood.php | 11 +
src/Models/OcConfig/MapConfigTrait.php | 6 +
.../interactiveMap/interactiveMap.tpl.php | 100 ++
.../markers/cacheMarkerMgr.tpl.php | 19 +
.../markers/cacheMarkerPopup.tpl.php | 101 ++
.../markers/cacheSetMarkerMgr.tpl.php | 37 +
.../markers/cacheWithLogMarkerMgr.tpl.php | 37 +
.../markers/guideMarkerMgr.tpl.php | 38 +
.../markers/guideMarkerPopup.tpl.php | 49 +
.../markers/logMarkerMgr.tpl.php | 18 +
.../markers/logMarkerPopup.tpl.php | 48 +
src/Views/myNbhInteractive/config.tpl.php | 167 ++
.../myNbhInteractive/detail_FTFCaches.tpl.php | 52 +
.../detail_LatestCaches.tpl.php | 79 +
.../detail_LatestLogs.tpl.php | 70 +
.../detail_RecommendedCaches.tpl.php | 79 +
.../detail_TitledCaches.tpl.php | 87 ++
.../detail_UpcommingEvents.tpl.php | 72 +
.../myNbhInteractive/myNeighbourhood.tpl.php | 82 +
.../myNbhInteractive/sub_FTFCaches.tpl.php | 46 +
.../myNbhInteractive/sub_LatestCaches.tpl.php | 52 +
.../myNbhInteractive/sub_LatestLogs.tpl.php | 54 +
src/Views/myNbhInteractive/sub_Map.tpl.php | 14 +
.../sub_RecommendedCaches.tpl.php | 48 +
.../myNbhInteractive/sub_TitledCaches.tpl.php | 57 +
.../sub_UpcommingEvents.tpl.php | 45 +
48 files changed, 5264 insertions(+)
create mode 100644 public/views/chunks/interactiveMap/interactiveMap.css
create mode 100644 public/views/chunks/interactiveMap/interactiveMap.js
create mode 100644 public/views/chunks/interactiveMap/markers/ocMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/simple/cacheMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/simple/highlightedMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/simple/logMarker.js
create mode 100644 public/views/myNbhInteractive/common.css
create mode 100644 public/views/myNbhInteractive/config.js
create mode 100644 public/views/myNbhInteractive/config_draw.js
create mode 100644 public/views/myNbhInteractive/myNeighbourhood-full.css
create mode 100644 public/views/myNbhInteractive/myNeighbourhood-min.css
create mode 100644 public/views/myNbhInteractive/myNeighbourhood.js
create mode 100644 src/Controllers/MyNbhInteractiveController.php
create mode 100644 src/Models/ChunkModels/InteractiveMap/AbstractMarkerModelBase.php
create mode 100644 src/Models/ChunkModels/InteractiveMap/CacheMarkerModel.php
create mode 100644 src/Models/ChunkModels/InteractiveMap/InteractiveMapModel.php
create mode 100644 src/Models/ChunkModels/InteractiveMap/LogMarkerModel.php
create mode 100644 src/Views/chunks/interactiveMap/interactiveMap.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/cacheMarkerMgr.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/cacheMarkerPopup.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/cacheSetMarkerMgr.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/cacheWithLogMarkerMgr.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/guideMarkerMgr.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/guideMarkerPopup.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/logMarkerMgr.tpl.php
create mode 100644 src/Views/chunks/interactiveMap/markers/logMarkerPopup.tpl.php
create mode 100644 src/Views/myNbhInteractive/config.tpl.php
create mode 100644 src/Views/myNbhInteractive/detail_FTFCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/detail_LatestCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/detail_LatestLogs.tpl.php
create mode 100644 src/Views/myNbhInteractive/detail_RecommendedCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/detail_TitledCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/detail_UpcommingEvents.tpl.php
create mode 100644 src/Views/myNbhInteractive/myNeighbourhood.tpl.php
create mode 100644 src/Views/myNbhInteractive/sub_FTFCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/sub_LatestCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/sub_LatestLogs.tpl.php
create mode 100644 src/Views/myNbhInteractive/sub_Map.tpl.php
create mode 100644 src/Views/myNbhInteractive/sub_RecommendedCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/sub_TitledCaches.tpl.php
create mode 100644 src/Views/myNbhInteractive/sub_UpcommingEvents.tpl.php
diff --git a/config/map.default.php b/config/map.default.php
index 838bd2dd8b..219e5b84e9 100644
--- a/config/map.default.php
+++ b/config/map.default.php
@@ -79,6 +79,12 @@
*/
$map['startPageMapDimensions'] = [250, 260];
+/**
+ * A family of marker styling used in interactive map.
+ * Currently supported values: 'simple'
+ */
+$map['markersFamily'] = 'simple';
+
/**
* Links to external maps used at least at viewpage
* (to disable map - just add key $map['external']['OSMapa']['enabled'] = false;)
diff --git a/lib/languages/en.php b/lib/languages/en.php
index 4d57f05866..a922a630d5 100644
--- a/lib/languages/en.php
+++ b/lib/languages/en.php
@@ -3028,4 +3028,7 @@
'gpMyCandidates_offerRefused' => 'Offer refused',
'edit_description' => 'Edit description',
+
+ 'map_popup_next' => 'Next',
+ 'map_popup_previous' => 'Previous'
);
diff --git a/public/views/chunks/interactiveMap/interactiveMap.css b/public/views/chunks/interactiveMap/interactiveMap.css
new file mode 100644
index 0000000000..cf63031f68
--- /dev/null
+++ b/public/views/chunks/interactiveMap/interactiveMap.css
@@ -0,0 +1,289 @@
+@charset "UTF-8";
+
+.interactiveMap_cursor {
+ cursor: crosshair
+}
+
+.interactiveMap_layerSwitcher {
+ top: 5px;
+ right: 5px;
+}
+
+.interactiveMap_layerSwitcher select {
+ padding: 7px;
+ margin: 5px;
+ border: none;
+ background-color: rgba(255,255,255,0.5);
+ color: #555;
+}
+
+/* all 3 classes to be sure that it overrride OL defaults */
+div.interactiveMap_attribution .ol-attribution.ol-control.ol-attribution {
+ bottom: 5px;
+ right: 5px;
+ background-color: rgba(238,238,238, .4);
+}
+
+/* for OL scale overriding default classes
+ is a best way to customize look of scale */
+.ol-scale-line {
+ bottom: 5px;
+ background-color: transparent;
+}
+
+@media screen and (max-width: 800px) {
+ .ol-scale-line {
+ left: 5px;
+ }
+}
+
+@media screen and (min-width: 800px) {
+ .ol-scale-line {
+ left: 50%;;
+ transform: translateX(-50%);
+ }
+}
+
+.ol-scale-line-inner {
+ /* this is a real scale line */
+ color: #000;
+ font-size: 0.7rem;
+ background-color: rgb(238,238,238);
+ opacity: 0.4;
+ border-width: 2px;
+ border-color: #000;
+ border-style: none solid none solid;
+}
+
+.interactiveMap_gpsLocator {
+ bottom: 130px;
+ right: 5px;
+}
+
+.interactiveMap_compassDiv {
+ top: 70px;
+ right: 5px;
+}
+
+.interactiveMap_mapZoom {
+ bottom: 30px;
+ right: 5px;
+ display: flex;
+ flex-direction: column;
+}
+
+.interactiveMap_mapZoom img,
+.interactiveMap_gpsLocator img,
+.interactiveMap_compassDiv img {
+ width: 25px;
+ height: 25px;
+ margin: 5px;
+}
+
+.interactiveMap_mousePosition {
+ bottom: 5px;
+ left: 5px;
+ background-color: rgb(238,238,238,0.4);
+ color: #555;
+ padding: 2px 10px;
+ font-size: 0.8rem;
+}
+
+.interactiveMap_infoMsg {
+ top: 5px;
+ left: 50%;
+ transform: translateX(-50%);
+
+ display: flex;
+ flex-direction: row;
+
+ padding: 2px 10px;
+ font-size: 0.8rem;
+}
+
+.interactiveMap_infoMsgClose {
+ margin-left: 10px;
+ cursor: pointer;
+ color: #888;
+}
+
+.interactiveMap_popup {
+ position: absolute;
+ background-color: white;
+ -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
+ filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2));
+ padding: 8px 15px 8px 8px;
+ border-radius: 5px;
+ border: 1px solid #cccccc;
+ bottom: 12px;
+ left: -48px;
+ min-width: 300px;
+ font-size: 1.0em;
+}
+
+.interactiveMap_popup:after, .interactiveMap_popup:before {
+ top: 100%;
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+ pointer-events: none;
+}
+
+.interactiveMap_popup:after {
+ border-top-color: white;
+ border-width: 10px;
+ left: 48px;
+ margin-left: -10px;
+}
+.interactiveMap_popup:before {
+ border-top-color: #cccccc;
+ border-width: 11px;
+ left: 48px;
+ margin-left: -11px;
+}
+.interactiveMap_popup .imp-closer {
+ text-decoration: none;
+ position: absolute;
+ top: 0px;
+ right: 2px;
+}
+.interactiveMap_popup .imp-closer:after {
+ content: "✖";
+ font-size: 15px;
+ cursor: pointer;
+ color: #000;
+}
+
+.interactiveMap_popup .imp-navi .imp-backward {
+ float: left;
+}
+
+.interactiveMap_popup .imp-navi .imp-forward {
+ float: right;
+}
+
+.interactiveMap_popup .imp-navi .imp-backward,
+.interactiveMap_popup .imp-navi .imp-forward {
+ padding: 0 3px;
+ font-weight: bold;
+}
+
+.interactiveMap_popup .imp-navi .imp-backward img,
+.interactiveMap_popup .imp-navi .imp-forward img {
+ width: 20px;
+ height: auto;
+ cursor: pointer;
+}
+
+.interactiveMap_popup .imp-navi .imp-backward img {
+ -moz-transform: scaleX(-1);
+ -o-transform: scaleX(-1);
+ -webkit-transform: scaleX(-1);
+ transform: scaleX(-1);
+ filter: FlipH;
+ -ms-filter: "FlipH";
+}
+
+/* a lot of log entries starts with a paragraph*/
+.interactiveMap_popup p {
+ font-size: inherit !important;
+}
+
+.interactiveMap_popup .imp-cache .imp-icon, .interactiveMap_popup .imp-cache .imp-icon img,
+.interactiveMap_popup .imp-cache-log .imp-cache-icon, .interactiveMap_popup .imp-cache-log .imp-cache-icon img,
+.interactiveMap_popup .imp-cache-log .imp-log-icon, .interactiveMap_popup .imp-cache-log .imp-log-icon img {
+ padding-left: 0px !important;
+ padding-right: 0px !important;
+}
+
+.interactiveMap_popup .imp-cache .imp-icon, .interactiveMap_popup .imp-cache .imp-icon img,
+.interactiveMap_popup .imp-cache-log .imp-cache-icon, .interactiveMap_popup .imp-cache-log .imp-cache-icon img {
+ width: 19px;
+ height: 19px;
+}
+
+.interactiveMap_popup .imp-cache .imp-wp {
+ float: right;
+ font-weight: normal;
+ font-size: 90% !important;
+}
+
+.interactiveMap_popup .imp-cache .imp-details {
+ font-size: 85%;
+}
+
+.interactiveMap_popup .imp-cache .imp-details img {
+ width: 10px;
+ height: 10px;
+}
+
+.interactiveMap_popup .imp-cache .imp-counter {
+ text-align: right;
+}
+
+.interactiveMap_popup .imp-cache .imp-label {
+ font-weight: bold;
+}
+
+.interactiveMap_popup .imp-cache-log .imp-block {
+ margin-top: 10px;
+}
+
+.interactiveMap_popup .imp-cache-log .imp-content {
+ font-weight: normal;
+}
+
+.interactiveMap_popup .imp-cache-log .imp-user {
+ font-weight: bold;
+}
+
+.interactiveMap_popup .imp-guide {
+ font-size: 13px;
+ font-weight: bold;
+ text-align: left;
+}
+
+.interactiveMap_popup .imp-guide .imp-desc {
+ max-height: 5em;
+ overflow: hidden;
+}
+
+.interactiveMap_popup .imp-table {
+ display: table;
+ width: 100%;
+}
+
+.interactiveMap_popup .imp-table .imp-row {
+ display: table-row;
+}
+
+.interactiveMap_popup .imp-table .imp-cell,
+.interactiveMap_popup .imp-table .imp-narrow-cell {
+ display: table-cell;
+ padding: 1px 5px;
+}
+
+.interactiveMap_popup .imp-table .imp-narrow-cell {
+ width: 1%;
+ white-space: nowrap;
+}
+
+.interactiveMap_popup .imp-cache .imp-icon,
+.interactiveMap_popup .imp-cache-log .imp-cache-icon,
+.interactiveMap_popup .imp-cache-log .imp-log-icon {
+ padding-bottom: 2px;
+}
+
+.interactiveMap_popup .ipm-section {
+ margin-bottom: 5px;
+}
+
+.interactiveMap_popup .imp-table .ipm-section {
+ padding: 0px 0px 1px 0px;
+ font-size: 0.8em;
+ font-weight: bold;
+ border-bottom: 1px solid #c0c0c0;
+ text-align: center;
+}
diff --git a/public/views/chunks/interactiveMap/interactiveMap.js b/public/views/chunks/interactiveMap/interactiveMap.js
new file mode 100644
index 0000000000..b0eca4ed9f
--- /dev/null
+++ b/public/views/chunks/interactiveMap/interactiveMap.js
@@ -0,0 +1,1365 @@
+/**
+ * This is a global object and an entry point to InteractiveMap collection
+ */
+var InteractiveMapServices = {
+ /**
+ * returns InteractiveMap object with given mapId
+ * or if params is an object, creates a new one with given id and params
+ */
+ getInteractiveMap: function(mapId, params) {
+ var result = null;
+ if (
+ typeof mapId !== "undefined"
+ ) {
+ if (typeof window["_interactiveMaps"] === "undefined") {
+ window["_interactiveMaps"] = [];
+ }
+ if (
+ typeof window["_interactiveMaps"][mapId]
+ === "undefined"
+ ) {
+ if (typeof params === "object") {
+ window["_interactiveMaps"][mapId] =
+ new InteractiveMap(mapId, params);
+ result = window["_interactiveMaps"][mapId];
+ }
+ } else {
+ result = window["_interactiveMaps"][mapId];
+ }
+ }
+ return result;
+ },
+
+ /**
+ * returns OpenLayers map object used as a base of this chunk instance
+ */
+ getMapObject: function(mapId) {
+ return (
+ typeof mapId !== "undefined"
+ && typeof window["_interactiveMaps"] !== "undefined"
+ && typeof window["_interactiveMaps"][mapId] !== "undefined"
+ ? window["_interactiveMaps"][mapId].map
+ : null
+ );
+ },
+
+ /**
+ * returns the name of currently selected map (layer) name
+ */
+ getSelectedLayerName: function(mapId) {
+ var map = this.getMapObject(mapId);
+
+ var visibleLayers = [];
+ if (map) {
+ map.getLayers().forEach(function(layer) {
+ if (
+ !OcLayerServices.isOcInternalLayer(layer)
+ && layer.getVisible()
+ ) {
+ visibleLayers.push(OcLayerServices.getOcLayerName(layer));
+ }
+ });
+ }
+
+ if (visibleLayers.length <= 0) {
+ console.err('--- no visible layer ?! ---');
+ return '';
+ }
+ if (visibleLayers.length > 1) {
+ console.err('--- many visible layers ?! ---');
+ }
+
+ return visibleLayers.pop();
+ },
+
+ /**
+ * add callback which will be called on map layer change
+ * callback should be a function with one input parameter: "selectedLayerName"
+ */
+ addMapLayerSwitchCallback: function(mapId, callback) {
+ var correct = true;
+ if (typeof mapId === "undefined") {
+ console.error('mapId is required!');
+ correct = false;
+ }
+ if (typeof callback !== "function") {
+ console.error('callback must be a function!');
+ correct = false;
+ }
+
+ if (correct) {
+ var map = this.getMapObject(mapId);
+ if (map) {
+ if (typeof map.layerSwitchCallbacks !== "array") {
+ map.layerSwitchCallbacks = []
+ }
+ map.layerSwitchCallbacks.push(callback);
+ }
+ }
+ },
+
+ /**
+ * Reorders sections of map with given id, see the InteractiveMap
+ * corresponding method.
+ */
+ reorderSections: function (mapId, orders) {
+ var correct = true;
+ if (typeof mapId === "undefined") {
+ console.error('mapId is required!');
+ correct = false;
+ }
+ if (typeof orders !== "object") {
+ console.error('orders must be an object!');
+ correct = false;
+ }
+ if (correct) {
+ var map = this.getInteractiveMap(mapId);
+ if (map) {
+ map.reorderSections(orders);
+ }
+ }
+ },
+
+ /**
+ * Toggles visibility of section of map with given id, see the
+ * InteractiveMap corresponding method.
+ */
+ toggleSectionVisibility: function(mapId, section) {
+ var correct = true;
+ if (typeof mapId === "undefined") {
+ console.error('mapId is required!');
+ correct = false;
+ }
+ if (typeof section === "undefined") {
+ console.error('section is required!');
+ correct = false;
+ }
+ if (correct) {
+ var map = this.getInteractiveMap(mapId);
+ if (map) {
+ map.toggleSectionVisibility(section);
+ }
+ }
+ },
+
+ /**
+ * Highlights a feature match given parameters: markerType, id
+ * (cache or log) and section of map with given id, see the InteractiveMap
+ * corresponding method.
+ */
+ highlightFeature: function(mapId, markerType, localId, section) {
+ var correct = true;
+ if (typeof mapId === "undefined") {
+ console.error('mapId is required!');
+ correct = false;
+ }
+ if (typeof markerType === "undefined") {
+ console.error('markerType is required!');
+ correct = false;
+ }
+ if (typeof localId === "undefined") {
+ console.error('localId is required!');
+ correct = false;
+ }
+ if (correct) {
+ var interactiveMap = this.getInteractiveMap(mapId);
+ if (interactiveMap) {
+ interactiveMap.highlightFeature(markerType, localId, section);
+ }
+ }
+ },
+
+ /**
+ * Tones down (de-emphasizes) previously highlighted feature of map with
+ * given id, see the InteractiveMap corresponding method.
+ */
+ toneDownFeature: function(mapId) {
+ var correct = true;
+ if (typeof mapId === "undefined") {
+ console.error('mapId is required!');
+ correct = false;
+ }
+ if (correct) {
+ var interactiveMap = this.getInteractiveMap(mapId);
+ if (interactiveMap) {
+ interactiveMap.toneDownFeature();
+ }
+ }
+ },
+
+ styler: { // styles in OL format
+ fgColor: [100, 100, 255, 1], // main foreground color in OL format
+ bgColor: [238, 238, 238, 0.4], // main background color in OL format
+ }
+
+};
+
+// =================================================================
+
+/**
+ * An InteractiveMap prototype
+ */
+function InteractiveMap(id, params) {
+ this.id = id;
+ this.targetDiv = undefined;
+ this.centerOn = undefined;
+ this.mapStartZoom = undefined;
+ this.forceMapZoom = undefined;
+ this.startExtent = undefined;
+ this.mapLayersConfig = getMapLayersConfig();
+ this.selectedLayerKey = undefined;
+ this.infoMessage = undefined;
+ this.markersData = undefined;
+ this.sectionsProperties = undefined;
+ this.sectionsNames = undefined;
+ this.markerMgrs = undefined;
+ this.markersFamily = undefined;
+
+ // defaults for controls and markers
+ this.enableScaleLine = true;
+ this.enableLayerSwitcher = true;
+ this.enableZoomControls = true;
+ this.enableCompass = true;
+ this.enableGPSLocator = true;
+ this.enableCooordsUnderCursor = true;
+ this.enableInfoMessage = true;
+ this.enableMarkers = true;
+ this.enablePopup = true;
+ this.enableHighlight = true;
+
+ this.compiledPopupTpls = [];
+ this.layerSwitchCallbacks = [];
+ // rewrite params entries to corresponding attributes
+ if (typeof params === "object") {
+ for (var p in params) {
+ if (this.hasOwnProperty(p)) {
+ this[p] = params[p];
+ }
+ }
+ }
+}
+
+/**
+ * Initializes OL map, controls, markers etc.
+ */
+InteractiveMap.prototype.init = function() {
+ var mapDiv = $('#' + this.targetDiv);
+ var attributionDiv = $('
');
+ mapDiv.addClass("interactiveMap_cursor");
+
+ this.map = new ol.Map({
+ target: this.targetDiv,
+ view: new ol.View({
+ center: ol.proj.fromLonLat(
+ [this.centerOn.lon, this.centerOn.lat]
+ ),
+ zoom: this.mapStartZoom,
+ }),
+ controls: ol.control.defaults({
+ attributionOptions: {
+ collapsible: false,
+ target: attributionDiv[0],
+ },
+ zoom: false,
+ rotate: false,
+ }),
+ });
+
+ // add attribution control
+ this.map.addControl(new ol.control.Control({
+ element: attributionDiv[0],
+ }));
+
+ if (this.enableScaleLine) {
+ // note: scaleLine has two css OL classes:
+ // .ol-scale-line .ol-scale-line-inner
+ this.map.addControl(new ol.control.ScaleLine({ minWidth: 100 }));
+ }
+
+ if (this.startExtent) {
+ // fit map to given extent
+ var sw = ol.proj.fromLonLat([
+ this.startExtent.sw.lon, this.startExtent.sw.lat
+ ]);
+ var ne = ol.proj.fromLonLat([
+ this.startExtent.ne.lon, this.startExtent.ne.lat]
+ );
+ this.map.getView().fit([sw[0], sw[1], ne[0], ne[1]], { nearest:true });
+ }
+
+ if (this.enableLayerSwitcher) {
+ // init layer switcher
+ this._layerSwitcherInit();
+ }
+ if (this.enableZoomControls) {
+ // init zoom controls
+ this._mapZoomControlsInit();
+ }
+ if (this.enableCompass) {
+ // init map compass (north-up reset button)
+ this._compassControlInit();
+ }
+ if (this.enableGPSLocator) {
+ // init localization control
+ this._gpsLocatorInit();
+ }
+ if (this.enableCoordsUnderCursor) {
+ // init mouse position coords
+ this._coordsUnderCursorInit();
+ }
+ if (this.enableInfoMessage) {
+ // init infoMessage control
+ this._infoMessageInit();
+ }
+
+ if (this.enableMarkers) {
+ // load markers data and create features
+ this._loadMarkers();
+ }
+}
+
+/**
+ * Initializes layer switcher control with preconfigured map layers
+ */
+InteractiveMap.prototype._layerSwitcherInit = function() {
+ var switcherDiv = $(
+ ""
+ );
+
+ // prepare dropdown object
+ var switcherDropdown = $('');
+
+ switcherDiv.append(switcherDropdown);
+
+ var instance = this;
+
+ // add layers from config to map
+ $.each(this.mapLayersConfig, function(key, layer) {
+ OcLayerServices.setOcLayerName(layer, key);
+ layer.set('wrapX', true);
+ layer.set('zIndex', 1);
+
+ if (key == instance.selectedLayerKey) {
+ switcherDropdown.append(
+ ''
+ );
+ layer.setVisible(true);
+ } else {
+ switcherDropdown.append(
+ ''
+ );
+ layer.setVisible(false);
+ }
+ instance.map.addLayer(layer);
+ });
+
+ // add switcher to map
+ this.map.addControl(
+ new ol.control.Control({ element: switcherDiv[0] })
+ );
+
+ // init switcher change callback
+ switcherDropdown.change(function(evt) {
+ var selectedLayerName = switcherDropdown.val();
+ instance.map.getLayers().forEach(function(layer) {
+ // first skip OC-internal layers (prefix oc_)
+ if (!OcLayerServices.isOcInternalLayer(layer)) {
+ // this is external layer (like OSM)
+ layer.setVisible(
+ OcLayerServices.getOcLayerName(layer) == selectedLayerName
+ );
+ } else {
+ // this is OC-generated layer
+ if (layer.getVisible() != true) {
+ layer.setVisible(true);
+ }
+ }
+ });
+
+ // run callback if present
+ if (typeof instance.layerSwitchCallbacks === 'undefined') {
+ $.each(instance.layerSwitchCallbacks, function(key, callback) {
+ callback(selectedLayerName);
+ });
+ }
+ });
+}
+
+/**
+ * Initializes GPS locator control
+ */
+InteractiveMap.prototype._gpsLocatorInit = function() {
+ if (!("geolocation" in navigator)) {
+ console.log('Geolocation not supported by browser.')
+ return;
+ }
+ var gpsDiv = $("");
+ var gpsImg = $(
+ '
'
+ );
+
+ gpsDiv.append(gpsImg);
+
+ this.map.addControl(
+ new ol.control.Control({ element: gpsDiv[0] })
+ );
+
+ var geolocationObj = new GeolocationOnMap(
+ this.map, '.interactiveMap_gpsLocator'
+ );
+ gpsImg.click(function() {
+ geolocationObj.getCurrentPosition();
+ });
+}
+
+/**
+ * Initializes Map zoom control
+ */
+InteractiveMap.prototype._mapZoomControlsInit = function() {
+ var zoomDiv = $('');
+ var zoomIn = $('
');
+ var zoomOut = $('
');
+
+ zoomDiv.append(zoomIn);
+ zoomDiv.append(zoomOut);
+
+ this.map.addControl(
+ new ol.control.Control({ element: zoomDiv[0] })
+ );
+
+ var instance = this;
+
+ zoomIn.click(function() {
+ var view = instance.map.getView();
+ var zoom = view.getZoom();
+ view.setZoom(zoom + 1)
+ });
+
+ zoomOut.click(function() {
+ var view = instance.map.getView()
+ var zoom = view.getZoom();
+ view.setZoom(zoom - 1)
+ });
+}
+
+/**
+ * Initializes Compass control
+ */
+InteractiveMap.prototype._compassControlInit = function() {
+ var compassDiv = $('');
+ var compass = $('
');
+ compassDiv.append(compass);
+
+ this.map.addControl(
+ new ol.control.Control({ element: compassDiv[0] })
+ );
+
+ var instance = this;
+ compassDiv.click(function() {
+ instance.map.getView().setRotation(0);
+ });
+
+ this.map.on('moveend', function (evt) {
+ var rotation = evt.map.getView().getRotation();
+ compass.css('transform', 'rotate(' + rotation + 'rad)');
+ });
+}
+
+/**
+ * Initializes a control showing coordinates under cursor
+ */
+InteractiveMap.prototype._coordsUnderCursorInit = function() {
+ if ($(window).width() < 800) {
+ console.log(
+ 'CordsUnderCursor control skipped because of window width.'
+ );
+ return;
+ }
+
+ this.curPos = {};
+ this.curPos.positionDiv = $(
+ ''
+ );
+
+ this.map.addControl(
+ new ol.control.Control({ element: this.curPos.positionDiv[0] })
+ );
+
+ this.curPos.lastKnownCoords = null;
+ this.curPos.coordsFormat = CoordinatesUtil.FORMAT.DEG_MIN;
+
+ var instance = this;
+ this.map.on('pointermove', function(event) {
+ if (
+ !CoordinatesUtil.cmp(
+ instance.curPos.lastKnownCoords, event.coordinate
+ )
+ ) {
+ instance.curPos.lastKnownCoords = event.coordinate;
+ instance.curPos.positionDiv.html(
+ CoordinatesUtil.toWGS84(
+ instance.map,
+ instance.curPos.lastKnownCoords,
+ instance.curPos.coordsFormat
+ )
+ );
+ }
+ });
+
+ // switch coords format on dbl-click
+ this.curPos.positionDiv.dblclick(function() {
+ switch(instance.curPos.coordsFormat) {
+ case CoordinatesUtil.FORMAT.DEG_MIN:
+ instance.curPos.coordsFormat =
+ CoordinatesUtil.FORMAT.DEG_MIN_SEC;
+ break;
+ case CoordinatesUtil.FORMAT.DEG_MIN_SEC:
+ instance.curPos.coordsFormat = CoordinatesUtil.FORMAT.DECIMAL;
+ break;
+ case CoordinatesUtil.FORMAT.DECIMAL:
+ default:
+ instance.curPos.coordsFormat = CoordinatesUtil.FORMAT.DEG_MIN;
+ break;
+ }
+ });
+}
+
+/**
+ * Initializes a control showing info message
+ */
+InteractiveMap.prototype._infoMessageInit = function() {
+ var infoMsgId = this.id + '_infoMsg';
+
+ var msgDiv = $(
+ ''
+ );
+ var closeBtn = $('✖
');
+ msgDiv.append(closeBtn);
+
+ this.map.addControl(
+ new ol.control.Control( { element: msgDiv[0] } )
+ );
+
+ if (this.infoMessage ) {
+ msgDiv.prepend(this.infoMessage);
+ msgDiv.show();
+ } else {
+ msgDiv.hide(0);
+ }
+
+ closeBtn.click(function() {
+ $('#' + infoMsgId).hide();
+ });
+}
+
+/**
+ * Loads markers from markersData, creates corresponding features and organizes
+ * them in section-related sources and layers.
+ * Then creates an InteractiveMapPopup instance and assignes it with the OL map.
+ */
+InteractiveMap.prototype._loadMarkers = function() {
+ this.markersBaseZIndex = 100;
+
+ if (!this.markersData || this.markersData.length == 0) {
+ return;
+ }
+
+ var frontViewFeatures = {};
+ var sources = {};
+ var currentZIndex = this.markersBaseZIndex;
+ var allExtent;
+ var renderOrderingReverse = true;
+ var instance = this;
+ Object.keys(this.markersData).forEach(function(section) {
+ var featuresArr = [];
+ var props = (
+ typeof instance.sectionsProperties !== "undefined"
+ && typeof instance.sectionsProperties[section] !== "undefined"
+ ? instance.sectionsProperties[section]:
+ undefined
+ );
+ // set zIndex according to section order if defined
+ var zIndex = currentZIndex;
+ if (props && typeof props["order"] !== "undefined") {
+ zIndex = instance.markersBaseZIndex - parseInt(props["order"]);
+ } else {
+ currentZIndex++;
+ }
+ // true (default) if section is visible
+ var visible =
+ props && typeof props["visible"] !== "undefined"
+ ? props["visible"]
+ : true;
+ Object.keys(instance.markersData[section]).forEach(function(markerType) {
+ instance.markersData[section][markerType].forEach(
+ function(markerData, id) {
+ var feature = instance.markerMgrs[markerType].markerFactory(
+ instance.map, markerType, id, markerData, section
+ );
+ if (visible) {
+ var geom = feature.getGeometry();
+ if (typeof geom["getCoordinates"] === "function") {
+ var coords = geom.getCoordinates();
+ var key = "" + coords[0] + "," + coords[1];
+ var isFirst = (
+ typeof frontViewFeatures[key] === "undefined"
+ );
+ if (
+ !isFirst
+ && (
+ renderOrderingReverse
+ ? frontViewFeatures[key].zIndex < zIndex
+ : frontViewFeatures[key].zIndex <= zIndex
+ )
+ ) {
+ frontViewFeatures[key].feature.set(
+ "isFirst", false
+ );
+ isFirst = true;
+ }
+ if (isFirst) {
+ feature.set("isFirst", true);
+ frontViewFeatures[key] = {
+ feature: feature,
+ zIndex: zIndex
+ }
+ }
+ }
+ }
+ featuresArr.push(feature);
+ }
+ );
+ });
+ sources[section] = {
+ src: new ol.source.Vector({ features: featuresArr }),
+ zIndex: zIndex,
+ visible: visible
+ }
+ if (!allExtent) {
+ allExtent = sources[section].src.getExtent();
+ } else {
+ allExtent = ol.extent.extend(
+ allExtent, sources[section].src.getExtent()
+ );
+ }
+ });
+
+ Object.keys(sources).forEach(function(section) {
+ var source = sources[section];
+ var markersLayer = new ol.layer.Vector ({
+ zIndex: source.zIndex,
+ visible: source.visible,
+ source: source.src,
+ ocLayerName: 'oc_markers_' + section,
+ renderOrder: function(f1, f2) {
+ return (
+ renderOrderingReverse
+ ? (
+ (f1["ol_uid"] > f2["ol_uid"])
+ ? -1
+ : +(f1["ol_uid"] < f2["ol_uid"])
+ )
+ : (
+ (f1["ol_uid"] < f2["ol_uid"])
+ ? -1
+ : +(f1["ol_uid"] > f2["ol_uid"])
+ )
+ );
+ }
+ });
+ instance.map.addLayer(markersLayer);
+ });
+
+ // zoom map to see all markers
+ if (!this.forceMapZoom && !ol.extent.isEmpty(allExtent)) {
+ // there are markers
+ this.map.getView().fit(allExtent);
+ }
+
+ if (this.enableHighlight) {
+ // source, layer and marker for highlightning,
+ // placed at the bottom of active oc layers
+ var highlightedSource = new ol.source.Vector();
+
+ var highlightedPointMarker_ocData = {
+ id: this.id,
+ lat: 0,
+ lon: 0
+ };
+ this._highlightedPointMarker = createOCMarkerFeature(
+ "_highlighted",
+ "_highlighted" + this.id,
+ highlightedPointMarker_ocData,
+ new HighlightedMarker(this.map, highlightedPointMarker_ocData)
+ );
+ highlightedSource.addFeature(this._highlightedPointMarker);
+
+ this._highlightedLayer = new ol.layer.Vector ({
+ zIndex: Math.min(this.markersBaseZIndex, currentZIndex) - 10,
+ visible: false,
+ source: highlightedSource,
+ ocLayerName: 'oc__highlighted',
+ });
+ this.map.addLayer(this._highlightedLayer);
+ }
+
+ if (this.enablePopup) {
+ // most top, foreground source and layer, where popped up features will
+ // be temporarily placed
+ this.foregroundSource = new ol.source.Vector();
+
+ var foregroundLayer = new ol.layer.Vector ({
+ zIndex: 500,
+ visible: true,
+ source: this.foregroundSource,
+ ocLayerName: 'oc__foreground',
+ });
+
+ this.map.addLayer(foregroundLayer);
+
+ this._popup = new InteractiveMapPopup()
+ this._popup.addToMap(this);
+ }
+}
+
+/**
+ * Returns a feature identified by given parameters: markerType, feature local
+ * id (cache or log id f.ex.) and section; null is returned if not found.
+ */
+InteractiveMap.prototype._getFeature = function(markerType, localId, section) {
+ var result = null;
+ var featureId = createFeatureId(
+ markerType, localId, section ? section : "_DEFAULT_"
+ );
+
+ this.map.getLayerGroup().getLayersArray().some(function(layer) {
+ if (OcLayerServices.isOcInternalLayer(layer)) {
+ result = layer.getSource().getFeatureById(featureId);
+ }
+ return (result != null);
+ });
+
+ return result;
+}
+
+/**
+ * Reorders sections basing on given orders array, by setting z-index
+ */
+InteractiveMap.prototype.reorderSections = function(orders) {
+ var instance = this;
+ this.map.getLayerGroup().getLayersArray().forEach(function(layer) {
+ var match = /^oc_markers_(.+)/.exec(layer.get('ocLayerName'));
+ if (match != null) {
+ var section= match[1];
+ if (orders[section] !== undefined) {
+ layer.setZIndex(instance.markersBaseZIndex - orders[section]);
+ }
+ }
+ });
+ this.map.renderSync();
+}
+
+/**
+ * Toggles visibility of given section
+ */
+InteractiveMap.prototype.toggleSectionVisibility = function(section) {
+ var instance = this;
+ this.map.getLayerGroup().getLayersArray().some(function(layer) {
+ var match = /^oc_markers_(.+)/.exec(layer.get('ocLayerName'));
+ if (match != null && match[1] == section) {
+ layer.setVisible(!layer.getVisible());
+ if (typeof instance._popup !== "undefined") {
+ instance.map.once("postrender", function(evt) {
+ instance._popup.adjustFeaturesByLayer(layer);
+ });
+ }
+ return true;
+ }
+ });
+}
+
+/**
+ * Highlights a feature identified by given parameters, if found
+ */
+InteractiveMap.prototype.highlightFeature = function(
+ markerType, localId, section
+) {
+ if (
+ this.enableHighlight
+ && typeof this._highlightedPointMarker !== "undefined"
+ && typeof this._highlightedLayer !== "undefined"
+ ) {
+ var feature = this._getFeature(markerType, localId, section);
+ if (feature) {
+ var coords = feature.getGeometry().getCoordinates();
+ if (coords) {
+ this._highlightedPointMarker.getGeometry().setCoordinates(
+ coords
+ );
+ this._highlightedLayer.setVisible(true);
+ }
+ }
+ }
+}
+
+/**
+ * Tones down previously highlighted feature
+ */
+InteractiveMap.prototype.toneDownFeature = function() {
+ if (
+ this.enableHighlight
+ && typeof this._highlightedLayer !== "undefined"
+ ) {
+ this._highlightedLayer.setVisible(false);
+ }
+}
+
+// =================================================================
+
+/**
+ * An InteractiveMapPopup prototype
+ */
+function InteractiveMapPopup() {
+ this.popup = new ol.Overlay({
+ element: $('')[0],
+ positioning: 'bottom-center',
+ stopEvent: true,
+ insertFirst: false,
+ offset: [0, -50],
+ autoPan: true,
+ autoPanAnimation: {
+ duration: 250
+ },
+ offsetYAdjusted: false,
+ });
+ this.features = [];
+ this.featureIndex = -1;
+ this.offsetYAdjusted = false;
+}
+
+/**
+ * Assigns this popup instance to given InteractiveMap instance, setting 'click'
+ * event handler.
+ */
+InteractiveMapPopup.prototype.addToMap = function(interactiveMap) {
+ this.interactiveMap = interactiveMap
+ this.interactiveMap.map.addOverlay(this.popup);
+ var instance = this;
+ this.interactiveMap.map.on('click', function(evt) {
+ instance._mapClickEvent(evt);
+ });
+}
+
+/**
+ * Should be called after any oc layer visibility change to adjust current
+ * features available in popup to the changed visibility. A layer where
+ * visibility has been changed is passed as a parameter.
+ */
+InteractiveMapPopup.prototype.adjustFeaturesByLayer = function(layer) {
+ var s = layer.getSource();
+ if (s && this.features.length > 0) {
+ var instance = this;
+ var oldFeatureSource = this.currentFeatureSource;
+ instance._clearFeature();
+ instance.interactiveMap.map.once("postrender", function(evt) {
+ var features = instance._getMapFeatures(
+ instance.interactiveMap.map.getPixelFromCoordinate(
+ instance.popup.getPosition()
+ )
+ ).filter(function(feature) {
+ return (
+ feature.getId()
+ && (
+ layer.getVisible()
+ || !s.getFeatureById(feature.getId())
+ )
+ );
+ });
+ if (!layer.getVisible() && s === oldFeatureSource) {
+ // currently displayed pop feature is hidden in layer,
+ // so reset index
+ instance.featureIndex = -1;
+ } else {
+ // currently displayed pop feature is still visible,
+ // so determine its index in new array of features
+ var currentFeature = instance.features[instance.featureIndex];
+ features.some(function(feature, index) {
+ if (feature == currentFeature) {
+ // set new index before desired feature,
+ // to be correctly used in _switchPopupContent
+ instance.featureIndex = index -1;
+ return true;
+ }
+ });
+ }
+ instance.features = features;
+ if (instance.features.length > 0) {
+ instance._switchPopupContent(true);
+ } else {
+ instance.popup.setPosition(undefined);
+ }
+ });
+ };
+}
+
+/**
+ * Returns map features being under given pixel, with exclusion of foreground
+ * (popup) layer.
+ */
+InteractiveMapPopup.prototype._getMapFeatures = function(pixel) {
+ var result = [];
+
+ var fC;
+ var instance = this;
+ this.interactiveMap.map.forEachFeatureAtPixel(pixel, function(feature) {
+ if (
+ feature.getId()
+ && (feature.get('ocData')) != undefined
+ && !instance.interactiveMap.foregroundSource.getFeatureById(
+ feature.getId()
+ )
+ ) {
+ var canAdd = true;
+ if (fC == undefined) {
+ // save the first feature coordinates
+ fC = feature.getGeometry().getCoordinates();
+ } else {
+ // add another features only if coordinates match the first one
+ var nFC = feature.getGeometry().getCoordinates();
+ canAdd = (
+ (nFC[0] == fC[0]) && (nFC[1] == fC[1])
+ || feature.getGeometry().intersectsCoordinate(fC)
+ );
+ }
+ if (canAdd) {
+ result.push(feature);
+ }
+ }
+ });
+
+ return result;
+}
+
+/**
+ * Clears from popup currently selected feature, movin it from the foreground
+ * source to its original one.
+ */
+InteractiveMapPopup.prototype._clearFeature = function(feature) {
+ if (feature === undefined && this.featureIndex >= 0) {
+ feature = this.features[this.featureIndex];
+ }
+ if (feature !== undefined && this.currentFeatureSource !== undefined) {
+ this.interactiveMap.foregroundSource.removeFeature(feature);
+ feature.set("isFirst", false);
+ this.currentFeatureSource.addFeature(feature);
+ this.currentFeatureSource = undefined;
+ }
+}
+
+/**
+ * Should be called on popup hide or just before possible show, to clear all
+ * variables and states related to previously displayed popup.
+ */
+InteractiveMapPopup.prototype._onHide = function() {
+ this._clearFeature();
+ this.featureIndex = -1;
+ this.features = [];
+ this.offsetYAdjusted = false;
+}
+
+/**
+ * An event handler to be assigned to OL map 'click' event.
+ * Checks all features being under clicked pixel and selects them if coordinates
+ * match the first one selected.
+ * If an array of selected features is not empty, the popup is shown.
+ */
+InteractiveMapPopup.prototype._mapClickEvent = function(evt) {
+ this._onHide();
+
+ var features = this._getMapFeatures(evt.pixel);
+ if (features.length > 0) {
+ this.features = features;
+ this._switchPopupContent(true);
+ } else {
+ this.popup.setPosition(undefined);
+ }
+}
+
+/**
+ * Computes popup offset Y to place it in a right place above current
+ * popup features. The computing result is based if applicable on 'popupOffsetY'
+ * attribute of features' markers, which are consecutively computed if missing.
+ */
+InteractiveMapPopup.prototype._computePopupOffsetY = function() {
+ var result;
+
+ this.features.forEach(function(feature) {
+ var ocData = feature.get("ocData");
+
+ var ocMarker = feature.get('ocMarker');
+ if (
+ ocMarker != undefined
+ && typeof(ocMarker['currentStyle']) != "undefined"
+ ) {
+ if (typeof(ocMarker.currentStyle['popupOffsetY']) === "undefined") {
+ ocMarker.computePopupOffsetY();
+ }
+ if (typeof(ocMarker.currentStyle['popupOffsetY']) !== "undefined") {
+ if (
+ result == undefined
+ || result > ocMarker.currentStyle.popupOffsetY
+ ) {
+ result = ocMarker.currentStyle.popupOffsetY;
+ }
+ }
+ } else {
+ var im;
+ var s = feature.getStyle();
+ if (typeof(s["getImage"]) == "function") {
+ im = s.getImage();
+ }
+ if (im && im instanceof ol.style.Icon) {
+ var anc = im.getAnchor();
+ var offset = -(anc[1] * im.getScale()) - 2;
+ if (result == undefined || result > offset) {
+ result = offset;
+ }
+ }
+ }
+ });
+
+ return result;
+}
+
+/**
+ * Selects the next or previous feature from features being under a popup point
+ * when the map was clicked. The selection depends on a 'forward' parameter.
+ * If there is no feature previously selected, the first one is chosen. Next,
+ * the content and position of popup is set according to the selected feature
+ * values.
+ */
+InteractiveMapPopup.prototype._switchPopupContent = function(forward) {
+ var oldFeature;
+ var i = this.featureIndex;
+ if (i >= 0) {
+ oldFeature = this.features[i];
+ // (+/-1) modulo features.length, negative value workaround
+ i = (
+ ((forward ? (i + 1) : (i - 1)) % this.features.length)
+ + this.features.length
+ ) % this.features.length;
+ } else if (i < 0) {
+ i = 0;
+ }
+
+ var feature = this.features[i];
+ var ocData = feature.get("ocData");
+
+ if (!this.offsetYAdjusted) {
+ var popupOffsetY = this._computePopupOffsetY();
+ if (popupOffsetY) {
+ this.popup.setOffset([0, popupOffsetY]);
+ }
+ this.offsetYAdjusted = true;
+ }
+
+ // move currect feature to the foreground layer, replacing the previous
+ // one
+ var featureId = feature.getId();
+ if (featureId) {
+ var instance = this;
+ this.interactiveMap.map.getLayerGroup().getLayersArray().some(
+ function(layer) {
+ if (/^oc_[^_].*/.test( layer.get('ocLayerName') )) {
+ var s = layer.getSource();
+ if (s.getFeatureById(featureId) === feature) {
+ if (oldFeature != undefined) {
+ instance._clearFeature(oldFeature);
+ }
+ s.removeFeature(feature);
+ feature.set("isFirst", true);
+ instance.interactiveMap.foregroundSource.addFeature(
+ feature
+ );
+ instance.currentFeatureSource = s;
+ return true;
+ }
+ }
+ }
+ );
+ }
+
+ var markerSection = ocData.markerSection;
+ var markerType = ocData.markerType;
+ var markerId = ocData.markerId;
+
+ if (!this.interactiveMap.compiledPopupTpls[markerType]) {
+ var popupTpl =
+ $('script[type="text/x-handlebars-template"].' + markerType).html();
+ this.interactiveMap.compiledPopupTpls[markerType] =
+ Handlebars.compile(popupTpl);
+ }
+
+ var markerContext =
+ this.interactiveMap.markersData[markerSection][markerType][markerId];
+ if (
+ typeof this.interactiveMap.sectionsNames !== "undefined"
+ && typeof this.interactiveMap.sectionsNames[markerSection]
+ !== "undefined"
+ ) {
+ markerContext['sectionName'] =
+ this.interactiveMap.sectionsNames[markerSection];
+ }
+ if (this.features.length > 1) {
+ markerContext['showNavi'] = true;
+ } else {
+ markerContext['showNavi'] = undefined;
+ }
+ $(this.popup.getElement()).html(
+ this.interactiveMap.compiledPopupTpls[markerType](markerContext)
+ );
+
+ var instance = this;
+ $(".imp-closer").click(function(evt) {
+ instance._onHide();
+ instance.popup.setPosition(undefined);
+ });
+
+ if (this.features.length > 1) {
+ $(".imp-navi .imp-backward > img").click(function(evt) {
+ instance._switchPopupContent(false);
+ });
+ $(".imp-navi .imp-forward > img").click(function(evt) {
+ instance._switchPopupContent(true);
+ });
+ }
+
+ this.featureIndex = i;
+ this.popup.setPosition(feature.getGeometry().getCoordinates());
+}
+
+// =================================================================
+// Utils and helper objects
+// =================================================================
+
+/* this is util used fo coords formatting */
+var CoordinatesUtil = {
+ FORMAT: Object.freeze({
+ DECIMAL: 1, /* decimal degrees: N 40.446321° W 79.982321° */
+ DEG_MIN: 2, /* degrees decimal minutes: N 40° 26.767′ W 79° 58.933′ */
+ DEG_MIN_SEC: 3, /* degrees minutes seconds: N 40° 26′ 46″ W 79° 58′ 56″ */
+ }),
+
+ cmp: function(coordsA, coordsB) {
+ return (
+ Array.isArray(coordsA) &&
+ Array.isArray(coordsB) &&
+ coordsA[0] == coordsB[0] &&
+ coordsA[1] == coordsB[1]
+ );
+ },
+
+ toWGS84: function (map, coords, outFormat) {
+ if (outFormat == undefined) {
+ // set default output format
+ outFormat = this.FORMAT.DEG_MIN;
+ }
+
+ // convert coords from map coords to WGS84
+ mapCoordsCode = map.getView().getProjection().getCode();
+ wgs84Coords = ol.proj.transform(coords, mapCoordsCode, 'EPSG:4326');
+ lon = wgs84Coords[0];
+ lat = wgs84Coords[1];
+
+ lonHemisfere = (lon < 0)?"W":"E";
+ latHemisfere = (lat < 0)?"S":"N";
+
+ lonParts = this.getParts(lon);
+ latParts = this.getParts(lat);
+
+ switch(outFormat) {
+ case this.FORMAT.DEG_MIN:
+ return (
+ latHemisfere + " " + Math.floor(latParts.deg) + "° "
+ + latParts.min.toFixed(3) + "' "
+ + lonHemisfere + " " + Math.floor(lonParts.deg) + "° "
+ + lonParts.min.toFixed(3) + "'"
+ );
+
+ case this.FORMAT.DECIMAL:
+ return (
+ latHemisfere + " " + latParts.deg.toFixed(5) + "° "
+ + lonHemisfere + " " + lonParts.deg.toFixed(5) + "°"
+ );
+
+ case this.FORMAT.DEG_MIN_SEC:
+ return (
+ latHemisfere + " " + Math.floor(latParts.deg) + "° "
+ + Math.floor(latParts.min) + "' "
+ + latParts.sec.toFixed(2) + '" '
+ + lonHemisfere + " " + Math.floor(lonParts.deg) + "° "
+ + Math.floor(lonParts.min) + "' "
+ + lonParts.sec.toFixed(2) + '"'
+ );
+ }
+ },
+
+ getParts: function(coordinate) {
+ var deg = Math.abs(coordinate);
+ var min = 60 * (deg - Math.floor(deg));
+ var sec = 60 * (min - Math.floor(min));
+ return {deg: deg, min: min, sec: sec};
+ },
+};
+
+/**
+ * Object used in processing geolocation on the map
+ * It allows to show current position read from GPS
+ */
+function GeolocationOnMap(map, iconSelector) {
+
+ this.map = map
+ this.positionMarkersCollection = new ol.Collection();
+ this.positionMarkersLayer = null;
+
+ this.STATUS = Object.freeze({
+ INIT: '', /* initial state */
+ IN_PROGRESS: 'rgb(255,255,177,.5)', /* position reading in progress */
+ POSITION_ACQUIRED: 'rgb(170,255,127,.5)', /* positions has been read */
+ ERROR: 'rgb(0,255,255,.5)', /* some error occured */
+ })
+
+
+ this.getCurrentPosition = function() {
+ console.log('get position...')
+
+ if (!("geolocation" in navigator)) {
+ console.error('Geolocation not supported by browser!');
+ this.changeGeolocIconStatus(obj.STATUS.ERROR);
+ return;
+ }
+
+ this.changeGeolocIconStatus(this.STATUS.IN_PROGRESS);
+
+ navigator.geolocation.getCurrentPosition(
+ this.getSuccessCallback(),
+ this.getErrorCallback(),
+ { enableHighAccuracy: true }
+ );
+ }
+
+ // set new status and its icon
+ this.changeGeolocIconStatus = function(newStatus) {
+ $(iconSelector).css('background-color', newStatus);
+ }
+
+ this.getSuccessCallback = function() {
+
+ var obj = this;
+
+ return function(position) {
+ console.log('position read: ', position);
+
+ obj.changeGeolocIconStatus(obj.STATUS.POSITION_ACQUIRED);
+
+ lat = position.coords.latitude;
+ lon = position.coords.longitude;
+
+ currCoords = ol.proj.fromLonLat([lon, lat]);
+ accuracy = position.coords.accuracy;
+
+ view = obj.map.getView();
+ view.setCenter(currCoords);
+ view.setZoom(obj.calculateZoomForAccuracy(accuracy));
+
+ // draw position marker
+ var accuracyFeature = new ol.Feature({
+ geometry: new ol.geom.Circle(currCoords, accuracy),
+ });
+
+ accuracyFeature.setStyle([
+ new ol.style.Style({ //circle
+ stroke: new ol.style.Stroke({
+ color: DynamicMapServices.styler.fgColor,
+ width: 2}),
+ }),
+ new ol.style.Style({ //center marker
+ geometry: function(feature){
+ return new ol.geom.Point(feature.getGeometry().getCenter());
+ },
+ image: new ol.style.RegularShape({
+ stroke: new ol.style.Stroke({
+ color: DynamicMapServices.styler.fgColor,
+ width: 2
+ }),
+ points: 4,
+ radius: 10,
+ radius2: 0,
+ angle: Math.PI / 4
+ })
+ }),
+ ]
+ )
+
+ obj.positionMarkersCollection.clear();
+ obj.positionMarkersCollection.push(accuracyFeature);
+
+ if (obj.positionMarkersLayer == null) {
+ obj.positionMarkersLayer = new ol.layer.Vector({
+ map: obj.map,
+ source: new ol.source.Vector({
+ features: obj.positionMarkersCollection,
+ }),
+ });
+ }
+ }
+ }
+
+ this.getErrorCallback = function() {
+ var obj = this;
+
+ return function(positionError) {
+ console.error('OC Map: positions reading error!', positionError);
+
+ if (positionError.code === 1) { // Permission denied
+ // User has denied geolocation - return to initial state
+ obj.changeGeolocIconStatus(obj.STATUS.INIT);
+ } else {
+ // Indicate actual problem with getting position
+ obj.changeGeolocIconStatus(obj.STATUS.ERROR);
+ }
+ }
+ }
+
+ this.calculateZoomForAccuracy = function(accuracy) {
+ // accuracy is in meters
+
+ if (accuracy < 300) return 16;
+ if (accuracy < 600) return 15;
+ if (accuracy < 1200) return 14;
+ if (accuracy < 2400) return 13;
+ if (accuracy < 5000) return 12;
+ if (accuracy < 10000) return 11;
+ return 10; // otherwise
+ }
+
+ return this;
+}
+
+var OcLayerServices = {
+
+ isOcInternalLayer: function (layer){
+ return ( /^oc_.*/.test( layer.get('ocLayerName') ));
+ },
+
+ setOcLayerName: function (layer, name){
+ layer.set('ocLayerName', name);
+ },
+
+ getOcLayerName: function(layer) {
+ return layer.get('ocLayerName');
+ }
+
+};
diff --git a/public/views/chunks/interactiveMap/markers/ocMarker.js b/public/views/chunks/interactiveMap/markers/ocMarker.js
new file mode 100644
index 0000000000..a30213c1e9
--- /dev/null
+++ b/public/views/chunks/interactiveMap/markers/ocMarker.js
@@ -0,0 +1,79 @@
+function createOCMarkerFeature(type, id, ocData, ocMarker, section) {
+ if (typeof section === "undefined") {
+ section = "_DEFAULT_";
+ }
+ var feature = new ol.Feature({
+ geometry: new ol.geom.Point(
+ ol.proj.fromLonLat([parseFloat(ocData.lon), parseFloat(ocData.lat)])
+ ),
+ ocData: {
+ markerSection: section,
+ markerType: type,
+ markerId: id
+ },
+ });
+ feature.setId(createFeatureId(type, ocData.id, section));
+ if (typeof ocMarker["getFeatureStyle"] === "function") {
+ ocMarker.feature = feature;
+ feature.set('ocMarker', ocMarker);
+ feature.setStyle(function(feature, resolution) {
+ return ocMarker.getFeatureStyle(resolution)
+ });
+ }
+ return feature;
+}
+
+/**
+ * Creates id for feature, basing on given parameters
+ */
+function createFeatureId(markerType, localId, section) {
+ if (typeof section === "undefined") {
+ section = "_DEFAULT_";
+ }
+ return section + '_' + markerType + '_' + localId;
+}
+
+/**
+ * A most top marker prototype. It is not advisable to instatiate it directly,
+ * rather instatiate one of derived subclasses
+ */
+function OCMarker(map, ocData) {
+ this.map = map;
+ this.ocData = ocData;
+ this.feature = undefined;
+ this.currentStyle = undefined;
+}
+
+/**
+ * Computes offset for possible popup placement, basing on current styles
+ */
+OCMarker.prototype.computePopupOffsetY = function() {
+ if (
+ this.currentStyle != undefined
+ && typeof(this.currentStyle["style"]) !== "undefined"
+ ) {
+ if (typeof(this.currentStyle.style["length"]) !== "undefined") {
+ var self = this;
+ this.currentStyle.style.forEach(function(s) {
+ var im = s.getImage();
+ if (im && im instanceof ol.style.Icon) {
+ var anchor = im.getAnchor();
+ var scale = im.getScale();
+ var cOfsY = -(anchor[1] * scale)
+ if (
+ typeof(self.currentStyle["popupOffsetY"]) === "undefined"
+ || self.currentStyle.popupOffsetY > cOfsY
+ ) {
+ self.currentStyle.popupOffsetY = cOfsY;
+ }
+ }
+ });
+ } else if (typeof(this.currentStyle.style["getImage"]) == "function") {
+ var im = this.currentStyle.style.getImage();
+ if (im && im instanceof ol.style.Icon) {
+ var anchor = im.getAnchor();
+ this.currentStyle.popupOffsetY = -(anchor[1] * im.getScale());
+ }
+ }
+ }
+}
diff --git a/public/views/chunks/interactiveMap/markers/simple/cacheMarker.js b/public/views/chunks/interactiveMap/markers/simple/cacheMarker.js
new file mode 100644
index 0000000000..9df95f8139
--- /dev/null
+++ b/public/views/chunks/interactiveMap/markers/simple/cacheMarker.js
@@ -0,0 +1,31 @@
+/**
+ * Marker for displaying a cache
+ */
+function CacheMarker(map, ocData) {
+ OCMarker.call(this, map, ocData);
+}
+
+CacheMarker.prototype = Object.create(OCMarker.prototype);
+
+CacheMarker.prototype.constructor = CacheMarker;
+
+/**
+ * Creates and returns style of the marker, based on server-side set icon
+ */
+CacheMarker.prototype.getFeatureStyle = function(resolution) {
+ if (this.currentStyle == undefined) {
+ this.currentStyle = {
+ style: new ol.style.Style({
+ image: new ol.style.Icon({
+ anchor: [0.5, 0.5],
+ anchorXUnits: 'fraction',
+ anchorYUnits: 'fraction',
+ src: this.ocData.icon,
+ scale: 0.6,
+ })
+ }),
+ popupOffsetY: undefined
+ };
+ }
+ return this.currentStyle.style;
+}
diff --git a/public/views/chunks/interactiveMap/markers/simple/highlightedMarker.js b/public/views/chunks/interactiveMap/markers/simple/highlightedMarker.js
new file mode 100644
index 0000000000..8d71b02e85
--- /dev/null
+++ b/public/views/chunks/interactiveMap/markers/simple/highlightedMarker.js
@@ -0,0 +1,32 @@
+/**
+ * Marker for displaying highlight for another feature
+ */
+function HighlightedMarker(map, ocData) {
+ OCMarker.call(this, map, ocData);
+}
+
+HighlightedMarker.prototype = Object.create(OCMarker.prototype);
+
+HighlightedMarker.prototype.constructor = HighlightedMarker;
+
+/**
+ * Creates and returns style of the marker: a green square
+ */
+HighlightedMarker.prototype.getFeatureStyle = function(resolution) {
+ if (this.currentStyle == undefined) {
+ this.currentStyle = {
+ style: new ol.style.Style({
+ image: new ol.style.RegularShape({
+ stroke: new ol.style.Stroke({
+ color: 'green',
+ width: 2
+ }),
+ points: 4,
+ radius: 15,
+ angle: Math.PI / 4
+ })
+ })
+ };
+ }
+ return this.currentStyle.style;
+}
diff --git a/public/views/chunks/interactiveMap/markers/simple/logMarker.js b/public/views/chunks/interactiveMap/markers/simple/logMarker.js
new file mode 100644
index 0000000000..4cdf023e6c
--- /dev/null
+++ b/public/views/chunks/interactiveMap/markers/simple/logMarker.js
@@ -0,0 +1,31 @@
+/**
+ * Marker for displaying a log of a cache
+ */
+function LogMarker(map, ocData) {
+ OCMarker.call(this, map, ocData);
+}
+
+LogMarker.prototype = Object.create(OCMarker.prototype);
+
+LogMarker.prototype.constructor = LogMarker;
+
+/**
+ * Creates and returns style of the marker, based on server-side set log icon
+ */
+LogMarker.prototype.getFeatureStyle = function(resolution) {
+ if (this.currentStyle == undefined) {
+ this.currentStyle = {
+ style: new ol.style.Style({
+ image: new ol.style.Icon({
+ anchor: [0.5, 0.5],
+ anchorXUnits: 'fraction',
+ anchorYUnits: 'fraction',
+ src: this.ocData.logIcon,
+ scale: 1,
+ })
+ }),
+ popupOffsetY: undefined
+ };
+ }
+ return this.currentStyle.style;
+}
diff --git a/public/views/myNbhInteractive/common.css b/public/views/myNbhInteractive/common.css
new file mode 100644
index 0000000000..359f8cad3b
--- /dev/null
+++ b/public/views/myNbhInteractive/common.css
@@ -0,0 +1,166 @@
+@charset "UTF-8";
+
+.content2-container {
+ font-size: 12px;
+}
+
+.nbh-pageheader {
+ color: rgb(88, 144, 168);
+ font-weight: bold;
+ font-size: 1.3em;
+}
+
+.nbh-nodisplay {
+ display: none;
+}
+
+.nbh-nowrap {
+ white-space: nowrap;
+}
+
+fieldset {
+ border: 1px solid #d3d3d3 !important;
+ border-radius: 3px !important;
+ padding: 10px 30px;
+ min-width: 40%;
+ display: inline-box;
+}
+
+legend {
+ font-size: 14px;
+}
+
+.ui-icon-background {
+ background-color: #fff !important;
+}
+
+#nbh-custom-handle {
+ width: 3em;
+ height: 1.6em;
+ top: 50%;
+ margin-top: -.8em;
+ margin-left: -1.6em;
+ text-align: center;
+ line-height: 1.6em;
+}
+
+.nbh-map {
+ height: 400px;
+ width: 100%;
+}
+
+.nbh-usermap {
+ height: 350px;
+ padding: 5px;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+}
+
+#nbh-startdraw-btn {
+ display: inline-block;
+}
+
+#nbh-coords-line {
+ display: none;
+}
+#nbh-delete-dialog-icon {
+ float: left;
+ margin: 12px 12px 20px 0;
+}
+
+.nbh-block {
+ display: inline-block;
+ vertical-align: top;
+}
+
+.nbh-half {
+ width: 49%;
+}
+
+.nbh-full {
+ width: 99%;
+}
+
+.nbh-line-container>a, .nbh-desc-container>a, .lightTipped>a {
+ text-decoration: none;
+}
+
+.lightTip {
+ margin: 0px 10px 0px 60px !important;
+}
+
+.nbh-block-placeholder {
+ border: 1px dotted #ccc;
+ border-radius: 3px;
+ margin: 10px 1em 1em 0;
+ height: 30px;
+ width: 49%;
+ display: inline-block;
+ vertical-align: top;
+ background-color: rgb(156, 186, 214);
+}
+
+.nbh-block-header {
+ background-color: #f9fcfc;
+ padding: 5px;
+ border: 1px solid #ccc;
+ border-radius: 3px;
+ color: rgb(88, 144, 168);
+ font-weight: bold;
+ font-size: 1.2em;
+ margin: 10px 0px 0px 0px;
+ cursor: move;
+}
+
+.nbh-back-btn {
+ display: inline !important;
+ font-weight: normal;
+}
+.nbh-sm-buttons,
+.nbh-md-buttons {
+ float: right;
+}
+
+.nbh-line-container {
+ padding: 2px;
+ width: 99%;
+}
+
+.nbh-desc-container {
+ padding: 5px;
+ display: table-cell;
+ vertical-align: middle;
+ line-height: 1.5em;
+ vertical-align: middle;
+}
+
+.nbh-image-container {
+ display: table-cell;
+ vertical-align: middle;
+ padding: 5px;
+}
+
+.nbh-arrow-north {
+ width: 10px;
+}
+
+.nbh-eye {
+ background-image: url("/images/misc/eye-uni.svg");
+ width: 16px;
+ height: 13px;
+ display: inline-block;
+ background-repeat: no-repeat;
+ background-size: 14px 13px;
+ vertical-aling: middle;
+ margin-bottom: -3px;
+}
+
+.nbh-top-config-btns {
+ background-color: #df4e49;
+ padding: 3px 10px;
+ border-radius: 3px;
+ margin-bottom: 5px;
+}
+.nbh-button-right {
+ float: right;
+}
\ No newline at end of file
diff --git a/public/views/myNbhInteractive/config.js b/public/views/myNbhInteractive/config.js
new file mode 100644
index 0000000000..b885a970ba
--- /dev/null
+++ b/public/views/myNbhInteractive/config.js
@@ -0,0 +1,50 @@
+// Slider to choose MyNbh caches item
+$(function() {
+ var handle = $("#nbh-custom-handle");
+ $("#nbh-slider").slider({
+ value : cachesCount,
+ min : minCaches,
+ max : maxCaches,
+ create : function() {
+ handle.text($(this).slider("value"));
+ },
+ slide : function(event, ui) {
+ handle.text(ui.value);
+ $("#input-caches").val(ui.value);
+ }
+ });
+});
+
+// Buttons to choose MyNbh style
+$(function() {
+ $(".nbh-radio").checkboxradio();
+ $("fieldset").controlgroup();
+});
+
+// Delete Nbh button
+$("#nbh-delete-btn").click(function(e) {
+ e.preventDefault();
+ $("#nbh-delete-dialog-confirm").dialog("open");
+});
+
+// Delete Nbh - confirm dialog
+$(function() {
+ $("#nbh-delete-dialog-confirm").dialog({
+ autoOpen : false,
+ resizable : false,
+ modal : true,
+ hide : 250,
+ closeText : cancelButton,
+ buttons : [ {
+ text : deleteButton,
+ click : function() {
+ window.location = deleteLink;
+ },
+ }, {
+ text : cancelButton,
+ click : function() {
+ $(this).dialog("close");
+ }
+ } ]
+ });
+});
diff --git a/public/views/myNbhInteractive/config_draw.js b/public/views/myNbhInteractive/config_draw.js
new file mode 100644
index 0000000000..7f44b60662
--- /dev/null
+++ b/public/views/myNbhInteractive/config_draw.js
@@ -0,0 +1,307 @@
+class ConfigDraw {
+
+ constructor(map, minRadius, maxRadius) {
+ if (map == null || ! map instanceof ol.Map) {
+ throw "Invalid map parameter";
+ }
+
+ this.map = map;
+ this.minRadius = minRadius;
+ this.maxRadius = maxRadius;
+
+ this.configDrawCommonStyles = {
+ 'Circle': [
+ new ol.style.Style({
+ fill: new ol.style.Fill({
+ color: [255, 255, 0, 0.35]
+ }),
+ stroke: new ol.style.Stroke({
+ color: [0, 0, 0, 0.8],
+ width: 1
+ }),
+ }),
+ ]
+ };
+ this.configDrawCommonStyles['GeometryCollection'] =
+ this.configDrawCommonStyles['Circle'].concat(
+ new ol.style.Style({
+ image: new ol.style.Circle({
+ radius: 5,
+ fill: new ol.style.Fill({
+ color: [255, 255, 255, 1]
+ }),
+ stroke: new ol.style.Stroke({
+ color: [0, 0, 0, 1],
+ width: 1
+ }),
+ }),
+ })
+ );
+
+ this.configDrawModifyStyles = Object.assign(
+ {}, this.configDrawCommonStyles
+ );
+ this.configDrawModifyStyles['Point'] = [
+ new ol.style.Style({
+ image: new ol.style.Circle({
+ radius: 4,
+ fill: new ol.style.Fill({
+ color: [255, 255, 255, 1]
+ }),
+ stroke: new ol.style.Stroke({
+ color: [0, 0, 0, 1],
+ width: 1
+ }),
+ }),
+ }),
+ ];
+
+ const instance = this;
+ this.configSource = new ol.source.Vector();
+ this.configLayer = new ol.layer.Vector({
+ source: this.configSource,
+ zIndex: 1000,
+ style: function(feature, resolution) {
+ return instance.configDrawModifyStyles[
+ feature.getGeometry().getType()
+ ];
+ },
+ });
+ this.configLayer.set('ocLayerName', 'oc_mynbh_config');
+
+ this.modify = new ol.interaction.Modify({
+ source: this.configSource,
+ style: function(feature, resolution) {
+ return instance.configDrawModifyStyles[
+ feature.getGeometry().getType()
+ ];
+ },
+ });
+
+ this.snap = new ol.interaction.Snap({
+ source: this.configSource
+ });
+
+ this.hooks = {};
+ }
+
+ setHooks(hooks) {
+ if (hooks != null && typeof(hooks) === "object") {
+ this.hooks = hooks;
+ }
+ }
+
+ addHook(name, hook) {
+ this.hooks[name] = hook;
+ }
+
+ init(initLatLon, initRadius) {
+ this.map.addLayer(this.configLayer);
+ this.map.addInteraction(this.snap);
+
+ if (initLatLon && initRadius) {
+ let currentGeometry = this._configGeometry(
+ this._computeShapePoints(initLatLon, initRadius)
+ );
+ this.configSource.addFeature(new ol.Feature({
+ geometry: currentGeometry,
+ style: this.configDrawCommonStyles['GeometryCollection']
+ }));
+ this.map.getView().fit(currentGeometry.getExtent());
+ this._startModifications();
+ } else {
+ const instance = this;
+ this.draw = new ol.interaction.Draw({
+ type: 'Circle',
+ source: this.configSource,
+ stopClick: true,
+ style: function(feature, resolution) {
+ return instance.configDrawCommonStyles[
+ feature.getGeometry().getType()
+ ];
+ },
+ freehand: true,
+ geometryFunction: this._configGeometry
+ });
+
+ this.draw.on("drawend", function(ev) {
+ return instance._drawComplete(ev.feature);
+ });
+ }
+ }
+
+ startDrawing() {
+ if (this.draw) {
+ this.map.addInteraction(this.draw);
+ }
+ }
+
+ _configGeometry(coordinates, geometry) {
+ let center = coordinates[0];
+ let last = coordinates[1];
+ let dx = center[0] - last[0];
+ let dy = center[1] - last[1];
+ let radius = Math.sqrt(dx * dx + dy * dy);
+ if (!geometry) {
+ geometry = new ol.geom.GeometryCollection();
+ }
+ geometry.setGeometries([
+ new ol.geom.Point(center),
+ new ol.geom.Circle(center, radius)
+ ]);
+ return geometry;
+ }
+
+ _drawComplete(feature) {
+ feature.setStyle(this.configDrawCommonStyles['GeometryCollection']);
+ this._applyRestrictions(feature);
+ this._callUpdateConfigHook(feature);
+ this.map.removeInteraction(this.draw);
+ this._startModifications();
+ }
+
+ _callUpdateConfigHook(feature, newCoords, newRadius) {
+ if (typeof(this.hooks["updateConfig"]) === "function") {
+ if (!newCoords || !newRadius) {
+ [ newCoords, newRadius ] =
+ this._computeNewConfigParams(feature);
+ }
+ this.hooks["updateConfig"](newCoords[0], newCoords[1], newRadius);
+ }
+ }
+
+ _getConfigShapes(feature, onlyCircle = false) {
+ let circle, point;
+ feature.getGeometry().getGeometries().forEach(function(g) {
+ if (g.getType() == 'Circle') {
+ circle = g;
+ } else if (!onlyCircle && g.getType() == 'Point') {
+ point = g;
+ }
+ });
+ return onlyCircle ? circle : [ circle, point ];
+ }
+
+ _applyRestrictions(feature) {
+ let circle = this._getConfigShapes(feature, true);
+ let radius = this._radiusToKm(circle);
+ let adjust = false;
+ if (radius > this.maxRadius) {
+ radius = this.maxRadius;
+ adjust = true;
+ } else if (radius < this.minRadius) {
+ radius = this.minRadius;
+ adjust = true;
+ }
+ if (adjust) {
+ feature.setGeometry(this._configGeometry(
+ this._computeShapePoints(circle.getCenter(), radius, false)
+ ));
+ }
+ }
+
+ _startModifications() {
+ this.map.addInteraction(this.modify);
+ const instance = this;
+ this.map.on('pointermove', function(ev) {
+ return instance._pointerMoveOnModify(ev);
+ });
+ this.modify.on('modifyend', function(ev) {
+ if (ev.features.getLength() > 0) {
+ let feature = ev.features.item(0);
+ instance._applyRestrictions(feature);
+ instance._callUpdateConfigHook(feature);
+ }
+ });
+ }
+
+ _pointerMoveOnModify(ev) {
+ const classNames = [
+ 'dynamicMap_cursorResize', 'dynamicMap_cursorMove'
+ ];
+ let c = ev.coordinate;
+ let mf = this.map.getView().getResolution() * 10;
+
+ let ft = this.configSource.getFeatures();
+ if (ft.length) {
+ let [circle, point] = this._getConfigShapes(ft[0]);
+ let className, dist;
+ if (circle) {
+ let radius = circle.getRadius();
+ dist = this._computeDist(circle.getCenter(), c);
+ if (dist >= (radius - mf) && dist <= (radius + mf)) {
+ className = classNames[0];
+ }
+ }
+ if (!className && point) {
+ if (!dist) {
+ dist = this._computeDist(point.getCoordinates(), c);
+ }
+ if (dist <= mf) {
+ className = classNames[1];
+ }
+ }
+ let classAdded = false;
+ let currentClasses = this.map.getTargetElement().classList;
+ classNames.forEach(function(cn) {
+ if (!className || className != cn) {
+ currentClasses.remove(cn);
+ } else {
+ classAdded = (className && currentClasses.contains(cn));
+ }
+ });
+ if (className && !classAdded) {
+ currentClasses.add(className);
+ }
+ }
+ }
+
+ _computeNewConfigParams(feature) {
+ let circle = this._getConfigShapes(feature, true);
+ let newCoords = this._toLatLon(circle.getCenter());
+ let newRadius = this._radiusToKm(circle);
+ return [ newCoords, newRadius ];
+ }
+
+ _computeDist(startCoords, finalCoords) {
+ let dx = startCoords[0] - finalCoords[0];
+ let dy = startCoords[1] - finalCoords[1];
+ return Math.sqrt(dx * dx + dy * dy);
+ }
+
+ _computeShapePoints(centerCoords, radiusInKm, coordsAreLatLon = true) {
+ let centerLatLon =
+ coordsAreLatLon ? centerCoords : this._toLatLon(centerCoords);
+ let centerPoint =
+ coordsAreLatLon ? this._fromLatLon(centerCoords) : centerCoords;
+ let factor = 1/Math.cos(centerLatLon[0] * Math.PI / 180);
+ let radiusPoint = ol.extent.getTopRight(
+ (new ol.geom.Circle(
+ centerPoint, radiusInKm * 1000 * factor
+ )).getExtent()
+ );
+ radiusPoint[1] = centerPoint[1];
+ return [ centerPoint, radiusPoint ];
+ }
+
+ _radiusToKm(circle) {
+ let centerLatLon = this._toLatLon(circle.getCenter());
+ let factor = 1/Math.cos(centerLatLon[0] * Math.PI / 180);
+ return Math.round( ( circle.getRadius() / factor ) / 1000 );
+ }
+
+ _fromLatLon(latlonPoint) {
+ return ol.proj.transform(
+ (latlonPoint.constructor === Array)
+ ? [ latlonPoint[1], latlonPoint[0] ]
+ : [ latlonPoint.lon, latlonPoint.lat ],
+ "EPSG:4326",
+ "EPSG:3857"
+ );
+ }
+
+ _toLatLon(xyPoint) {
+ let lonlat = ol.proj.transform(xyPoint, "EPSG:3857", "EPSG:4326");
+ return [ lonlat[1], lonlat[0] ];
+ }
+}
diff --git a/public/views/myNbhInteractive/myNeighbourhood-full.css b/public/views/myNbhInteractive/myNeighbourhood-full.css
new file mode 100644
index 0000000000..bae2efb864
--- /dev/null
+++ b/public/views/myNbhInteractive/myNeighbourhood-full.css
@@ -0,0 +1,13 @@
+@charset "UTF-8";
+
+.nbh-icon {
+ height: 32px;
+}
+
+.nbh-line-container:hover, tr:hover {
+ background-color: #f5f5f5;
+}
+
+.nbh-min-only {
+ display: none;
+}
\ No newline at end of file
diff --git a/public/views/myNbhInteractive/myNeighbourhood-min.css b/public/views/myNbhInteractive/myNeighbourhood-min.css
new file mode 100644
index 0000000000..5ea14cbde9
--- /dev/null
+++ b/public/views/myNbhInteractive/myNeighbourhood-min.css
@@ -0,0 +1,13 @@
+@charset "UTF-8";
+
+.nbh-icon {
+ height: 16px;
+}
+
+.nbh-line-container:nth-child(odd), tr:nth-child(odd) {
+ background-color: #f5f5f5;
+}
+
+.nbh-full-only {
+ display: none;
+}
\ No newline at end of file
diff --git a/public/views/myNbhInteractive/myNeighbourhood.js b/public/views/myNbhInteractive/myNeighbourhood.js
new file mode 100644
index 0000000000..e87cd1010b
--- /dev/null
+++ b/public/views/myNbhInteractive/myNeighbourhood.js
@@ -0,0 +1,83 @@
+$(".nbh-sort-list").sortable({
+ handle : ".nbh-block-header",
+ opacity : 0.7,
+ placeholder : "nbh-block-placeholder",
+ update : function(event, ui) {
+ let postData = $(this).sortable("serialize");
+
+ if (InteractiveMapServices.getInteractiveMap("nbhmap")) {
+ // get current order of sections
+ var orders = {};
+ var n = 0;
+ $(this).sortable("toArray").forEach(function(v) {
+ orders[v.replace('item_', '')] = n++;
+ });
+ // reorder map sections to move the highest section features to front
+ InteractiveMapServices.reorderSections("nbhmap", orders);
+ }
+
+ $.ajax({
+ url : changeOrderUri,
+ type : "post",
+ data : {
+ order : postData
+ }
+ });
+ }
+});
+
+$(".nbh-hide-toggle").on("click", function() {
+ let icon = $(this);
+ icon.closest(".nbh-block").find(".nbh-block-content").toggleClass(
+ 'nbh-nodisplay');
+ let hidden = icon.closest(".nbh-block").find(".nbh-block-content")
+ .hasClass("nbh-nodisplay");
+ let itemId = icon.closest(".nbh-block").attr('id');
+ let section = icon.closest(".nbh-block").attr('section');
+ $.ajax({
+ url : changeDisplayAjaxUri,
+ type : "post",
+ data : {
+ hide : hidden,
+ item : itemId
+ }
+ })
+ if (InteractiveMapServices.getInteractiveMap("nbhmap")) {
+ if (this.id == "nbh-map-hide") {
+ InteractiveMapServices.getMapObject("nbhmap").updateSize();
+ } else {
+ InteractiveMapServices.toggleSectionVisibility("nbhmap", section);
+ }
+ }
+});
+
+$(".nbh-size-toggle").on("click", function() {
+ let icon = $(this);
+ icon.closest(".nbh-block").toggleClass("nbh-half nbh-full");
+ let sizeClass = icon.closest(".nbh-block").hasClass("nbh-full");
+ let itemId = icon.closest(".nbh-block").attr('id');
+ $.ajax({
+ url : changeSizeAjaxUri,
+ type : "post",
+ data : {
+ size : sizeClass,
+ item : itemId
+ }
+ });
+ if (this.id == "nbh-map-resize") {
+ var map = InteractiveMapServices.getMapObject("nbhmap");
+ if (map) {
+ map.updateSize();
+ }
+ }
+});
+
+$("div[id^='mynbh_item_'").mouseenter(function() {
+ var id = this.id.substring("mynbh_item_".length);
+ var parts = id.split('_');
+ InteractiveMapServices.highlightFeature("nbhmap", parts[1], parts[2], parts[0]);
+});
+
+$("div[id^='mynbh_item_'").mouseleave(function() {
+ InteractiveMapServices.toneDownFeature("nbhmap");
+});
diff --git a/src/Controllers/MyNbhInteractiveController.php b/src/Controllers/MyNbhInteractiveController.php
new file mode 100644
index 0000000000..b44cbba7d2
--- /dev/null
+++ b/src/Controllers/MyNbhInteractiveController.php
@@ -0,0 +1,744 @@
+isUserLogged()
+ || self::VALIDATION_MODE && !(
+ $this->loggedUser->hasOcTeamRole()
+ || $this->loggedUser->hasAdvUserRole()
+ || $this->loggedUser->hasSysAdminRole()
+ )
+ ) {
+ $this->view->redirect(
+ Uri::setOrReplaceParamValue('target', Uri::getCurrentUri(), '/'));
+ exit();
+ }
+ }
+
+ /**
+ * Displays main MyNeighbourhood page
+ *
+ * @param int $nbhSeq - MyNbh number (seq). 0 = default user's Nbh
+ */
+ public function index($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ $neighbourhoodsList =
+ Neighbourhood::getNeighbourhoodsList($this->loggedUser);
+ if (empty($neighbourhoodsList)) {
+ // User doesn't have any MyNeighbourhoods set, so redirect to config
+ $this->view->redirect(
+ SimpleRouter::getLink(self::class, 'config')
+ );
+ exit();
+ }
+ $selectedNbh = (int) $nbhSeq;
+ if (! array_key_exists($selectedNbh, $neighbourhoodsList)) {
+ // Selected MyNeighbourhood not found
+ if ($selectedNbh == 0) {
+ // User has no Home Coords -> redirect to config
+ $this->view->redirect(
+ SimpleRouter::getLink(self::class, 'config')
+ );
+ } else {
+ // Redirect to default MyNeighbourhood
+ $this->view->redirect(
+ SimpleRouter::getLink(self::class, 'index', 0)
+ );
+ }
+ exit();
+ }
+ $preferences =
+ UserPreferences::getUserPrefsByKey(NeighbourhoodPref::KEY)->getValues();
+ $nbhItemSet = new MyNbhSets(
+ $neighbourhoodsList[$selectedNbh]->getCoords(),
+ $neighbourhoodsList[$selectedNbh]->getRadius()
+ );
+ $latestCaches = $nbhItemSet->getLatestCaches(
+ $preferences['style']['caches-count'], 0, false
+ );
+ $upcomingEvents = $nbhItemSet->getUpcomingEvents(
+ $preferences['style']['caches-count'], 0
+ );
+ $ftfCaches = $nbhItemSet->getLatestCaches(
+ $preferences['style']['caches-count'], 0, true
+ );
+ $latestLogs = $nbhItemSet->getLatestLogs(
+ $preferences['style']['caches-count'], 0
+ );
+ $topRatedCaches = $nbhItemSet->getTopRatedCaches(
+ $preferences['style']['caches-count'], 0
+ );
+ $latestTitled = $nbhItemSet->getLatestTitledCaches(
+ $preferences['style']['caches-count'], 0
+ );
+ $this->view->setVar('latestCaches', $latestCaches);
+ $this->view->setVar('upcomingEvents', $upcomingEvents);
+ $this->view->setVar('FTFCaches', $ftfCaches);
+ $this->view->setVar('latestLogs', $latestLogs);
+ $this->view->setVar('topRatedCaches', $topRatedCaches);
+ $this->view->setVar('latestTitled', $latestTitled);
+ $this->view->setVar('neighbourhoodsList', $neighbourhoodsList);
+ $this->view->setVar('selectedNbh', $selectedNbh);
+ $this->view->setVar('preferences', $preferences);
+ $this->view->setVar('user', $this->loggedUser);
+
+ $this->view->addHeaderChunk('openLayers5');
+
+ $mapModel = new InteractiveMapModel();
+ foreach ($preferences['items'] as $sectionName => $sectionConfig) {
+ $sectionCaches = null;
+ switch ($sectionName) {
+ case Neighbourhood::ITEM_LATESTCACHES:
+ $sectionCaches = $latestCaches;
+ break;
+ case Neighbourhood::ITEM_UPCOMINGEVENTS:
+ $sectionCaches = $upcomingEvents;
+ break;
+ case Neighbourhood::ITEM_FTFCACHES:
+ $sectionCaches = $ftfCaches;
+ break;
+ case Neighbourhood::ITEM_TITLEDCACHES:
+ $sectionCaches = $latestTitled;
+ break;
+ case Neighbourhood::ITEM_RECOMMENDEDCACHES:
+ $sectionCaches = $topRatedCaches;
+ break;
+ default:
+ break;
+ }
+ if ($sectionCaches) {
+ $mapModel->addMarkersWithExtractor(
+ CacheMarkerModel::class,
+ $sectionCaches,
+ function($row) use ($sectionName) {
+ $marker = CacheMarkerModel::fromGeocacheFactory(
+ $row, $this->loggedUser
+ );
+ $marker->section = $sectionName;
+ return $marker;
+ }
+ );
+ }
+ $mapModel->setSectionProperties($sectionName, [
+ "visible" => $sectionConfig['show'],
+ "order" => $sectionConfig['order'],
+ ]);
+ }
+
+ $mapModel->addMarkersWithExtractor(
+ LogMarkerModel::class,
+ $latestLogs,
+ function($row) {
+ $marker = LogMarkerModel::fromGeoCacheLogFactory(
+ $row, $this->loggedUser
+ );
+ $marker->section = Neighbourhood::ITEM_LATESTLOGS;
+ return $marker;
+ }
+ );
+
+ $mapModel->setSectionsKeys(Neighbourhood::SECTIONS);
+
+ $this->view->setVar('mapModel', $mapModel);
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'myNeighbourhood',
+ true, [ 'myNeighbourhood.js' ] , true
+ );
+ $this->view->setVar('controller', self::class);
+ $this->view->setVar('templatesPath', self::TEMPLATES_PATH);
+ $this->view->setVar('publicSrcPath', self::PUBLIC_SRC_PATH);
+ $this->view->buildView();
+ }
+
+ private function setPublicResourcesAndTemplate(
+ $preferences, $template,
+ $addStyled = true, $javascripts = [], $loadJQueryUI = false
+ ) {
+ $this->view->addLocalCss(
+ Uri::getLinkWithModificationTime(
+ self::PUBLIC_SRC_PATH . 'common.css'
+ )
+ );
+ if ($addStyled) {
+ $this->view->addLocalCss(
+ Uri::getLinkWithModificationTime(
+ self::PUBLIC_SRC_PATH . 'myNeighbourhood-'
+ . $preferences['style']['name'] . '.css'
+ )
+ );
+ }
+ $this->view->addLocalCss(
+ Uri::getLinkWithModificationTime('/css/lightTooltip.css')
+ );
+ if (!empty($javascripts)) {
+ if (!is_array($javascripts)) {
+ $javascripts = [ $javascripts ];
+ }
+ foreach ($javascripts as $js) {
+ $this->view->addLocalJs(
+ Uri::getLinkWithModificationTime(
+ self::PUBLIC_SRC_PATH . $js
+ ),
+ true,
+ true
+ );
+ }
+ }
+ if ($loadJQueryUI) {
+ $this->view->loadJQueryUI();
+ }
+ $this->view->setVar('controller', self::class);
+ $this->view->setTemplate(self::TEMPLATES_PATH . $template);
+ }
+
+ private function getSectionRequestCommons($nbhSeq = 0)
+ {
+ $this->redirectNotLoggedUsers();
+ $selectedNbh = (int) $nbhSeq;
+ $preferences =
+ UserPreferences::getUserPrefsByKey(NeighbourhoodPref::KEY)->getValues();
+ $neighbourhoodsList =
+ Neighbourhood::getNeighbourhoodsList($this->loggedUser);
+ if (! array_key_exists($selectedNbh, $neighbourhoodsList)) {
+ // Selected MyNeighbourhood not found
+ $this->view->redirect(
+ SimpleRouter::getLink(self::class, 'index')
+ );
+ exit();
+ }
+ $coords = $neighbourhoodsList[$selectedNbh]->getCoords();
+ $nbhItemSet = new MyNbhSets(
+ $coords,
+ $neighbourhoodsList[$selectedNbh]->getRadius()
+ );
+ $paginationModel = new PaginationModel(self::ITEMS_PER_DETAIL_PAGE);
+ return [
+ $selectedNbh, $preferences, $neighbourhoodsList,
+ $coords, $nbhItemSet, $paginationModel
+ ];
+ }
+
+ private function setSectionCommonVars(
+ $neighbourhoodsList, $paginationModel, $selectedNbh, $coords
+ ) {
+ $this->view->setVar('neighbourhoodsList', $neighbourhoodsList);
+ $this->view->setVar('paginationModel', $paginationModel);
+ $this->view->setVar('selectedNbh', $selectedNbh);
+ $this->view->setVar('user', $this->loggedUser);
+ $this->view->setVar('coords', $coords);
+ }
+
+ /**
+ * Displays latest caches detailed page for Nbh selected as $nbhSeq
+ *
+ * @param int $nbhSeq
+ */
+ public function latestCaches($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ list (
+ $selectedNbh, $preferences, $neighbourhoodsList,
+ $coords, $nbhItemSet, $paginationModel
+ ) = $this->getSectionRequestCommons($nbhSeq);
+
+ $paginationModel->setRecordsCount(
+ $nbhItemSet->getLatestCachesCount(false)
+ );
+ list ($limit, $offset) = $paginationModel->getQueryLimitAndOffset();
+ $this->view->setVar(
+ 'caches', $nbhItemSet->getLatestCaches($limit, $offset, false)
+ );
+ $this->setSectionCommonVars(
+ $neighbourhoodsList, $paginationModel, $selectedNbh, $coords
+ );
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'detail_LatestCaches'
+ );
+ $this->view->buildView();
+ }
+
+ /**
+ * Displays most recommended caches detailed page for Nbh selected as $nbhSeq
+ *
+ * @param int $nbhSeq
+ */
+ public function mostRecommended($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ list (
+ $selectedNbh, $preferences, $neighbourhoodsList,
+ $coords, $nbhItemSet, $paginationModel
+ ) = $this->getSectionRequestCommons($nbhSeq);
+
+ $paginationModel->setRecordsCount(
+ $nbhItemSet->getTopRatedCachesCount()
+ );
+ list ($limit, $offset) = $paginationModel->getQueryLimitAndOffset();
+ $this->view->setVar(
+ 'caches', $nbhItemSet->getTopRatedCaches($limit, $offset)
+ );
+ $this->setSectionCommonVars(
+ $neighbourhoodsList, $paginationModel, $selectedNbh, $coords
+ );
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'detail_RecommendedCaches'
+ );
+ $this->view->buildView();
+ }
+
+ /**
+ * Displays FTF caches detailed page for Nbh selected as $nbhSeq
+ *
+ * @param int $nbhSeq
+ */
+ public function ftfCaches($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ list (
+ $selectedNbh, $preferences, $neighbourhoodsList,
+ $coords, $nbhItemSet, $paginationModel
+ ) = $this->getSectionRequestCommons($nbhSeq);
+
+ $paginationModel->setRecordsCount(
+ $nbhItemSet->getLatestCachesCount(true)
+ );
+ list ($limit, $offset) = $paginationModel->getQueryLimitAndOffset();
+ $this->view->setVar(
+ 'caches', $nbhItemSet->getLatestCaches($limit, $offset, true)
+ );
+ $this->setSectionCommonVars(
+ $neighbourhoodsList, $paginationModel, $selectedNbh, $coords
+ );
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'detail_FTFCaches'
+ );
+ $this->view->buildView();
+ }
+
+ /**
+ * Displays titled caches detailed page for Nbh selected as $nbhSeq
+ *
+ * @param int $nbhSeq
+ */
+ public function titledCaches($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ list (
+ $selectedNbh, $preferences, $neighbourhoodsList,
+ $coords, $nbhItemSet, $paginationModel
+ ) = $this->getSectionRequestCommons($nbhSeq);
+
+ $paginationModel->setRecordsCount(
+ $nbhItemSet->getLatestTitledCachesCount()
+ );
+ list ($limit, $offset) = $paginationModel->getQueryLimitAndOffset();
+ $this->view->setVar(
+ 'caches', $nbhItemSet->getLatestTitledCaches($limit, $offset)
+ );
+ $this->setSectionCommonVars(
+ $neighbourhoodsList, $paginationModel, $selectedNbh, $coords
+ );
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'detail_TitledCaches'
+ );
+ $this->view->buildView();
+ }
+
+ /**
+ * Displays upcomming events detailed page for Nbh selected as $nbhSeq
+ *
+ * @param int $nbhSeq
+ */
+ public function upcommingEvents($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ list (
+ $selectedNbh, $preferences, $neighbourhoodsList,
+ $coords, $nbhItemSet, $paginationModel
+ ) = $this->getSectionRequestCommons($nbhSeq);
+
+ $paginationModel->setRecordsCount(
+ $nbhItemSet->getUpcomingEventsCount()
+ );
+ list ($limit, $offset) = $paginationModel->getQueryLimitAndOffset();
+ $this->view->setVar(
+ 'caches', $nbhItemSet->getUpcomingEvents($limit, $offset)
+ );
+ $this->setSectionCommonVars(
+ $neighbourhoodsList, $paginationModel, $selectedNbh, $coords
+ );
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'detail_UpcommingEvents'
+ );
+ $this->view->buildView();
+ }
+
+ /**
+ * Displays latest logs detailed page for Nbh selected as $nbhSeq
+ *
+ * @param int $nbhSeq
+ */
+ public function latestLogs($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ list (
+ $selectedNbh, $preferences, $neighbourhoodsList,
+ $coords, $logset, $paginationModel
+ ) = $this->getSectionRequestCommons($nbhSeq);
+
+ $paginationModel->setRecordsCount($logset->getLatestLogsCount());
+ list ($limit, $offset) = $paginationModel->getQueryLimitAndOffset();
+ $this->view->setVar('logs', $logset->getLatestLogs($limit, $offset));
+ $this->setSectionCommonVars(
+ $neighbourhoodsList, $paginationModel, $selectedNbh, $coords
+ );
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'detail_LatestLogs'
+ );
+ $this->view->buildView();
+ }
+
+ /**
+ * Displays MyNeighbour config
+ *
+ * @param number $nbhSeq - number of MyNbh (seq). 0 = default user's Nbh
+ */
+ public function config($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ $selectedNbh = (int) $nbhSeq;
+
+ $preferences =
+ UserPreferences::getUserPrefsByKey(NeighbourhoodPref::KEY)->getValues();
+
+ $neighbourhoodsList =
+ Neighbourhood::getNeighbourhoodsList($this->loggedUser);
+ if (
+ $selectedNbh != - 1
+ && ! array_key_exists($selectedNbh, $neighbourhoodsList)
+ ) {
+ $selectedNbh = 0;
+ }
+ if (array_key_exists($selectedNbh, $neighbourhoodsList)) {
+ $this->view->setVar('coordsOK', 1);
+ } else {
+ $this->view->setVar('coordsOK', 0);
+ }
+ $this->view->setVar('neighbourhoodsList', $neighbourhoodsList);
+ $this->view->setVar('selectedNbh', $selectedNbh);
+ $this->view->setVar('preferences', $preferences);
+ $this->view->setVar('maxnbh', self::MAX_NEIGHBOURHOODS);
+ $this->view->setVar('minCaches', self::CACHES_PER_PAGE_MIN);
+ $this->view->setVar('maxCaches', self::CACHES_PER_PAGE_MAX);
+ $this->view->setVar('minRadius', self::NBH_RADIUS_MIN);
+ $this->view->setVar('maxRadius', self::NBH_RADIUS_MAX);
+ $this->view->setVar('errorMsg', $this->errorMsg);
+ $this->view->setVar('infoMsg', $this->infoMsg);
+
+ $this->view->addHeaderChunk('openLayers5');
+
+ $mapModel = new InteractiveMapModel();
+ $mapModel->setZoom(6);
+ $this->view->setVar('mapModel', $mapModel);
+ $this->setPublicResourcesAndTemplate(
+ $preferences, 'config',
+ false, [ 'config.js', 'config_draw.js' ], true
+ );
+ $this->view->buildView();
+ }
+
+ /**
+ * Saves new/modified MyNbh. Called by MyNbh config form
+ *
+ * @param number $nbhSeq - number of MyNbh (seq). 0 = default user's Nbh
+ */
+ public function save($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ $error = null;
+ $seq = null;
+ $definedNbh = count(
+ Neighbourhood::getAdditionalNeighbourhoodsList($this->loggedUser)
+ );
+ // Store MyNeighbourhood data
+ if (
+ isset($_POST['lon'])
+ && isset($_POST['lat'])
+ && isset($_POST['radius'])
+ ) {
+ $coords = Coordinates::FromCoordsFactory(
+ $_POST['lat'], $_POST['lon']
+ );
+ $radius = (int) $_POST['radius'];
+ if ($radius > self::NBH_RADIUS_MAX) {
+ $radius = self::NBH_RADIUS_MAX;
+ } elseif ($radius < self::NBH_RADIUS_MIN) {
+ $radius = self::NBH_RADIUS_MIN;
+ }
+ if ($coords !== null) {
+ if ($nbhSeq == 0) {
+ // Update Home Coords and radius
+ if (
+ ! $this->loggedUser->updateUserNeighbourhood(
+ $coords, $_POST['radius']
+ )
+ ) {
+ // Error during save MyNbh (should never happen, but...)
+ $error = tr('myn_save_error');
+ }
+ } elseif (
+ isset($_POST['name'])
+ && ($nbhSeq > 0 || $definedNbh < self::MAX_NEIGHBOURHOODS)
+ ) {
+ // Save additional neighbourhood
+ $seq = ($nbhSeq < 0) ? null : $nbhSeq;
+ $name = trim($_POST['name']);
+ $name = UserInputFilter::purifyHtmlString($name);
+ $name = strip_tags($name);
+ $name = mb_strcut($name, 0, 16);
+ if (mb_strlen($name) < 1) {
+ // Name too short
+ $name = 'X';
+ }
+ if (
+ ! Neighbourhood::storeUserNeighbourhood(
+ $this->loggedUser, $coords, $radius, $name, $seq
+ )
+ ) {
+ // Error during save additional MyNbh
+ // (should never happen, but...)
+ $error = tr('myn_save_error');
+ }
+ } else {
+ // Incorrect $_POST - without name or user exceeded
+ // max total nbh's
+ $error = tr('myn_coords_error');
+ }
+ } else { // Coords are not OK
+ $error = tr('myn_coords_error');
+ }
+ } else { // User not choose coords | radius
+ $error = tr('myn_coords_error');
+ }
+ // Store user preferences
+ if (
+ $nbhSeq == 0
+ && isset($_POST['caches-perpage'])
+ && isset($_POST['style'])
+ && ($_POST['style'] == 'full' || $_POST['style'] == 'min')
+ ) {
+ $cachesPerpage = (int) $_POST['caches-perpage'];
+ if ($cachesPerpage > self::CACHES_PER_PAGE_MAX) {
+ $cachesPerpage = self::CACHES_PER_PAGE_MAX;
+ } elseif ($cachesPerpage < self::CACHES_PER_PAGE_MIN) {
+ $cachesPerpage = self::CACHES_PER_PAGE_MIN;
+ }
+ $preferences =
+ UserPreferences::getUserPrefsByKey(NeighbourhoodPref::KEY)->getValues();
+ $preferences['style']['name'] = $_POST['style'];
+ $preferences['style']['caches-count'] = $cachesPerpage;
+ if (
+ ! UserPreferences::savePreferencesJson(
+ NeighbourhoodPref::KEY, json_encode($preferences)
+ )
+ ) {
+ // Error during storing user preferences
+ $error = tr('myn_save_error');
+ }
+ }
+ if (is_null($error)) {
+ $this->infoMsg = tr('myn_save_success');
+ } else {
+ $this->errorMsg = $error;
+ }
+ $this->config($seq == null ? 0 : $seq);
+ }
+
+ /**
+ * Deletes My Nbh - called by form in config
+ *
+ * @param number $nbhSeq - MyNbh number (seq). 0 = default user's Nbh
+ */
+ public function delete($nbhSeq = 0)
+ {
+ $this->accessControl();
+
+ $success = true;
+ if ($nbhSeq > 0) { // User cannot delete HomeCoords!
+ if (
+ ! Neighbourhood::removeUserNeighbourhood(
+ $this->loggedUser, $nbhSeq
+ )
+ ) {
+ $success = false;
+ }
+ } else {
+ // User try to delete Home Coords
+ $success = false;
+ }
+ if ($success) {
+ $this->infoMsg = tr('myn_delete_success');
+ } else {
+ $this->errorMsg = tr('myn_delete_error');
+ }
+ $this->config(0);
+ exit();
+ }
+
+ /**
+ * Saves changed order of MyNbh sections. Called via Ajax by MyNbh main page
+ */
+ public function changeOrderAjax()
+ {
+ $this->checkUserLoggedAjax();
+ $this->paramAjaxCheck('order');
+ $order = [];
+ parse_str($_POST['order'], $order);
+ $preferences =
+ UserPreferences::getUserPrefsByKey(NeighbourhoodPref::KEY)->getValues();
+ $counter = 1;
+ foreach ($order['item'] as $itemOrder) {
+ $preferences['items'][$itemOrder]['order'] = $counter;
+ $counter += 1;
+ }
+ if (
+ ! UserPreferences::savePreferencesJson(
+ NeighbourhoodPref::KEY, json_encode($preferences)
+ )
+ ) {
+ $this->ajaxErrorResponse('Error saving UserPreferences');
+ }
+ $this->ajaxSuccessResponse();
+ }
+
+ /**
+ * Saves changed size of MyNbh section. Called via Ajax by MyNbh main page
+ */
+ public function changeSizeAjax()
+ {
+ $this->checkUserLoggedAjax();
+ $this->paramAjaxCheck('size');
+ $this->paramAjaxCheck('item');
+ $preferences =
+ UserPreferences::getUserPrefsByKey(NeighbourhoodPref::KEY)->getValues();
+ $itemNr = ltrim($_POST['item'], 'item_');
+ $preferences['items'][$itemNr]['fullsize'] = filter_var(
+ $_POST['size'], FILTER_VALIDATE_BOOLEAN
+ );
+ if (
+ ! UserPreferences::savePreferencesJson(
+ NeighbourhoodPref::KEY, json_encode($preferences)
+ )
+ ) {
+ $this->ajaxErrorResponse('Error saving UserPreferences');
+ }
+ $this->ajaxSuccessResponse();
+ }
+
+ /**
+ * Saves display status of MyNbh section. Called via Ajax by MyNbh main page
+ */
+ public function changeDisplayAjax()
+ {
+ $this->checkUserLoggedAjax();
+ $this->paramAjaxCheck('hide');
+ $this->paramAjaxCheck('item');
+ $preferences =
+ UserPreferences::getUserPrefsByKey(NeighbourhoodPref::KEY)->getValues();
+ $itemNr = ltrim($_POST['item'], 'item_');
+ $preferences['items'][$itemNr]['show'] = ! filter_var(
+ $_POST['hide'], FILTER_VALIDATE_BOOLEAN
+ );
+ if (
+ ! UserPreferences::savePreferencesJson(
+ NeighbourhoodPref::KEY, json_encode($preferences)
+ )
+ ) {
+ $this->ajaxErrorResponse('Error saving UserPreferences');
+ }
+ $this->ajaxSuccessResponse();
+ }
+
+ public function isCallableFromRouter($actionName)
+ {
+ return true;
+ }
+
+ /**
+ * Check if $_POST[$paramName] is set. If not - generates 400 AJAX response
+ *
+ * @param string $paramName
+ */
+ private function paramAjaxCheck($paramName)
+ {
+ if (! isset($_POST[$paramName])) {
+ $this->ajaxErrorResponse('No parameter: ' . $paramName, 400);
+ exit();
+ }
+ }
+}
diff --git a/src/Models/ChunkModels/InteractiveMap/AbstractMarkerModelBase.php b/src/Models/ChunkModels/InteractiveMap/AbstractMarkerModelBase.php
new file mode 100644
index 0000000000..f5a22f8dfa
--- /dev/null
+++ b/src/Models/ChunkModels/InteractiveMap/AbstractMarkerModelBase.php
@@ -0,0 +1,42 @@
+getShortName();
+ return preg_replace('/Model$/', '', lcfirst($str));
+ }
+
+ public function getMarkerJsData()
+ {
+ return json_encode($this, JSON_PRETTY_PRINT);
+ }
+
+ /**
+ * Check if all necessary data is set in this marker class
+ * @return boolean
+ */
+ public function checkMarkerData()
+ {
+ return true
+ && isset($this->id)
+ && isset($this->lat)
+ && isset($this->lon)
+ && isset($this->icon)
+ ;
+ }
+
+}
diff --git a/src/Models/ChunkModels/InteractiveMap/CacheMarkerModel.php b/src/Models/ChunkModels/InteractiveMap/CacheMarkerModel.php
new file mode 100644
index 0000000000..0d653c9ce9
--- /dev/null
+++ b/src/Models/ChunkModels/InteractiveMap/CacheMarkerModel.php
@@ -0,0 +1,129 @@
+importDataFromGeoCache( $c, $user);
+ return $marker;
+ }
+
+ protected function importDataFromGeoCache(GeoCache $c, User $user=null)
+ {
+ // Abstract-Marker data
+ $this->id = $c->getCacheId();
+ $this->icon = $c->getCacheIcon($user);
+ $this->lat = $c->getCoordinates()->getLatitude();
+ $this->lon = $c->getCoordinates()->getLongitude();
+
+ $this->wp = $c->getGeocacheWaypointId();
+ $this->link = $c->getCacheUrl();
+ $this->name = $c->getCacheName();
+ $this->username = $c->getOwner()->getUserName();
+ $this->userProfile = $c->getOwner()->getProfileUrl();
+
+ $this->isEvent= $c->isEvent();
+ if ($this->isEvent) {
+ $this->eventStartDate = Formatter::date($c->getDatePlaced());
+ }
+ $this->size = tr($c->getSizeTranslationKey());
+ $this->ratingVotes = $c->getRatingVotes();
+ $this->rating = (
+ $this->ratingVotes < 3
+ ? tr('not_available')
+ : $c->getRatingDesc()
+ );
+ $this->ratingId = $c->getRatingId();
+ $this->founds = $c->getFounds();
+ $this->notFounds = $c->getNotFounds();
+ $this->recommendations = $c->getRecommendations();
+ $this->isTitled = $c->isTitled();
+ if ($c->isTitled() ) {
+ global $titled_cache_period_prefix; //TODO: move it to the ocConfig
+ $this->titledDesc = tr($titled_cache_period_prefix.'_titled_cache');
+ }
+ $this->isStandingOut = ($this->titledDesc || $this->recommendations);
+ if ($c->isPowerTrailPart()) {
+ $this->powerTrailName = $c->getPowerTrail()->getName();
+ $this->powerTrailIcon = $c->getPowerTrail()->getFootIcon();
+ $this->powerTrailUrl = $c->getPowerTrail()->getPowerTrailUrl();
+ }
+
+ $this->cacheType = $c->getCacheType();
+ $this->cacheStatus = $c->getStatus();
+ $this->logStatus = $c->getLogStatus($user);
+ $this->isOwner =
+ ($user != null && $user->getUserId() == $c->getOwner()->getUserId());
+ }
+
+ /**
+ * Check if all necessary data is set in this marker class
+ * @return boolean
+ */
+ public function checkMarkerData()
+ {
+ return parent::checkMarkerData()
+ && isset($this->wp)
+ && isset($this->link)
+ && isset($this->name)
+ && isset($this->username)
+ && isset($this->userProfile)
+ && isset($this->isEvent)
+ && isset($this->size)
+ && isset($this->founds)
+ && isset($this->notFounds)
+ && isset($this->ratingVotes)
+ && isset($this->ratingId)
+ && isset($this->recommendations)
+ && isset($this->cacheType)
+ && isset($this->cacheStatus)
+ && isset($this->isOwner)
+ ;
+ }
+
+}
diff --git a/src/Models/ChunkModels/InteractiveMap/InteractiveMapModel.php b/src/Models/ChunkModels/InteractiveMap/InteractiveMapModel.php
new file mode 100644
index 0000000000..bc9d9e891a
--- /dev/null
+++ b/src/Models/ChunkModels/InteractiveMap/InteractiveMapModel.php
@@ -0,0 +1,259 @@
+ translation key) for sections used in
+ * markerModels
+ */
+ private $sectionsKeys = [];
+
+ public function __construct()
+ {
+
+ $this->ocConfig = OcConfig::instance();
+
+ $this->coords = OcConfig::getMapDefaultCenter();
+
+ $this->zoom = OcConfig::getStartPageMapZoom();
+ $this->forceZoom = false;
+ $this->startExtent = false;
+ $this->mapLayerName = 'OSM';
+ }
+
+ /**
+ * Add markers of one type
+ *
+ * @param string $markerClass - class returned by Extractor by 'CacheSetMarkerModel::class'
+ * @param array $dataRows - rows of data - every row describes one marker
+ * @param callable $rowExtractor - function which can create marekrClass based on given row
+ */
+ public function addMarkersWithExtractor(
+ $markerClass, array $dataRows, callable $rowExtractor
+ ) {
+ foreach ($dataRows as $row) {
+
+ $markerModel = call_user_func($rowExtractor, $row);
+
+ if (!($markerModel instanceof $markerClass)) {
+ Debug::errorLog(
+ "Extractor returns something different than $markerClass"
+ );
+ return;
+ }
+
+ if (!is_subclass_of($markerModel, AbstractMarkerModelBase::class)) {
+ Debug::errorLog(
+ "Marker class $markerClass is not a child of "
+ . AbstractMarkerModelBase::class
+ );
+ return;
+ }
+
+ $this->addMarker($markerModel);
+ } // foreach
+ }
+
+ /**
+ * Add one marker to internal base of markers
+ *
+ * @param AbstractMarkerModelBase $model
+ */
+ public function addMarker(AbstractMarkerModelBase $model)
+ {
+ $type = $model->getMarkerTypeName();
+
+ if (!$model->checkMarkerData()) {
+ $type = $model->getMarkerTypeName();
+ Debug::errorLog("Marker of $type has incomplete data!");
+ }
+ $section = (
+ isset($model->section) ? $model->section : self::DEFAULT_SECTION
+ );
+ if (!isset($this->markerModels[$section][$type])) {
+ $this->markerModels[$section][$type] = [];
+ }
+ $this->markerModels[$section][$type][] = $model;
+ }
+
+ /**
+ * Read OC map config from config and return map config JS
+ */
+ public static function getMapLayersJsConfig(){
+ return OcConfig::getMapJsConfig();
+ }
+
+ public function getMarkersDataJson(){
+ return json_encode($this->markerModels, JSON_PRETTY_PRINT);
+ }
+
+ public function getMarkerSections(){
+ return array_keys($this->markerModels);
+ }
+
+ public function getMarkerTypes($section = null) {
+ $result = [];
+ if ($section != null) {
+ $result =
+ isset($this->markerModels[$section])
+ ? array_keys($this->markerModels[$section])
+ : [];
+ } else {
+ foreach($this->markerModels as $s) {
+ foreach($s as $markerType => $markers) {
+ if (!in_array($markerType, $result)) {
+ $result[] = $markerType;
+ }
+ }
+ }
+ /*
+ // an alternative way but seems to be too complicated:
+ array_walk($this->markerModels, function($v) use (&$result) {
+ $result = array_merge($result, array_keys($v));
+ });
+ $result = array_values(array_unique($result));
+ */
+ }
+ return $result;
+ }
+
+ /**
+ * @return Coordinates
+ */
+ public function getCoords(){
+ return $this->coords;
+ }
+
+ public function getZoom(){
+ return $this->zoom;
+ }
+
+ public function isZoomForced()
+ {
+ return $this->forceZoom;
+ }
+
+ public function getSelectedLayerName(){
+ return $this->mapLayerName;
+ }
+
+ public function setZoom($zoom)
+ {
+ $this->zoom = $zoom;
+ $this->forceZoom = true;
+ }
+
+ public function setInitLayerName($name){
+ $this->mapLayerName = $name;
+ }
+
+ public function forceDefaultZoom()
+ {
+ $this->forceZoom = true;
+ }
+
+ public function setCoords(Coordinates $cords)
+ {
+ $this->coords = $cords;
+ }
+
+ public function setStartExtent(Coordinates $swCorner, Coordinates $neCorner)
+ {
+ $this->swCorner = $swCorner;
+ $this->neCorner = $neCorner;
+ $this->startExtent = true;
+ }
+
+ public function getStartExtentJson()
+ {
+ if($this->startExtent){
+ $sw = $this->swCorner->getAsOpenLayersFormat();
+ $ne = $this->neCorner->getAsOpenLayersFormat();
+ return "{ sw:$sw, ne:$ne }";
+ }else{
+ return "null";
+ }
+ }
+
+ public function setInfoMessage($msg)
+ {
+ $this->infoMessage = $msg;
+ }
+
+ public function getInfoMessage()
+ {
+ return $this->infoMessage;
+ }
+
+ /**
+ * Since it is pre-configured, only a getter is available now
+ */
+ public function getMarkersFamily()
+ {
+ return OcConfig::getMapMarkersFamily();
+ }
+
+ public function setSectionProperties($section, $properties)
+ {
+ $this->sectionsProperties[$section] = $properties;
+ }
+
+ public function getSectionsPropertiesJson()
+ {
+ return json_encode($this->sectionsProperties, JSON_PRETTY_PRINT);
+ }
+
+ public function setSectionsKeys($sectionsKeys)
+ {
+ $this->sectionsKeys = $sectionsKeys;
+ }
+
+ public function getSectionsKeys()
+ {
+ return $this->sectionsKeys;
+ }
+}
diff --git a/src/Models/ChunkModels/InteractiveMap/LogMarkerModel.php b/src/Models/ChunkModels/InteractiveMap/LogMarkerModel.php
new file mode 100644
index 0000000000..ceafe44ee3
--- /dev/null
+++ b/src/Models/ChunkModels/InteractiveMap/LogMarkerModel.php
@@ -0,0 +1,71 @@
+importDataFromGeoCacheLog($log, $user);
+ return $marker;
+ }
+
+ protected function importDataFromGeoCacheLog(
+ GeoCacheLog $log, User $user = null
+ ) {
+ parent::importDataFromGeoCache($log->getGeoCache(), $user);
+
+ $this->id = $log->getId();
+ $this->logLink = $log->getLogUrl();
+ $text = strip_tags($log->getText(),'
');
+ $textLen = mb_strlen($text);
+ if ($textLen > 200) {
+ $text = mb_strcut($text, 0, 200);
+ // do not leave open tags on truncate
+ $text = preg_replace('/\<[^\>]*$/', '', $text);
+ $text .= '...';
+ }
+ $this->logText = $text;
+ $this->logIcon = $log->getLogIcon();
+ $this->logType = $log->getType();
+ $this->logTypeName = tr(
+ GeoCacheLog::typeTranslationKey($log->getType())
+ );
+ $this->logUserName = $log->getUser()->getUserName();
+ $this->logDate = Formatter::date($log->getDateCreated());
+ }
+
+ /**
+ * Check if all necessary data is set in this marker class
+ * @return boolean
+ */
+ public function checkMarkerData()
+ {
+ return parent::checkMarkerData()
+ && isset($this->logLink)
+ && isset($this->logText)
+ && isset($this->logIcon)
+ && isset($this->logType)
+ && isset($this->logTypeName)
+ && isset($this->logUserName)
+ && isset($this->logDate)
+ ;
+ }
+}
diff --git a/src/Models/GeoCache/GeoCache.php b/src/Models/GeoCache/GeoCache.php
index 764eada862..20067d17ab 100644
--- a/src/Models/GeoCache/GeoCache.php
+++ b/src/Models/GeoCache/GeoCache.php
@@ -704,6 +704,41 @@ public function getRatingDesc()
return tr(self::CacheRatingTranslationKey($this->ratingId));
}
+ /**
+ * Computes the cache current log status for given user, based on the user
+ * log entries.
+ *
+ * @param \lib\Objects\User\User $forUser a user to compute current log
+ * status for, may be null
+ *
+ * @return int current log status
+ */
+ public function getLogStatus(User $forUser=null)
+ {
+ $logStatus = null;
+ if (!is_null($forUser)) {
+ $logsCount = $this->getLogsCountByType(
+ $forUser,
+ array(
+ GeoCacheLog::LOGTYPE_FOUNDIT,
+ GeoCacheLog::LOGTYPE_DIDNOTFIND
+ )
+ );
+ if (
+ isset($logsCount[GeoCacheLog::LOGTYPE_FOUNDIT])
+ && $logsCount[GeoCacheLog::LOGTYPE_FOUNDIT]>0
+ ) {
+ $logStatus = GeoCacheLog::LOGTYPE_FOUNDIT;
+ } else if (
+ isset($logsCount[GeoCacheLog::LOGTYPE_DIDNOTFIND])
+ && $logsCount[GeoCacheLog::LOGTYPE_DIDNOTFIND]>0
+ ) {
+ $logStatus = GeoCacheLog::LOGTYPE_DIDNOTFIND;
+ }
+ }
+ return $logStatus;
+ }
+
public function getCacheIcon(User $forUser=null)
{
$logStatus = null;
diff --git a/src/Models/GeoCache/GeoCacheCommons.php b/src/Models/GeoCache/GeoCacheCommons.php
index 462c811d17..8b08309fe9 100644
--- a/src/Models/GeoCache/GeoCacheCommons.php
+++ b/src/Models/GeoCache/GeoCacheCommons.php
@@ -4,6 +4,8 @@
use src\Models\BaseObject;
use src\Utils\Debug\Debug;
+use \ReflectionClass;
+
/**
* Common consts etc. for geocaches
*
@@ -467,4 +469,26 @@ public static function GetCacheUrlByWp($ocWaypoint)
{
return '/viewcache.php?wp=' . $ocWaypoint;
}
+
+ /**
+ * Returns a JSON structure containing a (constant_name, constant_value)
+ * pairs for all defined geocache statuses
+ *
+ * @return string JSON structure, ready for use in javascript f.ex.
+ */
+ public static function CacheStatusListJson()
+ {
+ $result = '{';
+ $gccClass = new ReflectionClass(__CLASS__);
+ foreach ($gccClass->getConstants() as $name => $value) {
+ if (preg_match('/^STATUS\_/', $name) === 1 && is_numeric($value)) {
+ if (strlen($result) > 1) {
+ $result .= ',';
+ }
+ $result .= '"' . $name . '":"' . $value . '"';
+ }
+ }
+ $result .= '}';
+ return $result;
+ }
}
diff --git a/src/Models/GeoCache/GeoCacheLogCommons.php b/src/Models/GeoCache/GeoCacheLogCommons.php
index bf5b80837d..f4e08f8dc2 100644
--- a/src/Models/GeoCache/GeoCacheLogCommons.php
+++ b/src/Models/GeoCache/GeoCacheLogCommons.php
@@ -4,6 +4,8 @@
use src\Utils\Debug\Debug;
use src\Models\BaseObject;
+use \ReflectionClass;
+
/**
* Common consts etc. for geocache log
*/
@@ -235,4 +237,26 @@ public static function getLogTypeTplKeys(
}
return $result;
}
+
+ /**
+ * Returns a JSON structure containing a (constant_name, constant_value)
+ * pairs for all defined log types
+ *
+ * @return string JSON structure, ready for use in javascript f.ex.
+ */
+ public static function LogTypeListJson()
+ {
+ $result = '{';
+ $gccClass = new ReflectionClass(__CLASS__);
+ foreach ($gccClass->getConstants() as $name => $value) {
+ if (preg_match('/^LOGTYPE\_/', $name) === 1 && is_numeric($value)) {
+ if (strlen($result) > 1) {
+ $result .= ',';
+ }
+ $result .= '"' . $name . '":"' . $value . '"';
+ }
+ }
+ $result .= '}';
+ return $result;
+ }
}
diff --git a/src/Models/Neighbourhood/Neighbourhood.php b/src/Models/Neighbourhood/Neighbourhood.php
index c7a1af7a45..3450eff33d 100644
--- a/src/Models/Neighbourhood/Neighbourhood.php
+++ b/src/Models/Neighbourhood/Neighbourhood.php
@@ -16,6 +16,17 @@ class Neighbourhood extends BaseObject
const ITEM_TITLEDCACHES = 6;
const ITEM_RECOMMENDEDCACHES = 7;
+ // An array of Neighbourhood sections with corresponding translation keys
+ const SECTIONS = [
+ self::ITEM_MAP => 'map',
+ self::ITEM_LATESTCACHES => 'newest_caches',
+ self::ITEM_UPCOMINGEVENTS => 'incomming_events',
+ self::ITEM_FTFCACHES => 'ftf_awaiting',
+ self::ITEM_LATESTLOGS => 'latest_logs',
+ self::ITEM_TITLEDCACHES => 'startPage_latestTitledCaches',
+ self::ITEM_RECOMMENDEDCACHES => 'top_recommended'
+ ];
+
/**
* Id in DB
*
diff --git a/src/Models/OcConfig/MapConfigTrait.php b/src/Models/OcConfig/MapConfigTrait.php
index ec3e251ee8..6b07e65dc8 100644
--- a/src/Models/OcConfig/MapConfigTrait.php
+++ b/src/Models/OcConfig/MapConfigTrait.php
@@ -90,6 +90,12 @@ public static function getMapExternalUrls()
}
return $result;
}
+
+ public static function getMapMarkersFamily()
+ {
+ return self::getMapVar('markersFamily');
+ }
+
/**
* Returns map properties
*
diff --git a/src/Views/chunks/interactiveMap/interactiveMap.tpl.php b/src/Views/chunks/interactiveMap/interactiveMap.tpl.php
new file mode 100644
index 0000000000..32c49c2551
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/interactiveMap.tpl.php
@@ -0,0 +1,100 @@
+view->addHeaderChunk('openLayers5');
+ *
+ */
+return function (InteractiveMapModel $mapModel, $canvasId)
+{
+ $publicSrcPath = '/views/chunks/interactiveMap/';
+
+ // load chunk CSS
+ View::callChunkInline('loadCssByJs',
+ Uri::getLinkWithModificationTime(
+ $publicSrcPath . 'interactiveMap.css'
+ )
+ );
+ View::callChunkInline('handlebarsJs');
+?>
+
+
+
+
+getMarkerTypes(), true);
+ $markerTypes["highlightedMarker"] = false;
+ foreach ($markerTypes as $markerType => $loadTpl) {
+ if (!$markerLibsLoaded) {
+ $markerLibsLoaded = true;
+ foreach ($markerLibs as $lib) {
+?>
+
+getMarkersFamily()
+ . '/'. $markerType . '.js'
+ );
+?>
+
+
+
+
+
+
+
+
+
+{
+ markerFactory: function(map, type, id, ocData, section){
+ return createOCMarkerFeature(
+ type, id, ocData, new CacheMarker(map, ocData), section
+ );
+ },
+
+}
diff --git a/src/Views/chunks/interactiveMap/markers/cacheMarkerPopup.tpl.php b/src/Views/chunks/interactiveMap/markers/cacheMarkerPopup.tpl.php
new file mode 100644
index 0000000000..7e5593392f
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/markers/cacheMarkerPopup.tpl.php
@@ -0,0 +1,101 @@
+
+
+
+ {{#if sectionName}}
+
+ {{/if}}
+
+
+
+

+
+
+
+
+
+
+
+ {{#if isEvent}}
+ =tr("beginning")?>: {{eventStartDate}}
+ {{else}}
+ =tr("size")?>: {{size}}
+ {{/if}}
+
+
+ {{#if isEvent}}
+

"> x {{founds}} =tr("attendends")?>
+ {{else}}
+

x {{founds}} =tr('found')?>
+ {{/if}}
+
+
+
+
+ {{#if rating}}=tr('score')?>: {{rating}}{{/if}}
+
+
+ {{#if isEvent}}
+

"> x {{notFounds}} =tr("will_attend")?>
+ {{else}}
+

x {{notFounds}} =tr('not_found')?>
+ {{/if}}
+
+
+
+
+
+

"> {{ratingVotes}} x =tr("scored")?>
+
+
+ {{#if isStandingOut}}
+
+
+ {{#if titledDesc}}
+
{{titledDesc}}
+ {{/if}}
+
+
+ {{#if recommendations}}
+

"> {{recommendations}} x =tr("recommended")?>
+ {{/if}}
+
+
+ {{/if}}
+
+ {{#if powerTrailName}}
+
+
+
+ =tr("pt000")?>:
+
+
+
+
+ {{/if}}
+
+
+{{#if showNavi}}
+
+
+

+
+
+

+
+
+{{/if}}
diff --git a/src/Views/chunks/interactiveMap/markers/cacheSetMarkerMgr.tpl.php b/src/Views/chunks/interactiveMap/markers/cacheSetMarkerMgr.tpl.php
new file mode 100644
index 0000000000..f91c64fcca
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/markers/cacheSetMarkerMgr.tpl.php
@@ -0,0 +1,37 @@
+
+{
+ markerFactory: function(map, type, id, ocData, section) {
+ if (typeof section === "undefined") {
+ section = "_DEFAULT_";
+ }
+ var iconFeature = new ol.Feature({
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(ocData.lon), parseFloat(ocData.lat)])),
+ ocData: {
+ markerSection: section,
+ markerType: type,
+ markerId: id
+ }
+ });
+ feature.setId(section + '_' + type + '_' + ocData.id);
+ iconFeature.setStyle(new ol.style.Style({
+ image: new ol.style.Icon( {
+ anchorOrigin: 'bottom-left',
+ anchor: [0.5, 0],
+ anchorXUnits: 'fraction',
+ anchorYUnits: 'pixels',
+ src: ocData.icon,
+ })
+ }));
+ return iconFeature;
+ },
+}
diff --git a/src/Views/chunks/interactiveMap/markers/cacheWithLogMarkerMgr.tpl.php b/src/Views/chunks/interactiveMap/markers/cacheWithLogMarkerMgr.tpl.php
new file mode 100644
index 0000000000..e5ed818d95
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/markers/cacheWithLogMarkerMgr.tpl.php
@@ -0,0 +1,37 @@
+
+{
+ markerFactory: function(map, type, id, ocData) {
+ if (typeof section === "undefined") {
+ section = "_DEFAULT_";
+ }
+ var iconFeature = new ol.Feature({
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(ocData.lon), parseFloat(ocData.lat)])),
+ ocData: {
+ markerSection: section,
+ markerType: type,
+ markerId: id
+ }
+ });
+ feature.setId(section + '_' + type + '_' + ocData.id);
+ iconFeature.setStyle(new ol.style.Style({
+ image: new ol.style.Icon( {
+ anchor: [0.5, 0.5],
+ anchorXUnits: 'fraction',
+ anchorYUnits: 'fraction',
+ src: ocData.icon,
+ scale: 0.5,
+ })
+ }));
+ return iconFeature;
+ },
+}
diff --git a/src/Views/chunks/interactiveMap/markers/guideMarkerMgr.tpl.php b/src/Views/chunks/interactiveMap/markers/guideMarkerMgr.tpl.php
new file mode 100644
index 0000000000..3ca72b6e83
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/markers/guideMarkerMgr.tpl.php
@@ -0,0 +1,38 @@
+
+{
+ markerFactory: function(map, type, id, ocData, section) {
+ if (typeof section === "undefined") {
+ section = "_DEFAULT_";
+ }
+ var iconFeature = new ol.Feature({
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([parseFloat(ocData.lon), parseFloat(ocData.lat)])),
+ ocData: {
+ markerSection: section,
+ markerType: type,
+ markerId: id
+ }
+ });
+ feature.setId(section + '_' + type + '_' + ocData.id);
+ iconFeature.setStyle(new ol.style.Style({
+ image: new ol.style.Icon({
+ anchorOrigin: "bottom-left",
+ anchor: [8, 0],
+ anchorXUnits: 'pixel',
+ anchorYUnits: 'pixel',
+ src: ocData.icon,
+ scale: 1,
+ })
+ }));
+ return iconFeature;
+ },
+}
diff --git a/src/Views/chunks/interactiveMap/markers/guideMarkerPopup.tpl.php b/src/Views/chunks/interactiveMap/markers/guideMarkerPopup.tpl.php
new file mode 100644
index 0000000000..f35008e82c
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/markers/guideMarkerPopup.tpl.php
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+

+
+
+
+
+
+
+

+
+
+ {{recCount}} =tr('guides_recommendations')?>
+
+
+
+
+

+
+
+
+
+
+
+{{#if showNavi}}
+
+
+

+
+
+

+
+
+{{/if}}
diff --git a/src/Views/chunks/interactiveMap/markers/logMarkerMgr.tpl.php b/src/Views/chunks/interactiveMap/markers/logMarkerMgr.tpl.php
new file mode 100644
index 0000000000..aee676173c
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/markers/logMarkerMgr.tpl.php
@@ -0,0 +1,18 @@
+
+{
+ markerFactory: function(map, type, id, ocData, section){
+ return createOCMarkerFeature(
+ type, id, ocData, new LogMarker(map, ocData), section
+ );
+ },
+}
diff --git a/src/Views/chunks/interactiveMap/markers/logMarkerPopup.tpl.php b/src/Views/chunks/interactiveMap/markers/logMarkerPopup.tpl.php
new file mode 100644
index 0000000000..04ccf29d85
--- /dev/null
+++ b/src/Views/chunks/interactiveMap/markers/logMarkerPopup.tpl.php
@@ -0,0 +1,48 @@
+
+
+
+ {{#if sectionName}}
+
+ {{/if}}
+
+
+
+

+
+
+
{{name}}
+ {{#if username}}({{username}}){{/if}}
+
+
+ {{#if logLink}}
+
+
+

+
+
+
+ {{/if}}
+
+
+
+{{#if showNavi}}
+
+
+

+
+
+

+
+
+{{/if}}
diff --git a/src/Views/myNbhInteractive/config.tpl.php b/src/Views/myNbhInteractive/config.tpl.php
new file mode 100644
index 0000000000..52578c6e01
--- /dev/null
+++ b/src/Views/myNbhInteractive/config.tpl.php
@@ -0,0 +1,167 @@
+
+
+ =$view->callChunk('infoBar', null, $view->infoMsg, $view->errorMsg)?>
+
+
+coordsOK == 0) {
+ if ($view->selectedNbh == 0) { ?>
+
=tr('myn_intro')?>
+
+
=tr('myn_map_info1')?>
+selectedNbh == 0) { ?>
+
=tr('myn_name_default')?>
+
+
=tr('myn_name_addition')?>
+
+
=tr('myn_map_info2')?>
+
+ callChunk('interactiveMap/interactiveMap', $view->mapModel, "nbhmapmain");?>
+
+
+
=tr('myn_map_drawbtn')?>
+
+
+ |
+ km
+
+
+
+
+
+
+
+
+
diff --git a/src/Views/myNbhInteractive/detail_FTFCaches.tpl.php b/src/Views/myNbhInteractive/detail_FTFCaches.tpl.php
new file mode 100644
index 0000000000..fb0bc2ef72
--- /dev/null
+++ b/src/Views/myNbhInteractive/detail_FTFCaches.tpl.php
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+ =tr('cache')?> |
+ =tr('date_hidden_label')?> |
+
+
+
+ caches as $cache) { ?>
+
+
+
+  ?>)
+
+
+ =$cache->getCacheName() ?>
+ isPowerTrailPart()) { ?>
+ ->getFootIcon()?>)
+
+ =tr('hidden_by')?>| =$cache->getOwner()->getUserName()?>
+
+
+
+ =tr($cache->getSizeTranslationKey())?> |
+ =round(Gis::distanceBetween($view->coords, $cache->getCoordinates()))?> km
+ 
+
+ |
+
+ =Formatter::date($cache->getDatePlaced())?>
+ |
+
+
+
+
+ callChunkInline('pagination', $view->paginationModel);?>
+
+
=tr('myn_distances')?>
+
diff --git a/src/Views/myNbhInteractive/detail_LatestCaches.tpl.php b/src/Views/myNbhInteractive/detail_LatestCaches.tpl.php
new file mode 100644
index 0000000000..c65a3d0506
--- /dev/null
+++ b/src/Views/myNbhInteractive/detail_LatestCaches.tpl.php
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+ =tr('cache')?> |
+ =tr('date_hidden_label')?> |
+ =tr('new_logs_myn')?> |
+
+
+
+ caches as $cache) { ?>
+
+
+
+  ?>)
+
+
+ =$cache->getCacheName() ?>
+ isPowerTrailPart()) { ?>
+ ->getFootIcon()?>)
+
+ =tr('hidden_by')?>| =$cache->getOwner()->getUserName()?>
+
+
+
+ =tr($cache->getSizeTranslationKey())?> |
+ =round(Gis::distanceBetween($view->coords, $cache->getCoordinates()))?> km
+ 
+ getRecommendations() > 0) { ?>
+ | 
+ (=$cache->getRecommendations()?>)
+
+
+ |
+
+ =Formatter::date($cache->getDatePlaced())?>
+ |
+ loadLogs($cache, false, 0, 1);
+ if (! empty($log)) { ?>
+
+
+ ![<?=tr(GeoCacheLog::typeTranslationKey($log[0]->getType()))?>](<?=GeoCacheLog::GetIconForType($log[0]->getType())?>)
+ =Formatter::date($log[0]->getDate())?>
+ =$log[0]->getUser()->getUserName()?>
+
+ =mb_substr(strip_tags($log[0]->getText()), 0, 35)?>=(mb_strlen(strip_tags($log[0]->getText())) > 35 ? '...' : '')?>
+
+ =$log[0]->getText()?>
+ |
+
+ |
+
+
+
+
+
+ callChunkInline('pagination', $view->paginationModel); ?>
+
+
=tr('myn_distances')?>
+
diff --git a/src/Views/myNbhInteractive/detail_LatestLogs.tpl.php b/src/Views/myNbhInteractive/detail_LatestLogs.tpl.php
new file mode 100644
index 0000000000..8ce1da1f24
--- /dev/null
+++ b/src/Views/myNbhInteractive/detail_LatestLogs.tpl.php
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+ =tr('cache')?> |
+ =tr('myn_log_txt')?> |
+
+
+
+ logs as $log) { ?>
+
+
+
+ ->getCacheIcon($view->user) ?>)
+
+
+ |
+
+
+ =UserInputFilter::purifyHtmlString($log->getText())?>
+ |
+
+
+
+
+ callChunkInline('pagination', $view->paginationModel);?>
+
+
=tr('myn_distances')?>
+
diff --git a/src/Views/myNbhInteractive/detail_RecommendedCaches.tpl.php b/src/Views/myNbhInteractive/detail_RecommendedCaches.tpl.php
new file mode 100644
index 0000000000..8e16b6e164
--- /dev/null
+++ b/src/Views/myNbhInteractive/detail_RecommendedCaches.tpl.php
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+ =tr('cache')?> |
+ =tr('date_hidden_label')?> |
+ =tr('new_logs_myn')?> |
+
+
+
+ caches as $cache) { ?>
+
+
+
+  ?>)
+
+
+ =$cache->getCacheName() ?>
+ isPowerTrailPart()) { ?>
+ ->getFootIcon()?>)
+
+ =tr('hidden_by')?>| =$cache->getOwner()->getUserName()?>
+
+
+
+ =tr($cache->getSizeTranslationKey())?> |
+ =round(Gis::distanceBetween($view->coords, $cache->getCoordinates()))?> km
+ 
+ getRecommendations() > 0) { ?>
+ | 
+ (=$cache->getRecommendations()?>)
+
+
+ |
+
+ =Formatter::date($cache->getDatePlaced())?>
+ |
+ loadLogs($cache, false, 0, 1);
+ if (! empty($log)) { ?>
+
+
+ ![<?=tr(GeoCacheLog::typeTranslationKey($log[0]->getType()))?>](<?=GeoCacheLog::GetIconForType($log[0]->getType())?>)
+ =Formatter::date($log[0]->getDate())?>
+ =$log[0]->getUser()->getUserName()?>
+
+ =mb_substr(strip_tags($log[0]->getText()), 0, 35)?>=(mb_strlen(strip_tags($log[0]->getText())) > 35 ? '...' : '')?>
+
+ =$log[0]->getText()?>
+ |
+
+ |
+
+
+
+
+
+ callChunkInline('pagination', $view->paginationModel);?>
+
+
=tr('myn_distances')?>
+
diff --git a/src/Views/myNbhInteractive/detail_TitledCaches.tpl.php b/src/Views/myNbhInteractive/detail_TitledCaches.tpl.php
new file mode 100644
index 0000000000..fae4536240
--- /dev/null
+++ b/src/Views/myNbhInteractive/detail_TitledCaches.tpl.php
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+ =tr('cache')?> |
+ =tr('date_hidden_label')?> |
+ =tr('myn_titleddate')?> |
+ =tr('new_logs_myn')?> |
+
+
+
+ caches as $cache) { ?>
+
+
+
+  ?>)
+
+
+ =$cache->getCacheName() ?>
+ isPowerTrailPart()) { ?>
+ ->getFootIcon()?>)
+
+ =tr('hidden_by')?>| =$cache->getOwner()->getUserName()?>
+
+
+
+ =tr($cache->getSizeTranslationKey())?> |
+ =round(Gis::distanceBetween($view->coords, $cache->getCoordinates()))?> km
+ 
+ getRecommendations() > 0) { ?>
+ | 
+ (=$cache->getRecommendations()?>)
+
+
+ |
+
+ =Formatter::date($cache->getDatePlaced())?>
+ |
+
+ getCacheId());
+ echo Formatter::date($cacheTitled->getTitledDate());
+ unset($cacheTitled);
+ ?>
+ |
+ loadLogs($cache, false, 0, 1);
+ if (! empty($log)) { ?>
+
+
+ ![<?=tr(GeoCacheLog::typeTranslationKey($log[0]->getType()))?>](<?=GeoCacheLog::GetIconForType($log[0]->getType())?>)
+ =Formatter::date($log[0]->getDate())?>
+ =$log[0]->getUser()->getUserName()?>
+
+ =mb_substr(strip_tags($log[0]->getText()), 0, 20)?>=(mb_strlen(strip_tags($log[0]->getText())) > 20 ? '...' : '')?>
+
+ =$log[0]->getText()?>
+ |
+
+ |
+
+
+
+
+
+ callChunkInline('pagination', $view->paginationModel);?>
+
+
=tr('myn_distances')?>
+
diff --git a/src/Views/myNbhInteractive/detail_UpcommingEvents.tpl.php b/src/Views/myNbhInteractive/detail_UpcommingEvents.tpl.php
new file mode 100644
index 0000000000..b3cc48960a
--- /dev/null
+++ b/src/Views/myNbhInteractive/detail_UpcommingEvents.tpl.php
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+ =tr('cache')?> |
+ =tr('myn_event_organizer')?> |
+ =tr('date_event_label')?> |
+ =tr('new_logs_myn')?> |
+
+
+
+ caches as $cache) { ?>
+
+
+
+  ?>)
+
+
+ =$cache->getCacheName() ?>
+ =round(Gis::distanceBetween($view->coords, $cache->getCoordinates()))?> km
+ 
+ |  =$cache->getNotFounds()?>
+
+ |
+
+ =$cache->getOwner()->getUserName()?>
+ |
+
+ =Formatter::date($cache->getDatePlaced())?>
+ |
+ loadLogs($cache, false, 0, 1);
+ if (! empty($log)) { ?>
+
+
+ ![<?=tr(GeoCacheLog::typeTranslationKey($log[0]->getType()))?>](<?=GeoCacheLog::GetIconForType($log[0]->getType())?>)
+ =Formatter::date($log[0]->getDate())?>
+ =$log[0]->getUser()->getUserName()?>
+
+ =mb_substr(strip_tags($log[0]->getText()), 0, 35)?>=(mb_strlen(strip_tags($log[0]->getText())) > 35 ? '...' : '')?>
+
+ =$log[0]->getText()?>
+ |
+
+ |
+
+
+
+
+
+ callChunkInline('pagination', $view->paginationModel); ?>
+
+
=tr('myn_distances')?>
+
diff --git a/src/Views/myNbhInteractive/myNeighbourhood.tpl.php b/src/Views/myNbhInteractive/myNeighbourhood.tpl.php
new file mode 100644
index 0000000000..58b707256e
--- /dev/null
+++ b/src/Views/myNbhInteractive/myNeighbourhood.tpl.php
@@ -0,0 +1,82 @@
+
+
+ neighbourhoodsList as $nbh) {
+ if ($nbh->getSeq() == $view->selectedNbh) {
+ $btnClassMod = 'btn-primary';
+ } else {
+ $btnClassMod = 'btn-default';
+ }
+ ?>
+
=$nbh->getName()?>
+
+
=tr('config')?>
+
+
+ preferences['items'] as $key => $item) {
+ $order[$item['order']] = $item;
+ $order[$item['order']]['item'] = $key;
+ }
+ ksort($order);
+ foreach ($order as $item) {
+ $classSize = ($item['fullsize'] == 1) ? 'nbh-full' : 'nbh-half';
+ switch ($item['item']) {
+ case Neighbourhood::ITEM_MAP:
+ $subTemplate = '/' . $view->templatesPath . 'sub_Map';
+ break;
+ case Neighbourhood::ITEM_LATESTCACHES:
+ $subTemplate = '/' . $view->templatesPath . 'sub_LatestCaches';
+ break;
+ case Neighbourhood::ITEM_UPCOMINGEVENTS:
+ $subTemplate = '/' . $view->templatesPath . 'sub_UpcommingEvents';
+ break;
+ case Neighbourhood::ITEM_FTFCACHES:
+ $subTemplate = '/' . $view->templatesPath . 'sub_FTFCaches';
+ break;
+ case Neighbourhood::ITEM_LATESTLOGS:
+ $subTemplate = '/' . $view->templatesPath . 'sub_LatestLogs';
+ break;
+ case Neighbourhood::ITEM_TITLEDCACHES:
+ $subTemplate = '/' . $view->templatesPath . 'sub_TitledCaches';
+ break;
+ case Neighbourhood::ITEM_RECOMMENDEDCACHES:
+ $subTemplate = '/' . $view->templatesPath . 'sub_RecommendedCaches';
+ break;
+ default:
+ break;
+ }
+ ?>
+
+ =$view->callSubTpl($subTemplate)?>
+
+
+
+ neighbourhoodsList[$view->selectedNbh]->getCoords()->getLatitudeParts(Coordinates::COORDINATES_FORMAT_DEG_MIN);
+ list($lonEW, $lon_h, $lon_min) = $view->neighbourhoodsList[$view->selectedNbh]->getCoords()->getLongitudeParts(Coordinates::COORDINATES_FORMAT_DEG_MIN);
+ ?>
+
+
+
+
=tr('myn_dragdrop')?>
+
=tr('myn_distances')?>
+
+
diff --git a/src/Views/myNbhInteractive/sub_FTFCaches.tpl.php b/src/Views/myNbhInteractive/sub_FTFCaches.tpl.php
new file mode 100644
index 0000000000..9a551d1df6
--- /dev/null
+++ b/src/Views/myNbhInteractive/sub_FTFCaches.tpl.php
@@ -0,0 +1,46 @@
+
+
+
+
+
+FTFCaches)) { ?>
+
=tr('list_of_caches_is_empty')?>
+FTFCaches as $cache) {?>
+
+ FTFCaches) == $view->preferences['style']['caches-count']) { ?>
+
=tr('more')?>
+
+
diff --git a/src/Views/myNbhInteractive/sub_LatestCaches.tpl.php b/src/Views/myNbhInteractive/sub_LatestCaches.tpl.php
new file mode 100644
index 0000000000..4adcc30110
--- /dev/null
+++ b/src/Views/myNbhInteractive/sub_LatestCaches.tpl.php
@@ -0,0 +1,52 @@
+
+
+
+
+
+latestCaches)) { ?>
+
=tr('list_of_caches_is_empty')?>
+latestCaches as $cache) {?>
+
+ latestCaches) == $view->preferences['style']['caches-count']) { ?>
+
=tr('more')?>
+
+
diff --git a/src/Views/myNbhInteractive/sub_LatestLogs.tpl.php b/src/Views/myNbhInteractive/sub_LatestLogs.tpl.php
new file mode 100644
index 0000000000..48c485262a
--- /dev/null
+++ b/src/Views/myNbhInteractive/sub_LatestLogs.tpl.php
@@ -0,0 +1,54 @@
+
+
+
+
+
+latestLogs)) { ?>
+
=tr('list_of_latest_logs_is_empty')?>
+latestLogs as $log) {?>
+
+
+
+
?>)
+
+
+
+
=UserInputFilter::purifyHtmlString($log->getText())?>
+
+ latestLogs) == $view->preferences['style']['caches-count']) { ?>
+
=tr('more')?>
+
+
diff --git a/src/Views/myNbhInteractive/sub_Map.tpl.php b/src/Views/myNbhInteractive/sub_Map.tpl.php
new file mode 100644
index 0000000000..2861b40861
--- /dev/null
+++ b/src/Views/myNbhInteractive/sub_Map.tpl.php
@@ -0,0 +1,14 @@
+
+
+
+
+callChunk('interactiveMap/interactiveMap', $view->mapModel, "nbhmap");?>
diff --git a/src/Views/myNbhInteractive/sub_RecommendedCaches.tpl.php b/src/Views/myNbhInteractive/sub_RecommendedCaches.tpl.php
new file mode 100644
index 0000000000..8bb48d9fb6
--- /dev/null
+++ b/src/Views/myNbhInteractive/sub_RecommendedCaches.tpl.php
@@ -0,0 +1,48 @@
+
+
+
+
+
+topRatedCaches)) { ?>
+
=tr('list_of_caches_is_empty')?>
+topRatedCaches as $cache) {?>
+
+ topRatedCaches) == $view->preferences['style']['caches-count']) { ?>
+
=tr('more')?>
+
+
diff --git a/src/Views/myNbhInteractive/sub_TitledCaches.tpl.php b/src/Views/myNbhInteractive/sub_TitledCaches.tpl.php
new file mode 100644
index 0000000000..be4bb78d7c
--- /dev/null
+++ b/src/Views/myNbhInteractive/sub_TitledCaches.tpl.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+latestTitled)) { ?>
+
=tr('list_of_caches_is_empty')?>
+
+ latestTitled as $cache) {
+ $cacheTitled = CacheTitled::fromCacheIdFactory($cache->getCacheId());
+ ?>
+
+ latestTitled) == $view->preferences['style']['caches-count']) { ?>
+
=tr('more')?>
+
+
diff --git a/src/Views/myNbhInteractive/sub_UpcommingEvents.tpl.php b/src/Views/myNbhInteractive/sub_UpcommingEvents.tpl.php
new file mode 100644
index 0000000000..1396ebd8f3
--- /dev/null
+++ b/src/Views/myNbhInteractive/sub_UpcommingEvents.tpl.php
@@ -0,0 +1,45 @@
+
+
+
+
+
+upcomingEvents)) { ?>
+
=tr('list_of_events_is_empty')?>
+upcomingEvents as $cache) {?>
+
+ upcomingEvents) == $view->preferences['style']['caches-count']) { ?>
+
+
+
From 7ce34c3d5ec90d35ead2cf9c0d2d9141ae051bcd Mon Sep 17 00:00:00 2001
From: rapotek <17698165+rapotek@users.noreply.github.com>
Date: Mon, 20 Jul 2020 14:59:09 +0200
Subject: [PATCH 02/17] Interactive Map with OKAPI-based style icons:
validation ready
---
lib/languages/en.php | 3 +
.../images/map_markers/background_layer.png | Bin 0 -> 699 bytes
.../map_markers/okapi/cache/large_event.png | Bin 0 -> 1095 bytes
.../okapi/cache/large_event_archived.png | Bin 0 -> 1516 bytes
.../cache/large_event_archived_found.png | Bin 0 -> 1533 bytes
.../large_event_archived_found_caption.png | Bin 0 -> 1569 bytes
.../okapi/cache/large_event_archived_new.png | Bin 0 -> 2063 bytes
.../okapi/cache/large_event_archived_own.png | Bin 0 -> 1940 bytes
.../okapi/cache/large_event_excellent.png | Bin 0 -> 1660 bytes
.../cache/large_event_excellent_found.png | Bin 0 -> 1830 bytes
.../large_event_excellent_found_caption.png | Bin 0 -> 1851 bytes
.../okapi/cache/large_event_excellent_new.png | Bin 0 -> 2212 bytes
.../okapi/cache/large_event_excellent_own.png | Bin 0 -> 2081 bytes
.../large_event_excellent_recommended.png | Bin 0 -> 2199 bytes
...arge_event_excellent_recommended_found.png | Bin 0 -> 2215 bytes
...nt_excellent_recommended_found_caption.png | Bin 0 -> 2200 bytes
.../large_event_excellent_recommended_new.png | Bin 0 -> 2705 bytes
.../large_event_excellent_recommended_own.png | Bin 0 -> 2581 bytes
.../okapi/cache/large_event_found.png | Bin 0 -> 1396 bytes
.../okapi/cache/large_event_found_caption.png | Bin 0 -> 1431 bytes
.../okapi/cache/large_event_new.png | Bin 0 -> 1663 bytes
.../okapi/cache/large_event_own.png | Bin 0 -> 1529 bytes
.../okapi/cache/large_event_unavailable.png | Bin 0 -> 1523 bytes
.../cache/large_event_unavailable_found.png | Bin 0 -> 1528 bytes
.../large_event_unavailable_found_caption.png | Bin 0 -> 1564 bytes
.../cache/large_event_unavailable_new.png | Bin 0 -> 2070 bytes
.../cache/large_event_unavailable_own.png | Bin 0 -> 1947 bytes
.../map_markers/okapi/cache/large_moving.png | Bin 0 -> 1090 bytes
.../okapi/cache/large_moving_archived.png | Bin 0 -> 1515 bytes
.../cache/large_moving_archived_found.png | Bin 0 -> 1513 bytes
.../large_moving_archived_found_caption.png | Bin 0 -> 1548 bytes
.../okapi/cache/large_moving_archived_new.png | Bin 0 -> 2060 bytes
.../okapi/cache/large_moving_archived_own.png | Bin 0 -> 1940 bytes
.../okapi/cache/large_moving_excellent.png | Bin 0 -> 1676 bytes
.../cache/large_moving_excellent_found.png | Bin 0 -> 1828 bytes
.../large_moving_excellent_found_caption.png | Bin 0 -> 1835 bytes
.../cache/large_moving_excellent_new.png | Bin 0 -> 2222 bytes
.../cache/large_moving_excellent_own.png | Bin 0 -> 2100 bytes
.../large_moving_excellent_recommended.png | Bin 0 -> 2215 bytes
...rge_moving_excellent_recommended_found.png | Bin 0 -> 2207 bytes
...ng_excellent_recommended_found_caption.png | Bin 0 -> 2187 bytes
...large_moving_excellent_recommended_new.png | Bin 0 -> 2710 bytes
...large_moving_excellent_recommended_own.png | Bin 0 -> 2594 bytes
.../okapi/cache/large_moving_found.png | Bin 0 -> 1380 bytes
.../cache/large_moving_found_caption.png | Bin 0 -> 1407 bytes
.../okapi/cache/large_moving_new.png | Bin 0 -> 1660 bytes
.../okapi/cache/large_moving_own.png | Bin 0 -> 1533 bytes
.../okapi/cache/large_moving_unavailable.png | Bin 0 -> 1528 bytes
.../cache/large_moving_unavailable_found.png | Bin 0 -> 1508 bytes
...large_moving_unavailable_found_caption.png | Bin 0 -> 1543 bytes
.../cache/large_moving_unavailable_new.png | Bin 0 -> 2067 bytes
.../cache/large_moving_unavailable_own.png | Bin 0 -> 1948 bytes
.../map_markers/okapi/cache/large_multi.png | Bin 0 -> 1065 bytes
.../okapi/cache/large_multi_archived.png | Bin 0 -> 1510 bytes
.../cache/large_multi_archived_found.png | Bin 0 -> 1551 bytes
.../large_multi_archived_found_caption.png | Bin 0 -> 1594 bytes
.../okapi/cache/large_multi_archived_new.png | Bin 0 -> 2063 bytes
.../okapi/cache/large_multi_archived_own.png | Bin 0 -> 1921 bytes
.../okapi/cache/large_multi_excellent.png | Bin 0 -> 1633 bytes
.../cache/large_multi_excellent_found.png | Bin 0 -> 1832 bytes
.../large_multi_excellent_found_caption.png | Bin 0 -> 1865 bytes
.../okapi/cache/large_multi_excellent_new.png | Bin 0 -> 2190 bytes
.../okapi/cache/large_multi_excellent_own.png | Bin 0 -> 2066 bytes
.../large_multi_excellent_recommended.png | Bin 0 -> 2175 bytes
...arge_multi_excellent_recommended_found.png | Bin 0 -> 2222 bytes
...ti_excellent_recommended_found_caption.png | Bin 0 -> 2207 bytes
.../large_multi_excellent_recommended_new.png | Bin 0 -> 2686 bytes
.../large_multi_excellent_recommended_own.png | Bin 0 -> 2555 bytes
.../okapi/cache/large_multi_found.png | Bin 0 -> 1414 bytes
.../okapi/cache/large_multi_found_caption.png | Bin 0 -> 1459 bytes
.../okapi/cache/large_multi_new.png | Bin 0 -> 1642 bytes
.../okapi/cache/large_multi_own.png | Bin 0 -> 1496 bytes
.../okapi/cache/large_multi_unavailable.png | Bin 0 -> 1517 bytes
.../cache/large_multi_unavailable_found.png | Bin 0 -> 1545 bytes
.../large_multi_unavailable_found_caption.png | Bin 0 -> 1590 bytes
.../cache/large_multi_unavailable_new.png | Bin 0 -> 2053 bytes
.../cache/large_multi_unavailable_own.png | Bin 0 -> 1934 bytes
.../map_markers/okapi/cache/large_other.png | Bin 0 -> 1001 bytes
.../okapi/cache/large_other_archived.png | Bin 0 -> 1444 bytes
.../cache/large_other_archived_found.png | Bin 0 -> 1501 bytes
.../large_other_archived_found_caption.png | Bin 0 -> 1530 bytes
.../okapi/cache/large_other_archived_new.png | Bin 0 -> 1995 bytes
.../okapi/cache/large_other_archived_own.png | Bin 0 -> 1876 bytes
.../okapi/cache/large_other_excellent.png | Bin 0 -> 1576 bytes
.../cache/large_other_excellent_found.png | Bin 0 -> 1807 bytes
.../large_other_excellent_found_caption.png | Bin 0 -> 1822 bytes
.../okapi/cache/large_other_excellent_new.png | Bin 0 -> 2137 bytes
.../okapi/cache/large_other_excellent_own.png | Bin 0 -> 2011 bytes
.../large_other_excellent_recommended.png | Bin 0 -> 2121 bytes
...arge_other_excellent_recommended_found.png | Bin 0 -> 2192 bytes
...er_excellent_recommended_found_caption.png | Bin 0 -> 2170 bytes
.../large_other_excellent_recommended_new.png | Bin 0 -> 2623 bytes
.../large_other_excellent_recommended_own.png | Bin 0 -> 2506 bytes
.../okapi/cache/large_other_found.png | Bin 0 -> 1360 bytes
.../okapi/cache/large_other_found_caption.png | Bin 0 -> 1390 bytes
.../okapi/cache/large_other_new.png | Bin 0 -> 1573 bytes
.../okapi/cache/large_other_own.png | Bin 0 -> 1438 bytes
.../okapi/cache/large_other_unavailable.png | Bin 0 -> 1457 bytes
.../cache/large_other_unavailable_found.png | Bin 0 -> 1495 bytes
.../large_other_unavailable_found_caption.png | Bin 0 -> 1526 bytes
.../cache/large_other_unavailable_new.png | Bin 0 -> 2000 bytes
.../cache/large_other_unavailable_own.png | Bin 0 -> 1884 bytes
.../map_markers/okapi/cache/large_own.png | Bin 0 -> 1063 bytes
.../okapi/cache/large_own_archived.png | Bin 0 -> 1471 bytes
.../okapi/cache/large_own_archived_found.png | Bin 0 -> 1484 bytes
.../large_own_archived_found_caption.png | Bin 0 -> 1534 bytes
.../okapi/cache/large_own_archived_new.png | Bin 0 -> 2016 bytes
.../okapi/cache/large_own_archived_own.png | Bin 0 -> 1897 bytes
.../okapi/cache/large_own_excellent.png | Bin 0 -> 1646 bytes
.../okapi/cache/large_own_excellent_found.png | Bin 0 -> 1793 bytes
.../large_own_excellent_found_caption.png | Bin 0 -> 1816 bytes
.../okapi/cache/large_own_excellent_new.png | Bin 0 -> 2195 bytes
.../okapi/cache/large_own_excellent_own.png | Bin 0 -> 2065 bytes
.../cache/large_own_excellent_recommended.png | Bin 0 -> 2177 bytes
.../large_own_excellent_recommended_found.png | Bin 0 -> 2183 bytes
...wn_excellent_recommended_found_caption.png | Bin 0 -> 2174 bytes
.../large_own_excellent_recommended_new.png | Bin 0 -> 2685 bytes
.../large_own_excellent_recommended_own.png | Bin 0 -> 2560 bytes
.../okapi/cache/large_own_found.png | Bin 0 -> 1349 bytes
.../okapi/cache/large_own_found_caption.png | Bin 0 -> 1396 bytes
.../map_markers/okapi/cache/large_own_new.png | Bin 0 -> 1633 bytes
.../map_markers/okapi/cache/large_own_own.png | Bin 0 -> 1498 bytes
.../okapi/cache/large_own_unavailable.png | Bin 0 -> 1477 bytes
.../cache/large_own_unavailable_found.png | Bin 0 -> 1482 bytes
.../large_own_unavailable_found_caption.png | Bin 0 -> 1529 bytes
.../okapi/cache/large_own_unavailable_new.png | Bin 0 -> 2023 bytes
.../okapi/cache/large_own_unavailable_own.png | Bin 0 -> 1903 bytes
.../map_markers/okapi/cache/large_quiz.png | Bin 0 -> 1199 bytes
.../okapi/cache/large_quiz_archived.png | Bin 0 -> 1601 bytes
.../okapi/cache/large_quiz_archived_found.png | Bin 0 -> 1586 bytes
.../large_quiz_archived_found_caption.png | Bin 0 -> 1628 bytes
.../okapi/cache/large_quiz_archived_new.png | Bin 0 -> 2122 bytes
.../okapi/cache/large_quiz_archived_own.png | Bin 0 -> 2004 bytes
.../okapi/cache/large_quiz_excellent.png | Bin 0 -> 1751 bytes
.../cache/large_quiz_excellent_found.png | Bin 0 -> 1883 bytes
.../large_quiz_excellent_found_caption.png | Bin 0 -> 1907 bytes
.../okapi/cache/large_quiz_excellent_new.png | Bin 0 -> 2288 bytes
.../okapi/cache/large_quiz_excellent_own.png | Bin 0 -> 2173 bytes
.../large_quiz_excellent_recommended.png | Bin 0 -> 2285 bytes
...large_quiz_excellent_recommended_found.png | Bin 0 -> 2272 bytes
...iz_excellent_recommended_found_caption.png | Bin 0 -> 2256 bytes
.../large_quiz_excellent_recommended_new.png | Bin 0 -> 2775 bytes
.../large_quiz_excellent_recommended_own.png | Bin 0 -> 2665 bytes
.../okapi/cache/large_quiz_found.png | Bin 0 -> 1456 bytes
.../okapi/cache/large_quiz_found_caption.png | Bin 0 -> 1503 bytes
.../okapi/cache/large_quiz_new.png | Bin 0 -> 1752 bytes
.../okapi/cache/large_quiz_own.png | Bin 0 -> 1628 bytes
.../okapi/cache/large_quiz_unavailable.png | Bin 0 -> 1605 bytes
.../cache/large_quiz_unavailable_found.png | Bin 0 -> 1583 bytes
.../large_quiz_unavailable_found_caption.png | Bin 0 -> 1624 bytes
.../cache/large_quiz_unavailable_new.png | Bin 0 -> 2124 bytes
.../cache/large_quiz_unavailable_own.png | Bin 0 -> 2009 bytes
.../okapi/cache/large_traditional.png | Bin 0 -> 1100 bytes
.../cache/large_traditional_archived.png | Bin 0 -> 1519 bytes
.../large_traditional_archived_found.png | Bin 0 -> 1516 bytes
...rge_traditional_archived_found_caption.png | Bin 0 -> 1567 bytes
.../cache/large_traditional_archived_new.png | Bin 0 -> 2055 bytes
.../cache/large_traditional_archived_own.png | Bin 0 -> 1938 bytes
.../cache/large_traditional_excellent.png | Bin 0 -> 1668 bytes
.../large_traditional_excellent_found.png | Bin 0 -> 1837 bytes
...ge_traditional_excellent_found_caption.png | Bin 0 -> 1854 bytes
.../cache/large_traditional_excellent_new.png | Bin 0 -> 2220 bytes
.../cache/large_traditional_excellent_own.png | Bin 0 -> 2099 bytes
...arge_traditional_excellent_recommended.png | Bin 0 -> 2205 bytes
...raditional_excellent_recommended_found.png | Bin 0 -> 2219 bytes
...al_excellent_recommended_found_caption.png | Bin 0 -> 2201 bytes
..._traditional_excellent_recommended_new.png | Bin 0 -> 2712 bytes
..._traditional_excellent_recommended_own.png | Bin 0 -> 2593 bytes
.../okapi/cache/large_traditional_found.png | Bin 0 -> 1397 bytes
.../cache/large_traditional_found_caption.png | Bin 0 -> 1435 bytes
.../okapi/cache/large_traditional_new.png | Bin 0 -> 1667 bytes
.../okapi/cache/large_traditional_own.png | Bin 0 -> 1537 bytes
.../cache/large_traditional_unavailable.png | Bin 0 -> 1518 bytes
.../large_traditional_unavailable_found.png | Bin 0 -> 1520 bytes
..._traditional_unavailable_found_caption.png | Bin 0 -> 1563 bytes
.../large_traditional_unavailable_new.png | Bin 0 -> 2061 bytes
.../large_traditional_unavailable_own.png | Bin 0 -> 1940 bytes
.../map_markers/okapi/cache/large_unknown.png | Bin 0 -> 1122 bytes
.../okapi/cache/large_unknown_archived.png | Bin 0 -> 1547 bytes
.../cache/large_unknown_archived_found.png | Bin 0 -> 1555 bytes
.../large_unknown_archived_found_caption.png | Bin 0 -> 1591 bytes
.../cache/large_unknown_archived_new.png | Bin 0 -> 2085 bytes
.../cache/large_unknown_archived_own.png | Bin 0 -> 1968 bytes
.../okapi/cache/large_unknown_excellent.png | Bin 0 -> 1691 bytes
.../cache/large_unknown_excellent_found.png | Bin 0 -> 1848 bytes
.../large_unknown_excellent_found_caption.png | Bin 0 -> 1861 bytes
.../cache/large_unknown_excellent_new.png | Bin 0 -> 2239 bytes
.../cache/large_unknown_excellent_own.png | Bin 0 -> 2114 bytes
.../large_unknown_excellent_recommended.png | Bin 0 -> 2228 bytes
...ge_unknown_excellent_recommended_found.png | Bin 0 -> 2239 bytes
...wn_excellent_recommended_found_caption.png | Bin 0 -> 2215 bytes
...arge_unknown_excellent_recommended_new.png | Bin 0 -> 2739 bytes
...arge_unknown_excellent_recommended_own.png | Bin 0 -> 2614 bytes
.../okapi/cache/large_unknown_found.png | Bin 0 -> 1430 bytes
.../cache/large_unknown_found_caption.png | Bin 0 -> 1456 bytes
.../okapi/cache/large_unknown_new.png | Bin 0 -> 1698 bytes
.../okapi/cache/large_unknown_own.png | Bin 0 -> 1563 bytes
.../okapi/cache/large_unknown_unavailable.png | Bin 0 -> 1551 bytes
.../cache/large_unknown_unavailable_found.png | Bin 0 -> 1551 bytes
...arge_unknown_unavailable_found_caption.png | Bin 0 -> 1591 bytes
.../cache/large_unknown_unavailable_new.png | Bin 0 -> 2092 bytes
.../cache/large_unknown_unavailable_own.png | Bin 0 -> 1972 bytes
.../map_markers/okapi/cache/large_virtual.png | Bin 0 -> 1202 bytes
.../okapi/cache/large_virtual_archived.png | Bin 0 -> 1600 bytes
.../cache/large_virtual_archived_found.png | Bin 0 -> 1617 bytes
.../large_virtual_archived_found_caption.png | Bin 0 -> 1656 bytes
.../cache/large_virtual_archived_new.png | Bin 0 -> 2137 bytes
.../cache/large_virtual_archived_own.png | Bin 0 -> 2024 bytes
.../okapi/cache/large_virtual_excellent.png | Bin 0 -> 1757 bytes
.../cache/large_virtual_excellent_found.png | Bin 0 -> 1916 bytes
.../large_virtual_excellent_found_caption.png | Bin 0 -> 1928 bytes
.../cache/large_virtual_excellent_new.png | Bin 0 -> 2300 bytes
.../cache/large_virtual_excellent_own.png | Bin 0 -> 2184 bytes
.../large_virtual_excellent_recommended.png | Bin 0 -> 2288 bytes
...ge_virtual_excellent_recommended_found.png | Bin 0 -> 2298 bytes
...al_excellent_recommended_found_caption.png | Bin 0 -> 2276 bytes
...arge_virtual_excellent_recommended_new.png | Bin 0 -> 2787 bytes
...arge_virtual_excellent_recommended_own.png | Bin 0 -> 2667 bytes
.../okapi/cache/large_virtual_found.png | Bin 0 -> 1498 bytes
.../cache/large_virtual_found_caption.png | Bin 0 -> 1527 bytes
.../okapi/cache/large_virtual_new.png | Bin 0 -> 1764 bytes
.../okapi/cache/large_virtual_own.png | Bin 0 -> 1641 bytes
.../okapi/cache/large_virtual_unavailable.png | Bin 0 -> 1611 bytes
.../cache/large_virtual_unavailable_found.png | Bin 0 -> 1611 bytes
...arge_virtual_unavailable_found_caption.png | Bin 0 -> 1651 bytes
.../cache/large_virtual_unavailable_new.png | Bin 0 -> 2139 bytes
.../cache/large_virtual_unavailable_own.png | Bin 0 -> 2026 bytes
.../map_markers/okapi/cache/large_webcam.png | Bin 0 -> 1133 bytes
.../okapi/cache/large_webcam_archived.png | Bin 0 -> 1561 bytes
.../cache/large_webcam_archived_found.png | Bin 0 -> 1545 bytes
.../large_webcam_archived_found_caption.png | Bin 0 -> 1592 bytes
.../okapi/cache/large_webcam_archived_new.png | Bin 0 -> 2097 bytes
.../okapi/cache/large_webcam_archived_own.png | Bin 0 -> 1979 bytes
.../okapi/cache/large_webcam_excellent.png | Bin 0 -> 1708 bytes
.../cache/large_webcam_excellent_found.png | Bin 0 -> 1850 bytes
.../large_webcam_excellent_found_caption.png | Bin 0 -> 1884 bytes
.../cache/large_webcam_excellent_new.png | Bin 0 -> 2248 bytes
.../cache/large_webcam_excellent_own.png | Bin 0 -> 2129 bytes
.../large_webcam_excellent_recommended.png | Bin 0 -> 2244 bytes
...rge_webcam_excellent_recommended_found.png | Bin 0 -> 2241 bytes
...am_excellent_recommended_found_caption.png | Bin 0 -> 2232 bytes
...large_webcam_excellent_recommended_new.png | Bin 0 -> 2747 bytes
...large_webcam_excellent_recommended_own.png | Bin 0 -> 2623 bytes
.../okapi/cache/large_webcam_found.png | Bin 0 -> 1413 bytes
.../cache/large_webcam_found_caption.png | Bin 0 -> 1457 bytes
.../okapi/cache/large_webcam_new.png | Bin 0 -> 1698 bytes
.../okapi/cache/large_webcam_own.png | Bin 0 -> 1573 bytes
.../okapi/cache/large_webcam_unavailable.png | Bin 0 -> 1564 bytes
.../cache/large_webcam_unavailable_found.png | Bin 0 -> 1537 bytes
...large_webcam_unavailable_found_caption.png | Bin 0 -> 1588 bytes
.../cache/large_webcam_unavailable_new.png | Bin 0 -> 2101 bytes
.../cache/large_webcam_unavailable_own.png | Bin 0 -> 1985 bytes
.../okapi/cache/medium_archived.png | Bin 0 -> 689 bytes
.../okapi/cache/medium_archived_found.png | Bin 0 -> 838 bytes
.../okapi/cache/medium_archived_new.png | Bin 0 -> 771 bytes
.../okapi/cache/medium_archived_own.png | Bin 0 -> 755 bytes
.../map_markers/okapi/cache/medium_event.png | Bin 0 -> 362 bytes
.../okapi/cache/medium_event_excellent.png | Bin 0 -> 504 bytes
.../cache/medium_event_excellent_found.png | Bin 0 -> 858 bytes
.../cache/medium_event_excellent_new.png | Bin 0 -> 560 bytes
.../cache/medium_event_excellent_own.png | Bin 0 -> 524 bytes
.../medium_event_excellent_recommended.png | Bin 0 -> 651 bytes
...dium_event_excellent_recommended_found.png | Bin 0 -> 896 bytes
...medium_event_excellent_recommended_new.png | Bin 0 -> 669 bytes
...medium_event_excellent_recommended_own.png | Bin 0 -> 649 bytes
.../okapi/cache/medium_event_found.png | Bin 0 -> 788 bytes
.../okapi/cache/medium_event_new.png | Bin 0 -> 434 bytes
.../okapi/cache/medium_event_own.png | Bin 0 -> 391 bytes
.../map_markers/okapi/cache/medium_moving.png | Bin 0 -> 358 bytes
.../okapi/cache/medium_moving_excellent.png | Bin 0 -> 499 bytes
.../cache/medium_moving_excellent_found.png | Bin 0 -> 858 bytes
.../cache/medium_moving_excellent_new.png | Bin 0 -> 555 bytes
.../cache/medium_moving_excellent_own.png | Bin 0 -> 522 bytes
.../medium_moving_excellent_recommended.png | Bin 0 -> 651 bytes
...ium_moving_excellent_recommended_found.png | Bin 0 -> 896 bytes
...edium_moving_excellent_recommended_new.png | Bin 0 -> 670 bytes
...edium_moving_excellent_recommended_own.png | Bin 0 -> 654 bytes
.../okapi/cache/medium_moving_found.png | Bin 0 -> 775 bytes
.../okapi/cache/medium_moving_new.png | Bin 0 -> 430 bytes
.../okapi/cache/medium_moving_own.png | Bin 0 -> 391 bytes
.../map_markers/okapi/cache/medium_multi.png | Bin 0 -> 363 bytes
.../okapi/cache/medium_multi_excellent.png | Bin 0 -> 509 bytes
.../cache/medium_multi_excellent_found.png | Bin 0 -> 857 bytes
.../cache/medium_multi_excellent_new.png | Bin 0 -> 566 bytes
.../cache/medium_multi_excellent_own.png | Bin 0 -> 533 bytes
.../medium_multi_excellent_recommended.png | Bin 0 -> 657 bytes
...dium_multi_excellent_recommended_found.png | Bin 0 -> 899 bytes
...medium_multi_excellent_recommended_new.png | Bin 0 -> 683 bytes
...medium_multi_excellent_recommended_own.png | Bin 0 -> 659 bytes
.../okapi/cache/medium_multi_found.png | Bin 0 -> 778 bytes
.../okapi/cache/medium_multi_new.png | Bin 0 -> 434 bytes
.../okapi/cache/medium_multi_own.png | Bin 0 -> 391 bytes
.../map_markers/okapi/cache/medium_other.png | Bin 0 -> 358 bytes
.../okapi/cache/medium_other_excellent.png | Bin 0 -> 499 bytes
.../cache/medium_other_excellent_found.png | Bin 0 -> 858 bytes
.../cache/medium_other_excellent_new.png | Bin 0 -> 555 bytes
.../cache/medium_other_excellent_own.png | Bin 0 -> 522 bytes
.../medium_other_excellent_recommended.png | Bin 0 -> 651 bytes
...dium_other_excellent_recommended_found.png | Bin 0 -> 896 bytes
...medium_other_excellent_recommended_new.png | Bin 0 -> 670 bytes
...medium_other_excellent_recommended_own.png | Bin 0 -> 654 bytes
.../okapi/cache/medium_other_found.png | Bin 0 -> 775 bytes
.../okapi/cache/medium_other_new.png | Bin 0 -> 430 bytes
.../okapi/cache/medium_other_own.png | Bin 0 -> 391 bytes
.../map_markers/okapi/cache/medium_own.png | Bin 0 -> 358 bytes
.../okapi/cache/medium_own_excellent.png | Bin 0 -> 499 bytes
.../cache/medium_own_excellent_found.png | Bin 0 -> 858 bytes
.../okapi/cache/medium_own_excellent_new.png | Bin 0 -> 555 bytes
.../okapi/cache/medium_own_excellent_own.png | Bin 0 -> 522 bytes
.../medium_own_excellent_recommended.png | Bin 0 -> 651 bytes
...medium_own_excellent_recommended_found.png | Bin 0 -> 896 bytes
.../medium_own_excellent_recommended_new.png | Bin 0 -> 670 bytes
.../medium_own_excellent_recommended_own.png | Bin 0 -> 654 bytes
.../okapi/cache/medium_own_found.png | Bin 0 -> 775 bytes
.../okapi/cache/medium_own_new.png | Bin 0 -> 430 bytes
.../okapi/cache/medium_own_own.png | Bin 0 -> 391 bytes
.../map_markers/okapi/cache/medium_quiz.png | Bin 0 -> 369 bytes
.../okapi/cache/medium_quiz_excellent.png | Bin 0 -> 508 bytes
.../cache/medium_quiz_excellent_found.png | Bin 0 -> 860 bytes
.../okapi/cache/medium_quiz_excellent_new.png | Bin 0 -> 565 bytes
.../okapi/cache/medium_quiz_excellent_own.png | Bin 0 -> 531 bytes
.../medium_quiz_excellent_recommended.png | Bin 0 -> 650 bytes
...edium_quiz_excellent_recommended_found.png | Bin 0 -> 899 bytes
.../medium_quiz_excellent_recommended_new.png | Bin 0 -> 679 bytes
.../medium_quiz_excellent_recommended_own.png | Bin 0 -> 656 bytes
.../okapi/cache/medium_quiz_found.png | Bin 0 -> 786 bytes
.../okapi/cache/medium_quiz_new.png | Bin 0 -> 438 bytes
.../okapi/cache/medium_quiz_own.png | Bin 0 -> 397 bytes
.../okapi/cache/medium_traditional.png | Bin 0 -> 374 bytes
.../cache/medium_traditional_excellent.png | Bin 0 -> 505 bytes
.../medium_traditional_excellent_found.png | Bin 0 -> 853 bytes
.../medium_traditional_excellent_new.png | Bin 0 -> 562 bytes
.../medium_traditional_excellent_own.png | Bin 0 -> 519 bytes
...dium_traditional_excellent_recommended.png | Bin 0 -> 659 bytes
...raditional_excellent_recommended_found.png | Bin 0 -> 891 bytes
..._traditional_excellent_recommended_new.png | Bin 0 -> 673 bytes
..._traditional_excellent_recommended_own.png | Bin 0 -> 651 bytes
.../okapi/cache/medium_traditional_found.png | Bin 0 -> 779 bytes
.../okapi/cache/medium_traditional_new.png | Bin 0 -> 439 bytes
.../okapi/cache/medium_traditional_own.png | Bin 0 -> 396 bytes
.../okapi/cache/medium_unavailable.png | Bin 0 -> 696 bytes
.../okapi/cache/medium_unavailable_found.png | Bin 0 -> 839 bytes
.../okapi/cache/medium_unavailable_new.png | Bin 0 -> 776 bytes
.../okapi/cache/medium_unavailable_own.png | Bin 0 -> 758 bytes
.../okapi/cache/medium_unknown.png | Bin 0 -> 352 bytes
.../okapi/cache/medium_unknown_excellent.png | Bin 0 -> 499 bytes
.../cache/medium_unknown_excellent_found.png | Bin 0 -> 857 bytes
.../cache/medium_unknown_excellent_new.png | Bin 0 -> 551 bytes
.../cache/medium_unknown_excellent_own.png | Bin 0 -> 521 bytes
.../medium_unknown_excellent_recommended.png | Bin 0 -> 648 bytes
...um_unknown_excellent_recommended_found.png | Bin 0 -> 888 bytes
...dium_unknown_excellent_recommended_new.png | Bin 0 -> 670 bytes
...dium_unknown_excellent_recommended_own.png | Bin 0 -> 654 bytes
.../okapi/cache/medium_unknown_found.png | Bin 0 -> 781 bytes
.../okapi/cache/medium_unknown_new.png | Bin 0 -> 426 bytes
.../okapi/cache/medium_unknown_own.png | Bin 0 -> 386 bytes
.../okapi/cache/medium_virtual.png | Bin 0 -> 362 bytes
.../okapi/cache/medium_virtual_excellent.png | Bin 0 -> 501 bytes
.../cache/medium_virtual_excellent_found.png | Bin 0 -> 858 bytes
.../cache/medium_virtual_excellent_new.png | Bin 0 -> 555 bytes
.../cache/medium_virtual_excellent_own.png | Bin 0 -> 520 bytes
.../medium_virtual_excellent_recommended.png | Bin 0 -> 650 bytes
...um_virtual_excellent_recommended_found.png | Bin 0 -> 898 bytes
...dium_virtual_excellent_recommended_new.png | Bin 0 -> 671 bytes
...dium_virtual_excellent_recommended_own.png | Bin 0 -> 647 bytes
.../okapi/cache/medium_virtual_found.png | Bin 0 -> 783 bytes
.../okapi/cache/medium_virtual_new.png | Bin 0 -> 431 bytes
.../okapi/cache/medium_virtual_own.png | Bin 0 -> 383 bytes
.../map_markers/okapi/cache/medium_webcam.png | Bin 0 -> 358 bytes
.../okapi/cache/medium_webcam_excellent.png | Bin 0 -> 499 bytes
.../cache/medium_webcam_excellent_found.png | Bin 0 -> 858 bytes
.../cache/medium_webcam_excellent_new.png | Bin 0 -> 555 bytes
.../cache/medium_webcam_excellent_own.png | Bin 0 -> 522 bytes
.../medium_webcam_excellent_recommended.png | Bin 0 -> 651 bytes
...ium_webcam_excellent_recommended_found.png | Bin 0 -> 896 bytes
...edium_webcam_excellent_recommended_new.png | Bin 0 -> 670 bytes
...edium_webcam_excellent_recommended_own.png | Bin 0 -> 654 bytes
.../okapi/cache/medium_webcam_found.png | Bin 0 -> 775 bytes
.../okapi/cache/medium_webcam_new.png | Bin 0 -> 430 bytes
.../okapi/cache/medium_webcam_own.png | Bin 0 -> 391 bytes
.../map_markers/okapi/cache/tiny_archived.png | Bin 0 -> 451 bytes
.../map_markers/okapi/cache/tiny_event.png | Bin 0 -> 205 bytes
.../map_markers/okapi/cache/tiny_moving.png | Bin 0 -> 207 bytes
.../map_markers/okapi/cache/tiny_multi.png | Bin 0 -> 210 bytes
.../map_markers/okapi/cache/tiny_other.png | Bin 0 -> 207 bytes
.../map_markers/okapi/cache/tiny_own.png | Bin 0 -> 207 bytes
.../map_markers/okapi/cache/tiny_quiz.png | Bin 0 -> 220 bytes
.../okapi/cache/tiny_traditional.png | Bin 0 -> 213 bytes
.../okapi/cache/tiny_unavailable.png | Bin 0 -> 495 bytes
.../map_markers/okapi/cache/tiny_unknown.png | Bin 0 -> 202 bytes
.../map_markers/okapi/cache/tiny_virtual.png | Bin 0 -> 207 bytes
.../map_markers/okapi/cache/tiny_webcam.png | Bin 0 -> 207 bytes
.../map_markers/okapi/highlighted_large.png | Bin 0 -> 3521 bytes
.../map_markers/okapi/highlighted_medium.png | Bin 0 -> 1293 bytes
.../map_markers/okapi/highlighted_tiny.png | Bin 0 -> 757 bytes
.../okapi/log/large_log_adminnote.png | Bin 0 -> 1280 bytes
.../okapi/log/large_log_adminnote_found.png | Bin 0 -> 1697 bytes
.../log/large_log_adminnote_found_caption.png | Bin 0 -> 1764 bytes
.../okapi/log/large_log_adminnote_new.png | Bin 0 -> 1869 bytes
.../okapi/log/large_log_adminnote_own.png | Bin 0 -> 1731 bytes
.../okapi/log/large_log_archived.png | Bin 0 -> 1274 bytes
.../okapi/log/large_log_archived_found.png | Bin 0 -> 1737 bytes
.../log/large_log_archived_found_caption.png | Bin 0 -> 1814 bytes
.../okapi/log/large_log_archived_new.png | Bin 0 -> 1858 bytes
.../okapi/log/large_log_archived_own.png | Bin 0 -> 1725 bytes
.../okapi/log/large_log_attended.png | Bin 0 -> 1319 bytes
.../okapi/log/large_log_attended_found.png | Bin 0 -> 1738 bytes
.../log/large_log_attended_found_caption.png | Bin 0 -> 1798 bytes
.../okapi/log/large_log_attended_new.png | Bin 0 -> 1904 bytes
.../okapi/log/large_log_attended_own.png | Bin 0 -> 1770 bytes
.../okapi/log/large_log_comment.png | Bin 0 -> 1258 bytes
.../okapi/log/large_log_comment_found.png | Bin 0 -> 1697 bytes
.../log/large_log_comment_found_caption.png | Bin 0 -> 1801 bytes
.../okapi/log/large_log_comment_new.png | Bin 0 -> 1850 bytes
.../okapi/log/large_log_comment_own.png | Bin 0 -> 1713 bytes
.../okapi/log/large_log_didnotfind.png | Bin 0 -> 1352 bytes
.../okapi/log/large_log_didnotfind_found.png | Bin 0 -> 1790 bytes
.../large_log_didnotfind_found_caption.png | Bin 0 -> 1860 bytes
.../okapi/log/large_log_didnotfind_new.png | Bin 0 -> 1931 bytes
.../okapi/log/large_log_didnotfind_own.png | Bin 0 -> 1801 bytes
.../okapi/log/large_log_foundit.png | Bin 0 -> 1433 bytes
.../okapi/log/large_log_foundit_found.png | Bin 0 -> 1862 bytes
.../log/large_log_foundit_found_caption.png | Bin 0 -> 1914 bytes
.../okapi/log/large_log_foundit_new.png | Bin 0 -> 2025 bytes
.../okapi/log/large_log_foundit_own.png | Bin 0 -> 1885 bytes
.../okapi/log/large_log_mademaintenance.png | Bin 0 -> 1381 bytes
.../log/large_log_mademaintenance_found.png | Bin 0 -> 1835 bytes
...arge_log_mademaintenance_found_caption.png | Bin 0 -> 1914 bytes
.../log/large_log_mademaintenance_new.png | Bin 0 -> 1967 bytes
.../log/large_log_mademaintenance_own.png | Bin 0 -> 1827 bytes
.../map_markers/okapi/log/large_log_moved.png | Bin 0 -> 1299 bytes
.../okapi/log/large_log_moved_found.png | Bin 0 -> 1753 bytes
.../log/large_log_moved_found_caption.png | Bin 0 -> 1813 bytes
.../okapi/log/large_log_moved_new.png | Bin 0 -> 1875 bytes
.../okapi/log/large_log_moved_own.png | Bin 0 -> 1741 bytes
.../okapi/log/large_log_needmaintenance.png | Bin 0 -> 1205 bytes
.../log/large_log_needmaintenance_found.png | Bin 0 -> 1610 bytes
...arge_log_needmaintenance_found_caption.png | Bin 0 -> 1694 bytes
.../log/large_log_needmaintenance_new.png | Bin 0 -> 1805 bytes
.../log/large_log_needmaintenance_own.png | Bin 0 -> 1671 bytes
.../okapi/log/large_log_readytosearch.png | Bin 0 -> 1383 bytes
.../log/large_log_readytosearch_found.png | Bin 0 -> 1809 bytes
.../large_log_readytosearch_found_caption.png | Bin 0 -> 1891 bytes
.../okapi/log/large_log_readytosearch_new.png | Bin 0 -> 1971 bytes
.../okapi/log/large_log_readytosearch_own.png | Bin 0 -> 1819 bytes
.../log/large_log_temporaryunavailable.png | Bin 0 -> 1199 bytes
.../large_log_temporaryunavailable_found.png | Bin 0 -> 1674 bytes
...log_temporaryunavailable_found_caption.png | Bin 0 -> 1750 bytes
.../large_log_temporaryunavailable_new.png | Bin 0 -> 1790 bytes
.../large_log_temporaryunavailable_own.png | Bin 0 -> 1644 bytes
.../okapi/log/large_log_willattend.png | Bin 0 -> 1310 bytes
.../okapi/log/large_log_willattend_found.png | Bin 0 -> 1754 bytes
.../large_log_willattend_found_caption.png | Bin 0 -> 1829 bytes
.../okapi/log/large_log_willattend_new.png | Bin 0 -> 1892 bytes
.../okapi/log/large_log_willattend_own.png | Bin 0 -> 1753 bytes
.../okapi/log/medium_log_adminnote.png | Bin 0 -> 790 bytes
.../okapi/log/medium_log_adminnote_found.png | Bin 0 -> 1081 bytes
.../okapi/log/medium_log_adminnote_new.png | Bin 0 -> 891 bytes
.../okapi/log/medium_log_adminnote_own.png | Bin 0 -> 894 bytes
.../okapi/log/medium_log_archived.png | Bin 0 -> 805 bytes
.../okapi/log/medium_log_archived_found.png | Bin 0 -> 1090 bytes
.../okapi/log/medium_log_archived_new.png | Bin 0 -> 913 bytes
.../okapi/log/medium_log_archived_own.png | Bin 0 -> 904 bytes
.../okapi/log/medium_log_attended.png | Bin 0 -> 795 bytes
.../okapi/log/medium_log_attended_found.png | Bin 0 -> 1082 bytes
.../okapi/log/medium_log_attended_new.png | Bin 0 -> 872 bytes
.../okapi/log/medium_log_attended_own.png | Bin 0 -> 872 bytes
.../okapi/log/medium_log_comment.png | Bin 0 -> 744 bytes
.../okapi/log/medium_log_comment_found.png | Bin 0 -> 1074 bytes
.../okapi/log/medium_log_comment_new.png | Bin 0 -> 856 bytes
.../okapi/log/medium_log_comment_own.png | Bin 0 -> 853 bytes
.../okapi/log/medium_log_didnotfind.png | Bin 0 -> 817 bytes
.../okapi/log/medium_log_didnotfind_found.png | Bin 0 -> 1091 bytes
.../okapi/log/medium_log_didnotfind_new.png | Bin 0 -> 930 bytes
.../okapi/log/medium_log_didnotfind_own.png | Bin 0 -> 927 bytes
.../okapi/log/medium_log_foundit.png | Bin 0 -> 832 bytes
.../okapi/log/medium_log_foundit_found.png | Bin 0 -> 1091 bytes
.../okapi/log/medium_log_foundit_new.png | Bin 0 -> 930 bytes
.../okapi/log/medium_log_foundit_own.png | Bin 0 -> 947 bytes
.../okapi/log/medium_log_mademaintenance.png | Bin 0 -> 821 bytes
.../log/medium_log_mademaintenance_found.png | Bin 0 -> 1093 bytes
.../log/medium_log_mademaintenance_new.png | Bin 0 -> 937 bytes
.../log/medium_log_mademaintenance_own.png | Bin 0 -> 931 bytes
.../okapi/log/medium_log_moved.png | Bin 0 -> 809 bytes
.../okapi/log/medium_log_moved_found.png | Bin 0 -> 1091 bytes
.../okapi/log/medium_log_moved_new.png | Bin 0 -> 945 bytes
.../okapi/log/medium_log_moved_own.png | Bin 0 -> 946 bytes
.../okapi/log/medium_log_needmaintenance.png | Bin 0 -> 807 bytes
.../log/medium_log_needmaintenance_found.png | Bin 0 -> 1083 bytes
.../log/medium_log_needmaintenance_new.png | Bin 0 -> 932 bytes
.../log/medium_log_needmaintenance_own.png | Bin 0 -> 926 bytes
.../okapi/log/medium_log_readytosearch.png | Bin 0 -> 762 bytes
.../log/medium_log_readytosearch_found.png | Bin 0 -> 1071 bytes
.../log/medium_log_readytosearch_new.png | Bin 0 -> 892 bytes
.../log/medium_log_readytosearch_own.png | Bin 0 -> 885 bytes
.../log/medium_log_temporaryunavailable.png | Bin 0 -> 810 bytes
.../medium_log_temporaryunavailable_found.png | Bin 0 -> 1087 bytes
.../medium_log_temporaryunavailable_new.png | Bin 0 -> 898 bytes
.../medium_log_temporaryunavailable_own.png | Bin 0 -> 899 bytes
.../okapi/log/medium_log_willattend.png | Bin 0 -> 804 bytes
.../okapi/log/medium_log_willattend_found.png | Bin 0 -> 1089 bytes
.../okapi/log/medium_log_willattend_new.png | Bin 0 -> 926 bytes
.../okapi/log/medium_log_willattend_own.png | Bin 0 -> 920 bytes
.../okapi/log/tiny_log_adminnote.png | Bin 0 -> 651 bytes
.../okapi/log/tiny_log_archived.png | Bin 0 -> 637 bytes
.../okapi/log/tiny_log_attended.png | Bin 0 -> 643 bytes
.../okapi/log/tiny_log_comment.png | Bin 0 -> 634 bytes
.../okapi/log/tiny_log_didnotfind.png | Bin 0 -> 647 bytes
.../okapi/log/tiny_log_foundit.png | Bin 0 -> 645 bytes
.../okapi/log/tiny_log_mademaintenance.png | Bin 0 -> 646 bytes
.../map_markers/okapi/log/tiny_log_moved.png | Bin 0 -> 621 bytes
.../okapi/log/tiny_log_needmaintenance.png | Bin 0 -> 622 bytes
.../okapi/log/tiny_log_readytosearch.png | Bin 0 -> 606 bytes
.../log/tiny_log_temporaryunavailable.png | Bin 0 -> 622 bytes
.../okapi/log/tiny_log_willattend.png | Bin 0 -> 620 bytes
.../chunks/interactiveMap/interactiveMap.js | 659 ++++++++++++------
.../markers/ocZoomCachedMarker.js | 113 +++
.../markers/okapi/cacheMarker.js | 207 ++++++
.../markers/okapi/highlightedMarker.js | 70 ++
.../interactiveMap/markers/okapi/logMarker.js | 105 +++
.../markers/okapi/okapiBasedMarker.css | 7 +
.../markers/okapi/okapiBasedMarker.js | 305 ++++++++
.../interactiveMap/markers/okapi/tahoma.ttf | Bin 0 -> 383140 bytes
.../MyNbhInteractiveController.php | 7 +
.../InteractiveMap/InteractiveMapModel.php | 14 +-
src/Models/OcConfig/MapConfigTrait.php | 6 -
.../UserPreferences/NeighbourhoodPref.php | 3 +-
.../interactiveMap/interactiveMap.tpl.php | 29 +-
src/Views/myNbhInteractive/config.tpl.php | 10 +
529 files changed, 1320 insertions(+), 218 deletions(-)
create mode 100644 public/images/map_markers/background_layer.png
create mode 100644 public/images/map_markers/okapi/cache/large_event.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_event_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_moving_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_multi_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_other.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_other_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_own_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_quiz_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_traditional_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_unknown_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_virtual_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_archived.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_recommended_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_own.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_unavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/large_webcam_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_archived.png
create mode 100644 public/images/map_markers/okapi/cache/medium_archived_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_archived_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_archived_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_event_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_moving_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_multi_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_other_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_own_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_quiz_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_traditional_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unavailable_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unavailable_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unavailable_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_unknown_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_virtual_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent_recommended.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent_recommended_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent_recommended_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_excellent_recommended_own.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_found.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_new.png
create mode 100644 public/images/map_markers/okapi/cache/medium_webcam_own.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_archived.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_event.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_moving.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_multi.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_other.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_own.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_quiz.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_traditional.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_unavailable.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_unknown.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_virtual.png
create mode 100644 public/images/map_markers/okapi/cache/tiny_webcam.png
create mode 100644 public/images/map_markers/okapi/highlighted_large.png
create mode 100644 public/images/map_markers/okapi/highlighted_medium.png
create mode 100644 public/images/map_markers/okapi/highlighted_tiny.png
create mode 100644 public/images/map_markers/okapi/log/large_log_adminnote.png
create mode 100644 public/images/map_markers/okapi/log/large_log_adminnote_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_adminnote_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_adminnote_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_adminnote_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_archived.png
create mode 100644 public/images/map_markers/okapi/log/large_log_archived_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_archived_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_archived_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_archived_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_attended.png
create mode 100644 public/images/map_markers/okapi/log/large_log_attended_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_attended_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_attended_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_attended_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_comment.png
create mode 100644 public/images/map_markers/okapi/log/large_log_comment_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_comment_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_comment_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_comment_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_didnotfind.png
create mode 100644 public/images/map_markers/okapi/log/large_log_didnotfind_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_didnotfind_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_didnotfind_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_didnotfind_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_foundit.png
create mode 100644 public/images/map_markers/okapi/log/large_log_foundit_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_foundit_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_foundit_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_foundit_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_mademaintenance.png
create mode 100644 public/images/map_markers/okapi/log/large_log_mademaintenance_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_mademaintenance_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_mademaintenance_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_mademaintenance_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_moved.png
create mode 100644 public/images/map_markers/okapi/log/large_log_moved_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_moved_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_moved_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_moved_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_needmaintenance.png
create mode 100644 public/images/map_markers/okapi/log/large_log_needmaintenance_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_needmaintenance_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_needmaintenance_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_needmaintenance_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_readytosearch.png
create mode 100644 public/images/map_markers/okapi/log/large_log_readytosearch_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_readytosearch_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_readytosearch_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_readytosearch_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_temporaryunavailable.png
create mode 100644 public/images/map_markers/okapi/log/large_log_temporaryunavailable_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_temporaryunavailable_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_temporaryunavailable_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_temporaryunavailable_own.png
create mode 100644 public/images/map_markers/okapi/log/large_log_willattend.png
create mode 100644 public/images/map_markers/okapi/log/large_log_willattend_found.png
create mode 100644 public/images/map_markers/okapi/log/large_log_willattend_found_caption.png
create mode 100644 public/images/map_markers/okapi/log/large_log_willattend_new.png
create mode 100644 public/images/map_markers/okapi/log/large_log_willattend_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_adminnote.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_adminnote_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_adminnote_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_adminnote_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_archived.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_archived_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_archived_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_archived_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_attended.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_attended_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_attended_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_attended_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_comment.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_comment_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_comment_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_comment_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_didnotfind.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_didnotfind_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_didnotfind_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_didnotfind_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_foundit.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_foundit_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_foundit_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_foundit_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_mademaintenance.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_mademaintenance_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_mademaintenance_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_mademaintenance_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_moved.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_moved_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_moved_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_moved_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_needmaintenance.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_needmaintenance_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_needmaintenance_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_needmaintenance_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_readytosearch.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_readytosearch_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_readytosearch_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_readytosearch_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_temporaryunavailable.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_temporaryunavailable_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_temporaryunavailable_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_temporaryunavailable_own.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_willattend.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_willattend_found.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_willattend_new.png
create mode 100644 public/images/map_markers/okapi/log/medium_log_willattend_own.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_adminnote.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_archived.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_attended.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_comment.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_didnotfind.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_foundit.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_mademaintenance.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_moved.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_needmaintenance.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_readytosearch.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_temporaryunavailable.png
create mode 100644 public/images/map_markers/okapi/log/tiny_log_willattend.png
create mode 100644 public/views/chunks/interactiveMap/markers/ocZoomCachedMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/okapi/cacheMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/okapi/highlightedMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/okapi/logMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/okapi/okapiBasedMarker.css
create mode 100644 public/views/chunks/interactiveMap/markers/okapi/okapiBasedMarker.js
create mode 100644 public/views/chunks/interactiveMap/markers/okapi/tahoma.ttf
diff --git a/lib/languages/en.php b/lib/languages/en.php
index a922a630d5..733cd59cba 100644
--- a/lib/languages/en.php
+++ b/lib/languages/en.php
@@ -631,6 +631,9 @@
'myn_addarea_info' => 'You can define more neighbourhoods that you watch',
'myn_cacheitems_lbl' => 'The number of caches and logs displayed',
'myn_style_lbl' => 'My Neighbourhood style',
+ 'myn_family_lbl' => 'A style of map icons',
+ 'myn_family_named_simple' => 'Simple',
+ 'myn_family_named_okapi' => 'Okapi',
'myn_log_txt' => 'Log content',
'myn_style_full' => 'Full',
'myn_style_min' => 'Minimalistic',
diff --git a/public/images/map_markers/background_layer.png b/public/images/map_markers/background_layer.png
new file mode 100644
index 0000000000000000000000000000000000000000..ffb0622d815bb60c6343627859d71347f195e93f
GIT binary patch
literal 699
zcmeAS@N?(olHy`uVBq!ia0y~yU<5K5893O0R7}x|G$6&6|H(?D8gCb
z5n0T@pr;JNj1^1m%NQ7#qCH(4Ln>~)ybP0l+XkKf9+uU
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event.png b/public/images/map_markers/okapi/cache/large_event.png
new file mode 100644
index 0000000000000000000000000000000000000000..2724ae1680691c5c1e7ee56d034d54446f3eee3f
GIT binary patch
literal 1095
zcmV-N1i1T&P)&UOhmF4JRJx24;-04Dh
zq>&|!Vqz$Td~g^v_uTt^=bm%V9l=NZ$M7A0F)=Z*aT*IJ5{d7D5@2}w1-iYA$KzK%
zgghFJ{t0{ytOM`7eElCn)CU)UP(P=xJK$jL)-C*@5I(;jVVc;M)iy449kW}4#oM=0u3zt*90>5&
zojVksJVEWggx_Tjg!}0&;OGdeR-^RtCBaC9i=(6DU%cSx^=kk|?%t)azD^aWbrJ`F
zptR!xn&w%AmZnj!R@sloDLj9U&*!7?>J=;Z?r|m@=3suFLOP8J)Lrvz+xF8az%ZZy
z11<~8u^T1cO1c
z^Yau_DK6Z&(bG=|5dhB7IEv8P@;aaaDvh+LClX-WHpNtm)mV(rmzF4})4luxG@^}k
zArHvk2K`cCsVenK1+!GbfA%bfVPFb@0c<^e%B6=7`SSjK>VUgL$P|R72=}&!X%)Tz
z>Yf7h!$WHO`vfjuW_W6fa5&62u^7Jy!GvM(#m$@Kx3|#%vwf=j6ohCMo!=F`1{j_x
z&~iCcpuD@w#^cA$1Kf-h*h!_(x=;55XK3{Shgg-?UqA(@0&1Z^G8V%+Hf~GvNv0lf
zlUHcmkQMp6?kV8sYSnA_ec>iAN&%XD=iP`-33VDT1lMXcW@l$B$z-xe8DL7n5|F1AeY2c81SArPAAqaCFmN6?x3#r(
z)#vkFo1B~+aQn{9&8gGV)0@l7%YVqIoQ^DL<-0`Vqr{26?iSFkb_Afy1u8)C@bGX`
z)3o78B=XtF$jB!EYin!9qeqY4EiNuD2_g1@H^46N7Wl{Y%m4>KL5ggvKGc!|7CX>tge0~#H1AYh6z~8_gun%Ni(bs6dvw8}!
z<J931>MlgWs9JifiMva%@2f0NPYXyp2cR>ha)j&_hk@9zO8
zPX?{KTwPdLm{t_!S|}9yYISw>S4qAEY}3lG8_qq@6CVAe*=O7z5V~oa8$t-u>GUFv
z$lu5)oh!lZZ+BbRjgJ2Xec)U&=V|nIC%>Lio~8gtgkx<->LdP__!rDZ;1P9eUtItI
N002ovPDHLkV1kEP3Y!1`
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_archived.png b/public/images/map_markers/okapi/cache/large_event_archived.png
new file mode 100644
index 0000000000000000000000000000000000000000..be04197ab4415a5ecbd9fed6c968fb90d1e63c0a
GIT binary patch
literal 1516
zcmVmBv=^?h#xv2*9nIkmO5C3o-M<>0}C#9}d4ty;yYQ>O@r!>YZ#
zy{fLRt{c$bDZ2Xl`o3s1D*0T~G*L>4&*zg38#YLFb+v5SvPE1jmz+L*T0}&iKY!kS
z;>3xs-bwsz0AjJ2D5b>f^-67Rt+-q+X=`hfP$(o@w{Df?%a_Z^lP5*fG#MHi`b9)6
z`SkJ@VbAW}SnPHREEbeuAju@9D^{?0?_RE7zfLe1q@kgK&6_u)5(%1`nsB?_T)ldg
z_3PKOV8McAfE|dw7eG?eCWMpmIHK!>?%yZk^Wk>8S+{N-RaI3yId_hL$HRARZ5%&-
zoZjAEDk>@n1Ok7|pFcmR__P3tu`x&{nYU*T&Z?@({=!0LI2=?~R`Q~?mG1rfiRe0&
zhQZvqbFo^jiQBht|91k7$ZGM1PuSmvXjNZ9}t*nfBE*HUDw;1W}CRkX=
z;(hz*IeL_ct`h^4Qs}zQkt0U}7cN}5Y#4?P*rouO@Vo_*jK@igj}vHaCe+?eK|ukb
zjt(B~-;brJh`}2-2>JaOKqBM0fq{X9VHh^R0XTu;40n*K3mag~3y=kqOrmKTUmQBb
z_e!yF*Di)`-b4?D-WY3Ez7r^W%}X+X?1259j$)h5#?Xx$guPzotXY$DoKngP%mU`5
zyG&02aZsU}{0GqovIMCm51SrMi$jj1c>DJ4k440yl(LG5wWg+~xUR0Q
z*y(g;0mou7T3TAhJRVPuGQcneM}Z)d(NC1q8vs|XTv-h)1r`Cbfmu(VK3!T+P_S&<
zwr$0kW3OGi7CnFd{No1?9{9|t(kHTFGT)=X%Z%s~nE+GOjsi4uf-xXGJUsk39*-|7
zD=VA1WXY1x0D5|Q^fPD9yzK1k>{3bvfG5B+;05q+Mmqou0wEJJtCpt%NSdVMz$;)#
zLs2i_+54&r3>5z8M%8P|eNF{SO~L>@>yyG@~COmFrhbR(!-<(Ko~)_xnIP
zPdbx#dGy}Bd*_`_=Q6w9Uh(MBquZu<7pZTBbbd1}eGlZcJm<&6Ig|MUp&5qJrWWNOk?RwW;Us_J)PgYQGQ5(G(_67w$%UjN!ovT8BOzm
S8HIlU0000Hg+dYhQ~F1!{Ub<=RZyV;OKWS5G{F~5i&YV8iv($0HEKk8AcRl=R05a{U=Y9^LWnMeD2v5ndjM1jAv7UGyJcB>^78UVGR2}#0WJfm
z;+!vOZ*QNSAW|)aSi~5sH%)ViuIrLv#q$XvRSt(^Pquh7CIBEGz`T~07Hr?X9sBm}
z1Aut|s>9)M7r+D<~qtDJMi<#Ofw{r)P4
z!*Oc<{Q1jNRV`)AKKB#PPeeOwzf19iM%C*z{Rc~
zAxlnq&EmDWwY9bD!{M+e5{cmC^=~l{?g!_by)w6Iu(A4G4gf-kyE9VY$dMz9QonJ|
zR}w-zfd}pQ`OX=oz&$H>VabcsBk~oO%Y|Qi&f{9}D%@^2=FTeDKX~&aA0>1|2yxZx
z^|oaqFq0QTm`@rx7+M9+5o05ulE$%_Y}vk2s97=?v}4;w1C
zz(WfVkH^)5f`V@nN%E&6zzqY0F$m6K+`6Ub6c)-#S(&`Lybht^N4OQdj-kjPSVZGY
zkD?Pste*uyh^Z9JAJ~LvCdy0H~BwAEi`YKj(cKyYeN1
ze{^tDRk5UWDb_4r8>NIQx~~5wNzx?%-AG^NaYeHBfTd|LM@A6o?1T{v!s&Fv>giGA
z_wO^8%J|z$H*l|&gCbuk>X$Ww5^4w`ZZKOz=)HRexB#UTYHzPWDLo1Rj4=v8PUDizr&b`EEzu=
zvMRtvM`5TcoC_A9q`n@MQWS68h~kYKA%p-S1byeu!AKz>gh+y<+9V~i5-?O1aR9M_
z0R&HSr#=-Q(}xse!t(-(9q!Xcsvsb>$=Wc
zTU)i}=4LGec=E{r7^&cC3AD7d{Eo4b${4%%%L4-gMU>Kcn>TOv+1IwUwP^lov0CaVA>AQFD9`5Mq7_cnM0$`P!
zu~;=Lpp;4ihoqEW9vT{A+qP{0gTQsq^A5YN`xS-4!y&50ZKYH;9*?iB7Eh~{0I&ww
z+27yK;lqbHdh{qjEAYKyvG{`HID9bnEqVthBx_Cbn|F_4x_RDw=U4Jadw+ruqUB>DV4CKjuIrls
zBOZ@O4jw$XTGw?pZ{EB{DOK+&my>_{Ii{OOO5fYiw8;ZdN`1I&0`2YX-(6_pu3fv<
zODVTXDf!F4|AeM#+E+L3)%NY%w@E3bNhx{r$}#>klK};ro3}grw{**Zz?GU5IDPtb
zTjiLP@_Aj?jp6b4_}$-6YKd5b*8J>xQVnZ0Ap{rx^+yIjyo6!stXa8E9@_nbh(I_}
z%InEw@{MW)mfeIxhv=8E?~N+Qt+
z-)ViF)yWi|=Xr@lq7R4w_7f=}9S6Ty#LMTIyK;r%!~{x8_HTKWt?RZEiPUj>c8r`k
zgLGV8`9e2eTK^)3VGxZ*{{eg;gs2L>qyoNegOoho)<*rtjQ}XaK-YD;TVG?^nr0$<
z6Xm*WUAvRLpW82m5EKf9Tghbd*TC5-Ny=p@;F~7y+#J^R>$v0NBoYbSk3Pc7=XuI_
zidT0W;+gofJhyT!-+1Bs0MhsU+>s+kj&*i+_628zQN=YtTT}t*IQX{By$cu6>g#FT
zuz|vj8;tk#@cHA%X<7MM-uU`2QA#0%Kq+MlAueY!nZm%pfL29e8TMtb0x2cF@6*)Y
z&KKW$i%23tX=Vli2qDPdz76nK0MGLxKoY30@L1rHvJy4zgu1SiPp2u2jL^7c3p0a*
z+&p_07bsd5djG^KILfXU?3N=K>4$!8irn0lMv$0ev)zIABoCFvd
z8OinZ^o$G-52t3;^Gx!`K?u-0V-+`u0Lhw2|BG5`**665ma%U2VLL`n#e8XFsX510u6!<}8Z
zT~z*FQh~6k3MUeYOvGZb{IzS>GR(_du78=pWA7|xwf;BMLJkXb^(Xd;)oT9(j(*-N
T3SES%00000NkvXXu0mjfJP{CF
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_archived_new.png b/public/images/map_markers/okapi/cache/large_event_archived_new.png
new file mode 100644
index 0000000000000000000000000000000000000000..af6fe8cd62de7bdc8be82cb258770c435af96359
GIT binary patch
literal 2063
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
U^u?cxBLDyZ07*qoM6N<$f=+97>;M1&
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_excellent_found_caption.png b/public/images/map_markers/okapi/cache/large_event_excellent_found_caption.png
new file mode 100644
index 0000000000000000000000000000000000000000..35a9e5e5f32fe2a4372571a8d36a06d351470c8e
GIT binary patch
literal 1851
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
LNkvXXu0mjfLp=G=
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_excellent_recommended.png b/public/images/map_markers/okapi/cache/large_event_excellent_recommended.png
new file mode 100644
index 0000000000000000000000000000000000000000..b1de2ec6a9f9d4e9019003028d0f564a14c9adb4
GIT binary patch
literal 2199
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
pq998pq=BaWE@
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_excellent_recommended_found_caption.png b/public/images/map_markers/okapi/cache/large_event_excellent_recommended_found_caption.png
new file mode 100644
index 0000000000000000000000000000000000000000..a3bb07d6b52bc784e2c0d230b95f0395d9c7681b
GIT binary patch
literal 2200
zcmV;J2xs?+P)2D_7&SW#*ek*M?y>sX&mw(PQoLg
z6bLD_jgv|cwQAL>Dzs8Xk*ZczrM8Otkouv8R!J)YQc;Z(8bBc`d9@IS;3O#77?Qv`
zwuv2ky*7UA%d@*P_x8i?I_tHugZh;t9nIW3_ul{i{Li^FcLW6%jlT1M5PGW+!k^!-
zldVO;uI?mEHTL2jD&Zt&a(*(ds-{q-xarv#-YM3%vOjsXhblHUV
zcKCvJD)c_l;y9LO;Tm#LSyC#cl)dv2(1g%idrqIOE2(Tm5JM2-(7pp4+IL{qwl0!r
znv+FhA;bV3tYVu)sfltbG$pttwTN1O9a7rI=T$%m;U5Y`X5>G}5
zrA9$0kbufQ6!3K2FYq_j;4~agDdo0EB(mG*^L?rkMt(z@Q2>^%+<+aqHr3y-q#oT@
zjV+Q4PK0D~`+IUZQE*e}MWq2_#};$V37$=|tU>
zqGjU}UF{=E>c}rhRajJ#;-p;
z3;ZyqX<+CsY$;JFmM?5Z8_-x;ww7{d1-4A{w_|@K8lON2K~v@JNF~uQr4XVPm_a~O
z%HFs7-lpE3U>~SB^-F8`=;R(I20Kw!3}wZb80@6?+}jA8faFB*Fekc>;Lr^oUi2vb
z1+@VDqkT6$Lsw9iV0GPkT37AFVHgNuN~P4*SySNkwj7PcIu7f;>hA^LAEe>dQbH7S
z;hn=IVq@e|^u={wM%M)IeSC@++y9E&<)yZ)f!c+QSXdms_&V=)y@f#FFImjD)<1=n
zRwR>AyxuWWDdX3`cV{R7pp?CD)jiA3k0gAYdi!Gl*4@3B&5x~R^J8mSclTm+hYQPA
z3{4E7=^Ak}E}wtv&(abmABNs%|GO`u>l!|fmmfa(3~q;qXw0JhtSR4kbEL>HoZpyD
zff*m8RLa^GIMQA^7*0$ZxO~-W8duy4Qt@)f^BnGc4SG5$A7cY|T@5k+SlfH5VD;lNP
zDCUWl@3Y8LLG8`;d~?H-nU$rCJ@?#m$FjlA8g$b=It`r*iGjL;xTb4AQ%IFJ)a_BtjwVL;|~DjBVQn83kavkn84)lF#WH;
zK6UV!0s_KaT~i4yuzYp%3FJ7V{}EN#?+lj7B-Tckhgf$|rOK+bJJB#f_w3(5DF_|lw}fXef9HloQ$BoeEvtW1@cm)8yt
z52yC**>gS+2wcd5MzYrg*K?gyAf5FY;P5F$n2kKe^zCi5x3`~nyWM^vgukb!=Urel
z3z%Qog|Cak_Ph$@n<{XePUk>TQBkzBv$LCw%(?vM2+Wu>mx=iX6quIhFiTZ`ZlBv{
awf_MW@avpGidm8X0000IX5E7m7nR({Uz4x5^|DESK=Q-yJrkRwr`G6nDpZ2OBXcD5j
zU&`7ifUf~B0!M|Ywx)d}4={zO9-03A=_Y0n-tzJOL%V(94gea4eXPq45b!K#!)G6U
z2{2Ebzwp4pV|CuA9=Pvnc~P-0gt&JCLdx3eNG$dvA%#8P?Rsb~2$3TGWJ^umi=%-7
z@|RXpva$*#&5bpdj$#kceW9NI&NCFPyp6#$(fh;NH+}i@y!x{n9_d(Bwpa%a0NcBI
zue)BWeZORhBY)(n9iRT25Y;ct2B0Rd{+61$7XhlaK8=#*#*XROF&zaRfW^0eijtL8
zbhR8I!<|u>R^T+wmUZ~PSGRBVU8np5mF1;hJAAG_@2uVG?Kgt1FNv)>P&ii#)a2;5
zj0Og%+WIsAU8nyEK*`D~0J<;KPu?$HwUOaq6U#&qU1~pl>xbNb>8>q#`|>e6kT;^n
zRTIzU3~Nb2z790Z2>|#%-hXI!{?bYm83N$dy}tzDr@wo3#`|
z_@Ws`aZ!#5bo@6Fn6!8#2*CPH+c5*}lh4=Q?nm>LVyk1c_g&-V({FM5wl>HR5J{y2
z%Ms_Yr`L11{-p2m`|f!I*gPjdIM`2OG>jN^Au|lNfA)6ZcCdy4*zxpZ0Q~!W3wtjd
zWO&mEic^pnktququmw_;^e?`yy?lEA@{BaMC1veDfXzZwo3{k;WaT49T>!kX?-zKo
zrq`fx>&;OERB=rJLnDt=?!18--4}Y`B{>C$#
zdt+wifXn5ynL1l;03>Vs`A;FfsPtm_PUAc7WJbybJQ^V1dd21_5jjdbC0zfrzcsjt1
zQXD(>n*)Co+sr`wq?qP%17I3Dmo6n}YG_6Cm9p)NPheTO09c7;zJA~*=+||A_4po~
zPB&-IwwUehy=ox3Maj9Ldc1JJ9qAE51yx|?Kt0OyxOWM
zt|Wb01ZFTR6e1Ce5&q~SG@p-x4I2m?KTfEz5rE~pcN08+o+uET+EtMf;&Bu}OBH0i
zcu%^*ES4|~tZ0-bmNJ9g8n>O9Dos?3w6R4pO9>&j>6Ct+%1JD^yi~c_WNGTa0AquL#Cm&COG{b0YZq>}n^k-E@VIUB8PjCh
zwrvEux-fwF^e6zfjY=}t+*l10qc;F^))W}S!|1?hcQ+Sbc?Ek0kt+=i7&CR2V2^j0
zSoagcdeY|xhyYPQ4+c5BXU~){PXI{9Hx$S8&NnPoJOYH1R}-*i1$ZnPo$d91YpLQR
zNdP1HZ1zI*e=>{lkdGu?pAd(srFinduxr<@&heRStF~>cn>KAqfAGNv-5!r;3UDkI
z68l41_WOF$(wmG1I;wi5($)qjrzey=ZtsX
zRoJm(M|!Hpd+)ucC&Irr_deIG34xt@KGkFB7dz=riVmfW-ntb)EAV_YmR>O!Dp?i`
zXXZt8C1-Jwwc>&Mgzs0cAGT|1^307JH);T_t*v(5hws?m`EtxP8Y_>qv^zVHW08av
zGDb&(;g;5T_s0#i0KLFK5@d?_RDdGs0=$mVQSbGkvs(Mrc2{5DHTT8tVe`H_1KMNT
zbnT^me^$!N%PB4{rlzJwx&Q7Sx5R7j|Df0m>m_QY*JpXX-f(t7c3_EfsAoVw(cRqo
z=c_59pYj`@%oIo|AMNSsscdLyC~Isyd6!e^x82%+?MWN9eOWaK@Anr2w*;8ega82+aYi!c8P+G(bg7{rMs607%nWSDEM;&mQ-P~h
zRaK2|9cWrT7|c=EmbRMf*L2;SF9}Kl!wIIMpt!u)PRGpRCz}_mXWLh3eSvcAk?mED
zz|~t04sM==^V9*`lQwAiJOMi=D`4ejg~|3t?9B9-JwI(cOVOA{D3YcOkEAPuK@USg
zpBf1JlyEFp9kcS3ii-8e)~#FDws7IXGeU@ivjQX`@_~w2Eaq=(Yg^FU+nW;z1bm~T
zqh4LtJ*H{8Z5ET?5l7In{kT;1T@7-jx
z*}Z%B?mhiuH_0Z1fHVEgoVjz)J?DHs=l473cg_`zGbzh5fg&Jt+^0^UN{Et9Da-B!
z9t2(l4hm6XjT<8!Foh`TA3y$h6B7upKep$S?QUNK02O_1mQVHINuJBfyEeTBn8&MY
zZvXi3(bW5Izx9WC**O6r#F}9UDa%Uy!Qit(3VVuEzvFTcB2IkU*+WNP9Q1UPIeRI2
z3yM(^ome3kirr0XO*x%SC&^y0ke)UHUs^
z`}6W0nf>?Qv+h4alsr8dfEs%iojr8)MS$WB52GYHv4a8ZU;u>x0JE0eMBaj8TF!n>
zk~3*WVpf9jePM(9_eXavzTres_tJR<4<0yEp8maEo7!o3^LKWr__+t+;9_N4c#VbvtL
zImyb;$_xM%mjwWdj_vtmd*tl{F^r%h
zO^FgxNcT-M3RmSCK>6hW6d<#?*+W)t0k%lFTzjPEV895`5bOjY!3JdPqX37g;vPye
za7)?OCC=j|ji=tB(Z$RvZ(yOsgV!0H3wo`*LB@NM;3Uat9=zSaFG
z34%z!jN8b7Es(0Db5@tOvvSYeq(rABW!V?NS|LizO9CXPWg-T306y6DXOh##=b)%v
zNYTmG+{hDQy43+l0H!hu;fOu;2pzLKwC6s1Z=sa3cKxd2&!sF|GZBOebZYJbn);41
zZ*dOEX_?&fyALi_mo0R(onUI3#&^{Xv<`Urp}p1I7e1-^r-wm+=2OXNNTIt+GQ*i*
zr>ailWYsy>jZ2IAlaib+z%vm*Rp|rQzxL0U-r2rjQ4&SV=W}e&W6UhNgXuGi0O&bi
z#rdjz0A$=yfTPdPqo#hGs9atIPWAQ^_@oa6tOmEL@ed?3R;W<>zZI
zQ_bP%WkbP@oblJA4hYt#-$ZA=OKEJX=D+1by8q4NnM+p9wKl9T^Z+Hmf$;#Nsra)K
zuk39N-fMd5N5nMU34mz?Xl#s7RZ)xPE@0z*_hMPo0k9&c`SsrC33LT`eaj9K5}ceo
zb=s^u*3CfTT5W22vKa}T>V51tIdwvm+&obT5Tc}0UVrshr86`0KHs)+aaG0f)K5P4
zjcGW0W-=w$tYqMHJ7=H#6V`x%9STwKEo(lv5G7t#J
zuW!3ee!X_BZ2a_7+0)Z=QSo}cvV7Y%`JoWpE3!ZAj_&z*;Xtfh9>5O_
z0RgX<13Pw%aq}>MBzmAY#&?bbi4*q&zSz?QtVsbj4-HNB`ARKbygvqD#OfwbME@tV
zh`PK#RszG~Fg6vBgmUZFtqoF2#kOr#N~x|}x6ZX`(PsiG)bw{CUC3+&ssFVMSl
zr~k>C8cP9N#0_kKzX^VbiT1|L-iikp{W*>9)7d>aIg5K%thlCs>eN|&MafLJtUTSe
zlXrze`VCvQ=xf%jQ2?r|tL?wM@Pf6qqr)_>+__xwK=!7x0|nj^pUb~;X*w-
zJDV@Q_`<$vXvm(Doz2mQf>ks#^*CAFYjgd
zZjZfd*Ffy_P-4%kfVmM^_Ug6Qx*ObX?Y_f@t;C_BULPEt0~e-3NRMqRasT}(;_kcM
zN^!BHz2WAufo5*7HQW1Zl
r7|!uNqFJtkXy$7IYK0JiE1~=!+t_?MDtB{400000NkvXXu0mjfFh=kO
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_found.png b/public/images/map_markers/okapi/cache/large_event_found.png
new file mode 100644
index 0000000000000000000000000000000000000000..85d78e8fdce0acddfccae68bceb7e2a10569cb05
GIT binary patch
literal 1396
zcmV-)1&jKLP)q}n>3r8
zoxPoNW~L9>BPW}^g{E(Q@N<|s|IGLO-}z_Y0RIEV#>QN#s(OpbCG$sRsZl
z#&$=e(Y5A0W9%RyWO+FD2q!Kc#&|T0j$gktU)SW?&psD&
z#@J_skXOwyA!KVb8vTM0(nJWUGq{GMKkr8*J^=t&QB`lI-Y;6fjvYJJWJ_#pYtSKsf+})erz6o{FLKw-ZPhG4zM}(0%=D0D#+BiVrsKf!nS?N_kgNl+W{R
znzsiAj~zQqN=iToL5bJvDzC3sUVrK(Bo?p7wfk3)ni@jKH+wNL6-F70KwY-5@16DU
zqsmhaDdni5D0>Q3mDd5GX%LA748{<aPs8IYw5iUMqUSmu7f8M_~-n2P`4XpwY7-exr5;|XVeu(jx4AuSwi1i
z_Yt_k0ZJjI9Ho@@2q8>@LJ&ot0wDy15Lmoz8&;n_EgW9&WPET?gOH$K4fga<4M0lQMQv*<(gN&h!dZ2s!!Rf2
zBtS|D76{-$M+ex34Tz79Lh8DZ8F`#@(*Y~7RlwtM{w7Q&rz0K*ak(I+1eX#zfJc`v
zqjJ|SENg26x9kW2=^n5ni{sDZ&=2~-vj@V*h+2{kllgy_V&A+bE@mQ
z-7pM$TU(p5dGqFSMNwu5P9~G0r>BQ?b#<{EC(gT@$qkoy>#3m#vY0O-}LS4T@rOUnr%p)~#C;n68jpLS~7)nCs6e&3NXt_6eS#So{mQ<%xvvSv3v-0000s_zy
z-S6j%-i@PUYe~RYJjs*xe)sG1{XXC4`@0_8hZr3lt6*#*tM?LI*Y$;}sxFX7aw3bWsx`r2@YMfCK-07z0nT1)#UEk!bo2L1vs;bo~v!C6+ZR18J#lF_B0ZyYXhU%VE~?;S@fZl@}G(c)YjI1aHowcR;+kh
z2=S5-f>VG0jFgg93*MwqDC`IZgJB^Ads?>9)qe?qC3BZq>lf8~1Ws2>0ATeZnilBjJ;V2Zd_yD@Wo~>vbEeOa0sL~|C)#>i2!*Cl9gW*tR(^(pf)L_TEEd~3
z5rK+5peRZNU|{q*0A}9c+uyfi36qNh=lG%RI{+e~C?Br=f`_yyLWrx8NaU5t>Q3r`
zYmJR-)nE`*m51idz`@zaVIAm{r?Gt8AdlD(-
zNF)+@pLEUsR~rFY3UXoi_Kv6^rv`l*+)gygvjjN
zx$^|Y@lKX1pib%mkNz}9!RBc()96r_}v
zqA0CG2-OENuB<;RJ_SMu9LFJETg#FI2M9%@FlIu
z?_M75>cZ^r$1zQul0A;&1Sl#1w@dC3sB8pIE{9`TIHrjb4rALkj+EFye@hE9-hG!R
z>gsSxS`|VBxFvU~>`?TE0K}vU*rTK5(`ly6nL~Wd8iK(fiMl!xb#-IL>pO9RJlv*&
zlv4A7dEMf6?|s^o8$mvu#sadb6upNJBTMc}V6dxeY@j9KSJzJ<@1{*T1+stza=4sY17Vb;2J>t@DcvD@}rmL(1yI@H(H)HGNDxXG>V$EG=sz`=tD_qgjZ
zpbB_+U|`@mRaKX7+_*8}-+S!XvHr%!#oJUkpuBob3=YHDHtot>TOhK7dDj*gC`<2X5PH&_A4`M?eLd!bSS3PqC(ASb2F
z2_dd`cXwB2x|1kH_=X)z!08sZ@UV?%ijT$>cc~H0^$x+?utgK*7y%;4twknQ(#qrzFtY+Ilt`
zjV2UDNnE*d_U7*q826jWLMgYQ
lBuZba#<}`IJczrE{{W4YmLogY$vOZ4002ovPDHLkV1n|au%Z9}
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_new.png b/public/images/map_markers/okapi/cache/large_event_new.png
new file mode 100644
index 0000000000000000000000000000000000000000..65596434d8137a3cc5db742c1167714e6af08f5d
GIT binary patch
literal 1663
zcmV-_27vjAP)#^LElA+Y53lP6E^
zejM=L-rjq51|ylGZnL%GaezvR>!I8BiVdzSB^TU&^;Lw=hb9Cvn?-rvig}sIkd4R5
z%*|m=O>uZ);*p7#B;aK-OTeCOqa0`Dylvw|BG|LDn32dDd-b>k+*ArYkEYjNBXH=@
zT4P;j^!3+?eeeP1I`&c`U`dxg7e7lANF?wqi{$0Y7@-hN2M-dxbcw{k006t+c!SuT
zJEQ??rKwN~vRMRRtV3W)OD3Ub+qmg8Gw;7o?DNmjG>zERtK53?P0IX!9$dUgY;24y
z;1<~_rG!$5v_%CFAXi}p^#i^!any4Hn17HYDIlMB2g+)U5*7^Y0Fug}^gS+*FEeGKtu-1;=s7N{Ivf
z_v~4AzWp}sCr;o3#T`N^C8R`HHhxyR-OqC3OTaBjATvLYH8X?0XAe*I_Tu;Z`F39)
zKb4XnI}W>!9wjr5n*VBrZ9Z$Mb3yz+q)8P89~dy}e_(OqRNoQt#>MsXB7xh(8brtRQSz
z7U#~LOI^5dVQm^{VA)GGpCorfD(rqKor(#J0MWm`bEd(vF&qcO^AMgy|LpRR{mCbS
zZL;m)cmT%E&Pu(6ZzlX}CJU3x4
zF2<6#hqIGkgt-mO0CRaFE5KJ0Xi+{OShlzre6VoS7@Z#V-M{~}|L$bOdHy?5g$=Bq$lf0XF|fv)(gk26Hh(Wb)~bjbELVs`Ky+emcOkB
z4xlNeo*o(+`o+f|oqD+`bl2ItXV`i6nQ>R;8;JsxhMnB>Y%tcR?n}0{!fHR
zyH=8g=6cL6eq?z$Xc}A}{FZ*}UWYLoYd2na@mFWMy1Gtlns#SB0y@xo?b@~Ou3eYS
zAASG&(w$4wK;&~?DWvj9Ne|!8elk!saI=xd#x(b*NbYFDtgb?qiJXn5!J&Nh!&PhMng+$JfS7f$*@)!4U%C3nI(Q)(8J`@Cp6qXoqn>+HSn?;(-BR
zdc)1Z+9a&d=VYLA-VFt!vaTlT*4HGd4W{JQDobvu%ta|}86;AbA`-6>^RWO6v5+23
zhD6e;*E4Q|=eOx4gXEHVnh``~Au4>gsqX6pA)CH!rlcwLPe;th@ybXqq-#
zDg@f<4@xN=Xdri!3FdY6WfGRpbd%+SCQh#F&1sspZrQDt{{adJ^m11B>(T%K002ov
JPDHLkV1g9jG*bWo
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_own.png b/public/images/map_markers/okapi/cache/large_event_own.png
new file mode 100644
index 0000000000000000000000000000000000000000..910a18b0a3791a7b31f227a56f546a7b05d919f3
GIT binary patch
literal 1529
zcmVxe8i%>rK6=lqyv#rj!!XG)a>tYubG6
zN4B%Gv$HdEyqMX|Zg;bdZv-EBn3;2)bN>J5Jm-1N8Tgw;6ka5RfvrF%pl@(q3z!9_
z1Q@jp)spwEz)_%KgWv^81D^qx*Gr%iXn6Uhmmc{m&`+E^IiB~OS~r2>vJVap_HG0`
z8jX%8puvL3ootnj0M!x;G!wKt*{QWUe>;2_Mb{CEf|t)DUAL^?%jL+YQsfpFF=H{F
zpPBj7L~9aobGah0YgtI!F7LN2?06h&ejYO(uNW^kO29D;a9!Hpc!P#ryDA5(DicSK
zk{lewtmc3p;(`{$D}B}`u(E=i&5}NU9xW1~{pqJk{O|)Smo5R&{nlF~M@Pv3+47-^
z1jY7&wJHRPT5}V+mW7kaaO1=YlIPALgdln00+-)@o4Qblg)?VJPEC;qoRV=;O2q}`
zmY-P-_(iUuA^dg?P}iLWuIrM^<>-C?eO~lDx(*#;@w@M^lgSEODW#GJEd}@Dr(!{y
zN(kwIUNZ!@i>7HTo;gEmc$n4~URcx4^E@>VYQhJ*pVcLI@XNG`9~SdZ5s*@n8Xjh(
zzn_ka7r8YxwU(Wl2hH$3ZMh9x4Zdye6av>YaSVfeI*n3ak8RuJJr5h0{^~2bKKzh}
z-g^%RD6J5|9#Abm-lfYPVs+ztfK!t|ZfS|^jT@*vJ#0O6h)^iR!~Ojn@H}3&Z64ga
zm&En!SU|pfs1mrW62zL-Y$$kd0d~z0Sn)U}aBFs!t6zLkOyHuYz|8P4R`ubEEUyCv
zU^CD=6EJ`bU?!7%+ux6STfYoc0Cj6mQwnb2AJazg?bIZ&Ka;7|ytR=qE7r&0p5K>EKYPmV7`lL6rzXnD}ijg5KVD2ft|M#H55r%s(RmyaJe
z-o0|gQNR-=6I)C)!S+n1hv^3l|$P5&?y<^ER3>C`>1VIY^&
zpFMCu-@SXc0x&u{>V5g~$4>O-O~=!9Bc|)WdzO{5=jYS$>FLEW)13Pm#>e40FdvYx
zC_gqzRzS*bU~j~AciofCD&a&zjmP5;J5AD)8W28uc4_)S5;N-6{7XwblU5>c=7VFW5)`sPyt?C0V(Cbfo%XXpZD@}
zbB1;8nw_1Pu${3n=dO{FNa*U-9jEK-!z)LQG_|(3D?fhniT$rDSL|zTZP)c3J0>4^
z{Bire9u1_k|QqQ&d%@uC8vhxw-kBYTy7uO1Td>Oge4x%P-3e4JEvRftBF&
zP=e>(K(`Bzefrc>k;zCzd-eP8oqIBw-IUcv+ep
zKiCZ6XppN4{`%{U?B5?@=gyX(Wn?V^6`K&p@mN?eh{a5%
zr!B_EO(rI6CMRuTu{_JmK443W!j>&}(cP`l)1%Sb8=|XAXUmolZEa!H;!!^;gm|YW
zfq=vgU@uU4{r&&sC*T_)#HCtB;`Rn9WeDiQ|F7E&w6l7tD7{b=YJ3{M%H71Td{e-f
f5Te>my+Zx~{9J-?t0oI#00000NkvXXu0mjfu4m-H
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_event_unavailable.png b/public/images/map_markers/okapi/cache/large_event_unavailable.png
new file mode 100644
index 0000000000000000000000000000000000000000..61a74f65bde677b944ec5ea0afd53b5fabae51fa
GIT binary patch
literal 1523
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
O0000W9d&RZZMDUbmyHoZ4GG4O
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
IM6N<$f`o(kxBvhE
literal 0
HcmV?d00001
diff --git a/public/images/map_markers/okapi/cache/large_moving_archived.png b/public/images/map_markers/okapi/cache/large_moving_archived.png
new file mode 100644
index 0000000000000000000000000000000000000000..ce7d1af37a6d9c689a1ced2b6dbc451566bd6eb7
GIT binary patch
literal 1515
zcmVJNR9J=Wm)&bqTN=iH&B@fX)KJ@lhy@XeQszR6j*@zzy(y-m
zW58YrqNt2`GZ(o~{{gSYqb-6^bQlD2C`Bt(DHOa>D3}(lqhmW&v>s+mY@1`7CTVu|
z*Lu%I_HK8-QkCPyfqCF%?X11Bp6C5o@7^1JuMm++5!oUlfkpH6BJw8@DgU12>qX>>
zhzy9x-$bOwng6qhJQtDoBJ!8-MP4l;|Fmse1_lPiL6?a9RYayoMn+_4Xh=jPDV_LMabyrs6-+WIdtfdq|<2;k*lli=l=!`KLbPIa5%hm>sD^x
zzRj97YiMd};@r7&q|<3)u^4ODu2sOmH|)PUL?kRCZ$5wiEGJK%ls$X)NONC>lNxNreY)7ZOrFKumYq|<5j
zU;_*1c!^509
zb&5-uE-^APLVbNb$z<|zU0vOZ?P$0xki5Ysf-uwet+w{N%l`}=#&o;~{yhr{nNpO?2}1T;;A!sPb4P#kwd5{3Qh}
z#;#qvh(@CTR8&-O=FAy3ZQ8VCom2Tipk|R(djti5z*o28jT<-4T~}08P+MEOWQ|hF
z57Ywd-6_W`pg{3d_<;OZMIez#aP#KPx!>L0-Mo15V#zuY@l*7+2Kdpj8Wwu*2mGrZ
zLtWRgEQ>@UK}Sainx+A8=guAa`}^l=z_Ki_03XF%S36!?6kD>7`PQretE7NjE=N9}
z=k43K^!E0W$z%ZN=;+|tvu9YAg|6#!B0X@AUb*9~d$ZsW8_u<{s(@@ZOEQ^6)3iB~
zM~@x>VB7XwgIWeY;0NZ