Merged in [9651] from rjsparks@nostrum.com:

Adds a graphical overview of each day by room for the secretariat to assist with scheduling additional meetings.
 - Legacy-Id: 9674
Note: SVN reference [9651] has been migrated to Git commit 06a0e2b6481fe909f6620ed951353eaf437321ec
This commit is contained in:
Henrik Levkowetz 2015-06-22 19:33:15 +00:00
parent f70b2d93c5
commit b49a452595
4 changed files with 664 additions and 2 deletions

View file

@ -149,6 +149,13 @@ class MeetingTests(TestCase):
self.assertFalse(any([x in r.content for x in ['mars','Test Room']])) self.assertFalse(any([x in r.content for x in ['mars','Test Room']]))
self.assertTrue(all([x in r.content for x in ['IESG Breakfast','Breakfast Room']])) self.assertTrue(all([x in r.content for x in ['IESG Breakfast','Breakfast Room']]))
def test_agenda_room_view(self):
meeting = make_meeting_test_data()
url = urlreverse("ietf.meeting.views.room_view",kwargs=dict(num=meeting.number))
login_testing_unauthorized(self,"secretary",url)
r = self.client.get(url)
self.assertTrue(all([x in r.content for x in ['mars','IESG Breakfast','Test Room','Breakfast Room']]))
def test_session_details(self): def test_session_details(self):
meeting = make_meeting_test_data() meeting = make_meeting_test_data()
url = urlreverse("ietf.meeting.views.session_details", kwargs=dict(num=meeting.number, acronym="mars")) url = urlreverse("ietf.meeting.views.session_details", kwargs=dict(num=meeting.number, acronym="mars"))

View file

@ -18,7 +18,9 @@ urlpatterns = patterns('',
(r'^agenda/agenda.ics$', views.ical_agenda), (r'^agenda/agenda.ics$', views.ical_agenda),
(r'^agenda.ics$', views.ical_agenda), (r'^agenda.ics$', views.ical_agenda),
(r'^agenda/week-view.html$', views.week_view), (r'^agenda/week-view.html$', views.week_view),
(r'^agenda/room-view.html$', views.room_view),
(r'^week-view.html$', views.week_view), (r'^week-view.html$', views.week_view),
(r'^room-view.html$', views.room_view),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/edit$', views.edit_agenda), (r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/edit$', views.edit_agenda),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/details$', views.edit_agenda_properties), (r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+)/details$', views.edit_agenda_properties),
(r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+).(?P<ext>.html)?/?$', views.agenda), (r'^(?P<num>\d+)/agenda/(?P<owner>[A-Za-z0-9-.+_]+@[A-Za-z0-9._]+)/(?P<name>[A-Za-z0-9-:_]+).(?P<ext>.html)?/?$', views.agenda),
@ -48,7 +50,9 @@ urlpatterns = patterns('',
(r'^(?P<num>\d+)/agendas$', ajax.agenda_infosurl), (r'^(?P<num>\d+)/agendas$', ajax.agenda_infosurl),
(r'^(?P<num>\d+)/agendas.json$', ajax.agenda_infosurl), (r'^(?P<num>\d+)/agendas.json$', ajax.agenda_infosurl),
(r'^(?P<num>\d+)/week-view.html$', views.week_view), (r'^(?P<num>\d+)/week-view.html$', views.week_view),
(r'^(?P<num>\d+)/room-view.html$', views.room_view),
(r'^(?P<num>\d+)/agenda/week-view.html$', views.week_view), (r'^(?P<num>\d+)/agenda/week-view.html$', views.week_view),
(r'^(?P<num>\d+)/agenda/room-view.html$', views.room_view),
(r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)-drafts.pdf$', views.session_draft_pdf), (r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)-drafts.pdf$', views.session_draft_pdf),
(r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)-drafts.tgz$', views.session_draft_tarfile), (r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)-drafts.tgz$', views.session_draft_tarfile),
(r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)/?$', views.session_agenda), (r'^(?P<num>\d+)/agenda/(?P<session>[A-Za-z0-9-]+)/?$', views.session_agenda),

View file

