Changeset 4451
- Timestamp:
- Dec 14, 2006, 5:53:18 PM (17 years ago)
- Location:
- trunk
- Files:
-
- 55 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/templates/attachment.html
r4173 r4451 15 15 16 16 <div py:choose="mode" id="content" class="attachment"> 17 17 <!--! TODO: parent.name -> context.parent.name --> 18 18 <py:when test="'new'"> 19 <h1>Add Attachment to <a href="$ parent.href">$parent.name</a></h1>19 <h1>Add Attachment to <a href="${context.parent.self_href()}">$parent.name</a></h1> 20 20 <form id="attachment" method="post" enctype="multipart/form-data" action=""> 21 21 <div class="field"> … … 44 44 <div class="buttons"> 45 45 <input type="hidden" name="action" value="new" /> 46 <input type="hidden" name="type" value="$ parent.type" />47 <input type="hidden" name="id" value="$ parent.id" />46 <input type="hidden" name="type" value="$context.parent.resource" /> 47 <input type="hidden" name="id" value="$context.parent.id" /> 48 48 <input type="submit" value="Add attachment" /> 49 49 <input type="submit" name="cancel" value="Cancel" /> … … 53 53 54 54 <py:when test="'delete'"> 55 <h1><a href="$ parent.href">$parent.name</a>: $attachment.filename</h1>55 <h1><a href="${context.parent.self_href()}">$parent.name</a>: $attachment.filename</h1> 56 56 <p><strong>Are you sure you want to delete this attachment?</strong><br /> 57 57 This is an irreversible operation.</p> … … 68 68 69 69 <py:when test="'list'"> 70 <h1><a href="$ parent.href">$parent.name</a></h1>71 ${list_of_attachments( attachments, href.attachment(parent.type,parent.id))}70 <h1><a href="${context.parent.self_href()}">$parent.name</a></h1> 71 ${list_of_attachments(context.parent, attachments, href.attachment(context.parent.resource, context.parent.id))} 72 72 </py:when> 73 73 74 74 <py:otherwise> <!--! 'render' mode --> 75 <h1><a href="$ parent.href">$parent.name</a>: $attachment.filename</h1>75 <h1><a href="${context.parent.self_href()}">$parent.name</a>: $attachment.filename</h1> 76 76 <table id="info" summary="Description"> 77 77 <tbody> … … 84 84 <tr> 85 85 <td class="message searchable"> 86 ${ wiki_to_html(attachment.description)}86 ${context.parent.wiki_to_html(attachment.description)} 87 87 </td> 88 88 </tr> -
trunk/templates/browser.html
r4438 r4451 102 102 <span class="change" py:choose=""> 103 103 <py:when test="wiki_format_messages"> 104 ${ wiki_to_oneliner(change.message, shorten=True)}104 ${context('changeset', change.rev).wiki_to_oneliner(change.message, shorten=True)} 105 105 </py:when> 106 106 <py:otherwise>${shorten_line(change.message)}</py:otherwise> … … 124 124 <td class="message searchable" py:choose=""> 125 125 <py:when test="wiki_format_messages"> 126 ${ wiki_to_html(file.changeset.message, escape_newlines=True)}126 ${context('changeset', file.changeset.rev).wiki_to_html(file.changeset.message, escape_newlines=True)} 127 127 </py:when> 128 128 <py:otherwise>${file.changeset.message}</py:otherwise> -
trunk/templates/changeset.html
r4367 r4451 108 108 <dt class="property $prop.htmlclass">$prop.name:</dt> 109 109 <dd class="$prop.htmlclass" py:choose=""> 110 <py:when test="prop.wikiflag">${ wiki_to_html(prop.value)}</py:when>110 <py:when test="prop.wikiflag">${context.wiki_to_html(prop.value)}</py:when> 111 111 <py:otherwise>$prop.value</py:otherwise> 112 112 </dd> … … 115 115 <dd class="message searchable" py:choose=""> 116 116 <py:when test="wiki_format_messages"> 117 ${ wiki_to_html(changeset.message, escape_newlines=True)}117 ${context.wiki_to_html(changeset.message, escape_newlines=True)} 118 118 </py:when> 119 119 <py:otherwise>${changeset.message}</py:otherwise> -
trunk/templates/macros.html
r4438 r4451 148 148 - 149 149 --> 150 <py:def function="list_of_attachments( attachments, attach_href, compact=False)">150 <py:def function="list_of_attachments(context, attachments, attach_href, compact=False)"> 151 151 <py:def function="show_one_attachment(attachment)"> 152 <a href="${href('attachment', attachment.parent_type, 153 attachment.parent_id, attachment.filename)}" 152 <a href="${context.href('attachment', context.resource, context.id, attachment.filename)}" 154 153 title="View attachment">$attachment.filename</a> 155 154 (${sizeinfo(attachment.size)}) - added by <em>$attachment.author</em> … … 162 161 <li py:for="attachment in attachments"> 163 162 ${show_one_attachment(attachment)} 164 <q py:if="compact and attachment.description">${ wiki_to_oneliner(attachment.description)}</q>163 <q py:if="compact and attachment.description">${context('attachment', attachment.filename).wiki_to_oneliner(attachment.description)}</q> 165 164 </li> 166 165 </ul> … … 173 172 <dt>${show_one_attachment(attachment)}</dt> 174 173 <dd py:if="attachment.description"> 175 ${ wiki_to_oneliner(attachment.description)}174 ${context('attachment', attachment.filename).wiki_to_oneliner(attachment.description)} 176 175 </dd> 177 176 </py:for> -
trunk/templates/milestone_view.html
r4202 r4451 70 70 </form> 71 71 72 <div class="description">${ wiki_to_html(milestone.description)}</div>72 <div class="description">${context.wiki_to_html(milestone.description)}</div> 73 73 74 74 <div py:if="'MILESTONE_MODIFY' in perm or 'MILESTONE_DELETE' in perm" -
trunk/templates/query.rss
r4229 r4451 18 18 <pubDate py:if="result.time">${http_date(result.time)}</pubDate> 19 19 <author py:if="result.reporter">$result.reporter</author> 20 <description>${unicode( wiki_to_html(result.description, absurls=True))}</description>20 <description>${unicode(context('ticket', result.id, abs_urls=True).wiki_to_html(result.description))}</description> 21 21 <category>Results</category> 22 22 <comments>$href#changelog</comments> -
trunk/templates/query_div.html
r4292 r4451 61 61 <p class="meta">Reported by <strong>${result.reporter}</strong>, 62 62 ${dateinfo(result.time)} ago<py:if test="result.description">:</py:if></p> 63 <p py:if="result.description">${ wiki_to_html(result.description)}</p>63 <p py:if="result.description">${context('ticket', result.id).wiki_to_html(result.description)}</p> 64 64 </td> 65 65 </tr> -
trunk/templates/report.rss
r4229 r4451 28 28 </py:when> 29 29 <py:when test="col == 'description'"> 30 <description>${unicode( wiki_to_html(cell.value, absurls=True))}</description>30 <description>${unicode(row.context.wiki_to_html(cell.value))}</description> 31 31 </py:when> 32 32 </py:choose> 33 33 </py:with> 34 34 </py:for> 35 <link py:if="row.id">${ abs_href.ticket(row.id)}</link>36 <guid isPermaLink="false" py:if="row.id">${ abs_href.ticket(row.id)}</guid>35 <link py:if="row.id">${row.context.self_href()}</link> 36 <guid isPermaLink="false" py:if="row.id">${row.context.self_href()}</guid> 37 37 <category>Report</category> 38 38 </item> -
trunk/templates/report_view.html
r4386 r4451 7 7 </h1> 8 8 9 <div py:if="report.description" id="description">${ wiki_to_html(report.description)}</div>9 <div py:if="report.description" id="description">${context.wiki_to_html(report.description)}</div> 10 10 11 11 <div py:if="report.id != -1 and (report.can.create or report.can.modify or report.can.delete)" class="buttons"> … … 81 81 <py:when test="col in ('ticket', 'id')"> 82 82 <td class="ticket" py:attrs="td_attrs"> 83 <a title="View ticket" href="${ href.ticket(cell.value)}">#$cell.value</a>83 <a title="View ticket" href="${row.context.self_href()}">#$cell.value</a> 84 84 <hr py:if="fullrow"/> 85 85 </td> … … 88 88 <py:when test="col == 'summary' and row.id"> 89 89 <td class="$col" py:attrs="td_attrs"> 90 <a title="View ticket" href="${ href.ticket(row.id)}">$cell.value</a>90 <a title="View ticket" href="${row.context.self_href()}">$cell.value</a> 91 91 <hr py:if="fullrow"/> 92 92 </td> … … 113 113 114 114 <py:when test="col == 'description'"> 115 <td class="$col" py:attrs="td_attrs">${ wiki_to_html(cell.value)}115 <td class="$col" py:attrs="td_attrs">${row.context.wiki_to_html(cell.value)} 116 116 <hr py:if="fullrow"/> 117 117 </td> -
trunk/templates/revisionlog.html
r4437 r4451 99 99 <tbody> 100 100 <py:for each="idx, item in enumerate(items)"> 101 <py:with vars="change = changes[item.rev]; odd_even = idx % 2 and 'odd' or 'even'"> 101 <py:with vars="change = changes[item.rev]; 102 change_context = context('changeset', change.rev); 103 odd_even = idx % 2 and 'odd' or 'even'"> 102 104 <!--! highlight copy or rename operations --> 103 105 <tr py:if="item.copyfrom_path" class="$odd_even"> … … 134 136 <py:when test="verbose"></py:when> 135 137 <py:when test="wiki_format_messages"> 136 ${ wiki_to_oneliner(change.message)}138 ${change_context.wiki_to_oneliner(change.message)} 137 139 </py:when> 138 140 <py:otherwise>shorten_line(change.message)</py:otherwise> … … 143 145 <td class="summary" colspan="7" py:choose=""> 144 146 <py:when test="wiki_format_messages"> 145 ${ wiki_to_html(change.message, escape_newlines=True)}147 ${change_context.wiki_to_html(change.message, escape_newlines=True)} 146 148 </py:when> 147 149 <py:otherwise><pre>${change.message}</pre></py:otherwise> -
trunk/templates/revisionlog.rss
r4228 r4451 13 13 </image> 14 14 15 <item py:for="item in items" py:with="change = changes[item.rev] ">15 <item py:for="item in items" py:with="change = changes[item.rev]; item_context = context('changeset', change.rev, abs_urls=True)"> 16 16 <author py:if="change.author" py:with="a = change.author">${a and '@' in a and a or email_map.get(a)}</author> 17 17 <pubDate>${http_date(change.date)}</pubDate> … … 20 20 <guid isPermaLink="false">${abs_href.changeset(item.rev, item.path)}</guid> 21 21 <description py:with="m = change.message">${ 22 unicode(wiki_format_messages and (verbose and wiki_to_html(m, absurls=True) \23 or wiki_to_oneliner(m, absurls=True)) \22 unicode(wiki_format_messages and (verbose and item_context.wiki_to_html(m) \ 23 or item_context.wiki_to_oneliner(m)) \ 24 24 or m) 25 25 }</description> -
trunk/templates/roadmap.html
r4238 r4451 58 58 </div> 59 59 60 <div class="description">${ wiki_to_html(milestone.description)}</div>60 <div class="description">${context('milestone', milestone.name).wiki_to_html(milestone.description)}</div> 61 61 62 62 </li> -
trunk/templates/ticket.rss
r4229 r4451 1 1 <?xml version="1.0"?> 2 2 <rss version="2.0" xmlns:py="http://genshi.edgewall.org/"> 3 <channel >3 <channel py:with="abs_context = context(abs_urls=True)"> 4 4 <title>${project.name}: Ticket $title</title> 5 5 <link>${abs_href.ticket(ticket.id)}</link> 6 <description>${unicode( wiki_to_html(ticket.description, absurls=True))}</description>6 <description>${unicode(abs_context.wiki_to_html(ticket.description))}</description> 7 7 <language>en-us</language> 8 8 <image py:if="chrome.logo.src"> … … 23 23 <ul> 24 24 <py:for each="field, value in change.fields.items()"> 25 <li><strong>$field</strong> 25 <li><strong>$field</strong> 26 26 <py:choose> 27 27 <py:when test="not value.old"> … … 39 39 </ul> 40 40 </py:if> 41 ${unicode( wiki_to_html(change.comment, absurls=True))}41 ${unicode(abs_context.wiki_to_html(change.comment, absurls=True))} 42 42 </description> 43 43 <category>Ticket</category> -
trunk/templates/ticket_diff.html
r4347 r4451 56 56 <dd class="message" py:choose=""> 57 57 <em py:when="multi" class="multi">(multiple changes)</em> 58 <py:otherwise>${ wiki_to_html(change.comment)}</py:otherwise>58 <py:otherwise>${context.wiki_to_html(change.comment)}</py:otherwise> 59 59 </dd> 60 60 </dl> -
trunk/templates/ticket_history.html
r4406 r4451 52 52 <td class="date">${format_datetime(item.date)}</td> 53 53 <td class="author" title="${item.ipnr and 'IP-Address: ' + item.ipnr or None">$item.author</td> 54 <td class="comment">${ wiki_to_oneliner(item.comment, shorten=True)}</td>54 <td class="comment">${context.wiki_to_oneliner(item.comment, shorten=True)}</td> 55 55 </tr> 56 56 </tbody> -
trunk/templates/ticket_new.html
r4400 r4451 36 36 <fieldset py:if="ticket.description" id="preview"> 37 37 <legend>Description Preview</legend> 38 ${ wiki_to_html(ticket.description)}38 ${context.wiki_to_html(ticket.description)} 39 39 </fieldset> 40 40 </div> -
trunk/templates/ticket_view.html
r4410 r4451 91 91 </h3> 92 92 <div class="searchable"> 93 ${ wiki_to_html(ticket.description)}93 ${context.wiki_to_html(ticket.description)} 94 94 </div> 95 95 </div> … … 98 98 99 99 <py:if test="not version and version != 0"> 100 ${list_of_attachments( attachments, attach_href)}100 ${list_of_attachments(context, attachments, attach_href)} 101 101 </py:if> 102 102 … … 160 160 </ul> 161 161 <div py:if="change.comment" class="comment searchable"> 162 ${ wiki_to_html(change.comment)}162 ${context.wiki_to_html(change.comment)} 163 163 </div> 164 164 </div> … … 187 187 <fieldset py:if="comment" id="preview"> 188 188 <legend>Comment Preview</legend> 189 ${ wiki_to_html(comment)}189 ${context.wiki_to_html(comment)} 190 190 </fieldset> 191 191 </div> -
trunk/templates/timeline.html
r4334 r4451 41 41 <py:if test="event.author">by ${event.author}</py:if> 42 42 </a></dt> 43 <dd class="${event.kind}" py:with="wikify = event.use_oneliner and partial( wiki_to_oneliner, shorten=event.shorten_oneliner) orwiki_to_html">43 <dd class="${event.kind}" py:with="wikify = event.use_oneliner and partial(event.context.wiki_to_oneliner, shorten=event.shorten_oneliner) or event.context.wiki_to_html"> 44 44 ${event.markup} 45 <py:if test="event. message">${wikify(event.message)}</py:if>45 <py:if test="event.wikitext">${wikify(event.wikitext)}</py:if> 46 46 </dd> 47 47 </py:for> -
trunk/templates/timeline.rss
r4336 r4451 19 19 </py:with> 20 20 <pubDate>${http_date(event.date)}</pubDate> 21 <link>${event.abs_href (req)}</link>22 <guid isPermaLink="false">${event.abs_href (req)}/${event.dateuid()}</guid>21 <link>${event.abs_href}</link> 22 <guid isPermaLink="false">${event.abs_href}/${event.dateuid()}</guid> 23 23 <description>${ 24 event.markup25 }<py:if test="event. message">${wiki_to_html(event.message, absurls=True)}</py:if></description>24 unicode(event.markup) 25 }<py:if test="event.wikitext">${unicode(event.context(abs_urls=True).wiki_to_html(event.wikitext))}</py:if></description> 26 26 </item> 27 27 -
trunk/templates/wiki_diff.html
r4406 r4451 52 52 <dd class="message" py:choose=""> 53 53 <em py:when="multi" class="multi">(multiple changes)</em> 54 <py:otherwise>${ wiki_to_html(change.comment)}</py:otherwise>54 <py:otherwise>${context.wiki_to_html(change.comment)}</py:otherwise> 55 55 </dd> 56 56 </dl> -
trunk/templates/wiki_edit.html
r4218 r4451 44 44 <tbody> 45 45 <tr><th scope="col">Preview of future version ${page.version+1} (modified by $author)</th></tr> 46 <tr><td class="message">${ wiki_to_html(comment)}</td></tr>46 <tr><td class="message">${context.wiki_to_html(comment)}</td></tr> 47 47 </tbody> 48 48 </table> 49 49 <fieldset id="preview"> 50 50 <legend>Preview (<a href="#edit">skip</a>)</legend> 51 <div class="wikipage">${ wiki_to_html(page.text)}</div>51 <div class="wikipage">${context.wiki_to_html(page.text)}</div> 52 52 </fieldset> 53 53 </py:when> -
trunk/templates/wiki_history.html
r4406 r4451 49 49 <td class="date">${format_datetime(item.date)}</td> 50 50 <td class="author" title="${item.ipnr and 'IP-Address: ' + item.ipnr or None">$item.author</td> 51 <td class="comment">${ wiki_to_oneliner(item.comment, shorten=True)}</td>51 <td class="comment">${context.wiki_to_oneliner(item.comment, shorten=True)}</td> 52 52 </tr> 53 53 </tbody> -
trunk/templates/wiki_view.html
r4365 r4451 45 45 </th></tr> 46 46 <tr><td class="message"> 47 ${ wiki_to_oneliner(comment or '--')}47 ${context.wiki_to_html(page.comment or '--')} 48 48 </td></tr> 49 49 </tbody> … … 53 53 <div class="wikipage searchable" py:choose=""> 54 54 <py:when test="page.exists"> 55 ${ wiki_to_html(page.text)}55 ${context.wiki_to_html(page.text)} 56 56 </py:when> 57 57 <py:otherwise> … … 60 60 </div> 61 61 62 ${list_of_attachments( attachments, attach_href, compact=True)}62 ${list_of_attachments(context, attachments, attach_href, compact=True)} 63 63 64 64 <py:with vars="modify_perm = 'WIKI_MODIFY' in perm; -
trunk/trac/attachment.py
r4356 r4451 36 36 from trac.web import HTTPBadRequest, IRequestHandler 37 37 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 38 from trac.wiki.api import IWikiSyntaxProvider 38 from trac.wiki.api import IWikiSyntaxProvider, Context 39 39 40 40 … … 134 134 135 135 def _get_title(self): 136 # TODO: get that from the parent context 136 137 return '%s%s: %s' % (self.parent_type == 'ticket' and '#' or '', 137 138 self.parent_id, self.filename) … … 335 336 # Populate attachment.parent: 336 337 parent_href = req.href(parent_type, parent_id) 338 # FIXME: Context should take care of 'name' as well 337 339 if parent_type == 'ticket': 338 340 parent_name = 'Ticket #' + parent_id 339 341 else: # 'wiki' 340 342 parent_name = parent_id 341 return {'type': parent_type, 'id': parent_id,342 'name': parent_name, 'href': parent_href}343 return (Context(self.env, req, parent_type, parent_id), 344 parent_name) 343 345 344 346 action = req.args.get('action', 'view') … … 351 353 if len(segments) == 1: 352 354 # No specific attachment specified, show the list 355 parent_context, pname = parent_data(parent_type, last_segment) 353 356 data = { 354 357 'mode': 'list', 355 'parent': parent_data(parent_type, last_segment), 356 'attachments': Attachment.select(env, parent_type, 358 'context': parent_context('attachment'), 359 'parent': {'name': pname}, 360 'attachments': Attachment.select(self.env, parent_type, 357 361 last_segment), 358 362 } … … 363 367 last_segment) 364 368 365 parent_data = parent_data(attachment.parent_type, attachment.parent_id) 369 parent_context, pname = parent_data(attachment.parent_type, 370 attachment.parent_id) 371 context = parent_context('attachment', attachment.filename) 372 366 373 if req.method == 'POST': 367 374 if action == 'new': … … 374 381 data = self._render_form(req, attachment) 375 382 else: 376 add_link(req, 'up', parent_data['href'], parent_data['name']) 377 data = self._render_view(req, attachment) 378 379 data['parent'] = parent_data 383 add_link(req, 'up', parent_context.self_href(), pname) 384 data = self._render_view(context, attachment) 385 386 data['context'] = context 387 data['parent'] = {'name': pname} 380 388 381 389 add_stylesheet(req, 'common/css/code.css') … … 410 418 yield ('created', type, id, filename, time, description, author) 411 419 412 def get_timeline_events(self, req, db, type, start, stop, display):420 def get_timeline_events(self, context, start, stop, display): 413 421 """Return an iterable of events suitable for ITimelineEventProvider. 414 422 415 423 `display` is a callback for formatting the attachment's parent 424 (context should be able to do that as well) 416 425 """ 417 426 for change, type, id, filename, time, descr, author in \ 418 self.get_history(start, stop, type):427 self.get_history(start, stop, context.resource): 419 428 title = html(html.em(os.path.basename(filename)), 420 429 ' attached to ', display(id)) 421 430 event = TimelineEvent('attachment', title, 422 req.href.attachment(type, id, filename))431 context.href.attachment(type, id, filename)) 423 432 event.set_changeinfo(time, author) 424 event.set_context( 'attachment', type+':'+id, descr)433 event.set_context(context(type, id)('attachment', id), descr) 425 434 yield event 426 435 … … 514 523 return {'mode': 'new', 'author': get_reporter_id(req)} 515 524 516 def _render_view(self, req, attachment): 525 def _render_view(self, context, attachment): 526 req = context.req 517 527 perm_map = {'ticket': 'TICKET_VIEW', 'wiki': 'WIKI_VIEW'} 518 528 req.perm.require(perm_map[attachment.parent_type]) … … 570 580 571 581 data['preview'] = mimeview.preview_data( 572 req, fd, os.fstat(fd.fileno()).st_size, mime_type,582 context, fd, os.fstat(fd.fileno()).st_size, mime_type, 573 583 attachment.filename, raw_href, annotations=['lineno']) 574 584 return data … … 584 594 else: 585 595 permute = False 586 # FIXME: the formatter should know which object the text being 587 # formatter belongs to 588 parent_type, parent_id = 'wiki', 'WikiStart' 589 if formatter.req: 590 path_info = formatter.req.path_info.split('/', 2) 591 if len(path_info) > 1: 592 parent_type = path_info[1] 593 if len(path_info) > 2: 594 parent_id = path_info[2] 596 parent_type, parent_id = formatter.context.resource, \ 597 formatter.context.id 595 598 filename = link 596 599 def attachment_link(parent_type, parent_id, filename): … … 605 608 return html.A(label, class_='attachment', href=href, 606 609 title='Attachment %s' % attachment.title) 607 except TracError :610 except TracError, e: 608 611 return None 609 612 link = attachment_link(parent_type, parent_id, filename) … … 611 614 link = attachment_link(filename, parent_type, parent_id) 612 615 if not link: 613 link = html.A(label, class_='missing attachment', rel='nofollow', 614 href=formatter.href()) 616 link = html.A(label, class_='missing attachment', rel='nofollow') 615 617 return link 616 618 -
trunk/trac/env.py
r4420 r4451 81 81 """Short description of the project.""") 82 82 83 project_url = Option('project', 'url', 'http://example.org/', 84 """URL of the main project web site.""") 83 project_url = Option('project', 'url', '', 84 """URL of the main project web site, usually the website in which 85 the `base_url` resides.""") 85 86 86 87 project_admin = Option('project', 'admin', '', -
trunk/trac/mimeview/api.py
r4411 r4451 243 243 """ 244 244 245 def render( req, mimetype, content, filename=None, url=None):246 """Render an XHTML preview of the raw `content` .245 def render(context, mimetype, content, filename=None, url=None): 246 """Render an XHTML preview of the raw `content` within a Context. 247 247 248 248 The `content` might be: … … 403 403 yield annotator.get_annotation_type() 404 404 405 def render(self, req, mimetype, content, filename=None, url=None,405 def render(self, context, mimetype, content, filename=None, url=None, 406 406 annotations=None): 407 407 """Render an XHTML preview of the given `content`. … … 456 456 rendered_content = expanded_content 457 457 458 result = renderer.render( req, full_mimetype, rendered_content,459 filename, url)458 result = renderer.render(context, full_mimetype, 459 rendered_content, filename, url) 460 460 if not result: 461 461 continue … … 472 472 473 473 if annotations: 474 m = req.args.get('marks')474 m = context.req and context.req.args.get('marks') or None 475 475 return self._annotate(result, annotations, m and Ranges(m)) 476 476 else: … … 594 594 return types 595 595 596 def preview_data(self, req, content, length, mimetype, filename,596 def preview_data(self, context, content, length, mimetype, filename, 597 597 url=None, annotations=None): 598 598 """Prepares a rendered preview of the given `content`. … … 605 605 'raw_href': url} 606 606 else: 607 return {'rendered': self.render( req, mimetype, content,607 return {'rendered': self.render(context, mimetype, content, 608 608 filename, url, annotations), 609 609 'raw_href': url} … … 721 721 return 1 722 722 723 def render(self, req, mimetype, content, filename=None, url=None):723 def render(self, context, mimetype, content, filename=None, url=None): 724 724 if is_binary(content): 725 725 self.env.log.debug("Binary data; no preview available") … … 741 741 return 0 742 742 743 def render(self, req, mimetype, content, filename=None, url=None):743 def render(self, context, mimetype, content, filename=None, url=None): 744 744 if url: 745 745 return tag.div(tag.img(src=url, alt=filename), … … 756 756 return 0 757 757 758 def render(self, req, mimetype, content, filename=None, url=None):759 from trac.wiki import wiki_to_html760 return wiki_to_html(content_to_unicode(self.env, content, mimetype),761 self.env, req) 758 def render(self, context, mimetype, content, filename=None, url=None): 759 return context.wiki_to_html(content_to_unicode(self.env, content, 760 mimetype)) 761 -
trunk/trac/mimeview/enscript.py
r4399 r4451 130 130 return self._types.get(mimetype, (None, 0))[1] 131 131 132 def render(self, req, mimetype, content, filename=None, rev=None):132 def render(self, context, mimetype, content, filename=None, rev=None): 133 133 cmdline = self.path 134 134 mimetype = mimetype.split(';', 1)[0] # strip off charset -
trunk/trac/mimeview/patch.py
r4282 r4451 43 43 return 0 44 44 45 def render(self, req, mimetype, content, filename=None, rev=None): 45 def render(self, context, mimetype, content, filename=None, rev=None): 46 req = context.req 46 47 from trac.web.chrome import Chrome 47 48 -
trunk/trac/mimeview/php.py
r4399 r4451 77 77 return 0 78 78 79 def render(self, req, mimetype, content, filename=None, rev=None):79 def render(self, context, mimetype, content, filename=None, rev=None): 80 80 # -n to ignore php.ini so we're using default colors 81 81 cmdline = '%s -sn' % self.path -
trunk/trac/mimeview/pygments_renderer.py
r4420 r4451 102 102 return 0 103 103 104 def render(self, req, mimetype, content, filename=None, rev=None): 104 def render(self, context, mimetype, content, filename=None, rev=None): 105 req = context.req 105 106 if self._types is None: 106 107 self._init_types() -
trunk/trac/mimeview/rst.py
r3832 r4451 33 33 from trac.web.href import Href 34 34 from trac.wiki.formatter import WikiProcessor 35 from trac.wiki import WikiSystem , wiki_to_link35 from trac.wiki import WikiSystem 36 36 37 37 class ReStructuredTextRenderer(Component): … … 46 46 return 0 47 47 48 def render(self, req, mimetype, content, filename=None, rev=None):48 def render(self, context, mimetype, content, filename=None, rev=None): 49 49 try: 50 50 from docutils import nodes … … 60 60 def trac_get_reference(rawtext, target, text): 61 61 fulltext = text and target+' '+text or target 62 link = wiki_to_link(fulltext, self.env, req)62 link = context.wiki_to_link(fulltext) 63 63 uri = None 64 64 missing = False … … 73 73 missing = 'missing' in link.attrib.get('class', '') 74 74 else: 75 uri = req.href.wiki(target)75 uri = context.href.wiki(target) 76 76 missing = not WikiSystem(self.env).has_page(target) 77 77 if uri: … … 143 143 # The code_block could is taken from the leo plugin rst2 144 144 def code_formatter(language, text): 145 processor = WikiProcessor( self.env, language)146 html = processor.process( req,text)145 processor = WikiProcessor(formatter, language) 146 html = processor.process(text) 147 147 raw = nodes.raw('', html, format='html') 148 148 return raw -
trunk/trac/mimeview/silvercity.py
r4420 r4451 109 109 return self._types.get(mimetype, (None, 0))[1] 110 110 111 def render(self, req, mimetype, content, filename=None, rev=None):111 def render(self, context, mimetype, content, filename=None, rev=None): 112 112 try: 113 113 mimetype = mimetype.split(';', 1)[0] -
trunk/trac/mimeview/tests/patch.py
r4115 r4451 26 26 from trac.web.chrome import Chrome 27 27 from trac.web.href import Href 28 from trac.wiki.api import Context 28 29 29 30 … … 32 33 def setUp(self): 33 34 env = EnvironmentStub(enable=[Chrome, PatchRenderer]) 35 req = Mock(base_path='',chrome={}, 36 abs_href=Href('/'), href=Href('/'), 37 perm=None, authname=None, tz=None) 38 self.context = Context(env, req) 34 39 self.patch = Mimeview(env).renderers[0] 35 self.req = Mock(base_path='',chrome={},36 abs_href=Href('/'), href=Href('/'),37 perm=None, authname=None, tz=None)38 40 patch_html = open(os.path.join(os.path.split(__file__)[0], 39 41 'patch.html')) … … 55 57 Simple patch rendering 56 58 """ 57 result = self.patch.render(self. req, None, """59 result = self.patch.render(self.context, None, """ 58 60 --- README.orig 2006-10-27 14:42:04.062500000 +0200 59 61 +++ README 2006-10-27 14:42:28.125000000 +0200 … … 75 77 Simple regression test for #4027 ("No newline at end of file") 76 78 """ 77 result = self.patch.render(self. req, None, """79 result = self.patch.render(self.context, None, """ 78 80 --- nonewline 2006-10-27 08:36:48.453125000 +0200 79 81 +++ newline 2006-10-27 08:36:57.187500000 +0200 … … 90 92 Another simple regression test for #4027 ("No newline at end of file") 91 93 """ 92 result = self.patch.render(self. req, None, """94 result = self.patch.render(self.context, None, """ 93 95 --- newline 2006-10-27 08:36:57.187500000 +0200 94 96 +++ nonewline 2006-10-27 08:36:48.453125000 +0200 -
trunk/trac/mimeview/tests/pygments_renderer.py
r4409 r4451 25 25 from trac.web.chrome import Chrome 26 26 from trac.web.href import Href 27 from trac.wiki.api import Context 27 28 28 29 … … 35 36 abs_href=Href('/'), href=Href('/'), 36 37 session={}, perm=None, authname=None, tz=None) 38 self.context = Context(self.env, self.req) 37 39 pygments_html = open(os.path.join(os.path.split(__file__)[0], 38 40 'pygments.html')) … … 54 56 Simple Python highlighting with Pygments (direct) 55 57 """ 56 result = self.pygments.render(self. req, 'text/x-python', """58 result = self.pygments.render(self.context, 'text/x-python', """ 57 59 def hello(): 58 60 return "Hello World!" … … 65 67 Simple Python highlighting with Pygments (through Mimeview.render) 66 68 """ 67 result = mimeview = Mimeview(self.env).render(self. req,69 result = mimeview = Mimeview(self.env).render(self.context, 68 70 'text/x-python', """ 69 71 def hello(): … … 77 79 Simple test for direct rendering of empty content. 78 80 """ 79 result = self.pygments.render(self. req, 'text/x-python', '')81 result = self.pygments.render(self.context, 'text/x-python', '') 80 82 self.assertTrue(result) 81 83 self._test('empty_content', result) -
trunk/trac/mimeview/txtl.py
r3544 r4451 32 32 return 0 33 33 34 def render(self, req, mimetype, content, filename=None, rev=None):34 def render(self, context, mimetype, content, filename=None, rev=None): 35 35 import textile 36 36 return textile.textile(content.encode('utf-8'), encoding='utf-8') -
trunk/trac/search/web_ui.py
r4331 r4451 28 28 from trac.web import IRequestHandler 29 29 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 30 from trac.wiki import IWikiSyntaxProvider, wiki_to_link30 from trac.wiki.api import IWikiSyntaxProvider, Context 31 31 32 32 … … 136 136 description = 'Browse repository path ' + kwd 137 137 else: 138 link = wiki_to_link(kwd, self.env, req)138 link = Context(self.env, req).wiki_to_link(kwd) 139 139 if isinstance(link, Element): 140 140 quickjump_href = link.attrib.get('href') -
trunk/trac/tests/wikisyntax.py
r4355 r4451 8 8 from trac.test import Mock 9 9 from trac.web.href import Href 10 from trac.wiki.api import Context 10 11 from trac.wiki.tests import formatter 11 12 … … 82 83 ------------------------------ 83 84 <p> 84 <a class="missing attachment" href=""rel="nofollow">attachment:foo.txt</a>85 <a class="missing attachment" href=""rel="nofollow">other file</a>85 <a class="missing attachment" rel="nofollow">attachment:foo.txt</a> 86 <a class="missing attachment" rel="nofollow">other file</a> 86 87 </p> 87 88 ------------------------------ … … 120 121 121 122 def suite(): 122 req = Mock(path_info='/wiki/WikiStart', href=Href('/'),123 abs_href=Href('http://www.example.com/'))124 123 suite = unittest.TestSuite() 125 124 suite.addTest(formatter.suite(SEARCH_TEST_CASES, file=__file__)) 126 125 suite.addTest(formatter.suite(ATTACHMENT_TEST_CASES, file=__file__, 126 context=Context(None, None, 127 'wiki', 'WikiStart'), 127 128 setup=attachment_setup, 128 teardown=attachment_teardown , req=req))129 teardown=attachment_teardown)) 129 130 return suite 130 131 -
trunk/trac/ticket/api.py
r4400 r4451 240 240 241 241 def _format_comment_link(self, formatter, ns, target, label): 242 type, id, cnum = 'ticket', '1', 0 243 href = None 242 context = None 244 243 if ':' in target: 245 244 elts = target.split(':') 246 245 if len(elts) == 3: 247 cnum, type, id = elts246 cnum, resource, id = elts 248 247 if cnum != 'description' and cnum and not cnum[0].isdigit(): 249 type, id, cnum = elts # support old comment: style250 href = formatter.href(type, id)248 resource, id, cnum = elts # support old comment: style 249 context = formatter.context(resource, id) 251 250 else: 252 # FIXME: the formatter should know which object the text being 253 # formatted belongs to 254 if formatter.req: 255 path_info = formatter.req.path_info.strip('/').split('/', 2) 256 if len(path_info) == 2: 257 type, id = path_info[:2] 258 href = formatter.href(type, id) 259 cnum = target 260 if href: 261 return html.A(label, href="%s#comment:%s" % (href, cnum), 262 title="Comment %s for %s:%s" % (cnum, type, id)) 251 context = formatter.context 252 cnum = target 253 254 if context: 255 return html.A(label, href="%s#comment:%s" % \ 256 (context.self_href(), cnum), 257 title="Comment %s for %s:%s" % \ 258 (cnum, context.resource, context.id)) 263 259 else: 264 260 return label -
trunk/trac/ticket/query.py
r4435 r4451 33 33 from trac.web.chrome import add_link, add_script, add_stylesheet, \ 34 34 INavigationContributor, Chrome 35 from trac.wiki.api import IWikiSyntaxProvider, parse_args 35 from trac.wiki.api import IWikiSyntaxProvider, parse_args, Context 36 36 from trac.wiki.macros import WikiMacroBase # TODO: should be moved in .api 37 37 … … 202 202 return results 203 203 204 def get_href(self, req, order=None, desc=None, format=None):205 # FIXME: only use .href from that 'req' for now204 def get_href(self, context, order=None, desc=None, format=None): 205 """Since 0.11: first argument is a Context instead of a Request.""" 206 206 if desc is None: 207 207 desc = self.desc 208 208 if order is None: 209 209 order = self.order 210 return req.href.query(order=order, desc=desc and 1 or None,211 group=self.group or None,212 groupdesc=self.groupdesc and 1 or None,213 verbose=self.verbose and 1 or None,214 format=format, **self.constraints)210 return context.href.query(order=order, desc=desc and 1 or None, 211 group=self.group or None, 212 groupdesc=self.groupdesc and 1 or None, 213 verbose=self.verbose and 1 or None, 214 format=format, **self.constraints) 215 215 216 216 def get_sql(self): … … 395 395 return "".join(sql), args 396 396 397 def template_data(self, req, db, tickets, orig_list=None, orig_time=None):397 def template_data(self, context, tickets, orig_list=None, orig_time=None): 398 398 constraints = {} 399 399 for k, v in self.constraints.items(): … … 419 419 headers = [{ 420 420 'name': col, 'label': labels.get(col, 'Ticket'), 421 'href': self.get_href( req, order=col, desc=(col == self.order and422 421 'href': self.get_href(context, order=col, 422 desc=(col == self.order and not self.desc)) 423 423 } for col in cols] 424 424 … … 464 464 465 465 return {'query': self, 466 'context': context, 466 467 'constraints': constraints, 467 468 'headers': headers, … … 533 534 req.args.has_key('verbose')) 534 535 536 context = Context(self.env, req) 535 537 if req.args.has_key('update'): 536 538 # Reset session vars … … 538 540 if req.session.has_key(var): 539 541 del req.session[var] 540 req.redirect(query.get_href( req))542 req.redirect(query.get_href(context)) 541 543 542 544 # Add registered converters … … 544 546 'trac.ticket.Query'): 545 547 add_link(req, 'alternate', 546 query.get_href( req, format=conversion[0]),548 query.get_href(context, format=conversion[0]), 547 549 conversion[1], conversion[3]) 548 550 … … 552 554 format, 'query') 553 555 554 return self.display_html( req, query)556 return self.display_html(context, query) 555 557 556 558 # Internal methods … … 594 596 return constraints 595 597 596 def display_html(self, req, query): 598 def display_html(self, context, query): 599 req = context.req 597 600 db = self.env.get_db_cnx() 598 601 tickets = query.execute(req, db) … … 633 636 tickets.insert(orig_list.index(rest_id), data) 634 637 635 data = query.template_data( req, db, tickets, orig_list, orig_time)638 data = query.template_data(context, tickets, orig_list, orig_time) 636 639 637 640 # For clients without JavaScript, we add a new constraint here if … … 650 653 **query.constraints) 651 654 652 req.session['query_href'] = query.get_href( req)655 req.session['query_href'] = query.get_href(context) 653 656 req.session['query_time'] = to_timestamp(orig_time) 654 657 req.session['query_tickets'] = ' '.join([str(t['id']) for t in tickets]) … … 696 699 **query.constraints) 697 700 698 data = {'results': results, 'query_href': query_href} 701 data = { 702 'context': Context(self.env, req), 703 'results': results, 704 'query_href': query_href 705 } 699 706 output = Chrome(self.env).render_template(req, 'query.rss', data, 700 707 'application/rss+xml') … … 715 722 else: 716 723 try: 717 query = Query.from_string( formatter.env, formatter.req, query)718 return html.A(label, href=query.get_href(formatter ), # Hack724 query = Query.from_string(self.env, formatter.req, query) 725 return html.A(label, href=query.get_href(formatter.context), 719 726 class_='query') 720 727 except QuerySyntaxError, e: … … 761 768 """ 762 769 763 def render_macro(self, req, name, content): 770 def render_macro(self, formatter, name, content): 771 req = formatter.req 764 772 query_string = '' 765 773 argv, kwargs = parse_args(content) … … 789 797 db = self.env.get_db_cnx() 790 798 tickets = query.execute(req, db) 791 data = query.template_data( req, db, tickets)799 data = query.template_data(formatter.context, tickets) 792 800 793 801 add_stylesheet(req, 'common/css/report.css') -
trunk/trac/ticket/report.py
r4225 r4451 28 28 from trac.web.api import IRequestHandler, RequestDone 29 29 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 30 from trac.wiki import IWikiSyntaxProvider, Formatter30 from trac.wiki import IWikiSyntaxProvider, Context, Formatter 31 31 32 32 class ReportModule(Component): … … 228 228 if id > 0: 229 229 title = '{%i} %s' % (id, title) 230 230 231 context = Context(self.env, req, 'report', id) 231 232 data = {'action': 'view', 'title': title, 233 'context': context, 232 234 'report': {'id': id, 'title': title, 233 235 'description': description, … … 290 292 cell_groups = [] 291 293 row = {'cell_groups': cell_groups} 294 resource = 'ticket' 292 295 for header_group in header_groups: 293 296 cell_group = [] … … 315 318 elif value in email_map: 316 319 cell['author'] = email_map[value] 320 elif col == 'resource': 321 resource = value 317 322 cell_group.append(cell) 318 323 cell_groups.append(cell_group) 324 row['context'] = context(resource, row.get('id')) 319 325 if row_groups: 320 326 row_group = row_groups[-1][1] -
trunk/trac/ticket/roadmap.py
r4371 r4451 33 33 from trac.web import IRequestHandler 34 34 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 35 from trac.wiki import IWikiSyntaxProvider35 from trac.wiki.api import IWikiSyntaxProvider, Context 36 36 from trac.config import ExtensionOption 37 37 … … 224 224 225 225 data = { 226 'context': Context(self.env, req), 226 227 'milestones': milestones, 227 228 'milestone_stats': stats, … … 369 370 def get_timeline_events(self, req, start, stop, filters): 370 371 if 'milestone' in filters: 371 db = self.env.get_db_cnx()372 cursor = db.cursor()372 context = Context(self.env, req) 373 cursor = context.db.cursor() 373 374 # TODO: creation and (later) modifications should also be reported 374 375 cursor.execute("SELECT completed,name,description FROM milestone " … … 381 382 req.href.milestone(name)) 382 383 event.set_changeinfo(completed, '') # FIXME: store the author 383 event.set_context( 'milestone', name, description)384 event.set_context(context('milestone', name), description) 384 385 yield event 385 386 … … 490 491 data = { 491 492 'milestone': milestone, 493 'context': Context(self.env, req, 'milestone', milestone.name, 494 db=db), 492 495 'milestones': Milestone.select(self.env, False, db) 493 496 } … … 497 500 data = { 498 501 'milestone': milestone, 502 'context': Context(self.env, req, 'milestone', milestone.name, 503 db=db), 499 504 'date_hint': get_date_format_hint(), 500 505 'datetime_hint': get_datetime_format_hint() … … 538 543 539 544 data = {'milestone': milestone, 545 'context': Context(self.env, req, 'milestone', milestone.name, 546 db=db), 540 547 'available_groups': available_groups, 541 548 'grouped_by': by, -
trunk/trac/ticket/tests/query.py
r4435 r4451 2 2 from trac.test import Mock, EnvironmentStub 3 3 from trac.ticket.query import Query, QueryModule 4 from trac.wiki.api import Context 4 5 from trac.wiki.formatter import LinkFormatter 5 6 … … 316 317 self.env = EnvironmentStub(default_data=True) 317 318 self.query_module = QueryModule(self.env) 318 self.formatter = LinkFormatter( self.env)319 self.formatter = LinkFormatter(Context(self.env, None)) 319 320 320 321 def _format_link(self, query, label): -
trunk/trac/ticket/web_ui.py
r4404 r4451 38 38 from trac.web.chrome import add_link, add_script, add_stylesheet, \ 39 39 INavigationContributor, Chrome 40 40 from trac.wiki.api import Context 41 41 42 42 class InvalidTicket(TracError): … … 132 132 ticket.values['reporter'] = get_reporter_id(req, 'reporter') 133 133 data['ticket'] = ticket 134 data['context'] = Context(self.env, req, 'ticket', ticket.id, db=db) 134 135 135 136 field_names = [field['name'] for field in ticket.fields … … 181 182 ticket = Ticket(self.env, id, db=db) 182 183 data['ticket'] = ticket 183 184 data['context'] = Context(self.env, req, 'ticket', ticket.id, db=db) 185 184 186 if action in ('history', 'diff'): 185 187 field = req.args.get('field') … … 469 471 'closed': ('closedticket', 'closed'), 470 472 'edit': ('editedticket', 'updated')} 473 context = Context(self.env, req) 471 474 472 475 def produce((id, ts, author, type, summary), status, fields, … … 503 506 event = TimelineEvent(kind, title, ticket_href, markup) 504 507 event.set_changeinfo(t, author) 505 event.set_context( 'ticket', id, message)508 event.set_context(context('ticket', id), message) 506 509 return event 507 510 … … 555 558 title=Ticket(self.env, id)['summary'])) 556 559 att = AttachmentModule(self.env) 557 for event in att.get_timeline_events( req, db, 'ticket',560 for event in att.get_timeline_events(context('ticket'), 558 561 start, stop, display): 559 562 yield event … … 599 602 data = { 600 603 'ticket': ticket, 604 'context': Context(self.env, req, 'ticket', ticket.id, db=db), 601 605 'changes': changes, 602 606 } -
trunk/trac/timeline/api.py
r4336 r4451 27 27 28 28 title: short summary for the event 29 href: link to the resource advertised by this event 29 href: link to the resource advertised by this event; 30 if not given, will be the context's self reference 30 31 markup: optional Markup that should be taken into account along side the 31 32 contextual information … … 33 34 date and authorship info for the event; 34 35 `date` is a datetime instance 35 type, id, message:36 context, wikitext: 36 37 context and contextual information; 37 ` message` will be interpreted as wiki text38 `wikitext` will be interpreted as wiki text 38 39 use_oneliner: 39 40 contextual information should be presented in brief … … 49 50 self.author = 'unknown' 50 51 self.date = self.authenticated = self.ipnr = None 51 self. type = self.id = self.message= None52 self.context = self.wikitext = None 52 53 self.use_oneliner = True 53 54 self.shorten_oneliner = True 54 55 55 56 def __repr__(self): 56 return '<TimelineEvent %s - %s>' % (self.date, self.href) 57 return '<TimelineEvent %s - %r - %s>' % \ 58 (self.date, self.context, self.href) 59 60 def _get_abs_href(self): 61 req = self.context.req 62 if self.href.startswith('/'): 63 # Convert from a relative `href` 64 return Href(req.abs_href.base[:-len(req.href.base)])() + self.href 65 else: 66 return self.href 67 abs_href = property(fget=_get_abs_href) 57 68 58 69 def set_changeinfo(self, date, author='anonymous', authenticated=None, … … 63 74 self.ipnr = ipnr 64 75 65 def set_context(self, type, id, message=None): 66 self.type = type 67 self.id = id 68 self.message = message 76 def set_context(self, context, wikitext=None): 77 self.context = context 78 self.wikitext = wikitext 69 79 70 80 def dateuid(self): 71 81 return to_timestamp(self.date) 72 82 73 def abs_href(self, req):74 if self.href.startswith('/'):75 # Convert from a relative `href`76 return Href(req.abs_href.base[:-len(req.href.base)])() + self.href77 else:78 return self.href79 83 80 84 … … 98 102 """Return a list of events in the time range given by the `start` and 99 103 `stop` parameters. 100 104 101 105 The `filters` parameters is a list of the enabled filters, each item 102 106 being the name of the tuples returned by `get_timeline_filters`. 103 107 104 The events are TimelineEvent instances.108 Since 0.11, the events are TimelineEvent instances. 105 109 106 110 Note: 107 111 The events returned by this function used to be tuples of the form 108 (kind, href, title, date, author, m essage). This is now deprecated.112 (kind, href, title, date, author, markup). This is now deprecated. 109 113 """ -
trunk/trac/timeline/web_ui.py
r4334 r4451 169 169 event = TimelineEvent(kind, title, href, markup) 170 170 event.set_changeinfo(date, author) 171 event.set_context(Context(self.env, None), '') 171 172 return event 172 173 -
trunk/trac/versioncontrol/web_ui/browser.py
r4438 r4451 31 31 from trac.web.chrome import add_link, add_script, add_stylesheet, \ 32 32 INavigationContributor 33 from trac.wiki import IWikiSyntaxProvider33 from trac.wiki.api import IWikiSyntaxProvider, Context 34 34 from trac.versioncontrol.api import NoSuchChangeset 35 35 from trac.versioncontrol.web_ui.util import * … … 124 124 add_link(req, 'up', path_links[-2]['href'], 'Parent directory') 125 125 126 context = Context(self.env, req, 'source', path) 126 127 data = { 128 'context': context, 127 129 'path': path, 'rev': node.rev, 'stickyrev': rev, 128 130 'created_path': node.created_path, … … 131 133 'path_links': path_links, 132 134 'dir': node.isdir and self._render_dir(req, repos, node, rev), 133 'file': node.isfile and self._render_file(req, repos, node, rev), 135 'file': node.isfile and self._render_file(context, repos, 136 node, rev), 134 137 'quickjump_entries': list(repos.get_quickjump_entries(rev)), 135 138 'wiki_format_messages': … … 187 190 'entries': entries, 'changes': changes} 188 191 189 def _render_file(self, req, repos, node, rev=None): 192 def _render_file(self, context, repos, node, rev=None): 193 req = context.req 190 194 req.perm.require('FILE_VIEW') 191 195 … … 237 241 add_stylesheet(req, 'common/css/code.css') 238 242 239 preview_data = mimeview.preview_data( req, node.get_content(),243 preview_data = mimeview.preview_data(context, node.get_content(), 240 244 node.get_content_length(), 241 245 mime_type, node.created_path, -
trunk/trac/versioncontrol/web_ui/changeset.py
r4367 r4451 45 45 from trac.web.chrome import add_link, add_script, add_stylesheet, \ 46 46 INavigationContributor 47 from trac.wiki import IWikiSyntaxProvider, Formatter47 from trac.wiki import IWikiSyntaxProvider, Context, Formatter 48 48 49 49 … … 265 265 data['chgset'] = chgset and True 266 266 data['restricted'] = restricted 267 context = Context(self.env, req) 267 268 268 269 if chgset: # Changeset Mode (possibly restricted on a path) 269 270 path, rev = data['new_path'], data['new_rev'] 271 context = context('changeset', rev) # context.detail = path ? 270 272 271 273 # -- getting the change summary from the Changeset.get_changes … … 346 348 347 349 data['title'] = title 350 data['context'] = context 348 351 349 352 if 'BROWSER_VIEW' not in req.perm: … … 613 616 614 617 repos = self.env.get_repository(req.authname) 618 context = Context(self.env, req) 615 619 616 620 for chgset in repos.get_changesets(start, stop): … … 637 641 req.href.changeset(chgset.rev), markup) 638 642 event.set_changeinfo(chgset.date, chgset.author, True) 639 event.set_context( 'changeset', chgset.rev, message)643 event.set_context(context('changeset', chgset.rev), message) 640 644 event.use_oneliner = not long_messages 641 645 yield event -
trunk/trac/versioncontrol/web_ui/log.py
r4428 r4451 31 31 from trac.web import IRequestHandler 32 32 from trac.web.chrome import add_link, add_stylesheet, INavigationContributor 33 from trac.wiki import IWikiSyntaxProvider, Formatter33 from trac.wiki import IWikiSyntaxProvider, Context, Formatter 34 34 35 35 LOG_LIMIT = 100 … … 202 202 extra_changes[rev] = cs 203 203 data = { 204 'context': Context(self.env, req, 'source', path), 204 205 'path': path, 'rev': rev, 'stop_rev': stop_rev, 205 206 'mode': mode, 'verbose': verbose, -
trunk/trac/web/chrome.py
r4421 r4451 41 41 from trac.web.api import IRequestHandler, HTTPNotFound 42 42 from trac.web.href import Href 43 from trac.wiki import IWikiSyntaxProvider , wiki_to_html, wiki_to_oneliner43 from trac.wiki import IWikiSyntaxProvider 44 44 45 45 def add_link(req, rel, href, title=None, mimetype=None, classname=None): … … 481 481 'fromtimestamp': partial(datetime.datetime.fromtimestamp, 482 482 tz=tzinfo), 483 484 # Wiki-formatting functions485 'wiki_to_html': partial(wiki_to_html, env=self.env, req=req),486 'wiki_to_oneliner': partial(wiki_to_oneliner, env=self.env, req=req),487 483 }) 488 484 -
trunk/trac/wiki/api.py
r4431 r4451 24 24 import urllib 25 25 import re 26 from StringIO import StringIO 27 28 from genshi.core import Markup 26 29 27 30 from trac.config import BoolOption … … 78 81 """ 79 82 80 def render_macro(req, name, content): 81 """Return the HTML output of the macro.""" 83 def render_macro(formatter, name, content): 84 """Return the HTML output of the macro. 85 86 Since 0.11: first argument is a Formatter instead of a Request. 87 """ 82 88 83 89 … … 101 107 The `label` is already HTML escaped, whereas the `target` is not. 102 108 """ 109 110 class Context(object): 111 """Base class for Wiki rendering contexts. 112 113 This encapsulates the "referential context" of a Wiki content, 114 and is therefore attached to a specific resource of type `resource`, 115 identified by its `id`. 116 117 A resource can also be parented in another resource, which means we are 118 talking about this resource in the context of another resource (and so on). 119 120 The context also encapsulates the "access context" of a Wiki content, 121 i.e. how the resource is accessed (`req`), so that links in the rendered 122 content will use the base URL. 123 If the request is not present in the context, the canonical base URLs 124 as configured in the environment will be used. 125 126 Finally, the context should also know about the rendering context, and 127 specifically about the expected output MIME type (TODO) 128 """ 129 130 def __init__(self, env, req, resource=None, id=None, parent=None, 131 abs_urls=False, db=None): 132 self.env = env 133 self.req = req 134 self.resource = resource 135 self.id = id 136 self.parent = parent 137 self.abs_urls = abs_urls 138 self._db = db 139 140 def __repr__(self): 141 return '<Context %r (%s,%s)%s>' % \ 142 (self.req, self.resource, self.id, 143 self.abs_urls and ' [abs]' or '') 144 145 def __call__(self, resource=None, id=None, abs_urls=None): 146 """Create a new Context, child of this Context. 147 148 The non specified parameters will inherit their corresponding 149 parent's context values. 150 """ 151 return Context(self.env, self.req, resource or self.resource, 152 id or self.id, self, 153 abs_urls=[self.abs_urls, abs_urls][abs_urls is None]) 154 155 def _get_db(self): 156 if not self._db: 157 self._db = self.env.get_db_cnx() 158 return self._db 159 db = property(fget=_get_db) 160 161 def _get_href(self): 162 """Return an Href instance, adapted to the context.""" 163 base = self.req or self.env 164 if self.abs_urls: 165 return base.abs_href 166 else: 167 return base.href 168 href = property(fget=_get_href) 169 170 def self_href(self, *args, **kwargs): 171 """Return a reference to the resource itself.""" 172 return self.href(self.resource, self.id, *args, **kwargs) 173 174 def local_url(self): 175 """Return the local URL, either the configured `[project] url` 176 or the one that can be infered from the request or the Environment. 177 """ 178 return (self.env.config.get('project', 'url') or 179 (self.req or self.env).abs_href.base) 180 181 # -- wiki rendering methods 182 183 def wiki_to_html(self, wikitext, escape_newlines=False): 184 from trac.wiki.formatter import Formatter 185 if not wikitext: 186 return Markup() 187 out = StringIO() 188 Formatter(self).format(wikitext, out, escape_newlines) 189 return Markup(out.getvalue()) 190 191 def wiki_to_oneliner(self, wikitext, shorten=False): 192 from trac.wiki.formatter import OneLinerFormatter 193 if not wikitext: 194 return Markup() 195 out = StringIO() 196 OneLinerFormatter(self).format(wikitext, out, shorten) 197 return Markup(out.getvalue()) 198 199 def wiki_to_outline(self, wikitext, max_depth=None, min_depth=None): 200 from trac.wiki.formatter import OutlineFormatter 201 if not wikitext: 202 return Markup() 203 out = StringIO() 204 OutlineFormatter(self).format(wikitext, out, max_depth, min_depth) 205 return Markup(out.getvalue()) 206 207 def wiki_to_link(self, wikitext): 208 from trac.wiki.formatter import LinkFormatter 209 if not wikitext: 210 return '' 211 return LinkFormatter(self).match(wikitext) 103 212 104 213 -
trunk/trac/wiki/formatter.py
r4245 r4451 31 31 from trac.util.text import shorten_line, to_unicode 32 32 33 __all__ = ['wiki_to_html', 'wiki_to_oneliner', 'wiki_to_outline', 34 'wiki_to_link', 'Formatter' ] 33 __all__ = ['Formatter'] 35 34 36 35 … … 44 43 _code_block_re = re.compile('^<div(?:\s+class="([^"]+)")?>(.*)</div>$') 45 44 46 def __init__(self, env, name): 47 # TODO: transmit `formatter` argument 48 self.env = env 45 def __init__(self, formatter, name): 46 """Since 0.11: first argument is a Formatter instead of an Environment. 47 """ 48 self.formatter = formatter 49 self.env = formatter.env 49 50 self.name = name 50 51 self.error = None … … 58 59 if not self.processor: 59 60 # Find a matching wiki macro 60 for macro_provider in WikiSystem(self.env).macro_providers:61 for macro_provider in formatter.wiki.macro_providers: 61 62 for macro_name in macro_provider.get_macros(): 62 63 if self.name == macro_name: … … 67 68 # Find a matching mimeview renderer 68 69 from trac.mimeview.api import Mimeview 69 mimetype = Mimeview( self.env).get_mimetype(self.name)70 mimetype = Mimeview(formatter.env).get_mimetype(self.name) 70 71 if mimetype: 71 72 self.name = mimetype … … 77 78 # builtin processors 78 79 79 def _comment_processor(self, req,text):80 def _comment_processor(self, text): 80 81 return '' 81 82 82 def _default_processor(self, req,text):83 def _default_processor(self, text): 83 84 return html.PRE(text, class_="wiki") 84 85 85 def _html_processor(self, req,text):86 def _html_processor(self, text): 86 87 from genshi import Stream 87 88 from genshi.input import HTMLParser, ParseError … … 97 98 # generic processors 98 99 99 def _macro_processor(self, req, text): 100 # TODO: macro should take a `formatter` argument 100 def _macro_processor(self, text): 101 101 self.env.log.debug('Executing Wiki macro %s by provider %s' 102 102 % (self.name, self.macro_provider)) 103 return self.macro_provider.render_macro(req, self.name, text) 104 105 def _mimeview_processor(self, req, text): 106 # TODO: transmit context from `formatter` 107 return Mimeview(self.env).render(req, self.name, text) 108 109 def process(self, req, text, in_paragraph=False): 103 return self.macro_provider.render_macro(self.formatter, self.name, text) 104 105 def _mimeview_processor(self, text): 106 return Mimeview(self.env).render(self.formatter.context, 107 self.name, text) 108 # TODO: use convert('text/html') instead of render 109 110 def process(self, text, in_paragraph=False): 110 111 if self.error: 111 112 text = system_message(Markup('Error: Failed to load processor ' … … 113 114 self.error) 114 115 else: 115 text = self.processor( req,text)116 text = self.processor(text) 116 117 if not text: 117 118 return '' … … 147 148 148 149 class Formatter(object): 150 """Base Wiki formatter. 151 152 Parses and formats wiki text, in a given Context. 153 """ 154 149 155 flavor = 'default' 150 156 … … 231 237 _anchor_re = re.compile('[^\w:.-]+', re.UNICODE) 232 238 233 def __init__(self, env, req=None, absurls=False, db=None): 234 self.env = env 235 self.req = req 236 self._db = db 237 self._absurls = absurls 239 def __init__(self, context): 240 """Since 0.11: only takes a single Context argument.""" 241 self.context = context 242 # shortcuts 243 self.env = context.env 244 self.req = context.req 245 self.db = context.db 246 self.href = context.abs_urls and context.abs_href or context.href 247 self.wiki = WikiSystem(context.env) 238 248 self._anchors = {} 239 249 self._open_tags = [] 240 self.href = absurls and (req or env).abs_href or (req or env).href241 self._local = env.config.get('project', 'url') \242 or (req or env).abs_href.base243 self.wiki = WikiSystem(self.env)244 245 def _get_db(self):246 if not self._db:247 self._db = self.env.get_db_cnx()248 return self._db249 db = property(fget=_get_db)250 250 251 251 def split_link(self, target): … … 362 362 label = self._unquote(label) 363 363 if rel: 364 return self._make_relative_link(rel, label or rel) 364 label = label or rel 365 if rel[0] == '#': 366 rel = self.context.self_href() + rel 367 return self._make_relative_link(rel, label) 365 368 else: 366 369 return self._make_link(ns, target, match, label) … … 368 371 def _make_link(self, ns, target, match, label): 369 372 # first check for an alias defined in trac.ini 370 ns = self.env.config .get('intertrac', ns) or ns373 ns = self.env.config['intertrac'].get(ns, ns) 371 374 if ns in self.wiki.link_resolvers: 372 375 return self.wiki.link_resolvers[ns](self, ns, target, … … 380 383 381 384 def _make_intertrac_link(self, ns, target, label): 382 intertrac _config= self.env.config['intertrac']383 url = intertrac _config.get(ns+'.url')385 intertrac = self.env.config['intertrac'] 386 url = intertrac.get(ns+'.url') 384 387 if url: 385 name = intertrac _config.get(ns+'.title', 'Trac project %s' % ns)386 compat = intertrac _config.getbool(ns+'.compat', 'true')388 name = intertrac.get(ns+'.title', 'Trac project %s' % ns) 389 compat = intertrac.getbool(ns+'.compat', 'true') 387 390 # TODO: set `compat` default to False once 0.10 gets widely used 388 391 # and remove compatibility code altogether once 0.[89] disappear... … … 404 407 if it_group: 405 408 alias = it_group.strip() 406 intertrac = self.env.config .get('intertrac', alias) or alias409 intertrac = self.env.config['intertrac'] 407 410 target = '%s:%s' % (ns, target[len(it_group):]) 408 return self._make_intertrac_link(intertrac , target, label) or \409 label411 return self._make_intertrac_link(intertrac.get(alias, alias), 412 target, label) or label 410 413 return None 411 414 … … 420 423 421 424 def _make_ext_link(self, url, text, title=''): 422 if not url.startswith(self. _local):425 if not url.startswith(self.context.local_url()): 423 426 return html.A(html.SPAN(text, class_="icon"), 424 427 class_="ext-link", href=url, title=title or None) … … 440 443 args = fullmatch.group('macroargs') 441 444 try: 442 macro = WikiProcessor(self .env, name)443 return macro.process( self.req, args,True)445 macro = WikiProcessor(self, name) 446 return macro.process(args, in_paragraph=True) 444 447 except Exception, e: 445 448 self.env.log.error('Macro %s(%s) failed' % (name, args), … … 456 459 anchor = fullmatch.group('hanchor') or '' 457 460 heading_text = match[depth+1:-depth-1-len(anchor)] 458 heading = wiki_to_oneliner(heading_text, self.env, self.db, False, 459 self._absurls, self.req) 461 heading = self.context.wiki_to_oneliner(heading_text, False) 460 462 if anchor: 461 463 anchor = anchor[1:] … … 473 475 self._anchors[anchor] = True 474 476 if shorten: 475 heading = wiki_to_oneliner(heading_text, self.env, self.db, True, 476 self._absurls, self.req) 477 heading = self.context.wiki_to_oneliner(heading_text, True) 477 478 return (depth, heading, anchor) 478 479 … … 575 576 tmp = self.in_def_list and '</dd>' or '<dl>' 576 577 definition = match[:match.find('::')] 577 tmp += '<dt>%s</dt><dd>' % wiki_to_oneliner(definition, self.env, 578 self.db, req=self.req) 578 tmp += '<dt>%s</dt><dd>' % self.context.wiki_to_oneliner(definition) 579 579 self.in_def_list = True 580 580 return tmp … … 728 728 self.code_text += line + os.linesep 729 729 if not self.code_processor: 730 self.code_processor = WikiProcessor(self .env, 'default')730 self.code_processor = WikiProcessor(self, 'default') 731 731 elif line.strip() == Formatter.ENDBLOCK: 732 732 self.in_code_block -= 1 … … 734 734 self.close_table() 735 735 self.close_paragraph() 736 self.out.write(to_unicode(self.code_processor.process( 737 self.req, self.code_text))) 736 processed = self.code_processor.process(self.code_text) 737 self.out.write(to_unicode(processed)) 738 738 739 else: 739 740 self.code_text += line + os.linesep … … 742 743 if match: 743 744 name = match.group(1) 744 self.code_processor = WikiProcessor(self .env, name)745 self.code_processor = WikiProcessor(self, name) 745 746 else: 746 747 self.code_text += line + os.linesep 747 self.code_processor = WikiProcessor(self .env, 'default')748 self.code_processor = WikiProcessor(self, 'default') 748 749 else: 749 750 self.code_text += line + os.linesep … … 776 777 return to_unicode(replacement) 777 778 778 def reset(self, out=None): 779 def reset(self, source, out=None): 780 self.source = source 779 781 class NullOut(object): 780 782 def write(self, data): pass … … 793 795 794 796 def format(self, text, out=None, escape_newlines=False): 795 self.reset( out)797 self.reset(text, out) 796 798 for line in text.splitlines(): 797 799 # Handle code block … … 862 864 flavor = 'oneliner' 863 865 864 def __init__(self, env, absurls=False, db=None, req=None):865 Formatter.__init__(self, env, req, absurls, db)866 def __init__(self, context): 867 Formatter.__init__(self, context) 866 868 867 869 # Override a few formatters to disable some wiki syntax in "oneliner"-mode … … 890 892 if not text: 891 893 return 892 self.out = out 893 self._open_tags = [] 894 self.reset(text, out) 894 895 895 896 # Simplify code blocks … … 935 936 flavor = 'outline' 936 937 937 def __init__(self, env, absurls=False, db=None, req=None):938 Formatter.__init__(self, env, req, absurls, db)938 def __init__(self, context): 939 Formatter.__init__(self, context) 939 940 940 941 # Avoid the possible side-effects of rendering WikiProcessors … … 982 983 flavor = 'link' 983 984 984 def __init__(self, env, absurls=False, db=None, req=None):985 OutlineFormatter.__init__(self, env, absurls, db, req)985 def __init__(self, context): 986 OutlineFormatter.__init__(self, context) 986 987 987 988 def _heading_formatter(self, match, fullmatch): … … 990 991 def match(self, wikitext): 991 992 """Return the Wiki match found at the beginning of the `wikitext`""" 992 self.reset( )993 self.reset(wikitext) 993 994 match = re.match(self.wiki.rules, wikitext) 994 995 if match: 995 996 return self.handle_match(match) 996 997 997 998 # -- wiki_to_* helper functions999 1000 def wiki_to_html(wikitext, env, req, db=None,1001 absurls=False, escape_newlines=False):1002 if not wikitext:1003 return Markup()1004 out = StringIO()1005 Formatter(env, req, absurls, db).format(wikitext, out, escape_newlines)1006 return Markup(out.getvalue())1007 1008 def wiki_to_oneliner(wikitext, env, db=None, shorten=False, absurls=False,1009 req=None):1010 if not wikitext:1011 return Markup()1012 out = StringIO()1013 OneLinerFormatter(env, absurls, db, req=req).format(wikitext, out, shorten)1014 return Markup(out.getvalue())1015 1016 def wiki_to_outline(wikitext, env, db=None,1017 absurls=False, max_depth=None, min_depth=None):1018 if not wikitext:1019 return Markup()1020 out = StringIO()1021 OutlineFormatter(env, absurls, db).format(wikitext, out, max_depth,1022 min_depth)1023 return Markup(out.getvalue())1024 1025 def wiki_to_link(wikitext, env, req):1026 if not wikitext:1027 return ''1028 return LinkFormatter(env, False, None, req).match(wikitext) -
trunk/trac/wiki/intertrac.py
r3889 r4451 21 21 from trac.util.html import Element, html 22 22 from trac.web import IRequestHandler 23 from trac.wiki.api import IWikiMacroProvider 24 from trac.wiki.formatter import wiki_to_link 23 from trac.wiki.api import IWikiMacroProvider, Context 25 24 26 25 … … 43 42 if not link: 44 43 raise TracError('No TracLinks given') 45 link_elt = wiki_to_link(link, self.env, req)44 link_elt = Context(self.env, req).wiki_to_link(link) 46 45 if isinstance(link_elt, Element): 47 46 href = link_elt.attrib.get('href') -
trunk/trac/wiki/macros.py
r4381 r4451 26 26 from StringIO import StringIO 27 27 28 from genshi.builder import tag 29 28 30 from trac.config import default_dir 29 31 from trac.core import * … … 53 55 return inspect.getdoc(self.__class__) 54 56 55 def render_macro(self, req, name, content):57 def render_macro(self, formatter, name, content): 56 58 raise NotImplementedError 57 59 … … 72 74 SPLIT_RE = re.compile(r"( |/|[0-9])") 73 75 74 def render_macro(self, req, name, content):76 def render_macro(self, formatter, name, content): 75 77 args, kw = parse_args(content) 76 78 prefix = args and args[0] or None … … 78 80 minsize = max(int(kw.get('min', 2)), 2) 79 81 80 wiki = WikiSystem(self.env)82 wiki = formatter.wiki 81 83 pages = sorted(wiki.get_pages(prefix)) 82 84 83 85 if format != 'group': 84 86 return html.UL([html.LI(html.A(wiki.format_page_name(page), 85 href= req.href.wiki(page)))87 href=formatter.href.wiki(page))) 86 88 for page in pages]) 87 89 … … 111 113 html(html.STRONG(elt[0]), render_groups(elt[1])) or 112 114 html.A(wiki.format_page_name(elt), 113 href= req.href.wiki(elt)))115 href=formatter.href.wiki(elt))) 114 116 for elt in groups]) 115 117 return render_groups(split_in_groups(pages)) … … 129 131 """ 130 132 131 def render_macro(self, req, name, content):133 def render_macro(self, formatter, name, content): 132 134 prefix = limit = None 133 135 if content: … … 138 140 limit = int(argv[1]) 139 141 140 db = self.env.get_db_cnx() 141 cursor = db.cursor() 142 cursor = formatter.db.cursor() 142 143 143 144 sql = 'SELECT name, ' \ … … 165 166 entries_per_date[-1][1].append((name, int(version))) 166 167 167 wiki = WikiSystem(self.env)168 168 return html.DIV( 169 169 [html.H3(date) + 170 170 html.UL([html.LI( 171 html.A(wiki.format_page_name(name), href=req.href.wiki(name)), 171 html.A(formatter.wiki.format_page_name(name), 172 href=formatter.href.wiki(name)), 172 173 ' ', 173 174 version > 1 and 174 html.SMALL('(', html.A('diff', 175 href=req.href.wiki(name, action='diff', 176 version=version)), ')') \ 175 html.SMALL('(', 176 html.A('diff', 177 href=formatter.href.wiki(name, action='diff', 178 version=version)), 179 ')') \ 177 180 or None) 178 181 for name, version in entries]) … … 201 204 """ 202 205 203 def render_macro(self, req, name, content): 204 from trac.wiki.formatter import wiki_to_outline 205 from genshi.builder import tag 206 def render_macro(self, formatter, name, content): 206 207 min_depth, max_depth = 1, 6 207 208 title = None … … 211 212 if len(argv) > 0: 212 213 depth = argv[0] 213 if depth.find('-') >= 0:214 if '-' in depth: 214 215 min_depth, max_depth = [int(d) for d in depth.split('-', 1)] 215 216 else: 216 min_depth , max_depth = int(depth),int(depth)217 min_depth = max_depth = int(depth) 217 218 if len(argv) > 1: 218 219 title = argv[1].strip() … … 220 221 inline = argv[2].strip().lower() == 'inline' 221 222 222 db = self.env.get_db_cnx() 223 cursor = db.cursor() 224 pagename = req.args.get('page') or 'WikiStart' 225 page = WikiPage(self.env, pagename) 226 227 outline = wiki_to_outline(page.text, self.env, db=db, 228 max_depth=max_depth, min_depth=min_depth) 223 outline = formatter.context.wiki_to_outline(formatter.source, 224 max_depth=max_depth, 225 min_depth=min_depth) 229 226 if title: 230 227 outline = tag.h4(title) + outline … … 286 283 """ 287 284 288 def render_macro(self, req, name, content):285 def render_macro(self, formatter, name, content): 289 286 # args will be null if the macro is called without parenthesis. 290 287 if not content: … … 348 345 if '@' in file: 349 346 file, rev = file.split('@') 350 url = req.href.browser(file, rev=rev)351 raw_url = req.href.browser(file, rev=rev, format='raw')347 url = formatter.href.browser(file, rev=rev) 348 raw_url = formatter.href.browser(file, rev=rev, format='raw') 352 349 desc = filespec 353 350 else: # #ticket:attachment or WikiPage:attachment … … 358 355 id = id[1:] 359 356 elif id == 'htdocs': 360 raw_url = url = req.href.chrome('site', file)357 raw_url = url = formatter.href.chrome('site', file) 361 358 desc = os.path.basename(file) 362 359 elif id in ('http', 'https', 'ftp'): # external URLs … … 365 362 module = 'wiki' 366 363 elif len(parts) == 1: # attachment 367 # determine current object368 # FIXME: should be retrieved from the formatter...369 # ...and the formatter should be provided to the macro370 364 file = filespec 371 module, id = 'wiki', 'WikiStart' 372 path_info = req.path_info.split('/',2) 373 if len(path_info) > 1: 374 module = path_info[1] 375 if len(path_info) > 2: 376 id = path_info[2] 377 if module not in ['wiki', 'ticket']: 365 module, id = formatter.context.resource, formatter.context.id 366 if module not in ['wiki', 'ticket']: # FIXME: shouldn't be needed 378 367 raise Exception('Cannot reference local attachment from here') 379 368 else: … … 382 371 from trac.attachment import Attachment 383 372 attachment = Attachment(self.env, module, id, file) 384 url = attachment.href( req)385 raw_url = attachment.href( req, format='raw')373 url = attachment.href(formatter.req) 374 raw_url = attachment.href(formatter.req, format='raw') 386 375 desc = attachment.description 387 376 for key in ['title', 'alt']: … … 408 397 """ 409 398 410 def render_macro(self, req, name, content):411 from trac.wiki.formatter import wiki_to_html,system_message412 wiki = WikiSystem(self.env) 413 399 def render_macro(self, formatter, name, content): 400 from trac.wiki.formatter import system_message 401 402 wikimacros = formatter.context('wiki', 'WikiMacros') 414 403 def get_macro_descr(): 415 for macro_provider in wiki.macro_providers:404 for macro_provider in formatter.wiki.macro_providers: 416 405 for macro_name in macro_provider.get_macros(): 417 406 if content and macro_name != content: … … 419 408 try: 420 409 descr = macro_provider.get_macro_description(macro_name) 421 descr = wiki _to_html(descr or '', self.env, req)410 descr = wikimacros.wiki_to_html(descr or '') 422 411 except Exception, e: 423 412 descr = Markup(system_message( … … 441 430 """ 442 431 443 def render_macro(self, req, name, filter):432 def render_macro(self, formatter, name, filter): 444 433 from trac.config import Option 445 from trac.wiki.formatter import wiki_to_oneliner446 434 filter = filter or '' 447 435 … … 449 437 if section.startswith(filter)]) 450 438 439 tracini = formatter.context('wiki', 'TracIni') 451 440 return html.DIV(class_='tracini')( 452 441 [(html.H2('[%s]' % section, id='%s-section' % section), 453 442 html.TABLE(class_='wiki')( 454 443 html.TBODY([html.TR(html.TD(html.TT(option.name)), 455 html.TD(wiki_to_oneliner(option.__doc__, 456 self.env, 457 req=req))) 444 html.TD(tracini.wiki_to_oneliner(option.\ 445 __doc__))) 458 446 for option in sorted(Option.registry.values(), 459 447 key=lambda o: o.name) … … 462 450 463 451 464 class UserMacroProvider(Component): 465 """Adds macros that are provided as Python source files in the 466 `wiki-macros` directory of the environment, or the global macros 467 directory. 468 """ 469 implements(IWikiMacroProvider) 470 471 def __init__(self): 472 self.env_macros = os.path.join(self.env.path, 'wiki-macros') 473 self.site_macros = default_dir('macros') 474 475 # IWikiMacroProvider methods 476 477 def get_macros(self): 478 found = [] 479 for path in (self.env_macros, self.site_macros): 480 if not os.path.exists(path): 481 continue 482 for filename in [filename for filename in os.listdir(path) 483 if filename.lower().endswith('.py') 484 and not filename.startswith('__')]: 485 try: 486 module = self._load_macro(filename[:-3]) 487 name = module.__name__ 488 if name in found: 489 continue 490 found.append(name) 491 yield name 492 except Exception, e: 493 self.log.error('Failed to load wiki macro %s (%s)', 494 filename, e, exc_info=True) 495 496 def get_macro_description(self, name): 497 return inspect.getdoc(self._load_macro(name)) 498 499 def render_macro(self, req, name, content): 500 module = self._load_macro(name) 501 try: 502 return module.execute(req and req.hdf, content, self.env) 503 except Exception, e: 504 self.log.error('Wiki macro %s failed (%s)', name, e, exc_info=True) 505 raise 506 507 def _load_macro(self, name): 508 for path in (self.env_macros, self.site_macros): 509 macro_file = os.path.join(path, name + '.py') 510 if os.path.isfile(macro_file): 511 return imp.load_source(name, macro_file) 512 raise TracError, 'Macro %s not found' % name 452 453 class TracGuideTocMacro(WikiMacroBase): 454 """ 455 This macro shows a quick and dirty way to make a table-of-contents 456 for a set of wiki pages. 457 """ 458 459 TOC = [('TracGuide', 'Index'), 460 ('TracInstall', 'Installation'), 461 ('TracInterfaceCustomization', 'Customization'), 462 ('TracPlugins', 'Plugins'), 463 ('TracUpgrade', 'Upgrading'), 464 ('TracIni', 'Configuration'), 465 ('TracAdmin', 'Administration'), 466 ('TracBackup', 'Backup'), 467 ('TracLogging', 'Logging'), 468 ('TracPermissions' , 'Permissions'), 469 ('TracWiki', 'The Wiki'), 470 ('WikiFormatting', 'Wiki Formatting'), 471 ('TracTimeline', 'Timeline'), 472 ('TracBrowser', 'Repository Browser'), 473 ('TracRevisionLog', 'Revision Log'), 474 ('TracChangeset', 'Changesets'), 475 ('TracTickets', 'Tickets'), 476 ('TracRoadmap', 'Roadmap'), 477 ('TracQuery', 'Ticket Queries'), 478 ('TracReports', 'Reports'), 479 ('TracRss', 'RSS Support'), 480 ('TracNotification', 'Notification'), 481 ] 482 483 def render_macro(self, formatter, name, args): 484 curpage = formatter.context.id 485 486 # Provision for multilingual TOC (e.g. TranslateRu/TracGuide ...) 487 lang = '' 488 idx = curpage.find('/') 489 if idx > 0: 490 lang = curpage[:idx+1] 491 492 return tag.div(tag.h4('Table of Contents'), 493 tag.ul([tag.li(tag.a(title, 494 href=formatter.href.wiki(lang+ref)), 495 class_=(ref == curpage and "active")) 496 for ref, title in self.TOC]), 497 class_="wiki-toc") -
trunk/trac/wiki/tests/formatter.py
r4355 r4451 5 5 6 6 from trac.core import * 7 from trac.wiki.api import IWikiSyntaxProvider 7 from trac.wiki.api import IWikiSyntaxProvider, Context 8 8 from trac.wiki.formatter import Formatter, OneLinerFormatter 9 9 from trac.wiki.macros import WikiMacroBase … … 70 70 71 71 def __init__(self, input, correct, file, line, setup=None, teardown=None, 72 req=None):72 context=None): 73 73 unittest.TestCase.__init__(self, 'test') 74 74 self.title, self.input = input.split('\n', 1) … … 81 81 self._teardown = teardown 82 82 83 self.env = EnvironmentStub() 83 self.context = context and context() or Context(None, None) 84 85 self.env = self.context.env = EnvironmentStub() 86 87 from trac.web.href import Href 88 self.req = self.context.req = \ 89 Mock(href=Href('/'), 90 abs_href=Href('http://www.example.com/'), 91 authname='anonymous') 92 84 93 # -- macros support 85 94 self.env.path = '' … … 90 99 self.env.config.set('intertrac', 't', 'trac') 91 100 92 from trac.web.href import Href93 if req:94 self.req = req95 else:96 self.req = Mock(href = Href('/'),97 abs_href = Href('http://www.example.com/'),98 authname='anonymous')99 101 # TODO: remove the following lines in order to discover 100 102 # all the places were we should use the req.href 101 # instead of env.href (will be solved by the Wikifier patch)103 # instead of env.href 102 104 self.env.href = self.req.href 103 105 self.env.abs_href = self.req.abs_href … … 137 139 138 140 def formatter(self): 139 return Formatter(self. env, self.req)141 return Formatter(self.context) 140 142 141 143 def shortDescription(self): … … 145 147 class OneLinerTestCase(WikiTestCase): 146 148 def formatter(self): 147 return OneLinerFormatter(self. env, req=self.req)149 return OneLinerFormatter(self.context) 148 150 149 151 150 def suite(data=None, setup=None, file=__file__, teardown=None, req=None):152 def suite(data=None, setup=None, file=__file__, teardown=None, context=None): 151 153 suite = unittest.TestSuite() 152 154 if not data: … … 166 168 continue 167 169 input, page, oneliner = blocks 168 tc = WikiTestCase(input, page, file, line, setup, teardown, req)170 tc = WikiTestCase(input, page, file, line, setup, teardown, context) 169 171 suite.addTest(tc) 170 172 if oneliner: 171 173 tc = OneLinerTestCase(input, oneliner[:-1], file, line, 172 setup, teardown, req)174 setup, teardown, context) 173 175 suite.addTest(tc) 174 176 return suite -
trunk/trac/wiki/web_ui.py
r4406 r4451 36 36 INavigationContributor 37 37 from trac.web import HTTPNotFound, IRequestHandler 38 from trac.wiki.api import IWikiPageManipulator, WikiSystem 38 from trac.wiki.api import IWikiPageManipulator, WikiSystem, Context 39 39 from trac.wiki.model import WikiPage 40 40 … … 140 140 return self._render_view(req, db, page) 141 141 142 def page_data(self, page, action=''):142 def page_data(self, req, page, action=''): 143 143 title = page_name = WikiSystem(self.env).format_page_name(page.name) 144 144 if action: 145 145 title += ' (%s)' % action 146 146 return {'page': page, 147 'context': Context(self.env, req, 'wiki', page.name), 147 148 'action': action, 148 149 'page_name': page_name, … … 215 216 old_version = int(req.args.get('old_version') or 0) or version 216 217 217 data = self.page_data( page, 'delete')218 data = self.page_data(req, page, 'delete') 218 219 if version is not None: 219 220 num_versions = 0 … … 302 303 add_script(req, 'common/js/diff.js') 303 304 304 data = self.page_data( page, 'diff')305 data = self.page_data(req, page, 'diff') 305 306 306 307 def version_info(v): … … 348 349 editrows = req.session.get('wiki_editrows', '20') 349 350 350 data = self.page_data( page, action)351 data = self.page_data(req, page, action) 351 352 data.update({ 352 353 'author': author, … … 368 369 raise TracError, "Page %s does not exist" % page.name 369 370 370 data = self.page_data( page, 'history')371 data = self.page_data(req, page, 'history') 371 372 372 373 history = [] … … 393 394 conversion[3]) 394 395 395 data = self.page_data( page)396 data = self.page_data(req, page) 396 397 if page.name == 'WikiStart': 397 398 data['title'] = '' … … 461 462 start, stop = to_timestamp(start), to_timestamp(stop) 462 463 wiki = WikiSystem(self.env) 463 db = self.env.get_db_cnx()464 cursor = db.cursor()464 context = Context(self.env, req) 465 cursor = context.db.cursor() 465 466 cursor.execute("SELECT time,name,comment,author,ipnr,version " 466 467 "FROM wiki WHERE time>=%s AND time<=%s", … … 478 479 markup) 479 480 event.set_changeinfo(t, author, ipnr=ipnr) 480 event.set_context( 'wiki', name, comment)481 event.set_context(context('wiki', name), comment) 481 482 yield event 482 483 483 484 # Attachments 484 485 att = AttachmentModule(self.env) 485 for event in att.get_timeline_events( req, db, 'wiki', start, stop,486 for event in att.get_timeline_events(context('wiki'), start, stop, 486 487 lambda id: html.em(id)): 487 488 yield event
Note:
See TracChangeset
for help on using the changeset viewer.