From ca1ff2fa0c9c8e596e1a15d9f2aebfc790219238 Mon Sep 17 00:00:00 2001
From: Adam Roach <adam@nostrum.com>
Date: Sat, 3 Nov 2012 21:01:40 +0000
Subject: [PATCH] Implementation of ticket 893  - Legacy-Id: 5003

---
 ietf/meeting/views.py                 | 24 ++++++--
 ietf/templates/meeting/agenda.html    | 83 +++++++++++++++++++++------
 ietf/templates/meeting/week-view.html | 44 +++++++++++++-
 3 files changed, 126 insertions(+), 25 deletions(-)

diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 2d1dee611..eb82bd72a 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -21,6 +21,7 @@ from django.middleware.gzip import GZipMiddleware
 from django.db.models import Max
 
 import debug
+import urllib
 
 from ietf.idtracker.models import InternetDraft
 from ietf.utils.pipe import pipe
@@ -425,24 +426,35 @@ def ical_agenda(request, num=None):
     meeting = get_meeting(num)
 
     q = request.META.get('QUERY_STRING','') or ""
-    filter = q.lower().replace('%2c',',').split(',');
+    filter = urllib.unquote(q).lower().split(',');
     include = set(filter)
-    include_types = ["Plenary","Other"]
+    include_types = set(["Plenary","Other"])
     exclude = []
 
     # Process the special flags.
+    #   "-wgname" will remove a working group from the output.
+    #   "~Type" will add that type to the output. 
+    #   "-~Type" will remove that type from the output
+    # Current types are:
+    #   Session, Other (default on), Break, Plenary (default on)
+    # Non-Working Group "wg names" include:
+    #   edu, ietf, tools, iesg, iab
+
     for item in include:
         if item:
-            if item[0] == '-':
+            if item[0] == '-' and item[1] == '~':
+                include_types -= set([item[2:3].upper()+item[3:]])
+            elif item[0] == '-':
                 exclude.append(item[1:])
-            if item[0] == '~':
-                include_types.append(item[1:2].upper()+item[2:])
+            elif item[0] == '~':
+                include_types |= set([item[1:2].upper()+item[2:]])
 
     timeslots = TimeSlot.objects.filter(Q(meeting__id = meeting.id),
         Q(type__name__in = include_types) |
         Q(session__group__acronym__in = filter) |
         Q(session__group__parent__acronym__in = filter)
-        )#.exclude(Q(session__group__isnull = False),
+        ).exclude(Q(session__group__acronym__in = exclude))
+        #.exclude(Q(session__group__isnull = False),
         #Q(session__group__acronym__in = exclude) | 
         #Q(session__group__parent__acronym__in = exclude))
 
diff --git a/ietf/templates/meeting/agenda.html b/ietf/templates/meeting/agenda.html
index d600fe9ce..4a6071323 100644
--- a/ietf/templates/meeting/agenda.html
+++ b/ietf/templates/meeting/agenda.html
@@ -19,6 +19,8 @@ table#wg-selector { border:1px solid black; border-collapse:collapse; }
 #wg-selector-triangle-right { vertical-align: text-top; }
 #wg-selector-triangle-down { vertical-align: text-top; }
 
+table#ics-preconfig { border:1px solid black; border-collapse:collapse; margin-top:24px; margin-bottom:24px;}
+
 #weekview.hidden { display: none; }
 #weekview { border: none; margin: 0 0 0 0;}
 #ical-link.hidden { display: none; }
@@ -88,6 +90,7 @@ img.hidden { display: none; }
     var ical_link = document.getElementById('ical-link');
     var ical_href = document.getElementById('ical-href');
 
+
     lastfrag = frag;
 
     var fragment = frag.split(',');
@@ -163,7 +166,14 @@ img.hidden { display: none; }
       }
     }
 
-
+    // Handle special cases (checkboxes)
+    var special = ['edu','ietf','tools','iesg','iab'];
+    var re3 = RegExp("^(" + fragment.join('|') + ")$");
+    for (i in special)
+    {
+      var include = document.getElementById("include-"+special[i]);
+      include.checked = ! re3.test("\-"+special[i]);
+    }
   }
 
   /* Resizes an IFRAME to fit its contents. */
@@ -203,6 +213,26 @@ img.hidden { display: none; }
     }
   }
 
