diff --git a/r2/r2/controllers/front.py b/r2/r2/controllers/front.py index 7aa0bf827..f3aabb564 100644 --- a/r2/r2/controllers/front.py +++ b/r2/r2/controllers/front.py @@ -162,6 +162,17 @@ class FrontController(RedditController): return old_visits + @validate(article = VLink('article'), + comment = VCommentID('comment'), + context = VInt('context', min = 0, max = 8), + sort = VMenu('controller', CommentSortMenu), + limit = VInt('limit'), + depth = VInt('depth')) + def POST_comments(self, article, comment, context, sort, limit, depth): + # VMenu validator will save the value of sort before we reach this + # point. Now just redirect to GET mode. + return self.redirect(request.fullpath + query_string(dict(sort=sort))) + @validate(article = VLink('article'), comment = VCommentID('comment'), context = VInt('context', min = 0, max = 8), diff --git a/r2/r2/controllers/listingcontroller.py b/r2/r2/controllers/listingcontroller.py index 1a260bb65..3ed28be75 100644 --- a/r2/r2/controllers/listingcontroller.py +++ b/r2/r2/controllers/listingcontroller.py @@ -379,6 +379,12 @@ class NewController(ListingController): else: return c.site.get_links('new', 'all') + @validate(sort = VMenu('controller', NewMenu)) + def POST_listing(self, sort, **env): + # VMenu validator will save the value of sort before we reach this + # point. Now just redirect to GET mode. + return self.redirect(request.fullpath + query_string(dict(sort=sort))) + @validate(sort = VMenu('controller', NewMenu)) def GET_listing(self, sort, **env): self.sort = sort @@ -405,6 +411,15 @@ class BrowseController(ListingController): def query(self): return c.site.get_links(self.sort, self.time) + # TODO: this is a hack with sort. + @validate(sort = VOneOf('sort', ('top', 'controversial')), + time = VMenu('where', ControversyTimeMenu)) + def POST_listing(self, sort, time, **env): + # VMenu validator will save the value of time before we reach this + # point. Now just redirect to GET mode. + return self.redirect( + request.fullpath + query_string(dict(sort=sort, time=time))) + # TODO: this is a hack with sort. @validate(sort = VOneOf('sort', ('top', 'controversial')), time = VMenu('where', ControversyTimeMenu)) diff --git a/r2/r2/controllers/validator/validator.py b/r2/r2/controllers/validator/validator.py index 040f6e701..6780b2936 100644 --- a/r2/r2/controllers/validator/validator.py +++ b/r2/r2/controllers/validator/validator.py @@ -1018,12 +1018,12 @@ class VMenu(Validator): def __init__(self, param, menu_cls, remember = True, **kw): self.nav = menu_cls self.remember = remember - param = (menu_cls.get_param, param) + param = (menu_cls.name, param) Validator.__init__(self, param, **kw) def run(self, sort, where): if self.remember: - pref = "%s_%s" % (where, self.nav.get_param) + pref = "%s_%s" % (where, self.nav.name) user_prefs = copy(c.user.sort_options) if c.user else {} user_pref = user_prefs.get(pref) @@ -1035,8 +1035,9 @@ class VMenu(Validator): if sort not in self.nav.options: sort = self.nav.default - # commit the sort if changed - if self.remember and c.user_is_loggedin and sort != user_pref: + # commit the sort if changed and if this is a POST request + if (self.remember and c.user_is_loggedin and sort != user_pref + and request.method.upper() == 'POST'): user_prefs[pref] = sort c.user.sort_options = user_prefs user = c.user diff --git a/r2/r2/lib/menus.py b/r2/r2/lib/menus.py index c163a6448..6b8305685 100644 --- a/r2/r2/lib/menus.py +++ b/r2/r2/lib/menus.py @@ -195,6 +195,8 @@ class NavMenu(Styled): a dropdown from a flatlist, while the optional _class, and _id attributes can be used to set individualized CSS.""" + use_post = True + def __init__(self, options, default = None, title = '', type = "dropdown", base_path = '', separator = '|', **kw): self.options = options @@ -270,8 +272,11 @@ class NavButton(Styled): p = {} base_path = ("%s/%s/" % (base_path, self.dest)).replace('//', '/') + self.action_params = p + self.bare_path = _force_unicode(base_path.replace('//', '/')).lower() self.bare_path = self.bare_path.rstrip('/') + self.base_path = base_path # append the query string base_path += query_string(p) @@ -349,8 +354,6 @@ class NamedButton(NavButton): except KeyError: return NavButton.selected_title(self) - - class JsButton(NavButton): """A button which fires a JS event and thus has no path and cannot be in the 'selected' state""" @@ -369,24 +372,26 @@ class PageNameNav(Styled): subreddit name, the page name, etc.)""" pass -class SimpleGetMenu(NavMenu): +class SimplePostMenu(NavMenu): """Parent class of menus used for sorting and time sensitivity of - results. More specifically, defines a type of menu which changes - the url by adding a GET parameter with name 'get_param' and which - defaults to 'default' (both of which are class-level parameters). + results. Defines a type of menu that uses hidden forms to POST the user's + selection to a handler that may commit the user's choice as a preference + change before redirecting to a URL that also includes the user's choice. + If other user's load this URL, they won't affect their own preferences, but + the given choice will apply for that page load. - The value of the GET parameter must be one of the entries in + The value of the POST/GET parameter must be one of the entries in 'cls.options'. This parameter is also used to construct the list of NavButtons contained in this Menu instance. The goal here is to have a menu object which 'out of the box' is self validating.""" options = [] - get_param = '' + name = '' title = '' default = None type = 'lightdrop' def __init__(self, **kw): - buttons = [NavButton(self.make_title(n), n, opt = self.get_param) + buttons = [NavButton(self.make_title(n), n, opt=self.name, style='post') for n in self.options] kw['default'] = kw.get('default', self.default) kw['base_path'] = kw.get('base_path') or request.path @@ -400,15 +405,15 @@ class SimpleGetMenu(NavMenu): """Converts the opt into a DB-esque operator used for sorting results""" return None -class SortMenu(SimpleGetMenu): +class SortMenu(SimplePostMenu): """The default sort menu.""" - get_param = 'sort' + name = 'sort' default = 'hot' options = ('hot', 'new', 'top', 'old', 'controversial') def __init__(self, **kw): kw['title'] = _("sorted by") - SimpleGetMenu.__init__(self, **kw) + SimplePostMenu.__init__(self, **kw) @classmethod def operator(self, sort): @@ -449,15 +454,15 @@ class RecSortMenu(SortMenu): default = 'new' options = ('hot', 'new', 'top', 'controversial', 'relevance') -class NewMenu(SimpleGetMenu): - get_param = 'sort' +class NewMenu(SimplePostMenu): + name = 'sort' default = 'rising' options = ('new', 'rising') type = 'flatlist' def __init__(self, **kw): kw['title'] = "" - SimpleGetMenu.__init__(self, **kw) + SimplePostMenu.__init__(self, **kw) @classmethod def operator(self, sort): @@ -465,29 +470,29 @@ class NewMenu(SimpleGetMenu): return operators.desc('_date') -class KindMenu(SimpleGetMenu): - get_param = 'kind' +class KindMenu(SimplePostMenu): + name = 'kind' default = 'all' options = ('links', 'comments', 'messages', 'all') def __init__(self, **kw): kw['title'] = _("kind") - SimpleGetMenu.__init__(self, **kw) + SimplePostMenu.__init__(self, **kw) def make_title(self, attr): if attr == "all": return _("all") return menu[attr] -class TimeMenu(SimpleGetMenu): +class TimeMenu(SimplePostMenu): """Menu for setting the time interval of the listing (from 'hour' to 'all')""" - get_param = 't' + name = 't' default = 'all' options = ('hour', 'day', 'week', 'month', 'year', 'all') def __init__(self, **kw): kw['title'] = _("links from") - SimpleGetMenu.__init__(self, **kw) + SimplePostMenu.__init__(self, **kw) @classmethod def operator(self, time): @@ -500,6 +505,8 @@ class ControversyTimeMenu(TimeMenu): default = 'day' class SubredditMenu(NavMenu): + use_post = False + def find_selected(self): """Always return False so the title is always displayed""" return None diff --git a/r2/r2/public/static/css/compact.css b/r2/r2/public/static/css/compact.css index 1491a1764..c7ae717b4 100644 --- a/r2/r2/public/static/css/compact.css +++ b/r2/r2/public/static/css/compact.css @@ -422,7 +422,7 @@ body[orient="landscape"] > #topbar > h1 { text-overflow: ellipsis; overflow: hidden; } -.subtoolbar > ul > li > a { +.subtoolbar > ul > li a { color: #4c566c; font-weight: bold; text-decoration: none; @@ -433,7 +433,7 @@ body[orient="landscape"] > #topbar > h1 { text-overflow: ellipsis; overflow: hidden; } -.subtoolbar > ul > li.selected > a { +.subtoolbar > ul > li.selected a { background-color: #7f7f7f; background: -moz-linear-gradient(-90deg, #dddddd, #aaaaaa); background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#dddddd), to(#aaaaaa)); diff --git a/r2/r2/public/static/css/compact.scss b/r2/r2/public/static/css/compact.scss index 75afec408..bed88cfc1 100644 --- a/r2/r2/public/static/css/compact.scss +++ b/r2/r2/public/static/css/compact.scss @@ -395,7 +395,7 @@ body[orient="landscape"] > #topbar > h1 { text-overflow: ellipsis; overflow: hidden; } -.subtoolbar > ul > li > a { +.subtoolbar > ul > li a { color: rgb(76, 86, 108); font-weight: bold; text-decoration: none; @@ -405,7 +405,7 @@ body[orient="landscape"] > #topbar > h1 { text-overflow: ellipsis; overflow: hidden; } -.subtoolbar > ul > li.selected > a { +.subtoolbar > ul > li.selected a { @include vertical_gradient(#ddd, #aaa); /* no color-stop outside of webkit */ background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#ddd), color-stop(.4,#ddd), to(#aaa)); diff --git a/r2/r2/templates/navbutton.compact b/r2/r2/templates/navbutton.compact index 527bcc063..a8f322398 100644 --- a/r2/r2/templates/navbutton.compact +++ b/r2/r2/templates/navbutton.compact @@ -20,7 +20,7 @@ ## CondeNet, Inc. All Rights Reserved. ################################################################################ -<%namespace file="utils.html" import="plain_link" /> +<%namespace file="utils.html" import="plain_link, post_link" /> <%def name="plain()"> ${plain_link(thing.title, @@ -36,4 +36,8 @@ onclick = thing.onclick)} %def> - +<%def name="post()"> + ${post_link(thing.title, thing.base_path, thing.path, thing.action_params, + _sr_path=sr_path, nocname=nocname, target=thing.target, + _class=thing.css_class, _id=thing._id)} +%def> diff --git a/r2/r2/templates/navbutton.html b/r2/r2/templates/navbutton.html index 8c5cbb957..16052a5bd 100644 --- a/r2/r2/templates/navbutton.html +++ b/r2/r2/templates/navbutton.html @@ -20,7 +20,7 @@ ## CondeNet, Inc. All Rights Reserved. ################################################################################ -<%namespace file="utils.html" import="plain_link" /> +<%namespace file="utils.html" import="plain_link, post_link" /> <%def name="plain()"> ${plain_link(thing.selected_title() if thing.selected else thing.title, @@ -36,4 +36,9 @@ onclick = thing.onclick)} %def> - +<%def name="post()"> + ${post_link(thing.selected_title() if thing.selected else thing.title, + thing.base_path, thing.path, thing.action_params, + _sr_path=thing.sr_path, nocname=thing.nocname, + target=thing.target, _class=thing.css_class, _id=thing._id)} +%def> diff --git a/r2/r2/templates/navmenu.html b/r2/r2/templates/navmenu.html index 9b5525858..d9e97da2e 100644 --- a/r2/r2/templates/navmenu.html +++ b/r2/r2/templates/navmenu.html @@ -20,7 +20,7 @@ ## CondeNet, Inc. All Rights Reserved. ################################################################################ -<%namespace file="utils.html" import="plain_link, text_with_links, img_link, separator"/> +<%namespace file="utils.html" import="plain_link, post_link, text_with_links, img_link, separator"/> <%def name="dropdown()"> ## caching comment: @@ -47,8 +47,14 @@