Some toolbar upgrades

This commit is contained in:
ketralnis
2009-05-29 12:04:00 -07:00
parent de17178bc1
commit a07c576d1a
64 changed files with 1273 additions and 338 deletions

View File

@@ -23,7 +23,7 @@
# Jacascript files to be compressified
js_targets = jquery.js jquery.json.js jquery.reddit.js reddit.js
# CSS targets
css_targets = reddit.css reddit-ie6-hax.css
css_targets = reddit.css reddit-ie6-hax.css reddit-ie7-hax.css
SED=sed

View File

@@ -134,8 +134,16 @@ def make_map(global_conf={}, app_conf={}):
requirements=dict(action="help|blog"))
mc('/help/:anything', controller='embed', action='help')
mc('/:action', controller='toolbar',
requirements=dict(action="goto|toolbar"))
mc('/goto', controller='toolbar', action='goto')
mc('/tb/:id', controller='toolbar', action='tb')
mc('/toolbar/:action', controller='toolbar',
requirements=dict(action="toolbar|inner|login"))
mc('/toolbar/comments/:id', controller='toolbar', action='comments')
mc('/s/*rest', controller='toolbar', action='s')
# additional toolbar-related rules just above the catchall
mc('/d/:what', controller='api', action='bookmarklet')
mc('/resetpassword/:key', controller='front',
action='resetpassword')
@@ -150,8 +158,6 @@ def make_map(global_conf={}, app_conf={}):
mc('/api/:action/:url_user', controller='api',
requirements=dict(action="login|register"))
mc('/api/:action', controller='api')
mc('/d/:what', controller='api', action='bookmarklet')
mc('/captcha/:iden', controller='captcha', action='captchaimg')
@@ -175,6 +181,15 @@ def make_map(global_conf={}, app_conf={}):
# displayed properly.
mc('/error/document/:id', controller='error', action="document")
# these should be near the buttom, because they should only kick
# in if everything else fails. It's the attempted catch-all
# reddit.com/http://... and reddit.com/34fr, but these redirect to
# the less-guessy versions at /s/ and /tb/
mc('/:linkoid', controller='toolbar', action='linkoid',
requirements=dict(linkoid='[0-9a-z]{1,6}'))
mc('/:urloid', controller='toolbar', action='urloid',
requirements=dict(urloid=r'(\w+\.\w{2,}|https?).*'))
mc("/*url", controller='front', action='catchall')
return map

View File

@@ -33,7 +33,7 @@ import r2.models.thing_changes as tc
from r2.controllers import ListingController
from r2.lib.utils import get_title, sanitize_url, timeuntil, set_last_modified
from r2.lib.utils import query_string, to36, timefromnow
from r2.lib.utils import query_string, to36, timefromnow, link_from_url
from r2.lib.wrapped import Wrapped
from r2.lib.pages import FriendList, ContributorList, ModList, \
BannedList, BoringPage, FormPage, NewLink, CssError, UploadedImage
@@ -55,25 +55,6 @@ from md5 import md5
from r2.lib.promote import promote, unpromote, get_promoted
def link_listing_by_url(url, count = None):
"""
Generates a listing of links which share a common url
"""
links = ()
try:
if url:
links = list(tup(Link._by_url(url, sr = c.site)))
links.sort(key = lambda x: -x._score)
if count is not None:
links = links[:count]
except NotFound:
pass
names = [l._fullname for l in links]
builder = IDBuilder(names, num = 25)
return LinkListing(builder).listing()
class ApiController(RedditController):
"""
Controller which deals with almost all AJAX site interaction.
@@ -95,10 +76,14 @@ class ApiController(RedditController):
count = VLimit('limit'))
def GET_info(self, link, count):
"""
Get's a listing of links which have the provided url.
Gets a listing of links which have the provided url.
"""
listing = link_listing_by_url(request.params.get('url'),
count = count)
if not link or 'url' not in request.params:
return abort(404, 'not found')
links = link_from_url(request.params.get('url'), filter_spam = False)
builder = IDBuilder([link._fullname for link in links], num = count)
listing = LinkListing(builder, nextprev = False).listing()
return BoringPage(_("API"), content = listing).render()
@validatedForm(VCaptcha(),
@@ -169,8 +154,9 @@ class ApiController(RedditController):
url = VUrl(['url', 'sr']),
title = VTitle('title'),
save = VBoolean('save'),
then = VOneOf('then', ('tb', 'comments'), default='comments')
)
def POST_submit(self, form, jquery, url, title, save, sr, ip):
def POST_submit(self, form, jquery, url, title, save, sr, ip, then):
if isinstance(url, (unicode, str)):
form.set_inputs(url = url)
@@ -245,13 +231,12 @@ class ApiController(RedditController):
# flag search indexer that something has changed
tc.changed(l)
# make_permalink is designed for links that can be set to _top
# here, we need to generate an ajax redirect as if we were not on a
# cname.
cname = c.cname
c.cname = False
path = l.make_permalink_slow()
c.cname = cname
if then == 'comments':
path = add_sr(l.make_permalink_slow())
elif then == 'tb':
form.attr('target', '_top')
path = add_sr('/tb/%s' % l._id36)
form.redirect(path)
def _login(self, form, user, dest='', rem = None):
@@ -706,7 +691,9 @@ class ApiController(RedditController):
errors.BANNED_IP in c.errors or
errors.CHEATER in c.errors)
# TODO: temporary hack until we migrate the rest of the vote data
if thing and thing._date > datetime(2009, 4, 17, 0, 0, 0, 0, g.tz):
if thing and thing._date < datetime(2009, 4, 17, 0, 0, 0, 0, g.tz):
g.log.debug("POST_vote: ignoring old vote on %s" % thing._fullname)
elif thing:
dir = (True if dir > 0
else False if dir < 0
else None)
@@ -1372,6 +1359,18 @@ class ApiController(RedditController):
return UploadedImage(_('saved'), thumbnail_url(link), "",
errors = errors).render()
@noresponse()
def POST_tb_commentspanel_show(self):
# this preference is allowed for non-logged-in users
c.user.pref_frame_commentspanel = True
c.user._commit()
@noresponse()
def POST_tb_commentspanel_hide(self):
# this preference is allowed for non-logged-in users
c.user.pref_frame_commentspanel = False
c.user._commit()
@validatedForm(promoted = VByName('ids', thing_cls = Link, multiple = True))
def POST_onload(self, form, jquery, promoted, *a, **kw):
# make sure that they are really promoted

View File

@@ -113,6 +113,8 @@ class ErrorController(RedditController):
def send404(self):
c.response.status_code = 404
if 'usable_error_content' in request.environ:
return request.environ['usable_error_content']
if c.site._spam and not c.user_is_admin:
message = (strings.banned_subreddit % dict(link = '/feedback'))

View File

@@ -22,12 +22,12 @@
from validator import *
from pylons.i18n import _, ungettext
from reddit_base import RedditController, base_listing
from api import link_listing_by_url
from r2 import config
from r2.models import *
from r2.lib.pages import *
from r2.lib.menus import *
from r2.lib.utils import to36, sanitize_url, check_cheating, title_to_url, query_string, UrlParser
from r2.lib.utils import to36, sanitize_url, check_cheating, title_to_url
from r2.lib.utils import query_string, UrlParser, link_from_url
from r2.lib.template_helpers import get_domain
from r2.lib.emailer import has_opted_out, Email
from r2.lib.db.operators import desc
@@ -76,20 +76,20 @@ class FrontController(RedditController):
def GET_random(self):
"""The Serendipity button"""
n = rand.randint(0, 9)
sort = 'new' if n > 5 else 'hot'
sort = 'new' if rand.choice((True,False)) else 'hot'
links = c.site.get_links(sort, 'all')
if isinstance(links, thing.Query):
links._limit = 25
links = [x._fullname for x in links]
links._limit = 25
links = [x._fullname for x in links]
else:
links = links[:25]
links = list(links)[:25]
if links:
name = links[rand.randint(0, min(24, len(links)-1))]
name = rand.choice(links)
link = Link._by_fullname(name, data = True)
return self.redirect(link.url)
return self.redirect(add_sr("/tb/" + link._id36))
else:
return self.redirect('/')
return self.redirect(add_sr('/'))
def GET_password(self):
"""The 'what is my password' page"""
@@ -138,8 +138,8 @@ class FrontController(RedditController):
#check for 304
self.check_modified(article, 'comments')
# if there is a focal comment, communicate down to comment_skeleton.html who
# that will be
# if there is a focal comment, communicate down to
# comment_skeleton.html who that will be
if comment:
c.focal_comment = comment._id36
@@ -150,7 +150,9 @@ class FrontController(RedditController):
check_cheating('comments')
# figure out number to show based on the menu
# figure out number to show based on the menu (when num_comments
# is 'true', the user wants to temporarily override their
# comments limit pref
user_num = c.user.pref_num_comments or g.num_comments
num = g.max_comments if num_comments == 'true' else user_num
@@ -411,8 +413,6 @@ class FrontController(RedditController):
return builder.total_num, timing, res
def GET_login(self):
"""The /login form. No link to this page exists any more on
the site (all actions invoking it now go through the login
@@ -432,10 +432,10 @@ class FrontController(RedditController):
@validate(VUser(),
VModhash())
def POST_logout(self):
def POST_logout(self, dest = None):
"""wipe login cookie and redirect to referer."""
self.logout()
dest = request.referer or '/'
dest = request.post.get('dest','') or request.referer or '/'
return self.redirect(dest)
@@ -474,38 +474,25 @@ class FrontController(RedditController):
@validate(VUser(),
VSRSubmitPage(),
url = VRequired('url', None),
title = VRequired('title', None))
def GET_submit(self, url, title):
title = VRequired('title', None),
then = VOneOf('then', ('tb','comments'), default = 'comments'))
def GET_submit(self, url, title, then):
"""Submit form."""
if url and not request.get.get('resubmit'):
# check to see if the url has already been submitted
listing = link_listing_by_url(url)
redirect_link = None
if listing.things:
# if there is only one submission, the operation is clear
if len(listing.things) == 1:
redirect_link = listing.things[0]
# if there is more than one, check the users' subscriptions
else:
subscribed = [l for l in listing.things
if c.user_is_loggedin
and l.subreddit.is_subscriber_defaults(c.user)]
links = link_from_url(url)
if links and len(links) == 1:
return self.redirect(links[0].already_submitted_link)
elif links:
builder = IDBuilder([link._fullname for link in links])
listing = LinkListing(builder, nextprev=False).listing()
infotext = (strings.multiple_submitted
% links[0].resubmit_link())
res = BoringPage(_("seen it"),
content = listing,
infotext = infotext).render()
return res
#if there is only 1 link to be displayed, just go there
if len(subscribed) == 1:
redirect_link = subscribed[0]
else:
infotext = strings.multiple_submitted % \
listing.things[0].resubmit_link()
res = BoringPage(_("seen it"),
content = listing,
infotext = infotext).render()
return res
# we've found a link already. Redirect to its permalink page
if redirect_link:
return self.redirect(redirect_link.already_submitted_link)
captcha = Captcha() if c.user.needs_captcha() else None
sr_names = Subreddit.submit_sr_names(c.user) if c.default_sr else ()
@@ -513,7 +500,8 @@ class FrontController(RedditController):
content=NewLink(url=url or '',
title=title or '',
subreddits = sr_names,
captcha=captcha)).render()
captcha=captcha,
then = then)).render()
def _render_opt_in_out(self, msg_hash, leave):
"""Generates the form for an optin/optout page"""

