Commit 55e6ca7ab370929880e6b6fc39a4c049349c51cd
Exists in
master
and in
3 other branches
Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring
Showing
12 changed files
with
210 additions
and
16 deletions
Show diff stats
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 = []; | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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 | + ] | ... | ... |
... | ... | @@ -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> {% 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> {% 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 | ... | ... |