Index: roundup/cgi/actions.py =================================================================== --- roundup/cgi/actions.py (revision 4176) +++ roundup/cgi/actions.py (working copy) @@ -1,4 +1,4 @@ -import re, cgi, StringIO, urllib, time, random, csv, codecs +import re, cgi, StringIO, urllib, time, random, csv, codecs, random, sys from roundup import hyperdb, token, date, password from roundup.actions import Action as BaseAction @@ -144,6 +144,7 @@ Split any String query values on whitespace and comma. + Store the query URL and result in session """ self.fakeFilterVars() queryname = self.getQueryName() @@ -151,13 +152,19 @@ # editing existing query name? old_queryname = self.getFromForm('old-queryname') + # parse the environment and figure what the query _is_ + req = templating.HTMLRequest(self.client) + url = self.getCurrentURL(req) + + search_id = "%x" % random.randint(0, sys.maxint) + searches = self.client.session_api.get('searches', {}) + url = "%s%s?%s&@search_id=%s" % (self.base, self.classname, url, search_id) + searches[search_id] = dict(url = url, result = ()) + self.client.session_api.set(searches = searches) + self.form.value.append(cgi.MiniFieldStorage('@search_id', search_id)) + # handle saving the query params if queryname: - # parse the environment and figure what the query _is_ - req = templating.HTMLRequest(self.client) - - url = self.getCurrentURL(req) - key = self.db.query.getkey() if key: # edit the old way, only one query per name @@ -1025,11 +1032,11 @@ def permission(self, args): """Raise Unauthorised if the current user is not allowed to execute this action. Users may override this method.""" - + pass def handle(self, args): - + raise NotImplementedError # vim: set filetype=python sts=4 sw=4 et si : Index: share/roundup/templates/classic/extensions/search_result.py =================================================================== --- share/roundup/templates/classic/extensions/search_result.py (revision 0) +++ share/roundup/templates/classic/extensions/search_result.py (revision 0) @@ -0,0 +1,54 @@ +def _get_stored_search(request, search_id = None) : + """Lookup stored search results""" + + searches = request.client.session_api.get("searches") + search_id = search_id or request.form.getfirst('@search_id') + if searches and search_id : + return searches.get(search_id) + +def _calc_match_url(request, nodeid) : + """For next/previous match, calculate url""" + + search_id = request.form.getfirst('@search_id') + return "%s%s%s?@search_id=%s" % (request.base, request.classname, nodeid, search_id) + +def update_search_result(request, search_id, batch) : + """Called from index page, updates stored search result""" + + search = _get_stored_search(request, search_id) + if not search : + return + + search["result"] = list(batch._sequence) + + # trigger session update + searches = request.client.session_api.get("searches") + request.client.session_api.set(searches = searches) + +def search_url(request) : + search = _get_stored_search(request) + return search and search["url"] or "" + +def search_next_match(request) : + search = _get_stored_search(request) + if not search : + return + result = search["result"] + pos = result.index(request.client.nodeid) + if pos + 1 < len(result) : + return _calc_match_url(request, result[pos + 1]) + +def search_prev_match(request) : + search = _get_stored_search(request) + if not search : + return + result = search["result"] + pos = result.index(request.client.nodeid) + if pos > 0 : + return _calc_match_url(request, result[pos - 1]) + +def init(instance): + instance.registerUtil('update_search_result', update_search_result) + instance.registerUtil('search_url', search_url) + instance.registerUtil('search_next_match', search_next_match) + instance.registerUtil('search_prev_match', search_prev_match) Index: share/roundup/templates/classic/html/style.css =================================================================== --- share/roundup/templates/classic/html/style.css (revision 4176) +++ share/roundup/templates/classic/html/style.css (working copy) @@ -76,7 +76,7 @@ font-family: monospace; } -td.sidebar p.classblock { +p.classblock { padding: 2px 5px 2px 5px; margin: 1px; border: 1px solid #444; Index: share/roundup/templates/classic/html/issue.item.html =================================================================== --- share/roundup/templates/classic/html/issue.item.html (revision 4176) +++ share/roundup/templates/classic/html/issue.item.html (working copy) @@ -39,6 +39,19 @@ onSubmit="return submit_once()" enctype="multipart/form-data" tal:attributes="action context/designator"> +

+ Return to search +
+ << previous + | + next >> +

+ Index: share/roundup/templates/classic/html/issue.index.html =================================================================== --- share/roundup/templates/classic/html/issue.index.html (revision 4176) +++ share/roundup/templates/classic/html/issue.index.html (working copy) @@ -21,7 +21,13 @@ and request.user.hasRole('Anonymous')" i18n:translate=""> Please login with your username and password.

- + + + +
Title
@@ -35,7 +41,7 @@ - +
PriorityCreator Assigned To
@@ -58,7 +64,7 @@   - title