+  function add_hash_item(item)
+  {
+    if (window.location.hash.replace("#","").length == 0)
+    {
+      window.location.hash = item;
+    }
+    else
+    {
+      window.location.hash += "," + item;
+    }
+    window.location.hash = window.location.hash.replace(/^#?,/,'');
+  }
+
+  function remove_hash_item(item)
+  {
+    var re = new RegExp('(^|#|,)' + item + "(,|$)");
+    window.location.hash = window.location.hash.replace(re,"$2")
+    window.location.hash = window.location.hash.replace(/^#?,/,'');
+  }
+
   function toggle(selection)
   {
     var active = selection.className;
@@ -210,26 +240,28 @@ img.hidden { display: none; }
 
     if (active == "selected")
     {
-      var re = new RegExp('(^|#|,)' + wg + "(,|$)");
-      window.location.hash = window.location.hash.replace(re,"$2")
-
+      remove_hash_item(wg);
     }
     else
     {
-      if (window.location.hash.replace("#","").length == 0)
-      {
-        window.location.hash = wg;
-      }
-      else
-      {
-        window.location.hash += "," + wg;
-      }
-
+      add_hash_item(wg);
     }
-    window.location.hash = window.location.hash.replace(/^#?,/,'');
     setGroupState();
   }
 
+  function toggle_special(checkbox)
+  {
+    var special = checkbox.id.replace('include-','');
+    if (checkbox.checked)
+    {
+      remove_hash_item("-"+special);
+    }
+    else
+    {
+      add_hash_item("-"+special);
+    }
+  }
+
   function toggle_wg_selector ()
   {
     var wg_selector = document.getElementById('wg-selector');
@@ -247,6 +279,7 @@ img.hidden { display: none; }
       triangle_right.className = '';
       triangle_down.className = 'hidden';
     }
+    setGroupState();
   }
 </script>
 
@@ -285,13 +318,31 @@ You can customize the agenda below to show only selected working group sessions.
       <div id='selector-{{wg.acronym}}' class="unselected" onclick="toggle(this)">{% if wg.state.name = "BOF" %}<i>{{wg.acronym}}</i>{% else %}{{wg.acronym}}{% endif %}</div>{% endfor %}
     </td>
   </tr>
-  <tr><td align="center" colspan="{{area_list.count}}"><i>Groups displayed in italics are BOFs</i></td></tr>
+  <tr><td align="center" colspan="{{area_list.count}}">
+    Also show:
+    <input type="checkbox" class="include-checkbox" id="include-edu" onchange="toggle_special(this)"/>EDU &#8226;
+    <input type="checkbox" class="include-checkbox" id="include-ietf" onchange="toggle_special(this)"/>IETF &#8226;
+    <input type="checkbox" class="include-checkbox" id="include-tools" onchange="toggle_special(this)"/>Tools &#8226;
+    <input type="checkbox" class="include-checkbox" id="include-iesg" onchange="toggle_special(this)"/>IESG &#8226;
+    <input type="checkbox" class="include-checkbox" id="include-iab" onchange="toggle_special(this)"/>IAB
+<!--  </td></tr>
+  <tr><td align="center" colspan="{{area_list.count}}">
+-->
+  <br/><i>Groups displayed in italics are BOFs</i></td></tr>
 </table>
 
-<div id="ical-link" class="hidden"><span style="font-size:150%">Week View</span><br/><a id="ical-href" href="{% url ietf.meeting.views.ical_agenda num=meeting.number %}"><em>Download as an .ical file</em></a></div>
+<div id="ical-link" class="hidden"><span style="font-size:150%">Week View</span><br/><a id="ical-href" href="{% url ietf.meeting.views.ical_agenda num=meeting.number %}"><em>Download as an .ics file</em></a></div>
 
 <iframe id="weekview" class="hidden" width="100%" height="600px" src="about:blank"></iframe>
 
+<table width="100%" id="ics-preconfig"><tr><td align="center">
+  Preconfigured .ics links:
+  {% for area in area_list %}
+    <a href="{% url ietf.meeting.views.ical_agenda num=meeting.number %}?{{area|upper}},-~Other,-~Plenary">{{area|upper}}</a> &#8226;
+  {% endfor %}
+  <a href="{% url ietf.meeting.views.ical_agenda num=meeting.number %}">Non-Area Events</a>
+</td></tr></table>
+
 {% if meeting.agenda_note %}<h2 class="ietf-divider" style="background-color: #C00; margin-top: 2em; margin-bottom: 0;">{{ meeting.agenda_note|safe }}</h2>{% endif %}
 
 <table id="agenda" width="100%">
diff --git a/ietf/templates/meeting/week-view.html b/ietf/templates/meeting/week-view.html
index ddb4384dc..8b68e9b9f 100644
--- a/ietf/templates/meeting/week-view.html
+++ b/ietf/templates/meeting/week-view.html
@@ -9,7 +9,7 @@ var items = new Array();
 {% autoescape off %}
 
 {% for slot in timeslots %} {% if slot.type.name in render_types %}
-items.push({day:{{slot.time|date:"w"}}, time:"{{slot.time|date:"Hi"}}-{{slot.end_time|date:"Hi"}}", duration:{{slot.duration.seconds}}, time_id:"{{slot.time|date:"mdHi"}}", type:"{{slot.type}}", {% if slot.session.name %}name:"{{slot.session.name}}",{% else %}{% if slot.type.name == "Break" %}name:"{{slot.name}}", area:"break", wg:"break",{% else %}name:"{{slot.session.group.name}}{%if slot.session.group.state.name = "BOF"%} BOF{%endif%}",wg:"{{slot.session.group.acronym}}",area:"{{slot.session.group.parent.acronym}}",{% endif %}{% endif %} {% if slot.show_location %}room:"{{slot.get_location}}",{% endif %} dayname:"{{ slot.time|date:"l"|upper }}, {{ slot.time|date:"F j, Y" }}"{% if slot.session.agenda %}, agenda:"http://www.ietf.org{{slot.session.agenda.get_absolute_url}}"{% endif %} });{% endif %}{% endfor %}
+items.push({key:"{{slot.pk}}",day:{{slot.time|date:"w"}}, time:"{{slot.time|date:"Hi"}}-{{slot.end_time|date:"Hi"}}", duration:{{slot.duration.seconds}}, time_id:"{{slot.time|date:"mdHi"}}", type:"{{slot.type}}", {% if slot.session.name %}name:"{{slot.session.name}}",{% if slot.session.group.acronym %} wg:"{{slot.session.group.acronym}}",{%endif%}{% else %}{% if slot.type.name == "Break" %}name:"{{slot.name}}", area:"break", wg:"break",{% else %}name:"{{slot.session.group.name}}{%if slot.session.group.state.name = "BOF"%} BOF{%endif%}",wg:"{{slot.session.group.acronym}}",state:"{{slot.session.group.state}}",area:"{{slot.session.group.parent.acronym}}",{% endif %}{% endif %} {% if slot.show_location %}room:"{{slot.get_location}}",{% endif %} dayname:"{{ slot.time|date:"l"|upper }}, {{ slot.time|date:"F j, Y" }}"{% if slot.session.agenda %}, agenda:"http://www.ietf.org{{slot.session.agenda.get_absolute_url}}"{% endif %} });{% endif %}{% endfor %}
 {% endautoescape %}
 
 /* Saturday events need to be moved to the day -1 */
@@ -63,8 +63,40 @@ var lastwidth;
 var padding = 2;
 var border = 1;
 
+var include = Array();
+
 setInterval("animate()",50);
 
+function is_visible(item)
+{
+   //   "-wgname" will remove a working group from the output.
+   //   "~Type" will add that type to the output. 
+   //   "-~Type" will remove that type from the output
+   //   "@bof" will include all BOFs
+   // Current types are:
+   //   Session, Other, Break, Plenary
+
+  if ("wg" in item)
+  {
+    if (include[(item.wg).toLowerCase()]) { return true; }
+    if (include["-"+(item.wg).toLowerCase()]) { return false; }
+  }
+  if ("state" in item)
+  {
+    if (include["@"+(item.state).toLowerCase()]) { return true; }
+  }
+  if (include["~"+(item.type).toLowerCase()]) { return true; }
+  if (include["-~"+(item.type).toLowerCase()]) { return false; }
+  if ("area" in item)
+  {
+    if (include[(item.area).toLowerCase()]) { return true; }
+  }
+  if (item.type === "Plenary") { return true; }
+  if (item.type === "Other") { return true; }
+ 
+  return false;
+}
+
 function draw_calendar()
 {
   window.setTimeout("draw_calendar()",1000);
@@ -88,7 +120,7 @@ function draw_calendar()
 
   var day_start = 0;
   var day_end = 0;
-  var include = Array();
+  include = [];
 
   var frag = window.location.hash.replace("#",'').split(',');
   for (i = 0; i < frag.length; i++)
@@ -99,8 +131,11 @@ function draw_calendar()
   /* Find our boundaries */
   for (i = 0; i < items.length; i++)
   {
+    if (is_visible(items[i]))
+  /*
     if (!("wg" in items[i]) || (include[(items[i].wg).toLowerCase()] 
         || include[(items[i].area).toLowerCase()]))
+  */
     {
       var start_time = parseInt(items[i].time.substr(0,2),10) * 60 +
                        parseInt(items[i].time.substr(2,2),10);
@@ -207,8 +242,11 @@ function draw_calendar()
 
   for (i = 0; i < items.length; i++)
   {
-    if (!("wg" in items[i])|| (include[(items[i].wg).toLowerCase()] 
+    if (is_visible(items[i]))
+  /*
+    if (!("wg" in items[i]) || (include[(items[i].wg).toLowerCase()] 
         || include[(items[i].area).toLowerCase()]))
+  */
     {
       var start_time = parseInt(items[i].time.substr(0,2),10) * 60 +
                        parseInt(items[i].time.substr(2,2),10);