# HG changeset patch # User Paul Boddie # Date 1422920025 -3600 # Node ID 96006c7331076f1cb07246c9a75932ec6eac72c4 # Parent 55be9e306c655496277b2afd06d3b369847bc89e Added support for whole-day selection, creating events with date value types. Made get_datetime more flexible about parsing dates when VALUE is undefined. Added a get_datetime_item function to produce iCalendar attributes and values. diff -r 55be9e306c65 -r 96006c733107 htdocs/styles.css --- a/htdocs/styles.css Tue Feb 03 00:02:18 2015 +0100 +++ b/htdocs/styles.css Tue Feb 03 00:33:45 2015 +0100 @@ -87,6 +87,7 @@ visibility: visible; } +input.newevent:checked ~ .day, input.newevent:checked ~ .timepoint { background-color: #af8; text-decoration: underline; diff -r 55be9e306c65 -r 96006c733107 imip_manager.py --- a/imip_manager.py Tue Feb 03 00:02:18 2015 +0100 +++ b/imip_manager.py Tue Feb 03 00:33:45 2015 +0100 @@ -33,9 +33,9 @@ from imiptools.content import Handler from imiptools.data import get_address, get_uri, make_freebusy, parse_object, \ Object, to_part -from imiptools.dates import format_datetime, get_datetime, get_start_of_day, \ - get_end_of_day, get_timestamp, ends_on_same_day, \ - to_timezone +from imiptools.dates import format_datetime, get_datetime, get_datetime_item, \ + get_start_of_day, get_start_of_next_day, get_timestamp, \ + ends_on_same_day, to_timezone from imiptools.mail import Messenger from imiptools.period import add_day_start_points, add_slots, convert_periods, \ get_freebusy_details, \ @@ -401,6 +401,12 @@ for i, (start, end) in enumerate(coalesced): this_uid = "%s-%s" % (uid, i) + start = get_datetime(start, {"TZID" : tzid}) + end = end and get_datetime(end, {"TZID" : tzid}) or get_start_of_next_day(start, tzid) + + start_value, start_attr = get_datetime_item(start) + end_value, end_attr = get_datetime_item(end) + # Create a calendar object and store it as a request. record = [] @@ -409,10 +415,8 @@ rwrite(("UID", {}, this_uid)) rwrite(("SUMMARY", {}, "New event at %s" % utcnow)) rwrite(("DTSTAMP", {}, utcnow)) - rwrite(("DTSTART", {"VALUE" : "DATE-TIME", "TZID" : tzid}, start)) - rwrite(("DTEND", {"VALUE" : "DATE-TIME", "TZID" : tzid}, end or - format_datetime(get_end_of_day(get_datetime(start, {"TZID" : tzid}))) - )) + rwrite(("DTSTART", start_attr, start_value)) + rwrite(("DTEND", end_attr, end_value)) rwrite(("ORGANIZER", {}, self.user)) for participant in participants: @@ -969,7 +973,7 @@ page.thead() page.tr() page.th(class_="dayheading", colspan=all_columns+1) - page.add(self.format_date(day, "full")) + self._day_heading(day) page.th.close() page.tr.close() page.thead.close() @@ -1092,21 +1096,37 @@ page.tr.close() + def _day_heading(self, day): + page = self.page + value, identifier = self._day_value_and_identifier(day) + slots = self.env.get_args().get("slot", []) + self._slot_selector(value, identifier, slots) + page.label(self.format_date(day, "full"), class_="day", for_=identifier) + def _time_point(self, point, endpoint): page = self.page value, identifier = self._slot_value_and_identifier(point, endpoint) slots = self.env.get_args().get("slot", []) + self._slot_selector(value, identifier, slots) + page.label(self.format_time(point, "long"), class_="timepoint", for_=identifier) + + def _slot_selector(self, value, identifier, slots): + page = self.page if value in slots: page.input(name="slot", type="checkbox", value=value, id=identifier, class_="newevent", checked="checked") else: page.input(name="slot", type="checkbox", value=value, id=identifier, class_="newevent") - page.label(self.format_time(point, "long"), class_="timepoint", for_=identifier) def _empty_slot(self, point, endpoint): page = self.page value, identifier = self._slot_value_and_identifier(point, endpoint) page.label("Select/deselect period", class_="newevent popup", for_=identifier) + def _day_value_and_identifier(self, day): + value = "%s-" % format_datetime(day) + identifier = "day-%s" % value + return value, identifier + def _slot_value_and_identifier(self, point, endpoint): value = "%s-%s" % (format_datetime(point), endpoint and format_datetime(endpoint) or "") identifier = "slot-%s" % value diff -r 55be9e306c65 -r 96006c733107 imiptools/dates.py --- a/imiptools/dates.py Tue Feb 03 00:02:18 2015 +0100 +++ b/imiptools/dates.py Tue Feb 03 00:33:45 2015 +0100 @@ -70,6 +70,13 @@ else: return dt.strftime("%Y%m%d") +def get_datetime_item(dt): + if not dt: + return None, None + value = format_datetime(dt) + attr = isinstance(dt, datetime) and {"TZID" : dt.tzname(), "VALUE" : "DATE-TIME"} or {"VALUE" : "DATE"} + return value, attr + def get_datetime(value, attr=None): """ @@ -94,7 +101,9 @@ return to_timezone(dt, m.group("utc") and "UTC" or attr and attr.get("TZID") or None) - if not attr or attr.get("VALUE") == "DATE": + # Permit dates even if the VALUE is not set to DATE. + + if not attr or attr.get("VALUE") in (None, "DATE"): m = match_date_icalendar(value) if m: year, month, day = map(m.group, ["year", "month", "day"]) @@ -108,6 +117,12 @@ def get_end_of_day(dt, tzid=None): return get_start_of_day(dt + timedelta(1), tzid) +def get_start_of_next_day(dt, tzid=None): + if isinstance(dt, datetime): + return get_end_of_day(dt, tzid) + else: + return dt + timedelta(1) + def ends_on_same_day(dt, end): return ( dt.date() == end.date() or