Commit 7d3bfadddc238ad69efe7b8c6c26b045d7bb0b24

Authored by Gustavo
2 parents c01733e8 e56e313b

Merge branch 'refactoring' of https://github.com/amadeusproject/amadeuslms into refactoring

amadeus/static/css/base/amadeus.css
... ... @@ -1349,9 +1349,9 @@ div.dataTables_wrapper div.dataTables_paginate {
1349 1349 border-width: 1px;
1350 1350 border-style: solid;
1351 1351 border-radius: 10px;
1352   - margin-right: 10px;
  1352 + margin-right: 5px;
1353 1353 position: relative;
1354   - top: 3px;
  1354 + top: -1px;
1355 1355 display: inline-block;
1356 1356 border-spacing: 0;
1357 1357 border-collapse: collapse;
... ...
amadeus/static/js/chat.js
  1 +var new_msgs = {};
  2 +
1 3 function getModalInfo(btn, space, space_type) {
2 4 var url = btn.data('url');
3 5  
... ... @@ -6,13 +8,15 @@ function getModalInfo(btn, space, space_type) {
6 8 url: url,
7 9 data: {'space': space, 'space_type': space_type},
8 10 success: function (response) {
  11 + var modal_shown = $("#chat-modal-info").is(":visible");
  12 +
9 13 $("#chat-modal-info").html(response);
10 14  
11 15 $("#chat-modal-info").modal('show');
12 16  
13 17 $.material.init();
14 18  
15   - $('#chat-modal-info').on('shown.bs.modal', function () {
  19 + if (modal_shown) {
16 20 $(".messages-container").each(function () {
17 21 var height = $(this)[0].scrollHeight;
18 22  
... ... @@ -20,7 +24,19 @@ function getModalInfo(btn, space, space_type) {
20 24 });
21 25  
22 26 setShortChatFormSubmit();
23   - });
  27 + setFiltersSubmitAndPagination();
  28 + } else {
  29 + $('#chat-modal-info').on('shown.bs.modal', function () {
  30 + $(".messages-container").each(function () {
  31 + var height = $(this)[0].scrollHeight;
  32 +
  33 + $(this).animate({scrollTop: height}, 0);
  34 + });
  35 +
  36 + setShortChatFormSubmit();
  37 + setFiltersSubmitAndPagination();
  38 + });
  39 + }
24 40  
25 41 $("#msg_editable").on('click', function () {
26 42 $(this).trigger('focusin');
... ... @@ -93,9 +109,13 @@ function setChatFormSubmit() {
93 109 $(this).animate({scrollTop: height}, 0);
94 110 });
95 111  
96   - $('#chat-modal-form').modal('hide');
  112 + if (typeof(new_msgs[data.talk_id]) == 'undefined') {
  113 + new_msgs[data.talk_id] = [];
  114 + }
  115 +
  116 + new_msgs[data.talk_id].push(data.new_id);
97 117  
98   - alertify.success(data.message);
  118 + $('#chat-modal-form').modal('hide');
99 119 },
100 120 error: function(data) {
101 121 $("#chat-modal-form").html(data.responseText);
... ... @@ -137,13 +157,16 @@ function setShortChatFormSubmit() {
137 157 $(this).animate({scrollTop: height}, 0);
138 158 });
139 159  
  160 + if (typeof(new_msgs[data.talk_id]) == 'undefined') {
  161 + new_msgs[data.talk_id] = [];
  162 + }
  163 +
  164 + new_msgs[data.talk_id].push(data.new_id);
  165 +
140 166 editable.html("");
141 167 editable.trigger("focusout");
142   -
143   - alertify.success(data.message);
144 168 },
145 169 error: function(data) {
146   - alertify.error(data.responseText);
147 170 setShortChatFormSubmit();
148 171 },
149 172 cache: false,
... ... @@ -154,4 +177,133 @@ function setShortChatFormSubmit() {
154 177  
155 178 return false;
156 179 });
  180 +}
  181 +
  182 +function favorite(btn) {
  183 + var action = btn.data('action'),
  184 + url = btn.data('url');
  185 +
  186 + $.ajax({
  187 + url: url,
  188 + data: {'action': action},
  189 + dataType: 'json',
  190 + success: function (response) {
  191 + if (action == 'favorite') {
  192 + btn.switchClass("btn_fav", "btn_unfav", 250, "easeInOutQuad");
  193 + btn.data('action', 'unfavorite');
  194 + } else {
  195 + btn.switchClass("btn_unfav", "btn_fav", 250, "easeInOutQuad");
  196 + btn.data('action', 'favorite');
  197 + }
  198 +
  199 + btn.attr('data-original-title', response.label);
  200 + }
  201 + });
  202 +}
  203 +
  204 +function setFiltersSubmitAndPagination() {
  205 + var filters = $('#chat-filters'),
  206 + clear_filters = $('#clear_filter'),
  207 + messages = $('.messages-container'),
  208 + loading = messages.find('.loading-msgs'),
  209 + more = messages.find('.more-msgs'),
  210 + msg_section = $('.messages-list');
  211 +
  212 + filters.submit(function () {
  213 + var favorite = $(this).find("input[name='favorite']").is(':checked') ? "True" : "",
  214 + mine = $(this).find("input[name='mine']").is(':checked') ? "True" : "",
  215 + url = messages.data('url');
  216 +
  217 + msg_section.html('');
  218 +
  219 + more.hide();
  220 + loading.show();
  221 +
  222 + $.ajax({
  223 + url: url,
  224 + data: {'favorite': favorite, 'mine': mine},
  225 + dataType: 'json',
  226 + success: function (data) {
  227 + loading.hide();
  228 +
  229 + if (data.count > 0) {
  230 + msg_section.append(data.messages);
  231 +
  232 + messages.data('pages', data.num_pages);
  233 + messages.data('page', data.num_page);
  234 +
  235 + if (data.num_page < data.num_pages) {
  236 + more.show();
  237 + } else {
  238 + more.hide();
  239 + }
  240 + }
  241 +
  242 + messages.data('fav', favorite);
  243 + messages.data('mine', mine);
  244 +
  245 + messages.each(function () {
  246 + var height = $(this)[0].scrollHeight;
  247 +
  248 + $(this).animate({scrollTop: height}, 0);
  249 + });
  250 + }
  251 + });
  252 +
  253 + return false;
  254 + });
  255 +
  256 + clear_filters.click(function () {
  257 + var frm = $(this).parent();
  258 +
  259 + $("input[type='checkbox']").prop('checked', false);
  260 +
  261 + frm.submit();
  262 + });
  263 +
  264 + more.click(function () {
  265 + var url = messages.data('url'),
  266 + pageNum = messages.data('page'),
  267 + numberPages = messages.data('pages'),
  268 + favorites = messages.data('fav'),
  269 + mine = messages.data('mine'),
  270 + talk = messages.data('talk');
  271 +
  272 + var showing;
  273 +
  274 + if (typeof(new_msgs[talk]) == 'undefined') {
  275 + showing = "";
  276 + } else {
  277 + showing = new_msgs[talk].join(',');
  278 + }
  279 +
  280 + if (pageNum == numberPages) {
  281 + return false
  282 + }
  283 +
  284 + pageNum = pageNum + 1;
  285 +
  286 + more.hide();
  287 + loading.show();
  288 +
  289 + $.ajax({
  290 + url: url,
  291 + data: {'page': pageNum, 'favorite': favorites, 'mine': mine, 'showing': showing},
  292 + dataType: 'json',
  293 + success: function (data) {
  294 + loading.hide();
  295 +
  296 + msg_section.prepend(data.messages);
  297 +
  298 + messages.data('pages', data.num_pages);
  299 + messages.data('page', data.num_page);
  300 +
  301 + if (data.num_page < data.num_pages) {
  302 + more.show();
  303 + } else {
  304 + more.hide();
  305 + }
  306 + }
  307 + });
  308 + });
157 309 }
158 310 \ No newline at end of file
... ...
chat/templates/chat/_message.html
  1 +{% load chat_tags %}
  2 +
1 3 <div class="col-md-12 message-view">
2 4 <h4 class="message-user">
3 5 {{ talk_msg.user }}
... ... @@ -5,7 +7,7 @@
5 7 ({{ talk_msg.create_date }})
6 8 </span>
7 9 <span class="btn-group pull-right">
8   - <button class="btn btn-sm btn_menu btn_fav" onclick="favorite($(this))" data-url="" data-action="" data-toggle="tooltip" data-placement="top" title="">
  10 + <button class="btn btn-sm btn_menu {{ talk_msg|fav_class:request.user }}" onclick="favorite($(this))" data-url="{% url 'chat:favorite' talk_msg.id %}" data-action="{{ talk_msg|fav_action:request.user }}" data-toggle="tooltip" data-placement="top" title="{{ talk_msg|fav_label:request.user }}">
9 11 <i class="fa fa-thumb-tack"></i>
10 12 </button>
11 13 </span>
... ...
chat/templates/chat/talk.html
... ... @@ -22,7 +22,7 @@
22 22 <div class="talk-filter">
23 23 <h4>{% trans 'Filter' %}</h4>
24 24  
25   - <form id="post-filters" class="form-inline" action="" method="GET">
  25 + <form id="chat-filters" class="form-inline" action="" method="GET">
26 26 <div class="checkbox">
27 27 <label>
28 28 <input name="favorite" type="checkbox"> {% trans 'Favorite messages' %} <i class="fa fa-thumb-tack"></i>
... ... @@ -39,7 +39,16 @@
39 39 </div>
40 40 </div>
41 41 <div class="row-fluid">
42   - <div class="messages-container">
  42 + <div class="messages-container" data-talk="{{ talk_id }}" data-url="{% url 'chat:load_messages' talk_id %}" data-page="{{ page_obj.number }}" data-pages="{{ paginator.num_pages }}">
  43 + <button type="button" class="btn btn-block btn-success btn-raised more-msgs" style="{% if paginator.num_pages == page_obj.number %}display:none;{% endif %}margin:0px">
  44 + {% trans 'See old messages' %}
  45 + </button>
  46 +
  47 + <div class="alert alert-success loading-msgs" role="alert" style="display:none">
  48 + <center>
  49 + <span class="fa fa-spin fa-circle-o-notch"></span>
  50 + </center>
  51 + </div>
43 52 <div class="messages_new">
44 53 {% trans 'You have new messages...' %}
45 54 </div>
... ...
chat/templatetags/chat_tags.py
... ... @@ -7,7 +7,7 @@ from django.contrib.sessions.models import Session
7 7  
8 8 from log.models import Log
9 9  
10   -from chat.models import TalkMessages, ChatVisualizations
  10 +from chat.models import TalkMessages, ChatVisualizations, ChatFavorites
11 11  
12 12 register = template.Library()
13 13  
... ... @@ -55,4 +55,25 @@ def last_message(chat):
55 55 def notifies(chat, user):
56 56 total = ChatVisualizations.objects.filter(message__talk = chat, user = user).count()
57 57  
58   - return total
59 58 \ No newline at end of file
  59 + return total
  60 +
  61 +@register.filter(name = 'fav_label')
  62 +def fav_label(message, user):
  63 + if ChatFavorites.objects.filter(message = message, user = user).exists():
  64 + return _('Unfavorite')
  65 +
  66 + return _('Favorite')
  67 +
  68 +@register.filter(name = 'fav_action')
  69 +def fav_action(message, user):
  70 + if ChatFavorites.objects.filter(message = message, user = user).exists():
  71 + return "unfavorite"
  72 +
  73 + return "favorite"
  74 +
  75 +@register.filter(name = 'fav_class')
  76 +def fav_class(message, user):
  77 + if ChatFavorites.objects.filter(message = message, user = user).exists():
  78 + return "btn_unfav"
  79 +
  80 + return "btn_fav"
60 81 \ No newline at end of file
... ...
chat/urls.py
... ... @@ -5,6 +5,8 @@ urlpatterns = [
5 5 url(r'^$', views.GeneralIndex.as_view(), name='manage_general'),
6 6 url(r'^participants/$', views.GeneralParticipants.as_view(), name='participants_general'),
7 7 url(r'^render_message/([\w_-]+)/$', views.render_message, name='render_message'),
  8 + url(r'^favorite/([\w_-]+)/$', views.favorite, name='favorite'),
  9 + url(r'^load_messages/([\w_-]+)/$', views.load_messages, name='load_messages'),
8 10 url(r'^talk/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.GetTalk.as_view(), name = 'talk'),
9 11 url(r'^send_message/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/(?P<talk_id>[\w_-]+)/(?P<space>[\w_-]+)/(?P<space_type>[\w_-]+)/$', views.SendMessage.as_view(), name = 'create'),
10 12 url(r'^participant/profile/(?P<email>[\w.%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4})/$', views.ParticipantProfile.as_view(), name = 'profile'),
... ...
chat/views.py
... ... @@ -7,10 +7,12 @@ from django.http import JsonResponse
7 7 from django.template.loader import render_to_string
8 8 from django.core.urlresolvers import reverse, reverse_lazy
9 9 import textwrap
  10 +from datetime import datetime
10 11 from django.utils import formats
11 12 from django.utils.html import strip_tags
12 13 from django.utils.translation import ugettext_lazy as _
13 14 from django.contrib.auth.mixins import LoginRequiredMixin
  15 +from django.contrib.auth.decorators import login_required
14 16 from django.db.models import Q
15 17  
16 18 from channels import Group
... ... @@ -20,7 +22,7 @@ from categories.models import Category
20 22 from subjects.models import Subject
21 23 from users.models import User
22 24  
23   -from .models import Conversation, GeneralTalk, CategoryTalk, SubjectTalk, TalkMessages, ChatVisualizations
  25 +from .models import Conversation, GeneralTalk, CategoryTalk, SubjectTalk, TalkMessages, ChatVisualizations, ChatFavorites
24 26 from .forms import ChatMessageForm
25 27  
26 28 class GeneralIndex(LoginRequiredMixin, generic.ListView):
... ... @@ -81,7 +83,7 @@ class GeneralParticipants(LoginRequiredMixin, generic.ListView):
81 83  
82 84 context['title'] = _('Messages - Participants')
83 85 context['totals'] = self.totals
84   - context['search'] = self.request.GET.get('search')
  86 + context['search'] = self.request.GET.get('search', '')
85 87 context['chat_menu_active'] = 'subjects_menu_active'
86 88  
87 89 return context
... ... @@ -222,8 +224,71 @@ def render_message(request, talk_msg):
222 224 context = {}
223 225 context['talk_msg'] = msg
224 226  
225   - message = _('Message sent successfully!')
226   -
227 227 html = render_to_string("chat/_message.html", context, request)
228 228  
229   - return JsonResponse({'message': message, 'view': html, 'new_id': msg.id})
230 229 \ No newline at end of file
  230 + return JsonResponse({'view': html, 'new_id': msg.id, 'talk_id': msg.talk.id})
  231 +
  232 +@login_required
  233 +def favorite(request, message):
  234 + action = request.GET.get('action', '')
  235 + message = get_object_or_404(TalkMessages, id = message)
  236 +
  237 + if action == 'favorite':
  238 + ChatFavorites.objects.create(message = message, user = request.user)
  239 +
  240 + return JsonResponse({'label': _('Unfavorite')})
  241 + else:
  242 + ChatFavorites.objects.filter(message = message, user = request.user).delete()
  243 +
  244 + return JsonResponse({'label': _('Favorite')})
  245 +
  246 +def load_messages(request, talk):
  247 + context = {
  248 + 'request': request,
  249 + }
  250 +
  251 + user = request.user
  252 + favorites = request.GET.get('favorite', False)
  253 + mines = request.GET.get('mine', False)
  254 + showing = request.GET.get('showing', '')
  255 + n_views = 0
  256 +
  257 + if not favorites:
  258 + if mines:
  259 + messages = TalkMessages.objects.filter(talk__id = talk, user = user)
  260 + else:
  261 + messages = TalkMessages.objects.filter(talk__id = talk)
  262 + else:
  263 + if mines:
  264 + messages = TalkMessages.objects.filter(talk__id = talk, chat_favorites_message__isnull = False, chat_favorites_message__user = user, user = user)
  265 + else:
  266 + messages = TalkMessages.objects.filter(talk__id = talk, chat_favorites_message__isnull = False, chat_favorites_message__user = user)
  267 +
  268 + if showing: #Exclude ajax creation messages results
  269 + showing = showing.split(',')
  270 + messages = messages.exclude(id__in = showing)
  271 +
  272 + has_page = request.GET.get('page', None)
  273 +
  274 + if has_page is None:
  275 + views = ChatVisualizations.objects.filter(Q(user = user) & Q(viewed = False) & (Q(message__talk__id = talk)))
  276 + n_views = views.count()
  277 + views.update(viewed = True, date_viewed = datetime.now())
  278 +
  279 + paginator = Paginator(messages.order_by("-create_date"), 20)
  280 +
  281 + try:
  282 + page_number = int(request.GET.get('page', 1))
  283 + except ValueError:
  284 + raise Http404
  285 +
  286 + try:
  287 + page_obj = paginator.page(page_number)
  288 + except EmptyPage:
  289 + raise Http404
  290 +
  291 + context['messages'] = page_obj.object_list
  292 +
  293 + response = render_to_string("chat/_list_messages.html", context, request)
  294 +
  295 + return JsonResponse({"messages": response, "unviewed": n_views, "count": messages.count(), "num_pages": paginator.num_pages, "num_page": page_obj.number})
231 296 \ No newline at end of file
... ...