start new editor

This commit is contained in:
Laura Klünder 2017-05-14 20:21:33 +02:00
parent 3b2753a5c8
commit 71e2b58a25
6 changed files with 285 additions and 194 deletions

View file

@ -29,15 +29,6 @@ form button.invisiblesubmit {
display: block; display: block;
} }
.leaflet-container .leaflet-control-layers-toggle {
color:#000000 !important;
font-size:14px;
text-align:center;
width:75px;
line-height:36px;
background-image:none;
padding:0 8px;
}
.leaflet-container .leaflet-control-layers-expanded { .leaflet-container .leaflet-control-layers-expanded {
min-width:75px; min-width:75px;
} }
@ -46,6 +37,28 @@ form button.invisiblesubmit {
line-height:18px; line-height:18px;
} }
.leaflet-control-sections a, .leaflet-control-sections a:hover {
width: auto;
font-size: 14px;
padding: 0 6px;
}
.leaflet-control-sections a, .leaflet-control-sections a:hover {
display:none;
}
.leaflet-control-sections a.current, .leaflet-control-sections-expanded a, .leaflet-control-sections-expanded a:hover {
display:block;
}
.leaflet-control-sections:not(.leaflet-control-sections-expanded) a.current {
border-radius:4px;
}
.leaflet-control-sections a.current {
font-weight:bold;
}
[data-sections] {
display:none;
}
#mapeditcontrols { #mapeditcontrols {
position: absolute; position: absolute;

View file

