Skip to content

Commit 9760cd9

Browse files
committed
Summary: Load the groups in the group menu with AJAX and delete the
jump to group modal. This cuts page rendering speed in more than half for simple pages and similarly shrinks them by a factor 3-4, while keeping the user experience the same. Fallbacks are in place for non-JS clients. There's still some overhead in the menu generation compared to just rendering the page content, but the group menu was definitely a major culprit. - Legacy-Id: 9077
1 parent a92752b commit 9760cd9

File tree

8 files changed

+98
-69
lines changed

8 files changed

+98
-69
lines changed

ietf/doc/templatetags/wg_menu.py

Lines changed: 13 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3232

3333
from django import template
34-
from django.core.cache import cache
3534
from django.template.loader import render_to_string
35+
from django.db import models
3636

3737
from ietf.group.models import Group
3838

@@ -44,27 +44,18 @@
4444
}
4545

4646
@register.simple_tag
47-
def wg_menu(flavor=""):
48-
res = cache.get('wgmenu' + flavor)
49-
if res:
50-
return res
47+
def wg_menu():
48+
parents = Group.objects.filter(models.Q(type="area") | models.Q(type="irtf", acronym="irtf"),
49+
state="active").order_by('type_id', 'acronym')
5150

52-
areas = Group.objects.filter(type="area", state="active").order_by('acronym')
53-
wgs = Group.objects.filter(type="wg", state="active", parent__in=areas).order_by("acronym")
54-
rgs = Group.objects.filter(type="rg", state="active").order_by("acronym")
51+
for p in parents:
52+
p.short_name = area_short_names.get(p.acronym) or p.name
53+
if p.short_name.endswith(" Area"):
54+
p.short_name = p.short_name[:-len(" Area")]
5555

56-
for a in areas:
57-
a.short_area_name = area_short_names.get(a.acronym) or a.name
58-
if a.short_area_name.endswith(" Area"):
59-
a.short_area_name = a.short_area_name[:-len(" Area")]
56+
if p.type_id == "area":
57+
p.menu_url = "/wg/#" + p.acronym
58+
elif p.acronym == "irtf":
59+
p.menu_url = "/rg/"
6060

61-
a.active_groups = [g for g in wgs if g.parent_id == a.id]
62-
63-
areas = [a for a in areas if a.active_groups]
64-
65-
if flavor == "modal":
66-
res = render_to_string('base/menu_wg_modal.html', {'areas':areas, 'rgs':rgs})
67-
else:
68-
res = render_to_string('base/menu_wg.html', {'areas':areas, 'rgs':rgs})
69-
cache.set('wgmenu' + flavor, res, 30*60)
70-
return res
61+
return render_to_string('base/menu_wg.html', { 'parents': parents })

ietf/group/ajax.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
import json
2+
from collections import defaultdict
23

3-
from django.http import HttpResponse
4+
from django.http import HttpResponse, JsonResponse
45
from django.shortcuts import get_object_or_404
6+
from django.core.urlresolvers import reverse as urlreverse
7+
from django.utils.html import escape
8+
from django.views.decorators.cache import cache_page, cache_control
59

610
from ietf.group.models import Group
711

@@ -12,3 +16,14 @@ def group_json(request, acronym):
1216
sort_keys=True, indent=2),
1317
content_type="text/json")
1418

19+
@cache_control(public=True)
20+
@cache_page(30 * 60)
21+
def group_menu_data(request):
22+
groups = Group.objects.filter(state="active", type__in=("wg", "rg"), parent__state="active").order_by("acronym")
23+
24+
groups_by_parent = defaultdict(list)
25+
for g in groups:
26+
url = urlreverse("ietf.group.info.group_home", kwargs={ 'group_type': g.type_id, 'acronym': g.acronym })
27+
groups_by_parent[g.parent_id].append({ 'acronym': g.acronym, 'name': escape(g.name), 'url': url })
28+
29+
return JsonResponse(groups_by_parent)

ietf/group/tests_info.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import shutil
33
import calendar
44
import datetime
5+
import json
56

67
from pyquery import PyQuery
78
import debug # pyflakes:ignore
@@ -934,3 +935,26 @@ def test_customize_workflow(self):
934935
self.assertEqual(len(q('form').find('input[name=tag][value="%s"]' % tag.pk).parents("form").find("input[name=active]")), 1)
935936
group = Group.objects.get(acronym=group.acronym)
936937
self.assertTrue(tag in group.unused_tags.all())
938+
939+
class AjaxTests(TestCase):
940+
def test_group_menu_data(self):
941+
make_test_data()
942+
943+
r = self.client.get(urlreverse("group_menu_data"))
944+
self.assertEqual(r.status_code, 200)
945+
946+
parents = json.loads(r.content)
947+
948+
area = Group.objects.get(type="area", acronym="farfut")
949+
self.assertTrue(str(area.id) in parents)
950+
951+
mars_wg_data = None
952+
for g in parents[str(area.id)]:
953+
if g["acronym"] == "mars":
954+
mars_wg_data = g
955+
break
956+
self.assertTrue(mars_wg_data)
957+
958+
mars_wg = Group.objects.get(acronym="mars")
959+
self.assertEqual(mars_wg_data["name"], mars_wg.name)
960+

ietf/group/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from django.conf.urls import patterns
44

