rename Section back to Level
This commit is contained in:
parent
27ff35e785
commit
1498b7aeb0
27 changed files with 416 additions and 334 deletions
|
@ -8,12 +8,12 @@ from rest_framework.response import Response
|
|||
from rest_framework.routers import SimpleRouter
|
||||
|
||||
from c3nav.editor.api import EditorViewSet
|
||||
from c3nav.mapdata.api import (AreaViewSet, BuildingViewSet, ColumnViewSet, DoorViewSet, HoleViewSet,
|
||||
from c3nav.mapdata.api import (AreaViewSet, BuildingViewSet, ColumnViewSet, DoorViewSet, HoleViewSet, LevelViewSet,
|
||||
LineObstacleViewSet, LocationGroupViewSet, LocationViewSet, ObstacleViewSet,
|
||||
PointViewSet, SectionViewSet, SourceViewSet, SpaceViewSet, StairViewSet)
|
||||
PointViewSet, SourceViewSet, SpaceViewSet, StairViewSet)
|
||||
|
||||
router = SimpleRouter()
|
||||
router.register(r'sections', SectionViewSet)
|
||||
router.register(r'levels', LevelViewSet)
|
||||
router.register(r'buildings', BuildingViewSet)
|
||||
router.register(r'spaces', SpaceViewSet)
|
||||
router.register(r'doors', DoorViewSet)
|
||||
|
|
|
@ -7,19 +7,19 @@ from rest_framework.response import Response
|
|||
from rest_framework.viewsets import ViewSet
|
||||
from shapely.ops import cascaded_union
|
||||
|
||||
from c3nav.mapdata.models import Section, Space
|
||||
from c3nav.mapdata.models import Level, Space
|
||||
|
||||
|
||||
class EditorViewSet(ViewSet):
|
||||
"""
|
||||
Editor API
|
||||
/geometries/ returns a list of geojson features, you have to specify ?section=<id> or ?space=<id>
|
||||
/geometries/ returns a list of geojson features, you have to specify ?level=<id> or ?space=<id>
|
||||
/geometrystyles/ returns styling information for all geometry types
|
||||
"""
|
||||
def _get_section_geometries(self, section: Section):
|
||||
buildings = section.buildings.all()
|
||||
def _get_level_geometries(self, level: Level):
|
||||
buildings = level.buildings.all()
|
||||
buildings_geom = cascaded_union([building.geometry for building in buildings])
|
||||
spaces = {space.id: space for space in section.spaces.all()}
|
||||
spaces = {space.id: space for space in level.spaces.all()}
|
||||
holes_geom = []
|
||||
for space in spaces.values():
|
||||
if space.outside:
|
||||
|
@ -38,66 +38,66 @@ class EditorViewSet(ViewSet):
|
|||
|
||||
results = []
|
||||
results.extend(buildings)
|
||||
for door in section.doors.all():
|
||||
for door in level.doors.all():
|
||||
results.append(door)
|
||||
|
||||
results.extend(spaces.values())
|
||||
return results
|
||||
|
||||
def _get_sections_pk(self, section):
|
||||
sections_under = ()
|
||||
sections_on_top = ()
|
||||
lower_section = section.lower().first()
|
||||
primary_sections = (section,) + ((lower_section,) if lower_section else ())
|
||||
secondary_sections = Section.objects.filter(on_top_of__in=primary_sections).values_list('pk', 'on_top_of')
|
||||
if lower_section:
|
||||
sections_under = tuple(pk for pk, on_top_of in secondary_sections if on_top_of == lower_section.pk)
|
||||
def _get_levels_pk(self, level):
|
||||
levels_under = ()
|
||||
levels_on_top = ()
|
||||
lower_level = level.lower().first()
|
||||
primary_levels = (level,) + ((lower_level,) if lower_level else ())
|
||||
secondary_levels = Level.objects.filter(on_top_of__in=primary_levels).values_list('pk', 'on_top_of')
|
||||
if lower_level:
|
||||
levels_under = tuple(pk for pk, on_top_of in secondary_levels if on_top_of == lower_level.pk)
|
||||
if True:
|
||||
sections_on_top = tuple(pk for pk, on_top_of in secondary_sections if on_top_of == section.pk)
|
||||
sections = chain([section.pk], sections_under, sections_on_top)
|
||||
return sections, sections_on_top, sections_under
|
||||
levels_on_top = tuple(pk for pk, on_top_of in secondary_levels if on_top_of == level.pk)
|
||||
levels = chain([level.pk], levels_under, levels_on_top)
|
||||
return levels, levels_on_top, levels_under
|
||||
|
||||
@list_route(methods=['get'])
|
||||
def geometries(self, request, *args, **kwargs):
|
||||
section = request.GET.get('section')
|
||||
level = request.GET.get('level')
|
||||
space = request.GET.get('space')
|
||||
if section is not None:
|
||||
if level is not None:
|
||||
if space is not None:
|
||||
raise ValidationError('Only section or space can be specified.')
|
||||
section = get_object_or_404(Section, pk=section)
|
||||
raise ValidationError('Only level or space can be specified.')
|
||||
level = get_object_or_404(Level, pk=level)
|
||||
|
||||
sections, sections_on_top, sections_under = self._get_sections_pk(section)
|
||||
sections = Section.objects.filter(pk__in=sections).prefetch_related('buildings', 'spaces', 'doors',
|
||||
'spaces__groups', 'spaces__holes',
|
||||
'spaces__columns')
|
||||
sections = {s.pk: s for s in sections}
|
||||
levels, levels_on_top, levels_under = self._get_levels_pk(level)
|
||||
levels = Level.objects.filter(pk__in=levels).prefetch_related('buildings', 'spaces', 'doors',
|
||||
'spaces__groups', 'spaces__holes',
|
||||
'spaces__columns')
|
||||
levels = {s.pk: s for s in levels}
|
||||
|
||||
section = sections[section.pk]
|
||||
sections_under = [sections[pk] for pk in sections_under]
|
||||
sections_on_top = [sections[pk] for pk in sections_on_top]
|
||||
level = levels[level.pk]
|
||||
levels_under = [levels[pk] for pk in levels_under]
|
||||
levels_on_top = [levels[pk] for pk in levels_on_top]
|
||||
|
||||
results = chain(
|
||||
*(self._get_section_geometries(s) for s in sections_under),
|
||||
self._get_section_geometries(section),
|
||||
*(self._get_section_geometries(s) for s in sections_on_top)
|
||||
*(self._get_level_geometries(s) for s in levels_under),
|
||||
self._get_level_geometries(level),
|
||||
*(self._get_level_geometries(s) for s in levels_on_top)
|
||||
)
|
||||
|
||||
return Response([obj.to_geojson() for obj in results])
|
||||
elif space is not None:
|
||||
space = get_object_or_404(Space.objects.select_related('section', 'section__on_top_of'), pk=space)
|
||||
section = space.section
|
||||
space = get_object_or_404(Space.objects.select_related('level', 'level__on_top_of'), pk=space)
|
||||
level = space.level
|
||||
|
||||
doors = [door for door in section.doors.all() if door.geometry.intersects(space.geometry)]
|
||||
doors = [door for door in level.doors.all() if door.geometry.intersects(space.geometry)]
|
||||
doors_space_geom = cascaded_union([door.geometry for door in doors]+[space.geometry])
|
||||
|
||||
sections, sections_on_top, sections_under = self._get_sections_pk(section.primary_section)
|
||||
other_spaces = Space.objects.filter(section__pk__in=sections).prefetch_related('groups')
|
||||
levels, levels_on_top, levels_under = self._get_levels_pk(level.primary_level)
|
||||
other_spaces = Space.objects.filter(level__pk__in=levels).prefetch_related('groups')
|
||||
other_spaces = [s for s in other_spaces
|
||||
if s.geometry.intersects(doors_space_geom) and s.pk != space.pk]
|
||||
|
||||
space.bounds = True
|
||||
|
||||
buildings = section.buildings.all()
|
||||
buildings = level.buildings.all()
|
||||
buildings_geom = cascaded_union([building.geometry for building in buildings])
|
||||
for other_space in other_spaces:
|
||||
if other_space.outside:
|
||||
|
@ -122,7 +122,7 @@ class EditorViewSet(ViewSet):
|
|||
)
|
||||
return Response(sum([self._get_geojsons(obj) for obj in results], ()))
|
||||
else:
|
||||
raise ValidationError('No section or space specified.')
|
||||
raise ValidationError('No level or space specified.')
|
||||
|
||||
def _get_geojsons(self, obj):
|
||||
return ((obj.to_shadow_geojson(),) if hasattr(obj, 'to_shadow_geojson') else ()) + (obj.to_geojson(),)
|
||||
|
|
|
@ -16,9 +16,9 @@ class MapitemFormMixin(ModelForm):
|
|||
super().__init__(*args, **kwargs)
|
||||
creating = not self.instance.pk
|
||||
|
||||
if 'section' in self.fields:
|
||||
# hide section widget
|
||||
self.fields['section'].widget = HiddenInput()
|
||||
if 'level' in self.fields:
|
||||
# hide level widget
|
||||
self.fields['level'].widget = HiddenInput()
|
||||
|
||||
if 'space' in self.fields:
|
||||
# hide space widget
|
||||
|
|
|
@ -110,7 +110,7 @@ legend {
|
|||
right: 8px;
|
||||
top: 8px;
|
||||
}
|
||||
[data-sections], [data-subsections] {
|
||||
[data-levels], [data-sublevels] {
|
||||
display:none;
|
||||
}
|
||||
form button.invisiblesubmit {
|
||||
|
@ -211,47 +211,47 @@ form button.invisiblesubmit {
|
|||
}
|
||||
|
||||
|
||||
/* leaftlet sections control */
|
||||
.leaflet-control-sections {
|
||||
/* leaftlet levels control */
|
||||
.leaflet-control-levels {
|
||||
overflow:hidden;
|
||||
}
|
||||
.leaflet-control-subsections {
|
||||
.leaflet-control-sublevels {
|
||||
position:absolute;
|
||||
}
|
||||
.leaflet-control-sections a, .leaflet-control-sections a:hover {
|
||||
.leaflet-control-levels a, .leaflet-control-levels a:hover {
|
||||
width: auto;
|
||||
font-size: 14px;
|
||||
padding: 0 7px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-sections a, .leaflet-touch .leaflet-control-sections a:hover {
|
||||
.leaflet-touch .leaflet-control-levels a, .leaflet-touch .leaflet-control-levels a:hover {
|
||||
width: auto;
|
||||
height:36px;
|
||||
line-height:37px;
|
||||
font-size: 14px;
|
||||
padding: 0 12px;
|
||||
}
|
||||
.leaflet-control-sections a, .leaflet-control-sections a:hover {
|
||||
.leaflet-control-levels a, .leaflet-control-levels a:hover {
|
||||
opacity:0;
|
||||
margin-top:-26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-sections a, .leaflet-touch .leaflet-control-sections a:hover {
|
||||
.leaflet-touch .leaflet-control-levels a, .leaflet-touch .leaflet-control-levels a:hover {
|
||||
margin-top:-36px;
|
||||
}
|
||||
.leaflet-control-sections a.current, .leaflet-control-sections-expanded a, .leaflet-control-sections-expanded a:hover,
|
||||
.leaflet-touch .leaflet-control-sections a.current, .leaflet-touch .leaflet-control-sections-expanded a,
|
||||
.leaflet-touch .leaflet-control-sections-expanded a:hover {
|
||||
.leaflet-control-levels a.current, .leaflet-control-levels-expanded a, .leaflet-control-levels-expanded a:hover,
|
||||
.leaflet-touch .leaflet-control-levels a.current, .leaflet-touch .leaflet-control-levels-expanded a,
|
||||
.leaflet-touch .leaflet-control-levels-expanded a:hover {
|
||||
opacity:1;
|
||||
margin-top:0;
|
||||
}
|
||||
.leaflet-control-sections:not(.leaflet-control-sections-expanded) a.current {
|
||||
.leaflet-control-levels:not(.leaflet-control-levels-expanded) a.current {
|
||||
border-radius:4px;
|
||||
border-width:0;
|
||||
}
|
||||
.leaflet-control-sections a.current {
|
||||
.leaflet-control-levels a.current {
|
||||
font-weight:bold;
|
||||
}
|
||||
.leaflet-control-sections .leaflet-disabled.current {
|
||||
.leaflet-control-levels .leaflet-disabled.current {
|
||||
color:#000000;
|
||||
background-color:#ffffff;
|
||||
}
|
||||
|
|
|
@ -38,11 +38,11 @@ editor = {
|
|||
$('body').removeClass('show-map');
|
||||
});
|
||||
|
||||
editor._section_control = new SectionControl().addTo(editor.map);
|
||||
editor._subsection_control = new SectionControl({addClasses: 'leaflet-control-subsections'}).addTo(editor.map);
|
||||
editor._level_control = new LevelControl().addTo(editor.map);
|
||||
editor._sublevel_control = new LevelControl({addClasses: 'leaflet-control-sublevels'}).addTo(editor.map);
|
||||
|
||||
editor._section_control_container = $(editor._section_control._container);
|
||||
editor._subsection_control_container = $(editor._subsection_control._container);
|
||||
editor._level_control_container = $(editor._level_control._container);
|
||||
editor._sublevel_control_container = $(editor._sublevel_control._container);
|
||||
|
||||
editor.init_geometries();
|
||||
},
|
||||
|
@ -105,30 +105,30 @@ editor = {
|
|||
},
|
||||
_sidebar_unload: function() {
|
||||
// unload the sidebar. called on sidebar_get and form submit.
|
||||
editor._section_control.disable();
|
||||
editor._subsection_control.disable();
|
||||
editor._level_control.disable();
|
||||
editor._sublevel_control.disable();
|
||||
$('#sidebar').addClass('loading').find('.content').html('');
|
||||
editor._cancel_editing();
|
||||
},
|
||||
_fill_section_control: function (section_control, section_list) {
|
||||
var sections = section_list.find('a');
|
||||
if (sections.length) {
|
||||
_fill_level_control: function (level_control, level_list) {
|
||||
var levels = level_list.find('a');
|
||||
if (levels.length) {
|
||||
var current;
|
||||
for (var i = 0; i < sections.length; i++) {
|
||||
var section = $(sections[i]);
|
||||
section_control.addSection(section.attr('data-id'), section.text(), section.attr('href'), section.is('.current'));
|
||||
for (var i = 0; i < levels.length; i++) {
|
||||
var level = $(levels[i]);
|
||||
level_control.addLevel(level.attr('data-id'), level.text(), level.attr('href'), level.is('.current'));
|
||||
|
||||
}
|
||||
if (sections.length > 1) {
|
||||
section_control.enable();
|
||||
if (levels.length > 1) {
|
||||
level_control.enable();
|
||||
} else {
|
||||
section_control.disable();
|
||||
level_control.disable();
|
||||
}
|
||||
section_control.show()
|
||||
level_control.show()
|
||||
} else {
|
||||
section_control.hide();
|
||||
level_control.hide();
|
||||
}
|
||||
section_control.current_id = parseInt(section_list.attr('data-current-id'));
|
||||
level_control.current_id = parseInt(level_list.attr('data-current-id'));
|
||||
},
|
||||
_sidebar_loaded: function(data) {
|
||||
// sidebar was loaded. load the content. check if there are any redirects. call _check_start_editing.
|
||||
|
@ -157,28 +157,28 @@ editor = {
|
|||
(editing_id.length ? editing_id.attr('data-editing') : null)
|
||||
);
|
||||
$('body').addClass('map-enabled');
|
||||
editor._section_control.clearSections();
|
||||
editor._subsection_control.clearSections();
|
||||
editor._level_control.clearLevels();
|
||||
editor._sublevel_control.clearLevels();
|
||||
|
||||
editor._fill_section_control(editor._section_control, content.find('[data-sections]'));
|
||||
editor._fill_section_control(editor._subsection_control, content.find('[data-subsections]'));
|
||||
editor._fill_level_control(editor._level_control, content.find('[data-levels]'));
|
||||
editor._fill_level_control(editor._sublevel_control, content.find('[data-sublevels]'));
|
||||
|
||||
var section_control_offset = $(editor._section_control_container).position();
|
||||
var offset_parent = $(editor._section_control_container).offsetParent();
|
||||
$(editor._subsection_control._container).css({
|
||||
bottom: offset_parent.height()-section_control_offset.top-editor._section_control_container.height()-parseInt(editor._section_control_container.css('margin-bottom')),
|
||||
right: offset_parent.width()-section_control_offset.left
|
||||
var level_control_offset = $(editor._level_control_container).position();
|
||||
var offset_parent = $(editor._level_control_container).offsetParent();
|
||||
$(editor._sublevel_control._container).css({
|
||||
bottom: offset_parent.height()-level_control_offset.top-editor._level_control_container.height()-parseInt(editor._level_control_container.css('margin-bottom')),
|
||||
right: offset_parent.width()-level_control_offset.left
|
||||
});
|
||||
} else {
|
||||
$('body').removeClass('map-enabled').removeClass('show-map');
|
||||
editor._section_control.hide();
|
||||
editor._subsection_control.hide();
|
||||
editor._level_control.hide();
|
||||
editor._sublevel_control.hide();
|
||||
}
|
||||
},
|
||||
_sidebar_error: function(data) {
|
||||
$('#sidebar').removeClass('loading').find('.content').html('<h3>Error '+data.status+'</h3>'+data.statusText);
|
||||
editor._section_control.hide();
|
||||
editor._subsection_control.hide();
|
||||
editor._level_control.hide();
|
||||
editor._sublevel_control.hide();
|
||||
},
|
||||
_sidebar_link_click: function(e) {
|
||||
// listener for link-clicks in the sidebar.
|
||||
|
@ -314,14 +314,14 @@ editor = {
|
|||
_get_geometry_style: function (feature) {
|
||||
// style callback for GeoJSON loader
|
||||
var style = editor._get_mapitem_type_style(feature.properties.type);
|
||||
if (editor._section_control.current_section_id === editor._subsection_control.current_section_id) {
|
||||
if (editor._subsection_control.section_ids.indexOf(feature.properties.section) >= 0 && editor._section_control.current_section_id !== feature.properties.section) {
|
||||
if (editor._level_control.current_level_id === editor._sublevel_control.current_level_id) {
|
||||
if (editor._sublevel_control.level_ids.indexOf(feature.properties.level) >= 0 && editor._level_control.current_level_id !== feature.properties.level) {
|
||||
style.stroke = true;
|
||||
style.weight = 1;
|
||||
style.color = '#ffffff';
|
||||
}
|
||||
} else {
|
||||
if (editor._subsection_control.current_section_id !== feature.properties.section) {
|
||||
if (editor._sublevel_control.current_level_id !== feature.properties.level) {
|
||||
style.fillOpacity = 0.5;
|
||||
}
|
||||
}
|
||||
|
@ -529,18 +529,18 @@ editor = {
|
|||
};
|
||||
|
||||
|
||||
SectionControl = L.Control.extend({
|
||||
LevelControl = L.Control.extend({
|
||||
options: {
|
||||
position: 'bottomright',
|
||||
addClasses: ''
|
||||
},
|
||||
|
||||
onAdd: function () {
|
||||
this._container = L.DomUtil.create('div', 'leaflet-control-sections leaflet-bar '+this.options.addClasses);
|
||||
this._sectionButtons = [];
|
||||
this._container = L.DomUtil.create('div', 'leaflet-control-levels leaflet-bar '+this.options.addClasses);
|
||||
this._levelButtons = [];
|
||||
//noinspection JSUnusedGlobalSymbols
|
||||
this.current_section_id = null;
|
||||
this.section_ids = [];
|
||||
this.current_level_id = null;
|
||||
this.level_ids = [];
|
||||
this._disabled = true;
|
||||
this._expanded = false;
|
||||
this.hide();
|
||||
|
@ -561,9 +561,9 @@ SectionControl = L.Control.extend({
|
|||
return this._container;
|
||||
},
|
||||
|
||||
addSection: function (id, title, href, current) {
|
||||
this.section_ids.push(parseInt(id));
|
||||
if (current) this.current_section_id = parseInt(id);
|
||||
addLevel: function (id, title, href, current) {
|
||||
this.level_ids.push(parseInt(id));
|
||||
if (current) this.current_level_id = parseInt(id);
|
||||
|
||||
var link = L.DomUtil.create('a', (current ? 'current' : ''), this._container);
|
||||
link.innerHTML = title;
|
||||
|
@ -571,32 +571,32 @@ SectionControl = L.Control.extend({
|
|||
|
||||
L.DomEvent
|
||||
.on(link, 'mousedown dblclick', L.DomEvent.stopPropagation)
|
||||
.on(link, 'click', this._sectionClick, this);
|
||||
.on(link, 'click', this._levelClick, this);
|
||||
|
||||
this._sectionButtons.push(link);
|
||||
this._levelButtons.push(link);
|
||||
return link;
|
||||
},
|
||||
|
||||
clearSections: function() {
|
||||
this.current_section_id = null;
|
||||
this.section_ids = [];
|
||||
for (var i = 0; i < this._sectionButtons.length; i++) {
|
||||
L.DomUtil.remove(this._sectionButtons[i]);
|
||||
clearLevels: function() {
|
||||
this.current_level_id = null;
|
||||
this.level_ids = [];
|
||||
for (var i = 0; i < this._levelButtons.length; i++) {
|
||||
L.DomUtil.remove(this._levelButtons[i]);
|
||||
}
|
||||
this._sectionButtons = [];
|
||||
this._levelButtons = [];
|
||||
},
|
||||
|
||||
disable: function () {
|
||||
for (var i = 0; i < this._sectionButtons.length; i++) {
|
||||
L.DomUtil.addClass(this._sectionButtons[i], 'leaflet-disabled');
|
||||
for (var i = 0; i < this._levelButtons.length; i++) {
|
||||
L.DomUtil.addClass(this._levelButtons[i], 'leaflet-disabled');
|
||||
}
|
||||
this.collapse();
|
||||
this._disabled = true;
|
||||
},
|
||||
|
||||
enable: function () {
|
||||
for (var i = 0; i < this._sectionButtons.length; i++) {
|
||||
L.DomUtil.removeClass(this._sectionButtons[i], 'leaflet-disabled');
|
||||
for (var i = 0; i < this._levelButtons.length; i++) {
|
||||
L.DomUtil.removeClass(this._levelButtons[i], 'leaflet-disabled');
|
||||
}
|
||||
this._disabled = false;
|
||||
},
|
||||
|
@ -609,7 +609,7 @@ SectionControl = L.Control.extend({
|
|||
this._container.style.display = '';
|
||||
},
|
||||
|
||||
_sectionClick: function (e) {
|
||||
_levelClick: function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (!this._expanded) {
|
||||
|
@ -625,13 +625,13 @@ SectionControl = L.Control.extend({
|
|||
expand: function () {
|
||||
if (this._disabled) return;
|
||||
this._expanded = true;
|
||||
L.DomUtil.addClass(this._container, 'leaflet-control-sections-expanded');
|
||||
L.DomUtil.addClass(this._container, 'leaflet-control-levels-expanded');
|
||||
return this;
|
||||
},
|
||||
|
||||
collapse: function () {
|
||||
this._expanded = false;
|
||||
L.DomUtil.removeClass(this._container, 'leaflet-control-sections-expanded');
|
||||
L.DomUtil.removeClass(this._container, 'leaflet-control-levels-expanded');
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
{% include 'editor/fragment_sections.html' %}
|
||||
{% include 'editor/fragment_levels.html' %}
|
||||
|
||||
<h3>{% blocktrans %}Delete {{ model_title }}{% endblocktrans %}</h3>
|
||||
<form action="{{ path }}" method="post">
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
|
||||
{% include 'editor/fragment_sections.html' %}
|
||||
{% include 'editor/fragment_levels.html' %}
|
||||
|
||||
<h3>
|
||||
{% if new %}
|
||||
|
@ -10,8 +10,8 @@
|
|||
{% blocktrans %}Edit {{ model_title }}{% endblocktrans %}
|
||||
{% endif %}
|
||||
{% if on_top_of %}
|
||||
{% with on_top_of.title as on_top_of_section_title %}
|
||||
<small>{% blocktrans %}on top of {{ on_top_of_section_title }}{% endblocktrans %}</small>
|
||||
{% with on_top_of.title as on_top_of_level_title %}
|
||||
<small>{% blocktrans %}on top of {{ on_top_of_level_title }}{% endblocktrans %}</small>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</h3>
|
||||
|
|
26
src/c3nav/editor/templates/editor/fragment_levels.html
Normal file
26
src/c3nav/editor/templates/editor/fragment_levels.html
Normal file
|
@ -0,0 +1,26 @@
|
|||
{% if levels %}
|
||||
<ul data-levels>
|
||||
{% for l in levels %}
|
||||
<li>
|
||||
<a data-id="{{ l.pk }}" href="{% if level_as_pk %}{% url level_url pk=l.id %}{% else %}{% url level_url level=l.id %}{% endif %}"{% if level.primary_level == l %} class="current"{% endif %}>{{ l.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul data-sublevels>
|
||||
{% for l in level.primary_level.sublevels %}
|
||||
<li>
|
||||
<a data-id="{{ l.pk }}" href="{% if level_as_pk %}{% url level_url pk=l.id %}{% else %}{% url level_url level=l.id %}{% endif %}"{% if level == l %} class="current"{% endif %}>{{ l.sublevel_title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% elif level %}
|
||||
<ul data-levels>
|
||||
<li><a data-id="{{ level.primary_level.pk }}" href="" class="current">{{ level.primary_level.title }}</a></li>
|
||||
</ul>
|
||||
<ul data-sublevels>
|
||||
<li><a data-id="{{ level.pk }}" href="" class="current">{{ level.sublevel_title }}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if geometry_url %}
|
||||
<span data-geometry-url="{{ geometry_url }}"></span>
|
||||
{% endif %}
|
|
@ -1,26 +0,0 @@
|
|||
{% if sections %}
|
||||
<ul data-sections>
|
||||
{% for s in sections %}
|
||||
<li>
|
||||
<a data-id="{{ s.pk }}" href="{% if section_as_pk %}{% url section_url pk=s.id %}{% else %}{% url section_url section=s.id %}{% endif %}"{% if section.primary_section == s %} class="current"{% endif %}>{{ s.title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<ul data-subsections>
|
||||
{% for s in section.primary_section.subsections %}
|
||||
<li>
|
||||
<a data-id="{{ s.pk }}" href="{% if section_as_pk %}{% url section_url pk=s.id %}{% else %}{% url section_url section=s.id %}{% endif %}"{% if section == s %} class="current"{% endif %}>{{ s.subsection_title }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% elif section %}
|
||||
<ul data-sections>
|
||||
<li><a data-id="{{ section.primary_section.pk }}" href="" class="current">{{ section.primary_section.title }}</a></li>
|
||||
</ul>
|
||||
<ul data-subsections>
|
||||
<li><a data-id="{{ section.pk }}" href="" class="current">{{ section.subsection_title }}</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% if geometry_url %}
|
||||
<span data-geometry-url="{{ geometry_url }}"></span>
|
||||
{% endif %}
|
|
@ -1,15 +1,15 @@
|
|||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="n" href="{% url 'editor.sections.create' %}">
|
||||
{% trans 'Section' as model_title %}
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="n" href="{% url 'editor.levels.create' %}">
|
||||
{% trans 'Level' as model_title %}
|
||||
{% blocktrans %}New {{ model_title }}{% endblocktrans %}
|
||||
</a>
|
||||
<h3>{% trans 'Sections' %}</h3>
|
||||
<h3>{% trans 'Level' %}</h3>
|
||||
<div class="list-group">
|
||||
{% for s in sections %}
|
||||
<a href="{% url 'editor.sections.detail' pk=s.pk %}" class="list-group-item">
|
||||
{{ s.title }}
|
||||
{% for l in levels %}
|
||||
<a href="{% url 'editor.levels.detail' pk=l.pk %}" class="list-group-item">
|
||||
{{ l.title }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
|
42
src/c3nav/editor/templates/editor/level.html
Normal file
42
src/c3nav/editor/templates/editor/level.html
Normal file
|
@ -0,0 +1,42 @@
|
|||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
{% include 'editor/fragment_levels.html' %}
|
||||
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="e" href="{% url 'editor.levels.edit' pk=level.pk %}">
|
||||
{% trans 'Level' as model_title %}
|
||||
{% blocktrans %}Edit {{ model_title }}{% endblocktrans %}
|
||||
</a>
|
||||
<h3>
|
||||
<h3>
|
||||
{{ level.title }}
|
||||
{% if level.on_top_of != None %}
|
||||
{% with level.on_top_of.title as on_top_of_level_title %}
|
||||
<small>{% blocktrans %}on top of {{ on_top_of_level_title }}{% endblocktrans %}</small>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p>
|
||||
{% if level.on_top_of == None %}
|
||||
<a href="{% url 'editor.index' %}">« {% trans 'back to overview' %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'editor.levels.detail' pk=level.on_top_of.pk %}">« {% trans 'back to parent level' %}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% include 'editor/fragment_child_models.html' %}
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
{% if level.on_top_of == None %}
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="n" href="{% url 'editor.levels_on_top.create' on_top_of=level.pk %}">
|
||||
{% blocktrans %}New {{ model_title }}{% endblocktrans %}
|
||||
</a>
|
||||
<h3>{% trans 'Levels on top' %}</h3>
|
||||
<div class="list-group">
|
||||
{% for l in levels_on_top %}
|
||||
<a href="{% url 'editor.levels.detail' pk=l.pk %}" class="list-group-item">
|
||||
{{ l.title }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
|
@ -1,16 +1,16 @@
|
|||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
|
||||
{% include 'editor/fragment_sections.html' %}
|
||||
{% include 'editor/fragment_levels.html' %}
|
||||
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="n" href="{{ create_url }}">
|
||||
{% blocktrans %}New {{ model_title }}{% endblocktrans %}
|
||||
</a>
|
||||
<h3>
|
||||
{% blocktrans %}{{ model_title_plural }}{% endblocktrans %}
|
||||
{% if section %}
|
||||
{% with section.title as section_title %}
|
||||
<small>{% blocktrans %}in section {{ section_title }}{% endblocktrans %}</small>
|
||||
{% if level %}
|
||||
{% with level.title as level_title %}
|
||||
<small>{% blocktrans %}on level {{ level_title }}{% endblocktrans %}</small>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
{% if space %}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
{% include 'editor/fragment_sections.html' %}
|
||||
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="e" href="{% url 'editor.sections.edit' pk=section.pk %}">
|
||||
{% trans 'Section' as model_title %}
|
||||
{% blocktrans %}Edit {{ model_title }}{% endblocktrans %}
|
||||
</a>
|
||||
<h3>
|
||||
{{ section.title }}
|
||||
{% if section.on_top_of != None %}
|
||||
{% with section.on_top_of.title as on_top_of_section_title %}
|
||||
<small>{% blocktrans %}on top of {{ on_top_of_section_title }}{% endblocktrans %}</small>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
</h3>
|
||||
<p>
|
||||
{% if section.on_top_of == None %}
|
||||
<a href="{% url 'editor.index' %}">« {% trans 'back to overview' %}</a>
|
||||
{% else %}
|
||||
<a href="{% url 'editor.sections.detail' pk=section.on_top_of.pk %}">« {% trans 'back to parent section' %}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
|
||||
{% include 'editor/fragment_child_models.html' %}
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
{% if section.on_top_of == None %}
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="n" href="{% url 'editor.sections_on_top.create' on_top_of=section.pk %}">
|
||||
{% blocktrans %}New {{ model_title }}{% endblocktrans %}
|
||||
</a>
|
||||
<h3>{% trans 'Sections on top' %}</h3>
|
||||
<div class="list-group">
|
||||
{% for s in sections_on_top %}
|
||||
<a href="{% url 'editor.sections.detail' pk=s.pk %}" class="list-group-item">
|
||||
{{ s.title }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
|
@ -1,14 +1,14 @@
|
|||
{% load bootstrap3 %}
|
||||
{% load i18n %}
|
||||
{% include 'editor/fragment_sections.html' %}
|
||||
{% include 'editor/fragment_levels.html' %}
|
||||
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="e" href="{% url 'editor.spaces.edit' section=space.section.pk pk=space.pk %}">
|
||||
<a class="btn btn-default btn-sm pull-right" accesskey="e" href="{% url 'editor.spaces.edit' level=space.level.pk pk=space.pk %}">
|
||||
{% trans 'Space' as model_title %}
|
||||
{% blocktrans %}Edit {{ model_title }}{% endblocktrans %}
|
||||
</a>
|
||||
<h3>{{ space.title }}</h3>
|
||||
<p>
|
||||
<a href="{% url 'editor.spaces.list' section=space.section.pk %}">« {% trans 'back to overview' %}</a>
|
||||
<a href="{% url 'editor.spaces.list' level=space.level.pk %}">« {% trans 'back to overview' %}</a>
|
||||
</p>
|
||||
|
||||
{% include 'editor/fragment_child_models.html' %}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from django.apps import apps
|
||||
from django.conf.urls import url
|
||||
|
||||
from c3nav.editor.views import edit, list_objects, main_index, section_detail, space_detail
|
||||
from c3nav.editor.views import edit, level_detail, list_objects, main_index, space_detail
|
||||
|
||||
|
||||
def add_editor_urls(model_name, parent_model_name=None, with_list=True, explicit_edit=False):
|
||||
|
@ -30,17 +30,17 @@ def add_editor_urls(model_name, parent_model_name=None, with_list=True, explicit
|
|||
|
||||
urlpatterns = [
|
||||
url(r'^$', main_index, name='editor.index'),
|
||||
url(r'^sections/(?P<pk>[0-9]+)/$', section_detail, name='editor.sections.detail'),
|
||||
url(r'^sections/(?P<section>[0-9]+)/spaces/(?P<pk>[0-9]+)/$', space_detail, name='editor.spaces.detail'),
|
||||
url(r'^sections/(?P<on_top_of>[0-9]+)/sections_on_top/create$', edit, name='editor.sections_on_top.create',
|
||||
kwargs={'model': 'Section'}),
|
||||
url(r'^levels/(?P<pk>[0-9]+)/$', level_detail, name='editor.levels.detail'),
|
||||
url(r'^levels/(?P<level>[0-9]+)/spaces/(?P<pk>[0-9]+)/$', space_detail, name='editor.spaces.detail'),
|
||||
url(r'^levels/(?P<on_top_of>[0-9]+)/levels_on_top/create$', edit, name='editor.levels_on_top.create',
|
||||
kwargs={'model': 'Level'}),
|
||||
]
|
||||
urlpatterns.extend(add_editor_urls('Section', with_list=False, explicit_edit=True))
|
||||
urlpatterns.extend(add_editor_urls('Level', with_list=False, explicit_edit=True))
|
||||
urlpatterns.extend(add_editor_urls('LocationGroup'))
|
||||
urlpatterns.extend(add_editor_urls('Source'))
|
||||
urlpatterns.extend(add_editor_urls('Building', 'Section'))
|
||||
urlpatterns.extend(add_editor_urls('Space', 'Section', explicit_edit=True))
|
||||
urlpatterns.extend(add_editor_urls('Door', 'Section'))
|
||||
urlpatterns.extend(add_editor_urls('Building', 'Level'))
|
||||
urlpatterns.extend(add_editor_urls('Space', 'Level', explicit_edit=True))
|
||||
urlpatterns.extend(add_editor_urls('Door', 'Level'))
|
||||
urlpatterns.extend(add_editor_urls('Hole', 'Space'))
|
||||
urlpatterns.extend(add_editor_urls('Area', 'Space'))
|
||||
urlpatterns.extend(add_editor_urls('Stair', 'Space'))
|
||||
|
|
|
@ -10,7 +10,7 @@ from django.urls import reverse
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.views.decorators.cache import never_cache
|
||||
|
||||
from c3nav.mapdata.models import Section, Space
|
||||
from c3nav.mapdata.models import Level, Space
|
||||
from c3nav.mapdata.models.base import EDITOR_FORM_MODELS
|
||||
|
||||
|
||||
|
@ -39,7 +39,7 @@ def child_model(model_name, kwargs=None, parent=None):
|
|||
@sidebar_view
|
||||
def main_index(request):
|
||||
return render(request, 'editor/index.html', {
|
||||
'sections': Section.objects.filter(on_top_of__isnull=True),
|
||||
'levels': Level.objects.filter(on_top_of__isnull=True),
|
||||
'child_models': [
|
||||
child_model('LocationGroup'),
|
||||
child_model('Source'),
|
||||
|
@ -48,28 +48,28 @@ def main_index(request):
|
|||
|
||||
|
||||
@sidebar_view
|
||||
def section_detail(request, pk):
|
||||
section = get_object_or_404(Section.objects.select_related('on_top_of'), pk=pk)
|
||||
def level_detail(request, pk):
|
||||
level = get_object_or_404(Level.objects.select_related('on_top_of'), pk=pk)
|
||||
|
||||
return render(request, 'editor/section.html', {
|
||||
'sections': Section.objects.filter(on_top_of__isnull=True),
|
||||
'section': section,
|
||||
'section_url': 'editor.sections.detail',
|
||||
'section_as_pk': True,
|
||||
return render(request, 'editor/level.html', {
|
||||
'levels': Level.objects.filter(on_top_of__isnull=True),
|
||||
'level': level,
|
||||
'level_url': 'editor.levels.detail',
|
||||
'level_as_pk': True,
|
||||
|
||||
'child_models': [child_model(model_name, kwargs={'section': pk}, parent=section)
|
||||
'child_models': [child_model(model_name, kwargs={'level': pk}, parent=level)
|
||||
for model_name in ('Building', 'Space', 'Door')],
|
||||
'sections_on_top': section.sections_on_top.all(),
|
||||
'geometry_url': '/api/editor/geometries/?section='+str(section.primary_section_pk),
|
||||
'levels_on_top': level.levels_on_top.all(),
|
||||
'geometry_url': '/api/editor/geometries/?level='+str(level.primary_level_pk),
|
||||
})
|
||||
|
||||
|
||||
@sidebar_view
|
||||
def space_detail(request, section, pk):
|
||||
space = get_object_or_404(Space, section__id=section, pk=pk)
|
||||
def space_detail(request, level, pk):
|
||||
space = get_object_or_404(Space, level__id=level, pk=pk)
|
||||
|
||||
return render(request, 'editor/space.html', {
|
||||
'section': space.section,
|
||||
'level': space.level,
|
||||
'space': space,
|
||||
|
||||
'child_models': [child_model(model_name, kwargs={'space': pk}, parent=space)
|
||||
|
@ -79,7 +79,7 @@ def space_detail(request, section, pk):
|
|||
|
||||
|
||||
@sidebar_view
|
||||
def edit(request, pk=None, model=None, section=None, space=None, on_top_of=None, explicit_edit=False):
|
||||
def edit(request, pk=None, model=None, level=None, space=None, on_top_of=None, explicit_edit=False):
|
||||
model = EDITOR_FORM_MODELS[model]
|
||||
related_name = model._meta.default_related_name
|
||||
|
||||
|
@ -87,19 +87,19 @@ def edit(request, pk=None, model=None, section=None, space=None, on_top_of=None,
|
|||
if pk is not None:
|
||||
# Edit existing map item
|
||||
kwargs = {'pk': pk}
|
||||
if section is not None:
|
||||
kwargs.update({'section__id': section})
|
||||
if level is not None:
|
||||
kwargs.update({'level__id': level})
|
||||
elif space is not None:
|
||||
kwargs.update({'space__id': space})
|
||||
obj = get_object_or_404(model, **kwargs)
|
||||
if False: # todo can access
|
||||
raise PermissionDenied
|
||||
elif section is not None:
|
||||
section = get_object_or_404(Section, pk=section)
|
||||
elif level is not None:
|
||||
level = get_object_or_404(Level, pk=level)
|
||||
elif space is not None:
|
||||
space = get_object_or_404(Space, pk=space)
|
||||
elif on_top_of is not None:
|
||||
on_top_of = get_object_or_404(Section.objects.filter(on_top_of__isnull=True), pk=on_top_of)
|
||||
on_top_of = get_object_or_404(Level.objects.filter(on_top_of__isnull=True), pk=on_top_of)
|
||||
|
||||
new = obj is None
|
||||
# noinspection PyProtectedMember
|
||||
|
@ -117,55 +117,55 @@ def edit(request, pk=None, model=None, section=None, space=None, on_top_of=None,
|
|||
'geomtype': model._meta.get_field('geometry').geomtype,
|
||||
})
|
||||
|
||||
if model == Section:
|
||||
if model == Level:
|
||||
ctx.update({
|
||||
'section': obj,
|
||||
'back_url': reverse('editor.index') if new else reverse('editor.sections.detail', kwargs={'pk': pk}),
|
||||
'level': obj,
|
||||
'back_url': reverse('editor.index') if new else reverse('editor.levels.detail', kwargs={'pk': pk}),
|
||||
})
|
||||
if not new:
|
||||
ctx.update({
|
||||
'geometry_url': '/api/editor/geometries/?section='+str(obj.primary_section_pk),
|
||||
'geometry_url': '/api/editor/geometries/?level='+str(obj.primary_level_pk),
|
||||
'on_top_of': obj.on_top_of,
|
||||
})
|
||||
elif on_top_of:
|
||||
ctx.update({
|
||||
'geometry_url': '/api/editor/geometries/?section=' + str(on_top_of.pk),
|
||||
'geometry_url': '/api/editor/geometries/?level=' + str(on_top_of.pk),
|
||||
'on_top_of': on_top_of,
|
||||
'back_url': reverse('editor.sections.detail', kwargs={'pk': on_top_of.pk}),
|
||||
'back_url': reverse('editor.levels.detail', kwargs={'pk': on_top_of.pk}),
|
||||
})
|
||||
elif model == Space and not new:
|
||||
section = obj.section
|
||||
level = obj.level
|
||||
ctx.update({
|
||||
'section': obj.section,
|
||||
'back_url': reverse('editor.spaces.detail', kwargs={'section': obj.section.pk, 'pk': pk}),
|
||||
'level': obj.level,
|
||||
'back_url': reverse('editor.spaces.detail', kwargs={'level': obj.level.pk, 'pk': pk}),
|
||||
'geometry_url': '/api/editor/geometries/?space='+pk,
|
||||
})
|
||||
elif model == Space and new:
|
||||
ctx.update({
|
||||
'section': section,
|
||||
'back_url': reverse('editor.spaces.list', kwargs={'section': section.pk}),
|
||||
'geometry_url': '/api/editor/geometries/?section='+str(section.primary_section_pk),
|
||||
'level': level,
|
||||
'back_url': reverse('editor.spaces.list', kwargs={'level': level.pk}),
|
||||
'geometry_url': '/api/editor/geometries/?level='+str(level.primary_level_pk),
|
||||
})
|
||||
elif hasattr(model, 'section'):
|
||||
elif hasattr(model, 'level'):
|
||||
if obj:
|
||||
section = obj.section
|
||||
level = obj.level
|
||||
ctx.update({
|
||||
'section': section,
|
||||
'back_url': reverse('editor.'+related_name+'.list', kwargs={'section': section.pk}),
|
||||
'geometry_url': '/api/editor/geometries/?section='+str(section.primary_section_pk),
|
||||
'level': level,
|
||||
'back_url': reverse('editor.'+related_name+'.list', kwargs={'level': level.pk}),
|
||||
'geometry_url': '/api/editor/geometries/?level='+str(level.primary_level_pk),
|
||||
})
|
||||
elif hasattr(model, 'space'):
|
||||
if obj:
|
||||
space = obj.space
|
||||
ctx.update({
|
||||
'section': space.section,
|
||||
'level': space.level,
|
||||
'back_url': reverse('editor.'+related_name+'.list', kwargs={'space': space.pk}),
|
||||
'geometry_url': '/api/editor/geometries/?space='+str(space.pk),
|
||||
})
|
||||
else:
|
||||
kwargs = {}
|
||||
if section is not None:
|
||||
kwargs.update({'section': section})
|
||||
if level is not None:
|
||||
kwargs.update({'level': level})
|
||||
elif space is not None:
|
||||
kwargs.update({'space': space})
|
||||
|
||||
|
@ -181,12 +181,12 @@ def edit(request, pk=None, model=None, section=None, space=None, on_top_of=None,
|
|||
# todo: suggest changes
|
||||
raise NotImplementedError
|
||||
obj.delete()
|
||||
if model == Section:
|
||||
if model == Level:
|
||||
if obj.on_top_of_id is not None:
|
||||
return redirect(reverse('editor.sections.detail', kwargs={'pk': obj.on_top_of_id}))
|
||||
return redirect(reverse('editor.levels.detail', kwargs={'pk': obj.on_top_of_id}))
|
||||
return redirect(reverse('editor.index'))
|
||||
elif model == Space:
|
||||
return redirect(reverse('editor.spaces.list', kwargs={'section': obj.section.pk}))
|
||||
return redirect(reverse('editor.spaces.list', kwargs={'level': obj.level.pk}))
|
||||
return redirect(ctx['back_url'])
|
||||
ctx['obj_title'] = obj.title
|
||||
return render(request, 'editor/delete.html', ctx)
|
||||
|
@ -213,8 +213,8 @@ def edit(request, pk=None, model=None, section=None, space=None, on_top_of=None,
|
|||
# todo: suggest changes
|
||||
raise NotImplementedError
|
||||
|
||||
if section is not None:
|
||||
obj.section = section
|
||||
if level is not None:
|
||||
obj.level = level
|
||||
|
||||
if space is not None:
|
||||
obj.space = space
|
||||
|
@ -237,7 +237,7 @@ def edit(request, pk=None, model=None, section=None, space=None, on_top_of=None,
|
|||
|
||||
|
||||
@sidebar_view
|
||||
def list_objects(request, model=None, section=None, space=None, explicit_edit=False):
|
||||
def list_objects(request, model=None, level=None, space=None, explicit_edit=False):
|
||||
model = EDITOR_FORM_MODELS[model]
|
||||
if not request.resolver_match.url_name.endswith('.list'):
|
||||
raise ValueError('url_name does not end with .list')
|
||||
|
@ -254,25 +254,25 @@ def list_objects(request, model=None, section=None, space=None, explicit_edit=Fa
|
|||
queryset = model.objects.all().order_by('id')
|
||||
reverse_kwargs = {}
|
||||
|
||||
if section is not None:
|
||||
reverse_kwargs['section'] = section
|
||||
section = get_object_or_404(Section, pk=section)
|
||||
queryset = queryset.filter(section=section)
|
||||
if level is not None:
|
||||
reverse_kwargs['level'] = level
|
||||
level = get_object_or_404(Level, pk=level)
|
||||
queryset = queryset.filter(level=level)
|
||||
ctx.update({
|
||||
'back_url': reverse('editor.sections.detail', kwargs={'pk': section.pk}),
|
||||
'back_title': _('back to section'),
|
||||
'sections': Section.objects.filter(on_top_of__isnull=True),
|
||||
'section': section,
|
||||
'section_url': request.resolver_match.url_name,
|
||||
'geometry_url': '/api/editor/geometries/?section='+str(section.primary_section_pk),
|
||||
'back_url': reverse('editor.levels.detail', kwargs={'pk': level.pk}),
|
||||
'back_title': _('back to level'),
|
||||
'levels': Level.objects.filter(on_top_of__isnull=True),
|
||||
'level': level,
|
||||
'level_url': request.resolver_match.url_name,
|
||||
'geometry_url': '/api/editor/geometries/?level='+str(level.primary_level_pk),
|
||||
})
|
||||
elif space is not None:
|
||||
reverse_kwargs['space'] = space
|
||||
space = get_object_or_404(Space, pk=space)
|
||||
queryset = queryset.filter(space=space)
|
||||
ctx.update({
|
||||
'section': space.section,
|
||||
'back_url': reverse('editor.spaces.detail', kwargs={'section': space.section.pk, 'pk': space.pk}),
|
||||
'level': space.level,
|
||||
'back_url': reverse('editor.spaces.detail', kwargs={'level': space.level.pk, 'pk': space.pk}),
|
||||
'back_title': _('back to space'),
|
||||
'geometry_url': '/api/editor/geometries/?space='+str(space.pk),
|
||||
})
|
||||
|
|
|
@ -12,24 +12,24 @@ from rest_framework.response import Response
|
|||
from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet
|
||||
|
||||
from c3nav.mapdata.models import Building, Door, Hole, LocationGroup, Source, Space
|
||||
from c3nav.mapdata.models.geometry.section import SECTION_MODELS
|
||||
from c3nav.mapdata.models.geometry.level import LEVEL_MODELS
|
||||
from c3nav.mapdata.models.geometry.space import SPACE_MODELS, Area, Column, LineObstacle, Obstacle, Point, Stair
|
||||
from c3nav.mapdata.models.level import Level
|
||||
from c3nav.mapdata.models.locations import LOCATION_MODELS, Location, LocationRedirect, LocationSlug
|
||||
from c3nav.mapdata.models.section import Section
|
||||
|
||||
|
||||
class MapdataViewSet(ReadOnlyModelViewSet):
|
||||
def list(self, request, *args, **kwargs):
|
||||
qs = self.get_queryset()
|
||||
geometry = ('geometry' in request.GET)
|
||||
if qs.model in SECTION_MODELS and 'section' in request.GET:
|
||||
if not request.GET['section'].isdigit():
|
||||
raise ValidationError(detail={'detail': _('%s is not an integer.') % 'section'})
|
||||
if qs.model in LEVEL_MODELS and 'level' in request.GET:
|
||||
if not request.GET['level'].isdigit():
|
||||
raise ValidationError(detail={'detail': _('%s is not an integer.') % 'level'})
|
||||
try:
|
||||
section = Section.objects.get(pk=request.GET['section'])
|
||||
except Section.DoesNotExist:
|
||||
raise NotFound(detail=_('section not found.'))
|
||||
qs = qs.filter(section=section)
|
||||
level = Level.objects.get(pk=request.GET['level'])
|
||||
except Level.DoesNotExist:
|
||||
raise NotFound(detail=_('level not found.'))
|
||||
qs = qs.filter(level=level)
|
||||
if qs.model in SPACE_MODELS and 'space' in request.GET:
|
||||
if not request.GET['space'].isdigit():
|
||||
raise ValidationError(detail={'detail': _('%s is not an integer.') % 'space'})
|
||||
|
@ -38,17 +38,17 @@ class MapdataViewSet(ReadOnlyModelViewSet):
|
|||
except Space.DoesNotExist:
|
||||
raise NotFound(detail=_('space not found.'))
|
||||
qs = qs.filter(space=space)
|
||||
if qs.model == Section and 'on_top_of' in request.GET:
|
||||
if qs.model == Level and 'on_top_of' in request.GET:
|
||||
if request.GET['on_top_of'] == 'null':
|
||||
qs = qs.filter(on_top_of__isnull=False)
|
||||
else:
|
||||
if not request.GET['on_top_of'].isdigit():
|
||||
raise ValidationError(detail={'detail': _('%s is not null or an integer.') % 'on_top_of'})
|
||||
try:
|
||||
section = Section.objects.get(pk=request.GET['on_top_of'])
|
||||
except Section.DoesNotExist:
|
||||
raise NotFound(detail=_('section not found.'))
|
||||
qs = qs.filter(on_top_of=section)
|
||||
level = Level.objects.get(pk=request.GET['on_top_of'])
|
||||
except Level.DoesNotExist:
|
||||
raise NotFound(detail=_('level not found.'))
|
||||
qs = qs.filter(on_top_of=level)
|
||||
return Response([obj.serialize(geometry=geometry) for obj in qs.order_by('id')])
|
||||
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
|
@ -61,28 +61,28 @@ class MapdataViewSet(ReadOnlyModelViewSet):
|
|||
])
|
||||
|
||||
|
||||
class SectionViewSet(MapdataViewSet):
|
||||
class LevelViewSet(MapdataViewSet):
|
||||
""" Add ?on_top_of=null or ?on_top_of=<id> to filter by on_top_of. """
|
||||
queryset = Section.objects.all()
|
||||
queryset = Level.objects.all()
|
||||
|
||||
@list_route(methods=['get'])
|
||||
def geometrytypes(self, request):
|
||||
return self.list_types(SECTION_MODELS)
|
||||
return self.list_types(LEVEL_MODELS)
|
||||
|
||||
@detail_route(methods=['get'])
|
||||
def svg(self, requests, pk=None):
|
||||
section = self.get_object()
|
||||
response = HttpResponse(section.render_svg(), 'image/svg+xml')
|
||||
level = self.get_object()
|
||||
response = HttpResponse(level.render_svg(), 'image/svg+xml')
|
||||
return response
|
||||
|
||||
|
||||
class BuildingViewSet(MapdataViewSet):
|
||||
""" Add ?geometry=1 to get geometries, add ?section=<id> to filter by section. """
|
||||
""" Add ?geometry=1 to get geometries, add ?level=<id> to filter by level. """
|
||||
queryset = Building.objects.all()
|
||||
|
||||
|
||||
class SpaceViewSet(MapdataViewSet):
|
||||
""" Add ?geometry=1 to get geometries, add ?section=<id> to filter by section. """
|
||||
""" Add ?geometry=1 to get geometries, add ?level=<id> to filter by level. """
|
||||
queryset = Space.objects.all()
|
||||
|
||||
@list_route(methods=['get'])
|
||||
|
@ -91,7 +91,7 @@ class SpaceViewSet(MapdataViewSet):
|
|||
|
||||
|
||||
class DoorViewSet(MapdataViewSet):
|
||||
""" Add ?geometry=1 to get geometries, add ?section=<id> to filter by section. """
|
||||
""" Add ?geometry=1 to get geometries, add ?level=<id> to filter by level. """
|
||||
queryset = Door.objects.all()
|
||||
|
||||
|
||||
|
|
|
@ -33,8 +33,8 @@ class MapdataConfig(AppConfig):
|
|||
from c3nav.mapdata.models.locations import Location, LOCATION_MODELS
|
||||
LOCATION_MODELS.extend(self._get_submodels(Location))
|
||||
|
||||
from c3nav.mapdata.models.geometry.section import SectionGeometryMixin, SECTION_MODELS
|
||||
SECTION_MODELS.extend(self._get_submodels(SectionGeometryMixin))
|
||||
from c3nav.mapdata.models.geometry.level import LevelGeometryMixin, LEVEL_MODELS
|
||||
LEVEL_MODELS.extend(self._get_submodels(LevelGeometryMixin))
|
||||
|
||||
from c3nav.mapdata.models.geometry.space import SpaceGeometryMixin, SPACE_MODELS
|
||||
SPACE_MODELS.extend(self._get_submodels(SpaceGeometryMixin))
|
||||
|
|
81
src/c3nav/mapdata/migrations/0012_rename_section_to_level.py
Normal file
81
src/c3nav/mapdata/migrations/0012_rename_section_to_level.py
Normal file
|
@ -0,0 +1,81 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Generated by Django 1.11.2 on 2017-06-11 12:06
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mapdata', '0011_outside_only_outside'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name='Section',
|
||||
new_name='Level',
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='level',
|
||||
options={'ordering': ['altitude'], 'verbose_name': 'Level', 'verbose_name_plural': 'Levels'},
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='building',
|
||||
old_name='section',
|
||||
new_name='level',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='door',
|
||||
old_name='section',
|
||||
new_name='level',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='space',
|
||||
old_name='section',
|
||||
new_name='level',
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='level',
|
||||
name='altitude',
|
||||
field=models.DecimalField(decimal_places=2, max_digits=6, unique=True, verbose_name='level altitude'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='level',
|
||||
name='groups',
|
||||
field=models.ManyToManyField(blank=True, related_name='levels', to='mapdata.LocationGroup',
|
||||
verbose_name='Location Groups'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='level',
|
||||
name='locationslug_ptr',
|
||||
field=models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True,
|
||||
primary_key=True, related_name='levels', serialize=False,
|
||||
to='mapdata.LocationSlug'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='level',
|
||||
name='on_top_of',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name='levels_on_top', to='mapdata.Level', verbose_name='on top of'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='building',
|
||||
name='level',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='buildings',
|
||||
to='mapdata.Level', verbose_name='level'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='door',
|
||||
name='level',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='doors',
|
||||
to='mapdata.Level', verbose_name='level'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='space',
|
||||
name='level',
|
||||
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='spaces',
|
||||
to='mapdata.Level', verbose_name='level'),
|
||||
),
|
||||
]
|
|
@ -1,5 +1,5 @@
|
|||
from .section import Section # noqa
|
||||
from .level import Level # noqa
|
||||
from .source import Source # noqa
|
||||
from c3nav.mapdata.models.geometry.section import Building, Space, Door # noqa
|
||||
from c3nav.mapdata.models.geometry.level import Building, Space, Door # noqa
|
||||
from c3nav.mapdata.models.geometry.space import Area, Stair, Obstacle, LineObstacle, Hole # noqa
|
||||
from .locations import Location, LocationSlug, LocationGroup # noqa
|
||||
|
|
|
@ -57,7 +57,7 @@ class BoundsMixin(SerializableMixin, models.Model):
|
|||
return ((float(result['bottom__min']), float(result['left__min'])),
|
||||
(float(result['top__max']), float(result['right__max'])))
|
||||
|
||||
def _serialize(self, section=True, **kwargs):
|
||||
def _serialize(self, level=True, **kwargs):
|
||||
result = super()._serialize(**kwargs)
|
||||
result['bounds'] = self.bounds
|
||||
return result
|
||||
|
|
|
@ -5,18 +5,18 @@ from c3nav.mapdata.fields import GeometryField
|
|||
from c3nav.mapdata.models.geometry.base import GeometryMixin
|
||||
from c3nav.mapdata.models.locations import SpecificLocation
|
||||
|
||||
SECTION_MODELS = []
|
||||
LEVEL_MODELS = []
|
||||
|
||||
|
||||
class SectionGeometryMixin(GeometryMixin):
|
||||
section = models.ForeignKey('mapdata.Section', on_delete=models.CASCADE, verbose_name=_('section'))
|
||||
class LevelGeometryMixin(GeometryMixin):
|
||||
level = models.ForeignKey('mapdata.Level', on_delete=models.CASCADE, verbose_name=_('level'))
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
def get_geojson_properties(self) -> dict:
|
||||
result = super().get_geojson_properties()
|
||||
result['section'] = self.section_id
|
||||
result['level'] = self.level_id
|
||||
if hasattr(self, 'get_color'):
|
||||
color = self.get_color()
|
||||
if color:
|
||||
|
@ -25,14 +25,14 @@ class SectionGeometryMixin(GeometryMixin):
|
|||
result['opacity'] = self.opacity
|
||||
return result
|
||||
|
||||
def _serialize(self, section=True, **kwargs):
|
||||
def _serialize(self, level=True, **kwargs):
|
||||
result = super()._serialize(**kwargs)
|
||||
if section:
|
||||
result['section'] = self.section.id
|
||||
if level:
|
||||
result['level'] = self.level_id
|
||||
return result
|
||||
|
||||
|
||||
class Building(SectionGeometryMixin, models.Model):
|
||||
class Building(LevelGeometryMixin, models.Model):
|
||||
"""
|
||||
The outline of a building on a specific level
|
||||
"""
|
||||
|
@ -44,9 +44,9 @@ class Building(SectionGeometryMixin, models.Model):
|
|||
default_related_name = 'buildings'
|
||||
|
||||
|
||||
class Space(SpecificLocation, SectionGeometryMixin, models.Model):
|
||||
class Space(SpecificLocation, LevelGeometryMixin, models.Model):
|
||||
"""
|
||||
An accessible space. Shouldn't overlap with spaces on same section.
|
||||
An accessible space. Shouldn't overlap with spaces on the same level.
|
||||
"""
|
||||
CATEGORIES = (
|
||||
('normal', _('normal')),
|
||||
|
@ -81,7 +81,7 @@ class Space(SpecificLocation, SectionGeometryMixin, models.Model):
|
|||
return color
|
||||
|
||||
|
||||
class Door(SectionGeometryMixin, models.Model):
|
||||
class Door(LevelGeometryMixin, models.Model):
|
||||
"""
|
||||
A connection between two spaces
|
||||
"""
|
|
@ -11,18 +11,18 @@ from c3nav.mapdata.models.locations import SpecificLocation
|
|||
from c3nav.mapdata.utils.svg import SVGImage
|
||||
|
||||
|
||||
class Section(SpecificLocation, EditorFormMixin, models.Model):
|
||||
class Level(SpecificLocation, EditorFormMixin, models.Model):
|
||||
"""
|
||||
A map section like a level
|
||||
A map level
|
||||
"""
|
||||
altitude = models.DecimalField(_('section altitude'), null=False, unique=True, max_digits=6, decimal_places=2)
|
||||
on_top_of = models.ForeignKey('mapdata.Section', null=True, on_delete=models.CASCADE,
|
||||
related_name='sections_on_top', verbose_name=_('on top of'))
|
||||
altitude = models.DecimalField(_('level altitude'), null=False, unique=True, max_digits=6, decimal_places=2)
|
||||
on_top_of = models.ForeignKey('mapdata.Level', null=True, on_delete=models.CASCADE,
|
||||
related_name='levels_on_top', verbose_name=_('on top of'))
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Section')
|
||||
verbose_name_plural = _('Sections')
|
||||
default_related_name = 'sections'
|
||||
verbose_name = _('Level')
|
||||
verbose_name_plural = _('Levels')
|
||||
default_related_name = 'levels'
|
||||
ordering = ['altitude']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -31,32 +31,32 @@ class Section(SpecificLocation, EditorFormMixin, models.Model):
|
|||
def lower(self):
|
||||
if self.on_top_of is not None:
|
||||
raise TypeError
|
||||
return Section.objects.filter(altitude__lt=self.altitude, on_top_of__isnull=True).order_by('-altitude')
|
||||
return Level.objects.filter(altitude__lt=self.altitude, on_top_of__isnull=True).order_by('-altitude')
|
||||
|
||||
def higher(self):
|
||||
if self.on_top_of is not None:
|
||||
raise TypeError
|
||||
return Section.objects.filter(altitude__gt=self.altitude, on_top_of__isnull=True).order_by('altitude')
|
||||
return Level.objects.filter(altitude__gt=self.altitude, on_top_of__isnull=True).order_by('altitude')
|
||||
|
||||
@property
|
||||
def subsections(self):
|
||||
def sublevels(self):
|
||||
if self.on_top_of is not None:
|
||||
raise TypeError
|
||||
return chain((self, ), self.sections_on_top.all())
|
||||
return chain((self, ), self.levels_on_top.all())
|
||||
|
||||
@property
|
||||
def subsection_title(self):
|
||||
def sublevel_title(self):
|
||||
return '-' if self.on_top_of_id is None else self.title
|
||||
|
||||
@property
|
||||
def primary_section(self):
|
||||
def primary_level(self):
|
||||
return self if self.on_top_of_id is None else self.on_top_of
|
||||
|
||||
@property
|
||||
def primary_section_pk(self):
|
||||
def primary_level_pk(self):
|
||||
return self.pk if self.on_top_of_id is None else self.on_top_of_id
|
||||
|
||||
def _serialize(self, section=True, **kwargs):
|
||||
def _serialize(self, level=True, **kwargs):
|
||||
result = super()._serialize(**kwargs)
|
||||
result['altitude'] = float(str(self.altitude))
|
||||
return result
|
||||
|
@ -109,10 +109,10 @@ class Section(SpecificLocation, EditorFormMixin, models.Model):
|
|||
# draw space background
|
||||
doors = self.doors.all()
|
||||
door_geometries = cascaded_union(tuple(d.geometry for d in doors))
|
||||
section_geometry = cascaded_union((space_geometries, building_geometries, door_geometries))
|
||||
section_geometry = section_geometry.difference(hole_geometries)
|
||||
section_clip = svg.register_geometry(section_geometry, defid='section', as_clip_path=True)
|
||||
svg.add_geometry(fill_color='#d1d1d1', clip_path=section_clip)
|
||||
level_geometry = cascaded_union((space_geometries, building_geometries, door_geometries))
|
||||
level_geometry = level_geometry.difference(hole_geometries)
|
||||
level_clip = svg.register_geometry(level_geometry, defid='level', as_clip_path=True)
|
||||
svg.add_geometry(fill_color='#d1d1d1', clip_path=level_clip)
|
||||
|
||||
# color in spaces
|
||||
spaces_by_color = {}
|
||||
|
@ -134,7 +134,7 @@ class Section(SpecificLocation, EditorFormMixin, models.Model):
|
|||
if effects:
|
||||
wall_dilated_geometry = wall_geometry.buffer(0.7, join_style=JOIN_STYLE.mitre)
|
||||
svg.add_geometry(wall_dilated_geometry, fill_color='#000000', opacity=0.1, filter='wallblur',
|
||||
clip_path=section_clip)
|
||||
clip_path=level_clip)
|
||||
|
||||
for space in spaces:
|
||||
self._render_space_inventory(svg, space)
|
|
@ -13,8 +13,8 @@ LOCATION_MODELS = []
|
|||
|
||||
class LocationSlug(SerializableMixin, models.Model):
|
||||
LOCATION_TYPE_CODES = {
|
||||
'Section': 'se',
|
||||
'Space': 'sp',
|
||||
'Level': 'l',
|
||||
'Space': 's',
|
||||
'Area': 'a',
|
||||
'Point': 'p',
|
||||
'LocationGroup': 'g'
|
||||
|
|
|
@ -20,7 +20,7 @@ class Source(EditorFormMixin, BoundsMixin, models.Model):
|
|||
def title(self):
|
||||
return self.name
|
||||
|
||||
def _serialize(self, section=True, **kwargs):
|
||||
def _serialize(self, level=True, **kwargs):
|
||||
result = super()._serialize(**kwargs)
|
||||
result['name'] = self.name
|
||||
return result
|
||||
|
|
|
@ -9,8 +9,8 @@ from django.conf import settings
|
|||
from scipy.sparse.csgraph._shortest_path import shortest_path
|
||||
from scipy.sparse.csgraph._tools import csgraph_from_dense
|
||||
|
||||
from c3nav.mapdata.models.level import Level
|
||||
from c3nav.mapdata.models.locations import Location, LocationGroup
|
||||
from c3nav.mapdata.models.section import Section
|
||||
from c3nav.routing.connection import GraphConnection
|
||||
from c3nav.routing.exceptions import AlreadyThere, NoRouteFound, NotYetRoutable
|
||||
from c3nav.routing.level import GraphLevel
|
||||
|
@ -28,7 +28,7 @@ class Graph:
|
|||
def __init__(self, mtime=None):
|
||||
self.mtime = mtime
|
||||
self.levels = OrderedDict()
|
||||
for level in Section.objects.all():
|
||||
for level in Level.objects.all():
|
||||
self.levels[level.name] = GraphLevel(self, level)
|
||||
|
||||
self.points = []
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.shortcuts import get_object_or_404, redirect, render
|
|||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from c3nav.mapdata.models.section import Section
|
||||
from c3nav.mapdata.models.level import Level
|
||||
|
||||
ctype_mapping = {
|
||||
'yes': ('up', 'down'),
|
||||
|
@ -232,7 +232,7 @@ def main(request, location=None, origin=None, destination=None):
|
|||
|
||||
|
||||
def map_image(request, area, level):
|
||||
level = get_object_or_404(Section, name=level, intermediate=False)
|
||||
level = get_object_or_404(Level, name=level, intermediate=False)
|
||||
if area == ':base':
|
||||
img = get_render_path('png', level.name, 'full', True)
|
||||
elif area == ':full':
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue