-
diff --git a/trac/search/templates/search.html b/trac/search/templates/search.html
|
a
|
b
|
|
| 30 | 30 | <p class="filters"> |
| 31 | 31 | <py:for each="filter in filters"> |
| 32 | 32 | <input type="checkbox" id="${filter.name}" name="${filter.name}" |
| 33 | | checked="${'checked' if filter.active else None}" /> |
| | 33 | checked="${filter.active or None}" /> |
| 34 | 34 | <label for="${filter.name}">${filter.label}</label> |
| 35 | 35 | </py:for> |
| 36 | 36 | </p> |
-
diff --git a/trac/ticket/notification.py b/trac/ticket/notification.py
|
a
|
b
|
class TicketNotifyEmail(NotifyEmail): |
| 84 | 84 | ambiguous_char_width = env.config.get('notification', |
| 85 | 85 | 'ambiguous_char_width', |
| 86 | 86 | 'single') |
| 87 | | self.ambiwidth = (1, 2)[ambiguous_char_width == 'double'] |
| | 87 | self.ambiwidth = 2 if ambiguous_char_width == 'double' else 1 |
| 88 | 88 | |
| 89 | 89 | def notify(self, ticket, newticket=True, modtime=None): |
| 90 | 90 | """Send ticket change notification e-mail (untranslated)""" |
-
diff --git a/trac/ticket/query.py b/trac/ticket/query.py
|
a
|
b
|
class QueryModule(Component): |
| 940 | 940 | conversion[1], conversion[4], conversion[0]) |
| 941 | 941 | |
| 942 | 942 | if format: |
| 943 | | filename = ('query', None)[format == 'rss'] |
| | 943 | filename = 'query' if format != 'rss' else None |
| 944 | 944 | Mimeview(self.env).send_converted(req, 'trac.ticket.Query', query, |
| 945 | 945 | format, filename=filename) |
| 946 | 946 | |
-
diff --git a/trac/ticket/templates/query.html b/trac/ticket/templates/query.html
|
a
|
b
|
|
| 40 | 40 | <table summary="Query filters"> |
| 41 | 41 | <tbody py:for="clause_num, constraints in enumerate(clauses or [{}])" |
| 42 | 42 | py:with="clause_pre = '%d_' % clause_num"> |
| 43 | | <tr style="${clause_num == 0 and 'display: none' or None}"> |
| | 43 | <tr style="${'display: none' if clause_num == 0 else None}"> |
| 44 | 44 | <td> |
| 45 | 45 | <div class="trac-clause-lsep"> <hr /></div> |
| 46 | 46 | <div class="trac-clause-msep">Or</div> |
| … |
… |
|
| 66 | 66 | <td py:if="field.type not in ('radio', 'checkbox', 'time')" class="mode"> |
| 67 | 67 | <select name="${n_field_name}_mode"> |
| 68 | 68 | <option py:for="mode in modes[field.type]" value="$mode.value" |
| 69 | | selected="${mode.value == constraint.mode and 'selected' or None}">$mode.name</option> |
| | 69 | selected="${mode.value == constraint.mode or None}">$mode.name</option> |
| 70 | 70 | </select> |
| 71 | 71 | </td> |
| 72 | 72 | </py:when> |
| 73 | 73 | <py:otherwise><!--! not the first line of a multiline constraint --> |
| 74 | | <th colspan="${field.type == 'time' and 1 or 2}"><label>or</label></th> |
| | 74 | <th colspan="${1 if field.type == 'time' else 2}"><label>or</label></th> |
| 75 | 75 | </py:otherwise> |
| 76 | 76 | </py:choose> |
| 77 | 77 | |
| 78 | | <td class="filter" colspan="${field.type in ('radio', 'checkbox', 'time') and 2 or None}" |
| | 78 | <td class="filter" colspan="${2 if field.type in ('radio', 'checkbox', 'time') else None}" |
| 79 | 79 | py:choose=""> |
| 80 | 80 | |
| 81 | 81 | <py:when test="field.type == 'select'"> |
| … |
… |
|
| 98 | 98 | <py:for each="option in field.options"> |
| 99 | 99 | <input type="checkbox" id="_${n_field_name}_$option" name="${n_field_name}" |
| 100 | 100 | value="$option" |
| 101 | | checked="${((constraint['mode'] == '') == (option in constraint['values'])) |
| 102 | | and 'checked' or None}" /> |
| | 101 | checked="${((constraint['mode'] == '') == (option in constraint['values'])) or None}" /> |
| 103 | 102 | <label for="_${n_field_name}_$option" class="control">${option or 'none'}</label> |
| 104 | 103 | </py:for> |
| 105 | 104 | </py:when> |
| … |
… |
|
| 172 | 171 | <py:for each="column in all_columns"> |
| 173 | 172 | <label> |
| 174 | 173 | <input type="checkbox" name="col" value="$column" |
| 175 | | checked="${any([(value == column) for value in col]) |
| 176 | | and 'checked' or None}" /> |
| | 174 | checked="${any(value == column for value in col) or None}" /> |
| 177 | 175 | ${fields.get(column, {'label': column or 'none'}).label} |
| 178 | 176 | </label> |
| 179 | 177 | </py:for> |
| … |
… |
|
| 200 | 198 | Show under each result: |
| 201 | 199 | <py:for each="column in all_textareas"> |
| 202 | 200 | <label><input type="checkbox" name="row" value="$column" |
| 203 | | checked="${any([(value == column) for value in row]) and 'checked' or None}" /> |
| | 201 | checked="${any(value == column for value in row) or None}" /> |
| 204 | 202 | ${fields.get(column, {'label': column or 'none'}).label}</label> |
| 205 | 203 | </py:for> |
| 206 | 204 | </p> |
| … |
… |
|
| 233 | 231 | value="${_('Edit query')}" /> |
| 234 | 232 | </div> |
| 235 | 233 | </form> |
| 236 | | <form py:if="new or edit" method="get" action="${edit and url_of(report_resource) or href.report()}"> |
| | 234 | <form py:if="new or edit" method="get" action="${url_of(report_resource) if edit else href.report()}"> |
| 237 | 235 | <div> |
| 238 | | <input type="hidden" name="action" value="${edit and 'edit' or 'new'}" /> |
| | 236 | <input type="hidden" name="action" value="${'edit' if edit else 'new'}" /> |
| 239 | 237 | <input type="hidden" name="query" value="${query.to_string()}" /> |
| 240 | 238 | <input type="submit" value="${_('Save query')}" |
| 241 | | title="${edit and _('Save updated query in report {%(id)s}', id=report_resource.id) or |
| 242 | | _('Create new report from current query')}" /> |
| | 239 | title="${_('Save updated query in report {%(id)s}', id=report_resource.id) if edit |
| | 240 | else _('Create new report from current query')}" /> |
| 243 | 241 | </div> |
| 244 | 242 | </form> |
| 245 | 243 | <form py:if="delete" method="get" action="${url_of(report_resource)}"> |
-
diff --git a/trac/ticket/templates/query_results.html b/trac/ticket/templates/query_results.html
|
a
|
b
|
|
| 33 | 33 | <py:def function="column_headers()"> |
| 34 | 34 | <tr class="trac-columns"> |
| 35 | 35 | <th py:for="header in headers" |
| 36 | | class="$header.name${query.order == header.name and (query.desc and ' desc' or ' asc') or ''}"> |
| | 36 | class="$header.name${(' desc' if query.desc else ' asc') if query.order == header.name else ''}"> |
| 37 | 37 | <?python asc = _('(ascending)'); desc = _('(descending)') ?> |
| 38 | 38 | <a title="${_('Sort by %(col)s %(direction)s', col=header.label, |
| 39 | | direction=(query.order == header.name and not query.desc and desc or asc))}" |
| | 39 | direction=(desc if query.order == header.name and not query.desc else asc))}" |
| 40 | 40 | href="$header.href">${header.label}</a> |
| 41 | 41 | </th> |
| 42 | 42 | </tr> |
| 43 | 43 | </py:def> |
| 44 | | ${groups and group_heading(*groups[0]) or None} |
| | 44 | ${group_heading(*groups[0]) if groups else None} |
| 45 | 45 | <table class="listing tickets"> |
| 46 | 46 | <thead py:strip="group_index"> |
| 47 | 47 | ${column_headers()} |
| … |
… |
|
| 65 | 65 | <py:with vars="ticket_context = context.child('ticket', result.id)"> |
| 66 | 66 | <py:if test="'TICKET_VIEW' in perm(ticket_context.resource)"> |
| 67 | 67 | |
| 68 | | <tr class="${idx % 2 and 'odd' or 'even'} prio${result.priority_value}${ |
| 69 | | 'added' in result and ' added' or ''}${ |
| 70 | | 'changed' in result and ' changed' or ''}${ |
| 71 | | 'removed' in result and ' removed' or ''}"> |
| | 68 | <tr class="${'odd' if idx % 2 else 'even'} prio${result.priority_value}${ |
| | 69 | ' added' if 'added' in result else ''}${ |
| | 70 | ' changed' if 'changed' in result else ''}${ |
| | 71 | ' removed' if 'removed' in result else ''}"> |
| 72 | 72 | <py:for each="idx, header in enumerate(headers)" py:choose=""> |
| 73 | 73 | <py:with vars="name = header.name; value = result[name]"> |
| 74 | 74 | <td py:when="name == 'id'" class="id"><a href="$result.href" title="View ticket" |
-
diff --git a/trac/ticket/templates/report.rss b/trac/ticket/templates/report.rss
|
a
|
b
|
|
| 10 | 10 | <image py:if="chrome.logo.src_abs"> |
| 11 | 11 | <title>$project.name</title> |
| 12 | 12 | <url>$chrome.logo.src_abs</url> |
| 13 | | <link>${abs_href.report(report.id != -1 and report.id or '')}</link> |
| | 13 | <link>${abs_href.report(report.id if report.id != -1 else '')}</link> |
| 14 | 14 | </image> |
| 15 | 15 | <generator>Trac v${trac.version}</generator> |
| 16 | 16 | |
-
diff --git a/trac/ticket/templates/report_edit.html b/trac/ticket/templates/report_edit.html
|
a
|
b
|
|
| 13 | 13 | <body> |
| 14 | 14 | <div id="content" class="report"> |
| 15 | 15 | |
| 16 | | <h1>${action == 'new' and _('New Report') or report.title}</h1> |
| | 16 | <h1>${_('New Report') if action == 'new' else report.title}</h1> |
| 17 | 17 | <form action="${href.report(report.id)}" method="post" id="edit_report"> |
| 18 | 18 | <div> |
| 19 | 19 | <input type="hidden" name="action" value="$action" /> |
-
diff --git a/trac/ticket/templates/report_list.html b/trac/ticket/templates/report_list.html
|
a
|
b
|
|
| 65 | 65 | <span id="trac-sort-order" py:with="report_asc = asc if sort == 'report' else None; |
| 66 | 66 | title_asc = asc if sort == 'title' else None"> |
| 67 | 67 | Sort by: |
| 68 | | <a href="${href.report(sort='report', asc=report_asc and '0' or '1')}" |
| | 68 | <a href="${href.report(sort='report', asc='0' if report_asc else '1')}" |
| 69 | 69 | class="${('desc', 'asc')[report_asc] if report_asc is not None else None}"> |
| 70 | 70 | Identifier</a> |
| 71 | | <a href="${href.report(sort='title', asc=title_asc and '0' or '1')}" |
| | 71 | <a href="${href.report(sort='title', asc='0' if title_asc else '1')}" |
| 72 | 72 | class="${('desc', 'asc')[title_asc] if title_asc is not None else None}"> |
| 73 | 73 | Title</a> |
| 74 | 74 | </span> |
-
diff --git a/trac/ticket/templates/report_view.html b/trac/ticket/templates/report_view.html
|
a
|
b
|
|
| 83 | 83 | <py:def function="column_headers()"> |
| 84 | 84 | <tr py:for="header_group in header_groups" class="trac-columns"> |
| 85 | 85 | <th py:for="header in header_group" py:if="not header.hidden" py:with="fullrow = header is header_group[-1]" |
| 86 | | colspan="${fullrow and '100' or None}" class="${header.asc is not None and ('desc', 'asc')[header.asc] or None}"> |
| | 86 | colspan="${'100' if fullrow else None}" class="${('desc', 'asc')[header.asc] if header.asc is not None else None}"> |
| 87 | 87 | <a py:strip="not sorting_enabled" |
| 88 | 88 | href="${report_href(sort=header.col, asc=not header.asc)}"> |
| 89 | 89 | $header.title |
| … |
… |
|
| 95 | 95 | <h2 py:if="value_for_group" class="report-result"> |
| 96 | 96 | <a py:strip="not row_group or '__grouplink__' not in row_group[0]" href="${row_group[0]['__grouplink__']}">$value_for_group</a> |
| 97 | 97 | <span class="numrows" py:with="cnt = len(row_group)"> |
| 98 | | (${cnt and ngettext('%(num)s match', '%(num)s matches', cnt) or _('No matches found.')}) |
| | 98 | (${ngettext('%(num)s match', '%(num)s matches', cnt) if cnt else _('No matches found.')}) |
| 99 | 99 | </span> |
| 100 | 100 | </h2> |
| 101 | 101 | </py:def> |
| 102 | | ${row_groups and group_heading(*row_groups[0]) or None} |
| | 102 | ${group_heading(*row_groups[0]) if row_groups else None} |
| 103 | 103 | <table py:if="row_groups" class="listing tickets"> |
| 104 | 104 | <py:for each="groupindex, (value_for_group, row_group) in enumerate(row_groups)"> |
| 105 | 105 | <thead py:if="not groupindex"> |
| … |
… |
|
| 118 | 118 | <py:for each="row in row_group"> |
| 119 | 119 | <tr py:for="cell_group in row.cell_groups" |
| 120 | 120 | py:with="fullrow = len(cell_group) == 1; |
| 121 | | td_attrs = fullrow and {'class': 'fullrow', 'colspan': 100} or {}" |
| 122 | | class="${'__color__' in row and 'color'+row.__color__+'-' or ''}${row.__idx__ % 2 and 'odd' or 'even'}" |
| 123 | | style="${'__bgcolor__' in row and 'background: '+row.__bgcolor__+';' or None |
| 124 | | }${'__fgcolor__' in row and 'color: '+row.__fgcolor__+';' or None |
| 125 | | }${'__style__' in row and row.__style__+';' or None |
| 126 | | }${fullrow and 'border: none; padding: 0;' or None}"> |
| | 121 | td_attrs = {'class': 'fullrow', 'colspan': 100} if fullrow else {}" |
| | 122 | class="${'color' + row.__color__ + '-' if '__color__' in row else ''}${'odd' if row.__idx__ % 2 else 'even'}" |
| | 123 | style="${'background: ' + row.__bgcolor__ + ';' if '__bgcolor__' in row else None |
| | 124 | }${'color: ' + row.__fgcolor__ + ';' if '__fgcolor__' in row else None |
| | 125 | }${row.__style__ + ';' if '__style__' in row else None |
| | 126 | }${'border: none; padding: 0;' if fullrow else None}"> |
| 127 | 127 | |
| 128 | 128 | <py:for each="cell in cell_group"> |
| 129 | 129 | <py:if test="not cell.header.hidden"> |
| … |
… |
|
| 155 | 155 | |
| 156 | 156 | <!--! generic fields --> |
| 157 | 157 | <py:when test="col == 'time'"> |
| 158 | | <td class="date" py:attrs="td_attrs">${cell.value != '' and format_time(from_utimestamp(long(cell.value))) or '--'} |
| | 158 | <td class="date" py:attrs="td_attrs">${format_time(from_utimestamp(long(cell.value))) if cell.value != '' else '--'} |
| 159 | 159 | <hr py:if="fullrow"/> |
| 160 | 160 | </td> |
| 161 | 161 | </py:when> |
| 162 | 162 | |
| 163 | 163 | <py:when test="col in ('date', 'created', 'modified')"> |
| 164 | | <td class="date" py:attrs="td_attrs">${cell.value != '' and format_date(from_utimestamp(long(cell.value))) or '--'} |
| | 164 | <td class="date" py:attrs="td_attrs">${format_date(from_utimestamp(long(cell.value))) if cell.value != '' else '--'} |
| 165 | 165 | <hr py:if="fullrow"/> |
| 166 | 166 | </td> |
| 167 | 167 | </py:when> |
| 168 | 168 | |
| 169 | 169 | <py:when test="col == 'datetime'"> |
| 170 | | <td class="date" py:attrs="td_attrs">${cell.value != '' and format_datetime(from_utimestamp(long(cell.value))) or '--'} |
| | 170 | <td class="date" py:attrs="td_attrs">${format_datetime(from_utimestamp(long(cell.value))) if cell.value != '' else '--'} |
| 171 | 171 | <hr py:if="fullrow"/> |
| 172 | 172 | </td> |
| 173 | 173 | </py:when> |
-
diff --git a/trac/ticket/templates/ticket.html b/trac/ticket/templates/ticket.html
|
a
|
b
|
|
| 127 | 127 | show_editor = can_edit_comment and str(change.cnum) == cnum_edit; |
| 128 | 128 | show_history = str(change.cnum) == cnum_hist; |
| 129 | 129 | max_version = max(change.comment_history); |
| 130 | | comment_version = (max_version, int(cversion or 0))[show_history]"> |
| 131 | | <div class="change" id="${'cnum' in change and 'trac-change-%d' % change.cnum or None}"> |
| | 130 | comment_version = int(cversion or 0) if show_history else max_version"> |
| | 131 | <div class="change" id="${'trac-change-%d' % change.cnum if 'cnum' in change else None}"> |
| 132 | 132 | <h3 class="change"> |
| 133 | 133 | <span class="threading" py:if="'cnum' in change" |
| 134 | 134 | py:with="change_replies = replies.get(str(change.cnum), [])"> |
| … |
… |
|
| 167 | 167 | </py:if> |
| 168 | 168 | <xi:include href="ticket_change.html"/> |
| 169 | 169 | <div py:if="not show_editor and len(change.comment_history) > 1" py:choose="" |
| 170 | | class="trac-lastedit ${comment_version != max_version and 'trac-shade' or None}"> |
| | 170 | class="trac-lastedit ${'trac-shade' if comment_version != max_version else None}"> |
| 171 | 171 | <i18n:msg params="version, date, author" py:when="comment_version != max_version"> |
| 172 | 172 | Version ${comment_version}, edited ${dateinfo(change.comment_history[comment_version].date)} ago |
| 173 | 173 | by ${authorinfo(change.comment_history[comment_version].author)} |
| … |
… |
|
| 197 | 197 | <!--! End of the section we don't show on initial new tickets --> |
| 198 | 198 | |
| 199 | 199 | <form py:if="has_property_editor" method="post" id="propertyform" |
| 200 | | action="${ticket.exists and href.ticket(ticket.id) + '#trac-add-comment' or href.newticket()}"> |
| | 200 | action="${href.ticket(ticket.id) + '#trac-add-comment' if ticket.exists else href.newticket()}"> |
| 201 | 201 | <!--! Add comment --> |
| 202 | 202 | <div py:if="ticket.exists and can_append" class="field" |
| 203 | 203 | py:with="show_comment_preview = (change_preview.fields or change_preview.comment) and cnum_edit is None"> |
| … |
… |
|
| 221 | 221 | may have failed. |
| 222 | 222 | </div> |
| 223 | 223 | <!--! Preview of ticket changes --> |
| 224 | | <div id="ticketchange" class="ticketdraft" style="${not show_comment_preview and 'display: none' or None}"> |
| 225 | | <h3 class="change" id="${'cnum' in change_preview and 'comment:%d' % change_preview.cnum or None}"> |
| | 224 | <div id="ticketchange" class="ticketdraft" style="${'display: none' if not show_comment_preview else None}"> |
| | 225 | <h3 class="change" id="${'comment:%d' % change_preview.cnum if 'cnum' in change_preview else None}"> |
| 226 | 226 | <span class="threading" py:if="'replyto' in change_preview"> |
| 227 | 227 | in reply to: ${commentref('↑ ', change_preview.replyto)} |
| 228 | 228 | </span> |
| … |
… |
|
| 285 | 285 | field.edit_label or field.label or field.name}:</label> |
| 286 | 286 | </th> |
| 287 | 287 | <td class="col${idx + 1}" py:if="idx == 0 or not fullrow" |
| 288 | | colspan="${fullrow and 3 or None}"> |
| | 288 | colspan="${3 if fullrow else None}"> |
| 289 | 289 | <py:choose test="field.type" py:if="field"> |
| 290 | 290 | <select py:when="'select'" id="field-${field.name}" name="field_${field.name}"> |
| 291 | 291 | <option py:if="field.optional"></option> |
| … |
… |
|
| 302 | 302 | </select> |
| 303 | 303 | <textarea py:when="'textarea'" id="field-${field.name}" name="field_${field.name}" |
| 304 | 304 | cols="${field.width}" rows="${field.height}" |
| 305 | | class="${field.format == 'wiki' and 'wikitext ' or None}trac-resizable"> |
| | 305 | class="${'wikitext ' if field.format == 'wiki' else None}trac-resizable"> |
| 306 | 306 | ${value}</textarea> |
| 307 | 307 | <span py:when="'checkbox'"> |
| 308 | 308 | <input type="checkbox" id="field-${field.name}" name="field_${field.name}" |
| 309 | | checked="${value == '1' and 'checked' or None}" value="1" /> |
| | 309 | checked="${value == '1' or None}" value="1" /> |
| 310 | 310 | <input type="hidden" name="field_checkbox_${field.name}" value="1" /> |
| 311 | 311 | </span> |
| 312 | 312 | <label py:when="'radio'" |
| … |
… |
|
| 404 | 404 | <input type="hidden" name="cnum" value="${cnum}" /> |
| 405 | 405 | </py:if> |
| 406 | 406 | <input type="submit" name="preview" value="${_('Preview')}" accesskey="r" /> |
| 407 | | <input type="submit" name="submit" value="${ticket.exists and _('Submit changes') or _('Create ticket')}" /> |
| | 407 | <input type="submit" name="submit" value="${_('Submit changes') if ticket.exists else _('Create ticket')}" /> |
| 408 | 408 | </div> |
| 409 | 409 | |
| 410 | 410 | </form> |
-
diff --git a/trac/ticket/templates/ticket_box.html b/trac/ticket/templates/ticket_box.html
|
a
|
b
|
Arguments: |
| 14 | 14 | xmlns:py="http://genshi.edgewall.org/" |
| 15 | 15 | xmlns:xi="http://www.w3.org/2001/XInclude" |
| 16 | 16 | xmlns:i18n="http://genshi.edgewall.org/i18n" |
| 17 | | id="ticket" class="${preview_mode and 'ticketdraft' or None}"> |
| | 17 | id="ticket" class="${'ticketdraft' if preview_mode else None}"> |
| 18 | 18 | <div class="date"> |
| 19 | 19 | <p i18n:msg="created" py:if="ticket.exists">Opened ${dateinfo(ticket.time)} ago</p> |
| 20 | 20 | <p i18n:msg="modified" py:if="ticket.changetime != ticket.time">Last modified ${dateinfo(ticket.changetime)} ago</p> |
| … |
… |
Arguments: |
| 28 | 28 | <tr> |
| 29 | 29 | <th id="h_reporter">Reported by:</th> |
| 30 | 30 | <td headers="h_reporter" class="searchable"> |
| 31 | | ${defined('reporter_link') and reporter_link or authorinfo(ticket.reporter)} |
| | 31 | ${reporter_link if defined('reporter_link') else authorinfo(ticket.reporter)} |
| 32 | 32 | </td> |
| 33 | 33 | <th id="h_owner">Owned by:</th> |
| 34 | 34 | <td headers="h_owner"> |
| 35 | | ${ticket.owner and (defined('owner_link') and owner_link or authorinfo(ticket.owner)) or ''} |
| | 35 | ${(owner_link if defined('owner_link') else authorinfo(ticket.owner)) if ticket.owner else ''} |
| 36 | 36 | </td> |
| 37 | 37 | </tr> |
| 38 | 38 | <tr py:for="row in group(fields, 2, lambda f: f.type != 'textarea')" |
| 39 | 39 | py:with="fullrow = len(row) == 1"> |
| 40 | 40 | <py:for each="idx, field in enumerate(row)"> |
| 41 | 41 | <th py:if="idx == 0 or not fullrow" |
| 42 | | id="${field and 'h_' + field.name or None}"> |
| | 42 | id="${'h_' + field.name if field else None}"> |
| 43 | 43 | <py:if test="field"><i18n:msg params="field">${field.label or field.name}:</i18n:msg></py:if> |
| 44 | 44 | </th> |
| 45 | 45 | <td py:if="idx == 0 or not fullrow" |
| 46 | | headers="${field and 'h_' + field.name or None}" |
| 47 | | class="${field and field.name in ('cc', 'keywords') and 'searchable' or None}" |
| 48 | | colspan="${fullrow and 3 or None}"> |
| | 46 | headers="${'h_' + field.name if field else None}" |
| | 47 | class="${'searchable' if field and field.name in ('cc', 'keywords') else None}" |
| | 48 | colspan="${3 if fullrow else None}"> |
| 49 | 49 | <py:if test="field"> |
| 50 | 50 | <py:choose test=""> |
| 51 | 51 | <py:when test="'rendered' in field">${field.rendered}</py:when> |
-
diff --git a/trac/ticket/templates/ticket_change.html b/trac/ticket/templates/ticket_change.html
|
a
|
b
|
Arguments: |
| 38 | 38 | <form py:if="show_editor" id="trac-comment-editor" method="post" action="#comment:${change.cnum}"> |
| 39 | 39 | <div> |
| 40 | 40 | <textarea name="edited_comment" class="wikitext trac-resizable" rows="10" cols="78"> |
| 41 | | ${(edited_comment, change.comment)[edited_comment is None]}</textarea> |
| | 41 | ${edited_comment if edited_comment is not None else change.comment}</textarea> |
| 42 | 42 | <input type="hidden" name="cnum_edit" value="${change.cnum}"/> |
| 43 | 43 | </div> |
| 44 | 44 | <div class="buttons"> |
| … |
… |
Arguments: |
| 51 | 51 | </div> |
| 52 | 52 | </form> |
| 53 | 53 | <py:choose> |
| 54 | | <div py:when="str(change.cnum) == cnum_edit" py:with="text = (edited_comment, change.comment)[edited_comment is None]" |
| 55 | | class="comment searchable ticketdraft" style="${not text and 'display: none' or None}" xml:space="preserve"> |
| | 54 | <div py:when="str(change.cnum) == cnum_edit" |
| | 55 | py:with="text = edited_comment if edited_comment is not None else change.comment" |
| | 56 | class="comment searchable ticketdraft" style="${'display: none' if not text else None}" xml:space="preserve"> |
| 56 | 57 | ${wiki_to_html(context, text, escape_newlines=preserve_newlines)} |
| 57 | 58 | </div> |
| 58 | 59 | <div py:otherwise="" py:choose="" class="comment searchable" xml:space="preserve"> |
-
diff --git a/trac/ticket/templates/ticket_notify_email.txt b/trac/ticket/templates/ticket_notify_email.txt
|
a
|
b
|
|
| 19 | 19 | {% end %}\ |
| 20 | 20 | {% if change.comment %}\ |
| 21 | 21 | |
| 22 | | ${changes_body and _('Comment:') or _('Comment (by %(author)s):', author=change.author)} |
| | 22 | ${_('Comment:') if changes_body else _('Comment (by %(author)s):', author=change.author)} |
| 23 | 23 | |
| 24 | 24 | $change.comment |
| 25 | 25 | {% end %}\ |
-
diff --git a/trac/ticket/tests/notification.py b/trac/ticket/tests/notification.py
|
a
|
b
|
class NotificationTestCase(unittest.Test |
| 176 | 176 | def run_bcc_feature(public): |
| 177 | 177 | # CC list should be private |
| 178 | 178 | self.env.config.set('notification', 'use_public_cc', |
| 179 | | public and 'true' or 'false') |
| | 179 | 'true' if public else 'false') |
| 180 | 180 | self.env.config.set('notification', 'smtp_always_bcc', |
| 181 | 181 | 'joe.foobar@example.net') |
| 182 | 182 | ticket = Ticket(self.env) |
-
diff --git a/trac/ticket/web_ui.py b/trac/ticket/web_ui.py
|
a
|
b
|
class TicketModule(Component): |
| 576 | 576 | format = req.args.get('format') |
| 577 | 577 | if format: |
| 578 | 578 | # FIXME: mime.send_converted(context, ticket, 'ticket_x') (#3332) |
| 579 | | filename = ('t%d' % ticket.id, None)[format == 'rss'] |
| | 579 | filename = 't%d' % ticket.id if format != 'rss' else None |
| 580 | 580 | mime.send_converted(req, 'trac.ticket.Ticket', ticket, |
| 581 | 581 | format, filename=filename) |
| 582 | 582 | |
| … |
… |
class TicketModule(Component): |
| 848 | 848 | |
| 849 | 849 | for field in text_fields: |
| 850 | 850 | old_text = old_ticket.get(field) |
| 851 | | old_text = old_text and old_text.splitlines() or [] |
| | 851 | old_text = old_text.splitlines() if old_text else [] |
| 852 | 852 | new_text = new_ticket.get(field) |
| 853 | | new_text = new_text and new_text.splitlines() or [] |
| | 853 | new_text = new_text.splitlines() if new_text else [] |
| 854 | 854 | diffs = diff_blocks(old_text, new_text, context=diff_context, |
| 855 | 855 | ignore_blank_lines='-B' in diff_options, |
| 856 | 856 | ignore_case='-i' in diff_options, |
| … |
… |
class TicketModule(Component): |
| 894 | 894 | |
| 895 | 895 | def _make_comment_url(self, req, ticket, cnum, version=None): |
| 896 | 896 | return req.href.ticket(ticket.id, |
| 897 | | cnum_hist=version is not None and cnum or None, |
| | 897 | cnum_hist=cnum if version is not None else None, |
| 898 | 898 | cversion=version) + '#comment:%d' % cnum |
| 899 | 899 | |
| 900 | 900 | def _get_comment_history(self, req, ticket, cnum): |
| … |
… |
class TicketModule(Component): |
| 902 | 902 | for version, date, author, comment in ticket.get_comment_history(cnum): |
| 903 | 903 | history.append({ |
| 904 | 904 | 'version': version, 'date': date, 'author': author, |
| 905 | | 'comment': version == 0 and _("''Initial version''") or '', |
| | 905 | 'comment': _("''Initial version''") if version == 0 else '', |
| 906 | 906 | 'value': comment, |
| 907 | 907 | 'url': self._make_comment_url(req, ticket, cnum, version) |
| 908 | 908 | }) |
| … |
… |
class TicketModule(Component): |
| 962 | 962 | def get_text(version): |
| 963 | 963 | try: |
| 964 | 964 | text = history[version]['value'] |
| 965 | | return text and text.splitlines() or [] |
| | 965 | return text.splitlines() if text else [] |
| 966 | 966 | except KeyError: |
| 967 | 967 | raise ResourceNotFound(_("No version %(version)d for comment " |
| 968 | 968 | "%(cnum)d on ticket #%(ticket)s", |
| … |
… |
class TicketModule(Component): |
| 1243 | 1243 | if ticket.save_changes(get_reporter_id(req, 'author'), |
| 1244 | 1244 | req.args.get('comment'), when=now, |
| 1245 | 1245 | cnum=internal_cnum): |
| 1246 | | fragment = cnum and '#comment:' + cnum or '' |
| | 1246 | fragment = '#comment:' + cnum if cnum else '' |
| 1247 | 1247 | try: |
| 1248 | 1248 | tn = TicketNotifyEmail(self.env) |
| 1249 | 1249 | tn.notify(ticket, newticket=False, modtime=now) |
| … |
… |
class TicketModule(Component): |
| 1420 | 1420 | value = ticket.values.get(name) |
| 1421 | 1421 | if value in ('1', '0'): |
| 1422 | 1422 | field['rendered'] = self._query_link(req, name, value, |
| 1423 | | value == '1' and _("yes") or _("no")) |
| | 1423 | _("yes") if value == '1' else _("no")) |
| 1424 | 1424 | elif type_ == 'text': |
| 1425 | 1425 | if field.get('format') == 'wiki': |
| 1426 | 1426 | field['rendered'] = format_to_oneliner(self.env, context, |
| … |
… |
class TicketModule(Component): |
| 1606 | 1606 | type_ = f['type'] |
| 1607 | 1607 | break |
| 1608 | 1608 | if type_ == 'checkbox': |
| 1609 | | rendered = new == '1' and _("set") or _("unset") |
| | 1609 | rendered = _("set") if new == '1' else _("unset") |
| 1610 | 1610 | elif type_ == 'textarea': |
| 1611 | 1611 | if not resource_new: |
| 1612 | 1612 | rendered = _("modified") |
| … |
… |
class TicketModule(Component): |
| 1667 | 1667 | autonum = 0 # used for "root" numbers |
| 1668 | 1668 | last_uid = current = None |
| 1669 | 1669 | for date, author, field, old, new, permanent in changelog: |
| 1670 | | uid = permanent and (date,) or (date, author) |
| | 1670 | uid = (date,) if permanent else (date, author) |
| 1671 | 1671 | if uid != last_uid: |
| 1672 | 1672 | if current: |
| 1673 | 1673 | last_comment = comment_history[max(comment_history)] |
-
diff --git a/trac/timeline/templates/timeline.html b/trac/timeline/templates/timeline.html
|
a
|
b
|
|
| 33 | 33 | </form> |
| 34 | 34 | |
| 35 | 35 | <py:for each="day, events in groupby(events, key=lambda e: format_date(e.date))"> |
| 36 | | <h2>${day}: ${day == today and _("Today") or day == yesterday and _("Yesterday") or None}</h2> |
| | 36 | <h2>${day}: ${_("Today") if day == today else _("Yesterday") if day == yesterday else None}</h2> |
| 37 | 37 | <dl py:for="unread, events in groupby(events, key=lambda e: lastvisit and lastvisit < e.dateuid)" |
| 38 | | class="${unread and 'unread' or None}"> |
| | 38 | class="${'unread' if unread else None}"> |
| 39 | 39 | <py:for each="event in events" |
| 40 | 40 | py:with="highlight = precision and precisedate and timedelta(0) <= (event.date - precisedate) < precision"> |
| 41 | 41 | <dt class="${classes(event.kind, highlight=highlight, unread=unread)}"> |
-
diff --git a/trac/timeline/web_ui.py b/trac/timeline/web_ui.py
|
a
|
b
|
class TimelineModule(Component): |
| 90 | 90 | req.perm.assert_permission('TIMELINE_VIEW') |
| 91 | 91 | |
| 92 | 92 | format = req.args.get('format') |
| 93 | | maxrows = int(req.args.get('max', format == 'rss' and 50 or 0)) |
| | 93 | maxrows = int(req.args.get('max', 50 if format == 'rss' else 0)) |
| 94 | 94 | lastvisit = int(req.session.get('timeline.lastvisit', '0')) |
| 95 | 95 | |
| 96 | 96 | # indication of new events is unchanged when form is updated by user |
| … |
… |
class TimelineModule(Component): |
| 123 | 123 | microsecond=999999) |
| 124 | 124 | |
| 125 | 125 | daysback = as_int(req.args.get('daysback'), |
| 126 | | format == 'rss' and 90 or None) |
| | 126 | 90 if format == 'rss' else None) |
| 127 | 127 | if daysback is None: |
| 128 | 128 | daysback = as_int(req.session.get('timeline.daysback'), None) |
| 129 | 129 | if daysback is None: |
| … |
… |
class TimelineModule(Component): |
| 188 | 188 | for event in provider.get_timeline_events(req, start, stop, |
| 189 | 189 | filters) or []: |
| 190 | 190 | # Check for 0.10 events |
| 191 | | author = (event[len(event) < 6 and 2 or 4] or '').lower() |
| | 191 | author = (event[2 if len(event) < 6 else 4] or '').lower() |
| 192 | 192 | if (not include or author in include) \ |
| 193 | 193 | and not author in exclude: |
| 194 | 194 | events.append(self._event_data(provider, event)) |
-
diff --git a/trac/util/__init__.py b/trac/util/__init__.py
|
a
|
b
|
def get_doc(obj): |
| 496 | 496 | return (None, None) |
| 497 | 497 | doc = to_unicode(doc).split('\n\n', 1) |
| 498 | 498 | summary = doc[0].replace('\n', ' ') |
| 499 | | description = len(doc) > 1 and doc[1] or None |
| | 499 | description = doc[1] if len(doc) > 1 else None |
| 500 | 500 | return (summary, description) |
| 501 | 501 | |
| 502 | 502 | # -- setuptools utils |
-
diff --git a/trac/util/datefmt.py b/trac/util/datefmt.py
|
a
|
b
|
def _parse_date_iso8601(text, tzinfo): |
| 308 | 308 | if tz == 0: |
| 309 | 309 | tzinfo = utc |
| 310 | 310 | else: |
| 311 | | tzinfo = FixedOffset(tzsign == '-' and -tz or tz, |
| | 311 | tzinfo = FixedOffset(-tz if tzsign == '-' else tz, |
| 312 | 312 | '%s%s:%s' % |
| 313 | 313 | (tzsign, tzhours, tzminutes)) |
| 314 | 314 | tm = time.strptime('%s ' * 6 % (years, months, days, |
-
diff --git a/trac/util/text.py b/trac/util/text.py
|
a
|
b
|
def text_width(text, ambiwidth=1): |
| 203 | 203 | |
| 204 | 204 | cf. http://www.unicode.org/reports/tr11/. |
| 205 | 205 | """ |
| 206 | | twice = ('FW', 'FWA')[ambiwidth == 2] |
| 207 | | return sum([(1, 2)[east_asian_width(chr) in twice] |
| | 206 | twice = 'FWA' if ambiwidth == 2 else 'FW' |
| | 207 | return sum([2 if east_asian_width(chr) in twice else 1 |
| 208 | 208 | for chr in to_unicode(text)]) |
| 209 | 209 | |
| 210 | 210 | def print_table(data, headers=None, sep=' ', out=None): |
| … |
… |
def obfuscate_email_address(address): |
| 419 | 419 | at = address.find('@') |
| 420 | 420 | if at != -1: |
| 421 | 421 | return address[:at] + u'@\u2026' + \ |
| 422 | | (address[-1] == '>' and '>' or '') |
| | 422 | ('>' if address[-1] == '>' else '') |
| 423 | 423 | return address |
| 424 | 424 | |
| 425 | 425 | def breakable_path(path): |
-
diff --git a/trac/util/translation.py b/trac/util/translation.py
|
a
|
b
|
|
| 11 | 11 | # individuals. For the exact contribution history, see the revision |
| 12 | 12 | # history and logs, available at http://trac.edgewall.org/log/. |
| 13 | 13 | |
| | 14 | """Utilities for text translation with gettext.""" |
| | 15 | |
| 14 | 16 | from __future__ import with_statement |
| 15 | 17 | |
| 16 | | """Utilities for text translation with gettext.""" |
| 17 | | |
| 18 | 18 | import pkg_resources |
| 19 | 19 | import re |
| 20 | 20 | |
| … |
… |
def dgettext_noop(domain, string, **kwar |
| 44 | 44 | N_ = _noop = lambda string: string |
| 45 | 45 | |
| 46 | 46 | def ngettext_noop(singular, plural, num, **kwargs): |
| 47 | | string = (plural, singular)[num == 1] |
| | 47 | string = singular if num == 1 else plural |
| 48 | 48 | kwargs.setdefault('num', num) |
| 49 | 49 | return safefmt(string, kwargs) |
| 50 | 50 | |
| … |
… |
def _tag_kwargs(trans, kwargs): |
| 59 | 59 | return tag(*trans_elts) |
| 60 | 60 | |
| 61 | 61 | def tgettext_noop(string, **kwargs): |
| 62 | | return kwargs and _tag_kwargs(string, kwargs) or string |
| | 62 | return _tag_kwargs(string, kwargs) if kwargs else string |
| 63 | 63 | |
| 64 | 64 | def dtgettext_noop(domain, string, **kwargs): |
| 65 | 65 | return tgettext_noop(string, **kwargs) |
| 66 | 66 | |
| 67 | 67 | def tngettext_noop(singular, plural, num, **kwargs): |
| 68 | | string = (plural, singular)[num == 1] |
| | 68 | string = singular if num == 1 else plural |
| 69 | 69 | kwargs.setdefault('num', num) |
| 70 | 70 | return _tag_kwargs(string, kwargs) |
| 71 | 71 | |
| … |
… |
try: |
| 221 | 221 | def tgettext(self, string, **kwargs): |
| 222 | 222 | def _tgettext(): |
| 223 | 223 | trans = self.active.ugettext(string) |
| 224 | | return kwargs and _tag_kwargs(trans, kwargs) or trans |
| | 224 | return _tag_kwargs(trans, kwargs) if kwargs else trans |
| 225 | 225 | if not self.isactive: |
| 226 | 226 | return LazyProxy(_tgettext) |
| 227 | 227 | return _tgettext() |
| … |
… |
try: |
| 229 | 229 | def dtgettext(self, domain, string, **kwargs): |
| 230 | 230 | def _dtgettext(): |
| 231 | 231 | trans = self.active.dugettext(domain, string) |
| 232 | | return kwargs and _tag_kwargs(trans, kwargs) or trans |
| | 232 | return _tag_kwargs(trans, kwargs) if kwargs else trans |
| 233 | 233 | if not self.isactive: |
| 234 | 234 | return LazyProxy(_dtgettext) |
| 235 | 235 | return _dtgettext() |
| … |
… |
try: |
| 250 | 250 | trans = self.active.dungettext(domain, singular, plural, num) |
| 251 | 251 | if '%(num)' in trans: |
| 252 | 252 | kwargs.update(num=num) |
| 253 | | return kwargs and _tag_kwargs(trans, kwargs) or trans |
| | 253 | return _tag_kwargs(trans, kwargs) if kwargs else trans |
| 254 | 254 | if not self.isactive: |
| 255 | 255 | return LazyProxy(_dtngettext) |
| 256 | 256 | return _dtngettext() |
-
diff --git a/trac/versioncontrol/admin.py b/trac/versioncontrol/admin.py
|
a
|
b
|
class RepositoryAdminPanel(Component): |
| 189 | 189 | |
| 190 | 190 | if path_info: |
| 191 | 191 | # Detail view |
| 192 | | reponame = not is_default(path_info) and path_info or '' |
| | 192 | reponame = path_info if not is_default(path_info) else '' |
| 193 | 193 | info = all_repos.get(reponame) |
| 194 | 194 | if info is None: |
| 195 | 195 | raise TracError(_("Repository '%(repo)s' not found", |
-
diff --git a/trac/versioncontrol/api.py b/trac/versioncontrol/api.py
|
a
|
b
|
class RepositoryManager(Component): |
| 386 | 386 | kind = _("path") |
| 387 | 387 | if resource.version: |
| 388 | 388 | version = '@%s' % resource.version |
| 389 | | in_repo = reponame and _(" in %(repo)s", repo=reponame) or '' |
| | 389 | in_repo = _(" in %(repo)s", repo=reponame) if reponame else '' |
| 390 | 390 | # TRANSLATOR: file /path/to/file.py at version 13 in reponame |
| 391 | 391 | return _('%(kind)s %(id)s%(at_version)s%(in_repo)s', |
| 392 | 392 | kind=kind, id=id, at_version=version, in_repo=in_repo) |
| … |
… |
class RepositoryManager(Component): |
| 551 | 551 | been truncated, if needed. |
| 552 | 552 | """ |
| 553 | 553 | matches = [] |
| 554 | | path = path and path.strip('/') + '/' or '/' |
| | 554 | path = path.strip('/') + '/' if path else '/' |
| 555 | 555 | for reponame in self.get_all_repositories().keys(): |
| 556 | 556 | stripped_reponame = reponame.strip('/') + '/' |
| 557 | 557 | if path.startswith(stripped_reponame): |
| … |
… |
class Node(object): |
| 1061 | 1061 | |
| 1062 | 1062 | def is_viewable(self, perm): |
| 1063 | 1063 | """Return True if view permission is granted on the node.""" |
| 1064 | | return (self.isdir and 'BROWSER_VIEW' or 'FILE_VIEW') \ |
| | 1064 | return ('BROWSER_VIEW' if self.isdir else 'FILE_VIEW') \ |
| 1065 | 1065 | in perm(self.resource) |
| 1066 | 1066 | |
| 1067 | 1067 | can_view = is_viewable # 0.12 compatibility |
-
diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py
|
a
|
b
|
class CachedRepository(Repository): |
| 346 | 346 | for i in range(1, len(components) + 1): |
| 347 | 347 | args.append('/'.join(components[:i])) |
| 348 | 348 | |
| 349 | | sql += " ORDER BY rev" + (direction == '<' and " DESC" or "") \ |
| | 349 | sql += " ORDER BY rev" + (" DESC" if direction == '<' else "") \ |
| 350 | 350 | + " LIMIT 1" |
| 351 | 351 | |
| 352 | 352 | for rev, in db(sql, args): |
-
diff --git a/trac/versioncontrol/diff.py b/trac/versioncontrol/diff.py
|
a
|
b
|
def get_diff_options(req): |
| 331 | 331 | |
| 332 | 332 | arg = int(req.args.get('contextall', 0)) |
| 333 | 333 | options_data['contextall'] = arg |
| 334 | | options = ['-U%d' % (arg and -1 or context)] |
| | 334 | options = ['-U%d' % (-1 if arg else context)] |
| 335 | 335 | |
| 336 | 336 | arg = get_bool_option('ignoreblanklines') |
| 337 | 337 | if arg: |
-
diff --git a/trac/versioncontrol/svn_authz.py b/trac/versioncontrol/svn_authz.py
|
a
|
b
|
def parse(authz, modules): |
| 83 | 83 | aliases[name] = value.strip() |
| 84 | 84 | else: |
| 85 | 85 | parts = section.split(':', 1) |
| 86 | | module, path = len(parts) > 1 and parts[0] or '', parts[-1] |
| | 86 | module, path = parts[0] if len(parts) > 1 else '', parts[-1] |
| 87 | 87 | if module in modules: |
| 88 | 88 | sections.setdefault((module, path), []).append((name, value)) |
| 89 | 89 | |
| … |
… |
class AuthzSourcePolicy(Component): |
| 149 | 149 | # IPermissionPolicy methods |
| 150 | 150 | |
| 151 | 151 | def check_permission(self, action, username, resource, perm): |
| 152 | | realm = resource and resource.realm or None |
| | 152 | realm = resource.realm if resource else None |
| 153 | 153 | if (realm, action) in self._handled_perms: |
| 154 | 154 | authz, users = self._get_authz_info() |
| 155 | 155 | if authz is None: |
| … |
… |
class AuthzSourcePolicy(Component): |
| 160 | 160 | else: |
| 161 | 161 | usernames = (username, '$authenticated', '*') |
| 162 | 162 | if resource is None: |
| 163 | | return users & set(usernames) and True or None |
| | 163 | return True if users & set(usernames) else None |
| 164 | 164 | |
| 165 | 165 | rm = RepositoryManager(self.env) |
| 166 | 166 | try: |
-
diff --git a/trac/versioncontrol/svn_fs.py b/trac/versioncontrol/svn_fs.py
|
a
|
b
|
def _is_path_within_scope(scope, fullpat |
| 117 | 117 | """Check whether the given `fullpath` is within the given `scope`""" |
| 118 | 118 | if scope == '/': |
| 119 | 119 | return fullpath is not None |
| 120 | | fullpath = fullpath and fullpath.lstrip('/') or '' |
| | 120 | fullpath = fullpath.lstrip('/') if fullpath else '' |
| 121 | 121 | scope = scope.strip('/') |
| 122 | 122 | return (fullpath + '/').startswith(scope + '/') |
| 123 | 123 | |
| … |
… |
class SubversionRepository(Repository): |
| 360 | 360 | self.scope = '/' |
| 361 | 361 | assert self.scope[0] == '/' |
| 362 | 362 | # we keep root_path_utf8 for RA |
| 363 | | ra_prefix = os.name == 'nt' and 'file:///' or 'file://' |
| | 363 | ra_prefix = 'file:///' if os.name == 'nt' else 'file://' |
| 364 | 364 | self.ra_url_utf8 = ra_prefix + root_path_utf8 |
| 365 | 365 | self.clear() |
| 366 | 366 | |
-
diff --git a/trac/versioncontrol/svn_prop.py b/trac/versioncontrol/svn_prop.py
|
a
|
b
|
class SubversionPropertyRenderer(Compone |
| 79 | 79 | def match_property(self, name, mode): |
| 80 | 80 | if name in ('svn:externals', 'svn:needs-lock'): |
| 81 | 81 | return 4 |
| 82 | | return name in ('svn:mergeinfo', 'svnmerge-blocked', |
| 83 | | 'svnmerge-integrated') and 2 or 0 |
| | 82 | return 2 if name in ('svn:mergeinfo', 'svnmerge-blocked', |
| | 83 | 'svnmerge-integrated') else 0 |
| 84 | 84 | |
| 85 | 85 | def render_property(self, name, mode, context, props): |
| 86 | 86 | if name == 'svn:externals': |
| … |
… |
class SubversionPropertyRenderer(Compone |
| 124 | 124 | base_url, pref = posixpath.split(base_url) |
| 125 | 125 | prefix.append(pref) |
| 126 | 126 | href = self._externals_map.get(base_url) |
| 127 | | revstr = rev and ' at revision '+rev or '' |
| | 127 | revstr = ' at revision ' + rev if rev else '' |
| 128 | 128 | if not href and (url.startswith('http://') or |
| 129 | 129 | url.startswith('https://')): |
| 130 | 130 | href = url.replace('%', '%%') |
| … |
… |
class SubversionMergePropertyRenderer(Co |
| 175 | 175 | # IPropertyRenderer methods |
| 176 | 176 | |
| 177 | 177 | def match_property(self, name, mode): |
| 178 | | return name in ('svn:mergeinfo', 'svnmerge-blocked', |
| 179 | | 'svnmerge-integrated') and 4 or 0 |
| | 178 | return 4 if name in ('svn:mergeinfo', 'svnmerge-blocked', |
| | 179 | 'svnmerge-integrated') else 0 |
| 180 | 180 | |
| 181 | 181 | def render_property(self, name, mode, context, props): |
| 182 | 182 | """Parse svn:mergeinfo and svnmerge-* properties, converting branch |
| … |
… |
class SubversionMergePropertyRenderer(Co |
| 184 | 184 | and eligible revisions. |
| 185 | 185 | """ |
| 186 | 186 | has_eligible = name in ('svnmerge-integrated', 'svn:mergeinfo') |
| 187 | | revs_label = (_('merged'), _('blocked'))[name.endswith('blocked')] |
| 188 | | revs_cols = has_eligible and 2 or None |
| | 187 | revs_label = _('blocked') if name.endswith('blocked') else _('merged') |
| | 188 | revs_cols = 2 if has_eligible else None |
| 189 | 189 | reponame = context.resource.parent.id |
| 190 | 190 | target_path = context.resource.id |
| 191 | 191 | repos = RepositoryManager(self.env).get_repository(reponame) |
| … |
… |
class SubversionMergePropertyRenderer(Co |
| 249 | 249 | if not rows: |
| 250 | 250 | return None |
| 251 | 251 | rows.sort() |
| 252 | | has_deleted = rows and rows[-1][0] or None |
| | 252 | has_deleted = rows[-1][0] if rows else None |
| 253 | 253 | return tag(has_deleted and tag.a(_('(toggle deleted branches)'), |
| 254 | 254 | class_='trac-toggledeleted', |
| 255 | 255 | href='#'), |
| 256 | 256 | tag.table(tag.tbody( |
| 257 | | [tag.tr(row, class_=deleted and 'trac-deleted' or None) |
| | 257 | [tag.tr(row, class_='trac-deleted' if deleted else None) |
| 258 | 258 | for deleted, spath, row in rows]), class_='props')) |
| 259 | 259 | |
| 260 | 260 | |
| … |
… |
class SubversionMergePropertyDiffRendere |
| 318 | 318 | # IPropertyDiffRenderer methods |
| 319 | 319 | |
| 320 | 320 | def match_property_diff(self, name): |
| 321 | | return name in ('svn:mergeinfo', 'svnmerge-blocked', |
| 322 | | 'svnmerge-integrated') and 4 or 0 |
| | 321 | return 4 if name in ('svn:mergeinfo', 'svnmerge-blocked', |
| | 322 | 'svnmerge-integrated') else 0 |
| 323 | 323 | |
| 324 | 324 | def render_property_diff(self, name, old_context, old_props, |
| 325 | 325 | new_context, new_props, options): |
-
diff --git a/trac/versioncontrol/templates/admin_repositories.html b/trac/versioncontrol/templates/admin_repositories.html
|
a
|
b
|
|
| 131 | 131 | <td class="name"> |
| 132 | 132 | <a href="${panel_href(info.name or '(default)')}">${info.name or _('(default)')}</a> |
| 133 | 133 | </td> |
| 134 | | <td>${not info.alias and (info.type or _('(default)')) or None}</td> |
| | 134 | <td>${(info.type or _('(default)')) if not info.alias else None}</td> |
| 135 | 135 | <td py:choose=""> |
| 136 | 136 | <py:when test="info.dir">$info.prettydir</py:when> |
| 137 | 137 | <em py:otherwise="" i18n:msg="repo">Alias of ${info.alias or _('(default)')}</em> |
-
diff --git a/trac/versioncontrol/templates/browser.html b/trac/versioncontrol/templates/browser.html
|
a
|
b
|
|
| 73 | 73 | <div id="jumprev"> |
| 74 | 74 | <form action="" method="get"> |
| 75 | 75 | <div> |
| 76 | | <label for="rev" title="${stickyrev and _('Hint: clear the field to view latest revision') or None}"> |
| | 76 | <label for="rev" title="${_('Hint: clear the field to view latest revision') if stickyrev else None}"> |
| 77 | 77 | View revision:</label> |
| 78 | 78 | <input type="text" id="rev" name="rev" value="$stickyrev" size="6" /> |
| 79 | 79 | </div> |
-
diff --git a/trac/versioncontrol/templates/changeset.html b/trac/versioncontrol/templates/changeset.html
|
a
|
b
|
|
| 78 | 78 | |
| 79 | 79 | <form py:if="not xhr and (has_diffs or diff.options.ignoreblanklines or diff.options.ignorecase or |
| 80 | 80 | diff.options.ignorewhitespace)" |
| 81 | | id="prefs" action=""> |
| | 81 | id="prefs" action=""> |
| 82 | 82 | <div> |
| 83 | 83 | <py:if test="not changeset"> |
| 84 | 84 | <input type="hidden" name="old_path" value="${'/' + pathjoin(reponame, old_path)}" /> |
| … |
… |
|
| 91 | 91 | </form> |
| 92 | 92 | |
| 93 | 93 | <py:def function="node_change(idx,item,cl,kind)"> |
| 94 | | <py:with vars="ndiffs = item.diffs is not None and len(item.diffs) or 0; |
| | 94 | <py:with vars="ndiffs = len(item.diffs) if item.diffs is not None else 0; |
| 95 | 95 | nprops = len(item.props); |
| 96 | 96 | is_removal = cl == 'rem'; |
| 97 | | path = is_removal and item.old.get('path') or item.new.get('path'); |
| | 97 | path = item.old.get('path') if is_removal else item.new.get('path'); |
| 98 | 98 | path = path and path[len(location):].strip('/')"> |
| 99 | 99 | <div class="$cl"> </div> |
| 100 | 100 | <py:choose> |
| 101 | | <a py:when="is_removal" href="$item.old.href" |
| 102 | | title="${_('Show what was removed (content at revision %(old_rev)s)', old_rev=display_rev(item.old.rev))}"> |
| | 101 | <a py:when="is_removal" href="$item.old.href" |
| | 102 | title="${_('Show what was removed (content at revision %(old_rev)s)', old_rev=display_rev(item.old.rev))}"> |
| 103 | 103 | $path |
| 104 | 104 | </a> |
| 105 | 105 | <a py:otherwise="" title="Show entry in browser" href="$item.new.href"> |
| … |
… |
|
| 120 | 120 | </py:when> |
| 121 | 121 | <py:when test="ndiffs + nprops > 0"> |
| 122 | 122 | (<a title="Show differences" href="#file$idx">${ |
| 123 | | ndiffs and ngettext('%(num)d diff', '%(num)d diffs', ndiffs) or None}${ |
| 124 | | (ndiffs and nprops) and ', ' or '' |
| 125 | | }${nprops and ngettext('%(num)d prop', '%(num)d props', nprops) or None}</a>) |
| | 123 | ngettext('%(num)d diff', '%(num)d diffs', ndiffs) if ndiffs else None}${ |
| | 124 | ', ' if ndiffs and nprops else None |
| | 125 | }${ngettext('%(num)d prop', '%(num)d props', nprops) if nprops else None}</a>) |
| 126 | 126 | </py:when> |
| 127 | 127 | </py:choose> |
| 128 | 128 | <py:if test="cl == 'mod' and item.diffs is None"> |
| … |
… |
|
| 167 | 167 | <dd class="searchable"><a href="${href.browser(reponame, location, rev=new_rev)}">$location</a></dd> |
| 168 | 168 | </py:if> |
| 169 | 169 | <dt class="property files"> |
| 170 | | ${files and ngettext('File:', 'Files:', num=len(files)) or _('(No files)')} |
| | 170 | ${ngettext('File:', 'Files:', num=len(files)) if files else _('(No files)')} |
| 171 | 171 | </dt> |
| 172 | 172 | <dd class="files"> |
| 173 | 173 | <div class="legend" id="file-legend" py:if="filestats"> |
-
diff --git a/trac/versioncontrol/templates/dir_entries.html b/trac/versioncontrol/templates/dir_entries.html
|
a
|
b
|
|
| 7 | 7 | chgset_context = change and context.child('changeset', change.rev, parent=repos.resource); |
| 8 | 8 | chgset_view = change and change.is_viewable(perm); |
| 9 | 9 | isdir = entry.kind == 'dir'"> |
| 10 | | <tr class="${idx % 2 and 'even' or 'odd'}"> |
| | 10 | <tr class="${'odd' if idx % 2 else 'even'}"> |
| 11 | 11 | <td class="name"> |
| 12 | 12 | <a class="$entry.kind" title="${_('View Directory') if isdir else _('View File')}" |
| 13 | 13 | href="${href.browser(reponame, entry.path, rev=stickyrev, |
| 14 | | order=(order != 'name' and order or None), desc=desc)}">$entry.name</a> |
| | 14 | order=order if order != 'name' else None, desc=desc)}">$entry.name</a> |
| 15 | 15 | </td> |
| 16 | 16 | <td class="size"> |
| 17 | 17 | <span title="${_('%(size)s bytes', size=entry.content_length)}">${pretty_size(entry.content_length)}</span> |
| … |
… |
|
| 24 | 24 | </td> |
| 25 | 25 | <td class="age" style="${chgset_view and dir.timerange and 'border-color: rgb(%s,%s,%s)' % |
| 26 | 26 | dir.colorize_age(dir.timerange.relative(change.date)) or None}"> |
| 27 | | ${chgset_view and dateinfo(change.date) or '–'} |
| | 27 | ${dateinfo(change.date) if chgset_view else '–'} |
| 28 | 28 | </td> |
| 29 | | <td class="author">${chgset_view and authorinfo_short(change.author) or '–'}</td> |
| | 29 | <td class="author">${authorinfo_short(change.author) if chgset_view else '–'}</td> |
| 30 | 30 | <td class="change" py:choose=""> |
| 31 | 31 | <py:when test="chgset_view" py:choose=""> |
| 32 | 32 | <py:when test="wiki_format_messages">${wiki_to_oneliner(chgset_context, change.message, shorten=True)}</py:when> |
-
diff --git a/trac/versioncontrol/templates/repository_index.html b/trac/versioncontrol/templates/repository_index.html
|
a
|
b
|
|
| 8 | 8 | <py:for each="idx, (reponame, repoinfo, repos, change, err, raw_href) in enumerate(repo.repositories)" |
| 9 | 9 | py:with="chgset_context = change and context.child('changeset', change.rev, parent=repos.resource); |
| 10 | 10 | chgset_view = change and change.is_viewable(perm)"> |
| 11 | | <tr class="${idx % 2 and 'even' or 'odd'}"> |
| | 11 | <tr class="${'odd' if idx % 2 else 'even'}"> |
| 12 | 12 | <td class="name"> |
| 13 | 13 | <em py:strip="not err"> |
| 14 | 14 | <b py:strip="repoinfo.alias != ''"> |
| 15 | 15 | <a class="dir" title="View Root Directory" |
| 16 | 16 | href="${href.browser(repos.reponame if repos else reponame, |
| 17 | | order=(order != 'name' and order or None), desc=desc)}">$reponame</a> |
| | 17 | order=order if order != 'name' else None, desc=desc)}">$reponame</a> |
| 18 | 18 | </b> |
| 19 | 19 | </em> |
| 20 | 20 | </td> |
| … |
… |
|
| 29 | 29 | </td> |
| 30 | 30 | <td class="age" style="${chgset_view and change and repo.timerange and 'border-color: rgb(%s,%s,%s)' % |
| 31 | 31 | repo.colorize_age(repo.timerange.relative(change.date)) or None}"> |
| 32 | | ${chgset_view and dateinfo(change.date) or '–'} |
| | 32 | ${dateinfo(change.date) if chgset_view else '–'} |
| 33 | 33 | </td> |
| 34 | | <td class="author">${chgset_view and authorinfo_short(change.author) or '–'}</td> |
| | 34 | <td class="author">${authorinfo_short(change.author) if chgset_view else '–'}</td> |
| 35 | 35 | <td class="change" py:choose=""> |
| 36 | 36 | <py:when test="err"><em py:content="err"></em></py:when> |
| 37 | 37 | <py:when test="chgset_view" py:choose=""> |
| … |
… |
|
| 41 | 41 | <py:otherwise>–</py:otherwise> |
| 42 | 42 | </td> |
| 43 | 43 | </tr> |
| 44 | | <tr class="${idx % 2 and 'even' or 'odd'}" py:if="repoinfo.description"> |
| | 44 | <tr class="${'odd' if idx % 2 else 'even'}" py:if="repoinfo.description"> |
| 45 | 45 | <td class="description" colspan="6">${wiki_to_html(context.child('source', '/', parent=repos.resource), repoinfo.description)}</td> |
| 46 | 46 | </tr> |
| 47 | 47 | </py:for> |
-
diff --git a/trac/versioncontrol/templates/revisionlog.html b/trac/versioncontrol/templates/revisionlog.html
|
a
|
b
|
|
| 77 | 77 | </label> |
| 78 | 78 | </i18n:msg><br /> |
| 79 | 79 | <label> |
| 80 | | <input type="checkbox" id="verbose" name="verbose" checked="${verbose and 'checked' or None}" /> |
| | 80 | <input type="checkbox" id="verbose" name="verbose" checked="${verbose or None}" /> |
| 81 | 81 | Show full log messages |
| 82 | 82 | </label> |
| 83 | 83 | </div> |
| … |
… |
|
| 106 | 106 | <input type="submit" value="${_('View changes')}" |
| 107 | 107 | title="Diff from Old Revision to New Revision (as selected in the Diff column)" /> |
| 108 | 108 | </div> |
| 109 | | <table class="listing chglist${graph and ' trac-graph' or None}"> |
| | 109 | <table class="listing chglist${' trac-graph' if graph else None}"> |
| 110 | 110 | <thead> |
| 111 | 111 | <tr> |
| 112 | 112 | <th py:if="graph" class="trac-graph">Graph</th> |
| … |
… |
|
| 132 | 132 | <py:with vars="change = changes[item.rev]; |
| 133 | 133 | is_separator = item.change is None; |
| 134 | 134 | chgset_context = context.child('changeset', change.rev, parent=repos.resource); |
| 135 | | odd_even = idx % 2 and 'odd' or 'even'"> |
| | 135 | odd_even = 'odd' if idx % 2 else 'even'"> |
| 136 | 136 | <!--! highlight copy or rename operations --> |
| 137 | 137 | <tr py:if="not is_separator and item.get('copyfrom_path')" class="$odd_even"> |
| 138 | 138 | <td /> |
-
diff --git a/trac/versioncontrol/templates/revisionlog.txt b/trac/versioncontrol/templates/revisionlog.txt
|
a
|
b
|
|
| 1 | 1 | # |
| 2 | | # ${_('ChangeLog for %(path)s%(in_repo)s', path=path, in_repo=reponame and _(" in %(repo)s", repo=reponame) or '')} |
| | 2 | # ${_("ChangeLog for %(path)s in %(repo)s", path=path, repo=reponame) if reponame \ |
| | 3 | else _("ChangeLog for %(path)s", path=path)} |
| 3 | 4 | # |
| 4 | 5 | # ${_('Generated by Trac %(version)s', version=trac.version)} |
| 5 | 6 | # ${format_datetime()} |
| … |
… |
|
| 14 | 15 | {% end %}\ |
| 15 | 16 | {% end %}\ |
| 16 | 17 | |
| 17 | | ${verbose and extra.message or shorten_line(extra.message)} |
| | 18 | ${extra.message if verbose else shorten_line(extra.message)} |
| 18 | 19 | |
| 19 | 20 | |
| 20 | 21 | {% end %}\ |
-
diff --git a/trac/versioncontrol/templates/sortable_th.html b/trac/versioncontrol/templates/sortable_th.html
|
a
|
b
|
|
| 14 | 14 | <html xmlns="http://www.w3.org/1999/xhtml" |
| 15 | 15 | xmlns:py="http://genshi.edgewall.org/" |
| 16 | 16 | xmlns:xi="http://www.w3.org/2001/XInclude" py:strip=""> |
| 17 | | <th class="$class_${order == class_ and (desc and ' desc' or ' asc') or ''}"> |
| | 17 | <th class="$class_${(' desc' if desc else ' asc') if order == class_ else None}"> |
| 18 | 18 | <a title="${_('Sort by %(col)s %(direction)s', col=class_, |
| 19 | | direction=(order == class_ and not desc |
| 20 | | and _('(descending)') or _('(ascending)')))}" |
| 21 | | href="${href.browser(reponame, path, rev=stickyrev, order=(class_ != 'name' and class_ or None), |
| 22 | | desc=(class_ == order and not desc and 1 or None))}">$title</a> |
| | 19 | direction=_('(descending)') if order == class_ and not desc else _('(ascending)'))}" |
| | 20 | href="${href.browser(reponame, path, rev=stickyrev, order=class_ if class_ != 'name' else None, |
| | 21 | desc=1 if class_ == order and not desc else None)}">$title</a> |
| 23 | 22 | </th> |
| 24 | 23 | </html> |
-
diff --git a/trac/versioncontrol/web_ui/browser.py b/trac/versioncontrol/web_ui/browser.py
|
a
|
b
|
class WikiPropertyRenderer(Component): |
| 130 | 130 | (''since 0.11'')""") |
| 131 | 131 | |
| 132 | 132 | def match_property(self, name, mode): |
| 133 | | return (name in self.wiki_properties or \ |
| 134 | | name in self.oneliner_properties) and 4 or 0 |
| | 133 | return 4 if name in self.wiki_properties \ |
| | 134 | or name in self.oneliner_properties else 0 |
| 135 | 135 | |
| 136 | 136 | def render_property(self, name, mode, context, props): |
| 137 | 137 | if name in self.wiki_properties: |
| … |
… |
class BrowserModule(Component): |
| 258 | 258 | # Get three ints out of a `rgb` string or return `default` |
| 259 | 259 | try: |
| 260 | 260 | t = tuple([int(v) for v in re.split(r'(\d+)', rgb)[1::2]]) |
| 261 | | return len(t) == 3 and t or default |
| | 261 | return t if len(t) == 3 else default |
| 262 | 262 | except ValueError: |
| 263 | 263 | return default |
| 264 | 264 | |
| … |
… |
class BrowserModule(Component): |
| 355 | 355 | if reponame and reponame != repos.reponame: # Redirect alias |
| 356 | 356 | qs = req.query_string |
| 357 | 357 | req.redirect(req.href.browser(repos.reponame or None, path) |
| 358 | | + (qs and '?' + qs or '')) |
| 359 | | reponame = repos and repos.reponame or None |
| | 358 | + ('?' + qs if qs else '')) |
| | 359 | reponame = repos.reponame if repos else None |
| 360 | 360 | |
| 361 | 361 | # Find node for the requested path/rev |
| 362 | 362 | context = web_context(req) |
| … |
… |
class BrowserModule(Component): |
| 410 | 410 | 'created_rev': node and node.created_rev, |
| 411 | 411 | 'properties': properties_data, |
| 412 | 412 | 'path_links': path_links, |
| 413 | | 'order': order, 'desc': desc and 1 or None, |
| | 413 | 'order': order, 'desc': 1 if desc else None, |
| 414 | 414 | 'repo': repo_data, 'dir': dir_data, 'file': file_data, |
| 415 | 415 | 'quickjump_entries': quickjump_data, |
| 416 | 416 | 'wiki_format_messages': \ |
| … |
… |
class BrowserModule(Component): |
| 525 | 525 | # Ordering of repositories |
| 526 | 526 | if order == 'date': |
| 527 | 527 | def repo_order((reponame, repoinfo, repos, youngest, err, href)): |
| 528 | | return (youngest and youngest.date or to_datetime(0), |
| | 528 | return (youngest.date if youngest else to_datetime(0), |
| 529 | 529 | embedded_numbers(reponame.lower())) |
| 530 | 530 | elif order == 'author': |
| 531 | 531 | def repo_order((reponame, repoinfo, repos, youngest, err, href)): |
| 532 | | return (youngest and youngest.author.lower() or '', |
| | 532 | return (youngest.author.lower() if youngest else '', |
| 533 | 533 | embedded_numbers(reponame.lower())) |
| 534 | 534 | else: |
| 535 | 535 | def repo_order((reponame, repoinfo, repos, youngest, err, href)): |
| … |
… |
class BrowserModule(Component): |
| 592 | 592 | def file_order(a): |
| 593 | 593 | return embedded_numbers(a.name.lower()) |
| 594 | 594 | |
| 595 | | dir_order = desc and 1 or -1 |
| | 595 | dir_order = 1 if desc else -1 |
| 596 | 596 | |
| 597 | 597 | def browse_order(a): |
| 598 | | return a.isdir and dir_order or 0, file_order(a) |
| | 598 | return dir_order if a.isdir else 0, file_order(a) |
| 599 | 599 | entries = sorted(entries, key=browse_order, reverse=desc) |
| 600 | 600 | |
| 601 | 601 | # ''Zip Archive'' alternate link |
| … |
… |
class BrowserModule(Component): |
| 630 | 630 | if format in ('raw', 'txt'): |
| 631 | 631 | req.send_response(200) |
| 632 | 632 | req.send_header('Content-Type', |
| 633 | | format == 'txt' and 'text/plain' or mime_type) |
| | 633 | 'text/plain' if format == 'txt' else mime_type) |
| 634 | 634 | req.send_header('Content-Length', node.content_length) |
| 635 | 635 | req.send_header('Last-Modified', http_date(node.last_modified)) |
| 636 | 636 | if rev is None: |
| … |
… |
class BrowserModule(Component): |
| 877 | 877 | add_stylesheet(formatter.req, 'common/css/browser.css') |
| 878 | 878 | wiki_format_messages = self.config['changeset'] \ |
| 879 | 879 | .getbool('wiki_format_messages') |
| 880 | | data = {'repo': repo, 'order': order, 'desc': desc and 1 or None, |
| | 880 | data = {'repo': repo, 'order': order, 'desc': 1 if desc else None, |
| 881 | 881 | 'reponame': None, 'path': '/', 'stickyrev': None, |
| 882 | 882 | 'wiki_format_messages': wiki_format_messages} |
| 883 | 883 | from trac.web.chrome import Chrome |
-
diff --git a/trac/versioncontrol/web_ui/changeset.py b/trac/versioncontrol/web_ui/changeset.py
|
a
|
b
|
class ChangesetModule(Component): |
| 488 | 488 | def node_info(node, annotated): |
| 489 | 489 | href = req.href.browser( |
| 490 | 490 | reponame, node.created_path, rev=node.created_rev, |
| 491 | | annotate=annotated and 'blame' or None) |
| | 491 | annotate='blame' if annotated else None) |
| 492 | 492 | title = _('Show revision %(rev)s of this file in browser', |
| 493 | 493 | rev=display_rev(node.rev)) |
| 494 | 494 | return {'path': node.path, 'rev': node.rev, |
| … |
… |
class ChangesetModule(Component): |
| 628 | 628 | 'new': new_node and node_info(new_node, annotated), |
| 629 | 629 | 'props': props, |
| 630 | 630 | 'diffs': diffs} |
| 631 | | files.append(new_node and new_node.path or \ |
| 632 | | old_node and old_node.path or '') |
| | 631 | files.append(new_node.path if new_node else \ |
| | 632 | old_node.path if old_node else '') |
| 633 | 633 | filestats[change] += 1 |
| 634 | 634 | if change in Changeset.DIFF_CHANGES: |
| 635 | 635 | if chgset: |
| … |
… |
class ChangesetModule(Component): |
| 1005 | 1005 | if reponame or len(repos_for_uid) > 1: |
| 1006 | 1006 | title = ngettext('Changeset in %(repo)s ', |
| 1007 | 1007 | 'Changesets in %(repo)s ', |
| 1008 | | single and 1 or 2, repo=', '.join(repos_for_uid)) |
| | 1008 | 1 if single else 2, repo=', '.join(repos_for_uid)) |
| 1009 | 1009 | else: |
| 1010 | | title = ngettext('Changeset ', 'Changesets ', single and 1 or 2) |
| | 1010 | title = ngettext('Changeset ', 'Changesets ', 1 if single else 2) |
| 1011 | 1011 | drev_a = older_cset.repos.display_rev(rev_a) |
| 1012 | 1012 | if single: |
| 1013 | 1013 | title = tag(title, tag.em('[%s]' % drev_a)) |
| … |
… |
class ChangesetModule(Component): |
| 1045 | 1045 | r"(?:\b|!)r\d+\b(?!:\d)(?:/[a-zA-Z0-9_/+-]+)?", |
| 1046 | 1046 | lambda x, y, z: |
| 1047 | 1047 | self._format_changeset_link(x, 'changeset', |
| 1048 | | y[0] == 'r' and y[1:] or y[1:-1], |
| | 1048 | y[1:] if y[0] == 'r' else y[1:-1], |
| 1049 | 1049 | y, z)) |
| 1050 | 1050 | |
| 1051 | 1051 | def get_link_resolvers(self): |
| … |
… |
class AnyDiffModule(Component): |
| 1194 | 1194 | if repos.is_viewable(req.perm)) |
| 1195 | 1195 | |
| 1196 | 1196 | elem = tag.ul( |
| 1197 | | [tag.li(isdir and tag.b(path) or path) |
| | 1197 | [tag.li(tag.b(path) if isdir else path) |
| 1198 | 1198 | for (isdir, name, path) in sorted(entries, key=kind_order) |
| 1199 | 1199 | if name.lower().startswith(prefix)]) |
| 1200 | 1200 | |
-
diff --git a/trac/versioncontrol/web_ui/log.py b/trac/versioncontrol/web_ui/log.py
|
a
|
b
|
class LogModule(Component): |
| 96 | 96 | if reponame != repos.reponame: # Redirect alias |
| 97 | 97 | qs = req.query_string |
| 98 | 98 | req.redirect(req.href.log(repos.reponame or None, path) |
| 99 | | + (qs and '?' + qs or '')) |
| | 99 | + ('?' + qs if qs else '')) |
| 100 | 100 | |
| 101 | 101 | normpath = repos.normalize_path(path) |
| 102 | 102 | # if `revs` parameter is given, then we're restricted to the |
| … |
… |
class LogModule(Component): |
| 263 | 263 | files = [] |
| 264 | 264 | actions = [] |
| 265 | 265 | for cpath, kind, chg, bpath, brev in changeset.get_changes(): |
| 266 | | files.append(chg == Changeset.DELETE and bpath or cpath) |
| | 266 | files.append(bpath if chg == Changeset.DELETE else cpath) |
| 267 | 267 | actions.append(chg) |
| 268 | 268 | cs['files'] = files |
| 269 | 269 | cs['actions'] = actions |
-
diff --git a/trac/versioncontrol/web_ui/util.py b/trac/versioncontrol/web_ui/util.py
|
a
|
b
|
def get_changes(repos, revs, log=None): |
| 48 | 48 | def get_path_links(href, reponame, path, rev, order=None, desc=None): |
| 49 | 49 | desc = desc or None |
| 50 | 50 | links = [{'name': 'source:', |
| 51 | | 'href': href.browser(rev=reponame == '' and rev or None, |
| | 51 | 'href': href.browser(rev=rev if reponame == '' else None, |
| 52 | 52 | order=order, desc=desc)}] |
| 53 | 53 | if reponame: |
| 54 | 54 | links.append({ |
-
diff --git a/trac/web/chrome.py b/trac/web/chrome.py
|
a
|
b
|
|
| 14 | 14 | # |
| 15 | 15 | # Author: Christopher Lenz <cmlenz@gmx.de> |
| 16 | 16 | |
| 17 | | from __future__ import with_statement |
| 18 | | |
| 19 | 17 | """Content presentation for the web layer. |
| 20 | 18 | |
| 21 | 19 | The Chrome module deals with delivering and shaping content to the end user, |
| … |
… |
mostly targeting (X)HTML generation but |
| 23 | 21 | web content are also using facilities provided here. |
| 24 | 22 | """ |
| 25 | 23 | |
| | 24 | from __future__ import with_statement |
| | 25 | |
| 26 | 26 | import datetime |
| 27 | 27 | from functools import partial |
| 28 | 28 | import itertools |
| … |
… |
def prevnext_nav(req, prev_label, next_l |
| 226 | 226 | class_='prev') |
| 227 | 227 | |
| 228 | 228 | add_ctxtnav(req, tag.span(Markup('← '), prev_link or prev_label, |
| 229 | | class_=not prev_link and 'missing' or None)) |
| | 229 | class_='missing' if not prev_link else None)) |
| 230 | 230 | |
| 231 | 231 | if up_label and 'up' in links: |
| 232 | 232 | up = links['up'][0] |
| … |
… |
def prevnext_nav(req, prev_label, next_l |
| 238 | 238 | class_='next') |
| 239 | 239 | |
| 240 | 240 | add_ctxtnav(req, tag.span(next_link or next_label, Markup(' →'), |
| 241 | | class_=not next_link and 'missing' or None)) |
| | 241 | class_='missing' if not next_link else None)) |
| 242 | 242 | |
| 243 | 243 | |
| 244 | 244 | def web_context(req, resource=None, id=False, version=False, parent=False, |
| … |
… |
def web_context(req, resource=None, id=F |
| 267 | 267 | :rtype: `RenderingContext` |
| 268 | 268 | """ |
| 269 | 269 | if req: |
| 270 | | href = absurls and req.abs_href or req.href |
| | 270 | href = req.abs_href if absurls else req.href |
| 271 | 271 | perm = req.perm |
| 272 | 272 | else: |
| 273 | 273 | href = None |
| … |
… |
class Chrome(Component): |
| 728 | 728 | # Like 'trac_banner.png' |
| 729 | 729 | logo_src_abs = abs_href.chrome('common', logo_src) |
| 730 | 730 | logo_src = href.chrome('common', logo_src) |
| 731 | | width = self.logo_width > -1 and self.logo_width or None |
| 732 | | height = self.logo_height > -1 and self.logo_height or None |
| | 731 | width = self.logo_width if self.logo_width > -1 else None |
| | 732 | height = self.logo_height if self.logo_height > -1 else None |
| 733 | 733 | logo = { |
| 734 | 734 | 'link': self.logo_link, 'src': logo_src, |
| 735 | 735 | 'src_abs': logo_src_abs, 'alt': self.logo_alt, |
| … |
… |
class Chrome(Component): |
| 747 | 747 | } |
| 748 | 748 | |
| 749 | 749 | href = req and req.href |
| 750 | | abs_href = req and req.abs_href or self.env.abs_href |
| | 750 | abs_href = req.abs_href if req else self.env.abs_href |
| 751 | 751 | admin_href = None |
| 752 | 752 | if self.env.project_admin_trac_url == '.': |
| 753 | 753 | admin_href = href |
| … |
… |
class Chrome(Component): |
| 794 | 794 | return get_resource_url(self.env, resource, abs_href, **kwargs) |
| 795 | 795 | |
| 796 | 796 | d.update({ |
| 797 | | 'context': req and web_context(req) or None, |
| | 797 | 'context': web_context(req) if req else None, |
| 798 | 798 | 'Resource': Resource, |
| 799 | 799 | 'url_of': get_rel_url, |
| 800 | 800 | 'abs_url_of': get_abs_url, |
| … |
… |
class Chrome(Component): |
| 805 | 805 | 'abs_href': abs_href, |
| 806 | 806 | 'href': href, |
| 807 | 807 | 'perm': req and req.perm, |
| 808 | | 'authname': req and req.authname or '<trac>', |
| | 808 | 'authname': req.authname if req else '<trac>', |
| 809 | 809 | 'locale': req and req.locale, |
| 810 | 810 | 'show_email_addresses': show_email_addresses, |
| 811 | 811 | 'show_ip_addresses': self.show_ip_addresses, |
-
diff --git a/trac/web/href.py b/trac/web/href.py
|
a
|
b
|
class Href(object): |
| 170 | 170 | |
| 171 | 171 | # assemble the query string |
| 172 | 172 | for k, v in kw.items(): |
| 173 | | add_param(k.endswith('_') and k[:-1] or k, v) |
| | 173 | add_param(k[:-1] if k.endswith('_') else k, v) |
| 174 | 174 | if params: |
| 175 | 175 | href += '?' + unicode_urlencode(params, self.query_safe) |
| 176 | 176 | |
-
diff --git a/trac/web/main.py b/trac/web/main.py
|
a
|
b
|
def dispatch_request(environ, start_resp |
| 425 | 425 | env_error = e |
| 426 | 426 | |
| 427 | 427 | req = Request(environ, start_response) |
| 428 | | translation.make_activable(lambda: req.locale, env and env.path or None) |
| | 428 | translation.make_activable(lambda: req.locale, env.path if env else None) |
| 429 | 429 | try: |
| 430 | 430 | return _dispatch_request(req, env, env_error) |
| 431 | 431 | finally: |
-
diff --git a/trac/web/standalone.py b/trac/web/standalone.py
|
a
|
b
|
def main(): |
| 315 | 315 | from trac.web.fcgi_frontend import FlupMiddleware |
| 316 | 316 | flup_app = FlupMiddleware(flup_app) |
| 317 | 317 | ret = server_cls(flup_app, bindAddress=server_address).run() |
| 318 | | sys.exit(ret and 42 or 0) # if SIGHUP exit with status 42 |
| | 318 | sys.exit(42 if ret else 0) # if SIGHUP exit with status 42 |
| 319 | 319 | |
| 320 | 320 | try: |
| 321 | 321 | if options.daemonize: |
-
diff --git a/trac/web/tests/session.py b/trac/web/tests/session.py
|
a
|
b
|
def _prep_session_table(env, spread_visi |
| 21 | 21 | db("DELETE FROM session") |
| 22 | 22 | db("DELETE FROM session_attribute") |
| 23 | 23 | last_visit_base = time.mktime(datetime(2010, 1, 1).timetuple()) |
| 24 | | visit_delta = spread_visits and 86400 or 0 |
| | 24 | visit_delta = 86400 if spread_visits else 0 |
| 25 | 25 | auth_list, anon_list = [], [] |
| 26 | 26 | with env.db_transaction as db: |
| 27 | 27 | for x in xrange(20): |
-
diff --git a/trac/wiki/formatter.py b/trac/wiki/formatter.py
|
a
|
b
|
class WikiProcessor(object): |
| 286 | 286 | raise ProcessorError(_("!#%(name)s must contain at least one table" |
| 287 | 287 | " cell (and table cells only)", |
| 288 | 288 | name=self.name)) |
| 289 | | return Markup(match.group(self.name == 'table' and 1 or 2)) |
| | 289 | return Markup(match.group(1 if self.name == 'table' else 2)) |
| 290 | 290 | |
| 291 | 291 | def _format_row(self, env, context, text): |
| 292 | 292 | if text: |
| … |
… |
class Formatter(object): |
| 539 | 539 | # HTML escape of &, < and > |
| 540 | 540 | |
| 541 | 541 | def _htmlescape_formatter(self, match, fullmatch): |
| 542 | | return match == "&" and "&" or match == "<" and "<" or ">" |
| | 542 | return "&" if match == "&" else "<" if match == "<" else ">" |
| 543 | 543 | |
| 544 | 544 | # Short form (shref) and long form (lhref) of TracLinks |
| 545 | 545 | |
| … |
… |
class Formatter(object): |
| 837 | 837 | self.close_indentation() # FIXME: why not lists in quotes? |
| 838 | 838 | self._list_stack.append((new_type, depth)) |
| 839 | 839 | self._set_tab(depth) |
| 840 | | class_attr = (lclass and ' class="%s"' % lclass) or '' |
| 841 | | start_attr = (start and ' start="%s"' % start) or '' |
| 842 | | self.out.write('<'+new_type+class_attr+start_attr+'><li>') |
| | 840 | class_attr = ' class="%s"' % lclass if lclass else '' |
| | 841 | start_attr = ' start="%s"' % start if start else '' |
| | 842 | self.out.write('<' + new_type + class_attr + start_attr + '><li>') |
| 843 | 843 | def close_item(): |
| 844 | 844 | self.flush_tags() |
| 845 | 845 | self.out.write('</li>') |
| … |
… |
class Formatter(object): |
| 877 | 877 | # Definition Lists |
| 878 | 878 | |
| 879 | 879 | def _definition_formatter(self, match, fullmatch): |
| 880 | | tmp = self.in_def_list and '</dd>' or '<dl class="wiki">' |
| | 880 | tmp = '</dd>' if self.in_def_list else '<dl class="wiki">' |
| 881 | 881 | definition = match[:match.find('::')] |
| 882 | 882 | tmp += '<dt>%s</dt><dd>' % format_to_oneliner(self.env, self.context, |
| 883 | 883 | definition) |
| … |
… |
class Formatter(object): |
| 901 | 901 | self.in_list_item = True |
| 902 | 902 | self._set_list_depth(idepth) |
| 903 | 903 | return '' |
| 904 | | elif idepth <= ldepth + (ltype == 'ol' and 3 or 2): |
| | 904 | elif idepth <= ldepth + (3 if ltype == 'ol' else 2): |
| 905 | 905 | self.in_list_item = True |
| 906 | 906 | return '' |
| 907 | 907 | if not self.in_def_list: |
| … |
… |
class Formatter(object): |
| 913 | 913 | |
| 914 | 914 | def _get_quote_depth(self): |
| 915 | 915 | """Return the space offset associated to the deepest opened quote.""" |
| 916 | | return self._quote_stack and self._quote_stack[-1] or 0 |
| | 916 | return self._quote_stack[-1] if self._quote_stack else 0 |
| 917 | 917 | |
| 918 | 918 | def _set_quote_depth(self, depth, citation=False): |
| 919 | 919 | def open_quote(depth): |
| … |
… |
class Formatter(object): |
| 923 | 923 | def open_one_quote(d): |
| 924 | 924 | self._quote_stack.append(d) |
| 925 | 925 | self._set_tab(d) |
| 926 | | class_attr = citation and ' class="citation"' or '' |
| | 926 | class_attr = ' class="citation"' if citation else '' |
| 927 | 927 | self.out.write('<blockquote%s>' % class_attr + os.linesep) |
| 928 | 928 | if citation: |
| 929 | 929 | for d in range(quote_depth+1, depth+1): |
| … |
… |
class Formatter(object): |
| 1070 | 1070 | args = WikiParser._processor_param_re.split(line) |
| 1071 | 1071 | del args[::3] |
| 1072 | 1072 | keys = [str(k) for k in args[::2]] # used as keyword parameters |
| 1073 | | values = [(v and v[0] in '"\'' and [v[1:-1]] or [v])[0] |
| | 1073 | values = [v[1:-1] if v[:1] + v[-1:] in ('""', "''") else v |
| 1074 | 1074 | for v in args[1::2]] |
| 1075 | 1075 | return dict(zip(keys, values)) |
| 1076 | 1076 | |
| … |
… |
class OneLinerFormatter(Formatter): |
| 1323 | 1323 | return '' |
| 1324 | 1324 | else: |
| 1325 | 1325 | args = fullmatch.group('macroargs') |
| 1326 | | return '[[%s%s]]' % (name, args and '(...)' or '') |
| | 1326 | return '[[%s%s]]' % (name, '(...)' if args else '') |
| 1327 | 1327 | |
| 1328 | 1328 | def format(self, text, out, shorten=False): |
| 1329 | 1329 | if not text: |
-
diff --git a/trac/wiki/intertrac.py b/trac/wiki/intertrac.py
|
a
|
b
|
class InterTracDispatcher(Component): |
| 83 | 83 | parts = link.split(':', 1) |
| 84 | 84 | if len(parts) > 1: |
| 85 | 85 | resolver, target = parts |
| 86 | | if target and (target[0] not in '\'"' or target[0] != target[-1]): |
| | 86 | if target[:1] + target[-1:] not in ('""', "''"): |
| 87 | 87 | link = '%s:"%s"' % (resolver, target) |
| 88 | 88 | from trac.web.chrome import web_context |
| 89 | 89 | link_frag = extract_link(self.env, web_context(req), link) |
-
diff --git a/trac/wiki/interwiki.py b/trac/wiki/interwiki.py
|
a
|
b
|
class InterWikiMap(Component): |
| 68 | 68 | """Replace "$1" by the first args, "$2" by the second, etc.""" |
| 69 | 69 | def setarg(match): |
| 70 | 70 | num = int(match.group()[1:]) |
| 71 | | return 0 < num <= len(args) and args[num-1] or '' |
| | 71 | return args[num - 1] if 0 < num <= len(args) else '' |
| 72 | 72 | return re.sub(InterWikiMap._argspec_re, setarg, txt) |
| 73 | 73 | |
| 74 | 74 | def _expand_or_append(self, txt, args): |
| … |
… |
class InterWikiMap(Component): |
| 76 | 76 | if not args: |
| 77 | 77 | return txt |
| 78 | 78 | expanded = self._expand(txt, args) |
| 79 | | return expanded == txt and txt + args[0] or expanded |
| | 79 | return txt + args[0] if expanded == txt else expanded |
| 80 | 80 | |
| 81 | 81 | def url(self, ns, target): |
| 82 | 82 | """Return `(url, title)` for the given InterWiki `ns`. |
| … |
… |
class InterWikiMap(Component): |
| 84 | 84 | Expand the colon-separated `target` arguments. |
| 85 | 85 | """ |
| 86 | 86 | ns, url, title = self[ns] |
| 87 | | maxargnum = max([0]+[int(a[1:]) for a in |
| 88 | | re.findall(InterWikiMap._argspec_re, url)]) |
| | 87 | maxargnum = max([0] + [int(a[1:]) for a in |
| | 88 | re.findall(InterWikiMap._argspec_re, url)]) |
| 89 | 89 | target, query, fragment = split_url_into_path_query_fragment(target) |
| 90 | 90 | if maxargnum > 0: |
| 91 | 91 | args = target.split(':', (maxargnum - 1)) |
| … |
… |
class InterWikiMap(Component): |
| 141 | 141 | if m: |
| 142 | 142 | prefix, url, title = m.groups() |
| 143 | 143 | url = url.strip() |
| 144 | | title = title and title.strip() or prefix |
| | 144 | title = title.strip() if title else prefix |
| 145 | 145 | map[prefix.upper()] = (prefix, url, title) |
| 146 | 146 | elif line.startswith('----'): |
| 147 | 147 | in_map = True |
| … |
… |
class InterWikiMap(Component): |
| 168 | 168 | interwikis.append({ |
| 169 | 169 | 'prefix': prefix, 'url': url, 'title': title, |
| 170 | 170 | 'rc_url': self._expand_or_append(url, ['RecentChanges']), |
| 171 | | 'description': title == prefix and url or title}) |
| | 171 | 'description': url if title == prefix else title}) |
| 172 | 172 | |
| 173 | 173 | return tag.table(tag.tr(tag.th(tag.em("Prefix")), |
| 174 | 174 | tag.th(tag.em("Site"))), |
-
diff --git a/trac/wiki/macros.py b/trac/wiki/macros.py
|
a
|
b
|
class WikiMacroBase(Component): |
| 54 | 54 | def get_macro_description(self, name): |
| 55 | 55 | """Return the subclass's docstring.""" |
| 56 | 56 | doc = inspect.getdoc(self.__class__) |
| 57 | | return doc and to_unicode(doc) or '' |
| | 57 | return to_unicode(doc) if doc else '' |
| 58 | 58 | |
| 59 | 59 | def parse_macro(self, parser, name, content): |
| 60 | 60 | raise NotImplementedError |
| … |
… |
class TitleIndexMacro(WikiMacroBase): |
| 103 | 103 | |
| 104 | 104 | def expand_macro(self, formatter, name, content): |
| 105 | 105 | args, kw = parse_args(content) |
| 106 | | prefix = args and args[0].strip() or None |
| | 106 | prefix = args[0].strip() if args else None |
| 107 | 107 | hideprefix = args and len(args) > 1 and args[1].strip() == 'hideprefix' |
| 108 | 108 | minsize = max(int(kw.get('min', 2)), 2) |
| 109 | 109 | depth = int(kw.get('depth', -1)) |
| 110 | | start = prefix and prefix.count('/') or 0 |
| | 110 | start = prefix.count('/') if prefix else 0 |
| 111 | 111 | format = kw.get('format', '') |
| 112 | 112 | |
| 113 | 113 | def parse_list(name): |
| … |
… |
class TitleIndexMacro(WikiMacroBase): |
| 175 | 175 | groups = [] |
| 176 | 176 | |
| 177 | 177 | for key, grouper in groupby(entries, lambda (elts, name): |
| 178 | | elts and elts[0] or ''): |
| | 178 | elts[0] if elts else ''): |
| 179 | 179 | # remove key from path_elements in grouped entries for further |
| 180 | 180 | # grouping |
| 181 | 181 | grouped_entries = [(path_elements[1:], page_name) |
| … |
… |
class MacroListMacro(WikiMacroBase): |
| 567 | 567 | def expand_macro(self, formatter, name, content): |
| 568 | 568 | from trac.wiki.formatter import system_message |
| 569 | 569 | |
| 570 | | content = content and content.strip() or '' |
| | 570 | content = content.strip() if content else '' |
| 571 | 571 | name_filter = content.strip('*') |
| 572 | 572 | |
| 573 | 573 | def get_macro_descr(): |
-
diff --git a/trac/wiki/model.py b/trac/wiki/model.py
|
a
|
b
|
class WikiPage(object): |
| 68 | 68 | self.time = from_utimestamp(time) |
| 69 | 69 | self.text = text |
| 70 | 70 | self.comment = comment |
| 71 | | self.readonly = readonly and int(readonly) or 0 |
| | 71 | self.readonly = int(readonly) if readonly else 0 |
| 72 | 72 | break |
| 73 | 73 | else: |
| 74 | 74 | self.version = 0 |
-
diff --git a/trac/wiki/templates/wiki_edit.html b/trac/wiki/templates/wiki_edit.html
|
a
|
b
|
|
| 63 | 63 | |
| 64 | 64 | <body> |
| 65 | 65 | <div id="content" class="wiki" |
| 66 | | py:with="preview_or_review = action == 'preview' and (not diff or changes[0].diffs)"> |
| | 66 | py:with="preview_or_review = action == 'preview' and (not diff or changes[0].diffs)"> |
| 67 | 67 | <div class="trac-topnav" py:if="sidebyside or preview_or_review" py:choose=""> |
| 68 | 68 | <a py:when="sidebyside" href="#changeinfo" |
| 69 | | title="Go to Save, Preview, Review or Cancel buttons">Actions</a> |
| | 69 | title="Go to Save, Preview, Review or Cancel buttons">Actions</a> |
| 70 | 70 | <a py:when="diff" href="#info" title="See the diffs">Review</a> |
| 71 | 71 | <a py:otherwise="" href="#info" title="See the preview">Preview</a> |
| 72 | 72 | ↓ |
-
diff --git a/trac/wiki/templates/wiki_edit_form.html b/trac/wiki/templates/wiki_edit_form.html
|
a
|
b
|
|
| 26 | 26 | </label> |
| 27 | 27 | <input type="checkbox" name="sidebyside" id="sidebyside" checked="$sidebyside" /> |
| 28 | 28 | </div> |
| 29 | | <p><textarea id="text" class="wikitext${not sidebyside and ' trac-resizable' or ''}" name="text" cols="80" rows="$edit_rows"> |
| | 29 | <p><textarea id="text" class="wikitext${' trac-resizable' if not sidebyside else None}" |
| | 30 | name="text" cols="80" rows="$edit_rows"> |
| 30 | 31 | $page.text</textarea> |
| 31 | 32 | </p> |
| 32 | 33 | <div id="help" i18n:msg=""> |
-
diff --git a/trac/wiki/templates/wiki_view.html b/trac/wiki/templates/wiki_view.html
|
a
|
b
|
|
| 88 | 88 | <div py:if="templates" id="template"> |
| 89 | 89 | <label for="template">Using the template:</label> |
| 90 | 90 | <select name="template"> |
| 91 | | <option selected="${not default_template in templates and 'selected' or None}" |
| | 91 | <option selected="${not default_template in templates or None}" |
| 92 | 92 | value="">(blank page)</option> |
| 93 | 93 | <option py:for="t in sorted(templates)" value="$t" |
| 94 | 94 | selected="${t == default_template or None}">$t</option> |
-
diff --git a/trac/wiki/tests/formatter.py b/trac/wiki/tests/formatter.py
|
a
|
b
|
class SampleResolver(Component): |
| 95 | 95 | def _format_link(self, formatter, ns, target, label): |
| 96 | 96 | kind, module = 'text', 'stuff' |
| 97 | 97 | try: |
| 98 | | kind = int(target) % 2 and 'odd' or 'even' |
| | 98 | kind = 'odd' if int(target) % 2 else 'even' |
| 99 | 99 | module = 'thing' |
| 100 | 100 | except ValueError: |
| 101 | 101 | pass |
-
diff --git a/trac/wiki/web_ui.py b/trac/wiki/web_ui.py
|
a
|
b
|
class WikiModule(Component): |
| 234 | 234 | # TRANSLATOR: wiki page |
| 235 | 235 | 'rev': v or _('currently edited'), |
| 236 | 236 | 'shortrev': v or last + 1, |
| 237 | | 'href': v and req.href.wiki(page.name, version=v) or None} |
| | 237 | 'href': req.href.wiki(page.name, version=v) if v else None} |
| 238 | 238 | changes = [{'diffs': diffs, 'props': [], |
| 239 | 239 | 'new': version_info(new_version, old_version), |
| 240 | 240 | 'old': version_info(old_version)}] |
| … |
… |
class WikiModule(Component): |
| 314 | 314 | new_name, old_version, old_name, new_name) |
| 315 | 315 | redirection.save(author, comment, req.remote_addr) |
| 316 | 316 | |
| 317 | | req.redirect(req.href.wiki(redirect and old_name or new_name)) |
| | 317 | req.redirect(req.href.wiki(old_name if redirect else new_name)) |
| 318 | 318 | |
| 319 | 319 | def _do_save(self, req, page): |
| 320 | 320 | if page.readonly: |
| … |
… |
class WikiModule(Component): |
| 351 | 351 | version = int(req.args.get('version', 0)) |
| 352 | 352 | old_version = int(req.args.get('old_version') or 0) or version |
| 353 | 353 | |
| 354 | | what = ((version and old_version and version - old_version > 1) and |
| 355 | | 'multiple') or version and 'single' or 'page' |
| | 354 | what = 'multiple' if version and old_version \ |
| | 355 | and version - old_version > 1 \ |
| | 356 | else 'single' if version else 'page' |
| 356 | 357 | |
| 357 | 358 | num_versions = 0 |
| 358 | 359 | new_date = None |
| … |
… |
class WikiModule(Component): |
| 382 | 383 | req.perm(page.resource).require('WIKI_RENAME') |
| 383 | 384 | |
| 384 | 385 | data = self._page_data(req, page, 'rename') |
| 385 | | data['new_name'] = new_name is None and page.name or new_name |
| | 386 | data['new_name'] = new_name if new_name is not None else page.name |
| 386 | 387 | self._wiki_ctxtnav(req, page) |
| 387 | 388 | return 'wiki_rename.html', data, None |
| 388 | 389 | |
| … |
… |
class WikiModule(Component): |
| 526 | 527 | 'attachments': AttachmentModule(self.env).attachment_data(context), |
| 527 | 528 | }) |
| 528 | 529 | if action in ('diff', 'merge'): |
| 529 | | old_text = original_text and original_text.splitlines() or [] |
| 530 | | new_text = page.text and page.text.splitlines() or [] |
| | 530 | old_text = original_text.splitlines() if original_text else [] |
| | 531 | new_text = page.text.splitlines() if page.text else [] |
| 531 | 532 | diff_data, changes = self._prepare_diff( |
| 532 | 533 | req, page, old_text, new_text, page.version, '') |
| 533 | 534 | data.update({'diff': diff_data, 'changes': changes, |
-
diff --git a/tracopt/mimeview/enscript.py b/tracopt/mimeview/enscript.py
|
a
|
b
|
class EnscriptRenderer(Component): |
| 151 | 151 | i = odata.find('<PRE>') |
| 152 | 152 | beg = i > 0 and i + 6 |
| 153 | 153 | i = odata.rfind('</PRE>') |
| 154 | | end = i > 0 and i or len(odata) |
| | 154 | end = i if i > 0 else len(odata) |
| 155 | 155 | |
| 156 | 156 | odata = EnscriptDeuglifier().format(odata[beg:end].decode('utf-8')) |
| 157 | 157 | return [Markup(line) for line in odata.splitlines()] |
-
diff --git a/tracopt/perm/authz_policy.py b/tracopt/perm/authz_policy.py
|
a
|
b
|
class AuthzPolicy(Component): |
| 169 | 169 | |
| 170 | 170 | def get_authz_file(self): |
| 171 | 171 | f = self.authz_file |
| 172 | | return os.path.isabs(f) and f or os.path.join(self.env.path, f) |
| | 172 | return f if os.path.isabs(f) else os.path.join(self.env.path, f) |
| 173 | 173 | |
| 174 | 174 | def parse_authz(self): |
| 175 | 175 | self.log.debug('Parsing authz security policy %s', |
-
diff --git a/tracopt/perm/config_perm_provider.py b/tracopt/perm/config_perm_provider.py
|
a
|
b
|
class ExtraPermissionsProvider(Component |
| 51 | 51 | meta = meta.strip().upper() |
| 52 | 52 | if meta and not meta.startswith('_'): |
| 53 | 53 | permissions.setdefault(meta, []).extend(perms) |
| 54 | | return [v and (k, v) or k for k, v in permissions.iteritems()] |
| | 54 | return [(k, v) if v else k for k, v in permissions.iteritems()] |