mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-01-15 01:48:18 -05:00
Add feature-flagged newsletter bar to the logged-out homepage.
This commit is contained in:
@@ -296,6 +296,23 @@ class ApiController(RedditController):
|
||||
# Pylons does not handle 204s correctly.
|
||||
return {}
|
||||
|
||||
@json_validate(
|
||||
VModhashIfLoggedIn(),
|
||||
VRatelimit(rate_ip=True, prefix="rate_newsletter_"),
|
||||
email=ValidEmail("email"),
|
||||
)
|
||||
def POST_newsletter(self, responder, email):
|
||||
"""Add an email to our newsletter."""
|
||||
|
||||
VRatelimit.ratelimit(rate_ip=True,
|
||||
prefix="rate_newsletter_")
|
||||
|
||||
try:
|
||||
newsletter.add_subscriber(email, source="newsletterbar")
|
||||
except newsletter.NewsletterError as e:
|
||||
g.log.warning("Failed to subscribe: %r" % e)
|
||||
abort(500)
|
||||
|
||||
@allow_oauth2_access
|
||||
@json_validate()
|
||||
@api_doc(api_section.captcha)
|
||||
|
||||
@@ -496,6 +496,7 @@ module["reddit"] = LocalizedModule("reddit.js",
|
||||
"ui.js",
|
||||
"popup.js",
|
||||
"login.js",
|
||||
"newsletter.js",
|
||||
"flair.js",
|
||||
"interestbar.js",
|
||||
"visited.js",
|
||||
|
||||
@@ -262,6 +262,7 @@ class Reddit(Templated):
|
||||
|
||||
#add the infobar
|
||||
self.welcomebar = None
|
||||
self.newsletterbar = None
|
||||
self.locationbar = None
|
||||
self.infobar = None
|
||||
# generate a canonical link for google
|
||||
@@ -304,6 +305,8 @@ class Reddit(Templated):
|
||||
|
||||
if not c.user_is_loggedin:
|
||||
self.welcomebar = WelcomeBar()
|
||||
if feature.is_enabled('newsletter') and getattr(self, "show_newsletterbar", True):
|
||||
self.newsletterbar = NewsletterBar()
|
||||
|
||||
show_locationbar &= not c.user.pref_hide_locationbar
|
||||
if (show_locationbar and c.used_localized_defaults and
|
||||
@@ -824,9 +827,17 @@ class Reddit(Templated):
|
||||
|
||||
def content(self):
|
||||
"""returns a Wrapped (or renderable) item for the main content div."""
|
||||
if self.newsletterbar:
|
||||
self.welcomebar = None
|
||||
|
||||
return self.content_stack((
|
||||
self.welcomebar, self.infobar, self.locationbar, self.nav_menu,
|
||||
self._content))
|
||||
self.welcomebar,
|
||||
self.newsletterbar,
|
||||
self.infobar,
|
||||
self.locationbar,
|
||||
self.nav_menu,
|
||||
self._content,
|
||||
))
|
||||
|
||||
def is_gold_page(self):
|
||||
return "gold-page-ga-tracking" in self.supplied_page_classes
|
||||
@@ -2294,6 +2305,9 @@ class WelcomeBar(InfoBar):
|
||||
_("where your votes shape what the world is talking about."))
|
||||
InfoBar.__init__(self, message=message)
|
||||
|
||||
class NewsletterBar(InfoBar):
|
||||
pass
|
||||
|
||||
class ClientInfoBar(InfoBar):
|
||||
"""Draws the message the top of a login page before OAuth2 authorization"""
|
||||
def __init__(self, client, *args, **kwargs):
|
||||
|
||||
@@ -39,3 +39,7 @@
|
||||
.c-btn-primary {
|
||||
.button-variant(@text-color: #fff; @bg-color: #4f86b5; @bevel-color: #4270a2);
|
||||
}
|
||||
|
||||
.c-btn-highlight {
|
||||
.button-variant(@text-color: #fff; @bg-color: #DC6431; @bevel-color: #C9532B);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
.c-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.c-clearfix {
|
||||
.clearfix();
|
||||
}
|
||||
|
||||
@@ -126,6 +126,9 @@ h3 { font-size:110%; /*text-transform:uppercase;*/ }
|
||||
a img { border: 0 none; }
|
||||
a { text-decoration: none; color: #369; }
|
||||
|
||||
/* Polyfill for HTML5 hidden attribute: http://caniuse.com/#feat=hidden */
|
||||
[hidden] { display: none; }
|
||||
|
||||
/*
|
||||
a:active { border: 0 none;}
|
||||
a:focus { -moz-outline-style: none; }
|
||||
@@ -1847,6 +1850,104 @@ body.with-listing-chooser.explore-page #header .pagename {
|
||||
border-bottom: 1px solid #a73a11;
|
||||
}
|
||||
|
||||
.infobar.newsletterbar {
|
||||
.box-sizing(border-box);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: 80px;
|
||||
padding: 15px 20px 20px;
|
||||
border: none;
|
||||
border-radius: 2px;
|
||||
background-color: #30659B;
|
||||
|
||||
header {
|
||||
float: left;
|
||||
height: 45px;
|
||||
width: 325px;
|
||||
}
|
||||
|
||||
a.newsletter-close {
|
||||
position: absolute;
|
||||
right: 3px;
|
||||
top: 0;
|
||||
font-size: 11px;
|
||||
color: #CCC;
|
||||
}
|
||||
|
||||
form {
|
||||
margin-left: 340px;
|
||||
margin-right: 150px;
|
||||
max-width: 400px;
|
||||
min-width: 150px;
|
||||
line-height: 45px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
&.success {
|
||||
header {
|
||||
padding-left: 65px;
|
||||
|
||||
&:before {
|
||||
content: "✓";
|
||||
color: #80d654;
|
||||
font-weight: bold;
|
||||
font-size: 60px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin: 0;
|
||||
|
||||
a:hover {
|
||||
border-bottom: 1px dotted #999;
|
||||
}
|
||||
}
|
||||
|
||||
h2 {
|
||||
color: white;
|
||||
font-weight: normal;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.c-form-group {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Display error-feedback indicator inside the input */
|
||||
.c-form-control-feedback-wrapper {
|
||||
margin-left: -30px;
|
||||
top: 5px;
|
||||
}
|
||||
|
||||
input[type="email"] {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
button {
|
||||
.button-size(@padding-base-vertical; @padding-base-horizontal; 12px; 20px; 3px);
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: @screen-md-min) {
|
||||
header {
|
||||
float: none;
|
||||
}
|
||||
|
||||
form {
|
||||
margin: 10px 0 0;
|
||||
}
|
||||
|
||||
.c-form-group {
|
||||
max-width: 50%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.locationbar {
|
||||
margin: 5px;
|
||||
|
||||
|
||||
@@ -124,6 +124,7 @@ $(function() {
|
||||
r.saved.init()
|
||||
r.messages.init()
|
||||
r.filter.init()
|
||||
r.newsletter.ui.init()
|
||||
} catch (err) {
|
||||
r.sendError('Error during base.js init', err)
|
||||
}
|
||||
|
||||
84
r2/r2/public/static/js/newsletter.js
Normal file
84
r2/r2/public/static/js/newsletter.js
Normal file
@@ -0,0 +1,84 @@
|
||||
r.newsletter = {
|
||||
post: function(form) {
|
||||
var email = $('input[name="email"]', form.$el).val();
|
||||
var apiTarget = form.$el.attr('action');
|
||||
|
||||
var params = form.serialize();
|
||||
params.push({name:'api_type', value:'json'});
|
||||
|
||||
return r.ajax({
|
||||
url: apiTarget,
|
||||
type: 'POST',
|
||||
dataType: 'json',
|
||||
data: params,
|
||||
xhrFields: {
|
||||
withCredentials: true
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
r.newsletter.ui = {
|
||||
init: function() {
|
||||
var newsletterBarSeen = !!store.get('newsletterbar.seen');
|
||||
|
||||
if (newsletterBarSeen || $('.newsletterbar').length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$('.newsletterbar').show();
|
||||
|
||||
$('.newsletter-signup').each(function(i, el) {
|
||||
new r.newsletter.ui.NewsletterForm(el)
|
||||
})
|
||||
|
||||
$('.newsletter-close').on('click', function() {
|
||||
$('.newsletterbar').addClass('c-hidden');
|
||||
});
|
||||
|
||||
store.set('newsletterbar.seen', true);
|
||||
},
|
||||
};
|
||||
|
||||
r.newsletter.ui.NewsletterForm = function() {
|
||||
r.ui.Form.apply(this, arguments)
|
||||
};
|
||||
|
||||
r.newsletter.ui.NewsletterForm.prototype = $.extend(new r.ui.Form(), {
|
||||
showStatus: function() {
|
||||
this.$el.find('.error').css('opacity', 1)
|
||||
r.ui.Form.prototype.showStatus.apply(this, arguments)
|
||||
},
|
||||
|
||||
_submit: function() {
|
||||
r.analytics.fireGAEvent('newsletter-form', 'submit');
|
||||
return r.newsletter.post(this);
|
||||
},
|
||||
|
||||
_showSuccess: function() {
|
||||
var parentEl = this.$el.parents('.newsletterbar');
|
||||
parentEl.find('.result-message').text(r._('you\'ll get your first newsletter soon'));
|
||||
parentEl.addClass('success');
|
||||
parentEl.find('header').fadeTo(250, 1);
|
||||
},
|
||||
|
||||
_handleResult: function(result) {
|
||||
if (result.json.errors.length) {
|
||||
r.ui.Form.prototype._handleResult.call(this, result);
|
||||
}
|
||||
|
||||
var parentEl = this.$el.parents('.newsletterbar');
|
||||
var calloutImg = parentEl.find('.subscribe-callout img');
|
||||
var thanksImg = $('<img />').attr('src', calloutImg.data('thanks-src'))
|
||||
.attr('alt', r._('thanks for subscribing'));
|
||||
|
||||
parentEl.find('header, form').fadeTo(250, 0, function() {
|
||||
calloutImg.hide().after(thanksImg);
|
||||
if (thanksImg.get(0).complete) {
|
||||
this._showSuccess();
|
||||
} else {
|
||||
thanksImg.one("load", this._showSuccess);
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
})
|
||||
@@ -255,9 +255,13 @@ r.ui.Form = function(el) {
|
||||
$(this).stateify('set', 'success');
|
||||
})
|
||||
.on('invalid.validator', function(e, resp) {
|
||||
var error = r.utils.parseError(resp.errors[0]);
|
||||
// resp may not always be set if client side validation triggered, like
|
||||
// from input type=email
|
||||
if (resp) {
|
||||
var error = r.utils.parseError(resp.errors[0]);
|
||||
|
||||
$(this).stateify('set', 'error', error.message);
|
||||
$(this).stateify('set', 'error', error.message);
|
||||
}
|
||||
})
|
||||
.on('loading.validator', function(e) {
|
||||
$(this).stateify('set', 'loading');
|
||||
|
||||
1
r2/r2/public/static/subscribe-header-thanks.svg
Normal file
1
r2/r2/public/static/subscribe-header-thanks.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.5 KiB |
1
r2/r2/public/static/subscribe-header.svg
Normal file
1
r2/r2/public/static/subscribe-header.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.9 KiB |
50
r2/r2/templates/newsletterbar.html
Normal file
50
r2/r2/templates/newsletterbar.html
Normal file
@@ -0,0 +1,50 @@
|
||||
## 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 reddit Inc.
|
||||
##
|
||||
## All portions of the code written by reddit are Copyright (c) 2006-2015
|
||||
## reddit Inc. All Rights Reserved.
|
||||
###############################################################################
|
||||
|
||||
<%!
|
||||
from r2.lib.template_helpers import static
|
||||
%>
|
||||
<%namespace file="utils.html" import="form_group" />
|
||||
|
||||
<section hidden class="infobar newsletterbar">
|
||||
<header>
|
||||
<h1 class="subscribe-callout">
|
||||
<a href="/newsletter"><img src="${static('subscribe-header.svg')}" data-thanks-src="${static('subscribe-header-thanks.svg')}" alt="${_('subscribe to our newsletter')}"></a>
|
||||
</h1>
|
||||
<h2 class="result-message">${_('get the best of reddit, delivered once a week')}</h2>
|
||||
</header>
|
||||
<form class="newsletter-signup form-v2" method="post" action="/api/newsletter.json">
|
||||
<%call expr="form_group('email', 'BAD_EMAIL', show_errors=True)">
|
||||
<label for="email" class="screenreader-only">${_('email')}:</label>
|
||||
<input value=""
|
||||
name="email"
|
||||
class="c-form-control"
|
||||
type="email"
|
||||
placeholder="${_('enter your email')}"
|
||||
data-validate-url="/api/check_email.json"
|
||||
data-validate-on="change blur">
|
||||
</%call>
|
||||
|
||||
<button type="submit" class="c-btn c-btn-highlight">${_('subscribe')}</button>
|
||||
</form>
|
||||
<a href="#" class="newsletter-close" title="close">×</a>
|
||||
</section>
|
||||
Reference in New Issue
Block a user