mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-02-15 08:55:49 -05:00
New help system and footer
This commit is contained in:
@@ -115,6 +115,8 @@ MIN_DOWN_KARMA = 0
|
||||
MIN_RATE_LIMIT_KARMA = 0
|
||||
MIN_RATE_LIMIT_COMMENT_KARMA = 0
|
||||
|
||||
WIKI_KARMA = 50
|
||||
|
||||
# time in days
|
||||
MODWINDOW = 2
|
||||
HOT_PAGE_AGE = 1
|
||||
|
||||
@@ -20,12 +20,15 @@
|
||||
# CondeNet, Inc. All Rights Reserved.
|
||||
################################################################################
|
||||
from reddit_base import RedditController, proxyurl
|
||||
from pylons import request
|
||||
from r2.lib.pages import Embed, BoringPage
|
||||
from r2.lib.pages import Embed, BoringPage, HelpPage
|
||||
from r2.lib.filters import websafe, SC_OFF, SC_ON
|
||||
from pylons.i18n import _
|
||||
from urllib2 import HTTPError
|
||||
from pylons import request
|
||||
from pylons import c
|
||||
|
||||
from BeautifulSoup import BeautifulSoup, Tag
|
||||
|
||||
from urllib2 import HTTPError
|
||||
|
||||
def force_redirect(dest):
|
||||
def _force_redirect(self, *a, **kw):
|
||||
@@ -33,27 +36,51 @@ def force_redirect(dest):
|
||||
return _force_redirect
|
||||
|
||||
class EmbedController(RedditController):
|
||||
def rendercontent(self, input, fp):
|
||||
soup = BeautifulSoup(input)
|
||||
|
||||
def rendercontent(self, content):
|
||||
if content.startswith("<!--TEMPLATE-->"):
|
||||
return BoringPage(_("help"),
|
||||
content = Embed(content=content),
|
||||
show_sidebar = None,
|
||||
space_compress = False).render()
|
||||
else:
|
||||
return content
|
||||
output = soup.find("div", { 'class':'wiki', 'id':'content'} )
|
||||
|
||||
# Replace all links to "/wiki/help/..." with "/help/..."
|
||||
for link in output.findAll('a'):
|
||||
if link.has_key('href') and link['href'].startswith("/wiki/help"):
|
||||
link['href'] = link['href'][5:]
|
||||
|
||||
# Add "edit this page" link if the user is allowed to edit the wiki
|
||||
if c.user_is_loggedin and c.user.can_wiki():
|
||||
edit_text = _('edit this page')
|
||||
read_first = _('read this first')
|
||||
url = "http://code.reddit.com/wiki" + websafe(fp) + "?action=edit"
|
||||
|
||||
edittag = """
|
||||
<div class="editlink">
|
||||
<hr/>
|
||||
<a href="%s">%s</a> 
|
||||
(<a href="/help/editing_help">%s</a>)
|
||||
</div>
|
||||
""" % (url, edit_text, read_first)
|
||||
|
||||
output.append(edittag)
|
||||
|
||||
output = SC_OFF + unicode(output) + SC_ON
|
||||
|
||||
return HelpPage(_("help"),
|
||||
content = Embed(content=output),
|
||||
show_sidebar = None).render()
|
||||
|
||||
def renderurl(self):
|
||||
|
||||
# Needed so http://reddit.com/help/ works
|
||||
fp = request.path.rstrip("/")
|
||||
u = "http://code.reddit.com/wiki" + fp + '?stripped=1'
|
||||
|
||||
try:
|
||||
content = proxyurl("http://reddit.infogami.com"+request.fullpath)
|
||||
return self.rendercontent(content)
|
||||
content = proxyurl(u)
|
||||
return self.rendercontent(content, fp)
|
||||
except HTTPError, e:
|
||||
if e.code == 404:
|
||||
return self.abort404()
|
||||
else:
|
||||
if e.code != 404:
|
||||
print "error %s" % e.code
|
||||
print e.fp.read()
|
||||
return self.abort404()
|
||||
|
||||
GET_help = POST_help = renderurl
|
||||
|
||||
GET_blog = force_redirect("http://blog.reddit.com/")
|
||||
|
||||
@@ -465,7 +465,8 @@ class FrontController(RedditController):
|
||||
returns their user name"""
|
||||
c.response_content_type = 'text/plain'
|
||||
if c.user_is_loggedin:
|
||||
c.response.content = c.user.name
|
||||
perm = str(c.user.can_wiki())
|
||||
c.response.content = c.user.name + "," + perm
|
||||
else:
|
||||
c.response.content = ''
|
||||
return c.response
|
||||
|
||||
@@ -38,6 +38,7 @@ class Globals(object):
|
||||
'MIN_DOWN_KARMA',
|
||||
'MIN_RATE_LIMIT_KARMA',
|
||||
'MIN_RATE_LIMIT_COMMENT_KARMA',
|
||||
'WIKI_KARMA',
|
||||
'HOT_PAGE_AGE',
|
||||
'MODWINDOW',
|
||||
'RATELIMIT',
|
||||
|
||||
@@ -26,10 +26,13 @@ from pylons.i18n import N_, _, ungettext, get_lang
|
||||
import r2.lib.helpers as h
|
||||
from r2.lib.utils import to_js
|
||||
from r2.lib.filters import spaceCompress, _force_unicode
|
||||
from r2.lib.template_helpers import get_domain
|
||||
from utils import storify, string2js, read_http_date
|
||||
|
||||
import re, md5
|
||||
from urllib import quote
|
||||
import urllib2
|
||||
|
||||
|
||||
#TODO hack
|
||||
import logging
|
||||
@@ -159,21 +162,14 @@ class BaseController(WSGIController):
|
||||
c.response.content = to_js(js, callback, escape)
|
||||
return c.response
|
||||
|
||||
import urllib2
|
||||
class EmbedHandler(urllib2.BaseHandler, urllib2.HTTPHandler,
|
||||
class EmbedHandler(urllib2.BaseHandler, urllib2.HTTPHandler,
|
||||
urllib2.HTTPErrorProcessor, urllib2.HTTPDefaultErrorHandler):
|
||||
@staticmethod
|
||||
def redirect(_status):
|
||||
def _redirect(url, status = None):
|
||||
MethodController.redirect(url, code = _status)
|
||||
return _redirect
|
||||
|
||||
|
||||
def http_redirect(self, req, fp, code, msg, hdrs):
|
||||
codes = [301, 302, 303, 307]
|
||||
map = dict((x, self.redirect(x)) for x in codes)
|
||||
to = hdrs['Location'].replace('reddit.infogami.com', g.domain)
|
||||
map[code](to)
|
||||
raise StopIteration
|
||||
to = hdrs['Location']
|
||||
h = urllib2.HTTPRedirectHandler()
|
||||
r = h.redirect_request(req, fp, code, msg, hdrs, to)
|
||||
return embedopen.open(r)
|
||||
|
||||
http_error_301 = http_redirect
|
||||
http_error_302 = http_redirect
|
||||
@@ -184,17 +180,7 @@ embedopen = urllib2.OpenerDirector()
|
||||
embedopen.add_handler(EmbedHandler())
|
||||
|
||||
def proxyurl(url):
|
||||
cstrs = ['%s="%s"' % (k, v.value) for k, v in c.cookies.iteritems()]
|
||||
cookiestr = "; ".join(cstrs)
|
||||
headers = {"Cookie":cookiestr}
|
||||
|
||||
# TODO make this work on POST
|
||||
data = None
|
||||
r = urllib2.Request(url, data, headers)
|
||||
r = urllib2.Request(url, None, {})
|
||||
content = embedopen.open(r).read()
|
||||
return content
|
||||
|
||||
__all__ = [__name for __name in locals().keys() if not __name.startswith('_') \
|
||||
or __name == '_']
|
||||
|
||||
|
||||
|
||||
@@ -42,19 +42,19 @@ static PyObject *
|
||||
filters_uwebsafe(PyObject * self, PyObject *args)
|
||||
{
|
||||
PyObject * com;
|
||||
Py_UNICODE * command;
|
||||
Py_UNICODE * input_buffer;
|
||||
Py_UNICODE *buffer;
|
||||
PyObject * res;
|
||||
int ic=0, ib=0;
|
||||
int len;
|
||||
Py_UNICODE c;
|
||||
if (!(com = unicode_arg(args))) return NULL;
|
||||
command = PyUnicode_AS_UNICODE(com);
|
||||
input_buffer = PyUnicode_AS_UNICODE(com);
|
||||
len = PyUnicode_GetSize(com);
|
||||
|
||||
buffer = (Py_UNICODE*)malloc(6*len*sizeof(Py_UNICODE));
|
||||
for(ic = 0, ib = 0; ic < len; ic++, ib++) {
|
||||
c = command[ic];
|
||||
c = input_buffer[ic];
|
||||
if (c == '&') {
|
||||
buffer[ib++] = (Py_UNICODE)'&';
|
||||
buffer[ib++] = (Py_UNICODE)'a';
|
||||
@@ -83,7 +83,7 @@ filters_uwebsafe(PyObject * self, PyObject *args)
|
||||
buffer[ib] = (Py_UNICODE)';';
|
||||
}
|
||||
else {
|
||||
buffer[ib] = command[ic];
|
||||
buffer[ib] = input_buffer[ic];
|
||||
}
|
||||
}
|
||||
res = PyUnicode_FromUnicode(buffer, ib);
|
||||
@@ -96,19 +96,19 @@ static PyObject *
|
||||
filters_uwebsafe_json(PyObject * self, PyObject *args)
|
||||
{
|
||||
PyObject * com;
|
||||
Py_UNICODE * command;
|
||||
Py_UNICODE * input_buffer;
|
||||
Py_UNICODE *buffer;
|
||||
PyObject * res;
|
||||
int ic=0, ib=0;
|
||||
int len;
|
||||
Py_UNICODE c;
|
||||
if (!(com = unicode_arg(args))) return NULL;
|
||||
command = PyUnicode_AS_UNICODE(com);
|
||||
input_buffer = PyUnicode_AS_UNICODE(com);
|
||||
len = PyUnicode_GetSize(com);
|
||||
|
||||
buffer = (Py_UNICODE*)malloc(5*len*sizeof(Py_UNICODE));
|
||||
for(ic = 0, ib = 0; ic < len; ic++, ib++) {
|
||||
c = command[ic];
|
||||
c = input_buffer[ic];
|
||||
if (c == '&') {
|
||||
buffer[ib++] = (Py_UNICODE)'&';
|
||||
buffer[ib++] = (Py_UNICODE)'a';
|
||||
@@ -129,7 +129,7 @@ filters_uwebsafe_json(PyObject * self, PyObject *args)
|
||||
buffer[ib] = (Py_UNICODE)';';
|
||||
}
|
||||
else {
|
||||
buffer[ib] = command[ic];
|
||||
buffer[ib] = input_buffer[ic];
|
||||
}
|
||||
}
|
||||
res = PyUnicode_FromUnicode(buffer, ib);
|
||||
@@ -142,18 +142,18 @@ filters_uwebsafe_json(PyObject * self, PyObject *args)
|
||||
static PyObject *
|
||||
filters_websafe(PyObject * self, PyObject *args)
|
||||
{
|
||||
const char * command;
|
||||
const char * input_buffer;
|
||||
char *buffer;
|
||||
PyObject * res;
|
||||
int ic=0, ib=0;
|
||||
int len;
|
||||
char c;
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
if (!PyArg_ParseTuple(args, "s", &input_buffer))
|
||||
return NULL;
|
||||
len = strlen(command);
|
||||
len = strlen(input_buffer);
|
||||
buffer = (char*)malloc(5*len);
|
||||
for(ic = 0, ib = 0; ic <= len; ic++, ib++) {
|
||||
c = command[ic];
|
||||
c = input_buffer[ic];
|
||||
if (c == '&') {
|
||||
buffer[ib++] = '&';
|
||||
buffer[ib++] = 'a';
|
||||
@@ -182,7 +182,7 @@ filters_websafe(PyObject * self, PyObject *args)
|
||||
buffer[ib] = ';';
|
||||
}
|
||||
else {
|
||||
buffer[ib] = command[ic];
|
||||
buffer[ib] = input_buffer[ic];
|
||||
}
|
||||
}
|
||||
res = Py_BuildValue("s", buffer);
|
||||
@@ -199,12 +199,12 @@ void print_unicode(Py_UNICODE *c, int len) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
const char *MD_START = "<div class=\"md\">";
|
||||
const char *MD_END = "</div>";
|
||||
const Py_UNICODE *MD_START_U;
|
||||
const Py_UNICODE *MD_END_U;
|
||||
int MD_START_LEN = 0;
|
||||
int MD_END_LEN = 0;
|
||||
const char *SC_OFF = "<!-- SC_OFF -->";
|
||||
const char *SC_ON = "<!-- SC_ON -->";
|
||||
const Py_UNICODE *SC_OFF_U;
|
||||
const Py_UNICODE *SC_ON_U;
|
||||
int SC_OFF_LEN = 0;
|
||||
int SC_ON_LEN = 0;
|
||||
|
||||
|
||||
|
||||
@@ -218,7 +218,7 @@ filters_uspace_compress(PyObject * self, PyObject *args) {
|
||||
PyObject * com;
|
||||
PyObject * res;
|
||||
Py_ssize_t len;
|
||||
Py_UNICODE *command;
|
||||
Py_UNICODE *input_buffer;
|
||||
Py_UNICODE *buffer;
|
||||
Py_UNICODE c;
|
||||
int ic, ib;
|
||||
@@ -227,36 +227,48 @@ filters_uspace_compress(PyObject * self, PyObject *args) {
|
||||
if(!com) {
|
||||
return NULL;
|
||||
}
|
||||
command = PyUnicode_AS_UNICODE(com);
|
||||
input_buffer = PyUnicode_AS_UNICODE(com);
|
||||
len = PyUnicode_GetSize(com);
|
||||
buffer = (Py_UNICODE*)malloc(len * sizeof(Py_UNICODE));
|
||||
|
||||
/* ic -> input buffer index, ib -> output buffer */
|
||||
for(ic = 0, ib = 0; ic <= len; ic++) {
|
||||
c = command[ic];
|
||||
c = input_buffer[ic];
|
||||
/* gobble -> we are space compressing */
|
||||
if(gobble) {
|
||||
/* remove spaces if encountered */
|
||||
if(Py_UNICODE_ISSPACE(c)) {
|
||||
while(Py_UNICODE_ISSPACE(c)) { c = command[++ic]; }
|
||||
/* after this loop, c will be a non-space */
|
||||
while(Py_UNICODE_ISSPACE(c)) { c = input_buffer[++ic]; }
|
||||
/* unless next char is a <, add a single space to account for
|
||||
the multiple spaces that have been removed */
|
||||
if(c != (Py_UNICODE)('<')) {
|
||||
buffer[ib++] = (Py_UNICODE)(' ');
|
||||
}
|
||||
}
|
||||
/* gobble all space after '>' */
|
||||
if(c == (Py_UNICODE)('>')) {
|
||||
buffer[ib++] = c;
|
||||
c = command[++ic];
|
||||
while(Py_UNICODE_ISSPACE(c)) { c = command[++ic]; }
|
||||
c = input_buffer[++ic];
|
||||
while(Py_UNICODE_ISSPACE(c)) { c = input_buffer[++ic]; }
|
||||
}
|
||||
if (len - ic >= MD_START_LEN &&
|
||||
memcmp(&command[ic], MD_START_U,
|
||||
sizeof(Py_UNICODE)*MD_START_LEN) == 0) {
|
||||
/* does the next part of the string match the SC_OFF label */
|
||||
if (len - ic >= SC_OFF_LEN &&
|
||||
memcmp(&input_buffer[ic], SC_OFF_U,
|
||||
sizeof(Py_UNICODE)*SC_OFF_LEN) == 0) {
|
||||
/* disable gobbling, and bypass that part of the string */
|
||||
gobble = 0;
|
||||
ic += SC_OFF_LEN;
|
||||
c = input_buffer[ic];
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (len - ic > MD_END_LEN &&
|
||||
memcmp(&command[ic], MD_END_U,
|
||||
sizeof(Py_UNICODE)*MD_END_LEN) == 0) {
|
||||
/* not gobbling, but find the SC_ON tag */
|
||||
else if (len - ic >= SC_ON_LEN &&
|
||||
memcmp(&input_buffer[ic], SC_ON_U,
|
||||
sizeof(Py_UNICODE)*SC_ON_LEN) == 0) {
|
||||
gobble = 1;
|
||||
}
|
||||
ic += SC_ON_LEN;
|
||||
c = input_buffer[ic];
|
||||
}
|
||||
if(c) {
|
||||
buffer[ib++] = c;
|
||||
@@ -268,57 +280,6 @@ filters_uspace_compress(PyObject * self, PyObject *args) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static PyObject *
|
||||
filters_space_compress(PyObject * self, PyObject *args)
|
||||
{
|
||||
PyObject * res;
|
||||
|
||||
const char * command;
|
||||
int len, ic, ib;
|
||||
char c;
|
||||
char * buffer;
|
||||
int gobble = 1;
|
||||
if (!PyArg_ParseTuple(args, "s", &command))
|
||||
return NULL;
|
||||
|
||||
len = strlen(command);
|
||||
buffer = (char*)malloc(len);
|
||||
|
||||
for(ic = 0, ib = 0; ic <= len; ic++) {
|
||||
c = command[ic];
|
||||
if(gobble) {
|
||||
if(c == '>') {
|
||||
buffer[ib++] = c;
|
||||
while(whitespace(command[++ic]));
|
||||
c = command[ic];
|
||||
}
|
||||
else if(whitespace(c)) {
|
||||
while(whitespace(command[++ic]));
|
||||
c = command[ic];
|
||||
if(c != '<') {
|
||||
buffer[ib++] = ' ';
|
||||
}
|
||||
}
|
||||
if (len - ic >= MD_START_LEN &&
|
||||
strncmp(&command[ic], MD_START, MD_START_LEN) == 0) {
|
||||
gobble = 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (len - ic > MD_END_LEN &&
|
||||
strncmp(&command[ic], MD_END, MD_END_LEN) == 0) {
|
||||
gobble = 1;
|
||||
}
|
||||
}
|
||||
buffer[ib++] = c;
|
||||
}
|
||||
|
||||
res = Py_BuildValue("s", buffer);
|
||||
free(buffer);
|
||||
return res;
|
||||
}
|
||||
|
||||
static PyMethodDef FilterMethods[] = {
|
||||
{"websafe", filters_websafe, METH_VARARGS,
|
||||
"make string web safe."},
|
||||
@@ -326,10 +287,8 @@ static PyMethodDef FilterMethods[] = {
|
||||
"make string web safe."},
|
||||
{"uwebsafe_json", filters_uwebsafe_json, METH_VARARGS,
|
||||
"make string web safe, no "."},
|
||||
{"space_compress", filters_space_compress, METH_VARARGS,
|
||||
"returns meep"},
|
||||
{"uspace_compress", filters_uspace_compress, METH_VARARGS,
|
||||
"returns meep"},
|
||||
"removes spaces around angle brackets. Can be disabled with the use of SC_OFF and SC_ON comments from r2.lib.filters."},
|
||||
{NULL, NULL, 0, NULL} /* Sentinel */
|
||||
};
|
||||
|
||||
@@ -347,10 +306,10 @@ Py_UNICODE *to_unicode(const char *c, int len) {
|
||||
PyMODINIT_FUNC
|
||||
initCfilters(void)
|
||||
{
|
||||
MD_START_LEN = strlen(MD_START);
|
||||
MD_START_U = to_unicode(MD_START, MD_START_LEN);
|
||||
MD_END_LEN = strlen(MD_END);
|
||||
MD_END_U = to_unicode(MD_END, MD_END_LEN);
|
||||
SC_OFF_LEN = strlen(SC_OFF);
|
||||
SC_OFF_U = to_unicode(SC_OFF, SC_OFF_LEN);
|
||||
SC_ON_LEN = strlen(SC_ON);
|
||||
SC_ON_U = to_unicode(SC_ON, SC_ON_LEN);
|
||||
|
||||
(void) Py_InitModule("Cfilters", FilterMethods);
|
||||
}
|
||||
|
||||
@@ -25,8 +25,9 @@ import cgi
|
||||
import urllib
|
||||
import re
|
||||
|
||||
MD_START = '<div class="md">'
|
||||
MD_END = '</div>'
|
||||
SC_OFF = "<!-- SC_OFF -->"
|
||||
SC_ON = "<!-- SC_ON -->"
|
||||
|
||||
|
||||
|
||||
def python_websafe(text):
|
||||
@@ -50,15 +51,23 @@ except ImportError:
|
||||
_between_tags1 = re.compile('> +')
|
||||
_between_tags2 = re.compile(' +<')
|
||||
_spaces = re.compile('[\s]+')
|
||||
_ignore = re.compile('(' + MD_START + '.*?' + MD_END + ')', re.S | re.I)
|
||||
_ignore = re.compile('(' + SC_OFF + '|' + SC_ON + ')', re.S | re.I)
|
||||
def spaceCompress(content):
|
||||
res = ''
|
||||
sc = True
|
||||
for p in _ignore.split(content):
|
||||
if not p.startswith(MD_START) and not p.endswith(MD_END):
|
||||
if p == SC_ON:
|
||||
sc = True
|
||||
elif p == SC_OFF:
|
||||
sc = False
|
||||
elif sc:
|
||||
p = _spaces.sub(' ', p)
|
||||
p = _between_tags1.sub('>', p)
|
||||
p = _between_tags2.sub('<', p)
|
||||
res += p
|
||||
res += p
|
||||
else:
|
||||
res += p
|
||||
|
||||
return res
|
||||
|
||||
class _Unsafe(unicode): pass
|
||||
@@ -141,7 +150,7 @@ def safemarkdown(text, nofollow = False):
|
||||
text = code_re.sub(code_handler, text)
|
||||
text = a_re.sub(inner_a_handler, text)
|
||||
text = fix_url.sub(r'\1', text)
|
||||
return MD_START + text + MD_END
|
||||
return SC_OFF + '<div class="md">' + text + '</div>' + SC_ON
|
||||
|
||||
|
||||
def keep_space(text):
|
||||
|
||||
@@ -85,20 +85,21 @@ menu = MenuHandler(hot = _('hot'),
|
||||
stats = _("stats"),
|
||||
submit = _("submit"),
|
||||
help = _("help"),
|
||||
blog = _("blog"),
|
||||
blog = _("the reddit blog"),
|
||||
logout = _("logout"),
|
||||
|
||||
#reddit footer strings
|
||||
feedback = _("feedback"),
|
||||
bookmarklets = _("bookmarklets"),
|
||||
socialite = _("socialite"),
|
||||
socialite = _("socialite firefox extension"),
|
||||
buttons = _("buttons"),
|
||||
widget = _("widget"),
|
||||
code = _("code"),
|
||||
code = _("source code"),
|
||||
mobile = _("mobile"),
|
||||
store = _("store"),
|
||||
ad_inq = _("advertise"),
|
||||
|
||||
ad_inq = _("advertise on reddit"),
|
||||
toplinks = _("top links"),
|
||||
|
||||
#preferences
|
||||
options = _('options'),
|
||||
friends = _("friends"),
|
||||
@@ -180,8 +181,9 @@ def menu_style(type):
|
||||
lightdrop = ('dropdown', 'lightdrop'),
|
||||
tabdrop = ('dropdown', 'tabdrop'),
|
||||
srdrop = ('dropdown', 'srdrop'),
|
||||
flatlist = ('flatlist', ''),
|
||||
flatlist = ('flatlist', 'flat-list'),
|
||||
tabmenu = ('tabmenu', ''),
|
||||
flat_vert = ('flatlist', 'flat-vert'),
|
||||
)
|
||||
return d.get(type, default)
|
||||
|
||||
@@ -292,6 +294,10 @@ class NavButton(Styled):
|
||||
when it is different from self.title)"""
|
||||
return self.title
|
||||
|
||||
class OffsiteButton(NavButton):
|
||||
def build(self, base_path = ''):
|
||||
self.path = self.bare_path = self.dest
|
||||
|
||||
class SubredditButton(NavButton):
|
||||
def __init__(self, sr):
|
||||
self.sr = sr
|
||||
|
||||
@@ -32,7 +32,7 @@ from r2.lib.traffic import load_traffic, load_summary
|
||||
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, menu
|
||||
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.template_helpers import add_sr, get_domain
|
||||
@@ -185,21 +185,69 @@ class Reddit(Wrapped):
|
||||
|
||||
def footer_nav(self):
|
||||
"""navigation buttons in the footer."""
|
||||
buttons = [NamedButton("help", False, nocname=True),
|
||||
NamedButton("blog", False, nocname=True),
|
||||
NamedButton("stats", False, nocname=True),
|
||||
NamedButton("feedback", False),
|
||||
NamedButton("bookmarklets", False),
|
||||
NamedButton("socialite", False),
|
||||
NamedButton("buttons", True),
|
||||
NamedButton("widget", True),
|
||||
NamedButton("code", False, nocname=True),
|
||||
NamedButton("mobile", False, nocname=True),
|
||||
NamedButton("store", False, nocname=True),
|
||||
NamedButton("ad_inq", False, nocname=True),
|
||||
]
|
||||
return [NavMenu([NamedButton("toplinks", False),
|
||||
NamedButton("mobile", False, nocname=True),
|
||||
OffsiteButton("rss", dest = '/.rss'),
|
||||
NamedButton("store", False, nocname=True),
|
||||
NamedButton("stats", False, nocname=True),
|
||||
NamedButton("feedback", False),],
|
||||
title = 'site links', type = 'flat_vert',
|
||||
separator = ''),
|
||||
|
||||
return NavMenu(buttons, base_path = "/", type = "flatlist")
|
||||
NavMenu([NamedButton("help", False, nocname=True),
|
||||
OffsiteButton("FAQ", dest = '/help/faq',
|
||||
nocname=True),
|
||||
OffsiteButton("reddiquette", nocname=True,
|
||||
dest = '/help/reddiquette')],
|
||||
title = 'help', type = 'flat_vert',
|
||||
separator = ''),
|
||||
|
||||
NavMenu([NamedButton("bookmarklets", False),
|
||||
NamedButton("buttons", True),
|
||||
NamedButton("code", False, nocname=True),
|
||||
NamedButton("socialite", False),
|
||||
NamedButton("widget", True)],
|
||||
title = 'reddit tools', type = 'flat_vert',
|
||||
separator = ''),
|
||||
|
||||
NavMenu([NamedButton("blog", False, nocname=True),
|
||||
OffsiteButton("our pet fish",
|
||||
dest="http://justin.tv/reddit"),
|
||||
NamedButton("ad_inq", False, nocname=True),
|
||||
OffsiteButton('reddit.tv', "http://www.reddit.tv"),
|
||||
OffsiteButton('redditall', "http://www.redditall.com"),],
|
||||
title = 'about us', type = 'flat_vert',
|
||||
separator = ''),
|
||||
NavMenu([OffsiteButton('BaconBuzz',
|
||||
"http://www.baconbuzz.com"),
|
||||
OffsiteButton('Destructoid reddit',
|
||||
"http://reddit.destructoid.com"),
|
||||
OffsiteButton('TheCuteList',
|
||||
"http://www.thecutelist.com"),
|
||||
OffsiteButton('The Independent reddit',
|
||||
"http://reddit.independent.co.uk"),
|
||||
OffsiteButton('redditGadgetGuide',
|
||||
"http://www.redditgadgetguide.com"),
|
||||
OffsiteButton('WeHeartGossip',
|
||||
"http://www.weheartgossip.com")],
|
||||
title = 'brothers', type = 'flat_vert',
|
||||
separator = ''),
|
||||
NavMenu([OffsiteButton('Wired.com',
|
||||
"http://www.wired.com"),
|
||||
OffsiteButton('Ars Technica',
|
||||
"http://www.arstechnica.com"),
|
||||
OffsiteButton('Style.com',
|
||||
"http://www.style.com"),
|
||||
OffsiteButton('Portfolio.com',
|
||||
"http://www.portfolio.com",
|
||||
css_class="line-through"),
|
||||
OffsiteButton('Epicurious.com',
|
||||
"http://www.epicurious.com"),
|
||||
OffsiteButton('Concierge.com',
|
||||
"http://www.concierge.com")],
|
||||
title = 'sisters', type = 'flat_vert',
|
||||
separator = '')
|
||||
]
|
||||
|
||||
def build_toolbars(self):
|
||||
"""Sets the layout of the navigation topbar on a Reddit. The result
|
||||
@@ -359,6 +407,9 @@ class BoringPage(Reddit):
|
||||
def build_toolbars(self):
|
||||
return [PageNameNav('nomenu', title = self.pagename)]
|
||||
|
||||
class HelpPage(BoringPage):
|
||||
def build_toolbars(self):
|
||||
return [PageNameNav('help', title = self.pagename)]
|
||||
|
||||
class FormPage(BoringPage):
|
||||
"""intended for rendering forms with no rightbox needed or wanted"""
|
||||
|
||||
@@ -61,6 +61,7 @@ class Account(Thing):
|
||||
has_subscribed = False,
|
||||
pref_media = 'subreddit',
|
||||
share = {},
|
||||
wiki_override = None,
|
||||
)
|
||||
|
||||
def karma(self, kind, sr = None):
|
||||
@@ -105,6 +106,13 @@ class Account(Thing):
|
||||
karma = self.link_karma
|
||||
return max(karma, 1) if karma > -1000 else karma
|
||||
|
||||
def can_wiki(self):
|
||||
if self.wiki_override is not None:
|
||||
return self.wiki_override
|
||||
else:
|
||||
return (self.link_karma >= g.WIKI_KARMA and
|
||||
self.comment_karma >= g.WIKI_KARMA)
|
||||
|
||||
def all_karmas(self):
|
||||
"""returns a list of tuples in the form (name, link_karma,
|
||||
comment_karma)"""
|
||||
|
||||
@@ -19,7 +19,7 @@ body {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
html,body { height: 100%; }
|
||||
/*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
|
||||
@@ -45,15 +45,10 @@ a:focus { -moz-outline-style: none; }
|
||||
*/
|
||||
|
||||
.rounded {
|
||||
-moz-border-radius-topleft: 7px;
|
||||
-moz-border-radius-topright: 7px;
|
||||
-moz-border-radius-bottomleft: 7px;
|
||||
-moz-border-radius-bottomright: 7px;
|
||||
-webkit-border-top-left-radius: 7px;
|
||||
-webkit-border-top-right-radius: 7px;
|
||||
-webkit-border-bottom-left-radius: 7px;
|
||||
-webkit-border-bottom-right-radius: 7px;
|
||||
-moz-border-radius: 7px;
|
||||
-webkit-border-radius: 7px;
|
||||
}
|
||||
|
||||
.rounded .morelink {
|
||||
-webkit-border-top-right-radius: 6px;
|
||||
-moz-border-radius-topright: 6px;
|
||||
@@ -98,6 +93,17 @@ input[type=checkbox], input[type=radio] { margin-top: .4em; }
|
||||
.flat-list form {display: inline; }
|
||||
.flat-list .selected a { color: orangered; }
|
||||
|
||||
ul.flat-vert {text-align: left;}
|
||||
.flat-vert .separator { margin: 0 }
|
||||
|
||||
.flat-vert.title {
|
||||
font-family:helvetica,arial,verdana,sans-serif;
|
||||
color: #777;
|
||||
font-size: 18px;
|
||||
font-weight: normal;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.separator { color: gray; margin: 0px .7ex 0px .7ex}
|
||||
|
||||
.pref-lang { font-weight: bold; }
|
||||
@@ -562,6 +568,9 @@ before enabling */
|
||||
.help p, .help form { margin: 5px; }
|
||||
.help form { display: inline; }
|
||||
|
||||
.wikipage {
|
||||
margin: 15px;
|
||||
}
|
||||
|
||||
/* organic listing */
|
||||
.organic-listing {
|
||||
@@ -640,7 +649,7 @@ before enabling */
|
||||
.infobar {
|
||||
background-color: #f6e69f;
|
||||
padding: 5px 10px;
|
||||
margin: 5px 310px 5px 0px;
|
||||
margin: 5px 305px 5px 0px;
|
||||
border: 1px solid orange;
|
||||
font-size: small;
|
||||
}
|
||||
@@ -754,7 +763,7 @@ a.star { text-decoration: none; color: #ff8b60 }
|
||||
}
|
||||
|
||||
/* compressed links */
|
||||
.linkcompressed { margin: 4px 0; overflow: hidden; }
|
||||
.linkcompressed { margin: 4px 0; overflow: hidden; margin-top: 5px; }
|
||||
.linkcompressed .title {margin-bottom: 1px; font-size:medium; font-weight: normal;}
|
||||
.linkcompressed .child h3 {
|
||||
margin: 15px;
|
||||
@@ -765,7 +774,7 @@ a.star { text-decoration: none; color: #ff8b60 }
|
||||
.linkcompressed .score.likes { color: #FF8B60; }
|
||||
.linkcompressed .score.dislikes { color: #9494FF; }
|
||||
.linkcompressed .rank {
|
||||
margin-top: 4px;
|
||||
margin-top: 5px;
|
||||
float:left;
|
||||
color: #c6c6c6;
|
||||
font-family: arial;
|
||||
@@ -780,7 +789,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: #f3f3f3;
|
||||
background-color: #f4f4f4;
|
||||
font-weight: bold
|
||||
}
|
||||
|
||||
@@ -967,23 +976,29 @@ textarea.gray { color: gray; }
|
||||
|
||||
|
||||
/* footer */
|
||||
.footer {
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
clear: both;
|
||||
padding-top: 1em;
|
||||
color: gray;
|
||||
font-size: larger;
|
||||
.footer-parent {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.footer p { margin: 10px }
|
||||
.footer {
|
||||
clear: both;
|
||||
color: gray;
|
||||
font-size: larger;
|
||||
padding: 5px;
|
||||
margin: 15px;
|
||||
border:1px solid #F0F0F0;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.wired a {text-decoration: underline;
|
||||
color: #369;
|
||||
font-size: smaller;
|
||||
padding-left: 5px;
|
||||
padding-right: 5px; }
|
||||
.wired img {vertical-align: middle;}
|
||||
.footer .col {
|
||||
float: left;
|
||||
margin: 10px;
|
||||
padding-left: 10px;
|
||||
border-left: 1px solid #E0E0E0;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.footer .col:first-child {border: none;}
|
||||
|
||||
.server-status { width: 300px; }
|
||||
.server-status table {
|
||||
@@ -1095,6 +1110,7 @@ textarea.gray { color: gray; }
|
||||
|
||||
.status { color: red; }
|
||||
.error { color: red; font-size: small; margin: 5px; }
|
||||
.line-through { text-decoration: line-through }
|
||||
|
||||
#noresults { margin-right: 310px; }
|
||||
|
||||
@@ -1274,7 +1290,7 @@ textarea.gray { color: gray; }
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.bottommenu { color: gray; font-size: smaller; }
|
||||
.bottommenu { color: gray; font-size: smaller; clear: both}
|
||||
.bottommenu a { color: gray; text-decoration: underline; }
|
||||
|
||||
|
||||
|
||||
30
r2/r2/templates/helppage.html
Normal file
30
r2/r2/templates/helppage.html
Normal 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.
|
||||
################################################################################
|
||||
|
||||
<%inherit file="reddit.html"/>
|
||||
|
||||
<%def name="stylesheet()">
|
||||
${parent.stylesheet()}
|
||||
<link rel="stylesheet"
|
||||
type="text/css"
|
||||
href="http://code.reddit.com/chrome/reddit/style.css" />
|
||||
</%def>
|
||||
@@ -57,12 +57,13 @@
|
||||
<%def name="flatlist()">
|
||||
<% css_class = str(thing.css_class) if thing.css_class else "" %>
|
||||
%if thing:
|
||||
%if thing.title:
|
||||
<span class="flat-list title">${thing.title}: </span>
|
||||
%endif
|
||||
|
||||
<ul class="flat-list hover"
|
||||
<ul class="${css_class} hover"
|
||||
${"id='%s'" % thing._id if thing._id else ""}>
|
||||
|
||||
%if thing.title:
|
||||
<li class="${css_class} title">${thing.title}</li>
|
||||
%endif
|
||||
|
||||
%for i, option in enumerate(thing):
|
||||
<%
|
||||
##option.title isn't the title, option.render() is the entire link
|
||||
|
||||
@@ -38,6 +38,12 @@
|
||||
<span class="pagename selected">${thing.title}</span>
|
||||
</%def>
|
||||
|
||||
<%def name="help()">
|
||||
<span class="hover pagename redditname">
|
||||
${plain_link(thing.title, "/help", _sr_path=False)}
|
||||
</span>
|
||||
</%def>
|
||||
|
||||
<%def name="newpagelink()">
|
||||
<span class="newpagelink">reddit all? ${plain_link("click here to find new links.", "/new/", _sr_path=False)}</span>
|
||||
</%def>
|
||||
|
||||
@@ -29,25 +29,24 @@
|
||||
<%namespace file="login.html" import="login_panel, login_form"/>
|
||||
<%namespace file="utils.html" import="text_with_links, plain_link"/>
|
||||
|
||||
<div class="footer">
|
||||
${thing.footer_nav().render()}
|
||||
<div class="footer-parent">
|
||||
<div class="footer rounded">
|
||||
%for toolbar in thing.footer_nav():
|
||||
<div class="col">
|
||||
${toolbar.render()}
|
||||
</div>
|
||||
%endfor
|
||||
|
||||
<p class="wired">
|
||||
<a rel="nofollow" target="_top" href="http://wired.com">
|
||||
<img src="${static('wired_w.png')}" alt="wired" /></a>
|
||||
<a rel="nofollow" target="_top" href="http://wired.com">WIRED.com</a>-
|
||||
<a rel="nofollow" target="_top" href="http://howto.wired.com">WIRED How-To</a>
|
||||
</p>
|
||||
<p class="bottommenu">
|
||||
${text_with_links(_("Use of this site constitutes acceptance of our %(user_agreement)s and %(privacy_policy)s"), nocname=True, user_agreement= (_("User Agreement {Genitive}"), "http://reddit.com/help/useragreement"), privacy_policy = (_("Privacy Policy {Genitive}"), "http://reddit.com/help/privacypolicy"))}.
|
||||
${_("(c) %(year)d CondeNet, Inc. All rights reserved.") % \
|
||||
dict(year=datetime.datetime.now().timetuple()[0])}
|
||||
</p>
|
||||
%if g.tracker_url and thing.site_tracking:
|
||||
<img alt="" src="${tracking.UserInfo.gen_url()}"/>
|
||||
%endif
|
||||
<p class="bottommenu">
|
||||
${text_with_links(_("Use of this site constitutes acceptance of our %(user_agreement)s and %(privacy_policy)s"), nocname=True, user_agreement= (_("User Agreement {Genitive}"), "http://reddit.com/help/useragreement"), privacy_policy = (_("Privacy Policy {Genitive}"), "http://reddit.com/help/privacypolicy"))}.
|
||||
${_("(c) %(year)d CondeNet, Inc. All rights reserved.") % \
|
||||
dict(year=datetime.datetime.now().timetuple()[0])}
|
||||
</p>
|
||||
%if g.tracker_url and thing.site_tracking:
|
||||
<img alt="" src="${tracking.UserInfo.gen_url()}"/>
|
||||
%endif
|
||||
</div>
|
||||
</div>
|
||||
|
||||
%if not c.user_is_loggedin:
|
||||
%if thing.enable_login_cover:
|
||||
${self.loginpopup(login_panel, login_form)}
|
||||
|
||||
Reference in New Issue
Block a user