You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@bloodhound.apache.org by gj...@apache.org on 2012/10/16 22:06:19 UTC
svn commit: r1398968 [23/28] - in /incubator/bloodhound/trunk/trac: ./
contrib/ doc/ doc/api/ doc/utils/ sample-plugins/
sample-plugins/permissions/ sample-plugins/workflow/ trac/ trac/admin/
trac/admin/templates/ trac/admin/tests/ trac/db/ trac/db/tes...
Modified: incubator/bloodhound/trunk/trac/trac/templates/attachment.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/templates/attachment.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/templates/attachment.html (original)
+++ incubator/bloodhound/trunk/trac/trac/templates/attachment.html Tue Oct 16 20:06:09 2012
@@ -38,18 +38,18 @@
<py:if test="authname == 'anonymous'">
<div class="field">
<label>Your email or username:<br />
- <input type="text" name="author" size="30" value="$author" />
+ <input type="text" name="author" size="30" value="${attachment.author or author}" />
</label>
</div>
</py:if>
<div class="field">
<label>Description of the file (optional):<br />
- <input type="text" name="description" size="60" /></label>
+ <input type="text" name="description" size="60" value="$attachment.description"/></label>
</div>
<br />
<py:if test="authname and authname != 'anonymous'">
<div class="options">
- <label><input type="checkbox" name="replace" />
+ <label><input type="checkbox" name="replace" checked="${is_replace or None}" />
Replace existing attachment of the same name</label>
</div>
<br />
Modified: incubator/bloodhound/trunk/trac/trac/templates/diff_div.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/templates/diff_div.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/templates/diff_div.html (original)
+++ incubator/bloodhound/trunk/trac/trac/templates/diff_div.html Tue Oct 16 20:06:09 2012
@@ -24,7 +24,7 @@
.offset - position within the file
.diffs_title - a sequence of titles for the list of blocks
- Note: integrate this into .diffs for 0.12 or 0.13.
+ Note: integrate this into .diffs for 0.12 or 1.0.
diff - dict specifying diff style and options
.style - can be 'sidebyside' (4 columns) or 'inline' (3 columns)
Modified: incubator/bloodhound/trunk/trac/trac/templates/layout.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/templates/layout.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/templates/layout.html (original)
+++ incubator/bloodhound/trunk/trac/trac/templates/layout.html Tue Oct 16 20:06:09 2012
@@ -10,7 +10,10 @@
<title py:with="title = list(select('title/text()'))">
<py:if test="title">${title} â </py:if>${project.name or 'Trac'}
</title>
- <meta py:if="chrome.content_type == 'text/html'" http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <py:if test="chrome.content_type == 'text/html'">
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="X-UA-Compatible" content="IE=edge" />
+ </py:if>
<meta py:for="meta in chrome.metas" py:attrs="meta"/>
<!--[if IE]><script type="text/javascript">
if (/^#__msie303:/.test(window.location.hash))
@@ -34,6 +37,14 @@
<py:for each="script in chrome.scripts">
${script.prefix}<script type="${script.type}" charset="${script.charset}" src="${script.href}"></script>${script.suffix}
</py:for>
+ <script py:if="chrome.warnings or chrome.notices" type="text/javascript">
+ jQuery(document).ready(function($) {
+ $(".trac-close-msg").show().click(function () {
+ $(this).closest(".system-message").hide();
+ return false;
+ });
+ });
+ </script>
${select("*[local-name() != 'title']|text()|comment()")}
</head></py:match>
Modified: incubator/bloodhound/trunk/trac/trac/templates/list_of_attachments.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/templates/list_of_attachments.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/templates/list_of_attachments.html (original)
+++ incubator/bloodhound/trunk/trac/trac/templates/list_of_attachments.html Tue Oct 16 20:06:09 2012
@@ -25,7 +25,7 @@ Arguments:
<py:if test="alist.attachments or alist.can_create">
<div id="attachments" py:choose="">
<py:when test="compact and alist.attachments">
- <h3 class="${'foldable' if foldable else None}">Attachments</h3>
+ <h3 class="${'foldable' if foldable else None}">Attachments <span class="trac-count">(${len(alist.attachments)})</span></h3>
<div>
<ul>
<py:for each="attachment in alist.attachments">
@@ -41,7 +41,7 @@ Arguments:
</div>
</py:when>
<py:when test="not compact">
- <h2 class="${'foldable' if foldable else None}">Attachments</h2>
+ <h3 class="${'foldable' if foldable else None}">Attachments <span class="trac-count">(${len(alist.attachments)})</span></h3>
<div py:if="alist.attachments or alist.can_create" class="attachments">
<dl py:if="alist.attachments" class="attachments">
<py:for each="attachment in alist.attachments">
Modified: incubator/bloodhound/trunk/trac/trac/templates/theme.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/templates/theme.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/templates/theme.html (original)
+++ incubator/bloodhound/trunk/trac/trac/templates/theme.html Tue Oct 16 20:06:09 2012
@@ -33,19 +33,21 @@
</div>
${navigation('mainnav')}
- <div id="main">
+ <div id="main" class="${classes(uisymbols=req.session.get('ui.use_symbols'),
+ uinohelp=req.session.get('ui.hide_help'))}">
<xi:include py:if="value_of('resourcepath_template')" href="${resourcepath_template}" />
<div id="ctxtnav" class="nav">
<h2>Context Navigation</h2>
- <ul py:if="chrome.ctxtnav">
- <li py:for="i, elm in enumerate(chrome.ctxtnav)"
- class="${classes(first_last(i, chrome.ctxtnav))}">$elm</li>
- </ul>
+ <ul py:if="chrome.ctxtnav">
+ <li py:for="i, elm in enumerate(chrome.ctxtnav)"
+ class="${classes(first_last(i, chrome.ctxtnav))}">$elm</li>
+ </ul>
<hr />
</div>
<div id="warning" py:if="chrome.warnings" class="system-message">
+ <a class="trac-close-msg" href="#" title="Hide this warning"><span>close</span></a>
<py:choose test="len(chrome.warnings)">
<strong>Warning:</strong>
<py:when test="1">${chrome.warnings[0]}</py:when>
@@ -53,6 +55,7 @@
</py:choose>
</div>
<div id="notice" py:if="chrome.notices" class="system-message">
+ <a class="trac-close-msg" href="#" title="Hide this notice"><span>close</span></a>
<py:choose test="len(chrome.notices)">
<py:when test="1">${chrome.notices[0]}</py:when>
<py:otherwise><ul><li py:for="notice in chrome.notices">$notice</li></ul></py:otherwise>
Modified: incubator/bloodhound/trunk/trac/trac/test.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/test.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/test.py (original)
+++ incubator/bloodhound/trunk/trac/trac/test.py Tue Oct 16 20:06:09 2012
@@ -26,8 +26,9 @@ import sys
try:
from babel import Locale
+ locale_en = Locale.parse('en_US')
except ImportError:
- Locale = None
+ locale_en = None
from trac.config import Configuration
from trac.core import Component, ComponentManager
@@ -264,6 +265,9 @@ class EnvironmentStub(Environment):
self.config.set('logging', 'log_type', 'stderr')
if enable is not None:
self.config.set('components', 'trac.*', 'disabled')
+ else:
+ self.config.set('components', 'tracopt.versioncontrol.svn.*',
+ 'enabled')
for name_or_class in enable or ():
config_key = self._component_name(name_or_class)
self.config.set('components', config_key, 'enabled')
@@ -298,7 +302,7 @@ class EnvironmentStub(Environment):
self.abs_href = Href('http://example.org/trac.cgi')
self.known_users = []
- translation.activate(Locale and Locale('en', 'US'))
+ translation.activate(locale_en)
def reset_db(self, default_data=None):
"""Remove all data from Trac tables, keeping the tables themselves.
@@ -418,7 +422,9 @@ def suite():
import trac.web.tests
import trac.wiki.tests
import tracopt.mimeview.tests
+ import tracopt.perm.tests
import tracopt.versioncontrol.git.tests
+ import tracopt.versioncontrol.svn.tests
suite = unittest.TestSuite()
suite.addTest(trac.tests.basicSuite())
@@ -434,7 +440,9 @@ def suite():
suite.addTest(trac.web.tests.suite())
suite.addTest(trac.wiki.tests.suite())
suite.addTest(tracopt.mimeview.tests.suite())
+ suite.addTest(tracopt.perm.tests.suite())
suite.addTest(tracopt.versioncontrol.git.tests.suite())
+ suite.addTest(tracopt.versioncontrol.svn.tests.suite())
suite.addTest(doctest.DocTestSuite(sys.modules[__name__]))
return suite
Modified: incubator/bloodhound/trunk/trac/trac/tests/config.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/tests/config.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/tests/config.py (original)
+++ incubator/bloodhound/trunk/trac/trac/tests/config.py Tue Oct 16 20:06:09 2012
@@ -190,9 +190,10 @@ class ConfigurationTestCase(unittest.Tes
config = self._read()
class Foo(object):
- option = ChoiceOption('a', 'option', ['Item1', 2, '3'])
- other = ChoiceOption('a', 'other', [1, 2, 3])
- invalid = ChoiceOption('a', 'invalid', ['a', 'b', 'c'])
+ # enclose in parentheses to avoid messages extraction
+ option = (ChoiceOption)('a', 'option', ['Item1', 2, '3'])
+ other = (ChoiceOption)('a', 'other', [1, 2, 3])
+ invalid = (ChoiceOption)('a', 'invalid', ['a', 'b', 'c'])
def __init__(self):
self.config = config
@@ -294,7 +295,8 @@ class ConfigurationTestCase(unittest.Tes
self.assertEquals(['a', 'b'], config.sections())
class Foo(object):
- section_c = ConfigSection('c', 'Doc for c')
+ # enclose in parentheses to avoid messages extraction
+ section_c = (ConfigSection)('c', 'Doc for c')
option_c = Option('c', 'option', 'value')
self.assertEquals(['a', 'b', 'c'], config.sections())
Modified: incubator/bloodhound/trunk/trac/trac/tests/functional/testenv.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/tests/functional/testenv.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/tests/functional/testenv.py (original)
+++ incubator/bloodhound/trunk/trac/trac/tests/functional/testenv.py Tue Oct 16 20:06:09 2012
@@ -110,7 +110,7 @@ class FunctionalTestEnvironment(object):
environment creation. For anything more complicated, use the
:meth:`post_create` method.
"""
- return []
+ return ['tracopt.versioncontrol.svn.*']
def create(self):
"""Create a new test environment.
Modified: incubator/bloodhound/trunk/trac/trac/tests/wikisyntax.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/tests/wikisyntax.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/tests/wikisyntax.py (original)
+++ incubator/bloodhound/trunk/trac/trac/tests/wikisyntax.py Tue Oct 16 20:06:09 2012
@@ -151,7 +151,7 @@ def email_default_context():
context = RenderingContext(Resource('wiki', 'WikiStart'), href=Href('/'),
perm=NoEmailViewPerm())
- context.req = None # 0.13 FIXME .req shouldn't be required by formatter
+ context.req = None # 1.0 FIXME .req shouldn't be required by formatter
return context
Modified: incubator/bloodhound/trunk/trac/trac/ticket/admin.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/admin.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/admin.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/admin.py Tue Oct 16 20:06:09 2012
@@ -342,6 +342,8 @@ class MilestoneAdminPanel(TicketAdminPan
'milestones': milestones,
'default': default}
+ Chrome(self.env).add_jquery_ui(req)
+
data.update({
'datetime_hint': get_datetime_format_hint(req.lc_time),
})
@@ -511,6 +513,8 @@ class VersionAdminPanel(TicketAdminPanel
'versions': model.Version.select(self.env),
'default': default}
+ Chrome(self.env).add_jquery_ui(req)
+
data.update({
'datetime_hint': get_datetime_format_hint(req.lc_time),
})
Modified: incubator/bloodhound/trunk/trac/trac/ticket/api.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/api.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/api.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/api.py Tue Oct 16 20:06:09 2012
@@ -503,8 +503,10 @@ class TicketSystem(Component):
ranges = str(r)
if params:
params = '&' + params[1:]
- return tag.a(label,
- title=_("Tickets %(ranges)s", ranges=ranges),
+ label_wrap = label.replace(',', u',\u200b')
+ ranges_wrap = ranges.replace(',', u', ')
+ return tag.a(label_wrap,
+ title=_("Tickets %(ranges)s", ranges=ranges_wrap),
href=formatter.href.query(id=ranges) + params)
except ValueError:
pass
Modified: incubator/bloodhound/trunk/trac/trac/ticket/batch.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/batch.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/batch.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/batch.py Tue Oct 16 20:06:09 2012
@@ -73,7 +73,7 @@ class BatchModifyModule(Component):
name = field['name']
if name not in ('id', 'resolution', 'status', 'owner', 'time',
'changetime', 'summary', 'reporter',
- 'description') and field['type'] != 'text-area':
+ 'description') and field['type'] != 'textarea':
value = req.args.get('batchmod_value_' + name)
if value is not None:
values[name] = value
@@ -98,8 +98,7 @@ class BatchModifyModule(Component):
{'name': _("add / remove"), 'value': "+-"},
{'name': _("set to"), 'value': "="},
]
- add_script_data(req, batch_modify=True,
- batch_list_modes=batch_list_modes,
+ add_script_data(req, batch_list_modes=batch_list_modes,
batch_list_properties=self.fields_as_list)
def _get_action_controls(self, req, tickets):
Modified: incubator/bloodhound/trunk/trac/trac/ticket/default_workflow.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/default_workflow.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/default_workflow.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/default_workflow.py Tue Oct 16 20:06:09 2012
@@ -3,7 +3,7 @@
# Copyright (C) 2006-2009 Edgewall Software
# Copyright (C) 2006 Alec Thomas
# Copyright (C) 2007 Eli Carter
-# Copyright (C) 2007 Christian Boos <cb...@neuf.fr>
+# Copyright (C) 2007 Christian Boos <cb...@edgewall.org>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
Modified: incubator/bloodhound/trunk/trac/trac/ticket/model.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/model.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/model.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/model.py Tue Oct 16 20:06:09 2012
@@ -3,7 +3,7 @@
# Copyright (C) 2003-2009 Edgewall Software
# Copyright (C) 2003-2006 Jonas Borgström <jo...@edgewall.com>
# Copyright (C) 2005 Christopher Lenz <cm...@gmx.de>
-# Copyright (C) 2006 Christian Boos <cb...@neuf.fr>
+# Copyright (C) 2006 Christian Boos <cb...@edgewall.org>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
@@ -59,8 +59,8 @@ class Ticket(object):
def __init__(self, env, tkt_id=None, db=None, version=None):
"""
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
self.env = env
if tkt_id is not None:
@@ -163,14 +163,16 @@ class Ticket(object):
"""
try:
value = self.values[name]
- if value is not empty:
- return value
- field = [field for field in self.fields if field['name'] == name]
- if field:
- return field[0].get('value', '')
+ return value if value is not empty else self.get_default(name)
except KeyError:
pass
+ def get_default(self, name):
+ """Return the default value of a field."""
+ field = [field for field in self.fields if field['name'] == name]
+ if field:
+ return field[0].get('value', '')
+
def populate(self, values):
"""Populate the ticket with 'suitable' values from a dictionary"""
field_names = [f['name'] for f in self.fields]
@@ -186,8 +188,8 @@ class Ticket(object):
def insert(self, when=None, db=None):
"""Add ticket to database.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert not self.exists, 'Cannot insert an existing ticket'
@@ -261,9 +263,9 @@ class Ticket(object):
the database. Returns False if there were no changes to save, True
otherwise.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
- :since 0.13: the `cnum` parameter is deprecated, and threading should
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
+ :since 1.0: the `cnum` parameter is deprecated, and threading should
be controlled with the `replyto` argument
"""
assert self.exists, "Cannot update a new ticket"
@@ -271,7 +273,8 @@ class Ticket(object):
if 'cc' in self.values:
self['cc'] = _fixup_cc_list(self.values['cc'])
- if not self._old and not comment:
+ props_unchanged = all(self.values.get(k) == v for k, v in self._old.iteritems())
+ if (not comment or not comment.strip()) and props_unchanged:
return False # Not modified
if when is None:
@@ -368,8 +371,8 @@ class Ticket(object):
the `permanent` flag is used to distinguish collateral changes
that are not yet immutable (like attachments, currently).
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
sid = str(self.id)
when_ts = to_utimestamp(when)
@@ -411,8 +414,8 @@ class Ticket(object):
def delete(self, db=None):
"""Delete the ticket.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
with self.env.db_transaction as db:
Attachment.delete_all(self.env, 'ticket', self.id, db)
@@ -426,8 +429,8 @@ class Ticket(object):
def get_change(self, cnum=None, cdate=None, db=None):
"""Return a ticket change by its number or date.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
if cdate is None:
row = self._find_change(cnum)
@@ -565,8 +568,8 @@ class Ticket(object):
"""Retrieve the edit history of a comment identified by its number or
date.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
if cdate is None:
row = self._find_change(cnum)
@@ -586,7 +589,7 @@ class Ticket(object):
break
if author0 is None:
for author0, last_comment in db("""
- SELECT author, new FROM ticket_change
+ SELECT author, newvalue FROM ticket_change
WHERE ticket=%%s AND time=%%s AND NOT field %s LIMIT 1
""" % db.like(),
(self.id, ts0, db.like_escape('_') + '%')):
@@ -691,8 +694,8 @@ class AbstractEnum(object):
def delete(self, db=None):
"""Delete the enum value.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert self.exists, "Cannot delete non-existent %s" % self.type
@@ -716,8 +719,8 @@ class AbstractEnum(object):
def insert(self, db=None):
"""Add a new enum value.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert not self.exists, "Cannot insert existing %s" % self.type
self.name = simplify_whitespace(self.name)
@@ -741,8 +744,8 @@ class AbstractEnum(object):
def update(self, db=None):
"""Update the enum value.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert self.exists, "Cannot update non-existent %s" % self.type
self.name = simplify_whitespace(self.name)
@@ -766,8 +769,8 @@ class AbstractEnum(object):
@classmethod
def select(cls, env, db=None):
"""
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
with env.db_query as db:
for name, value in db("""
@@ -812,8 +815,8 @@ class Severity(AbstractEnum):
class Component(object):
def __init__(self, env, name=None, db=None):
"""
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
self.env = env
self.name = self._old_name = self.owner = self.description = None
@@ -834,8 +837,8 @@ class Component(object):
def delete(self, db=None):
"""Delete the component.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert self.exists, "Cannot delete non-existent component"
@@ -848,8 +851,8 @@ class Component(object):
def insert(self, db=None):
"""Insert a new component.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert not self.exists, "Cannot insert existing component"
self.name = simplify_whitespace(self.name)
@@ -867,8 +870,8 @@ class Component(object):
def update(self, db=None):
"""Update the component.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert self.exists, "Cannot update non-existent component"
self.name = simplify_whitespace(self.name)
@@ -891,8 +894,8 @@ class Component(object):
@classmethod
def select(cls, env, db=None):
"""
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
for name, owner, description in env.db_query(
"SELECT name, owner, description FROM component ORDER BY name"):
@@ -950,8 +953,8 @@ class Milestone(object):
def delete(self, retarget_to=None, author=None, db=None):
"""Delete the milestone.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
with self.env.db_transaction as db:
self.env.log.info("Deleting milestone %s", self.name)
@@ -976,8 +979,8 @@ class Milestone(object):
def insert(self, db=None):
"""Insert a new milestone.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
self.name = simplify_whitespace(self.name)
if not self.name:
@@ -998,8 +1001,8 @@ class Milestone(object):
def update(self, db=None):
"""Update the milestone.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
self.name = simplify_whitespace(self.name)
if not self.name:
@@ -1036,8 +1039,8 @@ class Milestone(object):
@classmethod
def select(cls, env, include_completed=True, db=None):
"""
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
sql = "SELECT name, due, completed, description FROM milestone "
if not include_completed:
@@ -1092,8 +1095,8 @@ class Version(object):
def delete(self, db=None):
"""Delete the version.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert self.exists, "Cannot delete non-existent version"
@@ -1106,8 +1109,8 @@ class Version(object):
def insert(self, db=None):
"""Insert a new version.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert not self.exists, "Cannot insert existing version"
self.name = simplify_whitespace(self.name)
@@ -1124,8 +1127,8 @@ class Version(object):
def update(self, db=None):
"""Update the version.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
assert self.exists, "Cannot update non-existent version"
self.name = simplify_whitespace(self.name)
@@ -1148,8 +1151,8 @@ class Version(object):
@classmethod
def select(cls, env, db=None):
"""
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
versions = []
for name, time, description in env.db_query("""
Modified: incubator/bloodhound/trunk/trac/trac/ticket/notification.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/notification.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/notification.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/notification.py Tue Oct 16 20:06:09 2012
@@ -61,7 +61,7 @@ class TicketNotificationSystem(Component
"""Like ticket_subject_template but for batch modifications.
By default, the template is `$prefix Batch modify: $tickets_descr`.
- ''(since 0.13)''""")
+ ''(since 1.0)''""")
ambiguous_char_width = Option('notification', 'ambiguous_char_width',
'single',
Modified: incubator/bloodhound/trunk/trac/trac/ticket/query.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/query.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/query.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/query.py Tue Oct 16 20:06:09 2012
@@ -2,7 +2,7 @@
#
# Copyright (C) 2004-2009 Edgewall Software
# Copyright (C) 2004-2005 Christopher Lenz <cm...@gmx.de>
-# Copyright (C) 2005-2007 Christian Boos <cb...@neuf.fr>
+# Copyright (C) 2005-2007 Christian Boos <cb...@edgewall.org>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
@@ -273,8 +273,8 @@ class Query(object):
tzinfo=None, locale=None):
"""Get the number of matching tickets for the present query.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
sql, args = self.get_sql(req, cached_ids, authname, tzinfo, locale)
return self._count(sql, args)
@@ -290,8 +290,8 @@ class Query(object):
tzinfo=None, href=None, locale=None):
"""Retrieve the list of matching tickets.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
if req is not None:
href = req.href
@@ -1129,6 +1129,7 @@ class QueryModule(Component):
add_script_data(req, properties=properties, modes=data['modes'])
add_stylesheet(req, 'common/css/report.css')
+ Chrome(self.env).add_jquery_ui(req)
add_script(req, 'common/js/query.js')
return 'query.html', data, None
@@ -1421,7 +1422,8 @@ class TicketQueryMacro(WikiMacroBase):
if format == 'compact':
if query.group:
groups = [(v, ' ',
- tag.a('#%s' % ','.join([str(t['id']) for t in g]),
+ tag.a('#%s' % u',\u200b'.join(str(t['id'])
+ for t in g),
href=href, class_='query', title=title))
for v, g, href, title in ticket_groups()]
return tag(groups[0], [(', ', g) for g in groups[1:]])
Modified: incubator/bloodhound/trunk/trac/trac/ticket/report.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/report.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/report.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/report.py Tue Oct 16 20:06:09 2012
@@ -2,7 +2,7 @@
#
# Copyright (C) 2003-2009 Edgewall Software
# Copyright (C) 2003-2004 Jonas Borgström <jo...@edgewall.com>
-# Copyright (C) 2006 Christian Boos <cb...@neuf.fr>
+# Copyright (C) 2006 Christian Boos <cb...@edgewall.org>
# Copyright (C) 2006 Matthew Good <tr...@matt-good.net>
# All rights reserved.
#
@@ -36,13 +36,18 @@ from trac.util.presentation import Pagin
from trac.util.text import exception_to_unicode, to_unicode, quote_query_string
from trac.util.translation import _, tag_
from trac.web.api import IRequestHandler, RequestDone
-from trac.web.chrome import (INavigationContributor, Chrome,
+from trac.web.chrome import (INavigationContributor, Chrome,
add_ctxtnav, add_link, add_notice, add_script,
add_stylesheet, add_warning, auth_link,
web_context)
from trac.wiki import IWikiSyntaxProvider, WikiParser
+
+SORT_COLUMN = '@SORT_COLUMN@'
+LIMIT_OFFSET = '@LIMIT_OFFSET@'
+
+
def cell_value(v):
"""Normalize a cell value for display.
>>> (cell_value(None), cell_value(0), cell_value(1), cell_value('v'))
@@ -51,6 +56,58 @@ def cell_value(v):
return '0' if v is 0 else unicode(v) if v else ''
+_sql_re = re.compile(r'''
+ --.*$ # single line "--" comment
+ | /\*([^*/]|\*[^/]|/[^*])*\*/ # C style comment
+ | '(\\.|[^'\\])*' # literal string
+ | \([^()]+\) # parenthesis group
+''', re.MULTILINE | re.VERBOSE)
+
+def _expand_with_space(m):
+ return ' ' * len(m.group(0))
+
+def sql_skeleton(sql):
+ """Strip an SQL query to leave only its toplevel structure.
+
+ This is probably not 100% robust but should be enough for most
+ needs.
+
+ >>> re.sub('\s+', lambda m: '<%d>' % len(m.group(0)), sql_skeleton(''' \\n\
+ SELECT a FROM (SELECT x FROM z ORDER BY COALESCE(u, ')/*(')) ORDER \\n\
+ /* SELECT a FROM (SELECT x /* FROM z \\n\
+ ORDER BY */ COALESCE(u, '\)X(')) ORDER */ \\n\
+ BY c, (SELECT s FROM f WHERE v in ('ORDER BY', '(\\')') \\n\
+ ORDER BY (1), '') -- LIMIT \\n\
+ '''))
+ '<10>SELECT<1>a<1>FROM<48>ORDER<164>BY<1>c,<144>'
+ """
+ old = None
+ while sql != old:
+ old = sql
+ sql = _sql_re.sub(_expand_with_space, old)
+ return old
+
+_order_by_re = re.compile(r'ORDER\s+BY', re.MULTILINE)
+
+def split_sql(sql, clause_re, skel=None):
+ """Split an SQL query according to a toplevel clause regexp.
+
+ We assume there's only one such clause present in the outer query.
+
+ >>> split_sql('''SELECT a FROM x ORDER \
+ BY u, v''', _order_by_re)
+ ('SELECT a FROM x ', ' u, v')
+ """
+ if skel is None:
+ skel = sql_skeleton(sql)
+ blocks = clause_re.split(skel.upper())
+ if len(blocks) == 2:
+ return sql[:len(blocks[0])], sql[-len(blocks[1]):] # (before, after)
+ else:
+ return sql, '' # no single clause separator
+
+
+
class ReportModule(Component):
implements(INavigationContributor, IPermissionRequestor, IRequestHandler,
@@ -63,7 +120,7 @@ class ReportModule(Component):
items_per_page_rss = IntOption('report', 'items_per_page_rss', 0,
"""Number of tickets displayed in the rss feeds for reports
(''since 0.11'')""")
-
+
# INavigationContributor methods
def get_active_navigation_item(self, req):
@@ -74,12 +131,12 @@ class ReportModule(Component):
yield ('mainnav', 'tickets', tag.a(_('View Tickets'),
href=req.href.report()))
- # IPermissionRequestor methods
+ # IPermissionRequestor methods
- def get_permission_actions(self):
- actions = ['REPORT_CREATE', 'REPORT_DELETE', 'REPORT_MODIFY',
- 'REPORT_SQL_VIEW', 'REPORT_VIEW']
- return actions + [('REPORT_ADMIN', actions)]
+ def get_permission_actions(self):
+ actions = ['REPORT_CREATE', 'REPORT_DELETE', 'REPORT_MODIFY',
+ 'REPORT_SQL_VIEW', 'REPORT_VIEW']
+ return actions + [('REPORT_ADMIN', actions)]
# IRequestHandler methods
@@ -132,8 +189,8 @@ class ReportModule(Component):
else:
add_ctxtnav(req, _('Available Reports'))
- # Kludge: only show link to custom query if the query module is actually
- # enabled
+ # Kludge: only show link to custom query if the query module
+ # is actually enabled
from trac.ticket.query import QueryModule
if 'TICKET_VIEW' in req.perm and \
self.env.is_component_enabled(QueryModule):
@@ -244,12 +301,12 @@ class ReportModule(Component):
sort = req.args.get('sort', 'report')
asc = bool(int(req.args.get('asc', 1)))
format = req.args.get('format')
-
+
rows = self.env.db_query("""
SELECT id, title, description FROM report ORDER BY %s %s
""" % ('title' if sort == 'title' else 'id',
'' if asc else 'DESC'))
-
+
if format == 'rss':
data = {'rows': rows}
return 'report_list.rss', data, 'application/rss+xml'
@@ -273,8 +330,8 @@ class ReportModule(Component):
_('Comma-delimited Text'), 'text/plain')
add_link(req, 'alternate', report_href(format='tab'),
_('Tab-delimited Text'), 'text/plain')
-
- reports = [(id, title, description,
+
+ reports = [(id, title, description,
'REPORT_MODIFY' in req.perm('report', id),
'REPORT_DELETE' in req.perm('report', id))
for id, title, description in rows]
@@ -351,7 +408,7 @@ class ReportModule(Component):
asc = bool(int(asc)) # string '0' or '1' to int/boolean
def report_href(**kwargs):
- """Generate links to this report preserving user variables,
+ """Generate links to this report preserving user variables,
and sorting and paging variables.
"""
params = args.copy()
@@ -361,7 +418,7 @@ class ReportModule(Component):
if max:
params['max'] = max
params.update(kwargs)
- params['asc'] = '1' if params.get('asc', asc) else '0'
+ params['asc'] = '1' if params.get('asc', asc) else '0'
return req.href.report(id, params)
data = {'action': 'view',
@@ -370,24 +427,31 @@ class ReportModule(Component):
'title': title, 'description': description,
'max': limit, 'args': args, 'show_args_form': False,
'message': None, 'paginator': None,
- 'report_href': report_href,
+ 'report_href': report_href,
}
+ res = None
with self.env.db_query as db:
- try:
- cols, results, num_items, missing_args = \
- self.execute_paginated_report(req, db, id, sql, args, limit,
- offset)
- results = [list(row) for row in results]
- numrows = len(results)
+ res = self.execute_paginated_report(req, db, id, sql, args, limit,
+ offset)
- except Exception, e:
- data['message'] = tag_('Report execution failed: %(error)s',
- error=tag.pre(exception_to_unicode(e, traceback=True)))
- return 'report_view.html', data, None
+ if len(res) == 2:
+ e, sql = res
+ data['message'] = \
+ tag_("Report execution failed: %(error)s %(sql)s",
+ error=tag.pre(exception_to_unicode(e)),
+ sql=tag(tag.hr(),
+ tag.pre(sql, style="white-space: pre")))
+ return 'report_view.html', data, None
+
+ cols, results, num_items, missing_args, limit_offset = res
+ need_paginator = limit > 0 and limit_offset
+ need_reorder = limit_offset is None
+ results = [list(row) for row in results]
+ numrows = len(results)
paginator = None
- if limit > 0:
+ if need_paginator:
paginator = Paginator(results, page - 1, limit, num_items)
data['paginator'] = paginator
if paginator.has_next_page:
@@ -430,11 +494,11 @@ class ReportModule(Component):
if col == sort_col:
header['asc'] = asc
- if not paginator:
+ if not paginator and need_reorder:
# this dict will have enum values for sorting
# and will be used in sortkey(), if non-empty:
sort_values = {}
- if sort_col in ('status', 'resolution', 'priority',
+ if sort_col in ('status', 'resolution', 'priority',
'severity'):
# must fetch sort values for that columns
# instead of comparing them as strings
@@ -540,8 +604,7 @@ class ReportModule(Component):
data.update({'header_groups': header_groups,
'row_groups': row_groups,
- 'numrows': numrows,
- 'sorting_enabled': '__group__' not in cols})
+ 'numrows': numrows})
if format == 'rss':
data['email_map'] = chrome.get_email_map()
@@ -567,12 +630,12 @@ class ReportModule(Component):
add_link(req, 'alternate', report_href(format='tab', page=p),
_('Tab-delimited Text'), 'text/plain')
if 'REPORT_SQL_VIEW' in req.perm:
- add_link(req, 'alternate',
+ add_link(req, 'alternate',
req.href.report(id=id, format='sql'),
_('SQL Query'), 'text/plain')
# reuse the session vars of the query module so that
- # the query navigation links on the ticket can be used to
+ # the query navigation links on the ticket can be used to
# navigate report results as well
try:
req.session['query_tickets'] = \
@@ -581,7 +644,7 @@ class ReportModule(Component):
req.session['query_href'] = \
req.session['query_href'] = report_href()
# Kludge: we have to clear the other query session
- # variables, but only if the above succeeded
+ # variables, but only if the above succeeded
for var in ('query_constraints', 'query_time'):
if var in req.session:
del req.session[var]
@@ -598,53 +661,110 @@ class ReportModule(Component):
def execute_report(self, req, db, id, sql, args):
"""Execute given sql report (0.10 backward compatibility method)
-
+
:see: ``execute_paginated_report``
"""
- return self.execute_paginated_report(req, db, id, sql, args)[:2]
+ res = self.execute_paginated_report(req, db, id, sql, args)
+ if len(res) == 2:
+ raise res[0]
+ return res[:5]
- def execute_paginated_report(self, req, db, id, sql, args,
+ def execute_paginated_report(self, req, db, id, sql, args,
limit=0, offset=0):
sql, args, missing_args = self.sql_sub_vars(sql, args, db)
if not sql:
raise TracError(_("Report {%(num)s} has no SQL query.", num=id))
+ self.log.debug('Report {%d} with SQL "%s"', id, sql)
+ self.log.debug('Request args: %r', req.args)
cursor = db.cursor()
num_items = 0
- if id != -1 and limit > 0:
- cursor.execute("SELECT COUNT(*) FROM (%s) AS tab" % sql, args)
+ order_by = []
+ limit_offset = None
+ base_sql = sql.replace(SORT_COLUMN, '1').replace(LIMIT_OFFSET, '')
+ if id == -1 or limit == 0:
+ sql = base_sql
+ else:
+ # The number of tickets is obtained
+ count_sql = 'SELECT COUNT(*) FROM (\n%s\n) AS tab' % base_sql
+ self.log.debug("Report {%d} SQL (count): %s", id, count_sql)
+ try:
+ cursor.execute(count_sql, args)
+ except Exception, e:
+ return e, count_sql
num_items = cursor.fetchone()[0]
-
- # get the column names
- cursor.execute("SELECT * FROM (%s) AS tab LIMIT 1" % sql, args)
+
+ # The column names are obtained
+ colnames_sql = 'SELECT * FROM (\n%s\n) AS tab LIMIT 1' % base_sql
+ self.log.debug("Report {%d} SQL (col names): %s", id, colnames_sql)
+ try:
+ cursor.execute(colnames_sql, args)
+ except Exception, e:
+ return e, colnames_sql
cols = get_column_names(cursor)
+ # The ORDER BY columns are inserted
sort_col = req.args.get('sort', '')
+ asc = req.args.get('asc', '1')
+ self.log.debug("%r %s (%s)", cols, sort_col, asc and '^' or 'v')
order_cols = []
+ if sort_col and sort_col not in cols:
+ raise TracError(_('Query parameter "sort=%(sort_col)s" '
+ ' is invalid', sort_col=sort_col))
+ skel = None
if '__group__' in cols:
- sort_col = '' # sorting is disabled (#15030)
+ order_cols.append('__group__')
if sort_col:
- if sort_col in cols:
- order_cols.append(sort_col)
- else:
- raise TracError(_('Query parameter "sort=%(sort_col)s" '
- ' is invalid', sort_col=sort_col))
-
- # get the (partial) report results
- order_by = ''
- if order_cols:
- asc = req.args.get('asc', '1')
- order_by = " ORDER BY %s %s" % (
- ', '.join(db.quote(col) for col in order_cols),
- 'ASC' if asc == '1' else 'DESC')
- sql = "SELECT * FROM (%s) AS tab %s LIMIT %s OFFSET %s" % \
- (sql, order_by, str(limit), str(offset))
- self.log.debug("Query SQL: " + sql)
- cursor.execute(sql, args)
+ sort_col = '%s %s' % (db.quote(sort_col),
+ asc == '1' and 'ASC' or 'DESC')
+
+ if SORT_COLUMN in sql:
+ # Method 1: insert sort_col at specified position
+ sql = sql.replace(SORT_COLUMN, sort_col or '1')
+ elif sort_col:
+ # Method 2: automagically insert sort_col (and __group__
+ # before it, if __group__ was specified) as first criterions
+ if '__group__' in cols:
+ order_by.append('__group__ ASC')
+ order_by.append(sort_col)
+ # is there already an ORDER BY in the original sql?
+ skel = sql_skeleton(sql)
+ before, after = split_sql(sql, _order_by_re, skel)
+ if after: # there were some other criterions, keep them
+ order_by.append(after)
+ sql = ' '.join([before, 'ORDER BY', ', '.join(order_by)])
+
+ # Add LIMIT/OFFSET if pagination needed
+ limit_offset = ''
+ if num_items > limit:
+ limit_offset = ' '.join(['LIMIT', str(limit),
+ 'OFFSET', str(offset)])
+ if LIMIT_OFFSET in sql:
+ # Method 1: insert LIMIT/OFFSET at specified position
+ sql = sql.replace(LIMIT_OFFSET, limit_offset)
+ else:
+ # Method 2: limit/offset is added unless already present
+ skel = skel or sql_skeleton(sql)
+ if 'LIMIT' not in skel.upper():
+ sql = ' '.join([sql, limit_offset])
+ self.log.debug("Report {%d} SQL (order + limit): %s", id, sql)
+ try:
+ cursor.execute(sql, args)
+ except Exception, e:
+ if order_by or limit_offset:
+ add_notice(req, _("Hint: if the report failed due to automatic"
+ " modification of the ORDER BY clause or the"
+ " addition of LIMIT/OFFSET, please look up"
+ " %(sort_column)s and %(limit_offset)s in"
+ " TracReports to see how to gain complete"
+ " control over report rewriting.",
+ sort_column=SORT_COLUMN,
+ limit_offset=LIMIT_OFFSET))
+ return e, sql
rows = cursor.fetchall() or []
cols = get_column_names(cursor)
- return cols, rows, num_items, missing_args
+ return cols, rows, num_items, missing_args, limit_offset
def get_var_args(self, req):
# reuse somehow for #9574 (wiki vars)
@@ -663,8 +783,8 @@ class ReportModule(Component):
def sql_sub_vars(self, sql, args, db=None):
"""Extract $XYZ-style variables from the `sql` query.
- :since 0.13: the `db` parameter is no longer needed and will be removed
- in version 0.14
+ :since 1.0: the `db` parameter is no longer needed and will be removed
+ in version 1.1.1
"""
names = set()
values = []
@@ -706,7 +826,7 @@ class ReportModule(Component):
sql_io.write(repl_literal(expr))
else:
sql_io.write(var_re.sub(repl, expr))
-
+
# Remove arguments that don't appear in the SQL query
for name in set(args) - names:
del args[name]
@@ -748,7 +868,7 @@ class ReportModule(Component):
req.send_header('Content-Length', len(data))
if filename:
req.send_header('Content-Disposition',
- content_disposition(filename=filename))
+ content_disposition('attachment', filename))
req.end_headers()
req.write(data)
raise RequestDone
@@ -769,18 +889,20 @@ class ReportModule(Component):
req.send_header('Content-Length', len(data))
if id:
req.send_header('Content-Disposition',
- content_disposition(filename='report_%s.sql' % id))
+ content_disposition('attachment',
+ 'report_%s.sql' % id))
req.end_headers()
req.write(data)
raise RequestDone
-
+
# IWikiSyntaxProvider methods
-
+
def get_link_resolvers(self):
yield ('report', self._format_link)
def get_wiki_syntax(self):
- yield (r"!?\{(?P<it_report>%s\s*)\d+\}" % WikiParser.INTERTRAC_SCHEME,
+ yield (r"!?\{(?P<it_report>%s\s*)[0-9]+\}" % \
+ WikiParser.INTERTRAC_SCHEME,
lambda x, y, z: self._format_link(x, 'report', y[1:-1], y, z))
def _format_link(self, formatter, ns, target, label, fullmatch=None):
Modified: incubator/bloodhound/trunk/trac/trac/ticket/roadmap.py
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/roadmap.py?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/roadmap.py (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/roadmap.py Tue Oct 16 20:06:09 2012
@@ -2,7 +2,7 @@
#
# Copyright (C) 2004-2009 Edgewall Software
# Copyright (C) 2004-2005 Christopher Lenz <cm...@gmx.de>
-# Copyright (C) 2006-2007 Christian Boos <cb...@neuf.fr>
+# Copyright (C) 2006-2007 Christian Boos <cb...@edgewall.org>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
@@ -295,9 +295,9 @@ def get_ticket_stats(provider, tickets):
def get_tickets_for_milestone(env, db=None, milestone=None, field='component'):
"""Retrieve all tickets associated with the given `milestone`.
- .. versionchanged :: 0.13
+ .. versionchanged :: 1.0
the `db` parameter is no longer needed and will be removed in
- version 0.14
+ version 1.1.1
"""
with env.db_query as db:
fields = TicketSystem(env).get_ticket_fields()
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/batch_modify.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/batch_modify.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/batch_modify.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/batch_modify.html Tue Oct 16 20:06:09 2012
@@ -23,7 +23,9 @@
py:with="field_names = sorted(fields.iterkeys(), key=lambda name: fields[name].label.lower())">
<option></option>
<option py:for="field_name in field_names" py:with="field = fields[field_name]"
- py:if="field_name not in ('id', 'resolution', 'status', 'owner', 'time', 'changetime', 'summary', 'reporter', 'description') and fields[field_name].type != 'text-area'"
+ py:if="field_name not in ('id', 'resolution', 'status', 'owner', 'time', 'changetime', 'summary',
+ 'reporter', 'description')
+ and fields[field_name].type != 'textarea'"
value="$field_name">${field.label}</option>
</select>
</td>
@@ -45,16 +47,16 @@
</tr>
</table>
+ <div id="batchmod_help" i18n:msg="">
+ <strong>Note:</strong> See <a href="${href.wiki('TracBatchModify')}">TracBatchModify</a> for help on using batch modify.
+ </div>
+
<div>
<input type="hidden" name="selected_tickets" value=""/>
<input type="hidden" name="query_href" value="${query_href}"/>
<input type="submit" id="batchmod_submit" name="batchmod_submit" value="${_('Change tickets')}" />
</div>
- <div id="batchmod_help" i18n:msg="">
- <strong>Note:</strong> See <a href="${href.wiki('TracBatchModify')}">TracBatchModify</a> for help on using batch modify.
- </div>
-
</fieldset>
</form>
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_delete.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_delete.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_delete.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_delete.html Tue Oct 16 20:06:09 2012
@@ -7,7 +7,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="layout.html" />
<head>
- <title>Delete Milestone ${milestone.name}</title>
+ <title i18n:msg="name">Delete Milestone ${milestone.name}</title>
<link rel="stylesheet" type="text/css"
href="${chrome.htdocs_location}css/roadmap.css" />
<script type="text/javascript">
@@ -19,7 +19,7 @@
<body>
<div id="content" class="milestone">
- <h1>Delete Milestone ${milestone.name}</h1>
+ <h1 i18n:msg="name">Delete Milestone ${milestone.name}</h1>
<form id="edit" action="" method="post">
<div>
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_edit.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_edit.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_edit.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_edit.html Tue Oct 16 20:06:09 2012
@@ -8,7 +8,7 @@
<xi:include href="layout.html" />
<head>
<py:choose test="milestone.exists">
- <title py:when="True">Edit Milestone ${milestone.name}</title>
+ <title py:when="True" i18n:msg="name">Edit Milestone ${milestone.name}</title>
<title py:otherwise="">New Milestone</title>
</py:choose>
<link rel="stylesheet" type="text/css"
@@ -42,7 +42,7 @@
<body>
<div id="content" class="milestone">
<py:choose test="milestone.exists">
- <h1 py:when="True">Edit Milestone ${milestone.name}</h1>
+ <h1 py:when="True" i18n:msg="name">Edit Milestone ${milestone.name}</h1>
<h1 py:otherwise="">New Milestone</h1>
</py:choose>
@@ -95,7 +95,7 @@
</div>
</fieldset>
<div class="field">
- <fieldset class="iefix">
+ <fieldset>
<label for="description" i18n:msg="">Description (you may use <a tabindex="42"
href="${href.wiki('WikiFormatting')}">WikiFormatting</a> here):</label>
<p><textarea id="description" name="description" class="wikitext trac-resizable" rows="10" cols="78">
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_view.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_view.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_view.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/milestone_view.html Tue Oct 16 20:06:09 2012
@@ -7,7 +7,7 @@
xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="layout.html" />
<head>
- <title>Milestone ${milestone.name}</title>
+ <title i18n:msg="name">Milestone ${milestone.name}</title>
<link py:if="'MILESTONE_MODIFY' in perm(milestone.resource)" rel="alternate" type="application/x-wiki"
title="Edit this milestone" href="${href.milestone(milestone.name, action='edit')}" />
<script type="text/javascript">
@@ -20,7 +20,7 @@
<body>
<div id="content" class="milestone">
- <h1>Milestone ${milestone.name}</h1>
+ <h1 i18n:msg="name">Milestone ${milestone.name}</h1>
<div class="info trac-progress">
<py:choose>
<p py:when="milestone.completed" class="date">
@@ -65,7 +65,7 @@
</fieldset>
</form>
- <div class="description" xml:space="preserve">
+ <div py:if="milestone.description" class="description trac-content" xml:space="preserve">
${wiki_to_html(context, milestone.description)}
</div>
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/query.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/query.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/query.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/query.html Tue Oct 16 20:06:09 2012
@@ -9,23 +9,25 @@
<head>
<title>$title</title>
<script type="text/javascript" src="${chrome.htdocs_location}js/folding.js"></script>
- <script type="text/javascript">/*<![CDATA[*/
+ <script type="text/javascript">
jQuery(document).ready(function($) {
initializeFilters();
- if(batch_modify) {
- initializeBatch();
- }
+ <py:if test="batch_modify">
+ initializeBatch();
+ </py:if>
$("#group").change(function() {
$("#groupdesc").enable(this.selectedIndex != 0)
}).change();
$("fieldset legend.foldable").enableFolding(false);
+ /*<![CDATA[*/
/* Hide the filters for saved queries. */
if (window.location.href.search(/[?&]report=[0-9]+/) != -1)
$("#filters").toggleClass("collapsed");
+ /*]]>*/
/* Hide the columns by default. */
$("#columns").toggleClass("collapsed");
});
- /*]]>*/</script>
+ </script>
</head>
<body>
@@ -118,7 +120,7 @@
<py:when test="field.type in ('text', 'textarea', 'id')">
<input type="text" name="${n_field_name}" value="$constraint_value" size="42" />
</py:when>
-
+
<py:when test="field.type == 'time'"
py:with="(start, end) = '..' in constraint_value and constraint_value.split('..', 1)
or (constraint_value, '')">
@@ -223,14 +225,14 @@
<xi:include href="query_results.html" />
<xi:include py:if="batch_modify" href="batch_modify.html" />
- <div class="buttons"
+ <div id="trac-report-buttons" class="buttons"
py:with="edit = report_resource and 'REPORT_MODIFY' in perm(report_resource);
new = 'REPORT_CREATE' in perm;
delete = report_resource and 'REPORT_DELETE' in perm(report_resource)">
<form py:if="edit" method="get" action="${url_of(report_resource)}">
<div>
<input type="hidden" name="action" value="edit" />
- <input type="submit"
+ <input type="submit"
title="${_('Edit report {%(id)s} corresponding to this query', id=report_resource.id)}"
value="${_('Edit query')}" />
</div>
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/query_results.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/query_results.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/query_results.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/query_results.html Tue Oct 16 20:06:09 2012
@@ -42,14 +42,15 @@
</tr>
</py:def>
${group_heading(*groups[0]) if groups else None}
- <table class="listing tickets">
+ <table class="listing tickets"
+ py:with="num_cols = len(headers) + int(batch_modify or 0)">
<thead py:strip="group_index">
${column_headers()}
</thead>
<py:for each="group_index, (groupname, results) in enumerate(groups)">
<tbody py:if="group_index">
<tr py:if="groupname is not None" class="trac-group">
- <th colspan="${len(headers)}">
+ <th colspan="$num_cols">
${group_heading(groupname, results)}
</th>
</tr>
@@ -57,7 +58,7 @@
</tbody>
<tbody>
<tr py:if="not results" class="even">
- <td colspan="${len(headers)}">
+ <td colspan="$num_cols">
No tickets found
</td>
</tr>
@@ -90,13 +91,13 @@
<py:with vars="result_rows = [t for t in row if result[t]]">
<py:choose>
<tr py:when="ticket_context.resource in context" class="fullrow">
- <td colspan="${len(headers)}">
+ <td colspan="$num_cols">
<p class="meta"><em>(this ticket)</em></p>
</td>
</tr>
<tr py:otherwise="" py:for="r in result_rows" class="fullrow">
<th class="meta">${fields.get(r, {'label': r or 'none'}).label}</th>
- <td colspan="${len(headers)-1}" xml:space="preserve">
+ <td colspan="${num_cols - 1}" xml:space="preserve">
${wiki_to_html(ticket_context, result[r])}
</td>
</tr>
@@ -106,7 +107,7 @@
</py:with>
</py:for>
<tr py:if="group_index == len(groups)-1 and last_group_is_partial">
- <td colspan="${len(headers)}">
+ <td colspan="$num_cols">
<i>(more results for this group on next page)</i>
</td>
</tr>
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/report_list.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/report_list.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/report_list.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/report_list.html Tue Oct 16 20:06:09 2012
@@ -40,11 +40,12 @@
<div py:if="saved_query_href">
<form method="get" action="${href.report()}">
<div class="inlinebuttons">
+
<input type="hidden" name="action" value="clear" />
- <input type="submit" class="inlinebutton" title="Forget last query" value="${_('Clear')}" />
+ <input type="submit" value="${captioned_button('x', _('Clear'))}" title="Forget last query" class="trac-delete" />
</div>
</form>
- <h2><a href="$saved_query_href"><em>Return to Last Query</em></a></h2>
+ <h3><a href="$saved_query_href"><em>Return to Last Query</em></a></h3>
<span class="foldable" />
<div class="description">
<p>Continue browsing through the current list of results,
@@ -53,7 +54,7 @@
</div>
<div py:if="query_href">
- <h2><a href="$query_href"><em>Custom Query</em></a></h2>
+ <h3><a href="$query_href"><em>Custom Query</em></a></h3>
<span class="foldable" />
<div class="description">
<p>Compose a new ticket query by selecting filters and columns to display.</p>
@@ -78,16 +79,21 @@
<form py:if="can_delete" method="get" action="${href.report(id)}">
<div class="inlinebuttons">
<input type="hidden" name="action" value="delete" />
- <input type="submit" class="inlinebutton" title="Delete report" value="${_('Delete')}" />
+ <input type="submit" value="${captioned_button('â', _('Delete'))}"
+ title="Delete report" class="trac-delete" />
</div>
</form>
<form py:if="can_edit" method="get" action="${href.report(id)}">
<div class="inlinebuttons">
<input type="hidden" name="action" value="edit" />
- <input type="submit" class="inlinebutton" title="Edit report" value="${_('Edit')}" />
+ <input type="submit" value="${captioned_button('â', _('Edit'))}"
+ title="Edit report" />
</div>
</form>
- <h2><a title="View report" href="${href.report(id)}">{$id} <em>$title</em></a></h2>
+ <h3><a title="View report" href="${href.report(id)}" py:choose="sort">
+ <py:when test="'title'">$title <em>{$id}</em></py:when>
+ <py:otherwise><em>{$id}</em> $title</py:otherwise>
+ </a></h3>
<span class="foldable" />
<div py:if="description" class="description" xml:space="preserve">
${wiki_to_html(context, description)}
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/report_view.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/report_view.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/report_view.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/report_view.html Tue Oct 16 20:06:09 2012
@@ -84,8 +84,7 @@
<th py:for="header in header_group" py:if="not header.hidden" py:with="fullrow = header is header_group[-1]"
colspan="${'100' if fullrow else None}"
class="${'asc' if header.asc else 'desc' if header.asc is not None else None}">
- <a py:strip="not sorting_enabled"
- href="${report_href(sort=header.col, asc=not header.asc)}">
+ <a href="${report_href(sort=header.col, asc=not header.asc)}">
$header.title
</a>
</th>
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/roadmap.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/roadmap.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/roadmap.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/roadmap.html Tue Oct 16 20:06:09 2012
@@ -12,7 +12,6 @@
<body>
<div id="content" class="roadmap">
- <h1>Roadmap</h1>
<form id="prefs" method="get" action="">
<div>
@@ -30,6 +29,8 @@
</div>
</form>
+ <h1>Roadmap</h1>
+
<div class="milestones">
<div py:for="idx, milestone in enumerate(milestones)" class="milestone">
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket.html Tue Oct 16 20:06:09 2012
@@ -19,8 +19,12 @@
$("div.description").find("h1,h2,h3,h4,h5,h6").addAnchor(_("Link to this section"));
$(".foldable").enableFolding(false, true);
<py:when test="ticket.exists">/*<![CDATA[*/
+ $("#attachments").toggleClass("collapsed");
+ $("#trac-up-attachments").click(function () {
+ $("#attachments").removeClass("collapsed");
+ return true;
+ });
$("#modify").parent().toggleClass("collapsed");
- $(".trac-topnav a").click(function() { $("#modify").parent().removeClass("collapsed"); });
/* only enable control elements for the currently selected action */
var actions = $("#action input[name='action']");
@@ -34,6 +38,30 @@
actions.click(updateActionFields);
updateActionFields();
+ function setRevertHandler() {
+ $("button.trac-revert").click(function() {
+ var div = $("div", this);
+ var field_name = div[0].id.substr(7);
+ var field_value = div.text();
+ var input = $("#propertyform *[name=field_" + field_name + "]");
+ if (input.length > 0) {
+ if (input.filter("input[type=radio]").length > 0) {
+ input.val([field_value]);
+ } else if (input.filter("input[type=checkbox]").length > 0) {
+ input.val(field_value == "1" ? [field_value] : []);
+ } else {
+ input.val(field_value);
+ }
+ } else { // Special case for CC checkbox
+ input = $("#propertyform input[name=cc_update]").val([]);
+ }
+ input.change();
+ $(this).closest("li").remove();
+ return false;
+ });
+ }
+ setRevertHandler();
+
var comment_focused = false;
$("#comment").focus(function() { comment_focused = true; })
.blur(function() { comment_focused = false; });
@@ -45,6 +73,8 @@
if (!$('#trac-comments-oldest').checked())
$('#trac-comments-oldest').click().change();
$("#changelog").replaceWith(items.filter("#changelog"));
+ if ($('#trac-comments-only-toggle').attr('checked'))
+ $('#trac-comments-only-toggle').click().attr('checked', true);
// Show warning
var new_changes = $("#changelog .trac-new");
$("#trac-edit-warning").toggle(new_changes.length != 0);
@@ -56,6 +86,7 @@
var preview = $("#ticketchange").html(items.filter('#preview').children());
var show_preview = preview.children().length != 0;
$("#ticketchange").toggle(show_preview);
+ setRevertHandler();
// Collapse property form if comment editor has focus
if (show_preview && comment_focused)
$("#modify").parent().addClass("collapsed");
@@ -66,7 +97,6 @@
}, "#changelog .trac-loading");
/*]]>*/
<py:if test="preview_mode">
- $("#attachments").toggleClass("collapsed");
$("#trac-add-comment").scrollToTop();
</py:if>
</py:when>
@@ -96,30 +126,10 @@
has_edit_comment = 'TICKET_EDIT_COMMENT' in perm(ticket.resource);
has_property_editor = not version and version != 0 and not cnum_edit
and (can_append or can_modify or can_edit or can_create)">
- <div class="trac-topnav" py:if="ticket.exists and has_property_editor">
- <a href="#propertyform" title="Go to the ticket editor">Modify</a> ↓
- </div>
- <h1 id="trac-ticket-title" py:choose="">
- <py:when test="ticket.exists">
- <a href="${href.ticket(ticket.id)}" i18n:msg="id">Ticket #${ticket.id}</a>
- <span class="status">(${ticket.status}<py:if
- test="ticket.type"> ${ticket.type}</py:if><py:if
- test="ticket.resolution">: ${ticket.resolution}</py:if>)</span>
- <py:choose test="">
- <py:when test="version is None" />
- <py:when test="version == 0">
- — <i18n:msg>at <a href="#comment:description">Initial Version</a></i18n:msg>
- </py:when>
- <py:otherwise>
- — <i18n:msg params="version">at <a href="#comment:$version">Version $version</a></i18n:msg>
- </py:otherwise>
- </py:choose>
- </py:when>
- <py:otherwise>
- Create New Ticket <span py:if="preview_mode and ticket.type" class="status">(${ticket.type})</span>
- </py:otherwise>
- </h1>
+ <h1 py:if="not ticket.exists">
+ Create New Ticket <span py:if="preview_mode and ticket.type" class="status">(${ticket.type})</span>
+ </h1>
<py:if test="ticket.exists">
<xi:include href="ticket_box.html" py:with="preview_mode = change_preview.fields"/>
@@ -150,7 +160,7 @@
</form>
</div>
- <h2 class="foldable">Change History</h2>
+ <h3 class="foldable">Change History <span class="trac-count">(${len(changes)})</span></h3>
<div id="changelog">
<py:for each="change in changes">
@@ -169,33 +179,30 @@
else href.newticket() + '#ticket'}">
<!--! Add comment -->
<div py:if="ticket.exists and can_append" id="trac-add-comment" class="field">
- <div class="trac-nav">
- <a href="#content" title="View ticket fields and description">View</a> ↑
- </div>
- <h2>
- <a id="edit" onfocus="$('#comment').get(0).focus()">Add a comment</a>
- </h2>
- <div id="trac-edit-warning" class="warning system-message"
- style="${'display: none' if start_time == ticket['changetime'] else None}"
- i18n:msg="">
- This ticket has been modified since you started editing. You should review the
- <em class="trac-new">other modifications</em> which have been appended above,
- and any <em class="trac-conflict">conflicts</em> shown in the preview below.
- You can nevertheless proceed and submit your changes if you wish so.
- </div>
- <!--! Comment field -->
- <fieldset class="iefix">
- <label for="comment" i18n:msg="">You may use
- <a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a>
- here.
- </label>
- <textarea id="comment" name="comment" class="wikitext trac-resizable" rows="10" cols="78">
+ <h3 class="foldable" id="edit">Add Comment</h3>
+ <div>
+ <div id="trac-edit-warning" class="warning system-message"
+ style="${'display: none' if start_time == ticket['changetime'] else None}"
+ i18n:msg="">
+ This ticket has been modified since you started editing. You should review the
+ <em class="trac-new">other modifications</em> which have been appended above,
+ and any <em class="trac-conflict">conflicts</em> shown in the preview below.
+ You can nevertheless proceed and submit your changes if you wish so.
+ </div>
+ <!--! Comment field -->
+ <fieldset>
+ <label for="comment" i18n:msg="">You may use
+ <a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a>
+ here.
+ </label>
+ <textarea id="comment" name="comment" class="wikitext trac-resizable" rows="10" cols="78">
${comment}</textarea>
- </fieldset>
+ </fieldset>
+ </div>
</div>
<div>
- <h2 py:if="ticket.exists" class="foldable">Modify Ticket</h2>
+ <h3 py:if="ticket.exists" class="foldable">Modify Ticket</h3>
<div id="modify">
<!--! Properties -->
<fieldset id="properties" py:if="can_modify or can_edit or can_create"
@@ -225,7 +232,7 @@ ${comment}</textarea>
<tr>
<th><label for="field-description">Description:</label></th>
<td class="fullrow" colspan="3">
- <fieldset class="iefix">
+ <fieldset>
<label for="field-description" id="field-description-help" i18n:msg="">You may use
<a tabindex="42" href="${href.wiki('WikiFormatting')}">WikiFormatting</a> here.
</label>
@@ -364,7 +371,7 @@ ${value}</textarea>
</p>
<div py:if="ticket.exists" class="trac-nav">
- <a href="#attachments" title="Go to the list of attachments">Attachments</a> ↑
+ <a href="#attachments" id="trac-up-attachments" title="Go to the list of attachments">Attachments</a> ↑
</div>
<div class="buttons">
<py:if test="ticket.exists">
@@ -378,7 +385,8 @@ ${value}</textarea>
</form>
- <xi:include href="ticket_box.html" py:if="not ticket.exists" py:with="preview_mode = True"/>
+ <xi:include href="ticket_box.html" py:if="not ticket.exists"
+ py:with="hide = not preview_mode; preview_mode = True"/>
<div id="help" i18n:msg="">
<strong>Note:</strong> See
Modified: incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket_box.html
URL: http://svn.apache.org/viewvc/incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket_box.html?rev=1398968&r1=1398967&r2=1398968&view=diff
==============================================================================
--- incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket_box.html (original)
+++ incubator/bloodhound/trunk/trac/trac/ticket/templates/ticket_box.html Tue Oct 16 20:06:09 2012
@@ -7,6 +7,7 @@ Arguments:
- description_change: metadata about changes in the description
- can_append: True if the user is allowed to append to tickets
- preview_mode: if True, show the "draft" background
+ - hide=False: if True, hide the box
- reporter_link=None: rendered link for the reporter field
- owner_link=None: rendered link for the owner field
-->
@@ -14,32 +15,63 @@ Arguments:
xmlns:py="http://genshi.edgewall.org/"
xmlns:xi="http://www.w3.org/2001/XInclude"
xmlns:i18n="http://genshi.edgewall.org/i18n"
- id="ticket" class="${'ticketdraft' if preview_mode else None}">
+ id="ticket" class="trac-content ${'ticketdraft' if preview_mode else None}"
+ style="${'display: none' if value_of('hide', False) else None}">
+
<div class="date">
<p i18n:msg="created" py:if="ticket.exists">Opened ${pretty_dateinfo(ticket.time)}</p>
- <p i18n:msg="modified" py:if="ticket.changetime != ticket.time">Last modified ${pretty_dateinfo(ticket.changetime)}</p>
+ <p i18n:msg="closed" py:if="closetime">Closed ${pretty_dateinfo(closetime)}</p>
+ <p i18n:msg="modified" py:if="ticket.changetime != ticket.time and ticket.changetime != closetime">
+ Last modified ${pretty_dateinfo(ticket.changetime)}</p>
<p py:if="not ticket.exists"><span class="trac-loading"/><i>(ticket not yet created)</i></p>
</div>
<!--! use a placeholder if it's a new ticket -->
- <h2 class="summary searchable">$ticket.summary</h2>
+
+ <h2>
+ <a href="${href.ticket(ticket.id)}" class="trac-id">#${ticket.id}</a>
+ <span class="trac-status">
+ ${'status' in fields_map and fields[fields_map['status']].rendered or ticket.status}
+ </span>
+ <span class="trac-type" py:if="ticket.type">
+ ${'type' in fields_map and fields[fields_map['type']].rendered or ticket.type}
+ </span>
+ <span class="trac-resolution" py:if="ticket.resolution">
+ (${'resolution' in fields_map and fields[fields_map['resolution']].rendered or ticket.resolution})
+ </span>
+ </h2>
+
+ <h1 id="trac-ticket-title" class="searchable">
+ <span class="summary">$ticket.summary</span>
+ <py:choose test="">
+ <py:when test="version is None" />
+ <py:when test="version == 0">
+ — <i18n:msg>at <a href="#comment:description">Initial Version</a></i18n:msg>
+ </py:when>
+ <py:otherwise>
+ — <i18n:msg params="version">at <a href="#comment:$version">Version $version</a></i18n:msg>
+ </py:otherwise>
+ </py:choose>
+ </h1>
<table class="properties"
py:with="fields = [f for f in fields if not f.skip and f.name not in ('type', 'owner')]">
- <tr>
- <th id="h_reporter">Reported by:</th>
- <td headers="h_reporter" class="searchable">
- ${reporter_link if defined('reporter_link') else authorinfo(ticket.reporter)}
- </td>
- <th id="h_owner">Owned by:</th>
- <td headers="h_owner">
- ${(owner_link if defined('owner_link') else authorinfo(ticket.owner)) if ticket.owner else ''}
- </td>
+ <tr py:with="
+ v_reporter = reporter_link if defined('reporter_link') else authorinfo(ticket.reporter);
+ v_owner = (owner_link if defined('owner_link') else authorinfo(ticket.owner)) if ticket.owner else ''
+ ">
+ <th id="h_reporter" class="${classes(missing=not v_reporter)}">Reported by:</th>
+ <td headers="h_reporter" class="searchable">$v_reporter</td>
+ <th id="h_owner" class="${classes(missing=not v_owner)}">Owned by:</th>
+ <td headers="h_owner">$v_owner</td>
</tr>
<tr py:for="row in group(fields, 2, lambda f: f.type != 'textarea')"
py:with="fullrow = len(row) == 1">
<py:for each="idx, field in enumerate(row)">
<th py:if="idx == 0 or not fullrow"
- id="${'h_' + field.name if field else None}">
+ id="${'h_' + field.name if field else None}"
+ class="${classes(missing=not field or
+ ('rendered' in field and not field.rendered) or
+ not ticket[field.name])}" >
<py:if test="field"><i18n:msg params="field">${field.label or field.name}:</i18n:msg></py:if>
</th>
<td py:if="idx == 0 or not fullrow"
@@ -59,10 +91,10 @@ Arguments:
<div class="description">
<h3 id="comment:description">
Description
- <span py:if="description_change" class="lastmod" title="$description_change.date">
+ <a href="${href.ticket(ticket.id, action='diff', version=description_change.cnum)}"
+ py:if="description_change" class="lastmod trac-diff" title="$description_change.date">
<i18n:msg params="author">(last modified by ${authorinfo(description_change.author)})</i18n:msg>
- (<a href="${href.ticket(ticket.id, action='diff', version=description_change.cnum)}">diff</a>)
- </span>
+ </a>
</h3>
<!--! Quote the description (only for existing tickets) -->
@@ -70,7 +102,7 @@ Arguments:
id="addreply" method="get" action="#comment">
<div class="inlinebuttons">
<input type="hidden" name="replyto" value="description" />
- <input type="submit" name="reply" value="${_('Reply')}" title="Reply, quoting this description" />
+ <input type="submit" name="reply" value="${captioned_button('â³', _('Reply'))}" title="Reply, quoting this description" />
</div>
</form>
<div py:if="ticket.description" class="searchable" xml:space="preserve">