Added complete_description attribute to Collection for homepage #12 + Vue.js components to handle display and sart to harmonize javascript
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/iconolab/migrations/0013_auto_20160923_1404.py Thu Oct 06 15:07:50 2016 +0200
@@ -0,0 +1,37 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.10 on 2016-09-23 14:04
+from __future__ import unicode_literals
+
+from django.conf import settings
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('iconolab', '0012_auto_20160817_1019'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='collection',
+ name='complete_description',
+ field=models.TextField(blank=True, default='', null=True),
+ ),
+ migrations.AlterField(
+ model_name='collection',
+ name='description',
+ field=models.TextField(blank=True, default='', null=True),
+ ),
+ migrations.AlterField(
+ model_name='metacategory',
+ name='collection',
+ field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='metacategories', to='iconolab.Collection'),
+ ),
+ migrations.AlterField(
+ model_name='userprofile',
+ name='user',
+ field=models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='profile', to=settings.AUTH_USER_MODEL),
+ ),
+ ]
--- a/src/iconolab/models.py Wed Sep 21 14:48:21 2016 +0200
+++ b/src/iconolab/models.py Thu Oct 06 15:07:50 2016 +0200
@@ -35,7 +35,8 @@
class Collection(models.Model):
name = models.SlugField(max_length=50, unique=True)
verbose_name = models.CharField(max_length=50, null=True, blank=True)
- description = models.TextField(null=True)
+ description = models.TextField(null=True, blank=True, default="")
+ complete_description = models.TextField(null=True, blank=True, default="")
image = models.ImageField(upload_to='uploads/', height_field='height', width_field='width', null=True, blank=True)
height = models.IntegerField(null=True, blank=True)
width = models.IntegerField(null=True, blank=True)
--- a/src/iconolab/templates/iconolab/home.html Wed Sep 21 14:48:21 2016 +0200
+++ b/src/iconolab/templates/iconolab/home.html Thu Oct 06 15:07:50 2016 +0200
@@ -6,51 +6,47 @@
{% load iconolab_tags %}
{% block content %}
-
-{% for collection in collections.all %}
-<div id="collection-panel-{{collection.name}}" class="container collection-container panel panel-default {% if forloop.first %}selected{% endif %}" style="padding-top: 15px; padding-bottom: 15px;">
- <div class="row">
- <div class="col-md-4">
- {% thumbnail collection.image "350x350" crop=False as im %}
- <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
- {% endthumbnail %}
- </div>
- <div class="col-md-8">
- <h1 class="collection-title" style="margin-top:0px;"><small>Fonds Iconolab</small> {{ collection.verbose_name }}</h1>
- <p class="text-justify"> {{collection.description | safe}} </p>
- <a href="{% url 'collection_home' collection.name %}" class="btn btn-default btn-sm">Contribuer</a>
+<div id="homepage-main" class="row">
+ <div id="main-panel" class="container" style="padding-top: 15px; padding-bottom: 15px;">
+ <h1 class="text-center"><small>Projet</small> Iconolab</h1>
+ </div>
+ {% for collection in collections.all %}
+ <div id="collection-panel-{{collection.name}}" class="container collection-container panel panel-default" style="padding-top: 15px; padding-bottom: 15px;">
+ <div class="row">
+ <div class="col-md-4">
+ {% thumbnail collection.image "350x350" crop=False as im %}
+ <img src="{{ im.url }}" width="{{ im.width }}" height="{{ im.height }}">
+ {% endthumbnail %}
+ </div>
+ <div class="col-md-8">
+ <h1 class="collection-title" style="margin-top:0px;"><small>Fonds Iconolab</small> {{ collection.verbose_name }}</h1>
+ <p id="collection-description-short-{{collection.name}}" class="text-justify collection-description">
+ {{collection.description | safe}}
+ {% if collection.complete_description %}<a id="show-complete-{{collection.name}}" class="show-complete-link" @click="showCompleteDescription('{{collection.name}}')"> Voir plus</a></p>{% endif %}
+ </p>
+ <p id="collection-description-complete-{{collection.name}}" class="text-justify collection-description-complete">
+ {{collection.complete_description | safe}}
+ <a id="hide-complete-{{collection.name}}" class="hide-complete-link" @click="hideCompleteDescription('{{collection.name}}')"> Voir moins</a>
+ </p>
+ <a href="{% url 'collection_home' collection.name %}" class="btn btn-default btn-sm">Contribuer</a>
+ </div>
</div>
</div>
-</div>
-{% endfor %}
-<div class="collection-navbar text-center">
- <h4>Les autres fonds dans Iconolab</h4>
- <ul class="list-inline list-unstyled">
- {% for collection in collections.all %}
- <li><div id="show-collection-{{collection.name}}" class="btn btn-default btn-xs {% if forloop.first %}btn-primary{% endif %} btn-collection">{{collection.verbose_name}}</div></li>
- {% endfor %}
- </ul>
+ {% endfor %}
+ <div class="collection-navbar text-center">
+ <h4>Les fonds d'images du projet Iconolab</h4>
+ <ul class="list-inline list-unstyled">
+ {% for collection in collections.all %}
+ <li><div id="show-collection-{{collection.name}}" class="btn btn-default btn-xs btn-collection" @click="pickCollection('{{collection.name}}')">{{collection.verbose_name}}</div></li>
+ {% endfor %}
+ </ul>
+ </div>
</div>
{% endblock %}
{% block footer_js %}
<script>
- $(".collection-container:not(.selected)").hide();
- var selectedContainerId = $(".collection-container.selected").attr("id");
- if(selectedContainerId) {
- var selectedID = /collection\-panel\-([0-9a-z\-]+)/.exec($(".collection-container.selected").attr("id"))[1];
- $(".btn-collection").on("click", function(e){
- selectedID = /show\-collection\-([0-9a-z\-]+)/.exec($(this).attr("id"))[1];
- if (!$(this).hasClass("btn-primary")){
- $(".collection-container").removeClass("selected");
- $(".collection-container:not(.selected)").hide();
- $(".btn-collection").removeClass("btn-primary")
- $(this).addClass("btn-primary")
- $(".collection-container#collection-panel-"+selectedID).show()
- $(".collection-container#collection-panel-"+selectedID).addClass("selected")
- }
- });
- }
-
+ _v = new Vue(iconolab.CollectionSelector);
+ _v.$mount("#homepage-main");
</script>
{% endblock %}
--- a/src/iconolab/urls.py Wed Sep 21 14:48:21 2016 +0200
+++ b/src/iconolab/urls.py Thu Oct 06 15:07:50 2016 +0200
@@ -74,4 +74,5 @@
urlpatterns += staticfiles_urlpatterns()
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
#static url
+ print("wow runserver")
urlpatterns += static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
--- a/src/iconolab/views/iconolab_objects.py Wed Sep 21 14:48:21 2016 +0200
+++ b/src/iconolab/views/iconolab_objects.py Thu Oct 06 15:07:50 2016 +0200
@@ -25,7 +25,7 @@
return render(request, 'iconolab/home.html', context)
class TestView(View):
- template_name = "iconolab/compare.html"
+ template_name = 'iconolab/compare.html'
def get(self, request, *args, **kwargs):
return render(request, self.template_name)
@@ -137,28 +137,108 @@
context = super(CollectionHomepageView, self).get_context_data(**kwargs)
context['collection_name'] = self.kwargs.get('collection_name', '')
context['collection'] = collection
-
- # Recent annotations
- context['recent_annotations'] = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
+
+ # get Pagination and navigation query args
+ try:
+ items_page = int(request.GET.get('items_page', '1'))
+ except ValueError:
+ items_page = 1
+ try:
+ items_per_page = int(request.GET.get('items_perpage', '12'))
+ except ValueError:
+ items_per_page = 12
+
+ try:
+ recent_page = int(request.GET.get('recent_page', '1'))
+ except ValueError:
+ recent_page = 1
+ try:
+ recent_per_page = int(request.GET.get('recent_perpage', '10'))
+ except ValueError:
+ recent_per_page = 10
+
+ try:
+ revised_page = int(request.GET.get('revised_page', '1'))
+ except ValueError:
+ revised_page = 1
+ try:
+ revised_per_page = int(request.GET.get('revised_perpage', '10'))
+ except ValueError:
+ revised_per_page = 10
+
+ try:
+ contributions_page = int(request.GET.get('contributions_page', '1'))
+ except ValueError:
+ contributions_page = 1
+ try:
+ contributions_per_page = int(request.GET.get('contributions_perpage', '10'))
+ except ValueError:
+ contributions_per_page = 10
+
+ active_list = request.GET.get('show', 'items')
+ if active_list not in ['items', 'recent', 'revised', 'contributions']:
+ active_list = 'items'
+ context["active_list"] = active_list
+
+ # Paginated objects list
+ context["items_page"] = items_page
+ context["items_perpage"] = items_per_page
+ items_paginator = Paginator(collection.items.all(), items_per_page)
+ try:
+ context["items_list"] = items_paginator.page(items_page)
+ except PageNotAnInteger:
+ context["items_list"] = items_paginator.page(1)
+ except EmptyPage:
+ context["items_list"] = items_paginator.page(items_paginator.num_pages)
+
+ # Paginated recent annotations list
+ context["recent_page"] = recent_page
+ context["recent_perpage"] = recent_per_page
+ recent_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
'current_revision',
'stats'
).order_by('-current_revision__created')
-
- # Recent annotations
- context['revised_annotations'] = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
+ recent_paginator = Paginator(recent_annotations, recent_per_page)
+ try:
+ context["recent_list"] = recent_paginator.page(recent_page)
+ except PageNotAnInteger:
+ context["recent_list"] = recent_paginator.page(1)
+ except EmptyPage:
+ context["recent_list"] = recent_paginator.page(recent_paginator.num_pages)
+
+ # Paginated revised annotations list
+ context["revised_page"] = revised_page
+ context["revised_perpage"] = revised_per_page
+ revised_annotations = Annotation.objects.filter(image__item__collection__name=collection.name).prefetch_related(
'current_revision',
'stats'
- ).annotate(revision_count=Count("revisions")).order_by('-revision_count')
-
+ ).annotate(revision_count=Count('revisions')).order_by('-revision_count')
+ revised_paginator = Paginator(revised_annotations, revised_per_page)
+ try:
+ context["revised_list"] = revised_paginator.page(revised_page)
+ except PageNotAnInteger:
+ context["revised_list"] = revised_paginator.page(1)
+ except EmptyPage:
+ context["revised_list"] = revised_paginator.page(revised_paginator.num_pages)
+
+ # Paginated contribution calls annotation list
+ context["contributions_page"] = contributions_page
+ context["contributions_perpage"] = contributions_per_page
contrib_calls_annotations_ids = list(set(MetaCategoryInfo.objects.filter(
metacategory__collection__name=collection.name,
metacategory__triggers_notifications=MetaCategory.CONTRIBUTORS
- ).order_by("comment__submit_date").values_list("comment__object_pk", flat=True)))
-
+ ).order_by('comment__submit_date').values_list('comment__object_pk', flat=True)))
collection_annotations = Annotation.objects.filter(id__in=contrib_calls_annotations_ids).all()
collection_ann_dict = dict([(str(annotation.id), annotation) for annotation in collection_annotations])
- context["contribution_calls_annotations_list"] = [collection_ann_dict[id] for id in contrib_calls_annotations_ids]
-
+ contributions_annotations = [collection_ann_dict[id] for id in contrib_calls_annotations_ids]
+ contributions_paginator = Paginator(contributions_annotations, contributions_per_page)
+ try:
+ context["contributions_list"] = contributions_paginator.page(contributions_page)
+ except PageNotAnInteger:
+ context["contributions_list"] = contributions_paginator.page(1)
+ except EmptyPage:
+ context["contributions_list"] = contributions_paginator.page(contributions_paginator.num_pages)
+
return render(request, 'iconolab/collection_home.html', context)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src_js/iconolab-bundle/src/components/collectionhome/descriptionviewer/DescriptionViewer.vue Thu Oct 06 15:07:50 2016 +0200
@@ -0,0 +1,20 @@
+<script>
+export default {
+ data: {
+
+ },
+ mounted() {
+ $(".collection-description-complete").hide();
+ },
+ methods: {
+ showCompleteDescription: function(){
+ $(".collection-description").hide()
+ $(".collection-description-complete").show()
+ },
+ hideCompleteDescription: function(name){
+ $(".collection-description-complete").hide()
+ $(".collection-description").show()
+ }
+ },
+}
+</script>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src_js/iconolab-bundle/src/components/collectionhome/tabselector/TabSelector.vue Thu Oct 06 15:07:50 2016 +0200
@@ -0,0 +1,24 @@
+<script>
+
+export default {
+ data () {
+ return {}
+ },
+ mounted () {
+ var self=this;
+ $(".collection-home-block:not(.selected)").hide();
+ },
+ methods: {
+ switchTab: function(name){
+ $(".collection-home-block").removeClass("selected");
+ $(".collection-home-block").hide();
+ $(".collection-home-tab").parent().removeClass("active");
+ $("#list-"+name).show();
+ $("#tab-"+name).addClass("active");
+
+ }
+ }
+}
+
+
+</script>
\ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src_js/iconolab-bundle/src/components/collectionselector/CollectionSelector.vue Thu Oct 06 15:07:50 2016 +0200
@@ -0,0 +1,39 @@
+<script>
+
+export default {
+ data () {
+ return {}
+ },
+ mounted () {
+ var self=this;
+ $(".collection-container").hide();
+ $(".collection-description-complete").hide();
+ },
+ methods: {
+ pickCollection: function(name){
+ if (!$("#show-collection-"+name).hasClass("btn-primary")){
+ $("#main-panel").hide();
+ $(".collection-container").removeClass("selected");
+ $(".collection-container:not(.selected)").hide();
+ $(".collection-description-complete").hide()
+ $(".collection-description").show()
+ $(".btn-collection").removeClass("btn-primary")
+ $("#show-collection-"+name).addClass("btn-primary")
+ $(".collection-container#collection-panel-"+name).show()
+ $(".collection-container#collection-panel-"+name).addClass("selected")
+ }
+ },
+ showCompleteDescription: function(name){
+ $(".collection-description-complete").hide()
+ $("#collection-description-short-"+name).hide()
+ $("#collection-description-complete-"+name).show()
+ },
+ hideCompleteDescription: function(name){
+ $(".collection-description-complete").hide()
+ $("#collection-description-short-"+name).show()
+ }
+ }
+}
+
+
+</script>
\ No newline at end of file
--- a/src_js/iconolab-bundle/src/main.js Wed Sep 21 14:48:21 2016 +0200
+++ b/src_js/iconolab-bundle/src/main.js Thu Oct 06 15:07:50 2016 +0200
@@ -7,6 +7,9 @@
import Cutout from './components/cutout'
import Zoomview from './components/zoomview/Zoomview.vue'
import MergeTool from './components/mergetool/MergeTool.vue'
+import CollectionSelector from './components/collectionselector/CollectionSelector.vue'
+import TabSelector from './components/collectionhome/tabselector/TabSelector.vue'
+import DescriptionViewer from './components/collectionhome/descriptionviewer/DescriptionViewer.vue'
import DiffViewer from './components/diffviewer/diffviewer.vue'
import jsondiffpatch from 'jsondiffpatch'
@@ -16,6 +19,9 @@
Cutout : Cutout,
JsDiff: Diff,
JsonDiff: jsondiffpatch,
+ CollectionSelector: CollectionSelector,
+ TabSelector: TabSelector,
+ DescriptionViewer: DescriptionViewer,
VueComponents : {
Typeahead: Typeahead,
MergeTool: MergeTool,