55
urlpatterns = patterns('',
6+
(r'^groupmenu.json', 'ietf.group.ajax.group_menu_data', None, "group_menu_data"),
67
(r'^(?P<acronym>[a-z0-9]+).json$', 'ietf.group.ajax.group_json'),
78
(r'^chartering/$', 'ietf.group.info.chartering_groups'),
89
(r'^chartering/create/(?P<group_type>(wg|rg))/$', 'ietf.group.edit.edit', {'action': "charter"}, "group_create"),

ietf/templates/base/menu.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070
{% if flavor == "top" %}<li class="divider visible-lg-block"></li>{% endif %}
7171
<li {%if flavor == "top" %}class="dropdown-header visible-lg-block"{% else %}class="nav-header hidden-nojs"{% endif %}>By area/parent</li>
7272
{% wg_menu %}
73-
<li class="hidden-lg hidden-nojs"><a href="#" data-toggle="modal" data-target="#navmodal">Jump to group</a></li>
73+
{# <li class="hidden-lg hidden-nojs"><a href="#" data-toggle="modal" data-target="#navmodal">Jump to group</a></li> #}
7474

7575
{% if flavor == "top" %}<li class="divider hidden-xs"></li>{% endif %}
7676
<li {%if flavor == "top" %}class="dropdown-header hidden-xs"{% else %}class="nav-header"{% endif %}>New work</li>

ietf/templates/base/menu_wg.html

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,5 @@
1-
{% for area in areas %}
2-
<li class="hidden-nojs dropdown-submenu visible-lg-block">
3-
<a href="/wg/#{{ area.acronym }}">{{ area.short_area_name }}</a>
4-
<ul class="dropdown-menu" role="menu">
5-
{% for g in area.active_groups %}
6-
<li><a href="{% url "ietf.group.info.group_home" group_type=g.type_id acronym=g.acronym %}">{{ g.acronym }} &mdash; {{ g.name}}</a></li>
7-
{% endfor %}
8-
</ul>
9-
</li>
1+
{% for p in parents %}
2+
<li class="hidden-nojs dropdown-submenu visible-lg-block group-menu group-parent-{{ p.id }}">
3+
<a href="{{ p.menu_url }}">{{ p.short_name }}</a>
4+
</li>
105
{% endfor %}
11-
12-
<li class="hidden-nojs dropdown-submenu visible-lg-block">
13-
<a href="">IRTF</a>
14-
<ul class="dropdown-menu" role="menu">
15-
{% for group in rgs %}
16-
<li><a href="{% url "ietf.group.info.group_home" group_type=group.type_id acronym=group.acronym %}">{{ group.acronym }} &mdash; {{ group.name}}</a></li>
17-
{% endfor %}
18-
</ul>
19-
</li>

ietf/templates/ietf.html

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -24,33 +24,9 @@
2424
<link rel="apple-touch-icon-precomposed" href="/images/ietficon.png">
2525
</head>
2626

27-
<body {% block bodyAttrs %}{%endblock%}>
27+
<body {% block bodyAttrs %}{%endblock%} data-group-menu-data-url="{% url "group_menu_data" %}">
2828
{% filter amp|smartypants %}
29-
<div class="modal fade" id="navmodal" tabindex="-1" role="dialog" {#aria-labelledby="navmodallabel"#} aria-hidden="true">
30-
<div class="modal-dialog">
31-
<div class="modal-content">
32-
{% comment %}
33-
<div class="modal-header">
34-
<button type="button" class="close" data-dismiss="modal">
35-
<span aria-hidden="true">&times;</span>
36-
<span class="sr-only">Close</span>
37-
</button>
38-
<h4 class="modal-title" id="navmodallabel">Area &amp; WG navigation</h4>
39-
</div>
40-
{% endcomment %}
41-
<div class="modal-body">
42-
{% wg_menu "modal" %}
43-
</div>
44-
{% comment %}
45-
<div class="modal-footer">
46-
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
47-
</div>
48-
{% endcomment %}
49-
</div>
50-
</div>
51-
</div>
52-
53-
<nav class="navbar {% if server_mode and server_mode != "production" %}navbar-dev{% else %}navbar-default{% endif %} navbar-fixed-top" role="navigation">
29+
<nav class="navbar {% if server_mode and server_mode != "production" %}navbar-dev{% else %}navbar-default{% endif %} navbar-fixed-top" role="navigation">
5430
<div class="container-fluid">
5531
<div class="navbar-header">
5632
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse">
@@ -178,7 +154,6 @@ <h4 class="modal-title" id="navmodallabel">Area &amp; WG navigation</h4>
178154
</script>
179155

180156
{% endfilter %}
181-
{% include "debug.html" %}
182157
</body>
183158
</html>
184159

static/js/ietf.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,3 +201,40 @@ $(document).ready(function () {
201201
// explicit requirement asterisks
202202
$("form.show-required").find("input[required],select[required],textarea[required]").closest(".form-group").find("label").addClass("required");
203203
});
204+
205+
206+
$(document).ready(function () {
207+
// load data for the menu
208+
$.ajax({
209+
url: $(document.body).data("group-menu-data-url"),
210+
type: 'GET',
211+
dataType: "json",
212+
success: function (data) {
213+
for (var parentId in data) {
214+
var attachTo = $(".group-menu.group-parent-" + parentId);
215+
if (attachTo.length == 0)
216+
continue;
217+
218+
attachTo.find(".dropdown-menu").remove();
219+
220+
var menu = ['<ul class="dropdown-menu" role="menu">'];
221+
222+
var groups = data[parentId];
223+
for (var i = 0; i < groups.length; ++i) {
224+
var g = groups[i];
225+
menu.push('<li><a href="' + g.url + '">' + g.acronym +' &mdash; ' + g.name + '</a></li>');
226+
}
227+
228+
menu.push('</ul>');
229+
230+
attachTo.append(menu.join(""));
231+
}
232+
},
233+
error: function (err) {
234+
$(".group-menu").removeClass("dropdown-submenu");
235+
236+
if (console.log)
237+
console.log("Could not load menu data");
238+
}
239+
});
240+
});

0 commit comments

Comments
 (0)