# HG changeset patch # User Paul Boddie # Date 1237754044 -3600 # Node ID 9e6bb8250f87e58a6d02e1877010629d383a60e9 # Parent 321a0dd5ad956c9ec976fb53d411a48377459866 Introduced improved calendar marking in order to show events as continuous regions, supporting also "weekly" vs. "daily" display of event names. Replaced monthrange with daterange in order to support the above feature. diff -r 321a0dd5ad95 -r 9e6bb8250f87 css/event-aggregator.css --- a/css/event-aggregator.css Sun Mar 22 02:25:49 2009 +0100 +++ b/css/event-aggregator.css Sun Mar 22 21:34:04 2009 +0100 @@ -13,6 +13,7 @@ .event-month { width: 90%; + border-bottom: 1px solid #dddddd; } .event-month-heading { @@ -20,20 +21,50 @@ color: #ffffff; text-align: center; font-weight: bold; + border: 0; +} + +.event-weekday-heading { + background-color: #999999; + color: #ffffff; + text-align: center; + border: 1px solid #dddddd; } .event-day-heading { - background-color: #999999; + background-color: #ffffff; + width: 14%; + vertical-align: top; + padding-top: 0; + padding-left: 0; + border-top: 1px solid #dddddd; + border-bottom: 0; + border-left: 1px solid #dddddd; + border-right: 1px solid #dddddd; +} + +.event-day-empty span.event-day-number { + color: #000000; +} + +.event-day-busy span.event-day-number { + background-color: #555555; color: #ffffff; - text-align: center; +} + +.event-day-number { + padding: 0.25em; } .event-day { width: 14%; vertical-align: top; - padding-top: 0; padding-left: 0; padding-right: 0; + border-top: 0; + border-bottom: 0; + border-left: 1px solid #dddddd; + border-right: 1px solid #dddddd; } .event-day-empty { @@ -49,22 +80,10 @@ background-color: #dddddd; } -.event-day-empty span.event-day-number { - color: #000000; -} - -.event-day-busy span.event-day-number { - background-color: #555555; - color: #ffffff; -} - -.event-day-number { - padding: 0.25em; -} - .event-summary { padding: 0.25em; - margin-bottom: 0.5em; + margin-bottom: 0.25em; + min-height: 2em; } .event-starts { diff -r 321a0dd5ad95 -r 9e6bb8250f87 macros/EventAggregator.py --- a/macros/EventAggregator.py Sun Mar 22 02:25:49 2009 +0100 +++ b/macros/EventAggregator.py Sun Mar 22 21:34:04 2009 +0100 @@ -13,6 +13,11 @@ import calendar import re +try: + set +except NameError: + from sets import Set as set + __version__ = "0.1" Dependencies = ['pages'] @@ -111,24 +116,40 @@ else: return None -def monthrange(first, last): +def daterange(first, last): results = [] + months_only = len(first) == 2 + start_year = first[0] end_year = last[0] - for year in range(first[0], end_year + 1): - if year < last[0]: + for year in range(start_year, end_year + 1): + if year < end_year: end_month = 12 else: end_month = last[1] - if year > first[0]: + if year > start_year: start_month = 1 else: start_month = first[1] for month in range(start_month, end_month + 1): - results.append((year, month)) + if months_only: + results.append((year, month)) + else: + if month < end_month: + _wd, end_day = calendar.monthrange(year, month) + else: + end_day = last[2] + + if month > start_month: + start_day = 1 + else: + start_day = first[2] + + for day in range(start_day, end_day + 1): + results.append((year, month, day)) return results @@ -153,9 +174,16 @@ """ Execute the 'macro' with the given 'args': an optional list of selected category names (categories whose pages are to be shown), together with - optional named arguments of the form "start=YYYY-MM" and "end=YYYY-MM" - (indicating a restricted view of all events), and "mode=list" or - "mode=calendar" (indicating the style of view). + optional named arguments of the following forms: + + start=YYYY-MM shows event details starting from the specified month + end=YYYY-MM shows event details ending at the specified month + + mode=calendar shows a calendar view of events + mode=list shows a list of events by month + + names=daily shows the name of an event on every day of that event + names=weekly shows the name of an event once per week """ request = macro.request @@ -178,6 +206,7 @@ calendar_start = None calendar_end = None mode = "calendar" + name_usage = "daily" for arg in parsed_args: if arg.startswith("start="): @@ -186,6 +215,8 @@ calendar_end = getMonth(arg[4:]) elif arg.startswith("mode="): mode = arg[5:] + elif arg.startswith("names="): + name_usage = arg[6:] else: category_names.append(arg) @@ -213,6 +244,9 @@ real_page_in_category = Page(request, pagename) event_details = getEventDetails(real_page_in_category) + + # Define the event as the page together with its details. + event = (real_page_in_category, event_details) events.append(event) @@ -239,7 +273,7 @@ first = max(start_month, calendar_start or start_month) last = min(end_month, calendar_end or end_month) - for event_month in monthrange(first, last): + for event_month in daterange(first, last): if not shown_events.has_key(event_month): shown_events[event_month] = [] shown_events[event_month].append(event) @@ -256,7 +290,7 @@ first = calendar_start or earliest last = calendar_end or latest - for year, month in monthrange(first, last): + for year, month in daterange(first, last): # Either output a calendar view... @@ -283,7 +317,7 @@ output.append(fmt.table_row(on=1)) for weekday in range(0, 7): - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading"})) + output.append(fmt.table_cell(on=1, attrs={"class" : "event-weekday-heading"})) output.append(fmt.text(_(weekday_labels[weekday]))) output.append(fmt.table_cell(on=0)) @@ -302,41 +336,73 @@ while first_day <= number_of_days: - # Output a week. + # Find events in this week and determine how to mark them on the + # calendar. + + week_events = [] + week_coverage = set() + + week_start = (year, month, max(first_day, 1)) + week_end = (year, month, min(first_day + 6, number_of_days)) + + # Get event details. + + for event in shown_events.get((year, month), []): + event_page, event_details = event + + # Test for the event in the current week. + + if event_details["start"] <= week_end and event_details["end"] >= week_start: + + # Find the coverage of this week for the event. + + event_start = max(event_details["start"], week_start) + event_end = min(event_details["end"], week_end) + event_coverage = set(daterange(event_start, event_end)) + + # Update the overall coverage. + + week_coverage.update(event_coverage) + + # Try and fit the event into the events list. + + for i, (coverage, events) in enumerate(week_events): + + # Where the event does not overlap with the current + # element, add it alongside existing events. + + if not coverage.intersection(event_coverage): + events.append(event) + week_events[i] = coverage.union(event_coverage), events + break + + # Make a new element in the list if the event cannot be + # marked alongside existing events. + + else: + week_events.append((event_coverage, [event])) + + # Output a week, starting with the day numbers. output.append(fmt.table_row(on=1)) for weekday in range(0, 7): day = first_day + weekday + date = (year, month, day) # Output out-of-month days. if day < 1 or day > number_of_days: - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-excluded"})) + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-excluded"})) output.append(fmt.table_cell(on=0)) # Output normal days. else: - # Get event details. - # NOTE: Can be made more efficient. - - date = (year, month, day) - day_events = [] - - for event_page, event_details in shown_events.get((year, month), []): - - # Test for the event on the current day. - - if event_details["start"] <= date <= event_details["end"]: - day_events.append((event_page, event_details)) - - # Output the day. - - if day_events: - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-busy"})) + if date in week_coverage: + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-busy"})) else: - output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-empty"})) + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day-heading event-day-empty"})) output.append(fmt.div(on=1)) output.append(fmt.span(on=1, css_class="event-day-number")) @@ -344,11 +410,47 @@ output.append(fmt.span(on=0)) output.append(fmt.div(on=0)) - output.append(fmt.div(on=1, css_class="event-summaries")) + # End of day. + + output.append(fmt.table_cell(on=0)) + + # End of day numbers. + + output.append(fmt.table_row(on=0)) + + # Visit each set of scheduled events. + + for coverage, events in week_events: + + # Output each set. + + output.append(fmt.table_row(on=1)) + + # Then, output day details. - # Show event details. + for weekday in range(0, 7): + day = first_day + weekday + date = (year, month, day) + + # Skip out-of-month days. + + if day < 1 or day > number_of_days: + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-excluded"})) + output.append(fmt.table_cell(on=0)) + continue - for event_page, event_details in day_events: + # Output the day. + + if date in coverage: + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-busy"})) + else: + output.append(fmt.table_cell(on=1, attrs={"class" : "event-day event-day-empty"})) + + # Get event details for the current day. + + for event_page, event_details in events: + if not (event_details["start"] <= date <= event_details["end"]): + continue # Get a pretty version of the page name. @@ -363,24 +465,37 @@ if event_details["start"] == date: css_classes.append("event-starts") + start_of_event = 1 + else: + start_of_event = 0 if event_details["end"] == date: css_classes.append("event-ends") # Output the event. + if name_usage == "daily" or start_of_event or weekday == 0 or day == 1: + hide_text = 0 + else: + hide_text = 1 + output.append(fmt.div(on=1, css_class=(" ".join(css_classes)), style=("background-color: rgb(%d, %d, %d); color: rgb(%d, %d, %d);" % (bg + fg)))) - output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename))) + + if not hide_text: + output.append(event_page.link_to_raw(request, wikiutil.escape(pretty_pagename))) + output.append(fmt.div(on=0)) - output.append(fmt.div(on=0)) - # End of day. output.append(fmt.table_cell(on=0)) - output.append(fmt.table_row(on=0)) + # End of set. + + output.append(fmt.table_row(on=0)) + + # Process the next week... first_day += 7