# HG changeset patch # User Paul Boddie # Date 1237853150 -3600 # Node ID f398ad4b5d369d2761a1d04d8f167f9a34a12587 # Parent 8d656956624276d184597f99fec04120ab74434e Added support for last/current/next month values. Introduced month spans to complement the above special month values. Added navigation support with elementary features for paging through calendars. Added various support functions to work with dates and months. diff -r 8d6569566242 -r f398ad4b5d36 EventAggregatorSupport.py --- a/EventAggregatorSupport.py Mon Mar 23 01:52:13 2009 +0100 +++ b/EventAggregatorSupport.py Tue Mar 24 01:05:50 2009 +0100 @@ -11,6 +11,7 @@ from MoinMoin.Page import Page from MoinMoin import search, version import calendar +import datetime import re __version__ = "0.1" @@ -112,44 +113,82 @@ else: return None +def getCurrentMonth(): + + "Return the current month as a (year, month) tuple." + + today = datetime.date.today() + return (today.year, today.month) + +def monthupdate(date, n): + + "Return 'date' updated by 'n' months." + + if n < 0: + fn = prevmonth + else: + fn = nextmonth + + i = 0 + while i < abs(n): + date = fn(date) + i += 1 + + return date + def daterange(first, last): + + "Get the range of dates starting at 'first' and ending on 'last'." + results = [] + step = last > first and 1 or -1 months_only = len(first) == 2 start_year = first[0] end_year = last[0] - for year in range(start_year, end_year + 1): - if year < end_year: + for year in range(start_year, end_year + step, step): + if step == 1 and year < end_year: end_month = 12 + elif step == -1 and year > end_year: + end_month = 1 else: end_month = last[1] - if year > start_year: + if step == 1 and year > start_year: start_month = 1 + elif step == -1 and year < start_year: + start_month = 12 else: start_month = first[1] - for month in range(start_month, end_month + 1): + for month in range(start_month, end_month + step, step): if months_only: results.append((year, month)) else: - if month < end_month: + if step == 1 and month < end_month: _wd, end_day = calendar.monthrange(year, month) + elif step == -1 and month > end_month: + end_day = 1 else: end_day = last[2] - if month > start_month: + if step == 1 and month > start_month: start_day = 1 + elif step == -1 and month < start_month: + _wd, start_day = calendar.monthrange(year, month) else: start_day = first[2] - for day in range(start_day, end_day + 1): + for day in range(start_day, end_day + step, step): results.append((year, month, day)) return results def nextdate(date): + + "Return the date following the given 'date'." + year, month, day = date _wd, end_day = calendar.monthrange(year, month) if day == end_day: @@ -160,6 +199,40 @@ else: return (year, month, day + 1) +def prevdate(date): + + "Return the date preceding the given 'date'." + + year, month, day = date + if day == 1: + if month == 1: + return (year - 1, 12, 31) + else: + _wd, end_day = calendar.monthrange(year, month - 1) + return (year, month - 1, end_day) + else: + return (year, month, day - 1) + +def nextmonth(date): + + "Return the (year, month) tuple following 'date'." + + year, month = date + if month == 12: + return (year + 1, 1) + else: + return year, month + 1 + +def prevmonth(date): + + "Return the (year, month) tuple preceding 'date'." + + year, month = date + if month == 1: + return (year - 1, 12) + else: + return year, month - 1 + def getEvents(request, category_names, calendar_start=None, calendar_end=None): """ diff -r 8d6569566242 -r f398ad4b5d36 css/event-aggregator.css --- a/css/event-aggregator.css Mon Mar 23 01:52:13 2009 +0100 +++ b/css/event-aggregator.css Tue Mar 24 01:05:50 2009 +0100 @@ -24,6 +24,20 @@ border: 0; } +.event-month-heading a:link, +.event-month-heading a:hover, +.event-month-heading a:visited { + color: inherit !important; +} + +.event-month-heading .previous-month { + float: left; +} + +.event-month-heading .next-month { + float: right; +} + .event-weekday-heading { background-color: #999999; color: #ffffff; diff -r 8d6569566242 -r f398ad4b5d36 macros/EventAggregator.py --- a/macros/EventAggregator.py Mon Mar 23 01:52:13 2009 +0100 +++ b/macros/EventAggregator.py Tue Mar 24 01:05:50 2009 +0100 @@ -42,7 +42,25 @@ else: return (255, 255, 255) -# Macro function. +# Macro functions. + +def getMonth(arg): + if arg in ("current", "next", "last"): + date = EventAggregatorSupport.getCurrentMonth() + if arg == "next": + date = EventAggregatorSupport.monthupdate(date, 1) + elif arg == "last": + date = EventAggregatorSupport.monthupdate(date, -1) + else: + date = EventAggregatorSupport.getMonth(arg) + return date + +def getFormMonth(request, calendar_name, argname): + arg = request.form.get("%s-%s" % (calendar_name, argname), [None])[0] + if arg is not None: + return getMonth(arg) + else: + return None def execute(macro, args): @@ -52,7 +70,14 @@ optional named arguments of the following forms: start=YYYY-MM shows event details starting from the specified month + start=current shows event details starting with the current month + start=next shows event details starting with next month end=YYYY-MM shows event details ending at the specified month + end=current shows event details ending with the current month + end=last shows event details ending with last month + span=N shows event details for N months starting with the + specified start month, or ending with the specified end + month mode=calendar shows a calendar view of events mode=list shows a list of events by month @@ -60,6 +85,9 @@ 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 + + calendar=NAME uses the given NAME to provide request parameters which + can be used to control the calendar view """ request = macro.request @@ -81,21 +109,62 @@ category_names = [] calendar_start = None calendar_end = None + span = None mode = "calendar" name_usage = "daily" + calendar_name = None for arg in parsed_args: if arg.startswith("start="): - calendar_start = EventAggregatorSupport.getMonth(arg[6:]) + calendar_start = getMonth(arg[6:]) + elif arg.startswith("end="): - calendar_end = EventAggregatorSupport.getMonth(arg[4:]) + calendar_end = getMonth(arg[4:]) + + elif arg.startswith("span="): + span = abs(int(arg[5:])) + elif arg.startswith("mode="): mode = arg[5:] + elif arg.startswith("names="): name_usage = arg[6:] + + elif arg.startswith("calendar="): + calendar_name = arg[9:] + else: category_names.append(arg) + # Find request parameters to override settings. + + if calendar_name is not None: + new_calendar_start = getFormMonth(request, calendar_name, "start") + new_calendar_end = getFormMonth(request, calendar_name, "end") + if new_calendar_start is not None or new_calendar_end is not None: + calendar_start = new_calendar_start + calendar_end = new_calendar_end + + # Calculate the window of interest. + + if span is not None: + if calendar_start is not None: + calendar_end = EventAggregatorSupport.monthupdate(calendar_start, max(0, span - 1)) + elif calendar_end is not None: + calendar_start = EventAggregatorSupport.monthupdate(calendar_end, min(0, -span + 1)) + else: + calendar_start = EventAggregatorSupport.getCurrentMonth() + calendar_end = EventAggregatorSupport.monthupdate(calendar_start, max(0, span - 1)) + + # Some useful navigation months. + + if calendar_name is not None: + previous_year, previous_month = EventAggregatorSupport.prevmonth(calendar_start) + next_year, next_month = EventAggregatorSupport.nextmonth(calendar_start) + next_set_year, next_set_month = EventAggregatorSupport.nextmonth(calendar_end) + + # Get the events. + events, shown_events, all_shown_events, earliest, latest = \ EventAggregatorSupport.getEvents(request, category_names, calendar_start, calendar_end) @@ -125,13 +194,44 @@ output.append(fmt.table_row(on=1)) output.append(fmt.table_cell(on=1, attrs={"class" : "event-month-heading", "colspan" : "7"})) - output.append(fmt.span(on=1)) - output.append(fmt.text(_(month_labels[month - 1]))) # zero-based labels - output.append(fmt.span(on=0)) - output.append(fmt.text(" ")) - output.append(fmt.span(on=1)) - output.append(fmt.text(year)) - output.append(fmt.span(on=0)) + + # Either write a month heading or produce a link for navigable + # calendars. + + month_label = _(month_labels[month - 1]) # zero-based labels + + if calendar_name is not None: + previous_months_link = "%s-end=%04d-%02d" % (calendar_name, previous_year, previous_month) + previous_month_link = "%s-start=%04d-%02d" % (calendar_name, previous_year, previous_month) + + output.append(fmt.span(on=1, css_class="previous-month")) + output.append(page.link_to_raw(request, wikiutil.escape("<<"), previous_months_link)) + output.append(fmt.text(" ")) + output.append(page.link_to_raw(request, wikiutil.escape("<"), previous_month_link)) + output.append(fmt.span(on=0)) + + next_months_link = "%s-start=%04d-%02d" % (calendar_name, next_set_year, next_set_month) + next_month_link = "%s-start=%04d-%02d" % (calendar_name, next_year, next_month) + + output.append(fmt.span(on=1, css_class="next-month")) + output.append(page.link_to_raw(request, wikiutil.escape(">"), next_month_link)) + output.append(fmt.text(" ")) + output.append(page.link_to_raw(request, wikiutil.escape(">>"), next_months_link)) + output.append(fmt.span(on=0)) + + full_month_label = "%s %s" % (month_label, year) + month_link = "%s-start=%04d-%02d" % (calendar_name, year, month) + output.append(page.link_to_raw(request, wikiutil.escape(full_month_label), month_link)) + + else: + output.append(fmt.span(on=1)) + output.append(fmt.text(month_label)) + output.append(fmt.span(on=0)) + output.append(fmt.text(" ")) + output.append(fmt.span(on=1)) + output.append(fmt.text(year)) + output.append(fmt.span(on=0)) + output.append(fmt.table_cell(on=0)) output.append(fmt.table_row(on=0))