@ -5,7 +5,12 @@
} }
}()); }());
editor = { editor = {
options: {
position: 'bottomright'
},
init: function () { init: function () {
// Init Map // Init Map
editor.map = L.map('map', { editor.map = L.map('map', {
@ -29,10 +34,11 @@ editor = {
$('body').addClass('controls'); $('body').addClass('controls');
}); });
editor._section_control = new SectionControl().addTo(editor.map);
editor.init_geometries(); editor.init_geometries();
editor.init_sidebar(); editor.init_sidebar();
editor.get_sources(); editor.get_sources();
editor.get_levels();
bounds = [[0.0, 0.0], [240.0, 400.0]]; bounds = [[0.0, 0.0], [240.0, 400.0]];
editor.map.setMaxBounds(bounds); editor.map.setMaxBounds(bounds);
@ -44,7 +50,6 @@ editor = {
get_sources: function () { get_sources: function () {
// load sources // load sources
editor._sources_control = L.control.layers().addTo(editor.map); editor._sources_control = L.control.layers().addTo(editor.map);
$(editor._sources_control._layersLink).text('Sources');
$.getJSON('/api/sources/', function (sources) { $.getJSON('/api/sources/', function (sources) {
var source; var source;
@ -57,60 +62,101 @@ editor = {
}); });
}, },
// levels // sidebar
levels: {}, get_location_path: function () {
_level: null, return window.location.pathname + window.location.search;
_loading_geometry: true, },
_level_fake_layers: {}, init_sidebar: function() {
get_levels: function () { // init the sidebar. sed listeners for form submits and link clicks
// load levels and set the lowest one afterwards $('#mapeditcontrols').on('click', 'a[href]', editor._sidebar_link_click)
$.getJSON('/api/levels/?ordering=-altitude', function (levels) { .on('click', 'button[type=submit]', editor._sidebar_submit_btn_click)
var control = L.control.layers([], [], { .on('submit', 'form', editor._sidebar_submit);
position: 'bottomright' var location_path = editor.get_location_path();
}).addTo(editor.map); editor.sidebar_get(location_path);
$(control._layersLink).text('Levels').parent().addClass('leaflet-levels'); history.replaceState({}, '', location_path);
window.onpopstate = function() {
editor.sidebar_get(editor.get_location_path());
};
},
sidebar_get: function(location) {
// load a new page into the sidebar using a GET request
var location_path = editor.get_location_path();
if ($('#mapeditcontrols').html() !== '') {
history.pushState({}, '', location);
}
editor._sidebar_unload();
$.get(location, editor._sidebar_loaded).fail(editor._sidebar_error);
},
_sidebar_unload: function() {
// unload the sidebar. called on sidebar_get and form submit.
editor._section_control.disable();
$('#mapeditcontrols').html('').addClass('loading');
editor._unhighlight_geometry();
editor._cancel_editing();
},
_sidebar_loaded: function(data) {
// sidebar was loaded. load the content. check if there are any redirects. call _check_start_editing.
var content = $(data);
var mapeditcontrols = $('#mapeditcontrols');
mapeditcontrols.html(content).removeClass('loading');
var level, layer; redirect = $('span[data-redirect]');
for (var i = levels.length -1; i >= 0; i--) { if (redirect.length) {
level = levels[i]; editor.sidebar_get(redirect.attr('data-redirect'));
layer = L.circle([-200, -200], 0.1); return;
layer._c3nav_level = level.name; }
layer.on('add', editor._click_level);
editor._level_fake_layers[level.name] = layer; sections = $('[data-sections]');
control.addBaseLayer(layer, level.name); if (sections.length) {
var sections = sections.find('a');
editor._section_control.clearSections();
for(var i=0;i<sections.length;i++) {
var section = $(sections[i]);
editor._section_control.addSection(section.text(), section.attr('href'), section.is('.current'));
} }
if (sections.length > 1) {
editor._section_control.enable();
} else {
editor._section_control.disable();
}
editor._section_control.show()
} else {
editor._section_control.hide();
}
editor._loading_geometry = false; editor._check_start_editing();
editor.set_current_level(levels[0].name); },
_sidebar_error: function(data) {
$('#mapeditcontrols').html('<h3>Error '+data.status+'</h3>'+data.statusText).removeClass('loading');
editor._section_control.hide();
},
_sidebar_link_click: function(e) {
// listener for link-clicks in the sidebar.
e.preventDefault();
editor.sidebar_get($(this).attr('href'));
},
_sidebar_submit_btn_click: function() {
// listener for submit-button-clicks in the sidebar, so the submit event will know which button submitted.
$(this).closest('form').data('btn', $(this)).clearQueue().delay(300).queue(function() {
$(this).data('btn', null);
}); });
}, },
_click_level: function(e) { _sidebar_submit: function(e) {
if (editor._level === null) return; // listener for form submits in the sidebar.
var level = e.target._c3nav_level; e.preventDefault();
var success = editor.set_current_level(level); var data = $(this).serialize();
if (!success) { var btn = $(this).data('btn');
editor._level_fake_layers[level].remove(); if (btn !== undefined && btn !== null) {
editor._level_fake_layers[editor._level].addTo(editor.map); if ($(btn).is('[name]')) {
data += '&' + $('<input>').attr('name', $(btn).attr('name')).val($(btn).val()).serialize();
}
if ($(btn).is('[data-reload-geometries]')) {
editor._get_geometries_next_time = true;
}
} }
}, var action = $(this).attr('action');
set_current_level: function(level_name) { editor._sidebar_unload();
// sets the current level if the sidebar allows it $.post(action, data, editor._sidebar_loaded);
if (editor._loading_geometry) return false;
var level_switch = $('#mapeditcontrols').find('[data-level-switch]');
if (level_switch.length === 0) return;
editor._loading_geometry = true;
if (editor._level !== null) {
editor._level_fake_layers[editor._level].remove();
}
editor._level_fake_layers[level_name].addTo(editor.map);
editor._level = level_name;
editor.get_geometries();
var level_switch_href = level_switch.attr('data-level-switch');
if (level_switch_href) {
editor.sidebar_get(level_switch_href.replace('LEVEL', level_name));
}
return true;
}, },
// geometries // geometries
@ -122,9 +168,6 @@ editor = {
_geometries_shadows: {}, _geometries_shadows: {},
_creating: false, _creating: false,
_editing: null, _editing: null,
_geometry_types: [],
_shown_geometry_types: {},
_geometry_types_control: null,
init_geometries: function () { init_geometries: function () {
// init geometries and edit listeners // init geometries and edit listeners
editor._highlight_layer = L.layerGroup().addTo(editor.map); editor._highlight_layer = L.layerGroup().addTo(editor.map);
@ -142,50 +185,6 @@ editor = {
editor.map.on('editable:vertex:ctrlclick editable:vertex:metakeyclick', function (e) { editor.map.on('editable:vertex:ctrlclick editable:vertex:metakeyclick', function (e) {
e.vertex.continue(); e.vertex.continue();
}); });
editor._get_geometry_types();
},
_get_geometry_types: function() {
editor._geometry_types_control = L.control.layers().addTo(editor.map);
$(editor._geometry_types_control._layersLink).text('Types');
$.getJSON('/api/geometrytypes/', function(geometrytypes) {
var geometrytype, layer;
for (var i = 0; i < geometrytypes.length; i++) {
geometrytype = geometrytypes[i];
layer = L.circle([-200, -200], 0.1);
layer._c3nav_geometry_type = geometrytype.name;
layer.on('add', editor._add_geometrytype_layer);
layer.on('remove', editor._remove_geometrytype_layer);
layer.addTo(editor.map);
editor._geometry_types_control.addOverlay(layer, geometrytype.title_plural);
editor._geometry_types.push(geometrytype.name)
editor._shown_geometry_types[geometrytype.name] = true;
}
});
},
_add_geometrytype_layer: function(e) {
var type = e.target._c3nav_geometry_type;
if (!editor._shown_geometry_types[type]) {
if (editor._loading_geometry) {
e.target.remove();
return;
}
editor._loading_geometry = true;
editor._shown_geometry_types[type] = true;
editor.get_geometries();
}
},
_remove_geometrytype_layer: function(e) {
var type = e.target._c3nav_geometry_type;
if (editor._shown_geometry_types[type]) {
if (editor._loading_geometry) {
e.target.addTo(map);
return;
}
editor._loading_geometry = true;
editor._shown_geometry_types[type] = false;
editor.get_geometries();
}
}, },
get_geometries: function () { get_geometries: function () {
// reload geometries of current level // reload geometries of current level
@ -194,13 +193,7 @@ editor = {
if (editor._geometries_layer !== null) { if (editor._geometries_layer !== null) {
editor.map.removeLayer(editor._geometries_layer); editor.map.removeLayer(editor._geometries_layer);
} }
geometrytypes = ''; $.getJSON('/api/geometries/?level='+String(editor._level), function(geometries) {
for (var i = 0; i < editor._geometry_types.length; i++) {
if (editor._shown_geometry_types[editor._geometry_types[i]]) {
geometrytypes += '&type=' + editor._geometry_types[i];
}
}
$.getJSON('/api/geometries/?level='+String(editor._level)+geometrytypes, function(geometries) {
editor._geometries_layer = L.geoJSON(geometries, { editor._geometries_layer = L.geoJSON(geometries, {
style: editor._get_geometry_style, style: editor._get_geometry_style,
onEachFeature: editor._register_geojson_feature onEachFeature: editor._register_geojson_feature
@ -426,87 +419,106 @@ editor = {
if (editor._editing !== null) { if (editor._editing !== null) {
$('#id_geometry').val(JSON.stringify(editor._editing.toGeoJSON().geometry)); $('#id_geometry').val(JSON.stringify(editor._editing.toGeoJSON().geometry));
} }
},
// sidebar
sidebar_location: null,
init_sidebar: function() {
// init the sidebar. sed listeners for form submits and link clicks
$('#mapeditcontrols').on('click', 'a[href]', editor._sidebar_link_click)
.on('click', 'button[type=submit]', editor._sidebar_submit_btn_click)
.on('submit', 'form', editor._sidebar_submit);
},
sidebar_get: function(location) {
// load a new page into the sidebar using a GET request
editor._sidebar_unload();
$.get(location, editor._sidebar_loaded);
},
_sidebar_unload: function() {
// unload the sidebar. called on sidebar_get and form submit.
$('#mapeditcontrols').html('').addClass('loading');
editor._unhighlight_geometry();
editor._cancel_editing();
},
_sidebar_loaded: function(data) {
// sidebar was loaded. load the content. check if there are any redirects. call _check_start_editing.
var content = $(data);
var mapeditcontrols = $('#mapeditcontrols');
mapeditcontrols.html(content).removeClass('loading');
var redirect = mapeditcontrols.find('form[name=redirect]');
if (redirect.length) {
redirect.submit();
return;
}
redirect = $('span[data-redirect]');
if (redirect.length) {
editor.sidebar_get(redirect.attr('data-redirect').replace('LEVEL', editor._level));
return;
}
editor._check_start_editing();
},
_sidebar_link_click: function(e) {
// listener for link-clicks in the sidebar.
e.preventDefault();
if ($(this).is('[data-level-link]')) {
editor.set_current_level($(this).attr('data-level-link'));
return;
}
var href = $(this).attr('href');
if ($(this).is('[data-insert-level]')) {
href = href.replace('LEVEL', editor._level);
}
editor.sidebar_get(href);
},
_sidebar_submit_btn_click: function() {
// listener for submit-button-clicks in the sidebar, so the submit event will know which button submitted.
$(this).closest('form').data('btn', $(this)).clearQueue().delay(300).queue(function() {
$(this).data('btn', null);
});
},
_sidebar_submit: function(e) {
// listener for form submits in the sidebar.
if ($(this).attr('name') == 'redirect') return;
e.preventDefault();
var data = $(this).serialize();
var btn = $(this).data('btn');
if (btn !== undefined && btn !== null) {
if ($(btn).is('[name]')) {
data += '&' + $('<input>').attr('name', $(btn).attr('name')).val($(btn).val()).serialize();
}
if ($(btn).is('[data-reload-geometries]')) {
editor._get_geometries_next_time = true;
}
}
var action = $(this).attr('action');
editor._sidebar_unload();
$.post(action, data, editor._sidebar_loaded);
} }
}; };
SectionControl = L.Control.extend({
options: {
position: 'bottomright'
},
onAdd: function (map) {
this._container = L.DomUtil.create('div', 'leaflet-control-sections leaflet-bar');
this._sectionButtons = [];
this._disabled = true;
this.hide();
if (!L.Browser.android) {
L.DomEvent.on(this._container, {
mouseenter: this.expand,
mouseleave: this.collapse
}, this);
}
if (L.Browser.touch) {
L.DomEvent
.on(this._container, 'click', L.DomEvent.stop)
.on(this._container, 'click', this.collapse, this);
} else {
L.DomEvent.on(this._container, 'focus', this.expand, this);
}
this._map.on('click', this.collapse, this);
return this._container;
},
addSection: function (title, href, current) {
var link = L.DomUtil.create('a', (current ? 'current' : ''), this._container);
link.innerHTML = title;
link.href = href;
L.DomEvent
.on(link, 'mousedown dblclick', L.DomEvent.stopPropagation)
.on(link, 'click', this._sectionClick, this)
this._sectionButtons.push(link);
return link;
},
clearSections: function() {
for (var i = 0; i < this._sectionButtons.length; i++) {
L.DomUtil.remove(this._sectionButtons[i]);
}
this._sectionButtons = [];
},
disable: function () {
for (var i = 0; i < this._sectionButtons.length; i++) {
L.DomUtil.addClass(this._sectionButtons[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');
}
this._disabled = false;
},
hide: function () {
this._container.style.display = 'none';
},
show: function () {
this._container.style.display = '';
},
_sectionClick: function (e) {
console.log('click');
e.preventDefault();
if (!this._disabled) {
editor.sidebar_get(e.target.href);
this.collapse();
}
},
expand: function () {
if (this._disabled) return;
L.DomUtil.addClass(this._container, 'leaflet-control-sections-expanded');
return this;
},
collapse: function () {
L.DomUtil.removeClass(this._container, 'leaflet-control-sections-expanded');
return this;
}
});
if ($('#mapeditcontrols').length) { if ($('#mapeditcontrols').length) {
editor.init(); editor.init();
} }

View file

@ -0,0 +1,13 @@
{% if sections %}
<ul data-sections>
{% for s in sections %}
<li>
<a href="{% url section_url section=s.id %}"{% if section == s %} class="current"{% endif %}>{{ s.title }}</a>
</li>
{% endfor %}
</ul>
{% elif section %}
<ul data-sections>
<li class="current"><a href="{% url section_url section=section.id %}">{{ section.title }}</a></li>
</ul>
{% endif %}

View file

@ -0,0 +1,14 @@
{% load bootstrap3 %}
{% load i18n %}
{% include 'editor/fragment_sections.html' %}
<a class="btn btn-default btn-sm pull-right" accesskey="n" href="">{% trans 'Add section' %}</a>
<h3>{% trans 'Sections' %}</h3>
<div class="list-group">
{% for s in sections %}
<a href="{% url 'editor.index' section=s.id %}" class="list-group-item{% if s == section %} active{% endif %}">
{{ s.title }}
</a>
{% endfor %}
</div>

View file

@ -1,10 +1,11 @@
from django.conf.urls import url from django.conf.urls import url
from django.views.generic import TemplateView
from c3nav.editor.views import edit_mapitem, list_mapitems, list_mapitemtypes from c3nav.editor.views import edit_mapitem, list_mapitems, list_mapitemtypes, main_index, sections_list
urlpatterns = [ urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='editor/map.html'), name='editor.index'), url(r'^$', main_index, name='editor.index'),
url(r'^sections/$', sections_list, name='editor.sections'),
url(r'^sections/(?P<section>[0-9]+)/$', main_index, name='editor.index'),
url(r'^mapitemtypes/(?P<level>[^/]+)/$', list_mapitemtypes, name='editor.mapitemtypes'), url(r'^mapitemtypes/(?P<level>[^/]+)/$', list_mapitemtypes, name='editor.mapitemtypes'),
url(r'^mapitems/(?P<mapitem_type>[^/]+)/list/$', list_mapitems, name='editor.mapitems'), url(r'^mapitems/(?P<mapitem_type>[^/]+)/list/$', list_mapitems, name='editor.mapitems'),
url(r'^mapitems/(?P<mapitem_type>[^/]+)/list/(?P<sectionl>[0-9]+)/$', list_mapitems, name='editor.mapitems.level'), url(r'^mapitems/(?P<mapitem_type>[^/]+)/list/(?P<sectionl>[0-9]+)/$', list_mapitems, name='editor.mapitems.level'),

View file

@ -1,19 +1,57 @@
from functools import wraps
from django.conf import settings from django.conf import settings
from django.core.exceptions import PermissionDenied from django.core.exceptions import PermissionDenied
from django.http.response import Http404 from django.http.response import Http404
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import get_object_or_404, redirect, render
from django.urls import reverse
from c3nav.mapdata.models import Section from c3nav.mapdata.models import Section
from c3nav.mapdata.models.base import EDITOR_FORM_MODELS from c3nav.mapdata.models.base import EDITOR_FORM_MODELS
def sidebar_view(func):
@wraps(func)
def with_ajax_check(request, *args, **kwargs):
if not request.is_ajax():
return render(request, 'editor/map.html', {})
return func(request, *args, **kwargs)
return with_ajax_check
@sidebar_view
def main_index(request, section=None):
if section is None:
first_section = Section.objects.first()
if first_section:
return render(request, 'editor/redirect.html', {
'target': reverse('editor.index', kwargs={'section': first_section.id})
})
else:
return render(request, 'editor/redirect.html', {
'target': reverse('editor.sections')
})
else:
section = get_object_or_404(Section, pk=section)
return render(request, 'editor/index.html', {
'sections': Section.objects.all(),
'section': section,
'section_url': 'editor.index',
})
@sidebar_view
def sections_list(request):
return render(request, 'editor/sections.html', {})
def list_mapitemtypes(request, section): def list_mapitemtypes(request, section):
section = get_object_or_404(Section, pk=section) section = get_object_or_404(Section, pk=section)
def get_item_count(mapitemtype): def get_item_count(mapitemtype):
if hasattr(mapitemtype, 'section'): if hasattr(mapitemtype, 'section'):
return filter_queryset_by_access(request, mapitemtype.objects.filter(section=section)).count() return filter_queryset_by_access(request, mapitemtype.objects.filter(section=section)).count()
return 0 return 0
return render(request, 'editor/mapitemtypes.html', { return render(request, 'editor/mapitemtypes.html', {