View File

@@ -47,7 +47,7 @@ from r2.lib.tracking import encrypt, decrypt
NEVER = 'Thu, 31 Dec 2037 23:59:59 GMT'
cache_affecting_cookies = ('reddit_first','over18')
cache_affecting_cookies = ('reddit_first','over18','_options')
r_subnet = re.compile("^(\d+\.\d+)\.\d+\.\d+$")
@@ -73,7 +73,7 @@ class Cookie(object):
class UnloggedUser(FakeAccount):
_cookie = 'options'
allowed_prefs = ('pref_content_langs', 'pref_lang')
allowed_prefs = ('pref_content_langs', 'pref_lang', 'pref_frame_commentspanel')
def __init__(self, browser_langs, *a, **kw):
FakeAccount.__init__(self, *a, **kw)
@@ -90,6 +90,7 @@ class UnloggedUser(FakeAccount):
self._defaults = self._defaults.copy()
self._defaults['pref_lang'] = lang
self._defaults['pref_content_langs'] = content_langs
self._defaults['pref_frame_commentspanel'] = False
self._load()
@property

View File

@@ -21,31 +21,228 @@
################################################################################
from reddit_base import RedditController
from r2.lib.pages import *
from r2.models import *
from r2.lib.menus import CommentSortMenu
from r2.lib.filters import spaceCompress
from r2.lib.memoize import memoize
from r2.lib.template_helpers import add_sr
from r2.lib import utils
from validator import *
from pylons import c
from pylons import c, Response
import string
# strips /r/foo/, /s/, or both
strip_sr = re.compile('^/r/[a-zA-Z0-9_-]+')
strip_s_path = re.compile('^/s/')
leading_slash = re.compile('^/+')
has_protocol = re.compile('^https?:')
need_insert_slash = re.compile('^https?:/[^/]')
def demangle_url(path):
# there's often some URL mangling done by the stack above us, so
# let's clean up the URL before looking it up
path = strip_sr.sub('', path)
path = strip_s_path.sub('', path)
path = leading_slash.sub("", path)
if not has_protocol.match(path):
path = 'http://%s' % path
if need_insert_slash.match(path):
path = string.replace(path, '/', '//', 1)
path = utils.sanitize_url(path)
return path
def force_html():
"""Because we can take URIs like /s/http://.../foo.png, and we can
guarantee that the toolbar will never be used with a non-HTML
render style, we don't want to interpret the extension from the
target URL. So here we rewrite Middleware's interpretation of
the extension to force it to be HTML
"""
c.render_style = 'html'
c.extension = None
c.content_type = 'text/html; charset=UTF-8'
def auto_expand_panel(link):
if not link.num_comments:
return False
else:
return c.user.pref_frame_commentspanel
@memoize('toolbar.get_title', time = 500)
def get_title(url):
"""Find the <title> in the page contained at 'url'. Copied here
from utils so that we can memoize it"""
return utils.get_title(url)
class ToolbarController(RedditController):
@validate(link = VByName('id'))
def GET_toolbar(self, link):
if not link: return self.abort404()
link_builder = IDBuilder((link._fullname,))
link_listing = LinkListing(link_builder, nextprev=False).listing()
res = FrameToolbar(link = link_listing.things[0]).render()
return spaceCompress(res)
@validate(link = VByName('id'),
@validate(link1 = VByName('id'),
link2 = VLink('id', redirect = False))
def GET_goto(self, link, link2):
link = link2 if link2 else link
def GET_goto(self, link1, link2):
"""Support old /goto?id= urls. deprecated"""
link = link2 if link2 else link1
if link:
link._load()
if c.user and c.user.pref_frame:
return Frame(title = link.title,
url = link.url,
fullname = link._fullname).render()
else:
return self.redirect(link.url)
return self.redirect(add_sr("/tb/" + link._id36))
return self.abort404()
@validate(link = VLink('id'))
def GET_tb(self, link):
"/tb/$id36, show a given link with the toolbar"
if not link:
return self.abort404()
res = Frame(title = link.title,
url = link.url,
fullname = link._fullname)
return spaceCompress(res.render())
def GET_s(self, rest):
"""/s/http://..., show a given URL with the toolbar. if it's
submitted, redirect to /tb/$id36"""
force_html()
path = demangle_url(request.fullpath)
if not path:
# it was malformed
self.abort404()
link = utils.link_from_url(path, multiple = False)
if c.cname and not c.authorized_cname:
# In this case, we make some bad guesses caused by the
# cname frame on unauthorised cnames.
# 1. User types http://foo.com/http://myurl?cheese=brie
# (where foo.com is an unauthorised cname)
# 2. We generate a frame that points to
# http://www.reddit.com/r/foo/http://myurl?cnameframe=0.12345&cheese=brie
# 3. Because we accept everything after the /r/foo/, and
# we've now parsed, modified, and reconstituted that
# URL to add cnameframe, we really can't make any good
# assumptions about what we've done to a potentially
# already broken URL, and we can't assume that we've
# rebuilt it in the way that it was originally
# submitted (if it was)
# We could try to work around this with more guesses (by
# having demangle_url try to remove that param, hoping
# that it's not already a malformed URL, and that we
# haven't re-ordered the GET params, removed
# double-slashes, etc), but for now, we'll just refuse to
# do this operation
return self.abort404()
if link:
# we were able to find it, let's send them to the
# link-id-based URL so that their URL is reusable
return self.redirect(add_sr("/tb/" + link._id36))
title = get_title(path)
if not title:
title = utils.domain(path)
res = Frame(title = title, url = path)
# we don't want clients to think that this URL is actually a
# valid URL for search-indexing or the like
c.response = Response()
c.response.status_code = 404
request.environ['usable_error_content'] = spaceCompress(res.render())
return c.response
@validate(link = VLink('id'))
def GET_comments(self, link):
if not link:
self.abort404()
if not link.subreddit_slow.can_view(c.user):
abort(403, 'forbidden')
def builder_wrapper(cm):
w = Wrapped(cm)
w.render_class = StarkComment
w.target = "_top"
return w
link_builder = IDBuilder((link._fullname,))
link_listing = LinkListing(link_builder, nextprev=False).listing()
links = link_listing.things[0],
if not links:
# they aren't allowed to see this link
return self.abort(403, 'forbidden')
link = links[0]
res = FrameToolbar(link = link,
title = link.title,
url = link.url)
b = TopCommentBuilder(link, CommentSortMenu.operator('top'),
wrap = builder_wrapper)
listing = NestedListing(b, num = 10, # TODO: add config var
parent_name = link._fullname)
res = RedditMin(content=CommentsPanel(link=link, listing=listing.listing(),
expanded = auto_expand_panel(link)))
return res.render()
@validate(link = VByName('id'),
url = nop('url'))
def GET_toolbar(self, link, url):
"""The visible toolbar, with voting buttons and all"""
if not link:
link = utils.link_from_url(url, multiple = False)
if link:
link_builder = IDBuilder((link._fullname,))
res = FrameToolbar(link = link_builder.get_items()[0][0],
title = link.title,
url = link.url,
expanded = auto_expand_panel(link))
else:
res = FrameToolbar(link = None,
title = get_title(url),
url = url,
expanded = False)
return spaceCompress(res.render())
@validate(link = VByName('id'))
def GET_inner(self, link):
"""The intermediate frame that displays the comments side-bar
on one side and the link on the other"""
if not link:
return self.abort404()
res = InnerToolbarFrame(link = link, expanded = auto_expand_panel(link))
return spaceCompress(res.render())
@validate(link = VLink('linkoid'))
def GET_linkoid(self, link):
if not link:
return self.abort404()
return self.redirect(add_sr("/tb/" + link._id36))
slash_fixer = re.compile('(/s/https?:)/+')
@validate(urloid = nop('urloid'))
def GET_urloid(self, urloid):
# they got here from "/http://..."
path = demangle_url(request.fullpath)
if not path:
# malformed URL
self.abort404()
redir_path = add_sr("/s/" + path)
force_html()
# Redirect to http://reddit.com/s/http://google.com
# rather than http://reddit.com/s/http:/google.com
redir_path = self.slash_fixer.sub(r'\1///', redir_path, 1)
# ^^^
# 3=2 when it comes to self.redirect()
return self.redirect(redir_path)

View File

@@ -115,7 +115,7 @@ fix_url = re.compile('&lt;(http://[^\s\'\"\]\)]+)&gt;')
#TODO markdown should be looked up in batch?
#@memoize('markdown')
def safemarkdown(text, nofollow = False):
def safemarkdown(text, nofollow=False, target=None):
from contrib.markdown import markdown
if text:
# increase escaping of &, < and > once
@@ -133,8 +133,12 @@ def safemarkdown(text, nofollow = False):
def href_handler(m):
url = m.group(1).replace('&amp;', '&')
link = '<a href="%s"' % url
if c.cname:
if target:
link += ' target="%s"' % target
elif c.cname:
link += ' target="_top"'
if nofollow:
link += ' rel="nofollow"'
return link

View File

@@ -99,6 +99,7 @@ menu = MenuHandler(hot = _('hot'),
store = _("store"),
ad_inq = _("advertise on reddit"),
toplinks = _("top links"),
random = _('random'),
iphone = _("iPhone app"),
#preferences

View File

@@ -24,7 +24,7 @@ from r2.models import IDBuilder, LinkListing, Account, Default, FakeSubreddit, S
from r2.config import cache
from r2.lib.jsonresponse import json_respond
from r2.lib.jsontemplates import is_api
from pylons.i18n import _
from pylons.i18n import _, ungettext
from pylons import c, request, g
from pylons.controllers.util import abort
@@ -33,11 +33,13 @@ from r2.lib.captcha import get_iden
from r2.lib.filters import spaceCompress, _force_unicode, _force_utf8
from r2.lib.menus import NavButton, NamedButton, NavMenu, PageNameNav, JsButton
from r2.lib.menus import SubredditButton, SubredditMenu, OffsiteButton, menu
from r2.lib.strings import plurals, rand_strings, strings
from r2.lib.utils import title_to_url, query_string, UrlParser, to_js
from r2.lib.strings import plurals, rand_strings, strings, Score
from r2.lib.utils import title_to_url, query_string, UrlParser, to_js, vote_hash
from r2.lib.template_helpers import add_sr, get_domain
import sys, random, datetime, locale, calendar
import sys, random, datetime, locale, calendar, re
import graph
from urllib import quote
datefmt = _force_utf8(_('%d %b %Y'))
@@ -71,20 +73,23 @@ class Reddit(Wrapped):
create_reddit_box = True
submit_box = True
footer = True
searchbox = True
extension_handling = True
enable_login_cover = True
site_tracking = True
show_firsttext = True
def __init__(self, space_compress = True, nav_menus = None, loginbox = True,
infotext = '', content = None, title = '', robots = None,
show_sidebar = True, **context):
show_sidebar = True, footer = True, **context):
Wrapped.__init__(self, **context)
self.title = title
self.robots = robots
self.infotext = infotext
self.loginbox = True
self.show_sidebar = show_sidebar
self.footer = footer
self.space_compress = space_compress
#put the sort menus at the top
@@ -92,7 +97,7 @@ class Reddit(Wrapped):
#add the infobar
self.infobar = None
if c.firsttime and c.site.firsttext and not infotext:
if self.show_firsttext and c.firsttime and c.site.firsttext and not infotext:
infotext = c.site.firsttext
if infotext:
self.infobar = InfoBar(message = infotext)
@@ -190,6 +195,7 @@ class Reddit(Wrapped):
OffsiteButton("rss", dest = '/.rss'),
NamedButton("store", False, nocname=True),
NamedButton("stats", False, nocname=True),
NamedButton('random', False, nocname=False),
NamedButton("feedback", False),],
title = 'site links', type = 'flat_vert',
separator = ''),
@@ -297,6 +303,13 @@ class Reddit(Wrapped):
"""returns a Wrapped (or renderable) item for the main content div."""
return self.content_stack(self.infobar, self.nav_menu, self._content)
class RedditMin(Reddit):
"""a version of Reddit that has no sidebar, toolbar, footer,
etc"""
footer = False
show_sidebar = False
show_firsttext = False
class LoginFormWide(Wrapped):
"""generates a login form suitable for the 300px rightbox."""
pass
@@ -455,6 +468,17 @@ class SearchPage(BoringPage):
return self.content_stack(self.searchbar, self.infobar,
self.nav_menu, self._content)
class CommentsPanel(Wrapped):
"""the side-panel on the reddit toolbar frame that shows the top
comments of a link"""
def __init__(self, link = None, listing = None, expanded = False, *a, **kw):
self.link = link
self.listing = listing
self.expanded = expanded
Wrapped.__init__(self, *a, **kw)
class LinkInfoPage(Reddit):
"""Renders the varied /info pages for a link. The Link object is
passed via the link argument and the content passed to this class
@@ -531,12 +555,8 @@ class LinkInfoPage(Reddit):
class LinkInfoBar(Wrapped):
"""Right box for providing info about a link."""
def __init__(self, a = None):
if a:
a = Wrapped(a)
Wrapped.__init__(self, a = a, datefmt = datefmt)
class EditReddit(Reddit):
"""Container for the about page for a reddit"""
extension_handling= False
@@ -880,27 +900,73 @@ class SearchBar(Wrapped):
class Frame(Wrapped):
"""Frameset for the FrameToolbar used when a user hits /goto and
has pref_toolbar set. The top 30px of the page are dedicated to
the toolbar, while the rest of the page will show the results of
following the link."""
def __init__(self, url='', title='', fullname=''):
"""Frameset for the FrameToolbar used when a user hits /tb/. The
top 30px of the page are dedicated to the toolbar, while the rest
of the page will show the results of following the link."""
def __init__(self, url='', title='', fullname=None):
if title:
title = (_('%(site_title)s via %(domain)s')
% dict(site_title = _force_unicode(title),
domain = g.domain))
else:
title = g.domain
Wrapped.__init__(self, url = url, title = title, fullname = fullname)
dorks_re = re.compile(r"https?://?([-\w.]*\.)?digg\.com/\w+$")
class FrameToolbar(Wrapped):
"""The reddit voting toolbar used together with Frame."""
extension_handling = False
def __init__(self, link = None, **kw):
self.title = link.title
Wrapped.__init__(self, link = link, *kw)
def __init__(self, link = None, title = None, url = None, expanded = False, **kw):
self.title = title
self.url = url
self.expanded = expanded
self.link = link
self.dorks = dorks_re.match(link.url if link else url)
if link:
self.tblink = add_sr("/tb/"+link._id36)
likes = link.likes
self.upstyle = "mod" if likes else ""
self.downstyle = "mod" if likes is False else ""
if c.user_is_loggedin:
self.vh = vote_hash(c.user, link, 'valid')
score = link.score
if not link.num_comments:
# generates "comment" the imperative verb
self.com_label = _("comment {verb}")
else:
# generates "XX comments" as a noun
com_label = ungettext("comment", "comments", link.num_comments)
self.com_label = strings.number_label % (link.num_comments, com_label)
# generates "XX points" as a noun
self.score_label = Score.safepoints(score)
else:
self.tblink = add_sr("/s/"+quote(url))
submit_url_options = dict(url = _force_unicode(url),
then = 'tb')
if title:
submit_url_options['title'] = _force_unicode(title)
self.submit_url = add_sr('/submit' + query_string(submit_url_options))
if not c.user_is_loggedin:
self.loginurl = add_sr("/login?dest="+quote(self.tblink))
Wrapped.__init__(self, **kw)
class NewLink(Wrapped):
"""Render the link submission form"""
def __init__(self, captcha = None, url = '', title= '', subreddits = ()):
def __init__(self, captcha = None, url = '', title= '', subreddits = (),
then = 'comments'):
Wrapped.__init__(self, captcha = captcha, url = url,
title = title, subreddits = subreddits)
title = title, subreddits = subreddits,
then = then)
class ShareLink(Wrapped):
def __init__(self, link_name = "", emails = None):
@@ -994,7 +1060,13 @@ class Socialite(Wrapped):
class Bookmarklets(Wrapped):
"""The bookmarklets page."""
def __init__(self, buttons=["reddit", "serendipity!"]):
def __init__(self, buttons=None):
if buttons is None:
buttons = ["submit", "serendipity!"]
# only include the toolbar link if we're not on an
# unathorised cname. See toolbar.py:GET_s for discussion
if not (c.cname and c.site.domain not in g.authorized_cnames):
buttons.insert(0, "reddit toolbar")
Wrapped.__init__(self, buttons = buttons)
@@ -1377,4 +1449,6 @@ class RedditTraffic(Traffic):
"%5.2f%%" % f))
return res
class InnerToolbarFrame(Wrapped):
def __init__(self, link, expanded = False):
Wrapped.__init__(self, link = link, expanded = expanded)

View File

@@ -196,9 +196,15 @@ def dockletStr(context, type, browser):
if type == "serendipity!":
return "http://"+site_domain+"/random"
elif type == "reddit":
return "javascript:location.href='http://"+site_domain+"/submit?url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)"
elif type == "submit":
return ("javascript:location.href='http://"+site_domain+
"/submit?url='+encodeURIComponent(location.href)+'&title='+encodeURIComponent(document.title)")
elif type == "reddit toolbar":
return ("javascript:%20var%20h%20=%20window.location.href;%20h%20=%20'http://" +
site_domain + "/s/'%20+%20escape(h);%20window.location%20=%20h;")
else:
# these are the linked/disliked buttons, which we have removed
# from the UI
return (("javascript:function b(){var u=encodeURIComponent(location.href);"
"var i=document.getElementById('redstat')||document.createElement('a');"
"var s=i.style;s.position='%(position)s';s.top='0';s.left='0';"
@@ -283,3 +289,7 @@ def choose_width(link, width):
return 100 + (10 * (len(str(link._ups - link._downs))))
else:
return 110
def panel_size(state):
"the frame.cols of the reddit-toolbar's inner frame"
return '100%, 400px' if state =='expanded' else '100%x, 0px'

View File

@@ -26,6 +26,7 @@ import Queue
from copy import deepcopy
import cPickle as pickle
import re, datetime, math, random, string, sha, os
from operator import attrgetter
from datetime import datetime, timedelta
from pylons.i18n import ungettext, _
@@ -1037,3 +1038,47 @@ def interleave_lists(*args):
for a in args:
if i < len(a):
yield a[i]
def link_from_url(path, filter_spam = False, multiple = True):
from pylons import c
from r2.models import IDBuilder, Link, Subreddit, NotFound
if not path:
return
try:
links = Link._by_url(path, c.site)
except NotFound:
return [] if multiple else None
links = tup(links)
# run the list through a builder to remove any that the user
# isn't allowed to see
links = IDBuilder([link._fullname for link in links],
skip = False).get_items()[0]
if not links:
return
if filter_spam:
# first, try to remove any spam
links_nonspam = [ link for link in links
if not link._spam ]
if links_nonspam:
links = links_nonspam
# if it occurs in one or more of their subscriptions, show them
# that one first
subs = set(Subreddit.user_subreddits(c.user, limit = None))
def cmp_links(a, b):
if a.sr_id in subs and b.sr_id not in subs:
return -1
elif a.sr_id not in subs and b.sr_id in subs:
return 1
else:
return cmp(a._hot, b._hot)
links = sorted(links, cmp = cmp_links)
# among those, show them the hottest one
return links if multiple else links[0]

View File

@@ -39,6 +39,7 @@ class Account(Thing):
_int_prop_suffix = '_karma'
_defaults = dict(pref_numsites = 25,
pref_frame = False,
pref_frame_commentspanel = True,
pref_newwindow = False,
pref_public_votes = False,
pref_hide_ups = False,

View File

@@ -400,11 +400,16 @@ class SearchBuilder(QueryBuilder):
return done, new_items
class CommentBuilder(Builder):
def __init__(self, link, sort, comment = None, context = None):
Builder.__init__(self)
def __init__(self, link, sort, comment = None, context = None,
load_more=True, continue_this_thread=True,
max_depth = MAX_RECURSION, **kw):
Builder.__init__(self, **kw)
self.link = link
self.comment = comment
self.context = context
self.load_more = load_more
self.max_depth = max_depth
self.continue_this_thread = continue_this_thread
if sort.col == '_date':
self.sort_key = lambda x: x._date
@@ -419,7 +424,7 @@ class CommentBuilder(Builder):
for j in self.item_iter(i.child.things):
yield j
def get_items(self, num, nested = True, starting_depth = 0):
def get_items(self, num, starting_depth = 0):
r = link_comments(self.link._id)
cids, comment_tree, depth, num_children = r
if cids:
@@ -496,14 +501,14 @@ class CommentBuilder(Builder):
comments.remove(to_add)
if to_add._deleted and not comment_tree.has_key(to_add._id):
pass
elif depth[to_add._id] < MAX_RECURSION:
elif depth[to_add._id] < self.max_depth:
#add children
if comment_tree.has_key(to_add._id):
candidates.extend(comment_tree[to_add._id])
sort_candidates()
items.append(to_add)
num_have += 1
else:
elif self.continue_this_thread:
#add the recursion limit
p_id = to_add.parent_id
w = Wrapped(MoreRecursion(self.link, 0,
@@ -541,6 +546,9 @@ class CommentBuilder(Builder):
parent.child = empty_listing(morelink)
parent.child.parent_name = parent._fullname
if not self.load_more:
return final
#put the remaining comments into the tree (the show more comments link)
more_comments = {}
while candidates:
@@ -587,3 +595,16 @@ class CommentBuilder(Builder):
mc2.count += 1
return final
class TopCommentBuilder(CommentBuilder):
"""A comment builder to fetch only the top-level, non-spam,
non-deleted comments"""
def __init__(self, link, sort, wrap = Wrapped):
CommentBuilder.__init__(self, link, sort,
load_more = False,
continue_this_thread = False,
max_depth = 1, wrap = wrap)
def get_items(self, num = 10):
final = CommentBuilder.get_items(self, num = num, starting_depth = 0)
return [ cm for cm in final if not cm.deleted ]

View File

@@ -328,7 +328,17 @@ class Link(Thing, Printable):
item.domain_path = "/domain/%s" % item.domain
if item.is_self:
item.domain_path = item.subreddit_path
item.tblink = "http://%s/tb/%s" % (
get_domain(cname = c.cname, subreddit=False),
item._id36)
item.click_url = item.url
if item.is_self:
item.click_url = item.permalink
elif c.user.pref_frame:
item.click_url = item.tblink
if c.user_is_loggedin:
incr_counts(wrapped)
@@ -461,13 +471,16 @@ class Comment(Thing, Printable):
wrapped.likes,
wrapped.friend,
wrapped.collapsed,
wrapped.moderator_banned,
wrapped.nofollow,
wrapped.show_spam,
wrapped.show_reports,
wrapped.target,
wrapped.can_ban,
wrapped.moderator_banned,
wrapped.can_reply,
wrapped.deleted))
wrapped.deleted,
wrapped.render_class,
))
s = ''.join(s)
return s
@@ -481,8 +494,8 @@ class Comment(Thing, Printable):
@classmethod
def add_props(cls, user, wrapped):
#fetch parent links
links = Link._byID(set(l.link_id for l in wrapped), True)
links = Link._byID(set(l.link_id for l in wrapped), data = True,
return_dict = True)
#get srs for comments that don't have them (old comments)
for cm in wrapped:
@@ -499,8 +512,11 @@ class Comment(Thing, Printable):
for item in wrapped:
item.link = links.get(item.link_id)
if not hasattr(item, 'subreddit'):
item.subreddit = item.subreddit_slow
if not hasattr(item, 'target'):
item.target = None
if hasattr(item, 'parent_id'):
if cids.has_key(item.parent_id):
item.parent_permalink = '#' + utils.to36(item.parent_id)
@@ -542,6 +558,11 @@ class Comment(Thing, Printable):
item.score_fmt = Score.points
item.permalink = item.make_permalink(item.link, item.subreddit)
class StarkComment(Comment):
"""Render class for the comments in the top-comments display in
the reddit toolbar"""
_nodb = True
class MoreComments(object):
show_spam = False
show_reports = False

View File

@@ -114,7 +114,6 @@ class NestedListing(Listing):
def __init__(self, *a, **kw):
Listing.__init__(self, *a, **kw)
self.nested = kw.get('nested', True)
self.num = kw.get('num', g.num_comments)
self.parent_name = kw.get('parent_name')
@@ -122,7 +121,7 @@ class NestedListing(Listing):
##TODO use the local builder with the render cache. this may
##require separating the builder's get_items and tree-building
##functionality
wrapped_items = self.get_items(num = self.num, nested = True)
wrapped_items = self.get_items(num = self.num)
self.things = wrapped_items

View File

@@ -21,6 +21,7 @@
################################################################################
from r2.models import *
from r2.lib import promote
from r2.lib.utils import fetch_things2
import string
import random
@@ -64,3 +65,12 @@ def create_links(num):
if random.choice(([False] * 50) + [True]):
promote.promote(l)
def by_url_cache():
q = Link._query(Link.c._spam == (True,False),
data = True,
sort = desc('_date'))
for i, link in enumerate(fetch_things2(q)):
if i % 100 == 0:
print "%s..." % i
link.set_url_cache()

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View File

@@ -0,0 +1,4 @@
.toolbar .middle-side input[type=text] {
border: none;
height: 17px;
}

View File

@@ -1,3 +1,7 @@
html {
height: 100%; /* Needed for toolbar's comments panel's pinstripe */
}
body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,form,fieldset,input,p,blockquote,th,td,iframe {
margin:0;
padding:0;
@@ -19,8 +23,6 @@ body {
z-index: 1;
}
/*html,body { height: 100%; }*/
/* IE dumbness patch. hidden input in a hidden block that is
* subsequently shown leads to the input to "show" and generate undesired
* )padding. This makes it go away. */
@@ -725,6 +727,10 @@ a.star { text-decoration: none; color: #ff8b60 }
font-size: medium;
text-align: right;
}
.linkcompressed .arrow.down, .linkcompressed .arrow.downmod {
margin-top: 2px;
}
.linkcompressed .tagline { display: inline; margin-top: 0px; margin-bottom: 1px; }
.linkcompressed .flat-list { display: inline }
@@ -733,7 +739,7 @@ a.star { text-decoration: none; color: #ff8b60 }
.linkcompressed .entry .buttons li.first {padding-left: .5em;}
.linkcompressed .entry .buttons li a {
padding: 0 2px;
background-color: #f6f6f6;
background-color: #f7f7f7;
font-weight: bold
}
@@ -882,6 +888,20 @@ textarea.gray { color: gray; }
padding-left: 5px;
}
.starkcomment + .clearleft + .starkcomment {
margin-top: 10px
}
.starkcomment .commentbox {
color: black;
background-color: #f0f0f0;
padding: 5px;
margin-left: 10px;
margin-right: 5px;
}
.starkcomment .tagline {
text-align: right;
}
.fixedwidth { float: left; width: 100px; height: 0px; }
.clearleft { clear: left; height: 0px; }
.clear { clear: both; }
@@ -1246,7 +1266,9 @@ textarea.gray { color: gray; }
padding-right: 5px;
font-weight: bold;
}
.details td {
vertical-align: top;
}
.bottommenu { color: gray; font-size: smaller; clear: both}
.bottommenu a { color: gray; text-decoration: underline; }
@@ -1407,18 +1429,154 @@ textarea.gray { color: gray; }
font-size: larger;
}
/* the toolbar */
.toolbar { height: 30px; border-bottom: 1px solid black;}
.toolbar td { vertical-align: center; }
.toolbar td#frame-left > a,
.toolbar td#frame-left > form { margin-right: 20px; }
.toolbar td#frame-right { text-align: right; }
.toolbar td#frame-right > a,
.toolbar td#frame-right > form { margin: 0 5px; }
.toolbar .arrow {
background-position: center left;
padding-left: 18px;
display: inline;
.bookmarklet {
border: solid #888888 1px;
padding: 0px 2px;
}
.toolbar {
font-size: small;
border-bottom: 1px solid #336699;
background-color: #CEE3F8;
}
.toolbar .left-side {
height: 19px;
float: left;
border-right: solid #336699 1px;
background-image: url(/static/button-normal.png);
}
.toolbar .middle-side {
text-align: center;
background-image: url(/static/button-normal.png);
}
.toolbar .middle-side a, .toolbar .middle-side b {
display: block;
border-left: none;
}
.toolbar .middle-side input[type=text] {
font-size: 14px;
vertical-align: baseline;
width: 100%;
height: 18px;
border: none;
border-top: solid transparent 1px;
}
.toolbar .middle-side .url {
overflow: hidden;
}
.toolbar .right-side {
float: right;
background-image: url(/static/button-normal.png);
}
.toolbar a, .toolbar b {
font-weight: normal;
display: inline-block;
height: 18px;
border-left: solid #336699 1px;
white-space: nowrap;
padding: 1px 4px 0px;
overflow: hidden;
outline: none;
-moz-outline: none;
}
.toolbar a, .toolbar .clickable {
cursor: pointer;
color: #336699;
text-decoration: none !important;
}
.toolbar .clickable:active, .pushed-button {
background-image: url(/static/button-pressed.png) !important;
color: orangered !important;
}
.toolbar a img, toolbar b img {
vertical-align: middle;
padding-top: 3px;
}
.toolbar .content {
float: left;
vertical-align: middle;
}
.toolbar .logo {
margin: 0px;
padding: 0 2px;
border-left: none;
vertical-align: top;
}
.toolbar .title {
padding-left: 20px;
color: black;
font-style: italic;
}
.toolbar .controls {
float: right;
}
.toolbar .arrow {
display: inline-block;
width: auto;
margin: 0px;
background-position: left center;
padding-left: 18px;
}
.toolbar .arrow.upmod { background-image: url(/static/aminiupmod.gif); }
.toolbar .arrow.downmod { background-image: url(/static/aminidownmod.gif); }
.toolbar .arrow.up { background-image: url(/static/aminiupgray.gif); }
.toolbar .arrow.down { background-image: url(/static/aminidowngray.gif); }
.toolbar-status-bar {
border-top: solid #336699 1px;
border-bottom: solid #336699 1px;
background-color: #F6E69F;
padding: 0px 2px;
overflow: auto;
}
.toolbar-status-bar .login-arrow-left {
overflow: auto;
background-image: url(/static/tb-loginarrow-left.png);
background-position: top right;
}
.toolbar-status-bar .login-arrow-right {
float: right;
margin-right: 75px;
}
.toolbar-status-bar .login-message {
float: left;
background-color: #F6E69F;
padding-right: 3px;
}
.tb-comments-panel-toggle {
display: block;
font-size: larger;
margin: 15px 13px;
}
.min-body {
height: 100%;
}
.min-body .content {
margin-top: 0px;
border-left: solid #369 1px;
min-height: 100%;
max-width: 60em;
overflow: auto;
}
.min-body .content h1, .min-body .content h2 {
padding-left: 13px;
display: inline-block;
margin-bottom: 15px;
}
.min-body .content #noresults {
margin: 0 0 0 13px;
}
/* default form styles */

Binary file not shown.

After

Width:  |  Height:  |  Size: 504 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 357 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 722 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 906 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 7.9 KiB

View File

@@ -33,7 +33,16 @@ $.redirect = function(dest) {
$.fn.redirect = function(dest) {
/* for forms which are "posting" by ajax leading to a redirect */
$(this).filter("form").find(".status").show().html("redirecting...");
$.redirect(dest);
var target = $(this).attr('target');
if(target == "_top") {
var w = window;
while(w != w.parent) {
w = w.parent;
}
w.location = dest;
} else {
$.redirect(dest);
}
/* this should never happen, but for the sake of internal consistency */
return $(this)
}

View File

@@ -621,6 +621,118 @@ function register(elem) {
return post_user(this, "register");
};
var toolbar_p = function(expanded_size, collapsed_size) {
/* namespace for functions related to the reddit toolbar frame */
this.toggle_linktitle = function(s) {
$('.title, .submit, .url').toggle();
if($(s).is('.pushed-button')) {
$(s).parents('.middle-side').removeClass('clickable');
} else {
$(s).parents('.middle-side').addClass('clickable');
}
return this.toggle_pushed(s);
};
this.toggle_pushed = function(s) {
s = $(s);
if(s.is('.pushed-button')) {
s.removeClass('pushed-button').addClass('popped-button');
} else {
s.removeClass('popped-button').addClass('pushed-button');
}
return false;
};
this.push_button = function(s) {
$(s).removeClass("popped-button").addClass("pushed-button");
};
this.pop_button = function(s) {
$(s).removeClass("pushed-button").addClass("popped-button");
};
this.serendipity = function() {
this.push_button('.serendipity');
return true;
};
this.show_panel = function() {
parent.inner_toolbar.document.body.cols = expanded_size;
};
this.hide_panel = function() {
parent.inner_toolbar.document.body.cols = collapsed_size;
};
this.resize_toolbar = function() {
var height = $("body").height();
parent.document.body.rows = height + "px, 100%";
};
this.login_msg = function() {
$(".toolbar-status-bar").show();
$(".login-arrow").show();
this.resize_toolbar();
return false;
};
this.top_window = function() {
var w = window;
while(w != w.parent) {
w = w.parent;
}
return w.parent;
};
var pop_obj = null;
this.panel_loadurl = function(url) {
try {
var cur = window.parent.inner_toolbar.reddit_panel.location;
if (cur == url) {
return false;
} else {
if (pop_obj != null) {
this.pop_button(pop_obj);
pop_obj = null;
}
return true;
}
} catch (e) {
return true;
}
};
var comments_on = 0;
this.comments_pushed = function(ctl) {
comments_on = ! comments_on;
if (comments_on) {
this.push_button(ctl);
this.show_panel();
} else {
this.pop_button(ctl);
this.hide_panel();
}
};
this.gourl = function(form, base_url) {
var url = $(form).find('input[type=text]').attr('value');
var newurl = base_url + escape(url);
this.top_window().location.href = newurl;
return false;
};
this.pref_commentspanel_hide = function() {
$.request('tb_commentspanel_hide');
};
this.pref_commentspanel_show = function() {
$.request('tb_commentspanel_show');
};
};
/* The ready method */
$(function() {
/* set function to be called on thing creation/replacement,

Binary file not shown.

After

Width:  |  Height:  |  Size: 198 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 582 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 168 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 B

View File

@@ -24,37 +24,37 @@
<div class="instructions">
<script type="text/javascript">
function dragme() {window.alert("drag this link to your toolbar")};function favme() {window.alert('right-click this link and choose "Add to Favorites"')}
function dragme() {window.alert("drag this link to your bookmark bar")};function favme() {window.alert('right-click this link and choose "Add to Favorites"')}
</script>
<h1>
${_("install the %(site)s bookmarklet set") % dict(site=c.site.name)}
</h1>
<p>${_("once added to your toolbar, these buttons will let you \"reddit this\" (submit the link, or if it's already been submitted, share it and/or comment on it), like, dislike, and save links while you surf.")}</p>
<p>${_("once added to your bookmark bar, you can click these buttons from any site to get quick access to reddit functionality.")}</p>
<h2>${_("in Firefox")}</h2>
<p>
Try out our new firefox add-on, &#32;<a href="/socialite">Socialite</a>.
</p>
<p>
or ${_("click and drag")}&nbsp;
${_("click and drag")}&nbsp;
%for type in thing.buttons:
<a style="padding: 0 3px 0 3px" href="${dockletStr(type, 'firefox')}" onclick="dragme(); return false">
<img alt="${type}" src="/static/${type}_firefox.png" />
<span class="bookmarklet">${type}</span>&nbsp;
</a>
%endfor
${_("to your toolbar.")}
${_("to your bookmark bar.")}
</p>
<p>
<img border="0" src="/static/firefox.png" alt="firefox screenshot" />
</p>
<p>
See also our Firefox add-on, &#32;<a href="/socialite">Socialite</a>.
</p>
<h2>${_("in Internet Explorer")}</h2>
<p>
${_("right-click on")}&nbsp;
%for type in thing.buttons:
<a style="padding: 0 3px 0 3px" href="${dockletStr(type, 'ie')|}" onclick="favme(); return false">
<img alt="${type}" src="/static/${type}_ie.png" />
<span class="bookmarklet">${type}</span>&nbsp;
</a>
%endfor
${_('choose "Add to Favorites" and add to the "Links" folder.')}
${_('then choose "Add to Favorites" and add to the "Links" folder.')}
</p>
<p>
<img border="0" src="/static/ie.png" alt="ie screenshot" />
@@ -64,10 +64,10 @@
${_("click and drag")}&nbsp;
%for type in thing.buttons:
<a style="padding: 0 3px 0 3px" href="${dockletStr(type, 'safari')}" onclick="dragme(); return false">
<img alt="${type}" src="/static/${type}_safari.png" />
<span class="bookmarklet">${type}</span>&nbsp;
</a>
%endfor
${_("to your toolbar.")}
${_("to your bookmark bar.")}
</p>
<p>
<img border="0" src="/static/safari.png" alt="safari screenshot"/>

View File

@@ -52,7 +52,7 @@ ${class_def(1, width=choose_width(thing.link, thing.width))}
%if thing.vote:
${arrow(thing.link, 1, thing.likes)}
${arrow(thing.link, 0, thing.likes == False)}
${score(thing.link, thing.likes, inline=False)}
${score(thing.link, thing.likes, tag='div')}
%else:
${thing.link.score}
%endif
@@ -68,7 +68,7 @@ ${class_def(1, width=choose_width(thing.link, thing.width))}
%if thing.link:
%if thing.vote:
${arrow(thing.link, 1, thing.likes)}
${score(thing.link, thing.likes, inline=False)}
${score(thing.link, thing.likes, tag='div')}
${arrow(thing.link, 0, thing.likes == False)}
%else:
&nbsp;<br />
@@ -96,7 +96,7 @@ ${class_def(3)}
%if thing.link:
%if thing.vote:
${arrow(thing.link, 1, thing.likes)}
${score(thing.link, thing.likes, inline=False)}
${score(thing.link, thing.likes, tag='div')}
${arrow(thing.link, 0, thing.likes == False)}
%else:
&nbsp;<br />
@@ -121,7 +121,7 @@ ${class_def(3)}
%if thing.link:
%if thing.vote:
${arrow(thing.link, 1, thing.likes)}
${score(thing.link, thing.likes, inline=False)}
${score(thing.link, thing.likes, tag='div')}
${arrow(thing.link, 0, thing.likes == False)}
%else:
&nbsp;<br />

View File

@@ -54,7 +54,7 @@ ${parent.midcol(not thing.collapsed)}
${parent.collapsed()}
</%def>
<%def name="tagline(collapse=False)">
<%def name="tagline(collapse=False,showexpandcollapse=True)">
<%
if c.user_is_admin:
show = True
@@ -76,24 +76,25 @@ ${parent.collapsed()}
%if show:
${unsafe(self.score(thing, likes = thing.likes))}&#32;
%endif
${thing.timesince} ${_("ago")}
${_("%(timeago)s ago") % dict(timeago=thing.timesince)}
%if thing.editted:
<em>*</em>&nbsp;
%endif
%endif
<a href="#" class="expand"
%if collapse:
onclick="return showcomment(this)">
%else:
onclick="return hidecomment(this)">
%endif
[${_("+") if collapse else _("-")}]
%if collapse:
(${thing.num_children}
${ungettext("child", "children", thing.num_children)})
%if showexpandcollapse:
<a href="#" class="expand"
%if collapse:
onclick="return showcomment(this)">
%else:
onclick="return hidecomment(this)">
%endif
[${_("+") if collapse else _("-")}]
%if collapse:
(${thing.num_children}
${ungettext("child", "children", thing.num_children)})
%endif
</a>
%endif
</a>
</%def>
<%def name="Child()">
@@ -102,7 +103,8 @@ ${parent.Child(not thing.collapsed)}
<%def name="commentBody()">
%if c.user_is_admin or not thing.deleted:
${unsafe(safemarkdown(thing.body, thing.nofollow))}
${unsafe(safemarkdown(thing.body, nofollow=thing.nofollow,
target=thing.target))}
%else:
<div class="gray md">
${_("[deleted]")}

View File

@@ -0,0 +1,46 @@
## The contents of this file are subject to the Common Public Attribution
## License Version 1.0. (the "License"); you may not use this file except in
## compliance with the License. You may obtain a copy of the License at
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
## software over a computer network and provide for limited attribution for the
## Original Developer. In addition, Exhibit A has been modified to be consistent
## with Exhibit B.
##
## Software distributed under the License is distributed on an "AS IS" basis,
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
## the specific language governing rights and limitations under the License.
##
## The Original Code is Reddit.
##
## The Original Developer is the Initial Developer. The Initial Developer of
## the Original Code is CondeNet, Inc.
##
## All portions of the code written by CondeNet are Copyright (c) 2006-2009
## CondeNet, Inc. All Rights Reserved.
################################################################################
<%namespace file="printable.html" import="toggle_button"/>
<script type="text/javascript">
toolbar = new toolbar_p();
</script>
<h1>
${_('top comments')}
</h1>
<h2>
<a target="_top" href="${thing.link.permalink}">
${_("full discussion")}
</a>
</h2>
${thing.listing.render()}
${toggle_button("tb-comments-panel-toggle",
_("hide this panel by default"),
_("show this panel " +
"when there are comments"),
"toolbar.pref_commentspanel_hide",
"toolbar.pref_commentspanel_show",
reverse = not c.user.pref_frame_commentspanel)}

View File

@@ -21,6 +21,8 @@
################################################################################
<%
from r2.lib.template_helpers import add_sr
from r2.lib.utils import query_string
from r2.lib.filters import _force_unicode
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/html4/frameset.dtd">
@@ -28,8 +30,36 @@
<head>
<title>${thing.title}</title>
</head>
<frameset framespacing="0" rows="30px, 100%">
<frame frameborder="0" scrolling="no" src="${add_sr('/toolbar?id=' + thing.fullname)}"/>
<frame frameborder="0" src="${thing.url}"/>
<frameset framespacing="0" frameborder="0" border="0" rows="20px, 100%">
%if thing.fullname:
<frame frameborder="0" border="0" scrolling="no" name="reddit_top"
noresize="1" src="${add_sr('/toolbar/toolbar?id=' + thing.fullname)}"
/>
<frame frameborder="0" border="0"
src="${add_sr('/toolbar/inner?id='+thing.fullname)}" name="inner_toolbar" />
%else:
<frame frameborder="0" border="0" scrolling="no" name="reddit_top"
src="${add_sr('/toolbar/toolbar' +
query_string(dict(url = thing.url,
title = _force_unicode(thing.title))))}"
/>
<frame frameborder="0" border="0"
src="${thing.url}" name="inner_toolbar" />
%endif
</frameset>
<!-- Internet Explorer has a "feature" called "friendly error
messages" that defaults to being turned on, where it detects
certain remote error conditions (among them, 404s) such that
the response (presumably an error descriptor page) is less
than some size (512 bytes for 404s). If that happens, it
replaces the remote error message with a more "friendly"
description of the error, which obscures the server's error
message. Historically, this is because Apache's and IIS's
error messages are famously non-helpful, and were less than
that minimum size. This unnecessarily verbose comment serves
only to cause this page (whose status code may be a 404, set
in toolbar.py:GET_s) to go over that minimum size, so that we
can force our content to be shown to IE users with "friendly
error messages", even on braindead browsers. -->
</html>

View File

@@ -20,118 +20,164 @@
## CondeNet, Inc. All Rights Reserved.
################################################################################
<%!
from r2.lib.template_helpers import static, get_domain
from r2.lib.template_helpers import static, get_domain, add_sr, panel_size
from r2.lib.strings import Score
%>
<%inherit file="reddit.html"/>
<%namespace file="utils.html" import="plain_link, logout"/>
<%namespace file="printable.html" import="state_button, comment_button, thing_css_class" />
<%namespace file="printable.html" import="state_button, comment_button, thing_css_class, score" />
<%def name="javascript_run()">
${parent.javascript_run()}
toolbar = new toolbar_p("${panel_size('expanded')}", "${panel_size('collapsed')}");
</%def>
<%def name="bodyHTML()">
<body>
<% fullname = thing.link._fullname %>
<% upstyle = "mod" if thing.link.likes else "" %>
<% downstyle = "mod" if thing.link.likes is False else "" %>
<table class="${thing_css_class(thing.link)} toolbar" width="100%">
<script type="text/javascript">
function kill(uh) {
$("#main").hide();
$("#killed").show();
$.request('noframe');
}
function unkill() {
$("#killed").hide();
$("#main").show();
$.request('frame');
}
</script>
<tr id="killed" style="display: none" class="menu">
<td nowrap="nowrap">
after reloading, this frame will not be shown again. click
&#32;<a href="javascript:unkill()"> here</a>&#32;to undo.</td>
<td width="100%" />
</tr>
<tr id="main">
<td id="frame-left">
<a target="_top" href="http://${get_domain(cname = c.cname)}/">
<img style="border: none" src="${static('littlehead.png')}"
alt="reddit.com" title="reddit.com" />
</a>
<a id="up_${fullname}" class="arrow up${upstyle}"
%if c.user_is_loggedin:
href="javascript:void(0);"
onclick="$(this).vote()"
%else:
href="/login"
target="_top"
%endif
>
${_("like")}
</a>
<a id="down_${fullname}" class="arrow down${downstyle}"
%if c.user_is_loggedin:
href="javascript:void(0);"
onclick="$(this).vote()"
%else:
href="/login"
target="_top"
%endif
>
${_("dislike")}
</a>
%if c.user_is_loggedin:
%if thing.link.saved:
${state_button("unsave", _("unsave"),
"return change_state(this, 'unsave');", _("unsaved"))}
%else:
${state_button("save", _("save"),
"return change_state(this, 'save');", _("saved"))}
%endif
%endif
<%
if not thing.link.num_comments:
# generates "comment" the imperative verb
com_label = _("comment {verb}")
else:
# generates "XX comments" as a noun
com_label = ungettext("comment", "comments", thing.link.num_comments)
%>
<span>
${comment_button("comment", com_label,
thing.link.num_comments,
thing.link.permalink)}
</span>
</td>
<td id="frame-middle" nowrap="nowrap" style="display: none">
</td>
<td id="frame-right" class="menu" nowrap="nowrap">
%if c.user_is_loggedin:
<a href="http://${get_domain(cname = c.cname)}/user/${c.user.name}"
target="_parent">${c.user.name}</a> (${c.user.safe_karma})
${logout()}
%else:
<a href="/login">${_("login")}</a>
<a href="/login">${_("register")}</a>
<body class="toolbar">
<div class="left-side">
<a class="logo" target="_top" href="http://${get_domain(cname = c.cname)}/">
<img src="${static('logo-toolbar.png')}" alt="${c.site.description or c.site.name}"
title="${c.site.description or c.site.name}"/>
%if thing.dorks:
<img src="${static('dorks-toolbar.png')}"
title="${_('caution: dorkbar detected')}"/>
%endif
<a target="_top" href="/help/">
<img style="border: none" src="${static('help.png')}"
alt="help" title="help" />
</a>&nbsp;
<a target="_top" href="${thing.link.url}">
<img style="border: none"
src="${static('breakout.png')}"
alt="open without frame" title="open without frame" />
</a>&nbsp;
<a href="javascript:kill()">
<img style="cursor: pointer"
src="${static('kill.png')}"
alt="permanently close this frame"
title="permanently close this frame" />
</a>
</td>
</tr>
</table>
</a>
%if thing.link:
${withlink()}
%endif
</div>
<div class="right-side">
<a href="#" onclick="return toolbar.toggle_linktitle(this);">
<img src="${static('link.png')}" height="13" width="16"
title="${_('show url')}" alt="${_('show url')}"/>
</a>
<a class="serendipity popped-button"
title="${_('load a random link')}"
onmousedown="toolbar.push_button(this)"
onmouseup="toolbar.pop_button(this)"
onclick="toolbar.serendipity()"
href="${add_sr('/random')}"
target="_top" />
%if c.default_sr:
${_("serendipity")}
%else:
${"%(subreddit)s serendipity" % dict (subreddit=c.site.name)}
%endif
</a>
%if c.user_is_loggedin:
<a href="http://${get_domain(cname = c.cname)}/user/${c.user.name}"
title="${_('visit your userpage')}"
class="clickable" target="_top">${c.user.name}</a>
${logout(top=True,dest=thing.tblink,a_class="clickable")}
%elif thing.link:
<a href="${thing.loginurl}" target="_top" class="clickable">
${_("login / register")}
</a>
%endif
<a target="_top" href="/help/toolbar">
<img src="${static('help.png')}"
height="11" width="11"
alt="${_('help')}" title="${_('help')}" />
</a>
<a href="${thing.url}" target="_top">
<img src="${static('kill.png')}"
height="11" width="11"
alt="${_('turn off the toolbar')}"
title="${_('turn off the toolbar')}" />
</a>
</div>
<div class="middle-side clickable">
%if thing.link:
<a
title="${_('click to visit the main page for this submission')}"
class="title clickable"
target="_top"
href="${thing.link.make_permalink_slow()}">
${thing.link.title}
</a>
%else:
${plain_link(_('click to submit this link to reddit'), thing.submit_url,
target="_top", _class="submit")}
%endif
<div class="url" style="display: none;">
<form onsubmit="return toolbar.gourl(this, '${add_sr('/s/')}')">
<input type="text" value="${thing.url}" />
</form>
</div>
</div>
<div class="toolbar-status-bar" style="display: none;">
<div class="login-arrow" style="display: none;">
<img src="${static('tb-loginarrow-right.png')}" class="login-arrow-right"/>
<div class="login-arrow-left">
<p class="login-message">
${_("you'll need to login or register to do that")}
</p>
</div>
</div>
</body>
</%def>
<%def name="withlink()">
<span class="${thing_css_class(thing.link)}">
<span>
${score(thing.link, thing.link.likes, score_fmt = Score.safepoints, tag='b')}
</span>
<span class="arrows">
<%def name="arrow(direction, style, message)">
<a class="arrow ${direction + style}"
title="${_('vote %(direction)s') % dict(direction=direction)}"
%if c.user_is_loggedin:
href="javascript:void(0);"
onclick="$(this).vote('${thing.vh}')"
%else:
href="${thing.loginurl}"
target="_top"
onclick="return toolbar.login_msg()"
%endif
>
${message}
</a>
</%def>
${arrow("up", thing.upstyle, _("like"))}
${arrow("down", thing.downstyle, _("dislike"))}
</span>
%if c.user_is_loggedin:
%if thing.link.saved:
${state_button("unsave", _("unsave"),
"return change_state(this, 'unsave');", "<b>%s</b>" % _("unsaved"),
a_class="clickable")}
%else:
${state_button("save", _("save"),
"return change_state(this, 'save');", "<b>%s</b>" % _("saved"),
a_class="clickable")}
%endif
%endif
<a href="/toolbar/comments/${thing.link._id36}" target="reddit_panel"
title="${_('toggle the comments panel')}"
onclick="toolbar.comments_pushed(this); return toolbar.panel_loadurl(this.href);"
class="comments comments-button">${thing.com_label}</a>
</span>
%if thing.link and thing.expanded:
<script type="text/javascript">
$(function() {
toolbar.comments_pushed($('.comments-button'));
});
</script>
%endif
</%def>

View File

@@ -0,0 +1,30 @@
## The contents of this file are subject to the Common Public Attribution
## License Version 1.0. (the "License"); you may not use this file except in
## compliance with the License. You may obtain a copy of the License at
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
## software over a computer network and provide for limited attribution for the
## Original Developer. In addition, Exhibit A has been modified to be consistent
## with Exhibit B.
##
## Software distributed under the License is distributed on an "AS IS" basis,
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
## the specific language governing rights and limitations under the License.
##
## The Original Code is Reddit.
##
## The Original Developer is the Initial Developer. The Initial Developer of
## the Original Code is CondeNet, Inc.
##
## All portions of the code written by CondeNet are Copyright (c) 2006-2009
## CondeNet, Inc. All Rights Reserved.
################################################################################
<%!
from r2.lib.template_helpers import add_sr, panel_size
%>
<html>
<frameset cols="${panel_size('expanded' if thing.expanded else 'collapsed')}" name="inner_toolbar">
<frame frameborder="0" src="${thing.link.url}" name="reddit_link" />
<frame frameborder="0" src="${add_sr('/toolbar/comments/'+thing.link._id36)}" name="reddit_panel" />
</frameset>
</html>

View File

@@ -43,19 +43,13 @@
</%def>
<%def name="make_link(name, css_class)">
<a class="${css_class} ${ c.user_is_loggedin and 'loggedin' or ''} ${thing.clicked and 'click' or ''}"
%if c.user.pref_frame:
href="http://${get_domain(cname = c.cname, subreddit = False)}/goto?id=${thing._id36}"
%elif thing.is_self:
href="${thing.permalink}"
%else:
href="${thing.url}"
%endif
<a class="${css_class} ${ c.user_is_loggedin and 'loggedin' or ''} ${thing.clicked and 'click' or ''}"
href="${thing.click_url}"
%if thing.nofollow:
rel="nofollow"
%endif
%if c.user.pref_newwindow:
target="_blank"
target="_blank"
%elif c.cname:
target="_top"
%endif
@@ -96,7 +90,7 @@
%if thing.hide_score:
<div class="score">&bull;</div>
%else:
${self.score(thing, thing.likes, inline=False)}
${self.score(thing, thing.likes, tag='div')}
%endif
${self.arrow(thing, 0, thing.likes == False)}
</div>

View File

@@ -23,6 +23,8 @@
<div class="raisedbox linkinfo ${thing_css_class(thing.a)}">
<table class="details">
<tr><th>${_("toolbar link")}</th>
<td><a href="${thing.a.tblink}">${thing.a.tblink}</a></td></tr>
<tr><th>${_("submitted on")}</th>
<td>${thing.a._date.strftime(thing.datefmt)}</td></tr>
<tr><th>${ungettext('point', 'points', 5)}</th>

View File

@@ -22,6 +22,7 @@
<%!
from r2.lib.strings import strings
from r2.lib.template_helpers import add_sr
%>
<%namespace file="utils.html" import="error_field, submit_form, plain_link, text_with_links"/>
@@ -31,11 +32,12 @@
<h1>${_("submit to %(site)s") % dict(site=c.site.name)}</h1>
%endif
<%call expr="submit_form(onsubmit='return post_form(this, \'submit\', linkstatus, null, true)',
action='/submit', _class='long-text content', _id='newlink')">
<%call expr="submit_form(onsubmit='return post_form(this, \'submit\', linkstatus, null, true)',
action=add_sr('/submit'), _class='long-text content', _id='newlink')">
%if not thing.subreddits:
<input type="hidden" name="sr" value="${c.site.name}" />
%endif
<input type="hidden" name="then" value="${thing.then}" />
<table>
<tr>
<th>

View File

@@ -54,11 +54,12 @@ thing id-${what._fullname}
<%def name="RenderPrintable()">
<% cls = thing.lookups[0].__class__.__name__.lower() %>
<%
if hasattr(thing, 'render_class'):
cls = thing.render_class
if hasattr(thing, 'render_css_class'):
cls = thing.render_css_class
elif hasattr(thing, 'render_class'):
cls = thing.render_class.__name__.lower()
else:
cls = thing.lookups[0].__class__
cls = cls.__name__.lower()
cls = thing.lookups[0].__class__.__name__.lower()
if thing.show_spam:
rowclass = thing.rowstyle + " spam"
@@ -145,6 +146,11 @@ thing id-${what._fullname}
%if thing.deleted and not c.user_is_admin:
[deleted]
%else:
<%
target = None
if hasattr(thing, "target"):
target = thing.target
%>
%if thing.author._deleted:
<span>[deleted]</span>
%else:
@@ -155,11 +161,12 @@ thing id-${what._fullname}
author_cls += " friend"
elif gray:
author_cls += " gray"
name = websafe(author.name)
href = unsafe('href="%s"' % add_sr("/user/%s/" % name, sr_path = False))
if c.user_is_admin: name += " (%d)" % (author.link_karma)
disp_name = websafe(author.name)
if c.user_is_admin:
disp_name += " (%d)" % (author.link_karma)
%>
<a class="${author_cls}" ${href}>${name}</a>
${plain_link(disp_name, '/user/%s' % websafe(author.name),
_class = author_cls, _sr_path = False, target=target)}
%endif
%endif
%if c.user_is_admin and hasattr(thing, 'ip') and thing.ip:
@@ -184,25 +191,26 @@ thing id-${what._fullname}
</div>
</%def>
<%def name="score(this, likes=None, inline=True)">
<%def name="score(this, likes=None, tag='span', score_fmt = None)">
<%
tag = "span" if inline else "div"
_class = "" if likes is None else "likes" if likes else "dislikes"
# figure out alterna-points
score = this.score
base_score = score - 1 if likes else score if likes is None else score + 1
base_score = [base_score + x for x in range(-1, 2)];
if score_fmt is None:
score_fmt = thing.score_fmt
%>
<${tag} class="score ${_class}">
${thing.score_fmt(this.score)}
${score_fmt(this.score)}
</${tag}>
<script type="text/javascript">
if(reddit)
reddit.vl['${this._fullname}'] = ['${thing.score_fmt(base_score[0])}',
'${thing.score_fmt(base_score[1])}',
'${thing.score_fmt(base_score[2])}' ];
reddit.vl['${this._fullname}'] = ['${score_fmt(base_score[0])}',
'${score_fmt(base_score[1])}',
'${score_fmt(base_score[2])}' ];
</script>
</%def>

View File

@@ -73,6 +73,16 @@
<link rel="alternate" type="application/rss+xml" title="RSS"
href="${add_sr(join_urls(request.path,'.rss'))}" />
%endif
<!--[if lt IE 7]>
<link rel="stylesheet" href="${static('reddit-ie6-hax.css')}""
type="text/css" />
<![endif]-->
<!--[if lt IE 8]>
<link rel="stylesheet" href="${static('reddit-ie7-hax.css')}""
type="text/css" />
<![endif]-->
</%def>
<%def name="javascript()">
@@ -81,10 +91,6 @@
<script src="${static('jquery.json.js')}" type="text/javascript"></script>
<script src="${static('jquery.reddit.js')}" type="text/javascript"></script>
<script src="${static('reddit.js')}" type="text/javascript"></script>
<!--[if lt IE 7]>
<link rel="stylesheet" href="${static('reddit-ie6-hax.css')}""
type="text/css" />
<![endif]-->
</%def>
<%def name="javascript_run()">
@@ -110,7 +116,10 @@
</div>
%endif
<%include file="redditfooter.html"/>
%if thing.footer:
<%include file="redditfooter.html"/>
%endif
${framebuster()}
</body>

View File

@@ -72,12 +72,14 @@
mail_img ="mail"
if c.have_messages:
mail_img += ".png"
mail_img_class = 'havemail'
else:
mail_img += "gray.png"
mail_img_class = 'nohavemail'
mail_img = static(mail_img)
%>
${img_link(_("messages"), mail_img, path="/message/inbox/",
_id = "mail" )}
_id = "mail", _class=mail_img_class)}
${separator("|")}
%endif

View File

@@ -0,0 +1,32 @@
## The contents of this file are subject to the Common Public Attribution
## License Version 1.0. (the "License"); you may not use this file except in
## compliance with the License. You may obtain a copy of the License at
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
## software over a computer network and provide for limited attribution for the
## Original Developer. In addition, Exhibit A has been modified to be consistent
## with Exhibit B.
##
## Software distributed under the License is distributed on an "AS IS" basis,
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
## the specific language governing rights and limitations under the License.
##
## The Original Code is Reddit.
##
## The Original Developer is the Initial Developer. The Initial Developer of
## the Original Code is CondeNet, Inc.
##
## All portions of the code written by CondeNet are Copyright (c) 2006-2009
## CondeNet, Inc. All Rights Reserved.
############
<%inherit file="reddit.html"/>
<%def name="bodyHTML()">
<body onclick="close_menus()" class="min-body">
%if thing.content:
<div class="content">
${thing.content().render()}
</div>
%endif
</body>
</%def>

View File

@@ -0,0 +1,44 @@
## The contents of this file are subject to the Common Public Attribution
## License Version 1.0. (the "License"); you may not use this file except in
## compliance with the License. You may obtain a copy of the License at
## http://code.reddit.com/LICENSE. The License is based on the Mozilla Public
## License Version 1.1, but Sections 14 and 15 have been added to cover use of
## software over a computer network and provide for limited attribution for the
## Original Developer. In addition, Exhibit A has been modified to be consistent
## with Exhibit B.
##
## Software distributed under the License is distributed on an "AS IS" basis,
## WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
## the specific language governing rights and limitations under the License.
##
## The Original Code is Reddit.
##
## The Original Developer is the Initial Developer. The Initial Developer of
## the Original Code is CondeNet, Inc.
##
## All portions of the code written by CondeNet are Copyright (c) 2006-2009
## CondeNet, Inc. All Rights Reserved.
################################################################################
<%inherit file="comment.html"/>
<%def name="entry()">
<div class="commentbox">
<span class="commentbody">
${self.commentBody()}
</span>
<p class="tagline">
${self.tagline()}
<a target="_top" href="${thing.permalink}">
&#32;
${_("context")}
</a>
</p>
</div>
</%def>
<%def name="tagline(**kw)">
${parent.tagline(collapse=False,showexpandcollapse=False,**kw)}
</%def>
<%def name="arrow(*a, **kw)">
</%def>

View File

@@ -52,7 +52,11 @@ id="${arg}_${thing and thing._fullname or ''}"
<%def name="submit_form(onsubmit='', action='', _class='', method='post', _id='', **params)">
<form class="pretty-form ${_class or ''}" onsubmit="${onsubmit or ''}"
action="${action or ''}" ${_id and "id='" + _id + "'" or ""} method="${method}">
action="${action or ''}" ${_id and "id='" + _id + "'" or ""} method="${method}"
%if c.cname:
target="_top"
%endif
>
%if c.user_is_loggedin:
<input type="hidden" name="uh" value="${c.user.modhash()}" />
%endif
@@ -367,10 +371,23 @@ ${unsafe(txt)}
};
</%def>
<%def name="logout()">
<form method="post" action="/logout" class="logout hover">
<%def name="logout(top=False,dest=None,a_class='')">
<form method="post" action="/logout" class="logout hover"
%if top:
target="_top"
%endif
>
<input type="hidden" name="uh" value="${c.modhash}"/>
<a href="javascript:void(0)" onclick="$(this).parent().submit()">
<input type="hidden" name="top" value="${'on' if top else 'off'}"/>
%if dest:
<input type="hidden" name="dest" value="${dest}"/>
%endif
<a href="javascript:void(0)" onclick="$(this).parent().submit()"
%if a_class:
class="${a_class}"
%endif
>
${_("logout")}
</a>
</form>