make c3nav embeddable using iframes
This commit is contained in:
parent
e768a6176c
commit
276eee5adf
5 changed files with 167 additions and 118 deletions
|
@ -96,6 +96,9 @@ main.map {
|
|||
}
|
||||
|
||||
#search {
|
||||
width: 0;
|
||||
}
|
||||
#sidebar #search {
|
||||
z-index: 4;
|
||||
min-height: 54px;
|
||||
min-width: 54px;
|
||||
|
@ -103,7 +106,7 @@ main.map {
|
|||
transition: width 150ms;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
#search.loading {
|
||||
#sidebar #search.loading {
|
||||
/*noinspection CssUnknownTarget*/
|
||||
background: url('../../img/loader.gif') no-repeat 4px 3px;
|
||||
width: 5%;
|
||||
|
@ -116,6 +119,26 @@ main.map {
|
|||
background: url('../../img/loader.gif');
|
||||
}
|
||||
|
||||
#embed-logo {
|
||||
font-size: 3rem;
|
||||
line-height: 100%;
|
||||
font-weight: 300;
|
||||
z-index: 2;
|
||||
position: absolute;
|
||||
color: #606c76;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
opacity: 0.4;
|
||||
letter-spacing: -.1rem;
|
||||
}
|
||||
#embed-logo:hover {
|
||||
opacity: 1;
|
||||
text-shadow: 1px 1px 1px rgba(255, 255, 255, 0.3),
|
||||
1px -1px 1px rgba(255, 255, 255, 0.3),
|
||||
-1px 1px 1px rgba(255, 255, 255, 0.3),
|
||||
-1px -1px 1px rgba(255, 255, 255, 0.3);
|
||||
}
|
||||
|
||||
main:not([data-view^=route]) #origin-input,
|
||||
#search.loading #destination-input {
|
||||
margin-bottom: -55px;
|
||||
|
@ -475,13 +498,13 @@ main:not([data-view=route-result]) #route-summary {
|
|||
}
|
||||
|
||||
@media not all and (min-height: 700px) and (min-width: 1100px) {
|
||||
main[data-view=route-result] #search:not(.focused) .locationinput {
|
||||
main[data-view=route-result] #sidebar #search:not(.focused) .locationinput {
|
||||
margin-bottom: -21px;
|
||||
}
|
||||
main[data-view=route-result] #search:not(.focused) .locationinput input {
|
||||
main[data-view=route-result] #sidebar #search:not(.focused) .locationinput input {
|
||||
padding-bottom: 28px;
|
||||
}
|
||||
main[data-view=route-result] #search:not(.focused) .locationinput small {
|
||||
main[data-view=route-result] #sidebar #search:not(.focused) .locationinput small {
|
||||
opacity: 0;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
|
@ -489,16 +512,16 @@ main:not([data-view=route-result]) #route-summary {
|
|||
user-select: none;
|
||||
pointer-events: none;
|
||||
}
|
||||
main[data-view=route-result] #search:not(.focused) .locationinput .icon {
|
||||
main[data-view=route-result] #sidebar #search:not(.focused) .locationinput .icon {
|
||||
transform: scale(0.6);
|
||||
top: -1px;
|
||||
}
|
||||
main[data-view=route-result] #search:not(.focused) .locationinput button {
|
||||
main[data-view=route-result] #sidebar #search:not(.focused) .locationinput button {
|
||||
transform: scale(0.6);
|
||||
top: -5px;
|
||||
right: -5px;
|
||||
}
|
||||
main[data-view=route-result] #search:not(.focused) #route-dots {
|
||||
main[data-view=route-result] #sidebar #search:not(.focused) #route-dots {
|
||||
transform: scale(0.7);
|
||||
top: 32px;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,10 @@ c3nav = {
|
|||
|
||||
$('.locationinput').data('location', null);
|
||||
|
||||
var state = JSON.parse($('main').attr('data-state'));
|
||||
var $main = $('main'),
|
||||
state = JSON.parse($main.attr('data-state'));
|
||||
c3nav.embed = $main.is('[data-embed]');
|
||||
|
||||
history.replaceState(state, window.location.path);
|
||||
c3nav.load_state(state, true);
|
||||
c3nav.update_map_locations();
|
||||
|
@ -343,16 +346,16 @@ c3nav = {
|
|||
if (a.center[0] !== b.center[0] || a.center[1] !== b.center[1]) return false;
|
||||
return true;
|
||||
},
|
||||
_build_state_url: function (state) {
|
||||
var url;
|
||||
_build_state_url: function (state, embed) {
|
||||
var url = embed ? '/embed' : '';
|
||||
if (state.routing) {
|
||||
if (state.origin) {
|
||||
url = (state.destination) ? '/r/'+state.origin.slug+'/'+state.destination.slug+'/' : '/o/'+state.origin.slug+'/';
|
||||
url += (state.destination) ? '/r/'+state.origin.slug+'/'+state.destination.slug+'/' : '/o/'+state.origin.slug+'/';
|
||||
} else {
|
||||
url = (state.destination) ? '/d/'+state.destination.slug+'/' : '/r/';
|
||||
url += (state.destination) ? '/d/'+state.destination.slug+'/' : '/r/';
|
||||
}
|
||||
} else {
|
||||
url = state.destination?('/l/'+state.destination.slug+'/'):'/';
|
||||
url += state.destination?('/l/'+state.destination.slug+'/'):'/';
|
||||
}
|
||||
if (state.details && (url.startsWith('/l/') || url.startsWith('/r/'))) {
|
||||
url += 'details/'
|
||||
|
@ -368,7 +371,12 @@ c3nav = {
|
|||
|
||||
if (!replace && c3nav._equal_states(old_state, state)) return;
|
||||
|
||||
var url = c3nav._build_state_url(state);
|
||||
var url = c3nav._build_state_url(state, c3nav.embed),
|
||||
embed_logo = $('#embed-logo');
|
||||
|
||||
if (embed_logo.length) {
|
||||
embed_logo.attr('href', c3nav._build_state_url(state));
|
||||
}
|
||||
|
||||
c3nav.state = state;
|
||||
if (replace || (!state.sidebar && !old_state.sidebar)) {
|
||||
|
@ -859,8 +867,8 @@ c3nav = {
|
|||
var $search = $('#search'),
|
||||
$main = $('main'),
|
||||
padBesideSidebar = ($main.width() > 1000 && ($main.height() < 250 || c3nav.state.details)),
|
||||
left = padBesideSidebar ? $search.width()+10 : 0,
|
||||
top = padBesideSidebar ? 10 : $search.height()+10;
|
||||
left = padBesideSidebar ? ($search.width() || 0)+10 : 0,
|
||||
top = padBesideSidebar ? 10 : ($search.height() || 0)+10;
|
||||
options[topleft || 'paddingTopLeft'] = L.point(left+13, top+41);
|
||||
options[bottomright || 'paddingBottomRight'] = L.point(50, 20);
|
||||
return options;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
{% load i18n %}
|
||||
<!DOCTYPE html>
|
||||
<html lang="{{ LANGUAGE_CODE }}">
|
||||
<head>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, user-scalable=no">
|
||||
<title>c3nav</title>
|
||||
|
@ -15,110 +15,120 @@
|
|||
<link href="{% static 'material-icons/material-icons.css' %}" rel="stylesheet">
|
||||
<link href="{% static 'site/css/c3nav.css' %}" rel="stylesheet">
|
||||
{% endcompress %}
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header>
|
||||
<h1>c3nav</h1>
|
||||
<a href="#" id="user">
|
||||
<span>{{ user_data.title }}</span>
|
||||
{% if user_data.subtitle %}<small>{{ user_data.subtitle }}</small>{% endif %}
|
||||
</a>
|
||||
</header>
|
||||
<main class="map" data-state="{{ state }}">
|
||||
<section id="popup-buttons">
|
||||
<button class="button-clear as-location">{% trans 'Show only this location' %}</button>
|
||||
<button class="button-clear as-destination">{% trans 'Route to here' %}</button>
|
||||
<button class="button-clear as-origin">{% trans 'Route from here' %}</button>
|
||||
</section>
|
||||
<section class="share-ui">
|
||||
<h3>Share</h3>
|
||||
<img src="">
|
||||
<input type="text" readonly>
|
||||
</section>
|
||||
</head>
|
||||
<body>
|
||||
{% if not embed %}
|
||||
<header>
|
||||
<h1>c3nav</h1>
|
||||
<a href="#" id="user">
|
||||
<span>{{ user_data.title }}</span>
|
||||
{% if user_data.subtitle %}<small>{{ user_data.subtitle }}</small>{% endif %}
|
||||
</a>
|
||||
</header>
|
||||
{% endif %}
|
||||
<main class="map" data-state="{{ state }}"{% if embed %} data-embed{% endif %}>
|
||||
<section id="map" data-bounds="{{ bounds }}" data-levels="{{ levels }}"{% if tile_cache_server %} data-tile-server="{{ tile_cache_server }}"{% endif %}></section>
|
||||
<section id="sidebar">
|
||||
<section id="search" class="loading">
|
||||
<div class="location locationinput empty" id="origin-input">
|
||||
<i class="icon material-icons">place</i>
|
||||
<input type="text" autocomplete="off" spellcheck="false" placeholder="{% trans 'Search any location…' %}">
|
||||
<small></small>
|
||||
<button class="button-clear locate material-icons">my_location</button>
|
||||
<button class="button-clear clear material-icons">clear</button>
|
||||
</div>
|
||||
<div class="location locationinput empty" id="destination-input">
|
||||
<i class="icon material-icons">place</i>
|
||||
<input type="text" autocomplete="off" spellcheck="false" placeholder="{% trans 'Search any location…' %}">
|
||||
<small></small>
|
||||
<button class="button-clear locate material-icons">my_location</button>
|
||||
<button class="button-clear clear material-icons">clear</button>
|
||||
</div>
|
||||
<i class="material-icons" id="route-dots">more_vert</i>
|
||||
<div class="buttons" id="location-buttons">
|
||||
<button class="button-clear details">
|
||||
<i class="material-icons">expand_more</i>
|
||||
{% trans 'Details' %}
|
||||
</button>
|
||||
<button class="button-clear share">
|
||||
<i class="material-icons">share</i>
|
||||
{% trans 'Share' %}
|
||||
</button>
|
||||
<button class="button-clear route">
|
||||
<i class="material-icons">directions</i>
|
||||
{% trans 'Route' %}
|
||||
</button>
|
||||
</div>
|
||||
<div id="route-summary">
|
||||
<i class="icon material-icons">directions</i>
|
||||
<span>10min (100m)… sorry no routing yet</span>
|
||||
<small><em>default options</em></small>
|
||||
</div>
|
||||
<div class="buttons" id="route-search-buttons">
|
||||
<button class="button-clear swap">
|
||||
<i class="material-icons">swap_vert</i>
|
||||
{% trans 'Swap' %}
|
||||
</button>
|
||||
<button class="button-clear close">
|
||||
<i class="material-icons">close</i>
|
||||
{% trans 'Close' %}
|
||||
</button>
|
||||
</div>
|
||||
<div class="buttons" id="route-result-buttons">
|
||||
<button class="button-clear swap">
|
||||
<i class="material-icons">swap_vert</i>
|
||||
{% trans 'Swap' %}
|
||||
</button>
|
||||
<button class="button-clear details">
|
||||
<i class="material-icons">arrow_downward</i>
|
||||
{% trans 'Details' %}
|
||||
</button>
|
||||
{% if not embed %}
|
||||
<section id="popup-buttons">
|
||||
<button class="button-clear as-location">{% trans 'Show only this location' %}</button>
|
||||
<button class="button-clear as-destination">{% trans 'Route to here' %}</button>
|
||||
<button class="button-clear as-origin">{% trans 'Route from here' %}</button>
|
||||
</section>
|
||||
<section class="share-ui">
|
||||
<h3>Share</h3>
|
||||
<img src="">
|
||||
<input type="text" readonly>
|
||||
</section>
|
||||
<section id="sidebar">
|
||||
<section id="search" class="loading">
|
||||
<div class="location locationinput empty" id="origin-input">
|
||||
<i class="icon material-icons">place</i>
|
||||
<input type="text" autocomplete="off" spellcheck="false" placeholder="{% trans 'Search any location…' %}">
|
||||
<small></small>
|
||||
<button class="button-clear locate material-icons">my_location</button>
|
||||
<button class="button-clear clear material-icons">clear</button>
|
||||
</div>
|
||||
<div class="location locationinput empty" id="destination-input">
|
||||
<i class="icon material-icons">place</i>
|
||||
<input type="text" autocomplete="off" spellcheck="false" placeholder="{% trans 'Search any location…' %}">
|
||||
<small></small>
|
||||
<button class="button-clear locate material-icons">my_location</button>
|
||||
<button class="button-clear clear material-icons">clear</button>
|
||||
</div>
|
||||
<i class="material-icons" id="route-dots">more_vert</i>
|
||||
<div class="buttons" id="location-buttons">
|
||||
<button class="button-clear details">
|
||||
<i class="material-icons">expand_more</i>
|
||||
{% trans 'Details' %}
|
||||
</button>
|
||||
<button class="button-clear share">
|
||||
<i class="material-icons">share</i>
|
||||
{% trans 'Share' %}
|
||||
</button>
|
||||
<button class="button-clear route">
|
||||
<i class="material-icons">directions</i>
|
||||
{% trans 'Route' %}
|
||||
</button>
|
||||
</div>
|
||||
<div id="route-summary">
|
||||
<i class="icon material-icons">directions</i>
|
||||
<span>10min (100m)… sorry no routing yet</span>
|
||||
<small><em>default options</em></small>
|
||||
</div>
|
||||
<div class="buttons" id="route-search-buttons">
|
||||
<button class="button-clear swap">
|
||||
<i class="material-icons">swap_vert</i>
|
||||
{% trans 'Swap' %}
|
||||
</button>
|
||||
<button class="button-clear close">
|
||||
<i class="material-icons">close</i>
|
||||
{% trans 'Close' %}
|
||||
</button>
|
||||
</div>
|
||||
<div class="buttons" id="route-result-buttons">
|
||||
<button class="button-clear swap">
|
||||
<i class="material-icons">swap_vert</i>
|
||||
{% trans 'Swap' %}
|
||||
</button>
|
||||
<button class="button-clear details">
|
||||
<i class="material-icons">arrow_downward</i>
|
||||
{% trans 'Details' %}
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<div id="resultswrapper">
|
||||
<section id="autocomplete"></section>
|
||||
<section id="location-details" class="details">
|
||||
<div class="details-head">
|
||||
<a class="button button-clear editor float-right" target="_blank">
|
||||
<i class="material-icons">edit</i>
|
||||
{% trans 'Open in Editor' %}
|
||||
</a>
|
||||
<h2>{% trans 'Details' %}</h2>
|
||||
</div>
|
||||
<div class="details-body"></div>
|
||||
</section>
|
||||
<section id="route-details" class="details"></section>
|
||||
</div>
|
||||
</section>
|
||||
<div id="resultswrapper">
|
||||
<section id="autocomplete"></section>
|
||||
<section id="location-details" class="details">
|
||||
<div class="details-head">
|
||||
<a class="button button-clear editor float-right" target="_blank">
|
||||
<i class="material-icons">edit</i>
|
||||
{% trans 'Open in Editor' %}
|
||||
</a>
|
||||
<h2>{% trans 'Details' %}</h2>
|
||||
</div>
|
||||
<div class="details-body"></div>
|
||||
</section>
|
||||
<section id="route-details" class="details"></section>
|
||||
</div>
|
||||
</section>
|
||||
{% else %}
|
||||
<a id="embed-logo">c3nav</a>
|
||||
<section id="popup-buttons"></section>
|
||||
<section id="search">
|
||||
<input type="hidden" id="origin-input">
|
||||
<input type="hidden" id="destination-input">
|
||||
</section>
|
||||
{% endif %}
|
||||
</main>
|
||||
<div id="modal" class="loading">
|
||||
<div id="modal-content">
|
||||
|
||||
{% if not embed %}
|
||||
<div id="modal" class="loading">
|
||||
<div id="modal-content"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% compress js %}
|
||||
<script type="text/javascript" src="{% static 'jquery/jquery.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'leaflet/leaflet.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'site/js/c3nav.js' %}"></script>
|
||||
{% endcompress %}
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -2,14 +2,17 @@ from django.conf.urls import url
|
|||
|
||||
from c3nav.site.views import map_index, qr_code
|
||||
|
||||
slug = r'(?P<slug>[a-z0-9-_.:]+)'
|
||||
slug2 = r'(?P<slug2>[a-z0-9-_.:]+)'
|
||||
details = r'(?P<details>details/)?'
|
||||
pos = r'(@(?P<level>[a-z0-9-_:]+),(?P<x>-?\d+(\.\d+)?),(?P<y>-?\d+(\.\d+)?),(?P<zoom>-?\d+(\.\d+)?))?'
|
||||
embed = r'(?P<embed>embed/)?'
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^(?P<mode>[l])/(?P<slug>[a-z0-9-_.:]+)/%s%s$' % (details, pos), map_index, name='site.index'),
|
||||
url(r'^(?P<mode>[od])/(?P<slug>[a-z0-9-_.:]+)/%s$' % pos, map_index, name='site.index'),
|
||||
url(r'^r/(?P<slug>[a-z0-9-_.:]+)/(?P<slug2>[a-z0-9-_.:]+)/%s%s$' % (details, pos), map_index, name='site.index'),
|
||||
url(r'^(?P<mode>r)/%s$' % pos, map_index, name='site.index'),
|
||||
url(r'^%s(?P<mode>[l])/%s/%s%s$' % (embed, slug, details, pos), map_index, name='site.index'),
|
||||
url(r'^%s(?P<mode>[od])/%s/%s$' % (embed, slug, pos), map_index, name='site.index'),
|
||||
url(r'^%sr/%s/%s/%s%s$' % (embed, slug, slug2, details, pos), map_index, name='site.index'),
|
||||
url(r'^%s(?P<mode>r)/%s$' % (embed, pos), map_index, name='site.index'),
|
||||
url(r'^qr/(?P<path>.*)$', qr_code, name='site.qr'),
|
||||
url(r'^%s$' % pos, map_index, name='site.index')
|
||||
]
|
||||
|
|
|
@ -7,6 +7,7 @@ from django.core.serializers.json import DjangoJSONEncoder
|
|||
from django.http import HttpResponse, HttpResponseBadRequest
|
||||
from django.shortcuts import render
|
||||
from django.views.decorators.cache import cache_control
|
||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||
from django.views.decorators.http import etag
|
||||
|
||||
from c3nav.mapdata.models import Location, Source
|
||||
|
@ -35,7 +36,8 @@ def check_location(location: Optional[str], request) -> Optional[SpecificLocatio
|
|||
return location
|
||||
|
||||
|
||||
def map_index(request, mode=None, slug=None, slug2=None, details=None, level=None, x=None, y=None, zoom=None):
|
||||
def map_index(request, mode=None, slug=None, slug2=None, details=None,
|
||||
level=None, x=None, y=None, zoom=None, embed=None):
|
||||
origin = None
|
||||
destination = None
|
||||
routing = False
|
||||
|
@ -76,9 +78,12 @@ def map_index(request, mode=None, slug=None, slug2=None, details=None, level=Non
|
|||
'state': json.dumps(state, separators=(',', ':'), cls=DjangoJSONEncoder),
|
||||
'tile_cache_server': settings.TILE_CACHE_SERVER,
|
||||
'user_data': get_user_data(request),
|
||||
'embed': bool(embed),
|
||||
}
|
||||
response = render(request, 'site/map.html', ctx)
|
||||
set_tile_access_cookie(request, response)
|
||||
if embed:
|
||||
xframe_options_exempt(lambda: response)()
|
||||
return response
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue