mirror of
https://github.com/reddit-archive/reddit.git
synced 2026-04-27 03:00:12 -04:00
Comment embeds: add UI for creating embed code
This commit is contained in:
@@ -254,7 +254,7 @@ class FrontController(RedditController):
|
||||
#check for 304
|
||||
self.check_modified(article, 'comments')
|
||||
|
||||
embeds.setup_embed()
|
||||
embeds.setup_embed(thing=comment)
|
||||
|
||||
# If there is a focal comment, communicate down to
|
||||
# comment_skeleton.html who that will be. Also, skip
|
||||
|
||||
@@ -1,20 +1,34 @@
|
||||
from pylons import c, g, request
|
||||
from pylons.controllers.util import abort
|
||||
|
||||
from r2.controllers.reddit_base import (
|
||||
get_browser_langs,
|
||||
UnloggedUser,
|
||||
)
|
||||
from r2.controllers.reddit_base import UnloggedUser
|
||||
from r2.models.subreddit import Subreddit
|
||||
|
||||
def setup_embed():
|
||||
|
||||
DISALLOWED_SR_TYPES = {"private", "gold_restricted"}
|
||||
|
||||
|
||||
def can_embed(thing):
|
||||
try:
|
||||
sr = Subreddit._byID(thing.sr_id) if thing.sr_id else None
|
||||
except NotFound:
|
||||
sr = None
|
||||
|
||||
return (sr != None and not sr.type in DISALLOWED_SR_TYPES)
|
||||
|
||||
|
||||
def setup_embed(thing):
|
||||
if request.GET.get("embed") == "true":
|
||||
if request.host != g.media_domain:
|
||||
# don't serve up untrusted content except on our
|
||||
# specifically untrusted domain
|
||||
abort(404)
|
||||
|
||||
if not can_embed(thing):
|
||||
abort(404)
|
||||
|
||||
c.render_style = "iframe"
|
||||
c.user = UnloggedUser(get_browser_langs())
|
||||
c.user = UnloggedUser([c.lang])
|
||||
c.user_is_loggedin = False
|
||||
c.forced_loggedout = True
|
||||
c.allow_framing = True
|
||||
|
||||
@@ -493,8 +493,13 @@ module["reddit"] = LocalizedModule("reddit.js",
|
||||
"filter.js",
|
||||
"recommender.js",
|
||||
"action-forms.js",
|
||||
"embed.js",
|
||||
"saved.js",
|
||||
"messages.js",
|
||||
"embed/custom-event.js",
|
||||
"embed/utils.js",
|
||||
"embed/post-message.js",
|
||||
"embed/comment-embed.js",
|
||||
PermissionsDataSource({
|
||||
"moderator": ModeratorPermissionSet,
|
||||
"moderator_invite": ModeratorPermissionSet,
|
||||
|
||||
@@ -310,6 +310,8 @@ class Reddit(Templated):
|
||||
if srbar and not c.cname and not is_api():
|
||||
self.srtopbar = SubredditTopBar()
|
||||
|
||||
panes = [content]
|
||||
|
||||
if c.user_is_loggedin and not is_api() and not self.show_wiki_actions:
|
||||
# insert some form templates for js to use
|
||||
# TODO: move these to client side templates
|
||||
@@ -337,16 +339,15 @@ class Reddit(Templated):
|
||||
)
|
||||
report_form = ReportForm()
|
||||
|
||||
panes = [ShareLink(), content, report_form]
|
||||
panes.extend([ShareLink(), report_form])
|
||||
|
||||
if self.show_sidebar:
|
||||
panes.extend([gold_comment, gold_link])
|
||||
|
||||
if c.user_is_sponsor:
|
||||
panes.append(FraudForm())
|
||||
|
||||
self._content = PaneStack(panes)
|
||||
else:
|
||||
self._content = content
|
||||
self._content = PaneStack(panes)
|
||||
|
||||
self.show_chooser = (
|
||||
show_chooser and
|
||||
|
||||
@@ -21,7 +21,12 @@
|
||||
###############################################################################
|
||||
|
||||
from r2.lib.db.thing import NotFound
|
||||
from r2.lib.menus import Styled
|
||||
from r2.lib.menus import (
|
||||
JsButton,
|
||||
NavButton,
|
||||
NavMenu,
|
||||
Styled,
|
||||
)
|
||||
from r2.lib.wrapped import Wrapped
|
||||
from r2.models import LinkListing, Link, PromotedLink, Report
|
||||
from r2.models import make_wrapper, IDBuilder, Thing
|
||||
@@ -166,6 +171,22 @@ class CommentButtons(PrintableButtons):
|
||||
|
||||
show_givegold = thing.can_gild
|
||||
|
||||
embed_button = False
|
||||
|
||||
from r2.lib import embeds
|
||||
if embeds.can_embed(thing):
|
||||
embed_button = JsButton("embed",
|
||||
css_class="embed-comment",
|
||||
data={
|
||||
"media": g.media_domain or g.domain,
|
||||
"comment": thing.permalink,
|
||||
"link": thing.link.make_permalink(thing.subreddit),
|
||||
"title": thing.link.title,
|
||||
"root": ("true" if thing.parent_id is None else "false"),
|
||||
})
|
||||
|
||||
embed_button.build()
|
||||
|
||||
PrintableButtons.__init__(self, "commentbuttons", thing,
|
||||
can_save=thing.can_save,
|
||||
is_author = is_author,
|
||||
@@ -179,12 +200,13 @@ class CommentButtons(PrintableButtons):
|
||||
parent_permalink = thing.parent_permalink,
|
||||
can_reply = thing.can_reply,
|
||||
suppress_reply_buttons = suppress_reply_buttons,
|
||||
show_report = show_report,
|
||||
show_report=show_report,
|
||||
mod_reports=thing.mod_reports,
|
||||
user_reports=thing.user_reports,
|
||||
show_distinguish = show_distinguish,
|
||||
show_delete = show_delete,
|
||||
show_givegold=show_givegold,
|
||||
embed_button=embed_button,
|
||||
)
|
||||
|
||||
class MessageButtons(PrintableButtons):
|
||||
|
||||
@@ -184,6 +184,7 @@ def js_config(extra_config=None):
|
||||
"adtracker_url": g.adtracker_url,
|
||||
"clicktracker_url": g.clicktracker_url,
|
||||
"uitracker_url": g.uitracker_url,
|
||||
"comment_embed_scripts": js.src("comment-embed", absolute=True),
|
||||
"static_root": static(''),
|
||||
"over_18": bool(c.over18),
|
||||
"new_window": bool(c.user.pref_newwindow),
|
||||
|
||||
@@ -18,6 +18,10 @@
|
||||
}
|
||||
|
||||
.input-placeholder();
|
||||
|
||||
textarea& {
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
|
||||
.c-form-group {
|
||||
@@ -30,7 +34,6 @@
|
||||
position: relative;
|
||||
display: block;
|
||||
font-size: 12px;
|
||||
min-height: @input-height-base;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
@@ -47,7 +50,8 @@
|
||||
line-height: normal;
|
||||
position: absolute;
|
||||
margin-left: -21px;
|
||||
margin-top: 4px \9;
|
||||
margin-top: 0;
|
||||
margin-top: 4px \9; // ie hack
|
||||
|
||||
&:focus {
|
||||
outline: thin dotted;
|
||||
|
||||
@@ -82,7 +82,7 @@ p {
|
||||
list-style: none;
|
||||
margin-top: 36px;
|
||||
|
||||
.reddit-embed-content > .reddit-embed-list > & {
|
||||
.reddit-embed-content > .reddit-embed-list > &:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10551,3 +10551,24 @@ body.banned.deleted div#header {
|
||||
#compose-message select {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
#embed-preview {
|
||||
margin: -5px;
|
||||
margin-bottom: 0;
|
||||
overflow-y: hidden;
|
||||
|
||||
// re-add margin to non-iframed version
|
||||
.reddit-embed {
|
||||
margin: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.more-actions {
|
||||
.title {
|
||||
color: #888;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,11 @@ r.actionForm = {
|
||||
e.preventDefault();
|
||||
|
||||
if ($thingForm.length > 0) {
|
||||
$thingForm.toggle();
|
||||
if ($el.parents('.drop-choices').length) {
|
||||
$thingForm.show();
|
||||
} else {
|
||||
$thingForm.toggle();
|
||||
}
|
||||
} else {
|
||||
var $form = $(formSelector);
|
||||
var $clonedForm = $form.clone();
|
||||
|
||||
142
r2/r2/public/static/js/embed.js
Normal file
142
r2/r2/public/static/js/embed.js
Normal file
@@ -0,0 +1,142 @@
|
||||
;(function($, undefined) {
|
||||
var COMMENT_EMBED_SCRIPTS = r.config.comment_embed_scripts.map(function (src) {
|
||||
var attrs = r.config.comment_embed_scripts.length === 1 ? 'async' : '';
|
||||
|
||||
return '<script ' + attrs + ' src="' + src + '"></script>';
|
||||
}).join('');
|
||||
var commentModalTemplate = _.template(
|
||||
'<div class="modal fade" tabindex="-1" role="dialog">' +
|
||||
'<div class="modal-dialog modal-dialog-lg">' +
|
||||
'<div class="modal-content">' +
|
||||
'<div class="modal-header">' +
|
||||
'<a href="javascript: void 0;" class="c-close c-hide-text" data-dismiss="modal">' +
|
||||
_.escape(r._('close this window')) +
|
||||
'</a>' +
|
||||
'</div>' +
|
||||
'<div class="modal-body">' +
|
||||
'<h4 class="modal-title">' +
|
||||
_.escape(r._('Embed preview:')) +
|
||||
'</h4>' +
|
||||
'<div id="embed-preview">' +
|
||||
'<%= html %>' +
|
||||
'</div>' +
|
||||
'<% if (!root) { %>' +
|
||||
'<div class="c-checkbox">' +
|
||||
'<label class="remember">' +
|
||||
'<input type="checkbox" name="parent" <% if (parent) { %> checked <% } %>>' +
|
||||
_.escape(r._('Include parent comment.')) +
|
||||
'</label>' +
|
||||
'</div>' +
|
||||
'<% } %>' +
|
||||
'<div class="c-checkbox">' +
|
||||
'<label>' +
|
||||
'<input type="checkbox" name="live" <% if (!live) { %> checked <% } %> data-rerender="false">' +
|
||||
_.escape(r._('Do not show comment if edited.')) +
|
||||
' ' +
|
||||
'<a href="/help/embed#live-update">' +
|
||||
_.escape(r._('Learn more')) +
|
||||
'</a>' +
|
||||
'</label>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'<div class="modal-footer">' +
|
||||
'<div class="c-form-group">' +
|
||||
'<label for="embed-code" class="modal-title">' +
|
||||
_.escape(r._('Copy this code and paste it into your website:')) +
|
||||
'</label>' +
|
||||
'<textarea class="c-form-control" id="embed-code" rows="3" readonly>' +
|
||||
'<%= html %>' +
|
||||
'<%- scripts %>' +
|
||||
'</textarea>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>' +
|
||||
'</div>'
|
||||
);
|
||||
var embedCodeTemplate = _.template(
|
||||
'<div class="reddit-embed" ' +
|
||||
' data-embed-media="<%- media %>" ' +
|
||||
'<% if (parent) { %> data-embed-parent="true" <% } %>' +
|
||||
'<% if (live) { %> data-embed-live="true" <% } %>' +
|
||||
' data-embed-created="<%- new Date().toISOString() %>">' +
|
||||
'<a href="<%- comment %>">Comment</a> from discussion <a href="<%- link %>"><%- title %></a>.' +
|
||||
'</div>'
|
||||
);
|
||||
|
||||
function absolute(url) {
|
||||
if (/^https?:\/\//.test(url)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return 'https://' + location.host + '/' + (url.replace(/^\//, ''));
|
||||
}
|
||||
|
||||
function getEmbedOptions(data) {
|
||||
var defaults = {
|
||||
live: true,
|
||||
parent: false,
|
||||
media: location.host,
|
||||
};
|
||||
|
||||
data = _.defaults({}, data, defaults);
|
||||
data.comment = absolute(data.comment);
|
||||
data.link = absolute(data.link);
|
||||
|
||||
return _.extend({
|
||||
html: embedCodeTemplate(data),
|
||||
scripts: COMMENT_EMBED_SCRIPTS,
|
||||
}, data);
|
||||
}
|
||||
|
||||
$('body').on('click', '.embed-comment', function(e) {
|
||||
var $el = $(e.target);
|
||||
var data = $el.data();
|
||||
var $dialog = $(commentModalTemplate(getEmbedOptions(data)));
|
||||
var $textarea = $dialog.find('textarea');
|
||||
var $preview = $dialog.find('#embed-preview');
|
||||
|
||||
$dialog.on('change', '[type="checkbox"]', function(e) {
|
||||
var option = e.target.name;
|
||||
var $option = $(e.target);
|
||||
var prev = $el.data(option);
|
||||
|
||||
if (prev === undefined) {
|
||||
prev = embedOptions[option]
|
||||
}
|
||||
|
||||
$el.data(e.target.name, !prev);
|
||||
|
||||
var data = $el.data();
|
||||
var options = getEmbedOptions(data);
|
||||
var html = options.html;
|
||||
var height = $preview.height();
|
||||
|
||||
$textarea.val(html + options.scripts);
|
||||
|
||||
if ($option.data('rerender') !== false) {
|
||||
$preview.height(height).html(html);
|
||||
|
||||
window.rembeddit.init(function () {
|
||||
$preview.css({height: 'auto'});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$textarea.on('focus', function() {
|
||||
$(this).select();
|
||||
});
|
||||
|
||||
$dialog.on('hidden.bs.modal', function() {
|
||||
$dialog.remove();
|
||||
});
|
||||
|
||||
$dialog.on('shown.bs.modal', function() {
|
||||
window.rembeddit.init();
|
||||
});
|
||||
|
||||
$dialog.modal();
|
||||
|
||||
});
|
||||
|
||||
})(window.jQuery);
|
||||
@@ -1,10 +1,11 @@
|
||||
;(function(App, window, undefined) {
|
||||
|
||||
var RE_COMMENT = /(?:https?\:)?(\/\/(?:www\.)?reddit\.(?:com|local)(?:\:\d+)?\/r\/[\w_]+\/comments\/(?:[\w_]+\/){2,}[\w_]+\/?)/i;
|
||||
var RE_ABS = /^https?:\/\//i;
|
||||
var RE_COMMENT = /\/?r\/[\w_]+\/comments\/(?:[\w_]+\/){2,}[\w_]+\/?/i;
|
||||
var PROTOCOL = location.protocol === 'file:' ? 'https:' : '';
|
||||
|
||||
function isComment(url) {
|
||||
return typeof url === 'string' && RE_COMMENT.test(url);
|
||||
function isComment(anchor) {
|
||||
return RE_ABS.test(anchor.href) && RE_COMMENT.test(anchor.pathname);
|
||||
}
|
||||
|
||||
function getCommentPathname(anchor) {
|
||||
@@ -30,13 +31,14 @@
|
||||
context++;
|
||||
}
|
||||
|
||||
var query = 'context=' + context +
|
||||
var query = 'embed=true' +
|
||||
'&context=' + context +
|
||||
'&depth=' + (++context) +
|
||||
'&showedits=' + data.embedLive +
|
||||
'&created=' + data.embedCreated +
|
||||
'&showmore=false';
|
||||
|
||||
return PROTOCOL + (commentUrl.replace(/\/$/,'')) + '.iframe?' + query;
|
||||
return PROTOCOL + (commentUrl.replace(/\/$/,'')) + '?' + query;
|
||||
}
|
||||
|
||||
App.init = function(callback) {
|
||||
@@ -46,7 +48,6 @@
|
||||
var iframe = document.createElement('iframe');
|
||||
var anchors = embed.getElementsByTagName('a');
|
||||
var commentUrl = getCommentUrl(anchors, embed.dataset.embedMedia);
|
||||
var loaded = false;
|
||||
|
||||
if (!commentUrl) {
|
||||
return;
|
||||
@@ -59,18 +60,24 @@
|
||||
iframe.style.display = 'none';
|
||||
iframe.src = getEmbedUrl(commentUrl, embed.dataset);
|
||||
|
||||
App.receiveMessage('resize', function(e) {
|
||||
iframe.height = (e.detail + 'px');
|
||||
iframe.style.display = 'block';
|
||||
|
||||
if (!loaded) {
|
||||
loaded = true;
|
||||
|
||||
callback && callback(e);
|
||||
}
|
||||
App.receiveMessageOnce('loaded', function() {
|
||||
embed.parentNode.removeChild(embed);
|
||||
callback && callback(e);
|
||||
});
|
||||
|
||||
embed.parentNode.replaceChild(iframe, embed);
|
||||
var resizer = App.receiveMessage('resize', function(e) {
|
||||
if (!iframe.parentNode) {
|
||||
resizer.off();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
iframe.height = (e.detail + 'px');
|
||||
iframe.style.display = 'block';
|
||||
});
|
||||
|
||||
|
||||
embed.parentNode.insertBefore(iframe, embed);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
|
||||
function compileOriginRegExp(origins) {
|
||||
return new RegExp('http(s)?:\\/\\/' + origins.join('|'), 'i');
|
||||
return new RegExp('^http(s)?:\\/\\/' + origins.join('|'), 'i');
|
||||
}
|
||||
|
||||
function isWildcard(origin) {
|
||||
@@ -53,6 +53,16 @@
|
||||
};
|
||||
},
|
||||
|
||||
receiveMessageOnce: function(type, callback, context) {
|
||||
var listener = App.receiveMessage(type, function() {
|
||||
callback && callback();
|
||||
|
||||
listener.off();
|
||||
}, context);
|
||||
|
||||
return listener;
|
||||
},
|
||||
|
||||
addPostMessageOrigin: function(origin) {
|
||||
if (isWildcard(origin)) {
|
||||
allowedOrigins = [ALLOW_WILDCARD];
|
||||
|
||||
@@ -9,6 +9,11 @@ function open_menu(menu) {
|
||||
.addClass("active inuse");
|
||||
};
|
||||
|
||||
function close_menu(item) {
|
||||
$(item).closest('.drop-choices')
|
||||
.removeClass('active inuse');
|
||||
}
|
||||
|
||||
function close_menus(event) {
|
||||
$(".drop-choices.inuse").not(".active")
|
||||
.removeClass("inuse");
|
||||
|
||||
@@ -171,7 +171,7 @@ r.saved.SaveButton = {
|
||||
r.saved.categories = new r.saved.SaveCategories()
|
||||
|
||||
r.saved.init = function() {
|
||||
$('body').on('click', '.save-button a', function(e) {
|
||||
$('body').on('click', '.save-button a, a.save-button', function(e) {
|
||||
e.stopPropagation()
|
||||
e.preventDefault()
|
||||
r.saved.SaveButton.toggleSaved($(this))
|
||||
|
||||
@@ -333,16 +333,21 @@
|
||||
<li class="first">
|
||||
${self.bylink_button(_("permalink"), thing.permalink)}
|
||||
</li>
|
||||
%if thing.embed_button:
|
||||
<li>
|
||||
${thing.embed_button.render()}
|
||||
</li>
|
||||
%endif
|
||||
%if thing.can_save:
|
||||
%if thing.saved:
|
||||
<li class="comment-unsave-button save-button">
|
||||
<a href="javascript:void(0)">${_("unsave")}</a>
|
||||
</li>
|
||||
%else:
|
||||
<li class="comment-save-button save-button">
|
||||
<a href="javascript:void(0)">${_("save")}</a>
|
||||
</li>
|
||||
%endif
|
||||
%if thing.saved:
|
||||
<li class="comment-unsave-button save-button">
|
||||
<a href="javascript:void(0)">${_("unsave")}</a>
|
||||
</li>
|
||||
%else:
|
||||
<li class="comment-save-button save-button">
|
||||
<a href="javascript:void(0)">${_("save")}</a>
|
||||
</li>
|
||||
%endif
|
||||
%endif
|
||||
|
||||
%if c.profilepage:
|
||||
|
||||
Reference in New Issue
Block a user