# HG changeset patch # User Paul Boddie # Date 1443313182 -7200 # Node ID 3ecd1cdae909fc2af1a5427d5eca15dff11686df # Parent a10c6ba1ad1f0583bfebdafa374c53dc3292d145 Switched to using div elements and table-based display properties. diff -r a10c6ba1ad1f -r 3ecd1cdae909 htdocs/styles.css --- a/htdocs/styles.css Sun Sep 27 01:26:05 2015 +0200 +++ b/htdocs/styles.css Sun Sep 27 02:19:42 2015 +0200 @@ -1,6 +1,5 @@ /* Table styling. */ -table.calendar, table.conflicts, table.counters, table.recurrence, @@ -8,6 +7,34 @@ border: 2px solid #000; } +div.calendar { + display: table; +} + +div.dayheading { + display: table-caption; + text-align: center; + width: 100%; +} + +div.tablerow { + display: table-row; +} + +div.tableheading { + display: table-header-group; +} + +div.tablebody { + display: table-row-group; +} + +div.tablecell { + display: table-cell; + padding: 0.25em; + width: 10em; +} + colgroup#columns-request { background-color: #eef; } @@ -16,73 +43,76 @@ background-color: #fee; } -th.requestheading { +.requestheading { background-color: #aaf; } -th.participantheading{ +.participantheading{ background-color: #faa; } -th.dayheading, -th.mainheading { +.dayheading, +.mainheading { background-color: #f85; } -th.timeslot, -th.objectheading { +.timeslot, +.objectheading { white-space: nowrap; } -th.objectheading { +.objectheading { background-color: #fca; } -th.timeslot { +.timeslot { padding-top: 0; vertical-align: top; } -th.timeslot span.endpoint { +.timeslot span.endpoint { display: none; font-size: smaller; } -td.event { +.event { background-color: #ff8; - border: 2px solid #000; + border-right: 2px solid #777; } -td.event.only-organising { +.event.only-organising { background-color: #afd; } -td.event.organising { +.event.organising { background-color: #af8; } -td.event.continued { +.event.continued { border-top: 2px dotted #000; } -td.event.continues { +.event.continues { border-bottom: 2px dotted #000; } -td.event:target { - border-width: 4px; +.event.ends { + border-bottom: 2px solid #777; +} + +.event:target { background-color: #ee2; } -td.event.organising:target { +.event.organising:target { background-color: #5f4; } -td.event a { +.event a { color: #009; } -th.objectheading.error { +.objectheading.error { background-color: #f77; } @@ -136,17 +166,16 @@ display: inline; } -th.container, -td.container { +.container { padding: 0; /* for regions covered by labels */ } -th.dayheading:hover, -th.dayheading:focus, -th.timeslot:hover, -th.timeslot:focus, -td.container:hover, -td.container:focus { +.dayheading:hover, +.dayheading:focus, +.timeslot:hover, +.timeslot:focus, +.container:hover, +.container:focus { background-color: #af8; } @@ -161,8 +190,8 @@ text-align: center; } -td.container:hover label.newevent.popup, -td.container:focus label.newevent.popup { +.container:hover label.newevent.popup, +.container:focus label.newevent.popup { visibility: visible; } @@ -183,9 +212,10 @@ /* Hide calendar rows depending on the selected controls. */ -input#hidebusy:checked ~ .calendar tr.slot.busy, -input#showdays:not(:checked) ~ .calendar thead.separator.empty, -input#showdays:not(:checked) ~ .calendar tbody.points.empty, +input#hidebusy:checked ~ .calendar div.slot.busy, +input#showdays:not(:checked) ~ .calendar div.dayheading.empty, +input#showdays:not(:checked) ~ .calendar div.tableheading.empty, +input#showdays:not(:checked) ~ .calendar div.points.empty, /* Hiding/showing end datetimes and start/end times. */ @@ -215,7 +245,7 @@ /* Show slot endpoints when hiding adjacent busy periods. */ -input#hidebusy:checked ~ .calendar th.timeslot span.endpoint { +input#hidebusy:checked ~ .calendar .timeslot span.endpoint { display: block; } @@ -283,11 +313,11 @@ } label.showdays { - border-left: 1em solid #faa; /* th.participantheading background-color */ + border-left: 1em solid #faa; /* .participantheading background-color */ } label.hidebusy { - border-left: 1em solid #af8; /* td.event background-color */ + border-left: 1em solid #af8; /* .event background-color */ } label.reset { diff -r a10c6ba1ad1f -r 3ecd1cdae909 imipweb/calendar.py --- a/imipweb/calendar.py Sun Sep 27 01:26:05 2015 +0200 +++ b/imipweb/calendar.py Sun Sep 27 02:19:42 2015 +0200 @@ -409,10 +409,7 @@ # Show the calendar itself. - page.table(cellspacing=5, cellpadding=5, class_="calendar") - self.show_calendar_participant_headings(partitioned_group_types, partitioned_group_sources, group_columns) - self.show_calendar_days(days, partitioned_groups, partitioned_group_types, group_columns) - page.table.close() + self.show_calendar_days(days, partitioned_groups, partitioned_group_types, partitioned_group_sources, group_columns) # End the form region. @@ -443,8 +440,8 @@ for day in days: daystr, dayid = self._day_value_and_identifier(day) l.append("""\ -input.newevent.selector#%s:checked ~ table thead#region-%s label.day, -input.newevent.selector#%s:checked ~ table tbody#region-%s label.timepoint""" % (dayid, dayid, dayid, dayid)) +input.newevent.selector#%s:checked ~ div div#region-%s label.day, +input.newevent.selector#%s:checked ~ div div#region-%s label.timepoint""" % (dayid, dayid, dayid, dayid)) page.add(",\n".join(l)) page.add(""" { @@ -480,7 +477,7 @@ for point, endpoint in intervals: timestr, timeid = self._slot_value_and_identifier(point, endpoint) l.append("""\ -input.newevent.selector#%s:checked ~ table th#region-%s label.timepoint""" % (timeid, timeid)) +input.newevent.selector#%s:checked ~ div div#region-%s label.timepoint""" % (timeid, timeid)) page.add(",\n".join(l)) page.add(""" { @@ -491,7 +488,7 @@ page.style.close() - def show_calendar_participant_headings(self, group_types, group_sources, group_columns): + def show_calendar_participant_headings(self, group_types, group_sources, group_columns, is_empty): """ Show headings for the participants and other scheduling contributors, @@ -500,24 +497,20 @@ page = self.page - page.colgroup(span=1, id="columns-timeslot") - - for group_type, columns in zip(group_types, group_columns): - page.colgroup(span=max(columns, 1), id="columns-%s" % group_type) - - page.thead() - page.tr() - page.th("", class_="emptyheading") + page.div(class_="tableheading%s" % (is_empty and " empty" or "")) + page.div(class_="tablerow") + page.div("", class_="tablecell emptyheading") for group_type, source, columns in zip(group_types, group_sources, group_columns): - page.th(source, - class_=(group_type == "request" and "requestheading" or "participantheading"), - colspan=max(columns, 1)) + page.div(source, + class_="tablecell %s" % (group_type == "request" and "requestheading" or "participantheading")) + for i in range(1, max(columns, 1)): + page.div("", class_="tablecell %s" % (group_type == "request" and "requestheading" or "participantheading")) - page.tr.close() - page.thead.close() + page.div.close() + page.div.close() - def show_calendar_days(self, days, partitioned_groups, partitioned_group_types, group_columns): + def show_calendar_days(self, days, partitioned_groups, partitioned_group_types, partitioned_group_sources, group_columns): """ Show calendar days, defined by a collection of 'days', the contributing @@ -556,17 +549,18 @@ daystr, dayid = self._day_value_and_identifier(day) - page.thead(class_="separator%s" % (is_empty and " empty" or ""), id="region-%s" % dayid) - page.tr() - page.th(class_="dayheading container", colspan=all_columns+1) + page.div(class_="calendar") + + page.div(class_="dayheading container separator%s" % (is_empty and " empty" or ""), id="region-%s" % dayid) self._day_heading(day) - page.th.close() - page.tr.close() - page.thead.close() + page.div.close() + + self.show_calendar_participant_headings(partitioned_group_types, partitioned_group_sources, group_columns, is_empty) - page.tbody(class_="points%s" % (is_empty and " empty" or ""), id="region-%s" % dayid) + page.div(class_="tablebody points%s" % (is_empty and " empty" or ""), id="region-%s" % dayid) self.show_calendar_points(intervals, groups_for_day, partitioned_group_types, group_columns) - page.tbody.close() + page.div.close() + page.div.close() def show_calendar_points(self, intervals, groups, group_types, group_columns): @@ -612,14 +606,14 @@ continuation and "daystart" or "" ]) - page.tr(class_=css) + page.div(class_="tablerow %s" % css) if point.indicator == Point.PRINCIPAL: timestr, timeid = self._slot_value_and_identifier(point, endpoint) - page.th(class_="timeslot", id="region-%s" % timeid) + page.div(class_="tablecell timeslot", id="region-%s" % timeid) self._time_point(point, endpoint) else: - page.th() - page.th.close() + page.div(class_="tablecell") + page.div.close() # Obtain slots for the time point from each group. @@ -662,47 +656,56 @@ # Points defining the ends of instant events should # never define the start of new events. - if point.indicator == Point.PRINCIPAL and (point.point == p.get_start() or continuation): + first_cell_in_group = point.indicator == Point.PRINCIPAL and (point.point == p.get_start() or continuation) - has_continued = continuation and point.point != p.get_start() - will_continue = not ends_on_same_day(point.point, p.get_end(), tzid) - is_organiser = p.organiser == self.user + has_continued = continuation and point.point != p.get_start() + will_continue = not endpoint and not ends_on_same_day(point.point, p.get_end(), tzid) + is_organiser = p.organiser == self.user + + last_cell = not will_continue and (not endpoint or endpoint.point == p.get_end()) - css = " ".join([ - "event", - has_continued and "continued" or "", - will_continue and "continues" or "", - p.transp == "ORG" and "only-organising" or is_organiser and "organising" or "attending", - self._have_request(p.uid, p.recurrenceid, "COUNTER", True) and "counter" or "", - ]) + css = " ".join([ + "event", + has_continued and "continued" or "", + will_continue and "continues" or "", + last_cell and "ends" or "", + p.transp == "ORG" and "only-organising" or is_organiser and "organising" or "attending", + self._have_request(p.uid, p.recurrenceid, "COUNTER", True) and "counter" or "", + ]) - # Only anchor the first cell of events. - # Need to only anchor the first period for a recurring - # event. + # Only anchor the first cell of events. + # Need to only anchor the first period for a recurring + # event. - html_id = "%s-%s-%s" % (group_type, p.uid, p.recurrenceid or "") + html_id = "%s-%s-%s" % (group_type, p.uid, p.recurrenceid or "") - if point.point == p.get_start() and html_id not in self.html_ids: - page.td(class_=css, rowspan=span, id=html_id) - self.html_ids.add(html_id) - else: - page.td(class_=css, rowspan=span) + if point.point == p.get_start() and html_id not in self.html_ids: + page.div(class_="tablecell %s" % css, id=html_id) + self.html_ids.add(html_id) + else: + page.div(class_="tablecell %s" % css) - # Only link to events if they are not being updated - # by requests. + # Continue event spans using empty cells. + + if not first_cell_in_group: + pass + + # Only link to events if they are not being updated + # by requests. - if not p.summary or \ - group_type != "request" and self._have_request(p.uid, p.recurrenceid, None, True): + elif not p.summary or \ + group_type != "request" and self._have_request(p.uid, p.recurrenceid, None, True): - page.span(p.summary or "(Participant is busy)") + page.span(p.summary or "(Participant is busy)") - # Link to requests and events (including ones for - # which counter-proposals exist). + # Link to requests and events (including ones for + # which counter-proposals exist). - else: - page.a(p.summary, href=self.link_to(p.uid, p.recurrenceid)) + else: + page.a(p.summary, href=self.link_to(p.uid, p.recurrenceid)) - page.td.close() + page.div.close() + else: empty += 1 @@ -713,7 +716,7 @@ if empty: self._empty_slot(point, endpoint, empty) - page.tr.close() + page.div.close() def _day_heading(self, day): @@ -767,11 +770,13 @@ """ page = self.page - page.td(class_="empty%s" % (point.indicator == Point.PRINCIPAL and " container" or ""), colspan=colspan) - if point.indicator == Point.PRINCIPAL: - value, identifier = self._slot_value_and_identifier(point, endpoint) - page.label("Select/deselect period", class_="newevent popup", for_=identifier) - page.td.close() + + for i in range(0, colspan): + page.div(class_="tablecell empty%s" % (point.indicator == Point.PRINCIPAL and " container" or "")) + if point.indicator == Point.PRINCIPAL: + value, identifier = self._slot_value_and_identifier(point, endpoint) + page.label("Select/deselect period", class_="newevent popup", for_=identifier) + page.div.close() def _day_value_and_identifier(self, day):