def depart_title(self, node): spec, indent, attr = self.parse(node) if isinstance(node.parent, nodes.table): elem = tag.caption(**attr) else: assert self.heading_level >= 0 if self.heading_level == 0: self.heading_level = 1 if 'href' in attr: # backref to toc entry del attr['href'] elem = getattr(tag, 'h' + unicode(self.heading_level))(**attr) self.context.commit_elem(elem, indent)
def depart_title(self, node): spec, indent, attr = self.parse(node) if isinstance(node.parent, nodes.table): elem = tag.caption(**attr) else: assert self.heading_level >= 0 if self.heading_level == 0: self.heading_level = 1 if 'href' in attr: # backref to toc entry # anchor = tag.a(href=("#" + attr['href']), class_="toc-backref") # self.context.commit_elem(anchor) # anchor = self.context.pop() # self.context.begin_elem() # self.context.append(anchor, indent=False) del attr['href'] elem = getattr(tag, 'h' + unicode(self.heading_level))(**attr) self.context.commit_elem(elem, indent)
def expand_macro(self, formatter, name, arguments): self.ref = formatter self.tz_info = formatter.req.tz self.thistime = datetime.datetime.now(self.tz_info) # Add CSS stylesheet add_stylesheet(self.ref.req, 'wikiticketcalendar/css/wikiticketcalendar.css') # 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 # Begin with 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) day_ts = to_utimestamp(day_dt) day_ts_eod = day_ts + 86399999999 # 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 due_ts = to_utimestamp(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: ticket_ts = to_utimestamp(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') 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) 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]) list_condense = 0 show_t_open_dates = False wiki_page_template = "" wiki_subpages = [] 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"] # template name tried to create new pages # optional, default (empty page) is used, if 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] # 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 # 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 last_week_prevMonth = calendar.monthcalendar(prevYear, prevMonth)[-1] first_week_nextMonth = calendar.monthcalendar(nextYear, nextMonth)[0] # 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, **{"data-duedatefield": self.due_field_name}) else: buff(class_='wikitcalendar', **{"data-duedatefield": self.due_field_name}) 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) day_ts = to_utimestamp(day_dt) day_ts_eod = day_ts + 86399999999 # 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)) milestone = None 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 milestone = tag.div(tag.a(milestone, href=url)) milestone(class_='milestone') if len(wiki_subpages) > 0: pages = tag(day, Markup('<br />')) for page in wiki_subpages: label = tag(' ', page[0]) page = wiki + '/' + page url = self.env.href.wiki(page) pages(self._gen_wiki_links(page, label, 'subpage', url, wiki_page_template)) else: url = self.env.href.wiki(wiki) pages = self._gen_wiki_links(wiki, day, a_class, url, wiki_page_template) hours = 0 cell = tag.td(pages) cell(class_=td_class, valign='top', **{"data-date": "%02i/%02i/%i" %(day, month, year)}) if name == 'WikiCalendar': line(cell) else: if milestone: cell(milestone) else: cell(tag.br()) match = [] match_od = [] ticket_heap = tag.div('', class_="tickets") 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 due_ts = to_utimestamp(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.due_field_fmt)) if not due == duedate: continue id = t.get('id') hours += float(t.get(self.hours_field_name)) 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: ticket_ts = to_utimestamp(t.get('time')) if ticket_ts < day_ts or \ ticket_ts > day_ts_eod: continue a_class = 'opendate_' id = t.get('id') hours += float(t.get(self.hours_field_name)) 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)) cell(tag.span("%dh" % hours, class_="totalhours")) 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) 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 add_stylesheet(self.ref.req, 'wikicalendar/wikicalendar.css') if self.gridmodify_enabled: add_script(self.ref.req, 'datefield/js/jquery-ui.js') add_script(self.ref.req, 'wikicalendar/wikicalendar.js') add_stylesheet(self.ref.req, 'datefield/css/jquery-ui.css') add_stylesheet(self.ref.req, 'datefield/css/ui.datepicker.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