1.1 --- a/htdocs/styles.css Sat Feb 07 00:47:14 2015 +0100
1.2 +++ b/htdocs/styles.css Sat Feb 07 17:16:48 2015 +0100
1.3 @@ -108,51 +108,50 @@
1.4 text-decoration: underline;
1.5 }
1.6
1.7 -/* Hiding/showing unused slots/periods. */
1.8 +/* Hiding/showing busy slots/periods or unused days/slots/periods. */
1.9 +
1.10 +/* Hide the controls. */
1.11
1.12 -input#hideslots {
1.13 - display: none;
1.14 -}
1.15 +input#hidebusy,
1.16 +input#hidedays,
1.17 +input#hideslots,
1.18 +
1.19 +/* Hide the enable labels when controls are already enabled. */
1.20
1.21 -input#hideslots:checked ~ .controls label.enable[for=hideslots] {
1.22 - display: none;
1.23 -}
1.24 +input#hidebusy:checked ~ .controls label.enable[for=hidebusy],
1.25 +input#hidedays:checked ~ .controls label.enable[for=hidedays],
1.26 +input#hideslots:checked ~ .controls label.enable[for=hideslots],
1.27 +
1.28 +/* Hide the disable labels when controls are already disabled. */
1.29
1.30 -input#hideslots:not(:checked) ~ .controls label.disable[for=hideslots] {
1.31 - display: none;
1.32 -}
1.33 +input#hidebusy:not(:checked) ~ .controls label.disable[for=hidebusy],
1.34 +input#hidedays:not(:checked) ~ .controls label.disable[for=hidedays],
1.35 +input#hideslots:not(:checked) ~ .controls label.disable[for=hideslots],
1.36
1.37 +/* Hide calendar rows depending on the selected controls. */
1.38 +
1.39 +input#hidebusy:checked ~ .calendar tr.slot.busy,
1.40 +input#hidedays:checked ~ .calendar tr.separator.empty,
1.41 +input#hidedays:checked ~ .calendar tr.slot.onlyslot.daystart.empty,
1.42 +input#hideslots:checked ~ .calendar tr.separator.empty,
1.43 input#hideslots:checked ~ .calendar tr.slot.daystart.empty {
1.44 display: none;
1.45 }
1.46
1.47 -/* Hiding/showing busy slots/periods. */
1.48 -
1.49 -input#hidebusy {
1.50 - display: none;
1.51 -}
1.52 -
1.53 -input#hidebusy:checked ~ .controls label.enable[for=hidebusy] {
1.54 - display: none;
1.55 -}
1.56 -
1.57 -input#hidebusy:not(:checked) ~ .controls label.disable[for=hidebusy] {
1.58 - display: none;
1.59 -}
1.60 -
1.61 -input#hidebusy:checked ~ .calendar tr.slot.busy {
1.62 - display: none;
1.63 -}
1.64 +/* Show slot endpoints when hiding adjacent busy periods. */
1.65
1.66 input#hidebusy:checked ~ .calendar th.timeslot span.endpoint {
1.67 display: block;
1.68 }
1.69
1.70 +/* Style the labels. */
1.71 +
1.72 label.enable,
1.73 label.disable {
1.74 padding-left: 0.25em;
1.75 }
1.76
1.77 +label.hidedays,
1.78 label.hideslots {
1.79 border-left: 1em solid #faa; /* th.participantheading background-color */
1.80 }
2.1 --- a/imip_manager.py Sat Feb 07 00:47:14 2015 +0100
2.2 +++ b/imip_manager.py Sat Feb 07 17:16:48 2015 +0100
2.3 @@ -37,8 +37,8 @@
2.4 get_end_of_day, get_start_of_day, get_start_of_next_day, \
2.5 get_timestamp, ends_on_same_day, to_timezone
2.6 from imiptools.mail import Messenger
2.7 -from imiptools.period import add_day_start_points, add_slots, convert_periods, \
2.8 - get_freebusy_details, \
2.9 +from imiptools.period import add_day_start_points, add_empty_days, add_slots, \
2.10 + convert_periods, get_freebusy_details, \
2.11 get_scale, have_conflict, get_slots, get_spans, \
2.12 partition_by_day
2.13 from imiptools.profile import Preferences
2.14 @@ -854,11 +854,14 @@
2.15 # The positioning of the control, paragraph and table are important here.
2.16
2.17 page.input(name="hideslots", type="checkbox", value="hide", id="hideslots")
2.18 + page.input(name="hidedays", type="checkbox", value="hide", id="hidedays")
2.19 page.input(name="hidebusy", type="checkbox", value="hide", id="hidebusy")
2.20
2.21 page.p(class_="controls")
2.22 page.label("Hide busy time periods", for_="hidebusy", class_="hidebusy enable")
2.23 page.label("Show busy time periods", for_="hidebusy", class_="hidebusy disable")
2.24 + page.label("Hide empty days", for_="hidedays", class_="hidedays enable")
2.25 + page.label("Show empty days", for_="hidedays", class_="hidedays disable")
2.26 page.label("Hide unused time periods", for_="hideslots", class_="hideslots enable")
2.27 page.label("Show unused time periods", for_="hideslots", class_="hideslots disable")
2.28 page.p.close()
2.29 @@ -977,8 +980,16 @@
2.30 partitioned_group_types.append(group_type)
2.31 partitioned_group_sources.append(group_source)
2.32
2.33 + # Add empty days.
2.34 +
2.35 + add_empty_days(days, partitioned, tzid)
2.36 +
2.37 + # Show the controls permitting day selection.
2.38 +
2.39 self.show_calendar_day_controls(days)
2.40
2.41 + # Show the calendar itself.
2.42 +
2.43 page.table(cellspacing=5, cellpadding=5, class_="calendar")
2.44 self.show_calendar_participant_headings(partitioned_group_types, partitioned_group_sources, group_columns)
2.45 self.show_calendar_days(days, partitioned_groups, partitioned_group_types, group_columns)
2.46 @@ -1071,21 +1082,31 @@
2.47 # Produce a heading and time points for each day.
2.48
2.49 for day, intervals in all_days:
2.50 + groups_for_day = [partitioned.get(day) for partitioned in partitioned_groups]
2.51 + is_empty = True
2.52 +
2.53 + for slots in groups_for_day:
2.54 + if not slots:
2.55 + continue
2.56 +
2.57 + for active in slots.values():
2.58 + if active:
2.59 + is_empty = False
2.60 + break
2.61 +
2.62 page.thead()
2.63 - page.tr()
2.64 + page.tr(class_="separator%s" % (is_empty and " empty" or ""))
2.65 page.th(class_="dayheading container", colspan=all_columns+1)
2.66 self._day_heading(day)
2.67 page.th.close()
2.68 page.tr.close()
2.69 page.thead.close()
2.70
2.71 - groups_for_day = [partitioned.get(day) for partitioned in partitioned_groups]
2.72 -
2.73 page.tbody()
2.74 - self.show_calendar_points(intervals, groups_for_day, partitioned_group_types, group_columns)
2.75 + self.show_calendar_points(intervals, groups_for_day, partitioned_group_types, group_columns, is_empty)
2.76 page.tbody.close()
2.77
2.78 - def show_calendar_points(self, intervals, groups, group_types, group_columns):
2.79 + def show_calendar_points(self, intervals, groups, group_types, group_columns, is_empty):
2.80
2.81 """
2.82 Show the time 'intervals' along with period information from the given
2.83 @@ -1113,6 +1134,7 @@
2.84
2.85 css = " ".join(
2.86 ["slot"] +
2.87 + (is_empty and ["onlyslot"] or []) +
2.88 (have_active and ["busy"] or ["empty"]) +
2.89 (continuation and ["daystart"] or [])
2.90 )
3.1 --- a/imiptools/period.py Sat Feb 07 00:47:14 2015 +0100
3.2 +++ b/imiptools/period.py Sat Feb 07 17:16:48 2015 +0100
3.3 @@ -20,7 +20,7 @@
3.4 """
3.5
3.6 from bisect import bisect_left, insort_left
3.7 -from datetime import datetime
3.8 +from datetime import datetime, timedelta
3.9 from imiptools.dates import get_datetime, get_start_of_day, to_timezone
3.10
3.11 # Time management with datetime strings.
3.12 @@ -285,6 +285,23 @@
3.13
3.14 return d
3.15
3.16 +def add_empty_days(days, partitioned, tzid):
3.17 +
3.18 + "Add empty days to 'days' between busy days."
3.19 +
3.20 + last_day = None
3.21 + all_days = days.keys()
3.22 + all_days.sort()
3.23 +
3.24 + for day in all_days:
3.25 + if last_day:
3.26 + empty_day = last_day + timedelta(1)
3.27 + while empty_day < day:
3.28 + days[empty_day] = [(get_start_of_day(empty_day, tzid), None)]
3.29 + partitioned[empty_day] = {}
3.30 + empty_day += timedelta(1)
3.31 + last_day = day
3.32 +
3.33 def get_spans(slots):
3.34
3.35 "Inspect the given 'slots', returning a mapping of event uids to spans."