@ -15,11 +15,10 @@ from django.shortcuts import render, render_to_response, redirect
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404 from django.http import HttpResponse, HttpResponseRedirect, HttpResponseForbidden, Http404
from django.contrib import messages from django.contrib import messages
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.db.models import Q from django.db.models import Q, Min, Max
from django.template import RequestContext from django.template import RequestContext
from django.template.loader import render_to_string from django.template.loader import render_to_string
from django.conf import settings from django.conf import settings
from django.db.models import Max
from django.forms.models import modelform_factory from django.forms.models import modelform_factory
from django.views.decorators.csrf import ensure_csrf_cookie from django.views.decorators.csrf import ensure_csrf_cookie
from django.forms import ModelForm from django.forms import ModelForm
@ -612,6 +611,59 @@ def week_view(request, num=None):
return render_to_response(template, return render_to_response(template,
{"timeslots":timeslots,"render_types":["Session","Other","Break","Plenary"]}, context_instance=RequestContext(request)) {"timeslots":timeslots,"render_types":["Session","Other","Break","Plenary"]}, context_instance=RequestContext(request))
@role_required('Secretariat')
def room_view(request, num=None):
meeting = get_meeting(num)
rooms = meeting.room_set.order_by('functional_name','name')
if rooms.count() == 0:
raise Http404
scheduledsessions = meeting.agenda.scheduledsession_set.all()
unavailable = meeting.timeslot_set.filter(type__slug='unavail')
if (unavailable.count() + scheduledsessions.count()) == 0 :
raise Http404
earliest = None
latest = None
if scheduledsessions:
earliest = scheduledsessions.aggregate(Min('timeslot__time'))['timeslot__time__min']
latest = scheduledsessions.aggregate(Max('timeslot__time'))['timeslot__time__max']
if unavailable:
earliest_unavailable = unavailable.aggregate(Min('time'))['time__min']
if not earliest or ( earliest_unavailable and earliest_unavailable < earliest ):
earliest = earliest_unavailable
latest_unavailable = unavailable.aggregate(Max('time'))['time__max']
if not latest or ( latest_unavailable and latest_unavailable > latest ):
latest = latest_unavailable
if not (earliest and latest):
raise Http404
base_time = earliest
base_day = datetime.datetime(base_time.year,base_time.month,base_time.day)
day = base_day
days = []
while day <= latest :
days.append(day)
day += datetime.timedelta(days=1)
unavailable = list(unavailable)
for t in unavailable:
t.delta_from_beginning = (t.time - base_time).total_seconds()
t.day = (t.time-base_day).days
scheduledsessions = list(scheduledsessions)
for ss in scheduledsessions:
ss.delta_from_beginning = (ss.timeslot.time - base_time).total_seconds()
ss.day = (ss.timeslot.time-base_day).days
template = "meeting/room-view.html"
return render(request, template,{"meeting":meeting,"unavailable":unavailable,"scheduledsessions":scheduledsessions,"rooms":rooms,"days":days})
def ical_agenda(request, num=None, name=None, ext=None): def ical_agenda(request, num=None, name=None, ext=None):
meeting = get_meeting(num) meeting = get_meeting(num)
schedule = get_schedule(meeting, name) schedule = get_schedule(meeting, name)

View file

