diff --git a/r2/example.ini b/r2/example.ini
index c9fd46796..73c011969 100644
--- a/r2/example.ini
+++ b/r2/example.ini
@@ -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
diff --git a/r2/r2/controllers/embed.py b/r2/r2/controllers/embed.py
index 246a71186..f87908d2b 100644
--- a/r2/r2/controllers/embed.py
+++ b/r2/r2/controllers/embed.py
@@ -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(""):
- 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 = """
+
+ """ % (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/")
diff --git a/r2/r2/controllers/front.py b/r2/r2/controllers/front.py
index 4abd05c0f..4afe9f0fb 100644
--- a/r2/r2/controllers/front.py
+++ b/r2/r2/controllers/front.py
@@ -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
diff --git a/r2/r2/lib/app_globals.py b/r2/r2/lib/app_globals.py
index 91e7f3837..86b850d80 100644
--- a/r2/r2/lib/app_globals.py
+++ b/r2/r2/lib/app_globals.py
@@ -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',
diff --git a/r2/r2/lib/base.py b/r2/r2/lib/base.py
index bf157c14e..2852585de 100644
--- a/r2/r2/lib/base.py
+++ b/r2/r2/lib/base.py
@@ -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 == '_']
-
diff --git a/r2/r2/lib/c/filters.c b/r2/r2/lib/c/filters.c
index bea411609..ba8a5427e 100644
--- a/r2/r2/lib/c/filters.c
+++ b/r2/r2/lib/c/filters.c
@@ -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 = "";
-const char *MD_END = "
";
-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 = "";
+const char *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);
}
diff --git a/r2/r2/lib/filters.py b/r2/r2/lib/filters.py
index e93607a86..c29a17a1f 100644
--- a/r2/r2/lib/filters.py
+++ b/r2/r2/lib/filters.py
@@ -25,8 +25,9 @@ import cgi
import urllib
import re
-MD_START = ''
-MD_END = '
'
+SC_OFF = ""
+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 + '' + text + '
' + SC_ON
def keep_space(text):
diff --git a/r2/r2/lib/menus.py b/r2/r2/lib/menus.py
index f79867301..9ba3f9968 100644
--- a/r2/r2/lib/menus.py
+++ b/r2/r2/lib/menus.py
@@ -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
diff --git a/r2/r2/lib/pages/pages.py b/r2/r2/lib/pages/pages.py
index 27e20c493..7f6f79128 100644
--- a/r2/r2/lib/pages/pages.py
+++ b/r2/r2/lib/pages/pages.py
@@ -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"""
diff --git a/r2/r2/models/account.py b/r2/r2/models/account.py
index aedfc74ff..b8d9117f6 100644
--- a/r2/r2/models/account.py
+++ b/r2/r2/models/account.py
@@ -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)"""
diff --git a/r2/r2/public/static/css/reddit.css b/r2/r2/public/static/css/reddit.css
index 53e6d6b58..0ecf7bbd9 100644
--- a/r2/r2/public/static/css/reddit.css
+++ b/r2/r2/public/static/css/reddit.css
@@ -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; }
diff --git a/r2/r2/templates/helppage.html b/r2/r2/templates/helppage.html
new file mode 100644
index 000000000..b16ef765a
--- /dev/null
+++ b/r2/r2/templates/helppage.html
@@ -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()}
+
+%def>
diff --git a/r2/r2/templates/navmenu.html b/r2/r2/templates/navmenu.html
index 1dd1bacff..3e060d4ad 100644
--- a/r2/r2/templates/navmenu.html
+++ b/r2/r2/templates/navmenu.html
@@ -57,12 +57,13 @@
<%def name="flatlist()">
<% css_class = str(thing.css_class) if thing.css_class else "" %>
%if thing:
- %if thing.title:
- ${thing.title}:
- %endif
-
-
+
+ %if thing.title:
+ - ${thing.title}
+ %endif
+
%for i, option in enumerate(thing):
<%
##option.title isn't the title, option.render() is the entire link
diff --git a/r2/r2/templates/pagenamenav.html b/r2/r2/templates/pagenamenav.html
index 68293d1fb..8e4ad4239 100644
--- a/r2/r2/templates/pagenamenav.html
+++ b/r2/r2/templates/pagenamenav.html
@@ -38,6 +38,12 @@
${thing.title}
%def>
+<%def name="help()">
+
+ ${plain_link(thing.title, "/help", _sr_path=False)}
+
+%def>
+
<%def name="newpagelink()">
reddit all? ${plain_link("click here to find new links.", "/new/", _sr_path=False)}
%def>
diff --git a/r2/r2/templates/redditfooter.html b/r2/r2/templates/redditfooter.html
index a09728b35..508094364 100644
--- a/r2/r2/templates/redditfooter.html
+++ b/r2/r2/templates/redditfooter.html
@@ -29,25 +29,24 @@
<%namespace file="login.html" import="login_panel, login_form"/>
<%namespace file="utils.html" import="text_with_links, plain_link"/>
-