Editor: edit & delete features
This commit is contained in:
parent
6ce96148d7
commit
576b33fd1a
13 changed files with 239 additions and 31 deletions
|
@ -1,5 +1,4 @@
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include, url
|
||||||
|
|
||||||
from rest_framework.routers import DefaultRouter
|
from rest_framework.routers import DefaultRouter
|
||||||
|
|
||||||
from ..editor import api as editor_api
|
from ..editor import api as editor_api
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
|
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ViewSet
|
from rest_framework.viewsets import ViewSet
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ class FeatureForm(ModelForm):
|
||||||
|
|
||||||
titles = OrderedDict((lang_code, '') for lang_code, language in settings.LANGUAGES)
|
titles = OrderedDict((lang_code, '') for lang_code, language in settings.LANGUAGES)
|
||||||
if self.instance is not None and self.instance.pk:
|
if self.instance is not None and self.instance.pk:
|
||||||
|
self.fields['name'].widget.attrs['readonly'] = True
|
||||||
titles.update(self.instance.titles)
|
titles.update(self.instance.titles)
|
||||||
|
|
||||||
language_titles = dict(settings.LANGUAGES)
|
language_titles = dict(settings.LANGUAGES)
|
||||||
|
@ -35,6 +36,14 @@ class FeatureForm(ModelForm):
|
||||||
_('You have to select a title in at least one language.')
|
_('You have to select a title in at least one language.')
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def clean_name(self):
|
||||||
|
if self.instance is not None and self.instance.pk and self.cleaned_data['name'] != self.instance.name:
|
||||||
|
raise ValidationError(
|
||||||
|
_('You cannot edit feature identifiers of existing objects.')
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.cleaned_data['name']
|
||||||
|
|
||||||
def get_languages(self):
|
def get_languages(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
|
@ -78,9 +78,46 @@
|
||||||
padding-left:5.5px;
|
padding-left:5.5px;
|
||||||
padding-right:5.5px;
|
padding-right:5.5px;
|
||||||
}
|
}
|
||||||
|
legend {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
.start-drawing {
|
.start-drawing {
|
||||||
display:none;
|
display:none;
|
||||||
}
|
}
|
||||||
.leaflet-editable-drawing .leaflet-overlay-pane .leaflet-interactive {
|
.leaflet-editable-drawing .leaflet-overlay-pane .leaflet-interactive {
|
||||||
cursor:crosshair;
|
cursor:crosshair;
|
||||||
}
|
}
|
||||||
|
.feature_level_list {
|
||||||
|
list-style-type:none;
|
||||||
|
display:none;
|
||||||
|
margin-bottom:15px;
|
||||||
|
padding:0;
|
||||||
|
}
|
||||||
|
.feature_level_list li {
|
||||||
|
padding:5px 0 0;
|
||||||
|
border-style:solid;
|
||||||
|
border-width:0 0 1px;
|
||||||
|
border-color:#EEEEEE;
|
||||||
|
}
|
||||||
|
.feature_level_list li:hover, .feature_level_list li.hover {
|
||||||
|
background-color:#FFFFEE;
|
||||||
|
}
|
||||||
|
.feature_level_list p {
|
||||||
|
margin:0 0 5px;
|
||||||
|
cursor:default;
|
||||||
|
}
|
||||||
|
.feature_level_list p:first-child {
|
||||||
|
font-weight:bold;
|
||||||
|
font-size:16px;
|
||||||
|
}
|
||||||
|
.feature_level_list p:first-child em {
|
||||||
|
font-weight:normal;
|
||||||
|
font-size:14px;
|
||||||
|
padding-left:5px;
|
||||||
|
}
|
||||||
|
#map .leaflet-overlay-pane .c3nav-highlight {
|
||||||
|
pointer-events:none;
|
||||||
|
}
|
||||||
|
#btn_editing_cancel {
|
||||||
|
margin-right:8px;
|
||||||
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
editor = {
|
editor = {
|
||||||
feature_types: {},
|
feature_types: {},
|
||||||
feature_types_order: [],
|
feature_types_order: [],
|
||||||
|
_highlight_layer: null,
|
||||||
|
|
||||||
init: function () {
|
init: function () {
|
||||||
// Init Map
|
// Init Map
|
||||||
|
@ -14,6 +15,7 @@ editor = {
|
||||||
});
|
});
|
||||||
|
|
||||||
L.control.scale({imperial: false}).addTo(editor.map);
|
L.control.scale({imperial: false}).addTo(editor.map);
|
||||||
|
editor._highlight_layer = L.layerGroup().addTo(editor.map);
|
||||||
|
|
||||||
editor.get_feature_types();
|
editor.get_feature_types();
|
||||||
editor.get_packages();
|
editor.get_packages();
|
||||||
|
@ -29,7 +31,7 @@ editor = {
|
||||||
editor.feature_types[feature_type.name] = feature_type;
|
editor.feature_types[feature_type.name] = feature_type;
|
||||||
editor.feature_types_order.push(feature_type.name);
|
editor.feature_types_order.push(feature_type.name);
|
||||||
editcontrols.append(
|
editcontrols.append(
|
||||||
$('<fieldset>').attr('name', feature_type.name).append(
|
$('<fieldset class="feature_list">').attr('name', feature_type.name).append(
|
||||||
$('<legend>').text(feature_type.title_plural).append(
|
$('<legend>').text(feature_type.title_plural).append(
|
||||||
$('<button class="btn btn-default btn-xs pull-right start-drawing"><i class="glyphicon glyphicon-plus"></i></button>')
|
$('<button class="btn btn-default btn-xs pull-right start-drawing"><i class="glyphicon glyphicon-plus"></i></button>')
|
||||||
)
|
)
|
||||||
|
@ -101,17 +103,21 @@ editor = {
|
||||||
editor.set_current_level($(this).attr('name'));
|
editor.set_current_level($(this).attr('name'));
|
||||||
});
|
});
|
||||||
|
|
||||||
var level;
|
var level, feature_type;
|
||||||
for (var i = 0; i < levels.length; i++) {
|
for (var i = 0; i < levels.length; i++) {
|
||||||
level = levels[i];
|
level = levels[i];
|
||||||
editor.levels[level.name] = level;
|
editor.levels[level.name] = level;
|
||||||
editor.level_feature_layers[level.name] = {};
|
editor.level_feature_layers[level.name] = {};
|
||||||
for (var j = 0; j < editor.feature_types_order.length; j++) {
|
for (var j = 0; j < editor.feature_types_order.length; j++) {
|
||||||
editor.level_feature_layers[level.name][editor.feature_types_order[j]] = L.layerGroup();
|
feature_type = editor.feature_types_order[j];
|
||||||
|
editor.level_feature_layers[level.name][feature_type] = L.layerGroup();
|
||||||
|
$('.feature_list[name='+feature_type+']').append(
|
||||||
|
$('<ul class="feature_level_list">').attr('data-level', level.name)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
editor.set_current_level(levels[levels.length - 1].name);
|
editor.set_current_level(levels[levels.length - 1].name);
|
||||||
editor.init_drawing();
|
editor.init_features();
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
set_current_level: function(level_name) {
|
set_current_level: function(level_name) {
|
||||||
|
@ -125,11 +131,13 @@ editor = {
|
||||||
editor._level = level_name;
|
editor._level = level_name;
|
||||||
$('.leaflet-levels .current').removeClass('current');
|
$('.leaflet-levels .current').removeClass('current');
|
||||||
$('.leaflet-levels a[name='+level_name+']').addClass('current');
|
$('.leaflet-levels a[name='+level_name+']').addClass('current');
|
||||||
|
$('.feature_level_list').hide();
|
||||||
|
$('.feature_level_list[data-level='+level_name+']').show();
|
||||||
},
|
},
|
||||||
|
|
||||||
_creating: null,
|
_creating: null,
|
||||||
_editing: null,
|
_editing: null,
|
||||||
init_drawing: function () {
|
init_features: function () {
|
||||||
// Add drawing new features
|
// Add drawing new features
|
||||||
L.DrawControl = L.Control.extend({
|
L.DrawControl = L.Control.extend({
|
||||||
options: {
|
options: {
|
||||||
|
@ -150,29 +158,38 @@ editor = {
|
||||||
});
|
});
|
||||||
editor.map.addControl(new L.DrawControl());
|
editor.map.addControl(new L.DrawControl());
|
||||||
|
|
||||||
$('#mapeditlist').on('click', '.start-drawing', function () {
|
$('#mapeditlist').on('click', '.start-drawing', editor._click_start_drawing)
|
||||||
editor.start_creating($(this).closest('fieldset').attr('name'));
|
.on('mouseenter', '.feature_level_list li', editor._hover_feature_detail)
|
||||||
});
|
.on('mouseleave', '.feature_level_list li', editor._unhover_feature_detail)
|
||||||
|
.on('click', '.feature_level_list li', editor._click_feature_detail);
|
||||||
|
|
||||||
editor.map.on('editable:drawing:commit', editor.done_creating);
|
editor.map.on('editable:drawing:commit', editor.done_creating);
|
||||||
editor.map.on('editable:editing', editor.update_editing);
|
editor.map.on('editable:editing', editor.update_editing);
|
||||||
editor.map.on('editable:drawing:cancel', editor._canceled_creating);
|
editor.map.on('editable:drawing:cancel', editor._canceled_creating);
|
||||||
|
|
||||||
$('#mapeditdetail').on('click', '#btn_editing_cancel', editor.cancel_editing)
|
$('#mapeditdetail').on('click', '#btn_editing_cancel', editor.cancel_editing)
|
||||||
.on('submit', 'form', editor.submit_editing);
|
.on('click', 'button[type=submit]', editor.submit_editing_btn_click)
|
||||||
|
.on('submit', 'form', editor.submit_editing)
|
||||||
|
|
||||||
|
|
||||||
editor.get_features();
|
editor.get_features();
|
||||||
},
|
},
|
||||||
|
|
||||||
|
features: {},
|
||||||
get_features: function () {
|
get_features: function () {
|
||||||
$.getJSON('/api/v1/features/', function(features) {
|
$.getJSON('/api/v1/features/', function(features) {
|
||||||
for (level in editor.level_layers) {
|
var feature_type;
|
||||||
editor.level_layers[level].clearLayers();
|
for (var level in editor.levels) {
|
||||||
|
for (var j = 0; j < editor.feature_types_order.length; j++) {
|
||||||
|
feature_type = editor.feature_types_order[j];
|
||||||
|
editor.level_feature_layers[level][feature_type].clearLayers();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var feature;
|
$('.feature_level_list li').remove();
|
||||||
|
var feature, layergroup;
|
||||||
for (var i=0; i < features.length; i++) {
|
for (var i=0; i < features.length; i++) {
|
||||||
feature = features[i];
|
feature = features[i];
|
||||||
L.geoJSON({
|
layergroup = L.geoJSON({
|
||||||
type: 'Feature',
|
type: 'Feature',
|
||||||
geometry: feature.geometry,
|
geometry: feature.geometry,
|
||||||
properties: {
|
properties: {
|
||||||
|
@ -181,20 +198,86 @@ editor = {
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
style: editor._get_feature_style
|
style: editor._get_feature_style
|
||||||
}).addTo(editor.level_feature_layers[feature.level][feature.feature_type]);
|
}).on('mouseover', editor._hover_feature_layer)
|
||||||
|
.on('mouseout', editor._unhover_feature_layer)
|
||||||
|
.on('click', editor._click_feature_layer)
|
||||||
|
.addTo(editor.level_feature_layers[feature.level][feature.feature_type]);
|
||||||
|
feature.layer = layergroup.getLayers()[0];
|
||||||
|
editor.features[feature.name] = feature;
|
||||||
|
|
||||||
|
$('.feature_list[name='+feature.feature_type+'] > [data-level='+feature.level+']').append(
|
||||||
|
$('<li>').attr('name', feature.name).append(
|
||||||
|
$('<p>').text(feature.title).append(' ').append(
|
||||||
|
$('<em>').text(feature.name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
$('.start-drawing').show();
|
$('.start-drawing').show();
|
||||||
$('#mapeditcontrols').addClass('list');
|
$('#mapeditcontrols').addClass('list');
|
||||||
editor.set_current_level(editor._level);
|
editor.set_current_level(editor._level);
|
||||||
});
|
});
|
||||||
|
|
||||||
},
|
},
|
||||||
_get_feature_style: function (feature) {
|
_get_feature_style: function (feature) {
|
||||||
return editor.feature_types[feature.properties.feature_type];
|
return editor.feature_types[feature.properties.feature_type];
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_click_start_drawing: function (e) {
|
||||||
|
editor.start_creating($(this).closest('fieldset').attr('name'));
|
||||||
|
},
|
||||||
|
_hover_feature_detail: function (e) {
|
||||||
|
editor._highlight_layer.clearLayers();
|
||||||
|
L.geoJSON(editor.features[$(this).attr('name')].geometry, {
|
||||||
|
style: function() {
|
||||||
|
return {
|
||||||
|
color: '#FFFFEE',
|
||||||
|
opacity: 0.5,
|
||||||
|
fillOpacity: 0.5,
|
||||||
|
className: 'c3nav-highlight'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}).addTo(editor._highlight_layer);
|
||||||
|
},
|
||||||
|
_unhover_feature_detail: function () {
|
||||||
|
editor._highlight_layer.clearLayers();
|
||||||
|
},
|
||||||
|
_click_feature_detail: function() {
|
||||||
|
editor.start_editing($(this).attr('name'));
|
||||||
|
},
|
||||||
|
|
||||||
|
_hover_feature_layer: function (e) {
|
||||||
|
editor._unhover_feature_layer();
|
||||||
|
if (editor._editing === null && editor._creating === null) {
|
||||||
|
editor._highlight_layer.clearLayers();
|
||||||
|
L.geoJSON(e.layer.toGeoJSON(), {
|
||||||
|
style: function() {
|
||||||
|
return {
|
||||||
|
color: '#FFFFEE',
|
||||||
|
opacity: 0.5,
|
||||||
|
fillOpacity: 0.5,
|
||||||
|
className: 'c3nav-highlight'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}).addTo(editor._highlight_layer);
|
||||||
|
}
|
||||||
|
$('.feature_list li[name='+e.layer.feature.properties.name+']').addClass('hover');
|
||||||
|
},
|
||||||
|
_unhover_feature_layer: function (e) {
|
||||||
|
editor._highlight_layer.clearLayers();
|
||||||
|
$('.feature_list .hover').removeClass('hover');
|
||||||
|
},
|
||||||
|
_click_feature_layer: function(e) {
|
||||||
|
editor.start_editing(e.layer.feature.properties.name);
|
||||||
|
if ((e.originalEvent.ctrlKey || e.originalEvent.metaKey) && this.editEnabled()) {
|
||||||
|
if (e.layer.feature.properties.geomtype == 'polygon') {
|
||||||
|
this.editor.newHole(e.latlng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
start_creating: function (feature_type) {
|
start_creating: function (feature_type) {
|
||||||
if (editor._creating !== null || editor._editing !== null) return;
|
if (editor._creating !== null || editor._editing !== null) return;
|
||||||
|
editor._highlight_layer.clearLayers();
|
||||||
editor._creating = feature_type;
|
editor._creating = feature_type;
|
||||||
var options = editor.feature_types[feature_type];
|
var options = editor.feature_types[feature_type];
|
||||||
if (options.geomtype == 'polygon') {
|
if (options.geomtype == 'polygon') {
|
||||||
|
@ -230,8 +313,13 @@ editor = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
start_editing: function () {
|
start_editing: function (name) {
|
||||||
// todo
|
if (editor._creating !== null || editor._editing !== null) return;
|
||||||
|
editor._highlight_layer.clearLayers();
|
||||||
|
editor._editing = editor.features[name].layer;
|
||||||
|
var path = '/editor/features/edit/' + name + '/';
|
||||||
|
$('#mapeditcontrols').removeClass('list');
|
||||||
|
$('#mapeditdetail').load(path, editor.edit_form_loaded);
|
||||||
},
|
},
|
||||||
edit_form_loaded: function() {
|
edit_form_loaded: function() {
|
||||||
$('#mapeditcontrols').addClass('detail');
|
$('#mapeditcontrols').addClass('detail');
|
||||||
|
@ -263,9 +351,18 @@ editor = {
|
||||||
editor.get_features();
|
editor.get_features();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
submit_editing: function(e) {
|
submit_editing_btn_click: function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$(this).closest('form').trigger('submit', $(this));
|
||||||
|
},
|
||||||
|
submit_editing: function(e, btn) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
var data = $(this).serialize();
|
var data = $(this).serialize();
|
||||||
|
console.log($(btn));
|
||||||
|
console.log($(btn).is('[name]'));
|
||||||
|
if (btn !== undefined && $(btn).is('[name]')) {
|
||||||
|
data += '&'+$('<input>').attr('name', $(btn).attr('name')).val($(btn).val()).serialize();
|
||||||
|
}
|
||||||
var action = $(this).attr('action');
|
var action = $(this).attr('action');
|
||||||
$('#mapeditcontrols').removeClass('detail');
|
$('#mapeditcontrols').removeClass('detail');
|
||||||
$('#mapeditdetail').html('');
|
$('#mapeditdetail').html('');
|
||||||
|
|
|
@ -5,11 +5,16 @@
|
||||||
{% csrf_token %}
|
{% csrf_token %}
|
||||||
{% bootstrap_form form %}
|
{% bootstrap_form form %}
|
||||||
{% buttons %}
|
{% buttons %}
|
||||||
<button type="button" id="btn_editing_cancel" class="btn btn-danger">
|
{% if not new %}
|
||||||
Cancel
|
<button type="submit" name="delete" value="1" class="btn btn-danger">
|
||||||
</button>
|
Delete
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
<button type="submit" class="btn btn-primary pull-right">
|
<button type="submit" class="btn btn-primary pull-right">
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" id="btn_editing_cancel" class="btn {% if new %}btn-danger{% else %}btn-default pull-right{% endif %}">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
{% endbuttons %}
|
{% endbuttons %}
|
||||||
</form>
|
</form>
|
||||||
|
|
17
src/c3nav/editor/templates/editor/feature_delete.html
Normal file
17
src/c3nav/editor/templates/editor/feature_delete.html
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
{% load bootstrap3 %}
|
||||||
|
|
||||||
|
<h3>Delete {{ feature_type.title }}</h3>
|
||||||
|
<form action="{{ path }}" method="post">
|
||||||
|
{% csrf_token %}
|
||||||
|
<p>Please confirm deleting: {{ name }}</p>
|
||||||
|
<input type="hidden" name="delete" value="1">
|
||||||
|
<input type="hidden" name="name" value="{{ name }}">
|
||||||
|
{% buttons %}
|
||||||
|
<button type="button" id="btn_editing_cancel" class="btn btn-default">
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button type="submit" name="delete_confirm" value="1" class="btn btn-danger pull-right">
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
{% endbuttons %}
|
||||||
|
</form>
|
|
@ -1,9 +1,10 @@
|
||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.views.generic import TemplateView
|
from django.views.generic import TemplateView
|
||||||
|
|
||||||
from c3nav.editor.views import add_feature
|
from c3nav.editor.views import add_feature, edit_feature
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^$', TemplateView.as_view(template_name='editor/map.html'), name='editor.index'),
|
url(r'^$', TemplateView.as_view(template_name='editor/map.html'), name='editor.index'),
|
||||||
url(r'^features/(?P<feature_type>[^/]+)/add/$', add_feature, name='editor.feature.add')
|
url(r'^features/(?P<feature_type>[^/]+)/add/$', add_feature, name='editor.feature.add'),
|
||||||
|
url(r'^features/edit/(?P<name>[^/]+)/$', edit_feature, name='editor.feature.edit')
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,10 +1,12 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from django.core.exceptions import PermissionDenied
|
||||||
from django.db import transaction
|
from django.db import transaction
|
||||||
from django.http.response import Http404
|
from django.http.response import Http404
|
||||||
from django.shortcuts import render
|
from django.shortcuts import get_object_or_404, render
|
||||||
|
|
||||||
from c3nav.editor.forms import FeatureForm
|
from c3nav.editor.forms import FeatureForm
|
||||||
from c3nav.mapdata.models.feature import FEATURE_TYPES
|
from c3nav.mapdata.models.feature import FEATURE_TYPES, Feature
|
||||||
|
from c3nav.mapdata.permissions import can_access_package
|
||||||
|
|
||||||
|
|
||||||
def add_feature(request, feature_type):
|
def add_feature(request, feature_type):
|
||||||
|
@ -37,3 +39,47 @@ def add_feature(request, feature_type):
|
||||||
'path': request.path,
|
'path': request.path,
|
||||||
'new': True
|
'new': True
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def edit_feature(request, name):
|
||||||
|
feature = get_object_or_404(Feature, name=name)
|
||||||
|
if not can_access_package(feature.package):
|
||||||
|
raise PermissionDenied
|
||||||
|
feature_type = FEATURE_TYPES.get(feature.feature_type)
|
||||||
|
|
||||||
|
if request.method == 'POST':
|
||||||
|
if request.POST.get('delete') == '1':
|
||||||
|
if request.POST.get('delete_confirm') == '1':
|
||||||
|
feature.delete()
|
||||||
|
return render(request, 'editor/feature_success.html', {})
|
||||||
|
|
||||||
|
return render(request, 'editor/feature_delete.html', {
|
||||||
|
'name': feature.name,
|
||||||
|
'feature_type': feature_type,
|
||||||
|
'path': request.path
|
||||||
|
})
|
||||||
|
|
||||||
|
form = FeatureForm(instance=feature, data=request.POST, feature_type=feature_type)
|
||||||
|
if form.is_valid():
|
||||||
|
if not settings.DIRECT_EDITING:
|
||||||
|
return render(request, 'editor/feature_success.html', {})
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
feature = form.instance
|
||||||
|
feature.feature_type = feature_type.name
|
||||||
|
feature.titles = {}
|
||||||
|
for language, title in form.titles.items():
|
||||||
|
if title:
|
||||||
|
feature.titles[language] = title
|
||||||
|
feature.save()
|
||||||
|
|
||||||
|
return render(request, 'editor/feature_success.html', {})
|
||||||
|
else:
|
||||||
|
form = FeatureForm(instance=feature, feature_type=feature_type)
|
||||||
|
|
||||||
|
return render(request, 'editor/feature.html', {
|
||||||
|
'form': form,
|
||||||
|
'feature_type': feature_type,
|
||||||
|
'path': request.path,
|
||||||
|
'new': False
|
||||||
|
})
|
||||||
|
|
|
@ -4,7 +4,6 @@ import os
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.core.files import File
|
from django.core.files import File
|
||||||
from django.http import Http404, HttpResponse
|
from django.http import Http404, HttpResponse
|
||||||
|
|
||||||
from rest_framework.decorators import detail_route
|
from rest_framework.decorators import detail_route
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
|
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
|
||||||
|
|
|
@ -7,6 +7,7 @@ from django.utils.translation import get_language
|
||||||
from shapely.geometry import mapping, shape
|
from shapely.geometry import mapping, shape
|
||||||
|
|
||||||
from c3nav.mapdata.utils import sort_geojson
|
from c3nav.mapdata.utils import sort_geojson
|
||||||
|
|
||||||
from ..fields import GeometryField, JSONField
|
from ..fields import GeometryField, JSONField
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,7 +36,7 @@ class Feature(models.Model):
|
||||||
"""
|
"""
|
||||||
TYPES = tuple((name, t.title) for name, t in FEATURE_TYPES.items())
|
TYPES = tuple((name, t.title) for name, t in FEATURE_TYPES.items())
|
||||||
|
|
||||||
name = models.SlugField(_('feature identifier'), primary_key=True, max_length=50, help_text=_('e.g. noc'))
|
name = models.SlugField(_('feature identifier'), primary_key=True, max_length=50)
|
||||||
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='features',
|
package = models.ForeignKey('mapdata.Package', on_delete=models.CASCADE, related_name='features',
|
||||||
verbose_name=_('map package'))
|
verbose_name=_('map package'))
|
||||||
feature_type = models.CharField(max_length=50, choices=TYPES)
|
feature_type = models.CharField(max_length=50, choices=TYPES)
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
from ..models import Feature, Level, Package, Source
|
from ..models import Feature, Level, Package, Source
|
||||||
|
|
||||||
|
|
||||||
ordered_models = (Package, Level, Source, Feature)
|
ordered_models = (Package, Level, Source, Feature)
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework.exceptions import PermissionDenied
|
from rest_framework.exceptions import PermissionDenied
|
||||||
from rest_framework.permissions import BasePermission
|
from rest_framework.permissions import BasePermission
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue