Use browser history instead of hash for annotation URL.
--- a/src/iconolab/templates/iconolab/collection_home.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/iconolab/collection_home.html Mon Apr 17 14:42:38 2017 +0200
@@ -45,7 +45,7 @@
<div class="col-md-4">
<div class="fragment-container" style="position: relative">
{% thumbnail annotation.image.media "250x250" crop=False as im %}
- <a href="{% url 'image_detail' collection_name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' collection_name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
--- a/src/iconolab/templates/iconolab/detail_image.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/iconolab/detail_image.html Mon Apr 17 14:42:38 2017 +0200
@@ -22,6 +22,7 @@
<annotation-list
v-bind:annotations="annotations"
v-bind:annotation="annotation"
+ annotation-url="{% url 'annotation_detail' collection_name image_guid ':annotation_guid' %}"
v-on:click:annotation="onAnnotationClick($event)"
v-on:close:annotation="onAnnotationClose"><annotation-list>
{% else %}
@@ -100,8 +101,18 @@
var currentPath = "{{ request.path }}";
var getCommentFormURL = "{% url 'get_comment_form' ':annotation_guid' %}"
+ var imageURL = "{% url 'image_detail' collection_name image_guid %}"
+ var annotationURL = "{% url 'annotation_detail' collection_name image_guid ':annotation_guid' %}"
var isAuthenticated = {% if user.is_authenticated %}true{% else %}false{% endif %};
+ window.onpopstate = function(event) {
+ if (event.state.annotation_guid) {
+ vm.annotation = getAnnotationByGuid(event.state.annotation_guid);
+ } else {
+ vm.annotation = null;
+ }
+ };
+
Vue.component('comment-form', {
template: '<div></div>',
data: function() {
@@ -119,7 +130,12 @@
{% endfor %}
{% endif %}
- var annotation = getAnnotationFromHash();
+ {% if annotation %}
+ var annotation = getAnnotationByGuid("{{ annotation.annotation_guid }}");
+ {% else %}
+ var annotation = null;
+ {% endif %}
+
if (annotation) {
getCommentForm(annotation).then(function(template) {
updateCommentFormComponent(template);
@@ -129,9 +145,10 @@
createViewModel();
}
+ var vm;
function createViewModel() {
- var vm = new Vue({
+ vm = new Vue({
el: '.annotation-navigator',
data: function() {
return {
@@ -146,12 +163,12 @@
getCommentForm(annotation).then(function(template) {
updateCommentFormComponent(template);
self.annotation = annotation;
- location.hash = '#' + annotation.annotation_guid;
+ history.pushState({ annotation_guid: annotation.annotation_guid }, '', annotationURL.replace(':annotation_guid', annotation.annotation_guid));
});
},
onAnnotationClose: function() {
this.annotation = null;
- location.hash = '';
+ history.pushState({ annotation_guid: null }, '', imageURL);
}
}
});
@@ -220,18 +237,14 @@
function getCommentForm(annotation) {
return $.get(getCommentFormURL.replace(':annotation_guid', annotation.annotation_guid), {
- next: currentPath + '#' + annotation.annotation_guid
+ next: annotationURL.replace(':annotation_guid', annotation.annotation_guid)
})
}
- function getAnnotationFromHash() {
- var url = location.hash.slice(1);
- if (url.length) {
- var annotation_guid = url;
- return _.find(annotations, function(annotation) {
- return annotation.annotation_guid === annotation_guid;
- });
- }
+ function getAnnotationByGuid(guid) {
+ return _.find(annotations, function(annotation) {
+ return annotation.annotation_guid === guid;
+ });
}
</script>
--- a/src/iconolab/templates/iconolab_base.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/iconolab_base.html Mon Apr 17 14:42:38 2017 +0200
@@ -23,7 +23,7 @@
<body>
{% include "partials/header.html" %}
- <div class="{% if request.resolver_match.url_name == 'image_detail' %}container-fluid{% else %}container{% endif %}">
+ <div class="{% container_class %}">
{% block content %}{% endblock %}
</div>
--- a/src/iconolab/templates/partials/header.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/partials/header.html Mon Apr 17 14:42:38 2017 +0200
@@ -1,10 +1,11 @@
{% load notifications_tags %}
+{% load iconolab_tags %}
{% load staticfiles %}
<header>
<section id="topnav">
<nav class="navbar navbar-default">
- <div class="{% if request.resolver_match.url_name == 'image_detail' %}container-fluid{% else %}container{% endif %}">
+ <div class="{% container_class %}">
<div class="navbar-header">
{# {% if not homepage %} #}
<a class="navbar-brand" href="{% url 'home' %}">
@@ -37,6 +38,6 @@
</section>
</header>
-<div class="{% if request.resolver_match.url_name == 'image_detail' %}container-fluid{% else %}container{% endif %}">
+<div class="{% container_class %}">
{% include "partials/header_breadcrumbs.html" %}
</div>
--- a/src/iconolab/templates/partials/image_annotations_list.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/partials/image_annotations_list.html Mon Apr 17 14:42:38 2017 +0200
@@ -25,7 +25,7 @@
<td class="col-md-2">
<div class="fragment-container" style="position: relative">
{% thumbnail annotation.image.media "150x150" crop=False as im %}
- <a href="{% url 'image_detail' collection_name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' collection_name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
--- a/src/iconolab/templates/partials/user_pages/annotations_commented_panel.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/partials/user_pages/annotations_commented_panel.html Mon Apr 17 14:42:38 2017 +0200
@@ -14,7 +14,7 @@
<div style="position:relative" class="{% if large_image %}large-{% endif %}image-detail">
{% if large_image %}
{% thumbnail annotation.image.media "400x400" crop=False as im %}
- <a href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
@@ -25,7 +25,7 @@
{% endthumbnail %}
{% else %}
{% thumbnail annotation.image.media "150x150" crop=False as im %}
- <a href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
@@ -45,7 +45,7 @@
<dt>A commenté le : </dt>
<dd>{{annotation_data.latest_comment_date}}</dd>
</dl>
- <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">Voir annotation</a>
+ <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">Voir annotation</a>
</div>
{% if with_stats %}
<div class="stats-annotation-userpage">
--- a/src/iconolab/templates/partials/user_pages/annotations_contributed_panel.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/partials/user_pages/annotations_contributed_panel.html Mon Apr 17 14:42:38 2017 +0200
@@ -14,7 +14,7 @@
<div style="position:relative" class="{% if large_image %}large-{% endif %}image-detail">
{% if large_image %}
{% thumbnail annotation.image.media "400x400" crop=False as im %}
- <a href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
@@ -25,7 +25,7 @@
{% endthumbnail %}
{% else %}
{% thumbnail annotation.image.media "150x150" crop=False as im %}
- <a href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
@@ -47,7 +47,7 @@
<dt>.. Révisions acceptées: </dt>
<dd><span class="badge {% if annotation_data.accepted_count %}badge-success{% endif %}">{{annotation_data.accepted_count}}</span></dd>
</dl>
- <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">Voir annotation</a>
+ <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">Voir annotation</a>
</div>
{% if with_stats %}
<div class="stats-annotation-userpage">
--- a/src/iconolab/templates/partials/user_pages/annotations_created_panel.html Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templates/partials/user_pages/annotations_created_panel.html Mon Apr 17 14:42:38 2017 +0200
@@ -13,7 +13,7 @@
<div style="position:relative" class="{% if large_image %}large-{% endif %}image-detail">
{% if large_image %}
{% thumbnail annotation.image.media "400x400" crop=False as im %}
- <a href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
@@ -24,7 +24,7 @@
{% endthumbnail %}
{% else %}
{% thumbnail annotation.image.media "150x150" crop=False as im %}
- <a href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">
+ <a href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">
<img v-el:small-image src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}" />
<svg width="{{ im.width }}" height="{{ im.height }}" version="1.1" style="position:absolute; top:0px; left: 0px">
<g transform="matrix({% transform_matrix im_width=im.width im_height=im.height max_x=100 max_y=100 %})">
@@ -46,7 +46,7 @@
<dd><span class="badge {% if annotation.stats.awaiting_revisions_count > 0 %}badge-warning{% endif %}">{{annotation.stats.awaiting_revisions_count}}</span></dd>
</dl>
</dl>
- <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'image_detail' annotation.image.item.collection.name annotation.image.image_guid %}#{{ annotation.annotation_guid }}">Voir annotation</a>
+ <a class="btn btn-default btn-sm userpage-annotation-btn pull-left" href="{% url 'annotation_detail' annotation.image.item.collection.name annotation.image.image_guid annotation.annotation_guid %}">Voir annotation</a>
</div>
{% if with_stats %}
<div class="stats-annotation-userpage">
--- a/src/iconolab/templatetags/iconolab_tags.py Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/templatetags/iconolab_tags.py Mon Apr 17 14:42:38 2017 +0200
@@ -65,3 +65,11 @@
serializer = AnnotationRevisionSerializer(data)
return JSONRenderer().render(serializer.data)
return serialize('json', [data])
+
+@register.simple_tag(takes_context=True)
+def container_class(context):
+ request = context['request']
+ routes = ['image_detail', 'annotation_detail']
+ if request.resolver_match.url_name in routes:
+ return 'container-fluid'
+ return 'container'
--- a/src/iconolab/urls.py Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/urls.py Mon Apr 17 14:42:38 2017 +0200
@@ -38,7 +38,8 @@
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)$', views.objects.ShowImageView.as_view(), name='image_detail'),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/?$', django_views.generic.RedirectView.as_view(pattern_name="image_detail")),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/create$', login_required(views.objects.CreateAnnotationView.as_view()), name='annotation_create'),
- url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.objects.ShowAnnotationView.as_view(), name='annotation_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/?$', views.objects.ShowAnnotationView.as_view(), name='annotation_detail'),
+ url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/detail$', views.objects.ShowAnnotationViewOld.as_view(), name='annotation_detail_old'),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/readonly$', views.objects.ReadonlyAnnotationView.as_view(), name='annotation_readonly'),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/edit$', login_required(views.objects.EditAnnotationView.as_view()), name='annotation_edit'),
url(r'^collections/(?P<collection_name>[a-z0-9\-]+)/images/(?P<image_guid>[^/]+)/annotations/(?P<annotation_guid>[^/]+)/revisions/?$', django_views.generic.RedirectView.as_view(pattern_name="annotation_detail")),
--- a/src/iconolab/views/objects.py Mon Apr 17 13:31:59 2017 +0200
+++ b/src/iconolab/views/objects.py Mon Apr 17 14:42:38 2017 +0200
@@ -450,6 +450,23 @@
return render(request, 'iconolab/change_annotation.html', context)
class ShowAnnotationView(View, ContextMixin, IconolabObjectView):
+ def get(self, request, *args, **kwargs):
+ success, result = self.check_kwargs(kwargs)
+ if success:
+ (collection, image, annotation) = result
+ else:
+ return result(request)
+ context = super(ShowAnnotationView, self).get_context_data(**kwargs)
+ context['collection_name'] = self.kwargs.get('collection_name', '')
+ context['image_guid'] = self.kwargs.get('image_guid', '')
+ context['collection'] = collection
+ context['image'] = image
+ context['item'] = image.item
+ context['annotation'] = annotation
+ context['form'] = AnnotationRevisionForm()
+ return render(request, 'iconolab/detail_image.html', context)
+
+class ShowAnnotationViewOld(View, ContextMixin, IconolabObjectView):
"""
View that show a given annotation with the corresponding data, links to
submit new revisions and the paginated comments thread.
@@ -608,8 +625,8 @@
if (annotation.author != revision_author):
messages.add_message(request, messages.INFO, "Votre modification a été prise en compte. Le créateur de l'annotation a été notifié.")
- redirect_url = reverse('image_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid})
- return redirect(redirect_url + '#' + str(annotation.annotation_guid))
+ redirect_url = reverse('annotation_detail', kwargs={'collection_name': collection_name, 'image_guid': image_guid, 'annotation_guid': str(annotation.annotation_guid)})
+ return redirect(redirect_url)
context = self.get_context_data(**kwargs)
context['image'] = image
context['form'] = annotation_form
--- a/src_js/iconolab-bundle/src/components/editor/AnnotationList.vue Mon Apr 17 13:31:59 2017 +0200
+++ b/src_js/iconolab-bundle/src/components/editor/AnnotationList.vue Mon Apr 17 14:42:38 2017 +0200
@@ -3,7 +3,7 @@
<a v-for="annotation in annotations"
ref="annotations"
@click="toggleAnnotation($event, annotation)"
- :href="'#' + annotation.annotation_guid"
+ :href="getAnnotationURL(annotation.annotation_guid)"
class="list-group-item"
v-bind:class="{ active: isActive(annotation) }">
<h3 class="small list-group-item-heading">
@@ -24,7 +24,8 @@
export default {
props: [
'annotations',
- 'annotation'
+ 'annotation',
+ 'annotationUrl'
],
mounted() {
if (this.annotation) {
@@ -39,6 +40,9 @@
}
},
methods: {
+ getAnnotationURL: function(guid) {
+ return this.annotationUrl.replace(':annotation_guid', guid);
+ },
toggleAnnotation: function(e, annotation) {
e.preventDefault();
if (this.annotation && this.annotation === annotation) {
@@ -56,7 +60,7 @@
},
slideToAnnotation: function() {
var el = _.find(this.$refs.annotations, (el) => {
- return $(el).attr('href') === ('#' + this.annotation.annotation_guid);
+ return $(el).attr('href') === this.getAnnotationURL(this.annotation.annotation_guid);
});
if (el) {
var $container = $(this.$el.closest('.panel'));