def filter_stream (self, req, method, filename, stream, data): if filename not in ('ticket.html', 'query.html'): return stream if filename == 'ticket.html': for xpath in [self._item_to_xpath_t(f) for f in self.single_fields]: stream |= Transformer(xpath).attr('class', self.CLASS) for xpath in [self._item_to_xpath_t(f) for f in self.multiple_fields]: stream |= Transformer(xpath).attr('class', self.CLASS_MULTI) if filename == 'query.html': for xpath in [self._item_to_xpath_q(f) for f in self.single_fields]: stream |= Transformer(xpath).attr('class', self.CLASS) for xpath in [self._item_to_xpath_q(f) for f in self.multiple_fields]: stream |= Transformer(xpath).attr('class', self.CLASS_MULTI) stream |= Transformer('//head').append(tag.style(''' img.autocompluseraccount { vertical-align: middle; } ul.ui-autocomplete li.ui-menu-item span.username { font-size: 0.85em; font-style: italic; color: #888; } ''')) return stream
def _add_style_attributes(self, req, stream): logo = Chrome(self.env).get_logo_data(self.env.abs_href) if logo: height = logo['height'] # self.log.debug("Logo height: %s" % height) if height: style_css = ''; height += 25 style_css += '#mainnav, #ctxtnav, #pagepath {top: %ipx;}' % height height += 50 style_css += '#content, #notice, #warning, #altlinks, #altlinks, #footer {top: %ipx;}' % height style_css = '@media screen { %s }' % style_css style_tag = tag.style(style_css, type="text/css") stream |= Transformer('.//head').append(style_tag) # TODO: get logo-src and finding how big it is return stream
def _parse_params(self): self.metatags = [tag.meta(charset=self.document.settings.output_encoding)] self.stylesheets = [] stylesheets = self.document.settings.stylesheet or [] for href in stylesheets: self.stylesheets.append(tag.link(rel='stylesheet', href=href)) stylesheets_inline = [] for path in (self.document.settings.stylesheet_inline or []): with open(path) as f: stylesheets_inline.append(f.read()) if stylesheets_inline: self.stylesheets.append(tag.style(Markup(''.join(stylesheets_inline)))) self.scripts = [] scripts = self.document.settings.script or [] for src, attributes in scripts: script = tag.script(src=src) if attributes: script = script(**{attributes: attributes}) self.scripts.append(script) return
def filter_stream(self, req, method, filename, stream, data): if filename != "ticket.html" and filename != 'ticket_preview.html': return stream if 'ticket' in data: ticket = data['ticket'] stream |= Transformer('//head').append(tag.style(""" .relation_table { width: 100%; } .relation_table td { border-bottom: dotted 1px #eed; } """)) for relation in self.build_relations().values(): if relation.ticket_type_a == ticket['type']: stream = self._generate_html(relation, relation.relation_type_a, 'a', stream, ticket) elif relation.ticket_type_b == ticket['type']: stream = self._generate_html(relation, relation.relation_type_b, 'b', stream, ticket) return stream
def expand_macro(self, formatter, name, arguments): """Returns macro content.""" env = self.env req = formatter.req tz = req.tz # Parse arguments from macro invocation. args, kwargs = parse_args(arguments, strict=False) # Enable week number display regardless of argument position. week_pref = 'w' in args and args.pop(args.index('w')) week_pref = week_pref and week_pref or kwargs.get('w') week_start = None week_num_start = None # Parse per-instance week calculation rules, if available. if week_pref: if ':' not in week_pref: # Treat undelimitted setting as week start. week_pref += ':' w_start, wn_start = week_pref.split(':') try: week_start = int(w_start) except ValueError: week_start = None else: week_start = week_start > -1 and week_start < 7 and \ week_start or None try: week_num_start = int(wn_start) except ValueError: week_num_start = None else: week_num_start = week_num_start in (1, 4, 7) and \ week_num_start or None # Respect user's locale, if available. try: locale = Locale.parse(str(req.locale)) except (AttributeError, UnknownLocaleError): # Attribute 'req.locale' vailable since Trac 0.12. locale = None if has_babel: if locale: if not locale.territory: # Search first locale, which has the same `language` and # territory in preferred languages. for l in req.languages: l = l.replace('-', '_').lower() if l.startswith(locale.language.lower() + '_'): try: l = Locale.parse(l) if l.territory: locale = l break # first one rules except UnknownLocaleError: pass if not locale.territory and locale.language in LOCALE_ALIASES: locale = Locale.parse(LOCALE_ALIASES[locale.language]) else: # Default fallback. locale = Locale('en', 'US') env.log.debug('Locale setting for wiki calendar: %s' % locale.get_display_name('en')) if not week_start: if week_pref and week_pref.lower().startswith('iso'): week_start = 0 week_num_start = 4 elif has_babel: week_start = locale.first_week_day else: import calendar week_start = calendar.firstweekday() # ISO calendar will remain as default. if not week_num_start: if week_start == 6: week_num_start = 1 else: week_num_start = 4 env.log.debug('Effective settings: first_week_day=%s, ' '1st_week_of_year_rule=%s' % (week_start, week_num_start)) # Find year and month of interest. year = req.args.get('year') # Not clicked on any previous/next button, next look for macro args. if not year and len(args) >= 1 and args[0] != "*": year = args[0] year = year and year.isnumeric() and int(year) or None month = req.args.get('month') # Not clicked on any previous/next button, next look for macro args. if not month and len(args) >= 2 and args[1] != "*": month = args[1] month = month and month.isnumeric() and int(month) or None now = datetime.now(tz) # Force offset from start-of-day to avoid a false 'today' marker, # but use it only on request of different month/year. now.replace(second=1) today = None if (month and month != now.month) or (year and year != now.year): today = now.replace(year=year, month=month, day=1) # Use current month and year, if nothing else has been requested. if not today: today = now.replace(hour=0, minute=0, second=0, microsecond=0) showbuttons = True if len(args) >= 3 or kwargs.has_key('nav'): try: showbuttons = kwargs['nav'] in _TRUE_VALUES except KeyError: showbuttons = args[2] in _TRUE_VALUES wiki_page_format = "%Y-%m-%d" if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'): try: wiki_page_format = str(kwargs['wiki']) except KeyError: wiki_page_format = str(args[3]) # Support relative paths in macro arguments for wiki page links. wiki_page_format = resolve_relative_name(wiki_page_format, formatter.resource.id) list_condense = 0 show_t_open_dates = True wiki_subpages = [] # Read optional check plan. check = [] if kwargs.has_key('check'): check = kwargs['check'].split('.') if name == 'WikiTicketCalendar': if len(args) >= 5 or kwargs.has_key('cdate'): try: show_t_open_dates = kwargs['cdate'] in _TRUE_VALUES except KeyError: show_t_open_dates = args[4] in _TRUE_VALUES # TracQuery support for ticket selection query_args = "id!=0" if len(args) >= 7 or kwargs.has_key('query'): # prefer query arguments provided by kwargs try: query_args = kwargs['query'] except KeyError: query_args = args[6] # compress long ticket lists if len(args) >= 8 or kwargs.has_key('short'): # prefer query arguments provided by kwargs try: list_condense = int(kwargs['short']) except KeyError: list_condense = int(args[7]) # control calendar display width cal_width = "100%;" if len(args) >= 9 or kwargs.has_key('width'): # prefer query arguments provided by kwargs try: cal_width = kwargs['width'] except KeyError: cal_width = args[8] # multiple wiki (sub)pages per day if kwargs.has_key('subpages'): wiki_subpages = kwargs['subpages'].split('|') # Prepare datetime objects for previous/next navigation link creation. prev_year = month_offset(today, -12) prev_quarter = month_offset(today, -3) prev_month = month_offset(today, -1) next_month = month_offset(today, 1) next_quarter = month_offset(today, 3) next_year = month_offset(today, 12) # Find first and last calendar day, probably in last/next month, # using datetime objects exactly at start-of-day here. # Note: Calendar days are numbered 0 (Mo) - 6 (Su). first_day_month = today.replace(day=1, second=0) first_day = first_day_month - timedelta( week_index(first_day_month, week_start)) last_day_month = next_month.replace(day=1) - timedelta(1) if ((last_day_month - first_day).days + 1) % 7 > 0: last_day = last_day_month + timedelta(7 - ( (last_day_month - first_day).days + 1) % 7) else: last_day = last_day_month # Find relevant tickets. if name == 'WikiTicketCalendar': daystr = (uts and '..' or ':').join([ format_datetime(first_day, locale=locale), format_datetime(last_day, locale=locale) ]) provider = WikiCalendarTicketProvider(env) query_args = query_args and query_args + '&' or '' tkt_due = provider.harvest( req, query_args + '='.join([self.tkt_due_field, daystr])) if show_t_open_dates: tkt_new = provider.harvest( req, query_args + '='.join(['created', daystr])) # Finally building the output now. # Begin with caption and optional navigation links. buff = tag.tr() if showbuttons is True: # Create calendar navigation buttons. nx = 'next' pv = 'prev' nav_pv_y = _nav_link(req, '<<', pv, prev_year, locale) nav_pv_q = _nav_link(req, ' «', pv, prev_quarter, locale) nav_pv_m = _nav_link(req, ' <', pv, prev_month, locale) nav_nx_m = _nav_link(req, '> ', nx, next_month, locale) nav_nx_q = _nav_link(req, '» ', nx, next_quarter, locale) nav_nx_y = _nav_link(req, '>>', nx, next_year, locale) # Add buttons for going to previous months and year. buff(nav_pv_y, nav_pv_q, nav_pv_m) # The caption will always be there. if has_babel: heading = tag.td(format_datetime(today, 'MMMM y', locale=locale)) else: heading = tag.td(format_date(today, '%B %Y')) buff = buff(heading(class_='y')) if showbuttons is True: # Add buttons for going to next months and year. buff(nav_nx_m, nav_nx_q, nav_nx_y) buff = tag.caption(tag.table(tag.tbody(buff))) buff = tag.table(buff) if name == 'WikiTicketCalendar': if cal_width.startswith('+') is True: width = ":".join(['min-width', cal_width]) buff(class_='wikitcalendar', style=width) else: buff(class_='wikitcalendar') if name == 'WikiCalendar': buff(class_='wiki-calendar') heading = tag.tr() heading(align='center') if week_pref: # Add an empty cell matching the week number column below. heading(tag.th()) day_names = [(idx, day_name) for idx, day_name in get_day_names( 'abbreviated', 'format', locale).iteritems()] # Read day names after shifting into correct position. for idx, name_ in day_names[week_start:7] + day_names[0:week_start]: col = tag.th(name_) if has_babel: weekend = idx >= locale.weekend_start and \ idx <= locale.weekend_end else: weekend = idx > 4 col(class_=('workday', 'weekend')[weekend], scope='col') heading(col) heading = buff(tag.thead(heading)) # Building main calendar table body buff = tag.tbody() day = first_day while day.date() <= last_day.date(): # Insert a new row for every week. if (day - first_day).days % 7 == 0: line = tag.tr() line(align='right') if week_pref: cell = tag.td( week_num(env, day, week_start, week_num_start)) line(cell(class_='week')) if not (day < first_day_month or day > last_day_month): wiki = format_date(day, wiki_page_format) if day == today: a_class = 'day today' td_class = 'today' else: a_class = 'day' td_class = 'day' if uts: day_ts = to_utimestamp(day) day_ts_eod = day_ts + 86399999999 else: day_ts = to_timestamp(day) day_ts_eod = day_ts + 86399 # Check for milestone(s) on that day. #db = env.get_read_db() #cursor = db.cursor() #cursor.execute(""" # SELECT name # FROM milestone # WHERE due >= %s and due <= %s #""", (day_ts, day_ts_eod)) cursor = self.env.db_query( """ SELECT name FROM milestone WHERE due >= %s and due <= %s """, (day_ts, day_ts_eod)) milestones = tag() for row in cursor: if not a_class.endswith('milestone'): a_class += ' milestone' milestone = to_unicode(row[0]) url = env.href.milestone(milestone) milestone = '* ' + milestone milestones = tag( milestones, tag.div(tag.a(milestone, href=url), class_='milestone')) label = tag.span(day.day) label(class_='day') # Generate wiki page links with name specified in # 'wiki_page_format', and check their existence. if len(wiki_subpages) > 0: pages = tag(label, Markup('<br />')) for page in wiki_subpages: label = tag(' ', page[0]) page = '/'.join([wiki, page]) pages( self._wiki_link(req, args, kwargs, page, label, 'subpage', check)) else: pages = self._wiki_link(req, args, kwargs, wiki, label, a_class, check) cell = tag.td(pages) cell(class_=td_class, valign='top') if name == 'WikiCalendar': line(cell) else: if milestones: cell(milestones) else: cell(tag.br()) match = [] match_od = [] ticket_heap = tag('') ticket_list = tag.div('') ticket_list(align='left', class_='condense') # Get tickets with due date set to day. for t in tkt_due: due = t.get(self.tkt_due_field) if due is None or due in ('', '--'): continue else: if self.tkt_due_format == 'ts': if not isinstance(due, datetime): continue if uts: due_ts = to_utimestamp(due) else: due_ts = to_timestamp(due) if due_ts < day_ts or due_ts > day_ts_eod: continue else: # Beware: Format might even be unicode string, # but str is required by the function. duedate = format_date(day, str(self.tkt_due_format)) if not due == duedate: continue tkt_id = t.get('id') ticket, short = _ticket_links(env, formatter, t) ticket_heap(ticket) if not tkt_id in match: if len(match) == 0: ticket_list(short) else: ticket_list(', ', short) match.append(tkt_id) # Optionally, get tickets created on day too. if show_t_open_dates: ticket_od_list = tag.div('') ticket_od_list(align='left', class_='opendate_condense') for t in tkt_new: if uts: ticket_ts = to_utimestamp(t.get('time')) else: ticket_ts = to_timestamp(t.get('time')) if ticket_ts < day_ts or ticket_ts > day_ts_eod: continue a_class = 'opendate_' tkt_id = t.get('id') ticket, short = _ticket_links( env, formatter, t, a_class) ticket_heap(ticket) if not tkt_id in match: if len(match_od) == 0: ticket_od_list(short) else: ticket_od_list(', ', short) match_od.append(tkt_id) matches = len(match) + len(match_od) if list_condense > 0 and matches >= list_condense: if len(match_od) > 0: if len(match) > 0: ticket_list(', ') ticket_list = tag(ticket_list, ticket_od_list) line(cell(ticket_list)) else: line(cell(ticket_heap)) else: if name == 'WikiCalendar': wiki = format_date(day, wiki_page_format) a_class = 'day adjacent_month' pages = self._wiki_link(req, args, kwargs, wiki, day.day, a_class) cell = tag.td(pages, class_='day adjacent_month') line(cell) else: cell = tag.td('', class_='day adjacent_month') line(cell) # Append completed week rows. if (day - first_day).days % 7 == 6: buff(line) day += timedelta(1) buff = tag.div(heading(buff)) if name == 'WikiTicketCalendar': if cal_width.startswith('+') is True: width = ":".join(['width', cal_width]) buff(class_='wikitcalendar', style=width) else: buff(class_='wikitcalendar') if name == 'WikiCalendar': buff(class_='wiki-calendar') # Add common CSS stylesheet. if self.internal_css and not req.args.get('wikicalendar'): # Put definitions directly into the output. f = open('/'.join([self.htdocs_path, 'wikicalendar.css']), 'Ur') css = tag.style(Markup('<!--\n'), '\n'.join(f.readlines()), Markup('-->\n'))(type="text/css") f.close() # Add hint to prevent multiple inclusions. req.args['wikicalendar'] = True return tag(css, buff) elif not req.args.get('wikicalendar'): add_stylesheet(req, 'wikicalendar/wikicalendar.css') return buff
def expand_macro(self, formatter, name, arguments): self.ref = formatter self.tz_info = formatter.req.tz self.thistime = datetime.datetime.now(self.tz_info) # Parse arguments from macro invocation args, kwargs = parse_args(arguments, strict=False) # Find out whether use http param, current or macro param year/month http_param_year = formatter.req.args.get('year','') http_param_month = formatter.req.args.get('month','') if http_param_year == "": # not clicked on a prev or next button if len(args) >= 1 and args[0] <> "*": # year given in macro parameters year = int(args[0]) else: # use current year year = self.thistime.year else: # year in http params (clicked by user) overrides everything year = int(http_param_year) if http_param_month == "": # not clicked on a prev or next button if len(args) >= 2 and args[1] <> "*": # month given in macro parameters month = int(args[1]) else: # use current month month = self.thistime.month else: # month in http params (clicked by user) overrides everything month = int(http_param_month) showbuttons = True if len(args) >= 3 or kwargs.has_key('nav'): try: showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"] except KeyError: showbuttons = args[2] in ["True", "true", "yes", "1"] wiki_page_format = "%Y-%m-%d" if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'): try: wiki_page_format = str(kwargs['wiki']) except KeyError: wiki_page_format = str(args[3]) # Support relative paths in macro arguments for wiki page links. wiki_page_format = self._resolve_relative_name(wiki_page_format, formatter.resource.id) list_condense = 0 show_t_open_dates = True wiki_page_template = "" wiki_subpages = [] # Read optional check plan. check = [] if kwargs.has_key('check'): check = kwargs['check'].split('.') if name == 'WikiTicketCalendar': if len(args) >= 5 or kwargs.has_key('cdate'): try: show_t_open_dates = kwargs['cdate'] in \ ["True", "true", "yes", "1"] except KeyError: show_t_open_dates = args[4] in \ ["True", "true", "yes", "1"] # Optional page template to create new wiki pages. # The default (empty page) is used, if the template name is invalid. if len(args) >= 6 or kwargs.has_key('base'): try: wiki_page_template = kwargs['base'] except KeyError: wiki_page_template = args[5] if name == 'WikiTicketCalendar': # TracQuery support for ticket selection query_args = "id!=0" if len(args) >= 7 or kwargs.has_key('query'): # prefer query arguments provided by kwargs try: query_args = kwargs['query'] except KeyError: query_args = args[6] tickets = WikiCalendarTicketProvider(self.env) self.tickets = tickets.harvest(formatter.req, query_args) # compress long ticket lists if len(args) >= 8 or kwargs.has_key('short'): # prefer query arguments provided by kwargs try: list_condense = int(kwargs['short']) except KeyError: list_condense = int(args[7]) # control calendar display width cal_width = "100%;" if len(args) >= 9 or kwargs.has_key('width'): # prefer query arguments provided by kwargs try: cal_width = kwargs['width'] except KeyError: cal_width = args[8] # multiple wiki (sub)pages per day if kwargs.has_key('subpages'): wiki_subpages = kwargs['subpages'].split('|') # Can use this to change the day the week starts on, # but this is a system-wide setting. calendar.setfirstweekday(calendar.MONDAY) cal = calendar.monthcalendar(year, month) curr_day = None if year == self.thistime.year and month == self.thistime.month: curr_day = self.thistime.day # for prev/next navigation links prevMonth = month - 1 nextMonth = month + 1 nextYear = prevYear = year # check for year change (KISS version) if prevMonth == 0: prevMonth = 12 prevYear -= 1 if nextMonth == 13: nextMonth = 1 nextYear += 1 # for fast-forward/-rewind navigation links ffYear = frYear = year if month < 4: frMonth = month + 9 frYear -= 1 else: frMonth = month - 3 if month > 9: ffMonth = month - 9 ffYear += 1 else: ffMonth = month + 3 last_week_prevMonth = calendar.monthcalendar(prevYear, prevMonth)[-1] first_week_nextMonth = calendar.monthcalendar(nextYear, nextMonth)[0] # Switch to user's locale, if available. try: loc_req = str(formatter.req.locale) except AttributeError: # Available since in Trac 0.12 . loc_req = None if loc_req: loc = locale.getlocale() loc_prop = locale.normalize(loc_req) try: locale.setlocale(locale.LC_TIME, loc_prop) except locale.Error: try: # Re-try with UTF-8 as last resort. loc_prop = '.'.join([loc_prop.split('.')[0],'utf8']) locale.setlocale(locale.LC_TIME, loc_prop) except locale.Error: loc_prop = None self.env.log.debug('Locale setting for calendar: ' + str(loc_prop)) # Finally building the output # Begin with caption and optional navigation links buff = tag.tr() if showbuttons is True: # calendar navigation buttons nx = 'next' pv = 'prev' nav_pvY = self._mknav('<<', pv, month, year-1) nav_frM = self._mknav(' <', pv, frMonth, frYear) nav_pvM = self._mknav(' «', pv, prevMonth, prevYear) nav_nxM = self._mknav('» ', nx, nextMonth, nextYear) nav_ffM = self._mknav('> ', nx, ffMonth, ffYear) nav_nxY = self._mknav('>>', nx, month, year+1) # add buttons for going to previous months and year buff(nav_pvY, nav_frM, nav_pvM) # The caption will always be there. heading = tag.td( to_unicode(format_date(self._mkdatetime(year, month), '%B %Y'))) buff = buff(heading(class_='y')) if showbuttons is True: # add buttons for going to next months and year buff(nav_nxM, nav_ffM, nav_nxY) buff = tag.caption(tag.table(tag.tbody(buff))) buff = tag.table(buff) if name == 'WikiTicketCalendar': if cal_width.startswith('+') is True: width=":".join(['min-width', cal_width]) buff(class_='wikitcalendar', style=width) else: buff(class_='wikitcalendar') if name == 'WikiCalendar': buff(class_='wiki-calendar') heading = tag.tr() heading(align='center') for day in calendar.weekheader(2).split()[:-2]: col = tag.th(to_unicode(day)) col(class_='workday', scope='col') heading(col) for day in calendar.weekheader(2).split()[-2:]: col = tag.th(to_unicode(day)) col(class_='weekend', scope='col') heading(col) heading = buff(tag.thead(heading)) # Building main calendar table body buff = tag.tbody() w = -1 for week in cal: w = w + 1 line = tag.tr() line(align='right') d = -1 for day in week: d = d + 1 if day: # check for wikipage with name specified in # 'wiki_page_format' wiki = format_date(self._mkdatetime(year, month, day), wiki_page_format) if day == curr_day: a_class = 'day today' td_class = 'today' else: a_class = 'day' td_class = 'day' day_dt = self._mkdatetime(year, month, day) if uts: day_ts = to_utimestamp(day_dt) day_ts_eod = day_ts + 86399999999 else: day_ts = to_timestamp(day_dt) day_ts_eod = day_ts + 86399 # check for milestone(s) on that day db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(""" SELECT name FROM milestone WHERE due >= %s and due <= %s """, (day_ts, day_ts_eod)) milestones = tag() for row in cursor: if not a_class.endswith('milestone'): a_class += ' milestone' milestone = to_unicode(row[0]) url = self.env.href.milestone(milestone) milestone = '* ' + milestone milestones = tag(milestones, tag.div(tag.a(milestone, href=url), class_='milestone')) day = tag.span(day) day(class_='day') if len(wiki_subpages) > 0: pages = tag(day, Markup('<br />')) for page in wiki_subpages: label = tag(' ', page[0]) page = '/'.join([wiki, page]) url = self.env.href.wiki(page) pages(self._gen_wiki_links(page, label, 'subpage', url, wiki_page_template, check)) else: url = self.env.href.wiki(wiki) pages = self._gen_wiki_links(wiki, day, a_class, url, wiki_page_template, check) cell = tag.td(pages) cell(class_=td_class, valign='top') if name == 'WikiCalendar': line(cell) else: if milestones: cell(milestones) else: cell(tag.br()) match = [] match_od = [] ticket_heap = tag('') ticket_list = tag.div('') ticket_list(align='left', class_='condense') # get tickets with due date set to day for t in self.tickets: due = t.get(self.tkt_due_field) if due is None or due in ['', '--']: continue else: if self.tkt_due_format == 'ts': if not isinstance(due, datetime.datetime): continue if uts: due_ts = to_utimestamp(due) else: due_ts = to_timestamp(due) if due_ts < day_ts or due_ts > day_ts_eod: continue else: # Beware: Format might even be unicode str duedate = format_date(day_dt, str(self.tkt_due_format)) if not due == duedate: continue id = t.get('id') ticket, short = self._gen_ticket_entry(t) ticket_heap(ticket) if not id in match: if len(match) == 0: ticket_list(short) else: ticket_list(', ', short) match.append(id) # optionally get tickets created on day if show_t_open_dates is True: ticket_od_list = tag.div('') ticket_od_list(align='left', class_='opendate_condense') for t in self.tickets: if uts: ticket_ts = to_utimestamp(t.get('time')) else: ticket_ts = to_timestamp(t.get('time')) if ticket_ts < day_ts or \ ticket_ts > day_ts_eod: continue a_class = 'opendate_' id = t.get('id') ticket, short = self._gen_ticket_entry(t, a_class) ticket_heap(ticket) if not id in match: if len(match_od) == 0: ticket_od_list(short) else: ticket_od_list(', ', short) match_od.append(id) matches = len(match) + len(match_od) if list_condense > 0 and matches >= list_condense: if len(match_od) > 0: if len(match) > 0: ticket_list(', ') ticket_list = tag(ticket_list, ticket_od_list) line(cell(ticket_list)) else: line(cell(ticket_heap)) else: if name == 'WikiCalendar': if w == 0: day = last_week_prevMonth[d] wiki = format_date(self._mkdatetime( prevYear, prevMonth, day), wiki_page_format) else: day = first_week_nextMonth[d] wiki = format_date(self._mkdatetime( nextYear, nextMonth, day), wiki_page_format) url = self.env.href.wiki(wiki) a_class = 'day adjacent_month' pages = self._gen_wiki_links(wiki, day, a_class, url, wiki_page_template) cell = tag.td(pages) cell(class_='day adjacent_month') line(cell) else: cell = tag.td('') cell(class_='day adjacent_month') line(cell) buff(line) if loc_req and loc_prop: # We may have switched to users locale, resetting now. try: locale.setlocale(locale.LC_ALL, loc) self.env.log.debug('Locale setting restored: ' + str(loc)) except locale.Error: pass buff = tag.div(heading(buff)) if name == 'WikiTicketCalendar': if cal_width.startswith('+') is True: width=":".join(['width', cal_width]) buff(class_='wikitcalendar', style=width) else: buff(class_='wikitcalendar') if name == 'WikiCalendar': buff(class_='wiki-calendar') # Add common CSS stylesheet if self.internal_css and not self.ref.req.args.get('wikicalendar'): # Put definitions directly into the output. f = open('/'.join([self.htdocs_path, 'wikicalendar.css']), 'Ur') css = tag.style(Markup('<!--\n'), '\n'.join(f.readlines()), Markup('-->\n'))(type="text/css") f.close() # Add hint to prevent multiple inclusions. self.ref.req.args['wikicalendar'] = True return tag(css, buff) elif not self.ref.req.args.get('wikicalendar'): add_stylesheet(self.ref.req, 'wikicalendar/wikicalendar.css') return buff
def expand_macro(self, formatter, name, arguments): self.ref = formatter self.tz_info = formatter.req.tz self.thistime = datetime.datetime.now(self.tz_info) # Parse arguments from macro invocation args, kwargs = parse_args(arguments, strict=False) # Find out whether use http param, current or macro param year/month http_param_year = formatter.req.args.get('year', '') http_param_month = formatter.req.args.get('month', '') if http_param_year == "": # not clicked on a prev or next button if len(args) >= 1 and args[0] <> "*": # year given in macro parameters year = int(args[0]) else: # use current year year = self.thistime.year else: # year in http params (clicked by user) overrides everything year = int(http_param_year) if http_param_month == "": # not clicked on a prev or next button if len(args) >= 2 and args[1] <> "*": # month given in macro parameters month = int(args[1]) else: # use current month month = self.thistime.month else: # month in http params (clicked by user) overrides everything month = int(http_param_month) showbuttons = True if len(args) >= 3 or kwargs.has_key('nav'): try: showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"] except KeyError: showbuttons = args[2] in ["True", "true", "yes", "1"] wiki_page_format = "%Y-%m-%d" if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'): try: wiki_page_format = str(kwargs['wiki']) except KeyError: wiki_page_format = str(args[3]) show_t_open_dates = True if len(args) >= 5 or kwargs.has_key('cdate'): try: show_t_open_dates = kwargs['cdate'] in \ ["True", "true", "yes", "1"] except KeyError: show_t_open_dates = args[4] in ["True", "true", "yes", "1"] # template name tried to create new pages # optional, default (empty page) is used, if name is invalid wiki_page_template = "" if len(args) >= 6 or kwargs.has_key('base'): try: wiki_page_template = kwargs['base'] except KeyError: wiki_page_template = args[5] # TracQuery support for ticket selection query_args = "id!=0" if len(args) >= 7 or kwargs.has_key('query'): # prefer query arguments provided by kwargs try: query_args = kwargs['query'] except KeyError: query_args = args[6] self.tickets = self._ticket_query(formatter, query_args) # compress long ticket lists list_condense = 0 if len(args) >= 8 or kwargs.has_key('short'): # prefer query arguments provided by kwargs try: list_condense = int(kwargs['short']) except KeyError: list_condense = int(args[7]) # control calendar display width cal_width = "100%;" if len(args) >= 9 or kwargs.has_key('width'): # prefer query arguments provided by kwargs try: cal_width = kwargs['width'] except KeyError: cal_width = args[8] # Can use this to change the day the week starts on, # but this is a system-wide setting. calendar.setfirstweekday(calendar.MONDAY) cal = calendar.monthcalendar(year, month) curr_day = None if year == self.thistime.year and month == self.thistime.month: curr_day = self.thistime.day # Compile regex pattern before use for better performance pattern_del = '(?:<span .*?>)|(?:</span>)' pattern_del += '|(?:<p>)|(?:<p .*?>)|(?:</p>)' pattern_del += '|(?:</table>)|(?:<td.*?\n)|(?:<tr.*?</tr>)' self.end_RE = re.compile('(?:</a>)') self.del_RE = re.compile(pattern_del) self.item_RE = re.compile('(?:<img .*?>)') self.open_RE = re.compile('(?:<a .*?>)') self.tab_RE = re.compile('(?:<table .*?>)') # for prev/next navigation links prevMonth = month - 1 nextMonth = month + 1 nextYear = prevYear = year # check for year change (KISS version) if prevMonth == 0: prevMonth = 12 prevYear -= 1 if nextMonth == 13: nextMonth = 1 nextYear += 1 # for fast-forward/-rewind navigation links ffYear = frYear = year if month < 4: frMonth = month + 9 frYear -= 1 else: frMonth = month - 3 if month > 9: ffMonth = month - 9 ffYear += 1 else: ffMonth = month + 3 # Finally building the output # Prepending inline CSS definitions styles = """ \ <!-- table.wikiTicketCalendar th { font-weight: bold; } table.wikiTicketCalendar th.workday { width: 17%; } table.wikiTicketCalendar th.weekend { width: 7%; } table.wikiTicketCalendar caption { font-size: 120%; white-space: nowrap; } table.wikiTicketCalendar caption a { display: inline; margin: 0; border: 0; padding: 0; background-color: transparent; color: #b00; text-decoration: none; } table.wikiTicketCalendar caption a.prev { padding-right: 5px; font: bold; } table.wikiTicketCalendar caption a.next { padding-left: 5px; font: bold; } table.wikiTicketCalendar caption a:hover { background-color: #eee; } table.wikiTicketCalendar td.today { background: #fbfbfb; border-color: #444444; color: #444; border-style: solid; border-width: 1px; } table.wikiTicketCalendar td.day { background: #e5e5e5; border-color: #444444; color: #333; border-style: solid; border-width: 1px; } table.wikiTicketCalendar td.fill { background: #eee; border-color: #ccc; border-style: solid; border-width: 1px; } table.wikiTicketCalendar div.milestone { font-size: 9px; background: #f7f7f0; border: 1px solid #d7d7d7; border-bottom-color: #999; text-align: left; } table.wikiTicketCalendar a.day { width: 2em; height: 100%; margin: 0; border: 0px; padding: 0; color: #333; text-decoration: none; } table.wikiTicketCalendar a.day_haspage { width: 2em; height: 100%; margin: 0; border: 0px; padding: 0; color: #b00 !important; text-decoration: none; } table.wikiTicketCalendar a.day:hover { border-color: #eee; background-color: #eee; color: #000; } table.wikiTicketCalendar div.open, span.open { font-size: 9px; color: #000000; } table.wikiTicketCalendar div.closed, span.closed { font-size: 9px; color: #777777; text-decoration: line-through; } table.wikiTicketCalendar div.opendate_open, span.opendate_open { font-size: 9px; color: #000077; } table.wikiTicketCalendar div.opendate_closed, span.opendate_closed { font-size: 9px; color: #000077; text-decoration: line-through; } table.wikiTicketCalendar div.condense { background-color: #e5e5e5; } table.wikiTicketCalendar div.opendate_condense { background-color: #cdcdfa; } /* pure CSS style tooltip */ a.tip { position: relative; cursor: help; } a.tip span { display: none; } a.tip:hover span { display: block; z-index: 1; font-size: 0.75em; text-decoration: none; /* big left move because of z-index render bug in IE<8 */ position: absolute; top: 0.8em; left: 6em; border: 1px solid #000; background-color: #fff; padding: 5px; } --> """ # create inline style definition as Genshi fragment styles = tag.style(Markup(styles)) styles(type='text/css') # Build caption and optional navigation links buff = tag.caption() if showbuttons is True: # calendar navigation buttons nx = 'next' pv = 'prev' nav_pvY = self._mknav(' <<', pv, month, year - 1) nav_frM = self._mknav(' < ', pv, frMonth, frYear) nav_pvM = self._mknav(' « ', pv, prevMonth, prevYear) nav_nxM = self._mknav(' » ', nx, nextMonth, nextYear) nav_ffM = self._mknav(' > ', nx, ffMonth, ffYear) nav_nxY = self._mknav(' >>', nx, month, year + 1) # add buttons for going to previous months and year buff(nav_pvY, nav_frM, nav_pvM) # The caption will always be there. buff( tag.strong( to_unicode(format_date(self._mkdatetime(year, month), '%B %Y')))) if showbuttons is True: # add buttons for going to next months and year buff(nav_nxM, nav_ffM, nav_nxY) buff = tag.table(buff) width = ":".join(['min-width', cal_width]) buff(class_='wikiTicketCalendar', style=width) heading = tag.tr() heading(align='center') for day in calendar.weekheader(2).split()[:-2]: col = tag.th(day) col(class_='workday', scope='col') heading(col) for day in calendar.weekheader(2).split()[-2:]: col = tag.th(day) col(class_='weekend', scope='col') heading(col) heading = buff(tag.thead(heading)) # Building main calendar table body buff = tag.tbody() for row in cal: line = tag.tr() line(align='right') for day in row: if not day: cell = tag.td('') cell(class_='fill') line(cell) else: # check for wikipage with name specified in # 'wiki_page_format' wiki = format_date(self._mkdatetime(year, month, day), wiki_page_format) url = self.env.href.wiki(wiki) if WikiSystem(self.env).has_page(wiki): a_class = "day_haspage" title = "Go to page %s" % wiki else: a_class = "day" url += "?action=edit" # adding template name, if specified if wiki_page_template != "": url += "&template=" + wiki_page_template title = "Create page %s" % wiki if day == curr_day: td_class = 'today' else: td_class = 'day' cell = tag.a(tag.b(day), href=url) cell(class_=a_class, title_=title) cell = tag.td(cell) cell(class_=td_class, valign='top') day_dt = self._mkdatetime(year, month, day) if uts: day_ts = to_utimestamp(day_dt) day_ts_eod = day_ts + 86399999999 else: day_ts = to_timestamp(day_dt) day_ts_eod = day_ts + 86399 # check for milestone(s) on that day db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute( """ SELECT name FROM milestone WHERE due >= %s and due <= %s """, (day_ts, day_ts_eod)) while (1): row = cursor.fetchone() if row is None: cell(tag.br()) break else: name = to_unicode(row[0]) url = self.env.href.milestone(name) milestone = '* ' + name milestone = tag.div(tag.a(milestone, href=url)) milestone(class_='milestone') cell(milestone) match = [] match_od = [] ticket_heap = tag('') ticket_list = tag.div('') ticket_list(align='left', class_='condense') # get tickets with due date set to day for t in self.tickets: due = t.get(self.due_field_name) if due is None or due in ['', '--']: continue else: if self.due_field_fmt == 'ts': if not isinstance(due, datetime.datetime): continue else: if uts: due_ts = to_utimestamp(due) else: due_ts = to_timestamp(due) if due_ts < day_ts or \ due_ts > day_ts_eod: continue else: duedate = format_date(day_dt, self.due_field_fmt) if not due == duedate: continue id = t.get('id') ticket, short = self._gen_ticket_entry(t) ticket_heap(ticket) if not id in match: if len(match) == 0: ticket_list(short) else: ticket_list(', ', short) match.append(id) # optionally get tickets created on day if show_t_open_dates is True: ticket_od_list = tag.div('') ticket_od_list(align='left', class_='opendate_condense') for t in self.tickets: if uts: ticket_ts = to_utimestamp(t.get('time')) else: ticket_ts = to_timestamp(t.get('time')) if ticket_ts < day_ts or ticket_ts > day_ts_eod: continue a_class = 'opendate_' id = t.get('id') ticket, short = self._gen_ticket_entry(t, a_class) ticket_heap(ticket) if not id in match: if len(match_od) == 0: ticket_od_list(short) else: ticket_od_list(', ', short) match_od.append(id) matches = len(match) + len(match_od) if list_condense > 0 and matches >= list_condense: if len(match_od) > 0: if len(match) > 0: ticket_list(', ') ticket_list = tag(ticket_list, ticket_od_list) line(cell(ticket_list)) else: line(cell(ticket_heap)) buff(line) buff = tag.div(heading(buff)) if cal_width.startswith('+') is True: width = ":".join(['width', cal_width]) buff(class_='wikiTicketCalendar', style=width) else: buff(class_='wikiTicketCalendar') # Finally prepend prepared CSS styles buff = tag(styles, buff) return buff
def expand_macro(self, formatter, name, arguments): self.ref = formatter self.tz_info = formatter.req.tz self.thistime = datetime.datetime.now(self.tz_info) # Parse arguments from macro invocation args, kwargs = parse_args(arguments, strict=False) # Find out whether use http param, current or macro param year/month http_param_year = formatter.req.args.get('year','') http_param_month = formatter.req.args.get('month','') if http_param_year == "": # not clicked on a prev or next button if len(args) >= 1 and args[0] <> "*": # year given in macro parameters year = int(args[0]) else: # use current year year = self.thistime.year else: # year in http params (clicked by user) overrides everything year = int(http_param_year) if http_param_month == "": # not clicked on a prev or next button if len(args) >= 2 and args[1] <> "*": # month given in macro parameters month = int(args[1]) else: # use current month month = self.thistime.month else: # month in http params (clicked by user) overrides everything month = int(http_param_month) showbuttons = True if len(args) >= 3 or kwargs.has_key('nav'): try: showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"] except KeyError: showbuttons = args[2] in ["True", "true", "yes", "1"] wiki_page_format = "%Y-%m-%d" if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'): try: wiki_page_format = str(kwargs['wiki']) except KeyError: wiki_page_format = str(args[3]) show_t_open_dates = True if len(args) >= 5 or kwargs.has_key('cdate'): try: show_t_open_dates = kwargs['cdate'] in \ ["True", "true", "yes", "1"] except KeyError: show_t_open_dates = args[4] in ["True", "true", "yes", "1"] # template name tried to create new pages # optional, default (empty page) is used, if name is invalid wiki_page_template = "" if len(args) >= 6 or kwargs.has_key('base'): try: wiki_page_template = kwargs['base'] except KeyError: wiki_page_template = args[5] # TracQuery support for ticket selection query_args = "id!=0" if len(args) >= 7 or kwargs.has_key('query'): # prefer query arguments provided by kwargs try: query_args = kwargs['query'] except KeyError: query_args = args[6] self.tickets = self._ticket_query(formatter, query_args) # compress long ticket lists list_condense = 0 if len(args) >= 8 or kwargs.has_key('short'): # prefer query arguments provided by kwargs try: list_condense = int(kwargs['short']) except KeyError: list_condense = int(args[7]) # control calendar display width cal_width = "100%;" if len(args) >= 9 or kwargs.has_key('width'): # prefer query arguments provided by kwargs try: cal_width = kwargs['width'] except KeyError: cal_width = args[8] # Can use this to change the day the week starts on, # but this is a system-wide setting. calendar.setfirstweekday(calendar.MONDAY) cal = calendar.monthcalendar(year, month) curr_day = None if year == self.thistime.year and month == self.thistime.month: curr_day = self.thistime.day # Compile regex pattern before use for better performance pattern_del = '(?:<span .*?>)|(?:</span>)' pattern_del += '|(?:<p>)|(?:<p .*?>)|(?:</p>)' pattern_del += '|(?:</table>)|(?:<td.*?\n)|(?:<tr.*?</tr>)' self.end_RE = re.compile('(?:</a>)') self.del_RE = re.compile(pattern_del) self.item_RE = re.compile('(?:<img .*?>)') self.open_RE = re.compile('(?:<a .*?>)') self.tab_RE = re.compile('(?:<table .*?>)') # for prev/next navigation links prevMonth = month - 1 nextMonth = month + 1 nextYear = prevYear = year # check for year change (KISS version) if prevMonth == 0: prevMonth = 12 prevYear -= 1 if nextMonth == 13: nextMonth = 1 nextYear += 1 # for fast-forward/-rewind navigation links ffYear = frYear = year if month < 4: frMonth = month + 9 frYear -= 1 else: frMonth = month - 3 if month > 9: ffMonth = month - 9 ffYear += 1 else: ffMonth = month + 3 # Finally building the output # Prepending inline CSS definitions styles = """ \ <!-- table.wikiTicketCalendar th { font-weight: bold; } table.wikiTicketCalendar th.workday { width: 17%; } table.wikiTicketCalendar th.weekend { width: 7%; } table.wikiTicketCalendar caption { font-size: 120%; white-space: nowrap; } table.wikiTicketCalendar caption a { display: inline; margin: 0; border: 0; padding: 0; background-color: transparent; color: #b00; text-decoration: none; } table.wikiTicketCalendar caption a.prev { padding-right: 5px; font: bold; } table.wikiTicketCalendar caption a.next { padding-left: 5px; font: bold; } table.wikiTicketCalendar caption a:hover { background-color: #eee; } table.wikiTicketCalendar td.today { background: #fbfbfb; border-color: #444444; color: #444; border-style: solid; border-width: 1px; } table.wikiTicketCalendar td.day { background: #e5e5e5; border-color: #444444; color: #333; border-style: solid; border-width: 1px; } table.wikiTicketCalendar td.fill { background: #eee; border-color: #ccc; border-style: solid; border-width: 1px; } table.wikiTicketCalendar div.milestone { font-size: 9px; background: #f7f7f0; border: 1px solid #d7d7d7; border-bottom-color: #999; text-align: left; } table.wikiTicketCalendar a.day { width: 2em; height: 100%; margin: 0; border: 0px; padding: 0; color: #333; text-decoration: none; } table.wikiTicketCalendar a.day_haspage { width: 2em; height: 100%; margin: 0; border: 0px; padding: 0; color: #b00 !important; text-decoration: none; } table.wikiTicketCalendar a.day:hover { border-color: #eee; background-color: #eee; color: #000; } table.wikiTicketCalendar div.open, span.open { font-size: 9px; color: #000000; } table.wikiTicketCalendar div.closed, span.closed { font-size: 9px; color: #777777; text-decoration: line-through; } table.wikiTicketCalendar div.opendate_open, span.opendate_open { font-size: 9px; color: #000077; } table.wikiTicketCalendar div.opendate_closed, span.opendate_closed { font-size: 9px; color: #000077; text-decoration: line-through; } table.wikiTicketCalendar div.condense { background-color: #e5e5e5; } table.wikiTicketCalendar div.opendate_condense { background-color: #cdcdfa; } /* pure CSS style tooltip */ a.tip { position: relative; cursor: help; } a.tip span { display: none; } a.tip:hover span { display: block; z-index: 1; font-size: 0.75em; text-decoration: none; /* big left move because of z-index render bug in IE<8 */ position: absolute; top: 0.8em; left: 6em; border: 1px solid #000; background-color: #fff; padding: 5px; } --> """ # create inline style definition as Genshi fragment styles = tag.style(Markup(styles)) styles(type='text/css') # Build caption and optional navigation links buff = tag.caption() if showbuttons is True: # calendar navigation buttons nx = 'next' pv = 'prev' nav_pvY = self._mknav(' <<', pv, month, year-1) nav_frM = self._mknav(' < ', pv, frMonth, frYear) nav_pvM = self._mknav(' « ', pv, prevMonth, prevYear) nav_nxM = self._mknav(' » ', nx, nextMonth, nextYear) nav_ffM = self._mknav(' > ', nx, ffMonth, ffYear) nav_nxY = self._mknav(' >>', nx, month, year+1) # add buttons for going to previous months and year buff(nav_pvY, nav_frM, nav_pvM) # The caption will always be there. buff(tag.strong(to_unicode(format_date(self._mkdatetime( year, month), '%B %Y')))) if showbuttons is True: # add buttons for going to next months and year buff(nav_nxM, nav_ffM, nav_nxY) buff = tag.table(buff) width=":".join(['min-width', cal_width]) buff(class_='wikiTicketCalendar', style=width) heading = tag.tr() heading(align='center') for day in calendar.weekheader(2).split()[:-2]: col = tag.th(day) col(class_='workday', scope='col') heading(col) for day in calendar.weekheader(2).split()[-2:]: col = tag.th(day) col(class_='weekend', scope='col') heading(col) heading = buff(tag.thead(heading)) # Building main calendar table body buff = tag.tbody() for row in cal: line = tag.tr() line(align='right') for day in row: if not day: cell = tag.td('') cell(class_='fill') line(cell) else: # check for wikipage with name specified in # 'wiki_page_format' wiki = format_date(self._mkdatetime(year, month, day), wiki_page_format) url = self.env.href.wiki(wiki) if WikiSystem(self.env).has_page(wiki): a_class = "day_haspage" title = "Go to page %s" % wiki else: a_class = "day" url += "?action=edit" # adding template name, if specified if wiki_page_template != "": url += "&template=" + wiki_page_template title = "Create page %s" % wiki if day == curr_day: td_class = 'today' else: td_class = 'day' cell = tag.a(tag.b(day), href=url) cell(class_=a_class, title_=title) cell = tag.td(cell) cell(class_=td_class, valign='top') day_dt = self._mkdatetime(year, month, day) if uts: day_ts = to_utimestamp(day_dt) day_ts_eod = day_ts + 86399999999 else: day_ts = to_timestamp(day_dt) day_ts_eod = day_ts + 86399 # check for milestone(s) on that day db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute(""" SELECT name FROM milestone WHERE due >= %s and due <= %s """, (day_ts, day_ts_eod)) while (1): row = cursor.fetchone() if row is None: cell(tag.br()) break else: name = to_unicode(row[0]) url = self.env.href.milestone(name) milestone = '* ' + name milestone = tag.div(tag.a(milestone, href=url)) milestone(class_='milestone') cell(milestone) match = [] match_od = [] ticket_heap = tag('') ticket_list = tag.div('') ticket_list(align='left', class_='condense') # get tickets with due date set to day for t in self.tickets: due = t.get(self.due_field_name) if due is None or due in ['', '--']: continue else: if self.due_field_fmt == 'ts': if not isinstance(due, datetime.datetime): continue else: if uts: due_ts = to_utimestamp(due) else: due_ts = to_timestamp(due) if due_ts < day_ts or \ due_ts > day_ts_eod: continue else: duedate = format_date(day_dt, self.due_field_fmt) if not due == duedate: continue id = t.get('id') ticket, short = self._gen_ticket_entry(t) ticket_heap(ticket) if not id in match: if len(match) == 0: ticket_list(short) else: ticket_list(', ', short) match.append(id) # optionally get tickets created on day if show_t_open_dates is True: ticket_od_list = tag.div('') ticket_od_list(align='left', class_='opendate_condense') for t in self.tickets: if uts: ticket_ts = to_utimestamp(t.get('time')) else: ticket_ts = to_timestamp(t.get('time')) if ticket_ts < day_ts or ticket_ts > day_ts_eod: continue a_class = 'opendate_' id = t.get('id') ticket, short = self._gen_ticket_entry(t, a_class) ticket_heap(ticket) if not id in match: if len(match_od) == 0: ticket_od_list(short) else: ticket_od_list(', ', short) match_od.append(id) matches = len(match) + len(match_od) if list_condense > 0 and matches >= list_condense: if len(match_od) > 0: if len(match) > 0: ticket_list(', ') ticket_list = tag(ticket_list, ticket_od_list) line(cell(ticket_list)) else: line(cell(ticket_heap)) buff(line) buff = tag.div(heading(buff)) if cal_width.startswith('+') is True: width=":".join(['width', cal_width]) buff(class_='wikiTicketCalendar', style=width) else: buff(class_='wikiTicketCalendar') # Finally prepend prepared CSS styles buff = tag(styles, buff) return buff
def expand_macro(self, formatter, name, arguments): self.ref = formatter self.tz_info = formatter.req.tz self.thistime = datetime.datetime.now(self.tz_info) # Parse arguments from macro invocation args, kwargs = parse_args(arguments, strict=False) # Find out whether use http param, current or macro param year/month http_param_year = formatter.req.args.get('year', '') http_param_month = formatter.req.args.get('month', '') if http_param_year == "": # not clicked on a prev or next button if len(args) >= 1 and args[0] <> "*": # year given in macro parameters year = int(args[0]) else: # use current year year = self.thistime.year else: # year in http params (clicked by user) overrides everything year = int(http_param_year) if http_param_month == "": # not clicked on a prev or next button if len(args) >= 2 and args[1] <> "*": # month given in macro parameters month = int(args[1]) else: # use current month month = self.thistime.month else: # month in http params (clicked by user) overrides everything month = int(http_param_month) showbuttons = True if len(args) >= 3 or kwargs.has_key('nav'): try: showbuttons = kwargs['nav'] in ["True", "true", "yes", "1"] except KeyError: showbuttons = args[2] in ["True", "true", "yes", "1"] wiki_page_format = "%Y-%m-%d" if len(args) >= 4 and args[3] != "*" or kwargs.has_key('wiki'): try: wiki_page_format = str(kwargs['wiki']) except KeyError: wiki_page_format = str(args[3]) # Support relative paths in macro arguments for wiki page links. wiki_page_format = self._resolve_relative_name(wiki_page_format, formatter.resource.id) list_condense = 0 show_t_open_dates = True wiki_page_template = "" wiki_subpages = [] # Read optional check plan. check = [] if kwargs.has_key('check'): check = kwargs['check'].split('.') if name == 'WikiTicketCalendar': if len(args) >= 5 or kwargs.has_key('cdate'): try: show_t_open_dates = kwargs['cdate'] in \ ["True", "true", "yes", "1"] except KeyError: show_t_open_dates = args[4] in \ ["True", "true", "yes", "1"] # Optional page template to create new wiki pages. # The default (empty page) is used, if the template name is invalid. if len(args) >= 6 or kwargs.has_key('base'): try: wiki_page_template = kwargs['base'] except KeyError: wiki_page_template = args[5] if name == 'WikiTicketCalendar': # TracQuery support for ticket selection query_args = "id!=0" if len(args) >= 7 or kwargs.has_key('query'): # prefer query arguments provided by kwargs try: query_args = kwargs['query'] except KeyError: query_args = args[6] tickets = WikiCalendarTicketProvider(self.env) self.tickets = tickets.harvest(formatter.req, query_args) # compress long ticket lists if len(args) >= 8 or kwargs.has_key('short'): # prefer query arguments provided by kwargs try: list_condense = int(kwargs['short']) except KeyError: list_condense = int(args[7]) # control calendar display width cal_width = "100%;" if len(args) >= 9 or kwargs.has_key('width'): # prefer query arguments provided by kwargs try: cal_width = kwargs['width'] except KeyError: cal_width = args[8] # multiple wiki (sub)pages per day if kwargs.has_key('subpages'): wiki_subpages = kwargs['subpages'].split('|') # Can use this to change the day the week starts on, # but this is a system-wide setting. calendar.setfirstweekday(calendar.MONDAY) cal = calendar.monthcalendar(year, month) curr_day = None if year == self.thistime.year and month == self.thistime.month: curr_day = self.thistime.day # for prev/next navigation links prevMonth = month - 1 nextMonth = month + 1 nextYear = prevYear = year # check for year change (KISS version) if prevMonth == 0: prevMonth = 12 prevYear -= 1 if nextMonth == 13: nextMonth = 1 nextYear += 1 # for fast-forward/-rewind navigation links ffYear = frYear = year if month < 4: frMonth = month + 9 frYear -= 1 else: frMonth = month - 3 if month > 9: ffMonth = month - 9 ffYear += 1 else: ffMonth = month + 3 last_week_prevMonth = calendar.monthcalendar(prevYear, prevMonth)[-1] first_week_nextMonth = calendar.monthcalendar(nextYear, nextMonth)[0] # Switch to user's locale, if available. try: loc_req = str(formatter.req.locale) except AttributeError: # Available since in Trac 0.12 . loc_req = None if loc_req: loc = locale.getlocale() loc_prop = locale.normalize(loc_req) try: locale.setlocale(locale.LC_TIME, loc_prop) except locale.Error: try: # Re-try with UTF-8 as last resort. loc_prop = '.'.join([loc_prop.split('.')[0], 'utf8']) locale.setlocale(locale.LC_TIME, loc_prop) except locale.Error: loc_prop = None self.env.log.debug('Locale setting for calendar: ' + str(loc_prop)) # Finally building the output # Begin with caption and optional navigation links buff = tag.tr() if showbuttons is True: # calendar navigation buttons nx = 'next' pv = 'prev' nav_pvY = self._mknav('<<', pv, month, year - 1) nav_frM = self._mknav(' <', pv, frMonth, frYear) nav_pvM = self._mknav(' «', pv, prevMonth, prevYear) nav_nxM = self._mknav('» ', nx, nextMonth, nextYear) nav_ffM = self._mknav('> ', nx, ffMonth, ffYear) nav_nxY = self._mknav('>>', nx, month, year + 1) # add buttons for going to previous months and year buff(nav_pvY, nav_frM, nav_pvM) # The caption will always be there. heading = tag.td( to_unicode(format_date(self._mkdatetime(year, month), '%B %Y'))) buff = buff(heading(class_='y')) if showbuttons is True: # add buttons for going to next months and year buff(nav_nxM, nav_ffM, nav_nxY) buff = tag.caption(tag.table(tag.tbody(buff))) buff = tag.table(buff) if name == 'WikiTicketCalendar': if cal_width.startswith('+') is True: width = ":".join(['min-width', cal_width]) buff(class_='wikitcalendar', style=width) else: buff(class_='wikitcalendar') if name == 'WikiCalendar': buff(class_='wiki-calendar') heading = tag.tr() heading(align='center') for day in calendar.weekheader(2).split()[:-2]: col = tag.th(to_unicode(day)) col(class_='workday', scope='col') heading(col) for day in calendar.weekheader(2).split()[-2:]: col = tag.th(to_unicode(day)) col(class_='weekend', scope='col') heading(col) heading = buff(tag.thead(heading)) # Building main calendar table body buff = tag.tbody() w = -1 for week in cal: w = w + 1 line = tag.tr() line(align='right') d = -1 for day in week: d = d + 1 if day: # check for wikipage with name specified in # 'wiki_page_format' wiki = format_date(self._mkdatetime(year, month, day), wiki_page_format) if day == curr_day: a_class = 'day today' td_class = 'today' else: a_class = 'day' td_class = 'day' day_dt = self._mkdatetime(year, month, day) if uts: day_ts = to_utimestamp(day_dt) day_ts_eod = day_ts + 86399999999 else: day_ts = to_timestamp(day_dt) day_ts_eod = day_ts + 86399 # check for milestone(s) on that day db = self.env.get_db_cnx() cursor = db.cursor() cursor.execute( """ SELECT name FROM milestone WHERE due >= %s and due <= %s """, (day_ts, day_ts_eod)) milestones = tag() for row in cursor: if not a_class.endswith('milestone'): a_class += ' milestone' milestone = to_unicode(row[0]) url = self.env.href.milestone(milestone) milestone = '* ' + milestone milestones = tag( milestones, tag.div(tag.a(milestone, href=url), class_='milestone')) day = tag.span(day) day(class_='day') if len(wiki_subpages) > 0: pages = tag(day, Markup('<br />')) for page in wiki_subpages: label = tag(' ', page[0]) page = '/'.join([wiki, page]) url = self.env.href.wiki(page) pages( self._gen_wiki_links(page, label, 'subpage', url, wiki_page_template, check)) else: url = self.env.href.wiki(wiki) pages = self._gen_wiki_links(wiki, day, a_class, url, wiki_page_template, check) cell = tag.td(pages) cell(class_=td_class, valign='top') if name == 'WikiCalendar': line(cell) else: if milestones: cell(milestones) else: cell(tag.br()) match = [] match_od = [] ticket_heap = tag('') ticket_list = tag.div('') ticket_list(align='left', class_='condense') # get tickets with due date set to day for t in self.tickets: due = t.get(self.tkt_due_field) if due is None or due in ['', '--']: continue else: if self.tkt_due_format == 'ts': if not isinstance(due, datetime.datetime): continue if uts: due_ts = to_utimestamp(due) else: due_ts = to_timestamp(due) if due_ts < day_ts or due_ts > day_ts_eod: continue else: # Beware: Format might even be unicode str duedate = format_date( day_dt, str(self.tkt_due_format)) if not due == duedate: continue id = t.get('id') ticket, short = self._gen_ticket_entry(t) ticket_heap(ticket) if not id in match: if len(match) == 0: ticket_list(short) else: ticket_list(', ', short) match.append(id) # optionally get tickets created on day if show_t_open_dates is True: ticket_od_list = tag.div('') ticket_od_list(align='left', class_='opendate_condense') for t in self.tickets: if uts: ticket_ts = to_utimestamp(t.get('time')) else: ticket_ts = to_timestamp(t.get('time')) if ticket_ts < day_ts or \ ticket_ts > day_ts_eod: continue a_class = 'opendate_' id = t.get('id') ticket, short = self._gen_ticket_entry( t, a_class) ticket_heap(ticket) if not id in match: if len(match_od) == 0: ticket_od_list(short) else: ticket_od_list(', ', short) match_od.append(id) matches = len(match) + len(match_od) if list_condense > 0 and matches >= list_condense: if len(match_od) > 0: if len(match) > 0: ticket_list(', ') ticket_list = tag(ticket_list, ticket_od_list) line(cell(ticket_list)) else: line(cell(ticket_heap)) else: if name == 'WikiCalendar': if w == 0: day = last_week_prevMonth[d] wiki = format_date( self._mkdatetime(prevYear, prevMonth, day), wiki_page_format) else: day = first_week_nextMonth[d] wiki = format_date( self._mkdatetime(nextYear, nextMonth, day), wiki_page_format) url = self.env.href.wiki(wiki) a_class = 'day adjacent_month' pages = self._gen_wiki_links(wiki, day, a_class, url, wiki_page_template) cell = tag.td(pages) cell(class_='day adjacent_month') line(cell) else: cell = tag.td('') cell(class_='day adjacent_month') line(cell) buff(line) if loc_req and loc_prop: # We may have switched to users locale, resetting now. try: locale.setlocale(locale.LC_ALL, loc) self.env.log.debug('Locale setting restored: ' + str(loc)) except locale.Error: pass buff = tag.div(heading(buff)) if name == 'WikiTicketCalendar': if cal_width.startswith('+') is True: width = ":".join(['width', cal_width]) buff(class_='wikitcalendar', style=width) else: buff(class_='wikitcalendar') if name == 'WikiCalendar': buff(class_='wiki-calendar') # Add common CSS stylesheet if self.internal_css and not self.ref.req.args.get('wikicalendar'): # Put definitions directly into the output. f = open('/'.join([self.htdocs_path, 'wikicalendar.css']), 'Ur') css = tag.style(Markup('<!--\n'), '\n'.join(f.readlines()), Markup('-->\n'))(type="text/css") f.close() # Add hint to prevent multiple inclusions. self.ref.req.args['wikicalendar'] = True return tag(css, buff) elif not self.ref.req.args.get('wikicalendar'): add_stylesheet(self.ref.req, 'wikicalendar/wikicalendar.css') return buff
def expand_macro(self, formatter, name, arguments): """Returns macro content.""" env = self.env req = formatter.req tz = req.tz # Parse arguments from macro invocation. args, kwargs = parse_args(arguments, strict=False) # Enable week number display regardless of argument position. week_pref = "w" in args and args.pop(args.index("w")) week_pref = week_pref and week_pref or kwargs.get("w") week_start = None week_num_start = None # Parse per-instance week calculation rules, if available. if week_pref: if ":" not in week_pref: # Treat undelimitted setting as week start. week_pref += ":" w_start, wn_start = week_pref.split(":") try: week_start = int(w_start) except ValueError: week_start = None else: week_start = week_start > -1 and week_start < 7 and week_start or None try: week_num_start = int(wn_start) except ValueError: week_num_start = None else: week_num_start = week_num_start in (1, 4, 7) and week_num_start or None # Respect user's locale, if available. try: locale = Locale.parse(str(req.locale)) except (AttributeError, UnknownLocaleError): # Attribute 'req.locale' vailable since Trac 0.12. locale = None if has_babel: if locale: if not locale.territory: # Search first locale, which has the same `language` and # territory in preferred languages. for l in req.languages: l = l.replace("-", "_").lower() if l.startswith(locale.language.lower() + "_"): try: l = Locale.parse(l) if l.territory: locale = l break # first one rules except UnknownLocaleError: pass if not locale.territory and locale.language in LOCALE_ALIASES: locale = Locale.parse(LOCALE_ALIASES[locale.language]) else: # Default fallback. locale = Locale("en", "US") env.log.debug("Locale setting for wiki calendar: %s" % locale.get_display_name("en")) if not week_start: if week_pref and week_pref.lower().startswith("iso"): week_start = 0 week_num_start = 4 elif has_babel: week_start = locale.first_week_day else: import calendar week_start = calendar.firstweekday() # ISO calendar will remain as default. if not week_num_start: if week_start == 6: week_num_start = 1 else: week_num_start = 4 env.log.debug( "Effective settings: first_week_day=%s, " "1st_week_of_year_rule=%s" % (week_start, week_num_start) ) # Find year and month of interest. year = req.args.get("year") # Not clicked on any previous/next button, next look for macro args. if not year and len(args) >= 1 and args[0] != "*": year = args[0] year = year and year.isnumeric() and int(year) or None month = req.args.get("month") # Not clicked on any previous/next button, next look for macro args. if not month and len(args) >= 2 and args[1] != "*": month = args[1] month = month and month.isnumeric() and int(month) or None now = datetime.now(tz) # Force offset from start-of-day to avoid a false 'today' marker, # but use it only on request of different month/year. now.replace(second=1) today = None if month and month != now.month: today = now.replace(month=month) if year and year != now.year: today = today and today.replace(year=year) or now.replace(year=year) # Use current month and year, if nothing else has been requested. if not today: today = now.replace(hour=0, minute=0, second=0, microsecond=0) showbuttons = True if len(args) >= 3 or kwargs.has_key("nav"): try: showbuttons = kwargs["nav"] in _TRUE_VALUES except KeyError: showbuttons = args[2] in _TRUE_VALUES wiki_page_format = "%Y-%m-%d" if len(args) >= 4 and args[3] != "*" or kwargs.has_key("wiki"): try: wiki_page_format = str(kwargs["wiki"]) except KeyError: wiki_page_format = str(args[3]) # Support relative paths in macro arguments for wiki page links. wiki_page_format = resolve_relative_name(wiki_page_format, formatter.resource.id) list_condense = 0 show_t_open_dates = True wiki_subpages = [] # Read optional check plan. check = [] if kwargs.has_key("check"): check = kwargs["check"].split(".") if name == "WikiTicketCalendar": if len(args) >= 5 or kwargs.has_key("cdate"): try: show_t_open_dates = kwargs["cdate"] in _TRUE_VALUES except KeyError: show_t_open_dates = args[4] in _TRUE_VALUES # TracQuery support for ticket selection query_args = "id!=0" if len(args) >= 7 or kwargs.has_key("query"): # prefer query arguments provided by kwargs try: query_args = kwargs["query"] except KeyError: query_args = args[6] provider = WikiCalendarTicketProvider(env) tickets = provider.harvest(req, query_args) # compress long ticket lists if len(args) >= 8 or kwargs.has_key("short"): # prefer query arguments provided by kwargs try: list_condense = int(kwargs["short"]) except KeyError: list_condense = int(args[7]) # control calendar display width cal_width = "100%;" if len(args) >= 9 or kwargs.has_key("width"): # prefer query arguments provided by kwargs try: cal_width = kwargs["width"] except KeyError: cal_width = args[8] # multiple wiki (sub)pages per day if kwargs.has_key("subpages"): wiki_subpages = kwargs["subpages"].split("|") # Prepare datetime objects for previous/next navigation link creation. prev_year = month_offset(today, -12) prev_quarter = month_offset(today, -3) prev_month = month_offset(today, -1) next_month = month_offset(today, 1) next_quarter = month_offset(today, 3) next_year = month_offset(today, 12) # Find first and last calendar day, probably in last/next month, # using datetime objects exactly at start-of-day here. # Note: Calendar days are numbered 0 (Mo) - 6 (Su). first_day_month = today.replace(day=1, second=0) first_day = first_day_month - timedelta(week_index(first_day_month, week_start)) last_day_month = next_month.replace(day=1) - timedelta(1) if ((last_day_month - first_day).days + 1) % 7 > 0: last_day = last_day_month + timedelta(7 - ((last_day_month - first_day).days + 1) % 7) else: last_day = last_day_month # Finally building the output now. # Begin with caption and optional navigation links. buff = tag.tr() if showbuttons is True: # Create calendar navigation buttons. nx = "next" pv = "prev" nav_pv_y = _nav_link(req, "<<", pv, prev_year, locale) nav_pv_q = _nav_link(req, " «", pv, prev_quarter, locale) nav_pv_m = _nav_link(req, " <", pv, prev_month, locale) nav_nx_m = _nav_link(req, "> ", nx, next_month, locale) nav_nx_q = _nav_link(req, "» ", nx, next_quarter, locale) nav_nx_y = _nav_link(req, ">>", nx, next_year, locale) # Add buttons for going to previous months and year. buff(nav_pv_y, nav_pv_q, nav_pv_m) # The caption will always be there. if has_babel: heading = tag.td(format_datetime(today, "MMMM y", locale=locale)) else: heading = tag.td(format_date(today, "%B %Y")) buff = buff(heading(class_="y")) if showbuttons is True: # Add buttons for going to next months and year. buff(nav_nx_m, nav_nx_q, nav_nx_y) buff = tag.caption(tag.table(tag.tbody(buff))) buff = tag.table(buff) if name == "WikiTicketCalendar": if cal_width.startswith("+") is True: width = ":".join(["min-width", cal_width]) buff(class_="wikitcalendar", style=width) else: buff(class_="wikitcalendar") if name == "WikiCalendar": buff(class_="wiki-calendar") heading = tag.tr() heading(align="center") if week_pref: # Add an empty cell matching the week number column below. heading(tag.th()) day_names = [(idx, day_name) for idx, day_name in get_day_names("abbreviated", "format", locale).iteritems()] # Read day names after shifting into correct position. for idx, name_ in day_names[week_start:7] + day_names[0:week_start]: col = tag.th(name_) if has_babel: weekend = idx >= locale.weekend_start and idx <= locale.weekend_end else: weekend = idx > 4 col(class_=("workday", "weekend")[weekend], scope="col") heading(col) heading = buff(tag.thead(heading)) # Building main calendar table body buff = tag.tbody() day = first_day while day.date() <= last_day.date(): # Insert a new row for every week. if (day - first_day).days % 7 == 0: line = tag.tr() line(align="right") if week_pref: cell = tag.td(week_num(env, day, week_start, week_num_start)) line(cell(class_="week")) if not (day < first_day_month or day > last_day_month): wiki = format_date(day, wiki_page_format) if day == today: a_class = "day today" td_class = "today" else: a_class = "day" td_class = "day" if uts: day_ts = to_utimestamp(day) day_ts_eod = day_ts + 86399999999 else: day_ts = to_timestamp(day) day_ts_eod = day_ts + 86399 # Check for milestone(s) on that day. db = env.get_db_cnx() cursor = db.cursor() cursor.execute( """ SELECT name FROM milestone WHERE due >= %s and due <= %s """, (day_ts, day_ts_eod), ) milestones = tag() for row in cursor: if not a_class.endswith("milestone"): a_class += " milestone" milestone = to_unicode(row[0]) url = env.href.milestone(milestone) milestone = "* " + milestone milestones = tag(milestones, tag.div(tag.a(milestone, href=url), class_="milestone")) label = tag.span(day.day) label(class_="day") # Generate wiki page links with name specified in # 'wiki_page_format', and check their existence. if len(wiki_subpages) > 0: pages = tag(label, Markup("<br />")) for page in wiki_subpages: label = tag(" ", page[0]) page = "/".join([wiki, page]) pages(self._wiki_link(req, args, kwargs, page, label, "subpage", check)) else: pages = self._wiki_link(req, args, kwargs, wiki, label, a_class, check) cell = tag.td(pages) cell(class_=td_class, valign="top") if name == "WikiCalendar": line(cell) else: if milestones: cell(milestones) else: cell(tag.br()) match = [] match_od = [] ticket_heap = tag("") ticket_list = tag.div("") ticket_list(align="left", class_="condense") # Get tickets with due date set to day. for t in tickets: due = t.get(self.tkt_due_field) if due is None or due in ("", "--"): continue else: if self.tkt_due_format == "ts": if not isinstance(due, datetime): continue if uts: due_ts = to_utimestamp(due) else: due_ts = to_timestamp(due) if due_ts < day_ts or due_ts > day_ts_eod: continue else: # Beware: Format might even be unicode string, # but str is required by the function. duedate = format_date(day, str(self.tkt_due_format)) if not due == duedate: continue tkt_id = t.get("id") ticket, short = _ticket_links(env, formatter, t) ticket_heap(ticket) if not tkt_id in match: if len(match) == 0: ticket_list(short) else: ticket_list(", ", short) match.append(tkt_id) # Optionally, get tickets created on day too. if show_t_open_dates is True: ticket_od_list = tag.div("") ticket_od_list(align="left", class_="opendate_condense") for t in tickets: if uts: ticket_ts = to_utimestamp(t.get("time")) else: ticket_ts = to_timestamp(t.get("time")) if ticket_ts < day_ts or ticket_ts > day_ts_eod: continue a_class = "opendate_" tkt_id = t.get("id") ticket, short = _ticket_links(env, formatter, t, a_class) ticket_heap(ticket) if not tkt_id in match: if len(match_od) == 0: ticket_od_list(short) else: ticket_od_list(", ", short) match_od.append(tkt_id) matches = len(match) + len(match_od) if list_condense > 0 and matches >= list_condense: if len(match_od) > 0: if len(match) > 0: ticket_list(", ") ticket_list = tag(ticket_list, ticket_od_list) line(cell(ticket_list)) else: line(cell(ticket_heap)) else: if name == "WikiCalendar": wiki = format_date(day, wiki_page_format) a_class = "day adjacent_month" pages = self._wiki_link(req, args, kwargs, wiki, day.day, a_class) cell = tag.td(pages, class_="day adjacent_month") line(cell) else: cell = tag.td("", class_="day adjacent_month") line(cell) # Append completed week rows. if (day - first_day).days % 7 == 6: buff(line) day += timedelta(1) buff = tag.div(heading(buff)) if name == "WikiTicketCalendar": if cal_width.startswith("+") is True: width = ":".join(["width", cal_width]) buff(class_="wikitcalendar", style=width) else: buff(class_="wikitcalendar") if name == "WikiCalendar": buff(class_="wiki-calendar") # Add common CSS stylesheet. if self.internal_css and not req.args.get("wikicalendar"): # Put definitions directly into the output. f = open("/".join([self.htdocs_path, "wikicalendar.css"]), "Ur") css = tag.style(Markup("<!--\n"), "\n".join(f.readlines()), Markup("-->\n"))(type="text/css") f.close() # Add hint to prevent multiple inclusions. req.args["wikicalendar"] = True return tag(css, buff) elif not req.args.get("wikicalendar"): add_stylesheet(req, "wikicalendar/wikicalendar.css") return buff
def expand_macro(self, formatter, name, args): """ Called by the formatter to render the parsed wiki text. """ def to_html(text): """ Format the parsed text from the rows into HTML. """ if not text: return '' # simple check to determine whether format_to_html or # format_to_oneliner should be used. If there are multiple # lines, use format_to_html, otherwise use format_to_oneliner stripped_text = text.strip() splitlines = stripped_text.splitlines() if len(splitlines) > 1: formatted_text = format_to_html(self.env, formatter.context, text) else: formatted_text = '<br />'.join( [format_to_oneliner(self.env, formatter.context, line) \ for line in text.splitlines()] ) return Markup( formatted_text ) if not args: return Markup() # use the formatter to find the TablePluginStyles if not formatter.wiki.has_page('TablePluginStyles'): # if our build_table_plugin_styles_page(self.env) if formatter.wiki.has_page('TablePluginStyles'): # at this point, the new style page should exist # so use the styles defined there. config_args = self._parse_wiki_style_page(self.env) else: # nice error handling in here possible incase # the page cannot be created for whatever reason? pass config_table_styles, config_css_styles = self._parse_styles(config_args) args_table_styles, args_css_styles = self._parse_styles(args) global_css_styles = dict(config_css_styles.items() + args_css_styles.items()) column_list = [] row_count = 0 row_dict = {} row_list = [] heading = False body_name = '' heading_set = False body_set_first = False first_row_as_header = False is_row = False table_id = '' table_data = '' table_style = '' column_style_dict = {} for attribute in self._parse_args(args): if 'table' in attribute: # get the table id to use table_id = attribute['table']['name'] table_data = attribute['table']['data'] table_style = attribute['table']['style'].replace('@', '') elif 'css' in attribute: pass elif 'column' in attribute: column_name = attribute['column']['name'] column_list.append(column_name) if attribute['column']['style']: column_style_dict[column_name] = attribute['column']['style'] elif 'header' in attribute: heading = True heading_set = True elif 'body' in attribute: body_name = str(uuid4()) if not heading_set and not first_row_as_header: body_set_first = True heading = False elif 'row' in attribute: is_row = True row_count = 0 row_style = attribute['row']['style'] else: if not heading_set and not body_set_first: first_row_as_header = True for key, value in attribute.items(): value['heading'] = heading if body_name: value['body_name'] = body_name if is_row: # if its a row, apply row style original_style = value['style'] value['style'] = ' '.join([original_style, row_style]) if row_count == (len(column_list) - 1): row_dict.update(attribute) row_list.append(row_dict) row_dict = {} row_count = 0 is_row = False else: row_dict.update(attribute) row_count += 1 thead = tag.thead() for row in row_list: if body_set_first: break header_row = tag.tr() for column in column_list: header_cell = '' if row[column]['heading'] or first_row_as_header: header_cell = tag.th() header_cell(to_html(row[column]['data']), class_=row[column]['style'].replace('@', '')) header_row(header_cell) if header_cell: thead(header_row) if first_row_as_header: break if table_style: table_id = table_style table_data = config_table_styles[table_style]['data'] css_data = self._build_css_template(global_css_styles) full_style_data = '' full_style_data += table_data full_style_data += css_data tstyle = tag.style() tstyle = tag.style(full_style_data) tbody = tag.tbody() body_name = '' body_set = False tbody_list = [] for row in row_list: if first_row_as_header: heading_set = False first_row_as_header = False continue trow = tag.tr() tcol = '' for column in column_list: if row[column]['heading']: continue if row[column]['body_name'] == body_name and not body_set: body_set = True elif row[column]['body_name'] != body_name and not body_set: body_name = row[column]['body_name'] body_set = True elif row[column]['body_name'] != body_name and body_set: tbody_list.append(tbody) tbody = tag.tbody() trow = tag.tr() body_name = row[column]['body_name'] tcol = tag.td() # if there is a column style available, # add it to what is already there formatted_column_style = '' if column in column_style_dict: column_style = column_style_dict[column].replace('@', '') formatted_column_style = column_style.replace(';', ' ') class_styles = row[column]['style'].replace('@', '') formatted_class_styles = class_styles.replace(';', ' ') formatted_item = ' '.join([formatted_class_styles, formatted_column_style]) tcol(to_html(row[column]['data']), class_=formatted_item) trow(tcol) if tcol: tbody(trow) tbody_list.append(tbody) return tag.table([tstyle, thead, tbody_list], class_=table_id)