Added complete_description attribute to Collection for homepage #12 + Vue.js components to handle display and sart to harmonize javascript
authordurandn
Thu, 06 Oct 2016 15:07:50 +0200
changeset 212 1c7cce196665
parent 211 18d1da86fc67
child 213 43aa7c589048
Added complete_description attribute to Collection for homepage #12 + Vue.js components to handle display and sart to harmonize javascript
src/iconolab/migrations/0013_auto_20160923_1404.py
src/iconolab/models.py
src/iconolab/templates/iconolab/home.html
src/iconolab/urls.py
src/iconolab/views/iconolab_objects.py
src_js/iconolab-bundle/src/components/collectionhome/descriptionviewer/DescriptionViewer.vue
src_js/iconolab-bundle/src/components/collectionhome/tabselector/TabSelector.vue
src_js/iconolab-bundle/src/components/collectionselector/CollectionSelector.vue
src_js/iconolab-bundle/src/main.js
--- /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,