summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAurélien Bompard <aurelien@bompard.org>2013-05-17 18:52:37 +0200
committerAurélien Bompard <aurelien@bompard.org>2013-05-17 18:52:37 +0200
commita6cc5ed7ac9e95a4e21c49f9159c66ff9a726600 (patch)
tree079a8bac20271a3c8f7cc852645f12f2317e11da
parent3759498f4ecf5cae88eecf197b1f2cf075bc0565 (diff)
downloadhyperkitty-a6cc5ed7ac9e95a4e21c49f9159c66ff9a726600.tar.gz
hyperkitty-a6cc5ed7ac9e95a4e21c49f9159c66ff9a726600.tar.xz
hyperkitty-a6cc5ed7ac9e95a4e21c49f9159c66ff9a726600.zip
Load replies in chunks to avoid overloading the browser
-rw-r--r--hyperkitty/static/js/hyperkitty.js46
-rw-r--r--hyperkitty/templates/threads/participants.html14
-rw-r--r--hyperkitty/templates/threads/right_col.html15
-rw-r--r--hyperkitty/views/thread.py45
4 files changed, 61 insertions, 59 deletions
diff --git a/hyperkitty/static/js/hyperkitty.js b/hyperkitty/static/js/hyperkitty.js
index 62bacf4..ee30c74 100644
--- a/hyperkitty/static/js/hyperkitty.js
+++ b/hyperkitty/static/js/hyperkitty.js
@@ -355,25 +355,33 @@ function activity_graph(elem_id, dates, counts, baseurl) {
* Thread replies list
*/
function update_thread_replies(url) {
- $.ajax({
- dataType: "json",
- url: url,
- success: function(data) {
- // replies
- var newcontent = $(data.replies_html);
- $(".replies").html(newcontent);
- // re-bind events
- setup_emails_list(newcontent);
- fold_quotes(newcontent);
- setup_disabled_tooltips(newcontent);
- setup_vote(newcontent);
- // participants list
- $("#participants").html(data.participants_html);
- },
- error: function(jqXHR, textStatus, errorThrown) {
- alert(jqXHR.responseText);
- }
- });
+ function load_more(current_url) {
+ $.ajax({
+ dataType: "json",
+ url: current_url,
+ success: function(data) {
+ // replies
+ var newcontent = $(data.replies_html);
+ $(".replies").append(newcontent)
+ .append($(".replies .ajaxloader"));
+ // re-bind events
+ setup_emails_list(newcontent);
+ fold_quotes(newcontent);
+ setup_disabled_tooltips(newcontent);
+ setup_vote(newcontent);
+ // load the rest if applicable
+ if (data.more_pending) {
+ load_more(url+"&offset="+data.next_offset);
+ } else {
+ $(".replies .ajaxloader").remove();
+ }
+ },
+ error: function(jqXHR, textStatus, errorThrown) {
+ alert(jqXHR.responseText);
+ }
+ });
+ }
+ load_more(url);
}
diff --git a/hyperkitty/templates/threads/participants.html b/hyperkitty/templates/threads/participants.html
deleted file mode 100644
index b40445b..0000000
--- a/hyperkitty/templates/threads/participants.html
+++ /dev/null
@@ -1,14 +0,0 @@
-{% load url from future %}
-{% load gravatar %}
-{% load hk_generic %}
-
- <span id="participants_title">participants</span> ({{participants|length}})
- <ul>
- {% for name, email in participants.items|sort %}
- <li>
- {% gravatar email 20 %}
- {{ name|escapeemail }}
- </li>
- {% endfor %}
- </ul>
-
diff --git a/hyperkitty/templates/threads/right_col.html b/hyperkitty/templates/threads/right_col.html
index 8744f66..7f200fc 100644
--- a/hyperkitty/templates/threads/right_col.html
+++ b/hyperkitty/templates/threads/right_col.html
@@ -44,12 +44,15 @@
</form>
</div>
<div id="participants">
- {% if is_bot %}
- {% include 'threads/participants.html' %}
- {% else %}
- <span id="participants_title">participants</span>
- <img alt="Loading..." class="ajaxloader" src="{{ STATIC_URL }}img/ajax-loader.gif" />
- {% endif %}
+ <span id="participants_title">participants</span> ({{participants|length}})
+ <ul>
+ {% for name, email in participants %}
+ <li>
+ {% gravatar email 20 %}
+ {{ name|escapeemail }}
+ </li>
+ {% endfor %}
+ </ul>
</div>
</section>
diff --git a/hyperkitty/views/thread.py b/hyperkitty/views/thread.py
index be92be7..87cd0ee 100644
--- a/hyperkitty/views/thread.py
+++ b/hyperkitty/views/thread.py
@@ -39,8 +39,11 @@ from hyperkitty.lib import get_months, get_store, stripped_subject
from hyperkitty.lib.voting import set_message_votes
-def _get_thread_replies(request, thread):
- '''Get and sort the replies for a thread'''
+def _get_thread_replies(request, thread, offset=1, limit=None):
+ '''
+ Get and sort the replies for a thread.
+ By default, offset = 1 to skip the original message.
+ '''
if not thread:
raise Http404
@@ -51,23 +54,22 @@ def _get_thread_replies(request, thread):
sort_mode = "thread"
emails = thread.emails_by_reply
- # Don't forget to add the sender to the participants
- participants = {thread.starting_email.sender_name:
- thread.starting_email.sender_email}
- emails = list(emails)[1:] # only select replies
+ # XXX: Storm-specific
+ emails = emails.find()
+ emails.config(offset=offset)
+ if limit is not None:
+ emails.config(limit=limit)
+
+ emails = list(emails)
for email in emails:
# Extract all the votes for this message
set_message_votes(email, request.user)
-
- # Statistics on how many participants and messages this month
- participants[email.sender_name] = email.sender_email
-
if sort_mode == "thread":
email.level = email.thread_depth - 1 # replies start ragged left
if email.level > 5:
email.level = 5
- return {"replies": emails, "participants": participants}
+ return emails
def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
@@ -134,38 +136,41 @@ def thread_index(request, mlist_fqdn, threadid, month=None, year=None):
'fav_action': fav_action,
'reply_form': ReplyForm(),
'is_bot': is_bot,
+ 'participants': thread.participants,
}
+ context["participants"].sort(key=lambda x: x[0].lower())
if is_bot:
# Don't rely on AJAX to load the replies
- thread_replies = _get_thread_replies(request, thread)
- context["participants"] = thread_replies["participants"]
- context["replies"] = thread_replies["replies"]
+ context["replies"] = _get_thread_replies(request, thread)
return render(request, "thread.html", context)
def replies(request, mlist_fqdn, threadid):
"""Get JSON encoded lists with the replies and the participants"""
+ chunk_size = 5
+ offset = int(request.GET.get("offset", "1"))
store = get_store(request)
thread = store.get_thread(mlist_fqdn, threadid)
- thread_replies = _get_thread_replies(request, thread)
mlist = store.get_list(mlist_fqdn)
context = {
'mlist': mlist,
'threadid': threadid,
'reply_form': ReplyForm(),
}
- context["participants"] = thread_replies["participants"]
- context["replies"] = thread_replies["replies"]
+ context["replies"] = _get_thread_replies(request, thread, offset=offset,
+ limit=chunk_size)
replies_tpl = loader.get_template('threads/replies.html')
replies_html = replies_tpl.render(RequestContext(request, context))
- participants_tpl = loader.get_template('threads/participants.html')
- participants_html = participants_tpl.render(RequestContext(request, context))
response = {"replies_html": replies_html,
- "participants_html": participants_html,
+ "more_pending": False,
+ "next_offset": None,
}
+ if len(context["replies"]) == chunk_size:
+ response["more_pending"] = True
+ response["next_offset"] = offset + chunk_size
return HttpResponse(json.dumps(response),
mimetype='application/javascript')