Browse Source

Updated watched threads page

Ralfp 12 years ago
parent
commit
4969fe4ebe

+ 3 - 48
misago/watcher/views.py

@@ -21,65 +21,20 @@ def watched_threads(request, page=0, new=False):
     queryset = queryset.order_by('-thread__last')
     if request.settings.threads_per_page < count:
         queryset = queryset[pagination['start']:pagination['stop']]
-    queryset.prefetch_related('thread__forum', 'thread__last_poster')
+    queryset.prefetch_related('thread__forum', 'thread__start_poster', 'thread__last_poster')
     threads = []
     for thread in queryset:
         thread.thread.send_email = thread.email
         thread.thread.is_read = thread.thread.last <= thread.last_read             
         threads.append(thread.thread)
-    
-    # Build form and handle submit
-    form = None
-    message = request.messages.get_message('watcher')
-    if threads:
-        form_fields = {}
-        form_fields['list_action'] = forms.ChoiceField(choices=(
-                                                                ('mails', _("Send me e-mails")),
-                                                                ('nomails', _("Don't send me e-mails")),
-                                                                ('delete', _("Remove from watched threads")),
-                                                                ))
-        list_choices = []
-        for item in threads:
-            list_choices.append((item.pk, None))
-        form_fields['list_items'] = forms.MultipleChoiceField(choices=list_choices, widget=forms.CheckboxSelectMultiple)
-        form = type('ThreadsWatchForm', (Form,), form_fields)
-        if request.method == 'POST':
-            form = form(request.POST, request=request)
-            if form.is_valid():
-                checked_items = []
-                for thread in threads:
-                    if str(thread.pk) in form.cleaned_data['list_items']:
-                        checked_items.append(thread.pk)
-                if checked_items:
-                    queryset = ThreadWatch.objects.filter(user=request.user).filter(thread_id__in = checked_items)
-                    if form.cleaned_data['list_action'] == 'mails':
-                        queryset.update(email=True)
-                        request.messages.set_flash(Message(_('Selected threads will now send e-mails with notifications when somebody replies to them.')), 'success', 'watcher')
-                    if form.cleaned_data['list_action'] == 'nomails':
-                        queryset.update(email=False)
-                        request.messages.set_flash(Message(_('Selected threads will no longer send e-mails with notifications when somebody replies to them.')), 'success', 'watcher')
-                    if form.cleaned_data['list_action'] == 'delete':
-                        queryset.delete()
-                        request.messages.set_flash(Message(_('Selected threads have been removed from watched threads list.')), 'success', 'watcher')
-                    return redirect(reverse('watched_threads_new' if new else 'watched_threads')) 
-                else:
-                    message = Message(_("You have to select at least one thread."), 'error')                    
-            else:
-                if 'list_action' in form.errors:
-                    message = Message(_("Action requested is incorrect."), 'error')
-                else:
-                    message = Message(form.non_field_errors()[0], 'error')
-        else:
-            form = form(request=request)
             
     # Display page
     return request.theme.render_to_response('watched.html',
                                             {
-                                             'total_items': count,
+                                             'items_total': count,
                                              'pagination': pagination,
                                              'new': new,
-                                             'list_form': FormFields(form).fields if form else None,
                                              'threads': threads,
-                                             'message': message,
+                                             'message': request.messages.get_message('threads'),
                                              },
                                             context_instance=RequestContext(request))

+ 8 - 2
static/sora/css/sora.css

