Commit a98874b2c97343982adbda4092a6e1b4af638490

Authored by Zambom
1 parent 614033fd

Adding resource list ordering

amadeus/static/css/base/amadeus.css
... ... @@ -767,6 +767,8 @@ a.add-row {
767 767 padding: 10px 15px;
768 768 margin-bottom: -1px;
769 769 border-width: 1px !important;
  770 + overflow: inherit;
  771 + cursor: pointer;
770 772 }
771 773  
772 774 .resource_list > .list-group-item:last-child {
... ... @@ -777,4 +779,13 @@ a.add-row {
777 779  
778 780 .resource_list .list-group-item .list-group-item-heading {
779 781 font-weight: 500;
  782 +}
  783 +
  784 +.resource_list .btn-group {
  785 + display: inline;
  786 + margin: 0px;
  787 +}
  788 +
  789 +.resource_list a:hover, .resource_list a:focus {
  790 + text-decoration: none;
780 791 }
781 792 \ No newline at end of file
... ...
amadeus/static/css/themes/green.css
... ... @@ -361,10 +361,22 @@ a.add-row {
361 361 border: 1px solid #ddd;
362 362 }
363 363  
  364 +.resource_list > .list-group-item:hover {
  365 + background: #F5F5F5;
  366 +}
  367 +
364 368 .resource_list > .list-group-item:last-child {
365 369 border-bottom: 1px solid #ddd !important;
366 370 }
367 371  
  372 +.resource_list .category-card-items i {
  373 + color: #CCCCCC;
  374 +}
  375 +
  376 +.resource_list a {
  377 + color: inherit;
  378 +}
  379 +
368 380 @media(max-width: 768px) {
369 381 .navbar .navbar-nav .dropdown .dropdown-menu li > a {
370 382 color: #333333 !important;
... ...
amadeus/static/js/topics.js
... ... @@ -31,7 +31,7 @@ $('.collapse').on('hide.bs.collapse', function (e) {
31 31 $("#topics-accordion").sortable({
32 32 delay: 100,
33 33 distance: 5,
34   - handle: 'i.fa-arrows',
  34 + handle: 'i.move_topic',
35 35 update: function( event, ui ) {
36 36 var cont = 1;
37 37 var data = [];
... ...
topics/decorators.py 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +def always_as_child(fn):
  2 + """
  3 + Tries to run child model method if relevant
  4 + should be applied on KnowsChild child class
  5 + """
  6 + def f(self, *args, **kwargs):
  7 + child_self = self.as_child()
  8 + f_parent = getattr(self.__class__, fn.__name__)
  9 + f_child = getattr(child_self.__class__, fn.__name__)
  10 +
  11 + if f_parent != f_child:
  12 + return f_child(child_self, *args, **kwargs)
  13 + else:
  14 + return fn(self, *args, **kwargs)
  15 +
  16 + return f
0 17 \ No newline at end of file
... ...
topics/migrations/0006_resource__my_subclass.py 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-01-23 21:18
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations, models
  6 +
  7 +
  8 +class Migration(migrations.Migration):
  9 +
  10 + dependencies = [
  11 + ('topics', '0005_resource'),
  12 + ]
  13 +
  14 + operations = [
  15 + migrations.AddField(
  16 + model_name='resource',
  17 + name='_my_subclass',
  18 + field=models.CharField(default='webpage', max_length=200),
  19 + preserve_default=False,
  20 + ),
  21 + ]
... ...
topics/migrations/0007_auto_20170123_1911.py 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +# -*- coding: utf-8 -*-
  2 +# Generated by Django 1.10 on 2017-01-23 22:11
  3 +from __future__ import unicode_literals
  4 +
  5 +from django.db import migrations
  6 +
  7 +
  8 +class Migration(migrations.Migration):
  9 +
  10 + dependencies = [
  11 + ('topics', '0006_resource__my_subclass'),
  12 + ]
  13 +
  14 + operations = [
  15 + migrations.AlterModelOptions(
  16 + name='resource',
  17 + options={'ordering': ['order'], 'verbose_name': 'Resource', 'verbose_name_plural': 'Resources'},
  18 + ),
  19 + ]
... ...
topics/models.py
... ... @@ -6,6 +6,8 @@ from subjects.models import Subject, Tag
6 6 from students_group.models import StudentsGroup
7 7 from users.models import User
8 8  
  9 +from .decorators import always_as_child
  10 +
9 11 class Topic(models.Model):
10 12 name = models.CharField(_('Name'), max_length = 200)
11 13 slug = AutoSlugField(_("Slug"), populate_from = 'name', unique = True)
... ... @@ -25,7 +27,27 @@ class Topic(models.Model):
25 27 def __str__(self):
26 28 return self.name
27 29  
28   -class Resource(models.Model):
  30 +"""
  31 + Abstract model to make easier to know which kind of Resource we are dealing with
  32 +"""
  33 +class KnowsChild(models.Model):
  34 + # Make a place to store the class name of the child
  35 + _my_subclass = models.CharField(max_length=200)
  36 +
  37 + class Meta:
  38 + abstract = True
  39 +
  40 + def as_child(self):
  41 + return getattr(self, self._my_subclass)
  42 +
  43 + def save(self, *args, **kwargs):
  44 + # save what kind we are.
  45 + if not self._my_subclass:
  46 + self._my_subclass = self.__class__.__name__.lower()
  47 +
  48 + super(KnowsChild, self).save(*args, **kwargs)
  49 +
  50 +class Resource(KnowsChild):
29 51 name = models.CharField(_('Name'), max_length = 200)
30 52 slug = AutoSlugField(_("Slug"), populate_from = 'name', unique = True)
31 53 brief_description = models.TextField(_('Brief Description'), blank = True)
... ... @@ -43,6 +65,15 @@ class Resource(models.Model):
43 65 class Meta:
44 66 verbose_name = _('Resource')
45 67 verbose_name_plural = _('Resources')
  68 + ordering = ['order']
46 69  
47 70 def __str__(self):
48 71 return self.name
  72 +
  73 + """
  74 + Method to get the appropriated view link
  75 + Must override in the child models
  76 + """
  77 + @always_as_child
  78 + def access_link(self):
  79 + pass
... ...
topics/templates/topics/list.html
... ... @@ -28,7 +28,7 @@
28 28 <li><a href="{% url 'topics:update' subject.slug topic.slug %}"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>{% trans 'Edit' %}</a></li>
29 29 <li><a href="javascript:delete_topic('{% url 'topics:delete' topic.slug %}')"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>&nbsp;{% trans 'Remove' %}</a></li>
30 30 </ul>
31   - <a href="" ><i class="fa fa-arrows" aria-hidden="true"></i></a>
  31 + <a href="" ><i class="fa fa-arrows move_topic" aria-hidden="true"></i></a>
32 32 </div>
33 33 {% endif %}
34 34 </div>
... ...
topics/urls.py
... ... @@ -8,4 +8,5 @@ urlpatterns = [
8 8 url(r'^update/(?P<sub_slug>[\w_-]+)/(?P<slug>[\w_-]+)/$', views.UpdateView.as_view(), name = 'update'),
9 9 url(r'^delete/(?P<slug>[\w_-]+)/$', views.DeleteView.as_view(), name = 'delete'),
10 10 url(r'^update_order/$', views.update_order, name = 'update_order'),
  11 + url(r'^update_resource_order/$', views.update_resource_order, name = 'update_resource_order'),
11 12 ]
... ...
topics/views.py
... ... @@ -12,7 +12,7 @@ from amadeus.permissions import has_subject_permissions
12 12  
13 13 from subjects.models import Subject
14 14  
15   -from .models import Topic
  15 +from .models import Topic, Resource
16 16 from .forms import TopicForm
17 17  
18 18 class CreateView(LoginRequiredMixin, generic.edit.CreateView):
... ... @@ -149,4 +149,19 @@ def update_order(request):
149 149  
150 150 return JsonResponse({'message': 'ok'})
151 151  
  152 + return JsonResponse({'message': 'No data received'})
  153 +
  154 +def update_resource_order(request):
  155 + data = request.GET.get('data', None)
  156 +
  157 + if not data is None:
  158 + data = json.loads(data)
  159 +
  160 + for t_data in data:
  161 + resource = get_object_or_404(Resource, id = t_data['resource_id'])
  162 + resource.order = t_data['resource_order']
  163 + resource.save()
  164 +
  165 + return JsonResponse({'message': 'ok'})
  166 +
152 167 return JsonResponse({'message': 'No data received'})
153 168 \ No newline at end of file
... ...
webpage/models.py
... ... @@ -12,4 +12,10 @@ class Webpage(Resource):
12 12 verbose_name_plural = _('WebPages')
13 13  
14 14 def __str__(self):
15   - return self.name
16 15 \ No newline at end of file
  16 + return self.name
  17 +
  18 + def access_link(self):
  19 + if self.show_window:
  20 + return 'webpages:window_view'
  21 +
  22 + return 'webpages:view'
... ...
webpage/templates/webpages/list.html
1 1 {% load static i18n pagination permissions_tags %}
2 2 {% load django_bootstrap_breadcrumbs %}
3 3  
4   -<div class="list-group resource_list">
  4 +<div id="resource_{{ topic.slug }}" class="list-group resource_list">
5 5 {% for resource in topic.resource_topic.all %}
6 6 <div class="list-group-item">
  7 + <input type="hidden" class="id_inp" name="id" value="{{ resource.id }}" />
  8 + <input type="hidden" class="order_inp" name="order" value="{{ resource.order }}" />
  9 + <input type="hidden" class="url_order" value="{% url 'topics:update_resource_order' %}" />
  10 +
7 11 <h4 class="pull-left list-group-item-heading">
8   - {{ resource }}
  12 + <a href="{% url resource.access_link resource.slug %}" class="resource_link" {% if resource.show_window %}target="_blank"{% endif %}>
  13 + {{ resource }}
  14 + </a>
9 15 </h4>
10 16 <div class="pull-right category-card-items">
11   - <a href=""><i class="fa fa-arrows" aria-hidden="true"></i></a>
12   - <a href="" id="moreResources" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
13   - <i class="fa fa-ellipsis-v" aria-hidden="true"></i>
14   - </a>
15   - <ul class="dropdown-menu pull-right" aria-labelledby="moreResources">
16   - <li><a href="{% url 'topics:update' subject.slug topic.slug %}"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>{% trans 'Edit' %}</a></li>
17   - <li><a href="javascript:delete_topic('{% url 'topics:delete' topic.slug %}')"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>&nbsp;{% trans 'Remove' %}</a></li>
18   - </ul>
  17 + <a><i class="fa fa-arrows" aria-hidden="true"></i></a>
  18 + <span class="btn-group">
  19 + <a href="" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
  20 + <i class="fa fa-ellipsis-v" aria-hidden="true"></i>
  21 + </a>
  22 + <ul class="dropdown-menu pull-right" role="menu" aria-labelledby="moreResources">
  23 + <li><a href="{% url 'topics:update' subject.slug topic.slug %}"><i class="fa fa-pencil fa-fw" aria-hidden="true"></i>{% trans 'Edit' %}</a></li>
  24 + <li><a href="javascript:delete_topic('{% url 'topics:delete' topic.slug %}')"><i class="fa fa-trash fa-fw" aria-hidden="true"></i>{% trans 'Remove' %}</a></li>
  25 + </ul>
  26 + </span>
19 27 </div>
20 28 <br clear="all" />
21 29 {% autoescape off %}
... ... @@ -23,4 +31,58 @@
23 31 {% endautoescape %}
24 32 </div>
25 33 {% endfor %}
26   -</div>
27 34 \ No newline at end of file
  35 +</div>
  36 +<script type="text/javascript">
  37 + $(".list-group-item").unbind().on('click', function (e) {
  38 + var arrow = $(this).find('i.fa-arrows').is(e.target),
  39 + menu = $(this).find('i.fa-ellipsis-v').is(e.target);
  40 +
  41 + if (!arrow && !menu) {
  42 + var link = $(this).find('.resource_link').attr('href'),
  43 + target = $(this).find('.resource_link').attr('target');
  44 +
  45 + if (typeof(target) != 'undefined') {
  46 + window.open(link, target);
  47 + } else {
  48 + window.location = link;
  49 + }
  50 + }
  51 + });
  52 +
  53 + $("#resource_{{ topic.slug }}").sortable({
  54 + delay: 100,
  55 + distance: 5,
  56 + handle: 'i.fa-arrows',
  57 + update: function( event, ui ) {
  58 + var cont = 1;
  59 + var data = [];
  60 +
  61 + $("#resource_{{ topic.slug }}").find('.order_inp').each(function () {
  62 + $(this).val(cont++);
  63 +
  64 + data.push({
  65 + 'resource_id': $(this).parent().find('.id_inp').val(),
  66 + 'resource_order': $(this).val()
  67 + });
  68 + });
  69 +
  70 + data = JSON.stringify(data);
  71 +
  72 + sendUpdateResource(data);
  73 + },
  74 + });
  75 +
  76 + function sendUpdateResource(data) {
  77 + $.ajax({
  78 + url: $("#resource_{{ topic.slug }}").find('.url_order').val(),
  79 + dataType: 'json',
  80 + data: {'data': data},
  81 + success: function(response) {
  82 + console.log(response);
  83 + },
  84 + error: function(response) {
  85 + console.log(response);
  86 + }
  87 + });
  88 + }
  89 +</script>
28 90 \ No newline at end of file
... ...