@ -0,0 +1,599 @@
{# Copyright The IETF Trust 2015, All Rights Reserved #}
{% load origin %}{% origin %}
<html> <head>
<link rel="stylesheet" href="/css/bootstrap.min.css"> {% comment %} This sets box-sizing: border-box {% endcomment %}
<link rel="stylesheet" href="/css/bootstrap-theme.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script src="/js/lib/bootstrap.min.js"></script>
<script type="text/javascript">
var room_names = [{% for room in rooms %}"{{room.name}}"{% if not forloop.last %},{% endif %}{% endfor %}];
var room_functional_names = [{% for room in rooms %}"{{room.functional_name}}"{% if not forloop.last %},{% endif %}{% endfor %}];
var room_typelabels = [{% for room in rooms %}"{% for type in room.session_types.all %}{{type.name}}{% if not forloop.last %}, {% endif %}{% endfor %}"{% if not forloop.last %},{% endif %}{% endfor %}];
var items = new Array();
{% autoescape off %}
{% for slot in unavailable %}
if (room_names.indexOf("{{slot.get_hidden_location}}") >= 0 )
{
items.push({room_index:room_names.indexOf("{{slot.get_hidden_location}}"),day:{{slot.day}}, delta_from_beginning:{{slot.delta_from_beginning}},time:"{{slot.time|date:"Hi"}}-{{slot.end_time|date:"Hi"}}", verbose_time:"{{slot.time|date:"D M d Hi"}}-{{slot.end_time|date:"Hi"}}",duration:{{slot.duration.total_seconds}}, type:"{{slot.type}}", name:"Unavailable", dayname:"{{ slot.time|date:"l"|upper }}, {{ slot.time|date:"F j, Y" }}" });
}
{% endfor %}
{% for ss in scheduledsessions %}
if (room_names.indexOf("{{ss.timeslot.get_hidden_location}}") >= 0 )
{
items.push({room_index:room_names.indexOf("{{ss.timeslot.get_hidden_location}}"),day:{{ss.day}}, delta_from_beginning:{{ss.delta_from_beginning}},time:"{{ss.timeslot.time|date:"Hi"}}-{{ss.timeslot.end_time|date:"Hi"}}", verbose_time:"{{ss.timeslot.time|date:"D M d Hi"}}-{{ss.timeslot.end_time|date:"Hi"}}",duration:{{ss.timeslot.duration.total_seconds}}, type:"{{ss.timeslot.type}}", {% if ss.session.name %}name:"{{ss.session.name|escapejs}}",{% if ss.session.group.acronym %} wg:"{{ss.session.group.acronym}}",{%endif%}{% else %}{% if ss.timeslot.type.name == "Break" %}name:"{{ss.timeslot.name|escapejs}}", area:"break", wg:"break",{% elif ss.timeslot.type.slug == "unavail" %}name:"Unavailable",{% else %}name:"{{ss.session.group.name|escapejs}}{%if ss.session.group.state.name = "BOF"%} BOF{%endif%}",wg:"{{ss.session.group.acronym}}",state:"{{ss.session.group.state}}",area:"{{ss.session.group.parent.acronym}}",{% endif %}{% endif %} dayname:"{{ ss.timeslot.time|date:"l"|upper }}, {{ ss.timeslot.time|date:"F j, Y" }}"{% if ss.session.agenda %}, agenda:"{{ss.session.agenda.get_absolute_url}}"{% endif %} });
}
{% endfor %}
{% endautoescape %}
var start_map = items.map(function(el,i) {
return { room_index:el.room_index, start_time:el.delta_from_beginning, index:i};
});
start_map.sort(function(a,b) {
if ( a.room_index != b.room_index) {
return (a.room_index - b.room_index);
}
return a.start_time - b.start_time;
});
var end_map = items.map(function(el,i) {
return { room_index:el.room_index, end_time:el.delta_from_beginning+el.duration, index:i};
});
end_map.sort(function(a,b) {
if ( a.room_index != b.room_index) {
return (a.room_index - b.room_index);
}
return a.end_time - b.end_time;
});
var si = 0;
var ei = 0;
var overlap = 0;
var max_lanes = 0;
var next_lane = [];
var start_overlap = si;
while (si < items.length ) {
var start_room_change = false;
while ( !start_room_change && si < items.length && start_map[si].start_time < end_map[ei].end_time )
{
overlap++;
if (next_lane.length>0)
{
items[start_map[si].index].lane = next_lane.shift();
}
else
{
items[start_map[si].index].lane = max_lanes;
max_lanes++;
}
start_room_change = ( si+1 == items.length || start_map[si].room_index != start_map[si+1].room_index );
si++;
}
var end_room_change = false;
while ( ei < items.length && !end_room_change && ( start_room_change || si == items.length || start_map[si].start_time >= end_map[ei].end_time ) )
{
next_lane.push(items[end_map[ei].index].lane);
overlap--;
end_room_change = ( ei+1 == items.length || end_map[ei].room_index != end_map[ei+1].room_index );
ei++;
}
if ( overlap == 0 )
{
for (var i=start_overlap; i<si; i++)
{
items[start_map[i].index].lanes = max_lanes;
}
max_lanes = 0;
next_lane=[];
start_overlap = si;
}
}
var fg = {
'app': "#008",
'gen': "#080",
'int': "#088",
'ops': "#800",
'rai': "#808",
'rtg': "#880",
'sec': "#488",
'tsv': "#484",
'irtf': "#448",
'break': "#000"
};
var bg = {
'app': "#eef",
'gen': "#efe",
'int': "#eff",
'ops': "#fee",
'rai': "#fef",
'rtg': "#ffe",
'sec': "#dff",
'tsv': "#dfd",
'irtf': "#ddf",
'break': "#fff"
};
var divlist = [];
var lastfrag;
var lastheight;
var lastwidth;
var padding = 2;
var border = 1;
setInterval("animate()",50);
function draw_calendar()
{
window.setTimeout("draw_calendar()",1000);
var width = document.body.clientWidth;
var height = document.body.clientHeight;
if (lastheight == height &&
lastwidth == width &&
lastfrag == window.location.hash)
{
return;
}
var i;
var text="";
var start_day = items[0].day;
var end_day = start_day;
var day_start = 23*60+59;
var day_end = 0;
/* Find our boundaries */
for (i = 0; i < items.length; i++)
{
{
var start_time = parseInt(items[i].time.substr(0,2),10) * 60 +
parseInt(items[i].time.substr(2,2),10);
var end_time = start_time + (items[i].duration / 60)
if (start_time < day_start) { day_start = start_time; }
if (end_time > day_end) { day_end = end_time; }
if (items[i].day < start_day) { start_day = items[i].day; }
if (items[i].day > end_day) { end_day = items[i].day; }
}
}
var timelabel_width = width * 0.020;
var header_height = height * 0.05;
var header_offset = $('#daytabs').height();
var num_days = end_day - start_day + 1;
var num_minutes = day_end - day_start;
var minute_height = (height - header_height - header_offset)/num_minutes;
var body = document.body;
var daydiv;
{% for day in days %}
daydiv = document.getElementById("day{{forloop.counter0}}")
while (daydiv.childNodes.length) { daydiv.removeChild(daydiv.childNodes[0]); }
{% endfor %}
var room_width = (width - timelabel_width) {% if rooms.count %}/ {{ rooms.count }}{% endif %};
for (var day=0; day<num_days; day++)
{
for (var ri=0; ri<room_names.length; ri++)
{
var e = document.createElement("div");
e.style.border="solid";
e.style.borderWidth=border;
e.style.background="#2647f0";
e.style.color="#fff";
e.style.borderColor="#000 #fff";
e.style.borderColor="#2647f0 #2647f0 #000 #2647f0";
e.style.display="block";
e.style.overflow="hidden";
e.style.position="absolute";
e.style.top=header_offset;
e.style.left = timelabel_width+ri*room_width;
e.style.width=room_width;
e.style.height=header_height;
e.style.margin=0;
e.style.padding=padding;
e.style.fontFamily="sans-serif";
e.style.fontSize=header_height * 0.25;
e.style.textAlign="center";
var div = document.createElement("div");
div.appendChild(document.createTextNode(room_names[ri]));
if (room_functional_names[ri].length>0)
{
div.appendChild(document.createElement("br"));
div.appendChild(document.createTextNode(room_functional_names[ri]));
}
if (room_typelabels[ri].length>0)
{
div.title=room_names[ri]+"\n"+room_functional_names[ri]+"\n"+room_typelabels[ri];
}
e.appendChild(div);
document.getElementById("day"+day).appendChild(e);
//-----------------------------------------------------------------
// Draw column border
//-----------------------------------------------------------------
e = document.createElement("div");
e.style.border="solid";
e.style.borderWidth=border;
e.style.color="#000";
e.style.borderColor="#fff #000";
e.style.display="block";
e.style.overflow="hidden";
e.style.position="absolute";
e.style.top=header_height+header_offset;
e.style.left=timelabel_width + ri*room_width;
e.style.width=room_width ;
e.style.height=height - header_height - header_offset;
e.style.margin=0;
e.style.padding=padding;
document.getElementById("day"+day).appendChild(e);
}
//-----------------------------------------------------------------
// Draw hour lines
//-----------------------------------------------------------------
for (var time = day_start - (day_start%60) + 60; time < day_end ; time += 60)
{
e = document.createElement("div");
e.style.borderTopStyle="solid";
e.style.boderTopWidth="2px";
e.style.borderColor="#f8f8f8";
e.style.overflow="hidden";
e.style.position="absolute";
e.style.top=header_height + header_offset + (time - day_start) * minute_height;
e.style.left=timelabel_width;
e.style.width=width-timelabel_width;
e.style.height=0;
e.style.zIndex="-1";
e.style.margin=0;
e.style.padding=padding;
document.getElementById("day"+day).appendChild(e);
e = document.createElement("div");
e.style.overflow="hidden";
e.style.position="absolute";
e.style.top=header_height + header_offset - (header_height*0.125) + (time - day_start) * minute_height;
e.style.left=0;
e.style.width=timelabel_width;
e.style.height=header_height * 0.5;
e.style.zIndex="-1";
e.style.margin=0;
e.style.padding=padding;
e.style.fontFamily="sans-serif";
e.style.fontSize=header_height * 0.25;
e.style.textAlign="right";
e.style.color="#e0e0e0";
var label = time/60+"00";
if (label.length < 4 )
{
label = "0"+label;
}
e.appendChild(document.createTextNode(label));
document.getElementById("day"+day).appendChild(e);
}
}
//-----------------------------------------------------------------
// Draw a block for each meeting
//-----------------------------------------------------------------
var resize_func = function(div,t,l,w,h,to_fit)
{ return function(){resize(div,t,l,w,h,to_fit);} }
var maximize_func = function (e) { return function(){maximize(e);}}
for (i = 0; i < items.length; i++)
{
{
var start_time = parseInt(items[i].time.substr(0,2),10) * 60 +
parseInt(items[i].time.substr(2,2),10);
var end_time = start_time + (items[i].duration / 60);
var sess_width = room_width / items[i].lanes;
var sess_height = ((end_time - start_time) * minute_height) ;
var room_left = timelabel_width + items[i].room_index * room_width;
var sess_left = room_left + sess_width * items[i].lane;
var sess_top = ((start_time - day_start) * minute_height) + header_height + header_offset;
sess_width = sess_width;
var e = document.createElement("div");
e.style.border="solid";
e.style.borderWidth=border;
if (fg[items[i].area])
{
e.style.background=bg[items[i].area];
e.style.color=fg[items[i].area];
e.style.borderColor=fg[items[i].area];
}
else
{
e.style.background="#e0e0e0";
e.style.color="#000000";
e.style.borderColor="#000000";
}
e.style.display="block";
e.style.overflow="hidden";
e.style.position="absolute";
e.style.top=sess_top;
e.style.left=sess_left;
e.style.width=sess_width;
e.style.height=sess_height;
e.style.margin=0;
e.style.padding=padding;
e.style.fontFamily="sans-serif";
e.style.fontSize="8pt";
e.id=i;
e.onmouseover=resize_func(e,sess_top,room_left,
room_width,
sess_height, true);
e.onmouseout=resize_func(e,sess_top,sess_left,sess_width,sess_height,false);
if (items[i].agenda)
{
e.onclick=maximize_func(e);
e.style.cursor="pointer";
}
var div = document.createElement("div");
div.appendChild(document.createTextNode(items[i].verbose_time));
div.appendChild(document.createElement("br"));
var label = items[i].name;
if (label.length === 0) { label = "Free Slot"; }
if (items[i].wg && fg[items[i].area])
{
label = label + " (" + items[i].wg + ")";
}
var bold = document.createElement("span");
bold.appendChild(document.createTextNode(label));
bold.style.fontWeight="bold";
div.appendChild(bold);
e.appendChild(div);
document.getElementById("day"+items[i].day).appendChild(e);
}
}
lastheight = height;
lastwidth = width;
lastfrag = window.location.hash;
}
function resize(div,t2,l2,w2,h2,to_fit)
{
// Move the element to the front
var parent = div.parentElement;
parent.removeChild(div);
parent.appendChild(div);
div.t2 = t2;
div.l2 = l2;
div.w2 = w2;
div.h2 = h2;
div.to_fit = to_fit;
div.percent = 0;
divlist.push(div);
}
function animate()
{
var i;
for (i = divlist.length - 1; i >= 0; i--)
{
var div = divlist[i];
if (div.percent < 100)
{
div.percent += 5;
var t1 = parseFloat(div.style.top.replace("px",""));
var l1 = parseFloat(div.style.left.replace("px",""));
var w1 = parseFloat(div.style.width.replace("px",""));
var h1 = parseFloat(div.style.height.replace("px",""));
div.style.top = wavg(t1,div.t2,div.percent);
div.style.left = wavg(l1,div.l2,div.percent);
div.style.width = wavg(w1,div.w2,div.percent);
div.style.height = wavg(h1,div.h2,div.percent);
if (t1 == div.t2 && l1 == div.l2 &&
w1 == div.w2 && h1 == div.h2) { div.percent = 100; }
}
else
{
if (div.to_fit)
{
var tmp = div.style.height;
div.style.removeProperty("height");
if (div.h2 < div.clientHeight)
{
div.h2 = div.clientHeight;
div.percent = 0;
}
else
{
divlist.remove(i);
if (div.callback)
{
var tmp = div.callback;
div.callback = undefined;
tmp();
}
}
div.style.height = tmp;
}
else
{
divlist.remove(i);
if (div.callback)
{
var tmp = div.callback;
div.callback = undefined;
tmp();
}
}
}
}
}
function finish_maximize(e)
{
if (!items[e.id].agenda)
{
return;
}
e.insertBefore(document.createElement("br"),e.firstChild);
var minimize_func = function (e) { return function(){minimize(e);} }
var img = document.createElement("img");
img.src = "/images/agenda-weekview/close.png";
img.style.cssFloat="right";
img.onclick = minimize_func(e);
img.style.cursor="pointer";
e.insertBefore(img,e.firstChild);
var h = document.createElement("span");
h.appendChild(document.createTextNode(items[e.id].dayname));
h.style.fontWeight="bold";
e.insertBefore(h,e.firstChild);
e.style.fontSize="10pt";
var tmp = e.style.height;
e.style.removeProperty("height");
var used_height = e.clientHeight;
e.style.height = tmp;
var frame = document.createElement("iframe");
frame.setAttribute("src",items[e.id].agenda);
frame.style.position = "absolute";
frame.style.left = 8;
frame.style.width = e.clientWidth - 16 ;
frame.style.top = used_height + 8;
frame.style.height = e.clientHeight - used_height - 16 ;
frame.style.background = "#fff";
frame.style.overflow="auto";
frame.id="agenda";
frame.style.border = e.style.border;
frame.style.borderWidth = border;
frame.style.padding = padding;
frame.style.borderColor = e.style.borderColor;
e.appendChild(frame);
}
function finish_minimize(e)
{
e.onmouseover = e.oldmouseover;
e.onmouseout = e.oldmouseout;
e.oldmouseover = undefined;
e.oldmouseout = undefined;
e.style.cursor="pointer";
}
function maximize(e)
{
if (e.onmouseover)
{
e.oldmouseover = e.onmouseover;
e.oldmouseout = e.onmouseout;
e.onmouseover = undefined;
e.onmouseout = undefined;
e.style.cursor="auto";
var callback_func = function (e) { return function(){finish_maximize(e);}}
e.callback = callback_func(e);
resize(e,0,0,
document.body.clientWidth,
document.body.clientHeight);
}
}
function minimize(e)
{
var agenda = document.getElementById("agenda");
if (agenda)
{
e.removeChild(agenda);
}
var callback_func = function (e) { return function(){finish_minimize(e);}}
e.callback = callback_func(e);
e.oldmouseout();
e.removeChild(e.firstChild);
e.removeChild(e.firstChild);
e.removeChild(e.firstChild);
e.style.fontSize="8pt";
}
function wavg(x1,x2,percent)
{
if (percent == 100) { return x2; }
var res = x2 * (percent / 100) + x1 * ((100 - percent) / 100);
return res;
}
// Array Remove - By John Resig (MIT Licensed)
Array.prototype.remove = function(from, to) {
var rest = this.slice((to || from) + 1 || this.length);
this.length = from < 0 ? this.length + from : from;
return this.push.apply(this, rest);
};
</script>
</head>
<body onload="draw_calendar()" onresize="draw_calendar()" id="body">
<div id="daycontainer" role="tabpanel">
<ul id="daytabs" class="nav nav-tabs" role="tablist">
{% for day in days %}
<li {% if forloop.first %}class="active"{% endif %} role="presentation"><a href="#day{{forloop.counter0}}" id="day{{forloop.counter0}}-tab" role="tab" data-toggle="tab" area-controls="day{{forloop.counter0}}">{{day|date:"D M d"}}</a></li>
{% endfor %}
</ul>
<div class="tab-content">
{% for day in days %}
<div role="tab-panel" class="tab-pane{% if forloop.first %} active{% endif %}" id="day{{forloop.counter0}}">Error loading calendar for {{day|date:"D M d"}}</div>
{% endfor %}
</div>
<div>
</body></html>