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
This commit is contained in:
parent
a92752bbcf
commit
9760cd9c8e
|
@ -31,8 +31,8 @@
|
|||
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
from django import template
|
||||
from django.core.cache import cache
|
||||
from django.template.loader import render_to_string
|
||||
from django.db import models
|
||||
|
||||
from ietf.group.models import Group
|
||||
|
||||
|
@ -44,27 +44,18 @@ area_short_names = {
|
|||
}
|
||||
|
||||
@register.simple_tag
|
||||
def wg_menu(flavor=""):
|
||||
res = cache.get('wgmenu' + flavor)
|
||||
if res:
|
||||
return res
|
||||
def wg_menu():
|
||||
parents = Group.objects.filter(models.Q(type="area") | models.Q(type="irtf", acronym="irtf"),
|
||||
state="active").order_by('type_id', 'acronym')
|
||||
|
||||
areas = Group.objects.filter(type="area", state="active").order_by('acronym')
|
||||
wgs = Group.objects.filter(type="wg", state="active", parent__in=areas).order_by("acronym")
|
||||
rgs = Group.objects.filter(type="rg", state="active").order_by("acronym")
|
||||
for p in parents:
|
||||
p.short_name = area_short_names.get(p.acronym) or p.name
|
||||
if p.short_name.endswith(" Area"):
|
||||
p.short_name = p.short_name[:-len(" Area")]
|
||||
|
||||
for a in areas:
|
||||
a.short_area_name = area_short_names.get(a.acronym) or a.name
|
||||
if a.short_area_name.endswith(" Area"):
|
||||
a.short_area_name = a.short_area_name[:-len(" Area")]
|
||||
if p.type_id == "area":
|
||||
p.menu_url = "/wg/#" + p.acronym
|
||||
elif p.acronym == "irtf":
|
||||
p.menu_url = "/rg/"
|
||||
|
||||
a.active_groups = [g for g in wgs if g.parent_id == a.id]
|
||||
|
||||
areas = [a for a in areas if a.active_groups]
|
||||
|
||||
if flavor == "modal":
|
||||
res = render_to_string('base/menu_wg_modal.html', {'areas':areas, 'rgs':rgs})
|
||||
else:
|
||||
res = render_to_string('base/menu_wg.html', {'areas':areas, 'rgs':rgs})
|
||||
cache.set('wgmenu' + flavor, res, 30*60)
|
||||
return res
|
||||
return render_to_string('base/menu_wg.html', { 'parents': parents })
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import json
|
||||
from collections import defaultdict
|
||||
|
||||
from django.http import HttpResponse
|
||||
from django.http import HttpResponse, JsonResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.core.urlresolvers import reverse as urlreverse
|
||||
from django.utils.html import escape
|
||||
from django.views.decorators.cache import cache_page, cache_control
|
||||
|
||||
from ietf.group.models import Group
|
||||
|
||||
|
@ -12,3 +16,14 @@ def group_json(request, acronym):
|
|||
sort_keys=True, indent=2),
|
||||
content_type="text/json")
|
||||
|
||||
@cache_control(public=True)
|
||||
@cache_page(30 * 60)
|
||||
def group_menu_data(request):
|
||||
groups = Group.objects.filter(state="active", type__in=("wg", "rg"), parent__state="active").order_by("acronym")
|
||||
|
||||
groups_by_parent = defaultdict(list)
|
||||
for g in groups:
|
||||
url = urlreverse("ietf.group.info.group_home", kwargs={ 'group_type': g.type_id, 'acronym': g.acronym })
|
||||
groups_by_parent[g.parent_id].append({ 'acronym': g.acronym, 'name': escape(g.name), 'url': url })
|
||||
|
||||
return JsonResponse(groups_by_parent)
|
||||
|
|
|
@ -2,6 +2,7 @@ import os
|
|||
import shutil
|
||||
import calendar
|
||||
import datetime
|
||||
import json
|
||||
|
||||
from pyquery import PyQuery
|
||||
import debug # pyflakes:ignore
|
||||
|
@ -934,3 +935,26 @@ class CustomizeWorkflowTests(TestCase):
|
|||
self.assertEqual(len(q('form').find('input[name=tag][value="%s"]' % tag.pk).parents("form").find("input[name=active]")), 1)
|
||||
group = Group.objects.get(acronym=group.acronym)
|
||||
self.assertTrue(tag in group.unused_tags.all())
|
||||
|
||||
class AjaxTests(TestCase):
|
||||
def test_group_menu_data(self):
|
||||
make_test_data()
|
||||
|
||||
r = self.client.get(urlreverse("group_menu_data"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
|
||||
parents = json.loads(r.content)
|
||||
|
||||
area = Group.objects.get(type="area", acronym="farfut")
|
||||
self.assertTrue(str(area.id) in parents)
|
||||
|
||||
mars_wg_data = None
|
||||
for g in parents[str(area.id)]:
|
||||
if g["acronym"] == "mars":
|
||||
mars_wg_data = g
|
||||
break
|
||||
self.assertTrue(mars_wg_data)
|
||||
|
||||
mars_wg = Group.objects.get(acronym="mars")
|
||||
self.assertEqual(mars_wg_data["name"], mars_wg.name)
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
from django.conf.urls import patterns
|
||||
|
||||
urlpatterns = patterns('',
|
||||
(r'^groupmenu.json', 'ietf.group.ajax.group_menu_data', None, "group_menu_data"),
|
||||
(r'^(?P<acronym>[a-z0-9]+).json$', 'ietf.group.ajax.group_json'),
|
||||
(r'^chartering/$', 'ietf.group.info.chartering_groups'),
|
||||
(r'^chartering/create/(?P<group_type>(wg|rg))/$', 'ietf.group.edit.edit', {'action': "charter"}, "group_create"),
|
||||
|
|
|
@ -70,7 +70,7 @@
|
|||
{% if flavor == "top" %}<li class="divider visible-lg-block"></li>{% endif %}
|
||||
<li {%if flavor == "top" %}class="dropdown-header visible-lg-block"{% else %}class="nav-header hidden-nojs"{% endif %}>By area/parent</li>
|
||||
{% wg_menu %}
|
||||
<li class="hidden-lg hidden-nojs"><a href="#" data-toggle="modal" data-target="#navmodal">Jump to group</a></li>
|
||||
{# <li class="hidden-lg hidden-nojs"><a href="#" data-toggle="modal" data-target="#navmodal">Jump to group</a></li> #}
|
||||
|
||||
{% if flavor == "top" %}<li class="divider hidden-xs"></li>{% endif %}
|
||||
<li {%if flavor == "top" %}class="dropdown-header hidden-xs"{% else %}class="nav-header"{% endif %}>New work</li>
|
||||
|
|
|
@ -1,19 +1,5 @@
|
|||
{% for area in areas %}
|
||||
<li class="hidden-nojs dropdown-submenu visible-lg-block">
|
||||
<a href="/wg/#{{ area.acronym }}">{{ area.short_area_name }}</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
{% for g in area.active_groups %}
|
||||
<li><a href="{% url "ietf.group.info.group_home" group_type=g.type_id acronym=g.acronym %}">{{ g.acronym }} — {{ g.name}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% for p in parents %}
|
||||
<li class="hidden-nojs dropdown-submenu visible-lg-block group-menu group-parent-{{ p.id }}">
|
||||
<a href="{{ p.menu_url }}">{{ p.short_name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
|
||||
<li class="hidden-nojs dropdown-submenu visible-lg-block">
|
||||
<a href="">IRTF</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
{% for group in rgs %}
|
||||
<li><a href="{% url "ietf.group.info.group_home" group_type=group.type_id acronym=group.acronym %}">{{ group.acronym }} — {{ group.name}}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
|
|
|
@ -24,33 +24,9 @@
|
|||
<link rel="apple-touch-icon-precomposed" href="/images/ietficon.png">
|
||||
</head>
|
||||
|
||||
<body {% block bodyAttrs %}{%endblock%}>
|
||||
<body {% block bodyAttrs %}{%endblock%} data-group-menu-data-url="{% url "group_menu_data" %}">
|
||||
{% filter amp|smartypants %}
|
||||
<div class="modal fade" id="navmodal" tabindex="-1" role="dialog" {#aria-labelledby="navmodallabel"#} aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
{% comment %}
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">
|
||||
<span aria-hidden="true">×</span>
|
||||
<span class="sr-only">Close</span>
|
||||
</button>
|
||||
<h4 class="modal-title" id="navmodallabel">Area & WG navigation</h4>
|
||||
</div>
|
||||
{% endcomment %}
|
||||
<div class="modal-body">
|
||||
{% wg_menu "modal" %}
|
||||
</div>
|
||||
{% comment %}
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
{% endcomment %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<nav class="navbar {% if server_mode and server_mode != "production" %}navbar-dev{% else %}navbar-default{% endif %} navbar-fixed-top" role="navigation">
|
||||
<nav class="navbar {% if server_mode and server_mode != "production" %}navbar-dev{% else %}navbar-default{% endif %} navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#navbar-collapse">
|
||||
|
@ -178,7 +154,6 @@
|
|||
</script>
|
||||
|
||||
{% endfilter %}
|
||||
{% include "debug.html" %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
|
|
|
@ -201,3 +201,40 @@ $(document).ready(function () {
|
|||
// explicit requirement asterisks
|
||||
$("form.show-required").find("input[required],select[required],textarea[required]").closest(".form-group").find("label").addClass("required");
|
||||
});
|
||||
|
||||
|
||||
$(document).ready(function () {
|
||||
// load data for the menu
|
||||
$.ajax({
|
||||
url: $(document.body).data("group-menu-data-url"),
|
||||
type: 'GET',
|
||||
dataType: "json",
|
||||
success: function (data) {
|
||||
for (var parentId in data) {
|
||||
var attachTo = $(".group-menu.group-parent-" + parentId);
|
||||
if (attachTo.length == 0)
|
||||
continue;
|
||||
|
||||
attachTo.find(".dropdown-menu").remove();
|
||||
|
||||
var menu = ['<ul class="dropdown-menu" role="menu">'];
|
||||
|
||||
var groups = data[parentId];
|
||||
for (var i = 0; i < groups.length; ++i) {
|
||||
var g = groups[i];
|
||||
menu.push('<li><a href="' + g.url + '">' + g.acronym +' — ' + g.name + '</a></li>');
|
||||
}
|
||||
|
||||
menu.push('</ul>');
|
||||
|
||||
attachTo.append(menu.join(""));
|
||||
}
|
||||
},
|
||||
error: function (err) {
|
||||
$(".group-menu").removeClass("dropdown-submenu");
|
||||
|
||||
if (console.log)
|
||||
console.log("Could not load menu data");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue