Completing flow for sharing using bookmarklet. Just needs to actually share the story, then show shared stories in sidebar.

This commit is contained in:
Samuel Clay 2012-08-24 14:34:53 -07:00
parent a2859f75ea
commit 116b976b51
6 changed files with 281 additions and 72 deletions

View file

@ -8,7 +8,8 @@ from django.contrib.auth import login as login_user
from django.contrib.auth import logout as logout_user
from apps.reader.forms import SignupForm, LoginForm
from apps.profile.models import Profile
from apps.social.models import MSocialProfile
from apps.social.models import MSocialProfile, MSharedStory
from apps.rss_feeds.models import Feed
from apps.reader.models import UserSubscription, UserSubscriptionFolders
from utils import json_functions as json
from utils import log as logging
@ -129,7 +130,8 @@ def add_site(request, token):
if code > 0:
message = 'OK'
logging.user(profile.user, "~FRAdding URL from site: ~SB%s (in %s)" % (url, folder))
logging.user(profile.user, "~FRAdding URL from site: ~SB%s (in %s)" % (url, folder),
request=request)
return HttpResponse(callback + '(' + json.encode({
'code': code,
@ -140,9 +142,13 @@ def add_site(request, token):
def check_share_on_site(request, token):
code = 0
story_url = request.GET['story_url']
rss_url = request.GET['rss_url']
rss_url = request.GET.get('rss_url')
callback = request.GET['callback']
other_stories = None
same_stories = None
usersub = None
message = None
user = None
if not story_url:
@ -150,22 +156,38 @@ def check_share_on_site(request, token):
else:
try:
profile = Profile.objects.get(secret_token=token)
user = profile.user
except Profile.DoesNotExist:
code = -1
logging.user(profile.user, "~BM~FCChecking share from site: ~SB%s" % (story_url))
return HttpResponse(callback + '(' + json.encode({
'code': code,
'message': message,
'feed': None,
feed = Feed.get_feed_from_url(rss_url, create=False, fetch=False)
if not feed:
feed = Feed.get_feed_from_url(story_url, create=False, fetch=True)
if feed and user:
usersub = UserSubscription.objects.filter(user=user, feed=feed)
same_stories, other_stories = MSharedStory.get_shared_stories(feed.pk, story_url)
logging.user(profile.user, "~BM~FCChecking share from site: ~SB%s" % (story_url),
request=request)
response = HttpResponse(callback + '(' + json.encode({
'code' : code,
'message' : message,
'feed' : feed,
'subscribed' : usersub and usersub.count() > 0,
'same_stories' : same_stories,
'other_stories' : other_stories,
}) + ')', mimetype='text/plain')
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'GET'
return response
def share_story(request, token):
code = 0
story_url = request.GET['story_url']
comments = request.GET['comments']
callback = request.GET['callback']
story_url = request.POST['story_url']
comments = request.POST['comments']
message = None
if not story_url:
@ -178,8 +200,12 @@ def share_story(request, token):
logging.user(profile.user, "~BM~FYSharing story from site: ~SB%s: %s" % (story_url, comments))
return HttpResponse(callback + '(' + json.encode({
response = HttpResponse(json.encode({
'code': code,
'message': message,
'story': None,
}) + ')', mimetype='text/plain')
}), mimetype='text/plain')
response['Access-Control-Allow-Origin'] = '*'
response['Access-Control-Allow-Methods'] = 'POST'
return response

View file

@ -1099,6 +1099,16 @@ class MSharedStory(mongo.Document):
super(MSharedStory, self).delete(*args, **kwargs)
@classmethod
def get_shared_stories(cls, feed_id, story_url=None, limit=3):
same_stories = None
if story_url:
same_stories = cls.objects.filter(story_feed_id=feed_id, story_permalink=story_url).order_by('-shared_date')
other_stories = cls.objects.filter(story_feed_id=feed_id, story_permalink__ne=story_url).order_by('-shared_date')
return same_stories, other_stories
def ensure_story_db_id(self, save=True):
if not self.story_db_id:
story, _ = MStory.find_story(self.story_feed_id, self.story_guid)

View file

@ -91,6 +91,8 @@ javascripts:
- media/js/vendor/jquery.simplemodal-1.3.js
- media/js/vendor/jquery.corners.js
- media/js/vendor/jquery.hotkeys.js
- media/js/vendor/jquery.easing.js
- media/js/vendor/underscore-*.js
- media/js/vendor/readability-*.js
blurblog:
- media/js/vendor/jquery-*.js

View file

@ -90,7 +90,7 @@
overflow: hidden;
}
.NB-bookmarklet .NB-bookmarklet-main {
width: 70%;
width: 530px;
overflow: hidden;
float: right;
border-left: 6px solid #74B3B7;
@ -107,6 +107,21 @@
/* = Bookmarklet Add Site = */
/* ======================== */
.NB-bookmarklet .NB-subscribe-feed {
font-size: 12px;
font-weight: bold;
overflow: hidden;
}
.NB-bookmarklet .NB-subscribe-feed img {
width: 16px;
height: 16px;
float: left;
vertical-align: bottom;
margin: 11px 6px 0 0;
}
.NB-bookmarklet .NB-subscribe-feed-title {
margin: 12px 0 0;
}
.NB-bookmarklet .NB-modal-information {
float: right;
@ -116,8 +131,7 @@
font-size: 10px;
}
.NB-bookmarklet .NB-bookmarklet-folder-container {
margin: 28px 0;
float: right;
margin: 12px 0 0;
}
.NB-bookmarklet .NB-bookmarklet-folder-container .NB-bookmarklet-folder-label {
float: left;
@ -133,8 +147,9 @@
}
.NB-bookmarklet .NB-bookmarklet-new-folder-container {
display: none;
float: right;
clear: both;
overflow: hidden;
padding-left: 24px;
}
.NB-bookmarklet .NB-bookmarklet-folder-new {
float: left;
@ -143,17 +158,17 @@
font-size: 11px;
line-height: 13px;
margin: 2px 0 0;
width: 170px;
width: 156px;
}
.NB-bookmarklet .NB-bookmarklet-folder-new-label {
margin: 4px 4px 0 0;
float: left;
}
.NB-bookmarklet .NB-folders {
width: 150px;
width: 186px;
}
.NB-bookmarklet .NB-modal-submit {
margin: 24px 0 8px;
margin: 12px 0 8px;
padding: 0 0 6px;
clear: both;
overflow: hidden;
@ -162,16 +177,21 @@
clear: both;
padding: 0 16px;
line-height: 24px;
width: 160px;
width: 176px;
text-align: center;
text-shadow: none;
font-weight: normal;
}
.NB-bookmarklet .NB-modal-submit-button.NB-disabled:hover,
.NB-bookmarklet .NB-modal-submit-button.NB-disabled:active {
cursor: default;
}
.NB-bookmarklet .NB-modal-submit-button:hover,
.NB-bookmarklet .NB-modal-submit-button:active {
font-weight: normal;
}
.NB-bookmarklet .NB-modal-submit-button img {
margin: 5px 6px 0 0;
margin: 4px 6px 0 0;
width: 16px;
height: 16px;
float: left;
@ -189,12 +209,6 @@
vertical-align: top;
margin: -2px 6px 0 0;
}
.NB-bookmarklet .NB-bookmarklet-folder-label {
float: right;
}
.NB-bookmarklet .NB-folders {
float: right;
}
.NB-bookmarklet .NB-error-invalid {
padding: 12px 12px;
font-size: 13px;
@ -215,16 +229,23 @@
.NB-bookmarklet .NB-bookmarklet-page-title {
font-size: 20px;
font-weight: bold;
margin: 0 0 0 24px;
margin: 0 18px 0 14px;
padding: 12px 12px 12px 10px;
border-radius: 4px;
background-color: #F6F6F6;
line-height: 24px;
}
.NB-bookmarklet .NB-bookmarklet-page-content {
.NB-bookmarklet .NB-bookmarklet-page-content-wrapper {
max-height: 340px;
overflow-y: scroll;
padding: 0 24px;
margin: 12px 0 0;
background-color: white;
}
.NB-bookmarklet .NB-bookmarklet-page-content {
border-top: 1px solid #F0F0F0;
border-bottom: 1px solid #F0F0F0;
}
.NB-bookmarklet .NB-bookmarklet-page-comment {
margin-top: 12px;
/* border-top: 1px solid #F0F0F0;*/
@ -261,9 +282,71 @@
.NB-bookmarklet .NB-bookmarklet-comment-submit {
float: left;
clear: none;
width: 100px;
width: 98px;
height: 32px;
margin: 0 0 4px 12px;
padding: 8px 0;
line-height: 16px;
}
.NB-bookmarklet .NB-bookmarklet-comment-submit.NB-disabled {
padding: 14px 0 0;
}
.NB-bookmarklet .NB-bookmarklet-comment-submit .NB-bookmarklet-accept {
padding: 0 12px;
}
.NB-bookmarklet .NB-bookmarklet-comment-submit .NB-bookmarklet-accept img {
vertical-align: top;
margin: 0;
}
/* =============== */
/* = Side Layout = */
/* =============== */
.NB-bookmarklet .NB-bookmarklet-side {
position: relative;
width: 200px;
height: 400px;
margin: 24px 0 0;
overflow: hidden;
}
.NB-bookmarklet .NB-bookmarklet-side-half {
position: absolute;
top: 0;
left: 0;
width: 100%;
}
.NB-bookmarklet .NB-bookmarklet-side-subscribe {
left: 100%;
}
.NB-bookmarklet .NB-bookmarklet-side-loading {
text-align: center;
font-size: 15px;
color: #C0C0C0;
text-transform: uppercase;
font-weight: bold;
}
line-height: 18px;
padding: 48px 0 0;
}
.NB-bookmarklet .NB-subscribe-loader {
margin: 0 auto;
width: 16px;
height: 16px;
-webkit-animation: -webkit-slow-spin 4s infinite linear;
-moz-animation-duration: 4s;
-moz-animation-name: -moz-slow-spin;
-moz-animation-iteration-count: infinite;
-moz-animation-timing-function: linear;
}
@-webkit-keyframes -webkit-slow-spin {
from {-webkit-transform: rotate(0deg)}
to {-webkit-transform: rotate(360deg)}
}
@-moz-keyframes -moz-slow-spin {
from {-moz-transform: rotate(0deg)}
to {-moz-transform: rotate(360deg)}
}
.NB-bookmarklet .NB-subscribe-load-text {
padding: 24px 24px;
}

View file

@ -17,6 +17,9 @@
this.flags = {
'new_folder': false
};
this.images = {
'accept_image': "{{ accept_image }}"
};
this.options = $.extend({}, defaults, options);
this.runner();
@ -57,7 +60,9 @@
this.make_modal();
this.open_modal();
this.get_page_content();
this.pre_share_check_story();
_.delay(_.bind(function() {
this.pre_share_check_story();
}, this), 0);
this.$modal.bind('click', $.rescope(this.handle_clicks, this));
@ -80,8 +85,10 @@
$.make('div', { className: 'NB-bookmarklet-main'}, [
$.make('div', { className: 'NB-bookmarklet-page' }, [
$.make('div', { className: 'NB-bookmarklet-page-title' }),
$.make('div', { className: 'NB-bookmarklet-page-content' }),
$.make('div', { className: 'NB-bookmarklet-page-comment' }, [
$.make('div', { className: 'NB-bookmarklet-page-content-wrapper' }, [
$.make('div', { className: 'NB-bookmarklet-page-content' })
]),
$.make('div', { className: 'NB-bookmarklet-page-comment NB-modal-submit' }, [
$.make('div', { className: 'NB-bookmarklet-comment-photo' }, [
$.make('img', { src: this.profile.photo_url })
]),
@ -93,16 +100,23 @@
])
]),
$.make('div', { className: 'NB-bookmarklet-side' }, [
$.make('div', { className: 'NB-modal-submit' }, [
$.make('div', { className: 'NB-modal-submit-button NB-modal-submit-green' }, 'Subscribe to this site')
]),
$.make('div', { className: 'NB-bookmarklet-folder-container' }, [
$.make('img', { className: 'NB-bookmarklet-folder-add-button', src: 'data:image/png;charset=utf-8;base64,{{ add_image }}', title: 'Add New Folder' }),
this.make_folders(),
$.make('div', { className: 'NB-bookmarklet-new-folder-container' }, [
$.make('img', { className: 'NB-bookmarklet-folder-new-label', src: 'data:image/png;charset=utf-8;base64,{{ new_folder_image }}' }),
$.make('input', { type: 'text', name: 'new_folder_name', className: 'NB-bookmarklet-folder-new' })
$.make('div', { className: 'NB-bookmarklet-side-half NB-bookmarklet-side-subscribe' }, [
$.make('div', { className: 'NB-subscribe-feed' }),
$.make('div', { className: 'NB-bookmarklet-folder-container' }, [
$.make('img', { className: 'NB-bookmarklet-folder-add-button', src: 'data:image/png;charset=utf-8;base64,{{ add_image }}', title: 'Add New Folder' }),
this.make_folders(),
$.make('div', { className: 'NB-bookmarklet-new-folder-container' }, [
$.make('img', { className: 'NB-bookmarklet-folder-new-label', src: 'data:image/png;charset=utf-8;base64,{{ new_folder_image }}' }),
$.make('input', { type: 'text', name: 'new_folder_name', className: 'NB-bookmarklet-folder-new' })
])
]),
$.make('div', { className: 'NB-modal-submit' }, [
$.make('div', { className: 'NB-bookmarklet-button-subscribe NB-modal-submit-button NB-modal-submit-green' }, 'Subscribe to this site')
])
]),
$.make('div', { className: 'NB-bookmarklet-side-half NB-bookmarklet-side-loading' }, [
$.make('img', { className: 'NB-subscribe-loader', src: 'data:image/png;charset=utf-8;base64,{{ add_image }}', title: 'Loading...' }),
$.make('div', { className: 'NB-subscribe-load-text' }, 'Shared stories are on their way...')
])
])
]);
@ -191,7 +205,7 @@
save: function() {
var self = this;
var $submit = $('.NB-modal-submit-button');
var $submit = $('.NB-bookmarklet-button-subscribe', this.$modal);
var folder = $('.NB-folders').val();
var add_site_url = "http://"+this.domain+"{% url api-add-site token %}?callback=?";
@ -210,23 +224,23 @@
}
$.getJSON(add_site_url, data, function(resp) {
self.post_save(resp);
self.confirm_subscription(resp.code > 0, resp.message);
});
},
post_save: function(resp) {
var $submit = $('.NB-modal-submit-button');
confirm_subscription: function(subscribed, message) {
var $submit = $('.NB-bookmarklet-button-subscribe', this.$modal);
$submit.addClass('NB-close');
$submit.addClass('NB-disabled');
if (resp.code == 1) {
if (subscribed) {
$submit.html($.make('div', { className: 'NB-bookmarklet-accept' }, [
$.make('img', { src: 'data:image/png;charset=utf-8;base64,{{ accept_image }}' }),
'Added!'
$.make('img', { src: 'data:image/png;charset=utf-8;base64,' + this.images['accept_image'] }),
'Subscribed'
]));
setTimeout(function() {
$.modal.close();
}, 2000);
// setTimeout(function() {
// $.modal.close();
// }, 2000);
} else {
var $error = $.make('div', { className: 'NB-bookmarklet-error' }, [
$.make('img', { className: 'NB-bookmarklet-folder-label', src: 'data:image/png;charset=utf-8;base64,{{ error_image }}' }),
@ -242,15 +256,43 @@
// =============
pre_share_check_story: function() {
var $side = $('.NB-bookmarklet-side', this.$modal);
var $side_loading = $('.NB-bookmarklet-side-loading', this.$modal);
var $side_subscribe = $('.NB-bookmarklet-side-subscribe', this.$modal);
var check_story_url = "http://"+this.domain+"{% url api-check-share-on-site token %}?callback=?";
var data = {
story_url: window.location.href,
rss_url: $('link[type="application/rss+xml"]').attr('href')
rss_url: this.get_page_rss_url()
};
$.getJSON(check_story_url, data, function(resp) {
});
$.getJSON(check_story_url, data, _.bind(function(data) {
$side_loading.animate({'left': '-100%'}, {
'easing': 'easeInOutQuint',
'duration': 1650,
'queue': false
});
$side_subscribe.css('left', $side.outerWidth(true)+4).animate({'left': 0}, {
'easing': 'easeInOutQuint',
'duration': 1650,
'queue': false
});
this.feed = data.feed;
this.make_feed_subscribe(data.feed);
if (data.subscribed) {
$('.NB-bookmarklet-folder-container', this.$modal).hide();
this.confirm_subscription(data.subscribed);
}
}, this));
},
make_feed_subscribe: function(feed) {
if (feed) {
var $feed = $.make('div', { className: 'NB-subscribe-feed' }, [
$.make('img', { src: 'data:image/png;charset=utf-8;base64,' + feed.favicon }),
$.make('div', { className: 'NB-subscribe-feed-title' }, feed.feed_title)
]);
$('.NB-subscribe-feed', this.$modal).replaceWith($feed);
}
},
// ===============
@ -258,14 +300,47 @@
// ===============
share_story: function() {
var $share = $(".NB-bookmarklet-comment-submit", this.$modal);
$share.addClass('NB-disabled').text('Sharing...');
$.ajax({
url: 'http://'+this.domain+"{% url api-share-story token %}?callback=?",
})
url: '//'+this.domain+"{% url api-share-story token %}",
type: 'POST',
data: {
title: this.story_title,
content: this.story_content,
comments: $('textarea[name=newsblur_comment]', this.$modal).val(),
feed_id: this.feed && this.feed.id,
story_url: window.location.href,
rss_url: this.get_page_rss_url()
},
success: _.bind(this.post_share_story, this),
error: _.bind(this.error_share_story, this)
});
},
post_share_story: function(data) {
var $share = $(".NB-bookmarklet-comment-submit", this.$modal);
if (data.code < 0) {
return this.error_share_story(data);
}
$share.html($.make('div', { className: 'NB-bookmarklet-accept' }, [
$.make('img', { src: 'data:image/png;charset=utf-8;base64,' + this.images['accept_image'] }),
'Shared'
]));
// setTimeout(function() {
// $.modal.close();
// }, 2000);
},
error_share_story: function(data) {
$share.removeClass('NB-disabled');
console.log(["error sharing", data]);
this.update_share_button_title();
},
open_add_folder: function() {
@ -296,12 +371,12 @@
} else {
var $readability = $(window.readability.init());
var title = $readability.children("h1").text();
var content = $("#readability-content", $readability).html();
this.story_title = $readability.children("h1").text();
this.story_content = $("#readability-content", $readability).html();
}
$title.html(title);
$content.html(content);
$title.html(this.story_title);
$content.html(this.story_content);
},
get_selected_html: function() {
@ -355,6 +430,10 @@
return title;
},
get_page_rss_url: function() {
return $('link[type="application/rss+xml"]').attr('href');
},
// ===========
// = Actions =
// ===========
@ -362,7 +441,7 @@
handle_clicks: function(elem, e) {
var self = this;
$.targetIs(e, { tagSelector: '.NB-modal-submit-button' }, function($t, $p) {
$.targetIs(e, { tagSelector: '.NB-bookmarklet-button-subscribe' }, function($t, $p) {
e.preventDefault();
if (!$t.hasClass('NB-disabled')) {
@ -381,6 +460,14 @@
$t.toggleClass('NB-active');
});
$.targetIs(e, { tagSelector: '.NB-bookmarklet-comment-submit' }, function($t, $p) {
e.preventDefault();
if (!$t.hasClass('NB-disabled')) {
self.share_story();
}
});
$.targetIs(e, { tagSelector: '.NB-close' }, function($t, $p) {
e.preventDefault();

View file

@ -13,12 +13,13 @@ def getlogger():
logger = logging.getLogger('newsblur')
return logger
def user(u, msg):
def user(u, msg, request=None):
platform = '------'
time_elapsed = ""
if isinstance(u, WSGIRequest):
request = u
u = request.user
if isinstance(u, WSGIRequest) or request:
if not request:
request = u
u = request.user
user_agent = request.environ.get('HTTP_USER_AGENT', '')
if 'iPad App' in user_agent:
platform = 'iPad'