diff --git a/public/static/css/map_editor.css b/public/static/css/map_editor.css
index fe0b474..b173251 100644
--- a/public/static/css/map_editor.css
+++ b/public/static/css/map_editor.css
@@ -1,3 +1,17 @@
+#metadata {
+ position: absolute;
+ top: 50px;
+ left: 10px;
+ padding: 10px;
+ background-color: #eeeeee;
+ border: solid 1px #555555;
+ border-radius: 3px;
+ box-sizing: border-box;
+ opacity: 0.95;
+ z-index: 2;
+ visibility: hidden;
+}
+
#map {
width: 100%;
height: calc(100% - 40px);
@@ -28,12 +42,15 @@
#control {
position: absolute;
+ top: 50px;
+ right: 10px;
width: 125px;
z-index: 3;
}
#placeControl {
position: absolute;
+ right: 10px;
z-index: 3;
width: 100px;
visibility: hidden;
@@ -44,6 +61,9 @@
}
@media screen and (max-width: 999px) and (min-height: 600px) {
+ #metadata {
+ width: calc(100% - 155px);
+ }
#map.selected {
height: calc(50% - 20px);
}
@@ -53,17 +73,18 @@
right: 0;
height: calc(50% - 20px);
}
- #control {
- right: 10px;
- top: 50px;
- }
#placeControl {
- right: 10px;
top: calc(50% + 30px);
}
}
@media screen and (min-width: 1000px), (max-height: 599px) {
+ #metadata {
+ width: calc(50% - 20px);
+ }
+ #metadata.selected {
+ top: 95px;
+ }
#map.selected {
width: 50%;
}
@@ -73,12 +94,13 @@
right: 0;
width: 50%;
}
- #control, #placeControl {
- right: 10px;
+ #placeControl {
top: 50px;
}
+ #modified.selected {
+ right: calc(50% + 10px);
+ }
#control.selected {
right: calc(50% + 10px);
- top: 50px;
}
}
diff --git a/public/static/js/map_editor.js b/public/static/js/map_editor.js
index a5f0726..494ee00 100644
--- a/public/static/js/map_editor.js
+++ b/public/static/js/map_editor.js
@@ -2,6 +2,10 @@
(function () {
var MapEditor = {
+ metadata: {
+ name: null,
+ description: null
+ },
map: null,
panorama: null,
selectedMarker: null,
@@ -9,6 +13,19 @@
edited: {},
deleted: {},
+ editMetadata: function () {
+ var form = document.getElementById('metadataForm');
+
+ MapEditor.metadata.name = form.elements.name.value;
+ MapEditor.metadata.description = form.elements.description.value;
+
+ document.getElementById('mapName').innerHTML = form.elements.name.value ? form.elements.name.value : '[unnamed map]';
+
+ document.getElementById('metadata').style.visibility = 'hidden';
+
+ document.getElementById('saveButton').disabled = false;
+ },
+
getPlace: function (placeId, marker) {
var xhr = new XMLHttpRequest();
xhr.responseType = 'json';
@@ -92,9 +109,11 @@
select: function (marker) {
if (MapEditor.selectedMarker === marker) {
+ MapEditor.closePlace();
return;
}
+ document.getElementById('metadata').classList.add('selected');
document.getElementById('map').classList.add('selected');
document.getElementById('control').classList.add('selected');
document.getElementById('noPano').style.visibility = 'hidden';
@@ -141,14 +160,14 @@
}
},
- resetSelected: function () {
+ resetSelected: function (del) {
if (!MapEditor.selectedMarker) {
return;
}
var placeId = MapEditor.selectedMarker.placeId
- if (places[placeId].id) {
+ if (places[placeId].id && !del) {
MapEditor.selectedMarker.setIcon(places[placeId].noPano ? IconCollection.iconRed : IconCollection.iconGreen);
MapEditor.selectedMarker.setZIndexOffset(1000);
} else {
@@ -191,29 +210,25 @@
}
MapEditor.selectedMarker.setLatLng({ lat: places[placeId].lat, lng: places[placeId].lng });
+
+ document.getElementById('saveButton').disabled = false;
},
- closePlace: function () {
+ closePlace: function (del) {
+ document.getElementById('metadata').classList.remove('selected')
document.getElementById('map').classList.remove('selected');
document.getElementById('control').classList.remove('selected');
document.getElementById('noPano').style.visibility = 'hidden';
document.getElementById('panorama').style.visibility = 'hidden';
document.getElementById('placeControl').style.visibility = 'hidden';
- MapEditor.resetSelected();
+ MapEditor.resetSelected(del);
MapEditor.selectedMarker = null;
MapEditor.map.invalidateSize(true);
},
deletePlace: function () {
- document.getElementById('map').classList.remove('selected');
- document.getElementById('control').classList.remove('selected');
- document.getElementById('noPano').style.visibility = 'hidden';
- document.getElementById('panorama').style.visibility = 'hidden';
- document.getElementById('placeControl').style.visibility = 'hidden';
- document.getElementById('deleteButton').style.display = 'none';
-
var placeId = MapEditor.selectedMarker.placeId;
if (places[placeId].id && !MapEditor.added[placeId]) {
@@ -222,23 +237,29 @@
document.getElementById('deleted').innerHTML = String(Object.keys(MapEditor.deleted).length);
}
- delete places[placeId];
+ MapEditor.closePlace(true);
+
delete MapEditor.added[placeId];
delete MapEditor.edited[placeId];
document.getElementById('added').innerHTML = String(Object.keys(MapEditor.added).length);
document.getElementById('edited').innerHTML = String(Object.keys(MapEditor.edited).length);
- MapEditor.map.removeLayer(MapEditor.selectedMarker);
- MapEditor.selectedMarker = null;
-
- MapEditor.map.invalidateSize(true);
+ document.getElementById('saveButton').disabled = false;
},
saveMap: function () {
document.getElementById('loading').style.visibility = 'visible';
var data = new FormData();
+
+ if (MapEditor.metadata.name !== null) {
+ data.append('name', MapEditor.metadata.name);
+ }
+ if (MapEditor.metadata.description !== null) {
+ data.append('description', MapEditor.metadata.description);
+ }
+
for (var placeId in MapEditor.added) {
if (!MapEditor.added.hasOwnProperty(placeId)) {
continue;
@@ -277,6 +298,8 @@
document.getElementById('added').innerHTML = '0';
document.getElementById('edited').innerHTML = '0';
document.getElementById('deleted').innerHTML = '0';
+
+ document.getElementById('saveButton').disabled = true;
};
xhr.open('POST', '/admin/saveMap/' + mapId + '/json', true);
@@ -381,6 +404,29 @@
motionTracking: false
});
+ document.getElementById('mapName').onclick = function (e) {
+ e.preventDefault();
+
+ var metadata = document.getElementById('metadata');
+
+ if (metadata.style.visibility === 'visible') {
+ metadata.style.visibility = 'hidden';
+ } else {
+ metadata.style.visibility = 'visible';
+ document.getElementById('metadataForm').elements.name.select();
+ }
+ };
+
+ document.getElementById('metadataForm').onsubmit = function (e) {
+ e.preventDefault();
+
+ MapEditor.editMetadata();
+ };
+
+ document.getElementById('closeMetadataButton').onclick = function () {
+ document.getElementById('metadata').style.visibility = 'hidden';
+ };
+
document.getElementById('saveButton').onclick = function () {
MapEditor.saveMap();
};
@@ -389,7 +435,7 @@
MapEditor.applyPlace();
};
- document.getElementById('cancelButton').onclick = function () {
+ document.getElementById('closeButton').onclick = function () {
MapEditor.closePlace();
};
diff --git a/src/Controller/MapAdminController.php b/src/Controller/MapAdminController.php
index fcf2782..f4809c8 100644
--- a/src/Controller/MapAdminController.php
+++ b/src/Controller/MapAdminController.php
@@ -8,6 +8,7 @@ use MapGuesser\Interfaces\Authorization\ISecured;
use MapGuesser\Interfaces\Database\IResultSet;
use MapGuesser\Interfaces\Request\IRequest;
use MapGuesser\Interfaces\Response\IContent;
+use MapGuesser\Repository\MapRepository;
use MapGuesser\Repository\PlaceRepository;
use MapGuesser\Response\HtmlContent;
use MapGuesser\Response\JsonContent;
@@ -18,11 +19,14 @@ class MapAdminController implements ISecured
{
private IRequest $request;
+ private MapRepository $mapRepository;
+
private PlaceRepository $placeRepository;
public function __construct(IRequest $request)
{
$this->request = $request;
+ $this->mapRepository = new MapRepository();
$this->placeRepository = new PlaceRepository();
}
@@ -44,11 +48,11 @@ class MapAdminController implements ISecured
{
$mapId = (int) $this->request->query('mapId');
- $bounds = $this->getMapBounds($mapId);
-
+ $map = $this->mapRepository->getById($mapId);
+ $bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']);
$places = $this->getPlaces($mapId);
- $data = ['mapId' => $mapId, 'bounds' => $bounds->toArray(), 'places' => &$places];
+ $data = ['mapId' => $mapId, 'mapName' => $map['name'], 'mapDescription' => str_replace('
', '\n', $map['description']), 'bounds' => $bounds->toArray(), 'places' => &$places];
return new HtmlContent('admin/map_editor', $data);
}
@@ -109,25 +113,19 @@ class MapAdminController implements ISecured
'bound_east_lng' => $mapBounds->getEastLng()
];
+ if (isset($_POST['name'])) {
+ $map['name'] = $_POST['name'] ? $_POST['name'] : '[unnamed map]';
+ }
+ if (isset($_POST['description'])) {
+ $map['description'] = str_replace(['\n', '\r\n'], '
', $_POST['description']);
+ }
+
$this->saveMapData($mapId, $map);
$data = ['added' => $addedIds];
return new JsonContent($data);
}
- private function getMapBounds(int $mapId): Bounds
- {
- $select = new Select(\Container::$dbConnection, 'maps');
- $select->columns(['bound_south_lat', 'bound_west_lng', 'bound_north_lat', 'bound_east_lng']);
- $select->whereId($mapId);
-
- $map = $select->execute()->fetch(IResultSet::FETCH_ASSOC);
-
- $bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']);
-
- return $bounds;
- }
-
private function calculateMapBounds(int $mapId): Bounds
{
$select = new Select(\Container::$dbConnection, 'places');
diff --git a/views/admin/map_editor.php b/views/admin/map_editor.php
index 1917063..cea6b25 100644
--- a/views/admin/map_editor.php
+++ b/views/admin/map_editor.php
@@ -3,18 +3,53 @@