Replaced the subreddit box on the side with a bar across the top that lists reddits.

Removed all subreddit-subscribe checkboxes.

Limited the number of reddits that can make up a frontpag (to 25 for now).

Removed links to /reddit/mine and instead show a user's subscriptions in a sidebox on /reddits.
This commit is contained in:
spez
2008-11-07 10:31:25 -08:00
parent 4b2a9d9132
commit 5448f36c31
38 changed files with 470 additions and 212 deletions

View File

@@ -51,7 +51,7 @@ def make_map(global_conf={}, app_conf={}):
mc('/reddits/:where', controller='reddits', action='listing',
where = 'popular',
requirements=dict(where="popular|new|banned"))
mc('/reddits/mine/:where', controller='myreddits', action='listing',
where='subscriber',
requirements=dict(where='subscriber|contributor|moderator'))

View File

@@ -28,12 +28,13 @@ from listingcontroller import BrowseController
from listingcontroller import RecommendedController
from listingcontroller import MessageController
from listingcontroller import RedditsController
from listingcontroller import MyredditsController
from listingcontroller import ByIDController as ByidController
from listingcontroller import RandomrisingController
from listingcontroller import UserController
from listingcontroller import CommentsController
from listingcontroller import MyredditsController
from feedback import FeedbackController
from front import FrontController
from buttons import ButtonsController

View File