@@ -863,7 +863,7 @@ td.lead-cell{color:#555555;font-weight:bold;}
 .table-users.list-tiny a:link,.table-users.list-tiny a:active,.table-users.list-tiny a:visited,.table-users.list-tiny a:hover{font-size:100%;}
 .table-users.list-tiny .avatar{width:22px;height:22px;}
 .table-users.list-tiny i{position:relative;top:2px;}
-.btn{background:#dcdcdc;border:1px solid #dcdcdc;*border:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;padding:4px 10px;color:#6f6f6f;font-weight:bold;text-shadow:none;}.btn:hover,.btn:active{background:#e1e1e1;border:1px solid #e1e1e1;*border:0;box-shadow:none;color:#0088cc;}
+.btn{background:#dcdcdc;border:1px solid #dcdcdc;*border:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;padding:4px 10px;color:#6f6f6f;font-weight:bold;text-shadow:none;}.btn:hover,.btn:active{background:#e1e1e1;border:1px solid #e1e1e1;*border:0;box-shadow:none;}
 .btn i{opacity:0.7;filter:alpha(opacity=70);}
 .btn:hover i,.btn:active i{opacity:1;filter:alpha(opacity=100);}
 .btn.btn-primary,.btn.btn-info,.btn.btn-success,.btn.btn-warning,.btn.btn-danger,.btn.btn-inverse{color:#f2f2f2;}.btn.btn-primary i,.btn.btn-info i,.btn.btn-success i,.btn.btn-warning i,.btn.btn-danger i,.btn.btn-inverse i{opacity:0.9;filter:alpha(opacity=90);}
@@ -1044,6 +1044,10 @@ td.lead-cell{color:#555555;font-weight:bold;}
 .post-content{font-size:100%;}
 .signature{font-size:90%;}
 .clickable{cursor:pointer;}
+.hover-opacity{opacity:0.6;filter:alpha(opacity=60);}.hover-opacity:hover,.hover-opacity:active{opacity:0.9;filter:alpha(opacity=90);}
+.hover-opacity-strong{opacity:0.3;filter:alpha(opacity=30);}.hover-opacity-strong:hover,.hover-opacity-strong:active{opacity:0.9;filter:alpha(opacity=90);}
+.span-actions{text-align:right;}.span-actions form{margin:0px;padding:0px;float:right;}
+.span-actions .btn{margin-left:8px;}
 .profile-header{overflow:auto;border-bottom:none;margin-bottom:30px;}.profile-header .avatar-height{overflow:auto;}.profile-header .avatar-height .avatar{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;margin-right:24px;width:125px;height:125px;}
 .profile-header .avatar-height h1{font-size:300%;}
 .profile-header .avatar-height .lead{color:#555555;}.profile-header .avatar-height .lead .badge{position:relative;bottom:3px;}
@@ -1057,8 +1061,10 @@ td.lead-cell{color:#555555;font-weight:bold;}
 .diff table tr td.added{background-color:#cdeacd;}.diff table tr td.added.even{background-color:#b1deb1;}
 .diff table tr td.removed{background-color:#f4c8c5;}.diff table tr td.removed.even{background-color:#eea8a2;}
 .shorts-list{border-top:1px solid #eeeeee;margin-top:12px;}.shorts-list li{border-bottom:1px solid #eeeeee;padding:0px;padding-bottom:12px;margin:0px;margin-top:12px;}.shorts-list li .avatar{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;float:left;width:40px;height:40px;}
-.shorts-list li p{margin:0px;margin-left:54px;}.shorts-list li p.message{color:#555555;}
+.shorts-list li p{margin:0px;margin-left:54px;}.shorts-list li p.title a{color:#333333;}
+.shorts-list li p.message{color:#555555;}
 .shorts-list li p.location{color:#999999;font-size:80%;}
+.shorts-list-footer{background:none;border:none;margin-top:0px;padding-left:0px;}
 .well-post.rank-team{border:1px solid #0099e6;-webkit-box-shadow:0px 0px 0px 3px #66ccff;-moz-box-shadow:0px 0px 0px 3px #66ccff;box-shadow:0px 0px 0px 3px #66ccff;}
 .team-online.rank-team ul li{background-color:#0088cc;}.team-online.rank-team ul li div a{color:#ffffff;text-shadow:0px 1px 0px #000d13;}
 .team-online.rank-team ul li div .muted{color:#02435e;}

+ 0 - 2
static/sora/css/sora/buttons.less

@@ -41,8 +41,6 @@
   &:hover, &:active {
     .button-colors(@btnBackgroundHighlight);
     box-shadow: none;
-  
-    color: @linkColor;
   }
   
   .button-icon(70);

+ 42 - 0
static/sora/css/sora/utilities.less

@@ -4,6 +4,35 @@
   cursor: pointer;
 }
 
+.hover-opacity {
+  .opacity(60);
+  
+  &:hover, &:active {
+    .opacity(90);
+  }
+}
+
+.hover-opacity-strong {
+  .opacity(30);
+  
+  &:hover, &:active {
+    .opacity(90);
+  }
+}
+
+.span-actions {
+  text-align: right;
+  
+  form {
+    margin: 0px;
+    padding: 0px;
+  }
+  
+  .btn {
+    margin-left: 8px;
+  }
+}
+
 .profile-header {
   overflow: auto;
   border-bottom: none;
@@ -136,6 +165,12 @@
       margin: 0px;
       margin-left: 54px;
       
+      &.title {
+        a {
+          color: @textColor;
+        }
+      }
+      
       &.message {        
         color: @gray;
       }
@@ -147,3 +182,10 @@
     }
   }
 }
+
+.shorts-list-footer {
+  background: none;
+  border: none;
+  margin-top: 0px;
+  padding-left: 0px;
+}

+ 63 - 52
templates/sora/watched.html

@@ -1,6 +1,5 @@
 {% extends "sora/layout.html" %}
 {% load i18n %}
-{% import "_forms.html" as form_theme with context %}
 {% import "sora/macros.html" as macros with context %}
 
 {% block title %}{{ macros.page_title(title=_('Threads you are watching')) }}{% endblock %}
@@ -13,7 +12,9 @@
 {% if message %}{{ macros.draw_message(message) }}{% endif %}
 
 <div class="list-nav">
+  {% if items_total %}
   {{ pager() }}
+  {% endif %}
   <ul class="nav nav-pills pull-right">
     <li class="{% if new %}primary{% else %}info{% endif %}"><a href="{% url 'watched_threads_new' %}">{% trans %}Unread Threads{% endtrans %}</a></li>
     <li class="{% if not new %}primary{% else %}info{% endif %}"><a href="{% url 'watched_threads' %}">{% trans %}All Threads{% endtrans %}</a></li>
@@ -21,58 +22,38 @@
 </div>
 
 {% if threads %}
-<table class="table table-striped threads-list">
-  <thead>
-    <tr>
-      <th style="width: 1%;">&nbsp;</th>
-      <th>{% trans %}Thread{% endtrans %}</th>
-      <th>{% trans %}Forum{% endtrans %}</th>
-      <th>{% trans %}Replies{% endtrans %}</th>
-      <th>{% trans %}Last Poster{% endtrans %}</th>
-      <th class="check-cell"><label class="checkbox"><input type="checkbox" class="checkbox-master"></label></th>
-    </tr>
-  </thead>
-  <tbody>
-    {% for thread in threads %}
-    <tr>
-      <td><span class="thread-icon{% if not thread.is_read %} {% if thread.closed %}thread-closed{% else %}thread-new{% endif %}{% endif %}"><i class="icon-comment icon-white"></i></span></td>
-      <td>
-        <a href="{% url 'thread' thread=thread.pk, slug=thread.slug %}">{% if not thread.is_read %}<strong>{{ thread.name }}</strong>{% else %}{{ thread.name }}{% endif %}</a> {% if not thread.is_read -%}
-        <a href="{% url 'thread_new' thread=thread.pk, slug=thread.slug %}" class="jump jump-new tooltip-top" title="{% trans %}Jump to first unread post{% endtrans %}"><i class="icon-chevron-right"></i></a>
-        {%- else -%}
-        <a href="{% url 'thread_last' thread=thread.pk, slug=thread.slug %}" class="jump jump-last tooltip-top" title="{% trans %}Jump to last post{% endtrans %}"><i class="icon-chevron-right"></i></a>
-        {%- endif %}
-        <ul class="unstyled thread-flags">
-          {% if thread.send_email %}<li><span class="label label-success tooltip-top" title="{% trans %}You will receive notification on your e-mail when somebody replies to this thread.{% endtrans %}"><i class="icon-envelope icon-white"></i></span></li>{% endif %}
-          {% if thread.closed %}<li><span class="tooltip-top" title="{% trans %}This thread is closed for new replies.{% endtrans %}"><i class="icon-lock"></i></span></li>{% endif %}
-          {% if thread.moderated %}<li><span class="tooltip-top" title="{% trans %}This thread will not be visible to other members until moderator reviews it.{% endtrans %}"><i class="icon-eye-close"></i></span></li>{% endif %}
-          {% if thread.deleted %}<li><span class="tooltip-top" title="{% trans %}This thread has been deleted.{% endtrans %}"><i class="icon-remove"></i></span></li>{% endif %}
-        </ul>
-      </td>
-      <td class="span3 thread-author"><span class="tooltip-top" title="{{ thread.start|reltimesince }}">
-        <a href="{% url 'forum' forum=thread.forum.pk, slug=thread.forum.slug %}">{{ thread.forum.name }}</a>
-      </td>
-      <td class="span1 thread-stat">{{ thread.replies|intcomma }}</td>
-      <td class="span3 thread-poster"><span class="tooltip-top" title="{{ thread.last|reltimesince }}">{% if thread.last_poster_ignored -%}
-          {% if settings.avatars_on_threads_list %}<img src="{{ macros.avatar_guest(24) }}" alt="" class="avatar-tiny"> {% endif %}<em class="muted">{% trans %}Ignored Member{% endtrans %}</em>
-          {%- elif thread.last_poster_id -%}
-          {% if settings.avatars_on_threads_list %}<img src="{{ thread.last_poster.get_avatar(24) }}" alt="" class="avatar-tiny"> {% endif %}<a href="{% url 'user' user=thread.last_poster_id, username=thread.last_poster_slug %}">{{ thread.last_poster_name }}</a>
+<ul class="unstyled shorts-list">
+  {% for thread in threads %}
+  <li id="watch-{{ loop.index }}">
+    <div class="row">
+      <div class="span7">
+        <img src="{% if thread.start_post_id %}{{ thread.start_poster.get_avatar(36) }}{% else %}{{ macros.avatar_guest(24) }}{% endif %}" class="avatar tooltip-top" title="{% trans username=thread.start_poster_name %}Thread started by {{ username }}{% endtrans %}">
+        <p class="title">
+          <a href="{% url 'thread' thread=thread.pk, slug=thread.slug %}" class="hover-opacity tooltip-top" title="{% trans %}Jump to thread start{% endtrans %}"><i class="icon-asterisk"></i></a>
+          {% if not thread.is_read -%}
+          <a href="{% url 'thread_new' thread=thread.pk, slug=thread.slug %}" class="jump jump-new tooltip-top" title="{% trans %}Jump to first unread post{% endtrans %}">
           {%- else -%}
-          {% if settings.avatars_on_threads_list %}<img src="{{ macros.avatar_guest(24) }}" alt="" class="avatar-tiny"> {% endif %}<em class="muted">{{ thread.last_poster_name }}</em>
-          {%- endif %}</span></td>
-      <td class="check-cell"><label class="checkbox"><input form="threads_form" name="{{ list_form['list_items']['html_name'] }}" type="checkbox" class="checkbox-member" value="{{ thread.pk }}"{% if list_form['list_items']['has_value'] and ('' ~ thread.pk) in list_form['list_items']['value'] %} checked="checked"{% endif %}></label></td>      
-    </tr>
-    {% endfor %}
-  </tbody>
-</table>
-<div class="form-actions table-footer">
-  <form id="threads_form" class="form-inline pull-right" action="{% if new %}{% url 'watched_threads_new' %}{% else %}{% url 'watched_threads' %}{% endif %}" method="POST">
-    <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
-    {{ form_theme.input_select(list_form['list_action'],width=3) }}
-    <button type="submit" class="btn btn-primary">{% trans %}Go{% endtrans %}</button>
-  </form>
-</div>
-
+          <a href="{% url 'thread_last' thread=thread.pk, slug=thread.slug %}" class="jump jump-last tooltip-top" title="{% trans %}Jump to last post{% endtrans %}">
+          {%- endif -%}{% if not thread.is_read %}<strong>{{ thread.name }}</strong>{% else %}{{ thread.name }}{% endif %}</a>
+        </p>
+        <p class="location">{% trans forum=forum(thread.forum), starter=username(thread.start_poster_id, thread.start_poster_name, thread.start_poster_slug), start=thread.start|reldate %}Thread started by {{ starter }} in {{ forum }} on {{ start }}.{% endtrans %}</p>
+      </div>
+      <div class="span5 span-actions hover-opacity-strong">
+        <form action="{% url 'thread_unwatch' thread=thread.pk, slug=thread.slug %}" class="form-inline pull-right" method="post">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <input type="hidden" name="retreat" value="{{ delete_retreat(loop) }}">
+          <button class="btn btn-danger"><i class="icon-remove icon-white"></i> {% trans %}Unwatch{% endtrans %}</button>
+        </form>
+        <form action="{% if thread.send_email %}{% url 'thread_unwatch_email' thread=thread.pk, slug=thread.slug %}{% else %}{% url 'thread_watch_email' thread=thread.pk, slug=thread.slug %}{% endif %}" class="form-inline pull-right" method="post">
+          <input type="hidden" name="{{ csrf_id }}" value="{{ csrf_token }}">
+          <input type="hidden" name="retreat" value="{{ request_path }}#watch-{{ loop.index }}">
+          <button class="btn{% if thread.send_email %} btn-success{% endif %}"><i class="icon-envelope{% if thread.send_email %} icon-white{% endif %}"></i> {% trans %}E-mail{% endtrans %}</button>
+        </form>
+      </div>
+    </div>
+  </li>
+  {% endfor %}
+</ul>
 <div class="list-nav last">
   {{ pager() }}
 </div>
@@ -121,3 +102,33 @@
     </li>
   </ul>
 {%- endmacro %}
+
+
+{% macro forum(forum) -%}
+<a href="{% url 'forum' forum=forum.pk, slug=forum.slug %}">{{ forum.name }}</a>
+{%- endmacro %}
+
+{% macro username(id, username, slug) -%}
+{%- if id -%}
+<a href="{% url 'user' user=id, username=slug %}">{{ username }}</a>
+{%- else -%}
+{{ username }}
+{%- endif -%}
+{%- endmacro %}
+
+
+{% macro delete_retreat(loop) -%}
+{%- if pagination['page'] == 1 -%}
+  {{ request_path }}{% if not (loop.first and loop.last) %}#watch-{{ loop.index }}{% endif %}
+{%- else -%}
+  {%- if loop.first and loop.last -%}
+    {%- if new -%}
+      {%- if pagination['prev'] > 1 %}{% url 'watched_threads_new' page=pagination['prev'] %}{% else %}{% url 'watched_threads_new' %}{% endif %}
+    {%- else -%}
+      {%- if pagination['prev'] > 1 %}{% url 'watched_threads' page=pagination['prev'] %}{% else %}{% url 'watched_threads' %}{% endif %}
+    {%- endif -%}#watch-{{ settings.threads_per_page }}
+  {%- else -%}
+    {{ request_path }}#watch-{{ loop.index }}
+  {%- endif -%}
+{%- endif  -%}
+{%- endmacro %}