@@ -102,21 +102,6 @@ class ApiController(RedditController):
content = listing).render()
return res
@Json
@validate(dest = nop('dest'))
def POST_subscriptions(self, res, dest):
"""Updates a user's subscriptions after fiddling with them in the sr
sidebar"""
subs = {}
for k, v in request.post.iteritems():
if k.startswith('sr_sel_chx_'):
subs[k[11:]] = (v == 'on')
for sr in Subreddit._by_fullname(subs.keys(), data = True,
return_dict = False):
self._subscribe(sr, subs[sr._fullname])
res._redirect(dest)
@Json
@validate(VCaptcha(),
name=VRequired('name', errors.NO_NAME),
@@ -406,12 +391,11 @@ class ApiController(RedditController):
self._login(res, user, dest, rem)
@Json
@validate(VUser(),
VModhash(),
container = VByName('id'),
type = VOneOf('location', ('moderator', 'contributor')))
@Json
def POST_leave(self, res, container, type):
if container and c.user:
res._hide("pre_" + container._fullname)

View File

@@ -238,7 +238,6 @@ class HotController(FixListing, ListingController):
def title(self):
return c.site.title
@validate(VSrMask('srs'))
def GET_listing(self, **env):
self.infotext = request.get.get('deleted') and strings.user_deleted
return ListingController.GET_listing(self, **env)
@@ -262,7 +261,6 @@ class ToplinksController(ListingController):
def query(self):
return c.site.get_links('toplinks', 'all')
@validate(VSrMask('srs'))
def GET_listing(self, **env):
return ListingController.GET_listing(self, **env)
@@ -280,8 +278,7 @@ class NewController(ListingController):
else:
return c.site.get_links('new', 'all')
@validate(VSrMask('srs'),
sort = VMenu('controller', NewMenu))
@validate(sort = VMenu('controller', NewMenu))
def GET_listing(self, sort, **env):
self.sort = sort
return ListingController.GET_listing(self, **env)
@@ -297,8 +294,7 @@ class BrowseController(ListingController):
return c.site.get_links(self.sort, self.time)
# TODO: this is a hack with sort.
@validate(VSrMask('srs'),
sort = VOneOf('sort', ('top', 'controversial')),
@validate(sort = VOneOf('sort', ('top', 'controversial')),
time = VMenu('where', ControversyTimeMenu))
def GET_listing(self, sort, time, **env):
self.sort = sort

View File

@@ -347,6 +347,14 @@ def set_colors():
if color_rx.match(request.get.get('bordercolor') or ''):
c.bordercolor = request.get.get('bordercolor')
def set_recent_reddits():
names = read_user_cookie('recent_reddits')
c.recent_reddits = []
if names:
names = filter(None, names.split(','))
c.recent_reddits = Subreddit._by_fullname(names, data = True,
return_dict = False)
def ratelimit_agents():
user_agent = request.user_agent
for s in g.agents:
@@ -484,6 +492,7 @@ class RedditController(BaseController):
set_iface_lang()
set_content_lang()
set_colors()
set_recent_reddits()
# set some environmental variables in case we hit an abort
if not isinstance(c.site, FakeSubreddit):

View File

@@ -115,18 +115,6 @@ class VRequired(Validator):
else:
return item
class VSrMask(Validator):
def run(self, masks):
# only work for main reddit
if c.site == Default and masks:
mask_sr = MaskedSR()
masks = [m.split(":")[:2] for m in masks.split(',')]
masks = dict((k, int(v)) for k, v in masks)
mask_sr.set_mask(masks)
c.site = mask_sr
c.subreddit_sidebox = True
c.subreddit_checkboxes = True
class VLink(Validator):
def __init__(self, param, redirect = True, *a, **kw):
Validator.__init__(self, param, *a, **kw)

View File

@@ -115,6 +115,7 @@ menu = MenuHandler(hot = _('hot'),
details = _("details"),
# reddits
home = _("home"),
about = _("about"),
edit = _("edit"),
banned = _("banned"),
@@ -177,6 +178,7 @@ def menu_style(type):
d = dict(heavydrop = ('dropdown', 'heavydrop'),
lightdrop = ('dropdown', 'lightdrop'),
tabdrop = ('dropdown', 'tabdrop'),
srdrop = ('dropdown', 'srdrop'),
flatlist = ('flatlist', ''),
tabmenu = ('tabmenu', ''),
)
@@ -191,11 +193,14 @@ class NavMenu(Styled):
can be used to set individualized CSS."""
def __init__(self, options, default = None, title = '', type = "dropdown",
base_path = '', **kw):
base_path = '', separator = '|', **kw):
self.options = options
self.base_path = base_path
kw['style'], kw['css_class'] = menu_style(type)
#used by flatlist to delimit menu items
self.separator = separator
# since the menu contains the path info, it's buttons need a
# configuration pass to get them pointing to the proper urls
for opt in self.options:
@@ -204,32 +209,23 @@ class NavMenu(Styled):
# selected holds the currently selected button defined as the
# one whose path most specifically matches the current URL
# (possibly None)
self.selected = None
self.default = default
self.selected = self.find_selected()
Styled.__init__(self, title = title, **kw)
def find_selected(self):
maybe_selected = [o for o in self.options if o.is_selected()]
if maybe_selected:
# pick the button with the most restrictive pathing
maybe_selected.sort(lambda x, y:
len(y.bare_path) - len(x.bare_path))
self.selected = maybe_selected[0]
elif default:
return maybe_selected[0]
elif self.default:
#lookup the menu with the 'dest' that matches 'default'
for opt in self.options:
if opt.dest == default:
self.selected = opt
break
Styled.__init__(self, title = title, **kw)
# def render(self, **kw):
# prefix = unicode((c.lang, kw.get('style'), self.base_path, c.site.name,
# self.selected and self.selected.title)).encode('utf8')
# key = unicode([(opt.title, opt.path) for opt in self]).encode('utf8')
# r = cache.get(prefix + key)
# if not r:
# r = Styled.render(self, **kw)
# cache.set(prefix + key, r, g.page_cache_time)
# return r
if opt.dest == self.default:
return opt
def __repr__(self):
return "<NavMenu>"
@@ -295,6 +291,17 @@ class NavButton(Styled):
when it is different from self.title)"""
return self.title
class SubredditButton(NavButton):
def __init__(self, sr):
self.sr = sr
NavButton.__init__(self, sr.name, sr.path, False)
def build(self, base_path = ''):
self.path = self.sr.path
def is_selected(self):
return c.site == self.sr
class NamedButton(NavButton):
"""Convenience class for handling the majority of NavButtons
@@ -499,6 +506,11 @@ class NumCommentsMenu(SimpleGetMenu):
return ""
return SimpleGetMenu.render(self, **kw)
class SubredditMenu(NavMenu):
def find_selected(self):
"""Always return False so the title is always displayed"""
return None
# --------------------
# TODO: move to admin area
class AdminReporterMenu(SortMenu):

View File

@@ -30,7 +30,8 @@ from pylons.controllers.util import abort
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, menu
from r2.lib.menus import NavButton, NamedButton, NavMenu, PageNameNav, JsButton
from r2.lib.menus import SubredditButton, SubredditMenu, menu
from r2.lib.strings import plurals, rand_strings, strings
from r2.lib.utils import title_to_url, query_string, UrlParser
from r2.lib.template_helpers import add_sr, get_domain
@@ -93,12 +94,9 @@ class Reddit(Wrapped):
if infotext:
self.infobar = InfoBar(message = infotext)
#c.subredditbox is set by VSRMask
self.subreddit_sidebox = False
#don't show the sidebox on cnames
if c.subreddit_sidebox and not c.cname:
self.subreddit_sidebox = True
self.subreddit_checkboxes = c.site == Default
self.srtopbar = None
if not c.cname:
self.srtopbar = SubredditTopBar()
if c.user_is_loggedin and self.show_sidebar:
self._content = PaneStack([ShareLink(), content])
@@ -119,9 +117,6 @@ class Reddit(Wrapped):
if not isinstance(c.site, FakeSubreddit) and not c.cname:
ps.append(SubredditInfoBar())
if self.subreddit_sidebox:
ps.append(SubredditBox(self.subreddit_checkboxes))
if self.submit_box:
ps.append(SideBox(_('Submit a link'),
'/submit', 'submit',
@@ -264,10 +259,11 @@ class SubredditInfoBar(Wrapped):
c.site.is_moderator(c.user) or c.user_is_admin
buttons = [NavButton(plurals.moderators, 'moderators')]
if c.site.type != 'public':
buttons.append(NavButton(plurals.contributors, 'contributors'))
if is_moderator:
buttons.append(NamedButton('edit'))
if c.site.type != 'public':
buttons.append(NavButton(plurals.contributors, 'contributors'))
buttons.extend([NavButton(menu.banusers, 'banned'),
NamedButton('spam')])
return [NavMenu(buttons, type = "flatlist", base_path = "/about/")]
@@ -517,11 +513,13 @@ class SubredditsPage(Reddit):
NamedButton("new")]
if c.user_is_admin:
buttons.append(NamedButton("banned"))
if c.user_is_loggedin:
#add the aliases to "my reddits" stays highlighted
buttons.append(NamedButton("mine", aliases=['/reddits/mine/subscriber',
'/reddits/mine/contributor',
'/reddits/mine/moderator']))
#removing the 'my reddits' listing for now
#if c.user_is_loggedin:
# #add the aliases to "my reddits" stays highlighted
# buttons.append(NamedButton("mine", aliases=['/reddits/mine/subscriber',
# '/reddits/mine/contributor',
# '/reddits/mine/moderator']))
return [PageNameNav('reddits'),
@@ -531,6 +529,11 @@ class SubredditsPage(Reddit):
return self.content_stack(self.searchbar, self.nav_menu,
self.sr_infobar, self._content)
def rightbox(self):
ps = Reddit.rightbox(self)
ps.append(SubscriptionBox())
return ps
class MySubredditsPage(SubredditsPage):
"""Same functionality as SubredditsPage, without the search box."""
@@ -630,19 +633,52 @@ class Over18(Wrapped):
"""The creepy 'over 18' check page for nsfw content."""
pass
class SubredditTopBar(Wrapped):
"""The horizontal strip at the top of most pages for navigating
user-created reddits."""
def __init__(self):
Wrapped.__init__(self)
my_reddits = []
sr_ids = Subreddit.user_subreddits(c.user if c.user_is_loggedin else None)
if sr_ids:
my_reddits = Subreddit._byID(sr_ids, True,
return_dict = False)
my_reddits.sort(key = lambda sr: sr.name.lower())
drop_down_buttons = []
for sr in my_reddits:
drop_down_buttons.append(SubredditButton(sr))
#leaving the 'home' option out for now
#drop_down_buttons.insert(0, NamedButton(_('home'), sr_path = False,
# css_class = 'top-option',
# dest = '/'))
drop_down_buttons.append(NamedButton(_('edit'), sr_path = False,
css_class = 'bottom-option',
dest = '/reddits/'))
self.sr_dropdown = SubredditMenu(drop_down_buttons,
title = _('my reddits'),
type = 'srdrop')
pop_reddits = Subreddit.default_srs(c.content_langs, limit = 30)
buttons = [SubredditButton(sr) for sr in c.recent_reddits]
for sr in pop_reddits:
if sr not in c.recent_reddits:
buttons.append(SubredditButton(sr))
self.sr_bar = NavMenu(buttons, type='flatlist', separator = '-',
_id = 'sr-bar')
class SubredditBox(Wrapped):
"""A content pane that has the lists of subreddits that go in the
right pane by default"""
def __init__(self, checkboxes = True):
def __init__(self):
Wrapped.__init__(self)
self.checkboxes = checkboxes
if checkboxes:
self.title = _('Customize your reddit')
self.subtitle = _('Select which communities you want to see')
else:
self.title = _('Other reddit communities')
self.subtitle = 'Visit your subscribed reddits (in bold) or explore new ones'
self.title = _('Other reddit communities')
self.subtitle = 'Visit your subscribed reddits (in bold) or explore new ones'
self.create_link = ('/reddits/', menu.more)
self.more_link = ('/reddits/create', _('create'))
@@ -680,6 +716,16 @@ class SubredditBox(Wrapped):
self.cols = ((col1, col2))
self.mine = my_reddits
class SubscriptionBox(Wrapped):
"""The list of reddits a user is currently subscribed to to go in
the right pane."""
def __init__(self):
sr_ids = Subreddit.user_subreddits(c.user if c.user_is_loggedin else None)
srs = Subreddit._byID(sr_ids, True, return_dict = False)
srs.sort(key = lambda sr: sr.name.lower())
b = IDBuilder([sr._fullname for sr in srs])
self.reddits = LinkListing(b).listing().things
class CreateSubreddit(Wrapped):
"""reddit creation form."""
def __init__(self, site = None, name = ''):
@@ -1061,7 +1107,7 @@ class ContributorList(UserList):
@property
def table_title(self):
return plurals.contributors
return _("contributors to %(reddit)s") % dict(reddit = c.site.name)
def user_ids(self):
return c.site.contributors
@@ -1076,7 +1122,7 @@ class ModList(UserList):
@property
def table_title(self):
return plurals.moderators
return _("moderators to %(reddit)s") % dict(reddit = c.site.name)
def user_ids(self):
return c.site.moderators

View File

@@ -89,7 +89,7 @@ string_dict = dict(
moderator = _('below are the reddits that you have moderator access to.')
),
sr_subscribe = _('click the checkbox next to a reddit to subscribe'),
sr_subscribe = _('click the ![add](/static/sr-add-button.png) or ![remove](/static/sr-remove-button.png) buttons to choose which reddits appear on your front page.'),
searching_a_reddit = _('you\'re searching within the [%(reddit_name)s](%(reddit_link)s) reddit. '+
'you can also search within [all reddits](%(all_reddits_link)s)'),

View File

@@ -36,6 +36,10 @@ class Wrapped(object):
def __getattr__(self, attr):
#print "GETATTR: " + str(attr)
#one would think this would never happen
if attr == 'lookups':
raise AttributeError, attr
res = None
found = False
for lookup in self.lookups:

View File

@@ -33,6 +33,7 @@ from r2.lib.strings import strings, Score
from r2.lib.filters import _force_unicode
import os.path
import random
class Subreddit(Thing, Printable):
_defaults = dict(static_path = g.static_path,
@@ -235,7 +236,7 @@ class Subreddit(Thing, Printable):
rels = (SRMember._fast_query(wrapped, [user], names) if user else {})
defaults = Subreddit.default_srs(c.content_langs, ids = True)
for item in wrapped:
if user and not user.has_subscribed:
if not user or not user.has_subscribed:
item.subscriber = item._id in defaults
else:
item.subscriber = rels.get((item, user, 'subscriber'))
@@ -293,7 +294,11 @@ class Subreddit(Thing, Printable):
"""subreddits that appear in a user's listings. returns the default
srs if there are no subscriptions."""
if user and user.has_subscribed:
return Subreddit.reverse_subscriber_ids(user)
sr_ids = Subreddit.reverse_subscriber_ids(user)
if len(sr_ids) > 25:
return random.sample(sr_ids, 25)
else:
return sr_ids
else:
return cls.default_srs(c.content_langs, ids = True)
@@ -503,29 +508,6 @@ class DefaultSR(FakeSubreddit):
def title(self):
return _("reddit.com: what's new online!")
class MaskedSR(DefaultSR):
def set_mask(self, mask):
self.show_sr = []
self.hide_sr = []
for k, v in mask.iteritems():
if v:
self.show_sr.append(k)
else:
self.hide_sr.append(k)
self.show_sr = Subreddit._by_fullname(self.show_sr,
return_dict = False)
self.show_sr = [s._id for s in self.show_sr]
self.hide_sr = Subreddit._by_fullname(self.hide_sr,
return_dict = False)
self.hide_sr = [s._id for s in self.hide_sr]
def get_links(self, sort, time):
user = c.user if c.user_is_loggedin else None
sr_ids = Subreddit.user_subreddits(user)
sr_ids = [s for s in sr_ids if s not in self.hide_sr]
sr_ids.extend(self.show_sr)
return self.get_links_sr_ids(sr_ids, sort, time)
class MultiReddit(DefaultSR):
name = 'multi'

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 B

BIN
r2/r2/public/static/eye.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 633 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 703 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 724 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 306 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 546 B

BIN
r2/r2/public/static/pencil.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 450 B

View File

@@ -94,7 +94,7 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
background-color: #cee3f8;
}
#header-img {}
#header-img {margin-top: 2px;}
#header-top {
position: absolute;
@@ -138,7 +138,7 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
.dropdown-title {
}
.dropdown .drop-choices {
.drop-choices {
position: absolute;
left: 0px; /* top gets set in js */
visibility: hidden;
@@ -148,15 +148,16 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
white-space: nowrap;
line-height: normal;
margin-top: 1px;
display: inline;
}
.dropdown a.choice {
.drop-choices a.choice {
cursor: pointer;
padding: 0px 3px 0px 3px;
display: block;
}
.dropdown a.choice:hover {
.drop-choices a.choice:hover {
background-color: #c7def7;
}
@@ -177,7 +178,7 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
color: gray;
}
.dropdown.lightdrop .drop-choices {
.drop-choices.lightdrop {
margin-top: 2px;
}
@@ -198,10 +199,9 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
padding-bottom: 0;
border:none;
}
.dropdown.tabdrop .drop-choices {margin-top: 2px;}
.drop-choices.tabdrop {margin-top: 2px;}
.dropdown-title.tabdrop { display: none }
.tabmenu {
list-style-type: none;
white-space: nowrap;
@@ -223,6 +223,7 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
background-color: white;
border: 1px solid #5f99cf;
border-bottom: 1px solid white;
z-index: 100;
}
#search {
@@ -265,7 +266,7 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
}
.subredditbox {
border: 1px dotted gray;
border: 1px solid gray;
}
.subredditbox h4 {
@@ -333,9 +334,7 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
}
.sidebox {
border: gray solid 1px;
border-bottom: black solid 1px;
border-right: black solid 1px;
border: 1px solid gray;
padding-left: 44px;
}
.sidebox .spacer { margin-bottom: 5px }
@@ -356,9 +355,7 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
.raisedbox {
padding: 5px;
background: #E0E0E0;
border: gray solid 1px;
border-bottom: black solid 1px;
border-right: black solid 1px;
border: 1px solid gray;
}
.raisedbox h3 {
@@ -642,6 +639,29 @@ before enabling */
margin-right: 15px;
}
.infobar {
background-color: #f6e69f;
padding: 5px 10px;
margin: 5px 310px 5px 0px;
border: 1px solid orange;
font-size: small;
}
.infobar img {
display: inline;
vertical-align: middle;
}
.menuarea {
border-bottom: 1px dotted gray;
padding: 5px 10px;
margin: 5px 310px 5px 5px;
font-size: larger;
}
.menuarea .spacer {display: inline; margin-right: 15px}
/*top link*/
a.star { text-decoration: none; color: #ff8b60 }
@@ -832,9 +852,23 @@ a.star { text-decoration: none; color: #ff8b60 }
.subreddit { margin-bottom: 10px; }
.subreddit p { margin-top: 0px; margin-bottom: 1px; }
.subreddit .description {font-size: small; }
.subreddit .description {font-size: small; max-width: 60em;}
.subreddit .key {display: block;}
.subreddit .title { font-size: medium; margin-right: 5px; }
.subreddit .midcol { margin-right: 5px }
.sr-toggle-button {
width: 54px;
height: 18px;
margin-bottom: 5px;
cursor: pointer;
}
.sr-toggle-button.add { background-image: url(/static/sr-add-button.png) }
.sr-toggle-button.remove { background-image: url(/static/sr-remove-button.png)}
.sr-type-img {
margin-right: 2px;
}
.commentbody { }
@@ -1523,7 +1557,6 @@ ul#image-preview-list .description pre {
float: left;
}
/* Socialite */
.socialite.instructions ul {
margin: 10px;
@@ -1600,4 +1633,67 @@ ul#image-preview-list .description pre {
background-position: bottom left;
}
#sr-header-area {
padding: 3px 0;
background-color: #369;
white-space: nowrap;
overflow: hidden;
text-transform: uppercase;
}
.dropdown.srdrop .selected {
background: transparent url(/static/droparrowwhite.gif) no-repeat scroll center right;
padding-right: 21px;
margin: 0 5px;
color: white;
font-weight: normal;
}
.srdrop .choice.top-option {
font-style: italic;
border-bottom: 1px dotted #369;
}
.srdrop .choice.bottom-option {
font-style: italic;
border-top: 1px dotted #369;
}
#sr-bar .separator {color: white}
#sr-bar a {color: white;}
#sr-more-link {
color: white;
background-color: #369;
position: absolute;
right: 0px;
padding: 0 5px 0 15px;
font-weight: bold;
margin: 0 1px;
}
#sr-more-link:hover {text-decoration: underline;}
.subscription-box {
border: 1px solid gray;
padding: 0 10px;
}
.subscription-box li {
clear: left;
margin-bottom: 10px;
}
.subscription-box .sr-toggle-button {
margin-right: 5px;
float: left;
}
.subscription-box .title {
font-size: medium;
color: blue;
margin-right: 5px;
}
.subscription-box h1{ text-align: center; }

View File

@@ -3,20 +3,13 @@ var cur_menu = null; //track the current open menu
var have_open = false;
function open_menu(menu) {
for (var i=0; i< menu.childNodes.length; i++) {
child = menu.childNodes[i];
if (child.className == "drop-choices") {
child.style.visibility = 'visible';
child.style.top = menu.offsetHeight + 'px';
var child = menu.nextSibling;
if (child.className.indexOf("drop-choices") == -1) return;
child.style.visibility = 'visible';
child.style.top = (menu.offsetTop + menu.offsetHeight) + 'px';
child.style.left = menu.offsetLeft + 'px';
//expand the choices to width of the menu. fixes a
//highlighting issue in FF2
if (menu.offsetWidth > child.offsetWidth) {
child.style.width = menu.offsetWidth + 'px';
}
break;
}
}
menu.onclick = null;
cur_menu = menu;
have_open = true;
@@ -26,8 +19,8 @@ function close_menus() {
uls = document.getElementsByTagName('DIV');
for (var i=0; i<uls.length; i++) {
var ul = uls[i];
var menu = ul.parentNode;
if (menu != cur_menu && ul.className == 'drop-choices') {
var menu = ul.previousSibling;
if (menu != cur_menu && ul.className.indexOf('drop-choices') > -1) {
ul.style.visibility = 'hidden';
menu.onclick = function() {
return open_menu(this);
@@ -74,6 +67,8 @@ function init() {
/*updateMods();*/
}
stc = $("siteTable_comments");
update_reddit_count();
}
function deletetoggle(link, type) {
@@ -286,11 +281,77 @@ function set_sort(where, sort) {
return true;
}
function disable_ui(name) {
var help = $(name + "-help");
var gone = $(name + "-gone");
help.parentNode.innerHTML = gone.innerHTML;
redditRequest('disable_ui', {id: name});
}
function update_reddit_count() {
if (!cur_site || !logged) return;
var decay_factor = .9; //precentage to keep
var decay_period = 86400; //num of seconds between updates
var num_recent = 10; //num of recent reddits to report
var num_count = 100; //num of reddits to actually count
var date_key = '_date';
var cur_date = new Date();
var count_cookie = 'reddit_counts';
var recent_cookie = 'recent_reddits';
var reddit_counts = readCookie(count_cookie);
//init the reddit_counts dict
if (reddit_counts) reddit_counts = reddit_counts.parseJSON();
else {
reddit_counts = {};
reddit_counts[date_key] = cur_date.toString();
}
var last_reset = new Date(reddit_counts[date_key]);
var decay = cur_date - last_reset > decay_period * 1000;
var names = [];
//incrmenet the count on the current reddit
reddit_counts[cur_site] = (reddit_counts[cur_site] || 0) + 1;
//collect the reddit names (for sorting) and decay the view counts
//if necessary
for (var sr_name in reddit_counts) {
if (sr_name == date_key || Object.prototype[sr_name]) continue;
if (decay && sr_name != cur_site) {
//compute the new count val
var val = Math.floor(decay_factor * reddit_counts[sr_name]);
if (val > 0) reddit_counts[sr_name] = val;
else delete reddit_counts[sr_name];
}
if (reddit_counts[sr_name]) names.push(sr_name);
}
//sort the names by the view counts
names.sort(function(n1, n2) {return reddit_counts[n2] - reddit_counts[n1];});
//update the last decay date
if (decay) reddit_counts[date_key] = cur_date.toString();
//build the list of names to report as "recent"
var recent_reddits = "";
for (var i = 0; i < names.length; i++) {
var sr_name = names[i];
if (i < num_recent) {
recent_reddits += names[i] + ',';
} else if (i >= num_count && sr_name != cur_site) {
delete reddit_counts[sr_name];
}
}
//set the two cookies: one for the counts, one for the final
//recent list
createCookie(count_cookie, reddit_counts.toJSONString());
if (recent_reddits) {
createCookie(recent_cookie, recent_reddits);
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 985 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

View File

@@ -1,13 +1,17 @@
function subscribe(checkbox, id) {
if (!logged) {
return showcover();
}
if (checkbox.checked) {
function subscribe(button, id) {
if (!logged) return showcover();
var add_class = "sr-toggle-button add";
var remove_class = "sr-toggle-button remove";
if (button.className == add_class) {
action = 'sub';
button.className = remove_class;
set_score(id, 1);
}
else {
action = 'unsub';
button.className = add_class;
set_score(id, 0);
}
redditRequest_no_response('subscribe',

View File

@@ -56,22 +56,6 @@ function relative_path(updates) {
return path;
}
function close_menus() {
uls = document.getElementsByTagName('DIV');
for (var i=0; i<uls.length; i++) {
var ul = uls[i];
var menu = ul.parentNode;
if (menu != cur_menu && ul.className == 'drop-choices') {
ul.style.visibility = 'hidden';
menu.onclick = function() {
return open_menu(this);
}
}
}
cur_menu = null;
}
function _id(obj) {
if(obj && obj.id) {
var id = obj.id;

View File

@@ -21,7 +21,7 @@ function createLCookie(name,value,days) {
var expires="; expires="+date.toGMTString();
}
else expires="";
document.cookie=name+"="+escape(value)+expires+domain+"; path=/";
document.cookie=name+"="+ escape(value) +expires+domain+"; path=/";
}
function createCookie(name, value, days) {

View File

@@ -36,6 +36,8 @@
${self.robots()}
##these are globals, so they should be run first
##things that need are referenced by the reddit, the buttons, and
##the frame should go here
<script type="text/javascript">
var a = new Image();
a.src = "${static('aupmod.png')}";

View File

@@ -39,15 +39,17 @@
%elif thing.title:
<span class="selected title">${thing.title}</span>
%endif
<div class="drop-choices">
%for option in thing:
%if option != thing.selected:
${plain_link(option.title, option.path, _sr_path = option.sr_path,
_class = "choice")}
%endif
%endfor
</div>
</div>
<div class="drop-choices ${css_class}">
%for option in thing:
%if option != thing.selected:
${plain_link(option.title, option.path, _sr_path = option.sr_path,
_class = "choice" + " " + option.css_class)}
%endif
%endfor
</div>
%endif
</%def>
@@ -68,7 +70,7 @@
%>
<li ${class_name}>
%if i > 0:
${separator()}
${separator(thing.separator)}
%endif
${content}
</li>

View File

@@ -222,7 +222,8 @@ ${self.RenderPrintable()}
link = _link()
if fmt:
link = fmt % {fmt_param: link}
link = link.replace("\n", " ").replace(" <", "&#32;<").replace("> ", ">&#32;")
##who knows?
##link = link.replace("\n", " ").replace(" <", "&#32;<").replace("> ", ">&#32;")
%>
%if clicked:

View File

@@ -95,6 +95,7 @@
<%def name="javascript_run()">
var class_dict = ${class_dict()};
var where = ${path_info()};
var cur_site = "${c.site._fullname if not c.default_sr else ''}";
window.onload = init;
window.onpageshow = function(evt) {
if (evt.persisted) init()

View File

@@ -29,6 +29,10 @@
<%namespace file="utils.html" import="plain_link, text_with_js, img_link, separator"/>
<div id="header">
%if thing.srtopbar:
${thing.srtopbar.render()}
%endif
<div id="header-top" class="hover">
%if not c.user_is_loggedin:
<span class="user">
@@ -41,7 +45,7 @@
&nbsp;(<b>${c.user.safe_karma}</b>)
</span>
${separator()}
${separator("|")}
<%
mail_img ="mail"
@@ -55,7 +59,7 @@
_id = "mail" )}
%endif
${separator()}
${separator("|")}
${thing.corner_buttons().render()}
</div>

View File

@@ -30,7 +30,6 @@
<%def name="numcol()">
</%def>
<%def name="entry()">
<% fullname = thing._fullname %>
<p class="titlerow">
@@ -57,19 +56,47 @@
${self.score(thing, thing.subscriber)}
</%def>
##this function is used by subscriptionbox.html
<%def name="addremove_button(sr)">
<div class="sr-toggle-button ${'remove' if sr.subscriber else 'add'}"
onclick="subscribe(this, '${sr._fullname}');">
</div>
</%def>
##this function is used by subscriptionbox.html
<%def name="permission_icons(sr)">
%if sr.moderator:
<img class="sr-type-img" title="${_('moderator')}" alt="${_('moderator')}" src="/static/star.png" />
%endif
%if sr.type in ("restricted", "private") and not sr.moderator:
<img class="sr-type-img"
%if sr.contributor:
alt="${_('contributor')}"
title="${_('contributor')}"
src="/static/pencil.png"
%else:
alt="${_('not contributor')}"
title="${_('not contributor')}"
src="/static/pencil-gray.png"
%endif
/>
%endif
%if sr.type == "private":
<img class="sr-type-img" title="${_('private')}" alt="${_('private')}" src="/static/eye.png" />
%endif
%if sr.over_18:
<img class="sr-type-img" title="${_('over18')}" alt="${_('over18')}" src="/static/over18_icon.png" />
%endif
</%def>
<%def name="midcol(display=True)">
<div class="midcol">
<input type="checkbox"
autocomplete="off"
onchange="subscribe(this, '${thing._fullname}');"
onclick="this.blur();"
${thing.subscriber and unsafe("checked='checked'") or ''}/>
%if thing.type in ("restricted", "private"):
<% key_path = "green" if thing.contributor else "red" %>
<% alt_txt = "permitted" if thing.contributor else "not permitted" %>
<% key_path = "/static/key_%s.png" % key_path %>
<img class="key" src="${key_path}" alt="${alt_txt}" />
%endif
${addremove_button(thing)}
${permission_icons(thing)}
</div>
</%def>

View File

@@ -41,16 +41,7 @@
%if col:
<ul>
%for sr, sel in col:
<li ${"class='selected'" if sel else ''}
id="sr_sel_${sr._fullname}">
%if thing.checkboxes:
<input type="checkbox" ${"checked='checked'" if sel else ''}
autocomplete="off"
onclick="this.blur();"
name="sr_sel_chx_${sr._fullname}"
onchange="return change_sr('${sr._fullname}');"
id="sr_sel_chx_${sr._fullname}"/>
%endif
<li ${"class='selected'" if sel else ''} >
<%
if sr.path:
path = sr.path

View File

@@ -62,14 +62,14 @@
%if c.site.type in ("private", "restricted") and c.user_is_loggedin and \
c.site.is_contributor(c.user):
${moderate_button("contributor",
_("you are a %(contributor)s of this reddit."),
_("you are a contributor of this reddit. (%(leave)s)"),
_("stop being a contributor?"),
_("you are no longer a contributor"))}
%endif
%if c.user_is_loggedin and c.site.is_moderator(c.user):
${moderate_button("moderator",
_("you are a %(moderator)s of this reddit."),
_("you are a moderator of this reddit. (%(leave)s)"),
_("stop being a moderator?"),
_("you are no longer a moderator"))}
@@ -85,11 +85,11 @@
<%def name="moderate_button(location, fmt, question, left)">
${state_button("leave" + location, c.site._fullname, _(location),
${state_button("leave" + location, c.site._fullname, "leave",
"return deletetoggle(this, 'leave');",
left, location = location,
yes = _("yes"), no = _("no"),
question = question,
fmt = fmt, fmt_param = location,
fmt = fmt, fmt_param = "leave",
a_class="moderate")}
</%def>

View File

@@ -0,0 +1,29 @@
## 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-2008
## CondeNet, Inc. All Rights Reserved.
################################################################################
<%namespace file="utils.html" import="plain_link"/>
<div id="sr-header-area">
${thing.sr_dropdown.render()}
${thing.sr_bar.render()}
${plain_link(unsafe(_("more") + " &raquo;"), "/reddits/", id="sr-more-link")}
</div>

View File

@@ -0,0 +1,36 @@
## 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-2008
## CondeNet, Inc. All Rights Reserved.
################################################################################
<%namespace file="utils.html" import="plain_link"/>
<%namespace file="subreddit.html" import="addremove_button, permission_icons"/>
<div class="subscription-box">
<h1>your front page reddits</h1>
<ul>
%for sr in thing.reddits:
<li>
${addremove_button(sr)}
${plain_link(sr.name, sr.path, _class="title")}
${permission_icons(sr)}
</li>
%endfor
</ul>
</div>

View File

@@ -22,9 +22,8 @@
<%namespace file="utils.html" import="error_field"/>
<% from r2.lib.template_helpers import static %>
%if thing.editable or thing.users:
<div class="${thing._class} usertable">
%if thing.editable:
%if thing.editable:
<h1>${thing.form_title}</h1>
<script src="${static('tabular.js')}" type="text/javascript"></script>
@@ -38,10 +37,9 @@
<button class="btn" type="submit">${_("add")}</button>
${error_field("USER_DOESNT_EXIST", "span")}
</form>
%endif
%endif
<h1 style="${len(thing.users)==0 and 'display:none' or ''}">
<h1>
${thing.table_title}
</h1>
@@ -52,4 +50,4 @@
%endfor
</table>
</div>
%endif

View File

@@ -212,8 +212,8 @@ ${unsafe(txt)}
</table>
</%def>
<%def name="separator()">
<span class="separator">|</span>
<%def name="separator(separator_char)">
<span class="separator">${separator_char}</span>
</%def>
<%def name="optionalstyle(style)">